ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/image.C
Revision: 1.14
Committed: Fri Feb 2 22:49:11 2007 UTC (17 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.13: +1 -9 lines
Log Message:
fix rune writing no longer possible due to fixed update caching

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