Cogs.Core
RasterConversion.cpp
1#include "RasterConversion.h"
2
3#if defined( _WIN32 )
4 #pragma warning(push)
5 #pragma warning(disable:4244)
6#endif
7
8#define STB_DXT_IMPLEMENTATION
9#include "stb_dxt.h"
10
11#if defined( _WIN32 )
12 #pragma warning(pop)
13#endif
14
15#include "../ClipmapTerrainTypes.h"
16
17bool Cogs::isCompressible(TextureFormat format)
18{
19 return format == TextureFormat::R8G8B8_UNORM ||
20 format == TextureFormat::R8G8B8A8_UNORM ||
21 format == TextureFormat::R8G8B8A8_UNORM_SRGB;
22}
23
24Cogs::TextureFormat Cogs::getCompressedFormat(TextureFormat format)
25{
26 switch (format)
27 {
28 case TextureFormat::R8G8B8_UNORM:
29 return TextureFormat::BC3_UNORM;
30 case TextureFormat::R8G8B8A8_UNORM:
31 return TextureFormat::BC3_UNORM;
32 case TextureFormat::R8G8B8A8_UNORM_SRGB:
33 return TextureFormat::BC3_UNORM_SRGB;
34 default:
35 return TextureFormat::Unknown;
36 break;
37 }
38}
39
40bool Cogs::isConvertible(TextureFormat format)
41{
42 return format == TextureFormat::B8G8R8 ||
43 format == TextureFormat::B8G8R8A8 ||
44 format == TextureFormat::R8G8B8_UNORM;
45}
46
47Cogs::TextureFormat Cogs::compressTileData(std::vector<uint8_t> & destination,
48 const uint8_t * source,
49 TextureFormat sourceFormat,
50 int width,
51 int height)
52{
53 const auto targetFormat = getCompressedFormat(sourceFormat);
54
55 const size_t numBlocksX = width / 4;
56 const size_t numBlocksY = height / 4;
57
58 const size_t bpp = Cogs::getBlockSize(sourceFormat);
59 const bool hasAlpha = bpp == 4;
60
61 const size_t rowStride = width * bpp;
62
63 assert(destination.size() >= (numBlocksX * numBlocksY * 16) && "Destination buffer too small.");
64
65 auto d = destination.data();
66
67 for (size_t y = 0; y < numBlocksY; ++y) {
68 for (size_t x = 0; x < numBlocksX; ++x) {
69 uint8_t pixels[4 * 4 * 4];
70
71 for (int yy = 0; yy < 4; ++yy) {
72 for (int xx = 0; xx < 4; ++xx) {
73 const size_t sourceIndex = (4 * y * rowStride) + (yy * rowStride) + (x * 4 * bpp) + xx * bpp;
74
75 pixels[yy * 16 + xx * 4 + 0] = source[sourceIndex + 0];
76 pixels[yy * 16 + xx * 4 + 1] = source[sourceIndex + 1];
77 pixels[yy * 16 + xx * 4 + 2] = source[sourceIndex + 2];
78 pixels[yy * 16 + xx * 4 + 3] = hasAlpha ? source[sourceIndex + 3] : 255;
79 }
80 }
81
82 stb_compress_dxt_block(d, pixels, hasAlpha ? 1 : 0, STB_DXT_NORMAL);
83 d += 16;
84 }
85 }
86
87 return targetFormat;
88}
89
90Cogs::TextureFormat Cogs::convertBitmapData(const uint8_t * data,
91 const TileData * tileData,
92 std::vector<uint8_t> & destination)
93{
94 if (tileData->shouldConvert() && !Cogs::isConvertible(tileData->format)) {
95 return TextureFormat::Unknown;
96 }
97
98 const bool swizzle = tileData->shouldConvert() &&
99 (tileData->format == TextureFormat::B8G8R8 || tileData->format == TextureFormat::B8G8R8A8);
100 const int r = swizzle ? 2 : 0;
101 const int b = swizzle ? 0 : 2;
102
103 auto targetFormat = tileData->shouldConvert() ?
104 (tileData->isLinear() ? TextureFormat::R8G8B8A8_UNORM : TextureFormat::R8G8B8A8_UNORM_SRGB) :
105 tileData->format;
106
107 const size_t width = tileData->width;
108 const size_t height = tileData->height;
109 const size_t stride = tileData->stride;
110 const bool flip = tileData->shouldFlip();
111 const size_t bpp = Cogs::getBlockSize(tileData->format);
112
113 destination.resize(getTextureSize(static_cast<int>(width), static_cast<int>(height), targetFormat));
114
115 for (size_t y = 0; y < height; ++y) {
116 size_t targetLine = flip ? (height - 1 - y) * width : y * width;
117
118 for (size_t x = 0; x < width; ++x) {
119 size_t i = bpp * x;
120 size_t j = 4 * (targetLine + x);
121
122 destination[j + 0] = data[i + r];
123 destination[j + 1] = data[i + 1];
124 destination[j + 2] = data[i + b];
125 destination[j + 3] = bpp == 4 ? data[i + 3] : 255;
126 }
127
128 data += stride ? stride : width * 4;
129 }
130
131 return targetFormat;
132}