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.14 by root, Fri Feb 2 22:49:11 2007 UTC vs.
Revision 1.45 by root, Sat Nov 17 23:40:00 2018 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 (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
5 * Copyright (C) 2002 Mark Wedel & Crossfire Development Team 5 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
6 * Copyright (C) 1992 Frank Tore Johansen
7 * 6 *
8 * This program is free software; you can redistribute it and/or modify 7 * 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 8 * 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 9 * Free Software Foundation, either version 3 of the License, or (at your
11 * (at your option) any later version. 10 * option) any later version.
12 * 11 *
13 * This program is distributed in the hope that it will be useful, 12 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details. 15 * 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 * 16 *
22 * The maintainer of this code can be reached at <crossfire@schmorp.de> 17 * You should have received a copy of the Affero GNU General Public License
18 * and the GNU General Public License along with this program. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 * The authors can be reached via e-mail to <support@deliantra.net>
23 */ 22 */
24
25 23
26#include <global.h> 24#include <global.h>
27#include <stdio.h> 25#include <stdio.h>
28 26
29facetile *new_faces; 27#include "face.h"
28#include "crc.h"
30 29
31/* bmappair and xbm are used when looking for the image id numbers 30faceidx 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 31
43struct bmappair 32facehash_t facehash;
33std::vector<faceinfo> faces;
34
35static std::vector<faceidx> faces_freelist;
36
37faceidx face_alloc ()
44{ 38{
45 char *name; 39 faceidx idx;
46 unsigned int number;
47};
48 40
49static struct bmappair *xbm = NULL; 41 if (!faces_freelist.empty ())
42 {
43 idx = faces_freelist.back ();
44 faces_freelist.pop_back ();
45 }
46 else
47 {
48 idx = faces.size ();
50 49
51facetile *blank_face, *dark_faces[3], *empty_face, *smooth_face; 50 if (!idx) // skip index 0
51 idx = 1;
52 52
53/* nroffiles is the actual number of bitmaps defined. 53 faces.resize (idx + 1);
54 * nrofpixmaps is the number of bitmaps loaded. With 54 }
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 */
63static int nroffiles = 0;
64int nrofpixmaps = 0;
65 55
66/** 56 return idx;
67 * id is the face to smooth, smooth is the 16x2 face used to smooth id.
68 */
69struct smoothing : zero_initialised
70{
71 uint16 id;
72 uint16 smooth;
73};
74
75/**
76 * Contains all defined smoothing entries. smooth is an array of nrofsmooth
77 * entries. It is sorted by smooth[].id.
78 */
79static struct smoothing *smooth = NULL;
80int nrofsmooth = 0;
81
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 */
88static const char *const colorname[] = {
89 "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};
103
104static int
105compar (const struct bmappair *a, const struct bmappair *b)
106{
107 return strcmp (a->name, b->name);
108} 57}
109 58
110static int 59void
111compar_smooth (const struct smoothing *a, const struct smoothing *b) 60faceinfo::unref ()
112{ 61{
113 if (a->id < b->id) 62 if (--refcnt)
114 return -1; 63 return;
115 if (b->id < a->id) 64
65 refcnt = 1;
66
67}
68
69faceidx
70face_find (const char *name, faceidx defidx)
71{
72 if (!name)
73 return defidx;
74
75 facehash_t::iterator i = facehash.find (name);
76
77 return i == facehash.end ()
78 ? defidx : i->second;
79}
80
81faceinfo *
82face_info (faceidx idx)
83{
84 assert (0 < (faceidx)-1); // faceidx must be unsigned
85
86 if (idx >= faces.size ())
116 return 1; 87 return 0;
88
89 return &faces [idx];
90}
91
92facedata *
93faceinfo::data (int faceset) const
94{
95 if (!face [faceset].chksum_len)
96 faceset = 0;
97
98 return (facedata *)(face + faceset);
99}
100
101facedata *
102face_data (faceidx idx, int faceset)
103{
104 if (faceinfo *f = face_info (idx))
105 return f->data (faceset);
106
117 return 0; 107 return 0;
118} 108}
119 109
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 */
125static uint8
126find_color (const char *name)
127{
128 uint8 i;
129
130 for (i = 0; i < sizeof (colorname) / sizeof (*colorname); i++)
131 if (!strcmp (name, colorname[i]))
132 return i;
133 LOG (llevError, "Unknown color: %s\n", name);
134 return 0;
135}
136
137/* This reads the lib/faces file, getting color and visibility information.
138 * it is called by ReadBmapNames.
139 */
140static void
141ReadFaceData (void)
142{
143 char buf[MAX_BUF], *cp;
144 facetile *on_face = NULL;
145 FILE *fp;
146
147 sprintf (buf, "%s/faces", settings.datadir);
148 LOG (llevDebug, "Reading faces from %s...\n", buf);
149 if ((fp = fopen (buf, "r")) == NULL)
150 {
151 LOG (llevError, "Cannot open faces file %s: %s\n", buf, strerror (errno));
152 exit (-1);
153 }
154 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 }
174 on_face = &new_faces[tmp];
175 on_face->visibility = 0;
176 }
177 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 }
209 else
210 LOG (llevDebug, "Got unknown line in faces file: %s\n", buf);
211 }
212
213 LOG (llevDebug, "done\n");
214 fclose (fp);
215}
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 */
222void
223ReadBmapNames (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 LOG (llevDebug, "Reading bmaps from %s...\n", buf);
233 if ((fp = fopen (buf, "r")) == NULL)
234 {
235 LOG (llevError, "Cannot open bmaps file %s: %s\n", buf, strerror (errno));
236 exit (-1);
237 }
238
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 xbm[nroffiles].name = strdup (q);
261
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 }
288 fclose (fp);
289
290 LOG (llevDebug, "done (got %d/%d/%d)\n", nrofpixmaps, nrofbmaps, nroffiles);
291
292 new_faces = new facetile[nrofpixmaps];
293
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 }
301 for (i = 0; i < nroffiles; i++)
302 {
303 new_faces[xbm[i].number].name = xbm[i].name;
304 }
305
306 // non-pod datatype, likely not allowed
307 qsort (xbm, nroffiles, sizeof (struct bmappair), (int (*)(const void *, const void *)) compar);
308
309 ReadFaceData ();
310
311 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#endif
318 new_faces[i].magicmap = 0;
319 }
320 }
321 /* 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
333 smooth_face = &new_faces[FindFace (SMOOTH_FACE_NAME, 0)];
334}
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 */
349int
350FindFace (const char *name, int error)
351{
352 struct bmappair *bp, tmp;
353 char *p;
354
355 if (!name)
356 return error;
357
358 if ((p = strchr (name, '\n')))
359 *p = '\0';
360
361 tmp.name = (char *) name;
362 bp = (struct bmappair *) bsearch (&tmp, xbm, nroffiles, sizeof (struct bmappair), (int (*)(const void *, const void *)) compar);
363
364 return bp ? bp->number : error;
365}
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 */
374int
375ReadSmooth (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 LOG (llevDebug, "Reading smooth from %s...\n", buf);
384 if ((fp = fopen (buf, "r")) == NULL)
385 {
386 LOG (llevError, "Cannot open smooth file %s: %s\n", strerror (errno));
387 exit (-1);
388 }
389
390 /* 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 }
412 fclose (fp);
413
414 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}
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 */
428int
429FindSmooth (uint16 face, uint16 * smoothed)
430{
431 struct smoothing *bp, tmp;
432
433 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}
441
442/**
443 * Deallocates memory allocated by ReadBmapNames() and ReadSmooth().
444 */
445void
446free_all_images (void)
447{
448 int i;
449
450 for (i = 0; i < nroffiles; i++)
451 free (xbm[i].name);
452
453 delete[]xbm;
454 delete[]new_faces;
455 delete[]smooth;
456}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines