qzdoom/src/win32/win32iface.h
Randy Heit bf31d66d31 Use a better packing algorithm for the texture atlases
- The old algorithm is something I threw together that produced decent,
  but not spectacular results since it had a tendency to waste space by
  forcing everything onto "shelves".
  The new packer is the Skyline-MinWaste-WasteMap-BestFirstFit algorithm
  described by Jukka Jylanki in his paper *A Thousand Ways to Pack the Bin - A
  Practical Approach to Two-Dimensional Rectangle Bin Packing*, which can
  currently be read at http://clb.demon.fi/files/RectangleBinPack.pdf
  This is minus the optimization to rotate rectangles to make better fits.
2016-01-08 22:37:06 -06:00

539 lines
16 KiB
C++

/*
** win32iface.h
**
**---------------------------------------------------------------------------
** Copyright 1998-2008 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#ifndef __WIN32IFACE_H
#define __WIN32IFACE_H
#ifndef DIRECTDRAW_VERSION
#define DIRECTDRAW_VERSION 0x0300
#endif
#ifndef DIRECT3D_VERSION
#define DIRECT3D_VERSION 0x0900
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <ddraw.h>
#include <d3d9.h>
#include "hardware.h"
#define SAFE_RELEASE(x) { if (x != NULL) { x->Release(); x = NULL; } }
EXTERN_CVAR (Bool, vid_vsync)
extern HANDLE FPSLimitEvent;
class D3DTex;
class D3DPal;
struct FSoftwareRenderer;
class Win32Video : public IVideo
{
public:
Win32Video (int parm);
~Win32Video ();
bool InitD3D9();
void InitDDraw();
EDisplayType GetDisplayType () { return DISPLAY_Both; }
void SetWindowedScale (float scale);
DFrameBuffer *CreateFrameBuffer (int width, int height, bool fs, DFrameBuffer *old);
void StartModeIterator (int bits, bool fs);
bool NextMode (int *width, int *height, bool *letterbox);
bool GoFullscreen (bool yes);
void BlankForGDI ();
void DumpAdapters ();
private:
struct ModeInfo
{
ModeInfo (int inX, int inY, int inBits, int inRealY, int inDoubling)
: next (NULL),
width (inX),
height (inY),
bits (inBits),
realheight (inRealY),
doubling (inDoubling)
{}
ModeInfo *next;
int width, height, bits;
int realheight;
int doubling;
} *m_Modes;
ModeInfo *m_IteratorMode;
int m_IteratorBits;
bool m_IteratorFS;
bool m_IsFullscreen;
UINT m_Adapter;
void AddMode (int x, int y, int bits, int baseHeight, int doubling);
void FreeModes ();
static HRESULT WINAPI EnumDDModesCB (LPDDSURFACEDESC desc, void *modes);
void AddD3DModes (UINT adapter, D3DFORMAT format);
void AddLowResModes ();
void AddLetterboxModes ();
void ScaleModes (int doubling);
friend class DDrawFB;
friend class D3DFB;
};
class BaseWinFB : public DFrameBuffer
{
DECLARE_ABSTRACT_CLASS(BaseWinFB, DFrameBuffer)
public:
BaseWinFB (int width, int height) : DFrameBuffer (width, height), Windowed (true) {}
bool IsFullscreen () { return !Windowed; }
virtual void Blank () = 0;
virtual bool PaintToWindow () = 0;
virtual HRESULT GetHR () = 0;
virtual void ScaleCoordsFromWindow(SWORD &x, SWORD &y);
protected:
virtual bool CreateResources () = 0;
virtual void ReleaseResources () = 0;
virtual int GetTrueHeight() { return GetHeight(); }
bool Windowed;
friend int I_PlayMovie (const char *name);
friend class Win32Video;
BaseWinFB() {}
};
class DDrawFB : public BaseWinFB
{
DECLARE_CLASS(DDrawFB, BaseWinFB)
public:
DDrawFB (int width, int height, bool fullscreen);
~DDrawFB ();
bool IsValid ();
bool Lock (bool buffer);
void Unlock ();
void ForceBuffering (bool force);
void Update ();
PalEntry *GetPalette ();
void GetFlashedPalette (PalEntry pal[256]);
void UpdatePalette ();
bool SetGamma (float gamma);
bool SetFlash (PalEntry rgb, int amount);
void GetFlash (PalEntry &rgb, int &amount);
int GetPageCount ();
int QueryNewPalette ();
void PaletteChanged ();
void SetVSync (bool vsync);
void NewRefreshRate();
HRESULT GetHR ();
bool Is8BitMode();
virtual int GetTrueHeight() { return TrueHeight; }
void Blank ();
bool PaintToWindow ();
private:
enum LockSurfRes { NoGood, Good, GoodWasLost };
bool CreateResources ();
void ReleaseResources ();
bool CreateSurfacesAttached ();
bool CreateSurfacesComplex ();
bool CreateBlitterSource ();
LockSurfRes LockSurf (LPRECT lockrect, LPDIRECTDRAWSURFACE surf);
void RebuildColorTable ();
void MaybeCreatePalette ();
bool AddBackBuf (LPDIRECTDRAWSURFACE *surface, int num);
HRESULT AttemptRestore ();
HRESULT LastHR;
BYTE GammaTable[3][256];
PalEntry SourcePalette[256];
PALETTEENTRY PalEntries[256];
DWORD FlipFlags;
LPDIRECTDRAWPALETTE Palette;
LPDIRECTDRAWSURFACE PrimarySurf;
LPDIRECTDRAWSURFACE BackSurf;
LPDIRECTDRAWSURFACE BackSurf2;
LPDIRECTDRAWSURFACE BlitSurf;
LPDIRECTDRAWSURFACE LockingSurf;
LPDIRECTDRAWCLIPPER Clipper;
HPALETTE GDIPalette;
DWORD ClipSize;
PalEntry Flash;
int FlashAmount;
int BufferCount;
int BufferPitch;
int TrueHeight;
int PixelDoubling;
float Gamma;
bool NeedGammaUpdate;
bool NeedPalUpdate;
bool NeedResRecreate;
bool PaletteChangeExpected;
bool MustBuffer; // The screen is not 8-bit, or there is no backbuffer
bool BufferingNow; // Most recent Lock was buffered
bool WasBuffering; // Second most recent Lock was buffered
bool Write8bit;
bool UpdatePending; // On final unlock, call Update()
bool UseBlitter; // Use blitter to copy from sys mem to video mem
bool UsePfx;
DDrawFB() {}
};
class D3DFB : public BaseWinFB
{
DECLARE_CLASS(D3DFB, BaseWinFB)
public:
D3DFB (UINT adapter, int width, int height, bool fullscreen);
~D3DFB ();
bool IsValid ();
bool Lock (bool buffered);
void Unlock ();
void Update ();
void Flip ();
PalEntry *GetPalette ();
void GetFlashedPalette (PalEntry palette[256]);
void UpdatePalette ();
bool SetGamma (float gamma);
bool SetFlash (PalEntry rgb, int amount);
void GetFlash (PalEntry &rgb, int &amount);
int GetPageCount ();
bool IsFullscreen ();
void PaletteChanged ();
int QueryNewPalette ();
void Blank ();
bool PaintToWindow ();
void SetVSync (bool vsync);
void NewRefreshRate();
void GetScreenshotBuffer(const BYTE *&buffer, int &pitch, ESSType &color_type);
void ReleaseScreenshotBuffer();
void SetBlendingRect (int x1, int y1, int x2, int y2);
bool Begin2D (bool copy3d);
void DrawBlendingRect ();
FNativeTexture *CreateTexture (FTexture *gametex, bool wrapping);
FNativePalette *CreatePalette (FRemapTable *remap);
void STACK_ARGS DrawTextureV (FTexture *img, double x, double y, uint32 tag, va_list tags);
void Clear (int left, int top, int right, int bottom, int palcolor, uint32 color);
void Dim (PalEntry color, float amount, int x1, int y1, int w, int h);
void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin);
void DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32 realcolor);
void DrawPixel(int x, int y, int palcolor, uint32 rgbcolor);
void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
angle_t rotation, FDynamicColormap *colormap, int lightlevel);
bool WipeStartScreen(int type);
void WipeEndScreen();
bool WipeDo(int ticks);
void WipeCleanup();
HRESULT GetHR ();
bool Is8BitMode() { return false; }
virtual int GetTrueHeight() { return TrueHeight; }
private:
friend class D3DTex;
friend class D3DPal;
struct PackedTexture;
struct Atlas;
struct FBVERTEX
{
FLOAT x, y, z, rhw;
D3DCOLOR color0, color1;
FLOAT tu, tv;
};
#define D3DFVF_FBVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1)
struct BufferedTris
{
union
{
struct
{
BYTE Flags;
BYTE ShaderNum:4;
BYTE BlendOp:4;
BYTE SrcBlend, DestBlend;
};
DWORD Group1;
};
BYTE Desat;
D3DPal *Palette;
IDirect3DTexture9 *Texture;
WORD NumVerts; // Number of _unique_ vertices used by this set.
WORD NumTris; // Number of triangles used by this set.
};
enum
{
PSCONST_Desaturation = 1,
PSCONST_PaletteMod = 2,
PSCONST_Weights = 6,
PSCONST_Gamma = 7,
};
enum
{
SHADER_NormalColor,
SHADER_NormalColorPal,
SHADER_NormalColorInv,
SHADER_NormalColorPalInv,
SHADER_RedToAlpha,
SHADER_RedToAlphaInv,
SHADER_VertexColor,
SHADER_SpecialColormap,
SHADER_SpecialColormapPal,
SHADER_InGameColormap,
SHADER_InGameColormapDesat,
SHADER_InGameColormapInv,
SHADER_InGameColormapInvDesat,
SHADER_InGameColormapPal,
SHADER_InGameColormapPalDesat,
SHADER_InGameColormapPalInv,
SHADER_InGameColormapPalInvDesat,
SHADER_BurnWipe,
SHADER_GammaCorrection,
NUM_SHADERS
};
static const char *const ShaderNames[NUM_SHADERS];
void SetInitialState();
bool CreateResources();
void ReleaseResources();
bool LoadShaders();
void CreateBlockSurfaces();
bool CreateFBTexture();
bool CreatePaletteTexture();
bool CreateGammaTexture();
bool CreateVertexes();
void DoOffByOneCheck();
void UploadPalette();
void UpdateGammaTexture(float igamma);
void FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, bool vsync);
void CalcFullscreenCoords (FBVERTEX verts[4], bool viewarea_only, bool can_double, D3DCOLOR color0, D3DCOLOR color1) const;
bool Reset();
IDirect3DTexture9 *GetCurrentScreen(D3DPOOL pool=D3DPOOL_SYSTEMMEM);
void ReleaseDefaultPoolItems();
void KillNativePals();
void KillNativeTexs();
PackedTexture *AllocPackedTexture(int width, int height, bool wrapping, D3DFORMAT format);
void DrawPackedTextures(int packnum);
void DrawLetterbox();
void Draw3DPart(bool copy3d);
bool SetStyle(D3DTex *tex, DCanvas::DrawParms &parms, D3DCOLOR &color0, D3DCOLOR &color1, BufferedTris &quad);
static D3DBLEND GetStyleAlpha(int type);
static void SetColorOverlay(DWORD color, float alpha, D3DCOLOR &color0, D3DCOLOR &color1);
void DoWindowedGamma();
void AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR color);
void AddColorOnlyRect(int left, int top, int width, int height, D3DCOLOR color);
void CheckQuadBatch(int numtris=2, int numverts=4);
void BeginQuadBatch();
void EndQuadBatch();
void BeginLineBatch();
void EndLineBatch();
void EndBatch();
void CopyNextFrontBuffer();
D3DCAPS9 DeviceCaps;
// State
void EnableAlphaTest(BOOL enabled);
void SetAlphaBlend(D3DBLENDOP op, D3DBLEND srcblend=D3DBLEND(0), D3DBLEND destblend=D3DBLEND(0));
void SetConstant(int cnum, float r, float g, float b, float a);
void SetPixelShader(IDirect3DPixelShader9 *shader);
void SetTexture(int tnum, IDirect3DTexture9 *texture);
void SetPaletteTexture(IDirect3DTexture9 *texture, int count, D3DCOLOR border_color);
void SetPalTexBilinearConstants(Atlas *texture);
BOOL AlphaTestEnabled;
BOOL AlphaBlendEnabled;
D3DBLENDOP AlphaBlendOp;
D3DBLEND AlphaSrcBlend;
D3DBLEND AlphaDestBlend;
float Constant[3][4];
D3DCOLOR CurBorderColor;
IDirect3DPixelShader9 *CurPixelShader;
IDirect3DTexture9 *Texture[5];
PalEntry SourcePalette[256];
D3DCOLOR BorderColor;
D3DCOLOR FlashColor0, FlashColor1;
PalEntry FlashColor;
int FlashAmount;
int TrueHeight;
int PixelDoubling;
int SkipAt;
int LBOffsetI;
int RenderTextureToggle;
int CurrRenderTexture;
float LBOffset;
float Gamma;
bool UpdatePending;
bool NeedPalUpdate;
bool NeedGammaUpdate;
int FBWidth, FBHeight;
bool VSync;
RECT BlendingRect;
int In2D;
bool InScene;
bool SM14;
bool GatheringWipeScreen;
bool AALines;
BYTE BlockNum;
D3DPal *Palettes;
D3DTex *Textures;
Atlas *Atlases;
HRESULT LastHR;
UINT Adapter;
IDirect3DDevice9 *D3DDevice;
IDirect3DTexture9 *FBTexture;
IDirect3DTexture9 *TempRenderTexture, *RenderTexture[2];
IDirect3DTexture9 *PaletteTexture;
IDirect3DTexture9 *GammaTexture;
IDirect3DTexture9 *ScreenshotTexture;
IDirect3DSurface9 *ScreenshotSurface;
IDirect3DSurface9 *FrontCopySurface;
IDirect3DVertexBuffer9 *VertexBuffer;
FBVERTEX *VertexData;
IDirect3DIndexBuffer9 *IndexBuffer;
WORD *IndexData;
BufferedTris *QuadExtra;
int VertexPos;
int IndexPos;
int QuadBatchPos;
enum { BATCH_None, BATCH_Quads, BATCH_Lines } BatchType;
IDirect3DPixelShader9 *Shaders[NUM_SHADERS];
IDirect3DPixelShader9 *GammaShader;
IDirect3DSurface9 *BlockSurface[2];
IDirect3DSurface9 *OldRenderTarget;
IDirect3DTexture9 *InitialWipeScreen, *FinalWipeScreen;
D3DFB() {}
class Wiper
{
public:
virtual ~Wiper();
virtual bool Run(int ticks, D3DFB *fb) = 0;
void DrawScreen(D3DFB *fb, IDirect3DTexture9 *tex,
D3DBLENDOP blendop=D3DBLENDOP(0), D3DCOLOR color0=0, D3DCOLOR color1=0xFFFFFFF);
};
class Wiper_Melt; friend class Wiper_Melt;
class Wiper_Burn; friend class Wiper_Burn;
class Wiper_Crossfade; friend class Wiper_Crossfade;
Wiper *ScreenWipe;
};
// Flags for a buffered quad
enum
{
BQF_GamePalette = 1,
BQF_CustomPalette = 7,
BQF_Paletted = 7,
BQF_Bilinear = 8,
BQF_WrapUV = 16,
BQF_InvertSource = 32,
BQF_DisableAlphaTest= 64,
BQF_Desaturated = 128,
};
// Shaders for a buffered quad
enum
{
BQS_PalTex,
BQS_Plain,
BQS_RedToAlpha,
BQS_ColorOnly,
BQS_SpecialColormap,
BQS_InGameColormap,
};
#if 0
#define STARTLOG do { if (!dbg) dbg = fopen ("e:/vid.log", "w"); } while(0)
#define STOPLOG do { if (dbg) { fclose (dbg); dbg=NULL; } } while(0)
#define LOG(x) do { if (dbg) { fprintf (dbg, x); fflush (dbg); } } while(0)
#define LOG1(x,y) do { if (dbg) { fprintf (dbg, x, y); fflush (dbg); } } while(0)
#define LOG2(x,y,z) do { if (dbg) { fprintf (dbg, x, y, z); fflush (dbg); } } while(0)
#define LOG3(x,y,z,zz) do { if (dbg) { fprintf (dbg, x, y, z, zz); fflush (dbg); } } while(0)
#define LOG4(x,y,z,a,b) do { if (dbg) { fprintf (dbg, x, y, z, a, b); fflush (dbg); } } while(0)
#define LOG5(x,y,z,a,b,c) do { if (dbg) { fprintf (dbg, x, y, z, a, b, c); fflush (dbg); } } while(0)
extern FILE *dbg;
#define VID_FILE_DEBUG 1
#elif _DEBUG && 0
#define STARTLOG
#define STOPLOG
#define LOG(x) { OutputDebugString(x); }
#define LOG1(x,y) { char poo[1024]; mysnprintf(poo, countof(poo), x, y); OutputDebugString(poo); }
#define LOG2(x,y,z) { char poo[1024]; mysnprintf(poo, countof(poo), x, y, z); OutputDebugString(poo); }
#define LOG3(x,y,z,zz) { char poo[1024]; mysnprintf(poo, countof(poo), x, y, z, zz); OutputDebugString(poo); }
#define LOG4(x,y,z,a,b) { char poo[1024]; mysnprintf(poo, countof(poo), x, y, z, a, b); OutputDebugString(poo); }
#define LOG5(x,y,z,a,b,c) { char poo[1024]; mysnprintf(poo, countof(poo), x, y, z, a, b, c); OutputDebugString(poo); }
#else
#define STARTLOG
#define STOPLOG
#define LOG(x)
#define LOG1(x,y)
#define LOG2(x,y,z)
#define LOG3(x,y,z,zz)
#define LOG4(x,y,z,a,b)
#define LOG5(x,y,z,a,b,c)
#endif
#endif // __WIN32IFACE_H