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.2 by root, Tue Aug 29 08:01:35 2006 UTC vs.
Revision 1.37 by root, Sat Apr 23 04:56:45 2011 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines