1//
2// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7namespace rx
8{
9
10template <typename T, size_t componentCount, uint32_t widenDefaultValueBits>
11inline void CopyNativeVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
12{
13    const size_t attribSize = sizeof(T)* componentCount;
14    const T defaultValue = gl::bitCast<T>(widenDefaultValueBits);
15    const bool widen = (widenDefaultValueBits != 0);
16
17    if (attribSize == stride && !widen)
18    {
19        memcpy(output, input, count * attribSize);
20    }
21    else
22    {
23        size_t outputStride = widen ? 4 : componentCount;
24
25        for (size_t i = 0; i < count; i++)
26        {
27            const T *offsetInput = reinterpret_cast<const T*>(input + (i * stride));
28            T *offsetOutput = reinterpret_cast<T*>(output) + i * outputStride;
29
30            for (size_t j = 0; j < componentCount; j++)
31            {
32                offsetOutput[j] = offsetInput[j];
33            }
34
35            if (widen)
36            {
37                offsetOutput[3] = defaultValue;
38            }
39        }
40    }
41}
42
43template <size_t componentCount>
44inline void Copy32FixedTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
45{
46    static const float divisor = 1.0f / (1 << 16);
47
48    for (size_t i = 0; i < count; i++)
49    {
50        const GLfixed* offsetInput = reinterpret_cast<const GLfixed*>(input + (stride * i));
51        float* offsetOutput = reinterpret_cast<float*>(output) + i * componentCount;
52
53        for (size_t j = 0; j < componentCount; j++)
54        {
55            offsetOutput[j] = static_cast<float>(offsetInput[j]) * divisor;
56        }
57    }
58}
59
60template <typename T, size_t componentCount, bool normalized>
61inline void CopyTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
62{
63    typedef std::numeric_limits<T> NL;
64
65    for (size_t i = 0; i < count; i++)
66    {
67        const T *offsetInput = reinterpret_cast<const T*>(input + (stride * i));
68        float *offsetOutput = reinterpret_cast<float*>(output) + i * componentCount;
69
70        for (size_t j = 0; j < componentCount; j++)
71        {
72            if (normalized)
73            {
74                if (NL::is_signed)
75                {
76                    const float divisor = 1.0f / (2 * static_cast<float>(NL::max()) + 1);
77                    offsetOutput[j] = (2 * static_cast<float>(offsetInput[j]) + 1) * divisor;
78                }
79                else
80                {
81                    offsetOutput[j] =  static_cast<float>(offsetInput[j]) / NL::max();
82                }
83            }
84            else
85            {
86                offsetOutput[j] =  static_cast<float>(offsetInput[j]);
87            }
88        }
89    }
90}
91
92namespace priv
93{
94
95template <bool isSigned, bool normalized, bool toFloat>
96static inline void CopyPackedRGB(uint32_t data, uint8_t *output)
97{
98    const uint32_t rgbSignMask = 0x200;       // 1 set at the 9 bit
99    const uint32_t negativeMask = 0xFFFFFC00; // All bits from 10 to 31 set to 1
100
101    if (toFloat)
102    {
103        GLfloat *floatOutput = reinterpret_cast<GLfloat*>(output);
104        if (isSigned)
105        {
106            GLfloat finalValue = 0;
107            if (data & rgbSignMask)
108            {
109                int negativeNumber = data | negativeMask;
110                finalValue = static_cast<GLfloat>(negativeNumber);
111            }
112            else
113            {
114                finalValue = static_cast<GLfloat>(data);
115            }
116
117            if (normalized)
118            {
119                const int32_t maxValue = 0x1FF;      // 1 set in bits 0 through 8
120                const int32_t minValue = 0xFFFFFE01; // Inverse of maxValue
121
122                // A 10-bit two's complement number has the possibility of being minValue - 1 but
123                // OpenGL's normalization rules dictate that it should be clamped to minValue in this
124                // case.
125                if (finalValue < minValue)
126                {
127                    finalValue = minValue;
128                }
129
130                const int32_t halfRange = (maxValue - minValue) >> 1;
131                *floatOutput = ((finalValue - minValue) / halfRange) - 1.0f;
132            }
133            else
134            {
135                *floatOutput = finalValue;
136            }
137        }
138        else
139        {
140            if (normalized)
141            {
142                const uint32_t maxValue = 0x3FF; // 1 set in bits 0 through 9
143                *floatOutput = static_cast<GLfloat>(data) / static_cast<GLfloat>(maxValue);
144            }
145            else
146            {
147                *floatOutput = static_cast<GLfloat>(data);
148            }
149        }
150    }
151    else
152    {
153        if (isSigned)
154        {
155            GLshort *intOutput = reinterpret_cast<GLshort*>(output);
156
157            if (data & rgbSignMask)
158            {
159                *intOutput = data | negativeMask;
160            }
161            else
162            {
163                *intOutput = data;
164            }
165        }
166        else
167        {
168            GLushort *uintOutput = reinterpret_cast<GLushort*>(output);
169            *uintOutput = data;
170        }
171    }
172}
173
174template <bool isSigned, bool normalized, bool toFloat>
175inline void CopyPackedAlpha(uint32_t data, uint8_t *output)
176{
177    if (toFloat)
178    {
179        GLfloat *floatOutput = reinterpret_cast<GLfloat*>(output);
180        if (isSigned)
181        {
182            if (normalized)
183            {
184                switch (data)
185                {
186                  case 0x0: *floatOutput =  0.0f; break;
187                  case 0x1: *floatOutput =  1.0f; break;
188                  case 0x2: *floatOutput = -1.0f; break;
189                  case 0x3: *floatOutput = -1.0f; break;
190                  default: UNREACHABLE();
191                }
192            }
193            else
194            {
195                switch (data)
196                {
197                  case 0x0: *floatOutput =  0.0f; break;
198                  case 0x1: *floatOutput =  1.0f; break;
199                  case 0x2: *floatOutput = -2.0f; break;
200                  case 0x3: *floatOutput = -1.0f; break;
201                  default: UNREACHABLE();
202                }
203            }
204        }
205        else
206        {
207            if (normalized)
208            {
209                switch (data)
210                {
211                  case 0x0: *floatOutput = 0.0f / 3.0f; break;
212                  case 0x1: *floatOutput = 1.0f / 3.0f; break;
213                  case 0x2: *floatOutput = 2.0f / 3.0f; break;
214                  case 0x3: *floatOutput = 3.0f / 3.0f; break;
215                  default: UNREACHABLE();
216                }
217            }
218            else
219            {
220                switch (data)
221                {
222                  case 0x0: *floatOutput = 0.0f; break;
223                  case 0x1: *floatOutput = 1.0f; break;
224                  case 0x2: *floatOutput = 2.0f; break;
225                  case 0x3: *floatOutput = 3.0f; break;
226                  default: UNREACHABLE();
227                }
228            }
229        }
230    }
231    else
232    {
233        if (isSigned)
234        {
235            GLshort *intOutput = reinterpret_cast<GLshort*>(output);
236            switch (data)
237            {
238              case 0x0: *intOutput =  0; break;
239              case 0x1: *intOutput =  1; break;
240              case 0x2: *intOutput = -2; break;
241              case 0x3: *intOutput = -1; break;
242              default: UNREACHABLE();
243            }
244        }
245        else
246        {
247            GLushort *uintOutput = reinterpret_cast<GLushort*>(output);
248            switch (data)
249            {
250              case 0x0: *uintOutput = 0; break;
251              case 0x1: *uintOutput = 1; break;
252              case 0x2: *uintOutput = 2; break;
253              case 0x3: *uintOutput = 3; break;
254              default: UNREACHABLE();
255            }
256        }
257    }
258}
259
260}
261
262template <bool isSigned, bool normalized, bool toFloat>
263inline void CopyXYZ10W2ToXYZW32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
264{
265    const size_t outputComponentSize = toFloat ? 4 : 2;
266    const size_t componentCount = 4;
267
268    const uint32_t rgbMask = 0x3FF; // 1 set in bits 0 through 9
269    const size_t redShift = 0;    // red is bits 0 through 9
270    const size_t greenShift = 10; // green is bits 10 through 19
271    const size_t blueShift = 20;  // blue is bits 20 through 29
272
273    const uint32_t alphaMask = 0x3; // 1 set in bits 0 and 1
274    const size_t alphaShift = 30; // Alpha is the 30 and 31 bits
275
276    for (size_t i = 0; i < count; i++)
277    {
278        GLuint packedValue = *reinterpret_cast<const GLuint*>(input + (i * stride));
279        uint8_t *offsetOutput = output + (i * outputComponentSize * componentCount);
280
281        priv::CopyPackedRGB<isSigned, normalized, toFloat>(  (packedValue >> redShift)   & rgbMask,   offsetOutput + (0 * outputComponentSize));
282        priv::CopyPackedRGB<isSigned, normalized, toFloat>(  (packedValue >> greenShift) & rgbMask,   offsetOutput + (1 * outputComponentSize));
283        priv::CopyPackedRGB<isSigned, normalized, toFloat>(  (packedValue >> blueShift)  & rgbMask,   offsetOutput + (2 * outputComponentSize));
284        priv::CopyPackedAlpha<isSigned, normalized, toFloat>((packedValue >> alphaShift) & alphaMask, offsetOutput + (3 * outputComponentSize));
285    }
286}
287
288}
289