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 }