1/*
2 * LegacyClonk
3 *
4 * Copyright (c) RedWolf Design
5 * Copyright (c) 2001, Sven2
6 * Copyright (c) 2017-2021, The LegacyClonk Team and contributors
7 *
8 * Distributed under the terms of the ISC license; see accompanying file
9 * "COPYING" for details.
10 *
11 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12 * See accompanying file "TRADEMARK" for details.
13 *
14 * To redistribute this file separately, substitute the full license texts
15 * for the above references.
16 */
17
18/* A wrapper class to DirectDraw */
19
20#pragma once
21
22#include "C4Log.h"
23#include <C4Surface.h>
24#include <StdSurface8.h>
25#include <StdBuf.h>
26
27#include <array>
28#include <unordered_map>
29#include <vector>
30
31// texref-predef
32class CStdDDraw;
33class C4TexRef;
34class C4Surface;
35struct CStdPalette;
36class CStdGLCtx;
37class CStdApp;
38class CStdWindow;
39class CStdFont;
40class CMarkup;
41
42// engines
43#define GFXENGN_OPENGL 0
44#define GFXENGN_NOGFX 3
45
46// Global DDraw access pointer
47extern CStdDDraw *lpDDraw;
48extern CStdPalette *lpDDrawPal;
49
50extern int iGfxEngine;
51
52// rotation info class
53class CBltTransform
54{
55public:
56 float mat[9]; // transformation matrix
57
58public:
59 CBltTransform() {} // default: don't init fields
60
61 void Set(float fA, float fB, float fC, float fD, float fE, float fF, float fG, float fH, float fI)
62 {
63 mat[0] = fA; mat[1] = fB; mat[2] = fC; mat[3] = fD; mat[4] = fE; mat[5] = fF; mat[6] = fG; mat[7] = fH; mat[8] = fI;
64 }
65
66 void SetRotate(int iAngle, float fOffX, float fOffY); // set by angle and rotation offset
67 bool SetAsInv(CBltTransform &rOfTransform);
68
69 void Rotate(int iAngle, float fOffX, float fOffY) // rotate by angle around rotation offset
70 {
71 // multiply matrix as seen in SetRotate by own matrix
72 CBltTransform rot; rot.SetRotate(iAngle, fOffX, fOffY);
73 (*this) *= rot;
74 }
75
76 void SetMoveScale(float dx, float dy, float sx, float sy)
77 {
78 mat[0] = sx; mat[1] = 0; mat[2] = dx;
79 mat[3] = 0; mat[4] = sy; mat[5] = dy;
80 mat[6] = 0; mat[7] = 0; mat[8] = 1;
81 }
82
83 void MoveScale(float dx, float dy, float sx, float sy)
84 {
85 // multiply matrix by movescale matrix
86 CBltTransform move; move.SetMoveScale(dx, dy, sx, sy);
87 (*this) *= move;
88 }
89
90 void ScaleAt(float sx, float sy, float tx, float ty)
91 {
92 // scale and move back so tx and ty remain fixpoints
93 MoveScale(dx: -tx * (sx - 1), dy: -ty * (sy - 1), sx, sy);
94 }
95
96 CBltTransform &operator*=(CBltTransform &r)
97 {
98 // transform transformation
99 Set(
100 fA: mat[0] * r.mat[0] + mat[3] * r.mat[1] + mat[6] * r.mat[2],
101 fB: mat[1] * r.mat[0] + mat[4] * r.mat[1] + mat[7] * r.mat[2],
102 fC: mat[2] * r.mat[0] + mat[5] * r.mat[1] + mat[8] * r.mat[2],
103 fD: mat[0] * r.mat[3] + mat[3] * r.mat[4] + mat[6] * r.mat[5],
104 fE: mat[1] * r.mat[3] + mat[4] * r.mat[4] + mat[7] * r.mat[5],
105 fF: mat[2] * r.mat[3] + mat[5] * r.mat[4] + mat[8] * r.mat[5],
106 fG: mat[0] * r.mat[6] + mat[3] * r.mat[7] + mat[6] * r.mat[8],
107 fH: mat[1] * r.mat[6] + mat[4] * r.mat[7] + mat[7] * r.mat[8],
108 fI: mat[2] * r.mat[6] + mat[5] * r.mat[7] + mat[8] * r.mat[8]);
109 return *this;
110 }
111
112 void TransformPoint(float &rX, float &rY); // rotate point by angle
113};
114
115// pattern
116class CPattern
117{
118private:
119 // pattern surface for new-style patterns
120 class C4Surface *sfcPattern32;
121 class CSurface8 *sfcPattern8;
122 // Faster access
123 uint32_t *CachedPattern; int Wdt; int Hgt;
124 // pattern zoom factor; 0 means no zoom
125 int Zoom;
126 // pattern is to be applied monochromatic
127 bool Monochrome;
128 // color array for old-style patterns
129 uint32_t *pClrs;
130 // alpha array for old-style patterns
131 uint32_t *pAlpha;
132
133public:
134 CPattern &operator=(const CPattern &);
135 bool PatternClr(int iX, int iY, uint8_t &byClr, uint32_t &dwClr, CStdPalette &rPal) const; // apply pattern to color
136 bool Set(class C4Surface *sfcSource, int iZoom = 0, bool fMonochrome = false); // set and enable pattern
137 bool Set(class CSurface8 *sfcSource, int iZoom = 0, bool fMonochrome = false); // set and enable pattern
138 void SetColors(uint32_t *pClrs, uint32_t *pAlpha) { this->pClrs = pClrs; this->pAlpha = pAlpha; } // set color triplet for old-style textures
139 void SetZoom(int iZoom) { Zoom = iZoom; }
140 void Clear(); // clear pattern
141 CPattern();
142 ~CPattern() { Clear(); }
143};
144
145// blit position on screen
146struct CBltVertex
147{
148 float ftx, fty; // blit positions
149 uint32_t dwModClr; // color modulation
150};
151
152// blit data
153struct CBltData
154{
155 std::array<CBltVertex, 4> vtVtx; // vertices for polygon
156 CBltTransform TexPos; // texture mapping matrix
157 CBltTransform *pTransform; // Vertex transformation
158};
159
160// gamma ramp control
161class CGammaControl
162{
163private:
164 void SetClrChannel(uint16_t *pBuf, uint8_t c1, uint8_t c2, int c3, uint16_t *ref); // set color channel ramp
165
166protected:
167 uint16_t *red, *green, *blue; int size;
168
169public:
170 CGammaControl() : red(nullptr), green(nullptr), blue(nullptr), size(0) { Default(); }
171 ~CGammaControl();
172 void Default() { Set(dwClr1: 0x000000, dwClr2: 0x808080, dwClr3: 0xffffff, size: 256, ref: nullptr); } // set default ramp
173
174 void Set(uint32_t dwClr1, uint32_t dwClr2, uint32_t dwClr3, int size, CGammaControl *ref); // set color ramp
175 int GetSize() const;
176
177 uint32_t ApplyTo(uint32_t dwClr); // apply gamma to color value
178
179 friend class CStdDDraw;
180 friend class CStdGL;
181};
182
183class CStdRenderException : public std::runtime_error
184{
185public:
186 using std::runtime_error::runtime_error;
187};
188
189class CStdShader
190{
191public:
192 enum class Type : uint8_t
193 {
194 Vertex,
195 TesselationControl,
196 TesselationEvaluation,
197 Geometry,
198 Fragment
199 };
200
201 class Exception : public CStdRenderException
202 {
203 public:
204 using CStdRenderException::CStdRenderException;
205 };
206
207public:
208 CStdShader() = default;
209 explicit CStdShader(Type type, const std::string &source) : type{type}, source{source} {}
210 CStdShader(const CStdShader &) = delete;
211
212 virtual ~CStdShader() { Clear(); }
213
214 void SetMacro(const std::string &key, const std::string &value);
215 void UnsetMacro(const std::string &key);
216 void SetSource(const std::string &source);
217 void SetType(Type type);
218
219 virtual void Compile() = 0;
220 virtual void Clear();
221
222 std::string GetSource() const { return source; }
223 virtual int64_t GetHandle() const = 0;
224 std::unordered_map<std::string, std::string> GetMacros() const { return macros; }
225 virtual Type GetType() const { return type; }
226
227protected:
228 Type type;
229 std::string source;
230 std::unordered_map<std::string, std::string> macros;
231};
232
233class CStdShaderProgram
234{
235public:
236 class Exception : public CStdRenderException
237 {
238 public:
239 using CStdRenderException::CStdRenderException;
240 };
241
242public:
243 CStdShaderProgram() = default;
244 CStdShaderProgram(const CStdShaderProgram &) = delete;
245 virtual ~CStdShaderProgram() { Clear(); }
246
247 virtual explicit operator bool() const = 0;
248
249 bool AddShader(CStdShader *shader);
250
251 virtual void Link() = 0;
252 virtual void Validate() = 0;
253 void Select();
254 static void Deselect();
255 virtual void Clear();
256
257 virtual void EnsureProgram() = 0;
258 virtual int64_t GetProgram() const = 0;
259
260 std::vector<CStdShader *> GetPendingShaders() const { return shaders; }
261 static CStdShaderProgram *GetCurrentShaderProgram();
262
263protected:
264 virtual bool AddShaderInt(CStdShader *shader) = 0;
265 virtual void OnSelect() = 0;
266 virtual void OnDeselect() = 0;
267
268protected:
269 std::vector<CStdShader *> shaders;
270 static CStdShaderProgram *currentShaderProgram;
271};
272
273// direct draw encapsulation
274class CStdDDraw
275{
276public:
277 CStdDDraw() { lpDDrawPal = &Pal; }
278 virtual ~CStdDDraw() { lpDDraw = nullptr; }
279
280public:
281 CStdApp *pApp; // the application
282 C4Surface *lpPrimary; // primary and back surface (emulation...)
283 C4Surface *lpBack;
284 CStdPalette Pal; // 8bit-pal
285 bool Active; // set if device is ready to render, etc.
286 CGammaControl Gamma; // gamma
287 CGammaControl DefRamp; // default gamma ramp
288
289protected:
290 std::shared_ptr<spdlog::logger> logger;
291 int ClipX1, ClipY1, ClipX2, ClipY2;
292 int StClipX1, StClipY1, StClipX2, StClipY2;
293 bool ClipAll; // set if clipper clips everything away
294 C4Surface *RenderTarget; // current render target
295 bool BlitModulated; // set if blits should be modulated with BlitModulateClr
296 uint32_t BlitModulateClr; // modulation color for blitting
297 uint32_t dwBlitMode; // extra flags for blit
298 CClrModAddMap *pClrModMap; // map to be used for global color modulation (invalid if !fUseClrModMap)
299 bool fUseClrModMap; // if set, pClrModMap will be checked for color modulations
300 float texIndent;
301 float blitOffset;
302
303public:
304 // General
305 bool Init(CStdApp *pApp, C4LogSystem &logSystem);
306 virtual void Clear();
307 virtual void Default();
308 virtual CStdGLCtx *CreateContext(CStdWindow *, CStdApp *) { return nullptr; }
309#ifdef _WIN32
310 virtual CStdGLCtx *CreateContext(HWND, CStdApp *) { return nullptr; }
311#endif
312 virtual void PageFlip() = 0;
313 virtual int GetEngine() = 0; // get indexed engine
314 virtual std::string_view GetEngineName() const = 0;
315 virtual bool OnResolutionChanged() = 0; // reinit window for new resolution
316
317 // Palette
318 bool SetPrimaryPalette(uint8_t *pBuf, uint8_t *pAlphaBuf = nullptr);
319 bool AttachPrimaryPalette(C4Surface *sfcSurface);
320
321 // Clipper
322 bool GetPrimaryClipper(int &rX1, int &rY1, int &rX2, int &rY2);
323 bool SetPrimaryClipper(int iX1, int iY1, int iX2, int iY2);
324 bool SubPrimaryClipper(int iX1, int iY1, int iX2, int iY2);
325 bool StorePrimaryClipper();
326 bool RestorePrimaryClipper();
327 bool NoPrimaryClipper();
328 virtual bool UpdateClipper() = 0; // set current clipper to render target
329
330 // Surface
331 bool GetSurfaceSize(C4Surface *sfcSurface, int &iWdt, int &iHgt);
332 bool WipeSurface(C4Surface *sfcSurface);
333 void SurfaceAllowColor(C4Surface *sfcSfc, uint32_t *pdwColors, int iNumColors, bool fAllowZero = false);
334 void Grayscale(C4Surface *sfcSfc, int32_t iOffset = 0);
335 virtual bool PrepareRendering(C4Surface *sfcToSurface) = 0; // check if/make rendering possible to given surface
336
337 // Blit
338 virtual void BlitLandscape(C4Surface *sfcSource, C4Surface *sfcSource2, C4Surface *sfcLiquidAnimation, int fx, int fy,
339 C4Surface *sfcTarget, int tx, int ty, int wdt, int hgt);
340 void Blit8Fast(CSurface8 *sfcSource, int fx, int fy,
341 C4Surface *sfcTarget, int tx, int ty, int wdt, int hgt);
342 bool Blit(C4Surface *sfcSource, float fx, float fy, float fwdt, float fhgt,
343 C4Surface *sfcTarget, int tx, int ty, int twdt, int thgt,
344 bool fSrcColKey = false, CBltTransform *pTransform = nullptr, bool noScalingCorrection = false);
345 bool Blit(C4Surface *sfcSource, float fx, float fy, float fwdt, float fhgt,
346 C4Surface *sfcTarget, float tx, float ty, float twdt, float thgt,
347 bool fSrcColKey = false, CBltTransform *pTransform = nullptr, bool noScalingCorrection = false);
348 virtual void PerformBlt(CBltData &rBltData, C4TexRef *pTex, uint32_t dwModClr, bool fMod2, bool fExact) = 0;
349 bool Blit8(C4Surface *sfcSource, int fx, int fy, int fwdt, int fhgt, // force 8bit-blit (inline)
350 C4Surface *sfcTarget, int tx, int ty, int twdt, int thgt,
351 bool fSrcColKey = false, CBltTransform *pTransform = nullptr);
352 bool BlitRotate(C4Surface *sfcSource, int fx, int fy, int fwdt, int fhgt,
353 C4Surface *sfcTarget, int tx, int ty, int twdt, int thgt,
354 int iAngle, bool fTransparency = true);
355 bool BlitSurface(C4Surface *sfcSurface, C4Surface *sfcTarget, int tx, int ty, bool fBlitBase);
356 bool BlitSurfaceTile(C4Surface *sfcSurface, C4Surface *sfcTarget, int iToX, int iToY, int iToWdt, int iToHgt, int iOffsetX = 0, int iOffsetY = 0, bool fSrcColKey = false, float scale = 1.f);
357 bool BlitSurfaceTile2(C4Surface *sfcSurface, C4Surface *sfcTarget, int iToX, int iToY, int iToWdt, int iToHgt, int iOffsetX = 0, int iOffsetY = 0, bool fSrcColKey = false);
358 virtual void FillBG(uint32_t dwClr = 0) = 0;
359
360 // Text
361 enum { DEFAULT_MESSAGE_COLOR = 0xffffffff };
362 bool TextOut(const char *szText, CStdFont &rFont, float fZoom, C4Surface *sfcDest, int iTx, int iTy, uint32_t dwFCol = 0xffffffff, uint8_t byForm = ALeft, bool fDoMarkup = true);
363 bool StringOut(const char *szText, CStdFont &rFont, float fZoom, C4Surface *sfcDest, int iTx, int iTy, uint32_t dwFCol = 0xffffffff, uint8_t byForm = ALeft, bool fDoMarkup = true);
364
365 // Drawing
366 virtual void DrawPix(C4Surface *sfcDest, float tx, float ty, uint32_t dwCol);
367 void DrawBox(C4Surface *sfcDest, int iX1, int iY1, int iX2, int iY2, uint8_t byCol); // calls DrawBoxDw
368 void DrawBoxDw(C4Surface *sfcDest, int iX1, int iY1, int iX2, int iY2, uint32_t dwClr); // calls DrawBoxFade
369 void DrawBoxFade(C4Surface *sfcDest, int iX, int iY, int iWdt, int iHgt, uint32_t dwClr1, uint32_t dwClr2, uint32_t dwClr3, uint32_t dwClr4, int iBoxOffX, int iBoxOffY); // calls DrawQuadDw
370 void DrawPatternedCircle(C4Surface *sfcDest, int x, int y, int r, uint8_t col, CPattern &Pattern1, CPattern &Pattern2, CStdPalette &rPal);
371 void DrawHorizontalLine(C4Surface *sfcDest, int x1, int x2, int y, uint8_t col);
372 void DrawVerticalLine(C4Surface *sfcDest, int x, int y1, int y2, uint8_t col);
373 void DrawFrame(C4Surface *sfcDest, int x1, int y1, int x2, int y2, uint8_t col);
374 void DrawFrameDw(C4Surface *sfcDest, int x1, int y1, int x2, int y2, uint32_t dwClr);
375
376 virtual void DrawLine(C4Surface *sfcTarget, int x1, int y1, int x2, int y2, uint8_t byCol)
377 {
378 DrawLineDw(sfcTarget, x1: static_cast<float>(x1), y1: static_cast<float>(y1), x2: static_cast<float>(x2), y2: static_cast<float>(y2), dwClr: Pal.GetClr(byCol));
379 }
380
381 virtual void DrawLineDw(C4Surface *sfcTarget, float x1, float y1, float x2, float y2, uint32_t dwClr) = 0;
382 virtual void DrawQuadDw(C4Surface *sfcTarget, int *ipVtx, uint32_t dwClr1, uint32_t dwClr2, uint32_t dwClr3, uint32_t dwClr4) = 0;
383
384 // gamma
385 void SetGamma(uint32_t dwClr1, uint32_t dwClr2, uint32_t dwClr3); // set gamma ramp
386 virtual void DisableGamma(); // reset gamma ramp to default
387 virtual void EnableGamma(); // set current gamma ramp
388 uint32_t ApplyGammaTo(uint32_t dwClr); // apply gamma to given color
389 virtual bool ApplyGammaRamp(CGammaControl &ramp, bool fForce) = 0; // really apply gamma ramp
390 virtual bool SaveDefaultGammaRamp(CStdWindow *pWindow) = 0;
391
392 // blit states
393 void ActivateBlitModulation(uint32_t dwWithClr) { BlitModulated = true; BlitModulateClr = dwWithClr; } // modulate following blits with a given color
394 void DeactivateBlitModulation() { BlitModulated = false; } // stop color modulation of blits
395 bool GetBlitModulation(uint32_t &rdwColor) { rdwColor = BlitModulateClr; return BlitModulated; }
396 void SetBlitMode(uint32_t dwBlitMode); // set blit mode extra flags (additive blits, mod2-modulation, etc.)
397 void ResetBlitMode() { dwBlitMode = 0; }
398
399 void ClrByCurrentBlitMod(uint32_t &rdwClr)
400 {
401 // apply modulation if activated
402 if (BlitModulated) ModulateClr(dst&: rdwClr, src: BlitModulateClr);
403 }
404
405 void SetClrModMap(CClrModAddMap *pClrModMap) { this->pClrModMap = pClrModMap; }
406 void SetClrModMapEnabled(bool fToVal) { fUseClrModMap = fToVal; }
407 bool GetClrModMapEnabled() const { return fUseClrModMap; }
408 virtual void SetTexture() = 0;
409 virtual void ResetTexture() = 0;
410
411 // device objects
412 virtual bool RestoreDeviceObjects() = 0; // init/restore device dependent objects
413 virtual bool InvalidateDeviceObjects() = 0; // free device dependent objects
414 virtual bool DeviceReady() = 0; // return whether device exists
415
416protected:
417 bool StringOut(const char *szText, C4Surface *sfcDest, int iTx, int iTy, uint32_t dwFCol, uint8_t byForm, bool fDoMarkup, CMarkup &Markup, CStdFont *pFont, float fZoom);
418 virtual void DrawPixInt(C4Surface *sfcDest, float tx, float ty, uint32_t dwCol) = 0; // without ClrModMap
419 bool CreatePrimaryClipper();
420 virtual bool CreatePrimarySurfaces() = 0;
421 virtual bool CreateDirectDraw() = 0;
422 bool CalculateClipper(int *iX, int *iY, int *iWdt, int *iHgt);
423
424 friend class C4Surface;
425 friend class C4TexRef;
426 friend class CPattern;
427};
428
429C4LOGGERCONFIG_NAME_TYPE(CStdDDraw);
430
431CStdDDraw *DDrawInit(CStdApp *pApp, C4LogSystem &logSystem, int Engine);
432