1 //============================================================================
2
3 #include "PvrTcEncoder.h"
4 #include "AlphaBitmap.h"
5 #include "PvrTcPacket.h"
6 #include "RgbBitmap.h"
7 #include "RgbaBitmap.h"
8 #include "MortonTable.h"
9 #include "BitUtility.h"
10 #include "Interval.h"
11 #include <assert.h>
12 #include <math.h>
13 #include <stdint.h>
14
15 //============================================================================
16
17 using namespace Javelin;
18 using Data::MORTON_TABLE;
19
20 //============================================================================
21
22 static const unsigned char MODULATION_LUT[16] =
23 {
24 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3
25 };
26
27 //============================================================================
28
GetMortonNumber(int x,int y)29 inline unsigned PvrTcEncoder::GetMortonNumber(int x, int y)
30 {
31 return MORTON_TABLE[x >> 8] << 17 | MORTON_TABLE[y >> 8] << 16 | MORTON_TABLE[x & 0xFF] << 1 | MORTON_TABLE[y & 0xFF];
32 }
33
34 //============================================================================
35
EncodeAlpha2Bpp(void * result,const AlphaBitmap & bitmap)36 void PvrTcEncoder::EncodeAlpha2Bpp(void* result, const AlphaBitmap& bitmap)
37 {
38 int size = bitmap.GetBitmapWidth();
39 assert(size == bitmap.GetBitmapHeight());
40 assert(BitUtility::IsPowerOf2(size));
41
42 // Blocks in each dimension.
43 int xBlocks = size/8;
44 int yBlocks = size/4;
45
46 const unsigned char* bitmapData = bitmap.GetRawData();
47
48 PvrTcPacket* packets = static_cast<PvrTcPacket*>(result);
49 for(int y = 0; y < yBlocks; ++y)
50 {
51 for(int x = 0; x < xBlocks; ++x)
52 {
53 PvrTcPacket* packet = packets + GetMortonNumber(x, y);
54 packet->usePunchthroughAlpha = 0;
55 packet->colorAIsOpaque = 0;
56 packet->colorA = 0x7ff; // White, with 0 alpha
57 packet->colorBIsOpaque = 1;
58 packet->colorB = 0x7fff; // White with full alpha
59
60 const unsigned char* blockBitmapData = &bitmapData[y*4*size + x*8];
61
62 uint32_t modulationData = 0;
63 for(int py = 0; py < 4; ++py)
64 {
65 const unsigned char* rowBitmapData = blockBitmapData;
66 for(int px = 0; px < 8; ++px)
67 {
68 unsigned char pixel = *rowBitmapData++;
69 modulationData = BitUtility::RotateRight(modulationData | (pixel >> 7), 1);
70 }
71 blockBitmapData += size;
72 }
73 packet->modulationData = modulationData;
74 }
75 }
76 }
77
EncodeAlpha4Bpp(void * result,const AlphaBitmap & bitmap)78 void PvrTcEncoder::EncodeAlpha4Bpp(void* result, const AlphaBitmap& bitmap)
79 {
80 int size = bitmap.GetBitmapWidth();
81 assert(size == bitmap.GetBitmapHeight());
82 assert(BitUtility::IsPowerOf2(size));
83
84 // Blocks in each dimension.
85 int blocks = size/4;
86
87 const unsigned char* bitmapData = bitmap.GetRawData();
88
89 PvrTcPacket* packets = static_cast<PvrTcPacket*>(result);
90 for(int y = 0; y < blocks; ++y)
91 {
92 for(int x = 0; x < blocks; ++x)
93 {
94 PvrTcPacket* packet = packets + GetMortonNumber(x, y);
95 packet->usePunchthroughAlpha = 0;
96 packet->colorAIsOpaque = 0;
97 packet->colorA = 0x7ff; // White, with 0 alpha
98 packet->colorBIsOpaque = 1;
99 packet->colorB = 0x7fff; // White with full alpha
100
101 const unsigned char* blockBitmapData = &bitmapData[(y*size + x)*4];
102
103 uint32_t modulationData = 0;
104 for(int py = 0; py < 4; ++py)
105 {
106 const unsigned char* rowBitmapData = blockBitmapData;
107 for(int px = 0; px < 4; ++px)
108 {
109 unsigned char pixel = *rowBitmapData++;
110 modulationData = BitUtility::RotateRight(modulationData | MODULATION_LUT[pixel>>4], 2);
111 }
112 blockBitmapData += size;
113 }
114 packet->modulationData = modulationData;
115 }
116 }
117 }
118
119 //============================================================================
120
121 typedef Interval<ColorRgb<unsigned char> > ColorRgbBoundingBox;
122
CalculateBoundingBox(ColorRgbBoundingBox & cbb,const RgbBitmap & bitmap,int blockX,int blockY)123 static void CalculateBoundingBox(ColorRgbBoundingBox& cbb, const RgbBitmap& bitmap, int blockX, int blockY)
124 {
125 int size = bitmap.GetBitmapWidth();
126 const ColorRgb<unsigned char>* data = bitmap.GetData() + blockY * 4 * size + blockX * 4;
127
128 cbb.min = data[0];
129 cbb.max = data[0];
130 cbb |= data[1];
131 cbb |= data[2];
132 cbb |= data[3];
133
134 cbb |= data[size];
135 cbb |= data[size+1];
136 cbb |= data[size+2];
137 cbb |= data[size+3];
138
139 cbb |= data[2*size];
140 cbb |= data[2*size+1];
141 cbb |= data[2*size+2];
142 cbb |= data[2*size+3];
143
144 cbb |= data[3*size];
145 cbb |= data[3*size+1];
146 cbb |= data[3*size+2];
147 cbb |= data[3*size+3];
148 }
149
EncodeRgb4Bpp(void * result,const RgbBitmap & bitmap)150 void PvrTcEncoder::EncodeRgb4Bpp(void* result, const RgbBitmap& bitmap)
151 {
152 assert(bitmap.GetBitmapWidth() == bitmap.GetBitmapHeight());
153 assert(BitUtility::IsPowerOf2(bitmap.GetBitmapWidth()));
154 const int size = bitmap.GetBitmapWidth();
155 const int blocks = size / 4;
156 const int blockMask = blocks-1;
157
158 PvrTcPacket* packets = static_cast<PvrTcPacket*>(result);
159
160 for(int y = 0; y < blocks; ++y)
161 {
162 for(int x = 0; x < blocks; ++x)
163 {
164 ColorRgbBoundingBox cbb;
165 CalculateBoundingBox(cbb, bitmap, x, y);
166 PvrTcPacket* packet = packets + GetMortonNumber(x, y);
167 packet->usePunchthroughAlpha = 0;
168 packet->SetColorA(cbb.min);
169 packet->SetColorB(cbb.max);
170 }
171 }
172
173 for(int y = 0; y < blocks; ++y)
174 {
175 for(int x = 0; x < blocks; ++x)
176 {
177 const unsigned char (*factor)[4] = PvrTcPacket::BILINEAR_FACTORS;
178 const ColorRgb<unsigned char>* data = bitmap.GetData() + y * 4 * size + x * 4;
179
180 uint32_t modulationData = 0;
181
182 for(int py = 0; py < 4; ++py)
183 {
184 const int yOffset = (py < 2) ? -1 : 0;
185 const int y0 = (y + yOffset) & blockMask;
186 const int y1 = (y0+1) & blockMask;
187
188 for(int px = 0; px < 4; ++px)
189 {
190 const int xOffset = (px < 2) ? -1 : 0;
191 const int x0 = (x + xOffset) & blockMask;
192 const int x1 = (x0+1) & blockMask;
193
194 const PvrTcPacket* p0 = packets + GetMortonNumber(x0, y0);
195 const PvrTcPacket* p1 = packets + GetMortonNumber(x1, y0);
196 const PvrTcPacket* p2 = packets + GetMortonNumber(x0, y1);
197 const PvrTcPacket* p3 = packets + GetMortonNumber(x1, y1);
198
199 ColorRgb<int> ca = p0->GetColorRgbA() * (*factor)[0] +
200 p1->GetColorRgbA() * (*factor)[1] +
201 p2->GetColorRgbA() * (*factor)[2] +
202 p3->GetColorRgbA() * (*factor)[3];
203
204 ColorRgb<int> cb = p0->GetColorRgbB() * (*factor)[0] +
205 p1->GetColorRgbB() * (*factor)[1] +
206 p2->GetColorRgbB() * (*factor)[2] +
207 p3->GetColorRgbB() * (*factor)[3];
208
209 const ColorRgb<unsigned char>& pixel = data[py*size + px];
210 ColorRgb<int> d = cb - ca;
211 ColorRgb<int> p;
212 p.r=pixel.r*16;
213 p.g=pixel.g*16;
214 p.b=pixel.b*16;
215 ColorRgb<int> v = p - ca;
216
217 // PVRTC uses weightings of 0, 3/8, 5/8 and 1
218 // The boundaries for these are 3/16, 1/2 (=8/16), 13/16
219 int projection = (v % d) * 16;
220 int lengthSquared = d % d;
221 if(projection > 3*lengthSquared) modulationData++;
222 if(projection > 8*lengthSquared) modulationData++;
223 if(projection > 13*lengthSquared) modulationData++;
224
225 modulationData = BitUtility::RotateRight(modulationData, 2);
226
227 factor++;
228 }
229 }
230
231 PvrTcPacket* packet = packets + GetMortonNumber(x, y);
232 packet->modulationData = modulationData;
233 }
234 }
235 }
236
237 //============================================================================
238
CalculateBoundingBox(ColorRgbBoundingBox & cbb,const RgbaBitmap & bitmap,int blockX,int blockY)239 static void CalculateBoundingBox(ColorRgbBoundingBox& cbb, const RgbaBitmap& bitmap, int blockX, int blockY)
240 {
241 int size = bitmap.GetBitmapWidth();
242 const ColorRgba<unsigned char>* data = bitmap.GetData() + blockY * 4 * size + blockX * 4;
243
244 cbb.min = data[0];
245 cbb.max = data[0];
246
247 cbb |= data[1];
248 cbb |= data[2];
249 cbb |= data[3];
250
251 cbb |= data[size];
252 cbb |= data[size+1];
253 cbb |= data[size+2];
254 cbb |= data[size+3];
255
256 cbb |= data[2*size];
257 cbb |= data[2*size+1];
258 cbb |= data[2*size+2];
259 cbb |= data[2*size+3];
260
261 cbb |= data[3*size];
262 cbb |= data[3*size+1];
263 cbb |= data[3*size+2];
264 cbb |= data[3*size+3];
265 }
266
EncodeRgb4Bpp(void * result,const RgbaBitmap & bitmap)267 void PvrTcEncoder::EncodeRgb4Bpp(void* result, const RgbaBitmap& bitmap)
268 {
269 assert(bitmap.GetBitmapWidth() == bitmap.GetBitmapHeight());
270 assert(BitUtility::IsPowerOf2(bitmap.GetBitmapWidth()));
271 const int size = bitmap.GetBitmapWidth();
272 const int blocks = size / 4;
273 const int blockMask = blocks-1;
274
275 PvrTcPacket* packets = static_cast<PvrTcPacket*>(result);
276
277 for(int y = 0; y < blocks; ++y)
278 {
279 for(int x = 0; x < blocks; ++x)
280 {
281 ColorRgbBoundingBox cbb;
282 CalculateBoundingBox(cbb, bitmap, x, y);
283 PvrTcPacket* packet = packets + GetMortonNumber(x, y);
284 packet->usePunchthroughAlpha = 0;
285 packet->SetColorA(cbb.min);
286 packet->SetColorB(cbb.max);
287 }
288 }
289
290 for(int y = 0; y < blocks; ++y)
291 {
292 for(int x = 0; x < blocks; ++x)
293 {
294 const unsigned char (*factor)[4] = PvrTcPacket::BILINEAR_FACTORS;
295 const ColorRgba<unsigned char>* data = bitmap.GetData() + y * 4 * size + x * 4;
296
297 uint32_t modulationData = 0;
298
299 for(int py = 0; py < 4; ++py)
300 {
301 const int yOffset = (py < 2) ? -1 : 0;
302 const int y0 = (y + yOffset) & blockMask;
303 const int y1 = (y0+1) & blockMask;
304
305 for(int px = 0; px < 4; ++px)
306 {
307 const int xOffset = (px < 2) ? -1 : 0;
308 const int x0 = (x + xOffset) & blockMask;
309 const int x1 = (x0+1) & blockMask;
310
311 const PvrTcPacket* p0 = packets + GetMortonNumber(x0, y0);
312 const PvrTcPacket* p1 = packets + GetMortonNumber(x1, y0);
313 const PvrTcPacket* p2 = packets + GetMortonNumber(x0, y1);
314 const PvrTcPacket* p3 = packets + GetMortonNumber(x1, y1);
315
316 ColorRgb<int> ca = p0->GetColorRgbA() * (*factor)[0] +
317 p1->GetColorRgbA() * (*factor)[1] +
318 p2->GetColorRgbA() * (*factor)[2] +
319 p3->GetColorRgbA() * (*factor)[3];
320
321 ColorRgb<int> cb = p0->GetColorRgbB() * (*factor)[0] +
322 p1->GetColorRgbB() * (*factor)[1] +
323 p2->GetColorRgbB() * (*factor)[2] +
324 p3->GetColorRgbB() * (*factor)[3];
325
326 const ColorRgb<unsigned char>& pixel = data[py*size + px];
327 ColorRgb<int> d = cb - ca;
328 ColorRgb<int> p;
329 p.r=pixel.r*16;
330 p.g=pixel.g*16;
331 p.b=pixel.b*16;
332 ColorRgb<int> v = p - ca;
333
334 // PVRTC uses weightings of 0, 3/8, 5/8 and 1
335 // The boundaries for these are 3/16, 1/2 (=8/16), 13/16
336 int projection = (v % d) * 16;
337 int lengthSquared = d % d;
338 if(projection > 3*lengthSquared) modulationData++;
339 if(projection > 8*lengthSquared) modulationData++;
340 if(projection > 13*lengthSquared) modulationData++;
341
342 modulationData = BitUtility::RotateRight(modulationData, 2);
343
344 factor++;
345 }
346 }
347
348 PvrTcPacket* packet = packets + GetMortonNumber(x, y);
349 packet->modulationData = modulationData;
350 }
351 }
352 }
353
354 //============================================================================
355
356 typedef Interval<ColorRgba<unsigned char> > ColorRgbaBoundingBox;
357
CalculateBoundingBox(ColorRgbaBoundingBox & cbb,const RgbaBitmap & bitmap,int blockX,int blockY)358 static void CalculateBoundingBox(ColorRgbaBoundingBox& cbb, const RgbaBitmap& bitmap, int blockX, int blockY)
359 {
360 int size = bitmap.GetBitmapWidth();
361 const ColorRgba<unsigned char>* data = bitmap.GetData() + blockY * 4 * size + blockX * 4;
362
363 cbb.min = data[0];
364 cbb.max = data[0];
365
366 cbb |= data[1];
367 cbb |= data[2];
368 cbb |= data[3];
369
370 cbb |= data[size];
371 cbb |= data[size+1];
372 cbb |= data[size+2];
373 cbb |= data[size+3];
374
375 cbb |= data[2*size];
376 cbb |= data[2*size+1];
377 cbb |= data[2*size+2];
378 cbb |= data[2*size+3];
379
380 cbb |= data[3*size];
381 cbb |= data[3*size+1];
382 cbb |= data[3*size+2];
383 cbb |= data[3*size+3];
384 }
385
EncodeRgba4Bpp(void * result,const RgbaBitmap & bitmap)386 void PvrTcEncoder::EncodeRgba4Bpp(void* result, const RgbaBitmap& bitmap)
387 {
388 assert(bitmap.GetBitmapWidth() == bitmap.GetBitmapHeight());
389 assert(BitUtility::IsPowerOf2(bitmap.GetBitmapWidth()));
390 const int size = bitmap.GetBitmapWidth();
391 const int blocks = size / 4;
392 const int blockMask = blocks-1;
393
394 PvrTcPacket* packets = static_cast<PvrTcPacket*>(result);
395
396 for(int y = 0; y < blocks; ++y)
397 {
398 for(int x = 0; x < blocks; ++x)
399 {
400 ColorRgbaBoundingBox cbb;
401 CalculateBoundingBox(cbb, bitmap, x, y);
402 PvrTcPacket* packet = packets + GetMortonNumber(x, y);
403 packet->usePunchthroughAlpha = 0;
404 packet->SetColorA(cbb.min);
405 packet->SetColorB(cbb.max);
406 }
407 }
408
409 for(int y = 0; y < blocks; ++y)
410 {
411 for(int x = 0; x < blocks; ++x)
412 {
413 const unsigned char (*factor)[4] = PvrTcPacket::BILINEAR_FACTORS;
414 const ColorRgba<unsigned char>* data = bitmap.GetData() + y * 4 * size + x * 4;
415
416 uint32_t modulationData = 0;
417
418 for(int py = 0; py < 4; ++py)
419 {
420 const int yOffset = (py < 2) ? -1 : 0;
421 const int y0 = (y + yOffset) & blockMask;
422 const int y1 = (y0+1) & blockMask;
423
424 for(int px = 0; px < 4; ++px)
425 {
426 const int xOffset = (px < 2) ? -1 : 0;
427 const int x0 = (x + xOffset) & blockMask;
428 const int x1 = (x0+1) & blockMask;
429
430 const PvrTcPacket* p0 = packets + GetMortonNumber(x0, y0);
431 const PvrTcPacket* p1 = packets + GetMortonNumber(x1, y0);
432 const PvrTcPacket* p2 = packets + GetMortonNumber(x0, y1);
433 const PvrTcPacket* p3 = packets + GetMortonNumber(x1, y1);
434
435 ColorRgba<int> ca = p0->GetColorRgbaA() * (*factor)[0] +
436 p1->GetColorRgbaA() * (*factor)[1] +
437 p2->GetColorRgbaA() * (*factor)[2] +
438 p3->GetColorRgbaA() * (*factor)[3];
439
440 ColorRgba<int> cb = p0->GetColorRgbaB() * (*factor)[0] +
441 p1->GetColorRgbaB() * (*factor)[1] +
442 p2->GetColorRgbaB() * (*factor)[2] +
443 p3->GetColorRgbaB() * (*factor)[3];
444
445 const ColorRgba<unsigned char>& pixel = data[py*size + px];
446 ColorRgba<int> d = cb - ca;
447 ColorRgba<int> p;
448 p.r=pixel.r*16;
449 p.g=pixel.g*16;
450 p.b=pixel.b*16;
451 p.a=pixel.a*16;
452 ColorRgba<int> v = p - ca;
453
454 // PVRTC uses weightings of 0, 3/8, 5/8 and 1
455 // The boundaries for these are 3/16, 1/2 (=8/16), 13/16
456 int projection = (v % d) * 16;
457 int lengthSquared = d % d;
458 if(projection > 3*lengthSquared) modulationData++;
459 if(projection > 8*lengthSquared) modulationData++;
460 if(projection > 13*lengthSquared) modulationData++;
461
462 modulationData = BitUtility::RotateRight(modulationData, 2);
463
464 factor++;
465 }
466 }
467
468 PvrTcPacket* packet = packets + GetMortonNumber(x, y);
469 packet->modulationData = modulationData;
470 }
471 }
472 }
473
474 //============================================================================
475