ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/image.C
Revision: 1.7
Committed: Thu Sep 14 22:33:58 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.6: +1 -7 lines
Log Message:
indent

File Contents

# User Rev Content
1 elmex 1.1 /*
2     CrossFire, A Multiplayer game for X-windows
3    
4     Copyright (C) 2002 Mark Wedel & Crossfire Development Team
5     Copyright (C) 1992 Frank Tore Johansen
6    
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11    
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21 root 1.7 The maintainer of this code can be reached at <crossfire@schmorp.de>
22 elmex 1.1 */
23    
24    
25     #include <global.h>
26     #include <stdio.h>
27    
28     New_Face *new_faces;
29    
30     /* bmappair and xbm are used when looking for the image id numbers
31     * of a face by name. xbm is sorted alphabetically so that bsearch
32     * can be used to quickly find the entry for a name. the number is
33     * then an index into the new_faces array.
34     * This data is redundant with new_face information - the difference
35     * is that this data gets sorted, and that doesn't necessarily happen
36     * with the new_face data - when accessing new_face[some number],
37     * that some number corresponds to the face at that number - for
38     * xbm, it may not. At current time, these do in fact match because
39     * the bmaps file is created in a sorted order.
40     */
41    
42 root 1.4 struct bmappair
43     {
44     char *name;
45     unsigned int number;
46 elmex 1.1 };
47    
48 root 1.6 void free (bmappair *); // guard to catch free when delete should be used
49 root 1.4
50 root 1.6 static struct bmappair *xbm = NULL;
51 elmex 1.1
52     /* Following can just as easily be pointers, but
53     * it is easier to keep them like this.
54     */
55     New_Face *blank_face, *dark_faces[3], *empty_face, *smooth_face;
56    
57    
58     /* nroffiles is the actual number of bitmaps defined.
59     * nrofpixmaps is the number of bitmaps loaded. With
60     * the automatic generation of the bmaps file, this is now equal
61     * to nroffiles.
62     *
63     * The xbm array (which contains name and number information, and
64     * is then sorted) contains nroffiles entries. the xbm_names
65     * array (which is used for converting the numeric face to
66     * a name) contains nrofpixmaps entries.
67     */
68     static int nroffiles = 0;
69     int nrofpixmaps = 0;
70    
71     /**
72     * id is the face to smooth, smooth is the 16x2 face used to smooth id.
73     */
74 root 1.6 struct smoothing:zero_initialised
75 root 1.4 {
76 root 1.6 uint16 id;
77     uint16 smooth;
78 elmex 1.1 };
79    
80 root 1.6 void free (smoothing *); // guard to catch free when delete should be used
81 root 1.4
82 elmex 1.1 /**
83     * Contains all defined smoothing entries. smooth is an array of nrofsmooth
84     * entries. It is sorted by smooth[].id.
85     */
86 root 1.6 static struct smoothing *smooth = NULL;
87     int nrofsmooth = 0;
88 elmex 1.1
89     /* the only thing this table is used for now is to
90     * translate the colorname in the magicmap field of the
91     * face into a numeric index that is then sent to the
92     * client for magic map commands. The order of this table
93     * must match that of the NDI colors in include/newclient.h.
94     */
95     static const char *const colorname[] = {
96 root 1.6 "black", /* 0 */
97     "white", /* 1 */
98     "blue", /* 2 */
99     "red", /* 3 */
100     "orange", /* 4 */
101     "light_blue", /* 5 */
102     "dark_orange", /* 6 */
103     "green", /* 7 */
104     "light_green", /* 8 */
105     "grey", /* 9 */
106     "brown", /* 10 */
107     "yellow", /* 11 */
108     "khaki" /* 12 */
109 elmex 1.1 };
110    
111 root 1.6 static int
112     compar (const struct bmappair *a, const struct bmappair *b)
113     {
114     return strcmp (a->name, b->name);
115 elmex 1.1 }
116 root 1.6 static int
117     compar_smooth (const struct smoothing *a, const struct smoothing *b)
118     {
119     if (a->id < b->id)
120     return -1;
121     if (b->id < a->id)
122     return 1;
123     return 0;
124 elmex 1.1 }
125    
126    
127     /*
128     * Returns the matching color in the coloralias if found,
129     * 0 otherwise. Note that 0 will actually be black, so there is no
130     * way the calling function can tell if an error occurred or not
131     */
132    
133 root 1.6 static uint8
134     find_color (const char *name)
135     {
136 elmex 1.1 uint8 i;
137 root 1.6
138     for (i = 0; i < sizeof (colorname) / sizeof (*colorname); i++)
139     if (!strcmp (name, colorname[i]))
140 elmex 1.1 return i;
141 root 1.6 LOG (llevError, "Unknown color: %s\n", name);
142 elmex 1.1 return 0;
143     }
144    
145     /* This reads the lib/faces file, getting color and visibility information.
146     * it is called by ReadBmapNames.
147     */
148    
149 root 1.6 static void
150     ReadFaceData (void)
151 elmex 1.1 {
152 root 1.6 char buf[MAX_BUF], *cp;
153     New_Face *on_face = NULL;
154     FILE *fp;
155    
156     sprintf (buf, "%s/faces", settings.datadir);
157     LOG (llevDebug, "Reading faces from %s...", buf);
158     if ((fp = fopen (buf, "r")) == NULL)
159     {
160     LOG (llevError, "Cannot open faces file %s: %s\n", buf, strerror (errno));
161     exit (-1);
162 elmex 1.1 }
163 root 1.6 while (fgets (buf, MAX_BUF, fp) != NULL)
164     {
165     if (*buf == '#')
166     continue;
167     if (!strncmp (buf, "end", 3))
168     {
169     on_face = NULL;
170     }
171     else if (!strncmp (buf, "face", 4))
172     {
173     int tmp;
174    
175     cp = buf + 5;
176     cp[strlen (cp) - 1] = '\0'; /* remove newline */
177    
178     if ((tmp = FindFace (cp, -1)) == -1)
179     {
180     LOG (llevError, "Could not find face %s\n", cp);
181     continue;
182 root 1.4 }
183 root 1.6 on_face = &new_faces[tmp];
184     on_face->visibility = 0;
185 root 1.2 }
186 root 1.6 else if (on_face == NULL)
187     {
188     LOG (llevError, "Got line with no face set: %s\n", buf);
189     }
190     else if (!strncmp (buf, "color_fg", 8))
191     {
192     cp = buf + 9;
193     cp[strlen (cp) - 1] = '\0';
194     if (on_face->magicmap == 255)
195     on_face->magicmap = find_color (cp);
196     }
197     else if (!strncmp (buf, "color_bg", 8))
198     {
199     /* ignore it */
200     }
201     else if (!strncmp (buf, "visibility", 10))
202     {
203     on_face->visibility = atoi (buf + 11);
204     }
205     else if (!strncmp (buf, "magicmap", 8))
206     {
207     cp = buf + 9;
208     cp[strlen (cp) - 1] = '\0';
209     on_face->magicmap = find_color (cp);
210     }
211     else if (!strncmp (buf, "is_floor", 8))
212     {
213     int value = atoi (buf + 9);
214    
215     if (value)
216     on_face->magicmap |= FACE_FLOOR;
217 root 1.2 }
218 root 1.6 else
219     LOG (llevDebug, "Got unknown line in faces file: %s\n", buf);
220 elmex 1.1 }
221 root 1.6 LOG (llevDebug, "done\n");
222     fclose (fp);
223 elmex 1.1 }
224    
225     /* This reads the bmaps file to get all the bitmap names and
226     * stuff. It only needs to be done once, because it is player
227     * independent (ie, what display the person is on will not make a
228     * difference.)
229     */
230    
231 root 1.6 void
232     ReadBmapNames (void)
233     {
234     char buf[MAX_BUF], *p, *q;
235     FILE *fp;
236     int value, nrofbmaps = 0, i;
237     size_t l;
238    
239     bmaps_checksum = 0;
240     sprintf (buf, "%s/bmaps", settings.datadir);
241     LOG (llevDebug, "Reading bmaps from %s...", buf);
242     if ((fp = fopen (buf, "r")) == NULL)
243     {
244     LOG (llevError, "Cannot open bmaps file %s: %s\n", buf, strerror (errno));
245     exit (-1);
246 elmex 1.1 }
247 root 1.6
248     /* First count how many bitmaps we have, so we can allocate correctly */
249     while (fgets (buf, MAX_BUF, fp) != NULL)
250     if (buf[0] != '#' && buf[0] != '\n')
251     nrofbmaps++;
252     rewind (fp);
253    
254     xbm = new bmappair[nrofbmaps];
255     memset (xbm, 0, sizeof (struct bmappair) * nrofbmaps);
256    
257     while (nroffiles < nrofbmaps && fgets (buf, MAX_BUF, fp) != NULL)
258     {
259     if (*buf == '#')
260     continue;
261    
262     p = (*buf == '\\') ? (buf + 1) : buf;
263     if (!(p = strtok (p, " \t")) || !(q = strtok (NULL, " \t\n")))
264     {
265     LOG (llevDebug, "Warning, syntax error: %s\n", buf);
266     continue;
267     }
268     value = atoi (p);
269     xbm[nroffiles].name = strdup_local (q);
270    
271     /* We need to calculate the checksum of the bmaps file
272     * name->number mapping to send to the client. This does not
273     * need to match what sum or other utility may come up with -
274     * as long as we get the same results on the same real file
275     * data, it does the job as it lets the client know if
276     * the file has the same data or not.
277     */
278     ROTATE_RIGHT (bmaps_checksum);
279     bmaps_checksum += value & 0xff;
280     bmaps_checksum &= 0xffffffff;
281    
282     ROTATE_RIGHT (bmaps_checksum);
283     bmaps_checksum += (value >> 8) & 0xff;
284     bmaps_checksum &= 0xffffffff;
285     for (l = 0; l < strlen (q); l++)
286     {
287     ROTATE_RIGHT (bmaps_checksum);
288     bmaps_checksum += q[l];
289     bmaps_checksum &= 0xffffffff;
290     }
291    
292     xbm[nroffiles].number = value;
293     nroffiles++;
294     if (value >= nrofpixmaps)
295     nrofpixmaps = value + 1;
296 elmex 1.1 }
297 root 1.6 fclose (fp);
298 elmex 1.1
299 root 1.6 LOG (llevDebug, "done (got %d/%d/%d)\n", nrofpixmaps, nrofbmaps, nroffiles);
300 elmex 1.1
301 root 1.6 new_faces = new New_Face[nrofpixmaps];
302    
303     for (i = 0; i < nrofpixmaps; i++)
304     {
305     new_faces[i].name = "";
306     new_faces[i].number = i;
307     new_faces[i].visibility = 0;
308     new_faces[i].magicmap = 255;
309 elmex 1.1 }
310 root 1.6 for (i = 0; i < nroffiles; i++)
311     {
312     new_faces[xbm[i].number].name = xbm[i].name;
313 elmex 1.1 }
314    
315 root 1.6 // non-pod datatype, likely not allowed
316     qsort (xbm, nroffiles, sizeof (struct bmappair), (int (*)(const void *, const void *)) compar);
317 elmex 1.1
318 root 1.6 ReadFaceData ();
319 elmex 1.1
320 root 1.6 for (i = 0; i < nrofpixmaps; i++)
321     {
322     if (new_faces[i].magicmap == 255)
323     {
324     #if 0 /* Useful for initial debugging, not needed now */
325     LOG (llevDebug, "Face %s still had default magicmap, resetting to black\n", new_faces[i].name);
326 elmex 1.1 #endif
327 root 1.6 new_faces[i].magicmap = 0;
328 root 1.2 }
329 elmex 1.1 }
330 root 1.6 /* Actually forcefully setting the colors here probably should not
331     * be done - it could easily create confusion.
332     */
333     blank_face = &new_faces[FindFace (BLANK_FACE_NAME, 0)];
334     blank_face->magicmap = find_color ("khaki") | FACE_FLOOR;
335    
336     empty_face = &new_faces[FindFace (EMPTY_FACE_NAME, 0)];
337    
338     dark_faces[0] = &new_faces[FindFace (DARK_FACE1_NAME, 0)];
339     dark_faces[1] = &new_faces[FindFace (DARK_FACE2_NAME, 0)];
340     dark_faces[2] = &new_faces[FindFace (DARK_FACE3_NAME, 0)];
341 elmex 1.1
342 root 1.6 smooth_face = &new_faces[FindFace (SMOOTH_FACE_NAME, 0)];
343 elmex 1.1 }
344    
345     /* This returns an the face number of face 'name'. Number is constant
346     * during an invocation, but not necessarily between versions (this
347     * is because the faces are arranged in alphabetical order, so
348     * if a face is removed or added, all faces after that will now
349     * have a different number.
350     *
351     * the parameter error determines behaviour. If a face is
352     * not found, then error is returned. This can be useful if
353     * you want some default face used, or can be set to negative
354     * so that it will be known that the face could not be found
355     * (needed in client, so that it will know to request that image
356     * from the server)
357     */
358 root 1.6 int
359     FindFace (const char *name, int error)
360     {
361     struct bmappair *bp, tmp;
362     char *p;
363 elmex 1.1
364 root 1.6 if (!name)
365     return error;
366 root 1.5
367 root 1.6 if ((p = strchr (name, '\n')))
368     *p = '\0';
369 elmex 1.1
370 root 1.6 tmp.name = (char *) name;
371     bp = (struct bmappair *) bsearch (&tmp, xbm, nroffiles, sizeof (struct bmappair), (int (*)(const void *, const void *)) compar);
372 elmex 1.1
373 root 1.6 return bp ? bp->number : error;
374 elmex 1.1 }
375    
376     /* Reads the smooth file to know how to smooth datas.
377     * the smooth file if made of 2 elements lines.
378     * lines starting with # are comment
379     * the first element of line is face to smooth
380     * the next element is the 16x2 faces picture
381     * used for smoothing
382     */
383 root 1.6 int
384     ReadSmooth (void)
385     {
386     char buf[MAX_BUF], *p, *q;
387     FILE *fp;
388     int smoothcount = 0;
389    
390     bmaps_checksum = 0;
391     sprintf (buf, "%s/smooth", settings.datadir);
392     LOG (llevDebug, "Reading smooth from %s...", buf);
393     if ((fp = fopen (buf, "r")) == NULL)
394     {
395     LOG (llevError, "Cannot open smooth file %s: %s\n", strerror (errno));
396     exit (-1);
397 elmex 1.1 }
398    
399 root 1.6 /* First count how many smooth we have, so we can allocate correctly */
400     while (fgets (buf, MAX_BUF, fp) != NULL)
401     if (buf[0] != '#' && buf[0] != '\n')
402     smoothcount++;
403     rewind (fp);
404    
405     smooth = new smoothing[smoothcount];
406    
407     while (nrofsmooth < smoothcount && fgets (buf, MAX_BUF, fp) != NULL)
408     {
409     if (*buf == '#')
410     continue;
411     p = strchr (buf, ' ');
412     if (!p)
413     continue;
414     *p = '\0';
415     q = buf;
416     smooth[nrofsmooth].id = FindFace (q, 0);
417     q = p + 1;
418     smooth[nrofsmooth].smooth = FindFace (q, 0);
419     nrofsmooth++;
420 elmex 1.1 }
421 root 1.6 fclose (fp);
422 elmex 1.1
423 root 1.6 LOG (llevDebug, "done (got %d smooth entries)\n", nrofsmooth);
424     qsort (smooth, nrofsmooth, sizeof (struct smoothing), (int (*)(const void *, const void *)) compar_smooth);
425     return nrofsmooth;
426 elmex 1.1 }
427    
428     /**
429     * Find the smooth face for a given face.
430     *
431     * @param face the face to find the smoothing face for
432     *
433     * @param smoothed return value: set to smooth face
434     *
435     * @return 1=smooth face found, 0=no smooth face found
436     */
437 root 1.6 int
438     FindSmooth (uint16 face, uint16 * smoothed)
439     {
440     struct smoothing *bp, tmp;
441 elmex 1.1
442 root 1.6 tmp.id = face;
443     bp = (struct smoothing *) bsearch
444     (&tmp, smooth, nrofsmooth, sizeof (struct smoothing), (int (*)(const void *, const void *)) compar_smooth);
445     (*smoothed) = 0;
446     if (bp)
447     (*smoothed) = bp->smooth;
448     return bp ? 1 : 0;
449 elmex 1.1 }
450    
451     /**
452     * Deallocates memory allocated by ReadBmapNames() and ReadSmooth().
453     */
454 root 1.6 void
455     free_all_images (void)
456 elmex 1.1 {
457 root 1.6 int i;
458 elmex 1.1
459 root 1.6 for (i = 0; i < nroffiles; i++)
460     free (xbm[i].name);
461 root 1.4
462 root 1.6 delete[]xbm;
463     delete[]new_faces;
464     delete[]smooth;
465 elmex 1.1 }