2024-08-07 10:29:31 -03:00
# ifndef XNA_PIPELINE_WRITER_HPP
# define XNA_PIPELINE_WRITER_HPP
2024-08-07 16:58:59 -03:00
# include "../common/color.hpp"
# include "../common/numerics.hpp"
2024-08-07 10:29:31 -03:00
# include "../csharp/binary.hpp"
2024-08-07 16:58:59 -03:00
# include "../csharp/type.hpp"
2024-08-07 10:29:31 -03:00
# include "../default.hpp"
# include "pipeline-enums.hpp"
namespace xna {
2024-08-07 16:58:59 -03:00
//Provides an implementation for many of the ContentCompiler methods including compilation, state tracking for shared resources and creation of the header type manifest.
2024-08-07 10:29:31 -03:00
class ContentTypeWriter {
public :
2024-08-07 16:58:59 -03:00
//Gets the assembly qualified name of the runtime loader for this type.
virtual String GetRuntimeReader ( TargetPlatform targetPlatform ) { return String ( ) ; }
//Gets a format version number for this type.
2024-08-07 10:29:31 -03:00
virtual Int TypeVersion ( ) const { return 0 ; }
2024-08-07 16:58:59 -03:00
//Compiles an object into binary format.
virtual void Write ( ContentWriter & output , Object & value ) { }
2024-08-07 21:52:49 -03:00
//Determines if deserialization into an existing object is possible.
virtual bool CanDeserializeIntoExistingObject ( ) const { return false ; }
2024-08-07 15:23:31 -03:00
2024-08-07 16:58:59 -03:00
protected :
ContentTypeWriter ( P_Type const & targetType ) : targetType ( targetType ) { }
private :
P_Type targetType { nullptr } ;
2024-08-07 10:29:31 -03:00
} ;
2024-08-07 16:58:59 -03:00
//Provides a generic implementation of ContentTypeWriter methods and properties for compiling a specific managed type into a binary format.
2024-08-07 10:29:31 -03:00
template < class T >
2024-08-07 15:23:31 -03:00
class ContentTypeWriter_T : public ContentTypeWriter {
2024-08-07 16:58:59 -03:00
public :
//Compiles a strongly typed object into binary format.
virtual void Write ( ContentWriter & output , T & value ) { }
protected :
ContentTypeWriter_T ( ) : ContentTypeWriter ( typeof < T > ( ) ) { }
} ;
template < class T >
class BuiltinTypeWriter : public ContentTypeWriter_T < T > {
String GetRuntimeReader ( TargetPlatform targetPlatform ) override {
String name = typeid ( T ) . name ( ) ;
switch ( targetPlatform )
{
case xna : : TargetPlatform : : Windows :
name . append ( " ::Windows " ) ;
break ;
default :
break ;
}
return name ;
}
2024-08-07 15:23:31 -03:00
} ;
2024-08-07 10:29:31 -03:00
2024-08-07 15:23:31 -03:00
template < class T >
class ExternalReference {
public :
String FileName ( ) const ;
2024-08-07 10:29:31 -03:00
} ;
//Provides an implementation for many of the ContentCompiler methods including compilation, state tracking for shared resources and creation of the header type manifest.
class ContentWriter : public BinaryWriter {
public :
ContentWriter (
P_ContentCompiler & compiler ,
P_Stream const & output ,
TargetPlatform targetPlatform ,
GraphicsProfile targetProfile ,
bool compressContent ,
String const & rootDirectory ,
String const & referenceRelocationPath
) ;
//Gets the content build target platform.
constexpr TargetPlatform Target ( ) const { return targetPlatform ; }
//Gets or sets the target graphics profile.
constexpr GraphicsProfile TargetProfile ( ) const { return targetProfile ; }
//Writes a single object preceded by a type identifier to the output binary.
template < class T > void WriteObject ( T & value ) ;
//Writes a single object to the output binary, using the specified type hint and writer worker.
template < class T > void WriteObject ( T & value , ContentTypeWriter & writer ) ;
//Writes a single object to the output binary as an instance of the specified type.
template < class T > void WriteRawObject ( T & value ) ;
//Writes a single object to the output binary using the specified writer worker.
template < class T > void WriteRawObject ( T & value , ContentTypeWriter & typeWriter ) ;
//Adds a shared reference to the output binary and records the object to be serialized later.
template < class T > void WriteSharedResource ( T & value ) ;
//Writes the name of an external file to the output binary.
template < class T > void WriteExternalReference ( ExternalReference < T > & reference ) ;
using BinaryWriter : : Write ;
//Writes a Vector2 value.
void Write ( Vector2 const & value ) ;
//Writes a Vector3 value.
void Write ( Vector3 const & value ) ;
//Writes a Vector4 value.
void Write ( Vector4 const & value ) ;
//Writes a Matrix value.
void Write ( Matrix const & value ) ;
//Writes a Quaternion value.
void Write ( Quaternion const & value ) ;
//Writes a Color value.
void Write ( Color const & value ) ;
inline void FlushOutput ( ) {
WriteSharedResources ( ) ;
WriteHeader ( ) ;
WriteFinalOutput ( ) ;
}
private :
template < class T > void InvokeWriter ( T & value , ContentTypeWriter & writer ) ;
2024-08-07 15:23:31 -03:00
P_ContentTypeWriter GetTypeWriter ( Type const & type , Int & typeIndex ) ;
2024-08-07 10:29:31 -03:00
void WriteSharedResources ( ) ;
void WriteHeader ( ) ;
void WriteFinalOutput ( ) ;
void WriteUncompressedOutput ( ) ;
void WriteCompressedOutput ( ) ;
void WriteVersionNumber ( Ushort version ) ;
private :
P_ContentCompiler compiler { nullptr } ;
TargetPlatform targetPlatform { TargetPlatform : : Windows } ;
GraphicsProfile targetProfile { GraphicsProfile : : HiDef } ;
bool compressContent { false } ;
String rootDirectory ;
String referenceRelocationPath ;
P_Stream finalOutput { nullptr } ;
P_MemoryStream headerData { nullptr } ;
P_MemoryStream contentData { nullptr } ;
std : : vector < P_ContentTypeWriter > typeWriters ;
std : : map < std : : any , Int > sharedResourceNames ;
std : : queue < std : : any > sharedResources ;
2024-08-07 15:23:31 -03:00
std : : map < HashValue , Int > typeTable ;
2024-08-07 10:29:31 -03:00
private :
static constexpr Ushort XnbVersion = 5 ;
static constexpr Ushort XnbCompressedVersion = 32773 ;
static constexpr Ushort XnbVersionProfileMask = 32512 ;
static constexpr Int XnbVersionProfileShift = 8 ;
static constexpr Int XnbVersionOffset = 4 ;
static constexpr Int XnbFileSizeOffset = 6 ;
static constexpr Int XnbPrologueSize = 10 ;
2024-08-07 15:23:31 -03:00
inline static const String FilenameExt = " .xnb " ;
2024-08-07 10:29:31 -03:00
} ;
2024-09-06 21:22:38 -03:00
template < class T >
class TypeHandlerFactory {
} ;
class ContentTypeWriterFactory : public TypeHandlerFactory < ContentTypeWriter > {
public :
std : : vector < P_ContentTypeWriter > Initialize ( ) const {
std : : vector < P_ContentTypeWriter > writers ;
return writers ;
}
} ;
2024-08-07 10:29:31 -03:00
//
2024-09-06 21:22:38 -03:00
// ContentTypeWriter
2024-08-07 10:29:31 -03:00
//
template < class T >
void ContentWriter : : WriteObject ( T & value ) {
2024-08-07 16:58:59 -03:00
if constexpr ( XnaHelper : : IsSmartPoint < T > ( ) ) {
if ( value = = nullptr ) {
Exception : : Throw ( Exception : : ARGUMENT_IS_NULL ) ;
}
}
2024-08-07 15:23:31 -03:00
const auto type = typeof < T > ( ) ;
Int _ ;
auto typeWriter = GetTypeWriter ( * type , _ ) ;
2024-08-07 10:29:31 -03:00
2024-08-07 15:23:31 -03:00
InvokeWriter < T > ( value , * typeWriter ) ;
2024-08-07 10:29:31 -03:00
}
template < class T >
void ContentWriter : : WriteObject ( T & value , ContentTypeWriter & writer ) {
2024-08-07 15:23:31 -03:00
auto contentTypeWriter = reinterpret_cast < ContentTypeWriter_T < T > * > ( & writer ) ;
2024-08-07 10:29:31 -03:00
2024-08-07 16:58:59 -03:00
if ( contentTypeWriter ) {
2024-08-07 15:23:31 -03:00
contentTypeWriter - > Write ( * this , value ) ;
}
else {
Object _value = value ;
writer . Write ( * this , _value ) ;
}
2024-08-07 10:29:31 -03:00
}
template < class T >
void ContentWriter : : WriteRawObject ( T & value ) {
2024-08-07 16:58:59 -03:00
if constexpr ( XnaHelper : : IsSmartPoint < T > ( ) ) {
if ( value = = nullptr ) {
Exception : : Throw ( Exception : : ARGUMENT_IS_NULL ) ;
}
}
2024-08-07 10:29:31 -03:00
2024-08-07 15:23:31 -03:00
const auto type = typeof < T > ( ) ;
Int _ ;
auto typeWriter = GetTypeWriter ( * type , _ ) ;
InvokeWriter < T > ( value , * typeWriter ) ;
2024-08-07 10:29:31 -03:00
}
template < class T >
void ContentWriter : : WriteRawObject ( T & value , ContentTypeWriter & typeWriter ) {
2024-08-07 15:23:31 -03:00
Exception : : ThrowTIsNull ( value ) ;
2024-08-07 10:29:31 -03:00
2024-08-07 15:23:31 -03:00
InvokeWriter < T > ( value , typeWriter ) ;
2024-08-07 10:29:31 -03:00
}
template < class T >
void ContentWriter : : WriteSharedResource ( T & value ) {
2024-08-07 15:23:31 -03:00
if constexpr ( XnaHelper : : IsSmartPoint < T > ( ) ) {
if ( value = = nullptr )
Write7BitEncodedInt ( 0 ) ;
}
else {
Int num ;
Object obj = value ;
if ( ! sharedResourceNames . contains ( value ) ) {
num = sharedResourceNames . size ( ) + 1 ;
sharedResourceNames . emplace ( obj , num ) ;
sharedResources . push ( obj ) ;
}
else {
num = sharedResourceNames [ value ] ;
}
Write7BitEncodedInt ( num ) ;
}
2024-08-07 10:29:31 -03:00
}
template < class T >
2024-08-07 15:23:31 -03:00
void ContentWriter : : WriteExternalReference ( ExternalReference < T > & reference ) {
const auto & filename1 = reference . FileName ( ) ;
2024-08-07 10:29:31 -03:00
2024-08-07 15:23:31 -03:00
if ( filename1 . empty ( ) ) {
Write ( " " ) ;
}
else {
String filename2 ;
if ( filename1 . ends_with ( FilenameExt ) )
2024-08-07 16:58:59 -03:00
filename2 = filename1 . substr ( 0 , filename1 . size ( ) - FilenameExt . size ( ) ) ;
2024-08-07 15:23:31 -03:00
else
Exception : : Throw ( Exception : : INVALID_OPERATION ) ;
if ( ! filename2 . starts_with ( rootDirectory ) )
Exception : : Throw ( Exception : : INVALID_OPERATION ) ;
Exception : : Throw ( Exception : : NOT_IMPLEMENTED ) ;
}
2024-08-07 10:29:31 -03:00
}
template < class T >
void ContentWriter : : InvokeWriter ( T & value , ContentTypeWriter & writer ) {
2024-08-07 15:23:31 -03:00
auto contentTypeWriter = reinterpret_cast < ContentTypeWriter_T < T > * > ( & writer ) ;
if ( contentTypeWriter ) {
contentTypeWriter - > Write ( * this , value ) ;
}
else {
Object obj = value ;
writer . Write ( * this , obj ) ;
}
2024-08-07 10:29:31 -03:00
}
}
# endif