diff --git a/.vimrc b/.vimrc index d4a6f061..2340e9a2 100644 --- a/.vimrc +++ b/.vimrc @@ -3,7 +3,9 @@ set errorformat^=%f(%l):\ %m,%f(%l)\ :\ %m,%f\ :\ error\ %m,LINK\ :\ fatal\ erro map :wa let &makeprg='..\GameData\System\UCC.exe' make! make "ini=../../Code/UCC/UCC.ini" -noprompt -fullsourcepath -noincremental :cwindow map :wa let &makeprg='build.bat' make! debug :cwindow -map :!start "../GameData/System/CT.exe" dm_canyon?game=mpgame.dmgame?maxplayers=32?Listen -windowed -log -nosaveconfig -rendev=opengl + +" map :!start "../GameData/System/CT.exe" dm_canyon?game=mpgame.dmgame?maxplayers=32?Listen -windowed -log -nosaveconfig -rendev=rtx +map :!start "../GameData/System/CT.exe" geo_01a -windowed -log -nosaveconfig -rendev=rtx map :!start "../GameData/System/CTEditor.exe" augroup customhighlight diff --git a/CT.sln b/CT.sln index f3c0df37..5f353b5f 100644 --- a/CT.sln +++ b/CT.sln @@ -23,6 +23,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ModEd", "ModEd\ModEd.vcproj ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RtxDrv", "RtxDrv\RtxDrv.vcproj", "{D7878929-5402-468A-811D-1591523609F3}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug diff --git a/CT/Src/Launcher.cpp b/CT/Src/Launcher.cpp index 95bdfa33..814a2c9a 100644 --- a/CT/Src/Launcher.cpp +++ b/CT/Src/Launcher.cpp @@ -11,6 +11,21 @@ #pragma comment(lib, "Winmm.lib") // timeBeginPeriod, timeEndPeriod +// Allow short form of known render devices. +static FStringTemp GetFullRenderDeviceClassName(const FString& RenderDeviceClass) +{ + if(RenderDeviceClass == "D3D") + return "D3DDrv.D3DRenderDevice"; + else if(RenderDeviceClass == "OpenGL") + return "OpenGLDrv.OpenGLRenderDevice"; + else if(RenderDeviceClass == "Mod") + return "Mod.ModRenderDevice"; + else if(RenderDeviceClass == "Rtx") + return "RtxDrv.RtxRenderDevice"; + + return RenderDeviceClass; +} + static void EndFullscreen() { if(GEngine && GEngine->Client && GEngine->Client->Viewports.Num() > 0 && GEngine->Client->Viewports[0]) @@ -393,18 +408,18 @@ static struct FExecHook : public FExec, FNotifyHook{ SetFocus(Preferences->hWnd); return 1; - } - else if(!GIsEditor && GIsClient && ParseCommand(&Cmd, "USERENDEV")) - { - FString RenderDeviceClass = Cmd; - - if(RenderDeviceClass == "D3D") - RenderDeviceClass = "D3DDrv.D3DRenderDevice"; - else if(RenderDeviceClass == "OpenGL") - RenderDeviceClass = "OpenGLDrv.OpenGLRenderDevice"; - else if(RenderDeviceClass == "Mod") - RenderDeviceClass = "Mod.ModRenderDevice"; + }else if(GIsClient && ParseCommand(&Cmd, "GETRES")){ + Ar.Logf("%ix%i", GEngine->Client->Viewports[0]->SizeX, GEngine->Client->Viewports[0]->SizeY); + return 1; + }else if(ParseCommand(&Cmd, "GETRENDEV")){ + if(GEngine && GEngine->GRenDev) + Ar.Log(GEngine->GRenDev->GetClass()->GetPathName()); + else + Ar.Logf("No render device in use"); + return 1; + }else if(!GIsEditor && GIsClient && ParseCommand(&Cmd, "USERENDEV")){ + FString RenderDeviceClass = GetFullRenderDeviceClassName(Cmd); UClass* Class = LoadClass(NULL, *RenderDeviceClass, NULL, LOAD_NoWarn | LOAD_Quiet, NULL); if(Class) @@ -459,16 +474,8 @@ static void InitEngine() FString RenderDeviceClass; - if(Parse(appCmdLine(), "RenDev=", RenderDeviceClass)) - { - // Allow short form of known render devices. - if(RenderDeviceClass == "D3D") - RenderDeviceClass = "D3DDrv.D3DRenderDevice"; - else if(RenderDeviceClass == "OpenGL") - RenderDeviceClass = "OpenGLDrv.OpenGLRenderDevice"; - else if(RenderDeviceClass == "Mod") - RenderDeviceClass = "Mod.ModRenderDevice"; - + if(Parse(appCmdLine(), "RenDev=", RenderDeviceClass)){ + RenderDeviceClass = GetFullRenderDeviceClassName(RenderDeviceClass); debugf("RenderDevice set on command line: %s", *RenderDeviceClass); GConfig->SetString("Engine.Engine", "RenderDevice", *RenderDeviceClass); RenDevSetOnCommandLine = true; @@ -668,7 +675,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine appPreExit(); GIsGuarded = 0; - }catch(...) + } + catch(...) { GIsGuarded = 0; ExitCode = EXIT_FAILURE; diff --git a/Core/Inc/UnClass.h b/Core/Inc/UnClass.h index 59900e23..b7cf548c 100644 --- a/Core/Inc/UnClass.h +++ b/Core/Inc/UnClass.h @@ -240,6 +240,12 @@ class CORE_API UStruct : public UField{ UStruct* GetSuperStruct() const; bool StructCompare(const void* A, const void* B); + template + bool IsChildOf() + { + return IsChildOf(T::StaticClass()); + } + protected: // Cheat Protection BYTE FunctionMD5Digest[16]; // Holds a MD5 digest for this function diff --git a/Core/Inc/UnObjBas.h b/Core/Inc/UnObjBas.h index 744bd3ec..2476495f 100644 --- a/Core/Inc/UnObjBas.h +++ b/Core/Inc/UnObjBas.h @@ -511,7 +511,6 @@ class CORE_API UObject{ UBOOL IsA(FName SomeBaseClassName) const; UBOOL IsIn(UObject* SomeOuter) const; UBOOL IsProbing(FName ProbeName); - UField* FindObjectField(FName InName, UBOOL Global = 0); UFunction* FindFunction(FName InName, UBOOL Global = 0); UFunction* FindFunctionChecked(FName InName, UBOOL Global = 0); UState* FindState(FName InName); diff --git a/D3DDrv/Inc/D3DDrv.h b/D3DDrv/Inc/D3DDrv.h index 46c01977..7ae7ca01 100644 --- a/D3DDrv/Inc/D3DDrv.h +++ b/D3DDrv/Inc/D3DDrv.h @@ -18,10 +18,39 @@ struct IDirect3DDevice8; class D3DDRV_API UD3DRenderDevice : public URenderDevice{ DECLARE_CLASS(UD3DRenderDevice,URenderDevice,CLASS_Config,D3DDrv); public: - char Padding1[17920]; + char Padding1[16412]; // Padding + UBOOL UsePrecaching; + UBOOL UseTrilinear; + INT Padding2; // Padding + UBOOL UseVSync; + UBOOL UseHardwareTL; + UBOOL UseHardwareVS; + UBOOL UseCubemaps; + char PADDING3[16]; // Padding + UBOOL UseTripleBuffering; + UBOOL ReduceMouseLag; + UBOOL UseXBoxFSAA; + char Padding4[16]; // Padding + UBOOL CheckForOverflow; + UBOOL UseNPatches; + UBOOL DecompressTextures; + UBOOL AvoidHitches; + UBOOL OverrideDesktopRefreshRate; + INT Padding5; // Padding + INT AdapterNumber; + INT Padding6; // Padding + INT MaxPixelShaderVersion; + INT LevelOfAnisotropy; + FLOAT DetailTexMipBias; + FLOAT DefaultTexMipBias; + FLOAT TesselationFactor; + FLOAT DesiredRefreshRate; + INT VideoResetAttempts; + UBOOL StateCachingDisabled; + char Padding7[1370]; // Padding IDirect3D8* Direct3D8; IDirect3DDevice8* Direct3DDevice8; - char Padding2[47868]; + char Padding8[47868]; // Padding //Overrides virtual UBOOL Exec(const TCHAR* Cmd, FOutputDevice& Ar); diff --git a/Engine/Inc/EngineClasses.h b/Engine/Inc/EngineClasses.h index 7b7315b9..d931a479 100644 --- a/Engine/Inc/EngineClasses.h +++ b/Engine/Inc/EngineClasses.h @@ -5968,6 +5968,105 @@ class ENGINE_API UHardwareShaderWrapper : public URenderedMaterial{ } }; +/* + * HsBumpDiffBlend + */ + +class ENGINE_API UHsBumpDiffBlend : public UHardwareShaderWrapper{ +public: + class UTexture* DiffuseTexture; + class UTexture* BlendTexture; + class UTexture* NormalMap; + FLOAT DiffUVScale; + FLOAT BlendUVScale; + FLOAT BumpUVScale; + + DECLARE_CLASS(UHsBumpDiffBlend,UHardwareShaderWrapper,0,Engine) + // Make sure to implement this function in UnHardwareShaderWrapper.cpp + virtual INT SetupShaderWrapper(class FRenderInterface* RI); +}; + +/* + * HsBumpDiffBlendMask + */ + +class ENGINE_API UHsBumpDiffBlendMask : public UHardwareShaderWrapper{ +public: + class UTexture* DiffuseTexture; + class UTexture* BlendTexture; + class UTexture* NormalMap; + FLOAT DiffUVScale; + FLOAT BlendUVScale; + FLOAT BumpUVScale; + BYTE VertexToTextureBlend; + + DECLARE_CLASS(UHsBumpDiffBlendMask,UHardwareShaderWrapper,0,Engine) + // Make sure to implement this function in UnHardwareShaderWrapper.cpp + virtual INT SetupShaderWrapper(class FRenderInterface* RI); +}; + +/* + * HsBumpDiffBlendMaskIllum + */ + +class ENGINE_API UHsBumpDiffBlendMaskIllum : public UHardwareShaderWrapper{ +public: + class UTexture* DiffuseTexture; + class UTexture* BlendTexture; + class UTexture* NormalMap; + FLOAT DiffUVScale; + FLOAT BlendUVScale; + FLOAT BumpUVScale; + BYTE VertexToTextureBlend; + + DECLARE_CLASS(UHsBumpDiffBlendMaskIllum,UHardwareShaderWrapper,0,Engine) + // Make sure to implement this function in UnHardwareShaderWrapper.cpp + virtual INT SetupShaderWrapper(class FRenderInterface* RI); +}; + +/* + * HsBumpDiffSpec + */ + +class ENGINE_API UHsBumpDiffSpec : public UHardwareShaderWrapper{ +public: + class UTexture* DiffuseTexture; + class UTexture* NormalMap; + FLOAT DiffUVScale; + FLOAT BumpUVScale; + BYTE Specularity; + FColor SpecularTint; + + DECLARE_CLASS(UHsBumpDiffSpec,UHardwareShaderWrapper,0,Engine) + // Make sure to implement this function in UnHardwareShaderWrapper.cpp + virtual INT SetupShaderWrapper(class FRenderInterface* RI); +}; + +/* + * HsFalloff + */ + +class ENGINE_API UHsFalloff : public UHardwareShaderWrapper{ +public: + class UTexture* DiffuseTexture; + class UTexture* FalloffGradient; + FLOAT UPanRate; + FLOAT VPanRate; + FLOAT UOscilationRate; + FLOAT VOscilationRate; + FLOAT GradientBlendMode; + FColor DiffuseTint; + FColor GradientTint; + BYTE SrcBlend; + BYTE DestBlend; + BITFIELD ZTest:1; + BITFIELD ZWrite:1; + + DECLARE_CLASS(UHsFalloff,UHardwareShaderWrapper,0,Engine) + // Make sure to implement this function in UnHardwareShaderWrapper.cpp + virtual INT SetupShaderWrapper(class FRenderInterface* RI); +}; + /* * HsHologram */ @@ -5983,6 +6082,26 @@ class ENGINE_API UHsHologram : public UHardwareShaderWrapper{ virtual INT SetupShaderWrapper(class FRenderInterface* RI); }; +/* + * HsWorldDistortion + */ + +class ENGINE_API UHsWorldDistortion : public UHardwareShaderWrapper{ +public: + FColor ColorAdd; + FColor ColorVariation; + float WorldDistortion; + FLOAT WobbleScale; + FLOAT WobbleSpeed; + FLOAT WobbleAmplitute; + BITFIELD VortexEffect:1; + BYTE Alpha; + + DECLARE_CLASS(UHsWorldDistortion,UHardwareShaderWrapper,0,Engine) + // Make sure to implement this function in UnHardwareShaderWrapper.cpp + virtual INT SetupShaderWrapper(class FRenderInterface* RI); +}; + /* * ParticleMaterial */ diff --git a/Engine/Inc/UnRender.h b/Engine/Inc/UnRender.h index ab66798c..dd7b0414 100644 --- a/Engine/Inc/UnRender.h +++ b/Engine/Inc/UnRender.h @@ -137,7 +137,7 @@ class ENGINE_API FLevelSceneNode : public FSceneNode{ // Virtual functions virtual FConvexVolume GetViewFrustum(); virtual UBOOL FilterActor(AActor* Actor); - virtual UBOOL FilterAttachment(AActor* AttachedActor){ return 1; } + virtual UBOOL FilterAttachment(AActor* AttachedActor){ return 1; } virtual UBOOL FilterProjector(AProjector* Actor); }; diff --git a/Mod/PropertyOverrides/CTInventory.BattleDroidBlasterProj.txt b/Mod/PropertyOverrides/CTInventory.BattleDroidBlasterProj.txt new file mode 100644 index 00000000..c8dfdc51 --- /dev/null +++ b/Mod/PropertyOverrides/CTInventory.BattleDroidBlasterProj.txt @@ -0,0 +1,2 @@ +LightHue=255 +LightSaturation=40 diff --git a/Mod/PropertyOverrides/CTInventory.DC17BlasterProj.txt b/Mod/PropertyOverrides/CTInventory.DC17BlasterProj.txt new file mode 100644 index 00000000..9c15c7ea --- /dev/null +++ b/Mod/PropertyOverrides/CTInventory.DC17BlasterProj.txt @@ -0,0 +1,2 @@ +LightHue=170 +LightSaturation=40 diff --git a/Mod/PropertyOverrides/Properties.BattleDroidBlasterProjTM.txt b/Mod/PropertyOverrides/Properties.BattleDroidBlasterProjTM.txt new file mode 100644 index 00000000..c8dfdc51 --- /dev/null +++ b/Mod/PropertyOverrides/Properties.BattleDroidBlasterProjTM.txt @@ -0,0 +1,2 @@ +LightHue=255 +LightSaturation=40 diff --git a/ModEd/Src/ModEd.cpp b/ModEd/Src/ModEd.cpp index 70c6c374..b75f7813 100644 --- a/ModEd/Src/ModEd.cpp +++ b/ModEd/Src/ModEd.cpp @@ -72,6 +72,33 @@ static WWindow* GetMainWindow() return *reinterpret_cast(0x10FE39D4); } +static WNDPROC OriginalMainWindowProc = NULL; + +LRESULT CALLBACK MainWindowProcOverride(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + if(Msg == WM_INPUT) + { + RAWINPUT RawInput; + UINT RawInputSize = sizeof(RawInput); + + if(GET_RAWINPUT_CODE_WPARAM(wParam) != RIM_INPUT) + return 0; + + if(GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, &RawInput, &RawInputSize, sizeof(RAWINPUTHEADER)) != (UINT)-1) + { + if(RawInput.header.dwType == RIM_TYPEMOUSE) + { + + } + } + + DefWindowProcA(hWnd, Msg, wParam, lParam); + return 0; + } + + return OriginalMainWindowProc(hWnd, Msg, wParam, lParam); +} + static void(__fastcall*OriginalUUnrealEdEngineTick)(UEditorEngine*, DWORD, FLOAT) = NULL; /* @@ -113,6 +140,22 @@ static void __fastcall UnrealEdEngineTickOverride(UEditorEngine* Self, DWORD Edx SendMessageA(GetMainWindow()->hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon); } + OriginalMainWindowProc = reinterpret_cast(GetWindowLongA(GetMainWindow()->hWnd, GWLP_WNDPROC)); + SetWindowLongA(GetMainWindow()->hWnd, GWLP_WNDPROC, reinterpret_cast(MainWindowProcOverride)); + +#ifndef HID_USAGE_PAGE_GENERIC +#define HID_USAGE_PAGE_GENERIC ((USHORT)0x01) +#define HID_USAGE_GENERIC_MOUSE ((USHORT)0x02) +#endif + + RAWINPUTDEVICE RawInput; + RawInput.usUsagePage = HID_USAGE_PAGE_GENERIC; + RawInput.usUsage = HID_USAGE_GENERIC_MOUSE; + RawInput.dwFlags = 0; + RawInput.hwndTarget = GetMainWindow()->hWnd; + + RegisterRawInputDevices(&RawInput, 1, sizeof(RAWINPUTDEVICE)); + // Restore original tick function now that the initial setup is done. PatchVTable(Self, 32, OriginalUUnrealEdEngineTick); } @@ -168,5 +211,6 @@ DLL_EXPORT void ModEdInit(const TCHAR* InPackage, const TCHAR* InCmdLine, FOutpu InitSWRCFix(); + // Hook UUnrealEdEngine::Tick for initialization OriginalUUnrealEdEngineTick = static_cast(PatchDllClassVTable(*(FString(appPackage()) + ".exe"), "UUnrealEdEngine", "UObject", 32, UnrealEdEngineTickOverride)); } diff --git a/RtxDrv/Classes/Rtx.uc b/RtxDrv/Classes/Rtx.uc new file mode 100644 index 00000000..a0053c5f --- /dev/null +++ b/RtxDrv/Classes/Rtx.uc @@ -0,0 +1,48 @@ +class Rtx extends Object native transient config(Rtx) hidecategories(Object, None); + +var(Components) config array > ComponentClasses; +var(Components) native editconst editinline array Components; // Must be native so the property is excluded from gc. The array is cleared in native code when the level changes. + +// Most of these properties actually belong in RtxRenderDevice but can't be added there because the class is too large for 16 bit property offsets + +var(General) config color AnchorTriangleColor; +var(General) config bool bDrawAnchorTriangle; +var(General) config bool bCaptureMode; +var(General) config bool bReplaceHardwareShaderMaterials; +var(General) config bool bDisableFrustumCulling; +var(General) config bool bDisableSkyZones; + +var(Lighting) config bool bEnableD3DLights; +var(Lighting) const editinline array Lights; + +// Keep destroyed lights around to reduce overhead of creating/destroying short lived lights +var const editconst array DestroyedLights; + +native final function RtxLight CreateLight(); +native final function DestroyLight(RtxLight Light); +native final function SetConfigVariable(string Key, string Value); + +native static final function Rtx GetInstance(); + +cpptext +{ + void Init(); + void Exit(); + void SetConfigVariable(const TCHAR* Key, const TCHAR* Value); + URtxLight* CreateLight(bool ForceDefaultConstructed = false); + void DestroyLight(URtxLight* Light); + void LevelChanged(class ULevel* Level); + void RenderLights(); +} + +defaultproperties +{ + AnchorTriangleColor=(R=255,G=255,B=0,A=255) + bDrawAnchorTriangle=True + bReplaceHardwareShaderMaterials=True + bDisableFrustumCulling=True + bDisableSkyZones=True + bEnableD3DLights=False + ComponentClasses(0)=class'RtxFlashlightComponent' + ComponentClasses(1)=class'RtxParticleComponent' +} diff --git a/RtxDrv/Classes/RtxComponent.uc b/RtxDrv/Classes/RtxComponent.uc new file mode 100644 index 00000000..68c67bef --- /dev/null +++ b/RtxDrv/Classes/RtxComponent.uc @@ -0,0 +1,16 @@ +class RtxComponent extends Actor native transient config(Rtx) hidecategories(Advanced, AI, Collision, CollisionAdvanced, Display, DisplayAdvanced, Events, Karma, LightColor, Lighting, marker, Movement, MovementAdvanced, Object, Sound); + +var Rtx Rtx; + +event OnSaveConfig(); + +function PostBeginPlay() +{ + Rtx = class'Rtx'.static.GetInstance(); +} + +defaultproperties +{ + bHidden=True + DrawType=DT_None +} diff --git a/RtxDrv/Classes/RtxFlashlight.uc b/RtxDrv/Classes/RtxFlashlight.uc new file mode 100644 index 00000000..b55f5e95 --- /dev/null +++ b/RtxDrv/Classes/RtxFlashlight.uc @@ -0,0 +1,109 @@ +class RtxFlashlight extends Object config(Rtx) hidecategories(Object); + +var bool bIsOn; + +struct FlashlightCone{ + var() config float Angle; + var() config float Radius; + var() config float Radiance; + var() config float Softness; + var() config color Color; +}; + +var() config Vector FirstPersonOffset; +var() config float FocusDistance; +var() config FlashlightCone OuterCone; +var() config FlashlightCone MainCone; +var() config FlashlightCone InnerCone; + +var RtxLight OuterLight; +var RtxLight MainLight; +var RtxLight InnerLight; + +function CalcLightPositionAndDirection(Pawn Pawn, out vector Position, out vector Direction) +{ + local vector ViewPosition; + local rotator ViewRotation; + local vector X,Y,Z; + + ViewPosition = Pawn.Location; + ViewPosition.Z += Pawn.EyeHeight; + + if(Pawn.IsLocallyControlled()) + { + ViewRotation = Pawn.Controller.Rotation; + Position = ViewPosition + QuatRotateVector(QuatFromRotator(ViewRotation), FirstPersonOffset); + } + else + { + ViewRotation = Pawn.GetBoneRotation('LightAttach'); + GetAxes(ViewRotation, X, Y, Z); + Position = Pawn.GetBoneLocation('LightAttach') + Y * 5; // FIXME: Don't hardcode this + } + + if(FocusDistance >= 1.0) + Direction = (ViewPosition + vector(ViewRotation) * FocusDistance) - Position; + else + Direction = vector(ViewRotation); +} + +function UpdateAndRenderLight(Pawn Pawn, RtxLight Light, vector Position, vector Direction, FlashlightCone Cone) +{ + Light.Position = Position; + Light.Shaping.Direction = Direction; + Light.Color = Cone.Color; + Light.Radiance = Cone.Radiance; + Light.Sphere.Radius = Cone.Radius; + Light.Shaping.ConeAngleDegrees = Cone.Angle; + Light.Shaping.ConeSoftness = Cone.Softness; + + Light.Update(); + Light.Render(); +} + +function Init() +{ + OuterLight = new class'RtxLight'; + OuterLight.Type = RTXLIGHT_Sphere; + OuterLight.bUseShaping = true; + + MainLight = new class'RtxLight'; + MainLight.Type = RTXLIGHT_Sphere; + MainLight.bUseShaping = true; + + InnerLight = new class'RtxLight'; + InnerLight.Type = RTXLIGHT_Sphere; + InnerLight.bUseShaping = true; +} + +function Exit() +{ + OuterLight = None; + MainLight = None; + InnerLight = None; +} + +function Update(Pawn Pawn, bool bOn) +{ + local vector LightPosition; + local vector LightDirection; + + bIsOn = bOn; + + if(bIsOn && Pawn != None) + { + CalcLightPositionAndDirection(Pawn, LightPosition, LightDirection); + UpdateAndRenderLight(Pawn, OuterLight, LightPosition, LightDirection, OuterCone); + UpdateAndRenderLight(Pawn, MainLight, LightPosition, LightDirection, MainCone); + UpdateAndRenderLight(Pawn, InnerLight, LightPosition, LightDirection, InnerCone); + } +} + +defaultproperties +{ + FirstPersonOffset=(X=0,Y=13,Z=4) + FocusDistance=256 + OuterCone=(Angle=30,Color=(R=176,G=249,B=255,A=255),Radiance=10000,Radius=2,Softness=0.02) + MainCone=(Angle=25,Color=(R=253,G=255,B=217,A=255),Radiance=15000,Radius=3,Softness=0.05) + InnerCone=(Angle=5,Color=(R=254,G=248,B=205,A=255),Radiance=20000,Radius=4,Softness=0) +} diff --git a/RtxDrv/Classes/RtxFlashlightComponent.uc b/RtxDrv/Classes/RtxFlashlightComponent.uc new file mode 100644 index 00000000..9793a77f --- /dev/null +++ b/RtxDrv/Classes/RtxFlashlightComponent.uc @@ -0,0 +1,100 @@ +class RtxFlashlightComponent extends RtxComponent; + +struct SquadMemberFlashlight{ + var Pawn Pawn; + var RtxFlashlight Flashlight; +}; + +var array SquadFlashlights; +var() editinline RtxFlashlight PlayerFlashlight; + +function OnSaveConfig() +{ + PlayerFlashlight.SaveConfig(); +} + +function SetupSquadLights(Squad Squad) +{ + local int i, j; + + for(i = 1; i < Squad.SquadMembers.Length; ++i) + { + for(j = 0; j < SquadFlashlights.Length; ++j) + { + if(SquadFlashlights[j].Pawn == Squad.SquadMembers[i].Pawn) + goto end; + + if(SquadFlashlights[j].Pawn == None) + { + SquadFlashlights.Remove(j, 1); + goto end; + } + } + + j = SquadFlashlights.Length; + SquadFlashlights.Length = j + 1; + SquadFlashlights[j].Pawn = Squad.SquadMembers[i].Pawn; + SquadFlashlights[j].Flashlight = new class'RtxFlashlight'; + SquadFlashlights[j].Flashlight.Init(); +end: + } +} + +function PostBeginPlay() +{ + local VisionModeSniper VisionMode; + + VisionMode = VisionModeSniper'FrameFx.VisionModes.VisionNight'; + VisionMode.VisionShader = HardwareShader'FrameFX.VisionShaders.VisionShaderNormal'; + VisionMode.TargetedOrganicShader = None; + VisionMode.TargetedMechanicalShader = None; + + Super.PostBeginPlay(); + + if(PlayerFlashlight == None) + { + PlayerFlashlight = new class'RtxFlashlight'; + PlayerFlashlight.Init(); + } +} + +function Destroyed() +{ + local int i; + + for(i = 0; i < SquadFlashlights.Length; ++i) + SquadFlashlights[i].Flashlight.Exit(); + + SquadFlashlights.Length = 0; + PlayerFlashlight.Exit(); + Super.Destroyed(); +} + +function Tick(float DeltaTime) +{ + local PlayerController PC; + local Pawn Pawn; + local int i; + + PC = Level.GetLocalPlayerController(); + + if(PC == None || PC.Pawn == None) + return; + + Pawn = PC.Pawn; + + if(Pawn.Squad != None) + SetupSquadLights(PC.Pawn.Squad); + + PlayerFlashlight.Update(Pawn, Pawn.Flashlight.bIsOn); + + // Disable light spawned in Pawn::SetFlashlight + if(PC.PlayerSpotlight != None) + { + PC.PlayerSpotlight.LightType = LT_None; + PC.PlayerSpotlight.bLightPriorityOverride = false; + } + + for(i = 0; i < SquadFlashlights.Length; ++i) + SquadFlashlights[i].Flashlight.Update(SquadFlashlights[i].Pawn, PC.Pawn.Flashlight.bIsOn); +} diff --git a/RtxDrv/Classes/RtxLight.uc b/RtxDrv/Classes/RtxLight.uc new file mode 100644 index 00000000..e7a9b681 --- /dev/null +++ b/RtxDrv/Classes/RtxLight.uc @@ -0,0 +1,79 @@ +class RtxLight extends Object native transient hidecategories(Object, None); + +var(Common) enum ERtxLightType{ + RTXLIGHT_Sphere, + RTXLIGHT_Rect, + RTXLIGHT_Disk, + RTXLIGHT_Cylinder, + RTXLIGHT_Distant +} Type; + +var bool bShouldBeDestroyed; +var(Common) bool bEnabled; +var(Common) bool bUseShaping; +var(Common) vector Position; +var(Common) color Color; +var(Common) float Radiance; + +// Used by sphere, rect and disc if bUseShaping +var(Common) struct RtxLightShaping{ + var() vector Direction; + var() float ConeAngleDegrees; + var() float ConeSoftness; + var() float FocusExponent; +} Shaping; + +var(SphereLight) struct RtxSphereLight{ + var() float Radius; +} Sphere; + +var(RectLight) struct RtxRectLight{ + var() vector XAxis; + var() vector YAxis; + var() float XSize; + var() float YSize; + var() vector Direction; +} Rect; + +var(DiskLight) struct RtxDiskLight{ + var() vector XAxis; + var() vector YAxis; + var() float XRadius; + var() float YRadius; + var() vector Direction; +} Disk; + +var(CylinderLight) struct RtxCylinderLight{ + var() vector Axis; + var() float Length; + var() float Radius; +} Cylinder; + +var(DistantLight) struct RtxDistantLight{ + var() vector Direction; + var() float AngularDiameterDegrees; +} Distant; + +var const editconst noexport int Handle; + +native final function Update(); // Must be called whenever a property value has changed +native final function Render(); // Only needs to be called manually for lights that were not created with Rtx::CreateLight + +cpptext +{ + remixapi_LightHandle_T* Handle; + + virtual void Destroy(); + virtual void PostEditChange(){ Super::PostEditChange(); Update(); } + void Update(); + void Render(); + void DestroyHandle(); +} + +defaultproperties +{ + bEnabled=True + Color=(R=255,G=255,B=255,A=255) + Radiance=10000 + Sphere=(Radius=2.5) +} diff --git a/RtxDrv/Classes/RtxParticleComponent.uc b/RtxDrv/Classes/RtxParticleComponent.uc new file mode 100644 index 00000000..2a86875f --- /dev/null +++ b/RtxDrv/Classes/RtxParticleComponent.uc @@ -0,0 +1,21 @@ +class RtxParticleComponent extends RtxComponent; + +var() config bool bDisableFlipbookAnimations; + +function PostBeginPlay() +{ + if(bDisableFlipbookAnimations) + { + ConsoleCommand("SET SpriteEmitter TextureUSubdivisions 0"); + ConsoleCommand("SET SpriteEmitter TextureVSubdivisions 0"); + } +} + +function Tick(float DeltaTime) +{ +} + +defaultproperties +{ + bDisableFlipbookAnimations=True +} diff --git a/RtxDrv/Inc/RtxDrvClasses.h b/RtxDrv/Inc/RtxDrvClasses.h new file mode 100644 index 00000000..df2a1485 --- /dev/null +++ b/RtxDrv/Inc/RtxDrvClasses.h @@ -0,0 +1,163 @@ +/*=========================================================================== + C++ class definitions exported from UnrealScript. + This is automatically generated by the tools. + DO NOT modify this manually! Edit the corresponding .uc files instead! +===========================================================================*/ + +#ifndef RTXDRV_NATIVE_DEFS +#define RTXDRV_NATIVE_DEFS + +#if SUPPORTS_PRAGMA_PACK +#pragma pack (push,4) +#endif + +#ifndef RTXDRV_API +#define RTXDRV_API DLL_IMPORT +#endif + + + +class RTXDRV_API ARtxComponent : public AActor +{ +public: + class URtx* Rtx; + void OnSaveConfig() + { + DECLARE_NAME(OnSaveConfig); + ProcessEvent(NOnSaveConfig, NULL); + } + DECLARE_CLASS(ARtxComponent,AActor,0|CLASS_Transient,RtxDrv) + NO_DEFAULT_CONSTRUCTOR(ARtxComponent) +}; + + +class RTXDRV_API URtx : public UObject +{ +public: + TArrayNoInit ComponentClasses; + TArrayNoInit Components; + FColor AnchorTriangleColor; + BITFIELD bDrawAnchorTriangle:1 GCC_PACK(4); + BITFIELD bCaptureMode:1; + BITFIELD bReplaceHardwareShaderMaterials:1; + BITFIELD bDisableFrustumCulling:1; + BITFIELD bDisableSkyZones:1; + BITFIELD bEnableD3DLights:1; + TArrayNoInit Lights GCC_PACK(4); + TArrayNoInit DestroyedLights; + void execCreateLight(FFrame& Stack, void* Result); + void execDestroyLight(FFrame& Stack, void* Result); + void execSetConfigVariable(FFrame& Stack, void* Result); + void execGetInstance(FFrame& Stack, void* Result); + DECLARE_CLASS(URtx,UObject,0|CLASS_Transient|CLASS_Config,RtxDrv) + void Init(); + void Exit(); + void SetConfigVariable(const TCHAR* Key, const TCHAR* Value); + URtxLight* CreateLight(bool ForceDefaultConstructed = false); + void DestroyLight(URtxLight* Light); + void LevelChanged(class ULevel* Level); + void RenderLights(); + DECLARE_NATIVES(URtx) +}; + +enum ERtxLightType +{ + RTXLIGHT_Sphere, + RTXLIGHT_Rect, + RTXLIGHT_Disk, + RTXLIGHT_Cylinder, + RTXLIGHT_Distant, + RTXLIGHT_MAX +}; +struct RTXDRV_API FRtxLightShaping +{ + FVector Direction; + FLOAT ConeAngleDegrees; + FLOAT ConeSoftness; + FLOAT FocusExponent; +}; + +struct RTXDRV_API FRtxSphereLight +{ + FLOAT Radius; +}; + +struct RTXDRV_API FRtxRectLight +{ + FVector XAxis; + FVector YAxis; + FLOAT XSize; + FLOAT YSize; + FVector Direction; +}; + +struct RTXDRV_API FRtxDiskLight +{ + FVector XAxis; + FVector YAxis; + FLOAT XRadius; + FLOAT YRadius; + FVector Direction; +}; + +struct RTXDRV_API FRtxCylinderLight +{ + FVector Axis; + FLOAT Length; + FLOAT Radius; +}; + +struct RTXDRV_API FRtxDistantLight +{ + FVector Direction; + FLOAT AngularDiameterDegrees; +}; + + +class RTXDRV_API URtxLight : public UObject +{ +public: + BYTE Type; + BITFIELD bShouldBeDestroyed:1 GCC_PACK(4); + BITFIELD bEnabled:1; + BITFIELD bUseShaping:1; + FVector Position GCC_PACK(4); + FColor Color; + FLOAT Radiance; + FRtxLightShaping Shaping; + FRtxSphereLight Sphere; + FRtxRectLight Rect; + FRtxDiskLight Disk; + FRtxCylinderLight Cylinder; + FRtxDistantLight Distant; + void execUpdate(FFrame& Stack, void* Result); + void execRender(FFrame& Stack, void* Result); + DECLARE_CLASS(URtxLight,UObject,0|CLASS_Transient,RtxDrv) + remixapi_LightHandle_T* Handle; + + virtual void Destroy(); + virtual void PostEditChange(){ Super::PostEditChange(); Update(); } + void Update(); + void Render(); + void DestroyHandle(); + DECLARE_NATIVES(URtxLight) +}; + + + +#if SUPPORTS_PRAGMA_PACK +#pragma pack (pop) +#endif + +#if __STATIC_LINK + +#define AUTO_INITIALIZE_REGISTRANTS_RTXDRV \ + ARtxComponent::StaticClass(); \ + USolidColorMaterial::StaticClass(); \ + URtx::StaticClass(); \ + URtxLight::StaticClass(); \ + URtxRenderDevice::StaticClass(); \ + +#endif // __STATIC_LINK + +#endif // CORE_NATIVE_DEFS diff --git a/RtxDrv/RtxDrv.vcproj b/RtxDrv/RtxDrv.vcproj new file mode 100644 index 00000000..da9041ba --- /dev/null +++ b/RtxDrv/RtxDrv.vcproj @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RtxDrv/Src/Rtx.cpp b/RtxDrv/Src/Rtx.cpp new file mode 100644 index 00000000..cbaacea1 --- /dev/null +++ b/RtxDrv/Src/Rtx.cpp @@ -0,0 +1,289 @@ +#include "RtxDrvPrivate.h" +#include "RtxRenderDevice.h" + +static bool GRemixApiInitialized = false; +static remixapi_Interface GRemixApi = {0}; +static HMODULE GRemixDllHandle = NULL; + +void URtx::Init() +{ + if(!GRemixApiInitialized) + { + debugf("Initializing remix bridge API"); + + wchar_t DllPathBuffer[MAX_PATH]; + FString DllPath = FStringTemp(appBaseDir()) * "d3d9.dll"; + MultiByteToWideChar(CP_ACP, 0, *DllPath, -1, DllPathBuffer, ARRAY_COUNT(DllPathBuffer)); + + remixapi_ErrorCode Error = remixapi_lib_loadRemixDllAndInitialize(DllPathBuffer, &GRemixApi, &GRemixDllHandle) ; + GRemixApiInitialized = Error == REMIXAPI_ERROR_CODE_SUCCESS; + + if(!GRemixApiInitialized) + debugf(NAME_Error, "Failed to initialize remix API: %i", Error); + } + + Lights.SetNoShrink(true); + DestroyedLights.SetNoShrink(true); +} + +void URtx::Exit() +{ + if(GRemixApiInitialized) + { + remixapi_lib_shutdownAndUnloadRemixDll(&GRemixApi, GRemixDllHandle); + GRemixApiInitialized = false; + GRemixDllHandle = NULL; + } +} + +void URtx::SetConfigVariable(const TCHAR* Key, const TCHAR* Value) +{ + if(GRemixApiInitialized) + GRemixApi.SetConfigVariable(Key, Value); +} + +URtxLight* URtx::CreateLight(bool ForceDefaultConstructed) +{ + URtxLight* Light; + + if(!ForceDefaultConstructed && DestroyedLights.Num() > 0) + Light = DestroyedLights.Pop(); + else + Light = new(this) URtxLight; + + Light->bShouldBeDestroyed = 0; + Light->bEnabled = 1; + Lights.AddItem(Light); + return Light; +} + +void URtx::DestroyLight(URtxLight* Light) +{ + if(Light) + Light->bShouldBeDestroyed = 1; +} + +void URtx::LevelChanged(ULevel* Level) +{ + debugf("Level changed - Initializing RTX components"); + + DestroyedLights += Lights; + Lights.Empty(); + Components.Empty(); // Component actors aren't valid anymore now that the level has changed so just clear the old ones + + for(INT i = 0; i < ComponentClasses.Num(); ++i) + { + UClass* ComponentClass = ComponentClasses[i]; + if(ComponentClass) + { + debugf("Spawning RTX component: %s", ComponentClass->GetName()); + + ARtxComponent* Actor = static_cast(Level->SpawnActor(ComponentClass)); + + if(Actor) + Components.AddItem(Actor); + else + debugf("Failed to spawn RTX component of class %s", ComponentClass->GetName()); + } + } +} + +void URtx::RenderLights() +{ + for(INT i = 0; i < Lights.Num(); ++i) + { + URtxLight* Light = Lights[i]; + + if(Light && Light->bShouldBeDestroyed) + { + Light->DestroyHandle(); + URtxLight* Last = Lights.Pop(); + DestroyedLights.AddItem(Light); + + if(Light == Last) + break; + + Lights[i] = Last; + Light = Last; + } + + if(!Light) // NULL entry can happen if a light was added via the property window UI. In that case just create it + { + Light = CreateLight(true); + Lights[i] = Light; + } + + Light->Render(); + } +} + +void URtx::execCreateLight(FFrame& Stack, void* Result) +{ + P_FINISH; + *static_cast(Result) = CreateLight(); +} + +void URtx::execDestroyLight(FFrame& Stack, void* Result) +{ + P_GET_OBJECT(URtxLight, Light); + P_FINISH; + DestroyLight(Light); +} + +void URtx::execGetInstance(FFrame& Stack, void* Result) +{ + P_FINISH; + + URtxRenderDevice* RenDev = Cast(GEngine->GRenDev); + + if(RenDev) + *static_cast(Result) = RenDev->GetRtxInterface(); +} + +void URtx::execSetConfigVariable(FFrame& Stack, void* Result) +{ + P_GET_STR(Key); + P_GET_STR(Value); + P_FINISH; + SetConfigVariable(*Key, *Value); +} + +void URtxLight::execUpdate(FFrame& Stack, void* Result) +{ + P_FINISH; + Update(); +} + +void URtxLight::execRender(FFrame& Stack, void* Result) +{ + P_FINISH; + Render(); +} + +void URtxLight::Destroy() +{ + DestroyHandle(); + Super::Destroy(); +} + +static void InitFloat3D(remixapi_Float3D& Dest, const FVector& Src) +{ + Dest.x = Src.X; + Dest.y = Src.Y; + Dest.z = Src.Z; +} + +static void InitShaping(remixapi_LightInfoLightShaping& Dest, const FRtxLightShaping& Src) +{ + InitFloat3D(Dest.direction, Src.Direction.GetNormalized()); + Dest.coneAngleDegrees = Src.ConeAngleDegrees; + Dest.coneSoftness = Src.ConeSoftness; + Dest.focusExponent = Src.FocusExponent; +} + +void URtxLight::Update() +{ + if(!GRemixApiInitialized) + return; + + DestroyHandle(); + + remixapi_LightInfo LightInfo = {REMIXAPI_STRUCT_TYPE_LIGHT_INFO}; + LightInfo.hash = reinterpret_cast(this); + InitFloat3D(LightInfo.radiance, Color.Plane() * Radiance); + + switch(Type) + { + case RTXLIGHT_Sphere: + { + static remixapi_LightInfoSphereEXT SphereInfo = {REMIXAPI_STRUCT_TYPE_LIGHT_INFO_SPHERE_EXT}; + InitFloat3D(SphereInfo.position, Position); + SphereInfo.radius = Sphere.Radius; + SphereInfo.shaping_hasvalue = bUseShaping; + + if(SphereInfo.shaping_hasvalue) + InitShaping(SphereInfo.shaping_value, Shaping); + + LightInfo.pNext = &SphereInfo; + break; + } + case RTXLIGHT_Rect: + { + static remixapi_LightInfoRectEXT RectInfo = {REMIXAPI_STRUCT_TYPE_LIGHT_INFO_RECT_EXT}; + InitFloat3D(RectInfo.position, Position); + InitFloat3D(RectInfo.xAxis, Rect.XAxis.GetNormalized()); + RectInfo.xSize = Rect.XSize; + InitFloat3D(RectInfo.yAxis, Rect.YAxis.GetNormalized()); + RectInfo.ySize = Rect.YSize; + InitFloat3D(RectInfo.direction, Rect.Direction.GetNormalized()); + RectInfo.shaping_hasvalue = bUseShaping; + + if(RectInfo.shaping_hasvalue) + InitShaping(RectInfo.shaping_value, Shaping); + + LightInfo.pNext = &RectInfo; + break; + } + case RTXLIGHT_Disk: + { + static remixapi_LightInfoDiskEXT DiskInfo = {REMIXAPI_STRUCT_TYPE_LIGHT_INFO_DISK_EXT}; + InitFloat3D(DiskInfo.position, Position); + InitFloat3D(DiskInfo.xAxis, Disk.XAxis.GetNormalized()); + DiskInfo.xRadius = Disk.XRadius; + InitFloat3D(DiskInfo.yAxis, Disk.YAxis.GetNormalized()); + DiskInfo.yRadius = Disk.YRadius; + InitFloat3D(DiskInfo.direction, Disk.Direction.GetNormalized()); + DiskInfo.shaping_hasvalue = bUseShaping; + + if(DiskInfo.shaping_hasvalue) + InitShaping(DiskInfo.shaping_value, Shaping); + + LightInfo.pNext = &DiskInfo; + break; + } + case RTXLIGHT_Cylinder: + { + static remixapi_LightInfoCylinderEXT CylinderInfo = {REMIXAPI_STRUCT_TYPE_LIGHT_INFO_CYLINDER_EXT}; + InitFloat3D(CylinderInfo.position, Position); + InitFloat3D(CylinderInfo.axis, Cylinder.Axis.GetNormalized()); + CylinderInfo.radius = Cylinder.Radius; + CylinderInfo.axisLength = Cylinder.Length; + LightInfo.pNext = &CylinderInfo; + break; + } + case RTXLIGHT_Distant: + { + static remixapi_LightInfoDistantEXT DistantInfo = {REMIXAPI_STRUCT_TYPE_LIGHT_INFO_DISTANT_EXT}; + InitFloat3D(DistantInfo.direction, Distant.Direction.GetNormalized()); + DistantInfo.angularDiameterDegrees = Distant.AngularDiameterDegrees; + LightInfo.pNext = &DistantInfo; + break; + } + } + + GRemixApi.CreateLight(&LightInfo, &Handle); +} + +void URtxLight::Render() +{ + if(GRemixApiInitialized && Handle) + { + if(bEnabled) + { + if(!Handle) + Update(); + + if(Handle) + GRemixApi.DrawLightInstance(Handle); + } + } +} + +void URtxLight::DestroyHandle() +{ + if(GRemixApiInitialized && Handle) + { + GRemixApi.DestroyLight(Handle); + Handle = NULL; + } +} diff --git a/RtxDrv/Src/RtxDrvClasses.cpp b/RtxDrv/Src/RtxDrvClasses.cpp new file mode 100644 index 00000000..2eb47527 --- /dev/null +++ b/RtxDrv/Src/RtxDrvClasses.cpp @@ -0,0 +1,31 @@ +/*=========================================================================== + C++ class definitions exported from UnrealScript. + This is automatically generated by the tools. + DO NOT modify this manually! Edit the corresponding .uc files instead! +===========================================================================*/ + +#include "RtxDrvPrivate.h" + +IMPLEMENT_PACKAGE(RtxDrv) + + + +IMPLEMENT_CLASS(ARtxComponent); + +IMPLEMENT_CLASS(URtx); +FNativeEntry URtx::StaticNativeMap[] = { + MAP_NATIVE(CreateLight,0) + MAP_NATIVE(DestroyLight,0) + MAP_NATIVE(SetConfigVariable,0) + MAP_NATIVE(GetInstance,0) + {NULL,NULL} +}; +LINK_NATIVES(URtx); + +IMPLEMENT_CLASS(URtxLight); +FNativeEntry URtxLight::StaticNativeMap[] = { + MAP_NATIVE(Update,0) + MAP_NATIVE(Render,0) + {NULL,NULL} +}; +LINK_NATIVES(URtxLight); diff --git a/RtxDrv/Src/RtxDrvPrivate.h b/RtxDrv/Src/RtxDrvPrivate.h new file mode 100644 index 00000000..233d3214 --- /dev/null +++ b/RtxDrv/Src/RtxDrvPrivate.h @@ -0,0 +1,3 @@ +#include "Engine.h" +#include "remix_c.h" +#include "../Inc/RtxDrvClasses.h" diff --git a/RtxDrv/Src/RtxRenderDevice.cpp b/RtxDrv/Src/RtxRenderDevice.cpp new file mode 100644 index 00000000..62e60ab0 --- /dev/null +++ b/RtxDrv/Src/RtxRenderDevice.cpp @@ -0,0 +1,521 @@ +#include "RtxRenderDevice.h" +#include "RtxDrvPrivate.h" +#include "Window.h" +#include "Editor.h" +#include "CodeInjection.h" + +IMPLEMENT_CLASS(URtxRenderDevice) + +static URtxRenderDevice* GRtxRenDev = NULL; + +static ULevel* GetLevel() +{ + if(GEngine->IsA()) + return static_cast(GEngine)->GLevel; + + if(GEngine->IsA()) + return static_cast(GEngine)->Level; + + return NULL; +} + +typedef FConvexVolume&(__fastcall*FPlayerSceneNodeGetViewFrustum)(FLevelSceneNode* Self, DWORD Edx, FConvexVolume& Result); + +static FPlayerSceneNodeGetViewFrustum OriginalFPlayerSceneNodeGetViewFrustum = NULL; + +static FConvexVolume& __fastcall FPlayerSceneNodeGetViewFrustumOverride(FPlayerSceneNode* Self, DWORD Edx, FConvexVolume& Result) +{ + OriginalFPlayerSceneNodeGetViewFrustum(Self, Edx, Result); + + if(GRtxRenDev && GRtxRenDev->GetRtxInterface()->bDisableFrustumCulling) + { + for(INT i = 0; i < 5; i++) + Result.BoundingPlanes[i].W += 10000.0f; + } + + return Result; +} + +// static INT GetMaterialFlags(UMaterial* Material) +// { +// return reinterpret_cast(Material)[24] >> 2; +// } + +// static INT SetMaterialFlags(UMaterial* Material, INT Flags) +// { +// reinterpret_cast(Material)[24] = (Flags << 2) | (reinterpret_cast(Material)[24] & 0x3); +// } + +void ClearMaterialFlags() +{ + foreachobj(UMaterial, Material) + reinterpret_cast(*Material)[24] = (reinterpret_cast(*Material)[24] & 0x3); +} + +void URtxRenderDevice::Serialize(FArchive& Ar) +{ + Super::Serialize(Ar); + if(Ar.IsGarbageCollecting()) + Ar << Rtx; +} + +UBOOL URtxRenderDevice::Exec(const TCHAR* Cmd, FOutputDevice& Ar) +{ + if(ParseCommand(&Cmd, "RTX")) + { + if(ParseCommand(&Cmd, "TOGGLEANCHOR")) + { + Rtx->bDrawAnchorTriangle = !Rtx->bDrawAnchorTriangle; + return 1; + } + else if(ParseCommand(&Cmd, "PREFERENCES")) + { + GEngine->Client->GetLastCurrent()->EndFullscreen(); + WObjectProperties* P = new WObjectProperties("EditObj", 0, "", NULL, 1); + P->OpenWindow(GLogWindow->hWnd); + UObject* Obj = Rtx; + P->Root.SetObjects(&Obj, 1); + P->Show(1); + return 1; + } + else if(ParseCommand(&Cmd, "SET")) + { + FString Key = ParseToken(Cmd, 0); + FString Value = ParseToken(Cmd, 0); + + if(Key.Len() == 0) + Ar.Log("Missing variable name"); + else if(Value.Len() == 0) + Ar.Log("Missing value"); + else + Rtx->SetConfigVariable(*Key, *Value); + + return 1; + } + else if(ParseCommand(&Cmd, "CREATELIGHT")) + { + APlayerController* PC = GEngine->Client->Viewports[0]->Actor; + URtxLight* Light = Rtx->CreateLight(true); + + if(PC->Pawn) + Light->Position = PC->Pawn->Location; + else + Light->Position = PC->Location; + + if(!ParseCommand(&Cmd, "!")) + { + GEngine->Client->GetLastCurrent()->EndFullscreen(); + WObjectProperties* P = new WObjectProperties("EditObj", 0, "", NULL, 1); + P->OpenWindow(GLogWindow->hWnd); + UObject* Obj = Light; + P->Root.SetObjects(&Obj, 1); + P->Show(1); + } + + return 1; + } + else if(ParseCommand(&Cmd, "SAVECONFIG")) + { + Rtx->SaveConfig(); + + for(INT i = 0; i < Rtx->Components.Num(); ++i) + { + if(Rtx->Components[i]) + { + Rtx->Components[i]->SaveConfig(); + Rtx->Components[i]->OnSaveConfig(); + } + } + + return 1; + } + } + + return Super::Exec(Cmd, Ar); +} + +void URtxRenderDevice::StaticConstructor() +{ + UseStencil = 0; + CanDoDistortionEffects = 0; +} + +UBOOL URtxRenderDevice::Init() +{ + GRtxRenDev = this; + + // Init SWRCFix if it exists. Hacky but RenderDevice is always loaded at startup... + HMODULE ModDLL = LoadLibraryA("Mod.dll"); + + if(ModDLL) + { + void(CDECL*InitSWRCFix)(void) = reinterpret_cast(GetProcAddress(ModDLL, "InitSWRCFix")); + + if(InitSWRCFix) + InitSWRCFix(); + } + + static bool bCodeInjected = false; + if(!bCodeInjected) + { + OriginalFPlayerSceneNodeGetViewFrustum = reinterpret_cast( + PatchDllClassVTable("Engine.dll", "FPlayerSceneNode", NULL, 10, FPlayerSceneNodeGetViewFrustumOverride)); + bCodeInjected = true; + } + + ClearMaterialFlags(); + UClient* Client = GEngine->Client; + Client->FrameFXDisabled = 1; + Client->BloomQuality = 0; + Client->BlurEnabled = 0; + Client->BumpmappingQuality = 0; + GetDefault()->bVisor = 0; + GetDefault()->VisorModeDefault = 1; + + Rtx = new(this) URtx; + + return Super::Init(); +} + +void URtxRenderDevice::Exit(UViewport* Viewport) +{ + Rtx->Exit(); + delete Rtx; + Rtx = NULL; + Super::Exit(Viewport); + GRtxRenDev = NULL; +} + +UBOOL URtxRenderDevice::SetRes(UViewport* Viewport, INT NewX, INT NewY, UBOOL Fullscreen, INT ColorBytes, UBOOL bSaveSize) +{ + UBOOL Result = Super::SetRes(Viewport, NewX, NewY, Fullscreen, ColorBytes, bSaveSize); + + if(Result) + Rtx->Init(); + + return Result; +} + +void URtxRenderDevice::Flush(UViewport* Viewport) +{ + ClearMaterialFlags(); + Super::Flush(Viewport); +} + +/* + * Check for a level change and notify the RTX interface so it can recreate the components. + * This is the most reliable way to do it that I've been able to find. + * UGameEngine::GLevel does not always change when restarting the level so the additional check for a non-empty travel URL is also needed. + */ +void URtxRenderDevice::CheckForLevelChange(UViewport* Viewport) +{ + static bool bPendingLevel = false; + static ULevel* Level = NULL; + + if(Viewport && Viewport->TravelURL.Len() > 0) + { + bPendingLevel = true; + } + else if(bPendingLevel || Level != GetLevel()) + { + bPendingLevel = false; + Level = GetLevel(); + + AnchorTriangleStream.Update(appStrihash(Level->GetPathName()) / (FLOAT)MAXDWORD); + + if(Rtx->bDisableSkyZones) + { + foreach(AllActors, AZoneInfo, Info, Level) + { + Info->SkyZone = NULL; + Info->bUseSkyDome = 0; + } + } + + Rtx->LevelChanged(Level); + } +} + +FRenderInterface* URtxRenderDevice::Lock(UViewport* Viewport, BYTE* HitData, INT* HitSize) +{ + CheckForLevelChange(Viewport); + + // Make sure relevant graphics options are set to the correct values + UClient* Client = GEngine->Client; + appMemzero(Client->TextureLODSet, sizeof(Client->TextureLODSet)); + Client->Shadows = 0; + + if(Rtx->bCaptureMode) + Viewport->Precaching = 1; + + DepthCleared = 0; + + D3D = Super::Lock(Viewport, HitData, HitSize); + + if(!D3D) + return NULL; + + LockedViewport = Viewport; + + if(Viewport->Actor) + { + Viewport->Actor->bVisor = 0; + Viewport->Actor->VisorModeDefault = 1; + } + + return this; +} + +struct FProjectileLight{ + URtxLight* Light; + UBOOL bUsed; +}; + +void URtxRenderDevice::Unlock(FRenderInterface* RI) +{ + typedef TMap FProjLightMap; + static FProjLightMap ProjLights; + + foreach(AllActors, AProjectile, Proj, static_cast(GEngine)->GLevel) + { + DECLARE_NAME(GrenadeProj); + if(Proj->IsA(NGrenadeProj)) + continue; + + FProjectileLight* ProjLight = ProjLights.Find(*Proj); + + if(!ProjLight) + ProjLight = &ProjLights[*Proj]; + + if(!ProjLight->Light) + ProjLight->Light = Rtx->CreateLight(); + + URtxLight* Light = ProjLight->Light; + Light->Type = RTXLIGHT_Sphere; + Light->Position = Proj->Location; + Light->Radiance = 10000.0f; + Light->Color = FGetHSV(Proj->LightHue, Proj->LightSaturation, Proj->LightBrightness); + Light->Sphere.Radius = 2.5f; + Light->Update(); + + ProjLight->bUsed = 1; + } + + for(FProjLightMap::TIterator It(ProjLights); It; ++It) + { + if(!It->bUsed) + { + Rtx->DestroyLight(It.Value().Light); + ProjLights.Remove(It.Key()); + } + else + { + It->bUsed = 0; + } + } + + Rtx->RenderLights(); + + if(Rtx->bCaptureMode) + LockedViewport->Precaching = 0; + + LockedViewport = NULL; + + Super::Unlock(static_cast(RI)->D3D); +} + +void URtxRenderDevice::Present(UViewport* Viewport) +{ + Super::Present(Viewport); +} + +/* + * Draw anchor triangle at world center to parent assets to in remix + */ + +class USolidColorMaterial : public UConstantMaterial{ + DECLARE_CLASS(USolidColorMaterial,UConstantMaterial,0,RtxDrv) +public: + FColor Color; + virtual FColor GetColor(FLOAT TimeSeconds){ return Color; } +}; +IMPLEMENT_CLASS(USolidColorMaterial) + +void URtxRenderDevice::DrawAnchorTriangle() +{ + if(!Rtx->bDrawAnchorTriangle || !LockedViewport || !LockedViewport->Actor) + return; + + AActor* ViewActor = LockedViewport->Actor; + FVector CameraLocation = ViewActor->Location; + FRotator CameraRotation = ViewActor->Rotation; + LockedViewport->Actor->PlayerCalcView(ViewActor, CameraLocation, CameraRotation); + + // Initialize the view matrix. + FMatrix WorldToCamera = FTranslationMatrix(-CameraLocation); + + if(!LockedViewport->IsOrtho()) + { + WorldToCamera = WorldToCamera * FInverseRotationMatrix(CameraRotation); + WorldToCamera = WorldToCamera * FMatrix( + FPlane(0, 0, 1, 0), + FPlane(LockedViewport->ScaleX, 0, 0, 0), + FPlane(0, LockedViewport->ScaleY, 0, 0), + FPlane(0, 0, 0, 1)); + } + else if(LockedViewport->Actor->RendMap == REN_OrthXY) + { + WorldToCamera = WorldToCamera * FMatrix( + FPlane(LockedViewport->ScaleX, 0, 0, 0), + FPlane(0, -LockedViewport->ScaleY, 0, 0), + FPlane(0, 0, -1, 0), + FPlane(0, 0, -CameraLocation.Z, 1)); + } + else if(LockedViewport->Actor->RendMap == REN_OrthXZ) + { + WorldToCamera = WorldToCamera * FMatrix( + FPlane(LockedViewport->ScaleX, 0, 0, 0), + FPlane(0, 0, -1, 0), + FPlane(0, LockedViewport->ScaleY, 0, 0), + FPlane(0, 0, -CameraLocation.Y, 1)); + } + else if(LockedViewport->Actor->RendMap == REN_OrthYZ) + { + WorldToCamera = WorldToCamera * FMatrix( + FPlane(0, 0, 1, 0), + FPlane(LockedViewport->ScaleX, 0, 0, 0), + FPlane(0, LockedViewport->ScaleY, 0, 0), + FPlane(0, 0, CameraLocation.X, 1)); + } + + // Initialize the projection matrix. + FMatrix CameraToScreen; + if(LockedViewport->IsOrtho()) + { + const FLOAT Zoom = LockedViewport->Actor->OrthoZoom / (LockedViewport->SizeX * 15.0f); + CameraToScreen = FOrthoMatrix(Zoom * LockedViewport->SizeX / 2,Zoom * LockedViewport->SizeY / 2, 0.5f / HALF_WORLD_MAX, HALF_WORLD_MAX); + } + else + { + const FLOAT FOV = LockedViewport->Actor->FovAngle * PI / 360.0f; + CameraToScreen = FPerspectiveMatrix(FOV, FOV, 1.0f, (FLOAT)LockedViewport->SizeX / LockedViewport->SizeY, NEAR_CLIPPING_PLANE, FAR_CLIPPING_PLANE); + } + + // Material + DECLARE_STATIC_UOBJECT(USolidColorMaterial, Material, {}); + DECLARE_STATIC_UOBJECT(UFinalBlend, FinalBlend, + { + FinalBlend->Material = Material; + FinalBlend->FrameBufferBlending = FB_Overwrite; + FinalBlend->ZWrite = 1; + }); + + if(Material->Color != Rtx->AnchorTriangleColor) + { + Material->Color = Rtx->AnchorTriangleColor; + FinalBlend->ResetCachedStates(); + } + + PushState(); + SetTransform(TT_LocalToWorld, FMatrix::Identity); + SetTransform(TT_WorldToCamera, WorldToCamera); + SetTransform(TT_CameraToScreen, CameraToScreen); + SetMaterial(FinalBlend); + SetIndexBuffer(NULL, 0); + FVertexStream* Stream = &AnchorTriangleStream; + SetVertexStreams(VS_FixedFunction, &Stream, 1); + DrawPrimitive(PT_TriangleList, 0, 1); + PopState(); +} + +/* + * FRenderInterface + */ + +UBOOL URtxRenderDevice::SetRenderTarget(FRenderTarget* RenderTarget, bool bOwnDepthBuffer) +{ + return D3D->SetRenderTarget(RenderTarget, bOwnDepthBuffer); +} + +void URtxRenderDevice::Clear(UBOOL UseColor, FColor Color, UBOOL UseDepth, FLOAT Depth, UBOOL UseStencil, DWORD Stencil) +{ + D3D->Clear(UseColor, Color, UseDepth, Depth, UseStencil, Stencil); + + if(UseDepth && !DepthCleared) + { + DepthCleared = 1; + DrawAnchorTriangle(); + } +} + +void URtxRenderDevice::EnableLighting(UBOOL UseDynamic, UBOOL UseStatic, UBOOL Modulate2X, FBaseTexture* Lightmap, UBOOL LightingOnly, const FSphere& LitSphere, int IntValue) +{ + if(UseStatic && Lightmap) + IgnoreDrawCall |= IgnoreDrawCall_Lightmap; + else + IgnoreDrawCall &= ~IgnoreDrawCall_Lightmap; + + UseDynamic = 0; + Lightmap = NULL; + Modulate2X = 0; + D3D->EnableLighting(UseDynamic, UseStatic, Modulate2X, Lightmap, LightingOnly, LitSphere, IntValue); +} + +void URtxRenderDevice::SetLight(INT LightIndex, FDynamicLight* Light, FLOAT Scale) +{ + if(Rtx->bEnableD3DLights) + D3D->SetLight(LightIndex, Light, Scale); +} + +void URtxRenderDevice::SetTransform(ETransformType Type, const FMatrix& Matrix) +{ + D3D->SetTransform(Type, Matrix); +} + +void URtxRenderDevice::SetMaterial(UMaterial* Material, FString* ErrorString, UMaterial** ErrorMaterial, INT* NumPasses) +{ + if(Material) + { + if(Material->IsA()) + IgnoreDrawCall |= IgnoreDrawCall_Material; + else + IgnoreDrawCall &= ~IgnoreDrawCall_Material; + + UMaterial** ActualMaterial = &Material; + + while(*ActualMaterial && (*ActualMaterial)->IsA()) + ActualMaterial = &((UModifier*)*ActualMaterial)->Material; + + if(*ActualMaterial) + { + if(Rtx->bReplaceHardwareShaderMaterials && (*ActualMaterial)->IsA()) + { + UClass* Class = (*ActualMaterial)->GetClass(); + + if(Class->IsChildOf()) + *ActualMaterial = static_cast(*ActualMaterial)->DiffuseTexture; + else if(Class == UHsBumpDiffBlend::StaticClass()) + *ActualMaterial = static_cast(*ActualMaterial)->DiffuseTexture; + else if(Class == UHsBumpDiffBlendMask::StaticClass()) + *ActualMaterial = static_cast(*ActualMaterial)->DiffuseTexture; + else if(Class == UHsBumpDiffBlendMaskIllum::StaticClass()) + *ActualMaterial = static_cast(*ActualMaterial)->DiffuseTexture; + else if(Class == UHsFalloff::StaticClass()) + *ActualMaterial = static_cast(*ActualMaterial)->DiffuseTexture; + else if(Class == UHsHologram::StaticClass()) + *ActualMaterial = static_cast(*ActualMaterial)->DiffuseTexture; + } + } + + if(!*ActualMaterial) + *ActualMaterial = GetDefault()->DefaultMaterial; + } + + D3D->SetMaterial(Material, ErrorString, ErrorMaterial, NumPasses); +} + +void URtxRenderDevice::DrawPrimitive(EPrimitiveType PrimitiveType, INT FirstIndex, INT NumPrimitives, INT MinIndex, INT MaxIndex) +{ + if(!IgnoreDrawCall) + D3D->DrawPrimitive(PrimitiveType, FirstIndex, NumPrimitives, MinIndex, MaxIndex); +} diff --git a/RtxDrv/Src/RtxRenderDevice.h b/RtxDrv/Src/RtxRenderDevice.h new file mode 100644 index 00000000..046dd343 --- /dev/null +++ b/RtxDrv/Src/RtxRenderDevice.h @@ -0,0 +1,119 @@ +#pragma once + +#include "../../D3DDrv/Inc/D3DDrv.h" + +class URtx; + +class FAnchorTriangleVertexStream : public FVertexStream{ +public: + FAnchorTriangleVertexStream() + { + CacheId = MakeCacheID(CID_RenderVertices); + Update(0.0f); + } + + void Update(FLOAT InZOffset) + { + ZOffset = InZOffset; + ++Revision; + } + + virtual INT GetStride(){ return sizeof(FVector); } + virtual INT GetSize(){ return sizeof(FVector) * 3; } + + virtual INT GetComponents(FVertexComponent* Components) + { + Components->Type = CT_Float3; + Components->Function = FVF_Position; + return 1; + } + + virtual void GetStreamData(void* Dest) + { + FVector* D = static_cast(Dest); + const FLOAT Size = 512.0f; + D[0] = FVector(-Size, -Size, ZOffset); + D[1] = FVector( Size, -Size, ZOffset); + D[2] = FVector( 0.0f, Size, ZOffset); + } + +private: + FLOAT ZOffset; +}; + +class URtxRenderDevice : public UD3DRenderDevice, FRenderInterface{ + DECLARE_CLASS(URtxRenderDevice,UD3DRenderDevice,CLASS_Config,RtxDrv) + static const TCHAR* StaticConfigName(){ return "Rtx"; } +public: + void StaticConstructor(); + + virtual void Serialize(FArchive& Ar); + virtual UBOOL Exec(const TCHAR* Cmd, FOutputDevice& Ar); + virtual UBOOL Init(); + virtual void Exit(UViewport* Viewport); + virtual UBOOL SetRes(UViewport* Viewport, INT NewX, INT NewY, UBOOL Fullscreen, INT ColorBytes = 0, UBOOL bSaveSize = true); + virtual void Flush(UViewport* Viewport); + virtual FRenderInterface* Lock(UViewport* Viewport, BYTE* HitData, INT* HitSize); + virtual void Unlock(FRenderInterface* RI); + virtual void Present(UViewport* Viewport); + + URtx* GetRtxInterface(){ checkSlow(Rtx); return Rtx; } + + // FRenderInterface + + virtual void PushState(DWORD Flags = 0){ D3D->PushState(Flags); } + virtual void PopState(DWORD Flags = 0){ D3D->PopState(Flags); } + virtual UBOOL SetRenderTarget(FRenderTarget* RenderTarget, bool bOwnDepthBuffer); + virtual void SetViewport(INT X, INT Y, INT Width, INT Height){ D3D->SetViewport(X, Y, Width, Height); } + virtual void Clear(UBOOL UseColor = 1, FColor Color = FColor(0, 0, 0), UBOOL UseDepth = 1, FLOAT Depth = 1.0f, UBOOL UseStencil = 1, DWORD Stencil = 0); + virtual void PushHit(const BYTE* Data, INT Count){ D3D->PushHit(Data, Count); } + virtual void PopHit(INT Count, UBOOL Force){ D3D->PopHit(Count, Force); } + virtual void SetCullMode(ECullMode CullMode){ D3D->SetCullMode(CullMode); } + virtual void SetAmbientLight(FColor Color){} + virtual void EnableLighting(UBOOL UseDynamic, UBOOL UseStatic, UBOOL Modulate2X, FBaseTexture* Lightmap, UBOOL LightingOnly, const FSphere& LitSphere, int IntValue); + virtual void SetLight(INT LightIndex, FDynamicLight* Light, FLOAT Scale = 1.0f); + virtual void SetShaderLight(INT LightIndex, FDynamicLight* Light, FLOAT Scale = 1.0f){} + virtual void SetNPatchTesselation(FLOAT Tesselation){ D3D->SetNPatchTesselation(Tesselation); } + virtual void SetDistanceFog(UBOOL Enable, FLOAT FogStart, FLOAT FogEnd, FColor Color){ D3D->SetDistanceFog(0, 0.0f, 0.0f, FColor()); } + virtual UBOOL EnableFog(UBOOL Enable){ return D3D->EnableFog(0); } + virtual UBOOL IsFogEnabled(){ return D3D->IsFogEnabled(); } + virtual void SetGlobalColor(FColor Color){ D3D->SetGlobalColor(Color); } + virtual void SetTransform(ETransformType Type, const FMatrix& Matrix); + virtual FMatrix GetTransform(ETransformType Type) const { return D3D->GetTransform(Type); } + virtual void SetMaterial(UMaterial* Material, FString* ErrorString = NULL, UMaterial** ErrorMaterial = NULL, INT* NumPasses = NULL); + virtual UBOOL SetHardwareShaderMaterial(UHardwareShader* Material, FString* ErrorString = NULL, UMaterial** ErrorMaterial = NULL){ return D3D->SetHardwareShaderMaterial(Material, ErrorString, ErrorMaterial); } + virtual UBOOL ShowAlpha(UMaterial* Material){ return D3D->ShowAlpha(Material); } + virtual UBOOL IsShadowInterface(){ return 0; } + virtual void SetAntiAliasing(INT Level){} + virtual void CopyBackBufferToTarget(FAuxRenderTarget* Target){ D3D->CopyBackBufferToTarget(Target); } + virtual void SetLODDiffuseFade(FLOAT Distance){ D3D->SetLODDiffuseFade(Distance); } + virtual void SetLODSpecularFade(FLOAT Distance){ D3D->SetLODSpecularFade(Distance); } + virtual void SetStencilOp(ECompareFunction Test, DWORD Ref, DWORD Mask, EStencilOp FailOp, EStencilOp ZFailOp, EStencilOp PassOp, DWORD WriteMask){} + virtual void EnableStencil(UBOOL Enable){} + virtual void EnableDepth(UBOOL Enable){ D3D->EnableDepth(Enable); } + virtual void SetPrecacheMode(EPrecacheMode){ D3D->SetPrecacheMode(PRECACHE_All); } + virtual void SetZBias(INT ZBias){ D3D->SetZBias(ZBias); } + virtual INT SetVertexStreams(EVertexShader Shader, FVertexStream** Streams, INT NumStreams){ return D3D->SetVertexStreams(Shader, Streams, NumStreams); } + virtual INT SetDynamicStream(EVertexShader Shader, FVertexStream* Stream){ return D3D->SetDynamicStream(Shader, Stream); } + virtual INT SetIndexBuffer(FIndexBuffer* IndexBuffer, INT BaseIndex){ return D3D->SetIndexBuffer(IndexBuffer, BaseIndex); } + virtual INT SetDynamicIndexBuffer(FIndexBuffer* IndexBuffer, INT BaseIndex){ return D3D->SetDynamicIndexBuffer(IndexBuffer, BaseIndex); } + virtual void DrawPrimitive(EPrimitiveType PrimitiveType, INT FirstIndex, INT NumPrimitives, INT MinIndex = INDEX_NONE, INT MaxIndex = INDEX_NONE); + virtual void SetFillMode(EFillMode FillMode){ D3D->SetFillMode(FillMode); } + +private: + UViewport* LockedViewport; + FAnchorTriangleVertexStream AnchorTriangleStream; + FRenderInterface* D3D; + URtx* Rtx; + UBOOL DepthCleared; + + enum EIgnoreDrawCallFlags{ + IgnoreDrawCall_Lightmap = 0x1, + IgnoreDrawCall_Material = 0x2, + }; + + BITFIELD IgnoreDrawCall; + + void CheckForLevelChange(UViewport* Viewport); + void DrawAnchorTriangle(); +}; diff --git a/RtxDrv/Src/remix_c.h b/RtxDrv/Src/remix_c.h new file mode 100644 index 00000000..e41b4b9d --- /dev/null +++ b/RtxDrv/Src/remix_c.h @@ -0,0 +1,756 @@ +/* + * Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +// Bridge API header for both the x86 bridge client and the x86 game + +#ifndef BRIDGE_C_H_ +#define BRIDGE_C_H_ + +#include "UnVcWin32.h" + +typedef BYTE uint8_t; +typedef INT int32_t; +typedef DWORD uint32_t; +typedef QWORD uint64_t; + +// __stdcall convention +#define REMIXAPI_CALL __stdcall +#define REMIXAPI_PTR REMIXAPI_CALL + +#ifdef REMIX_LIBRARY_EXPORTS + #define REMIXAPI __declspec(dllexport) +#else + #define REMIXAPI __declspec(dllimport) +#endif // REMIX_LIBRARY_EXPORTS + + +#define REMIXAPI_VERSION_MAKE(major, minor, patch) ( \ + (((uint64_t)(major)) << 48) | \ + (((uint64_t)(minor)) << 16) | \ + (((uint64_t)(patch)) ) ) +#define REMIXAPI_VERSION_GET_MAJOR(version) (((uint64_t)(version) >> 48) & (uint64_t)0xFFFF) +#define REMIXAPI_VERSION_GET_MINOR(version) (((uint64_t)(version) >> 16) & (uint64_t)0xFFFFFFFF) +#define REMIXAPI_VERSION_GET_PATCH(version) (((uint64_t)(version) ) & (uint64_t)0xFFFF) + +#define REMIXAPI_VERSION_MAJOR 0 +#define REMIXAPI_VERSION_MINOR 4 +#define REMIXAPI_VERSION_PATCH 1 + + +// External +typedef struct IDirect3D9Ex IDirect3D9Ex; +typedef struct IDirect3DDevice9Ex IDirect3DDevice9Ex; +typedef struct IDirect3DSurface9 IDirect3DSurface9; + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + typedef enum remixapi_StructType { + REMIXAPI_STRUCT_TYPE_NONE = 0, + REMIXAPI_STRUCT_TYPE_INITIALIZE_LIBRARY_INFO = 1, + REMIXAPI_STRUCT_TYPE_MATERIAL_INFO = 2, + REMIXAPI_STRUCT_TYPE_MATERIAL_INFO_PORTAL_EXT = 3, + REMIXAPI_STRUCT_TYPE_MATERIAL_INFO_TRANSLUCENT_EXT = 4, + REMIXAPI_STRUCT_TYPE_MATERIAL_INFO_OPAQUE_EXT = 5, + REMIXAPI_STRUCT_TYPE_LIGHT_INFO = 6, + REMIXAPI_STRUCT_TYPE_LIGHT_INFO_DISTANT_EXT = 7, + REMIXAPI_STRUCT_TYPE_LIGHT_INFO_CYLINDER_EXT = 8, + REMIXAPI_STRUCT_TYPE_LIGHT_INFO_DISK_EXT = 9, + REMIXAPI_STRUCT_TYPE_LIGHT_INFO_RECT_EXT = 10, + REMIXAPI_STRUCT_TYPE_LIGHT_INFO_SPHERE_EXT = 11, + REMIXAPI_STRUCT_TYPE_MESH_INFO = 12, + REMIXAPI_STRUCT_TYPE_INSTANCE_INFO = 13, + REMIXAPI_STRUCT_TYPE_INSTANCE_INFO_BONE_TRANSFORMS_EXT = 14, + REMIXAPI_STRUCT_TYPE_INSTANCE_INFO_BLEND_EXT = 15, + REMIXAPI_STRUCT_TYPE_CAMERA_INFO = 16, + REMIXAPI_STRUCT_TYPE_CAMERA_INFO_PARAMETERIZED_EXT = 17, + REMIXAPI_STRUCT_TYPE_MATERIAL_INFO_OPAQUE_SUBSURFACE_EXT = 18, + REMIXAPI_STRUCT_TYPE_INSTANCE_INFO_OBJECT_PICKING_EXT = 19, + REMIXAPI_STRUCT_TYPE_LIGHT_INFO_DOME_EXT = 20, + REMIXAPI_STRUCT_TYPE_LIGHT_INFO_USD_EXT = 21, + REMIXAPI_STRUCT_TYPE_STARTUP_INFO = 22, + REMIXAPI_STRUCT_TYPE_PRESENT_INFO = 23, + // NOTE: if adding a new struct, register it in 'rtx_remix_specialization.inl' + } remixapi_StructType; + + typedef enum remixapi_ErrorCode { + REMIXAPI_ERROR_CODE_SUCCESS = 0, + REMIXAPI_ERROR_CODE_GENERAL_FAILURE = 1, + // WinAPI's LoadLibrary has failed + REMIXAPI_ERROR_CODE_LOAD_LIBRARY_FAILURE = 2, + REMIXAPI_ERROR_CODE_INVALID_ARGUMENTS = 3, + // Couldn't find 'remixInitialize' function in the .dll + REMIXAPI_ERROR_CODE_GET_PROC_ADDRESS_FAILURE = 4, + // CreateD3D9 / RegisterD3D9Device can be called only once + REMIXAPI_ERROR_CODE_ALREADY_EXISTS = 5, + // RegisterD3D9Device requires the device that was created with IDirect3DDevice9Ex, returned by CreateD3D9 + REMIXAPI_ERROR_CODE_REGISTERING_NON_REMIX_D3D9_DEVICE = 6, + // RegisterD3D9Device was not called + REMIXAPI_ERROR_CODE_REMIX_DEVICE_WAS_NOT_REGISTERED = 7, + REMIXAPI_ERROR_CODE_INCOMPATIBLE_VERSION = 8, + // WinAPI's SetDllDirectory has failed + REMIXAPI_ERROR_CODE_SET_DLL_DIRECTORY_FAILURE = 9, + // WinAPI's GetFullPathName has failed + REMIXAPI_ERROR_CODE_GET_FULL_PATH_NAME_FAILURE = 10, + REMIXAPI_ERROR_CODE_NOT_INITIALIZED = 11, + // Error codes that are encoded as HRESULT, i.e. returned from D3D9 functions. + // Look MAKE_D3DHRESULT, but with _FACD3D=0x896, instead of D3D9's 0x876 + REMIXAPI_ERROR_CODE_HRESULT_NO_REQUIRED_GPU_FEATURES = 0x88960001, + REMIXAPI_ERROR_CODE_HRESULT_DRIVER_VERSION_BELOW_MINIMUM = 0x88960002, + REMIXAPI_ERROR_CODE_HRESULT_DXVK_INSTANCE_EXTENSION_FAIL = 0x88960003, + REMIXAPI_ERROR_CODE_HRESULT_VK_CREATE_INSTANCE_FAIL = 0x88960004, + REMIXAPI_ERROR_CODE_HRESULT_VK_CREATE_DEVICE_FAIL = 0x88960005, + REMIXAPI_ERROR_CODE_HRESULT_GRAPHICS_QUEUE_FAMILY_MISSING = 0x88960006, + } remixapi_ErrorCode; + + typedef uint32_t remixapi_Bool; + + typedef struct remixapi_Rect2D { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; + } remixapi_Rect2D; + + typedef struct remixapi_Float2D { + float x; + float y; + } remixapi_Float2D; + + typedef struct remixapi_Float3D { + float x; + float y; + float z; + } remixapi_Float3D; + + typedef struct remixapi_Float4D { + float x; + float y; + float z; + float w; + } remixapi_Float4D; + + typedef struct remixapi_Transform { + float matrix[3][4]; + } remixapi_Transform; + + typedef struct remixapi_MaterialHandle_T* remixapi_MaterialHandle; + typedef struct remixapi_MeshHandle_T* remixapi_MeshHandle; + typedef struct remixapi_LightHandle_T* remixapi_LightHandle; + + typedef const wchar_t* remixapi_Path; + + + + typedef struct remixapi_StartupInfo { + remixapi_StructType sType; + void* pNext; + HWND hwnd; + remixapi_Bool disableSrgbConversionForOutput; + // If true, 'dxvk_GetExternalSwapchain' can be used to retrieve a raw VkImage, + // so the application can present it, for example by using OpenGL interop: + // converting VkImage to OpenGL, and presenting it via OpenGL. + // Default: false. Use VkSwapchainKHR to present frame into HWND. + remixapi_Bool forceNoVkSwapchain; + remixapi_Bool editorModeEnabled; + } remixapi_StartupInfo; + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_Startup)(const remixapi_StartupInfo* info); + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_Shutdown)(void); + + + + typedef struct remixapi_MaterialInfoOpaqueEXT { + remixapi_StructType sType; + void* pNext; + remixapi_Path roughnessTexture; + remixapi_Path metallicTexture; + float anisotropy; + remixapi_Float3D albedoConstant; + float opacityConstant; + float roughnessConstant; + float metallicConstant; + remixapi_Bool thinFilmThickness_hasvalue; + float thinFilmThickness_value; + remixapi_Bool alphaIsThinFilmThickness; + remixapi_Path heightTexture; + float heightTextureStrength; + // If true, InstanceInfoBlendEXT is used as a source for alpha state + remixapi_Bool useDrawCallAlphaState; + remixapi_Bool blendType_hasvalue; + int blendType_value; + remixapi_Bool invertedBlend; + int alphaTestType; + uint8_t alphaReferenceValue; + } remixapi_MaterialInfoOpaqueEXT; + + // Valid only if remixapi_MaterialInfo contains remixapi_MaterialInfoOpaqueEXT in pNext chain + typedef struct remixapi_MaterialInfoOpaqueSubsurfaceEXT { + remixapi_StructType sType; + void* pNext; + remixapi_Path subsurfaceTransmittanceTexture; + remixapi_Path subsurfaceThicknessTexture; + remixapi_Path subsurfaceSingleScatteringAlbedoTexture; + remixapi_Float3D subsurfaceTransmittanceColor; + float subsurfaceMeasurementDistance; + remixapi_Float3D subsurfaceSingleScatteringAlbedo; + float subsurfaceVolumetricAnisotropy; + } remixapi_MaterialInfoOpaqueSubsurfaceEXT; + + typedef struct remixapi_MaterialInfoTranslucentEXT { + remixapi_StructType sType; + void* pNext; + remixapi_Path transmittanceTexture; + float refractiveIndex; + remixapi_Float3D transmittanceColor; + float transmittanceMeasurementDistance; + remixapi_Bool thinWallThickness_hasvalue; + float thinWallThickness_value; + remixapi_Bool useDiffuseLayer; + } remixapi_MaterialInfoTranslucentEXT; + + typedef struct remixapi_MaterialInfoPortalEXT { + remixapi_StructType sType; + void* pNext; + uint8_t rayPortalIndex; + float rotationSpeed; + } remixapi_MaterialInfoPortalEXT; + + typedef struct remixapi_MaterialInfo { + remixapi_StructType sType; + void* pNext; + uint64_t hash; + remixapi_Path albedoTexture; + remixapi_Path normalTexture; + remixapi_Path tangentTexture; + remixapi_Path emissiveTexture; + float emissiveIntensity; + remixapi_Float3D emissiveColorConstant; + uint8_t spriteSheetRow; + uint8_t spriteSheetCol; + uint8_t spriteSheetFps; + uint8_t filterMode; + uint8_t wrapModeU; + uint8_t wrapModeV; + } remixapi_MaterialInfo; + + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_CreateMaterial)( + const remixapi_MaterialInfo* info, + remixapi_MaterialHandle* out_handle); + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_DestroyMaterial)( + remixapi_MaterialHandle handle); + + typedef struct remixapi_HardcodedVertex { + float position[3]; + float normal[3]; + float texcoord[2]; + uint32_t color; + uint32_t _pad0; + uint32_t _pad1; + uint32_t _pad2; + uint32_t _pad3; + uint32_t _pad4; + uint32_t _pad5; + uint32_t _pad6; + } remixapi_HardcodedVertex; + + typedef struct remixapi_MeshInfoSkinning { + uint32_t bonesPerVertex; + // Each tuple of 'bonesPerVertex' float-s defines a vertex. + // I.e. the size must be (bonesPerVertex * vertexCount). + const float* blendWeights_values; + uint32_t blendWeights_count; + // Each tuple of 'bonesPerVertex' uint32_t-s defines a vertex. + // I.e. the size must be (bonesPerVertex * vertexCount). + const uint32_t* blendIndices_values; + uint32_t blendIndices_count; + } remixapi_MeshInfoSkinning; + + typedef struct remixapi_MeshInfoSurfaceTriangles { + const remixapi_HardcodedVertex* vertices_values; + uint64_t vertices_count; + const uint32_t* indices_values; + uint64_t indices_count; + remixapi_Bool skinning_hasvalue; + remixapi_MeshInfoSkinning skinning_value; + remixapi_MaterialHandle material; + } remixapi_MeshInfoSurfaceTriangles; + + typedef struct remixapi_MeshInfo { + remixapi_StructType sType; + void* pNext; + uint64_t hash; + const remixapi_MeshInfoSurfaceTriangles* surfaces_values; + uint32_t surfaces_count; + } remixapi_MeshInfo; + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_CreateMesh)( + const remixapi_MeshInfo* info, + remixapi_MeshHandle* out_handle); + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_DestroyMesh)( + remixapi_MeshHandle handle); + + + + typedef enum remixapi_CameraType { + REMIXAPI_CAMERA_TYPE_WORLD, + REMIXAPI_CAMERA_TYPE_SKY, + REMIXAPI_CAMERA_TYPE_VIEW_MODEL, + } remixapi_CameraType; + + typedef struct remixapi_CameraInfoParameterizedEXT { + remixapi_StructType sType; + void* pNext; + remixapi_Float3D position; + remixapi_Float3D forward; + remixapi_Float3D up; + remixapi_Float3D right; + float fovYInDegrees; + float aspect; + float nearPlane; + float farPlane; + } remixapi_CameraInfoParameterizedEXT; + + typedef struct remixapi_CameraInfo { + remixapi_StructType sType; + void* pNext; + remixapi_CameraType type; + float view[4][4]; + float projection[4][4]; + } remixapi_CameraInfo; + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_SetupCamera)( + const remixapi_CameraInfo* info); + + + +#define REMIXAPI_INSTANCE_INFO_MAX_BONES_COUNT 256 + + typedef struct remixapi_InstanceInfoBoneTransformsEXT { + remixapi_StructType sType; + void* pNext; + const remixapi_Transform* boneTransforms_values; + uint32_t boneTransforms_count; + } remixapi_InstanceInfoBoneTransformsEXT; + + typedef struct remixapi_InstanceInfoBlendEXT { + remixapi_StructType sType; + void* pNext; + remixapi_Bool alphaTestEnabled; + uint8_t alphaTestReferenceValue; + uint32_t alphaTestCompareOp; + remixapi_Bool alphaBlendEnabled; + uint32_t srcColorBlendFactor; + uint32_t dstColorBlendFactor; + uint32_t colorBlendOp; + uint32_t textureColorArg1Source; + uint32_t textureColorArg2Source; + uint32_t textureColorOperation; + uint32_t textureAlphaArg1Source; + uint32_t textureAlphaArg2Source; + uint32_t textureAlphaOperation; + uint32_t tFactor; + remixapi_Bool isTextureFactorBlend; + } remixapi_InstanceInfoBlendEXT; + + typedef struct remixapi_InstanceInfoObjectPickingEXT { + remixapi_StructType sType; + void* pNext; + // A value to write for 'RequestObjectPicking' + uint32_t objectPickingValue; + } remixapi_InstanceInfoObjectPickingEXT; + + typedef enum remixapi_InstanceCategoryBit { + REMIXAPI_INSTANCE_CATEGORY_BIT_WORLD_UI = 1 << 0, + REMIXAPI_INSTANCE_CATEGORY_BIT_WORLD_MATTE = 1 << 1, + REMIXAPI_INSTANCE_CATEGORY_BIT_SKY = 1 << 2, + REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE = 1 << 3, + REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_LIGHTS = 1 << 4, + REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_ANTI_CULLING = 1 << 5, + REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_MOTION_BLUR = 1 << 6, + REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_OPACITY_MICROMAP = 1 << 7, + REMIXAPI_INSTANCE_CATEGORY_BIT_HIDDEN = 1 << 8, + REMIXAPI_INSTANCE_CATEGORY_BIT_PARTICLE = 1 << 9, + REMIXAPI_INSTANCE_CATEGORY_BIT_BEAM = 1 << 10, + REMIXAPI_INSTANCE_CATEGORY_BIT_DECAL_STATIC = 1 << 11, + REMIXAPI_INSTANCE_CATEGORY_BIT_DECAL_DYNAMIC = 1 << 12, + REMIXAPI_INSTANCE_CATEGORY_BIT_DECAL_SINGLE_OFFSET = 1 << 13, + REMIXAPI_INSTANCE_CATEGORY_BIT_DECAL_NO_OFFSET = 1 << 14, + REMIXAPI_INSTANCE_CATEGORY_BIT_ALPHA_BLEND_TO_CUTOUT = 1 << 15, + REMIXAPI_INSTANCE_CATEGORY_BIT_TERRAIN = 1 << 16, + REMIXAPI_INSTANCE_CATEGORY_BIT_ANIMATED_WATER = 1 << 17, + REMIXAPI_INSTANCE_CATEGORY_BIT_THIRD_PERSON_PLAYER_MODEL = 1 << 18, + REMIXAPI_INSTANCE_CATEGORY_BIT_THIRD_PERSON_PLAYER_BODY = 1 << 19, + REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_BAKED_LIGHTING = 1 << 20, + REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_ALPHA_CHANNEL = 1 << 21, + } remixapi_InstanceCategoryBit; + + typedef uint32_t remixapi_InstanceCategoryFlags; + + typedef struct remixapi_InstanceInfo { + remixapi_StructType sType; + void* pNext; + remixapi_InstanceCategoryFlags categoryFlags; + remixapi_MeshHandle mesh; + remixapi_Transform transform; + remixapi_Bool doubleSided; + } remixapi_InstanceInfo; + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_DrawInstance)( + const remixapi_InstanceInfo* info); + + + + typedef struct remixapi_LightInfoLightShaping { + // The direction the Light Shaping is pointing in. Must be normalized. + remixapi_Float3D direction; + float coneAngleDegrees; + float coneSoftness; + float focusExponent; + } remixapi_LightInfoLightShaping; + + typedef struct remixapi_LightInfoSphereEXT { + remixapi_StructType sType; + void* pNext; + remixapi_Float3D position; + float radius; + remixapi_Bool shaping_hasvalue; + remixapi_LightInfoLightShaping shaping_value; + } remixapi_LightInfoSphereEXT; + + typedef struct remixapi_LightInfoRectEXT { + remixapi_StructType sType; + void* pNext; + remixapi_Float3D position; + // The X axis of the Rect Light. Must be normalized and orthogonal to the Y and direction axes. + remixapi_Float3D xAxis; + float xSize; + // The Y axis of the Rect Light. Must be normalized and orthogonal to the X and direction axes. + remixapi_Float3D yAxis; + float ySize; + // The direction the Rect Light is pointing in, should match the Shaping direction if present. + // Must be normalized and orthogonal to the X and Y axes. + remixapi_Float3D direction; + remixapi_Bool shaping_hasvalue; + remixapi_LightInfoLightShaping shaping_value; + } remixapi_LightInfoRectEXT; + + typedef struct remixapi_LightInfoDiskEXT { + remixapi_StructType sType; + void* pNext; + remixapi_Float3D position; + // The X axis of the Disk Light. Must be normalized and orthogonal to the Y and direction axes. + remixapi_Float3D xAxis; + float xRadius; + // The Y axis of the Disk Light. Must be normalized and orthogonal to the X and direction axes. + remixapi_Float3D yAxis; + float yRadius; + // The direction the Disk Light is pointing in, should match the Shaping direction if present + // Must be normalized and orthogonal to the X and Y axes. + remixapi_Float3D direction; + remixapi_Bool shaping_hasvalue; + remixapi_LightInfoLightShaping shaping_value; + } remixapi_LightInfoDiskEXT; + + typedef struct remixapi_LightInfoCylinderEXT { + remixapi_StructType sType; + void* pNext; + remixapi_Float3D position; + float radius; + // The "center" axis of the Cylinder Light. Must be normalized. + remixapi_Float3D axis; + float axisLength; + } remixapi_LightInfoCylinderEXT; + + typedef struct remixapi_LightInfoDistantEXT { + remixapi_StructType sType; + void* pNext; + // The direction the Distant Light is pointing in. Must be normalized. + remixapi_Float3D direction; + float angularDiameterDegrees; + } remixapi_LightInfoDistantEXT; + + typedef struct remixapi_LightInfoDomeEXT { + remixapi_StructType sType; + void* pNext; + remixapi_Transform transform; + remixapi_Path colorTexture; + } remixapi_LightInfoDomeEXT; + + // Attachable to remixapi_LightInfo. + // If attached, 'remixapi_LightInfo::radiance' is ignored. + // Any other attached 'remixapi_LightInfo*EXT' are ignored. + // Most fields correspond to a usd token. Set to null, if no value. + typedef struct remixapi_LightInfoUSDEXT { + remixapi_StructType sType; + void* pNext; + remixapi_StructType lightType; + remixapi_Transform transform; + const float* pRadius; // "radius" + const float* pWidth; // "width" + const float* pHeight; // "height" + const float* pLength; // "length" + const float* pAngleRadians; // "angle" + const remixapi_Bool* pEnableColorTemp; // "enableColorTemperature" + const remixapi_Float3D* pColor; // "color" + const float* pColorTemp; // "colorTemperature" + const float* pExposure; // "exposure" + const float* pIntensity; // "intensity" + const float* pConeAngleRadians; // "shaping:cone:angle" + const float* pConeSoftness; // "shaping:cone:softness" + const float* pFocus; // "shaping:focus" + } remixapi_LightInfoUSDEXT; + + typedef struct remixapi_LightInfo { + remixapi_StructType sType; + void* pNext; + uint64_t hash; + remixapi_Float3D radiance; + } remixapi_LightInfo; + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_CreateLight)( + const remixapi_LightInfo* info, + remixapi_LightHandle* out_handle); + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_DestroyLight)( + remixapi_LightHandle handle); + + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_DrawLightInstance)( + remixapi_LightHandle lightHandle); + + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_SetConfigVariable)( + const char* key, + const char* value); + + typedef struct remixapi_PresentInfo { + remixapi_StructType sType; + void* pNext; + HWND hwndOverride; // Can be NULL + } remixapi_PresentInfo; + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_Present)(const remixapi_PresentInfo* info); + + typedef void (REMIXAPI_PTR* PFN_remixapi_pick_RequestObjectPickingUserCallback)( + const uint32_t* objectPickingValues_values, + uint32_t objectPickingValues_count, + void* callbackUserData); + + // Invokes 'callback' on a successful readback of 'remixapi_InstanceInfoObjectPickingEXT::objectPickingValue' + // of objects that are drawn in the 'pixelRegion'. 'pixelRegion' specified relative to the output size, + // not render size. 'callback' can be invoked from any thread. + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_pick_RequestObjectPicking)( + const remixapi_Rect2D* pixelRegion, + PFN_remixapi_pick_RequestObjectPickingUserCallback callback, + void* callbackUserData); + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_pick_HighlightObjects)( + const uint32_t* objectPickingValues_values, + uint32_t objectPickingValues_count, + uint8_t colorR, + uint8_t colorG, + uint8_t colorB); + + + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_dxvk_CreateD3D9)( + remixapi_Bool editorModeEnabled, + IDirect3D9Ex** out_pD3D9); + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_dxvk_RegisterD3D9Device)( + IDirect3DDevice9Ex* d3d9Device); + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_dxvk_GetExternalSwapchain)( + uint64_t* out_vkImage, + uint64_t* out_vkSemaphoreRenderingDone, + uint64_t* out_vkSemaphoreResumeSemaphore); + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_dxvk_GetVkImage)( + IDirect3DSurface9* source, + uint64_t* out_vkImage); + + typedef enum remixapi_dxvk_CopyRenderingOutputType { + REMIXAPI_DXVK_COPY_RENDERING_OUTPUT_TYPE_FINAL_COLOR = 0, + REMIXAPI_DXVK_COPY_RENDERING_OUTPUT_TYPE_DEPTH = 1, + REMIXAPI_DXVK_COPY_RENDERING_OUTPUT_TYPE_NORMALS = 2, + REMIXAPI_DXVK_COPY_RENDERING_OUTPUT_TYPE_OBJECT_PICKING = 3, + } remixapi_dxvk_CopyRenderingOutputType; + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_dxvk_CopyRenderingOutput)( + IDirect3DSurface9* destination, + remixapi_dxvk_CopyRenderingOutputType type); + + typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_dxvk_SetDefaultOutput)( + remixapi_dxvk_CopyRenderingOutputType type, + const remixapi_Float4D* color); + + + typedef struct remixapi_InitializeLibraryInfo { + remixapi_StructType sType; + void* pNext; + uint64_t version; + } remixapi_InitializeLibraryInfo; + + typedef struct remixapi_Interface { + PFN_remixapi_Shutdown Shutdown; + PFN_remixapi_CreateMaterial CreateMaterial; + PFN_remixapi_DestroyMaterial DestroyMaterial; + PFN_remixapi_CreateMesh CreateMesh; + PFN_remixapi_DestroyMesh DestroyMesh; + PFN_remixapi_SetupCamera SetupCamera; + PFN_remixapi_DrawInstance DrawInstance; + PFN_remixapi_CreateLight CreateLight; + PFN_remixapi_DestroyLight DestroyLight; + PFN_remixapi_DrawLightInstance DrawLightInstance; + PFN_remixapi_SetConfigVariable SetConfigVariable; + + // DXVK interoperability + PFN_remixapi_dxvk_CreateD3D9 dxvk_CreateD3D9; + PFN_remixapi_dxvk_RegisterD3D9Device dxvk_RegisterD3D9Device; + PFN_remixapi_dxvk_GetExternalSwapchain dxvk_GetExternalSwapchain; + PFN_remixapi_dxvk_GetVkImage dxvk_GetVkImage; + PFN_remixapi_dxvk_CopyRenderingOutput dxvk_CopyRenderingOutput; + PFN_remixapi_dxvk_SetDefaultOutput dxvk_SetDefaultOutput; + // Object picking utils + PFN_remixapi_pick_RequestObjectPicking pick_RequestObjectPicking; + PFN_remixapi_pick_HighlightObjects pick_HighlightObjects; + + PFN_remixapi_Startup Startup; + PFN_remixapi_Present Present; + } remixapi_Interface; + + REMIXAPI remixapi_ErrorCode REMIXAPI_CALL remixapi_InitializeLibrary( + const remixapi_InitializeLibraryInfo* info, + remixapi_Interface* out_result); + + typedef remixapi_ErrorCode(REMIXAPI_CALL* PFN_remixapi_InitializeLibrary)( + const remixapi_InitializeLibraryInfo* info, + remixapi_Interface* out_result); + + + inline remixapi_ErrorCode REMIXAPI_CALL remixapi_lib_loadRemixDllAndInitialize( + const wchar_t* remixD3D9DllPath, + remixapi_Interface* out_remixInterface, + HMODULE* out_remixDll + ) { + if (remixD3D9DllPath == NULL || remixD3D9DllPath[0] == '\0') { + return REMIXAPI_ERROR_CODE_INVALID_ARGUMENTS; + } + if (out_remixInterface == NULL || out_remixDll == NULL) { + return REMIXAPI_ERROR_CODE_INVALID_ARGUMENTS; + } + + HMODULE remixDll = NULL; + PFN_remixapi_InitializeLibrary pfn_InitializeLibrary = NULL; + { + // firstly, try the default method first, e.g. DLL is already loaded, + // DLL-s are around .exe, or an app has called SetDllDirectory + { + HMODULE dll = LoadLibraryW(remixD3D9DllPath); + if (dll) { + PROC func = GetProcAddress(dll, "remixapi_InitializeLibrary"); + if (func) { + remixDll = dll; + pfn_InitializeLibrary = (PFN_remixapi_InitializeLibrary) func; + } else { + FreeLibrary(dll); + } + } + } + + // then try raw user-provided 'remixD3D9DllPath' file + if (!pfn_InitializeLibrary) { + // set LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR to search + // dependency DLL-s in the folder of 'remixD3D9DllPath' + HMODULE dll = LoadLibraryW(remixD3D9DllPath); + if (dll) { + PROC func = GetProcAddress(dll, "remixapi_InitializeLibrary"); + if (func) { + remixDll = dll; + pfn_InitializeLibrary = (PFN_remixapi_InitializeLibrary) func; + } else { + FreeLibrary(dll); + } + } + } + } + + if (!remixDll) { + return REMIXAPI_ERROR_CODE_LOAD_LIBRARY_FAILURE; + } + if (!pfn_InitializeLibrary){ + return REMIXAPI_ERROR_CODE_GET_PROC_ADDRESS_FAILURE; + } + + remixapi_InitializeLibraryInfo info; + { + info.pNext = NULL; + info.sType = REMIXAPI_STRUCT_TYPE_INITIALIZE_LIBRARY_INFO; + info.version = REMIXAPI_VERSION_MAKE(REMIXAPI_VERSION_MAJOR, + REMIXAPI_VERSION_MINOR, + REMIXAPI_VERSION_PATCH); + } + remixapi_Interface remixInterface = { 0 }; + + remixapi_ErrorCode status = pfn_InitializeLibrary(&info, &remixInterface); + if (status != REMIXAPI_ERROR_CODE_SUCCESS) { + FreeLibrary(remixDll); + return status; + } + + *out_remixInterface = remixInterface; + *out_remixDll = remixDll; + return status; + } + + inline remixapi_ErrorCode REMIXAPI_CALL remixapi_lib_shutdownAndUnloadRemixDll( + remixapi_Interface* remixInterface, + HMODULE remixDll + ) { + if (remixInterface == NULL || remixInterface->Shutdown == NULL) { + if (remixDll != NULL) { + FreeLibrary(remixDll); + } + return REMIXAPI_ERROR_CODE_INVALID_ARGUMENTS; + } + + remixapi_ErrorCode status = remixInterface->Shutdown(); + if (remixDll != NULL) { + FreeLibrary(remixDll); + } + + remixapi_Interface nullInterface = { 0 }; + *remixInterface = nullInterface; + return status; + } + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // REMIX_C_H_ diff --git a/UCC/UCC.ini b/UCC/UCC.ini index b8200683..4cbdef3d 100644 --- a/UCC/UCC.ini +++ b/UCC/UCC.ini @@ -18,6 +18,7 @@ MatineeCurveDetail=0.1 ;Add the packages you want to compile here in this format: Editpackages+=MyPackageName EditPackages+=Mod EditPackages+=ModMPGame +EditPackages+=RtxDrv [URL] Protocol=republiccommando diff --git a/compile_flags.txt b/compile_flags.txt index 79124f26..1bbcf4f7 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -6,6 +6,7 @@ -DCTGAME_API= -DCTMARKERS_API= -DD3DDRV_API= +-DRTXDRV_API= -DEDITOR_API= -DENGINE_API= -DGAMEPLAY_API=