~ubuntu-branches/ubuntu/precise/widelands/precise-backports

« back to all changes in this revision

Viewing changes to src/sw16_graphic.cc

  • Committer: Bazaar Package Importer
  • Author(s): Martin Quinson
  • Date: 2005-02-14 10:41:12 UTC
  • Revision ID: james.westby@ubuntu.com-20050214104112-6v08iux9fptxpva9
Tags: upstream-build9
Import upstream version build9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2002-2004 by the Widelands Development Team
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License
 
6
 * as published by the Free Software Foundation; either version 2
 
7
 * of the License, or (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
 *
 
18
 */
 
19
/*
 
20
Management classes and functions of the 16-bit software renderer.
 
21
*/
 
22
 
 
23
#include <SDL_image.h>
 
24
#include "bob.h"
 
25
#include "editor_game_base.h"
 
26
#include "error.h"
 
27
#include "filesystem.h"
 
28
#include "map.h"
 
29
#include "player.h"
 
30
#include "sw16_graphic.h"
 
31
#include "tribe.h"
 
32
#include "overlay_manager.h"
 
33
#include "filesystem.h"
 
34
 
 
35
/*
 
36
 * Names of road terrains
 
37
 */
 
38
#define ROAD_NORMAL_PIC "pics/roadt_normal.png"
 
39
#define ROAD_BUSY_PIC   "pics/roadt_busy.png"
 
40
 
 
41
namespace Renderer_Software16
 
42
{
 
43
 
 
44
 
 
45
/*
 
46
===============
 
47
LoadImage
 
48
 
 
49
Helper function wraps around SDL_image. Returns the given image file as a
 
50
surface.
 
51
Cannot return 0, throws an exception on error.
 
52
===============
 
53
*/
 
54
SDL_Surface* LoadImage(std::string filename)
 
55
{
 
56
        FileRead fr;
 
57
        SDL_Surface* surf;
 
58
 
 
59
        fr.Open(g_fs, filename);
 
60
 
 
61
        surf = IMG_Load_RW(SDL_RWFromMem(fr.Data(0), fr.GetSize()), 1);
 
62
        if (!surf)
 
63
                throw wexception("%s", IMG_GetError());
 
64
 
 
65
        return surf;
 
66
}
 
67
 
 
68
 
 
69
/*
 
70
==============================================================================
 
71
 
 
72
RenderTargetImpl -- wrapper around a Bitmap that can be rendered into
 
73
 
 
74
==============================================================================
 
75
*/
 
76
 
 
77
/*
 
78
===============
 
79
RenderTargetImpl::RenderTargetImpl
 
80
 
 
81
Build a render target for the given bitmap.
 
82
Note that the bitmap will not be owned by the renderer, i.e. it won't be
 
83
deleted by the destructor.
 
84
===============
 
85
*/
 
86
RenderTargetImpl::RenderTargetImpl(Bitmap* bmp)
 
87
{
 
88
        m_bitmap = bmp;
 
89
 
 
90
        reset();
 
91
}
 
92
 
 
93
 
 
94
/*
 
95
===============
 
96
RenderTargetImpl::~RenderTargetImpl
 
97
===============
 
98
*/
 
99
RenderTargetImpl::~RenderTargetImpl()
 
100
{
 
101
}
 
102
 
 
103
/*
 
104
===============
 
105
RenderTargetImpl::reset
 
106
 
 
107
Called every time before the render target is handed out by the Graphic
 
108
implementation to start in a neutral state.
 
109
===============
 
110
*/
 
111
void RenderTargetImpl::reset()
 
112
{
 
113
        m_rect.x = m_rect.y = 0;
 
114
        m_rect.w = m_bitmap->w;
 
115
        m_rect.h = m_bitmap->h;
 
116
 
 
117
        m_offset.x = m_offset.y = 0;
 
118
}
 
119
 
 
120
 
 
121
/*
 
122
===============
 
123
RenderTargetImpl::get_window [const]
 
124
 
 
125
Retrieve the current window setting.
 
126
===============
 
127
*/
 
128
void RenderTargetImpl::get_window(Rect* rc, Point* ofs) const
 
129
{
 
130
        *rc = m_rect;
 
131
        *ofs = m_offset;
 
132
}
 
133
 
 
134
 
 
135
/*
 
136
===============
 
137
RenderTargetImpl::set_window
 
138
 
 
139
Sets an arbitrary drawing window.
 
140
===============
 
141
*/
 
142
void RenderTargetImpl::set_window(const Rect& rc, const Point& ofs)
 
143
{
 
144
        m_rect = rc;
 
145
        m_offset = ofs;
 
146
 
 
147
        // safeguards clipping against the bitmap itself
 
148
        if (m_rect.x < 0) {
 
149
                m_offset.x += m_rect.x;
 
150
                m_rect.w += m_rect.x;
 
151
                m_rect.x = 0;
 
152
        }
 
153
        if (m_rect.x + m_rect.w > m_bitmap->w)
 
154
                m_rect.w = m_bitmap->w - m_rect.x;
 
155
        if (m_rect.w < 0)
 
156
                m_rect.w = 0;
 
157
 
 
158
        if (m_rect.y < 0) {
 
159
                m_offset.y += m_rect.y;
 
160
                m_rect.h += m_rect.y;
 
161
                m_rect.y = 0;
 
162
        }
 
163
        if (m_rect.y + m_rect.h > m_bitmap->h)
 
164
                m_rect.h = m_bitmap->h - m_rect.y;
 
165
        if (m_rect.h < 0)
 
166
                m_rect.h = 0;
 
167
}
 
168
 
 
169
 
 
170
/*
 
171
===============
 
172
RenderTargetImpl::enter_window
 
173
 
 
174
Builds a subwindow. rc is relative to the current drawing window. The subwindow
 
175
will be clipped appropriately.
 
176
The previous window state is returned in previous and prevofs.
 
177
 
 
178
Returns false if the subwindow is invisible. In that case, the window state is
 
179
not changed at all. Otherwise, the function returns true.
 
180
===============
 
181
*/
 
182
bool RenderTargetImpl::enter_window(const Rect& rc, Rect* previous, Point* prevofs)
 
183
{
 
184
        Point newofs(0,0);
 
185
        Rect newrect;
 
186
 
 
187
        newrect.x = rc.x + m_offset.x;
 
188
        newrect.y = rc.y + m_offset.y;
 
189
        newrect.w = rc.w;
 
190
        newrect.h = rc.h;
 
191
 
 
192
        // Clipping
 
193
        if (newrect.x < 0) {
 
194
                newofs.x = newrect.x;
 
195
                newrect.w += newrect.x;
 
196
                newrect.x = 0;
 
197
        }
 
198
        if (newrect.x + newrect.w > m_rect.w)
 
199
                newrect.w = m_rect.w - newrect.x;
 
200
        if (newrect.w <= 0)
 
201
                return false;
 
202
 
 
203
        if (newrect.y < 0) {
 
204
                newofs.y = newrect.y;
 
205
                newrect.h += newrect.y;
 
206
                newrect.y = 0;
 
207
        }
 
208
        if (newrect.y + newrect.h > m_rect.h)
 
209
                newrect.h = m_rect.h - newrect.y;
 
210
        if (newrect.h <= 0)
 
211
                return false;
 
212
 
 
213
        newrect.x += m_rect.x;
 
214
        newrect.y += m_rect.y;
 
215
 
 
216
        // Apply the changes
 
217
        if (previous)
 
218
                *previous = m_rect;
 
219
        if (prevofs)
 
220
                *prevofs = m_offset;
 
221
 
 
222
        m_rect = newrect;
 
223
        m_offset = newofs;
 
224
 
 
225
        return true;
 
226
}
 
227
 
 
228
 
 
229
/*
 
230
===============
 
231
RenderTargetImpl::get_w [const]
 
232
RenderTargetImpl::get_h [const]
 
233
 
 
234
Returns the true size of the render target (ignoring the window settings).
 
235
===============
 
236
*/
 
237
int RenderTargetImpl::get_w() const
 
238
{
 
239
        return m_bitmap->w;
 
240
}
 
241
 
 
242
int RenderTargetImpl::get_h() const
 
243
{
 
244
        return m_bitmap->h;
 
245
}
 
246
 
 
247
/*
 
248
 * Render Target: draw line
 
249
 *
 
250
 * This functions draws a (not horizontal or vertical) 
 
251
 * line in the target, using Bresenham's algorithm
 
252
 *
 
253
 * This function is still quite slow, since it draws
 
254
 * every pixel as a rectangle. So use it with care
 
255
 */
 
256
void RenderTargetImpl::draw_line(int x1, int y1, int x2, int y2, RGBColor color)
 
257
{
 
258
   int dx=x2-x1;      /* the horizontal distance of the line */
 
259
   int dy=y2-y1;      /* the vertical distance of the line */
 
260
   int dxabs=abs(dx);
 
261
   int dyabs=abs(dy);
 
262
   int sdx= dx < 0 ? -1 : 1;
 
263
   int sdy= dy < 0 ? -1 : 1; 
 
264
   int x=dyabs>>1;
 
265
   int y=dxabs>>1;
 
266
   int px=x1;
 
267
   int py=y1;
 
268
 
 
269
   draw_rect(px,py,1,1,color);
 
270
 
 
271
   if (dxabs>=dyabs) /* the line is more horizontal than vertical */
 
272
   {
 
273
      for(int i=0;i<dxabs;i++)
 
274
      {
 
275
         y+=dyabs;
 
276
         if (y>=dxabs)
 
277
         {
 
278
            y-=dxabs;
 
279
            py+=sdy;
 
280
         }
 
281
         px+=sdx;
 
282
         draw_rect(px,py,1,1,color);
 
283
      }
 
284
   }
 
285
   else /* the line is more vertical than horizontal */
 
286
   {
 
287
      for(int i=0;i<dyabs;i++)
 
288
      {
 
289
         x+=dxabs;
 
290
         if (x>=dyabs)
 
291
         {
 
292
            x-=dyabs;
 
293
            px+=sdx;
 
294
         }
 
295
         py+=sdy;
 
296
         draw_rect(px,py,1,1,color);
 
297
      }
 
298
   }
 
299
}
 
300
/*
 
301
===============
 
302
RenderTargetImpl::draw_rect
 
303
RenderTargetImpl::fill_rect
 
304
RenderTargetImpl::brighten_rect
 
305
RenderTargetImpl::clear
 
306
 
 
307
Clip against window and pass those primitives along to the bitmap.
 
308
===============
 
309
*/
 
310
void RenderTargetImpl::draw_rect(int x, int y, int w, int h, RGBColor clr)
 
311
{
 
312
        x += m_offset.x;
 
313
        y += m_offset.y;
 
314
 
 
315
        if (x < 0) {
 
316
                w += x;
 
317
                x = 0;
 
318
        }
 
319
        if (x + w > m_rect.w)
 
320
                w = m_rect.w - x;
 
321
        if (w <= 0)
 
322
                return;
 
323
 
 
324
        if (y < 0) {
 
325
                h += y;
 
326
                y = 0;
 
327
        }
 
328
        if (y + h > m_rect.h)
 
329
                h = m_rect.h - y;
 
330
        if (h <= 0)
 
331
                return;
 
332
 
 
333
        m_bitmap->draw_rect(Rect(x + m_rect.x, y + m_rect.y, w, h), clr);
 
334
}
 
335
 
 
336
void RenderTargetImpl::fill_rect(int x, int y, int w, int h, RGBColor clr)
 
337
{
 
338
        x += m_offset.x;
 
339
        y += m_offset.y;
 
340
 
 
341
        if (x < 0) {
 
342
                w += x;
 
343
                x = 0;
 
344
        }
 
345
        if (x + w > m_rect.w)
 
346
                w = m_rect.w - x;
 
347
        if (w <= 0)
 
348
                return;
 
349
 
 
350
        if (y < 0) {
 
351
                h += y;
 
352
                y = 0;
 
353
        }
 
354
        if (y + h > m_rect.h)
 
355
                h = m_rect.h - y;
 
356
        if (h <= 0)
 
357
                return;
 
358
 
 
359
        m_bitmap->fill_rect(Rect(x + m_rect.x, y + m_rect.y, w, h), clr);
 
360
}
 
361
 
 
362
void RenderTargetImpl::brighten_rect(int x, int y, int w, int h, int factor)
 
363
{
 
364
        x += m_offset.x;
 
365
        y += m_offset.y;
 
366
 
 
367
        if (x < 0) {
 
368
                w += x;
 
369
                x = 0;
 
370
        }
 
371
        if (x + w > m_rect.w)
 
372
                w = m_rect.w - x;
 
373
        if (w <= 0)
 
374
                return;
 
375
 
 
376
        if (y < 0) {
 
377
                h += y;
 
378
                y = 0;
 
379
        }
 
380
        if (y + h > m_rect.h)
 
381
                h = m_rect.h - y;
 
382
        if (h <= 0)
 
383
                return;
 
384
 
 
385
        m_bitmap->brighten_rect(Rect(x + m_rect.x, y + m_rect.y, w, h), factor);
 
386
}
 
387
 
 
388
void RenderTargetImpl::clear(void)
 
389
{
 
390
        if (!m_rect.x && !m_rect.y && m_rect.w == m_bitmap->w && m_rect.h == m_bitmap->h)
 
391
                m_bitmap->clear();
 
392
        else
 
393
                m_bitmap->fill_rect(Rect(m_rect.x, m_rect.y, m_rect.w, m_rect.h), RGBColor(0,0,0));
 
394
}
 
395
 
 
396
 
 
397
/*
 
398
===============
 
399
RenderTargetImpl::doblit
 
400
 
 
401
Clip against window and source bitmap, then call the Bitmap blit routine.
 
402
===============
 
403
*/
 
404
void RenderTargetImpl::doblit(Point dst, Bitmap* src, Rect srcrc)
 
405
{
 
406
        dst.x += m_offset.x;
 
407
        dst.y += m_offset.y;
 
408
 
 
409
        // Clipping
 
410
        if (dst.x < 0) {
 
411
                srcrc.x -= dst.x;
 
412
                srcrc.w += dst.x;
 
413
                dst.x = 0;
 
414
        }
 
415
        if (srcrc.x < 0) {
 
416
                dst.x -= srcrc.x;
 
417
                srcrc.w += srcrc.x;
 
418
                srcrc.x = 0;
 
419
        }
 
420
        if (dst.x + srcrc.w > m_rect.w)
 
421
                srcrc.w = m_rect.w - dst.x;
 
422
        if (srcrc.w <= 0)
 
423
                return;
 
424
 
 
425
        if (dst.y < 0) {
 
426
                srcrc.y -= dst.y;
 
427
                srcrc.h += dst.y;
 
428
                dst.y = 0;
 
429
        }
 
430
        if (srcrc.y < 0) {
 
431
                dst.y -= srcrc.y;
 
432
                srcrc.h += srcrc.y;
 
433
                srcrc.y = 0;
 
434
        }
 
435
        if (dst.y + srcrc.h > m_rect.h)
 
436
                srcrc.h = m_rect.h - dst.y;
 
437
        if (srcrc.h <= 0)
 
438
                return;
 
439
 
 
440
        // Draw it
 
441
        m_bitmap->blit(Point(dst.x + m_rect.x, dst.y + m_rect.y), src, srcrc);
 
442
}
 
443
 
 
444
 
 
445
/*
 
446
===============
 
447
RenderTargetImpl::blit
 
448
RenderTargetImpl::blitrect
 
449
 
 
450
Blits a blitsource into this bitmap
 
451
===============
 
452
*/
 
453
void RenderTargetImpl::blit(int dstx, int dsty, uint picture)
 
454
{
 
455
        GraphicImpl* gfx = get_graphicimpl();
 
456
        Bitmap* src = gfx->get_picture_bitmap(picture);
 
457
 
 
458
        if (src)
 
459
                doblit(Point(dstx, dsty), src, Rect(0, 0, src->w, src->h));
 
460
}
 
461
 
 
462
void RenderTargetImpl::blitrect(int dstx, int dsty, uint picture,
 
463
                                     int srcx, int srcy, int w, int h)
 
464
{
 
465
        GraphicImpl* gfx = get_graphicimpl();
 
466
        Bitmap* src = gfx->get_picture_bitmap(picture);
 
467
 
 
468
        if (src)
 
469
                doblit(Point(dstx, dsty), src, Rect(srcx, srcy, w, h));
 
470
}
 
471
 
 
472
 
 
473
/*
 
474
===============
 
475
RenderTargetImpl::tile
 
476
 
 
477
Fill the given rectangle with the given picture.
 
478
The pixel from (ofsx/ofsy) inside picture is placed at the top-left corner of
 
479
the filled rectangle.
 
480
===============
 
481
*/
 
482
void RenderTargetImpl::tile(int x, int y, int w, int h, uint picture, int ofsx, int ofsy)
 
483
{
 
484
        GraphicImpl* gfx = get_graphicimpl();
 
485
        Bitmap* src = gfx->get_picture_bitmap(picture);
 
486
 
 
487
        if (!src) {
 
488
                log("RenderTargetImpl::tile: bad picture %u\n", picture);
 
489
                return;
 
490
        }
 
491
 
 
492
        // Clipping
 
493
        x += m_offset.x;
 
494
        y += m_offset.y;
 
495
 
 
496
        if (x < 0) {
 
497
                w += x;
 
498
                x = 0;
 
499
        }
 
500
        if (x + w > m_rect.w)
 
501
                w = m_rect.w - x;
 
502
        if (w <= 0)
 
503
                return;
 
504
 
 
505
        if (y < 0) {
 
506
                h += y;
 
507
                y = 0;
 
508
        }
 
509
        if (y + h > m_rect.h)
 
510
                h = m_rect.h - y;
 
511
        if (h <= 0)
 
512
                return;
 
513
 
 
514
        // Make sure the offset is within bounds
 
515
        ofsx = ofsx % src->w;
 
516
        if (ofsx < 0)
 
517
                ofsx += src->w;
 
518
 
 
519
        ofsy = ofsy % src->h;
 
520
        if (ofsy < 0)
 
521
                ofsy += src->h;
 
522
 
 
523
        // Blit the picture into the rectangle
 
524
        int ty = 0;
 
525
 
 
526
        while(ty < h)
 
527
                {
 
528
                int tx = 0;
 
529
                int tofsx = ofsx;
 
530
                Rect srcrc;
 
531
 
 
532
                srcrc.y = ofsy;
 
533
                srcrc.h = src->h - ofsy;
 
534
                if (ty + srcrc.h > h)
 
535
                        srcrc.h = h - ty;
 
536
 
 
537
                while(tx < w)
 
538
                        {
 
539
                        srcrc.x = tofsx;
 
540
                        srcrc.w = src->w - tofsx;
 
541
                        if (tx + srcrc.w > w)
 
542
                                srcrc.w = w - tx;
 
543
 
 
544
                        m_bitmap->blit(Point(m_rect.x + x + tx, m_rect.y + y + ty), src, srcrc);
 
545
 
 
546
                        tx += srcrc.w;
 
547
                        tofsx = 0;
 
548
                        }
 
549
 
 
550
                ty += srcrc.h;
 
551
                ofsy = 0;
 
552
                }
 
553
}
 
554
 
 
555
/*
 
556
===============
 
557
draw_overlays
 
558
 
 
559
Draw build help, frontier and registered overlays
 
560
===============
 
561
*/
 
562
static void draw_overlays(RenderTargetImpl* dst, Editor_Game_Base* egbase, const std::vector<bool>* visibility, FCoords fc, Point pos,
 
563
                 FCoords fcr, Point posr, FCoords fcbl, Point posbl, FCoords fcbr, Point posbr)
 
564
{
 
565
        // Render frontier
 
566
   uchar player;
 
567
   if((player=egbase->get_map()->get_overlay_manager()->is_frontier_field(fc))) {
 
568
      Player *ownerplayer = egbase->get_player(player);
 
569
      uint anim = ownerplayer->get_tribe()->get_frontier_anim();
 
570
      const RGBColor* playercolors = ownerplayer->get_playercolor();
 
571
 
 
572
      dst->drawanim(pos.x, pos.y, anim, 0, playercolors);
 
573
 
 
574
      // check to the right
 
575
      if(egbase->get_map()->get_overlay_manager()->draw_border_to_right(fc))
 
576
         dst->drawanim((pos.x+posr.x)/2, (pos.y+posr.y)/2, anim, 0, playercolors);
 
577
      // check to the bottom left
 
578
      if(egbase->get_map()->get_overlay_manager()->draw_border_to_bottom_left(fc))
 
579
         dst->drawanim((pos.x+posbl.x)/2, (pos.y+posbl.y)/2, anim, 0, playercolors);
 
580
      // check to the bottom right
 
581
      if(egbase->get_map()->get_overlay_manager()->draw_border_to_right(fcbl))
 
582
         dst->drawanim((pos.x+posbr.x)/2, (pos.y+posbr.y)/2, anim, 0, playercolors);
 
583
   }
 
584
 
 
585
        // Draw normal buildhelp
 
586
   Overlay_Manager::Overlay_Info overlay_info[MAX_OVERLAYS_PER_FIELD];
 
587
   int num_overlays=egbase->get_map()->get_overlay_manager()->get_overlays(fc, overlay_info);
 
588
 
 
589
   int i;
 
590
   for(i=0; i<num_overlays; i++) {
 
591
      int x = pos.x - overlay_info[i].hotspot_x;
 
592
      int y = pos.y - overlay_info[i].hotspot_y;
 
593
 
 
594
      dst->blit(x,y,overlay_info[i].picid);
 
595
   }
 
596
}
 
597
 
 
598
 
 
599
/*
 
600
===============
 
601
RenderTargetImpl::rendermap
 
602
 
 
603
Render the map into the current drawing window.
 
604
viewofs is the offset of the upper left corner of the window into the map,
 
605
in pixels.
 
606
===============
 
607
*/
 
608
void RenderTargetImpl::rendermap(Editor_Game_Base* egbase, const std::vector<bool>* visibility, Point viewofs)
 
609
{
 
610
        Bitmap dst;
 
611
 
 
612
        viewofs.x -= m_offset.x;
 
613
        viewofs.y -= m_offset.y;
 
614
 
 
615
        dst.pixels = &m_bitmap->pixels[m_rect.y * m_bitmap->pitch + m_rect.x];
 
616
        dst.pitch = m_bitmap->pitch;
 
617
        dst.w = m_rect.w;
 
618
        dst.h = m_rect.h;
 
619
        dst.hasclrkey = false; // should be irrelevant
 
620
 
 
621
        // Completely clear the window
 
622
        dst.clear();
 
623
 
 
624
        // Actually draw the map. Loop through fields row by row
 
625
        // For each field, draw ground textures, then roads, then immovables
 
626
        // (and borders), then bobs, then overlay stuff (build icons etc...)
 
627
        //Player *player = m_player->get_player();
 
628
        Map* map = egbase->get_map();
 
629
        int mapwidth = map->get_width();
 
630
        int minfx, minfy;
 
631
        int maxfx, maxfy;
 
632
 
 
633
        minfx = (viewofs.x + (FIELD_WIDTH>>1)) / FIELD_WIDTH - 1; // hack to prevent negative numbers
 
634
        minfy = viewofs.y / (FIELD_HEIGHT>>1);
 
635
        maxfx = (viewofs.x + (FIELD_WIDTH>>1) + dst.w) / FIELD_WIDTH;
 
636
        maxfy = (viewofs.y + dst.h) / (FIELD_HEIGHT>>1);
 
637
        maxfx += 1; // because of big buildings
 
638
        maxfy += 10; // necessary because of heights
 
639
 
 
640
        //log("%i %i -> %i %i\n", minfx, minfy, maxfx, maxfy);
 
641
        int dx = maxfx - minfx + 1;
 
642
        int dy = maxfy - minfy + 1;
 
643
   int linear_fy = minfy;
 
644
 
 
645
        while(dy--) {
 
646
                int linear_fx = minfx;
 
647
                FCoords f, bl, tl;
 
648
                int posx, posy;
 
649
                int blposx, bposy;
 
650
                int tlposx, tposy;
 
651
 
 
652
                // Use linear (non-wrapped) coordinates to calculate on-screen pos
 
653
                map->get_basepix(Coords(linear_fx, linear_fy), &posx, &posy);
 
654
                posx -= viewofs.x;
 
655
                posy -= viewofs.y;
 
656
 
 
657
                // Get linear bottom-left coordinate
 
658
                bl.y = linear_fy+1;
 
659
                bl.x = linear_fx - (bl.y&1);
 
660
 
 
661
                map->get_basepix(bl, &blposx, &bposy);
 
662
                blposx -= viewofs.x;
 
663
                bposy -= viewofs.y;
 
664
 
 
665
                // Get linear top-left coordinates
 
666
                tl.y = linear_fy-1;
 
667
                tl.x = linear_fx - (tl.y&1);
 
668
 
 
669
                map->get_basepix(tl, &tlposx, &tposy);
 
670
                tlposx -= viewofs.x;
 
671
                tposy -= viewofs.y;
 
672
 
 
673
                // Calculate safe (bounded) field coordinates and get field pointers
 
674
                f.x = linear_fx;
 
675
                f.y = linear_fy;
 
676
                map->normalize_coords(&f);
 
677
                map->normalize_coords(&bl);
 
678
                map->normalize_coords(&tl);
 
679
 
 
680
                f.field = map->get_field(f);
 
681
                bl.field = map->get_field(bl);
 
682
                tl.field = map->get_field(tl);
 
683
 
 
684
                int count = dx;
 
685
                while(count--) {
 
686
                        FCoords br, r, l, tr;
 
687
                        int rposx, brposx, lposx, trposx;
 
688
                        bool render_r=true;
 
689
                        bool render_b=true;
 
690
 
 
691
                        map->get_rn(f, &r);
 
692
                        rposx = posx + FIELD_WIDTH;
 
693
 
 
694
                        map->get_ln(f, &l);
 
695
                        lposx = posx - FIELD_WIDTH;
 
696
 
 
697
                        map->get_rn(bl, &br);
 
698
                        brposx = blposx + FIELD_WIDTH;
 
699
 
 
700
                        map->get_rn(tl, &tr);
 
701
                        trposx = tlposx + FIELD_WIDTH;
 
702
 
 
703
                        if (visibility) {
 
704
                                if (!(*visibility)[f.y*mapwidth + f.x] ||
 
705
                                         !(*visibility)[br.y*mapwidth + br.x]) {
 
706
                                        render_r=false;
 
707
                                        render_b=false;
 
708
                                } else {
 
709
                                        if(!(*visibility)[bl.y*mapwidth + bl.x])
 
710
                                                render_b=false;
 
711
                                        if(!(*visibility)[r.y*mapwidth + r.x])
 
712
                                                render_r=false;
 
713
                                }
 
714
                        }
 
715
 
 
716
                        // Render stuff that belongs to ground triangles
 
717
                        if (render_b || render_r) {
 
718
                                uchar roads = f.field->get_roads();
 
719
 
 
720
                                roads |= egbase->get_map()->get_overlay_manager()->get_road_overlay(f);
 
721
 
 
722
                                dst.draw_field(f.field, r.field, bl.field, br.field, l.field, tr.field,
 
723
                                                posx, rposx, posy, blposx, brposx, bposy, roads, render_r, render_b);
 
724
                        }
 
725
 
 
726
         // Render stuff that belongs to the field node
 
727
                        if (!visibility || (*visibility)[f.y*mapwidth + f.x])
 
728
         {
 
729
            Point wh_pos(posx, posy - MULTIPLY_WITH_HEIGHT_FACTOR(f.field->get_height()));
 
730
 
 
731
            // Render bobs
 
732
            // TODO - rendering order?
 
733
            // This must be defined somewho. some bobs have a higher priority than others
 
734
            //  ^-- maybe this priority is a moving vs. non-moving bobs thing?
 
735
            // draw_ground implies that this doesn't render map objects.
 
736
            // are there any overdraw issues with the current rendering order?
 
737
 
 
738
            // Draw Map_Objects hooked to this field
 
739
            BaseImmovable *imm = f.field->get_immovable();
 
740
 
 
741
            assert(egbase);
 
742
 
 
743
            if (imm)
 
744
               imm->draw(egbase, this, f, wh_pos);
 
745
 
 
746
            Bob *bob = f.field->get_first_bob();
 
747
            while(bob) {
 
748
               bob->draw(egbase, this, wh_pos);
 
749
               bob = bob->get_next_bob();
 
750
            }
 
751
 
 
752
            // Draw buildhelp, road buildhelp
 
753
            draw_overlays(this, egbase, visibility, f, wh_pos,
 
754
                  r, Point(rposx, posy-MULTIPLY_WITH_HEIGHT_FACTOR(r.field->get_height())),
 
755
                  bl, Point(blposx, bposy-MULTIPLY_WITH_HEIGHT_FACTOR(bl.field->get_height())),
 
756
                  br, Point(brposx, bposy-MULTIPLY_WITH_HEIGHT_FACTOR(br.field->get_height())));
 
757
         }
 
758
 
 
759
 
 
760
                        // Advance to next field in row
 
761
                        bl = br;
 
762
                        blposx = brposx;
 
763
 
 
764
                        f = r;
 
765
                        posx = rposx;
 
766
 
 
767
                        tl = tr;
 
768
                        tlposx = trposx;
 
769
                }
 
770
 
 
771
                linear_fy++;
 
772
        }
 
773
}
 
774
 
 
775
 
 
776
/*
 
777
===============
 
778
RenderTargetImpl::renderminimap
 
779
 
 
780
Renders a minimap into the current window.
 
781
The field at viewpt will be in the top-left corner of the window.
 
782
flags specifies what information to display (see Minimap_XXX enums).
 
783
===============
 
784
*/
 
785
void RenderTargetImpl::renderminimap(Editor_Game_Base* egbase, const std::vector<bool>* visibility, Coords viewpt, uint flags)
 
786
{
 
787
        Rect rc;
 
788
 
 
789
        // The entire clipping rect will be used for drawing
 
790
        rc = m_rect;
 
791
 
 
792
        // Calculate the field at the top-left corner of the clipping rect
 
793
        viewpt.x -= m_offset.x;
 
794
        viewpt.y -= m_offset.y;
 
795
 
 
796
        m_bitmap->draw_minimap(egbase, visibility, rc, viewpt, flags);
 
797
}
 
798
 
 
799
 
 
800
/*
 
801
===============
 
802
RenderTargetImpl::drawanim
 
803
 
 
804
Draws a frame of an animation at the given location
 
805
===============
 
806
*/
 
807
void RenderTargetImpl::drawanim(int dstx, int dsty, uint animation, uint time, const RGBColor* plrclrs)
 
808
{
 
809
        const AnimationData* data = g_anim.get_animation(animation);
 
810
        const AnimationGfx* gfx = get_graphicimpl()->get_animation(animation);
 
811
        const AnimFrame* frame;
 
812
        Rect rc;
 
813
 
 
814
        if (!data || !gfx) {
 
815
                log("WARNING: Animation %i doesn't exist\n", animation);
 
816
                return;
 
817
        }
 
818
 
 
819
        // Get the frame and its data
 
820
        frame = gfx->get_frame((time / data->frametime) % gfx->get_nrframes());
 
821
        dstx += m_offset.x;
 
822
        dsty += m_offset.y;
 
823
 
 
824
        dstx -= frame->hotspot.x;
 
825
        dsty -= frame->hotspot.y;
 
826
 
 
827
        rc.x = 0;
 
828
        rc.y = 0;
 
829
        rc.w = frame->width;
 
830
        rc.h = frame->height;
 
831
 
 
832
 
 
833
        // Clipping
 
834
        if (dstx < 0) {
 
835
                rc.x -= dstx;
 
836
                rc.w += dstx;
 
837
                dstx = 0;
 
838
        }
 
839
        if (dstx + rc.w > m_rect.w)
 
840
                rc.w = m_rect.w - dstx;
 
841
        if (rc.w <= 0)
 
842
                return;
 
843
 
 
844
        if (dsty < 0) {
 
845
                rc.y -= dsty;
 
846
                rc.h += dsty;
 
847
                dsty = 0;
 
848
        }
 
849
        if (dsty + rc.h > m_rect.h)
 
850
                rc.h = m_rect.h - dsty;
 
851
        if (rc.h <= 0)
 
852
                return;
 
853
 
 
854
 
 
855
        // Draw it
 
856
        m_bitmap->draw_animframe(Point(dstx + m_rect.x, dsty + m_rect.y), frame, rc, plrclrs);
 
857
}
 
858
 
 
859
 
 
860
/*
 
861
===============
 
862
RenderTargetImpl::drawanimrect
 
863
 
 
864
Draws a part of a frame of an animation at the given location
 
865
===============
 
866
*/
 
867
void RenderTargetImpl::drawanimrect(int dstx, int dsty, uint animation, uint time, const RGBColor* plrclrs,
 
868
                                                                                                int srcx, int srcy, int w, int h)
 
869
{
 
870
        const AnimationData* data = g_anim.get_animation(animation);
 
871
        const AnimationGfx* gfx = get_graphicimpl()->get_animation(animation);
 
872
        const AnimFrame* frame;
 
873
        Rect rc;
 
874
 
 
875
        if (!data || !gfx) {
 
876
                log("WARNING: Animation %i doesn't exist\n", animation);
 
877
                return;
 
878
        }
 
879
 
 
880
        // Get the frame and its data
 
881
        frame = gfx->get_frame((time / data->frametime) % gfx->get_nrframes());
 
882
        dstx += m_offset.x;
 
883
        dsty += m_offset.y;
 
884
 
 
885
        dstx -= frame->hotspot.x;
 
886
        dsty -= frame->hotspot.y;
 
887
 
 
888
        dstx += srcx;
 
889
        dsty += srcy;
 
890
 
 
891
        rc.x = srcx;
 
892
        rc.y = srcy;
 
893
        rc.w = w; //frame->width;
 
894
        rc.h = h; //frame->height;
 
895
 
 
896
        // Clipping against source
 
897
        if (rc.x < 0) {
 
898
                dstx -= rc.x;
 
899
                rc.w += rc.x;
 
900
                rc.x = 0;
 
901
        }
 
902
        if (rc.x + rc.w > frame->width)
 
903
                rc.w = frame->width - rc.x;
 
904
        if (rc.w <= 0)
 
905
                return;
 
906
 
 
907
        if (rc.y < 0) {
 
908
                dsty -= rc.y;
 
909
                rc.h += rc.y;
 
910
                rc.y = 0;
 
911
        }
 
912
        if (rc.y + rc.h > frame->height)
 
913
                rc.h = frame->height - rc.y;
 
914
        if (rc.h <= 0)
 
915
                return;
 
916
 
 
917
        // Clipping against destination
 
918
        if (dstx < 0) {
 
919
                rc.x -= dstx;
 
920
                rc.w += dstx;
 
921
                dstx = 0;
 
922
        }
 
923
        if (dstx + rc.w > m_rect.w)
 
924
                rc.w = m_rect.w - dstx;
 
925
        if (rc.w <= 0)
 
926
                return;
 
927
 
 
928
        if (dsty < 0) {
 
929
                rc.y -= dsty;
 
930
                rc.h += dsty;
 
931
                dsty = 0;
 
932
        }
 
933
        if (dsty + rc.h > m_rect.h)
 
934
                rc.h = m_rect.h - dsty;
 
935
        if (rc.h <= 0)
 
936
                return;
 
937
 
 
938
 
 
939
        // Draw it
 
940
        m_bitmap->draw_animframe(Point(dstx + m_rect.x, dsty + m_rect.y), frame, rc, plrclrs);
 
941
}
 
942
 
 
943
 
 
944
/*
 
945
===============================================================================
 
946
 
 
947
GraphicImpl -- 16 bit software implementation of main graphics interface
 
948
 
 
949
===============================================================================
 
950
*/
 
951
 
 
952
/*
 
953
===============
 
954
GraphicImpl::GraphicImpl
 
955
 
 
956
Initialize the SDL video mode.
 
957
===============
 
958
*/
 
959
GraphicImpl::GraphicImpl(int w, int h, bool fullscreen)
 
960
{
 
961
        m_nr_update_rects = 0;
 
962
        m_update_fullscreen = false;
 
963
   m_roadtextures = 0;
 
964
 
 
965
        // Set video mode using SDL
 
966
        int flags = SDL_SWSURFACE;
 
967
 
 
968
        if (fullscreen)
 
969
                flags |= SDL_FULLSCREEN;
 
970
 
 
971
        m_sdlsurface = SDL_SetVideoMode(w, h, 16, flags);
 
972
        if (!m_sdlsurface)
 
973
                throw wexception("Couldn't set video mode: %s", SDL_GetError());
 
974
 
 
975
        SDL_WM_SetCaption("Widelands " VERSION, "Widelands");
 
976
 
 
977
        m_screen.w = m_sdlsurface->w;
 
978
        m_screen.h = m_sdlsurface->h;
 
979
        m_screen.pitch = m_sdlsurface->pitch / sizeof(ushort);
 
980
   m_screen_pixels_size_in_bytes=m_screen.pitch*h*sizeof(ushort);
 
981
   m_lock_sdl_surface=SDL_MUSTLOCK(m_sdlsurface);
 
982
   if(m_lock_sdl_surface) {
 
983
      m_screen.pixels = (ushort*)malloc(m_screen.pitch*h*sizeof(ushort));
 
984
   } else {
 
985
      m_screen.pixels = (ushort*)m_sdlsurface->pixels;
 
986
   }
 
987
        m_rendertarget = new RenderTargetImpl(&m_screen);
 
988
}
 
989
 
 
990
/*
 
991
===============
 
992
GraphicImpl::~GraphicImpl
 
993
 
 
994
Free the surface
 
995
===============
 
996
*/
 
997
GraphicImpl::~GraphicImpl()
 
998
{
 
999
        if(m_lock_sdl_surface)
 
1000
      free(m_screen.pixels);
 
1001
 
 
1002
   flush(0);
 
1003
 
 
1004
   if(m_roadtextures) {
 
1005
      delete m_roadtextures;
 
1006
      m_roadtextures = 0;
 
1007
   }
 
1008
   
 
1009
        delete m_rendertarget;
 
1010
        SDL_FreeSurface(m_sdlsurface);
 
1011
}
 
1012
 
 
1013
/*
 
1014
===============
 
1015
GraphicImpl::get_xres
 
1016
GraphicImpl::get_yres
 
1017
 
 
1018
Return the screen resolution
 
1019
===============
 
1020
*/
 
1021
int GraphicImpl::get_xres()
 
1022
{
 
1023
        return m_sdlsurface->w;
 
1024
}
 
1025
 
 
1026
int GraphicImpl::get_yres()
 
1027
{
 
1028
        return m_sdlsurface->h;
 
1029
}
 
1030
 
 
1031
/*
 
1032
===============
 
1033
GraphicImpl::get_render_target
 
1034
 
 
1035
Return a pointer to the RenderTarget representing the screen
 
1036
===============
 
1037
*/
 
1038
RenderTarget* GraphicImpl::get_render_target()
 
1039
{
 
1040
        m_rendertarget->reset();
 
1041
 
 
1042
        return m_rendertarget;
 
1043
}
 
1044
 
 
1045
/*
 
1046
===============
 
1047
GraphicImpl::update_fullscreen
 
1048
 
 
1049
Mark the entire screen for refreshing
 
1050
===============
 
1051
*/
 
1052
void GraphicImpl::update_fullscreen()
 
1053
{
 
1054
        m_update_fullscreen = true;
 
1055
}
 
1056
 
 
1057
/*
 
1058
===============
 
1059
GraphicImpl::update_rectangle
 
1060
 
 
1061
Mark a rectangle for refreshing
 
1062
===============
 
1063
*/
 
1064
void GraphicImpl::update_rectangle(int x, int y, int w, int h)
 
1065
{
 
1066
        if (m_nr_update_rects >= MAX_RECTS)
 
1067
                {
 
1068
                m_update_fullscreen = true;
 
1069
                return;
 
1070
                }
 
1071
 
 
1072
        m_update_rects[m_nr_update_rects].x = x;
 
1073
        m_update_rects[m_nr_update_rects].y = y;
 
1074
        m_update_rects[m_nr_update_rects].w = w;
 
1075
        m_update_rects[m_nr_update_rects].h = h;
 
1076
        ++m_nr_update_rects;
 
1077
}
 
1078
 
 
1079
/*
 
1080
===============
 
1081
GraphicImpl::need_update
 
1082
 
 
1083
Returns true if parts of the screen have been marked for refreshing.
 
1084
===============
 
1085
*/
 
1086
bool GraphicImpl::need_update()
 
1087
{
 
1088
        return m_nr_update_rects || m_update_fullscreen;
 
1089
}
 
1090
 
 
1091
/*
 
1092
===============
 
1093
GraphicImpl::refresh
 
1094
 
 
1095
Bring the screen uptodate.
 
1096
===============
 
1097
*/
 
1098
void GraphicImpl::refresh()
 
1099
{
 
1100
//      if (m_update_fullscreen)
 
1101
   if(m_lock_sdl_surface) { 
 
1102
      if(SDL_LockSurface(m_sdlsurface)) // When lock failed, do not draw this frame
 
1103
         return; 
 
1104
      memcpy(m_sdlsurface->pixels, m_screen.pixels, m_screen_pixels_size_in_bytes);
 
1105
      SDL_UnlockSurface(m_sdlsurface);
 
1106
   } 
 
1107
 
 
1108
   SDL_UpdateRect(m_sdlsurface, 0, 0, 0, 0);
 
1109
//      else
 
1110
//              {
 
1111
//              SDL_UpdateRects(m_sdlsurface, m_nr_update_rects, m_update_rects);
 
1112
//              }
 
1113
 
 
1114
        m_update_fullscreen = false;
 
1115
        m_nr_update_rects = 0;
 
1116
}
 
1117
 
 
1118
 
 
1119
/*
 
1120
===============
 
1121
GraphicImpl::flush
 
1122
 
 
1123
Remove all resources (currently pictures) from the given modules.
 
1124
If mod is 0, all pictures are flushed.
 
1125
===============
 
1126
*/
 
1127
void GraphicImpl::flush(int mod)
 
1128
{
 
1129
   uint i;
 
1130
 
 
1131
   // Flush pictures
 
1132
   for(i = 0; i < m_pictures.size(); i++) {
 
1133
      Picture* pic = &m_pictures[i];
 
1134
 
 
1135
//      NoLog("Flushing picture: %i while flushing all!\n", i);
 
1136
      if (!pic->mod)
 
1137
         continue;
 
1138
 
 
1139
 
 
1140
      if (pic->mod < 0) {
 
1141
         if (!mod)
 
1142
            log("LEAK: SW16: flush(0): non-picture %i left.\n", i+1);
 
1143
         continue;
 
1144
      }
 
1145
 
 
1146
      pic->mod &= ~mod; // unmask the mods that should be flushed
 
1147
 
 
1148
      // Once the picture is no longer in any mods, free it
 
1149
      if (!pic->mod) {
 
1150
 
 
1151
         if (pic->u.fname) {
 
1152
            m_picturemap.erase(pic->u.fname);
 
1153
            free(pic->u.fname);
 
1154
         }
 
1155
         if(pic->bitmap.pixels)
 
1156
            free(pic->bitmap.pixels);
 
1157
      }
 
1158
   }
 
1159
 
 
1160
   // Flush game items
 
1161
   if (!mod || mod & PicMod_Game) {
 
1162
      for(i = 0; i < m_maptextures.size(); i++)
 
1163
         delete m_maptextures[i];
 
1164
      m_maptextures.resize(0);
 
1165
 
 
1166
      for(i = 0; i < m_animations.size(); i++)
 
1167
         delete m_animations[i];
 
1168
      m_animations.resize(0);
 
1169
 
 
1170
      if( m_roadtextures ) {
 
1171
         delete m_roadtextures; 
 
1172
         m_roadtextures = 0;
 
1173
      }
 
1174
   }
 
1175
}
 
1176
 
 
1177
 
 
1178
/*
 
1179
===============
 
1180
GraphicImpl::get_picture
 
1181
 
 
1182
Retrieves the picture ID of the picture with the given filename.
 
1183
If the picture has already been loaded, the old ID is reused.
 
1184
The picture is placed into the module(s) given by mod.
 
1185
 
 
1186
Returns 0 (a null-picture) if the picture cannot be loaded.
 
1187
===============
 
1188
*/
 
1189
uint GraphicImpl::get_picture(int mod, const char* fname, bool buse_clrkey)
 
1190
{
 
1191
        uint id;
 
1192
 
 
1193
        // Check if the picture's already loaded
 
1194
        picmap_t::iterator it = m_picturemap.find(fname);
 
1195
 
 
1196
        if (it != m_picturemap.end())
 
1197
        {
 
1198
                id = it->second;
 
1199
        }
 
1200
        else
 
1201
        {
 
1202
                SDL_Surface* bmp;
 
1203
 
 
1204
                try
 
1205
                {
 
1206
                        bmp = LoadImage(fname);
 
1207
                }
 
1208
                catch(std::exception& e)
 
1209
                {
 
1210
                        log("WARNING: Couldn't open %s: %s\n", fname, e.what());
 
1211
                        return 0;
 
1212
                }
 
1213
 
 
1214
                SDL_Surface* cv = SDL_ConvertSurface(bmp, m_sdlsurface->format, 0);
 
1215
 
 
1216
                // Fill in a free slot in the pictures array
 
1217
                Picture* pic;
 
1218
 
 
1219
                id = find_free_picture();
 
1220
                pic = &m_pictures[id];
 
1221
 
 
1222
                pic->mod = 0; // will be filled in by caller
 
1223
                pic->u.fname = strdup(fname);
 
1224
                pic->bitmap.pixels = (ushort*)malloc(cv->w*cv->h*2);
 
1225
                pic->bitmap.w = cv->w;
 
1226
                pic->bitmap.h = cv->h;
 
1227
                pic->bitmap.pitch = cv->w;
 
1228
                pic->bitmap.hasclrkey = false;
 
1229
 
 
1230
      SDL_LockSurface(cv);  //  paranoia
 
1231
                for(int y = 0; y < cv->h; y++)
 
1232
                        memcpy(pic->bitmap.pixels + y*cv->w, (Uint8*)cv->pixels + y*cv->pitch, cv->w*2);
 
1233
      SDL_UnlockSurface(cv);
 
1234
 
 
1235
                SDL_FreeSurface(cv);
 
1236
                SDL_FreeSurface(bmp);
 
1237
 
 
1238
                m_picturemap[pic->u.fname] = id;
 
1239
   }
 
1240
 
 
1241
        m_pictures[id].mod |= mod;
 
1242
   use_clrkey(id,buse_clrkey);
 
1243
 
 
1244
        return id;
 
1245
}
 
1246
 
 
1247
void GraphicImpl::use_clrkey(uint id, bool t) {
 
1248
   if (id  >= m_pictures.size() || !m_pictures[id].mod)
 
1249
      throw wexception("get_picture_size(%i): picture doesn't exist", id);
 
1250
   m_pictures[id].bitmap.clrkey = *m_pictures[id].bitmap.pixels;
 
1251
   m_pictures[id].bitmap.hasclrkey = t;
 
1252
}
 
1253
 
 
1254
bool GraphicImpl::has_clrkey(uint id) {
 
1255
   if (id  >= m_pictures.size() || !m_pictures[id].mod)
 
1256
      throw wexception("get_picture_size(%i): picture doesn't exist", id);
 
1257
   return m_pictures[id].bitmap.hasclrkey;
 
1258
}
 
1259
 
 
1260
 
 
1261
 
 
1262
// TODO: get rid of this function (needs change of font format)
 
1263
uint GraphicImpl::get_picture(int mod, int w, int h, const ushort* data, RGBColor clrkey)
 
1264
{
 
1265
        uint id = find_free_picture();
 
1266
        Picture* pic = &m_pictures[id];
 
1267
 
 
1268
        pic->mod = mod;
 
1269
        pic->u.fname = 0;
 
1270
        pic->bitmap.pixels = (ushort*)malloc(w*h*2);
 
1271
        pic->bitmap.w = w;
 
1272
        pic->bitmap.h = h;
 
1273
        pic->bitmap.pitch = w;
 
1274
        pic->bitmap.hasclrkey = true;
 
1275
        pic->bitmap.clrkey = clrkey.pack16();
 
1276
 
 
1277
        memcpy(pic->bitmap.pixels, data, w*h*2);
 
1278
 
 
1279
        return id;
 
1280
}
 
1281
 
 
1282
 
 
1283
/*
 
1284
===============
 
1285
GraphicImpl::get_picture_size
 
1286
 
 
1287
Stores the picture size in pw and ph.
 
1288
Throws an exception if the picture doesn't exist.
 
1289
===============
 
1290
*/
 
1291
void GraphicImpl::get_picture_size(uint pic, int* pw, int* ph)
 
1292
{
 
1293
        if (pic >= m_pictures.size() || !m_pictures[pic].mod)
 
1294
                throw wexception("get_picture_size(%i): picture doesn't exist", pic);
 
1295
 
 
1296
        Bitmap* bmp = &m_pictures[pic].bitmap;
 
1297
 
 
1298
        *pw = bmp->w;
 
1299
        *ph = bmp->h;
 
1300
}
 
1301
 
 
1302
 
 
1303
/*
 
1304
===============
 
1305
GraphicImpl::create_surface
 
1306
 
 
1307
Create an offscreen surface that can be used both as target and as source for
 
1308
rendering operations. The surface is put into a normal slot in the picture
 
1309
array so the surface can be used in normal blit() operations.
 
1310
A RenderTarget for the surface can be obtained using get_surface_renderer().
 
1311
Note that surfaces do not belong to a module and must be freed explicitly.
 
1312
===============
 
1313
*/
 
1314
uint GraphicImpl::create_surface(int w, int h)
 
1315
{
 
1316
        uint id = find_free_picture();
 
1317
        Picture* pic = &m_pictures[id];
 
1318
 
 
1319
        pic->mod = -1; // mark as surface
 
1320
        pic->bitmap.pixels = (ushort*)malloc(w*h*sizeof(ushort));
 
1321
        pic->bitmap.w = w;
 
1322
        pic->bitmap.h = h;
 
1323
        pic->bitmap.pitch = w;
 
1324
        pic->bitmap.hasclrkey = false;
 
1325
        pic->u.rendertarget = new RenderTargetImpl(&pic->bitmap);
 
1326
 
 
1327
        return id;
 
1328
}
 
1329
 
 
1330
uint GraphicImpl::create_surface(int w, int h, RGBColor clrkey)
 
1331
{
 
1332
        uint id = create_surface(w, h);
 
1333
        Picture* pic = &m_pictures[id];
 
1334
 
 
1335
        pic->bitmap.hasclrkey = true;
 
1336
        pic->bitmap.clrkey = clrkey.pack16();
 
1337
 
 
1338
        return id;
 
1339
}
 
1340
 
 
1341
 
 
1342
/*
 
1343
===============
 
1344
GraphicImpl::free_surface
 
1345
 
 
1346
Free the given surface.
 
1347
Unlike normal pictures, surfaces are not freed by flush().
 
1348
===============
 
1349
*/
 
1350
void GraphicImpl::free_surface(uint picid)
 
1351
{
 
1352
        assert(picid < m_pictures.size() && m_pictures[picid].mod == -1);
 
1353
 
 
1354
        Picture* pic = &m_pictures[picid];
 
1355
 
 
1356
        delete pic->u.rendertarget;
 
1357
        free(pic->bitmap.pixels);
 
1358
        pic->mod = 0;
 
1359
}
 
1360
 
 
1361
 
 
1362
/*
 
1363
===============
 
1364
GraphicImpl::get_surface_renderer
 
1365
 
 
1366
Returns the RenderTarget for the given surface
 
1367
===============
 
1368
*/
 
1369
RenderTarget* GraphicImpl::get_surface_renderer(uint pic)
 
1370
{
 
1371
        assert(pic < m_pictures.size() && m_pictures[pic].mod == -1);
 
1372
 
 
1373
        RenderTargetImpl* rt = m_pictures[pic].u.rendertarget;
 
1374
 
 
1375
        rt->reset();
 
1376
 
 
1377
        return rt;
 
1378
}
 
1379
 
 
1380
 
 
1381
/*
 
1382
===============
 
1383
GraphicImpl::get_picture_bitmap
 
1384
 
 
1385
Returns the bitmap that belongs to the given picture ID.
 
1386
May return 0 if the given picture does not exist.
 
1387
===============
 
1388
*/
 
1389
Bitmap* GraphicImpl::get_picture_bitmap(uint id)
 
1390
{
 
1391
        if (id >= m_pictures.size())
 
1392
                return 0;
 
1393
 
 
1394
        if (!m_pictures[id].mod)
 
1395
                return 0;
 
1396
 
 
1397
        return &m_pictures[id].bitmap;
 
1398
}
 
1399
 
 
1400
 
 
1401
/*
 
1402
===============
 
1403
GraphicImpl::get_maptexture
 
1404
 
 
1405
Creates a terrain texture.
 
1406
fnametempl is a filename with possible wildcard characters '?'. The function
 
1407
fills the wildcards with decimal numbers to get the different frames of a
 
1408
texture animation. For example, if fnametempl is "foo_??.bmp", it tries
 
1409
"foo_00.bmp", "foo_01.bmp" etc...
 
1410
frametime is in milliseconds.
 
1411
 
 
1412
Returns 0 if the texture couldn't be loaded.
 
1413
 
 
1414
Note: Terrain textures are not reused, even if fnametempl matches.
 
1415
      These textures are freed when PicMod_Game is flushed.
 
1416
===============
 
1417
*/
 
1418
uint GraphicImpl::get_maptexture(const char* fnametempl, uint frametime)
 
1419
{
 
1420
        try {
 
1421
                Texture* tex = new Texture(fnametempl, frametime);
 
1422
 
 
1423
                m_maptextures.push_back(tex);
 
1424
 
 
1425
                return m_maptextures.size(); // ID 1 is at m_maptextures[0]
 
1426
        } catch(std::exception& e) {
 
1427
                log("Failed to load maptexture %s: %s\n", fnametempl, e.what());
 
1428
                return 0;
 
1429
        }
 
1430
}
 
1431
 
 
1432
 
 
1433
/*
 
1434
===============
 
1435
GraphicImpl::animate_maptextures
 
1436
 
 
1437
Advance frames for animated textures
 
1438
===============
 
1439
*/
 
1440
void GraphicImpl::animate_maptextures(uint time)
 
1441
{
 
1442
        for(uint i = 0; i < m_maptextures.size(); i++)
 
1443
                m_maptextures[i]->animate(time);
 
1444
}
 
1445
 
 
1446
 
 
1447
/*
 
1448
===============
 
1449
GraphicImpl::get_maptexture_data
 
1450
 
 
1451
Return the actual texture data associated with the given ID.
 
1452
===============
 
1453
*/
 
1454
Texture* GraphicImpl::get_maptexture_data(uint id)
 
1455
{
 
1456
        id--; // ID 1 is at m_maptextures[0]
 
1457
 
 
1458
        if (id < m_maptextures.size())
 
1459
                return m_maptextures[id];
 
1460
        else
 
1461
                return 0;
 
1462
}
 
1463
 
 
1464
/*
 
1465
================
 
1466
GraphicImp::get_road_textures
 
1467
 
 
1468
returns the road textures 
 
1469
================
 
1470
*/
 
1471
Bitmap* GraphicImpl::get_road_texture( int roadtex) {
 
1472
   if(! m_roadtextures ) {
 
1473
      // Load the road textures
 
1474
      m_roadtextures = new Road_Textures();
 
1475
      m_roadtextures->pic_road_normal = get_picture(PicMod_Game, ROAD_NORMAL_PIC, 0); 
 
1476
      m_roadtextures->pic_road_busy   = get_picture(PicMod_Game, ROAD_BUSY_PIC  , 0); 
 
1477
   }
 
1478
   if(roadtex == Road_Normal)
 
1479
      return get_picture_bitmap(m_roadtextures->pic_road_normal);
 
1480
   else 
 
1481
      return get_picture_bitmap(m_roadtextures->pic_road_busy);
 
1482
}
 
1483
 
 
1484
/*
 
1485
==============
 
1486
GraphicImp::get_texture_picture
 
1487
 
 
1488
Return Filename of texture of given ID.
 
1489
==============
 
1490
*/
 
1491
const char* GraphicImpl::get_maptexture_picture(uint id) {
 
1492
        Texture* tex = get_maptexture_data(id);
 
1493
        if (tex)
 
1494
                return tex->get_texture_picture();
 
1495
        else
 
1496
                return 0;
 
1497
}
 
1498
 
 
1499
 
 
1500
/*
 
1501
===============
 
1502
GraphicImpl::load_animations
 
1503
 
 
1504
Load all animations that are registered with the AnimationManager
 
1505
===============
 
1506
*/
 
1507
void GraphicImpl::load_animations()
 
1508
{
 
1509
        assert(!m_animations.size());
 
1510
 
 
1511
        for(uint id = 1; id <= g_anim.get_nranimations(); id++)
 
1512
                m_animations.push_back(new AnimationGfx(g_anim.get_animation(id)));
 
1513
}
 
1514
 
 
1515
 
 
1516
/*
 
1517
===============
 
1518
GraphicImpl::get_animation
 
1519
 
 
1520
Retrieve the animation graphics
 
1521
===============
 
1522
*/
 
1523
AnimationGfx* GraphicImpl::get_animation(uint anim)
 
1524
{
 
1525
        if (!anim || anim > m_animations.size())
 
1526
                return 0;
 
1527
 
 
1528
        return m_animations[anim-1];
 
1529
}
 
1530
 
 
1531
/*
 
1532
 * Return the number of frames in this animation
 
1533
 */
 
1534
int GraphicImpl::get_animation_nr_frames(uint anim) {
 
1535
   AnimationGfx* gfx=get_animation(anim);
 
1536
   return gfx->get_nrframes();
 
1537
}
 
1538
 
 
1539
/*
 
1540
===============
 
1541
GraphicImpl::get_animation_size
 
1542
 
 
1543
Return the size of the animation at the given time.
 
1544
===============
 
1545
*/
 
1546
void GraphicImpl::get_animation_size(uint anim, uint time, int* pw, int* ph)
 
1547
{
 
1548
        const AnimationData* data = g_anim.get_animation(anim);
 
1549
        const AnimationGfx* gfx = get_graphicimpl()->get_animation(anim);
 
1550
        const AnimFrame* frame;
 
1551
        int w, h;
 
1552
 
 
1553
        if (!data || !gfx)
 
1554
        {
 
1555
                log("WARNING: Animation %i doesn't exist\n", anim);
 
1556
                w = h = 0;
 
1557
        }
 
1558
        else
 
1559
        {
 
1560
                // Get the frame and its data
 
1561
                frame = gfx->get_frame((time / data->frametime) % gfx->get_nrframes());
 
1562
 
 
1563
                w = frame->width;
 
1564
                h = frame->height;
 
1565
        }
 
1566
 
 
1567
        if (pw)
 
1568
                *pw = w;
 
1569
        if (ph)
 
1570
                *ph = h;
 
1571
 
 
1572
        return;
 
1573
}
 
1574
 
 
1575
 
 
1576
/*
 
1577
===============
 
1578
GraphicImpl::screenshot
 
1579
 
 
1580
Save a screenshot in the given file.
 
1581
===============
 
1582
*/
 
1583
void GraphicImpl::screenshot(const char* fname)
 
1584
{
 
1585
        // TODO: this is incorrect; it bypasses the files code
 
1586
   SDL_SaveBMP(m_sdlsurface, fname);
 
1587
}
 
1588
 
 
1589
 
 
1590
 
 
1591
/*
 
1592
===============
 
1593
GraphicImpl::find_free_picture
 
1594
 
 
1595
Find a free picture slot and return it.
 
1596
===============
 
1597
*/
 
1598
uint GraphicImpl::find_free_picture()
 
1599
{
 
1600
        uint id;
 
1601
 
 
1602
        for(id = 1; id < m_pictures.size(); id++)
 
1603
                if (!m_pictures[id].mod)
 
1604
                        return id;
 
1605
 
 
1606
        m_pictures.resize(id+1);
 
1607
 
 
1608
        return id;
 
1609
}
 
1610
 
 
1611
/*
 
1612
 * GraphicImpl::flush_picture(int)
 
1613
 */
 
1614
void GraphicImpl::flush_picture(uint pic_index) {
 
1615
   Picture* pic = &m_pictures[pic_index];
 
1616
 
 
1617
 
 
1618
   if (pic->u.fname) {
 
1619
      m_picturemap.erase(pic->u.fname);
 
1620
      free(pic->u.fname);
 
1621
      pic->u.fname=0;
 
1622
   }
 
1623
   free(pic->bitmap.pixels);
 
1624
   pic->bitmap.pixels=0;
 
1625
}
 
1626
 
 
1627
/*
 
1628
 * Save and load pictures
 
1629
 */
 
1630
#define PICTURE_VERSION 1
 
1631
void GraphicImpl::save_pic_to_file(uint pic_index, FileWrite* fw) {
 
1632
   Picture* pic = &m_pictures[pic_index];
 
1633
 
 
1634
   // First the version
 
1635
   fw->Unsigned16(PICTURE_VERSION);
 
1636
 
 
1637
   // Now has clrkey
 
1638
   fw->Unsigned8(pic->bitmap.hasclrkey);
 
1639
 
 
1640
   // Now width and height
 
1641
   fw->Unsigned16(pic->bitmap.w);
 
1642
   fw->Unsigned16(pic->bitmap.h);
 
1643
 
 
1644
   // now all the data as RGB values
 
1645
   for(int h=0; h<pic->bitmap.h; h++) {
 
1646
      for(int w=0; w<pic->bitmap.w; w++) {
 
1647
         ushort clr=pic->bitmap.pixels[h*pic->bitmap.pitch+w];
 
1648
         uchar r, g, b;
 
1649
         unpack_rgb(clr, &r,&g,&b);
 
1650
         fw->Unsigned8(r);
 
1651
         fw->Unsigned8(g);
 
1652
         fw->Unsigned8(b);
 
1653
      }
 
1654
   }
 
1655
}
 
1656
 
 
1657
uint GraphicImpl::load_pic_from_file(FileRead* fr, int mod) {
 
1658
   // First the version
 
1659
   int version=fr->Unsigned16();
 
1660
   if(version<=PICTURE_VERSION) {
 
1661
      bool has_clrkey=fr->Unsigned8();
 
1662
//     NoLog("Load picture:\n has clrkey: %i\n", has_clrkey);
 
1663
      int g_w=fr->Unsigned16();
 
1664
      int g_h=fr->Unsigned16();
 
1665
//      NoLog(" Width: %i, Height: %i\n", g_w, g_h);
 
1666
 
 
1667
      ushort* pixels=(ushort*)malloc(sizeof(ushort)*g_w*g_h);
 
1668
      for(int h=0; h<g_h; h++) {
 
1669
         for(int w=0; w<g_w; w++) {
 
1670
            ushort* clr=&pixels[h*g_w+w];
 
1671
            uchar r,g,b;
 
1672
            r=fr->Unsigned8();
 
1673
            g=fr->Unsigned8();
 
1674
            b=fr->Unsigned8();
 
1675
             // NoLog(" Pixel: (%i,%i) has color RGB(%i,%i,%i)\n", w, h, r, g, b);
 
1676
            *clr=pack_rgb(r,g,b);
 
1677
         }
 
1678
      }
 
1679
 
 
1680
      uint id = find_free_picture();
 
1681
//     NoLog(" Got Free id: %i\n", id);
 
1682
      Picture* pic = &m_pictures[id];
 
1683
 
 
1684
      pic->mod = mod;
 
1685
      pic->u.fname = 0;
 
1686
      pic->bitmap.pixels = pixels;
 
1687
      pic->bitmap.w = g_w;
 
1688
      pic->bitmap.h = g_h;
 
1689
      pic->bitmap.pitch = g_w;
 
1690
      pic->bitmap.hasclrkey = has_clrkey;
 
1691
      pic->bitmap.clrkey = *pixels; // Upper left pixel
 
1692
 
 
1693
      return id;
 
1694
   }
 
1695
   throw wexception("Unknown picture version %i in file!\n", version);
 
1696
}
 
1697
 
 
1698
} // namespace Renderer_Software16
 
1699
 
 
1700
 
 
1701
/*
 
1702
===============
 
1703
SW16_CreateGraphics
 
1704
 
 
1705
Factory function called by System code
 
1706
===============
 
1707
*/
 
1708
Graphic* SW16_CreateGraphics(int w, int h, bool fullscreen)
 
1709
{
 
1710
        return new Renderer_Software16::GraphicImpl(w, h, fullscreen);
 
1711
}