bool ezImageConversion::IsConvertible(ezImageFormat::Enum sourceFormat, ezImageFormat::Enum targetFormat) { if (!s_conversionTableValid) { RebuildConversionTable(); } ezUInt32 tableIndex = MakeKey(sourceFormat, targetFormat); return s_conversionTable.Contains(tableIndex); }
ezResult ezImageConversionBase::Convert(const ezImage& source, ezImage& target, ezImageFormat::Enum targetFormat) { ezImageFormat::Enum sourceFormat = source.GetImageFormat(); // Trivial copy if (sourceFormat == targetFormat) { target = source; return EZ_SUCCESS; } if (!s_bConversionTableValid) { RebuildConversionTable(); } ezUInt32 uiCurrentTableIndex = GetTableIndex(sourceFormat, targetFormat); // No conversion known if (s_conversionTable[uiCurrentTableIndex] == nullptr) { return EZ_FAILURE; } const ezImageConversionBase* pConversion = s_conversionTable[uiCurrentTableIndex]; const SubConversion& subConversion = pConversion->m_subConversions[s_subConversionTable[uiCurrentTableIndex]]; if (subConversion.m_targetFormat == targetFormat) { if (&source == &target && !subConversion.m_flags.IsSet(ezImageConversionFlags::InPlace)) { ezImage copy = source; return pConversion->DoConvert(copy, target, subConversion.m_targetFormat); } else { return pConversion->DoConvert(source, target, subConversion.m_targetFormat); } } else { ezImage intermediate; if (pConversion->DoConvert(source, intermediate, subConversion.m_targetFormat) == EZ_FAILURE) { return EZ_FAILURE; } return Convert(intermediate, target, targetFormat); } }
ezImageFormat::Enum ezImageConversionBase::FindClosestCompatibleFormat(ezImageFormat::Enum format, const ezImageFormat::Enum* pCompatibleFormats, ezUInt32 uiNumCompatible) { if (!s_bConversionTableValid) { RebuildConversionTable(); } float fBestCost = ezMath::BasicType<float>::GetInfinity(); ezImageFormat::Enum bestFormat = ezImageFormat::UNKNOWN; for (ezUInt32 uiTargetIndex = 0; uiTargetIndex < uiNumCompatible; uiTargetIndex++) { float fCost = s_costTable[GetTableIndex(format, pCompatibleFormats[uiTargetIndex])]; if (fCost < fBestCost) { fBestCost = fCost; bestFormat = pCompatibleFormats[uiTargetIndex]; } } return bestFormat; }
ezImageFormat::Enum ezImageConversion::FindClosestCompatibleFormat(ezImageFormat::Enum format, ezArrayPtr<const ezImageFormat::Enum> compatibleFormats) { if (!s_conversionTableValid) { RebuildConversionTable(); } TableEntry bestEntry; ezImageFormat::Enum bestFormat = ezImageFormat::UNKNOWN; for (ezUInt32 targetIndex = 0; targetIndex < ezUInt32(compatibleFormats.GetCount()); targetIndex++) { ezUInt32 tableIndex = MakeKey(format, compatibleFormats[targetIndex]); TableEntry candidate; if (s_conversionTable.TryGetValue(tableIndex, candidate) && candidate < bestEntry) { bestEntry = candidate; bestFormat = compatibleFormats[targetIndex]; } } return bestFormat; }
ezResult ezImageConversion::BuildPath(ezImageFormat::Enum sourceFormat, ezImageFormat::Enum targetFormat, bool bSourceEqualsTarget, ezHybridArray<ezImageConversion::ConversionPathNode, 16>& path_out, ezUInt32& numScratchBuffers_out) { path_out.Clear(); numScratchBuffers_out = 0; if (sourceFormat == targetFormat) { ConversionPathNode node; node.m_sourceFormat = sourceFormat; node.m_targetFormat = targetFormat; node.m_inPlace = bSourceEqualsTarget; node.m_sourceBufferIndex = 0; node.m_targetBufferIndex = 0; node.m_step = nullptr; path_out.PushBack(node); return EZ_SUCCESS; } if (!s_conversionTableValid) { RebuildConversionTable(); } for (ezImageFormat::Enum current = sourceFormat; current != targetFormat;) { ezUInt32 currentTableIndex = MakeKey(current, targetFormat); TableEntry entry; if (!s_conversionTable.TryGetValue(currentTableIndex, entry)) { return EZ_FAILURE; } ezImageConversion::ConversionPathNode step; step.m_sourceFormat = entry.m_sourceFormat; step.m_targetFormat = entry.m_targetFormat; step.m_inPlace = entry.m_flags.IsAnySet(ezImageConversionFlags::InPlace); step.m_step = entry.m_step; current = entry.m_targetFormat; path_out.PushBack(step); } ezHybridArray<IntermediateBuffer, 16> scratchBuffers; scratchBuffers.PushBack(IntermediateBuffer(ezImageFormat::GetBitsPerBlock(targetFormat))); for (int i = path_out.GetCount() - 1; i >= 0; --i) { if (i == path_out.GetCount() - 1) path_out[i].m_targetBufferIndex = 0; else path_out[i].m_targetBufferIndex = path_out[i + 1].m_sourceBufferIndex; if (i > 0) { if (path_out[i].m_inPlace) { path_out[i].m_sourceBufferIndex = path_out[i].m_targetBufferIndex; } else { ezUInt32 bitsPerBlock = ezImageFormat::GetBitsPerBlock(path_out[i].m_sourceFormat); path_out[i].m_sourceBufferIndex = allocateScratchBufferIndex(scratchBuffers, bitsPerBlock, path_out[i].m_targetBufferIndex); } } } if (bSourceEqualsTarget) { // Enforce constraint that source == target path_out[0].m_sourceBufferIndex = 0; // Did we accidentally break the in-place invariant? if (path_out[0].m_sourceBufferIndex == path_out[0].m_targetBufferIndex && !path_out[0].m_inPlace) { if (path_out.GetCount() == 1) { // Only a single step, so we need to add a copy step ezImageConversion::ConversionPathNode copy; copy.m_inPlace = false; copy.m_sourceFormat = sourceFormat; copy.m_targetFormat = sourceFormat; copy.m_sourceBufferIndex = path_out[0].m_sourceBufferIndex; copy.m_targetBufferIndex = allocateScratchBufferIndex(scratchBuffers, ezImageFormat::GetBitsPerBlock(path_out[0].m_sourceFormat), path_out[0].m_sourceBufferIndex); path_out[0].m_sourceBufferIndex = copy.m_targetBufferIndex; copy.m_step = nullptr; path_out.Insert(copy, 0); } else { // Turn second step to non-inplace path_out[1].m_inPlace = false; path_out[1].m_sourceBufferIndex = allocateScratchBufferIndex( scratchBuffers, ezImageFormat::GetBitsPerBlock(path_out[1].m_sourceFormat), path_out[0].m_sourceBufferIndex); path_out[0].m_targetBufferIndex = path_out[1].m_sourceBufferIndex; } } } else { path_out[0].m_sourceBufferIndex = scratchBuffers.GetCount(); } numScratchBuffers_out = scratchBuffers.GetCount() - 1; return EZ_SUCCESS; }