1 /*****************************************************************************
2 * Copyright (c) 2014-2020 OpenRCT2 developers
3 *
4 * For a complete list of all authors, please refer to contributors.md
5 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6 *
7 * OpenRCT2 is licensed under the GNU General Public License version 3.
8 *****************************************************************************/
9
10 #include "BitmapReader.h"
11
12 #include <SDL.h>
13 #include <algorithm>
14 #include <cstring>
15 #include <openrct2/core/Imaging.h>
16 #include <stdexcept>
17
ReadToVector(std::istream & stream)18 static std::vector<uint8_t> ReadToVector(std::istream& stream)
19 {
20 std::vector<uint8_t> result;
21 if (!stream.eof() && !stream.fail())
22 {
23 stream.seekg(0, std::ios_base::end);
24 auto size = stream.tellg();
25 result.resize(size);
26 stream.seekg(0, std::ios_base::beg);
27 stream.read(reinterpret_cast<char*>(result.data()), size);
28 }
29 return result;
30 }
31
32 // TODO Bitmaps aren't very complicated to read so we should probably just write our
33 // own implementation in libopenrct2 and spare the AOT implementation registration.
ReadBitmap(std::istream & istream,IMAGE_FORMAT format)34 static Image ReadBitmap(std::istream& istream, IMAGE_FORMAT format)
35 {
36 auto buffer = ReadToVector(istream);
37 auto sdlStream = SDL_RWFromConstMem(buffer.data(), static_cast<int>(buffer.size()));
38 auto bitmap = SDL_LoadBMP_RW(sdlStream, 1);
39 if (bitmap != nullptr)
40 {
41 auto numChannels = bitmap->format->BytesPerPixel;
42 if (numChannels < 3 || bitmap->format->BitsPerPixel < 24)
43 {
44 SDL_FreeSurface(bitmap);
45 throw std::runtime_error("Only 24-bit bitmaps are supported.");
46 }
47
48 // Copy pixels over, then discard the surface
49 if (SDL_LockSurface(bitmap) == 0)
50 {
51 Image image;
52 image.Width = bitmap->w;
53 image.Height = bitmap->h;
54 image.Depth = 32;
55 image.Pixels.resize(bitmap->w * bitmap->h * 4);
56 image.Stride = bitmap->w * 4;
57
58 // Clear image with 0xFF
59 std::fill(image.Pixels.begin(), image.Pixels.end(), 0xFF);
60
61 // Copy pixels over
62 auto src = static_cast<const uint8_t*>(bitmap->pixels);
63 auto dst = image.Pixels.data();
64 if (numChannels == 4)
65 {
66 for (int32_t y = 0; y < bitmap->h; y++)
67 {
68 std::memcpy(dst, src, bitmap->w);
69 src += bitmap->pitch;
70 dst += bitmap->w;
71 }
72 }
73 else
74 {
75 for (int32_t y = 0; y < bitmap->h; y++)
76 {
77 for (int32_t x = 0; x < bitmap->w; x++)
78 {
79 std::memcpy(dst, src, 3);
80 src += 3;
81 dst += 4;
82 }
83 src += bitmap->pitch - (bitmap->w * 3);
84 }
85 }
86 SDL_UnlockSurface(bitmap);
87 SDL_FreeSurface(bitmap);
88
89 return image;
90 }
91
92 SDL_FreeSurface(bitmap);
93 throw std::runtime_error("Unable to lock surface.");
94 }
95 else
96 {
97 throw std::runtime_error(SDL_GetError());
98 }
99 }
100
RegisterBitmapReader()101 void RegisterBitmapReader()
102 {
103 Imaging::SetReader(IMAGE_FORMAT::BITMAP, ReadBitmap);
104 }
105