Skip to content

Commit f2e3aee

Browse files
SGI loader: enabled uncompressed images
1 parent 4193bdd commit f2e3aee

File tree

1 file changed

+103
-60
lines changed

1 file changed

+103
-60
lines changed

TextureLoader/src/SGILoader.cpp

Lines changed: 103 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2022 Diligent Graphics LLC
2+
* Copyright 2019-2024 Diligent Graphics LLC
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,6 +26,8 @@
2626

2727
#include "SGILoader.h"
2828

29+
#include <cstring>
30+
2931
#include "DataBlob.h"
3032
#include "PlatformMisc.hpp"
3133
#include "Errors.hpp"
@@ -82,13 +84,13 @@ bool LoadSGI(IDataBlob* pSGIData,
8284
return false;
8385
}
8486

85-
const auto Width = PlatformMisc::SwapBytes(Header.WidthBE);
86-
const auto Height = PlatformMisc::SwapBytes(Header.HeightBE);
87-
const auto NumChannels = PlatformMisc::SwapBytes(Header.ChannelsBE);
88-
const auto BytesPerChannel = Header.BytePerPixelChannel;
89-
pDstImgDesc->Width = Width;
90-
pDstImgDesc->Height = Height;
91-
pDstImgDesc->NumComponents = NumChannels;
87+
const Uint32 Width = PlatformMisc::SwapBytes(Header.WidthBE);
88+
const Uint32 Height = PlatformMisc::SwapBytes(Header.HeightBE);
89+
const Uint32 NumChannels = PlatformMisc::SwapBytes(Header.ChannelsBE);
90+
const Uint32 BytesPerChannel = Header.BytePerPixelChannel;
91+
pDstImgDesc->Width = Width;
92+
pDstImgDesc->Height = Height;
93+
pDstImgDesc->NumComponents = NumChannels;
9294

9395
switch (BytesPerChannel)
9496
{
@@ -113,72 +115,113 @@ bool LoadSGI(IDataBlob* pSGIData,
113115
pDstPixels->Resize(size_t{Height} * pDstImgDesc->RowStride);
114116
auto* pDstPtr = reinterpret_cast<Uint8*>(pDstPixels->GetDataPtr());
115117

116-
// Offsets table starts at byte 512 and is Height * NumChannels * 4 bytes long.
117-
const auto TableSize = sizeof(Uint32) * Height * NumChannels;
118-
const auto* OffsetTableBE = reinterpret_cast<const Uint32*>(pSrcPtr);
119-
pSrcPtr += TableSize;
120-
if (pSrcPtr > pDataEnd)
121-
return false;
122-
123-
// Length table follows the offsets table and is the same size.
124-
const auto* LengthTableBE = reinterpret_cast<const Uint32*>(pSrcPtr);
125-
pSrcPtr += TableSize;
126-
if (pSrcPtr > pDataEnd)
127-
return false;
118+
if (Header.Compression == 0)
119+
{
120+
// Uncompressed SGI image
128121

129-
VERIFY(Header.Compression, "Only RLE compressed files are currently supported");
130-
VERIFY(BytesPerChannel == 1, "Only 8-bit images are currently supported");
122+
const size_t UncompressedSize = size_t{Width} * Height * NumChannels * BytesPerChannel;
123+
if (pSrcPtr + UncompressedSize > pDataEnd)
124+
{
125+
LOG_ERROR_MESSAGE("Not enough data for uncompressed image.");
126+
return false;
127+
}
131128

132-
const auto ReadLine = [Width, BytesPerChannel, NumChannels](auto* pDst, const auto* pLineDataStart, const auto* pLineDataEnd) //
129+
const size_t PlaneSize = size_t{Width} * Height * BytesPerChannel;
130+
for (size_t y = 0; y < Height; ++y)
131+
{
132+
for (size_t x = 0; x < Width; ++x)
133+
{
134+
// Copy each channel from the respective plane
135+
for (size_t c = 0; c < NumChannels; ++c)
136+
{
137+
const Uint8* pSrcPlane = pSrcPtr + PlaneSize * c;
138+
const size_t PixelIdx = y * Width + x;
139+
140+
// Copy channel
141+
std::memcpy(
142+
pDstPtr + (PixelIdx * NumChannels + c) * BytesPerChannel,
143+
pSrcPlane + PixelIdx * BytesPerChannel,
144+
BytesPerChannel);
145+
}
146+
}
147+
}
148+
}
149+
else if (Header.Compression == 1)
133150
{
134-
VERIFY_EXPR(sizeof(*pDst) == BytesPerChannel);
135-
VERIFY_EXPR(sizeof(*pLineDataStart) == BytesPerChannel);
136-
(void)BytesPerChannel;
151+
// RLE-compressed SGI image
137152

138-
const auto* pSrc = pLineDataStart;
153+
// Offsets table starts at byte 512 and is Height * NumChannels * 4 bytes long.
154+
const auto TableSize = sizeof(Uint32) * Height * NumChannels;
155+
const auto* OffsetTableBE = reinterpret_cast<const Uint32*>(pSrcPtr);
156+
pSrcPtr += TableSize;
157+
if (pSrcPtr > pDataEnd)
158+
return false;
159+
160+
// Length table follows the offsets table and is the same size.
161+
const auto* LengthTableBE = reinterpret_cast<const Uint32*>(pSrcPtr);
162+
pSrcPtr += TableSize;
163+
if (pSrcPtr > pDataEnd)
164+
return false;
139165

140-
Uint32 x = 0;
141-
while (x < Width && pSrc < pLineDataEnd)
166+
//VERIFY(Header.Compression, "Only RLE compressed files are currently supported");
167+
VERIFY(BytesPerChannel == 1, "Only 8-bit images are currently supported");
168+
169+
const auto ReadLine = [Width, BytesPerChannel, NumChannels](auto* pDst, const auto* pLineDataStart, const auto* pLineDataEnd) //
142170
{
143-
// The lowest 7 bits is the counter
144-
int Count = *pSrc & 0x7F;
171+
VERIFY_EXPR(sizeof(*pDst) == BytesPerChannel);
172+
VERIFY_EXPR(sizeof(*pLineDataStart) == BytesPerChannel);
173+
(void)BytesPerChannel;
145174

146-
// If the high order bit of the first byte is 1, then the count is used to specify how many values to copy
147-
// from the RLE data buffer.
148-
// If the high order bit of the first byte is 0, then the count is used to specify how many times to repeat
149-
// the value following the counter.
150-
auto DistinctValues = (*pSrc & 0x80) != 0;
175+
const auto* pSrc = pLineDataStart;
151176

152-
++pSrc;
153-
while (Count > 0 && pSrc < pLineDataEnd)
177+
Uint32 x = 0;
178+
while (x < Width && pSrc < pLineDataEnd)
154179
{
155-
*pDst = *pSrc;
156-
if (DistinctValues || Count == 1) // Always move the pointer for the last value
157-
++pSrc;
158-
159-
pDst += NumChannels;
160-
--Count;
161-
++x;
180+
// The lowest 7 bits is the counter
181+
int Count = *pSrc & 0x7F;
182+
183+
// If the high order bit of the first byte is 1, then the count is used to specify how many values to copy
184+
// from the RLE data buffer.
185+
// If the high order bit of the first byte is 0, then the count is used to specify how many times to repeat
186+
// the value following the counter.
187+
auto DistinctValues = (*pSrc & 0x80) != 0;
188+
189+
++pSrc;
190+
while (Count > 0 && pSrc < pLineDataEnd)
191+
{
192+
*pDst = *pSrc;
193+
if (DistinctValues || Count == 1) // Always move the pointer for the last value
194+
++pSrc;
195+
196+
pDst += NumChannels;
197+
--Count;
198+
++x;
199+
}
162200
}
163-
}
164-
return x == Width;
165-
};
201+
return x == Width;
202+
};
166203

167-
for (Uint32 c = 0; c < NumChannels; ++c)
168-
{
169-
for (Uint32 y = 0; y < Height; ++y)
204+
for (Uint32 c = 0; c < NumChannels; ++c)
170205
{
171-
// Each unsigned int in the offset table is the offset (from the file start) to the
172-
// start of the compressed data of each scanline for each channel.
173-
const auto RleOff = PlatformMisc::SwapBytes(OffsetTableBE[y + c * Height]);
174-
// The size table tells the size of the compressed data (unsigned int) of each scanline.
175-
const auto RleLen = PlatformMisc::SwapBytes(LengthTableBE[y + c * Height]);
176-
177-
auto* DstLine = pDstPtr + y * size_t{pDstImgDesc->RowStride} + c;
178-
if (!ReadLine(DstLine, pDataStart + RleOff, pSrcPtr + RleOff + RleLen))
179-
return false;
206+
for (Uint32 y = 0; y < Height; ++y)
207+
{
208+
// Each unsigned int in the offset table is the offset (from the file start) to the
209+
// start of the compressed data of each scanline for each channel.
210+
const auto RleOff = PlatformMisc::SwapBytes(OffsetTableBE[y + c * Height]);
211+
// The size table tells the size of the compressed data (unsigned int) of each scanline.
212+
const auto RleLen = PlatformMisc::SwapBytes(LengthTableBE[y + c * Height]);
213+
214+
auto* DstLine = pDstPtr + y * size_t{pDstImgDesc->RowStride} + c;
215+
if (!ReadLine(DstLine, pDataStart + RleOff, pSrcPtr + RleOff + RleLen))
216+
return false;
217+
}
180218
}
181219
}
220+
else
221+
{
222+
LOG_ERROR_MESSAGE("Unsupported compression value.");
223+
return false;
224+
}
182225

183226
return true;
184227
}

0 commit comments

Comments
 (0)