1 #ifndef _INCLUDED_AWTEXLD_HPP_
2 #define _INCLUDED_AWTEXLD_HPP_
3 
4 #include "awtexld.h"
5 #include "media.hpp"
6 #include "db.h"
7 #ifndef DB_COMMA
8 	#define DB_COMMA ,
9 #endif
10 
11 namespace AwTl {
12 
13 	#define CANT_HAPPEN db_msgf1(("AwCreateTexture(): (Line %u) CAN'T HAPPEN!",__LINE__));
14 
15 	/*********************************/
16 	/* Pixel format global structure */
17 	/*********************************/
18 
19 	struct PixelFormat
20 	{
PixelFormatAwTl::PixelFormat21 		PixelFormat() : validB(false){}
22 
23 		bool palettizedB : 1;
24 		bool alphaB : 1;
25 		bool validB : 1;
26 		bool texB : 1;
27 
28 		unsigned bitsPerPixel;
29 		unsigned redLeftShift;
30 		unsigned redRightShift;
31 		unsigned greenLeftShift;
32 		unsigned greenRightShift;
33 		unsigned blueLeftShift;
34 		unsigned blueRightShift;
35 
36 		unsigned dwRGBAlphaBitMask;
37 //		DDPIXELFORMAT ddpf;
38 	};
39 
40 	// DO SOMTHING ABOUT THIS
41 	extern PixelFormat pixelFormat;
42 	extern PixelFormat pfSurfaceFormat;
43 
44 	class CreateTextureParms;
45 
46 	/********************/
47 	/* Colour structure */
48 	/********************/
49 
50 	struct Colour
51 	{
52 		BYTE r,g,b;
53 
54 		class ConvNonTransp
55 		{
56 			public:
DoConv(Colour const * _colP,Colour const * =NULL db_code1 (DB_COMMA unsigned=0))57 				static inline unsigned DoConv (Colour const * _colP, Colour const * = NULL db_code1(DB_COMMA unsigned = 0))
58 				{
59 					return
60 						 static_cast<unsigned>(_colP->r)>>pixelFormat.redRightShift<<pixelFormat.redLeftShift
61 						|static_cast<unsigned>(_colP->g)>>pixelFormat.greenRightShift<<pixelFormat.greenLeftShift
62 						|static_cast<unsigned>(_colP->b)>>pixelFormat.blueRightShift<<pixelFormat.blueLeftShift
63 						|pixelFormat.dwRGBAlphaBitMask;
64 				}
DoConv(BYTE const * _colP,Colour const * _paletteP db_code1 (DB_COMMA unsigned _paletteSize))65 				static inline unsigned DoConv(BYTE const * _colP, Colour const * _paletteP db_code1(DB_COMMA unsigned _paletteSize))
66 				{
67 					db_assert1(_paletteP);
68 					db_onlyassert1(*_colP < _paletteSize);
69 					return DoConv(&_paletteP[*_colP]);
70 				}
71 		};
72 
73 		class ConvTransp
74 		{
75 			private:
MakeNonTranspCol(Colour const * _colP)76 				static inline unsigned MakeNonTranspCol(Colour const * _colP)
77 				{
78 					unsigned rv = ConvNonTransp::DoConv(_colP);
79 					if (rv) return rv;
80 					// make one of r,g or b in the output == 1, choose the one which is closest to the input
81 					unsigned rdiff = (1<<pixelFormat.redRightShift) - _colP->r;
82 					unsigned bdiff = (1<<pixelFormat.blueRightShift) - _colP->b;
83 					unsigned gdiff = (1<<pixelFormat.greenRightShift) - _colP->g;
84 					if (bdiff<=rdiff && bdiff<=gdiff)
85 						return 1<<pixelFormat.blueLeftShift;
86 					else if (rdiff<=gdiff)
87 						return 1<<pixelFormat.redLeftShift;
88 					else
89 						return 1<<pixelFormat.greenLeftShift;
90 				}
91 			public:
DoConv(Colour const * _colP,Colour const * =NULL db_code1 (DB_COMMA unsigned=0))92 				static inline unsigned DoConv (Colour const * _colP, Colour const * = NULL db_code1(DB_COMMA unsigned = 0))
93 				{
94 					if (!_colP->b && !_colP->r && !_colP->g)
95 						//return pixelFormat.alphaB ? pixelFormat.ddsd.ddpfPixelFormat.dwRBitMask|pixelFormat.ddsd.ddpfPixelFormat.dwGBitMask|pixelFormat.ddsd.ddpfPixelFormat.dwBBitMask : 0;
96 						return 0;
97 					else
98 						return MakeNonTranspCol(_colP);
99 				}
DoConv(BYTE const * _colP,Colour const * _paletteP db_code1 (DB_COMMA unsigned _paletteSize))100 				static inline unsigned DoConv(BYTE const * _colP, Colour const * _paletteP db_code1(DB_COMMA unsigned _paletteSize))
101 				{
102 					db_assert1(_paletteP);
103 					db_onlyassert1(*_colP < _paletteSize);
104 					if (!*_colP)
105 						//return pixelFormat.alphaB ? pixelFormat.ddsd.ddpfPixelFormat.dwRBitMask|pixelFormat.ddsd.ddpfPixelFormat.dwGBitMask|pixelFormat.ddsd.ddpfPixelFormat.dwBBitMask : 0;
106 						return 0;
107 					else
108 						return MakeNonTranspCol(&_paletteP[*_colP]);
109 				}
110 		};
111 
112 		class ConvNull
113 		{
114 			public:
115 				static inline unsigned DoConv (BYTE const * _colP, Colour const * db_code1(DB_COMMA unsigned = 0))
116 				{
117 					db_assert1(pixelFormat.palettizedB);
118 					return *_colP;
119 				}
120 		};
121 	};
122 
123 	/*****************/
124 	/* Pointer union */
125 	/*****************/
126 
127 	union SurfUnion
128 	{
129 		D3DTexture * textureP;
130 		DDSurface * surfaceP;
131 		void * voidP;
SurfUnion()132 		SurfUnion(){}
SurfUnion(void * p)133 		SurfUnion(void * p) : voidP(p){}
134 	};
135 
136 	union PtrUnion
137 	{
138 		void * voidP;
139 		char * charP;
140 		signed char * scharP;
141 		unsigned char * ucharP;
142 		BYTE * byteP;
143 		short * shortP;
144 		unsigned short * ushortP;
145 		WORD * wordP;
146 		signed * intP;
147 		unsigned * uintP;
148 		DWORD * dwordP;
149 		long * longP;
150 		unsigned long * ulongP;
151 		Colour * colourP;
152 
PtrUnion()153 		inline PtrUnion(){}
PtrUnion(void * _voidP)154 		inline PtrUnion(void * _voidP):voidP(_voidP){}
operator void*() const155 		inline operator void * () const { return voidP; }
156 	};
157 
158 	union PtrUnionConst
159 	{
160 		void const * voidP;
161 		char const * charP;
162 		signed char const * scharP;
163 		unsigned char const * ucharP;
164 		BYTE const * byteP;
165 		short const * shortP;
166 		unsigned short const * ushortP;
167 		WORD const * wordP;
168 		signed const * intP;
169 		unsigned const * uintP;
170 		DWORD const * dwordP;
171 		long const * longP;
172 		unsigned long const * ulongP;
173 		Colour const * colourP;
174 
PtrUnionConst()175 		inline PtrUnionConst(){}
PtrUnionConst(void const * _voidP)176 		inline PtrUnionConst(void const * _voidP):voidP(_voidP){}
PtrUnionConst(PtrUnion _uP)177 		inline PtrUnionConst(PtrUnion _uP):voidP(_uP.voidP){}
operator void const*() const178 		inline operator void const * () const { return voidP; }
179 	};
180 
181 	/***************************************/
182 	/* Generic copying to surface function */
183 	/***************************************/
184 
185 	template<class CONVERT, class SRCTYPE>
186 	class GenericConvertRow
187 	{
188 		public:
189 			static void Do (PtrUnion _dstRowP, unsigned _dstWidth, SRCTYPE const * _srcRowP, unsigned _srcWidth, Colour const * _paletteP = NULL db_code1(DB_COMMA unsigned _paletteSize = 0));
190 	};
191 
192 	template<class CONVERT, class SRCTYPE>
Do(PtrUnion _dstRowP,unsigned _dstWidth,SRCTYPE const * _srcRowP,unsigned _srcWidth,Colour const * _paletteP db_code1 (DB_COMMA unsigned _paletteSize))193 	void GenericConvertRow<CONVERT, SRCTYPE>::Do (PtrUnion _dstRowP, unsigned _dstWidth, SRCTYPE const * _srcRowP, unsigned _srcWidth, Colour const * _paletteP db_code1(DB_COMMA unsigned _paletteSize))
194 	{
195 		switch (pixelFormat.bitsPerPixel)
196 		{
197 			default:
198 				CANT_HAPPEN
199 			case 16:
200 			{
201 				db_assert1(!pixelFormat.palettizedB);
202 				for (unsigned colcount = _srcWidth; colcount; --colcount)
203 				{
204 					*_dstRowP.wordP++ = static_cast<WORD>(CONVERT::DoConv(_srcRowP++,_paletteP db_code1(DB_COMMA _paletteSize)));
205 				}
206 				if (_srcWidth<_dstWidth)
207 					*_dstRowP.wordP = static_cast<WORD>(CONVERT::DoConv(_srcRowP-1,_paletteP db_code1(DB_COMMA _paletteSize)));
208 				break;
209 			}
210 			case 24:
211 			{
212 				db_assert1(!pixelFormat.palettizedB);
213 				union { DWORD dw; BYTE b[3]; } u;
214 				for (unsigned colcount = _srcWidth; colcount; --colcount)
215 				{
216 					u.dw = static_cast<DWORD>(CONVERT::DoConv(_srcRowP++,_paletteP db_code1(DB_COMMA _paletteSize)));
217 					*_dstRowP.byteP++ = u.b[0];
218 					*_dstRowP.byteP++ = u.b[1];
219 					*_dstRowP.byteP++ = u.b[2];
220 				}
221 				if (_srcWidth<_dstWidth)
222 				{
223 					*_dstRowP.byteP++ = u.b[0];
224 					*_dstRowP.byteP++ = u.b[1];
225 					*_dstRowP.byteP = u.b[2];
226 				}
227 				break;
228 			}
229 			case 32:
230 			{
231 				db_assert1(!pixelFormat.palettizedB);
232 				for (unsigned colcount = _srcWidth; colcount; --colcount)
233 				{
234 					*_dstRowP.dwordP++ = static_cast<DWORD>(CONVERT::DoConv(_srcRowP++,_paletteP db_code1(DB_COMMA _paletteSize)));
235 				}
236 				if (_srcWidth<_dstWidth)
237 					*_dstRowP.dwordP = static_cast<DWORD>(CONVERT::DoConv(_srcRowP-1,_paletteP db_code1(DB_COMMA _paletteSize)));
238 				break;
239 			}
240 			case 8:
241 			{
242 				for (unsigned colcount = _srcWidth; colcount; --colcount)
243 				{
244 					*_dstRowP.byteP++ = static_cast<BYTE>(CONVERT::DoConv(_srcRowP++,_paletteP db_code1(DB_COMMA _paletteSize)));
245 				}
246 				if (_srcWidth<_dstWidth)
247 					*_dstRowP.byteP = static_cast<BYTE>(CONVERT::DoConv(_srcRowP-1,_paletteP db_code1(DB_COMMA _paletteSize)));
248 				break;
249 			}
250 			case 1:
251 			case 2:
252 				db_assert1(pixelFormat.palettizedB);
253 			case 4:
254 			{
255 				unsigned shift=0;
256 				unsigned val=0;
257 				--_dstRowP.byteP; // decrement here because we increment before the first write
258 				for (unsigned colcount = _srcWidth; colcount; --colcount)
259 				{
260 					val = CONVERT::DoConv(_srcRowP++,_paletteP db_code1(DB_COMMA _paletteSize));
261 					if (!shift)
262 						*++_dstRowP.byteP = static_cast<BYTE>(val);
263 					else
264 						*_dstRowP.byteP |= static_cast<BYTE>(val<<shift);
265 					shift += pixelFormat.bitsPerPixel;
266 					shift &= 7;
267 				}
268 				if (_srcWidth<_dstWidth)
269 				{
270 					if (!shift)
271 						*++_dstRowP.byteP = static_cast<BYTE>(val);
272 					else
273 						*_dstRowP.byteP |= static_cast<BYTE>(val<<shift);
274 				}
275 				break;
276 			}
277 		}
278 	}
279 
280 	// reference counting support
281 	class RefCntObj
282 	{
283 		public:
AddRef()284 			unsigned AddRef() { return ++m_nRefCnt; }
Release()285 			unsigned Release() { if (0==(--m_nRefCnt)) { delete this; return 0;} else return m_nRefCnt; }
286 		protected:
~RefCntObj()287 			virtual ~RefCntObj(){
288 				#ifndef NDEBUG
289 					DbForget(this);
290 				#endif
291 			}
RefCntObj()292 			RefCntObj() : m_nRefCnt(1){
293 				#ifndef NDEBUG
294 					DbRemember(this);
295 				#endif
296 			}
RefCntObj(RefCntObj const &)297 			RefCntObj(RefCntObj const &) : m_nRefCnt(1){
298 				#ifndef NDEBUG
299 					DbRemember(this);
300 				#endif
301 			}
operator =(RefCntObj const &)302 			RefCntObj & operator = (RefCntObj const &){ return *this;}
303 		private:
304 			unsigned m_nRefCnt;
305 
306 		#ifndef NDEBUG
307 			friend void DbRemember(RefCntObj * pObj);
308 			friend void DbForget(RefCntObj * pObj);
309 			friend class AllocList;
310 		#endif
311 	};
312 
313 	SurfUnion LoadFromParams(CreateTextureParms *);
314 
315 } // namespace AwTl
316 
317 struct AwBackupTexture : public AwTl::RefCntObj
318 {
319 	public:
320 		AwTl::SurfUnion Restore(AwTl::CreateTextureParms const & rParams);
321 	protected:
322 		AwTl::SurfUnion CreateTexture(AwTl::CreateTextureParms const & rParams);
323 
324 		void ChoosePixelFormat(AwTl::CreateTextureParms const & rParams);
325 
~AwBackupTextureAwBackupTexture326 		virtual ~AwBackupTexture(){}
327 
328 		// return the number of unique colours in the image or zero if this cannot be determined
329 		virtual unsigned GetNumColours() = 0;
330 
331 		// return the smallest palette size that is available for the image
332 		virtual unsigned GetMinPaletteSize() = 0;
333 
334 		// return true if the image has a single transparent colour
335 		virtual bool HasTransparentMask(bool bDefault);
336 
337 		// called when a backup texture is about to be used for restoring, but after the above two functions have been called
338 		virtual void OnBeginRestoring(unsigned nMaxPaletteSize);
339 
340 		virtual AwTl::Colour * GetPalette() = 0;
341 
342 		virtual bool AreRowsReversed();
343 
344 		virtual AwTl::PtrUnion GetRowPtr(unsigned nRow) = 0;
345 
346 		virtual void LoadNextRow(AwTl::PtrUnion pRow) = 0;
347 
348 		virtual void ConvertRow(AwTl::PtrUnion pDest, unsigned nDestWidth, AwTl::PtrUnionConst pSrc, unsigned nSrcOffset, unsigned nSrcWidth, AwTl::Colour * pPalette db_code1(DB_COMMA unsigned nPaletteSize));
349 
350 		virtual DWORD GetTransparentColour();
351 
352 		virtual void OnFinishRestoring(bool bSuccess);
353 
354 		// metrics
355 		unsigned m_nWidth;
356 		unsigned m_nHeight;
357 		unsigned m_nPaletteSize; // 0 inicates no palette
358 
359 		unsigned m_fFlags;
360 
361 	private:
362 		bool m_bTranspMask;
363 
364 	friend AwTl::SurfUnion AwTl::LoadFromParams(AwTl::CreateTextureParms *);
365 };
366 
367 namespace AwTl {
368 
369 	class TypicalBackupTexture : public ::AwBackupTexture
370 	{
371 		public:
TypicalBackupTexture(AwBackupTexture const & rBase,PtrUnion * ppPixMap,Colour * pPalette)372 			TypicalBackupTexture(AwBackupTexture const & rBase, PtrUnion * ppPixMap, Colour * pPalette)
373 				: AwBackupTexture(rBase)
374 				, m_ppPixMap(ppPixMap)
375 				, m_pPalette(pPalette)
376 			{}
377 
~TypicalBackupTexture()378 			virtual ~TypicalBackupTexture()
379 			{
380 				if (m_pPalette)
381 				{
382 					delete[] m_pPalette;
383 					if (m_ppPixMap)
384 					{
385 						delete[] m_ppPixMap->byteP;
386 						delete[] m_ppPixMap;
387 					}
388 				}
389 				else
390 				{
391 					if (m_ppPixMap)
392 					{
393 						delete[] m_ppPixMap->colourP;
394 						delete[] m_ppPixMap;
395 					}
396 				}
397 			}
398 
399 			virtual Colour * GetPalette();
400 
401 			virtual PtrUnion GetRowPtr(unsigned nRow);
402 
403 			virtual void LoadNextRow(PtrUnion pRow);
404 
405 			// note: the palette size member must be set in
406 			// LoadHeaderInfo() for these functions to work correctly
407 			virtual unsigned GetNumColours();
408 
409 			virtual unsigned GetMinPaletteSize();
410 
411 		private:
412 			PtrUnion * m_ppPixMap;
413 			Colour * m_pPalette;
414 	};
415 
416 	class TexFileLoader : public AwBackupTexture
417 	{
418 		public:
419 			SurfUnion Load(MediaMedium * pMedium, CreateTextureParms const & rParams);
420 
421 		protected:
422 			// standard constructor
423 			// & destructor
424 
425 			// Interface Functions. Each overridden version should set awTlLastErr
426 			// when an error occurs
427 
428 			// Called to set the width and height members; the palette size member can also be safely set at this point.
429 			// Neither the width height or palette size members need actually be set until AllocateBuffers returns
430 			virtual void LoadHeaderInfo(MediaMedium * pMedium) = 0;
431 
432 			// should ensure that the palette size is set
433 			virtual void AllocateBuffers(bool bWantBackup, unsigned nMaxPaletteSize) = 0;
434 
435 			virtual void OnFinishLoading(bool bSuccess);
436 
437 			virtual AwBackupTexture * CreateBackupTexture() = 0;
438 	};
439 
440 	class TypicalTexFileLoader : public TexFileLoader
441 	{
442 		protected:
TypicalTexFileLoader()443 			TypicalTexFileLoader() : m_pPalette(NULL), m_ppPixMap(NULL), m_pRowBuf(NULL) {}
444 
445 			virtual ~TypicalTexFileLoader();
446 
447 			virtual unsigned GetNumColours();
448 
449 			virtual unsigned GetMinPaletteSize();
450 
451 			virtual void AllocateBuffers(bool bWantBackup, unsigned nMaxPaletteSize);
452 
453 			virtual PtrUnion GetRowPtr(unsigned nRow);
454 
455 			virtual AwBackupTexture * CreateBackupTexture();
456 
457 			Colour * m_pPalette;
458 		private:
459 			PtrUnion * m_ppPixMap;
460 
461 			PtrUnion m_pRowBuf;
462 	};
463 
464 	extern void RegisterLoader(char const * pszMagic, AwTl::TexFileLoader * (* pfnCreate) () );
465 
466 } // namespace AwTl
467 
468 #define AWTEXLD_IMPLEMENT_DYNCREATE(pszMagic, tokenClassName) _AWTEXLD_IMPLEMENT_DYNCREATE_LINE_EX(pszMagic,tokenClassName,__LINE__)
469 #define _AWTEXLD_IMPLEMENT_DYNCREATE_LINE_EX(pszMagic, tokenClassName, nLine) _AWTEXLD_IMPLEMENT_DYNCREATE_LINE(pszMagic,tokenClassName,nLine)
470 
471 #define _AWTEXLD_IMPLEMENT_DYNCREATE_LINE(pszMagic,tokenClassName,nLine) \
472 	AwTl::TexFileLoader * AwTlCreateClassObject ##_## tokenClassName ##_## nLine () { \
473 		return new tokenClassName; \
474 	} \
475 	class AwTlRegisterLoaderClass ##_## tokenClassName ##_## nLine { \
476 		public: AwTlRegisterLoaderClass ##_## tokenClassName ##_## nLine () { \
477 			AwTl::RegisterLoader(pszMagic, AwTlCreateClassObject ##_## tokenClassName ##_## nLine); \
478 		} \
479 	} rlc ## tokenClassName ##_## nLine;
480 
481 #endif // ! _INCLUDED_AWTEXLD_HPP_
482