1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 **************************************************************************/
30 #include "vogl_core.h"
34 template <typename component_type>
35 struct color_quad_component_traits
47 struct color_quad_component_traits<int8>
59 struct color_quad_component_traits<int16>
71 struct color_quad_component_traits<uint16>
83 struct color_quad_component_traits<int32>
95 struct color_quad_component_traits<uint32>
107 struct color_quad_component_traits<float>
119 struct color_quad_component_traits<double>
130 template <typename component_type, typename parameter_type>
131 class color_quad : public helpers::rel_ops<color_quad<component_type, parameter_type> >
133 template <typename T>
134 static inline parameter_type clamp(T v)
136 parameter_type result = static_cast<parameter_type>(v);
137 if (!component_traits::cFloat)
139 if (v < component_traits::cMin)
140 result = static_cast<parameter_type>(component_traits::cMin);
141 else if (v > component_traits::cMax)
142 result = static_cast<parameter_type>(component_traits::cMax);
149 static inline parameter_type clamp(int v)
151 if (!component_traits::cFloat)
153 if ((!component_traits::cSigned) && (component_traits::cMin == 0) && (component_traits::cMax == 0xFF))
156 v = (~(static_cast<int>(v) >> 31)) & 0xFF;
160 if (v < component_traits::cMin)
161 v = component_traits::cMin;
162 else if (v > component_traits::cMax)
163 v = component_traits::cMax;
166 return static_cast<parameter_type>(v);
171 typedef component_type component_t;
172 typedef parameter_type parameter_t;
173 typedef color_quad_component_traits<component_type> component_traits;
190 component_type c[cNumComps];
199 inline color_quad(eClear)
200 : r(0), g(0), b(0), a(0)
204 inline color_quad(const color_quad &other)
205 : r(other.r), g(other.g), b(other.b), a(other.a)
209 explicit inline color_quad(parameter_type y, parameter_type alpha = component_traits::cMax)
214 inline color_quad(parameter_type red, parameter_type green, parameter_type blue, parameter_type alpha = component_traits::cMax)
216 set(red, green, blue, alpha);
219 explicit inline color_quad(eNoClamp, parameter_type y, parameter_type alpha = component_traits::cMax)
221 set_noclamp_y_alpha(y, alpha);
224 inline color_quad(eNoClamp, parameter_type red, parameter_type green, parameter_type blue, parameter_type alpha = component_traits::cMax)
226 set_noclamp_rgba(red, green, blue, alpha);
229 template <typename other_component_type, typename other_parameter_type>
230 inline color_quad(const color_quad<other_component_type, other_parameter_type> &other)
231 : r(static_cast<component_type>(clamp(other.r))), g(static_cast<component_type>(clamp(other.g))), b(static_cast<component_type>(clamp(other.b))), a(static_cast<component_type>(clamp(other.a)))
243 inline color_quad &operator=(const color_quad &other)
252 inline color_quad &set_rgb(const color_quad &other)
260 template <typename other_component_type, typename other_parameter_type>
261 inline color_quad &operator=(const color_quad<other_component_type, other_parameter_type> &other)
263 r = static_cast<component_type>(clamp(other.r));
264 g = static_cast<component_type>(clamp(other.g));
265 b = static_cast<component_type>(clamp(other.b));
266 a = static_cast<component_type>(clamp(other.a));
270 inline color_quad &operator=(parameter_type y)
272 set(y, component_traits::cMax);
276 inline color_quad &set(parameter_type y, parameter_type alpha = component_traits::cMax)
279 alpha = clamp(alpha);
280 r = static_cast<component_type>(y);
281 g = static_cast<component_type>(y);
282 b = static_cast<component_type>(y);
283 a = static_cast<component_type>(alpha);
287 inline color_quad &set_alpha(parameter_type alpha)
289 a = static_cast<component_type>(clamp(alpha));
293 inline color_quad &set_noclamp_y_alpha(parameter_type y, parameter_type alpha = component_traits::cMax)
295 VOGL_ASSERT((y >= component_traits::cMin) && (y <= component_traits::cMax));
296 VOGL_ASSERT((alpha >= component_traits::cMin) && (alpha <= component_traits::cMax));
298 r = static_cast<component_type>(y);
299 g = static_cast<component_type>(y);
300 b = static_cast<component_type>(y);
301 a = static_cast<component_type>(alpha);
305 inline color_quad &set(parameter_type red, parameter_type green, parameter_type blue, parameter_type alpha = component_traits::cMax)
307 r = static_cast<component_type>(clamp(red));
308 g = static_cast<component_type>(clamp(green));
309 b = static_cast<component_type>(clamp(blue));
310 a = static_cast<component_type>(clamp(alpha));
314 inline color_quad &set_noclamp_rgba(parameter_type red, parameter_type green, parameter_type blue, parameter_type alpha)
316 VOGL_ASSERT((red >= component_traits::cMin) && (red <= component_traits::cMax));
317 VOGL_ASSERT((green >= component_traits::cMin) && (green <= component_traits::cMax));
318 VOGL_ASSERT((blue >= component_traits::cMin) && (blue <= component_traits::cMax));
319 VOGL_ASSERT((alpha >= component_traits::cMin) && (alpha <= component_traits::cMax));
321 r = static_cast<component_type>(red);
322 g = static_cast<component_type>(green);
323 b = static_cast<component_type>(blue);
324 a = static_cast<component_type>(alpha);
328 inline color_quad &set_noclamp_rgb(parameter_type red, parameter_type green, parameter_type blue)
330 VOGL_ASSERT((red >= component_traits::cMin) && (red <= component_traits::cMax));
331 VOGL_ASSERT((green >= component_traits::cMin) && (green <= component_traits::cMax));
332 VOGL_ASSERT((blue >= component_traits::cMin) && (blue <= component_traits::cMax));
334 r = static_cast<component_type>(red);
335 g = static_cast<component_type>(green);
336 b = static_cast<component_type>(blue);
340 static inline parameter_type get_min_comp()
342 return component_traits::cMin;
344 static inline parameter_type get_max_comp()
346 return component_traits::cMax;
348 static inline bool get_comps_are_signed()
350 return component_traits::cSigned;
353 inline component_type operator[](uint i) const
355 VOGL_ASSERT(i < cNumComps);
358 inline component_type &operator[](uint i)
360 VOGL_ASSERT(i < cNumComps);
364 inline color_quad &set_component(uint i, parameter_type f)
366 VOGL_ASSERT(i < cNumComps);
368 c[i] = static_cast<component_type>(clamp(f));
373 inline color_quad &set_grayscale(parameter_t l)
375 component_t x = static_cast<component_t>(clamp(l));
382 inline color_quad &clamp(const color_quad &l, const color_quad &h)
384 for (uint i = 0; i < cNumComps; i++)
385 c[i] = static_cast<component_type>(math::clamp<parameter_type>(c[i], l[i], h[i]));
389 inline color_quad &clamp(parameter_type l, parameter_type h)
391 for (uint i = 0; i < cNumComps; i++)
392 c[i] = static_cast<component_type>(math::clamp<parameter_type>(c[i], l, h));
396 // Returns CCIR 601 luma (consistent with color_utils::RGB_To_Y).
397 inline parameter_type get_luma() const
399 return static_cast<parameter_type>((19595U * r + 38470U * g + 7471U * b + 32768U) >> 16U);
402 // Returns REC 709 luma.
403 inline parameter_type get_luma_rec709() const
405 return static_cast<parameter_type>((13938U * r + 46869U * g + 4729U * b + 32768U) >> 16U);
408 // Beware of endianness!
409 inline uint32 get_uint32() const
411 VOGL_ASSERT(sizeof(*this) == sizeof(uint32));
412 return *reinterpret_cast<const uint32 *>(this);
415 // Beware of endianness!
416 inline uint64_t get_uint64() const
418 VOGL_ASSERT(sizeof(*this) == sizeof(uint64_t));
419 return *reinterpret_cast<const uint64_t *>(this);
422 inline uint squared_distance(const color_quad &c, bool alpha = true) const
424 return math::square(r - c.r) + math::square(g - c.g) + math::square(b - c.b) + (alpha ? math::square(a - c.a) : 0);
427 inline bool rgb_equals(const color_quad &rhs) const
429 return (r == rhs.r) && (g == rhs.g) && (b == rhs.b);
432 inline bool operator==(const color_quad &rhs) const
434 if (sizeof(color_quad) == sizeof(uint32))
435 return m_u32 == rhs.m_u32;
437 return (r == rhs.r) && (g == rhs.g) && (b == rhs.b) && (a == rhs.a);
440 inline bool operator<(const color_quad &rhs) const
442 for (uint i = 0; i < cNumComps; i++)
446 else if (!(c[i] == rhs.c[i]))
452 color_quad &operator+=(const color_quad &other)
454 for (uint i = 0; i < 4; i++)
455 c[i] = static_cast<component_type>(clamp(c[i] + other.c[i]));
459 color_quad &operator-=(const color_quad &other)
461 for (uint i = 0; i < 4; i++)
462 c[i] = static_cast<component_type>(clamp(c[i] - other.c[i]));
466 color_quad &operator*=(parameter_type v)
468 for (uint i = 0; i < 4; i++)
469 c[i] = static_cast<component_type>(clamp(c[i] * v));
473 color_quad &operator/=(parameter_type v)
475 for (uint i = 0; i < 4; i++)
476 c[i] = static_cast<component_type>(c[i] / v);
480 color_quad get_swizzled(uint x, uint y, uint z, uint w) const
482 VOGL_ASSERT((x | y | z | w) < 4);
483 return color_quad(c[x], c[y], c[z], c[w]);
486 friend color_quad operator+(const color_quad &lhs, const color_quad &rhs)
488 color_quad result(lhs);
493 friend color_quad operator-(const color_quad &lhs, const color_quad &rhs)
495 color_quad result(lhs);
500 friend color_quad operator*(const color_quad &lhs, parameter_type v)
502 color_quad result(lhs);
507 friend color_quad operator/(const color_quad &lhs, parameter_type v)
509 color_quad result(lhs);
514 friend color_quad operator*(parameter_type v, const color_quad &rhs)
516 color_quad result(rhs);
521 inline bool is_grayscale() const
523 return (c[0] == c[1]) && (c[1] == c[2]);
526 uint get_min_component_index(bool alpha = true) const
529 uint limit = alpha ? cNumComps : (cNumComps - 1);
530 for (uint i = 1; i < limit; i++)
536 uint get_max_component_index(bool alpha = true) const
539 uint limit = alpha ? cNumComps : (cNumComps - 1);
540 for (uint i = 1; i < limit; i++)
546 operator size_t() const
548 return (size_t)fast_hash(this, sizeof(*this));
551 void get_float4(float *pDst)
553 for (uint i = 0; i < 4; i++)
554 pDst[i] = ((*this)[i] - component_traits::cMin) / float(component_traits::cMax - component_traits::cMin);
557 void get_float3(float *pDst)
559 for (uint i = 0; i < 3; i++)
560 pDst[i] = ((*this)[i] - component_traits::cMin) / float(component_traits::cMax - component_traits::cMin);
563 void scale_rgb_by_float(float flScale)
565 for (uint i = 0; i < 3; i++)
566 set_component(i, static_cast<parameter_t>(c[i] * flScale + (component_traits::cFloat ? 0.0f : .5f)));
569 void scale_rgb_by_component(parameter_t v)
572 if (component_traits::cFloat)
573 flScale = static_cast<float>(v);
575 flScale = math::maximum<float>(0.0f, v / static_cast<float>(component_traits::cMax));
576 scale_rgb_by_float(flScale);
579 static color_quad component_min(const color_quad &a, const color_quad &b)
582 for (uint i = 0; i < 4; i++)
583 result[i] = static_cast<component_type>(math::minimum(a[i], b[i]));
587 static color_quad component_max(const color_quad &a, const color_quad &b)
590 for (uint i = 0; i < 4; i++)
591 result[i] = static_cast<component_type>(math::maximum(a[i], b[i]));
595 static color_quad make_black()
597 return color_quad(0, 0, 0, static_cast<color_quad::component_t>(component_traits::cMax));
600 static color_quad make_white()
602 return color_quad(static_cast<color_quad::component_t>(component_traits::cMax), static_cast<color_quad::component_t>(component_traits::cMax), static_cast<color_quad::component_t>(component_traits::cMax), static_cast<color_quad::component_t>(component_traits::cMax));
604 }; // class color_quad
606 template <typename c, typename q>
607 struct scalar_type<color_quad<c, q> >
613 static inline void construct(color_quad<c, q> *p)
617 static inline void construct(color_quad<c, q> *p, const color_quad<c, q> &init)
619 memcpy(p, &init, sizeof(color_quad<c, q>));
621 static inline void construct_array(color_quad<c, q> *p, uint n)
623 VOGL_NOTE_UNUSED(p), VOGL_NOTE_UNUSED(n);
625 static inline void destruct(color_quad<c, q> *p)
629 static inline void destruct_array(color_quad<c, q> *p, uint n)
631 VOGL_NOTE_UNUSED(p), VOGL_NOTE_UNUSED(n);
635 typedef color_quad<uint8, int> color_quad_u8;
636 typedef color_quad<int8, int> color_quad_i8;
637 typedef color_quad<int16, int> color_quad_i16;
638 typedef color_quad<uint16, int> color_quad_u16;
639 typedef color_quad<int32, int> color_quad_i32;
640 typedef color_quad<uint32, uint> color_quad_u32;
641 typedef color_quad<float, float> color_quad_f;
642 typedef color_quad<double, double> color_quad_d;
646 inline uint elucidian_distance(uint r0, uint g0, uint b0, uint r1, uint g1, uint b1)
648 int dr = (int)r0 - (int)r1;
649 int dg = (int)g0 - (int)g1;
650 int db = (int)b0 - (int)b1;
652 return static_cast<uint>(dr * dr + dg * dg + db * db);
655 inline uint elucidian_distance(uint r0, uint g0, uint b0, uint a0, uint r1, uint g1, uint b1, uint a1)
657 int dr = (int)r0 - (int)r1;
658 int dg = (int)g0 - (int)g1;
659 int db = (int)b0 - (int)b1;
660 int da = (int)a0 - (int)a1;
662 return static_cast<uint>(dr * dr + dg * dg + db * db + da * da);
665 inline uint elucidian_distance(const color_quad_u8 &c0, const color_quad_u8 &c1, bool alpha)
668 return elucidian_distance(c0.r, c0.g, c0.b, c0.a, c1.r, c1.g, c1.b, c1.a);
670 return elucidian_distance(c0.r, c0.g, c0.b, c1.r, c1.g, c1.b);
673 inline uint weighted_elucidian_distance(uint r0, uint g0, uint b0, uint r1, uint g1, uint b1, uint wr, uint wg, uint wb)
675 int dr = (int)r0 - (int)r1;
676 int dg = (int)g0 - (int)g1;
677 int db = (int)b0 - (int)b1;
679 return static_cast<uint>((wr * dr * dr) + (wg * dg * dg) + (wb * db * db));
682 inline uint weighted_elucidian_distance(
683 uint r0, uint g0, uint b0, uint a0,
684 uint r1, uint g1, uint b1, uint a1,
685 uint wr, uint wg, uint wb, uint wa)
687 int dr = (int)r0 - (int)r1;
688 int dg = (int)g0 - (int)g1;
689 int db = (int)b0 - (int)b1;
690 int da = (int)a0 - (int)a1;
692 return static_cast<uint>((wr * dr * dr) + (wg * dg * dg) + (wb * db * db) + (wa * da * da));
695 inline uint weighted_elucidian_distance(const color_quad_u8 &c0, const color_quad_u8 &c1, uint wr, uint wg, uint wb, uint wa)
697 return weighted_elucidian_distance(c0.r, c0.g, c0.b, c0.a, c1.r, c1.g, c1.b, c1.a, wr, wg, wb, wa);
700 //const uint cRWeight = 8;//24;
701 //const uint cGWeight = 24;//73;
702 //const uint cBWeight = 1;//3;
704 const uint cRWeight = 8; //24;
705 const uint cGWeight = 25; //73;
706 const uint cBWeight = 1; //3;
708 inline uint color_distance(bool perceptual, const color_quad_u8 &e1, const color_quad_u8 &e2, bool alpha)
713 return weighted_elucidian_distance(e1, e2, cRWeight, cGWeight, cBWeight, cRWeight + cGWeight + cBWeight);
715 return weighted_elucidian_distance(e1, e2, cRWeight, cGWeight, cBWeight, 0);
718 return elucidian_distance(e1, e2, alpha);
721 inline uint peak_color_error(const color_quad_u8 &e1, const color_quad_u8 &e2)
723 return math::maximum<uint>(static_cast<uint>(labs(e1[0] - e2[0])), static_cast<uint>(labs(e1[1] - e2[1])), static_cast<uint>(labs(e1[2] - e2[2])));
724 //return math::square<int>(e1[0] - e2[0]) + math::square<int>(e1[1] - e2[1]) + math::square<int>(e1[2] - e2[2]);
730 inline void RGB_to_YCoCg(int r, int g, int b, int &y, int &co, int &cg)
732 y = (r >> 2) + (g >> 1) + (b >> 2);
733 co = (r >> 1) - (b >> 1);
734 cg = -(r >> 2) + (g >> 1) - (b >> 2);
737 inline void YCoCg_to_RGB(int y, int co, int cg, int &r, int &g, int &b)
745 static inline uint8 clamp_component(int i)
747 if (static_cast<uint>(i) > 255U)
754 return static_cast<uint8>(i);
757 // RGB->YCbCr constants, scaled by 2^16
758 const int YR = 19595, YG = 38470, YB = 7471, CB_R = -11059, CB_G = -21709, CB_B = 32768, CR_R = 32768, CR_G = -27439, CR_B = -5329;
759 // YCbCr->RGB constants, scaled by 2^16
760 const int R_CR = 91881, B_CB = 116130, G_CR = -46802, G_CB = -22554;
762 inline int RGB_to_Y(const color_quad_u8 &rgb)
764 const int r = rgb[0], g = rgb[1], b = rgb[2];
765 return (r * YR + g * YG + b * YB + 32768) >> 16;
768 // RGB to YCbCr (same as JFIF JPEG).
769 // Odd default biases account for 565 endpoint packing.
770 inline void RGB_to_YCC(color_quad_u8 &ycc, const color_quad_u8 &rgb, int cb_bias = 123, int cr_bias = 125)
772 const int r = rgb[0], g = rgb[1], b = rgb[2];
773 ycc.a = static_cast<uint8>((r * YR + g * YG + b * YB + 32768) >> 16);
774 ycc.r = clamp_component(cb_bias + ((r * CB_R + g * CB_G + b * CB_B + 32768) >> 16));
775 ycc.g = clamp_component(cr_bias + ((r * CR_R + g * CR_G + b * CR_B + 32768) >> 16));
780 // Odd biases account for 565 endpoint packing.
781 inline void YCC_to_RGB(color_quad_u8 &rgb, const color_quad_u8 &ycc, int cb_bias = 123, int cr_bias = 125)
784 const int cb = ycc.r - cb_bias;
785 const int cr = ycc.g - cr_bias;
786 rgb.r = clamp_component(y + ((R_CR * cr + 32768) >> 16));
787 rgb.g = clamp_component(y + ((G_CR * cr + G_CB * cb + 32768) >> 16));
788 rgb.b = clamp_component(y + ((B_CB * cb + 32768) >> 16));
792 // Float RGB->YCbCr constants
793 const float S = 1.0f / 65536.0f;
794 const float F_YR = S * YR, F_YG = S * YG, F_YB = S * YB, F_CB_R = S * CB_R, F_CB_G = S * CB_G, F_CB_B = S * CB_B, F_CR_R = S * CR_R, F_CR_G = S * CR_G, F_CR_B = S * CR_B;
795 // Float YCbCr->RGB constants
796 const float F_R_CR = S * R_CR, F_B_CB = S * B_CB, F_G_CR = S * G_CR, F_G_CB = S * G_CB;
798 inline void RGB_to_YCC_float(color_quad_f &ycc, const color_quad_u8 &rgb)
800 const int r = rgb[0], g = rgb[1], b = rgb[2];
801 ycc.a = r * F_YR + g * F_YG + b * F_YB;
802 ycc.r = r * F_CB_R + g * F_CB_G + b * F_CB_B;
803 ycc.g = r * F_CR_R + g * F_CR_G + b * F_CR_B;
807 inline void YCC_float_to_RGB(color_quad_u8 &rgb, const color_quad_f &ycc)
809 float y = ycc.a, cb = ycc.r, cr = ycc.g;
810 rgb.r = color::clamp_component(static_cast<int>(.5f + y + F_R_CR * cr));
811 rgb.g = color::clamp_component(static_cast<int>(.5f + y + F_G_CR * cr + F_G_CB * cb));
812 rgb.b = color::clamp_component(static_cast<int>(.5f + y + F_B_CB * cb));
818 // This class purposely trades off speed for flexibility. It can handle any component swizzle, any pixel type from 1-4 components and 1-32 bits/component,
819 // any pixel size between 1-16 bytes/pixel, any pixel stride, any color_quad data type (signed/unsigned/float 8/16/32 bits/component), and scaled/non-scaled components.
820 // On the downside, it's freaking slow.
829 pixel_packer(uint num_comps, uint bits_per_comp, int pixel_stride = -1, bool reversed = false)
831 init(num_comps, bits_per_comp, pixel_stride, reversed);
834 pixel_packer(const char *pComp_map, int pixel_stride = -1, int force_comp_size = -1)
836 init(pComp_map, pixel_stride, force_comp_size);
841 utils::zero_this(this);
844 inline bool is_valid() const
846 return m_pixel_stride > 0;
849 inline uint get_pixel_stride() const
851 return m_pixel_stride;
853 void set_pixel_stride(uint n)
858 uint get_num_comps() const
862 uint get_comp_size(uint index) const
864 VOGL_ASSERT(index < 4);
865 return m_comp_size[index];
867 uint get_comp_ofs(uint index) const
869 VOGL_ASSERT(index < 4);
870 return m_comp_ofs[index];
872 uint get_comp_max(uint index) const
874 VOGL_ASSERT(index < 4);
875 return m_comp_max[index];
877 bool get_rgb_is_luma() const
879 return m_rgb_is_luma;
882 template <typename color_quad_type>
883 const void *unpack(const void *p, color_quad_type &color, bool rescale = true) const
885 const uint8 *pSrc = static_cast<const uint8 *>(p);
887 for (uint i = 0; i < 4; i++)
889 const uint comp_size = m_comp_size[i];
892 if (color_quad_type::component_traits::cFloat)
893 color[i] = static_cast<typename color_quad_type::parameter_t>((i == 3) ? 1 : 0);
895 color[i] = static_cast<typename color_quad_type::parameter_t>((i == 3) ? color_quad_type::component_traits::cMax : 0);
899 uint n = 0, dst_bit_ofs = 0;
900 uint src_bit_ofs = m_comp_ofs[i];
901 while (dst_bit_ofs < comp_size)
903 const uint byte_bit_ofs = src_bit_ofs & 7;
904 n |= ((pSrc[src_bit_ofs >> 3] >> byte_bit_ofs) << dst_bit_ofs);
906 const uint bits_read = 8 - byte_bit_ofs;
907 src_bit_ofs += bits_read;
908 dst_bit_ofs += bits_read;
911 const uint32 mx = m_comp_max[i];
914 const uint32 h = static_cast<uint32>(color_quad_type::component_traits::cMax);
916 if (color_quad_type::component_traits::cFloat)
917 color.set_component(i, static_cast<typename color_quad_type::parameter_t>(n));
919 color.set_component(i, static_cast<typename color_quad_type::parameter_t>((static_cast<uint64_t>(n) * h + (mx >> 1U)) / mx));
920 else if (color_quad_type::component_traits::cSigned)
921 color.set_component(i, static_cast<typename color_quad_type::parameter_t>(math::minimum<uint32>(n, h)));
923 color.set_component(i, static_cast<typename color_quad_type::parameter_t>(n));
932 return pSrc + m_pixel_stride;
935 template <typename color_quad_type>
936 void *pack(const color_quad_type &color, void *p, bool rescale = true) const
938 uint8 *pDst = static_cast<uint8 *>(p);
940 for (uint i = 0; i < 4; i++)
942 const uint comp_size = m_comp_size[i];
946 uint32 mx = m_comp_max[i];
949 if (color_quad_type::component_traits::cFloat)
951 typename color_quad_type::parameter_t t = color[i];
954 else if (t > static_cast<typename color_quad_type::parameter_t>(mx))
957 n = math::minimum<uint32>(static_cast<uint32>(floor(t + .5f)), mx);
961 if (color_quad_type::component_traits::cSigned)
962 n = math::maximum<int>(static_cast<int>(color[i]), 0);
964 n = static_cast<uint32>(color[i]);
966 const uint32 h = static_cast<uint32>(color_quad_type::component_traits::cMax);
967 n = static_cast<uint32>((static_cast<uint64_t>(n) * mx + (h >> 1)) / h);
971 if (color_quad_type::component_traits::cSigned)
972 n = math::minimum<uint32>(static_cast<uint32>(math::maximum<int>(static_cast<int>(color[i]), 0)), mx);
974 n = math::minimum<uint32>(static_cast<uint32>(color[i]), mx);
977 uint src_bit_ofs = 0;
978 uint dst_bit_ofs = m_comp_ofs[i];
979 while (src_bit_ofs < comp_size)
981 const uint cur_byte_bit_ofs = (dst_bit_ofs & 7);
982 const uint cur_byte_bits = 8 - cur_byte_bit_ofs;
984 uint byte_val = pDst[dst_bit_ofs >> 3];
985 uint bit_mask = (mx << cur_byte_bit_ofs) & 0xFF;
986 byte_val &= ~bit_mask;
987 byte_val |= (n << cur_byte_bit_ofs);
988 pDst[dst_bit_ofs >> 3] = static_cast<uint8>(byte_val);
990 mx >>= cur_byte_bits;
993 dst_bit_ofs += cur_byte_bits;
994 src_bit_ofs += cur_byte_bits;
998 return pDst + m_pixel_stride;
1001 bool init(uint num_comps, uint bits_per_comp, int pixel_stride = -1, bool reversed = false)
1005 if ((num_comps < 1) || (num_comps > 4) || (bits_per_comp < 1) || (bits_per_comp > 32))
1011 for (uint i = 0; i < num_comps; i++)
1013 m_comp_size[i] = bits_per_comp;
1014 m_comp_ofs[i] = i * bits_per_comp;
1016 m_comp_ofs[i] = ((num_comps - 1) * bits_per_comp) - m_comp_ofs[i];
1019 for (uint i = 0; i < 4; i++)
1020 m_comp_max[i] = static_cast<uint32>((1ULL << m_comp_size[i]) - 1ULL);
1022 m_pixel_stride = (pixel_stride >= 0) ? pixel_stride : (num_comps * bits_per_comp + 7) / 8;
1033 // First component is at LSB in memory. Assumes unsigned integer components, 1-32bits each.
1034 bool init(const char *pComp_map, int pixel_stride = -1, int force_comp_size = -1)
1038 uint cur_bit_ofs = 0;
1042 char c = *pComp_map++;
1044 int comp_index = -1;
1060 uint n = *pComp_map;
1061 if ((n >= '0') && (n <= '9'))
1063 comp_size = n - '0';
1067 if ((n >= '0') && (n <= '9'))
1069 comp_size = (comp_size * 10) + (n - '0');
1074 if (force_comp_size != -1)
1075 comp_size = force_comp_size;
1077 if ((!comp_size) || (comp_size > 32))
1080 if (comp_index == 4)
1082 if (m_comp_size[0] || m_comp_size[1] || m_comp_size[2])
1085 //m_comp_ofs[0] = m_comp_ofs[1] = m_comp_ofs[2] = cur_bit_ofs;
1086 //m_comp_size[0] = m_comp_size[1] = m_comp_size[2] = comp_size;
1087 m_comp_ofs[1] = cur_bit_ofs;
1088 m_comp_size[1] = comp_size;
1089 m_rgb_is_luma = true;
1092 else if (comp_index >= 0)
1094 if (m_comp_size[comp_index])
1097 m_comp_ofs[comp_index] = cur_bit_ofs;
1098 m_comp_size[comp_index] = comp_size;
1102 cur_bit_ofs += comp_size;
1105 for (uint i = 0; i < 4; i++)
1106 m_comp_max[i] = static_cast<uint32>((1ULL << m_comp_size[i]) - 1ULL);
1108 if (pixel_stride >= 0)
1109 m_pixel_stride = pixel_stride;
1111 m_pixel_stride = (cur_bit_ofs + 7) / 8;
1116 uint m_pixel_stride;
1118 uint m_comp_size[4];