Files
UnrealEngine/Engine/Source/ThirdParty/etc2comp/EtcTool/EtcSourceImage.cpp
2025-05-18 13:04:45 +08:00

293 lines
7.2 KiB
C++

/*
* Copyright 2015 The Etc2Comp Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS (1)
#endif
#include "EtcConfig.h"
#include "EtcSourceImage.h"
#include "Etc.h"
#if USE_STB_IMAGE_LOAD
#include "stb_image.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "lodepng.h"
namespace Etc
{
// ----------------------------------------------------------------------------------------------------
//
SourceImage::SourceImage(const char *a_pstrFilename, int a_iPixelX, int a_iPixelY)
{
m_pstrFilename = nullptr;
m_pstrName = nullptr;
m_pstrFileExtension = nullptr;
m_uiWidth = 0;
m_uiHeight = 0;
m_pafrgbaPixels = nullptr;
SetName(a_pstrFilename);
Read(a_iPixelX, a_iPixelY);
}
// ----------------------------------------------------------------------------------------------------
//
SourceImage::SourceImage(ColorFloatRGBA *a_pafrgbaSource,
unsigned int a_uiSourceWidth,
unsigned int a_uiSourceHeight)
{
m_pstrFilename = nullptr;
m_pstrName = nullptr;
m_pstrFileExtension = nullptr;
m_uiWidth = a_uiSourceWidth;
m_uiHeight = a_uiSourceHeight;
m_pafrgbaPixels = a_pafrgbaSource;
}
// ----------------------------------------------------------------------------------------------------
//
SourceImage::~SourceImage()
{
if (m_pstrFilename != nullptr)
{
delete[] m_pstrFilename;
m_pstrFilename = nullptr;
}
if (m_pstrName != nullptr)
{
delete[] m_pstrName;
m_pstrName = nullptr;
m_pstrFileExtension = nullptr;
}
if (m_pafrgbaPixels != nullptr)
{
delete[] m_pafrgbaPixels;
m_pafrgbaPixels = nullptr;
}
m_uiWidth = 0;
m_uiHeight = 0;
}
// ----------------------------------------------------------------------------------------------------
//
void SourceImage::Read(int a_iPixelX, int a_iPixelY)
{
unsigned char* paucPixels = nullptr;
int iWidth = 0;
int iHeight = 0;
bool bool16BitImage = false;
#if USE_STB_IMAGE_LOAD
int iBitsPerPixel;
//if stb_iamge is available, only use it to load files other than png
char *fileExt = strrchr(m_pstrFilename, '.');
if (strcmp(fileExt, ".png") != 0)
{
paucPixels = stbi_load(m_pstrFilename, &iWidth, &iHeight, &iBitsPerPixel, 4);
if (paucPixels == nullptr)
{
printf("stb_image error %s\n", stbi_failure_reason());
assert(0);
exit(1);
}
}
#endif
if (paucPixels == nullptr)
{
//we can load 8 or 16 bit pngs
int iBitDepth = 16;
int error = lodepng_decode_file(&paucPixels,
(unsigned int*)&iWidth, (unsigned int*)&iHeight,
m_pstrFilename,
LCT_RGBA, iBitDepth);
bool16BitImage = (iBitDepth == 16) ? true : false;
if (error)
{
printf("lodePNG error %u: %s\n", error, lodepng_error_text(error));
assert(0);
exit(1);
}
}
//the pixel cords for the top left corner of the block
int iBlockX = 0;
int iBlockY = 0;
if (a_iPixelX > -1 && a_iPixelY > -1)
{
// in 1 block mode, we basically will have an img thats 4x4
m_uiWidth = 4;
m_uiHeight = 4;
if(a_iPixelX > iWidth)
a_iPixelX = iWidth;
if (a_iPixelY > iHeight)
a_iPixelY = iHeight;
// remove the bottom 2 bits to get the block coordinates
iBlockX = (a_iPixelX & 0xFFFFFFFC);
iBlockY = (a_iPixelY & 0xFFFFFFFC);
}
else
{
m_uiWidth = iWidth;
m_uiHeight = iHeight;
}
m_pafrgbaPixels = new ColorFloatRGBA[m_uiWidth * m_uiHeight];
assert(m_pafrgbaPixels);
int iBytesPerPixel = bool16BitImage ? 8 : 4;
unsigned char *pucPixel; // = &paucPixels[(iBlockY * iWidth + iBlockX) * iBytesPerPixel];
ColorFloatRGBA *pfrgbaPixel = m_pafrgbaPixels;
// convert pixels from RGBA* to ColorFloatRGBA
for (unsigned int uiV = iBlockY; uiV < (iBlockY+m_uiHeight); ++uiV)
{
// reset coordinate for each row
pucPixel = &paucPixels[(uiV * iWidth + iBlockX) * iBytesPerPixel];
// read each row
for (unsigned int uiH = iBlockX; uiH < (iBlockX+m_uiWidth); ++uiH)
{
if (bool16BitImage)
{
unsigned short ushR = (pucPixel[0]<<8) + pucPixel[1];
unsigned short ushG = (pucPixel[2]<<8) + pucPixel[3];
unsigned short ushB = (pucPixel[4]<<8) + pucPixel[5];
unsigned short ushA = (pucPixel[6]<<8) + pucPixel[7];
*pfrgbaPixel++ = ColorFloatRGBA((float)ushR / 65535.0f,
(float)ushG / 65535.0f,
(float)ushB / 65535.0f,
(float)ushA / 65535.0f);
}
else
{
*pfrgbaPixel++ = ColorFloatRGBA::ConvertFromRGBA8(pucPixel[0], pucPixel[1],
pucPixel[2], pucPixel[3]);
}
pucPixel += iBytesPerPixel;
}
}
#if USE_STB_IMAGE_LOAD
stbi_image_free(paucPixels);
#else
free(paucPixels);
#endif
}
// ----------------------------------------------------------------------------------------------------
// sets m_pstrFilename, m_pstrName and m_pstrFileExtension
//
void SourceImage::SetName(const char *a_pstrFilename)
{
if (a_pstrFilename == nullptr)
{
return;
}
m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
strcpy(m_pstrFilename, a_pstrFilename);
m_pstrName = new char[strlen(m_pstrFilename) + 1];
// ignore directory path
char *pcLastSlash = strrchr(m_pstrFilename, '/');
char *pcLastBackSlash = strrchr(m_pstrFilename, '\\');
if (pcLastSlash == nullptr && pcLastBackSlash == nullptr)
{
strcpy(m_pstrName, m_pstrFilename);
}
else if (pcLastSlash > pcLastBackSlash)
{
strcpy(m_pstrName, pcLastSlash + 1);
}
else
{
strcpy(m_pstrName, pcLastBackSlash + 1);
}
// find file extension and remove it from image name
char *pcLastPeriod = strrchr(m_pstrName, '.');
if (pcLastPeriod != nullptr)
{
m_pstrFileExtension = pcLastPeriod + 1;
*strrchr(m_pstrName, '.') = 0;
}
}
// ----------------------------------------------------------------------------------------------------
//
void SourceImage::NormalizeXYZ(void)
{
int iPixels = m_uiWidth * m_uiHeight;
ColorFloatRGBA *pfrgbaPixel = m_pafrgbaPixels;
for (int iPixel = 0; iPixel < iPixels; iPixel++)
{
float fX = 2.0f*pfrgbaPixel->fR - 1.0f;
float fY = 2.0f*pfrgbaPixel->fG - 1.0f;
float fZ = 2.0f*pfrgbaPixel->fB - 1.0f;
float fLength2 = fX*fX + fY*fY + fZ*fZ;
if (fLength2 == 0.0f)
{
pfrgbaPixel->fR = 1.0f;
pfrgbaPixel->fG = 0.0f;
pfrgbaPixel->fB = 0.0f;
}
else
{
float fLength = sqrtf(fLength2);
float fNormalizedX = fX / fLength;
float fNormalizedY = fY / fLength;
float fNormalizedZ = fZ / fLength;
pfrgbaPixel->fR = 0.5f * (fNormalizedX + 1.0f);
pfrgbaPixel->fG = 0.5f * (fNormalizedY + 1.0f);
pfrgbaPixel->fB = 0.5f * (fNormalizedZ + 1.0f);
}
pfrgbaPixel++;
}
}
// ----------------------------------------------------------------------------------------------------
//
} // namespace Etc