]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_state_vector.cpp
Initial vogl checkin
[vogl] / src / voglcommon / vogl_state_vector.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 // File: vogl_state_vector.cpp
27 #include "vogl_state_vector.h"
28 #include "vogl_sort.h"
29 #include "gl_pname_defs.inc"
30 #include "vogl_growable_array.h"
31
32 #define VOGL_CONTEXT_STATE_DEBUG 0
33
34 #if VOGL_CONTEXT_STATE_DEBUG
35 #warning VOGL_CONTEXT_STATE_DEBUG enabled
36 #endif
37
38 //----------------------------------------------------------------------------------------------------------------------
39 // vogl_get_state_type_name
40 //----------------------------------------------------------------------------------------------------------------------
41 const char *vogl_get_state_type_name(vogl_state_type s)
42 {
43     VOGL_FUNC_TRACER
44
45     switch (s)
46     {
47         case cSTInvalid:
48             return "invalid";
49         case cSTGLboolean:
50             return "boolean";
51         case cSTGLenum:
52             return "GLenum";
53         case cSTInt32:
54             return "int32";
55         case cSTUInt32:
56             return "uint32";
57         case cSTInt64:
58             return "int64_t";
59         case cSTUInt64:
60             return "uint64_t";
61         case cSTFloat:
62             return "float";
63         case cSTDouble:
64             return "double";
65         case cSTPointer:
66             return "pointer";
67         default:
68             VOGL_ASSERT_ALWAYS;
69             break;
70     }
71     return "?";
72 }
73
74 //----------------------------------------------------------------------------------------------------------------------
75 // vogl_get_state_type_from_name
76 //----------------------------------------------------------------------------------------------------------------------
77 vogl_state_type vogl_get_state_type_from_name(const char *pName)
78 {
79     VOGL_FUNC_TRACER
80
81     if (vogl_strcmp(pName, "invalid") == 0)
82         return cSTInvalid;
83     else if (vogl_strcmp(pName, "boolean") == 0)
84         return cSTGLboolean;
85     else if (vogl_strcmp(pName, "GLenum") == 0)
86         return cSTGLenum;
87     else if (vogl_strcmp(pName, "int32") == 0)
88         return cSTInt32;
89     else if (vogl_strcmp(pName, "uint32") == 0)
90         return cSTUInt32;
91     else if (vogl_strcmp(pName, "int64_t") == 0)
92         return cSTInt64;
93     else if (vogl_strcmp(pName, "uint64_t") == 0)
94         return cSTUInt64;
95     else if (vogl_strcmp(pName, "float") == 0)
96         return cSTFloat;
97     else if (vogl_strcmp(pName, "double") == 0)
98         return cSTDouble;
99     else if (vogl_strcmp(pName, "pointer") == 0)
100         return cSTPointer;
101
102     return cSTInvalid;
103 }
104
105 //----------------------------------------------------------------------------------------------------------------------
106 // vogl_get_state_type_size
107 //----------------------------------------------------------------------------------------------------------------------
108 uint vogl_get_state_type_size(vogl_state_type s)
109 {
110     VOGL_FUNC_TRACER
111
112     switch (s)
113     {
114         case cSTInvalid:
115             return 0;
116         case cSTGLboolean:
117             return sizeof(GLboolean);
118         case cSTGLenum:
119             return sizeof(GLenum);
120         case cSTInt32:
121             return sizeof(int32);
122         case cSTUInt32:
123             return sizeof(uint32);
124         case cSTInt64:
125             return sizeof(int64_t);
126         case cSTUInt64:
127             return sizeof(uint64_t);
128         case cSTFloat:
129             return sizeof(float);
130         case cSTDouble:
131             return sizeof(double);
132         case cSTPointer:
133             return sizeof(uint64_t);
134         default:
135             VOGL_ASSERT_ALWAYS;
136             return 0;
137     }
138 }
139
140 //----------------------------------------------------------------------------------------------------------------------
141 // vogl_state_data::vogl_state_data
142 //----------------------------------------------------------------------------------------------------------------------
143 vogl_state_data::vogl_state_data()
144     : m_id(0, 0, false),
145       m_data_type(cSTInvalid),
146       m_num_elements(0)
147 {
148     VOGL_FUNC_TRACER
149 }
150
151 //----------------------------------------------------------------------------------------------------------------------
152 // vogl_state_data::vogl_state_data
153 //----------------------------------------------------------------------------------------------------------------------
154 vogl_state_data::vogl_state_data(GLenum enum_val, uint index, uint n, vogl_state_type data_type, bool indexed_variant)
155     : m_id(enum_val, index, indexed_variant),
156       m_data_type(data_type),
157       m_num_elements(n),
158       m_data(n * vogl_get_state_type_size(data_type))
159 {
160     VOGL_FUNC_TRACER
161 }
162
163 //----------------------------------------------------------------------------------------------------------------------
164 // vogl_state_data::vogl_state_data
165 //----------------------------------------------------------------------------------------------------------------------
166 vogl_state_data::vogl_state_data(GLenum enum_val, uint index, const void *pData, uint element_size, bool indexed_variant)
167     : m_id(0, 0, false),
168       m_data_type(cSTInvalid),
169       m_num_elements(0)
170 {
171     VOGL_FUNC_TRACER
172
173     init(enum_val, index, pData, element_size, indexed_variant);
174 }
175
176 //----------------------------------------------------------------------------------------------------------------------
177 // vogl_state_data::init
178 //----------------------------------------------------------------------------------------------------------------------
179 void vogl_state_data::init(GLenum enum_val, uint index, uint n, vogl_state_type data_type, bool indexed_variant)
180 {
181     VOGL_FUNC_TRACER
182
183     m_id.set(enum_val, index, indexed_variant);
184     m_data_type = data_type;
185     m_num_elements = n;
186
187     uint data_type_size = vogl_get_state_type_size(data_type);
188
189 #if VOGL_CONTEXT_STATE_DEBUG
190     m_data.resize((n + 1) * data_type_size);
191     memset(m_data.get_ptr() + (n * data_type_size), 0xCF, data_type_size);
192 #else
193     m_data.resize(n * data_type_size);
194 #endif
195 }
196
197 //----------------------------------------------------------------------------------------------------------------------
198 // vogl_state_data::init
199 //----------------------------------------------------------------------------------------------------------------------
200 bool vogl_state_data::init(GLenum enum_val, uint index, const void *pData, uint element_size, bool indexed_variant)
201 {
202     VOGL_FUNC_TRACER
203
204     const char *pName = g_gl_enums.find_name(enum_val);
205
206     int pname_def_index = g_gl_enums.find_pname_def_index(enum_val);
207     if (pname_def_index < 0)
208     {
209         vogl_warning_printf("%s: Unable to find pname def for GL enum %s\n", VOGL_METHOD_NAME, pName);
210         return false;
211     }
212
213     const gl_pname_def_t &pname_def = g_gl_pname_defs[pname_def_index];
214
215     VOGL_ASSERT(pname_def.m_gl_enum == enum_val);
216
217     vogl_state_type state_type = static_cast<vogl_state_type>(pname_def.m_type);
218
219     if (state_type == cSTInvalid)
220     {
221         VOGL_ASSERT_ALWAYS;
222         vogl_warning_printf("%s: Can't determine type of GL enum %s\n", VOGL_METHOD_NAME, pName);
223         return false;
224     }
225
226     uint n = g_gl_enums.get_pname_count(enum_val);
227     if (!n)
228     {
229         VOGL_ASSERT_ALWAYS;
230         return false;
231     }
232
233     uint state_type_size = vogl_get_state_type_size(state_type);
234     VOGL_ASSERT(state_type_size);
235
236     init(enum_val, index, n, state_type, indexed_variant);
237
238     void *pDst = m_data.get_ptr();
239     if (state_type != cSTPointer)
240     {
241         if (element_size == state_type_size)
242             memcpy(pDst, pData, state_type_size * n);
243         else if ((state_type == cSTGLboolean) && (element_size == sizeof(GLint)))
244         {
245             for (uint i = 0; i < n; i++)
246                 static_cast<GLboolean *>(pDst)[i] = static_cast<const GLint *>(pData)[i];
247         }
248         else
249         {
250             VOGL_VERIFY(!"element_size is invalid");
251         }
252     }
253     else
254     {
255         VOGL_VERIFY(element_size == sizeof(void *));
256
257         // Convert from native 32/64 ptrs to 64-bit values
258         const void *const *pSrc_ptrs = static_cast<const void *const *>(pData);
259         uint64_t *pDst_u64 = static_cast<uint64_t *>(pDst);
260         for (uint i = 0; i < n; i++)
261             pDst_u64[i] = reinterpret_cast<uint64_t>(pSrc_ptrs[i]);
262     }
263
264     return true;
265 }
266
267 //----------------------------------------------------------------------------------------------------------------------
268 // vogl_state_data::debug_check
269 //----------------------------------------------------------------------------------------------------------------------
270 void vogl_state_data::debug_check()
271 {
272     VOGL_FUNC_TRACER
273
274 #if VOGL_CONTEXT_STATE_DEBUG
275     if (m_data.size())
276     {
277         const uint data_type_size = get_data_type_size();
278         VOGL_ASSERT((data_type_size) && ((m_data.size() / data_type_size) == (m_num_elements + 1)));
279         const uint8 *p = get_data_ptr<const uint8>() + m_num_elements * data_type_size;
280         (void)p;
281         for (uint i = 0; i < data_type_size; i++)
282             VOGL_ASSERT(p[i] == 0xCF);
283     }
284 #endif
285 }
286
287 //----------------------------------------------------------------------------------------------------------------------
288 // vogl_state_data::swap
289 //----------------------------------------------------------------------------------------------------------------------
290 void vogl_state_data::swap(vogl_state_data &other)
291 {
292     VOGL_FUNC_TRACER
293
294     std::swap(m_id, other.m_id);
295     std::swap(m_data_type, other.m_data_type);
296     std::swap(m_num_elements, other.m_num_elements);
297     m_data.swap(other.m_data);
298 }
299
300 //----------------------------------------------------------------------------------------------------------------------
301 // vogl_state_data::is_equal
302 //----------------------------------------------------------------------------------------------------------------------
303 bool vogl_state_data::is_equal(const vogl_state_data &rhs) const
304 {
305     VOGL_FUNC_TRACER
306
307     if (m_id != rhs.m_id)
308         return false;
309     if (m_data_type != rhs.m_data_type)
310         return false;
311     if (m_num_elements != rhs.m_num_elements)
312         return false;
313
314     uint total_size = get_data_type_size() * m_num_elements;
315     if ((m_data.size() < total_size) || (rhs.m_data.size() < total_size))
316     {
317         VOGL_ASSERT_ALWAYS;
318         return false;
319     }
320
321     if (memcmp(m_data.get_ptr(), rhs.m_data.get_ptr(), total_size) != 0)
322         return false;
323
324     return true;
325 }
326
327 //----------------------------------------------------------------------------------------------------------------------
328 // vogl_state_data::get_bool
329 //----------------------------------------------------------------------------------------------------------------------
330 void vogl_state_data::get_bool(bool *pVals) const
331 {
332     VOGL_FUNC_TRACER
333
334     switch (m_data_type)
335     {
336         case cSTGLboolean:
337         {
338             for (uint i = 0; i < m_num_elements; i++)
339                 pVals[i] = get_element<GLboolean>(i);
340             break;
341         }
342         case cSTGLenum:
343         {
344             for (uint i = 0; i < m_num_elements; i++)
345                 pVals[i] = get_element<GLenum>(i) != 0;
346             break;
347         }
348         case cSTInt32:
349         {
350             for (uint i = 0; i < m_num_elements; i++)
351                 pVals[i] = get_element<int32>(i) != 0;
352             break;
353         }
354         case cSTUInt32:
355         {
356             for (uint i = 0; i < m_num_elements; i++)
357                 pVals[i] = get_element<uint32>(i) != 0;
358             break;
359         }
360         case cSTInt64:
361         {
362             for (uint i = 0; i < m_num_elements; i++)
363                 pVals[i] = get_element<int64_t>(i) != 0;
364             break;
365         }
366         case cSTUInt64:
367         {
368             for (uint i = 0; i < m_num_elements; i++)
369                 pVals[i] = get_element<uint64_t>(i) != 0;
370             break;
371         }
372         case cSTFloat:
373         {
374             for (uint i = 0; i < m_num_elements; i++)
375                 pVals[i] = get_element<float>(i) != 0.0f;
376             break;
377         }
378         case cSTDouble:
379         {
380             for (uint i = 0; i < m_num_elements; i++)
381                 pVals[i] = get_element<double>(i) != 0.0f;
382             break;
383         }
384         case cSTPointer:
385         {
386             for (uint i = 0; i < m_num_elements; i++)
387                 pVals[i] = get_element<GLuint64>(i) != 0;
388             break;
389         }
390         case cSTInvalid:
391         case cTotalStateTypes:
392         {
393             VOGL_ASSERT_ALWAYS;
394             break;
395         }
396         default:
397         {
398             VOGL_ASSERT_ALWAYS;
399             break;
400         }
401     }
402 }
403
404 //----------------------------------------------------------------------------------------------------------------------
405 // vogl_state_data::get_uint64
406 // OK, GL itself is not type safe, unsigned vs. signed are mixed everywhere. And the pname table marks a ton of unsigned stuff as signed ints.
407 // So none of these methods clamp or do anything fancy on ints - I assume you know what you're doing.
408 //----------------------------------------------------------------------------------------------------------------------
409 void vogl_state_data::get_uint64(uint64_t *pVals) const
410 {
411     VOGL_FUNC_TRACER
412
413     switch (m_data_type)
414     {
415         case cSTGLboolean:
416         {
417             for (uint i = 0; i < m_num_elements; i++)
418                 pVals[i] = get_element<GLboolean>(i);
419             break;
420         }
421         case cSTGLenum:
422         {
423             for (uint i = 0; i < m_num_elements; i++)
424                 pVals[i] = get_element<GLenum>(i);
425             break;
426         }
427         case cSTInt32:
428         {
429             for (uint i = 0; i < m_num_elements; i++)
430                 pVals[i] = static_cast<int64_t>(get_element<int32>(i));
431             break;
432         }
433         case cSTUInt32:
434         {
435             for (uint i = 0; i < m_num_elements; i++)
436                 pVals[i] = get_element<uint32>(i);
437             break;
438         }
439         case cSTInt64:
440         {
441             for (uint i = 0; i < m_num_elements; i++)
442                 pVals[i] = get_element<int64_t>(i);
443             break;
444         }
445         case cSTPointer:
446         case cSTUInt64:
447         {
448             for (uint i = 0; i < m_num_elements; i++)
449                 pVals[i] = get_element<uint64_t>(i);
450             break;
451         }
452         case cSTFloat:
453         {
454             for (uint i = 0; i < m_num_elements; i++)
455             {
456                 double v = get_element<float>(i);
457                 v = trunc((v < 0.0f) ? (v - .5f) : (v + .5f));
458                 v = math::clamp<double>(v, static_cast<double>(cINT64_MIN), static_cast<double>(cUINT64_MAX));
459                 if (v < 0)
460                     pVals[i] = static_cast<int64_t>(v);
461                 else
462                     pVals[i] = static_cast<uint64_t>(v);
463             }
464             break;
465         }
466         case cSTDouble:
467         {
468             for (uint i = 0; i < m_num_elements; i++)
469             {
470                 double v = get_element<double>(i);
471                 v = trunc((v < 0.0f) ? (v - .5f) : (v + .5f));
472                 v = math::clamp<double>(v, static_cast<double>(cINT64_MIN), static_cast<double>(cUINT64_MAX));
473                 if (v < 0)
474                     pVals[i] = static_cast<int64_t>(v);
475                 else
476                     pVals[i] = static_cast<uint64_t>(v);
477             }
478             break;
479         }
480         case cSTInvalid:
481         case cTotalStateTypes:
482         {
483             VOGL_ASSERT_ALWAYS;
484             break;
485         }
486         default:
487         {
488             VOGL_ASSERT_ALWAYS;
489             break;
490         }
491     }
492 }
493
494 //----------------------------------------------------------------------------------------------------------------------
495 // vogl_state_data::get_uint
496 //----------------------------------------------------------------------------------------------------------------------
497 void vogl_state_data::get_uint(uint *pVals) const
498 {
499     VOGL_FUNC_TRACER
500
501     switch (m_data_type)
502     {
503         case cSTGLboolean:
504         {
505             for (uint i = 0; i < m_num_elements; i++)
506                 pVals[i] = get_element<GLboolean>(i);
507             break;
508         }
509         case cSTGLenum:
510         {
511             for (uint i = 0; i < m_num_elements; i++)
512                 pVals[i] = get_element<GLenum>(i);
513             break;
514         }
515         case cSTInt32:
516         {
517             for (uint i = 0; i < m_num_elements; i++)
518                 pVals[i] = get_element<int32>(i);
519             break;
520         }
521         case cSTUInt32:
522         {
523             for (uint i = 0; i < m_num_elements; i++)
524                 pVals[i] = get_element<uint32>(i);
525             break;
526         }
527         case cSTInt64:
528         {
529             for (uint i = 0; i < m_num_elements; i++)
530                 pVals[i] = static_cast<uint>(get_element<int64_t>(i));
531             break;
532         }
533         case cSTPointer:
534         case cSTUInt64:
535         {
536             for (uint i = 0; i < m_num_elements; i++)
537                 pVals[i] = static_cast<uint>(get_element<uint64_t>(i));
538             break;
539         }
540         case cSTFloat:
541         {
542             for (uint i = 0; i < m_num_elements; i++)
543             {
544                 double v = get_element<float>(i);
545                 v = trunc((v < 0.0f) ? (v - .5f) : (v + .5f));
546                 v = math::clamp<double>(v, static_cast<double>(cINT32_MIN), static_cast<double>(cUINT32_MAX));
547                 if (v < 0)
548                     pVals[i] = static_cast<int32>(v);
549                 else
550                     pVals[i] = static_cast<uint32>(v);
551             }
552             break;
553         }
554         case cSTDouble:
555         {
556             for (uint i = 0; i < m_num_elements; i++)
557             {
558                 double v = get_element<double>(i);
559                 v = trunc((v < 0.0f) ? (v - .5f) : (v + .5f));
560                 v = math::clamp<double>(v, static_cast<double>(cINT32_MIN), static_cast<double>(cUINT32_MAX));
561                 if (v < 0)
562                     pVals[i] = static_cast<int32>(v);
563                 else
564                     pVals[i] = static_cast<uint32>(v);
565             }
566             break;
567         }
568         case cSTInvalid:
569         case cTotalStateTypes:
570         {
571             VOGL_ASSERT_ALWAYS;
572             break;
573         }
574         default:
575         {
576             VOGL_ASSERT_ALWAYS;
577             break;
578         }
579     }
580 }
581
582 //----------------------------------------------------------------------------------------------------------------------
583 // vogl_state_data::get_int64
584 //----------------------------------------------------------------------------------------------------------------------
585 void vogl_state_data::get_int64(int64_t *pVals) const
586 {
587     VOGL_FUNC_TRACER
588
589     switch (m_data_type)
590     {
591         case cSTGLboolean:
592         {
593             for (uint i = 0; i < m_num_elements; i++)
594                 pVals[i] = get_element<GLboolean>(i);
595             break;
596         }
597         case cSTGLenum:
598         {
599             for (uint i = 0; i < m_num_elements; i++)
600                 pVals[i] = get_element<GLenum>(i);
601             break;
602         }
603         case cSTInt32:
604         {
605             for (uint i = 0; i < m_num_elements; i++)
606                 pVals[i] = get_element<int32>(i);
607             break;
608         }
609         case cSTUInt32:
610         {
611             for (uint i = 0; i < m_num_elements; i++)
612                 pVals[i] = get_element<uint32>(i);
613             break;
614         }
615         case cSTInt64:
616         {
617             for (uint i = 0; i < m_num_elements; i++)
618                 pVals[i] = get_element<int64_t>(i);
619             break;
620         }
621         case cSTPointer:
622         case cSTUInt64:
623         {
624             for (uint i = 0; i < m_num_elements; i++)
625                 pVals[i] = get_element<uint64_t>(i);
626             break;
627         }
628         case cSTFloat:
629         {
630             for (uint i = 0; i < m_num_elements; i++)
631             {
632                 double v = get_element<float>(i);
633                 v = trunc((v < 0.0f) ? (v - .5f) : (v + .5f));
634                 v = math::clamp<double>(v, static_cast<double>(cINT64_MIN), static_cast<double>(cUINT64_MAX));
635                 if (v > cINT64_MAX)
636                     pVals[i] = static_cast<uint64_t>(v);
637                 else
638                     pVals[i] = static_cast<int64_t>(v);
639             }
640             break;
641         }
642         case cSTDouble:
643         {
644             for (uint i = 0; i < m_num_elements; i++)
645             {
646                 double v = get_element<double>(i);
647                 v = trunc((v < 0.0f) ? (v - .5f) : (v + .5f));
648                 v = math::clamp<double>(v, static_cast<double>(cINT64_MIN), static_cast<double>(cUINT64_MAX));
649                 if (v > cINT64_MAX)
650                     pVals[i] = static_cast<uint64_t>(v);
651                 else
652                     pVals[i] = static_cast<int64_t>(v);
653             }
654             break;
655         }
656         case cSTInvalid:
657         case cTotalStateTypes:
658         {
659             VOGL_ASSERT_ALWAYS;
660             break;
661         }
662         default:
663         {
664             VOGL_ASSERT_ALWAYS;
665             break;
666         }
667     }
668 }
669
670 //----------------------------------------------------------------------------------------------------------------------
671 // vogl_state_data::get_int
672 //----------------------------------------------------------------------------------------------------------------------
673 void vogl_state_data::get_int(int *pVals) const
674 {
675     VOGL_FUNC_TRACER
676
677     switch (m_data_type)
678     {
679         case cSTGLboolean:
680         {
681             for (uint i = 0; i < m_num_elements; i++)
682                 pVals[i] = get_element<GLboolean>(i);
683             break;
684         }
685         case cSTGLenum:
686         {
687             for (uint i = 0; i < m_num_elements; i++)
688                 pVals[i] = get_element<GLenum>(i);
689             break;
690         }
691         case cSTInt32:
692         {
693             for (uint i = 0; i < m_num_elements; i++)
694                 pVals[i] = get_element<int32>(i);
695             break;
696         }
697         case cSTUInt32:
698         {
699             for (uint i = 0; i < m_num_elements; i++)
700                 pVals[i] = get_element<uint32>(i);
701             break;
702         }
703         case cSTInt64:
704         {
705             for (uint i = 0; i < m_num_elements; i++)
706                 pVals[i] = static_cast<int>(get_element<int64_t>(i));
707             break;
708         }
709         case cSTPointer:
710         case cSTUInt64:
711         {
712             for (uint i = 0; i < m_num_elements; i++)
713                 pVals[i] = static_cast<int>(get_element<uint64_t>(i));
714             break;
715         }
716         case cSTFloat:
717         {
718             for (uint i = 0; i < m_num_elements; i++)
719             {
720                 double v = get_element<float>(i);
721                 v = trunc((v < 0.0f) ? (v - .5f) : (v + .5f));
722                 v = math::clamp<double>(v, static_cast<double>(cINT32_MIN), static_cast<double>(cUINT32_MAX));
723                 if (v > cINT32_MAX)
724                     pVals[i] = static_cast<uint32>(v);
725                 else
726                     pVals[i] = static_cast<int32>(v);
727             }
728             break;
729         }
730         case cSTDouble:
731         {
732             for (uint i = 0; i < m_num_elements; i++)
733             {
734                 double v = get_element<double>(i);
735                 v = trunc((v < 0.0f) ? (v - .5f) : (v + .5f));
736                 v = math::clamp<double>(v, static_cast<double>(cINT32_MIN), static_cast<double>(cUINT32_MAX));
737                 if (v > cINT32_MAX)
738                     pVals[i] = static_cast<uint32>(v);
739                 else
740                     pVals[i] = static_cast<int32>(v);
741             }
742             break;
743         }
744         case cSTInvalid:
745         case cTotalStateTypes:
746         {
747             VOGL_ASSERT_ALWAYS;
748             break;
749         }
750         default:
751         {
752             VOGL_ASSERT_ALWAYS;
753             break;
754         }
755     }
756 }
757
758 //----------------------------------------------------------------------------------------------------------------------
759 // vogl_state_data::get_pointer
760 //----------------------------------------------------------------------------------------------------------------------
761 void vogl_state_data::get_pointer(void **ppVals) const
762 {
763     VOGL_FUNC_TRACER
764
765     vogl::growable_array<uint64_t, 16> temp(m_num_elements);
766
767     get_uint64(temp.get_ptr());
768
769     for (uint i = 0; i < m_num_elements; i++)
770     {
771         uint64_t v = temp[i];
772         ppVals[i] = *reinterpret_cast<void **>(&v);
773     }
774 }
775
776 //----------------------------------------------------------------------------------------------------------------------
777 // vogl_state_data::get_double
778 //----------------------------------------------------------------------------------------------------------------------
779 void vogl_state_data::get_double(double *pVals) const
780 {
781     VOGL_FUNC_TRACER
782
783     switch (m_data_type)
784     {
785         case cSTGLboolean:
786         {
787             for (uint i = 0; i < m_num_elements; i++)
788                 pVals[i] = static_cast<double>(get_element<GLboolean>(i));
789             break;
790         }
791         case cSTGLenum:
792         {
793             for (uint i = 0; i < m_num_elements; i++)
794                 pVals[i] = static_cast<double>(get_element<GLenum>(i));
795             break;
796         }
797         case cSTInt32:
798         {
799             for (uint i = 0; i < m_num_elements; i++)
800                 pVals[i] = static_cast<double>(get_element<int32>(i));
801             break;
802         }
803         case cSTUInt32:
804         {
805             for (uint i = 0; i < m_num_elements; i++)
806                 pVals[i] = static_cast<double>(get_element<uint32>(i));
807             break;
808         }
809         case cSTInt64:
810         {
811             for (uint i = 0; i < m_num_elements; i++)
812                 pVals[i] = static_cast<double>(get_element<int64_t>(i));
813             break;
814         }
815         case cSTPointer:
816         case cSTUInt64:
817         {
818             for (uint i = 0; i < m_num_elements; i++)
819                 pVals[i] = static_cast<double>(get_element<uint64_t>(i));
820             break;
821         }
822         case cSTFloat:
823         {
824             for (uint i = 0; i < m_num_elements; i++)
825                 pVals[i] = static_cast<double>(get_element<float>(i));
826             break;
827         }
828         case cSTDouble:
829         {
830             for (uint i = 0; i < m_num_elements; i++)
831                 pVals[i] = get_element<double>(i);
832             break;
833         }
834         case cSTInvalid:
835         case cTotalStateTypes:
836             break;
837         default:
838         {
839             VOGL_ASSERT_ALWAYS;
840             break;
841         }
842     }
843 }
844
845 //----------------------------------------------------------------------------------------------------------------------
846 // vogl_state_data::get_float
847 //----------------------------------------------------------------------------------------------------------------------
848 void vogl_state_data::get_float(float *pVals) const
849 {
850     VOGL_FUNC_TRACER
851
852     vogl::growable_array<double, 16> temp(m_num_elements);
853
854     get_double(temp.get_ptr());
855
856     for (uint i = 0; i < m_num_elements; i++)
857         pVals[i] = static_cast<float>(temp[i]);
858 }
859
860 //----------------------------------------------------------------------------------------------------------------------
861 // vogl_state_data::serialize
862 //----------------------------------------------------------------------------------------------------------------------
863 bool vogl_state_data::serialize(json_node &node) const
864 {
865     VOGL_FUNC_TRACER
866
867     const char *pEnum_name = g_gl_enums.find_name(m_id.m_enum_val);
868     dynamic_string enum_name;
869     if (pEnum_name)
870         enum_name.set(pEnum_name);
871     else
872         enum_name.format("0x%X", m_id.m_enum_val);
873
874     node.add_key_value("enum", enum_name.get_ptr());
875     node.add_key_value("index", m_id.m_index);
876     node.add_key_value("indexed_variant", m_id.m_indexed_variant);
877
878     node.add_key_value("data_type", vogl_get_state_type_name(m_data_type));
879     json_node &values_node = node.add_array("values");
880
881     // >=, not ==, in case of VOGL_CONTEXT_STATE_DEBUG
882     VOGL_ASSERT(m_data.size_in_bytes() >= m_num_elements * get_data_type_size());
883
884     for (uint i = 0; i < m_num_elements; i++)
885     {
886         const void *pElement = m_data.get_ptr() + i * get_data_type_size();
887
888         switch (m_data_type)
889         {
890             case cSTGLboolean:
891             {
892                 const GLboolean *pVal = reinterpret_cast<const GLboolean *>(pElement);
893                 values_node.add_value(*pVal ? true : false);
894                 break;
895             }
896             case cSTGLenum:
897             {
898                 const GLenum *pVal = reinterpret_cast<const GLenum *>(pElement);
899
900                 const char *pValue_enum_name = g_gl_enums.find_name(*pVal);
901                 dynamic_string value_enum_name;
902                 if (pValue_enum_name)
903                     value_enum_name.set(pValue_enum_name);
904                 else
905                     value_enum_name.format("0x%X", *pVal);
906
907                 values_node.add_value(value_enum_name);
908                 break;
909             }
910             case cSTInt32:
911             {
912                 const int32 *pVal = reinterpret_cast<const int32 *>(pElement);
913                 values_node.add_value(*pVal);
914                 break;
915             }
916             case cSTUInt32:
917             {
918                 const uint32 *pVal = reinterpret_cast<const uint32 *>(pElement);
919                 values_node.add_value(*pVal);
920                 break;
921             }
922             case cSTInt64:
923             {
924                 const int64_t *pVal = reinterpret_cast<const int64_t *>(pElement);
925                 values_node.add_value(*pVal);
926                 break;
927             }
928             case cSTFloat:
929             {
930                 const float *pVal = reinterpret_cast<const float *>(pElement);
931                 values_node.add_value(*pVal);
932                 break;
933             }
934             case cSTDouble:
935             {
936                 const double *pVal = reinterpret_cast<const double *>(pElement);
937                 values_node.add_value(*pVal);
938                 break;
939             }
940             case cSTPointer:
941             case cSTUInt64:
942             {
943                 char buf[256];
944                 vogl_sprintf_s(buf, sizeof(buf), "0x%" PRIX64, *reinterpret_cast<const uint64_t *>(pElement));
945                 values_node.add_value(buf);
946                 break;
947             }
948             default:
949             {
950                 VOGL_ASSERT_ALWAYS;
951                 values_node.add_value(0);
952                 break;
953             }
954         }
955     }
956
957     return true;
958 }
959
960 //----------------------------------------------------------------------------------------------------------------------
961 // vogl_state_data::deserialize
962 //----------------------------------------------------------------------------------------------------------------------
963 bool vogl_state_data::deserialize(const json_node &node)
964 {
965     VOGL_FUNC_TRACER
966
967     dynamic_string key_str(node.value_as_string("enum"));
968
969     uint64_t gl_enum = 0;
970     if (key_str.begins_with("0x"))
971         gl_enum = string_to_uint64(key_str.get_ptr(), gl_enums::cUnknownEnum);
972     else
973         gl_enum = g_gl_enums.find_enum(key_str.get_ptr());
974
975     if ((gl_enum == gl_enums::cUnknownEnum) || (gl_enum > cUINT32_MAX))
976     {
977         vogl_warning_printf("%s: Unknown/invalid GL enum \"%s\"\n", VOGL_METHOD_NAME, key_str.get_ptr());
978         return false;
979     }
980
981     int index = node.value_as_int("index", -1);
982     if (index < 0)
983     {
984         vogl_warning_printf("%s: Expected index for GL enum \"%s\"\n", VOGL_METHOD_NAME, key_str.get_ptr());
985         return false;
986     }
987
988     bool indexed_variant = node.value_as_bool("indexed_variant", false);
989
990     dynamic_string state_type_str(node.value_as_string("data_type"));
991
992     vogl_state_type state_type = vogl_get_state_type_from_name(state_type_str.get_ptr());
993     if (state_type == cSTInvalid)
994     {
995         vogl_warning_printf("%s: Unknown state_type for GL enum \"%s\"\n", VOGL_METHOD_NAME, key_str.get_ptr());
996         return false;
997     }
998
999     const json_node *pValues_array = node.find_child_array("values");
1000     if (!pValues_array)
1001     {
1002         vogl_warning_printf("%s: Can't find values array for GL enum \"%s\"\n", VOGL_METHOD_NAME, key_str.get_ptr());
1003         return false;
1004     }
1005
1006     uint num_elements = pValues_array->size();
1007     uint state_type_size = vogl_get_state_type_size(state_type);
1008
1009     vogl_state_data state;
1010     init(static_cast<GLenum>(gl_enum), index, num_elements, state_type, indexed_variant);
1011
1012     for (uint element_index = 0; element_index < num_elements; element_index++)
1013     {
1014         void *pElement = m_data.get_ptr() + element_index * state_type_size;
1015
1016         switch (state_type)
1017         {
1018             case cSTGLboolean:
1019             {
1020                 GLboolean *pVal = reinterpret_cast<GLboolean *>(pElement);
1021                 *pVal = pValues_array->value_as_bool(element_index);
1022                 break;
1023             }
1024             case cSTGLenum:
1025             {
1026                 const char *pStr = pValues_array->value_as_string_ptr(element_index);
1027                 if (!pStr)
1028                 {
1029                     vogl_warning_printf("%s: Failed converting value %u of GL enum \"%s\"\n", VOGL_METHOD_NAME, element_index, key_str.get_ptr());
1030                     return false;
1031                 }
1032
1033                 uint64_t gl_enum = 0;
1034                 if ((pStr[0] == '0') && (pStr[1] == 'x'))
1035                     gl_enum = string_to_uint64(pStr, gl_enums::cUnknownEnum);
1036                 else
1037                     gl_enum = g_gl_enums.find_enum(dynamic_string(pStr));
1038
1039                 if ((gl_enum == gl_enums::cUnknownEnum) || (gl_enum > cUINT32_MAX))
1040                 {
1041                     vogl_error_printf("%s: Unknown/invalid GL enum \"%s\"\n", VOGL_METHOD_NAME, pStr);
1042                     return false;
1043                 }
1044
1045                 GLenum *pVal = reinterpret_cast<GLenum *>(pElement);
1046                 *pVal = static_cast<GLenum>(gl_enum);
1047
1048                 break;
1049             }
1050             case cSTInt32:
1051             {
1052                 int32 *pVal = reinterpret_cast<int32 *>(pElement);
1053                 *pVal = pValues_array->value_as_int(element_index);
1054                 break;
1055             }
1056             case cSTUInt32:
1057             {
1058                 uint32 *pVal = reinterpret_cast<uint32 *>(pElement);
1059
1060                 int64_t v = pValues_array->value_as_int64(element_index);
1061                 *pVal = static_cast<uint32>(math::clamp<int64_t>(v, 0, cUINT32_MAX));
1062
1063                 break;
1064             }
1065             case cSTInt64:
1066             {
1067                 int64_t *pVal = reinterpret_cast<int64_t *>(pElement);
1068                 *pVal = pValues_array->value_as_int64(element_index);
1069                 break;
1070             }
1071             case cSTFloat:
1072             {
1073                 float *pVal = reinterpret_cast<float *>(pElement);
1074                 *pVal = pValues_array->value_as_float(element_index);
1075                 break;
1076             }
1077             case cSTDouble:
1078             {
1079                 double *pVal = reinterpret_cast<double *>(pElement);
1080                 *pVal = pValues_array->value_as_double(element_index);
1081                 break;
1082             }
1083             case cSTPointer:
1084             case cSTUInt64:
1085             {
1086                 const char *pStr = pValues_array->value_as_string_ptr(element_index);
1087                 if (!pStr)
1088                 {
1089                     vogl_warning_printf("%s: Failed converting value %u of GL enum \"%s\"\n", VOGL_METHOD_NAME, element_index, key_str.get_ptr());
1090                     return false;
1091                 }
1092
1093                 uint64_t *pVal = reinterpret_cast<uint64_t *>(pElement);
1094
1095                 uint64_t val = 0;
1096                 const char *pBuf = pStr;
1097                 string_ptr_to_uint64(pBuf, val);
1098                 *pVal = val;
1099
1100                 break;
1101             }
1102             default:
1103             {
1104                 VOGL_ASSERT_ALWAYS;
1105                 break;
1106             }
1107         }
1108     }
1109
1110     debug_check();
1111
1112     return true;
1113 }
1114
1115 //----------------------------------------------------------------------------------------------------------------------
1116 // vogl_state_vector::vogl_state_vector
1117 //----------------------------------------------------------------------------------------------------------------------
1118 vogl_state_vector::vogl_state_vector()
1119 {
1120     VOGL_FUNC_TRACER
1121 }
1122
1123 //----------------------------------------------------------------------------------------------------------------------
1124 // vogl_state_vector::clear
1125 //----------------------------------------------------------------------------------------------------------------------
1126 void vogl_state_vector::clear()
1127 {
1128     VOGL_FUNC_TRACER
1129
1130     m_states.clear();
1131 }
1132
1133 //----------------------------------------------------------------------------------------------------------------------
1134 // vogl_state_vector::find
1135 //----------------------------------------------------------------------------------------------------------------------
1136 const vogl_state_data *vogl_state_vector::find(GLenum enum_val, uint index, bool indexed_variant) const
1137 {
1138     VOGL_FUNC_TRACER
1139
1140     return m_states.find_value(vogl_state_id(enum_val, index, indexed_variant));
1141 }
1142
1143 //----------------------------------------------------------------------------------------------------------------------
1144 // vogl_state_vector::serialize
1145 //----------------------------------------------------------------------------------------------------------------------
1146 bool vogl_state_vector::serialize(json_node &node, vogl_blob_manager &blob_manager) const
1147 {
1148     VOGL_FUNC_TRACER
1149
1150     VOGL_NOTE_UNUSED(blob_manager);
1151
1152     json_node &node_array = node.add_array("states");
1153
1154     for (state_map::const_iterator it = m_states.begin(); it != m_states.end(); ++it)
1155     {
1156         const vogl_state_data &data = it->second;
1157
1158         if (!data.serialize(node_array.add_object()))
1159             return false;
1160     }
1161
1162     return true;
1163 }
1164
1165 //----------------------------------------------------------------------------------------------------------------------
1166 // vogl_state_vector::deserialize
1167 //----------------------------------------------------------------------------------------------------------------------
1168 bool vogl_state_vector::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
1169 {
1170     VOGL_FUNC_TRACER
1171
1172     VOGL_NOTE_UNUSED(blob_manager);
1173
1174     clear();
1175
1176     const json_node *pNode_array = node.find_child_array("states");
1177     if (!pNode_array)
1178         return false;
1179
1180     for (uint value_index = 0; value_index < pNode_array->size(); value_index++)
1181     {
1182         const json_node *pState_node = pNode_array->get_child(value_index);
1183         if (!pState_node)
1184             return false;
1185
1186         vogl_state_data state;
1187         if (!state.deserialize(*pState_node))
1188             continue;
1189
1190         if (!insert(state))
1191         {
1192             vogl_warning_printf("%s: vogl_state_vector::deserialize: Ignoring duplicate state 0x%X index %u\n", VOGL_METHOD_NAME, state.get_enum_val(), state.get_index());
1193         }
1194     }
1195
1196     return true;
1197 }
1198
1199 //----------------------------------------------------------------------------------------------------------------------
1200 // vogl_state_vector::deserialize
1201 //----------------------------------------------------------------------------------------------------------------------
1202 bool vogl_state_vector::deserialize(const char *pChild_name, const json_node &parent_node, const vogl_blob_manager &blob_manager)
1203 {
1204     VOGL_FUNC_TRACER
1205
1206     clear();
1207
1208     const json_node *pChild_node = parent_node.find_child_object(pChild_name);
1209     if (!pChild_node)
1210         return false;
1211
1212     return deserialize(*pChild_node, blob_manager);
1213 }
1214
1215 //----------------------------------------------------------------------------------------------------------------------
1216 // vogl_state_vector::operator==
1217 //----------------------------------------------------------------------------------------------------------------------
1218 bool vogl_state_vector::operator==(const vogl_state_vector &rhs) const
1219 {
1220     VOGL_FUNC_TRACER
1221
1222     if (m_states.size() != rhs.m_states.size())
1223         return false;
1224
1225     VOGL_ASSERT(m_states.debug_check());
1226     VOGL_ASSERT(rhs.m_states.debug_check());
1227
1228     const_iterator lhs_it(begin());
1229     const_iterator rhs_it(rhs.begin());
1230     for (; lhs_it != end(); ++lhs_it, ++rhs_it)
1231     {
1232         if (rhs_it == rhs.end())
1233         {
1234             VOGL_ASSERT_ALWAYS;
1235             return false;
1236         }
1237
1238         const vogl_state_data &lhs = lhs_it->second;
1239         const vogl_state_data &rhs = rhs_it->second;
1240
1241         if (lhs.get_id() != rhs.get_id())
1242             return false;
1243
1244         if (lhs.get_enum_val() == GL_TIMESTAMP)
1245             continue;
1246
1247         if (!lhs.is_equal(rhs))
1248             return false;
1249     }
1250
1251     return true;
1252 }
1253
1254 //----------------------------------------------------------------------------------------------------------------------
1255 // vogl_state_vector::insert
1256 //----------------------------------------------------------------------------------------------------------------------
1257 bool vogl_state_vector::insert(GLenum enum_val, uint index, const void *pData, uint element_size, bool indexed_variant)
1258 {
1259     VOGL_FUNC_TRACER
1260
1261     vogl_state_data state_data;
1262     if (!state_data.init(enum_val, index, pData, element_size, indexed_variant))
1263         return false;
1264
1265     return insert(state_data);
1266 }
1267
1268 //----------------------------------------------------------------------------------------------------------------------
1269 // vogl_state_vector::insert
1270 //----------------------------------------------------------------------------------------------------------------------
1271 bool vogl_state_vector::insert(const vogl_state_data &state_data)
1272 {
1273     VOGL_FUNC_TRACER
1274
1275     return m_states.insert(state_data.get_id(), state_data).second;
1276 }