1 /* GemRB - Infinity Engine Emulator
2  * Copyright (C) 2003 The GemRB Project
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  *
19  */
20 
21 /**
22  * @file Video.h
23  * Declares Video, base class for video output plugins.
24  * @author The GemRB Project
25  */
26 
27 #ifndef VIDEO_H
28 #define VIDEO_H
29 
30 #include "globals.h"
31 
32 #include "EnumFlags.h"
33 #include "Plugin.h"
34 #include "Polygon.h"
35 #include "Sprite2D.h"
36 
37 #include <deque>
38 #include <algorithm>
39 
40 namespace GemRB {
41 
42 class EventMgr;
43 class Palette;
44 using PaletteHolder = Holder<Palette>;
45 
46 // Note: not all these flags make sense together.
47 // Specifically: BlitFlags::GREY overrides BlitFlags::SEPIA
48 enum BlitFlags : uint32_t {
49 	NONE = 0,
50 	HALFTRANS = 2, // IE_VVC_TRANSPARENT
51 	BLENDED = 8, // IE_VVC_BLENDED, not implemented in SDLVideo yet
52 	MIRRORX = 0x10, // IE_VVC_MIRRORX
53 	MIRRORY = 0x20, // IE_VVC_MIRRORY
54 	// IE_VVC_TINT = 0x00030000. which is (BlitFlags::COLOR_MOD | BlitFlags::ALPHA_MOD)
55 	COLOR_MOD = 0x00010000, // srcC = srcC * (color / 255)
56 	ALPHA_MOD = 0x00020000, // srcA = srcA * (alpha / 255)
57 	GREY = 0x80000, // IE_VVC_GREYSCALE, timestop palette
58 	SEPIA = 0x02000000, // IE_VVC_SEPIA, dream scene palette
59 	MULTIPLY = 0x00100000, // IE_VVC_DARKEN, not implemented in SDLVideo yet
60 	GLOW = 0x00200000, // IE_VVC_GLOWING, not implemented in SDLVideo yet
61 	ADD = 0x00400000,
62 	STENCIL_ALPHA = 0x00800000, // blend with the stencil buffer using the stencil's alpha channel as the stencil
63 	STENCIL_RED = 0x01000000, // blend with the stencil buffer using the stencil's r channel as the stencil
64 	STENCIL_GREEN = 0x08000000, // blend with the stencil buffer using the stencil's g channel as the stencil
65 	STENCIL_BLUE = 0x20000000, // blend with the stencil buffer using the stencil's b channel as the stencil
66 	STENCIL_DITHER = 0x10000000 // use dithering instead of transpanency. only affects stencil values of 128.
67 };
68 
69 #define BLIT_STENCIL_MASK (BlitFlags::STENCIL_ALPHA|BlitFlags::STENCIL_RED|BlitFlags::STENCIL_GREEN|BlitFlags::STENCIL_BLUE|BlitFlags::STENCIL_DITHER)
70 
71 class GEM_EXPORT VideoBuffer {
72 protected:
73 	Region rect;
74 
75 public:
VideoBuffer(const Region & r)76 	VideoBuffer(const Region& r) : rect(r) {}
~VideoBuffer()77 	virtual ~VideoBuffer() {}
78 
Size()79 	::GemRB::Size Size() const { return rect.Dimensions(); }
Origin()80 	Point Origin() const { return rect.Origin(); }
Rect()81 	Region Rect() const  { return rect; }
82 
SetOrigin(const Point & p)83 	void SetOrigin(const Point& p) { rect.x = p.x; rect.y = p.y; }
84 
Clear()85 	virtual void Clear() { Clear({0, 0, rect.w, rect.h}); };
86 	virtual void Clear(const Region& rgn) = 0;
87 	// CopyPixels takes at least one void* buffer with implied pitch of Region.w, otherwise alternating pairs of buffers and their coresponding pitches
88 	virtual void CopyPixels(const Region& bufDest, const void* pixelBuf, const int* pitch = NULL, ...) = 0;
89 
90 	virtual bool RenderOnDisplay(void* display) const = 0;
91 };
92 
93 using VideoBufferPtr = std::shared_ptr<VideoBuffer>;
94 
95 /**
96  * @class Video
97  * Base class for video output plugins.
98  */
99 
100 class GEM_EXPORT Video : public Plugin {
101 public:
102 	static const TypeID ID;
103 
104 	enum class BufferFormat {
105 		DISPLAY, // whatever format the video driver thinks is best for the display
106 		DISPLAY_ALPHA, // the same RGB format as DISPLAY, but forces an alpha if DISPLAY doesn't provide one
107 		RGBPAL8,	// 8 bit palettized
108 		RGB555, // 16 bit RGB (truecolor)
109 		RGBA8888, // Standard 8 bits per channel with alpha
110 		YV12    // YUV format for BIK videos
111 	};
112 
113 protected:
114 	unsigned long lastTime;
115 	EventMgr* EvntManager;
116 	Region screenClip;
117 	Size screenSize;
118 	int bpp;
119 	bool fullscreen;
120 
121 	unsigned char Gamma10toGamma22[256];
122 	unsigned char Gamma22toGamma10[256];
123 
124 	using VideoBuffers = std::deque<VideoBuffer*>;
125 
126 	// collection of all existing video buffers
127 	VideoBuffers buffers;
128 	// collection built by calls to PushDrawingBuffer() and cleared after SwapBuffers()
129 	// the collection is iterated and drawn in order during SwapBuffers()
130 	// Note: we can add the same buffer more than once to drawingBuffers!
131 	VideoBuffers drawingBuffers;
132 	// the current top of drawingBuffers that draw operations occur on
133 	VideoBuffer* drawingBuffer;
134 	VideoBufferPtr stencilBuffer = nullptr;
135 
136 	Region ClippedDrawingRect(const Region& target, const Region* clip = NULL) const;
137 	virtual void Wait(unsigned long) = 0;
138 	void DestroyBuffer(VideoBuffer*);
139 	void DestroyBuffers();
140 
141 private:
142 	virtual VideoBuffer* NewVideoBuffer(const Region&, BufferFormat)=0;
143 	virtual void SwapBuffers(VideoBuffers&)=0;
144 	virtual int PollEvents() = 0;
145 	virtual int CreateDriverDisplay(const char* title) = 0;
146 
147 	// the actual drawing implementations
148 	virtual void DrawRectImp(const Region& rgn, const Color& color, bool fill, BlitFlags flags) = 0;
149 	virtual void DrawPointImp(const Point&, const Color& color, BlitFlags flags) = 0;
150 	virtual void DrawPointsImp(const std::vector<Point>& points, const Color& color, BlitFlags flags) = 0;
151 	virtual void DrawCircleImp(const Point& origin, unsigned short r, const Color& color, BlitFlags flags) = 0;
152 	virtual void DrawEllipseSegmentImp(const Point& origin, unsigned short xr, unsigned short yr, const Color& color,
153 									   double anglefrom, double angleto, bool drawlines, BlitFlags flags) = 0;
154 	virtual void DrawEllipseImp(const Point& origin, unsigned short xr, unsigned short yr, const Color& color, BlitFlags flags) = 0;
155 	virtual void DrawPolygonImp(const Gem_Polygon* poly, const Point& origin, const Color& color, bool fill, BlitFlags flags) = 0;
156 	virtual void DrawLineImp(const Point& p1, const Point& p2, const Color& color, BlitFlags flags) = 0;
157 	virtual void DrawLinesImp(const std::vector<Point>& points, const Color& color, BlitFlags flags)=0;
158 
159 public:
160 	Video(void);
161 	~Video(void) override;
162 
163 	virtual int Init(void) = 0;
164 
165 	int CreateDisplay(const Size&, int bpp, bool fullscreen, const char* title);
166 	virtual void SetWindowTitle(const char *title) = 0;
167 
168 	/** Toggles GemRB between fullscreen and windowed mode. */
169 	bool ToggleFullscreenMode();
170 	virtual bool SetFullscreenMode(bool set) = 0;
171 	bool GetFullscreenMode() const;
172 	/** Swaps displayed and back buffers */
173 	int SwapBuffers(unsigned int fpscap = 30);
174 	VideoBufferPtr CreateBuffer(const Region&, BufferFormat = BufferFormat::DISPLAY);
175 	void PushDrawingBuffer(const VideoBufferPtr&);
176 	void PopDrawingBuffer();
177 	void SetStencilBuffer(const VideoBufferPtr&);
178 	/** Grabs and releases mouse cursor within GemRB window */
179 	virtual bool ToggleGrabInput() = 0;
180 	virtual void CaptureMouse(bool enabled) = 0;
GetScreenSize()181 	const Size& GetScreenSize() { return screenSize; }
182 
183 	virtual void StartTextInput() = 0;
184 	virtual void StopTextInput() = 0;
185 	virtual bool InTextInput() = 0;
186 
187 	virtual bool TouchInputEnabled() = 0;
188 
189 	virtual Holder<Sprite2D> CreateSprite(const Region&, int bpp, ieDword rMask,
190 		ieDword gMask, ieDword bMask, ieDword aMask, void* pixels,
191 		bool cK = false, int index = 0) = 0;
192 	virtual Holder<Sprite2D> CreateSprite8(const Region&, void* pixels,
193 									PaletteHolder palette, bool cK = false, int index = 0) = 0;
194 	virtual Holder<Sprite2D> CreatePalettedSprite(const Region&, int bpp, void* pixels,
195 										   Color* palette, bool cK = false, int index = 0) = 0;
SupportsBAMSprites()196 	virtual bool SupportsBAMSprites() { return false; }
197 
198 	void BlitSprite(const Holder<Sprite2D> spr, Point p,
199 					const Region* clip = NULL);
200 
201 	virtual void BlitSprite(const Holder<Sprite2D> spr, const Region& src, Region dst,
202 							BlitFlags flags, Color tint = Color()) = 0;
203 
204 	virtual void BlitGameSprite(const Holder<Sprite2D> spr, const Point& p,
205 								BlitFlags flags, Color tint = Color()) = 0;
206 
207 	void BlitGameSpriteWithPalette(Holder<Sprite2D> spr, PaletteHolder pal, const Point& p,
208 								   BlitFlags flags, Color tint);
209 
210 	virtual void BlitVideoBuffer(const VideoBufferPtr& buf, const Point& p, BlitFlags flags,
211 								 const Color* tint = nullptr) = 0;
212 
213 	/** Return GemRB window screenshot.
214 	 * It's generated from the momentary back buffer */
215 	virtual Holder<Sprite2D> GetScreenshot(Region r, const VideoBufferPtr& buf = nullptr) = 0;
216 	/** This function Draws the Border of a Rectangle as described by the Region parameter. The Color used to draw the rectangle is passes via the Color parameter. */
217 	void DrawRect(const Region& rgn, const Color& color, bool fill = true, BlitFlags flags = BlitFlags::NONE);
218 
219 	void DrawPoint(const Point&, const Color& color, BlitFlags flags = BlitFlags::NONE);
220 	void DrawPoints(const std::vector<Point>& points, const Color& color, BlitFlags flags = BlitFlags::NONE);
221 
222 	/** Draws a circle */
223 	void DrawCircle(const Point& origin, unsigned short r, const Color& color, BlitFlags flags = BlitFlags::NONE);
224 	/** Draws an Ellipse Segment */
225 	void DrawEllipseSegment(const Point& origin, unsigned short xr, unsigned short yr, const Color& color,
226 									double anglefrom, double angleto, bool drawlines = true, BlitFlags flags = BlitFlags::NONE);
227 	/** Draws an ellipse */
228 	void DrawEllipse(const Point& origin, unsigned short xr, unsigned short yr, const Color& color, BlitFlags flags = BlitFlags::NONE);
229 	/** Draws a polygon on the screen */
230 	void DrawPolygon(const Gem_Polygon* poly, const Point& origin, const Color& color, bool fill = false, BlitFlags flags = BlitFlags::NONE);
231 	/** Draws a line segment */
232 	void DrawLine(const Point& p1, const Point& p2, const Color& color, BlitFlags flags = BlitFlags::NONE);
233 	void DrawLines(const std::vector<Point>& points, const Color& color, BlitFlags flags = BlitFlags::NONE);
234 	/** Sets Event Manager */
235 	void SetEventMgr(EventMgr* evnt);
236 	/** Flips sprite, returns new sprite */
237 	Holder<Sprite2D> MirrorSprite(const Holder<Sprite2D> sprite, BlitFlags flags, bool MirrorAnchor);
238 
239 	/** Sets Clip Rectangle */
240 	void SetScreenClip(const Region* clip);
241 	/** Gets Clip Rectangle */
GetScreenClip()242 	const Region& GetScreenClip() { return screenClip; }
243 	virtual void SetGamma(int brightness, int contrast) = 0;
244 
245 	/** Scales down a sprite by a ratio */
246 	Holder<Sprite2D> SpriteScaleDown(const Holder<Sprite2D> sprite, unsigned int ratio);
247 	/** Creates an ellipse or circle shaped sprite with various intensity
248 	 *  for projectile light spots */
249 	Holder<Sprite2D> CreateLight(int radius, int intensity);
250 
251 	Color SpriteGetPixelSum(const Holder<Sprite2D> sprite, unsigned short xbase, unsigned short ybase, unsigned int ratio);
252 };
253 
254 }
255 
256 #endif
257