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

# User Rev Content
1 elmex 1.1 /*
2     * static char *rcsid_image_c =
3 root 1.5 * "$Id: image.C,v 1.4 2006-09-04 11:07:59 root Exp $";
4 elmex 1.1 */
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 root 1.4 struct bmappair
48     {
49     char *name;
50     unsigned int number;
51 elmex 1.1 };
52    
53 root 1.4 void free (bmappair *); // guard to catch free when delete should be used
54    
55 elmex 1.1 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 root 1.4 struct smoothing : zero_initialised
80     {
81 elmex 1.1 uint16 id;
82     uint16 smooth;
83     };
84    
85 root 1.4 void free (smoothing *); // guard to catch free when delete should be used
86    
87 elmex 1.1 /**
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 root 1.3 LOG(llevError, "Cannot open faces file %s: %s\n", buf, strerror(errno));
157 root 1.2 exit(-1);
158 elmex 1.1 }
159     while (fgets(buf, MAX_BUF, fp)!=NULL) {
160 root 1.2 if (*buf=='#') continue;
161     if (!strncmp(buf,"end",3)) {
162     on_face = NULL;
163     }
164     else if (!strncmp(buf,"face",4)) {
165 root 1.4 int tmp;
166 root 1.2
167 root 1.4 cp = buf + 5;
168     cp[strlen(cp)-1] = '\0'; /* remove newline */
169 root 1.2
170 root 1.4 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 root 1.2 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 elmex 1.1 }
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 root 1.3 LOG(llevError, "Cannot open bmaps file %s: %s\n", buf, strerror(errno));
223 root 1.2 exit(-1);
224 elmex 1.1 }
225    
226     /* First count how many bitmaps we have, so we can allocate correctly */
227     while (fgets (buf, MAX_BUF, fp)!=NULL)
228 root 1.2 if(buf[0] != '#' && buf[0] != '\n' )
229     nrofbmaps++;
230 elmex 1.1 rewind(fp);
231    
232 root 1.4 xbm = new bmappair [nrofbmaps];
233 elmex 1.1 memset (xbm, 0, sizeof (struct bmappair) * nrofbmaps);
234    
235     while(nroffiles < nrofbmaps && fgets (buf, MAX_BUF, fp) != NULL) {
236 root 1.2 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 elmex 1.1 }
272     fclose(fp);
273    
274     LOG(llevDebug,"done (got %d/%d/%d)\n",nrofpixmaps,nrofbmaps,nroffiles);
275    
276 root 1.4 new_faces = new New_Face [nrofpixmaps];
277 elmex 1.1 for (i = 0; i < nrofpixmaps; i++) {
278 root 1.2 new_faces[i].name = "";
279     new_faces[i].number = i;
280     new_faces[i].visibility=0;
281     new_faces[i].magicmap=255;
282 elmex 1.1 }
283     for (i = 0; i < nroffiles; i++) {
284 root 1.2 new_faces[xbm[i].number].name = xbm[i].name;
285 elmex 1.1 }
286    
287 root 1.4 // non-pod datatype, likely not allowed
288 elmex 1.1 qsort (xbm, nroffiles, sizeof(struct bmappair), (int (*)(const void*, const void*))compar);
289    
290     ReadFaceData();
291    
292     for (i = 0; i < nrofpixmaps; i++) {
293 root 1.2 if (new_faces[i].magicmap==255) {
294 elmex 1.1 #if 0 /* Useful for initial debugging, not needed now */
295 root 1.2 LOG(llevDebug,"Face %s still had default magicmap, resetting to black\n",
296     new_faces[i].name);
297 elmex 1.1 #endif
298 root 1.2 new_faces[i].magicmap=0;
299     }
300 elmex 1.1 }
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 root 1.5 if (!name)
334     return error;
335    
336 elmex 1.1 if ((p = strchr (name, '\n')))
337 root 1.2 *p = '\0';
338 elmex 1.1
339     tmp.name = (char *)name;
340     bp = (struct bmappair *)bsearch
341 root 1.2 (&tmp, xbm, nroffiles, sizeof(struct bmappair), (int (*)(const void*, const void*))compar);
342 elmex 1.1
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 root 1.3 LOG(llevError, "Cannot open smooth file %s: %s\n", strerror(errno));
363 root 1.2 exit(-1);
364 elmex 1.1 }
365    
366     /* First count how many smooth we have, so we can allocate correctly */
367     while (fgets (buf, MAX_BUF, fp)!=NULL)
368 root 1.2 if(buf[0] != '#' && buf[0] != '\n' )
369     smoothcount++;
370 elmex 1.1 rewind(fp);
371    
372 root 1.4 smooth = new smoothing [smoothcount];
373 elmex 1.1
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 root 1.2 free(xbm[i].name);
424 root 1.4
425     delete [] xbm;
426     delete [] new_faces;
427     delete [] smooth;
428 elmex 1.1 }