Merge branch 'stabilization/2106' into AP_CacheCopyFailure

This commit is contained in:
amzn-mike
2021-06-21 08:13:32 -05:00
126 changed files with 28192 additions and 12788 deletions
@@ -1206,7 +1206,7 @@ namespace JsonSerializationTests
if (this->m_features.m_enableInitializationTest)
{
auto instance = this->m_description.CreateDefaultInstance();
typename TypeParam::Type compare;
typename TypeParam::Type compare = typename TypeParam::Type{};
if (!this->m_description.AreEqual(*instance, compare))
{
auto serializer = this->m_description.CreateSerializer();
@@ -44,6 +44,11 @@ namespace AzNetworking
//! @class IConnection
//! @brief interface class for network connections.
//!
//! IConnection provides a pure-virtual interface for all network connection types. IConnections provide access to
//! a ConnectionMetrics object which provides a variety of metrics on the connection itself such as data rate, RTT and
//! packet statistics.
class IConnection
{
public:
@@ -22,6 +22,12 @@ namespace AzNetworking
{
//! @class IConnectionListener
//! @brief interface class for application layer dealing with connection level events.
//!
//! IConnectionListener defines an abstract interface that the user of AzNetworking is expected to implement to react and
//! handle all IConnection related events, including the handling of any received IPacket derived packets. The AzNetworking
//! user should derive a handler class from IConnectionListener, and provide an instance of that handler to any
//! INetworkInterface the user instantiates. The lifetime of the IConnectionListener must outlive the lifetime of the
//! INetworkInterface.
class IConnectionListener
{
public:
@@ -18,6 +18,11 @@ namespace AzNetworking
{
//! @class IConnectionSet
//! @brief interface class for managing a set of connections.
//!
//! IConnectionSet defines a simple interface for working with an abstract set of IConnections bound to an
//! INetworkInterface. Generally users of AzNetworking will not have reason to interact directly with the IConnectionSet,
//! as its interface is completely wrapped by INetworkInterface.
class IConnectionSet
{
public:
@@ -23,10 +23,10 @@ namespace AzNetworking
//! Collection of compression related error codes
enum class CompressorError
{
Ok, ///< No error, operation finished successfully
InsufficientBuffer, ///< Buffer size is insufficient for the operation to complete, increase the size and try again
CorruptData, ///< Malformed or hacked packet, potentially security issue
Uninitialized ///< Compressor or supplied buffers are uninitialized
Ok, //!< No error, operation finished successfully
InsufficientBuffer, //!< Buffer size is insufficient for the operation to complete, increase the size and try again
CorruptData, //!< Malformed or hacked packet, potentially security issue
Uninitialized //!< Compressor or supplied buffers are uninitialized
};
//! Unique identifier of a given compressor
@@ -34,6 +34,12 @@ namespace AzNetworking
//! @class ICompressor
//! @brief Packet data compressor interface.
//!
//! ICompressor is an abstract compression interface meant for user provided GEMs to implement (such as the [Multiplayer
//! Compression Gem](http://docs.o3de.org/docs/user-guide/gems/reference/multiplayer-compression)).
//! Compression is supported for both TCP and UDP connections. Instantiation of a compressor is controlled by the
//! `net_UdpCompressor` or `net_TcpCompressor` cvar for their respective protocols.
class ICompressor
{
public:
@@ -87,8 +93,16 @@ namespace AzNetworking
) = 0;
};
//! Abstract factory to instantiate compressors.
//! Used by the network interface to create a compressor
//! @class ICompressorFactory
//! @brief Abstract factory to instantiate compressors.
//!
//! ICompressorFactory is an abstract compression interface meant for user provided GEMs to implement. ICompressorFactory
//! implementations can be registered to classes implementing INetworking. Registered factories can then be used to create
//! ICompressor implementations on demand. The [Multiplayer Compression
//! Gem](http://docs.o3de.org/docs/user-guide/gems/reference/multiplayer-compression) is an example of an ICompressorFactory
//! for an LZ4 Compressor. In it, MultiplayerCompressionSystemComponent registers its ICompressorFactory with
//! NetworkingSystemComponent, which is an implementation of INetworking. Registered factories are keyed by their AZ Name
//! which is accessed through the factory's GetFactoryName method.
class ICompressorFactory
{
public:
@@ -22,7 +22,16 @@
namespace AzNetworking
{
//! @class INetworkInterface
//! @brief pure virtual network interface class to abstract client/server and tcp/udp concerns from application code.
//! @brief Network interface class to abstract client/server and protocol concerns from application code.
//!
//! INetworkInterface provides an abstract API capable of receiving and opening IConnection objects, sending IPacket objects with optional
//! reliability, and determining the delivery status of packets that have been sent unreliably (delivery of reliable packets
//! is guaranteed as long as the associated connection remains open). INetworkInterface must be provided an
//! IConnectionListener instance that outlives the INetworkInterface itself. The INetworkInterface also creates and manages
//! the IConnectionSet, which tracks all open connections bound to the interface. INetworkInterface also provides GetMetrics
//! functions which can be used to fetch a struct detailing a variety of metrics relating to send and receive rates for both
//! packets and bytes in addition to the effect of features on those rates (such as packet size reduction due to compression.)
class INetworkInterface
{
public:
@@ -23,6 +23,17 @@ namespace AzNetworking
//! @class INetworking
//! @brief The interface for creating and working with network interfaces.
//!
//! INetworking is an Az::Interface<T> that provides applications access to higher level networking abstractions.
//! AzNetworking::INetworking can be used to instantiate new INetworkInterfaces that can be configured to operate over
//! either TCP or UDP, enable or disable encryption, and be assigned a trust level.
//!
//! INetworking is also responsible for registering ICompressorFactory implementations. This allows a developer to have
//! access to multiple ICompressorFactory implementations by name. The [MultiplayerCompressor
//! Gem](http://docs.o3de.org/docs/user-guide/gems/reference/multiplayer-compression) is an example of this using the
//! [LZ4](https://wikipedia.org/wiki/LZ4_%28compression_algorithm%29) algorithm.
//!
class INetworking
{
public:
@@ -24,6 +24,15 @@ namespace AzNetworking
//! @class IPacket
//! @brief Base class for all packets.
//!
//! IPacket defines an abstract interface that all packets transmitted using AzNetworking must conform to. While there are
//! a number of core packets used internally by AzNetworking, it is fully possible for end-users to define their own custom
//! packets using this interface. PacketType should be distinct, and should be greater than
//! AzNetworking::CorePackets::MAX. The Serialize method allows the IPacket to be used by an
//! ISerializer to move data between hosts safely and efficiently.
//!
//! For more information on the packet format and best practices for extending the packet system, read
//! [Networking Packets](http://docs.o3de.org/docs/user-guide/networking/packets) on the O3DE documentation site.
class IPacket
{
public:
@@ -28,6 +28,19 @@ namespace AzNetworking
//! @class IPacketHeader
//! @brief A packet header that lets us deduce packet type for any incoming packet.
//!
//! IPacketHeader defines an abstract interface for a descriptor of all AzNetworking::IPacket sent through AzNetworking. The
//! PacketHeader is used to identify and describe the contents of a Packet so that transport logic can identify what
//! additional processing steps need to be taken (if any) and what type of Packet is being inspected.
//!
//! The PacketFlags portion of the header represents the first byte of the header. While it can be encrypted it is
//! otherwise not exposed to additional processing (such as an AzNetworking::ICompressor). PacketFlags are a bitfield use to provide up
//! front information about the state of the packet. Currently there is only one flag to indicate if the Packet is
//! compressed or not.
//!
//! The remainder of the header contains the PacketType and the PacketId. While the PacketFlags byte is exempt from most
//! additional forms of processing, the remainder of the header is not.
class IPacketHeader
{
public:
@@ -27,6 +27,18 @@ namespace AzNetworking
//! @class ISerializer
//! @brief Interface class for all serializers to derive from.
//!
//! ISerializer defines an abstract interface for visiting an object hierarchy and performing operations upon that hierarchy,
//! typically reading from or writing data to the object hierarchy for reasons of persistence or network transmission.
//!
//! While the most common types of serializers are provided by the AzNetworking framework, users can implement custom
//! serializers and perform complex operations on any serializable structures. A few types native to AzNetworking, many of which
//! relate to packets, demonstrate this.
//!
//! Provided serializers include NetworkInputSerializer for writing an object model into a bytestream, NetworkOutputSerializer
//! for writing to an object model, TrackChangesSerializer which is used to efficiently serialize objects without incurring significant
//! copy or comparison overhead, and HashSerializer which can be used to generate a hash of all visited data which is important for
//! automated desync detection.
class ISerializer
{
public:
@@ -25,6 +25,44 @@ namespace AzNetworking
//! @class TcpNetworkInterface
//! @brief This class implements a TCP network interface.
//!
//! TcpNetworkInterface is an implementation of AzNetworking::INetworkInterface.
//! Unlike UDP, TCP implements a variety of transport features such as congestion
//! avoidance, flow control, and reliability. These features are valuable, but TCP
//! offers minimal configuration of them. This is why UdpNetworkInterface offers
//! similar features, but with greater flexibility in configuration. If your project doesn't
//! require the low latency of UDP, consider using TCP.
//!
//! ## Packet structure
//!
//! * Flags - A bitfield a receiving endpoint can quickly inspect to learn about configuration of a packet
//! * Header - Details the type of packet and other information related to reliability
//! * Payload - The actual serialized content of the packet
//!
//! For more information, read [Networking Packets](http://docs.o3de.org/docs/user-guide/networking/packets) in the O3DE documentation.
//!
//! ## Reliability
//!
//! TCP packets can only be sent reliably. This is a feature of TCP itself.
//!
//! ## Fragmentation
//!
//! TCP implements fragmentation under the hood. Consumers of TCP packets will never
//! need to worry about reconstructing the contents over multiple transmissions.
//!
//! ## Compression
//!
//! Compression here refers to content insensitive compression using libraries like
//! LZ4. If enabled, the target payload is run through the compressor and replaces
//! the original payload if it's in fact smaller. To tell if compression is enabled
//! on a given packet, we operate on a bit in the packet's Flags. The Sender writes
//! this bit while the Receiver checks it to see if a packet needs to be
//! decompressed.
//!
//! ## Encryption
//!
//! AzNetworking uses the [OpenSSL](https://www.openssl.org/) library to implement TLS encryption. If enabled,
//! the O3DE network layer handles the OpenSSL handshake under the hood using provided certificates.
class TcpNetworkInterface final
: public INetworkInterface
{
@@ -27,12 +27,58 @@ namespace AzNetworking
class IConnectionListener;
class ICompressor;
// 20 byte IPv4 header + 8 byte UDP header
static const uint32_t UdpPacketHeaderSize = 20 + 8;
static const uint32_t DtlsPacketHeaderSize = 13; // DTLS1_RT_HEADER_LENGTH
static const uint32_t UdpPacketHeaderSize = 20 + 8; //!< 20 byte IPv4 header + 8 byte UDP header
static const uint32_t DtlsPacketHeaderSize = 13; //!< DTLS1_RT_HEADER_LENGTH
//! @class UdpNetworkInterface
//! @brief This class implements a UDP network interface.
//!
//! UdpNetworkInterface is an implementation of AzNetworking::INetworkInterface. Since UDP is a very bare bones protocol,
//! the Open 3D Engine implementation has to provide significantly more than its TCP counterpart (since TCP implements a
//! significant number of reliability features.)
//!
//! When sent through UDP, a packet can have additional actions performed on it depending on which features are enabled and
//! configured. Each feature listed in this description is in the order a packet will see them on Send.
//!
//! ### Packet structure
//!
//! The general structure of a UDP packet is:
//!
//! * Flags - A bitfield a receiving endpoint can quickly inspect to learn about configuration of a packet
//! * Header - Details the type of packet and other information related to reliability
//! * Payload - The actual serialized content of the packet
//!
//! For more information, read [Networking Packets](http://docs.o3de.org/docs/user-guide/networking/packets) in the O3DE documentation.
//!
//! ### Reliability
//!
//! UDP packets can be sent reliably or unreliably. Reliably sent packets are registered for tracking first. This causes the
//! reliable packet to be resent if a timeout on the packet is reached. Once the packet is acknowledged, the packet is
//! unregistered.
//!
//! ### Fragmentation
//!
//! If the raw packet size exceeds the configured maximum transmission unit (MTU) then the packet is broken into
//! multiple reliable fragments to avoid fragmentation at the routing level. Fragments are always reliable so the original
//! packet can be reconstructed. Operations that alter the payload generally follow this step so that they can be
//! separately applied to the Fragments in addition to not being applied to both the original and Fragments.
//!
//! ### Compression
//!
//! Compression here refers to content insensitive compression using libraries like LZ4. If enabled, the target payload is
//! run through the compressor and replaces the original payload if it's in fact smaller. To tell if compression is enabled
//! on a given packet, we operate on a bit in the packet's Flags. The Sender writes this bit while the Receiver checks it to
//! see if a packet needs to be decompressed.
//!
//! O3DE could potentially move from over MTU to under with compression, and the UDP interface doesn't check for this. Detecting a change
//! that would reduce the number of fragmented packets would require pre-emptively compressing payloads to tell if that change happened,
//! which could potentially lead to a lot of unnecessary calls to the compressor.
//!
//! ### Encryption
//!
//! AzNetworking uses the [OpenSSL](https://www.openssl.org/) library to implement Datagram Layer Transport Security (DTLS) encryption
//! on UDP traffic. Encryption operates as described in [O3DE Networking Encryption](http://docs.o3de.org/docs/user-guide/networking/encryption)
//! on the documentation website. Once both endpoints have completed their handshake, all traffic is expected to be fully encrypted.
class UdpNetworkInterface final
: public INetworkInterface
{
@@ -326,6 +326,16 @@ namespace AzToolsFramework
return *(m_nestedInstances[newInstanceAlias] = std::move(instance));
}
void Instance::DetachNestedInstances(const AZStd::function<void(AZStd::unique_ptr<Instance>)>& callback)
{
for (auto&& [instanceAlias, instance] : m_nestedInstances)
{
instance->m_parent = nullptr;
callback(AZStd::move(instance));
}
m_nestedInstances.clear();
}
AZStd::unique_ptr<Instance> Instance::DetachNestedInstance(const InstanceAlias& instanceAlias)
{
AZStd::unique_ptr<Instance> removedNestedInstance;
@@ -103,6 +103,7 @@ namespace AzToolsFramework
Instance& AddInstance(AZStd::unique_ptr<Instance> instance);
Instance& AddInstance(AZStd::unique_ptr<Instance> instance, InstanceAlias instanceAlias);
AZStd::unique_ptr<Instance> DetachNestedInstance(const InstanceAlias& instanceAlias);
void DetachNestedInstances(const AZStd::function<void(AZStd::unique_ptr<Instance>)>& callback);
/**
* Gets the aliases for the entities in the Instance DOM.
@@ -151,6 +151,10 @@ namespace AzToolsFramework
return InvalidTemplateId;
}
// Add or replace the Source parameter in the dom
PrefabDomPath sourcePath = PrefabDomPath((AZStd::string("/") + PrefabDomUtils::SourceName).c_str());
sourcePath.Set(readPrefabFileResult.GetValue(), relativePath.Native().c_str());
// Create new Template with the Prefab DOM.
TemplateId newTemplateId = m_prefabSystemComponentInterface->AddTemplate(relativePath, readPrefabFileResult.TakeValue());
if (newTemplateId == InvalidTemplateId)
@@ -1211,25 +1211,23 @@ namespace AzToolsFramework
const auto instanceTemplateId = instancePtr->GetTemplateId();
auto parentContainerEntityId = parentInstance.GetContainerEntityId();
instancePtr->GetNestedInstances(
[&](AZStd::unique_ptr<Instance>& nestedInstancePtr)
instancePtr->DetachNestedInstances(
[&](AZStd::unique_ptr<Instance> detachedNestedInstance)
{
//get previous link patch
auto linkRef = m_prefabSystemComponentInterface->FindLink(nestedInstancePtr->GetLinkId());
PrefabDomValueReference linkPatches = linkRef->get().GetLinkPatches();
AZ_Assert(
linkPatches.has_value(), "Unable to get patches on link with id '%llu' during prefab creation.",
nestedInstancePtr->GetLinkId());
PrefabDom& nestedInstanceTemplateDom =
m_prefabSystemComponentInterface->FindTemplateDom(detachedNestedInstance->GetTemplateId());
PrefabDom linkPatchesCopy;
linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator());
RemoveLink(nestedInstancePtr, instanceTemplateId, undoBatch.GetUndoBatch());
UpdateLinkPatchesWithNewEntityAliases(linkPatchesCopy, oldEntityAliases, parentInstance);
Instance& nestedInstanceUnderNewParent = parentInstance.AddInstance(AZStd::move(detachedNestedInstance));
CreateLink(*nestedInstancePtr, parentTemplateId, undoBatch.GetUndoBatch(),
AZStd::move(linkPatchesCopy), true);
PrefabDom nestedInstanceDomUnderNewParent;
m_instanceToTemplateInterface->GenerateDomForInstance(
nestedInstanceDomUnderNewParent, nestedInstanceUnderNewParent);
PrefabDom reparentPatch;
m_instanceToTemplateInterface->GeneratePatch(
reparentPatch, nestedInstanceTemplateDom, nestedInstanceDomUnderNewParent);
CreateLink(nestedInstanceUnderNewParent, parentTemplateId, undoBatch.GetUndoBatch(), AZStd::move(reparentPatch), true);
});
}
@@ -207,6 +207,10 @@ namespace AzToolsFramework
instanceValue->CopyFrom(linkDom, m_prefabDom.GetAllocator());
}
// Remove Source parameter from the dom. It will be added on file load, and should not be stored to disk.
PrefabDomPath sourcePath = PrefabDomPath((AZStd::string("/") + PrefabDomUtils::SourceName).c_str());
sourcePath.Erase(output);
return true;
}
+3 -3
View File
@@ -33,13 +33,13 @@ BEGIN
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Amazon.com, Inc."
VALUE "FileDescription", "Lumberyard Editor"
VALUE "CompanyName", "Open 3D Foundation"
VALUE "FileDescription", "O3DE Editor"
VALUE "FileVersion", "0.1.0.1"
VALUE "InternalName", "Editor"
VALUE "LegalCopyright", "Portions of this file Copyright (c) Amazon.com, Inc. or its affiliates. All Rights Reserved. Original file Copyright (c) Crytek GMBH. Used under license by Amazon.com, Inc. and its affiliates."
VALUE "OriginalFilename", "Editor.exe"
VALUE "ProductName", "Lumberyard Editor"
VALUE "ProductName", "O3DE Editor"
VALUE "ProductVersion", "0.1.0.1"
END
END
-460
View File
@@ -1,460 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "EditorDefs.h"
#include "ImageHDR.h"
// Editor
#include "Util/Image.h"
// We need globals because of the callbacks (they don't allow us to pass state)
static CryMutex globalFileMutex;
static size_t globalFileBufferOffset = 0;
static size_t globalFileBufferSize = 0;
static char* fgets(char* _Buf, [[maybe_unused]] int _MaxCount, CCryFile* _File)
{
while (globalFileBufferOffset < globalFileBufferSize)
{
char chr;
_File->ReadRaw(&chr, 1);
globalFileBufferOffset++;
*_Buf++ = chr;
if (chr == '\n')
{
break;
}
}
*_Buf = '\0';
return _Buf;
}
static size_t fread(void* _DstBuf, size_t _ElementSize, size_t _Count, CCryFile* _File)
{
size_t cpy = min(_ElementSize * _Count, globalFileBufferSize - globalFileBufferOffset);
_File->ReadRaw(_DstBuf, cpy);
globalFileBufferOffset += cpy;
return cpy;
}
/* THIS CODE CARRIES NO GUARANTEE OF USABILITY OR FITNESS FOR ANY PURPOSE.
* WHILE THE AUTHORS HAVE TRIED TO ENSURE THE PROGRAM WORKS CORRECTLY,
* IT IS STRICTLY USE AT YOUR OWN RISK. */
/* utility for reading and writing Ward's rgbe image format.
See rgbe.txt file for more details.
*/
#include <stdio.h>
typedef struct
{
int valid; /* indicate which fields are valid */
char programtype[16]; /* listed at beginning of file to identify it
* after "#?". defaults to "RGBE" */
float gamma; /* image has already been gamma corrected with
* given gamma. defaults to 1.0 (no correction) */
float exposure; /* a value of 1.0 in an image corresponds to
* <exposure> watts/steradian/m^2.
* defaults to 1.0 */
char instructions[512];
} rgbe_header_info;
/* flags indicating which fields in an rgbe_header_info are valid */
#define RGBE_VALID_PROGRAMTYPE 0x01
#define RGBE_VALID_GAMMA 0x02
#define RGBE_VALID_EXPOSURE 0x04
#define RGBE_VALID_INSTRUCTIONS 0x08
/* return codes for rgbe routines */
#define RGBE_RETURN_SUCCESS 0
#define RGBE_RETURN_FAILURE -1
/* read or write headers */
/* you may set rgbe_header_info to null if you want to */
int RGBE_ReadHeader(CCryFile* fp, uint32* width, uint32* height, rgbe_header_info* info);
/* read or write pixels */
/* can read or write pixels in chunks of any size including single pixels*/
int RGBE_ReadPixels(CCryFile* fp, float* data, int numpixels);
/* read or write run length encoded files */
/* must be called to read or write whole scanlines */
int RGBE_ReadPixels_RLE(CCryFile* fp, float* data, uint32 scanline_width,
uint32 num_scanlines);
/* THIS CODE CARRIES NO GUARANTEE OF USABILITY OR FITNESS FOR ANY PURPOSE.
* WHILE THE AUTHORS HAVE TRIED TO ENSURE THE PROGRAM WORKS CORRECTLY,
* IT IS STRICTLY USE AT YOUR OWN RISK. */
#include <math.h>
#include <string.h>
#include <ctype.h>
/* This file contains code to read and write four byte rgbe file format
developed by Greg Ward. It handles the conversions between rgbe and
pixels consisting of floats. The data is assumed to be an array of floats.
By default there are three floats per pixel in the order red, green, blue.
(RGBE_DATA_??? values control this.) Only the mimimal header reading and
writing is implemented. Each routine does error checking and will return
a status value as defined below. This code is intended as a skeleton so
feel free to modify it to suit your needs.
(Place notice here if you modified the code.)
posted to http://www.graphics.cornell.edu/~bjw/
written by Bruce Walter (bjw@graphics.cornell.edu) 5/26/95
based on code written by Greg Ward
*/
#ifndef INLINE
#ifdef _CPLUSPLUS
/* define if your compiler understands inline commands */
#define INLINE inline
#else
#define INLINE
#endif
#endif
/* offsets to red, green, and blue components in a data (float) pixel */
#define RGBE_DATA_RED 0
#define RGBE_DATA_GREEN 1
#define RGBE_DATA_BLUE 2
#define RGBE_DATA_ALPHA 3
/* number of floats per pixel */
#define RGBE_DATA_SIZE 4
enum rgbe_error_codes
{
rgbe_read_error,
rgbe_write_error,
rgbe_format_error,
rgbe_memory_error,
};
/* default error routine. change this to change error handling */
static int rgbe_error(int rgbe_error_code, const char* msg)
{
switch (rgbe_error_code)
{
case rgbe_read_error:
CLogFile::FormatLine("RGBE read error");
break;
case rgbe_write_error:
CLogFile::FormatLine("RGBE write error");
break;
case rgbe_format_error:
CLogFile::FormatLine("RGBE bad file format: %s\n", msg);
break;
default:
case rgbe_memory_error:
CLogFile::FormatLine("RGBE error: %s\n", msg);
}
return RGBE_RETURN_FAILURE;
}
/* standard conversion from rgbe to float pixels */
/* note: Ward uses ldexp(col+0.5,exp-(128+8)). However we wanted pixels */
/* in the range [0,1] to map back into the range [0,1]. */
static INLINE void
rgbe2type(char* red, char* green, char* blue, unsigned char rgbe[4])
{
float f;
if (rgbe[3]) /*nonzero pixel*/
{
f = ldexp(1.0f, rgbe[3] - (int)(128 + 8)) * 255.0f;
*red = (unsigned char) max(0.0f, min(rgbe[0] * f, 255.0f));
*green = (unsigned char) max(0.0f, min(rgbe[1] * f, 255.0f));
*blue = (unsigned char) max(0.0f, min(rgbe[2] * f, 255.0f));
}
else
{
*red = *green = *blue = 0;
}
}
/* minimal header reading. modify if you want to parse more information */
int RGBE_ReadHeader(CCryFile* fp, uint32* width, uint32* height, rgbe_header_info* info)
{
char buf[512];
int found_format;
float tempf;
int i;
found_format = 0;
if (info)
{
info->valid = 0;
info->programtype[0] = 0;
info->gamma = info->exposure = 1.0;
}
if (fgets(buf, sizeof(buf) / sizeof(buf[0]), fp) == NULL)
{
return rgbe_error(rgbe_read_error, NULL);
}
if ((buf[0] != '#') || (buf[1] != '?'))
{
/* if you want to require the magic token then uncomment the next line */
/*return rgbe_error(rgbe_format_error,"bad initial token"); */
}
else if (info)
{
info->valid |= RGBE_VALID_PROGRAMTYPE;
for (i = 0; i < sizeof(info->programtype) - 1; i++)
{
if ((buf[i + 2] == 0) || isspace(buf[i + 2]))
{
break;
}
info->programtype[i] = buf[i + 2];
}
info->programtype[i] = 0;
if (fgets(buf, sizeof(buf) / sizeof(buf[0]), fp) == 0)
{
return rgbe_error(rgbe_read_error, NULL);
}
}
for (;; )
{
if ((buf[0] == 0) || (buf[0] == '\n'))
{
return rgbe_error(rgbe_format_error, "no FORMAT specifier found");
}
else if (strcmp(buf, "FORMAT=32-bit_rle_rgbe\n") == 0)
{
break; /* format found so break out of loop */
}
else if (info && (azsscanf(buf, "GAMMA=%g", &tempf) == 1))
{
info->gamma = tempf;
info->valid |= RGBE_VALID_GAMMA;
}
else if (info && (azsscanf(buf, "EXPOSURE=%g", &tempf) == 1))
{
info->exposure = tempf;
info->valid |= RGBE_VALID_EXPOSURE;
}
else if (info && (!strncmp(buf, "INSTRUCTIONS=", 13)))
{
info->valid |= RGBE_VALID_INSTRUCTIONS;
for (i = 0; i < sizeof(info->instructions) - 1; i++)
{
if ((buf[i + 13] == 0) || isspace(buf[i + 13]))
{
break;
}
info->instructions[i] = buf[i + 13];
}
}
if (fgets(buf, sizeof(buf) / sizeof(buf[0]), fp) == 0)
{
return rgbe_error(rgbe_read_error, NULL);
}
}
if (fgets(buf, sizeof(buf) / sizeof(buf[0]), fp) == 0)
{
return rgbe_error(rgbe_read_error, NULL);
}
if (strcmp(buf, "\n") != 0)
{
return rgbe_error(rgbe_format_error,
"missing blank line after FORMAT specifier");
}
if (fgets(buf, sizeof(buf) / sizeof(buf[0]), fp) == 0)
{
return rgbe_error(rgbe_read_error, NULL);
}
if (azsscanf(buf, "-Y %d +X %d", height, width) < 2)
{
return rgbe_error(rgbe_format_error, "missing image size specifier");
}
return RGBE_RETURN_SUCCESS;
}
/* simple read routine. will not correctly handle run length encoding */
int RGBE_ReadPixels(CCryFile* fp, char* data, int numpixels)
{
unsigned char rgbe[4];
while (numpixels-- > 0)
{
if (fread(rgbe, sizeof(rgbe), 1, fp) < 1)
{
return rgbe_error(rgbe_read_error, NULL);
}
rgbe2type(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN],
&data[RGBE_DATA_BLUE], rgbe);
data[RGBE_DATA_ALPHA] = 0.0f;
data += RGBE_DATA_SIZE;
}
return RGBE_RETURN_SUCCESS;
}
int RGBE_ReadPixels_RLE(CCryFile* fp, char* data, uint32 scanline_width,
uint32 num_scanlines)
{
unsigned char rgbe[4], * scanline_buffer, * ptr, * ptr_end;
int i, count;
unsigned char buf[2];
if ((scanline_width < 8) || (scanline_width > 0x7fff))
{
/* run length encoding is not allowed so read flat*/
return RGBE_ReadPixels(fp, data, scanline_width * num_scanlines);
}
scanline_buffer = NULL;
/* read in each successive scanline */
while (num_scanlines > 0)
{
if (fread(rgbe, sizeof(rgbe), 1, fp) < 1)
{
free(scanline_buffer);
return rgbe_error(rgbe_read_error, NULL);
}
if ((rgbe[0] != 2) || (rgbe[1] != 2) || (rgbe[2] & 0x80))
{
/* this file is not run length encoded */
rgbe2type(&data[0], &data[1], &data[2], rgbe);
data += RGBE_DATA_SIZE;
free(scanline_buffer);
return RGBE_ReadPixels(fp, data, scanline_width * num_scanlines - 1);
}
if ((((int)rgbe[2]) << 8 | rgbe[3]) != scanline_width)
{
free(scanline_buffer);
return rgbe_error(rgbe_format_error, "wrong scanline width");
}
if (scanline_buffer == NULL)
{
scanline_buffer = (unsigned char*)
malloc(sizeof(unsigned char) * 4 * scanline_width);
}
if (scanline_buffer == NULL)
{
return rgbe_error(rgbe_memory_error, "unable to allocate buffer space");
}
ptr = &scanline_buffer[0];
/* read each of the four channels for the scanline into the buffer */
for (i = 0; i < 4; i++)
{
ptr_end = &scanline_buffer[(i + 1) * scanline_width];
while (ptr < ptr_end)
{
if (fread(buf, sizeof(buf[0]) * 2, 1, fp) < 1)
{
free(scanline_buffer);
return rgbe_error(rgbe_read_error, NULL);
}
if (buf[0] > 128)
{
/* a run of the same value */
count = buf[0] - 128;
if ((count == 0) || (count > ptr_end - ptr))
{
free(scanline_buffer);
return rgbe_error(rgbe_format_error, "bad scanline data");
}
while (count-- > 0)
{
*ptr++ = buf[1];
}
}
else
{
/* a non-run */
count = buf[0];
if ((count == 0) || (count > ptr_end - ptr))
{
free(scanline_buffer);
return rgbe_error(rgbe_format_error, "bad scanline data");
}
*ptr++ = buf[1];
if (--count > 0)
{
if (fread(ptr, sizeof(*ptr) * count, 1, fp) < 1)
{
free(scanline_buffer);
return rgbe_error(rgbe_read_error, NULL);
}
ptr += count;
}
}
}
}
/* now convert data from buffer into floats */
for (i = 0; i < scanline_width; i++)
{
rgbe[0] = scanline_buffer[i];
rgbe[1] = scanline_buffer[i + scanline_width];
rgbe[2] = scanline_buffer[i + 2 * scanline_width];
rgbe[3] = scanline_buffer[i + 3 * scanline_width];
rgbe2type(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN],
&data[RGBE_DATA_BLUE], rgbe);
data[RGBE_DATA_ALPHA] = 0.0f;
data += RGBE_DATA_SIZE;
}
num_scanlines--;
}
free(scanline_buffer);
return RGBE_RETURN_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////////
bool CImageHDR::Load(const QString& fileName, CImageEx& outImage)
{
CCryFile file;
if (!file.Open(fileName.toUtf8().data(), "rb"))
{
CLogFile::FormatLine("File not found %s", fileName.toUtf8().data());
return false;
}
// We use some global variables in callbacks, so we must
// prevent multithread access to the data
CryAutoLock<CryMutex> tifAutoLock(globalFileMutex);
globalFileBufferSize = file.GetLength();
globalFileBufferOffset = 0;
bool bRet = false;
uint32 dwWidth, dwHeight;
rgbe_header_info info;
if (RGBE_RETURN_SUCCESS == RGBE_ReadHeader(&file, &dwWidth, &dwHeight, &info))
{
if (outImage.Allocate(dwWidth, dwHeight))
{
char* pDst = (char*)outImage.GetData();
if (RGBE_RETURN_SUCCESS == RGBE_ReadPixels_RLE(&file, (char*)pDst, dwWidth, dwHeight))
{
bRet = true;
}
}
}
if (!bRet)
{
outImage.Detach();
}
return bRet;
}
-22
View File
@@ -1,22 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
class CImageEx;
class CImageHDR
{
public:
bool Load(const QString& fileName, CImageEx& outImage);
};
-5
View File
@@ -21,7 +21,6 @@
// Editor
#include "Util/ImageGif.h"
#include "Util/ImageTIF.h"
#include "Util/ImageHDR.h"
//////////////////////////////////////////////////////////////////////////
bool CImageUtil::Save(const QString& strFileName, CImageEx& inImage)
@@ -275,10 +274,6 @@ bool CImageUtil::LoadImage(const QString& fileName, CImageEx& image, bool* pQual
{
return CImageUtil::Load(fileName, image);
}
else if (azstricmp(ext, ".hdr") == 0)
{
return CImageHDR().Load(fileName, image);
}
else
{
return CImageUtil::Load(fileName, image);
@@ -737,8 +737,6 @@ set(FILES
Util/GeometryUtil.cpp
Util/GuidUtil.cpp
Util/GuidUtil.h
Util/ImageHDR.cpp
Util/ImageHDR.h
Util/IObservable.h
Util/IndexedFiles.cpp
Util/IndexedFiles.h