ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/image.C
Revision: 1.10
Committed: Sat Jan 6 14:42:28 2007 UTC (17 years, 4 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.9: +1 -0 lines
Log Message:
added some copyrights

File Contents

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