ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/image.C
Revision: 1.5
Committed: Fri Sep 8 16:51:42 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.4: +4 -1 lines
Log Message:
generic accessors, take one

File Contents

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