http://coding.hanfling.de/launch/release/UnExt-20150504.zip
Description:
Unlinke in Unreal 227, the interfaces such as URenderDevice, UAudioSubsystem, UTexture, etc. are rather fixed. So if one would want to extend that functionality one would need to pull in either other packages and thus making these a requirement and largely incompatible, or one adds simply adding console commands. However both solutions are not really satisfying.
I can up with a powerful solution using the FUnknown (COM) interface, which is completely unused, which does not require linking and thus not pulling in any other dependencies.
Code: Select all
//
// COM IUnknown interface.
//
class CORE_API FUnknown
{
public:
virtual DWORD STDCALL QueryInterface( const FGuid& RefIID, void** InterfacePtr ) {return 0;}
virtual DWORD STDCALL AddRef() {return 0;}
virtual DWORD STDCALL Release() {return 0;}
};
Currently just one interface/guid is defined named IKnowWonderRenderDevice, which matches the URenderDevice interface found in Disney's Brother Bear and probably their UE1 Harry Potter games.
My first use of it was to add a seperate gamma command to my gameengine class, which would check for that interface, and if not found fall back to using old Flush() style to update gamma.
So lets start with the header files:
UnExt.h
Code: Select all
/*=============================================================================
UnExt.h: UnrealEngine Extension main header.
Revision history:
* Created by Sebastian Kaufel
=============================================================================*/
#ifndef UNEXT_GUID_ONLY
#define UNEXT_AUTOGENERATE_GUID(name,a,b,c,d) extern FGuid name;
#endif
#ifdef UNEXT_INCLUDE_RENDERDEVICES
#include "UnExtRenDev.h"
#endif
#ifndef UNEXT_GUID_ONLY
#undef UNEXT_AUTOGENERATE_GUID
#endif NAMES_ONLY
/*----------------------------------------------------------------------------
The End.
----------------------------------------------------------------------------*/
Code: Select all
/*=============================================================================
UnExtRenDev.h: UnrealEngine Extension render device header.
Revision history:
* Created by Sebastian Kaufel
=============================================================================*/
UNEXT_AUTOGENERATE_GUID(IID_IKnowWonderRenderDevice,0xCB1E8908,0xEF4C4A4A,0xA5DD8D16,0x4F335D26)
#ifndef UNEXT_GUID_ONLY
/*-----------------------------------------------------------------------------
KnowWonder RenderDevice interface.
Motivation:
Disney's Brother Bear offers an extended URenderDevice interface,
which reflects a logical next step to clean up the rendering path
with it's introduction of an interface to draw bunches of polygons,
optional font rendering, distance fog and gamma handling.
Reference implementation:
* Disney's Brother Bear.
Notes:
* Might be (partially) implemented in KnowWonder's Harry Potter games.
-----------------------------------------------------------------------------*/
struct IKnowWonderRenderDevice
{
virtual UBOOL Init( UViewport* InViewport, INT NewX, INT NewY, INT NewColorBytes, UBOOL Fullscreen )=0;
virtual UBOOL SetRes( INT NewX, INT NewY, INT NewColorBytes, UBOOL Fullscreen )=0;
virtual void Exit()=0;
virtual void Flush( UBOOL AllowPrecache )=0;
virtual UBOOL Exec( const TCHAR* Cmd, FOutputDevice& Ar )=0;
virtual void Lock( FPlane FlashScale, FPlane FlashFog, FPlane ScreenClear, DWORD RenderLockFlags, BYTE* HitData, INT* HitSize )=0;
virtual void Unlock( UBOOL Blit )=0;
virtual void UpdateGamma()=0;
virtual void RestoreGamma()=0;
virtual void DrawComplexSurface( FSceneNode* Frame, FSurfaceInfo& Surface, FSurfaceFacet& Facet, DWORD, BYTE )=0;
virtual INT MaxVertices()=0;
virtual void DrawTriangles( FSceneNode* Frame, FTextureInfo& Info, FTransTexture** Pts, INT NumPts, _WORD* RemapTable, INT NumIndices, DWORD PolyFlags, class FSpanBuffer* Span )=0;
virtual void DrawGouraudPolygon( FSceneNode* Frame, FTextureInfo& Info, FTransTexture** Pts, INT NumPts, DWORD PolyFlags, FSpanBuffer* Span )=0;
virtual void DrawTile( FSceneNode* Frame, FTextureInfo& Info, FLOAT X, FLOAT Y, FLOAT XL, FLOAT YL, FLOAT U, FLOAT V, FLOAT UL, FLOAT VL, class FSpanBuffer* Span, FLOAT Z, FPlane Color, FPlane Fog, DWORD PolyFlags )=0;
virtual void Draw3DLine( FSceneNode* Frame, FPlane Color, DWORD LineFlags, FVector OrigP, FVector OrigQ )=0;
virtual void Draw2DClippedLine( FSceneNode* Frame, FPlane Color, DWORD LineFlags, FVector P1, FVector P2 )=0;
virtual void Draw2DLine( FSceneNode* Frame, FPlane Color, DWORD LineFlags, FVector P1, FVector P2 )=0;
virtual void Draw2DPoint( FSceneNode* Frame, FPlane Color, DWORD LineFlags, FLOAT X1, FLOAT Y1, FLOAT X2, FLOAT Y2, FLOAT Z )=0;
virtual void ClearZ( FSceneNode* Frame )=0;
virtual void PushHit( const BYTE* Data, INT Count )=0;
virtual void PopHit( INT Count, UBOOL bForce )=0;
virtual void GetStats( TCHAR* Result )=0;
virtual void ReadPixels( FColor* Pixels )=0;
virtual void EndFlash()=0;
virtual void DrawStats( FSceneNode* Frame )=0;
virtual void SetSceneNode( FSceneNode* Frame )=0;
virtual void PrecacheTexture( FTextureInfo& Info, DWORD PolyFlags )=0;
virtual void SetDistanceFog( UBOOL Enable, FLOAT FogStart, FLOAT FogEnd, FColor Color )=0;
virtual void SetDistanceFogForceReset( UBOOL Enable )=0;
virtual UBOOL GetDistanceFogForceReset()=0;
virtual UBOOL HasNativeDrawString()=0;
virtual void DrawString( DWORD, UFont* Font, INT& X, INT& Y, const TCHAR* Text, const FPlane& Color )=0;
};
#endif // UNEXT_GUID_ONLY
/*----------------------------------------------------------------------------
The End.
----------------------------------------------------------------------------*/
Code: Select all
class UOpenGLRenderDevice : public URenderDevice, public IKnowWonderRenderDevice { ... }
Code: Select all
#define UNEXT_GUID_ONLY
#define UNEXT_AUTOGENERATE_GUID(name,a,b,c,d) FGuid name = FGuid(a,b,c,d);
#include "UnExt.h"
#undef AUTOGENERATE_FUNCTION
#undef UNEXT_GUID_ONLY
Code: Select all
//
// FUnknown.
//
DWORD STDCALL QueryInterface( const FGuid& RefIID, void** InterfacePtr )
{
if ( RefIID==IID_IKnowWonderRenderDevice )
{
*(IKnowWonderRenderDevice**)InterfacePtr = this;
return 1;
}
return 0;
}
So for using it on the other side you include the UnExt.h header to, and add the code for UNEXT_AUTOGENERATE_GUID in the same way. Next step is to query this interface, e.g. as part of my URevisionGameEngine::Exec() function:
Code: Select all
// Gamma update command using IKnowWonderRenderDevice
else if( ParseCommand(&Str,TEXT("UPDATEGAMMA")) )
{
if ( Client && Client->Viewports.Num() && Client->Viewports(0) && Client->Viewports(0)->RenDev )
{
IKnowWonderRenderDevice* I = NULL;
if ( Client->Viewports(0)->RenDev->QueryInterface(IID_IKnowWonderRenderDevice,(void**)&I) && I )
{
I->UpdateGamma();
Out.Logf( TEXT("Updated gamma using IKnowWonderRenderDevice.") );
return 1;
}
// Fallback.
Client->Viewports(0)->RenDev->Flush( 0 );
Out.Logf( TEXT("Updated gamma using fallback.") );
return 1;
}
// Fallback for Fallback.
Flush( 0 );
Out.Logf( TEXT("Updated gamma using fallbacks fallback.") );
return 1;
}
To sum up:
You get a clean way to extend individual components, have a clean way to check for these capabilities and don't need to depend on any specific class or implementation and get a great deal of compatiblity this way.