Change to the linux kernel coding style
[wmaker-crm.git] / wrlib / rotate.c
1 /* rotate.c - image rotation
2 *
3 * Raster graphics library
4 *
5 * Copyright (c) 2000-2003 Alfredo K. Kojima
6 *
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.
11 *
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.
16 *
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.
20 */
21
22 #include <config.h>
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <X11/Xlib.h>
28 #include "wraster.h"
29
30 #include <math.h>
31
32 #ifndef PI
33 #define PI 3.14159265358979323846
34 #endif
35
36 static RImage *rotateImage(RImage * image, float angle);
37
38 RImage *RRotateImage(RImage * image, float angle)
39 {
40 RImage *img;
41 int nwidth, nheight;
42 int x, y;
43 int bpp = image->format == RRGBAFormat ? 4 : 3;
44
45 angle = ((int)angle % 360) + (angle - (int)angle);
46
47 if (angle == 0.0) {
48 return RCloneImage(image);
49
50 } else if (angle == 90.0) {
51 nwidth = image->height;
52 nheight = image->width;
53
54 img = RCreateImage(nwidth, nheight, True);
55 if (!img) {
56 return NULL;
57 }
58
59 if (bpp == 3) {
60 unsigned char *optr, *nptr;
61 unsigned offs;
62
63 offs = nwidth * 4;
64
65 optr = image->data;
66 nptr = img->data;
67
68 for (x = 0; x < nwidth; x++) {
69 nptr = img->data + x * 4;
70 for (y = nheight; y; y--) {
71 nptr[0] = *optr++;
72 nptr[1] = *optr++;
73 nptr[2] = *optr++;
74 nptr[3] = 255;
75
76 nptr += offs;
77 }
78 }
79 } else {
80 unsigned *optr, *nptr;
81 unsigned *p;
82
83 optr = (unsigned *)image->data;
84 p = (unsigned *)img->data;
85 for (x = 0; x < nwidth; x++) {
86 nptr = p++;
87 for (y = nheight; y; y--) {
88 *nptr = *optr++;
89 nptr += nwidth;
90 }
91 }
92 }
93 } else if (angle == 180.0) {
94
95 nwidth = image->width;
96 nheight = image->height;
97 img = RCreateImage(nwidth, nheight, True);
98 if (!img) {
99 return NULL;
100 }
101
102 if (bpp == 3) {
103 unsigned char *optr, *nptr;
104
105 optr = image->data;
106 nptr = img->data + nwidth * nheight * 4 - 4;
107
108 for (y = 0; y < nheight; y++) {
109 for (x = 0; x < nwidth; x++) {
110 nptr[0] = optr[0];
111 nptr[1] = optr[1];
112 nptr[2] = optr[2];
113 nptr[3] = 255;
114
115 optr += 3;
116 nptr -= 4;
117 }
118 }
119 } else {
120 unsigned *optr, *nptr;
121
122 optr = (unsigned *)image->data;
123 nptr = (unsigned *)img->data + nwidth * nheight - 1;
124
125 for (y = nheight * nwidth - 1; y >= 0; y--) {
126 *nptr = *optr;
127 optr++;
128 nptr--;
129 }
130 }
131 } else if (angle == 270.0) {
132 nwidth = image->height;
133 nheight = image->width;
134
135 img = RCreateImage(nwidth, nheight, True);
136 if (!img) {
137 return NULL;
138 }
139
140 if (bpp == 3) {
141 unsigned char *optr, *nptr;
142 unsigned offs;
143
144 offs = nwidth * 4;
145
146 optr = image->data;
147 nptr = img->data;
148
149 for (x = 0; x < nwidth; x++) {
150 nptr = img->data + x * 4;
151 for (y = nheight; y; y--) {
152 nptr[0] = *optr++;
153 nptr[1] = *optr++;
154 nptr[2] = *optr++;
155 nptr[3] = 255;
156
157 nptr += offs;
158 }
159 }
160 } else {
161 unsigned *optr, *nptr;
162 unsigned *p;
163
164 optr = (unsigned *)image->data;
165 p = (unsigned *)img->data + nwidth * nheight;
166 for (x = 0; x < nwidth; x++) {
167 nptr = p--;
168 for (y = nheight; y; y--) {
169 *nptr = *optr++;
170 nptr -= nwidth;
171 }
172 }
173 }
174 } else {
175 img = rotateImage(image, angle);
176 }
177
178 return img;
179 }
180
181 /*
182 * Image rotation through Bresenham's line algorithm:
183 *
184 * If a square must be rotate by angle a, like in:
185 * _______
186 * | B |
187 * | /4\ |
188 * | /3 8\|
189 * | /2 7 /|
190 * |A1 6 / | A_______B
191 * | \5 / a| <--- |1 2 3 4|
192 * |__C/_)_| |5 6 7 8|
193 * C-------
194 *
195 * for each point P1 in the line from C to A
196 * for each point P2 in the perpendicular line starting at P1
197 * get pixel from the source and plot at P2
198 * increment pixel location from source
199 *
200 */
201
202 static void
203 copyLine(int x1, int y1, int x2, int y2, int nwidth, int format, unsigned char *dst, unsigned char **src)
204 {
205 unsigned char *s = *src;
206 int dx, dy;
207 int xi, yi;
208 int offset;
209 int dpr, dpru, p;
210
211 dx = abs(x2 - x1);
212 dy = abs(y2 - y1);
213
214 if (x1 > x2)
215 xi = -1;
216 else
217 xi = 1;
218 if (y1 > y2)
219 yi = -1;
220 else
221 yi = 1;
222
223 if (dx >= dy) {
224
225 dpr = dy << 1;
226 dpru = dpr - (dx << 1);
227 p = dpr - dx;
228
229 while (dx-- >= 0) {
230 /* fetch and draw the pixel */
231 offset = (x1 + y1 * nwidth) << 2;
232 dst[offset++] = *s++;
233 dst[offset++] = *s++;
234 dst[offset++] = *s++;
235 if (format == RRGBAFormat)
236 dst[offset++] = *s++;
237 else
238 dst[offset++] = 255;
239
240 /* calc next step */
241 if (p > 0) {
242 x1 += xi;
243 y1 += yi;
244 p += dpru;
245 } else {
246 x1 += xi;
247 p += dpr;
248 }
249 }
250 } else {
251
252 dpr = dx << 1;
253 dpru = dpr - (dy << 1);
254 p = dpr - dy;
255
256 while (dy-- >= 0) {
257 /* fetch and draw the pixel */
258 offset = (x1 + y1 * nwidth) << 2;
259 dst[offset++] = *s++;
260 dst[offset++] = *s++;
261 dst[offset++] = *s++;
262 if (format == RRGBAFormat)
263 dst[offset++] = *s++;
264 else
265 dst[offset++] = 255;
266
267 /* calc next step */
268 if (p > 0) {
269 x1 += xi;
270 y1 += yi;
271 p += dpru;
272 } else {
273 y1 += yi;
274 p += dpr;
275 }
276 }
277 }
278
279 *src = s;
280 }
281
282 static RImage *rotateImage(RImage * image, float angle)
283 {
284 RImage *img;
285 int nwidth, nheight;
286 int x1, y1;
287 int x2, y2;
288 int dx, dy;
289 int xi, yi;
290 int xx, yy;
291 unsigned char *src, *dst;
292 int dpr, dpru, p;
293
294 /* only 180o for now */
295 if (angle > 180.0)
296 angle -= 180.0;
297
298 angle = (angle * PI) / 180.0;
299
300 nwidth = ceil(abs(cos(angle) * image->width))
301 + ceil(abs(cos(PI / 2 - angle) * image->width));
302
303 nheight = ceil(abs(sin(angle) * image->height))
304 + ceil(abs(cos(PI / 2 - angle) * image->height));
305
306 img = RCreateImage(nwidth, nheight, True);
307 if (!img)
308 return NULL;
309
310 src = image->data;
311 dst = img->data;
312
313 x1 = floor(abs(cos(PI / 2 - angle) * image->width));
314 y1 = 0;
315
316 x2 = 0;
317 y2 = floor(abs(sin(PI / 2 - angle) * image->width));
318
319 xx = floor(abs(cos(angle) * image->height)) - 1;
320 yy = nheight - 1;
321
322 printf("%ix%i, %i %i %i %i %i\n", nwidth, nheight, x1, y1, x2, y2, (int)((angle * 180.0) / PI));
323
324 dx = abs(x2 - x1);
325 dy = abs(y2 - y1);
326
327 if (x1 > x2)
328 xi = -1;
329 else
330 xi = 1;
331 if (y1 > y2)
332 yi = -1;
333 else
334 yi = 1;
335
336 if (dx >= dy) {
337 dpr = dy << 1;
338 dpru = dpr - (dx << 1);
339 p = dpr - dx;
340
341 while (dx-- >= 0) {
342
343 copyLine(x1, y1, xx, yy, nwidth, image->format, dst, &src);
344
345 /* calc next step */
346
347 if (p > 0) {
348 x1 += xi;
349 y1 += yi;
350 xx += xi;
351 yy += yi;
352 p += dpru;
353 } else {
354 x1 += xi;
355 xx += xi;
356 p += dpr;
357 }
358 }
359 } else {
360 puts("NOT IMPLEMTENED");
361 return img;
362 dpr = dx << 1;
363 dpru = dpr - (dy << 1);
364 p = dpr - dy;
365
366 while (dy-- >= 0) {
367 xx = abs(x1 * sin(angle * PI / 180.0));
368 yy = abs(y1 * cos(angle * PI / 180.0));
369
370 copyLine(x1, y1, xx, yy, nwidth, image->format, dst, &src);
371
372 /* calc next step */
373 if (p > 0) {
374 x1 += xi;
375 y1 += yi;
376 p += dpru;
377 } else {
378 y1 += yi;
379 p += dpr;
380 }
381 }
382 }
383
384 return img;
385 }