1 /*
2  *	img.cc - Game image object (255 colours + transparency)
3  *	AYM 2000-06-13
4  */
5 
6 
7 /*
8 This file is part of Yadex.
9 
10 Yadex incorporates code from DEU 5.21 that was put in the public domain in
11 1994 by Rapha�l Quinet and Brendon Wyber.
12 
13 The rest of Yadex is Copyright � 1997-2003 Andr� Majorel and others.
14 
15 This program is free software; you can redistribute it and/or modify it under
16 the terms of the GNU General Public License as published by the Free Software
17 Foundation; either version 2 of the License, or (at your option) any later
18 version.
19 
20 This program is distributed in the hope that it will be useful, but WITHOUT
21 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
23 
24 You should have received a copy of the GNU General Public License along with
25 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
26 Place, Suite 330, Boston, MA 02111-1307, USA.
27 */
28 
29 
30 #include "yadex.h"
31 #include "help1.h"
32 #include "img.h"
33 #include "wadfile.h"
34 #include "wads.h"
35 
36 
37 // Holds the private data members
38 class Img_priv
39 {
40   public:
Img_priv()41     Img_priv () { buf = 0; width = 0; height = 0; opaque = false; }
~Img_priv()42     ~Img_priv () { if (buf != 0) delete[] buf; }
43     img_pixel_t *buf;
44     img_dim_t    width;
45     img_dim_t    height;
46     bool         opaque;
47 };
48 
49 
50 /*
51  *	Img::Img - default constructor
52  *
53  *	The new image is a null image.
54  */
Img()55 Img::Img ()
56 {
57   p = new Img_priv;
58 }
59 
60 
61 /*
62  *	Img::Img - constructor with dimensions
63  *
64  *	The new image is set to the specified dimensions.
65  */
Img(img_dim_t width,img_dim_t height,bool opaque)66 Img::Img (img_dim_t width, img_dim_t height, bool opaque)
67 {
68   p = new Img_priv;
69   resize (width, height);
70   set_opaque (opaque);
71 }
72 
73 
74 /*
75  *	Img::~Img - dtor
76  */
~Img()77 Img::~Img ()
78 {
79   delete p;
80 }
81 
82 
83 /*
84  *	Img::is_null - return true iff this is a null image
85  */
is_null() const86 bool Img::is_null () const
87 {
88   return p->buf == 0;
89 }
90 
91 
92 /*
93  *	Img::width - return the current width
94  *
95  *	If the image is null, return 0.
96  */
width() const97 img_dim_t Img::width () const
98 {
99   return p->width;
100 }
101 
102 
103 /*
104  *	Img::height - return the current height
105  *
106  *	If the image is null, return 0.
107  */
height() const108 img_dim_t Img::height () const
109 {
110   return p->height;
111 }
112 
113 
114 /*
115  *	Img::buf - return a const pointer on the buffer
116  *
117  *	If the image is null, return a null pointer.
118  */
buf() const119 const img_pixel_t *Img::buf () const
120 {
121   return p->buf;
122 }
123 
124 
125 /*
126  *	Img::wbuf - return a writable pointer on the buffer
127  *
128  *	If the image is null, return a null pointer.
129  */
wbuf()130 img_pixel_t *Img::wbuf ()
131 {
132   return p->buf;
133 }
134 
135 
136 /*
137  *	Img::clear - clear the image
138  */
clear()139 void Img::clear ()
140 {
141   if (p->buf != 0)
142     memset (p->buf, IMG_TRANSP, p->width * p->height);
143 }
144 
145 
146 /*
147  *	Img::set_opaque - set or clear the opaque flag
148  */
set_opaque(bool opaque)149 void Img::set_opaque (bool opaque)
150 {
151   p->opaque = opaque;
152 }
153 
154 
155 /*
156  *	Img::resize - resize the image
157  *
158  *	If either dimension is zero, the image becomes a null
159  *	image.
160  */
resize(img_dim_t width,img_dim_t height)161 void Img::resize (img_dim_t width, img_dim_t height)
162 {
163   if (width == p->width && height == p->height)
164     return;
165 
166   // Unallocate old buffer
167   if (p->buf != 0)
168   {
169     delete[] p->buf;
170     p->buf = 0;
171   }
172 
173   // Is it a null image ?
174   if (width == 0 || height == 0)
175   {
176     p->width  = 0;
177     p->height = 0;
178     return;
179   }
180 
181   // Allocate new buffer
182   p->width  = width;
183   p->height = height;
184   p->buf = new img_pixel_t[width * height + 10];  // Some slack
185   clear ();
186 }
187 
188 
189 /*
190  *	Img::save - save an image to file in packed PPM format
191  *
192  *	Return 0 on success, non-zero on failure
193  *
194  *	If an error occurs, errno is set to:
195  *	- ECHILD if PLAYPAL could not be loaded
196  *	- whatever fopen() or fclose() set it to
197  */
save(const char * filename) const198 int Img::save (const char *filename) const
199 {
200   int rc = 0;
201   FILE *fp = 0;
202 
203   // Load palette 0 from PLAYPAL
204   MDirPtr dir = FindMasterDir (MasterDir, "PLAYPAL");
205   if (dir == 0)
206   {
207     errno = ECHILD;
208     return 1;
209   }
210   unsigned char *pal = new unsigned char[768];
211   dir->wadfile->seek (dir->dir.start);
212   if (dir->wadfile->error ())
213   {
214     /*warn ("%s: can't seek to %lXh\n",
215 	dir->wadfile->filename, (unsigned long) ftell (dir->wadfile->fp));
216     warn ("PLAYPAL: seek error\n");*/
217     rc = 1;
218     errno = ECHILD;
219     goto byebye;
220   }
221   dir->wadfile->read_bytes (pal, 768);
222   if (dir->wadfile->error ())
223   {
224     /*warn ("%s: read error", dir->wadfile->where ());
225     warn ("PLAYPAL: read error\n");*/
226     rc = 1;
227     errno = ECHILD;
228     goto byebye;
229   }
230 
231   // Create PPM file
232   fp = fopen (filename, "wb");
233   if (fp == NULL)
234   {
235     rc = 1;
236     goto byebye;
237   }
238   fputs ("P6\n", fp);
239   fprintf (fp, "# %s\n", what ());
240   fprintf (fp, "%d %d 255\n", p->width, p->height);
241   {
242     const img_pixel_t *pix    = p->buf;
243     const img_pixel_t *pixmax = pix + (unsigned long) p->width * p->height;
244     for (; pix < pixmax; pix++)
245     {
246       if (*pix == IMG_TRANSP && ! p->opaque)
247       {
248 	putc ( 0, fp);	// DeuTex convention, rgb:0/2f/2f
249 	putc (47, fp);
250 	putc (47, fp);
251       }
252       else
253       {
254 	putc (pal[3 * *pix    ], fp);
255 	putc (pal[3 * *pix + 1], fp);
256 	putc (pal[3 * *pix + 2], fp);
257       }
258     }
259   }
260   if (ferror (fp))
261     rc = 1;
262 
263 byebye:
264   if (fp != 0)
265     if (fclose (fp))
266       rc = 1;
267   delete[] pal;
268   return rc;
269 }
270 
271 
272