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