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.12 by pippijn, Mon Jan 15 21:06:18 2007 UTC vs.
Revision 1.24 by root, Mon May 28 21:21:40 2007 UTC

1/* 1/*
2 * CrossFire, A Multiplayer game for X-windows 2 * This file is part of Crossfire TRT, the Multiplayer Online Role Playing Game.
3 * 3 *
4 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team 4 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5 * Copyright (C) 2002 Mark Wedel & Crossfire Development Team 5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (C) 1992 Frank Tore Johansen 6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * Crossfire TRT is free software; you can redistribute it and/or modify it
9 * it under the terms of the GNU General Public License as published by 9 * under the terms of the GNU General Public License as published by the Free
10 * the Free Software Foundation; either version 2 of the License, or 10 * Software Foundation; either version 2 of the License, or (at your option)
11 * (at your option) any later version. 11 * any later version.
12 * 12 *
13 * 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, but
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * GNU General Public License for more details. 16 * for more details.
17 * 17 *
18 * 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 along
19 * along with this program; if not, write to the Free Software 19 * with Crossfire TRT; if not, write to the Free Software Foundation, Inc. 51
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * 21 *
22 * The maintainer of this code can be reached at <crossfire@schmorp.de> 22 * The authors can be reached via e-mail to <crossfire@schmorp.de>
23 */ 23 */
24
25 24
26#include <global.h> 25#include <global.h>
27#include <stdio.h> 26#include <stdio.h>
28 27
29New_Face *new_faces; 28#include "face.h"
29#include "crc.h"
30 30
31/* bmappair and xbm are used when looking for the image id numbers 31faceidx blank_face, empty_face;
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 32
43struct bmappair 33facehash_t facehash;
44{ 34std::vector<faceinfo> faces;
45 char *name;
46 unsigned int number;
47};
48
49void free (bmappair *); // guard to catch free when delete should be used
50
51static struct bmappair *xbm = NULL;
52
53/* Following can just as easily be pointers, but
54 * it is easier to keep them like this.
55 */
56New_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 */
69static int nroffiles = 0;
70int nrofpixmaps = 0;
71
72/**
73 * id is the face to smooth, smooth is the 16x2 face used to smooth id.
74 */
75struct smoothing:zero_initialised
76{
77 uint16 id;
78 uint16 smooth;
79};
80
81void free (smoothing *); // guard to catch free when delete should be used
82
83/**
84 * Contains all defined smoothing entries. smooth is an array of nrofsmooth
85 * entries. It is sorted by smooth[].id.
86 */
87static struct smoothing *smooth = NULL;
88int nrofsmooth = 0;
89 35
90/* the only thing this table is used for now is to 36/* the only thing this table is used for now is to
91 * translate the colorname in the magicmap field of the 37 * translate the colorname in the magicmap field of the
92 * face into a numeric index that is then sent to the 38 * face into a numeric index that is then sent to the
93 * client for magic map commands. The order of this table 39 * client for magic map commands. The order of this table
107 "brown", /* 10 */ 53 "brown", /* 10 */
108 "yellow", /* 11 */ 54 "yellow", /* 11 */
109 "khaki" /* 12 */ 55 "khaki" /* 12 */
110}; 56};
111 57
112static int
113compar (const struct bmappair *a, const struct bmappair *b)
114{
115 return strcmp (a->name, b->name);
116}
117
118static int
119compar_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}
127
128/* 58/*
129 * Returns the matching color in the coloralias if found, 59 * Returns the matching color in the coloralias if found,
130 * 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
131 * 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
132 */ 62 */
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 */
148static void
149ReadFaceData (void)
150{ 78{
151 char buf[MAX_BUF], *cp; 79 if (!name)
152 New_Face *on_face = NULL; 80 return defidx;
153 FILE *fp;
154 81
155 sprintf (buf, "%s/faces", settings.datadir); 82 facehash_t::iterator i = facehash.find (name);
156 LOG (llevDebug, "Reading faces from %s...\n", buf);
157 if ((fp = fopen (buf, "r")) == NULL)
158 {
159 LOG (llevError, "Cannot open faces file %s: %s\n", buf, strerror (errno));
160 exit (-1);
161 }
162 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 83
174 cp = buf + 5; 84 return i == facehash.end ()
175 cp[strlen (cp) - 1] = '\0'; /* remove newline */ 85 ? defidx : i->second;
176
177 if ((tmp = FindFace (cp, -1)) == -1)
178 {
179 LOG (llevError, "Could not find face %s\n", cp);
180 continue;
181 }
182 on_face = &new_faces[tmp];
183 on_face->visibility = 0;
184 }
185 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 }
217 else
218 LOG (llevDebug, "Got unknown line in faces file: %s\n", buf);
219 }
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
228 * difference.)
229 */
230void
231ReadBmapNames (void)
232{ 90{
233 char buf[MAX_BUF], *p, *q; 91 assert (0 < (faceidx)-1); // faceidx must be unsigned
234 FILE *fp;
235 int value, nrofbmaps = 0, i;
236 size_t l;
237 92
238 bmaps_checksum = 0; 93 if (idx >= faces.size ())
239 sprintf (buf, "%s/bmaps", settings.datadir); 94 return 0;
240 LOG (llevDebug, "Reading bmaps from %s...\n", buf);
241 if ((fp = fopen (buf, "r")) == NULL)
242 {
243 LOG (llevError, "Cannot open bmaps file %s: %s\n", buf, strerror (errno));
244 exit (-1);
245 }
246 95
247 /* First count how many bitmaps we have, so we can allocate correctly */ 96 return &faces [idx];
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 xbm[nroffiles].name = strdup (q);
269
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 }
296 fclose (fp);
297
298 LOG (llevDebug, "done (got %d/%d/%d)\n", nrofpixmaps, nrofbmaps, nroffiles);
299
300 new_faces = new New_Face[nrofpixmaps];
301
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 }
309 for (i = 0; i < nroffiles; i++)
310 {
311 new_faces[xbm[i].number].name = xbm[i].name;
312 }
313
314 // non-pod datatype, likely not allowed
315 qsort (xbm, nroffiles, sizeof (struct bmappair), (int (*)(const void *, const void *)) compar);
316
317 ReadFaceData ();
318
319 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#endif
326 new_faces[i].magicmap = 0;
327 }
328 }
329 /* 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
341 smooth_face = &new_faces[FindFace (SMOOTH_FACE_NAME, 0)];
342} 97}
343 98
344/* This returns an the face number of face 'name'. Number is constant 99facedata *
345 * during an invocation, but not necessarily between versions (this 100face_data (faceidx idx, int faceset)
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 */
357int
358FindFace (const char *name, int error)
359{ 101{
360 struct bmappair *bp, tmp; 102 if (faceinfo *f = face_info (idx))
361 char *p; 103 return &(faceset ? f->data32 : f->data64);
362 104
363 if (!name) 105 return 0;
364 return error;
365
366 if ((p = strchr (name, '\n')))
367 *p = '\0';
368
369 tmp.name = (char *) name;
370 bp = (struct bmappair *) bsearch (&tmp, xbm, nroffiles, sizeof (struct bmappair), (int (*)(const void *, const void *)) compar);
371
372 return bp ? bp->number : error;
373} 106}
374 107
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 */
382int
383ReadSmooth (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 LOG (llevDebug, "Reading smooth from %s...\n", buf);
392 if ((fp = fopen (buf, "r")) == NULL)
393 {
394 LOG (llevError, "Cannot open smooth file %s: %s\n", strerror (errno));
395 exit (-1);
396 }
397
398 /* 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 }
420 fclose (fp);
421
422 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}
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 */
436int
437FindSmooth (uint16 face, uint16 * smoothed)
438{
439 struct smoothing *bp, tmp;
440
441 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}
449
450/**
451 * Deallocates memory allocated by ReadBmapNames() and ReadSmooth().
452 */
453void
454free_all_images (void)
455{
456 int i;
457
458 for (i = 0; i < nroffiles; i++)
459 free (xbm[i].name);
460
461 delete[]xbm;
462 delete[]new_faces;
463 delete[]smooth;
464}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines