1 /*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 1998-2000, Matthes Bender
5 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6 * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7 *
8 * Distributed under the terms of the ISC license; see accompanying file
9 * "COPYING" for details.
10 *
11 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12 * See accompanying file "TRADEMARK" for details.
13 *
14 * To redistribute this file separately, substitute the full license texts
15 * for the above references.
16 */
17 // a wrapper class to DirectDraw surfaces
18
19 #include "C4Include.h"
20 #include "graphics/CSurface8.h"
21
22 #include "graphics/Bitmap256.h"
23 #include "c4group/CStdFile.h"
24 #include "lib/StdColors.h"
25
CSurface8()26 CSurface8::CSurface8()
27 {
28 Wdt=Hgt=Pitch=0;
29 ClipX=ClipY=ClipX2=ClipY2=0;
30 Bits=nullptr;
31 pPal=nullptr;
32 }
33
CSurface8(int iWdt,int iHgt)34 CSurface8::CSurface8(int iWdt, int iHgt)
35 {
36 Wdt=Hgt=Pitch=0;
37 ClipX=ClipY=ClipX2=ClipY2=0;
38 Bits=nullptr;
39 pPal=nullptr;
40 Create(iWdt, iHgt);
41 }
42
~CSurface8()43 CSurface8::~CSurface8()
44 {
45 Clear();
46 }
47
Clear()48 void CSurface8::Clear()
49 {
50 // clear bitmap-copy
51 delete [] Bits; Bits=nullptr;
52 // clear pal
53 delete pPal;
54 pPal=nullptr;
55 }
56
Box(int iX,int iY,int iX2,int iY2,int iCol)57 void CSurface8::Box(int iX, int iY, int iX2, int iY2, int iCol)
58 {
59 for (int cy=iY; cy<=iY2; cy++) HLine(iX,iX2,cy,iCol);
60 }
61
NoClip()62 void CSurface8::NoClip()
63 {
64 ClipX=0; ClipY=0; ClipX2=Wdt-1; ClipY2=Hgt-1;
65 }
66
Clip(int iX,int iY,int iX2,int iY2)67 void CSurface8::Clip(int iX, int iY, int iX2, int iY2)
68 {
69 ClipX=Clamp(iX,0,Wdt-1); ClipY=Clamp(iY,0,Hgt-1);
70 ClipX2=Clamp(iX2,0,Wdt-1); ClipY2=Clamp(iY2,0,Hgt-1);
71 }
72
HLine(int iX,int iX2,int iY,int iCol)73 void CSurface8::HLine(int iX, int iX2, int iY, int iCol)
74 {
75 for (int cx=iX; cx<=iX2; cx++) SetPix(cx,iY,iCol);
76 }
77
Create(int iWdt,int iHgt)78 bool CSurface8::Create(int iWdt, int iHgt)
79 {
80 Clear();
81 // check size
82 if (!iWdt || !iHgt) return false;
83 Wdt=iWdt; Hgt=iHgt;
84
85 // create pal
86 pPal = new CStdPalette;
87 if (!pPal) return false;
88 memset(pPal->Colors, 0, sizeof(pPal->Colors));
89
90 Bits=new BYTE[Wdt*Hgt];
91 if (!Bits) return false;
92 memset(Bits, 0, Wdt*Hgt);
93 Pitch=Wdt;
94 // update clipping
95 NoClip();
96 return true;
97 }
98
Read(CStdStream & hGroup)99 bool CSurface8::Read(CStdStream &hGroup)
100 {
101 int cnt,lcnt;
102 C4BMP256Info BitmapInfo;
103 // read bmpinfo-header
104 if (!hGroup.Read(&BitmapInfo,sizeof(C4BMPInfo))) return false;
105 // is it 8bpp?
106 if (BitmapInfo.Info.biBitCount == 8)
107 {
108 if (!hGroup.Read(((BYTE *) &BitmapInfo)+sizeof(C4BMPInfo),sizeof(BitmapInfo)-sizeof(C4BMPInfo))) return false;
109 if (!hGroup.Advance(BitmapInfo.FileBitsOffset())) return false;
110 }
111 else
112 {
113 // read 24bpp
114 if (BitmapInfo.Info.biBitCount != 24) return false;
115 if (!hGroup.Advance(((C4BMPInfo) BitmapInfo).FileBitsOffset())) return false;
116 }
117
118 // Create and lock surface
119 if (!Create(BitmapInfo.Info.biWidth,BitmapInfo.Info.biHeight)) return false;
120
121 if (BitmapInfo.Info.biBitCount == 8)
122 {
123 // Copy palette
124 for (cnt=0; cnt<256; cnt++)
125 {
126 pPal->Colors[cnt] = C4RGB(BitmapInfo.Colors[cnt].rgbRed,
127 BitmapInfo.Colors[cnt].rgbGreen,
128 BitmapInfo.Colors[cnt].rgbBlue);
129 }
130 }
131
132 // create line buffer
133 int iBufSize=DWordAligned(BitmapInfo.Info.biWidth*BitmapInfo.Info.biBitCount/8);
134 BYTE *pBuf = new BYTE[iBufSize];
135 // Read lines
136 for (lcnt=Hgt-1; lcnt>=0; lcnt--)
137 {
138 if (!hGroup.Read(pBuf, iBufSize))
139 { Clear(); delete [] pBuf; return false; }
140 BYTE *pPix=pBuf;
141 for (int x=0; x<BitmapInfo.Info.biWidth; ++x)
142 switch (BitmapInfo.Info.biBitCount)
143 {
144 case 8:
145 SetPix(x, lcnt, *pPix++);
146 break;
147 case 24:
148 return false;
149 break;
150 }
151 }
152 // free buffer again
153 delete [] pBuf;
154
155 return true;
156 }
157
Save(const char * szFilename,CStdPalette * bpPalette)158 bool CSurface8::Save(const char *szFilename, CStdPalette *bpPalette)
159 {
160 C4BMP256Info BitmapInfo;
161 BitmapInfo.Set(Wdt,Hgt, bpPalette ? bpPalette : pPal);
162
163 // Create file & write info
164 CStdFile hFile;
165
166 if ( !hFile.Create(szFilename)
167 || !hFile.Write(&BitmapInfo,sizeof(BitmapInfo)) )
168 { return false; }
169
170 // Write lines
171 char bpEmpty[4]; ZeroMem(bpEmpty, 4);
172 const int iEmpty = DWordAligned(Wdt)-Wdt;
173 for (int cnt=Hgt-1; cnt>=0; cnt--)
174 {
175 if (!hFile.Write(Bits+(Pitch*cnt),Wdt))
176 { return false; }
177 if (iEmpty)
178 if (!hFile.Write(bpEmpty,iEmpty))
179 { return false; }
180 }
181
182 // Close file
183 hFile.Close();
184
185 // Success
186 return true;
187 }
188
MapBytes(BYTE * bpMap)189 void CSurface8::MapBytes(BYTE *bpMap)
190 {
191 if (!bpMap) return;
192 for (int cnt=0; cnt<Wdt*Hgt; cnt++) SetPix(cnt%Wdt, cnt/Wdt, bpMap[GetPix(cnt%Wdt, cnt/Wdt)]);
193 }
194
GetSurfaceSize(int & irX,int & irY) const195 void CSurface8::GetSurfaceSize(int &irX, int &irY) const
196 {
197 // simply assign stored values
198 irX=Wdt;
199 irY=Hgt;
200 }
201
ClearBox8Only(int iX,int iY,int iWdt,int iHgt)202 void CSurface8::ClearBox8Only(int iX, int iY, int iWdt, int iHgt)
203 {
204 // clear rect; assume clip already
205 for (int y=iY; y<iY+iHgt; ++y)
206 for (int x=iX; x<iX+iWdt; ++x)
207 Bits[y*Pitch+x] = 0;
208 // done
209 }
210
211
Circle(int x,int y,int r,BYTE col)212 void CSurface8::Circle(int x, int y, int r, BYTE col)
213 {
214 for (int ycnt=-r; ycnt<r; ycnt++)
215 {
216 int lwdt = (int) sqrt(float(r*r-ycnt*ycnt));
217 for (int xcnt = 2 * lwdt - 1; xcnt >= 0; xcnt--)
218 SetPix(x - lwdt + xcnt, y + ycnt, col);
219 }
220 }
221
AllowColor(BYTE iRngLo,BYTE iRngHi,bool fAllowZero)222 void CSurface8::AllowColor(BYTE iRngLo, BYTE iRngHi, bool fAllowZero)
223 {
224 // change colors
225 int xcnt,ycnt;
226 if (iRngHi<iRngLo) return;
227 for (ycnt=0; ycnt<Hgt; ycnt++)
228 {
229 for (xcnt=0; xcnt<Wdt; xcnt++)
230 {
231 BYTE px=GetPix(xcnt,ycnt);
232 if (px || !fAllowZero)
233 if ((px<iRngLo) || (px>iRngHi))
234 SetPix(xcnt, ycnt, iRngLo + px % (iRngHi-iRngLo+1));
235 }
236 }
237 }
238
SetBuffer(BYTE * pbyToBuf,int Wdt,int Hgt,int Pitch)239 void CSurface8::SetBuffer(BYTE *pbyToBuf, int Wdt, int Hgt, int Pitch)
240 {
241 // release old
242 Clear();
243 // set new
244 this->Wdt=Wdt;
245 this->Hgt=Hgt;
246 this->Pitch=Pitch;
247 this->Bits = pbyToBuf;
248 NoClip();
249 }
250
ReleaseBuffer()251 void CSurface8::ReleaseBuffer()
252 {
253 this->Bits = nullptr;
254 Clear();
255 }
256