mirror of
https://github.com/DrBeef/Raze.git
synced 2024-11-26 14:01:05 +00:00
51ad64f71e
This ensures that we have an immutable mapping of tile number to texture ID now.
361 lines
8.5 KiB
C++
361 lines
8.5 KiB
C++
#ifndef __2DDRAWER_H
|
|
#define __2DDRAWER_H
|
|
|
|
#include "buffers.h"
|
|
#include "tarray.h"
|
|
#include "vectors.h"
|
|
#include "textures.h"
|
|
#include "renderstyle.h"
|
|
#include "dobject.h"
|
|
#include "refcounted.h"
|
|
|
|
struct DrawParms;
|
|
struct FColormap;
|
|
struct IntRect;
|
|
|
|
class DShape2DTransform : public DObject
|
|
{
|
|
|
|
DECLARE_CLASS(DShape2DTransform, DObject)
|
|
public:
|
|
DShape2DTransform()
|
|
{
|
|
transform.Identity();
|
|
}
|
|
DMatrix3x3 transform;
|
|
};
|
|
|
|
// intermediate struct for shape drawing
|
|
|
|
enum EClearWhich
|
|
{
|
|
C_Verts = 1,
|
|
C_Coords = 2,
|
|
C_Indices = 4,
|
|
};
|
|
|
|
class F2DVertexBuffer;
|
|
|
|
struct F2DPolygons
|
|
{
|
|
TArray<FVector4> vertices;
|
|
TArray<int> indices;
|
|
|
|
unsigned AllocVertices(int num)
|
|
{
|
|
auto vindex = vertices.Reserve(num);
|
|
indices.Push(num);
|
|
return vindex;
|
|
}
|
|
|
|
};
|
|
|
|
class DShape2D;
|
|
struct DShape2DBufferInfo;
|
|
|
|
enum class SpecialDrawCommand {
|
|
NotSpecial,
|
|
|
|
EnableStencil,
|
|
SetStencil,
|
|
ClearStencil,
|
|
};
|
|
|
|
class F2DDrawer
|
|
{
|
|
public:
|
|
F2DDrawer() {
|
|
this->transform.Identity();
|
|
}
|
|
|
|
enum EDrawType : uint8_t
|
|
{
|
|
DrawTypeTriangles,
|
|
DrawTypeLines,
|
|
DrawTypePoints,
|
|
DrawTypeRotateSprite,
|
|
};
|
|
|
|
enum ETextureFlags : uint8_t
|
|
{
|
|
DTF_Wrap = 1,
|
|
DTF_Scissor = 2,
|
|
DTF_Burn = 4,
|
|
DTF_Indexed = 8,
|
|
};
|
|
|
|
|
|
// This vertex type is hardware independent and needs conversion when put into a buffer.
|
|
struct TwoDVertex
|
|
{
|
|
float x, y, z;
|
|
float u, v;
|
|
PalEntry color0;
|
|
|
|
void Set(float xx, float yy, float zz)
|
|
{
|
|
x = xx;
|
|
z = zz;
|
|
y = yy;
|
|
u = 0;
|
|
v = 0;
|
|
color0 = 0;
|
|
}
|
|
|
|
void Set(double xx, double yy, double zz, double uu, double vv, PalEntry col)
|
|
{
|
|
x = (float)xx;
|
|
z = (float)zz;
|
|
y = (float)yy;
|
|
u = (float)uu;
|
|
v = (float)vv;
|
|
color0 = col;
|
|
}
|
|
|
|
};
|
|
|
|
struct RenderCommand
|
|
{
|
|
SpecialDrawCommand isSpecial;
|
|
|
|
bool stencilOn;
|
|
|
|
int stencilOffs;
|
|
int stencilOp;
|
|
int stencilFlags;
|
|
|
|
EDrawType mType;
|
|
int mVertIndex;
|
|
int mVertCount;
|
|
int mIndexIndex;
|
|
int mIndexCount;
|
|
|
|
FGameTexture *mTexture;
|
|
int mTranslationId;
|
|
PalEntry mSpecialColormap[2];
|
|
int mScissor[4];
|
|
int mDesaturate;
|
|
FRenderStyle mRenderStyle;
|
|
PalEntry mColor1; // Overlay color
|
|
ETexMode mDrawMode;
|
|
uint8_t mLightLevel;
|
|
uint8_t mFlags;
|
|
float mScreenFade;
|
|
|
|
bool useTransform;
|
|
DMatrix3x3 transform;
|
|
|
|
RefCountedPtr<DShape2DBufferInfo> shape2DBufInfo;
|
|
int shape2DBufIndex;
|
|
int shape2DIndexCount;
|
|
int shape2DCommandCounter;
|
|
|
|
RenderCommand()
|
|
{
|
|
memset((void*)this, 0, sizeof(*this));
|
|
}
|
|
|
|
// If these fields match, two draw commands can be batched.
|
|
bool isCompatible(const RenderCommand &other) const
|
|
{
|
|
if (
|
|
isSpecial != SpecialDrawCommand::NotSpecial ||
|
|
other.isSpecial != SpecialDrawCommand::NotSpecial
|
|
) return false;
|
|
if (shape2DBufInfo != nullptr || other.shape2DBufInfo != nullptr) return false;
|
|
return mTexture == other.mTexture &&
|
|
mType == other.mType &&
|
|
mTranslationId == other.mTranslationId &&
|
|
mSpecialColormap[0].d == other.mSpecialColormap[0].d &&
|
|
mSpecialColormap[1].d == other.mSpecialColormap[1].d &&
|
|
!memcmp(mScissor, other.mScissor, sizeof(mScissor)) &&
|
|
mDesaturate == other.mDesaturate &&
|
|
mRenderStyle == other.mRenderStyle &&
|
|
mDrawMode == other.mDrawMode &&
|
|
mFlags == other.mFlags &&
|
|
mLightLevel == other.mLightLevel &&
|
|
mColor1.d == other.mColor1.d &&
|
|
useTransform == other.useTransform &&
|
|
mScreenFade == other.mScreenFade &&
|
|
(
|
|
!useTransform ||
|
|
(
|
|
transform[0] == other.transform[0] &&
|
|
transform[1] == other.transform[1] &&
|
|
transform[2] == other.transform[2]
|
|
)
|
|
);
|
|
}
|
|
};
|
|
|
|
TArray<int> mIndices;
|
|
TArray<TwoDVertex> mVertices;
|
|
TArray<RenderCommand> mData;
|
|
int Width, Height;
|
|
bool isIn2D;
|
|
bool locked = false; // prevents clearing of the data so it can be reused multiple times (useful for screen fades)
|
|
float screenFade = 1.f;
|
|
DVector2 offset;
|
|
DMatrix3x3 transform;
|
|
public:
|
|
int fullscreenautoaspect = 3;
|
|
int cliptop = -1, clipleft = -1, clipwidth = -1, clipheight = -1;
|
|
|
|
int AddCommand(RenderCommand *data);
|
|
void AddIndices(int firstvert, int count, ...);
|
|
private:
|
|
void AddIndices(int firstvert, TArray<int> &v);
|
|
bool SetStyle(FGameTexture *tex, DrawParms &parms, PalEntry &color0, RenderCommand &quad);
|
|
void SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcolor, PalEntry &overlaycolor);
|
|
|
|
public:
|
|
float GetClassicFlatScalarWidth();
|
|
float GetClassicFlatScalarHeight();
|
|
void AddTexture(FGameTexture* img, DrawParms& parms);
|
|
void AddShape(FGameTexture *img, DShape2D *shape, DrawParms &parms);
|
|
void AddPoly(FGameTexture *texture, FVector2 *points, int npoints,
|
|
double originx, double originy, double scalex, double scaley,
|
|
DAngle rotation, const FColormap &colormap, PalEntry flatcolor, double lightlevel, uint32_t *indices, size_t indexcount);
|
|
void AddPoly(FGameTexture* img, FVector4 *vt, size_t vtcount, const unsigned int *ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, const IntRect* clip);
|
|
void FillPolygon(int* rx1, int* ry1, int* xb1, int32_t npoints, int picnum, int palette, int shade, int props, const FVector2& xtex, const FVector2& ytex, const FVector2& otex,
|
|
int clipx1, int clipy1, int clipx2, int clipy2);
|
|
void AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, int local_origin = false, double flatscale = 1.0, PalEntry color = 0xffffffff, ERenderStyle rs = STYLE_Normal);
|
|
|
|
void AddColorOnlyQuad(int left, int top, int width, int height, PalEntry color, FRenderStyle *style = nullptr, bool prepend = false);
|
|
void ClearScreen(PalEntry color = 0xff000000);
|
|
void AddDim(PalEntry color, float damount, int x1, int y1, int w, int h);
|
|
void AddClear(int left, int top, int right, int bottom, int palcolor, uint32_t color);
|
|
|
|
|
|
void AddLine(const DVector2& v1, const DVector2& v2, const IntRect* clip, uint32_t color, uint8_t alpha = 255);
|
|
void AddThickLine(const DVector2& v1, const DVector2& v2, double thickness, uint32_t color, uint8_t alpha = 255);
|
|
void AddPixel(int x1, int y1, uint32_t color);
|
|
|
|
void AddEnableStencil(bool on);
|
|
void AddSetStencil(int offs, int op, int flags);
|
|
void AddClearStencil();
|
|
|
|
void Clear();
|
|
void Lock() { locked = true; }
|
|
void SetScreenFade(float factor) { screenFade = factor; }
|
|
void Unlock() { locked = false; }
|
|
int GetWidth() const { return Width; }
|
|
int GetHeight() const { return Height; }
|
|
void SetSize(int w, int h) { Width = w; Height = h; }
|
|
void Begin(int w, int h) { isIn2D = true; Width = w; Height = h; }
|
|
void End() { isIn2D = false; }
|
|
bool HasBegun2D() { return isIn2D; }
|
|
void OnFrameDone();
|
|
|
|
void ClearClipRect() { clipleft = cliptop = 0; clipwidth = clipheight = -1; }
|
|
void SetClipRect(int x, int y, int w, int h);
|
|
void GetClipRect(int* x, int* y, int* w, int* h);
|
|
|
|
DVector2 SetOffset(const DVector2& vec)
|
|
{
|
|
auto v = offset;
|
|
offset = vec;
|
|
return v;
|
|
}
|
|
|
|
void SetTransform(const DShape2DTransform& transform)
|
|
{
|
|
this->transform = transform.transform;
|
|
}
|
|
void ClearTransform()
|
|
{
|
|
this->transform.Identity();
|
|
}
|
|
|
|
int DrawCount() const
|
|
{
|
|
return mData.Size();
|
|
}
|
|
|
|
bool mIsFirstPass = true;
|
|
};
|
|
|
|
// DCanvas is already taken so using FCanvas instead.
|
|
class FCanvas : public DObject
|
|
{
|
|
DECLARE_CLASS(FCanvas, DObject)
|
|
public:
|
|
F2DDrawer Drawer;
|
|
FCanvasTexture* Tex = nullptr;
|
|
};
|
|
|
|
struct DShape2DBufferInfo : RefCountedBase
|
|
{
|
|
TArray<F2DVertexBuffer> buffers;
|
|
bool needsVertexUpload = true;
|
|
int bufIndex = -1;
|
|
int lastCommand = -1;
|
|
bool uploadedOnce = false;
|
|
};
|
|
|
|
class DShape2D : public DObject
|
|
{
|
|
|
|
DECLARE_CLASS(DShape2D,DObject)
|
|
public:
|
|
DShape2D()
|
|
: bufferInfo(new DShape2DBufferInfo)
|
|
{
|
|
transform.Identity();
|
|
}
|
|
|
|
TArray<int> mIndices;
|
|
TArray<DVector2> mVertices;
|
|
TArray<DVector2> mCoords;
|
|
|
|
double minx = 0.0;
|
|
double maxx = 0.0;
|
|
double miny = 0.0;
|
|
double maxy = 0.0;
|
|
|
|
DMatrix3x3 transform;
|
|
|
|
RefCountedPtr<DShape2DBufferInfo> bufferInfo;
|
|
|
|
DrawParms* lastParms;
|
|
|
|
void OnDestroy() override;
|
|
};
|
|
|
|
|
|
//===========================================================================
|
|
//
|
|
// Vertex buffer for 2D drawer
|
|
//
|
|
//===========================================================================
|
|
|
|
class F2DVertexBuffer
|
|
{
|
|
IVertexBuffer *mVertexBuffer;
|
|
IIndexBuffer *mIndexBuffer;
|
|
|
|
|
|
public:
|
|
|
|
F2DVertexBuffer();
|
|
|
|
~F2DVertexBuffer()
|
|
{
|
|
delete mIndexBuffer;
|
|
delete mVertexBuffer;
|
|
}
|
|
|
|
void UploadData(F2DDrawer::TwoDVertex *vertices, int vertcount, int *indices, int indexcount)
|
|
{
|
|
mVertexBuffer->SetData(vertcount * sizeof(*vertices), vertices, BufferUsageType::Stream);
|
|
mIndexBuffer->SetData(indexcount * sizeof(unsigned int), indices, BufferUsageType::Stream);
|
|
}
|
|
|
|
std::pair<IVertexBuffer *, IIndexBuffer *> GetBufferObjects() const
|
|
{
|
|
return std::make_pair(mVertexBuffer, mIndexBuffer);
|
|
}
|
|
};
|
|
|
|
|
|
#endif
|