ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/image.C
(Generate patch)

Comparing deliantra/server/common/image.C (file contents):
Revision 1.8 by root, Thu Dec 14 22:45:40 2006 UTC vs.
Revision 1.23 by root, Thu Apr 12 14:18:04 2007 UTC

1/* 1/*
2 CrossFire, A Multiplayer game for X-windows 2 * CrossFire, A Multiplayer game
3 3 *
4 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
4 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 5 * Copyright (C) 2002 Mark Wedel & Crossfire Development Team
5 Copyright (C) 1992 Frank Tore Johansen 6 * Copyright (C) 1992 Frank Tore Johansen
6 7 *
7 This program is free software; you can redistribute it and/or modify 8 * 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 * 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 * the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version. 11 * (at your option) any later version.
11 12 *
12 This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details. 16 * GNU General Public License for more details.
16 17 *
17 You should have received a copy of the GNU General Public License 18 * 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 * along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 21 *
21 The maintainer of this code can be reached at <crossfire@schmorp.de> 22 * The maintainer of this code can be reached at <crossfire@schmorp.de>
22*/ 23 */
23
24 24
25#include <global.h> 25#include <global.h>
26#include <stdio.h> 26#include <stdio.h>
27 27
28New_Face *new_faces; 28#include "face.h"
29#include "crc.h"
29 30
30/* bmappair and xbm are used when looking for the image id numbers 31faceidx blank_face, empty_face;
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 32
42struct bmappair 33facehash_t facehash;
43{ 34std::vector<faceinfo> faces;
44 char *name;
45 unsigned int number;
46};
47
48void free (bmappair *); // guard to catch free when delete should be used
49
50static struct bmappair *xbm = NULL;
51
52/* Following can just as easily be pointers, but
53 * it is easier to keep them like this.
54 */
55New_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 */
68static int nroffiles = 0;
69int nrofpixmaps = 0;
70
71/**
72 * id is the face to smooth, smooth is the 16x2 face used to smooth id.
73 */
74struct smoothing:zero_initialised
75{
76 uint16 id;
77 uint16 smooth;
78};
79
80void free (smoothing *); // guard to catch free when delete should be used
81
82/**
83 * Contains all defined smoothing entries. smooth is an array of nrofsmooth
84 * entries. It is sorted by smooth[].id.
85 */
86static struct smoothing *smooth = NULL;
87int nrofsmooth = 0;
88 35
89/* the only thing this table is used for now is to 36/* the only thing this table is used for now is to
90 * translate the colorname in the magicmap field of the 37 * translate the colorname in the magicmap field of the
91 * face into a numeric index that is then sent to the 38 * face into a numeric index that is then sent to the
92 * client for magic map commands. The order of this table 39 * client for magic map commands. The order of this table
106 "brown", /* 10 */ 53 "brown", /* 10 */
107 "yellow", /* 11 */ 54 "yellow", /* 11 */
108 "khaki" /* 12 */ 55 "khaki" /* 12 */
109}; 56};
110 57
111static int
112compar (const struct bmappair *a, const struct bmappair *b)
113{
114 return strcmp (a->name, b->name);
115}
116static int
117compar_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}
125
126
127/* 58/*
128 * Returns the matching color in the coloralias if found, 59 * Returns the matching color in the coloralias if found,
129 * 0 otherwise. Note that 0 will actually be black, so there is no 60 * 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 61 * way the calling function can tell if an error occurred or not
131 */ 62 */
132
133static uint8 63static uint8
134find_color (const char *name) 64find_color (const char *name)
135{ 65{
136 uint8 i; 66 uint8 i;
137 67
138 for (i = 0; i < sizeof (colorname) / sizeof (*colorname); i++) 68 for (i = 0; i < sizeof (colorname) / sizeof (*colorname); i++)
139 if (!strcmp (name, colorname[i])) 69 if (!strcmp (name, colorname[i]))
140 return i; 70 return i;
71
141 LOG (llevError, "Unknown color: %s\n", name); 72 LOG (llevError, "Unknown color: %s\n", name);
142 return 0; 73 return 0;
143} 74}
144 75
145/* This reads the lib/faces file, getting color and visibility information. 76faceidx
146 * it is called by ReadBmapNames. 77face_find (const char *name, faceidx defidx)
147 */ 78{
79 if (!name)
80 return defidx;
148 81
149static void 82 facehash_t::iterator i = facehash.find (name);
150ReadFaceData (void)
151{
152 char buf[MAX_BUF], *cp;
153 New_Face *on_face = NULL;
154 FILE *fp;
155 83
156 sprintf (buf, "%s/faces", settings.datadir); 84 return i == facehash.end ()
157 LOG (llevDebug, "Reading faces from %s...", buf); 85 ? defidx : i->second;
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 }
163 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 }
183 on_face = &new_faces[tmp];
184 on_face->visibility = 0;
185 }
186 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 }
218 else
219 LOG (llevDebug, "Got unknown line in faces file: %s\n", buf);
220 }
221 LOG (llevDebug, "done\n");
222 fclose (fp);
223} 86}
224 87
225/* This reads the bmaps file to get all the bitmap names and 88faceinfo *
226 * stuff. It only needs to be done once, because it is player 89face_info (faceidx idx)
227 * independent (ie, what display the person is on will not make a 90{
228 * difference.) 91 assert (0 < (faceidx)-1); // faceidx must be unsigned
229 */
230 92
231void 93 if (idx >= faces.size ())
232ReadBmapNames (void) 94 return 0;
233{
234 char buf[MAX_BUF], *p, *q;
235 FILE *fp;
236 int value, nrofbmaps = 0, i;
237 size_t l;
238 95
239 bmaps_checksum = 0; 96 return &faces [idx];
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 }
247
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 (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 }
297 fclose (fp);
298
299 LOG (llevDebug, "done (got %d/%d/%d)\n", nrofpixmaps, nrofbmaps, nroffiles);
300
301 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 }
310 for (i = 0; i < nroffiles; i++)
311 {
312 new_faces[xbm[i].number].name = xbm[i].name;
313 }
314
315 // non-pod datatype, likely not allowed
316 qsort (xbm, nroffiles, sizeof (struct bmappair), (int (*)(const void *, const void *)) compar);
317
318 ReadFaceData ();
319
320 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#endif
327 new_faces[i].magicmap = 0;
328 }
329 }
330 /* 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
342 smooth_face = &new_faces[FindFace (SMOOTH_FACE_NAME, 0)];
343} 97}
344 98
345/* This returns an the face number of face 'name'. Number is constant 99facedata *
346 * during an invocation, but not necessarily between versions (this 100face_data (faceidx idx, int faceset)
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 */
358int
359FindFace (const char *name, int error)
360{ 101{
361 struct bmappair *bp, tmp; 102 if (faceinfo *f = face_info (idx))
362 char *p; 103 return &(faceset ? f->data32 : f->data64);
363 104
364 if (!name) 105 return 0;
365 return error;
366
367 if ((p = strchr (name, '\n')))
368 *p = '\0';
369
370 tmp.name = (char *) name;
371 bp = (struct bmappair *) bsearch (&tmp, xbm, nroffiles, sizeof (struct bmappair), (int (*)(const void *, const void *)) compar);
372
373 return bp ? bp->number : error;
374} 106}
375 107
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 */
383int
384ReadSmooth (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 }
398
399 /* 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 }
421 fclose (fp);
422
423 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}
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 */
437int
438FindSmooth (uint16 face, uint16 * smoothed)
439{
440 struct smoothing *bp, tmp;
441
442 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}
450
451/**
452 * Deallocates memory allocated by ReadBmapNames() and ReadSmooth().
453 */
454void
455free_all_images (void)
456{
457 int i;
458
459 for (i = 0; i < nroffiles; i++)
460 free (xbm[i].name);
461
462 delete[]xbm;
463 delete[]new_faces;
464 delete[]smooth;
465}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines