gfx: Remove PartialElipse
[gfxprim.git] / libs / core / GP_Context.c
blob53c289e1c007d65eba6b7e1a33a048e29b9aaf0d
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2011 Jiri "BlueBear" Dluhos *
20 * <jiri.bluebear.dluhos@gmail.com> *
21 * *
22 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
23 * *
24 *****************************************************************************/
26 #include <errno.h>
27 #include <string.h>
29 #include "GP_Debug.h"
30 #include "GP_Transform.h"
31 #include "GP_Pixel.h"
32 #include "GP_GetPutPixel.h"
33 #include "GP_Gamma.h"
34 #include "GP_Pixmap.h"
35 #include "GP_Blit.h"
37 static uint32_t get_bpr(uint32_t bpp, uint32_t w)
39 uint64_t bits_per_row = (uint64_t)bpp * w;
40 uint8_t padd = !!(bits_per_row % 8);
42 if (bits_per_row / 8 + padd > UINT32_MAX) {
43 GP_WARN("Pixmap too wide %u (overflow detected)", w);
44 return 0;
47 return bits_per_row / 8 + padd;
50 GP_Pixmap *GP_PixmapAlloc(GP_Size w, GP_Size h, GP_PixelType type)
52 GP_Pixmap *pixmap;
53 uint32_t bpp;
54 size_t bpr;
55 void *pixels;
57 if (!GP_VALID_PIXELTYPE(type)) {
58 GP_WARN("Invalid pixel type %u", type);
59 errno = EINVAL;
60 return NULL;
63 if (w <= 0 || h <= 0) {
64 GP_WARN("Trying to allocate pixmap with zero width and/or height");
65 errno = EINVAL;
66 return NULL;
69 GP_DEBUG(1, "Allocating pixmap %u x %u - %s",
70 w, h, GP_PixelTypeName(type));
72 bpp = GP_PixelSize(type);
74 if (!(bpr = get_bpr(bpp, w)))
75 return NULL;
77 size_t size = bpr * h;
79 if (size / h != bpr) {
80 GP_WARN("Pixmap too big %u x %u (owerflow detected)", w, h);
81 return NULL;
84 pixels = malloc(size);
85 pixmap = malloc(sizeof(GP_Pixmap));
87 if (pixels == NULL || pixmap == NULL) {
88 free(pixels);
89 free(pixmap);
90 GP_WARN("Malloc failed :(");
91 errno = ENOMEM;
92 return NULL;
95 pixmap->pixels = pixels;
96 pixmap->bpp = bpp;
97 pixmap->bytes_per_row = bpr;
98 pixmap->offset = 0;
100 pixmap->w = w;
101 pixmap->h = h;
103 pixmap->gamma = NULL;
105 pixmap->pixel_type = type;
106 #warning Hmm, bit endianity... Why is not this settled by different pixel types?
107 pixmap->bit_endian = GP_PixelTypes[type].bit_endian;
109 /* rotation and mirroring */
110 GP_PixmapSetRotation(pixmap, 0, 0, 0);
112 pixmap->free_pixels = 1;
114 return pixmap;
117 void GP_PixmapFree(GP_Pixmap *pixmap)
119 GP_DEBUG(1, "Freeing pixmap (%p)", pixmap);
121 if (pixmap == NULL)
122 return;
124 if (pixmap->free_pixels)
125 free(pixmap->pixels);
127 if (pixmap->gamma)
128 GP_GammaRelease(pixmap->gamma);
130 free(pixmap);
133 GP_Pixmap *GP_PixmapInit(GP_Pixmap *pixmap, GP_Size w, GP_Size h,
134 GP_PixelType type, void *pixels)
136 uint32_t bpp = GP_PixelSize(type);
137 uint32_t bpr = get_bpr(bpp, w);
139 pixmap->pixels = pixels;
140 pixmap->bpp = bpp;
141 pixmap->bytes_per_row = bpr;
142 pixmap->offset = 0;
144 pixmap->w = w;
145 pixmap->h = h;
147 pixmap->pixel_type = type;
148 pixmap->bit_endian = 0;
150 pixmap->gamma = NULL;
152 /* rotation and mirroring */
153 GP_PixmapSetRotation(pixmap, 0, 0, 0);
155 pixmap->free_pixels = 0;
157 return pixmap;
160 int GP_PixmapResize(GP_Pixmap *pixmap, GP_Size w, GP_Size h)
162 uint32_t bpr = get_bpr(pixmap->bpp, w);
163 void *pixels;
165 pixels = realloc(pixmap->pixels, bpr * h);
167 if (pixels == NULL)
168 return 1;
170 pixmap->w = w;
171 pixmap->h = h;
172 pixmap->bytes_per_row = bpr;
173 pixmap->pixels = pixels;
175 return 0;
178 GP_Pixmap *GP_PixmapCopy(const GP_Pixmap *src, int flags)
180 GP_Pixmap *new;
181 uint8_t *pixels;
183 if (src == NULL)
184 return NULL;
186 new = malloc(sizeof(GP_Pixmap));
187 pixels = malloc(src->bytes_per_row * src->h);
189 if (pixels == NULL || new == NULL) {
190 free(pixels);
191 free(new);
192 GP_WARN("Malloc failed :(");
193 errno = ENOMEM;
194 return NULL;
197 new->pixels = pixels;
199 if (flags & GP_COPY_WITH_PIXELS)
200 memcpy(pixels, src->pixels, src->bytes_per_row * src->h);
202 new->bpp = src->bpp;
203 new->bytes_per_row = src->bytes_per_row;
204 new->offset = 0;
206 new->w = src->w;
207 new->h = src->h;
209 new->pixel_type = src->pixel_type;
210 new->bit_endian = src->bit_endian;
212 if (flags & GP_COPY_WITH_ROTATION)
213 GP_PixmapCopyRotation(src, new);
214 else
215 GP_PixmapSetRotation(new, 0, 0, 0);
217 //TODO: Copy the gamma too
218 new->gamma = NULL;
220 new->free_pixels = 1;
222 return new;
226 GP_Pixmap *GP_PixmapConvertAlloc(const GP_Pixmap *src,
227 GP_PixelType dst_pixel_type)
229 int w = GP_PixmapW(src);
230 int h = GP_PixmapH(src);
232 GP_Pixmap *ret = GP_PixmapAlloc(w, h, dst_pixel_type);
234 if (ret == NULL)
235 return NULL;
238 * Fill the buffer with zeroes, otherwise it will
239 * contain random data which will generate mess
240 * when converting image with alpha channel.
242 memset(ret->pixels, 0, ret->bytes_per_row * ret->h);
244 GP_Blit(src, 0, 0, w, h, ret, 0, 0);
246 return ret;
249 GP_Pixmap *GP_PixmapConvert(const GP_Pixmap *src, GP_Pixmap *dst)
251 //TODO: Asserts
252 int w = GP_PixmapW(src);
253 int h = GP_PixmapH(src);
256 * Fill the buffer with zeroes, otherwise it will
257 * contain random data which will generate mess
258 * when converting image with alpha channel.
260 memset(dst->pixels, 0, dst->bytes_per_row * dst->h);
262 GP_Blit(src, 0, 0, w, h, dst, 0, 0);
264 return dst;
267 GP_Pixmap *GP_SubPixmapAlloc(const GP_Pixmap *pixmap,
268 GP_Coord x, GP_Coord y, GP_Size w, GP_Size h)
270 GP_Pixmap *res = malloc(sizeof(GP_Pixmap));
272 if (res == NULL) {
273 GP_WARN("Malloc failed :(");
274 errno = ENOMEM;
275 return NULL;
278 return GP_SubPixmap(pixmap, res, x, y, w, h);
281 GP_Pixmap *GP_SubPixmap(const GP_Pixmap *pixmap, GP_Pixmap *subpixmap,
282 GP_Coord x, GP_Coord y, GP_Size w, GP_Size h)
284 GP_CHECK(pixmap, "NULL pixmap");
286 GP_TRANSFORM_RECT(pixmap, x, y, w, h);
288 GP_CHECK(pixmap->w >= x + w, "Subpixmap w out of original pixmap.");
289 GP_CHECK(pixmap->h >= y + h, "Subpixmap h out of original pixmap.");
291 subpixmap->bpp = pixmap->bpp;
292 subpixmap->bytes_per_row = pixmap->bytes_per_row;
293 subpixmap->offset = (pixmap->offset +
294 GP_PixelAddrOffset(x, pixmap->pixel_type)) % 8;
296 subpixmap->w = w;
297 subpixmap->h = h;
299 subpixmap->pixel_type = pixmap->pixel_type;
300 subpixmap->bit_endian = pixmap->bit_endian;
302 /* gamma */
303 subpixmap->gamma = pixmap->gamma;
305 /* rotation and mirroring */
306 GP_PixmapCopyRotation(pixmap, subpixmap);
308 subpixmap->pixels = GP_PIXEL_ADDR(pixmap, x, y);
310 subpixmap->free_pixels = 0;
312 return subpixmap;
315 void GP_PixmapPrintInfo(const GP_Pixmap *self)
317 printf("Pixmap info\n");
318 printf("------------\n");
319 printf("Size\t%ux%u\n", self->w, self->h);
320 printf("BPP\t%u\n", self->bpp);
321 printf("BPR\t%u\n", self->bytes_per_row);
322 printf("Pixel\t%s (%u)\n", GP_PixelTypeName(self->pixel_type),
323 self->pixel_type);
324 printf("Offset\t%u (only unaligned pixel types)\n", self->offset);
325 printf("Flags\taxes_swap=%u x_swap=%u y_swap=%u free_pixels=%u\n",
326 self->axes_swap, self->x_swap, self->y_swap, self->free_pixels);
328 if (self->gamma)
329 GP_GammaPrint(self->gamma);
333 * The pixmap rotations consists of two cyclic permutation groups that are
334 * mirrored.
336 * The flags change as follows:
338 * One group:
340 * x_swap y_swap axes_swap
341 * 0 0 0
342 * 1 0 1
343 * 1 1 0
344 * 0 1 1
346 * And mirrored group:
348 * x_swap y_swap axes_swap
349 * 0 0 1
350 * 1 0 0
351 * 1 1 1
352 * 0 1 0
355 void GP_PixmapRotateCW(GP_Pixmap *pixmap)
357 pixmap->axes_swap = !pixmap->axes_swap;
359 if (!pixmap->x_swap && !pixmap->y_swap) {
360 pixmap->x_swap = 1;
361 return;
364 if (pixmap->x_swap && !pixmap->y_swap) {
365 pixmap->y_swap = 1;
366 return;
369 if (pixmap->x_swap && pixmap->y_swap) {
370 pixmap->x_swap = 0;
371 return;
374 pixmap->y_swap = 0;
377 void GP_PixmapRotateCCW(GP_Pixmap *pixmap)
379 pixmap->axes_swap = !pixmap->axes_swap;
381 if (!pixmap->x_swap && !pixmap->y_swap) {
382 pixmap->y_swap = 1;
383 return;
386 if (pixmap->x_swap && !pixmap->y_swap) {
387 pixmap->x_swap = 0;
388 return;
391 if (pixmap->x_swap && pixmap->y_swap) {
392 pixmap->y_swap = 0;
393 return;
396 pixmap->x_swap = 1;
399 int GP_PixmapEqual(const GP_Pixmap *pixmap1, const GP_Pixmap *pixmap2)
401 if (pixmap1->pixel_type != pixmap2->pixel_type)
402 return 0;
404 if (GP_PixmapW(pixmap1) != GP_PixmapW(pixmap2))
405 return 0;
407 if (GP_PixmapH(pixmap1) != GP_PixmapH(pixmap2))
408 return 0;
410 GP_Coord x, y, w = GP_PixmapW(pixmap1), h = GP_PixmapH(pixmap1);
412 for (x = 0; x < w; x++)
413 for (y = 0; y < h; y++)
414 if (GP_GetPixel(pixmap1, x, y) != GP_GetPixel(pixmap2, x, y))
415 return 0;
417 return 1;