Matplot: handle ARGB data
[scilab.git] / scilab / modules / graphic_objects / src / cpp / NgonGridMatplotData.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2011-2012 - DIGITEO - Manuel Juliachs
4  *  Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
5  *
6  *  This file must be used under the terms of the CeCILL.
7  *  This source file is licensed as described in the file COPYING, which
8  *  you should have received as part of this distribution.  The terms
9  *  are also available at
10  *  http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
11  *
12  */
13
14 #include "NgonGridMatplotData.hxx"
15 #include "Texture.hxx"
16
17 #include <climits>
18
19 extern "C" {
20 #include <string.h>
21 #include <stdlib.h>
22
23 #include "graphicObjectProperties.h"
24 }
25
26 const bool NgonGridMatplotData::isLittleEndian = NgonGridMatplotData::initEndian();
27 bool NgonGridMatplotData::isABGRSupported = false;
28
29 NgonGridMatplotData::NgonGridMatplotData(void)
30 {
31     this->data = NULL;
32     this->dataSize = 0;
33     this->scilabData = NULL;
34     this->type = 0;
35     this->imagetype = MATPLOT_NONE;
36 }
37
38 NgonGridMatplotData::~NgonGridMatplotData(void)
39 {
40     disposeTextureData();
41     if (this->scilabData)
42     {
43         delete[] (unsigned char *)this->scilabData;
44         this->scilabData = NULL;
45     }
46 }
47
48 int NgonGridMatplotData::getPropertyFromName(int propertyName)
49 {
50     switch (propertyName)
51     {
52         case __GO_DATA_MODEL_GRID_SIZE__ :
53             return GRID_SIZE;
54         case __GO_DATA_MODEL_MATPLOT_BOUNDS__ :
55             return MATPLOT_BOUNDS;
56         case __GO_DATA_MODEL_MATPLOT_TYPE__ :
57             return MATPLOT_TYPE;
58         case __GO_DATA_MODEL_Z__ :
59             return Z_COORDINATES;
60         case __GO_DATA_MODEL_MATPLOT_GL_TYPE__ :
61             return MATPLOT_GL_TYPE;
62         case __GO_DATA_MODEL_MATPLOT_DATA_INFOS__ :
63             return MATPLOT_DATA_INFOS;
64         case __GO_DATA_MODEL_MATPLOT_DATA_TYPE__ :
65             return MATPLOT_DATA_TYPE;
66         case __GO_DATA_MODEL_MATPLOT_DATA_ORDER__ :
67             return MATPLOT_DATA_ORDER;
68         case __GO_DATA_MODEL_MATPLOT_IMAGE_TYPE__ :
69             return MATPLOT_IMAGE_TYPE;
70         case __GO_DATA_MODEL_MATPLOT_IMAGE_DATA__ :
71             return MATPLOT_IMAGE_DATA;
72         case __GO_DATA_MODEL_MATPLOT_IMAGE_DATASIZE__ :
73             return MATPLOT_IMAGE_DATASIZE;
74         default :
75             return NgonGridData::getPropertyFromName(propertyName);
76     }
77 }
78
79 int NgonGridMatplotData::setDataProperty(int property, void const* value, int numElements)
80 {
81     switch (property)
82     {
83         case GRID_SIZE :
84         {
85             return setGridSize((int const*) value);
86         }
87         case MATPLOT_BOUNDS :
88         {
89             setBounds((double const*) value);
90             break;
91         }
92         case Z_COORDINATES :
93         {
94             setDataZ((double const*) value, numElements);
95             break;
96         }
97         case MATPLOT_IMAGE_TYPE :
98         {
99             return setImageType(*((int const*) value));
100         }
101         case MATPLOT_DATA_INFOS :
102         {
103             setDataInfos(*((int const*) value));
104             break;
105         }
106         case MATPLOT_DATA_TYPE :
107         {
108             setDataType(*((int const*) value));
109             break;
110         }
111         case MATPLOT_DATA_ORDER :
112         {
113             setDataOrder(*((int const*) value));
114             break;
115         }
116         case MATPLOT_IMAGE_DATA :
117         {
118             setImageData((void const *) value, numElements);
119             break;
120         }
121         default :
122         {
123             return NgonGridData::setDataProperty(property, value, numElements);
124         }
125     }
126
127     return 1;
128 }
129
130 void NgonGridMatplotData::getDataProperty(int property, void **_pvData)
131 {
132     switch (property)
133     {
134         case MATPLOT_BOUNDS :
135         {
136             *_pvData = getBounds();
137             break;
138         }
139         case MATPLOT_TYPE :
140         {
141             ((int *) *_pvData)[0] = getType();
142             break;
143         }
144         case Z_COORDINATES :
145         {
146             *_pvData = getScilabData();
147             break;
148         }
149         case MATPLOT_IMAGE_TYPE :
150         {
151             ((int *) *_pvData)[0] = getImageType();
152             break;
153         }
154         case MATPLOT_GL_TYPE :
155         {
156             ((int *) *_pvData)[0] = getGLType();
157             break;
158         }
159         case MATPLOT_DATA_INFOS :
160         {
161             ((int *) *_pvData)[0] = getDataInfos();
162             break;
163         }
164         case MATPLOT_DATA_TYPE :
165         {
166             ((int *) *_pvData)[0] = getDataType();
167             break;
168         }
169         case MATPLOT_DATA_ORDER :
170         {
171             ((int *) *_pvData)[0] = getDataOrder();
172             break;
173         }
174         case MATPLOT_IMAGE_DATA :
175         {
176             *_pvData = getImageData();
177             break;
178         }
179         case MATPLOT_IMAGE_DATASIZE :
180         {
181             ((unsigned int *) *_pvData)[0] = getImageDataSize();
182             break;
183         }
184         default :
185         {
186             NgonGridData::getDataProperty(property, _pvData);
187             break;
188         }
189     }
190 }
191
192 /*
193  * To be done: refactoring with NgonGridData, as these two classes'
194  * setGridSize methods are almost identical.
195  */
196 int NgonGridMatplotData::setGridSize(int const* gridSize)
197 {
198     int newXSize = 0;
199     int newYSize = 0;
200     int xModified = 0;
201     int yModified = 0;
202     int zModified = 0;
203     int result = 0;
204     int formerGridSize = 0;
205
206     double* newXCoordinates = NULL;
207     double* newYCoordinates = NULL;
208     double* newZCoordinates = NULL;
209
210     result = 1;
211
212     xModified = 0;
213     yModified = 0;
214     zModified = 0;
215
216     if ((gridSize[0] != 1) && (gridSize[1] != 1))
217     {
218         return 0;
219     }
220
221     if ((gridSize[2] != 1) && (gridSize[3] != 1))
222     {
223         return 0;
224     }
225
226     newXSize = gridSize[0] * gridSize[1];
227     newYSize = gridSize[2] * gridSize[3];
228
229     if (newXSize != xSize)
230     {
231         xModified = 1;
232
233         try
234         {
235             newXCoordinates = new double[newXSize];
236         }
237         catch (const std::exception& e)
238         {
239             e.what();
240             result = 0;
241         }
242     }
243
244     if (newYSize != ySize)
245     {
246         yModified = 1;
247
248         try
249         {
250             newYCoordinates = new double[newYSize];
251         }
252         catch (const std::exception& e)
253         {
254             e.what();
255             result = 0;
256         }
257     }
258
259     if (!result || (!xModified && !yModified))
260     {
261         return result;
262     }
263
264     if (xSize > 0 && ySize > 0)
265     {
266         formerGridSize = (xSize - 1) * (ySize - 1);
267     }
268     else
269     {
270         formerGridSize = 0;
271     }
272
273     if ((newXSize - 1) * (newYSize - 1) != formerGridSize)
274     {
275         zModified = 1;
276
277         try
278         {
279             newZCoordinates = new double[(newXSize - 1) * (newYSize - 1)];
280         }
281         catch (const std::exception& e)
282         {
283             e.what();
284             result = 0;
285         }
286     }
287
288     if (result)
289     {
290         if (xModified)
291         {
292             if (xSize > 0)
293             {
294                 delete [] xCoordinates;
295             }
296
297             xCoordinates = newXCoordinates;
298             xSize = newXSize;
299         }
300
301         xDimensions[0] = gridSize[0];
302         xDimensions[1] = gridSize[1];
303
304         if (yModified)
305         {
306             if (ySize > 0)
307             {
308                 delete [] yCoordinates;
309             }
310
311             yCoordinates = newYCoordinates;
312             ySize = newYSize;
313         }
314
315         yDimensions[0] = gridSize[2];
316         yDimensions[1] = gridSize[3];
317
318         if (zModified)
319         {
320             if (formerGridSize > 0)
321             {
322                 delete [] zCoordinates;
323             }
324
325             zCoordinates = newZCoordinates;
326
327             numGons = (xSize - 1) * (ySize - 1);
328
329         }
330
331         if (xModified || yModified)
332         {
333             computeCoordinates();
334         }
335
336     }
337     else
338     {
339         /* Failed allocation(s) */
340
341         if (xModified && (newXCoordinates != NULL))
342         {
343             delete [] newXCoordinates;
344         }
345
346         if (yModified && (newYCoordinates != NULL))
347         {
348             delete [] newYCoordinates;
349         }
350
351         if (zModified && (newZCoordinates != NULL))
352         {
353             delete [] newZCoordinates;
354         }
355
356     }
357
358     return result;
359 }
360
361 void NgonGridMatplotData::setBounds(double const* bounds)
362 {
363     if (bounds == NULL)
364     {
365         /* Type 0 object: bounds are computed from element indices by the setGridSize method */
366         type = 0;
367     }
368     else
369     {
370         /* To be done: test whether max > min */
371         boundingRectangle[0] = bounds[0];
372         boundingRectangle[1] = bounds[2];
373         boundingRectangle[2] = bounds[1];
374         boundingRectangle[3] = bounds[3];
375
376         type = 1;
377     }
378 }
379
380 double* NgonGridMatplotData::getBounds(void)
381 {
382     return boundingRectangle;
383 }
384
385 void NgonGridMatplotData::computeCoordinates(void)
386 {
387     if (type == 0)
388     {
389         for (int i = 0; i < xSize; i++)
390         {
391             xCoordinates[i] = 0.5 + (double) i;
392         }
393
394         for (int i = 0; i < ySize; i++)
395         {
396             yCoordinates[i] = 0.5 + (double) i;
397         }
398
399         boundingRectangle[0] = 0.5;
400         boundingRectangle[1] = 0.5 + (double) (xSize - 1);
401         boundingRectangle[2] = 0.5;
402         boundingRectangle[3] = 0.5 + (double) (ySize - 1);
403     }
404     else
405     {
406         double min = boundingRectangle[0];
407         double max = boundingRectangle[1];
408         int numElements = 0;
409
410
411         if (xSize == 1)
412         {
413             numElements = 1;
414         }
415         else
416         {
417             numElements = xSize - 1;
418         }
419
420         for (int i = 0; i < xSize; i++)
421         {
422             xCoordinates[i] = min + (double) i * (max - min) / (double) numElements;
423         }
424
425         min = boundingRectangle[2];
426         max = boundingRectangle[3];
427
428         if (ySize == 1)
429         {
430             numElements = 1;
431         }
432         else
433         {
434             numElements = ySize - 1;
435         }
436
437         for (int i = 0; i < ySize; i++)
438         {
439             yCoordinates[i] = min + (double) i * (max - min) / (double) numElements;
440         }
441     }
442 }
443
444 void NgonGridMatplotData::setDataZ(double const* data, int numElements)
445 {
446     if (numElements > (xSize - 1) * (ySize - 1))
447     {
448         return;
449     }
450
451     for (int i = 0; i < numElements; i++)
452     {
453         zCoordinates[i] = data[i];
454     }
455 }
456
457 int NgonGridMatplotData::setImageType(int imagetype)
458 {
459     const ImageType type = (ImageType)imagetype;
460
461     if (this->imagetype != type)
462     {
463         int grid[4] = {xSize, 1, ySize, 1};
464         if (this->datatype == MATPLOT_UChar || this->datatype == MATPLOT_Char)
465         {
466             if (this->imagetype == MATPLOT_RGB)
467             {
468                 grid[2] = (ySize - 1) * 3 + 1;
469             }
470             else if (this->imagetype == MATPLOT_RGBA || this->imagetype == MATPLOT_ARGB)
471             {
472                 grid[2] = (ySize - 1) * 4 + 1;
473             }
474
475             if (type == MATPLOT_RGB)
476             {
477                 if ((grid[2] - 1) % 3 != 0)
478                 {
479                     return 0;
480                 }
481                 grid[2] = (grid[2] - 1) / 3 + 1;
482             }
483             else if (type == MATPLOT_RGBA || type == MATPLOT_ARGB)
484             {
485                 if ((grid[2] - 1) % 4 != 0)
486                 {
487                     return 0;
488                 }
489                 grid[2] = (grid[2] - 1) / 4 + 1;
490             }
491
492             this->setGridSize(grid);
493         }
494
495         this->imagetype = type;
496
497         if (this->scilabData)
498         {
499             setImageData(this->scilabData, (xSize - 1) * (ySize - 1));
500         }
501     }
502
503     return 1;
504 }
505
506 int NgonGridMatplotData::getImageType()
507 {
508     return (int)this->imagetype;
509 }
510
511 int NgonGridMatplotData::getGLType()
512 {
513     return (int)this->gltype;
514 }
515
516 int NgonGridMatplotData::getDataType()
517 {
518     return (int)this->datatype;
519 }
520
521 void NgonGridMatplotData::setDataType(int datatype)
522 {
523     if (this->datatype != (DataType)datatype)
524     {
525         this->datatype = (DataType)datatype;
526         disposeTextureData();
527     }
528 }
529
530 int NgonGridMatplotData::getDataOrder()
531 {
532     return (int)this->dataorder;
533 }
534
535 void NgonGridMatplotData::setDataOrder(int dataorder)
536 {
537     this->dataorder = (DataOrder)dataorder;
538 }
539
540 void * NgonGridMatplotData::getImageData()
541 {
542     if (this->data)
543     {
544         return this->data;
545     }
546     else if (this->scilabData)
547     {
548         setImageData(this->scilabData, (xSize - 1) * (ySize - 1));
549         return this->data;
550     }
551
552     return NULL;
553 }
554
555 void * NgonGridMatplotData::getScilabData()
556 {
557     return this->scilabData;
558 }
559
560 unsigned int NgonGridMatplotData::getImageDataSize()
561 {
562     return this->dataSize;
563 }
564
565 void NgonGridMatplotData::setDataInfos(int infos)
566 {
567     setDataType(infos & 0xFF);
568     setDataOrder((infos & 0xFF00) >> 8);
569     setImageType((infos & 0xFF0000) >> 16);
570 }
571
572 int NgonGridMatplotData::getDataInfos()
573 {
574     return buildMatplotType(this->datatype, this->dataorder, this->imagetype);
575 }
576
577 void NgonGridMatplotData::setImageData(void const* data, const int numElements)
578 {
579     if (!data)
580     {
581         disposeTextureData();
582         return;
583     }
584
585     unsigned int dataSize = 0;
586     const int N = ySize - 1;
587     const int M = xSize - 1;
588     const int NM = N * M;
589
590     if (numElements > NM)
591     {
592         return;
593     }
594
595     if (data != this->scilabData)
596     {
597         if (scilabData)
598         {
599             delete[] (unsigned char *)scilabData;
600             scilabData = NULL;
601         }
602
603         unsigned int _size;
604
605         switch (datatype)
606         {
607             case MATPLOT_HM3_Char :
608             case MATPLOT_HM3_UChar :
609                 _size = numElements * 3;
610                 break;
611             case MATPLOT_HM3_Double :
612                 _size = numElements * sizeof(double) * 3;
613                 break;
614             case MATPLOT_HM4_Char :
615             case MATPLOT_HM4_UChar :
616                 _size = numElements * 4;
617                 break;
618             case MATPLOT_HM4_Double :
619                 _size = numElements * sizeof(double) * 4;
620                 break;
621             case MATPLOT_HM1_Char :
622             case MATPLOT_HM1_UChar :
623             case MATPLOT_Char :
624             case MATPLOT_UChar :
625                 _size = numElements;
626                 break;
627             case MATPLOT_Int :
628             case MATPLOT_UInt :
629                 _size = numElements * sizeof(int);
630                 break;
631             case MATPLOT_Short :
632             case MATPLOT_UShort :
633                 _size = numElements * sizeof(short);
634                 break;
635             case MATPLOT_HM1_Double :
636             case MATPLOT_Double :
637                 _size = numElements * sizeof(double);
638                 break;
639         }
640         this->scilabData = new unsigned char[_size];
641         // todo: on peut ameliorer ca
642         // pr certains type de donnees (et certains modes) scilabData == data
643         // dc on peut eviter cette copie
644         memcpy(this->scilabData, data, _size);
645     }
646
647     void * dest = this->data;
648     if (this->imagetype == MATPLOT_INDEX)
649     {
650         this->gltype = MATPLOT_GL_RGBA_BYTE;
651     }
652     else if (Texture::getImage(data, numElements, this->datatype, this->imagetype, &(this->data), &(this->dataSize), &(this->gltype)))
653     {
654         if (dest)
655         {
656             delete[] (unsigned char *)dest;
657         }
658     }
659
660     //std::cout << this->imagetype << "::" << this->datatype << "::" << this->dataorder << "::" << this->dataSize << "::" << (void*)this->data << std::endl;
661 }
662
663 int NgonGridMatplotData::getType(void)
664 {
665     return type;
666 }
667
668 bool NgonGridMatplotData::initEndian()
669 {
670     const int num = 1;
671
672     return *(char *)&num == 1;
673 }
674
675 void NgonGridMatplotData::setABGRSupported(bool _isABGRSupported)
676 {
677     isABGRSupported = _isABGRSupported;
678 }
679
680 void NgonGridMatplotData::disposeTextureData(void)
681 {
682     if (this->data)
683     {
684         delete[] (unsigned char *)this->data;
685         this->data = NULL;
686         this->dataSize = 0;
687     }
688 }