1 /*
2  *	palview.cc
3  *	Palette (PLAYPAL & COLORMAP) viewer
4  *	AYM 1999-11-11
5  */
6 
7 
8 /*
9 This file is part of Yadex.
10 
11 Yadex incorporates code from DEU 5.21 that was put in the public domain in
12 1994 by Rapha�l Quinet and Brendon Wyber.
13 
14 The rest of Yadex is Copyright � 1997-2003 Andr� Majorel and others.
15 
16 This program is free software; you can redistribute it and/or modify it under
17 the terms of the GNU General Public License as published by the Free Software
18 Foundation; either version 2 of the License, or (at your option) any later
19 version.
20 
21 This program is distributed in the hope that it will be useful, but WITHOUT
22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
23 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
24 
25 You should have received a copy of the GNU General Public License along with
26 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
27 Place, Suite 330, Boston, MA 02111-1307, USA.
28 */
29 
30 
31 #include "yadex.h"
32 #include <X11/Xlib.h>
33 #include "colour.h"
34 #include "gcolour2.h"
35 #include "gfx.h"
36 #include "palview.h"
37 #include "rgb.h"
38 #include "wadfile.h"
39 #include "wads.h"
40 #include "ytime.h"
41 
42 
43 /*
44  *	Palette viewer::run
45  *	The only public method of the palette viewer.
46  */
47 
48 // One COLORMAP entry. Wrapped in struct to avoid array<->pointer problems
49 typedef struct { u8 c[DOOM_COLOURS]; } colormap_entry_t;
50 
run()51 void Palette_viewer::run ()
52 {
53 int       lines    = (ncolours + columns - 1) / columns;
54 const int pwidth   = columns * (pixels + 1);
55 const int pheight  = lines * (pixels + 1);
56 int       width    = 2 * BOX_BORDER + 2 * WIDE_HSPACING + pwidth;
57 int       height   = 2 * BOX_BORDER + 3 * WIDE_VSPACING + pheight + 7 * FONTH;
58 int       x0       = (ScrMaxX - width) / 2;
59 int       y0       = (ScrMaxY - height) / 2;
60 int       nmaps    = 0;  // Number of entries in the COLORMAP lump
61 colormap_entry_t **colormap = 0;
62 rgb_c    *playpal  = 0;
63 
64 // Load the PLAYPAL lump
65 do
66 {
67   playpal = new rgb_c[DOOM_COLOURS];
68   for (size_t n = 0; n < DOOM_COLOURS; n++)
69     playpal[n].set (0, 0, 0);
70   const char *lump_name = "PLAYPAL";
71   MDirPtr dir = FindMasterDir (MasterDir, lump_name);
72   if (dir == NULL)
73   {
74     warn ("%s: lump not found\n", lump_name);
75     break;
76   }
77   const Wad_file *wf = dir->wadfile;
78   if (dir->dir.size % (3 * DOOM_COLOURS) != 0)
79   {
80     warn ("%s has weird size (%ld, not mult of %d), ignoring tail\n",
81       lump_name, (long) dir->dir.size, (int) (DOOM_COLOURS * 3));
82   }
83   wf->seek (dir->dir.start);
84   if (wf->error ())
85   {
86     warn ("%s: seek error\n", lump_name);
87     break;
88   }
89   playpal = new rgb_c[DOOM_COLOURS];
90   for (size_t n = 0; n < DOOM_COLOURS; n++)
91   {
92     char buf[3];
93     wf->read_bytes (buf, sizeof buf);
94     playpal[n].set (buf[0], buf[1], buf[2]);
95   }
96   if (wf->error ())
97     warn ("%s: read error\n", lump_name);
98 }
99 while (0);
100 
101 // Load the COLORMAP lump
102 do
103 {
104   const char *lump_name = "COLORMAP";
105   MDirPtr dir = FindMasterDir (MasterDir, lump_name);
106   if (dir == NULL)
107   {
108     warn ("%s: lump not found\n", lump_name);
109     break;
110   }
111   const Wad_file *wf = dir->wadfile;
112   nmaps = dir->dir.size / DOOM_COLOURS;
113   if ((long) DOOM_COLOURS * nmaps != dir->dir.size)
114   {
115     warn ("%s: has weird size (%ld, not mult of %d), ignoring tail\n",
116       lump_name, (long) dir->dir.size, (int) DOOM_COLOURS);
117   }
118   if (nmaps > 200)
119   {
120     warn ("%s has too many (%d) entries, keeping only 200 first\n",
121 	lump_name, nmaps);
122     nmaps = 200;
123   }
124   wf->seek (dir->dir.start);
125   if (wf->error ())
126   {
127     warn ("%s: seek error\n", lump_name);
128     break;
129   }
130   colormap = new colormap_entry_t *[nmaps];
131   for (int n = 0; n < nmaps; n++)
132   {
133     colormap[n] = new colormap_entry_t;
134     wf->read_bytes (colormap[n]->c, sizeof colormap[n]->c);
135   }
136   if (wf->error ())
137     warn ("%s: read error\n", lump_name);
138 }
139 while (0);
140 
141 // On to the real business
142 ix0 = x0 + BOX_BORDER + WIDE_HSPACING;
143 iy0 = y0 + BOX_BORDER + WIDE_VSPACING;
144 int tx0 = ix0;					// Top left corner of text
145 int ty0 = y0 + BOX_BORDER + 2 * WIDE_VSPACING + pheight;
146 push_colour (0);				// Save current colour
147 #define DECIDX(i,n) do { i = (i - n + ncolours) % ncolours; } while (0)
148 #define INCIDX(i,n) do { i = (i + n           ) % ncolours; } while (0)
149 int           mapno         = 0;
150 bool          mapping       = true;
151 int           is_drawn      = 0;
152 const int     YID_WINDOW    = 0x01;
153 const int     YID_CURSOR    = 0x02;
154 const int     YID_PALETTE   = 0x04;
155 const int     YID_TEXT      = 0x08;
156 int           cursor_phase  = 0;
157 int           display_phase = 0;
158 unsigned long cursor_time   = 0;
159 i   = 0;
160 ofs = 0;
161 
162 for (;;)
163 {
164   int mi = colormap[mapno]->c[i];	// Mapped index
165   int ei = mapping ? mi : i;		// Effective index
166   int mapped_to = 0;			// N. distinct colours that map to i
167   for (int n = 0; n < ncolours; n++)
168     for (int m = 0; m < nmaps; m++)
169       if (colormap[m]->c[n] == i)
170       {
171 	mapped_to++;
172 	break;        // Don't count the same mapper twice
173       }
174   int maps_to = 0;			// N. distinct colours that i maps to
175   {
176     bitvec_c mappee (ncolours);
177     for (int m = 0; m < nmaps; m++)
178       mappee.set (colormap[m]->c[i]);
179     for (int n = 0; n < ncolours; n++)
180       if (mappee.get (n))
181 	maps_to++;
182   }
183 
184   // Draw the window
185   if (! (is_drawn & YID_WINDOW))
186   {
187     DrawScreenBox3D (x0, y0, x0 + width - 1, y0 + height - 1);
188     is_drawn = YID_WINDOW;  // Redraw everything else
189   }
190 
191   // Draw the cursor (frame around the current cell)
192   {
193     const int cycle = 800;  // 800 ms
194     unsigned long current_time = y_milliseconds ();
195     unsigned long elapsed_time = current_time - cursor_time;
196     cursor_time = current_time;
197 #if 0
198     cursor_time += elapsed_time - elapsed_time % cycle;  // Normalize
199     elapsed_time = current_time - cursor_time;
200 #endif
201     cursor_phase = (cursor_phase + elapsed_time) % cycle;
202     if ((cursor_phase >= cycle / 2) != (display_phase >= cycle / 2))
203       is_drawn &= ~YID_CURSOR;
204     if (! (is_drawn & YID_CURSOR))
205     {
206       draw_cursor (WINFG, cursor_phase >= cycle / 2);
207       display_phase = cursor_phase;
208       is_drawn |= YID_CURSOR;
209     }
210   }
211 
212   // Draw a (pixels x pixels) square for each colour
213   if (! (is_drawn & YID_PALETTE))
214   {
215     int x = 0;  // Initialized only to prevent GCC from warning
216     int y = 0;  // Initialized only to prevent GCC from warning
217     for (int n = 0; n < ncolours; n++)
218     {
219       if (n % columns == 0)
220       {
221 	x = ix0;
222 	if (n == 0)
223 	  y = iy0;
224 	else
225 	  y += pixels + 1;
226       }
227       else
228 	x += pixels + 1;
229 
230       if (game_colour == 0)  // If PLAYPAL not found
231 	set_pcolour (0);
232       else
233       {
234 	if (mapping)
235 	  set_pcolour (game_colour[colormap[mapno]->c[(n + ofs) % ncolours]]);
236 	else
237 	  set_pcolour (game_colour[(n + ofs) % ncolours]);
238       }
239       DrawScreenBoxwh (x, y, pixels, pixels);
240     }
241     is_drawn |= YID_PALETTE;
242     set_colour (WINFG_DIM);  // Just to force the next set_colour() to do sth
243   }
244 
245   // Draw the "caption"
246   if (! (is_drawn & YID_TEXT))
247   {
248     set_colour (WINBG);
249     DrawScreenBoxwh (tx0, ty0, pwidth, 7 * FONTH);
250     set_colour (WINFG);
251     DrawScreenText (tx0, ty0, "Index        %3d", i);
252     push_colour (mapping ? WINFG : WINFG_DIM);
253     DrawScreenText (tx0, -1,  "Mapped index %3d", mi);
254     pop_colour ();
255     DrawScreenText (tx0, -1,  "R            %3d", playpal[ei].r);
256     DrawScreenText (tx0, -1,  "G            %3d", playpal[ei].g);
257     DrawScreenText (tx0, -1,  "B            %3d", playpal[ei].b);
258     DrawScreenText (tx0, -1,  "Mapped to by %3d", mapped_to);
259     DrawScreenText (tx0, -1,  "Maps to      %3d", maps_to);
260     push_colour (mapping ? WINFG : WINFG_DIM);
261     DrawScreenText (tx0 + 18 * FONTW, ty0, "Colormap %3d", mapno);
262     pop_colour ();
263     is_drawn |= YID_TEXT;
264   }
265 
266   // Process any events
267   get_input_status ();
268   if (is.key == YK_PU)			// [Pgup] previous colormap
269   {
270     mapno--;
271     if (mapno < 0)
272       mapno = nmaps - 1;
273     is_drawn &= ~(YID_PALETTE | YID_TEXT);
274   }
275   else if (is.key == YK_PD)		// [Pgdn] next colormap
276   {
277     mapno++;
278     if (mapno >= nmaps)
279       mapno = 0;
280     is_drawn &= ~(YID_PALETTE | YID_TEXT);
281   }
282   else if (is.key == YK_LEFT)		// [Left] previous palette entry
283   {
284     draw_cursor (WINBG, false);
285     DECIDX (i, 1);
286     is_drawn &= ~(YID_PALETTE | YID_TEXT | YID_CURSOR);
287     cursor_phase = 0;
288   }
289   else if (is.key == YK_RIGHT)		// [Right] next palette entry
290   {
291     draw_cursor (WINBG, false);
292     INCIDX (i, 1);
293     is_drawn &= ~(YID_TEXT | YID_CURSOR);
294     cursor_phase = 0;
295   }
296   else if (is.key == YK_UP)		// [Up] previous palette row
297   {
298     draw_cursor (WINBG, false);
299     DECIDX (i, columns);
300     is_drawn &= ~(YID_TEXT | YID_CURSOR);
301     cursor_phase = 0;
302   }
303   else if (is.key == YK_DOWN)		// [Down] next palette row
304   {
305     draw_cursor (WINBG, false);
306     INCIDX (i, columns);
307     is_drawn &= ~(YID_TEXT | YID_CURSOR);
308     cursor_phase = 0;
309   }
310   else if (is.key == YK_END		// [End], [$]: end of current line
311       || is.key == '$')
312   {
313     draw_cursor (WINBG, false);
314     i += columns - i % columns - 1;
315     is_drawn &= ~(YID_TEXT | YID_CURSOR);
316     cursor_phase = 0;
317   }
318   else if (is.key == YK_HOME		// [Home], [0], [^]: start of cur. line
319       || is.key == '^'
320       || is.key == '0')
321   {
322     draw_cursor (WINBG, false);
323     i -= i % columns;
324     is_drawn &= ~(YID_TEXT | YID_CURSOR);
325     cursor_phase = 0;
326   }
327   else if (is.key == YK_RETURN)		// [Return]: beginning of next line
328   {
329     draw_cursor (WINBG, false);
330     i += columns - i % columns;
331     is_drawn &= ~(YID_TEXT | YID_CURSOR);
332     cursor_phase = 0;
333   }
334 #if 0  /* Conflicts with "rotate" */
335   else if (is.key == '-')		// [-]: beginning of previous line
336   {
337     draw_cursor (WINBG, false);
338     i -= columns + i % columns;
339     is_drawn &= ~(YID_TEXT | YID_CURSOR);
340     cursor_phase = 0;
341   }
342 #endif
343   else if (is.key == 'G' 		// [G], [L]: beginning of last line
344       || is.key == 'L')
345   {
346     draw_cursor (WINBG, false);
347     i = (lines  - 1) * columns;
348     is_drawn &= ~(YID_TEXT | YID_CURSOR);
349     cursor_phase = 0;
350   }
351   else if (is.key == 'H')		// [H] beginning of first line
352   {
353     draw_cursor (WINBG, false);
354     i = 0;
355     is_drawn &= ~(YID_TEXT | YID_CURSOR);
356     cursor_phase = 0;
357   }
358   else if (is.key == 'm')		// [m] toggle mapping
359   {
360     mapping = ! mapping;
361     is_drawn &= ~(YID_PALETTE | YID_TEXT);
362   }
363   else if (is.key == 'M')		// [M] beginning of middle line
364   {
365     draw_cursor (WINBG, false);
366     i = (lines / 2) * columns;
367     is_drawn &= ~(YID_TEXT | YID_CURSOR);
368     cursor_phase = 0;
369   }
370   else if (is.key == '+' || is.key == '=')  // [+] increment offset
371   {
372     INCIDX (ofs, 1);
373     INCIDX (i, 1);
374     is_drawn &= ~(YID_PALETTE | YID_TEXT);
375   }
376   else if (is.key == '-')		// [-] decrement offset
377   {
378     DECIDX (ofs, 1);
379     DECIDX (i, 1);
380     is_drawn &= ~(YID_PALETTE | YID_TEXT);
381   }
382   else if (is.key == YK_ESC)		// [Esc] quit
383   {
384     break;
385   }
386   else if (is.key == YE_EXPOSE)
387   {
388     is_drawn = 0;  // Redraw everything
389   }
390   else
391     ;
392 }
393 
394 pop_colour ();				// Restore current colour
395 delete[] playpal;
396 for (int n = 0; n < nmaps; n++)
397     delete colormap[n];
398 delete[] colormap;
399 }
400 
401 
draw_cursor(int c,bool phase)402 void Palette_viewer::draw_cursor (int c, bool phase)
403 {
404   const int a = (i + ncolours - ofs) % ncolours;
405   const int side = pixels + 2;
406   const int x0 = ix0 - 1 + (side - 1) * (a % columns);
407   const int y0 = iy0 - 1 + (side - 1) * (a / columns);
408   const int x1 = x0 + side - 1;
409   const int y1 = y0 + side - 1;
410   if (c == WINBG)
411   {
412     set_colour (c);
413     DrawScreenRect (x0, y0, side, side);
414   }
415   else
416   {
417     const int l1 = side / 2;
418     const int l2 = side - l1;
419     // FIXME this cursor looks ugly
420     set_colour (phase ? BLACK : WHITE);
421     DrawScreenLineLen (x0, y0,  l1,   0);
422     DrawScreenLineLen (x0, y0,   0,  l1);
423     DrawScreenLineLen (x1, y1,   0, -l1);
424     DrawScreenLineLen (x1, y1, -l1,   0);
425     set_colour (phase ? WHITE : BLACK);
426     DrawScreenLineLen (x1, y0, -l2,   0);
427     DrawScreenLineLen (x1, y0,   0,  l2);
428     DrawScreenLineLen (x0, y1,   0, -l2);
429     DrawScreenLineLen (x0, y1,  l2,   0);
430   }
431 }
432 
433 
434