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.17 by root, Thu Feb 15 18:09:33 2007 UTC vs.
Revision 1.39 by root, Tue Jan 3 11:25:30 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines