diff options
| -rw-r--r-- | base/main.cpp | 13 | ||||
| -rw-r--r-- | dists/msvc9/scummvm.vcproj | 51 | ||||
| -rw-r--r-- | graphics/VectorRenderer.cpp | 1001 | ||||
| -rw-r--r-- | graphics/VectorRenderer.h | 827 | ||||
| -rw-r--r-- | graphics/module.mk | 3 | ||||
| -rw-r--r-- | gui/InterfaceManager.cpp | 229 | ||||
| -rw-r--r-- | gui/InterfaceManager.h | 223 | ||||
| -rw-r--r-- | gui/ThemeParser.cpp | 219 | ||||
| -rw-r--r-- | gui/ThemeParser.h | 124 | ||||
| -rw-r--r-- | gui/module.mk | 2 | 
10 files changed, 2680 insertions, 12 deletions
diff --git a/base/main.cpp b/base/main.cpp index ff246fd8b3..20775f24db 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -43,6 +43,8 @@  #include "common/system.h"  #include "gui/newgui.h"  #include "gui/message.h" +#include "gui/InterfaceManager.h" +#include "gui/ThemeParser.h"  #if defined(_WIN32_WCE)  #include "backends/platform/wince/CELauncherDialog.h" @@ -68,6 +70,15 @@ static bool launcherDialog(OSystem &system) {  	// Clear the main screen  	system.clearScreen(); +#if 1 + +	GUI::ThemeParser parser; +	parser.debug_testEval(); +	g_InterfaceManager.runGUI(); +	return true; + +#else +  #if defined(_WIN32_WCE)  	CELauncherDialog dlg;  #elif defined(__DC__) @@ -76,6 +87,8 @@ static bool launcherDialog(OSystem &system) {  	GUI::LauncherDialog dlg;  #endif  	return (dlg.runModal() != -1); + +#endif // vector renderer debug  }  static const EnginePlugin *detectPlugin() { diff --git a/dists/msvc9/scummvm.vcproj b/dists/msvc9/scummvm.vcproj index 26f3f79ad4..bc88e6fc66 100644 --- a/dists/msvc9/scummvm.vcproj +++ b/dists/msvc9/scummvm.vcproj @@ -1,7 +1,7 @@  <?xml version="1.0" encoding="windows-1252"?>  <VisualStudioProject  	ProjectType="Visual C++" -	Version="9,00" +	Version="9.00"  	Name="scummvm"  	ProjectGUID="{8434CB15-D08F-427D-9E6D-581AE5B28440}"  	RootNamespace="scummvm" @@ -100,9 +100,6 @@  				Name="VCAppVerifierTool"  			/>  			<Tool -				Name="VCWebDeploymentTool" -			/> -			<Tool  				Name="VCPostBuildEventTool"  			/>  		</Configuration> @@ -194,9 +191,6 @@  				Name="VCAppVerifierTool"  			/>  			<Tool -				Name="VCWebDeploymentTool" -			/> -			<Tool  				Name="VCPostBuildEventTool"  			/>  		</Configuration> @@ -570,10 +564,6 @@  				>  			</File>  			<File -				RelativePath="..\..\sound\musicplugin.h" -				> -			</File> -			<File  				RelativePath="..\..\sound\mixer.cpp"  				>  			</File> @@ -598,6 +588,14 @@  				>  			</File>  			<File +				RelativePath="..\..\sound\musicplugin.cpp" +				> +			</File> +			<File +				RelativePath="..\..\sound\musicplugin.h" +				> +			</File> +			<File  				RelativePath="..\..\sound\null.cpp"  				>  			</File> @@ -1099,6 +1097,14 @@  				>  			</File>  			<File +				RelativePath="..\..\gui\InterfaceManager.cpp" +				> +			</File> +			<File +				RelativePath="..\..\gui\InterfaceManager.h" +				> +			</File> +			<File  				RelativePath="..\..\gui\Key.cpp"  				>  			</File> @@ -1215,6 +1221,14 @@  				>  			</File>  			<File +				RelativePath="..\..\gui\ThemeParser.cpp" +				> +			</File> +			<File +				RelativePath="..\..\gui\ThemeParser.h" +				> +			</File> +			<File  				RelativePath="..\..\gui\widget.cpp"  				>  			</File> @@ -1318,6 +1332,21 @@  				RelativePath="..\..\graphics\surface.h"  				>  			</File> +			<File +				RelativePath="..\..\graphics\VectorRenderer.cpp" +				> +			</File> +			<File +				RelativePath="..\..\graphics\VectorRenderer.h" +				> +				<FileConfiguration +					Name="Debug|Win32" +					> +					<Tool +						Name="VCCustomBuildTool" +					/> +				</FileConfiguration> +			</File>  			<Filter  				Name="scaler"  				> diff --git a/graphics/VectorRenderer.cpp b/graphics/VectorRenderer.cpp new file mode 100644 index 0000000000..abfd53edcd --- /dev/null +++ b/graphics/VectorRenderer.cpp @@ -0,0 +1,1001 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/util.h" +#include "common/system.h" +#include "common/events.h" + +#include "graphics/surface.h" +#include "graphics/colormasks.h" + +#include "gui/InterfaceManager.h" +#include "graphics/VectorRenderer.h" + +namespace Graphics { + +VectorRenderer *createRenderer(int mode) { +	switch (mode) { +	case GUI::InterfaceManager::kGfxStandard16bit: +		return new VectorRendererSpec<uint16, ColorMasks<565> >; + +	case GUI::InterfaceManager::kGfxAntialias16bit: +		return new VectorRendererAA<uint16, ColorMasks<565> >; + +	default: +		return 0; +	} +} + +/******************************************************************** + * DRAWSTEP handling functions + ********************************************************************/ +void VectorRenderer::drawStep(const Common::Rect &area, const DrawStep &step) { + +	if (step.flags & DrawStep::kStepCallbackOnly) { +		(this->*(step.drawing_call))(area, step); +		return; +	} + +	if (step.flags & DrawStep::kStepSetBG) +		setBgColor(step.color2.r, step.color2.g, step.color2.b); + +	if (step.flags & DrawStep::kStepSetFG) +		setFgColor(step.color1.r, step.color1.g, step.color1.b); + +	if (step.flags & DrawStep::kStepSetGradient) +		setGradientColors(step.color1.r, step.color1.g, step.color1.b,  +						  step.color2.r, step.color2.g, step.color2.b); + +	if (step.flags & DrawStep::kStepSetShadow) +		shadowEnable(step.shadow); + +	if (step.flags & DrawStep::kStepSetGradientFactor) +		setGradientFactor(step.factor); + +	if (step.flags & DrawStep::kStepSetStroke) +		setStrokeWidth(step.stroke); + +	if (step.flags & DrawStep::kStepSetFillMode) +		setFillMode((FillMode)step.fill_mode); +		 +	if (step.flags & DrawStep::kStepSettingsOnly) +		return; + +	(this->*(step.drawing_call))(area, step);	 +} + +/******************************************************************** + * MISCELANEOUS functions + ********************************************************************/ +/** Fixed point SQUARE ROOT **/ +inline uint32 fp_sqroot(uint32 x) { +	register uint32 root, remHI, remLO, testDIV, count; + +	root = 0; +	remHI = 0; +	remLO = x; +	count = 23; + +	do { +		remHI = (remHI << 2) | (remLO >> 30); +		remLO <<= 2; +		root <<= 1; +		testDIV = (root << 1) + 1; + +		if (remHI >= testDIV) { +			remHI -= testDIV; +			root++; +		} +	} while (count--); + +	return root; +} + +/** HELPER MACROS for BESENHALM's circle drawing algorithm **/ +#define __BE_ALGORITHM() { \ +	if (f >= 0) { \ +		y--; \ +		ddF_y += 2; \ +		f += ddF_y; \ +		py -= pitch; \ +	} \ +	px += pitch; \ +	ddF_x += 2; \ +	f += ddF_x + 1; \ +} + +#define __BE_DRAWCIRCLE(ptr1,ptr2,ptr3,ptr4,x,y,px,py) { \ +	*(ptr1 + (y) - (px)) = color; \ +	*(ptr1 + (x) - (py)) = color; \ +	*(ptr2 - (x) - (py)) = color; \ +	*(ptr2 - (y) - (px)) = color; \ +	*(ptr3 - (y) + (px)) = color; \ +	*(ptr3 - (x) + (py)) = color; \ +	*(ptr4 + (x) + (py)) = color; \ +	*(ptr4 + (y) + (px)) = color; \ +} + +#define __BE_RESET() { \ +	f = 1 - r; \ +	ddF_x = 0; ddF_y = -2 * r; \ +	x = 0; y = r; px = 0; py = pitch * r; \ +} + +/** HELPER MACROS for WU's circle drawing algorithm **/ +#define __WU_DRAWCIRCLE(ptr1,ptr2,ptr3,ptr4,x,y,px,py,a) { \ +	blendPixelPtr(ptr1 + (y) - (px), color, a); \ +	blendPixelPtr(ptr1 + (x) - (py), color, a); \ +	blendPixelPtr(ptr2 - (x) - (py), color, a); \ +	blendPixelPtr(ptr2 - (y) - (px), color, a); \ +	blendPixelPtr(ptr3 - (y) + (px), color, a); \ +	blendPixelPtr(ptr3 - (x) + (py), color, a); \ +	blendPixelPtr(ptr4 + (x) + (py), color, a); \ +	blendPixelPtr(ptr4 + (y) + (px), color, a); \ +} + +#define __WU_ALGORITHM() { \ +	oldT = T; \ +	T = fp_sqroot(rsq - ((y * y) << 16)) ^ 0xFFFF; \ +	py += p; \ +	if (T < oldT) { \ +		x--; px -= p; \ +	} \ +	a2 = (T >> 8); \ +	a1 = ~a2; \ +} + +#define __TRIANGLE_MAINX() \ +		if (error_term >= 0) { \ +			ptr_right += pitch; \ +			ptr_left += pitch; \ +			error_term += dysub; \ +		} else { \ +			error_term += ddy; \ +		} \ +		ptr_right++; \ +		ptr_left--; + +#define __TRIANGLE_MAINY() \ +		if (error_term >= 0) { \ +			ptr_right++; \ +			ptr_left--; \ +			error_term += dxsub; \ +		} else { \ +			error_term += ddx; \ +		} \ +		ptr_right += pitch; \ +		ptr_left += pitch; + +/******************************************************************** + * Primitive shapes drawing - Public API calls - VectorRendererSpec + ********************************************************************/ +/** LINES **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType, PixelFormat>:: +drawLine(int x1, int y1, int x2, int y2) { +	x1 = CLIP(x1, 0, (int)Base::_activeSurface->w); +	x2 = CLIP(x2, 0, (int)Base::_activeSurface->w); +	y1 = CLIP(y1, 0, (int)Base::_activeSurface->h); +	y2 = CLIP(y2, 0, (int)Base::_activeSurface->h); + +	// we draw from top to bottom +	if (y2 < y1) { +		SWAP(x1, x2); +		SWAP(y1, y2); +	} + +	int dx = ABS(x2 - x1); +	int dy = ABS(y2 - y1); + +	// this is a point, not a line. stoopid. +	if (dy == 0 && dx == 0)  +		return; + +	if (Base::_strokeWidth == 0) +		return; + +	PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1); +	int pitch = Base::surfacePitch(); + +	if (dy == 0) { // horizontal lines +		// these can be filled really fast with a single memset. +		colorFill(ptr, ptr + dx + 1, (PixelType)_fgColor); + +	} else if (dx == 0) { // vertical lines +		// these ones use a static pitch increase. +		while (y1++ <= y2) { +			*ptr = (PixelType)_fgColor; +			ptr += pitch; +		} + +	} else if (ABS(dx) == ABS(dy)) { // diagonal lines +		// these ones also use a fixed pitch increase +		pitch += (x2 > x1) ? 1 : -1; + +		while (dy--) { +			*ptr = (PixelType)_fgColor; +			ptr += pitch; +		} + +	} else { // generic lines, use the standard algorithm... +		drawLineAlg(x1, y1, x2, y2, dx, dy, (PixelType)_fgColor); +	} +} + +/** CIRCLES **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType, PixelFormat>:: +drawCircle(int x, int y, int r) { +	if (x + r > Base::_activeSurface->w || y + r > Base::_activeSurface->h || +		x - r < 0 || y - r < 0 || x == 0 || y == 0 || r <= 0) +		return; + +	if (Base::_fillMode != kFillDisabled && Base::_shadowOffset  +		&& x + r + Base::_shadowOffset < Base::_activeSurface->w +		&& y + r + Base::_shadowOffset < Base::_activeSurface->h) { +		drawCircleAlg(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kFillForeground); +	} + +	switch (Base::_fillMode) { +	case kFillDisabled: +		if (Base::_strokeWidth) +			drawCircleAlg(x, y, r, _fgColor, kFillDisabled); +		break; + +	case kFillForeground: +		drawCircleAlg(x, y, r, _fgColor, kFillForeground); +		break; + +	case kFillBackground: +		if (Base::_strokeWidth > 1) { +			drawCircleAlg(x, y, r, _fgColor, kFillForeground); +			drawCircleAlg(x, y, r - Base::_strokeWidth, _bgColor, kFillBackground); +		} else { +			drawCircleAlg(x, y, r, _bgColor, kFillBackground); +			drawCircleAlg(x, y, r, _fgColor, kFillDisabled); +		} +		break; + +	case kFillGradient: +		break; +	} +} + +/** SQUARES **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType, PixelFormat>:: +drawSquare(int x, int y, int w, int h) { +	if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h || +		w <= 0 || h <= 0 || x < 0 || y < 0) +		return; + +	if (Base::_fillMode != kFillDisabled && Base::_shadowOffset +		&& x + w + Base::_shadowOffset < Base::_activeSurface->w +		&& y + h + Base::_shadowOffset < Base::_activeSurface->h) { +		drawSquareShadow(x, y, w, h, Base::_shadowOffset); +	} + +	switch (Base::_fillMode) { +	case kFillDisabled: +		if (Base::_strokeWidth) +			drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled); +		break; + +	case kFillForeground: +		drawSquareAlg(x, y, w, h, _fgColor, kFillForeground); +		break; + +	case kFillBackground: +		drawSquareAlg(x, y, w, h, _bgColor, kFillBackground); +		drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled); +		break; + +	case kFillGradient: +		VectorRendererSpec::drawSquareAlg(x, y, w, h, 0, kFillGradient); +		if (Base::_strokeWidth) +			drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled); +		break; +	} +} + +/** ROUNDED SQUARES **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType, PixelFormat>:: +drawRoundedSquare(int x, int y, int r, int w, int h) { +	if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h || +		w <= 0 || h <= 0 || x < 0 || y < 0 || r <= 0 || r > 128) +		return; + +	if (Base::_fillMode != kFillDisabled && Base::_shadowOffset +		&& x + w + Base::_shadowOffset < Base::_activeSurface->w +		&& y + h + Base::_shadowOffset < Base::_activeSurface->h) { +		drawRoundedSquareShadow(x, y, r, w, h, Base::_shadowOffset); +	} + +	switch (Base::_fillMode) { +	case kFillDisabled: +		if (Base::_strokeWidth) +			drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kFillDisabled); +		break; + +	case kFillForeground: +		drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kFillForeground); +		break; + +	case kFillBackground: +		VectorRendererSpec::drawRoundedSquareAlg(x, y, r, w, h, _bgColor, kFillBackground); +		drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kFillDisabled); +		break; + +	case kFillGradient: +		if (Base::_strokeWidth > 1) { +			drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kFillForeground); +			VectorRendererSpec::drawRoundedSquareAlg(x + Base::_strokeWidth/2, y + Base::_strokeWidth/2,  +				r - Base::_strokeWidth/2, w - Base::_strokeWidth, h - Base::_strokeWidth, 0, kFillGradient); +		} else { +			VectorRendererSpec::drawRoundedSquareAlg(x, y, r, w, h, 0, kFillGradient); +			if (Base::_strokeWidth) +				drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kFillDisabled); +		} +		break; +	} +} + +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType, PixelFormat>:: +drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) { +	if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h) +		return; + +	PixelType color = 0; + +	if (Base::_strokeWidth <= 1) { +		if (Base::_fillMode == kFillForeground) +			color = _fgColor; +		else if (Base::_fillMode == kFillBackground) +			color = _bgColor; +	} else { +		if (Base::_fillMode == kFillDisabled) +			return; +		color = _fgColor; +	} + +	switch(orient) { +		case kTriangleUp: +		case kTriangleDown: +			drawTriangleVertAlg(x, y, w, h, (orient == kTriangleDown), color, Base::_fillMode); +			break; + +		case kTriangleLeft: +		case kTriangleRight: +			break; +	} + +	if (Base::_strokeWidth > 0) +		if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillGradient) +			drawTriangleVertAlg(x, y, w, h, (orient == kTriangleDown), _fgColor, kFillDisabled); +} + +/******************************************************************** + * Aliased Primitive drawing ALGORITHMS - VectorRendererSpec + ********************************************************************/ +/** SQUARE ALGORITHM **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType, PixelFormat>:: +drawSquareAlg(int x, int y, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { +	PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y); +	int pitch = Base::surfacePitch(); +	int max_h = h; +	 +	if (fill_m != kFillDisabled) { +		while (h--) { +			if (fill_m == kFillGradient) +				color = calcGradient(max_h - h, max_h); + +			colorFill(ptr, ptr + w, color); +			ptr += pitch; +		} +	} else { +		int sw = Base::_strokeWidth, sp = 0, hp = pitch * (h - 1); + +		while (sw--) { +			colorFill(ptr + sp, ptr + w + sp, color); +			colorFill(ptr + hp - sp, ptr + w + hp - sp, color); +			sp += pitch; +		} + +		while (h--) { +			colorFill(ptr, ptr + Base::_strokeWidth, color); +			colorFill(ptr + w - Base::_strokeWidth, ptr + w, color); +			ptr += pitch; +		} +	} +} + +/** SQUARE ALGORITHM **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType, PixelFormat>:: +drawBevelSquareAlg(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color) { +	PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y); +	int pitch = Base::surfacePitch(); +	int i, j; +	 +	i = bevel; +	while (i--) { +		colorFill(ptr_left, ptr_left + w, top_color); +		ptr_left += pitch; +	} + +	i = h - bevel; +	ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + bevel); +	while (i--) { +		colorFill(ptr_left, ptr_left + bevel, top_color); +		ptr_left += pitch; +	} + +	i = bevel; +	ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + h - bevel); +	while (i--) { +		colorFill(ptr_left + i, ptr_left + w, bottom_color); +		ptr_left += pitch; +	} + +	i = h - bevel; +	j = bevel; +	ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y); +	while (i--) { +		colorFill(ptr_left + j, ptr_left + bevel, bottom_color); +		if (j > 0) j--; +		ptr_left += pitch; +	} +} + +/** GENERIC LINE ALGORITHM **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType,PixelFormat>:: +drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { +	PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1); +	int pitch = Base::surfacePitch(); +	int xdir = (x2 > x1) ? 1 : -1; + +	*ptr = (PixelType)color; + +	if (dx > dy) { +		int ddy = dy * 2; +		int dysub = ddy - (dx * 2); +		int error_term = ddy - dx; + +		while (dx--) { +			if (error_term >= 0) { +				ptr += pitch; +				error_term += dysub; +			} else { +				error_term += ddy; +			} + +			ptr += xdir; +			*ptr = (PixelType)color; +		} +	} else { +		int ddx = dx * 2; +		int dxsub = ddx - (dy * 2); +		int error_term = ddx - dy; + +		while (dy--) { +			if (error_term >= 0) { +				ptr += xdir; +				error_term += dxsub; +			} else { +				error_term += ddx; +			} + +			ptr += pitch; +			*ptr = (PixelType)color; +		} +	} + +	ptr = (PixelType *)_activeSurface->getBasePtr(x2, y2); +	*ptr = (PixelType)color; +} + +/** VERTICAL TRIANGLE DRAWING ALGORITHM **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType,PixelFormat>:: +drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) { +	int dx = w >> 1, dy = h, gradient_h = 0; +	int pitch = Base::surfacePitch(); +	PixelType *ptr_right = 0, *ptr_left = 0; + +	if (inverted) { +		ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1); +		ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + w, y1); +	} else { +		ptr_right = ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + dx, y1); +	} + +	if (dx > dy) { +		int ddy = dy * 2; +		int dysub = ddy - (dx * 2); +		int error_term = ddy - dx; + +		switch(fill_m) { +		case kFillDisabled: +			while (dx--) { +				__TRIANGLE_MAINX(); +				*ptr_right = color; +				*ptr_left = color; +			} +			colorFill(ptr_left, ptr_right, color); +			break; + +		case kFillForeground: +		case kFillBackground: +			while (dx--) { +				__TRIANGLE_MAINX(); +				if (inverted) colorFill(ptr_right, ptr_left, color); +				else colorFill(ptr_left, ptr_right, color); +			} +			break; + +		case kFillGradient: +			while (dx--) { +				__TRIANGLE_MAINX(); +				if (inverted) colorFill(ptr_right, ptr_left, calcGradient(gradient_h++, h)); +				else colorFill(ptr_left, ptr_right, calcGradient(gradient_h++, h)); +			} +			break; +		} +	} else { +		int ddx = dx * 2; +		int dxsub = ddx - (dy * 2); +		int error_term = ddx - dy; + +		switch(fill_m) { +		case kFillDisabled: +			while (dy--) { +				__TRIANGLE_MAINY(); +				*ptr_right = color; +				*ptr_left = color; +			} +			colorFill(ptr_left, ptr_right, color); +			break; + +		case kFillForeground: +		case kFillBackground: +			while (dy--) { +				__TRIANGLE_MAINY(); +				if (inverted) colorFill(ptr_right, ptr_left, color); +				else colorFill(ptr_left, ptr_right, color); +			} +			break; +		case kFillGradient: +			while (dy--) { +				__TRIANGLE_MAINY(); +				if (inverted) colorFill(ptr_right, ptr_left, calcGradient(gradient_h++, h)); +				else colorFill(ptr_left, ptr_right, calcGradient(gradient_h++, h)); +			} +			break; +		} +	} +} + + +/** ROUNDED SQUARE ALGORITHM **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType, PixelFormat>:: +drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { +	int f, ddF_x, ddF_y; +	int x, y, px, py; +	int pitch = Base::surfacePitch(); +	int sw = 0, sp = 0, hp = h * pitch; +	 +	PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); +	PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); +	PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); +	PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); +	PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); + +	int real_radius = r; +	int short_h = h - (2 * r) + 2; +	int long_h = h; + +	if (fill_m == kFillDisabled) { +		while (sw++ < Base::_strokeWidth) { +			colorFill(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color); +			colorFill(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color); +			sp += pitch; + +			__BE_RESET(); +			r--; +			 +			while (x++ < y) { +				__BE_ALGORITHM(); +				__BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py); + +				if (Base::_strokeWidth > 1) { +					__BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py); +					__BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py); +				} +			}  +		} + +		ptr_fill += pitch * real_radius; +		while (short_h--) { +			colorFill(ptr_fill, ptr_fill + Base::_strokeWidth, color); +			colorFill(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color); +			ptr_fill += pitch; +		} +	} else { +		__BE_RESET(); + +		if (fill_m == kFillGradient) { +			while (x++ < y) { +				__BE_ALGORITHM(); +				colorFill(ptr_tl - x - py, ptr_tr + x - py, calcGradient(real_radius - y, long_h)); +				colorFill(ptr_tl - y - px, ptr_tr + y - px, calcGradient(real_radius - x, long_h)); + +				colorFill(ptr_bl - x + py, ptr_br + x + py, calcGradient(long_h - r + y, long_h)); +				colorFill(ptr_bl - y + px, ptr_br + y + px, calcGradient(long_h - r + x, long_h)); +			} +		} else { +			while (x++ < y) { +				__BE_ALGORITHM();			 + +				colorFill(ptr_tl - x - py, ptr_tr + x - py, color); +				colorFill(ptr_tl - y - px, ptr_tr + y - px, color); + +				colorFill(ptr_bl - x + py, ptr_br + x + py, color); +				colorFill(ptr_bl - y + px, ptr_br + y + px, color); + +				// FIXME: maybe not needed at all? +				__BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py); +			} +		} + +		ptr_fill += pitch * r; +		while (short_h--) { +			if (fill_m == kFillGradient) +				color = calcGradient(real_radius++, long_h); +			colorFill(ptr_fill, ptr_fill + w + 1, color); +			ptr_fill += pitch; +		} +	} +} + +/** CIRCLE ALGORITHM **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType, PixelFormat>:: +drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) { +	int f, ddF_x, ddF_y; +	int x, y, px, py, sw = 0; +	int pitch = Base::surfacePitch(); +	PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); + +	if (fill_m == kFillDisabled) { +		while (sw++ < Base::_strokeWidth) { +			__BE_RESET(); +			r--; + +			*(ptr + y) = color; +			*(ptr - y) = color; +			*(ptr + py) = color; +			*(ptr - py) = color; + +			while (x++ < y) { +				__BE_ALGORITHM(); +				__BE_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px, py); + +				if (Base::_strokeWidth > 1) { +					__BE_DRAWCIRCLE(ptr, ptr, ptr, ptr, x - 1, y, px, py); +					__BE_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px - pitch, py); +				} +			} +		} +	} else { +		colorFill(ptr - r, ptr + r, color); +		__BE_RESET(); + +		while (x++ < y) { +			__BE_ALGORITHM(); +			colorFill(ptr - x + py, ptr + x + py, color); +			colorFill(ptr - x - py, ptr + x - py, color); +			colorFill(ptr - y + px, ptr + y + px, color); +			colorFill(ptr - y - px, ptr + y - px, color); +		} +	} +} + + +/******************************************************************** + * SHADOW drawing algorithms - VectorRendererSpec + ********************************************************************/ +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType, PixelFormat>:: +drawSquareShadow(int x, int y, int w, int h, int blur) { +	PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + blur); +	int pitch = Base::surfacePitch(); +	int i, j; + +	i = h - blur; + +	while (i--) { +		j = blur; +		while (j--) +			blendPixelPtr(ptr + j, 0, ((blur - j) << 8) / blur); +		ptr += pitch; +	} + +	ptr = (PixelType *)_activeSurface->getBasePtr(x + blur, y + h - 1); + +	while (i++ < blur) { +		j = w - blur; +		while (j--) +			blendPixelPtr(ptr + j, 0, ((blur - i) << 8) / blur); +		ptr += pitch; +	} + +	ptr = (PixelType *)_activeSurface->getBasePtr(x + w, y + h); + +	i = 0; +	while (i++ < blur) { +		j = blur - 1; +		while (j--) +			blendPixelPtr(ptr + j, 0, (((blur - j) * (blur - i)) << 8) / (blur * blur)); +		ptr += pitch; +	} +} + +template<typename PixelType, typename PixelFormat> +void VectorRendererSpec<PixelType, PixelFormat>:: +drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int blur) { +	int f, ddF_x, ddF_y; +	int x, y, px, py; +	int pitch = Base::surfacePitch(); +	int alpha = 102; + +	x1 += blur; +	y1 += blur; + +	PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); +	PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); +	PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); +	PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - blur, y1 + r); + +	int short_h = h - (2 * r) + 1; + +	__BE_RESET(); + +	// HACK: As we are drawing circles exploting 8-axis symmetry, +	// there are 4 pixels on each circle which are drawn twice. +	// this is ok on filled circles, but when blending on surfaces, +	// we cannot let it blend twice. awful. +	bool *hb = new bool[r]; + +	int i = 0; +	while (i < r) +		hb[i++] = false; + +	while (x++ < y) { +		__BE_ALGORITHM(); + +		if (!hb[x]) { +			blendFill(ptr_tr - px - r, ptr_tr + y - px, 0, alpha); +			blendFill(ptr_bl - y + px, ptr_br + y + px, 0, alpha); +			hb[x] = true; +		} + +		if (!hb[y]) { +			blendFill(ptr_tr - r - py, ptr_tr + x - py, 0, alpha); +			blendFill(ptr_bl - x + py, ptr_br + x + py, 0, alpha); +			hb[y] = true; +		} +	} + +	delete[] hb; + +	while (short_h--) { +		blendFill(ptr_fill - r, ptr_fill + blur, 0, alpha); +		ptr_fill += pitch; +	} +} + + +/******************************************************************** + * ANTIALIASED PRIMITIVES drawing algorithms - VectorRendererAA + ********************************************************************/ +/** LINES **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererAA<PixelType, PixelFormat>:: +drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { + +	PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); +	int pitch = Base::surfacePitch(); +	int xdir = (x2 > x1) ? 1 : -1; +	uint16 error_tmp, error_acc, gradient; +	uint8 alpha; + +	*ptr = (PixelType)color; + +	if (dx > dy) { +		gradient = (uint32)(dy << 16) / (uint32)dx; +		error_acc = 0; + +		while (--dx) { +			error_tmp = error_acc; +			error_acc += gradient; + +			if (error_acc <= error_tmp) +				ptr += pitch; + +			ptr += xdir; +			alpha = (error_acc >> 8); + +			blendPixelPtr(ptr, color, ~alpha); +			blendPixelPtr(ptr + pitch, color, alpha); +		} +	} else { +		gradient = (uint32)(dx << 16) / (uint32)dy; +		error_acc = 0; + +		while (--dy) { +			error_tmp = error_acc; +			error_acc += gradient; + +			if (error_acc <= error_tmp) +				ptr += xdir; + +			ptr += pitch; +			alpha = (error_acc >> 8); + +			blendPixelPtr(ptr, color, ~alpha); +			blendPixelPtr(ptr + xdir, color, alpha); +		} +	} + +	Base::putPixel(x2, y2, color); +} + +/** ROUNDED SQUARES **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererAA<PixelType, PixelFormat>:: +drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { +	int x, y; +	int p = Base::surfacePitch(), px, py; +	int sw = 0, sp = 0, hp = h * p; + +	uint32 rsq = (r * r) << 16; +	uint32 T = 0, oldT; +	uint8 a1, a2; + +	PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); +	PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); +	PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); +	PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); +	PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); + +	int short_h = h - 2 * r; + +	if (fill_m == VectorRenderer::kFillDisabled) { +		while (sw++ < Base::_strokeWidth) { +			colorFill(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color); +			colorFill(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color); +			sp += p; + +			x = r - (sw - 1); y = 0; T = 0; +			px = p * x; py = 0; +			 +			while (x > y++) { +				__WU_ALGORITHM(); + +				if (sw != 1 && sw != Base::_strokeWidth) +					a2 = a1 = 255; + +				__WU_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, (x - 1), y, (px - p), py, a2); +				__WU_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1); +			}  +		} + +		ptr_fill += p * r; +		while (short_h-- >= 0) { +			colorFill(ptr_fill, ptr_fill + Base::_strokeWidth, color); +			colorFill(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color); +			ptr_fill += p; +		} +	} else { +		x = r; y = 0; T = 0; +		px = p * x; py = 0; +		 +		while (x > y++) { +			__WU_ALGORITHM(); + +			colorFill(ptr_tl - x - py, ptr_tr + x - py, color); +			colorFill(ptr_tl - y - px, ptr_tr + y - px, color); + +			colorFill(ptr_bl - x + py, ptr_br + x + py, color); +			colorFill(ptr_bl - y + px, ptr_br + y + px, color); + +			__WU_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1); +		} + +		ptr_fill += p * r; +		while (short_h-- >= 0) { +			colorFill(ptr_fill, ptr_fill + w + 1, color); +			ptr_fill += p; +		} +	} +} + +/** CIRCLES **/ +template<typename PixelType, typename PixelFormat> +void VectorRendererAA<PixelType, PixelFormat>:: +drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) { +	int x, y, sw = 0; +	int p = Base::surfacePitch(), px, py; + +	uint32 rsq = (r * r) << 16; +	uint32 T = 0, oldT; +	uint8 a1, a2; + +	PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); + +	if (fill_m == VectorRenderer::kFillDisabled) { +		while (sw++ < Base::_strokeWidth) { +			x = r - (sw - 1); y = 0; T = 0; +			px = p * x; py = 0; + +			*(ptr + x) = (PixelType)color; +			*(ptr - x) = (PixelType)color; +			*(ptr + px) = (PixelType)color; +			*(ptr - px) = (PixelType)color; + +			while (x > y++) { +				__WU_ALGORITHM(); + +				if (sw != 1 && sw != Base::_strokeWidth) +					a2 = a1 = 255; + +				__WU_DRAWCIRCLE(ptr, ptr, ptr, ptr, (x - 1), y, (px - p), py, a2); +				__WU_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px, py, a1); +			} +		} +	} else { +		colorFill(ptr - r, ptr + r + 1, color); +		x = r; y = 0; T = 0; +		px = p * x; py = 0; + +		while (x > y++) { +			__WU_ALGORITHM(); + +			colorFill(ptr - x + py, ptr + x + py, color); +			colorFill(ptr - x - py, ptr + x - py, color); +			colorFill(ptr - y + px, ptr + y + px, color); +			colorFill(ptr - y - px, ptr + y - px, color); +				 +			__WU_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px, py, a1); +		}				 +	} +} + +} // end of namespace Graphics diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h new file mode 100644 index 0000000000..310f32f856 --- /dev/null +++ b/graphics/VectorRenderer.h @@ -0,0 +1,827 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef VECTOR_RENDERER_H +#define VECTOR_RENDERER_H + +#include "common/scummsys.h" +#include "common/system.h" + +#include "graphics/surface.h" +#include "graphics/colormasks.h" + +#include "gui/InterfaceManager.h" + + +namespace Graphics { +class VectorRenderer; +struct DrawStep; + +struct DrawStep { +	uint32 flags; /** Step flags, see DrawStepFlags */ + +	struct {  +		uint8 r, g, b;  +	}	 +	color1, /** Foreground color/gradient start */ +	color2; /** Background color/gradient end */ + +	bool fill_area; /** If enabled, the draw step occupies the whole drawing area */ + +	struct { +		uint16 pos; +		bool relative; +	} x, y; /** Horizontal and vertical coordinates. Relative specifies if they are +			    measured from the opposite direction of the drawing area */ + +	uint16 w, h; /** width and height */ + +	uint8 shadow, stroke, factor, radius; /** Misc options... */ + +	uint8 fill_mode; /** active fill mode */ +	uint8 extra_data; /** Generic parameter for extra options (orientation/bevel) */ + +	uint32 scale; /** scale of all the coordinates in FIXED POINT with 16 bits mantissa */ + +	void (VectorRenderer::*drawing_call)(const Common::Rect &, const DrawStep &); /** Pointer to drawing function */ + +	enum DrawStepFlags { +		kStepCallbackOnly		= (1 << 0), +		kStepSettingsOnly		= (1 << 1), +		kStepSetBG				= (1 << 2), +		kStepSetFG				= (1 << 3), +		kStepSetGradient		= (1 << 4), +		kStepSetShadow			= (1 << 5), +		kStepSetGradientFactor	= (1 << 6), +		kStepSetStroke			= (1 << 7), +		kStepSetFillMode		= (1 << 8) +	}; +}; + +VectorRenderer *createRenderer(int mode); + +/** + * VectorRenderer: The core Vector Renderer Class + * + * This virtual class exposes the API with all the vectorial + * rendering functions that may be used to draw on a given Surface. + * + * This class must be instantiated as one of its children, which implement + * the actual rendering functionality for each Byte Depth / Byte Format + * combination, and may also contain platform specific code. + * + * TODO: Expand documentation. + * + * @see VectorRendererSpec + * @see VectorRendererAA + */ +class VectorRenderer { +public: +	VectorRenderer() : _shadowOffset(0), _fillMode(kFillDisabled),  +		_activeSurface(NULL), _strokeWidth(1), _gradientFactor(1) { +	 +	} + +	virtual ~VectorRenderer() {} + +	/** Specifies the way in which a shape is filled */ +	enum FillMode { +		kFillDisabled = 0, +		kFillForeground = 1, +		kFillBackground = 2, +		kFillGradient = 3 +	}; + +	enum TriangleOrientation { +		kTriangleUp, +		kTriangleDown, +		kTriangleLeft, +		kTriangleRight +	}; + +	/** +	 * Draws a line by considering the special cases for optimization. +	 * +	 * @param x1 Horizontal (X) coordinate for the line start +	 * @param x2 Horizontal (X) coordinate for the line end +	 * @param y1 Vertical (Y) coordinate for the line start +	 * @param y2 Vertical (Y) coordinate for the line end +	 */ +	virtual void drawLine(int x1, int y1, int x2, int y2) = 0; + +	/** +	 * Draws a circle centered at (x,y) with radius r. +	 * +	 * @param x Horizontal (X) coordinate for the center of the circle +	 * @param y Vertical (Y) coordinate for the center of the circle +	 * @param r Radius of the circle. +	 */ +	virtual void drawCircle(int x, int y, int r) = 0; + +	/** +	 * Draws a square starting at (x,y) with the given width and height. +	 * +	 * @param x Horizontal (X) coordinate for the center of the square +	 * @param y Vertical (Y) coordinate for the center of the square +	 * @param w Width of the square. +	 * @param h Height of the square +	 */ +	virtual void drawSquare(int x, int y, int w, int h) = 0; + +	/** +	 * Draws a rounded square starting at (x,y) with the given width and height. +	 * The corners of the square are rounded with the given radius. +	 * +	 * @param x Horizontal (X) coordinate for the center of the square +	 * @param y Vertical (Y) coordinate for the center of the square +	 * @param w Width of the square. +	 * @param h Height of the square +	 * @param r Radius of the corners. +	 */ +	virtual void drawRoundedSquare(int x, int y, int r, int w, int h) = 0; + +	/** +	 * Draws a triangle starting at (x,y) with the given base and height. +	 * The triangle will always be isosceles, with the given base and height. +	 * The orientation parameter controls the position of the base of the triangle. +	 * +	 * @param x Horizontal (X) coordinate for the top left corner of the triangle +	 * @param y Vertical (Y) coordinate for the top left corner of the triangle +	 * @param base Width of the base of the triangle +	 * @param h Height of the triangle +	 * @param orient Orientation of the triangle. +	 */ +	virtual void drawTriangle(int x, int y, int base, int height, TriangleOrientation orient) = 0; + +	/** +	 * Draws a beveled square like the ones in the Classic GUI themes. +	 * Beveled squares are always drawn with a transparent background. Draw them on top +	 * of a standard square to fill it. +	 * +	 * @param x Horizontal (X) coordinate for the center of the square +	 * @param y Vertical (Y) coordinate for the center of the square +	 * @param w Width of the square. +	 * @param h Height of the square +	 * @param bevel Amount of bevel. Must be positive. +	 */ +	virtual void drawBeveledSquare(int x, int y, int w, int h, int bevel) = 0; + +	/** +	 * Gets the pixel pitch for the current drawing surface. +	 * Note: This is a real pixel-pitch, not a byte-pitch. +	 * That means it can be safely used in pointer arithmetics and +	 * in pixel manipulation. +	 * +	 * @return integer with the active bytes per pixel +	 */ +	virtual uint16 surfacePitch() { +		return _activeSurface->pitch / _activeSurface->bytesPerPixel; +	} + +	/** +	 * Gets the BYTES (not bits) per Pixel we are working on, +	 * based on the active drawing surface. +	 * +	 * @return integer byte with the active bytes per pixel value +	 */ +	virtual uint8 bytesPerPixel() { +		return _activeSurface->bytesPerPixel; +	} + +	/** +	 * Set the active foreground painting color for the renderer. +	 * All the foreground drawing from then on will be done with that color, unless +	 * specified otherwise. +	 * +	 * Foreground drawing means all outlines and basic shapes. +	 * +	 * @param r	value of the red color byte +	 * @param g	value of the green color byte +	 * @param b	value of the blue color byte +	 */ +	virtual void setFgColor(uint8 r, uint8 g, uint8 b) = 0; + +	/** +	 * Set the active background painting color for the renderer. +	 * All the background drawing from then on will be done with that color, unless +	 * specified otherwise. +	 * +	 * Background drawing means all the shape filling. +	 * +	 * @param r	value of the red color byte +	 * @param g	value of the green color byte +	 * @param b	value of the blue color byte +	 */ +	virtual void setBgColor(uint8 r, uint8 g, uint8 b) = 0; + +	/** +	 * Set the active gradient color. All shapes drawn using kFillGradient +	 * as their fill mode will use this VERTICAL gradient as their fill color. +	 * +	 * @param r1	value of the red color byte for the start color +	 * @param g1	value of the green color byte for the start color +	 * @param b1	value of the blue color byte for the start color +	 * @param r2	value of the red color byte for the end color +	 * @param g2	value of the green color byte for the end color +	 * @param b2	value of the blue color byte for the end color +	 */ +	virtual void setGradientColors(uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2) = 0; + +	/** +	 * Sets the active drawing surface. All drawing from this +	 * point on will be done on that surface. +	 * +	 * @param surface Pointer to a Surface object. +	 */ +	virtual void setSurface(Surface *surface) { +		_activeSurface = surface; +	} + +	/** +	 * Fills the active surface with the specified fg/bg color or the active gradient. +	 * Defaults to using the active Foreground color for filling. +	 * +	 * @param mode Fill mode (bg, fg or gradient) used to fill the surface +	 */ +	virtual void fillSurface() = 0; + +	/** +	 * Clears the active surface. +	 */ +	virtual void clearSurface() { +		byte *src = (byte *)_activeSurface->pixels; +		memset(src, 0, _activeSurface->w * _activeSurface->h * _activeSurface->bytesPerPixel); +	} + +	/** +	 * Sets the active fill mode for all shapes. +	 * +	 * @see VectorRenderer::FillMode +	 * @param mode Specified fill mode. +	 */ +	virtual void setFillMode(FillMode mode) { +		_fillMode = mode; +	} + +	/** +	 * Sets the stroke width. All shapes drawn with a stroke will +	 * have that width. Pass 0 to disable shape stroking. +	 * +	 * @param width Witdh of the stroke in pixels. +	 */ +	virtual void setStrokeWidth(int width) { +		_strokeWidth = width; +	} + +	/** +	 * Enables adding shadows to all drawn primitives. +	 * Shadows are drawn automatically under the shapes. The given offset +	 * controls their intensity and size (the higher the offset, the +	 * bigger the shadows). +	 * +	 * @param offset Shadow offset. +	 * @see shadowDisable() +	 */ +	virtual void shadowEnable(int offset) { +		if (offset > 0) +			_shadowOffset = offset; +	} + +	/** +	 * Disables adding shadows to all drawn primitives. +	 * +	 * @see shadowEnable() +	 */ +	virtual void shadowDisable() { +		_shadowOffset = 0; +	} + +	/** +	 * Sets the multiplication factor of the active gradient. +	 * +	 * @see _gradientFactor +	 * @param factor Multiplication factor. +	 */ +	virtual void setGradientFactor(int factor) { +		if (factor > 0) +			_gradientFactor = factor; +	} + +	void stepGetPositions(const DrawStep &step, const Common::Rect &area, uint16 &in_x, uint16 &in_y, uint16 &in_w, uint16 &in_h) { +		if (step.fill_area) { +			in_x = area.left; +			in_y = area.top; +			in_w = area.width(); +			in_h = area.height(); +		} else { +			if (!step.x.relative) in_x = area.left + step.x.pos;  +			else in_x = area.left + area.width() - step.x.pos; + +			if (!step.y.relative) in_y = area.top + step.y.pos; +			else in_y = area.top + area.height() - step.y.pos; + +			if (in_x + step.w > area.right) in_w = area.right - in_x; +			else in_w = step.w; + +			if (in_y + step.h > area.bottom) in_h = area.bottom - in_y; +			else in_h = step.h; +		} + +		if (step.scale != (1 << 16) && step.scale != 0) { +			in_x = (in_x * step.scale) >> 16; +			in_y = (in_y * step.scale) >> 16; +			in_w = (in_w * step.scale) >> 16; +			in_h = (in_h * step.scale) >> 16; +		} +	} + +	/** +	 * DrawStep callback functions for each drawing feature  +	 */ +	void drawCallback_CIRCLE(const Common::Rect &area, const DrawStep &step) { +		uint16 x, y, w, h; +		stepGetPositions(step, area, x, y, w, h); +		drawCircle(x, y, (step.radius * step.scale) >> 16); +	} + +	void drawCallback_SQUARE(const Common::Rect &area, const DrawStep &step) { +		uint16 x, y, w, h; +		stepGetPositions(step, area, x, y, w, h); +		drawSquare(x, y, w, h); +	} + +	void drawCallback_LINE(const Common::Rect &area, const DrawStep &step) { +		uint16 x, y, w, h; +		stepGetPositions(step, area, x, y, w, h); +		drawLine(x, y, x + w, y + w); +	} + +	void drawCallback_ROUNDSQ(const Common::Rect &area, const DrawStep &step) { +		uint16 x, y, w, h; +		stepGetPositions(step, area, x, y, w, h); +		/* HACK! Radius of the rounded squares isn't scaled */ +		drawRoundedSquare(x, y, step.radius, w, h); +	} + +	void drawCallback_FILLSURFACE(const Common::Rect &area, const DrawStep &step) { +		fillSurface(); +	} + +	void drawCallback_TRIANGLE(const Common::Rect &area, const DrawStep &step) { +		uint16 x, y, w, h; +		stepGetPositions(step, area, x, y, w, h); +		drawTriangle(x, y, w, h, (TriangleOrientation)step.extra_data); +	} + +	void drawCallback_BEVELSQ(const Common::Rect &area, const DrawStep &step) { +		uint16 x, y, w, h; +		stepGetPositions(step, area, x, y, w, h); +		drawBeveledSquare(x, y, w, h, step.extra_data); +	} + +	/** +	 * Draws the specified draw step on the screen. +	 *  +	 * @see DrawStep +	 * @param area Zone to paint on +	 * @param step Pointer to a DrawStep struct. +	 */ +	virtual void drawStep(const Common::Rect &area, const DrawStep &step); + +	/** +	 * Copies the current surface to the system overlay  +	 * +	 * @param sys Pointer to the global System class +	 */ +	virtual void copyFrame(OSystem *sys) = 0; + +	/** +	 * Blits a given graphics surface on top of the current drawing surface. +	 * +	 * @param source Surface to blit into the drawing surface. +	 * @param r Position in the active drawing surface to do the blitting. +	 */ +	virtual void blitSurface(Graphics::Surface *source, const Common::Rect &r) = 0; + +protected: +	Surface *_activeSurface; /** Pointer to the surface currently being drawn */ + +	FillMode _fillMode; /** Defines in which way (if any) are filled the drawn shapes */ +	 +	int _shadowOffset; /** offset for drawn shadows */ +	int _strokeWidth; /** Width of the stroke of all drawn shapes */ + +	int _gradientFactor; /** Multiplication factor of the active gradient */ +	int _gradientBytes[3]; /** Color bytes of the active gradient, used to speed up calculation */ +}; + +/** + * VectorRendererSpec: Specialized Vector Renderer Class + * + * This templated class implements the basic subset of vector operations for + * all platforms by allowing the user to provide the actual Pixel Type and + * pixel information structs. + * + * This class takes two template parameters: + * + * @param PixelType Defines a type which may hold the color value of a single + *        pixel, such as "byte" or "uint16" for 8 and 16 BPP respectively. + * + * @param PixelFormat Defines the type of the PixelFormat struct which contains all + *        the actual information of the pixels being used, as declared in "graphics/colormasks.h" + *                     + * TODO: Expand documentation. + * + * @see VectorRenderer + */ +template<typename PixelType, typename PixelFormat> +class VectorRendererSpec : public VectorRenderer { +	typedef VectorRenderer Base; + +public: +	/** +	 * @see VectorRenderer::drawLine() +	 */ +	void drawLine(int x1, int y1, int x2, int y2); + +	/** +	 * @see VectorRenderer::drawCircle() +	 */ +	void drawCircle(int x, int y, int r); + +	/** +	 * @see VectorRenderer::drawSquare() +	 */ +	void drawSquare(int x, int y, int w, int h); + +	/** +	 * @see VectorRenderer::drawRoundedSquare() +	 */ +	void drawRoundedSquare(int x, int y, int r, int w, int h); + +	/** +	 * @see VectorRenderer::drawTriangle() +	 */ +	void drawTriangle(int x, int y, int base, int height, TriangleOrientation orient); + +	void drawBeveledSquare(int x, int y, int w, int h, int bevel) { +		drawBevelSquareAlg(x, y, w, h, bevel, _fgColor, _bgColor); +	} + +	/** +	 * @see VectorRenderer::setFgColor() +	 */ +	void setFgColor(uint8 r, uint8 g, uint8 b) { +		this->_fgColor = RGBToColor<PixelFormat>(r, g, b); +	} + +	/** +	 * @see VectorRenderer::setBgColor() +	 */ +	void setBgColor(uint8 r, uint8 g, uint8 b) { +		this->_bgColor = RGBToColor<PixelFormat>(r, g, b); +	} + +	/** +	 * @see VectorRenderer::setGradientColors() +	 */ +	void setGradientColors(uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2) { +		_gradientEnd = RGBToColor<PixelFormat>(r2, g2, b2); +		_gradientStart = RGBToColor<PixelFormat>(r1, g1, b1); + +		Base::_gradientBytes[0] = (_gradientEnd & PixelFormat::kRedMask) - (_gradientStart & PixelFormat::kRedMask); +		Base::_gradientBytes[1] = (_gradientEnd & PixelFormat::kGreenMask) - (_gradientStart & PixelFormat::kGreenMask); +		Base::_gradientBytes[2] = (_gradientEnd & PixelFormat::kBlueMask) - (_gradientStart & PixelFormat::kBlueMask); +	} + +	/** +	 * @see VectorRenderer::fillSurface() +	 */ +	void fillSurface() { +		PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(0, 0); + +		int w = _activeSurface->w; +		int h = _activeSurface->h ; +		int pitch = surfacePitch(); + +		if (Base::_fillMode == kFillBackground) +			colorFill(ptr, ptr + w * h, _bgColor); +		else if (Base::_fillMode == kFillForeground) +			colorFill(ptr, ptr + w * h, _fgColor); +		else if (Base::_fillMode == kFillGradient) { +			int i = h; +			while (i--) { +				colorFill(ptr, ptr + w, calcGradient(h - i, h)); +				ptr += pitch; +			} +		} +	} + +	/** +	 * @see VectorRenderer::copyFrame() +	 */ +	virtual void copyFrame(OSystem *sys) { +#ifdef OVERLAY_MULTIPLE_DEPTHS +		sys->copyRectToOverlay((const PixelType*)_activeSurface->getBasePtr(0, 0),  +			_activeSurface->w, 0, 0, _activeSurface->w, _activeSurface->w); +#else +		sys->copyRectToOverlay((const OverlayColor*)_activeSurface->getBasePtr(0, 0),  +			_activeSurface->w, 0, 0, _activeSurface->w, _activeSurface->w); +#endif +		sys->updateScreen(); +	} + +	/** +	 * @see VectorRenderer::blitSurface() +	 */ +	virtual void blitSurface(Graphics::Surface *source, const Common::Rect &r) { +		PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(r.top, r.left); +		PixelType *src_ptr = (PixelType *)source->getBasePtr(0, 0); + +		int dst_pitch = surfacePitch(); +		int src_pitch = source->pitch / source->bytesPerPixel; + +		int h = r.height(), w = r.width(); + +		while (h--) { +			colorCopy(src_ptr, dst_ptr, w); +			dst_ptr += dst_pitch; +			src_ptr += src_pitch; +		} +	} + +protected: + +	/** +	 * Draws a single pixel on the surface with the given coordinates and +	 * the given color. +	 * +	 * @param x Horizontal coordinate of the pixel. +	 * @param y Vertical coordinate of the pixel. +	 * @param color Color of the pixel +	 */ +	virtual inline void putPixel(int x, int y, PixelType color) { +		PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y); +		*ptr = color; +	} + +	/** +	 * Blends a single pixel on the surface with the given coordinates, color +	 * and Alpha intensity. +	 * +	 * @param x Horizontal coordinate of the pixel. +	 * @param y Vertical coordinate of the pixel. +	 * @param color Color of the pixel +	 * @param alpha Alpha intensity of the pixel (0-255) +	 */ +	virtual inline void blendPixel(int x, int y, PixelType color, uint8 alpha) { +		if (alpha == 255) +			putPixel(x, y, color); +		else if (alpha > 0) +			blendPixelPtr((PixelType*)Base::_activeSurface->getBasePtr(x, y), color, alpha); +	} + +	/** +	 * Blends a single pixel on the surface in the given pixel pointer, using supplied color +	 * and Alpha intensity. +	 *  +	 * This is implemented to prevent blendPixel() to calculate the surface pointer on each call. +	 * Optimized drawing algorithms should call this function when possible. +	 * +	 * @see blendPixel +	 * @param ptr Pointer to the pixel to blend on top of +	 * @param color Color of the pixel +	 * @param alpha Alpha intensity of the pixel (0-255) +	 */ +	virtual inline void blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha)	{ +		if (alpha == 255) { +			*ptr = color; +			return; +		} + +		register int idst = *ptr; +		register int isrc = color; + +		*ptr = (PixelType)( +			(PixelFormat::kRedMask & ((idst & PixelFormat::kRedMask) + +			((int)(((int)(isrc & PixelFormat::kRedMask) - +			(int)(idst & PixelFormat::kRedMask)) * alpha) >> 8))) | +			(PixelFormat::kGreenMask & ((idst & PixelFormat::kGreenMask) + +			((int)(((int)(isrc & PixelFormat::kGreenMask) - +			(int)(idst & PixelFormat::kGreenMask)) * alpha) >> 8))) | +			(PixelFormat::kBlueMask & ((idst & PixelFormat::kBlueMask) + +			((int)(((int)(isrc & PixelFormat::kBlueMask) - +			(int)(idst & PixelFormat::kBlueMask)) * alpha) >> 8))) ); +	} + +	/** +	 * PRIMITIVE DRAWING ALGORITHMS +	 * +	 * Generic algorithms for drawing all kinds of aliased primitive shapes. +	 * These may be overloaded in inheriting classes to implement platform-specific +	 * optimizations or improve looks. +	 * +	 * @see VectorRendererAA +	 * @see VectorRendererAA::drawLineAlg +	 * @see VectorRendererAA::drawCircleAlg +	 */ +	virtual void drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color); +	virtual void drawCircleAlg(int x, int y, int r, PixelType color, FillMode fill_m); +	virtual void drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, FillMode fill_m); +	virtual void drawSquareAlg(int x, int y, int w, int h, PixelType color, FillMode fill_m); +	virtual void drawTriangleVertAlg(int x, int y, int w, int h, bool inverted, PixelType color, FillMode fill_m); +	virtual void drawBevelSquareAlg(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color); + +	/** +	 * SHADOW DRAWING ALGORITHMS +	 * +	 * Optimized versions of the primitive drawing algorithms with alpha blending +	 * for shadow drawing. +	 * There functions may be overloaded in inheriting classes to improve performance +	 * in the slowest platforms where pixel alpha blending just doesn't cut it. +	 * +	 * @param blur Intensity/size of the shadow. +	 */ +	virtual void drawSquareShadow(int x, int y, int w, int h, int blur); +	virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h, int blur); + +	/** +	 * Calculates the color gradient on a given point. +	 * This function assumes that the gradient start/end colors have been set +	 * beforehand from the API function call. +	 * +	 * @param pos Progress of the gradient. +	 * @param max Maximum amount of the progress. +	 * @return Composite color of the gradient at the given "progress" amount. +	 */ +	virtual inline PixelType calcGradient(uint32 pos, uint32 max) { +		PixelType output = 0; +		pos = (MIN(pos * Base::_gradientFactor, max) << 12) / max; +		 +		output |= (_gradientStart + ((Base::_gradientBytes[0] * pos) >> 12)) & PixelFormat::kRedMask; +		output |= (_gradientStart + ((Base::_gradientBytes[1] * pos) >> 12)) & PixelFormat::kGreenMask; +		output |= (_gradientStart + ((Base::_gradientBytes[2] * pos) >> 12)) & PixelFormat::kBlueMask; +		output |= ~(PixelFormat::kRedMask | PixelFormat::kGreenMask | PixelFormat::kBlueMask); +	 +		return output; +	} + +	/** +	 * Fills several pixels in a row with a given color and the specifed alpha blending. +	 * +	 * @see blendPixelPtr +	 * @see blendPixel +	 * @param first Pointer to the first pixel to fill. +	 * @param last Pointer to the last pixel to fill. +	 * @param color Color of the pixel +	 * @param alpha Alpha intensity of the pixel (0-255) +	 */ +	virtual inline void blendFill(PixelType *first, PixelType *last, PixelType color, uint8 alpha) { +		while (first != last) +			blendPixelPtr(first++, color, alpha); +	} + +	/** +	 * Fills several pixels in a row with a given color. +	 * +	 * This is a replacement function for Common::set_to, using an unrolled +	 * loop to maximize performance on most architectures. +	 * This function may (and should) be overloaded in any child renderers +	 * for portable platforms with platform-specific assembly code. +	 * +	 * This fill operation is extensively used throughout the renderer, so this +	 * counts as one of the main bottlenecks. Please replace it with assembly  +	 * when possible! +	 * +	 * @param first Pointer to the first pixel to fill. +	 * @param last Pointer to the last pixel to fill. +	 * @param color Color of the pixel +	 */ +	virtual inline void colorFill(PixelType *first, PixelType *last, PixelType color) { +		if (first == last) { +			*first = color; +			return; +		} + +		register PixelType *ptr = first; +		register int count = (last - first); +		register int n = (count + 7) >> 3; +		switch (count % 8) { +		case 0: do {  +					*ptr++ = color; +		case 7:		*ptr++ = color; +		case 6:		*ptr++ = color; +		case 5:		*ptr++ = color; +		case 4:		*ptr++ = color; +		case 3:		*ptr++ = color; +		case 2:		*ptr++ = color; +		case 1:		*ptr++ = color; +				} while (--n > 0); +		} +	} + +	/** +	 * Copies several pixes in a row from a surface to another one. +	 * Used for surface blitting. +	 * See colorFill() for optimization guidelines. +	 * +	 * @param src Source surface. +	 * @param dst Destination surface. +	 * @param count Amount of pixels to copy over. +	 */ +	virtual inline void colorCopy(PixelType *src, PixelType *dst, int count) { +		register int n = (count + 7) >> 3; +		switch (count % 8) { +		case 0: do {  +					*dst++ = *src++; +		case 7:		*dst++ = *src++; +		case 6:		*dst++ = *src++; +		case 5:		*dst++ = *src++; +		case 4:		*dst++ = *src++; +		case 3:		*dst++ = *src++; +		case 2:		*dst++ = *src++; +		case 1:		*dst++ = *src++; +				} while (--n > 0); +		} +	} + +	PixelType _fgColor; /** Foreground color currently being used to draw on the renderer */ +	PixelType _bgColor; /** Background color currently being used to draw on the renderer */ + +	PixelType _gradientStart; /** Start color for the fill gradient */ +	PixelType _gradientEnd; /** End color for the fill gradient */ +}; + +/** + * VectorRendererAA: Anti-Aliased Vector Renderer Class + * + * This templated class inherits all the functionality of the VectorRendererSpec + * class but uses better looking yet slightly slower AA algorithms for drawing + * most primivitves. May be used in faster platforms. + *                     + * TODO: Expand documentation. + * + * @see VectorRenderer + * @see VectorRendererSpec + */ +template<typename PixelType, typename PixelFormat> +class VectorRendererAA : public VectorRendererSpec<PixelType, PixelFormat> { +	typedef VectorRendererSpec<PixelType, PixelFormat> Base; +protected: +	/** +	 * "Wu's Line Antialiasing Algorithm" as published by Xiaolin Wu, July 1991 +	 * Based on the implementation found in Michael Abrash's Graphics Programming Black Book. +	 * +	 * Generic line drawing algorithm for the Antialiased renderer. Optimized with no +	 * floating point operations, assumes no special cases. +	 * +	 * @see VectorRenderer::drawLineAlg() +	 */ +	virtual void drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color); + +	/** +	 * "Wu's Circle Antialiasing Algorithm" as published by Xiaolin Wu, July 1991 +	 * Based on the theoretical concept of the algorithm. +	 * +	 * Implementation of Wu's algorithm for circles using fixed point arithmetics. +	 * Could be quite fast. +	 * +	 * @see VectorRenderer::drawCircleAlg() +	 */ +	virtual void drawCircleAlg(int x, int y, int r, PixelType color, VectorRenderer::FillMode fill_m); + +	/** +	 * "Wu's Circle Antialiasing Algorithm" as published by Xiaolin Wu, July 1991, +	 * modified with corner displacement to allow drawing of squares with rounded +	 * corners. +	 * +	 * @see VectorRenderer::drawRoundedAlg() +	 */ +	virtual void drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m); +}; + +} // end of namespace Graphics + +#endif diff --git a/graphics/module.mk b/graphics/module.mk index 93e2db26c5..b8dfd94ad2 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -16,7 +16,8 @@ MODULE_OBJS := \  	primitives.o \  	scaler.o \  	scaler/thumbnail.o \ -	surface.o +	surface.o \ +	VectorRenderer.o  ifndef DISABLE_SCALERS  MODULE_OBJS += \ diff --git a/gui/InterfaceManager.cpp b/gui/InterfaceManager.cpp new file mode 100644 index 0000000000..f0874393f0 --- /dev/null +++ b/gui/InterfaceManager.cpp @@ -0,0 +1,229 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/util.h" +#include "graphics/surface.h" +#include "graphics/colormasks.h" +#include "common/system.h" +#include "common/events.h" + +#include "gui/InterfaceManager.h" +#include "graphics/VectorRenderer.h" + +DECLARE_SINGLETON(GUI::InterfaceManager); + +namespace GUI { + +using namespace Graphics; + +InterfaceManager::InterfaceManager() :  +	_vectorRenderer(0), _system(0), _graphicsMode(kGfxDisabled),  +	_screen(0), _bytesPerPixel(0) { +	_system = g_system; + +	setGraphicsMode(kGfxStandard16bit); +} + +template<typename PixelType>  +void InterfaceManager::screenInit() { +	freeScreen(); + +	_screen = new Surface; +	_screen->create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(PixelType)); +	_system->clearOverlay(); +} + +void InterfaceManager::setGraphicsMode(Graphics_Mode mode) { +	if (mode == _graphicsMode) +		return; + +	_graphicsMode = mode; + +	switch (mode) { +	case kGfxStandard16bit: +	case kGfxAntialias16bit: +		_bytesPerPixel = sizeof(uint16); +		screenInit<uint16>(); +		break; + +	default: +		return; +	} + +	freeRenderer(); +	_vectorRenderer = createRenderer(mode); +	_vectorRenderer->setSurface(_screen); +} + +bool InterfaceManager::init() { +	return false; +} + +bool InterfaceManager::isWidgetCached(DrawData type, const Common::Rect &r) { +	return _widgets[type] && _widgets[type]->_cached && +		_widgets[type]->_surfaceCache->w == r.width() &&  +		_widgets[type]->_surfaceCache->h == r.height(); +} + +void InterfaceManager::drawCached(DrawData type, const Common::Rect &r) { +	assert(_widgets[type]->_surfaceCache->bytesPerPixel == _screen->bytesPerPixel); +	_vectorRenderer->blitSurface(_widgets[type]->_surfaceCache, r); +} + +void InterfaceManager::drawDD(DrawData type, const Common::Rect &r) { +	if (isWidgetCached(type, r)) { +		drawCached(type, r); +	} else { +		for (int i = 0; i < _widgets[type]->_stepCount; ++i) +			_vectorRenderer->drawStep(r, *_widgets[type]->_steps[i]); +	} +} + +void InterfaceManager::drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, uint16 hints) { +	if (!_initOk) +		return; + +	if (state == kStateEnabled) +		drawDD(kDDButtonIdle, r); +	else if (state == kStateHighlight) +		drawDD(kDDButtonHover, r); + +	// TODO: Add text drawing. + +	addDirtyRect(r); +} + +void InterfaceManager::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) { +	if (!_initOk) +		return; + +	drawDD(kDDSeparator, r); +	addDirtyRect(r); +} + +void InterfaceManager::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) { +	if (!_initOk) +		return; + +	drawDD(checked ? kDDCheckboxEnabled : kDDCheckboxDisabled, r); + +	Common::Rect r2 = r; +	r2.left += 16; // TODO: add variable for checkbox text offset. + +	// TODO: text drawing +//	getFont()->drawString(&_screen, str, r2.left, r2.top, r2.width(), getColor(state), Graphics::kTextAlignLeft, 0, false); + +	addDirtyRect(r); +} + +void InterfaceManager::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state) { +	if (!_initOk) +		return; + +	drawDD(kDDSliderEmpty, r); + +	Common::Rect r2 = r; +	r2.setWidth(MIN((int16)width, r.width())); + +	drawDD(kDDSliderFull, r2); + +	addDirtyRect(r); +} + +void InterfaceManager::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState sb_state, WidgetStateInfo state) { +	if (!_initOk) +		return; +} + +int InterfaceManager::runGUI() { +	Common::EventManager *eventMan = _system->getEventManager(); +	_system->showOverlay(); + +	Graphics::DrawStep *steps = new Graphics::DrawStep[5]; + +	steps[0].color1.r = 214; +	steps[0].color1.g = 113; +	steps[0].color1.b = 8; +	steps[0].color2.r = 240; +	steps[0].color2.g = 200; +	steps[0].color2.b = 25; +	steps[0].fill_mode = VectorRenderer::kFillGradient; +	steps[0].drawing_call = &VectorRenderer::drawCallback_FILLSURFACE; +	steps[0].flags = DrawStep::kStepSetGradient | DrawStep::kStepSetFillMode; + +	steps[1].color1.r = 206; +	steps[1].color1.g = 121; +	steps[1].color1.b = 99; +	steps[1].color2.r = 173; +	steps[1].color2.g = 40; +	steps[1].color2.b = 8; +	steps[1].radius = 8; // radius +	steps[1].fill_area = true; +	steps[1].drawing_call = &VectorRenderer::drawCallback_ROUNDSQ; +	steps[1].flags = DrawStep::kStepSetGradient; +	steps[1].scale = (1 << 16); + +	steps[2].radius = 8; // radius +	steps[2].fill_area = false; +	steps[2].x.relative = true; +	steps[2].x.pos = 32; +	steps[2].y.relative = false; +	steps[2].y.pos = 32; +	steps[2].w = 128; +	steps[2].h = 32; +	steps[2].drawing_call = &VectorRenderer::drawCallback_ROUNDSQ; +	steps[2].flags = DrawStep::kStepCallbackOnly; +	steps[2].scale = (1 << 16); + +	steps[3].drawing_call = &VectorRenderer::drawCallback_ROUNDSQ; +	steps[3].flags = DrawStep::kStepCallbackOnly; + +	Common::Rect area = Common::Rect(32, 32, 256, 256); + +	bool running = true; +	while (running) { // draw!! + +		_vectorRenderer->drawStep(Common::Rect(), steps[0]); +		_vectorRenderer->drawStep(area, steps[1]); +		_vectorRenderer->drawStep(area, steps[2]); +//		_vectorRenderer->drawStep(Common::Rect(32, 32, 256, 256), &steps[3]); + +		_vectorRenderer->copyFrame(_system); + +		Common::Event event; +		_system->delayMillis(100); +		while (eventMan->pollEvent(event)) { +			if (event.type == Common::EVENT_QUIT) +				running = false; +		} +	} + +	_system->hideOverlay(); +	return 1; +} + + + +} // end of namespace GUI. diff --git a/gui/InterfaceManager.h b/gui/InterfaceManager.h new file mode 100644 index 0000000000..7ab3f4c9db --- /dev/null +++ b/gui/InterfaceManager.h @@ -0,0 +1,223 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef INTERFACE_MANAGER_H +#define INTERFACE_MANAGER_H + +#include "common/scummsys.h" +#include "graphics/surface.h" +#include "common/system.h" + +#include "graphics/surface.h" +#include "graphics/fontman.h" + +#include "graphics/VectorRenderer.h" + +namespace GUI { + +#define g_InterfaceManager	(GUI::InterfaceManager::instance()) + +struct WidgetDrawData; +class InterfaceManager; + +class InterfaceManager : public Common::Singleton<InterfaceManager> { + +	friend class Common::Singleton<SingletonBaseType>; +	typedef Common::String String; + +public: +	enum Graphics_Mode { +		kGfxDisabled = 0, +		kGfxStandard16bit, +		kGfxAntialias16bit +	}; + +	enum DrawData { +		kDDMainDialogBackground, +		kDDSpecialColorBackground, +		kDDPlainColorBackground, +		kDDDefaulBackground, + +		kDDButtonIdle, +		kDDButtonHover, + +		kDDSurface, + +		kDDSliderFull, +		kDDSliderEmpty, + +		kDDCheckboxEnabled, +		kDDCheckboxDisabled, + +		kDDTab, + +		kDDScrollbarBase, +		kDDScrollbarButtonTop, +		kDDScrollbarButtonBottom, +		kDDScrollbarHandle, + +		kDDPopUp, +		kDDCaret, +		kDDSeparator, +		kDrawDataMAX +	}; + +	enum FontStyle { +		kFontStyleBold = 0,			//! A bold font. This is also the default font. +		kFontStyleNormal = 1,		//! A normal font. +		kFontStyleItalic = 2,		//! Italic styled font. +		kFontStyleFixedNormal = 3,	//! Fixed size font. +		kFontStyleFixedBold = 4,	//! Fixed size bold font. +		kFontStyleFixedItalic = 5,	//! Fixed size italic font. +		kFontStyleMax +	}; + +	enum State { +		kStateDisabled,		//! Indicates that the widget is disabled, that does NOT include that it is invisible +		kStateEnabled,		//! Indicates that the widget is enabled +		kStateHighlight		//! Indicates that the widget is highlighted by the user +	}; + +	//! Widget background type +	enum WidgetBackground { +		kWidgetBackgroundNo,			//! No background at all +		kWidgetBackgroundPlain,			//! Simple background, this may not include borders +		kWidgetBackgroundBorder,		//! Same as kWidgetBackgroundPlain just with a border +		kWidgetBackgroundBorderSmall,	//! Same as kWidgetBackgroundPlain just with a small border +		kWidgetBackgroundEditText,		//! Background used for edit text fields +		kWidgetBackgroundSlider			//! Background used for sliders +	}; + +	typedef State WidgetStateInfo; + +	//! State of the scrollbar +	enum ScrollbarState { +		kScrollbarStateNo, +		kScrollbarStateUp, +		kScrollbarStateDown, +		kScrollbarStateSlider, +		kScrollbarStateSinglePage +	}; + +	//! Defined the align of the text +	enum TextAlign { +		kTextAlignLeft,		//! Text should be aligned to the left +		kTextAlignCenter,	//! Text should be centered +		kTextAlignRight		//! Text should be aligned to the right +	}; + +	//! Function used to process areas other than the current dialog +	enum ShadingStyle { +		kShadingNone,		//! No special post processing +		kShadingDim,		//! Dimming unused areas +		kShadingLuminance	//! Converting colors to luminance for unused areas +	}; + + +	InterfaceManager(); + +	~InterfaceManager() { +		freeRenderer(); +		freeScreen(); +	} + +	void setGraphicsMode(Graphics_Mode mode); +	int runGUI(); + +	bool init(); +	bool deinit(); + +	/** Font management */ +	const Graphics::Font *getFont(FontStyle font) const { return _font; } +	int getFontHeight(FontStyle font = kFontStyleBold) const { if (_initOk) return _font->getFontHeight(); return 0; } +	int getStringWidth(const Common::String &str, FontStyle font) const { if (_initOk) return _font->getStringWidth(str); return 0; } +	int getCharWidth(byte c, FontStyle font) const { if (_initOk) return _font->getCharWidth(c); return 0; } + +	/** Widget drawing */ +	void drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background = kWidgetBackgroundPlain, WidgetStateInfo state = kStateEnabled) {} +	void drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, uint16 hints = 0); +	void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state = kStateEnabled, int alpha = 256, bool themeTrans = false) {} +	void drawSlider(const Common::Rect &r, int width, WidgetStateInfo state = kStateEnabled); +	void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state = kStateEnabled); +	void drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state = kStateEnabled) {} +	void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState, WidgetStateInfo state = kStateEnabled); +	void drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state = kStateEnabled, TextAlign align = kTextAlignLeft) {} +	void drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state = kStateEnabled) {} +	void drawLineSeparator(const Common::Rect &r, WidgetStateInfo state = kStateEnabled); + +protected: +	template<typename PixelType> void screenInit(); + +	void freeRenderer() { +		delete _vectorRenderer; +		_vectorRenderer = 0; +	} + +	void freeScreen() { +		if (_screen != 0) { +			_screen->free(); +			delete _screen; +			_screen = 0; +		} +	} + +	bool isWidgetCached(DrawData type, const Common::Rect &r); +	void drawCached(DrawData type, const Common::Rect &r); + +	inline void drawDD(DrawData type, const Common::Rect &r); +	void addDirtyRect(const Common::Rect &r) {} + +	OSystem *_system; +	Graphics::VectorRenderer *_vectorRenderer; +	Graphics::Surface *_screen; + +	int _bytesPerPixel; +	Graphics_Mode _graphicsMode; + +	Common::String _fontName; +	const Graphics::Font *_font; + +	WidgetDrawData *_widgets[kDrawDataMAX]; + +	bool _initOk; +	bool _caching; +}; + +struct WidgetDrawData { +	Common::Rect _realSize; +	bool _scaled; + +	Graphics::DrawStep **_steps; +	int _stepCount; + +	bool _cached; +	Graphics::Surface *_surfaceCache; + +	InterfaceManager::DrawData _type; +}; + +} // end of namespace GUI. + +#endif diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp new file mode 100644 index 0000000000..260e3911a1 --- /dev/null +++ b/gui/ThemeParser.cpp @@ -0,0 +1,219 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/util.h" +#include "common/system.h" +#include "common/events.h" +#include "common/hashmap.h" +#include "common/hash-str.h" + +#include "gui/ThemeParser.h" + +/** + +<drawdata = "background_default" cache = true> +	<draw func = "roundedsq" fill = "gradient" gradient_start = "255, 255, 128" gradient_end = "128, 128, 128" size = "auto"> +	<draw func = "roundedsq" fill = "none" color = "0, 0, 0" size = "auto"> +</drawdata> + +*/ + +namespace GUI { + +void ThemeParser::debug_testEval() { +	static const char *debug_config_text = +		"<drawdata id = \"background_default\" cache = true>" +		"<draw func = \"roundedsq\" /*/fill = \"gradient\" gradient_start = \"255, 255, 128\" gradient_end = \"128, 128, 128\" size = \"auto\"/>" +		"<draw func = \"roundedsq\" fill = \"none\" color = /*\"0, 0, 0\"*/\"0, 1, 2\" size = \"auto\"/>" +		"</drawdata>/* lol this is just a simple test*/"; + +	_text = strdup(debug_config_text); +	parse(); +} +	 + +void ThemeParser::parserError(const char *error_string) { +	_state = kParserError; +	printf("PARSER ERROR: %s\n", error_string); +} + +void ThemeParser::parserCallback_DRAW() { +	printf("Draw callback!\n"); +} + +void ThemeParser::parserCallback_DRAWDATA() { +	printf("Drawdata callback!\n"); +} + +void ThemeParser::parseActiveKey(bool closed) { +	printf("Parsed key %s.\n", _activeKey.top().c_str()); + +	if (!_callbacks.contains(_activeKey.top())) { +		parserError("Unhandled value inside key."); +		return; +	} + +	// Don't you just love C++ syntax? Water clear. +	(this->*(_callbacks[_activeKey.top()]))(); + +	for (Common::StringMap::const_iterator t = _keyValues.top().begin(); t != _keyValues.top().end(); ++t) +		printf("    Key %s = %s\n", t->_key.c_str(), t->_value.c_str()); + +	if (closed) { +		_keyValues.pop(); +		_activeKey.pop(); +	} +} + +bool ThemeParser::parseKeyValue(Common::String &key_name) { +	assert(_keyValues.empty() == false); + +	if (_keyValues.top().contains(key_name)) +		return false; + +	Common::String name = key_name; +	_token.clear(); +	char string_start; + +	if (_text[_pos] == '"' || _text[_pos] == '\'') { +		string_start = _text[_pos++]; + +		while (_text[_pos] && _text[_pos] != string_start) +			_token += _text[_pos++]; + +		if (_text[_pos++] == 0) +			return false; + +	} else if (!parseToken()) { +		return false; +	} + +	_keyValues.top()[name] = _token; +	return true; +} + +bool ThemeParser::parse() { + +	bool active_closure = false; +	bool self_closure = false; + +	_state = kParserNeedKey; +	_pos = 0; +	_keyValues.clear(); +	_activeKey.clear(); +	 +	while (_text[_pos]) { +		if (_state == kParserError) +			break; + +		if (skipSpaces()) +			continue; + +		if (skipComments()) +			continue; + +		switch (_state) { +			case kParserNeedKey: +				if (_text[_pos++] != '<') parserError("Expecting key start."); +				else _state = kParserNeedKeyName; +				break; + +			case kParserNeedKeyName: +				if (_text[_pos] == '/') { +					_pos++; +					active_closure = true; +				} +				 +				if (!parseToken()) { +					parserError("Unexpected end of file while parsing token."); +					break; +				} + +				if (active_closure) { +					if (_activeKey.empty() || _token != _activeKey.top()) +						parserError("Unexpected closure."); +				} else { +					_keyValues.push(Common::StringMap()); +					_activeKey.push(_token); +				} + +				_state = kParserNeedPropertyName; +				break; + +			case kParserNeedPropertyName: +				if (active_closure) { +					active_closure = false; +					_activeKey.pop(); +					_keyValues.pop(); + +					if (_text[_pos++] != '>') +						parserError("Invalid syntax in key closure."); +					 +					_state = kParserNeedKey; +					break; +				} + +				self_closure = (_text[_pos] == '/'); + +				if ((self_closure && _text[_pos + 1] == '>') || _text[_pos] == '>') { +					parseActiveKey(self_closure); +					_pos += self_closure ? 2 : 1; +					_state = kParserNeedKey; +					break; +				} + +				if (!parseToken()) parserError("Error when parsing key value."); +				else _state = kParserNeedPropertyOperator; +				break; + +			case kParserNeedPropertyOperator: +				if (_text[_pos++] != '=') parserError("Unexpected character after key name."); +				else  _state = kParserNeedPropertyValue; +				break; + +			case kParserNeedPropertyValue: +				if (!parseKeyValue(_token)) parserError("Unable to parse key value."); +				else _state = kParserNeedPropertyName; +				break; + +			default: +				break; +		} +	} + +	if (_state == kParserError) { +		return false; +	} + +	if (_state != kParserNeedKey || !_activeKey.empty()) { +		parserError("Unexpected end of file."); +		return false; +	} + +	return true; +} + +} + diff --git a/gui/ThemeParser.h b/gui/ThemeParser.h new file mode 100644 index 0000000000..df99893d58 --- /dev/null +++ b/gui/ThemeParser.h @@ -0,0 +1,124 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef THEME_PARSER_H +#define THEME_PARSER_H + +#include "common/scummsys.h" +#include "graphics/surface.h" +#include "common/system.h" + +#include "common/hashmap.h" +#include "common/hash-str.h" +#include "common/stack.h" + +namespace GUI { + +class ThemeParser { + +	static const int kParserMaxDepth = 4; +	typedef void (ThemeParser::*ParserCallback)(); + +public: +	ThemeParser() { +		_callbacks["drawdata"] = &ThemeParser::parserCallback_DRAWDATA; +		_callbacks["draw"] = &ThemeParser::parserCallback_DRAW; +	} + +	~ThemeParser() {} + +	enum ParserState { +		kParserNeedKey, +		kParserNeedKeyName, + +		kParserNeedPropertyName, +		kParserNeedPropertyOperator, +		kParserNeedPropertyValue, + +		kParserError +	}; + +	bool parse(); +	void debug_testEval(); +	 +protected: +	void parserCallback_DRAW(); +	void parserCallback_DRAWDATA(); + +	bool parseKeyValue(Common::String &key_name); +	void parseActiveKey(bool closed); +	void parserError(const char *error_string); + +	inline bool skipSpaces() { +		if (!isspace(_text[_pos])) +			return false; + +		while (_text[_pos] && isspace(_text[_pos])) +			_pos++; + +		return true; +	} + +	inline bool skipComments() { +		if (_text[_pos] == '/' && _text[_pos + 1] == '*') { +			_pos += 2; +			while (_text[_pos++]) { +				if (_text[_pos - 2] == '*' && _text[_pos - 1] == '/') +					break; +			} +			return true; +		} +		return false; +	} + +	inline bool isValidNameChar(char c) { +		return isalnum(c) || c == '_'; +	} + +	inline bool parseToken() { +		_token.clear(); +		while (isValidNameChar(_text[_pos])) +			_token += _text[_pos++]; + +		return (_text[_pos] != 0); +	} + +	int _pos; +	char *_text; + +	ParserState _state; + +	Common::String _error; +	Common::String _token; + +	Common::FixedStack<Common::String, kParserMaxDepth> _activeKey; +	Common::FixedStack<Common::StringMap, kParserMaxDepth> _keyValues; + +	Common::HashMap<Common::String, ParserCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _callbacks; +}; + +} + +#endif diff --git a/gui/module.mk b/gui/module.mk index c572dcbeea..eecf9a093d 100644 --- a/gui/module.mk +++ b/gui/module.mk @@ -10,6 +10,7 @@ MODULE_OBJS := \  	editable.o \  	EditTextWidget.o \  	eval.o \ +	InterfaceManager.o \  	launcher.o \  	ListWidget.o \  	massadd.o \ @@ -25,6 +26,7 @@ MODULE_OBJS := \  	theme.o \  	ThemeClassic.o \  	ThemeModern.o \ +	ThemeParser.o \  	theme-config.o  # Include common rules  | 
