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 "twine/menu/interface.h"
24 #include "graphics/managed_surface.h"
25 #include "graphics/primitives.h"
26 #include "twine/twine.h"
27
28 namespace TwinE {
29
Interface(TwinEEngine * engine)30 Interface::Interface(TwinEEngine *engine) : _engine(engine) {}
31
32 const int32 INSIDE = 0; // 0000
33 const int32 LEFT = 1; // 0001
34 const int32 RIGHT = 2; // 0010
35 const int32 TOP = 4; // 0100
36 const int32 BOTTOM = 8; // 1000
37
checkClipping(int32 x,int32 y) const38 int32 Interface::checkClipping(int32 x, int32 y) const {
39 int32 code = INSIDE;
40 if (x < _clip.left) {
41 code |= LEFT;
42 } else if (x > _clip.right) {
43 code |= RIGHT;
44 }
45 if (y < _clip.top) {
46 code |= TOP;
47 } else if (y > _clip.bottom) {
48 code |= BOTTOM;
49 }
50 return code;
51 }
52
drawLine(int32 startWidth,int32 startHeight,int32 endWidth,int32 endHeight,uint8 lineColor)53 bool Interface::drawLine(int32 startWidth, int32 startHeight, int32 endWidth, int32 endHeight, uint8 lineColor) {
54 // draw line from left to right
55 if (startWidth > endWidth) {
56 SWAP(endWidth, startWidth);
57 SWAP(endHeight, startHeight);
58 }
59
60 // Perform proper clipping (CohenSutherland algorithm)
61 int32 outcode0 = checkClipping(startWidth, startHeight);
62 int32 outcode1 = checkClipping(endWidth, endHeight);
63
64 while ((outcode0 | outcode1) != INSIDE) {
65 if ((outcode0 & outcode1) != INSIDE && outcode0 != INSIDE) {
66 return false; // Reject lines which are behind one clipping plane
67 }
68
69 // At least one endpoint is outside the clip rectangle; pick it.
70 const int32 outcodeOut = outcode0 ? outcode0 : outcode1;
71
72 int32 x = 0;
73 int32 y = 0;
74 if (outcodeOut & TOP) { // point is above the clip rectangle
75 x = startWidth + (int)((endWidth - startWidth) * (float)(_clip.top - startHeight) / (float)(endHeight - startHeight));
76 y = _clip.top;
77 } else if (outcodeOut & BOTTOM) { // point is below the clip rectangle
78 x = startWidth + (int)((endWidth - startWidth) * (float)(_clip.bottom - startHeight) / (float)(endHeight - startHeight));
79 y = _clip.bottom;
80 } else if (outcodeOut & RIGHT) { // point is to the right of clip rectangle
81 y = startHeight + (int)((endHeight - startHeight) * (float)(_clip.right - startWidth) / (float)(endWidth - startWidth));
82 x = _clip.right;
83 } else if (outcodeOut & LEFT) { // point is to the left of clip rectangle
84 y = startHeight + (int)((endHeight - startHeight) * (float)(_clip.left - startWidth) / (float)(endWidth - startWidth));
85 x = _clip.left;
86 }
87
88 // Clip the point
89 if (outcodeOut == outcode0) {
90 startWidth = x;
91 startHeight = y;
92 outcode0 = checkClipping(startWidth, startHeight);
93 } else {
94 endWidth = x;
95 endHeight = y;
96 outcode1 = checkClipping(endWidth, endHeight);
97 }
98 }
99
100 int32 pitch = _engine->width();
101 endWidth -= startWidth;
102 endHeight -= startHeight;
103 if (endHeight < 0) {
104 pitch = -pitch;
105 endHeight = -endHeight;
106 }
107
108 uint8 *out = (uint8*)_engine->_frontVideoBuffer.getBasePtr(startWidth, startHeight);
109 _engine->_frontVideoBuffer.addDirtyRect(Common::Rect(startWidth, startHeight, startWidth + endWidth, startHeight + endHeight));
110
111 if (endWidth < endHeight) { // significant slope
112 SWAP(endWidth, endHeight);
113 const int16 var2 = endWidth << 1;
114 startHeight = endWidth;
115 endHeight <<= 1;
116 endWidth++;
117 do {
118 *out = lineColor;
119 startHeight -= endHeight;
120 if (startHeight > 0) {
121 out += pitch;
122 } else {
123 startHeight += var2;
124 out += pitch + 1;
125 }
126 } while (--endWidth);
127 } else { // reduced slope
128 const int16 var2 = endWidth << 1;
129 startHeight = endWidth;
130 endHeight <<= 1;
131 endWidth++;
132 do {
133 *out++ = lineColor;
134 startHeight -= endHeight;
135 if (startHeight < 0) {
136 startHeight += var2;
137 out += pitch;
138 }
139 } while (--endWidth);
140 }
141 return true;
142 }
143
blitBox(const Common::Rect & rect,const Graphics::ManagedSurface & source,Graphics::ManagedSurface & dest)144 void Interface::blitBox(const Common::Rect &rect, const Graphics::ManagedSurface &source, Graphics::ManagedSurface &dest) {
145 Common::Rect r(rect);
146 r.right += 1;
147 r.bottom += 1;
148 dest.blitFrom(source, r, Common::Point(rect.left, rect.top));
149 }
150
drawTransparentBox(const Common::Rect & rect,int32 colorAdj)151 void Interface::drawTransparentBox(const Common::Rect &rect, int32 colorAdj) {
152 Common::Rect r = rect;
153 r.clip(_engine->rect());
154 if (r.isEmpty()) {
155 return;
156 }
157
158 uint8 *pos = (uint8*)_engine->_frontVideoBuffer.getBasePtr(0, r.top);
159
160 for (int32 y = r.top; y <= r.bottom; ++y) {
161 for (int32 x = r.left; x <= r.right; ++x) {
162 const int8 color = (pos[x] & 0x0F) - colorAdj;
163 const int8 color2 = pos[x] & 0xF0;
164 if (color < 0) {
165 pos[x] = color2;
166 } else {
167 pos[x] = color + color2;
168 }
169 }
170 pos += _engine->_frontVideoBuffer.pitch;
171 }
172 _engine->_frontVideoBuffer.addDirtyRect(r);
173 }
174
drawFilledRect(const Common::Rect & rect,uint8 colorIndex)175 void Interface::drawFilledRect(const Common::Rect &rect, uint8 colorIndex) {
176 if (!rect.isValidRect()) {
177 return;
178 }
179 _engine->_frontVideoBuffer.fillRect(Common::Rect(rect.left, rect.top, rect.right + 1, rect.bottom + 1), colorIndex);
180 }
181
setClip(const Common::Rect & rect)182 bool Interface::setClip(const Common::Rect &rect) {
183 if (!_clip.isValidRect()) {
184 return false;
185 }
186 _clip = rect;
187 _clip.clip(_engine->rect());
188 return true;
189 }
190
saveClip()191 void Interface::saveClip() {
192 _savedClip = _clip;
193 }
194
loadClip()195 void Interface::loadClip() {
196 _clip = _savedClip;
197 }
198
resetClip()199 void Interface::resetClip() {
200 _clip = _engine->rect();
201 }
202
203 } // namespace TwinE
204