libs: core: debug: API for custom message handler.
[gfxprim.git] / libs / core / GP_Context.c
blobff6588482cc09a90e8a04da9b05c059ac53386e9
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_Context.h"
35 #include "GP_Blit.h"
37 static uint32_t get_bpr(uint32_t bpp, uint32_t w)
39 return (bpp * w) / 8 + !!((bpp * w) % 8);
42 GP_Context *GP_ContextAlloc(GP_Size w, GP_Size h, GP_PixelType type)
44 GP_CHECK_VALID_PIXELTYPE(type);
45 GP_Context *context;
46 uint32_t bpp = GP_PixelSize(type);
47 uint32_t bpr = get_bpr(bpp, w);
48 void *pixels;
50 GP_DEBUG(1, "Allocating context %u x %u - %s",
51 w, h, GP_PixelTypeName(type));
53 pixels = malloc(bpr * h);
54 context = malloc(sizeof(GP_Context));
56 if (pixels == NULL || context == NULL) {
57 free(pixels);
58 free(context);
59 GP_WARN("Malloc failed :(");
60 errno = ENOMEM;
61 return NULL;
64 context->pixels = pixels;
65 context->bpp = bpp;
66 context->bytes_per_row = bpr;
67 context->offset = 0;
69 context->w = w;
70 context->h = h;
72 context->gamma = NULL;
74 context->pixel_type = type;
75 #warning Hmm, bit endianity... Why is not this settled by different pixel types?
76 context->bit_endian = GP_PixelTypes[type].bit_endian;
78 /* rotation and mirroring */
79 GP_ContextSetRotation(context, 0, 0, 0);
81 context->free_pixels = 1;
83 return context;
86 void GP_ContextFree(GP_Context *context)
88 GP_DEBUG(1, "Freeing context (%p)", context);
90 if (context == NULL)
91 return;
93 if (context->free_pixels)
94 free(context->pixels);
96 if (context->gamma)
97 GP_GammaRelease(context->gamma);
99 free(context);
102 GP_Context *GP_ContextInit(GP_Context *context, GP_Size w, GP_Size h,
103 GP_PixelType type, void *pixels)
105 uint32_t bpp = GP_PixelSize(type);
106 uint32_t bpr = get_bpr(bpp, w);
108 context->pixels = pixels;
109 context->bpp = bpp;
110 context->bytes_per_row = bpr;
111 context->offset = 0;
113 context->w = w;
114 context->h = h;
116 context->pixel_type = type;
117 context->bit_endian = 0;
119 context->gamma = NULL;
121 /* rotation and mirroring */
122 GP_ContextSetRotation(context, 0, 0, 0);
124 context->free_pixels = 0;
126 return context;
129 int GP_ContextResize(GP_Context *context, GP_Size w, GP_Size h)
131 uint32_t bpr = get_bpr(context->bpp, w);
132 void *pixels;
134 pixels = realloc(context->pixels, bpr * h);
136 if (pixels == NULL)
137 return 1;
139 context->w = w;
140 context->h = h;
141 context->bytes_per_row = bpr;
142 context->pixels = pixels;
144 return 0;
147 GP_Context *GP_ContextCopy(const GP_Context *src, int flags)
149 GP_Context *new;
150 uint8_t *pixels;
152 if (src == NULL)
153 return NULL;
155 new = malloc(sizeof(GP_Context));
156 pixels = malloc(src->bytes_per_row * src->h);
158 if (pixels == NULL || new == NULL) {
159 free(pixels);
160 free(new);
161 GP_WARN("Malloc failed :(");
162 errno = ENOMEM;
163 return NULL;
166 new->pixels = pixels;
168 if (flags & GP_COPY_WITH_PIXELS)
169 memcpy(pixels, src->pixels, src->bytes_per_row * src->h);
171 new->bpp = src->bpp;
172 new->bytes_per_row = src->bytes_per_row;
173 new->offset = 0;
175 new->w = src->w;
176 new->h = src->h;
178 new->pixel_type = src->pixel_type;
179 new->bit_endian = src->bit_endian;
181 if (flags & GP_COPY_WITH_ROTATION)
182 GP_ContextCopyRotation(src, new);
183 else
184 GP_ContextSetRotation(new, 0, 0, 0);
186 //TODO: Copy the gamma too
187 new->gamma = NULL;
189 new->free_pixels = 1;
191 return new;
195 GP_Context *GP_ContextConvertAlloc(const GP_Context *src,
196 GP_PixelType dst_pixel_type)
198 int w = GP_ContextW(src);
199 int h = GP_ContextH(src);
201 GP_Context *ret = GP_ContextAlloc(w, h, dst_pixel_type);
203 if (ret == NULL)
204 return NULL;
206 GP_Blit(src, 0, 0, w, h, ret, 0, 0);
208 return ret;
211 GP_Context *GP_ContextConvert(const GP_Context *src, GP_Context *dst)
213 //TODO: Asserts
214 int w = GP_ContextW(src);
215 int h = GP_ContextH(src);
217 GP_Blit(src, 0, 0, w, h, dst, 0, 0);
219 return dst;
222 GP_Context *GP_SubContextAlloc(const GP_Context *context,
223 GP_Coord x, GP_Coord y, GP_Size w, GP_Size h)
225 GP_Context *res = malloc(sizeof(GP_Context));
227 if (res == NULL) {
228 GP_WARN("Malloc failed :(");
229 errno = ENOMEM;
230 return NULL;
233 return GP_SubContext(context, res, x, y, w, h);
236 GP_Context *GP_SubContext(const GP_Context *context, GP_Context *subcontext,
237 GP_Coord x, GP_Coord y, GP_Size w, GP_Size h)
239 GP_CHECK(context, "NULL context");
241 GP_TRANSFORM_RECT(context, x, y, w, h);
243 GP_CHECK(context->w >= x + w, "Subcontext w out of original context.");
244 GP_CHECK(context->h >= y + h, "Subcontext h out of original context.");
246 subcontext->bpp = context->bpp;
247 subcontext->bytes_per_row = context->bytes_per_row;
248 subcontext->offset = (context->offset +
249 GP_PixelAddrOffset(x, context->pixel_type)) % 8;
251 subcontext->w = w;
252 subcontext->h = h;
254 subcontext->pixel_type = context->pixel_type;
255 subcontext->bit_endian = context->bit_endian;
257 /* gamma */
258 subcontext->gamma = context->gamma;
260 /* rotation and mirroring */
261 GP_ContextCopyRotation(context, subcontext);
263 subcontext->pixels = GP_PIXEL_ADDR(context, x, y);
265 subcontext->free_pixels = 0;
267 return subcontext;
270 void GP_ContextPrintInfo(const GP_Context *self)
272 printf("Context info\n");
273 printf("------------\n");
274 printf("Size\t%ux%u\n", self->w, self->h);
275 printf("BPP\t%u\n", self->bpp);
276 printf("BPR\t%u\n", self->bytes_per_row);
277 printf("Pixel\t%s (%u)\n", GP_PixelTypeName(self->pixel_type),
278 self->pixel_type);
279 printf("Offset\t%u (only unaligned pixel types)\n", self->offset);
280 printf("Flags\taxes_swap=%u x_swap=%u y_swap=%u free_pixels=%u\n",
281 self->axes_swap, self->x_swap, self->y_swap, self->free_pixels);
283 if (self->gamma)
284 GP_GammaPrint(self->gamma);
288 * The context rotations consists of two cyclic permutation groups that are
289 * mirrored.
291 * The flags change as follows:
293 * One group:
295 * x_swap y_swap axes_swap
296 * 0 0 0
297 * 1 0 1
298 * 1 1 0
299 * 0 1 1
301 * And mirrored group:
303 * x_swap y_swap axes_swap
304 * 0 0 1
305 * 1 0 0
306 * 1 1 1
307 * 0 1 0
310 void GP_ContextRotateCW(GP_Context *context)
312 context->axes_swap = !context->axes_swap;
314 if (!context->x_swap && !context->y_swap) {
315 context->x_swap = 1;
316 return;
319 if (context->x_swap && !context->y_swap) {
320 context->y_swap = 1;
321 return;
324 if (context->x_swap && context->y_swap) {
325 context->x_swap = 0;
326 return;
329 context->y_swap = 0;
332 void GP_ContextRotateCCW(GP_Context *context)
334 context->axes_swap = !context->axes_swap;
336 if (!context->x_swap && !context->y_swap) {
337 context->y_swap = 1;
338 return;
341 if (context->x_swap && !context->y_swap) {
342 context->x_swap = 0;
343 return;
346 if (context->x_swap && context->y_swap) {
347 context->y_swap = 0;
348 return;
351 context->x_swap = 1;
354 int GP_ContextEqual(const GP_Context *ctx1, const GP_Context *ctx2)
356 if (ctx1->pixel_type != ctx2->pixel_type)
357 return 0;
359 if (GP_ContextW(ctx1) != GP_ContextW(ctx2))
360 return 0;
362 if (GP_ContextH(ctx1) != GP_ContextH(ctx2))
363 return 0;
365 GP_Coord x, y, w = GP_ContextW(ctx1), h = GP_ContextH(ctx1);
367 for (x = 0; x < w; x++)
368 for (y = 0; y < h; y++)
369 if (GP_GetPixel(ctx1, x, y) != GP_GetPixel(ctx2, x, y))
370 return 0;
372 return 1;