1 /* Public domain */
2
3 #ifndef _AGAR_GUI_SURFACE_H_
4 #define _AGAR_GUI_SURFACE_H_
5
6 #include <agar/gui/geometry.h>
7 #include <agar/gui/colors.h>
8
9 #include <agar/gui/begin.h>
10
11 /* Palette of AG_Color values */
12 typedef struct ag_palette {
13 AG_Color *colors; /* Color array */
14 Uint nColors; /* Color count */
15 } AG_Palette;
16
17 /* Pixel storage information */
18 typedef struct ag_pixel_format {
19 AG_Palette *palette; /* For indexed formats */
20 Uint8 BitsPerPixel; /* Depth (bits/pixel) */
21 Uint8 BytesPerPixel; /* Depth (bytes/pixel) */
22
23 Uint8 Rloss, Gloss, Bloss, Aloss; /* Component loss */
24 Uint8 Rshift, Gshift, Bshift, Ashift; /* Component shift */
25 Uint32 Rmask, Gmask, Bmask, Amask; /* Component masks */
26
27 Uint32 colorkey; /* Color key pixel */
28 Uint8 alpha; /* Per-surface alpha value */
29 } AG_PixelFormat;
30
31 enum ag_surface_type {
32 AG_SURFACE_PACKED, /* Packed-pixel format */
33 AG_SURFACE_INDEXED /* Indexed format */
34 };
35
36 /* General packed-pixel or indexed surface. */
37 typedef struct ag_surface {
38 enum ag_surface_type type; /* Type of surface */
39 AG_PixelFormat *format; /* Pixel format */
40 Uint flags;
41 #define AG_SRCCOLORKEY 0x01 /* Enable color key for blit as src */
42 #define AG_SRCALPHA 0x02 /* Enable alpha for blit as src */
43 #define AG_SURFACE_GLTEXTURE 0x04 /* Use directly as OpenGL texture */
44 #define AG_SAVED_SURFACE_FLAGS (AG_SRCCOLORKEY|AG_SRCALPHA|AG_SURFACE_GLTEXTURE)
45 Uint w, h; /* Size in pixels */
46 Uint pitch; /* Scanline size in bytes */
47 void *pixels; /* Raw pixel data */
48 AG_Rect clipRect; /* Clipping rect for blit as dst */
49 Uint padding; /* Scanline end padding in bytes */
50 } AG_Surface;
51
52 typedef enum ag_blend_func {
53 AG_ALPHA_ZERO,
54 AG_ALPHA_ONE,
55 AG_ALPHA_SRC,
56 AG_ALPHA_DST,
57 AG_ALPHA_ONE_MINUS_DST,
58 AG_ALPHA_ONE_MINUS_SRC,
59 AG_ALPHA_OVERLAY
60 } AG_BlendFn;
61
62 /* Clipping test for pixel at ax,ay in surface s (as dst) */
63 #define AG_CLIPPED_PIXEL(s, ax, ay) \
64 ((ax) < (s)->clipRect.x || \
65 (ax) >= (s)->clipRect.x+(s)->clipRect.w || \
66 (ay) < (s)->clipRect.y || \
67 (ay) >= (s)->clipRect.y+(s)->clipRect.h)
68
69 #define AG_ALPHA_TRANSPARENT 0 /* Transparent alpha value */
70 #define AG_ALPHA_OPAQUE 255 /* Opaque alpha value */
71
72 /* Flags for AG_SurfaceExportPNG() */
73 #define AG_EXPORT_PNG_ADAM7 0x01 /* Enable Adam7 interlacing */
74
75 /* Flags for AG_SurfaceExportJPEG() */
76 #define AG_EXPORT_JPEG_JDCT_ISLOW 0x01 /* Slow, accurate integer DCT */
77 #define AG_EXPORT_JPEG_JDCT_IFAST 0x02 /* Faster, less accurate integer DCT */
78 #define AG_EXPORT_JPEG_JDCT_FLOAT 0x04 /* Floating-point method */
79
80 __BEGIN_DECLS
81 extern const char *agBlendFuncNames[]; /* For enum ag_blend_func */
82 extern AG_PixelFormat *agSurfaceFmt; /* Recommended format for new surfaces */
83 extern AG_PixelFormat *agTextureFmt; /* Recommended format for textures */
84
85 AG_PixelFormat *AG_PixelFormatRGB(int, Uint32, Uint32, Uint32);
86 AG_PixelFormat *AG_PixelFormatRGBA(int, Uint32, Uint32, Uint32, Uint32);
87 AG_PixelFormat *AG_PixelFormatIndexed(int);
88 AG_PixelFormat *AG_PixelFormatDup(const AG_PixelFormat *);
89 void AG_PixelFormatFree(AG_PixelFormat *);
90 int AG_PixelFormatComparePalettes(const AG_Palette *, const AG_Palette *);
91
92 AG_Surface *AG_SurfaceNew(enum ag_surface_type, Uint, Uint,
93 const AG_PixelFormat *, Uint);
94 AG_Surface *AG_SurfaceEmpty(void);
95 AG_Surface *AG_SurfaceIndexed(Uint, Uint, int, Uint);
96 AG_Surface *AG_SurfaceRGB(Uint, Uint, int, Uint, Uint32, Uint32, Uint32);
97 AG_Surface *AG_SurfaceRGBA(Uint, Uint, int, Uint, Uint32, Uint32, Uint32,
98 Uint32);
99 AG_Surface *AG_SurfaceFromPixelsRGB(const void *, Uint, Uint, int, Uint32,
100 Uint32, Uint32);
101 AG_Surface *AG_SurfaceFromPixelsRGBA(const void *, Uint, Uint, int, Uint32,
102 Uint32, Uint32, Uint32);
103 AG_Surface *AG_SurfaceStdGL(Uint, Uint);
104
105 int AG_SurfaceSetPalette(AG_Surface *, AG_Color *, Uint, Uint);
106 AG_Surface *AG_SurfaceDup(const AG_Surface *);
107 AG_Surface *AG_SurfaceConvert(const AG_Surface *, const AG_PixelFormat *);
108 void AG_SurfaceCopy(AG_Surface *, const AG_Surface *);
109 void AG_SurfaceBlit(const AG_Surface *, const AG_Rect *,
110 AG_Surface *, int, int);
111 int AG_SurfaceResize(AG_Surface *, Uint, Uint);
112 void AG_SurfaceFree(AG_Surface *);
113
114 AG_Surface *AG_SurfaceFromFile(const char *);
115 int AG_SurfaceExportFile(const AG_Surface *, const char *);
116
117 AG_Surface *AG_SurfaceFromSDL(void *);
118 void *AG_SurfaceExportSDL(const AG_Surface *);
119
120 AG_Surface *AG_ReadSurfaceFromBMP(AG_DataSource *);
121 AG_Surface *AG_SurfaceFromBMP(const char *);
122 int AG_SurfaceExportBMP(const AG_Surface *, const char *);
123
124 AG_Surface *AG_ReadSurfaceFromPNG(AG_DataSource *);
125 AG_Surface *AG_SurfaceFromPNG(const char *);
126 int AG_SurfaceExportPNG(const AG_Surface *, const char *, Uint);
127
128 AG_Surface *AG_ReadSurfaceFromJPEG(AG_DataSource *);
129 AG_Surface *AG_SurfaceFromJPEG(const char *);
130 int AG_SurfaceExportJPEG(const AG_Surface *, const char *, Uint, Uint);
131
132 void AG_SurfaceBlendPixel(AG_Surface *, Uint8 *, AG_Color, AG_BlendFn);
133 void AG_RGB2HSV(Uint8, Uint8, Uint8, float *, float *, float *);
134 void AG_HSV2RGB(float, float, float, Uint8 *, Uint8 *, Uint8 *);
135 int AG_ScaleSurface(const AG_Surface *, Uint16, Uint16, AG_Surface **);
136 void AG_SetAlphaPixels(AG_Surface *, Uint8);
137 void AG_FillRect(AG_Surface *, const AG_Rect *, AG_Color);
138 Uint32 AG_MapPixelIndexedRGB(const AG_PixelFormat *, Uint8, Uint8, Uint8);
139 Uint32 AG_MapPixelIndexedRGBA(const AG_PixelFormat *, Uint8, Uint8, Uint8,
140 Uint8);
141
142 #define AG_SurfaceStdRGB(w,h) \
143 AG_SurfaceRGB((w),(h),agSurfaceFmt->BitsPerPixel,0, \
144 agSurfaceFmt->Rmask, \
145 agSurfaceFmt->Gmask, \
146 agSurfaceFmt->Bmask)
147 #define AG_SurfaceStdRGBA(w,h) \
148 AG_SurfaceRGBA((w),(h),agSurfaceFmt->BitsPerPixel,0, \
149 agSurfaceFmt->Rmask, \
150 agSurfaceFmt->Gmask, \
151 agSurfaceFmt->Bmask, \
152 agSurfaceFmt->Amask)
153
154 /*
155 * Generic pixel manipulation macros.
156 */
157 #define AG_GET_PIXEL(s, p) AG_GetPixel((s),(p))
158 #define AG_GET_PIXEL2(s, x, y) \
159 AG_GetPixel((s),(Uint8 *)(s)->pixels + (y)*(s)->pitch + \
160 (x)*(s)->format->BytesPerPixel)
161
162 #define AG_PUT_PIXEL(s, p, c) AG_SurfacePutPixel((s),(p),(c))
163 #define AG_PUT_PIXEL2(s, x, y, c) do { \
164 AG_SurfacePutPixel((s), \
165 (Uint8 *)(s)->pixels + (y)*(s)->pitch + \
166 (x)*(s)->format->BytesPerPixel, \
167 (c)); \
168 } while (0)
169 #define AG_PUT_PIXEL2_CLIPPED(s, x, y, c) do { \
170 if (!AG_CLIPPED_PIXEL((s), (x), (y))) { \
171 AG_SurfacePutPixel((s), \
172 (Uint8 *)(s)->pixels + (y)*(s)->pitch + \
173 (x)*(s)->format->BytesPerPixel, \
174 (c)); \
175 } \
176 } while (0)
177
178 #define AG_BLEND_RGBA(s, p, r, g, b, a, fn) \
179 AG_SurfaceBlendPixel((s),(p), \
180 AG_ColorRGBA((r),(g),(b),(a)),(fn))
181 #define AG_BLEND_RGBA2(s, x, y, r, g, b, a, fn) do { \
182 AG_SurfaceBlendPixel((s), \
183 (Uint8 *)(s)->pixels + (y)*(s)->pitch + \
184 (x)*(s)->format->BytesPerPixel, \
185 AG_ColorRGBA((r),(g),(b),(a)),(fn)); \
186 } while (0)
187 #define AG_BLEND_RGBA2_CLIPPED(s, x, y, r, g, b, a, fn) do { \
188 if (!AG_CLIPPED_PIXEL((s), (x), (y))) { \
189 AG_SurfaceBlendPixel((s), \
190 (Uint8 *)(s)->pixels + (y)*(s)->pitch + \
191 (x)*(s)->format->BytesPerPixel, \
192 AG_ColorRGBA((r),(g),(b),(a)),(fn)); \
193 } \
194 } while (0)
195
196 /* Compose a pixel value from RGB components. */
197 static __inline__ Uint32
AG_MapPixelRGB(const AG_PixelFormat * pf,Uint8 r,Uint8 g,Uint8 b)198 AG_MapPixelRGB(const AG_PixelFormat *pf, Uint8 r, Uint8 g, Uint8 b)
199 {
200 if (pf->palette != NULL) {
201 return AG_MapPixelIndexedRGB(pf, r, g, b);
202 }
203 return (r >> pf->Rloss) << pf->Rshift |
204 (g >> pf->Gloss) << pf->Gshift |
205 (b >> pf->Bloss) << pf->Bshift | pf->Amask;
206 }
207
208 /* Compose a pixel value from RGBA components. */
209 static __inline__ Uint32
AG_MapPixelRGBA(const AG_PixelFormat * pf,Uint8 r,Uint8 g,Uint8 b,Uint8 a)210 AG_MapPixelRGBA(const AG_PixelFormat *pf, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
211 {
212 if (pf->palette != NULL) {
213 return AG_MapPixelIndexedRGBA(pf, r, g, b, a);
214 }
215 return (r >> pf->Rloss) << pf->Rshift |
216 (g >> pf->Gloss) << pf->Gshift |
217 (b >> pf->Bloss) << pf->Bshift |
218 ((a >> pf->Aloss) << pf->Ashift & pf->Amask);
219 }
220
221 /* Compose a pixel value from an AG_Color (ignore any alpha). */
222 static __inline__ Uint32
AG_MapColorRGB(const AG_PixelFormat * pf,AG_Color C)223 AG_MapColorRGB(const AG_PixelFormat *pf, AG_Color C)
224 {
225 if (pf->palette != NULL) {
226 return AG_MapPixelIndexedRGB(pf, C.r, C.g, C.b);
227 }
228 return (C.r >> pf->Rloss) << pf->Rshift |
229 (C.g >> pf->Gloss) << pf->Gshift |
230 (C.b >> pf->Bloss) << pf->Bshift | pf->Amask;
231 }
232
233 /* Compose a pixel value from an AG_Color (honor any alpha). */
234 static __inline__ Uint32
AG_MapColorRGBA(const AG_PixelFormat * pf,AG_Color C)235 AG_MapColorRGBA(const AG_PixelFormat *pf, AG_Color C)
236 {
237 if (pf->palette != NULL) {
238 return AG_MapPixelIndexedRGBA(pf, C.r, C.g, C.b, C.a);
239 }
240 return (C.r >> pf->Rloss) << pf->Rshift |
241 (C.g >> pf->Gloss) << pf->Gshift |
242 (C.b >> pf->Bloss) << pf->Bshift |
243 ((C.a >> pf->Aloss) << pf->Ashift & pf->Amask);
244 }
245
246 #define AG_GET_PIXEL_COMPONENT(rv, mask, shift, loss) \
247 tmp = (pc & mask) >> shift; \
248 (rv) = (tmp << loss) + (tmp >> (8 - (loss << 1)));
249
250 /* Decompose a pixel value to RGB components. */
251 static __inline__ void
AG_GetPixelRGB(Uint32 pc,const AG_PixelFormat * pf,Uint8 * r,Uint8 * g,Uint8 * b)252 AG_GetPixelRGB(Uint32 pc, const AG_PixelFormat *pf, Uint8 *r, Uint8 *g,
253 Uint8 *b)
254 {
255 Uint tmp;
256
257 if (pf->palette != NULL) {
258 AG_Color *C = &pf->palette->colors[(Uint)pc % pf->palette->nColors];
259 *r = C->r;
260 *g = C->g;
261 *b = C->b;
262 } else {
263 AG_GET_PIXEL_COMPONENT(*r, pf->Rmask, pf->Rshift, pf->Rloss);
264 AG_GET_PIXEL_COMPONENT(*g, pf->Gmask, pf->Gshift, pf->Gloss);
265 AG_GET_PIXEL_COMPONENT(*b, pf->Bmask, pf->Bshift, pf->Bloss);
266 }
267 }
268
269 /* Decompose a pixel value to RGBA components. */
270 static __inline__ void
AG_GetPixelRGBA(Uint32 pc,const AG_PixelFormat * pf,Uint8 * r,Uint8 * g,Uint8 * b,Uint8 * a)271 AG_GetPixelRGBA(Uint32 pc, const AG_PixelFormat *pf, Uint8 *r, Uint8 *g,
272 Uint8 *b, Uint8 *a)
273 {
274 Uint tmp;
275
276 if (pf->palette != NULL) {
277 AG_Color *C = &pf->palette->colors[(Uint)pc % pf->palette->nColors];
278 *r = C->r;
279 *g = C->g;
280 *b = C->b;
281 *a = C->a;
282 } else {
283 AG_GET_PIXEL_COMPONENT(*r, pf->Rmask, pf->Rshift, pf->Rloss);
284 AG_GET_PIXEL_COMPONENT(*g, pf->Gmask, pf->Gshift, pf->Gloss);
285 AG_GET_PIXEL_COMPONENT(*b, pf->Bmask, pf->Bshift, pf->Bloss);
286 if (pf->Amask != 0) {
287 AG_GET_PIXEL_COMPONENT(*a, pf->Amask, pf->Ashift, pf->Aloss);
288 } else {
289 *a = AG_ALPHA_OPAQUE;
290 }
291 }
292 }
293
294 /* Decompose a pixel value to an AG_Color (ignore any alpha, set opaque). */
295 static __inline__ AG_Color
AG_GetColorRGB(Uint32 pc,const AG_PixelFormat * pf)296 AG_GetColorRGB(Uint32 pc, const AG_PixelFormat *pf)
297 {
298 AG_Color C;
299 Uint tmp;
300
301 if (pf->palette != NULL) {
302 return (pf->palette->colors[(Uint)pc % pf->palette->nColors]);
303 }
304 AG_GET_PIXEL_COMPONENT(C.r, pf->Rmask, pf->Rshift, pf->Rloss);
305 AG_GET_PIXEL_COMPONENT(C.g, pf->Gmask, pf->Gshift, pf->Gloss);
306 AG_GET_PIXEL_COMPONENT(C.b, pf->Bmask, pf->Bshift, pf->Bloss);
307 C.a = AG_ALPHA_OPAQUE;
308 return (C);
309 }
310
311 /* Decompose a pixel value to an AG_Color (honor any alpha). */
312 static __inline__ AG_Color
AG_GetColorRGBA(Uint32 pc,const AG_PixelFormat * pf)313 AG_GetColorRGBA(Uint32 pc, const AG_PixelFormat *pf)
314 {
315 AG_Color C;
316 Uint tmp;
317
318 if (pf->palette != NULL) {
319 return (pf->palette->colors[(Uint)pc % pf->palette->nColors]);
320 }
321 AG_GET_PIXEL_COMPONENT(C.r, pf->Rmask, pf->Rshift, pf->Rloss);
322 AG_GET_PIXEL_COMPONENT(C.g, pf->Gmask, pf->Gshift, pf->Gloss);
323 AG_GET_PIXEL_COMPONENT(C.b, pf->Bmask, pf->Bshift, pf->Bloss);
324 if (pf->Amask != 0) {
325 AG_GET_PIXEL_COMPONENT(C.a, pf->Amask, pf->Ashift, pf->Aloss);
326 } else {
327 C.a = AG_ALPHA_OPAQUE;
328 }
329 return (C);
330 }
331
332 #undef AG_GET_PIXEL_COMPONENT
333
334 /* Return pixel value at specified position in surface s. */
335 static __inline__ Uint32
AG_GetPixel(const AG_Surface * s,const Uint8 * pSrc)336 AG_GetPixel(const AG_Surface *s, const Uint8 *pSrc)
337 {
338 switch (s->format->BytesPerPixel) {
339 case 4:
340 return (*(Uint32 *)pSrc);
341 case 3:
342 #if AG_BYTEORDER == AG_BIG_ENDIAN
343 return ((pSrc[0] << 16) +
344 (pSrc[1] << 8) +
345 pSrc[2]);
346 #else
347 return (pSrc[0] +
348 (pSrc[1] << 8) +
349 (pSrc[2] << 16));
350 #endif
351 case 2:
352 return (*(Uint16 *)pSrc);
353 }
354 return (*pSrc);
355 }
356
357 /* Write pixel value at specified position in surface s. */
358 static __inline__ void
AG_SurfacePutPixel(AG_Surface * s,Uint8 * pDst,Uint32 cDst)359 AG_SurfacePutPixel(AG_Surface *s, Uint8 *pDst, Uint32 cDst)
360 {
361 switch (s->format->BytesPerPixel) {
362 case 4:
363 *(Uint32 *)pDst = cDst;
364 break;
365 case 3:
366 #if AG_BYTEORDER == AG_BIG_ENDIAN
367 pDst[0] = (cDst>>16) & 0xff;
368 pDst[1] = (cDst>>8) & 0xff;
369 pDst[2] = cDst & 0xff;
370 #else
371 pDst[2] = (cDst>>16) & 0xff;
372 pDst[1] = (cDst>>8) & 0xff;
373 pDst[0] = cDst & 0xff;
374 #endif
375 break;
376 case 2:
377 *(Uint16 *)pDst = (Uint16)cDst;
378 break;
379 default:
380 *pDst = (Uint8)cDst;
381 break;
382 }
383 }
384
385 /*
386 * Test whether two pixel formats are identical. If both formats are
387 * color-index, compare the palettes as well.
388 */
389 static __inline__ int
AG_PixelFormatCompare(const AG_PixelFormat * pf1,const AG_PixelFormat * pf2)390 AG_PixelFormatCompare(const AG_PixelFormat *pf1, const AG_PixelFormat *pf2)
391 {
392 if ((pf1->palette != NULL && pf2->palette == NULL) ||
393 (pf1->palette == NULL && pf2->palette != NULL)) {
394 return (1);
395 }
396 if (pf1->palette != NULL && pf2->palette != NULL &&
397 AG_PixelFormatComparePalettes(pf1->palette, pf2->palette) != 0) {
398 return (1);
399 }
400 return !(pf1->BitsPerPixel == pf2->BitsPerPixel &&
401 pf1->Rmask == pf2->Rmask &&
402 pf1->Gmask == pf2->Gmask &&
403 pf1->Bmask == pf2->Bmask &&
404 pf1->Amask == pf2->Amask &&
405 pf1->colorkey == pf2->colorkey);
406 }
407
408 /* Set the source alpha flag and per-surface alpha. */
409 static __inline__ void
AG_SurfaceSetAlpha(AG_Surface * s,Uint flags,Uint8 alpha)410 AG_SurfaceSetAlpha(AG_Surface *s, Uint flags, Uint8 alpha)
411 {
412 if (flags & AG_SRCALPHA) {
413 s->flags |= AG_SRCALPHA;
414 } else {
415 s->flags &= ~(AG_SRCALPHA);
416 }
417 s->format->alpha = alpha;
418 }
419
420 /* Set the source colorkey flag and per-surface colorkey. */
421 static __inline__ void
AG_SurfaceSetColorKey(AG_Surface * s,Uint flags,Uint32 colorkey)422 AG_SurfaceSetColorKey(AG_Surface *s, Uint flags, Uint32 colorkey)
423 {
424 if (flags & AG_SRCCOLORKEY) {
425 s->flags |= AG_SRCCOLORKEY;
426 } else {
427 s->flags &= ~(AG_SRCCOLORKEY);
428 }
429 s->format->colorkey = colorkey;
430 }
431
432 /* Retrieve the surface's clipping rectangle. */
433 static __inline__ void
AG_GetClipRect(const AG_Surface * su,AG_Rect * r)434 AG_GetClipRect(const AG_Surface *su, AG_Rect *r)
435 {
436 *r = su->clipRect;
437 }
438
439 /* Set the surface's clipping rectangle. */
440 static __inline__ void
AG_SetClipRect(AG_Surface * su,const AG_Rect * r)441 AG_SetClipRect(AG_Surface *su, const AG_Rect *r)
442 {
443 su->clipRect = *r;
444 }
445
446 #ifdef AG_LEGACY
447 void AG_SurfaceLock(AG_Surface *) DEPRECATED_ATTRIBUTE;
448 void AG_SurfaceUnlock(AG_Surface *) DEPRECATED_ATTRIBUTE;
449 Uint32 AG_MapRGB(const AG_PixelFormat *, Uint8, Uint8, Uint8) DEPRECATED_ATTRIBUTE;
450 Uint32 AG_MapRGBA(const AG_PixelFormat *, Uint8, Uint8, Uint8, Uint8) DEPRECATED_ATTRIBUTE;
451 void AG_GetRGB(Uint32, const AG_PixelFormat *, Uint8 *, Uint8 *, Uint8 *) DEPRECATED_ATTRIBUTE;
452 void AG_GetRGBA(Uint32, const AG_PixelFormat *, Uint8 *, Uint8 *, Uint8 *, Uint8 *) DEPRECATED_ATTRIBUTE;
453 AG_Surface *AG_DupSurface(AG_Surface *) DEPRECATED_ATTRIBUTE;
454 int AG_SamePixelFmt (const AG_Surface *, const AG_Surface *) DEPRECATED_ATTRIBUTE;
455 #endif /* AG_LEGACY */
456 __END_DECLS
457
458 #include <agar/gui/close.h>
459 #endif /* _AGAR_GUI_SURFACE_H_ */
460