- Fixed a bug that crashed wmaker when selecting the "Start alternate window
[wmaker-crm.git] / wrlib / rotate.c
blobefc9324f54bcdb35d75327ee68ada59d03546e74
1 /* rotate.c - image rotation
2 *
3 * Raster graphics library
4 *
5 * Copyright (c) 2000-2002 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., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <config.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <X11/Xlib.h>
28 #include "wraster.h"
30 #include <math.h>
32 #ifndef PI
33 #define PI 3.14159265358979323846
34 #endif
37 static RImage *rotateImage(RImage *image, float angle);
40 RImage*
41 RRotateImage(RImage *image, float angle)
43 RImage *img;
44 int nwidth, nheight;
45 int x, y;
46 int bpp = image->format == RRGBAFormat ? 4 : 3;
48 angle = ((int)angle % 360) + (angle - (int)angle);
50 if (angle == 0.0) {
51 return RCloneImage(image);
53 } else if (angle == 90.0) {
54 nwidth = image->height;
55 nheight = image->width;
57 img = RCreateImage(nwidth, nheight, True);
58 if (!img) {
59 return NULL;
62 if (bpp == 3) {
63 unsigned char *optr, *nptr;
64 unsigned offs;
67 offs = nwidth * 4;
69 optr = image->data;
70 nptr = img->data;
72 for (x = 0; x < nwidth; x++) {
73 nptr = img->data + x*4;
74 for (y = nheight; y; y--) {
75 nptr[0] = *optr++;
76 nptr[1] = *optr++;
77 nptr[2] = *optr++;
78 nptr[3] = 255;
80 nptr += offs;
83 } else {
84 unsigned *optr, *nptr;
85 unsigned *p;
87 optr = (unsigned*)image->data;
88 p = (unsigned*)img->data;
89 for (x = 0; x < nwidth; x++) {
90 nptr = p++;
91 for (y = nheight; y; y--) {
92 *nptr = *optr++;
93 nptr += nwidth;
97 } else if (angle == 180.0) {
99 nwidth = image->width;
100 nheight = image->height;
101 img = RCreateImage(nwidth, nheight, True);
102 if (!img) {
103 return NULL;
106 if (bpp == 3) {
107 unsigned char *optr, *nptr;
109 optr = image->data;
110 nptr = img->data + nwidth * nheight * 4 - 4;
112 for (y = 0; y < nheight; y++) {
113 for (x = 0; x < nwidth; x++) {
114 nptr[0] = optr[0];
115 nptr[1] = optr[1];
116 nptr[2] = optr[2];
117 nptr[3] = 255;
119 optr += 3;
120 nptr -= 4;
123 } else {
124 unsigned *optr, *nptr;
126 optr = (unsigned*)image->data;
127 nptr = (unsigned*)img->data + nwidth * nheight - 1;
129 for (y = nheight*nwidth-1; y >= 0; y--) {
130 *nptr = *optr;
131 optr++;
132 nptr--;
135 } else if (angle == 270.0) {
136 nwidth = image->height;
137 nheight = image->width;
139 img = RCreateImage(nwidth, nheight, True);
140 if (!img) {
141 return NULL;
144 if (bpp == 3) {
145 unsigned char *optr, *nptr;
146 unsigned offs;
149 offs = nwidth * 4;
151 optr = image->data;
152 nptr = img->data;
154 for (x = 0; x < nwidth; x++) {
155 nptr = img->data + x*4;
156 for (y = nheight; y; y--) {
157 nptr[0] = *optr++;
158 nptr[1] = *optr++;
159 nptr[2] = *optr++;
160 nptr[3] = 255;
162 nptr += offs;
165 } else {
166 unsigned *optr, *nptr;
167 unsigned *p;
169 optr = (unsigned*)image->data;
170 p = (unsigned*)img->data + nwidth*nheight;
171 for (x = 0; x < nwidth; x++) {
172 nptr = p--;
173 for (y = nheight; y; y--) {
174 *nptr = *optr++;
175 nptr -= nwidth;
179 } else {
180 img = rotateImage(image, angle);
183 return img;
190 * Image rotation through Bresenham's line algorithm:
192 * If a square must be rotate by angle a, like in:
193 * _______
194 * | B |
195 * | /4\ |
196 * | /3 8\|
197 * | /2 7 /|
198 * |A1 6 / | A_______B
199 * | \5 / a| <--- |1 2 3 4|
200 * |__C/_)_| |5 6 7 8|
201 * C-------
203 * for each point P1 in the line from C to A
204 * for each point P2 in the perpendicular line starting at P1
205 * get pixel from the source and plot at P2
206 * increment pixel location from source
211 static void
212 copyLine(int x1, int y1, int x2, int y2, int nwidth, int format,
213 unsigned char *dst, unsigned char **src)
215 unsigned char *s = *src;
216 int dx, dy;
217 int xi, yi;
218 int offset;
219 int dpr, dpru, p;
221 dx = abs(x2 - x1);
222 dy = abs(y2 - y1);
224 if (x1 > x2) xi = -1; else xi = 1;
225 if (y1 > y2) yi = -1; else yi = 1;
227 if (dx >= dy) {
229 dpr = dy << 1;
230 dpru = dpr - (dx << 1);
231 p = dpr - dx;
233 while (dx-- >= 0) {
234 /* fetch and draw the pixel */
235 offset = (x1 + y1 * nwidth) << 2;
236 dst[offset++] = *s++;
237 dst[offset++] = *s++;
238 dst[offset++] = *s++;
239 if (format == RRGBAFormat)
240 dst[offset++] = *s++;
241 else
242 dst[offset++] = 255;
244 /* calc next step */
245 if (p > 0) {
246 x1 += xi;
247 y1 += yi;
248 p += dpru;
249 } else {
250 x1 += xi;
251 p += dpr;
254 } else {
256 dpr = dx << 1;
257 dpru = dpr - (dy << 1);
258 p = dpr - dy;
260 while (dy-- >= 0) {
261 /* fetch and draw the pixel */
262 offset = (x1 + y1 * nwidth) << 2;
263 dst[offset++] = *s++;
264 dst[offset++] = *s++;
265 dst[offset++] = *s++;
266 if (format == RRGBAFormat)
267 dst[offset++] = *s++;
268 else
269 dst[offset++] = 255;
271 /* calc next step */
272 if (p > 0) {
273 x1 += xi;
274 y1 += yi;
275 p += dpru;
276 } else {
277 y1 += yi;
278 p += dpr;
284 *src = s;
288 static RImage*
289 rotateImage(RImage *image, float angle)
291 RImage *img;
292 int nwidth, nheight;
293 int x1, y1;
294 int x2, y2;
295 int dx, dy;
296 int xi, yi;
297 int xx, yy;
298 unsigned char *src, *dst;
299 int dpr, dpru, p;
301 /* only 180o for now */
302 if (angle > 180.0)
303 angle -= 180.0;
306 angle = (angle * PI) / 180.0;
308 nwidth = ceil(abs(cos(angle) * image->width))
309 + ceil(abs(cos(PI/2 - angle) * image->width));
311 nheight = ceil(abs(sin(angle) * image->height))
312 + ceil(abs(cos(PI/2 - angle) * image->height));
314 img = RCreateImage(nwidth, nheight, True);
315 if (!img)
316 return NULL;
318 src = image->data;
319 dst = img->data;
321 x1 = floor(abs(cos(PI/2 - angle)*image->width));
322 y1 = 0;
324 x2 = 0;
325 y2 = floor(abs(sin(PI/2 - angle)*image->width));
327 xx = floor(abs(cos(angle)*image->height)) - 1;
328 yy = nheight - 1;
330 printf("%ix%i, %i %i %i %i %i\n",
331 nwidth, nheight, x1, y1, x2, y2, (int)((angle*180.0)/PI));
333 dx = abs(x2 - x1);
334 dy = abs(y2 - y1);
336 if (x1 > x2) xi = -1; else xi = 1;
337 if (y1 > y2) yi = -1; else yi = 1;
339 if (dx >= dy) {
340 dpr = dy << 1;
341 dpru = dpr - (dx << 1);
342 p = dpr - dx;
344 while (dx-- >= 0) {
346 copyLine(x1, y1, xx, yy, nwidth, image->format, dst, &src);
348 /* calc next step */
350 if (p > 0) {
351 x1 += xi;
352 y1 += yi;
353 xx += xi;
354 yy += yi;
355 p += dpru;
356 } else {
357 x1 += xi;
358 xx += xi;
359 p += dpr;
362 } else {
363 puts("NOT IMPLEMTENED");
364 return img;
365 dpr = dx << 1;
366 dpru = dpr - (dy << 1);
367 p = dpr - dy;
369 while (dy-- >= 0) {
370 xx = abs(x1*sin(angle*PI/180.0));
371 yy = abs(y1*cos(angle*PI/180.0));
373 copyLine(x1, y1, xx, yy, nwidth, image->format, dst, &src);
375 /* calc next step*/
376 if (p > 0) {
377 x1 += xi;
378 y1 += yi;
379 p += dpru;
380 } else {
381 y1 += yi;
382 p += dpr;
387 return img;