wmaker: Added 'const' attribute to remaining functions
[wmaker-crm.git] / wrlib / rotate.c
blobd296815a3f2981c289cd750fcf6340a9c9629b81
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 = ((int)angle % 360) + (angle - (int)angle);
57 if (angle < min_usable_angle) {
58 /* Rotate by 0 degree */
59 return RCloneImage(image);
61 } else if ((angle > 90.0 - min_usable_angle) &&
62 (angle < 90.0 + min_usable_angle)) {
63 nwidth = image->height;
64 nheight = image->width;
66 img = RCreateImage(nwidth, nheight, True);
67 if (!img) {
68 return NULL;
71 if (bpp == 3) {
72 unsigned char *optr, *nptr;
73 unsigned offs;
75 offs = nwidth * 4;
77 optr = image->data;
78 nptr = img->data;
80 for (x = 0; x < nwidth; x++) {
81 nptr = img->data + x * 4;
82 for (y = nheight; y; y--) {
83 nptr[0] = *optr++;
84 nptr[1] = *optr++;
85 nptr[2] = *optr++;
86 nptr[3] = 255;
88 nptr += offs;
91 } else {
92 unsigned *optr, *nptr;
93 unsigned *p;
95 optr = (unsigned *)image->data;
96 p = (unsigned *)img->data;
97 for (x = 0; x < nwidth; x++) {
98 nptr = p++;
99 for (y = nheight; y; y--) {
100 *nptr = *optr++;
101 nptr += nwidth;
105 } else if ((angle > 180.0 - min_usable_angle) &&
106 (angle < 180.0 + min_usable_angle)) {
108 nwidth = image->width;
109 nheight = image->height;
110 img = RCreateImage(nwidth, nheight, True);
111 if (!img) {
112 return NULL;
115 if (bpp == 3) {
116 unsigned char *optr, *nptr;
118 optr = image->data;
119 nptr = img->data + nwidth * nheight * 4 - 4;
121 for (y = 0; y < nheight; y++) {
122 for (x = 0; x < nwidth; x++) {
123 nptr[0] = optr[0];
124 nptr[1] = optr[1];
125 nptr[2] = optr[2];
126 nptr[3] = 255;
128 optr += 3;
129 nptr -= 4;
132 } else {
133 unsigned *optr, *nptr;
135 optr = (unsigned *)image->data;
136 nptr = (unsigned *)img->data + nwidth * nheight - 1;
138 for (y = nheight * nwidth - 1; y >= 0; y--) {
139 *nptr = *optr;
140 optr++;
141 nptr--;
144 } else if ((angle > 270.0 - min_usable_angle) &&
145 (angle < 270.0 + min_usable_angle)) {
146 nwidth = image->height;
147 nheight = image->width;
149 img = RCreateImage(nwidth, nheight, True);
150 if (!img) {
151 return NULL;
154 if (bpp == 3) {
155 unsigned char *optr, *nptr;
156 unsigned offs;
158 offs = nwidth * 4;
160 optr = image->data;
161 nptr = img->data;
163 for (x = 0; x < nwidth; x++) {
164 nptr = img->data + x * 4;
165 for (y = nheight; y; y--) {
166 nptr[0] = *optr++;
167 nptr[1] = *optr++;
168 nptr[2] = *optr++;
169 nptr[3] = 255;
171 nptr += offs;
174 } else {
175 unsigned *optr, *nptr;
176 unsigned *p;
178 optr = (unsigned *)image->data;
179 p = (unsigned *)img->data + nwidth * nheight;
180 for (x = 0; x < nwidth; x++) {
181 nptr = p--;
182 for (y = nheight; y; y--) {
183 *nptr = *optr++;
184 nptr -= nwidth;
188 } else {
189 img = rotateImage(image, angle);
192 return img;
196 * Image rotation through Bresenham's line algorithm:
198 * If a square must be rotate by angle a, like in:
199 * _______
200 * | B |
201 * | /4\ |
202 * | /3 8\|
203 * | /2 7 /|
204 * |A1 6 / | A_______B
205 * | \5 / a| <--- |1 2 3 4|
206 * |__C/_)_| |5 6 7 8|
207 * C-------
209 * for each point P1 in the line from C to A
210 * for each point P2 in the perpendicular line starting at P1
211 * get pixel from the source and plot at P2
212 * increment pixel location from source
216 static void
217 copyLine(int x1, int y1, int x2, int y2, int nwidth, int format, unsigned char *dst, unsigned char **src)
219 unsigned char *s = *src;
220 int dx, dy;
221 int xi, yi;
222 int offset;
223 int dpr, dpru, p;
225 dx = abs(x2 - x1);
226 dy = abs(y2 - y1);
228 if (x1 > x2)
229 xi = -1;
230 else
231 xi = 1;
232 if (y1 > y2)
233 yi = -1;
234 else
235 yi = 1;
237 if (dx >= dy) {
239 dpr = dy << 1;
240 dpru = dpr - (dx << 1);
241 p = dpr - dx;
243 while (dx-- >= 0) {
244 /* fetch and draw the pixel */
245 offset = (x1 + y1 * nwidth) << 2;
246 dst[offset++] = *s++;
247 dst[offset++] = *s++;
248 dst[offset++] = *s++;
249 if (format == RRGBAFormat)
250 dst[offset++] = *s++;
251 else
252 dst[offset++] = 255;
254 /* calc next step */
255 if (p > 0) {
256 x1 += xi;
257 y1 += yi;
258 p += dpru;
259 } else {
260 x1 += xi;
261 p += dpr;
264 } else {
266 dpr = dx << 1;
267 dpru = dpr - (dy << 1);
268 p = dpr - dy;
270 while (dy-- >= 0) {
271 /* fetch and draw the pixel */
272 offset = (x1 + y1 * nwidth) << 2;
273 dst[offset++] = *s++;
274 dst[offset++] = *s++;
275 dst[offset++] = *s++;
276 if (format == RRGBAFormat)
277 dst[offset++] = *s++;
278 else
279 dst[offset++] = 255;
281 /* calc next step */
282 if (p > 0) {
283 x1 += xi;
284 y1 += yi;
285 p += dpru;
286 } else {
287 y1 += yi;
288 p += dpr;
293 *src = s;
296 static RImage *rotateImage(RImage * image, float angle)
298 RImage *img;
299 int nwidth, nheight;
300 int x1, y1;
301 int x2, y2;
302 int dx, dy;
303 int xi, yi;
304 int xx, yy;
305 unsigned char *src, *dst;
306 int dpr, dpru, p;
308 /* only 180o for now */
309 if (angle > 180.0)
310 angle -= 180.0;
312 angle = (angle * PI) / 180.0;
314 nwidth = ceil(abs(cos(angle) * image->width))
315 + ceil(abs(cos(PI / 2 - angle) * image->width));
317 nheight = ceil(abs(sin(angle) * image->height))
318 + ceil(abs(cos(PI / 2 - angle) * image->height));
320 img = RCreateImage(nwidth, nheight, True);
321 if (!img)
322 return NULL;
324 src = image->data;
325 dst = img->data;
327 x1 = floor(abs(cos(PI / 2 - angle) * image->width));
328 y1 = 0;
330 x2 = 0;
331 y2 = floor(abs(sin(PI / 2 - angle) * image->width));
333 xx = floor(abs(cos(angle) * image->height)) - 1;
334 yy = nheight - 1;
336 printf("%ix%i, %i %i %i %i %i\n", nwidth, nheight, x1, y1, x2, y2, (int)((angle * 180.0) / PI));
338 dx = abs(x2 - x1);
339 dy = abs(y2 - y1);
341 if (x1 > x2)
342 xi = -1;
343 else
344 xi = 1;
345 if (y1 > y2)
346 yi = -1;
347 else
348 yi = 1;
350 if (dx >= dy) {
351 dpr = dy << 1;
352 dpru = dpr - (dx << 1);
353 p = dpr - dx;
355 while (dx-- >= 0) {
357 copyLine(x1, y1, xx, yy, nwidth, image->format, dst, &src);
359 /* calc next step */
361 if (p > 0) {
362 x1 += xi;
363 y1 += yi;
364 xx += xi;
365 yy += yi;
366 p += dpru;
367 } else {
368 x1 += xi;
369 xx += xi;
370 p += dpr;
373 } else {
374 puts("NOT IMPLEMTENED");
375 return img;
376 dpr = dx << 1;
377 dpru = dpr - (dy << 1);
378 p = dpr - dy;
380 while (dy-- >= 0) {
381 xx = abs(x1 * sin(angle * PI / 180.0));
382 yy = abs(y1 * cos(angle * PI / 180.0));
384 copyLine(x1, y1, xx, yy, nwidth, image->format, dst, &src);
386 /* calc next step */
387 if (p > 0) {
388 x1 += xi;
389 y1 += yi;
390 p += dpru;
391 } else {
392 y1 += yi;
393 p += dpr;
398 return img;