Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support loading glb with compressed jpeg textures #545

Merged
merged 3 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion graphics/include/gz/common/Image.hh
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,11 @@ namespace gz
BAYER_GBRG8,
BAYER_GRBG8,
COMPRESSED_PNG,
PIXEL_FORMAT_COUNT
PIXEL_FORMAT_COUNT,
// \todo(iche033) COMPRESSED_JPEG is added at the end to
// preserve ABI compatibility. Move this enum up when merging
// forward to main
COMPRESSED_JPEG
};


Expand Down
25 changes: 21 additions & 4 deletions graphics/src/AssimpLoader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@
const aiNode* _node, const math::Matrix4d& _transform, Mesh* _mesh) const
{
if (!_node)
return;

Check warning on line 199 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L199

Added line #L199 was not covered by tests
// Visit this node, add the submesh
for (unsigned meshIdx = 0; meshIdx < _node->mNumMeshes; ++meshIdx)
{
Expand All @@ -221,7 +221,7 @@
SkeletonNode *skelNode =
skeleton->NodeByName(boneNodeName);
if (skelNode == nullptr)
continue;

Check warning on line 224 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L224

Added line #L224 was not covered by tests
skelNode->SetInverseBindTransform(
this->ConvertTransform(bone->mOffsetMatrix));
for (unsigned weightIdx = 0; weightIdx < bone->mNumWeights; ++weightIdx)
Expand Down Expand Up @@ -267,7 +267,7 @@
std::unordered_set<std::string>& _boneNames) const
{
if (!_node)
return;

Check warning on line 270 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L270

Added line #L270 was not covered by tests

for (unsigned meshIdx = 0; meshIdx < _node->mNumMeshes; ++meshIdx)
{
Expand Down Expand Up @@ -295,7 +295,7 @@
const std::unordered_set<std::string> &_boneNames) const
{
if (_node == nullptr || _parent == nullptr)
return;

Check warning on line 298 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L298

Added line #L298 was not covered by tests
// First explore this node
auto nodeName = ToString(_node->mName);
auto boneExist = _boneNames.find(nodeName) != _boneNames.end();
Expand Down Expand Up @@ -510,57 +510,74 @@
}

std::pair<ImagePtr, ImagePtr>
AssimpLoader::Implementation::SplitMetallicRoughnessMap(

Check warning on line 513 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L513

Added line #L513 was not covered by tests
const common::Image& _img) const
{
std::pair<ImagePtr, ImagePtr> ret;

Check warning on line 516 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L516

Added line #L516 was not covered by tests
// Metalness in B roughness in G
const auto width = _img.Width();
const auto height = _img.Height();
const auto bytesPerPixel = 4;

Check warning on line 520 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L518-L520

Added lines #L518 - L520 were not covered by tests

std::vector<unsigned char> metalnessData(width * height * bytesPerPixel);
std::vector<unsigned char> roughnessData(width * height * bytesPerPixel);

Check warning on line 523 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L522-L523

Added lines #L522 - L523 were not covered by tests

for (unsigned int y = 0; y < height; ++y)

Check warning on line 525 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L525

Added line #L525 was not covered by tests
{
for (unsigned int x = 0; x < width; ++x)

Check warning on line 527 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L527

Added line #L527 was not covered by tests
{
// RGBA so 4 bytes per pixel, alpha fully opaque
auto baseIndex = bytesPerPixel * (y * width + x);
auto color = _img.Pixel(x, (height - y - 1));
metalnessData[baseIndex] = color.B() * 255.0;
metalnessData[baseIndex + 1] = color.B() * 255.0;
metalnessData[baseIndex + 2] = color.B() * 255.0;
metalnessData[baseIndex + 3] = 255;
roughnessData[baseIndex] = color.G() * 255.0;
roughnessData[baseIndex + 1] = color.G() * 255.0;
roughnessData[baseIndex + 2] = color.G() * 255.0;
roughnessData[baseIndex + 3] = 255;

Check warning on line 539 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L530-L539

Added lines #L530 - L539 were not covered by tests
}
}
// First is metal, second is rough
ret.first = std::make_shared<Image>();
ret.first->SetFromData(&metalnessData[0], width, height, Image::RGBA_INT8);
ret.second = std::make_shared<Image>();
ret.second->SetFromData(&roughnessData[0], width, height, Image::RGBA_INT8);
return ret;

Check warning on line 547 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L543-L547

Added lines #L543 - L547 were not covered by tests
}

//////////////////////////////////////////////////
ImagePtr AssimpLoader::Implementation::LoadEmbeddedTexture(
const aiTexture* _texture) const
{
auto img = std::make_shared<Image>();
if (_texture->mHeight == 0)
{
Image::PixelFormatType format = Image::PixelFormatType::UNKNOWN_PIXEL_FORMAT;
if (_texture->CheckFormat("png"))
{
img->SetFromCompressedData((unsigned char*)_texture->pcData,
_texture->mWidth, Image::PixelFormatType::COMPRESSED_PNG);
format = Image::PixelFormatType::COMPRESSED_PNG;
}
else if (_texture->CheckFormat("jpg"))
{
format = Image::PixelFormatType::COMPRESSED_JPEG;
}
if (format != Image::PixelFormatType::UNKNOWN_PIXEL_FORMAT)
{
auto img = std::make_shared<Image>();
img->SetFromCompressedData(
reinterpret_cast<unsigned char *>(_texture->pcData),
_texture->mWidth, format);
return img;
}
else
{
gzerr << "Unable to load embedded texture. "
<< "Unsupported compressed image format"
<< std::endl;

Check warning on line 577 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L575-L577

Added lines #L575 - L577 were not covered by tests
}
}
return img;
return ImagePtr();

Check warning on line 580 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L580

Added line #L580 was not covered by tests
}

//////////////////////////////////////////////////
Expand Down Expand Up @@ -747,7 +764,7 @@
SkeletonNode *node = queue.front();
queue.pop();
if (nullptr == node)
continue;

Check warning on line 767 in graphics/src/AssimpLoader.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/AssimpLoader.cc#L767

Added line #L767 was not covered by tests

if (node->HasInvBindTransform())
{
Expand Down
33 changes: 33 additions & 0 deletions graphics/src/AssimpLoader_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,39 @@ TEST_F(AssimpLoader, LoadGlTF2BoxExternalTexture)
EXPECT_EQ(testTextureFile, mat->TextureImage());
}

/////////////////////////////////////////////////
// This test loads a box glb mesh with embedded compressed jpeg texture
TEST_F(AssimpLoader, LoadGlTF2BoxWithJPEGTexture)
{
common::AssimpLoader loader;
common::Mesh *mesh = loader.Load(
common::testing::TestFile("data", "box_texture_jpg.glb"));

EXPECT_STREQ("unknown", mesh->Name().c_str());
EXPECT_EQ(math::Vector3d(1, 1, 1), mesh->Max());
EXPECT_EQ(math::Vector3d(-1, -1, -1), mesh->Min());

EXPECT_EQ(24u, mesh->VertexCount());
EXPECT_EQ(24u, mesh->NormalCount());
EXPECT_EQ(36u, mesh->IndexCount());
EXPECT_EQ(24u, mesh->TexCoordCount());
EXPECT_EQ(1u, mesh->SubMeshCount());
EXPECT_EQ(1u, mesh->MaterialCount());

// Make sure we can read the submesh name
EXPECT_STREQ("Cube", mesh->SubMeshByIndex(0).lock()->Name().c_str());

const common::MaterialPtr mat = mesh->MaterialByIndex(0u);
ASSERT_TRUE(mat.get());

// Make sure we read the material color values
EXPECT_EQ(math::Color(0.4f, 0.4f, 0.4f, 1.0f), mat->Ambient());
EXPECT_EQ(math::Color(1.0f, 1.0f, 1.0f, 1.0f), mat->Diffuse());
EXPECT_EQ(math::Color(0.0f, 0.0f, 0.0f, 1.0f), mat->Specular());
EXPECT_EQ("Cube_Material_Diffuse", mat->TextureImage());
EXPECT_NE(nullptr, mat->TextureData());
}

/////////////////////////////////////////////////
// Use a fully featured glb test asset, including PBR textures, emissive maps
// embedded textures, lightmaps, animations to test advanced glb features
Expand Down
16 changes: 14 additions & 2 deletions graphics/src/Image.cc
Original file line number Diff line number Diff line change
Expand Up @@ -239,17 +239,17 @@
bluemask = 0xff0000;
scanlineBytes = _width * 3;
}
else if ((_format == BAYER_RGGB8) ||
(_format == BAYER_BGGR8) ||
(_format == BAYER_GBRG8) ||

Check warning on line 244 in graphics/src/Image.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/Image.cc#L242-L244

Added lines #L242 - L244 were not covered by tests
(_format == BAYER_GRBG8))
{
bpp = 8;
scanlineBytes = _width;

Check warning on line 248 in graphics/src/Image.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/Image.cc#L247-L248

Added lines #L247 - L248 were not covered by tests
}
else
{
gzerr << "Unable to handle format[" << _format << "]\n";

Check warning on line 252 in graphics/src/Image.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/Image.cc#L252

Added line #L252 was not covered by tests
return;
}

Expand All @@ -274,10 +274,22 @@
FreeImage_Unload(this->dataPtr->bitmap);
this->dataPtr->bitmap = nullptr;

if (_format == COMPRESSED_PNG)
FREE_IMAGE_FORMAT format = FIF_UNKNOWN;
switch (_format)
{
case COMPRESSED_PNG:
format = FIF_PNG;
break;
case COMPRESSED_JPEG:
format = FIF_JPEG;
break;
default:
break;
}
if (format != FIF_UNKNOWN)
{
FIMEMORY *fiMem = FreeImage_OpenMemory(_data, _size);
this->dataPtr->bitmap = FreeImage_LoadFromMemory(FIF_PNG, fiMem);
this->dataPtr->bitmap = FreeImage_LoadFromMemory(format, fiMem);
FreeImage_CloseMemory(fiMem);
}
else
Expand Down Expand Up @@ -396,7 +408,7 @@
}
else
{
data = this->dataPtr->DataImpl(this->dataPtr->bitmap);

Check warning on line 411 in graphics/src/Image.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/Image.cc#L411

Added line #L411 was not covered by tests
}
return data;
}
Expand Down Expand Up @@ -525,10 +537,10 @@
}
else
{
if (this->dataPtr->PixelIndex(
this->dataPtr->bitmap, _x, _y, clr) == FALSE)

Check warning on line 541 in graphics/src/Image.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/Image.cc#L540-L541

Added lines #L540 - L541 were not covered by tests
{
gzerr << "Image: Coordinates out of range ["

Check warning on line 543 in graphics/src/Image.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/Image.cc#L543

Added line #L543 was not covered by tests
<< _x << " " << _y << "] \n";
return clr;
}
Expand Down Expand Up @@ -590,7 +602,7 @@
if (FALSE ==
FreeImage_GetPixelColor(this->dataPtr->bitmap, x, y, &firgb))
{
gzerr << "Image: Coordinates out of range["

Check warning on line 605 in graphics/src/Image.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/Image.cc#L605

Added line #L605 was not covered by tests
<< x << " " << y << "] \n";
continue;
}
Expand All @@ -614,7 +626,7 @@
if (this->dataPtr->PixelIndex(
this->dataPtr->bitmap, x, y, clr) == FALSE)
{
gzerr << "Image: Coordinates out of range ["

Check warning on line 629 in graphics/src/Image.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/Image.cc#L629

Added line #L629 was not covered by tests
<< x << " " << y << "] \n";
continue;
}
Expand All @@ -635,7 +647,7 @@
FIBITMAP *_dib, unsigned _x, unsigned _y, math::Color &_color) const
{
if (!_dib)
return FALSE;

Check warning on line 650 in graphics/src/Image.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/Image.cc#L650

Added line #L650 was not covered by tests

FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(_dib);
// 8 bit images
Expand All @@ -646,7 +658,7 @@
if (FreeImage_GetPixelIndex(
_dib, _x, _y, &byteValue) == FALSE)
{
return FALSE;

Check warning on line 661 in graphics/src/Image.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/Image.cc#L661

Added line #L661 was not covered by tests
}

unsigned int bpp = FreeImage_GetBPP(_dib);
Expand All @@ -667,7 +679,7 @@
}
else
{
return FALSE;

Check warning on line 682 in graphics/src/Image.cc

View check run for this annotation

Codecov / codecov/patch

graphics/src/Image.cc#L682

Added line #L682 was not covered by tests
}
}
return TRUE;
Expand Down
Binary file added test/data/box_texture_jpg.glb
Binary file not shown.
Loading