1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14
15 #include "gfx/bitmap.h"
16 #include "util/memory.h"
17
18 #ifndef NULL
19 #define NULL 0
20 #endif
21
22 extern "C"
23 {
24 extern BITMAP *screen; // in allegro
25 }
26
27 namespace AGS
28 {
29 namespace Common
30 {
31
32 // TODO! Get rid of this global ptr in the future (need to rewrite drawing logic in the engine)
33 // NOTE: Screen bitmap is created either by working graphics driver, or in the engine_prepare_screen()
34 Bitmap *gl_ScreenBmp;
35
36 // TODO: revise this construction later
37 namespace BitmapHelper
38 {
39
CreateBitmap(int width,int height,int color_depth)40 Bitmap *CreateBitmap(int width, int height, int color_depth)
41 {
42 Bitmap *bitmap = new Bitmap();
43 if (!bitmap->Create(width, height, color_depth))
44 {
45 delete bitmap;
46 bitmap = NULL;
47 }
48 return bitmap;
49 }
50
CreateTransparentBitmap(int width,int height,int color_depth)51 Bitmap *CreateTransparentBitmap(int width, int height, int color_depth)
52 {
53 Bitmap *bitmap = new Bitmap();
54 if (!bitmap->CreateTransparent(width, height, color_depth))
55 {
56 delete bitmap;
57 bitmap = NULL;
58 }
59 return bitmap;
60 }
61
CreateSubBitmap(Bitmap * src,const Rect & rc)62 Bitmap *CreateSubBitmap(Bitmap *src, const Rect &rc)
63 {
64 Bitmap *bitmap = new Bitmap();
65 if (!bitmap->CreateSubBitmap(src, rc))
66 {
67 delete bitmap;
68 bitmap = NULL;
69 }
70 return bitmap;
71 }
72
CreateBitmapCopy(Bitmap * src,int color_depth)73 Bitmap *CreateBitmapCopy(Bitmap *src, int color_depth)
74 {
75 Bitmap *bitmap = new Bitmap();
76 if (!bitmap->CreateCopy(src, color_depth))
77 {
78 delete bitmap;
79 bitmap = NULL;
80 }
81 return bitmap;
82 }
83
LoadFromFile(const char * filename)84 Bitmap *LoadFromFile(const char *filename)
85 {
86 Bitmap *bitmap = new Bitmap();
87 if (!bitmap->LoadFromFile(filename))
88 {
89 delete bitmap;
90 bitmap = NULL;
91 }
92 return bitmap;
93 }
94
95
96 template <class TPx, size_t BPP_>
97 struct PixelTransCpy
98 {
99 static const size_t BPP = BPP_;
operator ()AGS::Common::BitmapHelper::PixelTransCpy100 inline void operator ()(uint8_t *dst, const uint8_t *src, color_t mask_color, bool use_alpha) const
101 {
102 if (*(TPx*)src == mask_color)
103 *(TPx*)dst = mask_color;
104 }
105 };
106
107 struct PixelNoSkip
108 {
operator ()AGS::Common::BitmapHelper::PixelNoSkip109 inline bool operator ()(uint8_t *data, color_t mask_color, bool use_alpha) const
110 {
111 return false;
112 }
113 };
114
115 typedef PixelTransCpy<uint8_t, 1> PixelTransCpy8;
116 typedef PixelTransCpy<uint16_t, 2> PixelTransCpy16;
117
118 struct PixelTransCpy24
119 {
120 static const size_t BPP = 3;
operator ()AGS::Common::BitmapHelper::PixelTransCpy24121 inline void operator ()(uint8_t *dst, const uint8_t *src, color_t mask_color, bool use_alpha) const
122 {
123 const uint8_t *mcol_ptr = (const uint8_t*)&mask_color;
124 if (src[0] == mcol_ptr[0] && src[1] == mcol_ptr[1] && src[2] == mcol_ptr[2])
125 {
126 dst[0] = mcol_ptr[0];
127 dst[1] = mcol_ptr[1];
128 dst[2] = mcol_ptr[2];
129 }
130 }
131 };
132
133 struct PixelTransCpy32
134 {
135 static const size_t BPP = 4;
operator ()AGS::Common::BitmapHelper::PixelTransCpy32136 inline void operator ()(uint8_t *dst, const uint8_t *src, color_t mask_color, bool use_alpha) const
137 {
138 if (*(const uint32_t*)src == mask_color)
139 *(uint32_t*)dst = mask_color;
140 else if (use_alpha)
141 dst[3] = src[3]; // copy alpha channel
142 else
143 dst[3] = 0xFF; // set the alpha channel byte to opaque
144 }
145 };
146
147 struct PixelTransSkip32
148 {
operator ()AGS::Common::BitmapHelper::PixelTransSkip32149 inline bool operator ()(uint8_t *data, color_t mask_color, bool use_alpha) const
150 {
151 return *(uint32_t*)data == mask_color || use_alpha && data[3] == 0;
152 }
153 };
154
155 template <class FnPxProc, class FnSkip>
ApplyMask(uint8_t * dst,const uint8_t * src,size_t pitch,size_t height,FnPxProc proc,FnSkip skip,color_t mask_color,bool dst_has_alpha,bool mask_has_alpha)156 void ApplyMask(uint8_t *dst, const uint8_t *src, size_t pitch, size_t height, FnPxProc proc, FnSkip skip, color_t mask_color, bool dst_has_alpha, bool mask_has_alpha)
157 {
158 for (size_t y = 0; y < height; ++y)
159 {
160 for (size_t x = 0; x < pitch; x += FnPxProc::BPP, src += FnPxProc::BPP, dst += FnPxProc::BPP)
161 {
162 if (!skip(dst, mask_color, dst_has_alpha))
163 proc(dst, src, mask_color, mask_has_alpha);
164 }
165 }
166 }
167
CopyTransparency(Bitmap * dst,const Bitmap * mask,bool dst_has_alpha,bool mask_has_alpha)168 void CopyTransparency(Bitmap *dst, const Bitmap *mask, bool dst_has_alpha, bool mask_has_alpha)
169 {
170 color_t mask_color = mask->GetMaskColor();
171 uint8_t *dst_ptr = dst->GetDataForWriting();
172 const uint8_t *src_ptr = mask->GetData();
173 const size_t bpp = mask->GetBPP();
174 const size_t pitch = mask->GetLineLength();
175 const size_t height = mask->GetHeight();
176
177 if (bpp == 1)
178 ApplyMask(dst_ptr, src_ptr, pitch, height, PixelTransCpy8(), PixelNoSkip(), mask_color, dst_has_alpha, mask_has_alpha);
179 else if (bpp == 2)
180 ApplyMask(dst_ptr, src_ptr, pitch, height, PixelTransCpy16(), PixelNoSkip(), mask_color, dst_has_alpha, mask_has_alpha);
181 else if (bpp == 3)
182 ApplyMask(dst_ptr, src_ptr, pitch, height, PixelTransCpy24(), PixelNoSkip(), mask_color, dst_has_alpha, mask_has_alpha);
183 else
184 ApplyMask(dst_ptr, src_ptr, pitch, height, PixelTransCpy32(), PixelTransSkip32(), mask_color, dst_has_alpha, mask_has_alpha);
185 }
186
ReadPixelsFromMemory(Bitmap * dst,const uint8_t * src_buffer,const size_t src_pitch,const size_t src_px_offset)187 void ReadPixelsFromMemory(Bitmap *dst, const uint8_t *src_buffer, const size_t src_pitch, const size_t src_px_offset)
188 {
189 const size_t bpp = dst->GetBPP();
190 const size_t src_px_pitch = src_pitch / bpp;
191 if (src_px_offset >= src_px_pitch)
192 return; // nothing to copy
193 Memory::BlockCopy(dst->GetDataForWriting(), dst->GetLineLength(), 0, src_buffer, src_pitch, src_px_offset * bpp, dst->GetHeight());
194 }
195
196 // TODO: redo this ugly workaround
197 // Unfortunately some of the allegro functions remaining in code require "screen"
198 // allegro bitmap, therefore we must set that pointer to something every time we
199 // assign an Bitmap to screen.
GetScreenBitmap()200 Bitmap *GetScreenBitmap()
201 {
202 return gl_ScreenBmp;
203 }
204
SetScreenBitmap(Bitmap * bitmap)205 void SetScreenBitmap(Bitmap *bitmap)
206 {
207 // We do not delete previous object here since we can't tell
208 // where it came from and whether it still exists.
209 // (Did I mention this is an ugly workaround? So...)
210 gl_ScreenBmp = bitmap;
211
212 // Only set allegro screen pointer if there's actual bitmap;
213 // setting it to NULL does not have any sense and may (will?)
214 // cause crashes.
215 if (gl_ScreenBmp)
216 {
217 screen = (BITMAP*)gl_ScreenBmp->GetAllegroBitmap();
218 }
219 }
220
221 } // namespace BitmapHelper
222
223 } // namespace Common
224 } // namespace AGS
225