⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 opengl.cpp

📁 虚幻的再开发程序包源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*=============================================================================
	OpenGL.cpp: Unreal OpenGL support implementation.
	Copyright 1997-1999 Epic Games, Inc. All Rights Reserved.

	The UOpenGLRenderDevice class implements Unreal's abstract
	URenderDevice class, which abstracts the concept of a "3d rendering
	device".

	Other URenderDevice subclasses include:
	* USoftwareRenderDevice: Software renderer.
	* UGlideRenderDevice: 3dfx Glide renderer.
	* UDirect3DRenderDevice: Direct3D renderer.

	Revision history:
	* Created by Tim Sweeney
	* Inspired by code written by Keith Leonard
=============================================================================*/

#include "OpenGLDrv.h"

/*-----------------------------------------------------------------------------
	Globals.
-----------------------------------------------------------------------------*/

#define STDGL 1						/* Use standard GL driver or minidriver by default */
#define DYNAMIC_BIND 1				/* If 0, must static link to OpenGL32, Gdi32 */
#define GL_DLL (STDGL ? "OpenGL32.dll" : "3dfxgl.dll")
#define PYR(n) ((n)*((n+1))/2)		/* Pyramid scaling function */
BYTE ScaleByteNormal  [PYR(256)];	/* Regular normalization table */
BYTE ScaleByteBrighten[PYR(256)];	/* 2X overbrightening normalization table */
FPlane One4(1,1,1,1);				/* 4 consecutive floats for OpenGL */
#define OVERBRIGHT 1.4f

/*-----------------------------------------------------------------------------
	UOpenGLDrv.
-----------------------------------------------------------------------------*/

//
// A OpenGL rendering device attached to a viewport.
//
class UOpenGLRenderDevice : public URenderDevice
{
	DECLARE_CLASS(UOpenGLRenderDevice,URenderDevice,CLASS_Config)

	// Information about a cached texture.
	struct FCachedTexture
	{
		GLuint Id;
		INT BaseMip;
		INT UBits, VBits;
		INT UCopyBits, VCopyBits;
		FPlane ColorNorm, ColorRenorm;
	};

	// Permanent variables.
	HGLRC hRC;
	HWND hWnd;
	HDC hDC;
	UBOOL WasFullscreen;
	TMap<QWORD,FCachedTexture> LocalBindMap, *BindMap;
	TArray<FPlane> Modes;
	UViewport* Viewport;

	// Timing.
	DWORD BindCycles, ImageCycles, ComplexCycles, GouraudCycles, TileCycles;

	// Hardware constraints.
	INT MaxLogUOverV;
	INT MaxLogVOverU;
	INT MinLogTextureSize;
	INT MaxLogTextureSize;
	UBOOL UseZTrick;
	UBOOL UseMultiTexture;
	UBOOL UsePalette;
	UBOOL Multipass1X;
	UBOOL DoPrecache;
	UBOOL ShareLists;
	UBOOL AlwaysMipmap;
	BYTE* ScaleByte;

	// Hit info.
	BYTE* HitData;
	INT* HitSize;

	// Lock variables.
	UBOOL ZTrickToggle;
	INT ZTrickFunc;
	FPlane FlashScale, FlashFog;
	FLOAT RProjZ, Aspect;
	DWORD CurrentPolyFlags;
	TArray<INT> GLHitData;
	struct FTexInfo
	{
		QWORD CurrentCacheID;
		FLOAT UMult;
		FLOAT VMult;
		FLOAT UPan;
		FLOAT VPan;
		FPlane ColorNorm;
		FPlane ColorRenorm;
	} TexInfo[4];
	FLOAT RFX2, RFY2;

	// Static variables.
	static TMap<QWORD,FCachedTexture> SharedBindMap;
	static TArray<HGLRC> AllContexts;
	static INT     NumDevices;
	static INT     LockCount;
	static HGLRC   hCurrentRC;
	static HMODULE hModuleGlMain;
	static HMODULE hModuleGlGdi;

	// GL functions.
	#define GL_EXT(name) static UBOOL SUPPORTS##name;
	#define GL_PROC(ext,ret,func,parms) static ret (__stdcall *func)parms;
	#include "OpenGLFuncs.h"
	#undef GL_EXT
	#undef GL_PROC

	// Implementation.
	UBOOL FindExt( const TCHAR* Name )
	{
		guard(UOpenGLRenderDevice::FindExt);
		UBOOL Result = appStrfind(appFromAnsi((char*)glGetString(GL_EXTENSIONS)),Name)!=NULL;
		if( Result )
			debugf( NAME_Init, TEXT("Device supports: %s"), Name );
		return Result;
		unguard;
	}
	void FindProc( void*& ProcAddress, char* Name, char* SupportName, UBOOL& Supports, UBOOL AllowExt )
	{
		guard(UOpenGLRenderDevice::FindProc);
#if DYNAMIC_BIND
		if( !ProcAddress )
			ProcAddress = GetProcAddress( hModuleGlMain, Name );
		if( !ProcAddress )
			ProcAddress = GetProcAddress( hModuleGlGdi, Name );
#endif
		if( !ProcAddress && Supports && AllowExt )
			ProcAddress = wglGetProcAddress( Name );
		if( !ProcAddress )
		{
			if( Supports )
				debugf( TEXT("   Missing function '%s' for '%s' support"), appFromAnsi(Name), appFromAnsi(SupportName) );
			Supports = 0;
		}
		unguard;
	}
	void FindProcs( UBOOL AllowExt )
	{
		guard(UOpenGLDriver::FindProcs);
		#define GL_EXT(name) if( AllowExt ) SUPPORTS##name = FindExt( TEXT(#name)+1 );
		#define GL_PROC(ext,ret,func,parms) FindProc( *(void**)&func, #func, #ext, SUPPORTS##ext, AllowExt );
		#include "OpenGLFuncs.h"
		#undef GL_EXT
		#undef GL_PROC
		unguard;
	}
	UBOOL FailedInitf( const TCHAR* Fmt, ... )
	{
		TCHAR TempStr[4096];
		GET_VARARGS( TempStr, ARRAY_COUNT(TempStr), Fmt );
		debugf( NAME_Init, TempStr );
		Exit();
		return 0;
	}
	void MakeCurrent()
	{
		guard(UOpenGLRenderDevice::MakeCurrent);
		check(hRC);
		check(hDC);
		if( hCurrentRC!=hRC )
		{
			verify(wglMakeCurrent(hDC,hRC));
			hCurrentRC = hRC;
		}
		unguard;
	}
	void Check( const char* Tag )
	{
		GLenum Error = glGetError();
		if( Error!=GL_NO_ERROR )
		{
			const TCHAR* Msg=TEXT("Unknown");
			switch( Error )
			{
				case GL_NO_ERROR:
					Msg = TEXT("GL_NO_ERROR");
					break;
				case GL_INVALID_ENUM:
					Msg = TEXT("GL_INVALID_ENUM");
					break;
				case GL_INVALID_VALUE:
					Msg = TEXT("GL_INVALID_VALUE");
					break;
				case GL_INVALID_OPERATION:
					Msg = TEXT("GL_INVALID_OPERATION");
					break;
				case GL_STACK_OVERFLOW:
					Msg = TEXT("GL_STACK_OVERFLOW");
					break;
				case GL_STACK_UNDERFLOW:
					Msg = TEXT("GL_STACK_UNDERFLOW");
					break;
				case GL_OUT_OF_MEMORY:
					Msg = TEXT("GL_OUT_OF_MEMORY");
					break;
			};
			appErrorf( TEXT("OpenGL Error: %s (%s)"), Msg, Tag );
		}
	}
	void SetNoTexture( INT Multi )
	{
		guard(UOpenGLRenderDevice::SetNoTexture);
		if( TexInfo[Multi].CurrentCacheID != 0 )
		{
			// Set small white texture.
			clock(BindCycles);
			glBindTexture( GL_TEXTURE_2D, 0 );
			TexInfo[Multi].CurrentCacheID = 0;
			unclock(BindCycles);
		}
		unguard;
	}
	void SetTexture( INT Multi, FTextureInfo& Info, DWORD PolyFlags, FLOAT PanBias )
	{
		guard(UOpenGLRenderDevice::SetTexture);

		// Set panning.
		FTexInfo& Tex = TexInfo[Multi];
		Tex.UPan      = Info.Pan.X + PanBias*Info.UScale;
		Tex.VPan      = Info.Pan.Y + PanBias*Info.VScale;

		// Find in cache.
		if( Info.CacheID==Tex.CurrentCacheID && !Info.bRealtimeChanged )
			return;

		// Make current.
		clock(BindCycles);
		Tex.CurrentCacheID = Info.CacheID;
		FCachedTexture *Bind=BindMap->Find(Info.CacheID), *ExistingBind=Bind;
		if( !Bind )
		{
			// Figure out OpenGL-related scaling for the texture.
			Bind            = &BindMap->Add( Info.CacheID, FCachedTexture() );
			glGenTextures( 1, &Bind->Id );
			Bind->BaseMip   = Min(0,Info.NumMips-1);
			Bind->UCopyBits = 0;
			Bind->VCopyBits = 0;
			Bind->UBits     = Info.Mips[Bind->BaseMip]->UBits;
			Bind->VBits     = Info.Mips[Bind->BaseMip]->VBits;
			if( Bind->UBits-Bind->VBits > MaxLogUOverV )
			{
				Bind->VCopyBits += (Bind->UBits-Bind->VBits)-MaxLogUOverV;
				Bind->VBits      = Bind->UBits-MaxLogUOverV;
			}
			if( Bind->VBits-Bind->UBits > MaxLogVOverU )
			{
				Bind->UCopyBits += (Bind->VBits-Bind->UBits)-MaxLogVOverU;
				Bind->UBits      = Bind->VBits-MaxLogVOverU;
			}
			if( Bind->UBits < MinLogTextureSize )
			{
				Bind->UCopyBits += MinLogTextureSize - Bind->UBits;
				Bind->UBits     += MinLogTextureSize - Bind->UBits;
			}
			if( Bind->VBits < MinLogTextureSize )
			{
				Bind->VCopyBits += MinLogTextureSize - Bind->VBits;
				Bind->VBits     += MinLogTextureSize - Bind->VBits;
			}
			if( Bind->UBits > MaxLogTextureSize )
			{
				Bind->BaseMip += Bind->UBits-MaxLogTextureSize;
				Bind->VBits   -= Bind->UBits-MaxLogTextureSize;
				Bind->UBits    = MaxLogTextureSize;
				if( Bind->VBits < 0 )
				{
					Bind->VCopyBits = -Bind->VBits;
					Bind->VBits     = 0;
				}
			}
			if( Bind->VBits > MaxLogTextureSize )
			{
				Bind->BaseMip += Bind->VBits-MaxLogTextureSize;
				Bind->UBits   -= Bind->VBits-MaxLogTextureSize;
				Bind->VBits    = MaxLogTextureSize;
				if( Bind->UBits < 0 )
				{
					Bind->UCopyBits = -Bind->UBits;
					Bind->UBits     = 0;
				}
			}
		}
		glBindTexture( GL_TEXTURE_2D, Bind->Id );
		unclock(BindCycles);

		// Account for all the impact on scale normalization.
		Tex.UMult = 1.0 / (Info.UScale * (Info.USize << Bind->UCopyBits));
		Tex.VMult = 1.0 / (Info.VScale * (Info.VSize << Bind->VCopyBits));

		// Upload if needed.
		if( !ExistingBind || Info.bRealtimeChanged )
		{
			// Cleanup texture flags.
			Info.Load();
			Info.bRealtimeChanged = 0;

			// Set maximum color.
			Info.CacheMaxColor();
			Bind->ColorNorm = Info.Palette ? Info.MaxColor->Plane() : FPlane(Info.MaxColor->B/127.f,Info.MaxColor->G/127.f,Info.MaxColor->R/127.f,0);
			Bind->ColorNorm.W = 1;
			if( Multipass1X )
			{
				Bind->ColorRenorm.X = Min( Bind->ColorNorm.X * OVERBRIGHT, 1.0f );
				Bind->ColorRenorm.Y = Min( Bind->ColorNorm.Y * OVERBRIGHT, 1.0f );
				Bind->ColorRenorm.Z = Min( Bind->ColorNorm.Z * OVERBRIGHT, 1.0f );
			}
			else Bind->ColorRenorm = Bind->ColorNorm;

			// Setup scaling.
			BYTE* ScaleR   = &ScaleByte[PYR(Info.MaxColor->R)];
			BYTE* ScaleG   = &ScaleByte[PYR(Info.MaxColor->G)];
			BYTE* ScaleB   = &ScaleByte[PYR(Info.MaxColor->B)];

			// Generate the palette.
			FColor LocalPal[256], *NewPal=Info.Palette, TempColor(0,0,0,0);
			UBOOL Paletted = UsePalette && Info.Palette && !(PolyFlags & PF_Masked) && Info.Palette[0].A==255;//!!hw might support alpha palettes?
			if( Info.Palette )
			{
				TempColor = Info.Palette[0];
				if( PolyFlags & PF_Masked )
					Info.Palette[0] = FColor(0,0,0,0);
				NewPal = LocalPal;
				for( INT i=0; i<256; i++ )
				{
					FColor& Src = Info.Palette[i];
					NewPal[i].R = ScaleR[Src.R];
					NewPal[i].G = ScaleG[Src.G];
					NewPal[i].B = ScaleB[Src.B];
					NewPal[i].A = Src.A;
				}
				if( Paletted )
					glColorTableEXT( GL_TEXTURE_2D, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, NewPal );
			}

			// Download the texture.
			clock(ImageCycles);
			FMemMark Mark(GMem);
			BYTE* Compose  = New<BYTE>( GMem, (1<<(Bind->UBits+Bind->VBits))*4 );
			UBOOL SkipMipmaps = Info.NumMips==1 && !AlwaysMipmap;
			for( INT Level=0; Level<=Max(Bind->UBits,Bind->VBits); Level++ )
			{
				// Convert the mipmap.
				INT MipIndex=Bind->BaseMip+Level, StepBits=0;
				if( MipIndex>=Info.NumMips )
				{
					StepBits = MipIndex - (Info.NumMips - 1);
					MipIndex = Info.NumMips - 1;
				}
				FMipmapBase* Mip      = Info.Mips[MipIndex];
				BYTE*        Src      = (BYTE*)Compose;
				DWORD        Mask     = Mip->USize-1;
				GLuint       SourceFormat, InternalFormat;
				if( Paletted )
				{
					guard(ConvertP8_P8);
					SourceFormat   = GL_COLOR_INDEX;
					InternalFormat = GL_COLOR_INDEX8_EXT;
					BYTE* Ptr      = (BYTE*)Compose;
					for( INT i=0; i<(1<<Max(0,Bind->VBits-Level)); i++ )
					{
						BYTE* Base = (BYTE*)Mip->DataPtr + ((i<<StepBits)&(Mip->VSize-1))*Mip->USize;
						for( INT j=0; j<(1<<Max(0,Bind->UBits-Level+StepBits)); j+=(1<<StepBits) )
							*Ptr++ = Base[j&Mask];
					}
					unguard;
				}
				else if( Info.Palette )
				{
					guard(ConvertP8_RGBA8888);
					SourceFormat   = GL_RGBA;
					InternalFormat = GL_RGBA8; // GL_RGBA4!!
					FColor* Ptr    = (FColor*)Compose;
					for( INT i=0; i<(1<<Max(0,Bind->VBits-Level)); i++ )
					{
						BYTE* Base = (BYTE*)Mip->DataPtr + ((i<<StepBits)&(Mip->VSize-1))*Mip->USize;
						for( INT j=0; j<(1<<Max(0,Bind->UBits-Level+StepBits)); j+=(1<<StepBits) )
							*Ptr++ = NewPal[Base[j&Mask]];
					}
					unguard;
				}
				else
				{
					guard(ConvertBGRA7777_RGBA8888);
					SourceFormat   = GL_RGBA;
					InternalFormat = GL_RGBA8;
					FColor* Ptr    = (FColor*)Compose;
					for( INT i=0; i<(1<<Max(0,Bind->VBits-Level)); i++ )
					{
						FColor* Base = (FColor*)Mip->DataPtr + Min<DWORD>((i<<StepBits)&(Mip->VSize-1),Info.VClamp-1)*Mip->USize;
						for( INT j=0; j<(1<<Max(0,Bind->UBits-Level+StepBits)); j+=(1<<StepBits) )
						{
							FColor& Src = Base[Min<DWORD>(j&Mask,Info.UClamp-1)]; 
							Ptr->R      = ScaleB[Src.B];
							Ptr->G      = ScaleG[Src.G];
							Ptr->B      = ScaleR[Src.R];
							Ptr->A      = Src.A*2;
							Ptr++;
						}
					}
					unguard;
				}
				if( ExistingBind && 0 )//crashes frequently on TNT for Apache. My bug or theirs?
				{
					guard(glTexSubImage2D);
					glTexSubImage2D( GL_TEXTURE_2D, Level, 0, 0, 1<<Max(0,Bind->UBits-Level), 1<<Max(0,Bind->VBits-Level), SourceFormat, GL_UNSIGNED_BYTE, Src );
					unguard;
				}
				else
				{
					guard(glTexImage2D);
					glTexImage2D( GL_TEXTURE_2D, Level, InternalFormat, 1<<Max(0,Bind->UBits-Level), 1<<Max(0,Bind->VBits-Level), 0, SourceFormat, GL_UNSIGNED_BYTE, Src );
					unguard;
				}
				if( SkipMipmaps )
					break;
			}
			Mark.Pop();
			unclock(ImageCycles);

			// Set texture state.
			if( !(PolyFlags & PF_NoSmooth) )
			{
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, SkipMipmaps ? GL_LINEAR : GL_LINEAR_MIPMAP_NEAREST );
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			}
			else
			{
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, SkipMipmaps ? GL_NEAREST : GL_NEAREST_MIPMAP_NEAREST );
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			}

			// Cleanup.
			if( Info.Palette )
				Info.Palette[0] = TempColor;
			if( SupportsLazyTextures )
				Info.Unload();
		}

		// Copy color norm.
		Tex.ColorNorm   = Bind->ColorNorm;
		Tex.ColorRenorm = Bind->ColorRenorm;

		unguard;
	}
	void SetBlend( DWORD PolyFlags )
	{
		guardSlow(UOpenGLRenderDevice::SetBlend);

		// Adjust PolyFlags according to Unreal's precedence rules.
		if( !(PolyFlags & (PF_Translucent|PF_Modulated)) )
			PolyFlags |= PF_Occlude;
		else if( PolyFlags & PF_Translucent )
			PolyFlags &= ~PF_Masked;

		// Detect changes in the blending modes.
		DWORD Xor = CurrentPolyFlags^PolyFlags;
		if( Xor & (PF_Translucent|PF_Modulated|PF_Invisible|PF_Occlude|PF_Masked|PF_Environment) )
		{
			if( Xor&(PF_Translucent|PF_Modulated|PF_Environment) )
			{
				if( PolyFlags & PF_Translucent )
				{
					glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR );
				}
				else if( PolyFlags & PF_Modulated )
				{
					glBlendFunc( GL_DST_COLOR, GL_SRC_COLOR );
				}
				else if( PolyFlags & PF_Environment )
				{
					glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
				}
				else
				{
					glBlendFunc( GL_ONE, GL_ZERO );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -