1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "titanic/star_control/surface_area.h"
24 #include "graphics/primitives.h"
25 
26 namespace Titanic {
27 
CSurfaceArea(CVideoSurface * surface)28 CSurfaceArea::CSurfaceArea(CVideoSurface *surface) {
29 	_width = surface->getWidth();
30 	_height = surface->getHeight();
31 	_pitch = surface->getPitch();
32 	_field0 = 0;
33 	_colorMask = _color = 0;
34 	_mode = SA_SOLID;
35 	_surface = nullptr;
36 
37 	// Original supported other pixel depths
38 	_bpp = surface->getPixelDepth();
39 	_pixelsPtr = (byte *)surface->getPixels();
40 	assert(_bpp == 2 && _pixelsPtr);
41 
42 	initialize();
43 }
44 
initialize()45 void CSurfaceArea::initialize() {
46 	_bounds = Rect(0, 0, _width - 1, _height - 1);
47 	_centroid = FPoint(_width / 2.0, _height / 2.0);
48 	_pixel = 0xffffff;
49 	_field27 = _field26 = _field25 = 0;
50 	_field24 = 0;
51 	_rgb = _field2C = 0;
52 	_mode = SA_SOLID;
53 }
54 
setColor(uint rgb)55 void CSurfaceArea::setColor(uint rgb) {
56 	switch (_mode) {
57 	case SA_MODE1:
58 		_color = 0;
59 		_colorMask = rgb;
60 		break;
61 	case SA_MODE2:
62 		_color = rgb;
63 		_colorMask = ~rgb;
64 		break;
65 	case SA_XOR:
66 		_color = rgb;
67 		_colorMask = 0xFFFFFFFF;
68 		break;
69 	case SA_MODE4:
70 		_color = 0;
71 		_colorMask = ~rgb;
72 		break;
73 	default:
74 		break;
75 	}
76 }
77 
setMode(SurfaceAreaMode mode)78 SurfaceAreaMode CSurfaceArea::setMode(SurfaceAreaMode mode) {
79 	SurfaceAreaMode oldMode = _mode;
80 	_mode = mode;
81 	setColor(_rgb);
82 	return oldMode;
83 }
84 
setColorFromPixel()85 void CSurfaceArea::setColorFromPixel() {
86 	pixelToRGB(_pixel, &_rgb);
87 	setColor(_rgb);
88 }
89 
getPixelFormat() const90 Graphics::PixelFormat CSurfaceArea::getPixelFormat() const {
91 	switch (_bpp) {
92 	case 1:
93 	case 2:
94 		return Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
95 	case 4:
96 		return Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
97 	default:
98 		return Graphics::PixelFormat::createFormatCLUT8();
99 	}
100 }
101 
pixelToRGB(uint pixel,uint * rgb)102 void CSurfaceArea::pixelToRGB(uint pixel, uint *rgb) {
103 	switch (_bpp) {
104 	case 0:
105 		*rgb = 0;
106 		break;
107 
108 	case 1:
109 	case 2: {
110 		Graphics::PixelFormat pf = getPixelFormat();
111 		*rgb = pf.RGBToColor(pixel & 0xff, (pixel >> 8) & 0xff, (pixel >> 16) & 0xff);
112 		break;
113 	}
114 
115 	case 3:
116 	case 4:
117 		*rgb = pixel;
118 		break;
119 
120 	default:
121 		break;
122 	}
123 }
124 
drawLine(const FPoint & pt1,const FPoint & pt2)125 double CSurfaceArea::drawLine(const FPoint &pt1, const FPoint &pt2) {
126 	if (pt1 == pt2)
127 		return pt1._y;
128 
129 	FPoint p1 = pt1, p2 = pt2;
130 	double xp = pt1._x, yp = pt1._y;
131 
132 	int flags1 = (p1._x < _bounds.left ? 1 : 0)
133 		| (p1._x > _bounds.right ? 2 : 0)
134 		| (p1._y < _bounds.top ? 4 : 0)
135 		| (p1._y > _bounds.bottom ? 8 : 0);
136 	int flags2 = (p2._x < _bounds.left ? 1 : 0)
137 		| (p2._x > _bounds.right ? 2 : 0)
138 		| (p2._y < _bounds.top ? 4 : 0)
139 		| (p2._y > _bounds.bottom ? 8 : 0);
140 
141 	// Handle any clipping
142 	while (flags1 | flags2) {
143 		if (flags1 & flags2)
144 			return p1._y;
145 
146 		int flags = flags1 ? flags1 : flags2;
147 		if ((flags & 1) || (flags & 2)) {
148 			xp = (flags & 1) ? _bounds.left : _bounds.right;
149 			yp = (p2._y - p1._y) * (xp - p1._x) / (p2._x - p1._x) + p1._y;
150 		} else if ((flags & 4) || (flags & 8)) {
151 			yp = (flags & 4) ? _bounds.top : _bounds.bottom;
152 			xp = (p2._x - p1._x) * (yp - p1._y) / (p2._y - p1._y) + p1._x;
153 		}
154 
155 		if (flags == flags1) {
156 			p1._x = xp;
157 			p1._y = yp;
158 
159 			flags1 = 0;
160 			if (xp < _bounds.left)
161 				flags1 |= 1;
162 			if (xp > _bounds.right)
163 				flags1 |= 2;
164 			if (yp < _bounds.top)
165 				flags1 |= 4;
166 			if (yp > _bounds.bottom)
167 				flags1 |= 8;
168 		} else {
169 			p2._x = xp;
170 			p2._y = yp;
171 
172 			flags2 = 0;
173 			if (xp < _bounds.left)
174 				flags2 |= 1;
175 			if (xp > _bounds.right)
176 				flags2 |= 2;
177 			if (yp < _bounds.top)
178 				flags2 |= 4;
179 			if (yp > _bounds.bottom)
180 				flags2 |= 8;
181 		}
182 	}
183 
184 	Common::Point srcPos((int)(p1._x - 0.5), (int)(p1._y - 0.5));
185 	Common::Point destPos((int)(p2._x - 0.5), (int)(p2._y - 0.5));
186 
187 	Graphics::Surface s;
188 	s.setPixels(_pixelsPtr);
189 	s.pitch = _pitch;
190 	s.format = getPixelFormat();
191 	s.w = _width;
192 	s.h = _height;
193 	_surface = &s;
194 
195 	switch (_bpp) {
196 	case 0:
197 		if (_mode != SA_SOLID) {
198 			Graphics::drawLine(srcPos.x, srcPos.y, destPos.x, destPos.y, 0, plotPoint<byte>, this);
199 			return p1._y;
200 		}
201 		break;
202 	case 1:
203 	case 2:
204 		if (_mode != SA_SOLID) {
205 			Graphics::drawLine(srcPos.x, srcPos.y, destPos.x, destPos.y, 0, plotPoint<uint16>, this);
206 			return p1._y;
207 		}
208 		break;
209 	case 4:
210 		if (_mode != SA_SOLID) {
211 			Graphics::drawLine(srcPos.x, srcPos.y, destPos.x, destPos.y, 0, plotPoint<uint32>, this);
212 			return p1._y;
213 		}
214 		break;
215 	default:
216 		error("Unknown bpp");
217 	}
218 
219 	s.drawLine(srcPos.x, srcPos.y, destPos.x, destPos.y, _rgb);
220 	return p1._y;
221 }
222 
223 } // End of namespace Titanic
224