Code refactoring: replaced macro 'HAVE_XRANDR' by 'USE_XRANDR' for consistency
[wmaker-crm.git] / wrlib / rotate.c
blobf04b95ebc64d65d2d0869caa396dce21e270799c
1 /* rotate.c - image rotation
3 * Raster graphics library
5 * Copyright (c) 2000-2003 Alfredo K. Kojima
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
23 #include <config.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <X11/Xlib.h>
29 #include "wraster.h"
31 #include <math.h>
33 #ifndef PI
34 #define PI 3.14159265358979323846
35 #endif
37 static RImage *rotateImage(RImage * image, float angle);
39 RImage *RRotateImage(RImage * image, float angle)
41 RImage *img;
42 int nwidth, nheight;
43 int x, y;
44 int bpp = image->format == RRGBAFormat ? 4 : 3;
47 * Angle steps below this value would represent a rotation
48 * of less than 1 pixel for a 4k wide image, so not worth
49 * bothering the difference. That makes it a perfect
50 * candidate for an Epsilon when trying to compare angle
51 * to known values
53 static const float min_usable_angle = 0.00699;
55 angle = fmod(angle, 360.0);
56 if (angle < 0.0)
57 angle += 360.0;
59 if (angle < min_usable_angle) {
60 /* Rotate by 0 degree */
61 return RCloneImage(image);
63 } else if ((angle > 90.0 - min_usable_angle) &&
64 (angle < 90.0 + min_usable_angle)) {
65 nwidth = image->height;
66 nheight = image->width;
68 img = RCreateImage(nwidth, nheight, True);
69 if (!img) {
70 return NULL;
73 if (bpp == 3) {
74 unsigned char *optr, *nptr;
75 unsigned offs;
77 offs = nwidth * 4;
79 optr = image->data;
80 nptr = img->data;
82 for (x = 0; x < nwidth; x++) {
83 nptr = img->data + x * 4;
84 for (y = nheight; y; y--) {
85 nptr[0] = *optr++;
86 nptr[1] = *optr++;
87 nptr[2] = *optr++;
88 nptr[3] = 255;
90 nptr += offs;
93 } else {
94 unsigned *optr, *nptr;
95 unsigned *p;
97 optr = (unsigned *)image->data;
98 p = (unsigned *)img->data;
99 for (x = 0; x < nwidth; x++) {
100 nptr = p++;
101 for (y = nheight; y; y--) {
102 *nptr = *optr++;
103 nptr += nwidth;
107 } else if ((angle > 180.0 - min_usable_angle) &&
108 (angle < 180.0 + min_usable_angle)) {
110 nwidth = image->width;
111 nheight = image->height;
112 img = RCreateImage(nwidth, nheight, True);
113 if (!img) {
114 return NULL;
117 if (bpp == 3) {
118 unsigned char *optr, *nptr;
120 optr = image->data;
121 nptr = img->data + nwidth * nheight * 4 - 4;
123 for (y = 0; y < nheight; y++) {
124 for (x = 0; x < nwidth; x++) {
125 nptr[0] = optr[0];
126 nptr[1] = optr[1];
127 nptr[2] = optr[2];
128 nptr[3] = 255;
130 optr += 3;
131 nptr -= 4;
134 } else {
135 unsigned *optr, *nptr;
137 optr = (unsigned *)image->data;
138 nptr = (unsigned *)img->data + nwidth * nheight - 1;
140 for (y = nheight * nwidth - 1; y >= 0; y--) {
141 *nptr = *optr;
142 optr++;
143 nptr--;
146 } else if ((angle > 270.0 - min_usable_angle) &&
147 (angle < 270.0 + min_usable_angle)) {
148 nwidth = image->height;
149 nheight = image->width;
151 img = RCreateImage(nwidth, nheight, True);
152 if (!img) {
153 return NULL;
156 if (bpp == 3) {
157 unsigned char *optr, *nptr;
158 unsigned offs;
160 offs = nwidth * 4;
162 optr = image->data;
163 nptr = img->data;
165 for (x = 0; x < nwidth; x++) {
166 nptr = img->data + x * 4;
167 for (y = nheight; y; y--) {
168 nptr[0] = *optr++;
169 nptr[1] = *optr++;
170 nptr[2] = *optr++;
171 nptr[3] = 255;
173 nptr += offs;
176 } else {
177 unsigned *optr, *nptr;
178 unsigned *p;
180 optr = (unsigned *)image->data;
181 p = (unsigned *)img->data + nwidth * nheight;
182 for (x = 0; x < nwidth; x++) {
183 nptr = p--;
184 for (y = nheight; y; y--) {
185 *nptr = *optr++;
186 nptr -= nwidth;
190 } else {
191 img = rotateImage(image, angle);
194 return img;
198 * Image rotation through Bresenham's line algorithm:
200 * If a square must be rotate by angle a, like in:
201 * _______
202 * | B |
203 * | /4\ |
204 * | /3 8\|
205 * | /2 7 /|
206 * |A1 6 / | A_______B
207 * | \5 / a| <--- |1 2 3 4|
208 * |__C/_)_| |5 6 7 8|
209 * C-------
211 * for each point P1 in the line from C to A
212 * for each point P2 in the perpendicular line starting at P1
213 * get pixel from the source and plot at P2
214 * increment pixel location from source
218 static void
219 copyLine(int x1, int y1, int x2, int y2, int nwidth, int format, unsigned char *dst, unsigned char **src)
221 unsigned char *s = *src;
222 int dx, dy;
223 int xi, yi;
224 int offset;
225 int dpr, dpru, p;
227 dx = abs(x2 - x1);
228 dy = abs(y2 - y1);
230 if (x1 > x2)
231 xi = -1;
232 else
233 xi = 1;
234 if (y1 > y2)
235 yi = -1;
236 else
237 yi = 1;
239 if (dx >= dy) {
241 dpr = dy << 1;
242 dpru = dpr - (dx << 1);
243 p = dpr - dx;
245 while (dx-- >= 0) {
246 /* fetch and draw the pixel */
247 offset = (x1 + y1 * nwidth) << 2;
248 dst[offset++] = *s++;
249 dst[offset++] = *s++;
250 dst[offset++] = *s++;
251 if (format == RRGBAFormat)
252 dst[offset++] = *s++;
253 else
254 dst[offset++] = 255;
256 /* calc next step */
257 if (p > 0) {
258 x1 += xi;
259 y1 += yi;
260 p += dpru;
261 } else {
262 x1 += xi;
263 p += dpr;
266 } else {
268 dpr = dx << 1;
269 dpru = dpr - (dy << 1);
270 p = dpr - dy;
272 while (dy-- >= 0) {
273 /* fetch and draw the pixel */
274 offset = (x1 + y1 * nwidth) << 2;
275 dst[offset++] = *s++;
276 dst[offset++] = *s++;
277 dst[offset++] = *s++;
278 if (format == RRGBAFormat)
279 dst[offset++] = *s++;
280 else
281 dst[offset++] = 255;
283 /* calc next step */
284 if (p > 0) {
285 x1 += xi;
286 y1 += yi;
287 p += dpru;
288 } else {
289 y1 += yi;
290 p += dpr;
295 *src = s;
298 static RImage *rotateImage(RImage * image, float angle)
300 RImage *img;
301 int nwidth, nheight;
302 int x1, y1;
303 int x2, y2;
304 int dx, dy;
305 int xi, yi;
306 int xx, yy;
307 unsigned char *src, *dst;
308 int dpr, dpru, p;
310 /* only 180o for now */
311 if (angle > 180.0)
312 angle -= 180.0;
314 angle = (angle * PI) / 180.0;
316 nwidth = ceil(abs(cos(angle) * image->width))
317 + ceil(abs(cos(PI / 2 - angle) * image->width));
319 nheight = ceil(abs(sin(angle) * image->height))
320 + ceil(abs(cos(PI / 2 - angle) * image->height));
322 img = RCreateImage(nwidth, nheight, True);
323 if (!img)
324 return NULL;
326 src = image->data;
327 dst = img->data;
329 x1 = floor(abs(cos(PI / 2 - angle) * image->width));
330 y1 = 0;
332 x2 = 0;
333 y2 = floor(abs(sin(PI / 2 - angle) * image->width));
335 xx = floor(abs(cos(angle) * image->height)) - 1;
336 yy = nheight - 1;
338 printf("%ix%i, %i %i %i %i %i\n", nwidth, nheight, x1, y1, x2, y2, (int)((angle * 180.0) / PI));
340 dx = abs(x2 - x1);
341 dy = abs(y2 - y1);
343 if (x1 > x2)
344 xi = -1;
345 else
346 xi = 1;
347 if (y1 > y2)
348 yi = -1;
349 else
350 yi = 1;
352 if (dx >= dy) {
353 dpr = dy << 1;
354 dpru = dpr - (dx << 1);
355 p = dpr - dx;
357 while (dx-- >= 0) {
359 copyLine(x1, y1, xx, yy, nwidth, image->format, dst, &src);
361 /* calc next step */
363 if (p > 0) {
364 x1 += xi;
365 y1 += yi;
366 xx += xi;
367 yy += yi;
368 p += dpru;
369 } else {
370 x1 += xi;
371 xx += xi;
372 p += dpr;
375 } else {
376 puts("NOT IMPLEMTENED");
377 return img;
378 dpr = dx << 1;
379 dpru = dpr - (dy << 1);
380 p = dpr - dy;
382 while (dy-- >= 0) {
383 xx = abs(x1 * sin(angle * PI / 180.0));
384 yy = abs(y1 * cos(angle * PI / 180.0));
386 copyLine(x1, y1, xx, yy, nwidth, image->format, dst, &src);
388 /* calc next step */
389 if (p > 0) {
390 x1 += xi;
391 y1 += yi;
392 p += dpru;
393 } else {
394 y1 += yi;
395 p += dpr;
400 return img;