void Interface::DeleteRwObject( RwObject *obj ) { EngineInterface *engineInterface = (EngineInterface*)this; // Delete it using the type system. GenericRTTI *rttiObj = engineInterface->typeSystem.GetTypeStructFromAbstractObject( obj ); if ( rttiObj ) { // By default, we can destroy. bool canDestroy = true; // If we have the refcount plugin, we want to handle things with it. if ( refCountManager *refMan = refCountRegister.GetPluginStruct( engineInterface ) ) { if ( refCountPlugin *refCountObj = RwTypeSystem::RESOLVE_STRUCT <refCountPlugin> ( engineInterface, rttiObj, engineInterface->rwobjTypeInfo, refMan->pluginOffset ) ) { canDestroy = refCountObj->RemoveRef(); } } if ( canDestroy ) { engineInterface->typeSystem.Destroy( engineInterface, rttiObj ); } } }
void registerTXDPlugins( void ) { // First register the main serialization plugins. // Those are responsible for detecting texture dictionaries and native textures in RW streams. // The sub module plugins depend on those. texDictionaryStreamStore.RegisterPlugin( engineFactory ); registerNativeTexturePlugins(); // Register pure sub modules. registerResizeFilteringEnvironment(); }
// Interface creation for the RenderWare engine. Interface* CreateEngine( LibraryVersion theVersion ) { if ( hasInitialized == false ) { // Verify data constants before we create a valid engine. if ( VerifyLibraryIntegrity() ) { // Configuration comes first. registerConfigurationEnvironment(); // Initialize our plugins first. refCountRegister.RegisterPlugin( engineFactory ); rwlockProvider.RegisterPlugin( engineFactory ); // Now do the main modules. registerThreadingEnvironment(); registerWarningHandlerEnvironment(); registerRasterConsistency(); registerEventSystem(); registerStreamGlobalPlugins(); registerFileSystemDataRepository(); registerSerializationPlugins(); registerObjectExtensionsPlugins(); registerTXDPlugins(); registerImagingPlugin(); registerWindowingSystem(); registerDriverEnvironment(); registerDrawingLayerEnvironment(); // After all plugins registered themselves, we know that // each configuration entry is properly initialized. // Now we can create a configuration block in the interface! registerConfigurationBlockDispatching(); hasInitialized = true; } } Interface *engineOut = NULL; if ( hasInitialized == true ) { // Create a specialized engine depending on the version. engineOut = engineFactory.Construct( _engineMemAlloc ); if ( engineOut ) { engineOut->SetVersion( theVersion ); } } return engineOut; }
const TexDictionary* ToConstTexDictionary( Interface *intf, const RwObject *rwObj ) { EngineInterface *engineInterface = (EngineInterface*)intf; texDictionaryStreamPlugin *txdStream = texDictionaryStreamStore.GetPluginStruct( engineInterface ); if ( txdStream ) { return txdStream->ToConstTexDictionary( engineInterface, rwObj ); } return NULL; }
void ReleaseObject( RwObject *obj ) { EngineInterface *engineInterface = (EngineInterface*)obj->engineInterface; // Increase the reference count. if ( refCountManager *refMan = refCountRegister.GetPluginStruct( (EngineInterface*)engineInterface ) ) { if ( refCountPlugin *refCount = refMan->GetPluginStruct( engineInterface, obj ) ) { // We just delete the object. engineInterface->DeleteRwObject( obj ); } } }
TexDictionary* CreateTexDictionary( Interface *intf ) { EngineInterface *engineInterface = (EngineInterface*)intf; TexDictionary *texDictOut = NULL; texDictionaryStreamPlugin *txdStream = texDictionaryStreamStore.GetPluginStruct( engineInterface ); if ( txdStream ) { texDictOut = txdStream->CreateTexDictionary( engineInterface ); } return texDictOut; }
namespace fsrandom { static fsLockProvider _fileSysRNGLockProvider; struct fsRandomGeneratorEnv { inline void Initialize( CFileSystemNative *fsys ) { return; } inline void Shutdown( CFileSystemNative *fsys ) { return; } inline void operator = ( const fsRandomGeneratorEnv& right ) { // Cannot assign random number generators. return; } // This may not be available on all systems. std::random_device _true_random; }; static PluginDependantStructRegister <fsRandomGeneratorEnv, fileSystemFactory_t> fsRandomGeneratorRegister; inline fsRandomGeneratorEnv* GetRandomEnv( CFileSystem *fsys ) { return fsRandomGeneratorRegister.GetPluginStruct( (CFileSystemNative*)fsys ); } unsigned long getSystemRandom( CFileSystem *sys ) { fsRandomGeneratorEnv *env = GetRandomEnv( sys ); assert( env != NULL ); // Not sure whether std::random_device is thread-safe, so be careful here. NativeExecutive::CReadWriteWriteContextSafe <> consistency( _fileSysRNGLockProvider.GetReadWriteLock( sys ) ); return env->_true_random(); } };
uint32 GetRefCount( RwObject *obj ) { uint32 refCountNum = 1; // If we do not support reference counting, this is actually a valid value. EngineInterface *engineInterface = (EngineInterface*)obj->engineInterface; // Increase the reference count. if ( refCountManager *refMan = refCountRegister.GetPluginStruct( engineInterface ) ) { if ( refCountPlugin *refCount = refMan->GetPluginStruct( engineInterface, obj ) ) { // We just delete the object. refCountNum = refCount->refCount; } } return refCountNum; }
// Acquisition routine for objects, so that reference counting is increased, if needed. // Can return NULL if the reference count could not be increased. RwObject* AcquireObject( RwObject *obj ) { EngineInterface *engineInterface = (EngineInterface*)obj->engineInterface; // Increase the reference count. if ( refCountManager *refMan = refCountRegister.GetPluginStruct( engineInterface ) ) { if ( refCountPlugin *refCount = refMan->GetPluginStruct( engineInterface, obj ) ) { // TODO: make sure that incrementing is actually possible. // we cannot increment if we would overflow the number, for instance. refCount->AddRef(); } } return obj; }
void registerD3D8NativePlugin( void ) { d3dNativeTexturePluginRegister.RegisterPlugin( engineFactory ); }
namespace rw { struct resizeFilterBlurPlugin : public rasterResizeFilterInterface { void GetSupportedFiltering( resizeFilteringCaps& capsOut ) const override { capsOut.supportsMagnification = false; capsOut.supportsMinification = true; capsOut.magnify2D = false; capsOut.minify2D = true; } void MagnifyFiltering( const resizeColorPipeline& srcBmp, uint32 magX, uint32 magY, uint32 magScaleX, uint32 magScaleY, resizeColorPipeline& dstBmp, uint32 dstX, uint32 dstY ) const override { // TODO. throw RwException( "not supported yet" ); } void MinifyFiltering( const resizeColorPipeline& srcBmp, uint32 minX, uint32 minY, uint32 minScaleX, uint32 minScaleY, abstractColorItem& colorItem ) const override { eColorModel model = srcBmp.getColorModel(); if ( model == COLORMODEL_RGBA ) { uint32 redSumm = 0; uint32 greenSumm = 0; uint32 blueSumm = 0; uint32 alphaSumm = 0; // Loop through the texels and calculate a blur. uint32 addCount = 0; for ( uint32 y = 0; y < minScaleY; y++ ) { for ( uint32 x = 0; x < minScaleX; x++ ) { abstractColorItem srcColorItem; bool hasColor = srcBmp.fetchcolor( x + minX, y + minY, srcColorItem ); if ( hasColor ) { // Add colors together. redSumm += srcColorItem.rgbaColor.r; greenSumm += srcColorItem.rgbaColor.g; blueSumm += srcColorItem.rgbaColor.b; alphaSumm += srcColorItem.rgbaColor.a; addCount++; } } } if ( addCount != 0 ) { // Calculate the real color. colorItem.rgbaColor.r = std::min( redSumm / addCount, 255u ); colorItem.rgbaColor.g = std::min( greenSumm / addCount, 255u ); colorItem.rgbaColor.b = std::min( blueSumm / addCount, 255u ); colorItem.rgbaColor.a = std::min( alphaSumm / addCount, 255u ); colorItem.model = COLORMODEL_RGBA; } } else if ( model == COLORMODEL_LUMINANCE ) { uint32 lumSumm = 0; uint32 alphaSumm = 0; // Loop through the texels and calculate a blur. uint32 addCount = 0; for ( uint32 y = 0; y < minScaleY; y++ ) { for ( uint32 x = 0; x < minScaleX; x++ ) { abstractColorItem srcColorItem; bool hasColor = srcBmp.fetchcolor( x + minX, y + minY, srcColorItem ); if ( hasColor ) { // Add colors together. lumSumm += srcColorItem.luminance.lum; alphaSumm += srcColorItem.luminance.alpha; addCount++; } } } if ( addCount != 0 ) { // Calculate the real color. colorItem.luminance.lum = std::min( lumSumm / addCount, 255u ); colorItem.luminance.alpha = std::min( alphaSumm / addCount, 255u ); colorItem.model = COLORMODEL_LUMINANCE; } } } inline void Initialize( EngineInterface *engineInterface ) { RegisterResizeFiltering( engineInterface, "blur", this ); } inline void Shutdown( EngineInterface *engineInterface ) { UnregisterResizeFiltering( engineInterface, this ); } }; static PluginDependantStructRegister <resizeFilterBlurPlugin, RwInterfaceFactory_t> resizeFilterBlurPluginRegister; void registerRasterSizeBlurPlugin( void ) { resizeFilterBlurPluginRegister.RegisterPlugin( engineFactory ); } };
void registerRasterSizeBlurPlugin( void ) { resizeFilterBlurPluginRegister.RegisterPlugin( engineFactory ); }
inline fsRandomGeneratorEnv* GetRandomEnv( CFileSystem *fsys ) { return fsRandomGeneratorRegister.GetPluginStruct( (CFileSystemNative*)fsys ); }
void registerMobileUNCNativePlugin( void ) { uncNativeTexturePlugin.RegisterPlugin( engineFactory ); }
namespace rw { eTexNativeCompatibility uncNativeTextureTypeProvider::IsCompatibleTextureBlock( BlockProvider& inputProvider ) const { eTexNativeCompatibility texCompat = RWTEXCOMPAT_NONE; BlockProvider texNativeImageBlock( &inputProvider ); texNativeImageBlock.EnterContext(); try { if ( texNativeImageBlock.getBlockID() == CHUNK_STRUCT ) { // Here we can check the platform descriptor, since we know it is unique. uint32 platformDescriptor = texNativeImageBlock.readUInt32(); if ( platformDescriptor == PLATFORMDESC_UNC_MOBILE ) { texCompat = RWTEXCOMPAT_ABSOLUTE; } } } catch( ... ) { texNativeImageBlock.LeaveContext(); throw; } texNativeImageBlock.LeaveContext(); return texCompat; } void uncNativeTextureTypeProvider::DeserializeTexture( TextureBase *theTexture, PlatformTexture *nativeTex, BlockProvider& inputProvider ) const { Interface *engineInterface = theTexture->engineInterface; // Read the texture native block. { BlockProvider texImageDataBlock( &inputProvider ); texImageDataBlock.EnterContext(); try { if ( texImageDataBlock.getBlockID() == CHUNK_STRUCT ) { // Read the meta header first. mobile_unc::textureNativeGenericHeader metaHeader; texImageDataBlock.read( &metaHeader, sizeof( metaHeader ) ); // Make sure we got the right platform descriptor. if ( metaHeader.platformDescriptor != PLATFORMDESC_UNC_MOBILE ) { throw RwException( "invalid platform descriptor in uncompressed mobile texture native" ); } // Cast out native texture type. NativeTextureMobileUNC *platformTex = (NativeTextureMobileUNC*)nativeTex; // Read the format info. metaHeader.formatInfo.parse( *theTexture ); // Read the texture names. { char tmpbuf[ sizeof( metaHeader.name ) + 1 ]; // Make sure the name buffer is zero terminted. tmpbuf[ sizeof( metaHeader.name ) ] = '\0'; // Move over the texture name. memcpy( tmpbuf, metaHeader.name, sizeof( metaHeader.name ) ); theTexture->SetName( tmpbuf ); // Move over the texture mask name. memcpy( tmpbuf, metaHeader.maskName, sizeof( metaHeader.maskName ) ); theTexture->SetMaskName( tmpbuf ); } // Read some advanced properties. bool hasAlpha = metaHeader.hasAlpha; platformTex->hasAlpha = hasAlpha; platformTex->unk2 = metaHeader.unk2; platformTex->unk3 = metaHeader.unk3; assert( metaHeader.unk1 == false ); assert( metaHeader.unk2 == 0 ); // This texture format is very primitive. // It supports only RASTER_4444 textures with 16 depth. // Everything that this format stores is already storable in the Direct3D 8/9 platform. eRasterFormat rasterFormat; uint32 depth; eColorOrdering colorOrder; getUNCRasterFormat( hasAlpha, rasterFormat, colorOrder, depth ); // Parse all mipmaps. // This format is pretty simple. uint32 maybeMipmapCount = metaHeader.mipmapCount; mipGenLevelGenerator mipLevelGen( metaHeader.width, metaHeader.height ); if ( !mipLevelGen.isValidLevel() ) { throw RwException( "texture " + theTexture->GetName() + " has invalid dimensions" ); } uint32 mipmap_index = 0; uint32 remainingTexImageDataSize = metaHeader.imageDataSectionSize; while ( true ) { if ( remainingTexImageDataSize == 0 ) { break; } if ( mipmap_index >= maybeMipmapCount ) { break; } bool couldEstablishLevel = true; if ( mipmap_index > 0 ) { couldEstablishLevel = mipLevelGen.incrementLevel(); } if ( !couldEstablishLevel ) { break; } // Create the new mipmap layer. NativeTextureMobileUNC::mipmapLayer newLayer; uint32 width = mipLevelGen.getLevelWidth(); uint32 height = mipLevelGen.getLevelHeight(); newLayer.layerWidth = width; newLayer.layerHeight = height; // Since we are an uncompressed texture, the layer dimensions equal the raw dimensions. newLayer.width = width; newLayer.height = height; // Calculate the size of this layer. uint32 texRowSize = getUNCRasterDataRowSize( width, depth ); uint32 texDataSize = getRasterDataSizeByRowSize( texRowSize, height ); // Reduce the texture image data section remainder. if ( remainingTexImageDataSize < texDataSize ) { throw RwException( "texture " + theTexture->GetName() + " has an invalid image data stream section size" ); } remainingTexImageDataSize -= texDataSize; // Store the texels. texImageDataBlock.check_read_ahead( texDataSize ); void *texels = engineInterface->PixelAllocate( texDataSize ); try { texImageDataBlock.read( texels, texDataSize ); } catch( ... ) { engineInterface->PixelFree( texels ); throw; } newLayer.texels = texels; newLayer.dataSize = texDataSize; // Store this layer. platformTex->mipmaps.push_back( newLayer ); // Increase the mipmap index. mipmap_index++; } // We do not want no empty textures. if ( mipmap_index == 0 ) { throw RwException( "texture " + theTexture->GetName() + " is empty" ); } // Fix filtering mode. fixFilteringMode( *theTexture, mipmap_index ); int warningLevel = engineInterface->GetWarningLevel(); // Check whether we have any remaining texture image data. if ( remainingTexImageDataSize != 0 ) { if ( warningLevel >= 3 ) { engineInterface->PushWarning( "texture " + theTexture->GetName() + " has image data section meta-data" ); } // Skip the meta-data. texImageDataBlock.skip( remainingTexImageDataSize ); } // We are done! } else { throw RwException( "could not find tex image data block in uncompressed mobile texture native" ); } } catch( ... ) { texImageDataBlock.LeaveContext(); throw; } texImageDataBlock.LeaveContext(); } // Deserialize extensions. engineInterface->DeserializeExtensions( theTexture, inputProvider ); } static PluginDependantStructRegister <uncNativeTextureTypeProvider, RwInterfaceFactory_t> uncNativeTexturePlugin; void registerMobileUNCNativePlugin( void ) { uncNativeTexturePlugin.RegisterPlugin( engineFactory ); } };
namespace rw { struct raster_constructor { EngineInterface *intf; void *constr_params; inline Raster* Construct( void *mem ) const { return new (mem) Raster( this->intf, this->constr_params ); } }; void EngineInterface::rasterTypeInterface::Construct( void *mem, EngineInterface *intf, void *constr_params ) const { raster_constructor constr; constr.intf = intf; constr.constr_params = constr_params; intf->rasterPluginFactory.ConstructPlacementEx( mem, constr ); } void EngineInterface::rasterTypeInterface::CopyConstruct( void *mem, const void *srcMem ) const { engineInterface->rasterPluginFactory.ClonePlacement( mem, (const rw::Raster*)srcMem ); } void EngineInterface::rasterTypeInterface::Destruct( void *mem ) const { engineInterface->rasterPluginFactory.DestroyPlacement( (rw::Raster*)mem ); } size_t EngineInterface::rasterTypeInterface::GetTypeSize( EngineInterface *intf, void *constr_params ) const { return intf->rasterPluginFactory.GetClassSize(); } size_t EngineInterface::rasterTypeInterface::GetTypeSizeByObject( EngineInterface *intf, const void *mem ) const { return intf->rasterPluginFactory.GetClassSize(); } // Factory for interfaces. RwMemoryAllocator _engineMemAlloc; RwInterfaceFactory_t engineFactory; EngineInterface::EngineInterface( void ) { // Set up the type system. this->typeSystem._memAlloc = &memAlloc; this->typeSystem.lockProvider.engineInterface = this; this->typeSystem.InitializeLockProvider(); // Set up some type interfaces. this->_rasterTypeInterface.engineInterface = this; // Register the main RenderWare types. { this->streamTypeInfo = this->typeSystem.RegisterAbstractType <Stream> ( "stream" ); this->rasterTypeInfo = this->typeSystem.RegisterType( "raster", &this->_rasterTypeInterface ); this->rwobjTypeInfo = this->typeSystem.RegisterAbstractType <RwObject> ( "rwobj" ); this->textureTypeInfo = this->typeSystem.RegisterStructType <TextureBase> ( "texture", this->rwobjTypeInfo ); } } RwObject::RwObject( Interface *engineInterface, void *construction_params ) { // Constructor that is called for creation. this->engineInterface = engineInterface; this->objVersion = engineInterface->GetVersion(); // when creating an object, we assign it the current version. } inline void SafeDeleteType( EngineInterface *engineInterface, RwTypeSystem::typeInfoBase*& theType ) { RwTypeSystem::typeInfoBase *theTypeVal = theType; if ( theTypeVal ) { engineInterface->typeSystem.DeleteType( theTypeVal ); theType = NULL; } } EngineInterface::~EngineInterface( void ) { // Unregister all types again. { SafeDeleteType( this, this->textureTypeInfo ); SafeDeleteType( this, this->rwobjTypeInfo ); SafeDeleteType( this, this->rasterTypeInfo ); SafeDeleteType( this, this->streamTypeInfo ); } } rwLockProvider_t rwlockProvider; void Interface::SetVersion( LibraryVersion version ) { EngineInterface *engineInterface = (EngineInterface*)this; GetEnvironmentConfigBlock( engineInterface ).SetVersion( version ); } LibraryVersion Interface::GetVersion( void ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; return GetConstEnvironmentConfigBlock( engineInterface ).GetVersion(); } void Interface::SetApplicationInfo( const softwareMetaInfo& metaInfo ) { EngineInterface *engineInterface = (EngineInterface*)this; scoped_rwlock_writer <rwlock> lock( GetReadWriteLock( engineInterface ) ); if ( const char *appName = metaInfo.applicationName ) { engineInterface->applicationName = appName; } else { engineInterface->applicationName.clear(); } if ( const char *appVersion = metaInfo.applicationVersion ) { engineInterface->applicationVersion = appVersion; } else { engineInterface->applicationVersion.clear(); } if ( const char *desc = metaInfo.description ) { engineInterface->applicationDescription = desc; } else { engineInterface->applicationDescription.clear(); } } void Interface::SetMetaDataTagging( bool enabled ) { EngineInterface *engineInterface = (EngineInterface*)this; GetEnvironmentConfigBlock( engineInterface ).SetMetaDataTagging( enabled ); } bool Interface::GetMetaDataTagging( void ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; return GetConstEnvironmentConfigBlock( engineInterface ).GetMetaDataTagging(); } std::string GetRunningSoftwareInformation( EngineInterface *engineInterface, bool outputShort ) { std::string infoOut; { scoped_rwlock_reader <rwlock> lock( GetReadWriteLock( engineInterface ) ); const rwConfigBlock& cfgBlock = GetConstEnvironmentConfigBlock( engineInterface ); // Only output anything if we enable meta data tagging. if ( cfgBlock.GetMetaDataTagging() ) { // First put the software name. bool hasAppName = false; if ( engineInterface->applicationName.length() != 0 ) { infoOut += engineInterface->applicationName; hasAppName = true; } else { infoOut += "RenderWare (generic)"; } infoOut += " [rwver: " + engineInterface->GetVersion().toString() + "]"; if ( hasAppName ) { if ( engineInterface->applicationVersion.length() != 0 ) { infoOut += " version: " + engineInterface->applicationVersion; } } if ( outputShort == false ) { if ( engineInterface->applicationDescription.length() != 0 ) { infoOut += " " + engineInterface->applicationDescription; } } } } return infoOut; } struct refCountPlugin { std::atomic <unsigned long> refCount; inline void operator =( const refCountPlugin& right ) { this->refCount.store( right.refCount ); } inline void Initialize( GenericRTTI *obj ) { this->refCount = 1; // we start off with one. } inline void Shutdown( GenericRTTI *obj ) { // Has to be zeroed by the manager. assert( this->refCount == 0 ); } inline void AddRef( void ) { this->refCount++; } inline bool RemoveRef( void ) { return ( this->refCount.fetch_sub( 1 ) == 1 ); } }; struct refCountManager { inline void Initialize( EngineInterface *engineInterface ) { this->pluginOffset = engineInterface->typeSystem.RegisterDependantStructPlugin <refCountPlugin> ( engineInterface->rwobjTypeInfo, RwTypeSystem::ANONYMOUS_PLUGIN_ID ); } inline void Shutdown( EngineInterface *engineInterface ) { engineInterface->typeSystem.UnregisterPlugin( engineInterface->rwobjTypeInfo, this->pluginOffset ); } inline refCountPlugin* GetPluginStruct( EngineInterface *engineInterface, RwObject *obj ) { GenericRTTI *rtObj = RwTypeSystem::GetTypeStructFromObject( obj ); return RwTypeSystem::RESOLVE_STRUCT <refCountPlugin> ( engineInterface, rtObj, engineInterface->rwobjTypeInfo, this->pluginOffset ); } RwTypeSystem::pluginOffset_t pluginOffset; }; static PluginDependantStructRegister <refCountManager, RwInterfaceFactory_t> refCountRegister; // Acquisition routine for objects, so that reference counting is increased, if needed. // Can return NULL if the reference count could not be increased. RwObject* AcquireObject( RwObject *obj ) { EngineInterface *engineInterface = (EngineInterface*)obj->engineInterface; // Increase the reference count. if ( refCountManager *refMan = refCountRegister.GetPluginStruct( engineInterface ) ) { if ( refCountPlugin *refCount = refMan->GetPluginStruct( engineInterface, obj ) ) { // TODO: make sure that incrementing is actually possible. // we cannot increment if we would overflow the number, for instance. refCount->AddRef(); } } return obj; } void ReleaseObject( RwObject *obj ) { EngineInterface *engineInterface = (EngineInterface*)obj->engineInterface; // Increase the reference count. if ( refCountManager *refMan = refCountRegister.GetPluginStruct( (EngineInterface*)engineInterface ) ) { if ( refCountPlugin *refCount = refMan->GetPluginStruct( engineInterface, obj ) ) { // We just delete the object. engineInterface->DeleteRwObject( obj ); } } } uint32 GetRefCount( RwObject *obj ) { uint32 refCountNum = 1; // If we do not support reference counting, this is actually a valid value. EngineInterface *engineInterface = (EngineInterface*)obj->engineInterface; // Increase the reference count. if ( refCountManager *refMan = refCountRegister.GetPluginStruct( engineInterface ) ) { if ( refCountPlugin *refCount = refMan->GetPluginStruct( engineInterface, obj ) ) { // We just delete the object. refCountNum = refCount->refCount; } } return refCountNum; } RwObject* Interface::ConstructRwObject( const char *typeName ) { EngineInterface *engineInterface = (EngineInterface*)this; RwObject *newObj = NULL; if ( RwTypeSystem::typeInfoBase *rwobjTypeInfo = engineInterface->rwobjTypeInfo ) { // Try to find a type that inherits from RwObject with this name. RwTypeSystem::typeInfoBase *rwTypeInfo = engineInterface->typeSystem.FindTypeInfo( typeName, rwobjTypeInfo ); if ( rwTypeInfo ) { // Try to construct us. GenericRTTI *rtObj = engineInterface->typeSystem.Construct( engineInterface, rwTypeInfo, NULL ); if ( rtObj ) { // We are successful! Return the new object. newObj = (RwObject*)RwTypeSystem::GetObjectFromTypeStruct( rtObj ); } } } return newObj; } RwObject* Interface::CloneRwObject( const RwObject *srcObj ) { EngineInterface *engineInterface = (EngineInterface*)this; RwObject *newObj = NULL; // We simply use our type system to do the job. const GenericRTTI *rttiObj = engineInterface->typeSystem.GetTypeStructFromConstAbstractObject( srcObj ); if ( rttiObj ) { GenericRTTI *newRtObj = engineInterface->typeSystem.Clone( engineInterface, rttiObj ); if ( newRtObj ) { newObj = (RwObject*)RwTypeSystem::GetObjectFromTypeStruct( newRtObj ); } } return newObj; } void Interface::DeleteRwObject( RwObject *obj ) { EngineInterface *engineInterface = (EngineInterface*)this; // Delete it using the type system. GenericRTTI *rttiObj = engineInterface->typeSystem.GetTypeStructFromAbstractObject( obj ); if ( rttiObj ) { // By default, we can destroy. bool canDestroy = true; // If we have the refcount plugin, we want to handle things with it. if ( refCountManager *refMan = refCountRegister.GetPluginStruct( engineInterface ) ) { if ( refCountPlugin *refCountObj = RwTypeSystem::RESOLVE_STRUCT <refCountPlugin> ( engineInterface, rttiObj, engineInterface->rwobjTypeInfo, refMan->pluginOffset ) ) { canDestroy = refCountObj->RemoveRef(); } } if ( canDestroy ) { engineInterface->typeSystem.Destroy( engineInterface, rttiObj ); } } } void Interface::GetObjectTypeNames( rwobjTypeNameList_t& listOut ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; if ( RwTypeSystem::typeInfoBase *rwobjTypeInfo = engineInterface->rwobjTypeInfo ) { for ( RwTypeSystem::type_iterator iter = engineInterface->typeSystem.GetTypeIterator(); !iter.IsEnd(); iter.Increment() ) { RwTypeSystem::typeInfoBase *item = iter.Resolve(); if ( item != rwobjTypeInfo ) { if ( engineInterface->typeSystem.IsTypeInheritingFrom( rwobjTypeInfo, item ) ) { listOut.push_back( item->name ); } } } } } bool Interface::IsObjectRegistered( const char *typeName ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; if ( RwTypeSystem::typeInfoBase *rwobjTypeInfo = engineInterface->rwobjTypeInfo ) { // Try to find a type that inherits from RwObject with this name. RwTypeSystem::typeInfoBase *rwTypeInfo = engineInterface->typeSystem.FindTypeInfo( typeName, rwobjTypeInfo ); if ( rwTypeInfo ) { return true; } } return false; } const char* Interface::GetObjectTypeName( const RwObject *rwObj ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; const char *typeName = "unknown"; const GenericRTTI *rtObj = engineInterface->typeSystem.GetTypeStructFromConstAbstractObject( rwObj ); if ( rtObj ) { RwTypeSystem::typeInfoBase *typeInfo = RwTypeSystem::GetTypeInfoFromTypeStruct( rtObj ); // Return its type name. // This is an IMMUTABLE property, so we are safe. typeName = typeInfo->name; } return typeName; } void Interface::SetWarningManager( WarningManagerInterface *warningMan ) { EngineInterface *engineInterface = (EngineInterface*)this; GetEnvironmentConfigBlock( engineInterface ).SetWarningManager( warningMan ); } WarningManagerInterface* Interface::GetWarningManager( void ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; return GetConstEnvironmentConfigBlock( engineInterface ).GetWarningManager(); } void Interface::SetWarningLevel( int level ) { EngineInterface *engineInterface = (EngineInterface*)this; GetEnvironmentConfigBlock( engineInterface ).SetWarningLevel( level ); } int Interface::GetWarningLevel( void ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; return GetConstEnvironmentConfigBlock( engineInterface ).GetWarningLevel(); } void Interface::SetIgnoreSecureWarnings( bool doIgnore ) { EngineInterface *engineInterface = (EngineInterface*)this; GetEnvironmentConfigBlock( engineInterface ).SetIgnoreSecureWarnings( doIgnore ); } bool Interface::GetIgnoreSecureWarnings( void ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; return GetConstEnvironmentConfigBlock( engineInterface ).GetIgnoreSecureWarnings(); } bool Interface::SetPaletteRuntime( ePaletteRuntimeType palRunType ) { EngineInterface *engineInterface = (EngineInterface*)this; return GetEnvironmentConfigBlock( engineInterface ).SetPaletteRuntime( palRunType ); } ePaletteRuntimeType Interface::GetPaletteRuntime( void ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; return GetConstEnvironmentConfigBlock( engineInterface ).GetPaletteRuntime(); } void Interface::SetDXTRuntime( eDXTCompressionMethod dxtRunType ) { EngineInterface *engineInterface = (EngineInterface*)this; GetEnvironmentConfigBlock( engineInterface ).SetDXTRuntime( dxtRunType ); } eDXTCompressionMethod Interface::GetDXTRuntime( void ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; return GetConstEnvironmentConfigBlock( engineInterface ).GetDXTRuntime(); } void Interface::SetFixIncompatibleRasters( bool doFix ) { EngineInterface *engineInterface = (EngineInterface*)this; GetEnvironmentConfigBlock( engineInterface ).SetFixIncompatibleRasters( doFix ); } bool Interface::GetFixIncompatibleRasters( void ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; return GetConstEnvironmentConfigBlock( engineInterface ).GetFixIncompatibleRasters(); } void Interface::SetCompatTransformNativeImaging( bool transfEnable ) { EngineInterface *engineInterface = (EngineInterface*)this; GetEnvironmentConfigBlock( engineInterface ).SetCompatTransformNativeImaging( transfEnable ); } bool Interface::GetCompatTransformNativeImaging( void ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; return GetConstEnvironmentConfigBlock( engineInterface ).GetCompatTransformNativeImaging(); } void Interface::SetPreferPackedSampleExport( bool preferPacked ) { EngineInterface *engineInterface = (EngineInterface*)this; GetEnvironmentConfigBlock( engineInterface ).SetPreferPackedSampleExport( preferPacked ); } bool Interface::GetPreferPackedSampleExport( void ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; return GetConstEnvironmentConfigBlock( engineInterface ).GetPreferPackedSampleExport(); } void Interface::SetDXTPackedDecompression( bool packedDecompress ) { EngineInterface *engineInterface = (EngineInterface*)this; GetEnvironmentConfigBlock( engineInterface ).SetDXTPackedDecompression( packedDecompress ); } bool Interface::GetDXTPackedDecompression( void ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; return GetConstEnvironmentConfigBlock( engineInterface ).GetDXTPackedDecompression(); } void Interface::SetIgnoreSerializationBlockRegions( bool doIgnore ) { EngineInterface *engineInterface = (EngineInterface*)this; GetEnvironmentConfigBlock( engineInterface ).SetIgnoreSerializationBlockRegions( doIgnore ); } bool Interface::GetIgnoreSerializationBlockRegions( void ) const { const EngineInterface *engineInterface = (const EngineInterface*)this; return GetConstEnvironmentConfigBlock( engineInterface ).GetIgnoreSerializationBlockRegions(); } // Static library object that takes care of initializing the module dependencies properly. extern void registerConfigurationEnvironment( void ); extern void registerThreadingEnvironment( void ); extern void registerWarningHandlerEnvironment( void ); extern void registerRasterConsistency( void ); extern void registerEventSystem( void ); extern void registerTXDPlugins( void ); extern void registerObjectExtensionsPlugins( void ); extern void registerSerializationPlugins( void ); extern void registerStreamGlobalPlugins( void ); extern void registerFileSystemDataRepository( void ); extern void registerImagingPlugin( void ); extern void registerWindowingSystem( void ); extern void registerDriverEnvironment( void ); extern void registerDrawingLayerEnvironment( void ); extern void registerConfigurationBlockDispatching( void ); static bool hasInitialized = false; static bool VerifyLibraryIntegrity( void ) { // We need to standardize the number formats. // One way to check that is to make out their size, I guess. // Then there is also the problem of endianness, which we do not check here :( // For that we have to add special handling into the serialization environments. return ( sizeof(uint8) == 1 && sizeof(uint16) == 2 && sizeof(uint32) == 4 && sizeof(uint64) == 8 && sizeof(int8) == 1 && sizeof(int16) == 2 && sizeof(int32) == 4 && sizeof(int64) == 8 && sizeof(float32) == 4 ); } // Interface creation for the RenderWare engine. Interface* CreateEngine( LibraryVersion theVersion ) { if ( hasInitialized == false ) { // Verify data constants before we create a valid engine. if ( VerifyLibraryIntegrity() ) { // Configuration comes first. registerConfigurationEnvironment(); // Initialize our plugins first. refCountRegister.RegisterPlugin( engineFactory ); rwlockProvider.RegisterPlugin( engineFactory ); // Now do the main modules. registerThreadingEnvironment(); registerWarningHandlerEnvironment(); registerRasterConsistency(); registerEventSystem(); registerStreamGlobalPlugins(); registerFileSystemDataRepository(); registerSerializationPlugins(); registerObjectExtensionsPlugins(); registerTXDPlugins(); registerImagingPlugin(); registerWindowingSystem(); registerDriverEnvironment(); registerDrawingLayerEnvironment(); // After all plugins registered themselves, we know that // each configuration entry is properly initialized. // Now we can create a configuration block in the interface! registerConfigurationBlockDispatching(); hasInitialized = true; } } Interface *engineOut = NULL; if ( hasInitialized == true ) { // Create a specialized engine depending on the version. engineOut = engineFactory.Construct( _engineMemAlloc ); if ( engineOut ) { engineOut->SetVersion( theVersion ); } } return engineOut; } void DeleteEngine( Interface *theEngine ) { assert( hasInitialized == true ); EngineInterface *engineInterface = (EngineInterface*)theEngine; // Kill everything threading related, so we can terminate (WARNING: HACK) PurgeActiveThreadingObjects( engineInterface ); // Destroy the engine again. engineFactory.Destroy( _engineMemAlloc, engineInterface ); } };
namespace rw { void d3d8NativeTextureTypeProvider::DeserializeTexture( TextureBase *theTexture, PlatformTexture *nativeTex, BlockProvider& inputProvider ) const { Interface *engineInterface = theTexture->engineInterface; { BlockProvider texNativeImageStruct( &inputProvider ); texNativeImageStruct.EnterContext(); try { if ( texNativeImageStruct.getBlockID() == CHUNK_STRUCT ) { d3d8::textureMetaHeaderStructGeneric metaHeader; texNativeImageStruct.read( &metaHeader, sizeof(metaHeader) ); uint32 platform = metaHeader.platformDescriptor; if (platform != PLATFORM_D3D8) { throw RwException( "invalid platform type in Direct3D 8 texture reading" ); } // Recast the texture to our native type. NativeTextureD3D8 *platformTex = (NativeTextureD3D8*)nativeTex; int engineWarningLevel = engineInterface->GetWarningLevel(); bool engineIgnoreSecureWarnings = engineInterface->GetIgnoreSecureWarnings(); // Read the texture names. { char tmpbuf[ sizeof( metaHeader.name ) + 1 ]; // Make sure the name buffer is zero terminted. tmpbuf[ sizeof( metaHeader.name ) ] = '\0'; // Move over the texture name. memcpy( tmpbuf, metaHeader.name, sizeof( metaHeader.name ) ); theTexture->SetName( tmpbuf ); // Move over the texture mask name. memcpy( tmpbuf, metaHeader.maskName, sizeof( metaHeader.maskName ) ); theTexture->SetMaskName( tmpbuf ); } // Read texture format. texFormatInfo formatInfo = metaHeader.texFormat; formatInfo.parse( *theTexture ); // Deconstruct the format flags. bool hasMipmaps = false; // TODO: actually use this flag. readRasterFormatFlags( metaHeader.rasterFormat, platformTex->rasterFormat, platformTex->paletteType, hasMipmaps, platformTex->autoMipmaps ); platformTex->hasAlpha = ( metaHeader.hasAlpha != 0 ? true : false ); uint32 depth = metaHeader.depth; uint32 maybeMipmapCount = metaHeader.mipmapCount; platformTex->depth = depth; platformTex->rasterType = metaHeader.rasterType; // Decide about the color order. { eColorOrdering colorOrder = COLOR_BGRA; if ( platformTex->paletteType != PALETTE_NONE ) { colorOrder = COLOR_RGBA; } platformTex->colorOrdering = colorOrder; } // Read compression information. { uint32 dxtInfo = metaHeader.dxtCompression; platformTex->dxtCompression = dxtInfo; // If we are compressed, it must be a compression we know about. if ( dxtInfo != 0 ) { if ( dxtInfo != 1 && dxtInfo != 2 && dxtInfo != 3 && dxtInfo != 4 && dxtInfo != 5 ) { throw RwException( "invalid Direct3D texture compression format" ); } } } // Verify raster properties and attempt to fix broken textures. // Broken textures travel with mods like San Andreas Retextured. // - Verify depth. { bool hasInvalidDepth = false; if (platformTex->paletteType == PALETTE_4BIT) { if (depth != 4 && depth != 8) { hasInvalidDepth = true; } } else if (platformTex->paletteType == PALETTE_8BIT) { if (depth != 8) { hasInvalidDepth = true; } } if (hasInvalidDepth == true) { throw RwException( "texture " + theTexture->GetName() + " has an invalid depth" ); // We cannot fix an invalid depth. } } if (platformTex->paletteType != PALETTE_NONE) { uint32 reqPalItemCount = getD3DPaletteCount( platformTex->paletteType ); uint32 palDepth = Bitmap::getRasterFormatDepth( platformTex->rasterFormat ); assert( palDepth != 0 ); size_t paletteDataSize = getPaletteDataSize( reqPalItemCount, palDepth ); // Check whether we have palette data in the stream. texNativeImageStruct.check_read_ahead( paletteDataSize ); void *palData = engineInterface->PixelAllocate( paletteDataSize ); try { texNativeImageStruct.read( palData, paletteDataSize ); } catch( ... ) { engineInterface->PixelFree( palData ); throw; } // Store the palette. platformTex->palette = palData; platformTex->paletteSize = reqPalItemCount; } mipGenLevelGenerator mipLevelGen( metaHeader.width, metaHeader.height ); if ( !mipLevelGen.isValidLevel() ) { throw RwException( "texture " + theTexture->GetName() + " has invalid dimensions" ); } uint32 mipmapCount = 0; uint32 processedMipmapCount = 0; uint32 dxtCompression = platformTex->dxtCompression; bool hasDamagedMipmaps = false; for (uint32 i = 0; i < maybeMipmapCount; i++) { bool couldEstablishLevel = true; if (i > 0) { couldEstablishLevel = mipLevelGen.incrementLevel(); } if (!couldEstablishLevel) { break; } // Create a new mipmap layer. NativeTextureD3D8::mipmapLayer newLayer; newLayer.layerWidth = mipLevelGen.getLevelWidth(); newLayer.layerHeight = mipLevelGen.getLevelHeight(); // Process dimensions. uint32 texWidth = newLayer.layerWidth; uint32 texHeight = newLayer.layerHeight; { // DXT compression works on 4x4 blocks, // no smaller values allowed if (dxtCompression != 0) { texWidth = ALIGN_SIZE( texWidth, 4u ); texHeight = ALIGN_SIZE( texHeight, 4u ); } } newLayer.width = texWidth; newLayer.height = texHeight; uint32 texDataSize = texNativeImageStruct.readUInt32(); // We started processing this mipmap. processedMipmapCount++; // Verify the data size. bool isValidMipmap = true; { uint32 actualDataSize = 0; if (dxtCompression != 0) { uint32 texItemCount = ( texWidth * texHeight ); actualDataSize = getDXTRasterDataSize(dxtCompression, texItemCount); } else { uint32 rowSize = getD3DRasterDataRowSize( texWidth, depth ); actualDataSize = getRasterDataSizeByRowSize( rowSize, texHeight ); } if (actualDataSize != texDataSize) { isValidMipmap = false; } } if ( !isValidMipmap ) { // Even the Rockstar games texture generator appeared to have problems with mipmap generation. // This is why textures appear to have the size of zero. if (texDataSize != 0) { if ( !engineIgnoreSecureWarnings ) { engineInterface->PushWarning( "texture " + theTexture->GetName() + " has damaged mipmaps (ignoring)" ); } hasDamagedMipmaps = true; } // Skip the damaged bytes. if (texDataSize != 0) { texNativeImageStruct.skip( texDataSize ); } break; } // We first have to check whether there is enough data in the stream. // Otherwise we would just flood the memory in case of an error; // that could be abused by exploiters. texNativeImageStruct.check_read_ahead( texDataSize ); void *texelData = engineInterface->PixelAllocate( texDataSize ); try { texNativeImageStruct.read( texelData, texDataSize ); } catch( ... ) { engineInterface->PixelFree( texelData ); throw; } // Store mipmap properties. newLayer.dataSize = texDataSize; // Store the image data pointer. newLayer.texels = texelData; // Put the layer. platformTex->mipmaps.push_back( newLayer ); mipmapCount++; } if ( mipmapCount == 0 ) { throw RwException( "texture " + theTexture->GetName() + " is empty" ); } // mipmapCount can only be smaller than maybeMipmapCount. // This is logically true and would be absurd to assert here. if ( processedMipmapCount < maybeMipmapCount ) { // Skip the remaining mipmaps (most likely zero-sized). bool hasSkippedNonZeroSized = false; for ( uint32 n = processedMipmapCount; n < maybeMipmapCount; n++ ) { uint32 mipSize = texNativeImageStruct.readUInt32(); if ( mipSize != 0 ) { hasSkippedNonZeroSized = true; // Skip the section. texNativeImageStruct.skip( mipSize ); } } if ( !engineIgnoreSecureWarnings && !hasDamagedMipmaps ) { // Print the debug message. if ( !hasSkippedNonZeroSized ) { engineInterface->PushWarning( "texture " + theTexture->GetName() + " has zero sized mipmaps" ); } else { engineInterface->PushWarning( "texture " + theTexture->GetName() + " violates mipmap rules" ); } } } // Fix filtering mode. fixFilteringMode( *theTexture, mipmapCount ); // - Verify auto mipmap { bool hasAutoMipmaps = platformTex->autoMipmaps; if ( hasAutoMipmaps ) { bool canHaveAutoMipmaps = ( mipmapCount == 1 ); if ( !canHaveAutoMipmaps ) { engineInterface->PushWarning( "texture " + theTexture->GetName() + " has an invalid auto-mipmap flag (fixing)" ); platformTex->autoMipmaps = false; } } } } else { engineInterface->PushWarning( "failed to find texture native image struct in D3D texture native" ); } } catch( ... ) { texNativeImageStruct.LeaveContext(); throw; } texNativeImageStruct.LeaveContext(); } // Read extensions. engineInterface->DeserializeExtensions( theTexture, inputProvider ); } static PluginDependantStructRegister <d3d8NativeTextureTypeProvider, RwInterfaceFactory_t> d3dNativeTexturePluginRegister; void registerD3D8NativePlugin( void ) { d3dNativeTexturePluginRegister.RegisterPlugin( engineFactory ); } };