about summary refs log tree commit diff
path: root/src/engine/client/graphics_threaded.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/client/graphics_threaded.h')
-rw-r--r--src/engine/client/graphics_threaded.h453
1 files changed, 453 insertions, 0 deletions
diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h
new file mode 100644
index 00000000..f90f818d
--- /dev/null
+++ b/src/engine/client/graphics_threaded.h
@@ -0,0 +1,453 @@
+#pragma once
+
+#include <engine/graphics.h>
+
+class CCommandBuffer
+{
+	class CBuffer
+	{
+		unsigned char *m_pData;
+		unsigned m_Size;
+		unsigned m_Used;
+	public:
+		CBuffer(unsigned BufferSize)
+		{
+			m_Size = BufferSize;
+			m_pData = new unsigned char[m_Size];
+			m_Used = 0;
+		}
+
+		~CBuffer()
+		{
+			delete [] m_pData;
+			m_pData = 0x0;
+			m_Used = 0;
+			m_Size = 0;
+		}
+
+		void Reset()
+		{
+			m_Used = 0;
+		}
+
+		void *Alloc(unsigned Requested)
+		{
+			if(Requested + m_Used > m_Size)
+				return 0;
+			void *pPtr = &m_pData[m_Used];
+			m_Used += Requested;
+			return pPtr;
+		}
+
+		unsigned char *DataPtr() { return m_pData; }
+		unsigned DataSize() { return m_Size; }
+		unsigned DataUsed() { return m_Used; }
+	};
+
+public:
+	CBuffer m_CmdBuffer;
+	CBuffer m_DataBuffer;
+
+	enum
+	{
+		MAX_TEXTURES=1024*4,
+	};
+
+	enum
+	{
+		// commadn groups
+		CMDGROUP_CORE = 0, // commands that everyone has to implement
+		CMDGROUP_PLATFORM = 10000, // commands specific to a platform
+
+		//
+		CMD_NOP = CMDGROUP_CORE,
+
+		//
+		CMD_RUNBUFFER,
+
+		// syncronization
+		CMD_SIGNAL,
+
+		// texture commands
+		CMD_TEXTURE_CREATE,
+		CMD_TEXTURE_DESTROY,
+		CMD_TEXTURE_UPDATE,
+
+		// rendering
+		CMD_CLEAR,
+		CMD_RENDER,
+
+		// swap
+		CMD_SWAP,
+
+		// misc
+		CMD_SCREENSHOT,
+		CMD_VIDEOMODES,
+
+	};
+
+	enum
+	{
+		TEXFORMAT_INVALID = 0,
+		TEXFORMAT_RGB,
+		TEXFORMAT_RGBA,
+		TEXFORMAT_ALPHA,
+
+		TEXFLAG_NOMIPMAPS = 1,
+	};
+
+	enum
+	{
+		INITFLAG_FULLSCREEN = 1,
+		INITFLAG_VSYNC = 2,
+		INITFLAG_RESIZABLE = 4,
+	};
+
+	enum
+	{
+		//
+		PRIMTYPE_INVALID = 0,
+		PRIMTYPE_LINES,	
+		PRIMTYPE_QUADS,
+	};
+
+	enum
+	{
+		BLEND_NONE = 0,
+		BLEND_ALPHA,
+		BLEND_ADDITIVE,
+	};
+
+	enum
+	{
+		WRAP_REPEAT = 0,
+		WRAP_CLAMP,
+	};
+
+	struct SPoint { float x, y, z; };
+	struct STexCoord { float u, v; };
+	struct SColor { float r, g, b, a; };
+
+	struct SVertex
+	{
+		SPoint m_Pos;
+		STexCoord m_Tex;
+		SColor m_Color;
+	};
+
+	struct SCommand
+	{
+	public:
+		SCommand(unsigned Cmd) : m_Cmd(Cmd), m_Size(0) {}
+		unsigned m_Cmd;
+		unsigned m_Size;
+	};
+
+	struct SState
+	{
+		int m_BlendMode;
+		int m_WrapMode;
+		int m_Texture;
+		SPoint m_ScreenTL;
+		SPoint m_ScreenBR;
+
+		// clip
+		bool m_ClipEnable;
+		int m_ClipX;
+		int m_ClipY;
+		int m_ClipW;
+		int m_ClipH;
+	};
+		
+	struct SCommand_Clear : public SCommand
+	{
+		SCommand_Clear() : SCommand(CMD_CLEAR) {}
+		SColor m_Color;
+	};
+		
+	struct SCommand_Signal : public SCommand
+	{
+		SCommand_Signal() : SCommand(CMD_SIGNAL) {}
+		semaphore *m_pSemaphore;
+	};
+
+	struct SCommand_RunBuffer : public SCommand
+	{
+		SCommand_RunBuffer() : SCommand(CMD_RUNBUFFER) {}
+		CCommandBuffer *m_pOtherBuffer;
+	};
+
+	struct SCommand_Render : public SCommand
+	{
+		SCommand_Render() : SCommand(CMD_RENDER) {}
+		SState m_State;
+		unsigned m_PrimType;
+		unsigned m_PrimCount;
+		SVertex *m_pVertices; // you should use the command buffer data to allocate vertices for this command
+	};
+
+	struct SCommand_Screenshot : public SCommand
+	{
+		SCommand_Screenshot() : SCommand(CMD_SCREENSHOT) {}
+		CImageInfo *m_pImage; // processor will fill this out, the one who adds this command must free the data as well
+	};
+
+	struct SCommand_VideoModes : public SCommand
+	{
+		SCommand_VideoModes() : SCommand(CMD_VIDEOMODES) {}
+
+		CVideoMode *m_pModes; // processor will fill this in
+		int m_MaxModes; // maximum of modes the processor can write to the m_pModes
+		int *m_pNumModes; // processor will write to this pointer
+	};
+
+	struct SCommand_Swap : public SCommand
+	{
+		SCommand_Swap() : SCommand(CMD_SWAP) {}
+
+		int m_Finish;
+	};
+
+	struct SCommand_Texture_Create : public SCommand
+	{
+		SCommand_Texture_Create() : SCommand(CMD_TEXTURE_CREATE) {}
+
+		// texture information
+		int m_Slot;
+
+		int m_Width;
+		int m_Height;
+		int m_Format;
+		int m_StoreFormat;
+		int m_Flags;
+		void *m_pData; // will be freed by the command processor
+	};
+
+	struct SCommand_Texture_Update : public SCommand
+	{
+		SCommand_Texture_Update() : SCommand(CMD_TEXTURE_UPDATE) {}
+
+		// texture information
+		int m_Slot;
+
+		int m_X;
+		int m_Y;
+		int m_Width;
+		int m_Height;
+		int m_Format;
+		void *m_pData; // will be freed by the command processor
+	};
+
+
+	struct SCommand_Texture_Destroy : public SCommand
+	{
+		SCommand_Texture_Destroy() : SCommand(CMD_TEXTURE_DESTROY) {}
+
+		// texture information
+		int m_Slot;
+	};
+	
+	//
+	CCommandBuffer(unsigned CmdBufferSize, unsigned DataBufferSize)
+	: m_CmdBuffer(CmdBufferSize), m_DataBuffer(DataBufferSize)
+	{
+	}
+
+	void *AllocData(unsigned WantedSize)
+	{
+		return m_DataBuffer.Alloc(WantedSize);
+	}
+
+	template<class T>
+	bool AddCommand(const T &Command)
+	{
+		// make sure that we don't do something stupid like ->AddCommand(&Cmd);
+		(void)static_cast<const SCommand *>(&Command);
+
+		// allocate and copy the command into the buffer
+		SCommand *pCmd = (SCommand *)m_CmdBuffer.Alloc(sizeof(Command));
+		if(!pCmd)
+			return false;
+		mem_copy(pCmd, &Command, sizeof(Command));
+		pCmd->m_Size = sizeof(Command);
+		return true;
+	}
+
+	SCommand *GetCommand(unsigned *pIndex)
+	{
+		if(*pIndex >= m_CmdBuffer.DataUsed())
+			return NULL;
+
+		SCommand *pCommand = (SCommand *)&m_CmdBuffer.DataPtr()[*pIndex];
+		*pIndex += pCommand->m_Size;
+		return pCommand;
+	}
+
+	void Reset()
+	{
+		m_CmdBuffer.Reset();
+		m_DataBuffer.Reset();
+	}
+};
+
+// interface for the graphics backend
+// all these functions are called on the main thread
+class IGraphicsBackend
+{
+public:
+	enum
+	{
+		INITFLAG_FULLSCREEN = 1,
+		INITFLAG_VSYNC = 2,
+		INITFLAG_RESIZABLE = 4,
+	};
+
+	virtual int Init(const char *pName, int Width, int Height, int FsaaSamples, int Flags) = 0;
+	virtual int Shutdown() = 0;
+
+	virtual void Minimize() = 0;
+	virtual void Maximize() = 0;
+	virtual int WindowActive() = 0;
+	virtual int WindowOpen() = 0;
+
+	virtual void RunBuffer(CCommandBuffer *pBuffer) = 0;
+	virtual bool IsIdle() const = 0;
+	virtual void WaitForIdle() = 0;
+};
+
+class CGraphics_Threaded : public IEngineGraphics
+{
+	enum
+	{
+		NUM_CMDBUFFERS = 2,
+
+		MAX_VERTICES = 32*1024,
+		MAX_TEXTURES = 1024*4,
+		
+		DRAWING_QUADS=1,
+		DRAWING_LINES=2
+	};
+
+	CCommandBuffer::SState m_State;
+	IGraphicsBackend *m_pBackend;
+
+	CCommandBuffer *m_apCommandBuffers[NUM_CMDBUFFERS];
+	CCommandBuffer *m_pCommandBuffer;
+	unsigned m_CurrentCommandBuffer;
+
+	//
+	class IStorage *m_pStorage;
+	class IConsole *m_pConsole;
+
+	CCommandBuffer::SVertex m_aVertices[MAX_VERTICES];
+	int m_NumVertices;
+
+	CCommandBuffer::SColor m_aColor[4];
+	CCommandBuffer::STexCoord m_aTexture[4];
+
+	bool m_RenderEnable;
+
+	float m_Rotation;
+	int m_Drawing;
+	bool m_DoScreenshot;
+	char m_aScreenshotName[128];
+
+	int m_InvalidTexture;
+
+	struct CTexture
+	{
+		int m_State;
+		int m_MemSize;
+		int m_Flags;
+		int m_Next;
+	};
+
+	CTexture m_aTextures[MAX_TEXTURES];
+	int m_FirstFreeTexture;
+	int m_TextureMemoryUsage;
+
+	void FlushVertices();
+	void AddVertices(int Count);
+	void Rotate4(const CCommandBuffer::SPoint &rCenter, CCommandBuffer::SVertex *pPoints);
+
+	static unsigned char Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp);
+	static unsigned char *Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData);
+
+	void KickCommandBuffer();
+
+	int IssueInit();
+	int InitWindow();
+public:
+	CGraphics_Threaded();
+
+	virtual void ClipEnable(int x, int y, int w, int h);
+	virtual void ClipDisable();
+
+	virtual void BlendNone();
+	virtual void BlendNormal();
+	virtual void BlendAdditive();
+
+	virtual void WrapNormal();
+	virtual void WrapClamp();
+
+	virtual int MemoryUsage() const;
+
+	virtual void MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY);
+	virtual void GetScreen(float *pTopLeftX, float *pTopLeftY, float *pBottomRightX, float *pBottomRightY);
+
+	virtual void LinesBegin();
+	virtual void LinesEnd();
+	virtual void LinesDraw(const CLineItem *pArray, int Num);
+
+	virtual int UnloadTexture(int Index);
+	virtual int LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags);
+	virtual int LoadTextureRawSub(int TextureID, int x, int y, int Width, int Height, int Format, const void *pData);
+
+	// simple uncompressed RGBA loaders
+	virtual int LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags);
+	virtual int LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType);
+
+	void ScreenshotDirect(const char *pFilename);
+
+	virtual void TextureSet(int TextureID);
+
+	virtual void Clear(float r, float g, float b);
+
+	virtual void QuadsBegin();
+	virtual void QuadsEnd();
+	virtual void QuadsSetRotation(float Angle);
+
+	virtual void SetColorVertex(const CColorVertex *pArray, int Num);
+	virtual void SetColor(float r, float g, float b, float a);
+
+	virtual void QuadsSetSubset(float TlU, float TlV, float BrU, float BrV);
+	virtual void QuadsSetSubsetFree(
+		float x0, float y0, float x1, float y1,
+		float x2, float y2, float x3, float y3);
+
+	virtual void QuadsDraw(CQuadItem *pArray, int Num);
+	virtual void QuadsDrawTL(const CQuadItem *pArray, int Num);
+	virtual void QuadsDrawFreeform(const CFreeformItem *pArray, int Num);
+	virtual void QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText);
+
+	virtual void Minimize();
+	virtual void Maximize();
+
+	virtual int WindowActive();
+	virtual int WindowOpen();
+
+	virtual int Init();
+	virtual void Shutdown();
+
+	virtual void TakeScreenshot(const char *pFilename);
+	virtual void Swap();
+
+	virtual int GetVideoModes(CVideoMode *pModes, int MaxModes);
+
+	// syncronization
+	virtual void InsertSignal(semaphore *pSemaphore);
+	virtual bool IsIdle();
+	virtual void WaitForIdle();
+};
+
+extern IGraphicsBackend *CreateGraphicsBackend();