From 5886f2a7cd1c9e0b5766f7a59fe00a087a23c03e Mon Sep 17 00:00:00 2001 From: Carsten Haitzler Date: Mon, 1 Nov 2004 09:45:31 +0000 Subject: [PATCH] and new much cleaner tree. SVN revision: 12113 --- AUTHORS | 30 + COPYING | 28 + COPYING-PLAIN | 33 + ChangeLog | 3007 ++++++++++++++ Doxyfile | 139 + INSTALL | 14 + Makefile.am | 22 + NEWS | 0 README | 41 + TODO | 6 + autogen.sh | 13 + configure.in | 394 ++ data/Makefile.am | 2 + data/fonts/Makefile.am | 11 + data/fonts/cinema.ttf | Bin 0 -> 11588 bytes data/fonts/grunge.ttf | Bin 0 -> 53204 bytes data/fonts/morpheus.ttf | Bin 0 -> 68044 bytes data/fonts/notepad.ttf | Bin 0 -> 31312 bytes data/images/Makefile.am | 25 + data/images/audio.png | Bin 0 -> 4263 bytes data/images/bg.png | Bin 0 -> 132721 bytes data/images/bulb.png | Bin 0 -> 3504 bytes data/images/cal.png | Bin 0 -> 2755 bytes data/images/calc.png | Bin 0 -> 3949 bytes data/images/folder.png | Bin 0 -> 2873 bytes data/images/globe.png | Bin 0 -> 3388 bytes data/images/imlib2.png | Bin 0 -> 53192 bytes data/images/lock.png | Bin 0 -> 2770 bytes data/images/mail.png | Bin 0 -> 3222 bytes data/images/menu.png | Bin 0 -> 3240 bytes data/images/mush.png | Bin 0 -> 3244 bytes data/images/paper.png | Bin 0 -> 3410 bytes data/images/sh1.png | Bin 0 -> 768 bytes data/images/sh2.png | Bin 0 -> 280 bytes data/images/sh3.png | Bin 0 -> 360 bytes data/images/stop.png | Bin 0 -> 2684 bytes data/images/tnt.png | Bin 0 -> 3010 bytes debian/Makefile.am | 9 + debian/changelog | 5 + debian/control | 44 + debian/copyright | 32 + debian/imlib2-config.1 | 17 + debian/imlib2-demo.install | 2 + debian/imlib2-test.install | 5 + debian/libimlib2-dev.doc-base | 10 + debian/libimlib2-dev.install | 10 + debian/libimlib2.install | 3 + debian/rules | 88 + doc/Makefile.am | 5 + doc/blank.gif | Bin 0 -> 266 bytes doc/foot.html | 2 + doc/head.html | 19 + doc/img/hilite.png | Bin 0 -> 6127 bytes doc/img/imlib2.png | Bin 0 -> 6433 bytes doc/img/imlib2_mini.png | Bin 0 -> 753 bytes doc/imlib2.css | 178 + doc/imlib2.gif | Bin 0 -> 6794 bytes doc/index.html | 2268 ++++++++++ gendoc | 17 + imlib2-config.in | 59 + imlib2.c.in | 547 +++ imlib2.pc.in | 12 + imlib2.spec | 184 + m4/ac_expand_dir.m4 | 14 + m4/ac_path_generic.m4 | 136 + src/Makefile.am | 2 + src/bin/Makefile.am | 35 + src/bin/imlib2_bumpmap.c | 128 + src/bin/imlib2_colorspace.c | 143 + src/bin/imlib2_conv.c | 92 + src/bin/imlib2_poly.c | 127 + src/bin/imlib2_show.c | 1378 +++++++ src/bin/imlib2_test.c | 274 ++ src/bin/imlib2_view.c | 346 ++ src/lib/Imlib2.h | 481 +++ src/lib/Makefile.am | 83 + src/lib/api.c | 5455 +++++++++++++++++++++++++ src/lib/asm_blend.S | 1059 +++++ src/lib/asm_blend_cmod.S | 1604 ++++++++ src/lib/asm_rgba.S | 301 ++ src/lib/asm_rotate.S | 469 +++ src/lib/asm_scale.S | 809 ++++ src/lib/blend.c | 1820 +++++++++ src/lib/blend.h | 556 +++ src/lib/color.c | 573 +++ src/lib/color.h | 22 + src/lib/color_helpers.c | 235 ++ src/lib/color_helpers.h | 9 + src/lib/colormod.c | 254 ++ src/lib/colormod.h | 72 + src/lib/common.h | 42 + src/lib/context.c | 212 + src/lib/context.h | 36 + src/lib/draw.c | 92 + src/lib/draw.h | 16 + src/lib/dynamic_filters.c | 193 + src/lib/dynamic_filters.h | 43 + src/lib/ellipse.c | 737 ++++ src/lib/file.c | 506 +++ src/lib/file.h | 20 + src/lib/filter.c | 241 ++ src/lib/filter.h | 42 + src/lib/font.h | 126 + src/lib/font_draw.c | 421 ++ src/lib/font_load.c | 431 ++ src/lib/font_main.c | 418 ++ src/lib/font_query.c | 313 ++ src/lib/format.c | 1 + src/lib/format.h | 3 + src/lib/grab.c | 729 ++++ src/lib/grab.h | 19 + src/lib/grad.c | 614 +++ src/lib/grad.h | 28 + src/lib/image.c | 1318 ++++++ src/lib/image.h | 202 + src/lib/libimlib2.la | 35 + src/lib/line.c | 711 ++++ src/lib/loaderpath.h | 3 + src/lib/polygon.c | 1733 ++++++++ src/lib/rectangle.c | 192 + src/lib/rend.c | 598 +++ src/lib/rend.h | 29 + src/lib/rgba.c | 4966 ++++++++++++++++++++++ src/lib/rgba.h | 33 + src/lib/rgbadraw.c | 624 +++ src/lib/rgbadraw.h | 141 + src/lib/rotate.c | 542 +++ src/lib/rotate.h | 33 + src/lib/scale.c | 1534 +++++++ src/lib/scale.h | 22 + src/lib/script.c | 298 ++ src/lib/script.h | 70 + src/lib/span.c | 1160 ++++++ src/lib/span.h | 24 + src/lib/updates.c | 195 + src/lib/updates.h | 16 + src/lib/ximage.c | 330 ++ src/lib/ximage.h | 16 + src/modules/Makefile.am | 2 + src/modules/filters/Makefile.am | 21 + src/modules/filters/filter_bumpmap.c | 292 ++ src/modules/filters/filter_colormod.c | 269 ++ src/modules/filters/filter_test.c | 115 + src/modules/loaders/Makefile.am | 91 + src/modules/loaders/loader_argb.c | 201 + src/modules/loaders/loader_bmp.c | 739 ++++ src/modules/loaders/loader_bz2.c | 107 + src/modules/loaders/loader_gif.c | 247 ++ src/modules/loaders/loader_jpeg.c | 376 ++ src/modules/loaders/loader_lbm.c | 550 +++ src/modules/loaders/loader_png.c | 440 ++ src/modules/loaders/loader_pnm.c | 832 ++++ src/modules/loaders/loader_tga.c | 584 +++ src/modules/loaders/loader_tiff.c | 494 +++ src/modules/loaders/loader_xpm.c | 691 ++++ src/modules/loaders/loader_zlib.c | 124 + 156 files changed, 50041 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 COPYING-PLAIN create mode 100644 ChangeLog create mode 100644 Doxyfile create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 TODO create mode 100755 autogen.sh create mode 100644 configure.in create mode 100644 data/Makefile.am create mode 100644 data/fonts/Makefile.am create mode 100644 data/fonts/cinema.ttf create mode 100644 data/fonts/grunge.ttf create mode 100644 data/fonts/morpheus.ttf create mode 100644 data/fonts/notepad.ttf create mode 100644 data/images/Makefile.am create mode 100644 data/images/audio.png create mode 100644 data/images/bg.png create mode 100644 data/images/bulb.png create mode 100644 data/images/cal.png create mode 100644 data/images/calc.png create mode 100644 data/images/folder.png create mode 100644 data/images/globe.png create mode 100644 data/images/imlib2.png create mode 100644 data/images/lock.png create mode 100644 data/images/mail.png create mode 100644 data/images/menu.png create mode 100644 data/images/mush.png create mode 100644 data/images/paper.png create mode 100644 data/images/sh1.png create mode 100644 data/images/sh2.png create mode 100644 data/images/sh3.png create mode 100644 data/images/stop.png create mode 100644 data/images/tnt.png create mode 100644 debian/Makefile.am create mode 100644 debian/changelog create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/imlib2-config.1 create mode 100644 debian/imlib2-demo.install create mode 100644 debian/imlib2-test.install create mode 100644 debian/libimlib2-dev.doc-base create mode 100644 debian/libimlib2-dev.install create mode 100644 debian/libimlib2.install create mode 100644 debian/rules create mode 100644 doc/Makefile.am create mode 100644 doc/blank.gif create mode 100644 doc/foot.html create mode 100644 doc/head.html create mode 100644 doc/img/hilite.png create mode 100644 doc/img/imlib2.png create mode 100644 doc/img/imlib2_mini.png create mode 100644 doc/imlib2.css create mode 100644 doc/imlib2.gif create mode 100644 doc/index.html create mode 100755 gendoc create mode 100644 imlib2-config.in create mode 100644 imlib2.c.in create mode 100644 imlib2.pc.in create mode 100644 imlib2.spec create mode 100644 m4/ac_expand_dir.m4 create mode 100644 m4/ac_path_generic.m4 create mode 100644 src/Makefile.am create mode 100644 src/bin/Makefile.am create mode 100644 src/bin/imlib2_bumpmap.c create mode 100644 src/bin/imlib2_colorspace.c create mode 100644 src/bin/imlib2_conv.c create mode 100644 src/bin/imlib2_poly.c create mode 100644 src/bin/imlib2_show.c create mode 100644 src/bin/imlib2_test.c create mode 100644 src/bin/imlib2_view.c create mode 100644 src/lib/Imlib2.h create mode 100644 src/lib/Makefile.am create mode 100644 src/lib/api.c create mode 100644 src/lib/asm_blend.S create mode 100644 src/lib/asm_blend_cmod.S create mode 100644 src/lib/asm_rgba.S create mode 100644 src/lib/asm_rotate.S create mode 100644 src/lib/asm_scale.S create mode 100644 src/lib/blend.c create mode 100644 src/lib/blend.h create mode 100644 src/lib/color.c create mode 100644 src/lib/color.h create mode 100644 src/lib/color_helpers.c create mode 100644 src/lib/color_helpers.h create mode 100644 src/lib/colormod.c create mode 100644 src/lib/colormod.h create mode 100644 src/lib/common.h create mode 100644 src/lib/context.c create mode 100644 src/lib/context.h create mode 100644 src/lib/draw.c create mode 100644 src/lib/draw.h create mode 100644 src/lib/dynamic_filters.c create mode 100644 src/lib/dynamic_filters.h create mode 100644 src/lib/ellipse.c create mode 100644 src/lib/file.c create mode 100644 src/lib/file.h create mode 100644 src/lib/filter.c create mode 100644 src/lib/filter.h create mode 100644 src/lib/font.h create mode 100644 src/lib/font_draw.c create mode 100644 src/lib/font_load.c create mode 100644 src/lib/font_main.c create mode 100644 src/lib/font_query.c create mode 100644 src/lib/format.c create mode 100644 src/lib/format.h create mode 100644 src/lib/grab.c create mode 100644 src/lib/grab.h create mode 100644 src/lib/grad.c create mode 100644 src/lib/grad.h create mode 100644 src/lib/image.c create mode 100644 src/lib/image.h create mode 100644 src/lib/libimlib2.la create mode 100644 src/lib/line.c create mode 100644 src/lib/loaderpath.h create mode 100644 src/lib/polygon.c create mode 100644 src/lib/rectangle.c create mode 100644 src/lib/rend.c create mode 100644 src/lib/rend.h create mode 100644 src/lib/rgba.c create mode 100644 src/lib/rgba.h create mode 100644 src/lib/rgbadraw.c create mode 100644 src/lib/rgbadraw.h create mode 100644 src/lib/rotate.c create mode 100644 src/lib/rotate.h create mode 100644 src/lib/scale.c create mode 100644 src/lib/scale.h create mode 100644 src/lib/script.c create mode 100644 src/lib/script.h create mode 100644 src/lib/span.c create mode 100644 src/lib/span.h create mode 100644 src/lib/updates.c create mode 100644 src/lib/updates.h create mode 100644 src/lib/ximage.c create mode 100644 src/lib/ximage.h create mode 100644 src/modules/Makefile.am create mode 100644 src/modules/filters/Makefile.am create mode 100644 src/modules/filters/filter_bumpmap.c create mode 100644 src/modules/filters/filter_colormod.c create mode 100644 src/modules/filters/filter_test.c create mode 100644 src/modules/loaders/Makefile.am create mode 100644 src/modules/loaders/loader_argb.c create mode 100644 src/modules/loaders/loader_bmp.c create mode 100644 src/modules/loaders/loader_bz2.c create mode 100644 src/modules/loaders/loader_gif.c create mode 100644 src/modules/loaders/loader_jpeg.c create mode 100644 src/modules/loaders/loader_lbm.c create mode 100644 src/modules/loaders/loader_png.c create mode 100644 src/modules/loaders/loader_pnm.c create mode 100644 src/modules/loaders/loader_tga.c create mode 100644 src/modules/loaders/loader_tiff.c create mode 100644 src/modules/loaders/loader_xpm.c create mode 100644 src/modules/loaders/loader_zlib.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..06ce4f0 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,30 @@ +The Rasterman (Carsten Haitzler) +Ryan Gustafson +Mandrake (Geoff Harrison) +Willem Monsuwe +KainX (Michael Jennings) +Eric Dorland +Chutt (Isaac Richards) +giblet (Tom Gilbert) +Takis +Dan Maas +Platon Fomichev +boris (Chris Ross) +Martin Grimm +Matt McClanahan +Steve Langasek +Christophe Tronche +Nathan Ingersoll +Masa(Masahiko) Mori +Term (Lyle Kempler) +Adam Kisiel +Carsten Pfeiffer +Lightman (Franz Marini) +Mark Bainter +Brian Lindholm +Renchi Raju +Yuri Hudobin +Radoslaw Grzanka +Kim Woelders +Nick Blievers +Mike Castle diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..474fcc5 --- /dev/null +++ b/COPYING @@ -0,0 +1,28 @@ +Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies of the Software and its Copyright notices. In addition publicly +documented acknowledgment must be given that this software has been used if no +source code of this software is made available publicly. This includes +acknowledgments in either Copyright notices, Manuals, Publicity and Marketing +documents or any documentation provided with any product containing this +software. This License does not apply to any software that links to the +libraries provided by this software (statically or dynamically), but only to +the software provided. + +Please see the COPYING.PLAIN for a plain-english explanation of this notice +and it's intent. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/COPYING-PLAIN b/COPYING-PLAIN new file mode 100644 index 0000000..376875e --- /dev/null +++ b/COPYING-PLAIN @@ -0,0 +1,33 @@ +Plain English Copyright Notice + +This file is not intended to be the actual License. The reason this file +exists is that we here are programmers and engineers. We aren't lawyers. We +provide licenses that we THINK say the right things, but we have our own +intentions at heart. This is a plain-english explanation of what those +intentions are, and if you follow them you will be within the "spirit" of +the license. + +The intent is for us to enjoy writing software that is useful to us (the +AUTHORS) and allow others to use it freely and also benefit from the work we +put into making it. We don't want to restrict others using it. They should +not *HAVE* to make the source code of the applications they write that +simply link to these libraries (be that statically or dynamically), or for +them to be limited as to what license they choose to use (be it open, closed +or anything else). But we would like to know you are using these libraries. +We simply would like to know that it has been useful to someone. This is why +we ask for acknowledgement of some sort. + +You can do what you want with the source of this software - it doesn't +matter. We still have it here for ourselves and it is open and free to use +and download and play with. It can't be taken away. We don't really mind what +you do with the source to your software. We would simply like to know that +you are using it - especially if it makes it to a commerical product. If you +simply e-mail all the AUTHORS (see COPYING and AUTHORS files) telling us, and +then make sure you include a paragraph or page in the manual for the product +with the copyright notice and state that you used this software, we will be +very happy. If you want to contribute back modifications and fixes you may have +made we will welcome those too with open arms (generally). If you want help +with changes needed, ports needed or features to be added, arrangements can +be easily made with some dialogue. + +Carsten Haitzler diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..b5c1a59 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,3007 @@ + + +Changes by: raster 99/08/01 15:14:14 + +Log message: + adding imlib2 code in.. NOT a lib yet... :) but playable code and loader + system + + Status: + + Vendor Tag: imlib2 + Release Tags: A + + N imlib2/loader_png.c + N imlib2/Makefile + N imlib2/README + N imlib2/blend.c + N imlib2/blend.h + N imlib2/color.c + N imlib2/color.h + N imlib2/common.h + N imlib2/file.c + N imlib2/file.h + N imlib2/grab.c + N imlib2/grab.h + N imlib2/image.c + N imlib2/image.h + N imlib2/main.c + N imlib2/rend.c + N imlib2/rend.h + N imlib2/rgba.c + N imlib2/rgba.h + N imlib2/scale.c + N imlib2/scale.h + N imlib2/ximage.c + N imlib2/ximage.h + N imlib2/test_images/im_rgb.png + N imlib2/test_images/im.png + + No conflicts created by this import + +_______________________________________________ + +Changes by: raster 99/08/02 15:50:36 + +Modified files: + . : loader_png.c +Added files: + . : COPYING + +Log message: +fixed minor bug in png loader.... added copying file :) + +_______________________________________________ + +Changes by: raster 99/08/02 22:15:35 + +Modified files: + . : image.c image.h loader_png.c main.c + +Log message: +updated loader api to include progress callback stuff.... :) + +_______________________________________________ + +Changes by: raster 99/09/01 10:36:17 + +Modified files: + . : api.c api.h context.c image.c image.h main.c + +Log message: +remember to not free images made form external data if it wasnt copied.. and +free colors from color cubes once the context is invalid.. :) + +_______________________________________________ + +Changes by: raster 99/09/08 10:27:41 + +Modified files: + . : api.c api.h blend.c blend.h draw.c grab.c + grab.h loader_png.c main.c rend.c rend.h rgba.c + +Log message: +lots more work on mr imlib2 :) + +_______________________________________________ + +Changes by: raster 99/09/08 11:15:04 + +Modified files: + . : api.c main.c + +Log message: +and more updates :) wheeeeeeeee + +_______________________________________________ + +Changes by: raster 99/09/08 19:39:19 + +Modified files: + . : Makefile api.c + libltdl : Makefile.am Makefile.in acinclude.m4 aclocal.m4 + config.h.in configure configure.in ltdl.c + ltdl.h + +Log message: +more work on imlib2.. :) + +_______________________________________________ + +Changes by: raster 99/09/09 19:33:12 + +Modified files: + . : api.c blend.c blend.h loader_png.c main.c + rend.c + +Log message: +ooh is imlib2 ever workign fast now baybeee.. blending one image onto +another .. with clipping, scaling, anti-aliasing and more.. need to add +a bit to the api, and move the stuff nowin api.c off into imlib backend +sinc ethat stuff doesnt belong in api.c + +_______________________________________________ + +Changes by: raster 99/09/10 11:11:47 + +Modified files: + . : Makefile Makefile.am api.c api.h main.c +Added files: + . : loader_jpeg.c + +Log message: +jpeg loader added that does everything RIGHT - needto mapk the png loader +do the same. :) + +_______________________________________________ + +Changes by: raster 99/09/10 19:04:10 + +Modified files: + . : api.c loader_png.c main.c + +Log message: +and now the png loader does full progress callbacks and multi-phase loading +correctly... WHEEEEEEEEEEe :) + +_______________________________________________ + +Changes by: raster 99/09/12 18:56:57 + +Modified files: + . : Makefile README api.c api.h blend.c blend.h + image.c loader_png.c main.c + libltdl : Makefile.am Makefile.in acinclude.m4 aclocal.m4 + config.h.in configure configure.in ltdl.c + ltdl.h +Added files: + test_images : audio.png bg.png folder.png mush.png paper.png + sh1.png sh2.png sh3.png + +Log message: +ooh now imlib2 has a sexy demo for you people :) mmmmm watch the alpha +blending... mmmmmmmmm + +_______________________________________________ + +Changes by: raster 99/09/12 21:06:58 + +Modified files: + . : color.c context.c main.c rgba.c + +Log message: +more playing with imlib2... :) + +_______________________________________________ + +Changes by: raster 99/09/12 22:32:36 + +Modified files: + . : main.c +Added files: + test_images : bulb.png cal.png calc.png globe.png lock.png + mail.png menu.png stop.png tnt.png + +Log message: +add some more images just to show off :) + +_______________________________________________ + +Changes by: raster 99/09/12 22:34:51 + +Modified files: + . : context.c + +Log message: +get rid of printfs i dont need no more :) + +_______________________________________________ + +Changes by: raster 99/09/13 21:21:29 + +Modified files: + . : Makefile api.c api.h blend.c blend.h draw.c + main.c rend.c rend.h + libltdl : Makefile.am Makefile.in acinclude.m4 aclocal.m4 + config.h.in configure configure.in ltdl.c + ltdl.h + +Log message: +add operation type to blend ops.. :) + +_______________________________________________ + +Changes by: mej 99/09/14 17:16:44 + +Modified files: + . : autogen.sh + +Log message: +*sigh* + +This should fix those weird autogen.sh problems. Apparently +automake --copy thinks it fails even though it really doesn't. + +_______________________________________________ + +Changes by: raster 99/09/14 18:15:55 + +Modified files: + . : blend.c main.c + +Log message: +oooh more blending and operation code :) + +_______________________________________________ + +Changes by: raster 99/09/14 18:23:00 + +Modified files: + . : autogen.sh + +Log message: +better autogen.sh comments to help you build imlib2 + +_______________________________________________ + +Changes by: raster 99/09/14 18:24:28 + +Modified files: + . : autogen.sh + +Log message: +some mroe echos... + +_______________________________________________ + +Changes by: raster 99/09/16 18:31:57 + +Modified files: + . : Makefile Makefile.am api.c api.h blend.c rend.c +Added files: + . : updates.c updates.h + +Log message: +added updates work.. well starting on it.. :) + +_______________________________________________ + +Changes by: raster 99/09/16 18:47:49 + +Modified files: + . : updates.c + +Log message: +more wokr on updates + +_______________________________________________ + +Changes by: raster 99/09/18 00:50:37 + +Modified files: + . : Makefile Makefile.am api.c api.h image.c main.c + rgbadraw.c rgbadraw.h updates.c + +Log message: +lots of new image manipulation functions and minor fix in loader module code. + +_______________________________________________ + +Changes by: raster 99/09/18 09:40:24 + +Added files: + . : colormod.c colormod.h config.h loaderpath.h + +Log message: +add some files + +_______________________________________________ + +Changes by: raster 99/09/18 09:41:59 + +Removed files: + . : config.h loaderpath.h + +Log message: +rewmove files i didnt mean tot add + +_______________________________________________ + +Changes by: raster 99/09/18 23:28:54 + +Modified files: + . : Makefile api.c api.h blend.c blend.h file.c + image.c image.h loader_jpeg.c loader_png.c + main.c rend.c rgbadraw.c scale.c + libltdl : Makefile.am Makefile.in acinclude.m4 aclocal.m4 + config.h.in configure configure.in ltdl.c + ltdl.h + +Log message: +cleaned up code a bit... :) minor speedup for sparse (lost of transparent +bits in images) for alpha blending :) + +_______________________________________________ + +Changes by: raster 99/09/19 11:33:15 + +Modified files: + . : rgba.c + +Log message: +get rid of extra space + +_______________________________________________ + +Changes by: raster 99/09/19 13:05:23 + +Modified files: + . : api.c api.h color.c color.h main.c + +Log message: +ok- fix depth retireval code :) + +_______________________________________________ + +Changes by: raster 99/09/19 14:00:17 + +Modified files: + . : loader_png.c + +Log message: +try make png laoder work on big endian... :) + +_______________________________________________ + +Changes by: raster 99/09/19 14:18:15 + +Modified files: + . : loader_png.c + +Log message: +and one mroe fix for big endian boxes for imlib png loader + +_______________________________________________ + +Changes by: raster 99/09/19 14:22:21 + +Modified files: + . : loader_png.c + +Log message: +and add soem comments + +_______________________________________________ + +Changes by: raster 99/09/19 14:43:59 + +Modified files: + . : rend.c + +Log message: +fix 15/16bpp depth problems + +_______________________________________________ + +Changes by: raster 99/09/19 14:53:59 + +Modified files: + . : configure.in loader_png.c rgba.c + +Log message: +let autoconf figure out our endianess + +_______________________________________________ + +Changes by: raster 99/09/19 14:56:55 + +Modified files: + . : Makefile Makefile.am + +Log message: +make install isnot system loader dirs + +_______________________________________________ + +Changes by: raster 99/09/19 14:57:37 + +Modified files: + . : autogen.sh + +Log message: +update autogen.sh + +_______________________________________________ + +Changes by: raster 99/09/19 15:05:59 + +Modified files: + . : main.c + +Log message: +fix main.c + +_______________________________________________ + +Changes by: raster 99/09/26 14:36:51 + +Modified files: + . : api.c api.h color.c color.h common.h main.c + rend.c rgbadraw.c updates.c + +Log message: +make imlib2 demo event based - test rect combining code in handling exposures +and stuff - works it seesm - need to expand api though... expose handlign works +fine as does rect mergeing and stuff.. must more efficient updating method now +for demo.. template for stuff to be used by apps later :) + +_______________________________________________ + +Changes by: raster 99/09/26 21:33:58 + +Modified files: + . : Makefile.am api.c api.h +Added files: + . : font.c font.h format.c format.h + +Log message: +add some files... + +_______________________________________________ + +Changes by: raster 99/09/26 22:24:42 + +Modified files: + . : Makefile font.c font.h + +Log message: +more font stuff + +_______________________________________________ + +Changes by: raster 99/09/27 08:16:52 + +Modified files: + . : Makefile Makefile.am font.c font.h + +Log message: +more code for font stugff being added.. more to come... + +_______________________________________________ + +Changes by: raster 99/09/27 08:19:11 + +Removed files: + . : Makefile + +Log message: +why did i have a Makefile in cvs ? + +_______________________________________________ + +Changes by: raster 99/09/27 15:47:45 + +imlib2/ttfonts + +Update of /cvs/enlightenment/imlib2/ttfonts +In directory ford:/tmp/cvs-serv11657/ttfonts + +Log Message: +Directory /cvs/enlightenment/imlib2/ttfonts added to the repository + +_______________________________________________ + +Changes by: raster 99/09/27 15:52:03 + +Modified files: + . : api.h font.c main.c ximage.c +Added files: + ttfonts : Gadzoox.ttf Glypic.ttf Lemonfnt.ttf + Tejartchi.ttf Terminator.ttf Virginlo.ttf + adlib.ttf andes.ttf angular.ttf anklepants.ttf + arabian.ttf arnprior.ttf asimov.ttf + aurabesh.ttf autobot.ttf axaxax.ttf axaxaxl.ttf + badfilms.ttf balconyangels.ttf baltar.ttf + baltar01.ttf bastarda.ttf battlest.ttf + battlestar.ttf beebop.ttf beebopp.ttf + bellbottomlaser.ttf berliner.ttf bevel.ttf + bigfish.ttf bitchin.ttf blackadderii.ttf + blackforest.ttf bloodofdracula.ttf bloody.ttf + blueregular.ttf bookworm.ttf branson.ttf + burnout.ttf busorama.ttf + butterflychromosome.ttf calligrapher.ttf + cardas1.ttf carrdin2.ttf carrding.ttf + carrelec.ttf carrkeys.ttf casloninitials.ttf + celticmd.ttf checkbk.ttf chemicalgus.ttf + choc.ttf chromosomelight.ttf cinema.ttf + cld_____.ttf comics.ttf competitor.ttf + computerfont.ttf crackbabies.ttf crackman.ttf + crapola.ttf crysta.ttf crystalradiokit.ttf + ctype.ttf cupertino.ttf dazzleships.ttf + decaying.ttf deceptgr.ttf demonnight.ttf + diamondgothic.ttf dienasty.ttf + dirtybakersdozen.ttf dogsonmars.ttf dolphin.ttf + down.ttf dragonwick.ttf duedate.ttf + dustmites.ttf dutchtreat.ttf eccentrical.ttf + elbjorgscript.ttf electrichermes.ttf enya.ttf + erasure.ttf fleur_tt.ttf flouridebeings.ttf + flytningar.ttf frowf___.ttf gaeil1.ttf + galab___.ttf galactic.ttf gardenparty.ttf + gathora.ttf glazkrak.ttf glypic.ttf goethe.ttf + goldengirdle.ttf goofball.ttf grease.ttf + grunge.ttf hackers.ttf handwriting.ttf + headhunter.ttf heavyheap.ttf hirosh.ttf + hman.ttf hman2.ttf holstein.ttf huskystash.ttf + hydrogenwhiskey.ttf id4.ttf igloo.ttf + inavelkusin.ttf inavelmutant.ttf + incantation.ttf induction2.ttf instanttunes.ttf + invisiblekiller.ttf joycircuit.ttf joystix.ttf + karloff.ttf kewken.ttf khaf____.ttf + khan____.ttf khb_____.ttf khf_____.ttf + khl_____.ttf kho_____.ttf kiloton.ttf + kingarthur.ttf kissmekissmekissme.ttf + klingonblade.ttf klingonscript.ttf kontrast.ttf + kurtrussell.ttf lansbury.ttf lavalava.ttf + lemonfnt.ttf lochen.ttf lockergn.ttf + lockergnome.ttf logger.ttf lombardic.ttf + lombnarr.ttf lowereastside.ttf + lowerwestside.ttf lunauror.ttf lunaurora.ttf + lynx.ttf machuman.ttf magdelena.ttf + marqueem.ttf massiveretaliation.ttf mechoba.ttf + metallord.ttf mickey.ttf minya.ttf monst___.ttf + monstro.ttf morpheus.ttf nasalization.ttf + neon2.ttf newworldvibes.ttf nightcourt.ttf + nine____.ttf nosferatu.ttf notepad.ttf + notepad_.ttf oldgermen.ttf oliver.ttf + oliviabrush.ttf ollon.ttf omnibus.ttf + parkavenue.ttf pastorofmuppets.ttf + planetbenson.ttf plasticbag.ttf + pleasantlyplump.ttf plump.ttf popticsone.ttf + popticsoneextras.ttf popticsthree.ttf + popticsthreeextras.ttf popticstwo.ttf + popticstwoextras.ttf pormask2039.ttf prick.ttf + prima.ttf puppf___.ttf purptete.ttf + quadrangle.ttf quake.ttf radiostars.ttf + ransom.ttf rattpick.ttf rebucked.ttf + refluxed.ttf reticulan.ttf reverb.ttf roar.ttf + robokoz.ttf romeo.ttf rotondosilver.ttf + rylodian.ttf saf.ttf sand____.ttf schizm.ttf + scritz.ttf seawfa__.ttf sham.ttf shlop.ttf + singothic.ttf slumberp.ttf snidely.ttf + solsticeofsuffering.ttf spillm~1.ttf + spirits.ttf spongy.ttf spund.ttf squealer.ttf + squire.ttf stonehenge.ttf stop.ttf + superglue.ttf superheterodyne.ttf + taxidermist.ttf thalia.ttf thickhead.ttf + tofu8.ttf tomhand.ttf toontime.ttf topbond.ttf + tosscasu.ttf touchofnature.ttf transylvania.ttf + trash.ttf tron.ttf turkeys.ttf ventilate.ttf + village.ttf virginlo.ttf wacko.ttf warlock.ttf + whitebld.ttf xenowort.ttf xoltoa.ttf yadou.ttf + yoinks.ttf zerohour.ttf + zodillinstrisstirust.ttf + +Log message: +add some test truetype fonts - just for testing... and truetype font +rendering code... :) + +_______________________________________________ + +Changes by: raster 99/09/27 15:52:56 + +Removed files: + ttfonts : zodillinstrisstirust.ttf + +Log message: +bad bad font....... + +_______________________________________________ + +Changes by: raster 99/09/27 15:55:56 + +Modified files: + . : main.c +Removed files: + ttfonts : instanttunes.ttf + +Log message: +actualyl chekc if the font laod works and remove another bad font + +_______________________________________________ + +Changes by: raster 99/09/27 16:09:07 + +Removed files: + ttfonts : Tejartchi.ttf beebop.ttf beebopp.ttf bevel.ttf + blackadderii.ttf carrelec.ttf computerfont.ttf + crysta.ttf galab___.ttf handwriting.ttf + lynx.ttf omnibus.ttf popticsthree.ttf + popticsthreeextras.ttf transylvania.ttf + +Log message: +get rid of soem useless fonts... + +_______________________________________________ + +Changes by: raster 99/09/27 16:09:55 + +Removed files: + ttfonts : cld_____.ttf fleur_tt.ttf frowf___.ttf + khaf____.ttf khan____.ttf khb_____.ttf + khf_____.ttf khl_____.ttf kho_____.ttf + monst___.ttf nine____.ttf notepad_.ttf + puppf___.ttf sand____.ttf seawfa__.ttf + +Log message: +get rid of silyl fonts with silyl names... i hate those names... :) + +_______________________________________________ + +Changes by: raster 99/09/27 16:12:12 + +Removed files: + ttfonts : hman2.ttf + +Log message: +this font segfaults freetype.. ooh nice freetype :) + +_______________________________________________ + +Changes by: raster 99/09/27 16:17:22 + +Removed files: + ttfonts : calligrapher.ttf inavelmutant.ttf + nasalization.ttf + +Log message: +nuke some more unusable fonts :) + +_______________________________________________ + +Changes by: raster 99/09/27 17:03:20 + +Removed files: + ttfonts : bastarda.ttf + +Log message: +another useless font + +_______________________________________________ + +Changes by: raster 99/09/27 17:33:23 + +Removed files: + ttfonts : Terminator.ttf carrdin2.ttf carrding.ttf + carrkeys.ttf gaeil1.ttf goldengirdle.ttf + klingonblade.ttf kontrast.ttf lockergn.ttf + planetbenson.ttf popticstwo.ttf pormask2039.ttf + quake.ttf refluxed.ttf reverb.ttf roar.ttf + saf.ttf stop.ttf + +Log message: +remove some more useless fonts + +_______________________________________________ + +Changes by: raster 99/09/27 17:36:41 + +Modified files: + . : font.c main.c + +Log message: +some fixes to font code... :) + +_______________________________________________ + +Changes by: raster 99/09/27 19:13:50 + +Modified files: + . : font.c font.h main.c + +Log message: +fix raster map over-allocation problem for fonts.. :) + +_______________________________________________ + +Changes by: raster 99/09/27 19:22:57 + +Modified files: + . : font.c font.h + +Log message: +add prototypes and cleanup unused vars + +_______________________________________________ + +Changes by: raster 99/09/27 23:59:55 + +Modified files: + . : font.c + +Log message: +you mightnt guess it - but rotated text all works now.. :) + +_______________________________________________ + +Changes by: raster 99/09/28 11:51:08 + +Modified files: + . : api.c api.h font.c updates.c updates.h + +Log message: +fix ups some toehr stuff... + +_______________________________________________ + +Changes by: raster 99/09/28 16:08:40 + +Modified files: + . : font.c main.c + +Log message: +some fixes to get the output nextx and nexty right... :) + +_______________________________________________ + +Changes by: raster 99/09/28 16:48:39 + +Modified files: + . : api.c api.h font.c font.h main.c + +Log message: +add some of the font api to the api :) + +_______________________________________________ + +Changes by: raster 99/09/29 10:25:52 + +Modified files: + . : api.c api.h font.c font.h main.c + +Log message: +add speculative fotn cache ability - just like we have for images and pixmaps +and ximages. + +_______________________________________________ + +Changes by: raster 99/09/29 11:10:14 + +Modified files: + . : api.c api.h font.c font.h + +Log message: +add actual api.h calls to the font caching stuff... + +_______________________________________________ + +Changes by: raster 99/09/30 09:46:04 + +Modified files: + . : main.c rgbadraw.c + +Log message: +we have... anti-aliased line drawing code now... :) (and funnily enough - +UNLIKE gimp it actually CAN draw a straight line for shit with anti-aliasing) + +_______________________________________________ + +Changes by: raster 99/10/21 10:07:21 + +Modified files: + . : api.c api.h blend.c blend.h colormod.c + colormod.h common.h draw.c font.c font.h grab.c + image.c image.h rend.c rgbadraw.c ximage.c + libltdl : Makefile.am Makefile.in acinclude.m4 aclocal.m4 + config.h.in configure configure.in ltdl.c + ltdl.h + +Log message: +color modifiers in imlib2 now done.. cleaned up soem code... + +_______________________________________________ + +Changes by: mandrake 99/10/22 04:19:11 + +Modified files: + . : api.h file.h font.c grab.c loader_jpeg.c + loader_png.c main.c rgbadraw.c rgbadraw.h + libltdl : Makefile.am Makefile.in acinclude.m4 aclocal.m4 + config.h.in configure configure.in ltdl.c + ltdl.h +Added files: + . : ChangeLog + +Log message: +Fri Oct 22 10:53:26 PDT 1999 +(Mandrake) + +removed almost all the warnings. +except for: +main.c:287: warning: implicit declaration of function `__imlib_draw_line' +which I believe is because it's not using the appropriate API call yet. + +_______________________________________________ + +Changes by: raster 99/10/22 04:40:45 + +Modified files: + . : api.h + +Log message: +again........ :) + +_______________________________________________ + +Changes by: raster 99/10/25 09:36:24 + +Modified files: + . : Makefile.am api.c api.h image.h main.c + rgbadraw.c rgbadraw.h + libltdl : ltdl.c + +Log message: +work work work... + +_______________________________________________ + +Changes by: raster 99/10/25 16:30:01 + +Modified files: + . : draw.c image.c + +Log message: +more flim + +_______________________________________________ + +Changes by: raster 99/10/25 16:30:46 + +Modified files: + . : api.c api.h image.h + +Log message: +more flim code..... >8) + +_______________________________________________ + +Changes by: raster 99/10/27 06:48:39 + +Modified files: + . : rgba.c + +Log message: +memcpy :) + +_______________________________________________ + +Changes by: raster 99/10/27 07:08:32 + +Modified files: + . : api.c api.h main.c +Added files: + . : grad.c grad.h + +Log message: +nice FAST gradient drawing code.... :) eat my dast... MUHAHAHAHAHHA! :) + +_______________________________________________ + +Changes by: raster 99/10/27 07:20:27 + +Modified files: + . : api.c api.h + +Log message: +pixel query call.... need this one + +_______________________________________________ + +Changes by: raster 99/10/27 10:44:15 + +Modified files: + . : api.c main.c + +Log message: +and the flim goes on.......... + +_______________________________________________ + +Changes by: raster 99/10/28 03:40:02 + +Modified files: + . : color.c + +Log message: +dont chose visuals > 24bit :) + +_______________________________________________ + +Changes by: mandrake 99/10/28 06:09:03 + +Added files: + libltdl : .cvsignore +Removed files: + libltdl : configure + +Log message: +trying to "fix" imlib2's cvs tree + +_______________________________________________ + +Changes by: mandrake 99/10/28 06:11:27 + +Added files: + . : .cvsignore + +Log message: +more "hush yo mouf cvs" changes + +_______________________________________________ + +Changes by: raster 99/10/28 08:26:19 + +Modified files: + . : api.c api.h blend.c grab.c + +Log message: +LOTS of checkign in the api now to make sure the calling program can't stuff +things up too badly... + +_______________________________________________ + +Changes by: raster 99/10/28 10:43:42 + +Removed files: + test_images : im.png im_rgb.png + +Log message: +get rid of images i'm nto using... + +_______________________________________________ + +Changes by: raster 99/10/28 16:04:27 + +Modified files: + . : api.h main.c + test_images : bg.png + +Log message: +better api.h + +_______________________________________________ + +Changes by: raster 99/10/29 02:11:58 + +Modified files: + . : rgbadraw.c + +Log message: +oooooooooops - thanks hans! :) + +_______________________________________________ + +Changes by: raster 99/10/29 03:39:09 + +Modified files: + . : color.h + +Log message: +dont need that fixme.. + +_______________________________________________ + +Changes by: raster 99/10/30 04:22:48 + +Modified files: + . : main.c rgba.c + libltdl : Makefile.am Makefile.in acinclude.m4 aclocal.m4 + config.h.in configure.in ltdl.c ltdl.h + +Log message: +speed testing code back.. just testing... + +_______________________________________________ + +Changes by: raster 99/10/30 04:54:01 + +Modified files: + . : loader_png.c + +Log message: +try this.. + +_______________________________________________ + +Changes by: raster 99/10/30 10:41:08 + +Modified files: + . : blend.c + +Log message: +optmiseeeeeeeeeeeeeeeeeee. :) + +_______________________________________________ + +Changes by: mandrake 99/10/31 11:45:23 + +Modified files: + . : ChangeLog + libltdl : .cvsignore +Removed files: + libltdl : Makefile.am Makefile.in acinclude.m4 aclocal.m4 + config.h.in configure.in ltdl.c ltdl.h + +Log message: +Sun Oct 31 20:21:13 PST 1999 +(Mandrake) + +libltdl (large chunks of it) is automatically generated by autogen.sh. +no need for those files to be in CVS. + +_______________________________________________ + +Changes by: mandrake 99/10/31 11:50:50 + +Modified files: + . : rgba.c + +Log message: +removed a warning + +_______________________________________________ + +Changes by: raster 99/10/31 14:50:06 + +Modified files: + . : blend.c + +Log message: +eeek math error at 255 (becomes 254) not surprising i didnt notice.. i +looked at the results rsather than numerically evaluating... + +_______________________________________________ + +Changes by: raster 99/10/31 15:08:18 + +Modified files: + . : grab.c rend.c rgba.c rgba.h + +Log message: +and handle ABGR ordering in 24/32bpp + +_______________________________________________ + +Changes by: raster 99/11/01 02:00:06 + +Modified files: + . : api.c api.h blend.c image.c image.h + +Log message: +added ability to attach integert vlue and data poitner tags to images by +string keys (with destructors optional) - wil be used for saving of images +(savers will look for these keys to gleen parameters for saaving) + +_______________________________________________ + +Changes by: raster 99/11/01 02:07:14 + +Modified files: + . : grad.c main.c rgbadraw.c + +Log message: +fix some minro roundoff problems as before... + +_______________________________________________ + +Changes by: raster 99/11/01 03:05:17 + +Modified files: + . : blend.c grad.c rgbadraw.c + +Log message: +udless &'s + +_______________________________________________ + +Changes by: raster 99/11/01 04:11:30 + +Modified files: + . : ChangeLog image.c image.h +Added files: + . : TODO + +Log message: +add TODO... + +_______________________________________________ + +Changes by: raster 99/11/01 06:35:25 + +Modified files: + . : api.c api.h image.c image.h + +Log message: +structure for savign all done - now just need to fill in the save() functions +in the loaders (yes laoder are also savers - loader and saver are +interchangeable). + +_______________________________________________ + +Changes by: raster 99/11/01 07:27:34 + +Modified files: + . : api.c image.c loader_jpeg.c main.c + +Log message: +we have a jpeg saver and the saver code works + +_______________________________________________ + +Changes by: raster 99/11/01 07:30:56 + +Modified files: + . : image.c + +Log message: +whee more robus tagging... + +_______________________________________________ + +Changes by: raster 99/11/01 08:14:00 + +Modified files: + . : image.c loader_png.c main.c + +Log message: +and now it all works... + +_______________________________________________ + +Changes by: raster 99/11/01 08:15:37 + +Modified files: + . : main.c + +Log message: +flim + +_______________________________________________ + +Changes by: raster 99/11/01 08:34:01 + +Modified files: + . : blend.c + +Log message: +and now thats all better. + +_______________________________________________ + +Changes by: raster 99/11/01 08:52:52 + +Modified files: + . : blend.c + +Log message: +fix that........ + +_______________________________________________ + +Changes by: raster 99/11/01 08:54:49 + +Modified files: + . : blend.c + +Log message: +fix that bitchift.. + +_______________________________________________ + +Changes by: raster 99/11/01 09:12:39 + +imlib2/loaders + +Update of /cvs/enlightenment/imlib2/loaders +In directory ford:/tmp/cvs-serv13720/loaders + +Log Message: +Directory /cvs/enlightenment/imlib2/loaders added to the repository + +_______________________________________________ + +Changes by: raster 99/11/01 09:12:40 + +imlib2/src + +Update of /cvs/enlightenment/imlib2/src +In directory ford:/tmp/cvs-serv13720/src + +Log Message: +Directory /cvs/enlightenment/imlib2/src added to the repository + +_______________________________________________ + +Changes by: raster 99/11/01 09:40:51 + +Modified files: + . : Makefile.am configure.in +Added files: + loaders : Makefile.am loader_jpeg.c loader_png.c + src : Imlib2.h Makefile.am api.c blend.c blend.h + color.c color.h colormod.c colormod.h common.h + context.c context.h draw.c draw.h file.c file.h + font.c font.h format.c format.h grab.c grab.h + grad.c grad.h image.c image.h main.c rend.c + rend.h rgba.c rgba.h rgbadraw.c rgbadraw.h + scale.c scale.h updates.c updates.h ximage.c + ximage.h +Removed files: + . : api.c api.h blend.c blend.h color.c color.h + colormod.c colormod.h common.h context.c + context.h draw.c draw.h file.c file.h font.c + font.h format.c format.h grab.c grab.h grad.c + grad.h image.c image.h loader_jpeg.c + loader_png.c main.c rend.c rend.h rgba.c rgba.h + rgbadraw.c rgbadraw.h scale.c scale.h updates.c + updates.h ximage.c ximage.h + +Log message: +re-structure...... + +_______________________________________________ + +Changes by: raster 99/11/01 09:41:03 + +imlib2/test + +Update of /cvs/enlightenment/imlib2/test +In directory ford:/tmp/cvs-serv14123/test + +Log Message: +Directory /cvs/enlightenment/imlib2/test added to the repository + +_______________________________________________ + +Changes by: raster 99/11/01 09:47:48 + +imlib2/test/test_images + +Update of /cvs/enlightenment/imlib2/test/test_images +In directory ford:/tmp/cvs-serv14183/test_images + +Log Message: +Directory /cvs/enlightenment/imlib2/test/test_images added to the repository + +_______________________________________________ + +Changes by: raster 99/11/01 09:48:23 + +imlib2/test/ttfonts + +Update of /cvs/enlightenment/imlib2/test/ttfonts +In directory ford:/tmp/cvs-serv14198/ttfonts + +Log Message: +Directory /cvs/enlightenment/imlib2/test/ttfonts added to the repository + +_______________________________________________ + +Changes by: raster 99/11/01 09:49:59 + +Modified files: + . : configure.in +Added files: + test : Makefile.am main.c + test/test_images: audio.png bg.png bulb.png cal.png calc.png + folder.png globe.png lock.png mail.png + menu.png mush.png paper.png sh1.png sh2.png + sh3.png stop.png tnt.png + test/ttfonts : cinema.ttf grunge.ttf morpheus.ttf notepad.ttf +Removed files: + src : main.c + test_images : audio.png bg.png bulb.png cal.png calc.png + folder.png globe.png lock.png mail.png menu.png + mush.png paper.png sh1.png sh2.png sh3.png + stop.png tnt.png + ttfonts : Gadzoox.ttf Glypic.ttf Lemonfnt.ttf + Virginlo.ttf adlib.ttf andes.ttf angular.ttf + anklepants.ttf arabian.ttf arnprior.ttf + asimov.ttf aurabesh.ttf autobot.ttf axaxax.ttf + axaxaxl.ttf badfilms.ttf balconyangels.ttf + baltar.ttf baltar01.ttf battlest.ttf + battlestar.ttf bellbottomlaser.ttf berliner.ttf + bigfish.ttf bitchin.ttf blackforest.ttf + bloodofdracula.ttf bloody.ttf blueregular.ttf + bookworm.ttf branson.ttf burnout.ttf + busorama.ttf butterflychromosome.ttf + cardas1.ttf casloninitials.ttf celticmd.ttf + checkbk.ttf chemicalgus.ttf choc.ttf + chromosomelight.ttf cinema.ttf comics.ttf + competitor.ttf crackbabies.ttf crackman.ttf + crapola.ttf crystalradiokit.ttf ctype.ttf + cupertino.ttf dazzleships.ttf decaying.ttf + deceptgr.ttf demonnight.ttf diamondgothic.ttf + dienasty.ttf dirtybakersdozen.ttf + dogsonmars.ttf dolphin.ttf down.ttf + dragonwick.ttf duedate.ttf dustmites.ttf + dutchtreat.ttf eccentrical.ttf + elbjorgscript.ttf electrichermes.ttf enya.ttf + erasure.ttf flouridebeings.ttf flytningar.ttf + galactic.ttf gardenparty.ttf gathora.ttf + glazkrak.ttf glypic.ttf goethe.ttf goofball.ttf + grease.ttf grunge.ttf hackers.ttf + headhunter.ttf heavyheap.ttf hirosh.ttf + hman.ttf holstein.ttf huskystash.ttf + hydrogenwhiskey.ttf id4.ttf igloo.ttf + inavelkusin.ttf incantation.ttf induction2.ttf + invisiblekiller.ttf joycircuit.ttf joystix.ttf + karloff.ttf kewken.ttf kiloton.ttf + kingarthur.ttf kissmekissmekissme.ttf + klingonscript.ttf kurtrussell.ttf lansbury.ttf + lavalava.ttf lemonfnt.ttf lochen.ttf + lockergnome.ttf logger.ttf lombardic.ttf + lombnarr.ttf lowereastside.ttf + lowerwestside.ttf lunauror.ttf lunaurora.ttf + machuman.ttf magdelena.ttf marqueem.ttf + massiveretaliation.ttf mechoba.ttf + metallord.ttf mickey.ttf minya.ttf monstro.ttf + morpheus.ttf neon2.ttf newworldvibes.ttf + nightcourt.ttf nosferatu.ttf notepad.ttf + oldgermen.ttf oliver.ttf oliviabrush.ttf + ollon.ttf parkavenue.ttf pastorofmuppets.ttf + plasticbag.ttf pleasantlyplump.ttf plump.ttf + popticsone.ttf popticsoneextras.ttf + popticstwoextras.ttf prick.ttf prima.ttf + purptete.ttf quadrangle.ttf radiostars.ttf + ransom.ttf rattpick.ttf rebucked.ttf + reticulan.ttf robokoz.ttf romeo.ttf + rotondosilver.ttf rylodian.ttf schizm.ttf + scritz.ttf sham.ttf shlop.ttf singothic.ttf + slumberp.ttf snidely.ttf + solsticeofsuffering.ttf spillm~1.ttf + spirits.ttf spongy.ttf spund.ttf squealer.ttf + squire.ttf stonehenge.ttf superglue.ttf + superheterodyne.ttf taxidermist.ttf thalia.ttf + thickhead.ttf tofu8.ttf tomhand.ttf + toontime.ttf topbond.ttf tosscasu.ttf + touchofnature.ttf trash.ttf tron.ttf + turkeys.ttf ventilate.ttf village.ttf + virginlo.ttf wacko.ttf warlock.ttf whitebld.ttf + xenowort.ttf xoltoa.ttf yadou.ttf yoinks.ttf + zerohour.ttf + +Log message: +restructure the direcotry a bit....... + +_______________________________________________ + +Changes by: raster 99/11/01 10:00:02 + +Modified files: + . : configure.in + +Log message: +fix the version + +_______________________________________________ + +Changes by: raster 99/11/01 10:05:48 + +Modified files: + . : README + +Log message: +update README + +_______________________________________________ + +Changes by: raster 99/11/01 10:06:33 + +Added files: + loaders : .cvsignore + src : .cvsignore + test : .cvsignore + +Log message: +add ignores...... + +_______________________________________________ + +Changes by: raster 99/11/01 10:07:34 + +Modified files: + . : .cvsignore + +Log message: +more in ignore + +_______________________________________________ + +Changes by: raster 99/11/01 10:10:30 + +Modified files: + loaders : loader_png.c + +Log message: +handle progress callback for saving in png loader.. + +_______________________________________________ + +Changes by: raster 99/11/01 10:12:42 + +Modified files: + test : main.c + +Log message: +stop testing saving.. it works.. + +_______________________________________________ + +Changes by: raster 99/11/01 10:13:02 + +Modified files: + src : blend.c + +Log message: +no printf + +_______________________________________________ + +Changes by: raster 99/11/01 10:45:29 + +Modified files: + loaders : Makefile.am loader_jpeg.c loader_png.c + src : image.c +Added files: + loaders : loader_pnm.c + +Log message: +starting on pnm loader (ppm, pgm pbm, pam) - will finish later... + +_______________________________________________ + +Changes by: raster 99/11/01 10:46:23 + +Modified files: + loaders : Makefile.am + +Log message: +oops makefile...... + +_______________________________________________ + +Changes by: raster 99/11/01 12:50:16 + +Modified files: + loaders : loader_pnm.c + +Log message: +hmm that didnt compile.. ooh fun :) + +_______________________________________________ + +Changes by: raster 99/11/01 16:24:17 + +Modified files: + loaders : loader_pnm.c + +Log message: +pnm loader handles binary formats allright... :) + +_______________________________________________ + +Changes by: raster 99/11/01 16:53:45 + +Modified files: + loaders : loader_pnm.c + +Log message: +binary png loaders done..plus speculating on the P8 format... dont like it +much... i think ineed a FAST trivial to load ARGB format. + +_______________________________________________ + +Changes by: raster 99/11/02 00:25:18 + +Modified files: + loaders : loader_pnm.c + +Log message: +pnm loader can save now... + +_______________________________________________ + +Changes by: raster 99/11/02 02:16:50 + +Modified files: + loaders : Makefile.am loader_pnm.c + src : api.c + test : main.c +Added files: + loaders : loader_argb.c + +Log message: +argb format loader & saver. my own format just so i can load and save raw ARGB +data blindingly fast for imlib2 :) + +_______________________________________________ + +Changes by: raster 99/11/02 02:17:07 + +Modified files: + test : main.c + +Log message: +get rid of saver func + +_______________________________________________ + +Changes by: raster 99/11/02 02:46:34 + +imlib2/demo + +Update of /cvs/enlightenment/imlib2/demo +In directory ford:/tmp/cvs-serv28365/demo + +Log Message: +Directory /cvs/enlightenment/imlib2/demo added to the repository + +_______________________________________________ + +Changes by: raster 99/11/02 03:12:59 + +Modified files: + . : configure.in + src : rgbadraw.c +Added files: + demo : Makefile.am view.c + +Log message: +oops - fix that filled rect drawing code + +_______________________________________________ + +Changes by: raster 99/11/02 03:13:59 + +Added files: + demo : .cvsignore + +Log message: +add ignores....... + +_______________________________________________ + +Changes by: raster 99/11/02 05:32:40 + +Modified files: + demo : view.c + loaders : loader_argb.c loader_jpeg.c loader_pnm.c + src : rend.c + +Log message: +fix a little of the rend code - never testyed that bit... +andf the imlib2_view works nicely iwth zooming too :) + +_______________________________________________ + +Changes by: raster 99/11/02 06:34:48 + +Modified files: + demo : view.c + +Log message: +primitive timeout.. its not even that good.. :) + +_______________________________________________ + +Changes by: raster 99/11/02 06:42:05 + +Modified files: + demo : view.c + +Log message: +now that works better + +_______________________________________________ + +Changes by: raster 99/11/02 07:29:52 + +Modified files: + . : configure.in + +Log message: +Makefile NOT Makefil ! :) + +_______________________________________________ + +Changes by: raster 99/11/02 07:56:23 + +Modified files: + . : Makefile.am +Added files: + . : imlib2.spec + +Log message: +more correct makefile.am in base........ + +_______________________________________________ + +Changes by: raster 99/11/03 08:21:02 + +Modified files: + demo : Makefile.am + src : blend.c +Added files: + demo : blend.c + +Log message: +add soem stuff and new blend.c from ryan :) + +_______________________________________________ + +Changes by: raster 99/11/03 08:22:21 + +Modified files: + src : blend.c + +Log message: +again.......... + +_______________________________________________ + +Changes by: raster 99/11/04 01:02:58 + +Modified files: + src : Imlib2.h api.c + +Log message: +mising 2 important calls inthe font code... :) + +_______________________________________________ + +Changes by: raster 99/11/04 08:20:08 + +Modified files: + src : font.c + +Log message: +ooooooooops :) + +_______________________________________________ + +Changes by: raster 99/11/07 00:51:47 + +Modified files: + . : COPYING + demo : blend.c + src : blend.c blend.h font.c rend.c +Added files: + . : AUTHORS + +Log message: +added AUTHORS file.. fixed copyting.... + +_______________________________________________ + +Changes by: raster 99/11/13 10:55:40 + +Modified files: + src : blend.c + +Log message: +oopsie in blend.c + +_______________________________________________ + +Changes by: raster 99/11/15 16:06:54 + +Modified files: + src : rgbadraw.c + +Log message: +oop s- clipping problme wiht lines.. fixed :) + +_______________________________________________ + +Changes by: raster 99/11/16 16:01:58 + +Modified files: + src : api.c + +Log message: +oh oops - image blending whilst scaling want quite right in the api.. :) + +_______________________________________________ + +Changes by: raster 99/11/18 23:42:21 + +Modified files: + src : grad.c + +Log message: +ok - gradients now dont overflow the precision buffer as badly.. :) + +_______________________________________________ + +Changes by: raster 99/12/02 13:02:01 + +Modified files: + src : image.c + +Log message: +oops saver does rescan loader - so unless you laoded an image no laoders +will be around... and it wont get rescanned on save.. :) + +_______________________________________________ + +Changes by: raster 99/12/07 09:28:53 + +Modified files: + src : Imlib2.h api.c + test : main.c + +Log message: +lets break the Imlib2 api and chnage it... now its context based.. :) + +_______________________________________________ + +Changes by: raster 99/12/07 09:30:01 + +Modified files: + . : configure.in + src : Makefile.am + +Log message: +just up the versions to show i did something... :) + +_______________________________________________ + +Changes by: raster 99/12/07 09:30:56 + +Modified files: + . : imlib2.spec + +Log message: +spec file too... + +_______________________________________________ + +Changes by: raster 99/12/07 10:02:48 + +Modified files: + test : main.c + +Log message: +test program back to normal.. nwo works with api changes... + +_______________________________________________ + +Changes by: raster 99/12/07 10:20:57 + +Modified files: + demo : Makefile.am view.c +Removed files: + demo : blend.c + +Log message: +fixe view to compile & work + +_______________________________________________ + +Changes by: raster 99/12/07 10:28:51 + +Modified files: + demo : Makefile.am view.c + +Log message: +imlib2_view works again... + +_______________________________________________ + +Changes by: raster 99/12/10 04:34:12 + +Modified files: + src : api.c + +Log message: +oops :) fixed :) + +_______________________________________________ + +Changes by: raster 99/12/10 06:26:13 + +Modified files: + . : configure.in + +Log message: +blum + +_______________________________________________ + +Changes by: raster 99/12/10 06:27:54 + +Modified files: + src : api.c font.c + +Log message: +more blum - bloody freetype - why does debian have to go move the headre to a +different location to where it always was? + +_______________________________________________ + +Changes by: raster 99/12/10 06:30:10 + +Modified files: + src : api.c font.c + +Log message: +compile damnit... + +_______________________________________________ + +Changes by: raster 99/12/10 06:31:32 + +Modified files: + src : font.c + +Log message: +include config.h + +_______________________________________________ + +Changes by: raster 99/12/14 01:18:24 + +Modified files: + src : blend.c colormod.h + +Log message: +fix fix fix fix......................... :) + +_______________________________________________ + +Changes by: raster 99/12/17 07:37:20 + +Modified files: + . : configure.in + loaders : Makefile.am + +Log message: +create .a's :) + +_______________________________________________ + +Changes by: llane 99/12/19 13:05:33 + +imlib2/debian + +Update of /cvs/enlightenment/imlib2/debian +In directory ford:/tmp/cvs-serv24002/debian + +Log Message: +Directory /cvs/enlightenment/imlib2/debian added to the repository + +_______________________________________________ + +Changes by: llane 99/12/19 13:08:33 + +Modified files: + debian : changelog +Added files: + debian : changelog control libeconfig0.postinst rules + shlibs.local + debian : changelog control libimlib2.postinst rules + shlibs.local + +Log message: +more preliminary assimilation + +_______________________________________________ + +Changes by: raster 99/12/19 15:03:06 + +Modified files: + loaders : loader_jpeg.c + test : main.c + +Log message: +fix loaders...... + +_______________________________________________ + +Changes by: mej 99/12/21 12:46:42 + +Modified files: + loaders : Makefile.am +Added files: + loaders : loader_gif.c + +Log message: +A GIF loader. There is no save function yet, and you'll need libgif to +use it. + +_______________________________________________ + +Changes by: raster 99/12/22 00:04:00 + +Modified files: + src : Imlib2.h api.c + +Log message: +for acceleration to work i nee to add a parameter to put_back_data + +_______________________________________________ + +Changes by: mej 99/12/22 02:48:31 + +Modified files: + loaders : loader_gif.c + +Log message: +Whoops. Forgot to call the progress callback one last time. + +_______________________________________________ + +Changes by: raster 99/12/23 08:43:26 + +Modified files: + src : api.c + +Log message: +oops typo :) + +_______________________________________________ + +Changes by: raster 99/12/23 15:30:18 + +Modified files: + src : blend.c + +Log message: +fix missing case in scaling for blending objects... + +_______________________________________________ + +Changes by: raster 99/12/26 10:27:05 + +Modified files: + src : blend.c rend.c updates.c + +Log message: +get clipping right... + +_______________________________________________ + +Changes by: raster 00/01/05 02:26:40 + +Modified files: + loaders : loader_gif.c + src : Imlib2.h api.c image.c + +Log message: +add loader flush call and fix gif loader to be able to load when theres no +progress set :) + +_______________________________________________ + +Changes by: raster 00/01/05 04:23:25 + +Modified files: + loaders : loader_png.c + +Log message: +oops - expand indexed images... + +_______________________________________________ + +Changes by: mej 00/01/05 06:28:50 + +Modified files: + loaders : loader_gif.c + +Log message: +Don't ask me how this got out of sync.... + +_______________________________________________ + +Changes by: mej 00/01/05 06:29:58 + +Modified files: + loaders : loader_gif.c + +Log message: +*grumble* + +_______________________________________________ + +Changes by: raster 00/01/05 21:58:21 + +Modified files: + src : font.c + +Log message: +allow full paths for font names too.. + +_______________________________________________ + +Changes by: raster 00/01/05 22:32:45 + +Modified files: + src : font.c + +Log message: +search path for font mroe sanely + +_______________________________________________ + +Changes by: raster 00/01/07 10:40:51 + +Modified files: + src : font.c + +Log message: +dont be so anal abotu ewncodings... if no apple or windows encoding is there +just use encoding charmap 0 :) + +_______________________________________________ + +Changes by: raster 00/01/09 21:41:18 + +Modified files: + src : Imlib2.h api.c image.c + +Log message: +i cant beleieve i missed wrappign the pixmap free function.... + +_______________________________________________ + +Changes by: raster 00/01/09 21:42:41 + +Modified files: + src : api.c + +Log message: +add to header..... + +_______________________________________________ + +Changes by: raster 00/01/09 22:49:20 + +Modified files: + src : Imlib2.h api.c + +Log message: +add dither mask pixmap rendering contexts... + +_______________________________________________ + +Changes by: raster 00/01/10 04:25:14 + +Modified files: + src : Imlib2.h Makefile.am + +Log message: +up version... add c++ usability.. + +_______________________________________________ + +Changes by: raster 00/01/10 19:15:59 + +Modified files: + . : configure.in + +Log message: +updates and fixes.. versioning etc... + +_______________________________________________ + +Changes by: mej 00/01/11 14:42:07 + +Modified files: + loaders : loader_gif.c + +Log message: +Ummm... + +_______________________________________________ + +Changes by: raster 00/01/17 10:20:29 + +Modified files: + src : Imlib2.h api.c + +Log message: +oops - forgort to remove param from imlib_free_color_rangex + +_______________________________________________ + +Changes by: raster 00/01/17 14:21:02 + +Modified files: + loaders : loader_gif.c + +Log message: +put that back... + +_______________________________________________ + +Changes by: mej 00/01/17 14:50:08 + +Modified files: + loaders : loader_gif.c + +Log message: +Put those back. I hate warnings. + +_______________________________________________ + +Changes by: raster 00/01/21 12:36:28 + +Modified files: + src : api.c + +Log message: +2 more checks in save calls for image data... + +_______________________________________________ + +Changes by: raster 00/01/24 09:07:05 + +Modified files: + src : font.c + +Log message: +that was silly! fix fix fix - thanks alan :) + +_______________________________________________ + +Changes by: raster 00/01/24 11:18:17 + +Modified files: + src : font.c + +Log message: +ooops - fix :) + +_______________________________________________ + +Changes by: raster 00/01/25 21:14:38 + +Modified files: + src : rgba.c + +Log message: +endinaness for masks broken onf sparc.. fix... + +_______________________________________________ + +Changes by: raster 00/01/25 21:18:32 + +Modified files: + src : rgba.c + +Log message: +oops typo + +_______________________________________________ + +Changes by: raster 00/01/25 21:25:19 + +Modified files: + src : rgba.c + +Log message: +get enmdianess roight for sparc (and ppc) for masks... + +_______________________________________________ + +Changes by: llane 00/02/02 16:10:14 + +Modified files: + debian : rules + +Log message: +clean target + +_______________________________________________ + +Changes by: raster 00/02/07 09:53:25 + +Modified files: + src : image.c + +Log message: +oopsie - problem with non extension format images :) + +_______________________________________________ + +Changes by: raster 00/02/07 14:04:05 + +Modified files: + src : image.c + +Log message: +oooops - image and pixmap cache baddies.. :( + +_______________________________________________ + +Changes by: raster 00/02/07 14:38:01 + +Modified files: + src : Imlib2.h api.c + +Log message: +const char * + +_______________________________________________ + +Changes by: raster 00/02/19 12:10:37 + +Modified files: + loaders : loader_argb.c + +Log message: +ooops - big eng9ian bug! :) + +_______________________________________________ + +Changes by: mandrake 00/02/22 14:29:17 + +Modified files: + . : configure.in + +Log message: +fixing freetype detection stuff, maybe? + +_______________________________________________ + +Changes by: raster 00/02/27 10:36:26 + +Modified files: + src : Imlib2.h Makefile.am api.c + test : main.c + +Log message: +rotattion code added... :) + +_______________________________________________ + +Changes by: raster 00/02/27 10:37:28 + +Modified files: + . : AUTHORS + +Log message: +authors.. BTW - anyone watching commtis list please check AUTHORS... +if your'e nto listed plese tell me to add you... I never do well maintaining +it. + +_______________________________________________ + +Changes by: raster 00/02/27 11:23:21 + +Added files: + src : loaderpath.h rotate.c rotate.h + +Log message: +add files... + +_______________________________________________ + +Changes by: raster 00/02/27 11:23:36 + +Removed files: + src : loaderpath.h + +Log message: +dont add that1 + +_______________________________________________ + +Changes by: raster 00/03/01 09:04:23 + +Modified files: + src : Imlib2.h api.c rotate.c rotate.h + test : main.c + +Log message: +flum.......... + +_______________________________________________ + +Changes by: raster 00/03/03 08:42:18 + +Modified files: + src : Imlib2.h api.c font.c rgbadraw.c rgbadraw.h + rotate.c + test : main.c + +Log message: +flum + +_______________________________________________ + +Changes by: raster 00/03/03 09:15:51 + +Modified files: + src : Imlib2.h api.c rotate.c rotate.h + +Log message: +better + +_______________________________________________ + +Changes by: raster 00/03/03 09:24:46 + +Modified files: + test : main.c + +Log message: +poatch main.c - but rottest doesnt work.. must fix later + +_______________________________________________ + +Changes by: raster 00/03/03 18:45:09 + +Modified files: + src : api.c + +Log message: +get context patch from tom...... + +_______________________________________________ + +Changes by: llane 00/03/07 09:15:24 + +Modified files: + debian : changelog + +Log message: +stuff + +_______________________________________________ + +Changes by: llane 00/03/07 14:39:28 + +Modified files: + debian : rules + debian : rules + debian : rules + debian : rules + debian : rules + debian : rules + debian : rules + debian : rules + +Log message: +removed dh_testversion + +_______________________________________________ + +Changes by: llane 00/03/07 17:58:06 + +Modified files: + debian : changelog + debian : changelog + debian : changelog rules + debian : changelog + debian : changelog + debian : changelog + debian : changelog + +Log message: +stuff + +_______________________________________________ + +Changes by: mej 00/03/07 20:05:01 + +Modified files: + loaders : Makefile.am +Added files: + loaders : loader_tiff.c + +Log message: +TIFF loader from Eric Dorland . + +_______________________________________________ + +Changes by: mej 00/03/07 22:08:29 + +Modified files: + loaders : Makefile.am +Added files: + loaders : loader_bmp.c + +Log message: +BMP loader from Isaac Richards . It currently has issues +with progressive loading, so don't use it with feh. :-) + +_______________________________________________ + +Changes by: mej 00/03/07 22:11:04 + +Modified files: + . : AUTHORS + +Log message: +Keep raster happy. + +_______________________________________________ + +Changes by: mej 00/03/08 08:20:06 + +Modified files: + loaders : loader_bmp.c + +Log message: +BMP loader fix for progressive loading from Chutt. + +_______________________________________________ + +Changes by: mej 00/03/08 12:01:31 + +Modified files: + loaders : loader_bmp.c + +Log message: +Murple. + +_______________________________________________ + +Changes by: gilbertt 00/03/17 12:54:19 + +Modified files: + loaders : loader_tiff.c + +Log message: +Shaddup ;) + +_______________________________________________ + +Changes by: gilbertt 00/03/17 17:20:55 + +Modified files: + loaders : loader_gif.c + +Log message: +shaddup ;) + +_______________________________________________ + +Changes by: gilbertt 00/03/17 19:37:54 + +Modified files: + loaders : loader_gif.c + +Log message: +AARGH. Godamn file decriptor leak which has been driving me CRAZY for a +WEEK! Got the BASTARD. DIE! + +(what complicated matters was that it only leaked on when it *couldn't* load +the image). + +Please note. there is also a filedes leak in the tiff loader, also when it +fails to load. I haven't been able to fix this yet, because libtiff sucks +ass and has totally encapsulated the file descriptor. Lemme work on it +tomorrow... + +_______________________________________________ + +Changes by: gilbertt 00/03/17 20:12:23 + +Modified files: + src : image.c + +Log message: +Removed a crufty bit. + +_______________________________________________ + +Changes by: gilbertt 00/03/17 20:43:47 + +Modified files: + src : image.c + +Log message: +nothing major + +_______________________________________________ +e-develop mailing list - e-develop@lists.on.openprojects.net + +Changes by: gilbertt 00/03/18 05:07:53 + +Modified files: + loaders : loader_tiff.c + +Log message: +Leak plugged. Thanks Eric :) + +_______________________________________________ + +Changes by: gilbertt 00/03/18 05:56:29 + +Modified files: + src : image.c image.h + +Log message: +Okay. The loader list is now trimmed. Where it would previously contain: +argb.a bmp.a gif.a jpeg.a png.a pnm.a tiff.a +argb.la bmp.la gif.la jpeg.la png.la pnm.la tiff.la +argb.so bmp.so gif.so jpeg.so png.so pnm.so tiff.so + +It now contains: +argb +bmp +gif +jpeg +png +pnm +tiff + +lt_dlopen knows how to do the Right Thing with these, trying first the .la, +then the .so. Now the loaders are each tried once per image (if none of them +manage to load it). + +Added the following functions to achieve this: +char **__imlib_TrimLoaderList(char **list, int *num); +int __imlib_LoaderInList(char **list, int size, char *item); + +_______________________________________________ + +Changes by: gilbertt 00/03/18 06:26:13 + +Modified files: + . : AUTHORS + +Log message: +Bite me =P + +_______________________________________________ + +Changes by: gilbertt 00/03/18 15:45:47 + +Modified files: + loaders : loader_tiff.c + +Log message: +Partial loader_tiff rewrite from Eric Dorland. Much nicer :) + +_______________________________________________ + +Changes by: raster 00/03/19 14:53:42 + +Modified files: + src : blend.c blend.h colormod.c grad.c rgbadraw.c + +Log message: +I'm back....... :) + +_______________________________________________ + +Changes by: raster 00/03/21 01:38:40 + +Modified files: + src : blend.c blend.h + +Log message: +fix cmod....... + +_______________________________________________ + +Changes by: raster 00/03/22 14:26:58 + +Modified files: + src : blend.c blend.h colormod.c colormod.h rotate.h + +Log message: +optmize.. fix endianess stuff... :) + +_______________________________________________ + +Changes by: raster 00/03/24 11:03:24 + +Modified files: + src : blend.c + +Log message: +oops - missed modfifying colros there.. :) + +_______________________________________________ + +Changes by: raster 00/03/24 11:06:01 + +Modified files: + src : api.c rend.c rotate.c rotate.h + +Log message: +rotate speedups - rend bugfix... wheeeeeee + +_______________________________________________ + +Changes by: raster 00/03/25 16:10:46 + +Modified files: + src : blend.h + +Log message: +fix endianes problems..... works now on sparc solaris nicely.. :) + +_______________________________________________ + +Changes by: raster 00/03/25 16:35:44 + +Modified files: + src : blend.h + +Log message: +ummmm fix dat..... + +_______________________________________________ + +Changes by: raster 00/03/27 11:17:37 + +Modified files: + src : color.c rend.c rgba.c rgba.h + test : main.c + +Log message: +BGR56r & BGR555 support.......... please test if u have a display like this :) + +_______________________________________________ + +Changes by: raster 00/03/27 11:20:29 + +Modified files: + src : blend.h + +Log message: +nicer including of config.h + +_______________________________________________ + +Changes by: raster 00/03/27 11:39:36 + +Modified files: + src : rgba.c + +Log message: +oopsa typo + +_______________________________________________ + +Changes by: raster 00/03/28 10:09:46 + +Modified files: + loaders : loader_png.c + src : Imlib2.h api.c file.c file.h font.c font.h + image.c image.h rotate.c + +Log message: +damn willem! you love playing with imlib2 don;t you? :-) good show :) + +_______________________________________________ + +Changes by: raster 00/03/28 14:25:45 + +Modified files: + src : scale.c + test : main.c + +Log message: +speedup scaling down....... but i cant seem to get any speedup for up scaling + +_______________________________________________ + +Changes by: raster 00/03/28 15:20:38 + +Modified files: + src : scale.c + +Log message: +optimize scalign down routine for RGBA as well as RGB... + +_______________________________________________ + +Changes by: raster 00/03/28 18:57:28 + +Modified files: + libltdl : COPYING.LIB README + src : scale.c + +Log message: +um ooops - how did that happen? + +_______________________________________________ + +Changes by: raster 00/03/29 19:28:56 + +Modified files: + src : scale.c + +Log message: +no more of that thanks + +_______________________________________________ + +Changes by: raster 00/04/02 13:31:40 + +Modified files: + src : Imlib2.h api.c + +Log message: +need new updates call..... + +_______________________________________________ + +Changes by: raster 00/04/02 13:42:42 + +Modified files: + src : updates.c + +Log message: +updates..... actually clip if only 1! + +_______________________________________________ + +Changes by: raster 00/04/03 15:38:01 + +Modified files: + src : scale.c + +Log message: +faster scaling up.......... :) + +_______________________________________________ + +Changes by: raster 00/04/04 18:34:06 + +Modified files: + src : rgba.c + +Log message: +fix dither mask generation.. works again now.. use for icons to dnd + +_______________________________________________ + +Changes by: raster 00/04/04 20:56:27 + +Modified files: + src : rgba.c + +Log message: +dont need that code no more + +_______________________________________________ + +Changes by: raster 00/04/07 21:13:52 + +Modified files: + src : Makefile.am api.c blend.c updates.c + +Log message: +now that was bad! fix update appending :) + +_______________________________________________ + +Changes by: raster 00/04/08 11:45:18 + +Added files: + src : asm_blend.S + +Log message: +add asm for blending.... this will break imlib2 right now for all platforms that +arent xz86 intel 9unless you rmove the asm form the makefile and blend.c + +_______________________________________________ + +Changes by: raster 00/04/08 12:15:48 + +Modified files: + . : configure.in + src : asm_blend.S blend.c blend.h common.h + +Log message: +check for i686 artch and only then compile the mmx asm (i586 isnt guaranteed +to have mmx - NB libs built for mmx will NOt work on non mmx boxes right now +need to do a runtime chekc for that) + +_______________________________________________ + +Changes by: raster 00/04/08 12:20:13 + +Modified files: + src : blend.c + +Log message: +dont compile mmx data struct in if no mmx asm is used + +_______________________________________________ + +Changes by: raster 00/04/08 14:06:17 + +Modified files: + . : imlib2.spec + +Log message: +fix spec file - dont buidl demos package + +_______________________________________________ + +Changes by: raster 00/04/13 09:48:48 + +.......... +summary: +added mmx rotuines for blending - optimized them further +thanks to some poitners form willem. added willems filter code. willem did +mmx asm for the other blend rotuines too - added - needs fixing because +math in C routines chnaged tobe fixed (there was a bug in RGBa destination +alpha routines). fixed minor scaling calculation bug for clipping when +blending. thansk everyone - please make sure your names are in the AUTHORS +file at some point... :) + +_______________________________________________ + +Thu Apr 27 02:59:57 GMT 2000 +(gilbertt) + +Well, I'm gonna use the damn ChangeLog anyhow ;-) + +Changed all the loaders to use ImlibProgressFunction instead of defining it +themselves. This is so I can change them all at once tomorrow. + +_______________________________________________ + +Thu Apr 27 03:16:59 GMT 2000 +(gilbertt) + +Okay, an ImlibProgressFunction now return int, not void. The idea of this is +so that a progressive load may be aborted midway, simply by returning 0 from +the progress callback. There are a number of reasons for wanting this. + +This is a slight breakage to people currently using progressive loading - +you'll have to change your definition to int, and return 1 to get normal +behaviour again. As far as I know, only feh and imlib2_view uses progressive +loading, and I'll sort those two out. To anyone else, sorry, but it's not +released yet, what did you expect? ;-) + +Notice. I haven't changed the loaders yet, so returning 0 won't do squat +until tomorrow, when I change them all. What they will do is clean up and +return what they've got so far. If anyone who wrote a loader wants to do +their own, cool, it'll save me learning the api of every damn image lib ;-) +It's just a case of swapping +progress(params, ...); +with +if(!progress(params, ...) + cleanup_some_stuff_and_return_what_there_is(); +Otherwise, I'll do it myself tomorrow. + +_______________________________________________ + +Wed Apr 26 19:58:05 PDT 2000 +(KainX) + +If progress() returns 0, clip the last row and +return 2. + +_______________________________________________ + +Thu Apr 27 04:00:28 GMT 2000 +(gilbertt) + +All done except the tiff loader. This one is gonna be hard. Libtiff is quite +broken in many ways ;-) + +_______________________________________________ + +Thu Apr 27 04:22:06 GMT 2000 +(gilbertt) + +Return 2 from interrupted loaders. + +_______________________________________________ + +Thu Apr 27 13:41:11 GMT 2000 +(gilbertt) + +Free up some RAM and close the filehandle when interrupted. + +_______________________________________________ + +Thu Apr 27 13:43:49 GMT 2000 +(gilbertt) + +Actually, made the gif loader give back what it's got without changing im->h +to reflect, or reallocing the image data. The reason for this is that it +already told apps what the image size was in the first progressive loader +callback, and changing it afterwards can cause confusion. Also, an app can +still handle/display a half-loaded image, as the rest is just filled black, +and the programmer knows how much of the image he got, 'cos he interrupted +it from the callback. If the programmer wants to trim the image, he knows +where to trim it, but if he/she wants to display a part-loaded image, +that'll work sanely. + +I think this is more sane behaviour, having tested it in feh and +imlib2_view, but feel free to disagree ;-) + +_______________________________________________ + +Wed Jul 12 22:20:53 PDT 2000 +(KainX) + +It's generally a good idea to increment the reference count when you +implement reference counting. This should fix the mysterious problems +people have been having with Imlib2 stealing pixmaps out from under +Eterm. + +_______________________________________________ + +Fri Aug 10 13:33:13 PDT 2001 +(KainX) + +None of the libraries are now absolute requirements. Everything that +requires external support which Imlib2 itself doesn't specifically +need can now be optionally built. + +_______________________________________________ + +Tue Jan 15 15:22:06 EST 2002 +(KainX) + +Fixed a whole slew of potential buffer overflows, hopefully including +the one recently posted to BUGTRAQ. + +_______________________________________________ + +Mon Mar 31 15:20:43 EST 2003 +(KainX) + +Finally got around to fixing the build. Having Imlib2 already installed +should no longer be necessary to build it. + +_______________________________________________ + +Thu Apr 3 14:06:53 EST 2003 +(KainX) + +Rearranged include directory order to make sure +local headers are found before system ones. + +_______________________________________________ + +Thu Apr 3 20:48:27 EST 2003 +(KainX) + +Minor Makefile.am tweak which apparently helps portability. + +_______________________________________________ + +Sat Jul 12 21:06:14 EDT 2003 +(KainX) + +Patch from Yuri Hudobin +for Freetype2 support. + +_______________________________________________ + +Sat Jul 12 21:33:20 EDT 2003 +(KainX) + +Up version numbers. + +_______________________________________________ + +Fri Jul 2 14:39:46 EDT 2004 +(KainX) + +Fixed build (again). + +_______________________________________________ + +Tue Aug 31 11:46:49 JST 2004 +(Raster) + +Fixed bmp security issue. +New IFF ILBM loader +Up to 1.1.2 + +_______________________________________________ diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..ea1f29d --- /dev/null +++ b/Doxyfile @@ -0,0 +1,139 @@ +PROJECT_NAME = Imlib2 +PROJECT_NUMBER = +OUTPUT_DIRECTORY = doc +INPUT = imlib2.c +IMAGE_PATH = doc/img +OUTPUT_LANGUAGE = English +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = doc/head.html +HTML_FOOTER = doc/foot.html +HTML_STYLESHEET = doc/imlib2.css +HTML_ALIGN_MEMBERS = YES +ENUM_VALUES_PER_LINE = 1 +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = YES +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +INTERNAL_DOCS = NO +STRIP_CODE_COMMENTS = YES +CASE_SENSE_NAMES = YES +SHORT_NAMES = NO +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = NO +SHOW_INCLUDE_FILES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 2 +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ALIASES = +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +SHOW_USED_FILES = NO +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +FILE_PATTERNS = +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 2 +IGNORE_PREFIX = +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +GENERATE_MAN = YES +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = YES +GENERATE_XML = YES +XML_SCHEMA = +XML_DTD = +GENERATE_AUTOGEN_DEF = NO +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = NO +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = NO +COLLABORATION_GRAPH = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = NO +GRAPHICAL_HIERARCHY = NO +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 512 +MAX_DOT_GRAPH_HEIGHT = 512 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +SEARCHENGINE = NO diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..013370a --- /dev/null +++ b/INSTALL @@ -0,0 +1,14 @@ +COMPILING and INSTALLING: + +If you got a official release tar archive do: + ./configure + +( otherwise if you got this from enlightenment cvs do: ./autogen.sh ) + +Then to compile: + make + +To install (run this as root, or the user who handles installs): + make install + +NOTE: You MUST make install Epeg for it to run properly. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..1b11508 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,22 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = src data doc debian + +MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess \ + config.h.in config.sub configure install-sh \ + ltconfig ltmain.sh missing mkinstalldirs \ + stamp-h.in imlib2_docs.tar imlib2_docs.tar.gz imlib2.c + +dist-hook: + ./gendoc; \ + tar cvf imlib2_docs.tar doc; \ + rm -f imlib2_docs.tar.gz; \ + gzip -9 imlib2_docs.tar; + + +bin_SCRIPTS = imlib2-config + +EXTRA_DIST = README AUTHORS COPYING COPYING-PLAIN TODO imlib2.spec imlib2.c.in imlib2.pc.in gendoc Doxyfile imlib2_docs.tar.gz + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = imlib2.pc diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/README b/README new file mode 100644 index 0000000..b9b8086 --- /dev/null +++ b/README @@ -0,0 +1,41 @@ +############################################################################### +# # +# I M L I B 2 # +# # +############################################################################### + +This is the Imlib 2 library - a library that does image file loading and +saving as well as rendering, manipulation, arbitrary polygon support, etc. + +It does ALL of these operations FAST. Imlib2 also tries to be highly +intelligent about doing them, so writing naive programs can be done +easily, without sacrificing speed. + +This is a complete rewrite over the Imlib 1.x series. The architecture is +more modular, simple, and flexible. See index.html in the doc/ directory +for more information. + +Imlib2 requires several libraries to be already installed. These are: + +libjpeg http://www.ijg.org/ +libpng http://www.libpng.org/pub/png/libpng.html +freetype 2.1.x http://www.freetype.org/ + + +For examples of this library in use, seek: + +Eterm http://www.eterm.org/ (CVS version only, currently) +feh http://www.linuxbrit.co.uk/feh.html +geist http://www.linuxbrit.co.uk/geist.html + + +A blurb about each of the directories: + +debian/ Debian build files +demo/ Demo view program +doc/ Documentation for imlib2, primarily in html +filters/ Filter shared objects +libltdl/ Libtool LGPL-licensed loadable module support library source +loaders/ Imlib2's image loader-savers (jpg, png, etc) +src/ Imlib2 main source +test/ Test program(s) diff --git a/TODO b/TODO new file mode 100644 index 0000000..e754229 --- /dev/null +++ b/TODO @@ -0,0 +1,6 @@ +* line code doesnt draw nice liens when clipping - fix +* filled polygons can break fill bounds on corner cases - fix +* go thru TODOs and FIXMEs + +evas2 has fixed code for these 2 in it that work just fine. just need to +port over (should be fairly easy). diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..9d8816d --- /dev/null +++ b/autogen.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +rm -rf autom4te.cache +rm -f aclocal.m4 + +echo "Running aclocal..."; aclocal $ACLOCAL_FLAGS -I m4 \ +&& echo "Running autoheader..."; autoheader \ +&& echo "Running autoconf..."; autoconf \ +&& echo "Running libtoolize..."; (libtoolize --automake || glibtoolize --automake) \ +&& echo "Running automake..."; automake --add-missing --copy --gnu + +### If you want this, uncomment it. +./configure "$@" diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..289f7ca --- /dev/null +++ b/configure.in @@ -0,0 +1,394 @@ +# get rid of that stupid cache mechanism +rm -f config.cache + +AC_INIT(configure.in) +AC_CANONICAL_BUILD +AC_CANONICAL_HOST +AC_CANONICAL_TARGET +AC_ISC_POSIX +AM_INIT_AUTOMAKE(imlib2, 1.2.0) +AM_CONFIG_HEADER(config.h) + +AC_C_BIGENDIAN +AC_PROG_CC +AM_PROG_CC_STDC +AC_HEADER_STDC +AC_C_CONST +AM_ENABLE_SHARED +AM_PROG_LIBTOOL + +if test "x${exec_prefix}" = "xNONE"; then + if test "x${prefix}" = "xNONE"; then + bindir="${ac_default_prefix}/bin"; + else + bindir="${prefix}/bin"; + fi +else + if test "x${prefix}" = "xNONE"; then + bindir="${ac_default_prefix}/bin"; + else + bindir="${prefix}/bin"; + fi +fi + +if test "x${exec_prefix}" = "xNONE"; then + if test "x${prefix}" = "xNONE"; then + libdir="${ac_default_prefix}/lib"; + else + libdir="${prefix}/lib"; + fi +else + if test "x${prefix}" = "xNONE"; then + libdir="${ac_default_prefix}/lib"; + else + libdir="${prefix}/lib"; + fi +fi + +dnl Set PACKAGE_BIN_DIR in config.h. +if test "x${bindir}" = 'xNONE'; then + if test "x${prefix}" = "xNONE"; then + AC_DEFINE_UNQUOTED(PACKAGE_BIN_DIR, "${ac_default_prefix}/bin", [Installation directory for user executables]) + else + AC_DEFINE_UNQUOTED(PACKAGE_BIN_DIR, "${prefix}/bin", [Installation directory for user executables]) + fi +else + AC_DEFINE_UNQUOTED(PACKAGE_BIN_DIR, "${bindir}", [Installation directory for user executables]) +fi + +dnl Set PACKAGE_LIB_DIR in config.h. +if test "x${libdir}" = 'xNONE'; then + if test "x${prefix}" = "xNONE"; then + AC_DEFINE_UNQUOTED(PACKAGE_LIB_DIR, "${ac_default_prefix}/lib", [Installation directory for libraries]) + else + AC_DEFINE_UNQUOTED(PACKAGE_LIB_DIR, "${prefix}/lib", [Installation directory for libraries]) + fi +else + AC_DEFINE_UNQUOTED(PACKAGE_LIB_DIR, "${libdir}", [Installation directory for libraries]) +fi + +dnl Set PACKAGE_DATA_DIR in config.h. +if test "x${datadir}" = 'x${prefix}/share'; then + if test "x${prefix}" = "xNONE"; then + AC_DEFINE_UNQUOTED(PACKAGE_DATA_DIR, "${ac_default_prefix}/share/${PACKAGE}", "Package installed data destination") + else + AC_DEFINE_UNQUOTED(PACKAGE_DATA_DIR, "${prefix}/share/${PACKAGE}", "Package installed data destination") + fi +else + AC_DEFINE_UNQUOTED(PACKAGE_DATA_DIR, "${datadir}/${PACKAGE}", "Package installed data destination") +fi + +dnl Set PACKAGE_SOURCE_DIR in config.h. +packagesrcdir=`cd $srcdir && pwd` +AC_DEFINE_UNQUOTED(PACKAGE_SOURCE_DIR, "${packagesrcdir}", [Source code directory]) + +mmx=no +AC_ARG_ENABLE(mmx,[ --disable-mmx attempt compiling using mmx assembly [default=yes]], +[ + if test x$enableval = xyes; then + mmx=yes + AC_MSG_RESULT(enabling mmx support) + else + mmx=no + AC_MSG_RESULT(disabling mmx support) + fi +], +[ +if test x$target_os = xlinux-gnu; then + if test x$target_cpu = x$host_cpu; then + mmx=`cat /proc/cpuinfo | grep mmx` + if test -n "$mmx"; then + mmx=yes + fi + else + echo "" + echo "You are cross-compiling on a "$host_cpu" machine for a "$target_os" machine." + echo "If this target supports mmx, please enable mmx with --enable-mmx as a" + echo "configure option." + echo "" + fi +else + echo "" + echo "You are not running Linux - This script cannot auto-detect mmx assembly." + echo "You will have to enable the mmx assembly (which gives anywhere from 10%" + echo "to 300% speedups) by adding --enable-mmx on the configure command-line." + echo "" +fi +] +) +if test x$mmx = xyes; then + AC_DEFINE(DO_MMX_ASM, 1, [enabling MMX Assembly]) + AC_MSG_RESULT(enabled mmx support) +else + AC_MSG_RESULT(disabled mmx support) +fi +AM_CONDITIONAL(BUILD_MMX, test x$mmx = xyes) + +ASFLAGS="$ASFLAGS -I../" +AS=$CC +AC_SUBST(ASFLAGS) +AC_SUBST(AS) + +CCASFLAGS="$ASFLAGS" +CCAS="$AS" +AC_SUBST(CCASFLAGS) +AC_SUBST(CCAS) + +# check for freetype +AC_ARG_WITH(freetype-config, +[ --with-freetype-config=FREETYPE_CONFIG use freetype-config specified ], +[ + PROG_CONFIG=$withval; + echo "using "$PROG_CONFIG" for freetype-config"; +],[ + PROG="freetype-config"; + AC_PATH_PROG(PROG_CONFIG, $PROG, "", $PATH) +]) +if test -n "$FREETYPE_CONFIG"; then + PROG_CONFIG=$FREETYPE_CONFIG; +fi +if test -z "$PROG_CONFIG"; then + echo $PROG " is not in your \$PATH. Please ensure it is."; + echo "You may need to install the library and/or development packages"; + echo "that contain this configure-script."; + echo "FATAL ERROR. ABORT."; + exit -1; +fi +freetype_cflags=`$PROG_CONFIG --cflags` +freetype_libs=`$PROG_CONFIG --libs` + +x11=no +AC_ARG_ENABLE(x11,[ --disable-x11 attempt to build with X11 support [default=yes]], +[ + if test x$enableval = xyes; then + have_x=yes + else + have_x=no + fi +], +[ + AC_CHECK_HEADER(X11/X.h, + [ have_x="yes" ], + [ have_x="no" ] + ) +] +) +AC_MSG_CHECKING(whether X11 support is to be enabled) +if test "x$have_x" = "xyes"; then + x_dir="/usr/X11R6"; + x_cflags="-I"$x_dir"/include" + x_libs="-L"$x_dir"/lib -lX11 -lXext" + AC_MSG_RESULT(enabling X11 support) + AM_CONDITIONAL(BUILD_X11, true) + AC_DEFINE(BUILD_X11, 1, [enabling X11 support]) +else + x_dir="" + x_cflags="" + x_libs="" + AC_MSG_RESULT(disabling X11 support) + AM_CONDITIONAL(BUILD_X11, false) +fi + +dlopen_libs="" +AC_CHECK_LIB(dl, dlopen, dlopen_libs=-ldl) + +my_includes=$freetype_cflags" "$x_cflags" " +my_libs=$freetype_libs" "$x_libs" "$dlopen_libs" -lm" +AC_SUBST(my_includes) +AC_SUBST(my_libs) + +AC_CHECK_LIB(jpeg, jpeg_destroy_decompress, + jpeg_ok=yes, + jpeg_ok=no + AC_MSG_WARN(*** Native JPEG support will not be built (JPEG library not found) ***), + ) +if test "$jpeg_ok" = yes; then + AC_MSG_CHECKING([for jpeglib.h]) + AC_TRY_CPP( + [#include + #undef PACKAGE + #undef VERSION + #include ], + jpeg_ok=yes, + jpeg_ok=no) + AC_MSG_RESULT($jpeg_ok) + if test "$jpeg_ok" = yes; then + JPEGLIBS="-ljpeg" + else + AC_MSG_WARN(*** Native JPEG support will not be built (JPEG header file not found) ***) + fi +fi +AM_CONDITIONAL(BUILD_JPEG_LOADER, test "$jpeg_ok" = yes) +AC_SUBST(JPEGLIBS) + +AC_CHECK_LIB(png, png_read_info, + png_ok=yes, + png_ok=no + AC_MSG_WARN(*** Native PNG support will not be built (PNG library not found) ***), + -lz -lm) +if test "$png_ok" = yes; then + AC_MSG_CHECKING([for png.h]) + AC_TRY_CPP( + [#include + #undef PACKAGE + #undef VERSION + #include ], + png_ok=yes, + png_ok=no) + AC_MSG_RESULT($png_ok) + if test "$png_ok" = yes; then + PNGLIBS="-lpng -lz -lm" + else + AC_MSG_WARN(*** Native PNG support will not be built (PNG header file not found) ***) + fi +fi +AM_CONDITIONAL(BUILD_PNG_LOADER, test "$png_ok" = yes) +AC_SUBST(PNGLIBS) + +AC_CHECK_LIB(tiff, TIFFReadScanline, + tiff_libs="-ltiff" + tiff_ok=yes, +AC_CHECK_LIB(tiff, TIFFReadScanline, + tiff_libs="-ltiff -ljpeg -lz -lm" + tiff_ok=yes, +AC_CHECK_LIB(tiff34, TIFFReadScanline, + tiff_libs="-ltiff34 -ljpeg -lz -lm" + tiff_ok=yes, + tiff_ok=no + AC_MSG_WARN(*** Native TIFF support will not be built (TIFF library not found) ***), + -ljpeg -lz -lm), + -ljpeg -lz -lm), + ) +if test "$tiff_ok" = yes; then + AC_MSG_CHECKING([for tiffio.h]) + AC_TRY_CPP( + [#include + #undef PACKAGE + #undef VERSION + #include ], + tiff_ok=yes, + tiff_ok=no) + AC_MSG_RESULT($tiff_ok) + if test "$tiff_ok" = yes; then + TIFFLIBS=$tiff_libs + else + AC_MSG_WARN(*** Native TIFF support will not be built (TIFF header file not found) ***) + fi +fi +AM_CONDITIONAL(BUILD_TIFF_LOADER, test "$tiff_ok" = yes) +AC_SUBST(TIFFLIBS) + +AC_CHECK_LIB(ungif, DGifOpenFileName, + gif_libs="-lungif" + gif_ok=yes, + gif_ok=no, + ) +if test "$gif_ok" = yes; then + AC_MSG_CHECKING([for gif_lib.h]) + AC_TRY_CPP( + [#include + #undef PACKAGE + #undef VERSION + #include ], + gif_ok=yes, + gif_ok=no) + AC_MSG_RESULT($gif_ok) + if test "$gif_ok" = yes; then + GIFLIBS=$gif_libs + fi +fi + +if test "$gif_ok" = no; then + AC_CHECK_LIB(gif, DGifOpenFileName, + gif_libs="-lgif" + gif_ok=yes, + gif_ok=no + AC_MSG_WARN(*** Native GIF support will not be built (GIF library not found) ***), + ) + if test "$gif_ok" = yes; then + AC_MSG_CHECKING([for gif_lib.h]) + AC_TRY_CPP( + [#include + #undef PACKAGE + #undef VERSION + #include ], + gif_ok=yes, + gif_ok=no) + AC_MSG_RESULT($gif_ok) + if test "$gif_ok" = yes; then + GIFLIBS=$gif_libs + else + AC_MSG_WARN(*** Native GIF support will not be built (GIF header file not found) ***) + fi + fi +fi +AM_CONDITIONAL(BUILD_GIF_LOADER, test "$gif_ok" = yes) +AC_SUBST(GIFLIBS) + +AC_CHECK_LIB(z, uncompress, + zlib_ok=yes, + zlib_ok=no + AC_MSG_WARN(*** Native zlib support will not be built (zlib not found) ***), + ) +if test "$zlib_ok" = yes; then + AC_MSG_CHECKING([for zlib.h]) + AC_TRY_CPP( + [#include + #undef PACKAGE + #undef VERSION + #include ], + zlib_ok=yes, + zlib_ok=no) + AC_MSG_RESULT($zlib_ok) + if test "$zlib_ok" = yes; then + ZLIBLIBS="-lz" + else + AC_MSG_WARN(*** Native zlib support will not be built (zlib header file not found) ***) + fi +fi +AM_CONDITIONAL(BUILD_ZLIB_LOADER, test "$zlib_ok" = yes) +AC_SUBST(ZLIBLIBS) + +AC_CHECK_LIB(bz2, BZ2_bzRead, + bz2_ok=yes, + bz2_ok=no + AC_MSG_WARN(*** Native bz2 support will not be built (bzip2 library not found) ***), + ) +if test "$bz2_ok" = yes; then + AC_MSG_CHECKING([for bzlib.h]) + AC_TRY_CPP( + [#include + #undef PACKAGE + #undef VERSION + #include ], + bz2_ok=yes, + bz2_ok=no) + AC_MSG_RESULT($bz2_ok) + if test "$bz2_ok" = yes; then + BZ2LIBS="-lbz2" + else + AC_MSG_WARN(*** Native bz2 support will not be built (bzip2 header file not found) ***) + fi +fi +AM_CONDITIONAL(BUILD_BZ2_LOADER, test "$bz2_ok" = yes) +AC_SUBST(BZ2LIBS) + +AC_OUTPUT([ +Makefile +src/Makefile +src/lib/Makefile +src/bin/Makefile +src/modules/Makefile +src/modules/filters/Makefile +src/modules/loaders/Makefile +data/Makefile +data/fonts/Makefile +data/images/Makefile +doc/Makefile +debian/Makefile +imlib2-config +imlib2.pc +],[ +chmod +x imlib2-config +touch imlib2_docs.tar.gz +]) diff --git a/data/Makefile.am b/data/Makefile.am new file mode 100644 index 0000000..e80f06f --- /dev/null +++ b/data/Makefile.am @@ -0,0 +1,2 @@ +MAINTAINERCLEANFILES = Makefile.in +SUBDIRS = fonts images diff --git a/data/fonts/Makefile.am b/data/fonts/Makefile.am new file mode 100644 index 0000000..4eedf9f --- /dev/null +++ b/data/fonts/Makefile.am @@ -0,0 +1,11 @@ +MAINTAINERCLEANFILES = Makefile.in + +FILES = \ +cinema.ttf \ +grunge.ttf \ +morpheus.ttf \ +notepad.ttf + +filesdir = $(pkgdatadir)/data/fonts +files_DATA = $(FILES) +EXTRA_DIST = $(FILES) diff --git a/data/fonts/cinema.ttf b/data/fonts/cinema.ttf new file mode 100644 index 0000000000000000000000000000000000000000..469f3d4401be5d0455762ecf62f5e486da9c761b GIT binary patch literal 11588 zcmch734B}CmG`~xN$+Wwp7fq1FS4~+k}X@ZB}?Azc!}dUiEZpSi&u zouna!hJkikV3@B=haY@jA(T)Eg>)H~qy?rFX4=9)_tGVFn1+@zOgo*iUcUc*PjceW z%(TDX_xqlH=joh#@4M&RbI*34L?|J|N*W1I4vtQwGY3AJ>n9}k2wF!r&duyTVn6%$ zgoN%Pguipkj_Wrczpc$hh+#D$<=@%5Y3@L0_`_+8pC?2Z+B!S4>BMp0EqE5sko;CO zh`%ws4g7sTbnD!{16@0uX9%gOCxjl{v1{WDG5p*@NOc1A&2uvcc9ZLA61X4ZgF9#D zX760F<{i+j;9s$O*WP_kjJbECi^=ykVX^~$z4uegHaI)~9b^6lE#$$!e*0^s?{g>5 z-D^0(-wc{3oc4tF41e>vd$EqQ=T72&qS($J(ywW)Wt!YWEMyE%GEPf?>lejLgea8V z_3KtLP{b&)k?$07jyMQbt6e-9q2)!~Kq~2ninx(<)5nXrfcCTd&LAMrhBdMmJD&hj#f5TQ_Fk>brr;h7#>bNeaj_Y#jxGtxT>vHP2 zCTCNsu_@TUZRhOVOfYz?sjV#=yu{UaeQT%cl0Et|E|g(>cFT1;X7*s3S+WH~cd&_ickJ7H{odf35HQWQ;ZGNXz&n_~u7ua|uvU_lLQ)*i%FC^VEBKq|Zvr-d zmW?YTqx1)yq>rl!Ng*EN=nvFxdOEJ&K1xrko9SNlc0$Pk8lo@JYcP_~P!72IC>^Jv zVKz&O-S{B!5FdIYVL_21QgbXxbIthV|S=ZA;6R9}Po zO^oT-S$p|ZU18G-HcclT<2o^yom8;7a%`IBm^RU3it8M%jrP-y)~)IfN*EpcL?Cak zbZuLyHkL4AB#r0p0P@{pFW*UW-?!n4ZJ=u@cQf62k3|TH2qwx9p4AFfboau*XSu;AriDH#<5y4-V$%| zVR0=!k)BG94UZ+Kr}ZzcwzKu>t6Mw!`-|Uf-^pjO@4rTl0zam#98*k|zI0^x@ZsSj zG=%%%!{}s@9^SPA`X*U1(vr*0Ob<^FZ^E`xG7an5d4cupRNtd^&3Y)a8SOb(Ru;3* z3=gv>qJ;3D!#ZV5E!e0Sq1`Z*7>o-xfgR#Mw?zG&`t`rNlDkXt_(En$Y;Avx%ch?F z;dXk)TIO=P=)Q)bqIL2wV5R_R(Dq#nrD&X4RL;|!Z|SDlcIpcWvLaVe5mp-sG5f_9 zhcbEoh2HwYbZnX1#&JuMj=aZgH*!x>N=MV-!rz6{=`c4FP9LdT?lyMElTpECpijp} zoT5NoZPk0uJQ$;|7lulz!$f`7}?_EfDkdkF*v3G}I%Ma0?6b%?dVXuTgh4DcU zvY-jZxB zUuv5kOxAWT-__xH8vTsDo;(cdd7YRmYlD+;_S1+!N|AM(Iy` zHh*z&7oF?N<&(X`iRQN9(T0F%m(%O!ELlhUc%XM<#kKJLTC8_1WO3zM`kMH<-_7Gu?D&6TNyky{9vfSjz2ZRtH<-4`VH5q^8I> zMRO9N#k^M{YlsV!aWM>@G@n>P)pwdGlE|I*9)!TmEmLHgC+osW)g zux{w0XIs{&k2WpssQ8Qh!(dNbx0R`TLtL*YXWbK7@wPjhrxf3R>OlFwIjPtO1TigK=}I(Ku! zN*f(-;H18hlh=IX@waa%t8I@&I)8HK$E&)UpuH6Mz5>3L#a$B_S9oj-Gt6$^jN2jK~<-X z(Ieh4BHpwgV78dbBk(^OMgn+g1 zMFj^a|JvBRIyKwGd&k1j!e=vyU(tW%KGeHSwI8c(YG`;E6EJP@&tVoBF$4BM;V@NH zkp@FYnXLk43uYjJc}1q+qU`=`XZ%g{~`?E{PUisP5$Migg>7 zMhkP?p1vXaQe@N>Z*B4fm9`c>xW7L!Qd!qjTX|FaeErflG%JLaXzK_pcpD3|=dHdJ zT66qs8?G+AJh+EWrTEBbBvQCh2{$LW=Fa?&ra!#8pQ;U4sdq1Ltn;Y%hwC=vnJ(k7 zidV5ZGutEP%SLTUyu@@=!@{-^D|vO@*!(;n&P|SmI|@%ko4H3qxqFtZqkL$zu5gwr z6^)%V9#W@i9rGHdv8OO6W~`+p(?*14`cZUy=ASBrdUkId=DuABl*jqH`Pav?+~cd7 z>3?=?e>d*^*yx9AT8lG1gqfU}w)8x!gV-iMRESk!ne#uIn(gDh$2Hbh9~f1C#@*0y zO-Tl}_p$RjTNEiYogvzzHbFUpGAPTxHriB}?p-n4!P~~_#|kgjMFQ2_hwCF2vpW}h z{u8Zh*EiFDYulpUF_p-t)UU-7v_9lYrEG3n&xIUOV<8hEBuOZ60<3hyvf~S-8~@r= z!8CQtvJE$&YWV}r#%`D%yoE(tJ~**_bu_VmeM=`_6^21`mioQUP*dOfjiV z@P%a?xW;Hgt)#!uo}O4-PFIEwVfiN9826(-zpznA+rS`eLYJ>bd^r z_3s|bwk2=kI69h9Jd)FHl_G8nS1H%}R2LtliL2GOzS%`5qkUG<+gjP!Pc?5Wdb$l! zx|CUUUoXY1lCNLr>d~=ixNxI4bdjqUo_=*ju1?l`9iGm-@=<8XL2zc*Y9AB>?KB7t zD;LHu{?V&?3cKml;0tuw-MyC&xA+TB2I{zvq;m9Rb~D?&j}Lt$)SU@l+or{jdH#2p zRnk07jI*E!m)GNyEH31-V)e)BdC^lNJ2A&6JFA1|9f`>8t^ymTEr$=d)$@I8^AohGOO+^Z0la%{?*OgSL zC<|4ssH-o$y(Y)q+mQZz-H>LP`}MR~^Sg_J75HCB(6kgU&FkTG(-Amu~0$gOCAlt272h+tzAG{z3IcEgGn&rUzL#ydWAd`PuF>`6K7$Ux-g7 zn_37BI0~FxK2bO}K71;j*%izB^IT7^EF0UMO`kfrtgU^JyKf@9Jr-3@)`cUrba^zk zJ)=b|rlq&Qg;m!ACy0?0<>H7sh=WWaJ~P!yCrAtyZ>8VZJJ2~adA9kX)au9z8}(3+ zeMNM2!!fR{UH$o8t1g?P?Y+MoOy1NKmR;)K&@Hk%oc>6o7HxBQ$8{w*jq2+O3t~9N zj1PB~aTdac>}A{JV{s2h6c*?a`E+@Zz!gdGW?NVs%eO2bq~RXy)iZ_?L;KLE!EAz~$XtS5#-6Mx!BF`!C@Ejy6}^(Nq8U-b@drNv~2* z>5?Yy_^Rqdy=9~KkA<_ex0;$OqK=B-kyu|}>_~N`Kd7j`5A@S)c+~@!mGvG9u4Mbf zH24nI)roZpVH}lV$S}l6EYi*8XeVvSA=CQw!~*%{D$a+F<`mUqdW%AF=HlOR^tetv zxBeT`O>R*z8*=yjlX?rKkF~W)Rbgv+`u50yd%XMQDZjjv{o4%a>WkM^2-#5Az<5CKSbYA|G?e36OyuOoLM6zHdEOf5K#t2 zB$i{etjC1&`l{%K;$hPtRIj0QT%CKYz0Fe`+he3|8vON8!!8J7m(8ACuH}<%J0#haM1`kYHH!gSrI9NhXZ1ssPj*m)Acpwo z=l5|N?e^iC!cUV~zKgnVQtv+eS-!lF9)53TbD+H3! z=#obZc!yY;k9mT?&g?~g`g|B!oKNSELRQN}_aa~44DDlm3-6*zxk!KW#L@v`Lq3Np zm!)%r29`+Qn|wzrnrY=EJ%PGe{rPV@^XicL4lAEgI&a#fry{&YLiwzgZOGq6f2mi| z%w~{Jxy_JNVHFEI*(`*g0M7jpCB$tmsKdkmxNO7eSoWtsrN?O1D1Ab&_C~+YX6U0F zeVE&>y%9nU4xzOuMIYWiJiMI&eMC`{koKdaaNX=lBcq8if3;Qu}gnMytT=CwK`iX)9q24tp3>I^t;vavJZ$BPqxOY z&dA9J$^#zr-#X=bA1owEpG0;FpiYEEvrM2Bbtut`CxeBC8fXyB8qIbh#Jv}FN{4*z z+6FKE2cWn5-0Ca0OTL&-`eZUlhv<{9x_z?pDy^tWtM};myvzOl?@LlF1b00jE!lz2 z2%``eB4!*0Q}cnSnY|#YYhm+O2Y(|Wa!P+Vs=l)jJVQ5{$0s(PkDkwu+Aa#8w$bM= zh@V%A9Yg2iCr7e$jGutzx>!u2BCAgtkzp?))& zQQW+-CX@Wz@p^ap_@Hf^>y)L!38&ZVc#Tz}#bC1tA$J95Fq>p!EcB{)$AxK~4LQdH&6@G~D{aTCFnm7Fybw2cv`deD~?swG~{py)B>QdVM$}8$= zmKSn_a5@Oo~z+84O05aHBLLA`Zc!m%sDkSF}gt#^nBDnx} z0^TCTO#q`Uzb2Cz@xf2_lk*abEt@v{-x;+9Zqg*-d)L68u8ihhO6VJI$7! z|9|t%_K9Gp*ro55hAz6TTSWc$#QKZ6OZ$FNvqoO^#~Lqa+dvHTFF~iEVf@1bI*!6d zJ79ZLWCOW@+(#ZDpCiY}qvQ=zpuNGeU?3O{g~M=2RQ&``vGH{n-;41x7=J(cKNx?! zINl$u42CWke*x?N0cF2yWwg&~=MEcJP8J@odI_>i9;S8Ux)9r3w_$y;&Tm5 zHvY$Wb{_o-X*7I_G`pzrJjwnUgUAwmm+1fd!cHPX;&K5tnXM*bWS3y(jYevq zW;1U#o6IJY*-WX?T)d1%v(Z{2%nTDt)CarFf>A`b(PT0jO^C1-yP5G21e9!oz!^D< z#bB|REoQUD!f}G7cnL;}U@s9C8!%Ie`e2tu#Pn7R1OyL6aI3>Y1a^s5orl$Guv#rv zi^XaM4{Pxf1*?d@wM*L{8xBcB9>Hv)gQT zJ9s$k4u>6J5*;QNP)6AuPTVb*?!ssbx*?z_S}mxA+;+wTTkL@Dz{BA%vbosA9A|Pm zoK6S8EILhYpp0@jUAS8>-G$Lsbc=SoDB7&3vOErAVwc6qc!-?SX>>a6+Qi_2zlgY; z0JF(u_5fv+)8)q9cIhsc#biUb3ClOxQ9Zh3jR(xg1to%q%O$v64oK>9ahzFlNsn4#{!pF1OWex4R`XmTz|8*DJTrrSq`4bslcF;C8#*lFRJ|50Bg9aRaPo zkJSg1QErcdyW`Sb9-G;LZnGqr%}!M39=}B3O)ymtHi|d%9*^kpNFKN3@$kG=_Qio)|Yuj2J80K3&| zF9*sf#ao8Ebm=ay!|HN*6{{>;t?U%wt(1#Ayf6md!h5|Yub2J##_I(Sob-HNfZgh| zR{~{}*H@0a`_f%LhgFh%UY!U259SLf1X00mclu0rJ9zkfCZA97c@>|J=k0!<-|quB zY<@=oD5HG-3f$e7?(#crZgktAVw(p?8h@3S@o?B(e)x>RYVi9_e!ti6^ZNY;gQLt} jR^|sdZDo!spp5dDRpRcsbXS=RJj(nwuh(XiaqRiOJh`|S literal 0 HcmV?d00001 diff --git a/data/fonts/grunge.ttf b/data/fonts/grunge.ttf new file mode 100644 index 0000000000000000000000000000000000000000..34d1021843302eac78133e9d9e064a1139c6b8f3 GIT binary patch literal 53204 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 z

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 PEX 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 Q&Qg<7C(ri5ZJSd60x+3$vH$=8 literal 0 HcmV?d00001 diff --git a/data/images/Makefile.am b/data/images/Makefile.am new file mode 100644 index 0000000..137e06f --- /dev/null +++ b/data/images/Makefile.am @@ -0,0 +1,25 @@ +MAINTAINERCLEANFILES = Makefile.in + +FILES = \ +audio.png \ +bg.png \ +bulb.png \ +cal.png \ +calc.png \ +folder.png \ +globe.png \ +imlib2.png \ +lock.png \ +mail.png \ +menu.png \ +mush.png \ +paper.png \ +sh1.png \ +sh2.png \ +sh3.png \ +stop.png \ +tnt.png + +filesdir = $(pkgdatadir)/data/images +files_DATA = $(FILES) +EXTRA_DIST = $(FILES) diff --git a/data/images/audio.png b/data/images/audio.png new file mode 100644 index 0000000000000000000000000000000000000000..01c061151f69e9e80cdcc29f4190f50dce809fca GIT binary patch literal 4263 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 JPDHLkV1n+!DZT&z literal 0 HcmV?d00001 diff --git a/data/images/bg.png b/data/images/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..3ca990aa4d160c272fc5f916cbfcec59766c71bf GIT binary patch literal 132721 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 KuX=A5{Qm%p43(V# literal 0 HcmV?d00001 diff --git a/data/images/bulb.png b/data/images/bulb.png new file mode 100644 index 0000000000000000000000000000000000000000..757e599d291d656ee2a7728b3296fd4872db0f0e GIT binary patch literal 3504 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 JPDHLkV1jV$NvHq- literal 0 HcmV?d00001 diff --git a/data/images/calc.png b/data/images/calc.png new file mode 100644 index 0000000000000000000000000000000000000000..812237b3ac5368d9205e24b66096c1f94b52e0a1 GIT binary patch literal 3949 zcmV-z50dbSP)uD!eV-n(;m_ss0{^jTH! zlMh|JE)Tod#>$5%wDhXFYPzQW&;R|u&-*<8f?t1r{rUg(k^e)u^nVMyyx478;ZzABHh@?a$ee}tPzE>Wp>wfD8z~ox?A)?B3TQAw8`AA`XWFgSp-#6u-B?&U*k~+F{l#DZ?ZGQZ z!~#JyED%P=mkr*C5CJ!NV`SvW!5{yyP$*W<&rI=`pZ^@ia)C9~QF^^Tt(6wNZl8Xy zPd1feZK=YhHEYSGQ*7TfPN`TV2m(|s)+%8bu+nND>2x}CwOakq?96=q(|`ZjZ$-fS zKri|p4ug@G$$C;ma>kgEum8*EKX%~e8}D-5B!Bg}f27fCvt?o&$8oShKo|sAYq3Fy z-}C8oJ9OJ!dfgtqZkI5yREi}si6pzXZ37W*+_x92O1IPI@R4UYbM^vvfAt%Cfez4( z0_X!i5V$W9xDgRoL=qyB5uvna&#w14ZUW!$ap!ICV0LMVj#}EiE@x(@QCG2{#kv8m z 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 literal 0 HcmV?d00001 diff --git a/data/images/folder.png b/data/images/folder.png new file mode 100644 index 0000000000000000000000000000000000000000..9a32d03701bce8daf3f15c5405e41715fca52915 GIT binary patch literal 2873 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 XFg@uR%%#qO00000NkvXXu0mjfXi}+< literal 0 HcmV?d00001 diff --git a/data/images/globe.png b/data/images/globe.png new file mode 100644 index 0000000000000000000000000000000000000000..b52af4b20629082595d2dba80b459f4750ee4390 GIT binary patch literal 3388 zcmV-C4a4$@P)?FP!MKp^n|NR2?^fd>SNkl+FFh~OFCl9y5;@z9DkY8666-8e}dU*gzte3{#sb3gm+ zy}ug|XP?Q=@r>Gjj=V_o7W_)M|GJNz!6|L+7u zZgS?k*nvRNruW=OCG&9!$O7=GslvV82uuOn{AV|F-~Xfuh#9~^;dA=4njtX-H3e+} zQ!u*&A^%AeD0+4ZHk?29%>1FJzV@p}R@5_#_3Y#u>-Qb}?7`K>q4^%y*3@uL^>2;) z{Y$UEJ^bO>S6}{acWZSB=-je`P4CST`9uha8IMN~KKoav<_|yqr%`SGw*##D#iJLA zYFkJgCQC3nAWbEEssq}i3}-ZEZ0xnmt?!&WbLE9|Z=SyhB)~ZTOn`J3B0FB{LxA4~ z4wRpG?wfx<|G=q#dgNeu>bak}DGxT=bgUsBSJ)RtD5q%F1VLy>(KI9o<%zMf)Raf} zKQ#XvbBm4TcQ4$!0F;2R5SFt!v#VmM4*^~Q(Zj#_{HGuN>Nj4j&()r-%Y@%QJr*a9 zG}!9HdS?z{8r&Mx*(W1bsv-APtH`9vnTr8+ulUS?B_3X$Z8)?_peS?{Jie4xQ=>j9tt)LtGsP?>-Fk)@xz+0tv*Z?pyl z74ti&)@>y2MqnHK@!xv>@dFQ?dU38AEd2Se%=1UTTw`UWhEV&35KAED5JGTpA5^5r zh>-f82Ip4CTv$z+6P}YRil2XS56xPg?kJ#T0vh#@Mvz619NY86<@e&NYwMk4W(Djn z`^Q}gOcOQ&Dkp#K&t7O$q9cF(^+P=UXham1Ks13!KnL6yM2u2`Bm3uh=HxM+Jig2m zNB2;!YA$S!dGd6Xm1BDeBTFPCKe{~R@LYnoDec}k+_$vn=u0nOc)hR!ZpLmSq3$7R zOP_h}U;nPzC_Q`X{yM+&g%e1*2+ZZVmk1bv@cDO*5HV6(gpf4rOB_8YIkJ$jvKXSu zH9(RMha8*>=#EBoHizDeNZ7F1xc|WX+?lgi-YpQA?iX%GkvuaQzmsH!5B>UIeyY)2 z_>)LQ{NWcH2yqh_=FjXG)Gq=A&Vn;>F6$vsLdXi2u8(->OozBXL{%b8sl?5;BM=pa z+KJdeuOD;z^ogH6e(dluU*@OVu+~T26|H8kNf=G%$abU5-=BUe7yF*E)sK61Z zNFY?c|BQh+f6ug{7y|>OPx$`pJ?>wK*f%E$D-kCS*GNZWzV-bLI=wMVO-Yu;M3sfb zvuEG_vDR7_2oyH=NxZAjXf-jMFbkZW6p#~-esY9&gMW?ovp_djcV??)X1Z}85L z7$by;M%S;ewhG{jyY%)d1iO?L3JA-M`DcU#A;CGvD>owEYVBvC1Y>R4*BEl&-Zt;_ z#+b|3k;W29#RH`h`>QZlRwyy?S!*li$TFP0F=lmLAXeMFer}Uj&Ta7Wr35P!uU$zw zc^H=W2+CD;KX49cie4Jf(+=e_+T#YJk>SL# zHoZ(U$}||qdN5>BO7;bg1xkn#4C66%CAqHw|NPA>bVi1=SGo*G=_EI$VeBpA%wVl0 z@%24$BB}`DWJp6omO+NYmr4YIVlx?0 z4Pdw#@%+E7F-#ra0M25(B@mKcCMd;VWDsua@cS0!_k!IBd?1XpgV0)Brg4z~4Ngt+ z$2yDmmU9~+UwpJoG9FMBLn;IeR7hqu{f^;M8;&1Js6~<+t9@>*IsWS%$A#4tyaVqM zI0B(Ccshw9=mSD9?Kg7Zw}HPC0Rc#3&Bz(uL`}rXNDoFJNbwScGjzue6)mwCfr}GD z2Mr}zOC;s8L-pli^w^s?13#0E?6$r9z^yMgveTK`nx6ZH_o?kvPqUNf~7+%0em1=nhj}I0Kiu z60Ijmiq&8y(jH(7)s19m1y&EnJM`Ofrrh3f1-9ih9d_T=mF96N5jal}2%I$FQY4e5 z|J~2l@bvJiK~S&a`#r3HO$%k~2nH!5>sakOi~(;o7!AfE>{QYLq40Qw7YIPdgW)ct zncH^V*=xJv8@H~V)jGjwjnyeeXXwmej3rAocAT(O1)V1Jd+Qir;9xY!z!`e6p`#(u z8idB{1ZOhH5-2 zd*{3B*Ee>UUf9{PI=I6MxNOiG#+%o_t5zQTvhxaOG%A?XJs$ARa&a9N_byY)x^!aA zt+6Ilj>tMTIw^0wqqw!1un?qt{&a=bR?4+jvK<*d=O6@lKj9F!ZmsJqoz^{i#){(? zFLwdIT?Mw^{_k&P$%r&fNvtN-DOy`HW6{oWV|_##96*$7q$7ZIpF(h%u58q69`R$BYPr~cLr4eVZST??mE!%`I?K{-Hr zOCAdjA3oKTry7ktpZ^Zp}HwW1THi26O z+sN;a@{qFXE<@WXnJ|lcnMr!BN^Rkk@HRwGT1IV4!W)gznnVjy9eMA|!h@F#ge1-% z=HK_xH1@r~Nr~4+Z(aJ|^KrM;&BJ3<2%W9mIytdvzv^}iq1{G_K|1Wj*{FM~+*m&1 zRjFpJLU=8_OTlH}QXmzQ0fLcmCiwyV-t%a2wk8py&8s)l-rA}R%jKY2 zUl6&LOhi%Q33DPQ-(~HDAl8ptH#W8|zIti6dU>tTE)I79zm=~){gr&gx65bl)vO%Ip-BHqObw``; zwVcUx;n`EgnI>*AblSOW7Qug@lo0oj13}(QRP)|+KA+bt<~E;OJ^!6);}PsoJr*6K z3(hHezg+;|nel#c6XQ-Ru+u8c9u-YNOy~R4=DSiDmw#ZzW_S5Q(hl+@?G&s#qdI1% z1CQV?@joSDcDa`pWUrA=4r+xd+U(4~=>6i~P6_mKk59cG&v^c}gO1=Hl6d+@W(LHR zKvDW?Gt-0ODA3=5z?8(W06dwA`yEed?uEcCiDJQ541?LxM^tD5#SWpD7D!A-dgGY^ zmbu#z(?>nzE7nR;VR{f1Mjx{c_-qcC9V*S)8R#9sf1G31*>hnv16s{^e^!Ou%n_^E zp=r6N!|#uC&@JxJbgLaCv>1*>E1nyF=u`Vo;=dY*T}IW?cZURbcS~^B;PANj{=T=~ zdVlnqnO;48PFK~by?34J2sMx#CK@Rk3=9mWg1odk3=C}i+rfqc_jcyq<*HxZAC70 zE*4dmHwQeQV1^#@-_=MaO3Rs+${|%@_)h8kROCY4hryu5miU4W+^h~7#Xac-90_o-Bv%7yR~!jh|GPaIo?l27)Nu_m{gJ}hO_HgedsTfL93km| z^4~2jB`meYiZTr>|DE?3It9~2OmP1Kn@2u_H;!9q@Y};IP}xhq2874+;gC)Md{<$$ z-fZ;s=h#R|CQOb3 za8JWwu~!;OA$)}YjMrOb-CQC-$Vu;LKeWa;%VL))d4jpbl4pm`<^V;XL~XLYA)O8h_;dln3`bd#^;ZXOR!{?1xNOkNROd!e(gS2Vx=F7K1~iKD3`yJNe39t!PG zy%{cOBXctC*ht8OT&b~ocmj(DEu|hpx!M{}3twC*)~w)`SCC3VbKw^3IrDcSLk#He zcw9V^DMQ~R3;aWwU@yKrLj)3GclOyRYAN)c!W-omlROM{1xZvSSp~@s6%@_FTm5b@ z35kFrnD1i!6Cg zJ6w_?v~j^o+X?5v=i)fq5&;Bz@*fj715qeF<*T$QnqW7FH!0rEZ>+3y=jZ6yt955PC}D z;7W8mp={qXrk1xTN#5O7Gp$M+ds4uc;p-7K4gn$|)TKJ_Us7vE1`#G~CHdd4*G5I( zerYw#i-0V5d$RnUf7dQkYjUyfr5THi2*lY&g>{A@rk588kc*{rxD<|)XO6!AAxNaf zRPVC*gI2ep>1Rm=njI|E^?bg}nP*>7^6d|UPMZarJy$Sk@&ely^m0+MmURJh@2dp! zB1~8#lLZLSjIf!0FY&^YIDH-cDqu!-(jW%qdk`M1NEHu4zy&&zqacGwv(aI)p@wL9 z{}A*{x7$}J(+ktQ z4O=8H;Ao&&2uqEqiUJ4AA)IG_JMfJ=e>}b#|Eq940BXBkjnc5~fNwRo&WIYbqmih_ zN(Vob2&Q*ru_7U9(u2c|AOK|9diPot5AOv-3v z;eY#$G*xzdeU1Use_gZ%HH2Ixt4w3=B#XM*n9&Bw_bAY$IE$oh0^KgD!^z`Fw^2Me zB)IMou&2Z7TO3e@Ru6->tMMVNg%Bv-@YFnHT4D8&6g3P&KnmD058hLlQAF8l2@*!G zgx~VamYc@IlQw0n5tQl$HN)n~Kxp-8eVv#D<|xO(^7j8mPhy698DzRgzsjpOPxc!m z6nTOnAefGv=g@K5(O}|g@Ct=GVDQ`Cft*5?fs0^XN?r;iaz|d@aagafc=9eociK*C zUltOHk2h}a;#d$Y*7&)(0SyQc!0f(3k%sHNAhoKRI$uQ+PTPdz5Z3n7S5Yr;w%>nC zVHuQ-#q#r1&QYcPv5GKJUUsA;neQByWY!-**_lMG@1fT%`c&-YBgH{2?xR`wq~_L*6AVKJr!-v9jtiSmhr5>x${rN zmFN=;v_W#FsekF1Ke@dj%>qT^4|&)VTU_Xm+-6uvD`lS0KuHWl*iO=pSA_si@b=Kn zc@uZgO}HuVr3GQa-w6tlXMoDTY#2q<54q@!`73!m4yRnCv@G1N>h2%fdF^I7QuNG| z&>46z0UHqW=3Ut9tRRYwRdB>#-`0n&W%+xv2<71Xy_WM&&IS{9@q4{jo1WXA*}_Ph zu-SW6TTm_KdELggkQ>zru`UNQ`-`WmuKkV2{!^ielNOf>smd%2GMC{8{8gvyQC5|p3B+O=7dryg4Q<16#6aBXTz)9;@zDoEvv(; z&wDvt(_Ob~Ywn$Gd*kY1pZJ-7x%Oj01tH6!Y7^f`o+UVi5ARv!A1%3~=I~Q?ioZYMaJO*ilo8FMXUnDXG__C45qR`v7nksf3NS4KmH%JHsNZE|k?+ zvjJ|oSnYL>liR04;JG=Lc!PAZb}uJrl;=@M0E7Jx`KkgUe;(?Zcf>(0WLY<5JY@QgqE5! zS3va?&>7-?p1(Iwb#mmWSdFGI95uAssHW8GNb`C7G#V_qx;8IHhTbBYr}iAt%fG*J zEauqbYKK<7Qd)LfKHAbPsD@ZN+zZF$wetgABamBdY3uVkoJmxq>6~FyX=6BeXs~*_ z&$KZStWUVC4r=K2w3fpy(1t6&*S`W8pth%6d8*fEM zAL!^T;J(FjM8C$JmjLcWCCOlT-4{PM0m7MfcDL-_ubY$V=6b18l^2KXtqRHwYLN73rJyLv8orFEMDiLDu3t{!k3RB z>EG6V{blTv={TI&b+h2-B3aSj?KVza~`Ay~m=b8E})uVM-SE4m13beWUg7@(q8bYTZve z)c*r!REXmIdhn$oHdJprdD1rT0`lWr^AZZBtqQL=Q=iK2ZmpmWHA@H*u7Qk zuJv-z(VRKY>h1+O9;P~HD>BQ4y%E18AmNaxSHzP7s}k6%E9xu4{8|WW<&PBTr@n%O zoznEX+KdQ?0kmWB|3l-|e}J`ECGajr>*W6sIWeQj46>XtX{=6OM8c#&F4Hf1H(=JftEtV=*!IET*xd8xyT!TZ2u`o)OfyFq&vDm8T`Y zIJ?e44;kCtlt=Z)i<~0J3*VY83U3Zn)9+L^jt2{xJsx_)!*J>7x_#rdW;ULKakq$U z{PRzAJ*zYnv&i6G94GS9!jhy0lUb#uF45+(|JHDh%nSoNNqz|@j93l;=aI=j!^0G%id%jD{*jXc3DvksW`>pv!c&^JE07kYYveUO9_)Z1S%<6 z@!5fcX~NEhg{aA7>NrkNy%Xb@1b;HSTd@Ae||o zs*C1b=QKQ?apD|_v(b)_`Ggr zWPS{)2z9Yp(t1ydbF05j4swGCJ0O7?^!8(ZCu=g!hc!CQP8lbG~B=#_7dgg3B`%H!CVbNXU;v1WIP;iPljETdJZ*g}oW3ym-QCe#xWy zdAHgYo9*D@=(~PAcwW?(g7Y!4fxo1EVJo@X&GgsM5)Zk99cU;!zsr&_gdG-d+AJ{q znoCW^80ZD3BwrQ!x31dbJjn0Fct*#LD~B*2)~RbJVzAn}%E13mE3wdO>ZIdCcT5Fd zMt8}Z9!rX!vfV4Ga2}qR$SGFWP7Y!ClJW=_K8WiWtOnKtEdoQLI- zNN^5aXhr{2LZlE;<@QThao^zuQ7^m6zpI7bE#kbVl4)Z6f2BiM5|j|{tCGnZ^JIWP z6B(LBpif;d{!8gjIJ}j|mt8^R)4PP3u5$W%I@~<(vadgL+n-yrvX|RAN76Ediyp*Y z&Bh8a)DuE~2lrpWHSTuQjDz_=3H~xJEEp__4?|-O0@W*GnLK_>a4_m_9P{7A%rY)Cn5g%CB{`WjXB_Hlb3GN5C)I)ezvN?*_Yrh}dZ7cdVmz>NDYijT zwju!yLEeofCon7|P3@+d6V0Xx4!019uW%%cjxne8M0uO<{3VZUX_J8{9vZG}&aUsY zv;=mLp*H-(vru9QRH&M#O68r#$XfaNWa<(UnCT${yVj((Lj}8Q7~C0ul5vcJO!E{V zXcs6w=&+O}?KtEQO9F)zywjoj-@)_<1^R9IU+SM_q)+~`Z@uN0fEv^u)biGcfi*c@ zO9tp?V6CrdG{*#7Gj}!T`&UbiOM0)w|DRS;8mxX%VD7INEg8G%R&j}3(!|g+c^fH+ zT&!K1BY29qOT3WWBfH$RTo7a$=MPpD2pagnoin8F+!2i7X_u?wiLC6ZML?l=m4hPPho6>Ry$adP+O+k9tqj39l zD#VUmeF9{_eq=2}PPH)l1s@@zHf+lPZDhHg|MRB58k4~)gry#IUkG^d1PWuy1VB#t z(dp)qAmiR%$Y-E<0y_Od>P31XCdbCDLFEA`K#UI|uVT0Q)UbsXTQW&&b=Emu3clvm zzTj8I9}RV=B97PNr7h`V8;`fshQWL8OwL*IQpFbWJ-V9%o`%1Y4G%GKX1|8&?8S4z8;p`BUWHDPI z?q~Gk?Jw*Q*hnOWrjFoS_KUOKZv&3ArNTX%GiMFkUi#fQzc#by1zuxMWal8Zj+A{H zsT+Z(W5<63l)H?^c<_)U|33?C4UhZt)}mq_M5UEF0y0gHHjs(Y3sIk=`~90Ijt7bn zAfF%g4P;hX3@xRerB1-ah={>dK=~j{j}!5i6fdLj@y;6aseXJ_&Te_`6q2~rQMU&U zfDtx6I}X|DNiau0aXcj2(fBSj>9ZsXjefsVob2;a!I7!iS5JQ^RNBrU}5xwd|2Vp@Yxss^@*ph#=SH zc$r14Z!U=>AVbtKUo(M?-K>qDFXV>AmY#>%`v_v)IH^KIr)%k>#3xmJ3jGL5Payp) z&?h0aoA^F7NY@G!!d7JGqNqJkA1qmb&FNM?5C8$kPD;sGhXKpaXVB8MIWoO&7ZJ3I z{LlKA$wm^gHVN<_UY4%VOAU{@Cxxmw)?Ttt(Ckp(fGBv}4$}%(@qffxqW_Ip=S}i$ zCietS`TvYV>E#K6TTt=AgKChxD`$hK-y`S;X|NBfp-;Es(VqagQJ;WpXlyBnlj9u> z^}_xKyshJGB}kb=*2N{PFoxBf(hW=VZERT_3KfeVg)x#?>CHkpg`daEjCo68eb3q( z%LDp?^%R?QL49+sUqB4d<`jXHC#e|?kezlhpM?MvE|*p+a@RRB2xm0_jFbxt0&FJO z<0irDzK{&Cia+o$n+Jv??Ds#K*yYOe=EBVeVg2yZXy$N|bqrixmn#3z@UOPik{^jy zxw|{|)Xg92@jackg?Ak3o4vI4b=+VK);ZM3+gXg`WTf4uDqT1RZY|2f{YW`^{sJG{3ccGeAa9yS@~Woy|X3z8{*` zL)cUZp$$%2nrIls45l>57OCaYhdJyXX%Z8txi+w}F5K{Jcz;(iX;<-QmdfvO!mx8M z0_-lDtTw;Bt3r@bP_oeXpUlW$nT-b|fLUrN>HA$Gu_-GcpHXUE6pgr@pWqz6fpWYf%G-ornTERe28ENR2r1n$?;Qaf2^otUKgE4jaz+TI z)XjLFNt!Sp4q-5+6!^e%nI9%2N}5OwG~3DMs~5P+JA3UL3KJC(^P=~0DBwbu z%FmCQVJy`htkw|hG;56y<%|6b7S%cRx0C&y_l6-#cWuwN zIaG^6ox->K+edIX!-Ky$@-fvizVBQ1XA+SDtOR^F`;Wf;>GHS{qcF%wh}VNh6NlHC z`C3@-_VdJ?Sg?lYaY9v;RrRKm#_i)xCYtquF+Y`kIPjpdn(t=!46=T$G~A(deqfPP(C z_^3Bt(wt#$u>a@79!fEsnK7mg;$bdc9)?DMVEpjk46=$yX_)G=Pfr$+T5d9|nB^?h zM>`hK><3OeUhc^2ktsTCP)@>LT-SX*;pXrC1WU8bo|5XnNL3+UzOj3D3|5PXphNZO zU4zZ0m8DBLscJU8BL}D2y&+0B+dj3&r?!FZb)P zN$TZ{5W)$->m>Tu&@tMd)u6{vH&{$+M4a%6<`GWkTKGq1=6n?av$FKVSaJAbI2-W< zHH3LoncM+-;YVwtYct(ClEi1!_#p&L5`I>V=^Rg|ISAXLcPCaQMm?IYEmh^v& z=-@o9r@3f(Qo*Q^WK78hE3{BPnO~S8jj+)AepbPEa3P)rmuTzF@1Y)8Z&lTI0(>37lPw)_RO-3!=fNfSuO{M#fd6Q8*C@#v~ySvqiejfK!s>B&{Jg#vv znP#I?DJ}KOSu!vrlY*Nt#D6J=Ck!@6jA7;7_I|eLhLF@KvRyX|3d&bwL-3a$Y;KkZBW#!u@-1 zxqCWIU?8uWE@s8*WZP{eX1ocmwa5aY9RqasUNC*A2u%%6_|nL0m+HZFVGuW+i#3lN z9KzZ8jPI!iA1MyY3|A(OT0GoTcF0@iaWAw!@G6j3^x-ER%)^Kb+$U-k0YTgO*xEg4_ zjcCs31bS@;9(-`a*^Z@*s#Dq3P?u9g>f-~N_1S4K>vHG^FV{_Ve2-=!1-+NF{Knc{ z!W9<;w1krZngt`e7!#nsm`G@I#H>&2zsI(n)i5?n%JndoJ9bi#53= zWWnC5Lb%ihZy8D_45;b3&zAmH@{_l|nP%#r{Ywb)YK<^-;V_eQQQs)L?EMq%{r`Fa z-c#M4e%CfW83M3hUr!Fgf3Ua@0($Lm`q{|FL`g|fWr{v7MKSF-q3USvrXZz4TB^(+ z4|gODFfqJOy{FZ|aN=iJalRLQ4in~AzxtOG6#H^kvP-nm1oBd!8vmz7xv$>XEJTjX zX?T+P7XUL`2joPpCs3$NYam>$G1)+ENwWLi8V^^Al9A#I2`vOIj=TcGT}qr>JkWBf zhK2nNo$t=(4px$y@DNUak6?zMvv`oqNinP~%>r=~E~oYSL5?#Iqnw3mD&^D%$z}Q3 z0A_7v(Y#+Pnc1&=ZP9S%7jv1KiPDbjaY=m+H??c?r>Ea56GL^RPk*Nz$abQ?yB?Ir zQaW)$Fzk42=GJ#?UmBfFCVH=<9ZXb=kfFabn*f8xOSdU#f39ZY&tiviSW$e@KQhe* z_B{_&DluCmafGLUdjb;~)=hDClPf8qNm~iK$&%lzZfHOxQ*2ZQ>EIS4o<~>MqJ);C)N9pv2IL<8!k zTMqA+li?Dzeu<-@9O$3hB3Rs^rv;8|a&-r!5o_V*QpPn_aT5BN$(uG14+kXKYlZi# zw1^fNcYu4SEOy#B&L%9VQ#BjMR>#V1yKhn zHITOYT41nJZ%l9sp=u(uuWTGW<&;dDI(_1lP zzW2OBe$3u;6Q%JYjk^i~29?e1^i$JcIBCO0k4U|9KGWmM^48-KvQy33HsQAN->}!m zZBd^u(UKc01PG(kMyHJ^LV_Po^Lu)IZ?c(Gm2*}!Ic8Jr3fEB+|C$%W?9|X@JZ9Is zFFAPE+X8NYurS#2oMYwKF$ju2Qb04@hk=RLG2b**1;G(RSaBFY<9ZjQt_-fsx}Y7Q z-2UUgq#vLXyGM`@SC`2X$DB+U?R+WCCB8}vb#)Vfe!nR~>xU_@p`fNXkgulwK8zr5 z0do6R15PCrqCS_*$m1B?ARS-}XCv!yAK73hm(gVKd+>!-|*sIV5B_-vV3YTHoQt(!i;- zl2q}v32PQRE4R;TP3<5Lx7OkiS(no4OItu4SDh#i+T%>!EYD)1!dM%F>Hay>+jCxw zKoy6J+2Ap|VW*vkbmti8Yqj5;hQapM_M4qQqhd;6&u}jwf4lu& zVL>vBWf~A6_>AQgd1r74hl}te!WdjDj<_N-_wf{qevR}8THTu#`bKNc#qDf)GUK%t z6gu4DQEH~03iY(x?+c$Mz(t3$|A2yJaz2~;B3Ax~iuc*gQFTE=p8YuY$nGN7Lq<={r9|AWnva9K*3l~QkqGhQ zJ2O&rJ<+`(g6&*MpB>;KAtZ*IzmVQUqG=c<3*k#s*Q;Ws26OSn8eTP0``zNq2V2VL zr(gpc*mn@RUpq7IeQtaJYs_Bj(4aQey{N8nDik3KhgS zIb1c~{idaaEx&U~W6hHUp7%1Og8tw~yE1a7Z()&PmyiOoTtmY^5CQ+%wom0X72kyC z)v#8&=-l^%aZzCgQ=;&}796n@1_?@&IA2qu)WDK(;w9oKnxGb z59n3T)S4`8Fs$9Q)Ufr{Hntv@*PTN%YvTNQ=#DVh^{X=*I{LcsS^>wZU7`y!Mlf2i zhX>fGb6#*i3DKd8YJJR|S>RRXFGcAlm{Rds;D^M7Kg1s15bi=SA>S@pSQH?L1(k_n zgkcaM^$i8eoZJ-yK2A0(R_1CbYFmd}eq|mwR)(cLn8%sv;M>(Wm;D^8!lf@*A3HB$f7W4s?uzp} zZSsHOJ@FbgQkxy_o1IO6_#KTb(BiYOHMtq9xYT*|MNaHFiYl8d)5Fa6bMq(RdajP& zw}iYme)l{SeggEf>SG=t-4#YXa3nqA`Q-M&hW`th*=A%$q#i7qIHBVn^irIP3+5Ug z*bTeQ8ZKk3N%C3AhLts!h3oGon9OmwH=i2X`&aAD>2`FW^rv?+m6_lznoRpW9BMcq z0+6tAuyGL3FWxV~4cymn?i(m5D=T#hKU14%q;nlK>XHae9=BY9sFR|$P!qKg4NU|^ zcLV)z@(oxQ(j{=mSWD#}(=1K}eP33v{UYV`2!^yKj92;#Le+NK|T|?`ps)hq61e68zqj*43A(Mz;WQ0XJ{|U&fJK^1|OAc zmeP6FT@(1t{Rr;e=6*oz z1SFH(XQx4E{Vo0V&GJC}M>`Y%uD9=9CvEW63*?=X<)*Z>wxG8n_p`rU^EHwodKOBX zZQ_DyXa3hNv@67bbihfM_t~ERRSXrS;rFj8CQ8HmHp*E}&Bu&q+?c7|)WZ%6*{e~nIS8!h8 zs3^k59cl3=xj!C6x~TyJ3k!OW7s#-HxP%2&7JfU8MhkEYGxb1oVHy7o*4BluEm!_< zFn#x9j7zQ9ijA9UXMfIon+tatJL;yuGC2$UL<+NU#pE&35BV*zLd;QDdN*H+3Ylhd zXPYPr!0vobD(OkM@9`BHDVZdMEfB|gtKTEKv!nkNR4OX8eetI9+WqBXRF)c<0j8u5 z$o|RX>@LFQoVt*Zm*Mw%{*%e?PSdkWjVOmLrH$)ka3QKR zB{(f5(htbbk)XB))kF#P1Lls)f6##L<9|aw6H$q6LLzlcqrnd!T|n>EC8FLpe2~>L zK2#KEXUm7wk<+RE;&UmMgxgEPuP`(#I0><(?)J7{T5Nj z)0k#mftjyyw_^7@IsQtqwL1Z<@Ho|?Zp%x&89E{^mVMUhN=T1jqmuLc9N&BgKWn09 z#@Cx`qfCzi!HZ%|OZKeisV`kl9)6|n6>8c!%6*`_iSMz zEJLxCY0w{$oUAYPLBQ-cd%Esp{aOG_i7LnHW_ufgmfv=@f#ta{qQ7}%nfkGQ20O-~ z=R@^h*+X;ADwS~dOljIzAKTwuo(Dn&0x7Ve9FX>1p^QxZh7}7qb{LIXUyB?Mq*9lH zFTr}JT5*5pF1`?tcL;ZKu?JwpBXWx)6^~6wqqGcV*r$TIuT#*vZoX9++nEtHqm9C+ ztzXS%NNNU6vbObm&4ViN6^GCAV3J{{X8ad^=HN&=QhY!_yBeHGcCv7R{07>N0xFUM zQ&EZq>xB4z0zj>%AS+2n5J_}!`~c9bW)QBS$PslZ5U-nEl)_F~Ov}{2OhX(c=7YZp z39UeodJs7t{UC0Tt`4gIVuB_i3XQ6}j#M%jsr8TyS2V2fbuQ+>WZy&r1@_n_35iR< zrSYA!+%ge1Owfok7EMnl9?Ty=C!ok?HKKeb0&MfeywU z8rx15K4c~AJpWcTJFm6P<#^b5Q8JMI)x{T8vH|#^$@}>45cnwI+Fa*j&akTRQ^e^L z%zA($@zcm>LsLyFv6kX6; z$sjbY)a4Rh=^!v6@m-zKagWRgFWwS;t?UVx{F_1Nnbk zg^@PnWvefQM3$9Aeto*pn5x)a6UpWC<@>-#gRf)YkU0YIylA|*4I0qn5StNrqgbK4^)ibe&I9YAF7e&rC zyphQ;LflMH4Rl{_Aut3d;E!tp&9*cu^lUrO(JX~LU>$A7M;-Dfd z+=W)#Hew72s0GI{hRMaHqT%Ish=WeW8o6RFzUc316cG2JJTFdk(%6-GZeIWCs%d@I zDK3h{FU>d{6~ilNQe+)MEV?}wd)jA85-=0*CP;FLq>^~c~woO#FN#uEj0Qj3%9naMUf^Qsbop$#}m!xL) zI^BNH)Jf$#@usNS=6(_u^)>f#Dk}SQtp7d1Ci7{H>9tI;k(0&geWqA3;~H;Wc*Pd- z>rc|Pgkwqegu{%&j7G+VJ%?zjj@!!vj$GnF_>OK;HQn!DrDBKxit_uN_XnS>3bB-j zZ@n%gH*ODa-Hp8T`DW7xx~f^a8f%;)t(?2<;Yf^AU=Jw-o)R_~fj^8-h~A-EpZ{`J zd_HF-M01He_>laNuB@p!G{~jbOCZo)5>J!wA|4FhO87$r?0Z*C2TzpVS?C6#)q<!%h~?Gm{s z9%zY1JG$_YTT+;r6T}c0Vf!9R9`-41=Z7Lz5?eTw3u;S5m7_P!4PO9;5|oB_hG^3d z0zyBgHW*35J*5RWYa-?7#^T`VTS)-I$mI$U3xnl>q7~#V0UK_Pk$rldKI?BSTC3#d zWRbB%*|6i66x)I(3{C~zQ`w5UFY}Z(B_yWpfXcI8V;Fgzs{oC zc$9vhnI?J5Iljv8ySq5M)am>YOIsTT#;rj-#dY{BQxqPFjoq0hbAbv^@Bv-a_>C84 zhEtO1$k{yXQ2E~Mxn~LR`f2=4kTZIHT$$*oM{B=cpD>~jBVCzKb$LzaxVqVx?mABgntp5Wc$6dGGe+@b{mtkI`&*>8yljo;S#4xgpt| z+M<8^yi~i+qRo>B#sL+n+?^84c!Ysyleg4;U797+nP$Ull(r0Z#UU%Gy+2V*T|oNq(v=fePm?n z3?U@L-d%b)FPWM~o>Uj0)nn%r2`v)mBXd#YCy)QU@$5zL!ZAQaxO`k9|H3Gr#BQKl zv8;}f7M0WParu)Nl$v5zAjV>-jT)zt)8YPbJbE4u(@$(J+`vAjSy*VC6S40G0T=#0 zzfU7R6U4>yGV$0hxe~1oUUs0>I7T{Bn99f|%egxt?!0-$$)Xff6tDc0jJ1LJ)&u)# z1tBNfl{_WC*RSDf@o@W~?^zD@U3$(-!-AiqhaZ|a;`zHt5x3GVyYkXh^1FkDk(}2v z(iTyU>(~#R%{Cz^*_{hwFNLzIIgMJ$i~}x_fkjRA&ewgfK7`D$F+yi2VlM*ln%}{p z(lq~aF_kTXI=5V#pUQ+3s9Fdqdd$qS&&+cKwv*2FUc!x+fJf^lL$8JhnTwbSDvwX#nnE2)(x zbBfGLQuFq--b3mbk1o)>-IS;PW~{p|=KI$O;`4WOa`5%~?rh)F3pM2F_vm5P)^$$n z`S1saXG?>zZ-YDEUr*PWqLzGUGIPjC5w~)l$6h4@(2sS$2WD(klvYq}!*Q1V%=acL znz1fKu$w<=J-_^Iz$7VolX$z_{(B+)hxD?l=G|D$mmHtxFe<-4VHW*yK~Hf9EaG&o zP<`!}UJ<#;R|n6hKYcDb zve;l2xshS7cQEmqI3QLG))u=jy!q6%3HdC{J#32!fYMHzEYpv`^AsV2<+4BQc5 zNrrP^A!XoG)dQMb)$-|MgVKuPSVL5@6d-ImDEQJ=-pOn6@fzuCOb?;I@WcBM`?}tX z>q*gP0kiV;kFxqAx-D-z&TM&!Ds1CE2NiqQ8ETzdYPvh6VmcfzXRqh}*lFmz4QS2l zj7JIl{yt8}gPd}4qb1js+|7s9MY4V^jYt}SJ8hs(ZD&Joez_p-;?-dh41fy5*B1Wn zT^`?ULINB z3)V5KTm$+X6`AIC4YBr-NvE&rg#Xrc0R=rv3)D2VayaHwSas99+&0tCNJ{dEb-Vav z(7~=N&B?qz4|@zj=saFX(lBzJo$uVttOryo*44M@HXiuP%2=bi70<-~9Edp$-nKTp zwS$h*r2osq)R!wS;8LXmz=9vf0kX7j6(*~;EsgG?=?c?p=4sbmxCt?7^{6;6LOEGL7F?hd=JD${YE5i4+(t3B<(*~1KahlWw953L_IIIBT35@j86<9qE(fmTrPiAjUK-0b$m%w`c)CYGHksl=Jt1T zb_v_;A8X4?#VD{Ivf|v!tiV+x%{t%TJZ94yyIF4Et3EBr`Ca5kTya8S)r;mkT{yKv zWz+f@U8M}kDW`H?fZ~yGGhZ`i%Za~dQ0hTml5+fAFwX-7tG!LUc-`xZERSR}+@wGU z?|{#oB4oAVoYVo2M$eCd(~;|ndZ&TRcFJ(m;#Bd-wc^Co;$8t59s8I)-Zzg+sy?XH z&`-(+f(Wg_-)EqFX{HCAH~=&zv%_?y7fY6lca>4 zS>pYLp$G|kPXAV~%4zjClezIU4@jUIg8IX1BetR7OOeV88z$Puv0$m~_yWS|>0ajo zs?_>wAG#<`PI&OT8fV<&&)7k_^F8~WWWtzIt2>+_bo*?y+yVDqw3M;9ne}t8k}jS} z#BCVZ=rKqZrHHfb!|?}B-?q|u6wZL{&x{PYSOtNU)bKF-?8H>U{_6TfHsZM7DJd&B zl$DHA0$1sB-rmv}r}THW^VqH-?p!OhO{H}lK;J0EiUU!-o?ljrWv2+KSt%Fr=4;9o z!&5?I1RtIk{ED+ith?{tLYZ7l51x9j`uaI@H~EFmpJjS=rA zKLFl+FHkBCR5*uDUgi?=L38e-1>%eEkgEIbu(vtFlc3|I+8Mgb5Ys3qHi7RhRol$Q^<%9*7cP zF*)T5dY^chxKK}h|a>KOeZx71}ro@NI{jkTDZq%dvRjQ#`Y@1myKz5`APR-sdLLYud-;A zB9}~*;xET|IYx}nOQC~yAZali8~jx_Z*KAQHQYi!<7t*)zHdIMbxR?f<7L9c-;R5_ z`>Rfj$wg^D4}=~`@L(98M!nKlv02_aOxC>372kAs2Sxl zu#kZ5^IEl_okkpB(>-l4aL|KoeTU%uzwNmuE|EDj9( z0W#*4Tthuz@%bNDu7nZF%u}k$`kdBz$viM*R?R=Ro z=OkNHpN;S)+x;<4jD$IiWvTEY;@}|SIc?$&Ug2_~V8H~CxluLB+VKP3!H~H8Px1Nw z&J0I>3OWXxGVC_9c-z&Cz>my@`Q09yJh@Y5y^^`9>dLSF%}AeMQv)^C{&v?GV2g%i zi!SkQymS*I`8~W+w7Cv{Byvh$ioQHCIat;>qqv4=z?(2o$xsY?dZ;9woZYX6 z?_fcjwSWilJ27I>Z^4TFdkY~faDNEGGN|aF>%L-av|&E}Q^`_Rz(>%Vk^kJ~NY%w? z{CRKPdSw0g>waMUxY7*5XtpdY|db{@9~d2d|KW8tR;9qZfhHV0Ugkx z*{dz8RnhGRvgVd`b8|UfPj#GmvIta3IEX%7gmGpmmMqD>9D+sLoJ%%w%+A`egOS3w zdu3Tv!oe7%er}>q?nWa<9$!)&5u4|Q_Fs1Wj|L0x-(g7>5q&fM4vv;K9&(dt{0Uem zePFSu36;!sg%u6~rkGwJ0{ax8b=aEH8@;S}+XO$ENA#Mk!@TB7{c3l9Iz8j<2B0Bn!|h&kpqroN_ODUhmy1oo70M!a zOCx%!t4+7N^}Mi`yTStk=8FDLB!$~%H|xG6&2Xc;mm`IrNpM=)AM-4P8xl3r;8G1= zTpbUU%??K)56%^6(G-4*vdCS`Wi3xDVN{~dr-g~jLRCF}6&#pxUZbc=oY9)?KBRYU zFmoGEMx_b6BF$VKluuZYfWQzyhxXU}Pbh7!c0u4R!Qv@*Oy?fbvzz4VfO$OUe) zOy12>6+9rdI1%m;jBLzSGeFd129TOz4ZkP1yV#DFgv*#0eE7lwd1K6i{_EUDa~eYt zydML=%P5JCCVUBMBsxGd+hQ*0c84GAECNxo#kcgIiV2Pg2URGABi_sYO3Y$@y9Ppw zG5A0kwuG((>!2vU-p`UPCN*tMJ*%F>qu3v)N7cFUZ-*CyucqCFLrO6|C=W+!Eo^&K zYp}s^R6njWi8OvO#u{YVpoM*tYv*O+h=Uk$=8J-!^BLJxnayXbL!?}<|LX-%@(S)_ znli%&+M2m{G<*A8ea_V=FH1vxsLP%jfubK4Zaq8^d`M~P2l$=_UCXzZYuP6lbyF`a zG9G`=7INCXh9(mXmD#35451i z?3|vWiU7(pNU)ir&{xOMag|F>SVZn$f;3cBPq$s*%~IWqp+ipQIZ+-~<$ z8^|?A1&4LMuO{Mj({GUXMym!vBfxh+%(kMWk^tBIYs>+!@J!E$!--faoq7*($p6FE zdxx|6zG36`tSY5y)K(2@mxP$LN0iuAt42|K##W<6?bs1oBaPWwEoxJHQ>C?I*Jx}( ze))Wl-~0ac9?8Lx_~-FF*L`2-bzbLn-rr$QpUlvjT@5YW*f<9yY2&_p#XL8;nej2) zg}Ye$GJ2dWgS3DDGJzUaDCa)ohf^`zo^`g6r*SWdoV~Co1F4}7zRA-1;TE5h@n(Ob zNY4nY{yX@0&E)Mg_D|axT@3dJNq$C>9mhfem49u1#YzNMYs zL^aD;0*D)(%cCj3IW(@MEfF|qmS2H=t&D;jf%z6BFVwKwO|REHwso4%#=}%=iivvW zpgmX|CJ^5}eld%R0@zYK;%sWi$J@}G(+&IZn6f(dzmn4WLZ~?ZTEzYZT-zwIPyOyb zWvbKpWk4+aK{S7$kU8hM!!y=A-fgy6ky4%0 zeIjW$Gm$zcF`O|ji_vKR=f^VmeG;GPYrYh+->W-iR%89#%3QQI$rv_8G3K6QZ~AbJ z3HltV{^$qtVNflb41j z>f^k&GX5$?pQ0$~U)K3kqzd3$OmXYIfq874n~oM*!sX#42|?!bz$#~QH`xhZ8H^@+ zUke^C2x}#vf=eHvGRd-n58l z&uUfYYOFIUmCJp(o!=Ww)SAk2)-$uS`29`KVe1zN8zGUZ%6q1|6>jS@Mgpa{!=IpD zXa&TevtPN^A$>x(_-+VltP)_`G}nfFt5kP7A_adWO+|B(`m5$TFR$5>EGv?iAk$1y znv;@dBq)ZgthfBv2bOfpKep+xrmywA8{eA9{Z~vWS~w~`_Au;A>TWm5H{mSXtuKr= zH@-wFKiWmAc(oy4GZV68l4Nqi8+CO3e(x+ay6sRto!9@mbfmZj?ga|8tVOdd`At{a zs9(&P8haGKO~GB~Qz!c9I0a+=x*dd_3Y$d^bqLtryMMWW=b4gK<~9I!xk4_*X-R<`B^>~ri9I^ZEAV?Gpi;dLk5GR{q0gjDKY)C=jC8<-@v{i~EVk&P zbjIT!s}S?Ssf7={y_sf<-#>q=ZLGBvtu`^$ZD{Z*HLlJQZqR8keO_~P@|ob}fFGBl zSIBuy3fWdOQJyNl9mI9@f_Lx@neW7VA0haX?#sIom#bep!Agm)o}-TI%?d!7FK5+n zt9rx2UaM|y0roO~sLIXGR%F3w{;+h54)75>u$0BWXsvfUK3|7E`!sp9Khul8iu#Y@ zZaqB5Y|ox?736@|AMJ`%^*01>?{)SelclwIQE)cWA6*3DIQD@}2&KmU_Y}Z)o+xnp z+PtItzz*}z^}8I4f#Tw8)rTK}>T(Innxn0!=XEx@#AT5#wpppT;p}D{MJaHMr`(NE zLXtol};QU04<-yqC4b%+Fo<0&qh$qJ*AA*~zTaGsaAn%`y5>F_FTEz(y-KV^@z-)0%0vOv_@U zDzl%vGdq{T-Bq)@C(X}2rPF1N8n)``SUGulQVYqW?tRFP)2N+tCJd7s2Vtc8Pl&h3 ziu+p@sRr@4ceXFQs73TkHc?bs znKT^dLvxBLVRwoPv=)pQPB%`RYe+opepR2TK4>X@vlc;r2g79MNlHgbn~QG_e*Bzp zAF22P|L~EGaVyL51~0GX2mg8e^|z(KMZ=wae24Q1CA;OaLWKFSkG_5`A~qc;%bFbA)NM^8Saw-h{qs_;B$*`br2=21ORB zdSpQip%yUl*5QeF*fj1>T!B-R8W<=O=?cfrx#{|6?{Ge`G7S8(Z`2xP*o~f0gN)j;IZB6>0AmzL^Q?+-9y%bV<{Xc%?06 z{A*K(oOOHSE?vJCDgLPn0@q{MF+i_Yw_=y%vdVSBiagvo}2X- z#q-%hrPdG27-d7VqM;N%x5GU(>R5MSBhW z1Fxt`gC`DSXjg)#568V$f(eEk{tB~4R`kftf9`G7iBL}P=_B{K9xt6f>j!M^M47L{ zH&(`WP%=a!4mc4D4Pa?^?1zaE9cQqkopwsh{=fLJK!rc@;97!C@_|zD>z()3Pd6k-USl4mKaAB(cS{mfeA__)b6EEfJTlSt=iN~JcplAVT&)9V1^Vx;tp#7mjg z5uGV$aKZt+w+^4gh@%`%Ir*|^Cv}lDwn1YzRtJ$3nWH+Ll!XyDbN*P$g`*DMPecx9 z55D803m?n}KD#?O2!I9s9p2@-7`1spTo$F zryOuk)Z4|@k6l@e4+sJi!w;QZm(GOLJ2S%~9t>JmY1}hWt2N|&K%slnjGZ`eqB>u% z{t|WswGCk^BdV!qoc*~Jc38Z21dVnRCfaX04lvQat3o+Ff5jB2VX(m@@mbpmwo|A7 z3Gw!fQ_D*S7_>gQ=X)SZqRYLV+(PyDdfB;e>4?V(G6xdi!zB)J;YZsuZoIRj0LwI= z@xD$wI%&6WBGta?-noN-?i|MXCfo|sQ;aJiBTJZYg=`D1Yj*K-uVYvdeqVvGuJ&0k zA#sVC@=8#tJm=N*#Ju!x z-qnVYl7^feV{k3OzPbBW2~h$!^zt8V>p}Dvw(0=KHDj%LS_3eYZXVjI?D(qZhrn~0 zTX~^-t^W3{+;LDjpC&>4{^6^GuKK=v3?p)1vBNgtKYf7fKHOg843=-P-NB8tB?N)m+LAHu$B0!y*PM90k85xZ^?)Ge1;wZ5l`VMJ2?5dOyS| zx26LHjNAUMznBK7)IH3C21oxL0UD6&JvMP%a~5twbAJAQc9Ff5m)9cGUSDfuE?k}U zQzz4?)DrzuXogK0d2A~{-$e@JBv!S25w0H+xVO`?*J!n*9B5$hFkjcXE_c7$xU3?c z9i2zXMZ@l+gSVirjgPFX5?^`EtNLOidpQ>R`-UuKap6gTpWVD;;^cZjlA-tuJ$(z! zwWTTY>XqZ0;y^uQdM;{CFz5ptcH=ST5|2fT-JC65nPIJn0FsI3+cgi}X3Km+Zg(8^ zccDM!7Ue%GEt{!T=Ip1sA86PMfL-NAoCl2UV8LGGIm8>0H?~3oxIzpfp|uPI`grUOLCC1`?Y^~i zE_85lf|VV@K(3C3Uv7Ir8u|yMfD)d0q7E$rUOLVv87zxAZMC1j)z?~?zjz^BlO??F z(_mC(Qqgb{T)g;dnw>5Z9CWkETz%XUxc+kg0b4))Le}2F*y*WbaB#Cv>-PS>p4r!_ znM??(K+j2-9gY1#S61gn*c3<|Vq!^^vjx;8C8=D+CgUz|MCHLc-m31Jo=IG-yMGgd z9rKw|ADG^z8$cMXC}g0VX0FWi7s@iE`wK?}Hwu=CN(Z1#*L|ybfeomG5PF4^39~ja zz6Ve2mgq2%9}z#A{ag>*`rwunx8PK$E75P0^4xD*Ro4M7}y}h$_oHOg3>~M@WuTK_wyT?|y(9a+$GOBTp}U zHOg=D1F;Td)7(-B`;7fK=m+YW%&r|_Ph@^;^XJdT=78#|>de`}OdmpEPP;ao_%HE& zunv6jbw!4)Ivk>i0*lSgX76$hZ{S*vt`}OvUJ%|*NIjYC?a{L4mdRXE!3^!vN!|i` zcC=*XJQFI2SLUM@22MxsEkUMb8(TX^l`NY7BmKHa*L^8{81SI%t>($!Oj1l--$&J| zZ!>A3HodO=|9YU`_&R=G5R264fSkmm?1b)ar;fgKbF;gQn|NRJJ=AL>w%Xw z;8~)qnVuR=+T&#X=AeXNj z7>JU5v8|_3G6fJ6FhVoUu029k{;93gILlMsA$s)s(-&VI$`5J}sp!;2*DsH)<$3G1 ztidSNCkjg8l{hS5U}abo$0D^7GWVo)H|2^+f|&t--G`*`vN4EobysJ5vcTPWlIRlu zB_)ze>FS?z8!lV)`McKq3ynLUFZX{xJyR_EZ)%kF0nbNSdMqe1gs$^rYt zBTuGlGkw3aim|ZsCQpAfeg3^jz;bqnSQKj)qw+;3PU*_eAiSfdoH)jC`et?TzuS+a z(G|W)<}@Z6>~J?wDBx;&x>RbhYG!k%De9-K8DTK3NWILn=?lUhf*cUWxH!D-8<=XZ zhiw9A?)&jmv51WzuGiOvk92j1dNWt&=PhAXR*%huXLf=c8mkq+0%cZXzUVVVKix=qX*Uj?zqo;l+#{uiXEx{ozM}+WBw^7J_Z9w?L{$N?NBt&Sh1e%<| z2oYi~iwfsVd&Dkj{`wW)%W5( zW&m)pIeOvJx}JjQ)*<)&DG0@-BqPGVJg*8My4WrdrCNh4A{Oc*0?uy2%mfvRbSKK$ zwQ#z$MTeu$TauLs-Lh(=j6i6HqEgQD7dlbLL{c?~exsUeeqG?{puy?Atm88|a@*TM z*@vRynvC9&p zuD>OQ0d!Q?cXD5_E)yhBdbf$UDMICh$#w}f=!#hk^j5Km+vMZB7&vc#fLTB7`?Yrq zZtHNi`&|yPpH(#9cgSSiVCP7@08N&90PUtdB+>qyD&rNc!CX*O45Dn|zaoyKWDkJ+57 z>2YGCzlpiP4_8=aSnNU3N}Pv-Gb*Jm@b7UVpy8#yezj9qrEs*!LTThC=S7dy*iEd} zsj#|M^yFW@oykmXg|iQu#6;7cGP4Fszqi9ElMyx#8`;&r=C$ue>_3M^61mVkiDa~+ z&LLkU7p;hW&UJBEb9PD>b8O*~6%qXR*extp;FEvMRZTID^2p}gXFN#aIO-?s2ij3l z_qR}n#9^;N@B|g=y%jBrso4J}{In#2Wu1uu=b2&FUngh4Gcho=0~VlP1p5Cg81kLH zmz`~zpgw^1X|O_@y6yUemrr=@rW?`Co=Bs>W6@*i>$N!~r;ABxOS93YBt&knL~2{_ zVZlI2i)3!~zF(kOS&MwZNLfouOYK7L>p;S%nT3L#9Z0DZMCkEkG9L%ysHu#RzFM5+ zYxqam+R$P_b}I4%5{3_^4p#F|%FjlLaaX_`k)|^9Ur%;g9y}8JOb04W0XMK2>xa!f z?Nn=4%|zY^QzrZCBh%y3bul?E1P9Ne;GI8^{=Ehl<=TXgX0t^5|Jz-kc0z!oA=D~@V;!x^ z{V-Qy2(mny9D#z|tp3FuXSyW{>k3!&HcZZ2mKvks!VRufgfQJr3T|DI+41PUg#)K} z3uTO)EHqZMpuP(KF4*7E@%JyCbP+7jE`|QL0Zc;X@!5k8R}n9A{mdRNEM)FuJtt%n zj4gr5cizO@{iWrfL9lybAojsgi+KT%x*vRnS8^=wh)Hv}K*A-$j~j-;>z1f z<;slYNnU(AYHKwU8@jT3;#f9oY5wheqq=2(7NIky|MTp@J0BfkzYm_zJac~8ipj3i zgsQLmub_JaOhelPDoJwNI`49YS^ADY`s~4S6itt9$NdW%H|jW?#qV9t;vb_gzHv6( z3-`ae{WU`C6IcG0>4WO>*U`^NUBjN9kOnH-spHj}$T)y8Q7RqMXroYT)qox}`=I@&;8kv$MN|%s27s8{MqCw3Ulqlh5=f@nP*n+tv6pGXfC)-@|a0#O_%O z6)@g_;e1BPTA<`LAR5khLBMyDxyBDObet!1^@K7YjyDmfiy~U-BJ!0jV+(w|d_EP! zux)MhIO$MUq`=UE|_1%gV~wAh|>PR$<{s zQ-L$-;u;!%ifWO`A-fesb#7w)83ey(#d^8F^hA)3Bv6m9axC-+IQ*d-WsRuvXr$D1 zkNkP~t0|^1N;!+jH^F50TI~8yP1qTJWIJ(?k49x3P3k6$E#I)(IlL~)`HNhdCaY3E%oj&I>9Yqyp+!?$IB$~5vqKr@=*xaD56R%a_n zV52UA9E)G|)T|B1eHBv>p z3O}ynLFEAr)Ddz9G2aCcVEk3X*8_!LVWD23exW{+_mQ{yiYNTQ1@8q>&V*Op+?-y( zgfE`-4lwpxb3;R8!_2mSw?}Zxp32%Dnty0gM0ZkJA6nQ0(w^kk&5+ig68ZPb)zRhW zpylILGx44)+U!#8)yI|mH(1{^>l4JP+3kw@dFyZ79Css~_uI}6duxoT#58}r6$@Xl z@Vs&h@Dtkq^YjVo{LjAz7MW$7^Iu818l!L!#r;V3SSA#~rCZ4^-ZD?~EMlX^^J+Qe zJ6=!@F1sAT}PIveb47wK;0gi`d!CSGxJRvUKJC zxbq*oS4DKOg!j%nAA@sxte@!fL$2>0udBfL*uH}sD&n8AjS(AW;dMypRmis{e+rVy z81RY0UC@CnuJ~ME`UWw}awPHPzERjg&Mv{MR1c9FVlur&Y6vRcffnfK*98pq0xQV~oylw)!!SO3QFYA2HbseZ0Z6c!Gb; z{gww3VhcjC$QmY>tM@Qt8SW(`pT7>I9a0)}%C*j%>Yy5G(;F-;TK4EZ zN)M%r4Al-hy5yB;XI*g5x#S6GGv;IlJC%0+8I+8$%W~A7*LlwAYoYr7Xs$4y-{|p` zVa>Ty?0G*eVT95Mw(VLjW=%`93<=Jc4ZqBmUBZX2@@cfbTGKP>kSOoy_6WVc_+)ER zI*m?!+(a*4`s9V;zH{ryJLqe#z1GXR-%97jGRl2T+V6hRNuc0{8+hDSqS6_Z-V=Af z>M6?`bJ#bB=XY86pT=D9*jmox3xGY2=jx#n7FxT%E?%5> z?k_Id;m?D{xsv0$)96!Vb0G#}PErRc`vu^mLl_r{vN^6Z6NTLI@Tfcvt|H8e%9eZ= z$ZQ~Syuxdzm!N48*iKw)CzFpZzl+d%o%BF0zwWzNxw@gFh}2ulyo~4_kmdN|R$u0W z$Lnys%MnMs>m!(_(DflI;-aFkjkfz`yHrx?WAvx#c2L_**ZCzat;r5*t-muqnxP}e zpO2LzkjU%I<8qMsrG1p%`qW8Ph8ezfR8ZD(v>;B5JtVhFHn@X!AfPa0T|kiM5JmJ` z>Ewi^FwF62&a4`ImQePN6nOcZ;AVGIwUXV=;KD~_)e=FAqtqnA5rr_R=lM?I#8lfZ zhuSY8&%&(e!NVX+XwxPimgpso8z=kg8;iO96@r zwg2Zg?5tQ`KIQZ*C7GaWyRnr%9^J~=#vC92eH{=Wm%lzgAax!@0(}VeJh5BT!LB>SICubTX?+ zk+kw)CPSF(7!T?72VXcc?z5w%`d=4(}nl-q5m zvd9~ZMxr9Pe3i*;g@Xfp7E9eh_J^rM0XLY9?~a(aZfEpPAiov>*073{HoWI7QTV0OIW9iqw{bUM8q_ns1(AfIuO5B0oy$JQ}~t($RX=;OWC>l3{zj+m30w z(VZRb1R!77?@T6=Pjb&{^b30lAzb${7JqW^%Nq;yo(m@sWS?MkMifv$Z%bFI&emW= zrvO#0cxDwCR<*F#XliPC9M4&Un-tNX9IiQ^*WF`scL2pjB7G|FZdWLTw++3e-WYs6_Et8v*zq2FqWj#y&lH1O}SE3Z$0g3J31+A%38 zqQm1vH#aj#LB0TWwsRFXCx~b(VsBQq{hIQc->}b}xtW)eXgp%y@%%6egK9^<_7Lj? zxVMkUG+yGjBZv=f9^uXK-y6R8Ustp%)A5@GE)!vII{&5+21pWXJg$V+ogJ!7^-JQ8 z^u5Kxa49yI#Sz=SZ;pviU2rbST&LcVPR54T{?aN$vV5~N0n5NrUBuX(wuaVV$B^Aj zu_|{D_pr5Wj)prq(CNS@B|Zk^CV5bZhsWJb0A(C>=c%&)84JPnl96Yu{rq1NA=pE{ zwFLSFO)Dv~7TnS-P76fxI{U4GW2H|2sS$P5FDwRMZf7<$oa%g?alwt@jM~-LS;8#x zN-%kMPIJ=vwO`}~CDL^5q%cbDa3r+t{V2iQh4)O5=MP1BB@{AHQJG^Oe+`CYcIhP# zFufBsPlaA7l5gEknLXP-6IfOKU{0;M{%3AygYZ_(yv!!-G9_PGM_fh#lbAOPJ?jsM zzKue~-uQl!LB&9IrYB}2t}nmhBMZAJoU)*ySFc}IkdE_uFoAj(CJ^?KAlHOPhh`Bg z+bq@!urtlqnp+G3w+|!mg{CR=mhDGNQ|W5_si7-OM}x%m2aDi0hu%FB9cjh&lgAdF zfXBC-U3J|kRPe0`)(6M<_VWf$f_~llVs$5T@1&~2p!G_9;r-ACTuh9}=&V2O2reAT zFxFlkpSsC^Nm3y!jtXjgB{;_Q{oi5%E`{@ei<6TsnKF9C3(S$EnK3osAV;u2T2fKu z+XM`U_1FasMzdp{~5@RXgj0C zYo6YuIPWW&y%S!8FO!$>3yWt5rn-B0UhgdZoK0xN4@E4JL`EFitZta5L3Mt|LZt(| za9nt^f(U$>{QQ}5UU;zY@hSaVP269*3cfAANYdGs+OX?&F}cWHu?TN}Uv^^a%X!(E zBcgA6!+8YV;-9U@fi^Znq|EZL$;VpLheAK$UggsR8O~b1f@8s(=!2`n9}90=QqEFt z5$pxIzcz4D4=qp%*tc=6?pDW_OR9s{-;76VEL)AjnRnj#XYMR>Ed= z()L-?=Q9jwo#czE=Uu1NBCY%MK0|E2;x!`2QW(`(q{R{fxa>jr=+t`YTz=9hYx*DZ7J0x! zZ~kQ$*!!{VMX1`z~qtN0{lbVk90yBX03UgkC!n6 zyKT#uT!-AtL($g>g6PnWP0h#uc&5Hf2rPK@@F8KY>D%bRqX!)49pTCvMPo`UZ)}k5 zpXAbZLLusJwGFFi#KygmD_fU0 zdGYBL2=c|sm0i2&tD*M7oCX6{1clU#`Th-087HGo2GbVPaQvjB&w%K*} z2nddXrez2=1yjrlTAwv7XDloIrLBL{6VbRS1XPy~Av_nM?cZDUyhVLX;wUV*@6USO zpQfG&qBRa8CPuWWce&TJUg#kbqHecgGWQ`E_`|F(Q)9D2_%Ta&vznz*H@eHWB@aqM zQks(orBR8CN#MQ5s=>Y;>*qua`9eagdP@_*w02MRLki0b?2sNhqM@b^Z zpwFPq2|pjk0wS@-27)OD)d#M%8gTCKA8--kdBsbbGYM7vujCGoSRoGxCbWqbHc%qC z7i}FkKlU_euykp8&_y}z+LBuhq zE%7&PbUr%X=XtsQr?h(MwihT_}wD7 zkIuH#ESfnbugAaN-I(Sz&{0dU;A6#c|CZqLD#GX%COWSqSqxT-FoGaO7wIo6C%K<~ z`}yt?GkSfd)Yfto6j6vkQFIRktX^(rP^2j)y-{RpZ6D}`Xj=(_ZsE#>o z!645eF68Rd6wEOO0QB{{`#z-`pqTr2>cC@nhmS%xfR=Ch3<8TE?VxxhReSbyVnUHX zfkEgfz;s9l;zAACXWo7TC<3WJPWz}1vACGN&(^9{7{&gbV7JuhtG#0Ufq$$MMv&Qv zc#)ghKvRR;)0wix7=w-XT+zWxy^5pRE}vhMm7UI85b(>BM}mgSPJ+L68qs zkv`baf4%$jLcI@ef)_Ip zlSLo2Sx4i8v%Pe*n26Irr4VZ>)Ufo2#dlFow%EZ7wTj2d< z&EkLKn*FpJ#_loSGc%KR4XP@u8e0|`Q??l8Vc54}bO`XvO+X(6$M%7(6coJl1m$NZeqFw1tV*60 zfEDpYl6>;Viufb#Aq?g&P_7Qp`C`h_#qrJl+I9C+Z814cgR-@O?QQfgs0jqQ&~S26 z@w;HAp_vMX!Q=+-qI+P20@^gUbD-L<{JLJ+152IT+X~kaH2O~vG+tB>O~vWMR=|~% zot`gZ!z#y5_{V&WSW{Z`X20GdD9As(KK8v0$$TeIkJ?HxGAj*u|CxKprxFRhT^SP$ z0r0+pq%}%eD{G4*?CtWP32M*A0HuWU%gXz_bTAbZZj;^zCE9|W*HuvxB-7yP!92TAclaNX%jSx@=yoGLaa%{ zy>c*X>zMCK*Zb^ey)akc{Ups|bcxF8=oSo}fl5gY^fy7EOlxIeL8kJs1h+TBad}jsFJ+sP+ND5y%U;>nW3CAMM4$J#;>BQ1*L;P5P$+RWV>rp zUIG2;BlG1WbMHwYDf#uSRwl@R*HFJS#`vzFL4yV@6|K3%SpE?~hA(fh$Hm$1y;h7% zIX$IMNlB&@?4Ga%vgwztNyrOqQNeC-f`&2QcNdaIGOcSGCMQmf-$jZtVAFd%OB0Wn z)WKe&0oYp)rV#1oX(c>hw{;EX>CgQDIq?+eYlnfpn8O)Trf&Y??Shk3e8468Jq0LWX%95%;u}Keyfh^#%TR%sOuUos<)-vqyYP=Y7!LcR=ED~1M@@4T~8hBtpDxaNaEE5QmAru?# zh6FW^kixY2$IOBixSTc@r6uIT2;MPWN$C=M{}r?1!{hv*+X&hZ91K=GY2|qm*u~>6 zWNNXD7Pi+%hYkg%9)uZ>0#KJ0-2h@r!*?dJ$xnL#KfxmaL)+!(VO5P3Q`>I9(`Lb8 zfUZ#+rWVxu5k_>;OG3DyAT|u4{=pq?EEM!n;uv{6EBP=Z^%>5&N7JXiV*#^Ogah&l zoGi@GO3^mgge9SPW2_(Zod)9l?aqFai3qah=8ysEy+;5kLTZ9 zpY;IzckP+jAn{Iv#ahwH@|@l}X;jAE9{rMt$>L7uCyAx&&HfYy5~$&4b!5<%NQ0!f z@~<(_GQKP*O|g!2ifa$RP?qT1d+GjB&>q+^-eMhdkwNcqK?TEUUa#HQinGzbMM9nJ zLdq@JFpWv6X8RZyK1|aF1UV0*F{X6*h}K3Mf9`>mBcQ6N3xwpZ+FayjYk)0YxI~Qg zLV)K9BSS~iqqOozgQ|!(pSz|Fbi(Gp3x#+JF+<|9B132|{$YzYvo64k*y=}ck}%0t zc)FNEGZSRO7M;vyt)(4SxZ$hw<8ud~DMj=ivv0!sZkpj!p);*#r6BcSHIB6B&sM>u z!1Z%%4m3Gvx_`hoiVCJg2qgmg57B(v*ViXloYDD8nlnX%k*7wH&L`dJ_n5+OM^ub` z%=eEO&N_CCiiEYMLLaHD{rm+vVQ8;`wgnGd73#RF+9Q?HDk=_hoYGW;*{1aaHRcKv=O5sFaHQ z*#KZJ{Y{r#n$nH1htG$1#1y;}`kuD2_^Wd9J`2L4CjOjU>>9jXsDUt|G&JsmKmKkL z1O0dldy6TY>5kLEggwGO_MUmBR|4i&ns|A&^U%7ljyPkyke80`^5Pfe->N5F@nny@ zbe_`bweJ8kQ~zM8U@`Re`qU@_zv39jgg|||W$Zf`{odnq`>A{lo*;->Shy~J%0<|B zIg=i)4fugGrTd+qFkoe5W*ff}7=B1LFRW43=UD*-NFSO#>W{s38%Yhl=qdp3B2ZiI zSLF<-U(=I?EZCo!Pd<}WVL39uW4?YlFVB5$bIW~Ras1?*=#^jt@`}9ux7QaaaAdym zEKQbW6hLXJs(>OZii46-bpz~bR^iH>+h6r~KW)M}1>ON2S9q}|(PD3)35pUZCSln7 zy*uiN<`OEHBf{suBo=WR{dHd<^g9az92WC^+d-1mAiq>)anZ76wE%4Pnhk>$8}W(( z7Y>)ps3H>)V3=ICug*roaj#niK|5(RN=RtvBmRo_&>cIz>3Gn3C0V$y2Sj^UE64To3Y<6kQ*dr5 zaiPnH>1s#XZDap(zC^+rF#4@U(wd~RGnxf5c>DwX?R{xV$(RqxmeD4_Y!?H{MTT#l z6oP+IBji|vosYMJ7_p~M5>mf@nX}kykQc7XJW}uX<=MXFU4Ea(U<~||0fu3oPHiGd zl!N_17>Tb&)4Z8MOm;P?sxtR`w46KGAvf#5+Khfpz~oxj9EgxsW}8rN{?z8oICZWo zsI>6+M{p^E@y?^(X@n7#5W&nVzjDTF1>tj9^pOA#cYYaKWD$urW|hBjYd*o|JvbY`?V5nc;z>iT%#!2VqwoC>Dj&ZFK^s^OMen zpr#023*?UbYrkNH_*B#sw~by5_>NONp}=wPLhEb-x&cCz_P7{HbqGTt!N6YZqfNaG z+1yaqA5FJqG3Bv4Qez@&IZ?XYY6~p{7BBe5%(pz|f2B?(nbRLIBp$5JP(0&kO2`Bs zSp5fGTZXf!?uZc6ASO$m6M`iwAsWJeC?GjLspXNr0v~sVLB8a!k+BvIQNg|{g`F?< z1#<3la&SE0IuU4n^)6L5zo1|=G~jm3Z7Nu2`rxFruB8bB zHp>rNqFFu3^~6Tq^9vyiqU9Z*vqIDZ#+!g9pWD@#yox`uHd)@^Xi7;~UmJ=H~mTXRpr0fd+=b6aS9= z=Edo-M`Ql8Kj#-bDtu;~UoG!#J9$B0j;uekx$Q6;a^ zpr(pX;(}SW>r9q=fu#)vW0MgH(dF9UepmRtRrsGl5>&||2})1Xyr{b0D}nzJ#S6j$ z}m(+iBbQ&V-xd2oXTka^K~a zL`@F}_5t?Us0?)ZAMq09JRAtET!X*2BbfC^OQV?3OpaP@oU8<k!pdF}jhzShikl)941-59W)U_LMER$u+)c8GBoz}bVJfLx=Xy=cZNr^hpOvCKI` znk7&#LqbvmQ$s)>Qu-Ov<%p&T)F#ss+UwZ@Um%PD`>OF3Bn+PvcH7{QL8{OK2RNPhXhk9&z$9ylHm9ZY{if}+vL;x(;@ zPu+3r2axg^f5aGH$Vqf0YO^&Y_6x9^E2{bI`>;iGzx<+B9tS-ZCp+#L3~PM$QzDFB zB*nbpNk1DQRppEU(u?J~-!PG!>vRM3<*KfD+q3@1I=)Gxg5^QU|8Egf#wUT2p6)oV zNQRa|kmM*bCw&2wsJ!apSDO~^vz7g|=wiNj42bo=dhECoOy|SIA znW@F*z|3>NJIO891F%nxOprwl0-0M~d(gI5wsvoK zc>hK!_+6@5HU%rO-QLbj!^p^}YfWoyx*;1zke!EqIxKPeS!J3lgw^`c=`<7quq*Pa zr9wGKJj%LDNZ~R+iU!|mk4^|0jXV`^2M68^jfr}T3icR3G;&;2<0BZquWfaxkWecl z`H%lW(x7oK_3jPjQ6MIDboedPp*jXC{?BNnP{yS?GrAbs^ZU$fG?%R9+Ng5q0}H}V zS^}2rLX%ARITNnlx1OH)^!+D13jy4N)-bH@K@T1je!n@Tr02ZQLPlpKNcYRBT6Yc{ z1$+8Fo#fu7$5~piO`bY3@r=pAOx62^SByJhIzR#0!7WZQe+r)X4f2ATO(x>%Zvg9N z>myAeV5~@}A`1TK**luwCRXfN8Y?}K%PKy*k#PaghA5>UwH)O;D$%tsj4u*`)O^Vu zR)zL~o8vXqYXUrKjP>>eGs(rN@B9O*42karfTgIUNvNr<%Da_!!6bz9XUAmwjc zKLb+IvtBw*?sp-~vu-QjxWV+_XnqUipuZ5iCq`(`hThL^!so1S%3uf-+x>^&U)z|NkW42?KU|&zf*Ggcc}xoo0eXu`LXLonN>Q zRs;h7a-C2{cfJzOdr!c8nBzY#ss1tG_CRD=u8&3piAySTVGvh>4T&-{>f^~gFM?N^ zd9Z?|IW!GQp^@k{m`&L@nmUUjeom!De04`c)33>hn=Dda7e{~@XaAj zcOPcNG#8n7@r{2ZqrBs-gU;=buebDF4@DTwi$3!zXPxv}kc&p;Kqmtq|G$_%Ht&R) zy;{P4>nb5aN>aK$Ezh;s2E*Nqu0@kV#CE2*4OB7c4F>E6O2t}E75ThlAVcsmm{4Aj z%fHhv|A9z%V1=l zNDtNps)uD8l9q}Pm5V3(@0>Z`;Ta>83+#%U=n7&#ecz(#7`<*8P0h;DQ6+CxIPbqYlC2<+dI=Loo7{to5Wm3SFJ?W3%19s^B_=U<<*u1nP1fLkm*?gb<%w|U!{6Fs$M z9ri6*=u6ETCp?hPPnC%%E%L^POF;U8KX@zq0hhYrbRgSw9|{7rF#kYqDuD3$*zv_w z%Gy}l)K(Nf=lx&ZLmjG5J3}kTSkwVfmpjU8si|3yB9Ox(C{?#1kO|?2_xB4C;1cUN zg63(J``3QhPK#3T=02epeU^OtGWuq~3&`>1h)J{muHaazzPeLHVA#vBke0e;%WR4! zml$v+1*ra9iU4P&IgX7W?9U}o_w5GN7_DAalWR=-B>d&B*BAQIPJ>{Kz9llN+RBTl z*rYTNuZ#?18{a%1y!NAyH-7M#+6~5}per)}Mv>Q+B&Q{YF0}ZIKf*|D9Kox6A2N{{ z2PGj#ElI`~A^(>Mn`8gTq}8y666Q-P;l#2}nY>-&rTYyYs&d-kHfvhL4pg+FLnRMw z@^X_=`cvFB9`04{?*73G1n42GTeldb!TJcu-2I6G zRYJ>Voq1~Zi9moqG9mv3dFbG6T*uT^7gG$e$6A(g#0f(Xc zmsSpJ7^RDScKU$R)7!~}R$oR`phh9&Va5OkKFM7;;!_EU4t4kUEuMPrUgKveENmD9 z=3-sAJJ|B9iC;TRu2MRa3Z}iO*I-j&aYbmIR%(#|q0%I{zIba#VD*9?syGYAMH9YYM=APpig zAR!1+(mA9<$Iu|5fS{ywmr@c#D$)ufdLDoOz0cm~oEPVuy}d49z$*sU^Q?8>_viku z!WR;hYjb(qIag+-Vm^xE#rVuKJC1JlvkE(Dd3hm6M#|pnQ^gO6b1=VTg4%Z%+|7Vv zh+Z_JWImqvC+QHq?oXjp84Nbad>xg56`uqJbJPe7@ZQNrygLSntiN|LmLghOi}J097q@QH=3pbBs?VmZLmHtd1u!7TU}q zwbX}z#?X0~B+O=d_>N!c!Z55xm#b`oUhERoPOa*=o6um|L^=nAh= zwc?Y9F(4l)!wtfC;Z-tRV1uH?^o{4Jrws-}pS~#QvB&TipM5q}Q;~f<+vUANmz2qR z8;@rw-8%?Q8fRt{N8rK_+?e>+{TomkP!^=Sr27!>&L=zU9S`tLP8!UVMx+?j*&Lv? za(S7_Ld66qeX)RlM9QChQr!h4$@ko~pK6%J@enpgiyz~f zk-rFdu+MRdJ-e7DYBHLD%jQuz+`cq`M6fUh8H6~=U;_7L3lY`eP;gAz$Ea2`*~4D( zd0!f6TJ^|PqL}(F7w-8m4?7Rj-Bsm^cb&YBpeO@eVk%e7*qk!penv~m+HQ*)8PmYm zLQ0jrg|{&xnlF*ygP{_%!!#h69G*)LwbGuFp~*0L_kx&YckZ_Z{phm{=*kc*S1#C- z9y;U2Dge08s+?Z#&>rwby8yi4Lr^^CUGM}GbUR#Tp?*5d0x_nQ~=H;8t zZq5Cw*lodok$TVX4ww$91!|mjsp(Ge(QA>jG3gv9t6-XjMlA)GLx zrEb4M8?rdT)1r7VA4SZ-Fq>{N6}*?~Ly^Al)xbaWg+y2Dmn!O~XdOL4N?vT&F)ZLw ztJ5r(OPxvY=dU&1r_!{i@$drRD6iySl!*8x6rr7%Iyl0>J zMU$$$HRR=v#eU+06@;B^-Qry9_~9LJw0B$?79u6bnykiqB(FNL2mH-uo;>}sk1<_X zSQ1_}!C0pg1r?J7QHTVv(gMaIE_WWnqCxaktgE||(MUo&+HlWcI~U=k#$=4ib8lzz zAshYL07V;a_hbpetDd;JbLXpIKd;T5vXVyT6N&}gx&J`HrdynJ_gJGUNgywE=<@~v zj&-lBjo-WuY4GneEBg?k8Bp7lwwN_nev{SuDWrUA*tZZENHtHvm5P^)##n761pYR* z1`NJ;O4MK+KvQ`fVy_})*WM!kOark{Uun;YodkO_xm&7BbMpvEQ2zXUQq7{tf{6kK z@S{v-wC(^r6fZwo7RKTI1KkefL55LuHmT{%i6YItr$>x1X=OI=k&kX<3J0j?2A*O2 z0zD4s^xwzI_B592qsaLFXnSY4WCN_$;5ea2o-kWK42iQ#L!*Cp^+Lf(YTgHozJQ9- z_=?pSS>K-rR8~g)zjl&;msGg7c*jI$VHXkL^{aYlc`;Fitv`^V%Dd^%ajXHZjR>Y+ z>n|*KB!7|5xz={={o~~Kw0+prk#Wjx_Z^umW_2dw5RO9zDUeL z9mt?Fb+BVEO34&=NVy1e=^E7(cewUE%3H0=T<_t7o!);eK=GV^3_x_Vv79^i8_~@< z;BfW7a}p5BQ$7HaSO5<4N>*<>x?TsBcd_y40rohfTk3=+VU9QNqA?y(@+P?m4@WUydYmqlF?NQI%j`uQBA!BPUh`dtO84M} zyU?CXB@lVlQ?yAp?E1!UgL&aT)%u13uYo;ov`UbkTYPhF*zSDkB|yG&!;MvjUS<#l zArU;-d_hWI>nQoh9#w)d-dY?%QuzDoxn#Rrs0f4H+kQ51?o(x6c^K-hS=J_sW`H8v z-F?nqfue6#+fqKvP6rwSA~uugYJcqmunhq2@!^xDk(sY}vs?+v{PYnnI=pa3 zU@vQEf3O{%Xp%6w<*5BVc(V#@x1$gYYyp z2&#Vml2$It^C7oGEM~p0JDmJMNmdk$XIc$6x9OfV7n(fCoLl{vQ-E26SgLgoEK}9; z3($WoLX-=1m+69|pl$5_<_#A|`QIo+%i;NH)(17)Wxy{J4EXl`&j}C?U0-A6Wmw=J z=(Qq4>Pdp04XA%N3IgOe3wH`Mx+HVtwG=x3Ymq9%DRYU<$&6;8&JZmnVUdHF|89y8 z&n?!E5QdhsJyh?ALO9go8pMZdAi%$G6Y2Wk@@nZ`6nnfBC7!H5Pd3%X|rB=%0}`iMzSva zMxKM&wTayZ!vnP%*)+VKI|+(^?y}qebcIWDQ7o1H!!&@+9BI9k z#in%emT5)x!G?I|=0zxkXJdHI-8`=2_PEp^3vW5YPWSuNpT2m(KKyre=l?V=4EVcO zsdUwMT{;Aa0$GY{So{oEw(3yAEZ2SD(Jd-CusFPhtX`p_158sbxFoz9>XfG5pmS9Y z>|AvyLTvaB`Mn@1z^LiplGDh=YH<+pJ7(A87a)aRdPNM#vmCDs2hZs#e8 zaA}X?M7*NACFREy+OG1%GLf5iNeoSg9Nb?DGL(Z>Ht;>4;VbB--4}~QtUaUsNuWd% z&^^pn*9{^r$_JQG2YyDh{ID0E$=9j0V8O|-A4|(WH~#Ejx>K3e9cbANyf zP01L$7%>!`c}T72ns=Bh_h%Ghqh8e91QZST_p(d+KuZ9h{d;2;mZ6Fihf9ulolfSa z1w=rL5wViSNbg^2sZB+od7cs*As?w1)t0$mIsDbmL4d#d`~2y*YT8b}uH7w$YMx*5VzT`a-Jtv6AQrU5QhOu;?U0XAOR`y? zJ`Iyla{na>sEk{gliM7rl?y)YoGZzp&h7=d$4hPI`BukeU@S@rqX=sor;UcI2+{Ii z@-YCb@VV_|`bPcf^@~CE!N`maR|)ncf!ULsd^%u#^vf3x01Q=t>|N7f?k-nnG@V72 z%Fx+g!>ALGnZ*y8*|{fABX*yOVm{g#NX%?AZ=kkS6#zF6T0J5@1loz5@iw-RHGYHe z(b8|>!j$EX3HN~_Yu(|Wm}VpoXzxqOVEB?Pj7WJ9MbJ6W%gF z0Od00L_!CcGItnkE1&~)c!+zp4O$UibW_ciX>faTGN3D?k!3wrWhkg8iDVIuS7fH= z)>8(K3ai&|k3#%BcBg-@ZJeA8H-_=hoM6}K8vK^0T)#l@QQBu1#5I{DT2b@7wwXE0k zf{RCQ!Ab7`hLD5NOX(%wYBKv@7+MTLjS%spDMO3l2owK!u}PqA&A7kkKgkpi&(uJY``@cih*st^CH8*)JN7t@}O zK=}PE5)uDq)@?qo#iAS{ypw7YN5p$U9>k2$@(JWUR^6goi%|$7acys{4?P8QQU)Cl z*;GoqKmQzjrc$tf|fIb6VpA_y{1Cm@pEV92%l zz=MzDy*HoCn9kpr%aBIpYI7?g5yF37)=VK_8c5!X*3$3_ijwaoepL~LaDo^7eZT)Z zjDT9Pz0O|@^F8YM_U-p{af-YQdx~1diKASB78|xXk0j{UOOIvC{55xscAC6po!_wZ zP*2Ytd$4U=2F4g1RDBDs+5o)U=N<$qA2=L}ms(3=C>D9((+%!$&|A&EN>+@Mdma2kVUK@XUD9l(t_|Xep_#Do4jCCI|T8813|S>_mXT4>E#SdrhGj9WDb_ z41w4ZPpK)X9aWVTtMfPD*Ki&OI!BI z2QGsfV|T$^-2vSuwZL+*@c+B6fXF*iwKlHEX6O*Th6IveIA+)Dfp=?+cg(+!Fj@~?)rxmni zd7rp#Y3G6b(NcnJVY3_P@kP`Yvu#9hVNZhA2il{L**~ z)c(9uTY~Njq`cl_P@x}}CL;2lL{A`U3fj$nqciF_ZYbe+09BR7!SSZz4rsU4R3gNn zl%PZB8~dDTVojGKm>~wRZ}mzLnP-&z2I>WaF()AUHsNC+XDeR8N%gnHkGp=H;1}AQ zf5b4~P6D)vqg+1xrRvbr>Nl^Z_b&ho0(kLA0`5r806oleRRArOQ;B5&`|Dc?Z==ju zkr2in4Y&M=Y=apscw8kgJvpQiP1mRUl6wYjw9TqY?i)W`%;oUHyr&`=kyZ@oTiO); z_lOrX%7nKmZ!pA0VilOPg)D8Hp0qI$-H&4iDTb;0tg-gMI6+Pd%v9Ki+rafAT|57V zC6wyi+ML@3!`2S|D$Winu8q+aj<1eTBSX8ts1=oQ!E2i4oCIPh**4WVnv1%6r8qr_&b>O{)7dj7$Fo!uGwuq5x)U>Cui18V& z_m{8$|GN3Z*QPKmh>=^oP1j9u5*8)DR_;3zR4qr@B!$t2@+Z7|zXwPfNi$yU18X!w zXojIH349P)C=9n3(a??qyx)j10rV!QH;8opCfg-Owt>AVI`f|QiriYCgLdp!5%XIB z+QVmP!s;*~Ot$a{N31uyF@(egpVRozvjY0t`aqsg#x1oJNVnjbz*QLs>>_mBN9wYQ zZJ`0cA!mBS;C+~sd@kTBz#~`O1MU_+14ByR+%w0pa6e81=28K`1&-Eo>MPiRARW_& zQ4|MAoJN1!9P)1lTD-mkgmLi}t!ie&I?DY;N$QSK)s4&xMEozHZ(vJgs5Oru<4R+_ zE$pjBYX5=I>P5n3`{AI-WIi$$dMQKkGf<-FM`KYs!hKkPe^?(jh!=34^OV2@s#8VLM!)R@QX|CM>Lj7zx9F&Q!wzGYXU`p%&sgWEcm=RHXvQYe4 zx<7`?{bN}N8j*q-ItzvD&uLULny999kfU}IL2SB?Zg1ukMnzLlXThPs1U5c|Fkwf)fAAYXDDwiFNRfI8B0g!;_ZJ> z15m*X9^x4--289o5|>^|&_JR_2^k2X86D(Wt_%QS2vjX{UwUiJRsknX^CT$avbq!l z5i}mek9Hqqn)JUKIs4Dmr8gbiRMMd0n2dIwfD;+^Fgdb$5>i02n*|c>nl7{N@SA;nD5Cr(>WQ z&X%m6G3+WY3Q+GrcmXe%l>b{C@_WFirxm%PRl|ej*GxACsDpr0hDa^1oSb*Mkb$s= z@Tv^gR<*V#ig3w-z36%iqNX9xUBJq_M764G(K7XEcs~T3@oHDtbH6HX3<-smqM^?- zW*;pDWgfWO1Im%9?rt?eeaaLYZn&}qST%E z<|&{dEFEna+BWeds6xz#wp$fPyBXd~NoSkn7*qviDbmLcF~{-anuw zik!BSX4U3t*N)_M?`$Xjj+*6a7T6aIA;hTYGVd^e{EIsQrNRt#vTGs1 z=sdEr>2u`(Sm>Oznso*lH6mWRRuYVsT~D+JB)TF8Rv>0Ni5gu;9poQ4pJRvImbP^y zm@Bf*X3ja7MDfYdWZ~6j&{Ld}NNHWJNprmCYWC4{|IQFZmMHJi5g&yFUhf=U-vgS+ zkgiI-NO{sU41j^WEF=m7u)h|TCoNb3wUZlM-~f&YyW+u~fCx(~e_6p#jQO8TS-~|U z%}J7mt>CPkB0V7dB7v{;+^;#R9H}rA1=ywXPZ;u3$XSvSNiiF+drJC;L!%T#qIx+@ zo+CE6j^#?*e9s>Pcx)S=F78zQ5emfcF%UrL(f_nfPQ}+kcK>#O+TMl*(x8FB5IZ{y zcnUNdOWNX3OdkL#0%ohPgR^oeP*-7>8pd zb_Rp0nwt8=f2%KjzH3ev&P_?EpZbQKTX`2be|`FlTDbfXwcsyFbo^`Yt<2K<(Nx^T zz{sEHcUnWZ-5Al;38}=6j(`OD7&C)Tk1qabJLeU47!YK-GK4?vO>=%c_fT6MsZ}u9OJ2|% zDH1+mVvYWh-j%S5ScZ#+#utPXgs~9SCt0dQ z?ZG9sE&^_3ZoQ7hGI<+w8F8tDi@&ct9)EsH1H|hTzp|Yxw%lf=hiWV>JuEE&xD_}Y zjLg&mDYTQykg#uj1?&#|l`rWlrY(la9lU?cG6Pdr z*8nmyha#K|9j~6)y2LKNZN!Ig2QCKg(8*U|#yD`Z*p9wX0K0yO*=JB&(#xjtm{U&P zW8cdy!oQ?t3$JCgXF>r+C^t?N->(tttP)E(*qUmE^6!kJcPDl(kB`>(8t+3`0|6M? zQ7Tsl4x&8$Br*s%O#gY(44vxGS=zKhaVL4EcKRHqPYV$TU{}9|2Z8*s8nUf!{e(;# z!uZVrgpn2xH||JB)b?nxWD|owCnA=pnvNad<|=94_@$~4ew9~Wca(c8zl_PyO|T7+ zF(D7p=y-;9G(s`}YkC`l{d|h9mPU!iBZAR5Q&uB-GWV%{3H)%@mhjef18~B}cHQeY z8FFDw5nKE(Ee5Y*&7iQ&CJKaLRyJTL^;D53q`vv@(*U!>mGp%>-XlxO@^S7^{uG(i z$m(A_=%y!0J1E0Bjld|Oouvr0gQ6Lnl%_RU`<_9j3xnto$gN`9T4s!l0*Lo;jCw!` zXcnel4T+(ESZml`Sc;L}L`lW@**D(FzJ^S(? z2ak`W9jR#BRXjNWFt6zUG|>b||39mrQn;lGD!$!Yksg{_ zDn-fXQXRaqSx3pm*|iXfiYrm|!T{;W{6)uD6yF@nkZVK(m!*N6}^9bve4AoKN(zbM~qQ$yL)a&&wL#_@$6 zsR+H>6m8GrCi>TC9UWpUM2oHTb^J#u2SjYXJo)4NjGcQpI)=^ffIreU!y;azXH+M( z*V@hTg7pzr6ZinYWAF>`0~Hpn-%KC`q<#Wl)B_%=PeBQA=RnwoYug(KlQ?Ke!DVf* zy%un+m;;F0Z^0l;TLE3*36OyIXg>E~Q`3b;v&;)5y+&8VSpK;6gQlhCB;vm|ocU;p zHRrJ-tFr=Zek846%0Ih1o25Jyy6mA6c?^TE2YHq76X14BRQt z2e9vkNP>ViaAxL`B^;Dwd;mVSKq1H!s^yVdnJybf`R>)*7X2XDFwZ~vKQqz(sn%RO zqX}Mlc{jhp#4j4R%BrAnq-{Np)D+ylV3bcXxt@W&C zpFcI*!{PF{B22mwNijw0GR08Qc0;pw_uyx<(q=5~?=_E%pYIrbbgcI|{nc~pXtn*% z-pTKcjp_A32^OlsXz8KmPv%Zhof8KKALc!TJ!%RNcL5;FtvnYH@@aGv0M^^~v=vUe zo0O`4G(AS{5jKz1>QYYP@E_?OYRTY84BnC5MV-H(CX1}xQ}xkmOEl#0Gfw;Fu22&l zJu^y#Zjw^Yuf@}k8*6f~aJ~a4Md*+pK#hf)(-A)%{wxk#=1y;Xi41Ccvk5u41QU$? z%G0j}n+4iyFlCKOp6~(t_kS_opS>fwgW3Ro%Ri0BK~A!6EHYaR9udmYZ)%ef23;0Z&?4UQRs_t}KvfCXEkB2y{RRq3@c`}_f#`J$ z1u7B!tu@OYFHM(ffX+Zls%aV#RAq>~o|L=VB`L$@!7fN&j0dNj^ZUHd$Z>>mFfM#p zGjCiM%Kt>4;C~uzG|}}~BWZzobW>J(i9WP5Ys-i+{4%qHXJLg9!vE*5nKgLVhZ}Cr zeFkxQ#db$*hrwhBYx7Vd^DFxMtklXocBCJOXXpF`5g~>ix9I7mD|IW5w%`0!|29%y zUB~yXLd%Wu7i^FeOV{_Er_@hk5sUz+S_TjlD3YLE%}6U|?#X3~5rB&x2+7-$_ZNeM zSoTku2SC9S1HHT|q^=DA7-~SeZ}52bKhph=WW9;M^IsxN(qs@kgbiCp{MYVKW88$v zaD?GTNUqdipyrUQiQa>sK705b_&6gRCRuE|7r+5Ws?9ajg(>ElW~|tAb{7T@yZVgX zNcE?(YuDI~Z@+&R2NbYTsc%gO%CYH@0h=k%SNPZLf^?$xRk)>jp0ypDqhuvc7V=aY zFwIaMH)RvF(X4}XyY??wu)r^9-C+Y74`P~1xM-o)kZv9lt2m3n5 zM&05Ao3sC7xRV$L%plkWpy;HUKRc`GYsY+z@J?EC%`Ihp1CXWS0oBJ}Vh z9=vEzX&F2d^hl$8b>1s+X}_Hssolp@E%pDJ;ZJvAGgvZh;}IrR#z7abY;oU_ZdZFa zWvMLtQ0Y&&r?!mw>1ioJXq_{-&fz3EZ#11!EAtO1Qk3%zXwuMU8FOPyeJwh z;Bn>U_Qg=+2#Nnwd1w}gjDaGv`5{i{??|szV(Zkwxj>#KnA!xS&fnnY?+OqmsN3(O zq2-Qjv_Hcis3RD!Qr=Il{fMW+d_pFXttcqSsp$6HH@L= zJiN`}%cmEY8t~-6G<0ovR%M9(qT~B!!fGop)S~nTq!nq!^w(bch2_N#>ypX38^AS# zfVP@Yo^(0d;Ze;FN|mEaYCC(AA-=^BenRS&;eFT(DOdBug)>Tc(gN}C;8>n(% zOh9VAS+?TCFI`jXa>7wH79Xg(v}hOH%jQw+O)MaYWm$*-7@=S0_8LQs)sq(I)=mqX zs?0HpuPNH(1H`n^$m5^ON1xxlY5qIn$j?`vg$j7I#8dza=~LV9xsfIJx66+L`&#h-&mDwWg zxS!wyP6yG%(a_^oTJ2mxqEA}0M7M!Y;d>>OO9)q$htW0?V0dy5NL6T^Q5I3n?E&nB zz@Qk~0F%7_+<*tqNuQ zQ>hteFUg`G1I1F&5scx|r;2MoY;0tRW3plSz488LO|Vcg@Ywaw$#2}X_6P6+U0&=( zy_NarHL`z<8IiLSx)A`X6x_rP%f?>l3TLh`8+A@$%~KKbFUgPd2CG=q5`6x;U#|Ti zCu@U0yzmo{(YXm)>ewB)4pjiZ2oKZft@;p3aPHm283;rvp(4?rB> z_8J)t%>CPwV#4ipV-@YYDEPT{&b!#}Hqp5pu|4fb;54b~F}7m)eLw71zGVRCx33&u zIe)J2MP~F={?2KOaK)5vAz}+P8q4ZiJ;Xv;moowIY4NhFCm|Ry$&<*$_VbJ{rOw zZS2B?MKLyUVR$|OJ5S>JDLUOJkz6wCS5nsGN7~f)yI+q&lY=(dqpH674&?{<5uZOZ zi$}Qgn>9&|dWKHi<)ioEIDD*erMSxPWTRu%VaNP=R66oCN^)<<5R z_2;nQ=`jd@iy<(h>K|)m-YpfsKpL|rBeE;6x>X6`iX@*$Z%Uf}pK-j*H0$%~PUFXJ zm`zlXt1?{k4lm=bq@i8qmJtC!BA8?Q8`s0KBu9NmtUNCMXnKP?Ucb^=wux*YgWJE# z4q16mVcSA010(2X&(||NdjBhtl+WIKKD+ShLGwZM#`y9N+py~!y`v+=;E=|!x%+Y) z=Qk!l1EmUdFu)jB;J-`rY;$wwbelYE?arj1?7}_8bU|p4Gm;l;T(0c3Bd?0)F}qT( z*<$#U1k4}dVX337&rdG~`??^Fi83sWL%U4f6 z+IXk}4Prnx_%Uvyo0go_yJA8s>Z2V$43Mq%Req{y(Du>NYxK>1-SxAe(t`~d|5<}~ z-u#8UD$QxC0%P~RWPxh2u_kGQ&qI>reQ!Sh!5#)YUJGr!28Ob%SB9zdOy>ec*krzSo?I4IT}Pybgu z(4Lz60B`nw5N;}9+uIx0)*g_-jajwQVta9?1`?X8q2<-7yw9i;jQS>tRj6XNB`%Yy z!JW}gkiYefu-!fYoKaj`y+@IoijS$-q7m8n`Ze+W3-l~?I%noT{EQfcvgt`d#AHT> zOAl50;6nslQXC8|&*`qq0GFNug`Y&Sguf-|6}TGx-UpctRL>|Ku(lfoZ+VX_@Mewy z-^j3f$^kdVACgd|&SiZ)Q~lCMYgn3R47ZMXTMD-&2UuAjrdLYawXrajDE6tN*4@;M zLP6_HC+v%hL(a9pKU=_>`Kq7@k%!1Zzfr?Jd_Qqye-|x3JA4h(XC9-)<DwBP}h=Pq0z5NB051DG-HrvP3 z4qZc=I78q*ZiKUx_$Vkecjl$ptA{voV;V7{Or&wuu|K1H77v4Sg}CBloxi{^ux|Tv5V!6i`}8(dhQyVxpICNT4GBrk&2M1nDR4*Ir6c4R zou>oLWt*M-1pM3g1ZDsm2sl30iT0{}^ysmof7jc0?`A9?1>7@tDW7*Quk$<{5-lKt zLIMRGbwbsEu*wuz)Uqmp%CbXCw$1_{&{9?j5Y_jRZ#x05}9Cj-$PS0AfwF8}(7qP$x}}2~`!$7-7|OvOyVMkaHu)DQSEtXECT2SEcj=V=ey zMsx7XVij?jvFm;BgbY3bEu}66|GO{q_jUdF^tpjyv13c$=fC~5z|=tJO?+N7OKWp! z%57yp{|V|Hk0eY0lQ#B@q0t?elVC>`Xs?K6ojL%6*gA12bGNim?2H?KJA7KPbd=F0 zDf|36biJ*HaDz9L80q{xZ?IuU4zbkA48=G@%}3uEBLgtv0+ddA;8$Mk7l)>Mf-

    {6478N@q;oc3BnU=w{O_Ei0J$Sb ztvIDYf{iNFRDblM7Mm3cQpy|k>6dhTOE1!N6w-@EGm+qkXdSYuc@l$hFCj#aN_Ji! zXjLI}p3qy1Z_vNE%Q*;M<*`kbJtSgdiXsg^uPXdwh|KX!ZXrVY#eMFBaayV^=H(ZR zclKl6ACDaD?2J@a`Q{V3mO)Qt&45mSp>B z2q#UPQ)V-g8vu`CD(?=+v{!OtN+Nx(0Df{_3JrT!92MRz)b#!wRQk3WRJ82j+>lpg zxP+1!B$rbCH(kQyX(IwmzqkibXG#a&&k<&xarGS$2;&$-z7p>u>?YE81f6mqe76oJ zQ28a+j7oE#=0-W2x1&j+*2U%q_V{6QbH~9AUGHzB%L5A0pCv}6=V2OayL1})_{6bp z!sO^`fZWENK=|r~OW+#D+gvf1qru0jX+309SPAsz)nKPY;}n{XP_#xC{5kxeP~IFx zk=>%Xq$wV*p7nu1$r{WX@(SH+mYPL3%)m{UJL*mLh*2tzDb;Q1k=P7AzVi?k+(#1H zNsB@0%myQsWZn=kO;gr_U(;Zw-l0C}^V8F!-{i8(#2MlB1^7m|Jh89zqTM z36^>Qrq|%t%p;H`^wpuRff7VXkK$npfWZjsr)9Nj)~dZcKtY*zn-C9(J}?JH2+_sx z*rLCC*WBMEp4cnVoumi|<7rYv3Z-}jXKNx5?owaW2II%&3`RhqtQsI=y*M2ssnUn9 z&G`7Lc@F45EEf}iu~+9(^!h+u0tawd{M@z(sfzG@KSE5c+z3s? zGge)e`dNIEd}y+=I;}*YUDZda&KIp$bN;@X)Tvs%%&vjcyAK6ZU&3G>N^9kts_YKw z6}x@~C5l--@p>ng)83IB?W9C%{}IENppyNkh1eZJggpGqDUDxS!A?1U) zDsF_J#b%5D8O5_ch*~olPKCDe4=}-Q zS^fVAk&3;#yry6_u^zy)GNK<&bhVS|evSC~@W_#m|8+{)7n9);djl~9siYJy&OqPo z+pl@Zj7=L;oFo}^#K%LjEuB7ySBI02ZK2#E6cID7Yb9#uC-KkENv57A@ZcR++#@F~ z8|wJ-<@fT?nxuj!oc|!<+2-LsR`^+`sHzf7NyGcsY4#~F4s~|_lcV%)O2NM0=VkXf z&eaEBZ2dmLVgseV7AD8cPVas7lX?k1`^35f{b?tia|QvKjlQ}>DU^Kvuvm$22ARQv z^&^?*>mG}9Rz3DoHq8Ba@N@h#tn?)c^!;6}St$AL>$+c_CriDTMhmuAzBYZ}3Ddi^ zSQQ`i#mlAUflVjk9V^TG9Rok2S?}+j{=^k)DEaOg(tUEDc_n+VQk-rf^#|7uvzB#jnQi(T<1<+G?Zj)dlnbS{6~n?>{=2RK_gk$}0dX0x;h z_YReP79Zp#H_xU{Ek&tea7U(6c^31|Fn6Ts9IR!#^nUC1qgL{w!TT~LecwGbZ*@u# zN5?QZSJr$(-FZA(b0VHEYFI(^3N@ll=A`=&FhWVTN=^nUGx^E-eoGijmDX6jT77Lg zZ7k-6P_8Jg7~tUDq%%m6;BkQ%l=g9qM@wjwc8T32~v%UPHE+wN2ieA#k4Hcf*U* z#%o4@uA7{Z9(OhucFQkM#Rpn884Nx#LGEsjI-?~scv*$umuD8j;KZ&`XJ6TitrkQxMXf`_}dyO zK<}uwlrXP3o^Y-+YA`-)TF`po&}^K+|Y&8UMoA(^2gj(q@}L> znbkxIcW`ISJ-2puzEYPJnrDfK=N(%QV=T-Wxtu}|FVskXc56c3EHBE*SXURUf`Les@syk9`Ol7=r zI~;fNSe!P$&^D}2Ff;@4U6(E5eP9Y+(%S|N)1SGwekAP3=Bl^f4&FXNKKp$T29y{3 zSCW69LH#HbVpV?bt%hqP(%$=8ETuE4<<8q|R#5v|0gM-q@zibReeF zta$k{@p>`FNm|sQb>fY{6Jc(C#-<5M&y3aaeY?A_kY!$06ZzJbL_IKr-Y;Hpl882G zQ6tBPcgI_Lk#AIK^r&9(t4nf~XP6e1uf3Jfs{QJ8pL5Pd^ON;9k+_+M)^bpYB1u)H z@@%Dd3f@3M=$VszSVBiCNz#j-lwPe1$<6t@S6>>QS@Y()AGRf*bv)a_ThM9B3OxHl z&ElQ@B%%|+?<3Z#5eObH{-otHsDOh*O|7Y-Y(!EzuP42I_xM25HJvT;ZC3;Xy zf#~awqs&*hkeN$Ba*bmrNjjl}Opf+!9JRsY4bA6LanVkwCQGqU;=ZD{Fh5A8IVT{| zQ;I5-*Y&%HR+aU%%hUZMo+kY1OpMMIXW}$3DJpm-MQd=!Ijt^Ib~Dm~m*Y>4d{2CW zPe=Y>P;WpwGyGNllbIOAR&|gdZMvd{%nEw+`z|KG@NCic=AdvbE_T`H=BEAGvtfVh zMe0vy9$;p~=|j+;CvpWbBfnG)5t1uZdNsEn;@3bYDGn(WOXp4u6IWKP_xRzy9Y|oI36I=4VbeWqed(RPk!9P+p zj$kuSk0KTMq*_{^v^?P`wDq;VIiP=d*rxct{{0{I`WkJFSXV&F#ahjY0D%|P@7vQ> z%329g1O|rE>P3z`{axhpsyDiU=~GqcK~+8{S0-RsE_KgaVj;U=)=2FvlPY4>n~XXJ zuawu`TqS+a)yZ3*Jik2{=wwBipepi7>#hgEY95^T0jZSHKB_idfMi4wlCl|lvc$^W zD--BZUaZ(EfWzovc_wc()_K8Wb;g1(IKO|B&2R2d% zvNS*k*2lq4;8)~ZS7)yXa{G1F?2d}DZYsP zo-;wi<#g&vAj5G$#}DtwrAaqP8xm%+(Fr08j1p)Z?HhQB@g%>a#C=o|yc0_5Z*QuB zJ)gQ9BY|izOWsK-u%q=Qlz4vT-44%lUH>rkictw>M%$_+EP`37snvT(;I(738VRBo zB6WGwdRMhpZ>E>voidHZeU>Ol%Lp{P3QoQ;Q6bCZH z^%L=WuX9udwv&~!mEEHn`%)=pIUPPe;F*EGrZBqT<)kc$bM)UZg|KO>sPDHv@?HIsMV ziY;F5H@u3MdFBS22pUga<{$jjkg$_-G&V9gy2$>IVUkubAwSj1?=+-6Ww8hZ$m9(~L}LayUIRqEy(kkG>nSNnL- zm4U;h{RF0-1R_rns><7WLAuL;MZ_444H)fm7(NZ=Mxyl-TbAnW#}PdwrNc!ufuI&T z0g2%V(xtYGQduYi<`DAJzx6@z`#h5ILK(ifDiN9$RVqfi)DpgkK1V;lX?s|Z2LZza z*WyoQ)1jkVI|Wrl$FqZ@4}_ANb$OfGxBTPO8N<=U3lzc~&AF>9bt~35+~x zh~efT8WyZM1ulD>key`C5Do2&hiWN9F^=318p%~p;$)-&b7b$3972GhyMKgNbgAJ3 zP6`1IK|9NH_*%gfG)3d-U~^xf*HFY4o4%H*keJM*vG0nY&zClM4fsD#+vodhqTc1_ z$%)!GYd5)WpbqmIR&%;xy<>+(@DOy;%kzoDJ=4d&6W_b=F`o4SeJT!QM8hk_av6a% zJ-8IU+a{J0LxYZMqdj-4N(z@_f`7U632hY~y089(EbmW}heMXe7<{j<)!5di-Bi z_3LzB-R>KZ*~mrj4dJIyj5TWX2lpiJnnqho_^zsjmUG3C$e(8Q!^i;Bnj>8D>BuqqjT%< zYmJVBZ#!C6lp6{nac1S)LGj)%Q^p#$4sx}2=3+^=7zpW6eiM(=WBc%MRoHWcJmn(e z`a$$avoYPK~6Cnw5f zXCe>($dfJIic@iHq)kqiK{{>bXI2?UL5}m>=O8XLZ_ZnySXD!s>k6mhtNz~C2l;`g zjOlDjgxn%32p-h}S4AfWjudCuAc=0{Z;MDNF|00Q3Xcu*cT&F~QM$ZKO11LC(1#Ki zju#A;{s7iS5!_eRuC1XFEO-q&qoCt(dDgG9`u>gBarH}*SBi5%iOqX1IRnbBEMV@f z*1>8p=g^L-dnLUt(uel#f^2^;i8v@{0DAUJ%Xp*K%XXa~%cpn20}&IP8L7xtMsd{Y1g2dCT4qnas* zUxvusnz-fE>|p?q!Ghu!YSSVS<`(2s023C#q_6;!Fv!pe9c(PQMA3K?yrDJ4kVl(1 zeuzRh5$?f!sdL$HuK5fz(R`iJ4QqZ^#{?NsSt) zb$Wf)d1nG(5l@tSjFw!?OyB2dLLo=nT%$xzX%X@!!6S#LtLkAggyX;0nb1oAfpfqA z%Wa$ze#xLZ|5C{Ki*m{v>Ht@mm}5Dl`jbxBWx39*HlkDwSDgtoC4&%7C_`&Qi)0Uj zIZ@J$$hm&D_35rJI{N`az!Zr|4Sa-dO!!m|Oam=T31h*dF4RjF1L?xV5<8L`q0Uro z2Vxc9>h$7Li`Kl;5=}@{VeKXA%&y(&Tt9kZAHs+(CgQ-uGzmT2>HPn@=_%n`PA$Bs z;Z?IQfd+W7GU$eV_wc#_TxQTCrxu<2hUBw)Y&wAYqQwjguP3kfDIO!fG-1sXQ?d!U zGvW17yYH;rHu0(m?7cPNLlR@|mCgha!HT4_FkzMqFwdM?+Ukh>ktX$; zY^Pioy<*UfOd0kOH#Ph281#-)kwJ!%XJ~F3!kaHRmFAPa?B~;0u(;EiO?dr1r*3() ztH0M-K_nITJlfTN#lEiqly$yk%DoBLgGa8KFuQs<=%Dl2L=e$K^N-uk^+xjzr}iib z45|V54TDzP)F^q;&>VhdP>HaGv$SCc74s>`7W1jr`4$$n&OhQ*YMTT5oz7b@rQ()H zzsISh^Lqfj6ni!SzThZV6J}R0aZgdKP5jfhv-j~Nb*aPtfk9d3HG^(sUNUH9UuMu3 zoQh-&@S+T$*F4(Q!_?gA^!l#=6isZ!zA^Cti;d1bm{Rf1L=B546W?>HXqyM}9jB5B zJ0kCR^iaR(48?!VrdJ7R%OHCLG9@o=7!-H?cEhh26xj#L-!-JSV0z-wuKtAyum1`_ zLFZoVPdK&ZQP7#|3!Tpj zBpAJK_=0^llQx`sYM9}**O@t$<`dn4DHXRo+ST8i@cQ2b&`Ytx#10~_cyz}p)cMN9 zjwt~ai-{dXzR($9v9RN{3D^_n)h&;96XxH%8L(cYJRabBhyviY40_^JWRRic-kG2? z!{{}qa84vxP%)q0fhiSV!{XM&_ng`R=vge8_>NN>0KEj$y@?%D?qIR2|5B$Npv07d zM|%@5IhAz60s8MYZ)>obiZGg^8aVZmL0jA;7`<=!nn9J!LPnSqU-4*HA12^h{DLW& zN701W|AEd2c5F=SAo5D*eI(!MEKKZ}@&zoQ{wtlZr!4Myw5#89%8LKpVEbPWXi85T S+>izU0000jTszm!wR7!UJJ-(tiCf(NB;N02Os3W;CwskK@3F@o zd+))62cH8Zpf3f&`zLVP2fV#|_ullt0}mXYnVG4rtgNUfo_ON!C!c)sd0@)QI8e6A z#X$7bQ&0UUNs{{E!-o$&{P4q{1o}W^L1Y)Zuyhp_5A64quDkBKJzxCn-G4aS?T)Ul zu8PMWfBc@~$B&-`b^$wqN$Y{KwelzsY;0_ttJmwV5klM!Oju(Sv0yF+;%Wf!?e|nZ zfA9Oh^OiT?yl;APB51W+%r+Zz#-~R=_|Dh=;5Wa0`lt6j^o^eb9bn8V?^&e^0|Z)Y zPM|8=Mx#c%)gtvuYz`9gpjQ8n|GfR< zzx(;?KlaCGpI!Lum%sZ%`*~^UGXTWI#KexdxjB}Wmarf*K-l*vNBIjNf>)?~8K{5j zYo9*3bH~o9>8UZMCdL>aAEVyv&}fbUK2g}`rGB(lJMyuJN zQExI@Yf>uL$+8@y1euO$*UKoGu)4NEBGdA{``+`ZPv3Lf2Y_T`WTZJUF>%L{BS)B@ zpC<@{lRyoqS{bp%_J$Kr@CrCz|N56cd3e{ZSM6@M>Wp<-blOeojSl5nlRWoG;*i1S z27`VVB@?8O7_HG-6NU+spG=u(m!rnTmk!X_= z#|a`yFeby86s-+P84@AUS`tQr*X}5@wzl?5plK~0I4QQc|L?p|dYQbheeau}JKAoy zgHEeKqh6&_DKlCh!yl<)v>}Ol^t&r)tjzfpflZ&Iju`WvdDq==LRzET-gp^twwZ8IflxS}VfAmX(b$Xk$=PB84Ck5~U1M zYJ|`vN)jis2wJT53n_H)9l79v?EokNwRhif+fPoMI?c?ENgA~(H@s#Kqs>Wj0#;U5 zNx}{MY^&C2r3u4`D7Mrw2CWrRO5!*{YmL+zArw+6lukKuX1(h$!n3V|+aS91@wVfE z3)Fe!3;SO@{HJ5S=fUFg8d;X{tKS^v`rW&koqaRo?FKs3EU$K{Rx9MGAsmD#r7>xW z)+tIV;zVq{RvIC#^2%Ve%KMS-J9lSJ%W%n#xwIYY_Xpw^N~a$h34HS003KPEF~6|D z$y4);kF~kw4L2}0)?j^olU}b+o@%meOIal)Ns^$HLTQbZR&lhVZt(E&$np%|^YJ_zPkBxh3+B%(;{l_U61{$e))FZtS{al!NTG>@vJ}#+ zZT8K|M!aI1x;5au%|MY=I<~Kc730j!mjn=404-qZFLP(|x6j_ZS7}knfWY@S`obKm zYh9$0wA(H6JSWd`dQpT_DYdf4W^aH|nlwuhLLsCikqRL+N~`?2x%G`K&%4(0>%b-u zI@V7d0Lk!l=5J$O&g_Sx|M~vGUsozMt(8VdO*n|RD(@iTr8CQ@)DQ$dffo=alC#|y z-}i|UL6S(MR3y@%q$W)b%j*NJ)2wGLUeHE5R?eKkUOSf0x7$jj_Jgs#p!?t7JNQT6 z_lz+amFg&!$_R~Ci|L6L%~}=D_wfQB-}fMgfy(jyfGF9ryi$6rCK#R1FZEX)<=w(% z9Lb!TkPVNOm!nY0_9Yb?&~>2p=Od@gEqia6Y&V;}ANbU&qqLe0n$0>Q5#afhe4i}O zNHdU`he=`vQH(MgV^WUJuMLFG3fipO7zmwU71kr6^M83I07iy@RDjBJ$L4jbS*`Av z8XxI&nqI5bpi!%Fese&c=cHLinnPw%j7c$RPNoD>YI=h>ducUVvbF`K-xilIKJ$)y*FZ3fPUtCm2URY4I(Na0^JzuEQQ(7aGMyixF zOUct5V+_aUSNf4i&pFobTI+{S_ZeB~7X$x4+6@KUSW@{zU0|VjIxJ^by7J`0l3ZF| zOQSIKj8dM_8qWjI54@MoEXGUge?y&h$NB|rVn_MDWBrS+886jJWR7ym397EsY!z#f zzFkDMfqImvT9kClEOi5CFwxHER~_s39i@xBUj%L8k@O#}7cT`Mca}=(A~Z_v1)(iI zn|5i{wArfSOjf!5j?h}%rOv=HPN96{#Dlp~0InC5L#4=Bf2$!7Z9C5vE0KyrQ*GbZ za}*y8^*M?CU+83`^is>+?TnPh*`j$v9x6J=!~s!tHVGByj&vwMlOYifmEs}guNXk? zfXJO)X6AUuSj7^nba_bmlH<+dy@ltL(?ScUc}twin_uZXFbpDfDq%hZpzuOvsQ3j= zHp`q?Fiy)*v4b_K{A!`?}eMkA>EkfpaB6WrsR literal 0 HcmV?d00001 diff --git a/data/images/mail.png b/data/images/mail.png new file mode 100644 index 0000000000000000000000000000000000000000..5247b3f551d19f6c0e2eb4f5e12b6a12b7d9167a GIT binary patch literal 3222 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 IM6N<$g2I(Ty#N3J literal 0 HcmV?d00001 diff --git a/data/images/menu.png b/data/images/menu.png new file mode 100644 index 0000000000000000000000000000000000000000..ab5d833e4622b79f020c770550d6f15d436825dc GIT binary patch literal 3240 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 a75Hxy$#0>Hohe)Z0000i^qxHIm=vo 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 literal 0 HcmV?d00001 diff --git a/data/images/paper.png b/data/images/paper.png new file mode 100644 index 0000000000000000000000000000000000000000..f6bbc6d36c241ca25f6e43e1b8a8aa01a2e326cd GIT binary patch literal 3410 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 literal 0 HcmV?d00001 diff --git a/data/images/sh2.png b/data/images/sh2.png new file mode 100644 index 0000000000000000000000000000000000000000..e4dee7a19a3dd8dc100e4db9f6e66b2591a3e426 GIT binary patch literal 280 zcmeAS@N?(olHy`uVBq!ia0vp^=YZIVgAGWE_&-?&q*&4&eH|GXHuiJ>Nn{1`ISV`@ ziy0WWg+Q3`(%rg0K*3#}E{-7;bKc(C$jcPS!+Nm%(#87y0uH=6pGq(Ju=<7Zy~(~^ zejxr`?)%Hm2QJ^aZMVF=VYwh5%b`XG3jq#xriTs+G8`?;jRguHEEyVmK@0&jSs4e# z4TTt@U_C&kad`^ZWtlZt%+O2%>)EkwuOC07|7T|J2?m$?bwZMXzF_cl^>bP0l+XkK DXZ2Dk literal 0 HcmV?d00001 diff --git a/data/images/sh3.png b/data/images/sh3.png new file mode 100644 index 0000000000000000000000000000000000000000..f15b89294348b44c91b0b44bfe15faad158a185a GIT binary patch literal 360 zcmeAS@N?(olHy`uVBq!ia0vp^MnHUygAGX52BR01_nkhPZ!6KiaBr38*&|X5MVjD@!$U>%MJSq8k-K4985dyP`~Z( zw!63Yv6p`;-}Uv?y{-0v9m@oK6=yk_v}SN!6j`L{5E1R|xn~>y3l7*qhKpIgDs zquq6%RTe>4U33>)+jf%%C}IRiP@o$dXyH{*J8jV>ND!b(2z*9?jNJeNRPy5wQQf@0XWf2jZvk-rtFUop@-OGW;du`1N&fhd=Ux z%?Kj{ZxE)}iQq(OIH9RZU3E=`f7~eT@4ou>>Se%w?*z&(Eq}|6%Wu7(NB2=_Y=($O z2nfN90Q7=k0v+c_RRK^{6q%55A&>UAe|q-A7XklCi0qqyoqXWYI1Jxk&&w~rlSkI0 z&Ae?02tDMtV1N9XmW=%C=d$vF3qCT6fNXnprU_I%;NX2gdOK{l zRlq;<&{rfYzx`%jvK0;62_8Y)9jMg^S%#}OW+5V?q)rfo%nXC75>1qd-s5TwT)j>x zJgQX=DMB;Rhu4PrwXL*vwkV36Io0X53fQ>(t8?SPX4vh?Y3N+v+#)kbJ6-%>fQihM z03mfs$2oE{dS#%rZPk1>z$UrD#3`ymQyoVZ(ywQu(ZfK4In{Em0@wfOfn$wv{Lb5X zU|`0yYHS6g?zDQY3e8Xw3QyYU%!uhk2@phux++71Q8XNoIETS5C8GD!ghtV&^TYf? z(&@gJ=cB=1D$G@&9p%q2m&U-hJ+BCfZY$7KoxF5Az6~L5Z|8&|h$;sY$AVL`2%`{Z zN)%ZiL#Quy5UoP3l{)TA-PelJF9Wr`FeY>G3(-zq_eKGH;hQZEu2h#BLbQsznPB3! zfA<0jNLoYOBC*T}Wrmdw5-=|mr7_GS3k`>J+s|D8)sTxntQua!IS!@Cqs7+nv#nO^ z{VdDI+@e3sQ$VHUb3+3&IJlBbn$;ZeR)IHh1fSuH0aejDFavK0X`*ym2{OGG0hB{u zXn{HqAr+yWxPxZ)FscXl!a9$DE8xD|c2pi9nj%Se27U^B_V@H$Dfl8|*dG!j2%VV& zsvn0;8y!kC#c;E*5*3<>tC`tyS(cq6M~>VwU+0EUfJW6xw!v3n(uedwHA9qxk1Ii? zL{cV1fzhx}nkcT`L4dLt%^Wfq8PN;~lXHTJ5u+f8nAuW{v6bifEuB4=z|a_j))CtV zKLzSDgbw05#4xJDhsk&`jdv50L?9TW!l+qBQtu#X8v&vp(QN4KKG143F(F_KLo_pM zhq6pV2)8Vy^Fm0x$&J}0d5d_DHo(LouJbYQ{a&1T**PUm6Y|0s=NZvY2q(WCR@>Dr zkH&`gHgWQvIOh?tUbGA8WahbfKJ1Ej*iKdeNjkeKjUfz%VV3kxg?i0V1}H-$_`I5b z($>uTTkqu{LTSP<1g_*hQ1#DPInF+&!n_c&D@8n$IC+{Voc)I(PDVQhI2grh_HQN| zvzlKF`m;nFS*5~)bBtmHs)kmY;Z#vs!vxZH2cK1r2nHVGW>Io&T;w7$NRq@m=l0#m z>|c7rf1Peqx@-EZ!lmJqD9|e-!+xJ&wqwkIhB`)Otd}JV&S8_0J5ePfM5^xYvy8Oe zo;Ac_8M!pd8HBJYA~#hvYcv|S+!5vx2;bWnpSx0ow{`O1V6tNpt$?-@N1~IE>G!c_ zd&hPrEG8+VXk0C-v0@Yr5k;%qp3MhEmf>1$ycySvf;Tt&K}2q<$VX|C^t;_|6p@dq zFpoe?)3o>R{rsQmPH~et-(Z)Q4WXGNlwveg5mltsrZB4j3M?flOSKvcPA5x{Afm{` z8B=8gFsd(belX<2d^|+ts)$@{Hk-Ybm6d%fVEul7@V)E(AD$hK-%2N54(tX$tx||E z0xTO)b4nsrc$q;xaU|0a6q(IIs%|!xM_{wJ#kuQi{N%<)5Rq%ZyGfFKaQN`y?3Gtu z**5_IUzX)Ze{<>P-*1#Lo4zctJB$#aF&P0yX81uyt=lD$N|BvA@j~Kug`tQN%oqjZ z@+jxWYwOnYWe<^yX7)ezdi~0wLx;wD0lXc7U}hUV(bGS;y7_7zEmUI#w^U+5b(X9E zvDsq1C}$OD=hul*tim}0d4$V(&QEV_^6p?b5|IxDPB-fHUoS5&ub(`5GA2o~|8aU^ zx%d9!e`Vu;{_g6{*VlXqe#(w25qIvyQ!-myeVi)N-rfTv$oRLb zH#oh~8;i(QM9vuetlRB=@Wc~Oj82_8wdY25CriB@KYqMiU0oer4>mZP7+^lyZQwP zNxOs31_Tqv7TNSASH}f!_XhlYeKU9?1Fj_eAE#-W{m0F%o2Pr(mp|8T9(}UgY~J6fOVc?L)yeW+-Bg<4H+qa?q*s<) z$qU{cWSr|~VNixbM7DrSBJvAW{Yj(IIP=IOkF37%!V9^X%>`e%XMZMC>)n!b?lD#U zQjGD7X0~!~nmqUi^|ZB=rb#z-(sWJ`VHhG?zO=Q%+qH3F8@>!yIU@ts5P2W7(<1Wo z0|ySgd+gY;o6kM>-1yX~Q+7M>pM=2F9MDeF^uZY8W5DNu$IR>jU=e5o3sm2Al&aWx zU<3?+bwpML-Z6MU>%R0OaV=qqTm&-(6o{zc+-i ztg4@lF+K-E%oFFUs==bWW!YTa%(uB@!YS6_WKsw!n!lBVhJ q{~sLtv7L*^C-L%KyK8rCZ~I?ZZ%$SXA2xsh0000brpjA1NrE)$2D_Bi9YbkDUfbvd_v-BKb(AvrpBjs&B3Rt#5zpZ208(CS5eS_#KzyVqwEnF>IVECzA!@U>Tb3AU$l%snKfCt( zfAq?0w-RsU9p@r1DMyq0oJ z#6WI6+9|=@*4}c<(?N0uiqr%2=e* zv|iI{%WmB=Z6(`PD}jTFJ}yxxD?SGBXLKu1EoR_jz)Ov{2GwdBWvHcOyJ^tQA&q0F zX_!jQ)$!ySa3BG1lY-_SSpawc?xhpLyYo$1uX&@fbY7i%fAf7{321;GkO49KD8Nr&K7Gm?bKWbxCcHz$h-($bXiTdqrD9yw?6fVT zRx)W7Qz;p>iqcx{mepIp09fdP|452>`ts>h!rL>#TC|ji7(g3ZB`G{KS~IF^CR$P| z&2A+bwUSy}TIX;f?4G-F<85Fu6>#V*XusSd-ue4)pYcYY64sJ+3f5Z-#xs_hT1m!g z5A>*(OqHZHmexC5jP}PHx8DT%9b1uggLtR_>a&FaSU&0E!`#35otIAZA}?m%o$7^v zcNXUys%i<|60N5(CV_9+ZCXaPqSlH^8Kn0pAK2U;|KQHFn$EJF3Rou}#QmJ$ zeY1Y{^a<6d^V;aOL6IY3Kxso%h8P^WH3%X`8zxF}w``a+ib^R;tx+MMd|4ku| zhOEdzTUsTF+R-XQBPFE>Y*#JgMp8*dV=S%nC>Jo!PhWrc{qqUDOkm6OQb|Tlnh8-n zBz<~mtnWvo&F{SQ&8lo(>=W@?lM(3&&~=M7nx|hxP#*qW#{*_g?K-1(W`-PT*(MF&{R73>c>Ic=qLcul&u4+?q40 zQO^Zq@LD5!Ig3S(t~GVrqNLu-ywo&S(-^~~mbBW?7)#?EjrG_V?T@eDe6uslGw>>1 zS1AbHX=Zp>8O?y@&Y0bQ`P*lsl4qPUYg)GGR(SoZA70%&w^h}3N9kr}O(yQof^yw%?13}TQJg%vK!AMv%%7in|Ft*H zY;4}5bO9eDLjkLYS2%ibg=}d^St@F^N1K4B)|N(UcAJ)|HZ<1l6|E2UN7pvrOyIlS zR+m0H1v2A)x2=pteYWTUVfm!csvDgV3>zB1$ZJcfDfJ^A}+IRD}ghCa@(-7xPZ=}m4->XXUrzrBE3h4 z$o90nbYbK6{?++OGi#90HCc;B~sWmmJ^`;ED8wV}o7*1j+?; zbY#6qzh`itM=F;<4k7%JU;fJ(J2h6>gix zO(%e#TZ@Y2lP=b0iz@N_=_HvOfT1|JMAm-_FQ3}Gd-&waFwkm&Fp*wnSQ;vv%PH$V zHs7?$_msvlk_sIHIz)5`80#k&Hf~?)0H0B(yVA};Pg4;$=`%e?qn|6{ofO1Z z$@-ray~DTZ9gHA8jc=a<5y_W6QylgGcA(ClKaf@Q1`=fj|9)9u+k)dOeVh;U5x5Bb zqF`zq5wIcPTo`}<-7DYiP-bS%R44PZ>~{lcJC>p=qx=4*NSu#k3&+U@&xw5Dx5ePG z1KHqHzd>=}3!-;uB^w-*y~TEGsi?nl^ym};oLjfNe!1pOC0SY+uw3*&2y(Hfx*Ju6 z@*d-Zef8qym*)z0R798c#Yw$V8vmbptctdE$IQKD;CHg^XhPcSN!Bj2J#0 zM80qgh(!D4r=Q9~xp;ki^Ty!txyzQfZ&+3q28>(Fc2%=F9MGqSM^G9~Yds+b`_9Jg z?E5dEVAQ7qr3x1z;xZ7nTv?EJN~9l zS#CSZGwocS>oue??N!Qq2S>`vJf6`PKaMyJw$KyP@Me7dXO92P_|g( za518M*e}*9fu3}zQg--nI%?xTDEr+2_NLkFv|s z&-D)rzFPzTV`c4F#p1yGBJbbAO!|@0D7xxN0H3d1bUwe*R86_FJJRE6ohyqC0U-^c zQ8-|b39>9hW_|gj^Yz(%K`L=o9bMIn{bne#eu%FA zEI?M+pQ%dUymxb3H&ygIC4*^=tt2jlef}09k_V4-e%}^%)usES!E~HvcMFLR6~J5& z^}dxhJ1Xw25!V5tD{o`tC=>WfBBph;J0&^+wW%E=AXe^|;qa2@Cb z;X6+TCctL8WwJ69a%C99=61|(Y@wxL&;i@)?E09FcekCw^c~8E`4;j2ZJ)S4Tjc5U zMc|qA_B*NA{PIaRYkIoPPxnEY@AS7~j^ANUBL7$5A8Mn!K3nutp8#-u`J^**d$_Xz zL}&4e_feAWIer+W`DO0Zi@D9{`AzBg0XyyS|M>s>H{0bg;KbUXTL1t607*qoM6N<$ Ef=`$G=l}o! literal 0 HcmV?d00001 diff --git a/debian/Makefile.am b/debian/Makefile.am new file mode 100644 index 0000000..ba35b62 --- /dev/null +++ b/debian/Makefile.am @@ -0,0 +1,9 @@ +EXTRA_DIST = \ +changelog \ +control \ +copyright \ +imlib2-config.1 \ +libimlib2-dev.doc-base \ +libimlib2.files \ +libimlib2-dev.files \ +rules diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..f5790d8 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +imlib2 (1.1.2-0cvs20040918) unstable; urgency=low + + * a CVS release + + -- Sytse Wielinga Sat, 18 Sep 2004 12:48:44 +0200 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..6998ca2 --- /dev/null +++ b/debian/control @@ -0,0 +1,44 @@ +Source: imlib2 +Section: libs +Priority: optional +Maintainer: Laurence J. Lane +Build-Depends: libjpeg62-dev, libttf-dev, libpng3-dev | libpng2-dev | libpng-dev, libtiff4-dev | libtiff-dev, zlib1g-dev, libungif4-dev | libungif3g-dev | giflib3g-dev, xlibs-dev, libfreetype6-dev | freetype2-dev, libbz2-dev, libltdl3-dev, automake1.7 | automaken, libtool, debhelper (>= 4.0) +Standards-Version: 3.5.7.0 + +Package: imlib2-demo +Architecture: any +Section: graphics +Depends: ${shlibs:Depends} +Description: Imlib2 demo's + This package contains two small Imlib2-based programs: a simple + image viewer and a simple image conversion program. + +Package: imlib2-test +Architecture: any +Section: graphics +Depends: ${shlibs:Depends} +Description: Imlib2 test programs + This package contains some, not generally usable, test programs + for Imlib2. + +Package: libimlib2 +Section: libs +Architecture: any +Depends: ${shlibs:Depends} +Suggests: imlib2-loaders, imlib2-demo (= ${Source-Version}) +Description: Powerful image loading and rendering library + Imlib2 is an advanced replacement library for libraries like + libXpm that provides many more features with much greater + flexibility and speed than standard libraries, including font + rasterization, rotation, RGBA space rendering and blending, + dynamic binary filters, scripting, and more. + . + Imlib2 is not a drop-in replacement for Imlib 1.x. + +Package: libimlib2-dev +Architecture: any +Section: devel +Architecture: any +Depends: libimlib2 (= ${Source-Version}), libc6-dev | libc-dev, libjpeg62-dev, libpng3-dev | libpng2-dev | libpng-dev, libtiff4-dev | libtiff-dev, zlib1g-dev, libttf-dev, libungif4-dev | libungif3g-dev | giflib3g-dev, xlibs-dev, libfreetype6-dev | freetype2-dev, libbz2-dev +Description: Imlib2 headers, static libraries and documentation + Headers, static libraries and documentation for Imlib2. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..25d1164 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,32 @@ +This package was debianized by Laurence J. Lane on +Sat, 28 Oct 2000 17:56:46 -0400. + +The source code is from the e17/libs/imlib2 module of the enlightenment CVS +tree. For more information, see: + + http://www.enlightenment.org/cvs.html + +Upstream Author: Carsten Haitzler + +Copyright: + +Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies of the Software, its documentation and marketing & publicity +materials, and acknowledgment shall be given in the documentation, materials +and software packages that this Software was used. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/debian/imlib2-config.1 b/debian/imlib2-config.1 new file mode 100644 index 0000000..6d00705 --- /dev/null +++ b/debian/imlib2-config.1 @@ -0,0 +1,17 @@ +.TH imlib2-config 1 "29 Oct 2000" imlib2-config +.SH NAME +.HP +imlib2-config - imlib2 build information script +.SH SYNOPSIS +.HP +imlib2-config [options] +.P +.SH DESCRIPTION +.HP +.I imlib2-config +is a script that's used by make and other build enviroments to +gather imlib2 information. +.HP +Run +.I imlib2-config +for additional information. diff --git a/debian/imlib2-demo.install b/debian/imlib2-demo.install new file mode 100644 index 0000000..16f5b43 --- /dev/null +++ b/debian/imlib2-demo.install @@ -0,0 +1,2 @@ +usr/bin/imconvert +usr/bin/imlib2_view diff --git a/debian/imlib2-test.install b/debian/imlib2-test.install new file mode 100644 index 0000000..0f6203c --- /dev/null +++ b/debian/imlib2-test.install @@ -0,0 +1,5 @@ +usr/bin/imlib2 +usr/bin/imlib2_test +usr/bin/bumpmaptest +usr/bin/color_spaces +usr/bin/polytest diff --git a/debian/libimlib2-dev.doc-base b/debian/libimlib2-dev.doc-base new file mode 100644 index 0000000..09d1d32 --- /dev/null +++ b/debian/libimlib2-dev.doc-base @@ -0,0 +1,10 @@ +Document: imlib2 +Title: Imlib2 Guide +Author: Carsten Haitzler +Abstract: This document describes Imlib2 API + and provides sample C code. +Section: Apps/Programming + +Format: HTML +Index: /usr/share/doc/libimlib2-dev/html/index.html +Files: /usr/share/doc/libimlib2-dev/html/index.html diff --git a/debian/libimlib2-dev.install b/debian/libimlib2-dev.install new file mode 100644 index 0000000..f3094ca --- /dev/null +++ b/debian/libimlib2-dev.install @@ -0,0 +1,10 @@ +usr/bin/imlib2-config +usr/lib/pkgconfig/* +usr/include +usr/lib/*.so +usr/lib/*.a +usr/lib/*.la +usr/lib/imlib2_loaders/filter/*.a +usr/lib/imlib2_loaders/filter/*.la +usr/lib/imlib2_loaders/image/*.a +usr/lib/imlib2_loaders/image/*.la diff --git a/debian/libimlib2.install b/debian/libimlib2.install new file mode 100644 index 0000000..58c526b --- /dev/null +++ b/debian/libimlib2.install @@ -0,0 +1,3 @@ +usr/lib/*.so.* +usr/lib/imlib2_loaders/filter/*.so +usr/lib/imlib2_loaders/image/*.so diff --git a/debian/rules b/debian/rules new file mode 100644 index 0000000..9cc7640 --- /dev/null +++ b/debian/rules @@ -0,0 +1,88 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This is the debhelper compatability version to use. +export DH_COMPAT=4 + +# These are used for cross-compiling and for saving the configure script +# from having to guess our platform (since we know it already) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +CFLAGS ?= -Wall -g + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif +ifneq (,$(findstring mmx,$(DEB_BUILD_OPTIONS))) + ENABLE_MMX = yes +else + ENABLE_MMX = no +endif + +INSTALL=/usr/bin/install -p +CONFIGUREOPTS = --prefix=/usr --enable-mmx=$(ENABLE_MMX) --build=$(DEB_BUILD_GNU_TYPE) --host=$(DEB_HOST_GNU_TYPE) +package=libimlib2 + +configure: configure-stamp +configure-stamp: + test -x autogen.sh && ./autogen.sh $(CONFIGUREOPTS) || ./configure $(CONFIGUREOPTS) + touch configure-stamp + +build: build-stamp +build-stamp: configure-stamp + dh_testdir + $(MAKE) + touch build-stamp + +clean: + dh_testdir + rm -f build-stamp configure-stamp + + -$(MAKE) distclean + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp/ + + $(INSTALL) -d debian/$(package)-dev/usr/share/doc/$(package)-dev/html + $(INSTALL) -m 644 doc/*.html doc/*.gif \ + debian/$(package)-dev/usr/share/doc/$(package)-dev/html + +binary-indep: build install + +binary-arch: build install + dh_testdir + dh_testroot + dh_install --sourcedir=debian/tmp --list-missing + + dh_installdocs AUTHORS README + dh_installchangelogs + dh_link + dh_strip + dh_compress + dh_fixperms + dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..aa89a7c --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,5 @@ +MAINTAINERCLEANFILES = Makefile.in + +EXTRA_DIST = imlib2.gif \ + blank.gif \ + index.html diff --git a/doc/blank.gif b/doc/blank.gif new file mode 100644 index 0000000000000000000000000000000000000000..60fa7a1acfebae5abb3f687985ff70ca668a9397 GIT binary patch literal 266 zcmZ?wbhEHbWMp7uSjxb_%*?Eypy1`@Ra;xz-rhcM-n<<(9l@1Vg(l$ z*S~-N?Ck8)($dbIJNKW)K=Ge~bACZ(QD%BZi9$$5szOj=aY<@XZepH-hO?%E5zv7Q aia%KxxftXbbQpjD + diff --git a/doc/head.html b/doc/head.html new file mode 100644 index 0000000..3fdb33d --- /dev/null +++ b/doc/head.html @@ -0,0 +1,19 @@ + + + + +$title + + + + + + diff --git a/doc/img/hilite.png b/doc/img/hilite.png new file mode 100644 index 0000000000000000000000000000000000000000..88a43816ea0718f59d609b5301e22a140f4cfdcb GIT binary patch literal 6127 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 literal 0 HcmV?d00001 diff --git a/doc/img/imlib2_mini.png b/doc/img/imlib2_mini.png new file mode 100644 index 0000000000000000000000000000000000000000..f4f99f0fa3224a7319ef0d51e1f2235c5a4b7bf5 GIT binary patch literal 753 zcmV~${x~c#G0&Yn}K~#9!rIK4nlVKdjf8V!*n`dqFG;=|Cgi14(B}SSJqq49I z@kUajq@>V`8YG2~K?e~+2s5mUE+p!%3&kKRA`cm*mR_t@j3T!@yMwy#TUQ&)G>D$7 z_y4@l|KZ_zUkJs-*pvC-ptx%({r=H5od-ZmT~X5c(}(@QRuQ1*^{4#OP0}K;mo;&% zvCP|Y);tv?!Zpf{#aV|xNIbY$vUK%S;Tu3utlAcCUpTNm!w@ms|6$SxAOvpet9Er2 z=BC!9Zj3{hmOj6&*iy2*A`J%}!WDAvj*JbP6BM4-_U>VYfSCNvG21JI+5?Ax0>BD9 z0v7lu+-flEJ1yodq1nX1;Zj|3_fMbNVRwg(T&Xqn1w_h#&=9Yw)axTj%TD+DyppM@ zYw$M*O;(bY$35=`^Uaqv#+1w`Ko=@lb}g+)M~jS2wx{*B(J!t!zy%QK!Ea26I3BK6 zREr+3w!FUm#)?m#1e~EgBm>oe3U~?(0Dk@#!dhfo!~PVn#0jM+RCy#ZSs$embm4xx zV`{$ROxue)z|tQ*24+jm?q*r3wnu0b&8XB_KE&v^)@ipYHYT%gbUGJ^4_#2MHb{(% zIA)0SiEdfxG3DsA*=73#IV>+}eBdRW#RqF`N6tClTb<2-XRQQk$?IB9h>zyk(AUPC z%KN2aZ1v5Wlh=pj*n;`~zFyCW)fodst(U+p%F@HB1$Um=WN59}W0a${Vx&sFfami) zr)_fPxmKf`aC?2ydL;@#3Q)c?JFy}?H7Z%7RCvbibJka5KkUE^FbMPqK7#O<*HHs8 jfEJJeH!uhILWREo3h>l;^}Oio00000NkvXXu0mjfuFYE5 literal 0 HcmV?d00001 diff --git a/doc/imlib2.css b/doc/imlib2.css new file mode 100644 index 0000000..6117b39 --- /dev/null +++ b/doc/imlib2.css @@ -0,0 +1,178 @@ +td.md { + background-color: #ffffff; + font-family: monospace; + text-align: left; + vertical-align: center; + font-size: 10; + padding-right : 1px; + padding-top : 1px; + padding-left : 1px; + padding-bottom : 1px; + margin-left : 1px; + margin-right : 1px; + margin-top : 1px; + margin-bottom : 1px +} +td.mdname { + font-family: monospace; + text-align: left; + vertical-align: center; + font-size: 10; + padding-right : 1px; + padding-top : 1px; + padding-left : 1px; + padding-bottom : 1px; + margin-left : 1px; + margin-right : 1px; + margin-top : 1px; + margin-bottom : 1px +} +h1 +{ + text-align: center; + color: #333333 +} +h2 +{ + text-align: left; + color: #333333 +} +h3 +{ + text-align: left; + color: #333333 +} +a:link +{ + text-decoration: none; + color: #444444; + font-weight: bold; +} +a:visited +{ + text-decoration: none; + color: #666666; + font-weight: bold; +} +a:hover +{ + text-decoration: none; + color: #000000; + font-weight: bold; +} +a.nav:link +{ + text-decoration: none; + color: #444444; + font-weight: normal; +} +a.nav:visited +{ + text-decoration: none; + color: #666666; + font-weight: normal; +} +a.nav:hover +{ + text-decoration: none; + color: #000000; + font-weight: normal; +} +a.qindex:link +{ + text-decoration: none; + color: #444444; + font-weight: normal; +} +a.qindex:visited +{ + text-decoration: none; + color: #666666; + font-weight: normal; +} +a.qindex:hover +{ + text-decoration: none; + color: #000000; + font-weight: normal; +} +p +{ + color: #000000; + font-family: sans-serif; + font-size: 10; +} +body { + background-image: url("hilite.png"); + background-repeat: no-repeat; + background-position: left top; + background-color: #dddddd; + color: #000000; + font-family: sans-serif; + padding: 8px; + margin: 0; +} +div.fragment +{ + background-image: url("hilite.png"); + background-repeat: no-repeat; + background-position: left top; + border: thin solid #888888; + background-color: #eeeeee; + padding: 4px; + text-align: left; + vertical-align: center; + font-size: 12; +} +hr +{ + border: 0; + background-color: #000000; + width: 80%; + height: 1; +} +dl +{ + background-image: url("hilite.png"); + background-repeat: no-repeat; + background-position: left top; + border: thin solid #aaaaaa; + background-color: #eeeeee; + padding: 4px; + text-align: left; + vertical-align: center; + font-size: 12; +} +em +{ + color: #334466; + font-family: courier; + font-size: 10; + font-style: normal; +} + +div.nav +{ + border: thin solid #000000; + background-color: #ffffff; + padding: 1px; + text-align: center; + vertical-align: center; + font-size: 12; +} +div.body +{ + border: thin solid #000000; + background-color: #ffffff; + padding: 4px; + text-align: left; + font-size: 10; +} +div.diag +{ + border: thin solid #888888; + background-color: #eeeeee; + padding: 4px; + text-align: center; + font-size: 8; +} diff --git a/doc/imlib2.gif b/doc/imlib2.gif new file mode 100644 index 0000000000000000000000000000000000000000..1fcd7f3de29c50dc45aca7e81ecd9fbaf2d6b2a3 GIT binary patch literal 6794 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 literal 0 HcmV?d00001 diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..2ec4735 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,2268 @@ + + + + + + + Imlib 2 - Documentation. + + + + +
    +

    +Imlib2

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    What +is it?
    Imlib 2 is the successor +to Imlib. It is NOT a newer version - it is a completely new library. Imlib +2 can be installed alongside Imlib 1.x without any problems since they +are effectively different libraries - BUT they Have very similar functionality. +

    Imlib 2 does the following: +

      +
    • +Load image files from disk in one of many formats
    • + +
    • +Save images to disk in one of many formats
    • + +
    • +Render image data onto other images
    • + +
    • +Render images to an X-Windows drawable
    • + +
    • +Produce pixmaps and pixmap masks of Images
    • + +
    • +Apply filters to images
    • + +
    • +Rotate images
    • + +
    • +Accept RGBA Data for images
    • + +
    • +Scale images
    • + +
    • +Alpha blend Images on other images or drawables
    • + +
    • +Apply color correction and modification tables and factors to images
    • + +
    • +Render images onto images with color correction and modification tables
    • + +
    • +Render truetype anti-aliased text
    • + +
    • +Render truetype anti-aliased text at any angle
    • + +
    • +Render anti-aliased lines
    • + +
    • +Render rectangles
    • + +
    • +Render linear multi-colored gradients
    • + +
    • +Cache data intelligently for maximum performance
    • + +
    • +Allocate colors automatically
    • + +
    • +Allow full control over caching and color allocation
    • + +
    • +Provide highly optimized MMX assembly for core routines
    • + +
    • +Provide plug-in filter interface
    • + +
    • +Provide on-the-fly runtime plug-in image loading and saving interface
    • + +
    • +Fastest image compositing, rendering and manipulation library for X
    • +
    +If what you want isn't in the list above somewhere then likely Imlib 2 +does not do it. If it does it it likely does it faster than any other library +you can find (this includes gdk-pixbuf, gdkrgb, etc.) primarily because +of highly optimized code and a smart subsystem that does the dirty work +for you and picks up the pieces for you so you can be lazy and let all +the optimizations for FOR you. +

    Imlib 2 can run without a display, so it can be easily used for background +image processing for web sites or servers - it only requires the X libraries +to be installed - that is all - it does not require an XServer to run unless +you wish to display images. +

    The interface is simple - once you get used to it, the functions do +exactly what they say they do.

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    A +Simple Example
    The best way to start +is to show a simple example of an Imlib2 program. This one will load an +image of any format you have a loader installed for (all loaders are dynamic +code objects that Imlib2 will use and update automatically runtime - anyone +is free to write a loader. All that has to be done is for the object to +be dropped into the loaders directory with the others and all Imlib2 programs +will automatically be able to use it - without a restart). +
    +
    /* standard headers */
    +#include <X11/Xlib.h>
    +#include <Imlib2.h>
    +#include <stdio.h>
    +#include <string.h>
    +
    +/* main program */
    +int main(int argc, char **argv)
    +{
    +  /* an image handle */
    +  Imlib_Image image;
    +  
    +  /* if we provided < 2 arguments after the command - exit */
    +  if (argc != 3) exit(1);
    +  /* load the image */
    +  image = imlib_load_image(argv[1]);
    +  /* if the load was successful */
    +  if (image)
    +    {
    +      char *tmp;
    +      /* set the image we loaded as the current context image to work on */
    +      imlib_context_set_image(image);
    +      /* set the image format to be the format of the extension of our last */
    +      /* argument - i.e. .png = png, .tif = tiff etc. */
    +      tmp = strrchr(argv[2], '.');
    +      if(tmp)
    +         imlib_image_set_format(tmp + 1);
    +      /* save the image */
    +      imlib_save_image(argv[2]);
    +    }
    +}
    +Now to compile this +
    +cc imlib2_convert.c -o imlib2_convert `imlib2-config --cflags` `imlib2-config --libs` +
    +You now have a program that if used as follows: +
    +./imlib2_convert image1.jpg image2.png +
    +will convert image1.jpg into a png called image2.png. It is that simple.
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    How +Image Loading Works
    It is probably a +good idea to discuss how Imlib2 actually loads an Image so the programmer +knows what is going on, how to take advantage of the optimizations already +there and to explain why things work as they do. +
    +
    +

    +Loading using imlib_load_image();

    +This is likely to be by far the most common way to load an image - when +you don't really care about the details of the loading process or why it +failed - all you care about is if you got a valid image handle. +

    When you call this function Imlib2 attempts to find the file specified +as the parameter. This will involve Imlib2 first checking to see if that +file path already has been loaded and is in Imlib2's cache (a cache of +already decoded images in memory to save having to load and decode from +disk all the time). If there already is a copy in the cache (either already +active or speculatively cached from a previous load & free) this copy +will have its handle returned instead of Imlib2 checking on disk (in some +circumstances this is not true - see later in this section to find out). +This means if your program blindly loads an Image, renders it, then frees +it - then soon afterwards loads the same image again, it will not be loaded +from disk at all, instead it will simply be re-referenced from the cache +- meaning the load will be almost instant. A great way to take full advantage +of this is to set the cache to some size you are happy with for the image +data being used by your application and then all rendering o an image follows +the pseudo code: +

    set cache to some amount (e.g. 4 Mb)
    +...
    +rendering loop ...
    +    load image
    +    render image
    +    free image
    +... continue loop
    +This may normally sound silly - load image, render then free - EVERY time +we want to use it, BUT - it is actually the smartest way to use Imlib2 +- since the caching will find the image for you in the cache - you do not +need to manage your own cache, or worry about filling up memory with image +data - only as much memory as you have set for the cache size will actually +ever be used to store image data - if you have lots of image data to work +with then increase the cache size for better performance, but this is the +only thing you need to worry about. you won't have problems of accidentally +forgetting to free images later since you free them immediately after use. +

    Now what happens if the file changes on disk while it's in cache? By +default nothing. The file is ignored. This is an optimization (to avoid +hitting the disk to check if the file changed for every load if it's cached). +You can inform Imlib2 that you care about this by using the imlib_image_set_changes_on_disk(); +call. +Do this whenever you load an Image that you expect will change on disk, +and the fact that it changes really matters. Remember this will marginally +reduce the caching performance. +

    Now what actually happens when we try and load +an image using a filename? First the filename is broken down into 2 parts. +the filename before a colon (:) and the key after the colon. This means +when we have a filename like: +

    /path/to/file.jpg +

    the filename is: +

    /path/to/file.jpg +

    and the key is blank. If we have: +

    /path/to/file.db:key.value/blah +

    the filename is: +

    /path/to/file.db +

    and the key is: +

    key.value/blah +

    You may ask what is this thing with keys and filenames? +Well Imlib2 has loaders that are able to load data that is WITHIN a file +(the loader capable of this right now is the database loader that is able +to load image data stored with a key in a Berkeley-db database file). The +colon is used to delimit where the filename ends and the key begins. Fro +the majority of files you load you won't have to worry, but there is a +limit in this case that filenames cannot contain a color character. +

    First Imlib2 checks to see if the file exists +and that you have permission to read it. If this fails it will abort the +load. Now that it has checked that this is the case it evaluates that it's +list of dynamically loaded loader modules it up to date then it runs through +the loader modules until one of them claims it can load this file. If this +is the case that loader is now used to decode the image and return +an Image handle to the calling program. If the loader is written correctly +and the file format sanely supports this, the loader will NOT decode any +image data at this point. It will ONLY read the header of the image to +figure out its size, if it has an alpha channel, format and any other header +information. The loader is remembered and it will be re-used to load the +image data itself later if and ONLY if the actual image data itself is +needed. This means you can scan vast directories of files figuring their +format and size and other such information just by loading and freeing +- and it will be fast because no image data is decoded. You can take advantage +of this by loading the image and checking its size to calculate the size +of an output area before you ever load the data. This means geometry +calculations can be done fast ahead of time. +

    If you desire more detailed information about +why a load failed you can use imlib_load_image_with_error_return(); +and +it will return a detailed error return code. +

    If you do not wish to have the image data loaded +later using the optimized "deferred" method of loading, you can force the +data to be decoded immediately with imlib_load_image_immediately(); +

    If you wish to bypass the cache when loading images +you can using imlib_load_image_without_cache(); +and +imlib_load_image_immediately_without_cache();. +

    Sometimes loading images can take a while. Often +it is a good idea to provide feedback to the user whilst this is happening. +This is when you set the progress function callback. Setting this to NULL +will mean no progress function is called during load - this is the default. +When it is set you set it to a function that will get called every so often +(depending on the progress granularity) during load. Use imlib_context_set_progress_function(); +and imlib_context_set_progress_granularity(); +to +set this up.

    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    A +more advanced Example
    This is a more comprehensive +example that should show off a fair number of features of imlib2. The code +this was based off can be found in Imlib2's test directory. This covers +a lot of the core of Imlib2's API so you should have a pretty good idea +on how it works if you understand this code snippet. +
    +
    /* include X11 stuff */
    +#include <X11/Xlib.h>
    +/* include Imlib2 stuff */
    +#include <Imlib2.h>
    +/* sprintf include */
    +#include <stdio.h>
    +
    +/* some globals for our window & X display */
    +Display *disp;
    +Window   win;
    +Visual  *vis;
    +Colormap cm;
    +int      depth;
    +
    +/* the program... */
    +int main(int argc, char **argv)
    +{
    +   /* events we get from X */
    +   XEvent ev;
    +   /* areas to update */
    +   Imlib_Updates updates, current_update;
    +   /* our virtual framebuffer image we draw into */
    +   Imlib_Image buffer;
    +   /* a font */
    +   Imlib_Font font;
    +   /* our color range */
    +   Imlib_Color_Range range;
    +   /* our mouse x, y coordinates */
    +   int mouse_x = 0, mouse_y = 0;
    +   
    +   /* connect to X */
    +   disp  = XOpenDisplay(NULL);
    +   /* get default visual , colormap etc. you could ask imlib2 for what it */
    +   /* thinks is the best, but this example is intended to be simple */
    +   vis   = DefaultVisual(disp, DefaultScreen(disp));
    +   depth = DefaultDepth(disp, DefaultScreen(disp));
    +   cm    = DefaultColormap(disp, DefaultScreen(disp));
    +   /* create a window 640x480 */
    +   win = XCreateSimpleWindow(disp, DefaultRootWindow(disp), 
    +                             0, 0, 640, 480, 0, 0, 0);
    +   /* tell X what events we are interested in */
    +   XSelectInput(disp, win, ButtonPressMask | ButtonReleaseMask | 
    +                PointerMotionMask | ExposureMask);
    +   /* show the window */
    +   XMapWindow(disp, win);
    +   /* set our cache to 2 Mb so it doesn't have to go hit the disk as long as */
    +   /* the images we use use less than 2Mb of RAM (that is uncompressed) */
    +   imlib_set_cache_size(2048 * 1024);
    +   /* set the font cache to 512Kb - again to avoid re-loading */
    +   imlib_set_font_cache_size(512 * 1024);
    +   /* add the ./ttfonts dir to our font path - you'll want a notepad.ttf */
    +   /* in that dir for the text to display */
    +   imlib_add_path_to_font_path("./ttfonts");
    +   /* set the maximum number of colors to allocate for 8bpp and less to 128 */
    +   imlib_set_color_usage(128);
    +   /* dither for depths < 24bpp */
    +   imlib_context_set_dither(1);
    +   /* set the display , visual, colormap and drawable we are using */
    +   imlib_context_set_display(disp);
    +   imlib_context_set_visual(vis);
    +   imlib_context_set_colormap(cm);
    +   imlib_context_set_drawable(win);
    +   /* infinite event loop */
    +   for (;;)
    +     {
    +        /* image variable */
    +        Imlib_Image image;
    +        /* width and height values */
    +        int w, h, text_w, text_h;
    +        
    +        /* init our updates to empty */
    +        updates = imlib_updates_init();
    +        /* while there are events form X - handle them */
    +        do
    +          {
    +             XNextEvent(disp, &ev);
    +             switch (ev.type)
    +               {
    +               case Expose:
    +                  /* window rectangle was exposed - add it to the list of */
    +                  /* rectangles we need to re-render */
    +                  updates = imlib_update_append_rect(updates,
    +                                                     ev.xexpose.x, ev.xexpose.y,
    +                                                     ev.xexpose.width, ev.xexpose.height);
    +                  break;
    +               case ButtonPress:
    +                  /* if we click anywhere in the window, exit */
    +                  exit(0);
    +                  break;
    +               case MotionNotify:
    +                  /* if the mouse moves - note it */
    +                  /* add a rectangle update for the new mouse position */
    +                  image = imlib_load_image("./test_images/mush.png");
    +                  imlib_context_set_image(image);
    +                  w = imlib_image_get_width();
    +                  h = imlib_image_get_height();
    +                  imlib_context_set_image(image);
    +                  imlib_free_image();
    +                  /* the old position - so we wipe over where it used to be */
    +                  updates = imlib_update_append_rect(updates,
    +                                                     mouse_x - (w / 2), mouse_y - (h / 2),
    +                                                     w, h);
    +                  font = imlib_load_font("notepad/30");
    +                  if (font)
    +                    {
    +                       char text[4096];
    +                       
    +                       imlib_context_set_font(font);
    +                       sprintf(text, "Mouse is at %i, %i", mouse_x, mouse_y);
    +                       imlib_get_text_size(text, &text_w, &text_h); 
    +                       imlib_free_font();
    +                       updates = imlib_update_append_rect(updates,
    +                                                          320 - (text_w / 2), 240 - (text_h / 2),
    +                                                          text_w, text_h);
    +                    }
    +                  
    +                  mouse_x = ev.xmotion.x;
    +                  mouse_y = ev.xmotion.y;
    +                  /* the new one */
    +                  updates = imlib_update_append_rect(updates,
    +                                                     mouse_x - (w / 2), mouse_y - (h / 2),
    +                                                     w, h);
    +                  font = imlib_load_font("notepad/30");
    +                  if (font)
    +                    {
    +                       char text[4096];
    +                       
    +                       imlib_context_set_font(font);
    +                       sprintf(text, "Mouse is at %i, %i", mouse_x, mouse_y);
    +                       imlib_get_text_size(text, &text_w, &text_h); 
    +                       imlib_free_font();
    +                       updates = imlib_update_append_rect(updates,
    +                                                          320 - (text_w / 2), 240 - (text_h / 2),
    +                                                          text_w, text_h);
    +                    }
    +               default:
    +                  /* any other events - do nothing */
    +                  break;
    +               }
    +          }
    +        while (XPending(disp));
    +        
    +        /* no more events for now ? ok - idle time so lets draw stuff */
    +        
    +        /* take all the little rectangles to redraw and merge them into */
    +        /* something sane for rendering */
    +        updates = imlib_updates_merge_for_rendering(updates, 640, 480);
    +        for (current_update = updates; 
    +             current_update; 
    +             current_update = imlib_updates_get_next(current_update))
    +          {
    +             int up_x, up_y, up_w, up_h;
    +
    +             /* find out where the first update is */
    +             imlib_updates_get_coordinates(current_update, 
    +                                           &up_x, &up_y, &up_w, &up_h);
    +             
    +             /* create our buffer image for rendering this update */
    +             buffer = imlib_create_image(up_w, up_h);
    +             
    +             /* we can blend stuff now */
    +             imlib_context_set_blend(1);
    +             
    +             /* fill the window background */
    +             /* load the background image - you'll need to have some images */
    +             /* in ./test_images lying around for this to actually work */
    +             image = imlib_load_image("./test_images/bg.png");
    +             /* we're working with this image now */
    +             imlib_context_set_image(image);
    +             /* get its size */
    +             w = imlib_image_get_width();
    +             h = imlib_image_get_height();
    +             /* now we want to work with the buffer */
    +             imlib_context_set_image(buffer);
    +             /* if the iimage loaded */
    +             if (image) 
    +               {
    +                  /* blend image onto the buffer and scale it to 640x480 */
    +                  imlib_blend_image_onto_image(image, 0, 
    +                                               0, 0, w, h, 
    +                                               - up_x, - up_y, 640, 480);
    +                  /* working with the loaded image */
    +                  imlib_context_set_image(image);
    +                  /* free it */
    +                  imlib_free_image();
    +               }
    +             
    +             /* draw an icon centered around the mouse position */
    +             image = imlib_load_image("./test_images/mush.png");
    +             imlib_context_set_image(image);
    +             w = imlib_image_get_width();
    +             h = imlib_image_get_height();
    +             imlib_context_set_image(buffer);
    +             if (image) 
    +               {
    +                  imlib_blend_image_onto_image(image, 0, 
    +                                               0, 0, w, h, 
    +                                               mouse_x - (w / 2) - up_x, mouse_y - (h / 2) - up_y, w, h);
    +                  imlib_context_set_image(image);
    +                  imlib_free_image();
    +               }
    +             
    +             /* draw a gradient on top of things at the top left of the window */
    +             /* create a range */
    +             range = imlib_create_color_range();
    +             imlib_context_set_color_range(range);
    +             /* add white opaque as the first color */
    +             imlib_context_set_color(255, 255, 255, 255);
    +             imlib_add_color_to_color_range(0);
    +             /* add an orange color, semi-transparent 10 units from the first */
    +             imlib_context_set_color(255, 200, 10, 100);
    +             imlib_add_color_to_color_range(10);
    +             /* add black, fully transparent at the end 20 units away */
    +             imlib_context_set_color(0, 0, 0, 0);
    +             imlib_add_color_to_color_range(20);
    +             /* draw the range */
    +             imlib_context_set_image(buffer);
    +             imlib_image_fill_color_range_rectangle(- up_x, - up_y, 128, 128, -45.0);
    +             /* free it */
    +             imlib_free_color_range();
    +             
    +             /* draw text - centered with the current mouse x, y */
    +             font = imlib_load_font("notepad/30");
    +             if (font)
    +               {
    +                  char text[4096];
    +                  
    +                  /* set the current font */
    +                  imlib_context_set_font(font);
    +                  /* set the image */
    +                  imlib_context_set_image(buffer);
    +                  /* set the color (black) */
    +                  imlib_context_set_color(0, 0, 0, 255);
    +                  /* print text to display in the buffer */
    +                  sprintf(text, "Mouse is at %i, %i", mouse_x, mouse_y);
    +                  /* query the size it will be */
    +                  imlib_get_text_size(text, &text_w, &text_h); 
    +                  /* draw it */
    +                  imlib_text_draw(320 - (text_w / 2) - up_x, 240 - (text_h / 2) - up_y, text); 
    +                  /* free the font */
    +                  imlib_free_font();
    +               }
    +             
    +             /* don't blend the image onto the drawable - slower */
    +             imlib_context_set_blend(0);
    +             /* set the buffer image as our current image */
    +             imlib_context_set_image(buffer);
    +             /* render the image at 0, 0 */
    +             imlib_render_image_on_drawable(up_x, up_y);
    +             /* don't need that temporary buffer image anymore */
    +             imlib_free_image();
    +          }
    +        /* if we had updates - free them */
    +        if (updates)
    +           imlib_updates_free(updates);
    +        /* loop again waiting for events */
    +     }
    +   return 0;
    +}
    +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    API +Reference
    + +

    This is a list of +all the Imlib2 API calls and what each of them do. You should familiarize +yourself well with this API so you have a good idea of what can be done.

    +void imlib_context_set_display(Display *display); + +
    Sets the current X display to be used for rendering of images +to drawables. You do not need to set this if you do not intend to render +an image to an X drawable. If you do you will need to set this. If you +change displays just set this to the new display pointer. Do not use a +Display pointer if you have closed that display already - also note that +if you close a display connection and continue to render using Imlib2 without +setting the display pointer to NULL or something new, crashes may occur.
    + +void imlib_context_set_visual(Visual *visual); + +
    This sets the current visual to use when rendering images to +drawables or producing pixmaps. You need to set this for anything to render +to a drawable or produce any pixmaps (this can be the default visual).
    + +void imlib_context_set_colormap(Colormap colormap); + +
    Sets the colormap to use when rendering to drawables and allocating +colors. You must set this to the colormap you are using to render any images +or produce any pixmaps (this can be the default colormap).
    + +void imlib_context_set_drawable(Drawable drawable); + +
    This sets the X drawable to which images will be rendered when +you call a render call in Imlib2. This may be either a pixmap or a window. +You must set this to render anything.
    + +void imlib_context_set_mask(Pixmap mask); + +
    This sets the 1-bit deep pixmap to be drawn to when rendering +to generate a mask pixmap. This is only useful if the image you are rendering +has alpha. Set this to 0 to not render a pixmap mask.
    + +void imlib_context_set_dither_mask(char dither_mask); + +
    Selects if, you are rendering to a mask, or producing pixmap +masks from images, if the mask is to be dithered or not. passing in 1 for +dither_mask means the mask pixmap will be dithered, 0 means it will not +be dithered.
    + +void imlib_context_set_anti_alias(char anti_alias); + +
    Toggles "anti-aliased" scaling of images. This isn't quite +correct since it's actually super and sub pixel sampling that it turns +on and off, but anti-aliasing is used for having "smooth" edges to lines +and shapes and this means when images are scaled they will keep their smooth +appearance. Passing in 1 turns this on and 0 turns it off.
    + +void imlib_context_set_dither(char dither); + +
    Sets the dithering flag for rendering to a drawable or when +pixmaps are produced. This affects the color image appearance by enabling +dithering. Dithering slows down rendering but produces considerably better +results. this option has no effect foe rendering in 24 bit and up, but +in 16 bit and lower it will dither, producing smooth gradients and much +better quality images. setting dither to 1 enables it and 0 disables it.
    + +void imlib_context_set_blend(char blend); + +
    When rendering an image to a drawable, Imlib2 is able to blend +the image directly onto the drawable during rendering. setting this to +1 will enable this. If the image has no alpha channel this has no effect. +Setting it to 0 will disable this.
    + +void imlib_context_set_color_modifier(Imlib_Color_Modifier color_modifier); + +
    This sets the current color modifier used for rendering pixmaps +or images to a drawable or images onto other images. Color modifiers are +lookup tables that map the values in the red, green, blue and alpha channels +to other values in the same channel when rendering, allowing for fades, +color correction etc. to be done whilst rendering. pass in NULL as the +color_modifier to disable the color modifier for rendering.
    + +void imlib_context_set_operation(Imlib_Operation operation); + +
    When Imlib2 draws an image onto another or an image onto a +drawable it is able to do more than just blend the result on using the +given alpha channel of the image. It is also able to do saturating additive, +subtractive and a combination of the both (called reshade) rendering. The +default mode is IMLIB_OP_COPY. you can also set it to IMLIB_OP_ADD, IMLIB_OP_SUBTRACT +or IMLIB_OP_RESHADE. Use this function to set the rendering operation. +IMLIB_OP_COPY performs basic alpha blending: DST = (SRC * A) + (DST * (1 +- A)). IMLIB_OP_ADD does DST = DST + (SRC * A). IMLIB_OP_SUBTRACT does +DST = DST - (SRC * A) and IMLIB_OP_RESHADE does DST = DST + (((SRC - 0.5) +/ 2) * A).
    + +void imlib_context_set_font(Imlib_Font font); + +
    This function sets the current font to use when rendering text. +you should load the font first with imlib_load_font().
    + +void imlib_context_set_direction(Imlib_Text_Direction direction); + +
    This sets the direction in which to draw text in terms of simple +90 degree orientations or an arbitrary angle. The direction can be one +of IMLIB_TEXT_TO_RIGHT, IMLIB_TEXT_TO_LEFT, IMLIB_TEXT_TO_DOWN, IMLIB_TEXT_TO_UP +or IMLIB_TEXT_TO_ANGLE. The default is IMLIB_TEXT_TO_RIGHT. If you use +IMLIB_TEXT_TO_ANGLE, you will also have to set the angle with imlib_context_set_angle().
    + +void imlib_context_set_angle(double angle); + +
    This sets the angle at which text strings will be drawn if +the text direction has been set to IMLIB_TEXT_TO_ANGLE with imlib_context_set_direction().
    + +void imlib_context_set_color(int red, int green, int blue, int alpha); + +
    This sets the color with which text, lines and rectangles are +drawn when being rendered onto an image. Values for red, green, blue and +alpha are between 0 and 255 - any other values have undefined results.
    + +void imlib_context_set_color_cmya(int cyan, magenta, int yellow, int alpha); + +
    This sets the color in CMYA space. Values for cyan, magenta, +yellow and alpha are between 0 and 255 - any other values have undefined results.
    + +void imlib_context_set_color_hsva(float hue, float saturation, float value, int alpha); + +
    This sets the color in HSVA space. Values for hue are between 0 and 360, +values for saturation and value between 0 and 1, and values for alpha are between 0 +and 255 - any other values have undefined results.
    + +void imlib_context_set_color_hlsa(float hue, float lightness, float saturation, int alpha); + +
    This sets the color in HLSA space. Values for hue are between 0 and 360, +values for lightness and saturation between 0 and 1, and values for alpha are +between 0 and 255 - any other values have undefined results.
    + +void imlib_context_set_color_range(Imlib_Color_Range color_range); + +
    This sets the current color range to use for rendering gradients.
    + +void imlib_context_set_progress_function(Imlib_Progress_Function progress_function); + +
    This sets the progress function to be called back whilst loading +images. Set this to the function to be called, or set it to NULL to disable +progress callbacks whilst loading.
    + +void imlib_context_set_progress_granularity(char progress_granularity); + +
    This hints as to how often to call the progress callback. 0 +means as often as possible. 1 means whenever 15 more of the image has been +decoded, 10 means every 10% of the image decoding, 50 means every 50% and +100 means only call at the end. Values outside of the range 0-100 are undefined.
    + +void imlib_context_set_image(Imlib_Image image); + +
    This sets the current image Imlib2 will be using with its function +calls.
    + +void imlib_context_set_filter(Imlib_Filter filter); + +
    This sets the current filter to be used when applying filters +to images. Set this to NULL to disable filters.
    + +Display *imlib_context_get_display(void); + +
    This returns the current display used for Imlib2's display +context.
    + +Visual *imlib_context_get_visual(void); + +
    Returns the current visual used for Imlib2's context.
    + +Colormap imlib_context_get_colormap(void); + +
    Returns the current Colormap used for Imlib2's context.
    + +Drawable imlib_context_get_drawable(void); + +
    Returns the current Drawable used for Imlib2's context.
    + +Pixmap imlib_context_get_mask(void); + +
    Returns the current pixmap destination to be used to render +a mask into.
    + +char imlib_context_get_dither_mask(void); + +
    Returns the current mode for dithering pixmap masks. 1 means +dithering is enabled and 0 means it is not.
    + +char imlib_context_get_anti_alias(void); + +
    Returns if Imlib2 currently will smoothly scale images. 1 means +it will and 0 means it will not.
    + +char imlib_context_get_dither(void); + +
    Returns if image data is rendered with dithering currently. +1 means yes and 0 means no.
    + +char imlib_context_get_blend(void); + +
    Returns if Imlib2 will blend images onto a drawable whilst +rendering to that drawable. 1 means yes and 0 means no.
    + +Imlib_Color_Modifier imlib_context_get_color_modifier(void); + +
    Returns the current colormodifier being used.
    + +Imlib_Operation imlib_context_get_operation(void); + +
    Returns the current operation mode.
    + +Imlib_Font imlib_context_get_font(void); + +
    Returns the current font.
    + +double imlib_context_get_angle(void); + +
    Returns the current angle used to render text at if the direction +is IMLIB_TEXT_TO_ANGLE.
    + +Imlib_Text_Direction imlib_context_get_direction(void); + +
    Returns the current direction to render text in.
    + +void imlib_context_get_color(int *red, int *green, int *blue, int *alpha); + +
    Returns the current color for rendering text, rectangles and +lines.
    + +void imlib_context_get_color_cmya(int *cyan, int *magenta, int *yellow, int *alpha); + +
    Returns the current color for rendering text, rectangles and +lines in CMYA space.
    + +void imlib_context_get_color_hsva(float *hue, float *saturation, float *value, int *alpha); + +
    Returns the current color for rendering text, rectangles and +lines in HSVA space.
    + +void imlib_context_get_color_hlsa(float *hue, float * lightness, float *saturation, int *alpha); + +
    Returns the current color for rendering text, rectangles and +lines in HLSA space.
    + +Imlib_Color *imlib_context_get_imlib_color(void); + +
    Returns the current color as a color struct. Do NOT free this +pointer.
    + +Imlib_Color_Range imlib_context_get_color_range(void); + +
    Return the current color range being used for gradients.
    + +Imlib_Progress_Function imlib_context_get_progress_function(void); + +
    Return the current progress function being used.
    + +char imlib_context_get_progress_granularity(void); + +
    Get the current progress granularity being used.
    + +Imlib_Image imlib_context_get_image(void); + +
    Return the current context image.
    + +Imlib_Filter imlib_context_get_filter(void); + +
    Get the current context image filter.
    + +int imlib_get_cache_size(void); + +
    Return the current size of the image cache in bytes. The cache +is a unified cache used for image data AND pixmaps.
    + +void imlib_set_cache_size(int bytes); + +
    Set the cache size. The size is in bytes. Setting the cache +size to 0 effectively flushes the cache and keeps the cache size at 0 until +set to another value. Whenever you set the cache size Imlib2 will flush +as many old images and pixmap from the cache as needed until the current +cache usage is less than or equal to the cache size.
    + +int imlib_get_color_usage(void); + +
    Get the number of colors Imlib2 currently at a maximum is allowed +to allocate for rendering. The default is 256.
    + +void imlib_set_color_usage(int max); + +
    Set the maximum number of colors you would like Imlib2 to allocate +for you when rendering. The default ids 256. This has no effect in depths +greater than 8 bit.
    + +void imlib_flush_loaders(void); + +
    If you want Imlib2 to forcibly flush any cached loaders it +has and re-load them from disk (this is useful if the program just installed +a new loader and does not want to wait till Imlib2 deems it an optimal +time to rescan the loaders)
    + +int imlib_get_visual_depth(Display *display, Visual *visual); + +
    Convenience function that returns the depth of a visual for +that display.
    + +Visual *imlib_get_best_visual(Display *display, int screen, int *depth_return); + +
    Returns the visual for that display and screen that Imlib2 +thinks will give you the best quality output. depth_return should point +to an int that will be filled with the depth of that visual too.
    + +Imlib_Image imlib_load_image(const char *file); + +
    This function loads an image from disk located at the path +specified by file. Please see the "How image loading works" section for +more detail. Returns an image handle on success or NULL on failure.
    + +Imlib_Image imlib_load_image_immediately(const char *file); + +
    Loads an image from disk located at the path specified by file. +This forces the image data to be decoded at load time too, instead of decoding +being deferred until it is needed. Returns an image handle on success or +NULL on failure.
    + +Imlib_Image imlib_load_image_without_cache(const char *file); + +
    This loads the image without looking in the cache first. Returns +an image handle on success or NULL on failure.
    + +Imlib_Image imlib_load_image_immediately_without_cache(const char *file); + +
    Loads the image without deferred image data decoding (i.e. +it is decoded straight away) and without looking in the cache. Returns +an image handle on success or NULL on failure.
    + +Imlib_Image imlib_load_image_with_error_return(const char *file, Imlib_Load_Error *error_return); + +
    This loads an image at the path file on disk. If it succeeds +it returns a valid image handle, if not NULL is returned and the error_return +pointed to is set to the detail of the error.
    + +void imlib_free_image(void); + +
    This frees the image that is set as the current image in Imlib2's +context.
    + +void imlib_free_image_and_decache(void); + +
    Frees the current image in Imlib2's context AND removes it +from the cache.
    + +int imlib_image_get_width(void); + +
    Returns the width in pixels of the current image in Imlib2's +context.
    + +int imlib_image_get_height(void); + +
    Returns the height in pixels of the current image in Imlib2's +context.
    + +const char *imlib_image_get_filename(void); + +
    This returns the filename for the file that is set as the current +context. The pointer returned is only valid as long as no operations cause +the filename of the image to change. Saving the file with a different name +would cause this. It is suggested you duplicate the string if you wish +to continue to use the string for later processing. Do not free the string +pointer returned by this function.
    + +DATA32 *imlib_image_get_data(void); + +
    This returns a pointer to the image data in the image set as +the image for the current context. When you get this pointer it is assumed +you are planning on writing to the data, thus once you do this the image +can no longer be used for caching - in fact all images cached from this +one will also be affected when you put the data back. If this matters it +is suggested you clone the image first before playing with the image data. +The image data is returned in the format of a DATA32 (32 bits) per pixel +in a linear array ordered from the top left of the image to the bottom +right going from left to right each line. Each pixel has the upper 8 bits +as the alpha channel and the lower 8 bits are the blue channel - so a pixel's +bits are ARGB (from most to least significant, 8 bits per channel). You +must put the data back at some point.
    + +DATA32 *imlib_image_get_data_for_reading_only(void); + +
    This functions the same way as imlib_image_get_data(), but +returns a pointer expecting the program to NOT write to the data returned +(it is for inspection purposes only). Writing to this data has undefined +results. The data does not need to be put back.
    + +void imlib_image_put_back_data(DATA32 *data); + +
    This will put back data when it was obtained by imlib_image_get_data(). +The data must be the same pointer returned by imlib_image_get_data(). This +operated on the current context image.
    + +char imlib_image_has_alpha(void); + +
    Returns 1 if the current context image has an alpha channel, +or 0 if it does not (the alpha data space is still there and available +- just "unused").
    + +void imlib_image_set_changes_on_disk(void); + +
    By default Imlib2 will not check the timestamp of an image +on disk and compare it with the image in its cache - this is to minimize +disk activity when using the cache. Call this function and it will flag +the current context image as being liable to change on disk and Imlib2 +will check the timestamp of the image file on disk and compare it with +the cached image when it next needs to use this image in the cache.
    + +void imlib_image_get_border(Imlib_Border *border); + +
    This function fills the Imlib_Border structure to which border +points to with the values of the border of the current context image. The +border is the area at the edge of the image that does not scale with the +rest of the image when resized - the borders remain constant in size. This +is useful for scaling bevels at the edge of images differently to the image +center.
    + +void imlib_image_set_border(Imlib_Border *border); + +
    This sets the border of the current context image to the values +contained in the Imlib_Border structure border points to.
    + +void imlib_image_set_format(const char *format); + +
    This sets the format of the current image. This is used for +when you wish to save an image in a different format that it was loaded +in, or if the image currently has no file format associated with it.
    + +void imlib_image_set_irrelevant_format(char irrelevant); + +
    This sets if the format value of the current image is irrelevant +for caching purposes - by default it is. pass irrelevant as 1 to make it +irrelevant and 0 to make it relevant for caching.
    + +void imlib_image_set_irrelevant_border(char irrelevant); + +
    This sets if the border of the current image is irrelevant +for caching purposes. By default it is. Set irrelevant to 1 to make it +irrelevant, and 0 to make it relevant.
    + +void imlib_image_set_irrelevant_alpha(char irrelevant); + +
    This sets if the alpha channel status of the current image +(i.e. if there is or is not one) is important for caching purposes. By +default it is not. Set irrelevant to 1 to make it irrelevant and 0 to make +it relevant.
    + +char *imlib_image_format(void); + +
    This returns the current image's format. Do not free this string. +Duplicate it if you need it for later use.
    + +void imlib_image_set_has_alpha(char has_alpha); + +
    Sets the alpha flag for the current image. Set has_alpha to +1 to enable the alpha channel in the current image, or 0 to disable it.
    + +void imlib_render_pixmaps_for_whole_image(Pixmap *pixmap_return, Pixmap *mask_return); + +
    This function will create a pixmap of the current image (and +a mask if the image has an alpha value) and return the id's of the pixmap +and mask to the pixmap_return and mask_return pixmap id's. You must free +these pixmaps using Imlib2's free function imlib_free_pixmap_and_mask();.
    + +void imlib_render_pixmaps_for_whole_image_at_size(Pixmap *pixmap_return, Pixmap *mask_return, int width, int height); + +
    This function works just like imlib_render_pixmaps_for_whole_image(), +but will scale the output result to the width and height specified. Scaling +is done before depth conversion so pixels used for dithering don't grow +large.
    + +void imlib_free_pixmap_and_mask(Pixmap pixmap); + +
    This will free the pixmap (and any mask generated in association +with that pixmap). The pixmap will remain cached until the image the pixmap +was generated from is dirtied or decached, or the cache is flushed.
    + +void imlib_render_image_on_drawable(int x, int y); + +
    This renders the current image onto the current drawable at +the x, y pixel location specified without scaling.
    + +void imlib_render_image_on_drawable_at_size(int x, int y, int width, int height); + +
    This will render the current image onto the current drawable +at the x, y location specified AND scale the image to the width and height +specified.
    + +void imlib_render_image_part_on_drawable_at_size(int source_x, int source_y, int source_width, int source_height, int x, int y, int width, int height); + +
    This renders the source x, y, width, height pixel rectangle +from the current image onto the current drawable at the x, y location scaled +to the width and height specified.
    + +void imlib_blend_image_onto_image(Imlib_Image source_image, char merge_alpha, int source_x, int source_y, int source_width, int source_height, int destination_x, int destination_y, int destination_width, int destination_height); + +
    This will blend the source rectangle x, y, width, height from +the source_image onto the current image at the destination x, y location +scaled to the width and height specified. If merge_alpha is set to 1 it +will also modify the destination image alpha channel, otherwise the destination +alpha channel is left untouched.
    + +Imlib_Image imlib_create_image(int width, int height); + +
    This creates a new blank image of size width and height. The +contents of this image at creation time are undefined (they could be garbage +memory). You are free to do whatever you like with this image. It is not +cached. On success an image handle is returned - on failure NULL is returned.
    + +Imlib_Image imlib_create_image_using_data(int width, int height, DATA32 *data); + +
    This creates an image from the image data specified with the +width and height specified. The image data must be in the same format as +imlib_image_get_data() would return. You are responsible for freeing this +image data once the image is freed - Imlib2 will not do that for you. This +is useful for when you already have static buffers of the same format Imlib2 +uses (many video grabbing devices use such a format) and wish to use Imlib2 +to render the results onto another image, or X drawable. You should free +the image when you are done with it. Imlib2 returns a valid image handle +on success or NULL on failure
    + +Imlib_Image imlib_create_image_using_copied_data(int width, + int height, + DATA32 *data); + +
    This works the same way as imlib_create_image_using_data() +but Imlib2 copies the image data to the image structure. You may now do +whatever you wish with the original data as it will not be needed anymore. +Imlib2 returns a valid image handle on success or NULL on failure.
    + +Imlib_Image imlib_create_image_from_drawable(Pixmap mask, + int x, + int y, + int width, + int height, + char need_to_grab_x); + +
    This will return an image (using the mask to determine the +alpha channel) from the current drawable. If the mask is 0 it will not +create a useful alpha channel in the image. It will create an image from +the x, y, width , height rectangle in the drawable. If need_to_grab_x is +1 it will also grab the X Server to avoid possible race conditions in grabbing. +If you have not already grabbed the server you MUST set this to 1. Imlib2 +returns a valid image handle on success or NULL on failure.
    + +Imlib_Image imlib_create_scaled_image_from_drawable(Pixmap mask, + int source_x, + int source_y, + int source_width, + int source_height, + int destination_width, + int destination_height, + char need_to_grab_x, + char get_mask_from_shape); + +
    This will create an image from the current drawable (optionally +using the mask pixmap specified to determine alpha transparency) and scale +the grabbed data first before converting to an actual image (to minimize +reads from the frame buffer which can be slow). The source x, y, width, +height rectangle will be grabbed, scaled to the destination width and height, +then converted to an image. If need_to_grab_x is set to 1, X is grabbed +(set this to 1 unless you have already grabbed the server) and if get_mask_from_shape +and the current drawable is a window its shape is used for determining +the alpha channel. If successful this function will return a valid image +handle, otherwise NULL is returned.
    + +char imlib_copy_drawable_to_image(Pixmap mask, + int x, + int y, + int width, + int height, + int destination_x, + int destination_y, + char need_to_grab_x); + +
    This routine will grab a section of the current drawable (optionally +using the pixmap provided as a corresponding mask for that drawable - if +mask is 0 this is not used). It grabs the x, y, width, height rectangle +and places it at the destination x, y location in the current image. If +need_to_grab_x is 1 it will grab and ungrab the server whilst doing this +- you need to do this if you have not already grabbed the server.
    + +Imlib_Image imlib_clone_image(void); + +
    This creates an exact duplicate of the current image and returns +a valid image handle on success, or NULL on failure.
    + +Imlib_Image imlib_create_cropped_image(int x, + int y, + int width, + int height); + +
    This creates a duplicate of a x, y, width, height rectangle +in the current image and returns a valid image handle on success, or NULL +on failure.
    + +Imlib_Image imlib_create_cropped_scaled_image(int source_x, + int source_y, + int source_width, + int source_height, + int destination_width, + int destination_height); + +
    This function works the same as imlib_create_cropped_image() +but will scale the new image to the new destination width and height whilst +cropping.
    + +Imlib_Updates imlib_updates_clone(Imlib_Updates updates); + +
    This function creates a duplicate of the updates list passed +into the function.
    + +Imlib_Updates imlib_update_append_rect(Imlib_Updates updates, + int x, + int y, + int w, + int h); + +
    This function appends an update rectangle to the updates list +passed in (if the updates is NULL it will create a new updates list) and +returns a handle to the modified updates list (the handle may be modified +so only use the new updates handle returned)
    + +Imlib_Updates imlib_updates_merge(Imlib_Updates updates, + int w, + int h); + +
    This function takes an updates list, and modifies it by merging +overlapped rectangles and lots of tiny rectangles into larger rectangles +to minimize the number of rectangles in the list for optimized redrawing. +The new updates handle is now valid and the old one passed in is not.
    + +Imlib_Updates imlib_updates_merge_for_rendering(Imlib_Updates updates, + int w, + int h); + +
    This works almost exactly as imlib_updates_merge() but is more +lenient on the spacing between update rectangles - if they are very close +it amalgamates 2 smaller rectangles into 1 larger one.
    + +void imlib_updates_free(Imlib_Updates updates); + +
    This frees an updates list.
    + +Imlib_Updates imlib_updates_get_next(Imlib_Updates updates); + +
    This gets the next update in the updates list relative to the +one passed in.
    + +void imlib_updates_get_coordinates(Imlib_Updates updates, + int *x_return, + int *y_return, + int *width_return, + int *height_return); + +
    This returns the coordinates of an update.
    + +void imlib_updates_set_coordinates(Imlib_Updates updates, + int x, + int y, + int width, + int height); + +
    This modifies the coordinates of an update in an updates list.
    + +void imlib_render_image_updates_on_drawable(Imlib_Updates updates, + int x, + int y); + +
    Given an updates list (preferable already merged for rendering) +this will render the corresponding parts of the image to the current drawable +at an offset of x, y in the drawable.
    + +Imlib_Updates imlib_updates_init(void); + +
    This initializes an updates list before you add any updates +to it or merge it for rendering etc.
    + +Imlib_Updates imlib_updates_append_updates(Imlib_Updates updates, + Imlib_Updates appended_updates); + +
    This appends one updates list (appended_updates) to the updates +list (updates) and returns the new list.
    + +void imlib_image_flip_horizontal(void); + +
    This will flip/mirror the current image horizontally.
    + +void imlib_image_flip_vertical(void); + +
    This will flip/mirror the current image vertically.
    + +void imlib_image_flip_diagonal(void); + +
    This will flip/mirror the current image diagonally (good for +quick and dirty 90 degree rotations if used before to after a horizontal +or vertical flip).
    + +void imlib_image_orientate(int orientation); + +
    This will perform 90 degree rotations on the current image. +Passing in orientation does not rotate, 1 rotates clockwise by 90 degree, +2, rotates clockwise by 180 degrees, 3 rotates clockwise by 270 degrees.
    + +void imlib_image_blur(int radius); + +
    This will blur the current image. A radius of 0 has no effect, +1 and above determine the blur matrix radius that determine how much to +blur the image.
    + +void imlib_image_sharpen(int radius); + +
    This sharpens the current image. The radius affects how much +to sharpen by.
    + +void imlib_image_tile_horizontal(void); + +
    This modifies an image so it will tile seamlessly horizontally +if used as a tile (i.e. drawn multiple times horizontally)
    + +void imlib_image_tile_vertical(void); + +
    This modifies an image so it will tile seamlessly vertically +if used as a tile (i.e. drawn multiple times vertically)
    + +void imlib_image_tile(void); + +
    This modifies an image so it will tile seamlessly horizontally +and vertically if used as a tile (i.e. drawn multiple times horizontally +and vertically)
    + +Imlib_Font imlib_load_font(const char *font_name); + +
    This function will load a truetype font from the first directory +in the font path that contains that font. The font name format is "font_name/size". +For example. If there is a font file called blum.ttf somewhere in the font +path you might use "blum/20" to load a 20 pixel sized font of blum. If +the font cannot be found NULL is returned.
    + +void imlib_free_font(void); + +
    This frees the current font.
    + +void imlib_text_draw(int x, int y, const char *text); + +
    Call this function to draw the null-byte terminated string text +using the current font on the current image at the x, y location (x, y +denoting the top left corner of the font string)
    + +void imlib_text_draw_with_return_metrics(int x, + int y, + const char *text, + int *width_return, + int *height_return, + int *horizontal_advance_return, + int *vertical_advance_return); + +
    This function works just like imlib_text_draw() but also returns +the width and height of the string drawn, and horizontal_advance_return +returns the number of pixels you should advance horizontally to draw another +string (useful if you are drawing a line of text word by word) and vertical_advance_return +does the same for the vertical direction (i.e. drawing text line by line).
    + +void imlib_get_text_size(const char *text, + int *width_return, + int *height_return); + +
    This function returns the width and height in pixels the text +string would use up if drawn with the current font.
    + + +void imlib_get_text_advance(const char *text, + int *horizontal_advance_return, + int *vertical_advance_return); + +
    This function returns the advance horizontally and vertically +in pixels the next text string would need to be placed at for the current +font. The advances are not adjusted for rotation so you will have to translate +the advances (which are calculated as if the text was drawn horizontally +from left to right) depending on the text orientation.
    + + +int imlib_get_text_inset(const char *text); + +
    This function returns the inset of the first character of the +text string passed in using the current font and returns that value in pixels. +
    + +void imlib_add_path_to_font_path(const char *path); + +
    This function adds the directory path to the end of the current +list of directories to scan for fonts.
    + +void imlib_remove_path_from_font_path(const char *path); + +
    This function removes all directories in the font path that +match the path specified.
    + +char **imlib_list_font_path(int *number_return); + +
    This returns a list of strings that are the directories in +the font path. Do not free this list or change it in any way. If you add +or delete members of the font path this list will be invalid. If you intend +to use this list later duplicate it for your own use. The number of elements +in the array of strings is put into number_return.
    + +int imlib_text_get_index_and_location(const char *text, + int x, + int y, + int *char_x_return, + int *char_y_return, + int *char_width_return, + int *char_height_return); + +
    This will return the character number in the string text using +the current font at the x, y pixel location which is an offset relative +to the top left of that string. -1 is returned if there is no character +there. If there is a character, character x, y, width and height are also +filled in.
    + +void imlib_text_get_location_at_index(const char *text, + int index, + int *char_x_return, + int *char_y_return, + int *char_width_return, + int *char_height_return); + +
    This will return the geometry of the character at index index +in the text string using the current font.
    + +char **imlib_list_fonts(int *number_return); + +
    This returns a list of fonts imlib2 can find in its font path.
    + +void imlib_free_font_list(char **font_list, + int number); + +
    This will free the font list returned by imlib_list_fonts().
    + +int imlib_get_font_cache_size(void); + +
    This returns the font cache size in bytes.
    + +void imlib_set_font_cache_size(int bytes); + +
    This sets the font cache in bytes. Whenever you set the font +cache size Imlib2 will flush fonts from the cache until the memory used +by fonts is less than or equal to the font cache size. Setting the size +to 0 effectively frees all speculatively cached fonts.
    + +void imlib_flush_font_cache(void); + +
    This will cause a flush of all speculatively cached fonts from +the font cache.
    + +int imlib_get_font_ascent(void); + +
    Returns the current font's ascent value in pixels.
    + +int imlib_get_font_descent(void); + +
    Returns the current font's descent value in pixels.
    + +int imlib_get_maximum_font_ascent(void); + +
    Returns the current font's maximum ascent extent.
    + +int imlib_get_maximum_font_descent(void); + +
    Returns the current font's maximum descent extent.
    + +Imlib_Color_Modifier imlib_create_color_modifier(void); + +
    This function creates a new empty color modifier and returns +a valid handle on success. NULL is returned on failure.
    + +void imlib_free_color_modifier(void); + +
    Calling this function frees the current color modifier.
    + +void imlib_modify_color_modifier_gamma(double gamma_value); + +
    This function modifies the current color modifier by adjusting +the gamma by the value specified. The color modifier is modified not set, +so calling this repeatedly has cumulative effects. A gamma of 1.0 is normal +linear, 2.0 brightens and 0.5 darkens etc. Negative values are not allows.
    + +void imlib_modify_color_modifier_brightness(double brightness_value); + +
    This function modifies the current color modifier by adjusting +the brightness by the value specified. The color modifier is modified not +set, so calling this repeatedly has cumulative effects. brightness values +of 0 do not affect anything. -1.0 will make things completely black and +1.0 will make things all white. Values in-between vary brightness linearly.
    + +void imlib_modify_color_modifier_contrast(double contrast_value); + +
    This function modifies the current color modifier by adjusting +the contrast by the value specified. The color modifier is modified not +set, so calling this repeatedly has cumulative effects. Contrast of 1.0 +does nothing. 0.0 will merge to gray, 2.0 will double contrast etc.
    + +void imlib_set_color_modifier_tables(DATA8 *red_table, + DATA8 *green_table, + DATA8 *blue_table, + DATA8 *alpha_table); + +
    This function explicitly copies the mapping tables from the +table pointers passed into this function into those of the current color +modifier. Tables are 256 entry arrays of DATA8 which are a mapping of that +channel value to a new channel value. A normal mapping would be linear +(v[0] = 0, v[10] = 10, v[50] = 50, v[200] = 200, v[255] = 255).
    + +void imlib_get_color_modifier_tables(DATA8 *red_table, + DATA8 *green_table, + DATA8 *blue_table, + DATA8 *alpha_table); + +
    This copies the table values from the current color modifier +into the pointers to mapping tables specified. They must have 256 entries +and be DATA8 format.
    + +void imlib_reset_color_modifier(void); + +
    This function resets the current color modifier to have linear +mapping tables.
    + +void imlib_apply_color_modifier(void); + +
    This uses the current color modifier and modifies the current +image using the mapping tables in the current color modifier.
    + +void imlib_apply_color_modifier_to_rectangle(int x, + int y, + int width, + int height); + +
    This works the same way as imlib_apply_color_modifier() but +only modifies a selected rectangle in the current image.
    + +Imlib_Updates imlib_image_draw_line(int x1, + int y1, + int x2, + int y2, + char make_updates); + +
    Draw a line using the current color on the current image from +coordinates x1, y1 to x2, y2. If make_updates is 1 it will also return +an update you can use for an updates list, otherwise it returns NULL.
    + +void imlib_image_draw_rectangle(int x, + int y, + int width, + int height); + +
    This draws the outline of a rectangle on the current image +at the x, y coordinates with a size of width and height pixels, using the +current color.
    + +void imlib_image_fill_rectangle(int x, + int y, + int width, + int height); + +
    This draws a filled rectangle on the current image at the x, +y coordinates with a size of width and height pixels, using the current +color.
    + +void imlib_image_copy_alpha_to_image(Imlib_Image image_source, + int x, + int y); + +
    This copies the alpha channel of the source image to the x, +y coordinates of the current image, replacing the alpha channel there.
    + +void imlib_image_copy_alpha_rectangle_to_image(Imlib_Image image_source, + int x, + int y, + int width, + int height, + int destination_x, + int destination_y); + +
    This copies the source x, y, width, height rectangle alpha +channel from the source image and replaces the alpha channel on the destination +image at the x, y, coordinates.
    + +void imlib_image_scroll_rect(int x, + int y, + int width, + int height, + int delta_x, + int delta_y); + +
    This scrolls a rectangle at x, y, width, height within the +current image by the delta x, y distance (in pixels).
    + +void imlib_image_copy_rect(int x, + int y, + int width, + int height, + int new_x, + int new_y); + +
    This copies a rectangle of size width, height at the x, y location +specified in the current image to a new location x, y in the same image.
    + +Imlib_Color_Range imlib_create_color_range(void); + +
    This creates a new empty color range and returns a valid handle +to that color range.
    + +void imlib_free_color_range(void); + +
    This frees the current color range.
    + +void imlib_add_color_to_color_range(int distance_away); + +
    This adds the current color to the current color range at a +distance_away distance from the previous color in the range (if it's the +first color in the range this is irrelevant).
    + +void imlib_image_fill_color_range_rectangle(int x, + int y, + int width, + int height, + double angle); + +
    This fills a rectangle of width and height at the x, y location +specified in the current image with a linear gradient of the current color +range at an angle of angle degrees with 0 degrees being vertical from top +to bottom going clockwise from there.
    + +void imlib_image_fill_hsva_color_range_rectangle(int x, + int y, + int width, + int height, + double angle); + +
    This fills a rectangle of width and height at the x, y location +specified in the current image with a linear gradient in HSVA color space of +the current color range at an angle of angle degrees with 0 degrees being +vertical from top to bottom going clockwise from there.
    + +void imlib_image_query_pixel(int x, + int y, + Imlib_Color *color_return); + +
    This fills the color_return color structure with the color +of the pixel in the current image that is at the x, y location specified.
    + +void imlib_image_query_pixel_cmya(int x, + int y, + int *cyan, + int *magenta, + int *yellow, + int *alpha); + +
    This returns the CMYA color of the pixel in the current image +that is at the x, y location specified.
    + +void imlib_image_query_pixel_hsva(int x, + int y, + float *hue, + float *saturation, + float *value, + int *alpha); + +
    This returns the HSVA color of the pixel in the current image +that is at the x, y location specified.
    + +void imlib_image_query_pixel_hlsa(int x, + int y, + float *hue, + float *lightness, + float *saturation, + int *alpha); + +
    This returns the HLSA color of the pixel in the current image +that is at the x, y location specified.
    + +void imlib_image_attach_data_value(const char *key, + void *data, + int value, + Imlib_Data_Destructor_Function destructor_function); + +
    This attaches data to the current image with the string key +of key, and the data of data and an integer of value. The destructor function, +if not NULL is called when this image is freed so the destructor can free +the data, if this is needed.
    + +void *imlib_image_get_attached_data(const char *key); + +
    This returns the data attached to the current image with the +key specified. NULL is returned if no data could be found with that key +on the current image.
    + +int imlib_image_get_attached_value(const char *key); + +
    This returns the value attached to the current image with the +specified key. If none could be found 0 is returned.
    + +void imlib_image_remove_attached_data_value(const char *key); + +
    This detaches the data & value attached with the specified +key from the current image.
    + +void imlib_image_remove_and_free_attached_data_value(const char *key); + +
    This removes the data and value attached to the current image +with the specified key and also calls the destructor function that was +supplied when attaching it.
    + +void imlib_save_image(const char *filename); + +
    This saves the current image in the format specified by the +current image's format settings to the filename specified.
    + +void imlib_save_image_with_error_return(const char *filename, + Imlib_Load_Error *error_return); + +
    This works the same way imlib_save_image() works, but will +set the error_return to an error value if the save fails.
    + +Imlib_Image imlib_create_rotated_image(double angle); + +
    This creates an new copy of the current image, but rotated +by angle degrees. On success it returns a valid image handle, otherwise +NULL.
    + +void imlib_blend_image_onto_image_at_angle(Imlib_Image source_image, + char merge_alpha, + int source_x, + int source_y, + int source_width, + int source_height, + int destination_x, + int destination_y, + int angle_x, + int angle_y); + +
    This function works just like imlib_blend_image_onto_image_skewed() +except you cannot skew an image (v_angle_x and v_angle_y are 0).
    + +void imlib_blend_image_onto_image_skewed(Imlib_Image source_image, + char merge_alpha, + int source_x, + int source_y, + int source_width, + int source_height, + int destination_x, + int destination_y, + int h_angle_x, + int h_angle_y, + int v_angle_x, + int v_angle_y); + +
    This will blend the source rectangle x, y, width, height from +the source_image onto the current image at the destination x, y location. +

    It will be rotated and scaled so that the upper right corner will be +positioned h_angle_x pixels to the right (or left, if negative) and h_angle_y +pixels down (from destination_[x|y]). +

    If v_angle_x and v_angle_y are not 0, the image will also be skewed +so that the lower left corner will be positioned v_angle_x pixels to the +right and v_angle_y pixels down. +

    The at_angle versions simply have the v_angle_x and v_angle_y set to +0 so the rotation doesn't get skewed, and the render_..._on_drawable ones +seem obvious enough; they do the same on a drawable. +

    Examples: +

      +
    • +imlib_blend_image_onto_image_skewed(..., 0, 0, 100, 0, 0, 100);
    • + +


      will simply scale the image to be 100x100. +
      +

    • +imlib_blend_image_onto_image_skewed(..., 0, 0, 0, 100, 100, 0);
    • + +


      will scale the image to be 100x100, and flip it diagonally. +
      +

    • +imlib_blend_image_onto_image_skewed(..., 100, 0, 0, 100, -100, 0);
    • + +


      will scale the image and rotate it 90 degrees clockwise. +
      +

    • +imlib_blend_image_onto_image_skewed(..., 50, 0, 50, 50, -50, 50);
    • + +


      will rotate the image 45 degrees clockwise, and will scale it so +its corners are at (50,0)-(100,50)-(50,100)-(0,50) i.e. it fits into the +100x100 square, so it's scaled down to 70.7% (sqrt(2)/2). +
      +

    • +imlib_blend_image_onto_image_skewed(..., 50, 50, 100 * cos(a), 100 * sin(a), +0);
    • + +


      will rotate the image `a' degrees, with its upper left corner at +(50,50). +

    +
    + +void imlib_render_image_on_drawable_skewed(int source_x, + int source_y, + int source_width, + int source_height, + int destination_x, + int destination_y, + int h_angle_x, + int h_angle_y, + int v_angle_x, + int v_angle_y); + +
    This works just like imlib_blend_image_onto_image_skewed(), +except it blends the image onto the current drawable instead of the current +image.
    + +void imlib_render_image_on_drawable_at_angle(int source_x, + int source_y, + int source_width, + int source_height, + int destination_x, + int destination_y, + int angle_x, + int angle_y); + +
    This function works just like imlib_render_image_on_drawable_skewed() +except you cannot skew an image (v_angle_x and v_angle_y are 0).
    + +void imlib_context_set_cliprect(int x, int y, int w, int h); + +
    Sets the current clipping rectangle to (x,y w*h). The clipping +rectangle effects all image drawing functions and prevents the area outside +the rectangle from being edited. Set w to 0 to disable clipping.
    + +int imlib_clip_line(int x0, int y0, int x1, int y1, int xmin, int xmax, int ymin, int ymax, int *clip_x0, int *clip_y0, int *clip_x1, int *clip_y1); + +
    A utility function to return clipped line coordinates.
    + +void imlib_polygon_new(void); + +
    Returns a new polygon object with no points set.
    + +void imlib_polygon_free(ImlibPolygon poly); + +
    Frees a polygon object.
    + +void imlib_polygon_add_point(ImlibPolygon poly, int x, int y); + +
    Adds the point (x,y) to a polygon object. The point will be +added to the end of the polygon's internal point list. The points are drawn +in order, from the first to the last.
    + +void imlib_image_draw_polygon(ImlibPolygon poly, unsigned char closed); + +
    Draws a polygon onto the current context image. Points which +have been added to the polygon are drawn in sequence, first to last. The +final point will be joined with the first point if closed is non-zero.
    + +void imlib_image_fill_polygon(ImlibPolygon poly); + +
    Fill the area defined by the polygon on the current context +image with the current context colour.
    + +void imlib_polygon_get_bounds(ImlibPolygon poly, int *px1, int *py1, int *px2, int *py2); + +
    Calculate the bounding area of the polygon. (px1, py1) defines +the upper left corner of the bounding box and (px2, py2) defines it's lower +right corner.
    + +unsigned char imlib_polygon_contains_point(ImlibPolygon poly, int x, int y); + +
    Returns non-zero if the point (x,y) is within the area defined +by the polygon.
    + +void imlib_image_draw_ellipse(int xc, int yc, int a, int b); + +
    Draw an ellipse on the current context image. The ellipse is +defined as (x-xc)^2/a^2 + (y-yc)^2/b^2 = 1. This means that the point (xc,yc) +marks the center of the ellipse, a defines the horizontal amplitude +of the ellipse, and b defines the vertical amplitude.
    + +void imlib_image_fill_ellipse(int xc, int yc, int a, int b); + +
    Fills an ellipse on the current context image using the current +context colour. The ellipse is defined as (x-xc)^2/a^2 + (y-yc)^2/b^2 = +1. This means that the point (xc,yc) marks the center of +the ellipse, a defines the horizontal amplitude of the ellipse, +and b defines the vertical amplitude.
    + +void imlib_image_filter(void); + +
    +
    + +Imlib_Filter imlib_create_filter(int initsize); + +
    +
    + +void imlib_free_filter(void); +
    +
    + +void imlib_filter_set(int xoff, + int yoff, + int a, + int r, + int g, + int b); + +
    +
    + +void imlib_filter_set_alpha(int xoff, + int yoff, + int a, + int r, + int g, + int b); + +
    +
    + +void imlib_filter_set_red(int xoff, + int yoff, + int a, + int r, + int g, + int b); + +
    +
    + +void imlib_filter_set_green(int xoff, + int yoff, + int a, + int r, + int g, + int b); + +
    +
    + +void imlib_filter_set_blue(int xoff, + int yoff, + int a, + int r, + int g, + int b); + +
    +
    + +void imlib_filter_constants(int a, + int r, + int g, + int b); + +
    +
    + +void imlib_filter_divisors(int a, + int r, + int g, + int b); + +
    +
    + +void imlib_apply_filter( char *script, ... ); + +
    +
    + +

    +Imlib 2 Dynamic Filters +

    +Imlib2 has built in features allowing filters and effects to be applied at +run time through a very small scripting language, this is similar to that +of script-fu found in the GIMP (http://www.gimp.org). There are two parts +to the system, the client library call ``imlib_apply_filter'' and the +library side filters. The library side filters are synonymous with image +loaders. +

    +To run a script on an image you need to set the context image then call: +

    +

    +
    +imlib_apply_filter( script_string, ... );
    +
    +
    +

    +The script_string variable is made up of the script language, which is +very simple and made up of only function calls. Functions calls look like +this: +

    +

    +
    +filter name( key=value [, ...] );
    +
    +
    +

    +Where, +

    +

    +filter name is the name of the filter you wish to apply
    +key is an expected value
    +value is a ``string'', a number, or an actual variable in
    +
    +

    +the program, or the result of another filter. +

    +eg. +

    +

    +
    +bump_map( map=tint(red=50,tint=200), blue=10 );
    +
    +
    +

    +This example would bump map using a a map generated from the tint filter. +

    +It is also possible to pass application information to the filters via the +usage of the [] operator. When the script is being compiled the script +engine looks on the parameters passed to it and picks up a pointer for +every [] found. +

    +eg2. +

    +

    +
    +imlib_apply_filter( "tint( x=[], y=[], red=255, alpha=55 );", &myxint, &myyint );
    +
    +
    +

    +This will cause a tint to the current image at (myxint,myyint) to be +done. This is very useful for when you want the filters to dynamically +change according to program variables. +The system is very quick as the code is pseudo-compiled and then run. The +advantage of having the scripting system allows customization of the image +manipulations, this is particularly useful in applications that allow +modifications to be done (eg. image viewers). +

    +Filter Library +

    +There are three functions that must be in every filter library +

    +

    +
    +void init( struct imlib_filter_info *info ); - Called once on loading of the filter
    +
    +
    +

    +info - a structure passed to the filter to be filled in with information about the filter +info->name - Name of the filter library
    +info->author - Name of the library author
    +info->description - Description of the filter library
    +info->num_filters - Number of filters the library exports
    +info->filters - An array of ``char *'' with each filter name in it.
    +

    +

    +
    +void deinit(); - Called when the filter is closed
    +
    +
    +

    +

    +
    +/* Called every time a filter the library exports is called */
    +void *exec( char *filter, void *im, pIFunctionParam params );
    +
    +
    +

    +filter - The name of the filter being asked for +im - The image that the filter should be applied against +params - A linked list of parameters. +

    +The best way to get all the values is such: +

    +Declare all parameters and initialize them to there default values. +
    +
    +  for( ptr = params; ptr != NULL; ptr = ptr->next )
    +    {
    +      ..MACRO TO GET VALUE..
    +    }
    +
    +
    +Current Macros are: +
    +
    +   ASSIGN_INT( keyname, local variable )
    +   ASSIGN_DATA8( keyname, local variable )
    +   ASSIGN_IMAGE( keyname, local variable )
    +
    +
    +eg. +
    +
    +   int r = 50;
    +   IFunctionParam *ptr;
    +				      
    +   for( ptr = params; ptr != NULL; ptr = ptr->next )
    +     {
    +       ASSIGN_INT( "red", r );
    +     }
    +
    +
    +
    +

    +If the value "red" is not passed to the filter then it will remain +at 50, but it a value is passed, it will be assign to r. +

    +return type - Imlib_Image, this is the result of filter. +

    + +

    + + + + diff --git a/gendoc b/gendoc new file mode 100755 index 0000000..ed1fed4 --- /dev/null +++ b/gendoc @@ -0,0 +1,17 @@ +#!/bin/sh +cp ./imlib2.c.in ./imlib2.c + +for I in `find ./src -name "api.c" -print`; do + cat $I >> ./imlib2.c +done + +#for I in `find ./src/lib -name "*.c" -print`; do +# cat $I >> ./imlib2.c +#done +rm -rf ./doc/html ./doc/latex ./doc/man +doxygen +cp doc/img/*.png doc/html/ +rm -f imlib2_docs.tar imlib2_docs.tar.gz +tar -cvf imlib2_docs.tar doc/html doc/man doc/latex +gzip -9 imlib2_docs.tar +exit 0 diff --git a/imlib2-config.in b/imlib2-config.in new file mode 100644 index 0000000..315cadb --- /dev/null +++ b/imlib2-config.in @@ -0,0 +1,59 @@ +#!/bin/sh + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +exec_prefix_set=no + +usage="\ +Usage: imlib2-config [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] [--libs] [--cflags]" + +if test $# -eq 0; then + echo "${usage}" 1>&2 + exit 1 +fi + +while test $# -gt 0; do + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case $1 in + --prefix=*) + prefix=$optarg + if test $exec_prefix_set = no ; then + exec_prefix=$optarg + fi + ;; + --prefix) + echo $prefix + ;; + --exec-prefix=*) + exec_prefix=$optarg + exec_prefix_set=yes + ;; + --exec-prefix) + echo $exec_prefix + ;; + --version) + echo @VERSION@ + ;; + --cflags) + if test @includedir@ != /usr/include ; then + includes=-I@includedir@ + fi + echo $includes + ;; + --libs) + libdirs=-L@libdir@ + echo $libdirs -lImlib2 @my_libs@ + ;; + *) + echo "${usage}" 1>&2 + exit 1 + ;; + esac + shift +done + +exit 0 diff --git a/imlib2.c.in b/imlib2.c.in new file mode 100644 index 0000000..3439287 --- /dev/null +++ b/imlib2.c.in @@ -0,0 +1,547 @@ +/** +@file +@brief Imlib2 library + +Brief of imlib2 library +*/ +/** + +@mainpage Imlib2 Library Documentation +@image html imlib2.png +@version 1.1.1 +@author Carsten Haitzler +@date 1999-2004 + +@section intro What is Imlib2 ? + + +Imlib 2 is the successor to Imlib. It is NOT a newer version - it is a completely new library. Imlib 2 can be installed alongside Imlib 1.x without any problems since they are effectively different libraries - BUT they Have very similar functionality. + +Imlib 2 does the following: + +\li Load image files from disk in one of many formats +\li Save images to disk in one of many formats +\li Render image data onto other images +\li Render images to an X-Windows drawable +\li Produce pixmaps and pixmap masks of Images +\li Apply filters to images +\li Rotate images +\li Accept RGBA Data for images +\li Scale images +\li Alpha blend Images on other images or drawables +\li Apply color correction and modification tables and factors to images +\li Render images onto images with color correction and modification tables +\li Render truetype anti-aliased text +\li Render truetype anti-aliased text at any angle +\li Render anti-aliased lines +\li Render rectangles +\li Render linear multi-colored gradients +\li Cache data intelligently for maximum performance +\li Allocate colors automatically +\li Allow full control over caching and color allocation +\li Provide highly optimized MMX assembly for core routines +\li Provide plug-in filter interface +\li Provide on-the-fly runtime plug-in image loading and saving interface +\li Fastest image compositing, rendering and manipulation library for X + +If what you want isn't in the list above somewhere then likely Imlib 2 does not do it. If it does it it likely does it faster than any other library you can find (this includes gdk-pixbuf, gdkrgb, etc.) primarily because of highly optimized code and a smart subsystem that does the dirty work for you and picks up the pieces for you so you can be lazy and let all the optimizations for FOR you. + +Imlib 2 can run without a display, so it can be easily used for background image processing for web sites or servers - it only requires the X libraries to be installed - that is all - it does not require an XServer to run unless you wish to display images. + +The interface is simple - once you get used to it, the functions do exactly what they say they do. + +@section first_ex A Simple Example + +The best way to start is to show a simple example of an Imlib2 +program. This one will load an image of any format you have a loader +installed for (all loaders are dynamic code objects that Imlib2 will +use and update automatically runtime - anyone is free to write a +loader. All that has to be done is for the object to be dropped into +the loaders directory with the others and all Imlib2 programs will +automatically be able to use it - without a restart). + +@code +/* main program */ +int main(int argc, char **argv) +{ + /* an image handle */ + Imlib_Image image; + + /* if we provided < 2 arguments after the command - exit */ + if (argc != 3) exit(1); + /* load the image */ + image = imlib_load_image(argv[1]); + /* if the load was successful */ + if (image) + { + char *tmp; + /* set the image we loaded as the current context image to work on */ + imlib_context_set_image(image); + /* set the image format to be the format of the extension of our last */ + /* argument - i.e. .png = png, .tif = tiff etc. */ + tmp = strrchr(argv[2], '.'); + if(tmp) + imlib_image_set_format(tmp + 1); + /* save the image */ + imlib_save_image(argv[2]); + } +} +@endcode + +Now to compile this + +@verbatim +cc imlib2_convert.c -o imlib2_convert `imlib2-config --cflags` `imlib2-config --libs` +@endverbatim + +You now have a program that if used as follows: + +@verbatim +cc imlib2_con +./imlib2_convert image1.jpg image2.png +@endverbatim + +will convert image1.jpg into a png called image2.png. It is that simple. + +@section loading How Image Loading Works + +It is probably a good idea to discuss how Imlib2 actually loads an Image so the programmer knows what is going on, how to take advantage of the optimizations already there and to explain why things work as they do. + +@subsection load_func Loading using imlib_load_image(); + +This is likely to be by far the most common way to load an image - when you don't really care about the details of the loading process or why it failed - all you care about is if you got a valid image handle. + +When you call this function Imlib2 attempts to find the file specified as the parameter. This will involve Imlib2 first checking to see if that file path already has been loaded and is in Imlib2's cache (a cache of already decoded images in memory to save having to load and decode from disk all the time). If there already is a copy in the cache (either already active or speculatively cached from a previous load & free) this copy will have its handle returned instead of Imlib2 checking on disk (in some circumstances this is not true - see later in this section to find out). This means if your program blindly loads an Image, renders it, then frees it - then soon afterwards loads the same image again, it will not be loaded from disk at all, instead it will simply be re-referenced from the cache - meaning the load will be almost instant. A great way to take full advantage of this is to set the cache to some size you are happy with for the image data being used by your application and then all rendering o an image follows the pseudo code: + +@verbatim +set cache to some amount (e.g. 4 Mb) +... +rendering loop ... + load image + render image + free image +... continue loop +@endverbatim + +This may normally sound silly - load image, render then free - EVERY time we want to use it, BUT - it is actually the smartest way to use Imlib2 - since the caching will find the image for you in the cache - you do not need to manage your own cache, or worry about filling up memory with image data - only as much memory as you have set for the cache size will actually ever be used to store image data - if you have lots of image data to work with then increase the cache size for better performance, but this is the only thing you need to worry about. you won't have problems of accidentally forgetting to free images later since you free them immediately after use. + +Now what happens if the file changes on disk while it's in cache? By default nothing. The file is ignored. This is an optimization (to avoid hitting the disk to check if the file changed for every load if it's cached). You can inform Imlib2 that you care about this by using the imlib_image_set_changes_on_disk(); call. Do this whenever you load an Image that you expect will change on disk, and the fact that it changes really matters. Remember this will marginally reduce the caching performance. + +Now what actually happens when we try and load an image using a +filename? First the filename is broken down into 2 parts. the filename +before a colon (:) and the key after the colon. This means when we +have a filename like: + +@verbatim +/path/to/file.jpg +@endverbatim + +the filename is: + +@verbatim +/path/to/file.jpg +@endverbatim + +and the key is blank. If we have: + +@verbatim +/path/to/file.db:key.value/blah +@endverbatim + +the filename is: + +@verbatim +/path/to/file.db +@endverbatim + +and the key is: + +@verbatim +key.value/blah +@endverbatim + +You may ask what is this thing with keys and filenames? Well Imlib2 has loaders that are able to load data that is WITHIN a file (the loader capable of this right now is the database loader that is able to load image data stored with a key in a Berkeley-db database file). The colon is used to delimit where the filename ends and the key begins. Fro the majority of files you load you won't have to worry, but there is a limit in this case that filenames cannot contain a color character. + +First Imlib2 checks to see if the file exists and that you have permission to read it. If this fails it will abort the load. Now that it has checked that this is the case it evaluates that it's list of dynamically loaded loader modules it up to date then it runs through the loader modules until one of them claims it can load this file. If this is the case that loader is now used to decode the image and return an Image handle to the calling program. If the loader is written correctly and the file format sanely supports this, the loader will NOT decode any image data at this point. It will ONLY read the header of the image to figure out its size, if it has an alpha channel, format and any other header information. The loader is remembered and it will be re-used to load the image data itself later if and ONLY if the actual image data itself is needed. This means you can scan vast directories of files figuring their format and size and other such information just by loading and freeing - and it will be fast because no image data is decoded. You can take advantage of this by loading the image and checking its size to calculate the size of an output area before you ever load the data. This means geometry calculations can be done fast ahead of time. + +If you desire more detailed information about why a load failed you can use imlib_load_image_with_error_return(); and it will return a detailed error return code. + +If you do not wish to have the image data loaded later using the optimized "deferred" method of loading, you can force the data to be decoded immediately with imlib_load_image_immediately(); + +If you wish to bypass the cache when loading images you can using imlib_load_image_without_cache(); and imlib_load_image_immediately_without_cache();. + +Sometimes loading images can take a while. Often it is a good idea to provide feedback to the user whilst this is happening. This is when you set the progress function callback. Setting this to NULL will mean no progress function is called during load - this is the default. When it is set you set it to a function that will get called every so often (depending on the progress granularity) during load. Use imlib_context_set_progress_function(); and imlib_context_set_progress_granularity(); to set this up. + +@section second_ex A more advanced Example + +This is a more comprehensive example that should show off a fair number of features of imlib2. The code this was based off can be found in Imlib2's test directory. This covers a lot of the core of Imlib2's API so you should have a pretty good idea on how it works if you understand this code snippet. + +@code +/* include X11 stuff */ +#include +/* include Imlib2 stuff */ +#include +/* sprintf include */ +#include + +/* some globals for our window & X display */ +Display *disp; +Window win; +Visual *vis; +Colormap cm; +int depth; + +/* the program... */ +int main(int argc, char **argv) +{ + /* events we get from X */ + XEvent ev; + /* areas to update */ + Imlib_Updates updates, current_update; + /* our virtual framebuffer image we draw into */ + Imlib_Image buffer; + /* a font */ + Imlib_Font font; + /* our color range */ + Imlib_Color_Range range; + /* our mouse x, y coordinates */ + int mouse_x = 0, mouse_y = 0; + + /* connect to X */ + disp = XOpenDisplay(NULL); + /* get default visual , colormap etc. you could ask imlib2 for what it */ + /* thinks is the best, but this example is intended to be simple */ + vis = DefaultVisual(disp, DefaultScreen(disp)); + depth = DefaultDepth(disp, DefaultScreen(disp)); + cm = DefaultColormap(disp, DefaultScreen(disp)); + /* create a window 640x480 */ + win = XCreateSimpleWindow(disp, DefaultRootWindow(disp), + 0, 0, 640, 480, 0, 0, 0); + /* tell X what events we are interested in */ + XSelectInput(disp, win, ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | ExposureMask); + /* show the window */ + XMapWindow(disp, win); + /* set our cache to 2 Mb so it doesn't have to go hit the disk as long as */ + /* the images we use use less than 2Mb of RAM (that is uncompressed) */ + imlib_set_cache_size(2048 * 1024); + /* set the font cache to 512Kb - again to avoid re-loading */ + imlib_set_font_cache_size(512 * 1024); + /* add the ./ttfonts dir to our font path - you'll want a notepad.ttf */ + /* in that dir for the text to display */ + imlib_add_path_to_font_path("./ttfonts"); + /* set the maximum number of colors to allocate for 8bpp and less to 128 */ + imlib_set_color_usage(128); + /* dither for depths < 24bpp */ + imlib_context_set_dither(1); + /* set the display , visual, colormap and drawable we are using */ + imlib_context_set_display(disp); + imlib_context_set_visual(vis); + imlib_context_set_colormap(cm); + imlib_context_set_drawable(win); + /* infinite event loop */ + for (;;) + { + /* image variable */ + Imlib_Image image; + /* width and height values */ + int w, h, text_w, text_h; + + /* init our updates to empty */ + updates = imlib_updates_init(); + /* while there are events form X - handle them */ + do + { + XNextEvent(disp, &ev); + switch (ev.type) + { + case Expose: + /* window rectangle was exposed - add it to the list of */ + /* rectangles we need to re-render */ + updates = imlib_update_append_rect(updates, + ev.xexpose.x, ev.xexpose.y, + ev.xexpose.width, ev.xexpose.height); + break; + case ButtonPress: + /* if we click anywhere in the window, exit */ + exit(0); + break; + case MotionNotify: + /* if the mouse moves - note it */ + /* add a rectangle update for the new mouse position */ + image = imlib_load_image("./test_images/mush.png"); + imlib_context_set_image(image); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + imlib_context_set_image(image); + imlib_free_image(); + /* the old position - so we wipe over where it used to be */ + updates = imlib_update_append_rect(updates, + mouse_x - (w / 2), mouse_y - (h / 2), + w, h); + font = imlib_load_font("notepad/30"); + if (font) + { + char text[4096]; + + imlib_context_set_font(font); + sprintf(text, "Mouse is at %i, %i", mouse_x, mouse_y); + imlib_get_text_size(text, &text_w, &text_h); + imlib_free_font(); + updates = imlib_update_append_rect(updates, + 320 - (text_w / 2), 240 - (text_h / 2), + text_w, text_h); + } + + mouse_x = ev.xmotion.x; + mouse_y = ev.xmotion.y; + /* the new one */ + updates = imlib_update_append_rect(updates, + mouse_x - (w / 2), mouse_y - (h / 2), + w, h); + font = imlib_load_font("notepad/30"); + if (font) + { + char text[4096]; + + imlib_context_set_font(font); + sprintf(text, "Mouse is at %i, %i", mouse_x, mouse_y); + imlib_get_text_size(text, &text_w, &text_h); + imlib_free_font(); + updates = imlib_update_append_rect(updates, + 320 - (text_w / 2), 240 - (text_h / 2), + text_w, text_h); + } + default: + /* any other events - do nothing */ + break; + } + } + while (XPending(disp)); + + /* no more events for now ? ok - idle time so lets draw stuff */ + + /* take all the little rectangles to redraw and merge them into */ + /* something sane for rendering */ + updates = imlib_updates_merge_for_rendering(updates, 640, 480); + for (current_update = updates; + current_update; + current_update = imlib_updates_get_next(current_update)) + { + int up_x, up_y, up_w, up_h; + + /* find out where the first update is */ + imlib_updates_get_coordinates(current_update, + &up_x, &up_y, &up_w, &up_h); + + /* create our buffer image for rendering this update */ + buffer = imlib_create_image(up_w, up_h); + + /* we can blend stuff now */ + imlib_context_set_blend(1); + + /* fill the window background */ + /* load the background image - you'll need to have some images */ + /* in ./test_images lying around for this to actually work */ + image = imlib_load_image("./test_images/bg.png"); + /* we're working with this image now */ + imlib_context_set_image(image); + /* get its size */ + w = imlib_image_get_width(); + h = imlib_image_get_height(); + /* now we want to work with the buffer */ + imlib_context_set_image(buffer); + /* if the iimage loaded */ + if (image) + { + /* blend image onto the buffer and scale it to 640x480 */ + imlib_blend_image_onto_image(image, 0, + 0, 0, w, h, + - up_x, - up_y, 640, 480); + /* working with the loaded image */ + imlib_context_set_image(image); + /* free it */ + imlib_free_image(); + } + + /* draw an icon centered around the mouse position */ + image = imlib_load_image("./test_images/mush.png"); + imlib_context_set_image(image); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + imlib_context_set_image(buffer); + if (image) + { + imlib_blend_image_onto_image(image, 0, + 0, 0, w, h, + mouse_x - (w / 2) - up_x, mouse_y - (h / 2) - up_y, w, h); + imlib_context_set_image(image); + imlib_free_image(); + } + + /* draw a gradient on top of things at the top left of the window */ + /* create a range */ + range = imlib_create_color_range(); + imlib_context_set_color_range(range); + /* add white opaque as the first color */ + imlib_context_set_color(255, 255, 255, 255); + imlib_add_color_to_color_range(0); + /* add an orange color, semi-transparent 10 units from the first */ + imlib_context_set_color(255, 200, 10, 100); + imlib_add_color_to_color_range(10); + /* add black, fully transparent at the end 20 units away */ + imlib_context_set_color(0, 0, 0, 0); + imlib_add_color_to_color_range(20); + /* draw the range */ + imlib_context_set_image(buffer); + imlib_image_fill_color_range_rectangle(- up_x, - up_y, 128, 128, -45.0); + /* free it */ + imlib_free_color_range(); + + /* draw text - centered with the current mouse x, y */ + font = imlib_load_font("notepad/30"); + if (font) + { + char text[4096]; + + /* set the current font */ + imlib_context_set_font(font); + /* set the image */ + imlib_context_set_image(buffer); + /* set the color (black) */ + imlib_context_set_color(0, 0, 0, 255); + /* print text to display in the buffer */ + sprintf(text, "Mouse is at %i, %i", mouse_x, mouse_y); + /* query the size it will be */ + imlib_get_text_size(text, &text_w, &text_h); + /* draw it */ + imlib_text_draw(320 - (text_w / 2) - up_x, 240 - (text_h / 2) - up_y, text); + /* free the font */ + imlib_free_font(); + } + + /* don't blend the image onto the drawable - slower */ + imlib_context_set_blend(0); + /* set the buffer image as our current image */ + imlib_context_set_image(buffer); + /* render the image at 0, 0 */ + imlib_render_image_on_drawable(up_x, up_y); + /* don't need that temporary buffer image anymore */ + imlib_free_image(); + } + /* if we had updates - free them */ + if (updates) + imlib_updates_free(updates); + /* loop again waiting for events */ + } + return 0; +} +@endcode + +@section filters Imlib2 filters + +@subsection dyn_filter Imlib 2 Dynamic Filters + +Imlib2 has built in features allowing filters and effects to be applied at run time through a very small scripting language, this is similar to that of script-fu found in the GIMP (http://www.gimp.org). There are two parts to the system, the client library call ``imlib_apply_filter'' and the library side filters. The library side filters are synonymous with image loaders. + +To run a script on an image you need to set the context image then call: + +@verbatim +imlib_apply_filter( script_string, ... ); +@endverbatim + +The script_string variable is made up of the script language, which is very simple and made up of only function calls. Functions calls look like this: + +@verbatim +filter name( key=value [, ...] ); +@endverbatim + +Where, + +\li filter name is the name of the filter you wish to apply +\li \b key is an expected value +\li \b value is a ``string'', a number, or an actual variable in + +the program, or the result of another filter. + +eg. + +@verbatim +bump_map( map=tint(red=50,tint=200), blue=10 ); +@endverbatim + +This example would bump map using a a map generated from the tint filter. + +It is also possible to pass application information to the filters via the usage of the [] operator. When the script is being compiled the script engine looks on the parameters passed to it and picks up a pointer for every [] found. + +eg2. + +@verbatim +imlib_apply_filter( "tint( x=[], y=[], red=255, alpha=55 );", &myxint, &myyint ); +@endverbatim + +This will cause a tint to the current image at (myxint,myyint) to be done. This is very useful for when you want the filters to dynamically change according to program variables. The system is very quick as the code is pseudo-compiled and then run. The advantage of having the scripting system allows customization of the image manipulations, this is particularly useful in applications that allow modifications to be done (eg. image viewers). + + +@subsection lib_filter Filter Library +There are three functions that must be in every filter library + +@code +void init( struct imlib_filter_info *info ); - Called once on loading of the filter +@endcode + +info - a structure passed to the filter to be filled in with information about the filter info->name - Name of the filter library +info->author - Name of the library author +info->description - Description of the filter library +info->num_filters - Number of filters the library exports +info->filters - An array of ``char *'' with each filter name in it. + +@code +void deinit(); - Called when the filter is closed + +/* Called every time a filter the library exports is called */ +void *exec( char *filter, void *im, pIFunctionParam params ); +@endcode + +filter - The name of the filter being asked for im - The image that the filter should be applied against params - A linked list of parameters. + +The best way to get all the values is such: + +Declare all parameters and initialize them to there default values. + +@code +for( ptr = params; ptr != NULL; ptr = ptr->next ) + { + ..MACRO TO GET VALUE.. + } +@endcode + +Current Macros are: + +@verbatim + ASSIGN_INT( keyname, local variable ) + ASSIGN_DATA8( keyname, local variable ) + ASSIGN_IMAGE( keyname, local variable ) +@endverbatim + +eg. + +@code +int r = 50; +IFunctionParam *ptr; + +for( ptr = params; ptr != NULL; ptr = ptr->next ) + { + ASSIGN_INT( "red", r ); + } +@endcode + +If the value "red" is not passed to the filter then it will remain at 50, but it a value is passed, it will be assign to r. + +return type - Imlib_Image, this is the result of filter. + +@todo line code doesnt draw nice liens when clipping - fix +@todo filled polygons can break fill bounds on corner cases - fix +@todo go thru TODOs and FIXMEs + +*/ \ No newline at end of file diff --git a/imlib2.pc.in b/imlib2.pc.in new file mode 100644 index 0000000..6d4e81c --- /dev/null +++ b/imlib2.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: imlib2 +Description: Powerful image loading and rendering library +Requires: @requirements@ +Version: @VERSION@ +Libs: -L${libdir} -lImlib2 +Cflags: -I${includedir} + diff --git a/imlib2.spec b/imlib2.spec new file mode 100644 index 0000000..a7a4f5d --- /dev/null +++ b/imlib2.spec @@ -0,0 +1,184 @@ +Summary: Powerful image loading and rendering library +Name: imlib2 +Version: 1.2.0 +Release: 1.%(date '+%Y%m%d') +Copyright: BSD +Group: System Environment/Libraries +Source: ftp://ftp.enlightenment.org/pub/enlightenment/e17/libs/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-root +Packager: Michael Jennings +URL: http://www.rasterman.com/raster/imlib.html +#BuildSuggests: freetype-devel xorg-x11-devel +Requires: %{name}-loader_jpeg = %{version} +Requires: %{name}-loader_png = %{version} +Requires: %{name}-loader_argb = %{version} + +%description +Imlib2 is an advanced replacement library for libraries like libXpm that +provides many more features with much greater flexibility and speed than +standard libraries, including font rasterization, rotation, RGBA space +rendering and blending, dynamic binary filters, scripting, and more. + +%package devel +Summary: Imlib2 headers, static libraries and documentation +Group: System Environment/Libraries +Requires: %{name} = %{version} +%description devel +Headers, static libraries and documentation for Imlib2. + +%package filters +Summary: Imlib2 basic plugin filters set +Group: System Environment/Libraries +Requires: %{name} = %{version} +%description filters +Basic set of plugin filters that come with Imlib2 + +%package loader_lbm +Summary: Imlib2 LBM loader +Group: System Environment/Libraries +%description loader_lbm +LBM image loader/saver for Imlib2 + +%package loader_jpeg +Summary: Imlib2 JPEG loader +Group: System Environment/Libraries +BuildRequires: libjpeg-devel +%description loader_jpeg +JPEG image loader/saver for Imlib2 + +%package loader_png +Summary: Imlib2 PNG loader +Group: System Environment/Libraries +BuildRequires: libpng-devel +BuildRequires: zlib-devel +%description loader_png +PNG image loader/saver for Imlib2 + +%package loader_argb +Summary: Imlib2 ARGB loader +Group: System Environment/Libraries +%description loader_argb +ARGB image loader/saver for Imlib2 + +%package loader_bmp +Summary: Imlib2 BMP loader +Group: System Environment/Libraries +%description loader_bmp +BMP image loader/saver for Imlib2 + +%package loader_gif +Summary: Imlib2 GIF loader +Group: System Environment/Libraries +%description loader_gif +GIF image loader for Imlib2 + +%package loader_pnm +Summary: Imlib2 PNM loader +Group: System Environment/Libraries +%description loader_pnm +PNM image loader/saver for Imlib2 + +%package loader_tga +Summary: Imlib2 TGA loader +Group: System Environment/Libraries +%description loader_tga +TGA image loader/saver for Imlib2 + +%package loader_tiff +Summary: Imlib2 TIFF loader +Group: System Environment/Libraries +BuildRequires: libtiff-devel +%description loader_tiff +TIFF image loader/saver for Imlib2 + +%package loader_xpm +Summary: Imlib2 XPM loader +Group: System Environment/Libraries +%description loader_xpm +XPM image loader/saver for Imlib2 + +%package loader_bz2 +Summary: Imlib2 .bz2 loader +Group: System Environment/Libraries +%description loader_bz2 +Bzip2 compressed image loader/saver for Imlib2 + +%package loader_gz +Summary: Imlib2 .gz loader +Group: System Environment/Libraries +%description loader_gz +gz compressed image loader/saver for Imlib2 + +%prep +%setup -q + +%build +%{configure} --prefix=%{_prefix} +%{__make} %{?_smp_mflags} %{?mflags} + +%install +%{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install + +%clean +test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files +%defattr(-, root, root) +%doc AUTHORS COPYING README ChangeLog doc/index.html doc/imlib2.gif doc/blank.gif +%{_libdir}/lib*.so.* +%{_bindir}/* + +%files devel +%defattr(-, root, root, 0755) +%{_libdir}/libImlib2.so +%{_libdir}/*.a +%{_libdir}/*.la +%{_libdir}/pkgconfig/imlib2.pc +%{_includedir}/* + +%files filters +%attr(755,root,root) %{_libdir}/imlib2/filters/*.so + +%files loader_lbm +%attr(755,root,root) %{_libdir}/imlib2/loaders/lbm.so + +%files loader_jpeg +%attr(755,root,root) %{_libdir}/imlib2/loaders/jpeg.so + +%files loader_png +%attr(755,root,root) %{_libdir}/imlib2/loaders/png.so + +%files loader_argb +%attr(755,root,root) %{_libdir}/imlib2/loaders/argb.so + +%files loader_bmp +%attr(755,root,root) %{_libdir}/imlib2/loaders/bmp.so + +%files loader_gif +%attr(755,root,root) %{_libdir}/imlib2/loaders/gif.so + +%files loader_pnm +%attr(755,root,root) %{_libdir}/imlib2/loaders/pnm.so + +%files loader_tga +%attr(755,root,root) %{_libdir}/imlib2/loaders/tga.so + +%files loader_tiff +%attr(755,root,root) %{_libdir}/imlib2/loaders/tiff.so + +%files loader_xpm +%attr(755,root,root) %{_libdir}/imlib2/loaders/xpm.so + +%files loader_bz2 +%attr(755,root,root) %{_libdir}/imlib2/loaders/bz2.so + +%files loader_gz +%attr(755,root,root) %{_libdir}/imlib2/loaders/zlib.so + +%changelog diff --git a/m4/ac_expand_dir.m4 b/m4/ac_expand_dir.m4 new file mode 100644 index 0000000..b5599a0 --- /dev/null +++ b/m4/ac_expand_dir.m4 @@ -0,0 +1,14 @@ +dnl AC_EXPAND_DIR(VARNAME, DIR) +dnl expands occurrences of ${prefix} and ${exec_prefix} in the given DIR, +dnl and assigns the resulting string to VARNAME +dnl example: AC_DEFINE_DIR(DATADIR, "$datadir") +dnl by Alexandre Oliva +AC_DEFUN([AC_EXPAND_DIR], [ + $1=$2 + $1=`( + test "x$prefix" = xNONE && prefix="$ac_default_prefix" + test "x$exec_prefix" = xNONE && exec_prefix="${prefix}" + eval echo \""[$]$1"\" + )` +]) + diff --git a/m4/ac_path_generic.m4 b/m4/ac_path_generic.m4 new file mode 100644 index 0000000..27b55b3 --- /dev/null +++ b/m4/ac_path_generic.m4 @@ -0,0 +1,136 @@ +dnl @synopsis AC_PATH_GENERIC(LIBRARY [, MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl +dnl Runs a LIBRARY-config script and defines LIBRARY_CFLAGS and LIBRARY_LIBS +dnl +dnl The script must support `--cflags' and `--libs' args. +dnl If MINIMUM-VERSION is specified, the script must also support the +dnl `--version' arg. +dnl If the `--with-library-[exec-]prefix' arguments to ./configure are given, +dnl it must also support `--prefix' and `--exec-prefix'. +dnl (In other words, it must be like gtk-config.) +dnl +dnl For example: +dnl +dnl AC_PATH_GENERIC(Foo, 1.0.0) +dnl +dnl would run `foo-config --version' and check that it is at least 1.0.0 +dnl +dnl If so, the following would then be defined: +dnl +dnl FOO_CFLAGS to `foo-config --cflags` +dnl FOO_LIBS to `foo-config --libs` +dnl +dnl At present there is no support for additional "MODULES" (see AM_PATH_GTK) +dnl (shamelessly stolen from gtk.m4 and then hacked around a fair amount) +dnl +dnl @author Angus Lees + +AC_DEFUN([AC_PATH_GENERIC], +[dnl +dnl we're going to need uppercase, lowercase and user-friendly versions of the +dnl string `LIBRARY' +pushdef([UP], translit([$1], [a-z], [A-Z]))dnl +pushdef([DOWN], translit([$1], [A-Z], [a-z]))dnl + +dnl +dnl Get the cflags and libraries from the LIBRARY-config script +dnl +AC_ARG_WITH(DOWN-prefix,[ --with-]DOWN[-prefix=PFX Prefix where $1 is installed (optional)], + DOWN[]_config_prefix="$withval", DOWN[]_config_prefix="") +AC_ARG_WITH(DOWN-exec-prefix,[ --with-]DOWN[-exec-prefix=PFX Exec prefix where $1 is installed (optional)], + DOWN[]_config_exec_prefix="$withval", DOWN[]_config_exec_prefix="") + + if test x$DOWN[]_config_exec_prefix != x ; then + DOWN[]_config_args="$DOWN[]_config_args --exec-prefix=$DOWN[]_config_exec_prefix" + if test x${UP[]_CONFIG+set} != xset ; then + UP[]_CONFIG=$DOWN[]_config_exec_prefix/bin/DOWN-config + fi + fi + if test x$DOWN[]_config_prefix != x ; then + DOWN[]_config_args="$DOWN[]_config_args --prefix=$DOWN[]_config_prefix" + if test x${UP[]_CONFIG+set} != xset ; then + UP[]_CONFIG=$DOWN[]_config_prefix/bin/DOWN-config + fi + fi + + AC_PATH_PROG(UP[]_CONFIG, DOWN-config, no) + ifelse([$2], , + AC_MSG_CHECKING(for $1), + AC_MSG_CHECKING(for $1 - version >= $2) + ) + no_[]DOWN="" + if test "$UP[]_CONFIG" = "no" ; then + no_[]DOWN=yes + else + UP[]_CFLAGS="`$UP[]_CONFIG $DOWN[]_config_args --cflags`" + UP[]_LIBS="`$UP[]_CONFIG $DOWN[]_config_args --libs`" + ifelse([$2], , ,[ + DOWN[]_config_major_version=`$UP[]_CONFIG $DOWN[]_config_args \ + --version | sed 's/[[^0-9]]*\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + DOWN[]_config_minor_version=`$UP[]_CONFIG $DOWN[]_config_args \ + --version | sed 's/[[^0-9]]*\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + DOWN[]_config_micro_version=`$UP[]_CONFIG $DOWN[]_config_args \ + --version | sed 's/[[^0-9]]*\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + DOWN[]_wanted_major_version="regexp($2, [\<\([0-9]*\)], [\1])" + DOWN[]_wanted_minor_version="regexp($2, [\<\([0-9]*\)\.\([0-9]*\)], [\2])" + DOWN[]_wanted_micro_version="regexp($2, [\<\([0-9]*\).\([0-9]*\).\([0-9]*\)], [\3])" + + # Compare wanted version to what config script returned. + # If I knew what library was being run, i'd probably also compile + # a test program at this point (which also extracted and tested + # the version in some library-specific way) + if test "$DOWN[]_config_major_version" -lt \ + "$DOWN[]_wanted_major_version" \ + -o \( "$DOWN[]_config_major_version" -eq \ + "$DOWN[]_wanted_major_version" \ + -a "$DOWN[]_config_minor_version" -lt \ + "$DOWN[]_wanted_minor_version" \) \ + -o \( "$DOWN[]_config_major_version" -eq \ + "$DOWN[]_wanted_major_version" \ + -a "$DOWN[]_config_minor_version" -eq \ + "$DOWN[]_wanted_minor_version" \ + -a "$DOWN[]_config_micro_version" -lt \ + "$DOWN[]_wanted_micro_version" \) ; then + # older version found + no_[]DOWN=yes + echo -n "*** An old version of $1 " + echo -n "($DOWN[]_config_major_version" + echo -n ".$DOWN[]_config_minor_version" + echo ".$DOWN[]_config_micro_version) was found." + echo -n "*** You need a version of $1 newer than " + echo -n "$DOWN[]_wanted_major_version" + echo -n ".$DOWN[]_wanted_minor_version" + echo ".$DOWN[]_wanted_micro_version." + echo "***" + echo "*** If you have already installed a sufficiently new version, this error" + echo "*** probably means that the wrong copy of the DOWN-config shell script is" + echo "*** being found. The easiest way to fix this is to remove the old version" + echo "*** of $1, but you can also set the UP[]_CONFIG environment to point to the" + echo "*** correct copy of DOWN-config. (In this case, you will have to" + echo "*** modify your LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf" + echo "*** so that the correct libraries are found at run-time)" + fi + ]) + fi + if test "x$no_[]DOWN" = x ; then + AC_MSG_RESULT(yes) + ifelse([$3], , :, [$3]) + else + AC_MSG_RESULT(no) + if test "$UP[]_CONFIG" = "no" ; then + echo "*** The DOWN-config script installed by $1 could not be found" + echo "*** If $1 was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the UP[]_CONFIG environment variable to the" + echo "*** full path to DOWN-config." + fi + UP[]_CFLAGS="" + UP[]_LIBS="" + ifelse([$4], , :, [$4]) + fi + AC_SUBST(UP[]_CFLAGS) + AC_SUBST(UP[]_LIBS) + + popdef([UP]) + popdef([DOWN]) +]) + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..3c913a8 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,2 @@ +MAINTAINERCLEANFILES = Makefile.in +SUBDIRS = lib bin modules diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am new file mode 100644 index 0000000..6414cf7 --- /dev/null +++ b/src/bin/Makefile.am @@ -0,0 +1,35 @@ +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = \ +-I../lib \ +-I$(top_srcdir)/src/lib \ +@my_includes@ + +if BUILD_X11 +X_BASED_PROGS = imlib2_show imlib2_test imlib2_bumpmap imlib2_poly imlib2_colorspace imlib2_view +endif + +bin_PROGRAMS = \ +imlib2_conv \ +$(X_BASED_PROGS) + +imlib2_conv_SOURCES = imlib2_conv.c +imlib2_conv_LDADD = $(top_builddir)/src/lib/libImlib2.la + +imlib2_show_SOURCES = imlib2_show.c +imlib2_show_LDADD = $(top_builddir)/src/lib/libImlib2.la + +imlib2_test_SOURCES = imlib2_test.c +imlib2_test_LDADD = $(top_builddir)/src/lib/libImlib2.la + +imlib2_bumpmap_SOURCES = imlib2_bumpmap.c +imlib2_bumpmap_LDADD = $(top_builddir)/src/lib/libImlib2.la + +imlib2_poly_SOURCES = imlib2_poly.c +imlib2_poly_LDADD = $(top_builddir)/src/lib/libImlib2.la + +imlib2_colorspace_SOURCES = imlib2_colorspace.c +imlib2_colorspace_LDADD = $(top_builddir)/src/lib/libImlib2.la + +imlib2_view_SOURCES = imlib2_view.c +imlib2_view_LDADD = $(top_builddir)/src/lib/libImlib2.la diff --git a/src/bin/imlib2_bumpmap.c b/src/bin/imlib2_bumpmap.c new file mode 100644 index 0000000..3722ed2 --- /dev/null +++ b/src/bin/imlib2_bumpmap.c @@ -0,0 +1,128 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +#include +#include "common.h" +#include "image.h" +#include "rend.h" +#include "rgba.h" +#include "ximage.h" +#include "color.h" + */ +#include "Imlib2.h" + +Display *disp; +Window win; +Visual *vis; +Colormap cm; +int depth; + +int +main(int argc, char **argv) +{ + int i, j, w, h, x, y; + Imlib_Image im = NULL, im_bg = NULL; + XEvent ev; + + /** + * Initialization according to options + */ + printf("Initialising\n"); + + /** + * First tests to determine which rendering task to perform + */ + disp = XOpenDisplay(NULL); + vis = DefaultVisual(disp, DefaultScreen(disp)); + depth = DefaultDepth(disp, DefaultScreen(disp)); + cm = DefaultColormap(disp, DefaultScreen(disp)); + win = + XCreateSimpleWindow(disp, DefaultRootWindow(disp), 0, 0, 100, 100, 0, 0, + 0); + XSelectInput(disp, win, + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | + PointerMotionMask | ExposureMask); + XMapWindow(disp, win); + + /** + * Start rendering + */ + printf("Rendering\n"); + imlib_context_set_display(disp); + imlib_context_set_visual(vis); + imlib_context_set_colormap(cm); + imlib_context_set_drawable(win); + imlib_context_set_dither(1); + imlib_context_set_blend(0); + imlib_context_set_color_modifier(NULL); + + im_bg = imlib_load_image(PACKAGE_DATA_DIR"/data/images/imlib2.png"); + im = imlib_load_image(PACKAGE_DATA_DIR"/data/images/imlib2.png"); + + imlib_context_set_image(im_bg); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + printf("Resizing Window to %d by %d\n", w, h); + XResizeWindow(disp, win, w, h); + XSync(disp, False); + x = -9999; + y = -9999; + while (1) + { + Imlib_Image *temp, *temp2; + + do + { + XNextEvent(disp, &ev); + switch (ev.type) + { + case Expose: + break; + case ButtonRelease: + exit(0); + break; + case MotionNotify: + x = ev.xmotion.x; + y = ev.xmotion.y; + default: + break; + + } + } + while (XPending(disp)); + + imlib_context_set_blend(0); + imlib_context_set_image(im_bg); + temp = imlib_clone_image(); + imlib_context_set_image(temp); + + /* imlib_blend_image_onto_image(im_bg, 0, + * 0, 0, w, h, + * 0, 0, w, h); + * first = 0; */ + + imlib_apply_filter + ("bump_map_point(x=[],y=[],map="PACKAGE_DATA_DIR"/data/images/imlib2.png);", &x, &y); + + temp2 = im_bg; + im_bg = temp; + imlib_context_set_image(im_bg); + imlib_render_image_on_drawable(0, 0); + im_bg = temp2; + imlib_context_set_image(temp); + imlib_free_image(); + } + + return 0; +} diff --git a/src/bin/imlib2_colorspace.c b/src/bin/imlib2_colorspace.c new file mode 100644 index 0000000..44bc3fa --- /dev/null +++ b/src/bin/imlib2_colorspace.c @@ -0,0 +1,143 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Imlib2.h" + +Display *disp; +Window win; +Visual *vis; +Colormap cm; +int depth; + +int +main(int argc, char **argv) +{ + int w, h, tw, th; + Imlib_Image im_bg = NULL; + XEvent ev; + KeySym keysym; + static char kbuf[20]; + Imlib_Font font; + Imlib_Color_Range range; + + /** + * First tests to determine which rendering task to perform + */ + disp = XOpenDisplay(NULL); + vis = DefaultVisual(disp, DefaultScreen(disp)); + depth = DefaultDepth(disp, DefaultScreen(disp)); + cm = DefaultColormap(disp, DefaultScreen(disp)); + win = + XCreateSimpleWindow(disp, DefaultRootWindow(disp), 0, 0, 100, 100, 0, 0, + 0); + XSelectInput(disp, win, + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | + PointerMotionMask | ExposureMask | KeyPressMask); + XMapWindow(disp, win); + + /** + * Start rendering + */ + imlib_set_font_cache_size(512 * 1024); + imlib_add_path_to_font_path(PACKAGE_DATA_DIR"/data/fonts"); + imlib_context_set_display(disp); + imlib_context_set_visual(vis); + imlib_context_set_colormap(cm); + imlib_context_set_drawable(win); + imlib_context_set_blend(0); + imlib_context_set_color_modifier(NULL); + imlib_context_set_blend(0); + + im_bg = imlib_create_image(600, 400); + imlib_context_set_image(im_bg); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + imlib_context_set_color(128, 128, 255, 255); + imlib_image_fill_rectangle(0, 0, w, h); + XResizeWindow(disp, win, w, h); + XSync(disp, False); + + while (1) + { + do + { + XNextEvent(disp, &ev); + switch (ev.type) + { + case ButtonRelease: + exit(0); + break; + case KeyPress: + XLookupString(&ev.xkey, (char *)kbuf, sizeof(kbuf), &keysym, + NULL); + switch (*kbuf) + { + case 'q': + exit(0); + default: + break; + } + break; + default: + break; + + } + } + while (XPending(disp)); + + imlib_context_set_image(im_bg); + imlib_context_set_color(128, 128, 255, 255); + imlib_image_fill_rectangle(0, 0, w, h); + imlib_context_set_color(0, 0, 0, 255); + imlib_image_draw_rectangle(20, 20, 560, 140); + imlib_image_draw_rectangle(20, 220, 560, 140); + font = imlib_load_font("notepad/15"); + if (font) + { + char text[4096]; + + imlib_context_set_font(font); + imlib_context_set_color(0, 0, 0, 255); + sprintf(text, "RGBA range, 2 points, from red to magenta"); + imlib_get_text_size(text, &tw, &th); + imlib_text_draw(300 - tw / 2, 180 - th / 2, text); + sprintf(text, "HSVA range, 2 points, from red to magenta"); + imlib_get_text_size(text, &tw, &th); + imlib_text_draw(300 - tw / 2, 380 - th / 2, text); + imlib_free_font(); + } + + /* Draw rectangle w/ RGBA gradient */ + range = imlib_create_color_range(); + imlib_context_set_color_range(range); + imlib_context_set_color(255, 0, 0, 255); + imlib_add_color_to_color_range(0); + imlib_context_set_color(255, 0, 255, 255); + imlib_add_color_to_color_range(20); + imlib_image_fill_color_range_rectangle(21, 21, 558, 138, -90.0); + imlib_free_color_range(); + + /* Draw rectangle w/ HSVA gradient */ + range = imlib_create_color_range(); + imlib_context_set_color_range(range); + imlib_context_set_color_hsva(0, 1, 1, 255); + imlib_add_color_to_color_range(0); + imlib_context_set_color_hsva(300, 1, 1, 255); + imlib_add_color_to_color_range(20); + imlib_image_fill_hsva_color_range_rectangle(21, 221, 558, 138, -90.0); + imlib_free_color_range(); + + imlib_render_image_on_drawable(0, 0); + } + return 0; +} diff --git a/src/bin/imlib2_conv.c b/src/bin/imlib2_conv.c new file mode 100644 index 0000000..8aa6083 --- /dev/null +++ b/src/bin/imlib2_conv.c @@ -0,0 +1,92 @@ +#include "config.h" +/* Convert images between formats, using Imlib2's API. Smart enough to know + * about edb files; defaults to jpg's. + */ + +#include +#include +#include +#include + +#define X_DISPLAY_MISSING +#include + +#define PROG_NAME "imconvert" + +static void usage(int exit_status); + +int +main(int argc, char **argv) +{ + char *dot, *colon, *n, *oldn; + Imlib_Image im; + + /* I'm just plain being lazy here.. get our basename. */ + for (oldn = n = argv[0]; n; oldn = n) + n = strchr(++oldn, '/'); + if (argc < 3 || !strcmp(argv[1], "-h")) + usage(-1); + if ((im = imlib_load_image(argv[1])) == NULL) + { + fprintf(stderr, PROG_NAME ": Error loading image: %s\n", argv[1]); + exit(-1); + } + + /* we only care what format the export format is. */ + imlib_context_set_image(im); + /* hopefully the last one will be the one we want.. */ + dot = strrchr(argv[2], '.'); + /* if there's a format, snarf it and set the format. */ + if (dot && *(dot + 1)) + { + colon = strrchr(++dot, ':'); + /* if a db file with a key, export it to a db. */ + if (colon && *(colon + 1)) + { + *colon = 0; + /* beats having to look for strcasecmp() */ + if (!strncmp(dot, "db", 2) || !strncmp(dot, "dB", 2) || + !strncmp(dot, "DB", 2) || !strncmp(dot, "Db", 2)) + { + imlib_image_set_format("db"); + } + *colon = ':'; + } + else + { + char *p, *q; + + /* max length of 8 for format name. seems reasonable. */ + q = p = malloc(8); + memset(p, 0, 8); + strncpy(p, dot, (strlen(dot) < 9) ? strlen(dot) : 8); + /* Imlib2 only recognizes lowercase formats. convert it. */ + for (q[8] = 0; *q; q++) + *q = tolower(*q); + imlib_image_set_format(p); + free(p); + } + dot--; + } + else + imlib_image_set_format("jpg"); + + imlib_save_image(argv[2]); + + return 0; +} + +static void +usage(int exit_status) +{ + fprintf(exit_status ? stderr : stdout, + PROG_NAME ": Convert images between formats (part of the " + "Imlib2 package)\n\n" + "Usage: " PROG_NAME " [ -h | ]\n" + " defaults to jpg if not provided; images in " + "edb files are supported via\n" + " the file.db:/key/name convention.\n" + " -h shows this help.\n\n"); + + exit(exit_status); +} diff --git a/src/bin/imlib2_poly.c b/src/bin/imlib2_poly.c new file mode 100644 index 0000000..a684761 --- /dev/null +++ b/src/bin/imlib2_poly.c @@ -0,0 +1,127 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Imlib2.h" + +Display *disp; +Window win; +Visual *vis; +Colormap cm; +int depth; + +int +main(int argc, char **argv) +{ + int w, h; + Imlib_Image im_bg = NULL; + XEvent ev; + KeySym keysym; + static char kbuf[20]; + ImlibPolygon poly, poly1, poly2; + + /** + * First tests to determine which rendering task to perform + */ + disp = XOpenDisplay(NULL); + vis = DefaultVisual(disp, DefaultScreen(disp)); + depth = DefaultDepth(disp, DefaultScreen(disp)); + cm = DefaultColormap(disp, DefaultScreen(disp)); + win = + XCreateSimpleWindow(disp, DefaultRootWindow(disp), 0, 0, 100, 100, 0, 0, + 0); + XSelectInput(disp, win, + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | + PointerMotionMask | ExposureMask | KeyPressMask); + XMapWindow(disp, win); + + /** + * Start rendering + */ + imlib_context_set_display(disp); + imlib_context_set_visual(vis); + imlib_context_set_colormap(cm); + imlib_context_set_drawable(win); + imlib_context_set_blend(0); + imlib_context_set_color_modifier(NULL); + imlib_context_set_blend(0); + + im_bg = imlib_create_image(400, 400); + imlib_context_set_image(im_bg); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + imlib_context_set_color(0, 0, 0, 255); + imlib_image_fill_rectangle(0, 0, w, h); + XResizeWindow(disp, win, w, h); + XSync(disp, False); + + poly = imlib_polygon_new(); + imlib_polygon_add_point(poly, 20, 20); + imlib_polygon_add_point(poly, 70, 20); + imlib_polygon_add_point(poly, 70, 70); + imlib_polygon_add_point(poly, 20, 70); + + poly1 = imlib_polygon_new(); + imlib_polygon_add_point(poly1, 100, 20); + imlib_polygon_add_point(poly1, 190, 100); + imlib_polygon_add_point(poly1, 120, 70); + + poly2 = imlib_polygon_new(); + imlib_polygon_add_point(poly2, 290, 20); + imlib_polygon_add_point(poly2, 200, 100); + imlib_polygon_add_point(poly2, 270, 70); + + while (1) + { + do + { + XNextEvent(disp, &ev); + switch (ev.type) + { + case ButtonRelease: + exit(0); + break; + case KeyPress: + XLookupString(&ev.xkey, (char *)kbuf, sizeof(kbuf), &keysym, + NULL); + switch (*kbuf) + { + case ' ': + imlib_context_set_anti_alias + (!imlib_context_get_anti_alias()); + printf("AA is %s\n", + imlib_context_get_anti_alias()? "on" : "off"); + break; + case 'q': + exit(0); + default: + break; + } + break; + default: + break; + + } + } + while (XPending(disp)); + + imlib_context_set_image(im_bg); + imlib_context_set_color(0, 0, 0, 255); + imlib_image_fill_rectangle(0, 0, w, h); + imlib_context_set_color(255, 255, 255, 255); + imlib_image_fill_polygon(poly); + imlib_image_fill_polygon(poly1); + imlib_image_fill_polygon(poly2); + imlib_render_image_on_drawable(0, 0); + } + return 0; +} diff --git a/src/bin/imlib2_show.c b/src/bin/imlib2_show.c new file mode 100644 index 0000000..6318bb0 --- /dev/null +++ b/src/bin/imlib2_show.c @@ -0,0 +1,1378 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +#include +#include "common.h" +#include "image.h" +#include "rend.h" +#include "rgba.h" +#include "ximage.h" +#include "color.h" + */ +#include "Imlib2.h" + +Display *disp; +Window win; +Visual *vis; +Colormap cm; +int depth; + +void progress(Imlib_Image * im, char percent, int update_x, + int update_y, int update_w, int update_h); + +void +progress(Imlib_Image * im, char percent, + int update_x, int update_y, int update_w, int update_h) +{ + imlib_context_set_display(disp); + imlib_context_set_visual(vis); + imlib_context_set_colormap(cm); + imlib_context_set_drawable(win); + imlib_context_set_dither(0); + imlib_context_set_blend(0); + imlib_context_set_color_modifier(NULL); + imlib_context_set_operation(IMLIB_OP_COPY); + imlib_context_set_image(im); + imlib_render_image_part_on_drawable_at_size(update_x, update_y, + update_w, update_h, + update_x, update_y, + update_w, update_h); +} + +int +main(int argc, char **argv) +{ + int i, j; + Imlib_Image *im = NULL; + int sec1, usec1, sec2, usec2; + int pixels = 0; + struct timeval timev; + double sec; + char *file = NULL; + char *fon = NULL, *str = NULL; + + int root = 0; + int scale = 0; + int w = 20; + int h = 20; + int aa = 0; + int dith = 0; + int loop = 0; + int blend = 1; + int interactive = 1; + int blendtest = 0; + int filter = 0; + int pol = 0; + int rotate = 0; + int rottest = 0; + int scaleup = 0; + int scaleboth = 0; + int origone = 0; + int bump_map_to_point = 0; + Imlib_Color_Modifier colormod = 0; + ImlibPolygon poly, poly2, poly3; + int textdir = IMLIB_TEXT_TO_RIGHT; + int xfdtest = 0; + int xfdcachetest = 0; + char *xfdfname = NULL; + int xfdloop = 1; + + /* now we'll set the locale */ + setlocale(LC_ALL, ""); + if (!XSupportsLocale()) + setlocale(LC_ALL, "C"); + XSetLocaleModifiers(""); + setlocale(LC_ALL, NULL); + + /** + * Parse all the command line arguments + */ + if ((argc > 1) && (!strcmp(argv[1], "-help"))) + { + printf("Imlib2 program test. (Imlib v2.0.0.4)\n"); + printf("usage: imlib2 [options] [file]\n"); + printf("options are:\n"); + printf("-help\t\tDisplays this help.\n"); + printf("-root\t\tDraw in the root window.\n"); + printf("-smooth\t\tWhen scaling images scale with anti-aliasing.\n"); + printf("-up\t\tWhen doing scal test scale up, not down.\n"); + printf("-both\t\tScale horizontally AND vertically in scale test.\n"); + printf + ("-orig\t\tKeep original width and height in each pass of scale test.\n"); + printf("-blend\t\tBlending test.\n"); + printf("-dither\t\tTurn dithering on for depths < 24bpp\n"); + printf("-colormod \t\tSet up color mod tables\n"); + printf("-scale\t\tScale test.\n"); + printf("-noloop\t\tDont loop - timing test.\n"); + printf + ("-rotate\t\tAlso rotate background image with mouse in interative test.\n"); + printf("-size \t\tScale from w x h down in scaling test.\n"); // require parameters w / h + printf("-maxcolors \t\tLimit color allocation count to n colors.\n"); // require parameter nb colors + printf + ("-text\t\tDisplays the text following this option. Need a loaded font.\n"); + printf + ("-font\t\tLoads a font. The parameter must follow the police_name/size format. Example: loading the grunge font at size 18 is : grunge/18.\n\t\tThe XFD font also can be specified. Ex. 'notepad/32,-*--24-*'.\n"); + printf("-poly\t\tPerforms a poly test\n"); + printf("The following options requires a file to work properly.\n"); + printf("-textdir\t\tText Direction. 0: L to R, 1: R to L\n"); + printf(" 2: U to D, 3: D to U, 4: angle\n"); + printf("-xfdtest\t\tXFD Font queue test.\n"); + printf + ("-xfdcachetest []\t\tXFD tFont cache test.\n\t\tThe file f is drawn l times\n"); + printf("-blast\t\tDisplays the file.\n"); + printf("-loop\t\tScales down the image.\n"); + printf("-blendtest\tPerforms a blending test on the file.\n"); + printf("-rotatetest\tPerforms a rotate test on the file.\n"); + printf + ("-filter\t\tPerforms filtering. Possible filters are,\n\t\t\t1:Blur filter, 2:Sharpen filter, 3:Color blur filter, \n\t\t\t4:Emboss filter, 5:Grayscale filter, 6:Saturation filter,\n\t\t\t7:Edge detection filter.\n"); + printf("-bmp2pt\t\tPerformas Bump Mapping to a point\n"); + return 0; + } + + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-root")) + root = 1; + else if (!strcmp(argv[i], "-smooth")) + aa = 1; + else if (!strcmp(argv[i], "-blast")) + interactive = 0; + else if (!strcmp(argv[i], "-loop")) + { + interactive = 0; + loop = 1; + } + else if (!strcmp(argv[i], "-up")) + scaleup = 1; + else if (!strcmp(argv[i], "-both")) + scaleboth = 1; + else if (!strcmp(argv[i], "-bmp2pt")) + bump_map_to_point = 1; + else if (!strcmp(argv[i], "-orig")) + origone = 1; + else if (!strcmp(argv[i], "-blend")) + blend = 1; + else if (!strcmp(argv[i], "-poly")) + pol = 1; + else if (!strcmp(argv[i], "-blendtest")) + { + blendtest = 1; + interactive = 0; + } + else if (!strcmp(argv[i], "-colormod")) + { + DATA8 rt[256], gt[256], bt[256], at[256]; + double rm, gm, bm, am; + int j; + + /*\ Setup color mod tables \ */ + if (!colormod) + colormod = imlib_create_color_modifier(); + imlib_context_set_color_modifier(colormod); + rm = strtod(argv[++i], 0); + gm = strtod(argv[++i], 0); + bm = strtod(argv[++i], 0); + am = strtod(argv[++i], 0); + imlib_get_color_modifier_tables(rt, gt, bt, at); + for (j = 0x100; --j >= 0;) + { + rt[j] = ((double)rt[j]) * rm; + gt[j] = ((double)gt[j]) * gm; + bt[j] = ((double)bt[j]) * bm; + at[j] = ((double)at[j]) * am; + } + imlib_set_color_modifier_tables(rt, gt, bt, at); + } + else if (!strcmp(argv[i], "-dither")) + dith = 1; + else if (!strcmp(argv[i], "-scale")) + scale = 1; + else if (!strcmp(argv[i], "-noloop")) + loop = 0; + else if (!strcmp(argv[i], "-size")) + { + i++; + w = atoi(argv[i++]); + h = atoi(argv[i]); + } + else if (!strcmp(argv[i], "-maxcolors")) + { + i++; + imlib_set_color_usage(atoi(argv[i])); + } + else if (!strcmp(argv[i], "-font")) + { + i++; + fon = argv[i]; + } + else if (!strcmp(argv[i], "-text")) + { + i++; + str = argv[i]; + } + else if (!strcmp(argv[i], "-xfdtest")) + xfdtest = 1; + else if (!strcmp(argv[i], "-xfdcachetest")) + { + xfdcachetest = 1; + i++; + xfdfname = argv[i]; + i++; + if (i < argc) + xfdloop = atoi(argv[i]); + } + else if (!strcmp(argv[i], "-textdir")) + { + i++; + textdir = atoi(argv[i]); + } + else if (!strcmp(argv[i], "-rotate")) + rotate = 1; + else if (!strcmp(argv[i], "-filter")) + { + filter = atoi(argv[++i]); + interactive = 0; + } + else if (!strcmp(argv[i], "-rotatetest")) + { + rottest = 1; + interactive = 0; + } + else + file = argv[i]; + } + + /** + * Initialization according to options + */ + printf("init\n"); + + /** + * First tests to determine which rendering task to perform + */ + if (!blendtest) + { + disp = XOpenDisplay(NULL); + vis = DefaultVisual(disp, DefaultScreen(disp)); + depth = DefaultDepth(disp, DefaultScreen(disp)); + cm = DefaultColormap(disp, DefaultScreen(disp)); + /* nasty - using imlib internal function.. but it makes benchmarks fair */ + if (!interactive) + __imlib_SetMaxXImageCount(disp, 3); + if (root) + win = DefaultRootWindow(disp); + else + { + win = + XCreateSimpleWindow(disp, DefaultRootWindow(disp), 0, 0, 10, + 10, 0, 0, 0); + XSelectInput(disp, win, + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask + | PointerMotionMask | ExposureMask); + } + } + + if (!interactive) + { + printf("load %s\n", file); + im = imlib_load_image_immediately(file); + if (!im) + { + printf("load failed\n"); + exit(0); + } + imlib_context_set_image(im); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + printf("image %i x %i\n", w, h); + } + + if (!blendtest) + { + if (!root) + { + if (scaleup) + XResizeWindow(disp, win, w * 4, h * 4); + else if (scaleboth) + XResizeWindow(disp, win, w * 2, h * 2); + else + XResizeWindow(disp, win, w, h); + XMapWindow(disp, win); + } + if (scale) + { + Window d; + int dd; + + XGetGeometry(disp, win, &d, &dd, &dd, &dd, &dd, &dd, &dd); + } + XSync(disp, False); + } + + /** + * Start rendering + */ + printf("rend\n"); + + if (!blendtest) + { + imlib_context_set_display(disp); + imlib_context_set_visual(vis); + imlib_context_set_colormap(cm); + imlib_context_set_drawable(win); + } + imlib_context_set_anti_alias(aa); + imlib_context_set_dither(dith); + imlib_context_set_blend(blend); + imlib_context_set_color_modifier(NULL); + imlib_context_set_operation(IMLIB_OP_COPY); + imlib_context_set_image(im); + + gettimeofday(&timev, NULL); + sec1 = (int)timev.tv_sec; /* and stores it so we can time outselves */ + usec1 = (int)timev.tv_usec; /* we will use this to vary speed of rot */ + + poly = imlib_polygon_new(); + imlib_polygon_add_point(poly, 400, 50); + imlib_polygon_add_point(poly, 450, 100); + imlib_polygon_add_point(poly, 350, 100); + + poly2 = imlib_polygon_new(); + imlib_polygon_add_point(poly2, 400, 150); + imlib_polygon_add_point(poly2, 450, 200); + imlib_polygon_add_point(poly2, 350, 200); + + poly3 = imlib_polygon_new(); + imlib_polygon_add_point(poly3, 400, 250); + imlib_polygon_add_point(poly3, 450, 300); + imlib_polygon_add_point(poly3, 350, 300); + +#define A90 (3.141592654 / 2) + if (pol) + { + Imlib_Image im_bg, im; + int w, h; + int i; + double a, points[8][2]; + + if (file) + im_bg = imlib_load_image(file); + else + im_bg = imlib_load_image(PACKAGE_DATA_DIR"/data/images/bg.png"); + imlib_context_set_image(im_bg); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + XResizeWindow(disp, win, w, h); + XSync(disp, False); + im = imlib_create_image(w, h); + srand(time(NULL)); + for (i = 0; i < 8; i++) + { + points[i][0] = (rand() % w) - (w / 2); + points[i][1] = (rand() % h) - (h / 2); + } + a = 0.0; + for (;;) + { + imlib_context_set_image(im); + imlib_blend_image_onto_image(im_bg, 0, 0, 0, w, h, 0, 0, w, h); + + poly = imlib_polygon_new(); + for (i = 0; i < 8; i++) + { + double xx, yy; + + xx = (w / 2) + + (cos(a) * points[i][0]) + (cos(a + A90) * points[i][1]); + yy = (h / 2) + + (sin(a) * points[i][0]) + (sin(a + A90) * points[i][1]); + imlib_polygon_add_point(poly, xx, yy); + } + printf("draw angle %3.3f\n", a); + imlib_context_set_color(255, 255, 255, 100); + imlib_image_fill_polygon(poly); + imlib_context_set_color(0, 0, 0, 20); + imlib_image_draw_polygon(poly, 1); + imlib_polygon_free(poly); + + imlib_render_image_on_drawable(0, 0); + a += 0.05; + } + } + + if (loop) + { + printf("loop\n"); + + // first test + if (scaleup) + { + printf("scale up\n"); + for (i = 0; i < w * 3; i += 8) + { + if (!blendtest) + { + Imlib_Image im_tmp; + + im_tmp = imlib_create_cropped_scaled_image(0, 0, w, h, + w + i, + (((w + + i) * h) / + w)); + if (im_tmp) + { + imlib_context_set_image(im_tmp); + imlib_render_image_on_drawable(0, 0); + imlib_free_image(); + } + imlib_context_set_image(im); + } + else + { + Imlib_Image im_tmp; + + im_tmp = imlib_create_cropped_scaled_image(0, 0, w, h, + w + i, + (((w + + i) * h) / + w)); + if (im_tmp) + { + imlib_context_set_image(im_tmp); + imlib_free_image(); + } + imlib_context_set_image(im); + } + pixels += (w + i) * (((w + i) * h) / w); + } + } + + // else if // second + else if (scaleboth) + { + if (origone) + { + for (i = 0; i < w * 2; i += 4) + { + if (!blendtest) + { + Imlib_Image im_tmp; + + im_tmp = + imlib_create_cropped_scaled_image(0, 0, w, h, w, + (((i) * h) / + w)); + if (im_tmp) + { + imlib_context_set_image(im_tmp); + imlib_render_image_on_drawable(0, 0); + imlib_free_image(); + } + imlib_context_set_image(im); + } + else + { + Imlib_Image im_tmp; + + im_tmp = + imlib_create_cropped_scaled_image(0, 0, w, h, w, + (((i) * h) / + w)); + if (im_tmp) + { + imlib_context_set_image(im_tmp); + imlib_free_image(); + } + imlib_context_set_image(im); + } + XSync(disp, False); + pixels += (2 * w - i) * (((i) * h) / w); + } + for (i = 0; i < w * 2; i += 4) + { + if (!blendtest) + imlib_render_image_on_drawable_at_size(0, 0, + 2 * w - i, h); + else + { + Imlib_Image im_tmp; + + im_tmp = + imlib_create_cropped_scaled_image(0, 0, w, h, + 2 * w - i, h); + if (im_tmp) + { + imlib_context_set_image(im_tmp); + imlib_free_image(); + } + imlib_context_set_image(im); + } + pixels += (2 * w - i) * h; + } + } + else + { + for (i = 0; i < w * 2; i += 4) + { + if (!blendtest) + imlib_render_image_on_drawable_at_size(0, 0, + 2 * w - i, + (((i) * h) / + w)); + else + { + Imlib_Image im_tmp; + + im_tmp = + imlib_create_cropped_scaled_image(0, 0, w, h, + 2 * w - i, + (((i) * h) / + w)); + if (im_tmp) + { + imlib_context_set_image(im_tmp); + imlib_free_image(); + } + imlib_context_set_image(im); + } + pixels += w * (((i) * h) / w); + } + } + } + else + { + printf("scale down 0 -> %i incriment by 1\n", w); + for (i = 0; i < w; i++) + { + if (!blendtest) + imlib_render_image_on_drawable_at_size(0, 0, + w - i, + (((w - + i) * h) / w)); + else + { + Imlib_Image im_tmp; + + im_tmp = imlib_create_cropped_scaled_image(0, 0, w, h, + w - i, + (((w - + i) * h) / + w)); + if (im_tmp) + { + imlib_context_set_image(im_tmp); + imlib_free_image(); + } + imlib_context_set_image(im); + } + pixels += (w + i) * (((w + i) * h) / w); + } + } + } + + // last test + /* else if (scaleboth) + * { + * for (i = 0; i < w * 2; i+= 1) + * { + * if (!blendtest) + * imlib_render_image_on_drawable_at_size(0, 0, + * 2 * w - i, (((i) * h) / w)); + * else + * { + * Imlib_Image im_tmp; + * im_tmp = imlib_create_cropped_scaled_image(0, 0, w, h, + * 2 * w - i, (((i) * h) / w)); + * if (im_tmp) + * { + * imlib_context_set_image(im_tmp); + * imlib_free_image(); + * } + * imlib_context_set_image(im); + * } + * pixels += (2 * w - i) * (((i) * h) / w); + * } + * } + * } */// end if loop + else if (blendtest) + { + Imlib_Image im2; + + im2 = imlib_create_image(w, h); + imlib_context_set_image(im2); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + imlib_context_set_image(im2); + imlib_context_set_color_modifier(colormod); + for (i = 0; i < 256; i++) + { + imlib_blend_image_onto_image(im, 0, 0, 0, w, h, 0, 0, w, h); + pixels += (w * h); + } + } + else if (rottest) + { + int w, h; + double i; + + imlib_context_set_image(im); + imlib_render_image_on_drawable(0, 0); + + w = imlib_image_get_width(); + h = imlib_image_get_height(); + printf("rotating inside %dx%d frame\n", w, h); + + imlib_context_set_blend(1); + imlib_context_set_image(imlib_create_image(w, h)); + for (i = 0; i < 1; i += 0.01) + { + imlib_blend_image_onto_image(im, 0, 0, 0, w, h, 0, 0, w, h); + imlib_context_set_color_modifier(colormod); + imlib_blend_image_onto_image_at_angle(im, 0, 0, 0, w, h, + 0, h * i, + w * (1 - i), -(h * i)); + imlib_context_set_color_modifier(NULL); + imlib_render_image_on_drawable(0, 0); + pixels += w * h; + } + for (i = 0; i < 1; i += 0.01) + { + imlib_blend_image_onto_image(im, 0, 0, 0, w, h, 0, 0, w, h); + imlib_context_set_color_modifier(colormod); + imlib_context_set_operation(IMLIB_OP_ADD); + imlib_blend_image_onto_image_at_angle(im, 0, 0, 0, w, h, + w * i, h, + -(w * i), h * (i - 1)); + imlib_context_set_operation(IMLIB_OP_COPY); + imlib_context_set_color_modifier(NULL); + imlib_render_image_on_drawable(0, 0); + pixels += w * h; + } + for (i = 0; i < 1; i += 0.01) + { + imlib_blend_image_onto_image(im, 0, 0, 0, w, h, 0, 0, w, h); + imlib_context_set_color_modifier(colormod); + imlib_context_set_operation(IMLIB_OP_SUBTRACT); + imlib_blend_image_onto_image_at_angle(im, 0, 0, 0, w, h, + w, h * (1 - i), + w * (i - 1), h * i); + imlib_context_set_operation(IMLIB_OP_COPY); + imlib_context_set_color_modifier(NULL); + imlib_render_image_on_drawable(0, 0); + pixels += w * h; + } + for (i = 0; i < 1; i += 0.01) + { + imlib_blend_image_onto_image(im, 0, 0, 0, w, h, 0, 0, w, h); + imlib_context_set_color_modifier(colormod); + imlib_context_set_operation(IMLIB_OP_RESHADE); + imlib_blend_image_onto_image_at_angle(im, 0, 0, 0, w, h, + w * (1 - i), 0, + w * i, h * (1 - i)); + imlib_context_set_operation(IMLIB_OP_COPY); + imlib_context_set_color_modifier(NULL); + imlib_render_image_on_drawable(0, 0); + pixels += w * h; + } + imlib_free_image(); + } + else if (filter) + { + imlib_context_set_filter(imlib_create_filter(0)); + switch (filter) + { + default: + case 1: + /*\ Blur filter \ */ + imlib_filter_set(0, 0, 0, 8, 8, 8); + imlib_filter_set(-1, 0, 0, 4, 4, 4); + imlib_filter_set(0, -1, 0, 4, 4, 4); + imlib_filter_set(1, 0, 0, 4, 4, 4); + imlib_filter_set(0, 1, 0, 4, 4, 4); + imlib_filter_set(-2, 0, 0, 1, 1, 1); + imlib_filter_set(0, -2, 0, 1, 1, 1); + imlib_filter_set(2, 0, 0, 1, 1, 1); + imlib_filter_set(0, 2, 0, 1, 1, 1); + imlib_filter_set(-1, -1, 0, 1, 1, 1); + imlib_filter_set(-1, 1, 0, 1, 1, 1); + imlib_filter_set(1, -1, 0, 1, 1, 1); + imlib_filter_set(1, 1, 0, 1, 1, 1); + break; + case 2: + /*\ Sharpen filter \ */ + imlib_filter_set(0, 0, 0, 5, 5, 5); + imlib_filter_set(-1, 0, 0, -1, -1, -1); + imlib_filter_set(0, -1, 0, -1, -1, -1); + imlib_filter_set(1, 0, 0, -1, -1, -1); + imlib_filter_set(0, 1, 0, -1, -1, -1); + break; + case 3: + /*\ Color blur filter \ */ + imlib_filter_set(0, 0, 0, 3, 3, 3); + imlib_filter_set(-1, -1, 0, 1, 0, 0); + imlib_filter_set(1, -1, 0, 0, 1, 0); + imlib_filter_set(0, 1, 0, 0, 0, 1); + break; + case 4: + /*\ Emboss filter \ */ + imlib_filter_set_red(-1, -1, 0, -1, -1, -1); + imlib_filter_set_red(0, 0, 0, 1, 1, 1); + imlib_filter_set_green(-1, -1, 0, -1, -1, -1); + imlib_filter_set_green(0, 0, 0, 1, 1, 1); + imlib_filter_set_blue(-1, -1, 0, -1, -1, -1); + imlib_filter_set_blue(0, 0, 0, 1, 1, 1); + + imlib_filter_constants(0, 768, 768, 768); + imlib_filter_divisors(0, 6, 6, 6); + break; + case 5: + /*\ Grayscale filter \ */ + imlib_filter_set_red(0, 0, 0, 80, 1, 1); + imlib_filter_set_green(0, 0, 0, 1, 80, 1); + imlib_filter_set_blue(0, 0, 0, 1, 1, 80); + break; + case 6: + /*\ Saturation filter \ */ + imlib_filter_set_red(0, 0, 0, 80, -1, -1); + imlib_filter_set_green(0, 0, 0, -1, 80, -1); + imlib_filter_set_blue(0, 0, 0, -1, -1, 80); + break; + case 7: + /*\ Edge detection filter \ */ + imlib_filter_set(-1, -1, 0, -1, -1, -1); + imlib_filter_set(-1, 0, 0, -3, -3, -3); + imlib_filter_set(-1, 1, 0, -1, -1, -1); + imlib_filter_set(0, -1, 0, -3, -3, -3); + imlib_filter_set(0, 0, 0, 16, 16, 16); + imlib_filter_set(0, 1, 0, -3, -3, -3); + imlib_filter_set(1, -1, 0, -1, -1, -1); + imlib_filter_set(1, 0, 0, -3, -3, -3); + imlib_filter_set(1, 1, 0, -1, -1, -1); + imlib_filter_divisors(0, 3, 3, 3); + } + pixels = 0; + imlib_render_image_on_drawable_at_size(0, 0, w, h); + for (i = 0; i < w; i++) + { + imlib_image_filter(); + imlib_render_image_on_drawable_at_size(0, 0, w, h); + pixels += w * h; + } + imlib_free_filter(); + } + else if (interactive) + { + int wo, ho, px, py, first = 1; + Imlib_Image im_bg, im_sh1, im_sh2, im_sh3, im_ic[13], im_tmp; + + /* Imlib_Border border; */ + Imlib_Updates up = NULL; + int x, y, i, j; + XEvent ev; + Imlib_Font fn = NULL; + struct font_hdr { + int type; + struct font_hdr *next; + char *name; + int ref; + XFontSet xfontset; + int font_count; + XFontStruct **font_struct; + char **font_name; + int ascent; + int descent; + int max_ascent; + int max_descent; + int max_width; + struct font_hdr *ttf; + } *f, *f1, *f2, *f3, *f4; + + /* "ARIAL/30" "COMIC/30" "IMPACT/30" "Prole/30" "Proteron/30" */ + /* "TIMES/30" "badacid/30" "bajoran/30" "bigfish/30" */ + imlib_add_path_to_font_path(PACKAGE_DATA_DIR"/data/fonts"); + + if (xfdtest) + { + printf("Font Cache test start\n"); + + f = imlib_load_font("notepad/10"); + printf("imlib_load_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f, f->next, f->type, f->ref, f->name); + imlib_context_set_font((Imlib_Font) f); + printf + ("\t\t ascent=%d, descent=%d, max_ascent=%d, max_descent=%d\n", + imlib_get_font_ascent(), imlib_get_font_descent(), + imlib_get_maximum_font_ascent(), + imlib_get_maximum_font_descent()); + imlib_free_font(); + printf("imlib_free_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f, f->next, f->type, f->ref, f->name); + printf("\n"); + + f = imlib_load_font("-*-fixed-*--14-*"); + printf("imlib_load_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f, f->next, f->type, f->ref, f->name); + imlib_context_set_font((Imlib_Font) f); + printf + ("\t\t ascent=%d, descent=%d, max_ascent=%d, max_descent=%d\n", + imlib_get_font_ascent(), imlib_get_font_descent(), + imlib_get_maximum_font_ascent(), + imlib_get_maximum_font_descent()); + imlib_free_font(); + printf("imlib_free_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f, f->next, f->type, f->ref, f->name); + printf("\n"); + + f1 = imlib_load_font("notepad/10"); + printf("imlib_load_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f1, f1->next, f1->type, f1->ref, f1->name); + f2 = imlib_load_font("-*-fixed-*--14-*"); + printf("imlib_load_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f2, f2->next, f2->type, f2->ref, f2->name); + f3 = imlib_load_font("notepad/10,-*-fixed-*--14-*"); + printf("imlib_load_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f3, f3->next, f3->type, f3->ref, f3->name); + f = f3->ttf; + printf(" f->ttf: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f, f->next, f->type, f->ref, f->name); + f4 = imlib_load_font("notepad/10,-*-fixed-*--14-*"); + printf("imlib_load_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f4, f4->next, f4->type, f4->ref, f4->name); + f = f4->ttf; + printf(" f->ttf: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f, f->next, f->type, f->ref, f->name); + printf("\n"); + + imlib_context_set_font((Imlib_Font) f4); + imlib_free_font(); + printf("imlib_free_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f4, f4->next, f4->type, f4->ref, f4->name); + f = f4->ttf; + printf(" f->ttf: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f, f->next, f->type, f->ref, f->name); + imlib_context_set_font((Imlib_Font) f1); + imlib_free_font(); + printf("imlib_free_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f1, f1->next, f1->type, f1->ref, f1->name); + imlib_context_set_font((Imlib_Font) f2); + imlib_free_font(); + printf("imlib_free_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f2, f2->next, f2->type, f2->ref, f2->name); + imlib_context_set_font((Imlib_Font) f3); + imlib_free_font(); + printf("imlib_free_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f3, f3->next, f3->type, f3->ref, f3->name); + f = f3->ttf; + printf(" f->ttf: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f, f->next, f->type, f->ref, f->name); + printf("\n"); + imlib_flush_font_cache(); + printf("imlib_flush_font_cache: \n"); + printf("\n"); + f1 = imlib_load_font("notepad/10,-*-fixed-*--14-*"); + printf("imlib_load_font: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f1, f1->next, f1->type, f1->ref, f1->name); + f = f1->ttf; + printf(" f->ttf: f=%x, next=%8x, type=%d, ref=%d, '%s'\n", + f, f->next, f->type, f->ref, f->name); + imlib_context_set_font((Imlib_Font) f1); + printf + ("\t\t ascent=%d, descent=%d, max_ascent=%d, max_descent=%d\n", + imlib_get_font_ascent(), imlib_get_font_descent(), + imlib_get_maximum_font_ascent(), + imlib_get_maximum_font_descent()); + + printf("Font Cache test end\n"); + } + + if (fon) + { + fn = imlib_load_font(fon); + + if (xfdtest) + { + int i; + + f = fn; + if (fn != NULL && f->type & 2) + for (i = 0; i < f->font_count; i++) + printf("xfont%d: %s\n", i, f->font_name[i]); + } + + imlib_context_set_font(fn); + if (!fn) + fon = NULL; + } + + imlib_context_set_progress_function(NULL); + imlib_context_set_progress_granularity(0); + if (file) + im_bg = imlib_load_image(file); + else + im_bg = imlib_load_image(PACKAGE_DATA_DIR"/data/images/bg.png"); + imlib_context_set_image(im_bg); + im_tmp = imlib_clone_image(); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + wo = w; + ho = h; + w *= 1; + h *= 1; + XResizeWindow(disp, win, w, h); + XSync(disp, False); + im = imlib_create_image(w, h); + imlib_set_cache_size(4 * 1024 * 1024); + i = 0; + up = imlib_update_append_rect(up, 0, 0, w, h); + x = -9999; + y = -9999; + while (1) + { + px = x; + py = y; + do + { + XNextEvent(disp, &ev); + switch (ev.type) + { + case Expose: + up = imlib_update_append_rect(up, + ev.xexpose.x, + ev.xexpose.y, + ev.xexpose.width, + ev.xexpose.height); + break; + case ButtonRelease: + if (fon) + { + imlib_context_set_font(fn); + imlib_free_font(); + } + exit(0); + break; + case MotionNotify: + x = ev.xmotion.x; + y = ev.xmotion.y; + default: + break; + + } + } + while (XPending(disp)); + + im_sh1 = imlib_load_image(PACKAGE_DATA_DIR"/data/images/sh1.png"); + im_sh2 = imlib_load_image(PACKAGE_DATA_DIR"/data/images/sh2.png"); + im_sh3 = imlib_load_image(PACKAGE_DATA_DIR"/data/images/sh3.png"); + im_ic[0] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/audio.png"); + im_ic[1] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/folder.png"); + im_ic[2] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/mush.png"); + im_ic[3] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/paper.png"); + im_ic[4] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/mail.png"); + im_ic[5] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/calc.png"); + im_ic[6] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/cal.png"); + im_ic[7] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/stop.png"); + im_ic[8] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/globe.png"); + im_ic[9] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/menu.png"); + im_ic[10] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/tnt.png"); + im_ic[11] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/bulb.png"); + im_ic[12] = imlib_load_image(PACKAGE_DATA_DIR"/data/images/lock.png"); + + imlib_context_set_image(im); + if (first) + { + imlib_blend_image_onto_image(im_bg, 0, + 0, 0, w, h, 0, 0, w, h); + first = 0; + } + else if (rotate) + { + Imlib_Image rotim; + double s, c; + int x1, y1, x2, y2, w, h; + + w = imlib_image_get_width(); + h = imlib_image_get_height(); + s = sin(6.2831853 * (double)y / (double)h); + c = cos(6.2831853 * (double)y / (double)h); + + x1 = (w - w * c + h * s) / 2; + y1 = (h - h * c - w * s) / 2; + x2 = (w + w * c - h * s) / 2; + y2 = (h + h * c + w * s) / 2; + + imlib_context_set_blend(1); + imlib_blend_image_onto_image_at_angle(im_bg, 0, + 0, 0, + imlib_image_get_width(), + imlib_image_get_height + (), x1, y1, x2, y2); + up = imlib_update_append_rect(up, 0, 0, + imlib_image_get_width(), + imlib_image_get_height()); + + } +/* + if( bump_map_to_point ) + imlib_apply_filter("bump_map_point(x=[],y=[],map=test_images/bulb.png);", &x, &y ); + else + imlib_apply_filter("bump_map(x=[],y=[],map=test_images/bulb.png);", &x, &y ); +*/ + up = imlib_update_append_rect(up, 0, 0, + imlib_image_get_width(), + imlib_image_get_height()); + { + Imlib_Updates uu; + + imlib_context_set_cliprect(0, 0, 0, 0); + imlib_context_set_color(255, 255, 255, 255); + uu = imlib_image_draw_line(200, 200, x, y, 1); + up = imlib_updates_append_updates(up, uu); + + /* test ellipses */ + imlib_context_set_color(255, 255, 255, 255); + imlib_image_draw_ellipse(50, 250, 30, 40); + imlib_image_fill_ellipse(50, 300, 30, 40); + + imlib_image_draw_rectangle(120, 245, 70, 70); + up = imlib_update_append_rect(up, 120, 245, 70, 70); + imlib_image_draw_ellipse(160, 280, 50, 20); + + imlib_context_set_cliprect(120, 245, 70, 70); + imlib_context_set_color(255, 55, 55, 255); + imlib_image_draw_ellipse(160, 280, 50, 20); + + /* test line clipping */ + imlib_context_set_cliprect(0, 0, 0, 0); + imlib_image_draw_rectangle(50, 50, 100, 100); + up = imlib_update_append_rect(up, 50, 50, 100, 100); + + imlib_context_set_color(255, 255, 255, 255); + + uu = imlib_image_draw_line(0, 0, 200, 200, 1); + up = imlib_updates_append_updates(up, uu); + + uu = imlib_image_draw_line(305, 25, 20, 200, 1); + up = imlib_updates_append_updates(up, uu); + + uu = imlib_image_draw_line(100, 5, 100, 205, 1); + up = imlib_updates_append_updates(up, uu); + + uu = imlib_image_draw_line(275, 5, 20, 100, 1); + up = imlib_updates_append_updates(up, uu); + + imlib_context_set_color(255, 55, 55, 255); + imlib_context_set_cliprect(50, 50, 100, 100); + + uu = imlib_image_draw_line(0, 0, 200, 200, 1); + up = imlib_updates_append_updates(up, uu); + + uu = imlib_image_draw_line(305, 25, 20, 200, 1); + up = imlib_updates_append_updates(up, uu); + + uu = imlib_image_draw_line(100, 5, 100, 205, 1); + up = imlib_updates_append_updates(up, uu); + + uu = imlib_image_draw_line(275, 5, 20, 100, 1); + up = imlib_updates_append_updates(up, uu); + + /* test rectangle clipping */ + imlib_context_set_color(255, 255, 255, 255); + imlib_context_set_cliprect(0, 0, 0, 0); + + imlib_image_draw_rectangle(70, 90, 20, 20); + imlib_image_draw_rectangle(115, 70, 60, 30); + imlib_image_draw_rectangle(30, 120, 50, 50); + + imlib_context_set_color(255, 55, 55, 255); + imlib_context_set_cliprect(50, 50, 100, 100); + + imlib_image_draw_rectangle(70, 90, 20, 20); + up = imlib_update_append_rect(up, 70, 90, 20, 20); + imlib_image_draw_rectangle(115, 70, 60, 30); + up = imlib_update_append_rect(up, 115, 70, 60, 30); + imlib_image_draw_rectangle(30, 120, 50, 50); + up = imlib_update_append_rect(up, 30, 120, 50, 50); + + imlib_context_set_cliprect(0, 0, 0, 0); + + /* test polygons */ + imlib_context_set_color(255, 0, 0, 128); + imlib_image_fill_polygon(poly); + imlib_context_set_color(255, 255, 255, 255); + imlib_image_draw_polygon(poly2, 0); + imlib_image_draw_polygon(poly3, 1); + imlib_image_draw_rectangle(380, 260, 50, 50); + + imlib_context_set_color(255, 55, 55, 255); + imlib_context_set_cliprect(380, 260, 50, 50); + imlib_image_fill_polygon(poly3); + imlib_context_set_cliprect(0, 0, 0, 0); + + } + { + static Imlib_Color_Range rg = NULL; + + if (!rg) + { + rg = imlib_create_color_range(); + imlib_context_set_color_range(rg); + imlib_context_set_color(255, 255, 255, 255); + imlib_add_color_to_color_range(0); + imlib_context_set_color(255, 255, 160, 255); + imlib_add_color_to_color_range(1); + imlib_context_set_color(255, 160, 120, 255); + imlib_add_color_to_color_range(1); + imlib_context_set_color(255, 80, 100, 128); + imlib_add_color_to_color_range(1); + imlib_context_set_color(32, 48, 80, 0); + imlib_add_color_to_color_range(1); + } + imlib_context_set_operation(IMLIB_OP_RESHADE); + imlib_image_fill_color_range_rectangle(60, 60, 256, 256, + (double)x); + up = imlib_update_append_rect(up, 60, 60, 256, 256); + imlib_context_set_operation(IMLIB_OP_COPY); + } + + if (xfdcachetest) + { + int l; + int retw, reth, tx, ty, nx, ny; + int secs, usecs, sece, usece; + FILE *f; + char buf[129]; + + f = fopen(xfdfname, "r"); + if (!f) + { + printf("file %s can not be opened!\n", file); + exit(-1); + } + + tx = ty = 0; + imlib_context_set_color(255, 255, 255, 255); + + gettimeofday(&timev, NULL); + secs = (int)timev.tv_sec; + usecs = (int)timev.tv_usec; + + l = xfdloop; + while (l) + { + fseek(f, 0, SEEK_SET); + while (fgets(buf, 128, f)) + { + if (buf[strlen(buf) - 1] == '\n') + buf[strlen(buf) - 1] = '\0'; + imlib_text_draw_with_return_metrics(tx, ty, buf, + &retw, &reth, + &nx, &ny); + up = imlib_update_append_rect(up, tx, ty, retw, + reth); + ty += ny; + if (ty > h) + ty = 0; + } + l--; + } + + gettimeofday(&timev, NULL); + sece = (int)timev.tv_sec; + usece = (int)timev.tv_usec; + { + double t1, t2; + + t1 = (double)secs + ((double)usecs / 1000000); + t2 = (double)sece + ((double)usece / 1000000); + sec = t2 - t1; + } + printf("%3.3f sec\n", sec); + + } + else if (fon) + { + int retw, reth, tx, ty, nx, ny, cx, cy, cw, + ch, cp; + int cx2, cy2, cw2, ch2; + + if (!str) + str = "This is a test string"; + tx = ty = 50; + for (i = 0; i < 16; i++) + { + int al; + + imlib_context_set_direction(textdir); + if (textdir == IMLIB_TEXT_TO_ANGLE) + { + double an = (double)i / 10.0; + + imlib_context_set_angle(an); + } + + al = (15 - i) * 16; + if (al > 255) + al = 255; + imlib_context_set_color(255, 255, 255, al); + imlib_text_draw_with_return_metrics(tx, ty, str, + &retw, &reth, + &nx, &ny); + up = imlib_update_append_rect(up, tx, ty, retw, reth); + switch (textdir) + { + case IMLIB_TEXT_TO_RIGHT: + case IMLIB_TEXT_TO_LEFT: + case IMLIB_TEXT_TO_ANGLE: + ty += ny; + break; + case IMLIB_TEXT_TO_DOWN: + case IMLIB_TEXT_TO_UP: + tx += nx; + break; + } + } + cp = imlib_text_get_index_and_location(str, x - 50, y - 50, + &cx, &cy, &cw, &ch); + if (cp >= 0) + { + char tmp[16]; + int len; + + len = mblen(str + cp, MB_CUR_MAX); + if (len < 0) + len = 1; + strncpy(tmp, str + cp, len); + tmp[len] = '\0'; + printf("over char %s : cp=%d cx=%d cy=%d cw=%d ch=%d : ", + tmp, cp, cx, cy, cw, ch); + imlib_text_get_location_at_index(str, cp, &cx2, &cy2, + &cw2, &ch2); + printf("cx2=%d cy2=%d cw2=%d ch2=%d \n", + cx2, cy2, cw2, ch2); + } + } + imlib_context_set_blend(1); + if ((px != x) || (py != y)) + { + for (j = 0; j < 32; j++) + { + for (i = 0; i < 32; i++) + { + int ic, iw, ih, ww, hh; + + ic = ((j * 32) + i) % 13; + imlib_context_set_image(im_ic[ic]); + iw = imlib_image_get_width(); + ih = imlib_image_get_height(); + ww = iw; + hh = ih; + up = imlib_update_append_rect(up, x + (i * iw * 2), + y + (j * ih * 2), ww, + hh); + up = imlib_update_append_rect(up, px + (i * iw * 2), + py + (j * ih * 2), ww, + hh); + imlib_context_set_image(im); + imlib_blend_image_onto_image(im_ic[ic], 0, + 0, 0, iw, ih, + x + (i * iw * 2), + y + (j * ih * 2), + ww, hh); + } + } + } +/* + imlib_apply_filter( "tint(x=200,y=200,w=300,h=100,alpha=100,red=155,green=25,blue=25);"\ + "tint(green=20,red=20,blue=20,alpha=200,x=30,y=30);" \ + "tint(green=40,red=40,blue=240,alpha=60,x=50,y=150,h=200);" ); +*/ + imlib_blend_image_onto_image(im_sh1, 0, 0, 0, 50, 50, 0, 0, 50, + 50); + up = imlib_update_append_rect(up, 0, 0, 50, 50); + imlib_blend_image_onto_image(im_sh2, 0, 0, 0, 50, 50, 50, 0, + w - 50, 50); + up = imlib_update_append_rect(up, 50, 0, w - 50, 50); + imlib_blend_image_onto_image(im_sh3, 0, 0, 0, 50, 50, 0, 50, 50, + h - 50); + up = imlib_update_append_rect(up, 0, 50, 50, h - 50); + up = imlib_updates_merge_for_rendering(up, w, h); + imlib_context_set_blend(0); + imlib_render_image_updates_on_drawable(up, 0, 0); + if ((px != x) || (py != y)) + { + Imlib_Updates u; + + u = up; + while (u) + { + int ux, uy, uw, uh; + + imlib_updates_get_coordinates(u, &ux, &uy, &uw, &uh); + imlib_blend_image_onto_image(im_bg, 0, + ux, uy, uw, uh, + ux, uy, uw, uh); + u = imlib_updates_get_next(u); + } + } + imlib_updates_free(up); + up = NULL; + imlib_context_set_image(im_sh1); + imlib_free_image(); + imlib_context_set_image(im_sh1); + imlib_free_image(); + imlib_context_set_image(im_sh1); + imlib_free_image(); + imlib_context_set_image(im_ic[0]); + imlib_free_image(); + imlib_context_set_image(im_ic[1]); + imlib_free_image(); + imlib_context_set_image(im_ic[2]); + imlib_free_image(); + imlib_context_set_image(im_ic[3]); + imlib_free_image(); + + } + } + else + { + printf("blast test\n"); + pixels = 0; + imlib_context_set_color_modifier(colormod); + for (i = 0; i < w; i++) + { + imlib_render_image_on_drawable_at_size(0, 0, w, h); + pixels += w * h; + } + } + + /** + * Determine horse power of your video card driver + */ + gettimeofday(&timev, NULL); + sec2 = (int)timev.tv_sec; /* and stores it so we can time outselves */ + usec2 = (int)timev.tv_usec; /* we will use this to vary speed of rot */ + printf("done\n"); + { + double t1, t2; + + t1 = (double)sec1 + ((double)usec1 / 1000000); + t2 = (double)sec2 + ((double)usec2 / 1000000); + sec = t2 - t1; + } + printf("%3.3f sec, %3.3f M pixels (%i)\n", sec, (double)pixels / 1000000, + pixels); + printf("%3.3f Mpixels / sec\n", (double)(pixels) / (sec * 1000000)); + return 0; +} diff --git a/src/bin/imlib2_test.c b/src/bin/imlib2_test.c new file mode 100644 index 0000000..f823fa8 --- /dev/null +++ b/src/bin/imlib2_test.c @@ -0,0 +1,274 @@ +#include "config.h" +/* include X11 stuff */ +#include +/* include Imlib2 stuff */ +#include +/* sprintf include */ +#include + +/* some globals for our window & X display */ +Display *disp; +Window win; +Visual *vis; +Colormap cm; +int depth; + +/* the program... */ +int +main(int argc, char **argv) +{ + /* events we get from X */ + XEvent ev; + + /* areas to update */ + Imlib_Updates updates, current_update; + + /* our virtual framebuffer image we draw into */ + Imlib_Image buffer; + + /* a font */ + Imlib_Font font; + + /* our color range */ + Imlib_Color_Range range; + + /* our mouse x, y coordinates */ + int mouse_x = 0, mouse_y = 0; + + /* connect to X */ + disp = XOpenDisplay(NULL); + /* get default visual , colormap etc. you could ask imlib2 for what it */ + /* thinks is the best, but this example is intended to be simple */ + vis = DefaultVisual(disp, DefaultScreen(disp)); + depth = DefaultDepth(disp, DefaultScreen(disp)); + cm = DefaultColormap(disp, DefaultScreen(disp)); + /* create a window 640x480 */ + win = XCreateSimpleWindow(disp, DefaultRootWindow(disp), + 0, 0, 640, 480, 0, 0, 0); + /* tell X what events we are interested in */ + XSelectInput(disp, win, ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | ExposureMask); + /* show the window */ + XMapWindow(disp, win); + /* set our cache to 2 Mb so it doesnt have to go hit the disk as long as */ + /* the images we use use less than 2Mb of RAM (that is uncompressed) */ + imlib_set_cache_size(2048 * 1024); + /* set the font cache to 512Kb - again to avoid re-loading */ + imlib_set_font_cache_size(512 * 1024); + /* add the ./ttfonts dir to our font path - you'll want a notepad.ttf */ + /* in that dir for the text to display */ + imlib_add_path_to_font_path(PACKAGE_DATA_DIR"/data/fonts"); + /* set the maximum number of colors to allocate for 8bpp and less to 128 */ + imlib_set_color_usage(128); + /* dither for depths < 24bpp */ + imlib_context_set_dither(1); + /* set the display , visual, colormap and drawable we are using */ + imlib_context_set_display(disp); + imlib_context_set_visual(vis); + imlib_context_set_colormap(cm); + imlib_context_set_drawable(win); + /* infinite event loop */ + for (;;) + { + /* image variable */ + Imlib_Image image; + + /* width and height values */ + int w, h, text_w, text_h; + + /* init our updates to empty */ + updates = imlib_updates_init(); + /* while there are events form X - handle them */ + do + { + XNextEvent(disp, &ev); + switch (ev.type) + { + case Expose: + /* window rectangle was exposed - add it to the list of */ + /* rectangles we need to re-render */ + updates = imlib_update_append_rect(updates, + ev.xexpose.x, + ev.xexpose.y, + ev.xexpose.width, + ev.xexpose.height); + break; + case ButtonPress: + /* if we click anywhere in the window, exit */ + exit(0); + break; + case MotionNotify: + /* if the mouse moves - note it */ + /* add a rectangle update for the new mouse position */ + image = imlib_load_image(PACKAGE_DATA_DIR"/data/images/mush.png"); + imlib_context_set_image(image); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + imlib_context_set_image(image); + imlib_free_image(); + /* the old position - so we wipe over where it used to be */ + updates = imlib_update_append_rect(updates, + mouse_x - (w / 2), + mouse_y - (h / 2), w, h); + font = imlib_load_font("notepad/30"); + if (font) + { + char text[4096]; + + imlib_context_set_font(font); + sprintf(text, "Mouse is at %i, %i", mouse_x, mouse_y); + imlib_get_text_size(text, &text_w, &text_h); + imlib_free_font(); + updates = imlib_update_append_rect(updates, + 320 - (text_w / 2), + 240 - (text_h / 2), + text_w, text_h); + } + + mouse_x = ev.xmotion.x; + mouse_y = ev.xmotion.y; + /* the new one */ + updates = imlib_update_append_rect(updates, + mouse_x - (w / 2), + mouse_y - (h / 2), w, h); + font = imlib_load_font("notepad/30"); + if (font) + { + char text[4096]; + + imlib_context_set_font(font); + sprintf(text, "Mouse is at %i, %i", mouse_x, mouse_y); + imlib_get_text_size(text, &text_w, &text_h); + imlib_free_font(); + updates = imlib_update_append_rect(updates, + 320 - (text_w / 2), + 240 - (text_h / 2), + text_w, text_h); + } + default: + /* any other events - do nothing */ + break; + } + } + while (XPending(disp)); + + /* no more events for now ? ok - idle time so lets draw stuff */ + + /* take all the little rectangles to redraw and merge them into */ + /* something sane for rendering */ + updates = imlib_updates_merge_for_rendering(updates, 640, 480); + for (current_update = updates; + current_update; + current_update = imlib_updates_get_next(current_update)) + { + int up_x, up_y, up_w, up_h; + + /* find out where the first update is */ + imlib_updates_get_coordinates(current_update, + &up_x, &up_y, &up_w, &up_h); + + /* create our buffer image for renderign this update */ + buffer = imlib_create_image(up_w, up_h); + + /* we can blend stuff now */ + imlib_context_set_blend(1); + + /* fill the window background */ + /* load the background image - you'll need to have some images */ + /* in ./test_images lying around for this to actually work */ + image = imlib_load_image(PACKAGE_DATA_DIR"/data/images/bg.png"); + /* we're working with this image now */ + imlib_context_set_image(image); + /* get its size */ + w = imlib_image_get_width(); + h = imlib_image_get_height(); + /* now we want to work with the buffer */ + imlib_context_set_image(buffer); + /* if the iimage loaded */ + if (image) + { + /* blend image onto the buffer and scale it to 640x480 */ + imlib_blend_image_onto_image(image, 0, + 0, 0, w, h, + -up_x, -up_y, 640, 480); + /* working with the loaded image */ + imlib_context_set_image(image); + /* free it */ + imlib_free_image(); + } + + /* draw an icon centered around the mouse position */ + image = imlib_load_image(PACKAGE_DATA_DIR"/data/images/mush.png"); + imlib_context_set_image(image); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + imlib_context_set_image(buffer); + if (image) + { + imlib_blend_image_onto_image(image, 0, + 0, 0, w, h, + mouse_x - (w / 2) - up_x, + mouse_y - (h / 2) - up_y, w, h); + imlib_context_set_image(image); + imlib_free_image(); + } + + /* draw a gradient on top of things at the top left of the window */ + /* create a range */ + range = imlib_create_color_range(); + imlib_context_set_color_range(range); + /* add white opaque as the first color */ + imlib_context_set_color(255, 255, 255, 255); + imlib_add_color_to_color_range(0); + /* add an orange color, semi-transparent 10 units from the first */ + imlib_context_set_color(255, 200, 10, 100); + imlib_add_color_to_color_range(10); + /* add black, fully transparent at the end 20 units away */ + imlib_context_set_color(0, 0, 0, 0); + imlib_add_color_to_color_range(20); + /* draw the range */ + imlib_context_set_image(buffer); + imlib_image_fill_color_range_rectangle(-up_x, -up_y, 128, 128, + -45.0); + /* free it */ + imlib_free_color_range(); + + /* draw text - centered with the current mouse x, y */ + font = imlib_load_font("notepad/30"); + if (font) + { + char text[4096]; + + /* set the current font */ + imlib_context_set_font(font); + /* set the image */ + imlib_context_set_image(buffer); + /* set the color (black) */ + imlib_context_set_color(0, 0, 0, 255); + /* print text to display in the buffer */ + sprintf(text, "Mouse is at %i, %i", mouse_x, mouse_y); + /* query the size it will be */ + imlib_get_text_size(text, &text_w, &text_h); + /* draw it */ + imlib_text_draw(320 - (text_w / 2) - up_x, + 240 - (text_h / 2) - up_y, text); + /* free the font */ + imlib_free_font(); + } + + /* dont blend the image onto the drawable - slower */ + imlib_context_set_blend(0); + /* set the buffer image as our current image */ + imlib_context_set_image(buffer); + /* render the image at 0, 0 */ + imlib_render_image_on_drawable(up_x, up_y); + /* don't need that temproary buffer image anymore */ + imlib_free_image(); + } + /* if we had updates - free them */ + if (updates) + imlib_updates_free(updates); + /* loop again waiting for events */ + } + return 0; +} diff --git a/src/bin/imlib2_view.c b/src/bin/imlib2_view.c new file mode 100644 index 0000000..9135e25 --- /dev/null +++ b/src/bin/imlib2_view.c @@ -0,0 +1,346 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Imlib2.h" + +Display *disp; +Window win; +Pixmap pm = 0; +Visual *vis; +Colormap cm; +int depth; +int image_width = 0, image_height = 0; +Imlib_Image bg_im = NULL; + +static int + progress(Imlib_Image im, char percent, int update_x, int update_y, + int update_w, int update_h); + +static int +progress(Imlib_Image im, char percent, int update_x, int update_y, + int update_w, int update_h) +{ + /* first time it's called */ + imlib_context_set_drawable(pm); + imlib_context_set_anti_alias(0); + imlib_context_set_dither(0); + imlib_context_set_blend(0); + if (image_width == 0) + { + int x, y, onoff; + + imlib_context_set_image(im); + image_width = imlib_image_get_width(); + image_height = imlib_image_get_height(); + if (pm) + XFreePixmap(disp, pm); + pm = XCreatePixmap(disp, win, image_width, image_height, depth); + imlib_context_set_drawable(pm); + if (bg_im) + { + imlib_context_set_image(bg_im); + imlib_free_image_and_decache(); + } + bg_im = imlib_create_image(image_width, image_height); + imlib_context_set_image(bg_im); + for (y = 0; y < image_height; y += 8) + { + onoff = (y / 8) & 0x1; + for (x = 0; x < image_width; x += 8) + { + if (onoff) + imlib_context_set_color(144, 144, 144, 255); + else + imlib_context_set_color(100, 100, 100, 255); + imlib_image_fill_rectangle(x, y, 8, 8); + onoff++; + if (onoff == 2) + onoff = 0; + } + } + imlib_render_image_part_on_drawable_at_size(0, 0, image_width, + image_height, 0, 0, + image_width, image_height); + XSetWindowBackgroundPixmap(disp, win, pm); + XResizeWindow(disp, win, image_width, image_height); + XMapWindow(disp, win); + XSync(disp, False); + } + imlib_context_set_anti_alias(0); + imlib_context_set_dither(0); + imlib_context_set_blend(1); + imlib_blend_image_onto_image(im, 0, + update_x, update_y, + update_w, update_h, + update_x, update_y, update_w, update_h); + imlib_context_set_blend(0); + imlib_render_image_part_on_drawable_at_size(update_x, update_y, + update_w, update_h, + update_x, update_y, + update_w, update_h); + XSetWindowBackgroundPixmap(disp, win, pm); + XClearArea(disp, win, update_x, update_y, update_w, update_h, False); + XFlush(disp); + return 1; +} + +int +main(int argc, char **argv) +{ + Imlib_Image *im = NULL; + char *file = NULL; + int no = 1; + + if (argc < 2) + return 1; + + file = argv[no]; + disp = XOpenDisplay(NULL); + vis = DefaultVisual(disp, DefaultScreen(disp)); + depth = DefaultDepth(disp, DefaultScreen(disp)); + cm = DefaultColormap(disp, DefaultScreen(disp)); + win = XCreateSimpleWindow(disp, DefaultRootWindow(disp), 0, 0, 10, 10, + 0, 0, 0); + XSelectInput(disp, win, ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | PointerMotionMask); + imlib_context_set_display(disp); + imlib_context_set_visual(vis); + imlib_context_set_colormap(cm); + imlib_context_set_progress_function(progress); + imlib_context_set_progress_granularity(10); + imlib_context_set_drawable(win); + im = imlib_load_image(file); + while (!im) + { + no++; + if (no == argc) + exit(0); + file = argv[no]; + image_width = 0; + im = imlib_load_image(file); + imlib_context_set_image(im); + } + if (!im) + { + fprintf(stderr, "Image format not available\n"); + exit(0); + } + for (;;) + { + int x, y, b, count, fdsize, xfd, timeout = 0; + XEvent ev; + static int zoom_mode = 0, zx, zy; + static double zoom = 1.0; + struct timeval tval; + fd_set fdset; + double t1; + + XFlush(disp); + while (XPending(disp)) + { + XNextEvent(disp, &ev); + switch (ev.type) + { + case ButtonPress: + b = ev.xbutton.button; + x = ev.xbutton.x; + y = ev.xbutton.y; + if (b == 3) + { + zoom_mode = 1; + zx = x; + zy = y; + imlib_context_set_drawable(pm); + imlib_context_set_image(bg_im); + imlib_context_set_anti_alias(0); + imlib_context_set_dither(0); + imlib_context_set_blend(0); + imlib_render_image_part_on_drawable_at_size + (0, 0, image_width, image_height, + 0, 0, image_width, image_height); + XSetWindowBackgroundPixmap(disp, win, pm); + XClearWindow(disp, win); + } + break; + case ButtonRelease: + b = ev.xbutton.button; + x = ev.xbutton.x; + y = ev.xbutton.y; + if (b == 3) + zoom_mode = 0; + if (b == 1) + { + no++; + if (no == argc) + no = argc - 1; + file = argv[no]; + image_width = 0; + zoom = 1.0; + zoom_mode = 0; + imlib_context_set_image(im); + imlib_free_image_and_decache(); + im = imlib_load_image(file); + while (!im) + { + no++; + if (no == argc) + exit(0); + file = argv[no]; + image_width = 0; + im = imlib_load_image(file); + } + imlib_context_set_image(im); + } + if (b == 2) + { + no--; + if (no == 0) + no = 1; + file = argv[no]; + image_width = 0; + zoom = 1.0; + zoom_mode = 0; + imlib_context_set_image(im); + imlib_free_image_and_decache(); + im = imlib_load_image(file); + while (!im) + { + no--; + if (no == 0) + no = 1; + file = argv[no]; + image_width = 0; + im = imlib_load_image(file); + } + imlib_context_set_image(im); + } + break; + case MotionNotify: + while (XCheckTypedWindowEvent + (disp, win, MotionNotify, &ev)); + x = ev.xmotion.x; + y = ev.xmotion.y; + if (zoom_mode) + { + int sx, sy, sw, sh, dx, dy, dw, dh; + + zoom = ((double)x - (double)zx) / 32.0; + if (zoom < 0) + zoom = 1.0 + ((zoom * 32.0) / ((double)(zx + 1))); + else + zoom += 1.0; + if (zoom <= 0.0001) + zoom = 0.0001; + if (zoom > 1.0) + { + dx = 0; + dy = 0; + dw = image_width; + dh = image_height; + + sx = zx - (zx / zoom); + sy = zy - (zy / zoom); + sw = image_width / zoom; + sh = image_height / zoom; + } + else + { + dx = zx - (zx * zoom); + dy = zy - (zy * zoom); + dw = image_width * zoom; + dh = image_height * zoom; + + sx = 0; + sy = 0; + sw = image_width; + sh = image_height; + } + imlib_context_set_anti_alias(0); + imlib_context_set_dither(0); + imlib_context_set_blend(0); + imlib_context_set_image(bg_im); + imlib_render_image_part_on_drawable_at_size + (sx, sy, sw, sh, dx, dy, dw, dh); + XSetWindowBackgroundPixmap(disp, win, pm); + XClearWindow(disp, win); + XFlush(disp); + timeout = 1; + } + default: + break; + } + t1 = 0.2; + tval.tv_sec = (long)t1; + tval.tv_usec = (long)((t1 - ((double)tval.tv_sec)) * 1000000); + xfd = ConnectionNumber(disp); + fdsize = xfd + 1; + FD_ZERO(&fdset); + FD_SET(xfd, &fdset); + if (timeout) + count = select(fdsize, &fdset, NULL, NULL, &tval); + else + count = select(fdsize, &fdset, NULL, NULL, NULL); + if (count < 0) + { + if ((errno == ENOMEM) || (errno == EINVAL) + || (errno == EBADF)) + exit(1); + } + else + { + if ((count == 0) && (timeout)) + { + int sx, sy, sw, sh, dx, dy, dw, dh; + + if (zoom > 1.0) + { + dx = 0; + dy = 0; + dw = image_width; + dh = image_height; + + sx = zx - (zx / zoom); + sy = zy - (zy / zoom); + sw = image_width / zoom; + sh = image_height / zoom; + } + else + { + dx = zx - (zx * zoom); + dy = zy - (zy * zoom); + dw = image_width * zoom; + dh = image_height * zoom; + + sx = 0; + sy = 0; + sw = image_width; + sh = image_height; + } + imlib_context_set_anti_alias(1); + imlib_context_set_dither(1); + imlib_context_set_blend(0); + imlib_context_set_image(bg_im); + imlib_render_image_part_on_drawable_at_size + (sx, sy, sw, sh, dx, dy, dw, dh); + XSetWindowBackgroundPixmap(disp, win, pm); + XClearWindow(disp, win); + XFlush(disp); + timeout = 0; + } + } + + } + } + return 0; +} diff --git a/src/lib/Imlib2.h b/src/lib/Imlib2.h new file mode 100644 index 0000000..6480db0 --- /dev/null +++ b/src/lib/Imlib2.h @@ -0,0 +1,481 @@ +#ifndef __IMLIB_API_H +# define __IMLIB_API_H 1 + +/* Data types to use */ +# ifndef DATA64 +# define DATA64 unsigned long long +# define DATA32 unsigned int +# define DATA16 unsigned short +# define DATA8 unsigned char +# endif + +/* opaque data types */ +typedef void *Imlib_Context; +typedef void *Imlib_Image; +typedef void *Imlib_Color_Modifier; +typedef void *Imlib_Updates; +typedef void *Imlib_Font; +typedef void *Imlib_Color_Range; +typedef void *Imlib_Filter; +typedef struct _imlib_border Imlib_Border; +typedef struct _imlib_color Imlib_Color; +typedef void *ImlibPolygon; + +/* blending operations */ +enum _imlib_operation +{ + IMLIB_OP_COPY, + IMLIB_OP_ADD, + IMLIB_OP_SUBTRACT, + IMLIB_OP_RESHADE +}; + +enum _imlib_text_direction +{ + IMLIB_TEXT_TO_RIGHT = 0, + IMLIB_TEXT_TO_LEFT = 1, + IMLIB_TEXT_TO_DOWN = 2, + IMLIB_TEXT_TO_UP = 3, + IMLIB_TEXT_TO_ANGLE = 4 +}; + +enum _imlib_load_error +{ + IMLIB_LOAD_ERROR_NONE, + IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST, + IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY, + IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ, + IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT, + IMLIB_LOAD_ERROR_PATH_TOO_LONG, + IMLIB_LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT, + IMLIB_LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY, + IMLIB_LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE, + IMLIB_LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS, + IMLIB_LOAD_ERROR_OUT_OF_MEMORY, + IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS, + IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_WRITE, + IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE, + IMLIB_LOAD_ERROR_UNKNOWN +}; + +/* Encodings known to Imlib2 (so far) */ +enum _imlib_TTF_encoding +{ + IMLIB_TTF_ENCODING_ISO_8859_1, + IMLIB_TTF_ENCODING_ISO_8859_2, + IMLIB_TTF_ENCODING_ISO_8859_3, + IMLIB_TTF_ENCODING_ISO_8859_4, + IMLIB_TTF_ENCODING_ISO_8859_5 +}; + +typedef enum _imlib_operation Imlib_Operation; +typedef enum _imlib_load_error Imlib_Load_Error; +typedef enum _imlib_text_direction Imlib_Text_Direction; +typedef enum _imlib_TTF_encoding Imlib_TTF_Encoding; + +struct _imlib_border +{ + int left, right, top, bottom; +}; + +struct _imlib_color +{ + int alpha, red, green, blue; +}; + +/* Progressive loading callbacks */ +typedef int (*Imlib_Progress_Function) (Imlib_Image im, char percent, + int update_x, int update_y, + int update_w, int update_h); +typedef void (*Imlib_Data_Destructor_Function) (Imlib_Image im, void *data); + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* context handling */ + Imlib_Context imlib_context_new(void); + void imlib_context_free(Imlib_Context context); + + void imlib_context_push(Imlib_Context context); + void imlib_context_pop(void); + Imlib_Context imlib_context_get(void); + +/* context setting */ +#ifndef X_DISPLAY_MISSING + void imlib_context_set_display(Display * display); + void imlib_context_set_visual(Visual * visual); + void imlib_context_set_colormap(Colormap colormap); + void imlib_context_set_drawable(Drawable drawable); + void imlib_context_set_mask(Pixmap mask); +#endif + void imlib_context_set_dither_mask(char dither_mask); + void imlib_context_set_anti_alias(char anti_alias); + void imlib_context_set_dither(char dither); + void imlib_context_set_blend(char blend); + void imlib_context_set_color_modifier(Imlib_Color_Modifier color_modifier); + void imlib_context_set_operation(Imlib_Operation operation); + void imlib_context_set_font(Imlib_Font font); + void imlib_context_set_direction(Imlib_Text_Direction direction); + void imlib_context_set_angle(double angle); + void imlib_context_set_color(int red, int green, int blue, int alpha); + void imlib_context_set_color_hsva(float hue, float saturation, float value, int alpha); + void imlib_context_set_color_hlsa(float hue, float lightness, float saturation, int alpha); + void imlib_context_set_color_cmya(int cyan, int magenta, int yellow, int alpha); + void imlib_context_set_color_range(Imlib_Color_Range color_range); + void imlib_context_set_progress_function(Imlib_Progress_Function + progress_function); + void imlib_context_set_progress_granularity(char progress_granularity); + void imlib_context_set_image(Imlib_Image image); + void imlib_context_set_cliprect(int x, int y, int w, int h); + void imlib_context_set_TTF_encoding(Imlib_TTF_Encoding encoding); + +/* context getting */ +#ifndef X_DISPLAY_MISSING + Display *imlib_context_get_display(void); + Visual *imlib_context_get_visual(void); + Colormap imlib_context_get_colormap(void); + Drawable imlib_context_get_drawable(void); + Pixmap imlib_context_get_mask(void); +#endif + char imlib_context_get_dither_mask(void); + char imlib_context_get_anti_alias(void); + char imlib_context_get_dither(void); + char imlib_context_get_blend(void); + Imlib_Color_Modifier imlib_context_get_color_modifier(void); + Imlib_Operation imlib_context_get_operation(void); + Imlib_Font imlib_context_get_font(void); + double imlib_context_get_angle(void); + Imlib_Text_Direction imlib_context_get_direction(void); + void imlib_context_get_color(int *red, int *green, int *blue, int *alpha); + void imlib_context_get_color_hsva(float *hue, float *saturation, float *value, int *alpha); + void imlib_context_get_color_hlsa(float *hue, float *lightness, float *saturation, int *alpha); + void imlib_context_get_color_cmya(int *cyan, int *magenta, int *yellow, int *alpha); + Imlib_Color *imlib_context_get_imlib_color(void); + Imlib_Color_Range imlib_context_get_color_range(void); + Imlib_Progress_Function imlib_context_get_progress_function(void); + char imlib_context_get_progress_granularity(void); + Imlib_Image imlib_context_get_image(void); + void imlib_context_get_cliprect(int *x, int *y, int *w, int *h); + Imlib_TTF_Encoding imlib_context_get_TTF_encoding(void); + + int imlib_get_cache_size(void); + void imlib_set_cache_size(int bytes); + int imlib_get_color_usage(void); + void imlib_set_color_usage(int max); + void imlib_flush_loaders(void); +#ifndef X_DISPLAY_MISSING + int imlib_get_visual_depth(Display * display, Visual * visual); + Visual *imlib_get_best_visual(Display * display, int screen, + int *depth_return); +#endif + + Imlib_Image imlib_load_image(const char *file); + Imlib_Image imlib_load_image_immediately(const char *file); + Imlib_Image imlib_load_image_without_cache(const char *file); + Imlib_Image imlib_load_image_immediately_without_cache(const char *file); + Imlib_Image imlib_load_image_with_error_return(const char *file, + Imlib_Load_Error * + error_return); + void imlib_free_image(void); + void imlib_free_image_and_decache(void); + +/* query/modify image parameters */ + int imlib_image_get_width(void); + int imlib_image_get_height(void); + const char *imlib_image_get_filename(void); + DATA32 *imlib_image_get_data(void); + DATA32 *imlib_image_get_data_for_reading_only(void); + void imlib_image_put_back_data(DATA32 * data); + char imlib_image_has_alpha(void); + void imlib_image_set_changes_on_disk(void); + void imlib_image_get_border(Imlib_Border * border); + void imlib_image_set_border(Imlib_Border * border); + void imlib_image_set_format(const char *format); + void imlib_image_set_irrelevant_format(char irrelevant); + void imlib_image_set_irrelevant_border(char irrelevant); + void imlib_image_set_irrelevant_alpha(char irrelevant); + char *imlib_image_format(void); + void imlib_image_set_has_alpha(char has_alpha); + void imlib_image_query_pixel(int x, int y, Imlib_Color * color_return); + void imlib_image_query_pixel_hsva(int x, int y, float *hue, float *saturation, float *value, int *alpha); + void imlib_image_query_pixel_hlsa(int x, int y, float *hue, float *lightness, float *saturation, int *alpha); + void imlib_image_query_pixel_cmya(int x, int y, int *cyan, int *magenta, int *yellow, int *alpha); + +/* rendering functions */ +#ifndef X_DISPLAY_MISSING + void imlib_render_pixmaps_for_whole_image(Pixmap * pixmap_return, + Pixmap * mask_return); + void imlib_render_pixmaps_for_whole_image_at_size(Pixmap * pixmap_return, + Pixmap * mask_return, + int width, int height); + void imlib_free_pixmap_and_mask(Pixmap pixmap); + void imlib_render_image_on_drawable(int x, int y); + void imlib_render_image_on_drawable_at_size(int x, int y, int width, + int height); + void imlib_render_image_part_on_drawable_at_size(int source_x, + int source_y, + int source_width, + int source_height, int x, + int y, int width, + int height); + DATA32 imlib_render_get_pixel_color(void); +#endif + void imlib_blend_image_onto_image(Imlib_Image source_image, + char merge_alpha, int source_x, + int source_y, int source_width, + int source_height, int destination_x, + int destination_y, int destination_width, + int destination_height); + +/* creation functions */ + Imlib_Image imlib_create_image(int width, int height); + Imlib_Image imlib_create_image_using_data(int width, int height, + DATA32 * data); + Imlib_Image imlib_create_image_using_copied_data(int width, int height, + DATA32 * data); +#ifndef X_DISPLAY_MISSING + Imlib_Image imlib_create_image_from_drawable(Pixmap mask, int x, int y, + int width, int height, + char need_to_grab_x); + Imlib_Image imlib_create_image_from_ximage(XImage *image, XImage *mask, int x, int y, + int width, int height, + char need_to_grab_x); + Imlib_Image imlib_create_scaled_image_from_drawable(Pixmap mask, + int source_x, + int source_y, + int source_width, + int source_height, + int destination_width, + int destination_height, + char need_to_grab_x, + char + get_mask_from_shape); + char imlib_copy_drawable_to_image(Pixmap mask, int x, int y, int width, + int height, int destination_x, + int destination_y, char need_to_grab_x); +#endif + Imlib_Image imlib_clone_image(void); + Imlib_Image imlib_create_cropped_image(int x, int y, int width, + int height); + Imlib_Image imlib_create_cropped_scaled_image(int source_x, int source_y, + int source_width, + int source_height, + int destination_width, + int destination_height); + +/* imlib updates. lists of rectangles for storing required update draws */ + Imlib_Updates imlib_updates_clone(Imlib_Updates updates); + Imlib_Updates imlib_update_append_rect(Imlib_Updates updates, int x, int y, + int w, int h); + Imlib_Updates imlib_updates_merge(Imlib_Updates updates, int w, int h); + Imlib_Updates imlib_updates_merge_for_rendering(Imlib_Updates updates, + int w, int h); + void imlib_updates_free(Imlib_Updates updates); + Imlib_Updates imlib_updates_get_next(Imlib_Updates updates); + void imlib_updates_get_coordinates(Imlib_Updates updates, int *x_return, + int *y_return, int *width_return, + int *height_return); + void imlib_updates_set_coordinates(Imlib_Updates updates, int x, int y, + int width, int height); + void imlib_render_image_updates_on_drawable(Imlib_Updates updates, int x, + int y); + Imlib_Updates imlib_updates_init(void); + Imlib_Updates imlib_updates_append_updates(Imlib_Updates updates, + Imlib_Updates appended_updates); + +/* image modification */ + void imlib_image_flip_horizontal(void); + void imlib_image_flip_vertical(void); + void imlib_image_flip_diagonal(void); + void imlib_image_orientate(int orientation); + void imlib_image_blur(int radius); + void imlib_image_sharpen(int radius); + void imlib_image_tile_horizontal(void); + void imlib_image_tile_vertical(void); + void imlib_image_tile(void); + +/* fonts and text */ + Imlib_Font imlib_load_font(const char *font_name); + void imlib_free_font(void); + void imlib_text_draw(int x, int y, const char *text); + void imlib_text_draw_with_return_metrics(int x, int y, const char *text, + int *width_return, + int *height_return, + int *horizontal_advance_return, + int *vertical_advance_return); + void imlib_get_text_size(const char *text, int *width_return, + int *height_return); + void imlib_get_text_advance(const char *text, + int *horizontal_advance_return, + int *vertical_advance_return); + int imlib_get_text_inset(const char *text); + void imlib_add_path_to_font_path(const char *path); + void imlib_remove_path_from_font_path(const char *path); + char **imlib_list_font_path(int *number_return); + int imlib_text_get_index_and_location(const char *text, int x, int y, + int *char_x_return, + int *char_y_return, + int *char_width_return, + int *char_height_return); + void imlib_text_get_location_at_index(const char *text, int index, + int *char_x_return, + int *char_y_return, + int *char_width_return, + int *char_height_return); + char **imlib_list_fonts(int *number_return); + void imlib_free_font_list(char **font_list, int number); + int imlib_get_font_cache_size(void); + void imlib_set_font_cache_size(int bytes); + void imlib_flush_font_cache(void); + int imlib_get_font_ascent(void); + int imlib_get_font_descent(void); + int imlib_get_maximum_font_ascent(void); + int imlib_get_maximum_font_descent(void); + +/* color modifiers */ + Imlib_Color_Modifier imlib_create_color_modifier(void); + void imlib_free_color_modifier(void); + void imlib_modify_color_modifier_gamma(double gamma_value); + void imlib_modify_color_modifier_brightness(double brightness_value); + void imlib_modify_color_modifier_contrast(double contrast_value); + void imlib_set_color_modifier_tables(DATA8 * red_table, + DATA8 * green_table, + DATA8 * blue_table, + DATA8 * alpha_table); + void imlib_get_color_modifier_tables(DATA8 * red_table, + DATA8 * green_table, + DATA8 * blue_table, + DATA8 * alpha_table); + void imlib_reset_color_modifier(void); + void imlib_apply_color_modifier(void); + void imlib_apply_color_modifier_to_rectangle(int x, int y, int width, + int height); + +/* drawing on images */ + Imlib_Updates imlib_image_draw_pixel(int x, int y, char make_updates); + Imlib_Updates imlib_image_draw_line(int x1, int y1, int x2, int y2, + char make_updates); + int imlib_clip_line(int x0, int y0, int x1, int y1, int xmin, int xmax, + int ymin, int ymax, int *clip_x0, int *clip_y0, + int *clip_x1, int *clip_y1); + void imlib_image_draw_rectangle(int x, int y, int width, int height); + void imlib_image_fill_rectangle(int x, int y, int width, int height); + void imlib_image_copy_alpha_to_image(Imlib_Image image_source, int x, + int y); + void imlib_image_copy_alpha_rectangle_to_image(Imlib_Image image_source, + int x, int y, int width, + int height, + int destination_x, + int destination_y); + void imlib_image_scroll_rect(int x, int y, int width, int height, + int delta_x, int delta_y); + void imlib_image_copy_rect(int x, int y, int width, int height, int new_x, + int new_y); + +/* polygons */ + ImlibPolygon imlib_polygon_new(void); + void imlib_polygon_free(ImlibPolygon poly); + void imlib_polygon_add_point(ImlibPolygon poly, int x, int y); + void imlib_image_draw_polygon(ImlibPolygon poly, unsigned char closed); + void imlib_image_fill_polygon(ImlibPolygon poly); + void imlib_polygon_get_bounds(ImlibPolygon poly, int *px1, int *py1, + int *px2, int *py2); + unsigned char imlib_polygon_contains_point(ImlibPolygon poly, int x, + int y); + +/* ellipses */ + void imlib_image_draw_ellipse(int xc, int yc, int a, int b); + void imlib_image_fill_ellipse(int xc, int yc, int a, int b); + +/* color ranges */ + Imlib_Color_Range imlib_create_color_range(void); + void imlib_free_color_range(void); + void imlib_add_color_to_color_range(int distance_away); + void imlib_image_fill_color_range_rectangle(int x, int y, int width, + int height, double angle); + void imlib_image_fill_hsva_color_range_rectangle(int x, int y, int width, + int height, double angle); + +/* image data */ + void imlib_image_attach_data_value(const char *key, void *data, int value, + Imlib_Data_Destructor_Function + destructor_function); + void *imlib_image_get_attached_data(const char *key); + int imlib_image_get_attached_value(const char *key); + void imlib_image_remove_attached_data_value(const char *key); + void imlib_image_remove_and_free_attached_data_value(const char *key); + +/* saving */ + void imlib_save_image(const char *filename); + void imlib_save_image_with_error_return(const char *filename, + Imlib_Load_Error * error_return); + +/* FIXME: */ +/* need to add arbitary rotation routines */ + +/* rotation/skewing */ + Imlib_Image imlib_create_rotated_image(double angle); + +/* rotation from buffer to context (without copying)*/ + void imlib_rotate_image_from_buffer(double angle, + Imlib_Image source_image); + + void imlib_blend_image_onto_image_at_angle(Imlib_Image source_image, + char merge_alpha, int source_x, + int source_y, int source_width, + int source_height, + int destination_x, + int destination_y, int angle_x, + int angle_y); + void imlib_blend_image_onto_image_skewed(Imlib_Image source_image, + char merge_alpha, int source_x, + int source_y, int source_width, + int source_height, + int destination_x, + int destination_y, int h_angle_x, + int h_angle_y, int v_angle_x, + int v_angle_y); +#ifndef X_DISPLAY_MISSING + void imlib_render_image_on_drawable_skewed(int source_x, int source_y, + int source_width, + int source_height, + int destination_x, + int destination_y, + int h_angle_x, int h_angle_y, + int v_angle_x, int v_angle_y); + void imlib_render_image_on_drawable_at_angle(int source_x, int source_y, + int source_width, + int source_height, + int destination_x, + int destination_y, + int angle_x, int angle_y); +#endif + +/* image filters */ + void imlib_image_filter(void); + Imlib_Filter imlib_create_filter(int initsize); + void imlib_context_set_filter(Imlib_Filter filter); + Imlib_Filter imlib_context_get_filter(void); + void imlib_free_filter(void); + void imlib_filter_set(int xoff, int yoff, int a, int r, int g, int b); + void imlib_filter_set_alpha(int xoff, int yoff, int a, int r, int g, + int b); + void imlib_filter_set_red(int xoff, int yoff, int a, int r, int g, int b); + void imlib_filter_set_green(int xoff, int yoff, int a, int r, int g, + int b); + void imlib_filter_set_blue(int xoff, int yoff, int a, int r, int g, int b); + void imlib_filter_constants(int a, int r, int g, int b); + void imlib_filter_divisors(int a, int r, int g, int b); + + void imlib_apply_filter(char *script, ...); + + void imlib_image_clear(void); + void imlib_image_clear_color(int r, int g, int b, int a); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am new file mode 100644 index 0000000..3476202 --- /dev/null +++ b/src/lib/Makefile.am @@ -0,0 +1,83 @@ +AUTOMAKE_OPTIONS = 1.4 foreign +MAINTAINERCLEANFILES = Makefile.in +INCLUDES = @my_includes@ -I. -I$(top_srcdir) -I$(top_builddir) + +lib_LTLIBRARIES = libImlib2.la +include_HEADERS = Imlib2.h +libImlib2_la_SOURCES = \ +api.c \ +blend.c \ +blend.h \ +color.c \ +color.h \ +color_helpers.c \ +color_helpers.h \ +colormod.c \ +colormod.h \ +common.h \ +context.c \ +context.h \ +draw.c \ +draw.h \ +dynamic_filters.c \ +dynamic_filters.h \ +ellipse.c \ +file.c \ +file.h \ +filter.c \ +filter.h \ +font.h \ +font_draw.c \ +font_load.c \ +font_main.c \ +font_query.c \ +format.c \ +format.h \ +grab.c \ +grab.h \ +grad.c \ +grad.h \ +image.c \ +image.h \ +line.c \ +loaderpath.h \ +polygon.c \ +rectangle.c \ +rend.c \ +rend.h \ +rgba.c \ +rgba.h \ +rgbadraw.c \ +rgbadraw.h \ +rotate.c \ +rotate.h \ +scale.c \ +scale.h \ +script.c \ +script.h \ +span.c \ +span.h \ +updates.c \ +updates.h \ +ximage.c \ +ximage.h + +MMX_SRCS = \ +asm_blend.S \ +asm_blend_cmod.S \ +asm_rgba.S \ +asm_rotate.S \ +asm_scale.S + +EXTRA_libImlib2_la_SOURCES = $(MMX_SRCS) + +MMX_OBJS = $(MMX_SRCS:.S=.lo) + +if BUILD_MMX +libImlib2_la_LIBADD = $(MMX_OBJS) @my_libs@ +libImlib2_la_DEPENDENCIES = $(top_builddir)/config.h $(MMX_OBJS) +else +libImlib2_la_LIBADD = @my_libs@ +libImlib2_la_DEPENDENCIES = $(top_builddir)/config.h +endif +libImlib2_la_LDFLAGS = $(LDFLAGS) -version-info 3:0:2 diff --git a/src/lib/api.c b/src/lib/api.c new file mode 100644 index 0000000..84438d2 --- /dev/null +++ b/src/lib/api.c @@ -0,0 +1,5455 @@ +#include "config.h" +#ifdef BUILD_X11 +#include +#include +#include +#else +# define X_DISPLAY_MISSING +#endif +#include +#include +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "scale.h" +#include "blend.h" +#include "span.h" +#ifdef BUILD_X11 +#include "context.h" +#include "color.h" +#include "grab.h" +#include "rend.h" +#include "rgba.h" +#include "ximage.h" +#include "draw.h" +#endif +#include "file.h" +#include "updates.h" +#include "rgbadraw.h" +#include "Imlib2.h" +#include +#include FT_FREETYPE_H +/*#ifdef HAVE_FREETYPE1_FREETYPE_FREETYPE_H +#include +#elif defined(HAVE_FREETYPE_FREETYPE_H) +#include +#else +#include +#endif +*/ +#include "font.h" +#include "grad.h" +#include "rotate.h" +#include "filter.h" +#include "dynamic_filters.h" +#include "script.h" +#include +#include "color_helpers.h" + +/* convenience macros */ +#define CAST_IMAGE(im, image) (im) = (ImlibImage *)(image) +#define CHECK_PARAM_POINTER_RETURN(func, sparam, param, ret) \ +if (!(param)) \ +{ \ + fprintf(stderr, "***** Imlib2 Developer Warning ***** :\n" \ + "\tThis program is calling the Imlib call:\n\n" \ + "\t%s();\n\n" \ + "\tWith the parameter:\n\n" \ + "\t%s\n\n" \ + "\tbeing NULL. Please fix your program.\n", func, sparam); \ + return ret; \ +} + +#define CHECK_PARAM_POINTER(func, sparam, param) \ +if (!(param)) \ +{ \ + fprintf(stderr, "***** Imlib2 Developer Warning ***** :\n" \ + "\tThis program is calling the Imlib call:\n\n" \ + "\t%s();\n\n" \ + "\tWith the parameter:\n\n" \ + "\t%s\n\n" \ + "\tbeing NULL. Please fix your program.\n", func, sparam); \ + return; \ +} + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/* internal typedefs for function pointers */ +typedef void (*Imlib_Internal_Progress_Function) (void *, char, int, int, + int, int); +typedef void (*Imlib_Internal_Data_Destructor_Function) (void *, void *); + +struct _imlibcontext; +typedef struct _imlibcontext ImlibContext; + +struct _imlibcontext { +#ifdef BUILD_X11 + Display *display; + Visual *visual; + Colormap colormap; + int depth; + Drawable drawable; + Pixmap mask; +#endif + char anti_alias; + char dither; + char blend; + Imlib_Color_Modifier color_modifier; + Imlib_Operation operation; + Imlib_Font font; + Imlib_Text_Direction direction; + double angle; + Imlib_Color color; + Imlib_Color_Range color_range; + Imlib_Image image; + Imlib_Progress_Function progress_func; + char progress_granularity; + char dither_mask; + Imlib_Filter filter; + Imlib_Rectangle cliprect; + Imlib_TTF_Encoding encoding; + + int references; + char dirty; +}; + +struct _imlibcontextitem; +typedef struct _imlibcontextitem ImlibContextItem; +struct _imlibcontextitem { + ImlibContext *context; + ImlibContextItem *below; +}; + +/* a stack of contexts -- only used by context-handling functions. */ +static ImlibContextItem *contexts = NULL; /* (ImlibContext*) imlib_context_new(); */ + +/* this is the context all functions use rely on */ +static ImlibContext *ctx = NULL; /* contexts->context; */ + +/* frees the given context including all its members */ +void +__imlib_free_context(ImlibContext * context) +{ + ImlibContextItem *next = contexts; + + if (ctx == context) + { + next = contexts->below; + free(contexts); + contexts = next; + } + + ctx = context; + + if (ctx->image) + { + imlib_free_image(); + ctx->image = NULL; + } + if (ctx->font) + { + imlib_free_font(); + ctx->font = NULL; + } + if (ctx->color_modifier) + { + imlib_free_color_modifier(); + ctx->color_modifier = NULL; + } + if (ctx->filter) + { + imlib_free_filter(); + ctx->filter = NULL; + } + + free(ctx); + ctx = next->context; +} + +Imlib_Context +imlib_context_new(void) +{ + ImlibContext *context = malloc(sizeof(ImlibContext)); + +#ifdef BUILD_X11 + context->display = NULL; + context->visual = NULL; + context->colormap = 0; + context->depth = 0; + context->drawable = 0; + context->mask = 0; +#endif + context->anti_alias = 1; + context->dither = 0; + context->blend = 1; + context->color_modifier = NULL; + context->operation = IMLIB_OP_COPY; + context->font = NULL; + context->direction = IMLIB_TEXT_TO_RIGHT; + context->angle = 0.0; + context->color.alpha = 255; + context->color.red = 255; + context->color.green = 255; + context->color.blue = 255; + context->color_range = NULL; + context->image = NULL; + context->progress_func = NULL; + context->progress_granularity = 0; + context->dither_mask = 0; + context->filter = NULL; + context->cliprect.x = 0; + context->cliprect.y = 0; + context->cliprect.w = 0; + context->cliprect.h = 0; + context->encoding = IMLIB_TTF_ENCODING_ISO_8859_1; + + context->references = 0; + context->dirty = 0; + + return (Imlib_Context) context; +} + +/* frees the given context if it doesn't have any reference anymore. The + last (default) context can never be freed. + If context is the current context, the context below will be made the + current context. +*/ +void +imlib_context_free(Imlib_Context context) +{ + ImlibContext *c = (ImlibContext *) context; + + CHECK_PARAM_POINTER("imlib_context_free", "context", context); + if (c == ctx && !contexts->below) + return; + + if (c->references == 0) + __imlib_free_context(c); + else + c->dirty = 1; +} + +void +imlib_context_push(Imlib_Context context) +{ + ImlibContextItem *item; + + CHECK_PARAM_POINTER("imlib_context_push", "context", context); + ctx = (ImlibContext *) context; + + item = malloc(sizeof(ImlibContextItem)); + item->context = ctx; + item->below = contexts; + contexts = item; + + ctx->references++; +} + +void +imlib_context_pop(void) +{ + ImlibContextItem *item = contexts; + ImlibContext *current_ctx = item->context; + + if (!item->below) + return; + + contexts = item->below; + ctx = contexts->context; + current_ctx->references--; + if (current_ctx->dirty && current_ctx->references <= 0) + __imlib_free_context(current_ctx); + + free(item); +} + +Imlib_Context +imlib_context_get(void) +{ + return (Imlib_Context) ctx; +} + +/* context setting/getting functions */ + +/** + * @param x The top left x coordinate of the rectangle. + * @param y The top left y coordinate of the rectangle. + * @param w The width of the rectangle. + * @param h The height of the rectangle. + * + * Sets the rectangle of the current context. + **/ +void +imlib_context_set_cliprect(int x, int y, int w, int h) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->cliprect.x = x; + ctx->cliprect.y = y; + ctx->cliprect.w = w; + ctx->cliprect.h = h; +} + +void +imlib_context_get_cliprect(int *x, int *y, int *w, int *h) +{ + if (!ctx) + ctx = imlib_context_new(); + *x = ctx->cliprect.x; + *y = ctx->cliprect.y; + *w = ctx->cliprect.w; + *h = ctx->cliprect.h; +} + +#ifdef BUILD_X11 +/** + * @param display Current display to bu used. + * + * Sets the current X display to be used for rendering of images to + * drawables. You do not need to set this if you do not intend to + * render an image to an X drawable. If you do you will need to set + * this. If you change displays just set this to the new display + * pointer. Do not use a Display pointer if you have closed that + * display already - also note that if you close a display connection + * and continue to render using Imlib2 without setting the display + * pointer to NULL or something new, crashes may occur. + */ +void +imlib_context_set_display(Display * display) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->display = display; +} + +/** + * @return The current display. + * + * Returns the current display used for Imlib2's display context. + */ +Display * +imlib_context_get_display(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->display; +} + +/** + * @param visual Current visual to use. + * + * Sets the current visual to use when rendering images to + * drawables or producing pixmaps. You need to set this for anything to + * render to a drawable or produce any pixmaps (this can be the default + * visual). + */ +void +imlib_context_set_visual(Visual * visual) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->visual = visual; + ctx->depth = imlib_get_visual_depth(ctx->display, ctx->visual); +} + +/** + * @return The current visual. + * + * Returns the current visual used for Imlib2's context. + */ +Visual * +imlib_context_get_visual(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->visual; +} + +/** + * @param colormap Colormap to use. + * + * Sets the colormap to use when rendering to drawables and allocating + * colors. You must set this to the colormap you are using to render any + * images or produce any pixmaps (this can be the default colormap). + */ +void +imlib_context_set_colormap(Colormap colormap) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->colormap = colormap; +} + +/** + * @return The current colormap. + * + * Returns the current Colormap used for Imlib2's context. + */ +Colormap +imlib_context_get_colormap(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->colormap; +} + +/** + * @param drawable An X drawable. + * + * Sets the X drawable to which images will be rendered when you call + * a render call in Imlib2. This may be either a pixmap or a + * window. You must set this to render anything. + */ +void +imlib_context_set_drawable(Drawable drawable) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->drawable = drawable; +} + +/** + * @return The current drawable. + * + * Returns the current Drawable used for Imlib2's context. + */ +Drawable +imlib_context_get_drawable(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->drawable; +} + +/** + * @param mask An 1-bit deep pixmap. + * + * Sets the 1-bit deep pixmap to be drawn to when rendering to generate + * a mask pixmap. This is only useful if the image you are rendering + * has alpha. Set this to 0 to not render a pixmap mask. + */ +void +imlib_context_set_mask(Pixmap mask) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->mask = mask; +} + +/** + * @return The current pixmap. + * + * Returns the current pixmap destination to be used to render a mask into. + */ +Pixmap +imlib_context_get_mask(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->mask; +} +#endif + +/** + * @param dither_mask The dither mask flag. + * + * Selects if, you are rendering to a mask, or producing pixmap masks + * from images, if the mask is to be dithered or not. passing in 1 for + * dither_mask means the mask pixmap will be dithered, 0 means it will + * not be dithered. + */ +void +imlib_context_set_dither_mask(char dither_mask) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->dither_mask = dither_mask; +} + +/** + * @return The current dither mask flag. + * + * Returns the current mode for dithering pixmap masks. 1 means + * dithering is enabled and 0 means it is not. + */ +char +imlib_context_get_dither_mask(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->dither_mask; +} + +/** + * @param anti_alias The anti alias flag. + * + * Toggles "anti-aliased" scaling of images. This + * isn't quite correct since it's actually super and sub pixel + * sampling that it turns on and off, but anti-aliasing is used for + * having "smooth" edges to lines and shapes and this means when + * images are scaled they will keep their smooth appearance. Passing + * in 1 turns this on and 0 turns it off. + */ +void +imlib_context_set_anti_alias(char anti_alias) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->anti_alias = anti_alias; +} + +/** + * @return The current anti alias flag. + * + * Returns if Imlib2 currently will smoothly scale images. 1 means it + * will and 0 means it will not. + */ +char +imlib_context_get_anti_alias(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->anti_alias; +} + +/** + * @param dither The dithering flag. + * + * Sets the dithering flag for rendering to a drawable or when pixmaps + * are produced. This affects the color image appearance by enabling + * dithering. Dithering slows down rendering but produces considerably + * better results. this option has no effect foe rendering in 24 bit + * and up, but in 16 bit and lower it will dither, producing smooth + * gradients and much better quality images. setting dither to 1 + * enables it and 0 disables it. + */ +void +imlib_context_set_dither(char dither) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->dither = dither; +} + +/** + * @return The current dithering flag. + * + * Returns if image data is rendered with dithering currently. 1 means + * yes and 0 means no. + */ +char +imlib_context_get_dither(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->dither; +} + +/** + * @param blend The blending flag. + * + * When rendering an image to a drawable, Imlib2 is able to blend the + * image directly onto the drawable during rendering. Setting this to 1 + * will enable this. If the image has no alpha channel this has no + * effect. Setting it to 0 will disable this. + */ +void +imlib_context_set_blend(char blend) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->blend = blend; +} + +/** + * @return The current blending flag. + * + * Returns if Imlib2 will blend images onto a drawable whilst + * rendering to that drawable. 1 means yes and 0 means no. + */ +char +imlib_context_get_blend(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->blend; +} + +/** + * @param color_modifier Current color modifier. + * + * Sets the current color modifier used for rendering pixmaps or + * images to a drawable or images onto other images. Color modifiers + * are lookup tables that map the values in the red, green, blue and + * alpha channels to other values in the same channel when rendering, + * allowing for fades, color correction etc. to be done whilst + * rendering. pass in NULL as the color_modifier to disable the color + * modifier for rendering. + */ +void +imlib_context_set_color_modifier(Imlib_Color_Modifier color_modifier) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->color_modifier = color_modifier; +} + +/** + * @return The current color modifier. + * + * Returns the current color modifier being used. + */ +Imlib_Color_Modifier +imlib_context_get_color_modifier(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->color_modifier; +} + +/** + * @param operation + * + * When Imlib2 draws an image onto another or an image onto a drawable + * it is able to do more than just blend the result on using the given + * alpha channel of the image. It is also able to do saturating + * additive, subtractive and a combination of the both (called reshade) + * rendering. The default mode is IMLIB_OP_COPY. you can also set it to + * IMLIB_OP_ADD, IMLIB_OP_SUBTRACT or IMLIB_OP_RESHADE. Use this + * function to set the rendering operation. IMLIB_OP_COPY performs + * basic alpha blending: DST = (SRC * A) + (DST * (1 - + * A)). IMLIB_OP_ADD does DST = DST + (SRC * A). IMLIB_OP_SUBTRACT does + * DST = DST - (SRC * A) and IMLIB_OP_RESHADE does DST = DST + (((SRC - + * 0.5) / 2) * A). + */ +void +imlib_context_set_operation(Imlib_Operation operation) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->operation = operation; +} + +/** + * @return The current operation mode. + * + * Returns the current operation mode. + */ +Imlib_Operation +imlib_context_get_operation(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->operation; +} + +/** + * @param font Current font. + * + * Sets the current font to use when rendering text. you should load + * the font first with imlib_load_font(). + */ +void +imlib_context_set_font(Imlib_Font font) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->font = font; +} + +/** + * @return The current font. + * + * Returns the current font. + */ +Imlib_Font +imlib_context_get_font(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->font; +} + +/** + * @param direction Text direction. + * + * Sets the direction in which to draw text in terms of simple 90 + * degree orientations or an arbitrary angle. The direction can be one + * of IMLIB_TEXT_TO_RIGHT, IMLIB_TEXT_TO_LEFT, IMLIB_TEXT_TO_DOWN, + * IMLIB_TEXT_TO_UP or IMLIB_TEXT_TO_ANGLE. The default is + * IMLIB_TEXT_TO_RIGHT. If you use IMLIB_TEXT_TO_ANGLE, you will also + * have to set the angle with imlib_context_set_angle(). + */ +void +imlib_context_set_direction(Imlib_Text_Direction direction) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->direction = direction; +} + +/** + * @param angle Angle of the text strings. + * + * Sets the angle at which text strings will be drawn if the text + * direction has been set to IMLIB_TEXT_TO_ANGLE with + * imlib_context_set_direction(). + */ +void +imlib_context_set_angle(double angle) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->angle = angle; +} + +/** + * @return The current angle of the text strings. + * + * Returns the current angle used to render text at if the direction + * is IMLIB_TEXT_TO_ANGLE. + */ +double +imlib_context_get_angle(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->angle; +} + +/** + * @return The current direction of the text. + * + * Returns the current direction to render text in. + */ +Imlib_Text_Direction +imlib_context_get_direction(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->direction; +} + +/** + * @param red Red channel of the current color. + * @param green Green channel of the current color. + * @param blue Blue channel of the current color. + * @param alpha Alpha channel of the current color. + * + * Sets the color with which text, lines and rectangles are drawn when + * being rendered onto an image. Values for @p red, @p green, @p blue + * and @p alpha are between 0 and 255 - any other values have + * undefined results. + */ +void +imlib_context_set_color(int red, int green, int blue, int alpha) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->color.red = red; + ctx->color.green = green; + ctx->color.blue = blue; + ctx->color.alpha = alpha; +} + +/** + * @param red Red channel of the current color. + * @param green Green channel of the current color. + * @param blue Blue channel of the current color. + * @param alpha Alpha channel of the current color. + * + * Returns the current color for rendering text, rectangles and lines. + */ +void +imlib_context_get_color(int *red, int *green, int *blue, int *alpha) +{ + if (!ctx) + ctx = imlib_context_new(); + *red = ctx->color.red; + *green = ctx->color.green; + *blue = ctx->color.blue; + *alpha = ctx->color.alpha; +} + +/** + * @return The current color. + * + * Returns the current color as a color struct. Do NOT free this + * pointer. + */ +Imlib_Color * +imlib_context_get_imlib_color(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return &ctx->color; +} + +/** + * @param hue Hue channel of the current color. + * @param saturation Saturation channel of the current color. + * @param value Value channel of the current color. + * @param alpha Alpha channel of the current color. + * + * Sets the color in HSVA space. Values for @p hue are between 0 and 360, + * values for @p saturation and @p value between 0 and 1, and values for + * @p alpha are between 0 and 255 - any other values have undefined + * results. + */ +void +imlib_context_set_color_hsva(float hue, float saturation, float value, + int alpha) +{ + int r, g, b; + + __imlib_hsv_to_rgb(hue, saturation, value, &r, &g, &b); + imlib_context_set_color(r, g, b, alpha); +} + +/** + * @param hue Hue channel of the current color. + * @param saturation Saturation channel of the current color. + * @param value Value channel of the current color. + * @param alpha Alpha channel of the current color. + * + * Returns the current color for rendering text, rectangles and lines + * in HSVA space. + */ +void +imlib_context_get_color_hsva(float *hue, float *saturation, float *value, + int *alpha) +{ + int r, g, b; + + imlib_context_get_color(&r, &g, &b, alpha); + __imlib_rgb_to_hsv(r, g, b, hue, saturation, value); +} + +/** + * @param hue Hue channel of the current color. + * @param lightness Lightness channel of the current color. + * @param saturation Saturation channel of the current color. + * @param alpha Alpha channel of the current color. + * + * Sets the color in HLSA space. Values for @p hue are between 0 and 360, + * values for @p lightness and @p saturation between 0 and 1, and values for + * @p alpha are between 0 and 255 - any other values have undefined + * results. + */ +void +imlib_context_set_color_hlsa(float hue, float lightness, float saturation, + int alpha) +{ + int r, g, b; + + __imlib_hls_to_rgb(hue, lightness, saturation, &r, &g, &b); + imlib_context_set_color(r, g, b, alpha); +} + +/** + * @param hue Hue channel of the current color. + * @param lightness Lightness channel of the current color. + * @param saturation Saturation channel of the current color. + * @param alpha Alpha channel of the current color. + * + * Returns the current color for rendering text, rectangles and lines + * in HLSA space. + */ +void +imlib_context_get_color_hlsa(float *hue, float *lightness, float *saturation, + int *alpha) +{ + int r, g, b; + + imlib_context_get_color(&r, &g, &b, alpha); + __imlib_rgb_to_hls(r, g, b, hue, lightness, saturation); +} + +/** + * @param cyan Cyan channel of the current color. + * @param magenta Magenta channel of the current color. + * @param yellow Yellow channel of the current color. + * @param alpha Alpha channel of the current color. + * + * Sets the color in CMYA space. Values for @p cyan, @p magenta, @p yellow and + * @p alpha are between 0 and 255 - any other values have undefined + * results. + */ +void +imlib_context_set_color_cmya(int cyan, int magenta, int yellow, int alpha) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->color.red = 255 - cyan; + ctx->color.green = 255 - magenta; + ctx->color.blue = 255 - yellow; + ctx->color.alpha = alpha; +} + +/** + * @param cyan Cyan channel of the current color. + * @param magenta Magenta channel of the current color. + * @param yellow Yellow channel of the current color. + * @param alpha Alpha channel of the current color. + * + * Returns the current color for rendering text, rectangles and lines + * in CMYA space. + */ +void +imlib_context_get_color_cmya(int *cyan, int *magenta, int *yellow, int *alpha) +{ + if (!ctx) + ctx = imlib_context_new(); + *cyan = 255 - ctx->color.red; + *magenta = 255 - ctx->color.green; + *yellow = 255 - ctx->color.blue; + *alpha = ctx->color.alpha; +} + +/** + * @param color_range Color range. + * + * Sets the current color range to use for rendering gradients. + */ +void +imlib_context_set_color_range(Imlib_Color_Range color_range) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->color_range = color_range; +} + +/** + * @return The current color range. + * + * Returns the current color range being used for gradients. + */ +Imlib_Color_Range +imlib_context_get_color_range(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->color_range; +} + +/** + * @param progress_function A progress function. + * + * Sets the progress function to be called back whilst loading + * images. Set this to the function to be called, or set it to NULL to + * disable progress callbacks whilst loading. + */ +void +imlib_context_set_progress_function(Imlib_Progress_Function progress_function) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->progress_func = progress_function; +} + +/** + * @return The current progress function. + * + * Returns the current progress function being used. + */ +Imlib_Progress_Function +imlib_context_get_progress_function(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->progress_func; +} + +/** + * @param progress_granularity A char. + * + * This hints as to how often to call the progress callback. 0 means + * as often as possible. 1 means whenever 15 more of the image has been + * decoded, 10 means every 10% of the image decoding, 50 means every + * 50% and 100 means only call at the end. Values outside of the range + * 0-100 are undefined. + */ +void +imlib_context_set_progress_granularity(char progress_granularity) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->progress_granularity = progress_granularity; +} + +/** + * @return The current progress granularity + * + * Returns the current progress granularity being used. + */ +char +imlib_context_get_progress_granularity(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->progress_granularity; +} + +/** + * @param image Current image. + * + * Sets the current image Imlib2 will be using with its function calls. + */ +void +imlib_context_set_image(Imlib_Image image) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->image = image; +} + +/** + * @return The current image. + * + * Returns the current context image. + */ +Imlib_Image +imlib_context_get_image(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->image; +} + +void +imlib_context_set_TTF_encoding(Imlib_TTF_Encoding encoding) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->encoding = encoding; +} + +Imlib_TTF_Encoding +imlib_context_get_TTF_encoding(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->encoding; +} + +/* imlib api */ + +/** + * @return The current image size. + * + * Returns the current size of the image cache in bytes. The cache is + * a unified cache used for image data AND pixmaps. + */ +int +imlib_get_cache_size(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return __imlib_GetCacheSize(); +} + +/** + * @param bytes Cache size. + * + * Sets the cache size. The size is in bytes. Setting the cache size to + * 0 effectively flushes the cache and keeps the cache size at 0 until + * set to another value. Whenever you set the cache size Imlib2 will + * flush as many old images and pixmap from the cache as needed until + * the current cache usage is less than or equal to the cache size. + */ +void +imlib_set_cache_size(int bytes) +{ + if (!ctx) + ctx = imlib_context_new(); + __imlib_SetCacheSize(bytes); +} + +/** + * @return The current number of colors. + * + * Gets the number of colors Imlib2 currently at a maximum is allowed + * to allocate for rendering. The default is 256. + */ +int +imlib_get_color_usage(void) +{ + if (!ctx) + ctx = imlib_context_new(); +#ifdef BUILD_X11 + return (int)_max_colors; +#else + return 256; +#endif +} + +/** + * @param max Maximum number of colors. + * + * Sets the maximum number of colors you would like Imlib2 to allocate + * for you when rendering. The default is 256. This has no effect in + * depths greater than 8 bit. + */ +void +imlib_set_color_usage(int max) +{ + if (!ctx) + ctx = imlib_context_new(); +#ifdef BUILD_X11 + if (max < 2) + max = 2; + else if (max > 256) + max = 256; + _max_colors = max; +#endif +} + +/** + * If you want Imlib2 to forcibly flush any cached loaders it has and + * re-load them from disk (this is useful if the program just + * installed a new loader and does not want to wait till Imlib2 deems + * it an optimal time to rescan the loaders) + */ +void +imlib_flush_loaders(void) +{ + if (!ctx) + ctx = imlib_context_new(); + __imlib_RemoveAllLoaders(); +} + +#ifdef BUILD_X11 +/** + * @param display The current display + * @param visual The current visual + * @return + * + * Convenience function that returns the depth of a visual for that + * display. + */ +int +imlib_get_visual_depth(Display * display, Visual * visual) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_get_visual_depth", "display", display, 0); + CHECK_PARAM_POINTER_RETURN("imlib_get_visual_depth", "visual", visual, 0); + return __imlib_XActualDepth(display, visual); +} + +/** + * @param display The current display + * @param screen The screen + * @param depth_return The depth of the returned visual. + * @return The best visual. + * + * Returns the visual for the display @p display and the screen @p + * screen that Imlib2 thinks + * will give you the best quality output. @p depth_return should point to + * an int that will be filled with the depth of that visual too. + */ +Visual * +imlib_get_best_visual(Display * display, int screen, int *depth_return) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_get_best_visual", "display", display, + NULL); + CHECK_PARAM_POINTER_RETURN("imlib_get_best_visual", "depth_return", + depth_return, NULL); + return __imlib_BestVisual(display, screen, depth_return); +} +#endif + +/** + * @param file Image file. + * @return An image handle. + * + * Loads an image from disk located at the path specified by + * @p file. Please see the section \ref loading for more + * detail. Returns an image handle on success or NULL on failure. + */ +Imlib_Image +imlib_load_image(const char *file) +{ + Imlib_Image im = NULL; + Imlib_Image prev_ctxt_image; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_load_image", "file", file, NULL); + prev_ctxt_image = ctx->image; + im = __imlib_LoadImage(file, (ImlibProgressFunction) ctx->progress_func, + ctx->progress_granularity, 0, 0, NULL); + ctx->image = prev_ctxt_image; + return (Imlib_Image) im; +} + +/** + * @param file Image file. + * @return An image handle. + * + * Loads an image from disk located at the path specified by + * @p file. This forces the image data to be decoded at load time too, + * instead of decoding being deferred until it is needed. Returns an + * image handle on success or NULL on failure. + */ +Imlib_Image +imlib_load_image_immediately(const char *file) +{ + Imlib_Image im = NULL; + Imlib_Image prev_ctxt_image; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_load_image_immediately", "file", file, + NULL); + prev_ctxt_image = ctx->image; + im = __imlib_LoadImage(file, (ImlibProgressFunction) ctx->progress_func, + ctx->progress_granularity, 1, 0, NULL); + ctx->image = prev_ctxt_image; + return (Imlib_Image) im; +} + +/** + * @param file Image file. + * @return An image handle. + * + * Loads the image without looking in the cache first. Returns an + * image handle on success or NULL on failure. + */ +Imlib_Image +imlib_load_image_without_cache(const char *file) +{ + Imlib_Image im = NULL; + Imlib_Image prev_ctxt_image; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_load_image_without_cache", "file", + file, NULL); + prev_ctxt_image = ctx->image; + im = __imlib_LoadImage(file, (ImlibProgressFunction) ctx->progress_func, + ctx->progress_granularity, 0, 1, NULL); + ctx->image = prev_ctxt_image; + return (Imlib_Image) im; +} + +/** + * @param file Image file. + * @return An image handle. + * + * Loads the image without deferred image data decoding (i.e. it is + * decoded straight away) and without looking in the cache. Returns an + * image handle on success or NULL on failure. + */ +Imlib_Image +imlib_load_image_immediately_without_cache(const char *file) +{ + Imlib_Image im = NULL; + Imlib_Image prev_ctxt_image; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_load_image_immediately_without_cache", + "file", file, NULL); + prev_ctxt_image = ctx->image; + im = __imlib_LoadImage(file, (ImlibProgressFunction) ctx->progress_func, + ctx->progress_granularity, 1, 1, NULL); + ctx->image = prev_ctxt_image; + return (Imlib_Image) im; +} + +/** + * @param file Image file. + * @param error_return The returned error. + * @return An image handle. + * + * Loads an image at the path @p file on disk. If it succeeds it returns + * a valid image handle, if not NULL is returned and @p error_return + * is set to the detail of the error. + */ +Imlib_Image +imlib_load_image_with_error_return(const char *file, + Imlib_Load_Error * error_return) +{ + Imlib_Image im = NULL; + ImlibLoadError er; + Imlib_Image prev_ctxt_image; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_load_image_with_error_return", "file", + file, NULL); + if (!__imlib_FileExists(file)) + { + *error_return = IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST; + return NULL; + } + if (__imlib_FileIsDir(file)) + { + *error_return = IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY; + return NULL; + } + if (!__imlib_FileCanRead(file)) + { + *error_return = IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ; + return NULL; + } + prev_ctxt_image = ctx->image; + im = (Imlib_Image) __imlib_LoadImage(file, + (ImlibProgressFunction) + ctx->progress_func, + ctx->progress_granularity, 1, 0, &er); + ctx->image = prev_ctxt_image; + if (im) + *error_return = IMLIB_LOAD_ERROR_NONE; + else + { + if (er == IMLIB_LOAD_ERROR_NONE) + *error_return = IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT; + else + *error_return = (Imlib_Load_Error) er; + } + return im; +} + +/** + * Frees the image that is set as the current image in Imlib2's context. + */ +void +imlib_free_image(void) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_free_image", "image", ctx->image); + __imlib_FreeImage(ctx->image); + ctx->image = NULL; +} + +/** + * Frees the current image in Imlib2's context AND removes it from the + * cache. + */ +void +imlib_free_image_and_decache(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_free_image_and_decache", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + SET_FLAG(im->flags, F_INVALID); + __imlib_FreeImage(im); + ctx->image = NULL; +} + +/** + * Returns the width in pixels of the current image in Imlib2's context. + */ +int +imlib_image_get_width(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_image_get_width", "image", ctx->image, 0); + CAST_IMAGE(im, ctx->image); + return im->w; +} + +/** + * Returns the height in pixels of the current image in Imlib2's context. + */ +int +imlib_image_get_height(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_image_get_height", "image", ctx->image, 0); + CAST_IMAGE(im, ctx->image); + return im->h; +} + +/** + * @return The current filename. + * + * Returns the filename for the file that is set as the current + * context. The pointer returned is only valid as long as no operations + * cause the filename of the image to change. Saving the file with a + * different name would cause this. It is suggested you duplicate the + * string if you wish to continue to use the string for later + * processing. Do not free the string pointer returned by this + * function. + */ +const char * +imlib_image_get_filename(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_image_get_filename", "image", ctx->image, + 0); + CAST_IMAGE(im, ctx->image); + /* strdup() the returned value if you want to alter it! */ + return (const char *)(im->file); +} + +/** + * @return A pointer to the image data. + * + * Returns a pointer to the image data in the image set as the image + * for the current context. When you get this pointer it is assumed you + * are planning on writing to the data, thus once you do this the image + * can no longer be used for caching - in fact all images cached from + * this one will also be affected when you put the data back. If this + * matters it is suggested you clone the image first before playing + * with the image data. The image data is returned in the format of a + * DATA32 (32 bits) per pixel in a linear array ordered from the top + * left of the image to the bottom right going from left to right each + * line. Each pixel has the upper 8 bits as the alpha channel and the + * lower 8 bits are the blue channel - so a pixel's bits are ARGB (from + * most to least significant, 8 bits per channel). You must put the + * data back at some point. + */ +DATA32 * +imlib_image_get_data(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_image_get_data", "image", ctx->image, + NULL); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!im->data) + return NULL; + __imlib_DirtyImage(im); + return im->data; +} + +/** + * @return A pointer to the image data. + * + * Functions the same way as imlib_image_get_data(), but returns a + * pointer expecting the program to NOT write to the data returned (it + * is for inspection purposes only). Writing to this data has undefined + * results. The data does not need to be put back. + */ +DATA32 * +imlib_image_get_data_for_reading_only(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_image_get_data_for_reading_only", + "image", ctx->image, NULL); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!im->data) + return NULL; + return im->data; +} + +/** + * @param data The pointer to the image data. + * + * Puts back @p data when it was obtained by + * imlib_image_get_data(). @p data must be the same pointer returned + * by imlib_image_get_data(). This operated on the current context + * image. + */ +void +imlib_image_put_back_data(DATA32 * data) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_put_back_data", "image", ctx->image); + CHECK_PARAM_POINTER("imlib_image_put_back_data", "data", data); + CAST_IMAGE(im, ctx->image); + __imlib_DirtyImage(im); + data = NULL; +} + +/** + * @return Current alpha channel flag. + * + * Returns 1 if the current context image has an alpha channel, or 0 + * if it does not (the alpha data space is still there and available - + * just "unused"). + */ +char +imlib_image_has_alpha(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_image_has_alpha", "image", ctx->image, 0); + CAST_IMAGE(im, ctx->image); + if (IMAGE_HAS_ALPHA(im)) + return 1; + return 0; +} + +/** + * By default Imlib2 will not check the timestamp of an image on disk + * and compare it with the image in its cache - this is to minimize + * disk activity when using the cache. Call this function and it will + * flag the current context image as being liable to change on disk + * and Imlib2 will check the timestamp of the image file on disk and + * compare it with the cached image when it next needs to use this + * image in the cache. + */ +void +imlib_image_set_changes_on_disk(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_set_never_changes_on_disk", "image", + ctx->image); + CAST_IMAGE(im, ctx->image); + SET_FLAG(im->flags, F_ALWAYS_CHECK_DISK); +} + +/** + * @param border The border of the image. + * + * Fills the Imlib_Border structure to which @p border points to with the + * values of the border of the current context image. The border is the + * area at the edge of the image that does not scale with the rest of + * the image when resized - the borders remain constant in size. This + * is useful for scaling bevels at the edge of images differently to + * the image center. + */ +void +imlib_image_get_border(Imlib_Border * border) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_get_border", "image", ctx->image); + CHECK_PARAM_POINTER("imlib_image_get_border", "border", border); + CAST_IMAGE(im, ctx->image); + border->left = im->border.left; + border->right = im->border.right; + border->top = im->border.top; + border->bottom = im->border.bottom; +} + +/** + * @param border The border of the image. + * + * Sets the border of the current context image to the values contained + * in the Imlib_Border structure @p border points to. + */ +void +imlib_image_set_border(Imlib_Border * border) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_set_border", "image", ctx->image); + CHECK_PARAM_POINTER("imlib_image_set_border", "border", border); + CAST_IMAGE(im, ctx->image); + if ((im->border.left == border->left) + && (im->border.right == border->right) + && (im->border.top == border->top) + && (im->border.bottom == border->bottom)) + return; + im->border.left = border->left; + im->border.right = border->right; + im->border.top = border->top; + im->border.bottom = border->bottom; + __imlib_DirtyPixmapsForImage(im); +} + +/** + * @param format Format of the image. + * + * Sets the format of the current image. This is used for when you + * wish to save an image in a different format that it was loaded in, + * or if the image currently has no file format associated with it. + */ +void +imlib_image_set_format(const char *format) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_set_format", "image", ctx->image); + CHECK_PARAM_POINTER("imlib_image_set_format", "format", format); + CAST_IMAGE(im, ctx->image); + if (im->format) + free(im->format); + if (format) + im->format = strdup(format); + else + im->format = NULL; + if (!(im->flags & F_FORMAT_IRRELEVANT)) + { + __imlib_DirtyImage(im); + } +} + +/** + * @param irrelevant Irrelevant format flag. + * + * Sets if the format value of the current image is irrelevant for + * caching purposes - by default it is. pass irrelevant as 1 to make it + * irrelevant and 0 to make it relevant for caching. + */ +void +imlib_image_set_irrelevant_format(char irrelevant) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_set_irrelevant_format", "image", + ctx->image); + CAST_IMAGE(im, ctx->image); + if (irrelevant) + { + SET_FLAG(im->flags, F_FORMAT_IRRELEVANT); + } + else + { + UNSET_FLAG(im->flags, F_FORMAT_IRRELEVANT); + } +} + +/** + * @param irrelevant Irrelevant border flag. + * + * Sets if the border of the current image is irrelevant for caching + * purposes. By default it is. Set irrelevant to 1 to make it + * irrelevant, and 0 to make it relevant. + */ +void +imlib_image_set_irrelevant_border(char irrelevant) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_set_irrelevant_border", "image", + ctx->image); + CAST_IMAGE(im, ctx->image); + if (irrelevant) + { + SET_FLAG(im->flags, F_BORDER_IRRELEVANT); + } + else + { + UNSET_FLAG(im->flags, F_BORDER_IRRELEVANT); + } +} + +/** + * @param irrelevant Irrelevant alpha flag. + * + * Sets if the alpha channel status of the current image (i.e. if + * there is or is not one) is important for caching purposes. By + * default it is not. Set irrelevant to 1 to make it irrelevant and 0 + * to make it relevant. + */ +void +imlib_image_set_irrelevant_alpha(char irrelevant) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_set_irrelevant_alpha", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if (irrelevant) + { + SET_FLAG(im->flags, F_ALPHA_IRRELEVANT); + } + else + { + UNSET_FLAG(im->flags, F_ALPHA_IRRELEVANT); + } +} + +/** + * @return Current image format. + * + * Returns the current image's format. Do not free this + * string. Duplicate it if you need it for later use. + */ +char * +imlib_image_format(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_image_format", "image", ctx->image, NULL); + CAST_IMAGE(im, ctx->image); + return im->format; +} + +/** + * @param has_alpha Alpha flag. + * + * Sets the alpha flag for the current image. Set @p has_alpha to 1 to + * enable the alpha channel in the current image, or 0 to disable it. + */ +void +imlib_image_set_has_alpha(char has_alpha) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_set_has_alpha", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if (has_alpha) + SET_FLAG(im->flags, F_HAS_ALPHA); + else + UNSET_FLAG(im->flags, F_HAS_ALPHA); +} + +#ifdef BUILD_X11 +/** + * @param pixmap_return The returned pixmap. + * @param mask_return The returned mask. + * + * Creates a pixmap of the current image (and a mask if the image has + * an alpha value) and return the id's of the pixmap and mask to + * @p pixmap_return and @p mask_return pixmap id's. You must free these + * pixmaps using Imlib2's free function imlib_free_pixmap_and_mask();. + */ +void +imlib_render_pixmaps_for_whole_image(Pixmap * pixmap_return, + Pixmap * mask_return) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_render_pixmaps_for_whole_image", "image", + ctx->image); + CHECK_PARAM_POINTER("imlib_render_pixmaps_for_whole_image", + "pixmap_return", pixmap_return); + CHECK_PARAM_POINTER("imlib_render_pixmaps_for_whole_image", "mask_return", + mask_return); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_CreatePixmapsForImage(ctx->display, ctx->drawable, ctx->visual, + ctx->depth, ctx->colormap, im, pixmap_return, + mask_return, 0, 0, im->w, im->h, im->w, + im->h, 0, ctx->dither, ctx->dither_mask, + ctx->color_modifier); +} + +/** + * @param pixmap_return The returned pixmap. + * @param mask_return The returned mask. + * @param width Width of the pixmap. + * @param height Height of the pixmap. + * + * Works just like imlib_render_pixmaps_for_whole_image(), but will + * scale the output result to the width @p width and height @p height + * specified. Scaling + * is done before depth conversion so pixels used for dithering don't + * grow large. + */ +void +imlib_render_pixmaps_for_whole_image_at_size(Pixmap * pixmap_return, + Pixmap * mask_return, int width, + int height) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_render_pixmaps_for_whole_image_at_size", + "image", ctx->image); + CHECK_PARAM_POINTER("imlib_render_pixmaps_for_whole_image_at_size", + "pixmap_return", pixmap_return); + CHECK_PARAM_POINTER("imlib_render_pixmaps_for_whole_image_at_size", + "mask_return", mask_return); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + + if (!(im->data)) + return; + __imlib_CreatePixmapsForImage(ctx->display, ctx->drawable, ctx->visual, + ctx->depth, ctx->colormap, im, pixmap_return, + mask_return, 0, 0, im->w, im->h, width, + height, ctx->anti_alias, ctx->dither, + ctx->dither_mask, ctx->color_modifier); +} + +/** + * @param pixmap The pixmap. + * + * Frees @p pixmap (and any mask generated in association with that + * pixmap). The pixmap will remain cached until the image the pixmap + * was generated from is dirtied or decached, or the cache is flushed. + */ +void +imlib_free_pixmap_and_mask(Pixmap pixmap) +{ + if (!ctx) + ctx = imlib_context_new(); + __imlib_FreePixmap(ctx->display, pixmap); +} + +/** + * @param x X coordinate of the pixel. + * @param y Y coordinate of the pixel. + * + * Renders the current image onto the current drawable at the (@p x, @p y) + * pixel location specified without scaling. + */ +void +imlib_render_image_on_drawable(int x, int y) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_render_image_on_drawable", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_RenderImage(ctx->display, im, ctx->drawable, ctx->mask, + ctx->visual, ctx->colormap, ctx->depth, 0, 0, im->w, + im->h, x, y, im->w, im->h, 0, ctx->dither, ctx->blend, + ctx->dither_mask, ctx->color_modifier, ctx->operation); +} + +/** + * @param x X coordinate of the pixel. + * @param y Y coordinate of the pixel. + * @param width Width of the rendered image. + * @param height Height of the rendered image. + * + * Renders the current image onto the current drawable at the (@p x, @p y) + * location specified AND scale the image to the width @p width and height + * @p height. + */ +void +imlib_render_image_on_drawable_at_size(int x, int y, int width, int height) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_render_image_on_drawable_at_size", "image", + ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_RenderImage(ctx->display, im, ctx->drawable, ctx->mask, + ctx->visual, ctx->colormap, ctx->depth, 0, 0, im->w, + im->h, x, y, width, height, ctx->anti_alias, + ctx->dither, ctx->blend, ctx->dither_mask, + ctx->color_modifier, ctx->operation); +} + +/** + * @param source_x X coordinate of the source image. + * @param source_y Y coordinate of the source image. + * @param source_width Width of the source image. + * @param source_height Height of the source image. + * @param x X coordinate of the destination image. + * @param y Y coordinate of the destination image. + * @param width Width of the destination image. + * @param height Height of the destination image. + * + * Renders the source (@p source_x, @p source_y, @p source_width, @p source_height) pixel + * rectangle from the + * current image onto the current drawable at the (@p x, @p y) location scaled + * to the width @p width and height @p height. + */ +void +imlib_render_image_part_on_drawable_at_size(int source_x, int source_y, + int source_width, + int source_height, int x, int y, + int width, int height) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_render_image_part_on_drawable_at_size", "image", + ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_RenderImage(ctx->display, im, ctx->drawable, 0, ctx->visual, + ctx->colormap, ctx->depth, source_x, source_y, + source_width, source_height, x, y, width, height, + ctx->anti_alias, ctx->dither, ctx->blend, 0, + ctx->color_modifier, ctx->operation); +} + +DATA32 +imlib_render_get_pixel_color(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return __imlib_RenderGetPixel(ctx->display, ctx->drawable, ctx->visual, + ctx->colormap, ctx->depth, + (DATA8) ctx->color.red, + (DATA8) ctx->color.green, + (DATA8) ctx->color.blue); +} + +#endif + +/** + * @param source_image The source image. + * @param merge_alpha Alpha flag. + * @param source_x X coordinate of the source image. + * @param source_y Y coordinate of the source image. + * @param source_width Width of the source image. + * @param source_height Height of the source image. + * @param destination_x X coordinate of the destination image. + * @param destination_y Y coordinate of the destination image. + * @param destination_width Width of the destination image. + * @param destination_height Height of the destination image. + * + * Blends the source rectangle (@p source_x, @p source_y, @p + * source_width, @p source_height) from + * @p source_image onto the current image at the destination (@p + * destination_x, @p destination_y) location + * scaled to the width @p destination_width and height @p + * destination_height. If @p merge_alpha is set to 1 + * it will also modify the destination image alpha channel, otherwise + * the destination alpha channel is left untouched. + */ +void +imlib_blend_image_onto_image(Imlib_Image source_image, char merge_alpha, + int source_x, int source_y, int source_width, + int source_height, int destination_x, + int destination_y, int destination_width, + int destination_height) +{ + ImlibImage *im_src, *im_dst; + int aa; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_blend_image_onto_image", "source_image", + source_image); + CHECK_PARAM_POINTER("imlib_blend_image_onto_image", "image", ctx->image); + CAST_IMAGE(im_src, source_image); + CAST_IMAGE(im_dst, ctx->image); + if ((!(im_src->data)) && (im_src->loader) && (im_src->loader->load)) + im_src->loader->load(im_src, NULL, 0, 1); + if (!(im_src->data)) + return; + if ((!(im_dst->data)) && (im_dst->loader) && (im_dst->loader->load)) + im_dst->loader->load(im_dst, NULL, 0, 1); + if (!(im_dst->data)) + return; + __imlib_DirtyImage(im_dst); + /* FIXME: hack to get around infinite loops for scaling down too far */ + aa = ctx->anti_alias; + if ((abs(destination_width) < (source_width >> 7)) + || (abs(destination_height) < (source_height >> 7))) + aa = 0; + __imlib_BlendImageToImage(im_src, im_dst, aa, ctx->blend, + merge_alpha, source_x, source_y, source_width, + source_height, destination_x, destination_y, + destination_width, destination_height, + ctx->color_modifier, ctx->operation, + ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h); +} + +/** + * @param width The width of the image. + * @param height The height of the image. + * @return A new blank image. + * + * Creates a new blank image of size @p width and @p height. The contents of + * this image at creation time are undefined (they could be garbage + * memory). You are free to do whatever you like with this image. It + * is not cached. On success an image handle is returned - on failure + * NULL is returned. + **/ +Imlib_Image +imlib_create_image(int width, int height) +{ + DATA32 *data; + + if (!ctx) + ctx = imlib_context_new(); + if ((width <= 0) || (height <= 0)) + return NULL; + data = malloc(width * height * sizeof(DATA32)); + if (data) + return (Imlib_Image) __imlib_CreateImage(width, height, data); + return NULL; +} + +/** + * @param width The width of the image. + * @param height The height of the image. + * @param data The data. + * @return A valid image, otherwise NULL. + * + * Creates an image from the image data specified with the width @p width and + * the height @p height specified. The image data @p data must be in the same format as + * imlib_image_get_data() would return. You are responsible for + * freeing this image data once the image is freed - Imlib2 will not + * do that for you. This is useful for when you already have static + * buffers of the same format Imlib2 uses (many video grabbing devices + * use such a format) and wish to use Imlib2 to render the results + * onto another image, or X drawable. You should free the image when + * you are done with it. Imlib2 returns a valid image handle on + * success or NULL on failure + * + **/ +Imlib_Image +imlib_create_image_using_data(int width, int height, DATA32 * data) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_create_image_using_data", "data", data, + NULL); + if ((width <= 0) || (height <= 0)) + return NULL; + im = __imlib_CreateImage(width, height, data); + if (im) + SET_FLAG(im->flags, F_DONT_FREE_DATA); + return (Imlib_Image) im; +} + +/** + * @param width The width of the image. + * @param height The height of the image. + * @param data The data. + * @return A valid image, otherwise NULL. + * + * Works the same way as imlib_create_image_using_data() but Imlib2 + * copies the image data to the image structure. You may now do + * whatever you wish with the original data as it will not be needed + * anymore. Imlib2 returns a valid image handle on success or NULL on + * failure. + * + **/ +Imlib_Image +imlib_create_image_using_copied_data(int width, int height, DATA32 * data) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_create_image_using_copied_data", "data", + data, NULL); + if ((width <= 0) || (height <= 0)) + return NULL; + im = __imlib_CreateImage(width, height, NULL); + if (!im) + return NULL; + im->data = malloc(width * height * sizeof(DATA32)); + if (data) + { + memcpy(im->data, data, width * height * sizeof(DATA32)); + return (Imlib_Image) im; + } + else + __imlib_FreeImage(im); + return NULL; +} + +#ifdef BUILD_X11 +/** + * @param mask A mask. + * @param x The top left x coordinate of the rectangle. + * @param y The top left y coordinate of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * @param need_to_grab_x Grab flag. + * @return a valid image, otherwise NULL. + * + * Return an image (using the mask @p mask to determine the alpha channel) + * from the current drawable. If the mask is 0 it will not create a + * useful alpha channel in the image. It will create an image from the + * (@p x, @p y, @p width , @p height) rectangle in the drawable. If @p + * need_to_grab_x + * is 1 it will also grab the X Server to avoid possible race + * conditions in grabbing. If you have not already grabbed the server + * you MUST set this to 1. Imlib2 returns a valid image handle on + * success or NULL on failure. + * + **/ +Imlib_Image +imlib_create_image_from_drawable(Pixmap mask, int x, int y, int width, + int height, char need_to_grab_x) +{ + ImlibImage *im; + char domask = 0; + + if (!ctx) + ctx = imlib_context_new(); + if (mask) + domask = 1; + im = __imlib_CreateImage(width, height, NULL); + im->data = malloc(width * height * sizeof(DATA32)); + __imlib_GrabDrawableToRGBA(im->data, 0, 0, width, height, ctx->display, + ctx->drawable, mask, ctx->visual, ctx->colormap, + ctx->depth, x, y, width, height, domask, + need_to_grab_x); + return (Imlib_Image) im; +} + +/** + * @param image An image. + * @param mask A mask. + * @param x The top left x coordinate of the rectangle. + * @param y The top left y coordinate of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * @param need_to_grab_x Grab flag. + * @return a valid image, otherwise NULL. + * + * + **/ +Imlib_Image +imlib_create_image_from_ximage(XImage * image, XImage * mask, int x, int y, + int width, int height, char need_to_grab_x) +{ + ImlibImage *im; + char domask = 0; + + if (!ctx) + ctx = imlib_context_new(); + if (mask) + domask = 1; + im = __imlib_CreateImage(width, height, NULL); + im->data = malloc(width * height * sizeof(DATA32)); + __imlib_GrabXImageToRGBA(im->data, 0, 0, width, height, + ctx->display, image, mask, ctx->visual, + ctx->depth, x, y, width, height, need_to_grab_x); + return (Imlib_Image) im; +} + +/** + * @param mask A mask. + * @param source_x The top left x coordinate of the rectangle. + * @param source_y The top left y coordinate of the rectangle. + * @param source_width The width of the rectangle. + * @param source_height The height of the rectangle. + * @param destination_width The width of the returned image. + * @param destination_height The height of the returned image. + * @param need_to_grab_x Grab flag. + * @param get_mask_from_shape A char. + * @return A valid image, otherwise NULL. + * + * Creates an image from the current drawable (optionally using the + * @p mask pixmap specified to determine alpha transparency) and scale + * the grabbed data first before converting to an actual image (to + * minimize reads from the frame buffer which can be slow). The source + * (@p source_x, @p source_y, @p source_width, @p source_height) rectangle will be grabbed, scaled to the + * destination @p destination_width and @p destination_height, then converted to an image. If + * @p need_to_grab_x is set to 1, X is grabbed (set this to 1 unless you + * have already grabbed the server) and if @p get_mask_from_shape and the + * current drawable is a window its shape is used for determining the + * alpha channel. If successful this function will return a valid + * image handle, otherwise NULL is returned. + * + **/ +Imlib_Image +imlib_create_scaled_image_from_drawable(Pixmap mask, int source_x, + int source_y, int source_width, + int source_height, + int destination_width, + int destination_height, + char need_to_grab_x, + char get_mask_from_shape) +{ + ImlibImage *im; + char domask = 0, tmpmask = 0; + int x, xx; + XGCValues gcv; + GC gc = 0, mgc = 0; + Pixmap p, m; + + if (!ctx) + ctx = imlib_context_new(); + if ((mask) || (get_mask_from_shape)) + domask = 1; + p = XCreatePixmap(ctx->display, ctx->drawable, destination_width, + source_height, ctx->depth); + gcv.foreground = 0; + gcv.subwindow_mode = IncludeInferiors; + if (domask) + { + m = XCreatePixmap(ctx->display, ctx->drawable, destination_width, + source_height, 1); + mgc = XCreateGC(ctx->display, m, GCForeground, &gcv); + } + else + m = None; + gc = XCreateGC(ctx->display, ctx->drawable, GCSubwindowMode, &gcv); + if ((domask) && (!mask)) + { + XRectangle *rect; + int rect_num, rect_ord; + + tmpmask = 1; + mask = + XCreatePixmap(ctx->display, ctx->drawable, source_width, + source_height, 1); + rect = + XShapeGetRectangles(ctx->display, ctx->drawable, ShapeBounding, + &rect_num, &rect_ord); + XFillRectangle(ctx->display, mask, mgc, 0, 0, source_width, + source_height); + if (rect) + { + XSetForeground(ctx->display, mgc, 1); + for (x = 0; x < rect_num; x++) + XFillRectangle(ctx->display, mask, mgc, rect[x].x, rect[x].y, + rect[x].width, rect[x].height); + XFree(rect); + } + /* build mask from window shape rects */ + } + for (x = 0; x < destination_width; x++) + { + xx = (source_width * x) / destination_width; + XCopyArea(ctx->display, ctx->drawable, p, gc, source_x + xx, 0, 1, + source_height, x, 0); + if (m != None) + XCopyArea(ctx->display, mask, m, mgc, xx, 0, 1, source_height, x, + 0); + } + for (x = 0; x < destination_height; x++) + { + xx = (source_height * x) / destination_height; + XCopyArea(ctx->display, p, p, gc, 0, source_y + xx, + destination_width, 1, 0, x); + if (m != None) + XCopyArea(ctx->display, m, m, mgc, 0, source_y + xx, + destination_width, 1, 0, x); + } + im = __imlib_CreateImage(destination_width, destination_height, NULL); + im->data = malloc(destination_width * destination_height * sizeof(DATA32)); + __imlib_GrabDrawableToRGBA(im->data, 0, 0, destination_width, + source_height, ctx->display, p, m, + ctx->visual, ctx->colormap, ctx->depth, 0, 0, + destination_width, destination_height, domask, + need_to_grab_x); + XFreePixmap(ctx->display, p); + if (m != None) + { + XFreeGC(ctx->display, mgc); + XFreePixmap(ctx->display, m); + if (tmpmask) + XFreePixmap(ctx->display, mask); + } + XFreeGC(ctx->display, gc); + return (Imlib_Image) im; +} + +/** + * @param mask A mask. + * @param x The top left x coordinate of the rectangle. + * @param y The top left y coordinate of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * @param destination_x The x coordinate of the new location. + * @param destination_y The x coordinate of the new location. + * @param need_to_grab_x Grab flag. + * @return A char. + * + * Grabs a section of the current drawable (optionally using the + * pixmap @p mask + * provided as a corresponding mask for that drawable - if @p mask is 0 + * this is not used). It grabs the (@p x, @p y, @p width, @p height) rectangle and + * places it at the destination (@p destination_x, @p destination_y) location in the current image. If + * @p need_to_grab_x is 1 it will grab and ungrab the server whilst doing + * this - you need to do this if you have not already grabbed the + * server. + * + **/ +char +imlib_copy_drawable_to_image(Pixmap mask, int x, int y, int width, int height, + int destination_x, int destination_y, + char need_to_grab_x) +{ + ImlibImage *im; + char domask = 0; + int pre_adj; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_copy_drawable_to_image", "image", + ctx->image, 0); + if (mask) + domask = 1; + CAST_IMAGE(im, ctx->image); + + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return 0; + + pre_adj = 0; + if (x < 0) + { + width += x; + pre_adj = x; + x = 0; + } + if (width < 0) + width = 0; + if (destination_x < 0) + { + width += destination_x; + x -= destination_x - pre_adj; + destination_x = 0; + } + if ((destination_x + width) >= im->w) + width = im->w - destination_x; + + pre_adj = 0; + if (y < 0) + { + height += y; + pre_adj = y; + y = 0; + } + if (height < 0) + height = 0; + if (destination_y < 0) + { + height += destination_y; + y -= destination_y - pre_adj; + destination_y = 0; + } + if ((destination_y + height) >= im->h) + height = im->h - destination_y; + + if ((width <= 0) || (height <= 0)) + return 0; + __imlib_DirtyImage(im); + return __imlib_GrabDrawableToRGBA(im->data, destination_x, destination_y, + im->w, im->h, ctx->display, + ctx->drawable, mask, ctx->visual, + ctx->colormap, ctx->depth, x, y, width, + height, domask, need_to_grab_x); +} +#endif + +/** + * @return A valid image, otherwise NULL. + * + * Creates an exact duplicate of the current image and returns a valid + * image handle on success, or NULL on failure. + * + **/ +Imlib_Image +imlib_clone_image(void) +{ + ImlibImage *im, *im_old; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_clone_image", "image", ctx->image, NULL); + CAST_IMAGE(im_old, ctx->image); + if ((!(im_old->data)) && (im_old->loader) && (im_old->loader->load)) + im_old->loader->load(im_old, NULL, 0, 1); + if (!(im_old->data)) + return NULL; + im = __imlib_CreateImage(im_old->w, im_old->h, NULL); + if (!(im)) + return NULL; + im->data = malloc(im->w * im->h * sizeof(DATA32)); + if (!(im->data)) + { + __imlib_FreeImage(im); + return NULL; + } + memcpy(im->data, im_old->data, im->w * im->h * sizeof(DATA32)); + im->flags = im_old->flags; + SET_FLAG(im->flags, F_UNCACHEABLE); + im->moddate = im_old->moddate; + im->border = im_old->border; + im->loader = im_old->loader; + if (im_old->format) + { + im->format = malloc(strlen(im_old->format) + 1); + strcpy(im->format, im_old->format); + } + if (im_old->file) + { + im->file = malloc(strlen(im_old->file) + 1); + strcpy(im->file, im_old->file); + } + return (Imlib_Image) im; +} + +/** + * @param x The top left x coordinate of the rectangle. + * @param y The top left y coordinate of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * @return A valid image, otherwise NULL. + * + * Creates a duplicate of a (@p x, @p y, @p width, @p height) rectangle in the + * current image and returns a valid image handle on success, or NULL + * on failure. + * + **/ +Imlib_Image +imlib_create_cropped_image(int x, int y, int width, int height) +{ + ImlibImage *im, *im_old; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_create_cropped_image", "image", + ctx->image, NULL); + CAST_IMAGE(im_old, ctx->image); + if ((!(im_old->data)) && (im_old->loader) && (im_old->loader->load)) + im_old->loader->load(im_old, NULL, 0, 1); + if (!(im_old->data)) + return NULL; + im = __imlib_CreateImage(abs(width), abs(height), NULL); + im->data = malloc(abs(width * height) * sizeof(DATA32)); + if (!(im->data)) + { + __imlib_FreeImage(im); + return NULL; + } + if (IMAGE_HAS_ALPHA(im_old)) + { + SET_FLAG(im->flags, F_HAS_ALPHA); + __imlib_BlendImageToImage(im_old, im, 0, 0, 1, x, y, abs(width), + abs(height), 0, 0, width, height, NULL, + IMLIB_OP_COPY, + ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h); + } + else + { + __imlib_BlendImageToImage(im_old, im, 0, 0, 0, x, y, abs(width), + abs(height), 0, 0, width, height, NULL, + IMLIB_OP_COPY, + ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h); + } + return (Imlib_Image) im; +} + +/** + * @param source_x The top left x coordinate of the source rectangle. + * @param source_y The top left y coordinate of the source rectangle. + * @param source_width The width of the source rectangle. + * @param source_height The height of the source rectangle. + * @param destination_width The width of the destination image. + * @param destination_height The height of the destination image. + * @return A valid image, otherwise NULL. + * + * Works the same as imlib_create_cropped_image() but will scale the + * new image to the new destination @p destination_width and + * @p destination_height whilst cropping. + * + **/ +Imlib_Image +imlib_create_cropped_scaled_image(int source_x, int source_y, + int source_width, int source_height, + int destination_width, int destination_height) +{ + ImlibImage *im, *im_old; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_create_cropped_scaled_image", "image", + ctx->image, NULL); + CAST_IMAGE(im_old, ctx->image); + if ((!(im_old->data)) && (im_old->loader) && (im_old->loader->load)) + im_old->loader->load(im_old, NULL, 0, 1); + if (!(im_old->data)) + return NULL; + im = __imlib_CreateImage(abs(destination_width), abs(destination_height), + NULL); + im->data = + malloc(abs(destination_width * destination_height) * sizeof(DATA32)); + if (!(im->data)) + { + __imlib_FreeImage(im); + return NULL; + } + if (IMAGE_HAS_ALPHA(im_old)) + { + SET_FLAG(im->flags, F_HAS_ALPHA); + __imlib_BlendImageToImage(im_old, im, ctx->anti_alias, 0, 1, source_x, + source_y, source_width, source_height, 0, 0, + destination_width, destination_height, NULL, + IMLIB_OP_COPY, + ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h); + } + else + { + __imlib_BlendImageToImage(im_old, im, ctx->anti_alias, 0, 0, source_x, + source_y, source_width, source_height, 0, 0, + destination_width, destination_height, NULL, + IMLIB_OP_COPY, + ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h); + } + return (Imlib_Image) im; +} + +/** + * @param updates An updates list. + * @return Duplicate of @p updates. + * + * Creates a duplicate of the updates list passed into the function. + **/ +Imlib_Updates +imlib_updates_clone(Imlib_Updates updates) +{ + ImlibUpdate *u; + + if (!ctx) + ctx = imlib_context_new(); + u = (ImlibUpdate *) updates; + return (Imlib_Updates) __imlib_DupUpdates(u); +} + +/** + * @param updates An updates list. + * @param x The top left x coordinate of the rectangle. + * @param y The top left y coordinate of the rectangle. + * @param w The width of the rectangle. + * @param h The height of the rectangle. + * @return The updates handle. + * + * Appends an update rectangle to the updates list passed in (if the + * updates is NULL it will create a new updates list) and returns a + * handle to the modified updates list (the handle may be modified so + * only use the new updates handle returned). + **/ +Imlib_Updates +imlib_update_append_rect(Imlib_Updates updates, int x, int y, int w, int h) +{ + ImlibUpdate *u; + + if (!ctx) + ctx = imlib_context_new(); + u = (ImlibUpdate *) updates; + return (Imlib_Updates) __imlib_AddUpdate(u, x, y, w, h); +} + +/** + * @param updates An updates list. + * @param w The width of the rectangle. + * @param h The height of the rectangle. + * @return The updates handle. + * + * Takes an updates list, and modifies it by merging overlapped + * rectangles and lots of tiny rectangles into larger rectangles to + * minimize the number of rectangles in the list for optimized + * redrawing. The new updates handle is now valid and the old one + * passed in is not. + **/ +Imlib_Updates +imlib_updates_merge(Imlib_Updates updates, int w, int h) +{ + ImlibUpdate *u; + + if (!ctx) + ctx = imlib_context_new(); + u = (ImlibUpdate *) updates; + return (Imlib_Updates) __imlib_MergeUpdate(u, w, h, 0); +} + +/** + * @param updates An updates list. + * @param w The width of the rectangle. + * @param h The height of the rectangle. + * @return The updates handle. + * + * Works almost exactly as imlib_updates_merge() but is more lenient + * on the spacing between update rectangles - if they are very close it + * amalgamates 2 smaller rectangles into 1 larger one. + **/ +Imlib_Updates +imlib_updates_merge_for_rendering(Imlib_Updates updates, int w, int h) +{ + ImlibUpdate *u; + + if (!ctx) + ctx = imlib_context_new(); + u = (ImlibUpdate *) updates; + return (Imlib_Updates) __imlib_MergeUpdate(u, w, h, 3); +} + +/** + * @param updates An updates list. + * + * Frees an updates list. + **/ +void +imlib_updates_free(Imlib_Updates updates) +{ + ImlibUpdate *u; + + if (!ctx) + ctx = imlib_context_new(); + u = (ImlibUpdate *) updates; + __imlib_FreeUpdates(u); +} + +/** + * @param updates An updates list. + * @return The next updates. + * + * Gets the next update in the updates list relative to the one passed + * in. + **/ +Imlib_Updates +imlib_updates_get_next(Imlib_Updates updates) +{ + ImlibUpdate *u; + + if (!ctx) + ctx = imlib_context_new(); + u = (ImlibUpdate *) updates; + return (Imlib_Updates) (u->next); +} + +/** + * @param updates An updates list. + * @param x_return The top left x coordinate of the update. + * @param y_return The top left y coordinate of the update. + * @param width_return The width of the update. + * @param height_return The height of the update. + * + * Returns the coordinates of an update. + **/ +void +imlib_updates_get_coordinates(Imlib_Updates updates, int *x_return, + int *y_return, int *width_return, + int *height_return) +{ + ImlibUpdate *u; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_updates_get_coordinates", "updates", updates); + u = (ImlibUpdate *) updates; + if (x_return) + *x_return = u->x; + if (y_return) + *y_return = u->y; + if (width_return) + *width_return = u->w; + if (height_return) + *height_return = u->h; +} + +/** + * @param updates An updates list. + * @param x The top left x coordinate of the update. + * @param y The top left y coordinate of the update. + * @param width The width of the update. + * @param height The height of the update. + * + * Modifies the coordinates of an update in @p update. + **/ +void +imlib_updates_set_coordinates(Imlib_Updates updates, int x, int y, int width, + int height) +{ + ImlibUpdate *u; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_updates_set_coordinates", "updates", updates); + u = (ImlibUpdate *) updates; + u->x = x; + u->y = y; + u->w = width; + u->h = height; +} + +#ifdef BUILD_X11 +/** + * @param updates An updates list. + * @param x The top left x coordinate of the update. + * @param y The top left y coordinate of the update. + * + * Given an updates list (preferable already merged for rendering) + * this will render the corresponding parts of the image to the current + * drawable at an offset of @p x, @p y in the drawable. + **/ +void +imlib_render_image_updates_on_drawable(Imlib_Updates updates, int x, int y) +{ + ImlibUpdate *u; + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_render_image_updates_on_drawable", "image", + ctx->image); + CAST_IMAGE(im, ctx->image); + u = (ImlibUpdate *) updates; + if (!updates) + return; + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_SetMaxXImageCount(ctx->display, 10); + for (; u; u = u->next) + { + __imlib_RenderImage(ctx->display, im, ctx->drawable, 0, ctx->visual, + ctx->colormap, ctx->depth, u->x, u->y, u->w, u->h, + x + u->x, y + u->y, u->w, u->h, 0, ctx->dither, 0, + 0, ctx->color_modifier, OP_COPY); + } + __imlib_SetMaxXImageCount(ctx->display, 0); +} +#endif + +/** + * @return The initialized updates list. + * + * Initializes an updates list before you add any updates to it or + * merge it for rendering etc. + **/ +Imlib_Updates +imlib_updates_init(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return (Imlib_Updates) NULL; +} + +/** + * @param updates An updates list. + * @param appended_updates The updates list to append. + * @return The new updates list. + * + * Appends @p appended_updates to the updates list @p updates and + * returns the new list. + **/ +Imlib_Updates +imlib_updates_append_updates(Imlib_Updates updates, + Imlib_Updates appended_updates) +{ + ImlibUpdate *u, *uu; + + if (!ctx) + ctx = imlib_context_new(); + u = (ImlibUpdate *) updates; + uu = (ImlibUpdate *) appended_updates; + if (!uu) + return (Imlib_Updates) u; + if (!u) + return (Imlib_Updates) uu; + while (u) + { + if (!(u->next)) + { + u->next = uu; + return updates; + } + u = u->next; + } + return (Imlib_Updates) u; +} + +/** + * Flips/mirrors the current image horizontally. + **/ +void +imlib_image_flip_horizontal(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_flip_horizontal", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_FlipImageHoriz(im); +} + +/** + * Flips/mirrors the current image vertically. + **/ +void +imlib_image_flip_vertical(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_flip_vertical", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_FlipImageVert(im); +} + +/** + * Flips/mirrors the current image diagonally (good for quick and dirty + * 90 degree rotations if used before to after a horizontal or vertical + * flip). + **/ +void +imlib_image_flip_diagonal(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_flip_diagonal", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_FlipImageDiagonal(im, 0); +} + +/** + * @param orientation The orientation. + * + * Performs 90 degree rotations on the current image. Passing in + * @p orientation does not rotate, 1 rotates clockwise by 90 degree, 2, + * rotates clockwise by 180 degrees, 3 rotates clockwise by 270 + * degrees. + **/ +void +imlib_image_orientate(int orientation) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_orientate", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + switch (orientation) + { + default: + case 0: + break; + case 1: + __imlib_FlipImageDiagonal(im, 1); + break; + case 2: + __imlib_FlipImageBoth(im); + break; + case 3: + __imlib_FlipImageDiagonal(im, 2); + break; + case 4: + __imlib_FlipImageHoriz(im); + break; + case 5: + __imlib_FlipImageDiagonal(im, 3); + break; + case 6: + __imlib_FlipImageVert(im); + break; + case 7: + __imlib_FlipImageDiagonal(im, 0); + break; + } +} + +/** + * @param radius The radius. + * + * Blurs the current image. A @p radius value of 0 has no effect, 1 and above + * determine the blur matrix radius that determine how much to blur the + * image. + **/ +void +imlib_image_blur(int radius) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_blur", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_BlurImage(im, radius); +} + +/** + * @param radius The radius. + * + * Sharpens the current image. The @p radius value affects how much to sharpen + * by. + **/ +void +imlib_image_sharpen(int radius) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CAST_IMAGE(im, ctx->image); + CHECK_PARAM_POINTER("imlib_image_sharpen", "image", ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_SharpenImage(im, radius); +} + +/** + * Modifies an image so it will tile seamlessly horizontally if used + * as a tile (i.e. drawn multiple times horizontally). + **/ +void +imlib_image_tile_horizontal(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_tile_horizontal", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_TileImageHoriz(im); +} + +/** + * Modifies an image so it will tile seamlessly vertically if used as + * a tile (i.e. drawn multiple times vertically). + **/ +void +imlib_image_tile_vertical(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_tile_vertical", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_TileImageVert(im); +} + +/** + * Modifies an image so it will tile seamlessly horizontally and + * vertically if used as a tile (i.e. drawn multiple times horizontally + * and vertically). + **/ +void +imlib_image_tile(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_tile", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_TileImageHoriz(im); + __imlib_TileImageVert(im); +} + +/** + * @param font_name The font name with the size. + * @return NULL if no font found. + * + * Loads a truetype font from the first directory in the font path that + * contains that font. The font name @p font_name format is "font_name/size". For + * example. If there is a font file called blum.ttf somewhere in the + * font path you might use "blum/20" to load a 20 pixel sized font of + * blum. If the font cannot be found NULL is returned. + * + **/ +Imlib_Font +imlib_load_font(const char *font_name) +{ + return imlib_font_load_joined(font_name); +} + +/** + * Frees the current font. + **/ +void +imlib_free_font(void) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_free_font", "font", ctx->font); + imlib_font_free(ctx->font); + ctx->font = NULL; +} + +/** + * @param x The x coordinate of the top left corner. + * @param y The y coordinate of the top left corner. + * @param text A null-byte terminated string. + * + * Draws the null-byte terminated string @p text using the current font on + * the current image at the (@p x, @p y) location (@p x, @p y denoting the top left + * corner of the font string) + **/ +void +imlib_text_draw(int x, int y, const char *text) +{ + if (!ctx) + ctx = imlib_context_new(); + imlib_text_draw_with_return_metrics(x, y, text, NULL, NULL, NULL, NULL); +} + +/** + * @param x The x coordinate of the top left corner. + * @param y The y coordinate of the top left corner. + * @param text A null-byte terminated string. + * @param width_return The width of the string. + * @param height_return The height of the string. + * @param horizontal_advance_return Horizontal offset. + * @param vertical_advance_return Vertical offset. + * + * Works just like imlib_text_draw() but also returns the width and + * height of the string drawn, and @p horizontal_advance_return returns + * the number of pixels you should advance horizontally to draw another + * string (useful if you are drawing a line of text word by word) and + * @p vertical_advance_return does the same for the vertical direction + * (i.e. drawing text line by line). + **/ +void +imlib_text_draw_with_return_metrics(int x, int y, const char *text, + int *width_return, int *height_return, + int *horizontal_advance_return, + int *vertical_advance_return) +{ + ImlibImage *im; + ImlibFont *fn; + int dir; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_text_draw_with_return_metrics", "font", + ctx->font); + CHECK_PARAM_POINTER("imlib_text_draw_with_return_metrics", "image", + ctx->image); + CHECK_PARAM_POINTER("imlib_text_draw_with_return_metrics", "text", text); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + fn = (ImlibFont *) ctx->font; + __imlib_DirtyImage(im); + + dir = ctx->direction; + if (ctx->direction == IMLIB_TEXT_TO_ANGLE && ctx->angle == 0.0) + dir = IMLIB_TEXT_TO_RIGHT; + + imlib_render_str(im, fn, x, y, text, (DATA8) ctx->color.red, + (DATA8) ctx->color.green, (DATA8) ctx->color.blue, + (DATA8) ctx->color.alpha, (char)dir, + ctx->angle, width_return, height_return, 0, + horizontal_advance_return, vertical_advance_return, + ctx->operation, + ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h); +} + +/** + * @param text A string. + * @param width_return The width of the text. + * @param height_return The height of the text. + * + * Gets the width and height in pixels the @p text string would use up + * if drawn with the current font. + **/ +void +imlib_get_text_size(const char *text, int *width_return, int *height_return) +{ + ImlibFont *fn; + int w, h; + int dir; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_get_text_size", "font", ctx->font); + CHECK_PARAM_POINTER("imlib_get_text_size", "text", text); + fn = (ImlibFont *) ctx->font; + + dir = ctx->direction; + if (ctx->direction == IMLIB_TEXT_TO_ANGLE && ctx->angle == 0.0) + dir = IMLIB_TEXT_TO_RIGHT; + + imlib_font_query_size(fn, text, &w, &h); + + switch (dir) + { + case IMLIB_TEXT_TO_RIGHT: + case IMLIB_TEXT_TO_LEFT: + if (width_return) + *width_return = w; + if (height_return) + *height_return = h; + break; + case IMLIB_TEXT_TO_DOWN: + case IMLIB_TEXT_TO_UP: + if (width_return) + *width_return = h; + if (height_return) + *height_return = w; + break; + case IMLIB_TEXT_TO_ANGLE: + if (width_return || height_return) + { + double sa, ca; + + sa = sin(ctx->angle); + ca = cos(ctx->angle); + + if (width_return) + { + double x1, x2, xt; + + x1 = x2 = 0.0; + xt = ca * w; + if (xt < x1) + x1 = xt; + if (xt > x2) + x2 = xt; + xt = -(sa * h); + if (xt < x1) + x1 = xt; + if (xt > x2) + x2 = xt; + xt = ca * w - sa * h; + if (xt < x1) + x1 = xt; + if (xt > x2) + x2 = xt; + *width_return = (int)(x2 - x1); + } + if (height_return) + { + double y1, y2, yt; + + y1 = y2 = 0.0; + yt = sa * w; + if (yt < y1) + y1 = yt; + if (yt > y2) + y2 = yt; + yt = ca * h; + if (yt < y1) + y1 = yt; + if (yt > y2) + y2 = yt; + yt = sa * w + ca * h; + if (yt < y1) + y1 = yt; + if (yt > y2) + y2 = yt; + *height_return = (int)(y2 - y1); + } + } + break; + default: + break; + } +} + +/** + * @param text A string. + * @param horizontal_advance_return Horizontal offset. + * @param vertical_advance_return Vertical offset. + * + * Gets the advance horizontally and vertically in pixels the next + * text string would need to be placed at for the current font. The + * advances are not adjusted for rotation so you will have to translate + * the advances (which are calculated as if the text was drawn + * horizontally from left to right) depending on the text orientation. + **/ +void +imlib_get_text_advance(const char *text, int *horizontal_advance_return, + int *vertical_advance_return) +{ + ImlibFont *fn; + int w, h; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_get_text_advance", "font", ctx->font); + CHECK_PARAM_POINTER("imlib_get_text_advance", "text", text); + fn = (ImlibFont *) ctx->font; + imlib_font_query_advance(fn, text, &w, &h); + if (horizontal_advance_return) + *horizontal_advance_return = w; + if (vertical_advance_return) + *vertical_advance_return = h; +} + +/** + * @param text A string. + * @return The inset value of @text. + * + * Returns the inset of the first character of @p text + * in using the current font and returns that value in pixels. + * + **/ +int +imlib_get_text_inset(const char *text) +{ + ImlibFont *fn; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_get_text_advance", "font", ctx->font, 0); + CHECK_PARAM_POINTER_RETURN("imlib_get_text_advance", "text", text, 0); + fn = (ImlibFont *) ctx->font; + return imlib_font_query_inset(fn, text); +} + +/** + * @param path A directory path. + * + * Adds the directory @p path to the end of the current list of + * directories to scan for fonts. + **/ +void +imlib_add_path_to_font_path(const char *path) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_add_path_to_font_path", "path", path); + if (!imlib_font_path_exists(path)) + imlib_font_add_font_path(path); +} + +/** + * @param path A directory path. + * + * Removes all directories in the font path that match @p path. + **/ +void +imlib_remove_path_from_font_path(const char *path) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_remove_path_from_font_path", "path", path); + imlib_font_del_font_path(path); +} + +/** + * @param number_return Number of paths in the list. + * @return A list of strings. + * + * Returns a list of strings that are the directories in the font + * path. Do not free this list or change it in any way. If you add or + * delete members of the font path this list will be invalid. If you + * intend to use this list later duplicate it for your own use. The + * number of elements in the array of strings is put into + * @p number_return. + * + **/ +char ** +imlib_list_font_path(int *number_return) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_list_font_path", "number_return", + number_return, NULL); + return imlib_font_list_font_path(number_return); +} + +/** + * @param text A string. + * @param x The x offset. + * @param y The y offset. + * @param char_x_return The x coordinate of the character. + * @param char_y_return The x coordinate of the character. + * @param char_width_return The width of the character. + * @param char_height_return The height of the character. + * @return -1 if no character found. + * + * Returns the character number in the string @p text using the current + * font at the (@p x, @p y) pixel location which is an offset relative to the + * top left of that string. -1 is returned if there is no character + * there. If there is a character, @p char_x_return, @p char_y_return, + * @p char_width_return and @p char_height_return (respectively the + * character x, y, width and height) are also filled in. + * + **/ +int +imlib_text_get_index_and_location(const char *text, int x, int y, + int *char_x_return, int *char_y_return, + int *char_width_return, + int *char_height_return) +{ + ImlibFont *fn; + int w, h, cx, cy, cw, ch, cp, xx, yy; + int dir; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_text_get_index_and_location", "font", + ctx->font, -1); + CHECK_PARAM_POINTER_RETURN("imlib_text_get_index_and_location", "text", + text, -1); + fn = (ImlibFont *) ctx->font; + + dir = ctx->direction; + if (ctx->direction == IMLIB_TEXT_TO_ANGLE && ctx->angle == 0.0) + dir = IMLIB_TEXT_TO_RIGHT; + + imlib_get_text_size(text, &w, &h); + + switch (dir) + { + case IMLIB_TEXT_TO_RIGHT: + xx = x; + yy = y; + break; + case IMLIB_TEXT_TO_LEFT: + xx = w - x; + yy = h - y; + break; + case IMLIB_TEXT_TO_DOWN: + xx = y; + yy = w - x; + break; + case IMLIB_TEXT_TO_UP: + xx = h - y; + yy = x; + break; + default: + return -1; + } + + cp = imlib_font_query_text_at_pos(fn, text, xx, yy, &cx, &cy, &cw, &ch); + + switch (dir) + { + case IMLIB_TEXT_TO_RIGHT: + if (char_x_return) + *char_x_return = cx; + if (char_y_return) + *char_y_return = cy; + if (char_width_return) + *char_width_return = cw; + if (char_height_return) + *char_height_return = ch; + return cp; + break; + case IMLIB_TEXT_TO_LEFT: + cx = 1 + w - cx - cw; + if (char_x_return) + *char_x_return = cx; + if (char_y_return) + *char_y_return = cy; + if (char_width_return) + *char_width_return = cw; + if (char_height_return) + *char_height_return = ch; + return cp; + break; + case IMLIB_TEXT_TO_DOWN: + if (char_x_return) + *char_x_return = cy; + if (char_y_return) + *char_y_return = cx; + if (char_width_return) + *char_width_return = ch; + if (char_height_return) + *char_height_return = cw; + return cp; + break; + case IMLIB_TEXT_TO_UP: + cy = 1 + h - cy - ch; + if (char_x_return) + *char_x_return = cy; + if (char_y_return) + *char_y_return = cx; + if (char_width_return) + *char_width_return = ch; + if (char_height_return) + *char_height_return = cw; + return cp; + break; + default: + return -1; + break; + } + return -1; +} + +/** + * @param text A string. + * @param index The index of @text. + * @param char_x_return The x coordinate of the character. + * @param char_y_return The y coordinate of the character. + * @param char_width_return The width of the character. + * @param char_height_return The height of the character. + * + * Gets the geometry of the character at index @p index in the @p text + * string using the current font. + **/ +void +imlib_text_get_location_at_index(const char *text, int index, + int *char_x_return, int *char_y_return, + int *char_width_return, + int *char_height_return) +{ + ImlibFont *fn; + int cx, cy, cw, ch, w, h; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_text_get_index_and_location", "font", ctx->font); + CHECK_PARAM_POINTER("imlib_text_get_index_and_location", "text", text); + fn = (ImlibFont *) ctx->font; + + imlib_font_query_char_coords(fn, text, index, &cx, &cy, &cw, &ch); + + imlib_get_text_size(text, &w, &h); + + switch (ctx->direction) + { + case IMLIB_TEXT_TO_RIGHT: + if (char_x_return) + *char_x_return = cx; + if (char_y_return) + *char_y_return = cy; + if (char_width_return) + *char_width_return = cw; + if (char_height_return) + *char_height_return = ch; + return; + break; + case IMLIB_TEXT_TO_LEFT: + cx = 1 + w - cx - cw; + if (char_x_return) + *char_x_return = cx; + if (char_y_return) + *char_y_return = cy; + if (char_width_return) + *char_width_return = cw; + if (char_height_return) + *char_height_return = ch; + return; + break; + case IMLIB_TEXT_TO_DOWN: + if (char_x_return) + *char_x_return = cy; + if (char_y_return) + *char_y_return = cx; + if (char_width_return) + *char_width_return = ch; + if (char_height_return) + *char_height_return = cw; + return; + break; + case IMLIB_TEXT_TO_UP: + cy = 1 + h - cy - ch; + if (char_x_return) + *char_x_return = cy; + if (char_y_return) + *char_y_return = cx; + if (char_width_return) + *char_width_return = ch; + if (char_height_return) + *char_height_return = cw; + return; + break; + default: + return; + break; + } +} + +/** + * @param number_return Number of fonts in the list. + * @return A list of fonts. + * + * Returns a list of fonts imlib2 can find in its font path. + * + **/ +char ** +imlib_list_fonts(int *number_return) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_list_fonts", "number_return", + number_return, NULL); + return imlib_font_list_fonts(number_return); +} + +/** + * @param font_list The font list. + * @param number Number of fonts in the list. + * + * Frees the font list returned by imlib_list_fonts(). + * + **/ +void +imlib_free_font_list(char **font_list, int number) +{ + __imlib_FileFreeDirList(font_list, number); +} + +/** + * @return The font cache size. + * + * Returns the font cache size in bytes. + * + **/ +int +imlib_get_font_cache_size(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return imlib_font_cache_get(); +} + +/** + * @param bytes The font cache size. + * + * Sets the font cache in bytes. Whenever you set the font cache size + * Imlib2 will flush fonts from the cache until the memory used by + * fonts is less than or equal to the font cache size. Setting the size + * to 0 effectively frees all speculatively cached fonts. + **/ +void +imlib_set_font_cache_size(int bytes) +{ + if (!ctx) + ctx = imlib_context_new(); + imlib_font_cache_set(bytes); +} + +/** + * Causes a flush of all speculatively cached fonts from the font + * cache. + **/ +void +imlib_flush_font_cache(void) +{ + if (!ctx) + ctx = imlib_context_new(); + imlib_font_flush(); +} + +/** + * @return The font's ascent. + * + * Returns the current font's ascent value in pixels. + * + **/ +int +imlib_get_font_ascent(void) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_get_font_ascent", "font", ctx->font, 0); + return imlib_font_ascent_get(ctx->font); +} + +/** + * @return The font's descent. + * + * Returns the current font's descent value in pixels. + * + **/ +int +imlib_get_font_descent(void) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_get_font_ascent", "font", ctx->font, 0); + return imlib_font_descent_get(ctx->font); +} + +/** + * @return The font's maximum ascent. + * + * Returns the current font's maximum ascent extent. + * + **/ +int +imlib_get_maximum_font_ascent(void) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_get_font_ascent", "font", ctx->font, 0); + return imlib_font_max_ascent_get(ctx->font); +} + +/** + * @return The font's maximum descent. + * + * Returns the current font's maximum descent extent. + * + **/ +int +imlib_get_maximum_font_descent(void) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_get_font_ascent", "font", ctx->font, 0); + return imlib_font_max_descent_get(ctx->font); +} + +/** + * @return Valid handle. + * + * Creates a new empty color modifier and returns a + * valid handle on success. NULL is returned on failure. + * + **/ +Imlib_Color_Modifier +imlib_create_color_modifier(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return (Imlib_Color_Modifier) __imlib_CreateCmod(); +} + +/** + * Frees the current color modifier. + **/ +void +imlib_free_color_modifier(void) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_free_color_modifier", "color_modifier", + ctx->color_modifier); + __imlib_FreeCmod((ImlibColorModifier *) ctx->color_modifier); + ctx->color_modifier = NULL; +} + +/** + * @param gamma_value Value of gamma. + * + * Modifies the current color modifier by adjusting the gamma by the + * value specified @p gamma_value. The color modifier is modified not set, so calling + * this repeatedly has cumulative effects. A gamma of 1.0 is normal + * linear, 2.0 brightens and 0.5 darkens etc. Negative values are not + * allowed. + **/ +void +imlib_modify_color_modifier_gamma(double gamma_value) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_modify_color_modifier_gamma", "color_modifier", + ctx->color_modifier); + __imlib_CmodModGamma((ImlibColorModifier *) ctx->color_modifier, + gamma_value); +} + +/** + * @param brightness_value Value of brightness. + * + * Modifies the current color modifier by adjusting the brightness by + * the value @p brightness_value. The color modifier is modified not set, so + * calling this repeatedly has cumulative effects. brightness values + * of 0 do not affect anything. -1.0 will make things completely black + * and 1.0 will make things all white. Values in-between vary + * brightness linearly. + **/ +void +imlib_modify_color_modifier_brightness(double brightness_value) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_modify_color_modifier_brightness", + "color_modifier", ctx->color_modifier); + __imlib_CmodModBrightness((ImlibColorModifier *) ctx->color_modifier, + brightness_value); +} + +/** + * @param contrast_value Value of contrast. + * + * Modifies the current color modifier by adjusting the contrast by + * the value @p contrast_value. The color modifier is modified not set, so + * calling this repeatedly has cumulative effects. Contrast of 1.0 does + * nothing. 0.0 will merge to gray, 2.0 will double contrast etc. + **/ +void +imlib_modify_color_modifier_contrast(double contrast_value) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_modify_color_modifier_contrast", + "color_modifier", ctx->color_modifier); + __imlib_CmodModContrast((ImlibColorModifier *) ctx->color_modifier, + contrast_value); +} + +/** + * @param red_table An array of #DATA8. + * @param green_table An array of #DATA8. + * @param blue_table An array of #DATA8. + * @param alpha_table An array of #DATA8. + * + * Explicitly copies the mapping tables from the table pointers passed + * into this function into those of the current color modifier. Tables + * are 256 entry arrays of DATA8 which are a mapping of that channel + * value to a new channel value. A normal mapping would be linear (v[0] + * = 0, v[10] = 10, v[50] = 50, v[200] = 200, v[255] = 255). + **/ +void +imlib_set_color_modifier_tables(DATA8 * red_table, DATA8 * green_table, + DATA8 * blue_table, DATA8 * alpha_table) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_set_color_modifier_tables", "color_modifier", + ctx->color_modifier); + __imlib_CmodSetTables((ImlibColorModifier *) ctx->color_modifier, + red_table, green_table, blue_table, alpha_table); +} + +/** + * @param red_table: an array of #DATA8. + * @param green_table: an array of #DATA8. + * @param blue_table: an array of #DATA8. + * @param alpha_table: an array of #DATA8. + * + * Copies the table values from the current color modifier into the + * pointers to mapping tables specified. They must have 256 entries and + * be DATA8 format. + **/ +void +imlib_get_color_modifier_tables(DATA8 * red_table, DATA8 * green_table, + DATA8 * blue_table, DATA8 * alpha_table) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_get_color_modifier_tables", "color_modifier", + ctx->color_modifier); + __imlib_CmodGetTables((ImlibColorModifier *) ctx->color_modifier, + red_table, green_table, blue_table, alpha_table); +} + +/** + * Resets the current color modifier to have linear mapping tables. + **/ +void +imlib_reset_color_modifier(void) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_rset_color_modifier", "color_modifier", + ctx->color_modifier); + __imlib_CmodReset((ImlibColorModifier *) ctx->color_modifier); +} + +/** + * Uses the current color modifier and modifies the current image using + * the mapping tables in the current color modifier. + **/ +void +imlib_apply_color_modifier(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_apply_color_modifier", "image", ctx->image); + CHECK_PARAM_POINTER("imlib_apply_color_modifier", "color_modifier", + ctx->color_modifier); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_DataCmodApply(im->data, im->w, im->h, 0, &(im->flags), + (ImlibColorModifier *) ctx->color_modifier); +} + +/** + * @param x The x coordinate of the left edge of the rectangle. + * @param y The y coordinate of the top edge of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * + * Works the same way as imlib_apply_color_modifier() but only modifies + * a selected rectangle in the current image. + **/ +void +imlib_apply_color_modifier_to_rectangle(int x, int y, int width, int height) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_apply_color_modifier_to_rectangle", "image", + ctx->image); + CHECK_PARAM_POINTER("imlib_apply_color_modifier_to_rectangle", + "color_modifier", ctx->color_modifier); + CAST_IMAGE(im, ctx->image); + if (x < 0) + { + width += x; + x = 0; + } + if (width <= 0) + return; + if ((x + width) > im->w) + width = (im->w - x); + if (width <= 0) + return; + if (y < 0) + { + height += y; + y = 0; + } + if (height <= 0) + return; + if ((y + height) > im->h) + height = (im->h - y); + if (height <= 0) + return; + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_DataCmodApply(im->data + (y * im->w) + x, width, height, + im->w - width, &(im->flags), + (ImlibColorModifier *) ctx->color_modifier); +} + +Imlib_Updates +imlib_image_draw_pixel(int x, int y, char make_updates) +{ + ImlibImage *im; + DATA32 color; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_image_draw_pixel", "image", ctx->image, + NULL); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return NULL; + __imlib_DirtyImage(im); + A_VAL(&color) = (DATA8) ctx->color.alpha; + R_VAL(&color) = (DATA8) ctx->color.red; + G_VAL(&color) = (DATA8) ctx->color.green; + B_VAL(&color) = (DATA8) ctx->color.blue; + return (Imlib_Updates) __imlib_Point_DrawToImage(x, y, color, im, + ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h, + ctx->operation, ctx->blend, + make_updates); +} + +/** + * @param x1 The x coordinate of the first point. + * @param y1 The y coordinate of the first point. + * @param x2 The x coordinate of the second point. + * @param y2 The y coordinate of the second point. + * @param make_updates: a char. + * @return An updates list. + * + * Draws a line using the current color on the current image from + * coordinates (@p x1, @p y1) to (@p x2, @p y2). If @p make_updates is 1 it will also + * return an update you can use for an updates list, otherwise it + * returns NULL. + * + **/ +Imlib_Updates +imlib_image_draw_line(int x1, int y1, int x2, int y2, char make_updates) +{ + ImlibImage *im; + DATA32 color; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_image_draw_line", "image", ctx->image, + NULL); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return NULL; + __imlib_DirtyImage(im); + A_VAL(&color) = (DATA8) ctx->color.alpha; + R_VAL(&color) = (DATA8) ctx->color.red; + G_VAL(&color) = (DATA8) ctx->color.green; + B_VAL(&color) = (DATA8) ctx->color.blue; + return (Imlib_Updates) __imlib_Line_DrawToImage(x1, y1, x2, y2, color, im, + ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h, + ctx->operation, ctx->blend, + ctx->anti_alias, make_updates); +} + +/** + * @param x The top left x coordinate of the rectangle. + * @param y The top left y coordinate of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * + * Draws the outline of a rectangle on the current image at the (@p x, + * @p y) + * coordinates with a size of @p width and @p height pixels, using the + * current color. + **/ +void +imlib_image_draw_rectangle(int x, int y, int width, int height) +{ + ImlibImage *im; + DATA32 color; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_draw_rectangle", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + A_VAL(&color) = (DATA8) ctx->color.alpha; + R_VAL(&color) = (DATA8) ctx->color.red; + G_VAL(&color) = (DATA8) ctx->color.green; + B_VAL(&color) = (DATA8) ctx->color.blue; + __imlib_Rectangle_DrawToImage(x, y, width, height, color, + im, ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h, + ctx->operation, ctx->blend); +} + +/** + * @param x The top left x coordinate of the rectangle. + * @param y The top left y coordinate of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * + * Draws a filled rectangle on the current image at the (@p x, @p y) + * coordinates with a size of @p width and @p height pixels, using the + * current color. + **/ +void +imlib_image_fill_rectangle(int x, int y, int width, int height) +{ + ImlibImage *im; + DATA32 color; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_fill_rectangle", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + A_VAL(&color) = (DATA8) ctx->color.alpha; + R_VAL(&color) = (DATA8) ctx->color.red; + G_VAL(&color) = (DATA8) ctx->color.green; + B_VAL(&color) = (DATA8) ctx->color.blue; + __imlib_Rectangle_FillToImage(x, y, width, height, color, + im, ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h, + ctx->operation, ctx->blend); +} + +/** + * @param image_source An image. + * @param x The x coordinate. + * @param y The y coordinate. + * + * Copies the alpha channel of the source image @p image_source to the + * (@p x, @p y) coordinates + * of the current image, replacing the alpha channel there. + **/ +void +imlib_image_copy_alpha_to_image(Imlib_Image image_source, int x, int y) +{ + ImlibImage *im, *im2; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_copy_alpha_to_image", "image_source", + image_source); + CHECK_PARAM_POINTER("imlib_image_copy_alpha_to_image", "image_destination", + ctx->image); + CAST_IMAGE(im, image_source); + CAST_IMAGE(im2, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if ((!(im2->data)) && (im2->loader) && (im2->loader->load)) + im2->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + if (!(im2->data)) + return; + __imlib_DirtyImage(im); + __imlib_copy_alpha_data(im, im2, 0, 0, im->w, im->h, x, y); +} + +/** + * @param image_source An image. + * @param x The top left x coordinate of the rectangle. + * @param y The top left y coordinate of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * @param destination_x The top left x coordinate of the destination rectangle. + * @param destination_y The top left x coordinate of the destination rectangle. + * + * Copies the source (@p x, @p y, @p width, @p height) rectangle alpha channel from + * the source image @p image_source and replaces the alpha channel on the destination + * image at the (@p destination_x, @p destination_y) coordinates. + **/ +void +imlib_image_copy_alpha_rectangle_to_image(Imlib_Image image_source, int x, + int y, int width, int height, + int destination_x, int destination_y) +{ + ImlibImage *im, *im2; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_copy_alpha_rectangle_to_image", + "image_source", image_source); + CHECK_PARAM_POINTER("imlib_image_copy_alpha_rectangle_to_image", + "image_destination", ctx->image); + CAST_IMAGE(im, image_source); + CAST_IMAGE(im2, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if ((!(im2->data)) && (im2->loader) && (im2->loader->load)) + im2->loader->load(im2, NULL, 0, 1); + if (!(im->data)) + return; + if (!(im2->data)) + return; + __imlib_DirtyImage(im); + __imlib_copy_alpha_data(im, im2, x, y, width, height, destination_x, + destination_y); +} + +/** + * @param x The top left x coordinate of the rectangle. + * @param y The top left y coordinate of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * @param delta_x Distance along the x coordinates. + * @param delta_y Distance along the y coordinates. + * + * Scrolls a rectangle of size @p width, @p height at the (@p x, @p y) + * location within the current image + * by the @p delta_x, @p delta_y distance (in pixels). + **/ +void +imlib_image_scroll_rect(int x, int y, int width, int height, int delta_x, + int delta_y) +{ + ImlibImage *im; + int xx, yy, w, h, nx, ny; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_scroll_rect", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + if (delta_x > 0) + { + xx = x; + nx = x + delta_x; + w = width - delta_x; + } + else + { + xx = x - delta_x; + nx = x; + w = width + delta_x; + } + if (delta_y > 0) + { + yy = y; + ny = y + delta_y; + h = height - delta_y; + } + else + { + yy = y - delta_y; + ny = y; + h = height + delta_y; + } + __imlib_DirtyImage(im); + __imlib_copy_image_data(im, xx, yy, w, h, nx, ny); +} + +/** + * @param x The top left x coordinate of the rectangle. + * @param y The top left y coordinate of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * @param new_x The top left x coordinate of the new location. + * @param new_y The top left y coordinate of the new location. + * + * Copies a rectangle of size @p width, @p height at the (@p x, @p y) location + * specified in the current image to a new location (@p new_x, @p new_y) in the same + * image. + **/ +void +imlib_image_copy_rect(int x, int y, int width, int height, int new_x, int new_y) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_copy_rect", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_copy_image_data(im, x, y, width, height, new_x, new_y); +} + +/** + * @return valid handle. + * + * Creates a new empty color range and returns a valid handle to that + * color range. + **/ +Imlib_Color_Range +imlib_create_color_range(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return (Imlib_Color_Range) __imlib_CreateRange(); +} + +/** + * Frees the current color range. + **/ +void +imlib_free_color_range(void) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_free_color_range", "color_range", + ctx->color_range); + __imlib_FreeRange((ImlibRange *) ctx->color_range); + ctx->color_range = NULL; +} + +/** + * @param distance_away Distance from the previous color. + * + * Adds the current color to the current color range at a @p distance_away + * distance from the previous color in the range (if it's the first + * color in the range this is irrelevant). + **/ +void +imlib_add_color_to_color_range(int distance_away) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_add_color_to_color_range", "color_range", + ctx->color_range); + __imlib_AddRangeColor((ImlibRange *) ctx->color_range, ctx->color.red, + ctx->color.green, ctx->color.blue, ctx->color.alpha, + distance_away); +} + +/** + * @param x The x coordinate of the left edge of the rectangle. + * @param y The y coordinate of the top edge of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * @param angle Angle of gradient. + * + * Fills a rectangle of width @p width and height @p height at the (@p x, @p y) location + * specified in the current image with a linear gradient of the + * current color range at an angle of @p angle degrees with 0 degrees + * being vertical from top to bottom going clockwise from there. + **/ +void +imlib_image_fill_color_range_rectangle(int x, int y, int width, int height, + double angle) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_fill_color_range_rectangle", "image", + ctx->image); + CHECK_PARAM_POINTER("imlib_image_fill_color_range_rectangle", + "color_range", ctx->color_range); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_DrawGradient(im, x, y, width, height, + (ImlibRange *) ctx->color_range, angle, + ctx->operation, + ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h); +} + +/** + * @param x The x coordinate of the left edge of the rectangle. + * @param y The y coordinate of the top edge of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * @param angle Angle of gradient. + * + * Fills a rectangle of width @p width and height @p height at the (@p + * x, @p y) location + * specified in the current image with a linear gradient in HSVA color + * space of the current color range at an angle of @p angle degrees with + * 0 degrees being vertical from top to bottom going clockwise from + * there. + **/ +void +imlib_image_fill_hsva_color_range_rectangle(int x, int y, int width, int height, + double angle) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_fill_color_range_rectangle", "image", + ctx->image); + CHECK_PARAM_POINTER("imlib_image_fill_color_range_rectangle", + "color_range", ctx->color_range); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_DrawHsvaGradient(im, x, y, width, height, + (ImlibRange *) ctx->color_range, angle, + ctx->operation, + ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h); +} + +/** + * @param x The x coordinate of the pixel. + * @param y The y coordinate of the pixel. + * @param color_return The returned color. + * + * Fills the @p color_return color structure with the color of the pixel + * in the current image that is at the (@p x, @p y) location specified. + **/ +void +imlib_image_query_pixel(int x, int y, Imlib_Color * color_return) +{ + ImlibImage *im; + DATA32 *p; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_query_pixel", "image", ctx->image); + CHECK_PARAM_POINTER("imlib_image_query_pixel", "color_return", color_return); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + if ((x < 0) || (x >= im->w) || (y < 0) || (y >= im->h)) + { + color_return->red = 0; + color_return->green = 0; + color_return->blue = 0; + color_return->alpha = 0; + return; + } + p = im->data + (im->w * y) + x; + color_return->red = ((*p) >> 16) & 0xff; + color_return->green = ((*p) >> 8) & 0xff; + color_return->blue = (*p) & 0xff; + color_return->alpha = ((*p) >> 24) & 0xff; +} + +/** + * @param x The x coordinate of the pixel. + * @param y The y coordinate of the pixel. + * @param hue The returned hue channel. + * @param saturation The returned saturation channel. + * @param value The returned value channel. + * @param alpha The returned alpha channel. + * + * Gets the HSVA color of the pixel from the current image that is at + * the (@p x, @p y) location specified. + **/ +void +imlib_image_query_pixel_hsva(int x, int y, float *hue, float *saturation, + float *value, int *alpha) +{ + ImlibImage *im; + DATA32 *p; + int r, g, b; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_query_pixel", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + if ((x < 0) || (x >= im->w) || (y < 0) || (y >= im->h)) + { + *hue = 0; + *saturation = 0; + *value = 0; + *alpha = 0; + return; + } + p = im->data + (im->w * y) + x; + r = ((*p) >> 16) & 0xff; + g = ((*p) >> 8) & 0xff; + b = (*p) & 0xff; + *alpha = ((*p) >> 24) & 0xff; + + __imlib_rgb_to_hsv(r, g, b, hue, saturation, value); +} + +/** + * @param x The x coordinate of the pixel. + * @param y The y coordinate of the pixel. + * @param hue The returned hue channel. + * @param lightness The returned lightness channel. + * @param saturation The returned saturation channel. + * @param alpha The returned alpha channel. + * + * Gets the HLSA color of the pixel from the current image that is at + * the (@p x, @p y) location specified. + **/ +void +imlib_image_query_pixel_hlsa(int x, int y, float *hue, float *lightness, + float *saturation, int *alpha) +{ + ImlibImage *im; + DATA32 *p; + int r, g, b; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_query_pixel", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + if ((x < 0) || (x >= im->w) || (y < 0) || (y >= im->h)) + { + *hue = 0; + *lightness = 0; + *saturation = 0; + *alpha = 0; + return; + } + p = im->data + (im->w * y) + x; + r = ((*p) >> 16) & 0xff; + g = ((*p) >> 8) & 0xff; + b = (*p) & 0xff; + *alpha = ((*p) >> 24) & 0xff; + + __imlib_rgb_to_hls(r, g, b, hue, lightness, saturation); +} + +/** + * @param x Tthe x coordinate of the pixel. + * @param y The y coordinate of the pixel. + * @param cyan The returned cyan channel. + * @param magenta The returned magenta channel. + * @param yellow The returned yellow channel. + * @param alpha The returned alpha channel. + * + * Gets the CMYA color of the pixel from the current image that is at + * the (@p x, @p y) location specified. + * + **/ +void +imlib_image_query_pixel_cmya(int x, int y, int *cyan, int *magenta, int *yellow, + int *alpha) +{ + ImlibImage *im; + DATA32 *p; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_query_pixel", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + if ((x < 0) || (x >= im->w) || (y < 0) || (y >= im->h)) + { + *cyan = 0; + *magenta = 0; + *yellow = 0; + *alpha = 0; + return; + } + p = im->data + (im->w * y) + x; + *cyan = 255 - (((*p) >> 16) & 0xff); + *magenta = 255 - (((*p) >> 8) & 0xff); + *yellow = 255 - ((*p) & 0xff); + *alpha = ((*p) >> 24) & 0xff; +} + +/** + * @param key A string. + * @param data A pointer. + * @param value A value. + * @param destructor_function An Imlib internal function. + * + * Attaches data to the current image with the string key of @p key, and + * the data of @p data and an integer of @p value. The + * @p destructor_function function, if not NULL is called when this + * image is freed so the destructor can free @p data, if this is needed. + **/ +void +imlib_image_attach_data_value(const char *key, void *data, int value, + Imlib_Internal_Data_Destructor_Function + destructor_function) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_attach_data_value", "image", ctx->image); + CHECK_PARAM_POINTER("imlib_image_attach_data_value", "key", key); + CAST_IMAGE(im, ctx->image); + __imlib_AttachTag(im, key, value, data, + (ImlibDataDestructorFunction) destructor_function); +} + +/** + * @param key A string. + * @return The attached data as a pointer, or NULL if none. + * + * Gets the data attached to the current image with the key @p key + * specified. NULL is returned if no data could be found with that key + * on the current image. + * + **/ +void * +imlib_image_get_attached_data(const char *key) +{ + ImlibImageTag *t; + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_image_get_attached_data", "image", + ctx->image, NULL); + CHECK_PARAM_POINTER_RETURN("imlib_image_get_attached_data", "key", key, + NULL); + CAST_IMAGE(im, ctx->image); + t = __imlib_GetTag(im, key); + if (t) + return t->data; + return NULL; +} + +/** + * @param key A string. + * @return The attached value as an integer, or 0 if none. + * + * Returns the value attached to the current image with the specified + * key @p key. If none could be found 0 is returned. + * + **/ +int +imlib_image_get_attached_value(const char *key) +{ + ImlibImageTag *t; + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_image_get_attached_value", "image", + ctx->image, 0); + CHECK_PARAM_POINTER_RETURN("imlib_image_get_attached_value", "key", key, 0); + CAST_IMAGE(im, ctx->image); + t = __imlib_GetTag(im, key); + if (t) + return t->val; + return 0; +} + +/** + * @param key A string. + * + * Detaches the data & value attached with the specified key @p key from the + * current image. + **/ +void +imlib_image_remove_attached_data_value(const char *key) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_remove_attached_data_value", "image", + ctx->image); + CHECK_PARAM_POINTER("imlib_image_remove_attached_data_value", "key", key); + CAST_IMAGE(im, ctx->image); + __imlib_RemoveTag(im, key); +} + +/** + * @param key A string. + * + * Removes the data and value attached to the current image with the + * specified key @p key and also calls the destructor function that was + * supplied when attaching it (see imlib_image_attach_data_value()). + **/ +void +imlib_image_remove_and_free_attached_data_value(const char *key) +{ + ImlibImageTag *t; + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_remove_and_free_attached_data_value", + "image", ctx->image); + CHECK_PARAM_POINTER("imlib_image_remove_and_free_attached_data_value", + "key", key); + CAST_IMAGE(im, ctx->image); + t = __imlib_RemoveTag(im, key); + __imlib_FreeTag(im, t); +} + +/** + * @param filename The file name. + * + * Saves the current image in the format specified by the current + * image's format settings to the filename @p filename. + **/ +void +imlib_save_image(const char *filename) +{ + ImlibImage *im; + Imlib_Image prev_ctxt_image; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_save_image", "image", ctx->image); + CHECK_PARAM_POINTER("imlib_save_image", "filename", filename); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!im->data) + return; + prev_ctxt_image = ctx->image; + __imlib_SaveImage(im, filename, (ImlibProgressFunction) ctx->progress_func, + ctx->progress_granularity, NULL); + ctx->image = prev_ctxt_image; +} + +/** + * @param filename The file name. + * @param error_return The returned error. + * + * Works the same way imlib_save_image() works, but will set the + * @p error_return to an error value if the save fails. + **/ +void +imlib_save_image_with_error_return(const char *filename, + Imlib_Load_Error * error_return) +{ + ImlibImage *im; + Imlib_Image prev_ctxt_image; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_save_image_with_error_return", "image", + ctx->image); + CHECK_PARAM_POINTER("imlib_save_image_with_error_return", "filename", + filename); + CHECK_PARAM_POINTER("imlib_save_image_with_error_return", "error_return", + error_return); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!im->data) + return; + prev_ctxt_image = ctx->image; + __imlib_SaveImage(im, filename, (ImlibProgressFunction) ctx->progress_func, + ctx->progress_granularity, error_return); + ctx->image = prev_ctxt_image; +} + +/** + * @param angle An angle in radians. + * @return A new image, or NULL. + * + * Creates an new copy of the current image, but rotated by @p angle + * radians. On success it returns a valid image handle, otherwise + * NULL. + **/ +Imlib_Image +imlib_create_rotated_image(double angle) +{ + ImlibImage *im, *im_old; + int x, y, dx, dy, sz; + double x1, y1, d; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_create_rotated_image", "image", + ctx->image, NULL); + CAST_IMAGE(im_old, ctx->image); + if ((!(im_old->data)) && (im_old->loader) && (im_old->loader->load)) + im_old->loader->load(im_old, NULL, 0, 1); + if (!(im_old->data)) + return NULL; + + d = hypot((double)(im_old->w + 4), (double)(im_old->h + 4)) / sqrt(2.0); + + x1 = (double)(im_old->w) / 2.0 - sin(angle + atan(1.0)) * d; + y1 = (double)(im_old->h) / 2.0 - cos(angle + atan(1.0)) * d; + + sz = (int)(d * sqrt(2.0)); + x = (int)(x1 * _ROTATE_PREC_MAX); + y = (int)(y1 * _ROTATE_PREC_MAX); + dx = (int)(cos(angle) * _ROTATE_PREC_MAX); + dy = -(int)(sin(angle) * _ROTATE_PREC_MAX); + + im = __imlib_CreateImage(sz, sz, NULL); + im->data = calloc(sz * sz, sizeof(DATA32)); + if (!(im->data)) + { + __imlib_FreeImage(im); + return NULL; + } + + if (ctx->anti_alias) + { +#ifdef DO_MMX_ASM + if (__imlib_get_cpuid() & CPUID_MMX) + __imlib_mmx_RotateAA(im_old->data, im->data, im_old->w, im_old->w, + im_old->h, im->w, sz, sz, x, y, dx, dy, -dy, + dx); + else +#endif + __imlib_RotateAA(im_old->data, im->data, im_old->w, im_old->w, + im_old->h, im->w, sz, sz, x, y, dx, dy, -dy, dx); + } + else + { + __imlib_RotateSample(im_old->data, im->data, im_old->w, im_old->w, + im_old->h, im->w, sz, sz, x, y, dx, dy, -dy, dx); + } + SET_FLAG(im->flags, F_HAS_ALPHA); + + return (Imlib_Image) im; +} + +void imlib_rotate_image_from_buffer(double angle, + Imlib_Image source_image) +{ + ImlibImage *im, *im_old; + int x, y, dx, dy, sz; + double x1, y1, d; + + if (!ctx) + ctx = imlib_context_new(); + // source image (to rotate) + CHECK_PARAM_POINTER("imlib_rotate_image_from_buffer", "source_image", + source_image); + CAST_IMAGE(im_old, source_image); + + // current context image + CHECK_PARAM_POINTER("imlib_rotate_image_from_buffer", "image", + ctx->image); + CAST_IMAGE(im, ctx->image); + + if ((!(im_old->data)) && (im_old->loader) && (im_old->loader->load)) + im_old->loader->load(im_old, NULL, 0, 1); + + if (!(im_old->data)) return; + + d = hypot((double)(im_old->w + 4), (double)(im_old->h + 4)) / sqrt(2.0); + + x1 = (double)(im_old->w) / 2.0 - sin(angle + atan(1.0)) * d; + y1 = (double)(im_old->h) / 2.0 - cos(angle + atan(1.0)) * d; + + sz = (int)(d * sqrt(2.0)); + x = (int)(x1 * _ROTATE_PREC_MAX); + y = (int)(y1 * _ROTATE_PREC_MAX); + dx = (int)(cos(angle) * _ROTATE_PREC_MAX); + dy = -(int)(sin(angle) * _ROTATE_PREC_MAX); + + if ( (im->w != im->h) || ((im->w < sz) && (im->h < sz))) + return; // If size is wrong + else sz = im->w; // update sz with real width + + /* Not neccesary 'cause destination is context + im = __imlib_CreateImage(sz, sz, NULL); + im->data = calloc(sz * sz, sizeof(DATA32)); + if (!(im->data)) + { + __imlib_FreeImage(im); + return; + }*/ + + if (ctx->anti_alias) + { +#ifdef DO_MMX_ASM + if (__imlib_get_cpuid() & CPUID_MMX) + __imlib_mmx_RotateAA(im_old->data, im->data, im_old->w, im_old->w, + im_old->h, im->w, sz, sz, x, y, dx, dy, -dy, + dx); + else +#endif + __imlib_RotateAA(im_old->data, im->data, im_old->w, im_old->w, + im_old->h, im->w, sz, sz, x, y, dx, dy, -dy, dx); + } + else + { + __imlib_RotateSample(im_old->data, im->data, im_old->w, im_old->w, + im_old->h, im->w, sz, sz, x, y, dx, dy, -dy, dx); + } + SET_FLAG(im->flags, F_HAS_ALPHA); + + + return; +} + +/** + * @param source_image The image source. + * @param merge_alpha A char. + * @param source_x The source x coordinate. + * @param source_y The source y coordinate. + * @param source_width The source width. + * @param source_height The source height. + * @param destination_x The destination x coordinate. + * @param destination_y The destination y coordinate. + * @param angle_x An angle. + * @param angle_y An angle. + * + * Works just like imlib_blend_image_onto_image_skewed() except you + * cannot skew an image (@p v_angle_x and @p v_angle_y are 0). + **/ +void +imlib_blend_image_onto_image_at_angle(Imlib_Image source_image, + char merge_alpha, int source_x, + int source_y, int source_width, + int source_height, int destination_x, + int destination_y, int angle_x, + int angle_y) +{ + ImlibImage *im_src, *im_dst; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_blend_image_onto_image_at_angle", + "source_image", source_image); + CHECK_PARAM_POINTER("imlib_blend_image_onto_image_at_angle", "image", + ctx->image); + CAST_IMAGE(im_src, source_image); + CAST_IMAGE(im_dst, ctx->image); + if ((!(im_src->data)) && (im_src->loader) && (im_src->loader->load)) + im_src->loader->load(im_src, NULL, 0, 1); + if (!(im_src->data)) + return; + if ((!(im_dst->data)) && (im_dst->loader) && (im_dst->loader->load)) + im_dst->loader->load(im_dst, NULL, 0, 1); + if (!(im_dst->data)) + return; + __imlib_DirtyImage(im_dst); + __imlib_BlendImageToImageSkewed(im_src, im_dst, ctx->anti_alias, + ctx->blend, merge_alpha, source_x, + source_y, source_width, source_height, + destination_x, destination_y, angle_x, + angle_y, 0, 0, ctx->color_modifier, + ctx->operation, + ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h); +} + +/** + * @param source_image The source image. + * @param merge_alpha A char + * @param source_x The source x coordinate. + * @param source_y The source y coordinate. + * @param source_width The source width. + * @param source_height The source height. + * @param destination_x The destination x coordinate. + * @param destination_y The destination y coordinate. + * @param h_angle_x An angle. + * @param h_angle_y An angle. + * @param v_angle_x An angle. + * @param v_angle_y An angle. + * + * Blends the source rectangle (@p source_x, @p source_y, @p source_width, + * @p source_height) from the + * @p source_image onto the current image at the destination + * (@p destination_x, @p destination_y) + * location. It will be rotated and scaled so that the upper right + * corner will be positioned @p h_angle_x pixels to the right (or left, + * if negative) and @p h_angle_y pixels down (from (@p destination_x, + * @p destination_y). If + * @p v_angle_x and @p v_angle_y are not 0, the image will also be skewed so + * that the lower left corner will be positioned @p v_angle_x pixels to + * the right and @p v_angle_y pixels down. The at_angle versions simply + * have the @p v_angle_x and @p v_angle_y set to 0 so the rotation doesn't + * get skewed, and the render_..._on_drawable ones seem obvious + * enough; they do the same on a drawable. + * + * Example: + * @code + * imlib_blend_image_onto_image_skewed(..., 0, 0, 100, 0, 0, 100); + * @endcode + * will simply scale the image to be 100x100. + * @code + * imlib_blend_image_onto_image_skewed(..., 0, 0, 0, 100, 100, 0); + * @endcode + * will scale the image to be 100x100, and flip it diagonally. + * @code + * imlib_blend_image_onto_image_skewed(..., 100, 0, 0, 100, -100, 0); + * @endcode + * will scale the image and rotate it 90 degrees clockwise. + * @code + * imlib_blend_image_onto_image_skewed(..., 50, 0, 50, 50, -50, 50); + * @endcode + * will rotate the image 45 degrees clockwise, and will scale it so + * its corners are at (50,0)-(100,50)-(50,100)-(0,50) i.e. it fits + * into the 100x100 square, so it's scaled down to 70.7% (sqrt(2)/2). + * @code + * imlib_blend_image_onto_image_skewed(..., 50, 50, 100 * cos(a), 100 * sin(a), 0); + * @endcode + * will rotate the image `a' degrees, with its upper left corner at (50,50). + **/ +void +imlib_blend_image_onto_image_skewed(Imlib_Image source_image, + char merge_alpha, int source_x, + int source_y, int source_width, + int source_height, int destination_x, + int destination_y, int h_angle_x, + int h_angle_y, int v_angle_x, int v_angle_y) +{ + ImlibImage *im_src, *im_dst; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_blend_image_onto_image_skewed", "source_image", + source_image); + CHECK_PARAM_POINTER("imlib_blend_image_onto_image_skewed", "image", + ctx->image); + CAST_IMAGE(im_src, source_image); + CAST_IMAGE(im_dst, ctx->image); + if ((!(im_src->data)) && (im_src->loader) && (im_src->loader->load)) + im_src->loader->load(im_src, NULL, 0, 1); + if (!(im_src->data)) + return; + if ((!(im_dst->data)) && (im_dst->loader) && (im_dst->loader->load)) + im_dst->loader->load(im_dst, NULL, 0, 1); + if (!(im_dst->data)) + return; + __imlib_DirtyImage(im_dst); + __imlib_BlendImageToImageSkewed(im_src, im_dst, ctx->anti_alias, + ctx->blend, merge_alpha, source_x, + source_y, source_width, source_height, + destination_x, destination_y, h_angle_x, + h_angle_y, v_angle_x, v_angle_y, + ctx->color_modifier, ctx->operation, + ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h); +} + +#ifdef BUILD_X11 +/** + * @param source_x The source x coordinate. + * @param source_y The source y coordinate. + * @param source_width The source width. + * @param source_height The source height. + * @param destination_x The destination x coordinate. + * @param destination_y The destination y coordinate. + * @param h_angle_x An angle. + * @param h_angle_y An angle. + * @param v_angle_x An angle. + * @param v_angle_y An angle. + * + * + * Works just like imlib_blend_image_onto_image_skewed(), except it + * blends the image onto the current drawable instead of the current + * image. + **/ +void +imlib_render_image_on_drawable_skewed(int source_x, int source_y, + int source_width, int source_height, + int destination_x, int destination_y, + int h_angle_x, int h_angle_y, + int v_angle_x, int v_angle_y) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_render_image_on_drawable_skewed", "image", + ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + CAST_IMAGE(im, ctx->image); + __imlib_RenderImageSkewed(ctx->display, im, ctx->drawable, ctx->mask, + ctx->visual, ctx->colormap, ctx->depth, source_x, + source_y, source_width, source_height, + destination_x, destination_y, h_angle_x, + h_angle_y, v_angle_x, v_angle_y, ctx->anti_alias, + ctx->dither, ctx->blend, ctx->dither_mask, + ctx->color_modifier, ctx->operation); +} + +/** + * @param source_x The source x coordinate. + * @param source_y The source y coordinate. + * @param source_width The source width. + * @param source_height The source height. + * @param destination_x The destination x coordinate. + * @param destination_y The destination y coordinate. + * @param angle_x An angle. + * @param angle_y An angle. + * + * + * Works just like imlib_render_image_on_drawable_skewed() except you + * cannot skew an image (@p v_angle_x and @p v_angle_y are 0). + **/ +void +imlib_render_image_on_drawable_at_angle(int source_x, int source_y, + int source_width, int source_height, + int destination_x, int destination_y, + int angle_x, int angle_y) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_render_image_on_drawable_at_angle", "image", + ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + CAST_IMAGE(im, ctx->image); + __imlib_RenderImageSkewed(ctx->display, im, ctx->drawable, ctx->mask, + ctx->visual, ctx->colormap, ctx->depth, source_x, + source_y, source_width, source_height, + destination_x, destination_y, angle_x, angle_y, + 0, 0, ctx->anti_alias, ctx->dither, ctx->blend, + ctx->dither_mask, ctx->color_modifier, + ctx->operation); +} +#endif + +void +imlib_image_filter(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_filter", "image", ctx->image); + CHECK_PARAM_POINTER("imlib_image_filter", "filter", ctx->filter); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + __imlib_FilterImage(im, (ImlibFilter *) ctx->filter); +} + +Imlib_Filter +imlib_create_filter(int initsize) +{ + if (!ctx) + ctx = imlib_context_new(); + return (Imlib_Filter) __imlib_CreateFilter(initsize); +} + +void +imlib_free_filter(void) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_free_filter", "filter", ctx->filter); + __imlib_FreeFilter((ImlibFilter *) ctx->filter); + ctx->filter = NULL; +} + +/** + * @param filter Current filter. + * + * Sets the current filter to be used when applying filters to + * images. Set this to NULL to disable filters. + */ +void +imlib_context_set_filter(Imlib_Filter filter) +{ + if (!ctx) + ctx = imlib_context_new(); + ctx->filter = filter; +} + +/** + * @return + * + * Gets the current context image filter. + */ +Imlib_Filter +imlib_context_get_filter(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return ctx->filter; +} + +void +imlib_filter_set(int xoff, int yoff, int a, int r, int g, int b) +{ + ImlibFilter *fil; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_filter_set", "filter", ctx->filter); + fil = (ImlibFilter *) ctx->filter; + __imlib_FilterSetColor(&fil->alpha, xoff, yoff, a, 0, 0, 0); + __imlib_FilterSetColor(&fil->red, xoff, yoff, 0, r, 0, 0); + __imlib_FilterSetColor(&fil->green, xoff, yoff, 0, 0, g, 0); + __imlib_FilterSetColor(&fil->blue, xoff, yoff, 0, 0, 0, b); +} + +void +imlib_filter_set_alpha(int xoff, int yoff, int a, int r, int g, int b) +{ + ImlibFilter *fil; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_filter_set_alpha", "filter", ctx->filter); + fil = (ImlibFilter *) ctx->filter; + __imlib_FilterSetColor(&fil->alpha, xoff, yoff, a, r, g, b); +} + +void +imlib_filter_set_red(int xoff, int yoff, int a, int r, int g, int b) +{ + ImlibFilter *fil; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_filter_set_red", "filter", ctx->filter); + fil = (ImlibFilter *) ctx->filter; + __imlib_FilterSetColor(&fil->red, xoff, yoff, a, r, g, b); +} + +void +imlib_filter_set_green(int xoff, int yoff, int a, int r, int g, int b) +{ + ImlibFilter *fil; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_filter_set_green", "filter", ctx->filter); + fil = (ImlibFilter *) ctx->filter; + __imlib_FilterSetColor(&fil->green, xoff, yoff, a, r, g, b); +} + +void +imlib_filter_set_blue(int xoff, int yoff, int a, int r, int g, int b) +{ + ImlibFilter *fil; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_filter_set_blue", "filter", ctx->filter); + fil = (ImlibFilter *) ctx->filter; + __imlib_FilterSetColor(&fil->blue, xoff, yoff, a, r, g, b); +} + +void +imlib_filter_constants(int a, int r, int g, int b) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_filter_constants", "filter", ctx->filter); + __imlib_FilterConstants((ImlibFilter *) ctx->filter, a, r, g, b); +} + +void +imlib_filter_divisors(int a, int r, int g, int b) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_filter_divisors", "filter", ctx->filter); + __imlib_FilterDivisors((ImlibFilter *) ctx->filter, a, r, g, b); +} + +void +imlib_apply_filter(char *script, ...) +{ + va_list param_list; + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + __imlib_dynamic_filters_init(); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + va_start(param_list, script); + __imlib_script_parse(im, script, param_list); + va_end(param_list); +} + +/** + * Returns a new polygon object with no points set. + **/ +ImlibPolygon +imlib_polygon_new(void) +{ + if (!ctx) + ctx = imlib_context_new(); + return (ImlibPolygon) __imlib_polygon_new(); +} + +/** + * @param poly A polygon + * @param x The X coordinate. + * @param y The Y coordinate. + * + * Adds the point (@p x, @p y) to the polygon @p poly. The point will be added + * to the end of the polygon's internal point list. The points are + * drawn in order, from the first to the last. + **/ +void +imlib_polygon_add_point(ImlibPolygon poly, int x, int y) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_polygon_add_point", "polygon", poly); + __imlib_polygon_add_point((ImlibPoly) poly, x, y); +} + +/** + * @param poly A polygon. + * + * Frees a polygon object. + **/ +void +imlib_polygon_free(ImlibPolygon poly) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_polygon_free", "polygon", poly); + __imlib_polygon_free((ImlibPoly) poly); +} + +/** + * @param poly A polygon. + * @param closed Closed polygon flag. + * + * Draws the polygon @p poly onto the current context image. Points which have + * been added to the polygon are drawn in sequence, first to last. The + * final point will be joined with the first point if @p closed is + * non-zero. + **/ +void +imlib_image_draw_polygon(ImlibPolygon poly, unsigned char closed) +{ + ImlibImage *im; + DATA32 color; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_draw_polygon", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + A_VAL(&color) = (DATA8) ctx->color.alpha; + R_VAL(&color) = (DATA8) ctx->color.red; + G_VAL(&color) = (DATA8) ctx->color.green; + B_VAL(&color) = (DATA8) ctx->color.blue; + __imlib_Polygon_DrawToImage((ImlibPoly) poly, closed, color, + im, ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h, + ctx->operation, ctx->blend, ctx->anti_alias); +} + +/** + * @param poly A polygon. + * + * Fills the area defined by the polygon @p polyon the current context image + * with the current context color. + **/ +void +imlib_image_fill_polygon(ImlibPolygon poly) +{ + ImlibImage *im; + DATA32 color; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_fill_polygon", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + A_VAL(&color) = (DATA8) ctx->color.alpha; + R_VAL(&color) = (DATA8) ctx->color.red; + G_VAL(&color) = (DATA8) ctx->color.green; + B_VAL(&color) = (DATA8) ctx->color.blue; + __imlib_Polygon_FillToImage((ImlibPoly) poly, color, + im, ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h, + ctx->operation, ctx->blend, ctx->anti_alias); +} + +/** + * @param poly A polygon. + * @param px1 X coordinate of the upper left corner. + * @param py1 Y coordinate of the upper left corner. + * @param px2 X coordinate of the lower right corner. + * @param py2 Y coordinate of the lower right corner. + * + * Calculates the bounding area of the polygon @p poly. (@p px1, @p py1) defines the + * upper left corner of the bounding box and (@p px2, @p py2) defines it's + * lower right corner. + **/ +void +imlib_polygon_get_bounds(ImlibPolygon poly, int *px1, int *py1, int *px2, + int *py2) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_polygon_get_bounds", "polygon", poly); + __imlib_polygon_get_bounds((ImlibPoly) poly, px1, py1, px2, py2); +} + +/** + * @param xc X coordinate of the center of the ellipse. + * @param yc Y coordinate of the center of the ellipse. + * @param a The horizontal amplitude of the ellipse. + * @param b The vertical amplitude of the ellipse. + * + * Draws an ellipse on the current context image. The ellipse is + * defined as (@p x-@p xc)^2/@p a^2 + (@p y-@p yc)^2/@p b^2 = 1. This means that the + * point (@p xc, @p yc) marks the center of the ellipse, @p a defines the + * horizontal amplitude of the ellipse, and @p b defines the vertical + * amplitude. + **/ +void +imlib_image_draw_ellipse(int xc, int yc, int a, int b) +{ + ImlibImage *im; + DATA32 color; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_draw_ellipse", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + A_VAL(&color) = (DATA8) ctx->color.alpha; + R_VAL(&color) = (DATA8) ctx->color.red; + G_VAL(&color) = (DATA8) ctx->color.green; + B_VAL(&color) = (DATA8) ctx->color.blue; + __imlib_Ellipse_DrawToImage(xc, yc, a, b, color, + im, ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h, + ctx->operation, ctx->blend, ctx->anti_alias); +} + +/** + * @param xc X coordinate of the center of the ellipse. + * @param yc Y coordinate of the center of the ellipse. + * @param a The horizontal amplitude of the ellipse. + * @param b The vertical amplitude of the ellipse. + * + * Fills an ellipse on the current context image using the current + * context color. The ellipse is + * defined as (@p x-@p xc)^2/@p a^2 + (@p y-@p yc)^2/@p b^2 = 1. This means that the + * point (@p xc, @p yc) marks the center of the ellipse, @p a defines the + * horizontal amplitude of the ellipse, and @p b defines the vertical + * amplitude. + **/ +void +imlib_image_fill_ellipse(int xc, int yc, int a, int b) +{ + ImlibImage *im; + DATA32 color; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_fill_ellipse", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + A_VAL(&color) = (DATA8) ctx->color.alpha; + R_VAL(&color) = (DATA8) ctx->color.red; + G_VAL(&color) = (DATA8) ctx->color.green; + B_VAL(&color) = (DATA8) ctx->color.blue; + __imlib_Ellipse_FillToImage(xc, yc, a, b, color, + im, ctx->cliprect.x, ctx->cliprect.y, + ctx->cliprect.w, ctx->cliprect.h, + ctx->operation, ctx->blend, ctx->anti_alias); +} + +/** + * @param poly A polygon + * @param x The X coordinate. + * @param y The Y coordinate. + * + * Returns non-zero if the point (@p x, @p y) is within the area defined by + * the polygon @p poly. + **/ +unsigned char +imlib_polygon_contains_point(ImlibPolygon poly, int x, int y) +{ + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER_RETURN("imlib_polygon_contains_point", "polygon", poly, 0); + return __imlib_polygon_contains_point((ImlibPoly) poly, x, y); +} + +void +imlib_image_clear(void) +{ + ImlibImage *im; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_clear", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + memset(im->data, 0, im->w * im->h * sizeof(DATA32)); +} + +void +imlib_image_clear_color(int r, int g, int b, int a) +{ + ImlibImage *im; + int i, max; + DATA32 col; + + if (!ctx) + ctx = imlib_context_new(); + CHECK_PARAM_POINTER("imlib_image_clear_color", "image", ctx->image); + CAST_IMAGE(im, ctx->image); + if ((!(im->data)) && (im->loader) && (im->loader->load)) + im->loader->load(im, NULL, 0, 1); + if (!(im->data)) + return; + __imlib_DirtyImage(im); + max = im->w * im->h; + WRITE_RGBA(&col, r, g, b, a); + for (i = 0; i < max; i++) + im->data[i] = col; +} diff --git a/src/lib/asm_blend.S b/src/lib/asm_blend.S new file mode 100644 index 0000000..313e077 --- /dev/null +++ b/src/lib/asm_blend.S @@ -0,0 +1,1059 @@ +#include + +#ifdef __EMX__ +/* Due to strange behaviour of as.exe we use this macros */ +/* For all OS/2 coders - please use PGCC to compile this code */ +#define PR_(foo) ___##foo +#define PT_(foo,func) ___##foo,##func +#define SIZE(sym) \ + .___end_##sym:; \ + .size ___##sym,.___end_##sym-___##sym; \ + .align 8; +#else +#define PR_(foo) __##foo +#define PT_(foo,func) __##foo,##func +#define SIZE(sym) \ + .__end_##sym:; \ + .size __##sym,.__end_##sym-__##sym; \ + .align 8; +#endif + +#ifdef DO_MMX_ASM + +/*\ +|*| MMX assembly blending routines for Imlib2 +|*| Written by Willem Monsuwe +|*| +|*| Special (hairy) constructs are only commented on first use. +\*/ + +/*\ All functions have the same calling convention: +|*| __imlib_mmx__rgba_to_rgb[A](void *src, int sw, void *dst, int dw, +|*| int w, int h, ImlibColorModifier *cm) +\*/ + +#define src 8(%ebp) +#define sw 12(%ebp) +#define dst 16(%ebp) +#define dw 20(%ebp) +#define w 24(%ebp) +#define h 28(%ebp) +#define cm 32(%ebp) + +.text + .align 8 +.globl PR_(imlib_mmx_blend_rgba_to_rgb) + .type PT_(imlib_mmx_blend_rgba_to_rgb,@function) +.globl PR_(imlib_mmx_blend_rgba_to_rgba) + .type PT_(imlib_mmx_blend_rgba_to_rgba,@function) +.globl PR_(imlib_mmx_copy_rgba_to_rgb) + .type PT_(imlib_mmx_copy_rgba_to_rgb,@function) +.globl PR_(imlib_mmx_copy_rgba_to_rgba) + .type PT_(imlib_mmx_copy_rgba_to_rgba,@function) +.globl PR_(imlib_mmx_copy_rgb_to_rgba) + + .type PT_(imlib_mmx_copy_rgb_to_rgba,@function) +.globl PR_(imlib_mmx_add_blend_rgba_to_rgb) + .type PT_(imlib_mmx_add_blend_rgba_to_rgb,@function) +.globl PR_(imlib_mmx_add_blend_rgba_to_rgba) + .type PT_(imlib_mmx_add_blend_rgba_to_rgba,@function) +.globl PR_(imlib_mmx_add_copy_rgba_to_rgb) + .type PT_(imlib_mmx_add_copy_rgba_to_rgb,@function) +.globl PR_(imlib_mmx_add_copy_rgba_to_rgba) + .type PT_(imlib_mmx_add_copy_rgba_to_rgba,@function) +.globl PR_(imlib_mmx_add_copy_rgb_to_rgba) + .type PT_(imlib_mmx_add_copy_rgb_to_rgba,@function) + +.globl PR_(imlib_mmx_subtract_blend_rgba_to_rgb) + .type PT_(imlib_mmx_subtract_blend_rgba_to_rgb,@function) +.globl PR_(imlib_mmx_subtract_blend_rgba_to_rgba) + .type PT_(imlib_mmx_subtract_blend_rgba_to_rgba,@function) +.globl PR_(imlib_mmx_subtract_copy_rgba_to_rgb) + .type PT_(imlib_mmx_subtract_copy_rgba_to_rgb,@function) +.globl PR_(imlib_mmx_subtract_copy_rgba_to_rgba) + .type PT_(imlib_mmx_subtract_copy_rgba_to_rgba,@function) +.globl PR_(imlib_mmx_subtract_copy_rgb_to_rgba) + .type PT_(imlib_mmx_subtract_copy_rgb_to_rgba,@function) + +.globl PR_(imlib_mmx_reshade_blend_rgba_to_rgb) + .type PT_(imlib_mmx_reshade_blend_rgba_to_rgb,@function) +.globl PR_(imlib_mmx_reshade_blend_rgba_to_rgba) + .type PT_(imlib_mmx_reshade_blend_rgba_to_rgba,@function) +.globl PR_(imlib_mmx_reshade_copy_rgba_to_rgb) + .type PT_(imlib_mmx_reshade_copy_rgba_to_rgb,@function) +.globl PR_(imlib_mmx_reshade_copy_rgba_to_rgba) + .type PT_(imlib_mmx_reshade_copy_rgba_to_rgba,@function) +.globl PR_(imlib_mmx_reshade_copy_rgb_to_rgba) + .type PT_(imlib_mmx_reshade_copy_rgb_to_rgba,@function) + +/*\ Some useful masks \*/ +m0X000000: .byte 0, 0, 0, 0, 0, 0, 255, 0 +m10000000: .byte 0, 0, 0, 0, 0, 0, 0, 1 +m00XXXXXX: .byte 255, 255, 255, 255, 255, 255, 0, 0 +mVX000000: .byte 0, 0, 0, 0, 0, 0, 255, 127 +mV0000000: .byte 0, 0, 0, 0, 0, 0, 0, 128 +m0XXX0XXX: .byte 255, 255, 255, 0, 255, 255, 255, 0 +mX000X000: .byte 0, 0, 0, 255, 0, 0, 0, 255 +m10001000: .byte 0, 0, 0, 1, 0, 0, 0, 1 +m000V0V0V: .byte 127, 0, 127, 0, 127, 0, 0, 0 +mI0000000: .byte 0, 0, 0, 0, 0, 0, 0, 64 +m0VVV0VVV: .byte 127, 127, 127, 0, 127, 127, 127, 0 +c1: .word 0x1, 0x1, 0x1, 0x1 + +/*\ MMX register use: +|*| %mm1 = Source value +|*| %mm2 = Destination value +|*| %mm3 = Alpha value +|*| %mm4 = 0 +|*| %mm5-%mm6 = masks +\*/ + +/*\ Common code \*/ +/*\ Set MMX mode, save registers, load common parameters \*/ +#define ENTER \ + pushl %ebp ;\ + movl %esp, %ebp ;\ + pushl %ebx ;\ + pushl %ecx ;\ + pushl %edx ;\ + pushl %edi ;\ + pushl %esi ;\ + movl h, %edx ;\ + movl w, %ebx ;\ + movl src, %esi ;\ + movl dst, %edi ;\ + leal (%esi, %ebx, 4), %esi ;\ + leal (%edi, %ebx, 4), %edi ;\ + negl %ebx ;\ + jz 9f ;\ + incl %edx ;\ + decl %edx ;\ + jz 9f ;\ + decl %edx ;\ + +#define LOOP_START \ +8: ;\ + movl %ebx, %ecx + +#define LOOP_END \ + movl sw, %ecx ;\ + leal (%esi, %ecx, 4), %esi ;\ + movl dw, %ecx ;\ + leal (%edi, %ecx, 4), %edi ;\ + decl %edx ;\ + jns 8b + + +/*\ Unset MMX mode, reset registers, return \*/ +#define LEAVE \ +9: ;\ + emms ;\ + popl %esi ;\ + popl %edi ;\ + popl %edx ;\ + popl %ecx ;\ + popl %ebx ;\ + movl %ebp, %esp ;\ + popl %ebp ;\ + ret + + +PR_(imlib_mmx_blend_rgba_to_rgb): + ENTER + + pxor %mm4, %mm4 + movq c1, %mm5 + + LOOP_START +1: + /*\ Load source and destination \*/ + movd (%esi, %ecx, 4), %mm1 + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and unpack/copy to eight bytes + |*| which are treated as four words. + |*| Result ranges from [0, 0x7fff), and is mapped to + |*| point value in [0.0, 1.0) by using the high word + |*| of the 16->32 multiplications. + |*| (Because we want the unsigned value we shift one bit, + |*| and also shift the other factor to compensate.) + |*| Magic to get the fourth byte: lhh + \*/ + movq %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Make the alpha value that gets multiplied to the + |*| alpha channels 0, so the resulting alpha value is + |*| the destination alpha value. + \*/ + psrlq $16, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (a * ((s - d) + 0.5)) \*/ + psubw %mm2, %mm1 + psllw $1, %mm1 + paddw %mm5, %mm1 /*\ Roundoff \*/ + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_blend_rgba_to_rgb) + +PR_(imlib_mmx_blend_rgba_to_rgba): + ENTER + + pxor %mm4, %mm4 + movq m0X000000, %mm5 + movq m00XXXXXX, %mm6 + movq c1, %mm7 + + LOOP_START +1: + /*\ Load source and destination \*/ + movd (%esi, %ecx, 4), %mm1 + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and target, a = src + (255 - dest) \*/ + movq %mm2, %mm3 + pxor %mm6, %mm3 + paddusb %mm1, %mm3 + /*\ Unpack/copy to eight bytes \*/ + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ Separate alpha channel \*/ + movq %mm1, %mm0 + pand %mm5, %mm0 + + /*\ d = d + (a * ((s - d) + 0.5)) \*/ + psubw %mm2, %mm1 + psllw $1, %mm1 + paddw %mm7, %mm1 /*\ Roundoff \*/ + pmulhw %mm3, %mm1 + + /*\ Replace alpha channel with separated out version in mm0 and add \*/ + pand %mm6, %mm1 + por %mm0, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_blend_rgba_to_rgba) + +PR_(imlib_mmx_copy_rgba_to_rgb): + ENTER + + movq m0XXX0XXX, %mm5 + movq mX000X000, %mm6 + + /*\ Two at a time: last item is at %ecx = 0 \*/ + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + movq (%esi, %ecx, 4), %mm1 + movq (%edi, %ecx, 4), %mm2 + + /*\ Clear alpha channel of source, get alpha of destination \*/ + pand %mm5, %mm1 + pand %mm6, %mm2 + + /*\ d = d | s, and save \*/ + por %mm1, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + movd (%esi), %mm1 + movd (%edi), %mm2 + + pand %mm5, %mm1 + pand %mm6, %mm2 + + por %mm1, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_copy_rgba_to_rgb) + +PR_(imlib_mmx_copy_rgba_to_rgba): + ENTER + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source, save destination \*/ + movq (%esi, %ecx, 4), %mm1 + movq %mm1, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + movd (%esi), %mm1 + movd %mm1, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_copy_rgba_to_rgba) + +PR_(imlib_mmx_copy_rgb_to_rgba): + ENTER + + movq mX000X000, %mm5 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source, save destination \*/ + movq (%esi, %ecx, 4), %mm1 + por %mm5, %mm1 + movq %mm1, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + movd (%esi), %mm1 + por %mm5, %mm1 + movd %mm1, (%edi) +3: + + LOOP_END + LEAVE + +SIZE(imlib_mmx_copy_rgb_to_rgba) + +PR_(imlib_mmx_add_blend_rgba_to_rgb): + ENTER + + pxor %mm4, %mm4 + + LOOP_START +1: + /*\ Load source and destination \*/ + movd (%esi, %ecx, 4), %mm1 + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and unpack/copy to eight bytes \*/ + movq %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + psrlq $16, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (a * s) \*/ + psllw $1, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_add_blend_rgba_to_rgb) + +PR_(imlib_mmx_add_blend_rgba_to_rgba): + ENTER + + pxor %mm4, %mm4 + movq mVX000000, %mm5 + movq m00XXXXXX, %mm6 + + LOOP_START +1: + /*\ Load source and destination \*/ + movd (%esi, %ecx, 4), %mm1 + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and target and unpack/copy to eight bytes \*/ + movq %mm2, %mm3 + pxor %mm6, %mm3 + paddusb %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Make the alpha value that gets multiplied to the + |*| alpha channels 0x7fff, so the resulting alpha value is + |*| the sum of the source and destination alpha values. + \*/ + por %mm5, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (a * s) \*/ + psllw $1, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_add_blend_rgba_to_rgba) + +PR_(imlib_mmx_add_copy_rgba_to_rgb): + ENTER + + movq m0XXX0XXX, %mm5 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + movq (%esi, %ecx, 4), %mm1 + movq (%edi, %ecx, 4), %mm2 + + /*\ Clear alpha channel of source \*/ + pand %mm5, %mm1 + + /*\ d = d + s, unsigned saturation, and save \*/ + paddusb %mm1, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + movd (%esi), %mm1 + movd (%edi), %mm2 + pand %mm5, %mm1 + paddusb %mm1, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_add_copy_rgba_to_rgb) + +PR_(imlib_mmx_add_copy_rgba_to_rgba): + ENTER + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + movq (%esi, %ecx, 4), %mm1 + movq (%edi, %ecx, 4), %mm2 + + /*\ d = d + s, unsigned saturation, and save \*/ + paddusb %mm1, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + movd (%esi), %mm1 + movd (%edi), %mm2 + paddusb %mm1, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_add_copy_rgba_to_rgba) + +PR_(imlib_mmx_add_copy_rgb_to_rgba): + ENTER + + movq mX000X000, %mm5 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + movq (%esi, %ecx, 4), %mm1 + movq (%edi, %ecx, 4), %mm2 + + /*\ d = d + s, unsigned saturation, and save \*/ + paddusb %mm1, %mm2 + + /*\ Make result alpha 0xff \*/ + por %mm5, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + movd (%esi), %mm1 + movd (%edi), %mm2 + paddusb %mm1, %mm2 + por %mm5, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_add_copy_rgb_to_rgba) + +PR_(imlib_mmx_subtract_blend_rgba_to_rgb): + ENTER + + pxor %mm4, %mm4 + + LOOP_START +1: + /*\ Load source and destination \*/ + movd (%esi, %ecx, 4), %mm1 + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and unpack/copy to eight bytes \*/ + movq %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + psrlq $16, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d - (a * s) \*/ + psllw $1, %mm1 + pmulhw %mm3, %mm1 + psubw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_subtract_blend_rgba_to_rgb) + +PR_(imlib_mmx_subtract_blend_rgba_to_rgba): + ENTER + + pxor %mm4, %mm4 + movq mV0000000, %mm5 + movq m00XXXXXX, %mm6 + + LOOP_START +1: + /*\ Load source and destination \*/ + movd (%esi, %ecx, 4), %mm1 + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and target and unpack/copy to eight bytes \*/ + movq %mm2, %mm3 + pxor %mm6, %mm3 + paddusb %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Make alpha value that gets multiplied with alpha channel + |*| 0x8000, (-1.0), so that the alpha result is s + d + \*/ + psrlq $16, %mm3 + por %mm5, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d - (a * s) \*/ + psllw $1, %mm1 + pmulhw %mm3, %mm1 + psubw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_subtract_blend_rgba_to_rgba) + +PR_(imlib_mmx_subtract_copy_rgba_to_rgb): + ENTER + + movq m0XXX0XXX, %mm5 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + movq (%esi, %ecx, 4), %mm1 + movq (%edi, %ecx, 4), %mm2 + + /*\ Clear alpha channel of source \*/ + pand %mm5, %mm1 + + /*\ d = d - s, unsigned saturation, and save \*/ + psubusb %mm1, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + movd (%esi), %mm1 + movd (%edi), %mm2 + pand %mm5, %mm1 + psubusb %mm1, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_subtract_copy_rgba_to_rgb) + +PR_(imlib_mmx_subtract_copy_rgba_to_rgba): + ENTER + + movq mX000X000, %mm5 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + movq (%esi, %ecx, 4), %mm1 + movq (%edi, %ecx, 4), %mm2 + + /*\ Negate destination alphas \*/ + pxor %mm5, %mm2 + + /*\ d = d - s, unsigned saturation, and save \*/ + psubusb %mm1, %mm2 + + /*\ Negate result alphas \*/ + pxor %mm5, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + movd (%esi), %mm1 + movd (%edi), %mm2 + pxor %mm5, %mm2 + psubusb %mm1, %mm2 + pxor %mm5, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_subtract_copy_rgba_to_rgba) + +PR_(imlib_mmx_subtract_copy_rgb_to_rgba): + ENTER + + movq mX000X000, %mm5 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + movq (%esi, %ecx, 4), %mm1 + movq (%edi, %ecx, 4), %mm2 + + /*\ d = d - s, unsigned saturation, and save \*/ + psubusb %mm1, %mm2 + + /*\ Make result alpha 0xff \*/ + por %mm5, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + movd (%esi), %mm1 + movd (%edi), %mm2 + psubusb %mm1, %mm2 + por %mm5, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_subtract_copy_rgb_to_rgba) + +PR_(imlib_mmx_reshade_blend_rgba_to_rgb): + ENTER + + pxor %mm4, %mm4 + movq m000V0V0V, %mm6 + + LOOP_START +1: + /*\ Load source and destination \*/ + movd (%esi, %ecx, 4), %mm1 + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and unpack/copy to eight bytes \*/ + movq %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + psrlq $16, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (2 * a * (s - 127)) \*/ + psubw %mm6, %mm1 + psllw $2, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_reshade_blend_rgba_to_rgb) + +PR_(imlib_mmx_reshade_blend_rgba_to_rgba): + ENTER + + pxor %mm4, %mm4 + movq mI0000000, %mm5 + movq m000V0V0V, %mm6 + movq m00XXXXXX, %mm7 + + LOOP_START +1: + /*\ Load source and destination \*/ + movd (%esi, %ecx, 4), %mm1 + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and target and unpack/copy to eight bytes \*/ + movq %mm2, %mm3 + pxor %mm7, %mm3 + paddusb %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Make the alpha value that gets multiplied to the + |*| alpha channels 0x4000 (0.5), so the resulting alpha value is + |*| the sum of the source and destination alpha values. + \*/ + psrlq $16, %mm3 + por %mm5, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (2 * a * (s - 127)), (alpha channel: d = d + (2 * 0.5 * (s - 0)) ) \*/ + psubw %mm6, %mm1 + psllw $2, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_reshade_blend_rgba_to_rgba) + +PR_(imlib_mmx_reshade_copy_rgba_to_rgb): + ENTER + + pxor %mm4, %mm4 + movq m0XXX0XXX, %mm5 + movq m0VVV0VVV, %mm6 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + movq (%esi, %ecx, 4), %mm1 + movq (%edi, %ecx, 4), %mm2 + + /*\ To take advantage of saturation and be able to do 8 bytes + |*| at a time, we divide reshading into two separate steps: + |*| adding values above 128, and subtracting values below 128 + |*| These values go into %mm1 and %mm3 respectively + |*| - %mm1 becomes (2 * (s - 127)) + |*| - %mm3 becomes (2 * (255 - (127 + s))) = (2 * (128 - s)) + \*/ + movq %mm1, %mm3 + psubusb %mm6, %mm1 + paddusb %mm1, %mm1 + paddusb %mm6, %mm3 + pxor %mm5, %mm3 + paddusb %mm3, %mm3 + + /*\ Clear alpha channel of s1 and s2 \*/ + pand %mm5, %mm1 + pand %mm5, %mm3 + + /*\ d = d + s1 - s2, unsigned saturation, and save \*/ + paddusb %mm1, %mm2 + psubusb %mm3, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + movd (%esi), %mm1 + movd (%edi), %mm2 + movq %mm1, %mm3 + psubusb %mm6, %mm1 + paddusb %mm1, %mm1 + paddusb %mm6, %mm3 + pxor %mm5, %mm3 + paddusb %mm3, %mm3 + pand %mm5, %mm1 + pand %mm5, %mm3 + paddusb %mm1, %mm2 + psubusb %mm3, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_reshade_copy_rgba_to_rgb) + +PR_(imlib_mmx_reshade_copy_rgba_to_rgba): + ENTER + + pxor %mm4, %mm4 + movq m0XXX0XXX, %mm5 + movq m0VVV0VVV, %mm6 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + movq (%esi, %ecx, 4), %mm1 + movq (%edi, %ecx, 4), %mm2 + + /*\ This time, the alpha channels have to be added. + |*| For that, the alpha channel of %mm1 should remain + |*| the same. This is done by subtracting 0 from the + |*| alpha channel, and then doing the *2 via a separate + |*| register, clearing its alpha channel first. + \*/ + movq %mm1, %mm3 + psubusb %mm6, %mm1 + movq %mm1, %mm0 + pand %mm5, %mm0 + paddusb %mm0, %mm1 + paddusb %mm6, %mm3 + pxor %mm5, %mm3 + paddusb %mm3, %mm3 + + /*\ Clear alpha channel of s2 \*/ + pand %mm5, %mm3 + + /*\ d = d + s1 - s2, unsigned saturation, and save \*/ + paddusb %mm1, %mm2 + psubusb %mm3, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + movd (%esi), %mm1 + movd (%edi), %mm2 + movq %mm1, %mm3 + psubusb %mm6, %mm1 + movq %mm1, %mm0 + pand %mm5, %mm0 + paddusb %mm0, %mm1 + paddusb %mm6, %mm3 + pxor %mm5, %mm3 + paddusb %mm3, %mm3 + pand %mm5, %mm3 + paddusb %mm1, %mm2 + psubusb %mm3, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_reshade_copy_rgba_to_rgba) + +PR_(imlib_mmx_reshade_copy_rgb_to_rgba): + ENTER + + pxor %mm4, %mm4 + movq m0XXX0XXX, %mm5 + movq m0VVV0VVV, %mm6 + movq mX000X000, %mm7 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + movq (%esi, %ecx, 4), %mm1 + movq (%edi, %ecx, 4), %mm2 + + movq %mm1, %mm3 + psubusb %mm6, %mm1 + paddusb %mm1, %mm1 + paddusb %mm6, %mm3 + pxor %mm5, %mm3 + paddusb %mm3, %mm3 + + /*\ d = d + s1 - s2, unsigned saturation, and save \*/ + paddusb %mm1, %mm2 + psubusb %mm3, %mm2 + + /*\ Make result alpha 0xff \*/ + por %mm7, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + movd (%esi), %mm1 + movd (%edi), %mm2 + movq %mm1, %mm3 + psubusb %mm6, %mm1 + paddusb %mm1, %mm1 + paddusb %mm6, %mm3 + pxor %mm5, %mm3 + paddusb %mm3, %mm3 + paddusb %mm1, %mm2 + psubusb %mm3, %mm2 + por %mm7, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_reshade_copy_rgb_to_rgba) + +#endif diff --git a/src/lib/asm_blend_cmod.S b/src/lib/asm_blend_cmod.S new file mode 100644 index 0000000..a09c7c5 --- /dev/null +++ b/src/lib/asm_blend_cmod.S @@ -0,0 +1,1604 @@ +#include + +#ifdef __EMX__ +/* Due to strange behaviour of as.exe we use this macros */ +/* For all OS/2 coders - please use PGCC to compile this code */ +#define PR_(foo) ___##foo +#define PT_(foo,func) ___##foo,##func +#define SIZE(sym) \ + .___end_##sym:; \ + .size ___##sym,.___end_##sym-___##sym; \ + .align 8; +#else +#define PR_(foo) __##foo +#define PT_(foo,func) __##foo,##func +#define SIZE(sym) \ + .__end_##sym:; \ + .size __##sym,.__end_##sym-__##sym; \ + .align 8; +#endif + +#ifdef DO_MMX_ASM + +/*\ +|*| MMX assembly blending routines, with colour modding, for Imlib2 +|*| Written by Willem Monsuwe +|*| +|*| Special (hairy) constructs are only commented on first use. +\*/ + +/*\ All functions have the same calling convention: +|*| PR_(imlib_mmx__rgba_to_rgb[A]_cmod(void *src, int sw, void *dst, int dw, +|*| int w, int h, ImlibColorModifier *cm) +\*/ + +#define src 8(%ebp) +#define sw 12(%ebp) +#define dst 16(%ebp) +#define dw 20(%ebp) +#define w 24(%ebp) +#define h 28(%ebp) +#define cm 32(%ebp) + +/*\ Cmod tables, from %ebx \*/ +#define rmap(x) (%ebx, x) +#define gmap(x) 0x100(%ebx, x) +#define bmap(x) 0x200(%ebx, x) +#define amap(x) 0x300(%ebx, x) +#define amap_ff 0x3ff(%ebx) + +.text + .align 8 +.globl PR_(imlib_mmx_blend_rgba_to_rgb_cmod) + .type PT_(imlib_mmx_blend_rgba_to_rgb_cmod,@function) +.globl PR_(imlib_mmx_blend_rgba_to_rgba_cmod) + .type PT_(imlib_mmx_blend_rgba_to_rgba_cmod,@function) +.globl PR_(imlib_mmx_blend_rgb_to_rgb_cmod) + .type PT_(imlib_mmx_blend_rgb_to_rgb_cmod,@function) +.globl PR_(imlib_mmx_blend_rgb_to_rgba_cmod) + .type PT_(imlib_mmx_blend_rgb_to_rgba_cmod,@function) + +.globl PR_(imlib_mmx_copy_rgba_to_rgb_cmod) + .type PT_(imlib_mmx_copy_rgba_to_rgb_cmod,@function) +.globl PR_(imlib_mmx_copy_rgba_to_rgba_cmod) + .type PT_(imlib_mmx_copy_rgba_to_rgba_cmod,@function) +.globl PR_(imlib_mmx_copy_rgb_to_rgba_cmod) + .type PT_(imlib_mmx_copy_rgb_to_rgba_cmod,@function) + +.globl PR_(imlib_mmx_add_blend_rgba_to_rgb_cmod) + .type PT_(imlib_mmx_add_blend_rgba_to_rgb_cmod,@function) +.globl PR_(imlib_mmx_add_blend_rgba_to_rgba_cmod) + .type PT_(imlib_mmx_add_blend_rgba_to_rgba_cmod,@function) +.globl PR_(imlib_mmx_add_blend_rgb_to_rgb_cmod) + .type PT_(imlib_mmx_add_blend_rgb_to_rgb_cmod,@function) +.globl PR_(imlib_mmx_add_blend_rgb_to_rgba_cmod) + .type PT_(imlib_mmx_add_blend_rgb_to_rgba_cmod,@function) + +.globl PR_(imlib_mmx_add_copy_rgba_to_rgb_cmod) + .type PT_(imlib_mmx_add_copy_rgba_to_rgb_cmod,@function) +.globl PR_(imlib_mmx_add_copy_rgba_to_rgba_cmod) + .type PT_(imlib_mmx_add_copy_rgba_to_rgba_cmod,@function) +.globl PR_(imlib_mmx_add_copy_rgb_to_rgba_cmod) + .type PT_(imlib_mmx_add_copy_rgb_to_rgba_cmod,@function) + +.globl PR_(imlib_mmx_subtract_blend_rgba_to_rgb_cmod) + .type PT_(imlib_mmx_subtract_blend_rgba_to_rgb_cmod,@function) +.globl PR_(imlib_mmx_subtract_blend_rgba_to_rgba_cmod) + .type PT_(imlib_mmx_subtract_blend_rgba_to_rgba_cmod,@function) +.globl PR_(imlib_mmx_subtract_blend_rgb_to_rgb_cmod) + .type PT_(imlib_mmx_subtract_blend_rgb_to_rgb_cmod,@function) +.globl PR_(imlib_mmx_subtract_blend_rgb_to_rgba_cmod) + .type PT_(imlib_mmx_subtract_blend_rgb_to_rgba_cmod,@function) + +.globl PR_(imlib_mmx_subtract_copy_rgba_to_rgb_cmod) + .type PT_(imlib_mmx_subtract_copy_rgba_to_rgb_cmod,@function) +.globl PR_(imlib_mmx_subtract_copy_rgba_to_rgba_cmod) + .type PT_(imlib_mmx_subtract_copy_rgba_to_rgba_cmod,@function) +.globl PR_(imlib_mmx_subtract_copy_rgb_to_rgba_cmod) + .type PT_(imlib_mmx_subtract_copy_rgb_to_rgba_cmod,@function) + +.globl PR_(imlib_mmx_reshade_blend_rgba_to_rgb_cmod) + .type PT_(imlib_mmx_reshade_blend_rgba_to_rgb_cmod,@function) +.globl PR_(imlib_mmx_reshade_blend_rgba_to_rgba_cmod) + .type PT_(imlib_mmx_reshade_blend_rgba_to_rgba_cmod,@function) +.globl PR_(imlib_mmx_reshade_blend_rgb_to_rgb_cmod) + .type PT_(imlib_mmx_reshade_blend_rgb_to_rgb_cmod,@function) +.globl PR_(imlib_mmx_reshade_blend_rgb_to_rgba_cmod) + .type PT_(imlib_mmx_reshade_blend_rgb_to_rgba_cmod,@function) + +.globl PR_(imlib_mmx_reshade_copy_rgba_to_rgb_cmod) + .type PT_(imlib_mmx_reshade_copy_rgba_to_rgb_cmod,@function) +.globl PR_(imlib_mmx_reshade_copy_rgba_to_rgba_cmod) + .type PT_(imlib_mmx_reshade_copy_rgba_to_rgba_cmod,@function) +.globl PR_(imlib_mmx_reshade_copy_rgb_to_rgba_cmod) + .type PT_(imlib_mmx_reshade_copy_rgb_to_rgba_cmod,@function) + +/*\ Some useful masks \*/ +m0X000000: .byte 0, 0, 0, 0, 0, 0, 255, 0 +m10000000: .byte 0, 0, 0, 0, 0, 0, 0, 1 +m00XXXXXX: .byte 255, 255, 255, 255, 255, 255, 0, 0 +mVX000000: .byte 0, 0, 0, 0, 0, 0, 255, 127 +mV0000000: .byte 0, 0, 0, 0, 0, 0, 0, 128 +m0XXX0XXX: .byte 255, 255, 255, 0, 255, 255, 255, 0 +mX000X000: .byte 0, 0, 0, 255, 0, 0, 0, 255 +m10001000: .byte 0, 0, 0, 1, 0, 0, 0, 1 +m000V0V0V: .byte 127, 0, 127, 0, 127, 0, 0, 0 +mI0000000: .byte 0, 0, 0, 0, 0, 0, 0, 64 +m0VVV0VVV: .byte 127, 127, 127, 0, 127, 127, 127, 0 +c1: .word 0x1, 0x1, 0x1, 0x1 + +/*\ MMX register use: +|*| %mm1 = Source value +|*| %mm2 = Destination value +|*| %mm3 = Alpha value +|*| %mm4 = 0 +|*| %mm5-%mm6 = masks +\*/ + +/*\ Common code \*/ +/*\ Set MMX mode, save registers, load common parameters \*/ +#define ENTER \ + pushl %ebp ;\ + movl %esp, %ebp ;\ + pushl %ebx ;\ + pushl %ecx ;\ + pushl %edx ;\ + pushl %edi ;\ + pushl %esi ;\ + movl cm, %ebx ;\ + movl src, %esi ;\ + movl dst, %edi ;\ + movl w, %ecx ;\ + leal (%esi, %ecx, 4), %esi ;\ + leal (%edi, %ecx, 4), %edi ;\ + negl %ecx ;\ + jz 9f ;\ + movl h, %edx ;\ + decl %edx ;\ + jz 9f ;\ + +#define LOOP_START \ +8: ;\ + movl w, %ecx ;\ + negl %ecx + +#define LOOP_END \ + movl sw, %ecx ;\ + leal (%esi, %ecx, 4), %esi ;\ + movl dw, %ecx ;\ + leal (%edi, %ecx, 4), %edi ;\ + decl %edx ;\ + jns 8b + + +/*\ Unset MMX mode, reset registers, return \*/ +#define LEAVE \ +9: ;\ + emms ;\ + popl %esi ;\ + popl %edi ;\ + popl %edx ;\ + popl %ecx ;\ + popl %ebx ;\ + movl %ebp, %esp ;\ + popl %ebp ;\ + ret + + +/*\ Load one value, colourmod it, and put it in %mm1 \*/ +#define LOAD1_CMOD \ + movzbl 3(%esi, %ecx, 4), %eax ;\ + movzbl amap(%eax), %eax ;\ + movd %eax, %mm1 ;\ + movzbl 2(%esi, %ecx, 4), %eax ;\ + psllq $8, %mm1 ;\ + movzbl rmap(%eax), %eax ;\ + movd %eax, %mm0 ;\ + movzbl 1(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl gmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl (%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl bmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + por %mm0, %mm1 + + +/*\ Load two values, colourmod them, and put them in %mm1 \*/ +#define LOAD2_CMOD \ + movzbl 7(%esi, %ecx, 4), %eax ;\ + movzbl amap(%eax), %eax ;\ + movd %eax, %mm1 ;\ + movzbl 6(%esi, %ecx, 4), %eax ;\ + psllq $8, %mm1 ;\ + movzbl rmap(%eax), %eax ;\ + movd %eax, %mm0 ;\ + movzbl 5(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl gmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl 4(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl bmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl 3(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl amap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl 2(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl rmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl 1(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl gmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl (%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl bmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + por %mm0, %mm1 + + +/*\ Load one value, alpha 0xff, colourmod it, and put it in %mm1 \*/ +#define LOAD1_CMOD_AFF \ + movzbl amap_ff, %eax ;\ + movd %eax, %mm1 ;\ + movzbl 2(%esi, %ecx, 4), %eax ;\ + psllq $8, %mm1 ;\ + movzbl rmap(%eax), %eax ;\ + movd %eax, %mm0 ;\ + movzbl 1(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl gmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl (%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl bmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + por %mm0, %mm1 + + +/*\ Load two values, alpha 0xff, colourmod them, and put them in %mm1 \*/ +#define LOAD2_CMOD_AFF \ + movzbl amap_ff, %eax ;\ + movd %eax, %mm1 ;\ + movzbl 6(%esi, %ecx, 4), %eax ;\ + psllq $8, %mm1 ;\ + movzbl rmap(%eax), %eax ;\ + movd %eax, %mm0 ;\ + movzbl 5(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl gmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl 4(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl bmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + por %mm0, %mm1 ;\ + movzbl amap_ff, %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl 2(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl rmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl 1(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl gmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl (%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl bmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + por %mm0, %mm1 + + +/*\ Load one value, colourmod it, alpha 0, and put it in %mm1 \*/ +#define LOAD1_CMOD_A00 \ + movzbl 2(%esi, %ecx, 4), %eax ;\ + movzbl rmap(%eax), %eax ;\ + movd %eax, %mm1 ;\ + movzbl 1(%esi, %ecx, 4), %eax ;\ + psllq $8, %mm1 ;\ + movzbl gmap(%eax), %eax ;\ + movd %eax, %mm0 ;\ + movzbl (%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl bmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + por %mm0, %mm1 + + +/*\ Load two values, colourmod them, alpha 0, and put them in %mm1 \*/ +#define LOAD2_CMOD_A00 \ + movzbl 6(%esi, %ecx, 4), %eax ;\ + movzbl rmap(%eax), %eax ;\ + movd %eax, %mm1 ;\ + movzbl 5(%esi, %ecx, 4), %eax ;\ + psllq $8, %mm1 ;\ + movzbl gmap(%eax), %eax ;\ + movd %eax, %mm0 ;\ + movzbl 4(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl bmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl 2(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl rmap(%eax), %eax ;\ + psllq $16, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl 1(%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl gmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + movzbl (%esi, %ecx, 4), %eax ;\ + por %mm0, %mm1 ;\ + movzbl bmap(%eax), %eax ;\ + psllq $8, %mm1 ;\ + movd %eax, %mm0 ;\ + por %mm0, %mm1 + + + +PR_(imlib_mmx_blend_rgba_to_rgb_cmod): + ENTER + + pxor %mm4, %mm4 + movq c1, %mm5 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and unpack/copy to eight bytes + |*| which are treated as four words. + |*| Result ranges from [0, 0x7fff), and is mapped to + |*| point value in [0.0, 1.0) by using the high word + |*| of the 16->32 multiplications. + |*| (Because we want the unsigned value we shift one bit, + |*| and also shift the other factor to compensate.) + |*| Magic to get the fourth byte: lhh + \*/ + movq %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Make the alpha value that gets multiplied to the + |*| alpha channels 0, so the resulting alpha value is + |*| the destination alpha value. + \*/ + psrlq $16, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (a * ((s - d) + 0.5)) \*/ + psubw %mm2, %mm1 + psllw $1, %mm1 + paddw %mm5, %mm1 /*\ Roundoff \*/ + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_blend_rgba_to_rgb_cmod) + +PR_(imlib_mmx_blend_rgba_to_rgba_cmod): + ENTER + + pxor %mm4, %mm4 + movq m0X000000, %mm5 + movq m00XXXXXX, %mm6 + movq c1, %mm7 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and target, a = src + (255 - dest) \*/ + movq %mm2, %mm3 + pxor %mm6, %mm3 + paddusb %mm1, %mm3 + /*\ Unpack/copy to eight bytes \*/ + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ Separate alpha channel \*/ + movq %mm1, %mm0 + pand %mm5, %mm0 + + /*\ d = d + (a * ((s - d) + 0.5)) \*/ + psubw %mm2, %mm1 + psllw $1, %mm1 + paddw %mm7, %mm1 /*\ Roundoff \*/ + pmulhw %mm3, %mm1 + + /*\ Replace alpha channel with separated out version in mm0 and add \*/ + pand %mm6, %mm1 + por %mm0, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_blend_rgba_to_rgba_cmod) + +PR_(imlib_mmx_blend_rgb_to_rgb_cmod): + ENTER + + pxor %mm4, %mm4 + movq c1, %mm5 + + /*\ Load alpha beforehand, as it's always amap(0xff) \*/ + movzbl amap_ff, %eax + movd %eax, %mm3 + punpcklbw %mm3, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + psrlw $1, %mm3 + psrlq $16, %mm3 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD_A00 + movd (%edi, %ecx, 4), %mm2 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (a * ((s - d) + 0.5)) \*/ + psubw %mm2, %mm1 + psllw $1, %mm1 + paddw %mm5, %mm1 /*\ Roundoff \*/ + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_blend_rgb_to_rgb_cmod) + +PR_(imlib_mmx_blend_rgb_to_rgba_cmod): + ENTER + + pxor %mm4, %mm4 + movq m0X000000, %mm5 + movq m00XXXXXX, %mm6 + movq c1, %mm7 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD_AFF + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and target, a = src + (255 - dest) \*/ + movq %mm2, %mm3 + pxor %mm6, %mm3 + paddusb %mm1, %mm3 + /*\ Unpack/copy to eight bytes \*/ + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ Separate alpha channel \*/ + movq %mm1, %mm0 + pand %mm5, %mm0 + + /*\ d = d + (a * ((s - d) + 0.5)) \*/ + psubw %mm2, %mm1 + psllw $1, %mm1 + paddw %mm7, %mm1 /*\ Roundoff \*/ + pmulhw %mm3, %mm1 + + /*\ Replace alpha channel with separated out version in mm0 and add \*/ + pand %mm6, %mm1 + por %mm0, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_blend_rgb_to_rgba_cmod) + +PR_(imlib_mmx_copy_rgba_to_rgb_cmod): + ENTER + + LOOP_START +1: + movzbl (%esi, %ecx, 4), %eax + movzbl bmap(%eax), %eax + movb %al, (%edi, %ecx, 4) + movzbl 1(%esi, %ecx, 4), %eax + movzbl gmap(%eax), %eax + movb %al, 1(%edi, %ecx, 4) + movzbl 2(%esi, %ecx, 4), %eax + movzbl rmap(%eax), %eax + movb %al, 2(%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_copy_rgba_to_rgb_cmod) + +PR_(imlib_mmx_copy_rgba_to_rgba_cmod): + ENTER + + LOOP_START +1: + movzbl (%esi, %ecx, 4), %eax + movzbl bmap(%eax), %eax + movb %al, (%edi, %ecx, 4) + movzbl 1(%esi, %ecx, 4), %eax + movzbl gmap(%eax), %eax + movb %al, 1(%edi, %ecx, 4) + movzbl 2(%esi, %ecx, 4), %eax + movzbl rmap(%eax), %eax + movb %al, 2(%edi, %ecx, 4) + movzbl 3(%esi, %ecx, 4), %eax + movzbl amap(%eax), %eax + movb %al, 3(%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_copy_rgba_to_rgba_cmod) + +PR_(imlib_mmx_copy_rgb_to_rgba_cmod): + ENTER + + LOOP_START +1: + movzbl (%esi, %ecx, 4), %eax + movzbl bmap(%eax), %eax + movb %al, (%edi, %ecx, 4) + movzbl 1(%esi, %ecx, 4), %eax + movzbl gmap(%eax), %eax + movb %al, 1(%edi, %ecx, 4) + movzbl 2(%esi, %ecx, 4), %eax + movzbl rmap(%eax), %eax + movb %al, 2(%edi, %ecx, 4) + movb $0xff, 3(%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_copy_rgb_to_rgba_cmod) + +PR_(imlib_mmx_add_blend_rgba_to_rgb_cmod): + ENTER + + pxor %mm4, %mm4 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and unpack/copy to eight bytes \*/ + movq %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + psrlq $16, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (a * s) \*/ + psllw $1, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_add_blend_rgba_to_rgb_cmod) + +PR_(imlib_mmx_add_blend_rgba_to_rgba_cmod): + ENTER + + pxor %mm4, %mm4 + movq mVX000000, %mm5 + movq m00XXXXXX, %mm6 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and target and unpack/copy to eight bytes \*/ + movq %mm2, %mm3 + pxor %mm6, %mm3 + paddusb %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Make the alpha value that gets multiplied to the + |*| alpha channels 0x7fff, so the resulting alpha value is + |*| the sum of the source and destination alpha values. + \*/ + por %mm5, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (a * s) \*/ + psllw $1, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_add_blend_rgba_to_rgba_cmod) + +PR_(imlib_mmx_add_blend_rgb_to_rgb_cmod): + ENTER + + pxor %mm4, %mm4 + + /*\ Load alpha beforehand, as it's always amap(0xff) \*/ + movzbl amap_ff, %eax + movd %eax, %mm3 + punpcklbw %mm3, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + psrlw $1, %mm3 + psrlq $16, %mm3 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD_A00 + movd (%edi, %ecx, 4), %mm2 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (a * s) \*/ + psllw $1, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_add_blend_rgb_to_rgb_cmod) + +PR_(imlib_mmx_add_blend_rgb_to_rgba_cmod): + ENTER + + pxor %mm4, %mm4 + movq mVX000000, %mm5 + movq m00XXXXXX, %mm6 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD_AFF + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and target and unpack/copy to eight bytes \*/ + movq %mm2, %mm3 + pxor %mm6, %mm3 + paddusb %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Make the alpha value that gets multiplied to the + |*| alpha channels 0x7fff, so the resulting alpha value is + |*| the sum of the source and destination alpha values. + \*/ + por %mm5, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (a * s) \*/ + psllw $1, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_add_blend_rgb_to_rgba_cmod) + +PR_(imlib_mmx_add_copy_rgba_to_rgb_cmod): + ENTER + + movq m0XXX0XXX, %mm5 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + LOAD2_CMOD + movq (%edi, %ecx, 4), %mm2 + + /*\ Clear alpha channel of source \*/ + pand %mm5, %mm1 + + /*\ d = d + s, unsigned saturation, and save \*/ + paddusb %mm1, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + LOAD1_CMOD + movd (%edi), %mm2 + pand %mm5, %mm1 + paddusb %mm1, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_add_copy_rgba_to_rgb_cmod) + +PR_(imlib_mmx_add_copy_rgba_to_rgba_cmod): + ENTER + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + LOAD2_CMOD + movq (%edi, %ecx, 4), %mm2 + + /*\ d = d + s, unsigned saturation, and save \*/ + paddusb %mm1, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + LOAD1_CMOD + movd (%edi), %mm2 + paddusb %mm1, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_add_copy_rgba_to_rgba_cmod) + +PR_(imlib_mmx_add_copy_rgb_to_rgba_cmod): + ENTER + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + LOAD2_CMOD_AFF + movq (%edi, %ecx, 4), %mm2 + + /*\ d = d + s, unsigned saturation, and save \*/ + paddusb %mm1, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + LOAD1_CMOD_AFF + movd (%edi), %mm2 + paddusb %mm1, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_add_copy_rgb_to_rgba_cmod) + +PR_(imlib_mmx_subtract_blend_rgba_to_rgb_cmod): + ENTER + + pxor %mm4, %mm4 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and unpack/copy to eight bytes \*/ + movq %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + psrlq $16, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d - (a * s) \*/ + psllw $1, %mm1 + pmulhw %mm3, %mm1 + psubw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_subtract_blend_rgba_to_rgb_cmod) + +PR_(imlib_mmx_subtract_blend_rgba_to_rgba_cmod): + ENTER + + pxor %mm4, %mm4 + movq mV0000000, %mm5 + movq m00XXXXXX, %mm6 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and target and unpack/copy to eight bytes \*/ + movq %mm2, %mm3 + pxor %mm6, %mm3 + paddusb %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Make alpha value that gets multiplied with alpha channel + |*| 0x8000, (-1.0), so that the alpha result is s + d + \*/ + psrlq $16, %mm3 + por %mm5, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d - (a * s) \*/ + psllw $1, %mm1 + pmulhw %mm3, %mm1 + psubw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_subtract_blend_rgba_to_rgba_cmod) + +PR_(imlib_mmx_subtract_blend_rgb_to_rgb_cmod): + ENTER + + pxor %mm4, %mm4 + + /*\ Load alpha beforehand, as it's always amap(0xff) \*/ + movzbl amap_ff, %eax + movd %eax, %mm3 + punpcklbw %mm3, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + psrlw $1, %mm3 + psrlq $16, %mm3 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD_A00 + movd (%edi, %ecx, 4), %mm2 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d - (a * s) \*/ + psllw $1, %mm1 + pmulhw %mm3, %mm1 + psubw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_subtract_blend_rgb_to_rgb_cmod) + +PR_(imlib_mmx_subtract_blend_rgb_to_rgba_cmod): + ENTER + + pxor %mm4, %mm4 + movq mV0000000, %mm5 + movq m00XXXXXX, %mm6 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD_AFF + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and target and unpack/copy to eight bytes \*/ + movq %mm2, %mm3 + pxor %mm6, %mm3 + paddusb %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Make alpha value that gets multiplied with alpha channel + |*| 0x8000, (-1.0), so that the alpha result is s + d + \*/ + psrlq $16, %mm3 + por %mm5, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d - (a * s) \*/ + psllw $1, %mm1 + pmulhw %mm3, %mm1 + psubw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_subtract_blend_rgb_to_rgba_cmod) + +PR_(imlib_mmx_subtract_copy_rgba_to_rgb_cmod): + ENTER + + movq m0XXX0XXX, %mm5 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + LOAD2_CMOD + movq (%edi, %ecx, 4), %mm2 + + /*\ Clear alpha channel of source \*/ + pand %mm5, %mm1 + + /*\ d = d - s, unsigned saturation, and save \*/ + psubusb %mm1, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + LOAD1_CMOD + movd (%edi), %mm2 + pand %mm5, %mm1 + psubusb %mm1, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_subtract_copy_rgba_to_rgb_cmod) + +PR_(imlib_mmx_subtract_copy_rgba_to_rgba_cmod): + ENTER + + movq mX000X000, %mm5 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + LOAD2_CMOD + movq (%edi, %ecx, 4), %mm2 + + /*\ Negate destination alphas \*/ + pxor %mm5, %mm2 + + /*\ d = d - s, unsigned saturation, and save \*/ + psubusb %mm1, %mm2 + + /*\ Negate result alphas \*/ + pxor %mm5, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + LOAD1_CMOD + movd (%edi), %mm2 + pxor %mm5, %mm2 + psubusb %mm1, %mm2 + pxor %mm5, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_subtract_copy_rgba_to_rgba_cmod) + +PR_(imlib_mmx_subtract_copy_rgb_to_rgba_cmod): + ENTER + + movq mX000X000, %mm5 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + LOAD2_CMOD_AFF + movq (%edi, %ecx, 4), %mm2 + pxor %mm5, %mm2 + + /*\ d = d - s, unsigned saturation, and save \*/ + psubusb %mm1, %mm2 + pxor %mm5, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + LOAD1_CMOD_AFF + movd (%edi), %mm2 + pxor %mm5, %mm2 + psubusb %mm1, %mm2 + pxor %mm5, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_subtract_copy_rgb_to_rgba_cmod) + +PR_(imlib_mmx_reshade_blend_rgba_to_rgb_cmod): + ENTER + + pxor %mm4, %mm4 + movq m000V0V0V, %mm6 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and unpack/copy to eight bytes \*/ + movq %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + psrlq $16, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (2 * a * (s - 127)) \*/ + psubw %mm6, %mm1 + psllw $2, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_reshade_blend_rgba_to_rgb_cmod) + +PR_(imlib_mmx_reshade_blend_rgba_to_rgba_cmod): + ENTER + + pxor %mm4, %mm4 + movq mI0000000, %mm5 + movq m000V0V0V, %mm6 + movq m00XXXXXX, %mm7 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and target and unpack/copy to eight bytes \*/ + movq %mm2, %mm3 + pxor %mm7, %mm3 + paddusb %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Make the alpha value that gets multiplied to the + |*| alpha channels 0x4000 (0.5), so the resulting alpha value is + |*| the sum of the source and destination alpha values. + \*/ + psrlq $16, %mm3 + por %mm5, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (2 * a * (s - 127)), (alpha channel: d = d + (2 * 0.5 * (s - 0)) ) \*/ + psubw %mm6, %mm1 + psllw $2, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_reshade_blend_rgba_to_rgba_cmod) + +PR_(imlib_mmx_reshade_blend_rgb_to_rgb_cmod): + ENTER + + pxor %mm4, %mm4 + movq m000V0V0V, %mm6 + + /*\ Load alpha beforehand, as it's always amap(0xff) \*/ + movzbl amap_ff, %eax + movd %eax, %mm3 + punpcklbw %mm3, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + psrlw $1, %mm3 + psrlq $16, %mm3 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD_A00 + movd (%edi, %ecx, 4), %mm2 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (2 * a * (s - 127)) \*/ + psubw %mm6, %mm1 + psllw $2, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_reshade_blend_rgb_to_rgb_cmod) + +PR_(imlib_mmx_reshade_blend_rgb_to_rgba_cmod): + ENTER + + pxor %mm4, %mm4 + movq mI0000000, %mm5 + movq m000V0V0V, %mm6 + movq m00XXXXXX, %mm7 + + LOOP_START +1: + /*\ Load source and destination \*/ + LOAD1_CMOD_AFF + movd (%edi, %ecx, 4), %mm2 + + /*\ Get alpha from source and target and unpack/copy to eight bytes \*/ + movq %mm2, %mm3 + pxor %mm7, %mm3 + paddusb %mm1, %mm3 + punpcklbw %mm3, %mm3 + punpckhwd %mm3, %mm3 + punpckhdq %mm3, %mm3 + psrlw $1, %mm3 + + /*\ Make the alpha value that gets multiplied to the + |*| alpha channels 0x4000 (0.5), so the resulting alpha value is + |*| the sum of the source and destination alpha values. + \*/ + psrlq $16, %mm3 + por %mm5, %mm3 + + /*\ Unpack source and destination, bytes to words \*/ + punpcklbw %mm4, %mm1 + punpcklbw %mm4, %mm2 + + /*\ d = d + (2 * a * (s - 127)), (alpha channel: d = d + (2 * 0.5 * (s - 0)) ) \*/ + psubw %mm6, %mm1 + psllw $2, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm2 + + /*\ Pack into lower 4 bytes and save \*/ + packuswb %mm4, %mm2 + movd %mm2, (%edi, %ecx, 4) + + incl %ecx + js 1b + + LOOP_END + LEAVE + +SIZE(imlib_mmx_reshade_blend_rgb_to_rgba_cmod) + +PR_(imlib_mmx_reshade_copy_rgba_to_rgb_cmod): + ENTER + + pxor %mm4, %mm4 + movq m0XXX0XXX, %mm5 + movq m0VVV0VVV, %mm6 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + LOAD2_CMOD + movq (%edi, %ecx, 4), %mm2 + + /*\ To take advantage of saturation and be able to do 8 bytes + |*| at a time, we divide reshading into two separate steps: + |*| adding values above 128, and subtracting values below 128 + |*| These values go into %mm1 and %mm3 respectively + |*| - %mm1 becomes (2 * (s - 127)) + |*| - %mm3 becomes (2 * (255 - (127 + s))) = (2 * (128 - s)) + \*/ + movq %mm1, %mm3 + psubusb %mm6, %mm1 + paddusb %mm1, %mm1 + paddusb %mm6, %mm3 + pxor %mm5, %mm3 + paddusb %mm3, %mm3 + + /*\ Clear alpha channel of s1 and s2 \*/ + pand %mm5, %mm1 + pand %mm5, %mm3 + + /*\ d = d + s1 - s2, unsigned saturation, and save \*/ + paddusb %mm1, %mm2 + psubusb %mm3, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + LOAD1_CMOD + movd (%edi), %mm2 + movq %mm1, %mm3 + psubusb %mm6, %mm1 + paddusb %mm1, %mm1 + paddusb %mm6, %mm3 + pxor %mm5, %mm3 + paddusb %mm3, %mm3 + pand %mm5, %mm1 + pand %mm5, %mm3 + paddusb %mm1, %mm2 + psubusb %mm3, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_reshade_copy_rgba_to_rgb_cmod) + +PR_(imlib_mmx_reshade_copy_rgba_to_rgba_cmod): + ENTER + + pxor %mm4, %mm4 + movq m0XXX0XXX, %mm5 + movq m0VVV0VVV, %mm6 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + LOAD2_CMOD + movq (%edi, %ecx, 4), %mm2 + + /*\ This time, the alpha channels have to be added. + |*| For that, the alpha channel of %mm1 should remain + |*| the same. This is done by subtracting 0 from the + |*| alpha channel, and then doing the *2 via a separate + |*| register, clearing its alpha channel first. + \*/ + movq %mm1, %mm3 + psubusb %mm6, %mm1 + movq %mm1, %mm0 + pand %mm5, %mm0 + paddusb %mm0, %mm1 + paddusb %mm6, %mm3 + pxor %mm5, %mm3 + paddusb %mm3, %mm3 + + /*\ Clear alpha channel of s2 \*/ + pand %mm5, %mm3 + + /*\ d = d + s1 - s2, unsigned saturation, and save \*/ + paddusb %mm1, %mm2 + psubusb %mm3, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + LOAD1_CMOD + movd (%edi), %mm2 + movq %mm1, %mm3 + psubusb %mm6, %mm1 + movq %mm1, %mm0 + pand %mm5, %mm0 + paddusb %mm0, %mm1 + paddusb %mm6, %mm3 + pxor %mm5, %mm3 + paddusb %mm3, %mm3 + pand %mm5, %mm3 + paddusb %mm1, %mm2 + psubusb %mm3, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_reshade_copy_rgba_to_rgba_cmod) + +PR_(imlib_mmx_reshade_copy_rgb_to_rgba_cmod): + ENTER + + pxor %mm4, %mm4 + movq m0XXX0XXX, %mm5 + movq m0VVV0VVV, %mm6 + + subl $4, %esi + subl $4, %edi + + LOOP_START + incl %ecx + jz 2f +1: + /*\ Load source and destination \*/ + LOAD2_CMOD_AFF + movq (%edi, %ecx, 4), %mm2 + + movq %mm1, %mm3 + psubusb %mm6, %mm1 + movq %mm1, %mm0 + pand %mm5, %mm0 + paddusb %mm0, %mm1 + paddusb %mm6, %mm3 + pxor %mm5, %mm3 + paddusb %mm3, %mm3 + + /*\ Clear alpha channel of s2 \*/ + pand %mm5, %mm3 + + /*\ d = d + s1 - s2, unsigned saturation, and save \*/ + paddusb %mm1, %mm2 + psubusb %mm3, %mm2 + movq %mm2, (%edi, %ecx, 4) + + addl $2, %ecx + js 1b + jnz 3f +2: + LOAD1_CMOD_AFF + movd (%edi), %mm2 + movq %mm1, %mm3 + psubusb %mm6, %mm1 + movq %mm1, %mm0 + pand %mm5, %mm0 + paddusb %mm0, %mm1 + paddusb %mm6, %mm3 + pxor %mm5, %mm3 + paddusb %mm3, %mm3 + pand %mm5, %mm3 + paddusb %mm1, %mm2 + psubusb %mm3, %mm2 + movd %mm2, (%edi) +3: + LOOP_END + LEAVE + +SIZE(imlib_mmx_reshade_copy_rgb_to_rgba_cmod) + +#endif diff --git a/src/lib/asm_rgba.S b/src/lib/asm_rgba.S new file mode 100644 index 0000000..ff122c8 --- /dev/null +++ b/src/lib/asm_rgba.S @@ -0,0 +1,301 @@ +#include + +#ifdef __EMX__ +/* Due to strange behaviour of as.exe we use this macros */ +/* For all OS/2 coders - please use PGCC to compile this code */ +#define PR_(foo) ___##foo +#define PT_(foo,func) ___##foo,##func +#define SIZE(sym) \ + .___end_##sym:; \ + .size ___##sym,.___end_##sym-___##sym; \ + .align 8; +#else +#define PR_(foo) __##foo +#define PT_(foo,func) __##foo,##func +#define SIZE(sym) \ + .__end_##sym:; \ + .size __##sym,.__end_##sym-__##sym; \ + .align 8; +#endif + +#ifdef DO_MMX_ASM + +/*\ +|*| MMX assembly rgba rendering routines for Imlib2 +|*| Written by Willem Monsuwe +|*| +|*| Special (hairy) constructs are only commented on first use. +\*/ + +/*\ All functions have the same calling convention: +|*| __imlib_mmx_rgbXXX(void *src, int sjmp, void *dst, int dw, +|*| int w, int h, int dx, int dy) +\*/ + +#define src 8(%ebp) +#define sjmp 12(%ebp) +#define dst 16(%ebp) +#define dw 20(%ebp) +#define w 24(%ebp) +#define h 28(%ebp) +#define dx 32(%ebp) +#define dy 36(%ebp) + +.text + .align 8 +.globl PR_(imlib_mmx_rgb565_fast) + .type PT_(imlib_mmx_rgb565_fast,@function) +.globl PR_(imlib_mmx_bgr565_fast) + .type PT_(imlib_mmx_bgr565_fast,@function) +.globl PR_(imlib_mmx_rgb555_fast) + .type PT_(imlib_mmx_rgb555_fast,@function) +.globl PR_(imlib_mmx_bgr555_fast) + .type PT_(imlib_mmx_bgr555_fast,@function) + +.globl PR_(imlib_get_cpuid) + .type PT_(imlib_get_cpuid,@function) + +/*\ Some useful masks \*/ +m_rb: .long 0x00f800f8, 0x00f800f8 +m_r: .long 0xf800f800, 0xf800f800 +m_g6: .long 0x0000fc00, 0x0000fc00 +m_g5: .long 0x0000f800, 0x0000f800 +/*\ Multiply constants to fake two shifts at once \*/ +mul_rgb565: .long 0x20000004, 0x20000004 +mul_bgr565: .long 0x00042000, 0x00042000 +mul_rgb555: .long 0x20000008, 0x20000008 +mul_bgr555: .long 0x00082000, 0x00082000 + +/*\ Common code \*/ +/*\ Save registers, load common parameters \*/ +#define ENTER \ + pushl %ebp; \ + movl %esp, %ebp; \ + pushl %ebx; \ + pushl %ecx; \ + pushl %edx; \ + pushl %edi; \ + pushl %esi; \ + movl src, %esi; \ + movl dst, %edi; \ + movl w, %ebx; \ + movl h, %edx; \ + addl %ebx, sjmp + +#define LOOP_START \ + testl %edx, %edx; \ + jz 4f; \ + testl %ebx, %ebx; \ + jz 4f; \ +0: \ + movl %ebx, %ecx + +#define LOOP_END \ +3: \ + movl sjmp, %ecx; \ + leal (%esi, %ecx, 4), %esi; \ + addl dw, %edi; \ + decl %edx; \ + jnz 0b; \ +4: + +/*\ Unset MMX mode, reset registers, return \*/ +#define LEAVE \ + emms; \ + popl %esi; \ + popl %edi; \ + popl %edx; \ + popl %ecx; \ + popl %ebx; \ + movl %ebp, %esp; \ + popl %ebp; \ + ret + + + +PR_(imlib_mmx_bgr565_fast): + movq mul_bgr565, %mm7 /*\ This constant is the only difference \*/ + jmp .rgb565_fast_entry + +SIZE(imlib_mmx_bgr565_fast) + +PR_(imlib_mmx_rgb565_fast): + movq mul_rgb565, %mm7 +.rgb565_fast_entry: + ENTER + + movq m_rb, %mm5 + movq m_g6, %mm6 + + LOOP_START + + test $1, %ecx + jz 1f + decl %ecx + movd (%esi, %ecx, 4), %mm0 + movq %mm0, %mm1 + pand %mm5, %mm0 + pand %mm6, %mm1 + pmaddwd %mm7, %mm0 + por %mm1, %mm0 + psrad $5, %mm0 + + movd %mm0, %eax + movw %ax, (%edi, %ecx, 2) + + jz 3f +1: + test $2, %ecx + jz 2f + subl $2, %ecx + movq (%esi, %ecx, 4), %mm0 + movq %mm0, %mm1 + pand %mm5, %mm0 + pand %mm6, %mm1 + pmaddwd %mm7, %mm0 + por %mm1, %mm0 + pslld $11, %mm0 + psrad $16, %mm0 + + packssdw %mm0, %mm0 + + movd %mm0, (%edi, %ecx, 2) + + jz 3f +2: + subl $4, %ecx + movq (%esi, %ecx, 4), %mm0 + movq 8(%esi, %ecx, 4), %mm2 + movq %mm0, %mm1 /*\ a r g b (2x) \*/ + movq %mm2, %mm3 + pand %mm5, %mm0 /*\ 0 rrrrr000 0 bbbbb000 (2 x) \*/ + pand %mm5, %mm2 + pand %mm6, %mm1 /*\ 0 0 gggggg00 00000000 (2 x) \*/ + pand %mm6, %mm3 + pmaddwd %mm7, %mm0 /*\ 0 000rrrrr 000000bb bbb00000 (2 x) \*/ + pmaddwd %mm7, %mm2 + por %mm1, %mm0 /*\ 0 000rrrrr ggggggbb bbb00000 (2 x) \*/ + por %mm3, %mm2 + pslld $11, %mm0 /*\ rrrrrggg gggbbbbb 0 0 (2 x) \*/ + pslld $11, %mm2 + psrad $16, %mm0 /*\ x x rrrrrggg gggbbbbb (2 x) \*/ + psrad $16, %mm2 + + packssdw %mm2, %mm0 /*\ rrrrrggg gggbbbbb (4 x) \*/ + + movq %mm0, (%edi, %ecx, 2) + + jnz 2b + LOOP_END + LEAVE + +SIZE(imlib_mmx_rgb565_fast) + + +PR_(imlib_mmx_bgr555_fast): + movq mul_bgr555, %mm7 /*\ This constant is the only difference \*/ + jmp .rgb555_fast_entry + +SIZE(imlib_mmx_bgr555_fast) + +PR_(imlib_mmx_rgb555_fast): + movq mul_rgb555, %mm7 +.rgb555_fast_entry: + ENTER + + movq m_rb, %mm5 + movq m_g5, %mm6 + + LOOP_START + + test $1, %ecx + jz 1f + decl %ecx + movd (%esi, %ecx, 4), %mm0 + movq %mm0, %mm1 + pand %mm5, %mm0 + pand %mm6, %mm1 + pmaddwd %mm7, %mm0 + por %mm1, %mm0 + psrad $5, %mm0 + + movd %mm0, %eax + movw %ax, (%edi, %ecx, 2) + + jz 3f +1: + test $2, %ecx + jz 2f + subl $2, %ecx + movq (%esi, %ecx, 4), %mm0 + movq %mm0, %mm1 + pand %mm5, %mm0 + pand %mm6, %mm1 + pmaddwd %mm7, %mm0 + por %mm1, %mm0 + psrld $6, %mm0 + + packssdw %mm0, %mm0 + + movd %mm0, (%edi, %ecx, 2) + + jz 3f +2: + subl $4, %ecx + movq (%esi, %ecx, 4), %mm0 + movq 8(%esi, %ecx, 4), %mm2 + movq %mm0, %mm1 /*\ a r g b (2x) \*/ + movq %mm2, %mm3 + pand %mm5, %mm0 /*\ 0 rrrrr000 0 bbbbb000 (2 x) \*/ + pand %mm5, %mm2 + pand %mm6, %mm1 /*\ 0 0 ggggg000 00000000 (2 x) \*/ + pand %mm6, %mm3 + pmaddwd %mm7, %mm0 /*\ 0 000rrrrr 00000bbb bb000000 (2 x) \*/ + pmaddwd %mm7, %mm2 + por %mm1, %mm0 /*\ 0 000rrrrr gggggbbb bb000000 (2 x) \*/ + por %mm3, %mm2 + psrld $6, %mm0 /*\ 0 0 0rrrrrgg gggbbbbb (2 x) \*/ + psrld $6, %mm2 + + packssdw %mm2, %mm0 /*\ 0rrrrrgg gggbbbbb (4 x) \*/ + + movq %mm0, (%edi, %ecx, 2) + + jnz 2b + LOOP_END + LEAVE + +SIZE(imlib_mmx_rgb555_fast) + +PR_(imlib_get_cpuid): + pushl %ebx + pushl %edx + + pushf + popl %eax + movl %eax, %ebx + xorl $0x200000, %eax + pushl %eax + popf + pushf + popl %eax + xorl %ebx, %eax + andl $0x200000, %eax + jz 1f + xorl %eax, %eax + cpuid + testl %eax, %eax + jz 1f + movl $1, %eax + cpuid + and $0x00000f00, %eax + and $0xfffff0ff, %edx + orl %edx, %eax +1: + popl %edx + popl %ebx + ret + +SIZE(imlib_get_cpuid) + +#endif diff --git a/src/lib/asm_rotate.S b/src/lib/asm_rotate.S new file mode 100644 index 0000000..b8f9527 --- /dev/null +++ b/src/lib/asm_rotate.S @@ -0,0 +1,469 @@ +#include + +#ifdef __EMX__ +/* Due to strange behaviour of as.exe we use this macros */ +/* For all OS/2 coders - please use PGCC to compile this code */ +#define PR_(foo) ___##foo +#define PT_(foo,func) ___##foo,##func +#define SIZE(sym) \ + .___end_##sym:; \ + .size ___##sym,.___end_##sym-___##sym; \ + .align 8; +#else +#define PR_(foo) __##foo +#define PT_(foo,func) __##foo,##func +#define SIZE(sym) \ + .__end_##sym:; \ + .size __##sym,.__end_##sym-__##sym; \ + .align 8; +#endif + +#ifdef DO_MMX_ASM + +/*\ +|*| MMX assembly rotation routine for Imlib2 +|*| Written by Willem Monsuwe +\*/ + +.text + .align 8 +.globl PR_(imlib_mmx_RotateAA) + .type PT_(imlib_mmx_RotateAA,@function) + + +/*\ Prototype: __imlib_mmx_RotateAA(DATA32 *src, DATA32 *dest, int sow, int sw, +|*| int sh, int dow, int dw, int dh, int x, int y, +|*| int dxh, int dyh, int dxv, int dyv) +\*/ + +#define src 8(%ebp) +#define dest 12(%ebp) +#define sow 16(%ebp) +#define sw 20(%ebp) +#define sh 24(%ebp) +#define dow 28(%ebp) +#define dw 32(%ebp) +#define dh 36(%ebp) +#define x 40(%ebp) +#define y 44(%ebp) +#define dxh 48(%ebp) +#define dyh 52(%ebp) +#define dxv 56(%ebp) +#define dyv 60(%ebp) + +/*\ Local variables \*/ +#define j -4(%ebp) +#define dly -8(%ebp) +#define dlx -12(%ebp) +#define sht -16(%ebp) +#define swt -20(%ebp) +#define m0fffh -24(%ebp) +#define m0fff -28(%ebp) +#define mulsow -32(%ebp) + +PR_(imlib_mmx_RotateAA): + pushl %ebp + movl %esp, %ebp + subl $40, %esp + pushl %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + + /*\ Check (dw > 0) && (dh > 0) \*/ + cmpl $0, dw + jle .rotate_leave + cmpl $0, dh + jle .rotate_leave + + pxor %mm7, %mm7 + movl sow, %eax + sall $16, %eax + orl $1, %eax + movl %eax, mulsow + movl $0x0fff, %eax + movl %eax, m0fff + movl %eax, m0fffh + + /*\ mm6 = x, y \*/ + movq x, %mm6 + + /*\ edi = dest + dw \*/ + movl dest, %edi + movl dw, %eax + leal (%edi, %eax, 4), %edi + + /*\ dlx = dxv - dw * dxh \*/ + movl dw, %eax + imull dxh, %eax + negl %eax + addl dxv, %eax + movl %eax, dlx + + /*\ dly = dyv - dw * dyh \*/ + movl dw, %eax + imull dyh, %eax + negl %eax + addl dyv, %eax + movl %eax, dly + + /*\ j = dh \*/ + movl dh, %eax + movl %eax, j + + /*\ Check if all coordinates will be inside the source \*/ + /*\ x < sw \*/ + movl sw, %edx + movl x, %ecx + cmpl %edx, %ecx + jae .rotate_outside + /*\ x + dxh * dw < sw \*/ + movl dxh, %ebx + imull dw, %ebx + addl %ebx, %ecx + cmpl %edx, %ecx + jae .rotate_outside + /*\ x + dxh * dw + dxv * dh < sw \*/ + movl dxv, %eax + imull dh, %eax + subl %eax, %ecx + cmpl %edx, %ecx + jae .rotate_outside + /*\ x + dxv * dh < sw \*/ + subl %ebx, %ecx + cmpl %edx, %ecx + jae .rotate_outside + + /*\ y < sh \*/ + movl sh, %edx + movl y, %ecx + cmpl %edx, %ecx + jae .rotate_outside + /*\ y + dyh * dw < sh \*/ + movl dyh, %ebx + imull dw, %ebx + addl %ebx, %ecx + cmpl %edx, %ecx + jae .rotate_outside + /*\ y + dyh * dw + dyv * dh < sh \*/ + movl dyv, %eax + imull dh, %eax + addl %eax, %ecx + cmpl %edx, %ecx + jae .rotate_outside + /*\ y + dyv * dh < sh \*/ + subl %ebx, %ecx + cmpl %edx, %ecx + jae .rotate_outside + +.rotate_inside: + movl sow, %ebx + movl src, %edx +.inside_loop_y: + + /*\ i = -dw \*/ + movl dw, %ecx + negl %ecx +.inside_loop_x: + /*\ esi = src + x >> 12 + (y >> 12) * sow \*/ + movq %mm6, %mm0 + psrad $12, %mm0 + packssdw %mm0, %mm0 + pmaddwd mulsow, %mm0 + movd %mm0, %eax + leal (%edx, %eax, 4), %esi + + /*\ x and y \*/ + movq %mm6, %mm0 + pand m0fff, %mm0 + movq %mm0, %mm1 + /*\ mm0 = x & 0xfff \*/ + punpcklwd %mm0, %mm0 + punpckldq %mm0, %mm0 + /*\ mm1 = y & 0xfff \*/ + punpckhwd %mm1, %mm1 + punpckldq %mm1, %mm1 + + /*\ Load and unpack four pixels in parralel + |*| %mm2 = ptr[0], %mm3 = ptr[1] + |*| %mm4 = ptr[sow], %mm5 = ptr[sow + 1] + \*/ + movq (%esi), %mm2 + movq (%esi, %ebx, 4), %mm4 + movq %mm2, %mm3 + movq %mm4, %mm5 + punpcklbw %mm7, %mm2 + punpcklbw %mm7, %mm4 + punpckhbw %mm7, %mm3 + punpckhbw %mm7, %mm5 + + /*\ X interpolation: r = l + (r - l) * xap \*/ + psubw %mm2, %mm3 + psubw %mm4, %mm5 + psllw $4, %mm3 + psllw $4, %mm5 + pmulhw %mm0, %mm3 + pmulhw %mm0, %mm5 + paddw %mm2, %mm3 + paddw %mm4, %mm5 + + /*\ Y interpolation: d = u + (d - u) * yap \*/ + psubw %mm3, %mm5 + psllw $4, %mm5 + pmulhw %mm1, %mm5 + paddw %mm3, %mm5 + packuswb %mm5, %mm5 + movd %mm5, (%edi, %ecx, 4) + + paddd dxh, %mm6 + + incl %ecx + jnz .inside_loop_x + + paddd dlx, %mm6 + movl dow, %ecx + leal (%edi, %ecx, 4), %edi + decl j + jnz .inside_loop_y + + jmp .rotate_leave + +.rotate_outside: + movl sw, %eax + decl %eax + sall $12, %eax + movl %eax, swt + movl sh, %eax + decl %eax + sall $12, %eax + movl %eax, sht + + movl sow, %ebx + movl src, %edx +.outside_loop_y: + + /*\ i = -dw \*/ + movl dw, %ecx + negl %ecx +.outside_loop_x: + /*\ esi = src + x >> 12 + (y >> 12) * sow \*/ + movq %mm6, %mm0 + psrad $12, %mm0 + packssdw %mm0, %mm0 + pmaddwd mulsow, %mm0 + movd %mm0, %eax + leal (%edx, %eax, 4), %esi + + /*\ x & 0xfff and y & 0xfff \*/ + movq %mm6, %mm0 + pand m0fff, %mm0 + movq %mm0, %mm1 + + /*\ x < swt \*/ + movq %mm6, %mm2 + psrlq $32, %mm2 + movd %mm6, %eax + cmpl swt, %eax + jae 2f + + /*\ y < sht \*/ + movd %mm2, %eax + cmpl sht, %eax + jae 1f + /*\ 1234 \*/ +.interp_argb: + /*\ Unpack x and y \*/ + punpcklwd %mm0, %mm0 + punpckldq %mm0, %mm0 + punpckhwd %mm1, %mm1 + punpckldq %mm1, %mm1 + /*\ Load and unpack four pixels in parralel + |*| %mm2 = ptr[0], %mm3 = ptr[1] + |*| %mm4 = ptr[sow], %mm5 = ptr[sow + 1] + \*/ + movq (%esi), %mm2 + movq (%esi, %ebx, 4), %mm4 + movq %mm2, %mm3 + movq %mm4, %mm5 + punpcklbw %mm7, %mm2 + punpcklbw %mm7, %mm4 + punpckhbw %mm7, %mm3 + punpckhbw %mm7, %mm5 + + /*\ X interpolation: r = l + (r - l) * xap \*/ + psubw %mm2, %mm3 + psubw %mm4, %mm5 + psllw $4, %mm3 + psllw $4, %mm5 + pmulhw %mm0, %mm3 + pmulhw %mm0, %mm5 + paddw %mm2, %mm3 + paddw %mm4, %mm5 + + /*\ Y interpolation: d = u + (d - u) * yap \*/ + psubw %mm3, %mm5 + psllw $4, %mm5 + pmulhw %mm1, %mm5 + paddw %mm3, %mm5 + packuswb %mm5, %mm5 + movd %mm5, (%edi, %ecx, 4) + jmp .outside_il_end +1: + /*\ (-y-1) < 4096 \*/ + notl %eax + cmpl $4095, %eax + ja 1f + /*\ ..34 \*/ + pxor m0fff, %mm1 + movd (%esi, %ebx, 4), %mm2 + movd 4(%esi, %ebx, 4), %mm4 + +.interp_rgb_a0: + /*\ Unpack x and y \*/ + punpcklwd %mm0, %mm0 + punpckldq %mm0, %mm0 + punpckhwd %mm1, %mm1 + /*\ Unpack two pixels \*/ + punpcklbw %mm7, %mm2 + punpcklbw %mm7, %mm4 + /*\ Interpolate \*/ + psubw %mm2, %mm4 + psllw $4, %mm4 + pmulhw %mm0, %mm4 + paddw %mm2, %mm4 + /*\ Separate out alpha, multiply with mm1, and subtract \*/ + movq %mm4, %mm2 + psllq $48, %mm1 + psllw $4, %mm4 + pmulhw %mm1, %mm4 + psubw %mm4, %mm2 + packuswb %mm2, %mm2 + movd %mm2, (%edi, %ecx, 4) + jmp .outside_il_end +1: + /*\ (y - sht) < 4096 \*/ + notl %eax + subl sht, %eax + cmpl $4095, %eax + ja .outside_il_0 + /*\ 12.. \*/ + movd (%esi), %mm2 + movd 4(%esi), %mm4 + jmp .interp_rgb_a0 +2: + /*\ Switch x and y \*/ + psrlq $32, %mm0 + psllq $32, %mm1 + /*\ -x-1 < 4096 \*/ + notl %eax + cmpl $4095, %eax + ja 2f + + pxor m0fff, %mm1 + /*\ y < sht \*/ + movd %mm2, %eax + cmpl sht, %eax + jae 1f + /*\ .2.4 \*/ + movd 4(%esi), %mm2 + movd 4(%esi, %ebx, 4), %mm4 + jmp .interp_rgb_a0 +1: + /*\ (-y-1) < 4096 \*/ + notl %eax + cmpl $4095, %eax + ja 1f + /*\ ...4 \*/ + movd 4(%esi, %ebx, 4), %mm2 +.interp_a000: + /*\ Separate out alpha, multiply with mm0 and mm1 \*/ + pxor m0fff, %mm1 + punpcklbw %mm7, %mm2 + movq %mm2, %mm3 + psllq $2, %mm0 + psrlq $30, %mm1 + pmulhw %mm0, %mm1 + pxor m0fff, %mm1 + psllq $48, %mm1 + psllw $4, %mm3 + pmulhw %mm1, %mm3 + psubw %mm3, %mm2 + packuswb %mm2, %mm2 + movd %mm2, (%edi, %ecx, 4) + jmp .outside_il_end +1: + /*\ (y - sht) < 4096 \*/ + notl %eax + subl sht, %eax + cmpl $4095, %eax + ja .outside_il_0 + /*\ .2.. \*/ + pxor m0fff, %mm0 + movd 4(%esi), %mm2 + jmp .interp_a000 +2: + /*\ (x - swt) < 4096 \*/ + notl %eax + subl swt, %eax + cmpl $4095, %eax + ja .outside_il_0 + + /*\ y < sht \*/ + movd %mm2, %eax + cmpl sht, %eax + jae 1f + /*\ 1.3. \*/ + movd (%esi), %mm2 + movd (%esi, %ebx, 4), %mm4 + jmp .interp_rgb_a0 +1: + /*\ (-y-1) < 4096 \*/ + notl %eax + cmpl $4095, %eax + ja 1f + /*\ ..3. \*/ + movd (%esi, %ebx, 4), %mm2 + jmp .interp_a000 +1: + /*\ (y - sht) < 4096 \*/ + notl %eax + subl sht, %eax + cmpl $4095, %eax + ja .outside_il_0 + /*\ 1... \*/ + pxor m0fff, %mm0 + movd (%esi), %mm2 + jmp .interp_a000 + +.outside_il_0: + movl $0, %eax + movl %eax, (%edi, %ecx, 4) + +.outside_il_end: + paddd dxh, %mm6 + + incl %ecx + jnz .outside_loop_x + + paddd dlx, %mm6 + movl dow, %ecx + leal (%edi, %ecx, 4), %edi + decl j + jnz .outside_loop_y + +.rotate_leave: + emms + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + movl %ebp, %esp + popl %ebp + ret + +SIZE(imlib_mmx_RotateAA) + +#endif + diff --git a/src/lib/asm_scale.S b/src/lib/asm_scale.S new file mode 100644 index 0000000..e48c190 --- /dev/null +++ b/src/lib/asm_scale.S @@ -0,0 +1,809 @@ +#include + +#ifdef __EMX__ +/* Due to strange behaviour of as.exe we use this macros */ +/* For all OS/2 coders - please use PGCC to compile this code */ +#define PR_(foo) ___##foo +#define PT_(foo,func) ___##foo,##func +#define SIZE(sym) \ + .___end_##sym:; \ + .size ___##sym,.___end_##sym-___##sym; \ + .align 8; +#else +#define PR_(foo) __##foo +#define PT_(foo,func) __##foo,##func +#define SIZE(sym) \ + .__end_##sym:; \ + .size __##sym,.__end_##sym-__##sym; \ + .align 8; +#endif + +#ifdef DO_MMX_ASM + +/*\ +|*| MMX assembly scaling routine for Imlib2 +|*| Written by Willem Monsuwe +\*/ + +.text + .align 8 +.globl PR_(imlib_Scale_mmx_AARGBA) + .type PT_(imlib_Scale_mmx_AARGBA,@function) + +/*\ Prototype: __imlib_Scale_mmx_AARGBA(ImlibScaleInfo *isi, DATA32 *dest, +|*| int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow) +\*/ + +#define isi 8(%ebp) +#define dest 12(%ebp) +#define dxx 16(%ebp) +#define dyy 20(%ebp) +#define dx 24(%ebp) +#define dy 28(%ebp) +#define dw 32(%ebp) +#define dh 36(%ebp) +#define dow 40(%ebp) +#define sow 44(%ebp) + +/*\ Local variables that didn't fit in registers \*/ +#define y -4(%ebp) +#define yp -8(%ebp) +#define yap -12(%ebp) +#define xp -16(%ebp) +#define xap -20(%ebp) +#define Cx -24(%ebp) +#define Mx -28(%ebp) +#define Cy -32(%ebp) +#define My -36(%ebp) +#define sow_4 -40(%ebp) + +/*\ When %edx points to ImlibScaleInfo, these are the members \*/ +#define xpoints (%edx) +#define ypoints 4(%edx) +#define xapoints 8(%edx) +#define yapoints 12(%edx) +#define xup_yup 16(%edx) + +PR_(imlib_Scale_mmx_AARGBA): + pushl %ebp + movl %esp, %ebp + subl $40, %esp + pushl %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + movl isi, %edx + + /*\ Check (dw > 0) && (dh > 0) \*/ + cmpl $0, dw + jle .scale_leave + cmpl $0, dh + jle .scale_leave + + /*\ X-based array pointers point to the end; we're looping up to 0 \*/ + /*\ %edi = dest + dow * dy + dx + dw \*/ + movl dow, %eax + imull dy, %eax + addl dx, %eax + addl dw, %eax + movl dest, %edi + leal (%edi, %eax, 4), %edi + /*\ xp = xpoints + dxx + dw \*/ + movl dxx, %ebx + addl dw, %ebx + movl xpoints, %eax + leal (%eax, %ebx, 4), %eax + movl %eax, xp + /*\ xap = xapoints + dxx + dw \*/ + movl xapoints, %eax + leal (%eax, %ebx, 4), %eax + movl %eax, xap + /*\ y = dh \*/ + movl dh, %eax + movl %eax, y + /*\ yp = ypoints + dyy \*/ + movl dyy, %ebx + movl ypoints, %eax + leal (%eax, %ebx, 4), %eax + movl %eax, yp + /*\ yap = yapoints + dyy \*/ + movl yapoints, %eax + leal (%eax, %ebx, 4), %eax + movl %eax, yap + + pxor %mm7, %mm7 + + /*\ Test xup bit \*/ + movl xup_yup, %eax + sarl $1, %eax + jnc .scale_x_down + +.scale_x_up: + /*\ Test yup bit \*/ + sarl $1, %eax + jnc .scale_x_up_y_down + + +/*\ Scaling up both ways \*/ + +.scale_x_up_y_up: + movl sow, %ebx + +.up_up_loop_y: + + /*\ x = -dw \*/ + movl dw, %ecx + negl %ecx + + /*\ %eax = *yap << 4 \*/ + movl yap, %eax + movl (%eax), %eax + sall $4, %eax + jz .up_up_yap_0 + movd %eax, %mm1 + punpcklwd %mm1, %mm1 + punpckldq %mm1, %mm1 + +.up_up_loop1_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + /*\ %eax = xap[x] << 4 \*/ + movl xap, %eax + movl (%eax, %ecx, 4), %eax + sall $4, %eax + jz .up_up_xap_0 + + /*\ %mm0 = xap[x] << 4 \*/ + movd %eax, %mm0 + punpcklwd %mm0, %mm0 + punpckldq %mm0, %mm0 + + /*\ Load and unpack four pixels in parralel + |*| %mm2 = ptr[0], %mm3 = ptr[1] + |*| %mm4 = ptr[sow], %mm5 = ptr[sow + 1] + \*/ + movq (%esi), %mm2 + movq (%esi, %ebx, 4), %mm4 + movq %mm2, %mm3 + movq %mm4, %mm5 + punpcklbw %mm7, %mm2 + punpcklbw %mm7, %mm4 + punpckhbw %mm7, %mm3 + punpckhbw %mm7, %mm5 + + /*\ X interpolation: r = l + (r - l) * xap \*/ + psubw %mm2, %mm3 + psubw %mm4, %mm5 + psllw $4, %mm3 + psllw $4, %mm5 + pmulhw %mm0, %mm3 + pmulhw %mm0, %mm5 + paddw %mm2, %mm3 + paddw %mm4, %mm5 + /*\ Now %mm3 = I(ptr[0], ptr[1]), %mm5 = I(ptr[sow], ptr[sow + 1]) \*/ + jmp .up_up_common +.up_up_xap_0: + /*\ Load and unpack two pixels + |*| %mm3 = ptr[0], %mm5 = ptr[sow] + \*/ + movd (%esi), %mm3 + movd (%esi, %ebx, 4), %mm5 + punpcklbw %mm7, %mm3 + punpcklbw %mm7, %mm5 +.up_up_common: + /*\ Y interpolation: d = u + (d - u) * yap \*/ + psubw %mm3, %mm5 + psllw $4, %mm5 + pmulhw %mm1, %mm5 + paddw %mm3, %mm5 + packuswb %mm5, %mm5 + movd %mm5, (%edi, %ecx, 4) + + /*\ while (++x) \*/ + incl %ecx + jnz .up_up_loop1_x + jmp .up_up_yap_end +.up_up_yap_0: + +.up_up_loop2_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + /*\ %eax = xap[x] << 4 \*/ + movl xap, %eax + movl (%eax, %ecx, 4), %eax + sall $4, %eax + jz .up_up_0 + + /*\ %mm0 = xap[x] << 4 \*/ + movd %eax, %mm0 + punpcklwd %mm0, %mm0 + punpckldq %mm0, %mm0 + + /*\ Load and unpack two pixels in parralel + |*| %mm2 = ptr[0], %mm3 = ptr[1] + \*/ + movq (%esi), %mm2 + movq %mm2, %mm3 + punpcklbw %mm7, %mm2 + punpckhbw %mm7, %mm3 + + /*\ X interpolation: r = l + (r - l) * xap \*/ + psubw %mm2, %mm3 + psllw $4, %mm3 + pmulhw %mm0, %mm3 + paddw %mm2, %mm3 + packuswb %mm3, %mm3 + movd %mm3, (%edi, %ecx, 4) + jmp .up_up_1 +.up_up_0: + /*\ dptr[x] = *sptr \*/ + movl (%esi), %eax + movl %eax, (%edi, %ecx, 4) +.up_up_1: + incl %ecx + jnz .up_up_loop2_x + +.up_up_yap_end: + /*\ dptr += dow \*/ + movl dow, %eax + leal (%edi, %eax, 4), %edi + /*\ yap++; yp++ \*/ + addl $4, yap + addl $4, yp + /*\ while (y--) \*/ + decl y + jnz .up_up_loop_y + + jmp .scale_leave + + +/*\ Scaling down vertically \*/ + +.scale_x_up_y_down: + /*\ sow_4 = sow * 4 \*/ + movl sow, %eax + sall $2, %eax + movl %eax, sow_4 + +.up_down_loop_y: + + /*\ Setup My and Cy \*/ + movl yap, %eax + movzwl (%eax), %ebx + movl %ebx, My + movzwl 2(%eax), %eax + movl %eax, Cy + + /*\ mm4 = Cy \*/ + movd %eax, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + /*\ mm5 = My \*/ + movd %ebx, %mm5 + punpcklwd %mm5, %mm5 + punpckldq %mm5, %mm5 + + /*\ x = -dw \*/ + movl dw, %ecx + negl %ecx +.up_down_loop_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + movl %esi, %eax + /*\ v = (*p * My) >> 10 \*/ + movd (%eax), %mm0 + punpcklbw %mm7, %mm0 + psllw $6, %mm0 + pmulhw %mm5, %mm0 + + /*\ i = 0x4000 - My \*/ + movl $0x4000, %ebx + subl My, %ebx + jbe 5f + jmp 2f +1: + /*\ p += sow; v += (*p * Cy) >> 10 \*/ + addl sow_4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm0 + + /*\ i -= Cy; while (i > Cy) \*/ + subl Cy, %ebx +2: + cmpl Cy, %ebx + jg 1b + + /*\ mm6 = i \*/ + movd %ebx, %mm6 + punpcklwd %mm6, %mm6 + punpckldq %mm6, %mm6 + + /*\ p += sow; v += (*p * i) >> 10 \*/ + addl sow_4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm0 +5: + /*\ %eax = xap[x] << 5 \*/ + movl xap, %eax + movl (%eax, %ecx, 4), %eax + sall $5, %eax + jz 6f + /*\ mm3 = xap[x] << 5 \*/ + movd %eax, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + + /*\ p + 1 \*/ + movl %esi, %eax + addl $4, %eax + /*\ vv = (*p * My) >> 10 \*/ + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $6, %mm2 + pmulhw %mm5, %mm2 + + /*\ i = 0x4000 - My \*/ + movl $0x4000, %ebx + subl My, %ebx + jbe 5f + jmp 2f +1: + /*\ p += sow; vv += (*p * Cy) >> 10 \*/ + addl sow_4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm2 + + /*\ i -= Cy; while (i > Cy) \*/ + subl Cy, %ebx +2: + cmpl Cy, %ebx + jg 1b + + /*\ p += sow; v += (*p * i) >> 10 \*/ + addl sow_4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm2 +5: + /*\ v = v + (vv - v) * xap \*/ + psubw %mm0, %mm2 + psllw $3, %mm2 + pmulhw %mm3, %mm2 + paddw %mm2, %mm0 +6: + /*\ dest[x] = v >> 4 \*/ + psrlw $4, %mm0 + packuswb %mm0, %mm0 + movd %mm0, (%edi, %ecx, 4) + + /*\ while (++x) \*/ + incl %ecx + jnz .up_down_loop_x + + /*\ dptr += dow \*/ + movl dow, %eax + leal (%edi, %eax, 4), %edi + /*\ yap++; yp++ \*/ + addl $4, yap + addl $4, yp + /*\ while (y--) \*/ + decl y + jnz .up_down_loop_y + + jmp .scale_leave + +.scale_x_down: + /*\ Test yup bit \*/ + sarl $1, %eax + jnc .scale_x_down_y_down + + +/*\ Scaling down horizontally \*/ + +.scale_x_down_y_up: + /*\ sow_4 = sow * 4 \*/ + movl sow, %eax + sall $2, %eax + movl %eax, sow_4 + +.down_up_loop_y: + + /*\ %eax = *yap << 5 \*/ + movl yap, %eax + movl (%eax), %eax + sall $5, %eax + /*\ mm3 = *yap << 5 \*/ + movd %eax, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + + /*\ x = -dw \*/ + movl dw, %ecx + negl %ecx +.down_up_loop_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + /*\ Setup Mx and Cx \*/ + movl xap, %eax + movzwl (%eax, %ecx, 4), %ebx + movl %ebx, Mx + movzwl 2(%eax, %ecx, 4), %eax + movl %eax, Cx + + /*\ mm4 = Cx \*/ + movd %eax, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + /*\ mm5 = Mx \*/ + movd %ebx, %mm5 + punpcklwd %mm5, %mm5 + punpckldq %mm5, %mm5 + + movl %esi, %eax + /*\ v = (*p * Mx) >> 10 \*/ + movd (%eax), %mm0 + punpcklbw %mm7, %mm0 + psllw $6, %mm0 + pmulhw %mm5, %mm0 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ p += sow; v += (*p * Cx) >> 10 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm0 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ mm6 = i \*/ + movd %ebx, %mm6 + punpcklwd %mm6, %mm6 + punpckldq %mm6, %mm6 + + /*\ p += sow; v += (*p * i) >> 10 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm0 +5: + movd %mm3, %eax + testl %eax, %eax + jz 6f + /*\ p + sow \*/ + movl %esi, %eax + addl sow_4, %eax + /*\ vv = (*p * Mx) >> 10 \*/ + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $6, %mm2 + pmulhw %mm5, %mm2 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ p += sow; vv += (*p * Cx) >> 10 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm2 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ p += sow; v += (*p * i) >> 10 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm2 +5: + /*\ v = v + (vv - v) * yap \*/ + psubw %mm0, %mm2 + psllw $3, %mm2 + pmulhw %mm3, %mm2 + paddw %mm2, %mm0 +6: + /*\ dest[x] = v >> 4 \*/ + psrlw $4, %mm0 + packuswb %mm0, %mm0 + movd %mm0, (%edi, %ecx, 4) + + /*\ while (++x) \*/ + incl %ecx + jnz .down_up_loop_x + + /*\ dptr += dow \*/ + movl dow, %eax + leal (%edi, %eax, 4), %edi + /*\ yap++; yp++ \*/ + addl $4, yap + addl $4, yp + /*\ while (y--) \*/ + decl y + jnz .down_up_loop_y + + jmp .scale_leave + + +/*\ Scaling down both ways \*/ + +.scale_x_down_y_down: + /*\ sow_4 = sow * 4 \*/ + movl sow, %eax + sall $2, %eax + movl %eax, sow_4 + +.down_down_loop_y: + + /*\ Setup My and Cy \*/ + movl yap, %eax + movzwl (%eax), %ebx + movl %ebx, My + movzwl 2(%eax), %eax + movl %eax, Cy + + /*\ x = -dw \*/ + movl dw, %ecx + negl %ecx +.down_down_loop_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + /*\ Setup Mx and Cx \*/ + movl xap, %eax + movzwl (%eax, %ecx, 4), %ebx + movl %ebx, Mx + movzwl 2(%eax, %ecx, 4), %eax + movl %eax, Cx + + /*\ mm3 = Cx \*/ + movd %eax, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + /*\ mm5 = Mx \*/ + movd %ebx, %mm5 + punpcklwd %mm5, %mm5 + punpckldq %mm5, %mm5 + + /*\ p = sptr; v = (*p * Mx) >> 9 \*/ + movl %esi, %eax + movd (%eax), %mm0 + punpcklbw %mm7, %mm0 + psllw $7, %mm0 + pmulhw %mm5, %mm0 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ v += (*++p * Cx) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $7, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm0 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ mm6 = i \*/ + movd %ebx, %mm6 + punpcklwd %mm6, %mm6 + punpckldq %mm6, %mm6 + + /*\ v += (*++p * i) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $7, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm0 +5: + /*\ v *= My \*/ + movd My, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + psllw $2, %mm0 + pmulhw %mm4, %mm0 + + /*\ j = 0x4000 - My \*/ + movl $0x4000, %edx + subl My, %edx + jbe 6f + jmp 4f +3: + /*\ sptr += sow; p = sptr \*/ + addl sow_4, %esi + movl %esi, %eax + /*\ vx = (*p * Mx) >> 9 \*/ + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $7, %mm1 + pmulhw %mm5, %mm1 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ vx += (*++p * Cx) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $7, %mm2 + pmulhw %mm3, %mm2 + paddw %mm2, %mm1 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ vx += (*++p * i) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $7, %mm2 + pmulhw %mm6, %mm2 + paddw %mm2, %mm1 +5: + /*\ v += (vx * Cy) >> 14 \*/ + movd Cy, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + psllw $2, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm0 + + /*\ j -= Cy; while (j > Cy) \*/ + subl Cy, %edx +4: + cmpl Cy, %edx + jg 3b + + /*\ sptr += sow; p = sptr \*/ + addl sow_4, %esi + movl %esi, %eax + /*\ vx = (*p * Mx) >> 9 \*/ + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $7, %mm1 + pmulhw %mm5, %mm1 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ vx += (*++p * Cx) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $7, %mm2 + pmulhw %mm3, %mm2 + paddw %mm2, %mm1 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ vx += (*++p * i) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $7, %mm2 + pmulhw %mm6, %mm2 + paddw %mm2, %mm1 +5: + /*\ v += (vx * j) >> 14 \*/ + movd %edx, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + psllw $2, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm0 +6: + /*\ dptr[x] = mm0 >> 5 \*/ + psrlw $5, %mm0 + packuswb %mm0, %mm0 + movd %mm0, (%edi, %ecx, 4) + + /*\ while (++x) \*/ + incl %ecx + jnz .down_down_loop_x + + /*\ dptr += dow \*/ + movl dow, %eax + leal (%edi, %eax, 4), %edi + /*\ yap++; yp++ \*/ + addl $4, yap + addl $4, yp + /*\ while (y--) \*/ + decl y + jnz .down_down_loop_y + + jmp .scale_leave + +.scale_leave: + emms + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + movl %ebp, %esp + popl %ebp + ret + +SIZE(imlib_Scale_mmx_AARGBA) + +#endif diff --git a/src/lib/blend.c b/src/lib/blend.c new file mode 100644 index 0000000..9966f9c --- /dev/null +++ b/src/lib/blend.c @@ -0,0 +1,1820 @@ +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include "scale.h" + + +#define ADD_COPY(r, g, b, dest) \ + ADD_COLOR(R_VAL(dest), r, R_VAL(dest)); \ + ADD_COLOR(G_VAL(dest), g, G_VAL(dest)); \ + ADD_COLOR(B_VAL(dest), b, B_VAL(dest)); + +#define SUB_COPY(r, g, b, dest) \ + SUB_COLOR(R_VAL(dest), r, R_VAL(dest)); \ + SUB_COLOR(G_VAL(dest), g, G_VAL(dest)); \ + SUB_COLOR(B_VAL(dest), b, B_VAL(dest)); + +#define RE_COPY(r, g, b, dest) \ + RESHADE_COLOR(R_VAL(dest), r, R_VAL(dest)); \ + RESHADE_COLOR(G_VAL(dest), g, G_VAL(dest)); \ + RESHADE_COLOR(B_VAL(dest), b, B_VAL(dest)); + + + +int pow_lut_initialized = 0; +DATA8 pow_lut[256][256]; + +void +__imlib_build_pow_lut(void) +{ + int i, j; + + if (pow_lut_initialized) + return; + pow_lut_initialized = 1; + for (i = 0; i < 256; i++) + { + for (j = 0; j < 256; j++) +/* pow_lut[i][j] = 255 * pow((double)i / 255, (double)j / 255); */ + { + int divisor; + + divisor = (i + (j * (255 - i)) / 255); + if (divisor > 0) + pow_lut[i][j] = (i * 255) / divisor; + else + pow_lut[i][j] = 0; + } + } +} + + +/* COPY OPS */ + +static void +__imlib_BlendRGBAToRGB(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a; + + a = A_VAL(src); + switch (a) + { + case 0: + break; + case 255: + *dst = (*dst & 0xff000000) | (*src & 0x00ffffff); + break; + default: + BLEND(R_VAL(src), G_VAL(src), B_VAL(src), a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_BlendRGBAToRGBA(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a, aa; + + aa = A_VAL(src); + switch (aa) + { + case 0: + break; + case 255: + *dst = *src; + break; + default: + a = pow_lut[aa][A_VAL(dst)]; + BLEND_COLOR(aa, A_VAL(dst), 255, A_VAL(dst)); + BLEND(R_VAL(src), G_VAL(src), B_VAL(src), a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_CopyRGBAToRGB(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + *dst = (*dst & 0xff000000) | (*src & 0x00ffffff); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_CopyRGBToRGBA(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + *dst = 0xff000000 | (*src & 0x00ffffff); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_CopyRGBAToRGBA(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + *dst = *src; + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + + +/* ADD OPS */ + +static void +__imlib_AddBlendRGBAToRGB(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a; + + a = A_VAL(src); + switch (a) + { + case 0: + break; + case 255: + ADD_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + break; + default: + BLEND_ADD(R_VAL(src), G_VAL(src), B_VAL(src), a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_AddBlendRGBAToRGBA(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a, aa; + + aa = A_VAL(src); + switch (aa) + { + case 0: + break; + case 255: + A_VAL(dst) = 0xff; + ADD_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + break; + default: + a = pow_lut[aa][A_VAL(dst)]; + BLEND_COLOR(aa, A_VAL(dst), 255, A_VAL(dst)); + BLEND_ADD(R_VAL(src), G_VAL(src), B_VAL(src), a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_AddCopyRGBAToRGB(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + ADD_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_AddCopyRGBAToRGBA(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + A_VAL(dst) = A_VAL(src); + ADD_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_AddCopyRGBToRGBA(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + A_VAL(dst) = 0xff; + ADD_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + + +/* SUBTRACT OPS */ + +static void +__imlib_SubBlendRGBAToRGB(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a; + + a = A_VAL(src); + switch (a) + { + case 0: + break; + case 255: + SUB_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + break; + default: + BLEND_SUB(R_VAL(src), G_VAL(src), B_VAL(src), a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_SubBlendRGBAToRGBA(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a, aa; + + aa = A_VAL(src); + switch (aa) + { + case 0: + break; + case 255: + A_VAL(dst) = 0xff; + SUB_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + break; + default: + a = pow_lut[aa][A_VAL(dst)]; + BLEND_COLOR(aa, A_VAL(dst), 255, A_VAL(dst)); + BLEND_SUB(R_VAL(src), G_VAL(src), B_VAL(src), a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_SubCopyRGBAToRGB(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + SUB_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_SubCopyRGBAToRGBA(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + A_VAL(dst) = A_VAL(src); + SUB_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_SubCopyRGBToRGBA(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + A_VAL(dst) = 0xff; + SUB_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +/* RESHADE OPS */ + +static void +__imlib_ReBlendRGBAToRGB(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a; + + a = A_VAL(src); + switch (a) + { + case 0: + break; + case 255: + RE_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + break; + default: + BLEND_RE(R_VAL(src), G_VAL(src), B_VAL(src), a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_ReBlendRGBAToRGBA(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a, aa; + + aa = A_VAL(src); + switch (aa) + { + case 0: + break; + case 255: + A_VAL(dst) = 0xff; + RE_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + break; + default: + a = pow_lut[aa][A_VAL(dst)]; + BLEND_COLOR(aa, A_VAL(dst), 255, A_VAL(dst)); + BLEND_RE(R_VAL(src), G_VAL(src), B_VAL(src), a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_ReCopyRGBAToRGB(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + RE_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + + +static void +__imlib_ReCopyRGBAToRGBA(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + A_VAL(dst) = A_VAL(src); + RE_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_ReCopyRGBToRGBA(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + A_VAL(dst) = 0xff; + RE_COPY(R_VAL(src), G_VAL(src), B_VAL(src), dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + + +/* WITH COLOMOD */ +/* COPY OPS */ + +static void +__imlib_BlendRGBAToRGBCmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a; + + a = amod[A_VAL(src)]; + switch (a) + { + case 0: + break; + case 255: + R_VAL(dst) = rmod[R_VAL(src)]; + G_VAL(dst) = gmod[G_VAL(src)]; + B_VAL(dst) = bmod[B_VAL(src)]; + break; + default: + BLEND(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_BlendRGBAToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a, aa; + + aa = amod[A_VAL(src)]; + switch (aa) + { + case 0: + break; + case 255: + A_VAL(dst) = 0xff; + R_VAL(dst) = rmod[R_VAL(src)]; + G_VAL(dst) = gmod[G_VAL(src)]; + B_VAL(dst) = bmod[B_VAL(src)]; + break; + default: + a = pow_lut[aa][A_VAL(dst)]; + BLEND_COLOR(aa, A_VAL(dst), 255, A_VAL(dst)); + BLEND(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_BlendRGBToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + DATA8 am = amod[255]; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a; + + a = pow_lut[am][A_VAL(dst)]; + BLEND_COLOR(am, A_VAL(dst), 255, A_VAL(dst)) + BLEND(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], a, dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_BlendRGBToRGBCmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + DATA8 am = amod[255]; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + BLEND(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], am, dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_CopyRGBAToRGBCmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + R_VAL(dst) = rmod[R_VAL(src)]; + G_VAL(dst) = gmod[G_VAL(src)]; + B_VAL(dst) = bmod[B_VAL(src)]; + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_CopyRGBToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + DATA8 am = amod[255]; + + while (h--) + { + while (w--) + { + A_VAL(dst) = am; + R_VAL(dst) = rmod[R_VAL(src)]; + G_VAL(dst) = gmod[G_VAL(src)]; + B_VAL(dst) = bmod[B_VAL(src)]; + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_CopyRGBAToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + A_VAL(dst) = amod[A_VAL(src)]; + R_VAL(dst) = rmod[R_VAL(src)]; + G_VAL(dst) = gmod[G_VAL(src)]; + B_VAL(dst) = bmod[B_VAL(src)]; + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + + +/* ADD OPS */ + +static void +__imlib_AddBlendRGBAToRGBCmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a; + + a = amod[A_VAL(src)]; + switch (a) + { + case 0: + break; + case 255: + ADD_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + break; + default: + BLEND_ADD(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_AddBlendRGBAToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a, aa; + + aa = amod[A_VAL(src)]; + switch (aa) + { + case 0: + break; + case 255: + A_VAL(dst) = 0xff; + ADD_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + break; + default: + a = pow_lut[aa][A_VAL(dst)]; + BLEND_COLOR(aa, A_VAL(dst), 255, A_VAL(dst)); + BLEND_ADD(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_AddBlendRGBToRGBCmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + DATA8 am = amod[255]; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + BLEND_ADD(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], am, dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_AddBlendRGBToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + DATA8 am = amod[255]; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a; + + a = pow_lut[am][A_VAL(dst)]; + BLEND_COLOR(am, A_VAL(dst), 255, A_VAL(dst)); + BLEND_ADD(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], a, dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_AddCopyRGBAToRGBCmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + ADD_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_AddCopyRGBAToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + A_VAL(dst) = amod[A_VAL(src)]; + ADD_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_AddCopyRGBToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + DATA8 am = amod[255]; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + A_VAL(dst) = am; + ADD_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + + +/* SUBTRACT OPS */ + +static void +__imlib_SubBlendRGBAToRGBCmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a; + + a = amod[A_VAL(src)]; + switch (a) + { + case 0: + break; + case 255: + SUB_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + break; + default: + BLEND_SUB(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_SubBlendRGBAToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a, aa; + + aa = amod[A_VAL(src)]; + switch (aa) + { + case 0: + break; + case 255: + A_VAL(dst) = 0xff; + SUB_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + break; + default: + a = pow_lut[aa][A_VAL(dst)]; + BLEND_COLOR(aa, A_VAL(dst), 255, A_VAL(dst)); + BLEND_SUB(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_SubBlendRGBToRGBCmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + DATA8 am = amod[255]; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + BLEND_SUB(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], am, dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_SubBlendRGBToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + DATA8 am = amod[255]; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a; + + a = pow_lut[am][A_VAL(dst)]; + BLEND_COLOR(am, A_VAL(dst), 255, A_VAL(dst)); + BLEND_SUB(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], a, dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_SubCopyRGBAToRGBCmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + SUB_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_SubCopyRGBAToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + A_VAL(dst) = amod[A_VAL(src)]; + SUB_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_SubCopyRGBToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + DATA8 am = amod[255]; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + A_VAL(dst) = am; + SUB_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + + +/* RESHADE OPS */ + +static void +__imlib_ReBlendRGBAToRGBCmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a; + + a = amod[A_VAL(src)]; + switch (a) + { + case 0: + break; + case 255: + RE_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + break; + default: + BLEND_RE(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], a, dst); + break; + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_ReBlendRGBAToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a, aa; + + aa = amod[A_VAL(src)]; + switch (aa) + { + case 0: + break; + case 255: + A_VAL(dst) = 0xff; + RE_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + break; + default: + a = pow_lut[aa][A_VAL(dst)]; + BLEND_COLOR(aa, A_VAL(dst), 255, A_VAL(dst)); + BLEND_RE(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], a, dst); + } + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_ReBlendRGBToRGBCmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + DATA8 am = amod[255]; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + BLEND_RE(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], am, dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_ReBlendRGBToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + DATA8 am = amod[255]; + + while (h--) + { + while (w--) + { + DATA32 tmp; + DATA8 a; + + a = pow_lut[am][A_VAL(dst)]; + BLEND_COLOR(am, A_VAL(dst), 255, A_VAL(dst)); + BLEND_RE(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], a, dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_ReCopyRGBAToRGBCmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + RE_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_ReCopyRGBAToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + A_VAL(dst) = amod[A_VAL(src)]; + RE_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + +static void +__imlib_ReCopyRGBToRGBACmod(DATA32 * src, int srcw, DATA32 * dst, int dstw, + int w, int h, ImlibColorModifier * cm) +{ + int src_step = (srcw - w), dst_step = (dstw - w), ww = w; + DATA8 *amod = cm->alpha_mapping, *rmod = cm->red_mapping, + *gmod = cm->green_mapping, *bmod = cm->blue_mapping; + DATA8 am = amod[255]; + + while (h--) + { + while (w--) + { + DATA32 tmp; + + A_VAL(dst) = am; + RE_COPY(rmod[R_VAL(src)], gmod[G_VAL(src)], bmod[B_VAL(src)], dst); + src++; dst++; + } + src += src_step; + dst += dst_step; + w = ww; + } +} + + +/*\ Equivalent functions \*/ + +#define __imlib_CopyRGBToRGB __imlib_CopyRGBToRGBA +#define __imlib_BlendRGBToRGB __imlib_CopyRGBToRGB +#define __imlib_BlendRGBToRGBA __imlib_CopyRGBToRGBA +#define __imlib_mmx_copy_rgb_to_rgb __imlib_mmx_copy_rgb_to_rgba +#define __imlib_mmx_blend_rgb_to_rgb __imlib_mmx_copy_rgb_to_rgb +#define __imlib_mmx_blend_rgb_to_rgba __imlib_mmx_copy_rgb_to_rgba +#define __imlib_CopyRGBToRGBCmod __imlib_CopyRGBAToRGBCmod +#define __imlib_mmx_copy_rgb_to_rgb_cmod __imlib_mmx_copy_rgba_to_rgb_cmod + +#define __imlib_AddCopyRGBToRGB __imlib_AddCopyRGBAToRGB +#define __imlib_AddBlendRGBToRGB __imlib_AddCopyRGBToRGB +#define __imlib_AddBlendRGBToRGBA __imlib_AddCopyRGBToRGBA +#define __imlib_mmx_add_copy_rgb_to_rgb __imlib_mmx_add_copy_rgba_to_rgb +#define __imlib_mmx_add_blend_rgb_to_rgb __imlib_mmx_add_copy_rgb_to_rgb +#define __imlib_mmx_add_blend_rgb_to_rgba __imlib_mmx_add_copy_rgb_to_rgba +#define __imlib_AddCopyRGBToRGBCmod __imlib_AddCopyRGBAToRGBCmod +#define __imlib_mmx_add_copy_rgb_to_rgb_cmod __imlib_mmx_add_copy_rgb_to_rgba_cmod + +#define __imlib_SubCopyRGBToRGB __imlib_SubCopyRGBAToRGB +#define __imlib_SubBlendRGBToRGB __imlib_SubCopyRGBToRGB +#define __imlib_SubBlendRGBToRGBA __imlib_SubCopyRGBToRGBA +#define __imlib_mmx_subtract_copy_rgb_to_rgba __imlib_mmx_subtract_copy_rgba_to_rgba +#define __imlib_mmx_subtract_copy_rgb_to_rgb __imlib_mmx_subtract_copy_rgba_to_rgb +#define __imlib_mmx_subtract_blend_rgb_to_rgb __imlib_mmx_subtract_copy_rgb_to_rgb +#define __imlib_mmx_subtract_blend_rgb_to_rgba __imlib_mmx_subtract_copy_rgb_to_rgba +#define __imlib_SubCopyRGBToRGBCmod __imlib_SubCopyRGBAToRGBCmod +#define __imlib_mmx_subtract_copy_rgb_to_rgb_cmod __imlib_mmx_subtract_copy_rgb_to_rgba_cmod + +#define __imlib_ReCopyRGBToRGB __imlib_ReCopyRGBAToRGB +#define __imlib_ReBlendRGBToRGB __imlib_ReCopyRGBToRGB +#define __imlib_ReBlendRGBToRGBA __imlib_ReCopyRGBToRGBA +#define __imlib_mmx_reshade_copy_rgb_to_rgba __imlib_mmx_reshade_copy_rgba_to_rgba +#define __imlib_mmx_reshade_copy_rgb_to_rgb __imlib_mmx_reshade_copy_rgba_to_rgb +#define __imlib_mmx_reshade_blend_rgb_to_rgb __imlib_mmx_reshade_copy_rgb_to_rgb +#define __imlib_mmx_reshade_blend_rgb_to_rgba __imlib_mmx_reshade_copy_rgb_to_rgba +#define __imlib_ReCopyRGBToRGBCmod __imlib_ReCopyRGBAToRGBCmod +#define __imlib_mmx_reshade_copy_rgb_to_rgb_cmod __imlib_mmx_reshade_copy_rgb_to_rgba_cmod + + +ImlibBlendFunction +__imlib_GetBlendFunction(ImlibOp op, char blend, char merge_alpha, char rgb_src, + ImlibColorModifier * cm) +{ + /*\ [ mmx ][ operation ][ cmod ][ merge_alpha ][ rgb_src ][ blend ] \ */ + static ImlibBlendFunction ibfuncs[][4][2][2][2][2] = { + /*\ OP_COPY \ */ + {{{{{__imlib_CopyRGBAToRGB, __imlib_BlendRGBAToRGB}, + {__imlib_CopyRGBToRGB, __imlib_BlendRGBToRGB}}, + {{__imlib_CopyRGBAToRGBA, __imlib_BlendRGBAToRGBA}, + {__imlib_CopyRGBToRGBA, __imlib_BlendRGBToRGBA}}}, + + {{{__imlib_CopyRGBAToRGBCmod, __imlib_BlendRGBAToRGBCmod}, + {__imlib_CopyRGBToRGBCmod, __imlib_BlendRGBToRGBCmod}}, + {{__imlib_CopyRGBAToRGBACmod, __imlib_BlendRGBAToRGBACmod}, + {__imlib_CopyRGBToRGBACmod, __imlib_BlendRGBToRGBACmod}}}}, + /*\ OP_ADD \ */ + {{{{__imlib_AddCopyRGBAToRGB, __imlib_AddBlendRGBAToRGB}, + {__imlib_AddCopyRGBToRGB, __imlib_AddBlendRGBToRGB}}, + {{__imlib_AddCopyRGBAToRGBA, __imlib_AddBlendRGBAToRGBA}, + {__imlib_AddCopyRGBToRGBA, __imlib_AddBlendRGBToRGBA}}}, + + {{{__imlib_AddCopyRGBAToRGBCmod, __imlib_AddBlendRGBAToRGBCmod}, + {__imlib_AddCopyRGBToRGBCmod, __imlib_AddBlendRGBToRGBCmod}}, + {{__imlib_AddCopyRGBAToRGBACmod, __imlib_AddBlendRGBAToRGBACmod}, + {__imlib_AddCopyRGBToRGBACmod, __imlib_AddBlendRGBToRGBACmod}}}}, + /*\ OP_SUBTRACT \ */ + {{{{__imlib_SubCopyRGBAToRGB, __imlib_SubBlendRGBAToRGB}, + {__imlib_SubCopyRGBToRGB, __imlib_SubBlendRGBToRGB}}, + {{__imlib_SubCopyRGBAToRGBA, __imlib_SubBlendRGBAToRGBA}, + {__imlib_SubCopyRGBToRGBA, __imlib_SubBlendRGBToRGBA}}}, + + {{{__imlib_SubCopyRGBAToRGBCmod, __imlib_SubBlendRGBAToRGBCmod}, + {__imlib_SubCopyRGBToRGBCmod, __imlib_SubBlendRGBToRGBCmod}}, + {{__imlib_SubCopyRGBAToRGBACmod, __imlib_SubBlendRGBAToRGBACmod}, + {__imlib_SubCopyRGBToRGBACmod, __imlib_SubBlendRGBToRGBACmod}}}}, + /*\ OP_RESHADE \ */ + {{{{__imlib_ReCopyRGBAToRGB, __imlib_ReBlendRGBAToRGB}, + {__imlib_ReCopyRGBToRGB, __imlib_ReBlendRGBToRGB}}, + {{__imlib_ReCopyRGBAToRGBA, __imlib_ReBlendRGBAToRGBA}, + {__imlib_ReCopyRGBToRGBA, __imlib_ReBlendRGBToRGBA}}}, + + {{{__imlib_ReCopyRGBAToRGBCmod, __imlib_ReBlendRGBAToRGBCmod}, + {__imlib_ReCopyRGBToRGBCmod, __imlib_ReBlendRGBToRGBCmod}}, + {{__imlib_ReCopyRGBAToRGBACmod, __imlib_ReBlendRGBAToRGBACmod}, + {__imlib_ReCopyRGBToRGBACmod, __imlib_ReBlendRGBToRGBACmod}}}}}, + +#ifdef DO_MMX_ASM + /*\ OP_COPY \ */ + {{{{{__imlib_mmx_copy_rgba_to_rgb, __imlib_mmx_blend_rgba_to_rgb}, + {__imlib_mmx_copy_rgb_to_rgb, __imlib_mmx_blend_rgb_to_rgb}}, + {{__imlib_mmx_copy_rgba_to_rgba, + __imlib_BlendRGBAToRGBA /*__imlib_mmx_blend_rgba_to_rgba*/ }, + {__imlib_mmx_copy_rgb_to_rgba, __imlib_mmx_blend_rgb_to_rgba}}}, + + {{{__imlib_mmx_copy_rgba_to_rgb_cmod, + __imlib_mmx_blend_rgba_to_rgb_cmod}, + {__imlib_mmx_copy_rgb_to_rgb_cmod, + __imlib_mmx_blend_rgb_to_rgb_cmod}}, + {{__imlib_mmx_copy_rgba_to_rgba_cmod, + __imlib_BlendRGBAToRGBACmod /*__imlib_mmx_blend_rgba_to_rgba_cmod*/ + }, + {__imlib_mmx_copy_rgb_to_rgba_cmod, + __imlib_BlendRGBToRGBACmod /*__imlib_mmx_blend_rgb_to_rgba_cmod*/}}}}, + /*\ OP_ADD \ */ + {{{{__imlib_mmx_add_copy_rgba_to_rgb, __imlib_mmx_add_blend_rgba_to_rgb}, + {__imlib_mmx_add_copy_rgb_to_rgb, __imlib_mmx_add_blend_rgb_to_rgb}}, + {{__imlib_AddCopyRGBAToRGBA /*__imlib_mmx_add_copy_rgba_to_rgba*/, + __imlib_AddBlendRGBAToRGBA /*__imlib_mmx_add_blend_rgba_to_rgba*/ }, + {__imlib_mmx_add_copy_rgb_to_rgba, + __imlib_mmx_add_blend_rgb_to_rgba}}}, + + {{{__imlib_mmx_add_copy_rgba_to_rgb_cmod, + __imlib_mmx_add_blend_rgba_to_rgb_cmod}, + {__imlib_mmx_add_copy_rgb_to_rgb_cmod, + __imlib_mmx_add_blend_rgb_to_rgb_cmod}}, + {{__imlib_AddCopyRGBAToRGBACmod /*__imlib_mmx_add_copy_rgba_to_rgba_cmod*/, + __imlib_AddBlendRGBAToRGBACmod + /*__imlib_mmx_add_blend_rgba_to_rgba_cmod*/ }, + {__imlib_AddCopyRGBToRGBACmod /*__imlib_mmx_add_copy_rgb_to_rgba_cmod*/, + __imlib_AddBlendRGBToRGBACmod /*__imlib_mmx_add_blend_rgb_to_rgba_cmod*/}}}}, + /*\ OP_SUBTRACT \ */ + {{{{__imlib_mmx_subtract_copy_rgba_to_rgb, + __imlib_mmx_subtract_blend_rgba_to_rgb}, + {__imlib_mmx_subtract_copy_rgb_to_rgb, + __imlib_mmx_subtract_blend_rgb_to_rgb}}, + {{__imlib_SubCopyRGBAToRGBA /*__imlib_mmx_subtract_copy_rgba_to_rgba*/, + __imlib_SubBlendRGBAToRGBA + /*__imlib_mmx_subtract_blend_rgba_to_rgba*/ }, + {__imlib_mmx_subtract_copy_rgb_to_rgba, + __imlib_mmx_subtract_blend_rgb_to_rgba}}}, + + {{{__imlib_mmx_subtract_copy_rgba_to_rgb_cmod, + __imlib_mmx_subtract_blend_rgba_to_rgb_cmod}, + {__imlib_mmx_subtract_copy_rgb_to_rgb_cmod, + __imlib_mmx_subtract_blend_rgb_to_rgb_cmod}}, + {{__imlib_SubCopyRGBAToRGBACmod /*__imlib_mmx_subtract_copy_rgba_to_rgba_cmod*/, + __imlib_SubBlendRGBAToRGBACmod + /*__imlib_mmx_subtract_blend_rgba_to_rgba_cmod*/ }, + {__imlib_SubCopyRGBToRGBACmod /*__imlib_mmx_subtract_copy_rgb_to_rgba_cmod*/, + __imlib_SubBlendRGBToRGBACmod /*__imlib_mmx_subtract_blend_rgb_to_rgba_cmod*/}}}}, + /*\ OP_RESHADE \ */ + {{{{__imlib_mmx_reshade_copy_rgba_to_rgb, + __imlib_mmx_reshade_blend_rgba_to_rgb}, + {__imlib_mmx_reshade_copy_rgb_to_rgb, + __imlib_mmx_reshade_blend_rgb_to_rgb}}, + {{__imlib_ReCopyRGBAToRGBA /*__imlib_mmx_reshade_copy_rgba_to_rgba*/, + __imlib_ReBlendRGBAToRGBA /*__imlib_mmx_reshade_blend_rgba_to_rgba*/ + }, + {__imlib_mmx_reshade_copy_rgb_to_rgba, + __imlib_mmx_reshade_blend_rgb_to_rgba}}}, + + {{{__imlib_mmx_reshade_copy_rgba_to_rgb_cmod, + __imlib_mmx_reshade_blend_rgba_to_rgb_cmod}, + {__imlib_mmx_reshade_copy_rgb_to_rgb_cmod, + __imlib_mmx_reshade_blend_rgb_to_rgb_cmod}}, + {{__imlib_ReCopyRGBAToRGBACmod /*__imlib_mmx_reshade_copy_rgba_to_rgba_cmod*/, + __imlib_ReBlendRGBAToRGBACmod + /*__imlib_mmx_reshade_blend_rgba_to_rgba_cmod*/ }, + {__imlib_ReCopyRGBToRGBACmod /*__imlib_mmx_reshade_copy_rgb_to_rgba_cmod*/, + __imlib_ReBlendRGBToRGBACmod /*__imlib_mmx_reshade_blend_rgb_to_rgba_cmod*/}}}}}, +#endif + }; + + int opi = (op == OP_COPY) ? 0 + : (op == OP_ADD) ? 1 + : (op == OP_SUBTRACT) ? 2 : (op == OP_RESHADE) ? 3 : -1; + int do_mmx = 0; + + if (opi == -1) + return NULL; + +#ifdef DO_MMX_ASM + do_mmx = !!(__imlib_get_cpuid() & CPUID_MMX); +#endif + if (cm && rgb_src && (A_CMOD(cm, 0xff) == 0xff)) + blend = 0; + if (blend && cm && rgb_src && (A_CMOD(cm, 0xff) == 0)) + return NULL; + return ibfuncs[!!do_mmx][opi][!!cm][!!merge_alpha][!!rgb_src][!!blend]; +} + +void +__imlib_BlendRGBAToData(DATA32 * src, int src_w, int src_h, DATA32 * dst, + int dst_w, int dst_h, int sx, int sy, int dx, int dy, + int w, int h, char blend, char merge_alpha, + ImlibColorModifier * cm, ImlibOp op, char rgb_src) +{ + ImlibBlendFunction blender; + + if (sx < 0) + { + w += sx; + dx -= sx; + sx = 0; + } + if (sy < 0) + { + h += sy; + dy -= sy; + sy = 0; + } + if (dx < 0) + { + w += dx; + sx -= dx; + dx = 0; + } + if (dy < 0) + { + h += dy; + sy -= dy; + dy = 0; + } + if ((w <= 0) || (h <= 0)) + return; + if ((sx + w) > src_w) + w = src_w - sx; + if ((sy + h) > src_h) + h = src_h - sy; + if ((dx + w) > dst_w) + w = dst_w - dx; + if ((dy + h) > dst_h) + h = dst_h - dy; + if ((w <= 0) || (h <= 0)) + return; + + __imlib_build_pow_lut(); + blender = __imlib_GetBlendFunction(op, blend, merge_alpha, rgb_src, cm); + if (blender) + blender(src + (sy * src_w) + sx, src_w, + dst + (dy * dst_w) + dx, dst_w, w, h, cm); +} + +#define LINESIZE 16 + +void +__imlib_BlendImageToImage(ImlibImage * im_src, ImlibImage * im_dst, + char aa, char blend, char merge_alpha, + int ssx, int ssy, int ssw, int ssh, + int ddx, int ddy, int ddw, int ddh, + ImlibColorModifier * cm, ImlibOp op, + int clx, int cly, int clw, int clh) +{ + char rgb_src = 0; + + if ((!(im_src->data)) && (im_src->loader) && (im_src->loader->load)) + im_src->loader->load(im_src, NULL, 0, 1); + if ((!(im_dst->data)) && (im_dst->loader) && (im_src->loader->load)) + im_dst->loader->load(im_dst, NULL, 0, 1); + if (!im_src->data) + return; + if (!im_dst->data) + return; + + if ((ssw == ddw) && (ssh == ddh)) + { + if (!IMAGE_HAS_ALPHA(im_dst)) + merge_alpha = 0; + if (!IMAGE_HAS_ALPHA(im_src)) + { + rgb_src = 1; + if (merge_alpha) + blend = 1; + } + if (clw) + { + int px, py; + + px = ddx; + py = ddy; + CLIP_TO(ddx, ddy, ddw, ddh, clx, cly, clw, clh); + px = ddx - px; + py = ddy - py; + ssx += px; + ssy += py; + if ((ssw < 1) || (ssh < 1)) + return; + if ((ddw < 1) || (ddh < 1)) + return; + } + + __imlib_BlendRGBAToData(im_src->data, im_src->w, im_src->h, + im_dst->data, im_dst->w, im_dst->h, + ssx, ssy, + ddx, ddy, + ddw, ddh, blend, merge_alpha, cm, op, rgb_src); + } + else + { + ImlibScaleInfo *scaleinfo = NULL; + DATA32 *buf = NULL; + int sx, sy, sw, sh, dx, dy, dw, dh, dxx, dyy, y2, x2; + int psx, psy, psw, psh; + int y, h, hh; + int do_mmx; + + sx = ssx; + sy = ssy; + sw = ssw; + sh = ssh; + dx = ddx; + dy = ddy; + dw = abs(ddw); + dh = abs(ddh); + /* don't do anything if we have a 0 width or height image to render */ + /* if the input rect size < 0 don't render either */ + if ((dw <= 0) || (dh <= 0) || (sw <= 0) || (sh <= 0)) + return; + /* clip the source rect to be within the actual image */ + psx = sx; + psy = sy; + psw = sw; + psh = sh; + CLIP(sx, sy, sw, sh, 0, 0, im_src->w, im_src->h); + if (psx != sx) + dx += ((sx - psx) * abs(ddw)) / ssw; + if (psy != sy) + dy += ((sy - psy) * abs(ddh)) / ssh; + if (psw != sw) + dw = (dw * sw) / psw; + if (psh != sh) + dh = (dh * sh) / psh; + if ((dw <= 0) || (dh <= 0) || (sw <= 0) || (sh <= 0)) + { + return; + } + /* clip output coords to clipped input coords */ + psx = dx; + psy = dy; + psw = dw; + psh = dh; + x2 = sx; + y2 = sy; + CLIP(dx, dy, dw, dh, 0, 0, im_dst->w, im_dst->h); + if ((dw <= 0) || (dh <= 0) || (sw <= 0) || (sh <= 0)) + return; + if (clw) + { + CLIP_TO(dx, dy, dw, dh, clx, cly, clw, clh); + if ((dw < 1) || (dh < 1)) + return; + } + if (psx != dx) + sx += ((dx - psx) * ssw) / abs(ddw); + if (psy != dy) + sy += ((dy - psy) * ssh) / abs(ddh); + if (psw != dw) + sw = (sw * dw) / psw; + if (psh != dh) + sh = (sh * dh) / psh; + dxx = dx - psx; + dyy = dy - psy; + dxx += (x2 * abs(ddw)) / ssw; + dyy += (y2 * abs(ddh)) / ssh; + + if ((dw > 0) && (sw == 0)) + sw = 1; + if ((dh > 0) && (sh == 0)) + sh = 1; + /* do a second check to see if we now have invalid coords */ + /* don't do anything if we have a 0 width or height image to render */ + /* if the input rect size < 0 don't render either */ + if ((dw <= 0) || (dh <= 0) || (sw <= 0) || (sh <= 0)) + { + return; + } + scaleinfo = __imlib_CalcScaleInfo(im_src, ssw, ssh, ddw, ddh, aa); + if (!scaleinfo) + return; + /* if we are scaling the image at all make a scaling buffer */ + /* allocate a buffer to render scaled RGBA data into */ + buf = malloc(dw * LINESIZE * sizeof(DATA32)); + if (!buf) + { + __imlib_FreeScaleInfo(scaleinfo); + return; + } + /* setup h */ + h = dh; + if (!IMAGE_HAS_ALPHA(im_dst)) + merge_alpha = 0; + if (!IMAGE_HAS_ALPHA(im_src)) + { + rgb_src = 1; + if (merge_alpha) + blend = 1; + } + /* scale in LINESIZE Y chunks and convert to depth */ +#ifdef DO_MMX_ASM + do_mmx = __imlib_get_cpuid() & CPUID_MMX; +#endif + for (y = 0; y < dh; y += LINESIZE) + { + hh = LINESIZE; + if (h < LINESIZE) + hh = h; + /* scale the imagedata for this LINESIZE lines chunk of image */ + if (aa) + { +#ifdef DO_MMX_ASM + if (do_mmx) + __imlib_Scale_mmx_AARGBA(scaleinfo, buf, dxx, dyy + y, + 0, 0, dw, hh, dw, im_src->w); + else +#endif + if (IMAGE_HAS_ALPHA(im_src)) + __imlib_ScaleAARGBA(scaleinfo, buf, dxx, dyy + y, + 0, 0, dw, hh, dw, im_src->w); + else + __imlib_ScaleAARGB(scaleinfo, buf, dxx, dyy + y, + 0, 0, dw, hh, dw, im_src->w); + } + else + __imlib_ScaleSampleRGBA(scaleinfo, buf, dxx, dyy + y, + 0, 0, dw, hh, dw); + __imlib_BlendRGBAToData(buf, dw, hh, + im_dst->data, im_dst->w, + im_dst->h, + 0, 0, dx, dy + y, dw, dh, + blend, merge_alpha, cm, op, rgb_src); + h -= LINESIZE; + } + /* free up our buffers and point tables */ + free(buf); + __imlib_FreeScaleInfo(scaleinfo); + } +} diff --git a/src/lib/blend.h b/src/lib/blend.h new file mode 100644 index 0000000..77f4696 --- /dev/null +++ b/src/lib/blend.h @@ -0,0 +1,556 @@ +#ifndef __BLEND +#define __BLEND 1 + +#ifndef WORDS_BIGENDIAN + +#define A_VAL(p) ((DATA8 *)(p))[3] +#define R_VAL(p) ((DATA8 *)(p))[2] +#define G_VAL(p) ((DATA8 *)(p))[1] +#define B_VAL(p) ((DATA8 *)(p))[0] + +#else + +#define A_VAL(p) ((DATA8 *)(p))[0] +#define R_VAL(p) ((DATA8 *)(p))[1] +#define G_VAL(p) ((DATA8 *)(p))[2] +#define B_VAL(p) ((DATA8 *)(p))[3] + +#endif + +/* FIXME: endian dependant */ +#define READ_RGB(p, r, g, b) \ + (r) = R_VAL(p); \ + (g) = G_VAL(p); \ + (b) = B_VAL(p); + +#define READ_ALPHA(p, a) \ + (a) = A_VAL(p); + +#define READ_RGBA(p, r, g, b, a) \ + (r) = R_VAL(p); \ + (g) = G_VAL(p); \ + (b) = B_VAL(p); \ + (a) = A_VAL(p); + +#define WRITE_RGB(p, r, g, b) \ + R_VAL(p) = (r); \ + G_VAL(p) = (g); \ + B_VAL(p) = (b); + +#define WRITE_RGB_PRESERVE_ALPHA(p, r, g, b) \ + WRITE_RGB(p, r, g, b) + +#define WRITE_RGBA(p, r, g, b, a) \ + R_VAL(p) = (r); \ + G_VAL(p) = (g); \ + B_VAL(p) = (b); \ + A_VAL(p) = (a); + +#define INTERSECTS(x, y, w, h, xx, yy, ww, hh) \ + ((x < (xx + ww)) && \ + (y < (yy + hh)) && \ + ((x + w) > xx) && \ + ((y + h) > yy)) + +#define CLIP_TO(_x, _y, _w, _h, _cx, _cy, _cw, _ch) \ +{ \ +if (INTERSECTS(_x, _y, _w, _h, _cx, _cy, _cw, _ch)) \ + { \ + if (_x < _cx) \ + { \ + _w += _x - _cx; \ + _x = _cx; \ + if (_w < 0) _w = 0; \ + } \ + if ((_x + _w) > (_cx + _cw)) \ + _w = _cx + _cw - _x; \ + if (_y < _cy) \ + { \ + _h += _y - _cy; \ + _y = _cy; \ + if (_h < 0) _h = 0; \ + } \ + if ((_y + _h) > (_cy + _ch)) \ + _h = _cy + _ch - _y; \ + } \ +else \ + { \ + _w = 0; _h = 0; \ + } \ +} + +/* + * 1) Basic Saturation - 8 bit unsigned + * + * The add, subtract, and reshade operations generate new color values that may + * be out of range for an unsigned 8 bit quantity. Therefore, we will want to + * saturate the values into the range [0, 255]. Any value < 0 will become 0, + * and any value > 255 will become 255. Or simply: + * + * saturated = (value < 0) ? 0 : ((value > 255) ? 255 : value) + * + * Of course the above isn't the most efficient means of saturating. Sometimes + * due to the nature of a calculation, we know we only need to saturate from + * above (> 255) or just from below (< 0). Or simply: + * + * saturated = (value < 0) ? 0 : value + * saturated = (value > 255) ? 255 : value + * + * 2) Alternate Forms of Saturation + * + * The methods of saturation described above use testing/branching operations, + * which are not necessarily efficient on all platforms. There are other means + * of performing saturation using just simple arithmetic operations + * (+, -, >>, <<, ~). A discussion of these saturation techniques follows. + * + * A) Saturation in the range [0, 512), or "from above". + * + * Assuming we have an integral value in the range [0, 512), the following + * formula evaluates to either 0, or 255: + * + * (value & 255) - ((value & 256) >> 8) + * + * This is easy to show. Notice that if the value is in the range [0, 256) + * the 9th bit is 0, and we get (0 - 0), which is 0. And if the value is in + * the range [256, 512) the 9th bit is 1, and we get (256 - 1), which is 255. + * + * Now, using the above information and the fact that assigning an integer to + * an 8 bit unsigned value will truncate to the lower 8 bits of the integer, + * the following properly saturates: + * + * 8bit_value = value | (value & 256) - ((value & 256) >> 8) + * + * To prove this to yourself, just think about what the lower 8 bits look like + * in the ranges [0, 256) and [256, 512). In particular, notice that the value + * in the range [0, 256) are unchanged, and values in the range [256, 512) + * always give you 255. Just what we want! + * + * B) Saturation in the range (-256, 256), or "from below". + * + * Assuming we have an integral value in the range (-256, 256), the following + * formula evaluates to either 0, or -1: + * + * ~(value >> 8) + * + * Here's why. If the value is in the range [0, 256), then shifting right by + * 8 bits gives us all 0 bits, or 0. And thus inverting the bits gives all + * 1 bits, which is -1. If the value is in the range (-256, 0), then the 9th + * bit and higher bits are all 1. So, when we shift right by 8 bits (with + * signed extension), we get a value with all 1 bits. Which when inverted is + * all 0 bits, or 0. + * + * Now, using the above information the following properly saturates: + * + * 8bit_value = value & (~(value >> 8)) + * + * To prove this to yourself, noticed that values in the range (-256, 0) will + * always be AND'd with 0, and thus map to 0. Further, values in the range + * [0, 256) will always be AND'd with a value that is all 1 bits, and thus + * be unchanged. Just what we want! + * + * C) Saturation in the range (-256, 512), or "from above and below". + * + * The short of it is the following works: + * + * 8bit_value = (tmp | ((tmp & 256) - ((tmp & 256) >> 8))) & (~(tmp >> 9)) + * + * We leave it to the reader to prove. Looks very similar to the techniques + * used above, eh? :) + */ + +/* Saturate values in the range [0, 512) */ +#define SATURATE_UPPER(nc, v) \ + tmp = (v); \ + nc = (tmp | (-(tmp >> 8))); + +/* Saturate values in the range (-256, 256) */ +#define SATURATE_LOWER(nc, v) \ + tmp = (v); \ + nc = tmp & (~(tmp >> 8)); + +/* Saturate values in the range (-256, 512) */ +#define SATURATE_BOTH(nc, v) \ + tmp = (v); \ + nc = (tmp | (-(tmp >> 8))) & (~(tmp >> 9)); + +/* + * 1) Operations + * + * There are 4 operations supported: + * + * Copy, Add, Subtract, and Reshade + * + * For each operation there are 3 different variations that can be made: + * + * a) Use "blend" or "copy" in the calculations? A "blend" uses the alpha + * value of the source pixel to lighten the source pixel values. Where + * as "copy" ignores the alpha value and uses the raw source pixel values. + * b) Include source alpha in the calculation for new destination alpha? + * If source alpha is not used, then destination alpha is preserved. + * If source alpha is used, a "copy" sets the new alpha to the source + * alpha, and a "blend" increases it by a factor given by the product + * of the source alpha with one minus the destination alpha. + * c) Should the source pixels be passed through a color modifier before the + * calculations are performed? + * + * All together we have 4*2*2*2 = 32 combinations. + * + * 2) Copy operation + * + * The "copy" version of this operation copies the source image onto the + * destination image. + * + * The "blend" version of this operation blends the source image color 'c' with + * the destination image color 'cc' using 'a' (in the range [0, 1]) according + * to the following formula. Also notice that saturation is not needed for + * this calculation, the output is in the range [0, 255]: + * + * nc = c * alpha + (1 - alpha) * cc + * = c * alpha - cc * alpha + cc + * = (c - cc) * alpha + cc; + * + * A discussion of how we're calculating this value follows: + * + * We're using 'a', an integer, in the range [0, 255] for alpha (and for 'c' + * and 'cc', BTW). Therefore, we need to slightly modify the equation to take + * that into account. To get into the range [0, 255] we need to divide 'a' + * by 255: + * + * nc = ((c - cc) * a) / 255 + cc + * + * Notice that it is faster to divide by 256 (bit shifting), however without a + * fudge factor 'x' to balance things this isn't horribly accurate. So, let's + * solve for 'x'. The equality is: + * + * ((c - cc) * a) / 256 + cc + x = ((c - cc) * a) / 255 + cc + * + * The 'cc' terms cancel, and multiply both sides by 255*256 to remove the + * fractions: + * + * ((c - cc) * a) * 255 + 255 * 256 * x = ((c - cc) * a) * 256 + * + * Get the 'x' term alone: + * + * 255 * 256 * x = ((c - cc) * a) + * + * Divide both sides by 255 * 256 to solve for 'x': + * + * x = ((c - cc) * a) / (255 * 256) + * + * And putting 'x' back into the equation we get: + * + * nc = ((c - cc) * a) / 256 + cc + ((c - cc) * a) / (255 * 256) + * + * And if we let 'tmp' represent the value '(c - cc) * a', and do a little + * regrouping we get: + * + * nc = tmp / 256 + tmp / (255 * 256) + cc + * = (tmp + tmp / 255) / 256 + cc + * + * We'll be using integer arithmetic, and over the range of values tmp takes + * (in [-255*255, 255*255]) the term tmp/(255*256) is pretty much the same as + * tmp/(256*256). So we get: + * + * nc = (tmp + tmp / 256) / 256 + cc + * + * And because the division of the sum uses integer arithmetic, it always + * rounds up/down even if that isn't the "best" choice. If we add .5 to the + * sum, we can get standard rounding: Like so: + * + * nc = (tmp + tmp / 256 + 128) / 256 + cc + * + * 3) Add operation + * + * The "copy" version of this operation sums the source image pixel values + * with the destination image pixel values, saturating at 255 (from above). + * + * The "blend" version of this operation sums the source image pixel values, + * after taking into account alpha transparency (e.g. a percentage), with the + * destination image pixel values, saturating at 255 (from above). + * + * 4) Subtract operation + * + * This operation is the same as the Add operation, except the source values + * are subtracted from the destination values (instead of added). Further, + * the result must be saturated at 0 (from below). + * + * 5) Reshade operation + * + * This operation uses the source image color values to lighten/darken color + * values in the destination image using the following formula: + * + * nc = cc + ((c - middle_value) * 2 * alpha) + * + * Recall our pixel color and alpha values are in the range [0, 255]. So, the + * "blend" version of this operation can be calculated as: + * + * nc = cc + ((c - 127) * 2 * (a / 255)) + * + * And in an integer arithmetic friendly form is: + * + * nc = cc + (((c - 127) * a) >> 7) + * + * The "copy" version of this operation treats alpha as 1.0 (or a/255), and in + * integer arithmetic friendly form is: + * + * nc = cc + ((c - 127) << 1) + * + * Notice the color values created by this operation are in the range + * (-256, 512), and thus must be saturated at 0 and 255 (from above and below). + * + * For all the operations, when the "blend" version involves computing new + * destination alpha values via the use of some source alpha, we have that: + * + * nalpha = alpha + ((255 - alpha) * (a / 255)) + * + * We can use the previous argument for approximating division by 255, and + * calculate this by: + * + * tmp = (255 - alpha) * a; + * nalpha = alpha + ((tmp + (tmp >> 8) + 0x80) >> 8); + * + * This is again in the range [0, 255], so no saturation is needed. + */ + +#define BLEND_COLOR(a, nc, c, cc) \ +tmp = ((c) - (cc)) * (a); \ +nc = (cc) + ((tmp + (tmp >> 8) + 0x80) >> 8); + +#define ADD_COLOR_WITH_ALPHA(a, nc, c, cc) \ +tmp = (c) * (a); \ +tmp = (cc) + ((tmp + (tmp >> 8) + 0x80) >> 8); \ +nc = (tmp | (-(tmp >> 8))); + +#define ADD_COLOR(nc, c, cc) \ +tmp = (cc) + (c); \ +nc = (tmp | (-(tmp >> 8))); + +#define SUB_COLOR_WITH_ALPHA(a, nc, c, cc) \ +tmp = (c) * (a); \ +tmp = (cc) - ((tmp + (tmp >> 8) + 0x80) >> 8); \ +nc = (tmp & (~(tmp >> 8))); + +#define SUB_COLOR(nc, c, cc) \ +tmp = (cc) - (c); \ +nc = (tmp & (~(tmp >> 8))); + +#define RESHADE_COLOR_WITH_ALPHA(a, nc, c, cc) \ +tmp = (cc) + ((((c) - 127) * (a)) >> 7); \ +nc = (tmp | (-(tmp >> 8))) & (~(tmp >> 9)); + +#define RESHADE_COLOR(nc, c, cc) \ +tmp = (cc) + (((c) - 127) << 1); \ +nc = (tmp | (-(tmp >> 8))) & (~(tmp >> 9)); + +extern int pow_lut_initialized; +extern DATA8 pow_lut[256][256]; + +#define BLEND_DST_ALPHA(r1, g1, b1, a1, dest) \ +{ DATA8 _aa; \ +_aa = pow_lut[a1][A_VAL(dest)]; \ +BLEND_COLOR(a1, A_VAL(dest), 255, A_VAL(dest)); \ +BLEND_COLOR(_aa, R_VAL(dest), r1, R_VAL(dest)); \ +BLEND_COLOR(_aa, G_VAL(dest), g1, G_VAL(dest)); \ +BLEND_COLOR(_aa, B_VAL(dest), b1, B_VAL(dest)); \ +} + +#define BLEND(r1, g1, b1, a1, dest) \ +BLEND_COLOR(a1, R_VAL(dest), r1, R_VAL(dest)); \ +BLEND_COLOR(a1, G_VAL(dest), g1, G_VAL(dest)); \ +BLEND_COLOR(a1, B_VAL(dest), b1, B_VAL(dest)); + +#define BLEND_ADD(r1, g1, b1, a1, dest) \ +ADD_COLOR_WITH_ALPHA(a1, R_VAL(dest), r1, R_VAL(dest)); \ +ADD_COLOR_WITH_ALPHA(a1, G_VAL(dest), g1, G_VAL(dest)); \ +ADD_COLOR_WITH_ALPHA(a1, B_VAL(dest), b1, B_VAL(dest)); + +#define BLEND_SUB(r1, g1, b1, a1, dest) \ +SUB_COLOR_WITH_ALPHA(a1, R_VAL(dest), r1, R_VAL(dest)); \ +SUB_COLOR_WITH_ALPHA(a1, G_VAL(dest), g1, G_VAL(dest)); \ +SUB_COLOR_WITH_ALPHA(a1, B_VAL(dest), b1, B_VAL(dest)); + +#define BLEND_RE(r1, g1, b1, a1, dest) \ +RESHADE_COLOR_WITH_ALPHA(a1, R_VAL(dest), r1, R_VAL(dest)); \ +RESHADE_COLOR_WITH_ALPHA(a1, G_VAL(dest), g1, G_VAL(dest)); \ +RESHADE_COLOR_WITH_ALPHA(a1, B_VAL(dest), b1, B_VAL(dest)); + +enum _imlibop +{ + OP_COPY, + OP_ADD, + OP_SUBTRACT, + OP_RESHADE +}; + +typedef enum _imlibop ImlibOp; + +typedef void (*ImlibBlendFunction)(DATA32*, int, DATA32*, int, int, int, + ImlibColorModifier *); + +ImlibBlendFunction +__imlib_GetBlendFunction(ImlibOp op, char merge_alpha, char blend, char rgb_src, + ImlibColorModifier * cm); +void +__imlib_BlendImageToImage(ImlibImage *im_src, ImlibImage *im_dst, + char aa, char blend, char merge_alpha, + int ssx, int ssy, int ssw, int ssh, + int ddx, int ddy, int ddw, int ddh, + ImlibColorModifier *cm, ImlibOp op, + int clx, int cly, int clw, int clh); +void +__imlib_BlendRGBAToData(DATA32 *src, int src_w, int src_h, DATA32 *dst, + int dst_w, int dst_h, int sx, int sy, int dx, int dy, + int w, int h, char blend, char merge_alpha, + ImlibColorModifier *cm, ImlibOp op, char rgb_src); +void +__imlib_build_pow_lut(void); + +#ifdef DO_MMX_ASM +void +__imlib_mmx_blend_rgba_to_rgb(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_blend_rgba_to_rgba(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_copy_rgba_to_rgb(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_copy_rgba_to_rgba(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_copy_rgb_to_rgba(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_add_blend_rgba_to_rgb(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_add_blend_rgba_to_rgba(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_add_copy_rgba_to_rgb(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_add_copy_rgba_to_rgba(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_add_copy_rgb_to_rgba(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_subtract_blend_rgba_to_rgb(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_subtract_blend_rgba_to_rgba(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_subtract_copy_rgba_to_rgb(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_subtract_copy_rgba_to_rgba(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_subtract_copy_rgb_to_rgba(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_reshade_blend_rgba_to_rgb(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_reshade_blend_rgba_to_rgba(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_reshade_copy_rgba_to_rgb(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_reshade_copy_rgba_to_rgba(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_reshade_copy_rgb_to_rgba(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); + +void +__imlib_mmx_blend_rgba_to_rgb_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_blend_rgba_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_blend_rgb_to_rgb_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_blend_rgb_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_copy_rgba_to_rgb_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_copy_rgba_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_copy_rgb_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_add_blend_rgba_to_rgb_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_add_blend_rgba_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_add_blend_rgb_to_rgb_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_add_blend_rgb_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_add_copy_rgba_to_rgb_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_add_copy_rgba_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_add_copy_rgb_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_subtract_blend_rgba_to_rgb_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_subtract_blend_rgba_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_subtract_blend_rgb_to_rgb_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_subtract_blend_rgb_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_subtract_copy_rgba_to_rgb_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_subtract_copy_rgba_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_subtract_copy_rgb_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_reshade_blend_rgba_to_rgb_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_reshade_blend_rgba_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_reshade_blend_rgb_to_rgb_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_reshade_blend_rgb_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_reshade_copy_rgba_to_rgb_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_reshade_copy_rgba_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); +void +__imlib_mmx_reshade_copy_rgb_to_rgba_cmod(DATA32 *src, int sw, DATA32 *dst, + int dw, int w, int h, ImlibColorModifier *cm); + +#endif +#endif diff --git a/src/lib/color.c b/src/lib/color.c new file mode 100644 index 0000000..0b49d2d --- /dev/null +++ b/src/lib/color.c @@ -0,0 +1,573 @@ +#include "common.h" +#ifdef BUILD_X11 +#include +#include +#include "color.h" +#endif + +#ifdef BUILD_X11 + +DATA8 _pal_type = 0; +DATA16 _max_colors = 256; + +int +__imlib_XActualDepth(Display * d, Visual * v) +{ + XVisualInfo xvi, *xvir; + int depth = 0, num; + + xvi.visual = v; + xvi.visualid = XVisualIDFromVisual(v); + xvir = XGetVisualInfo(d, VisualIDMask, &xvi, &num); + if (xvir) + { + depth = xvir[0].depth; + if ((depth == 16) && + ((xvir->red_mask | xvir->green_mask | xvir->blue_mask) == 0x7fff)) + depth = 15; + XFree(xvir); + } + return depth; +} + +Visual * +__imlib_BestVisual(Display * d, int screen, int *depth_return) +{ + XVisualInfo xvi, *xvir; + int j, i, num, maxd = 0; + Visual *v = NULL; + const int visprefs[] = + { PseudoColor, TrueColor, DirectColor, StaticColor, GrayScale, +StaticGray }; + + xvi.screen = screen; + maxd = 0; + for (j = 0; j < 6; j++) + { + xvi.class = visprefs[j]; + xvir = XGetVisualInfo(d, VisualScreenMask | VisualClassMask, + &xvi, &num); + if (xvir) + { + for (i = 0; i < num; i++) + { + if ((xvir[i].depth > 1) && + (xvir[i].depth >= maxd) && (xvi.class == PseudoColor)) + { + maxd = xvir[i].depth; + v = xvir[i].visual; + } + else if ((xvir[i].depth > maxd) && (xvir[i].depth <= 24)) + { + maxd = xvir[i].depth; + v = xvir[i].visual; + } + } + XFree(xvir); + } + } + if (depth_return) + *depth_return = maxd; + return v; +} + +DATA8 * +__imlib_AllocColorTable(Display * d, Colormap cmap, DATA8 * type_return, + Visual * v) +{ + DATA8 *color_lut = NULL; + + if (v->bits_per_rgb > 1) + { + if ((_max_colors >= 256) + && (color_lut = __imlib_AllocColors332(d, cmap, v))) + { + *type_return = _pal_type; + return color_lut; + } + if ((_max_colors >= 216) + && (color_lut = __imlib_AllocColors666(d, cmap, v))) + { + *type_return = _pal_type; + return color_lut; + } + if ((_max_colors >= 128) + && (color_lut = __imlib_AllocColors232(d, cmap, v))) + { + *type_return = _pal_type; + return color_lut; + } + if ((_max_colors >= 64) + && (color_lut = __imlib_AllocColors222(d, cmap, v))) + { + *type_return = _pal_type; + return color_lut; + } + if ((_max_colors >= 32) + && (color_lut = __imlib_AllocColors221(d, cmap, v))) + { + *type_return = _pal_type; + return color_lut; + } + if ((_max_colors >= 16) + && (color_lut = __imlib_AllocColors121(d, cmap, v))) + { + *type_return = _pal_type; + return color_lut; + } + } + if ((_max_colors >= 8) && (color_lut = __imlib_AllocColors111(d, cmap, v))) + { + *type_return = _pal_type; + return color_lut; + } + color_lut = __imlib_AllocColors1(d, cmap, v); + *type_return = _pal_type; + return color_lut; +} + +DATA8 * +__imlib_AllocColors332(Display * d, Colormap cmap, Visual * v) +{ + int r, g, b, i; + DATA8 *color_lut; + int sig_mask = 0; + + for (i = 0; i < v->bits_per_rgb; i++) + sig_mask |= (0x1 << i); + sig_mask <<= (16 - v->bits_per_rgb); + i = 0; + color_lut = malloc(256 * sizeof(DATA8)); + for (r = 0; r < 8; r++) + { + for (g = 0; g < 8; g++) + { + for (b = 0; b < 4; b++) + { + XColor xcl; + XColor xcl_in; + int val; + Status ret; + + val = (r << 6) | (r << 3) | (r); + xcl.red = (unsigned short)((val << 7) | (val >> 2)); + val = (g << 6) | (g << 3) | (g); + xcl.green = (unsigned short)((val << 7) | (val >> 2)); + val = (b << 6) | (b << 4) | (b << 2) | (b); + xcl.blue = (unsigned short)((val << 8) | (val)); + xcl_in = xcl; + ret = XAllocColor(d, cmap, &xcl); + if ((ret == Success) || + ((xcl_in.red & sig_mask) != (xcl.red & sig_mask)) || + ((xcl_in.green & sig_mask) != (xcl.green & sig_mask)) || + ((xcl_in.blue & sig_mask) != (xcl.blue & sig_mask))) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for (j = 0; j < i; j++) + pixels[j] = (unsigned long)color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + free(color_lut); + return NULL; + } + color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 0; + return color_lut; +} + +DATA8 * +__imlib_AllocColors666(Display * d, Colormap cmap, Visual * v) +{ + int r, g, b, i; + DATA8 *color_lut; + int sig_mask = 0; + + for (i = 0; i < v->bits_per_rgb; i++) + sig_mask |= (0x1 << i); + sig_mask <<= (16 - v->bits_per_rgb); + i = 0; + color_lut = malloc(256 * sizeof(DATA8)); + for (r = 0; r < 6; r++) + { + for (g = 0; g < 6; g++) + { + for (b = 0; b < 6; b++) + { + XColor xcl; + XColor xcl_in; + int val; + Status ret; + + val = (int)((((double)r) / 5.0) * 65535); + xcl.red = (unsigned short)(val); + val = (int)((((double)g) / 5.0) * 65535); + xcl.green = (unsigned short)(val); + val = (int)((((double)b) / 5.0) * 65535); + xcl.blue = (unsigned short)(val); + xcl_in = xcl; + ret = XAllocColor(d, cmap, &xcl); + if ((ret == Success) || + ((xcl_in.red & sig_mask) != (xcl.red & sig_mask)) || + ((xcl_in.green & sig_mask) != (xcl.green & sig_mask)) || + ((xcl_in.blue & sig_mask) != (xcl.blue & sig_mask))) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for (j = 0; j < i; j++) + pixels[j] = (unsigned long)color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + free(color_lut); + return NULL; + } + color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 7; + return color_lut; +} + +DATA8 * +__imlib_AllocColors232(Display * d, Colormap cmap, Visual * v) +{ + int r, g, b, i; + DATA8 *color_lut; + int sig_mask = 0; + + for (i = 0; i < v->bits_per_rgb; i++) + sig_mask |= (0x1 << i); + sig_mask <<= (16 - v->bits_per_rgb); + i = 0; + color_lut = malloc(128 * sizeof(DATA8)); + for (r = 0; r < 4; r++) + { + for (g = 0; g < 8; g++) + { + for (b = 0; b < 4; b++) + { + XColor xcl; + XColor xcl_in; + int val; + Status ret; + + val = (r << 6) | (r << 4) | (r << 2) | (r); + xcl.red = (unsigned short)((val << 8) | (val)); + val = (g << 6) | (g << 3) | (g); + xcl.green = (unsigned short)((val << 7) | (val >> 2)); + val = (b << 6) | (b << 4) | (b << 2) | (b); + xcl.blue = (unsigned short)((val << 8) | (val)); + xcl_in = xcl; + ret = XAllocColor(d, cmap, &xcl); + if ((ret == Success) || + ((xcl_in.red & sig_mask) != (xcl.red & sig_mask)) || + ((xcl_in.green & sig_mask) != (xcl.green & sig_mask)) || + ((xcl_in.blue & sig_mask) != (xcl.blue & sig_mask))) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for (j = 0; j < i; j++) + pixels[j] = (unsigned long)color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + free(color_lut); + return NULL; + } + color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 1; + return color_lut; +} + +DATA8 * +__imlib_AllocColors222(Display * d, Colormap cmap, Visual * v) +{ + int r, g, b, i; + DATA8 *color_lut; + int sig_mask = 0; + + for (i = 0; i < v->bits_per_rgb; i++) + sig_mask |= (0x1 << i); + sig_mask <<= (16 - v->bits_per_rgb); + i = 0; + color_lut = malloc(64 * sizeof(DATA8)); + for (r = 0; r < 4; r++) + { + for (g = 0; g < 4; g++) + { + for (b = 0; b < 4; b++) + { + XColor xcl; + XColor xcl_in; + int val; + Status ret; + + val = (r << 6) | (r << 4) | (r << 2) | (r); + xcl.red = (unsigned short)((val << 8) | (val)); + val = (g << 6) | (g << 4) | (g << 2) | (g); + xcl.green = (unsigned short)((val << 8) | (val)); + val = (b << 6) | (b << 4) | (b << 2) | (b); + xcl.blue = (unsigned short)((val << 8) | (val)); + xcl_in = xcl; + ret = XAllocColor(d, cmap, &xcl); + if ((ret == Success) || + ((xcl_in.red & sig_mask) != (xcl.red & sig_mask)) || + ((xcl_in.green & sig_mask) != (xcl.green & sig_mask)) || + ((xcl_in.blue & sig_mask) != (xcl.blue & sig_mask))) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for (j = 0; j < i; j++) + pixels[j] = (unsigned long)color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + free(color_lut); + return NULL; + } + color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 2; + return color_lut; +} + +DATA8 * +__imlib_AllocColors221(Display * d, Colormap cmap, Visual * v) +{ + int r, g, b, i; + DATA8 *color_lut; + int sig_mask = 0; + + for (i = 0; i < v->bits_per_rgb; i++) + sig_mask |= (0x1 << i); + sig_mask <<= (16 - v->bits_per_rgb); + i = 0; + color_lut = malloc(32 * sizeof(DATA8)); + for (r = 0; r < 4; r++) + { + for (g = 0; g < 4; g++) + { + for (b = 0; b < 2; b++) + { + XColor xcl; + XColor xcl_in; + int val; + Status ret; + + val = (r << 6) | (r << 4) | (r << 2) | (r); + xcl.red = (unsigned short)((val << 8) | (val)); + val = (g << 6) | (g << 4) | (g << 2) | (g); + xcl.green = (unsigned short)((val << 8) | (val)); + val = + (b << 7) | (b << 6) | (b << 5) | (b << 4) | (b << 3) | (b + << + 2) + | (b << 1) | (b); + xcl.blue = (unsigned short)((val << 8) | (val)); + xcl_in = xcl; + ret = XAllocColor(d, cmap, &xcl); + if ((ret == Success) || + ((xcl_in.red & sig_mask) != (xcl.red & sig_mask)) || + ((xcl_in.green & sig_mask) != (xcl.green & sig_mask)) || + ((xcl_in.blue & sig_mask) != (xcl.blue & sig_mask))) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for (j = 0; j < i; j++) + pixels[j] = (unsigned long)color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + free(color_lut); + return NULL; + } + color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 3; + return color_lut; +} + +DATA8 * +__imlib_AllocColors121(Display * d, Colormap cmap, Visual * v) +{ + int r, g, b, i; + DATA8 *color_lut; + int sig_mask = 0; + + for (i = 0; i < v->bits_per_rgb; i++) + sig_mask |= (0x1 << i); + sig_mask <<= (16 - v->bits_per_rgb); + i = 0; + color_lut = malloc(16 * sizeof(DATA8)); + for (r = 0; r < 2; r++) + { + for (g = 0; g < 4; g++) + { + for (b = 0; b < 2; b++) + { + XColor xcl; + XColor xcl_in; + int val; + Status ret; + + val = + (r << 7) | (r << 6) | (r << 5) | (r << 4) | (r << 3) | (r + << + 2) + | (r << 1) | (r); + xcl.red = (unsigned short)((val << 8) | (val)); + val = (g << 6) | (g << 4) | (g << 2) | (g); + xcl.green = (unsigned short)((val << 8) | (val)); + val = + (b << 7) | (b << 6) | (b << 5) | (b << 4) | (b << 3) | (b + << + 2) + | (b << 1) | (b); + xcl.blue = (unsigned short)((val << 8) | (val)); + xcl_in = xcl; + ret = XAllocColor(d, cmap, &xcl); + if ((ret == Success) || + ((xcl_in.red & sig_mask) != (xcl.red & sig_mask)) || + ((xcl_in.green & sig_mask) != (xcl.green & sig_mask)) || + ((xcl_in.blue & sig_mask) != (xcl.blue & sig_mask))) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for (j = 0; j < i; j++) + pixels[j] = (unsigned long)color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + free(color_lut); + return NULL; + } + color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 4; + return color_lut; +} + +DATA8 * +__imlib_AllocColors111(Display * d, Colormap cmap, Visual * v) +{ + int r, g, b, i; + DATA8 *color_lut; + int sig_mask = 0; + + for (i = 0; i < v->bits_per_rgb; i++) + sig_mask |= (0x1 << i); + sig_mask <<= (16 - v->bits_per_rgb); + i = 0; + color_lut = malloc(8 * sizeof(DATA8)); + for (r = 0; r < 2; r++) + { + for (g = 0; g < 2; g++) + { + for (b = 0; b < 2; b++) + { + XColor xcl; + XColor xcl_in; + int val; + Status ret; + + val = + (r << 7) | (r << 6) | (r << 5) | (r << 4) | (r << 3) | (r + << + 2) + | (r << 1) | (r); + xcl.red = (unsigned short)((val << 8) | (val)); + val = + (g << 7) | (g << 6) | (g << 5) | (g << 4) | (g << 3) | (g + << + 2) + | (g << 1) | (g); + xcl.green = (unsigned short)((val << 8) | (val)); + val = + (b << 7) | (b << 6) | (b << 5) | (b << 4) | (b << 3) | (b + << + 2) + | (b << 1) | (b); + xcl.blue = (unsigned short)((val << 8) | (val)); + xcl_in = xcl; + ret = XAllocColor(d, cmap, &xcl); + if ((ret == Success) || + ((xcl_in.red & sig_mask) != (xcl.red & sig_mask)) || + ((xcl_in.green & sig_mask) != (xcl.green & sig_mask)) || + ((xcl_in.blue & sig_mask) != (xcl.blue & sig_mask))) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for (j = 0; j < i; j++) + pixels[j] = (unsigned long)color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + free(color_lut); + return NULL; + } + color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 5; + return color_lut; +} + +DATA8 * +__imlib_AllocColors1(Display * d, Colormap cmap, Visual * v) +{ + XColor xcl; + DATA8 *color_lut; + + color_lut = malloc(2 * sizeof(DATA8)); + xcl.red = (unsigned short)(0x0000); + xcl.green = (unsigned short)(0x0000); + xcl.blue = (unsigned short)(0x0000); + XAllocColor(d, cmap, &xcl); + color_lut[0] = xcl.pixel; + xcl.red = (unsigned short)(0xffff); + xcl.green = (unsigned short)(0xffff); + xcl.blue = (unsigned short)(0xffff); + XAllocColor(d, cmap, &xcl); + color_lut[1] = xcl.pixel; + _pal_type = 6; + return color_lut; +} + +#endif diff --git a/src/lib/color.h b/src/lib/color.h new file mode 100644 index 0000000..7f58194 --- /dev/null +++ b/src/lib/color.h @@ -0,0 +1,22 @@ +#ifndef __COLOR +#define __COLOR 1 + +#ifdef BUILD_X11 + +extern DATA16 _max_colors; + +int __imlib_XActualDepth(Display *d, Visual *v); +Visual *__imlib_BestVisual(Display *d, int screen, int *depth_return); +DATA8 * __imlib_AllocColorTable(Display *d, Colormap cmap, DATA8 *type_return, Visual *v); +DATA8 * __imlib_AllocColors332(Display *d, Colormap cmap, Visual *v); +DATA8 * __imlib_AllocColors666(Display *d, Colormap cmap, Visual *v); +DATA8 * __imlib_AllocColors232(Display *d, Colormap cmap, Visual *v); +DATA8 * __imlib_AllocColors222(Display *d, Colormap cmap, Visual *v); +DATA8 * __imlib_AllocColors221(Display *d, Colormap cmap, Visual *v); +DATA8 * __imlib_AllocColors121(Display *d, Colormap cmap, Visual *v); +DATA8 * __imlib_AllocColors111(Display *d, Colormap cmap, Visual *v); +DATA8 * __imlib_AllocColors1(Display *d, Colormap cmap, Visual *v); + +#endif + +#endif diff --git a/src/lib/color_helpers.c b/src/lib/color_helpers.c new file mode 100644 index 0000000..69dc2d5 --- /dev/null +++ b/src/lib/color_helpers.c @@ -0,0 +1,235 @@ +#include "color_helpers.h" +/* + * Color space conversion helper routines + * Convert between rgb and hsv adn between rgb and hls + */ + +void +__imlib_rgb_to_hsv(int r, int g, int b, float *hue, float *saturation, + float *value) +{ + int f; + float i, j, k, max, min, d; + + i = ((float)r) / 255.0; + j = ((float)g) / 255.0; + k = ((float)b) / 255.0; + + f = 0; + max = min = i; + if (j > max) + { + max = j; + f = 1; + } + else + min = j; + if (k > max) + { + max = k; + f = 2; + } + else if (k < min) + min = k; + d = max - min; + + *value = max; + if (max != 0) + *saturation = d / max; + else + *saturation = 0; + if (*saturation == 0) + *hue = 0; + else + { + switch (f) + { + case 0: + *hue = (j - k) / d; + break; + case 1: + *hue = 2 + (k - i) / d; + break; + case 2: + *hue = 4 + (i - j) / d; + break; + } + *hue *= 60.0; + if (*hue < 0) + *hue += 360.0; + } +} + +void +__imlib_hsv_to_rgb(float hue, float saturation, float value, int *r, int *g, + int *b) +{ + int i, p, q, t, h; + float vs, vsf; + + i = (int)(value * 255.0); + if (saturation == 0) + *r = *g = *b = i; + else + { + if (hue == 360) + hue = 0; + hue = hue / 60.0; + h = (int)hue; + vs = value * saturation; + vsf = vs * (hue - h); + p = (int)(255.0 * (value - vs)); + q = (int)(255.0 * (value - vsf)); + t = (int)(255.0 * (value - vs + vsf)); + switch (h) + { + case 0: + *r = i; + *g = t; + *b = p; + break; + case 1: + *r = q; + *g = i; + *b = p; + break; + case 2: + *r = p; + *g = i; + *b = t; + break; + case 3: + *r = p; + *g = q; + *b = i; + break; + case 4: + *r = t; + *g = p; + *b = i; + break; + case 5: + *r = i; + *g = p; + *b = q; + break; + } + } +} + +void +__imlib_rgb_to_hls(int r, int g, int b, float *hue, float *lightness, + float *saturation) +{ + int f; + float i, j, k, max, min, d; + + i = ((float)r) / 255.0; + j = ((float)g) / 255.0; + k = ((float)b) / 255.0; + + f = 0; + max = min = i; + if (j > max) + { + max = j; + f = 1; + } + else + min = j; + if (k > max) + { + max = k; + f = 2; + } + else if (k < min) + min = k; + d = max - min; + + *lightness = (max + min) / 2.0; + if (d == 0) + { + *saturation = 0; + *hue = 0; + } + else + { + if (*lightness < 0.5) + *saturation = d / (max + min); + else + *saturation = d / (2 - max - min); + switch (f) + { + case 0: + *hue = (j - k) / d; + break; + case 1: + *hue = 2 + (k - i) / d; + break; + case 2: + *hue = 4 + (i - j) / d; + break; + } + *hue *= 60.0; + if (*hue < 0) + *hue += 360.0; + } +} + +void +__imlib_hls_to_rgb(float hue, float lightness, float saturation, int *r, int *g, + int *b) +{ + float m1, m2, m21, h; + + if (saturation == 0) + *r = *g = *b = (int)(lightness * 255.0); + else + { + if (lightness <= 0.5) + m2 = lightness * (1 + saturation); + else + m2 = lightness + saturation + lightness * saturation; + m1 = 2 * lightness - m2; + m21 = m2 - m1; + h = hue + 120; + if (h > 360) + h -= 360; + else if (h < 0) + h += 360; + if (h < 60) + *r = (int)(255.0 * (m1 + m21 * h / 60.0)); + else if (h < 180) + *r = (int)(255.0 * m2); + else if (h < 240) + *r = (int)(255.0 * (m1 + m21 * (240.0 - h) / 60.0)); + else + *r = (int)(255.0 * m1); + h = hue; + if (h > 360) + h -= 360; + else if (h < 0) + h += 360; + if (h < 60) + *g = (int)(255.0 * (m1 + m21 * h / 60.0)); + else if (h < 180) + *g = (int)(255.0 * m2); + else if (h < 240) + *g = (int)(255.0 * (m1 + m21 * (240.0 - h) / 60.0)); + else + *g = (int)(255.0 * m1); + h = hue - 120; + if (h > 360) + h -= 360; + else if (h < 0) + h += 360; + if (h < 60) + *b = (int)(255.0 * (m1 + m21 * h / 60.0)); + else if (h < 180) + *b = (int)(255.0 * m2); + else if (h < 240) + *b = (int)(255.0 * (m1 + m21 * (240.0 - h) / 60.0)); + else + *b = (int)(255.0 * m1); + } +} diff --git a/src/lib/color_helpers.h b/src/lib/color_helpers.h new file mode 100644 index 0000000..0ed1999 --- /dev/null +++ b/src/lib/color_helpers.h @@ -0,0 +1,9 @@ +#ifndef __COLOR_HELPERS +#define __COLOR_HELPERS 1 + +void __imlib_rgb_to_hsv(int r, int g, int b, float *hue, float *saturation, float *value); +void __imlib_hsv_to_rgb(float hue, float saturation, float value, int *r, int *g, int *b); +void __imlib_rgb_to_hls(int r, int g, int b, float *hue, float *lightness, float *saturation); +void __imlib_hls_to_rgb(float hue, float lightness, float saturation, int *r, int *g, int *b); + +#endif diff --git a/src/lib/colormod.c b/src/lib/colormod.c new file mode 100644 index 0000000..7940989 --- /dev/null +++ b/src/lib/colormod.c @@ -0,0 +1,254 @@ +#include "common.h" +#include "colormod.h" +#include "file.h" +#include "loaderpath.h" +#include +#include "image.h" +#include "blend.h" + +static DATABIG mod_count = 0; + +ImlibColorModifier * +__imlib_CreateCmod(void) +{ + ImlibColorModifier *cm; + int i; + + cm = malloc(sizeof(ImlibColorModifier)); + cm->modification_count = mod_count; + for (i = 0; i < 256; i++) + { + cm->red_mapping[i] = (DATA8) i; + cm->green_mapping[i] = (DATA8) i; + cm->blue_mapping[i] = (DATA8) i; + cm->alpha_mapping[i] = (DATA8) i; + } + return cm; +} + +void +__imlib_FreeCmod(ImlibColorModifier * cm) +{ + free(cm); +} + +void +__imlib_CmodChanged(ImlibColorModifier * cm) +{ + mod_count++; + cm->modification_count = mod_count; +} + +void +__imlib_CmodSetTables(ImlibColorModifier * cm, + DATA8 * r, DATA8 * g, DATA8 * b, DATA8 * a) +{ + int i; + + for (i = 0; i < 256; i++) + { + if (r) + cm->red_mapping[i] = r[i]; + if (g) + cm->green_mapping[i] = g[i]; + if (b) + cm->blue_mapping[i] = b[i]; + if (a) + cm->alpha_mapping[i] = a[i]; + } + __imlib_CmodChanged(cm); +} + +void +__imlib_CmodReset(ImlibColorModifier * cm) +{ + int i; + + for (i = 0; i < 256; i++) + { + cm->red_mapping[i] = (DATA8) i; + cm->green_mapping[i] = (DATA8) i; + cm->blue_mapping[i] = (DATA8) i; + cm->alpha_mapping[i] = (DATA8) i; + } + __imlib_CmodChanged(cm); +} + +void +__imlib_DataCmodApply(DATA32 * data, int w, int h, int jump, + ImlibImageFlags * fl, ImlibColorModifier * cm) +{ + int x, y; + DATA32 *p; + + /* We might be adding alpha */ + if (fl && !(*fl & F_HAS_ALPHA)) + { + p = data; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + R_VAL(p) = R_CMOD(cm, R_VAL(p)); + G_VAL(p) = G_CMOD(cm, G_VAL(p)); + B_VAL(p) = B_CMOD(cm, B_VAL(p)); + A_VAL(p) = A_CMOD(cm, 255); + p++; + } + p += jump; + } + if (A_CMOD(cm, 255) != 255) + *fl |= F_HAS_ALPHA; + return; + } + + p = data; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + R_VAL(p) = R_CMOD(cm, R_VAL(p)); + G_VAL(p) = G_CMOD(cm, G_VAL(p)); + B_VAL(p) = B_CMOD(cm, B_VAL(p)); + A_VAL(p) = A_CMOD(cm, A_VAL(p)); + p++; + } + p += jump; + } +} + +void +__imlib_CmodGetTables(ImlibColorModifier * cm, DATA8 * r, DATA8 * g, + DATA8 * b, DATA8 * a) +{ + if (r) + memcpy(r, cm->red_mapping, (256 * sizeof(DATA8))); + if (g) + memcpy(g, cm->green_mapping, (256 * sizeof(DATA8))); + if (b) + memcpy(b, cm->blue_mapping, (256 * sizeof(DATA8))); + if (a) + memcpy(a, cm->alpha_mapping, (256 * sizeof(DATA8))); +} + +void +__imlib_CmodModBrightness(ImlibColorModifier * cm, double v) +{ + int i, val, val2; + + val = (int)(v * 255); + for (i = 0; i < 256; i++) + { + val2 = (int)cm->red_mapping[i] + val; + if (val2 < 0) + val2 = 0; + if (val2 > 255) + val2 = 255; + cm->red_mapping[i] = (DATA8) val2; + + val2 = (int)cm->green_mapping[i] + val; + if (val2 < 0) + val2 = 0; + if (val2 > 255) + val2 = 255; + cm->green_mapping[i] = (DATA8) val2; + + val2 = (int)cm->blue_mapping[i] + val; + if (val2 < 0) + val2 = 0; + if (val2 > 255) + val2 = 255; + cm->blue_mapping[i] = (DATA8) val2; + + val2 = (int)cm->alpha_mapping[i] + val; + if (val2 < 0) + val2 = 0; + if (val2 > 255) + val2 = 255; + cm->alpha_mapping[i] = (DATA8) val2; + } +} + +void +__imlib_CmodModContrast(ImlibColorModifier * cm, double v) +{ + int i, val2; + + for (i = 0; i < 256; i++) + { + val2 = (int)(((double)cm->red_mapping[i] - 127) * v) + 127; + if (val2 < 0) + val2 = 0; + if (val2 > 255) + val2 = 255; + cm->red_mapping[i] = (DATA8) val2; + + val2 = (int)(((double)cm->green_mapping[i] - 127) * v) + 127; + if (val2 < 0) + val2 = 0; + if (val2 > 255) + val2 = 255; + cm->green_mapping[i] = (DATA8) val2; + + val2 = (int)(((double)cm->blue_mapping[i] - 127) * v) + 127; + if (val2 < 0) + val2 = 0; + if (val2 > 255) + val2 = 255; + cm->blue_mapping[i] = (DATA8) val2; + + val2 = (int)(((double)cm->alpha_mapping[i] - 127) * v) + 127; + if (val2 < 0) + val2 = 0; + if (val2 > 255) + val2 = 255; + cm->alpha_mapping[i] = (DATA8) val2; + } +} + +void +__imlib_CmodModGamma(ImlibColorModifier * cm, double v) +{ + int i, val2; + + if (v < 0.01) + v = 0.01; + for (i = 0; i < 256; i++) + { + val2 = (int)(pow(((double)cm->red_mapping[i] / 255), (1 / v)) * 255); + if (val2 < 0) + val2 = 0; + if (val2 > 255) + val2 = 255; + cm->red_mapping[i] = (DATA8) val2; + + val2 = (int)(pow(((double)cm->green_mapping[i] / 255), (1 / v)) * 255); + if (val2 < 0) + val2 = 0; + if (val2 > 255) + val2 = 255; + cm->green_mapping[i] = (DATA8) val2; + + val2 = (int)(pow(((double)cm->blue_mapping[i] / 255), (1 / v)) * 255); + if (val2 < 0) + val2 = 0; + if (val2 > 255) + val2 = 255; + cm->blue_mapping[i] = (DATA8) val2; + + val2 = (int)(pow(((double)cm->alpha_mapping[i] / 255), (1 / v)) * 255); + if (val2 < 0) + val2 = 0; + if (val2 > 255) + val2 = 255; + cm->alpha_mapping[i] = (DATA8) val2; + } +} + +#if 0 +void +__imlib_ImageCmodApply(ImlibImage * im, ImlibColorModifier * cm) +{ + __imlib_DataCmodApply(im->data, im->w, im->h, 0, cm); +} +#endif diff --git a/src/lib/colormod.h b/src/lib/colormod.h new file mode 100644 index 0000000..4ac25a4 --- /dev/null +++ b/src/lib/colormod.h @@ -0,0 +1,72 @@ +#ifndef __COLORMOD +#define __COLORMOD 1 + +#include "common.h" +#include +#include +#include +#include +#include +#include +#include +#include "image.h" + +typedef struct _imlib_color_modifier ImlibColorModifier; + +struct _imlib_color_modifier +{ + DATA8 red_mapping[256]; + DATA8 green_mapping[256]; + DATA8 blue_mapping[256]; + DATA8 alpha_mapping[256]; + DATABIG modification_count; +}; + +#define CMOD_APPLY_RGB(cm, r, g, b) \ +(r) = (cm)->red_mapping[(int)(r)]; \ +(g) = (cm)->green_mapping[(int)(g)]; \ +(b) = (cm)->blue_mapping[(int)(b)]; + +#define CMOD_APPLY_RGBA(cm, r, g, b, a) \ +(r) = (cm)->red_mapping[(int)(r)]; \ +(g) = (cm)->green_mapping[(int)(g)]; \ +(b) = (cm)->blue_mapping[(int)(b)]; \ +(a) = (cm)->alpha_mapping[(int)(a)]; + +#define CMOD_APPLY_R(cm, r) \ +(r) = (cm)->red_mapping[(int)(r)]; +#define CMOD_APPLY_G(cm, g) \ +(g) = (cm)->green_mapping[(int)(g)]; +#define CMOD_APPLY_B(cm, b) \ +(b) = (cm)->blue_mapping[(int)(b)]; +#define CMOD_APPLY_A(cm, a) \ +(a) = (cm)->alpha_mapping[(int)(a)]; + +#define R_CMOD(cm, r) \ +(cm)->red_mapping[(int)(r)] +#define G_CMOD(cm, g) \ +(cm)->green_mapping[(int)(g)] +#define B_CMOD(cm, b) \ +(cm)->blue_mapping[(int)(b)] +#define A_CMOD(cm, a) \ +(cm)->alpha_mapping[(int)(a)] + +ImlibColorModifier * __imlib_CreateCmod(void); +void __imlib_FreeCmod(ImlibColorModifier *cm); +void __imlib_CmodChanged(ImlibColorModifier *cm); +void __imlib_CmodSetTables(ImlibColorModifier *cm, DATA8 *r, + DATA8 *g, DATA8 *b, DATA8 *a); +void __imlib_CmodReset(ImlibColorModifier *cm); +void __imlib_DataCmodApply(DATA32 *data, int w, int h, + int jump, ImlibImageFlags *fl, + ImlibColorModifier *cm); + +void __imlib_CmodGetTables(ImlibColorModifier *cm, DATA8 *r, + DATA8 *g, DATA8 *b, DATA8 *a); +void __imlib_CmodModBrightness(ImlibColorModifier *cm, + double v); +void __imlib_CmodModContrast(ImlibColorModifier *cm, + double v); +void __imlib_CmodModGamma(ImlibColorModifier *cm, + double v); +#endif diff --git a/src/lib/common.h b/src/lib/common.h new file mode 100644 index 0000000..3a99628 --- /dev/null +++ b/src/lib/common.h @@ -0,0 +1,42 @@ +#ifndef __COMMON +#define __COMMON 1 + +#include "config.h" + +#include +#include +#include +#include +#include +#ifdef WITH_DMALLOC +# include +#endif +#ifdef __EMX__ +#include +#endif + +#define DATABIG unsigned long long +#define DATA64 unsigned long long +#define DATA32 unsigned int +#define DATA16 unsigned short +#define DATA8 unsigned char + +#ifdef DO_MMX_ASM +int __imlib_get_cpuid(void); +#define CPUID_MMX (1 << 23) +#define CPUID_XMM (1 << 25) +#endif + +#define CLIP(x, y, w, h, xx, yy, ww, hh) \ +if (x < (xx)) {w += (x - (xx)); x = (xx);} \ +if (y < (yy)) {h += (y - (yy)); y = (yy);} \ +if ((x + w) > ((xx) + (ww))) {w = (ww) - (x - xx);} \ +if ((y + h) > ((yy) + (hh))) {h = (hh) - (y - yy);} +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#ifdef __EMX__ +extern char *__XOS2RedirRoot(const char *); +#endif + +#endif diff --git a/src/lib/context.c b/src/lib/context.c new file mode 100644 index 0000000..a0b5794 --- /dev/null +++ b/src/lib/context.c @@ -0,0 +1,212 @@ +#include "common.h" +#ifdef BUILD_X11 +#include +#endif +#include "image.h" +#include "context.h" +#include "color.h" +#include "rgba.h" + +#ifdef BUILD_X11 + +static Context *context = NULL; +static int max_context_count = 128; +static int context_counter = 0; + +void +__imlib_SetMaxContexts(int num) +{ + max_context_count = num; + __imlib_FlushContexts(); +} + +int +__imlib_GetMaxContexts(void) +{ + return max_context_count; +} + +void +__imlib_FlushContexts(void) +{ + Context *ct, *pct, *ctt; + + ct = context; + pct = NULL; + while (ct) + { + ctt = ct; + ct = ct->next; + /* it hasnt been referenced in the last max_context_count refernces */ + /* thus old and getrid of it */ + if (ctt->last_use < (context_counter - max_context_count)) + { + if (pct) + context = ctt->next; + else + pct->next = ctt->next; + if (ctt->palette) + { + int i, num[] = { 256, 128, 64, 32, 16, 8, 1 }; + unsigned long pixels[256]; + + for (i = 0; i < num[ctt->palette_type]; i++) + pixels[i] = (unsigned long)ctt->palette[i]; + XFreeColors(ctt->display, ctt->colormap, pixels, + num[ctt->palette_type], 0); + + free(ctt->palette); + free(ctt->r_dither); + free(ctt->g_dither); + free(ctt->b_dither); + } + else if (ctt->r_dither) + { + free(ctt->r_dither); + free(ctt->g_dither); + free(ctt->b_dither); + } + free(ctt); + } + else + pct = ctt; + } +} + +void +__imlib_FreeContextForDisplay(Display * d) +{ + Context *ct; + + ct = context; + while (ct) + { + if (ct->display == d) + ct->last_use = -(max_context_count * 2); + ct = ct->next; + } + __imlib_FlushContexts(); +} + +void +__imlib_FreeContextForColormap(Display * d, Colormap cm) +{ + Context *ct; + + ct = context; + while (ct) + { + if ((ct->display == d) && (ct->colormap == cm)) + ct->last_use = -(max_context_count * 2); + ct = ct->next; + } + __imlib_FlushContexts(); +} + +void +__imlib_FreeContextForVisual(Display * d, Visual * v) +{ + Context *ct; + + ct = context; + while (ct) + { + if ((ct->display == d) && (ct->visual == v)) + ct->last_use = -(max_context_count * 2); + ct = ct->next; + } + __imlib_FlushContexts(); +} + +Context * +__imlib_FindContext(Display * d, Visual * v, Colormap c, int depth) +{ + Context *ct, *pct; + + pct = NULL; + ct = context; + while (ct) + { + if ((ct->display == d) && (ct->visual == v) && + (ct->colormap == c) && (ct->depth == depth)) + { + if (pct) + { + pct->next = ct->next; + ct->next = context; + context = ct; + } + return ct; + } + pct = ct; + ct = ct->next; + } + return NULL; +} + +Context * +__imlib_NewContext(Display * d, Visual * v, Colormap c, int depth) +{ + Context *ct; + + context_counter++; + ct = malloc(sizeof(Context)); + ct->last_use = context_counter; + ct->display = d; + ct->visual = v; + ct->colormap = c; + ct->depth = depth; + ct->next = NULL; + + if (depth <= 8) + { + ct->palette = __imlib_AllocColorTable(d, c, &(ct->palette_type), v); + ct->r_dither = malloc(sizeof(DATA8) * DM_X * DM_Y * 256); + ct->g_dither = malloc(sizeof(DATA8) * DM_X * DM_Y * 256); + ct->b_dither = malloc(sizeof(DATA8) * DM_X * DM_Y * 256); + __imlib_RGBA_init((void *)ct->r_dither, (void *)ct->g_dither, + (void *)ct->b_dither, depth, ct->palette_type); + } + else + { + ct->palette = NULL; + ct->palette_type = 0; + if ((depth > 8) && (depth <= 16)) + { + ct->r_dither = malloc(sizeof(DATA16) * 4 * 4 * 256); + ct->g_dither = malloc(sizeof(DATA16) * 4 * 4 * 256); + ct->b_dither = malloc(sizeof(DATA16) * 4 * 4 * 256); + __imlib_RGBA_init((void *)ct->r_dither, (void *)ct->g_dither, + (void *)ct->b_dither, depth, 0); + } + else + { + ct->r_dither = NULL; + ct->g_dither = NULL; + ct->b_dither = NULL; + __imlib_RGBA_init((void *)ct->r_dither, (void *)ct->g_dither, + (void *)ct->b_dither, depth, 0); + } + } + return ct; +} + +Context * +__imlib_GetContext(Display * d, Visual * v, Colormap c, int depth) +{ + Context *ct; + + ct = __imlib_FindContext(d, v, c, depth); + if (ct) + { + ct->last_use = context_counter; + return ct; + } + ct = __imlib_NewContext(d, v, c, depth); + ct->next = context; + context = ct; + __imlib_FlushContexts(); + return ct; +} + +#endif diff --git a/src/lib/context.h b/src/lib/context.h new file mode 100644 index 0000000..c4bc2ab --- /dev/null +++ b/src/lib/context.h @@ -0,0 +1,36 @@ +#ifndef __CONTEXT +#define __CONTEXT 1 + +#ifdef BUILD_X11 + +typedef struct _context Context; + +struct _context +{ + int last_use; + Display *display; + Visual *visual; + Colormap colormap; + int depth; + Context *next; + + DATA8 *palette; + DATA8 palette_type; + void *r_dither; + void *g_dither; + void *b_dither; +}; + +void __imlib_SetMaxContexts(int num); +int __imlib_GetMaxContexts(void); +void __imlib_FlushContexts(void); +void __imlib_FreeContextForDisplay(Display *d); +void __imlib_FreeContextForColormap(Display *d, Colormap cm); +void __imlib_FreeContextForVisual(Display *d, Visual *v); +Context *__imlib_FindContext(Display *d, Visual *v, Colormap c, int depth); +Context *__imlib_NewContext(Display *d, Visual *v, Colormap c, int depth); +Context *__imlib_GetContext(Display *d, Visual *v, Colormap c, int depth); + +#endif + +#endif diff --git a/src/lib/draw.c b/src/lib/draw.c new file mode 100644 index 0000000..df45000 --- /dev/null +++ b/src/lib/draw.c @@ -0,0 +1,92 @@ +#include "common.h" +#ifdef BUILD_X11 +#include +#include +#endif +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include "rend.h" +#include "draw.h" + +#ifdef BUILD_X11 + +char +__imlib_CreatePixmapsForImage(Display * d, Drawable w, Visual * v, int depth, + Colormap cm, ImlibImage * im, Pixmap * p, + Mask * m, int sx, int sy, int sw, int sh, int dw, + int dh, char antialias, char hiq, + char dither_mask, ImlibColorModifier * cmod) +{ + ImlibImagePixmap *ip = NULL; + Pixmap pmap = 0; + Pixmap mask = 0; + long long mod_count = 0; + + if (cmod) + mod_count = cmod->modification_count; + ip = __imlib_FindCachedImagePixmap(im, dw, dh, d, v, depth, sx, sy, + sw, sh, cm, antialias, hiq, dither_mask, + mod_count); + if (ip) + { + if (p) + *p = ip->pixmap; + if (m) + *m = ip->mask; + ip->references++; +#ifdef DEBUG_CACHE + fprintf(stderr, + "[Imlib2] Match found in cache. Reference count is %d, pixmap 0x%08x, mask 0x%08x\n", + ip->references, ip->pixmap, ip->mask); +#endif + return 2; + } + if (p) + { + pmap = XCreatePixmap(d, w, dw, dh, depth); + *p = pmap; + } + if (m) + { + if (IMAGE_HAS_ALPHA(im)) + mask = XCreatePixmap(d, w, dw, dh, 1); + *m = mask; + } + __imlib_RenderImage(d, im, pmap, mask, v, cm, depth, sx, sy, sw, sh, 0, 0, + dw, dh, antialias, hiq, 0, dither_mask, cmod, OP_COPY); + ip = __imlib_ProduceImagePixmap(); + ip->visual = v; + ip->depth = depth; + ip->image = im; + if (im->file) + ip->file = strdup(im->file); + ip->border.left = im->border.left; + ip->border.right = im->border.right; + ip->border.top = im->border.top; + ip->border.bottom = im->border.bottom; + ip->colormap = cm; + ip->display = d; + ip->w = dw; + ip->h = dh; + ip->source_x = sx; + ip->source_y = sy; + ip->source_w = sw; + ip->source_h = sh; + ip->antialias = antialias; + ip->modification_count = mod_count; + ip->dither_mask = dither_mask; + ip->hi_quality = hiq; + ip->references = 1; + ip->pixmap = pmap; + ip->mask = mask; + __imlib_AddImagePixmapToCache(ip); +#ifdef DEBUG_CACHE + fprintf(stderr, + "[Imlib2] Created pixmap. Reference count is %d, pixmap 0x%08x, mask 0x%08x\n", + ip->references, ip->pixmap, ip->mask); +#endif + return 1; +} + +#endif diff --git a/src/lib/draw.h b/src/lib/draw.h new file mode 100644 index 0000000..52ec770 --- /dev/null +++ b/src/lib/draw.h @@ -0,0 +1,16 @@ +#ifndef __DRAW +#define __DRAW 1 + +#ifdef BUILD_X11 + +char +__imlib_CreatePixmapsForImage(Display *d, Drawable w, Visual *v, int depth, + Colormap cm, ImlibImage *im, Pixmap *p, Mask *m, + int sx, int sy, int sw, int sh, + int dw, int dh, + char anitalias, char hiq, char dither_mask, + ImlibColorModifier *cmod); + +#endif + +#endif diff --git a/src/lib/dynamic_filters.c b/src/lib/dynamic_filters.c new file mode 100644 index 0000000..1f99750 --- /dev/null +++ b/src/lib/dynamic_filters.c @@ -0,0 +1,193 @@ +#include "common.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "image.h" +#include "file.h" +#include "dynamic_filters.h" +#include "script.h" +#include "loaderpath.h" + +pImlibExternalFilter filters = NULL; +int dyn_initialised = 0; + +#define MALLOCSHOW +#define FREESHOW +/* +#define FDEBUG +*/ + +pImlibExternalFilter +__imlib_LoadFilter(char *file) +{ + ImlibExternalFilter *ptr; + struct imlib_filter_info *info; + + /* printf( "Loading filter %s\n", file ); */ + MALLOCSHOW; + ptr = malloc(sizeof(ImlibExternalFilter)); + ptr->filename = strdup(file); + ptr->handle = dlopen(file, RTLD_NOW | RTLD_LOCAL); + if (!ptr->handle) + { + FREESHOW; + free(ptr->filename); + FREESHOW; + free(ptr); + return NULL; + } + ptr->init_filter = dlsym(ptr->handle, "init"); + ptr->deinit_filter = dlsym(ptr->handle, "deinit"); + ptr->exec_filter = dlsym(ptr->handle, "exec"); + if (!ptr->init_filter || !ptr->deinit_filter || !ptr->exec_filter) + { + dlclose(ptr->handle); + FREESHOW; + free(ptr->filename); + FREESHOW; + free(ptr); + return NULL; + } + info = malloc(sizeof(struct imlib_filter_info)); + ptr->init_filter(info); + ptr->num_filters = info->num_filters; + ptr->filters = info->filters; + ptr->name = info->name; + ptr->author = info->author; + ptr->description = info->description; + + free(info); + +#ifdef FDEBUG + printf("Filter has %d filters in it.\n", ptr->num_filters); + for (i = 0; i < ptr->num_filters; i++) + printf(" -> \"%s\"\n", ptr->filters[i]); +#endif + + ptr->next = NULL; + return ptr; +} + +void +__imlib_dynamic_filters_init() +{ + char **list; + int num_filters, i = 0; + ImlibExternalFilter *ptr, *tptr; + + if (!dyn_initialised) + { + MALLOCSHOW; + filters = malloc(sizeof(ImlibExternalFilter)); + filters->filename = ""; + filters->next = NULL; + ptr = filters; +#ifdef FDEBUG + printf("DEBUG: Dynamic filters Initisialising\n"); +#endif + dyn_initialised = 1; +#ifdef FDEBUG + printf("DEBUG: Loading Filters\n"); +#endif + list = __imlib_ListFilters(&num_filters); + for (i = num_filters - 1; i >= 0; i--) + { + tptr = NULL; + if ((tptr = __imlib_LoadFilter(list[i])) != NULL) + { + ptr->next = tptr; + ptr = ptr->next; + } + if (list[i]) + { + FREESHOW; + free(list[i]); + } + } + FREESHOW; + if (list) + free(list); + } +} + +void +__imlib_dynamic_filters_deinit() +{ +} + +pImlibExternalFilter +__imlib_get_dynamic_filter(char *name) +{ + pImlibExternalFilter f_ptr; + int i = 0; + + /* scan the filters */ + for (f_ptr = filters->next; f_ptr != NULL; f_ptr = f_ptr->next) + { + /* scan the methods provided */ + for (i = 0; i < f_ptr->num_filters; i++) + { + if (strcmp(f_ptr->filters[i], name) == 0) + { +#ifdef FDEBUG + printf("DEBUG: Found filter \"%s\"\n", name); +#endif + return f_ptr; + } + } + } + return NULL; +} + +/* loader dir */ +char ** +__imlib_ListFilters(int *num_ret) +{ + char **list = NULL, **l, *s; + int num, i, pi = 0; + + *num_ret = 0; + /* same for system loader path */ + s = (char *)malloc(sizeof(SYS_LOADERS_PATH) + 8 + 1); + sprintf(s, SYS_LOADERS_PATH "/filters"); +#ifndef __EMX__ + l = __imlib_FileDir(s, &num); +#else + l = __imlib_FileDir(__XOS2RedirRoot(s), &num); +#endif + if (num > 0) + { + *num_ret += num; + list = realloc(list, sizeof(char *) * *num_ret); + for (i = 0; i < num; i++) + { + s = (char *)realloc(s, + sizeof(SYS_LOADERS_PATH) + 9 + strlen(l[i]) + + 1); + sprintf(s, SYS_LOADERS_PATH "/filters/%s", l[i]); +#ifndef __EMX__ + list[pi + i] = strdup(s); +#else + list[pi + i] = strdup(__XOS2RedirRoot(s)); +#endif + } + __imlib_FileFreeDirList(l, num); + } + free(s); + + /* List currently contains *everything in there* we need to weed out + * the .so, .la, .a versions of the same loader or whatever else. + * dlopen can take an extension-less name and do the Right Thing + * with it, so that's what we'll give it. */ + list = __imlib_TrimLoaderList(list, num_ret); + + return list; +} diff --git a/src/lib/dynamic_filters.h b/src/lib/dynamic_filters.h new file mode 100644 index 0000000..93eae42 --- /dev/null +++ b/src/lib/dynamic_filters.h @@ -0,0 +1,43 @@ +#ifndef _DYNAMIC_FILTERS_H_ +#define _DYNAMIC_FILTERS_H_ + +#include "script.h" + +struct imlib_filter_info +{ + char *name; + char *author; + char *description; + char **filters; + int num_filters; +}; + +typedef struct _imlib_external_filter ImlibExternalFilter; +typedef struct _imlib_external_filter *pImlibExternalFilter; +struct _imlib_external_filter +{ + char *name; + char *author; + char *description; + int num_filters; + char *filename; + void *handle; + char **filters; + void (*init_filter)( struct imlib_filter_info *info ); + void (*deinit_filter)(); + void *(*exec_filter)( char *filter, void *im, pIFunctionParam params ); + pImlibExternalFilter next; +}; + +void __imlib_dynamic_filters_init(); +void __imlib_dynamic_filters_deinit(); +pImlibExternalFilter __imlib_get_dynamic_filter( char *name ); +char **__imlib_ListFilters(int *num_ret); +pImlibExternalFilter __imlib_LoadFilter( char *file ); + + + +#endif + + + diff --git a/src/lib/ellipse.c b/src/lib/ellipse.c new file mode 100644 index 0000000..8ddf5b1 --- /dev/null +++ b/src/lib/ellipse.c @@ -0,0 +1,737 @@ +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include "span.h" +#include "updates.h" +#include "rgbadraw.h" + + +static void +__imlib_Ellipse_DrawToData(int xc, int yc, int a, int b, DATA32 color, + DATA32 *dst, int dstw, int clx, int cly, int clw, int clh, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibPointDrawFunction pfunc; + int xx, yy, x, y, prev_x, prev_y, ty, by, lx, rx; + DATA32 a2, b2, *tp, *bp; + DATA64 dx, dy; + + if (A_VAL(&color) == 0xff) + blend = 0; + pfunc = __imlib_GetPointDrawFunction(op, dst_alpha, blend); + if (!pfunc) + return; + + xc -= clx; + yc -= cly; + dst += (dstw * cly) + clx; + + a2 = a*a; b2 = b*b; + + yy = b << 16; + prev_y = b; + + dx = a2 * b; + dy = 0; + + ty = yc - b - 1; + by = yc + b; + lx = xc - 1; + rx = xc; + + tp = dst + (dstw * ty) + lx; + bp = dst + (dstw * by) + lx; + + while (dy < dx) + { + int len; + + y = yy >> 16; + y += ((yy - (y << 16)) >> 15); + + if (prev_y != y) + { + prev_y = y; + dx -= a2; + ty++; by--; + tp += dstw; + bp -= dstw; + } + + len = rx - lx; + + if (IN_RANGE(lx, ty, clw, clh)) + pfunc(color, tp); + if (IN_RANGE(rx, ty, clw, clh)) + pfunc(color, tp + len); + if (IN_RANGE(lx, by, clw, clh)) + pfunc(color, bp); + if (IN_RANGE(rx, by, clw, clh)) + pfunc(color, bp + len); + + dy += b2; + yy -= ((dy << 16) / dx); + lx--; rx++; + tp--; bp--; + + if ( (lx < 0) && (rx > clw) ) + return; + if ( (ty > clh) || (by < 0) ) + return; + } + + xx = yy; + prev_x = xx >> 16; + + dx = dy; + + ty++; + by--; + + tp += dstw; + bp -= dstw; + + while (ty < yc) + { + int len; + + x = xx >> 16; + x += ((xx - (x << 16)) >> 15); + + if (prev_x != x) + { + prev_x = x; + dy += b2; + lx--; rx++; + tp--; bp--; + } + + len = rx - lx; + + if (IN_RANGE(lx, ty, clw, clh)) + pfunc(color, tp); + if (IN_RANGE(rx, ty, clw, clh)) + pfunc(color, tp + len); + if (IN_RANGE(lx, by, clw, clh)) + pfunc(color, bp); + if (IN_RANGE(rx, by, clw, clh)) + pfunc(color, bp + len); + + dx -= a2; + xx += ((dx << 16) / dy); + ty++; by--; + tp += dstw; + bp -= dstw; + + if ( (lx < 0) && (rx > clw) ) + return; + if ( (ty > clh) || (by < 0) ) + return; + } +} + +static void +__imlib_Ellipse_DrawToData_AA(int xc, int yc, int a, int b, DATA32 color, + DATA32 *dst, int dstw, int clx, int cly, int clw, int clh, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibPointDrawFunction pfunc; + int xx, yy, x, y, prev_x, prev_y, ty, by, lx, rx; + DATA32 a2, b2, col0, col1, *tp, *bp; + DATA64 dx, dy; + DATA8 ca = A_VAL(&color); + + pfunc = __imlib_GetPointDrawFunction(op, dst_alpha, blend); + if (!pfunc) + return; + + xc -= clx; + yc -= cly; + dst += (dstw * cly) + clx; + + col0 = col1 = color; + a2 = a*a; b2 = b*b; + + yy = b << 16; + prev_y = b; + + dx = a2 * b; + dy = 0; + + ty = yc - b - 2; + by = yc + b + 1; + lx = xc - 1; + rx = xc; + + tp = dst + (dstw * ty) + lx; + bp = dst + (dstw * by) + lx; + + while (dy < dx) + { + int len; + DATA32 tmp; + + y = yy >> 16; + + if (prev_y != y) + { + prev_y = y; + dx -= a2; + ty++; by--; + tp += dstw; + bp -= dstw; + } + + A_VAL(&col1) = (yy - (y << 16)) >> 8; + A_VAL(&col0) = 255 - A_VAL(&col1); + + if (ca < 255) + { + MULT(A_VAL(&col0), ca, A_VAL(&col0), tmp) + MULT(A_VAL(&col1), ca, A_VAL(&col1), tmp) + } + + len = rx - lx; + + if (IN_RANGE(lx, ty, clw, clh)) + pfunc(col1, tp); + if (IN_RANGE(lx, ty + 1, clw, clh)) + pfunc(col0, tp + dstw); + + if (IN_RANGE(rx, ty + 1, clw, clh)) + pfunc(col0, tp + dstw + len); + if (IN_RANGE(rx, ty, clw, clh)) + pfunc(col1, tp + len); + + if (IN_RANGE(lx, by, clw, clh)) + pfunc(col1, bp); + if (IN_RANGE(lx, by - 1, clw, clh)) + pfunc(col0, bp - dstw); + + if (IN_RANGE(rx, by - 1, clw, clh)) + pfunc(col0, bp - dstw + len); + if (IN_RANGE(rx, by, clw, clh)) + pfunc(col1, bp + len); + + dy += b2; + yy -= ((dy << 16) / dx); + lx--; rx++; + tp--; bp--; + + if ( (lx < 0) && (rx > clw) ) + return; + if ( (ty > clh) || (by < 0) ) + return; + } + + y = yy >> 16; + xx = yy; + prev_x = y; + + dx = dy; + + ty++; + by--; + + tp += dstw; + bp -= dstw; + + while (ty < yc) + { + int len; + DATA32 tmp; + + x = xx >> 16; + + if (prev_x != x) + { + prev_x = x; + dy += b2; + lx--; rx++; + tp--; bp--; + } + + A_VAL(&col1) = (xx - (x << 16)) >> 8; + A_VAL(&col0) = 255 - A_VAL(&col1); + + if (ca < 255) + { + MULT(A_VAL(&col0), ca, A_VAL(&col0), tmp) + MULT(A_VAL(&col1), ca, A_VAL(&col1), tmp) + } + + len = rx - lx; + + if (IN_RANGE(lx, ty, clw, clh)) + pfunc(col1, tp); + if (IN_RANGE(lx + 1, ty, clw, clh) && (x != y)) + pfunc(col0, tp + 1); + + if (IN_RANGE(rx - 1, ty, clw, clh) && (x != y)) + pfunc(col0, tp + len - 1); + if (IN_RANGE(rx, ty, clw, clh)) + pfunc(col1, tp + len); + + if (IN_RANGE(lx, by, clw, clh)) + pfunc(col1, bp); + if (IN_RANGE(lx + 1, by, clw, clh) && (x != y)) + pfunc(col0, bp + 1); + + if (IN_RANGE(rx - 1, by, clw, clh) && (x != y)) + pfunc(col0, bp + len - 1); + if (IN_RANGE(rx, by, clw, clh)) + pfunc(col1, bp + len); + + dx -= a2; + xx += ((dx << 16) / dy); + ty++; by--; + tp += dstw; + bp -= dstw; + + if ( (lx < 0) && (rx > clw) ) + return; + if ( (ty > clh) || (by < 0) ) + return; + } +} + +static void +__imlib_Ellipse_FillToData(int xc, int yc, int a, int b, DATA32 color, + DATA32 *dst, int dstw, int clx, int cly, int clw, int clh, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibPointDrawFunction pfunc; + ImlibSpanDrawFunction sfunc; + int xx, yy, x, y, prev_x, prev_y, ty, by, lx, rx; + DATA32 a2, b2, *tp, *bp; + DATA64 dx, dy; + + if (A_VAL(&color) == 0xff) + blend = 0; + pfunc = __imlib_GetPointDrawFunction(op, dst_alpha, blend); + sfunc = __imlib_GetSpanDrawFunction(op, dst_alpha, blend); + if ((!sfunc) || (!pfunc)) + return; + + xc -= clx; + yc -= cly; + dst += (dstw * cly) + clx; + + a2 = a*a; b2 = b*b; + + yy = b << 16; + prev_y = b; + + dx = a2 * b; + dy = 0; + + ty = yc - b - 1; + by = yc + b; + lx = xc - 1; + rx = xc; + + tp = dst + (dstw * ty) + lx; + bp = dst + (dstw * by) + lx; + + while (dy < dx) + { + int len; + DATA32 *tpp, *bpp; + + y = yy >> 16; + y += ((yy - (y << 16)) >> 15); + + if (prev_y != y) + { + prev_y = y; + dx -= a2; + ty++; by--; + tp += dstw; + bp -= dstw; + + tpp = tp + 1; + bpp = bp + 1; + len = rx; + if (len > clw) len = clw; + len -= (lx + 1); + if (lx < -1) + { + len += (lx + 1); + tpp -= (lx + 1); + bpp -= (lx + 1); + } + + if ( ((unsigned)(ty) < clh) && (len > 0) ) + sfunc(color, tpp, len); + if ( ((unsigned)(by) < clh) && (len > 0) ) + sfunc(color, bpp, len); + } + + len = rx - lx; + + if (IN_RANGE(lx, ty, clw, clh)) + pfunc(color, tp); + if (IN_RANGE(rx, ty, clw, clh)) + pfunc(color, tp + len); + if (IN_RANGE(lx, by, clw, clh)) + pfunc(color, bp); + if (IN_RANGE(rx, by, clw, clh)) + pfunc(color, bp + len); + + dy += b2; + yy -= ((dy << 16) / dx); + lx--; rx++; + tp--; bp--; + + if ( (ty > clh) || (by < 0) ) + return; + } + + xx = yy; + prev_x = xx >> 16; + + dx = dy; + + ty++; + by--; + + tp += dstw; + bp -= dstw; + + while (ty < yc) + { + int len; + DATA32 *tpp, *bpp; + + x = xx >> 16; + x += ((xx - (x << 16)) >> 15); + + if (prev_x != x) + { + prev_x = x; + dy += b2; + lx--; rx++; + tp--; bp--; + } + + tpp = tp; + bpp = bp; + len = rx + 1; + if (len > clw) len = clw; + len -= lx; + if (lx < 0) + { + len += lx; + tpp -= lx; + bpp -= lx; + } + + if ( ((unsigned)(ty) < clh) && (len > 0) ) + sfunc(color, tpp, len); + if ( ((unsigned)(by) < clh) && (len > 0) ) + sfunc(color, bpp, len); + + dx -= a2; + xx += ((dx << 16) / dy); + ty++; by--; + tp += dstw; + bp -= dstw; + + if ( (ty > clh) || (by < 0) ) + return; + } +} + +static void +__imlib_Ellipse_FillToData_AA(int xc, int yc, int a, int b, DATA32 color, + DATA32 *dst, int dstw, int clx, int cly, int clw, int clh, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibPointDrawFunction pfunc; + ImlibSpanDrawFunction sfunc; + int xx, yy, x, y, prev_x, prev_y, ty, by, lx, rx; + DATA32 a2, b2, col1, *tp, *bp; + DATA64 dx, dy; + DATA8 ca = A_VAL(&color); + + pfunc = __imlib_GetPointDrawFunction(op, dst_alpha, blend); + if (ca == 0xff) + blend = 0; + sfunc = __imlib_GetSpanDrawFunction(op, dst_alpha, blend); + if ((!pfunc) || (!sfunc)) + return; + + xc -= clx; + yc -= cly; + dst += (dstw * cly) + clx; + + col1 = color; + a2 = a*a; b2 = b*b; + + yy = b << 16; + prev_y = b; + + dx = a2 * b; + dy = 0; + + ty = yc - b - 2; + by = yc + b + 1; + lx = xc - 1; + rx = xc; + + tp = dst + (dstw * ty) + lx; + bp = dst + (dstw * by) + lx; + + while (dy < dx) + { + int len; + DATA32 tmp, *tpp, *bpp; + + y = yy >> 16; + + if (prev_y != y) + { + prev_y = y; + dx -= a2; + ty++; by--; + tp += dstw; + bp -= dstw; + + tpp = tp + 1; + bpp = bp + 1; + len = rx; + if (len > clw) len = clw; + len -= (lx + 1); + if (lx < -1) + { + len += (lx + 1); + tpp -= (lx + 1); + bpp -= (lx + 1); + } + + if ( ((unsigned)(ty) < clh) && (len > 0) ) + sfunc(color, tpp, len); + if ( ((unsigned)(by) < clh) && (len > 0) ) + sfunc(color, bpp, len); + } + + A_VAL(&col1) = ((yy - (y << 16)) >> 8); + if (ca < 255) + MULT(A_VAL(&col1), ca, A_VAL(&col1), tmp) + + len = rx - lx; + + if (IN_RANGE(lx, ty, clw, clh)) + pfunc(col1, tp); + if (IN_RANGE(rx, ty, clw, clh)) + pfunc(col1, tp + len); + if (IN_RANGE(lx, by, clw, clh)) + pfunc(col1, bp); + if (IN_RANGE(rx, by, clw, clh)) + pfunc(col1, bp + len); + + dy += b2; + yy -= ((dy << 16) / dx); + lx--; rx++; + tp--; bp--; + + if ( (ty > clh) || (by < 0) ) + return; + } + + y = yy >> 16; + xx = yy; + prev_x = y; + + dx = dy; + + ty++; + by--; + + tp += dstw; + bp -= dstw; + + while (ty < yc) + { + int len; + DATA32 tmp, *tpp, *bpp; + + x = xx >> 16; + + if (prev_x != x) + { + prev_x = x; + dy += b2; + lx--; rx++; + tp--; bp--; + } + + tpp = tp + 1; + bpp = bp + 1; + len = rx; + if (len > clw) len = clw; + len -= (lx + 1); + if (lx < -1) + { + len += (lx + 1); + tpp -= (lx + 1); + bpp -= (lx + 1); + } + + if ( ((unsigned)(ty) < clh) && (len > 0) ) + sfunc(color, tpp, len); + if ( ((unsigned)(by) < clh) && (len > 0) ) + sfunc(color, bpp, len); + + A_VAL(&col1) = ((xx - (x << 16)) >> 8); + if (ca < 255) + MULT(A_VAL(&col1), ca, A_VAL(&col1), tmp) + + len = rx - lx; + + if (IN_RANGE(lx, ty, clw, clh)) + pfunc(col1, tp); + if (IN_RANGE(rx, ty, clw, clh)) + pfunc(col1, tp + len); + if (IN_RANGE(lx, by, clw, clh)) + pfunc(col1, bp); + if (IN_RANGE(rx, by, clw, clh)) + pfunc(col1, bp + len); + + dx -= a2; + xx += ((dx << 16) / dy); + ty++; by--; + tp += dstw; + bp -= dstw; + + if ( (ty > clh) || (by < 0) ) + return; + } +} + + +void +__imlib_Ellipse_DrawToImage(int xc, int yc, int a, int b, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend, char anti_alias) +{ + int x, y, w, h; + + if ((a == 0) || (b == 0)) + { + (void) __imlib_Line_DrawToImage(xc - a, yc - b, xc + a, yc + b, color, + im, clx, cly, clw, clh, + op, blend, anti_alias, 0); + return; + } + if (blend && (!A_VAL(&color))) + return; + if (clw < 0) + return; + if (clw == 0) + { + clw = im->w; + clx = 0; + clh = im->h; + cly = 0; + } + + CLIP_RECT_TO_RECT(clx, cly, clw, clh, 0, 0, im->w, im->h); + if ((clw < 1) || (clh < 1)) + return; + + if (a < 0) a = -a; + if (b < 0) b = -b; + if (a > 65535) a = 65535; + if (b > 65535) b = 65535; + + w = 2 * (a + 1); + h = 2 * (b + 1); + x = xc - a - 1; + y = yc - b - 1; + if (anti_alias) + { + w += 2; h += 2; + x--; y--; + } + + CLIP_RECT_TO_RECT(x, y, w, h, clx, cly, clw, clh); + if ((w < 1) || (h < 1)) + return; + + if (blend && IMAGE_HAS_ALPHA(im)) + __imlib_build_pow_lut(); + + if (anti_alias) + __imlib_Ellipse_DrawToData_AA(xc, yc, a, b, color, + im->data, im->w, clx, cly, clw, clh, + op, IMAGE_HAS_ALPHA(im), blend); + else + __imlib_Ellipse_DrawToData(xc, yc, a, b, color, + im->data, im->w, clx, cly, clw, clh, + op, IMAGE_HAS_ALPHA(im), blend); +} + + +void +__imlib_Ellipse_FillToImage(int xc, int yc, int a, int b, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend, char anti_alias) +{ + int x, y, w, h; + + if ((a == 0) || (b == 0)) + { + (void) __imlib_Line_DrawToImage(xc - a, yc - b, xc + a, yc + b, color, + im, clx, cly, clw, clh, + op, blend, anti_alias, 0); + return; + } + if (blend && (!A_VAL(&color))) + return; + if (clw < 0) + return; + if (clw == 0) + { + clw = im->w; + clx = 0; + clh = im->h; + cly = 0; + } + + CLIP_RECT_TO_RECT(clx, cly, clw, clh, 0, 0, im->w, im->h); + if ((clw < 1) || (clh < 1)) + return; + + if (a < 0) a = -a; + if (b < 0) b = -b; + if (a > 65535) a = 65535; + if (b > 65535) b = 65535; + + w = 2 * (a + 1); + h = 2 * (b + 1); + x = xc - a - 1; + y = yc - b - 1; + if (anti_alias) + { + w += 2; h += 2; + x--; y--; + } + + CLIP_RECT_TO_RECT(x, y, w, h, clx, cly, clw, clh); + if ((w < 1) || (h < 1)) + return; + + if (blend && IMAGE_HAS_ALPHA(im)) + __imlib_build_pow_lut(); + + if (anti_alias) + __imlib_Ellipse_FillToData_AA(xc, yc, a, b, color, + im->data, im->w, clx, cly, clw, clh, + op, IMAGE_HAS_ALPHA(im), blend); + else + __imlib_Ellipse_FillToData(xc, yc, a, b, color, + im->data, im->w, clx, cly, clw, clh, + op, IMAGE_HAS_ALPHA(im), blend); +} diff --git a/src/lib/file.c b/src/lib/file.c new file mode 100644 index 0000000..d693048 --- /dev/null +++ b/src/lib/file.c @@ -0,0 +1,506 @@ +#include "common.h" +#include +#include +#ifdef __EMX__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include "file.h" + +static void __imlib_FileFieldWord(char *s, int num, char *wd); + +char * +__imlib_FileKey(const char *file) +{ + char *newfile; + + newfile = malloc(strlen(file) + 1); + if (!newfile) + return NULL; + newfile[0] = 0; + { + char *p1, *p2; + int go; + + go = 0; + p1 = (char *)file; + p2 = newfile; + while (p1[0]) + { + if (go) + { + p2[0] = p1[0]; + p2++; + } + if ((p1[0] == ':') && (p1[1] != ':')) + go = 1; + if ((p1[0] == ':') && (p1[1] == ':')) + p1++; + p1++; + } + p2[0] = p1[0]; + } + if (newfile[0]) + return newfile; + else + free(newfile); + return NULL; +} + +char * +__imlib_FileRealFile(const char *file) +{ + char *newfile; + + newfile = malloc(strlen(file) + 1); + if (!newfile) + return NULL; + newfile[0] = 0; + { + char *p1, *p2; + + p1 = (char *)file; + p2 = newfile; + while (p1[0]) + { + if (p1[0] == ':') + { + if (p1[1] == ':') + { + p2[0] = ':'; + p2++; + p1++; + } + else + { + p2[0] = 0; + return newfile; + } + } + else + { + p2[0] = p1[0]; + p2++; + } + p1++; + } + p2[0] = p1[0]; + } + return newfile; +} + +char * +__imlib_FileExtension(const char *file) +{ + char *p; + char *fl; + + fl = __imlib_FileRealFile(file); + if (!fl) + return strdup(""); + p = strrchr(file, '.'); + if (p) + { + char *ret; + + ret = strdup(p + 1); + free(fl); + return ret; + } + free(fl); + return strdup(""); +} + +int +__imlib_FileExists(const char *s) +{ + struct stat st; + char *fl; + + if ((!s) || (!*s)) + return 0; + if (__imlib_IsRealFile(s)) + fl = strdup(s); + else + fl = __imlib_FileRealFile(s); + if (!fl) + return 0; + if (stat(fl, &st) < 0) + { + free(fl); + return 0; + } + free(fl); + return 1; +} + +int +__imlib_FileIsFile(const char *s) +{ + struct stat st; + char *fl; + + if ((!s) || (!*s)) + return 0; + if (__imlib_IsRealFile(s)) + fl = strdup(s); + else + fl = __imlib_FileRealFile(s); + if (!fl) + return 0; + if (stat(fl, &st) < 0) + { + free(fl); + return 0; + } + if (S_ISREG(st.st_mode)) + { + free(fl); + return 1; + } + free(fl); + return 0; +} + +int +__imlib_FileIsDir(const char *s) +{ + struct stat st; + char *fl; + + if ((!s) || (!*s)) + return 0; + if (__imlib_IsRealFile(s)) + fl = strdup(s); + else + fl = __imlib_FileRealFile(s); + if (!fl) + return 0; + if (stat(fl, &st) < 0) + { + free(fl); + return 0; + } + if (S_ISDIR(st.st_mode)) + { + free(fl); + return 1; + } + free(fl); + return 0; +} + +int +__imlib_FilePermissions(const char *s) +{ + struct stat st; + char *fl; + + if ((!s) || (!*s)) + return 0; + if (__imlib_IsRealFile(s)) + fl = strdup(s); + else + fl = __imlib_FileRealFile(s); + if (!fl) + return 0; + if (stat(fl, &st) < 0) + { + free(fl); + return 0; + } + free(fl); + return st.st_mode; +} + +int +__imlib_FileCanRead(const char *s) +{ + char *fl; + int val; + + if (__imlib_IsRealFile(s)) + fl = strdup(s); + else + fl = __imlib_FileRealFile(s); + if (!fl) + return 0; + if (!(__imlib_FilePermissions(fl) & (S_IRUSR | S_IRGRP | S_IROTH))) + { + free(fl); + return 0; + } + + val = (1 + access(fl, R_OK)); + free(fl); + return val; +} + +char ** +__imlib_FileDir(char *dir, int *num) +{ + int i, dirlen; + int done = 0; + DIR *dirp; + char **names; + struct dirent *dp; + + if ((!dir) || (!*dir)) + return (0); + dirp = opendir(dir); + if (!dirp) + { + *num = 0; + return (NULL); + } + /* count # of entries in dir (worst case) */ + for (dirlen = 0; (dp = readdir(dirp)) != NULL; dirlen++); + if (!dirlen) + { + closedir(dirp); + *num = dirlen; + return (NULL); + } + names = (char **)malloc(dirlen * sizeof(char *)); + + if (!names) + return (NULL); + + rewinddir(dirp); + for (i = 0; i < dirlen;) + { + dp = readdir(dirp); + if (!dp) + break; + if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, ".."))) + { + names[i] = strdup(dp->d_name); + i++; + } + } + + if (i < dirlen) + dirlen = i; /* dir got shorter... */ + closedir(dirp); + *num = dirlen; + /* do a simple bubble sort here to alphanumberic it */ + while (!done) + { + done = 1; + for (i = 0; i < dirlen - 1; i++) + { + if (strcmp(names[i], names[i + 1]) > 0) + { + char *tmp; + + tmp = names[i]; + names[i] = names[i + 1]; + names[i + 1] = tmp; + done = 0; + } + } + } + return (names); +} + +void +__imlib_FileFreeDirList(char **l, int num) +{ + if (!l) + return; + while (num--) + if (l[num]) + free(l[num]); + free(l); + return; +} + +void +__imlib_FileDel(char *s) +{ + if ((!s) || (!*s)) + return; + unlink(s); + return; +} + +int +__imlib_IsRealFile(const char *s) +{ + struct stat st; + + return ((stat(s, &st) != -1) && (S_ISREG(st.st_mode))); +} + +time_t +__imlib_FileModDate(const char *s) +{ + struct stat st; + char *fl; + + if ((!s) || (!*s)) + return 0; + if (__imlib_IsRealFile(s)) + fl = strdup(s); + else + fl = __imlib_FileRealFile(s); + if (!fl) + return 0; + if (stat(fl, &st) < 0) + { + free(fl); + return 0; + } + if (st.st_mtime > st.st_ctime) + { + free(fl); + return st.st_mtime; + } + free(fl); + return st.st_ctime; +} + +char * +__imlib_FileHomeDir(int uid) +{ + static int usr_uid = -1; + static char *usr_s = NULL; + char *s; + struct passwd *pwd; + +#ifndef __EMX__ + s = getenv("HOME"); + if (s) + return strdup(s); + if (usr_uid < 0) + usr_uid = getuid(); + if ((uid == usr_uid) && (usr_s)) + { + return (strdup(usr_s)); + } + pwd = getpwuid(uid); + if (pwd) + { + s = strdup(pwd->pw_dir); + if (uid == usr_uid) + usr_s = strdup(s); + return (s); + } +#else + if ((s = getenv("HOME")) != NULL) + return strdup(s); + else if ((s = getenv("TMP")) != NULL) + return strdup(s); +#endif + return NULL; +} + +/* gets word number [num] in the string [s] and copies it into [wd] */ +/* wd is NULL terminated. If word [num] does not exist wd = "" */ +/* NB: this function now handles quotes so for a line: */ +/* Hello to "Welcome sir - may I Help" Shub Foo */ +/* Word 1 = Hello */ +/* Word 2 = to */ +/* Word 3 = Welcome sir - may I Help */ +/* Word 4 = Shub */ +/* word 5 = Foo */ + +char * +__imlib_FileField(char *s, int field) +{ + char buf[4096]; + + buf[0] = 0; + __imlib_FileFieldWord(s, field + 1, buf); + if (buf[0]) + { + if ((!strcmp(buf, "NULL")) || (!strcmp(buf, "(null)"))) + return (NULL); + return (strdup(buf)); + } + return (NULL); +} + +static void +__imlib_FileFieldWord(char *s, int num, char *wd) +{ + char *cur, *start, *end; + int count, inword, inquote, len; + + if (!s) + return; + if (!wd) + return; + *wd = 0; + if (num <= 0) + return; + cur = s; + count = 0; + inword = 0; + inquote = 0; + start = NULL; + end = NULL; + while ((*cur) && (count < num)) + { + if (inword) + { + if (inquote) + { + if (*cur == '"') + { + inquote = 0; + inword = 0; + end = cur; + count++; + } + } + else + { + if (isspace(*cur)) + { + end = cur; + inword = 0; + count++; + } + } + } + else + { + if (!isspace(*cur)) + { + if (*cur == '"') + { + inquote = 1; + start = cur + 1; + } + else + start = cur; + inword = 1; + } + } + if (count == num) + break; + cur++; + } + if (!start) + return; + if (!end) + end = cur; + if (end <= start) + return; + len = (int)(end - start); + if (len > 4000) + len = 4000; + if (len > 0) + { + strncpy(wd, start, len); + wd[len] = 0; + } + return; +} diff --git a/src/lib/file.h b/src/lib/file.h new file mode 100644 index 0000000..5544175 --- /dev/null +++ b/src/lib/file.h @@ -0,0 +1,20 @@ +#ifndef __FILE +#define __FILE 1 +char *__imlib_FileKey(const char *file); +char *__imlib_FileRealFile(const char *file); +char *__imlib_FileExtension(const char *file); +int __imlib_FileExists(const char *s); +int __imlib_FileIsFile(const char *s); +int __imlib_FileIsDir(const char *s); +char **__imlib_FileDir(char *dir, int *num); +void __imlib_FileFreeDirList(char **l, int num); +void __imlib_FileDel(char *s); +time_t __imlib_FileModDate(const char *s); +char *__imlib_FileHomeDir(int uid); +char *__imlib_FileField(char *s, int field); +int __imlib_FilePermissions(const char *s); +int __imlib_FileCanRead(const char *s); +int __imlib_IsRealFile(const char *s); + + +#endif diff --git a/src/lib/filter.c b/src/lib/filter.c new file mode 100644 index 0000000..6436dee --- /dev/null +++ b/src/lib/filter.c @@ -0,0 +1,241 @@ +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include "filter.h" + +/*\ Create and return an empty filter struct \*/ +ImlibFilter * +__imlib_CreateFilter(int size) +{ + ImlibFilter *fil; + + fil = malloc(sizeof(ImlibFilter)); + if (size > 0) + { + fil->alpha.pixels = malloc(size * sizeof(ImlibFilterPixel)); + fil->red.pixels = malloc(size * sizeof(ImlibFilterPixel)); + fil->green.pixels = malloc(size * sizeof(ImlibFilterPixel)); + fil->blue.pixels = malloc(size * sizeof(ImlibFilterPixel)); + fil->alpha.size = size; + fil->red.size = size; + fil->green.size = size; + fil->blue.size = size; + } + else + { + fil->alpha.pixels = 0; + fil->red.pixels = 0; + fil->green.pixels = 0; + fil->blue.pixels = 0; + fil->alpha.size = 0; + fil->red.size = 0; + fil->green.size = 0; + fil->blue.size = 0; + } + fil->alpha.entries = 0; + fil->red.entries = 0; + fil->green.entries = 0; + fil->blue.entries = 0; + fil->alpha.div = 0; + fil->red.div = 0; + fil->green.div = 0; + fil->blue.div = 0; + fil->alpha.cons = 0; + fil->red.cons = 0; + fil->green.cons = 0; + fil->blue.cons = 0; + return fil; +} + +/*\ Free a filter struct \*/ +void +__imlib_FreeFilter(ImlibFilter * fil) +{ + free(fil->alpha.pixels); + free(fil->red.pixels); + free(fil->green.pixels); + free(fil->blue.pixels); + free(fil); +} + +void +__imlib_FilterSetColor(ImlibFilterColor * fil, int x, int y, + int a, int r, int g, int b) +{ + int i; + ImlibFilterPixel *pix = fil->pixels; + + /*\ Look for an entry matching (x, y) \ */ + for (i = fil->entries; --i >= 0;) + { + if ((pix[i].xoff == x) && (pix[i].yoff == y)) + break; + } + /*\ If all zero, remove the found entry \ */ + if (!(a | r | g | b)) + { + if (i >= 0) + { + while (i < fil->entries) + { + pix[i] = pix[i + 1]; + } + fil->entries--; + } + return; + } + /*\ No match, then make a new entry \ */ + if (i < 0) + i = fil->entries; + if (i >= fil->size) + { + fil->size += 4; + pix = realloc(pix, (fil->size * sizeof(ImlibFilterPixel))); + if (!pix) + return; + fil->pixels = pix; + } + if (i >= fil->entries) + fil->entries = i + 1; + pix[i].xoff = x; + pix[i].yoff = y; + pix[i].a = a; + pix[i].r = r; + pix[i].g = g; + pix[i].b = b; +} + +/*\ Set the divisors manually \*/ +void +__imlib_FilterDivisors(ImlibFilter * fil, int a, int r, int g, int b) +{ + fil->alpha.div = a; + fil->red.div = r; + fil->green.div = g; + fil->blue.div = b; +} + +/*\ Set the constants \*/ +void +__imlib_FilterConstants(ImlibFilter * fil, int a, int r, int g, int b) +{ + fil->alpha.cons = a; + fil->red.cons = r; + fil->green.cons = g; + fil->blue.cons = b; +} + +static int +__imlib_FilterCalcDiv(ImlibFilterColor * fil) +{ + int i, ret; + ImlibFilterPixel *pix; + + if (fil->div) + return fil->div; + ret = 0; + pix = fil->pixels; + for (i = fil->entries; --i >= 0;) + { + ret += pix->a + pix->r + pix->g + pix->b; + pix++; + } + return ret; +} + +static int +__imlib_FilterGet(ImlibFilterColor * fil, DATA32 * data, + int w, int h, int x, int y) +{ + int i, off, ret; + ImlibFilterPixel *pix; + DATA32 *p; + + ret = fil->cons; + pix = fil->pixels; + for (i = fil->entries; --i >= 0;) + { + off = x + pix->xoff; + if (off < 0) + off = 0; + if (off >= w) + off = w - 1; + p = data + off; + off = y + pix->yoff; + if (off < 0) + off = 0; + if (off >= h) + off = h - 1; + p += off * w; + ret += A_VAL(p) * pix->a + R_VAL(p) * pix->r + + G_VAL(p) * pix->g + B_VAL(p) * pix->b; + pix++; + } + return ret; +} + +/*\ Correct saturation from [-32768, 32767] to [0, 255] \*/ +#define SATURATE(x) ((((x) | (!((x) >> 8) - 1)) & (~((x) >> 31))) & 0xff) + +/*\ Filter an image with the a, r, g, b filters in fil +|*| NB: This is currently not very optimal, and could probably be improved +\*/ +void +__imlib_FilterImage(ImlibImage * im, ImlibFilter * fil) +{ + int x, y, a, r, g, b, ad, rd, gd, bd; + DATA32 *data, *p1, *p2; + + data = malloc(im->w * im->h * sizeof(DATA32)); + if (!data) + return; + + ad = __imlib_FilterCalcDiv(&fil->alpha); + rd = __imlib_FilterCalcDiv(&fil->red); + gd = __imlib_FilterCalcDiv(&fil->green); + bd = __imlib_FilterCalcDiv(&fil->blue); + + p1 = im->data; + p2 = data; + + for (y = 0; y < im->h; y++) + { + for (x = 0; x < im->w; x++) + { + *p2 = *p1; + if (ad) + { + a = __imlib_FilterGet(&fil->alpha, im->data, im->w, im->h, x, + y); + a /= ad; + A_VAL(p2) = SATURATE(a); + } + if (rd) + { + r = __imlib_FilterGet(&fil->red, im->data, im->w, im->h, x, + y); + r /= rd; + R_VAL(p2) = SATURATE(r); + } + if (gd) + { + g = __imlib_FilterGet(&fil->green, im->data, im->w, im->h, x, + y); + g /= gd; + G_VAL(p2) = SATURATE(g); + } + if (bd) + { + b = __imlib_FilterGet(&fil->blue, im->data, im->w, im->h, x, + y); + b /= bd; + B_VAL(p2) = SATURATE(b); + } + p1++; + p2++; + } + } + free(im->data); + im->data = data; +} diff --git a/src/lib/filter.h b/src/lib/filter.h new file mode 100644 index 0000000..0c504b0 --- /dev/null +++ b/src/lib/filter.h @@ -0,0 +1,42 @@ +#ifndef __FILTER +#define __FILTER 1 + +typedef struct _imlib_filter ImlibFilter; +typedef struct _imlib_filter_color ImlibFilterColor; +typedef struct _imlib_filter_pixel ImlibFilterPixel; + +struct _imlib_filter_pixel +{ + int xoff, yoff; + int a, r, g, b; +}; + +struct _imlib_filter_color +{ + int size, entries; + int div, cons; + ImlibFilterPixel *pixels; +}; + +struct _imlib_filter +{ + ImlibFilterColor alpha, red, green, blue; +}; + +ImlibFilter * +__imlib_CreateFilter(int size); +void +__imlib_FreeFilter(ImlibFilter *fil); +void +__imlib_FilterSet(ImlibFilterColor *fil, int x, int y, + int a, int r, int g, int b); +void +__imlib_FilterSetColor(ImlibFilterColor * fil, int x, int y, + int a, int r, int g, int b); +void +__imlib_FilterDivisors(ImlibFilter *fil, int a, int r, int g, int b); +void +__imlib_FilterConstants(ImlibFilter *fil, int a, int r, int g, int b); +void +__imlib_FilterImage(ImlibImage *im, ImlibFilter *fil); +#endif diff --git a/src/lib/font.h b/src/lib/font.h new file mode 100644 index 0000000..526acb3 --- /dev/null +++ b/src/lib/font.h @@ -0,0 +1,126 @@ + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +/* TODO separate fonts and data stuff */ + +typedef struct _Imlib_Font ImlibFont; +typedef struct _Imlib_Font_Glyph Imlib_Font_Glyph; + +typedef struct _Imlib_Object_List Imlib_Object_List; +typedef struct _Imlib_Hash Imlib_Hash; +typedef struct _Imlib_Hash_El Imlib_Hash_El; + +struct _Imlib_Object_List +{ + Imlib_Object_List *next, *prev; + Imlib_Object_List *last; +}; + +struct _Imlib_Hash +{ + int population; + Imlib_Object_List *buckets[256]; +}; + +struct _Imlib_Hash_El +{ + Imlib_Object_List _list_data; + char *key; + void *data; +}; + +struct _Imlib_Font +{ + Imlib_Object_List _list_data; + char *name; + char *file; + int size; + + struct + { + FT_Face face; + } + ft; + + Imlib_Hash *glyphs; + + int usage; + + int references; + +}; + +struct _Imlib_Font_Glyph +{ + FT_Glyph glyph; + FT_BitmapGlyph glyph_out; +}; + +/* functions */ + +void imlib_font_init(void); +int imlib_font_ascent_get(ImlibFont * fn); +int imlib_font_descent_get(ImlibFont * fn); +int imlib_font_max_ascent_get(ImlibFont * fn); +int imlib_font_max_descent_get(ImlibFont * fn); +int imlib_font_get_line_advance(ImlibFont * fn); +int imlib_font_utf8_get_next(unsigned char *buf, int *iindex); +void imlib_font_add_font_path(const char *path); +void imlib_font_del_font_path(const char *path); +int imlib_font_path_exists(const char *path); +char **imlib_font_list_font_path(int *num_ret); +char **imlib_font_list_fonts(int *num_ret); + +ImlibFont *imlib_font_load_joined(const char *name); +ImlibFont *imlib_font_load(const char *name, int size); +void imlib_font_free(ImlibFont * fn); +int imlib_font_cache_get(void); +void imlib_font_cache_set(int size); +void imlib_font_flush(void); +void imlib_font_modify_cache_by(ImlibFont * fn, int dir); +void imlib_font_modify_cache_by(ImlibFont * fn, int dir); +void imlib_font_flush_last(void); +ImlibFont *imlib_font_find(const char *name, int size); + +void imlib_font_query_size(ImlibFont * fn, const char *text, + int *w, int *h); +int imlib_font_query_inset(ImlibFont * fn, const char *text); +void imlib_font_query_advance(ImlibFont * fn, const char *text, + int *h_adv, int *v_adv); +int imlib_font_query_char_coords(ImlibFont * fn, + const char *text, int pos, + int *cx, int *cy, int *cw, + int *ch); +int imlib_font_query_text_at_pos(ImlibFont * fn, + const char *text, int x, int y, + int *cx, int *cy, int *cw, + int *ch); + +Imlib_Font_Glyph *imlib_font_cache_glyph_get(ImlibFont * fn, FT_UInt index); +void imlib_render_str(ImlibImage * im, ImlibFont * f, int drx, + int dry, const char *text, DATA8 r, + DATA8 g, DATA8 b, DATA8 a, char dir, + double angle, int *retw, int *reth, + int blur, int *nextx, int *nexty, + ImlibOp op, int clx, int cly, int clw, + int clh); +void imlib_font_draw(ImlibImage * dst, DATA32 col, + ImlibFont * fn, int x, int y, + const char *text, int *nextx, int *nexty, + int clx, int cly, int clw, int clh); + +/* data manipulation */ + +void *imlib_object_list_prepend(void *in_list, void *in_item); +void *imlib_object_list_remove(void *in_list, void *in_item); +Imlib_Hash *imlib_hash_add(Imlib_Hash * hash, const char *key, + const void *data); +void *imlib_hash_find(Imlib_Hash * hash, const char *key); +void imlib_hash_free(Imlib_Hash * hash); +void imlib_hash_foreach(Imlib_Hash * hash, + int (*func) (Imlib_Hash * hash, + const char *key, void *data, + void *fdata), + const void *fdata); diff --git a/src/lib/font_draw.c b/src/lib/font_draw.c new file mode 100644 index 0000000..69985ff --- /dev/null +++ b/src/lib/font_draw.c @@ -0,0 +1,421 @@ +#include "config.h" +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include "font.h" +#include +#include +#include +#include "file.h" +#include "updates.h" +#include "rgbadraw.h" +#include "rotate.h" + +extern FT_Library ft_lib; + +Imlib_Font_Glyph * +imlib_font_cache_glyph_get(ImlibFont * fn, FT_UInt index) +{ + Imlib_Font_Glyph *fg; + char key[6]; + FT_Error error; + + key[0] = ((index) & 0x7f) + 1; + key[1] = ((index >> 7) & 0x7f) + 1; + key[2] = ((index >> 14) & 0x7f) + 1; + key[3] = ((index >> 21) & 0x7f) + 1; + key[4] = ((index >> 28) & 0x0f) + 1; + key[5] = 0; + + fg = imlib_hash_find(fn->glyphs, key); + if (fg) + return fg; + + error = FT_Load_Glyph(fn->ft.face, index, FT_LOAD_NO_BITMAP); + if (error) + return NULL; + + fg = malloc(sizeof(struct _Imlib_Font_Glyph)); + if (!fg) + return NULL; + memset(fg, 0, (sizeof(struct _Imlib_Font_Glyph))); + + error = FT_Get_Glyph(fn->ft.face->glyph, &(fg->glyph)); + if (error) + { + free(fg); + return NULL; + } + if (fg->glyph->format != ft_glyph_format_bitmap) + { + error = FT_Glyph_To_Bitmap(&(fg->glyph), ft_render_mode_normal, 0, 1); + if (error) + { + FT_Done_Glyph(fg->glyph); + free(fg); + return NULL; + } + } + fg->glyph_out = (FT_BitmapGlyph) fg->glyph; + + fn->glyphs = imlib_hash_add(fn->glyphs, key, fg); + return fg; +} + +void +imlib_render_str(ImlibImage * im, ImlibFont * fn, int drx, int dry, + const char *text, DATA8 r, DATA8 g, DATA8 b, DATA8 a, + char dir, double angle, int *retw, int *reth, int blur, + int *nextx, int *nexty, ImlibOp op, int clx, int cly, + int clw, int clh) +{ + int w, h, ascent; + ImlibImage *im2; + DATA32 *data, col; + int nx, ny, tmp; + + imlib_font_query_advance(fn, text, &w, &h); + + data = malloc(w * h * sizeof(DATA32)); + if (!data) + return; + memset(data, 0, w * h * sizeof(DATA32)); + /* TODO check if this is the right way of rendering. Esp for huge sizes */ + im2 = __imlib_CreateImage(w, h, data); + if (!im2) + { + free(data); + return; + } + SET_FLAG(im2->flags, F_HAS_ALPHA); + + /* TODO check for endianess */ + col = (a << 24) | (r << 16) | (g << 8) | b; + + ascent = imlib_font_max_ascent_get(fn); + + imlib_font_draw(im2, col, fn, 0, ascent, text, &nx, &ny, clx, cly, clw, clh); + + /* OK, now we have small ImlibImage with text rendered, + * have to blend it on im */ + + if (blur > 0) + __imlib_BlurImage(im2, blur); + + switch (dir) + { + case 0: /* to right */ + angle = 0.0; + break; + case 1: /* to left */ + angle = 0.0; + __imlib_FlipImageBoth(im2); + break; + case 2: /* to down */ + angle = 0.0; + __imlib_FlipImageDiagonal(im2, 1); + break; + case 3: /* to up */ + angle = 0.0; + __imlib_FlipImageDiagonal(im2, 2); + break; + default: + break; + } + if (angle == 0.0) + { + __imlib_BlendImageToImage(im2, im, 0, 1, IMAGE_HAS_ALPHA(im), 0, 0, + im2->w, im2->h, drx, dry, im2->w, im2->h, + NULL, op, clx, cly, clw, clh); + } + else + { + int xx, yy; + double sa, ca; + + sa = sin(angle); + ca = cos(angle); + xx = drx; + yy = dry; + if (sa > 0.0) + xx += sa * im2->h; + else + yy -= sa * im2->w; + if (ca < 0.0) + { + xx -= ca * im2->w; + yy -= ca * im2->h; + } + __imlib_BlendImageToImageSkewed(im2, im, 1, 1, IMAGE_HAS_ALPHA(im), 0, + 0, im2->w, im2->h, xx, yy, (w * ca), + (w * sa), 0, 0, NULL, op, clx, cly, clw, + clh); + } + + __imlib_FreeImage(im2); + + /* finally deal with return values */ + switch (dir) + { + case 0: + case 1: + if (retw) + *retw = w; + if (reth) + *reth = h; + if (nextx) + *nextx = nx; + if (nexty) + *nexty = ny; + break; + case 2: + case 3: + if (retw) + *retw = h; + if (reth) + *reth = w; + if (nextx) + *nextx = ny; + if (nexty) + *nexty = nx; + break; + case 4: + { + double sa, ca; + double x1, x2, xt; + double y1, y2, yt; + + sa = sin(angle); + ca = cos(angle); + + x1 = x2 = 0.0; + xt = ca * w; + if (xt < x1) + x1 = xt; + if (xt > x2) + x2 = xt; + xt = -(sa * h); + if (xt < x1) + x1 = xt; + if (xt > x2) + x2 = xt; + xt = ca * w - sa * h; + if (xt < x1) + x1 = xt; + if (xt > x2) + x2 = xt; + w = (int)(x2 - x1); + + y1 = y2 = 0.0; + yt = sa * w; + if (yt < y1) + y1 = yt; + if (yt > y2) + y2 = yt; + yt = ca * h; + if (yt < y1) + y1 = yt; + if (yt > y2) + y2 = yt; + yt = sa * w + ca * h; + if (yt < y1) + y1 = yt; + if (yt > y2) + y2 = yt; + h = (int)(y2 - y1); + } + if (retw) + *retw = w; + if (reth) + *reth = h; + if (nextx) + *nextx = nx; + if (nexty) + *nexty = ny; + break; + default: + break; + } + + /* TODO this function is purely my art -- check once more */ +} + +void +imlib_font_draw(ImlibImage * dst, DATA32 col, ImlibFont * fn, int x, int y, + const char *text, int *nextx, int *nexty, int clx, int cly, + int clw, int clh) +{ + int use_kerning; + int pen_x, pen_y; + int chr; + FT_UInt prev_index; + int ext_x, ext_y, ext_w, ext_h; + DATA32 *im; + int im_w, im_h; + int lut[256]; + int ii; + + im = dst->data; + im_w = dst->w; + im_h = dst->h; + + ext_x = 0; + ext_y = 0; + ext_w = im_w; + ext_h = im_h; + + if (clw) + { + ext_x = clx; + ext_y = cly; + ext_w = clw; + ext_h = clh; + } + if (ext_x < 0) + { + ext_w += ext_x; + ext_x = 0; + } + if (ext_y < 0) + { + ext_h += ext_y; + ext_y = 0; + } + if ((ext_x + ext_w) > im_w) + ext_w = im_w - ext_x; + if ((ext_y + ext_h) > im_h) + ext_h = im_h - ext_y; + + if (ext_w <= 0) + return; + if (ext_h <= 0) + return; + + for (ii = 0; ii < 256; ii++) + { + lut[ii] = (col & 0x00ffffff); /* TODO check endianess */ + lut[ii] |= ((((ii + 1) * (col >> 24)) >> 8) << 24); + } + + pen_x = x << 8; + pen_y = y << 8; + use_kerning = FT_HAS_KERNING(fn->ft.face); + prev_index = 0; + for (chr = 0; text[chr];) + { + FT_UInt index; + Imlib_Font_Glyph *fg; + int chr_x, chr_y; + int gl; + + gl = imlib_font_utf8_get_next((unsigned char *)text, &chr); + if (gl == 0) + break; + index = FT_Get_Char_Index(fn->ft.face, gl); + if ((use_kerning) && (prev_index) && (index)) + { + FT_Vector delta; + + FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default, + &delta); + pen_x += delta.x << 2; + } + fg = imlib_font_cache_glyph_get(fn, index); + if (!fg) + continue; + + chr_x = (pen_x + (fg->glyph_out->left << 8)) >> 8; + chr_y = (pen_y + (fg->glyph_out->top << 8)) >> 8; + + if (chr_x < (ext_x + ext_w)) + { + DATA8 *data; + int i, j, w, h; + + data = fg->glyph_out->bitmap.buffer; + j = fg->glyph_out->bitmap.pitch; + w = fg->glyph_out->bitmap.width; + if (j < w) + j = w; + h = fg->glyph_out->bitmap.rows; + if ((fg->glyph_out->bitmap.pixel_mode == ft_pixel_mode_grays) + && (fg->glyph_out->bitmap.num_grays == 256)) + { + if ((j > 0) && (chr_x + w > ext_x)) + { + for (i = 0; i < h; i++) + { + int dx, dy; + int in_x, in_w; + + in_x = 0; + in_w = 0; + dx = chr_x; + dy = y - (chr_y - i - y); + if ((dx < (ext_x + ext_w)) && (dy >= (ext_y)) + && (dy < (ext_y + ext_h))) + { + if (dx + w > (ext_x + ext_w)) + in_w += (dx + w) - (ext_x + ext_w); + if (dx < ext_x) + { + in_w += ext_x - dx; + in_x = ext_x - dx; + dx = ext_x; + } + if (in_w < w) + { + DATA8 *src_ptr; + DATA32 *dst_ptr; + DATA32 *dst_end_ptr; + + src_ptr = data + (i * j) + in_x; + dst_ptr = im + (dy * im_w) + dx; + dst_end_ptr = dst_ptr + w - in_w; + + while (dst_ptr < dst_end_ptr) + { + /* FIXME Oops! change this op */ + if (!*dst_ptr) + *dst_ptr = + lut[(unsigned char)*src_ptr]; + else if (*src_ptr) + { + /* very rare case - I've never seen symbols + * overlapped by kerning */ + int tmp; + + tmp = + (*dst_ptr >> 24) + + (lut + [(unsigned char)*src_ptr] + >> 24); + tmp = (tmp > 256) ? 256 : tmp; + *dst_ptr &= 0x00ffffff; + *dst_ptr |= (tmp << 24); + } + + dst_ptr++; + src_ptr++; + } + } + } + } + } + } + } + else + break; + pen_x += fg->glyph->advance.x >> 8; + prev_index = index; + } + + if (nextx) + *nextx = (pen_x >> 8) - x; + if (nexty) + *nexty = imlib_font_get_line_advance(fn); +} diff --git a/src/lib/font_load.c b/src/lib/font_load.c new file mode 100644 index 0000000..c86f3c3 --- /dev/null +++ b/src/lib/font_load.c @@ -0,0 +1,431 @@ +#include "config.h" +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include "font.h" +#include +#include +#include +#include "file.h" +#include "updates.h" +#include "rgbadraw.h" +#include "rotate.h" + +extern FT_Library ft_lib; + +static int font_cache_usage = 0; +static int font_cache = 0; +static char **fpath = NULL; +static int fpath_num = 0; +static Imlib_Object_List *fonts = NULL; + +static int font_modify_cache_cb(Imlib_Hash * hash, const char *key, + void *data, void *fdata); +static int font_flush_free_glyph_cb(Imlib_Hash * hash, const char *key, + void *data, void *fdata); + +/* FIXME now! listdir() from evas_object_text.c */ + +/* separate fontname and size, find font file, start imlib_font_load() then */ +ImlibFont * +imlib_font_load_joined(const char *fontname) +{ + int j, size; + char *name = NULL, *file = NULL, *tmp = NULL; + ImlibFont *fn; + + /* split font name (in format name/size) */ + for (j = strlen(fontname) - 1; (j >= 0) && (fontname[j] != '/'); j--); + /* no "/" in font after the first char */ + if (j <= 0) + return NULL; + /* get size */ + size = atoi(&(fontname[j + 1])); + /* split name in front off */ + name = malloc((j + 1) * sizeof(char)); + memcpy(name, fontname, j); + name[j] = 0; + /* find file if it exists */ + tmp = malloc(strlen(name) + 4 + 1); + if (!tmp) + { + free(name); + return NULL; + } + sprintf(tmp, "%s.ttf", name); + if (__imlib_FileIsFile(tmp)) + file = strdup(tmp); + else + { + sprintf(tmp, "%s.TTF", name); + if (__imlib_FileIsFile(tmp)) + file = strdup(tmp); + else + { + sprintf(tmp, "%s", name); + if (__imlib_FileIsFile(tmp)) + file = strdup(tmp); + } + } + free(tmp); + if (!file) + { + for (j = 0; (j < fpath_num) && (!file); j++) + { + tmp = malloc(strlen(fpath[j]) + 1 + strlen(name) + 4 + 1); + if (!tmp) + { + free(name); + return NULL; + } + else + { + sprintf(tmp, "%s/%s.ttf", fpath[j], name); + if (__imlib_FileIsFile(tmp)) + file = strdup(tmp); + else + { + sprintf(tmp, "%s/%s.TTF", fpath[j], name); + if (__imlib_FileIsFile(tmp)) + file = strdup(tmp); + else + { + sprintf(tmp, "%s/%s", fpath[j], name); + if (__imlib_FileIsFile(tmp)) + file = strdup(tmp); + } + } + } + free(tmp); + } + } + free(name); + /* didnt find a file? abort */ + if (!file) + return NULL; + fn = imlib_font_load(file, size); + free(file); + return fn; +} + +ImlibFont * +imlib_font_load(const char *name, int size) +{ + int error; + ImlibFont *fn; + char *file; + + fn = imlib_font_find(name, size); + if (fn) + return fn; + + imlib_font_init(); + + fn = malloc(sizeof(ImlibFont)); + file = (char *)name; + + error = FT_New_Face(ft_lib, file, 0, &(fn->ft.face)); + if (error) + { + free(fn); + return NULL; + } + error = FT_Set_Char_Size(fn->ft.face, 0, (size * 64), 96, 96); + if (error) + error = FT_Set_Pixel_Sizes(fn->ft.face, 0, size); + if (error) + { + int i; + int chosen_size = 0; + int chosen_width = 0; + + for (i = 0; i < fn->ft.face->num_fixed_sizes; i++) + { + int s; + int d, cd; + + s = fn->ft.face->available_sizes[i].height; + cd = chosen_size - size; + if (cd < 0) + cd = -cd; + d = s - size; + if (d < 0) + d = -d; + if (d < cd) + { + chosen_width = fn->ft.face->available_sizes[i].width; + chosen_size = s; + } + if (d == 0) + break; + } + error = FT_Set_Pixel_Sizes(fn->ft.face, chosen_width, chosen_size); + if (error) + { + /* couldn't choose the size anyway... what now? */ + } + } + + error = FT_Select_Charmap(fn->ft.face, ft_encoding_unicode); + if (error) + { + } + + fn->file = strdup(file); + fn->name = strdup(file); + fn->size = size; + + fn->glyphs = NULL; + + fn->usage = 0; + + fn->references = 1; + + fonts = imlib_object_list_prepend(fonts, fn); + return fn; +} + +void +imlib_font_free(ImlibFont * fn) +{ + fn->references--; + if (fn->references == 0) + { + imlib_font_modify_cache_by(fn, 1); + imlib_font_flush(); + } +} + +static int +font_modify_cache_cb(Imlib_Hash * hash, const char *key, void *data, + void *fdata) +{ + int *dir; + Imlib_Font_Glyph *fg; + + fg = data; + dir = fdata; + font_cache_usage += (*dir) * ((fg->glyph_out->bitmap.width * fg->glyph_out->bitmap.rows) + sizeof(Imlib_Font_Glyph) + sizeof(Imlib_Object_List) + 400); /* fudge values */ + return 1; + hash = 0; + key = 0; +} + +void +imlib_font_modify_cache_by(ImlibFont * fn, int dir) +{ + int sz_name = 0, sz_file = 0, sz_hash = 0; + + if (fn->name) + sz_name = strlen(fn->name); + if (fn->file) + sz_file = strlen(fn->file); + if (fn->glyphs) + sz_hash = sizeof(Imlib_Hash); + imlib_hash_foreach(fn->glyphs, font_modify_cache_cb, &dir); + font_cache_usage += dir * (sizeof(ImlibFont) + sz_name + sz_file + sz_hash + sizeof(FT_FaceRec) + 16384); /* fudge values */ +} + +int +imlib_font_cache_get(void) +{ + return font_cache; +} + +void +imlib_font_cache_set(int size) +{ + font_cache = size; + imlib_font_flush(); +} + +void +imlib_font_flush(void) +{ + if (font_cache_usage < font_cache) + return; + while (font_cache_usage > font_cache) + imlib_font_flush_last(); +} + +static int +font_flush_free_glyph_cb(Imlib_Hash * hash, const char *key, void *data, + void *fdata) +{ + Imlib_Font_Glyph *fg; + + fg = data; + FT_Done_Glyph(fg->glyph); + free(fg); + return 1; + hash = 0; + key = 0; + fdata = 0; +} + +void +imlib_font_flush_last(void) +{ + Imlib_Object_List *l; + ImlibFont *fn = NULL; + + for (l = fonts; l; l = l->next) + { + ImlibFont *fn_tmp; + + fn_tmp = (ImlibFont *) l; + if (fn_tmp->references == 0) + fn = fn_tmp; + } + if (!fn) + return; + + fonts = imlib_object_list_remove(fonts, fn); + imlib_font_modify_cache_by(fn, -1); + + imlib_hash_foreach(fn->glyphs, font_flush_free_glyph_cb, NULL); + imlib_hash_free(fn->glyphs); + + if (fn->file) + free(fn->file); + if (fn->name) + free(fn->name); + FT_Done_Face(fn->ft.face); + free(fn); +} + +ImlibFont * +imlib_font_find(const char *name, int size) +{ + Imlib_Object_List *l; + + for (l = fonts; l; l = l->next) + { + ImlibFont *fn; + + fn = (ImlibFont *) l; + if ((fn->size == size) && (!strcmp(name, fn->name))) + { + if (fn->references == 0) + imlib_font_modify_cache_by(fn, -1); + fn->references++; + fonts = imlib_object_list_remove(fonts, fn); + fonts = imlib_object_list_prepend(fonts, fn); + return fn; + } + } + return NULL; +} + +/* font pathes */ +void +imlib_font_add_font_path(const char *path) +{ + fpath_num++; + if (!fpath) + fpath = malloc(sizeof(char *)); + else + fpath = realloc(fpath, (fpath_num * sizeof(char *))); + fpath[fpath_num - 1] = strdup(path); +} + +void +imlib_font_del_font_path(const char *path) +{ + int i, j; + + for (i = 0; i < fpath_num; i++) + { + if (!strcmp(path, fpath[i])) + { + if (fpath[i]) + free(fpath[i]); + fpath_num--; + for (j = i; j < fpath_num; j++) + fpath[j] = fpath[j + 1]; + if (fpath_num > 0) + fpath = realloc(fpath, fpath_num * sizeof(char *)); + else + { + free(fpath); + fpath = NULL; + } + } + } +} + +int +imlib_font_path_exists(const char *path) +{ + int i; + + for (i = 0; i < fpath_num; i++) + { + if (!strcmp(path, fpath[i])) + return 1; + } + return 0; +} + +char ** +imlib_font_list_font_path(int *num_ret) +{ + *num_ret = fpath_num; + return fpath; +} + +/* fonts list */ +char ** +imlib_font_list_fonts(int *num_ret) +{ + int i, j, d, l = 0; + char **list = NULL, **dir, *path; + FT_Error error; + char *p; + + imlib_font_init(); + + for (i = 0; i < fpath_num; i++) + { + dir = __imlib_FileDir(fpath[i], &d); + if (dir) + { + for (j = 0; j < d; j++) + { + path = malloc(strlen(fpath[i]) + strlen(dir[j]) + 2); + sprintf(path, "%s/%s", fpath[i], dir[j]); + /* trim .ttf if it is there */ + if ((p = strrchr(dir[j], '.'))) + *p = '\0'; + if (!__imlib_ItemInList(list, l, dir[j])) + { + if (__imlib_FileIsFile(path)) + { + FT_Face f; + + error = FT_New_Face(ft_lib, path, 0, &f); + if (!error) + { + FT_Done_Face(f); + l++; + if (list) + list = realloc(list, sizeof(char *) * l); + else + list = malloc(sizeof(char *)); + list[l - 1] = strdup(dir[j]); + } + free(dir[j]); + } + } + free(path); + } + free(dir); + } + } + *num_ret = l; + return list; +} diff --git a/src/lib/font_main.c b/src/lib/font_main.c new file mode 100644 index 0000000..e266cc6 --- /dev/null +++ b/src/lib/font_main.c @@ -0,0 +1,418 @@ +#include "config.h" +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include "font.h" +#include +#include +#include +#include "file.h" +#include "updates.h" +#include "rgbadraw.h" +#include "rotate.h" + +FT_Library ft_lib; + +static int imlib_hash_gen(const char *key); +static int imlib_list_alloc_error(void); + +static int _imlib_hash_alloc_error = 0; +static int _imlib_list_alloc_error = 0; + +void +imlib_font_init(void) +{ + static int initialised = 0; + int error; + + if (initialised) + return; + error = FT_Init_FreeType(&ft_lib); + if (error) + return; + initialised = 1; +} + +int +imlib_font_ascent_get(ImlibFont * fn) +{ + int val; + int ret; + + val = (int)fn->ft.face->ascender; + fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct + * val */ + ret = + (val * fn->ft.face->size->metrics.y_scale) / + (fn->ft.face->units_per_EM * fn->ft.face->units_per_EM); + return ret; +} + +int +imlib_font_descent_get(ImlibFont * fn) +{ + int val; + int ret; + + val = -(int)fn->ft.face->descender; + fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct + * val */ + ret = + (val * fn->ft.face->size->metrics.y_scale) / + (fn->ft.face->units_per_EM * fn->ft.face->units_per_EM); + return ret; +} + +int +imlib_font_max_ascent_get(ImlibFont * fn) +{ + int val; + int ret; + + val = (int)fn->ft.face->bbox.yMax; + fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct + * val */ + ret = + (val * fn->ft.face->size->metrics.y_scale) / + (fn->ft.face->units_per_EM * fn->ft.face->units_per_EM); + return ret; +} + +int +imlib_font_max_descent_get(ImlibFont * fn) +{ + int val; + int ret; + + val = (int)fn->ft.face->bbox.yMin; + fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct + * val */ + ret = + (val * fn->ft.face->size->metrics.y_scale) / + (fn->ft.face->units_per_EM * fn->ft.face->units_per_EM); + return ret; +} + +int +imlib_font_get_line_advance(ImlibFont * fn) +{ + int val; + int ret; + + val = (int)fn->ft.face->height; + fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct + * val */ + ret = + (val * fn->ft.face->size->metrics.y_scale) / + (fn->ft.face->units_per_EM * fn->ft.face->units_per_EM); + return ret; +} + +int +imlib_font_utf8_get_next(unsigned char *buf, int *iindex) +{ + /* Reads UTF8 bytes from @buf, starting at *@index and returns the code + * point of the next valid code point. @index is updated ready for the + * next call. + * + * * Returns 0 to indicate an error (e.g. invalid UTF8) */ + + int index = *iindex, r; + unsigned char d = buf[index++], d2, d3, d4; + + if (!d) + return 0; + if (d < 0x80) + { + *iindex = index; + return d; + } + if ((d & 0xe0) == 0xc0) + { + /* 2 byte */ + d2 = buf[index++]; + if ((d2 & 0xc0) != 0x80) + return 0; + r = d & 0x1f; /* copy lower 5 */ + r <<= 6; + r |= (d2 & 0x3f); /* copy lower 6 */ + } + else if ((d & 0xf0) == 0xe0) + { + /* 3 byte */ + d2 = buf[index++]; + d3 = buf[index++]; + if ((d2 & 0xc0) != 0x80 || (d3 & 0xc0) != 0x80) + return 0; + r = d & 0x0f; /* copy lower 4 */ + r <<= 6; + r |= (d2 & 0x3f); + r <<= 6; + r |= (d3 & 0x3f); + } + else + { + /* 4 byte */ + d2 = buf[index++]; + d3 = buf[index++]; + d4 = buf[index++]; + if ((d2 & 0xc0) != 0x80 || (d3 & 0xc0) != 0x80 || (d4 & 0xc0) != 0x80) + return 0; + r = d & 0x0f; /* copy lower 4 */ + r <<= 6; + r |= (d2 & 0x3f); + r <<= 6; + r |= (d3 & 0x3f); + r <<= 6; + r |= (d4 & 0x3f); + + } + if (r < 0xdfff && d > 0xd800) + { + /* ill-formed says Table 3.1B in the */ + /* Unicode 3.2 std */ + return 0; + } + *iindex = index; + return r; +} + +/* TODO put this somewhere else */ + +void * +imlib_object_list_prepend(void *in_list, void *in_item) +{ + Imlib_Object_List *new_l; + Imlib_Object_List *list, *item; + + list = in_list; + item = in_item; + new_l = item; + new_l->prev = NULL; + if (!list) + { + new_l->next = NULL; + new_l->last = new_l; + return new_l; + } + new_l->next = list; + list->prev = new_l; + new_l->last = list->last; + list->last = NULL; + return new_l; +} + +void * +imlib_object_list_remove(void *in_list, void *in_item) +{ + Imlib_Object_List *return_l; + Imlib_Object_List *list, *item; + + /* checkme */ + if (!in_list) + return in_list; + + list = in_list; + item = in_item; + if (!item) + return list; + if (item->next) + item->next->prev = item->prev; + if (item->prev) + { + item->prev->next = item->next; + return_l = list; + } + else + { + return_l = item->next; + if (return_l) + return_l->last = list->last; + } + if (item == list->last) + list->last = item->prev; + item->next = NULL; + item->prev = NULL; + return return_l; +} + +static int +imlib_hash_gen(const char *key) +{ + unsigned int hash_num = 0; + const unsigned char *ptr; + + if (!key) + return 0; + + for (ptr = (unsigned char *)key; *ptr; ptr++) + hash_num ^= (int)(*ptr); + + hash_num &= 0xff; + return (int)hash_num; +} + +Imlib_Hash * +imlib_hash_add(Imlib_Hash * hash, const char *key, const void *data) +{ + int hash_num; + Imlib_Hash_El *el; + + _imlib_hash_alloc_error = 0; + if (!hash) + { + hash = calloc(1, sizeof(struct _Imlib_Hash)); + if (!hash) + { + _imlib_hash_alloc_error = 1; + return NULL; + } + } + if (!(el = malloc(sizeof(struct _Imlib_Hash_El)))) + { + if (hash->population <= 0) + { + free(hash); + hash = NULL; + } + _imlib_hash_alloc_error = 1; + return hash; + }; + if (key) + { + el->key = strdup(key); + if (!el->key) + { + free(el); + _imlib_hash_alloc_error = 1; + return hash; + } + hash_num = imlib_hash_gen(key); + } + else + { + el->key = NULL; + hash_num = 0; + } + el->data = (void *)data; + + hash->buckets[hash_num] = + imlib_object_list_prepend(hash->buckets[hash_num], el); + + if (imlib_list_alloc_error()) + { + _imlib_hash_alloc_error = 1; + if (el->key) + free(el->key); + free(el); + return hash; + } + hash->population++; + return hash; +} + +void * +imlib_hash_find(Imlib_Hash * hash, const char *key) +{ + int hash_num; + Imlib_Hash_El *el; + Imlib_Object_List *l; + + _imlib_hash_alloc_error = 0; + if (!hash) + return NULL; + hash_num = imlib_hash_gen(key); + for (l = hash->buckets[hash_num]; l; l = l->next) + { + el = (Imlib_Hash_El *) l; + if (((el->key) && (key) && (!strcmp(el->key, key))) + || ((!el->key) && (!key))) + { + if (l != hash->buckets[hash_num]) + { + /* FIXME: move to front of list without alloc */ + hash->buckets[hash_num] = + imlib_object_list_remove(hash->buckets[hash_num], el); + hash->buckets[hash_num] = + imlib_object_list_prepend(hash->buckets[hash_num], el); + if (imlib_list_alloc_error()) + { + _imlib_hash_alloc_error = 1; + return el->data; + } + } + return el->data; + } + } + return NULL; +} + +void +imlib_hash_free(Imlib_Hash * hash) +{ + int i, size; + + if (!hash) + return; + size = imlib_hash_size(hash); + for (i = 0; i < size; i++) + { + while (hash->buckets[i]) + { + Imlib_Hash_El *el; + + el = (Imlib_Hash_El *) hash->buckets[i]; + if (el->key) + free(el->key); + hash->buckets[i] = imlib_object_list_remove(hash->buckets[i], el); + free(el); + } + } + free(hash); +} + +void +imlib_hash_foreach(Imlib_Hash * hash, int (*func) (Imlib_Hash * hash, + const char *key, void *data, + void *fdata), + const void *fdata) +{ + int i, size; + + if (!hash) + return; + size = imlib_hash_size(hash); + for (i = 0; i < size; i++) + { + Imlib_Object_List *l, *next_l; + + for (l = hash->buckets[i]; l;) + { + Imlib_Hash_El *el; + + next_l = l->next; + el = (Imlib_Hash_El *) l; + if (!func(hash, el->key, el->data, (void *)fdata)) + return; + l = next_l; + } + } +} + +int +imlib_hash_size(Imlib_Hash * hash) +{ + if (!hash) + return 0; + return 256; +} + +int +imlib_list_alloc_error(void) +{ + return _imlib_list_alloc_error; +} diff --git a/src/lib/font_query.c b/src/lib/font_query.c new file mode 100644 index 0000000..b7cf837 --- /dev/null +++ b/src/lib/font_query.c @@ -0,0 +1,313 @@ +#include "config.h" +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include "font.h" +#include +#include +#include +#include "file.h" +#include "updates.h" +#include "rgbadraw.h" +#include "rotate.h" + +extern FT_Library ft_lib; + +/* string extents */ +void +imlib_font_query_size(ImlibFont * fn, const char *text, int *w, int *h) +{ + int use_kerning; + int pen_x, pen_y; + int start_x, end_x; + int chr; + FT_UInt prev_index; + + start_x = 0; + end_x = 0; + pen_x = 0; + pen_y = 0; + use_kerning = FT_HAS_KERNING(fn->ft.face); + prev_index = 0; + for (chr = 0; text[chr];) + { + FT_UInt index; + Imlib_Font_Glyph *fg; + int chr_x, chr_y, chr_w; + int gl; + + gl = imlib_font_utf8_get_next((unsigned char *)text, &chr); + if (gl == 0) + break; + index = FT_Get_Char_Index(fn->ft.face, gl); + if ((use_kerning) && (prev_index) && (index)) + { + FT_Vector delta; + + FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default, + &delta); + pen_x += delta.x << 2; + } + fg = imlib_font_cache_glyph_get(fn, index); + if (!fg) + continue; + + chr_x = (pen_x >> 8) + fg->glyph_out->left; + chr_y = (pen_y >> 8) + fg->glyph_out->top; + chr_w = fg->glyph_out->bitmap.width; + + if (!prev_index) + start_x = chr_x; + if ((chr_x + chr_w) > end_x) + end_x = chr_x + chr_w; + + pen_x += fg->glyph->advance.x >> 8; + prev_index = index; + } + if (w) + *w = (pen_x >> 8) - start_x; + if (h) + *h = imlib_font_max_ascent_get(fn) - imlib_font_max_descent_get(fn); +} + +/* text x inset */ +int +imlib_font_query_inset(ImlibFont * fn, const char *text) +{ + FT_UInt index; + Imlib_Font_Glyph *fg; + int chr; + int gl; + + chr = 0; + if (!text[0]) + return 0; + gl = imlib_font_utf8_get_next((unsigned char *)text, &chr); + if (gl == 0) + return 0; + index = FT_Get_Char_Index(fn->ft.face, gl); + fg = imlib_font_cache_glyph_get(fn, index); + if (!fg) + return 0; + return -fg->glyph_out->left; +} + +/* h & v advance */ +void +imlib_font_query_advance(ImlibFont * fn, const char *text, int *h_adv, + int *v_adv) +{ + int use_kerning; + int pen_x, pen_y; + int start_x; + int chr; + FT_UInt prev_index; + + start_x = 0; + pen_x = 0; + pen_y = 0; + use_kerning = FT_HAS_KERNING(fn->ft.face); + prev_index = 0; + for (chr = 0; text[chr];) + { + FT_UInt index; + Imlib_Font_Glyph *fg; + int chr_x, chr_y, chr_w; + int gl; + + gl = imlib_font_utf8_get_next((unsigned char *)text, &chr); + if (gl == 0) + break; + index = FT_Get_Char_Index(fn->ft.face, gl); + if ((use_kerning) && (prev_index) && (index)) + { + FT_Vector delta; + + FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default, + &delta); + pen_x += delta.x << 2; + } + fg = imlib_font_cache_glyph_get(fn, index); + if (!fg) + continue; + + chr_x = (pen_x >> 8) + fg->glyph_out->left; + chr_y = (pen_y >> 8) + fg->glyph_out->top; + chr_w = fg->glyph_out->bitmap.width; + + pen_x += fg->glyph->advance.x >> 8; + prev_index = index; + } + if (v_adv) + *v_adv = imlib_font_get_line_advance(fn); + if (h_adv) + *h_adv = (pen_x >> 8) - start_x; +} + +/* x y w h for char at char pos */ +int +imlib_font_query_char_coords(ImlibFont * fn, const char *text, int pos, + int *cx, int *cy, int *cw, int *ch) +{ + int use_kerning; + int pen_x, pen_y; + int prev_chr_end; + int chr; + int asc, desc; + FT_UInt prev_index; + + pen_x = 0; + pen_y = 0; + use_kerning = FT_HAS_KERNING(fn->ft.face); + prev_index = 0; + prev_chr_end = 0; + asc = imlib_font_max_ascent_get(fn); + desc = imlib_font_max_descent_get(fn); + for (chr = 0; text[chr];) + { + int pchr; + FT_UInt index; + Imlib_Font_Glyph *fg; + int chr_x, chr_y, chr_w; + int gl, kern; + FT_Vector delta; + + pchr = chr; + gl = imlib_font_utf8_get_next((unsigned char *)text, &chr); + if (gl == 0) + break; + index = FT_Get_Char_Index(fn->ft.face, gl); + kern = 0; + if ((use_kerning) && (prev_index) && (index)) + { + FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default, + &delta); + kern = delta.x << 2; + pen_x += kern; + } + fg = imlib_font_cache_glyph_get(fn, index); + if (!fg) + continue; + + if (kern < 0) + kern = 0; + chr_x = ((pen_x - kern) >> 8) + fg->glyph_out->left; + chr_y = (pen_y >> 8) + fg->glyph_out->top; + chr_w = fg->glyph_out->bitmap.width + (kern >> 8); + if (text[chr]) + { + int advw; + + advw = ((fg->glyph->advance.x + (kern << 8)) >> 16); + if (chr_w < advw) + chr_w = advw; + } + if (chr_x > prev_chr_end) + { + chr_w += (chr_x - prev_chr_end); + chr_x = prev_chr_end; + } + if (pchr == pos) + { + if (cx) + *cx = chr_x; + if (cy) + *cy = -asc; + if (cw) + *cw = chr_w; + if (ch) + *ch = asc + desc; + return 1; + } + prev_chr_end = chr_x + chr_w; + pen_x += fg->glyph->advance.x >> 8; + prev_index = index; + } + return 0; +} + +/* char pos of text at xy pos */ +int +imlib_font_query_text_at_pos(ImlibFont * fn, const char *text, int x, int y, + int *cx, int *cy, int *cw, int *ch) +{ + int use_kerning; + int pen_x, pen_y; + int prev_chr_end; + int chr; + int asc, desc; + FT_UInt prev_index; + + pen_x = 0; + pen_y = 0; + use_kerning = FT_HAS_KERNING(fn->ft.face); + prev_index = 0; + prev_chr_end = 0; + asc = imlib_font_max_ascent_get(fn); + desc = imlib_font_max_descent_get(fn); + for (chr = 0; text[chr];) + { + int pchr; + FT_UInt index; + Imlib_Font_Glyph *fg; + int chr_x, chr_y, chr_w; + int gl, kern; + FT_Vector delta; + + pchr = chr; + gl = imlib_font_utf8_get_next((unsigned char *)text, &chr); + if (gl == 0) + break; + index = FT_Get_Char_Index(fn->ft.face, gl); + kern = 0; + if ((use_kerning) && (prev_index) && (index)) + { + FT_Get_Kerning(fn->ft.face, prev_index, index, ft_kerning_default, + &delta); + kern = delta.x << 2; + pen_x += kern; + } + fg = imlib_font_cache_glyph_get(fn, index); + if (!fg) + continue; + + if (kern < 0) + kern = 0; + chr_x = ((pen_x - kern) >> 8) + fg->glyph_out->left; + chr_y = (pen_y >> 8) + fg->glyph_out->top; + chr_w = fg->glyph_out->bitmap.width + (kern >> 8); + if (text[chr]) + { + int advw; + + advw = ((fg->glyph->advance.x + (kern << 8)) >> 16); + if (chr_w < advw) + chr_w = advw; + } + if (chr_x > prev_chr_end) + { + chr_w += (chr_x - prev_chr_end); + chr_x = prev_chr_end; + } + if ((x >= chr_x) && (x <= (chr_x + chr_w)) && (y > -asc) && (y < desc)) + { + if (cx) + *cx = chr_x; + if (cy) + *cy = -asc; + if (cw) + *cw = chr_w; + if (ch) + *ch = asc + desc; + return pchr; + } + prev_chr_end = chr_x + chr_w; + pen_x += fg->glyph->advance.x >> 8; + prev_index = index; + } + return -1; +} diff --git a/src/lib/format.c b/src/lib/format.c new file mode 100644 index 0000000..b0d6a10 --- /dev/null +++ b/src/lib/format.c @@ -0,0 +1 @@ +#include "format.h" diff --git a/src/lib/format.h b/src/lib/format.h new file mode 100644 index 0000000..94137af --- /dev/null +++ b/src/lib/format.h @@ -0,0 +1,3 @@ +#ifndef __FORMAT +#define __FORMAT 1 +#endif diff --git a/src/lib/grab.c b/src/lib/grab.c new file mode 100644 index 0000000..a2bee15 --- /dev/null +++ b/src/lib/grab.c @@ -0,0 +1,729 @@ +#include "common.h" +#ifdef BUILD_X11 +# include +# include +# include +# include +# include +# include +#endif +#include "grab.h" + +#ifdef BUILD_X11 + +static char _x_err = 0; +static DATA8 rtab[256], gtab[256], btab[256]; + +static void +Tmp_HandleXError(Display * d, XErrorEvent * ev) +{ + d = NULL; + ev = NULL; + _x_err = 1; +} + +void +__imlib_GrabXImageToRGBA(DATA32 * data, int ox, int oy, int ow, int oh, + Display * d, XImage * xim, XImage * mxim, Visual * v, + int depth, int x, int y, int w, int h, char grab) +{ + int inx, iny; + DATA32 *src, *ptr; + int pixel; + int origx, origy; + int bgr = 0; + + if (!data) + return; + + if (grab) + XGrabServer(d); /* This may prevent the image to be changed under our feet */ + origx = x; + origy = y; + + if (v->blue_mask > v->red_mask) + bgr = 1; + + if (origx < 0) + inx = -origx; + else + inx = ox; + if (origy < 0) + iny = -origy; + else + iny = oy; + /* go thru the XImage and convert */ + if (xim->bits_per_pixel == 32) + depth = 32; + switch (depth) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + if (mxim) + { + for (y = 0; y < h; y++) + { + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + pixel = (btab[pixel & 0xff]) | + (gtab[pixel & 0xff] << 8) | + (rtab[pixel & 0xff] << 16); + if (XGetPixel(mxim, x, y)) + pixel |= 0xff000000; + *ptr++ = pixel; + } + } + } + else + { + for (y = 0; y < h; y++) + { + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + *ptr++ = 0xff000000 | + (btab[pixel & 0xff]) | + (gtab[pixel & 0xff] << 8) | + (rtab[pixel & 0xff] << 16); + } + } + } + break; + case 16: +#undef MP +#undef RMSK +#undef GMSK +#undef BMSK +#undef R1SH +#undef G1SH +#undef B1SH +#undef R2SH +#undef G2SH +#undef B2SH +#undef P1 +#undef P2 +#define MP(x, y) ((XGetPixel(mxim, (x), (y))) ? 0xff000000 : 0) +#define RMSK 0xf80000 +#define GMSK 0x00fc00 +#define BMSK 0x0000f8 +#define R1SH(p) ((p) << 8) +#define G1SH(p) ((p) << 5) +#define B1SH(p) ((p) << 3) +#define R2SH(p) ((p) >> 8) +#define G2SH(p) ((p) >> 11) +#define B2SH(p) ((p) >> 13) +#define P1(p) (R1SH(p) & RMSK) | (G1SH(p) & GMSK) | (B1SH(p) & BMSK) +#define P2(p) (R2SH(p) & RMSK) | (G2SH(p) & GMSK) | (B2SH(p) & BMSK) + if (mxim) + { + for (y = 0; y < h; y++) + { + src = (DATA32 *) (xim->data + (xim->bytes_per_line * y)); + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < (w - 1); x += 2) + { +#ifdef WORDS_BIGENDIAN + *ptr++ = MP(x + 1, y) | P2(*src); + *ptr++ = MP(x, y) | P1(*src); +#else + *ptr++ = MP(x, y) | P1(*src); + *ptr++ = MP(x + 1, y) | P2(*src); +#endif + src++; + } + if (x == (w - 1)) + { + pixel = XGetPixel(xim, x, y); + *ptr++ = MP(x, y) | P1(pixel); + } + } + } +#undef MP +#define MP(x, y) (0xff000000) + else + { + for (y = 0; y < h; y++) + { + src = (DATA32 *) (xim->data + (xim->bytes_per_line * y)); + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < (w - 1); x += 2) + { +#ifdef WORDS_BIGENDIAN + *ptr++ = MP(x + 1, y) | P2(*src); + *ptr++ = MP(x, y) | P1(*src); +#else + *ptr++ = MP(x, y) | P1(*src); + *ptr++ = MP(x + 1, y) | P2(*src); +#endif + src++; + } + if (x == (w - 1)) + { + pixel = XGetPixel(xim, x, y); + *ptr++ = MP(x, y) | P1(pixel); + } + } + } + break; + case 15: +#undef MP +#undef RMSK +#undef GMSK +#undef BMSK +#undef R1SH +#undef G1SH +#undef B1SH +#undef R2SH +#undef G2SH +#undef B2SH +#undef P1 +#undef P2 +#define MP(x, y) ((XGetPixel(mxim, (x), (y))) ? 0xff000000 : 0) +#define RMSK 0xf80000 +#define GMSK 0x00f800 +#define BMSK 0x0000f8 +#define R1SH(p) ((p) << 9) +#define G1SH(p) ((p) << 6) +#define B1SH(p) ((p) << 3) +#define R2SH(p) ((p) >> 7) +#define G2SH(p) ((p) >> 10) +#define B2SH(p) ((p) >> 13) +#define P1(p) (R1SH(p) & RMSK) | (G1SH(p) & GMSK) | (B1SH(p) & BMSK) +#define P2(p) (R2SH(p) & RMSK) | (G2SH(p) & GMSK) | (B2SH(p) & BMSK) + if (mxim) + { + for (y = 0; y < h; y++) + { + src = (DATA32 *) (xim->data + (xim->bytes_per_line * y)); + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < (w - 1); x += 2) + { +#ifdef WORDS_BIGENDIAN + *ptr++ = MP(x + 1, y) | P2(*src); + *ptr++ = MP(x, y) | P1(*src); +#else + *ptr++ = MP(x, y) | P1(*src); + *ptr++ = MP(x + 1, y) | P2(*src); +#endif + src++; + } + if (x == (w - 1)) + { + pixel = XGetPixel(xim, x, y); + *ptr++ = MP(x, y) | P1(pixel); + } + } + } +#undef MP +#define MP(x, y) (0xff000000) + else + { + for (y = 0; y < h; y++) + { + src = (DATA32 *) (xim->data + (xim->bytes_per_line * y)); + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < (w - 1); x += 2) + { +#ifdef WORDS_BIGENDIAN + *ptr++ = MP(x + 1, y) | P2(*src); + *ptr++ = MP(x, y) | P1(*src); +#else + *ptr++ = MP(x, y) | P1(*src); + *ptr++ = MP(x + 1, y) | P2(*src); +#endif + src++; + } + if (x == (w - 1)) + { + pixel = XGetPixel(xim, x, y); + *ptr++ = MP(x, y) | P1(pixel); + } + } + } + break; + case 24: + if (bgr) + { + if (mxim) + { + for (y = 0; y < h; y++) + { + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + pixel = ((pixel << 16) & 0xff0000) | + ((pixel) & 0x00ff00) | + ((pixel >> 16) & 0x0000ff); + if (XGetPixel(mxim, x, y)) + pixel |= 0xff000000; + *ptr++ = pixel; + } + } + } + else + { + for (y = 0; y < h; y++) + { + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + *ptr++ = 0xff000000 | + ((pixel << 16) & 0xff0000) | + ((pixel) & 0x00ff00) | + ((pixel >> 16) & 0x0000ff); + } + } + } + } + else + { + if (mxim) + { + for (y = 0; y < h; y++) + { + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y) & 0x00ffffff; + if (XGetPixel(mxim, x, y)) + pixel |= 0xff000000; + *ptr++ = pixel; + } + } + } + else + { + for (y = 0; y < h; y++) + { + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + *ptr++ = 0xff000000 | (pixel & 0x00ffffff); + } + } + } + } + break; + case 32: + if (bgr) + { + if (mxim) + { + for (y = 0; y < h; y++) + { + src = + (DATA32 *) (xim->data + (xim->bytes_per_line * y)); + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = ((*src << 16) & 0xff0000) | + ((*src) & 0x00ff00) | + ((*src >> 16) & 0x0000ff); + if (XGetPixel(mxim, x, y)) + pixel |= 0xff000000; + *ptr++ = pixel; + src++; + } + } + } + else + { + for (y = 0; y < h; y++) + { + src = + (DATA32 *) (xim->data + (xim->bytes_per_line * y)); + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + *ptr++ = 0xff000000 | + ((*src << 16) & 0xff0000) | + ((*src) & 0x00ff00) | + ((*src >> 16) & 0x0000ff); + src++; + } + } + } + } + else + { + if (mxim) + { + for (y = 0; y < h; y++) + { + src = + (DATA32 *) (xim->data + (xim->bytes_per_line * y)); + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = (*src) & 0x00ffffff; + if (XGetPixel(mxim, x, y)) + pixel |= 0xff000000; + *ptr++ = pixel; + src++; + } + } + } + else + { + for (y = 0; y < h; y++) + { + src = + (DATA32 *) (xim->data + (xim->bytes_per_line * y)); + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + *ptr++ = 0xff000000 | ((*src) & 0x00ffffff); + src++; + } + } + } + } + break; + default: + break; + } + + if (grab) + XUngrabServer(d); +} + +char +__imlib_GrabDrawableToRGBA(DATA32 * data, int ox, int oy, int ow, int oh, + Display * d, Drawable p, Pixmap m, Visual * v, + Colormap cm, int depth, int x, int y, + int w, int h, char domask, char grab) +{ + XErrorHandler prev_erh = NULL; + XWindowAttributes xatt, ratt; + char is_pixmap = 0, created_mask = 0, is_shm = 0, is_mshm = 0; + int i; + int src_x, src_y, src_w, src_h, origw, origh; + int width, height, clipx, clipy; + XShmSegmentInfo shminfo, mshminfo; + XImage *xim = NULL, *mxim = NULL; + static signed char x_does_shm = -1; + XColor cols[256]; + + /* FIXME: oh isnt used - i wonder if there's a bug looming... */ + oh = 0; + origw = w; + origh = h; + if (grab) + XGrabServer(d); + XSync(d, False); + prev_erh = XSetErrorHandler((XErrorHandler) Tmp_HandleXError); + _x_err = 0; + /* lets see if its a pixmap or not */ + XGetWindowAttributes(d, p, &xatt); + XSync(d, False); + if (_x_err) + is_pixmap = 1; + /* reset our error handler */ + XSetErrorHandler((XErrorHandler) prev_erh); + if (is_pixmap) + { + Window dw; + + XGetGeometry(d, p, &dw, &src_x, &src_y, + (unsigned int *)&src_w, (unsigned int *)&src_h, + (unsigned int *)&src_x, (unsigned int *)&xatt.depth); + src_x = 0; + src_y = 0; + } + else + { + Window dw; + + XGetWindowAttributes(d, xatt.root, &ratt); + XTranslateCoordinates(d, p, xatt.root, 0, 0, &src_x, &src_y, &dw); + src_w = xatt.width; + src_h = xatt.height; + if ((xatt.map_state != IsViewable) && (xatt.backing_store == NotUseful)) + { + if (grab) + XUngrabServer(d); + return 0; + } + } + + /* clip to the drawable tree and screen */ + clipx = 0; + clipy = 0; + width = src_w - x; + height = src_h - y; + if (width > w) + width = w; + if (height > h) + height = h; + + if (!is_pixmap) + { + if ((src_x + x + width) > ratt.width) + width = ratt.width - (src_x + x); + if ((src_y + y + height) > ratt.height) + height = ratt.height - (src_y + y); + } + if (x < 0) + { + clipx = -x; + width += x; + x = 0; + } + if (y < 0) + { + clipy = -y; + height += y; + y = 0; + } + if (!is_pixmap) + { + if ((src_x + x) < 0) + { + clipx -= (src_x + x); + width += (src_x + x); + x = -src_x; + } + if ((src_y + y) < 0) + { + clipy -= (src_y + y); + height += (src_y + y); + y = -src_y; + } + } + if ((width <= 0) || (height <= 0)) + { + if (grab) + XUngrabServer(d); + return 0; + } + w = width; + h = height; + if ((!is_pixmap) && (domask) && (!m)) + { + int ord, rect_no = 0; + XRectangle *r = NULL; + + r = XShapeGetRectangles(d, p, ShapeBounding, &rect_no, &ord); + if (r) + { + if (!((rect_no == 1) && + (r[0].x == 0) && (r[0].y == 0) && + (r[0].width == xatt.width) && (r[0].height == xatt.height))) + { + XGCValues gcv; + GC gc; + + created_mask = 1; + m = XCreatePixmap(d, p, w, h, 1); + gcv.foreground = 0; + gc = XCreateGC(d, m, GCForeground, &gcv); + XFillRectangle(d, m, gc, 0, 0, w, h); + XSetForeground(d, gc, 1); + for (i = 0; i < rect_no; i++) + XFillRectangle(d, m, gc, + r[i].x - x, r[i].y - y, + r[i].width, r[i].height); + XFreeGC(d, gc); + } + XFree(r); + } + } + + /* Create an Ximage (shared or not) */ + if (x_does_shm < 0) + { + if (XShmQueryExtension(d)) + x_does_shm = 1; + else + x_does_shm = 0; + } + + prev_erh = XSetErrorHandler((XErrorHandler) Tmp_HandleXError); + + if (x_does_shm) + { + _x_err = 0; + xim = XShmCreateImage(d, v, xatt.depth, ZPixmap, NULL, &shminfo, w, h); + if (xim) + { + XSync(d, False); + if (_x_err) + { + XDestroyImage(xim); + } + else + { + shminfo.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * + xim->height, IPC_CREAT | 0666); + if (shminfo.shmid < 0) + { + XDestroyImage(xim); + } + else + { + shminfo.shmaddr = xim->data = shmat(shminfo.shmid, 0, 0); + if (xim->data != (char *)-1) + { + shminfo.readOnly = False; + XShmAttach(d, &shminfo); + is_shm = 1; + XShmGetImage(d, p, xim, x, y, 0xffffffff); + XSync(d, False); + if (_x_err) + { + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + XDestroyImage(xim); + is_shm = 0; + } + } + else + { + shmctl(shminfo.shmid, IPC_RMID, 0); + XDestroyImage(xim); + } + } + } + } + } + if (!is_shm) + xim = XGetImage(d, p, x, y, w, h, 0xffffffff, ZPixmap); + + if ((m) && (domask)) + { + _x_err = 0; + if (x_does_shm) + { + mxim = XShmCreateImage(d, v, 1, ZPixmap, NULL, &mshminfo, w, h); + if (mxim) + { + XSync(d, False); + if (_x_err) + { + XDestroyImage(mxim); + } + else + { + mshminfo.shmid = shmget(IPC_PRIVATE, + mxim->bytes_per_line * + mxim->height, IPC_CREAT | 0666); + if (mshminfo.shmid < 0) + { + XDestroyImage(mxim); + } + else + { + mshminfo.shmaddr = mxim->data = + shmat(mshminfo.shmid, 0, 0); + if (mxim->data != (char *)-1) + { + mshminfo.readOnly = False; + XShmAttach(d, &mshminfo); + is_mshm = 1; + XShmGetImage(d, m, mxim, 0, 0, 0xffffffff); + XSync(d, False); + if (_x_err) + { + shmdt(mshminfo.shmaddr); + shmctl(mshminfo.shmid, IPC_RMID, 0); + XDestroyImage(mxim); + is_mshm = 0; + } + } + else + { + shmctl(mshminfo.shmid, IPC_RMID, 0); + XDestroyImage(mxim); + } + } + } + } + } + if (!is_mshm) + mxim = XGetImage(d, m, 0, 0, w, h, 0xffffffff, ZPixmap); + } + + XSetErrorHandler((XErrorHandler) prev_erh); + + if ((is_shm) || (is_mshm)) + { + XSync(d, False); + if (grab) + XUngrabServer(d); + XSync(d, False); + } + else if (grab) + XUngrabServer(d); + + if ((xatt.depth == 1) && (!cm) && (is_pixmap)) + { + rtab[0] = 255; + gtab[0] = 255; + btab[0] = 255; + rtab[1] = 0; + gtab[1] = 0; + btab[1] = 0; + } + else if (xatt.depth <= 8) + { + if ((!is_pixmap) && (!cm)) + { + cm = xatt.colormap; + if (cm == None) + cm = ratt.colormap; + } + else + cm = ratt.colormap; + + for (i = 0; i < (1 << xatt.depth); i++) + { + cols[i].pixel = i; + cols[i].flags = DoRed | DoGreen | DoBlue; + } + XQueryColors(d, cm, cols, 1 << xatt.depth); + for (i = 0; i < (1 << xatt.depth); i++) + { + rtab[i] = cols[i].red >> 8; + gtab[i] = cols[i].green >> 8; + btab[i] = cols[i].blue >> 8; + } + } + __imlib_GrabXImageToRGBA(data, ox + clipx, oy + clipy, ow, oh, + d, xim, mxim, v, xatt.depth, x, y, w, h, 0); + + /* destroy the Ximage */ + if (is_shm) + { + XSync(d, False); + XShmDetach(d, &shminfo); + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + } + if ((is_mshm) && (mxim)) + { + XShmDetach(d, &mshminfo); + shmdt(mshminfo.shmaddr); + shmctl(mshminfo.shmid, IPC_RMID, 0); + } + XDestroyImage(xim); + if (created_mask) + XFreePixmap(d, m); + if (mxim) + XDestroyImage(mxim); + return 1; +} + +#endif diff --git a/src/lib/grab.h b/src/lib/grab.h new file mode 100644 index 0000000..9e83f69 --- /dev/null +++ b/src/lib/grab.h @@ -0,0 +1,19 @@ +#ifndef __GRAB +#define __GRAB 1 + +#ifdef BUILD_X11 + +char +__imlib_GrabDrawableToRGBA(DATA32 *data, int ox, int oy, int ow, int oh, + Display *d, Drawable p, Pixmap m, Visual *v, + Colormap cm, int depth, int x, int y, + int w, int h, char domask, char grab); +void +__imlib_GrabXImageToRGBA(DATA32 *data, int ox, int oy, int ow, int oh, + Display *d, XImage *xim, XImage *mxim, Visual *v, + int depth, int x, int y, + int w, int h, char grab); + +#endif + +#endif diff --git a/src/lib/grad.c b/src/lib/grad.c new file mode 100644 index 0000000..9f53d10 --- /dev/null +++ b/src/lib/grad.c @@ -0,0 +1,614 @@ +#include "common.h" +#include "colormod.h" +#include "file.h" +#include "loaderpath.h" +#include +#include "image.h" +#include "blend.h" +#include "grad.h" +#include "color_helpers.h" + +ImlibRange * +__imlib_CreateRange(void) +{ + ImlibRange *rg = NULL; + + rg = malloc(sizeof(ImlibRange)); + rg->color = NULL; + return rg; +} + +void +__imlib_FreeRange(ImlibRange * rg) +{ + ImlibRangeColor *p, *pp; + + p = rg->color; + while (p) + { + pp = p; + p = p->next; + free(pp); + } + free(rg); +} + +void +__imlib_AddRangeColor(ImlibRange * rg, DATA8 r, DATA8 g, DATA8 b, DATA8 a, + int dist) +{ + ImlibRangeColor *p, *rc; + + if (dist < 1) + dist = 1; + if (!rg->color) + dist = 0; + + rc = malloc(sizeof(ImlibRangeColor)); + rc->red = r; + rc->green = g; + rc->blue = b; + rc->alpha = a; + rc->distance = 0; + rc->next = NULL; + + p = rg->color; + if (p) + { + while (p) + { + if (!p->next) + { + p->distance = dist; + p->next = rc; + p = NULL; + } + else + p = p->next; + } + } + else + rg->color = rc; +} + +DATA32 * +__imlib_MapRange(ImlibRange * rg, int len) +{ + ImlibRangeColor *p; + DATA32 *map, *pmap, v, vv; + int r, g, b, a, rr, gg, bb, aa, i, l, ll, v1, v2, inc, j; + + if (!rg->color) + return NULL; + if (!rg->color->next) + return NULL; + ll = 1; + for (p = rg->color; p; p = p->next) + ll += p->distance; + map = malloc(len * sizeof(DATA32)); + pmap = malloc(ll * sizeof(DATA32)); + i = 0; + for (p = rg->color; p; p = p->next) + { + if (p->next) + { + for (j = 0; j < p->distance; j++) + { + v1 = (j << 16) / p->distance; + v2 = 65536 - v1; + r = ((p->red * v2) + (p->next->red * v1)) >> 16; + g = ((p->green * v2) + (p->next->green * v1)) >> 16; + b = ((p->blue * v2) + (p->next->blue * v1)) >> 16; + a = ((p->alpha * v2) + (p->next->alpha * v1)) >> 16; + pmap[i++] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + else + { + r = p->red; + g = p->green; + b = p->blue; + a = p->alpha; + pmap[i++] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + inc = ((ll - 1) << 16) / (len); + l = 0; + for (i = 0; i < len; i++) + { + v = pmap[l >> 16]; + if ((l >> 16) < ll) + vv = pmap[(l >> 16) + 1]; + else + vv = pmap[(l >> 16)]; + v1 = l - ((l >> 16) << 16); + v2 = 65536 - v1; + b = ((v)) & 0xff; + g = ((v) >> 8) & 0xff; + r = ((v) >> 16) & 0xff; + a = ((v) >> 24) & 0xff; + bb = ((vv)) & 0xff; + gg = ((vv) >> 8) & 0xff; + rr = ((vv) >> 16) & 0xff; + aa = ((vv) >> 24) & 0xff; + r = ((r * v2) + (rr * v1)) >> 16; + g = ((g * v2) + (gg * v1)) >> 16; + b = ((b * v2) + (bb * v1)) >> 16; + a = ((a * v2) + (aa * v1)) >> 16; + map[i] = (a << 24) | (r << 16) | (g << 8) | b; + l += inc; + } + free(pmap); + return map; +} + +DATA32 * +__imlib_MapHsvaRange(ImlibRange * rg, int len) +{ + ImlibRangeColor *p; + DATA32 *map, *pmap, k, kk; + int r, g, b, a, rr, gg, bb, aa, i, l, ll, inc, j; + float h1, s1, v1, h2, s2, v2, h, s, v, k1, k2; + + if (!rg->color) + return NULL; + if (!rg->color->next) + return NULL; + ll = 1; + for (p = rg->color; p; p = p->next) + ll += p->distance; + map = malloc(len * sizeof(DATA32)); + pmap = malloc(ll * sizeof(DATA32)); + i = 0; + for (p = rg->color; p; p = p->next) + { + if (p->next) + { + for (j = 0; j < p->distance; j++) + { + k1 = (j << 16) / (float)p->distance; + k2 = 65536 - k1; + r = p->red; + rr = p->next->red; + g = p->green; + gg = p->next->green; + b = p->blue; + bb = p->next->blue; + __imlib_rgb_to_hsv(r, g, b, &h1, &s1, &v1); + __imlib_rgb_to_hsv(rr, gg, bb, &h2, &s2, &v2); + h = ((h1 * k2) + (h2 * k1)) / 65536.0; + s = ((s1 * k2) + (s2 * k1)) / 65536.0; + v = ((v1 * k2) + (v2 * k1)) / 65536.0; + __imlib_hsv_to_rgb(h, s, v, &r, &g, &b); + a = (unsigned long int)((p->alpha * k2) + + (p->next->alpha * k1)) >> 16; + pmap[i++] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + else + { + r = p->red; + g = p->green; + b = p->blue; + a = p->alpha; + pmap[i++] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + inc = ((ll - 1) << 16) / (len); + l = 0; + for (i = 0; i < len; i++) + { + k = pmap[l >> 16]; + if ((l >> 16) < ll) + kk = pmap[(l >> 16) + 1]; + else + kk = pmap[(l >> 16)]; + k1 = l - (float)((l >> 16) << 16); + k2 = 65536 - k1; + b = ((k)) & 0xff; + g = ((k) >> 8) & 0xff; + r = ((k) >> 16) & 0xff; + a = ((k) >> 24) & 0xff; + bb = ((kk)) & 0xff; + gg = ((kk) >> 8) & 0xff; + rr = ((kk) >> 16) & 0xff; + aa = ((kk) >> 24) & 0xff; + __imlib_rgb_to_hsv(r, g, b, &h1, &s1, &v1); + __imlib_rgb_to_hsv(rr, gg, bb, &h2, &s2, &v2); + h = ((h1 * k2) + (h2 * k1)) / 65536.0; + s = ((s1 * k2) + (s2 * k1)) / 65536.0; + v = ((v1 * k2) + (v2 * k1)) / 65536.0; + __imlib_hsv_to_rgb(h, s, v, &r, &g, &b); + a = (unsigned long int)((a * k2) + (aa * k1)) >> 16; + map[i] = (a << 24) | (r << 16) | (g << 8) | b; + l += inc; + } + free(pmap); + return map; +} + +void +__imlib_DrawGradient(ImlibImage * im, int x, int y, int w, int h, + ImlibRange * rg, double angle, ImlibOp op, + int clx, int cly, int clw, int clh) +{ + DATA32 *map, *p, v; + int *hlut, *vlut, len = 0, xx, yy, xoff = 0, yoff = + 0, ww, hh, jump; + int tmp, i, divw, divh; + DATA8 rr, gg, bb, aa, r, g, b, a, nr, ng, nb, na; + + ww = w; + hh = h; + if (x < 0) + { + w += x; + xoff = -x; + x = 0; + } + if (w <= 0) + return; + if ((x + w) > im->w) + w = (im->w - x); + if (w <= 0) + return; + if (y < 0) + { + h += y; + yoff = -y; + y = 0; + } + if (h <= 0) + return; + if ((y + h) > im->h) + h = (im->h - y); + if (h <= 0) + return; + if (clw) + { + int px, py; + + CLIP_TO(clx, cly, clw, clh, 0, 0, im->w, im->h); + px = x; + py = y; + CLIP_TO(x, y, w, h, clx, cly, clw, clh); + if ((w < 1) || (h < 1)) + return; + xoff += (x - px); + yoff += (y - py); + } + + hlut = malloc(sizeof(int) * ww); + vlut = malloc(sizeof(int) * hh); + if (ww > hh) + len = ww * 16; + else + len = hh * 16; + map = __imlib_MapRange(rg, len); + if (!map) + return; + + xx = (int)(32 * sin(((angle + 180) * 2 * 3.141592654) / 360)); + yy = -(int)(32 * cos(((angle + 180) * 2 * 3.141592654) / 360)); + divw = ((ww - 1) << 5); + divh = ((hh - 1) << 5); + if (divw < 1) + divw = 1; + if (divh < 1) + divh = 1; + if (xx < 0) + { + for (i = 0; i < ww; i++) + hlut[i] = (-xx * (ww - 1 - i) * len) / divw; + } + else + { + for (i = 0; i < ww; i++) + hlut[i] = (xx * i * len) / divw; + } + if (yy < 0) + { + for (i = 0; i < hh; i++) + vlut[i] = (-yy * (hh - 1 - i) * len) / divh; + } + else + { + for (i = 0; i < hh; i++) + vlut[i] = (yy * i * len) / divh; + } + jump = im->w - w; + + p = im->data + (y * im->w) + x; + switch (op) + { + case OP_COPY: + if (IMAGE_HAS_ALPHA(im)) + { + __imlib_build_pow_lut(); + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + i = vlut[yoff + yy] + hlut[xoff + xx]; + if (i < 0) + i = 0; + else if (i >= len) + i = len - 1; + READ_RGBA(&(map[i]), r, g, b, a); + BLEND_DST_ALPHA(r, g, b, a, p); + p++; + } + p += jump; + } + } + else + { + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + i = vlut[yoff + yy] + hlut[xoff + xx]; + if (i < 0) + i = 0; + else if (i >= len) + i = len - 1; + READ_RGBA(&(map[i]), r, g, b, a); + BLEND(r, g, b, a, p); + p++; + } + p += jump; + } + } + break; + case OP_ADD: + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + i = vlut[yoff + yy] + hlut[xoff + xx]; + if (i < 0) + i = 0; + else if (i >= len) + i = len - 1; + READ_RGBA(&(map[i]), r, g, b, a); + BLEND_SUB(r, g, b, a, p); + p++; + } + p += jump; + } + break; + case OP_SUBTRACT: + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + i = vlut[yoff + yy] + hlut[xoff + xx]; + if (i < 0) + i = 0; + else if (i >= len) + i = len - 1; + READ_RGBA(&(map[i]), r, g, b, a); + BLEND_SUB(r, g, b, a, p); + p++; + } + p += jump; + } + break; + case OP_RESHADE: + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + i = vlut[yoff + yy] + hlut[xoff + xx]; + if (i < 0) + i = 0; + else if (i >= len) + i = len - 1; + READ_RGBA(&(map[i]), r, g, b, a); + BLEND_RE(r, g, b, a, p); + p++; + } + p += jump; + } + break; + default: + break; + } + + free(vlut); + free(hlut); + free(map); +} + +void +__imlib_DrawHsvaGradient(ImlibImage * im, int x, int y, int w, int h, + ImlibRange * rg, double angle, ImlibOp op, + int clx, int cly, int clw, int clh) +{ + DATA32 *map, *p, v; + int *hlut, *vlut, len = 0, xx, yy, xoff = 0, yoff = + 0, ww, hh, jump; + int tmp, i, divw, divh; + DATA8 rr, gg, bb, aa, r, g, b, a, nr, ng, nb, na; + + ww = w; + hh = h; + if (x < 0) + { + w += x; + xoff = -x; + x = 0; + } + if (w <= 0) + return; + if ((x + w) > im->w) + w = (im->w - x); + if (w <= 0) + return; + if (y < 0) + { + h += y; + yoff = -y; + y = 0; + } + if (h <= 0) + return; + if ((y + h) > im->h) + h = (im->h - y); + if (h <= 0) + return; + if (clw) + { + int px, py; + + CLIP_TO(clx, cly, clw, clh, 0, 0, im->w, im->h); + px = x; + py = y; + CLIP_TO(x, y, w, h, clx, cly, clw, clh); + if ((w < 1) || (h < 1)) + return; + xoff += (x - px); + yoff += (y - py); + } + + hlut = malloc(sizeof(int) * ww); + vlut = malloc(sizeof(int) * hh); + if (ww > hh) + len = ww * 16; + else + len = hh * 16; + map = __imlib_MapHsvaRange(rg, len); + if (!map) + return; + + xx = (int)(32 * sin(((angle + 180) * 2 * 3.141592654) / 360)); + yy = -(int)(32 * cos(((angle + 180) * 2 * 3.141592654) / 360)); + divw = ((ww - 1) << 5); + divh = ((hh - 1) << 5); + if (divw < 1) + divw = 1; + if (divh < 1) + divh = 1; + if (xx < 0) + { + for (i = 0; i < ww; i++) + hlut[i] = (-xx * (ww - 1 - i) * len) / divw; + } + else + { + for (i = 0; i < ww; i++) + hlut[i] = (xx * i * len) / divw; + } + if (yy < 0) + { + for (i = 0; i < hh; i++) + vlut[i] = (-yy * (hh - 1 - i) * len) / divh; + } + else + { + for (i = 0; i < hh; i++) + vlut[i] = (yy * i * len) / divh; + } + jump = im->w - w; + + p = im->data + (y * im->w) + x; + switch (op) + { + case OP_COPY: + if (IMAGE_HAS_ALPHA(im)) + { + __imlib_build_pow_lut(); + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + i = vlut[yoff + yy] + hlut[xoff + xx]; + if (i < 0) + i = 0; + else if (i >= len) + i = len - 1; + READ_RGBA(&(map[i]), r, g, b, a); + BLEND_DST_ALPHA(r, g, b, a, p); + p++; + } + p += jump; + } + } + else + { + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + i = vlut[yoff + yy] + hlut[xoff + xx]; + if (i < 0) + i = 0; + else if (i >= len) + i = len - 1; + READ_RGBA(&(map[i]), r, g, b, a); + BLEND(r, g, b, a, p); + p++; + } + p += jump; + } + } + break; + case OP_ADD: + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + i = vlut[yoff + yy] + hlut[xoff + xx]; + if (i < 0) + i = 0; + else if (i >= len) + i = len - 1; + READ_RGBA(&(map[i]), r, g, b, a); + BLEND_SUB(r, g, b, a, p); + p++; + } + p += jump; + } + break; + case OP_SUBTRACT: + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + i = vlut[yoff + yy] + hlut[xoff + xx]; + if (i < 0) + i = 0; + else if (i >= len) + i = len - 1; + READ_RGBA(&(map[i]), r, g, b, a); + BLEND_SUB(r, g, b, a, p); + p++; + } + p += jump; + } + break; + case OP_RESHADE: + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + i = vlut[yoff + yy] + hlut[xoff + xx]; + if (i < 0) + i = 0; + else if (i >= len) + i = len - 1; + READ_RGBA(&(map[i]), r, g, b, a); + BLEND_RE(r, g, b, a, p); + p++; + } + p += jump; + } + break; + default: + break; + } + + free(vlut); + free(hlut); + free(map); +} diff --git a/src/lib/grad.h b/src/lib/grad.h new file mode 100644 index 0000000..616394b --- /dev/null +++ b/src/lib/grad.h @@ -0,0 +1,28 @@ +#ifndef __GRAD +#define __GRAD 1 + +typedef struct _imlib_range ImlibRange; +typedef struct _imlib_range_color ImlibRangeColor; + +struct _imlib_range_color +{ + DATA8 red, green, blue, alpha; + int distance; + ImlibRangeColor *next; +}; + +struct _imlib_range +{ + ImlibRangeColor *color; +}; + +ImlibRange *__imlib_CreateRange(void); +void __imlib_FreeRange(ImlibRange *rg); +void __imlib_AddRangeColor(ImlibRange *rg, DATA8 r, DATA8 g, DATA8 b, + DATA8 a, int dist); +DATA32 *__imlib_MapRange(ImlibRange *rg, int len); +DATA32 *__imlib_MapHsvaRange(ImlibRange *rg, int len); +void __imlib_DrawGradient(ImlibImage *im, int x, int y, int w, int h, ImlibRange *rg, double angle, ImlibOp op, int clx, int cly, int clw, int clh); +void __imlib_DrawHsvaGradient(ImlibImage *im, int x, int y, int w, int h, ImlibRange *rg, double angle, ImlibOp op, int clx, int cly, int clw, int clh); + +#endif diff --git a/src/lib/image.c b/src/lib/image.c new file mode 100644 index 0000000..576ac4e --- /dev/null +++ b/src/lib/image.c @@ -0,0 +1,1318 @@ +#include "common.h" +#include +#include +#include +#include +#include +#include +#include +#ifdef BUILD_X11 +# include +#endif +#include "image.h" +#include "file.h" +#include "loaderpath.h" + +static ImlibImage *images = NULL; + +#ifdef BUILD_X11 +static ImlibImagePixmap *pixmaps = NULL; +#endif +static ImlibLoader *loaders = NULL; +static int cache_size = 4096 * 1024; + +/* attach a string key'd data and/or int value to an image that cna be */ +/* looked up later by its string key */ +void +__imlib_AttachTag(ImlibImage * im, const char *key, int val, void *data, + ImlibDataDestructorFunction destructor) +{ + ImlibImageTag *t; + + /* no string key? abort */ + if (!key) + return; + + /* if a tag of that name alreayd exists - remove it and free it */ + if ((t = __imlib_RemoveTag(im, key))) + __imlib_FreeTag(im, t); + /* allocate the struct */ + t = malloc(sizeof(ImlibImageTag)); + /* fill it int */ + t->key = strdup(key); + t->val = val; + t->data = data; + t->destructor = destructor; + t->next = im->tags; + /* prepend it to the list of tags */ + im->tags = t; +} + +/* look up a tage by its key on the image it was attached to */ +ImlibImageTag * +__imlib_GetTag(ImlibImage * im, const char *key) +{ + ImlibImageTag *t; + + t = im->tags; + while (t) + { + if (!strcmp(t->key, key)) + return t; + t = t->next; + } + /* no tag found - return NULL */ + return NULL; +} + +/* remove a tag by looking it up by its key and removing it from */ +/* the list of keys */ +ImlibImageTag * +__imlib_RemoveTag(ImlibImage * im, const char *key) +{ + ImlibImageTag *t, *tt; + + tt = NULL; + t = im->tags; + while (t) + { + if (!strcmp(t->key, key)) + { + if (tt) + tt->next = t->next; + else + im->tags = t->next; + return t; + } + tt = t; + t = t->next; + } + /* no tag found - NULL */ + return NULL; +} + +/* free the data struct for the tag and if a destructor function was */ +/* provided call it on the data member */ +void +__imlib_FreeTag(ImlibImage * im, ImlibImageTag * t) +{ + free(t->key); + if (t->destructor) + t->destructor(im, t->data); + free(t); +} + +/* free all the tags attached to an image */ +void +__imlib_FreeAllTags(ImlibImage * im) +{ + ImlibImageTag *t, *tt; + + t = im->tags; + while (t) + { + tt = t; + t = t->next; + __imlib_FreeTag(im, tt); + } +} + +/* set the cache size */ +void +__imlib_SetCacheSize(int size) +{ + cache_size = size; + __imlib_CleanupImageCache(); +#ifdef BUILD_X11 + __imlib_CleanupImagePixmapCache(); +#endif +} + +/* return the cache size */ +int +__imlib_GetCacheSize(void) +{ + return cache_size; +} + +/* create an image data struct and fill it in */ +ImlibImage * +__imlib_ProduceImage(void) +{ + ImlibImage *im; + + im = malloc(sizeof(ImlibImage)); + memset(im, 0, sizeof(ImlibImage)); + im->data = NULL; + im->file = NULL; + im->real_file = NULL; + im->key = NULL; + im->flags = F_FORMAT_IRRELEVANT | F_BORDER_IRRELEVANT | F_ALPHA_IRRELEVANT; + im->loader = NULL; + im->next = NULL; + im->tags = NULL; + return im; +} + +/* free an image struct */ +void +__imlib_ConsumeImage(ImlibImage * im) +{ +#ifdef BUILD_X11 + ImlibImagePixmap *ip; +#endif + + __imlib_FreeAllTags(im); + if (im->file) + free(im->file); + if (im->real_file) + free(im->real_file); + if (im->key) + free(im->key); + if ((IMAGE_FREE_DATA(im)) && (im->data)) + free(im->data); + if (im->format) + free(im->format); + free(im); +#ifdef BUILD_X11 + ip = pixmaps; + while (ip) + { + if (ip->image == im) + { + ip->image = NULL; + ip->dirty = 1; + } + ip = ip->next; + } +#endif +} + +ImlibImage * +__imlib_FindCachedImage(const char *file) +{ + ImlibImage *im, *previous_im; + + im = images; + previous_im = NULL; + /* go through the images list */ + while (im) + { + /* if the filenames match and it's valid */ + if ((!strcmp(file, im->file)) && (IMAGE_IS_VALID(im))) + { + /* move the image to the head of the pixmap list */ + if (previous_im) + { + previous_im->next = im->next; + im->next = images; + images = im; + } + /* return it */ + return im; + } + previous_im = im; + im = im->next; + } + return NULL; +} + +/* add an image to the cache of images (at the start) */ +void +__imlib_AddImageToCache(ImlibImage * im) +{ + im->next = images; + images = im; +} + +/* remove (unlink) an image from the cache of images */ +void +__imlib_RemoveImageFromCache(ImlibImage * im) +{ + ImlibImage *current_im, *previous_im; + + current_im = images; + previous_im = NULL; + while (current_im) + { + if (im == current_im) + { + if (previous_im) + previous_im->next = im->next; + else + images = im->next; + return; + } + previous_im = current_im; + current_im = current_im->next; + } +} + +/* work out how much we have floaitng aroudn in our speculative cache */ +/* (images and pixmaps that have 0 reference counts) */ +int +__imlib_CurrentCacheSize(void) +{ + ImlibImage *im; + +#ifdef BUILD_X11 + ImlibImagePixmap *ip; +#endif + int current_cache = 0; + + /* go through the image cache */ + im = images; + while (im) + { + /* mayaswell clean out stuff thats invalid that we dont need anymore */ + if (im->references == 0) + { + if (!(IMAGE_IS_VALID(im))) + { + ImlibImage *tmp_im; + + tmp_im = im; + im = im->next; + __imlib_RemoveImageFromCache(tmp_im); + __imlib_ConsumeImage(tmp_im); +#ifdef BUILD_X11 + ip = pixmaps; + while (ip) + { + if (ip->image == tmp_im) + { + ip->image = NULL; + ip->dirty = 1; + } + ip = ip->next; + } +#endif + continue; + } + /* it's valid but has 0 ref's - append to cache size count */ + else + current_cache += im->w * im->h * sizeof(DATA32); + } + im = im->next; + } +#ifdef BUILD_X11 + /* go through the pixmaps */ + ip = pixmaps; + while (ip) + { + /* if the pixmap has 0 references */ + if (ip->references == 0) + { + /* if the image is invalid */ + if ((ip->dirty) || ((ip->image) && (!(IMAGE_IS_VALID(ip->image))))) + { + ImlibImagePixmap *tmp_ip; + + tmp_ip = ip; + ip = ip->next; + __imlib_RemoveImagePixmapFromCache(tmp_ip); + __imlib_ConsumeImagePixmap(tmp_ip); + continue; + } + else + { + /* add the pixmap data size to the cache size */ + if (ip->pixmap) + { + if (ip->depth < 8) + current_cache += ip->w * ip->h * (ip->depth / 8); + else if (ip->depth == 8) + current_cache += ip->w * ip->h; + else if (ip->depth <= 16) + current_cache += ip->w * ip->h * 2; + else if (ip->depth <= 32) + current_cache += ip->w * ip->h * 4; + } + /* if theres a mask add it too */ + if (ip->mask) + current_cache += ip->w * ip->h / 8; + } + } + ip = ip->next; + } +#endif + return current_cache; +} + +/* clean out images fromthe cache if the cache is overgrown */ +void +__imlib_CleanupImageCache(void) +{ + ImlibImage *im, *im_last; + int current_cache; + char operation = 1; + + current_cache = __imlib_CurrentCacheSize(); + im_last = NULL; + im = images; + /* remove 0 ref count invalid (dirty) images */ + while (im) + { + im_last = im; + im = im->next; + if ((im_last->references <= 0) && (!(IMAGE_IS_VALID(im_last)))) + { + __imlib_RemoveImageFromCache(im_last); + __imlib_ConsumeImage(im_last); + } + } + /* while the cache size of 0 ref coutn data is bigger than the set value */ + /* clean out the oldest members of the imaeg cache */ + while ((current_cache > cache_size) && (operation)) + { + im_last = NULL; + operation = 0; + im = images; + while (im) + { + if (im->references <= 0) + im_last = im; + im = im->next; + } + if (im_last) + { + __imlib_RemoveImageFromCache(im_last); + __imlib_ConsumeImage(im_last); + operation = 1; + } + if (operation) + current_cache = __imlib_CurrentCacheSize(); + } +} + +#ifdef BUILD_X11 +/* create a pixmap cache data struct */ +ImlibImagePixmap * +__imlib_ProduceImagePixmap(void) +{ + ImlibImagePixmap *ip; + + ip = malloc(sizeof(ImlibImagePixmap)); + memset(ip, 0, sizeof(ImlibImagePixmap)); + ip->display = NULL; + ip->visual = NULL; + ip->image = NULL; + ip->next = NULL; + ip->file = NULL; + return ip; +} + +/* free a pixmap cache data struct and the pixmaps in it */ +void +__imlib_ConsumeImagePixmap(ImlibImagePixmap * ip) +{ +#ifdef DEBUG_CACHE + fprintf(stderr, + "[Imlib2] Deleting pixmap. Reference count is %d, pixmap 0x%08x, mask 0x%08x\n", + ip->references, ip->pixmap, ip->mask); +#endif + if (ip->pixmap) + XFreePixmap(ip->display, ip->pixmap); + if (ip->mask) + XFreePixmap(ip->display, ip->mask); + if (ip->file) + free(ip->file); + free(ip); +} + +ImlibImagePixmap * +__imlib_FindCachedImagePixmap(ImlibImage * im, int w, int h, Display * d, + Visual * v, int depth, int sx, int sy, int sw, + int sh, Colormap cm, char aa, char hiq, + char dmask, DATABIG modification_count) +{ + ImlibImagePixmap *ip, *previous_ip; + + ip = pixmaps; + previous_ip = NULL; + /* go through the pixmap list */ + while (ip) + { + /* if all the pixmap attributes match */ + if ((ip->w == w) && (ip->h == h) && (ip->depth == depth) && (!ip->dirty) + && (ip->visual == v) && (ip->display == d) + && (ip->source_x == sx) && (ip->source_x == sy) + && (ip->source_w == sw) && (ip->source_h == sh) + && (ip->colormap == cm) && (ip->antialias == aa) + && (ip->modification_count == modification_count) + && (ip->dither_mask == dmask) + && (ip->border.left == im->border.left) + && (ip->border.right == im->border.right) + && (ip->border.top == im->border.top) + && (ip->border.bottom == im->border.bottom) && + (((im->file) && (ip->file) && !strcmp(im->file, ip->file)) || + ((!im->file) && (!ip->file) && (im == ip->image)))) + { + /* move the pixmap to the head of the pixmap list */ + if (previous_ip) + { + previous_ip->next = ip->next; + ip->next = pixmaps; + pixmaps = ip; + } + /* return it */ + return ip; + } + previous_ip = ip; + ip = ip->next; + } + return NULL; +} + +ImlibImagePixmap * +__imlib_FindCachedImagePixmapByID(Display * d, Pixmap p) +{ + ImlibImagePixmap *ip; + + ip = pixmaps; + /* go through the pixmap list */ + while (ip) + { + /* if all the pixmap attributes match */ + if ((ip->pixmap == p) && (ip->display == d)) + return ip; + ip = ip->next; + } + return NULL; +} + +/* add a pixmap cahce struct to the pixmap cache (at the start of course */ +void +__imlib_AddImagePixmapToCache(ImlibImagePixmap * ip) +{ + ip->next = pixmaps; + pixmaps = ip; +} + +/* remove a pixmap cache struct fromt he pixmap cache */ +void +__imlib_RemoveImagePixmapFromCache(ImlibImagePixmap * ip) +{ + ImlibImagePixmap *current_ip, *previous_ip; + + current_ip = pixmaps; + previous_ip = NULL; + while (current_ip) + { + if (ip == current_ip) + { + if (previous_ip) + previous_ip->next = ip->next; + else + pixmaps = ip->next; + return; + } + previous_ip = current_ip; + current_ip = current_ip->next; + } +} + +/* clean out 0 reference count & dirty pixmaps from the cache */ +void +__imlib_CleanupImagePixmapCache(void) +{ + ImlibImagePixmap *ip, *ip_last; + int current_cache; + char operation = 0; + + current_cache = __imlib_CurrentCacheSize(); + ip_last = NULL; + ip = pixmaps; + while (ip) + { + ip_last = ip; + ip = ip->next; + if ((ip_last->references <= 0) && (ip_last->dirty)) + { + __imlib_RemoveImagePixmapFromCache(ip_last); + __imlib_ConsumeImagePixmap(ip_last); + } + } + while ((current_cache > cache_size) && (operation)) + { + ip_last = NULL; + operation = 0; + ip = pixmaps; + while (ip) + { + if (ip->references <= 0) + ip_last = ip; + ip = ip->next; + } + if (ip_last) + { + __imlib_RemoveImagePixmapFromCache(ip_last); + __imlib_ConsumeImagePixmap(ip_last); + operation = 1; + } + if (operation) + current_cache = __imlib_CurrentCacheSize(); + } +} +#endif + +#define LOADERS_UNINITIALISED -4444 + +static int errors = LOADERS_UNINITIALISED; + +/* try dlopen()ing the file if we succeed finish filling out the malloced */ +/* loader struct and return it */ +ImlibLoader * +__imlib_ProduceLoader(char *file) +{ + ImlibLoader *l; + void (*l_formats) (ImlibLoader * l); + + l = malloc(sizeof(ImlibLoader)); + l->num_formats = 0; + l->formats = NULL; + l->handle = dlopen(file, RTLD_NOW | RTLD_LOCAL); + if (!l->handle) + { + free(l); + return NULL; + } + l->load = dlsym(l->handle, "load"); + l->save = dlsym(l->handle, "save"); + l_formats = dlsym(l->handle, "formats"); + + /* each loader must provide formats() and at least load() or save() */ + if (!l_formats || (!l->load && !l->save)) + { + dlclose(l->handle); + free(l); + return NULL; + } + l_formats(l); + l->file = strdup(file); + l->next = NULL; + return l; +} + +/* list all the filenames of loaders int he system loaders dir and the user */ +/* loader dir */ +char ** +__imlib_ListLoaders(int *num_ret) +{ + char **list = NULL, **l, *s; + int num, i, pi = 0; + + *num_ret = 0; + /* same for system loader path */ + s = (char *)malloc(sizeof(SYS_LOADERS_PATH) + 8 + 1); + sprintf(s, SYS_LOADERS_PATH "/loaders"); +#ifndef __EMX__ + l = __imlib_FileDir(s, &num); +#else + l = __imlib_FileDir(__XOS2RedirRoot(s), &num); +#endif + if (num > 0) + { + *num_ret += num; + list = realloc(list, sizeof(char *) * *num_ret); + + for (i = 0; i < num; i++) + { + s = (char *)realloc(s, + sizeof(SYS_LOADERS_PATH) + 9 + strlen(l[i]) + + 1); + sprintf(s, SYS_LOADERS_PATH "/loaders/%s", l[i]); +#ifndef __EMX__ + list[pi + i] = strdup(s); +#else + list[pi + i] = strdup(__XOS2RedirRoot(s)); +#endif + } + __imlib_FileFreeDirList(l, num); + } + free(s); + + /* List currently contains *everything in there* we need to weed out + * the .so, .la, .a versions of the same loader or whatever else. + * dlopen can take an extension-less name and do the Right Thing + * with it, so that's what we'll give it. */ + list = __imlib_TrimLoaderList(list, num_ret); + + return list; +} + +char ** +__imlib_TrimLoaderList(char **list, int *num) +{ + int i, n, size = 0; + + char **ret = NULL; + + if (!list) + return NULL; + if (*num == 0) + return list; + + n = *num; + + for (i = 0; i < n; i++) + { + char *ext; + + if (!list[i]) + continue; + ext = strrchr(list[i], '.'); + if ((ext) && (!strcasecmp(ext, ".so"))) + { + /* Don't add the same loader multiple times... */ + if (!__imlib_ItemInList(ret, size, list[i])) + { + ret = realloc(ret, sizeof(char *) * (size + 1)); + + ret[size++] = strdup(list[i]); + } + } + if (list[i]) + free(list[i]); + } + if (list) + free(list); + *num = size; + return ret; +} + +int +__imlib_ItemInList(char **list, int size, char *item) +{ + int i; + + if (!size) + return 0; + if (!list) + return 0; + if (!item) + return 0; + + for (i = 0; i < size; i++) + { + if (!strcmp(list[i], item)) + return 1; + } + return 0; +} + +/* fre the struct for a loader and close its dlopen'd handle */ +void +__imlib_ConsumeLoader(ImlibLoader * l) +{ + if (l->file) + free(l->file); + if (l->handle) + dlclose(l->handle); + if (l->formats) + { + int i; + + for (i = 0; i < l->num_formats; i++) + free(l->formats[i]); + free(l->formats); + } + free(l); +} + +void +__imlib_RescanLoaders(void) +{ + static time_t last_scan_time = 0; + static time_t last_modified_system_time = 0; + time_t current_time; + char do_reload = 0; + + /* dont stat the dir and rescan if we checked in the last 5 seconds */ + current_time = time(NULL); + if ((current_time - last_scan_time) < 5) + return; + /* ok - was the system loaders dir contents modified ? */ + last_scan_time = current_time; +#ifndef __EMX__ + if (__imlib_FileIsDir(SYS_LOADERS_PATH "/loaders/")) +#else + if (__imlib_FileIsDir(__XOS2RedirRoot(SYS_LOADERS_PATH "/loaders/"))) +#endif + { +#ifndef __EMX__ + current_time = __imlib_FileModDate(SYS_LOADERS_PATH "/loaders/"); +#else + current_time = + __imlib_FileModDate(__XOS2RedirRoot(SYS_LOADERS_PATH "/loaders/")); +#endif + if (current_time > last_modified_system_time) + { + /* yup - set the "do_reload" flag */ + do_reload = 1; + last_modified_system_time = current_time; + } + } + /* if we dont ned to reload the loaders - get out now */ + if (!do_reload) + return; + __imlib_RemoveAllLoaders(); + __imlib_LoadAllLoaders(); +} + +/* remove all loaders int eh list we have cached so we can re-load them */ +void +__imlib_RemoveAllLoaders(void) +{ + ImlibLoader *l, *il; + + l = loaders; + while (l) + { + il = l; + l = l->next; + __imlib_ConsumeLoader(il); + } + loaders = NULL; +} + +/* find all the loaders we can find and load them up to see what they can */ +/* load / save */ +void +__imlib_LoadAllLoaders(void) +{ + int i, num; + char **list; + + /* list all the loaders imlib can find */ + list = __imlib_ListLoaders(&num); + /* no loaders? well don't load anything */ + if (!list) + return; + + /* go through the list of filenames for loader .so's and load them */ + /* (or try) and if it succeeds, append to our loader list */ + for (i = num - 1; i >= 0; i--) + { + ImlibLoader *l; + + l = __imlib_ProduceLoader(list[i]); + if (l) + { + l->next = loaders; + loaders = l; + } + if (list[i]) + free(list[i]); + } + free(list); +} + +ImlibLoader * +__imlib_FindBestLoaderForFile(const char *file, int for_save) +{ + char *extension, *lower, *rfile; + ImlibLoader *l = NULL; + + /* use the file extension for a "best guess" as to what loader to try */ + /* first at any rate */ + + rfile = __imlib_FileRealFile(file); + extension = __imlib_FileExtension(rfile); + free(rfile); + /* change the extensiont o all lower case as all "types" are listed as */ + /* lower case strings fromt he loader that represent all the possible */ + /* extensions that file format could have */ + lower = extension; + while (*lower) + { + *lower = tolower(*lower); + lower++; + } + if (!extension) + return NULL; + /* go through the loaders - first loader that claims to handle that */ + /* image type (extension wise) wins as a first guess to use - NOTE */ + /* this is an OPTIMISATION - it is possible the file has no extension */ + /* or has an unrecognised one but still is loadable by a loader. */ + /* if thkis initial loader failes to load the load mechanism will */ + /* systematically go from most recently used to least recently used */ + /* loader until one succeeds - or none are left and all have failed */ + /* and only if all fail does the laod fail. the lao9der that does */ + /* succeed gets it way tot he head of the list so it's going */ + /* to be used first next time in this search mechanims - this */ + /* assumes you tend to laod a few image types and ones generally */ + /* of the same format */ + l = loaders; + while (l) + { + int i; + + /* go through all the formats that loader supports */ + for (i = 0; i < l->num_formats; i++) + { + /* does it match ? */ + if (!strcmp(l->formats[i], extension)) + { + /* does it provide the function we need? */ + if ((for_save && l->save) || (!for_save && l->load)) + { + /* free the memory allocated for the extension */ + free(extension); + /* return the loader */ + return l; + } + } + } + l = l->next; + } + /* free the memory allocated for the extension */ + free(extension); + /* return the loader */ + return l; +} + +ImlibLoader * +__imlib_FindBestLoaderForFileFormat(const char *file, char *format, + int for_save) +{ + char *extension, *lower; + ImlibLoader *l = NULL; + + /* if the format is provided ("png" "jpg" etc.) use that */ + if (format) + extension = strdup(format); + /* otherwise us the extension */ + else + { + extension = __imlib_FileExtension(file); + /* change the extension to all lower case as all "types" are listed as */ + /* lower case strings fromt he loader that represent all the possible */ + /* extensions that file format could have */ + if (extension) + { + lower = extension; + while (*lower) + { + *lower = tolower(*lower); + lower++; + } + } + } + if (!extension) + return NULL; + /* look through the loaders one by one to see if one matches that format */ + l = loaders; + while (l) + { + int i; + + /* go through all the formats that loader supports */ + for (i = 0; i < l->num_formats; i++) + { + /* does it match ? */ + if (!strcmp(l->formats[i], extension)) + { + /* does it provide the function we need? */ + if ((for_save && l->save) || (!for_save && l->load)) + { + /* free the memory allocated for the extension */ + free(extension); + /* return the loader */ + return l; + } + } + } + l = l->next; + } + /* free the memory allocated for the extension */ + free(extension); + /* return the loader */ + return l; +} + +/* set or unset the alpha flag on the umage (alpha = 1 / 0 ) */ +void +__imlib_SetImageAlphaFlag(ImlibImage * im, char alpha) +{ + if (alpha) + SET_FLAG(im->flags, F_HAS_ALPHA); + else + UNSET_FLAG(im->flags, F_HAS_ALPHA); +} + +/* create a new image struct from data passed that is wize w x h then return */ +/* a pointer to that image sturct */ +ImlibImage * +__imlib_CreateImage(int w, int h, DATA32 * data) +{ + ImlibImage *im; + + im = __imlib_ProduceImage(); + im->w = w; + im->h = h; + im->data = data; + im->references = 1; + SET_FLAG(im->flags, F_UNCACHEABLE); + return im; +} + +ImlibImage * +__imlib_LoadImage(const char *file, ImlibProgressFunction progress, + char progress_granularity, char immediate_load, + char dont_cache, ImlibLoadError * er) +{ + ImlibImage *im; + ImlibLoader *best_loader; + char loader_ret = 0; + + if (!file) + return NULL; + if (file[0] == 0) + return NULL; + /* see if we alreayd have the image cached */ + im = __imlib_FindCachedImage(file); + /* if we found a cached image and we shoudl always check that it is */ + /* accurate to the disk conents if they changed since we last loaded */ + /* and that it is still a valid image */ + if ((im) && (IMAGE_IS_VALID(im))) + { + if (IMAGE_ALWAYS_CHECK_DISK(im)) + { + time_t current_modified_time; + + current_modified_time = __imlib_FileModDate(file); + /* if the file on disk is newer than the cached one */ + if (current_modified_time > im->moddate) + { + /* invalidate image */ + SET_FLAG(im->flags, F_INVALID); + } + else + { + /* image is ok to re-use - program is just being stupid loading */ + /* the same data twice */ + im->references++; + return im; + } + } + else + { + im->references++; + return im; + } + } + /* either image in cache is invalid or we dont even have it in cache */ + /* so produce a new one and load an image into that */ + im = __imlib_ProduceImage(); + im->file = strdup(file); + if (__imlib_IsRealFile(file)) + { + im->real_file = strdup(im->file); + im->key = NULL; + } + else + { + im->real_file = __imlib_FileRealFile(file); + im->key = __imlib_FileKey(file); + } + im->moddate = __imlib_FileModDate(file); + /* ok - just check all our loaders are up to date */ + __imlib_RescanLoaders(); + /* take a guess by extension on the best loader to use */ + best_loader = __imlib_FindBestLoaderForFile(im->real_file, 0); + errno = 0; + if (best_loader) + loader_ret = + best_loader->load(im, progress, progress_granularity, immediate_load); + /* width is still 0 - the loader didnt manage to do anything */ + if (im->w == 0) + { + ImlibLoader *l, *previous_l = NULL; + + errno = 0; + l = loaders; + /* run through all loaders and try load until one succeeds */ + while ((l) && (im->w == 0)) + { + /* if its not the best loader that alreayd failed - try load */ + if (l != best_loader) + loader_ret = + l->load(im, progress, progress_granularity, immediate_load); + /* if it failed - advance */ + if (im->w == 0) + { + previous_l = l; + l = l->next; + } + } + /* if we have a loader then its the loader that succeeded */ + /* move the successful loader to the head of the list */ + /* as long as it's not alreayd at the head of the list */ + if ((l) && (previous_l)) + { + im->loader = l; + previous_l->next = l->next; + l->next = loaders; + loaders = l; + } + if (im->w > 0) + im->loader = l; + } + else + im->loader = best_loader; + /* all loaders have been tried and they all failed. free the skeleton */ + /* image struct we had and return NULL */ + if (im->w == 0) + { + /* if the caller wants an error return */ + if (er) + { + /* set to a default fo no error */ + *er = LOAD_ERROR_NONE; + /* if the errno is set */ + if (errno != 0) + { + /* default to unknown error */ + *er = LOAD_ERROR_UNKNOWN; + /* standrad fopen() type errors translated */ + if (errno == EEXIST) + *er = LOAD_ERROR_FILE_DOES_NOT_EXIST; + else if (errno == EISDIR) + *er = LOAD_ERROR_FILE_IS_DIRECTORY; + else if (errno == EISDIR) + *er = LOAD_ERROR_FILE_IS_DIRECTORY; + else if (errno == EACCES) + *er = LOAD_ERROR_PERMISSION_DENIED_TO_READ; + else if (errno == ENAMETOOLONG) + *er = LOAD_ERROR_PATH_TOO_LONG; + else if (errno == ENOENT) + *er = LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT; + else if (errno == ENOTDIR) + *er = LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY; + else if (errno == EFAULT) + *er = LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE; + else if (errno == ELOOP) + *er = LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS; + else if (errno == ENOMEM) + *er = LOAD_ERROR_OUT_OF_MEMORY; + else if (errno == EMFILE) + *er = LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS; + if (*er != LOAD_ERROR_UNKNOWN) + { + /* free the stuct we created */ + __imlib_ConsumeImage(im); + return NULL; + } + } + errno = 0; + } + __imlib_ConsumeImage(im); + return NULL; + } + + /* the load succeeded - make sure the image is referenced then add */ + /* it to our cache if dont_cache isn't set */ + im->references = 1; + if (loader_ret == 2) + dont_cache = 1; + if (!dont_cache) + __imlib_AddImageToCache(im); + else + SET_FLAG(im->flags, F_UNCACHEABLE); + return im; +} + +#ifdef BUILD_X11 +/* find an imagepixmap cache entry by the display and pixmap id */ +ImlibImagePixmap * +__imlib_FindImlibImagePixmapByID(Display * d, Pixmap p) +{ + ImlibImagePixmap *ip; + + ip = pixmaps; + /* go through the pixmap list */ + while (ip) + { + /* if all the pixmap ID & Display match */ + if ((ip->pixmap == p) && (ip->display == d)) + { +#ifdef DEBUG_CACHE + fprintf(stderr, + "[Imlib2] Match found. Reference count is %d, pixmap 0x%08x, mask 0x%08x\n", + ip->references, ip->pixmap, ip->mask); +#endif + return ip; + } + ip = ip->next; + } + return NULL; +} +#endif + +/* free and image - if its uncachable and refcoutn is 0 - free it in reality */ +void +__imlib_FreeImage(ImlibImage * im) +{ + /* if the refcount is positive */ + if (im->references >= 0) + { + /* reduce a reference from the count */ + im->references--; + /* if its uncachchable ... */ + if (IMAGE_IS_UNCACHEABLE(im)) + { + /* and we're down to no references for the image then free it */ + if (im->references == 0) + __imlib_ConsumeImage(im); + } + /* otherwise clean up our cache if the image becoem 0 ref count */ + else if (im->references == 0) + __imlib_CleanupImageCache(); + } +} + +#ifdef BUILD_X11 +/* free a cached pixmap */ +void +__imlib_FreePixmap(Display * d, Pixmap p) +{ + ImlibImagePixmap *ip; + + /* find the pixmap in the cache by display and id */ + ip = __imlib_FindImlibImagePixmapByID(d, p); + if (ip) + { + /* if tis positive reference count */ + if (ip->references > 0) + { + /* dereference it by one */ + ip->references--; +#ifdef DEBUG_CACHE + fprintf(stderr, + "[Imlib2] Reference count is now %d for pixmap 0x%08x\n", + ip->references, ip->pixmap); +#endif + /* if it becaume 0 reference count - clean the cache up */ + if (ip->references == 0) + __imlib_CleanupImagePixmapCache(); + } + } + else + { +#ifdef DEBUG_CACHE + fprintf(stderr, "[Imlib2] Pixmap 0x%08x not found. Freeing.\n", p); +#endif + XFreePixmap(d, p); + } +} + +/* mark all pixmaps generated from this image as dirty so the cache code */ +/* wont pick up on them again since they are now invalid since the original */ +/* data they were generated from has changed */ +void +__imlib_DirtyPixmapsForImage(ImlibImage * im) +{ + ImlibImagePixmap *ip; + + ip = pixmaps; + /* go through the pixmap list */ + while (ip) + { + /* if image matches */ + if (ip->image == im) + ip->dirty = 1; + ip = ip->next; + } + __imlib_CleanupImagePixmapCache(); +} +#endif + +/* dirty and image by settings its invalid flag */ +void +__imlib_DirtyImage(ImlibImage * im) +{ + SET_FLAG(im->flags, F_INVALID); + /* and dirty all pixmaps generated from it */ + __imlib_DirtyPixmapsForImage(im); +} + +void +__imlib_SaveImage(ImlibImage * im, const char *file, + ImlibProgressFunction progress, char progress_granularity, + ImlibLoadError * er) +{ + ImlibLoader *l; + char e, *pfile; + + if (!file) + { + if (er) + *er = LOAD_ERROR_FILE_DOES_NOT_EXIST; + return; + } + /* ok - just check all our loaders are up to date */ + __imlib_RescanLoaders(); + /* set the filename to the saved one */ + pfile = im->file; + im->file = strdup(file); + + if (im->real_file) + free(im->real_file); + + im->real_file = strdup(im->file); + + /* find the laoder for the format - if its null use the extension */ + l = __imlib_FindBestLoaderForFileFormat(im->real_file, im->format, 1); + /* no loader - abort */ + if (!l) + { + if (er) + *er = LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT; + /* set the filename back to the laoder image filename */ + free(im->file); + im->file = pfile; + return; + } + /* if they want an error returned - assume none by default */ + if (er) + *er = LOAD_ERROR_NONE; + + /* call the saver */ + e = l->save(im, progress, progress_granularity); + /* set the filename back to the laoder image filename */ + free(im->file); + im->file = pfile; + + /* if there's an error return and the save faile (e = 0) figure it out */ + if ((er) && (e == 0)) + { + *er = LOAD_ERROR_UNKNOWN; + if (errno == EEXIST) + *er = LOAD_ERROR_FILE_DOES_NOT_EXIST; + else if (errno == EISDIR) + *er = LOAD_ERROR_FILE_IS_DIRECTORY; + else if (errno == EISDIR) + *er = LOAD_ERROR_FILE_IS_DIRECTORY; + else if (errno == EACCES) + *er = LOAD_ERROR_PERMISSION_DENIED_TO_WRITE; + else if (errno == ENAMETOOLONG) + *er = LOAD_ERROR_PATH_TOO_LONG; + else if (errno == ENOENT) + *er = LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT; + else if (errno == ENOTDIR) + *er = LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY; + else if (errno == EFAULT) + *er = LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE; + else if (errno == ELOOP) + *er = LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS; + else if (errno == ENOMEM) + *er = LOAD_ERROR_OUT_OF_MEMORY; + else if (errno == EMFILE) + *er = LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS; + else if (errno == ENOSPC) + *er = LOAD_ERROR_OUT_OF_DISK_SPACE; + else if (errno == EROFS) + *er = LOAD_ERROR_PERMISSION_DENIED_TO_WRITE; + } +} diff --git a/src/lib/image.h b/src/lib/image.h new file mode 100644 index 0000000..6f0c1a5 --- /dev/null +++ b/src/lib/image.h @@ -0,0 +1,202 @@ +#ifndef __IMAGE +# define __IMAGE 1 + +#include "common.h" +#ifdef BUILD_X11 +#include +#endif + +#include + +typedef struct _imlibimage ImlibImage; +#ifdef BUILD_X11 +typedef struct _imlibimagepixmap ImlibImagePixmap; +#endif +typedef struct _imlibborder ImlibBorder; +typedef struct _imlibloader ImlibLoader; +typedef struct _imlibimagetag ImlibImageTag; + +typedef int (*ImlibProgressFunction)(ImlibImage *im, char percent, + int update_x, int update_y, + int update_w, int update_h); +typedef void (*ImlibDataDestructorFunction)(ImlibImage *im, void *data); + +enum _load_error +{ + LOAD_ERROR_NONE, + LOAD_ERROR_FILE_DOES_NOT_EXIST, + LOAD_ERROR_FILE_IS_DIRECTORY, + LOAD_ERROR_PERMISSION_DENIED_TO_READ, + LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT, + LOAD_ERROR_PATH_TOO_LONG, + LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT, + LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY, + LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE, + LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS, + LOAD_ERROR_OUT_OF_MEMORY, + LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS, + LOAD_ERROR_PERMISSION_DENIED_TO_WRITE, + LOAD_ERROR_OUT_OF_DISK_SPACE, + LOAD_ERROR_UNKNOWN +}; + +enum _iflags +{ + F_NONE = 0, + F_HAS_ALPHA = (1 << 0), + F_UNLOADED = (1 << 1), + F_UNCACHEABLE = (1 << 2), + F_ALWAYS_CHECK_DISK = (1 << 3), + F_INVALID = (1 << 4), + F_DONT_FREE_DATA = (1 << 5), + F_FORMAT_IRRELEVANT = (1 << 6), + F_BORDER_IRRELEVANT = (1 << 7), + F_ALPHA_IRRELEVANT = (1 << 8) +}; + +typedef enum _iflags ImlibImageFlags; +typedef enum _load_error ImlibLoadError; + +struct _imlibborder +{ + int left, right, top, bottom; +}; + +struct _imlibimagetag +{ + char *key; + int val; + void *data; + void (*destructor)(ImlibImage *im, void *data); + ImlibImageTag *next; +}; + +struct _imlibimage +{ + char *file; + int w, h; + DATA32 *data; + ImlibImageFlags flags; + time_t moddate; + ImlibBorder border; + int references; + ImlibLoader *loader; + char *format; + ImlibImage *next; + ImlibImageTag *tags; + char *real_file; + char *key; +}; + +#ifdef BUILD_X11 +struct _imlibimagepixmap +{ + int w, h; + Pixmap pixmap, mask; + Display *display; + Visual *visual; + int depth; + int source_x, source_y, source_w, source_h; + Colormap colormap; + char antialias, hi_quality, dither_mask; + ImlibBorder border; + ImlibImage *image; + char *file; + char dirty; + int references; + DATABIG modification_count; + ImlibImagePixmap *next; +}; +#endif + +struct _imlibloader +{ + char *file; + int num_formats; + char **formats; + void *handle; + char (*load)(ImlibImage *im, + ImlibProgressFunction progress, + char progress_granularity, char immediate_load); + char (*save)(ImlibImage *im, + ImlibProgressFunction progress, + char progress_granularity); + ImlibLoader *next; +}; + +void __imlib_AttachTag(ImlibImage *im, const char *key, int val, void *data, + ImlibDataDestructorFunction destructor); +ImlibImageTag *__imlib_GetTag(ImlibImage *im, const char *key); +ImlibImageTag *__imlib_RemoveTag(ImlibImage *im, const char *key); +void __imlib_FreeTag(ImlibImage *im, ImlibImageTag *t); +void __imlib_FreeAllTags(ImlibImage *im); + +void __imlib_SetCacheSize(int size); +int __imlib_GetCacheSize(void); +ImlibImage *__imlib_ProduceImage(void); +void __imlib_ConsumeImage(ImlibImage *im); +ImlibImage *__imlib_FindCachedImage(const char *file); +void __imlib_AddImageToCache(ImlibImage *im); +void __imlib_RemoveImageFromCache(ImlibImage *im); +int __imlib_CurrentCacheSize(void); +void __imlib_CleanupImageCache(void); +#ifdef BUILD_X11 +ImlibImagePixmap *__imlib_ProduceImagePixmap(void); +void __imlib_ConsumeImagePixmap(ImlibImagePixmap *ip); +ImlibImagePixmap *__imlib_FindCachedImagePixmap(ImlibImage *im, int w, int h, + Display *d, Visual *v, + int depth, int sx, int sy, + int sw, int sh, Colormap cm, + char aa, char hiq, char dmask, + DATABIG modification_count); +ImlibImagePixmap *__imlib_FindCachedImagePixmapByID(Display *d, Pixmap p); +void __imlib_AddImagePixmapToCache(ImlibImagePixmap *ip); +void __imlib_RemoveImagePixmapFromCache(ImlibImagePixmap *ip); +void __imlib_CleanupImagePixmapCache(void); +#endif +ImlibLoader *__imlib_ProduceLoader(char *file); +char **__imlib_ListLoaders(int *num_ret); +char **__imlib_TrimLoaderList(char **list, int *num); +int __imlib_ItemInList(char **list, int size, char *item); +void __imlib_ConsumeLoader(ImlibLoader *l); +void __imlib_RescanLoaders(void); +void __imlib_RemoveAllLoaders(void); +void __imlib_LoadAllLoaders(void); +ImlibLoader *__imlib_FindBestLoaderForFile(const char *file, int for_save); +ImlibLoader *__imlib_FindBestLoaderForFileFormat(const char *file, char *format, int for_save); +void __imlib_SetImageAlphaFlag(ImlibImage *im, char alpha); +ImlibImage *__imlib_CreateImage(int w, int h, DATA32 *data); +ImlibImage *__imlib_LoadImage(const char *file, + ImlibProgressFunction progress, + char progress_granularity, char immediate_load, + char dont_cache, ImlibLoadError *er); +#ifdef BUILD_X11 +ImlibImagePixmap *__imlib_FindImlibImagePixmapByID(Display *d, Pixmap p); +#endif +void __imlib_FreeImage(ImlibImage *im); +#ifdef BUILD_X11 +void __imlib_FreePixmap(Display *d, Pixmap p); +#endif +void __imlib_FlushCache(void); +#ifdef BUILD_X11 +void __imlib_DirtyPixmapsForImage(ImlibImage *im); +#else +#define __imlib_DirtyPixmapsForImage(x) /* x */ +#endif +void __imlib_DirtyImage(ImlibImage *im); +void __imlib_SaveImage(ImlibImage *im, const char *file, + ImlibProgressFunction progress, + char progress_granularity, + ImlibLoadError *er); + +# define IMAGE_HAS_ALPHA(im) ((im)->flags & F_HAS_ALPHA) +# define IMAGE_IS_UNLOADED(im) ((im)->flags & F_UNLOADED) +# define IMAGE_IS_UNCACHEABLE(im) ((im)->flags & F_UNCACHEABLE) +# define IMAGE_ALWAYS_CHECK_DISK(im) ((im)->flags & F_ALWAYS_CHECK_DISK) +# define IMAGE_IS_VALID(im) (!((im)->flags & F_INVALID)) +# define IMAGE_FREE_DATA(im) (!((im)->flags & F_DONT_FREE_DATA)) + +# define SET_FLAG(flags, f) ((flags) |= (f)) +# define UNSET_FLAG(flags, f) ((flags) &= (~f)) + +#endif diff --git a/src/lib/libimlib2.la b/src/lib/libimlib2.la new file mode 100644 index 0000000..41ab148 --- /dev/null +++ b/src/lib/libimlib2.la @@ -0,0 +1,35 @@ +# libimlib2.la - a libtool library file +# Generated by ltmain.sh - GNU libtool 1.5.6 (1.1220.2.95 2004/04/11 05:50:42) Debian: 215 $ +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='libimlib2.so.1' + +# Names of this library. +library_names='libimlib2.so.1.1.2 libimlib2.so.1 libimlib2.so' + +# The name of the static archive. +old_library='libimlib2.a' + +# Libraries that this one depends upon. +dependency_libs=' /usr/lib/gcc-lib/i486-linux/3.3.4/../../..//libfreetype.la -lz -L/usr/X11R6/lib -lX11 -lXext -ldl' + +# Version information for libimlib2. +current=2 +age=1 +revision=2 + +# Is this an already installed library? +installed=no + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/usr/local/lib' diff --git a/src/lib/line.c b/src/lib/line.c new file mode 100644 index 0000000..9675327 --- /dev/null +++ b/src/lib/line.c @@ -0,0 +1,711 @@ +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include "span.h" +#include "updates.h" +#include "rgbadraw.h" + + +#define EXCHANGE_POINTS(x0, y0, x1, y1) \ +{ \ + int _tmp = y0; \ + \ + y0 = y1; \ + y1 = _tmp; \ + \ + _tmp = x0; \ + x0 = x1; \ + x1 = _tmp; \ +} + + +ImlibUpdate * +__imlib_Point_DrawToImage(int x, int y, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend, char make_updates) +{ + ImlibPointDrawFunction pfunc; + + if (blend && (!A_VAL(&color))) + return NULL; + if (!IN_RANGE(x, y, im->w, im->h)) + return NULL; + if (clw == 0) + { + clw = im->w; + clx = 0; + clh = im->h; + cly = 0; + } + if (!IN_RECT(x,y,clx,cly,clw,clh)) + return NULL; + + if (A_VAL(&color) == 0xff) + blend = 0; + if (blend && IMAGE_HAS_ALPHA(im)) + __imlib_build_pow_lut(); + + pfunc = __imlib_GetPointDrawFunction(op, IMAGE_HAS_ALPHA(im), blend); + if (pfunc) + pfunc(color, im->data + (im->w * y) + x); + if (make_updates) + return __imlib_AddUpdate(NULL, x, y, 1, 1); + return NULL; +} + + +static int +__imlib_SimpleLine_DrawToData(int x0, int y0, int x1, int y1, DATA32 color, + DATA32 *dst, int dstw, int clx, int cly, int clw, int clh, + int *cl_x0, int *cl_y0, int *cl_x1, int *cl_y1, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibPointDrawFunction pfunc; + ImlibSpanDrawFunction sfunc; + int dx, dy, len, lx, ty, rx, by; + DATA32 *p; + + if (A_VAL(&color) == 0xff) blend = 0; + + if (y0 > y1) + EXCHANGE_POINTS(x0, y0, x1, y1) + + dx = x1 - x0; + dy = y1 - y0; + + lx = clx; + rx = clx + clw - 1; + ty = cly; + by = cly + clh - 1; + + if ((x0 < lx) && (x1 < lx)) return 0; + if ((x0 > rx) && (x1 > rx)) return 0; + if ((y0 > by) || (y1 < ty)) return 0; + + if (dy == 0) + { + sfunc = __imlib_GetSpanDrawFunction(op, dst_alpha, blend); + if (!sfunc) return 0; + + if (dx < 0) + { + int tmp = x1; + + x1 = x0; + x0 = tmp; + } + + if (x0 < lx) x0 = lx; + if (x1 > rx) x1 = rx; + + len = x1 - x0 + 1; + + p = dst + (dstw * y0) + x0; + + sfunc(color, p, len); + + *cl_x0 = x0; + *cl_y0 = y0; + *cl_x1 = x1; + *cl_y1 = y1; + + return 1; + } + + pfunc = __imlib_GetPointDrawFunction(op, dst_alpha, blend); + if (!pfunc) return 0; + + if (dx == 0) + { + if (y0 < ty) y0 = ty; + if (y1 > by) y1 = by; + + len = y1 - y0 + 1; + + p = dst + (dstw * y0) + x0; + + while (len--) + { + pfunc(color, p); + p += dstw; + } + + *cl_x0 = x0; + *cl_y0 = y0; + *cl_x1 = x1; + *cl_y1 = y1; + + return 1; + } + + if ((dy == dx) || (dy == -dx)) + { + int p0_in, p1_in; + + p0_in = (IN_RECT(x0, y0, clx, cly, clw, clh) ? 1 : 0); + p1_in = (IN_RECT(x1, y1, clx, cly, clw, clh) ? 1 : 0); + + if (dx > 0) + { + if (!p0_in) + { + x0 = x0 + (ty - y0); + y0 = ty; + if (x0 > rx) return 0; + if (x0 < lx) + { + y0 = y0 + (lx - x0); + x0 = lx; + if ((y0 < ty) || (y0 > by)) return 0; + } + } + if (!p1_in) + { + x1 = x0 + (by - y0); + y1 = by; + if (x1 < lx) return 0; + if (x1 > rx) + { + y1 = y0 + (rx - x0); + x1 = rx; + if ((y1 < ty) || (y1 > by)) return 0; + } + } + } + else + { + if (!p0_in) + { + x0 = x0 - (ty - y0); + y0 = ty; + if (x0 < lx) return 0; + if (x0 > rx) + { + y0 = y0 - (rx - x0); + x0 = rx; + if ((y0 < ty) || (y0 > by)) return 0; + } + } + if (!p1_in) + { + x1 = x0 - (by - y0); + y1 = by; + if (x1 > rx) return 0; + if (x1 < lx) + { + y1 = y0 - (lx - x0); + x1 = lx; + if ((y1 < ty) || (y1 > by)) return 0; + } + } + } + + len = y1 - y0 + 1; + + p = dst + (dstw * y0) + x0; + if (dx > 0) dstw++; + else dstw--; + + while (len--) + { + pfunc(color, p); + p += dstw; + } + } + + *cl_x0 = x0; + *cl_y0 = y0; + *cl_x1 = x1; + *cl_y1 = y1; + + return 1; +} + + +#define SETUP_LINE_SHALLOW \ + if (x0 > x1) \ + { \ + EXCHANGE_POINTS(x0, y0, x1, y1) \ + dx = -dx; \ + dy = -dy; \ + } \ + \ + px = x0; \ + py = y0; \ + \ + p0_in = (IN_RANGE(x0 ,y0 , clw, clh) ? 1 : 0); \ + p1_in = (IN_RANGE(x1 ,y1 , clw, clh) ? 1 : 0); \ + \ + dely = 1; \ + dh = dstw; \ + if (dy < 0) \ + { \ + dely = -1; \ + dh = -dstw; \ + } \ + \ + dyy = (dy << 16) / dx; \ + \ + if (!p0_in) \ + { \ + dxx = (dx << 16) / dy; \ + if (px < 0) \ + { \ + x = -px; px = 0; \ + yy = x * dyy; \ + y = yy >> 16; \ + if (!a_a) \ + y += (yy - (y << 16)) >> 15; \ + py += y; \ + if ((dely > 0) && (py >= clh)) \ + return 0; \ + else if ((dely < 0) && (py < -1)) \ + return 0; \ + } \ + \ + y = 0; \ + if ((dely > 0) && (py < -1)) \ + y = (-1 - py); \ + else if ((dely < 0) && (py >= clh)) \ + y = (clh - 1 - py); \ + \ + xx = y * dxx; \ + x = xx >> 16; \ + if (!a_a) \ + x += (xx - (x << 16)) >> 15; \ + px += x; \ + if (px >= clw) return 0; \ + \ + yy = x * dyy; \ + y = yy >> 16; \ + if (!a_a) \ + y += (yy - (y << 16)) >> 15; \ + py += y; \ + if ((dely > 0) && (py >= clh)) \ + return 0; \ + else if ((dely < 0) && (py < -1)) \ + return 0; \ + } \ + \ + p = dst + (dstw * py) + px; \ + \ + x = px - x0; \ + yy = x * dyy; \ + prev_y = (yy >> 16); \ + \ + rx = MIN(x1 + 1, clw); \ + by = clh - 1; + + +#define SETUP_LINE_STEEP \ + if (y0 > y1) \ + { \ + EXCHANGE_POINTS(x0, y0, x1, y1) \ + dx = -dx; \ + dy = -dy; \ + } \ + \ + px = x0; \ + py = y0; \ + \ + p0_in = (IN_RANGE(x0 ,y0 , clw, clh) ? 1 : 0); \ + p1_in = (IN_RANGE(x1 ,y1 , clw, clh) ? 1 : 0); \ + \ + delx = 1; \ + if (dx < 0) \ + delx = -1; \ + \ + dxx = (dx << 16) / dy; \ + \ + if (!p0_in) \ + { \ + dyy = (dy << 16) / dx; \ + \ + if (py < 0) \ + { \ + y = -py; py = 0; \ + xx = y * dxx; \ + x = xx >> 16; \ + if (!a_a) \ + x += (xx - (x << 16)) >> 15; \ + px += x; \ + if ((delx > 0) && (px >= clw)) \ + return 0; \ + else if ((delx < 0) && (px < -1)) \ + return 0; \ + } \ + \ + x = 0; \ + if ((delx > 0) && (px < -1)) \ + x = (-1 - px); \ + else if ((delx < 0) && (px >= clw)) \ + x = (clw - 1 - px); \ + \ + yy = x * dyy; \ + y = yy >> 16; \ + if (!a_a) \ + y += (yy - (y << 16)) >> 15; \ + py += y; \ + if (py >= clh) return 0; \ + \ + xx = y * dxx; \ + x = xx >> 16; \ + if (!a_a) \ + x += (xx - (x << 16)) >> 15; \ + px += x; \ + if ((delx > 0) && (px >= clw)) \ + return 0; \ + else if ((delx < 0) && (px < -1)) \ + return 0; \ + } \ + \ + p = dst + (dstw * py) + px; \ + \ + y = py - y0; \ + xx = y * dxx; \ + prev_x = (xx >> 16); \ + \ + by = MIN(y1 + 1, clh); \ + rx = clw - 1; + + + +static int +__imlib_Line_DrawToData(int x0, int y0, int x1, int y1, DATA32 color, + DATA32 *dst, int dstw, int clx, int cly, int clw, int clh, + int *cl_x0, int *cl_y0, int *cl_x1, int *cl_y1, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibPointDrawFunction pfunc; + int px, py, x, y, prev_x, prev_y; + int dx, dy, rx, by, p0_in, p1_in, dh, a_a = 0; + int delx, dely, xx, yy, dxx, dyy; + DATA32 *p; + + dx = x1 - x0; + dy = y1 - y0; + + if ( (dx == 0) || (dy == 0) || (dx == dy) || (dx == -dy) ) + return __imlib_SimpleLine_DrawToData(x0, y0, x1, y1, color, + dst, dstw, clx, cly, clw, clh, + cl_x0, cl_y0, cl_x1, cl_y1, + op, dst_alpha, blend); + + if (A_VAL(&color) == 0xff) blend = 0; + + pfunc = __imlib_GetPointDrawFunction(op, dst_alpha, blend); + if (!pfunc) return 0; + + dst += (dstw * cly) + clx; + x0 -= clx; + y0 -= cly; + x1 -= clx; + y1 -= cly; + + /* shallow: x-parametric */ + if ((dy < dx) || (dy < -dx)) + { + SETUP_LINE_SHALLOW + + *cl_x0 = px + clx; + *cl_y0 = py + cly; + + while (px < rx) + { + y = (yy >> 16); + y += ((yy - (y << 16)) >> 15); + if (prev_y != y) + { + prev_y = y; + p += dh; + py += dely; + } + + if (!p1_in) + { + if ((py < 0) && (dely < 0)) break; + if ((py > by) && (dely > 0)) break; + } + + if (IN_RANGE(px, py, clw, clh)) + pfunc(color, p); + + yy += dyy; + px++; + p++; + } + + *cl_x1 = px + clx; + *cl_y1 = py + cly; + + return 1; + } + + /* steep: y-parametric */ + + SETUP_LINE_STEEP + + *cl_x0 = px + clx; + *cl_y0 = py + cly; + + while (py < by) + { + x = (xx >> 16); + x += ((xx - (x << 16)) >> 15); + if (prev_x != x) + { + prev_x = x; + px += delx; + p += delx; + } + + if (!p1_in) + { + if ((px < 0) && (delx < 0)) break; + if ((px > rx) && (delx > 0)) break; + } + + if (IN_RANGE(px, py, clw, clh)) + pfunc(color, p); + + xx += dxx; + py++; + p += dstw; + } + + *cl_x1 = px + clx; + *cl_y1 = py + cly; + + return 1; +} + + +static int +__imlib_Line_DrawToData_AA(int x0, int y0, int x1, int y1, DATA32 color, + DATA32 *dst, int dstw, int clx, int cly, int clw, int clh, + int *cl_x0, int *cl_y0, int *cl_x1, int *cl_y1, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibPointDrawFunction pfunc; + int px, py, x, y, prev_x, prev_y; + int dx, dy, rx, by, p0_in, p1_in, dh, a_a = 1; + int delx, dely, xx, yy, dxx, dyy; + DATA32 *p; + DATA8 ca = A_VAL(&color); + + dx = x1 - x0; + dy = y1 - y0; + + if ( (dx == 0) || (dy == 0) || (dx == dy) || (dx == -dy) ) + return __imlib_SimpleLine_DrawToData(x0, y0, x1, y1, color, + dst, dstw, clx, cly, clw, clh, + cl_x0, cl_y0, cl_x1, cl_y1, + op, dst_alpha, blend); + + pfunc = __imlib_GetPointDrawFunction(op, dst_alpha, blend); + if (!pfunc) return 0; + + dst += (dstw * cly) + clx; + x0 -= clx; + y0 -= cly; + x1 -= clx; + y1 -= cly; + + /* shallow: x-parametric */ + if ((dy < dx) || (dy < -dx)) + { + SETUP_LINE_SHALLOW + + *cl_x0 = px + clx; + *cl_y0 = py + cly; + + while (px < rx) + { + DATA32 tmp; + DATA8 aa; + + y = (yy >> 16); + if (prev_y != y) + { + prev_y = y; + p += dh; + py += dely; + } + + if (!p1_in) + { + if ((py < -1) && (dely < 0)) break; + if ((py > by) && (dely > 0)) break; + } + + if ((unsigned)(px) < clw) + { + aa = (yy - (y << 16)) >> 8; + + A_VAL(&color) = 255 - aa; + if (ca < 255) + MULT(A_VAL(&color), ca, A_VAL(&color), tmp) + + if ((unsigned)(py) < clh) + pfunc(color, p); + + if ((unsigned)(py + 1) < clh) + { + A_VAL(&color) = aa; + if (ca < 255) + MULT(A_VAL(&color), ca, A_VAL(&color), tmp) + pfunc(color, p + dstw); + } + } + + yy += dyy; + px++; + p++; + } + + *cl_x1 = px + clx; + *cl_y1 = py + cly; + + return 1; + } + + /* steep: y-parametric */ + + SETUP_LINE_STEEP + + *cl_x0 = px + clx; + *cl_y0 = py + cly; + + while (py < by) + { + DATA32 tmp; + DATA8 aa; + + x = (xx >> 16); + if (prev_x != x) + { + prev_x = x; + px += delx; + p += delx; + } + + if (!p1_in) + { + if ((px < -1) && (delx < 0)) break; + if ((px > rx) && (delx > 0)) break; + } + + if ((unsigned)(py) < clh) + { + aa = (xx - (x << 16)) >> 8; + + A_VAL(&color) = 255 - aa; + if (ca < 255) + MULT(A_VAL(&color), ca, A_VAL(&color), tmp) + + if ((unsigned)(px) < clw) + pfunc(color, p); + + if ((unsigned)(px + 1) < clw) + { + A_VAL(&color) = aa; + if (ca < 255) + MULT(A_VAL(&color), ca, A_VAL(&color), tmp) + pfunc(color, p + 1); + } + } + + xx += dxx; + py++; + p += dstw; + } + + *cl_x1 = px + clx; + *cl_y1 = py + cly; + + return 1; +} + + +ImlibUpdate * +__imlib_Line_DrawToImage(int x0, int y0, int x1, int y1, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend, char anti_alias, + char make_updates) +{ + int cl_x0, cl_y0, cl_x1, cl_y1, drew; + + if ((x0 == x1) && (y0 == y1)) + return __imlib_Point_DrawToImage(x0, y0, color, + im, clx, cly, clw, clh, + op, blend, make_updates); + + if (blend && (!A_VAL(&color))) return NULL; + if (clw < 0) return NULL; + + if (clw == 0) + { + clw = im->w; + clx = 0; + clh = im->h; + cly = 0; + } + + CLIP_RECT_TO_RECT(clx, cly, clw, clh, 0, 0, im->w, im->h); + if ((clw < 1) || (clh < 1)) + return NULL; + + if ((x0 < clx) && (x1 < clx)) return NULL; + if ((x0 >= (clx + clw)) && (x1 >= (clx + clw))) return NULL; + if ((y0 < cly) && (y1 < cly)) return NULL; + if ((y0 >= (cly + clh)) && (y1 >= (cly + clh))) return NULL; + + if (blend && IMAGE_HAS_ALPHA(im)) + __imlib_build_pow_lut(); + + if (anti_alias) + drew = __imlib_Line_DrawToData_AA(x0, y0, x1, y1, color, + im->data, im->w, clx, cly, clw, clh, + &cl_x0, &cl_y0, &cl_x1, &cl_y1, + op, IMAGE_HAS_ALPHA(im), blend); + else + drew = __imlib_Line_DrawToData(x0, y0, x1, y1, color, + im->data, im->w, clx, cly, clw, clh, + &cl_x0, &cl_y0, &cl_x1, &cl_y1, + op, IMAGE_HAS_ALPHA(im), blend); + + if (drew && make_updates) + { + int mi, ma, dx, dy, w, h; + + mi = MIN(cl_x0, cl_x1); + ma = MAX(cl_x0, cl_x1); + cl_x0 = mi; + cl_x1 = ma; + dx = cl_x1 - cl_x0; + + mi = MIN(cl_y0, cl_y1); + ma = MAX(cl_y0, cl_y1); + cl_y0 = mi; + cl_y1 = ma; + dy = cl_y1 - cl_y0; + + w = dx + 1; + h = dy + 1; + + if (anti_alias) + { + if ( ((cl_x1 + 1) < (clx + clw)) && (dy > dx) ) w++; + if ( ((cl_y1 + 1) < (cly + clh)) && (dx > dy) ) h++; + } + + CLIP_RECT_TO_RECT(cl_x0, cl_y0, w, h, clx, cly, clw, clh); + if ((w < 1) || (h < 1)) + return NULL; + + return __imlib_AddUpdate(NULL, cl_x0, cl_y0, w, h); + } + + return NULL; +} diff --git a/src/lib/loaderpath.h b/src/lib/loaderpath.h new file mode 100644 index 0000000..8ae051f --- /dev/null +++ b/src/lib/loaderpath.h @@ -0,0 +1,3 @@ +#include "config.h" + +#define SYS_LOADERS_PATH PACKAGE_LIB_DIR"/imlib2" diff --git a/src/lib/polygon.c b/src/lib/polygon.c new file mode 100644 index 0000000..3219265 --- /dev/null +++ b/src/lib/polygon.c @@ -0,0 +1,1733 @@ +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include "span.h" +#include "updates.h" +#include "rgbadraw.h" + + +ImlibPoly +__imlib_polygon_new() +{ + ImlibPoly poly; + + poly = malloc(sizeof(_ImlibPoly)); + if (!poly) + return NULL; + memset(poly, 0, sizeof(_ImlibPoly)); + return poly; +} + +void +__imlib_polygon_add_point(ImlibPoly poly, int x, int y) +{ + if (!poly->points) + { + poly->points = (ImlibPoint *)malloc(sizeof(ImlibPoint)); + if (!poly->points) return; + + poly->pointcount++; + poly->lx = poly->rx = x; + poly->ty = poly->by = y; + } + else + { + poly->pointcount++; + poly->points = + (ImlibPoint *)realloc(poly->points, (poly->pointcount * sizeof(ImlibPoint))); + + if (!poly->points) { poly->pointcount = 0; return; } + + if (x < poly->lx) poly->lx = x; + if (poly->rx < x) poly->rx = x; + if (y < poly->ty) poly->ty = y; + if (poly->by < y) poly->by = y; + } + + poly->points[poly->pointcount - 1].x = x; + poly->points[poly->pointcount - 1].y = y; +} + +void +__imlib_polygon_free(ImlibPoly poly) +{ + if (poly->points) + free(poly->points); + free(poly); +} + + +#define TRUE 1 +#define FALSE 0 + +/* Check if p lies on segment [ s1, s2 ] given that + it lies on the line defined by s1 and s2. */ +#define __imlib_point_inside_segment(p_x, p_y, s1_x, s1_y, s2_x,s2_y) \ +(s1_y != s2_y) ? (p_y <= MAX(s1_y, s2_y) && p_y >= MIN(s1_y, s2_y)) : (p_x <= MAX(s1_x, s2_x) && p_x >= MIN(s1_x, s2_x)) + +#define __imlib_point_on_segment(p_x, p_y, s1_x, s1_y, s2_x, s2_y) \ +__imlib_segments_intersect(p_x, p_y, p_x, p_y, s1_x, s1_y, s2_x, s2_y) + + +void +__imlib_polygon_get_bounds(ImlibPoly poly, int *px1, int *py1, int *px2, int *py2) +{ + if (!poly || !poly->points || (poly->pointcount < 1)) + return; + + if (px1) *px1 = poly->lx; + if (py1) *py1 = poly->ty; + if (px2) *px2 = poly->rx; + if (py2) *py2 = poly->by; +} + +static double +__imlib_point_delta_from_line(int p_x, int p_y, int s1_x, int s1_y, int s2_x, + int s2_y) +{ + if (s2_x - s1_x == 0.0) + return p_x - s1_x; + else + { + double m = (double)(s2_y - s1_y) / (double)(s2_x - s1_x); + + return (p_y - s1_y - (double)(p_x - s1_x) * m); + } +} + +static unsigned char +__imlib_segments_intersect(int r1_x, int r1_y, int r2_x, int r2_y, int s1_x, + int s1_y, int s2_x, int s2_y) +{ + double testS1R = + __imlib_point_delta_from_line(s1_x, s1_y, r1_x, r1_y, r2_x, r2_y); + double testS2R = + __imlib_point_delta_from_line(s2_x, s2_y, r1_x, r1_y, r2_x, r2_y); + double testR1S = + __imlib_point_delta_from_line(r1_x, r1_y, s1_x, s1_y, s2_x, s2_y); + double testR2S = + __imlib_point_delta_from_line(r2_x, r2_y, s1_x, s1_y, s2_x, s2_y); + + /* check if segments are collinear */ + if (testS1R == 0.0 && testS2R == 0.0) + { + if (__imlib_point_inside_segment(s1_x, s1_y, r1_x, r1_y, r2_x, r2_y) + || __imlib_point_inside_segment(s2_x, s2_y, r1_x, r1_y, r2_x, r2_y) + || __imlib_point_inside_segment(r1_x, r1_y, s1_x, s1_y, s2_x, s2_y) + || __imlib_point_inside_segment(r2_x, r2_y, s1_x, s1_y, s2_x, s2_y)) + return TRUE; + else + return FALSE; + } + + if (testS1R * testS2R <= 0.0 && testR1S * testR2S <= 0.0) + return TRUE; + else + return FALSE; +} + +unsigned char +__imlib_polygon_contains_point(ImlibPoly poly, int x, int y) +{ + int count = 0; + int start = 0; + int ysave = 0; /* initial value arbitrary */ + int cx, nx, out_x, out_y, i, n; + int curr_x, curr_y, next_x, next_y; + + /* find a vertex of poly that does not lie on the test line */ + while (start < poly->pointcount && poly->points[start].y == y) + start++; + /* if one doesn't exist we will use point on segment test + * and can start with vertex 0 anyway */ + cx = start % poly->pointcount; + + out_x = poly->points[0].x; + out_y = y; + + for (i = 1; i < poly->pointcount; i++) + { + out_x = MAX(out_x, poly->points[i].x); + } + out_x++; /* out now guaranteed to be outside poly */ + + for (n = 0; n < poly->pointcount; n++) + { + nx = (cx + 1) % poly->pointcount; + + curr_x = poly->points[cx].x; + curr_y = poly->points[cx].y; + next_x = poly->points[nx].x; + next_y = poly->points[nx].y; + + if (__imlib_point_on_segment(x, y, curr_x, curr_y, next_x, next_y)) + return TRUE; + + /* ignore horizontal segments from this point on */ + if (poly->points[cx].y != poly->points[nx].y) + { + if (__imlib_segments_intersect + (curr_x, curr_y, next_x, next_y, x, y, out_x, out_y)) + { + count++; + + if (__imlib_point_on_segment + (next_x, next_y, x, y, out_x, out_y)) + { + /* current seg intersects test seg @ 2nd vtx + * reset ysave */ + ysave = curr_y; + } + if (__imlib_point_on_segment + (curr_x, curr_y, x, y, out_x, out_y) + && (ysave < y != next_y < y)) + { + /* current seg xsects test seg @ 1st vtx and + * ysave on opposite side of test line from + * curr seg 2nd vtx; + * decrement hits (2-1) for odd parity */ + count--; + } + } + } + cx = nx; + } + return (count % 2 == 1); +} + + + +/** Polygon Drawing and Filling **/ + +#define STEEP_EDGE 0 +#define SHALLOW_EDGE 1 +#define HORZ_EDGE 2 + +typedef struct _PolyEdge PolyEdge; +typedef struct _IndexedValue IndexedValue; + +struct _PolyEdge +{ + int type; + int xx; + int dxx, dyy; + ImlibPoint *v0, *v1; + int index; +}; + +struct _IndexedValue +{ + int val; + int index; +}; + +static int +poly_value_sorter(const void *a, const void *b) +{ + IndexedValue *p, *q; + + p = (IndexedValue *)a; + q = (IndexedValue *)b; + if (p->val <= q->val) return -1; + return 1; +} + +static int +poly_edge_sorter(const void *a, const void *b) +{ + PolyEdge *p, *q; + + p = (PolyEdge *)a; + q = (PolyEdge *)b; + if (p->xx < q->xx) return -1; + if (p->xx > q->xx) return 1; + if (p->dxx <= q->dxx) return -1; + return 1; +} + + +/* general macros */ + +#define DEL_EDGE(j) \ +{ \ + int m; \ + for (m = 0; (m < nactive_edges) && (edge[m].index != (j)); m++); \ + \ + if (m < nactive_edges) \ + { \ + if (edge[m].type == HORZ_EDGE) nactive_horz_edges--; \ + nactive_edges--; \ + memmove(edge + m, edge + m + 1, \ + (nactive_edges - m) * sizeof(PolyEdge)); \ + } \ +} + +#define DEL_HORZ_EDGES \ +{ \ + int m = 0; \ + \ + while (m < nactive_edges) \ + { \ + if (edge[m].type == HORZ_EDGE) \ + { \ + nactive_edges--; \ + memmove(edge + m, edge + m + 1, \ + (nactive_edges - m) * sizeof(PolyEdge)); \ + m--; \ + } \ + m++; \ + } \ + nactive_horz_edges = 0; \ +} + + +#define ADD_EDGE(i) \ +{ \ + int m; \ + \ + for (m = 0; (m < nactive_edges) && (edge[m].index != i); m++); \ + \ + if ((m == nactive_edges) && (i < nvertices) && \ + (nactive_edges < (nvertices - 1))) \ + { \ + ImlibPoint *v0, *v1, *w; \ + PolyEdge *ne; \ + int dx, dy; \ + \ + if (i < (nvertices - 1)) m = i + 1; \ + else m = 0; \ + \ + v0 = (poly->points) + i; \ + v1 = (poly->points) + m; \ + if ((v1->y) < (v0->y)) \ + { \ + w = v0; \ + v0 = v1; \ + v1 = w; \ + } \ + \ + dx = (v1->x) - (v0->x); \ + dy = (v1->y) - (v0->y); \ + ne = edge + nactive_edges; \ + ne->index = i; \ + if (dy == 0) \ + { \ + ne->type = HORZ_EDGE; \ + ne->dxx = 0; \ + if ((v1->x) < (v0->x)) \ + { \ + w = v0; \ + v0 = v1; \ + v1 = w; \ + } \ + ne->xx = (v0->x) << 16; \ + nactive_horz_edges++; \ + } \ + else \ + { \ + ne->type = STEEP_EDGE; \ + ne->dxx = ((dx << 16) / dy); \ + ne->xx = ((ne->dxx) * (y - (v0->y))) + ((v0->x) << 16); \ + if ((dy < dx) || (dy < (-dx))) \ + { \ + ne->type = SHALLOW_EDGE; \ + ne->dyy = ((dy << 16) / dx); \ + } \ + } \ + ne->v0 = v0; \ + ne->v1 = v1; \ + nactive_edges++; \ + } \ +} + + +#define GET_EDGE_RANGE(e, elx, erx) \ + switch(e->type) \ + { \ + case SHALLOW_EDGE: \ + { \ + elx = (e->xx - (2 * e->dxx)) >> 16; \ + erx = (e->xx + (2 * e->dxx)) >> 16; \ + if (e->dxx < 0) \ + { lx = elx; elx = erx; erx = lx; } \ + break; \ + } \ + case STEEP_EDGE: \ + { \ + lx = (e->xx >> 16); \ + elx = erx = lx; \ + break; \ + } \ + case HORZ_EDGE: \ + { \ + elx = e->v0->x; \ + erx = e->v1->x; \ + break; \ + } \ + default: \ + break; \ + } + + +#define CLIP_SPAN(lx, rx, clx, clrx) \ + if (lx < (clx)) lx = (clx); \ + if (rx > (clrx)) rx = (clrx); + + +#define BLEND_ALPHA(dst, a, tmp) \ + if (*dst) \ + { \ + tmp = ((a) * (255 - (*(dst)))) + 0x80; \ + *(dst) += ((tmp + (tmp >> 8)) >> 8); \ + } \ + else \ + *(dst) = (a); + + +/* initializing macro used in drawing/filling functions */ + +#define INIT_POLY \ + sfunc = __imlib_GetShapedSpanDrawFunction(op, dst_alpha, blend); \ + if (!sfunc) return; \ + \ + nvertices = poly->pointcount; \ + if (nvertices < 1) return; \ + \ + clrx = clx + clw - 1; \ + clby = cly + clh - 1; \ + \ + CLIP_SPAN(clx, clrx, poly->lx, a_a + poly->rx) \ + if (clrx < clx) return; \ + \ + CLIP_SPAN(cly, clby, poly->ty, poly->by) \ + if (clby < cly) return; \ + \ + clw = clrx - clx + 1; \ + clh = clby - cly + 1; \ + \ + edge = (PolyEdge *)malloc(nvertices * sizeof(PolyEdge)); \ + if (!edge) return; \ + \ + ysort = (IndexedValue *)malloc(nvertices * sizeof(IndexedValue)); \ + if (!ysort) { free(edge); return; } \ + \ + s0 = (DATA8 *)malloc(clw * sizeof(DATA8)); \ + if (!s0) { free(edge); free(ysort); return; } \ + \ + s1 = (DATA8 *)malloc(clw * sizeof(DATA8)); \ + if (!s1) { free(edge); free(ysort); free(s0); return; } \ + \ + memset(s0,0,clw); \ + \ + k = 0; \ + while (k < nvertices) \ + { \ + ysort[k].val = poly->points[k].y; \ + ysort[k].index = k; \ + k++; \ + } \ + \ + qsort(ysort, nvertices, sizeof(IndexedValue), poly_value_sorter); \ + \ + s0 -= clx; \ + s1 -= clx; \ + \ + x0 = clx; \ + x1 = clrx; \ + \ + nx0 = clrx + 1; \ + nx1 = clx - 1; \ + \ + if (cly > poly->ty) \ + ty = cly - 1; \ + else \ + ty = cly; \ + by = clby; \ + \ + p = dst + (dstw * ty); \ + k = 0; \ + nactive_edges = 0; \ + nactive_horz_edges = 0; \ + y = ty; + + +#define DE_INIT_POLY \ + free(edge); \ + free(ysort); \ + s0 += clx; \ + free(s0); \ + s1 += clx; \ + free(s1); + + + +/** Polygon Drawing **/ + + +/* aliased drawing */ +/* draws the poly-line defined by the sequence of vertices */ + +static void +__imlib_Polygon_DrawToData(ImlibPoly poly, char close, DATA32 color, + DATA32 *dst, int dstw, + int clx, int cly, int clw, int clh, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibShapedSpanDrawFunction sfunc; + IndexedValue *ysort; + PolyEdge *edge; + int k, a_a = 0; + int nactive_edges, nactive_horz_edges, nvertices; + int clrx, clby, ty, by, y; + int x0, x1, nx0, nx1; + DATA32 *p; + DATA8 *s0, *s1, *ps; + + INIT_POLY + + while (y <= by) + { + int j; + + while ((k < nvertices) && (poly->points[ysort[k].index].y <= y)) + { + int i = ysort[k].index; + + j = i - 1; + if (close && (i == 0)) + j = nvertices - 1; + + if (j >= 0) + { + if (poly->points[j].y < y) + DEL_EDGE(j) + else + ADD_EDGE(j) + } + + j = i + 1; + if (close && (i == (nvertices - 1))) + j = 0; + + if (j < nvertices) + { + if (poly->points[j].y < y) + DEL_EDGE(i) + else + ADD_EDGE(i) + } + + k++; + } + + /* not really needed, but... */ + qsort(edge, nactive_edges, sizeof(PolyEdge), poly_edge_sorter); + + /* clear alpha buffer */ + if (x0 <= x1) + memset(s1 + x0, 0, x1 - x0 + 1); + + x0 = nx0; x1 = nx1; + nx0 = clrx + 1; nx1 = clx - 1; + + /* draw to alpha buffer */ + j = 0; + while (j < nactive_edges) + { + int lx, rx; + int e_lx, e_rx; + PolyEdge *e; + + e = edge + j; + + GET_EDGE_RANGE(e, e_lx, e_rx) + if ((e_lx < e->v0->x) && (e->dxx > 0)) + e_lx = e->v0->x; + if ((e_rx > e->v0->x) && (e->dxx < 0)) + e_rx = e->v0->x; + + /* draw edge */ + switch (e->type) + { + case STEEP_EDGE: + { + lx = e_lx; + lx += (e->xx - (lx << 16)) >> 15; + if (IN_SEGMENT(lx, clx, clw)) + { + *(s0 + lx) = 255; + if (lx < x0) x0 = lx; + if (lx > x1) x1 = lx; + } + + if ((e->v1->y == (y + 1)) && (y < clby)) + { + lx = e->v1->x; + if (IN_SEGMENT(lx, clx, clw)) + { + *(s1 + lx) = 255; + if (lx < nx0) nx0 = lx; + if (lx > nx1) nx1 = lx; + } + } + break; + } + case SHALLOW_EDGE: + { + int x, ey, eyy; + + if (e->dyy > 0) x = e_lx; + else x = e_rx; + + eyy = ((e->v0->y) << 16) + (x - (e->v0->x)) * (e->dyy); + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + + if (e->dyy > 0) + { + if (x < x0) x0 = x; + while (ey <= y) + { + if ((ey == y) && IN_SEGMENT(x, clx, clw)) + *(s0 + x) = 255; + eyy += e->dyy; + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + x++; + } + if (x > x1) x1 = x; + + if (((y + 1) == e->v1->y) && (y < clby)) + { + if (x < nx0) nx0 = x; + rx = e->v1->x; + while ((ey == (y + 1)) && (x <= rx)) + { + if (IN_SEGMENT(x, clx, clw)) + *(s1 + x) = 255; + eyy += e->dyy; + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + x++; + } + if (x > nx1) nx1 = x; + } + break; + } + + if (x > x1) x1 = x; + while (ey <= y) + { + if ((ey == y) && IN_SEGMENT(x, clx, clw)) + *(s0 + x) = 255; + eyy -= e->dyy; + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + x--; + } + if (x < x0) x0 = x; + + if (((y + 1) == e->v1->y) && (y < clby)) + { + if (x > nx1) nx1 = x; + lx = e->v1->x; + while ((ey == (y + 1)) && (x >= lx)) + { + if (IN_SEGMENT(x, clx, clw)) + *(s1 + x) = 255; + eyy -= e->dyy; + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + x--; + } + if (x < nx0) nx0 = x; + } + break; + } + case HORZ_EDGE: + { + lx = e_lx; + rx = e_rx; + CLIP_SPAN(lx, rx, clx, clrx); + if (lx <= rx) + { + memset(s0 + lx, 255, rx - lx + 1); + if (lx < x0) x0 = lx; + if (rx > x1) x1 = rx; + } + break; + } + + default: + break; + } + + e->xx += e->dxx; + j++; + } + + if (nactive_horz_edges > 0) + DEL_HORZ_EDGES + + /* draw alpha buffer to dst */ + CLIP_SPAN(x0, x1, clx, clrx) + if ((x0 <= x1) && (y >= cly)) + sfunc(s0 + x0, color, p + x0, x1 - x0 + 1); + + /* exchange alpha buffers */ + ps = s0; s0 = s1; s1 = ps; + + y++; + p += dstw; + } + + DE_INIT_POLY +} + + +/* anti-aliased drawing */ + +static void +__imlib_Polygon_DrawToData_AA(ImlibPoly poly, char close, DATA32 color, + DATA32 *dst, int dstw, + int clx, int cly, int clw, int clh, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibShapedSpanDrawFunction sfunc; + IndexedValue *ysort; + PolyEdge *edge; + int k, a_a = 1; + int nactive_edges, nactive_horz_edges, nvertices; + int clrx, clby, ty, by, y, yy, prev_y, prev_yy; + int x0, x1, nx0, nx1; + DATA32 *p; + DATA8 *s0, *s1, *ps; + + INIT_POLY + + yy = y << 16; + prev_y = y - 1; + prev_yy = prev_y << 16; + + while (y <= by) + { + int j; + + while ((k < nvertices) && (poly->points[ysort[k].index].y <= y)) + { + int i = ysort[k].index; + + j = i - 1; + if (close && (i == 0)) + j = nvertices - 1; + + if (j >= 0) + { + if (poly->points[j].y < y) + DEL_EDGE(j) + else + ADD_EDGE(j) + } + + j = i + 1; + if (close && (i == (nvertices - 1))) + j = 0; + + if (j < nvertices) + { + if (poly->points[j].y <= y) + DEL_EDGE(i) + else + ADD_EDGE(i) + } + + k++; + } + + /* not really needed, but... */ + qsort(edge, nactive_edges, sizeof(PolyEdge), poly_edge_sorter); + + /* clear alpha buffer */ + if (x0 <= x1) + memset(s1 + x0, 0, x1 - x0 + 1); + + x0 = nx0; x1 = nx1; + nx0 = clrx + 1; nx1 = clx - 1; + + /* draw to alpha buffer */ + j = 0; + while (j < nactive_edges) + { + int lx, rx; + int e_lx, e_rx; + PolyEdge *e; + + e = edge + j; + + GET_EDGE_RANGE(e, e_lx, e_rx) + if ((e_lx < e->v0->x) && (e->dxx > 0)) + e_lx = e->v0->x; + if ((e_rx > e->v0->x) && (e->dxx < 0)) + e_rx = e->v0->x; + + /* draw aa edge */ + switch (e->type) + { + case STEEP_EDGE: + { + DATA32 tmp; DATA8 aa; + + aa = (e->xx - (e_lx << 16)) >> 8; + rx = e_lx + 1; + if (IN_SEGMENT(rx, clx, clw)) + { + ps = s0 + rx; + BLEND_ALPHA(ps, aa, tmp) + if (rx > x1) x1 = rx; + } + if (IN_SEGMENT(e_lx, clx, clw)) + { + aa = 255 - aa; + ps = s0 + e_lx; + BLEND_ALPHA(ps, aa, tmp) + if (e_lx < x0) x0 = e_lx; + } + + if ((e->v1->y == (y + 1)) && (y < clby)) + { + lx = (e->xx + e->dxx) >> 16; + aa = ((e->xx + e->dxx - (lx << 16)) >> 8); + rx = lx + 1; + if (IN_SEGMENT(rx, clx, clw)) + { + ps = s1 + rx; + BLEND_ALPHA(ps, aa, tmp) + if (rx > nx1) nx1 = rx; + } + if (IN_SEGMENT(lx, clx, clw)) + { + aa = 255 - aa; + ps = s1 + lx; + BLEND_ALPHA(ps, aa, tmp) + if (lx < nx0) nx0 = lx; + } + } + break; + } + case SHALLOW_EDGE: + { + int x, ey, eyy; + + if (e->dyy > 0) x = e_lx; + else x = e_rx; + + eyy = ((e->v0->y) << 16) + (x - (e->v0->x)) * (e->dyy); + ey = eyy >> 16; + + if (e->dyy > 0) + { + if (x < x0) x0 = x; + while (ey < y) + { + DATA32 tmp; DATA8 aa; + + if ((ey == prev_y) && IN_SEGMENT(x, clx, clw)) + { + aa = ((eyy - prev_yy) >> 8); + ps = s0 + x; + BLEND_ALPHA(ps, aa, tmp) + } + eyy += e->dyy; + ey = eyy >> 16; + x++; + } + lx = x; + while (ey == y) + { + DATA32 tmp; DATA8 aa; + + if (IN_SEGMENT(x, clx, clw)) + { + aa = 255 - ((eyy - yy) >> 8); + ps = s0 + x; + BLEND_ALPHA(ps, aa, tmp) + } + eyy += e->dyy; + ey = eyy >> 16; + x++; + } + if (x > x1) x1 = x; + + if (((y + 1) == e->v1->y) && (y < clby)) + { + x = lx; + if (x < nx0) nx0 = x; + rx = e->v1->x; + eyy = ((e->v0->y) << 16) + (x - (e->v0->x)) * (e->dyy); + ey = eyy >> 16; + while ((ey == y) && (x <= rx)) + { + DATA32 tmp; DATA8 aa; + + if (IN_SEGMENT(x, clx, clw)) + { + aa = ((eyy - yy) >> 8); + ps = s1 + x; + BLEND_ALPHA(ps, aa, tmp) + } + eyy += e->dyy; + ey = eyy >> 16; + x++; + } + if (x > nx1) nx1 = x; + } + break; + } + + if (x > x1) x1 = x; + while (ey < y) + { + DATA32 tmp; DATA8 aa; + + if ((ey == prev_y) && IN_SEGMENT(x, clx, clw)) + { + aa = ((eyy - prev_yy) >> 8); + ps = s0 + x; + BLEND_ALPHA(ps, aa, tmp) + } + eyy -= e->dyy; + ey = eyy >> 16; + x--; + } + rx = x; + while (ey == y) + { + DATA32 tmp; DATA8 aa; + + if (IN_SEGMENT(x, clx, clw)) + { + aa = 255 - ((eyy - yy) >> 8); + ps = s0 + x; + BLEND_ALPHA(ps, aa, tmp) + } + eyy -= e->dyy; + ey = eyy >> 16; + x--; + } + if (x < x0) x0 = x; + + if (((y + 1) == e->v1->y) && (y < clby)) + { + x = rx; + if (x > nx1) nx1 = x; + lx = e->v1->x; + eyy = ((e->v0->y) << 16) + (x - (e->v0->x)) * (e->dyy); + ey = eyy >> 16; + while ((ey == y) && (x >= lx)) + { + DATA32 tmp; DATA8 aa; + + if (IN_SEGMENT(x, clx, clw)) + { + aa = ((eyy - yy) >> 8); + ps = s1 + x; + BLEND_ALPHA(ps, aa, tmp) + } + eyy -= e->dyy; + ey = eyy >> 16; + x--; + } + if (x < nx0) nx0 = x; + } + break; + } + case HORZ_EDGE: + { + lx = e_lx; + rx = e_rx; + CLIP_SPAN(lx, rx, clx, clrx); + if (lx <= rx) + { + memset(s0 + lx, 255, rx - lx + 1); + if (lx < x0) x0 = lx; + if (rx > x1) x1 = rx; + } + break; + } + + default: + break; + } + + e->xx += e->dxx; + j++; + } + + if (nactive_horz_edges > 0) + DEL_HORZ_EDGES + + /* draw alpha buffer to dst */ + CLIP_SPAN(x0, x1, clx, clrx) + if ((x0 <= x1) && (y >= cly)) + sfunc(s0 + x0, color, p + x0, x1 - x0 + 1); + + /* exchange alpha buffers */ + ps = s0; s0 = s1; s1 = ps; + + prev_yy = yy; + prev_y = y; + + y++; + yy = y << 16; + + p += dstw; + } + + DE_INIT_POLY +} + + + +void +__imlib_Polygon_DrawToImage(ImlibPoly poly, char close, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend, char anti_alias) +{ + if ((!poly) || (!poly->points) || (poly->pointcount < 1) || (clw < 0)) + return; + if (blend && (!A_VAL(&color))) + return; + if (poly->pointcount == 1) + { + (void)__imlib_Point_DrawToImage(poly->points[0].x, poly->points[0].y, color, + im, clx, cly, clw, clh, + op, blend, 0); + return; + } + if (poly->pointcount == 2) + { + (void)__imlib_Line_DrawToImage(poly->points[0].x, poly->points[0].y, + poly->points[1].x, poly->points[1].y, color, + im, clx, cly, clw, clh, + op, blend, anti_alias, 0); + return; + } + + if (clw == 0) + { + clw = im->w; + clx = 0; + clh = im->h; + cly = 0; + } + + CLIP_RECT_TO_RECT(clx, cly, clw, clh, 0, 0, im->w, im->h); + if ((clw < 1) || (clh < 1)) + return; + + if (blend && IMAGE_HAS_ALPHA(im)) + __imlib_build_pow_lut(); + + if (anti_alias) + __imlib_Polygon_DrawToData_AA(poly, close, color, + im->data, im->w, + clx, cly, clw, clh, + op, IMAGE_HAS_ALPHA(im), blend); + else + __imlib_Polygon_DrawToData(poly, close, color, + im->data, im->w, + clx, cly, clw, clh, + op, IMAGE_HAS_ALPHA(im), blend); +} + + + +/** Polygon Filling **/ + + +/* aliased filling */ + +static void +__imlib_Polygon_FillToData(ImlibPoly poly, DATA32 color, + DATA32 *dst, int dstw, + int clx, int cly, int clw, int clh, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibShapedSpanDrawFunction sfunc; + IndexedValue *ysort; + PolyEdge *edge; + int k, a_a = 0; + int nactive_edges, nactive_horz_edges, nvertices; + int clrx, clby, ty, by, y; + int x0, x1, nx0, nx1; + DATA32 *p; + DATA8 *s0, *s1, *ps; + + INIT_POLY + + while (y <= by) + { + int j; + + while ((k < nvertices) && (poly->points[ysort[k].index].y <= y)) + { + int i = ysort[k].index; + + if (i > 0) j = i - 1; + else j = nvertices - 1; + + if (poly->points[j].y < y) + DEL_EDGE(j) + else + ADD_EDGE(j) + + if (i < (nvertices - 1)) j = i + 1; + else j = 0; + + if (poly->points[j].y < y) + DEL_EDGE(i) + else + ADD_EDGE(i) + + k++; + } + + qsort(edge, nactive_edges, sizeof(PolyEdge), poly_edge_sorter); + + /* clear alpha buffer */ + if (x0 <= x1) + memset(s1 + x0, 0, x1 - x0 + 1); + + x0 = nx0; x1 = nx1; + nx0 = clrx + 1; nx1 = clx - 1; + + /* draw to alpha buffer */ + j = 0; + while (j < nactive_edges) + { + int lx, rx; + int le_lx, le_rx; + int re_lx, re_rx; + PolyEdge *le, *re; + + if (j < (nactive_edges - 1)) + { le = edge + j; re = le + 1; } + else if (j > 0) + { le = edge + (j - 1); le->xx -= le->dxx; re = le + 1; } + else + { re = le = edge; } + + GET_EDGE_RANGE(le, le_lx, le_rx) + if ((le_lx < le->v0->x) && (le->dxx > 0)) + le_lx = le->v0->x; + GET_EDGE_RANGE(re, re_lx, re_rx) + if ((re_rx > re->v0->x) && (re->dxx < 0)) + re_rx = re->v0->x; + + /* draw left edge */ + switch (le->type) + { + case STEEP_EDGE: + { + le_rx += (le->xx - (le_rx << 16)) >> 15; + if (le_rx < x0) x0 = le_rx; + + if ((le->v1->y == (y + 1)) && (y < clby)) + { + lx = le->v1->x; + if (IN_SEGMENT(lx, clx, clw)) + { + *(s1 + lx) = 255; + if (lx < nx0) nx0 = lx; + } + } + break; + } + case SHALLOW_EDGE: + { + int x, ey, eyy; + + x = le_lx; + eyy = ((le->v0->y) << 16) + (x - (le->v0->x)) * (le->dyy); + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + + if (le->dyy > 0) + { + while (ey < y) + { + eyy += le->dyy; + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + x++; + } + le_rx = x; + if (x < x0) x0 = x; + + if (((y + 1) == le->v1->y) && (y < clby)) + { + if (x < nx0) nx0 = x; + rx = le->v1->x; + while ((ey <= (y + 1)) && (x <= rx)) + { + if ((ey == (y + 1)) && IN_SEGMENT(x, clx, clw)) + *(s1 + x) = 255; + eyy += le->dyy; + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + x++; + } + if (x > nx1) nx1 = x; + } + break; + } + + while (ey > y) + { + eyy += le->dyy; + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + x++; + } + le_rx = x; + if (x < x0) x0 = x; + break; + } + case HORZ_EDGE: + { + lx = le_lx; + rx = le_rx; + CLIP_SPAN(lx, rx, clx, clrx); + if (lx <= rx) + { + memset(s0 + lx, 255, rx - lx + 1); + if (lx < x0) x0 = lx; + } + le_rx++; + break; + } + + default: + break; + } + + /* draw right edge */ + switch (re->type) + { + case STEEP_EDGE: + { + re_lx += (re->xx - (re_lx << 16)) >> 15; + if (re_lx > x1) x1 = re_lx; + + if ((re->v1->y == (y + 1)) && (y < clby)) + { + rx = re->v1->x; + if (IN_SEGMENT(rx, clx, clw)) + { + *(s1 + rx) = 255; + if (rx > nx1) nx1 = rx; + } + } + break; + } + case SHALLOW_EDGE: + { + int x, ey, eyy; + + x = re_rx; + eyy = ((re->v0->y) << 16) + (x - (re->v0->x)) * (re->dyy); + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + + if (re->dyy > 0) + { + while (ey > y) + { + eyy -= re->dyy; + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + x--; + } + re_lx = x; + if (x > x1) x1 = x; + break; + } + + while (ey < y) + { + eyy -= re->dyy; + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + x--; + } + re_lx = x; + if (x > x1) x1 = x; + + if (((y + 1) == re->v1->y) && (y < clby)) + { + if (x > nx1) nx1 = x; + lx = re->v1->x; + while ((ey <= (y + 1)) && (x >= lx)) + { + if ((ey == (y + 1)) && IN_SEGMENT(x, clx, clw)) + *(s1 + x) = 255; + eyy -= re->dyy; + ey = eyy >> 16; + ey += (eyy - (ey << 16)) >> 15; + x--; + } + if (x < nx0) nx0 = x; + } + break; + } + case HORZ_EDGE: + { + lx = re_lx; + rx = re_rx; + CLIP_SPAN(lx, rx, clx, clrx); + if (lx <= rx) + { + memset(s0 + lx, 255, rx - lx + 1); + if (rx > x1) x1 = rx; + } + re_lx--; + break; + } + + default: + break; + } + + /* draw span between edges */ + lx = le_rx; rx = re_lx; + CLIP_SPAN(lx, rx, clx, clrx) + if ((lx <= rx) && (y >= cly)) + memset(s0 + lx, 255, rx - lx + 1); + + le->xx += le->dxx; + if (le != re) + re->xx += re->dxx; + + j += 2; + } + + if (nactive_horz_edges > 0) + DEL_HORZ_EDGES + + /* draw alpha buffer to dst */ + CLIP_SPAN(x0, x1, clx, clrx) + if ((x0 <= x1) && (y >= cly)) + sfunc(s0 + x0, color, p + x0, x1 - x0 + 1); + + /* exchange alpha buffers */ + ps = s0; s0 = s1; s1 = ps; + + y++; + p += dstw; + } + + DE_INIT_POLY +} + + +/* anti-aliased filling */ + +static void +__imlib_Polygon_FillToData_AA(ImlibPoly poly, DATA32 color, + DATA32 *dst, int dstw, + int clx, int cly, int clw, int clh, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibShapedSpanDrawFunction sfunc; + IndexedValue *ysort; + PolyEdge *edge; + int k, a_a = 1; + int nactive_edges, nactive_horz_edges, nvertices; + int clrx, clby, ty, by, y, yy, prev_y, prev_yy; + int x0, x1, nx0, nx1; + DATA32 *p; + DATA8 *s0, *s1, *ps; + + INIT_POLY + + yy = y << 16; + prev_y = y - 1; + prev_yy = prev_y << 16; + + while (y <= by) + { + int j; + + while ((k < nvertices) && (poly->points[ysort[k].index].y <= y)) + { + int i = ysort[k].index; + + if (i > 0) j = i - 1; + else j = nvertices - 1; + + if (poly->points[j].y < y) + DEL_EDGE(j) + else + ADD_EDGE(j) + + if (i < (nvertices - 1)) j = i + 1; + else j = 0; + + if (poly->points[j].y < y) + DEL_EDGE(i) + else + ADD_EDGE(i) + + k++; + } + + qsort(edge, nactive_edges, sizeof(PolyEdge), poly_edge_sorter); + + /* clear alpha buffer */ + if (x0 <= x1) + memset(s1 + x0, 0, x1 - x0 + 1); + + x0 = nx0; x1 = nx1; + nx0 = clrx + 1; nx1 = clx - 1; + /* draw to alpha buffer */ + j = 0; + while (j < nactive_edges) + { + int lx, rx; + int le_lx, le_rx; + int re_lx, re_rx; + PolyEdge *le, *re; + + if (j < (nactive_edges - 1)) + { le = edge + j; re = le + 1; } + else if (j > 0) + { le = edge + (j - 1); le->xx -= le->dxx; re = le + 1; } + else + { re = le = edge; } + + GET_EDGE_RANGE(le, le_lx, le_rx) + if ((le_lx < le->v0->x) && (le->dxx > 0)) + le_lx = le->v0->x; + GET_EDGE_RANGE(re, re_lx, re_rx) + if ((re_rx > re->v0->x) && (re->dxx < 0)) + re_rx = re->v0->x; + + /* draw left aa edge */ + switch (le->type) + { + case STEEP_EDGE: + { + DATA32 tmp; DATA8 aa; + + if (le_lx < x0) x0 = le_lx; + le_rx = le_lx + 1; + + if (IN_SEGMENT(le_lx, clx, clw)) + { + aa = 255 - ((le->xx - (le_lx << 16)) >> 8); + ps = s0 + le_lx; + BLEND_ALPHA(ps, aa, tmp) + } + + if ((le->v1->y == (y + 1)) && (y < clby)) + { + lx = (le->xx + le->dxx) >> 16; + if (IN_SEGMENT(lx, clx, clw)) + { + aa = 255 - ((le->xx + le->dxx - (lx << 16)) >> 8); + ps = s1 + lx; + BLEND_ALPHA(ps, aa, tmp) + if (lx < nx0) nx0 = lx; + } + } + break; + } + case SHALLOW_EDGE: + { + int x, ey, eyy; + + if (le_lx < x0) x0 = le_lx; + x = le_lx; + eyy = ((le->v0->y) << 16) + (x - (le->v0->x)) * (le->dyy); + ey = eyy >> 16; + + if (le->dyy > 0) + { + while (ey < y) + { + DATA32 tmp; DATA8 aa; + + if ((ey == prev_y) && IN_SEGMENT(x, clx, clw)) + { + aa = ((eyy - prev_yy) >> 8); + ps = s0 + x; + BLEND_ALPHA(ps, aa, tmp) + } + eyy += le->dyy; + ey = eyy >> 16; + x++; + } + le_rx = x; + + if (((y + 1) == le->v1->y) && (y < clby)) + { + if (x < nx0) nx0 = x; + rx = le->v1->x; + while ((ey == y) && (x <= rx)) + { + DATA32 tmp; DATA8 aa; + + if (IN_SEGMENT(x, clx, clw)) + { + aa = ((eyy - yy) >> 8); + ps = s1 + x; + BLEND_ALPHA(ps, aa, tmp) + } + eyy += le->dyy; + ey = eyy >> 16; + x++; + } + } + break; + } + + while (ey >= y) + { + DATA32 tmp; DATA8 aa; + + if ((ey == y) && IN_SEGMENT(x, clx, clw)) + { + aa = 255 - ((eyy - yy) >> 8); + ps = s0 + x; + BLEND_ALPHA(ps, aa, tmp) + } + eyy += le->dyy; + ey = eyy >> 16; + x++; + } + le_rx = x; + break; + } + case HORZ_EDGE: + { + lx = le_lx; + rx = le_rx; + CLIP_SPAN(lx, rx, clx, clrx); + if (lx <= rx) + { + memset(s0 + lx, 255, rx - lx + 1); + if (lx < x0) x0 = lx; + } + le_rx++; + break; + } + + default: + break; + } + + /* draw right aa edge */ + switch (re->type) + { + case STEEP_EDGE: + { + DATA32 tmp; DATA8 aa; + + rx = re_lx + 1; + if (rx > x1) x1 = rx; + + if (IN_SEGMENT(rx, clx, clw)) + { + aa = (re->xx - (re_lx << 16)) >> 8; + ps = s0 + rx; + BLEND_ALPHA(ps, aa, tmp) + } + + if ((re->v1->y == (y + 1)) && (y < clby)) + { + lx = (re->xx + re->dxx) >> 16; rx = lx + 1; + if (IN_SEGMENT(rx, clx, clw)) + { + aa = ((re->xx + re->dxx - (lx << 16)) >> 8); + ps = s1 + rx; + BLEND_ALPHA(ps, aa, tmp) + if (rx > nx1) nx1 = rx; + } + } + break; + } + case SHALLOW_EDGE: + { + int x, ey, eyy; + + if (re_rx > x1) x1 = re_rx; + x = re_rx; + eyy = ((re->v0->y) << 16) + (x - (re->v0->x)) * (re->dyy); + ey = eyy >> 16; + + if (re->dyy > 0) + { + while (ey >= y) + { + DATA32 tmp; DATA8 aa; + + if ((ey == y) && IN_SEGMENT(x, clx, clw)) + { + aa = 255 - ((eyy - yy) >> 8); + ps = s0 + x; + BLEND_ALPHA(ps, aa, tmp) + } + eyy -= re->dyy; + ey = eyy >> 16; + x--; + } + re_lx = x; + break; + } + + while (ey < y) + { + DATA32 tmp; DATA8 aa; + + if ((ey == prev_y) && IN_SEGMENT(x, clx, clw)) + { + aa = ((eyy - prev_yy) >> 8); + ps = s0 + x; + BLEND_ALPHA(ps, aa, tmp) + } + eyy -= re->dyy; + ey = eyy >> 16; + x--; + } + re_lx = x; + + if (((y + 1) == re->v1->y) && (y < clby)) + { + if (x > nx1) nx1 = x; + lx = re->v1->x; + while ((ey == y) && (x >= lx)) + { + DATA32 tmp; DATA8 aa; + + if (IN_SEGMENT(x, clx, clw)) + { + aa = ((eyy - yy) >> 8); + ps = s1 + x; + BLEND_ALPHA(ps, aa, tmp) + } + eyy -= re->dyy; + ey = eyy >> 16; + x--; + } + } + break; + } + case HORZ_EDGE: + { + lx = re_lx; + rx = re_rx; + CLIP_SPAN(lx, rx, clx, clrx); + if (lx <= rx) + { + memset(s0 + lx, 255, rx - lx + 1); + if (rx > x1) x1 = rx; + } + re_lx--; + break; + } + + default: + break; + } + + /* draw span between edges */ + lx = le_rx; rx = re_lx; + CLIP_SPAN(lx, rx, clx, clrx) + if ((lx <= rx) && (y >= cly)) + memset(s0 + lx, 255, rx - lx + 1); + + le->xx += le->dxx; + if (le != re) + re->xx += re->dxx; + + j += 2; + } + + if (nactive_horz_edges > 0) + DEL_HORZ_EDGES + + /* draw alpha buffer to dst */ + CLIP_SPAN(x0, x1, clx, clrx) + if ((x0 <= x1) && (y >= cly)) + sfunc(s0 + x0, color, p + x0, x1 - x0 + 1); + + /* exchange alpha buffers */ + ps = s0; s0 = s1; s1 = ps; + + prev_yy = yy; + prev_y = y; + + y++; + yy = y << 16; + + p += dstw; + } + + DE_INIT_POLY +} + + + +void +__imlib_Polygon_FillToImage(ImlibPoly poly, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend, char anti_alias) +{ + if ((!poly) || (!poly->points) || (poly->pointcount < 1) || (clw < 0)) + return; + if (blend && (!A_VAL(&color))) + return; + if (poly->pointcount == 1) + { + (void)__imlib_Point_DrawToImage(poly->points[0].x, poly->points[0].y, color, + im, clx, cly, clw, clh, + op, blend, 0); + return; + } + if (poly->pointcount == 2) + { + (void)__imlib_Line_DrawToImage(poly->points[0].x, poly->points[0].y, + poly->points[1].x, poly->points[1].y, color, + im, clx, cly, clw, clh, + op, blend, anti_alias, 0); + return; + } + + if (clw == 0) + { + clw = im->w; + clx = 0; + clh = im->h; + cly = 0; + } + + CLIP_RECT_TO_RECT(clx, cly, clw, clh, 0, 0, im->w, im->h); + if ((clw < 1) || (clh < 1)) + return; + + if (blend && IMAGE_HAS_ALPHA(im)) + __imlib_build_pow_lut(); + + if (anti_alias) + __imlib_Polygon_FillToData_AA(poly, color, + im->data, im->w, + clx, cly, clw, clh, + op, IMAGE_HAS_ALPHA(im), blend); + else + __imlib_Polygon_FillToData(poly, color, + im->data, im->w, + clx, cly, clw, clh, + op, IMAGE_HAS_ALPHA(im), blend); +} + diff --git a/src/lib/rectangle.c b/src/lib/rectangle.c new file mode 100644 index 0000000..9be13fe --- /dev/null +++ b/src/lib/rectangle.c @@ -0,0 +1,192 @@ +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include "span.h" +#include "updates.h" +#include "rgbadraw.h" + + +static void +__imlib_Rectangle_DrawToData(int x, int y, int rw, int rh, DATA32 color, + DATA32 *dst, int dstw, int clx, int cly, int clw, int clh, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibPointDrawFunction pfunc; + ImlibSpanDrawFunction sfunc; + int x0, y0, x1, y1, len; + DATA32 *p, *pp; + + if (A_VAL(&color) == 0xff) blend = 0; + + sfunc = __imlib_GetSpanDrawFunction(op, dst_alpha, blend); + pfunc = __imlib_GetPointDrawFunction(op, dst_alpha, blend); + if (!pfunc || !sfunc) + return; + + dst += (dstw * cly) + clx; + x -= clx; + y -= cly; + + x0 = x; + x1 = x + rw - 1; + + if (x0 < 0) x0 = 0; + if (x1 >= clw) x1 = clw - 1; + + if (y >= 0) + { + p = dst + (dstw * y) + x0; + len = x1 - x0 + 1; + sfunc(color, p, len); + } + if ((y + rh) <= clh) + { + p = dst + (dstw * (y + rh - 1)) + x0; + len = x1 - x0 + 1; + sfunc(color, p, len); + } + + y0 = y + 1; + y1 = y + rh - 2; + + if (y0 < 0) y0 = 0; + if (y1 >= clh) y1 = clh - 1; + + len = y1 - y0 + 1; + if (len <= 0) return; + y1 = len; + + if (x >= 0) + { + p = dst + (dstw * y0) + x; + while (len--) + { + pfunc(color, p); + p += dstw; + } + } + if ((x + rw) <= clw) + { + len = y1; + p = dst + (dstw * y0) + x + rw - 1; + while (len--) + { + pfunc(color, p); + p += dstw; + } + } +} + +static void +__imlib_Rectangle_FillToData(int x, int y, int rw, int rh, DATA32 color, + DATA32 *dst, int dstw, int clx, int cly, int clw, int clh, + ImlibOp op, char dst_alpha, char blend) +{ + ImlibSpanDrawFunction sfunc; + DATA32 *p; + + if (A_VAL(&color) == 0xff) + blend = 0; + sfunc = __imlib_GetSpanDrawFunction(op, dst_alpha, blend); + if (!sfunc) return; + + dst += (dstw * cly) + clx; + x -= clx; + y -= cly; + + CLIP_RECT_TO_RECT(x, y, rw, rh, 0, 0, clw, clh); + if ((rw < 1) || (rh < 1)) + return; + + p = dst + (dstw * y) + x; + while (rh--) + { + sfunc(color, p, rw); + p += dstw; + } +} + + +void +__imlib_Rectangle_DrawToImage(int x, int y, int w, int h, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend) +{ + if ((w < 1) || (h < 1) || (clw < 0)) + return; + if ((w == 1) || (h == 1)) + { + (void) __imlib_Line_DrawToImage(x, y, x + w - 1, y + h - 1, color, + im, clx, cly, clw, clh, + op, blend, 0, 0); + return; + } + if (blend && (!A_VAL(&color))) + return; + + if (clw == 0) + { + clw = im->w; + clx = 0; + clh = im->h; + cly = 0; + } + + CLIP_RECT_TO_RECT(clx, cly, clw, clh, 0, 0, im->w, im->h); + if ((clw < 1) || (clh < 1)) + return; + + CLIP_RECT_TO_RECT(clx, cly, clw, clh, x, y, w, h); + if ((clw < 1) || (clh < 1)) + return; + + if (blend && IMAGE_HAS_ALPHA(im)) + __imlib_build_pow_lut(); + + __imlib_Rectangle_DrawToData(x, y, w, h, color, + im->data, im->w, clx, cly, clw, clh, + op, IMAGE_HAS_ALPHA(im), blend); +} + + +void +__imlib_Rectangle_FillToImage(int x, int y, int w, int h, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend) +{ + if ((w < 1) || (h < 1) || (clw < 0)) + return; + if ((w == 1) || (h == 1)) + { + (void) __imlib_Line_DrawToImage(x, y, x + w - 1, y + h - 1, color, + im, clx, cly, clw, clh, + op, blend, 0, 0); + return; + } + if (blend && (!A_VAL(&color))) + return; + + if (clw == 0) + { + clw = im->w; + clx = 0; + clh = im->h; + cly = 0; + } + + CLIP_RECT_TO_RECT(clx, cly, clw, clh, 0, 0, im->w, im->h); + if ((clw < 1) || (clh < 1)) + return; + + CLIP_RECT_TO_RECT(clx, cly, clw, clh, x, y, w, h); + if ((clw < 1) || (clh < 1)) + return; + + if (blend && IMAGE_HAS_ALPHA(im)) + __imlib_build_pow_lut(); + + __imlib_Rectangle_FillToData(x, y, w, h, color, + im->data, im->w, clx, cly, clw, clh, + op, IMAGE_HAS_ALPHA(im), blend); +} diff --git a/src/lib/rend.c b/src/lib/rend.c new file mode 100644 index 0000000..389062d --- /dev/null +++ b/src/lib/rend.c @@ -0,0 +1,598 @@ +#include "common.h" +#ifdef BUILD_X11 +#include +#include +#include +#endif +#include "colormod.h" +#include "image.h" +#include "scale.h" +#include "ximage.h" +#include "context.h" +#include "rgba.h" +#include "color.h" +#include "grab.h" +#include "blend.h" +#include "rend.h" +#include "rotate.h" + +#ifdef BUILD_X11 + +/* size of the lines per segment we scale / render at a time */ +#define LINESIZE 16 + +DATA32 +__imlib_RenderGetPixel(Display * d, Drawable w, Visual * v, Colormap cm, + int depth, DATA8 r, DATA8 g, DATA8 b) +{ + Context *ct; + int actual_depth; + + ct = __imlib_GetContext(d, v, cm, depth); + actual_depth = depth; + if (depth == 16) + actual_depth = __imlib_XActualDepth(d, v); + + if (ct->palette) + { + switch (ct->palette_type) + { + case 0: /* 332 */ + return ct->palette[((r >> 0) & 0xe0) | + ((g >> 3) & 0x1b) | ((b >> 6) & 0x02)]; + break; + case 1: /* 232 */ + return ct->palette[((r >> 0) & 0xe0) | + ((g >> 3) & 0x1b) | ((b >> 6) & 0x02)]; + break; + case 2: /* 222 */ + return ct->palette[((r >> 0) & 0xe0) | + ((g >> 3) & 0x1b) | ((b >> 6) & 0x02)]; + break; + case 3: /* 221 */ + return ct->palette[((r >> 0) & 0xe0) | + ((g >> 3) & 0x1b) | ((b >> 6) & 0x02)]; + break; + case 4: /* 121 */ + return ct->palette[((r >> 0) & 0xe0) | + ((g >> 3) & 0x1b) | ((b >> 6) & 0x02)]; + break; + case 5: /* 111 */ + return ct->palette[((r >> 0) & 0xe0) | + ((g >> 3) & 0x1b) | ((b >> 6) & 0x02)]; + break; + case 6: /* 1 */ + return ct->palette[((r >> 0) & 0xe0) | + ((g >> 3) & 0x1b) | ((b >> 6) & 0x02)]; + break; + case 7: /* 666 */ + return ct->palette[((int)(((double)r / 255) * 5.0) * 36) + + ((int)(((double)g / 255) * 5.0) * 6) + + ((int)(((double)b / 255) * 5.0))]; + break; + default: + return 0; + } + } + else + { + unsigned int rm, gm, bm; + int i, rshift = 0, gshift = 0, bshift = 0; + DATA32 val; + + rm = v->red_mask; + gm = v->green_mask; + bm = v->blue_mask; + if ((rm == 0xf800) && (gm == 0x7e0) && (bm == 0x1f)) /* 565 */ + { + return (((r << 8) & 0xf800) | + ((g << 3) & 0x07e0) | ((b >> 3) & 0x001f)); + } + if ((rm == 0xff0000) && (gm == 0xff00) && (bm == 0xff)) /* 888 */ + { + return (((r << 16) & 0xff0000) | + ((g << 8) & 0x00ff00) | ((r) & 0x0000ff)); + } + if ((rm == 0x7c00) && (gm == 0x3e0) && (bm == 0x1f)) /* 555 */ + { + return (((r << 7) & 0x7c00) | + ((g << 2) & 0x03e0) | ((b >> 3) & 0x001f)); + } + for (i = 31; i >= 0; i--) + { + if (rm >= (1 << i)) + { + rshift = i - 7; + break; + } + } + for (i = 31; i >= 0; i--) + { + if (gm >= (1 << i)) + { + gshift = i - 7; + break; + } + } + for (i = 31; i >= 0; i--) + { + if (bm >= (1 << i)) + { + bshift = i - 7; + break; + } + } + if (rshift >= 0) + val = ((r << rshift) & rm); + else + val = ((r >> (-rshift)) & rm); + if (gshift >= 0) + val |= ((g << gshift) & gm); + else + val |= ((g >> (-gshift)) & gm); + if (bshift >= 0) + val |= ((b << bshift) & bm); + else + val |= ((b >> (-bshift)) & bm); + return val; + } + return 0; +} + +void + __imlib_generic_render(DATA32 * src, int jump, int w, int h, int dx, int dy, + XImage * xim, Visual * v, + Context * ct); + +void +__imlib_generic_render(DATA32 * src, int jump, int w, int h, int dx, int dy, + XImage * xim, Visual * v, Context * ct) +{ + unsigned int x, y, r, g, b, val, hh; + unsigned int rmask, gmask, bmask; + int i, rshift, gshift, bshift; + const DATA8 _dither_88[8][8] = { + {0, 32, 8, 40, 2, 34, 10, 42}, + {48, 16, 56, 24, 50, 18, 58, 26}, + {12, 44, 4, 36, 14, 46, 6, 38}, + {60, 28, 52, 20, 62, 30, 54, 22}, + {3, 35, 11, 43, 1, 33, 9, 41}, + {51, 19, 59, 27, 49, 17, 57, 25}, + {15, 47, 7, 39, 13, 45, 5, 37}, + {63, 31, 55, 23, 61, 29, 53, 21} + }; + + if (xim->depth == 1) + { + hh = dy + h; + for (y = dy; y < hh; y++) + { + for (x = dx; x < w; x++) + { + r = R_VAL(src); + g = G_VAL(src); + b = B_VAL(src); + val = (R_VAL(src) + G_VAL(src) + B_VAL(src)) / 12; + if (val > _dither_88[x & 0x3][y & 0x3]) + val = ct->palette[1]; + else + val = ct->palette[0]; + XPutPixel(xim, x, y, val); + src++; + } + } + return; + } + rmask = xim->red_mask; + gmask = xim->green_mask; + bmask = xim->blue_mask; + rshift = 0; + gshift = 0; + bshift = 0; + for (i = 31; i >= 0; i--) + { + if (rmask >= (1 << i)) + { + rshift = i - 7; + break; + } + } + for (i = 31; i >= 0; i--) + { + if (gmask >= (1 << i)) + { + gshift = i - 7; + break; + } + } + for (i = 31; i >= 0; i--) + { + if (bmask >= (1 << i)) + { + bshift = i - 7; + break; + } + } + hh = dy + h; + for (y = dy; y < hh; y++) + { + for (x = dx; x < w; x++) + { + r = R_VAL(src); + if (rshift >= 0) + val = ((r << rshift) & rmask); + else + val = ((r >> (-rshift)) & rmask); + g = G_VAL(src); + if (gshift >= 0) + val |= ((g << gshift) & gmask); + else + val |= ((g >> (-gshift)) & gmask); + b = B_VAL(src); + if (bshift >= 0) + val |= ((b << bshift) & bmask); + else + val |= ((b >> (-bshift)) & bmask); + XPutPixel(xim, x, y, val); + src++; + } + } +} + +void +__imlib_RenderImage(Display * d, ImlibImage * im, + Drawable w, Drawable m, + Visual * v, Colormap cm, int depth, + int sx, int sy, int sw, int sh, + int dx, int dy, int dw, int dh, + char antialias, char hiq, char blend, char dither_mask, + ImlibColorModifier * cmod, ImlibOp op) +{ + XImage *xim = NULL, *mxim = NULL; + Context *ct; + DATA32 *buf = NULL, *pointer = NULL, *back = NULL; + int y, h, hh, jump; + static Display *disp = NULL; + static GC gc = 0; + static GC gcm = 0; + XGCValues gcv; + ImlibScaleInfo *scaleinfo = NULL; + int psx, psy, psw, psh; + int actual_depth = 0; + char shm = 0; + ImlibRGBAFunction rgbaer, masker = NULL; + ImlibBlendFunction blender = NULL; + int do_mmx; + + blender = __imlib_GetBlendFunction(op, 1, 0, + (!(im->flags & F_HAS_ALPHA)), NULL); + + /* dont do anything if we have a 0 widht or height image to render */ + if ((dw == 0) || (dh == 0)) + return; + /* if the input rect size < 0 dont render either */ + if ((sw <= 0) || (sh <= 0)) + return; + /* if the output is too big (8k arbitary limit here) dont bother */ + if ((abs(dw) > 8192) || (abs(dh) > 8192)) + return; + /* clip the source rect to be within the actual image */ + psx = sx; + psy = sy; + psw = sw; + psh = sh; + CLIP(sx, sy, sw, sh, 0, 0, im->w, im->h); + /* clip output coords to clipped input coords */ + if (psx != sx) + dx = (dx * sx) / psx; + if (psy != sy) + dy = (dy * sy) / psy; + if (psw != sw) + dw = (dw * sw) / psw; + if (psh != sh) + dh = (dh * sh) / psh; + /* do a second check to see if we now have invalid coords */ + /* dont do anything if we have a 0 widht or height image to render */ + if ((dw == 0) || (dh == 0)) + return; + /* if the input rect size < 0 dont render either */ + if ((sw <= 0) || (sh <= 0)) + return; + /* if the output is too big (8k arbitary limit here) dont bother */ + if ((abs(dw) > 8192) || (abs(dh) > 8192)) + return; + /* if we are scaling the image at all make a scaling buffer */ + if (!((sw == dw) && (sh == dh))) + { + scaleinfo = __imlib_CalcScaleInfo(im, sw, sh, dw, dh, antialias); + if (!scaleinfo) + return; + } + /* Sign not needed anymore */ + dw = abs(dw); + dh = abs(dh); + ct = __imlib_GetContext(d, v, cm, depth); + actual_depth = depth; + if (depth == 16) + actual_depth = __imlib_XActualDepth(d, v); + __imlib_RGBASetupContext(ct); + if ((blend) && (IMAGE_HAS_ALPHA(im))) + { + back = malloc(dw * dh * sizeof(DATA32)); + if (!__imlib_GrabDrawableToRGBA + (back, 0, 0, dw, dh, d, w, 0, v, cm, depth, dx, dy, dw, dh, 0, 1)) + { + free(back); + back = NULL; + } + } + /* get a new XImage - or get one from the cached list */ + xim = __imlib_ProduceXImage(d, v, depth, dw, dh, &shm); + if (!xim) + { + __imlib_FreeScaleInfo(scaleinfo); + if (back) + free(back); + return; + } + /* do a double check in 24/32bpp */ + if ((xim->bits_per_pixel == 32) && (depth == 24)) + actual_depth = 32; + if (m) + { + mxim = __imlib_ProduceXImage(d, v, 1, dw, dh, &shm); + if (!mxim) + { + __imlib_ConsumeXImage(d, xim); + __imlib_FreeScaleInfo(scaleinfo); + if (back) + free(back); + return; + } + memset(mxim->data, 0, mxim->bytes_per_line * mxim->height); + } + /* if we are scaling the image at all make a scaling buffer */ + if (scaleinfo) + { + /* allocate a buffer to render scaled RGBA data into */ + buf = malloc(dw * LINESIZE * sizeof(DATA32)); + if (!buf) + { + __imlib_ConsumeXImage(d, xim); + if (m) + __imlib_ConsumeXImage(d, mxim); + __imlib_FreeScaleInfo(scaleinfo); + if (back) + free(back); + return; + } + } + /* setup h */ + h = dh; + /* scale in LINESIZE Y chunks and convert to depth */ + /* Get rgba and mask functions for XImage rendering */ + rgbaer = __imlib_GetRGBAFunction(xim->bits_per_pixel, + v->red_mask, v->green_mask, v->blue_mask, + hiq, ct->palette_type); + if (m) + masker = __imlib_GetMaskFunction(dither_mask); +#ifdef DO_MMX_ASM + do_mmx = __imlib_get_cpuid() & CPUID_MMX; +#endif + for (y = 0; y < dh; y += LINESIZE) + { + hh = LINESIZE; + if (h < LINESIZE) + hh = h; + /* if we're scaling it */ + if (scaleinfo) + { + /* scale the imagedata for this LINESIZE lines chunk of image data */ + if (antialias) + { +#ifdef DO_MMX_ASM + if (do_mmx) + __imlib_Scale_mmx_AARGBA(scaleinfo, buf, + ((sx * dw) / sw), + ((sy * dh) / sh) + y, + 0, 0, dw, hh, dw, im->w); + else +#endif + if (IMAGE_HAS_ALPHA(im)) + __imlib_ScaleAARGBA(scaleinfo, buf, ((sx * dw) / sw), + ((sy * dh) / sh) + y, + 0, 0, dw, hh, dw, im->w); + else + __imlib_ScaleAARGB(scaleinfo, buf, ((sx * dw) / sw), + ((sy * dh) / sh) + y, + 0, 0, dw, hh, dw, im->w); + } + else + __imlib_ScaleSampleRGBA(scaleinfo, buf, ((sx * dw) / sw), + ((sy * dh) / sh) + y, 0, 0, dw, hh, dw); + jump = 0; + pointer = buf; + if (cmod) + __imlib_DataCmodApply(buf, dw, hh, 0, NULL, cmod); + } + else + { + if (cmod) + { + if (!buf) + buf = malloc(im->w * LINESIZE * sizeof(DATA32)); + if (!buf) + { + __imlib_ConsumeXImage(d, xim); + if (m) + __imlib_ConsumeXImage(d, mxim); + __imlib_FreeScaleInfo(scaleinfo); + if (back) + free(back); + return; + } + memcpy(buf, im->data + ((y + sy) * im->w) + sx, + im->w * hh * sizeof(DATA32)); + __imlib_DataCmodApply(buf, dw, hh, im->w - dw, NULL, cmod); + pointer = buf; + jump = 0; + } + else + { + jump = im->w - sw; + pointer = im->data + ((y + sy) * im->w) + sx; + } + } + /* if we have a back buffer - we're blending to the bg */ + if (back) + { + blender(pointer, jump + dw, back + (y * dw), dw, dw, hh, NULL); + pointer = back + (y * dw); + jump = 0; + } + /* once scaled... convert chunk to bit depth into XImage bufer */ + if (rgbaer) + rgbaer(pointer, jump, + ((DATA8 *) xim->data) + (y * (xim->bytes_per_line)), + xim->bytes_per_line, dw, hh, dx, dy + y); + else + __imlib_generic_render(pointer, jump, dw, hh, 0, y, xim, v, ct); + if (m) + masker(pointer, jump, + ((DATA8 *) mxim->data) + (y * (mxim->bytes_per_line)), + mxim->bytes_per_line, dw, hh, dx, dy + y); + h -= LINESIZE; + } + /* free up our buffers and poit tables */ + if (buf) + free(buf); + if (scaleinfo) + __imlib_FreeScaleInfo(scaleinfo); + if (back) + free(back); + /* if we changed diplays since last time... free old gc's */ + if (disp != d) + { + if (gc) + XFreeGC(disp, gc); + if (gcm) + XFreeGC(disp, gcm); + gc = 0; + gcm = 0; + } + /* if we didnt have a gc... create it */ + if (!gc) + { + disp = d; + gcv.graphics_exposures = False; + gc = XCreateGC(d, w, GCGraphicsExposures, &gcv); + } + if (m) + { + if (!gcm) + { + gcv.graphics_exposures = False; + gcm = XCreateGC(d, m, GCGraphicsExposures, &gcv); + } + /* write the mask */ + if (shm) + /* write shm XImage */ + XShmPutImage(d, m, gcm, mxim, 0, 0, dx, dy, dw, dh, False); + /* write regular XImage */ + else + XPutImage(d, m, gcm, mxim, 0, 0, dx, dy, dw, dh); + } + /* write the image */ + if (shm) + /* write shm XImage */ + XShmPutImage(d, w, gc, xim, 0, 0, dx, dy, dw, dh, False); + /* write regular XImage */ + else + XPutImage(d, w, gc, xim, 0, 0, dx, dy, dw, dh); + /* free the XImage and put onto our free list */ + /* wait for the write to be done */ + if (shm) + XSync(d, False); + __imlib_ConsumeXImage(d, xim); + if (m) + __imlib_ConsumeXImage(d, mxim); +} + +void +__imlib_RenderImageSkewed(Display * d, ImlibImage * im, Drawable w, Drawable m, + Visual * v, Colormap cm, int depth, + int sx, int sy, int sw, int sh, int dx, int dy, + int hsx, int hsy, int vsx, int vsy, + char antialias, char hiq, char blend, + char dither_mask, ImlibColorModifier * cmod, + ImlibOp op) +{ + Context *ct; + int dx1, dy1, dx2, dy2, dw, dh, tsx, tsy; + ImlibImage *back; + + dx1 = dx2 = dx; + dy1 = dy2 = dy; + + if (hsx < 0) + dx1 += hsx; + else + dx2 += hsx; + if (hsy < 0) + dy1 += hsy; + else + dy2 += hsy; + tsx = vsx; + tsy = vsy; + if (!tsx && !tsy) + { + tsy = (hsx * im->h) / im->w; + tsx = -(hsy * im->h) / im->w; + } + if (tsx < 0) + dx1 += tsx; + else + dx2 += tsx; + if (tsy < 0) + dy1 += tsy; + else + dy2 += tsy; + + if ((dx2 < 0) || (dy2 < 0)) + return; + + dw = dx2 - dx1; + dh = dy2 - dy1; + + if ((dw <= 0) || (dh <= 0)) + return; + + if (dx1 < 0) + { + dw += dx1; + dx1 = 0; + } + if (dy1 < 0) + { + dh += dy1; + dy1 = 0; + } + + ct = __imlib_GetContext(d, v, cm, depth); + + back = __imlib_CreateImage(dw, dh, NULL); + back->data = malloc(dw * dh * sizeof(DATA32)); + memset(back->data, 0, dw * dh * sizeof(DATA32)); + __imlib_GrabDrawableToRGBA(back->data, 0, 0, dw, dh, d, w, 0, v, cm, + depth, dx1, dy1, dw, dh, 0, 1); + + __imlib_BlendImageToImageSkewed(im, back, antialias, 1, 0, sx, sy, sw, sh, + dx - dx1, dy - dy1, hsx, hsy, vsx, vsy, + cmod, op, 0, 0, 0, 0); + + __imlib_RenderImage(d, back, w, m, v, cm, depth, 0, 0, dw, dh, + dx1, dy1, dw, dh, 0, hiq, 0, dither_mask, 0, OP_COPY); + __imlib_FreeImage(back); +} + +#endif diff --git a/src/lib/rend.h b/src/lib/rend.h new file mode 100644 index 0000000..4705570 --- /dev/null +++ b/src/lib/rend.h @@ -0,0 +1,29 @@ +#ifndef __REND +#define __REND 1 + +#ifdef BUILD_X11 + +DATA32 +__imlib_RenderGetPixel(Display *d, Drawable w, Visual *v, Colormap cm, int depth, DATA8 r, DATA8 g, DATA8 b); + +void +__imlib_RenderImage(Display *d, ImlibImage *im, + Drawable w, Drawable m, + Visual *v, Colormap cm, int depth, + int sx, int sy, int sw, int sh, + int dx, int dy, int dw, int dh, + char anitalias, char hiq, char blend, char dither_mask, + ImlibColorModifier *cmod, ImlibOp op); + +void +__imlib_RenderImageSkewed(Display *d, ImlibImage *im, Drawable w, + Drawable m, Visual *v, Colormap cm, int depth, + int sx, int sy, int sw, int sh, int dx, int dy, + int hsx, int hsy, int vsx, int vsy, + char antialias, char hiq, char blend, + char dither_mask, ImlibColorModifier *cmod, + ImlibOp op); + +#endif + +#endif diff --git a/src/lib/rgba.c b/src/lib/rgba.c new file mode 100644 index 0000000..c54b1f2 --- /dev/null +++ b/src/lib/rgba.c @@ -0,0 +1,4966 @@ +#include "common.h" +#ifdef BUILD_X11 +# include +# include "context.h" +#endif +#include "rgba.h" + +#ifdef BUILD_X11 + +#define IS_ALIGNED_64(val) (!((val) & 0x7)) +#define IS_ALIGNED_32(val) (!((val) & 0x3)) +#define IS_ALIGNED_16(val) (!((val) & 0x1)) + +#define IS_MULTIPLE_2(val) (!((val) & 0x1)) +#define IS_MULTIPLE_4(val) (!((val) & 0x3)) + +/* for PPC / Motorola / SPARC, not x86, ALPHA */ +/* dont uncomment this - i have this here for my own testing */ +/*#define WORDS_BIGENDIAN*/ +/* for data in ABGR memory model */ + +/* NOTES: */ +/* x86: RGBA in byte order = ABGR when read as an int (in register/int) */ + +/* lookup table to see what color index to use */ +static DATA8 *_dither_color_lut; +static DATA8 _pal_type; + +/* using DATA32 - major speedup for aligned memory reads */ + +/* these data structs global rather than context-based for speed */ +static DATA16 *_dither_r16; +static DATA16 *_dither_g16; +static DATA16 *_dither_b16; +static DATA8 *_dither_r8; +static DATA8 *_dither_g8; +static DATA8 *_dither_b8; +static DATA8 *_dither_666r; +static DATA8 *_dither_666g; +static DATA8 *_dither_666b; +static int dither_a_init = 0; +static DATA8 _dither_a1[8 * 8 * 256]; + +/* the famous dither matrix */ +const DATA8 _dither_44[4][4] = { + {0, 4, 1, 5}, + {6, 2, 7, 3}, + {1, 5, 0, 4}, + {7, 3, 6, 2} +}; +const DATA8 _dither_88[8][8] = { + {0, 32, 8, 40, 2, 34, 10, 42}, + {48, 16, 56, 24, 50, 18, 58, 26}, + {12, 44, 4, 36, 14, 46, 6, 38}, + {60, 28, 52, 20, 62, 30, 54, 22}, + {3, 35, 11, 43, 1, 33, 9, 41}, + {51, 19, 59, 27, 49, 17, 57, 25}, + {15, 47, 7, 39, 13, 45, 5, 37}, + {63, 31, 55, 23, 61, 29, 53, 21} +}; + +/* This dither table was generated by Raph Levien using patented + * technology (US Patent 5,276,535). The dither table itself is in the + * public domain. */ + +const DATA8 _dither_128128[128][128] = { + {0, 41, 23, 5, 17, 39, 7, 15, 62, 23, 40, 51, 31, 47, 9, 32, 52, 27, 57, 25, + 6, 61, 27, 52, 37, 7, 40, 63, 18, 36, 10, 42, 25, 62, 45, 34, 20, 42, 37, + 14, 35, 29, 50, 10, 61, 2, 40, 8, 37, 12, 58, 22, 5, 41, 10, 39, 0, 60, 11, + 46, 2, 55, 38, 17, 36, 59, 13, 54, 37, 56, 8, 29, 16, 13, 63, 22, 41, 55, 7, + 20, 49, 14, 23, 55, 37, 23, 19, 36, 15, 49, 23, 63, 30, 14, 38, 27, 53, 13, + 22, 41, 19, 31, 7, 19, 50, 30, 49, 16, 3, 32, 56, 40, 29, 34, 8, 48, 19, 45, + 4, 51, 12, 46, 35, 49, 16, 42, 12, 62}, + {30, 57, 36, 54, 47, 34, 52, 27, 43, 4, 28, 7, 17, 36, 62, 13, 44, 7, 18, 48, + 33, 21, 44, 14, 30, 47, 12, 33, 5, 55, 31, 58, 13, 30, 4, 17, 52, 10, 60, + 26, 46, 0, 39, 27, 42, 22, 47, 25, 60, 32, 9, 38, 48, 17, 59, 30, 49, 18, + 34, 25, 51, 19, 5, 48, 21, 8, 28, 46, 1, 32, 41, 19, 54, 47, 37, 18, 28, 11, + 44, 30, 39, 56, 2, 33, 8, 42, 61, 28, 58, 8, 46, 9, 41, 4, 58, 7, 21, 48, + 59, 10, 52, 14, 42, 57, 12, 25, 7, 53, 42, 24, 11, 50, 17, 59, 42, 2, 36, + 60, 32, 17, 63, 29, 21, 7, 59, 32, 24, 39}, + {22, 8, 16, 32, 3, 25, 13, 57, 18, 45, 58, 39, 55, 20, 5, 42, 23, 34, 63, 1, + 51, 10, 58, 4, 60, 23, 53, 27, 44, 21, 3, 48, 8, 50, 43, 54, 27, 32, 5, 55, + 21, 58, 12, 53, 6, 36, 14, 50, 17, 29, 53, 15, 24, 52, 7, 36, 13, 42, 4, 53, + 9, 35, 61, 26, 56, 32, 49, 15, 62, 23, 6, 60, 2, 31, 4, 48, 58, 38, 15, 61, + 5, 25, 47, 28, 50, 15, 7, 40, 3, 32, 33, 52, 25, 50, 35, 42, 61, 3, 28, 36, + 23, 63, 4, 33, 46, 62, 36, 23, 60, 6, 54, 28, 4, 37, 23, 55, 25, 8, 42, 54, + 14, 6, 56, 38, 19, 52, 4, 46}, + {48, 53, 43, 12, 45, 63, 30, 37, 9, 34, 21, 1, 25, 47, 29, 58, 3, 54, 15, 39, + 29, 17, 38, 35, 20, 43, 1, 49, 15, 59, 29, 39, 22, 35, 16, 23, 1, 47, 39, + 18, 8, 44, 25, 31, 57, 19, 63, 4, 45, 3, 42, 61, 1, 31, 45, 20, 57, 29, 62, + 21, 32, 41, 14, 44, 3, 39, 5, 34, 10, 43, 51, 35, 23, 52, 40, 10, 21, 1, 53, + 18, 51, 43, 12, 62, 18, 54, 26, 51, 20, 57, 14, 1, 62, 16, 11, 18, 32, 39, + 17, 44, 1, 48, 26, 37, 18, 2, 51, 14, 28, 45, 35, 18, 57, 13, 47, 11, 51, + 20, 2, 39, 31, 47, 25, 1, 50, 11, 60, 7}, + {18, 28, 1, 56, 21, 10, 51, 2, 46, 54, 14, 61, 11, 50, 13, 38, 19, 31, 45, 9, + 55, 24, 47, 5, 54, 9, 62, 11, 35, 8, 51, 14, 57, 6, 63, 40, 58, 14, 51, 28, + 62, 34, 15, 48, 1, 41, 30, 35, 55, 21, 34, 11, 49, 37, 8, 52, 4, 23, 15, 43, + 1, 58, 11, 23, 53, 16, 55, 26, 58, 18, 27, 12, 45, 14, 25, 63, 42, 33, 27, + 35, 9, 31, 21, 38, 1, 44, 34, 12, 48, 38, 21, 44, 29, 47, 26, 53, 1, 46, 54, + 8, 59, 29, 11, 55, 22, 41, 33, 20, 39, 1, 48, 9, 44, 32, 5, 62, 29, 44, 57, + 23, 10, 58, 34, 43, 15, 37, 26, 33}, + {51, 38, 59, 24, 35, 42, 19, 60, 5, 32, 41, 26, 43, 33, 7, 53, 48, 11, 59, + 23, 42, 2, 61, 30, 16, 40, 32, 24, 56, 41, 19, 33, 37, 26, 47, 9, 31, 22, 2, + 45, 9, 54, 4, 37, 21, 52, 11, 23, 7, 57, 16, 25, 55, 18, 63, 27, 46, 39, 56, + 10, 50, 37, 29, 47, 19, 63, 24, 9, 46, 2, 39, 60, 9, 57, 30, 7, 49, 11, 59, + 3, 45, 57, 5, 60, 29, 22, 5, 60, 30, 9, 59, 18, 40, 6, 57, 36, 30, 12, 24, + 34, 15, 40, 52, 6, 49, 9, 58, 4, 63, 12, 26, 61, 22, 53, 38, 16, 35, 14, 28, + 50, 42, 17, 5, 28, 62, 20, 54, 12}, + {26, 6, 31, 15, 49, 6, 38, 27, 22, 49, 16, 56, 2, 62, 30, 21, 0, 36, 28, 6, + 49, 32, 13, 52, 26, 50, 19, 46, 3, 26, 62, 0, 53, 12, 29, 3, 53, 41, 60, 24, + 38, 13, 58, 16, 43, 9, 59, 39, 46, 28, 44, 40, 2, 33, 13, 41, 16, 6, 47, 31, + 26, 17, 57, 6, 38, 0, 42, 36, 29, 52, 20, 31, 48, 0, 34, 56, 20, 36, 23, 54, + 14, 41, 24, 37, 10, 55, 46, 25, 16, 45, 36, 4, 55, 23, 15, 8, 50, 62, 5, 56, + 44, 20, 13, 28, 59, 31, 24, 47, 31, 52, 37, 17, 40, 0, 26, 49, 3, 60, 7, 33, + 0, 61, 53, 40, 8, 45, 2, 41}, + {16, 63, 43, 4, 61, 24, 56, 13, 53, 8, 36, 12, 24, 41, 16, 46, 60, 26, 52, + 39, 14, 57, 21, 37, 0, 45, 7, 59, 38, 17, 43, 10, 45, 20, 61, 43, 19, 11, + 33, 17, 50, 32, 23, 61, 28, 49, 26, 0, 18, 51, 5, 60, 22, 58, 29, 0, 59, 34, + 19, 62, 3, 52, 7, 44, 30, 59, 13, 50, 15, 62, 7, 17, 38, 22, 44, 15, 40, 4, + 47, 28, 33, 17, 49, 16, 51, 40, 10, 56, 0, 53, 13, 49, 28, 38, 60, 21, 43, + 19, 37, 27, 3, 51, 34, 39, 0, 45, 15, 43, 10, 21, 3, 55, 8, 33, 59, 10, 41, + 18, 52, 24, 46, 20, 30, 13, 58, 22, 36, 57}, + {50, 34, 11, 47, 29, 17, 44, 0, 33, 63, 28, 46, 52, 5, 57, 10, 42, 18, 4, 63, + 20, 8, 44, 10, 56, 34, 14, 29, 5, 54, 23, 59, 32, 49, 7, 34, 49, 27, 56, 0, + 42, 7, 46, 3, 40, 6, 54, 32, 62, 13, 36, 10, 47, 8, 35, 49, 24, 51, 12, 40, + 22, 35, 60, 12, 22, 51, 33, 4, 40, 25, 43, 55, 5, 54, 12, 61, 26, 51, 8, 62, + 0, 53, 7, 63, 2, 32, 19, 34, 42, 24, 31, 63, 2, 10, 45, 33, 0, 48, 9, 61, + 22, 47, 8, 62, 18, 56, 7, 54, 27, 57, 46, 30, 50, 19, 45, 30, 56, 36, 22, + 47, 11, 38, 3, 51, 32, 48, 18, 9}, + {0, 21, 40, 19, 52, 9, 37, 48, 20, 40, 3, 18, 27, 38, 35, 22, 31, 56, 13, 35, + 46, 28, 60, 40, 27, 18, 61, 50, 41, 30, 7, 36, 2, 25, 16, 57, 5, 15, 47, 29, + 55, 19, 30, 52, 15, 34, 20, 12, 43, 30, 20, 54, 25, 44, 53, 12, 38, 5, 55, + 27, 48, 15, 33, 27, 45, 8, 19, 28, 56, 11, 33, 49, 18, 36, 29, 2, 45, 16, + 39, 19, 31, 43, 27, 35, 20, 52, 26, 6, 61, 11, 41, 17, 29, 51, 20, 56, 25, + 32, 41, 17, 53, 31, 25, 14, 42, 23, 35, 16, 38, 6, 34, 12, 15, 62, 6, 21, + 13, 1, 63, 9, 55, 27, 43, 25, 14, 4, 31, 55}, + {44, 29, 61, 2, 35, 58, 26, 15, 60, 10, 51, 59, 14, 55, 8, 50, 2, 44, 25, 51, + 1, 33, 16, 4, 48, 36, 2, 21, 12, 57, 48, 13, 51, 55, 40, 28, 37, 62, 8, 39, + 12, 63, 36, 10, 59, 24, 56, 47, 9, 50, 41, 1, 32, 17, 6, 21, 61, 30, 9, 43, + 1, 54, 41, 2, 54, 37, 48, 61, 1, 46, 21, 3, 58, 24, 50, 32, 60, 10, 57, 25, + 46, 12, 59, 4, 45, 13, 57, 47, 27, 39, 5, 58, 47, 14, 35, 4, 52, 13, 60, 6, + 36, 10, 45, 55, 4, 50, 29, 2, 61, 50, 25, 58, 44, 24, 36, 42, 54, 28, 40, + 32, 16, 56, 6, 62, 46, 39, 60, 23}, + {7, 48, 14, 54, 23, 40, 4, 45, 30, 22, 42, 32, 1, 44, 20, 29, 58, 8, 37, 19, + 41, 54, 24, 58, 9, 53, 25, 46, 34, 16, 23, 38, 27, 11, 18, 1, 52, 21, 35, + 22, 48, 5, 25, 45, 18, 38, 2, 27, 35, 4, 57, 15, 62, 39, 57, 28, 42, 16, 36, + 60, 24, 18, 10, 63, 20, 5, 16, 23, 37, 14, 59, 27, 41, 8, 13, 42, 21, 35, 6, + 50, 3, 38, 15, 48, 30, 39, 17, 3, 49, 14, 53, 33, 24, 7, 61, 44, 11, 39, 23, + 49, 19, 58, 1, 32, 36, 12, 60, 41, 20, 13, 41, 4, 39, 1, 48, 8, 18, 51, 14, + 44, 5, 37, 21, 34, 1, 26, 10, 37}, + {53, 36, 27, 9, 50, 12, 32, 55, 2, 57, 7, 17, 48, 34, 63, 15, 40, 26, 62, 11, + 49, 6, 31, 39, 22, 42, 6, 63, 1, 39, 60, 4, 42, 61, 32, 45, 24, 44, 2, 60, + 16, 41, 53, 1, 33, 61, 49, 17, 63, 23, 45, 26, 33, 3, 23, 46, 2, 50, 20, 4, + 45, 34, 49, 30, 39, 58, 44, 31, 53, 34, 6, 52, 30, 47, 63, 1, 53, 22, 42, + 31, 58, 23, 54, 22, 61, 8, 36, 59, 22, 35, 21, 1, 55, 40, 27, 16, 30, 54, 2, + 29, 43, 16, 39, 63, 21, 46, 26, 10, 48, 32, 19, 53, 30, 56, 26, 60, 33, 4, + 61, 23, 49, 59, 15, 53, 19, 58, 42, 16}, + {20, 5, 59, 46, 25, 62, 7, 19, 43, 25, 37, 61, 11, 24, 4, 54, 12, 52, 3, 32, + 17, 61, 12, 47, 15, 55, 18, 31, 53, 28, 9, 50, 21, 6, 55, 9, 58, 14, 54, 26, + 33, 7, 31, 58, 13, 21, 8, 42, 29, 6, 37, 11, 48, 52, 14, 60, 11, 39, 56, 32, + 14, 58, 7, 26, 17, 4, 42, 8, 11, 47, 19, 38, 10, 17, 26, 37, 9, 55, 28, 13, + 18, 40, 6, 33, 1, 43, 25, 11, 51, 7, 62, 43, 18, 37, 3, 57, 45, 9, 38, 58, + 5, 52, 27, 7, 17, 53, 5, 57, 37, 2, 63, 9, 22, 15, 11, 38, 25, 45, 35, 0, + 28, 10, 41, 30, 50, 8, 31, 57}, + {49, 33, 16, 38, 1, 42, 51, 34, 53, 14, 28, 49, 30, 56, 36, 23, 43, 20, 38, + 56, 22, 45, 28, 0, 62, 35, 26, 44, 11, 19, 52, 35, 44, 15, 30, 38, 10, 31, + 40, 4, 46, 50, 20, 40, 27, 44, 51, 14, 56, 53, 19, 59, 7, 29, 41, 19, 35, + 25, 8, 52, 22, 44, 13, 53, 50, 32, 61, 24, 56, 25, 63, 0, 45, 57, 33, 59, + 16, 46, 4, 62, 50, 11, 60, 37, 52, 19, 55, 29, 37, 46, 13, 26, 48, 10, 50, + 34, 21, 63, 26, 13, 42, 33, 22, 55, 35, 28, 43, 15, 24, 51, 27, 34, 46, 49, + 58, 3, 52, 9, 57, 19, 48, 55, 3, 35, 12, 45, 24, 3}, + {41, 11, 56, 28, 18, 31, 22, 10, 37, 6, 47, 13, 3, 41, 9, 46, 0, 48, 29, 6, + 34, 10, 55, 37, 20, 8, 49, 3, 41, 59, 14, 25, 0, 63, 19, 47, 27, 51, 17, 57, + 23, 10, 61, 6, 54, 3, 38, 31, 0, 22, 34, 43, 20, 55, 31, 0, 49, 63, 29, 38, + 3, 62, 28, 40, 0, 22, 14, 35, 2, 48, 15, 43, 23, 14, 3, 29, 49, 20, 39, 34, + 0, 44, 29, 9, 15, 47, 5, 42, 0, 31, 58, 5, 31, 61, 23, 15, 0, 47, 19, 50, + 24, 3, 59, 11, 44, 0, 31, 59, 6, 42, 17, 60, 0, 39, 20, 31, 43, 17, 29, 40, + 12, 25, 60, 22, 52, 15, 63, 29}, + {20, 52, 8, 44, 62, 4, 59, 49, 17, 63, 21, 39, 60, 18, 52, 27, 33, 59, 14, + 51, 59, 43, 24, 5, 51, 30, 57, 17, 32, 5, 37, 56, 48, 34, 42, 3, 60, 5, 36, + 13, 43, 37, 18, 34, 25, 12, 59, 24, 47, 36, 11, 50, 3, 38, 9, 58, 16, 5, 43, + 18, 47, 10, 37, 18, 59, 46, 29, 52, 40, 12, 34, 28, 56, 36, 53, 7, 43, 8, + 24, 52, 26, 17, 56, 43, 24, 32, 63, 20, 57, 16, 22, 52, 36, 8, 41, 56, 29, + 32, 54, 7, 35, 57, 14, 48, 20, 62, 13, 39, 53, 29, 8, 45, 13, 29, 7, 61, 14, + 54, 6, 63, 38, 32, 18, 43, 2, 39, 6, 47}, + {0, 58, 23, 35, 13, 46, 12, 39, 0, 31, 55, 24, 5, 35, 15, 61, 17, 5, 39, 25, + 18, 2, 50, 33, 41, 13, 39, 23, 62, 46, 29, 12, 22, 8, 56, 25, 20, 49, 32, + 62, 0, 56, 11, 46, 63, 42, 9, 16, 55, 5, 60, 15, 62, 26, 45, 21, 36, 51, 13, + 57, 31, 24, 55, 6, 35, 9, 57, 5, 20, 60, 7, 51, 5, 19, 40, 25, 61, 32, 56, + 12, 36, 48, 21, 2, 58, 12, 39, 28, 9, 50, 40, 12, 44, 18, 25, 49, 6, 38, 11, + 62, 18, 46, 30, 9, 40, 25, 49, 19, 10, 36, 55, 22, 33, 52, 41, 18, 37, 27, + 49, 21, 2, 46, 7, 53, 33, 61, 27, 35}, + {41, 31, 5, 39, 51, 26, 33, 57, 27, 41, 9, 44, 54, 29, 48, 7, 44, 36, 57, 10, + 31, 63, 16, 45, 11, 60, 1, 47, 7, 20, 43, 3, 58, 36, 13, 52, 39, 7, 15, 28, + 22, 48, 30, 21, 1, 29, 49, 44, 27, 17, 40, 30, 24, 42, 12, 53, 33, 7, 47, + 20, 1, 42, 11, 49, 25, 43, 17, 32, 45, 27, 41, 21, 31, 62, 11, 49, 2, 15, + 42, 5, 63, 7, 41, 27, 49, 6, 54, 23, 46, 34, 2, 28, 54, 3, 59, 12, 46, 17, + 42, 28, 40, 1, 37, 51, 5, 55, 2, 34, 47, 16, 3, 62, 47, 5, 23, 56, 1, 44, + 12, 34, 51, 16, 57, 11, 25, 17, 54, 13}, + {60, 26, 55, 18, 3, 60, 20, 6, 52, 15, 50, 19, 32, 11, 23, 53, 26, 21, 1, 47, + 42, 27, 8, 58, 21, 27, 53, 36, 26, 54, 31, 50, 17, 30, 45, 1, 29, 59, 44, + 53, 41, 4, 35, 58, 51, 19, 32, 4, 52, 34, 48, 8, 51, 5, 56, 2, 25, 61, 27, + 38, 54, 27, 62, 21, 51, 1, 39, 62, 10, 50, 1, 58, 13, 47, 38, 18, 35, 54, + 22, 51, 30, 19, 59, 34, 14, 32, 44, 4, 60, 15, 52, 62, 20, 43, 30, 35, 21, + 60, 4, 52, 12, 24, 61, 18, 30, 42, 23, 61, 25, 50, 27, 38, 11, 59, 12, 35, + 50, 30, 59, 24, 8, 42, 28, 37, 48, 9, 44, 21}, + {10, 47, 15, 50, 30, 43, 8, 45, 29, 2, 36, 59, 1, 58, 41, 3, 63, 31, 54, 20, + 13, 55, 35, 38, 4, 44, 15, 9, 61, 2, 14, 38, 61, 10, 23, 54, 18, 12, 24, 2, + 14, 55, 16, 8, 38, 14, 41, 60, 10, 23, 1, 58, 32, 17, 28, 37, 41, 15, 3, 60, + 15, 33, 4, 36, 16, 59, 28, 14, 23, 55, 37, 18, 44, 28, 2, 57, 30, 10, 27, + 46, 14, 38, 3, 53, 21, 61, 17, 35, 10, 41, 26, 7, 33, 9, 57, 1, 53, 37, 26, + 20, 56, 48, 9, 33, 58, 16, 37, 7, 45, 1, 57, 15, 32, 26, 42, 23, 7, 20, 4, + 54, 31, 62, 22, 1, 59, 30, 4, 51}, + {36, 2, 38, 11, 24, 36, 54, 22, 62, 47, 25, 8, 28, 45, 16, 38, 12, 43, 9, 37, + 49, 3, 23, 52, 18, 30, 50, 33, 19, 42, 49, 26, 6, 40, 47, 35, 63, 38, 50, + 33, 60, 26, 36, 47, 24, 57, 6, 26, 39, 63, 19, 44, 14, 46, 61, 9, 50, 30, + 45, 23, 10, 50, 44, 8, 31, 54, 6, 46, 36, 4, 30, 54, 8, 52, 22, 41, 4, 60, + 40, 0, 58, 24, 45, 10, 37, 1, 48, 30, 56, 17, 38, 48, 24, 47, 19, 39, 14, 8, + 45, 32, 2, 34, 27, 44, 4, 52, 11, 56, 31, 21, 40, 19, 44, 51, 2, 63, 46, 58, + 36, 43, 14, 5, 50, 38, 14, 56, 40, 23}, + {61, 46, 32, 63, 54, 1, 14, 34, 12, 40, 18, 49, 37, 10, 61, 30, 51, 24, 60, + 7, 29, 40, 62, 11, 46, 58, 6, 56, 24, 10, 34, 52, 21, 59, 16, 3, 27, 5, 20, + 46, 9, 40, 7, 62, 2, 30, 53, 15, 48, 10, 28, 35, 54, 6, 21, 34, 18, 55, 7, + 40, 57, 19, 26, 60, 41, 13, 24, 51, 19, 61, 9, 25, 34, 15, 63, 11, 45, 17, + 20, 47, 33, 8, 31, 62, 43, 26, 53, 7, 24, 59, 0, 13, 55, 4, 62, 27, 51, 31, + 63, 15, 58, 7, 54, 14, 46, 22, 28, 43, 12, 63, 8, 54, 5, 17, 39, 33, 15, 10, + 27, 17, 47, 34, 19, 45, 27, 12, 33, 17}, + {5, 28, 21, 7, 17, 48, 42, 58, 23, 4, 63, 14, 55, 21, 34, 5, 19, 0, 45, 17, + 52, 15, 25, 32, 0, 22, 40, 13, 45, 62, 18, 0, 43, 11, 33, 55, 30, 42, 57, + 19, 51, 31, 22, 43, 18, 45, 34, 0, 43, 31, 56, 3, 23, 40, 59, 0, 44, 13, 48, + 35, 2, 32, 46, 0, 21, 48, 35, 3, 40, 32, 43, 59, 0, 48, 33, 26, 53, 36, 55, + 12, 51, 16, 55, 5, 18, 29, 11, 39, 51, 19, 45, 31, 42, 21, 35, 6, 22, 47, + 10, 38, 23, 50, 20, 36, 0, 60, 38, 4, 50, 35, 48, 34, 24, 57, 9, 53, 28, 48, + 61, 0, 56, 24, 53, 3, 63, 6, 42, 57}, + {13, 53, 45, 40, 58, 27, 6, 16, 38, 51, 33, 30, 43, 2, 47, 56, 40, 50, 33, + 57, 27, 5, 47, 42, 60, 36, 16, 54, 28, 4, 37, 57, 28, 51, 22, 8, 45, 14, 6, + 39, 0, 54, 11, 59, 28, 12, 50, 21, 61, 13, 19, 38, 49, 11, 25, 37, 58, 29, + 22, 63, 14, 56, 12, 53, 30, 63, 9, 57, 26, 12, 47, 16, 23, 39, 50, 6, 31, 2, + 25, 6, 28, 41, 36, 22, 50, 57, 42, 3, 34, 8, 28, 61, 11, 50, 16, 54, 41, 0, + 55, 43, 5, 29, 41, 63, 25, 16, 53, 18, 26, 10, 21, 0, 61, 30, 41, 22, 3, 38, + 20, 39, 29, 8, 41, 16, 36, 52, 22, 19}, + {55, 34, 0, 25, 10, 32, 56, 44, 28, 0, 57, 7, 26, 53, 23, 8, 13, 35, 22, 12, + 36, 60, 20, 8, 14, 29, 48, 2, 41, 49, 23, 13, 39, 7, 48, 58, 25, 53, 34, 62, + 28, 16, 48, 4, 37, 56, 27, 5, 36, 52, 46, 7, 62, 33, 52, 11, 17, 53, 5, 28, + 41, 24, 38, 17, 5, 39, 20, 45, 15, 56, 5, 38, 60, 8, 14, 57, 21, 48, 62, 39, + 59, 13, 1, 60, 9, 32, 16, 63, 44, 25, 52, 15, 36, 2, 60, 29, 12, 33, 25, 17, + 59, 45, 13, 8, 49, 32, 6, 40, 59, 29, 45, 37, 13, 47, 6, 55, 30, 45, 9, 52, + 13, 59, 25, 47, 32, 1, 49, 30}, + {9, 39, 14, 61, 49, 37, 3, 20, 50, 13, 41, 19, 46, 17, 38, 59, 28, 62, 4, 44, + 54, 1, 34, 51, 55, 7, 63, 32, 21, 8, 56, 31, 62, 19, 36, 1, 41, 17, 24, 12, + 42, 35, 25, 52, 20, 8, 44, 59, 25, 2, 22, 42, 16, 29, 4, 46, 20, 36, 43, 9, + 51, 8, 49, 26, 58, 33, 54, 1, 37, 29, 52, 20, 27, 45, 19, 35, 42, 16, 10, + 32, 20, 49, 46, 27, 40, 4, 47, 22, 13, 55, 4, 47, 26, 44, 23, 40, 58, 19, + 48, 13, 31, 2, 57, 34, 42, 19, 61, 32, 14, 55, 5, 51, 26, 19, 58, 16, 49, + 14, 62, 5, 33, 44, 21, 7, 60, 26, 11, 41}, + {62, 24, 47, 29, 8, 19, 53, 11, 60, 24, 32, 61, 4, 55, 31, 2, 49, 16, 39, 9, + 31, 24, 43, 17, 26, 38, 11, 25, 58, 43, 12, 35, 3, 46, 15, 32, 63, 4, 49, + 56, 2, 60, 10, 32, 63, 17, 39, 12, 55, 30, 57, 9, 48, 55, 39, 24, 60, 2, 58, + 31, 19, 61, 34, 3, 42, 11, 22, 46, 7, 61, 10, 42, 3, 55, 32, 1, 58, 28, 44, + 54, 4, 34, 23, 15, 56, 20, 37, 58, 6, 30, 38, 18, 63, 9, 32, 5, 51, 3, 62, + 37, 52, 18, 39, 23, 3, 51, 9, 47, 1, 23, 43, 15, 60, 35, 11, 40, 1, 36, 31, + 26, 57, 2, 37, 54, 18, 44, 58, 16}, + {5, 51, 3, 33, 43, 62, 21, 42, 35, 9, 48, 15, 36, 10, 22, 42, 20, 46, 26, 56, + 50, 12, 59, 3, 48, 19, 45, 53, 1, 27, 47, 17, 52, 24, 56, 11, 51, 21, 37, + 30, 20, 46, 14, 41, 1, 47, 33, 7, 41, 17, 35, 27, 20, 1, 14, 54, 26, 33, 18, + 47, 1, 44, 14, 59, 16, 52, 28, 18, 49, 31, 25, 34, 63, 13, 51, 24, 9, 50, 3, + 23, 38, 63, 7, 52, 29, 46, 11, 33, 50, 22, 57, 36, 1, 57, 49, 17, 39, 28, 9, + 35, 6, 27, 53, 15, 55, 30, 24, 58, 36, 41, 11, 52, 32, 3, 44, 25, 62, 23, + 51, 15, 42, 22, 50, 10, 39, 4, 31, 35}, + {46, 22, 57, 17, 12, 39, 26, 5, 31, 59, 1, 45, 27, 62, 52, 7, 58, 33, 6, 18, + 39, 22, 33, 41, 57, 5, 35, 18, 40, 16, 60, 5, 29, 42, 7, 39, 27, 44, 9, 47, + 8, 26, 54, 22, 51, 29, 24, 49, 15, 61, 4, 51, 31, 63, 43, 6, 50, 8, 39, 12, + 53, 37, 23, 30, 40, 6, 62, 43, 14, 53, 2, 49, 7, 36, 17, 41, 61, 37, 18, 56, + 11, 18, 44, 35, 2, 19, 61, 0, 41, 14, 8, 30, 43, 12, 24, 46, 14, 54, 42, 21, + 44, 61, 10, 46, 37, 11, 44, 7, 18, 63, 20, 29, 7, 49, 28, 54, 8, 43, 4, 48, + 18, 63, 12, 29, 48, 24, 59, 20}, + {13, 36, 28, 54, 35, 2, 56, 46, 16, 49, 22, 40, 11, 34, 14, 43, 29, 12, 63, + 48, 2, 61, 7, 15, 28, 30, 50, 9, 61, 33, 38, 23, 54, 13, 61, 33, 3, 59, 16, + 35, 58, 40, 5, 38, 13, 57, 3, 58, 37, 21, 45, 12, 39, 7, 35, 30, 13, 56, 22, + 62, 27, 6, 55, 10, 48, 21, 33, 2, 38, 23, 40, 20, 44, 29, 59, 4, 26, 12, 33, + 47, 28, 53, 31, 13, 59, 41, 27, 49, 26, 54, 45, 16, 53, 21, 35, 7, 59, 26, + 11, 56, 1, 24, 33, 4, 28, 62, 21, 49, 31, 2, 56, 39, 24, 58, 13, 17, 37, 21, + 56, 10, 38, 0, 34, 55, 15, 43, 1, 52}, + {42, 9, 50, 6, 25, 60, 14, 38, 10, 29, 53, 18, 57, 3, 25, 51, 0, 53, 25, 17, + 29, 37, 52, 46, 0, 62, 14, 37, 4, 50, 10, 44, 0, 46, 20, 25, 50, 19, 55, 0, + 23, 31, 62, 34, 11, 45, 19, 32, 0, 53, 10, 59, 23, 47, 18, 60, 42, 28, 37, + 3, 50, 15, 35, 44, 0, 51, 27, 60, 9, 57, 16, 58, 11, 22, 46, 15, 53, 48, 7, + 42, 0, 60, 5, 49, 24, 54, 9, 17, 39, 5, 34, 62, 3, 40, 60, 31, 0, 47, 29, + 16, 49, 39, 59, 17, 50, 0, 40, 13, 53, 38, 16, 46, 0, 42, 34, 60, 2, 53, 29, + 31, 58, 46, 27, 6, 61, 8, 37, 28}, + {0, 63, 21, 40, 45, 18, 51, 23, 63, 34, 6, 43, 28, 38, 55, 19, 40, 35, 8, 41, + 54, 10, 21, 32, 39, 23, 53, 26, 55, 28, 22, 63, 30, 34, 9, 48, 6, 38, 29, + 43, 49, 6, 18, 52, 27, 61, 9, 43, 28, 42, 33, 26, 56, 3, 51, 23, 0, 48, 16, + 45, 32, 25, 63, 20, 57, 17, 42, 12, 35, 47, 5, 31, 39, 56, 6, 30, 34, 21, + 61, 25, 14, 40, 22, 38, 15, 6, 36, 56, 20, 60, 25, 12, 51, 27, 10, 56, 42, + 20, 36, 63, 32, 6, 21, 41, 12, 34, 60, 26, 5, 48, 27, 10, 62, 19, 6, 47, 39, + 14, 45, 7, 24, 17, 41, 32, 23, 51, 19, 56}, + {45, 31, 15, 59, 4, 33, 7, 47, 0, 41, 13, 61, 4, 47, 9, 23, 60, 14, 57, 31, + 4, 45, 59, 6, 58, 10, 44, 20, 8, 42, 15, 6, 55, 17, 58, 31, 53, 12, 61, 10, + 15, 57, 43, 2, 23, 35, 48, 14, 54, 6, 18, 49, 15, 38, 11, 34, 62, 9, 21, 58, + 11, 41, 4, 31, 38, 8, 29, 55, 19, 36, 27, 52, 0, 25, 50, 43, 1, 39, 8, 55, + 35, 51, 10, 30, 45, 62, 29, 2, 46, 10, 32, 48, 18, 38, 5, 22, 33, 8, 51, 3, + 14, 44, 54, 25, 57, 30, 18, 52, 33, 22, 59, 28, 36, 52, 32, 21, 26, 50, 5, + 55, 35, 60, 14, 54, 4, 40, 16, 33}, + {27, 3, 49, 10, 30, 40, 55, 27, 57, 24, 52, 21, 32, 17, 60, 30, 5, 44, 27, + 49, 19, 34, 13, 24, 43, 36, 3, 49, 31, 59, 37, 48, 26, 41, 2, 41, 14, 36, + 21, 32, 40, 26, 13, 49, 55, 5, 16, 40, 25, 60, 36, 1, 63, 29, 17, 44, 25, + 40, 52, 5, 29, 47, 54, 13, 46, 24, 60, 4, 51, 22, 63, 14, 45, 18, 12, 62, + 17, 57, 19, 42, 3, 26, 58, 48, 1, 21, 40, 52, 23, 37, 44, 1, 29, 58, 43, 50, + 15, 61, 19, 45, 58, 28, 7, 48, 2, 46, 8, 42, 3, 55, 8, 50, 12, 4, 55, 10, + 63, 33, 20, 40, 11, 3, 46, 20, 48, 26, 61, 11}, + {44, 56, 24, 36, 53, 19, 12, 37, 16, 44, 7, 36, 49, 54, 11, 37, 48, 21, 15, + 1, 62, 25, 47, 56, 16, 18, 51, 12, 40, 1, 24, 11, 52, 16, 23, 59, 28, 1, 45, + 53, 4, 60, 37, 21, 39, 30, 63, 20, 52, 10, 30, 45, 8, 41, 54, 4, 57, 7, 34, + 55, 36, 18, 23, 59, 2, 48, 11, 32, 44, 1, 41, 8, 33, 54, 38, 23, 30, 46, 6, + 29, 62, 18, 32, 16, 55, 34, 14, 11, 61, 7, 55, 16, 53, 13, 23, 2, 55, 37, + 26, 10, 33, 23, 36, 16, 38, 22, 56, 15, 24, 43, 35, 17, 44, 40, 25, 46, 16, + 1, 57, 25, 49, 36, 28, 62, 9, 35, 7, 53}, + {17, 38, 8, 61, 1, 50, 26, 62, 3, 31, 56, 15, 1, 26, 40, 2, 34, 51, 56, 36, + 42, 9, 38, 2, 29, 60, 32, 57, 19, 62, 34, 47, 4, 57, 39, 7, 44, 63, 24, 18, + 46, 28, 8, 54, 1, 34, 7, 46, 3, 37, 50, 23, 57, 21, 13, 46, 31, 20, 43, 15, + 1, 61, 8, 33, 37, 17, 56, 26, 15, 49, 24, 59, 28, 3, 56, 9, 52, 32, 13, 49, + 10, 43, 5, 45, 8, 25, 59, 42, 28, 33, 19, 40, 8, 63, 35, 47, 25, 4, 40, 52, + 1, 60, 12, 53, 63, 9, 29, 60, 37, 19, 1, 62, 31, 20, 58, 12, 41, 30, 43, 9, + 18, 52, 22, 1, 39, 30, 58, 21}, + {13, 47, 29, 18, 43, 34, 5, 48, 20, 42, 10, 45, 30, 58, 20, 63, 24, 11, 6, + 28, 54, 14, 22, 52, 41, 7, 26, 5, 45, 15, 53, 13, 35, 27, 18, 50, 12, 33, 5, + 56, 10, 17, 45, 24, 59, 15, 50, 26, 56, 13, 19, 5, 32, 52, 27, 36, 2, 61, + 12, 26, 49, 40, 27, 52, 13, 50, 6, 39, 61, 34, 10, 37, 48, 20, 41, 27, 2, + 36, 59, 24, 54, 33, 63, 20, 38, 50, 3, 17, 52, 4, 58, 27, 45, 21, 32, 11, + 48, 17, 57, 20, 46, 38, 25, 43, 4, 34, 51, 6, 13, 45, 57, 26, 6, 48, 2, 35, + 53, 23, 61, 34, 59, 6, 42, 56, 13, 51, 2, 41}, + {32, 5, 55, 23, 58, 14, 22, 52, 29, 15, 61, 25, 51, 8, 43, 13, 53, 41, 46, + 20, 3, 33, 63, 11, 48, 21, 54, 38, 28, 3, 30, 43, 21, 62, 9, 31, 55, 22, 51, + 29, 37, 62, 32, 12, 42, 29, 41, 9, 33, 44, 62, 28, 43, 1, 59, 19, 48, 30, + 51, 39, 24, 4, 58, 19, 42, 29, 22, 43, 3, 18, 53, 5, 13, 50, 16, 60, 45, 21, + 7, 40, 15, 0, 26, 53, 13, 31, 43, 24, 47, 31, 15, 49, 2, 41, 6, 59, 29, 42, + 9, 30, 14, 7, 49, 18, 31, 47, 20, 39, 49, 32, 11, 41, 54, 15, 61, 18, 7, 38, + 4, 13, 44, 28, 15, 32, 45, 19, 27, 49}, + {63, 34, 11, 39, 2, 45, 37, 8, 59, 39, 33, 4, 36, 17, 48, 5, 29, 18, 32, 61, + 39, 50, 5, 27, 35, 0, 46, 12, 22, 49, 60, 6, 54, 0, 38, 49, 2, 42, 15, 40, + 0, 47, 20, 51, 3, 57, 18, 61, 22, 0, 39, 16, 55, 12, 35, 8, 41, 22, 6, 59, + 16, 45, 10, 36, 0, 62, 9, 54, 30, 58, 21, 43, 63, 31, 7, 35, 12, 48, 58, 28, + 47, 37, 41, 9, 57, 20, 61, 0, 36, 11, 57, 35, 23, 52, 37, 18, 0, 62, 22, 55, + 35, 62, 27, 54, 0, 15, 61, 28, 2, 59, 22, 9, 37, 27, 33, 51, 29, 48, 19, 50, + 25, 37, 10, 57, 5, 37, 60, 8}, + {20, 25, 46, 52, 31, 60, 12, 55, 0, 19, 11, 46, 62, 35, 23, 38, 57, 0, 55, + 10, 16, 30, 58, 44, 17, 59, 29, 63, 42, 8, 36, 20, 33, 46, 16, 61, 25, 35, + 8, 54, 26, 7, 58, 22, 34, 6, 47, 14, 53, 31, 48, 9, 37, 25, 49, 63, 16, 55, + 45, 14, 34, 63, 21, 53, 25, 33, 46, 16, 35, 7, 46, 29, 0, 39, 25, 55, 22, + 34, 18, 4, 56, 11, 23, 51, 28, 6, 39, 14, 62, 44, 19, 8, 60, 12, 56, 28, 50, + 34, 39, 5, 51, 3, 41, 12, 57, 35, 10, 53, 25, 17, 52, 30, 47, 0, 43, 14, 5, + 57, 31, 55, 0, 63, 47, 23, 54, 24, 14, 43}, + {0, 57, 16, 6, 26, 19, 35, 28, 49, 42, 54, 26, 21, 1, 59, 27, 9, 47, 26, 44, + 50, 22, 13, 40, 8, 37, 10, 34, 17, 56, 25, 58, 13, 27, 44, 9, 20, 58, 31, + 17, 60, 36, 10, 41, 53, 25, 36, 39, 4, 24, 58, 17, 60, 4, 22, 38, 10, 32, 0, + 50, 31, 7, 28, 47, 12, 57, 5, 26, 52, 23, 14, 40, 57, 17, 47, 5, 53, 1, 44, + 31, 19, 60, 46, 2, 35, 48, 30, 54, 22, 5, 51, 39, 25, 31, 4, 43, 14, 9, 45, + 16, 24, 44, 19, 29, 40, 23, 44, 7, 38, 42, 4, 63, 12, 54, 23, 59, 22, 42, 8, + 15, 40, 21, 8, 34, 3, 41, 30, 50}, + {39, 10, 48, 33, 41, 54, 5, 47, 23, 13, 32, 7, 52, 44, 14, 39, 58, 18, 35, 6, + 37, 2, 60, 24, 55, 19, 53, 2, 51, 32, 1, 41, 51, 4, 40, 29, 47, 3, 52, 44, + 13, 49, 28, 16, 1, 62, 11, 27, 52, 35, 5, 42, 29, 47, 14, 56, 28, 53, 26, + 38, 9, 56, 40, 3, 38, 15, 41, 60, 1, 37, 50, 25, 11, 28, 61, 19, 42, 62, 10, + 52, 39, 6, 32, 14, 58, 17, 7, 26, 42, 34, 27, 10, 54, 40, 20, 63, 26, 53, + 21, 61, 32, 7, 59, 48, 3, 56, 18, 31, 58, 14, 49, 21, 36, 16, 45, 9, 36, 24, + 62, 45, 27, 31, 53, 17, 49, 12, 62, 18}, + {28, 59, 21, 58, 2, 16, 38, 9, 62, 3, 56, 41, 10, 31, 50, 4, 32, 52, 12, 63, + 23, 46, 33, 31, 4, 48, 25, 43, 14, 23, 47, 11, 22, 55, 14, 60, 23, 37, 11, + 39, 23, 2, 45, 56, 31, 43, 19, 55, 16, 46, 21, 51, 11, 33, 44, 2, 41, 18, 5, + 52, 23, 44, 17, 60, 27, 49, 11, 32, 44, 10, 54, 2, 56, 33, 8, 38, 13, 29, + 36, 16, 24, 63, 27, 51, 21, 43, 56, 12, 49, 3, 59, 48, 1, 15, 46, 7, 36, 2, + 47, 11, 50, 27, 37, 13, 33, 8, 51, 46, 1, 34, 28, 40, 3, 33, 60, 29, 47, 1, + 35, 11, 59, 42, 2, 60, 26, 46, 6, 35}, + {4, 43, 9, 29, 36, 63, 24, 44, 20, 50, 30, 17, 60, 22, 16, 43, 25, 3, 42, 19, + 51, 15, 8, 54, 42, 15, 61, 5, 39, 57, 18, 61, 31, 48, 34, 2, 50, 19, 57, 5, + 63, 33, 19, 38, 13, 27, 48, 7, 32, 61, 2, 26, 58, 6, 24, 50, 13, 61, 42, 20, + 62, 2, 35, 20, 51, 4, 62, 18, 23, 58, 20, 31, 43, 15, 51, 45, 26, 50, 4, 55, + 45, 3, 35, 9, 38, 1, 32, 61, 20, 45, 17, 33, 24, 57, 29, 51, 22, 58, 38, 30, + 15, 1, 54, 21, 63, 43, 26, 12, 24, 56, 8, 60, 50, 19, 5, 52, 13, 54, 17, 50, + 4, 16, 36, 12, 32, 56, 22, 54}, + {51, 25, 40, 53, 12, 49, 15, 57, 34, 7, 38, 47, 2, 36, 55, 8, 61, 30, 56, 7, + 28, 59, 48, 11, 27, 35, 21, 45, 28, 36, 9, 38, 6, 16, 24, 63, 10, 32, 28, + 43, 21, 53, 5, 60, 8, 57, 3, 45, 11, 37, 15, 54, 40, 20, 62, 36, 27, 34, 11, + 48, 30, 15, 54, 8, 30, 42, 22, 34, 48, 13, 35, 63, 4, 37, 22, 2, 59, 9, 41, + 23, 13, 41, 49, 18, 59, 24, 40, 5, 37, 30, 9, 61, 44, 6, 37, 11, 33, 17, 5, + 55, 41, 60, 23, 39, 17, 5, 30, 62, 41, 16, 46, 25, 11, 56, 39, 26, 20, 38, + 29, 39, 22, 52, 44, 20, 48, 1, 38, 14}, + {15, 33, 2, 18, 44, 6, 27, 0, 32, 61, 25, 12, 58, 28, 40, 20, 47, 13, 34, 43, + 38, 1, 23, 62, 40, 0, 51, 10, 63, 3, 52, 26, 44, 30, 45, 6, 41, 54, 0, 51, + 12, 30, 46, 24, 49, 22, 40, 33, 63, 23, 43, 30, 9, 47, 0, 17, 54, 7, 57, 3, + 37, 47, 24, 46, 13, 55, 7, 52, 2, 42, 6, 26, 49, 18, 60, 34, 16, 57, 33, 20, + 61, 30, 8, 54, 14, 46, 12, 53, 16, 55, 38, 13, 22, 53, 18, 59, 46, 27, 43, + 19, 32, 10, 45, 6, 49, 36, 52, 2, 20, 55, 6, 39, 32, 15, 44, 3, 58, 10, 63, + 6, 56, 30, 7, 58, 9, 40, 19, 63}, + {10, 47, 61, 23, 55, 31, 52, 42, 17, 45, 4, 51, 27, 6, 15, 53, 0, 49, 26, 10, + 56, 18, 36, 6, 20, 58, 32, 30, 13, 49, 19, 56, 0, 59, 12, 53, 27, 17, 38, + 25, 48, 9, 15, 36, 14, 30, 59, 17, 0, 50, 8, 58, 18, 56, 31, 45, 21, 41, 29, + 19, 60, 6, 32, 59, 0, 36, 29, 39, 19, 59, 46, 12, 55, 30, 10, 47, 24, 3, 28, + 48, 0, 55, 44, 27, 33, 4, 63, 29, 49, 0, 26, 50, 34, 2, 42, 14, 0, 62, 9, + 56, 3, 52, 28, 34, 58, 9, 20, 48, 37, 32, 22, 53, 0, 62, 27, 49, 34, 46, 21, + 33, 41, 14, 25, 37, 53, 29, 31, 45}, + {56, 28, 7, 37, 11, 36, 20, 9, 54, 14, 39, 19, 34, 63, 45, 37, 24, 17, 60, + 31, 21, 45, 53, 29, 47, 15, 7, 55, 40, 23, 34, 14, 42, 20, 37, 35, 15, 59, + 7, 62, 34, 40, 59, 1, 51, 42, 10, 28, 54, 21, 35, 5, 38, 13, 36, 4, 59, 12, + 39, 53, 15, 43, 9, 21, 39, 62, 16, 56, 25, 9, 32, 38, 0, 41, 14, 51, 40, 53, + 43, 11, 37, 17, 5, 22, 57, 39, 19, 7, 42, 21, 60, 10, 31, 63, 25, 52, 30, + 49, 36, 25, 48, 17, 61, 14, 22, 42, 29, 13, 60, 11, 47, 18, 35, 41, 7, 23, + 4, 16, 51, 11, 0, 48, 61, 3, 17, 50, 5, 24}, + {0, 42, 21, 49, 60, 3, 57, 40, 29, 48, 23, 56, 42, 11, 22, 5, 59, 39, 4, 50, + 3, 41, 12, 57, 25, 50, 44, 18, 4, 46, 7, 62, 33, 50, 4, 56, 21, 32, 43, 18, + 3, 23, 55, 34, 20, 4, 53, 38, 12, 46, 29, 52, 25, 61, 23, 51, 26, 46, 1, 34, + 25, 57, 28, 51, 26, 11, 50, 3, 44, 28, 53, 21, 57, 27, 62, 6, 31, 19, 8, 63, + 26, 59, 36, 47, 15, 29, 50, 25, 35, 47, 18, 41, 4, 48, 8, 40, 12, 23, 6, 44, + 13, 40, 1, 31, 55, 0, 61, 43, 4, 50, 26, 58, 9, 53, 24, 61, 42, 55, 31, 43, + 57, 20, 34, 27, 43, 8, 59, 39}, + {18, 51, 30, 13, 26, 16, 46, 22, 2, 59, 8, 30, 1, 48, 33, 51, 29, 9, 46, 16, + 62, 14, 33, 2, 38, 9, 27, 60, 37, 26, 53, 17, 28, 10, 24, 46, 2, 49, 8, 57, + 29, 45, 6, 26, 62, 44, 18, 25, 61, 3, 42, 14, 49, 10, 43, 6, 17, 32, 63, 10, + 49, 4, 40, 14, 45, 33, 22, 37, 12, 61, 5, 17, 43, 7, 23, 37, 15, 58, 49, 13, + 39, 21, 10, 52, 1, 62, 9, 56, 12, 2, 58, 28, 36, 16, 56, 28, 56, 35, 20, 63, + 24, 37, 51, 8, 45, 25, 16, 33, 27, 38, 2, 44, 13, 30, 17, 36, 12, 26, 5, 18, + 28, 47, 13, 60, 23, 45, 13, 33}, + {55, 4, 62, 34, 52, 38, 7, 63, 32, 37, 13, 53, 25, 62, 18, 12, 55, 41, 27, + 35, 24, 49, 31, 52, 17, 63, 34, 1, 56, 12, 41, 2, 48, 58, 39, 16, 61, 27, + 41, 52, 13, 19, 50, 39, 11, 31, 57, 6, 32, 40, 20, 55, 1, 28, 33, 57, 48, 8, + 37, 22, 44, 18, 53, 1, 61, 5, 54, 16, 47, 36, 50, 24, 55, 34, 48, 45, 1, 30, + 33, 46, 2, 50, 32, 42, 25, 34, 43, 21, 38, 52, 23, 45, 14, 54, 21, 4, 44, + 16, 53, 29, 10, 47, 19, 57, 12, 54, 39, 10, 51, 15, 63, 21, 57, 40, 51, 1, + 48, 57, 37, 62, 2, 38, 9, 52, 1, 35, 58, 22}, + {36, 46, 10, 42, 1, 27, 43, 15, 50, 21, 45, 16, 41, 3, 35, 44, 20, 1, 57, 11, + 55, 7, 43, 8, 22, 42, 13, 46, 21, 39, 31, 60, 22, 5, 29, 44, 11, 35, 20, 4, + 36, 58, 32, 15, 47, 2, 36, 48, 16, 60, 8, 35, 44, 63, 16, 2, 40, 26, 55, 14, + 58, 35, 24, 31, 19, 42, 31, 58, 1, 29, 10, 40, 2, 19, 12, 54, 22, 61, 7, 24, + 56, 5, 28, 16, 54, 3, 15, 58, 6, 30, 8, 62, 1, 43, 31, 47, 7, 59, 1, 38, 58, + 4, 34, 27, 38, 5, 31, 59, 7, 46, 30, 3, 34, 6, 28, 59, 20, 8, 32, 15, 53, + 24, 55, 31, 19, 49, 11, 26}, + {2, 24, 16, 58, 19, 55, 5, 35, 10, 61, 4, 28, 57, 24, 58, 7, 31, 47, 22, 38, + 19, 28, 61, 36, 54, 5, 59, 29, 6, 52, 15, 11, 43, 36, 8, 54, 52, 1, 62, 25, + 47, 9, 1, 60, 28, 53, 24, 14, 46, 27, 51, 22, 12, 24, 38, 53, 20, 11, 51, 3, + 29, 7, 48, 63, 8, 49, 9, 21, 52, 14, 63, 32, 46, 60, 35, 4, 41, 16, 52, 35, + 18, 42, 59, 7, 36, 61, 45, 27, 33, 51, 19, 39, 34, 11, 61, 18, 33, 41, 28, + 15, 54, 22, 42, 3, 49, 21, 47, 18, 36, 23, 55, 19, 48, 24, 45, 10, 33, 44, + 50, 40, 7, 35, 15, 41, 63, 6, 40, 54}, + {62, 41, 32, 8, 47, 28, 60, 24, 44, 30, 38, 49, 9, 33, 14, 40, 50, 14, 60, 2, + 54, 40, 0, 20, 25, 39, 16, 49, 24, 35, 57, 47, 19, 61, 33, 18, 23, 37, 13, + 55, 31, 43, 22, 41, 17, 8, 42, 58, 0, 37, 5, 56, 31, 54, 7, 30, 60, 33, 42, + 17, 59, 39, 12, 27, 38, 17, 35, 41, 27, 45, 20, 7, 25, 15, 29, 58, 27, 47, + 11, 40, 14, 54, 23, 46, 19, 31, 11, 40, 13, 49, 5, 58, 24, 51, 26, 6, 50, + 20, 49, 9, 32, 46, 17, 60, 14, 63, 24, 1, 57, 41, 9, 43, 14, 62, 16, 52, 3, + 27, 14, 22, 61, 45, 4, 28, 9, 47, 29, 17}, + {5, 50, 12, 53, 38, 18, 11, 51, 0, 55, 17, 6, 47, 54, 19, 63, 5, 26, 34, 45, + 13, 30, 47, 58, 10, 48, 32, 3, 62, 9, 26, 0, 25, 14, 50, 3, 47, 30, 42, 16, + 6, 63, 12, 49, 33, 55, 21, 10, 34, 63, 18, 41, 3, 47, 19, 43, 0, 49, 8, 28, + 46, 20, 52, 0, 56, 24, 60, 3, 59, 5, 39, 57, 48, 52, 9, 38, 3, 21, 26, 60, + 0, 32, 12, 38, 4, 48, 53, 0, 60, 15, 29, 44, 18, 10, 38, 57, 13, 60, 2, 26, + 62, 7, 50, 29, 35, 8, 40, 53, 28, 12, 60, 33, 38, 5, 37, 29, 60, 39, 56, 0, + 30, 18, 50, 34, 59, 25, 14, 44}, + {20, 31, 60, 22, 3, 49, 33, 25, 40, 13, 34, 59, 22, 36, 0, 28, 37, 56, 8, 18, + 51, 16, 4, 45, 27, 12, 53, 42, 18, 44, 51, 31, 55, 40, 28, 58, 7, 60, 10, + 51, 27, 37, 24, 56, 5, 26, 44, 29, 50, 23, 45, 11, 34, 15, 59, 27, 13, 23, + 62, 37, 4, 57, 15, 32, 42, 6, 47, 11, 30, 43, 23, 13, 0, 36, 18, 44, 63, 51, + 37, 29, 49, 20, 57, 27, 62, 9, 24, 35, 23, 53, 37, 3, 42, 55, 0, 36, 23, 39, + 31, 43, 17, 37, 24, 11, 52, 43, 19, 32, 5, 50, 26, 0, 56, 21, 54, 11, 19, 6, + 47, 25, 59, 42, 12, 54, 21, 3, 38, 57}, + {48, 0, 35, 27, 44, 14, 59, 7, 57, 46, 26, 2, 42, 12, 52, 43, 10, 27, 53, 42, + 32, 62, 37, 21, 34, 61, 7, 23, 36, 4, 38, 12, 41, 5, 17, 45, 22, 27, 39, 21, + 59, 0, 45, 18, 39, 62, 3, 38, 14, 7, 54, 26, 61, 39, 9, 52, 45, 36, 18, 50, + 10, 34, 44, 22, 50, 14, 36, 55, 17, 34, 53, 62, 33, 26, 56, 6, 31, 12, 6, + 53, 9, 44, 2, 50, 20, 40, 55, 17, 47, 7, 26, 63, 22, 32, 48, 16, 46, 8, 52, + 12, 57, 41, 0, 56, 25, 3, 61, 14, 45, 35, 18, 44, 12, 46, 23, 42, 32, 51, + 35, 10, 17, 36, 23, 1, 45, 52, 32, 10}, + {37, 15, 43, 8, 63, 39, 21, 31, 16, 37, 19, 62, 30, 46, 17, 60, 21, 48, 1, + 23, 6, 25, 11, 56, 1, 40, 30, 58, 15, 54, 21, 59, 9, 63, 35, 56, 11, 51, 2, + 46, 34, 14, 53, 7, 30, 11, 51, 19, 60, 40, 30, 1, 24, 50, 20, 32, 3, 56, 5, + 25, 31, 13, 61, 2, 29, 60, 25, 20, 51, 2, 27, 8, 18, 42, 10, 45, 21, 34, 43, + 17, 62, 29, 41, 14, 34, 6, 30, 43, 2, 57, 33, 13, 45, 12, 27, 62, 4, 55, 21, + 35, 5, 27, 45, 33, 16, 47, 30, 54, 22, 10, 51, 27, 63, 7, 49, 1, 58, 22, 15, + 43, 53, 7, 57, 39, 27, 12, 61, 24}, + {56, 51, 26, 56, 19, 2, 41, 54, 5, 52, 9, 48, 6, 23, 39, 4, 32, 15, 63, 35, + 59, 49, 43, 15, 52, 19, 50, 9, 46, 33, 1, 29, 48, 20, 32, 1, 38, 33, 19, 54, + 9, 32, 24, 48, 58, 35, 16, 48, 4, 52, 13, 57, 33, 5, 45, 59, 15, 29, 41, 55, + 47, 39, 23, 53, 9, 40, 4, 57, 10, 44, 48, 40, 50, 14, 61, 24, 55, 1, 59, 22, + 33, 8, 51, 25, 58, 46, 11, 59, 20, 41, 17, 51, 6, 56, 35, 25, 42, 30, 15, + 58, 48, 18, 61, 9, 58, 39, 13, 2, 37, 59, 40, 2, 31, 16, 34, 41, 8, 30, 62, + 3, 29, 48, 33, 5, 63, 16, 41, 7}, + {22, 4, 46, 11, 33, 51, 29, 10, 62, 24, 43, 27, 15, 58, 50, 25, 54, 44, 9, + 38, 18, 3, 29, 57, 32, 5, 26, 43, 17, 61, 24, 52, 8, 42, 23, 53, 15, 61, 7, + 28, 57, 43, 4, 40, 20, 2, 43, 25, 32, 35, 21, 43, 17, 48, 10, 22, 38, 54, + 11, 21, 1, 58, 16, 30, 48, 18, 46, 32, 38, 13, 22, 4, 59, 35, 2, 51, 30, 39, + 15, 47, 4, 56, 13, 37, 1, 28, 16, 52, 32, 9, 61, 29, 38, 19, 3, 52, 10, 48, + 1, 32, 11, 40, 20, 36, 6, 22, 49, 29, 55, 6, 20, 56, 36, 52, 19, 60, 26, 46, + 18, 54, 40, 13, 20, 46, 35, 19, 49, 29}, + {61, 17, 34, 53, 23, 6, 48, 35, 20, 40, 1, 56, 36, 29, 11, 34, 7, 41, 14, 30, + 55, 20, 46, 8, 24, 38, 63, 2, 37, 10, 45, 14, 34, 49, 6, 13, 44, 25, 49, 41, + 21, 12, 61, 15, 54, 29, 63, 12, 56, 8, 49, 2, 62, 36, 28, 61, 0, 25, 41, 63, + 35, 8, 44, 6, 37, 62, 7, 21, 63, 28, 55, 31, 16, 24, 41, 19, 9, 57, 27, 36, + 18, 42, 31, 62, 22, 55, 38, 4, 27, 47, 1, 40, 14, 54, 43, 20, 60, 23, 38, + 63, 25, 51, 2, 53, 26, 63, 10, 42, 17, 34, 47, 25, 13, 5, 44, 11, 55, 2, 38, + 27, 6, 60, 52, 25, 9, 55, 1, 40}, + {8, 30, 58, 3, 42, 61, 17, 38, 13, 59, 32, 10, 54, 3, 51, 20, 61, 26, 57, 2, + 46, 33, 12, 60, 41, 13, 48, 29, 55, 20, 39, 27, 57, 18, 62, 29, 55, 2, 31, + 16, 37, 50, 26, 36, 6, 46, 9, 41, 27, 57, 23, 39, 26, 6, 51, 12, 31, 46, 7, + 16, 27, 52, 19, 56, 26, 12, 33, 53, 1, 41, 8, 57, 46, 7, 54, 32, 47, 5, 49, + 11, 60, 23, 5, 48, 10, 43, 19, 63, 35, 24, 49, 21, 59, 5, 31, 37, 14, 44, 7, + 42, 6, 30, 46, 13, 44, 32, 19, 50, 4, 58, 8, 30, 62, 38, 28, 53, 21, 36, 13, + 50, 21, 33, 15, 2, 44, 31, 14, 47}, + {37, 13, 39, 16, 28, 9, 57, 0, 25, 49, 21, 45, 18, 47, 12, 42, 0, 49, 22, 39, + 16, 53, 25, 36, 0, 52, 22, 16, 6, 60, 4, 51, 0, 26, 37, 47, 10, 36, 63, 5, + 57, 0, 18, 59, 23, 33, 51, 19, 0, 44, 15, 11, 54, 17, 42, 35, 53, 18, 58, + 33, 49, 4, 34, 42, 0, 50, 43, 25, 16, 49, 34, 20, 37, 28, 12, 63, 16, 38, + 25, 44, 0, 40, 52, 17, 35, 3, 50, 14, 8, 53, 11, 36, 25, 45, 9, 62, 0, 54, + 28, 17, 50, 55, 15, 24, 57, 0, 53, 34, 23, 41, 15, 45, 0, 49, 16, 4, 48, 9, + 63, 45, 0, 42, 58, 37, 61, 22, 54, 26}, + {0, 50, 21, 47, 54, 36, 27, 45, 52, 4, 34, 15, 63, 29, 37, 59, 17, 31, 6, 61, + 28, 5, 48, 18, 59, 27, 34, 56, 44, 31, 35, 12, 41, 59, 16, 3, 40, 20, 50, + 22, 30, 40, 52, 10, 45, 3, 59, 22, 37, 61, 29, 46, 31, 58, 2, 22, 9, 43, 3, + 39, 14, 61, 24, 54, 15, 29, 11, 60, 39, 17, 5, 61, 0, 44, 50, 3, 31, 14, 58, + 21, 54, 28, 15, 45, 60, 26, 33, 58, 44, 22, 60, 2, 57, 34, 49, 27, 18, 34, + 21, 59, 29, 4, 36, 41, 8, 39, 28, 11, 62, 26, 53, 20, 35, 24, 59, 32, 29, + 39, 24, 31, 57, 23, 11, 28, 5, 36, 11, 59}, + {44, 32, 63, 5, 20, 12, 41, 7, 30, 61, 42, 8, 39, 5, 33, 8, 24, 53, 45, 11, + 37, 58, 7, 44, 10, 50, 3, 40, 8, 22, 53, 19, 46, 9, 33, 52, 24, 58, 8, 44, + 13, 47, 8, 34, 38, 30, 14, 47, 7, 34, 4, 55, 9, 19, 40, 49, 56, 26, 60, 21, + 30, 45, 10, 19, 40, 58, 23, 36, 3, 52, 45, 23, 54, 13, 22, 42, 53, 45, 7, + 33, 10, 36, 57, 6, 29, 12, 41, 0, 30, 15, 41, 30, 17, 7, 16, 53, 40, 56, 2, + 39, 12, 61, 10, 52, 31, 60, 16, 45, 1, 37, 7, 61, 40, 10, 43, 17, 58, 7, 54, + 14, 4, 51, 39, 49, 18, 56, 42, 20}, + {14, 6, 24, 36, 56, 49, 22, 60, 18, 14, 23, 51, 26, 57, 21, 52, 41, 14, 35, + 50, 19, 31, 40, 23, 33, 14, 63, 17, 32, 47, 7, 62, 23, 30, 56, 11, 42, 27, + 14, 60, 35, 19, 28, 61, 17, 55, 25, 39, 53, 17, 42, 21, 38, 63, 25, 5, 14, + 36, 12, 50, 1, 37, 59, 32, 2, 51, 6, 56, 27, 32, 11, 30, 38, 26, 60, 8, 26, + 19, 62, 39, 50, 2, 21, 39, 53, 23, 56, 19, 49, 39, 5, 46, 55, 23, 42, 4, 31, + 11, 47, 26, 45, 22, 48, 18, 21, 5, 48, 25, 57, 14, 47, 30, 3, 56, 12, 50, 1, + 42, 19, 47, 35, 17, 8, 30, 45, 25, 4, 51}, + {28, 58, 43, 1, 31, 8, 33, 2, 44, 55, 32, 1, 60, 12, 46, 27, 4, 62, 23, 1, + 56, 13, 62, 2, 54, 36, 25, 51, 1, 57, 26, 42, 3, 49, 17, 38, 1, 48, 31, 4, + 54, 3, 50, 24, 1, 49, 5, 63, 13, 27, 52, 1, 48, 13, 45, 33, 52, 30, 46, 20, + 55, 28, 6, 48, 24, 38, 20, 47, 14, 62, 48, 9, 58, 4, 36, 30, 56, 1, 34, 12, + 18, 63, 25, 48, 4, 16, 37, 7, 62, 10, 52, 28, 13, 50, 36, 63, 24, 51, 15, + 58, 8, 33, 1, 38, 56, 35, 42, 9, 33, 51, 22, 18, 48, 32, 27, 37, 23, 61, 33, + 11, 59, 29, 62, 1, 53, 10, 60, 33}, + {12, 39, 17, 52, 26, 46, 53, 38, 25, 11, 48, 36, 16, 43, 2, 35, 55, 17, 39, + 29, 43, 9, 28, 45, 20, 5, 46, 12, 42, 28, 13, 52, 36, 6, 60, 22, 54, 17, 62, + 39, 25, 42, 15, 55, 44, 20, 31, 10, 35, 57, 24, 32, 29, 6, 59, 18, 7, 62, 3, + 41, 10, 44, 16, 54, 13, 62, 31, 9, 41, 1, 21, 43, 18, 47, 15, 40, 11, 49, + 28, 55, 46, 30, 8, 43, 32, 61, 28, 47, 25, 34, 21, 61, 32, 1, 20, 9, 46, 6, + 35, 19, 41, 54, 27, 63, 14, 3, 51, 20, 62, 2, 38, 55, 8, 21, 63, 6, 46, 9, + 26, 51, 3, 24, 43, 34, 16, 41, 18, 48}, + {62, 23, 55, 9, 15, 62, 19, 13, 58, 40, 6, 30, 54, 19, 50, 31, 10, 44, 6, 59, + 21, 47, 51, 15, 60, 39, 30, 54, 21, 61, 19, 33, 14, 29, 43, 11, 34, 45, 7, + 21, 10, 56, 36, 6, 38, 11, 58, 42, 2, 47, 11, 60, 50, 16, 41, 28, 38, 23, + 47, 17, 35, 63, 22, 33, 42, 5, 45, 17, 53, 35, 25, 56, 33, 6, 51, 19, 60, + 23, 43, 15, 5, 40, 58, 13, 51, 1, 45, 11, 54, 3, 43, 8, 37, 48, 59, 29, 39, + 21, 61, 43, 3, 31, 10, 44, 24, 29, 60, 12, 28, 40, 11, 25, 43, 52, 14, 41, + 16, 57, 44, 20, 40, 55, 12, 21, 57, 27, 35, 2}, + {37, 6, 31, 42, 40, 4, 29, 50, 0, 20, 63, 28, 9, 58, 14, 24, 63, 26, 48, 16, + 34, 4, 32, 38, 23, 11, 58, 4, 37, 9, 45, 5, 63, 48, 26, 57, 2, 28, 32, 51, + 46, 29, 13, 62, 27, 46, 28, 18, 50, 15, 40, 4, 19, 34, 54, 0, 53, 9, 26, 58, + 28, 5, 49, 0, 57, 27, 19, 60, 29, 8, 59, 12, 37, 63, 24, 46, 3, 37, 6, 52, + 26, 32, 20, 36, 9, 22, 59, 18, 35, 51, 14, 57, 17, 24, 12, 44, 56, 0, 30, + 13, 59, 20, 49, 17, 54, 43, 6, 34, 46, 17, 58, 36, 0, 34, 29, 54, 25, 2, 36, + 15, 60, 6, 37, 46, 4, 50, 9, 45}, + {19, 59, 48, 3, 24, 60, 44, 22, 34, 51, 15, 45, 41, 5, 33, 47, 0, 37, 12, 55, + 25, 54, 8, 57, 0, 47, 18, 34, 49, 15, 55, 24, 40, 20, 8, 35, 53, 13, 41, 18, + 0, 59, 22, 33, 4, 52, 8, 60, 24, 36, 31, 56, 45, 26, 10, 43, 15, 56, 36, 4, + 51, 14, 39, 30, 12, 55, 36, 2, 39, 49, 4, 44, 17, 0, 32, 13, 53, 35, 59, 17, + 62, 0, 55, 24, 52, 38, 31, 6, 42, 19, 29, 40, 4, 54, 33, 5, 16, 27, 52, 37, + 23, 55, 7, 37, 0, 39, 23, 49, 4, 53, 31, 15, 59, 10, 50, 4, 60, 34, 48, 7, + 31, 49, 27, 14, 62, 22, 53, 29}, + {46, 21, 14, 51, 36, 17, 7, 57, 10, 32, 3, 37, 22, 60, 39, 18, 56, 20, 42, 3, + 36, 10, 44, 26, 41, 29, 53, 27, 2, 39, 30, 52, 0, 59, 15, 48, 23, 61, 6, 58, + 37, 12, 40, 49, 16, 39, 20, 44, 0, 62, 8, 21, 3, 59, 23, 32, 49, 31, 12, 44, + 22, 59, 18, 50, 24, 7, 43, 52, 15, 23, 41, 26, 51, 28, 55, 39, 21, 27, 10, + 42, 12, 45, 27, 47, 3, 15, 63, 26, 55, 0, 60, 26, 45, 18, 62, 38, 58, 49, 8, + 47, 4, 33, 46, 29, 57, 13, 56, 16, 59, 21, 5, 47, 23, 39, 18, 44, 13, 22, + 28, 53, 19, 0, 58, 32, 41, 7, 26, 13}, + {0, 56, 34, 28, 11, 55, 31, 47, 26, 41, 56, 13, 53, 28, 11, 49, 7, 52, 32, + 61, 50, 22, 63, 17, 13, 56, 7, 19, 43, 62, 10, 21, 37, 32, 43, 4, 38, 19, + 44, 25, 31, 54, 5, 23, 61, 30, 53, 12, 35, 22, 43, 53, 37, 48, 7, 62, 20, 2, + 61, 41, 8, 34, 47, 9, 63, 34, 28, 10, 55, 33, 14, 57, 7, 47, 9, 61, 4, 49, + 31, 50, 21, 38, 8, 16, 57, 44, 33, 5, 49, 36, 12, 50, 7, 34, 10, 25, 2, 22, + 36, 15, 26, 61, 18, 9, 22, 46, 32, 8, 27, 37, 44, 30, 55, 3, 62, 24, 38, 56, + 5, 45, 38, 24, 43, 10, 19, 54, 39, 61}, + {41, 30, 8, 63, 43, 23, 38, 3, 62, 19, 8, 49, 25, 1, 58, 30, 23, 40, 9, 28, + 18, 40, 6, 38, 49, 22, 35, 59, 8, 27, 50, 5, 56, 17, 11, 50, 30, 9, 55, 2, + 51, 19, 34, 47, 9, 41, 6, 26, 48, 57, 14, 28, 17, 12, 39, 13, 37, 46, 25, + 19, 54, 27, 1, 37, 16, 45, 20, 60, 1, 48, 20, 38, 31, 22, 42, 15, 19, 44, 1, + 61, 6, 34, 56, 40, 29, 10, 20, 46, 13, 22, 41, 23, 59, 42, 30, 51, 45, 13, + 63, 53, 42, 12, 51, 38, 62, 2, 26, 41, 50, 1, 61, 10, 19, 42, 31, 8, 49, 32, + 12, 63, 9, 52, 16, 56, 36, 2, 31, 16}, + {52, 5, 47, 20, 1, 53, 12, 50, 16, 35, 43, 21, 33, 43, 16, 44, 3, 59, 14, 46, + 1, 30, 60, 33, 2, 45, 12, 42, 31, 47, 14, 33, 46, 25, 55, 27, 60, 36, 16, + 42, 14, 46, 26, 1, 55, 15, 63, 32, 2, 38, 5, 47, 33, 61, 30, 52, 4, 57, 6, + 38, 11, 43, 61, 24, 52, 3, 31, 22, 42, 10, 62, 3, 59, 11, 35, 57, 33, 54, + 24, 14, 29, 48, 18, 2, 60, 41, 53, 24, 32, 62, 3, 53, 15, 1, 55, 17, 32, 40, + 6, 31, 1, 40, 28, 5, 35, 52, 19, 63, 13, 33, 17, 41, 52, 26, 15, 57, 1, 20, + 42, 17, 35, 27, 48, 5, 25, 50, 44, 11}, + {35, 25, 38, 57, 33, 17, 40, 6, 59, 27, 54, 5, 61, 10, 52, 26, 36, 19, 51, + 35, 57, 48, 11, 20, 54, 25, 61, 16, 1, 58, 24, 61, 3, 39, 7, 47, 1, 22, 49, + 28, 63, 10, 58, 32, 17, 36, 45, 19, 51, 29, 59, 10, 50, 1, 23, 42, 18, 29, + 51, 21, 56, 32, 14, 5, 40, 58, 47, 13, 54, 35, 29, 45, 18, 52, 26, 2, 38, 8, + 46, 36, 58, 11, 52, 35, 17, 28, 1, 58, 9, 39, 17, 28, 37, 48, 20, 9, 57, 24, + 50, 19, 58, 16, 48, 25, 43, 11, 35, 6, 45, 24, 56, 4, 36, 7, 47, 35, 52, 28, + 59, 30, 2, 61, 21, 33, 63, 12, 18, 59}, + {3, 49, 15, 10, 27, 61, 25, 45, 30, 0, 14, 47, 31, 38, 17, 62, 7, 55, 27, 4, + 15, 24, 42, 52, 10, 34, 5, 51, 36, 18, 41, 11, 35, 21, 62, 13, 33, 57, 8, + 35, 5, 40, 21, 43, 52, 3, 24, 56, 11, 16, 33, 25, 41, 20, 55, 8, 60, 35, 15, + 48, 2, 57, 30, 49, 18, 25, 6, 39, 17, 57, 7, 25, 43, 5, 49, 16, 62, 22, 55, + 4, 25, 43, 23, 7, 50, 11, 37, 48, 14, 51, 33, 57, 7, 27, 39, 46, 4, 29, 11, + 43, 34, 56, 7, 60, 20, 54, 30, 57, 22, 49, 9, 33, 54, 14, 63, 23, 6, 43, 10, + 40, 50, 13, 44, 8, 38, 33, 46, 23}, + {55, 39, 22, 50, 44, 4, 36, 9, 52, 23, 37, 59, 21, 2, 46, 13, 31, 41, 11, 45, + 62, 29, 6, 37, 19, 48, 30, 23, 44, 7, 53, 28, 54, 16, 41, 29, 44, 18, 52, + 24, 60, 15, 48, 7, 27, 59, 9, 34, 42, 54, 7, 63, 4, 46, 31, 27, 45, 0, 40, + 26, 34, 17, 37, 10, 53, 29, 36, 50, 2, 27, 51, 11, 61, 37, 23, 41, 30, 7, + 18, 50, 39, 14, 63, 32, 45, 61, 19, 30, 25, 44, 2, 47, 23, 63, 11, 34, 59, + 37, 60, 3, 22, 14, 44, 30, 15, 0, 47, 15, 3, 38, 61, 20, 27, 45, 11, 39, 51, + 16, 55, 3, 22, 54, 29, 58, 1, 57, 6, 29}, + {9, 17, 60, 2, 34, 56, 20, 62, 39, 12, 49, 6, 29, 56, 34, 48, 0, 58, 22, 38, + 18, 43, 56, 0, 63, 14, 55, 3, 59, 31, 15, 45, 0, 49, 6, 58, 3, 38, 12, 45, + 0, 37, 29, 57, 13, 39, 30, 49, 0, 23, 44, 36, 16, 57, 13, 54, 11, 24, 63, 9, + 53, 7, 62, 42, 0, 59, 15, 23, 63, 34, 40, 16, 32, 0, 53, 12, 48, 28, 59, 33, + 0, 53, 9, 27, 3, 22, 54, 5, 56, 9, 61, 13, 42, 14, 52, 19, 0, 21, 47, 27, + 53, 36, 3, 50, 39, 58, 25, 40, 53, 28, 12, 50, 0, 59, 32, 2, 21, 34, 26, 46, + 37, 7, 18, 47, 24, 14, 53, 42}, + {61, 32, 13, 54, 29, 7, 46, 13, 28, 57, 18, 41, 53, 15, 9, 39, 24, 49, 33, 3, + 53, 9, 26, 32, 40, 28, 46, 39, 25, 9, 56, 21, 63, 37, 26, 22, 51, 27, 17, + 56, 31, 53, 4, 43, 22, 46, 12, 18, 60, 40, 20, 26, 50, 21, 39, 5, 49, 33, + 16, 44, 22, 46, 20, 32, 24, 45, 8, 43, 12, 46, 4, 48, 56, 20, 29, 58, 3, 40, + 10, 42, 31, 21, 47, 41, 56, 38, 15, 42, 36, 27, 20, 33, 55, 3, 26, 44, 31, + 54, 12, 35, 9, 63, 28, 10, 21, 32, 9, 60, 17, 8, 43, 29, 40, 16, 36, 48, 60, + 7, 57, 14, 62, 31, 42, 15, 36, 40, 20, 26}, + {0, 37, 47, 23, 41, 18, 32, 48, 1, 35, 8, 25, 4, 26, 63, 20, 54, 8, 16, 61, + 35, 23, 51, 15, 58, 7, 12, 20, 50, 34, 42, 4, 38, 10, 32, 47, 8, 60, 41, 20, + 9, 25, 50, 19, 62, 1, 37, 56, 28, 8, 53, 11, 3, 58, 34, 43, 19, 60, 38, 4, + 58, 31, 3, 51, 11, 55, 38, 30, 21, 58, 19, 26, 9, 44, 36, 13, 46, 20, 62, + 24, 13, 60, 5, 28, 12, 34, 7, 59, 0, 53, 45, 6, 38, 30, 50, 7, 62, 16, 41, + 5, 46, 18, 55, 42, 51, 5, 45, 23, 34, 48, 19, 58, 5, 25, 54, 19, 13, 41, 28, + 21, 0, 49, 10, 60, 4, 51, 9, 45}, + {19, 28, 6, 58, 10, 51, 4, 22, 55, 42, 60, 45, 34, 51, 42, 5, 30, 45, 27, 40, + 13, 47, 4, 49, 21, 38, 60, 29, 2, 57, 17, 27, 52, 19, 61, 14, 30, 34, 2, 44, + 63, 33, 11, 35, 16, 51, 25, 6, 14, 47, 31, 61, 37, 29, 18, 8, 52, 2, 28, 54, + 13, 41, 15, 62, 35, 18, 2, 60, 6, 33, 41, 61, 31, 6, 56, 17, 34, 50, 6, 52, + 44, 35, 16, 51, 59, 24, 48, 18, 31, 40, 16, 49, 21, 60, 17, 39, 10, 49, 32, + 57, 24, 39, 1, 25, 18, 62, 37, 12, 56, 1, 37, 11, 52, 44, 9, 30, 47, 4, 51, + 40, 55, 25, 34, 27, 56, 30, 32, 54}, + {63, 40, 49, 15, 43, 26, 63, 38, 16, 20, 30, 12, 57, 14, 19, 60, 36, 12, 59, + 2, 57, 17, 42, 31, 1, 44, 16, 35, 47, 11, 32, 48, 13, 43, 1, 39, 51, 12, 57, + 23, 6, 40, 53, 3, 55, 31, 39, 60, 35, 44, 5, 15, 45, 1, 62, 41, 26, 14, 47, + 22, 36, 27, 50, 9, 26, 47, 52, 28, 54, 16, 1, 13, 51, 39, 23, 63, 1, 30, 15, + 26, 2, 57, 19, 37, 1, 44, 21, 50, 13, 63, 8, 24, 56, 1, 35, 25, 58, 20, 2, + 28, 14, 51, 33, 59, 13, 30, 4, 49, 31, 24, 63, 26, 33, 3, 58, 38, 62, 24, + 32, 8, 17, 45, 5, 48, 18, 3, 43, 11}, + {21, 4, 24, 34, 59, 1, 37, 11, 53, 5, 47, 2, 22, 40, 32, 1, 24, 50, 21, 29, + 38, 25, 63, 8, 55, 24, 53, 6, 62, 23, 59, 3, 54, 20, 58, 24, 5, 46, 15, 38, + 48, 14, 27, 42, 23, 7, 46, 10, 17, 58, 25, 52, 23, 32, 49, 12, 55, 30, 40, + 7, 59, 1, 56, 21, 39, 4, 23, 15, 37, 46, 55, 42, 21, 4, 48, 8, 45, 54, 37, + 55, 32, 8, 46, 10, 30, 54, 4, 41, 25, 29, 36, 48, 11, 43, 14, 47, 5, 43, 53, + 36, 61, 10, 45, 6, 41, 54, 27, 43, 16, 55, 6, 46, 18, 42, 23, 15, 1, 45, 12, + 60, 37, 22, 62, 12, 39, 59, 16, 52}, + {47, 35, 56, 7, 19, 46, 31, 50, 33, 24, 61, 35, 50, 7, 53, 44, 55, 6, 46, 10, + 52, 5, 21, 43, 36, 10, 18, 41, 26, 37, 8, 29, 40, 36, 9, 49, 34, 26, 61, 21, + 7, 59, 18, 62, 29, 54, 20, 32, 51, 0, 40, 10, 55, 6, 20, 36, 9, 61, 5, 51, + 44, 19, 33, 43, 13, 57, 40, 63, 8, 24, 29, 10, 60, 34, 27, 40, 25, 18, 10, + 42, 21, 49, 26, 62, 38, 12, 33, 61, 5, 57, 2, 19, 54, 28, 62, 22, 38, 31, + 16, 7, 22, 47, 29, 17, 35, 8, 20, 51, 2, 40, 22, 50, 13, 61, 28, 53, 35, 20, + 56, 30, 2, 53, 14, 41, 23, 34, 8, 31}, + {12, 2, 42, 29, 52, 13, 21, 8, 55, 14, 41, 17, 28, 58, 23, 11, 17, 36, 31, + 62, 17, 34, 50, 14, 28, 61, 33, 52, 2, 51, 17, 45, 7, 25, 62, 30, 18, 55, 0, + 42, 30, 35, 45, 1, 12, 48, 3, 63, 21, 36, 30, 48, 19, 59, 43, 27, 46, 17, + 34, 25, 12, 29, 53, 6, 48, 31, 11, 34, 49, 3, 36, 50, 19, 47, 14, 61, 11, + 36, 58, 4, 60, 14, 39, 22, 6, 52, 15, 35, 17, 46, 31, 42, 9, 34, 3, 52, 12, + 60, 26, 56, 40, 2, 53, 23, 57, 38, 62, 14, 36, 59, 10, 31, 39, 6, 49, 9, 41, + 26, 5, 48, 43, 27, 33, 58, 1, 50, 25, 57}, + {61, 37, 15, 61, 3, 39, 58, 43, 26, 0, 44, 10, 47, 3, 37, 63, 28, 43, 13, 39, + 3, 57, 30, 59, 0, 48, 5, 43, 13, 22, 60, 33, 55, 15, 42, 4, 52, 10, 45, 13, + 54, 4, 24, 49, 37, 26, 41, 14, 42, 9, 61, 13, 38, 23, 3, 53, 0, 58, 21, 42, + 63, 10, 17, 61, 25, 0, 58, 28, 17, 44, 57, 12, 27, 0, 55, 5, 52, 28, 23, 47, + 29, 0, 43, 17, 58, 28, 47, 23, 55, 10, 58, 23, 51, 40, 18, 33, 45, 0, 49, 8, + 32, 61, 19, 48, 0, 26, 7, 47, 29, 18, 44, 0, 56, 34, 20, 59, 15, 51, 37, 18, + 10, 52, 7, 20, 46, 9, 38, 17}, + {6, 27, 48, 23, 45, 29, 5, 18, 38, 62, 27, 56, 20, 32, 15, 9, 48, 0, 54, 22, + 45, 20, 7, 41, 23, 39, 19, 27, 58, 31, 44, 0, 12, 50, 23, 56, 20, 39, 32, + 59, 16, 52, 33, 9, 57, 22, 6, 58, 28, 50, 24, 2, 56, 35, 16, 45, 32, 38, 15, + 54, 2, 38, 46, 22, 35, 45, 20, 5, 52, 25, 7, 35, 59, 32, 22, 43, 38, 3, 51, + 16, 34, 53, 32, 50, 3, 40, 8, 43, 0, 39, 27, 4, 14, 61, 8, 55, 15, 41, 20, + 44, 27, 13, 39, 11, 46, 42, 54, 33, 4, 52, 23, 61, 14, 25, 43, 2, 33, 11, + 63, 29, 61, 17, 40, 55, 22, 62, 28, 44}, + {20, 54, 8, 56, 35, 10, 63, 31, 52, 12, 48, 6, 59, 41, 52, 33, 19, 58, 25, + 49, 11, 37, 47, 12, 54, 15, 56, 35, 7, 47, 16, 53, 28, 34, 5, 37, 28, 8, 48, + 3, 28, 38, 18, 61, 16, 43, 53, 32, 4, 17, 47, 27, 44, 8, 63, 10, 25, 49, 6, + 37, 24, 52, 32, 3, 50, 12, 41, 56, 38, 14, 62, 20, 40, 16, 53, 31, 18, 63, + 41, 9, 59, 7, 13, 25, 57, 20, 63, 26, 53, 18, 48, 62, 30, 46, 21, 25, 58, + 29, 36, 4, 55, 34, 6, 60, 31, 16, 21, 12, 58, 38, 9, 29, 47, 7, 52, 30, 57, + 44, 22, 0, 35, 45, 3, 31, 14, 36, 0, 51}, + {42, 14, 33, 24, 16, 49, 40, 2, 22, 33, 16, 36, 25, 1, 21, 61, 38, 8, 33, 4, + 62, 26, 29, 60, 6, 46, 30, 11, 63, 4, 36, 40, 19, 57, 46, 11, 41, 63, 22, + 25, 58, 10, 46, 2, 34, 27, 11, 38, 56, 34, 12, 53, 18, 33, 41, 51, 13, 28, + 60, 20, 47, 14, 29, 59, 16, 62, 8, 22, 32, 47, 9, 49, 2, 44, 7, 12, 45, 6, + 20, 27, 45, 24, 62, 42, 36, 11, 33, 15, 37, 7, 32, 10, 37, 1, 35, 50, 6, 11, + 63, 24, 52, 15, 50, 24, 3, 37, 56, 27, 34, 22, 49, 16, 36, 62, 17, 39, 4, + 15, 54, 24, 50, 8, 58, 26, 49, 54, 11, 30}, + {4, 59, 41, 1, 53, 12, 25, 45, 59, 7, 51, 39, 54, 14, 46, 4, 27, 53, 16, 44, + 18, 51, 1, 32, 25, 2, 50, 40, 20, 54, 24, 9, 62, 2, 27, 60, 1, 17, 36, 50, + 6, 40, 30, 55, 41, 19, 49, 1, 21, 60, 40, 5, 62, 1, 22, 30, 57, 4, 43, 31, + 1, 55, 40, 7, 27, 37, 30, 54, 1, 19, 42, 30, 56, 26, 62, 49, 24, 57, 37, 56, + 2, 39, 16, 5, 30, 55, 3, 49, 60, 23, 56, 44, 17, 52, 13, 42, 28, 48, 18, 45, + 9, 37, 21, 41, 58, 10, 48, 1, 63, 5, 41, 57, 2, 24, 12, 48, 27, 42, 32, 46, + 13, 38, 19, 34, 5, 41, 25, 60}, + {39, 28, 21, 46, 32, 57, 36, 9, 19, 42, 4, 29, 11, 43, 30, 49, 13, 42, 35, + 56, 9, 39, 15, 52, 36, 61, 18, 26, 45, 14, 31, 48, 21, 43, 14, 33, 49, 54, + 14, 44, 21, 62, 13, 23, 8, 62, 15, 51, 44, 7, 30, 37, 20, 42, 56, 7, 39, 18, + 50, 11, 61, 9, 19, 43, 57, 2, 48, 11, 39, 60, 28, 4, 37, 17, 35, 1, 33, 11, + 31, 14, 48, 19, 35, 51, 46, 21, 44, 29, 12, 41, 2, 22, 58, 26, 54, 4, 59, + 38, 2, 33, 57, 1, 63, 13, 28, 51, 15, 40, 18, 45, 8, 30, 43, 37, 54, 19, 8, + 59, 21, 6, 60, 29, 55, 10, 63, 15, 47, 17}, + {3, 50, 10, 62, 18, 5, 27, 49, 60, 23, 55, 18, 62, 24, 56, 10, 59, 28, 2, 23, + 34, 59, 43, 20, 10, 42, 8, 49, 1, 37, 57, 6, 51, 29, 53, 7, 23, 31, 5, 32, + 51, 0, 35, 54, 45, 31, 5, 26, 36, 24, 55, 15, 48, 29, 14, 48, 26, 60, 21, + 41, 36, 26, 50, 33, 14, 44, 17, 24, 52, 15, 46, 23, 54, 6, 47, 21, 60, 50, + 4, 53, 29, 61, 8, 23, 1, 60, 19, 6, 53, 16, 47, 34, 6, 39, 16, 31, 12, 20, + 53, 22, 30, 43, 25, 46, 35, 6, 44, 32, 53, 26, 55, 19, 11, 59, 5, 33, 51, 1, + 35, 53, 25, 3, 42, 23, 44, 32, 7, 53}, + {22, 44, 37, 6, 26, 51, 38, 0, 34, 13, 31, 46, 3, 37, 6, 19, 40, 21, 47, 63, + 12, 5, 29, 55, 22, 58, 34, 28, 60, 22, 11, 41, 17, 38, 9, 44, 59, 39, 56, + 19, 11, 47, 25, 15, 3, 39, 57, 17, 61, 11, 46, 3, 58, 9, 54, 35, 2, 34, 8, + 45, 15, 56, 5, 23, 53, 33, 63, 35, 4, 59, 10, 51, 13, 61, 29, 41, 15, 25, + 43, 19, 40, 10, 54, 33, 41, 12, 38, 51, 31, 26, 61, 9, 30, 45, 24, 62, 49, + 40, 10, 61, 14, 49, 5, 17, 54, 20, 60, 23, 3, 13, 35, 50, 32, 23, 46, 27, + 38, 63, 16, 12, 39, 48, 18, 51, 1, 27, 56, 35}, + {63, 15, 30, 55, 43, 14, 57, 17, 53, 44, 7, 48, 26, 50, 32, 60, 0, 53, 14, + 31, 50, 24, 46, 0, 38, 13, 4, 52, 16, 45, 30, 59, 0, 25, 55, 35, 16, 10, 26, + 42, 58, 29, 60, 38, 50, 22, 28, 47, 0, 50, 28, 19, 33, 39, 11, 44, 16, 52, + 24, 59, 3, 38, 27, 51, 0, 21, 7, 42, 26, 34, 21, 40, 33, 18, 39, 3, 54, 38, + 8, 59, 0, 44, 27, 15, 58, 28, 57, 9, 43, 0, 36, 50, 20, 59, 8, 34, 0, 27, + 47, 7, 36, 19, 56, 32, 0, 38, 11, 29, 62, 47, 6, 61, 0, 41, 14, 56, 10, 23, + 45, 31, 57, 8, 36, 13, 58, 38, 11, 19}, + {0, 34, 12, 47, 21, 2, 40, 30, 11, 25, 61, 20, 40, 15, 35, 22, 45, 36, 7, 41, + 17, 57, 9, 48, 32, 62, 44, 24, 35, 3, 54, 13, 33, 63, 19, 4, 48, 22, 62, 2, + 37, 8, 33, 6, 20, 52, 9, 32, 43, 13, 39, 63, 25, 4, 49, 23, 62, 32, 9, 30, + 48, 18, 63, 12, 46, 29, 58, 13, 48, 8, 57, 31, 0, 51, 9, 58, 12, 22, 47, 29, + 35, 22, 49, 5, 46, 4, 34, 20, 63, 24, 56, 11, 41, 3, 51, 19, 56, 35, 17, 58, + 28, 42, 9, 45, 59, 26, 51, 42, 17, 36, 25, 15, 53, 21, 44, 3, 30, 55, 5, 50, + 21, 28, 61, 32, 6, 49, 28, 46}, + {58, 42, 60, 4, 31, 59, 22, 63, 35, 38, 9, 54, 1, 57, 8, 51, 16, 58, 27, 53, + 3, 38, 30, 15, 27, 6, 19, 56, 10, 50, 21, 36, 47, 5, 43, 28, 51, 32, 13, 46, + 18, 54, 16, 43, 63, 12, 36, 59, 22, 34, 5, 52, 17, 59, 27, 41, 0, 19, 55, + 37, 13, 43, 6, 34, 41, 10, 36, 55, 19, 44, 3, 16, 58, 27, 49, 25, 32, 62, + 17, 55, 13, 63, 18, 52, 25, 37, 17, 48, 13, 32, 5, 46, 28, 37, 14, 43, 25, + 5, 51, 39, 3, 52, 33, 22, 8, 40, 12, 4, 57, 9, 46, 39, 28, 58, 13, 62, 17, + 42, 19, 36, 0, 47, 16, 43, 24, 21, 54, 13}, + {25, 9, 23, 50, 36, 8, 45, 14, 3, 51, 16, 28, 44, 12, 42, 29, 4, 26, 10, 47, + 22, 61, 18, 54, 51, 39, 46, 13, 41, 26, 58, 7, 18, 39, 12, 57, 15, 1, 52, + 27, 41, 23, 48, 1, 27, 45, 18, 2, 57, 26, 55, 8, 43, 31, 6, 58, 14, 51, 40, + 5, 61, 31, 24, 54, 17, 60, 22, 1, 39, 30, 53, 45, 36, 13, 43, 5, 45, 2, 37, + 6, 34, 42, 2, 39, 10, 62, 7, 54, 40, 18, 60, 15, 52, 21, 63, 8, 55, 46, 15, + 30, 23, 13, 62, 16, 50, 24, 58, 31, 48, 21, 34, 2, 49, 7, 31, 37, 26, 48, 9, + 61, 40, 11, 52, 2, 60, 40, 4, 37}, + {52, 28, 39, 16, 54, 19, 29, 55, 42, 20, 58, 33, 24, 63, 18, 55, 39, 62, 43, + 34, 12, 40, 6, 35, 2, 25, 8, 62, 34, 1, 31, 42, 61, 27, 53, 24, 40, 61, 34, + 8, 59, 4, 30, 56, 40, 6, 53, 42, 10, 48, 16, 37, 12, 46, 21, 36, 47, 11, 28, + 45, 22, 10, 57, 2, 49, 31, 14, 44, 61, 11, 25, 6, 23, 63, 18, 36, 28, 56, + 20, 51, 11, 48, 27, 56, 32, 22, 45, 30, 2, 42, 27, 39, 1, 44, 23, 31, 38, + 22, 11, 61, 43, 54, 4, 47, 35, 2, 44, 16, 28, 54, 12, 62, 18, 43, 10, 52, 1, + 58, 33, 15, 29, 56, 20, 34, 9, 30, 48, 17}, + {46, 2, 56, 11, 41, 1, 49, 6, 27, 47, 2, 48, 5, 32, 37, 3, 13, 19, 32, 1, 55, + 28, 60, 17, 43, 59, 32, 20, 49, 16, 55, 23, 14, 46, 2, 36, 6, 30, 20, 49, + 12, 47, 35, 14, 21, 60, 29, 14, 35, 24, 46, 1, 56, 29, 53, 8, 33, 23, 56, 1, + 35, 46, 20, 39, 26, 4, 53, 28, 17, 38, 60, 34, 48, 9, 55, 15, 46, 7, 41, 31, + 60, 24, 16, 36, 1, 59, 19, 52, 35, 6, 55, 11, 59, 33, 7, 57, 4, 29, 48, 1, + 19, 26, 37, 30, 18, 63, 37, 6, 59, 1, 40, 24, 56, 33, 46, 22, 35, 7, 24, 53, + 39, 5, 26, 45, 55, 18, 62, 7}, + {20, 60, 29, 34, 20, 62, 33, 52, 10, 36, 13, 60, 41, 21, 50, 27, 56, 49, 8, + 51, 21, 45, 11, 48, 8, 23, 53, 3, 29, 44, 5, 52, 9, 32, 50, 17, 43, 56, 3, + 38, 24, 10, 62, 25, 51, 9, 33, 49, 61, 7, 30, 62, 22, 19, 2, 42, 63, 5, 49, + 18, 60, 15, 52, 7, 43, 56, 23, 50, 5, 50, 2, 20, 41, 30, 1, 52, 22, 61, 14, + 26, 3, 43, 53, 7, 47, 28, 11, 14, 23, 58, 33, 25, 47, 13, 50, 17, 40, 54, + 34, 60, 41, 6, 59, 14, 50, 7, 25, 55, 20, 42, 51, 8, 27, 4, 16, 60, 28, 50, + 44, 3, 22, 49, 63, 12, 33, 1, 43, 31}, + {36, 5, 46, 8, 44, 24, 13, 39, 25, 57, 31, 18, 8, 52, 10, 45, 6, 30, 36, 24, + 63, 4, 33, 26, 57, 40, 15, 56, 37, 12, 40, 25, 37, 58, 11, 63, 21, 45, 16, + 60, 31, 53, 18, 33, 3, 45, 23, 0, 20, 54, 40, 15, 50, 38, 60, 16, 25, 42, + 29, 38, 7, 41, 25, 62, 18, 33, 8, 35, 42, 16, 32, 56, 12, 39, 59, 19, 34, 9, + 49, 38, 57, 12, 21, 50, 14, 40, 61, 44, 50, 9, 49, 19, 3, 29, 35, 62, 12, + 24, 7, 18, 52, 32, 10, 46, 21, 41, 32, 11, 36, 29, 14, 34, 60, 38, 54, 11, + 41, 14, 19, 57, 32, 16, 7, 41, 51, 25, 14, 57}, + {53, 18, 26, 50, 15, 58, 4, 63, 17, 43, 7, 40, 61, 35, 15, 41, 23, 60, 16, + 38, 14, 42, 19, 50, 0, 31, 10, 46, 27, 63, 18, 60, 0, 20, 29, 39, 8, 26, 37, + 5, 42, 0, 44, 39, 57, 17, 58, 41, 28, 37, 4, 32, 9, 44, 12, 31, 54, 10, 59, + 14, 27, 53, 12, 36, 0, 47, 13, 63, 21, 58, 10, 24, 50, 27, 4, 26, 44, 53, + 31, 0, 18, 42, 29, 33, 57, 4, 32, 26, 0, 38, 16, 61, 41, 53, 20, 0, 42, 44, + 49, 27, 10, 56, 39, 0, 57, 15, 53, 49, 3, 61, 22, 47, 17, 5, 49, 26, 2, 63, + 39, 10, 47, 27, 37, 23, 4, 59, 38, 10}, + {23, 39, 61, 3, 37, 28, 48, 31, 0, 34, 51, 23, 2, 26, 58, 0, 53, 11, 46, 1, + 57, 29, 52, 14, 37, 61, 21, 35, 2, 49, 7, 34, 47, 55, 4, 33, 54, 13, 58, 52, + 19, 50, 22, 7, 13, 29, 36, 11, 51, 17, 60, 25, 55, 4, 34, 51, 0, 35, 20, 48, + 32, 3, 51, 30, 59, 28, 40, 3, 46, 29, 54, 43, 7, 62, 47, 11, 39, 4, 23, 46, + 55, 8, 63, 5, 25, 37, 18, 46, 21, 56, 31, 5, 36, 8, 45, 58, 26, 15, 2, 36, + 47, 21, 29, 44, 25, 34, 3, 27, 43, 10, 52, 0, 45, 30, 24, 36, 43, 18, 34, + 59, 0, 52, 61, 15, 44, 19, 30, 49}, + {0, 27, 12, 43, 54, 9, 22, 53, 21, 46, 15, 55, 29, 47, 20, 33, 39, 28, 59, + 35, 9, 44, 5, 24, 47, 7, 52, 17, 56, 22, 30, 42, 14, 26, 45, 18, 49, 1, 24, + 34, 11, 27, 55, 32, 61, 47, 2, 56, 6, 44, 13, 47, 36, 27, 58, 22, 16, 47, + 40, 4, 57, 38, 21, 45, 16, 9, 56, 26, 11, 38, 0, 22, 36, 17, 33, 57, 16, 30, + 62, 15, 35, 40, 20, 45, 59, 10, 54, 8, 63, 13, 52, 27, 22, 57, 28, 12, 32, + 51, 55, 22, 63, 4, 16, 54, 12, 62, 45, 19, 58, 13, 32, 40, 20, 56, 7, 57, 9, + 54, 6, 29, 42, 21, 8, 55, 35, 47, 6, 41}, + {56, 33, 58, 32, 19, 35, 42, 6, 59, 11, 38, 5, 49, 12, 62, 7, 52, 17, 5, 25, + 54, 20, 61, 31, 54, 27, 41, 11, 44, 5, 59, 12, 36, 51, 10, 61, 28, 41, 48, + 9, 43, 63, 5, 40, 20, 8, 49, 26, 34, 21, 58, 1, 18, 45, 7, 39, 61, 26, 8, + 50, 23, 10, 63, 5, 55, 37, 19, 49, 52, 15, 59, 47, 13, 54, 1, 25, 42, 58, + 10, 48, 3, 27, 50, 1, 17, 48, 34, 41, 16, 40, 2, 45, 10, 39, 17, 61, 5, 38, + 19, 9, 41, 31, 60, 38, 5, 23, 36, 8, 30, 55, 24, 63, 12, 48, 14, 51, 31, 20, + 45, 25, 12, 50, 32, 2, 28, 11, 62, 14}, + {44, 16, 7, 48, 1, 62, 16, 50, 27, 33, 61, 25, 17, 44, 31, 14, 22, 43, 32, + 48, 18, 40, 8, 36, 3, 16, 33, 62, 23, 38, 25, 53, 2, 21, 41, 6, 22, 15, 59, + 29, 16, 37, 26, 15, 52, 42, 23, 15, 54, 39, 10, 30, 53, 11, 49, 24, 2, 43, + 55, 17, 34, 44, 15, 31, 24, 44, 2, 32, 7, 35, 25, 5, 40, 45, 29, 51, 6, 21, + 37, 52, 24, 60, 13, 31, 53, 23, 2, 28, 49, 24, 31, 60, 20, 51, 1, 34, 48, + 14, 59, 33, 50, 1, 18, 33, 48, 60, 17, 51, 39, 6, 38, 2, 35, 29, 40, 23, 1, + 62, 15, 53, 37, 17, 46, 57, 40, 51, 24, 22}, + {5, 37, 52, 24, 45, 13, 40, 3, 45, 9, 19, 42, 56, 4, 37, 46, 56, 2, 63, 11, + 51, 1, 49, 13, 59, 45, 39, 1, 48, 15, 58, 9, 46, 31, 54, 35, 57, 38, 3, 46, + 56, 4, 47, 57, 1, 30, 38, 63, 3, 46, 28, 63, 41, 14, 33, 62, 19, 32, 13, 28, + 61, 1, 53, 42, 11, 60, 22, 62, 27, 42, 61, 31, 19, 8, 61, 12, 32, 55, 2, 18, + 33, 12, 43, 36, 9, 62, 30, 55, 6, 58, 35, 7, 43, 29, 54, 23, 43, 30, 3, 25, + 11, 45, 52, 28, 7, 14, 42, 1, 22, 50, 16, 53, 19, 59, 4, 46, 33, 41, 4, 35, + 58, 5, 26, 13, 20, 2, 34, 54}, + {30, 63, 21, 10, 26, 55, 29, 59, 23, 39, 53, 1, 36, 24, 59, 27, 10, 34, 23, + 38, 30, 60, 22, 42, 28, 19, 9, 57, 30, 19, 43, 33, 13, 63, 3, 19, 11, 50, + 31, 20, 14, 34, 10, 35, 17, 59, 7, 31, 19, 25, 50, 5, 20, 57, 29, 6, 52, 41, + 4, 46, 20, 37, 26, 17, 49, 6, 39, 18, 53, 14, 3, 49, 57, 23, 34, 48, 14, 41, + 28, 38, 56, 6, 58, 25, 39, 19, 43, 15, 37, 11, 47, 18, 53, 4, 37, 9, 62, 21, + 53, 40, 57, 24, 13, 40, 56, 26, 47, 31, 59, 25, 45, 27, 10, 43, 21, 61, 13, + 27, 48, 9, 23, 43, 31, 62, 38, 59, 9, 47}, + {25, 4, 40, 60, 34, 6, 18, 36, 8, 57, 12, 30, 49, 14, 6, 54, 41, 16, 50, 6, + 43, 15, 34, 4, 53, 24, 50, 35, 4, 51, 7, 55, 28, 24, 39, 44, 60, 7, 25, 62, + 42, 53, 24, 61, 28, 45, 52, 12, 48, 37, 9, 35, 43, 3, 37, 48, 12, 58, 30, + 52, 9, 59, 6, 57, 33, 29, 48, 4, 37, 45, 20, 34, 10, 39, 0, 60, 22, 45, 8, + 63, 21, 42, 14, 49, 3, 56, 11, 46, 21, 61, 0, 42, 25, 13, 63, 17, 36, 8, 46, + 16, 6, 35, 63, 0, 21, 37, 4, 57, 9, 34, 5, 61, 48, 32, 8, 37, 54, 17, 56, + 30, 60, 0, 50, 16, 7, 29, 42, 17}, + {32, 50, 15, 48, 2, 43, 52, 25, 47, 16, 32, 63, 21, 52, 40, 19, 0, 61, 29, + 58, 20, 56, 26, 46, 12, 55, 6, 22, 62, 32, 17, 40, 0, 49, 34, 8, 27, 32, 48, + 0, 21, 39, 5, 44, 12, 6, 22, 40, 0, 57, 16, 60, 23, 17, 54, 22, 36, 15, 24, + 39, 19, 34, 47, 23, 0, 54, 13, 51, 24, 9, 55, 16, 52, 27, 44, 20, 4, 54, 26, + 49, 0, 30, 46, 16, 29, 51, 34, 4, 52, 28, 33, 15, 57, 39, 26, 49, 0, 56, 27, + 31, 48, 20, 43, 29, 53, 11, 46, 19, 41, 13, 55, 18, 0, 57, 26, 51, 2, 44, 6, + 38, 14, 40, 22, 45, 36, 53, 3, 57}, + {44, 12, 37, 28, 22, 57, 11, 38, 0, 51, 9, 41, 4, 29, 11, 47, 33, 45, 12, 26, + 3, 36, 9, 63, 31, 16, 38, 44, 14, 47, 25, 61, 20, 58, 15, 47, 17, 57, 13, + 36, 9, 51, 18, 29, 50, 36, 54, 20, 61, 27, 32, 13, 53, 44, 9, 27, 0, 63, 45, + 2, 56, 10, 14, 43, 41, 28, 58, 11, 35, 60, 30, 41, 6, 63, 11, 51, 37, 32, + 15, 10, 35, 53, 5, 61, 22, 7, 26, 59, 23, 9, 44, 48, 21, 3, 51, 32, 24, 41, + 12, 61, 2, 55, 9, 15, 35, 58, 28, 15, 62, 30, 37, 23, 42, 29, 11, 17, 35, + 24, 63, 20, 52, 28, 8, 55, 11, 23, 47, 19}, + {0, 56, 8, 53, 14, 31, 61, 20, 55, 28, 62, 18, 35, 60, 25, 57, 7, 23, 39, 54, + 47, 17, 43, 0, 40, 59, 29, 2, 56, 10, 37, 5, 43, 11, 29, 52, 1, 23, 54, 41, + 59, 30, 55, 1, 62, 15, 33, 4, 43, 10, 47, 39, 1, 31, 40, 60, 49, 33, 7, 55, + 26, 50, 31, 61, 8, 18, 21, 32, 44, 1, 25, 47, 18, 36, 30, 23, 59, 7, 40, 59, + 27, 19, 38, 32, 44, 54, 40, 17, 38, 60, 27, 6, 35, 55, 10, 14, 44, 5, 50, + 17, 38, 26, 42, 50, 18, 3, 44, 52, 2, 49, 7, 52, 15, 46, 62, 39, 55, 10, 31, + 48, 3, 58, 33, 18, 61, 34, 13, 59}, + {39, 27, 63, 20, 35, 41, 4, 45, 26, 5, 38, 13, 44, 2, 50, 17, 37, 52, 2, 13, + 28, 58, 24, 51, 21, 8, 34, 48, 27, 42, 18, 51, 31, 56, 5, 36, 38, 44, 4, 17, + 26, 11, 38, 23, 42, 8, 56, 39, 24, 51, 5, 56, 21, 59, 14, 6, 18, 42, 22, 35, + 16, 37, 3, 25, 39, 46, 63, 5, 50, 17, 58, 8, 55, 3, 50, 12, 43, 17, 47, 2, + 51, 9, 62, 12, 1, 35, 13, 50, 1, 37, 12, 51, 19, 29, 46, 59, 22, 58, 33, 45, + 22, 60, 10, 32, 61, 39, 8, 33, 25, 36, 20, 60, 38, 4, 21, 5, 28, 45, 12, 18, + 42, 11, 49, 1, 27, 40, 6, 30}, + {24, 16, 42, 1, 50, 10, 48, 17, 33, 43, 24, 48, 21, 55, 31, 42, 10, 21, 63, + 35, 49, 6, 33, 13, 41, 53, 10, 20, 60, 6, 53, 26, 12, 41, 22, 60, 14, 28, + 63, 33, 49, 3, 45, 16, 48, 26, 14, 46, 18, 30, 35, 26, 8, 50, 29, 51, 25, + 57, 12, 47, 53, 9, 62, 20, 54, 2, 36, 15, 40, 28, 33, 13, 38, 24, 46, 1, 29, + 56, 33, 20, 44, 24, 41, 26, 57, 20, 63, 8, 30, 55, 5, 41, 62, 8, 34, 2, 37, + 10, 19, 6, 37, 1, 53, 23, 5, 27, 58, 22, 43, 12, 50, 26, 9, 34, 54, 32, 49, + 1, 59, 37, 22, 46, 25, 36, 51, 15, 54, 46}, + {52, 7, 45, 33, 26, 58, 14, 60, 7, 54, 3, 58, 8, 34, 14, 5, 59, 30, 18, 44, + 8, 22, 48, 62, 3, 26, 55, 38, 23, 16, 39, 1, 62, 24, 49, 9, 53, 19, 46, 7, + 19, 60, 31, 58, 2, 34, 53, 7, 59, 2, 62, 42, 46, 19, 36, 11, 44, 4, 38, 28, + 1, 43, 32, 51, 12, 29, 56, 22, 52, 2, 62, 49, 22, 60, 14, 35, 63, 5, 25, 57, + 14, 53, 4, 46, 18, 31, 42, 22, 47, 20, 58, 31, 16, 43, 23, 54, 30, 42, 52, + 57, 29, 49, 30, 13, 45, 48, 16, 55, 6, 63, 1, 44, 14, 58, 19, 47, 15, 24, + 51, 34, 6, 55, 5, 63, 20, 41, 21, 9}, + {30, 62, 18, 55, 5, 23, 39, 29, 49, 30, 15, 36, 28, 46, 60, 25, 39, 46, 4, + 32, 61, 40, 15, 30, 36, 45, 14, 2, 49, 33, 57, 45, 18, 32, 3, 45, 30, 2, 35, + 52, 40, 27, 13, 21, 38, 63, 20, 28, 37, 23, 16, 10, 13, 55, 2, 62, 21, 32, + 60, 17, 58, 23, 5, 40, 16, 48, 7, 45, 10, 26, 43, 19, 6, 31, 52, 21, 39, 16, + 48, 9, 37, 28, 36, 55, 7, 48, 3, 59, 15, 45, 25, 1, 53, 13, 47, 7, 62, 15, + 4, 25, 12, 41, 18, 60, 38, 11, 34, 19, 39, 31, 29, 56, 23, 42, 3, 27, 60, + 41, 8, 16, 61, 29, 43, 9, 32, 2, 60, 34}, + {3, 38, 13, 37, 52, 44, 2, 19, 12, 42, 63, 19, 40, 1, 20, 50, 12, 55, 15, 56, + 27, 1, 54, 11, 57, 18, 32, 63, 44, 4, 29, 13, 37, 61, 35, 16, 42, 57, 12, + 22, 6, 55, 43, 10, 50, 5, 44, 11, 48, 52, 34, 58, 28, 41, 38, 30, 7, 52, 11, + 49, 30, 14, 45, 27, 59, 34, 21, 38, 32, 58, 11, 36, 56, 42, 9, 41, 3, 54, + 31, 42, 0, 60, 16, 11, 39, 24, 52, 33, 6, 36, 10, 40, 32, 60, 26, 20, 39, + 28, 47, 34, 63, 8, 54, 3, 24, 56, 0, 51, 13, 47, 16, 40, 7, 35, 52, 11, 36, + 4, 57, 30, 39, 13, 18, 50, 58, 28, 12, 48}, + {57, 24, 49, 21, 10, 31, 61, 36, 56, 0, 22, 53, 11, 56, 32, 7, 36, 27, 41, 9, + 46, 19, 34, 42, 25, 7, 50, 9, 28, 21, 54, 8, 50, 7, 27, 59, 10, 25, 48, 62, + 37, 0, 33, 58, 25, 18, 32, 61, 0, 15, 45, 5, 50, 3, 23, 55, 47, 17, 40, 6, + 60, 34, 53, 8, 41, 0, 61, 13, 54, 4, 46, 28, 0, 17, 48, 27, 58, 13, 23, 61, + 33, 21, 50, 30, 62, 8, 14, 29, 56, 27, 61, 49, 17, 2, 44, 11, 51, 0, 59, 17, + 40, 20, 32, 47, 36, 21, 42, 28, 60, 4, 54, 10, 59, 17, 30, 62, 21, 43, 26, + 48, 0, 56, 36, 25, 8, 44, 39, 17}, + {10, 42, 4, 59, 27, 47, 8, 23, 51, 32, 45, 6, 37, 26, 48, 43, 62, 0, 21, 53, + 38, 12, 51, 5, 60, 47, 24, 37, 59, 15, 35, 47, 22, 55, 0, 50, 21, 40, 6, 29, + 15, 52, 24, 8, 41, 55, 13, 29, 40, 56, 24, 31, 19, 33, 61, 15, 0, 35, 24, + 42, 21, 2, 19, 57, 24, 15, 30, 50, 20, 25, 40, 16, 57, 34, 61, 8, 29, 45, 6, + 49, 11, 47, 2, 44, 19, 57, 38, 50, 12, 42, 21, 4, 35, 52, 28, 56, 23, 36, + 13, 45, 4, 52, 27, 14, 6, 62, 9, 45, 21, 37, 25, 46, 33, 49, 0, 44, 7, 53, + 13, 19, 53, 31, 3, 47, 15, 56, 22, 51}, + {35, 28, 53, 32, 1, 16, 54, 40, 9, 17, 25, 58, 14, 59, 3, 22, 16, 51, 31, 5, + 23, 58, 28, 17, 35, 20, 0, 42, 11, 52, 3, 31, 41, 17, 43, 13, 32, 54, 18, + 60, 32, 45, 17, 49, 2, 36, 51, 22, 7, 36, 9, 63, 48, 12, 46, 26, 43, 28, 63, + 13, 48, 37, 51, 33, 5, 47, 55, 9, 42, 63, 7, 51, 24, 12, 37, 19, 55, 34, 18, + 38, 15, 28, 54, 34, 5, 43, 22, 0, 48, 14, 54, 24, 58, 9, 38, 5, 32, 55, 21, + 30, 49, 9, 59, 43, 30, 51, 35, 26, 7, 53, 2, 22, 14, 27, 57, 18, 38, 24, 33, + 45, 10, 41, 20, 60, 37, 5, 32, 0}, + {63, 19, 15, 40, 62, 35, 14, 28, 46, 61, 4, 49, 35, 10, 29, 54, 33, 8, 45, + 62, 37, 1, 43, 55, 10, 52, 61, 30, 19, 40, 25, 62, 11, 38, 27, 58, 36, 3, + 46, 8, 39, 4, 62, 28, 47, 20, 4, 54, 47, 27, 43, 1, 21, 38, 8, 58, 10, 54, + 4, 56, 9, 26, 12, 39, 60, 27, 18, 37, 1, 31, 35, 5, 45, 50, 2, 43, 26, 1, + 59, 23, 56, 40, 7, 26, 58, 17, 32, 63, 25, 39, 7, 31, 45, 19, 63, 15, 48, 8, + 37, 61, 16, 34, 1, 56, 18, 3, 15, 58, 49, 32, 63, 41, 55, 5, 40, 22, 50, 6, + 59, 2, 63, 23, 52, 11, 26, 61, 44, 23}, + {11, 56, 46, 6, 22, 43, 58, 3, 34, 21, 38, 30, 18, 44, 52, 13, 41, 57, 17, + 28, 14, 49, 25, 7, 33, 39, 26, 6, 56, 48, 1, 20, 56, 5, 46, 9, 19, 51, 30, + 25, 56, 21, 35, 14, 57, 42, 16, 33, 10, 57, 17, 59, 41, 25, 53, 37, 20, 40, + 30, 18, 31, 62, 44, 22, 3, 44, 11, 48, 23, 53, 18, 60, 29, 22, 62, 15, 53, + 47, 10, 41, 3, 19, 52, 36, 13, 46, 10, 35, 3, 61, 41, 16, 1, 50, 26, 42, 18, + 46, 2, 25, 54, 20, 39, 23, 47, 31, 41, 12, 38, 17, 8, 19, 31, 48, 12, 61, 9, + 54, 29, 35, 15, 38, 6, 43, 34, 14, 7, 47}, + {39, 2, 33, 26, 53, 8, 18, 50, 41, 12, 53, 1, 63, 24, 19, 39, 2, 24, 47, 10, + 60, 38, 19, 63, 48, 4, 15, 45, 32, 14, 60, 36, 29, 53, 23, 63, 34, 12, 61, + 1, 43, 11, 53, 30, 1, 26, 60, 45, 23, 39, 3, 29, 12, 50, 4, 16, 51, 3, 45, + 36, 50, 1, 16, 54, 35, 14, 57, 30, 58, 9, 46, 14, 41, 10, 32, 38, 4, 30, 21, + 51, 32, 63, 25, 1, 60, 27, 53, 18, 51, 22, 28, 55, 34, 12, 40, 3, 60, 29, + 57, 41, 6, 44, 11, 53, 8, 61, 24, 57, 1, 28, 44, 59, 36, 3, 34, 25, 41, 31, + 16, 44, 22, 47, 28, 58, 1, 49, 54, 29}, + {58, 25, 50, 13, 38, 30, 60, 24, 6, 57, 27, 42, 9, 45, 6, 61, 30, 50, 4, 34, + 29, 3, 46, 13, 22, 42, 58, 28, 9, 39, 23, 44, 7, 15, 44, 2, 40, 15, 47, 41, + 23, 37, 7, 59, 38, 11, 34, 6, 62, 14, 52, 35, 55, 19, 32, 61, 33, 24, 57, 6, + 22, 59, 29, 7, 49, 25, 40, 3, 17, 39, 27, 52, 0, 55, 16, 57, 24, 61, 36, 6, + 29, 12, 48, 39, 20, 44, 6, 40, 33, 5, 48, 10, 57, 36, 22, 51, 33, 9, 24, 12, + 62, 29, 50, 35, 14, 43, 5, 33, 47, 52, 13, 23, 10, 51, 56, 16, 46, 1, 49, 4, + 61, 9, 52, 18, 31, 21, 36, 17}, + {19, 42, 9, 48, 2, 44, 11, 37, 48, 20, 33, 16, 55, 35, 49, 15, 37, 20, 59, + 16, 53, 22, 56, 31, 50, 11, 34, 54, 16, 51, 4, 49, 33, 53, 21, 28, 56, 24, + 31, 9, 52, 16, 48, 24, 44, 13, 51, 20, 31, 49, 18, 6, 34, 2, 44, 14, 47, 8, + 15, 43, 13, 41, 33, 52, 20, 61, 7, 51, 34, 62, 4, 20, 36, 33, 43, 8, 46, 13, + 53, 17, 45, 42, 9, 31, 52, 11, 30, 56, 13, 59, 17, 44, 27, 6, 62, 11, 43, + 17, 49, 38, 26, 2, 16, 27, 58, 21, 54, 18, 26, 5, 35, 61, 43, 27, 7, 39, 14, + 58, 37, 55, 20, 33, 13, 40, 62, 10, 55, 5}, + {51, 14, 61, 29, 59, 20, 55, 31, 0, 49, 11, 60, 3, 26, 22, 56, 0, 40, 12, 43, + 41, 8, 36, 0, 17, 57, 24, 2, 46, 26, 61, 18, 0, 38, 12, 59, 6, 49, 3, 57, + 19, 63, 5, 33, 18, 54, 28, 56, 0, 43, 26, 46, 63, 27, 56, 22, 27, 54, 38, + 28, 63, 24, 10, 45, 0, 31, 42, 21, 12, 25, 44, 49, 59, 6, 26, 50, 3, 34, 27, + 59, 0, 35, 62, 16, 4, 58, 47, 0, 43, 24, 37, 2, 54, 20, 46, 31, 0, 56, 34, + 5, 55, 45, 60, 37, 0, 40, 10, 38, 63, 46, 15, 20, 0, 53, 21, 62, 30, 11, 24, + 27, 40, 0, 57, 26, 3, 45, 27, 35} +}; + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB565 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB565 conversion */ +#define WRITE1_RGBA_RGB565(src, dest) \ +*dest = ((*src >> 8) & 0xf800) | \ + ((*src >> 5) & 0x7e0) | \ + ((*src >> 3) & 0x1f); dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_RGB565(src, dest) \ +{ \ + *((DATA32 *)dest) = ((src[1] >> 8) & 0xf800) | \ + ((src[1] >> 5) & 0x7e0) | \ + ((src[1] >> 3) & 0x1f) | \ + ((src[0] << 8) & 0xf8000000) | \ + ((src[0] << 11) & 0x7e00000) | \ + ((src[0] << 13) & 0x1f0000); \ + dest += 2; src += 2; \ +} +#else +#define WRITE2_RGBA_RGB565(src, dest) \ +{ \ + *((DATA32 *)dest) = ((src[0] >> 8) & 0xf800) | \ + ((src[0] >> 5) & 0x7e0) | \ + ((src[0] >> 3) & 0x1f) | \ + ((src[1] << 8) & 0xf8000000) | \ + ((src[1] << 11) & 0x7e00000) | \ + ((src[1] << 13) & 0x1f0000); \ + dest += 2; src += 2; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB565 conversion */ +#define DITHER_RGBA_565_LUT_R(num) \ +(_dither_r16[(((x + num) & 0x3) << 10) | ((y & 0x3) << 8) | ((src[num] >> 16 ) & 0xff)]) +#define DITHER_RGBA_565_LUT_G(num) \ +(_dither_g16[(((x + num) & 0x3) << 10) | ((y & 0x3) << 8) | ((src[num] >> 8 ) & 0xff)]) +#define DITHER_RGBA_565_LUT_B(num) \ +(_dither_b16[(((x + num) & 0x3) << 10) | ((y & 0x3) << 8) | ((src[num] >> 0 ) & 0xff)]) + +#define WRITE1_RGBA_RGB565_DITHER(src, dest) \ +*dest = (DITHER_RGBA_565_LUT_R(0)) | \ + (DITHER_RGBA_565_LUT_G(0)) | \ + (DITHER_RGBA_565_LUT_B(0)); dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_RGB565_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = ((DITHER_RGBA_565_LUT_R(1))) | \ + ((DITHER_RGBA_565_LUT_G(1))) | \ + ((DITHER_RGBA_565_LUT_B(1))) | \ + ((DITHER_RGBA_565_LUT_R(0) << 16)) | \ + ((DITHER_RGBA_565_LUT_G(0) << 16)) | \ + ((DITHER_RGBA_565_LUT_B(0) << 16)); \ + dest += 2; src += 2; \ +} +#else +#define WRITE2_RGBA_RGB565_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = ((DITHER_RGBA_565_LUT_R(0))) | \ + ((DITHER_RGBA_565_LUT_G(0))) | \ + ((DITHER_RGBA_565_LUT_B(0))) | \ + ((DITHER_RGBA_565_LUT_R(1) << 16)) | \ + ((DITHER_RGBA_565_LUT_G(1) << 16)) | \ + ((DITHER_RGBA_565_LUT_B(1) << 16)); \ + dest += 2; src += 2; \ +} +#endif +/*****************************************************************************/ +/* MACROS for plain RGBA -> BGR565 conversion */ +#define WRITE1_RGBA_BGR565(src, dest) \ +*dest = ((*src << 8) & 0xf800) | \ + ((*src >> 5) & 0x7e0) | \ + ((*src >> 19)& 0x1f); dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_BGR565(src, dest) \ +{ \ + *((DATA32 *)dest) = ((src[1] << 8) & 0xf800) | \ + ((src[1] >> 5) & 0x7e0) | \ + ((src[1] >> 19)& 0x1f) | \ + ((src[0] << 24) & 0xf8000000) | \ + ((src[0] << 11) & 0x7e00000) | \ + ((src[0] >> 3) & 0x1f0000); \ + dest += 2; src += 2; \ +} +#else +#define WRITE2_RGBA_BGR565(src, dest) \ +{ \ + *((DATA32 *)dest) = ((src[0] << 8) & 0xf800) | \ + ((src[0] >> 5) & 0x7e0) | \ + ((src[0] >> 19)& 0x1f) | \ + ((src[1] << 24) & 0xf8000000) | \ + ((src[1] << 11) & 0x7e00000) | \ + ((src[1] >> 3) & 0x1f0000); \ + dest += 2; src += 2; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> BGR565 conversion */ +#define DITHER_RGBA_BGR565_LUT_R(num) \ +(_dither_r16[(((x + num) & 0x3) << 10) | ((y & 0x3) << 8) | ((src[num] >> 0 ) & 0xff)]) +#define DITHER_RGBA_BGR565_LUT_G(num) \ +(_dither_g16[(((x + num) & 0x3) << 10) | ((y & 0x3) << 8) | ((src[num] >> 8 ) & 0xff)]) +#define DITHER_RGBA_BGR565_LUT_B(num) \ +(_dither_b16[(((x + num) & 0x3) << 10) | ((y & 0x3) << 8) | ((src[num] >> 16) & 0xff)]) + +#define WRITE1_RGBA_BGR565_DITHER(src, dest) \ +*dest = (DITHER_RGBA_BGR565_LUT_R(0)) | \ + (DITHER_RGBA_BGR565_LUT_G(0)) | \ + (DITHER_RGBA_BGR565_LUT_B(0)); dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_BGR565_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = ((DITHER_RGBA_BGR565_LUT_R(1))) | \ + ((DITHER_RGBA_BGR565_LUT_G(1))) | \ + ((DITHER_RGBA_BGR565_LUT_B(1))) | \ + ((DITHER_RGBA_BGR565_LUT_R(0) << 16)) | \ + ((DITHER_RGBA_BGR565_LUT_G(0) << 16)) | \ + ((DITHER_RGBA_BGR565_LUT_B(0) << 16)); \ + dest += 2; src += 2; \ +} +#else +#define WRITE2_RGBA_BGR565_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = ((DITHER_RGBA_BGR565_LUT_R(0))) | \ + ((DITHER_RGBA_BGR565_LUT_G(0))) | \ + ((DITHER_RGBA_BGR565_LUT_B(0))) | \ + ((DITHER_RGBA_BGR565_LUT_R(1) << 16)) | \ + ((DITHER_RGBA_BGR565_LUT_G(1) << 16)) | \ + ((DITHER_RGBA_BGR565_LUT_B(1) << 16)); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB555 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB555 conversion */ +#define WRITE1_RGBA_RGB555(src, dest) \ +*dest = ((*src >> 9) & 0x7c00) | \ + ((*src >> 6) & 0x3e0) | \ + ((*src >> 3) & 0x1f); dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_RGB555(src, dest) \ +{ \ + *((DATA32 *)dest) = ((src[1] >> 9) & 0x7c00) | \ + ((src[1] >> 6) & 0x3e0) | \ + ((src[1] >> 3) & 0x1f) | \ + ((src[0] << 7) & 0x7c000000) | \ + ((src[0] << 10) & 0x3e00000) | \ + ((src[0] << 13) & 0x1f0000); \ + dest += 2; src += 2; \ +} +#else +#define WRITE2_RGBA_RGB555(src, dest) \ +{ \ + *((DATA32 *)dest) = ((src[0] >> 9) & 0x7c00) | \ + ((src[0] >> 6) & 0x3e0) | \ + ((src[0] >> 3) & 0x1f) | \ + ((src[1] << 7) & 0x7c000000) | \ + ((src[1] << 10) & 0x3e00000) | \ + ((src[1] << 13) & 0x1f0000); \ + dest += 2; src += 2; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB555 conversion */ +#define DITHER_RGBA_555_LUT_R(num) \ +(_dither_r16[(((x + num) & 0x3) << 10) | ((y & 0x3) << 8) | ((src[num] >> 16 ) & 0xff)]) +#define DITHER_RGBA_555_LUT_G(num) \ +(_dither_g16[(((x + num) & 0x3) << 10) | ((y & 0x3) << 8) | ((src[num] >> 8 ) & 0xff)]) +#define DITHER_RGBA_555_LUT_B(num) \ +(_dither_b16[(((x + num) & 0x3) << 10) | ((y & 0x3) << 8) | ((src[num] >> 0 ) & 0xff)]) + +#define WRITE1_RGBA_RGB555_DITHER(src, dest) \ +*dest = (DITHER_RGBA_555_LUT_R(0)) | \ + (DITHER_RGBA_555_LUT_G(0)) | \ + (DITHER_RGBA_555_LUT_B(0)); dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_RGB555_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = ((DITHER_RGBA_555_LUT_R(1))) | \ + ((DITHER_RGBA_555_LUT_G(1))) | \ + ((DITHER_RGBA_555_LUT_B(1))) | \ + ((DITHER_RGBA_555_LUT_R(0) << 16)) | \ + ((DITHER_RGBA_555_LUT_G(0) << 16)) | \ + ((DITHER_RGBA_555_LUT_B(0) << 16)); \ + dest += 2; src += 2; \ +} +#else +#define WRITE2_RGBA_RGB555_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = ((DITHER_RGBA_555_LUT_R(0))) | \ + ((DITHER_RGBA_555_LUT_G(0))) | \ + ((DITHER_RGBA_555_LUT_B(0))) | \ + ((DITHER_RGBA_555_LUT_R(1) << 16)) | \ + ((DITHER_RGBA_555_LUT_G(1) << 16)) | \ + ((DITHER_RGBA_555_LUT_B(1) << 16)); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* MACROS for plain RGBA -> BGR555 conversion */ +#define WRITE1_RGBA_BGR555(src, dest) \ +*dest = ((*src << 7) & 0x7c00) | \ + ((*src >> 6) & 0x3e0) | \ + ((*src >> 19)& 0x1f); dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_BGR555(src, dest) \ +{ \ + *((DATA32 *)dest) = ((src[1] << 7) & 0x7c00) | \ + ((src[1] >> 6) & 0x3e0) | \ + ((src[1] >> 19)& 0x1f) | \ + ((src[0] << 23) & 0x7c000000) | \ + ((src[0] << 10) & 0x3e00000) | \ + ((src[0] >> 3) & 0x1f0000); \ + dest += 2; src += 2; \ +} +#else +#define WRITE2_RGBA_BGR555(src, dest) \ +{ \ + *((DATA32 *)dest) = ((src[0] << 7) & 0x7c00) | \ + ((src[0] >> 6) & 0x3e0) | \ + ((src[0] >> 19)& 0x1f) | \ + ((src[1] << 23) & 0x7c000000) | \ + ((src[1] << 10) & 0x3e00000) | \ + ((src[1] >> 3) & 0x1f0000); \ + dest += 2; src += 2; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> BGR555 conversion */ +#define DITHER_RGBA_BGR555_LUT_R(num) \ +(_dither_r16[(((x + num) & 0x3) << 10) | ((y & 0x3) << 8) | ((src[num] >> 0 ) & 0xff)]) +#define DITHER_RGBA_BGR555_LUT_G(num) \ +(_dither_g16[(((x + num) & 0x3) << 10) | ((y & 0x3) << 8) | ((src[num] >> 8 ) & 0xff)]) +#define DITHER_RGBA_BGR555_LUT_B(num) \ +(_dither_b16[(((x + num) & 0x3) << 10) | ((y & 0x3) << 8) | ((src[num] >> 16 ) & 0xff)]) + +#define WRITE1_RGBA_BGR555_DITHER(src, dest) \ +*dest = (DITHER_RGBA_BGR555_LUT_R(0)) | \ + (DITHER_RGBA_BGR555_LUT_G(0)) | \ + (DITHER_RGBA_BGR555_LUT_B(0)); dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_BGR555_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = ((DITHER_RGBA_BGR555_LUT_R(1))) | \ + ((DITHER_RGBA_BGR555_LUT_G(1))) | \ + ((DITHER_RGBA_BGR555_LUT_B(1))) | \ + ((DITHER_RGBA_BGR555_LUT_R(0) << 16)) | \ + ((DITHER_RGBA_BGR555_LUT_G(0) << 16)) | \ + ((DITHER_RGBA_BGR555_LUT_B(0) << 16)); \ + dest += 2; src += 2; \ +} +#else +#define WRITE2_RGBA_BGR555_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = ((DITHER_RGBA_BGR555_LUT_R(0))) | \ + ((DITHER_RGBA_BGR555_LUT_G(0))) | \ + ((DITHER_RGBA_BGR555_LUT_B(0))) | \ + ((DITHER_RGBA_BGR555_LUT_R(1) << 16)) | \ + ((DITHER_RGBA_BGR555_LUT_G(1) << 16)) | \ + ((DITHER_RGBA_BGR555_LUT_B(1) << 16)); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB332 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB332 conversion */ +#define WRITE1_RGBA_RGB332(src, dest) \ +*dest = _dither_color_lut[((*src >> 6) & 0x03) | \ + ((*src >> 11) & 0x1c) | \ + ((*src >> 16) & 0xe0)]; dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_RGB332(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[1] >> 6) & 0x03) | \ + ((src[1] >> 11) & 0x1c) | \ + ((src[1] >> 16) & 0xe0)]) | \ + (_dither_color_lut[((src[0] >> 6) & 0x03) | \ + ((src[0] >> 11) & 0x1c) | \ + ((src[0] >> 16) & 0xe0)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB332(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[3] >> 6) & 0x03) | \ + ((src[3] >> 11) & 0x1c) | \ + ((src[3] >> 16) & 0xe0)]) | \ + (_dither_color_lut[((src[2] >> 6) & 0x03) | \ + ((src[2] >> 11) & 0x1c) | \ + ((src[2] >> 16) & 0xe0)] << 8) | \ + (_dither_color_lut[((src[1] >> 6) & 0x03) | \ + ((src[1] >> 11) & 0x1c) | \ + ((src[1] >> 16) & 0xe0)] << 16) | \ + (_dither_color_lut[((src[0] >> 6) & 0x03) | \ + ((src[0] >> 11) & 0x1c) | \ + ((src[0] >> 16) & 0xe0)] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB332(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[0] >> 6) & 0x03) | \ + ((src[0] >> 11) & 0x1c) | \ + ((src[0] >> 16) & 0xe0)]) | \ + (_dither_color_lut[((src[1] >> 6) & 0x03) | \ + ((src[1] >> 11) & 0x1c) | \ + ((src[1] >> 16) & 0xe0)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB332(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[0] >> 6) & 0x03) | \ + ((src[0] >> 11) & 0x1c) | \ + ((src[0] >> 16) & 0xe0)]) | \ + (_dither_color_lut[((src[1] >> 6) & 0x03) | \ + ((src[1] >> 11) & 0x1c) | \ + ((src[1] >> 16) & 0xe0)] << 8) | \ + (_dither_color_lut[((src[2] >> 6) & 0x03) | \ + ((src[2] >> 11) & 0x1c) | \ + ((src[2] >> 16) & 0xe0)] << 16) | \ + (_dither_color_lut[((src[3] >> 6) & 0x03) | \ + ((src[3] >> 11) & 0x1c) | \ + ((src[3] >> 16) & 0xe0)] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB332 conversion */ +#define DITHER_RGBA_332_LUT_R(num) \ +(_dither_r8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 16) & 0xff)]) +#define DITHER_RGBA_332_LUT_G(num) \ +(_dither_g8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 8) & 0xff)]) +#define DITHER_RGBA_332_LUT_B(num) \ +(_dither_b8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 0) & 0xff)]) + +#define WRITE1_RGBA_RGB332_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_332_LUT_R(0)) | \ + (DITHER_RGBA_332_LUT_G(0)) | \ + (DITHER_RGBA_332_LUT_B(0))]; dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE4_RGBA_RGB332_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_332_LUT_R(3))) | \ + ((DITHER_RGBA_332_LUT_G(3))) | \ + ((DITHER_RGBA_332_LUT_B(3)))]) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(2))) | \ + ((DITHER_RGBA_332_LUT_G(2))) | \ + ((DITHER_RGBA_332_LUT_B(2)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(1))) | \ + ((DITHER_RGBA_332_LUT_G(1))) | \ + ((DITHER_RGBA_332_LUT_B(1)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(0))) | \ + ((DITHER_RGBA_332_LUT_G(0))) | \ + ((DITHER_RGBA_332_LUT_B(0)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB332_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_332_LUT_R(1))) | \ + ((DITHER_RGBA_332_LUT_G(1))) | \ + ((DITHER_RGBA_332_LUT_B(1)))]) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(0))) | \ + ((DITHER_RGBA_332_LUT_G(0))) | \ + ((DITHER_RGBA_332_LUT_B(0)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB332_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_332_LUT_R(0))) | \ + ((DITHER_RGBA_332_LUT_G(0))) | \ + ((DITHER_RGBA_332_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(1))) | \ + ((DITHER_RGBA_332_LUT_G(1))) | \ + ((DITHER_RGBA_332_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(2))) | \ + ((DITHER_RGBA_332_LUT_G(2))) | \ + ((DITHER_RGBA_332_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(3))) | \ + ((DITHER_RGBA_332_LUT_G(3))) | \ + ((DITHER_RGBA_332_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB332_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_332_LUT_R(0))) | \ + ((DITHER_RGBA_332_LUT_G(0))) | \ + ((DITHER_RGBA_332_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(1))) | \ + ((DITHER_RGBA_332_LUT_G(1))) | \ + ((DITHER_RGBA_332_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB666 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB666 conversion */ +#define WRITE1_RGBA_RGB666(src, dest) \ +{ \ +*dest = _dither_color_lut[(_dither_666r[(*src >> 16) & 0xff] ) + \ + (_dither_666g[(*src >> 8 ) & 0xff] ) + \ + (_dither_666b[(*src ) & 0xff] )]; dest++; src++; \ +} +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_RGB666(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[(_dither_666r[(src[1] >> 16) & 0xff] ) + \ + (_dither_666g[(src[1] >> 8 ) & 0xff] ) + \ + (_dither_666b[(src[1] ) & 0xff] )]) | \ + (_dither_color_lut[(_dither_666r[(src[0] >> 16) & 0xff] ) + \ + (_dither_666g[(src[0] >> 8 ) & 0xff] ) + \ + (_dither_666b[(src[0] ) & 0xff] )] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB666(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[(_dither_666r[(src[3] >> 16) & 0xff] ) + \ + (_dither_666g[(src[3] >> 8 ) & 0xff] ) + \ + (_dither_666b[(src[3] ) & 0xff] )]) | \ + (_dither_color_lut[(_dither_666r[(src[2] >> 16) & 0xff] ) + \ + (_dither_666g[(src[2] >> 8 ) & 0xff] ) + \ + (_dither_666b[(src[2] ) & 0xff] )] << 8) | \ + (_dither_color_lut[(_dither_666r[(src[1] >> 16) & 0xff] ) + \ + (_dither_666g[(src[1] >> 8 ) & 0xff] ) + \ + (_dither_666b[(src[1] ) & 0xff] )] << 16) | \ + (_dither_color_lut[(_dither_666r[(src[0] >> 16) & 0xff] ) + \ + (_dither_666g[(src[0] >> 8 ) & 0xff] ) + \ + (_dither_666b[(src[0] ) & 0xff] )] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB666(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[(_dither_666r[(src[0] >> 16) & 0xff] ) + \ + (_dither_666g[(src[0] >> 8 ) & 0xff] ) + \ + (_dither_666b[(src[0] ) & 0xff] )]) | \ + (_dither_color_lut[(_dither_666r[(src[1] >> 16) & 0xff] ) + \ + (_dither_666g[(src[1] >> 8 ) & 0xff] ) + \ + (_dither_666b[(src[1] ) & 0xff] )] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB666(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[(_dither_666r[(src[0] >> 16) & 0xff] ) + \ + (_dither_666g[(src[0] >> 8 ) & 0xff] ) + \ + (_dither_666b[(src[0] ) & 0xff] )]) | \ + (_dither_color_lut[(_dither_666r[(src[1] >> 16) & 0xff] ) + \ + (_dither_666g[(src[1] >> 8 ) & 0xff] ) + \ + (_dither_666b[(src[1] ) & 0xff] )] << 8) | \ + (_dither_color_lut[(_dither_666r[(src[2] >> 16) & 0xff] ) + \ + (_dither_666g[(src[2] >> 8 ) & 0xff] ) + \ + (_dither_666b[(src[2] ) & 0xff] )] << 16) | \ + (_dither_color_lut[(_dither_666r[(src[3] >> 16) & 0xff] ) + \ + (_dither_666g[(src[3] >> 8 ) & 0xff] ) + \ + (_dither_666b[(src[3] ) & 0xff] )] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB666 conversion */ +#define DITHER_RGBA_666_LUT_R(num) \ +(_dither_r8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 16) & 0xff)]) +#define DITHER_RGBA_666_LUT_G(num) \ +(_dither_g8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 8) & 0xff)]) +#define DITHER_RGBA_666_LUT_B(num) \ +(_dither_b8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 0) & 0xff)]) + +#define WRITE1_RGBA_RGB666_DITHER(src, dest) \ +{ \ +int _dith; \ +int _r[1], _g[1], _b[1]; \ +_dith = (_dither_128128[(x + 0) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[0] = ((((src[0] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[0] = ((((src[0] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[0] = ((((src[0] ) & 0xff) * 5) + _dith) >> 8; \ + *((DATA8 *)dest) = \ +(_dither_color_lut[(_r[0] * 36) + (_g[0] * 6) + _b[0]]) \ +; \ +dest += 1; src += 1; \ +} +#ifdef WORDS_BIGENDIAN +#define WRITE4_RGBA_RGB666_DITHER(src, dest) \ +{ \ +int _dith; \ +int _r[4], _g[4], _b[4]; \ +_dith = (_dither_128128[(x + 0) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[0] = ((((src[0] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[0] = ((((src[0] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[0] = ((((src[0] ) & 0xff) * 5) + _dith) >> 8; \ +_dith = (_dither_128128[(x + 1) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[1] = ((((src[1] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[1] = ((((src[1] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[1] = ((((src[1] ) & 0xff) * 5) + _dith) >> 8; \ +_dith = (_dither_128128[(x + 2) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[2] = ((((src[2] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[2] = ((((src[2] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[2] = ((((src[2] ) & 0xff) * 5) + _dith) >> 8; \ +_dith = (_dither_128128[(x + 3) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[3] = ((((src[3] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[3] = ((((src[3] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[3] = ((((src[3] ) & 0xff) * 5) + _dith) >> 8; \ + *((DATA32 *)dest) = \ +(_dither_color_lut[(_r[3] * 36) + (_g[3] * 6) + _b[3]]) | \ +(_dither_color_lut[(_r[2] * 36) + (_g[2] * 6) + _b[2]] << 8) | \ +(_dither_color_lut[(_r[1] * 36) + (_g[1] * 6) + _b[1]] << 16) | \ +(_dither_color_lut[(_r[0] * 36) + (_g[0] * 6) + _b[0]] << 24) \ +; \ +dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB666_DITHER(src, dest) \ +{ \ +int _dith; \ +int _r[2], _g[2], _b[2]; \ +_dith = (_dither_128128[(x + 0) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[0] = ((((src[0] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[0] = ((((src[0] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[0] = ((((src[0] ) & 0xff) * 5) + _dith) >> 8; \ +_dith = (_dither_128128[(x + 1) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[1] = ((((src[1] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[1] = ((((src[1] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[1] = ((((src[1] ) & 0xff) * 5) + _dith) >> 8; \ + *((DATA16 *)dest) = \ +(_dither_color_lut[(_r[1] * 36) + (_g[1] * 6) + _b[1]]) | \ +(_dither_color_lut[(_r[0] * 36) + (_g[0] * 6) + _b[0]] << 8) \ +; \ +dest += 2; src += 2; \ +} +#else +#if 0 /* OOOOOOLD code for 666 - the 666 dithering uses the 128x128 dither mask :) */ +#define WRITE4_RGBA_RGB666_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_666_LUT_R(0))) + \ + ((DITHER_RGBA_666_LUT_G(0))) + \ + ((DITHER_RGBA_666_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_666_LUT_R(1))) + \ + ((DITHER_RGBA_666_LUT_G(1))) + \ + ((DITHER_RGBA_666_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_666_LUT_R(2))) + \ + ((DITHER_RGBA_666_LUT_G(2))) + \ + ((DITHER_RGBA_666_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_666_LUT_R(3))) + \ + ((DITHER_RGBA_666_LUT_G(3))) + \ + ((DITHER_RGBA_666_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB666_DITHER(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((DITHER_RGBA_666_LUT_R(0))) + \ + ((DITHER_RGBA_666_LUT_G(0))) + \ + ((DITHER_RGBA_666_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_666_LUT_R(1))) + \ + ((DITHER_RGBA_666_LUT_G(1))) + \ + ((DITHER_RGBA_666_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB666_DITHER(src, dest) \ +{ \ +int _dith; \ +int _r[4], _g[4], _b[4]; \ +_dith = (_dither_128128[(x + 0) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[0] = ((((src[0] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[0] = ((((src[0] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[0] = ((((src[0] ) & 0xff) * 5) + _dith) >> 8; \ +_dith = (_dither_128128[(x + 1) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[1] = ((((src[1] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[1] = ((((src[1] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[1] = ((((src[1] ) & 0xff) * 5) + _dith) >> 8; \ +_dith = (_dither_128128[(x + 2) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[2] = ((((src[2] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[2] = ((((src[2] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[2] = ((((src[2] ) & 0xff) * 5) + _dith) >> 8; \ +_dith = (_dither_128128[(x + 3) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[3] = ((((src[3] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[3] = ((((src[3] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[3] = ((((src[3] ) & 0xff) * 5) + _dith) >> 8; \ + *((DATA32 *)dest) = \ +(_dither_color_lut[(_r[0] * 36) + (_g[0] * 6) + _b[0]]) | \ +(_dither_color_lut[(_r[1] * 36) + (_g[1] * 6) + _b[1]] << 8) | \ +(_dither_color_lut[(_r[2] * 36) + (_g[2] * 6) + _b[2]] << 16) | \ +(_dither_color_lut[(_r[3] * 36) + (_g[3] * 6) + _b[3]] << 24) \ +; \ +dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB666_DITHER(src, dest) \ +{ \ +int _dith; \ +int _r[2], _g[2], _b[2]; \ +_dith = (_dither_128128[(x + 0) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[0] = ((((src[0] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[0] = ((((src[0] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[0] = ((((src[0] ) & 0xff) * 5) + _dith) >> 8; \ +_dith = (_dither_128128[(x + 1) & 0x7f][y & 0x7f] << 2) | 7; \ +_r[1] = ((((src[1] >> 16) & 0xff) * 5) + _dith) >> 8; \ +_g[1] = ((((src[1] >> 8 ) & 0xff) * 5) + (262 - _dith)) >> 8; \ +_b[1] = ((((src[1] ) & 0xff) * 5) + _dith) >> 8; \ + *((DATA16 *)dest) = \ +(_dither_color_lut[(_r[0] * 36) + (_g[0] * 6) + _b[0]]) | \ +(_dither_color_lut[(_r[1] * 36) + (_g[1] * 6) + _b[1]] << 8) \ +; \ +dest += 2; src += 2; \ +} +#endif +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB232 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB232 conversion */ +#define RGB232_BSHIFT >> 6 +#define RGB232_GSHIFT >> 11 +#define RGB232_RSHIFT >> 17 +#define RGB232_BMASK & 0x03 +#define RGB232_GMASK & 0x1c +#define RGB232_RMASK & 0x60 + +#define WRITE1_RGBA_RGB232(src, dest) \ +*dest = _dither_color_lut[((*src RGB232_BSHIFT) RGB232_BMASK) | \ + ((*src RGB232_GSHIFT) RGB232_GMASK) | \ + ((*src RGB232_RSHIFT) RGB232_RMASK)]; dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_RGB232(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[1] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[1] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[1] RGB232_RSHIFT) RGB232_RMASK)]) | \ + (_dither_color_lut[((src[0] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[0] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[0] RGB232_RSHIFT) RGB232_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB232(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[3] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[3] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[3] RGB232_RSHIFT) RGB232_RMASK)]) | \ + (_dither_color_lut[((src[2] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[2] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[2] RGB232_RSHIFT) RGB232_RMASK)] << 8) | \ + (_dither_color_lut[((src[1] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[1] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[1] RGB232_RSHIFT) RGB232_RMASK)] << 16) | \ + (_dither_color_lut[((src[0] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[0] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[0] RGB232_RSHIFT) RGB232_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB232(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[0] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[0] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[0] RGB232_RSHIFT) RGB232_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[1] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[1] RGB232_RSHIFT) RGB232_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB232(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[0] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[0] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[0] RGB232_RSHIFT) RGB232_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[1] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[1] RGB232_RSHIFT) RGB232_RMASK)] << 8) | \ + (_dither_color_lut[((src[2] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[2] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[2] RGB232_RSHIFT) RGB232_RMASK)] << 16) | \ + (_dither_color_lut[((src[3] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[3] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[3] RGB232_RSHIFT) RGB232_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB232 conversion */ +#define DITHER_RGBA_232_LUT_R(num) \ +(_dither_r8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 16) & 0xff)]) +#define DITHER_RGBA_232_LUT_G(num) \ +(_dither_g8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 8) & 0xff)]) +#define DITHER_RGBA_232_LUT_B(num) \ +(_dither_b8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 0) & 0xff)]) + +#define WRITE1_RGBA_RGB232_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_232_LUT_R(0)) | \ + (DITHER_RGBA_232_LUT_G(0)) | \ + (DITHER_RGBA_232_LUT_B(0))]; dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE4_RGBA_RGB232_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_232_LUT_R(3))) | \ + ((DITHER_RGBA_232_LUT_G(3))) | \ + ((DITHER_RGBA_232_LUT_B(3)))]) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(2))) | \ + ((DITHER_RGBA_232_LUT_G(2))) | \ + ((DITHER_RGBA_232_LUT_B(2)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(1))) | \ + ((DITHER_RGBA_232_LUT_G(1))) | \ + ((DITHER_RGBA_232_LUT_B(1)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(0))) | \ + ((DITHER_RGBA_232_LUT_G(0))) | \ + ((DITHER_RGBA_232_LUT_B(0)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB232_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_232_LUT_R(1))) | \ + ((DITHER_RGBA_232_LUT_G(1))) | \ + ((DITHER_RGBA_232_LUT_B(1)))]) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(0))) | \ + ((DITHER_RGBA_232_LUT_G(0))) | \ + ((DITHER_RGBA_232_LUT_B(0)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB232_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_232_LUT_R(0))) | \ + ((DITHER_RGBA_232_LUT_G(0))) | \ + ((DITHER_RGBA_232_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(1))) | \ + ((DITHER_RGBA_232_LUT_G(1))) | \ + ((DITHER_RGBA_232_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(2))) | \ + ((DITHER_RGBA_232_LUT_G(2))) | \ + ((DITHER_RGBA_232_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(3))) | \ + ((DITHER_RGBA_232_LUT_G(3))) | \ + ((DITHER_RGBA_232_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB232_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_232_LUT_R(0))) | \ + ((DITHER_RGBA_232_LUT_G(0))) | \ + ((DITHER_RGBA_232_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(1))) | \ + ((DITHER_RGBA_232_LUT_G(1))) | \ + ((DITHER_RGBA_232_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB222 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB222 conversion */ +#define RGB222_BSHIFT >> 6 +#define RGB222_GSHIFT >> 12 +#define RGB222_RSHIFT >> 18 +#define RGB222_BMASK & 0x03 +#define RGB222_GMASK & 0x0c +#define RGB222_RMASK & 0x30 + +#define WRITE1_RGBA_RGB222(src, dest) \ +*dest = _dither_color_lut[((*src RGB222_BSHIFT) RGB222_BMASK) | \ + ((*src RGB222_GSHIFT) RGB222_GMASK) | \ + ((*src RGB222_RSHIFT) RGB222_RMASK)]; dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_RGB222(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[1] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[1] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[1] RGB222_RSHIFT) RGB222_RMASK)]) | \ + (_dither_color_lut[((src[0] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[0] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[0] RGB222_RSHIFT) RGB222_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB222(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[3] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[3] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[3] RGB222_RSHIFT) RGB222_RMASK)]) | \ + (_dither_color_lut[((src[2] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[2] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[2] RGB222_RSHIFT) RGB222_RMASK)] << 8) | \ + (_dither_color_lut[((src[1] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[1] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[1] RGB222_RSHIFT) RGB222_RMASK)] << 16) | \ + (_dither_color_lut[((src[0] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[0] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[0] RGB222_RSHIFT) RGB222_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB222(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[0] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[0] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[0] RGB222_RSHIFT) RGB222_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[1] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[1] RGB222_RSHIFT) RGB222_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB222(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[0] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[0] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[0] RGB222_RSHIFT) RGB222_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[1] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[1] RGB222_RSHIFT) RGB222_RMASK)] << 8) | \ + (_dither_color_lut[((src[2] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[2] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[2] RGB222_RSHIFT) RGB222_RMASK)] << 16) | \ + (_dither_color_lut[((src[3] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[3] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[3] RGB222_RSHIFT) RGB222_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB222 conversion */ +#define DITHER_RGBA_222_LUT_R(num) \ +(_dither_r8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 16) & 0xff)]) +#define DITHER_RGBA_222_LUT_G(num) \ +(_dither_g8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 8) & 0xff)]) +#define DITHER_RGBA_222_LUT_B(num) \ +(_dither_b8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 0) & 0xff)]) + +#define WRITE1_RGBA_RGB222_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_222_LUT_R(0)) | \ + (DITHER_RGBA_222_LUT_G(0)) | \ + (DITHER_RGBA_222_LUT_B(0))]; dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE4_RGBA_RGB222_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_222_LUT_R(3))) | \ + ((DITHER_RGBA_222_LUT_G(3))) | \ + ((DITHER_RGBA_222_LUT_B(3)))]) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(2))) | \ + ((DITHER_RGBA_222_LUT_G(2))) | \ + ((DITHER_RGBA_222_LUT_B(2)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(1))) | \ + ((DITHER_RGBA_222_LUT_G(1))) | \ + ((DITHER_RGBA_222_LUT_B(1)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(0))) | \ + ((DITHER_RGBA_222_LUT_G(0))) | \ + ((DITHER_RGBA_222_LUT_B(0)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB222_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_222_LUT_R(1))) | \ + ((DITHER_RGBA_222_LUT_G(1))) | \ + ((DITHER_RGBA_222_LUT_B(1)))]) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(0))) | \ + ((DITHER_RGBA_222_LUT_G(0))) | \ + ((DITHER_RGBA_222_LUT_B(0)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB222_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_222_LUT_R(0))) | \ + ((DITHER_RGBA_222_LUT_G(0))) | \ + ((DITHER_RGBA_222_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(1))) | \ + ((DITHER_RGBA_222_LUT_G(1))) | \ + ((DITHER_RGBA_222_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(2))) | \ + ((DITHER_RGBA_222_LUT_G(2))) | \ + ((DITHER_RGBA_222_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(3))) | \ + ((DITHER_RGBA_222_LUT_G(3))) | \ + ((DITHER_RGBA_222_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB222_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_222_LUT_R(0))) | \ + ((DITHER_RGBA_222_LUT_G(0))) | \ + ((DITHER_RGBA_222_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(1))) | \ + ((DITHER_RGBA_222_LUT_G(1))) | \ + ((DITHER_RGBA_222_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB221 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB221 conversion */ +#define RGB221_BSHIFT >> 7 +#define RGB221_GSHIFT >> 13 +#define RGB221_RSHIFT >> 19 +#define RGB221_BMASK & 0x01 +#define RGB221_GMASK & 0x06 +#define RGB221_RMASK & 0x18 + +#define WRITE1_RGBA_RGB221(src, dest) \ +*dest = _dither_color_lut[((*src RGB221_BSHIFT) RGB221_BMASK) | \ + ((*src RGB221_GSHIFT) RGB221_GMASK) | \ + ((*src RGB221_RSHIFT) RGB221_RMASK)]; dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_RGB221(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[1] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[1] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[1] RGB221_RSHIFT) RGB221_RMASK)]) | \ + (_dither_color_lut[((src[0] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[0] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[0] RGB221_RSHIFT) RGB221_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB221(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[3] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[3] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[3] RGB221_RSHIFT) RGB221_RMASK)]) | \ + (_dither_color_lut[((src[2] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[2] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[2] RGB221_RSHIFT) RGB221_RMASK)] << 8) | \ + (_dither_color_lut[((src[1] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[1] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[1] RGB221_RSHIFT) RGB221_RMASK)] << 16) | \ + (_dither_color_lut[((src[0] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[0] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[0] RGB221_RSHIFT) RGB221_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB221(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[0] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[0] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[0] RGB221_RSHIFT) RGB221_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[1] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[1] RGB221_RSHIFT) RGB221_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB221(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[0] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[0] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[0] RGB221_RSHIFT) RGB221_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[1] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[1] RGB221_RSHIFT) RGB221_RMASK)] << 8) | \ + (_dither_color_lut[((src[2] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[2] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[2] RGB221_RSHIFT) RGB221_RMASK)] << 16) | \ + (_dither_color_lut[((src[3] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[3] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[3] RGB221_RSHIFT) RGB221_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB221 conversion */ +#define DITHER_RGBA_221_LUT_R(num) \ +(_dither_r8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 16) & 0xff)]) +#define DITHER_RGBA_221_LUT_G(num) \ +(_dither_g8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 8) & 0xff)]) +#define DITHER_RGBA_221_LUT_B(num) \ +(_dither_b8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 0) & 0xff)]) + +#define WRITE1_RGBA_RGB221_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_221_LUT_R(0)) | \ + (DITHER_RGBA_221_LUT_G(0)) | \ + (DITHER_RGBA_221_LUT_B(0))]; dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE4_RGBA_RGB221_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_221_LUT_R(3))) | \ + ((DITHER_RGBA_221_LUT_G(3))) | \ + ((DITHER_RGBA_221_LUT_B(3)))]) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(2))) | \ + ((DITHER_RGBA_221_LUT_G(2))) | \ + ((DITHER_RGBA_221_LUT_B(2)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(1))) | \ + ((DITHER_RGBA_221_LUT_G(1))) | \ + ((DITHER_RGBA_221_LUT_B(1)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(0))) | \ + ((DITHER_RGBA_221_LUT_G(0))) | \ + ((DITHER_RGBA_221_LUT_B(0)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB221_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_221_LUT_R(1))) | \ + ((DITHER_RGBA_221_LUT_G(1))) | \ + ((DITHER_RGBA_221_LUT_B(1)))]) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(0))) | \ + ((DITHER_RGBA_221_LUT_G(0))) | \ + ((DITHER_RGBA_221_LUT_B(0)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB221_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_221_LUT_R(0))) | \ + ((DITHER_RGBA_221_LUT_G(0))) | \ + ((DITHER_RGBA_221_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(1))) | \ + ((DITHER_RGBA_221_LUT_G(1))) | \ + ((DITHER_RGBA_221_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(2))) | \ + ((DITHER_RGBA_221_LUT_G(2))) | \ + ((DITHER_RGBA_221_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(3))) | \ + ((DITHER_RGBA_221_LUT_G(3))) | \ + ((DITHER_RGBA_221_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB221_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_221_LUT_R(0))) | \ + ((DITHER_RGBA_221_LUT_G(0))) | \ + ((DITHER_RGBA_221_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(1))) | \ + ((DITHER_RGBA_221_LUT_G(1))) | \ + ((DITHER_RGBA_221_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB121 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB121 conversion */ +#define RGB121_BSHIFT >> 7 +#define RGB121_GSHIFT >> 13 +#define RGB121_RSHIFT >> 20 +#define RGB121_BMASK & 0x01 +#define RGB121_GMASK & 0x06 +#define RGB121_RMASK & 0x08 + +#define WRITE1_RGBA_RGB121(src, dest) \ +*dest = _dither_color_lut[((*src RGB121_BSHIFT) RGB121_BMASK) | \ + ((*src RGB121_GSHIFT) RGB121_GMASK) | \ + ((*src RGB121_RSHIFT) RGB121_RMASK)]; dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_RGB121(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[1] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[1] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[1] RGB121_RSHIFT) RGB121_RMASK)]) | \ + (_dither_color_lut[((src[0] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[0] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[0] RGB121_RSHIFT) RGB121_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB121(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[3] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[3] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[3] RGB121_RSHIFT) RGB121_RMASK)]) | \ + (_dither_color_lut[((src[2] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[2] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[2] RGB121_RSHIFT) RGB121_RMASK)] << 8) | \ + (_dither_color_lut[((src[1] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[1] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[1] RGB121_RSHIFT) RGB121_RMASK)] << 16) | \ + (_dither_color_lut[((src[0] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[0] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[0] RGB121_RSHIFT) RGB121_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB121(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[0] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[0] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[0] RGB121_RSHIFT) RGB121_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[1] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[1] RGB121_RSHIFT) RGB121_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB121(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[0] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[0] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[0] RGB121_RSHIFT) RGB121_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[1] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[1] RGB121_RSHIFT) RGB121_RMASK)] << 8) | \ + (_dither_color_lut[((src[2] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[2] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[2] RGB121_RSHIFT) RGB121_RMASK)] << 16) | \ + (_dither_color_lut[((src[3] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[3] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[3] RGB121_RSHIFT) RGB121_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB121 conversion */ +#define DITHER_RGBA_121_LUT_R(num) \ +(_dither_r8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 16) & 0xff)]) +#define DITHER_RGBA_121_LUT_G(num) \ +(_dither_g8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 8) & 0xff)]) +#define DITHER_RGBA_121_LUT_B(num) \ +(_dither_b8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 0) & 0xff)]) + +#define WRITE1_RGBA_RGB121_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_121_LUT_R(0)) | \ + (DITHER_RGBA_121_LUT_G(0)) | \ + (DITHER_RGBA_121_LUT_B(0))]; dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE4_RGBA_RGB121_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_121_LUT_R(3))) | \ + ((DITHER_RGBA_121_LUT_G(3))) | \ + ((DITHER_RGBA_121_LUT_B(3)))]) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(2))) | \ + ((DITHER_RGBA_121_LUT_G(2))) | \ + ((DITHER_RGBA_121_LUT_B(2)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(1))) | \ + ((DITHER_RGBA_121_LUT_G(1))) | \ + ((DITHER_RGBA_121_LUT_B(1)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(0))) | \ + ((DITHER_RGBA_121_LUT_G(0))) | \ + ((DITHER_RGBA_121_LUT_B(0)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB121_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_121_LUT_R(1))) | \ + ((DITHER_RGBA_121_LUT_G(1))) | \ + ((DITHER_RGBA_121_LUT_B(1)))]) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(0))) | \ + ((DITHER_RGBA_121_LUT_G(0))) | \ + ((DITHER_RGBA_121_LUT_B(0)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB121_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_121_LUT_R(0))) | \ + ((DITHER_RGBA_121_LUT_G(0))) | \ + ((DITHER_RGBA_121_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(1))) | \ + ((DITHER_RGBA_121_LUT_G(1))) | \ + ((DITHER_RGBA_121_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(2))) | \ + ((DITHER_RGBA_121_LUT_G(2))) | \ + ((DITHER_RGBA_121_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(3))) | \ + ((DITHER_RGBA_121_LUT_G(3))) | \ + ((DITHER_RGBA_121_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB121_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_121_LUT_R(0))) | \ + ((DITHER_RGBA_121_LUT_G(0))) | \ + ((DITHER_RGBA_121_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(1))) | \ + ((DITHER_RGBA_121_LUT_G(1))) | \ + ((DITHER_RGBA_121_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB111 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB111 conversion */ +#define RGB111_BSHIFT >> 7 +#define RGB111_GSHIFT >> 14 +#define RGB111_RSHIFT >> 21 +#define RGB111_BMASK & 0x01 +#define RGB111_GMASK & 0x02 +#define RGB111_RMASK & 0x04 + +#define WRITE1_RGBA_RGB111(src, dest) \ +*dest = _dither_color_lut[((*src RGB111_BSHIFT) RGB111_BMASK) | \ + ((*src RGB111_GSHIFT) RGB111_GMASK) | \ + ((*src RGB111_RSHIFT) RGB111_RMASK)]; dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE2_RGBA_RGB111(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[1] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[1] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[1] RGB111_RSHIFT) RGB111_RMASK)]) | \ + (_dither_color_lut[((src[0] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[0] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[0] RGB111_RSHIFT) RGB111_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB111(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[3] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[3] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[3] RGB111_RSHIFT) RGB111_RMASK)]) | \ + (_dither_color_lut[((src[2] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[2] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[2] RGB111_RSHIFT) RGB111_RMASK)] << 8) | \ + (_dither_color_lut[((src[1] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[1] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[1] RGB111_RSHIFT) RGB111_RMASK)] << 16) | \ + (_dither_color_lut[((src[0] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[0] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[0] RGB111_RSHIFT) RGB111_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB111(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[0] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[0] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[0] RGB111_RSHIFT) RGB111_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[1] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[1] RGB111_RSHIFT) RGB111_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB111(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[0] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[0] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[0] RGB111_RSHIFT) RGB111_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[1] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[1] RGB111_RSHIFT) RGB111_RMASK)] << 8) | \ + (_dither_color_lut[((src[2] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[2] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[2] RGB111_RSHIFT) RGB111_RMASK)] << 16) | \ + (_dither_color_lut[((src[3] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[3] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[3] RGB111_RSHIFT) RGB111_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB111 conversion */ +#define DITHER_RGBA_111_LUT_R(num) \ +(_dither_r8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 16) & 0xff)]) +#define DITHER_RGBA_111_LUT_G(num) \ +(_dither_g8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 8) & 0xff)]) +#define DITHER_RGBA_111_LUT_B(num) \ +(_dither_b8[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 0) & 0xff)]) + +#define WRITE1_RGBA_RGB111_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_111_LUT_R(0)) | \ + (DITHER_RGBA_111_LUT_G(0)) | \ + (DITHER_RGBA_111_LUT_B(0))]; dest++; src++ +#ifdef WORDS_BIGENDIAN +#define WRITE4_RGBA_RGB111_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_111_LUT_R(3))) | \ + ((DITHER_RGBA_111_LUT_G(3))) | \ + ((DITHER_RGBA_111_LUT_B(3)))]) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(2))) | \ + ((DITHER_RGBA_111_LUT_G(2))) | \ + ((DITHER_RGBA_111_LUT_B(2)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(1))) | \ + ((DITHER_RGBA_111_LUT_G(1))) | \ + ((DITHER_RGBA_111_LUT_B(1)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(0))) | \ + ((DITHER_RGBA_111_LUT_G(0))) | \ + ((DITHER_RGBA_111_LUT_B(0)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB111_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_111_LUT_R(1))) | \ + ((DITHER_RGBA_111_LUT_G(1))) | \ + ((DITHER_RGBA_111_LUT_B(1)))]) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(0))) | \ + ((DITHER_RGBA_111_LUT_G(0))) | \ + ((DITHER_RGBA_111_LUT_B(0)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB111_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_111_LUT_R(0))) | \ + ((DITHER_RGBA_111_LUT_G(0))) | \ + ((DITHER_RGBA_111_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(1))) | \ + ((DITHER_RGBA_111_LUT_G(1))) | \ + ((DITHER_RGBA_111_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(2))) | \ + ((DITHER_RGBA_111_LUT_G(2))) | \ + ((DITHER_RGBA_111_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(3))) | \ + ((DITHER_RGBA_111_LUT_G(3))) | \ + ((DITHER_RGBA_111_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB111_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_111_LUT_R(0))) | \ + ((DITHER_RGBA_111_LUT_G(0))) | \ + ((DITHER_RGBA_111_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(1))) | \ + ((DITHER_RGBA_111_LUT_G(1))) | \ + ((DITHER_RGBA_111_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB1 (mono B&W) */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB1 conversion */ + +#define WRITE1_RGBA_RGB1(src, dest) \ +*dest = _dither_color_lut[((((*src >> 0) & 0xff) + \ + ((*src >> 8) & 0xff) + \ + ((*src >> 16) & 0xff)) / 3) >> 7]; dest++; src++ +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB1 conversion */ +#define DITHER_RGBA_1_LUT(num) \ +(_dither_r8[(((x + num) & 0x7) << DM_BS1) | \ + ((y & 0x7) << DM_BS2) | \ + ((((*src >> 0) & 0xff) + \ + ((*src >> 8) & 0xff) + \ + ((*src >> 16) & 0xff)) / 3)]) + +#define WRITE1_RGBA_RGB1_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_1_LUT(0))]; dest++; src++ + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> A1 (mono B&W - alpha mas) */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> A1 conversion */ + +#ifdef WORDS_BIGENDIAN +# define WRITE1_RGBA_A1(src, dest) \ +*dest |= ((*src & 0x80000000) >> (24 + (x & 0x7))); \ +if ((x & 0x7) == 0x7) dest++; \ +src++ +#else +# define WRITE1_RGBA_A1(src, dest) \ +*dest |= ((*src & 0x80000000) >> (31 - (x & 0x7))); \ +if ((x & 0x7) == 0x7) dest++; \ +src++ +#endif + +/*****************************************************************************/ +/* MACROS for dithered RGBA -> A1 conversion */ +# define DITHER_RGBA_A1_LUT(num) \ +(_dither_a1[(((x + num) & 0x7) << DM_BS1) | ((y & 0x7) << DM_BS2) | ((src[num] >> 24))]) +#ifdef WORDS_BIGENDIAN +#define WRITE1_RGBA_A1_DITHER(src, dest) \ +*dest |= (DITHER_RGBA_A1_LUT(0)) << (7 - (x & 0x7)); \ +if ((x & 0x7) == 0x7) dest++; \ +src++; +#else +#define WRITE1_RGBA_A1_DITHER(src, dest) \ +*dest |= (DITHER_RGBA_A1_LUT(0)) << (0 + (x & 0x7)); \ +if ((x & 0x7) == 0x7) dest++; \ +src++; +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB8888 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB8888 conversion */ +#define WRITE1_RGBA_RGB8888(src, dest) \ +*dest = *src; dest++; src++; +# define WRITE1_RGBA_BGR8888(src, dest) \ +*dest = (((*src) >> 16) & 0x0000ff) | \ + (((*src) ) & 0x00ff00) | \ + (((*src) << 16) & 0xff0000); dest++; src++; + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB888 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB888 conversion */ +#define WRITE1_RGBA_RGB888(src, dest) \ +*dest = ((*src >> 0) & 0xff); dest++; \ +*dest = ((*src >> 8) & 0xff); dest++; \ +*dest = ((*src >> 16) & 0xff); dest++; src++; +#define WRITE1_RGBA_BGR888(src, dest) \ +*dest = ((*src >> 16) & 0xff); dest++; \ +*dest = ((*src >> 8) & 0xff); dest++; \ +*dest = ((*src >> 0) & 0xff); dest++; src++; + +void +__imlib_RGBASetupContext(Context * ct) +{ + _dither_color_lut = ct->palette; + _pal_type = ct->palette_type; + + if ((ct->depth == 16) || (ct->depth == 15)) + { + _dither_r16 = (DATA16 *) ct->r_dither; + _dither_g16 = (DATA16 *) ct->g_dither; + _dither_b16 = (DATA16 *) ct->b_dither; + } + else if (ct->depth <= 8) + { + switch (_pal_type) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 7: + _dither_r8 = (DATA8 *) ct->r_dither; + _dither_g8 = (DATA8 *) ct->g_dither; + _dither_b8 = (DATA8 *) ct->b_dither; + break; + case 6: + _dither_r8 = (DATA8 *) ct->r_dither; + break; + default: + break; + } + } + _dither_r8 = (DATA8 *) ct->r_dither; +} + +/* Palette mode stuff */ + +void +__imlib_RGBA_init(void *rd, void *gd, void *bd, int depth, DATA8 palette_type) +{ + DATA16 *rd16, *gd16, *bd16; + DATA8 *rd8, *gd8, *bd8; + int i, x, y; + + if (!dither_a_init) + { + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + for (i = 0; i < 256; i++) + { + int pi; + + pi = (i * (256 - 128)) / 255; + if ((_dither_88[x][y] < ((pi & 0x7f) >> 1)) + && (pi < (256 - 128))) + _dither_a1[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 128) >> 7) & 0x01); + else + _dither_a1[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 7) & 0x01); + } + } + } + dither_a_init = 1; + } + if (!rd || !gd || !bd) + return; + switch (depth) + { + case 16: + rd16 = (DATA16 *) rd; + gd16 = (DATA16 *) gd; + bd16 = (DATA16 *) bd; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 4; x++) + { + for (i = 0; i < 256; i++) + { + if ((_dither_44[x][y] < (i & 0x7)) && (i < (256 - 8))) + rd16[(x << 10) | (y << 8) | i] = + ((i + 8) & 0xf8) << 8; + else + rd16[(x << 10) | (y << 8) | i] = (i & 0xf8) << 8; + + if ((_dither_44[x][y] < ((i & 0x3) << 1)) + && (i < (256 - 4))) + gd16[(x << 10) | (y << 8) | i] = + (((i + 4) & 0xfc) << 8) >> 5; + else + gd16[(x << 10) | (y << 8) | i] = + ((i & 0xfc) << 8) >> 5; + + if ((_dither_44[x][y] < (i & 0x7)) && (i < (256 - 8))) + bd16[(x << 10) | (y << 8) | i] = + (((i + 8) & 0xf8) << 16) >> 19; + else + bd16[(x << 10) | (y << 8) | i] = + ((i & 0xf8) << 16) >> 19; + } + } + } + break; + case 15: + rd16 = (DATA16 *) rd; + gd16 = (DATA16 *) gd; + bd16 = (DATA16 *) bd; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 4; x++) + { + for (i = 0; i < 256; i++) + { + if ((_dither_44[x][y] < (i & 0x7)) && (i < (256 - 8))) + rd16[(x << 10) | (y << 8) | i] = + (((i + 8) & 0xf8) << 8) >> 1; + else + rd16[(x << 10) | (y << 8) | i] = + ((i & 0xf8) << 8) >> 1; + + if ((_dither_44[x][y] < (i & 0x7)) && (i < (256 - 8))) + gd16[(x << 10) | (y << 8) | i] = + (((i + 8) & 0xf8) << 8) >> 6; + else + gd16[(x << 10) | (y << 8) | i] = + ((i & 0xf8) << 8) >> 6; + + if ((_dither_44[x][y] < (i & 0x7)) && (i < (256 - 8))) + bd16[(x << 10) | (y << 8) | i] = + (((i + 8) & 0xf8) << 16) >> 19; + else + bd16[(x << 10) | (y << 8) | i] = + ((i & 0xf8) << 16) >> 19; + } + } + } + break; + default: + rd8 = (DATA8 *) rd; + gd8 = (DATA8 *) gd; + bd8 = (DATA8 *) bd; + switch (palette_type) + { + case 0: + for (y = 0; y < DM_Y; y++) + { + for (x = 0; x < DM_X; x++) + { + for (i = 0; i < 256; i++) + { + int pi; + + pi = (i * (256 - 32)) / 255; + if ((_dither_88[x][y] < ((pi & 0x1f) << 1)) + && (pi < (256 - 32))) + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi + 32) & 0xe0); + else + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (pi & 0xe0); + + pi = (i * (256 - 32)) / 255; + if ((_dither_88[x][y] < ((pi & 0x1f) << 1)) + && (pi < (256 - 32))) + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 32) >> 3) & 0x1c); + else + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 3) & 0x1c); + + pi = (i * (256 - 64)) / 255; + if ((_dither_88[x][y] < (pi & 0x3f)) + && (pi < (256 - 64))) + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 64) >> 6) & 0x03); + else + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 6) & 0x03); + } + } + } + break; + case 7: /* 666 8 bit 216 color rgb cube */ + if (!_dither_666r) + { + _dither_666r = malloc(256 * sizeof(DATA8)); + _dither_666g = malloc(256 * sizeof(DATA8)); + _dither_666b = malloc(256 * sizeof(DATA8)); + } + for (y = 0; y < 256; y++) + { + _dither_666r[y] = (DATA8) (((y * 6) >> 8) * 6 * 6); + _dither_666g[y] = (DATA8) (((y * 6) >> 8) * 6); + _dither_666b[y] = (DATA8) (((y * 6) >> 8)); + } + for (y = 0; y < DM_Y; y++) + { + for (x = 0; x < DM_X; x++) + { + for (i = 0; i < 256; i++) + { + double pi; + + pi = 64.0 * + (((double)i - + (_dither_666b[i] * (256.0 / 6.0))) / + (256.0 / 6.0)); + if ((_dither_88[x][y] < (DATA8) pi) + && ((double)i < (256 - (256.0 / 6.0)))) + { + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (_dither_666b[i] + 1) * 6 * 6; + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (_dither_666b[i] + 1) * 6; + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (_dither_666b[i] + 1); + } + else + { + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (_dither_666b[i]) * 6 * 6; + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (_dither_666b[i]) * 6; + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (_dither_666b[i]); + } + } + } + } + break; + case 1: + for (y = 0; y < DM_Y; y++) + { + for (x = 0; x < DM_X; x++) + { + for (i = 0; i < 256; i++) + { + int pi; + + pi = (i * (256 - 64)) / 255; + if ((_dither_88[x][y] < (pi & 0x3f)) + && (pi < (256 - 64))) + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 64) >> 1) & 0x60); + else + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 1) & 0x60); + + pi = (i * (256 - 32)) / 255; + if ((_dither_88[x][y] < ((pi & 0x1f) << 1)) + && (pi < (256 - 32))) + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 32) >> 3) & 0x1c); + else + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 3) & 0x1c); + + pi = (i * (256 - 64)) / 255; + if ((_dither_88[x][y] < (pi & 0x3f)) + && (pi < (256 - 64))) + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 64) >> 6) & 0x03); + else + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 6) & 0x03); + } + } + } + break; + case 2: + for (y = 0; y < DM_Y; y++) + { + for (x = 0; x < DM_X; x++) + { + for (i = 0; i < 256; i++) + { + int pi; + + pi = (i * (256 - 64)) / 255; + if ((_dither_88[x][y] < (pi & 0x3f)) + && (pi < (256 - 64))) + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 64) >> 2) & 0x30); + else + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 2) & 0x30); + + pi = (i * (256 - 64)) / 255; + if ((_dither_88[x][y] < (pi & 0x3f)) + && (pi < (256 - 64))) + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 64) >> 4) & 0x0c); + else + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 4) & 0x0c); + + pi = (i * (256 - 64)) / 255; + if ((_dither_88[x][y] < (pi & 0x3f)) + && (pi < (256 - 64))) + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 64) >> 6) & 0x03); + else + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 6) & 0x03); + } + } + } + break; + case 3: + for (y = 0; y < DM_Y; y++) + { + for (x = 0; x < DM_X; x++) + { + for (i = 0; i < 256; i++) + { + int pi; + + pi = (i * (256 - 64)) / 255; + if ((_dither_88[x][y] < (pi & 0x3f)) + && (pi < (256 - 64))) + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 64) >> 3) & 0x18); + else + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 3) & 0x18); + + pi = (i * (256 - 64)) / 255; + if ((_dither_88[x][y] < (pi & 0x3f)) + && (pi < (256 - 64))) + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 64) >> 5) & 0x06); + else + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 5) & 0x06); + + pi = (i * (256 - 128)) / 255; + if ((_dither_88[x][y] < ((pi & 0x7f) >> 1)) + && (pi < (256 - 128))) + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 128) >> 7) & 0x01); + else + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 7) & 0x01); + } + } + } + break; + case 4: + for (y = 0; y < DM_Y; y++) + { + for (x = 0; x < DM_X; x++) + { + for (i = 0; i < 256; i++) + { + int pi; + + pi = (i * (256 - 128)) / 255; + if ((_dither_88[x][y] < ((pi & 0x7f) >> 1)) + && (pi < (256 - 128))) + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 128) >> 4) & 0x08); + else + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 4) & 0x08); + + pi = (i * (256 - 64)) / 255; + if ((_dither_88[x][y] < (pi & 0x3f)) + && (pi < (256 - 64))) + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 64) >> 5) & 0x06); + else + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 5) & 0x06); + + pi = (i * (256 - 128)) / 255; + if ((_dither_88[x][y] < ((pi & 0x7f) >> 1)) + && (pi < (256 - 128))) + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 128) >> 7) & 0x01); + else + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 7) & 0x01); + } + } + } + break; + case 5: + for (y = 0; y < DM_Y; y++) + { + for (x = 0; x < DM_X; x++) + { + for (i = 0; i < 256; i++) + { + int pi; + + pi = (i * (256 - 128)) / 255; + if ((_dither_88[x][y] < ((pi & 0x7f) >> 1)) + && (pi < (256 - 128))) + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 128) >> 5) & 0x04); + else + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 5) & 0x04); + + pi = (i * (256 - 128)) / 255; + if ((_dither_88[x][y] < ((pi & 0x7f) >> 1)) + && (pi < (256 - 128))) + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 128) >> 6) & 0x02); + else + gd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 6) & 0x02); + + pi = (i * (256 - 128)) / 255; + if ((_dither_88[x][y] < ((pi & 0x7f) >> 1)) + && (pi < (256 - 128))) + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 128) >> 7) & 0x01); + else + bd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 7) & 0x01); + } + } + } + break; + case 6: + for (y = 0; y < DM_Y; y++) + { + for (x = 0; x < DM_X; x++) + { + for (i = 0; i < 256; i++) + { + int pi; + + pi = (i * (256 - 128)) / 255; + if ((_dither_88[x][y] < ((pi & 0x7f) >> 1)) + && (pi < (256 - 128))) + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + (((pi + 128) >> 7) & 0x01); + else + rd8[(x << DM_BS1) | (y << DM_BS2) | i] = + ((pi >> 7) & 0x01); + } + } + } + break; + default: + break; + } + break; + } +} + +static void +__imlib_RGBA_to_RGB565_fast(DATA32 * src, int src_jump, + DATA8 * dst, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + DATA16 *dest = (DATA16 *) dst; + int dest_jump = (dow / sizeof(DATA16)) - width; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_2(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 2) + WRITE2_RGBA_RGB565(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 2) + WRITE2_RGBA_RGB565(src, dest); + WRITE1_RGBA_RGB565(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + else + { + if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = 0; y < h; y++) + { + WRITE1_RGBA_RGB565(src, dest); + for (x = 0; x < w; x += 2) + WRITE2_RGBA_RGB565(src, dest); + WRITE1_RGBA_RGB565(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + WRITE1_RGBA_RGB565(src, dest); + for (x = 0; x < w; x += 2) + WRITE2_RGBA_RGB565(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB565_dither(DATA32 * src, int src_jump, + DATA8 * dst, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + DATA16 *dest = (DATA16 *) dst; + int dest_jump = (dow / sizeof(DATA16)) - width; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_2(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 2) + WRITE2_RGBA_RGB565_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 2) + WRITE2_RGBA_RGB565_DITHER(src, dest); + WRITE1_RGBA_RGB565_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + else + { + if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = dy; y < h; y++) + { + x = dx - 1; + WRITE1_RGBA_RGB565_DITHER(src, dest); + for (x = dx; x < w; x += 2) + WRITE2_RGBA_RGB565_DITHER(src, dest); + WRITE1_RGBA_RGB565_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + x = dx - 1; + WRITE1_RGBA_RGB565_DITHER(src, dest); + for (x = dx; x < w; x += 2) + WRITE2_RGBA_RGB565_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_BGR565_fast(DATA32 * src, int src_jump, + DATA8 * dst, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + DATA16 *dest = (DATA16 *) dst; + int dest_jump = (dow / sizeof(DATA16)) - width; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_2(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 2) + WRITE2_RGBA_BGR565(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 2) + WRITE2_RGBA_BGR565(src, dest); + WRITE1_RGBA_BGR565(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + else + { + if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = 0; y < h; y++) + { + WRITE1_RGBA_BGR565(src, dest); + for (x = 0; x < w; x += 2) + WRITE2_RGBA_BGR565(src, dest); + WRITE1_RGBA_BGR565(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + WRITE1_RGBA_BGR565(src, dest); + for (x = 0; x < w; x += 2) + WRITE2_RGBA_BGR565(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_BGR565_dither(DATA32 * src, int src_jump, + DATA8 * dst, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + DATA16 *dest = (DATA16 *) dst; + int dest_jump = (dow / sizeof(DATA16)) - width; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_2(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 2) + WRITE2_RGBA_BGR565_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 2) + WRITE2_RGBA_BGR565_DITHER(src, dest); + WRITE1_RGBA_BGR565_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + else + { + if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = dy; y < h; y++) + { + x = dx - 1; + WRITE1_RGBA_BGR565_DITHER(src, dest); + for (x = dx; x < w; x += 2) + WRITE2_RGBA_BGR565_DITHER(src, dest); + WRITE1_RGBA_BGR565_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + x = dx - 1; + WRITE1_RGBA_BGR565_DITHER(src, dest); + for (x = dx; x < w; x += 2) + WRITE2_RGBA_BGR565_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB555_fast(DATA32 * src, int src_jump, + DATA8 * dst, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + DATA16 *dest = (DATA16 *) dst; + int dest_jump = (dow / sizeof(DATA16)) - width; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_2(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 2) + WRITE2_RGBA_RGB555(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 2) + WRITE2_RGBA_RGB555(src, dest); + WRITE1_RGBA_RGB555(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + else + { + if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = 0; y < h; y++) + { + WRITE1_RGBA_RGB555(src, dest); + for (x = 0; x < w; x += 2) + WRITE2_RGBA_RGB555(src, dest); + WRITE1_RGBA_RGB555(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + WRITE1_RGBA_RGB555(src, dest); + for (x = 0; x < w; x += 2) + WRITE2_RGBA_RGB555(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB555_dither(DATA32 * src, int src_jump, + DATA8 * dst, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + DATA16 *dest = (DATA16 *) dst; + int dest_jump = (dow / sizeof(DATA16)) - width; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_2(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 2) + WRITE2_RGBA_RGB555_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 2) + WRITE2_RGBA_RGB555_DITHER(src, dest); + WRITE1_RGBA_RGB555_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + else + { + if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = dy; y < h; y++) + { + x = dx - 1; + WRITE1_RGBA_RGB555_DITHER(src, dest); + for (x = dx; x < w; x += 2) + WRITE2_RGBA_RGB555_DITHER(src, dest); + WRITE1_RGBA_RGB555_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = dy; y < h; y++) + { + x = dx - 1; + WRITE1_RGBA_RGB555_DITHER(src, dest); + for (x = dx; x < w; x += 2) + WRITE2_RGBA_RGB555_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_BGR555_fast(DATA32 * src, int src_jump, + DATA8 * dst, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + DATA16 *dest = (DATA16 *) dst; + int dest_jump = (dow / sizeof(DATA16)) - width; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_2(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 2) + WRITE2_RGBA_BGR555(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 2) + WRITE2_RGBA_BGR555(src, dest); + WRITE1_RGBA_BGR555(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + else + { + if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = 0; y < h; y++) + { + WRITE1_RGBA_BGR555(src, dest); + for (x = 0; x < w; x += 2) + WRITE2_RGBA_BGR555(src, dest); + WRITE1_RGBA_BGR555(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + WRITE1_RGBA_BGR555(src, dest); + for (x = 0; x < w; x += 2) + WRITE2_RGBA_BGR555(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_BGR555_dither(DATA32 * src, int src_jump, + DATA8 * dst, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + DATA16 *dest = (DATA16 *) dst; + int dest_jump = (dow / sizeof(DATA16)) - width; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_2(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 2) + WRITE2_RGBA_BGR555_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 2) + WRITE2_RGBA_BGR555_DITHER(src, dest); + WRITE1_RGBA_BGR555_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + else + { + if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = dy; y < h; y++) + { + x = dx - 1; + WRITE1_RGBA_BGR555_DITHER(src, dest); + for (x = dx; x < w; x += 2) + WRITE2_RGBA_BGR555_DITHER(src, dest); + WRITE1_RGBA_BGR555_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = dy; y < h; y++) + { + x = dx - 1; + WRITE1_RGBA_BGR555_DITHER(src, dest); + for (x = dx; x < w; x += 2) + WRITE2_RGBA_BGR555_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB332_fast(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB332(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB332(src, dest); + WRITE2_RGBA_RGB332(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB332(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB332(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB332(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x += 4) + WRITE4_RGBA_RGB332(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB332(src, dest); + WRITE2_RGBA_RGB332(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB332(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB332(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB332_dither(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB332_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB332_DITHER(src, dest); + WRITE2_RGBA_RGB332_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB332_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB332_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB332_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x += 4) + WRITE4_RGBA_RGB332_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB332_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB666_fast(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB666(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB666(src, dest); + WRITE2_RGBA_RGB666(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB666(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB666(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB666(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x += 4) + WRITE4_RGBA_RGB666(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB666(src, dest); + WRITE2_RGBA_RGB666(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB666(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB666(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB666_dither(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB666_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB666_DITHER(src, dest); + WRITE2_RGBA_RGB666_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB666_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB666_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB666_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x += 4) + WRITE4_RGBA_RGB666_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB666_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB232_fast(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB232(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB232(src, dest); + WRITE2_RGBA_RGB232(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB232(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB232(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB232(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x += 4) + WRITE4_RGBA_RGB232(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB232(src, dest); + WRITE2_RGBA_RGB232(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB232(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB232(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB232_dither(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB232_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB232_DITHER(src, dest); + WRITE2_RGBA_RGB232_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB232_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB232_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB232_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x += 4) + WRITE4_RGBA_RGB232_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB232_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB222_fast(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB222(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB222(src, dest); + WRITE2_RGBA_RGB222(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB222(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB222(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB222(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x += 4) + WRITE4_RGBA_RGB222(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB222(src, dest); + WRITE2_RGBA_RGB222(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB222(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB222(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB222_dither(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB222_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB222_DITHER(src, dest); + WRITE2_RGBA_RGB222_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB222_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB222_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB222_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x += 4) + WRITE4_RGBA_RGB222_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB222_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB221_fast(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB221(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB221(src, dest); + WRITE2_RGBA_RGB221(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB221(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB221(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB221(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x += 4) + WRITE4_RGBA_RGB221(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB221(src, dest); + WRITE2_RGBA_RGB221(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB221(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB221(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB221_dither(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB221_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB221_DITHER(src, dest); + WRITE2_RGBA_RGB221_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB221_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB221_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB221_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x += 4) + WRITE4_RGBA_RGB221_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB221_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB121_fast(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB121(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB121(src, dest); + WRITE2_RGBA_RGB121(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB121(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB121(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB121(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x += 4) + WRITE4_RGBA_RGB121(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB121(src, dest); + WRITE2_RGBA_RGB121(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB121(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB121(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB121_dither(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB121_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB121_DITHER(src, dest); + WRITE2_RGBA_RGB121_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB121_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB121_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB121_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x += 4) + WRITE4_RGBA_RGB121_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB121_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB111_fast(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB111(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB111(src, dest); + WRITE2_RGBA_RGB111(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x += 4) + WRITE4_RGBA_RGB111(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB111(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB111(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x += 4) + WRITE4_RGBA_RGB111(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB111(src, dest); + WRITE2_RGBA_RGB111(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x += 4) + WRITE4_RGBA_RGB111(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB111(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB111_dither(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB111_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w -= 2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB111_DITHER(src, dest); + WRITE2_RGBA_RGB111_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w -= 3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x += 4) + WRITE4_RGBA_RGB111_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB111_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB111_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x += 4) + WRITE4_RGBA_RGB111_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB111_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB1_fast(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width; + h = height; + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + WRITE1_RGBA_RGB1(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB1_dither(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - width; + + w = width + dx; + h = height + dy; + + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x++) + { + WRITE1_RGBA_RGB1_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_A1_fast(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - (width >> 3); + + w = width; + h = height; + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + WRITE1_RGBA_A1(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_A1_dither(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - (width >> 3); + + w = width + dx; + h = height + dy; + + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x++) + { + WRITE1_RGBA_A1_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB8888_fast(DATA32 * src, int src_jump, + DATA8 * dst, int dow, + int width, int height, int dx, int dy) +{ + int y, w, h; + DATA32 *dest = (DATA32 *) dst; + int dest_jump = (dow / sizeof(DATA32)) - width; + + w = width; + h = height; + + if ((src_jump > 0) || (dest_jump > 0)) + { + for (y = h; y > 0; y--) + { + memcpy(dest, src, w * sizeof(DATA32)); + src += src_jump + w; + dest += dest_jump + w; + } + } + else + memcpy(dest, src, h * w * sizeof(DATA32)); + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_BGR8888_fast(DATA32 * src, int src_jump, + DATA8 * dst, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + DATA32 *dest = (DATA32 *) dst; + int dest_jump = (dow / sizeof(DATA32)) - width; + + w = width; + h = height; + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + WRITE1_RGBA_BGR8888(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_RGB888_fast(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - (width * 3); + + w = width; + h = height; + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + WRITE1_RGBA_RGB888(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_BGR888_fast(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + int dest_jump = dow - (width * 3); + + w = width; + h = height; + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + WRITE1_RGBA_BGR888(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + +static void +__imlib_RGBA_to_Nothing(DATA32 * src, int src_jump, + DATA8 * dest, int dow, + int width, int height, int dx, int dy) +{ + /*\ Nothing: Dummy function \ */ +} + +ImlibRGBAFunction +__imlib_GetRGBAFunction(int depth, + unsigned long rm, unsigned long gm, unsigned long bm, + char hiq, DATA8 palette_type) +{ + if (depth == 16) + { + if (hiq) + { + if ((rm == 0xf800) && (gm == 0x7e0) && (bm == 0x1f)) + return __imlib_RGBA_to_RGB565_dither; + if ((rm == 0x7c00) && (gm == 0x3e0) && (bm == 0x1f)) + return __imlib_RGBA_to_RGB555_dither; + if ((bm == 0xf800) && (gm == 0x7e0) && (rm == 0x1f)) + return __imlib_RGBA_to_BGR565_dither; + if ((bm == 0x7c00) && (gm == 0x3e0) && (rm == 0x1f)) + return __imlib_RGBA_to_BGR555_dither; + } + else + { +#ifdef DO_MMX_ASM + if (__imlib_get_cpuid() && CPUID_MMX) + { + if ((rm == 0xf800) && (gm == 0x7e0) && (bm == 0x1f)) + return __imlib_mmx_rgb565_fast; + if ((rm == 0x7c00) && (gm == 0x3e0) && (bm == 0x1f)) + return __imlib_mmx_rgb555_fast; + if ((bm == 0xf800) && (gm == 0x7e0) && (rm == 0x1f)) + return __imlib_mmx_bgr565_fast; + if ((bm == 0x7c00) && (gm == 0x3e0) && (rm == 0x1f)) + return __imlib_mmx_bgr555_fast; + } + else +#endif + { + if ((rm == 0xf800) && (gm == 0x7e0) && (bm == 0x1f)) + return __imlib_RGBA_to_RGB565_fast; + if ((rm == 0x7c00) && (gm == 0x3e0) && (bm == 0x1f)) + return __imlib_RGBA_to_RGB555_fast; + if ((bm == 0xf800) && (gm == 0x7e0) && (rm == 0x1f)) + return __imlib_RGBA_to_BGR565_fast; + if ((bm == 0x7c00) && (gm == 0x3e0) && (rm == 0x1f)) + return __imlib_RGBA_to_BGR555_fast; + } + } + return NULL; + } + else if (depth == 32) + { + if ((rm == 0xff0000) && (gm == 0xff00) && (bm == 0xff)) + return __imlib_RGBA_to_RGB8888_fast; + return NULL; + } + else if (depth == 24) + { + if ((rm == 0xff0000) && (gm == 0xff00) && (bm == 0xff)) + return __imlib_RGBA_to_RGB888_fast; + return NULL; + } + else if (depth == 8) + { + if (hiq) + { + if (palette_type == 0) + return __imlib_RGBA_to_RGB332_dither; + if (palette_type == 1) + return __imlib_RGBA_to_RGB232_dither; + if (palette_type == 2) + return __imlib_RGBA_to_RGB222_dither; + if (palette_type == 3) + return __imlib_RGBA_to_RGB221_dither; + if (palette_type == 4) + return __imlib_RGBA_to_RGB121_dither; + if (palette_type == 5) + return __imlib_RGBA_to_RGB111_dither; + if (palette_type == 6) + return __imlib_RGBA_to_RGB1_dither; + if (palette_type == 7) + return __imlib_RGBA_to_RGB666_dither; + } + else + { + if (palette_type == 0) + return __imlib_RGBA_to_RGB332_fast; + if (palette_type == 1) + return __imlib_RGBA_to_RGB232_fast; + if (palette_type == 2) + return __imlib_RGBA_to_RGB222_fast; + if (palette_type == 3) + return __imlib_RGBA_to_RGB221_fast; + if (palette_type == 4) + return __imlib_RGBA_to_RGB121_fast; + if (palette_type == 5) + return __imlib_RGBA_to_RGB111_fast; + if (palette_type == 6) + return __imlib_RGBA_to_RGB1_fast; + if (palette_type == 7) + return __imlib_RGBA_to_RGB666_fast; + } + } + return NULL; +} + +ImlibRGBAFunction +__imlib_GetMaskFunction(char hiq) +{ + return hiq ? &__imlib_RGBA_to_A1_dither : &__imlib_RGBA_to_A1_fast; +} + +#endif diff --git a/src/lib/rgba.h b/src/lib/rgba.h new file mode 100644 index 0000000..93ae908 --- /dev/null +++ b/src/lib/rgba.h @@ -0,0 +1,33 @@ +#ifndef __RGBA +#define __RGBA 1 + +#ifdef BUILD_X11 + +#define DM_BS1 (8 + 3) +#define DM_BS2 (8) +#define DM_X (8) +#define DM_Y (8) + +void __imlib_RGBASetupContext(Context *ct); +void __imlib_RGBA_init(void *rd, void *gd, void *bd, int depth, + DATA8 palette_type); + +typedef void (*ImlibRGBAFunction)(DATA32*, int, DATA8*, + int, int, int, int, int); +ImlibRGBAFunction +__imlib_GetRGBAFunction(int depth, + unsigned long rm, unsigned long gm, unsigned long bm, + char hiq, DATA8 palette_type); +ImlibRGBAFunction +__imlib_GetMaskFunction(char hiq); + +#ifdef DO_MMX_ASM +void __imlib_mmx_rgb555_fast(DATA32*, int, DATA8*, int, int, int, int, int); +void __imlib_mmx_bgr555_fast(DATA32*, int, DATA8*, int, int, int, int, int); +void __imlib_mmx_rgb565_fast(DATA32*, int, DATA8*, int, int, int, int, int); +void __imlib_mmx_bgr565_fast(DATA32*, int, DATA8*, int, int, int, int, int); +#endif + +#endif + +#endif diff --git a/src/lib/rgbadraw.c b/src/lib/rgbadraw.c new file mode 100644 index 0000000..0653f5e --- /dev/null +++ b/src/lib/rgbadraw.c @@ -0,0 +1,624 @@ +#include "common.h" +#include +#include "colormod.h" +#include "image.h" +#include "scale.h" +#include "blend.h" +#include "updates.h" +#include "rgbadraw.h" + + +void +__imlib_FlipImageHoriz(ImlibImage * im) +{ + DATA32 *p1, *p2, tmp; + int x, y; + + for (y = 0; y < im->h; y++) + { + p1 = im->data + (y * im->w); + p2 = im->data + ((y + 1) * im->w) - 1; + for (x = 0; x < (im->w >> 1); x++) + { + tmp = *p1; + *p1 = *p2; + *p2 = tmp; + p1++; + p2--; + } + } + x = im->border.left; + im->border.left = im->border.right; + im->border.right = x; +} + +void +__imlib_FlipImageVert(ImlibImage * im) +{ + DATA32 *p1, *p2, tmp; + int x, y; + + for (y = 0; y < (im->h >> 1); y++) + { + p1 = im->data + (y * im->w); + p2 = im->data + ((im->h - 1 - y) * im->w); + for (x = 0; x < im->w; x++) + { + tmp = *p1; + *p1 = *p2; + *p2 = tmp; + p1++; + p2++; + } + } + x = im->border.top; + im->border.top = im->border.bottom; + im->border.bottom = x; +} + +void +__imlib_FlipImageBoth(ImlibImage * im) +{ + DATA32 *p1, *p2, tmp; + int x; + + p1 = im->data; + p2 = im->data + (im->h * im->w) - 1; + for (x = (im->w * im->h) / 2; --x >= 0;) + { + tmp = *p1; + *p1 = *p2; + *p2 = tmp; + p1++; + p2--; + } + x = im->border.top; + im->border.top = im->border.bottom; + im->border.bottom = x; + x = im->border.left; + im->border.left = im->border.right; + im->border.right = x; +} + +/*\ Directions (source is right/down): +|*| 0 = down/right (flip over ul-dr diagonal) +|*| 1 = down/left (rotate 90 degrees clockwise) +|*| 2 = up/right (rotate 90 degrees counterclockwise) +|*| 3 = up/left (flip over ur-ll diagonal) +\*/ +void +__imlib_FlipImageDiagonal(ImlibImage * im, int direction) +{ + DATA32 *data, *to, *from; + int x, y, w, hw, tmp; + + data = malloc(im->w * im->h * sizeof(DATA32)); + from = im->data; + w = im->h; + im->h = im->w; + im->w = w; + hw = w * im->h; + switch (direction) + { + default: + case 0: /*\ DOWN_RIGHT \ */ + tmp = im->border.top; + im->border.top = im->border.left; + im->border.left = tmp; + tmp = im->border.bottom; + im->border.bottom = im->border.right; + im->border.right = tmp; + to = data; + hw = -hw + 1; + break; + case 1: /*\ DOWN_LEFT \ */ + tmp = im->border.top; + im->border.top = im->border.left; + im->border.left = im->border.bottom; + im->border.bottom = im->border.right; + im->border.right = tmp; + to = data + w - 1; + hw = -hw - 1; + break; + case 2: /*\ UP_RIGHT \ */ + tmp = im->border.top; + im->border.top = im->border.right; + im->border.right = im->border.bottom; + im->border.bottom = im->border.left; + im->border.left = tmp; + to = data + hw - w; + w = -w; + hw = hw + 1; + break; + case 3: /*\ UP_LEFT \ */ + tmp = im->border.top; + im->border.top = im->border.right; + im->border.right = tmp; + tmp = im->border.bottom; + im->border.bottom = im->border.left; + im->border.left = tmp; + to = data + hw - 1; + w = -w; + hw = hw - 1; + break; + } + from = im->data; + for (x = im->w; --x >= 0;) + { + for (y = im->h; --y >= 0;) + { + *to = *from; + from++; + to += w; + } + to += hw; + } + free(im->data); + im->data = data; +} + +void +__imlib_BlurImage(ImlibImage * im, int rad) +{ + DATA32 *p1, *p2, *data; + int x, y, mx, my, mw, mh, mt, xx, yy; + int a, r, g, b; + int *as, *rs, *gs, *bs; + + if (rad < 1) + return; + data = malloc(im->w * im->h * sizeof(DATA32)); + as = malloc(sizeof(int) * im->w); + rs = malloc(sizeof(int) * im->w); + gs = malloc(sizeof(int) * im->w); + bs = malloc(sizeof(int) * im->w); + + for (y = 0; y < im->h; y++) + { + my = y - rad; + mh = (rad << 1) + 1; + if (my < 0) + { + mh += my; + my = 0; + } + if ((my + mh) > im->h) + mh = im->h - my; + + p1 = data + (y * im->w); + memset(as, 0, im->w * sizeof(int)); + memset(rs, 0, im->w * sizeof(int)); + memset(gs, 0, im->w * sizeof(int)); + memset(bs, 0, im->w * sizeof(int)); + + for (yy = 0; yy < mh; yy++) + { + p2 = im->data + ((yy + my) * im->w); + for (x = 0; x < im->w; x++) + { + as[x] += (*p2 >> 24) & 0xff; + rs[x] += (*p2 >> 16) & 0xff; + gs[x] += (*p2 >> 8) & 0xff; + bs[x] += *p2 & 0xff; + p2++; + } + } + if (im->w > ((rad << 1) + 1)) + { + for (x = 0; x < im->w; x++) + { + a = 0; + r = 0; + g = 0; + b = 0; + mx = x - rad; + mw = (rad << 1) + 1; + if (mx < 0) + { + mw += mx; + mx = 0; + } + if ((mx + mw) > im->w) + mw = im->w - mx; + mt = mw * mh; + for (xx = mx; xx < (mw + mx); xx++) + { + a += as[xx]; + r += rs[xx]; + g += gs[xx]; + b += bs[xx]; + } + a = a / mt; + r = r / mt; + g = g / mt; + b = b / mt; + *p1 = (a << 24) | (r << 16) | (g << 8) | b; + p1++; + } + } + else + { + } + } + free(as); + free(rs); + free(gs); + free(bs); + free(im->data); + im->data = data; +} + +void +__imlib_SharpenImage(ImlibImage * im, int rad) +{ + DATA32 *data, *p1, *p2; + int a, r, g, b, x, y; + + data = malloc(im->w * im->h * sizeof(DATA32)); + if (rad == 0) + return; + else + { + int mul, mul2, tot; + + mul = (rad * 4) + 1; + mul2 = rad; + tot = mul - (mul2 * 4); + for (y = 1; y < (im->h - 1); y++) + { + p1 = im->data + 1 + (y * im->w); + p2 = data + 1 + (y * im->w); + for (x = 1; x < (im->w - 1); x++) + { + b = (int)((p1[0]) & 0xff) * 5; + g = (int)((p1[0] >> 8) & 0xff) * 5; + r = (int)((p1[0] >> 16) & 0xff) * 5; + a = (int)((p1[0] >> 24) & 0xff) * 5; + b -= (int)((p1[-1]) & 0xff); + g -= (int)((p1[-1] >> 8) & 0xff); + r -= (int)((p1[-1] >> 16) & 0xff); + a -= (int)((p1[-1] >> 24) & 0xff); + b -= (int)((p1[1]) & 0xff); + g -= (int)((p1[1] >> 8) & 0xff); + r -= (int)((p1[1] >> 16) & 0xff); + a -= (int)((p1[1] >> 24) & 0xff); + b -= (int)((p1[-im->w]) & 0xff); + g -= (int)((p1[-im->w] >> 8) & 0xff); + r -= (int)((p1[-im->w] >> 16) & 0xff); + a -= (int)((p1[-im->w] >> 24) & 0xff); + b -= (int)((p1[im->w]) & 0xff); + g -= (int)((p1[im->w] >> 8) & 0xff); + r -= (int)((p1[im->w] >> 16) & 0xff); + a -= (int)((p1[im->w] >> 24) & 0xff); + + a = (a & ((~a) >> 16)); + a = ((a | ((a & 256) - ((a & 256) >> 8)))); + r = (r & ((~r) >> 16)); + r = ((r | ((r & 256) - ((r & 256) >> 8)))); + g = (g & ((~g) >> 16)); + g = ((g | ((g & 256) - ((g & 256) >> 8)))); + b = (b & ((~b) >> 16)); + b = ((b | ((b & 256) - ((b & 256) >> 8)))); + + *p2 = (a << 24) | (r << 16) | (g << 8) | b; + p2++; + p1++; + } + } + } + free(im->data); + im->data = data; +} + +void +__imlib_TileImageHoriz(ImlibImage * im) +{ + DATA32 *p1, *p2, *p3, *p, *data; + int x, y, per, tmp, na, nr, ng, nb, mix, a, r, g, b, aa, rr, + gg, bb; + + data = malloc(im->w * im->h * sizeof(DATA32)); + p1 = im->data; + p = data; + for (y = 0; y < im->h; y++) + { + p2 = p1 + (im->w >> 1); + p3 = p1; + per = (im->w >> 1); + for (x = 0; x < (im->w >> 1); x++) + { + mix = (x * 255) / per; + b = (*p1) & 0xff; + g = (*p1 >> 8) & 0xff; + r = (*p1 >> 16) & 0xff; + a = (*p1 >> 24) & 0xff; + + bb = (*p2) & 0xff; + gg = (*p2 >> 8) & 0xff; + rr = (*p2 >> 16) & 0xff; + aa = (*p2 >> 24) & 0xff; + + tmp = (r - rr) * mix; + nr = rr + ((tmp + (tmp >> 8) + 0x80) >> 8); + tmp = (g - gg) * mix; + ng = gg + ((tmp + (tmp >> 8) + 0x80) >> 8); + tmp = (b - bb) * mix; + nb = bb + ((tmp + (tmp >> 8) + 0x80) >> 8); + tmp = (a - aa) * mix; + na = aa + ((tmp + (tmp >> 8) + 0x80) >> 8); + *p = (na << 24) | (nr << 16) | (ng << 8) | nb; + p++; + p1++; + p2++; + } + p2 = p3; + per = (im->w - (im->w >> 1)); + for (; x < im->w; x++) + { + mix = ((im->w - 1 - x) * 255) / per; + b = (*p1) & 0xff; + g = (*p1 >> 8) & 0xff; + r = (*p1 >> 16) & 0xff; + a = (*p1 >> 24) & 0xff; + + bb = (*p2) & 0xff; + gg = (*p2 >> 8) & 0xff; + rr = (*p2 >> 16) & 0xff; + aa = (*p2 >> 24) & 0xff; + + tmp = (r - rr) * mix; + nr = rr + ((tmp + (tmp >> 8) + 0x80) >> 8); + tmp = (g - gg) * mix; + ng = gg + ((tmp + (tmp >> 8) + 0x80) >> 8); + tmp = (b - bb) * mix; + nb = bb + ((tmp + (tmp >> 8) + 0x80) >> 8); + tmp = (a - aa) * mix; + na = aa + ((tmp + (tmp >> 8) + 0x80) >> 8); + *p = (na << 24) | (nr << 16) | (ng << 8) | nb; + p++; + p1++; + p2++; + } + } + free(im->data); + im->data = data; +} + +void +__imlib_TileImageVert(ImlibImage * im) +{ + DATA32 *p1, *p2, *p, *data; + int x, y, tmp, na, nr, ng, nb, mix, a, r, g, b, aa, rr, gg, + bb; + + data = malloc(im->w * im->h * sizeof(DATA32)); + p = data; + for (y = 0; y < im->h; y++) + { + p1 = im->data + (y * im->w); + if (y < (im->h >> 1)) + { + p2 = im->data + ((y + (im->h >> 1)) * im->w); + mix = (y * 255) / (im->h >> 1); + } + else + { + p2 = im->data + ((y - (im->h >> 1)) * im->w); + mix = ((im->h - y) * 255) / (im->h - (im->h >> 1)); + } + for (x = 0; x < im->w; x++) + { + b = (*p1) & 0xff; + g = (*p1 >> 8) & 0xff; + r = (*p1 >> 16) & 0xff; + a = (*p1 >> 24) & 0xff; + + bb = (*p2) & 0xff; + gg = (*p2 >> 8) & 0xff; + rr = (*p2 >> 16) & 0xff; + aa = (*p2 >> 24) & 0xff; + + tmp = (r - rr) * mix; + nr = rr + ((tmp + (tmp >> 8) + 0x80) >> 8); + tmp = (g - gg) * mix; + ng = gg + ((tmp + (tmp >> 8) + 0x80) >> 8); + tmp = (b - bb) * mix; + nb = bb + ((tmp + (tmp >> 8) + 0x80) >> 8); + tmp = (a - aa) * mix; + na = aa + ((tmp + (tmp >> 8) + 0x80) >> 8); + *p = (na << 24) | (nr << 16) | (ng << 8) | nb; + p++; + p1++; + p2++; + } + } + free(im->data); + im->data = data; +} + +void +__imlib_copy_image_data(ImlibImage * im, int x, int y, int w, int h, int nx, + int ny) +{ + int xx, yy, jump; + DATA32 *p1, *p2; + + /* clip horizontal co-ordinates so that both dest and src fit inside */ + /* the image */ + if (x < 0) + { + w += x; + nx -= x; + x = 0; + } + if (w <= 0) + return; + if (nx < 0) + { + w += nx; + x -= nx; + nx = 0; + } + if (w <= 0) + return; + if ((x + w) > im->w) + w = (im->w - x); + if (w <= 0) + return; + if ((nx + w) > im->w) + w = (im->w - nx); + if (w <= 0) + return; + /* clip vertical co-ordinates so that both dest and src fit inside */ + /* the image */ + if (y < 0) + { + h += y; + ny -= y; + y = 0; + } + if (h <= 0) + return; + if (ny < 0) + { + h += ny; + y -= ny; + ny = 0; + } + if (h <= 0) + return; + if ((y + h) > im->h) + h = (im->h - y); + if (h <= 0) + return; + if ((ny + h) > im->h) + h = (im->h - ny); + if (h <= 0) + return; + + /* figure out what our source and destnation start pointers are */ + p1 = im->data + (y * im->w) + x; + p2 = im->data + (ny * im->w) + nx; + /* the pointer jump between lines */ + jump = (im->w - w); + /* dest < src address - we can copy forwards */ + if (p2 < p1) + { + /* work our way thru the array */ + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + *p2 = *p1; + p1++; + p2++; + } + p1 += jump; + p2 += jump; + } + } + /* dst > src - we must copy backwards */ + else + { + /* new pointers to start working at (bottom-right of rect) */ + p1 = im->data + ((y + h - 1) * im->w) + x + w - 1; + p2 = im->data + ((ny + h - 1) * im->w) + nx + w - 1; + /* work our way thru the array */ + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + *p2 = *p1; + p1--; + p2--; + } + p1 -= jump; + p2 -= jump; + } + } +} + +void +__imlib_copy_alpha_data(ImlibImage * src, ImlibImage * dst, int x, int y, + int w, int h, int nx, int ny) +{ + int xx, yy, jump, jump2; + DATA32 *p1, *p2; + + /* clip horizontal co-ordinates so that both dest and src fit inside */ + /* the image */ + if (x < 0) + { + w += x; + nx -= x; + x = 0; + } + if (w <= 0) + return; + if (nx < 0) + { + w += nx; + x -= nx; + nx = 0; + } + if (w <= 0) + return; + if ((x + w) > src->w) + w = (src->w - x); + if (w <= 0) + return; + if ((nx + w) > dst->w) + w = (dst->w - nx); + if (w <= 0) + return; + /* clip vertical co-ordinates so that both dest and src fit inside */ + /* the image */ + if (y < 0) + { + h += y; + ny -= y; + y = 0; + } + if (h <= 0) + return; + if (ny < 0) + { + h += ny; + y -= ny; + ny = 0; + } + if (h <= 0) + return; + if ((y + h) > src->h) + h = (src->h - y); + if (h <= 0) + return; + if ((ny + h) > dst->h) + h = (dst->h - ny); + if (h <= 0) + return; + + /* figure out what our source and destnation start pointers are */ + p1 = src->data + (y * src->w) + x; + p2 = dst->data + (ny * dst->w) + nx; + /* the pointer jump between lines */ + jump = (src->w - w); + jump2 = (dst->w - w); + /* copy forwards */ + if (p2 < p1) + { + /* work our way thru the array */ + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + *p2 = (*p1 & 0xff000000) | (*p2 & 0x00ffffff); + p1++; + p2++; + } + p1 += jump; + p2 += jump2; + } + } +} + diff --git a/src/lib/rgbadraw.h b/src/lib/rgbadraw.h new file mode 100644 index 0000000..7708073 --- /dev/null +++ b/src/lib/rgbadraw.h @@ -0,0 +1,141 @@ +#ifndef __RGBADRAW +#define __RGBADRAW 1 + +#define IN_SEGMENT(x, sx, sw) \ +((unsigned)((x) - (sx)) < (sw)) + +#define IN_RANGE(x, y, w, h) \ +( ((unsigned)(x) < (w)) && ((unsigned)(y) < (h)) ) + +#define IN_RECT(x, y, rx, ry, rw, rh) \ +( ((unsigned)((x) - (rx)) < (rw)) && ((unsigned)((y) - (ry)) < (rh)) ) + +#define CLIP_RECT_TO_RECT(x, y, w, h, rx, ry, rw, rh) \ +{ \ + int _t0, _t1; \ + \ + _t0 = MAX(x, (rx)); \ + _t1 = MIN(x + w, (rx) + (rw)); \ + x = _t0; \ + w = _t1 - _t0; \ + _t0 = MAX(y, (ry)); \ + _t1 = MIN(y + h, (ry) + (rh)); \ + y = _t0; \ + h = _t1 - _t0; \ +} + +#define DIV_255(a, x, tmp) \ +{ \ + tmp = (x) + 0x80; \ + a = (tmp + (tmp >> 8)) >> 8; \ +} + +#define MULT(na, a0, a1, tmp) \ + DIV_255(na, (a0) * (a1), tmp) + + +typedef struct _imlib_point ImlibPoint; + +struct _imlib_point +{ + int x, y; +}; + +typedef struct _imlib_rectangle Imlib_Rectangle; + +struct _imlib_rectangle +{ + int x, y, w, h; +}; + +typedef struct _imlib_polygon _ImlibPoly; +typedef _ImlibPoly *ImlibPoly; + +struct _imlib_polygon +{ + ImlibPoint *points; + int pointcount; + int lx, rx; + int ty, by; +}; + +/* image related operations: in rgbadraw.c */ + +void __imlib_FlipImageHoriz(ImlibImage * im); +void __imlib_FlipImageVert(ImlibImage * im); +void __imlib_FlipImageBoth(ImlibImage * im); +void __imlib_FlipImageDiagonal(ImlibImage * im, int direction); +void __imlib_BlurImage(ImlibImage * im, int rad); +void __imlib_SharpenImage(ImlibImage * im, int rad); +void __imlib_TileImageHoriz(ImlibImage * im); +void __imlib_TileImageVert(ImlibImage * im); + +void __imlib_copy_alpha_data(ImlibImage * src, ImlibImage * dst, int x, int y, + int w, int h, int nx, int ny); + +void __imlib_copy_image_data(ImlibImage * im, int x, int y, int w, int h, + int nx, int ny); + + +/* point and line drawing: in line.c */ + +ImlibUpdate * +__imlib_Point_DrawToImage(int x, int y, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend, char make_updates); + +ImlibUpdate * +__imlib_Line_DrawToImage(int x0, int y0, int x1, int y1, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend, char anti_alias, + char make_updates); + + +/* rectangle drawing and filling: in rectangle.c */ + +void +__imlib_Rectangle_DrawToImage(int xc, int yc, int w, int h, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend); + +void +__imlib_Rectangle_FillToImage(int xc, int yc, int w, int h, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend); + + +/* ellipse drawing and filling: in ellipse.c */ + +void +__imlib_Ellipse_DrawToImage(int xc, int yc, int a, int b, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend, char anti_alias); + +void +__imlib_Ellipse_FillToImage(int xc, int yc, int a, int b, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend, char anti_alias); + + +/* polygon handling functions: in polygon.c */ + +ImlibPoly __imlib_polygon_new(void); +void __imlib_polygon_free(ImlibPoly poly); +void __imlib_polygon_add_point(ImlibPoly poly, int x, int y); +unsigned char __imlib_polygon_contains_point(ImlibPoly poly, int x, int y); +void __imlib_polygon_get_bounds(ImlibPoly poly, int *px1, int *py1, int *px2, int *py2); + + +/* polygon drawing and filling: in polygon.c */ + +void +__imlib_Polygon_DrawToImage(ImlibPoly poly, char closed, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend, char anti_alias); +void +__imlib_Polygon_FillToImage(ImlibPoly poly, DATA32 color, + ImlibImage *im, int clx, int cly, int clw, int clh, + ImlibOp op, char blend, char anti_alias); + + +#endif diff --git a/src/lib/rotate.c b/src/lib/rotate.c new file mode 100644 index 0000000..900a242 --- /dev/null +++ b/src/lib/rotate.c @@ -0,0 +1,542 @@ +#include "common.h" +#include "rotate.h" +#include "blend.h" + +/*\ Linear interpolation functions \*/ +/*\ Between two values \*/ +#define INTERP(v1, v2, f) \ + (((v1) << _ROTATE_PREC) + (((v2) - (v1)) * (f))) + +/*\ Between two colour bytes \*/ +#define INTERP_VAL1(x_VAL, dest, l, r, x) \ + x_VAL(dest) = (INTERP(x_VAL(l), x_VAL(r), (x)) >> _ROTATE_PREC) + +/*\ Alpha channel: between two values and two zeroes \*/ +#define INTERP_VAL1_A0(dest, v1, v2, f1, f2) \ + A_VAL(dest) = ((INTERP(A_VAL(v1), A_VAL(v2), (f1)) * \ + (f2)) >> (2 * _ROTATE_PREC)) + +/*\ Between four values \*/ +#define INTERP_VAL2(x_VAL, dest, ul, ur, ll, lr, x, y) \ + x_VAL(dest) = (INTERP(INTERP(x_VAL(ul), x_VAL(ur), (x)), \ + INTERP(x_VAL(ll), x_VAL(lr), (x)), \ + (y)) >> (2 * _ROTATE_PREC)) + +/*\ Functions used in rotation routines. +|*| The do { } while(0) construction is to make it one statement. +\*/ +/*\ Between four colours \*/ +#define INTERP_ARGB(dest, src, sow, x, y) do { \ + INTERP_VAL2(R_VAL, (dest), (src), (src) + 1, (src) + (sow), (src) + (sow) + 1, (x) & _ROTATE_PREC_BITS, (y) & _ROTATE_PREC_BITS); \ + INTERP_VAL2(G_VAL, (dest), (src), (src) + 1, (src) + (sow), (src) + (sow) + 1, (x) & _ROTATE_PREC_BITS, (y) & _ROTATE_PREC_BITS); \ + INTERP_VAL2(B_VAL, (dest), (src), (src) + 1, (src) + (sow), (src) + (sow) + 1, (x) & _ROTATE_PREC_BITS, (y) & _ROTATE_PREC_BITS); \ + INTERP_VAL2(A_VAL, (dest), (src), (src) + 1, (src) + (sow), (src) + (sow) + 1, (x) & _ROTATE_PREC_BITS, (y) & _ROTATE_PREC_BITS); \ + } while (0) + +/*\ Between two colours, alpha between two values and zeroes \*/ +#define INTERP_RGB_A0(dest, v1, v2, f, f2) do { \ + INTERP_VAL1(R_VAL, (dest), (v1), (v2), (f) & _ROTATE_PREC_BITS); \ + INTERP_VAL1(G_VAL, (dest), (v1), (v2), (f) & _ROTATE_PREC_BITS); \ + INTERP_VAL1(B_VAL, (dest), (v1), (v2), (f) & _ROTATE_PREC_BITS); \ + INTERP_VAL1_A0(dest, (v1), (v2), (f) & _ROTATE_PREC_BITS, (f2) & _ROTATE_PREC_BITS); \ + } while (0) + +/*\ One colour, alpha between one value and three zeroes \*/ +#define INTERP_A000(dest, v, f1, f2) do { \ + *(dest) = *(v); \ + A_VAL(dest) = (A_VAL(dest) * \ + ((f1) & _ROTATE_PREC_BITS) * ((f2) & _ROTATE_PREC_BITS)) >> (2 * _ROTATE_PREC); \ + } while (0) + +/*\ Rotate by pixel sampling only, target inside source \*/ +static void +__imlib_RotateSampleInside(DATA32 * src, DATA32 * dest, int sow, int dow, + int dw, int dh, int x, int y, + int dxh, int dyh, int dxv, int dyv) +{ + int i; + + if ((dw < 1) || (dh < 1)) + return; + + while (1) + { + i = dw - 1; + do + { + *dest = src[(x >> _ROTATE_PREC) + ((y >> _ROTATE_PREC) * sow)]; + /*\ RIGHT; \ */ + x += dxh; + y += dyh; + dest++; + } while (--i >= 0); + if (--dh <= 0) + break; + /*\ DOWN/LEFT; \ */ + x += dxv - dw * dxh; + y += dyv - dw * dyh; + dest += (dow - dw); + } +} + +/*\ Same as last function, but with antialiasing \*/ +static void +__imlib_RotateAAInside(DATA32 * src, DATA32 * dest, int sow, int dow, + int dw, int dh, int x, int y, + int dxh, int dyh, int dxv, int dyv) +{ + int i; + + if ((dw < 1) || (dh < 1)) + return; + + while (1) + { + i = dw - 1; + do + { + DATA32 *src_x_y = (src + (x >> _ROTATE_PREC) + + ((y >> _ROTATE_PREC) * sow)); + INTERP_ARGB(dest, src_x_y, sow, x, y); + /*\ RIGHT; \ */ + x += dxh; + y += dyh; + dest++; + } while (--i >= 0); + if (--dh <= 0) + break; + /*\ DOWN/LEFT; \ */ + x += dxv - dw * dxh; + y += dyv - dw * dyh; + dest += (dow - dw); + } +} + +/*\ NOTE: To check if v is in [b .. t) ((v >= b) && (v < t)) +|*| it's quicker to do ((unsigned)(v - b) < (t - b)) +|*| as negative values, cast to unsigned, become large positive +|*| values, and fall through the compare. +|*| v in [0 .. t) is a special case: ((unsigned)v < t) +|*| v in [-t .. 0) is also special, as its the same as ~v in [0 .. t) +\*/ +static int +__check_inside_coords(int x, int y, int dxh, int dyh, int dxv, int dyv, + int dw, int dh, int sw, int sh) +{ + sw <<= _ROTATE_PREC; + sh <<= _ROTATE_PREC; + + if (((unsigned)x >= sw) || ((unsigned)y >= sh)) + return 0; + x += dxh * dw; + y += dyh * dw; + if (((unsigned)x >= sw) || ((unsigned)y >= sh)) + return 0; + x += dxv * dh; + y += dyv * dh; + if (((unsigned)x >= sw) || ((unsigned)y >= sh)) + return 0; + x -= dxh * dw; + y -= dyh * dw; + if (((unsigned)x >= sw) || ((unsigned)y >= sh)) + return 0; + + return 1; +} + +/*\ These ones don't need the target to be inside the source \*/ +void +__imlib_RotateSample(DATA32 * src, DATA32 * dest, int sow, int sw, int sh, + int dow, int dw, int dh, int x, int y, + int dxh, int dyh, int dxv, int dyv) +{ + int i; + + if ((dw < 1) || (dh < 1)) + return; + + if (__check_inside_coords(x, y, dxh, dyh, dxv, dyv, dw, dh, sw, sh)) + { + __imlib_RotateSampleInside(src, dest, sow, dow, dw, dh, x, y, + dxh, dyh, dxv, dyv); + return; + + } + + sw <<= _ROTATE_PREC; + sh <<= _ROTATE_PREC; + while (1) + { + i = dw - 1; + do + { + if (((unsigned)x < sw) && ((unsigned)y < sh)) + *dest = src[(x >> _ROTATE_PREC) + ((y >> _ROTATE_PREC) * sow)]; + else + *dest = 0; + /*\ RIGHT; \ */ + x += dxh; + y += dyh; + dest++; + + } while (--i >= 0); + if (--dh <= 0) + break; + /*\ DOWN/LEFT; \ */ + x += dxv - dw * dxh; + y += dyv - dw * dyh; + dest += (dow - dw); + + } +} + +/*\ With antialiasing. +|*| NB: The function 'sees' a transparent border around the source, +|*| with colour channels matching the edge, so there is no need to do +|*| anything special, but remember to account for this when calculating +|*| the bounding box. +\*/ +void +__imlib_RotateAA(DATA32 * src, DATA32 * dest, int sow, int sw, int sh, + int dow, int dw, int dh, int x, int y, + int dxh, int dyh, int dxv, int dyv) +{ + int i; + + if ((dw < 1) || (dh < 1)) + return; + + if (__check_inside_coords(x, y, dxh, dyh, dxv, dyv, dw, dh, sw - 1, sh - 1)) + { + __imlib_RotateAAInside(src, dest, sow, dow, dw, dh, x, y, + dxh, dyh, dxv, dyv); + return; + + } + + sw--; + sh--; + sw <<= _ROTATE_PREC; + sh <<= _ROTATE_PREC; + while (1) + { + i = dw - 1; + do + { + DATA32 *src_x_y = (src + (x >> _ROTATE_PREC) + + ((y >> _ROTATE_PREC) * sow)); + if ((unsigned)x < sw) + { + if ((unsigned)y < sh) + { + /*\ 12 + * |*| 34 + * \ */ + INTERP_ARGB(dest, src_x_y, sow, x, y); + } + else if ((unsigned)(y - sh) < _ROTATE_PREC_MAX) + { + /*\ 12 + * |*| .. + * \ */ + INTERP_RGB_A0(dest, src_x_y, src_x_y + 1, x, ~y); + } + else if ((unsigned)(~y) < _ROTATE_PREC_MAX) + { + /*\ .. + * |*| 34 + * \ */ + INTERP_RGB_A0(dest, src_x_y + sow, src_x_y + sow + 1, x, + y); + } + else + *dest = 0; + } + else if ((unsigned)(x - sw) < (_ROTATE_PREC_MAX)) + { + if ((unsigned)y < sh) + { + /*\ 1. + * |*| 3. + * \ */ + INTERP_RGB_A0(dest, src_x_y, src_x_y + sow, y, ~x); + } + else if ((unsigned)(y - sh) < _ROTATE_PREC_MAX) + { + /*\ 1. + * |*| .. + * \ */ + INTERP_A000(dest, src_x_y, ~x, ~y); + } + else if ((unsigned)(~y) < _ROTATE_PREC_MAX) + { + /*\ .. + * |*| 3. + * \ */ + INTERP_A000(dest, src_x_y + sow, ~x, y); + } + else + *dest = 0; + } + else if ((unsigned)(~x) < _ROTATE_PREC_MAX) + { + if ((unsigned)y < sh) + { + /*\ .2 + * |*| .4 + * \ */ + INTERP_RGB_A0(dest, src_x_y + 1, src_x_y + sow + 1, y, + x); + } + else if ((unsigned)(y - sh) < _ROTATE_PREC_MAX) + { + /*\ .2 + * |*| .. + * \ */ + INTERP_A000(dest, src_x_y + 1, x, ~y); + } + else if ((unsigned)(~y) < _ROTATE_PREC_MAX) + { + /*\ .. + * |*| .4 + * \ */ + INTERP_A000(dest, src_x_y + sow + 1, x, y); + } + else + *dest = 0; + } + else + *dest = 0; + /*\ RIGHT; \ */ + x += dxh; + y += dyh; + dest++; + + } while (--i >= 0); + if (--dh <= 0) + break; + /*\ DOWN/LEFT; \ */ + x += dxv - dw * dxh; + y += dyv - dw * dyh; + dest += (dow - dw); + + } +} + +/*\ Should this be in blend.c ?? \*/ +#define LINESIZE 16 + +void +__imlib_BlendImageToImageSkewed(ImlibImage * im_src, ImlibImage * im_dst, + char aa, char blend, char merge_alpha, + int ssx, int ssy, int ssw, int ssh, + int ddx, int ddy, + int hsx, int hsy, int vsx, int vsy, + ImlibColorModifier * cm, ImlibOp op, + int clx, int cly, int clw, int clh) +{ + int x, y, dxh, dyh, dxv, dyv, i; + double xy2; + DATA32 *data, *src; + int do_mmx; + + if ((ssw < 0) || (ssh < 0)) + return; + + if ((!(im_src->data)) && (im_src->loader) && (im_src->loader->load)) + im_src->loader->load(im_src, NULL, 0, 1); + if (!im_src->data) + return; + if ((!(im_dst->data)) && (im_dst->loader) && (im_src->loader->load)) + im_dst->loader->load(im_dst, NULL, 0, 1); + if (!im_dst->data) + return; + + /*\ Complicated gonio. Works on paper.. + * |*| Too bad it doesn't all fit into integer math.. + * \ */ + if (vsx | vsy) + { + xy2 = (double)(hsx * vsy - vsx * hsy) / _ROTATE_PREC_MAX; + if (xy2 == 0.0) + return; + dxh = (double)(ssw * vsy) / xy2; + dxv = (double)-(ssw * vsx) / xy2; + dyh = (double)-(ssh * hsy) / xy2; + dyv = (double)(ssh * hsx) / xy2; + } + else + { + xy2 = (double)(hsx * hsx + hsy * hsy) / _ROTATE_PREC_MAX; + if (xy2 == 0.0) + return; + dxh = (double)(ssw * hsx) / xy2; + dyh = (double)-(ssw * hsy) / xy2; + dxv = -dyh; + dyv = dxh; + } + x = -(ddx * dxh + ddy * dxv); + y = -(ddx * dyh + ddy * dyv); + + if (ssx < 0) + { + x += ssx * _ROTATE_PREC_MAX; + ssw += ssx; + ssx = 0; + + } + if (ssy < 0) + { + y += ssy * _ROTATE_PREC_MAX; + ssh += ssy; + ssy = 0; + + } + if ((ssw + ssx) > im_src->w) + ssw = im_src->w - ssx; + if ((ssh + ssy) > im_src->h) + ssh = im_src->h - ssy; + + src = im_src->data + ssx + ssy * im_src->w; + data = malloc(im_dst->w * LINESIZE * sizeof(DATA32)); + if (!data) + return; + if (aa) + { + /*\ Account for virtual transparent border \ */ + x += _ROTATE_PREC_MAX; + y += _ROTATE_PREC_MAX; + } +#ifdef DO_MMX_ASM + do_mmx = __imlib_get_cpuid() & CPUID_MMX; +#endif + for (i = 0; i < im_dst->h; i += LINESIZE) + { + int x2, y2, w, h, l, r; + + h = MIN(LINESIZE, im_dst->h - i); + + x2 = x + h * dxv; + y2 = y + h * dyv; + + w = ssw << _ROTATE_PREC; + h = ssh << _ROTATE_PREC; + if (aa) + { + /*\ Account for virtual transparent border \ */ + w += 2 << _ROTATE_PREC; + h += 2 << _ROTATE_PREC; + } + /*\ Pretty similar code \ */ + if (dxh > 0) + { + if (dyh > 0) + { + l = MAX(-MAX(y, y2) / dyh, -MAX(x, x2) / dxh); + r = MIN((h - MIN(y, y2)) / dyh, (w - MIN(x, x2)) / dxh); + + } + else if (dyh < 0) + { + l = MAX(-MAX(x, x2) / dxh, (h - MIN(y, y2)) / dyh); + r = MIN(-MAX(y, y2) / dyh, (w - MIN(x, x2)) / dxh); + + } + else + { + l = -MAX(x, x2) / dxh; + r = (w - MIN(x, x2)) / dxh; + + } + } + else if (dxh < 0) + { + if (dyh > 0) + { + l = MAX(-MAX(y, y2) / dyh, (w - MIN(x, x2)) / dxh); + r = MIN(-MAX(x, x2) / dxh, (h - MIN(y, y2)) / dyh); + + } + else if (dyh < 0) + { + l = MAX((h - MIN(y, y2)) / dyh, (w - MIN(x, x2)) / dxh); + r = MIN(-MAX(y, y2) / dyh, -MAX(x, x2) / dxh); + + } + else + { + l = (w - MIN(x, x2)) / dxh; + r = -MAX(x, x2) / dxh; + + } + + } + else + { + if (dyh > 0) + { + l = -MAX(y, y2) / dyh; + r = (h - MIN(y, y2)) / dyh; + + } + else if (dyh < 0) + { + l = (h - MIN(y, y2)) / dyh; + r = -MAX(y, y2) / dyh; + + } + else + { + l = 0; + r = 0; + + } + + } + l--; + r += 2; /*\ Be paranoid about roundoff errors \ */ + if (l < 0) + l = 0; + if (r > im_dst->w) + r = im_dst->w; + if (r <= l) + { + x = x2; + y = y2; + continue; + + } + + w = r - l; + h = MIN(LINESIZE, im_dst->h - i); + x += l * dxh; + y += l * dyh; + if (aa) + { + x -= _ROTATE_PREC_MAX; + y -= _ROTATE_PREC_MAX; +#ifdef DO_MMX_ASM + if (do_mmx) + __imlib_mmx_RotateAA(src, data, im_src->w, ssw, ssh, w, w, h, + x, y, dxh, dyh, dxv, dyv); + else +#endif + __imlib_RotateAA(src, data, im_src->w, ssw, ssh, w, w, h, + x, y, dxh, dyh, dxv, dyv); + + } + else + { + __imlib_RotateSample(src, data, im_src->w, ssw, ssh, w, w, h, + x, y, dxh, dyh, dxv, dyv); + + } + __imlib_BlendRGBAToData(data, w, h, im_dst->data, + im_dst->w, im_dst->h, 0, 0, l, i, w, h, + blend, merge_alpha, cm, op, 0); + x = x2; + y = y2; + + } + free(data); +} diff --git a/src/lib/rotate.h b/src/lib/rotate.h new file mode 100644 index 0000000..9e69342 --- /dev/null +++ b/src/lib/rotate.h @@ -0,0 +1,33 @@ +#ifndef __ROTATE +#define __ROTATE 1 + +#include "image.h" +#include "colormod.h" +#include "blend.h" + +/*\ Calc precision \*/ +#define _ROTATE_PREC 12 +#define _ROTATE_PREC_MAX (1 << _ROTATE_PREC) +#define _ROTATE_PREC_BITS (_ROTATE_PREC_MAX - 1) + +void __imlib_RotateSample(DATA32 *src, DATA32 *dest, int sow, int sw, int sh, + int dow, int dw, int dh, int x, int y, + int dxh, int dyh, int dxv, int dyv); +void __imlib_RotateAA(DATA32 *src, DATA32 *dest, int sow, int sw, int sh, + int dow, int dw, int dh, int x, int y, + int dx, int dy, int dxv, int dyv); +void __imlib_BlendImageToImageSkewed(ImlibImage *im_src, ImlibImage *im_dst, + char aa, char blend, char merge_alpha, + int ssx, int ssy, int ssw, int ssh, + int ddx, int ddy, + int hsx, int hsy, int vsx, int vsy, + ImlibColorModifier *cm, ImlibOp op, + int clx, int cly, int clw, int clh); + + +#ifdef DO_MMX_ASM +void __imlib_mmx_RotateAA(DATA32 *src, DATA32 *dest, int sow, int sw, int sh, + int dow, int dw, int dh, int x, int y, + int dx, int dy, int dxv, int dyv); +#endif +#endif diff --git a/src/lib/scale.c b/src/lib/scale.c new file mode 100644 index 0000000..71e523d --- /dev/null +++ b/src/lib/scale.c @@ -0,0 +1,1534 @@ +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include "scale.h" + +#include + +/*\ NB: If you change this, don't forget asm_scale.S \*/ +struct _imlib_scale_info { + int *xpoints; + DATA32 **ypoints; + int *xapoints, *yapoints; + int xup_yup; + DATA32 *pix_assert; +}; + +#define RGBA_COMPOSE(r, g, b, a) ((a) << 24) | ((r) << 16) | ((g) << 8) | (b) +#define INV_XAP (256 - xapoints[x]) +#define XAP (xapoints[x]) +#define INV_YAP (256 - yapoints[dyy + y]) +#define YAP (yapoints[dyy + y]) + +static DATA32 ** +__imlib_CalcYPoints(DATA32 * src, int sw, int sh, int dh, int b1, int b2) +{ + DATA32 **p; + int i, j = 0; + int val, inc, rv = 0; + + if (dh < 0) + { + dh = -dh; + rv = 1; + } + p = malloc((dh + 1) * sizeof(DATA32 *)); + if (dh < (b1 + b2)) + { + if (dh < b1) + { + b1 = dh; + b2 = 0; + } + else + b2 = dh - b1; + } + val = 0; + inc = 1 << 16; + for (i = 0; i < b1; i++) + { + p[j++] = src + ((val >> 16) * sw); + val += inc; + } + if (dh > (b1 + b2)) + { + val = (b1 << 16); + inc = ((sh - b1 - b2) << 16) / (dh - b1 - b2); + for (i = 0; i < (dh - b1 - b2); i++) + { + p[j++] = src + ((val >> 16) * sw); + val += inc; + } + } + val = (sh - b2) << 16; + inc = 1 << 16; + for (i = 0; i <= b2; i++) + { + p[j++] = src + ((val >> 16) * sw); + val += inc; + } + if (rv) + for (i = dh / 2; --i >= 0;) + { + DATA32 *tmp = p[i]; + + p[i] = p[dh - i - 1]; + p[dh - i - 1] = tmp; + } + return p; +} + +static int * +__imlib_CalcXPoints(int sw, int dw, int b1, int b2) +{ + int *p, i, j = 0; + int val, inc, rv = 0; + + if (dw < 0) + { + dw = -dw; + rv = 1; + } + p = malloc((dw + 1) * sizeof(int)); + if (dw < (b1 + b2)) + { + if (dw < b1) + { + b1 = dw; + b2 = 0; + } + else + b2 = dw - b1; + } + val = 0; + inc = 1 << 16; + for (i = 0; i < b1; i++) + { + p[j++] = (val >> 16); + val += inc; + } + if (dw > (b1 + b2)) + { + val = (b1 << 16); + inc = ((sw - b1 - b2) << 16) / (dw - b1 - b2); + for (i = 0; i < (dw - b1 - b2); i++) + { + p[j++] = (val >> 16); + val += inc; + } + } + val = (sw - b2) << 16; + inc = 1 << 16; + for (i = 0; i <= b2; i++) + { + p[j++] = (val >> 16); + val += inc; + } + if (rv) + for (i = dw / 2; --i >= 0;) + { + int tmp = p[i]; + + p[i] = p[dw - i - 1]; + p[dw - i - 1] = tmp; + } + return p; +} + +static int * +__imlib_CalcApoints(int s, int d, int b1, int b2, int up) +{ + int *p, i, j = 0, rv = 0; + + if (d < 0) + { + rv = 1; + d = -d; + } + p = malloc(d * sizeof(int)); + if (d < (b1 + b2)) + { + if (d < b1) + { + b1 = d; + b2 = 0; + } + else + b2 = d - b1; + } + /* scaling up */ + if (up) + { + int val, inc; + + for (i = 0; i < b1; i++) + p[j++] = 0; + if (d > (b1 + b2)) + { + int ss, dd; + + ss = s - b1 - b2; + dd = d - b1 - b2; + val = 0; + inc = (ss << 16) / dd; + for (i = 0; i < dd; i++) + { + p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00); + if (((val >> 16) + b1) >= (s - 1)) + p[j - 1] = 0; + val += inc; + } + } + for (i = 0; i < b2; i++) + p[j++] = 0; + } + /* scaling down */ + else + { + int val, inc; + + for (i = 0; i < b1; i++) + p[j++] = (1 << (16 + 14)) + (1 << 14); + if (d > (b1 + b2)) + { + int ss, dd, ap, Cp; + + ss = s - b1 - b2; + dd = d - b1 - b2; + val = 0; + inc = (ss << 16) / dd; + Cp = ((dd << 14) / ss) + 1; + for (i = 0; i < dd; i++) + { + ap = ((0x100 - ((val >> 8) & 0xff)) * Cp) >> 8; + p[j] = ap | (Cp << 16); + j++; + val += inc; + } + } + for (i = 0; i < b2; i++) + p[j++] = (1 << (16 + 14)) + (1 << 14); + } + if (rv) + { + for (i = d / 2; --i >= 0;) + { + int tmp = p[i]; + + p[i] = p[d - i - 1]; + p[d - i - 1] = tmp; + } + } + return p; +} + +ImlibScaleInfo * +__imlib_FreeScaleInfo(ImlibScaleInfo * isi) +{ + if (isi) + { + free(isi->xpoints); + free(isi->ypoints); + free(isi->xapoints); + free(isi->yapoints); + free(isi); + } + return NULL; +} + +ImlibScaleInfo * +__imlib_CalcScaleInfo(ImlibImage * im, int sw, int sh, int dw, int dh, char aa) +{ + ImlibScaleInfo *isi; + int scw, sch; + + scw = dw * im->w / sw; + sch = dh * im->h / sh; + + isi = malloc(sizeof(ImlibScaleInfo)); + if (!isi) + return NULL; + memset(isi, 0, sizeof(ImlibScaleInfo)); + + isi->pix_assert = im->data + im->w * im->h; + + isi->xup_yup = (abs(dw) >= sw) + ((abs(dh) >= sh) << 1); + + isi->xpoints = __imlib_CalcXPoints(im->w, scw, + im->border.left, im->border.right); + if (!isi->xpoints) + return __imlib_FreeScaleInfo(isi); + isi->ypoints = __imlib_CalcYPoints(im->data, im->w, im->h, sch, + im->border.top, im->border.bottom); + if (!isi->ypoints) + return __imlib_FreeScaleInfo(isi); + if (aa) + { + isi->xapoints = __imlib_CalcApoints(im->w, scw, im->border.left, + im->border.right, isi->xup_yup & 1); + if (!isi->xapoints) + return __imlib_FreeScaleInfo(isi); + isi->yapoints = __imlib_CalcApoints(im->h, sch, im->border.top, + im->border.bottom, + isi->xup_yup & 2); + if (!isi->yapoints) + return __imlib_FreeScaleInfo(isi); + } + return isi; +} + +/* scale by pixel sampling only */ +void +__imlib_ScaleSampleRGBA(ImlibScaleInfo * isi, DATA32 * dest, int dxx, int dyy, + int dx, int dy, int dw, int dh, int dow) +{ + DATA32 *sptr, *dptr; + int x, y, end; + DATA32 **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + + /* whats the last pixel ont he line so we stop there */ + end = dxx + dw; + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* get the pointer to the start of the destination scanline */ + dptr = dest + dx + ((y + dy) * dow); + /* calculate the source line we'll scan from */ + sptr = ypoints[dyy + y]; + /* go thru the scanline and copy across */ + for (x = dxx; x < end; x++) + *dptr++ = sptr[xpoints[x]]; + } +} + +/* FIXME: NEED to optimise ScaleAARGBA - currently its "ok" but needs work*/ + +/* scale by area sampling */ +void +__imlib_ScaleAARGBA(ImlibScaleInfo * isi, DATA32 * dest, int dxx, int dyy, + int dx, int dy, int dw, int dh, int dow, int sow) +{ + DATA32 *sptr, *dptr; + int x, y, end; + DATA32 **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + end = dxx + dw; + /* scaling up both ways */ + if (isi->xup_yup == 3) + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + if (YAP > 0) + { + for (x = dxx; x < end; x++) + { + int r, g, b, a; + int rr, gg, bb, aa; + DATA32 *pix; + + if (XAP > 0) + { + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + a = A_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + a += A_VAL(pix) * XAP; + pix += sow; + rr = R_VAL(pix) * XAP; + gg = G_VAL(pix) * XAP; + bb = B_VAL(pix) * XAP; + aa = A_VAL(pix) * XAP; + pix--; + rr += R_VAL(pix) * INV_XAP; + gg += G_VAL(pix) * INV_XAP; + bb += B_VAL(pix) * INV_XAP; + aa += A_VAL(pix) * INV_XAP; + r = ((rr * YAP) + (r * INV_YAP)) >> 16; + g = ((gg * YAP) + (g * INV_YAP)) >> 16; + b = ((bb * YAP) + (b * INV_YAP)) >> 16; + a = ((aa * YAP) + (a * INV_YAP)) >> 16; + *dptr++ = RGBA_COMPOSE(r, g, b, a); + } + else + { + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_YAP; + g = G_VAL(pix) * INV_YAP; + b = B_VAL(pix) * INV_YAP; + a = A_VAL(pix) * INV_YAP; + pix += sow; + r += R_VAL(pix) * YAP; + g += G_VAL(pix) * YAP; + b += B_VAL(pix) * YAP; + a += A_VAL(pix) * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + a >>= 8; + *dptr++ = RGBA_COMPOSE(r, g, b, a); + } + } + } + else + { + for (x = dxx; x < end; x++) + { + int r, g, b, a; + DATA32 *pix; + + if (XAP > 0) + { + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + a = A_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + a += A_VAL(pix) * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + a >>= 8; + *dptr++ = RGBA_COMPOSE(r, g, b, a); + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } + } + /* if we're scaling down vertically */ + else if (isi->xup_yup == 1) +#ifndef OLD_SCALE_DOWN + { + /*\ 'Correct' version, with math units prepared for MMXification \ */ + int Cy, j; + DATA32 *pix; + int r, g, b, a, rr, gg, bb, aa; + int yap; + + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + Cy = YAP >> 16; + yap = YAP & 0xffff; + + dptr = dest + dx + ((y + dy) * dow); + for (x = dxx; x < end; x++) + { + pix = ypoints[dyy + y] + xpoints[x]; + r = (R_VAL(pix) * yap) >> 10; + g = (G_VAL(pix) * yap) >> 10; + b = (B_VAL(pix) * yap) >> 10; + a = (A_VAL(pix) * yap) >> 10; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) + { + pix += sow; + r += (R_VAL(pix) * Cy) >> 10; + g += (G_VAL(pix) * Cy) >> 10; + b += (B_VAL(pix) * Cy) >> 10; + a += (A_VAL(pix) * Cy) >> 10; + } + if (j > 0) + { + pix += sow; + r += (R_VAL(pix) * j) >> 10; + g += (G_VAL(pix) * j) >> 10; + b += (B_VAL(pix) * j) >> 10; + a += (A_VAL(pix) * j) >> 10; + } + assert(pix < isi->pix_assert); + if (XAP > 0) + { + pix = ypoints[dyy + y] + xpoints[x] + 1; + rr = (R_VAL(pix) * yap) >> 10; + gg = (G_VAL(pix) * yap) >> 10; + bb = (B_VAL(pix) * yap) >> 10; + aa = (A_VAL(pix) * yap) >> 10; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) + { + pix += sow; + rr += (R_VAL(pix) * Cy) >> 10; + gg += (G_VAL(pix) * Cy) >> 10; + bb += (B_VAL(pix) * Cy) >> 10; + aa += (A_VAL(pix) * Cy) >> 10; + } + if (j > 0) + { + pix += sow; + rr += (R_VAL(pix) * j) >> 10; + gg += (G_VAL(pix) * j) >> 10; + bb += (B_VAL(pix) * j) >> 10; + aa += (A_VAL(pix) * j) >> 10; + } + assert(pix < isi->pix_assert); + r = r * INV_XAP; + g = g * INV_XAP; + b = b * INV_XAP; + a = a * INV_XAP; + r = (r + ((rr * XAP))) >> 12; + g = (g + ((gg * XAP))) >> 12; + b = (b + ((bb * XAP))) >> 12; + a = (a + ((aa * XAP))) >> 12; + } + else + { + r >>= 4; + g >>= 4; + b >>= 4; + a >>= 4; + } + *dptr = RGBA_COMPOSE(r, g, b, a); + dptr++; + } + } + } +#else + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + int yap; + + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + + yap = (ypoints[dyy + y + 1] - ypoints[dyy + y]) / sow; + if (yap > 1) + { + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0, a = 0; + int rr = 0, gg = 0, bb = 0, aa = 0; + DATA32 *pix; + + if (XAP > 0) + { + pix = sptr + xpoints[x]; + for (j = 0; j < yap; j++) + { + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + a += A_VAL(pix); + rr += R_VAL(pix + 1); + gg += G_VAL(pix + 1); + bb += B_VAL(pix + 1); + aa += A_VAL(pix + 1); + pix += sow; + } + r = r * INV_XAP / yap; + g = g * INV_XAP / yap; + b = b * INV_XAP / yap; + a = a * INV_XAP / yap; + r = (r + ((rr * XAP) / yap)) >> 8; + g = (g + ((gg * XAP) / yap)) >> 8; + b = (b + ((bb * XAP) / yap)) >> 8; + a = (a + ((aa * XAP) / yap)) >> 8; + *dptr++ = RGBA_COMPOSE(r, g, b, a); + } + else + { + pix = sptr + xpoints[x]; + for (j = 0; j < yap; j++) + { + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + a += A_VAL(pix); + pix += sow; + } + r /= yap; + g /= yap; + b /= yap; + a /= yap; + *dptr++ = RGBA_COMPOSE(r, g, b, a); + } + } + } + else + { + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0, a = 0; + int count; + DATA32 *pix; + + if (XAP > 0) + { + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + a = A_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + a += A_VAL(pix) * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + a >>= 8; + *dptr++ = RGBA_COMPOSE(r, g, b, a); + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } + } +#endif + /* if we're scaling down horizontally */ + else if (isi->xup_yup == 2) +#ifndef OLD_SCALE_DOWN + { + /*\ 'Correct' version, with math units prepared for MMXification \ */ + int Cx, j; + DATA32 *pix; + int r, g, b, a, rr, gg, bb, aa; + int xap; + + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + dptr = dest + dx + ((y + dy) * dow); + for (x = dxx; x < end; x++) + { + Cx = XAP >> 16; + xap = XAP & 0xffff; + + pix = ypoints[dyy + y] + xpoints[x]; + r = (R_VAL(pix) * xap) >> 10; + g = (G_VAL(pix) * xap) >> 10; + b = (B_VAL(pix) * xap) >> 10; + a = (A_VAL(pix) * xap) >> 10; + for (j = (1 << 14) - xap; j > Cx; j -= Cx) + { + pix++; + r += (R_VAL(pix) * Cx) >> 10; + g += (G_VAL(pix) * Cx) >> 10; + b += (B_VAL(pix) * Cx) >> 10; + a += (A_VAL(pix) * Cx) >> 10; + } + if (j > 0) + { + pix++; + r += (R_VAL(pix) * j) >> 10; + g += (G_VAL(pix) * j) >> 10; + b += (B_VAL(pix) * j) >> 10; + a += (A_VAL(pix) * j) >> 10; + } + assert(pix < isi->pix_assert); + if (YAP > 0) + { + pix = ypoints[dyy + y] + xpoints[x] + sow; + rr = (R_VAL(pix) * xap) >> 10; + gg = (G_VAL(pix) * xap) >> 10; + bb = (B_VAL(pix) * xap) >> 10; + aa = (A_VAL(pix) * xap) >> 10; + for (j = (1 << 14) - xap; j > Cx; j -= Cx) + { + pix++; + rr += (R_VAL(pix) * Cx) >> 10; + gg += (G_VAL(pix) * Cx) >> 10; + bb += (B_VAL(pix) * Cx) >> 10; + aa += (A_VAL(pix) * Cx) >> 10; + } + if (j > 0) + { + pix++; + rr += (R_VAL(pix) * j) >> 10; + gg += (G_VAL(pix) * j) >> 10; + bb += (B_VAL(pix) * j) >> 10; + aa += (A_VAL(pix) * j) >> 10; + } + assert(pix < isi->pix_assert); + r = r * INV_YAP; + g = g * INV_YAP; + b = b * INV_YAP; + a = a * INV_YAP; + r = (r + ((rr * YAP))) >> 12; + g = (g + ((gg * YAP))) >> 12; + b = (b + ((bb * YAP))) >> 12; + a = (a + ((aa * YAP))) >> 12; + } + else + { + r >>= 4; + g >>= 4; + b >>= 4; + a >>= 4; + } + *dptr = RGBA_COMPOSE(r, g, b, a); + dptr++; + } + } + } +#else + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + if (YAP > 0) + { + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0, a = 0; + int rr = 0, gg = 0, bb = 0, aa = 0; + int xap; + DATA32 *pix; + + xap = xpoints[x + 1] - xpoints[x]; + if (xap > 1) + { + pix = ypoints[dyy + y] + xpoints[x]; + for (i = 0; i < xap; i++) + { + r += R_VAL(pix + i); + g += G_VAL(pix + i); + b += B_VAL(pix + i); + a += A_VAL(pix + i); + } + r = r * INV_YAP / xap; + g = g * INV_YAP / xap; + b = b * INV_YAP / xap; + a = a * INV_YAP / xap; + pix = ypoints[dyy + y] + xpoints[x] + sow; + for (i = 0; i < xap; i++) + { + rr += R_VAL(pix + i); + gg += G_VAL(pix + i); + bb += B_VAL(pix + i); + aa += A_VAL(pix + i); + } + r = (r + ((rr * YAP) / xap)) >> 8; + g = (g + ((gg * YAP) / xap)) >> 8; + b = (b + ((bb * YAP) / xap)) >> 8; + a = (a + ((aa * YAP) / xap)) >> 8; + *dptr++ = RGBA_COMPOSE(r, g, b, a); + } + else + { + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_YAP; + g = G_VAL(pix) * INV_YAP; + b = B_VAL(pix) * INV_YAP; + a = A_VAL(pix) * INV_YAP; + pix += sow; + r += R_VAL(pix) * YAP; + g += G_VAL(pix) * YAP; + b += B_VAL(pix) * YAP; + a += A_VAL(pix) * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + a >>= 8; + *dptr++ = RGBA_COMPOSE(r, g, b, a); + } + } + } + else + { + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0, a = 0; + int xap; + DATA32 *pix; + + xap = xpoints[x + 1] - xpoints[x]; + if (xap > 1) + { + pix = ypoints[dyy + y] + xpoints[x]; + for (i = 0; i < xap; i++) + { + r += R_VAL(pix + i); + g += G_VAL(pix + i); + b += B_VAL(pix + i); + a += A_VAL(pix + i); + } + r /= xap; + g /= xap; + b /= xap; + a /= xap; + *dptr++ = RGBA_COMPOSE(r, g, b, a); + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } + } +#endif + /* if we're scaling down horizontally & vertically */ + else +#ifndef OLD_SCALE_DOWN + { + /*\ 'Correct' version, with math units prepared for MMXification: + * |*| The operation 'b = (b * c) >> 16' translates to pmulhw, + * |*| so the operation 'b = (b * c) >> d' would translate to + * |*| psllw (16 - d), %mmb; pmulh %mmc, %mmb + * \ */ + int Cx, Cy, i, j; + DATA32 *pix; + int a, r, g, b, ax, rx, gx, bx; + int xap, yap; + + for (y = 0; y < dh; y++) + { + Cy = YAP >> 16; + yap = YAP & 0xffff; + + dptr = dest + dx + ((y + dy) * dow); + for (x = dxx; x < end; x++) + { + Cx = XAP >> 16; + xap = XAP & 0xffff; + + sptr = ypoints[dyy + y] + xpoints[x]; + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + ax = (A_VAL(pix) * xap) >> 9; + pix++; + for (i = (1 << 14) - xap; i > Cx; i -= Cx) + { + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + ax += (A_VAL(pix) * Cx) >> 9; + pix++; + } + if (i > 0) + { + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + ax += (A_VAL(pix) * i) >> 9; + } + + r = (rx * yap) >> 14; + g = (gx * yap) >> 14; + b = (bx * yap) >> 14; + a = (ax * yap) >> 14; + + for (j = (1 << 14) - yap; j > Cy; j -= Cy) + { + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + ax = (A_VAL(pix) * xap) >> 9; + pix++; + for (i = (1 << 14) - xap; i > Cx; i -= Cx) + { + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + ax += (A_VAL(pix) * Cx) >> 9; + pix++; + } + if (i > 0) + { + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + ax += (A_VAL(pix) * i) >> 9; + } + + r += (rx * Cy) >> 14; + g += (gx * Cy) >> 14; + b += (bx * Cy) >> 14; + a += (ax * Cy) >> 14; + } + if (j > 0) + { + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + ax = (A_VAL(pix) * xap) >> 9; + pix++; + for (i = (1 << 14) - xap; i > Cx; i -= Cx) + { + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + ax += (A_VAL(pix) * Cx) >> 9; + pix++; + } + if (i > 0) + { + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + ax += (A_VAL(pix) * i) >> 9; + } + + r += (rx * j) >> 14; + g += (gx * j) >> 14; + b += (bx * j) >> 14; + a += (ax * j) >> 14; + } + + R_VAL(dptr) = r >> 5; + G_VAL(dptr) = g >> 5; + B_VAL(dptr) = b >> 5; + A_VAL(dptr) = a >> 5; + dptr++; + } + } + } +#else + { + int count; + DATA32 *pix; + int a, r, g, b; + + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + int yap = + (ypoints[dyy + y + 1] - ypoints[dyy + y]) / sow; + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + for (x = dxx; x < end; x++) + { + int xap = xpoints[x + 1] - xpoints[x]; + + if ((xap > 1) || (yap > 1)) + { + r = 0; + g = 0; + b = 0; + pix = ypoints[dyy + y] + xpoints[x]; + for (j = yap; --j >= 0;) + { + for (i = xap; --i >= 0;) + { + r += R_VAL(pix + i); + g += G_VAL(pix + i); + b += B_VAL(pix + i); + a += A_VAL(pix + i); + } + pix += sow; + } + count = xap * yap; + R_VAL(dptr) = r / count; + G_VAL(dptr) = g / count; + B_VAL(dptr) = b / count; + A_VAL(dptr) = a / count; + dptr++; + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } +#endif +} + +/* scale by area sampling - IGNORE the ALPHA byte*/ +void +__imlib_ScaleAARGB(ImlibScaleInfo * isi, DATA32 * dest, int dxx, int dyy, + int dx, int dy, int dw, int dh, int dow, int sow) +{ + DATA32 *sptr, *dptr; + int x, y, end; + DATA32 **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + end = dxx + dw; + /* scaling up both ways */ + if (isi->xup_yup == 3) + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + if (YAP > 0) + { + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0; + int rr = 0, gg = 0, bb = 0; + DATA32 *pix; + + if (XAP > 0) + { + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + pix += sow; + rr = R_VAL(pix) * XAP; + gg = G_VAL(pix) * XAP; + bb = B_VAL(pix) * XAP; + pix--; + rr += R_VAL(pix) * INV_XAP; + gg += G_VAL(pix) * INV_XAP; + bb += B_VAL(pix) * INV_XAP; + r = ((rr * YAP) + (r * INV_YAP)) >> 16; + g = ((gg * YAP) + (g * INV_YAP)) >> 16; + b = ((bb * YAP) + (b * INV_YAP)) >> 16; + *dptr++ = RGBA_COMPOSE(r, g, b, 0xff); + } + else + { + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_YAP; + g = G_VAL(pix) * INV_YAP; + b = B_VAL(pix) * INV_YAP; + pix += sow; + r += R_VAL(pix) * YAP; + g += G_VAL(pix) * YAP; + b += B_VAL(pix) * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + *dptr++ = RGBA_COMPOSE(r, g, b, 0xff); + } + } + } + else + { + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0; + DATA32 *pix; + + if (XAP > 0) + { + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + *dptr++ = RGBA_COMPOSE(r, g, b, 0xff); + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } + } + /* if we're scaling down vertically */ + else if (isi->xup_yup == 1) +#ifndef OLD_SCALE_DOWN + { + /*\ 'Correct' version, with math units prepared for MMXification \ */ + int Cy, j; + DATA32 *pix; + int r, g, b, rr, gg, bb; + int yap; + + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + Cy = YAP >> 16; + yap = YAP & 0xffff; + + dptr = dest + dx + ((y + dy) * dow); + for (x = dxx; x < end; x++) + { + pix = ypoints[dyy + y] + xpoints[x]; + r = (R_VAL(pix) * yap) >> 10; + g = (G_VAL(pix) * yap) >> 10; + b = (B_VAL(pix) * yap) >> 10; + pix += sow; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) + { + r += (R_VAL(pix) * Cy) >> 10; + g += (G_VAL(pix) * Cy) >> 10; + b += (B_VAL(pix) * Cy) >> 10; + pix += sow; + } + if (j > 0) + { + r += (R_VAL(pix) * j) >> 10; + g += (G_VAL(pix) * j) >> 10; + b += (B_VAL(pix) * j) >> 10; + } + if (XAP > 0) + { + pix = ypoints[dyy + y] + xpoints[x] + 1; + rr = (R_VAL(pix) * yap) >> 10; + gg = (G_VAL(pix) * yap) >> 10; + bb = (B_VAL(pix) * yap) >> 10; + pix += sow; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) + { + rr += (R_VAL(pix) * Cy) >> 10; + gg += (G_VAL(pix) * Cy) >> 10; + bb += (B_VAL(pix) * Cy) >> 10; + pix += sow; + } + if (j > 0) + { + rr += (R_VAL(pix) * j) >> 10; + gg += (G_VAL(pix) * j) >> 10; + bb += (B_VAL(pix) * j) >> 10; + } + r = r * INV_XAP; + g = g * INV_XAP; + b = b * INV_XAP; + r = (r + ((rr * XAP))) >> 12; + g = (g + ((gg * XAP))) >> 12; + b = (b + ((bb * XAP))) >> 12; + } + else + { + r >>= 4; + g >>= 4; + b >>= 4; + } + *dptr = RGBA_COMPOSE(r, g, b, 0xff); + dptr++; + } + } + } +#else + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + int yap; + + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + + yap = (ypoints[dyy + y + 1] - ypoints[dyy + y]) / sow; + if (yap > 1) + { + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0; + int rr = 0, gg = 0, bb = 0; + DATA32 *pix; + + if (XAP > 0) + { + pix = sptr + xpoints[x]; + for (j = 0; j < yap; j++) + { + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + rr += R_VAL(pix + 1); + gg += G_VAL(pix + 1); + bb += B_VAL(pix + 1); + pix += sow; + } + r = r * INV_XAP / yap; + g = g * INV_XAP / yap; + b = b * INV_XAP / yap; + r = (r + ((rr * XAP) / yap)) >> 8; + g = (g + ((gg * XAP) / yap)) >> 8; + b = (b + ((bb * XAP) / yap)) >> 8; + *dptr++ = RGBA_COMPOSE(r, g, b, 0xff); + } + else + { + pix = sptr + xpoints[x]; + for (j = 0; j < yap; j++) + { + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + pix += sow; + } + r /= yap; + g /= yap; + b /= yap; + *dptr++ = RGBA_COMPOSE(r, g, b, 0xff); + } + } + } + else + { + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0; + DATA32 *pix; + + if (XAP > 0) + { + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + *dptr++ = RGBA_COMPOSE(r, g, b, 0xff); + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } + } +#endif + /* if we're scaling down horizontally */ + else if (isi->xup_yup == 2) +#ifndef OLD_SCALE_DOWN + { + /*\ 'Correct' version, with math units prepared for MMXification \ */ + int Cx, j; + DATA32 *pix; + int r, g, b, rr, gg, bb; + int xap; + + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + dptr = dest + dx + ((y + dy) * dow); + for (x = dxx; x < end; x++) + { + Cx = XAP >> 16; + xap = XAP & 0xffff; + + pix = ypoints[dyy + y] + xpoints[x]; + r = (R_VAL(pix) * xap) >> 10; + g = (G_VAL(pix) * xap) >> 10; + b = (B_VAL(pix) * xap) >> 10; + pix++; + for (j = (1 << 14) - xap; j > Cx; j -= Cx) + { + r += (R_VAL(pix) * Cx) >> 10; + g += (G_VAL(pix) * Cx) >> 10; + b += (B_VAL(pix) * Cx) >> 10; + pix++; + } + if (j > 0) + { + r += (R_VAL(pix) * j) >> 10; + g += (G_VAL(pix) * j) >> 10; + b += (B_VAL(pix) * j) >> 10; + } + if (YAP > 0) + { + pix = ypoints[dyy + y] + xpoints[x] + sow; + rr = (R_VAL(pix) * xap) >> 10; + gg = (G_VAL(pix) * xap) >> 10; + bb = (B_VAL(pix) * xap) >> 10; + pix++; + for (j = (1 << 14) - xap; j > Cx; j -= Cx) + { + rr += (R_VAL(pix) * Cx) >> 10; + gg += (G_VAL(pix) * Cx) >> 10; + bb += (B_VAL(pix) * Cx) >> 10; + pix++; + } + if (j > 0) + { + rr += (R_VAL(pix) * j) >> 10; + gg += (G_VAL(pix) * j) >> 10; + bb += (B_VAL(pix) * j) >> 10; + } + r = r * INV_YAP; + g = g * INV_YAP; + b = b * INV_YAP; + r = (r + ((rr * YAP))) >> 12; + g = (g + ((gg * YAP))) >> 12; + b = (b + ((bb * YAP))) >> 12; + } + else + { + r >>= 4; + g >>= 4; + b >>= 4; + } + *dptr = RGBA_COMPOSE(r, g, b, 0xff); + dptr++; + } + } + } +#else + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + if (YAP > 0) + { + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0; + int rr = 0, gg = 0, bb = 0; + int xap; + DATA32 *pix; + + xap = xpoints[x + 1] - xpoints[x]; + if (xap > 1) + { + pix = ypoints[dyy + y] + xpoints[x]; + for (i = 0; i < xap; i++) + { + r += R_VAL(pix + i); + g += G_VAL(pix + i); + b += B_VAL(pix + i); + } + r = r * INV_YAP / xap; + g = g * INV_YAP / xap; + b = b * INV_YAP / xap; + pix = ypoints[dyy + y] + xpoints[x] + sow; + for (i = 0; i < xap; i++) + { + rr += R_VAL(pix + i); + gg += G_VAL(pix + i); + bb += B_VAL(pix + i); + } + r = (r + ((rr * YAP) / xap)) >> 8; + g = (g + ((gg * YAP) / xap)) >> 8; + b = (b + ((bb * YAP) / xap)) >> 8; + *dptr++ = RGBA_COMPOSE(r, g, b, 0xff); + } + else + { + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_YAP; + g = G_VAL(pix) * INV_YAP; + b = B_VAL(pix) * INV_YAP; + pix += sow; + r += R_VAL(pix) * YAP; + g += G_VAL(pix) * YAP; + b += B_VAL(pix) * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + *dptr++ = RGBA_COMPOSE(r, g, b, 0xff); + } + } + } + else + { + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0; + int xap; + DATA32 *pix; + + xap = xpoints[x + 1] - xpoints[x]; + if (xap > 1) + { + pix = ypoints[dyy + y] + xpoints[x]; + for (i = 0; i < xap; i++) + { + r += R_VAL(pix + i); + g += G_VAL(pix + i); + b += B_VAL(pix + i); + } + r /= xap; + g /= xap; + b /= xap; + *dptr++ = RGBA_COMPOSE(r, g, b, 0xff); + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } + } +#endif + /* fully optimized (i think) - onyl change of algorithm can help */ + /* if we're scaling down horizontally & vertically */ + else +#ifndef OLD_SCALE_DOWN + { + /*\ 'Correct' version, with math units prepared for MMXification \ */ + int Cx, Cy, i, j; + DATA32 *pix; + int r, g, b, rx, gx, bx; + int xap, yap; + + for (y = 0; y < dh; y++) + { + Cy = YAP >> 16; + yap = YAP & 0xffff; + + dptr = dest + dx + ((y + dy) * dow); + for (x = dxx; x < end; x++) + { + Cx = XAP >> 16; + xap = XAP & 0xffff; + + sptr = ypoints[dyy + y] + xpoints[x]; + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + pix++; + for (i = (1 << 14) - xap; i > Cx; i -= Cx) + { + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + pix++; + } + if (i > 0) + { + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + } + + r = (rx * yap) >> 14; + g = (gx * yap) >> 14; + b = (bx * yap) >> 14; + + for (j = (1 << 14) - yap; j > Cy; j -= Cy) + { + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + pix++; + for (i = (1 << 14) - xap; i > Cx; i -= Cx) + { + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + pix++; + } + if (i > 0) + { + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + } + + r += (rx * Cy) >> 14; + g += (gx * Cy) >> 14; + b += (bx * Cy) >> 14; + } + if (j > 0) + { + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + pix++; + for (i = (1 << 14) - xap; i > Cx; i -= Cx) + { + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + pix++; + } + if (i > 0) + { + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + } + + r += (rx * j) >> 14; + g += (gx * j) >> 14; + b += (bx * j) >> 14; + } + + R_VAL(dptr) = r >> 5; + G_VAL(dptr) = g >> 5; + B_VAL(dptr) = b >> 5; + dptr++; + } + } + } +#else + { + int count; + DATA32 *pix; + int r, g, b; + + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + int yap = + (ypoints[dyy + y + 1] - ypoints[dyy + y]) / sow; + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + for (x = dxx; x < end; x++) + { + int xap = xpoints[x + 1] - xpoints[x]; + + if ((xap > 1) || (yap > 1)) + { + r = 0; + g = 0; + b = 0; + pix = sptr + xpoints[x]; + for (j = yap; --j >= 0;) + { + for (i = xap; --i >= 0;) + { + r += R_VAL(pix + i); + g += G_VAL(pix + i); + b += B_VAL(pix + i); + } + pix += sow; + } + count = xap * yap; + R_VAL(dptr) = r / count; + G_VAL(dptr) = g / count; + B_VAL(dptr) = b / count; + dptr++; + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } +#endif +} diff --git a/src/lib/scale.h b/src/lib/scale.h new file mode 100644 index 0000000..f3b0b17 --- /dev/null +++ b/src/lib/scale.h @@ -0,0 +1,22 @@ +#ifndef __SCALE +#define __SCALE 1 + +typedef struct _imlib_scale_info ImlibScaleInfo; + +ImlibScaleInfo * +__imlib_CalcScaleInfo(ImlibImage *im, int sw, int sh, int dw, int dh, char aa); +ImlibScaleInfo * +__imlib_FreeScaleInfo(ImlibScaleInfo *isi); +void +__imlib_ScaleSampleRGBA(ImlibScaleInfo *isi, DATA32 *dest, int dxx, int dyy, + int dx, int dy, int dw, int dh, int dow); +void +__imlib_ScaleAARGBA(ImlibScaleInfo *isi, DATA32 *dest, int dxx, int dyy, + int dx, int dy, int dw, int dh, int dow, int sow); +void +__imlib_ScaleAARGB(ImlibScaleInfo *isi, DATA32 *dest, int dxx, int dyy, + int dx, int dy, int dw, int dh, int dow, int sow); +void +__imlib_Scale_mmx_AARGBA(ImlibScaleInfo *isi, DATA32 *dest, int dxx, int dyy, + int dx, int dy, int dw, int dh, int dow, int sow); +#endif diff --git a/src/lib/script.c b/src/lib/script.c new file mode 100644 index 0000000..13bf263 --- /dev/null +++ b/src/lib/script.c @@ -0,0 +1,298 @@ +#include "common.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef BUILD_X11 +# include +#else +# define X_DISPLAY_MISSING +#endif +#include "image.h" +#include "file.h" +#include "dynamic_filters.h" +#include "script.h" +#include "loaderpath.h" + +/* +#define FDEBUG 1 +*/ +#ifdef FDEBUG +# define D( str ) printf( "DEBUG: %s\n", str ) +#else +#define D( str ) +#endif + +IVariable *vars, *current_var, *curtail; + +static int +__imlib_find_string(char *haystack, char *needle) +{ + if (strstr(haystack, needle) != NULL) + return (strstr(haystack, needle) - haystack); + return 0; +} + +static char * +__imlib_stripwhitespace(char *str) +{ + int i, strt = 0, in_quote = 0; + char *tmpstr = calloc(strlen(str) + 1, sizeof(char)); + + for (i = 0; i < strlen(str); i++) + { + if (str[i] == '\"') + in_quote = (in_quote == 0 ? 1 : 0); + if (in_quote || !isspace(*(str + i))) + tmpstr[strt++] = str[i]; + } + strcpy(str, tmpstr); + free(tmpstr); + return str; +} + +static char * +__imlib_copystr(char *str, int start, int end) +{ + int i = 0; + char *rstr = calloc(1024, sizeof(char)); + + if (start <= end && end < strlen(str)) + { + for (i = start; i <= end; i++) + rstr[i - start] = str[i]; + return rstr; + } + return NULL; +} + +static void +__imlib_script_tidyup_params(IFunctionParam * param) +{ + if (param->next) + { + __imlib_script_tidyup_params(param->next); + } + free(param->key); + if (param->type == VAR_CHAR) + free(param->data); + free(param); +} + +static void +__imlib_script_delete_variable(IVariable * var) +{ + if (var->next != NULL) + __imlib_script_delete_variable(var->next); + free(var); +} + +void +__imlib_script_tidyup(void) +{ + __imlib_script_delete_variable(vars); +} + +void * +__imlib_script_get_next_var(void) +{ + if (current_var != NULL) + current_var = current_var->next; + if (current_var != NULL) + return current_var->ptr; + else + return NULL; +} + +void +__imlib_script_add_var(void *ptr) +{ + curtail->next = malloc(sizeof(IVariable)); + curtail = curtail->next; + curtail->ptr = ptr; + curtail->next = NULL; +} + +IFunctionParam * +__imlib_script_parse_parameters(Imlib_Image im, char *parameters) +{ + int i = 0, in_quote = 0, depth = 0, start = 0, value_start = + 0; + char *value = NULL; + IFunctionParam *rootptr, *ptr; + + D("(--) ===> Entering __imlib_script_parse_parameters()"); + + rootptr = malloc(sizeof(IFunctionParam)); + rootptr->key = strdup("NO-KEY"); + rootptr->type = VAR_CHAR; + rootptr->data = strdup("NO-VALUE"); + rootptr->next = NULL; + ptr = rootptr; + + for (i = 0; i <= strlen(parameters); i++) + { + if (parameters[i] == '\"') + in_quote = (in_quote == 0 ? 1 : 0); + if (!in_quote && parameters[i] == '(') + depth++; + if (!in_quote && parameters[i] == ')') + depth--; + if (!in_quote && parameters[i] == '=' && depth == 0) + value_start = i + 1; + if (!in_quote && (parameters[i] == ',' || i == (strlen(parameters))) + && depth == 0) + { + ptr->next = malloc(sizeof(IFunctionParam)); + ptr = ptr->next; + ptr->key = __imlib_copystr(parameters, start, value_start - 2); + value = __imlib_copystr(parameters, value_start, i - 1); +#ifdef FDEBUG + printf("DEBUG: (--) --> Variable \"%s\" = \"%s\"\n", ptr->key, + value); +#endif + if (__imlib_find_string(value, "(") < + __imlib_find_string(value, "\"")) + { + D("(--) Found a function"); + ptr->data = __imlib_script_parse_function(im, value); + ptr->type = VAR_PTR; + free(value); + } + else + { + if (strcmp(value, "[]") == 0) + { + ptr->data = __imlib_script_get_next_var(); + if (ptr->data == NULL) + D("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEK"); + /* printf( "Using pointer variable %p\n", ptr->data ); */ + ptr->type = VAR_PTR; + free(value); + } + else + { + ptr->data = value; + ptr->type = VAR_CHAR; + } + } + ptr->next = NULL; + start = i + 1; + } + } + D("(--) <=== Leaving __imlib_script_parse_parameters()"); + return rootptr; +} + +Imlib_Image +__imlib_script_parse_function(Imlib_Image im, char *function) +{ + char *funcname, *funcparams; + IFunctionParam *params; + ImlibExternalFilter *filter = NULL; + Imlib_Image retval; + + D("(--) ===> Entering __imlib_script_parse_function()"); + funcname = + __imlib_copystr(function, 0, __imlib_find_string(function, "(") - 1); + funcparams = + __imlib_copystr(function, __imlib_find_string(function, "(") + 1, + strlen(function) - 2); +#ifdef FDEBUG + printf("DEBUG: (??) = function <%s>( \"%s\" )\n", funcname, funcparams); +#endif + params = __imlib_script_parse_parameters(im, funcparams); + /* excute the filter */ + filter = __imlib_get_dynamic_filter(funcname); + if (filter != NULL) + { +#ifdef FDEBUG + printf("DEBUG: (--) Executing Filter \"%s\".\n", funcname); +#endif + retval = filter->exec_filter(funcname, im, params); + } + else + { +#ifdef FDEBUG + printf + ("DEBUG: (!!) Can't find filter \"%s\", returning given image.\n", + funcname); +#endif + retval = im; + } + D("Get Here"); + /* clean up params */ + free(funcname); + free(funcparams); + __imlib_script_tidyup_params(params); + D("(--) <=== Leaving __imlib_script_parse_function()"); + return retval; +} + +Imlib_Image +__imlib_script_parse(Imlib_Image im, char *script, va_list param_list) +{ + int i = 0, in_quote = 0, start = 0, depth = 0; + char *scriptbuf = NULL, *function; + + D("(--) Script Parser Start."); + if (script != NULL && strlen(script) > 0) + { + vars = malloc(sizeof(IVariable)); + vars->ptr = NULL; + vars->next = NULL; + curtail = vars; + current_var = vars; + /* gather up variable from the command line */ + D("(--) String Whitespace from script."); + scriptbuf = __imlib_stripwhitespace(strdup(script)); + + i = __imlib_find_string(scriptbuf + start, "=[]") - 1; + while (i > 0) + { + __imlib_script_add_var(va_arg(param_list, void *)); + + start = start + i + 2; + i = __imlib_find_string(scriptbuf + start, "=[]") - 1; + i = (i == 0 ? 0 : i); + D("(??) Found pointer variable"); + } + + start = 0; + i = 0; + for (i = 0; i < strlen(scriptbuf); i++) + { + if (script[i] == '\"') + in_quote = (in_quote == 0 ? 1 : 0); + if (!in_quote && script[i] == '(') + depth++; + if (!in_quote && script[i] == ')') + depth--; + if (!in_quote && (script[i] == ';') && depth == 0) + { + function = __imlib_copystr(scriptbuf, start, i - 1); + im = __imlib_script_parse_function(im, function); + imlib_context_set_image(im); + start = i + 1; + free(function); + } + } + D("(--) Cleaning up parameter list"); + __imlib_script_tidyup(); + D("(--) Script Parser Successful."); + free(scriptbuf); + return im; + } + else + { + D("(!!) Script Parser Failed."); + return NULL; + } +} diff --git a/src/lib/script.h b/src/lib/script.h new file mode 100644 index 0000000..db52859 --- /dev/null +++ b/src/lib/script.h @@ -0,0 +1,70 @@ +#ifndef _DYN_FUNCTION_H_ +#define _DYN_FUNCTION_H_ + +#include + +#ifndef BUILD_X11 +# ifndef X_DISPLAY_MISSING +# define X_DISPLAY_MISSING +# endif +#endif +#include "Imlib2.h" +#include + +#define VAR_CHAR 1 +#define VAR_PTR 2 + +#define ASSIGN_DATA8( var, v ) if( strcmp( ptr->key, var ) == 0 ) v = (DATA8)atoi( (char *)ptr->data ) +#define ASSIGN_INT(k, v) \ + if (!strcmp((k), ptr->key)) { \ + if (ptr->type == VAR_PTR) { \ + (v) = (*(int *)ptr->data); \ + } else if (ptr->type == VAR_CHAR) { \ + (v) = strtol(ptr->data, 0, 0); \ + } \ + } + +#define ASSIGN_IMAGE(k, v) \ + if (!strcmp((k), ptr->key)) { \ + if (ptr->type == VAR_PTR) { \ + (v) = ((Imlib_Image)ptr->data); \ + } else if (ptr->type == VAR_CHAR) { \ + if (!free_map) \ + (v) = imlib_load_image(ptr->data); \ + free_map = 1; \ + } \ + } + +typedef struct _imlib_function_param IFunctionParam; +typedef struct _imlib_function_param *pIFunctionParam; +struct _imlib_function_param +{ + char *key; + int type; + void *data; + pIFunctionParam next; +}; + +typedef struct _imlib_function IFunction; +typedef struct _imlib_function *pIFunction; +struct _imlib_function +{ + char *name; + pIFunctionParam params; + pIFunction next; +}; + +typedef struct _imlib_variable +{ + void *ptr; + struct _imlib_variable *next; +} IVariable; + +Imlib_Image __imlib_script_parse( Imlib_Image im, char *script, va_list ); +IFunctionParam *__imlib_script_parse_parameters( Imlib_Image im, char *parameters ); +Imlib_Image __imlib_script_parse_function( Imlib_Image im, char *function ); +void __imlib_script_tidyup(void); +void *__imlib_script_get_next_var(void); +void __imlib_script_add_var( void *ptr ); + +#endif /* _FUNCTION_H_ */ diff --git a/src/lib/span.c b/src/lib/span.c new file mode 100644 index 0000000..fa7233b --- /dev/null +++ b/src/lib/span.c @@ -0,0 +1,1160 @@ +#include "common.h" +#include "colormod.h" +#include "image.h" +#include "blend.h" +#include "span.h" + + +#define ADD_COPY(r, g, b, dest) \ + ADD_COLOR(R_VAL(dest), r, R_VAL(dest)); \ + ADD_COLOR(G_VAL(dest), g, G_VAL(dest)); \ + ADD_COLOR(B_VAL(dest), b, B_VAL(dest)); + +#define SUB_COPY(r, g, b, dest) \ + SUB_COLOR(R_VAL(dest), r, R_VAL(dest)); \ + SUB_COLOR(G_VAL(dest), g, G_VAL(dest)); \ + SUB_COLOR(B_VAL(dest), b, B_VAL(dest)); + +#define RE_COPY(r, g, b, dest) \ + RESHADE_COLOR(R_VAL(dest), r, R_VAL(dest)); \ + RESHADE_COLOR(G_VAL(dest), g, G_VAL(dest)); \ + RESHADE_COLOR(B_VAL(dest), b, B_VAL(dest)); + +#define MULT(na, a0, a1, tmp) \ + tmp = ((a0) * (a1)) + 0x80; \ + na = (tmp + (tmp >> 8)) >> 8; + + +extern DATA8 pow_lut[256][256]; + + +/* point drawing functions */ + +/* COPY OPS */ + +static void +__imlib_CopyToRGBA(DATA32 color, DATA32 *dst) +{ + *dst = color; +} + +static void +__imlib_CopyToRGB(DATA32 color, DATA32 *dst) +{ + *dst = (*dst & 0xff000000) | (color & 0x00ffffff); +} + +static void +__imlib_BlendToRGB(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + + BLEND(R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color), dst); +} + +static void +__imlib_BlendToRGBA(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + DATA8 a; + + a = pow_lut[A_VAL(&color)][A_VAL(dst)]; + BLEND_COLOR(A_VAL(&color), A_VAL(dst), 255, A_VAL(dst)); + BLEND(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); +} + + +/* ADD OPS */ + +static void +__imlib_AddCopyToRGBA(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + + A_VAL(dst) = A_VAL(&color); + ADD_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); +} + +static void +__imlib_AddCopyToRGB(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + + ADD_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); +} + +static void +__imlib_AddBlendToRGB(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + + BLEND_ADD(R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color), dst); +} + +static void +__imlib_AddBlendToRGBA(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + DATA8 a; + + a = pow_lut[A_VAL(&color)][A_VAL(dst)]; + BLEND_COLOR(A_VAL(&color), A_VAL(dst), 255, A_VAL(dst)); + BLEND_ADD(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); +} + + +/* SUBTRACT OPS */ + +static void +__imlib_SubCopyToRGBA(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + + A_VAL(dst) = A_VAL(&color); + SUB_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); +} + +static void +__imlib_SubCopyToRGB(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + + SUB_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); +} + +static void +__imlib_SubBlendToRGB(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + + BLEND_SUB(R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color), dst); +} + +static void +__imlib_SubBlendToRGBA(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + DATA8 a; + + a = pow_lut[A_VAL(&color)][A_VAL(dst)]; + BLEND_COLOR(A_VAL(&color), A_VAL(dst), 255, A_VAL(dst)); + BLEND_SUB(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); +} + + +/* RESHADE OPS */ + +static void +__imlib_ReCopyToRGBA(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + + A_VAL(dst) = A_VAL(&color); + RE_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); +} + +static void +__imlib_ReCopyToRGB(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + + RE_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); +} + +static void +__imlib_ReBlendToRGB(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + + BLEND_RE(R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color), dst); +} + +static void +__imlib_ReBlendToRGBA(DATA32 color, DATA32 *dst) +{ + DATA32 tmp; + DATA8 a; + + a = pow_lut[A_VAL(&color)][A_VAL(dst)]; + BLEND_COLOR(A_VAL(&color), A_VAL(dst), 255, A_VAL(dst)); + BLEND_RE(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); +} + + +/* span drawing functions* */ + +/* COPY OPS */ + +static void +__imlib_CopySpanToRGBA(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + *dst = color; + dst++; + } +} + +static void +__imlib_CopySpanToRGB(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + *dst = (*dst & 0xff000000) | (color & 0x00ffffff); + dst++; + } +} + +static void +__imlib_BlendSpanToRGB(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + BLEND(R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color), dst); + dst++; + } +} + +static void +__imlib_BlendSpanToRGBA(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + DATA8 a; + + a = pow_lut[A_VAL(&color)][A_VAL(dst)]; + BLEND_COLOR(A_VAL(&color), A_VAL(dst), 255, A_VAL(dst)); + BLEND(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + dst++; + } +} + + +/* ADD OPS */ + +static void +__imlib_AddCopySpanToRGBA(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + A_VAL(dst) = A_VAL(&color); + ADD_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + dst++; + } +} + +static void +__imlib_AddCopySpanToRGB(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + ADD_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + dst++; + } +} + +static void +__imlib_AddBlendSpanToRGB(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + BLEND_ADD(R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color), dst); + dst++; + } +} + +static void +__imlib_AddBlendSpanToRGBA(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + DATA8 a; + + a = pow_lut[A_VAL(&color)][A_VAL(dst)]; + BLEND_COLOR(A_VAL(&color), A_VAL(dst), 255, A_VAL(dst)); + BLEND_ADD(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + dst++; + } +} + + +/* SUBTRACT OPS */ + +static void +__imlib_SubCopySpanToRGBA(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + A_VAL(dst) = A_VAL(&color); + SUB_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + dst++; + } +} + +static void +__imlib_SubCopySpanToRGB(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + SUB_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + dst++; + } +} + +static void +__imlib_SubBlendSpanToRGB(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + BLEND_SUB(R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color), dst); + dst++; + } +} + +static void +__imlib_SubBlendSpanToRGBA(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + DATA8 a; + + a = pow_lut[A_VAL(&color)][A_VAL(dst)]; + BLEND_COLOR(A_VAL(&color), A_VAL(dst), 255, A_VAL(dst)); + BLEND_SUB(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + dst++; + } +} + + +/* RESHADE OPS */ + +static void +__imlib_ReCopySpanToRGBA(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + A_VAL(dst) = A_VAL(&color); + RE_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + dst++; + } +} + +static void +__imlib_ReCopySpanToRGB(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + RE_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + dst++; + } +} + +static void +__imlib_ReBlendSpanToRGB(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + BLEND_RE(R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color), dst); + dst++; + } +} + +static void +__imlib_ReBlendSpanToRGBA(DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + DATA8 a; + + a = pow_lut[A_VAL(&color)][A_VAL(dst)]; + BLEND_COLOR(A_VAL(&color), A_VAL(dst), 255, A_VAL(dst)); + BLEND_RE(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + dst++; + } +} + + + +/* shaped span drawing functions* */ + +/* COPY OPS */ + +static void +__imlib_CopyShapedSpanToRGBA(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + DATA32 col = color; + + if (A_VAL(&color) < 255) + { + while (len--) + { + DATA32 tmp; + + switch (*src) + { + case 0: break; + case 255: { *dst = color; break; } + default: + { + MULT(A_VAL(&col), *src, A_VAL(&color), tmp); + *dst = col; + break; + } + } + src++; dst++; + } + return; + } + + while (len--) + { + switch (*src) + { + case 0: break; + case 255: { *dst = color; break; } + default: + { + A_VAL(&col) = *src; + *dst = col; + break; + } + } + src++; dst++; + } +} + +static void +__imlib_CopyShapedSpanToRGB(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + if (*src) + *dst = (*dst & 0xff000000) | (color & 0x00ffffff); + + src++; dst++; + } +} + +static void +__imlib_BlendShapedSpanToRGB(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + if (A_VAL(&color) < 255) + { + while (len--) + { + DATA32 tmp; DATA8 a; + + switch (*src) + { + case 0: break; + case 255: + { + BLEND(R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color), dst); + break; + } + default: + { + MULT(a, *src, A_VAL(&color), tmp); + BLEND(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + } + src++; dst++; + } + return; + } + + while (len--) + { + DATA32 tmp; + + switch (*src) + { + case 0: break; + case 255: + { + *dst = (*dst & 0xff000000) | (color & 0x00ffffff); + break; + } + default: + { + BLEND(R_VAL(&color), G_VAL(&color), B_VAL(&color), *src, dst); + break; + } + } + src++; dst++; + } +} + +static void +__imlib_BlendShapedSpanToRGBA(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + if (A_VAL(&color) < 255) + { + while (len--) + { + DATA32 tmp; DATA8 a, aa; + + switch (*src) + { + case 0: break; + case 255: + { + a = pow_lut[A_VAL(&color)][A_VAL(dst)]; + BLEND_COLOR(A_VAL(&color), A_VAL(dst), 255, A_VAL(dst)); + BLEND(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + default: + { + MULT(aa, *src, A_VAL(&color), tmp); + a = pow_lut[aa][A_VAL(dst)]; + BLEND_COLOR(aa, A_VAL(dst), 255, A_VAL(dst)); + BLEND(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + } + src++; dst++; + } + return; + } + + while (len--) + { + DATA32 tmp; DATA8 a; + + switch (*src) + { + case 0: break; + case 255: + { + *dst = color; + break; + } + default: + { + a = pow_lut[*src][A_VAL(dst)]; + BLEND_COLOR(*src, A_VAL(dst), 255, A_VAL(dst)); + BLEND(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + } + src++; dst++; + } +} + + +/* ADD OPS */ + +static void +__imlib_AddCopyShapedSpanToRGBA(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + if (A_VAL(&color) < 255) + { + while (len--) + { + DATA32 tmp; + + switch (*src) + { + case 0: break; + case 255: + { + A_VAL(dst) = A_VAL(&color); + ADD_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + break; + } + default: + { + MULT(A_VAL(dst), *src, A_VAL(&color), tmp); + ADD_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + break; + } + } + src++; dst++; + } + return; + } + + while (len--) + { + DATA32 tmp; + + if (*src) + { + A_VAL(dst) = *src; + ADD_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + } + src++; dst++; + } +} + +static void +__imlib_AddCopyShapedSpanToRGB(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + if (*src) + { ADD_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst) } + + src++; dst++; + } +} + +static void +__imlib_AddBlendShapedSpanToRGB(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + if (A_VAL(&color) < 255) + { + while (len--) + { + DATA32 tmp; DATA8 a; + + switch (*src) + { + case 0: break; + case 255: + { + BLEND_ADD(R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color), dst); + break; + } + default: + { + MULT(a, *src, A_VAL(&color), tmp); + BLEND_ADD(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + } + src++; dst++; + } + return; + } + + while (len--) + { + DATA32 tmp; + + switch (*src) + { + case 0: break; + case 255: + { + ADD_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + break; + } + default: + { + BLEND_ADD(R_VAL(&color), G_VAL(&color), B_VAL(&color), *src, dst); + break; + } + } + src++; dst++; + } +} + +static void +__imlib_AddBlendShapedSpanToRGBA(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + if (A_VAL(&color) < 255) + { + while (len--) + { + DATA32 tmp; DATA8 a, aa; + + switch (*src) + { + case 0: break; + case 255: + { + a = pow_lut[A_VAL(&color)][A_VAL(dst)]; + BLEND_COLOR(A_VAL(&color), A_VAL(dst), 255, A_VAL(dst)); + BLEND_ADD(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + default: + { + MULT(aa, *src, A_VAL(&color), tmp); + a = pow_lut[aa][A_VAL(dst)]; + BLEND_COLOR(aa, A_VAL(dst), 255, A_VAL(dst)); + BLEND_ADD(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + } + src++; dst++; + } + return; + } + + while (len--) + { + DATA32 tmp; DATA8 a; + + switch (*src) + { + case 0: break; + case 255: + { + A_VAL(dst) = 255; + ADD_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + break; + } + default: + { + a = pow_lut[*src][A_VAL(dst)]; + BLEND_COLOR(*src, A_VAL(dst), 255, A_VAL(dst)); + BLEND_ADD(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + } + src++; dst++; + } +} + + +/* SUBTRACT OPS */ + +static void +__imlib_SubCopyShapedSpanToRGBA(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + if (A_VAL(&color) < 255) + { + while (len--) + { + DATA32 tmp; + + switch (*src) + { + case 0: break; + case 255: + { + A_VAL(dst) = A_VAL(&color); + SUB_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + break; + } + default: + { + MULT(A_VAL(dst), *src, A_VAL(&color), tmp); + SUB_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + break; + } + } + src++; dst++; + } + return; + } + + while (len--) + { + DATA32 tmp; + + if (*src) + { + A_VAL(dst) = *src; + SUB_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + } + src++; dst++; + } +} + +static void +__imlib_SubCopyShapedSpanToRGB(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + if (*src) + { SUB_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst) } + + src++; dst++; + } +} + +static void +__imlib_SubBlendShapedSpanToRGB(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + if (A_VAL(&color) < 255) + { + while (len--) + { + DATA32 tmp; DATA8 a; + + switch (*src) + { + case 0: break; + case 255: + { + BLEND_SUB(R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color), dst); + break; + } + default: + { + MULT(a, *src, A_VAL(&color), tmp); + BLEND_SUB(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + } + src++; dst++; + } + return; + } + + while (len--) + { + DATA32 tmp; + + switch (*src) + { + case 0: break; + case 255: + { + SUB_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + break; + } + default: + { + BLEND_SUB(R_VAL(&color), G_VAL(&color), B_VAL(&color), *src, dst); + break; + } + } + src++; dst++; + } +} + +static void +__imlib_SubBlendShapedSpanToRGBA(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + if (A_VAL(&color) < 255) + { + while (len--) + { + DATA32 tmp; DATA8 a, aa; + + switch (*src) + { + case 0: break; + case 255: + { + a = pow_lut[A_VAL(&color)][A_VAL(dst)]; + BLEND_COLOR(A_VAL(&color), A_VAL(dst), 255, A_VAL(dst)); + BLEND_SUB(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + default: + { + MULT(aa, *src, A_VAL(&color), tmp); + a = pow_lut[aa][A_VAL(dst)]; + BLEND_COLOR(aa, A_VAL(dst), 255, A_VAL(dst)); + BLEND_SUB(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + } + src++; dst++; + } + return; + } + + while (len--) + { + DATA32 tmp; DATA8 a; + + switch (*src) + { + case 0: break; + case 255: + { + A_VAL(dst) = 255; + SUB_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + break; + } + default: + { + a = pow_lut[*src][A_VAL(dst)]; + BLEND_COLOR(*src, A_VAL(dst), 255, A_VAL(dst)); + BLEND_SUB(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + } + src++; dst++; + } +} + + +/* RESHADE OPS */ + +static void +__imlib_ReCopyShapedSpanToRGBA(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + if (A_VAL(&color) < 255) + { + while (len--) + { + DATA32 tmp; + + switch (*src) + { + case 0: break; + case 255: + { + A_VAL(dst) = A_VAL(&color); + RE_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + break; + } + default: + { + MULT(A_VAL(dst), *src, A_VAL(&color), tmp); + RE_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + break; + } + } + src++; dst++; + } + return; + } + + while (len--) + { + DATA32 tmp; + + if (*src) + { + A_VAL(dst) = *src; + RE_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + } + src++; dst++; + } +} + +static void +__imlib_ReCopyShapedSpanToRGB(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + while (len--) + { + DATA32 tmp; + + if (*src) + { RE_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst) } + + src++; dst++; + } +} + +static void +__imlib_ReBlendShapedSpanToRGB(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + if (A_VAL(&color) < 255) + { + while (len--) + { + DATA32 tmp; DATA8 a; + + switch (*src) + { + case 0: break; + case 255: + { + BLEND_RE(R_VAL(&color), G_VAL(&color), B_VAL(&color), A_VAL(&color), dst); + break; + } + default: + { + MULT(a, *src, A_VAL(&color), tmp); + BLEND_RE(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + } + src++; dst++; + } + return; + } + + while (len--) + { + DATA32 tmp; + + switch (*src) + { + case 0: break; + case 255: + { + RE_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + break; + } + default: + { + BLEND_RE(R_VAL(&color), G_VAL(&color), B_VAL(&color), *src, dst); + break; + } + } + src++; dst++; + } +} + +static void +__imlib_ReBlendShapedSpanToRGBA(DATA8 *src, DATA32 color, DATA32 *dst, int len) +{ + if (A_VAL(&color) < 255) + { + while (len--) + { + DATA32 tmp; DATA8 a, aa; + + switch (*src) + { + case 0: break; + case 255: + { + a = pow_lut[A_VAL(&color)][A_VAL(dst)]; + BLEND_COLOR(A_VAL(&color), A_VAL(dst), 255, A_VAL(dst)); + BLEND_RE(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + default: + { + MULT(aa, *src, A_VAL(&color), tmp); + a = pow_lut[aa][A_VAL(dst)]; + BLEND_COLOR(aa, A_VAL(dst), 255, A_VAL(dst)); + BLEND_RE(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + } + src++; dst++; + } + return; + } + + while (len--) + { + DATA32 tmp; DATA8 a; + + switch (*src) + { + case 0: break; + case 255: + { + A_VAL(dst) = 255; + RE_COPY(R_VAL(&color), G_VAL(&color), B_VAL(&color), dst); + break; + } + default: + { + a = pow_lut[*src][A_VAL(dst)]; + BLEND_COLOR(*src, A_VAL(dst), 255, A_VAL(dst)); + BLEND_RE(R_VAL(&color), G_VAL(&color), B_VAL(&color), a, dst); + break; + } + } + src++; dst++; + } +} + + + +ImlibPointDrawFunction +__imlib_GetPointDrawFunction(ImlibOp op, char dst_alpha, char blend) +{ + /* [ operation ][ dst_alpha ][ blend ] */ + static ImlibPointDrawFunction ptfuncs[4][2][2] = + /* OP_COPY */ + { { {__imlib_CopyToRGB, __imlib_BlendToRGB}, + {__imlib_CopyToRGBA, __imlib_BlendToRGBA} }, + /* OP_ADD */ + { {__imlib_AddCopyToRGB, __imlib_AddBlendToRGB}, + {__imlib_AddCopyToRGBA, __imlib_AddBlendToRGBA} }, + /* OP_SUBTRACT */ + { {__imlib_SubCopyToRGB, __imlib_SubBlendToRGB}, + {__imlib_SubCopyToRGBA, __imlib_SubBlendToRGBA} }, + /* OP_RESHADE */ + { {__imlib_ReCopyToRGB, __imlib_ReBlendToRGB}, + {__imlib_ReCopyToRGBA, __imlib_ReBlendToRGBA} }, }; + + int opi = (op == OP_COPY) ? 0 + : (op == OP_ADD) ? 1 + : (op == OP_SUBTRACT) ? 2 : (op == OP_RESHADE) ? 3 : -1; + + if (opi == -1) + return NULL; + + return ptfuncs[opi][!!dst_alpha][!!blend]; +} + +ImlibSpanDrawFunction +__imlib_GetSpanDrawFunction(ImlibOp op, char dst_alpha, char blend) +{ + static ImlibSpanDrawFunction spanfuncs[4][2][2] = + /* OP_COPY */ + { { {__imlib_CopySpanToRGB, __imlib_BlendSpanToRGB}, + {__imlib_CopySpanToRGBA, __imlib_BlendSpanToRGBA} }, + /* OP_ADD */ + { {__imlib_AddCopySpanToRGB, __imlib_AddBlendSpanToRGB}, + {__imlib_AddCopySpanToRGBA, __imlib_AddBlendSpanToRGBA} }, + /* OP_SUBTRACT */ + { {__imlib_SubCopySpanToRGB, __imlib_SubBlendSpanToRGB}, + {__imlib_SubCopySpanToRGBA, __imlib_SubBlendSpanToRGBA} }, + /* OP_RESHADE */ + { {__imlib_ReCopySpanToRGB, __imlib_ReBlendSpanToRGB}, + {__imlib_ReCopySpanToRGBA, __imlib_ReBlendSpanToRGBA} }, }; + + int opi = (op == OP_COPY) ? 0 + : (op == OP_ADD) ? 1 + : (op == OP_SUBTRACT) ? 2 : (op == OP_RESHADE) ? 3 : -1; + + if (opi == -1) + return NULL; + + return spanfuncs[opi][!!dst_alpha][!!blend]; +} + +ImlibShapedSpanDrawFunction +__imlib_GetShapedSpanDrawFunction(ImlibOp op, char dst_alpha, char blend) +{ + static ImlibShapedSpanDrawFunction shapedspanfuncs[4][2][2] = + /* OP_COPY */ + { { {__imlib_CopyShapedSpanToRGB, __imlib_BlendShapedSpanToRGB}, + {__imlib_CopyShapedSpanToRGBA, __imlib_BlendShapedSpanToRGBA} }, + /* OP_ADD */ + { {__imlib_AddCopyShapedSpanToRGB, __imlib_AddBlendShapedSpanToRGB}, + {__imlib_AddCopyShapedSpanToRGBA, __imlib_AddBlendShapedSpanToRGBA} }, + /* OP_SUBTRACT */ + { {__imlib_SubCopyShapedSpanToRGB, __imlib_SubBlendShapedSpanToRGB}, + {__imlib_SubCopyShapedSpanToRGBA, __imlib_SubBlendShapedSpanToRGBA} }, + /* OP_RESHADE */ + { {__imlib_ReCopyShapedSpanToRGB, __imlib_ReBlendShapedSpanToRGB}, + {__imlib_ReCopyShapedSpanToRGBA, __imlib_ReBlendShapedSpanToRGBA} }, }; + + int opi = (op == OP_COPY) ? 0 + : (op == OP_ADD) ? 1 + : (op == OP_SUBTRACT) ? 2 : (op == OP_RESHADE) ? 3 : -1; + + if (opi == -1) + return NULL; + + return shapedspanfuncs[opi][!!dst_alpha][!!blend]; +} + diff --git a/src/lib/span.h b/src/lib/span.h new file mode 100644 index 0000000..149aa24 --- /dev/null +++ b/src/lib/span.h @@ -0,0 +1,24 @@ +#ifndef __SPAN +#define __SPAN 1 + + +typedef void (*ImlibPointDrawFunction)(DATA32, DATA32 *); + +ImlibPointDrawFunction +__imlib_GetPointDrawFunction(ImlibOp op, char dst_alpha, char blend); + + +typedef void (*ImlibSpanDrawFunction)(DATA32, DATA32 *, int); + +ImlibSpanDrawFunction +__imlib_GetSpanDrawFunction(ImlibOp op, char dst_alpha, char blend); + + +typedef void (*ImlibShapedSpanDrawFunction)(DATA8 *, DATA32, DATA32 *, int); + +ImlibShapedSpanDrawFunction +__imlib_GetShapedSpanDrawFunction(ImlibOp op, char dst_alpha, char blend); + + +#endif + diff --git a/src/lib/updates.c b/src/lib/updates.c new file mode 100644 index 0000000..c96c2e8 --- /dev/null +++ b/src/lib/updates.c @@ -0,0 +1,195 @@ +#include "common.h" +#include "updates.h" + +enum _t_used { + T_UNUSED = 0, + T_USED = 1 +}; + +struct _tile { + enum _t_used used; +}; + +#define TBITS 5 +#define TB TBITS +#define TM ((1 << TBITS) - 1) +#define TS (1 << TBITS) + +#define T(x, y) t[((y) * tw) + (x)] + +ImlibUpdate * +__imlib_MergeUpdate(ImlibUpdate * u, int w, int h, int hgapmax) +{ + ImlibUpdate *nu = NULL, *uu; + struct _tile *t; + int tw, th, x, y, i; + int *gaps = NULL; + + /* if theres no rects to process.. return NULL */ + if (!u) + return NULL; + tw = w >> TB; + if (w & TM) + tw++; + th = h >> TB; + if (h & TM) + th++; + t = malloc(tw * th * sizeof(struct _tile)); + /* fill in tiles to be all not used */ + for (i = 0, y = 0; y < th; y++) + { + for (x = 0; x < tw; x++) + t[i++].used = T_UNUSED; + } + /* fill in all tiles */ + for (uu = u; uu; uu = uu->next) + { + CLIP(uu->x, uu->y, uu->w, uu->h, 0, 0, w, h); + for (y = uu->y >> TB; y <= ((uu->y + uu->h - 1) >> TB); y++) + { + for (x = uu->x >> TB; x <= ((uu->x + uu->w - 1) >> TB); x++) + T(x, y).used = T_USED; + } + } + /* scan each line - if > hgapmax gaps between tiles, then fill smallest */ + gaps = malloc(tw * sizeof(int)); + for (y = 0; y < th; y++) + { + int hgaps = 0, start = -1, min; + char have = 1, gap = 0; + + for (x = 0; x < tw; x++) + gaps[x] = 0; + for (x = 0; x < tw; x++) + { + if ((have) && (T(x, y).used == T_UNUSED)) + { + start = x; + gap = 1; + have = 0; + } + else if ((!have) && (gap) && (T(x, y).used & T_USED)) + { + gap = 0; + hgaps++; + have = 1; + gaps[start] = x - start; + } + else if (T(x, y).used & T_USED) + have = 1; + } + while (hgaps > hgapmax) + { + start = -1; + min = tw; + + for (x = 0; x < tw; x++) + { + if ((gaps[x] > 0) && (gaps[x] < min)) + { + start = x; + min = gaps[x]; + } + } + if (start >= 0) + { + gaps[start] = 0; + for (x = start; + T(x, y).used == T_UNUSED; T(x++, y).used = T_USED); + hgaps--; + } + } + } + free(gaps); + /* coalesce tiles into larger blocks and make new rect list */ + for (y = 0; y < th; y++) + { + for (x = 0; x < tw; x++) + { + if (T(x, y).used & T_USED) + { + int xx, yy, ww, hh, ok; + + for (xx = x + 1, ww = 1; + (T(xx, y).used & T_USED) && (xx < tw); xx++, ww++); + for (yy = y + 1, hh = 1, ok = 1; + (yy < th) && (ok); yy++, hh++) + { + for (xx = x; xx < (x + ww); xx++) + { + if (!(T(xx, yy).used & T_USED)) + { + ok = 0; + xx = x + ww; + hh--; + } + } + } + for (yy = y; yy < (y + hh); yy++) + { + for (xx = x; xx < (x + ww); xx++) + T(xx, yy).used = T_UNUSED; + } + nu = __imlib_AddUpdate(nu, (x << TB), (y << TB), + (ww << TB), (hh << TB)); + } + } + } + free(t); + __imlib_FreeUpdates(u); + return nu; +} + +ImlibUpdate * +__imlib_AddUpdate(ImlibUpdate * u, int x, int y, int w, int h) +{ + ImlibUpdate *nu; + + if ((w < 1) || (h < 1) || ((x + w) < 1) || ((y + h) < 1)) + return u; + nu = malloc(sizeof(ImlibUpdate)); + nu->x = x; + nu->y = y; + nu->w = w; + nu->h = h; + nu->next = u; + return nu; +} + +void +__imlib_FreeUpdates(ImlibUpdate * u) +{ + ImlibUpdate *uu; + + uu = u; + while (uu) + { + u = uu; + uu = uu->next; + free(u); + } +} + +ImlibUpdate * +__imlib_DupUpdates(ImlibUpdate * u) +{ + ImlibUpdate *uu, *cu, *pu, *ru; + + if (!u) + return NULL; + + uu = malloc(sizeof(ImlibUpdate)); + memcpy(uu, u, sizeof(ImlibUpdate)); + cu = u->next; + pu = u; + ru = uu; + while (cu) + { + uu = malloc(sizeof(ImlibUpdate)); + memcpy(uu, u, sizeof(ImlibUpdate)); + pu->next = uu; + pu = cu; + cu = cu->next; + } + return ru; +} diff --git a/src/lib/updates.h b/src/lib/updates.h new file mode 100644 index 0000000..4730751 --- /dev/null +++ b/src/lib/updates.h @@ -0,0 +1,16 @@ +#ifndef __UPDATES +#define __UPDATES 1 +typedef struct _imlibupdate ImlibUpdate; + +struct _imlibupdate +{ + int x, y, w, h; + ImlibUpdate *next; +}; + +ImlibUpdate *__imlib_AddUpdate(ImlibUpdate *u, int x, int y, int w, int h); +ImlibUpdate *__imlib_MergeUpdate(ImlibUpdate *u, int w, int h, int hgapmax); +void __imlib_FreeUpdates(ImlibUpdate *u); +ImlibUpdate *__imlib_DupUpdates(ImlibUpdate *u); + +#endif diff --git a/src/lib/ximage.c b/src/lib/ximage.c new file mode 100644 index 0000000..9d43305 --- /dev/null +++ b/src/lib/ximage.c @@ -0,0 +1,330 @@ +#include "common.h" +#ifdef BUILD_X11 +# include +# include +# include +# include +# include +# include "ximage.h" +#endif + +#ifdef BUILD_X11 + +/* static private variables */ +static signed char x_does_shm = -1; +static int list_num = 0; +static XImage **list_xim = NULL; +static XShmSegmentInfo **list_si = NULL; +static Display **list_d = NULL; +static char *list_used = NULL; +static int list_mem_use = 0; +static int list_max_mem = 1024 * 1024 * 1024; +static int list_max_count = 0; + +/* temporary X error catcher we use later */ +static char _x_err = 0; + +/* the fucntion we use for catching the error */ +static void +TmpXError(Display * d, XErrorEvent * ev) +{ + _x_err = 1; + return; + d = NULL; + ev = NULL; +} + +void +__imlib_SetMaxXImageCount(Display * d, int num) +{ + list_max_count = num; + __imlib_FlushXImage(d); +} + +int +__imlib_GetMaxXImageCount(Display * d) +{ + return list_max_count; + d = NULL; +} + +void +__imlib_SetMaxXImageTotalSize(Display * d, int num) +{ + list_max_mem = num; + __imlib_FlushXImage(d); +} + +int +__imlib_GetMaxXImageTotalSize(Display * d) +{ + return list_max_mem; + d = NULL; +} + +void +__imlib_FlushXImage(Display * d) +{ + int i; + XImage *xim; + char did_free = 1; + + while (((list_mem_use > list_max_mem) || (list_num > list_max_count)) && + (did_free)) + { + did_free = 0; + for (i = 0; i < list_num; i++) + { + if (list_used[i] == 0) + { + int j; + + xim = list_xim[i]; + list_mem_use -= xim->bytes_per_line * xim->height; + if (list_si[i]) + XShmDetach(d, list_si[i]); + XDestroyImage(xim); + if (list_si[i]) + { + shmdt(list_si[i]->shmaddr); + shmctl(list_si[i]->shmid, IPC_RMID, 0); + free(list_si[i]); + } + list_num--; + for (j = i; j < list_num; j++) + { + list_xim[j] = list_xim[j + 1]; + list_si[j] = list_si[j + 1]; + list_used[j] = list_used[j + 1]; + list_d[j] = list_d[j + 1]; + } + if (list_num == 0) + { + if (list_xim) + free(list_xim); + if (list_si) + free(list_si); + if (list_used) + free(list_used); + if (list_d) + free(list_d); + list_xim = NULL; + list_si = NULL; + list_used = NULL; + list_d = NULL; + } + else + { + list_xim = + realloc(list_xim, sizeof(XImage *) * list_num); + list_si = + realloc(list_si, + sizeof(XShmSegmentInfo *) * list_num); + list_used = realloc(list_used, sizeof(char) * list_num); + list_d = realloc(list_d, sizeof(Display *) * list_num); + } + did_free = 1; + } + } + } +} + +/* free (consume == opposite of produce) the XImage (mark as unused) */ +void +__imlib_ConsumeXImage(Display * d, XImage * xim) +{ + int i; + + /* march through the XImage list */ + for (i = 0; i < list_num; i++) + { + /* find a match */ + if (list_xim[i] == xim) + { + /* we have a match = mark as unused */ + list_used[i] = 0; + /* flush the XImage list to get rud of stuff we dont want */ + __imlib_FlushXImage(d); + /* return */ + return; + } + } +} + +/* create a new XImage or find it on our list of currently available ones so */ +/* we dont need to create a new one */ +XImage * +__imlib_ProduceXImage(Display * d, Visual * v, int depth, int w, int h, + char *shared) +{ + XImage *xim; + int i; + + /* if we havent check the shm extension before - see if its there */ + if (x_does_shm < 0) + { + /* if its there set dose_xhm flag */ + if (XShmQueryExtension(d)) + x_does_shm = 1; + /* clear the flag - no shm at all */ + else + x_does_shm = 0; + } + /* find a cached XImage (to avoid server to & fro) that is big enough */ + /* for our needs and the right depth */ + *shared = 0; + /* go thru the current image list */ + for (i = 0; i < list_num; i++) + { + int depth_ok = 0; + + /* if the image has the same depth, width and height - recycle it */ + /* as long as its not used */ + if ( (list_xim[i]->bits_per_pixel == depth) || + ((list_xim[i]->bits_per_pixel == 32) && (depth == 24)) ) + depth_ok = 1; + if ( depth_ok && + (list_xim[i]->width >= w) && + (list_xim[i]->height >= h) && + /* (list_d[i] == d) && */ + (!list_used[i])) + { + /* mark it as used */ + list_used[i] = 1; + /* if its shared set shared flag */ + if (list_si[i]) + *shared = 1; + /* return it */ + return list_xim[i]; + } + } + /* can't find a usable XImage on the cache - create one */ + /* add the new XImage to the XImage cache */ + list_num++; + if (list_num == 1) + { + list_xim = malloc(sizeof(XImage *) * list_num); + list_si = malloc(sizeof(XShmSegmentInfo *) * list_num); + list_used = malloc(sizeof(char) * list_num); + list_d = malloc(sizeof(Display *) * list_num); + } + else + { + list_xim = realloc(list_xim, sizeof(XImage *) * list_num); + list_si = realloc(list_si, sizeof(XShmSegmentInfo *) * list_num); + list_used = realloc(list_used, sizeof(char) * list_num); + list_d = realloc(list_d, sizeof(Display *) * list_num); + } + list_si[list_num - 1] = malloc(sizeof(XShmSegmentInfo)); + + /* work on making a shared image */ + xim = NULL; + /* if the server does shm */ + if (x_does_shm) + { + /* try create an shm image */ + xim = XShmCreateImage(d, v, depth, ZPixmap, NULL, + list_si[list_num - 1], w, h); + /* if it succeeds */ + if (xim) + { + /* add to list */ + list_xim[list_num - 1] = xim; + /* get an shm id of this image */ + list_si[list_num - 1]->shmid = + shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, + IPC_CREAT | 0777); + /* if the get succeeds */ + if (list_si[list_num - 1]->shmid != -1) + { + /* set the params for the shm segment */ + list_si[list_num - 1]->readOnly = False; + list_si[list_num - 1]->shmaddr = xim->data = + shmat(list_si[list_num - 1]->shmid, 0, 0); + /* get the shm addr for this data chunk */ + if (xim->data != (char *)-1) + { + XErrorHandler ph; + + /* setup a temporary error handler */ + _x_err = 0; + ph = XSetErrorHandler((XErrorHandler) TmpXError); + /* ask X to attach to the shared mem segment */ + XShmAttach(d, list_si[list_num - 1]); + /* wait for X to reply and do this */ + XSync(d, False); + /* reset the error handler */ + XSetErrorHandler((XErrorHandler) ph); + /* if we attached without an error we're set */ + if (!_x_err) + { + /* mark the image as used */ + list_used[list_num - 1] = 1; + /* incrument our memory count */ + list_mem_use += xim->bytes_per_line * xim->height; + /* set shared flag */ + *shared = 1; + } + /* attach by X failed... must be remote client */ + else + { + /* flag shm foevere to not work - remote */ + x_does_shm = 0; + /* destroy our previous image */ + XDestroyImage(xim); + /* detach */ + shmdt(list_si[list_num - 1]->shmaddr); + /* remove the shm id */ + shmctl(list_si[list_num - 1]->shmid, IPC_RMID, 0); + /* flag out xim as NULL */ + xim = NULL; + } + } + /* get failed - out of shm id's or shm segment too big ? */ + else + { + /* destroy previous image */ + XDestroyImage(xim); + /* remove the shm id we created */ + shmctl(list_si[list_num - 1]->shmid, IPC_RMID, 0); + /* flag xim as NULL */ + xim = NULL; + } + } + /* couldnt create SHM image ? */ + else + { + /* destroy previous image */ + XDestroyImage(xim); + /* flag xim as NULL */ + xim = NULL; + } + } + } + /* ok if xim == NULL it all failed - fall back to XImages */ + if (!xim) + { + /* get rid of out shm info struct */ + free(list_si[list_num - 1]); + /* flag it as NULL ot indicate a normal XImage */ + list_si[list_num - 1] = NULL; + /* create a normal ximage */ + xim = XCreateImage(d, v, depth, ZPixmap, 0, NULL, w, h, 32, 0); + /* allocate data for it */ + xim->data = malloc(xim->bytes_per_line * xim->height); + /* add xim to our list */ + list_xim[list_num - 1] = xim; + /* incriment our memory count */ + list_mem_use += xim->bytes_per_line * xim->height; + /* mark image as used */ + list_used[list_num - 1] = 1; + /* remember what display that XImage was for */ + list_d[list_num - 1] = d; + } + /* flush unused images from the image list */ + __imlib_FlushXImage(d); + /* return out image */ + return xim; +} + +#endif diff --git a/src/lib/ximage.h b/src/lib/ximage.h new file mode 100644 index 0000000..4dc0bac --- /dev/null +++ b/src/lib/ximage.h @@ -0,0 +1,16 @@ +#ifndef __XIMAGE +#define __XIMAGE 1 + +#ifdef BUILD_X11 + +void __imlib_SetMaxXImageCount(Display *d, int num); +int __imlib_GetMaxXImageCount(Display *d); +void __imlib_SetMaxXImageTotalSize(Display *d, int num); +int __imlib_GetMaxXImageTotalSize(Display *d); +void __imlib_FlushXImage(Display *d); +void __imlib_ConsumeXImage(Display *d, XImage *xim); +XImage *__imlib_ProduceXImage(Display *d, Visual *v, int depth, int w, int h, char *shared); + +#endif + +#endif diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am new file mode 100644 index 0000000..7f48e35 --- /dev/null +++ b/src/modules/Makefile.am @@ -0,0 +1,2 @@ +MAINTAINERCLEANFILES = Makefile.in +SUBDIRS = loaders filters diff --git a/src/modules/filters/Makefile.am b/src/modules/filters/Makefile.am new file mode 100644 index 0000000..90b3a81 --- /dev/null +++ b/src/modules/filters/Makefile.am @@ -0,0 +1,21 @@ +MAINTAINERCLEANFILES = Makefile.in +AUTOMAKE_OPTIONS = 1.4 foreign + +INCLUDES = -I. \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/modules/filters \ + @my_includes@ + +pkgdir = $(libdir)/imlib2/filters +pkg_LTLIBRARIES = testfilter.la bumpmap.la colormod.la + +testfilter_la_SOURCES = filter_test.c +testfilter_la_LDFLAGS = $(LDFLAGS) -module -avoid-version + +bumpmap_la_SOURCES = filter_bumpmap.c +bumpmap_la_LDFLAGS = $(LDFLAGS) -module -avoid-version + +colormod_la_SOURCES = filter_colormod.c +colormod_la_LDFLAGS = $(LDFLAGS) -module -avoid-version + diff --git a/src/modules/filters/filter_bumpmap.c b/src/modules/filters/filter_bumpmap.c new file mode 100644 index 0000000..47c7631 --- /dev/null +++ b/src/modules/filters/filter_bumpmap.c @@ -0,0 +1,292 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include + +#ifndef X_DISPLAY_MISSING +# include +# include +# include +#endif + +#include +#include "image.h" +#include "script.h" +#include "dynamic_filters.h" +#include "colormod.h" +#include "blend.h" + +#define PI (4 * atan(1)) + +static Imlib_Image +bump_map(Imlib_Image im, pIFunctionParam par) +{ + Imlib_Image map = im; + pIFunctionParam ptr; + double an = 0, el = 30, d = 0x200; + double red = 0x200, green = 0x200, blue = 0x200; + double ambient = 0; + + int free_map = 0; + DATA32 *src; + DATA32 *mp, *mpy, *mpp; + double z, z_2, x2, y2; + int w, h, i, j, w2, h2, wh2, mx, my; + + for (ptr = par; ptr; ptr = ptr->next) + { + ASSIGN_IMAGE("map", map); + ASSIGN_INT("angle", an); + ASSIGN_INT("elevation", el); + ASSIGN_INT("depth", d); + ASSIGN_INT("red", red); + ASSIGN_INT("green", green); + ASSIGN_INT("blue", blue); + ASSIGN_INT("ambient", ambient); + } + if (!map) + return im; + + red /= 0x100; + green /= 0x100; + blue /= 0x100; + ambient /= 0x100; + d /= 0x100; + + imlib_context_set_image(im); + src = imlib_image_get_data(); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + + imlib_context_set_image(map); + mpp = imlib_image_get_data_for_reading_only(); + w2 = imlib_image_get_width(); + h2 = imlib_image_get_height(); + wh2 = w2 * h2; + + an *= (PI / 180); + el *= (PI / 180); + + x2 = sin(an) * cos(el); + y2 = cos(an) * cos(el); + z = sin(el); + + d /= (255 * (255 + 255 + 255)); + z_2 = z * z; + + my = h2; + for (j = h; --j >= 0;) + { + mp = mpp; + mpp += w2; + if (--my <= 0) + { + mpp -= wh2; + my = h2; + } + mpy = mpp; + mx = w2; + for (i = w; --i >= 0;) + { + double x1, y1, v; + int r, g, b, gr; + + gr = A_VAL(mp) * (R_VAL(mp) + G_VAL(mp) + B_VAL(mp)); + y1 = d * (double)(A_VAL(mpy) * (R_VAL(mpy) + + G_VAL(mpy) + B_VAL(mpy)) - gr); + mp++; + mpy++; + if (--mx <= 0) + { + mp -= w2; + mpy -= w2; + mx = w2; + } + x1 = d * (double)(A_VAL(mp) * (R_VAL(mp) + + G_VAL(mp) + B_VAL(mp)) - gr); + v = x1 * x2 + y1 * y2 + z; + v /= sqrt((x1 * x1) + (y1 * y1) + 1.0); + v += ambient; + r = v * R_VAL(src) * red; + g = v * G_VAL(src) * green; + b = v * B_VAL(src) * blue; + if (r < 0) + r = 0; + if (r > 255) + r = 255; + if (g < 0) + g = 0; + if (g > 255) + g = 255; + if (b < 0) + b = 0; + if (b > 255) + b = 255; + R_VAL(src) = r; + G_VAL(src) = g; + B_VAL(src) = b; + + src++; + } + } + if (free_map) + { + imlib_context_set_image(map); + imlib_free_image(); + } + return im; +} + +static Imlib_Image +bump_map_point(Imlib_Image im, pIFunctionParam par) +{ + Imlib_Image map = im; + pIFunctionParam ptr; + double x = 0, y = 0, z = 30, d = 0x200; + double red = 0x200, green = 0x200, blue = 0x200; + double ambient = 0; + + int free_map = 0; + DATA32 *src; + DATA32 *mp, *mpy, *mpp; + double z_2, x2, y2; + int w, h, i, j, w2, h2, wh2, mx, my; + + for (ptr = par; ptr; ptr = ptr->next) + { + ASSIGN_IMAGE("map", map); + ASSIGN_INT("x", x); + ASSIGN_INT("y", y); + ASSIGN_INT("z", z); + ASSIGN_INT("depth", d); + ASSIGN_INT("red", red); + ASSIGN_INT("green", green); + ASSIGN_INT("blue", blue); + ASSIGN_INT("ambient", ambient); + } + if (!map) + return im; + + red /= 0x100; + green /= 0x100; + blue /= 0x100; + ambient /= 0x100; + d /= 0x100; + + imlib_context_set_image(im); + src = imlib_image_get_data(); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + + imlib_context_set_image(map); + mpp = imlib_image_get_data_for_reading_only(); + w2 = imlib_image_get_width(); + h2 = imlib_image_get_height(); + wh2 = w2 * h2; + + d /= (255 * (255 + 255 + 255)); + z_2 = z * z; + + my = h2; + y2 = -y; + for (j = h; --j >= 0;) + { + mp = mpp; + mpp += w2; + if (--my <= 0) + { + mpp -= wh2; + my = h2; + } + mpy = mpp; + mx = w2; + x2 = -x; + for (i = w; --i >= 0;) + { + double x1, y1, v; + int r, g, b, gr; + + gr = A_VAL(mp) * (R_VAL(mp) + G_VAL(mp) + B_VAL(mp)); + y1 = d * (double)(A_VAL(mpy) * (R_VAL(mpy) + + G_VAL(mpy) + B_VAL(mpy)) - gr); + mp++; + mpy++; + if (--mx <= 0) + { + mp -= w2; + mpy -= w2; + mx = w2; + } + x1 = d * (double)(A_VAL(mp) * (R_VAL(mp) + + G_VAL(mp) + B_VAL(mp)) - gr); + v = x1 * x2 + y1 * y2 + z; + v /= sqrt((x1 * x1) + (y1 * y1) + 1.0); + v /= sqrt((x2 * x2) + (y2 * y2) + z_2); + v += ambient; + r = v * R_VAL(src) * red; + g = v * G_VAL(src) * green; + b = v * B_VAL(src) * blue; + if (r < 0) + r = 0; + if (r > 255) + r = 255; + if (g < 0) + g = 0; + if (g > 255) + g = 255; + if (b < 0) + b = 0; + if (b > 255) + b = 255; + R_VAL(src) = r; + G_VAL(src) = g; + B_VAL(src) = b; + + x2++; + src++; + } + y2++; + } + if (free_map) + { + imlib_context_set_image(map); + imlib_free_image(); + } + return im; +} + +void +init(struct imlib_filter_info *info) +{ + char *filters[] = { "bump_map_point", "bump_map" }; + int i = (sizeof(filters) / sizeof(*filters)); + + info->name = strdup("Bump Mapping"); + info->author = strdup("Willem Monsuwe (willem@stack.nl)"); + info->description = + strdup + ("Provides bumpmapping to a point and bumpmapping from an infinite light source. *very* cool."); + info->num_filters = i; + info->filters = malloc(sizeof(char *) * i); + while (--i >= 0) + info->filters[i] = strdup(filters[i]); + +} + +void +deinit() +{ + return; +} + +void * +exec(char *filter, void *im, pIFunctionParam par) +{ + if (!strcmp(filter, "bump_map")) + return bump_map((Imlib_Image) im, par); + if (!strcmp(filter, "bump_map_point")) + return bump_map_point((Imlib_Image) im, par); + return im; +} diff --git a/src/modules/filters/filter_colormod.c b/src/modules/filters/filter_colormod.c new file mode 100644 index 0000000..1706cbb --- /dev/null +++ b/src/modules/filters/filter_colormod.c @@ -0,0 +1,269 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include + +#ifndef X_DISPLAY_MISSING +# include +# include +# include +#endif + +#include +#include "image.h" +#include "script.h" +#include "dynamic_filters.h" + +#define GET_INT(x, ptr) (((ptr)->type == VAR_PTR) ? \ + (x) = (*(int *)(ptr)->data) : \ + ((ptr)->type == VAR_CHAR) ? \ + (x) = strtol((ptr)->data, 0, 0) \ + : 0) + +#define GET_DOUBLE(x, ptr) (((ptr)->type == VAR_PTR) ? \ + (x) = (*(double *)(ptr)->data) : \ + ((ptr)->type == VAR_CHAR) ? \ + (x) = strtod((ptr)->data, 0) \ + : 0) + +static void +mod_brightness(double t[256], double v) +{ + int i; + + for (i = 256; --i >= 0;) + t[i] += v; +} + +static void +mod_contrast(double t[256], double v) +{ + int i; + + for (i = 256; --i >= 0;) + t[i] = ((t[i] - 0.5) * v) + 0.5; +} + +static void +mod_gamma(double t[256], double v) +{ + int i; + + for (i = 256; --i >= 0;) + t[i] = pow(t[i], 1 / v); +} + +static void +mod_tint(double t[256], double v) +{ + int i; + + for (i = 256; --i >= 0;) + t[i] *= v; +} + +static Imlib_Image +colormod(Imlib_Image im, pIFunctionParam par) +{ + double a_d[256], r_d[256], g_d[256], b_d[256]; + DATA8 a_b[256], r_b[256], g_b[256], b_b[256]; + pIFunctionParam ptr; + int x = 0, y = 0, h, w, i; + double v = 0.0; + + imlib_context_set_image(im); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + + for (i = 256; --i >= 0;) + a_d[i] = r_d[i] = g_d[i] = b_d[i] = (double)i / 255; + + for (ptr = par; ptr; ptr = ptr->next) + { + if (!strcmp("x", ptr->key)) + { + GET_INT(x, ptr); + } + else if (!strcmp("y", ptr->key)) + { + GET_INT(y, ptr); + } + else if (!strcmp("w", ptr->key)) + { + GET_INT(w, ptr); + } + else if (!strcmp("h", ptr->key)) + { + GET_INT(h, ptr); + } + else if (!memcmp("brightness", ptr->key, 10)) + { + GET_DOUBLE(v, ptr); + if (!ptr->key[10]) + { + mod_brightness(r_d, v); + mod_brightness(g_d, v); + mod_brightness(b_d, v); + mod_brightness(a_d, v); + } + else if (!strcmp("_r", ptr->key + 10)) + { + mod_brightness(r_d, v); + } + else if (!strcmp("_g", ptr->key + 10)) + { + mod_brightness(g_d, v); + } + else if (!strcmp("_b", ptr->key + 10)) + { + mod_brightness(b_d, v); + } + else if (!strcmp("_a", ptr->key + 10)) + { + mod_brightness(a_d, v); + } + } + else if (!memcmp("contrast", ptr->key, 8)) + { + GET_DOUBLE(v, ptr); + if (!ptr->key[8]) + { + mod_contrast(r_d, v); + mod_contrast(g_d, v); + mod_contrast(b_d, v); + mod_contrast(a_d, v); + } + else if (!strcmp("_r", ptr->key + 8)) + { + mod_contrast(r_d, v); + } + else if (!strcmp("_g", ptr->key + 8)) + { + mod_contrast(g_d, v); + } + else if (!strcmp("_b", ptr->key + 8)) + { + mod_contrast(b_d, v); + } + else if (!strcmp("_a", ptr->key + 8)) + { + mod_contrast(a_d, v); + } + } + else if (!memcmp("gamma", ptr->key, 5)) + { + GET_DOUBLE(v, ptr); + if (!ptr->key[5]) + { + mod_gamma(r_d, v); + mod_gamma(g_d, v); + mod_gamma(b_d, v); + mod_gamma(a_d, v); + } + else if (!strcmp("_r", ptr->key + 5)) + { + mod_gamma(r_d, v); + } + else if (!strcmp("_g", ptr->key + 5)) + { + mod_gamma(g_d, v); + } + else if (!strcmp("_b", ptr->key + 5)) + { + mod_gamma(b_d, v); + } + else if (!strcmp("_a", ptr->key + 5)) + { + mod_gamma(a_d, v); + } + } + else if (!memcmp("tint", ptr->key, 4)) + { + GET_DOUBLE(v, ptr); + if (!ptr->key[4]) + { + mod_tint(r_d, v); + mod_tint(g_d, v); + mod_tint(b_d, v); + mod_tint(a_d, v); + } + else if (!strcmp("_r", ptr->key + 4)) + { + mod_tint(r_d, v); + } + else if (!strcmp("_g", ptr->key + 4)) + { + mod_tint(g_d, v); + } + else if (!strcmp("_b", ptr->key + 4)) + { + mod_tint(b_d, v); + } + else if (!strcmp("_a", ptr->key + 4)) + { + mod_tint(a_d, v); + } + } + } + for (i = 256; --i >= 0;) + { + if (a_d[i] < 0) + a_d[i] = 0; + if (a_d[i] > 1) + a_d[i] = 1; + a_b[i] = a_d[i] * 255; + if (r_d[i] < 0) + r_d[i] = 0; + if (r_d[i] > 1) + r_d[i] = 1; + r_b[i] = r_d[i] * 255; + if (g_d[i] < 0) + g_d[i] = 0; + if (g_d[i] > 1) + g_d[i] = 1; + g_b[i] = g_d[i] * 255; + if (b_d[i] < 0) + b_d[i] = 0; + if (b_d[i] > 1) + b_d[i] = 1; + b_b[i] = b_d[i] * 255; + } + imlib_context_set_color_modifier(imlib_create_color_modifier()); + imlib_set_color_modifier_tables(r_b, g_b, b_b, a_b); + imlib_apply_color_modifier_to_rectangle(x, y, w, h); + imlib_free_color_modifier(); + return im; +} + +void +init(struct imlib_filter_info *info) +{ + char *filters[] = { "colormod" }; + int i = (sizeof(filters) / sizeof(*filters)); + + info->name = strdup("Tinting"); + info->author = strdup("Willem Monsuwe (willem@stack.nl)"); + info->description = + strdup("Provides most common color modification filters."); + info->num_filters = i; + info->filters = malloc(sizeof(char *) * i); + while (--i >= 0) + info->filters[i] = strdup(filters[i]); + +} + +void +deinit() +{ + return; +} + +void * +exec(char *filter, void *im, pIFunctionParam par) +{ + if (!strcmp(filter, "colormod")) + return colormod((Imlib_Image) im, par); + return im; +} diff --git a/src/modules/filters/filter_test.c b/src/modules/filters/filter_test.c new file mode 100644 index 0000000..cc9f448 --- /dev/null +++ b/src/modules/filters/filter_test.c @@ -0,0 +1,115 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include +#include "image.h" +#include "script.h" +#include "dynamic_filters.h" + +void init(struct imlib_filter_info *info); +void deinit(void); +void *exec(char *filter, void *im, pIFunctionParam params); + +void +init(struct imlib_filter_info *info) +{ + char *filters[] = { "tint", "cool_text", "gradient" }; + int i = 0; + + info->name = strdup("Test Filter"); + info->author = strdup("Chris Ross - Boris - chris@darkrock.co.uk"); + info->description = + strdup + ("This filter is used to show that the imlib2 filter system works!"); + info->num_filters = 3; + info->filters = malloc(sizeof(char *) * 3); + for (i = 0; i < info->num_filters; i++) + info->filters[i] = strdup(filters[i]); + +} + +void +deinit(void) +{ + return; +} + +void * +exec(char *filter, void *im, pIFunctionParam params) +{ + Imlib_Image imge = im; + Imlib_Image anoim; + IFunctionParam *ptr; + + if (strcmp(filter, "tint") == 0) + { + Imlib_Color_Modifier cm; + DATA8 atab[256]; + int x = 0, y = 0, w = 0, h = 0; + DATA8 r = 255, b = 255, g = 255, a = 255; + +/* + printf( "filter_test.c: tint called\n" ); + */ + /* Set friendly defaults */ + imlib_context_set_image(imge); + w = imlib_image_get_width(); + h = imlib_image_get_height(); + + for (ptr = params; ptr != NULL; ptr = ptr->next) + { + ASSIGN_DATA8("red", r); + ASSIGN_DATA8("blue", b); + ASSIGN_DATA8("green", g); + ASSIGN_INT("x", x); + ASSIGN_INT("y", y); + ASSIGN_INT("w", w); + ASSIGN_INT("h", h); + ASSIGN_DATA8("alpha", a); + } +/* + printf( "Using values red=%d,blue=%d,green=%d,x=%d,y=%d,height=%d,width=%d,alpha=%d\n", r,b,g,x,y,w,h,a ); + */ + anoim = imlib_create_image(w, h); + cm = imlib_create_color_modifier(); + imlib_context_set_color_modifier(cm); + imlib_context_set_image(anoim); + + imlib_context_set_color(r, g, b, 255); + imlib_image_fill_rectangle(0, 0, w, h); + imlib_context_set_blend(1); + imlib_image_set_has_alpha(1); + + memset(atab, a, sizeof(atab)); + imlib_set_color_modifier_tables(NULL, NULL, NULL, atab); + imlib_apply_color_modifier_to_rectangle(0, 0, w, h); + + imlib_context_set_image(imge); + imlib_blend_image_onto_image(anoim, 0, 0, 0, w, h, x, y, w, h); + + imlib_free_color_modifier(); + imlib_context_set_image(anoim); + imlib_free_image_and_decache(); + imlib_context_set_image(imge); + + return imge; + } + + if (strcmp(filter, "cool_text") == 0) + { + return imge; + } + if (strcmp(filter, "gradient") == 0) + { + int angle = 0; + + for (ptr = params; ptr != NULL; ptr = ptr->next) + { + ASSIGN_INT("angle", angle); + } + return imge; + } + return imge; +} diff --git a/src/modules/loaders/Makefile.am b/src/modules/loaders/Makefile.am new file mode 100644 index 0000000..2d6b596 --- /dev/null +++ b/src/modules/loaders/Makefile.am @@ -0,0 +1,91 @@ +MAINTAINERCLEANFILES = Makefile.in +AUTOMAKE_OPTIONS = 1.4 foreign + +INCLUDES = -I. \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/modules/loaders \ + @my_includes@ + +pkgdir = $(libdir)/imlib2/loaders + +if BUILD_JPEG_LOADER +JPEG_L = jpeg.la +endif +if BUILD_PNG_LOADER +PNG_L = png.la +endif +if BUILD_TIFF_LOADER +TIFF_L = tiff.la +endif +if BUILD_GIF_LOADER +GIF_L = gif.la +endif +if BUILD_ZLIB_LOADER +ZLIB_L = zlib.la +endif +if BUILD_BZ2_LOADER +BZ2_L = bz2.la +endif + +pkg_LTLIBRARIES = \ +$(JPEG_L) \ +$(PNG_L) \ +$(TIFF_L) \ +$(GIF_L) \ +$(ZLIB_L) \ +$(BZ2_L) \ +pnm.la \ +argb.la \ +bmp.la \ +xpm.la \ +tga.la \ +lbm.la + +jpeg_la_SOURCES = loader_jpeg.c +jpeg_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +jpeg_la_LIBADD = @JPEGLIBS@ + +png_la_SOURCES = loader_png.c +png_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +png_la_LIBADD = @PNGLIBS@ + +tiff_la_SOURCES = loader_tiff.c +tiff_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +tiff_la_LIBADD = @TIFFLIBS@ + +gif_la_SOURCES = loader_gif.c +gif_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +gif_la_LIBADD = @GIFLIBS@ + +zlib_la_SOURCES = loader_zlib.c +zlib_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +zlib_la_LIBADD = @ZLIBLIBS@ + +bz2_la_SOURCES = loader_bz2.c +bz2_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +bz2_la_LIBADD = @BZ2LIBS@ + +pnm_la_SOURCES = loader_pnm.c +pnm_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +pnm_la_LIBADD = + +argb_la_SOURCES = loader_argb.c +argb_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +argb_la_LIBADD = + +bmp_la_SOURCES = loader_bmp.c +bmp_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +bmp_la_LIBADD = + +xpm_la_SOURCES = loader_xpm.c +xpm_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +xpm_la_LIBADD = + +tga_la_SOURCES = loader_tga.c +tga_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +tga_la_LIBADD = + +lbm_la_SOURCES = loader_lbm.c +lbm_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +lbm_la_LIBADD = diff --git a/src/modules/loaders/loader_argb.c b/src/modules/loaders/loader_argb.c new file mode 100644 index 0000000..20c33aa --- /dev/null +++ b/src/modules/loaders/loader_argb.c @@ -0,0 +1,201 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include + +#ifndef X_DISPLAY_MISSING +# include +# include +# include +#endif + +#include "image.h" + +char load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity); +void formats(ImlibLoader * l); + +#define SWAP32(x) (x) = \ +((((x) & 0x000000ff ) << 24) |\ + (((x) & 0x0000ff00 ) << 8) |\ + (((x) & 0x00ff0000 ) >> 8) |\ + (((x) & 0xff000000 ) >> 24)) + +char +load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) +{ + int w, h, alpha; + FILE *f; + + if (im->data) + return 0; + f = fopen(im->real_file, "rb"); + if (!f) + return 0; + + /* header */ + { + char buf[256], buf2[256]; + + if (!fgets(buf, 255, f)) + { + fclose(f); + return 0; + } + sscanf(buf, "%s %i %i %i", buf2, &w, &h, &alpha); + if (strcmp(buf2, "ARGB")) + { + fclose(f); + return 0; + } + im->w = w; + im->h = h; + if (!im->format) + { + if (alpha) + SET_FLAG(im->flags, F_HAS_ALPHA); + else + UNSET_FLAG(im->flags, F_HAS_ALPHA); + im->format = strdup("argb"); + } + } + if (((!im->data) && (im->loader)) || (immediate_load) || (progress)) + { + DATA32 *ptr; + int y, pl = 0; + char pper = 0; + + /* must set the im->data member before callign progress function */ + ptr = im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + fclose(f); + return 0; + } + for (y = 0; y < h; y++) + { +#ifdef WORDS_BIGENDIAN + { + int x; + + fread(ptr, im->w, 4, f); + for (x = 0; x < im->w; x++) + SWAP32(ptr[x]); + } +#else + fread(ptr, im->w, 4, f); +#endif + ptr += im->w; + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || + (y == (im->h - 1))) + { + l = y - pl; + if (!progress(im, per, 0, (y - l), im->w, l)) + { + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + } + fclose(f); + return 1; +} + +char +save(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity) +{ + FILE *f; + DATA32 *ptr; + int y, pl = 0, alpha = 0; + char pper = 0; + +#ifdef WORDS_BIGENDIAN + DATA32 *buf = (DATA32 *) malloc(im->w * 4); +#endif + + /* no image data? abort */ + if (!im->data) + return 0; + f = fopen(im->real_file, "wb"); + if (!f) + return 0; + if (im->flags & F_HAS_ALPHA) + alpha = 1; + fprintf(f, "ARGB %i %i %i\n", im->w, im->h, alpha); + ptr = im->data; + for (y = 0; y < im->h; y++) + { +#ifdef WORDS_BIGENDIAN + { + int x; + + memcpy(buf, ptr, im->w * 4); + for (x = 0; x < im->w; x++) + SWAP32(buf[x]); + fwrite(buf, im->w, 4, f); + } +#else + fwrite(ptr, im->w, 4, f); +#endif + ptr += im->w; + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || (y == (im->h - 1))) + { + l = y - pl; + if (!progress(im, per, 0, (y - l), im->w, l)) + { +#ifdef WORDS_BIGENDIAN + if (buf) + free(buf); +#endif + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + /* finish off */ +#ifdef WORDS_BIGENDIAN + if (buf) + free(buf); +#endif + fclose(f); + return 1; +} + +void +formats(ImlibLoader * l) +{ + char *list_formats[] = { "argb", "arg" }; + + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof(char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} diff --git a/src/modules/loaders/loader_bmp.c b/src/modules/loaders/loader_bmp.c new file mode 100644 index 0000000..46f445a --- /dev/null +++ b/src/modules/loaders/loader_bmp.c @@ -0,0 +1,739 @@ +/* + * Based off of Peter Alm's BMP loader from xmms, with additions from + * imlib's old BMP loader + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include +#include + +#ifndef X_DISPLAY_MISSING +# include +# include +# include +#endif + +#include "image.h" + +char load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity); +void formats(ImlibLoader * l); + +typedef struct tagRGBQUAD { + unsigned char rgbBlue; + unsigned char rgbGreen; + unsigned char rgbRed; + unsigned char rgbReserved; +} RGBQUAD; + +#define BI_RGB 0 +#define BI_RLE8 1 +#define BI_RLE4 2 +#define BI_BITFIELDS 3 + +static int +ReadleShort(FILE * file, unsigned short *ret) +{ + unsigned char b[2]; + + if (fread(b, sizeof(unsigned char), 2, file) != 2) + return 0; + + *ret = (b[1] << 8) | b[0]; + return 1; +} + +static int +ReadleLong(FILE * file, unsigned long *ret) +{ + unsigned char b[4]; + + if (fread(b, sizeof(unsigned char), 4, file) != 4) + return 0; + + *ret = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]; + return 1; +} + +char +load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) +{ + FILE *f; + char pper = 0; + int pl = 0; + char type[2]; + unsigned long size, offset, headSize, comp, imgsize, j, k, l; + unsigned short tmpShort, planes, bitcount, ncols, skip; + unsigned char tempchar, byte = 0, g, b, r; + unsigned long i, w, h; + unsigned short x, y; + DATA32 *ptr, *data_end; + unsigned char *buffer_ptr, *buffer, *buffer_end; + RGBQUAD rgbQuads[256]; + unsigned long rmask = 0xff, gmask = 0xff, bmask = 0xff; + unsigned long rshift = 0, gshift = 0, bshift = 0; + + if (im->data) + return 0; + f = fopen(im->real_file, "rb"); + if (!f) + return 0; + + /* header */ + { + struct stat statbuf; + + if (stat(im->real_file, &statbuf) == -1) + { + fclose(f); + return 0; + } + size = statbuf.st_size; + + if (fread(type, 1, 2, f) != 2) + { + fclose(f); + return 0; + } + if (strncmp(type, "BM", 2)) + { + fclose(f); + return 0; + } + + fseek(f, 8, SEEK_CUR); + ReadleLong(f, &offset); + ReadleLong(f, &headSize); + if (offset >= size) + { + fclose(f); + return 0; + } + if (headSize == 12) + { + ReadleShort(f, &tmpShort); + w = tmpShort; + ReadleShort(f, &tmpShort); + h = tmpShort; + ReadleShort(f, &planes); + ReadleShort(f, &bitcount); + imgsize = size - offset; + comp = BI_RGB; + } + else if (headSize == 40) + { + ReadleLong(f, &w); + ReadleLong(f, &h); + ReadleShort(f, &planes); + ReadleShort(f, &bitcount); + ReadleLong(f, &comp); + ReadleLong(f, &imgsize); + imgsize = size - offset; + + fseek(f, 16, SEEK_CUR); + } + else + { + fclose(f); + return 0; + } + + if ((w > 8192) || (h > 8192)) + { + fclose(f); + return 0; + } + + if (bitcount < 16) + { + ncols = (offset - headSize - 14); + if (headSize == 12) + { + ncols /= 3; + if (ncols > 256) ncols = 256; + for (i = 0; i < ncols; i++) + fread(&rgbQuads[i], 3, 1, f); + } + else + { + ncols /= 4; + if (ncols > 256) ncols = 256; + fread(rgbQuads, 4, ncols, f); + } + } + else if (bitcount == 16 || bitcount == 32) + { + if (comp == BI_BITFIELDS) + { + int bit; + + ReadleLong(f, &bmask); + ReadleLong(f, &gmask); + ReadleLong(f, &rmask); + for (bit = bitcount - 1; bit >= 0; bit--) + { + if (bmask & (1 << bit)) + bshift = bit; + if (gmask & (1 << bit)) + gshift = bit; + if (rmask & (1 << bit)) + rshift = bit; + } + } + else if (bitcount == 16) + { + rmask = 0x7C00; + gmask = 0x03E0; + bmask = 0x001F; + rshift = 10; + gshift = 5; + bshift = 0; + } + else if (bitcount == 32) + { + rmask = 0x00FF0000; + gmask = 0x0000FF00; + bmask = 0x000000FF; + rshift = 16; + gshift = 8; + bshift = 0; + } + } + + im->w = w; + im->h = h; + if (!im->format) + { + UNSET_FLAG(im->flags, F_HAS_ALPHA); + im->format = strdup("bmp"); + } + } + if (((!im->data) && (im->loader)) || (immediate_load) || (progress)) + { + fseek(f, offset, SEEK_SET); + buffer = malloc(imgsize); + if (!buffer) + { + fclose(f); + return 0; + } + im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + fclose(f); + free(buffer); + return 0; + } + + fread(buffer, imgsize, 1, f); + fclose(f); + buffer_ptr = buffer; + buffer_end = buffer + imgsize; + + data_end = im->data + w * h; + ptr = im->data + ((h - 1) * w); + + if (bitcount == 1) + { + if (comp == BI_RGB) + { + skip = ((((w + 31) / 32) * 32) - w) / 8; + for (y = 0; y < h; y++) + { + for (x = 0; x < w && buffer_ptr < buffer_end; x++) + { + if ((x & 7) == 0) + byte = *(buffer_ptr++); + k = (byte >> 7) & 1; + *ptr++ = 0xff000000 | + (rgbQuads[k].rgbRed << 16) | + (rgbQuads[k].rgbGreen << 8) | + rgbQuads[k].rgbBlue; + byte <<= 1; + } + buffer_ptr += skip; + ptr -= w * 2; + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || + (y == (im->h - 1))) + { + l = y - pl; + if (!progress + (im, per, 0, im->h - y - 1, im->w, + im->h - y + l)) + { + free(buffer); + return 2; + } + pper = per; + pl = y; + } + } + } + } + } + if (bitcount == 4) + { + if (comp == BI_RLE4) + { + x = 0; + y = 0; + + for (i = 0, g = 1; + i < imgsize && g && buffer_ptr < buffer_end; i++) + { + byte = *(buffer_ptr++); + if (byte) + { + unsigned char t1, t2; + + l = byte; + byte = *(buffer_ptr++); + t1 = byte & 0xF; + t2 = (byte >> 4) & 0xF; + for (j = 0; j < l; j++) + { + k = (j & 1) ? t1 : t2; + + if (x >= w) + break; + + *ptr++ = 0xff000000 | + (rgbQuads[k].rgbRed << 16) | + (rgbQuads[k].rgbGreen << 8) | + rgbQuads[k].rgbBlue; + x++; + if (ptr > data_end) + ptr = data_end; + } + } + else + { + byte = *(buffer_ptr++); + switch (byte) + { + case 0: + x = 0; + y++; + ptr = im->data + ((h - y - 1) + * w * sizeof(DATA32)); + if (ptr > data_end) + ptr = data_end; + break; + case 1: + g = 0; + break; + case 2: + x += *(buffer_ptr++); + y += *(buffer_ptr++); + ptr = im->data + ((h - y - 1) * w * + sizeof(DATA32)) + x; + if (ptr > data_end) + ptr = data_end; + break; + default: + l = byte; + for (j = 0; j < l; j++) + { + char t1 = '\0', t2 = + '\0'; + + if ((j & 1) == 0) + { + byte = *(buffer_ptr++); + t1 = byte & 0xF; + t2 = (byte >> 4) & 0xF; + } + k = (j & 1) ? t1 : t2; + + if (x >= w) + { + buffer_ptr += (l - j) / 2; + break; + } + + *ptr++ = 0xff000000 | + (rgbQuads[k].rgbRed << 16) | + (rgbQuads[k].rgbGreen << 8) | + rgbQuads[k].rgbBlue; + x++; + + if (ptr > data_end) + ptr = data_end; + + } + + if ((l & 3) == 1) + { + tempchar = *(buffer_ptr++); + tempchar = *(buffer_ptr++); + } + else if ((l & 3) == 2) + buffer_ptr++; + break; + } + } + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || + (y == (im->h - 1))) + { + l = y - pl; + if (!progress + (im, per, 0, im->h - y - 1, im->w, + im->h - y + l)) + { + free(buffer); + return 2; + } + pper = per; + pl = y; + } + } + + } + } + else if (comp == BI_RGB) + { + skip = ((((w + 7) / 8) * 8) - w) / 2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w && buffer_ptr < buffer_end; x++) + { + if ((x & 1) == 0) + byte = *(buffer_ptr++); + k = (byte & 0xF0) >> 4; + *ptr++ = 0xff000000 | + (rgbQuads[k].rgbRed << 16) | + (rgbQuads[k].rgbGreen << 8) | + rgbQuads[k].rgbBlue; + byte <<= 4; + } + buffer_ptr += skip; + ptr -= w * 2; + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || + (y == (im->h - 1))) + { + l = y - pl; + if (!progress + (im, per, 0, im->h - y - 1, im->w, + im->h - y + l)) + { + free(buffer); + return 2; + } + pper = per; + pl = y; + } + } + } + } + } + if (bitcount == 8) + { + if (comp == BI_RLE8) + { + x = 0; + y = 0; + for (i = 0, g = 1; + i < imgsize && buffer_ptr < buffer_end && g; i++) + { + byte = *(buffer_ptr++); + if (byte) + { + l = byte; + byte = *(buffer_ptr++); + for (j = 0; j < l; j++) + { + if (x >= w) + break; + + *ptr++ = 0xff000000 | + (rgbQuads[byte].rgbRed << 16) | + (rgbQuads[byte].rgbGreen << 8) | + rgbQuads[byte].rgbBlue; + + x++; + if (ptr > data_end) + ptr = data_end; + } + } + else + { + byte = *(buffer_ptr++); + switch (byte) + { + case 0: + x = 0; + y++; + ptr = im->data + ((h - y - 1) + * w * sizeof(DATA32)); + if (ptr > data_end) + ptr = data_end; + break; + case 1: + g = 0; + break; + case 2: + x += *(buffer_ptr++); + y += *(buffer_ptr++); + ptr = im->data + ((h - y - 1) + * w * + sizeof(DATA32)) + + (x * sizeof(DATA32)); + if (ptr > data_end) + ptr = data_end; + break; + default: + l = byte; + for (j = 0; j < l; j++) + { + byte = *(buffer_ptr++); + + if (x >= w) + { + buffer_ptr += l - j; + break; + } + + *ptr++ = 0xff000000 | + (rgbQuads[byte].rgbRed << 16) | + (rgbQuads[byte].rgbGreen << 8) | + rgbQuads[byte].rgbBlue; + x++; + + if (ptr > data_end) + ptr = data_end; + } + if (l & 1) + buffer_ptr++; + break; + } + } + } + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || + (y == (im->h - 1))) + { + l = y - pl; + if (!progress + (im, per, 0, im->h - y - 1, im->w, + im->h - y + l)) + { + free(buffer); + return 2; + } + pper = per; + pl = y; + } + } + } + else if (comp == BI_RGB) + { + skip = (((w + 3) / 4) * 4) - w; + for (y = 0; y < h; y++) + { + for (x = 0; x < w && buffer_ptr < buffer_end; x++) + { + byte = *(buffer_ptr++); + *ptr++ = 0xff000000 | + (rgbQuads[byte].rgbRed << 16) | + (rgbQuads[byte].rgbGreen << 8) | + rgbQuads[byte].rgbBlue; + } + ptr -= w * 2; + buffer_ptr += skip; + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || + (y == (im->h - 1))) + { + l = y - pl; + if (!progress + (im, per, 0, im->h - y - 1, im->w, + im->h - y + l)) + { + free(buffer); + return 2; + } + pper = per; + pl = y; + } + } + } + } + + } + else if (bitcount == 16) + { + skip = (((w * 16 + 31) / 32) * 4) - (w * 2); + for (y = 0; y < h; y++) + { + for (x = 0; x < w && buffer_ptr < buffer_end; x++) + { + r = ((unsigned short)(*buffer_ptr) & rmask) >> rshift; + g = ((unsigned short)(*buffer_ptr) & gmask) >> gshift; + b = ((unsigned short)(*(buffer_ptr++)) & bmask) >> + bshift; + *ptr++ = 0xff000000 | (r << 16) | (g << 8) | b; + } + ptr -= w * 2; + buffer_ptr += skip; + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || + (y == (im->h - 1))) + { + l = y - pl; + if (!progress + (im, per, 0, im->h - y - 1, im->w, + im->h - y + l)) + { + free(buffer); + return 2; + } + pper = per; + pl = y; + } + } + } + } + else if (bitcount == 24) + { + skip = (4 - ((w * 3) % 4)) & 3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w && buffer_ptr < buffer_end; x++) + { + b = *(buffer_ptr++); + g = *(buffer_ptr++); + r = *(buffer_ptr++); + *ptr++ = 0xff000000 | (r << 16) | (g << 8) | b; + } + ptr -= w * 2; + buffer_ptr += skip; + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || + (y == (im->h - 1))) + { + l = y - pl; + if (!progress + (im, per, 0, im->h - y - 1, im->w, + im->h - y + l)) + { + free(buffer); + return 2; + } + pper = per; + pl = y; + } + } + } + } + else if (bitcount == 32) + { + skip = (((w * 32 + 31) / 32) * 4) - (w * 4); + for (y = 0; y < h; y++) + { + for (x = 0; x < w && buffer_ptr < buffer_end; x++) + { + r = ((unsigned long)(*buffer_ptr) & rmask) >> rshift; + g = ((unsigned long)(*buffer_ptr) & gmask) >> gshift; + b = ((unsigned long)(*buffer_ptr) & bmask) >> bshift; + *ptr++ = 0xff000000 | (r << 16) | (g << 8) | b; + r = *(buffer_ptr++); + r = *(buffer_ptr++); + } + ptr -= w * 2; + buffer_ptr += skip; + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || + (y == (im->h - 1))) + { + l = y - pl; + if (!progress + (im, per, 0, im->h - y - 1, im->w, + im->h - y + l)) + { + free(buffer); + return 2; + } + pper = per; + pl = y; + } + } + } + } + free(buffer); + } + return 1; +} + +#if 0 +char +save(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity) +{ + /* TODO */ + return 0; +} +#endif + +void +formats(ImlibLoader * l) +{ + char *list_formats[] = { "bmp" }; + + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof(char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} diff --git a/src/modules/loaders/loader_bz2.c b/src/modules/loaders/loader_bz2.c new file mode 100644 index 0000000..dcc484d --- /dev/null +++ b/src/modules/loaders/loader_bz2.c @@ -0,0 +1,107 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "image.h" + +#define OUTBUF_SIZE 16384 +#define INBUF_SIZE 1024 + +static int uncompress_file (FILE *fp, int dest) +{ + BZFILE *bf; + DATA8 outbuf[OUTBUF_SIZE]; + int bytes, error; + + bf = BZ2_bzReadOpen (&error, fp, 0, 0, NULL, 0); + + if (error != BZ_OK) { + BZ2_bzReadClose (NULL, bf); + return 0; + } + + error = BZ_OK; + + while (error == BZ_OK) { + bytes = BZ2_bzRead (&error, bf, &outbuf, OUTBUF_SIZE); + + if (error == BZ_OK) + write (dest, outbuf, bytes); + } + + BZ2_bzReadClose (&error, bf); + + return 1; +} + +char load (ImlibImage *im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) +{ + ImlibLoader *loader; + FILE *fp; + int dest, res; + char *file, tmp[] = "/tmp/imlib2_loader_bz2-XXXXXX"; + + assert (im); + + /* we'll need a copy of it later */ + file = im->real_file; + + if ((dest = mkstemp (tmp)) < 0) + return 0; + + if (!(fp = fopen (im->real_file, "rb"))) { + unlink (tmp); + return 0; + } + + res = uncompress_file (fp, dest); + fclose (fp); + close (dest); + + if (!res) { + unlink (tmp); + return 0; + } + + if (!(loader = __imlib_FindBestLoaderForFile (tmp, 0))) { + unlink (tmp); + return 0; + } + + free (im->real_file); + im->real_file = strdup (tmp); + loader->load (im, progress, progress_granularity, immediate_load); + + free (im->real_file); + im->real_file = strdup (file); + unlink (tmp); + + return 1; +} + +void formats (ImlibLoader *l) +{ + /* this is the only bit you have to change... */ + char *list_formats[] = {"bz2"}; + int i; + + /* don't bother changing any of this - it just reads this in + * and sets the struct values and makes copies + */ + l->num_formats = sizeof (list_formats) / sizeof (char *); + l->formats = malloc (sizeof (char *) * l->num_formats); + + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup (list_formats[i]); +} diff --git a/src/modules/loaders/loader_gif.c b/src/modules/loaders/loader_gif.c new file mode 100644 index 0000000..b8809fb --- /dev/null +++ b/src/modules/loaders/loader_gif.c @@ -0,0 +1,247 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include +#include +#include +#include +#include + +#ifndef X_DISPLAY_MISSING +# include +# include +# include +#endif + +#include "image.h" +#include + +char load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity); +void formats(ImlibLoader * l); + +char +load(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity, + char immediate_load) +{ + DATA32 *ptr; + GifFileType *gif; + GifRowType *rows; + GifRecordType rec; + ColorMapObject *cmap; + int i, j, done, bg, r, g, b, w = 0, h = 0; + float per = 0.0, per_inc; + int last_per = 0, last_y = 0; + int intoffset[] = { 0, 4, 2, 1 }; + int intjump[] = { 8, 8, 4, 2 }; + int transp; + int fd; + + done = 0; + rows = NULL; + transp = -1; + + /* if immediate_load is 1, then dont delay image laoding as below, or */ + /* already data in this image - dont load it again */ + if (im->data) + return 0; +#ifndef __EMX__ + fd = open(im->real_file, O_RDONLY); +#else + fd = open(im->real_file, O_RDONLY | O_BINARY); +#endif + if (fd < 0) + return 0; + gif = DGifOpenFileHandle(fd); + if (!gif) + { + close(fd); + return 0; + } + do + { + if (DGifGetRecordType(gif, &rec) == GIF_ERROR) + { + /* PrintGifError(); */ + rec = TERMINATE_RECORD_TYPE; + } + if ((rec == IMAGE_DESC_RECORD_TYPE) && (!done)) + { + if (DGifGetImageDesc(gif) == GIF_ERROR) + { + /* PrintGifError(); */ + rec = TERMINATE_RECORD_TYPE; + } + w = gif->Image.Width; + h = gif->Image.Height; + rows = malloc(h * sizeof(GifRowType *)); + if (!rows) + { + DGifCloseFile(gif); + return 0; + } + for (i = 0; i < h; i++) + { + rows[i] = NULL; + } + for (i = 0; i < h; i++) + { + rows[i] = malloc(w * sizeof(GifPixelType)); + if (!rows[i]) + { + DGifCloseFile(gif); + for (i = 0; i < h; i++) + { + if (rows[i]) + { + free(rows[i]); + } + } + free(rows); + return 0; + } + } + if (gif->Image.Interlace) + { + for (i = 0; i < 4; i++) + { + for (j = intoffset[i]; j < h; j += intjump[i]) + { + DGifGetLine(gif, rows[j], w); + } + } + } + else + { + for (i = 0; i < h; i++) + { + DGifGetLine(gif, rows[i], w); + } + } + done = 1; + } + else if (rec == EXTENSION_RECORD_TYPE) + { + int ext_code; + GifByteType *ext; + + ext = NULL; + DGifGetExtension(gif, &ext_code, &ext); + while (ext) + { + if ((ext_code == 0xf9) && (ext[1] & 1) && (transp < 0)) + { + transp = (int)ext[4]; + } + ext = NULL; + DGifGetExtensionNext(gif, &ext); + } + } + } while (rec != TERMINATE_RECORD_TYPE); + if (transp >= 0) + { + SET_FLAG(im->flags, F_HAS_ALPHA); + } + else + { + UNSET_FLAG(im->flags, F_HAS_ALPHA); + } + /* set the format string member to the lower-case full extension */ + /* name for the format - so example names would be: */ + /* "png", "jpeg", "tiff", "ppm", "pgm", "pbm", "gif", "xpm" ... */ + im->w = w; + im->h = h; + if (!im->format) + im->format = strdup("gif"); + if (im->loader || immediate_load || progress) + { + bg = gif->SBackGroundColor; + cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap); + im->data = (DATA32 *) malloc(sizeof(DATA32) * w * h); + if (!im->data) + { + DGifCloseFile(gif); + free(rows); + return 0; + } + ptr = im->data; + per_inc = 100.0 / (((float)w) * h); + for (i = 0; i < h; i++) + { + for (j = 0; j < w; j++) + { + if (rows[i][j] == transp) + { + r = cmap->Colors[bg].Red; + g = cmap->Colors[bg].Green; + b = cmap->Colors[bg].Blue; + *ptr++ = 0x00ffffff & ((r << 16) | (g << 8) | b); + } + else + { + r = cmap->Colors[rows[i][j]].Red; + g = cmap->Colors[rows[i][j]].Green; + b = cmap->Colors[rows[i][j]].Blue; + *ptr++ = (0xff << 24) | (r << 16) | (g << 8) | b; + } + per += per_inc; + if (progress && (((int)per) != last_per) + && (((int)per) % progress_granularity == 0)) + { + last_per = (int)per; + if (!(progress(im, (int)per, 0, last_y, w, i))) + { + DGifCloseFile(gif); + for (i = 0; i < h; i++) + { + free(rows[i]); + } + free(rows); + return 2; + } + last_y = i; + } + } + } + } + if (progress) + { + progress(im, 100, 0, last_y, w, h); + } + DGifCloseFile(gif); + for (i = 0; i < h; i++) + { + free(rows[i]); + } + free(rows); + return 1; +} + +/* fills the ImlibLoader struct with a strign array of format file */ +/* extensions this loader can load. eg: */ +/* loader->formats = { "jpeg", "jpg"}; */ +/* giving permutations is a good idea. case sensitivity is irrelevant */ +/* your laoder CAN load more than one format if it likes - like: */ +/* loader->formats = { "gif", "png", "jpeg", "jpg"} */ +/* if it can load those formats. */ +void +formats(ImlibLoader * l) +{ + /* this is the only bit you have to change... */ + char *list_formats[] = { "gif" }; + + /* don't bother changing any of this - it just reads this in and sets */ + /* the struct values and makes copies */ + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof(char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} diff --git a/src/modules/loaders/loader_jpeg.c b/src/modules/loaders/loader_jpeg.c new file mode 100644 index 0000000..55693a0 --- /dev/null +++ b/src/modules/loaders/loader_jpeg.c @@ -0,0 +1,376 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include + +#ifndef X_DISPLAY_MISSING +# include +# include +# include +#endif + +#include "image.h" +#include +#include + +struct ImLib_JPEG_error_mgr { + struct jpeg_error_mgr pub; + sigjmp_buf setjmp_buffer; +}; +typedef struct ImLib_JPEG_error_mgr *emptr; + +void _JPEGFatalErrorHandler(j_common_ptr cinfo); +void _JPEGErrorHandler(j_common_ptr cinfo); +void _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level); +char load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity); +void formats(ImlibLoader * l); + +void +_JPEGFatalErrorHandler(j_common_ptr cinfo) +{ + emptr errmgr; + + errmgr = (emptr) cinfo->err; +/* cinfo->err->output_message(cinfo);*/ + siglongjmp(errmgr->setjmp_buffer, 1); + return; +} + +void +_JPEGErrorHandler(j_common_ptr cinfo) +{ + emptr errmgr; + + errmgr = (emptr) cinfo->err; +/* cinfo->err->output_message(cinfo);*/ +/* siglongjmp(errmgr->setjmp_buffer, 1);*/ + return; +} + +void +_JPEGErrorHandler2(j_common_ptr cinfo, int msg_level) +{ + emptr errmgr; + + errmgr = (emptr) cinfo->err; +/* cinfo->err->output_message(cinfo);*/ +/* siglongjmp(errmgr->setjmp_buffer, 1);*/ + return; + msg_level = 0; +} + +char +load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) +{ + int w, h; + struct jpeg_decompress_struct cinfo; + struct ImLib_JPEG_error_mgr jerr; + FILE *f; + + if (im->data) + return 0; + f = fopen(im->real_file, "rb"); + if (!f) + return 0; + cinfo.err = jpeg_std_error(&(jerr.pub)); + jerr.pub.error_exit = _JPEGFatalErrorHandler; + jerr.pub.emit_message = _JPEGErrorHandler2; + jerr.pub.output_message = _JPEGErrorHandler; + if (sigsetjmp(jerr.setjmp_buffer, 1)) + { + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 0; + } + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, f); + jpeg_read_header(&cinfo, TRUE); + cinfo.do_fancy_upsampling = FALSE; + cinfo.do_block_smoothing = FALSE; + jpeg_start_decompress(&cinfo); + if ((!im->loader) && (!im->data)) + { + im->w = w = cinfo.output_width; + im->h = h = cinfo.output_height; + UNSET_FLAG(im->flags, F_HAS_ALPHA); + im->format = strdup("jpeg"); + } + if (((!im->data) && (im->loader)) || (immediate_load) || (progress)) + { + DATA8 *ptr, *line[16], *data; + DATA32 *ptr2; + int x, y, l, i, scans, count, prevy; + + im->w = w = cinfo.output_width; + im->h = h = cinfo.output_height; + + if (cinfo.rec_outbuf_height > 16) + { + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 0; + } + data = malloc(w * 16 * 3); + if (!data) + { + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 0; + } + /* must set the im->data member before callign progress function */ + ptr2 = im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + free(data); + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 0; + } + count = 0; + prevy = 0; + if (cinfo.output_components == 3) + { + for (i = 0; i < cinfo.rec_outbuf_height; i++) + line[i] = data + (i * w * 3); + for (l = 0; l < h; l += cinfo.rec_outbuf_height) + { + jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); + scans = cinfo.rec_outbuf_height; + if ((h - l) < scans) + scans = h - l; + ptr = data; + for (y = 0; y < scans; y++) + { + for (x = 0; x < w; x++) + { + *ptr2 = + (0xff000000) | ((ptr[0]) << 16) | ((ptr[1]) << + 8) | + (ptr[2]); + ptr += 3; + ptr2++; + } + } + if (progress) + { + int per; + + per = (l * 100) / h; + if (((per - count) >= progress_granularity) + || ((h - l) <= cinfo.rec_outbuf_height)) + { + count = per; + if (!progress + (im, per, 0, prevy, w, scans + l - prevy)) + { + free(data); + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 2; + } + prevy = l + scans; + } + } + } + } + else if (cinfo.output_components == 1) + { + for (i = 0; i < cinfo.rec_outbuf_height; i++) + line[i] = data + (i * w); + for (l = 0; l < h; l += cinfo.rec_outbuf_height) + { + jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); + scans = cinfo.rec_outbuf_height; + if ((h - l) < scans) + scans = h - l; + ptr = data; + for (y = 0; y < scans; y++) + { + for (x = 0; x < w; x++) + { + *ptr2 = + (0xff000000) | ((ptr[0]) << 16) | ((ptr[0]) << + 8) | + (ptr[0]); + ptr++; + ptr2++; + } + } + if (progress) + { + int per; + + per = (l * 100) / h; + if (((per - count) >= progress_granularity) + || ((h - l) <= cinfo.rec_outbuf_height)) + { + count = per; + if (!progress + (im, per, 0, prevy, w, l + scans - prevy)) + { + free(data); + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 2; + } + prevy = l + scans; + } + } + } + } + free(data); + } + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 1; +} + +char +save(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity) +{ + struct jpeg_compress_struct cinfo; + struct ImLib_JPEG_error_mgr jerr; + FILE *f; + DATA8 *buf; + DATA32 *ptr; + JSAMPROW *jbuf; + int y = 0, quality = 75, compression = 2; + ImlibImageTag *tag; + int i, j, pl = 0; + char pper = 0; + + /* no image data? abort */ + if (!im->data) + return 0; + /* allocate a small buffer to convert image data */ + buf = malloc(im->w * 3 * sizeof(DATA8)); + if (!buf) + return 0; + f = fopen(im->real_file, "wb"); + if (!f) + { + free(buf); + return 0; + } + /* set up error handling */ + jerr.pub.error_exit = _JPEGFatalErrorHandler; + jerr.pub.emit_message = _JPEGErrorHandler2; + jerr.pub.output_message = _JPEGErrorHandler; + cinfo.err = jpeg_std_error(&(jerr.pub)); + if (sigsetjmp(jerr.setjmp_buffer, 1)) + { + jpeg_destroy_compress(&cinfo); + free(buf); + fclose(f); + return 0; + } + /* setup compress params */ + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, f); + cinfo.image_width = im->w; + cinfo.image_height = im->h; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + /* look for tags attached to image to get extra parameters liek quality */ + /* settigns etc. - thsi si the "api" to hint for extra information for */ + /* saver modules */ + + /* compression */ + tag = __imlib_GetTag(im, "compression"); + if (tag) + { + compression = tag->val; + if (compression < 0) + compression = 0; + if (compression > 9) + compression = 9; + } + /* convert to quality */ + quality = (9 - compression) * 10; + quality = quality * 10 / 9; + /* quality */ + tag = __imlib_GetTag(im, "quality"); + if (tag) + quality = tag->val; + if (quality < 1) + quality = 1; + if (quality > 100) + quality = 100; + + /* set up jepg compression parameters */ + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + /* get the start pointer */ + ptr = im->data; + /* go one scanline at a time... and save */ + while (cinfo.next_scanline < cinfo.image_height) + { + /* convcert scaline from ARGB to RGB packed */ + for (j = 0, i = 0; i < im->w; i++) + { + buf[j++] = ((*ptr) >> 16) & 0xff; + buf[j++] = ((*ptr) >> 8) & 0xff; + buf[j++] = ((*ptr)) & 0xff; + ptr++; + } + /* write scanline */ + jbuf = (JSAMPROW *) (&buf); + jpeg_write_scanlines(&cinfo, jbuf, 1); + y++; + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || (y == (im->h - 1))) + { + l = y - pl; + if (!progress(im, per, 0, (y - l), im->w, l)) + { + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + free(buf); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + /* finish off */ + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + free(buf); + fclose(f); + return 1; + progress = NULL; +} + +void +formats(ImlibLoader * l) +{ + char *list_formats[] = { "jpg", "jpeg", "jfif", "jfi" }; + + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof(char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} diff --git a/src/modules/loaders/loader_lbm.c b/src/modules/loaders/loader_lbm.c new file mode 100644 index 0000000..8542aa0 --- /dev/null +++ b/src/modules/loaders/loader_lbm.c @@ -0,0 +1,550 @@ +/*------------------------------------------------------------------------------ + * Reads regular Amiga IFF ILBM files. + * + * Supports IMLIB2_LBM_NOMASK environment variable. If this is set to "1", then + * a transparency mask in an image will be ignored. On the Amiga a mask is often + * applied only when loading a brush rather than a picture, but this loader has + * no way to tell when the user wants this behaviour from the picture alone. + * + * Author: John Bickers + * Since: 2004-08-21 + * Version: 2004-08-28 + *------------------------------------------------------------------------------*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "common.h" +#include "image.h" + +char load(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity, char immediate_load); +#if 0 +char save(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity); +#endif +void formats(ImlibLoader *l); + + +#define L2RLONG(a) ((((long)((a)[0]) & 0xff) << 24) + (((long)((a)[1]) & 0xff) << 16) + (((long)((a)[2]) & 0xff) << 8) + ((long)((a)[3]) & 0xff)) +#define L2RWORD(a) ((((long)((a)[0]) & 0xff) << 8) + ((long)((a)[1]) & 0xff)) + +typedef struct CHUNK { + long size; + unsigned char *data; +} CHUNK; + +typedef struct ILBM { + CHUNK bmhd; + CHUNK camg; + CHUNK cmap; + CHUNK ctbl; + CHUNK sham; + CHUNK body; + + int depth; + int mask; + int ham; + int hbrite; + + int row; + + int offset; + int count; + int rle; +} ILBM; + +static void freeilbm(ILBM *); +static int loadchunks(char *, ILBM *, int); +static void bodyrow(unsigned char *, int, ILBM *); +static unsigned char scalegun(unsigned char, int); +static void scalecmap(ILBM *); +static void deplane(DATA32 *, int, ILBM *, unsigned char **); + + +/*------------------------------------------------------------------------------ + * Frees memory allocated as part of an ILBM structure. + *------------------------------------------------------------------------------*/ +static void freeilbm(ILBM *ilbm) +{ + if (ilbm->bmhd.data) free(ilbm->bmhd.data); + if (ilbm->camg.data) free(ilbm->camg.data); + if (ilbm->cmap.data) free(ilbm->cmap.data); + if (ilbm->ctbl.data) free(ilbm->ctbl.data); + if (ilbm->sham.data) free(ilbm->sham.data); + if (ilbm->body.data) free(ilbm->body.data); + + memset(ilbm, 0, sizeof(*ilbm)); +} + + +/*------------------------------------------------------------------------------ + * Reads the given chunks out of a file, returns 0 if the file had a problem. + * + * Format FORMsizeILBMtag.size....tag.size....tag.size.... + *------------------------------------------------------------------------------*/ +static int loadchunks(char *name, ILBM *ilbm, int full) +{ +CHUNK *c; +FILE *f; +size_t s; +long formsize, pos, z; +int ok, seek; +char buf[12]; + + ok = 0; + + f = fopen(name, "rb"); + if (f) { + s = fread(buf, 1, 12, f); + if (s == 12 && !memcmp(buf, "FORM", 4) && !memcmp(buf + 8, "ILBM", 4)) { + memset(ilbm, 0, sizeof(*ilbm)); + formsize = L2RLONG(buf + 4); + + while (1) { + pos = ftell(f); + if (pos < 0 || pos >= formsize + 8) break; /* Error or FORM data is finished. */ + seek = 1; + + s = fread(buf, 1, 8, f); + if (s != 8) break; /* Error or short file. */ + + z = L2RLONG(buf + 4); + if (z < 0) break; /* Corrupt file. */ + + c = NULL; + if (!memcmp(buf, "BMHD", 4)) c = &(ilbm->bmhd); + else if (full) { + if (!memcmp(buf, "CAMG", 4)) c = &(ilbm->camg); + else if (!memcmp(buf, "CMAP", 4)) c = &(ilbm->cmap); + else if (!memcmp(buf, "CTBL", 4)) c = &(ilbm->ctbl); + else if (!memcmp(buf, "SHAM", 4)) c = &(ilbm->sham); + else if (!memcmp(buf, "BODY", 4)) c = &(ilbm->body); + } + + if (c && !c->data) { + c->size = z; + c->data = malloc(c->size); + if (!c->data) break; /* Out of memory. */ + + s = fread(c->data, 1, c->size, f); + if (s != c->size) break; /* Error or short file. */ + + seek = 0; + if (!full) { /* Only BMHD required. */ + ok = 1; + break; + } + } + + if (pos + 8 + z >= formsize + 8) break; /* This was last chunk. */ + + if (seek && fseek(f, z, SEEK_CUR) != 0) break; + } + + /* File may end strangely, especially if body size is uneven, but it's + * ok if we have the chunks we want. !full check is already done. */ + if (ilbm->bmhd.data && ilbm->body.data) ok = 1; + if (!ok) freeilbm(ilbm); + } + fclose(f); + } + + return ok; +} + + +/*------------------------------------------------------------------------------ + * Unpacks a row of possibly RLE data at a time. + * + * RLE compression depends on a count byte, followed by data bytes. + * + * 0x80 means skip. + * 0xff to 0x81 means repeat one data byte (256 - count) + 1 times. + * 0x00 to 0x7f means copy count + 1 data bytes. + * + * In theory RLE compression is not supposed to create runs across scanlines. + *------------------------------------------------------------------------------*/ +static void bodyrow(unsigned char *p, int z, ILBM *ilbm) +{ +int i, x, w; +unsigned char b; + + if (ilbm->offset >= ilbm->body.size) { + memset(p, 0, z); + return; + } + + if (!ilbm->rle) { + w = ilbm->body.size - ilbm->offset; + if (w > z) w = z; + memcpy(p, ilbm->body.data + ilbm->offset, w); + if (w < z) memset(p + w, 0, z - w); + ilbm->offset += w; + return; + } + + for (i = 0; i < z; ) { + b = ilbm->body.data[ilbm->offset++]; + while (b == 0x80 && ilbm->offset < ilbm->body.size) b = ilbm->body.data[ilbm->offset++]; + if (ilbm->offset >= ilbm->body.size) break; + + if (b & 0x80) { + w = (0x100 - b) + 1; + if (w > z - i) w = z - i; + + b = ilbm->body.data[ilbm->offset++]; + memset(p + i, b, w); + i += w; + } + else { + w = (b & 0x7f) + 1; + if (w > ilbm->body.size - ilbm->offset) w = ilbm->body.size - ilbm->offset; + x = (w <= z - i)? w: z - i; + memcpy(p + i, ilbm->body.data + ilbm->offset, x); + i += x; + ilbm->offset += w; + } + } + + if (i < z) memset(p, 0, z - i); +} + + +/*------------------------------------------------------------------------------ + * Shifts a value to produce an 8-bit colour gun, and fills in the lower bits + * from the high bits of the value so that, for example, 4-bit 0x0f scales to + * 0xff, or 1-bit 0x01 scales to 0xff. + *------------------------------------------------------------------------------*/ +static unsigned char scalegun(unsigned char v, int sl) +{ +int sr; + + switch (sl) { + case 1: + case 2: + case 3: + sr = 8 - sl; + return (v << sl) | (v >> sr); + + case 4: + return (v << 4) | v; + + case 5: + return v * 0x24; + + case 6: + return v * 0x55; + + case 7: + return v * 0xff; + } + return v; +} + + +/*------------------------------------------------------------------------------ + * Scales the colours in a CMAP chunk if they all look like 4-bit colour, so + * that they use all 8-bits. This is done by copying the high nybble into the + * low nybble, so for example 0xf0 becomes 0xff. + *------------------------------------------------------------------------------*/ +static void scalecmap(ILBM *ilbm) +{ +int i; + + if (!ilbm->cmap.data) return; + + for (i = 0; i < ilbm->cmap.size; i++) + if (ilbm->cmap.data[i] & 0x0f) return; + + for (i = 0; i < ilbm->cmap.size; i++) + ilbm->cmap.data[i] |= ilbm->cmap.data[i] >> 4; +} + + +/*------------------------------------------------------------------------------ + * Deplanes and converts an array of bitplanes to a single scanline of DATA32 + * (unsigned int) values. DATA32 is ARGB. + *------------------------------------------------------------------------------*/ +static void deplane(DATA32 *row, int w, ILBM *ilbm, unsigned char *plane[]) +{ +unsigned long l; +int i, o, sl, x; +unsigned char bit, r, g, b, a, v, h, *pal; + + pal = NULL; + if (ilbm->sham.data && ilbm->sham.size >= 2 + (ilbm->row + 1) * 2 * 16) + pal = ilbm->sham.data + 2 + ilbm->row * 2 * 16; + if (ilbm->ctbl.data && ilbm->ctbl.size >= (ilbm->row + 1) * 2 * 16) + pal = ilbm->ctbl.data + ilbm->row * 2 * 16; + + if (ilbm->ham) r = g = b = 0; + + bit = 0x80; + o = 0; + for (x = 0; x < w; x++) { + l = 0; + for (i = ilbm->depth - 1; i >= 0; i--) { + l = l << 1; + if (plane[i][o] & bit) l = l | 1; + } + a = (ilbm->mask == 0 || (ilbm->mask == 1 && (plane[ilbm->depth][o] & bit)) || ilbm->mask == 2)? 0xff: 0x00; + + if (ilbm->depth == 32) { + a = (l >> 24) & 0xff; + b = (l >> 16) & 0xff; + g = (l >> 8) & 0xff; + r = l & 0xff; + } + else if (ilbm->depth == 24) { + b = (l >> 16) & 0xff; + g = (l >> 8) & 0xff; + r = l & 0xff; + } + else if (ilbm->ham) { + v = l & ((1 << (ilbm->depth - 2)) - 1); + h = (l & ~v) >> (ilbm->depth - 2); + + if (h == 0x00) { + if (!pal) { + if ((v + 1) * 3 <= ilbm->cmap.size) { + r = ilbm->cmap.data[v * 3]; + g = ilbm->cmap.data[v * 3 + 1]; + b = ilbm->cmap.data[v * 3 + 2]; + } + else r = g = b = 0; + } + else { + r = scalegun(pal[v * 2] & 0x0f, 4); + g = scalegun((pal[v * 2 + 1] & 0xf0) >> 4, 4); + b = scalegun((pal[v * 2 + 1] & 0x0f), 4); + } + } + else if (h == 0x01) b = scalegun(v, 8 - (ilbm->depth - 2)); + else if (h == 0x02) r = scalegun(v, 8 - (ilbm->depth - 2)); + else g = scalegun(v, 8 - (ilbm->depth - 2)); + } + else if (ilbm->hbrite) { + v = l & ((1 << (ilbm->depth - 1)) - 1); + h = (l & ~v) >> (ilbm->depth - 1); + + if (!pal) { + if ((v + 1) * 3 <= ilbm->cmap.size) { + r = ilbm->cmap.data[v * 3]; + g = ilbm->cmap.data[v * 3 + 1]; + b = ilbm->cmap.data[v * 3 + 2]; + } + else r = g = b = 0; + } + else { + r = scalegun(pal[v * 2] & 0x0f, 4); + g = scalegun((pal[v * 2 + 1] & 0xf0) >> 4, 4); + b = scalegun((pal[v * 2 + 1] & 0x0f), 4); + } + + if (h) { + r = r >> 1; + g = g >> 1; + b = b >> 1; + } + + if (ilbm->mask == 2 && v == L2RWORD(ilbm->bmhd.data + 12)) a = 0x00; + } + else if (ilbm->cmap.size == 0 && !pal) { + v = l & ((1 << ilbm->depth) - 1); + r = scalegun(v, ilbm->depth); + g = r; + b = r; + } + else { + v = l & 0xff; + if (!pal) { + if ((v + 1) * 3 <= ilbm->cmap.size) { + r = ilbm->cmap.data[v * 3]; + g = ilbm->cmap.data[v * 3 + 1]; + b = ilbm->cmap.data[v * 3 + 2]; + } + else r = g = b = 0; + } + else { + r = scalegun(pal[v * 2] & 0x0f, 4); + g = scalegun((pal[v * 2 + 1] & 0xf0) >> 4, 4); + b = scalegun((pal[v * 2 + 1] & 0x0f), 4); + } + + if (ilbm->mask == 2 && v == L2RWORD(ilbm->bmhd.data + 12)) a = 0x00; + } + + row[x] = ((unsigned long)a << 24) | ((unsigned long)r << 16) | ((unsigned long)g << 8) | (unsigned long)b; + + bit = bit >> 1; + if (bit == 0) { + o++; + bit = 0x80; + } + } +} + + +/*------------------------------------------------------------------------------ + * Loads an image. If im->loader is non-zero, or immediate_load is non-zero, or + * progress is non-zero, then the file is fully loaded, otherwise only the width + * and height are read. + * + * Imlib2 doesn't support reading comment chunks like ANNO. + *------------------------------------------------------------------------------*/ +char load(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity, char immediate_load) +{ +char *env; +int cancel, full, i, j, k, n, ok, y, z, gran, nexty, prevy; +unsigned char *plane[40]; +ILBM ilbm; + + /*---------- + * Do nothing if the data is already loaded. + *----------*/ + if (im->data) return 0; + + /*---------- + * Load the chunk(s) we're interested in. If full is not true, then we only + * want the image size and format. + *----------*/ + full = (im->loader || immediate_load || progress); + ok = loadchunks(im->real_file, &ilbm, full); + if (!ok) return 0; + + /*---------- + * Use and check header. + *----------*/ + ok = 0; + if (ilbm.bmhd.size >= 20) { + ok = 1; + + im->w = L2RWORD(ilbm.bmhd.data); + im->h = L2RWORD(ilbm.bmhd.data + 2); + if (im->w <= 0 || im->h <= 0) ok = 0; + + ilbm.depth = ilbm.bmhd.data[8]; + if (ilbm.depth < 1 || (ilbm.depth > 8 && ilbm.depth != 24 && ilbm.depth != 32)) ok = 0; /* Only 1 to 8, 24, or 32 planes. */ + + ilbm.rle = ilbm.bmhd.data[10]; + if (ilbm.rle < 0 || ilbm.rle > 1) ok = 0; /* Only NONE or RLE compression. */ + + ilbm.mask = ilbm.bmhd.data[9]; + + if (ilbm.mask || ilbm.depth == 32) SET_FLAG(im->flags, F_HAS_ALPHA); + else UNSET_FLAG(im->flags, F_HAS_ALPHA); + + env = getenv("IMLIB2_LBM_NOMASK"); + if (env && (!strcmp(env, "true") || !strcmp(env, "1") || !strcmp(env, "yes") || !strcmp(env, "on"))) UNSET_FLAG(im->flags, F_HAS_ALPHA); + + if (!im->format) im->format = strdup("lbm"); + + ilbm.ham = 0; + ilbm.hbrite = 0; + if (ilbm.depth <= 8) { + if (ilbm.camg.size == 4) { + if (ilbm.camg.data[2] & 0x08) ilbm.ham = 1; + if (ilbm.camg.data[3] & 0x80) ilbm.hbrite = 1; + } + else { /* Only guess at ham and hbrite if CMAP is present. */ + if (ilbm.depth == 6 && full && ilbm.cmap.size >= 3 * 16) ilbm.ham = 1; + if (full && !ilbm.ham && ilbm.depth > 1 && ilbm.cmap.size == 3 * (1 << (ilbm.depth - 1))) ilbm.hbrite = 1; + } + } + } + if (!full || !ok) { + freeilbm(&ilbm); + return ok; + } + + /*---------- + * The source data is planar. Each plane is an even number of bytes wide. If + * masking type is 1, there is an extra plane that defines the mask. Scanlines + * from each plane are interleaved, from top to bottom. The first plane is the + * 0 bit. + *----------*/ + ok = 0; + cancel = 0; + plane[0] = NULL; + + im->data = malloc(im->w * im->h * sizeof(DATA32)); + if (im->data) { + n = ilbm.depth; + if (ilbm.mask == 1) n++; + + plane[0] = malloc(((im->w + 15) / 16) * 2 * n); + for (i = 1; i < n; i++) plane[i] = plane[i - 1] + ((im->w + 15) / 16) * 2; + + z = ((im->w + 15) / 16) * 2 * n; + + if (progress) { + prevy = 0; + if (progress_granularity <= 0) progress_granularity = 1; + gran = progress_granularity; + nexty = ((im->h * gran) / 100); + } + + scalecmap(&ilbm); + + for (y = 0; y < im->h; y++) { + bodyrow(plane[0], z, &ilbm); + + deplane(im->data + im->w * y, im->w, &ilbm, plane); + ilbm.row++; + + if (progress && (y >= nexty || y == im->h - 1)) { + if (!progress(im, (char)((100 * (y + 1)) / im->h), 0, prevy, im->w, y + 1)) { + cancel = 1; + break; + } + prevy = y; + gran += progress_granularity; + nexty = ((im->h * gran) / 100); + } + } + + ok = !cancel; + } + + /*---------- + * We either had a successful decode, the user cancelled, or we couldn't get + * the memory for im->data. + *----------*/ + if (!ok) { + if (im->data) free(im->data); + im->data = NULL; + } + + if (plane[0]) free(plane[0]); + + freeilbm(&ilbm); + + return (cancel)? 2: ok; +} + + +/*------------------------------------------------------------------------------ + * Perhaps save only in 32-bit format? The IFF ILBM format has pretty much gone + * the way of the Amiga, who saves in this format any more? + *------------------------------------------------------------------------------*/ +#if 0 +char save(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity) +{ + return 0; +} +#endif + + +/*------------------------------------------------------------------------------ + * Identifies the file extensions this loader handles. Standard code from other + * loaders. + *------------------------------------------------------------------------------*/ +void formats(ImlibLoader *l) +{ +char *list_formats[] = { "iff", "ilbm", "lbm" }; +int i; + + l->num_formats = sizeof(list_formats) / sizeof(list_formats[0]); + l->formats = malloc(l->num_formats * sizeof(list_formats[0])); + for (i = 0; i < l->num_formats; i++) l->formats[i] = strdup(list_formats[i]); +} diff --git a/src/modules/loaders/loader_png.c b/src/modules/loaders/loader_png.c new file mode 100644 index 0000000..ca2f4b4 --- /dev/null +++ b/src/modules/loaders/loader_png.c @@ -0,0 +1,440 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include + +#ifndef X_DISPLAY_MISSING +# include +# include +# include +#endif + +#include "image.h" +#include + +/* this is a quick sample png loader module... nice and small isnt it? */ + +/* PNG stuff */ +#define PNG_BYTES_TO_CHECK 4 + +char load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity); +void formats(ImlibLoader * l); + +static void comment_free(ImlibImage * im, void *data); +static void +comment_free(ImlibImage * im, void *data) +{ + free(data); +} + +char +load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) +{ + png_uint_32 w32, h32; + int w, h; + char hasa = 0, hasg = 0; + FILE *f; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + int bit_depth, color_type, interlace_type; + + /* if immediate_load is 1, then dont delay image laoding as below, or */ + /* already data in this image - dont load it again */ + if (im->data) + return 0; + f = fopen(im->real_file, "rb"); + if (!f) + return 0; + /* read header */ + if (!im->data) + { + unsigned char buf[PNG_BYTES_TO_CHECK]; + + /* if we havent read the header before, set the header data */ + fread(buf, 1, PNG_BYTES_TO_CHECK, f); + if (!png_check_sig(buf, PNG_BYTES_TO_CHECK)) + { + fclose(f); + return 0; + } + rewind(f); + png_ptr = + png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + fclose(f); + return 0; + } + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, NULL, NULL); + fclose(f); + return 0; + } + if (setjmp(png_ptr->jmpbuf)) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fclose(f); + return 0; + } + png_init_io(png_ptr, f); + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32), + (png_uint_32 *) (&h32), &bit_depth, &color_type, + &interlace_type, NULL, NULL); + im->w = (int)w32; + im->h = (int)h32; + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_set_expand(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + hasa = 1; + } + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + hasa = 1; + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + hasa = 1; + hasg = 1; + } + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) + hasg = 1; + if (hasa) + SET_FLAG(im->flags, F_HAS_ALPHA); + else + UNSET_FLAG(im->flags, F_HAS_ALPHA); + /* set the format string member to the lower-case full extension */ + /* name for the format - so example names would be: */ + /* "png", "jpeg", "tiff", "ppm", "pgm", "pbm", "gif", "xpm" ... */ + if (!im->loader) + im->format = strdup("png"); + } + /* if its the second phase load OR its immediate load or a progress */ + /* callback is set then load the data */ + if ((im->loader) || (immediate_load) || (progress)) + { + unsigned char **lines; + int i; + + w = im->w; + h = im->h; + if (hasa) + png_set_expand(png_ptr); + /* we want ARGB */ +/* note form raster: */ +/* thanks to mustapha for helping debug this on PPC Linux remotely by */ +/* sending across screenshots all the tiem and me figuring out form them */ +/* what the hell was up with the colors */ +/* now png loading shoudl work on big endian machines nicely */ +#ifdef WORDS_BIGENDIAN + png_set_swap_alpha(png_ptr); + png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE); +#else + png_set_bgr(png_ptr); + png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); +#endif + /* 16bit color -> 8bit color */ + png_set_strip_16(png_ptr); + /* pack all pixels to byte boundaires */ + png_set_packing(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand(png_ptr); + if (im->data) + free(im->data); + im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); + fclose(f); + return 0; + } + lines = (unsigned char **)malloc(h * sizeof(unsigned char *)); + + if (!lines) + { + free(im->data); + im->data = NULL; + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); + fclose(f); + return 0; + } + if (hasg) + { + png_set_gray_to_rgb(png_ptr); + if (png_get_bit_depth(png_ptr, info_ptr) < 8) + png_set_gray_1_2_4_to_8(png_ptr); + } + for (i = 0; i < h; i++) + lines[i] = ((unsigned char *)(im->data)) + (i * w * sizeof(DATA32)); + if (progress) + { + int y, count, prevy, pass, number_passes, per, + nrows = 1; + + count = 0; + number_passes = png_set_interlace_handling(png_ptr); + for (pass = 0; pass < number_passes; pass++) + { + prevy = 0; + per = 0; + for (y = 0; y < h; y += nrows) + { + png_read_rows(png_ptr, &lines[y], NULL, nrows); + + per = (((pass * h) + y) * 100) / (h * number_passes); + if ((per - count) >= progress_granularity) + { + count = per; + if (!progress(im, per, 0, prevy, w, y - prevy + 1)) + { + free(lines); + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp) NULL); + fclose(f); + return 2; + } + prevy = y + 1; + } + } + if (!progress(im, per, 0, prevy, w, y - prevy + 1)) + { + free(lines); + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp) NULL); + fclose(f); + return 2; + } + } + } + else + png_read_image(png_ptr, lines); + free(lines); + png_read_end(png_ptr, info_ptr); + } +#ifdef PNG_TEXT_SUPPORTED + { + png_textp text; + int num; + int i; + + num = 0; + png_get_text(png_ptr, info_ptr, &text, &num); + for (i = 0; i < num; i++) + { + if (!strcmp(text[i].key, "Imlib2-Comment")) + __imlib_AttachTag(im, "comment", 0, strdup(text[i].text), + comment_free); + } + } +#endif + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); + fclose(f); + return 1; +} + +char +save(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity) +{ + FILE *f; + png_structp png_ptr; + png_infop info_ptr; + DATA32 *ptr; + int x, y, j; + png_bytep row_ptr, data = NULL; + png_color_8 sig_bit; + int pl = 0; + char pper = 0; + ImlibImageTag *tag; + int quality = 75, compression = 3, num_passes = 1, pass; + + if (!im->data) + return 0; + + f = fopen(im->real_file, "wb"); + if (!f) + return 0; + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + fclose(f); + return 0; + } + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + fclose(f); + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + return 0; + } + if (setjmp(png_ptr->jmpbuf)) + { + fclose(f); + png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr); + png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr); + return 0; + } + + /* check whether we should use interlacing */ + if ((tag = __imlib_GetTag(im, "interlacing")) && tag->val) + { +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + png_ptr->interlaced = PNG_INTERLACE_ADAM7; + num_passes = png_set_interlace_handling(png_ptr); +#endif + } + + png_init_io(png_ptr, f); + if (im->flags & F_HAS_ALPHA) + { + png_set_IHDR(png_ptr, info_ptr, im->w, im->h, 8, + PNG_COLOR_TYPE_RGB_ALPHA, png_ptr->interlaced, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); +#ifdef WORDS_BIGENDIAN + png_set_swap_alpha(png_ptr); +#else + png_set_bgr(png_ptr); +#endif + } + else + { + png_set_IHDR(png_ptr, info_ptr, im->w, im->h, 8, PNG_COLOR_TYPE_RGB, + png_ptr->interlaced, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + data = malloc(im->w * 3 * sizeof(char)); + } + sig_bit.red = 8; + sig_bit.green = 8; + sig_bit.blue = 8; + sig_bit.alpha = 8; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + /* quality */ + tag = __imlib_GetTag(im, "quality"); + if (tag) + { + quality = tag->val; + if (quality < 1) + quality = 1; + if (quality > 99) + quality = 99; + } + /* convert to compression */ + quality = quality / 10; + compression = 9 - quality; + /* compression */ + tag = __imlib_GetTag(im, "compression"); + if (tag) + compression = tag->val; + if (compression < 0) + compression = 0; + if (compression > 9) + compression = 9; + tag = __imlib_GetTag(im, "comment"); + if (tag) + { +#ifdef PNG_TEXT_SUPPORTED + png_text text; + + text.key = "Imlib2-Comment"; + text.text = tag->data; + text.compression = PNG_TEXT_COMPRESSION_zTXt; + png_set_text(png_ptr, info_ptr, &(text), 1); +#endif + } + png_set_compression_level(png_ptr, compression); + png_write_info(png_ptr, info_ptr); + png_set_shift(png_ptr, &sig_bit); + png_set_packing(png_ptr); + + for (pass = 0; pass < num_passes; pass++) + { + ptr = im->data; + + for (y = 0; y < im->h; y++) + { + if (im->flags & F_HAS_ALPHA) + row_ptr = (png_bytep) ptr; + else + { + for (j = 0, x = 0; x < im->w; x++) + { + data[j++] = (ptr[x] >> 16) & 0xff; + data[j++] = (ptr[x] >> 8) & 0xff; + data[j++] = (ptr[x]) & 0xff; + } + row_ptr = (png_bytep) data; + } + png_write_rows(png_ptr, &row_ptr, 1); + if (progress) + { + char per; + int l; + + per = 100 * (pass + y / (float) im->h) / num_passes; + if ((per - pper) >= progress_granularity) + { + l = y - pl; + if (!progress(im, per, 0, (y - l), im->w, l)) + { + if (data) + free(data); + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, + (png_infopp) & info_ptr); + png_destroy_info_struct(png_ptr, + (png_infopp) & info_ptr); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + ptr += im->w; + } + } + if (data) + free(data); + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr); + png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr); + + fclose(f); + return 1; +} + +/* fills the ImlibLoader struct with a strign array of format file */ +/* extensions this loader can load. eg: */ +/* loader->formats = { "jpeg", "jpg"}; */ +/* giving permutations is a good idea. case sensitivity is irrelevant */ +/* your loader CAN load more than one format if it likes - like: */ +/* loader->formats = { "gif", "png", "jpeg", "jpg"} */ +/* if it can load those formats. */ +void +formats(ImlibLoader * l) +{ + /* this is the only bit you have to change... */ + char *list_formats[] = { "png" }; + + /* don't bother changing any of this - it just reads this in and sets */ + /* the struct values and makes copies */ + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof(char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} diff --git a/src/modules/loaders/loader_pnm.c b/src/modules/loaders/loader_pnm.c new file mode 100644 index 0000000..a7e16c9 --- /dev/null +++ b/src/modules/loaders/loader_pnm.c @@ -0,0 +1,832 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include + +#ifndef X_DISPLAY_MISSING +# include +# include +# include +#endif + +#include +#include "image.h" + +char load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity); +void formats(ImlibLoader * l); + +char +load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) +{ + char p = ' ', numbers = 3, count = 0; + int w = 0, h = 0, v = 255, c = 0; + char buf[256]; + FILE *f = NULL; + + if (im->data) + return 0; + f = fopen(im->real_file, "rb"); + if (!f) + return 0; + + /* can't use fgets(), because there might be + * binary data after the header and there + * needn't be a newline before the data, so + * no chance to distinguish between end of buffer + * and a binary 0. + */ + + /* read the header info */ + + c = fgetc(f); + if (c != 'P') + { + fclose(f); + return 0; + } + + p = fgetc(f); + if (p == '1' || p == '4') + numbers = 2; /* bitimages don't have max value */ + + if ((p < '1') || (p > '8')) + { + fclose(f); + return 0; + } + count = 0; + while (count < numbers) + { + c = fgetc(f); + + if (c == EOF) + { + fclose(f); + return 0; + } + + /* eat whitespace */ + while (isspace(c)) + c = fgetc(f); + /* if comment, eat that */ + if (c == '#') + { + do + c = fgetc(f); + while (c != '\n' && c != EOF); + } + /* no comment -> proceed */ + else + { + int i = 0; + + /* read numbers */ + while (c != EOF && !isspace(c)) + { + buf[i++] = c; + c = fgetc(f); + } + if (i) + { + buf[i] = 0; + count++; + switch (count) + { + /* width */ + case 1: + w = atoi(buf); + break; + /* height */ + case 2: + h = atoi(buf); + break; + /* max value, only for color and greyscale */ + case 3: + v = atoi(buf); + break; + } + } + } + } + if ((w <= 0) || (w > 8192) || (h <= 0) || (h > 8192) || (v < 0) || (v > 255)) + { + fclose(f); + return 0; + } + + im->w = w; + im->h = h; + if (!im->format) + { + if (p == '8') + SET_FLAG(im->flags, F_HAS_ALPHA); + else + UNSET_FLAG(im->flags, F_HAS_ALPHA); + im->format = strdup("pnm"); + } + + if (((!im->data) && (im->loader)) || (immediate_load) || (progress)) + { + DATA8 *data = NULL; /* for the binary versions */ + DATA8 *ptr = NULL; + int *idata = NULL; /* for the ASCII versions */ + int *iptr; + char buf2[256]; + DATA32 *ptr2; + int i, j, x, y, pl = 0; + char pper = 0; + + /* must set the im->data member before callign progress function */ + ptr2 = im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + fclose(f); + return 0; + } + /* start reading the data */ + switch (p) + { + case '1': /* ASCII monochrome */ + buf[0] = 0; + i = 0; + for (y = 0; y < h; y++) + { + x = 0; + while (x < w) + { + if (!buf[i]) /* fill buffer */ + { + if (!fgets(buf, 255, f)) + { + fclose(f); + return 0; + } + i = 0; + } + while (buf[i] && isspace(buf[i])) + i++; + if (buf[i]) + { + if (buf[i] == '1') + *ptr2 = 0xff000000; + else if (buf[i] == '0') + *ptr2 = 0xffffffff; + else + { + fclose(f); + return 0; + } + ptr2++; + i++; + } + } + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) + || (y == (im->h - 1))) + { + l = y - pl; + + /* fix off by one in case of the last line */ + if (y == (im->h - 1)) + l++; + + if (!progress(im, per, 0, pl, im->w, l)) + { + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + break; + case '2': /* ASCII greyscale */ + idata = malloc(sizeof(int) * w); + + if (!idata) + { + fclose(f); + return 0; + } + buf[0] = 0; + i = 0; + j = 0; + for (y = 0; y < h; y++) + { + iptr = idata; + x = 0; + while (x < w) + { + if (!buf[i]) /* fill buffer */ + { + if (!fgets(buf, 255, f)) + { + free(idata); + fclose(f); + return 0; + } + i = 0; + } + while (buf[i] && isspace(buf[i])) + i++; + while (buf[i] && !isspace(buf[i])) + buf2[j++] = buf[i++]; + if (j) + { + buf2[j] = 0; + *(iptr++) = atoi(buf2); + j = 0; + x++; + } + } + iptr = idata; + if (v == 255) + { + for (x = 0; x < w; x++) + { + *ptr2 = + 0xff000000 | (iptr[0] << 16) | (iptr[0] << 8) + | iptr[0]; + ptr2++; + iptr++; + } + } + else + { + for (x = 0; x < w; x++) + { + *ptr2 = + 0xff000000 | (((iptr[0] * 255) / v) << 16) | + (((iptr[0] * 255) / v) << 8) | ((iptr[0] * + 255) / v); + ptr2++; + iptr++; + } + } + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) + || (y == (im->h - 1))) + { + + l = y - pl; + + /* fix off by one in case of the last line */ + if (y == (im->h - 1)) + l++; + + if (!progress(im, per, 0, pl, im->w, l)) + { + if (idata) + free(idata); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + break; + case '3': /* ASCII RGB */ + idata = malloc(3 * sizeof(int) * w); + + if (!idata) + { + fclose(f); + return 0; + } + buf[0] = 0; + i = 0; + j = 0; + for (y = 0; y < h; y++) + { + int w3 = 3 * w; + + iptr = idata; + x = 0; + while (x < w3) + { + if (!buf[i]) /* fill buffer */ + { + if (!fgets(buf, 255, f)) + { + free(idata); + fclose(f); + return 0; + } + i = 0; + } + while (buf[i] && isspace(buf[i])) + i++; + while (buf[i] && !isspace(buf[i])) + buf2[j++] = buf[i++]; + if (j) + { + buf2[j] = 0; + *(iptr++) = atoi(buf2); + j = 0; + x++; + } + } + iptr = idata; + if (v == 255) + { + for (x = 0; x < w; x++) + { + *ptr2 = + 0xff000000 | (iptr[0] << 16) | (iptr[1] << 8) + | iptr[2]; + ptr2++; + iptr += 3; + } + } + else + { + for (x = 0; x < w; x++) + { + *ptr2 = + 0xff000000 | (((ptr[0] * 255) / v) << 16) | + (((iptr[1] * 255) / v) << 8) | ((iptr[2] * + 255) / v); + ptr2++; + iptr += 3; + } + } + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) + || (y == (im->h - 1))) + { + l = y - pl; + + /* fix off by one in case of the last line */ + if (y == (im->h - 1)) + l++; + + if (!progress(im, per, 0, pl, im->w, l)) + { + if (idata) + free(idata); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + break; + case '4': /* binary 1bit monochrome */ + data = malloc(1 * sizeof(DATA8)); + if (!data) + { + fclose(f); + return 0; + } + ptr2 = im->data; + j = 0; + while ((fread(data, 1, 1, f)) && (j < (w * h))) + { + for (i = 7; i >= 0; i--) + { + if (j < (w * h)) + { + if (data[0] & (1 << i)) + *ptr2 = 0xff000000; + else + *ptr2 = 0xffffffff; + ptr2++; + } + j++; + } + } + break; + case '5': /* binary 8bit grayscale GGGGGGGG */ + data = malloc(1 * sizeof(DATA8) * w); + if (!data) + { + fclose(f); + return 0; + } + ptr2 = im->data; + for (y = 0; y < h; y++) + { + if (!fread(data, w * 1, 1, f)) + { + free(data); + fclose(f); + return 1; + } + ptr = data; + if (v == 255) + { + for (x = 0; x < w; x++) + { + *ptr2 = + 0xff000000 | (ptr[0] << 16) | (ptr[0] << 8) | + ptr[0]; + ptr2++; + ptr++; + } + } + else + { + for (x = 0; x < w; x++) + { + *ptr2 = + 0xff000000 | (((ptr[0] * 255) / v) << 16) | + (((ptr[0] * 255) / v) << 8) | ((ptr[0] * + 255) / v); + ptr2++; + ptr++; + } + } + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) + || (y == (im->h - 1))) + { + l = y - pl; + + /* fix off by one in case of the last line */ + if (y == (im->h - 1)) + l++; + + if (!progress(im, per, 0, pl, im->w, l)) + { + if (data) + free(data); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + break; + case '6': /* 24bit binary RGBRGBRGB */ + data = malloc(3 * sizeof(DATA8) * w); + if (!data) + { + fclose(f); + return 0; + } + ptr2 = im->data; + for (y = 0; y < h; y++) + { + if (!fread(data, w * 3, 1, f)) + { + free(data); + fclose(f); + return 1; + } + ptr = data; + if (v == 255) + { + for (x = 0; x < w; x++) + { + *ptr2 = + 0xff000000 | (ptr[0] << 16) | (ptr[1] << 8) | + ptr[2]; + ptr2++; + ptr += 3; + } + } + else + { + for (x = 0; x < w; x++) + { + *ptr2 = + 0xff000000 | (((ptr[0] * 255) / v) << 16) | + (((ptr[1] * 255) / v) << 8) | ((ptr[2] * + 255) / v); + ptr2++; + ptr += 3; + } + } + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) + || (y == (im->h - 1))) + { + l = y - pl; + + /* fix off by one in case of the last line */ + if (y == (im->h - 1)) + l++; + + if (!progress(im, per, 0, pl, im->w, l)) + { + if (data) + free(data); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + break; + case '7': /* XV's 8bit 332 format */ + data = malloc(1 * sizeof(DATA8) * w); + if (!data) + { + fclose(f); + return 0; + } + ptr2 = im->data; + for (y = 0; y < h; y++) + { + if (!fread(data, w * 1, 1, f)) + { + free(data); + fclose(f); + return 1; + } + ptr = data; + for (x = 0; x < w; x++) + { + int r, g, b; + + r = (*ptr >> 5) & 0x7; + g = (*ptr >> 2) & 0x7; + b = (*ptr) & 0x3; + *ptr2 = + 0xff000000 | (((r << 21) | (r << 18) | (r << 15)) & + 0xff0000) | (((g << 13) | (g << 10) | + (g << 7)) & 0xff00) | + ((b << 6) | (b << 4) | (b << 2) | (b << 0)); + ptr2++; + ptr++; + } + if (progress) + { + char per; + int l = 0; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) + || (y == (im->h - 1))) + { + /* fix off by one in case of the last line */ + if (y == (im->h - 1)) + l++; + + if (!progress(im, per, 0, pl, im->w, l)) + { + if (data) + free(data); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + break; + case '8': /* 24bit binary RGBARGBARGBA */ + data = malloc(4 * sizeof(DATA8) * w); + if (!data) + { + fclose(f); + return 0; + } + ptr2 = im->data; + for (y = 0; y < h; y++) + { + if (!fread(data, w * 4, 1, f)) + { + free(data); + fclose(f); + return 1; + } + ptr = data; + if (v == 255) + { + for (x = 0; x < w; x++) + { + *ptr2 = + (ptr[3] << 24) | (ptr[0] << 16) | (ptr[1] << + 8) | + ptr[2]; + ptr2++; + ptr += 4; + } + } + else + { + for (x = 0; x < w; x++) + { + *ptr2 = + (((ptr[3] * 255) / + v) << 24) | (((ptr[0] * 255) / + v) << 16) | (((ptr[1] * 255) / + v) << 8) | + ((ptr[2] * 255) / v); + ptr2++; + ptr += 4; + } + } + if (progress) + { + char per; + int l = 0; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) + || (y == (im->h - 1))) + { + /* fix off by one in case of the last line */ + if (y == (im->h - 1)) + l++; + + if (!progress(im, per, 0, pl, im->w, l)) + { + if (data) + free(data); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + break; + default: + fclose(f); + return 0; + break; + } + if (idata) + free(idata); + if (data) + free(data); + } + fclose(f); + return 1; +} + +char +save(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity) +{ + FILE *f; + DATA8 *buf, *bptr; + DATA32 *ptr; + int x, y, pl = 0; + char pper = 0; + + /* no image data? abort */ + if (!im->data) + return 0; + f = fopen(im->real_file, "wb"); + if (!f) + return 0; + /* if the image has a useful alpha channel */ + if (im->flags & F_HAS_ALPHA) + { + /* allocate a small buffer to convert image data */ + buf = malloc(im->w * 4 * sizeof(DATA8)); + if (!buf) + { + fclose(f); + return 0; + } + ptr = im->data; + fprintf(f, "P8\n" "# PNM File written by Imlib2\n" "%i %i\n" "255\n", + im->w, im->h); + for (y = 0; y < im->h; y++) + { + bptr = buf; + for (x = 0; x < im->w; x++) + { + bptr[0] = ((*ptr) >> 16) & 0xff; + bptr[1] = ((*ptr) >> 8) & 0xff; + bptr[2] = ((*ptr)) & 0xff; + bptr[3] = ((*ptr) >> 24) & 0xff; + bptr += 4; + ptr++; + } + fwrite(buf, im->w * 4, 1, f); + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) + || (y == (im->h - 1))) + { + l = y - pl; + if (!progress(im, per, 0, (y - l), im->w, l)) + { + free(buf); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + } + else + { + /* allocate a small buffer to convert image data */ + buf = malloc(im->w * 3 * sizeof(DATA8)); + if (!buf) + { + fclose(f); + return 0; + } + ptr = im->data; + fprintf(f, "P6\n" "# PNM File written by Imlib2\n" "%i %i\n" "255\n", + im->w, im->h); + for (y = 0; y < im->h; y++) + { + bptr = buf; + for (x = 0; x < im->w; x++) + { + bptr[0] = ((*ptr) >> 16) & 0xff; + bptr[1] = ((*ptr) >> 8) & 0xff; + bptr[2] = ((*ptr)) & 0xff; + bptr += 3; + ptr++; + } + fwrite(buf, im->w * 3, 1, f); + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) + || (y == (im->h - 1))) + { + l = y - pl; + if (!progress(im, per, 0, (y - l), im->w, l)) + { + free(buf); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + } + /* finish off */ + free(buf); + fclose(f); + return 1; + progress = NULL; +} + +void +formats(ImlibLoader * l) +{ + char *list_formats[] = { "pnm", "ppm", "pgm", "pbm", "pam" }; + + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof(char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} diff --git a/src/modules/loaders/loader_tga.c b/src/modules/loaders/loader_tga.c new file mode 100644 index 0000000..4addbf3 --- /dev/null +++ b/src/modules/loaders/loader_tga.c @@ -0,0 +1,584 @@ +/* + * loader_tga.c - Loader for Truevision Targa images + * for Imlib2 + * + * by Dan Maas May 15, 2000 + * + * based on TGA specifications available at: + * http://www.wotsit.org/cgi-bin/search.cgi?TGA + * + * header/footer structures courtesy of the GIMP Targa plugin + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include +#include +#include +#include + +#ifndef X_DISPLAY_MISSING +# include +# include +# include +#endif + +#include "image.h" +#include "colormod.h" +#include "blend.h" + +char load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity); +void formats(ImlibLoader * l); + +/* flip an inverted image - see RLE reading below */ +static void tgaflip(DATA32 * in, int w, int h); + +/* TGA pixel formats */ +#define TGA_TYPE_MAPPED 1 +#define TGA_TYPE_COLOR 2 +#define TGA_TYPE_GRAY 3 +#define TGA_TYPE_MAPPED_RLE 9 +#define TGA_TYPE_COLOR_RLE 10 +#define TGA_TYPE_GRAY_RLE 11 + +/* TGA header flags */ +#define TGA_DESC_ABITS 0x0f +#define TGA_DESC_HORIZONTAL 0x10 +#define TGA_DESC_VERTICAL 0x20 + +#define TGA_SIGNATURE "TRUEVISION-XFILE" + +typedef struct { + unsigned char idLength; + unsigned char colorMapType; + unsigned char imageType; + unsigned char colorMapIndexLo, colorMapIndexHi; + unsigned char colorMapLengthLo, colorMapLengthHi; + unsigned char colorMapSize; + unsigned char xOriginLo, xOriginHi; + unsigned char yOriginLo, yOriginHi; + unsigned char widthLo, widthHi; + unsigned char heightLo, heightHi; + unsigned char bpp; + unsigned char descriptor; +} tga_header; + +typedef struct { + unsigned int extensionAreaOffset; + unsigned int developerDirectoryOffset; + char signature[16]; + char dot; + char null; +} tga_footer; + +/* + * Write an uncompressed RGBA 24- or 32-bit targa to disk + * (If anyone wants to write a RLE saver, feel free =) + */ + +char +save(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity) +{ + FILE *f; + DATA32 *dataptr; + unsigned char *buf, *bufptr; + int y, pl = 0; + char pper = 0; + + tga_header header; + + if (!im->data) + return 0; + + f = fopen(im->real_file, "wb"); + if (!f) + return 0; + + /* assemble the TGA header information */ + + /* most entries are zero... */ + memset(&header, 0x0, sizeof(header)); + + /* uncompressed RGB Targa identifier */ + header.imageType = TGA_TYPE_COLOR; + + /* image width, low byte */ + header.widthLo = im->w & 0xFF; + /* image width, high byte */ + header.widthHi = im->w >> 8; + + /* image height, low byte */ + header.heightLo = im->h & 0xFF; + /* image height, high byte */ + header.heightHi = im->h >> 8; + + /* total number of bits per pixel */ + header.bpp = (im->flags & F_HAS_ALPHA) ? 32 : 24; + /* number of extra (alpha) bits per pixel */ + header.descriptor = (im->flags & F_HAS_ALPHA) ? 8 : 0; + + /* top-to-bottom storage */ + header.descriptor |= TGA_DESC_VERTICAL; + + /* allocate a buffer to receive the BGRA-swapped pixel values */ + buf = malloc(im->w * im->h * ((im->flags & F_HAS_ALPHA) ? 4 : 3)); + if (!buf) + { + fclose(f); + return 0; + } + + /* now we have to read from im->data into buf, swapping RGBA to BGRA */ + dataptr = im->data; + bufptr = buf; + + /* for each row */ + for (y = 0; y < im->h; y++) + { + int x; + unsigned char r, g, b, a; + + /* for each pixel in the row */ + for (x = 0; x < im->w; x++) + { + if (im->flags & F_HAS_ALPHA) + { + READ_RGBA(dataptr, r, g, b, a); + *bufptr++ = b; + *bufptr++ = g; + *bufptr++ = r; + *bufptr++ = a; + } + else + { + READ_RGB(dataptr, r, g, b); + *bufptr++ = b; + *bufptr++ = g; + *bufptr++ = r; + } + dataptr++; + } /* end for (each pixel in row) */ + + /* report progress every row */ + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || (y == (im->h - 1))) + { + l = y - pl; + if (!progress(im, per, 0, (y - l), im->w, l)) + { + if (buf) + free(buf); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } + + /* write the header */ + fwrite(&header, sizeof(header), 1, f); + + /* write the image data */ + fwrite(buf, 1, im->w * im->h * ((im->flags & F_HAS_ALPHA) ? 4 : 3), f); + + if (buf) + free(buf); + fclose(f); + return 1; +} + +/* Load up a TGA file + * + * As written this function only recognizes the following types of Targas: + * Type 02 - Uncompressed RGB, 24 or 32 bits + * Type 03 - Uncompressed grayscale, 8 bits + * Type 10 - RLE-compressed RGB, 24 or 32 bits + * Type 11 - RLE-compressed grayscale, 8 bits + * There are several other (uncommon) Targa formats which this function can't currently handle + */ + +char +load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) +{ + int fd; + void *seg, *filedata; + struct stat ss; + int bpp, vinverted = 0; + int rle = 0, footer_present = 0; + + tga_header *header; + tga_footer *footer; + + if (im->data) + return 0; + + fd = open(im->real_file, O_RDONLY); + if (fd < 0) + return 0; + + if (fstat(fd, &ss) < 0) + { + close(fd); + return 0; + } + + if (ss.st_size < sizeof(tga_header) + sizeof(tga_footer)) + { + close(fd); + return 0; + } + seg = mmap(0, ss.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (seg == MAP_FAILED) + { + close(fd); + return 0; + } + + filedata = seg; + header = (tga_header *) filedata; + footer = (tga_footer *) ((char *)filedata + ss.st_size - sizeof(tga_footer)); + + /* check the footer to see if we have a v2.0 TGA file */ + if (memcmp(footer->signature, TGA_SIGNATURE, sizeof(footer->signature)) == 0) + footer_present = 1; + + if (!footer_present) + { + } + + /* skip over header */ + filedata = (char *)filedata + sizeof(tga_header); + + /* skip over alphanumeric ID field */ + if (header->idLength) + filedata = (char *)filedata + header->idLength; + + /* now parse the header */ + + /* this flag indicated bottom-up pixel storage */ + vinverted = !(header->descriptor & TGA_DESC_VERTICAL); + + switch (header->imageType) + { + case TGA_TYPE_COLOR_RLE: + case TGA_TYPE_GRAY_RLE: + rle = 1; + break; + + case TGA_TYPE_COLOR: + case TGA_TYPE_GRAY: + rle = 0; + break; + + default: + munmap(seg, ss.st_size); + close(fd); + return 0; + } + + /* bits per pixel */ + bpp = header->bpp; + + if (!((bpp == 32) || (bpp == 24) || (bpp == 8))) + { + munmap(seg, ss.st_size); + close(fd); + return 0; + } + + /* endian-safe loading of 16-bit sizes */ + im->w = (header->widthHi << 8) | header->widthLo; + im->h = (header->heightHi << 8) | header->heightLo; + + if ((im->w > 32767) || (im->w < 1) || (im->h > 32767) || (im->h < 1)) + { + im->w = 0; + munmap(seg, ss.st_size); + close(fd); + return 0; + } + + if (!im->format) + { + if (bpp == 32) + SET_FLAG(im->flags, F_HAS_ALPHA); + else + UNSET_FLAG(im->flags, F_HAS_ALPHA); + im->format = strdup("tga"); + } + + /* if we need to actually read the pixel data... */ + if (((!im->data) && (im->loader)) || (immediate_load) || (progress)) + { + unsigned long datasize; + unsigned char *bufptr; + DATA32 *dataptr; + + int y, pl = 0; + char pper = 0; + + /* allocate the destination buffer */ + im->data = malloc(im->w * im->h * sizeof(DATA32)); + if (!im->data) + { + im->w = 0; + munmap(seg, ss.st_size); + close(fd); + return 0; + } + + /* first we read the file data into a buffer for parsing */ + /* then we decode from RAM */ + + /* find out how much data must be read from the file */ + /* (this is NOT simply width*height*4, due to compression) */ + + datasize = ss.st_size - sizeof(tga_header) - header->idLength - + (footer_present ? sizeof(tga_footer) : 0); + + /* buffer is ready for parsing */ + + /* bufptr is the next byte to be read from the buffer */ + bufptr = filedata; + + /* dataptr is the next 32-bit pixel to be filled in */ + dataptr = im->data; + + /* decode uncompressed BGRA data */ + if (!rle) + { + for (y = 0; y < im->h; y++) /* for each row */ + { + int x; + + /* point dataptr at the beginning of the row */ + if (vinverted) + /* some TGA's are stored upside-down! */ + dataptr = im->data + ((im->h - y - 1) * im->w); + else + dataptr = im->data + (y * im->w); + + for (x = 0; x < im->w; x++) /* for each pixel in the row */ + { + switch (bpp) + { + + /* 32-bit BGRA pixels */ + case 32: + WRITE_RGBA(dataptr, + *(bufptr + 2), /* R */ + *(bufptr + 1), /* G */ + *(bufptr + 0), /* B */ + *(bufptr + 3) /* A */ + ); + dataptr++; + bufptr += 4; + break; + + /* 24-bit BGR pixels */ + case 24: + WRITE_RGBA(dataptr, + *(bufptr + 2), /* R */ + *(bufptr + 1), /* G */ + *(bufptr + 0), /* B */ + (char)0xff /* A */ + ); + dataptr++; + bufptr += 3; + break; + + /* 8-bit grayscale */ + case 8: + WRITE_RGBA(dataptr, /* grayscale */ + *bufptr, + *bufptr, + *bufptr, (char)0xff); + dataptr++; + bufptr += 1; + break; + } + + } /* end for (each pixel) */ + } + if (progress) + { + char per; + int l; + + progress(im, 100, 0, 0, im->w, im->h); + } /* end for (each row) */ + } + /* end if (!RLE) */ + /* decode RLE compressed data */ + else + { + unsigned char curbyte, red, green, blue, alpha; + DATA32 *final_pixel = dataptr + im->w * im->h; + + /* loop until we've got all the pixels */ + while (dataptr < final_pixel) + { + int count; + + curbyte = *bufptr++; + count = (curbyte & 0x7F) + 1; + + if (curbyte & 0x80) /* RLE packet */ + { + int i; + + switch (bpp) + { + case 32: + blue = *bufptr++; + green = *bufptr++; + red = *bufptr++; + alpha = *bufptr++; + for (i = 0; i < count; i++) + { + WRITE_RGBA(dataptr, red, green, blue, alpha); + dataptr++; + } + break; + + case 24: + blue = *bufptr++; + green = *bufptr++; + red = *bufptr++; + for (i = 0; i < count; i++) + { + WRITE_RGBA(dataptr, red, green, blue, + (char)0xff); + dataptr++; + } + break; + + case 8: + alpha = *bufptr++; + for (i = 0; i < count; i++) + { + WRITE_RGBA(dataptr, alpha, alpha, alpha, + (char)0xff); + dataptr++; + } + break; + } + + } /* end if (RLE packet) */ + + else /* raw packet */ + { + int i; + + for (i = 0; i < count; i++) + { + switch (bpp) + { + + /* 32-bit BGRA pixels */ + case 32: + WRITE_RGBA(dataptr, *(bufptr + 2), /* R */ + *(bufptr + 1), /* G */ + *(bufptr + 0), /* B */ + *(bufptr + 3) /* A */ + ); + dataptr++; + bufptr += 4; + break; + + /* 24-bit BGR pixels */ + case 24: + WRITE_RGBA(dataptr, *(bufptr + 2), /* R */ + *(bufptr + 1), /* G */ + *(bufptr + 0), /* B */ + (char)0xff /* A */ + ); + dataptr++; + bufptr += 3; + break; + + /* 8-bit grayscale */ + case 8: + WRITE_RGBA(dataptr, *bufptr, /* pseudo-grayscale */ + *bufptr, *bufptr, (char)0xff); + dataptr++; + bufptr += 1; + break; + } + } + } /* end if (raw packet) */ + } /* end for (each packet) */ + /* must now flip a bottom-up image */ + if (vinverted) tgaflip(im->data, im->w, im->h); + if (progress) + { + char per; + int l; + + progress(im, 100, 0, 0, im->w, im->h); + } /* end for (each row) */ + } + /* end if (image is RLE) */ + } + /* end if (loading pixel data) */ + + munmap(seg, ss.st_size); + close(fd); + return 1; +} + +void +formats(ImlibLoader * l) +{ + char *list_formats[] = { "tga" }; + + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof(char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} + +/**********************/ + +/* flip a DATA32 image block vertically in place */ + +static void +tgaflip (DATA32 * in, int w, int h) +{ + DATA32 *adv, *adv2; + int x, y; + + adv = in; + adv2 = in + (w * (h - 1)); + + for (y = 0; y < (h / 2); y++) + { + DATA32 tmp; + for (x = 0; x < w; x++) + { + tmp = adv[x]; + adv[x] = adv2[x]; + adv2[x] = tmp; + } + adv2 -= w; + adv += w; + } +} diff --git a/src/modules/loaders/loader_tiff.c b/src/modules/loaders/loader_tiff.c new file mode 100644 index 0000000..b779bef --- /dev/null +++ b/src/modules/loaders/loader_tiff.c @@ -0,0 +1,494 @@ +/* To do: */ +/* o Need code to handle tiff with different orientations */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include + +#ifndef X_DISPLAY_MISSING +# include +# include +# include +#endif + +#include +#include +#include +#include "image.h" +#include + +/* This is a wrapper data structure for TIFFRGBAImage, so that data can be */ +/* passed into the callbacks. More elegent, I think, than a bunch of globals */ + +struct TIFFRGBAImage_Extra { + TIFFRGBAImage rgba; + tileContigRoutine put_contig; + tileSeparateRoutine put_separate; + ImlibImage *image; + ImlibProgressFunction progress; + char pper; + char progress_granularity; + uint32 num_pixels; + uint32 py; +}; + +typedef struct TIFFRGBAImage_Extra TIFFRGBAImage_Extra; + +static void put_contig_and_raster(TIFFRGBAImage *, uint32 *, + uint32, uint32, uint32, uint32, int32, + int32, unsigned char *); +static void put_separate_and_raster(TIFFRGBAImage *, uint32 *, uint32, + uint32, uint32, uint32, int32, + int32, unsigned char *, + unsigned char *, unsigned char *, + unsigned char *); +static void raster(TIFFRGBAImage_Extra * img, uint32 * raster, uint32 x, + uint32 y, uint32 w, uint32 h); +char load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity); +void formats(ImlibLoader * l); + +static void +put_contig_and_raster(TIFFRGBAImage * img, uint32 * rast, + uint32 x, uint32 y, uint32 w, uint32 h, + int32 fromskew, int32 toskew, unsigned char *cp) +{ + (*(((TIFFRGBAImage_Extra *) img)->put_contig)) (img, rast, x, y, w, h, + fromskew, toskew, cp); + raster((TIFFRGBAImage_Extra *) img, rast, x, y, w, h); +} + +static void +put_separate_and_raster(TIFFRGBAImage * img, uint32 * rast, + uint32 x, uint32 y, uint32 w, uint32 h, + int32 fromskew, int32 toskew, + unsigned char *r, unsigned char *g, unsigned char *b, + unsigned char *a) +{ + (*(((TIFFRGBAImage_Extra *) img)->put_separate)) + (img, rast, x, y, w, h, fromskew, toskew, r, g, b, a); + raster((TIFFRGBAImage_Extra *) img, rast, x, y, w, h); +} + +/* needs orientation code */ + +static void +raster(TIFFRGBAImage_Extra * img, uint32 * rast, + uint32 x, uint32 y, uint32 w, uint32 h) +{ + uint32 image_width, image_height; + uint32 *pixel, pixel_value; + int i, j, dy, rast_offset; + DATA32 *buffer_pixel, *buffer = img->image->data; + + image_width = img->image->w; + image_height = img->image->h; + + dy = h > y ? -1 : y - h; + + /* rast seems to point to the beginning of the last strip processed */ + /* so you need use negative offsets. Bizzare. Someone please check this */ + /* I don't understand why, but that seems to be what's going on. */ + /* libtiff needs better docs! */ + + for (i = y, rast_offset = 0; i > dy; i--, rast_offset--) + { + pixel = rast + (rast_offset * image_width); + buffer_pixel = buffer + ((((image_height - 1) - i) * image_width) + x); + + for (j = 0; j < w; j++) + { + pixel_value = (*(pixel++)); + (*(buffer_pixel++)) = + (TIFFGetA(pixel_value) << 24) | + (TIFFGetR(pixel_value) << 16) | (TIFFGetG(pixel_value) << 8) | + TIFFGetB(pixel_value); + } + } + + if (img->progress) + { + char per; + uint32 real_y = (image_height - 1) - y; + + if (w >= image_width) + { + per = (char)(((real_y + h - 1) * 100) / image_height); + + if (((per - img->pper) >= img->progress_granularity) || + (real_y + h) >= image_height) + { + (*img->progress) (img->image, per, 0, img->py, w, + (real_y + h) - img->py); + img->py = real_y + h; + img->pper = per; + } + } + else + { + /* for tile based images, we just progress each tile because */ + /* of laziness. Couldn't think of a good way to do this */ + per = (char)((w * h * 100) / img->num_pixels); + img->pper += per; + (*img->progress) (img->image, img->pper, x, + (image_height - 1) - y, w, h); + } + } +} + +char +load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) +{ + TIFF *tif = NULL; + FILE *file; + int fd; + uint16 magic_number; + TIFFRGBAImage_Extra rgba_image; + uint32 *rast = NULL; + uint32 width, height, num_pixels; + char txt[1024]; + + if (im->data) + return 0; + + file = fopen(im->real_file, "rb"); + + if (!file) + return 0; + + fread(&magic_number, sizeof(uint16), 1, file); + /* Apparently rewind(f) isn't sufficient */ + fseek(file, (long)0, SEEK_SET); + + if ((magic_number != TIFF_BIGENDIAN) /* Checks if actually tiff file */ + && (magic_number != TIFF_LITTLEENDIAN)) + { + fclose(file); + return 0; + } + + fd = fileno(file); + fd = dup(fd); + lseek(fd, (long)0, SEEK_SET); + fclose(file); + + tif = TIFFFdOpen(fd, im->real_file, "r"); + + if (!tif) + return 0; + + strcpy(txt, "Cannot be processed by libtiff"); + if (!TIFFRGBAImageOK(tif, txt)) + { + TIFFClose(tif); + return 0; + } + strcpy(txt, "Cannot begin reading tiff"); + if (!TIFFRGBAImageBegin((TIFFRGBAImage *) & rgba_image, tif, 0, + txt)) + { + TIFFClose(tif); + return 0; + } + + rgba_image.image = im; + im->w = width = rgba_image.rgba.width; + im->h = height = rgba_image.rgba.height; + rgba_image.num_pixels = num_pixels = width * height; + if (rgba_image.rgba.alpha != EXTRASAMPLE_UNSPECIFIED) + SET_FLAG(im->flags, F_HAS_ALPHA); + else + UNSET_FLAG(im->flags, F_HAS_ALPHA); + if (!im->format) + im->format = strdup("tiff"); + + if ((im->loader) || (immediate_load) || (progress)) + { + rgba_image.progress = progress; + rgba_image.pper = rgba_image.py = 0; + rgba_image.progress_granularity = progress_granularity; + rast = (uint32 *) _TIFFmalloc(sizeof(uint32) * num_pixels); + im->data = (DATA32 *) malloc(sizeof(DATA32) * num_pixels); + + if ((!rast) || (!im->data)) /* Error checking */ + { + fprintf(stderr, "imlib2-tiffloader: Out of memory\n"); + + if (!rast) + _TIFFfree(rast); + if (!im->data) + { + free(im->data); + im->data = NULL; + } + + TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image); + TIFFClose(tif); + + return 0; + } + + if (rgba_image.rgba.put.any == NULL) + { + fprintf(stderr, "imlib2-tiffloader: No put function"); + + _TIFFfree(rast); + free(im->data); + im->data = NULL; + TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image); + TIFFClose(tif); + + return 0; + } + else + { + if (rgba_image.rgba.isContig) + { + rgba_image.put_contig = rgba_image.rgba.put.contig; + rgba_image.rgba.put.contig = put_contig_and_raster; + } + else + { + rgba_image.put_separate = rgba_image.rgba.put.separate; + rgba_image.rgba.put.separate = put_separate_and_raster; + } + } +/* if (rgba_image.rgba.samplesperpixel == 8)*/ + if (rgba_image.rgba.bitspersample == 8) + { + if (!TIFFRGBAImageGet((TIFFRGBAImage *) & rgba_image, + rast, width, height)) + { + _TIFFfree(rast); + free(im->data); + im->data = NULL; + TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image); + TIFFClose(tif); + + return 0; + } + } + else + { + printf("channel bits == %i\n", (int)rgba_image.rgba.samplesperpixel); + } + + _TIFFfree(rast); + } + + TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image); + TIFFClose(tif); + + return 1; +} + +/* this seems to work, except the magic number isn't written. I'm guessing */ +/* this is a problem in libtiff */ + +char +save(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity) +{ + TIFF *tif = NULL; + uint8 *buf = NULL; + DATA32 pixel, *data = im->data; + double alpha_factor; + uint32 x, y; + uint8 r, g, b, a = 0; + int has_alpha = IMAGE_HAS_ALPHA(im); + int i = 0, pl = 0; + char pper = 0; + + /* By default uses patent-free use COMPRESSION_DEFLATE, + * another lossless compression technique */ + ImlibImageTag *tag; + int compression_type = COMPRESSION_DEFLATE; + + if (!im->data) + return 0; + + tif = TIFFOpen(im->real_file, "w"); + + if (!tif) + return 0; + + /* None of the TIFFSetFields are checked for errors, but since they */ + /* shouldn't fail, this shouldn't be a problem */ + + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, im->h); + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, im->w); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE); + + /* look for tags attached to image to get extra parameters like quality */ + /* settings etc. - this is the "api" to hint for extra information for */ + /* saver modules */ + + /* compression */ + tag = __imlib_GetTag(im, "compression_type"); + if (tag) + { + compression_type = tag->val; + switch (compression_type) + { + case COMPRESSION_NONE: + break; + case COMPRESSION_CCITTRLE: + break; + case COMPRESSION_CCITTFAX3: + break; + case COMPRESSION_CCITTFAX4: + break; + case COMPRESSION_LZW: + break; + case COMPRESSION_OJPEG: + break; + case COMPRESSION_JPEG: + break; + case COMPRESSION_NEXT: + break; + case COMPRESSION_CCITTRLEW: + break; + case COMPRESSION_PACKBITS: + break; + case COMPRESSION_THUNDERSCAN: + break; + case COMPRESSION_IT8CTPAD: + break; + case COMPRESSION_IT8LW: + break; + case COMPRESSION_IT8MP: + break; + case COMPRESSION_IT8BL: + break; + case COMPRESSION_PIXARFILM: + break; + case COMPRESSION_PIXARLOG: + break; + case COMPRESSION_DEFLATE: + break; + case COMPRESSION_ADOBE_DEFLATE: + break; + case COMPRESSION_DCS: + break; + case COMPRESSION_JBIG: + break; + case COMPRESSION_SGILOG: + break; + case COMPRESSION_SGILOG24: + break; + default: + compression_type = COMPRESSION_DEFLATE; + } + + } + TIFFSetField(tif, TIFFTAG_COMPRESSION, compression_type); + + if (has_alpha) + { + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4); + TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, EXTRASAMPLE_ASSOCALPHA); + } + else + { + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); + } + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, 0)); + + buf = (uint8 *) _TIFFmalloc(TIFFScanlineSize(tif)); + + if (!buf) + { + TIFFClose(tif); + return 0; + } + + for (y = 0; y < im->h; y++) + { + i = 0; + for (x = 0; x < im->w; x++) + { + pixel = data[(y * im->w) + x]; + + r = (pixel >> 16) & 0xff; + g = (pixel >> 8) & 0xff; + b = pixel & 0xff; + if (has_alpha) + { + /* TIFF makes you pre-mutiply the rgb components by alpha */ + a = (pixel >> 24) & 0xff; + alpha_factor = ((double)a / 255.0); + r *= alpha_factor; + g *= alpha_factor; + b *= alpha_factor; + } + + /* This might be endian dependent */ + buf[i++] = r; + buf[i++] = g; + buf[i++] = b; + if (has_alpha) + buf[i++] = a; + } + + if (!TIFFWriteScanline(tif, buf, y, 0)) + { + _TIFFfree(buf); + TIFFClose(tif); + return 0; + } + + if (progress) + { + char per; + int l; + + per = (char)((100 * y) / im->h); + if ((per - pper) >= progress_granularity) + { + l = y - pl; + (*progress) (im, per, 0, (y - l), im->w, l); + pper = per; + pl = y; + } + } + } + + _TIFFfree(buf); + TIFFClose(tif); + + return 1; +} + +/* fills the ImlibLoader struct with a strign array of format file */ +/* extensions this loader can load. eg: */ +/* loader->formats = { "jpeg", "jpg"}; */ +/* giving permutations is a good idea. case sensitivity is irrelevant */ +/* your laoder CAN load more than one format if it likes - like: */ +/* loader->formats = { "gif", "png", "jpeg", "jpg"} */ +/* if it can load those formats. */ +void +formats(ImlibLoader * l) +{ + /* this is the only bit you have to change... */ + char *list_formats[] = { "tiff", "tif" }; + + /* don't bother changing any of this - it just reads this in and sets */ + /* the struct values and makes copies */ + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof(char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} diff --git a/src/modules/loaders/loader_xpm.c b/src/modules/loaders/loader_xpm.c new file mode 100644 index 0000000..221d7df --- /dev/null +++ b/src/modules/loaders/loader_xpm.c @@ -0,0 +1,691 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include +#include +#include +#include +#include + +#ifndef X_DISPLAY_MISSING +# include +# include +# include +#endif + +#include "image.h" + +char load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity); +void formats(ImlibLoader * l); + +static FILE *rgb_txt = NULL; + +static void +xpm_parse_color(char *color, int *r, int *g, int *b) +{ + char buf[4096]; + + /* is a #ff00ff like color */ + if (color[0] == '#') + { + int len; + char val[32]; + + len = strlen(color) - 1; + if (len < 96) + { + int i; + + len /= 3; + for (i = 0; i < len; i++) + val[i] = color[1 + i + (0 * len)]; + val[i] = 0; + sscanf(val, "%x", r); + for (i = 0; i < len; i++) + val[i] = color[1 + i + (1 * len)]; + val[i] = 0; + sscanf(val, "%x", g); + for (i = 0; i < len; i++) + val[i] = color[1 + i + (2 * len)]; + val[i] = 0; + sscanf(val, "%x", b); + if (len == 1) + { + *r = (*r << 4) | *r; + *g = (*g << 4) | *g; + *b = (*b << 4) | *b; + } + else if (len > 2) + { + *r >>= (len - 2) * 4; + *g >>= (len - 2) * 4; + *b >>= (len - 2) * 4; + } + } + return; + } + /* look in rgb txt database */ + if (!rgb_txt) +#ifndef __EMX__ + rgb_txt = fopen("/usr/X11R6/lib/X11/rgb.txt", "r"); +#else + rgb_txt = fopen(__XOS2RedirRoot("/XFree86/lib/X11/rgb.txt"), "rt"); +#endif + if (!rgb_txt) + return; + fseek(rgb_txt, 0, SEEK_SET); + while (fgets(buf, 4000, rgb_txt)) + { + if (buf[0] != '!') + { + int rr, gg, bb; + char name[4096]; + + sscanf(buf, "%i %i %i %[^\n]", &rr, &gg, &bb, name); + if (!strcasecmp(name, color)) + { + *r = rr; + *g = gg; + *b = bb; + return; + } + } + } +} + +static void +xpm_parse_done(void) +{ + if (rgb_txt) + fclose(rgb_txt); + rgb_txt = NULL; +} + +char +load(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity, + char immediate_load) +{ + DATA32 *ptr, *end; + FILE *f; + + int pc, c, i, j, k, w, h, ncolors, cpp, comment, transp, + quote, context, len, done, r, g, b; + char *line, s[256], tok[128], col[256]; + int lsz = 256; + struct _cmap { + unsigned char str[6]; + unsigned char transp; + short r, g, b; + } *cmap; + + short lookup[128 - 32][128 - 32]; + float per = 0.0, per_inc = 0.0; + int last_per = 0, last_y = 0; + int count, pixels; + + done = 0; + transp = -1; + + /* if immediate_load is 1, then dont delay image laoding as below, or */ + /* already data in this image - dont load it again */ + + if (im->data) + { + xpm_parse_done(); + return 0; + } + f = fopen(im->real_file, "rb"); + if (!f) + { + xpm_parse_done(); + return 0; + } + fread(s, 1, 9, f); + rewind(f); + s[9] = 0; + if (strcmp("/* XPM */", s)) + { + fclose(f); + xpm_parse_done(); + return 0; + } + + i = 0; + j = 0; + cmap = NULL; + w = 10; + h = 10; + ptr = NULL; + end = NULL; + c = ' '; + comment = 0; + quote = 0; + context = 0; + pixels = 0; + count = 0; + line = malloc(lsz); + memset(lookup, 0, sizeof(lookup)); + while (!done) + { + pc = c; + c = fgetc(f); + if (c == EOF) + break; + if (!quote) + { + if ((pc == '/') && (c == '*')) + comment = 1; + else if ((pc == '*') && (c == '/') && (comment)) + comment = 0; + } + if (!comment) + { + if ((!quote) && (c == '"')) + { + quote = 1; + i = 0; + } + else if ((quote) && (c == '"')) + { + line[i] = 0; + quote = 0; + if (context == 0) + { + /* Header */ + sscanf(line, "%i %i %i %i", &w, &h, &ncolors, &cpp); + if (ncolors > 32766) + { + fprintf(stderr, + "IMLIB ERROR: XPM files with colors > 32766 not supported\n"); + free(line); + fclose(f); + xpm_parse_done(); + return 0; + } + if (cpp > 5) + { + fprintf(stderr, + "IMLIB ERROR: XPM files with characters per pixel > 5 not supported\n"); + free(line); + fclose(f); + xpm_parse_done(); + return 0; + } + if (w > 32767) + { + fprintf(stderr, + "IMLIB ERROR: Image width > 32767 pixels for file\n"); + free(line); + fclose(f); + xpm_parse_done(); + return 0; + } + if (h > 32767) + { + fprintf(stderr, + "IMLIB ERROR: Image height > 32767 pixels for file\n"); + free(line); + fclose(f); + xpm_parse_done(); + return 0; + } + im->w = w; + im->h = h; + if (!im->format) + im->format = strdup("xpm"); + + cmap = malloc(sizeof(struct _cmap) * ncolors); + + if (!cmap) + { + free(line); + fclose(f); + xpm_parse_done(); + return 0; + } + + per_inc = 100.0 / (((float)w) * h); + + j = 0; + context++; + } + else if (context == 1) + { + /* Color Table */ + if (j < ncolors) + { + int slen; + int hascolor, iscolor; + + iscolor = 0; + hascolor = 0; + tok[0] = 0; + col[0] = 0; + s[0] = 0; + len = strlen(line); + strncpy(cmap[j].str, line, cpp); + cmap[j].str[cpp] = 0; + cmap[j].r = -1; + cmap[j].transp = 0; + for (k = cpp; k < len; k++) + { + if (line[k] != ' ') + { + s[0] = 0; + sscanf(&line[k], "%65535s", s); + slen = strlen(s); + k += slen; + if (!strcmp(s, "c")) + iscolor = 1; + if ((!strcmp(s, "m")) || (!strcmp(s, "s")) + || (!strcmp(s, "g4")) + || (!strcmp(s, "g")) + || (!strcmp(s, "c")) || (k >= len)) + { + if (k >= len) + { + if (col[0]) + strcat(col, " "); + if (strlen(col) + strlen(s) < + sizeof(col)) + strcat(col, s); + } + if (col[0]) + { + if (!strcasecmp(col, "none")) + { + transp = 1; + cmap[j].transp = 1; + } + else + { + if ((((cmap[j].r < 0) || + (!strcmp(tok, "c"))) + && (!hascolor))) + { + r = 0; + g = 0; + b = 0; + xpm_parse_color(col, + &r, + &g, + &b); + cmap[j].r = r; + cmap[j].g = g; + cmap[j].b = b; + if (iscolor) + hascolor = 1; + } + } + } + strcpy(tok, s); + col[0] = 0; + } + else + { + if (col[0]) + strcat(col, " "); + strcat(col, s); + } + } + } + } + j++; + if (j >= ncolors) + { + if (cpp == 1) + for (i = 0; i < ncolors; i++) + lookup[(int)cmap[i].str[0] - 32][0] = i; + if (cpp == 2) + for (i = 0; i < ncolors; i++) + lookup[(int)cmap[i].str[0] - + 32][(int)cmap[i].str[1] - 32] = i; + context++; + } + + if (transp >= 0) + { + SET_FLAG(im->flags, F_HAS_ALPHA); + } + else + { + UNSET_FLAG(im->flags, F_HAS_ALPHA); + } + + if (im->loader || immediate_load || progress) + { + im->data = + (DATA32 *) malloc(sizeof(DATA32) * im->w * + im->h); + if (!im->data) + { + free(cmap); + free(line); + fclose(f); + xpm_parse_done(); + return 0; + } + ptr = im->data; + end = ptr + (sizeof(DATA32) * w * h); + pixels = w * h; + } + else + { + free(cmap); + free(line); + fclose(f); + xpm_parse_done(); + return 1; + } + } + else + { + /* Image Data */ + i = 0; + if (cpp == 0) + { + /* Chars per pixel = 0? well u never know */ + } + if (cpp == 1) + { + if (transp) + { + for (i = 0; + ((i < 65536) && (ptr < end) && (line[i])); + i++) + { + col[0] = line[i]; + if (cmap[lookup[(int)col[0] - 32][0]]. + transp) + { + r = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [0]].r; + g = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [0]].g; + b = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [0]].b; + *ptr++ = + 0x00ffffff & ((r << 16) | + (g << 8) | b); + count++; + } + else + { + r = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [0]].r; + g = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [0]].g; + b = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [0]].b; + *ptr++ = + (0xff << 24) | (r << 16) | (g << + 8) | + b; + count++; + } + } + } + else + { + for (i = 0; + ((i < 65536) && (ptr < end) && (line[i])); + i++) + { + col[0] = line[i]; + r = (unsigned char) + cmap[lookup[(int)col[0] - 32][0]].r; + g = (unsigned char) + cmap[lookup[(int)col[0] - 32][0]].g; + b = (unsigned char) + cmap[lookup[(int)col[0] - 32][0]].b; + *ptr++ = + (0xff << 24) | (r << 16) | (g << 8) | + b; + count++; + } + } + } + else if (cpp == 2) + { + if (transp) + { + for (i = 0; + ((i < 65536) && (ptr < end) && (line[i])); + i++) + { + col[0] = line[i++]; + col[1] = line[i]; + if (cmap + [lookup[(int)col[0] - 32] + [(int)col[1] - 32]].transp) + { + r = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [(int)col[1] - 32]].r; + g = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [(int)col[1] - 32]].g; + b = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [(int)col[1] - 32]].b; + *ptr++ = + 0x00ffffff & ((r << 16) | + (g << 8) | b); + count++; + } + else + { + r = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [(int)col[1] - 32]].r; + g = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [(int)col[1] - 32]].g; + b = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [(int)col[1] - 32]].b; + *ptr++ = + (0xff << 24) | (r << 16) | (g << + 8) | + b; + count++; + } + } + } + else + { + for (i = 0; + ((i < 65536) && (ptr < end) && (line[i])); + i++) + { + col[0] = line[i++]; + col[1] = line[i]; + r = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [(int)col[1] - 32]].r; + g = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [(int)col[1] - 32]].g; + b = (unsigned char) + cmap[lookup[(int)col[0] - 32] + [(int)col[1] - 32]].b; + *ptr++ = + (0xff << 24) | (r << 16) | (g << 8) | + b; + count++; + } + } + } + else + { + if (transp) + { + for (i = 0; + ((i < 65536) && (ptr < end) && (line[i])); + i++) + { + for (j = 0; j < cpp; j++, i++) + { + col[j] = line[i]; + } + col[j] = 0; + i--; + for (j = 0; j < ncolors; j++) + { + if (!strcmp(col, cmap[j].str)) + { + if (cmap[j].transp) + { + r = (unsigned char) + cmap[lookup + [(int)col[0] - + 32][0]].r; + g = (unsigned char) + cmap[lookup + [(int)col[0] - + 32][0]].g; + b = (unsigned char) + cmap[lookup + [(int)col[0] - + 32][0]].b; + *ptr++ = + 0x00ffffff & ((r << 16) + | (g << + 8) | + b); + count++; + } + else + { + r = (unsigned char)cmap[j]. + r; + g = (unsigned char)cmap[j]. + g; + b = (unsigned char)cmap[j]. + b; + *ptr++ = + (0xff << 24) | (r << + 16) | + (g << 8) | b; + count++; + } + j = ncolors; + } + } + } + } + else + { + for (i = 0; + ((i < 65536) && (ptr < end) && (line[i])); + i++) + { + for (j = 0; j < cpp; j++, i++) + { + col[j] = line[i]; + } + col[j] = 0; + i--; + for (j = 0; j < ncolors; j++) + { + if (!strcmp(col, cmap[j].str)) + { + r = (unsigned char)cmap[j].r; + g = (unsigned char)cmap[j].g; + b = (unsigned char)cmap[j].b; + *ptr++ = + (0xff << 24) | (r << 16) | + (g << 8) | b; + count++; + j = ncolors; + } + } + } + } + } + per += per_inc; + if (progress && (((int)per) != last_per) + && (((int)per) % progress_granularity == 0)) + { + last_per = (int)per; + if (!(progress(im, (int)per, 0, last_y, w, i))) + { + fclose(f); + free(cmap); + free(line); + xpm_parse_done(); + return 2; + } + last_y = i; + } + } + } + } + /* Scan in line from XPM file */ + if ((!comment) && (quote) && (c != '"')) + { + if (c < 32) + c = 32; + else if (c > 127) + c = 127; + line[i++] = c; + } + if (i >= lsz) + { + lsz += 256; + line = realloc(line, lsz); + } + if (((ptr) && ((ptr - im->data) >= (w * h * sizeof(DATA32)))) || + ((context > 1) && (count >= pixels))) + done = 1; + } + + if (progress) + { + progress(im, 100, 0, last_y, w, h); + } + + fclose(f); + free(cmap); + free(line); + + xpm_parse_done(); + + return 1; +} + +/* fills the ImlibLoader struct with a strign array of format file */ +/* extensions this loader can load. eg: */ +/* loader->formats = { "jpeg", "jpg"}; */ +/* giving permutations is a good idea. case sensitivity is irrelevant */ +/* your laoder CAN load more than one format if it likes - like: */ +/* loader->formats = { "gif", "png", "jpeg", "jpg"} */ +/* if it can load those formats. */ +void +formats(ImlibLoader * l) +{ + /* this is the only bit you have to change... */ + char *list_formats[] = { "xpm" }; + + /* don't bother changing any of this - it just reads this in and sets */ + /* the struct values and makes copies */ + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof(char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} diff --git a/src/modules/loaders/loader_zlib.c b/src/modules/loaders/loader_zlib.c new file mode 100644 index 0000000..924b925 --- /dev/null +++ b/src/modules/loaders/loader_zlib.c @@ -0,0 +1,124 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "image.h" + +#define OUTBUF_SIZE 16484 +#define INBUF_SIZE 1024 + +static int handle_buffer (DATA8 *src, unsigned long src_len, + DATA8 **dest, unsigned long *dest_len) +{ + static DATA8 outbuf[OUTBUF_SIZE]; + uLongf outbuf_len = OUTBUF_SIZE; + int res; + + assert (src); + assert (src_len); + assert (dest); + assert (dest_len); + + res = uncompress (outbuf, &outbuf_len, src, src_len); + + switch (res) { + case Z_OK: + *dest = outbuf; + *dest_len = (unsigned long) outbuf_len; + return 1; + case Z_BUF_ERROR: + return 0; + default: + *dest = NULL; + *dest_len = 0; + return 0; + } +} + +static void uncompress_file (int src, int dest, off_t size) +{ + DATA8 inbuf[INBUF_SIZE], *outbuf; + off_t left; + ssize_t inlen; + unsigned long outlen = 0; + + for (left = size; left; left -= inlen) { + inlen = read (src, inbuf, MIN (left, INBUF_SIZE)); + + if (inlen <= 0) + break; + + if (handle_buffer (inbuf, inlen, &outbuf, &outlen)) + write (dest, outbuf, outlen); + } +} + +char load (ImlibImage *im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) +{ + ImlibLoader *loader; + int src, dest; + char *file, tmp[] = "/tmp/imlib2_loader_zlib-XXXXXX"; + struct stat st; + + assert (im); + + /* we'll need a copy of it later */ + file = im->real_file; + + if (stat (im->real_file, &st) < 0) + return 0; + + if ((dest = mkstemp (tmp)) < 0) + return 0; + + if ((src = open (im->real_file, O_RDONLY)) < 0) { + unlink (tmp); + return 0; + } + + uncompress_file (src, dest, st.st_size); + + close (src); + close (dest); + + if (!(loader = __imlib_FindBestLoaderForFile (tmp, 0))) { + unlink (tmp); + return 0; + } + + free (im->real_file); + im->real_file = strdup (tmp); + loader->load (im, progress, progress_granularity, immediate_load); + + free (im->real_file); + im->real_file = strdup (file); + unlink (tmp); + + return 1; +} + +void formats (ImlibLoader *l) +{ + /* this is the only bit you have to change... */ + char *list_formats[] = {"gz"}; + int i; + + /* don't bother changing any of this - it just reads this in + * and sets the struct values and makes copies + */ + l->num_formats = sizeof (list_formats) / sizeof (char *); + l->formats = malloc (sizeof (char *) * l->num_formats); + + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup (list_formats[i]); +}