core, filters: Add initial version of gamma correction.
[gfxprim.git] / libs / core / GP_Context.c
blob88a0298ee302dd8b86aee66ec73ed8ba41550c8d
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-2012 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_GammaCorrection.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 pixels = malloc(bpr * h);
51 context = malloc(sizeof(GP_Context));
53 if (pixels == NULL || context == NULL) {
54 free(pixels);
55 free(context);
56 GP_WARN("Malloc failed :(");
57 errno = ENOMEM;
58 return NULL;
61 context->pixels = pixels;
62 context->bpp = bpp;
63 context->bytes_per_row = bpr;
64 context->offset = 0;
66 context->w = w;
67 context->h = h;
69 context->gamma = NULL;
71 context->pixel_type = type;
72 #warning Hmm, bit endianity... Why is not this settled by different pixel types?
73 context->bit_endian = 0;
75 /* rotation and mirroring */
76 GP_ContextSetRotation(context, 0, 0, 0);
78 context->free_pixels = 1;
80 return context;
83 void GP_ContextFree(GP_Context *context)
85 GP_DEBUG(1, "Freeing context (%p)", context);
87 if (context == NULL)
88 return;
90 if (context->free_pixels)
91 free(context->pixels);
93 if (context->gamma)
94 GP_GammaRelease(context->gamma);
96 free(context);
99 GP_Context *GP_ContextInit(GP_Context *context, GP_Size w, GP_Size h,
100 GP_PixelType type, void *pixels)
102 uint32_t bpp = GP_PixelSize(type);
103 uint32_t bpr = get_bpr(bpp, w);
105 context->pixels = pixels;
106 context->bpp = bpp;
107 context->bytes_per_row = bpr;
108 context->offset = 0;
110 context->w = w;
111 context->h = h;
113 context->pixel_type = type;
114 context->bit_endian = 0;
116 context->gamma = NULL;
118 /* rotation and mirroring */
119 GP_ContextSetRotation(context, 0, 0, 0);
121 context->free_pixels = 0;
123 return context;
126 int GP_ContextResize(GP_Context *context, GP_Size w, GP_Size h)
128 uint32_t bpr = get_bpr(context->bpp, w);
129 void *pixels;
131 pixels = realloc(context->pixels, bpr * h);
133 if (pixels == NULL)
134 return 1;
136 context->w = w;
137 context->h = h;
138 context->bytes_per_row = bpr;
139 context->pixels = pixels;
141 return 0;
144 GP_Context *GP_ContextCopy(const GP_Context *src, int flags)
146 GP_Context *new;
147 uint8_t *pixels;
149 if (src == NULL)
150 return NULL;
152 new = malloc(sizeof(GP_Context));
153 pixels = malloc(src->bytes_per_row * src->h);
155 if (pixels == NULL || new == NULL) {
156 free(pixels);
157 free(new);
158 GP_WARN("Malloc failed :(");
159 errno = ENOMEM;
160 return NULL;
163 new->pixels = pixels;
165 if (flags & GP_COPY_WITH_PIXELS)
166 memcpy(pixels, src->pixels, src->bytes_per_row * src->h);
168 new->bpp = src->bpp;
169 new->bytes_per_row = src->bytes_per_row;
170 new->offset = 0;
172 new->w = src->w;
173 new->h = src->h;
175 new->pixel_type = src->pixel_type;
176 new->bit_endian = src->bit_endian;
178 if (flags & GP_COPY_WITH_ROTATION)
179 GP_ContextCopyRotation(src, new);
180 else
181 GP_ContextSetRotation(new, 0, 0, 0);
183 //TODO: Copy the gamma too
184 new->gamma = NULL;
186 new->free_pixels = 1;
188 return new;
192 GP_Context *GP_ContextConvertAlloc(const GP_Context *src,
193 GP_PixelType dst_pixel_type)
195 int w = GP_ContextW(src);
196 int h = GP_ContextH(src);
198 GP_Context *ret = GP_ContextAlloc(w, h, dst_pixel_type);
200 if (ret == NULL)
201 return NULL;
203 GP_Blit(src, 0, 0, w, h, ret, 0, 0);
205 return ret;
208 GP_Context *GP_ContextConvert(const GP_Context *src, GP_Context *dst)
210 //TODO: Asserts
211 int w = GP_ContextW(src);
212 int h = GP_ContextH(src);
214 GP_Blit(src, 0, 0, w, h, dst, 0, 0);
216 return dst;
219 GP_Context *GP_SubContextAlloc(const GP_Context *context,
220 GP_Coord x, GP_Coord y, GP_Size w, GP_Size h)
222 GP_Context *res = malloc(sizeof(GP_Context));
224 if (res == NULL) {
225 GP_WARN("Malloc failed :(");
226 errno = ENOMEM;
227 return NULL;
230 return GP_SubContext(context, res, x, y, w, h);
233 GP_Context *GP_SubContext(const GP_Context *context, GP_Context *subcontext,
234 GP_Coord x, GP_Coord y, GP_Size w, GP_Size h)
236 GP_CHECK(context, "NULL context");
238 GP_TRANSFORM_RECT(context, x, y, w, h);
240 GP_CHECK(context->w >= x + w, "Subcontext w out of original context.");
241 GP_CHECK(context->h >= y + h, "Subcontext h out of original context.");
243 subcontext->bpp = context->bpp;
244 subcontext->bytes_per_row = context->bytes_per_row;
245 subcontext->offset = (context->offset +
246 GP_PixelAddrOffset(x, context->pixel_type)) % 8;
248 subcontext->w = w;
249 subcontext->h = h;
251 subcontext->pixel_type = context->pixel_type;
252 subcontext->bit_endian = context->bit_endian;
254 /* gamma */
255 subcontext->gamma = context->gamma;
257 /* rotation and mirroring */
258 GP_ContextCopyRotation(context, subcontext);
260 subcontext->pixels = GP_PIXEL_ADDR(context, x, y);
262 subcontext->free_pixels = 0;
264 return subcontext;
267 void GP_ContextPrintInfo(const GP_Context *self)
269 printf("Context info\n");
270 printf("------------\n");
271 printf("Size\t%ux%u\n", self->w, self->h);
272 printf("BPP\t%u\n", self->bpp);
273 printf("BPR\t%u\n", self->bytes_per_row);
274 printf("Pixel\t%s (%u)\n", GP_PixelTypeName(self->pixel_type),
275 self->pixel_type);
276 printf("Offset\t%u (only unaligned pixel types)\n", self->offset);
277 printf("Flags\taxes_swap=%u x_swap=%u y_swap=%u free_pixels=%u\n",
278 self->axes_swap, self->x_swap, self->y_swap, self->free_pixels);
279 printf("Gamma table %p", self->gamma);
283 * The context rotations consists of two cyclic permutation groups that are
284 * mirrored.
286 * The flags change as follows:
288 * One group:
290 * x_swap y_swap axes_swap
291 * 0 0 0
292 * 1 0 1
293 * 1 1 0
294 * 0 1 1
296 * And mirrored group:
298 * x_swap y_swap axes_swap
299 * 0 0 1
300 * 1 0 0
301 * 1 1 1
302 * 0 1 0
305 void GP_ContextRotateCW(GP_Context *context)
307 context->axes_swap = !context->axes_swap;
309 if (!context->x_swap && !context->y_swap) {
310 context->x_swap = 1;
311 return;
314 if (context->x_swap && !context->y_swap) {
315 context->y_swap = 1;
316 return;
319 if (context->x_swap && context->y_swap) {
320 context->x_swap = 0;
321 return;
324 context->y_swap = 0;
327 void GP_ContextRotateCCW(GP_Context *context)
329 context->axes_swap = !context->axes_swap;
331 if (!context->x_swap && !context->y_swap) {
332 context->y_swap = 1;
333 return;
336 if (context->x_swap && !context->y_swap) {
337 context->x_swap = 0;
338 return;
341 if (context->x_swap && context->y_swap) {
342 context->y_swap = 0;
343 return;
346 context->x_swap = 1;