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.10 by pippijn, Sat Jan 6 14:42:28 2007 UTC vs.
Revision 1.43 by root, Sun Nov 11 05:53:11 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines