ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/image.C
Revision: 1.13
Committed: Fri Jan 19 17:50:10 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.12: +5 -5 lines
Log Message:
- rename Animations => animation
- rename New_Face => facetile
- add but do not implement some generic loader framework classes

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.13 * CrossFire, A Multiplayer game
3 pippijn 1.12 *
4     * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5     * 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     * The maintainer of this code can be reached at <crossfire@schmorp.de>
23     */
24 elmex 1.1
25    
26     #include <global.h>
27     #include <stdio.h>
28    
29 root 1.13 facetile *new_faces;
30 elmex 1.1
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 root 1.13 facetile *blank_face, *dark_faces[3], *empty_face, *smooth_face;
57 elmex 1.1
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.11
118 root 1.6 static int
119     compar_smooth (const struct smoothing *a, const struct smoothing *b)
120     {
121     if (a->id < b->id)
122     return -1;
123     if (b->id < a->id)
124     return 1;
125     return 0;
126 elmex 1.1 }
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 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 root 1.6 static void
149     ReadFaceData (void)
150 elmex 1.1 {
151 root 1.6 char buf[MAX_BUF], *cp;
152 root 1.13 facetile *on_face = NULL;
153 root 1.6 FILE *fp;
154    
155     sprintf (buf, "%s/faces", settings.datadir);
156 pippijn 1.9 LOG (llevDebug, "Reading faces from %s...\n", buf);
157 root 1.6 if ((fp = fopen (buf, "r")) == NULL)
158     {
159     LOG (llevError, "Cannot open faces file %s: %s\n", buf, strerror (errno));
160     exit (-1);
161 elmex 1.1 }
162 root 1.6 while (fgets (buf, MAX_BUF, fp) != NULL)
163     {
164     if (*buf == '#')
165     continue;
166     if (!strncmp (buf, "end", 3))
167     {
168     on_face = NULL;
169     }
170     else if (!strncmp (buf, "face", 4))
171     {
172     int tmp;
173    
174     cp = buf + 5;
175     cp[strlen (cp) - 1] = '\0'; /* remove newline */
176    
177     if ((tmp = FindFace (cp, -1)) == -1)
178     {
179     LOG (llevError, "Could not find face %s\n", cp);
180     continue;
181 root 1.4 }
182 root 1.6 on_face = &new_faces[tmp];
183     on_face->visibility = 0;
184 root 1.2 }
185 root 1.6 else if (on_face == NULL)
186     {
187     LOG (llevError, "Got line with no face set: %s\n", buf);
188     }
189     else if (!strncmp (buf, "color_fg", 8))
190     {
191     cp = buf + 9;
192     cp[strlen (cp) - 1] = '\0';
193     if (on_face->magicmap == 255)
194     on_face->magicmap = find_color (cp);
195     }
196     else if (!strncmp (buf, "color_bg", 8))
197     {
198     /* ignore it */
199     }
200     else if (!strncmp (buf, "visibility", 10))
201     {
202     on_face->visibility = atoi (buf + 11);
203     }
204     else if (!strncmp (buf, "magicmap", 8))
205     {
206     cp = buf + 9;
207     cp[strlen (cp) - 1] = '\0';
208     on_face->magicmap = find_color (cp);
209     }
210     else if (!strncmp (buf, "is_floor", 8))
211     {
212     int value = atoi (buf + 9);
213    
214     if (value)
215     on_face->magicmap |= FACE_FLOOR;
216 root 1.2 }
217 root 1.6 else
218     LOG (llevDebug, "Got unknown line in faces file: %s\n", buf);
219 elmex 1.1 }
220 root 1.11
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 root 1.6 void
231     ReadBmapNames (void)
232     {
233     char buf[MAX_BUF], *p, *q;
234     FILE *fp;
235     int value, nrofbmaps = 0, i;
236     size_t l;
237    
238     bmaps_checksum = 0;
239     sprintf (buf, "%s/bmaps", settings.datadir);
240 pippijn 1.9 LOG (llevDebug, "Reading bmaps from %s...\n", buf);
241 root 1.6 if ((fp = fopen (buf, "r")) == NULL)
242     {
243     LOG (llevError, "Cannot open bmaps file %s: %s\n", buf, strerror (errno));
244     exit (-1);
245 elmex 1.1 }
246 root 1.6
247     /* First count how many bitmaps we have, so we can allocate correctly */
248     while (fgets (buf, MAX_BUF, fp) != NULL)
249     if (buf[0] != '#' && buf[0] != '\n')
250     nrofbmaps++;
251     rewind (fp);
252    
253     xbm = new bmappair[nrofbmaps];
254     memset (xbm, 0, sizeof (struct bmappair) * nrofbmaps);
255    
256     while (nroffiles < nrofbmaps && fgets (buf, MAX_BUF, fp) != NULL)
257     {
258     if (*buf == '#')
259     continue;
260    
261     p = (*buf == '\\') ? (buf + 1) : buf;
262     if (!(p = strtok (p, " \t")) || !(q = strtok (NULL, " \t\n")))
263     {
264     LOG (llevDebug, "Warning, syntax error: %s\n", buf);
265     continue;
266     }
267     value = atoi (p);
268 root 1.8 xbm[nroffiles].name = strdup (q);
269 root 1.6
270     /* We need to calculate the checksum of the bmaps file
271     * name->number mapping to send to the client. This does not
272     * need to match what sum or other utility may come up with -
273     * as long as we get the same results on the same real file
274     * data, it does the job as it lets the client know if
275     * the file has the same data or not.
276     */
277     ROTATE_RIGHT (bmaps_checksum);
278     bmaps_checksum += value & 0xff;
279     bmaps_checksum &= 0xffffffff;
280    
281     ROTATE_RIGHT (bmaps_checksum);
282     bmaps_checksum += (value >> 8) & 0xff;
283     bmaps_checksum &= 0xffffffff;
284     for (l = 0; l < strlen (q); l++)
285     {
286     ROTATE_RIGHT (bmaps_checksum);
287     bmaps_checksum += q[l];
288     bmaps_checksum &= 0xffffffff;
289     }
290    
291     xbm[nroffiles].number = value;
292     nroffiles++;
293     if (value >= nrofpixmaps)
294     nrofpixmaps = value + 1;
295 elmex 1.1 }
296 root 1.6 fclose (fp);
297 elmex 1.1
298 root 1.6 LOG (llevDebug, "done (got %d/%d/%d)\n", nrofpixmaps, nrofbmaps, nroffiles);
299 elmex 1.1
300 root 1.13 new_faces = new facetile[nrofpixmaps];
301 root 1.6
302     for (i = 0; i < nrofpixmaps; i++)
303     {
304     new_faces[i].name = "";
305     new_faces[i].number = i;
306     new_faces[i].visibility = 0;
307     new_faces[i].magicmap = 255;
308 elmex 1.1 }
309 root 1.6 for (i = 0; i < nroffiles; i++)
310     {
311     new_faces[xbm[i].number].name = xbm[i].name;
312 elmex 1.1 }
313    
314 root 1.6 // non-pod datatype, likely not allowed
315     qsort (xbm, nroffiles, sizeof (struct bmappair), (int (*)(const void *, const void *)) compar);
316 elmex 1.1
317 root 1.6 ReadFaceData ();
318 elmex 1.1
319 root 1.6 for (i = 0; i < nrofpixmaps; i++)
320     {
321     if (new_faces[i].magicmap == 255)
322     {
323     #if 0 /* Useful for initial debugging, not needed now */
324     LOG (llevDebug, "Face %s still had default magicmap, resetting to black\n", new_faces[i].name);
325 elmex 1.1 #endif
326 root 1.6 new_faces[i].magicmap = 0;
327 root 1.2 }
328 elmex 1.1 }
329 root 1.6 /* Actually forcefully setting the colors here probably should not
330     * be done - it could easily create confusion.
331     */
332     blank_face = &new_faces[FindFace (BLANK_FACE_NAME, 0)];
333     blank_face->magicmap = find_color ("khaki") | FACE_FLOOR;
334    
335     empty_face = &new_faces[FindFace (EMPTY_FACE_NAME, 0)];
336    
337     dark_faces[0] = &new_faces[FindFace (DARK_FACE1_NAME, 0)];
338     dark_faces[1] = &new_faces[FindFace (DARK_FACE2_NAME, 0)];
339     dark_faces[2] = &new_faces[FindFace (DARK_FACE3_NAME, 0)];
340 elmex 1.1
341 root 1.6 smooth_face = &new_faces[FindFace (SMOOTH_FACE_NAME, 0)];
342 elmex 1.1 }
343    
344     /* This returns an the face number of face 'name'. Number is constant
345     * during an invocation, but not necessarily between versions (this
346     * is because the faces are arranged in alphabetical order, so
347     * if a face is removed or added, all faces after that will now
348     * have a different number.
349     *
350     * the parameter error determines behaviour. If a face is
351     * not found, then error is returned. This can be useful if
352     * you want some default face used, or can be set to negative
353     * so that it will be known that the face could not be found
354     * (needed in client, so that it will know to request that image
355     * from the server)
356     */
357 root 1.6 int
358     FindFace (const char *name, int error)
359     {
360     struct bmappair *bp, tmp;
361     char *p;
362 elmex 1.1
363 root 1.6 if (!name)
364     return error;
365 root 1.5
366 root 1.6 if ((p = strchr (name, '\n')))
367     *p = '\0';
368 elmex 1.1
369 root 1.6 tmp.name = (char *) name;
370     bp = (struct bmappair *) bsearch (&tmp, xbm, nroffiles, sizeof (struct bmappair), (int (*)(const void *, const void *)) compar);
371 elmex 1.1
372 root 1.6 return bp ? bp->number : error;
373 elmex 1.1 }
374    
375     /* Reads the smooth file to know how to smooth datas.
376     * the smooth file if made of 2 elements lines.
377     * lines starting with # are comment
378     * the first element of line is face to smooth
379     * the next element is the 16x2 faces picture
380     * used for smoothing
381     */
382 root 1.6 int
383     ReadSmooth (void)
384     {
385     char buf[MAX_BUF], *p, *q;
386     FILE *fp;
387     int smoothcount = 0;
388    
389     bmaps_checksum = 0;
390     sprintf (buf, "%s/smooth", settings.datadir);
391 pippijn 1.9 LOG (llevDebug, "Reading smooth from %s...\n", buf);
392 root 1.6 if ((fp = fopen (buf, "r")) == NULL)
393     {
394     LOG (llevError, "Cannot open smooth file %s: %s\n", strerror (errno));
395     exit (-1);
396 elmex 1.1 }
397    
398 root 1.6 /* First count how many smooth we have, so we can allocate correctly */
399     while (fgets (buf, MAX_BUF, fp) != NULL)
400     if (buf[0] != '#' && buf[0] != '\n')
401     smoothcount++;
402     rewind (fp);
403    
404     smooth = new smoothing[smoothcount];
405    
406     while (nrofsmooth < smoothcount && fgets (buf, MAX_BUF, fp) != NULL)
407     {
408     if (*buf == '#')
409     continue;
410     p = strchr (buf, ' ');
411     if (!p)
412     continue;
413     *p = '\0';
414     q = buf;
415     smooth[nrofsmooth].id = FindFace (q, 0);
416     q = p + 1;
417     smooth[nrofsmooth].smooth = FindFace (q, 0);
418     nrofsmooth++;
419 elmex 1.1 }
420 root 1.6 fclose (fp);
421 elmex 1.1
422 root 1.6 LOG (llevDebug, "done (got %d smooth entries)\n", nrofsmooth);
423     qsort (smooth, nrofsmooth, sizeof (struct smoothing), (int (*)(const void *, const void *)) compar_smooth);
424     return nrofsmooth;
425 elmex 1.1 }
426    
427     /**
428     * Find the smooth face for a given face.
429     *
430     * @param face the face to find the smoothing face for
431     *
432     * @param smoothed return value: set to smooth face
433     *
434     * @return 1=smooth face found, 0=no smooth face found
435     */
436 root 1.6 int
437     FindSmooth (uint16 face, uint16 * smoothed)
438     {
439     struct smoothing *bp, tmp;
440 elmex 1.1
441 root 1.6 tmp.id = face;
442     bp = (struct smoothing *) bsearch
443     (&tmp, smooth, nrofsmooth, sizeof (struct smoothing), (int (*)(const void *, const void *)) compar_smooth);
444     (*smoothed) = 0;
445     if (bp)
446     (*smoothed) = bp->smooth;
447     return bp ? 1 : 0;
448 elmex 1.1 }
449    
450     /**
451     * Deallocates memory allocated by ReadBmapNames() and ReadSmooth().
452     */
453 root 1.6 void
454     free_all_images (void)
455 elmex 1.1 {
456 root 1.6 int i;
457 elmex 1.1
458 root 1.6 for (i = 0; i < nroffiles; i++)
459     free (xbm[i].name);
460 root 1.4
461 root 1.6 delete[]xbm;
462     delete[]new_faces;
463     delete[]smooth;
464 elmex 1.1 }