~ubuntu-branches/ubuntu/vivid/rlvm/vivid-proposed

« back to all changes in this revision

Viewing changes to src/systems/sdl/sdl_surface.cc

  • Committer: Package Import Robot
  • Author(s): Ying-Chun Liu (PaulLiu)
  • Date: 2014-10-22 03:24:19 UTC
  • mfrom: (1.1.8)
  • Revision ID: package-import@ubuntu.com-20141022032419-yqxls9ky4n1w811n
Tags: 0.14-1
* New upstream release
* Bump Standards-Version to 3.9.6: nothing needs to be changed

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- Mode: C++; tab-width:2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 
2
// vi:tw=80:et:ts=2:sts=2
 
3
//
 
4
// -----------------------------------------------------------------------
 
5
//
 
6
// This file is part of RLVM, a RealLive virtual machine clone.
 
7
//
 
8
// -----------------------------------------------------------------------
 
9
//
 
10
// Copyright (C) 2006, 2007 Elliot Glaysher
 
11
//
 
12
// This program is free software; you can redistribute it and/or modify
 
13
// it under the terms of the GNU General Public License as published by
 
14
// the Free Software Foundation; either version 3 of the License, or
 
15
// (at your option) any later version.
 
16
//
 
17
// This program is distributed in the hope that it will be useful,
 
18
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
20
// GNU General Public License for more details.
 
21
//
 
22
// You should have received a copy of the GNU General Public License
 
23
// along with this program; if not, write to the Free Software
 
24
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
25
//
 
26
// -----------------------------------------------------------------------
 
27
 
 
28
#include "systems/sdl/sdl_surface.h"
 
29
 
 
30
#include <SDL/SDL.h>
 
31
#include <iostream>
 
32
#include <sstream>
 
33
#include <vector>
 
34
 
 
35
#include "base/notification_source.h"
 
36
#include "pygame/alphablit.h"
 
37
#include "systems/base/colour.h"
 
38
#include "systems/base/graphics_object.h"
 
39
#include "systems/base/graphics_object_data.h"
 
40
#include "systems/base/system_error.h"
 
41
#include "systems/sdl/sdl_graphics_system.h"
 
42
#include "systems/sdl/sdl_utils.h"
 
43
#include "systems/sdl/texture.h"
 
44
#include "utilities/graphics.h"
 
45
 
 
46
namespace {
 
47
 
 
48
// An interface to TransformSurface that maps one color to another.
 
49
class ColourTransformer {
 
50
 public:
 
51
  virtual ~ColourTransformer() {}
 
52
  virtual SDL_Color operator()(const SDL_Color& colour) const = 0;
 
53
};
 
54
 
 
55
class ToneCurveColourTransformer : public ColourTransformer {
 
56
 public:
 
57
  explicit ToneCurveColourTransformer(const ToneCurveRGBMap m) : colormap(m) {}
 
58
  virtual SDL_Color operator()(const SDL_Color& colour) const {
 
59
    SDL_Color out = {colormap[0][colour.r], colormap[1][colour.g],
 
60
                     colormap[2][colour.b], 0};
 
61
    return out;
 
62
  }
 
63
 
 
64
 private:
 
65
  ToneCurveRGBMap colormap;
 
66
};
 
67
 
 
68
class InvertColourTransformer : public ColourTransformer {
 
69
 public:
 
70
  virtual SDL_Color operator()(const SDL_Color& colour) const {
 
71
    SDL_Color out = {255 - colour.r, 255 - colour.g, 255 - colour.b, 0};
 
72
    return out;
 
73
  }
 
74
};
 
75
 
 
76
class MonoColourTransformer : public ColourTransformer {
 
77
 public:
 
78
  virtual SDL_Color operator()(const SDL_Color& colour) const {
 
79
    float grayscale = 0.3 * colour.r + 0.59 * colour.g + 0.11 * colour.b;
 
80
    Clamp(grayscale, 0, 255);
 
81
    SDL_Color out = {grayscale, grayscale, grayscale, 0};
 
82
    return out;
 
83
  }
 
84
};
 
85
 
 
86
class ApplyColourTransformer : public ColourTransformer {
 
87
 public:
 
88
  explicit ApplyColourTransformer(const RGBColour& colour) : colour_(colour) {}
 
89
 
 
90
  int compose(int in_colour, int surface_colour) const {
 
91
    if (in_colour > 0) {
 
92
      return 255 -
 
93
             ((static_cast<float>((255 - in_colour) * (255 - surface_colour)) /
 
94
               (255 * 255)) *
 
95
              255);
 
96
    } else if (in_colour < 0) {
 
97
      return (static_cast<float>(abs(in_colour) * surface_colour) /
 
98
              (255 * 255)) *
 
99
             255;
 
100
    } else {
 
101
      return surface_colour;
 
102
    }
 
103
  }
 
104
 
 
105
  virtual SDL_Color operator()(const SDL_Color& colour) const {
 
106
    SDL_Color out = {
 
107
        compose(colour_.r(), colour.r), compose(colour_.g(), colour.g),
 
108
        compose(colour_.b(), colour.b), 0};
 
109
    return out;
 
110
  }
 
111
 
 
112
 private:
 
113
  RGBColour colour_;
 
114
};
 
115
 
 
116
// Applies a |transformer| to every pixel in |area| in the surface |surface|.
 
117
void TransformSurface(SDLSurface* our_surface,
 
118
                      const Rect& area,
 
119
                      const ColourTransformer& transformer) {
 
120
  SDL_Surface* surface = our_surface->rawSurface();
 
121
  SDL_Color colour;
 
122
  Uint32 col = 0;
 
123
 
 
124
  // determine position
 
125
  char* p_position = (char*)surface->pixels;
 
126
 
 
127
  // offset by y
 
128
  p_position += (surface->pitch * area.y());
 
129
 
 
130
  SDL_LockSurface(surface);
 
131
  {
 
132
    for (int y = 0; y < area.height(); ++y) {
 
133
      // advance forward x
 
134
      p_position += (surface->format->BytesPerPixel * area.x());
 
135
 
 
136
      for (int x = 0; x < area.width(); ++x) {
 
137
        // copy pixel data
 
138
        memcpy(&col, p_position, surface->format->BytesPerPixel);
 
139
 
 
140
        // Before someone tries to simplify the following four lines,
 
141
        // remember that sizeof(int) != sizeof(Uint8).
 
142
        Uint8 alpha;
 
143
        SDL_GetRGBA(
 
144
            col, surface->format, &colour.r, &colour.g, &colour.b, &alpha);
 
145
        SDL_Color out = transformer(colour);
 
146
        Uint32 out_colour =
 
147
            SDL_MapRGBA(surface->format, out.r, out.g, out.b, alpha);
 
148
 
 
149
        memcpy(p_position, &out_colour, surface->format->BytesPerPixel);
 
150
 
 
151
        p_position += surface->format->BytesPerPixel;
 
152
      }
 
153
 
 
154
      // advance forward image_width - area.width() - x
 
155
      int advance = surface->w - area.x() - area.width();
 
156
      p_position += (surface->format->BytesPerPixel * advance);
 
157
    }
 
158
  }
 
159
  SDL_UnlockSurface(surface);
 
160
 
 
161
  // If we are the main screen, then we want to update the screen
 
162
  our_surface->markWrittenTo(our_surface->GetRect());
 
163
}
 
164
 
 
165
}  // namespace
 
166
 
 
167
// -----------------------------------------------------------------------
 
168
 
 
169
// Note to self: These describe the byte order IN THE RAW G00 DATA!
 
170
// These should NOT be switched to native byte order.
 
171
#define DefaultRmask 0xff0000
 
172
#define DefaultGmask 0xff00
 
173
#define DefaultBmask 0xff
 
174
#define DefaultAmask 0xff000000
 
175
#define DefaultBpp 32
 
176
 
 
177
SDL_Surface* buildNewSurface(const Size& size) {
 
178
  // Create an empty surface
 
179
  SDL_Surface* tmp = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA,
 
180
                                          size.width(),
 
181
                                          size.height(),
 
182
                                          DefaultBpp,
 
183
                                          DefaultRmask,
 
184
                                          DefaultGmask,
 
185
                                          DefaultBmask,
 
186
                                          DefaultAmask);
 
187
 
 
188
  if (tmp == NULL) {
 
189
    std::ostringstream ss;
 
190
    ss << "Couldn't allocate surface in build_new_surface"
 
191
       << ": " << SDL_GetError();
 
192
    throw SystemError(ss.str());
 
193
  }
 
194
 
 
195
  return tmp;
 
196
}
 
197
 
 
198
// -----------------------------------------------------------------------
 
199
// SDLSurface::TextureRecord
 
200
// -----------------------------------------------------------------------
 
201
SDLSurface::TextureRecord::TextureRecord(SDL_Surface* surface,
 
202
                                         int x,
 
203
                                         int y,
 
204
                                         int w,
 
205
                                         int h,
 
206
                                         unsigned int bytes_per_pixel,
 
207
                                         int byte_order,
 
208
                                         int byte_type)
 
209
    : texture(new Texture(surface,
 
210
                          x,
 
211
                          y,
 
212
                          w,
 
213
                          h,
 
214
                          bytes_per_pixel,
 
215
                          byte_order,
 
216
                          byte_type)),
 
217
      x_(x),
 
218
      y_(y),
 
219
      w_(w),
 
220
      h_(h),
 
221
      bytes_per_pixel_(bytes_per_pixel),
 
222
      byte_order_(byte_order),
 
223
      byte_type_(byte_type) {}
 
224
 
 
225
// -----------------------------------------------------------------------
 
226
 
 
227
void SDLSurface::TextureRecord::reupload(SDL_Surface* surface,
 
228
                                         const Rect& dirty) {
 
229
  if (texture) {
 
230
    Rect i = Rect::REC(x_, y_, w_, h_).Intersection(dirty);
 
231
    if (!i.is_empty()) {
 
232
      texture->reupload(surface,
 
233
                        i.x() - x_,
 
234
                        i.y() - y_,
 
235
                        i.x(),
 
236
                        i.y(),
 
237
                        i.width(),
 
238
                        i.height(),
 
239
                        bytes_per_pixel_,
 
240
                        byte_order_,
 
241
                        byte_type_);
 
242
    }
 
243
  } else {
 
244
    texture.reset(new Texture(
 
245
        surface, x_, y_, w_, h_, bytes_per_pixel_, byte_order_, byte_type_));
 
246
  }
 
247
}
 
248
 
 
249
// -----------------------------------------------------------------------
 
250
 
 
251
void SDLSurface::TextureRecord::forceUnload() { texture.reset(); }
 
252
 
 
253
// -----------------------------------------------------------------------
 
254
// SDLSurface
 
255
// -----------------------------------------------------------------------
 
256
 
 
257
SDLSurface::SDLSurface(SDLGraphicsSystem* system)
 
258
    : surface_(NULL),
 
259
      texture_is_valid_(false),
 
260
      is_dc0_(false),
 
261
      graphics_system_(system),
 
262
      is_mask_(false) {
 
263
  registerForNotification(system);
 
264
}
 
265
 
 
266
// -----------------------------------------------------------------------
 
267
 
 
268
SDLSurface::SDLSurface(SDLGraphicsSystem* system, SDL_Surface* surf)
 
269
    : surface_(surf),
 
270
      texture_is_valid_(false),
 
271
      is_dc0_(false),
 
272
      graphics_system_(system),
 
273
      is_mask_(false) {
 
274
  buildRegionTable(Size(surf->w, surf->h));
 
275
  registerForNotification(system);
 
276
}
 
277
 
 
278
// -----------------------------------------------------------------------
 
279
 
 
280
// Surface that takes ownership of an externally created surface.
 
281
SDLSurface::SDLSurface(SDLGraphicsSystem* system,
 
282
                       SDL_Surface* surf,
 
283
                       const std::vector<SDLSurface::GrpRect>& region_table)
 
284
    : surface_(surf),
 
285
      region_table_(region_table),
 
286
      texture_is_valid_(false),
 
287
      is_dc0_(false),
 
288
      graphics_system_(system),
 
289
      is_mask_(false) {
 
290
  registerForNotification(system);
 
291
}
 
292
 
 
293
// -----------------------------------------------------------------------
 
294
 
 
295
SDLSurface::SDLSurface(SDLGraphicsSystem* system, const Size& size)
 
296
    : surface_(NULL),
 
297
      texture_is_valid_(false),
 
298
      is_dc0_(false),
 
299
      graphics_system_(system),
 
300
      is_mask_(false) {
 
301
  allocate(size);
 
302
  buildRegionTable(size);
 
303
  registerForNotification(system);
 
304
}
 
305
 
 
306
// -----------------------------------------------------------------------
 
307
 
 
308
void SDLSurface::EnsureUploaded() const {
 
309
  // TODO(erg): Style fix this entire file and make this implementation:
 
310
  uploadTextureIfNeeded();
 
311
}
 
312
 
 
313
// -----------------------------------------------------------------------
 
314
 
 
315
void SDLSurface::registerForNotification(GraphicsSystem* system) {
 
316
  registrar_.Add(this,
 
317
                 NotificationType::FULLSCREEN_STATE_CHANGED,
 
318
                 Source<GraphicsSystem>(system));
 
319
}
 
320
 
 
321
// -----------------------------------------------------------------------
 
322
 
 
323
// Constructor helper function
 
324
void SDLSurface::buildRegionTable(const Size& size) {
 
325
  // Build a region table with one entry the size of the surface (This
 
326
  // should never need to be used with objects created with this
 
327
  // constructor, but let's make sure everything is initialized since
 
328
  // it'll happen somehow.)
 
329
  SDLSurface::GrpRect rect;
 
330
  rect.rect = Rect(Point(0, 0), size);
 
331
  rect.originX = 0;
 
332
  rect.originY = 0;
 
333
  region_table_.push_back(rect);
 
334
}
 
335
 
 
336
// -----------------------------------------------------------------------
 
337
 
 
338
SDLSurface::~SDLSurface() { deallocate(); }
 
339
 
 
340
// -----------------------------------------------------------------------
 
341
 
 
342
Size SDLSurface::GetSize() const {
 
343
  assert(surface_);
 
344
  return Size(surface_->w, surface_->h);
 
345
}
 
346
 
 
347
// -----------------------------------------------------------------------
 
348
 
 
349
void SDLSurface::Dump() {
 
350
  static int count = 0;
 
351
  std::ostringstream ss;
 
352
  ss << "dump_" << count << ".bmp";
 
353
  count++;
 
354
  SDL_SaveBMP(surface_, ss.str().c_str());
 
355
}
 
356
 
 
357
// -----------------------------------------------------------------------
 
358
 
 
359
void SDLSurface::allocate(const Size& size) {
 
360
  deallocate();
 
361
 
 
362
  surface_ = buildNewSurface(size);
 
363
 
 
364
  Fill(RGBAColour::Black());
 
365
}
 
366
 
 
367
// -----------------------------------------------------------------------
 
368
 
 
369
void SDLSurface::allocate(const Size& size, bool is_dc0) {
 
370
  is_dc0_ = is_dc0;
 
371
  allocate(size);
 
372
}
 
373
 
 
374
// -----------------------------------------------------------------------
 
375
 
 
376
void SDLSurface::deallocate() {
 
377
  textures_.clear();
 
378
  if (surface_) {
 
379
    SDL_FreeSurface(surface_);
 
380
    surface_ = NULL;
 
381
  }
 
382
}
 
383
 
 
384
// TODO(erg): This function doesn't ignore alpha blending when use_src_alpha is
 
385
// false; thus, grp_open and grp_mask_open are really grp_mask_open.
 
386
void SDLSurface::BlitToSurface(Surface& dest_surface,
 
387
                               const Rect& src,
 
388
                               const Rect& dst,
 
389
                               int alpha,
 
390
                               bool use_src_alpha) const {
 
391
  SDLSurface& sdl_dest_surface = dynamic_cast<SDLSurface&>(dest_surface);
 
392
 
 
393
  SDL_Rect src_rect, dest_rect;
 
394
  RectToSDLRect(src, &src_rect);
 
395
  RectToSDLRect(dst, &dest_rect);
 
396
 
 
397
  if (src.size() != dst.size()) {
 
398
    // Blit the source rectangle into its own image.
 
399
    SDL_Surface* src_image = buildNewSurface(src.size());
 
400
    if (pygame_AlphaBlit(surface_, &src_rect, src_image, NULL))
 
401
      reportSDLError("SDL_BlitSurface", "SDLGraphicsSystem::blitSurfaceToDC()");
 
402
 
 
403
    SDL_Surface* tmp = buildNewSurface(dst.size());
 
404
    pygame_stretch(src_image, tmp);
 
405
 
 
406
    if (use_src_alpha) {
 
407
      if (SDL_SetAlpha(tmp, SDL_SRCALPHA, alpha))
 
408
        reportSDLError("SDL_SetAlpha", "SDLGraphicsSystem::blitSurfaceToDC()");
 
409
    } else {
 
410
      if (SDL_SetAlpha(tmp, 0, 0))
 
411
        reportSDLError("SDL_SetAlpha", "SDLGraphicsSystem::blitSurfaceToDC()");
 
412
    }
 
413
 
 
414
    if (SDL_BlitSurface(tmp, NULL, sdl_dest_surface.surface(), &dest_rect))
 
415
      reportSDLError("SDL_BlitSurface", "SDLGraphicsSystem::blitSurfaceToDC()");
 
416
 
 
417
    SDL_FreeSurface(tmp);
 
418
    SDL_FreeSurface(src_image);
 
419
  } else {
 
420
    if (use_src_alpha) {
 
421
      if (SDL_SetAlpha(surface_, SDL_SRCALPHA, alpha))
 
422
        reportSDLError("SDL_SetAlpha", "SDLGraphicsSystem::blitSurfaceToDC()");
 
423
    } else {
 
424
      if (SDL_SetAlpha(surface_, 0, 0))
 
425
        reportSDLError("SDL_SetAlpha", "SDLGraphicsSystem::blitSurfaceToDC()");
 
426
    }
 
427
 
 
428
    if (SDL_BlitSurface(
 
429
            surface_, &src_rect, sdl_dest_surface.surface(), &dest_rect))
 
430
      reportSDLError("SDL_BlitSurface", "SDLGraphicsSystem::blitSurfaceToDC()");
 
431
  }
 
432
  sdl_dest_surface.markWrittenTo(dst);
 
433
}
 
434
 
 
435
// -----------------------------------------------------------------------
 
436
 
 
437
// Allows for tight coupling with SDL_ttf. Rethink the existence of
 
438
// this function later.
 
439
void SDLSurface::blitFROMSurface(SDL_Surface* src_surface,
 
440
                                 const Rect& src,
 
441
                                 const Rect& dst,
 
442
                                 int alpha,
 
443
                                 bool use_src_alpha) {
 
444
  SDL_Rect src_rect, dest_rect;
 
445
  RectToSDLRect(src, &src_rect);
 
446
  RectToSDLRect(dst, &dest_rect);
 
447
 
 
448
  if (use_src_alpha) {
 
449
    if (pygame_AlphaBlit(src_surface, &src_rect, surface_, &dest_rect))
 
450
      reportSDLError("pygame_AlphaBlit",
 
451
                     "SDLGraphicsSystem::blitSurfaceToDC()");
 
452
  } else {
 
453
    if (SDL_BlitSurface(src_surface, &src_rect, surface_, &dest_rect))
 
454
      reportSDLError("SDL_BlitSurface", "SDLGraphicsSystem::blitSurfaceToDC()");
 
455
  }
 
456
 
 
457
  markWrittenTo(dst);
 
458
}
 
459
 
 
460
// -----------------------------------------------------------------------
 
461
 
 
462
static void determineProperties(SDL_Surface* surface,
 
463
                                bool is_mask,
 
464
                                GLenum& bytes_per_pixel,
 
465
                                GLint& byte_order,
 
466
                                GLint& byte_type) {
 
467
  SDL_LockSurface(surface);
 
468
  {
 
469
    bytes_per_pixel = surface->format->BytesPerPixel;
 
470
    byte_order = GL_RGBA;
 
471
    byte_type = GL_UNSIGNED_BYTE;
 
472
 
 
473
    // Determine the byte order of the surface
 
474
    SDL_PixelFormat* format = surface->format;
 
475
    if (bytes_per_pixel == 4) {
 
476
      // If the order is RGBA...
 
477
      if (format->Rmask == 0xFF000000 && format->Amask == 0xFF)
 
478
        byte_order = GL_RGBA;
 
479
      // OSX's crazy ARGB pixel format
 
480
      else if ((format->Amask == 0x0 || format->Amask == 0xFF000000) &&
 
481
               format->Rmask == 0xFF0000 && format->Gmask == 0xFF00 &&
 
482
               format->Bmask == 0xFF) {
 
483
        // This is an insane hack to get around OSX's crazy byte order
 
484
        // for alpha on PowerPC. Since there isn't a GL_ARGB type, we
 
485
        // need to specify BGRA and then tell the byte type to be
 
486
        // reversed order.
 
487
        //
 
488
        // 20070303: Whoah! Is this the internal format on all
 
489
        // platforms!?
 
490
        byte_order = GL_BGRA;
 
491
        byte_type = GL_UNSIGNED_INT_8_8_8_8_REV;
 
492
      } else {
 
493
        std::ios_base::fmtflags f = std::cerr.flags(
 
494
            std::ios::hex | std::ios::uppercase);
 
495
        std::cerr << "Unknown mask: (" << format->Rmask << ", " << format->Gmask
 
496
                  << ", " << format->Bmask << ", " << format->Amask << ")"
 
497
                  << std::endl;
 
498
        std::cerr.flags(f);
 
499
      }
 
500
    } else if (bytes_per_pixel == 3) {
 
501
      // For now, just assume RGB.
 
502
      byte_order = GL_RGB;
 
503
      std::cerr << "Warning: Am I really an RGB Surface? Check"
 
504
                << " Texture::Texture()!" << std::endl;
 
505
    } else {
 
506
      std::ostringstream oss;
 
507
      oss << "Error loading texture: bytes_per_pixel == "
 
508
          << int(bytes_per_pixel) << " and we only handle 3 or 4.";
 
509
      throw SystemError(oss.str());
 
510
    }
 
511
  }
 
512
  SDL_UnlockSurface(surface);
 
513
 
 
514
  if (is_mask) {
 
515
    // Compile shader for use:
 
516
    bytes_per_pixel = GL_ALPHA;
 
517
  }
 
518
}
 
519
 
 
520
// -----------------------------------------------------------------------
 
521
 
 
522
void SDLSurface::uploadTextureIfNeeded() const {
 
523
  if (!texture_is_valid_) {
 
524
    if (textures_.size() == 0) {
 
525
      GLenum bytes_per_pixel;
 
526
      GLint byte_order, byte_type;
 
527
      determineProperties(
 
528
          surface_, is_mask_, bytes_per_pixel, byte_order, byte_type);
 
529
 
 
530
      // ---------------------------------------------------------------------
 
531
 
 
532
      // Figure out the optimal way of splitting up the image.
 
533
      std::vector<int> x_pieces, y_pieces;
 
534
      x_pieces = segmentPicture(surface_->w);
 
535
      y_pieces = segmentPicture(surface_->h);
 
536
 
 
537
      int x_offset = 0;
 
538
      for (std::vector<int>::const_iterator it = x_pieces.begin();
 
539
           it != x_pieces.end();
 
540
           ++it) {
 
541
        int y_offset = 0;
 
542
        for (std::vector<int>::const_iterator jt = y_pieces.begin();
 
543
             jt != y_pieces.end();
 
544
             ++jt) {
 
545
          TextureRecord record(surface_,
 
546
                               x_offset,
 
547
                               y_offset,
 
548
                               *it,
 
549
                               *jt,
 
550
                               bytes_per_pixel,
 
551
                               byte_order,
 
552
                               byte_type);
 
553
          textures_.push_back(record);
 
554
 
 
555
          y_offset += *jt;
 
556
        }
 
557
 
 
558
        x_offset += *it;
 
559
      }
 
560
    } else {
 
561
      // Reupload the textures without reallocating them.
 
562
      for_each(textures_.begin(), textures_.end(), [&](TextureRecord& record) {
 
563
        record.reupload(surface_, dirty_rectangle_);
 
564
      });
 
565
    }
 
566
 
 
567
    dirty_rectangle_ = Rect();
 
568
    texture_is_valid_ = true;
 
569
  }
 
570
}
 
571
 
 
572
// -----------------------------------------------------------------------
 
573
 
 
574
void SDLSurface::RenderToScreen(const Rect& src,
 
575
                                const Rect& dst,
 
576
                                int alpha) const {
 
577
  uploadTextureIfNeeded();
 
578
 
 
579
  for (std::vector<TextureRecord>::iterator it = textures_.begin();
 
580
       it != textures_.end();
 
581
       ++it) {
 
582
    it->texture->RenderToScreen(src, dst, alpha);
 
583
  }
 
584
}
 
585
 
 
586
// -----------------------------------------------------------------------
 
587
 
 
588
void SDLSurface::RenderToScreenAsColorMask(const Rect& src,
 
589
                                           const Rect& dst,
 
590
                                           const RGBAColour& rgba,
 
591
                                           int filter) const {
 
592
  uploadTextureIfNeeded();
 
593
 
 
594
  for (std::vector<TextureRecord>::iterator it = textures_.begin();
 
595
       it != textures_.end();
 
596
       ++it) {
 
597
    it->texture->RenderToScreenAsColorMask(src, dst, rgba, filter);
 
598
  }
 
599
}
 
600
 
 
601
// -----------------------------------------------------------------------
 
602
 
 
603
void SDLSurface::RenderToScreen(const Rect& src,
 
604
                                const Rect& dst,
 
605
                                const int opacity[4]) const {
 
606
  uploadTextureIfNeeded();
 
607
 
 
608
  for (std::vector<TextureRecord>::iterator it = textures_.begin();
 
609
       it != textures_.end();
 
610
       ++it) {
 
611
    it->texture->RenderToScreen(src, dst, opacity);
 
612
  }
 
613
}
 
614
 
 
615
// -----------------------------------------------------------------------
 
616
 
 
617
void SDLSurface::RenderToScreenAsObject(const GraphicsObject& rp,
 
618
                                        const Rect& src,
 
619
                                        const Rect& dst,
 
620
                                        int alpha) const {
 
621
  uploadTextureIfNeeded();
 
622
 
 
623
  for (std::vector<TextureRecord>::iterator it = textures_.begin();
 
624
       it != textures_.end();
 
625
       ++it) {
 
626
    it->texture->RenderToScreenAsObject(rp, *this, src, dst, alpha);
 
627
  }
 
628
}
 
629
 
 
630
// -----------------------------------------------------------------------
 
631
 
 
632
void SDLSurface::Fill(const RGBAColour& colour) {
 
633
  // Fill the entire surface with the incoming colour
 
634
  Uint32 sdl_colour = MapRGBA(surface_->format, colour);
 
635
 
 
636
  if (SDL_FillRect(surface_, NULL, sdl_colour))
 
637
    reportSDLError("SDL_FillRect", "SDLGraphicsSystem::wipe()");
 
638
 
 
639
  // If we are the main screen, then we want to update the screen
 
640
  markWrittenTo(GetRect());
 
641
}
 
642
 
 
643
// -----------------------------------------------------------------------
 
644
 
 
645
void SDLSurface::Fill(const RGBAColour& colour, const Rect& area) {
 
646
  // Fill the entire surface with the incoming colour
 
647
  Uint32 sdl_colour = MapRGBA(surface_->format, colour);
 
648
 
 
649
  SDL_Rect rect;
 
650
  RectToSDLRect(area, &rect);
 
651
 
 
652
  if (SDL_FillRect(surface_, &rect, sdl_colour))
 
653
    reportSDLError("SDL_FillRect", "SDLGraphicsSystem::wipe()");
 
654
 
 
655
  // If we are the main screen, then we want to update the screen
 
656
  markWrittenTo(area);
 
657
}
 
658
 
 
659
// -----------------------------------------------------------------------
 
660
 
 
661
void SDLSurface::Invert(const Rect& rect) {
 
662
  InvertColourTransformer inverter;
 
663
  TransformSurface(this, rect, inverter);
 
664
}
 
665
 
 
666
// -----------------------------------------------------------------------
 
667
 
 
668
void SDLSurface::Mono(const Rect& rect) {
 
669
  MonoColourTransformer mono;
 
670
  TransformSurface(this, rect, mono);
 
671
}
 
672
 
 
673
// -----------------------------------------------------------------------
 
674
 
 
675
void SDLSurface::ToneCurve(const ToneCurveRGBMap effect, const Rect& area) {
 
676
  ToneCurveColourTransformer tc(effect);
 
677
  TransformSurface(this, area, tc);
 
678
}
 
679
 
 
680
// -----------------------------------------------------------------------
 
681
 
 
682
void SDLSurface::ApplyColour(const RGBColour& colour, const Rect& area) {
 
683
  ApplyColourTransformer apply(colour);
 
684
  TransformSurface(this, area, apply);
 
685
}
 
686
 
 
687
// -----------------------------------------------------------------------
 
688
 
 
689
int SDLSurface::GetNumPatterns() const { return region_table_.size(); }
 
690
 
 
691
// -----------------------------------------------------------------------
 
692
 
 
693
const SDLSurface::GrpRect& SDLSurface::GetPattern(int patt_no) const {
 
694
  if (patt_no < region_table_.size())
 
695
    return region_table_[patt_no];
 
696
  else
 
697
    return region_table_[0];
 
698
}
 
699
 
 
700
// -----------------------------------------------------------------------
 
701
 
 
702
Surface* SDLSurface::Clone() const {
 
703
  SDL_Surface* tmp_surface =
 
704
      SDL_CreateRGBSurface(surface_->flags,
 
705
                           surface_->w,
 
706
                           surface_->h,
 
707
                           surface_->format->BitsPerPixel,
 
708
                           surface_->format->Rmask,
 
709
                           surface_->format->Gmask,
 
710
                           surface_->format->Bmask,
 
711
                           surface_->format->Amask);
 
712
 
 
713
  // Disable alpha blending because we're copying onto a blank (and
 
714
  // blank alpha!) surface
 
715
  if (SDL_SetAlpha(surface_, 0, 0))
 
716
    reportSDLError("SDL_SetAlpha", "SDLGraphicsSystem::blitSurfaceToDC()");
 
717
 
 
718
  if (SDL_BlitSurface(surface_, NULL, tmp_surface, NULL))
 
719
    reportSDLError("SDL_BlitSurface", "SDLSurface::clone()");
 
720
 
 
721
  return new SDLSurface(graphics_system_, tmp_surface, region_table_);
 
722
}
 
723
 
 
724
// -----------------------------------------------------------------------
 
725
 
 
726
std::vector<int> SDLSurface::segmentPicture(int size_remainging) {
 
727
  int max_texture_size = GetMaxTextureSize();
 
728
 
 
729
  std::vector<int> output;
 
730
  while (size_remainging > max_texture_size) {
 
731
    output.push_back(max_texture_size);
 
732
    size_remainging -= max_texture_size;
 
733
  }
 
734
 
 
735
  if (IsNPOTSafe()) {
 
736
    output.push_back(size_remainging);
 
737
  } else {
 
738
    while (size_remainging) {
 
739
      int ss = SafeSize(size_remainging);
 
740
      if (ss > 512) {
 
741
        output.push_back(512);
 
742
        size_remainging -= 512;
 
743
      } else {
 
744
        output.push_back(size_remainging);
 
745
        size_remainging = 0;
 
746
      }
 
747
    }
 
748
  }
 
749
 
 
750
  return output;
 
751
}
 
752
 
 
753
// -----------------------------------------------------------------------
 
754
 
 
755
void SDLSurface::GetDCPixel(const Point& pos, int& r, int& g, int& b) const {
 
756
  SDL_Color colour;
 
757
  Uint32 col = 0;
 
758
 
 
759
  // determine position
 
760
  char* p_position = (char*)surface_->pixels;
 
761
 
 
762
  // offset by y
 
763
  p_position += (surface_->pitch * pos.y());
 
764
 
 
765
  // offset by x
 
766
  p_position += (surface_->format->BytesPerPixel * pos.x());
 
767
 
 
768
  // copy pixel data
 
769
  memcpy(&col, p_position, surface_->format->BytesPerPixel);
 
770
 
 
771
  // Before someone tries to simplify the following four lines,
 
772
  // remember that sizeof(int) != sizeof(Uint8).
 
773
  SDL_GetRGB(col, surface_->format, &colour.r, &colour.g, &colour.b);
 
774
  r = colour.r;
 
775
  g = colour.g;
 
776
  b = colour.b;
 
777
}
 
778
 
 
779
// -----------------------------------------------------------------------
 
780
 
 
781
std::shared_ptr<Surface> SDLSurface::ClipAsColorMask(const Rect& clip_rect,
 
782
                                                       int r,
 
783
                                                       int g,
 
784
                                                       int b) const {
 
785
  const char* function_name = "SDLGraphicsSystem::ClipAsColorMask()";
 
786
 
 
787
  // TODO(erg): This needs to be made exception safe and so does the rest
 
788
  // of this file.
 
789
  SDL_Surface* tmp_surface = SDL_CreateRGBSurface(
 
790
      0, surface_->w, surface_->h, 24, 0xFF0000, 0xFF00, 0xFF, 0);
 
791
 
 
792
  if (!tmp_surface)
 
793
    reportSDLError("SDL_CreateRGBSurface", function_name);
 
794
 
 
795
  if (SDL_BlitSurface(surface_, NULL, tmp_surface, NULL))
 
796
    reportSDLError("SDL_BlitSurface", function_name);
 
797
 
 
798
  Uint32 colour = SDL_MapRGB(tmp_surface->format, r, g, b);
 
799
  if (SDL_SetColorKey(tmp_surface, SDL_SRCCOLORKEY, colour))
 
800
    reportSDLError("SDL_SetAlpha", function_name);
 
801
 
 
802
  // The OpenGL pieces don't know what to do an image formatted to
 
803
  // (FF0000, FF00, FF, 0), so convert it to a standard RGBA image
 
804
  // (and clip to the desired rectangle)
 
805
  SDL_Surface* surface = buildNewSurface(clip_rect.size());
 
806
  SDL_Rect srcrect;
 
807
  RectToSDLRect(clip_rect, &srcrect);
 
808
  if (SDL_BlitSurface(tmp_surface, &srcrect, surface, NULL))
 
809
    reportSDLError("SDL_BlitSurface", function_name);
 
810
 
 
811
  SDL_FreeSurface(tmp_surface);
 
812
 
 
813
  return std::shared_ptr<Surface>(new SDLSurface(graphics_system_, surface));
 
814
}
 
815
 
 
816
// -----------------------------------------------------------------------
 
817
 
 
818
void SDLSurface::markWrittenTo(const Rect& written_rect) {
 
819
  // If we are marked as dc0, alert the SDLGraphicsSystem.
 
820
  if (is_dc0_ && graphics_system_) {
 
821
    graphics_system_->MarkScreenAsDirty(GUT_DRAW_DC0);
 
822
  }
 
823
 
 
824
  // Mark that the texture needs reuploading
 
825
  dirty_rectangle_ = dirty_rectangle_.RectUnion(written_rect);
 
826
  texture_is_valid_ = false;
 
827
}
 
828
 
 
829
void SDLSurface::Observe(NotificationType type,
 
830
                         const NotificationSource& source,
 
831
                         const NotificationDetails& details) {
 
832
  if (surface_) {
 
833
    // Force unloading of all OpenGL resources
 
834
    for (std::vector<TextureRecord>::iterator it = textures_.begin();
 
835
         it != textures_.end();
 
836
         ++it) {
 
837
      it->forceUnload();
 
838
    }
 
839
 
 
840
    dirty_rectangle_ = GetRect();
 
841
  }
 
842
 
 
843
  texture_is_valid_ = false;
 
844
}