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