// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "MuR/Mesh.h" #include "MuR/Platform.h" #include "MuR/MutableMath.h" #include "Math/Float16.h" namespace mu { //--------------------------------------------------------------------------------------------- //! Convert one channel element //--------------------------------------------------------------------------------------------- inline void ConvertData ( int channel, void* pResult, EMeshBufferFormat resultFormat, const void* pSource, EMeshBufferFormat sourceFormat ) { switch ( resultFormat ) { case EMeshBufferFormat::Float64: { double* pTypedResult = reinterpret_cast(pResult); uint8* pByteResult = reinterpret_cast(pResult); const uint8* pByteSource = reinterpret_cast(pSource); switch (sourceFormat) { case EMeshBufferFormat::Float64: { // Just dereferencing is not safe in all architectures. some like ARM require the // floats to be 4-byte aligned and it may not be the case. We need memcpy. memcpy(pByteResult + 8 * channel, pByteSource + 8* channel, 8); break; } case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::Int32: { const int32* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); break; } case EMeshBufferFormat::UInt32: { const uint32* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); break; } case EMeshBufferFormat::Int16: { const int16* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); break; } case EMeshBufferFormat::UInt16: { const uint16* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); break; } case EMeshBufferFormat::Int8: { const int8* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); break; } case EMeshBufferFormat::UInt8: { const uint8* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); break; } case EMeshBufferFormat::NInt32: { const int32* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); pTypedResult[channel] /= 65536.0f * 65536.0f / 2.0f; break; } case EMeshBufferFormat::NUInt32: { const uint32* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); pTypedResult[channel] /= 65536.0f * 65536.0f - 1.0f; break; } case EMeshBufferFormat::NInt16: { const int16* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); pTypedResult[channel] /= 32768.0f; break; } case EMeshBufferFormat::NUInt16: { const uint16* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); pTypedResult[channel] /= 65535.0f; break; } case EMeshBufferFormat::NInt8: { const int8* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); pTypedResult[channel] /= 128.0f; break; } case EMeshBufferFormat::NUInt8: { const uint8* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); pTypedResult[channel] /= 255.0f; break; } case EMeshBufferFormat::PackedDir8: case EMeshBufferFormat::PackedDir8_W_TangentSign: { const uint8* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); pTypedResult[channel] /= 127.5f; pTypedResult[channel] -= 1.0f; break; } case EMeshBufferFormat::PackedDirS8: case EMeshBufferFormat::PackedDirS8_W_TangentSign: { const int8* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (double)(pTypedSource[channel]); pTypedResult[channel] /= 127.5f; break; } default: checkf(false, TEXT("Conversion not implemented.")); break; } break; } case EMeshBufferFormat::Float32: { float* pTypedResult = reinterpret_cast( pResult ); uint8* pByteResult = reinterpret_cast( pResult ); const uint8* pByteSource = reinterpret_cast( pSource ); switch ( sourceFormat ) { case EMeshBufferFormat::Float64: { const double* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = float(pTypedSource[channel]); break; } case EMeshBufferFormat::Float32: { // Just dereferencing is not safe in all architectures. some like ARM require the // floats to be 4-byte aligned and it may not be the case. We need memcpy. memcpy(pByteResult + 4 * channel, pByteSource + 4 * channel, 4); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::Int32: { const int32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); break; } case EMeshBufferFormat::UInt32: { const uint32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); break; } case EMeshBufferFormat::Int16: { const int16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); break; } case EMeshBufferFormat::UInt16: { const uint16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); break; } case EMeshBufferFormat::Int8: { const int8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); break; } case EMeshBufferFormat::UInt8: { const uint8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); break; } case EMeshBufferFormat::NInt32: { const int32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); pTypedResult[channel] /= 65536.0f*65536.0f/2.0f; break; } case EMeshBufferFormat::NUInt32: { const uint32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); pTypedResult[channel] /= 65536.0f*65536.0f-1.0f; break; } case EMeshBufferFormat::NInt16: { const int16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); pTypedResult[channel] /= 32768.0f; break; } case EMeshBufferFormat::NUInt16: { const uint16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); pTypedResult[channel] /= 65535.0f; break; } case EMeshBufferFormat::NInt8: { const int8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); pTypedResult[channel] /= 128.0f; break; } case EMeshBufferFormat::NUInt8: { const uint8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); pTypedResult[channel] /= 255.0f; break; } case EMeshBufferFormat::PackedDir8: case EMeshBufferFormat::PackedDir8_W_TangentSign: { const uint8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); pTypedResult[channel] /= 127.5f; pTypedResult[channel] -= 1.0f; break; } case EMeshBufferFormat::PackedDirS8: case EMeshBufferFormat::PackedDirS8_W_TangentSign: { const int8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); pTypedResult[channel] /= 127.5f; break; } default: checkf( false, TEXT("Conversion not implemented.") ); break; } break; } //----------------------------------------------------------------------------------------- case EMeshBufferFormat::Float16: { FFloat16* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::UInt32: { const uint32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); break; } case EMeshBufferFormat::Int32: { const int32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); break; } case EMeshBufferFormat::UInt16: { const uint16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); break; } case EMeshBufferFormat::Int16: { const int16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); break; } case EMeshBufferFormat::UInt8: { const uint8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); break; } case EMeshBufferFormat::Int8: { const int8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (float)(pTypedSource[channel]); break; } default: checkf( false, TEXT("Conversion not implemented.") ); break; } break; } //----------------------------------------------------------------------------------------- case EMeshBufferFormat::UInt8: { uint8* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint8) FMath::Min( 0xFF, FMath::Max( 0, (uint32)(pTypedSource[channel]) ) ); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint8) FMath::Min( 0xFF, FMath::Max( 0, (uint32)float(pTypedSource[channel]) ) ); break; } case EMeshBufferFormat::Int8: { const int8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint8)FMath::Max( 0, pTypedSource[channel] ); break; } case EMeshBufferFormat::UInt8: { const uint8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::Int16: { const int16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint8) FMath::Min( 0xFF, FMath::Max( 0, pTypedSource[channel] ) ); break; } case EMeshBufferFormat::UInt16: { // Clamp const uint16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint8) FMath::Min( 0xFF, FMath::Max( 0, pTypedSource[channel] ) ); break; } case EMeshBufferFormat::Int32: { const int32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint8) FMath::Min( 0xFF, FMath::Max( 0, pTypedSource[channel] ) ); break; } case EMeshBufferFormat::UInt32: { // Clamp const uint32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint8) FMath::Min( 0xFF, FMath::Max( 0, pTypedSource[channel] ) ); break; } case EMeshBufferFormat::NUInt8: case EMeshBufferFormat::NUInt16: case EMeshBufferFormat::NUInt32: case EMeshBufferFormat::NInt8: case EMeshBufferFormat::NInt16: case EMeshBufferFormat::NInt32: pTypedResult = 0; break; default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } case EMeshBufferFormat::UInt16: { uint16* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint16) FMath::Min( 0xFFFF, FMath::Max( 0, (uint32)(pTypedSource[channel]) ) ); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint16) FMath::Min( 0xFF, FMath::Max( 0, (uint32)float(pTypedSource[channel]) ) ); break; } case EMeshBufferFormat::UInt8: { const uint8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::Int8: { const int8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint16)FMath::Max( 0, pTypedSource[channel] ); break; } case EMeshBufferFormat::UInt16: { const uint16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::Int16: { const int16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint16)FMath::Max( 0, pTypedSource[channel] ); break; } case EMeshBufferFormat::UInt32: { // Clamp const uint32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint16) FMath::Min( 0xFFFF, FMath::Max( 0, pTypedSource[channel] ) ); break; } case EMeshBufferFormat::Int32: { // Clamp const int32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint16) FMath::Min( 0xFFFF, FMath::Max( 0, pTypedSource[channel] ) ); break; } case EMeshBufferFormat::NUInt8: case EMeshBufferFormat::NUInt16: case EMeshBufferFormat::NUInt32: case EMeshBufferFormat::NInt8: case EMeshBufferFormat::NInt16: case EMeshBufferFormat::NInt32: pTypedResult = 0; break; default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } case EMeshBufferFormat::UInt32: { uint32* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = FMath::Min( 0xFFFF, FMath::Max( 0, (uint32)(pTypedSource[channel]) ) ); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = FMath::Min( 0xFF, FMath::Max( 0, (uint32)float(pTypedSource[channel]) ) ); break; } case EMeshBufferFormat::UInt8: { const uint8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::Int8: { const int8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint16)FMath::Max( 0, pTypedSource[channel] ); break; } case EMeshBufferFormat::UInt16: { const uint16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::Int16: { const int16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint16)FMath::Max( 0, pTypedSource[channel] ); break; } case EMeshBufferFormat::UInt32: { const uint32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::Int32: { // Clamp const int32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint32)FMath::Max( 0, pTypedSource[channel] ); break; } case EMeshBufferFormat::NUInt8: case EMeshBufferFormat::NUInt16: case EMeshBufferFormat::NUInt32: case EMeshBufferFormat::NInt8: case EMeshBufferFormat::NInt16: case EMeshBufferFormat::NInt32: pTypedResult = 0; break; default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } case EMeshBufferFormat::UInt64: { uint64* pTypedResult = reinterpret_cast(pResult); switch (sourceFormat) { case EMeshBufferFormat::UInt8: { const uint8* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::UInt16: { const uint16* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::UInt32: { const uint32* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::UInt64: { const uint64* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = pTypedSource[channel]; break; } default: checkf(false, TEXT("Conversion not implemented.")); break; } break; } case EMeshBufferFormat::Int8: { int8* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int8) FMath::Min( 127, FMath::Max( -128, (int32)(pTypedSource[channel]) ) ); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int8) FMath::Min( 127, FMath::Max( -128, (int32)float(pTypedSource[channel]) ) ); break; } case EMeshBufferFormat::Int8: { const int8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::NUInt8: case EMeshBufferFormat::NUInt16: case EMeshBufferFormat::NUInt32: case EMeshBufferFormat::NInt8: case EMeshBufferFormat::NInt16: case EMeshBufferFormat::NInt32: pTypedResult = 0; break; default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } case EMeshBufferFormat::Int16: { int16* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int16) FMath::Min( 32767, FMath::Max( -32768, (int32)(pTypedSource[channel]) ) ); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int16) FMath::Min( 32767, FMath::Max( -32768, (int32)float(pTypedSource[channel]) ) ); break; } case EMeshBufferFormat::Int8: { const int8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int16)pTypedSource[channel]; break; } case EMeshBufferFormat::UInt8: { const uint8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int16)pTypedSource[channel]; break; } case EMeshBufferFormat::UInt16: { const uint16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int16) FMath::Min( 32767, (int32)pTypedSource[channel] ); break; } case EMeshBufferFormat::Int32: { const int32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int16) FMath::Min( 32767, FMath::Max( -32768, pTypedSource[channel] ) ); break; } case EMeshBufferFormat::UInt32: { const uint32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int16) FMath::Min( 32767, pTypedSource[channel] ); break; } case EMeshBufferFormat::NUInt8: case EMeshBufferFormat::NUInt16: case EMeshBufferFormat::NUInt32: case EMeshBufferFormat::NInt8: case EMeshBufferFormat::NInt16: case EMeshBufferFormat::NInt32: pTypedResult = 0; break; default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } case EMeshBufferFormat::Int32: { int32* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int32)(pTypedSource[channel]); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int32)float(pTypedSource[channel]); break; } case EMeshBufferFormat::Int8: { const int8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int32)pTypedSource[channel]; break; } case EMeshBufferFormat::UInt8: { const uint8* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int32)pTypedSource[channel]; break; } case EMeshBufferFormat::Int16: { const int16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int32)pTypedSource[channel]; break; } case EMeshBufferFormat::UInt16: { const uint16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int32)pTypedSource[channel]; break; } case EMeshBufferFormat::UInt32: { const uint32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int32)pTypedSource[channel]; break; } case EMeshBufferFormat::Int32: { const int32* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::NUInt8: case EMeshBufferFormat::NUInt16: case EMeshBufferFormat::NUInt32: case EMeshBufferFormat::NInt8: case EMeshBufferFormat::NInt16: case EMeshBufferFormat::NInt32: pTypedResult = 0; break; default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } //----------------------------------------------------------------------------------------- case EMeshBufferFormat::NUInt8: { uint8* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::NUInt8: { const uint8* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::NUInt16: { const uint16* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = pTypedSource[channel] / (65535 / 255); break; } case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = (uint8) FMath::Min( 0xFF, FMath::Max( 0, (uint32)(((float)0xFF)*pTypedSource[channel] + 0.5f) ) ); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint8) FMath::Min( 0xFF, FMath::Max( 0, (uint32)(((float)0xFF)*float(pTypedSource[channel])+0.5f) ) ); break; } case EMeshBufferFormat::UInt8: case EMeshBufferFormat::UInt16: case EMeshBufferFormat::UInt32: case EMeshBufferFormat::Int8: case EMeshBufferFormat::Int16: case EMeshBufferFormat::Int32: // TODO: 1 or 0 pTypedResult = 0; break; default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } case EMeshBufferFormat::NUInt16: { uint16* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::NUInt16: { const uint16* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = pTypedSource[channel]; break; } case EMeshBufferFormat::NUInt8: { const uint8* pTypedSource = reinterpret_cast(pSource); pTypedResult[channel] = pTypedSource[channel] * (65535 / 255); break; } case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint16) FMath::Min( 0xFFFF, FMath::Max( 0, (uint32)(((float)0xFFFF)*pTypedSource[channel]+0.5f) ) ); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint16) FMath::Min( 0xFFFF, FMath::Max( 0, (uint32)(((float)0xFFFF)*float(pTypedSource[channel])+0.5f) ) ); break; } case EMeshBufferFormat::UInt8: case EMeshBufferFormat::UInt16: case EMeshBufferFormat::UInt32: case EMeshBufferFormat::Int8: case EMeshBufferFormat::Int16: case EMeshBufferFormat::Int32: // TODO: 1 or 0 pTypedResult = 0; break; default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } case EMeshBufferFormat::NUInt32: { uint32* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint32) FMath::Min( 0xFFFFFFFF, FMath::Max( 0, (uint32)(((float)0xFFFFFFFF)*pTypedSource[channel]) ) ); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (uint32) FMath::Min( 0xFFFFFFFF, FMath::Max( 0, (uint32)(((float)0xFFFFFFFF)*float(pTypedSource[channel])+0.5f) ) ); break; } case EMeshBufferFormat::UInt8: case EMeshBufferFormat::UInt16: case EMeshBufferFormat::UInt32: case EMeshBufferFormat::Int8: case EMeshBufferFormat::Int16: case EMeshBufferFormat::Int32: // TODO: 1 or 0 pTypedResult = 0; break; default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } case EMeshBufferFormat::NInt8: { int8* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int8) FMath::Min( 127, FMath::Max( -128, (int32)(128.0f*pTypedSource[channel]+0.5f) ) ); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int8) FMath::Min( 127, FMath::Max( -128, (int32)(128.0f*float(pTypedSource[channel])+0.5f) ) ); break; } case EMeshBufferFormat::UInt8: case EMeshBufferFormat::UInt16: case EMeshBufferFormat::UInt32: case EMeshBufferFormat::Int8: case EMeshBufferFormat::Int16: case EMeshBufferFormat::Int32: // TODO: -1, 1 or 0 pTypedResult = 0; break; default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } case EMeshBufferFormat::NInt16: { int16* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int16) FMath::Min( 32767, FMath::Max( -32768, (int32)(32768.0f*pTypedSource[channel]+0.5f) ) ); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int16) FMath::Min( 32767, FMath::Max( -32768, (int32)(32768.0f*float(pTypedSource[channel])+0.5f) ) ); break; } case EMeshBufferFormat::UInt8: case EMeshBufferFormat::UInt16: case EMeshBufferFormat::UInt32: case EMeshBufferFormat::Int8: case EMeshBufferFormat::Int16: case EMeshBufferFormat::Int32: // TODO: -1, 1 or 0 pTypedResult = 0; break; default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } case EMeshBufferFormat::NInt32: { int32* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int32)(2147483648.0f*pTypedSource[channel]+0.5f); break; } case EMeshBufferFormat::Float16: { const FFloat16* pTypedSource = reinterpret_cast( pSource ); pTypedResult[channel] = (int32)(2147483648.0f*float(pTypedSource[channel])+0.5f); break; } case EMeshBufferFormat::UInt8: case EMeshBufferFormat::UInt16: case EMeshBufferFormat::UInt32: case EMeshBufferFormat::Int8: case EMeshBufferFormat::Int16: case EMeshBufferFormat::Int32: // TODO: -1, 1 or 0 pTypedResult = 0; break; default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } case EMeshBufferFormat::PackedDir8: case EMeshBufferFormat::PackedDir8_W_TangentSign: { uint8* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::PackedDir8: case EMeshBufferFormat::PackedDir8_W_TangentSign: { const uint8* pTypedSource = reinterpret_cast( pSource ); uint8 source = pTypedSource[channel]; pTypedResult[channel] = source; break; } case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); float source = pTypedSource[channel]; source = (source*0.5f+0.5f)*255.0f; pTypedResult[channel] = (uint8)FMath::Min( 255.0f, FMath::Max( 0.0f, source ) ); break; } default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } case EMeshBufferFormat::PackedDirS8: case EMeshBufferFormat::PackedDirS8_W_TangentSign: { int8* pTypedResult = reinterpret_cast( pResult ); switch ( sourceFormat ) { case EMeshBufferFormat::PackedDirS8: case EMeshBufferFormat::PackedDirS8_W_TangentSign: { const int8* pTypedSource = reinterpret_cast( pSource ); int8 source = pTypedSource[channel]; pTypedResult[channel] = source; break; } case EMeshBufferFormat::Float32: { const float* pTypedSource = reinterpret_cast( pSource ); float source = pTypedSource[channel]; source = source*0.5f*255.0f; pTypedResult[channel] = (int8)FMath::Min( 127.0f, FMath::Max( -128.0f, source ) ); break; } default: checkf( false, TEXT("Conversion not implemented." ) ); break; } break; } default: checkf( false, TEXT("Conversion not implemented." ) ); break; } } }