ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/image.C
Revision: 1.6
Committed: Sun Sep 10 16:00:23 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.5: +279 -236 lines
Log Message:
indent

File Contents

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