Skip to content

Commit 6197c08

Browse files
committed
feat: drop old image_c data, use only GLI textures
Using GLI's texture2d_array class to carry image data allows us to now represent texture arrays and mipmap sets in a single image object while also indicating the data type more precisely.
1 parent ed0a2f9 commit 6197c08

7 files changed

Lines changed: 247 additions & 365 deletions

File tree

engine/core/core_image.cpp

Lines changed: 79 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -35,69 +35,49 @@ image_c::image_c(IConsole* conHnd)
3535
: con(conHnd)
3636
{}
3737

38-
void image_c::CopyRaw(int inType, dword inWidth, dword inHeight, const byte* inDat)
38+
bool image_c::CopyRaw(int type, dword inWidth, dword inHeight, const byte* inDat)
3939
{
40-
// Populate legacy fields
41-
comp = inType & 0xF;
42-
type = inType;
43-
width = inWidth;
44-
height = inHeight;
45-
46-
// Populate gli texture
47-
PopulateTex(inDat);
48-
}
40+
gli::format format = gli::format::FORMAT_UNDEFINED;
41+
const glm::ivec2 extent{ inWidth, inHeight };
42+
if (type == IMGTYPE_NONE)
43+
tex = {};
44+
45+
if (type > IMGTYPE_RGBA)
46+
return false;
4947

50-
void image_c::Free()
51-
{
52-
tex = {};
53-
}
48+
if (inWidth >= (1 << 15) || inHeight >= (1 << 15))
49+
return false;
5450

55-
//TODO(zao): Make this function only care about unpacked source data.
56-
void image_c::PopulateTex(const byte* dat)
57-
{
58-
gli::format format = gli::format::FORMAT_UNDEFINED;
59-
const glm::ivec2 extent{ width, height };
60-
size_t dataSize = width * height * comp; // Common default for regular formats.
61-
62-
const auto PhysicalSize = [](dword width, dword height, dword blockSize, dword side = 4) -> dword {
63-
dword numBlocks = ((width + side - 1) / side) * ((height + side - 1) / side);
64-
return numBlocks * blockSize;
65-
};
66-
switch ((imageType_s)type) {
67-
case imageType_s::IMGTYPE_NONE:
51+
const int comp = type & 0xF;
52+
size_t dataSize = extent.x * extent.y * comp;
53+
54+
switch (comp) {
55+
case 0:
6856
tex = {};
69-
return;
70-
case imageType_s::IMGTYPE_GRAY:
71-
format = gli::format::FORMAT_R8_SRGB_PACK8;
72-
break;
73-
case imageType_s::IMGTYPE_RGB:
74-
format = gli::format::FORMAT_RGB8_SRGB_PACK8;
75-
break;
76-
case imageType_s::IMGTYPE_RGBA:
77-
format = gli::format::FORMAT_RGBA8_SNORM_PACK8;
78-
break;
79-
case imageType_s::IMGTYPE_RGBA_BC1:
80-
format = gli::format::FORMAT_RGBA_DXT1_SRGB_BLOCK8;
81-
dataSize = PhysicalSize(width, height, 8);
57+
return false;
58+
case 1:
59+
format = gli::format::FORMAT_L8_UNORM_PACK8;
8260
break;
83-
case imageType_s::IMGTYPE_RGBA_BC2:
84-
format = gli::format::FORMAT_RGBA_DXT3_SRGB_BLOCK16;
85-
dataSize = PhysicalSize(width, height, 16);
61+
case 3:
62+
format = gli::format::FORMAT_RGB8_UNORM_PACK8;
8663
break;
87-
case imageType_s::IMGTYPE_RGBA_BC3:
88-
format = gli::format::FORMAT_RGBA_DXT5_SRGB_BLOCK16;
89-
dataSize = PhysicalSize(width, height, 16);
64+
case 4:
65+
format = gli::format::FORMAT_RGBA8_UNORM_PACK8;
9066
break;
91-
case imageType_s::IMGTYPE_RGBA_BC7:
92-
format = gli::format::FORMAT_RGBA_BP_SRGB_BLOCK16;
93-
dataSize = PhysicalSize(width, height, 16);
67+
default:
68+
return false;
9469
}
95-
96-
tex = gli::texture2d(format, extent, 1);
70+
tex = gli::texture2d_array(format, extent, 1, 1);
9771
if (tex.size(0) == dataSize)
98-
memcpy(tex.data(0, 0, 0), dat, dataSize);
72+
memcpy(tex.data(0, 0, 0), inDat, dataSize);
9973
else
10074
assert(tex.size(0) == dataSize);
75+
return true;
76+
}
77+
78+
void image_c::Free()
79+
{
80+
tex = {};
10181
}
10282

10383
bool image_c::Load(const char* fileName, std::optional<size_callback_t> sizeCallback)
@@ -202,10 +182,10 @@ bool targa_c::Load(const char* fileName, std::optional<size_callback_t> sizeCall
202182
}
203183

204184
// Read image
205-
width = hdr.width;
206-
height = hdr.height;
207-
comp = hdr.depth >> 3;
208-
type = ittable[it_m][2];
185+
dword width = hdr.width;
186+
dword height = hdr.height;
187+
int comp = hdr.depth >> 3;
188+
int type = ittable[it_m][2];
209189
int rowSize = width * comp;
210190
std::vector<byte> datBuf(height * rowSize);
211191
byte* dat = datBuf.data();
@@ -253,30 +233,30 @@ bool targa_c::Load(const char* fileName, std::optional<size_callback_t> sizeCall
253233
}
254234
}
255235

256-
PopulateTex(dat);
257-
258-
return false;
236+
return !CopyRaw(type, width, height, dat);
259237
}
260238

261239
bool targa_c::Save(const char* fileName)
262240
{
263-
if (type != IMGTYPE_RGB && type != IMGTYPE_RGBA) {
241+
auto format = tex.format();
242+
if (is_compressed(format) || !is_unsigned_integer(format))
243+
return true;
244+
245+
int comp = (int)component_count(format);
246+
if (comp != 3 && comp != 4)
264247
return true;
265-
}
266248

267249
// Open file
268250
fileOutputStream_c out;
269251
if (out.FileOpen(fileName, true)) {
270252
return true;
271253
}
272254

273-
if (is_compressed(tex.format()))
274-
return true;
275-
255+
auto extent = tex.extent();
276256
auto rc = stbi_write_tga_to_func([](void* ctx, void* data, int size) {
277257
auto out = (fileOutputStream_c*)ctx;
278258
out->Write(data, size);
279-
}, &out, width, height, comp, tex.data(0, 0, 0));
259+
}, &out, extent.x, extent.y, comp, tex.data(0, 0, 0));
280260

281261
return !rc;
282262
}
@@ -304,7 +284,7 @@ bool jpeg_c::Load(const char* fileName, std::optional<size_callback_t> sizeCallb
304284
return true;
305285
}
306286
if (in_comp != 1 && in_comp != 3) {
307-
con->Warning("JPEG '%s': unsupported component count '%d'", fileName, comp);
287+
con->Warning("JPEG '%s': unsupported component count '%d'", fileName, in_comp);
308288
return true;
309289
}
310290
if (sizeCallback)
@@ -315,37 +295,35 @@ bool jpeg_c::Load(const char* fileName, std::optional<size_callback_t> sizeCallb
315295
stbi_image_free(data);
316296
return true;
317297
}
318-
width = x;
319-
height = y;
320-
comp = in_comp;
321-
type = in_comp == 1 ? IMGTYPE_GRAY : IMGTYPE_RGB;
322298

323-
PopulateTex(data);
299+
bool success = CopyRaw(in_comp == 1 ? IMGTYPE_GRAY : IMGTYPE_RGB, x, y, data);
324300
stbi_image_free(data);
325301

326-
return false;
302+
return !success;
327303
}
328304

329305
bool jpeg_c::Save(const char* fileName)
330306
{
331307
// JPEG only supports RGB and grayscale images
332-
if (type != IMGTYPE_RGB && type != IMGTYPE_GRAY) {
308+
auto format = tex.format();
309+
if (is_compressed(format) || !is_unsigned_integer(format))
310+
return true;
311+
312+
int comp = (int)component_count(format);
313+
if (comp != 1 && comp != 3)
333314
return true;
334-
}
335315

336316
// Open the file
337317
fileOutputStream_c out;
338318
if (out.FileOpen(fileName, true)) {
339319
return true;
340320
}
341321

342-
if (is_compressed(tex.format()))
343-
return true;
344-
322+
auto extent = tex.extent();
345323
int rc = stbi_write_jpg_to_func([](void* ctx, void* data, int size) {
346324
auto out = (fileOutputStream_c*)ctx;
347325
out->Write(data, size);
348-
}, &out, width, height, comp, tex.data(0, 0, 0), quality);
326+
}, &out, extent.x, extent.y, comp, tex.data(0, 0, 0), quality);
349327
return !rc;
350328
}
351329

@@ -372,41 +350,46 @@ bool png_c::Load(const char* fileName, std::optional<size_callback_t> sizeCallba
372350
return true;
373351
}
374352

375-
width = x;
376-
height = y;
353+
dword width = x;
354+
dword height = y;
377355
if (sizeCallback)
378356
(*sizeCallback)(width, height);
379357

380-
comp = (in_comp == 1 || in_comp == 3) ? 3 : 4;
381-
type = comp == 3 ? IMGTYPE_RGB : IMGTYPE_RGBA;
358+
int comp = (in_comp == 1 || in_comp == 3) ? 3 : 4;
359+
int type = comp == 3 ? IMGTYPE_RGB : IMGTYPE_RGBA;
382360
stbi_uc* data = stbi_load_from_memory(fileData.data(), (int)fileData.size(), &x, &y, &in_comp, comp);
383361
if (!data) {
384362
stbi_image_free(data);
385363
return true;
386364
}
387365

388-
PopulateTex(data);
366+
bool success = CopyRaw(type, width, height, data);
389367
stbi_image_free(data);
390368

391-
return false;
369+
return !success;
392370
}
393371

394372
bool png_c::Save(const char* fileName)
395373
{
396-
if (type != IMGTYPE_RGB && type != IMGTYPE_RGBA) {
374+
auto format = tex.format();
375+
if (is_compressed(format) || !is_unsigned_integer(format))
376+
return true;
377+
378+
int comp = (int)component_count(format);
379+
if (comp != 3 && comp != 4)
397380
return true;
398-
}
399381

400382
// Open file
401383
fileOutputStream_c out;
402384
if (out.FileOpen(fileName, true)) {
403385
return true;
404386
}
405387

388+
auto extent = tex.extent();
406389
auto rc = stbi_write_png_to_func([](void* ctx, void* data, int size) {
407390
auto out = (fileOutputStream_c*)ctx;
408391
out->Write(data, size);
409-
}, &out, width, height, comp, tex.data(0, 0, 0), width * comp);
392+
}, &out, extent.x, extent.y, comp, tex.data(0, 0, 0), extent.x * comp);
410393

411394
return !rc;
412395
}
@@ -434,18 +417,15 @@ bool gif_c::Load(const char* fileName, std::optional<size_callback_t> sizeCallba
434417
stbi_image_free(data);
435418
return true;
436419
}
437-
width = x;
438-
height = y;
420+
dword width = x;
421+
dword height = y;
439422
if (sizeCallback)
440423
(*sizeCallback)(width, height);
441424

442-
comp = in_comp;
443-
type = IMGTYPE_RGBA;
444-
445-
PopulateTex(data);
425+
bool success = CopyRaw(IMGTYPE_RGBA, width, height, data);
446426
stbi_image_free(data);
447427

448-
return false;
428+
return !success;
449429
}
450430
}
451431

@@ -490,6 +470,9 @@ bool jpeg_xl_c::Load(const char* fileName, std::optional<size_callback_t> sizeCa
490470
JxlDecoderCloseInput(dec.get());
491471

492472
std::vector<byte> datBuf;
473+
int width{};
474+
int height{};
475+
int comp{};
493476

494477
while (true) {
495478
JxlDecoderStatus status = JxlDecoderProcessInput(dec.get());
@@ -507,13 +490,7 @@ bool jpeg_xl_c::Load(const char* fileName, std::optional<size_callback_t> sizeCa
507490
if (sizeCallback)
508491
(*sizeCallback)(width, height);
509492
comp = info.num_color_channels + !!info.alpha_bits;
510-
if (comp == 1)
511-
type = IMGTYPE_GRAY;
512-
else if (comp == 3)
513-
type = IMGTYPE_RGB;
514-
else if (comp == 4)
515-
type = IMGTYPE_RGBA;
516-
else
493+
if (comp != 1 && comp != 3 && comp != 4)
517494
return true;
518495

519496
if (runner)
@@ -535,8 +512,7 @@ bool jpeg_xl_c::Load(const char* fileName, std::optional<size_callback_t> sizeCa
535512
case JXL_DEC_SUCCESS:
536513
case JXL_DEC_FULL_IMAGE: {
537514
// We don't care about animations, consider loading completed when a full image has obtained.
538-
PopulateTex(datBuf.data());
539-
return false;
515+
return !CopyRaw(g_imageTypeFromComp[comp], width, height, datBuf.data());
540516
} break;
541517

542518
default:

engine/core/core_image.h

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include <functional>
1212
#include <optional>
1313

14-
#include <gli/texture2d.hpp>
14+
#include <gli/texture2d_array.hpp>
1515

1616
// Image types
1717
enum imageType_s {
@@ -32,17 +32,20 @@ enum imageType_s {
3232
IMGTYPE_RGBA_BC7 = 0xD4,
3333
};
3434

35+
constexpr imageType_s g_imageTypeFromComp[]{
36+
IMGTYPE_NONE,
37+
IMGTYPE_GRAY,
38+
IMGTYPE_NONE,
39+
IMGTYPE_RGB,
40+
IMGTYPE_RGBA,
41+
};
42+
3543
// Image
3644
class image_c {
3745
public:
38-
dword width = 0;
39-
dword height = 0;
40-
int comp = 0;
41-
int type = 0;
42-
4346
// This `tex` member supersedes the past raw data and metadata fields in order to hold
4447
// both unblocked and blocked texture formats with array layers and mip levels.
45-
gli::texture2d tex{};
48+
gli::texture2d_array tex{};
4649

4750
explicit image_c(IConsole* conHnd = NULL);
4851
virtual ~image_c() = default;
@@ -54,9 +57,8 @@ class image_c {
5457
virtual bool Load(const char* fileName, std::optional<size_callback_t> sizeCallback = {});
5558
virtual bool Save(const char* fileName);
5659

57-
void CopyRaw(int type, dword width, dword height, const byte* dat);
60+
bool CopyRaw(int type, dword width, dword height, const byte* dat);
5861
void Free();
59-
void PopulateTex(const byte* inDat);
6062

6163
static image_c* LoaderForFile(IConsole* conHnd, const char* fileName);
6264
};

0 commit comments

Comments
 (0)