1 /************************************************************************
2 * *
3 * FreeSynd - a remake of the classic Bullfrog game "Syndicate". *
4 * *
5 * Copyright (C) 2005 Stuart Binge <skbinge@gmail.com> *
6 * Copyright (C) 2005 Joost Peters <joostp@users.sourceforge.net> *
7 * Copyright (C) 2006 Trent Waddington <qg@biodome.org> *
8 * Copyright (C) 2006 Tarjei Knapstad <tarjei.knapstad@gmail.com> *
9 * Copyright (C) 2010 Bohdan Stelmakh <chamel@users.sourceforge.net> *
10 * *
11 * This program is free software; you can redistribute it and / or *
12 * modify it under the terms of the GNU General Public License as *
13 * published by the Free Software Foundation; either version 2 of the *
14 * License, or (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
19 * General Public License for more details. *
20 * *
21 * You can view the GNU General Public License, online, at the GNU *
22 * project's web site; see <http://www.gnu.org/licenses/gpl.html>. *
23 * The full text of the license is also included in the file COPYING. *
24 * *
25 ************************************************************************/
26
27 #include "common.h"
28 #include "screen.h"
29 #include "utils/file.h"
30
Screen(int width,int height)31 Screen::Screen(int width, int height)
32 :width_(width)
33 , height_(height)
34 , pixels_(NULL)
35 , dirty_(false)
36 , data_logo_(NULL), data_logo_copy_(NULL)
37 , data_mini_logo_(NULL), data_mini_logo_copy_(NULL)
38 {
39 assert(width_ > 0);
40 assert(height_ > 0);
41
42 pixels_ = new uint8[width_ * height_];
43 }
44
~Screen()45 Screen::~Screen()
46 {
47 delete[] pixels_;
48 if (data_logo_)
49 delete[] data_logo_;
50 if (data_logo_copy_)
51 delete[] data_logo_copy_;
52 if (data_mini_logo_)
53 delete[] data_mini_logo_;
54 if (data_mini_logo_copy_)
55 delete[] data_mini_logo_copy_;
56 }
57
clear(uint8 color)58 void Screen::clear(uint8 color)
59 {
60 memset(pixels_, color, width_ * height_);
61 dirty_ = true;
62 }
63 /*!
64 * Blits data to screen
65 * @param x position by x coord
66 * @param y position by y coord
67 * @param width data's width
68 * @param height data's height
69 * @param pixeldata pointer to data to be blitted
70 * @param flipped draw flipped
71 * @param stride actual data width (Sprite class related)
72 * @sa sprite.h
73 */
blit(int x,int y,int width,int height,const uint8 * pixeldata,bool flipped,int stride)74 void Screen::blit(int x, int y, int width, int height,
75 const uint8 * pixeldata, bool flipped, int stride)
76 {
77 if (x + width < 0 || y + height < 0 || x >= width_ || y >= height_)
78 return;
79
80 int clipped_x = x < 0 ? 0 : x;
81 int clipped_y = y < 0 ? 0 : y;
82
83 int sx = x < 0 ? -x : 0;
84 int sy = y < 0 ? -y : 0;
85
86 int w = x < 0 ? x + width : x + width > width_ ? width_ - x : width;
87 int h = y < 0
88 ? y + height : y + height > height_ ? height_ - y : height;
89
90 stride = (stride == 0 ? width : stride);
91 int ofs = (flipped ? w - 1 : 0) + clipped_x;
92 uint8 *d = pixels_ + clipped_y * width_ + ofs;
93
94 if (flipped) {
95 const uint8 *s = pixeldata + sy * stride + sx + (width - w);
96 for (int j = 0; j < h; ++j) {
97
98 const uint8 *cp_s = s;
99 s += stride;
100 uint8 *cp_d = d;
101 d += width_;
102 for (int i = 0; i < w; ++i) {
103 uint8 c = *cp_s++;
104
105 if (c != 255)
106 *cp_d = c;
107 cp_d--;
108 }
109 }
110 } else {
111 const uint8 *s = pixeldata + sy * stride + sx;
112 for (int j = 0; j < h; ++j) {
113
114 const uint8 *cp_s = s;
115 s += stride;
116 uint8 *cp_d = d;
117 d += width_;
118 for (int i = 0; i < w; ++i) {
119 uint8 c = *cp_s++;
120
121 if (c != 255)
122 *cp_d = c;
123 cp_d++;
124 }
125 }
126 }
127
128 dirty_ = true;
129 }
130
131 /*!
132 * Blits a portion of the source data to the screen a given position.
133 */
blitRect(int x,int y,int width,int height,const uint8 * pixeldata,bool flipped,int stride)134 void Screen::blitRect(int x, int y, int width, int height,
135 const uint8 * pixeldata, bool flipped, int stride)
136 {
137 if (x + width < 0 || y + height < 0 || x >= width_ || y >= height_)
138 return;
139
140 int dest_x = x < 0 ? 0 : x;
141 int dest_y = y < 0 ? 0 : y;
142
143 int clipped_w = x < 0 ? x + width : x + width > width_ ? width_ - x : width;
144 int clipped_h = y < 0
145 ? y + height : y + height > height_ ? height_ - y : height;
146
147 stride = (stride == 0 ? width : stride);
148 int ofs = (flipped ? clipped_w - 1 : 0) + dest_x;
149 uint8 *d = pixels_ + dest_y * width_ + ofs;
150
151 if (flipped) {
152 const uint8 *s = pixeldata + y * stride + x + (width - clipped_w);
153 for (int j = 0; j < clipped_h; ++j) {
154
155 const uint8 *cp_s = s;
156 s += stride;
157 uint8 *cp_d = d;
158 d += width_;
159 for (int i = 0; i < clipped_w; ++i) {
160 uint8 c = *cp_s++;
161
162 if (c != 255)
163 *cp_d = c;
164 cp_d--;
165 }
166 }
167 } else {
168 const uint8 *s = pixeldata + y * stride + x;
169 for (int j = 0; j < clipped_h; ++j) {
170
171 const uint8 *cp_s = s;
172 s += stride;
173 uint8 *cp_d = d;
174 d += width_;
175 for (int i = 0; i < clipped_w; ++i) {
176 uint8 c = *cp_s++;
177
178 if (c != 255)
179 *cp_d = c;
180 cp_d++;
181 }
182 }
183 }
184
185 dirty_ = true;
186 }
187
scale2x(int x,int y,int width,int height,const uint8 * pixeldata,int stride,bool transp)188 void Screen::scale2x(int x, int y, int width, int height,
189 const uint8 * pixeldata, int stride, bool transp)
190 {
191 stride = (stride == 0 ? width : stride);
192
193 for (int j = 0; j < height; ++j) {
194 uint8 *d = pixels_ + (y + j * 2) * width_ + x;
195
196 for (int i = 0; i < width; ++i, d += 2) {
197 uint8 c = *(pixeldata + i);
198 if (c != 255 || !transp) {
199 *(d + 0) = c;
200 *(d + 1) = c;
201 *(d + 0 + width_) = c;
202 *(d + 1 + width_) = c;
203 }
204 }
205
206 pixeldata += stride;
207 }
208
209 dirty_ = true;
210 }
211
drawVLine(int x,int y,int length,uint8 color)212 void Screen::drawVLine(int x, int y, int length, uint8 color)
213 {
214 if (x < 0 || x >= width_ || y + length < 0 || y >= height_)
215 return;
216
217 length = y + length >= height_ ? height_ - y : length;
218 if (y < 0) {
219 length += y;
220 y = 0;
221 }
222 if (length < 1)
223 return;
224
225 uint8 *pixel = pixels_ + y * width_ + x;
226 while (length--) {
227 *pixel = color;
228 pixel += width_;
229 }
230
231 dirty_ = true;
232 }
233
drawHLine(int x,int y,int length,uint8 color)234 void Screen::drawHLine(int x, int y, int length, uint8 color)
235 {
236 if ((x + length) < 0 || x >= width_ || y < 0 || y >= height_)
237 return;
238
239 length = x + length >= width_ ? width_ - x : length;
240 if (x < 0) {
241 length += x;
242 x = 0;
243 }
244 if (length < 1)
245 return;
246
247 uint8 *pixel_ptr = pixels_ + y * width_ + x;
248 while (length--)
249 *pixel_ptr++ = color;
250
251 dirty_ = true;
252 }
253
numLogos()254 int Screen::numLogos()
255 {
256 return size_logo_ / (32 * 32);
257 }
258
drawLogo(int x,int y,int logo,int colour,bool mini)259 void Screen::drawLogo(int x, int y, int logo, int colour, bool mini)
260 {
261 if (data_logo_ == NULL) {
262 data_logo_ = File::loadOriginalFile("mlogos.dat", size_logo_);
263 data_logo_copy_ = new uint8[size_logo_];
264 }
265 if (data_mini_logo_ == NULL) {
266 data_mini_logo_ = File::loadOriginalFile("mminlogo.dat", size_mini_logo_);
267 data_mini_logo_copy_ = new uint8[size_mini_logo_];
268 }
269
270 for (int i = 0; i < size_logo_; i++)
271 if (data_logo_[i] == 0xFE)
272 data_logo_copy_[i] = colour;
273 else
274 data_logo_copy_[i] = data_logo_[i];
275 for (int i = 0; i < size_mini_logo_; i++)
276 if (data_mini_logo_[i] == 0xFE)
277 data_mini_logo_copy_[i] = colour;
278 else
279 data_mini_logo_copy_[i] = data_mini_logo_[i];
280 if (mini)
281 scale2x(x, y, 16, 16, data_mini_logo_copy_ + logo * 16 * 16, 16);
282 else
283 scale2x(x, y, 32, 32, data_logo_copy_ + logo * 32 * 32, 32);
284
285 dirty_ = true;
286 }
287
288 // Taken from SDL_gfx
289 #define ABS(a) (((a)<0) ? -(a) : (a))
drawLine(int x1,int y1,int x2,int y2,uint8 color,int skip,int off)290 void Screen::drawLine(int x1, int y1, int x2, int y2, uint8 color,
291 int skip, int off)
292 {
293 int pixx, pixy;
294 int x, y;
295 int dx, dy;
296 int sx, sy;
297 int swaptmp;
298 uint8 *pixel;
299
300 /*
301 * Variable setup
302 */
303 dx = x2 - x1;
304 dy = y2 - y1;
305 sx = (dx >= 0) ? 1 : -1;
306 sy = (dy >= 0) ? 1 : -1;
307
308 /*
309 * No alpha blending - use fast pixel routines
310 */
311
312 /*
313 * More variable setup
314 */
315 dx = sx * dx + 1;
316 dy = sy * dy + 1;
317 pixx = 1;
318 pixy = GAME_SCREEN_WIDTH;
319 pixel = pixels_ + pixx * (int) x1 + pixy * (int) y1;
320 pixx *= sx;
321 pixy *= sy;
322 if (dx < dy) {
323 swaptmp = dx;
324 dx = dy;
325 dy = swaptmp;
326 swaptmp = pixx;
327 pixx = pixy;
328 pixy = swaptmp;
329 }
330
331 /*
332 * Draw
333 */
334 x = 0;
335 y = 0;
336 int count = 0;
337 for (; x < dx; x++, pixel += pixx) {
338 if (skip == 0 || !(((off + count++) / skip) & 1))
339 if (pixel >= pixels_ && pixel < pixels_ + width_ * height_)
340 *pixel = color;
341 y += dy;
342 if (y >= dx) {
343 y -= dx;
344 pixel += pixy;
345 }
346 }
347
348 dirty_ = true;
349 }
350
setPixel(int x,int y,uint8 color)351 void Screen::setPixel(int x, int y, uint8 color)
352 {
353 if (x < 0 || y < 0 || x >= width_ || y >= height_)
354 return;
355 pixels_[y * width_ + x] = color;
356 dirty_ = true;
357 }
358
359
drawRect(int x,int y,int width,int height,uint8 color)360 void Screen::drawRect(int x, int y, int width, int height, uint8 color)
361 {
362 if (x < 0 || y < 0 || (x + width) > width_
363 || (y + height) > height_ || width <= 0 || height <= 0)
364 return;
365 // NOTE: we don't handle properly clipping by (x,y), do we need it?
366
367
368 for (int i = 0; i < height; i++) {
369 uint8 *p_pixels = pixels_ + x + width_ * (y + i);
370 for (int w = 0; w != width; w++)
371 *p_pixels++ = color;
372 }
373 dirty_ = true;
374 }
375
gameScreenHeight()376 int Screen::gameScreenHeight()
377 {
378 return GAME_SCREEN_HEIGHT;
379 }
380
gameScreenWidth()381 int Screen::gameScreenWidth()
382 {
383 return GAME_SCREEN_WIDTH;
384 }
385
gameScreenLeftMargin()386 int Screen::gameScreenLeftMargin()
387 {
388 return 129;
389 }
390
391