ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/image.c
Revision: 1.2
Committed: Sun Aug 13 17:16:00 2006 UTC (17 years, 9 months ago) by elmex
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +1 -1 lines
State: FILE REMOVED
Log Message:
Made server compile with C++.
Removed cfanim plugin and crossedit.
C++ here we come.

File Contents

# Content
1 /*
2 * static char *rcsid_image_c =
3 * "$Id$";
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 }