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