]> git.mxchange.org Git - flightgear.git/blob - src/Canvas/ShivaVG/src/shImage.c
Fix a Clang warning in Shiva.
[flightgear.git] / src / Canvas / ShivaVG / src / shImage.c
1 /*
2  * Copyright (c) 2007 Ivan Leben
3  *
4  * This library 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  * This library 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 this library in the file COPYING;
16  * if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20
21 #include <vg/openvg.h>
22 #include "shImage.h"
23 #include "shContext.h"
24 #include <string.h>
25 #include <stdio.h>
26
27 #define _ITEM_T SHColor
28 #define _ARRAY_T SHColorArray
29 #define _FUNC_T shColorArray
30 #define _ARRAY_DEFINE
31 #define _COMPARE_T(c1,c2) 0
32 #include "shArrayBase.h"
33
34 #define _ITEM_T SHImage*
35 #define _ARRAY_T SHImageArray
36 #define _FUNC_T shImageArray
37 #define _ARRAY_DEFINE
38 #include "shArrayBase.h"
39
40
41 /*-----------------------------------------------------------
42  * Prepares the proper pixel pack/unpack info for the given
43  * OpenVG image format.
44  *-----------------------------------------------------------*/
45
46 void shSetupImageFormat(VGImageFormat vg, SHImageFormatDesc *f)
47 {
48   SHuint8 abits = 0;
49   SHuint8 tshift = 0;
50   SHuint8 tmask = 0;
51   SHuint32 amsbBit = 0;
52   SHuint32 bgrBit = 0;
53
54   /* Store VG format name */
55   f->vgformat = vg;
56
57   /* Check if alpha on MSB or colors in BGR order */
58   amsbBit = ((vg & (1 << 6)) >> 6);
59   bgrBit = ((vg & (1 << 7)) >> 7);
60
61   /* Find component ordering and size */
62   switch(vg & 0x1F)
63   {
64   case 0: /* VG_sRGBX_8888 */
65   case 7: /* VG_lRGBX_8888 */
66     f->bytes = 4;
67     f->rmask = 0xFF000000;
68     f->rshift = 24;
69     f->rmax = 255;
70     f->gmask = 0x00FF0000;
71     f->gshift = 16;
72     f->gmax = 255;
73     f->bmask = 0x0000FF00;
74     f->bshift = 8;
75     f->bmax = 255;
76     f->amask = 0x0;
77     f->ashift = 0;
78     f->amax = 1;
79     break;
80   case 1: /* VG_sRGBA_8888 */
81   case 2: /* VG_sRGBA_8888_PRE */
82   case 8: /* VG_lRGBA_8888 */
83   case 9: /* VG_lRGBA_8888_PRE */
84     f->bytes = 4;
85     f->rmask = 0xFF000000;
86     f->rshift = 24;
87     f->rmax = 255;
88     f->gmask = 0x00FF0000;
89     f->gshift = 16;
90     f->gmax = 255;
91     f->bmask = 0x0000FF00;
92     f->bshift = 8;
93     f->bmax = 255;
94     f->amask = 0x000000FF;
95     f->ashift = 0;
96     f->amax = 255;
97     break;
98   case 3: /* VG_sRGB_565 */
99     f->bytes = 2;
100     f->rmask = 0xF800;
101     f->rshift = 11;
102     f->rmax = 31;
103     f->gmask = 0x07E0;
104     f->gshift = 5;
105     f->gmax = 63;
106     f->bmask = 0x001F;
107     f->bshift = 0;
108     f->bmax = 31;
109     f->amask = 0x0;
110     f->ashift = 0;
111     f->amax = 1;
112     break;
113   case 4: /* VG_sRGBA_5551 */
114     f->bytes = 2;
115     f->rmask = 0xF800;
116     f->rshift = 11;
117     f->rmax = 31;
118     f->gmask = 0x07C0;
119     f->gshift = 6;
120     f->gmax = 31;
121     f->bmask = 0x003E;
122     f->bshift = 1;
123     f->bmax = 31;
124     f->amask = 0x0001;
125     f->ashift = 0;
126     f->amax = 1;
127     break;
128   case 5: /* VG_sRGBA_4444 */
129     f->bytes = 2;
130     f->rmask = 0xF000;
131     f->rshift = 12;
132     f->rmax = 15;
133     f->gmask = 0x0F00;
134     f->gshift = 8;
135     f->gmax = 15;
136     f->bmask = 0x00F0;
137     f->bshift = 4;
138     f->bmax = 15;
139     f->amask = 0x000F;
140     f->ashift = 0;
141     f->amax = 15;
142     break;
143   case 6: /* VG_sL_8 */
144   case 10: /* VG_lL_8 */
145     f->bytes = 1;
146     f->rmask = 0xFF;
147     f->rshift = 0;
148     f->rmax = 255;
149     f->gmask = 0xFF;
150     f->gshift = 0;
151     f->gmax = 255;
152     f->bmask = 0xFF;
153     f->bshift = 0;
154     f->bmax = 255;
155     f->amask = 0x0;
156     f->ashift = 0;
157     f->amax = 1;
158     break;
159   case 11: /* VG_A_8 */
160     f->bytes = 1;
161     f->rmask = 0x0;
162     f->rshift = 0;
163     f->rmax = 1;
164     f->gmask = 0x0;
165     f->gshift = 0;
166     f->gmax = 1;
167     f->bmask = 0x0;
168     f->bshift = 0;
169     f->bmax = 1;
170     f->amask = 0xFF;
171     f->ashift = 0;
172     f->amax = 255;
173     break;
174   case 12: /* VG_BW_1 */
175     f->bytes = 1;
176     f->rmask = 0x0;
177     f->rshift = 0;
178     f->rmax = 1;
179     f->gmask = 0x0;
180     f->gshift = 0;
181     f->gmax = 1;
182     f->bmask = 0x0;
183     f->bshift = 0;
184     f->bmax = 1;
185     f->amask = 0x0;
186     f->ashift = 0;
187     f->amax = 1;
188     break;
189   }
190
191   /* Check for A,X at MSB */
192   if (amsbBit) {
193
194     abits = f->bshift;
195
196     f->rshift -= abits;
197     f->gshift -= abits;
198     f->bshift -= abits;
199     f->ashift = f->bytes * 8 - abits;
200
201     f->rmask >>= abits;
202     f->gmask >>= abits;
203     f->bmask >>= abits;
204     f->amask <<= f->bytes * 8 - abits;
205   }
206
207   /* Check for BGR ordering */
208   if (bgrBit) {
209
210     tshift = f->bshift;
211     f->bshift = f->rshift;
212     f->rshift = tshift;
213
214     tmask = f->bmask;
215     f->bmask = f->rmask;
216     f->rmask = tmask;
217   }
218
219   /* Find proper mapping to OpenGL formats */
220   switch(vg & 0x1F)
221   {
222   case VG_sRGBX_8888:
223   case VG_lRGBX_8888:
224   case VG_sRGBA_8888:
225   case VG_sRGBA_8888_PRE:
226   case VG_lRGBA_8888:
227   case VG_lRGBA_8888_PRE:
228
229     f->glintformat = GL_RGBA;
230
231     if (amsbBit == 0 && bgrBit == 0) {
232       f->glformat = GL_RGBA;
233       f->gltype = GL_UNSIGNED_INT_8_8_8_8;
234
235     }else if (amsbBit == 1 && bgrBit == 0) {
236       f->glformat = GL_BGRA;
237       f->gltype = GL_UNSIGNED_INT_8_8_8_8_REV;
238
239     }else if (amsbBit == 0 && bgrBit == 1) {
240       f->glformat = GL_BGRA;
241       f->gltype = GL_UNSIGNED_INT_8_8_8_8;
242
243     }else if (amsbBit == 1 && bgrBit == 1) {
244       f->glformat = GL_RGBA;
245       f->gltype = GL_UNSIGNED_INT_8_8_8_8_REV;
246     }
247
248     break;
249   case VG_sRGBA_5551:
250
251     f->glintformat = GL_RGBA;
252
253     if (amsbBit == 0 && bgrBit == 0) {
254       f->glformat = GL_RGBA;
255       f->gltype = GL_UNSIGNED_SHORT_5_5_5_1;
256
257     }else if (amsbBit == 1 && bgrBit == 0) {
258       f->glformat = GL_BGRA;
259       f->gltype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
260
261     }else if (amsbBit == 0 && bgrBit == 1) {
262       f->glformat = GL_BGRA;
263       f->gltype = GL_UNSIGNED_SHORT_5_5_5_1;
264
265     }else if (amsbBit == 1 && bgrBit == 1) {
266       f->glformat = GL_RGBA;
267       f->gltype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
268     }
269
270     break;
271   case VG_sRGBA_4444:
272
273     f->glintformat = GL_RGBA;
274
275     if (amsbBit == 0 && bgrBit == 0) {
276       f->glformat = GL_RGBA;
277       f->gltype = GL_UNSIGNED_SHORT_4_4_4_4;
278
279     }else if (amsbBit == 1 && bgrBit == 0) {
280       f->glformat = GL_BGRA;
281       f->gltype = GL_UNSIGNED_SHORT_4_4_4_4_REV;
282
283     }else if (amsbBit == 0 && bgrBit == 1) {
284       f->glformat = GL_BGRA;
285       f->gltype = GL_UNSIGNED_SHORT_4_4_4_4;
286
287     }else if (amsbBit == 1 && bgrBit == 1) {
288       f->glformat = GL_RGBA;
289       f->gltype = GL_UNSIGNED_SHORT_4_4_4_4_REV;
290     }
291
292     break;
293   case VG_sRGB_565:
294
295     f->glintformat = GL_RGB;
296
297     if (bgrBit == 0) {
298       f->glformat = GL_RGB;
299       f->gltype = GL_UNSIGNED_SHORT_5_6_5;
300
301     }else if (bgrBit == 1) {
302       f->glformat = GL_RGB;
303       f->gltype = GL_UNSIGNED_SHORT_5_6_5;
304     }
305
306     break;
307   case VG_sL_8:
308   case VG_lL_8:
309
310     f->glintformat = GL_LUMINANCE;
311     f->glformat = GL_LUMINANCE;
312     f->gltype = GL_UNSIGNED_BYTE;
313
314     break;
315   case VG_A_8:
316
317     f->glintformat = GL_ALPHA;
318     f->glformat = GL_ALPHA;
319     f->gltype = GL_UNSIGNED_BYTE;
320
321     break;
322   case VG_BW_1:
323
324     f->glintformat = 0;
325     f->glformat = 0;
326     f->gltype = 0;
327     break;
328   }
329 }
330
331 /*-----------------------------------------------------
332  * Returns 1 if the given format is valid according to
333  * the OpenVG specification, else 0.
334  *-----------------------------------------------------*/
335
336 int shIsValidImageFormat(VGImageFormat format)
337 {
338   SHint aOrderBit = (1 << 6);
339   SHint rgbOrderBit = (1 << 7);
340   SHint baseFormat = format & 0x1F;
341   SHint unorderedRgba = format & (~(aOrderBit | rgbOrderBit));
342   SHint isRgba = (baseFormat == VG_sRGBX_8888     ||
343                   baseFormat == VG_sRGBA_8888     ||
344                   baseFormat == VG_sRGBA_8888_PRE ||
345                   baseFormat == VG_sRGBA_5551     ||
346                   baseFormat == VG_sRGBA_4444     ||
347                   baseFormat == VG_lRGBX_8888     ||
348                   baseFormat == VG_lRGBA_8888     ||
349                   baseFormat == VG_lRGBA_8888_PRE);
350   
351   SHint check = isRgba ? unorderedRgba : format;
352   return check >= VG_sRGBX_8888 && check <= VG_BW_1;
353 }
354
355 /*-----------------------------------------------------
356  * Returns 1 if the given format is supported by this
357  * implementation
358  *-----------------------------------------------------*/
359
360 int shIsSupportedImageFormat(VGImageFormat format)
361 {
362   SHuint32 baseFormat = (format & 0x1F);
363   if (baseFormat == VG_sRGBA_8888_PRE ||
364       baseFormat == VG_lRGBA_8888_PRE ||
365       baseFormat == VG_BW_1)
366       return 0;
367
368   return 1;
369 }
370
371 /*--------------------------------------------------------
372  * Packs the pixel color components into memory at given
373  * address according to given format
374  *--------------------------------------------------------*/
375
376 void shStoreColor(SHColor *c, void *data, SHImageFormatDesc *f)
377 {
378   /*
379   TODO: unsupported formats:
380   - s and l both behave linearly
381   - 1-bit black & white (BW_1)
382   */
383
384   SHfloat l = 0.0f;
385   SHuint32 out = 0x0;
386
387   if (f->vgformat == VG_lL_8 || f->vgformat == VG_sL_8) {
388
389     /* Grayscale (luminosity) conversion as defined by the spec */
390     l = 0.2126f * c->r + 0.7152f * c->g + 0.0722f * c->r;
391     out = (SHuint32)(l * (SHfloat)f->rmax + 0.5f);
392
393   }else{
394
395     /* Pack color components */
396     out += ( ((SHuint32)(c->r * (SHfloat)f->rmax + 0.5f)) << f->rshift ) & f->rmask;
397     out += ( ((SHuint32)(c->g * (SHfloat)f->gmax + 0.5f)) << f->gshift ) & f->gmask;
398     out += ( ((SHuint32)(c->b * (SHfloat)f->bmax + 0.5f)) << f->bshift ) & f->bmask;
399     out += ( ((SHuint32)(c->a * (SHfloat)f->amax + 0.5f)) << f->ashift ) & f->amask;
400   }
401   
402   /* Store to buffer */
403   switch (f->bytes) {
404   case 4: *((SHuint32*)data) = (SHuint32)(out & 0xFFFFFFFF); break;
405   case 2: *((SHuint16*)data) = (SHuint16)(out & 0x0000FFFF); break;
406   case 1: *((SHuint8*)data)  = (SHuint8) (out & 0x000000FF); break;
407   }
408 }
409
410 /*---------------------------------------------------------
411  * Unpacks the pixel color components from memory at given
412  * address according to the given format
413  *---------------------------------------------------------*/
414
415 void shLoadColor(SHColor *c, const void *data, SHImageFormatDesc *f)
416 {
417   /*
418   TODO: unsupported formats:
419   - s and l both behave linearly
420   - 1-bit black & white (BW_1)
421   */
422
423   SHuint32 in = 0x0;
424   
425   /* Load from buffer */
426   switch (f->bytes) {
427   case 4: in = (SHuint32) *((SHuint32*)data); break;
428   case 2: in = (SHuint32) *((SHuint16*)data); break;
429   case 1: in = (SHuint32) *((SHuint8*)data); break;
430   }
431
432   /* Unpack color components */
433   c->r = (SHfloat)((in & f->rmask) >> f->rshift) / (SHfloat) f->rmax;
434   c->g = (SHfloat)((in & f->gmask) >> f->gshift) / (SHfloat) f->gmax;
435   c->b = (SHfloat)((in & f->bmask) >> f->bshift) / (SHfloat) f->bmax;
436   c->a = (SHfloat)((in & f->amask) >> f->ashift) / (SHfloat) f->amax;
437   
438   /* Initialize unused components to 1 */
439   if (f->amask == 0x0) { c->a = 1.0f; }
440   if (f->rmask == 0x0) { c->r = 1.0f; c->g = 1.0f; c->b = 1.0f; }
441 }
442
443
444 /*----------------------------------------------
445  * Color and Image constructors and destructors
446  *----------------------------------------------*/
447
448 void SHColor_ctor(SHColor *c)
449 {
450   c->r = 0.0f;
451   c->g = 0.0f;
452   c->b = 0.0f;
453   c->a = 0.0f;
454 }
455
456 void SHColor_dtor(SHColor *c) {
457 }
458
459 void SHImage_ctor(SHImage *i)
460 {
461   i->data = NULL;
462   i->width = 0;
463   i->height = 0;
464   glGenTextures(1, &i->texture);
465 }
466
467 void SHImage_dtor(SHImage *i)
468 {
469   if (i->data != NULL)
470     free(i->data);
471   
472   if (glIsTexture(i->texture))
473     glDeleteTextures(1, &i->texture);
474 }
475
476 /*--------------------------------------------------------
477  * Finds appropriate OpenGL texture size for the size of
478  * the given image
479  *--------------------------------------------------------*/
480
481 void shUpdateImageTextureSize(SHImage *i)
482 {
483   i->texwidth = i->width;
484   i->texheight = i->height;
485   i->texwidthK = 1.0f;
486   i->texheightK = 1.0f;
487   
488   /* Round size to nearest power of 2 */
489   /* TODO: might be dropped out if it works without  */
490   
491   /*i->texwidth = 1;
492   while (i->texwidth < i->width)
493     i->texwidth *= 2;
494   
495   i->texheight = 1;
496   while (i->texheight < i->height)
497     i->texheight *= 2;
498   
499   i->texwidthK  = (SHfloat)i->width  / i->texwidth;
500   i->texheightK = (SHfloat)i->height / i->texheight; */
501 }
502
503 /*--------------------------------------------------
504  * Downloads the image data from OpenVG into 
505  * an OpenGL texture
506  *--------------------------------------------------*/
507
508 void shUpdateImageTexture(SHImage *i, VGContext *c)
509 {
510   SHint potwidth;
511   SHint potheight;
512   SHint8 *potdata;
513
514   /* Find nearest power of two size */
515
516   potwidth = 1;
517   while (potwidth < i->width)
518     potwidth *= 2;
519   
520   potheight = 1;
521   while (potheight < i->height)
522     potheight *= 2;
523   
524   
525   /* Scale into a temp buffer if image not a power-of-two size (pot)
526      and non-power-of-two textures are not supported by OpenGL */  
527   
528   if ((i->width < potwidth || i->height < potheight) &&
529       !c->isGLAvailable_TextureNonPowerOfTwo) {
530     
531     potdata = (SHint8*)malloc( potwidth * potheight * i->fd.bytes );
532     if (!potdata) return;
533     
534     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
535     glPixelStorei(GL_PACK_ALIGNMENT, 1);
536     glBindTexture(GL_TEXTURE_2D, i->texture);
537     
538     
539     gluScaleImage(i->fd.glformat, i->width, i->height, i->fd.gltype, i->data,
540                   potwidth, potheight, i->fd.gltype, potdata);
541     
542     glTexImage2D(GL_TEXTURE_2D, 0, i->fd.glintformat, potwidth, potheight, 0,
543                  i->fd.glformat, i->fd.gltype, potdata);
544     
545     free(potdata);
546     return;
547   }
548   
549   /* Store pixels to texture */
550   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
551   glBindTexture(GL_TEXTURE_2D, i->texture);
552   glTexImage2D(GL_TEXTURE_2D, 0, i->fd.glintformat,
553                i->texwidth, i->texheight, 0,
554                i->fd.glformat, i->fd.gltype, i->data);
555 }
556
557 /*----------------------------------------------------------
558  * Creates a new image object and returns the handle to it
559  *----------------------------------------------------------*/
560
561 VG_API_CALL VGImage vgCreateImage(VGImageFormat format,
562                                   VGint width, VGint height,
563                                   VGbitfield allowedQuality)
564 {
565   SHImage *i = NULL;
566   SHImageFormatDesc fd;
567   VG_GETCONTEXT(VG_INVALID_HANDLE);
568   
569   /* Reject invalid formats */
570   VG_RETURN_ERR_IF(!shIsValidImageFormat(format),
571                    VG_UNSUPPORTED_IMAGE_FORMAT_ERROR,
572                    VG_INVALID_HANDLE);
573   
574   /* Reject unsupported formats */
575   VG_RETURN_ERR_IF(!shIsSupportedImageFormat(format),
576                    VG_UNSUPPORTED_IMAGE_FORMAT_ERROR,
577                    VG_INVALID_HANDLE);
578   
579   /* Reject invalid sizes */
580   VG_RETURN_ERR_IF(width  <= 0 || width > SH_MAX_IMAGE_WIDTH ||
581                    height <= 0 || height > SH_MAX_IMAGE_HEIGHT ||
582                    width * height > SH_MAX_IMAGE_PIXELS,
583                    VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
584   
585   /* Check if byte size exceeds SH_MAX_IMAGE_BYTES */
586   shSetupImageFormat(format, &fd);
587   VG_RETURN_ERR_IF(width * height * fd.bytes > SH_MAX_IMAGE_BYTES,
588                    VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
589   
590   /* Reject invalid quality bits */
591   VG_RETURN_ERR_IF(allowedQuality &
592                    ~(VG_IMAGE_QUALITY_NONANTIALIASED |
593                      VG_IMAGE_QUALITY_FASTER | VG_IMAGE_QUALITY_BETTER),
594                    VG_ILLEGAL_ARGUMENT_ERROR, VG_INVALID_HANDLE);
595   
596   /* Create new image object */
597   SH_NEWOBJ(SHImage, i);
598   VG_RETURN_ERR_IF(!i, VG_OUT_OF_MEMORY_ERROR, VG_INVALID_HANDLE);
599   i->width = width;
600   i->height = height;
601   i->fd = fd;
602   
603   /* Allocate data memory */
604   shUpdateImageTextureSize(i);
605   i->data = (SHuint8*)malloc( i->texwidth * i->texheight * fd.bytes );
606   
607   if (i->data == NULL) {
608     SH_DELETEOBJ(SHImage, i);
609     VG_RETURN_ERR(VG_OUT_OF_MEMORY_ERROR, VG_INVALID_HANDLE); }
610   
611   /* Initialize data by zeroing-out */
612   memset(i->data, 1, width * height * fd.bytes);
613   shUpdateImageTexture(i, context);
614   
615   /* Add to resource list */
616   shImageArrayPushBack(&context->images, i);
617   
618   VG_RETURN((VGImage)i);
619 }
620
621 VG_API_CALL void vgDestroyImage(VGImage image)
622 {
623   SHint index;
624   VG_GETCONTEXT(VG_NO_RETVAL);
625   
626   /* Check if valid resource */
627   index = shImageArrayFind(&context->images, (SHImage*)image);
628   VG_RETURN_ERR_IF(index == -1, VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL);
629   
630   /* Delete object and remove resource */
631   SH_DELETEOBJ(SHImage, (SHImage*)image);
632   shImageArrayRemoveAt(&context->images, index);
633   
634   VG_RETURN(VG_NO_RETVAL);
635 }
636
637 /*---------------------------------------------------
638  * Clear given rectangle area in the image data with
639  * color set via vgSetfv(VG_CLEAR_COLOR, ...)
640  *---------------------------------------------------*/
641
642 VG_API_CALL void vgClearImage(VGImage image,
643                               VGint x, VGint y, VGint width, VGint height)
644 {
645   SHImage *i;
646   SHColor clear;
647   SHuint8 *data;
648   SHint X,Y, ix, iy, dx, dy, stride;
649   VG_GETCONTEXT(VG_NO_RETVAL);
650   
651   VG_RETURN_ERR_IF(!shIsValidImage(context, image),
652                    VG_BAD_HANDLE_ERROR, VG_NO_RETVAL);
653   
654   /* TODO: check if image current render target */
655   
656   i = (SHImage*)image;
657   VG_RETURN_ERR_IF(width <= 0 || height <= 0,
658                    VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL);
659   
660   /* Nothing to do if target rectangle out of bounds */
661   if (x >= i->width || y >= i->height)
662     VG_RETURN(VG_NO_RETVAL);
663   if (x + width < 0 || y + height < 0)
664     VG_RETURN(VG_NO_RETVAL);
665
666   /* Clamp to image bounds */
667   ix = SH_MAX(x, 0); dx = ix - x;
668   iy = SH_MAX(y, 0); dy = iy - y;
669   width  = SH_MIN( width  - dx, i->width  - ix);
670   height = SH_MIN( height - dy, i->height - iy);
671   stride = i->texwidth * i->fd.bytes;
672   
673   /* Walk pixels and clear*/
674   clear = context->clearColor;
675   
676   for (Y=iy; Y<iy+height; ++Y) {
677     data = i->data + ( Y*stride + ix * i->fd.bytes );
678     
679     for (X=ix; X<ix+width; ++X) {
680       shStoreColor(&clear, data, &i->fd);
681       data += i->fd.bytes;
682     }}
683   
684   shUpdateImageTexture(i, context);
685   VG_RETURN(VG_NO_RETVAL);
686 }
687
688 /*------------------------------------------------------------
689  * Generic function for copying a rectangle area of pixels
690  * of size (width,height) among two data buffers. The size of
691  * source (swidth,sheight) and destination (dwidth,dheight)
692  * images may vary as well as the source coordinates (sx,sy)
693  * and destination coordinates(dx, dy).
694  *------------------------------------------------------------*/
695
696 void shCopyPixels(SHuint8 *dst, VGImageFormat dstFormat, SHint dstStride,
697                   const SHuint8 *src, VGImageFormat srcFormat, SHint srcStride,
698                   SHint dwidth, SHint dheight, SHint swidth, SHint sheight,
699                   SHint dx, SHint dy, SHint sx, SHint sy,
700                   SHint width, SHint height)
701 {
702   SHint dxold, dyold;
703   SHint SX, SY, DX, DY;
704   const SHuint8 *SD;
705   SHuint8 *DD;
706   SHColor c;
707
708   SHImageFormatDesc dfd;
709   SHImageFormatDesc sfd;
710
711   /* Setup image format descriptors */
712   SH_ASSERT(shIsSupportedImageFormat(dstFormat));
713   SH_ASSERT(shIsSupportedImageFormat(srcFormat));
714   shSetupImageFormat(dstFormat, &dfd);
715   shSetupImageFormat(srcFormat, &sfd);
716
717   /*
718     In order to optimize the copying loop and remove the
719     if statements from it to check whether target pixel
720     is in the source and destination surface, we clamp
721     copy rectangle in advance. This is quite a tedious
722     task though. Here is a picture of the scene. Note that
723     (dx,dy) is actually an offset of the copy rectangle
724     (clamped to src surface) from the (0,0) point on dst
725     surface. A negative (dx,dy) (as in this picture) also
726     affects src coords of the copy rectangle which have
727     to be readjusted again (sx,sy,width,height).
728
729                           src
730     *----------------------*
731     | (sx,sy)  copy rect   |
732     | *-----------*        |
733     | |\(dx, dy)  |        |          dst
734     | | *------------------------------*
735     | | |xxxxxxxxx|        |           |
736     | | |xxxxxxxxx|        |           |
737     | *-----------*        |           |
738     |   |   (width,height) |           |
739     *----------------------*           |
740         |           (swidth,sheight)   |
741         *------------------------------*
742                                 (dwidth,dheight)
743   */
744
745   /* Cancel if copy rect out of src bounds */
746   if (sx >= swidth || sy >= sheight) return;
747   if (sx + width < 0 || sy + height < 0) return;
748   
749   /* Clamp copy rectangle to src bounds */
750   sx = SH_MAX(sx, 0);
751   sy = SH_MAX(sy, 0);
752   width = SH_MIN(width, swidth - sx);
753   height = SH_MIN(height, sheight - sy);
754   
755   /* Cancel if copy rect out of dst bounds */
756   if (dx >= dwidth || dy >= dheight) return;
757   if (dx + width < 0 || dy + height < 0) return;
758   
759   /* Clamp copy rectangle to dst bounds */
760   dxold = dx; dyold = dy;
761   dx = SH_MAX(dx, 0);
762   dy = SH_MAX(dy, 0);
763   sx += dx - dxold;
764   sy += dy - dyold;
765   width -= dx - dxold;
766   height -= dy - dyold;
767   width = SH_MIN(width, dwidth  - dx);
768   height = SH_MIN(height, dheight - dy);
769   
770   /* Calculate stride from format if not given */
771   if (dstStride == -1) dstStride = dwidth * dfd.bytes;
772   if (srcStride == -1) srcStride = swidth * sfd.bytes;
773   
774   if (srcFormat == dstFormat) {
775     
776     /* Walk pixels and copy */
777     for (SY=sy, DY=dy; SY < sy+height; ++SY, ++DY) {
778       SD = src + SY * srcStride + sx * sfd.bytes;
779       DD = dst + DY * dstStride + dx * dfd.bytes;
780       memcpy(DD, SD, width * sfd.bytes);
781     }
782     
783   }else{
784   
785     /* Walk pixels and copy */
786     for (SY=sy, DY=dy; SY < sy+height; ++SY, ++DY) {
787       SD = src + SY * srcStride + sx * sfd.bytes;
788       DD = dst + DY * dstStride + dx * dfd.bytes;
789       
790       for (SX=sx, DX=dx; SX < sx+width; ++SX, ++DX) {
791         shLoadColor(&c, SD, &sfd);
792         shStoreColor(&c, DD, &dfd);
793         SD += sfd.bytes; DD += dfd.bytes;
794       }}
795   }
796 }
797
798 /*---------------------------------------------------------
799  * Copies a rectangle area of pixels of size (width,height)
800  * from given data buffer to image surface at destination
801  * coordinates (x,y)
802  *---------------------------------------------------------*/
803
804 VG_API_CALL void vgImageSubData(VGImage image,
805                                 const void * data, VGint dataStride,
806                                 VGImageFormat dataFormat,
807                                 VGint x, VGint y, VGint width, VGint height)
808 {
809   SHImage *i;
810   VG_GETCONTEXT(VG_NO_RETVAL);
811   
812   VG_RETURN_ERR_IF(!shIsValidImage(context, image),
813                    VG_BAD_HANDLE_ERROR, VG_NO_RETVAL);
814   
815   /* TODO: check if image current render target */
816   i = (SHImage*)image;
817   
818   /* Reject invalid formats */
819   VG_RETURN_ERR_IF(!shIsValidImageFormat(dataFormat),
820                    VG_UNSUPPORTED_IMAGE_FORMAT_ERROR,
821                    VG_NO_RETVAL);
822   
823   /* Reject unsupported image formats */
824   VG_RETURN_ERR_IF(!shIsSupportedImageFormat(dataFormat),
825                    VG_UNSUPPORTED_IMAGE_FORMAT_ERROR,
826                    VG_NO_RETVAL);
827   
828   VG_RETURN_ERR_IF(width <= 0 || height <= 0 || !data,
829                    VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL);
830   
831   /* TODO: check data array alignment */
832   
833   shCopyPixels(i->data, i->fd.vgformat, i->texwidth * i->fd.bytes,
834                data, dataFormat,dataStride,
835                i->width, i->height, width, height,
836                x, y, 0, 0, width, height);
837   
838   shUpdateImageTexture(i, context);
839   VG_RETURN(VG_NO_RETVAL);
840 }
841
842 /*---------------------------------------------------------
843  * Copies a rectangle area of pixels of size (width,height)
844  * from image surface at source coordinates (x,y) to given
845  * data buffer
846  *---------------------------------------------------------*/
847
848 VG_API_CALL void vgGetImageSubData(VGImage image,
849                                    void * data, VGint dataStride,
850                                    VGImageFormat dataFormat,
851                                    VGint x, VGint y,
852                                    VGint width, VGint height)
853 {
854   SHImage *i;
855   VG_GETCONTEXT(VG_NO_RETVAL);
856   
857   VG_RETURN_ERR_IF(!shIsValidImage(context, image),
858                    VG_BAD_HANDLE_ERROR, VG_NO_RETVAL);
859   
860   /* TODO: check if image current render target */
861   i = (SHImage*)image;
862   
863   /* Reject invalid formats */
864   VG_RETURN_ERR_IF(!shIsValidImageFormat(dataFormat),
865                    VG_UNSUPPORTED_IMAGE_FORMAT_ERROR,
866                    VG_NO_RETVAL);
867   
868   /* Reject unsupported formats */
869   VG_RETURN_ERR_IF(!shIsSupportedImageFormat(dataFormat),
870                    VG_UNSUPPORTED_IMAGE_FORMAT_ERROR,
871                    VG_NO_RETVAL);
872   
873   VG_RETURN_ERR_IF(width <= 0 || height <= 0 || !data,
874                    VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL);
875   
876   /* TODO: check data array alignment */
877   
878   shCopyPixels(data, dataFormat, dataStride,
879                i->data, i->fd.vgformat, i->texwidth * i->fd.bytes,
880                width, height, i->width, i->height,
881                0,0,x,x,width,height);
882   
883   VG_RETURN(VG_NO_RETVAL);
884 }
885
886 /*----------------------------------------------------------
887  * Copies a rectangle area of pixels of size (width,height)
888  * from src image surface at source coordinates (sx,sy) to
889  * dst image surface at destination cordinates (dx,dy)
890  *---------------------------------------------------------*/
891
892 VG_API_CALL void vgCopyImage(VGImage dst, VGint dx, VGint dy,
893                              VGImage src, VGint sx, VGint sy,
894                              VGint width, VGint height,
895                              VGboolean dither)
896 {
897   SHImage *s, *d;
898   SHuint8 *pixels;
899
900   VG_GETCONTEXT(VG_NO_RETVAL);
901   
902   VG_RETURN_ERR_IF(!shIsValidImage(context, src) ||
903                    !shIsValidImage(context, dst),
904                    VG_BAD_HANDLE_ERROR, VG_NO_RETVAL);
905
906   /* TODO: check if images current render target */
907
908   s = (SHImage*)src; d = (SHImage*)dst;
909   VG_RETURN_ERR_IF(width <= 0 || height <= 0,
910                    VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL);
911
912   /* In order to perform copying in a cosistent fashion
913      we first copy to a temporary buffer and only then to
914      destination image */
915   
916   /* TODO: rather check first if the image is really
917      the same and whether the regions overlap. if not
918      we can copy directly */
919
920   pixels = (SHuint8*)malloc(width * height * s->fd.bytes);
921   SH_RETURN_ERR_IF(!pixels, VG_OUT_OF_MEMORY_ERROR, SH_NO_RETVAL);
922
923   shCopyPixels(pixels, s->fd.vgformat, s->texwidth * s->fd.bytes,
924                s->data, s->fd.vgformat, s->texwidth * s->fd.bytes,
925                width, height, s->width, s->height,
926                0, 0, sx, sy, width, height);
927
928   shCopyPixels(d->data, d->fd.vgformat, d->texwidth * d->fd.bytes,
929                pixels, s->fd.vgformat, s->texwidth * s->fd.bytes,
930                d->width, d->height, width, height,
931                dx, dy, 0, 0, width, height);
932   
933   free(pixels);
934   
935   shUpdateImageTexture(d, context);
936   VG_RETURN(VG_NO_RETVAL);
937 }
938
939 /*---------------------------------------------------------
940  * Copies a rectangle area of pixels of size (width,height)
941  * from src image surface at source coordinates (sx,sy) to
942  * window surface at destination coordinates (dx,dy)
943  *---------------------------------------------------------*/
944
945 VG_API_CALL void vgSetPixels(VGint dx, VGint dy,
946                              VGImage src, VGint sx, VGint sy,
947                              VGint width, VGint height)
948 {
949   SHImage *i;
950   SHuint8 *pixels;
951   SHImageFormatDesc winfd;
952
953   VG_GETCONTEXT(VG_NO_RETVAL);
954   
955   VG_RETURN_ERR_IF(!shIsValidImage(context, src),
956                    VG_BAD_HANDLE_ERROR, VG_NO_RETVAL);
957   
958   /* TODO: check if image current render target (requires EGL) */
959
960   i = (SHImage*)src;
961   VG_RETURN_ERR_IF(width <= 0 || height <= 0,
962                    VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL);
963
964   /* Setup window image format descriptor */
965   /* TODO: this actually depends on the target framebuffer type
966      if we really want the copy to be optimized */
967   shSetupImageFormat(VG_sRGBA_8888, &winfd);
968
969   /* OpenGL doesn't allow us to use random stride. We have to
970      manually copy the image data and write from a copy with
971      normal row length (without power-of-two roundup pixels) */
972
973   pixels = (SHuint8*)malloc(width * height * winfd.bytes);
974   SH_RETURN_ERR_IF(!pixels, VG_OUT_OF_MEMORY_ERROR, SH_NO_RETVAL);
975
976   shCopyPixels(pixels, winfd.vgformat, -1,
977                i->data, i->fd.vgformat, i->texwidth * i->fd.bytes,
978                width, height, i->width, i->height,
979                0,0,sx,sy, width, height);
980
981   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
982   glRasterPos2i(dx, dy);
983   glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
984   glRasterPos2i(0,0);
985   
986   free(pixels);
987
988   VG_RETURN(VG_NO_RETVAL);
989 }
990
991 /*---------------------------------------------------------
992  * Copies a rectangle area of pixels of size (width,height)
993  * from given data buffer at source coordinates (sx,sy) to
994  * window surface at destination coordinates (dx,dy)
995  *---------------------------------------------------------*/
996
997 VG_API_CALL void vgWritePixels(const void * data, VGint dataStride,
998                                VGImageFormat dataFormat,
999                                VGint dx, VGint dy,
1000                                VGint width, VGint height)
1001 {
1002   SHuint8 *pixels;
1003   SHImageFormatDesc winfd;
1004
1005   VG_GETCONTEXT(VG_NO_RETVAL);
1006
1007   /* Reject invalid formats */
1008   VG_RETURN_ERR_IF(!shIsValidImageFormat(dataFormat),
1009                    VG_UNSUPPORTED_IMAGE_FORMAT_ERROR,
1010                    VG_NO_RETVAL);
1011   
1012   /* Reject unsupported formats */
1013   VG_RETURN_ERR_IF(!shIsSupportedImageFormat(dataFormat),
1014                    VG_UNSUPPORTED_IMAGE_FORMAT_ERROR,
1015                    VG_NO_RETVAL);
1016
1017   /* TODO: check output data array alignment */
1018   
1019   VG_RETURN_ERR_IF(width <= 0 || height <= 0 || !data,
1020                    VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL);
1021
1022   /* Setup window image format descriptor */
1023   /* TODO: this actually depends on the target framebuffer type
1024      if we really want the copy to be optimized */
1025   shSetupImageFormat(VG_sRGBA_8888, &winfd);
1026
1027   /* OpenGL doesn't allow us to use random stride. We have to
1028      manually copy the image data and write from a copy with
1029      normal row length */
1030
1031   pixels = (SHuint8*)malloc(width * height * winfd.bytes);
1032   SH_RETURN_ERR_IF(!pixels, VG_OUT_OF_MEMORY_ERROR, SH_NO_RETVAL);
1033   
1034   shCopyPixels(pixels, winfd.vgformat, -1,
1035                (SHuint8*)data, dataFormat, dataStride,
1036                width, height, width, height,
1037                0,0,0,0, width, height);
1038   
1039   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1040   glRasterPos2i(dx, dy);
1041   glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
1042   glRasterPos2i(0,0);
1043   
1044   free(pixels);
1045
1046   VG_RETURN(VG_NO_RETVAL); 
1047 }
1048
1049 /*-----------------------------------------------------------
1050  * Copies a rectangle area of pixels of size (width, height)
1051  * from window surface at source coordinates (sx, sy) to
1052  * image surface at destination coordinates (dx, dy)
1053  *-----------------------------------------------------------*/
1054
1055 VG_API_CALL void vgGetPixels(VGImage dst, VGint dx, VGint dy,
1056                              VGint sx, VGint sy,
1057                              VGint width, VGint height)
1058 {
1059   SHImage *i;
1060   SHuint8 *pixels;
1061   SHImageFormatDesc winfd;
1062   VG_GETCONTEXT(VG_NO_RETVAL);
1063   
1064   VG_RETURN_ERR_IF(!shIsValidImage(context, dst),
1065                    VG_BAD_HANDLE_ERROR, VG_NO_RETVAL);
1066   
1067    /* TODO: check if image current render target */
1068
1069   i = (SHImage*)dst;
1070   VG_RETURN_ERR_IF(width <= 0 || height <= 0,
1071                    VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL);
1072
1073   /* Setup window image format descriptor */
1074   /* TODO: this actually depends on the target framebuffer type
1075      if we really want the copy to be optimized */
1076   shSetupImageFormat(VG_sRGBA_8888, &winfd);
1077   
1078   /* OpenGL doesn't allow us to read to random destination
1079      coordinates nor using random stride. We have to
1080      read first and then manually copy to the image data */
1081
1082   pixels = (SHuint8*)malloc(width * height * winfd.bytes);
1083   SH_RETURN_ERR_IF(!pixels, VG_OUT_OF_MEMORY_ERROR, SH_NO_RETVAL);
1084
1085   glPixelStorei(GL_PACK_ALIGNMENT, 1);
1086   glReadPixels(sx, sy, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
1087   
1088   shCopyPixels(i->data, i->fd.vgformat, i->texwidth * i->fd.bytes,
1089                pixels, winfd.vgformat, -1,
1090                i->width, i->height, width, height,
1091                dx, dy, 0, 0, width, height);
1092
1093   free(pixels);
1094   
1095   shUpdateImageTexture(i, context);
1096   VG_RETURN(VG_NO_RETVAL);
1097 }
1098
1099 /*-----------------------------------------------------------
1100  * Copies a rectangle area of pixels of size (width, height)
1101  * from window surface at source coordinates (sx, sy) to
1102  * to given output data buffer.
1103  *-----------------------------------------------------------*/
1104
1105 VG_API_CALL void vgReadPixels(void * data, VGint dataStride,
1106                               VGImageFormat dataFormat,
1107                               VGint sx, VGint sy,
1108                               VGint width, VGint height)
1109 {
1110   SHuint8 *pixels;
1111   SHImageFormatDesc winfd;
1112   VG_GETCONTEXT(VG_NO_RETVAL);
1113
1114   /* Reject invalid formats */
1115   VG_RETURN_ERR_IF(!shIsValidImageFormat(dataFormat),
1116                    VG_UNSUPPORTED_IMAGE_FORMAT_ERROR,
1117                    VG_NO_RETVAL);
1118   
1119   /* Reject unsupported image formats */
1120   VG_RETURN_ERR_IF(!shIsSupportedImageFormat(dataFormat),
1121                    VG_UNSUPPORTED_IMAGE_FORMAT_ERROR,
1122                    VG_NO_RETVAL);
1123
1124   /* TODO: check output data array alignment */
1125   
1126   VG_RETURN_ERR_IF(width <= 0 || height <= 0 || !data,
1127                    VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL);
1128
1129   /* Setup window image format descriptor */
1130   /* TODO: this actually depends on the target framebuffer type
1131      if we really want the copy to be optimized */
1132   shSetupImageFormat(VG_sRGBA_8888, &winfd);
1133
1134   /* OpenGL doesn't allow random data stride. We have to
1135      read first and then manually copy to the output buffer */
1136
1137   pixels = (SHuint8*)malloc(width * height * winfd.bytes);
1138   SH_RETURN_ERR_IF(!pixels, VG_OUT_OF_MEMORY_ERROR, SH_NO_RETVAL);
1139
1140   glPixelStorei(GL_PACK_ALIGNMENT, 1);
1141   glReadPixels(sx, sy, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
1142   
1143   shCopyPixels(data, dataFormat, dataStride,
1144                pixels, winfd.vgformat, -1,
1145                width, height, width, height,
1146                0, 0, 0, 0, width, height);
1147
1148   free(pixels);
1149   
1150   VG_RETURN(VG_NO_RETVAL);
1151 }
1152
1153 /*----------------------------------------------------------
1154  * Copies a rectangle area of pixels of size (width,height)
1155  * from window surface at source coordinates (sx,sy) to
1156  * windows surface at destination cordinates (dx,dy)
1157  *---------------------------------------------------------*/
1158
1159 VG_API_CALL void vgCopyPixels(VGint dx, VGint dy,
1160                               VGint sx, VGint sy,
1161                               VGint width, VGint height)
1162 {
1163   VG_GETCONTEXT(VG_NO_RETVAL);
1164   
1165   VG_RETURN_ERR_IF(width <= 0 || height <= 0,
1166                    VG_ILLEGAL_ARGUMENT_ERROR, VG_NO_RETVAL);
1167   
1168   glPixelStorei(GL_PACK_ALIGNMENT, 1);
1169   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1170   glRasterPos2i(dx, dy);
1171   glCopyPixels(sx, sy, width, height, GL_COLOR);
1172   glRasterPos2i(0, 0);
1173   
1174   VG_RETURN(VG_NO_RETVAL);
1175 }
1176
1177 VG_API_CALL VGImage vgChildImage(VGImage parent,
1178                                  VGint x, VGint y, VGint width, VGint height)
1179 {
1180   return VG_INVALID_HANDLE;
1181 }
1182
1183 VG_API_CALL VGImage vgGetParent(VGImage image)
1184 {
1185   return VG_INVALID_HANDLE;
1186 }
1187
1188 VG_API_CALL void vgColorMatrix(VGImage dst, VGImage src,
1189                                const VGfloat * matrix)
1190 {
1191 }
1192
1193 VG_API_CALL void vgConvolve(VGImage dst, VGImage src,
1194                             VGint kernelWidth, VGint kernelHeight,
1195                             VGint shiftX, VGint shiftY,
1196                             const VGshort * kernel,
1197                             VGfloat scale,
1198                             VGfloat bias,
1199                             VGTilingMode tilingMode)
1200 {
1201 }
1202
1203 VG_API_CALL void vgSeparableConvolve(VGImage dst, VGImage src,
1204                                      VGint kernelWidth,
1205                                      VGint kernelHeight,
1206                                      VGint shiftX, VGint shiftY,
1207                                      const VGshort * kernelX,
1208                                      const VGshort * kernelY,
1209                                      VGfloat scale,
1210                                      VGfloat bias,
1211                                      VGTilingMode tilingMode)
1212 {
1213 }
1214
1215 VG_API_CALL void vgGaussianBlur(VGImage dst, VGImage src,
1216                                 VGfloat stdDeviationX,
1217                                 VGfloat stdDeviationY,
1218                                 VGTilingMode tilingMode)
1219 {
1220 }
1221
1222 VG_API_CALL void vgLookup(VGImage dst, VGImage src,
1223                           const VGubyte * redLUT,
1224                           const VGubyte * greenLUT,
1225                           const VGubyte * blueLUT,
1226                           const VGubyte * alphaLUT,
1227                           VGboolean outputLinear,
1228                           VGboolean outputPremultiplied)
1229 {
1230 }
1231
1232 VG_API_CALL void vgLookupSingle(VGImage dst, VGImage src,
1233                                 const VGuint * lookupTable,
1234                                 VGImageChannel sourceChannel,
1235                                 VGboolean outputLinear,
1236                                 VGboolean outputPremultiplied)
1237 {
1238 }