ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/image.c
Revision: 1.1
Committed: Fri Feb 3 07:11:30 2006 UTC (18 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Branch point for: UPSTREAM
Log Message:
Initial revision

File Contents

# User Rev Content
1 root 1.1 /*
2     * static char *rcsid_image_c =
3     * "$Id: image.c,v 1.18 2005/12/05 23:34:03 akirschbaum 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     char *name;
49     unsigned int number;
50     };
51    
52     static struct bmappair *xbm=NULL;
53    
54     /* Following can just as easily be pointers, but
55     * it is easier to keep them like this.
56     */
57     New_Face *blank_face, *dark_faces[3], *empty_face, *smooth_face;
58    
59    
60     /* nroffiles is the actual number of bitmaps defined.
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     */
70     static int nroffiles = 0;
71     int nrofpixmaps = 0;
72    
73     /**
74     * id is the face to smooth, smooth is the 16x2 face used to smooth id.
75     */
76     struct 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     */
85     static struct smoothing *smooth=NULL;
86     int 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     */
94     static 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    
110     static int compar (struct bmappair *a, struct bmappair *b) {
111     return strcmp (a->name, b->name);
112     }
113     static int compar_smooth (struct smoothing *a, 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     }
120    
121    
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     */
127    
128     static uint8 find_color(const char *name) {
129     uint8 i;
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     */
140    
141     static 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    
206     void 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     */
322     int FindFace (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 = 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     */
343     int 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     */
394     int 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     */
409     void 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     }