Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_image_c = 00003 * "$Id: image.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The maintainer of this code can be reached at crossfire-devel@real-time.com 00027 */ 00028 00034 #include <global.h> 00035 #include <stdio.h> 00036 #include "image.h" 00037 00038 New_Face *new_faces; 00039 00052 struct bmappair { 00053 char *name; 00054 unsigned int number; 00055 }; 00060 static struct bmappair *xbm = NULL; 00061 00066 New_Face *blank_face, *empty_face, *smooth_face; 00067 00068 00070 static int nroffiles = 0; 00071 00076 int nrofpixmaps = 0; 00077 00078 face_sets facesets[MAX_FACE_SETS]; 00087 static const char *const colorname[] = { 00088 "black", /* 0 */ 00089 "white", /* 1 */ 00090 "blue", /* 2 */ 00091 "red", /* 3 */ 00092 "orange", /* 4 */ 00093 "light_blue", /* 5 */ 00094 "dark_orange", /* 6 */ 00095 "green", /* 7 */ 00096 "light_green", /* 8 */ 00097 "grey", /* 9 */ 00098 "brown", /* 10 */ 00099 "yellow", /* 11 */ 00100 "khaki" /* 12 */ 00101 }; 00102 00106 static int compar(const struct bmappair *a, const struct bmappair *b) { 00107 return strcmp(a->name, b->name); 00108 } 00109 00123 static uint8 find_color(const char *name) { 00124 uint8 i; 00125 00126 for (i = 0; i < sizeof(colorname)/sizeof(*colorname); i++) 00127 if (!strcmp(name, colorname[i])) 00128 return i; 00129 00130 LOG(llevError, "Unknown color: %s\n", name); 00131 return 0; 00132 } 00133 00141 static void read_face_data(void) { 00142 char buf[MAX_BUF], *cp; 00143 New_Face *on_face = NULL; 00144 FILE *fp; 00145 00146 snprintf(buf, sizeof(buf), "%s/faces", settings.datadir); 00147 LOG(llevDebug, "Reading faces from %s...\n", buf); 00148 if ((fp = fopen(buf, "r")) == NULL) { 00149 LOG(llevError, "Cannot open faces file: %s\n", strerror_local(errno, buf, sizeof(buf))); 00150 exit(-1); 00151 } 00152 00153 while (fgets(buf, MAX_BUF, fp) != NULL) { 00154 if (*buf == '#') 00155 continue; 00156 if (!strncmp(buf, "end", 3)) { 00157 on_face = NULL; 00158 } else if (!strncmp(buf, "face", 4)) { 00159 unsigned tmp; 00160 00161 cp = buf+5; 00162 cp[strlen(cp)-1] = '\0'; /* remove newline */ 00163 00164 if ((tmp = find_face(cp, (unsigned)-1)) == (unsigned)-1) { 00165 LOG(llevError, "Could not find face %s\n", cp); 00166 continue; 00167 } 00168 on_face = &new_faces[tmp]; 00169 on_face->visibility = 0; 00170 } else if (on_face == NULL) { 00171 LOG(llevError, "Got line with no face set: %s\n", buf); 00172 } else if (!strncmp(buf, "visibility", 10)) { 00173 on_face->visibility = atoi(buf+11); 00174 } else if (!strncmp(buf, "magicmap", 8)) { 00175 cp = buf+9; 00176 cp[strlen(cp)-1] = '\0'; 00177 on_face->magicmap = find_color(cp); 00178 } else if (!strncmp(buf, "is_floor", 8)) { 00179 int value = atoi(buf+9); 00180 if (value) 00181 on_face->magicmap |= FACE_FLOOR; 00182 } else 00183 LOG(llevDebug, "Got unknown line in faces file: %s\n", buf); 00184 } 00185 LOG(llevDebug, "done\n"); 00186 fclose(fp); 00187 } 00188 00198 void read_bmap_names(void) { 00199 char buf[MAX_BUF], *p, *q; 00200 FILE *fp; 00201 int value, nrofbmaps = 0, i; 00202 size_t l; 00203 00204 bmaps_checksum = 0; 00205 snprintf(buf, sizeof(buf), "%s/bmaps", settings.datadir); 00206 LOG(llevDebug, "Reading bmaps from %s...\n", buf); 00207 if ((fp = fopen(buf, "r")) == NULL) { 00208 LOG(llevError, "Cannot open bmaps file: %s\n", strerror_local(errno, buf, sizeof(buf))); 00209 exit(-1); 00210 } 00211 00212 /* First count how many bitmaps we have, so we can allocate correctly */ 00213 while (fgets(buf, MAX_BUF, fp) != NULL) 00214 if (buf[0] != '#' && buf[0] != '\n') 00215 nrofbmaps++; 00216 rewind(fp); 00217 00218 xbm = (struct bmappair *)malloc(sizeof(struct bmappair)*nrofbmaps); 00219 if (xbm == NULL) { 00220 LOG(llevError, "read_bmap_names: xbm memory allocation failure.\n"); 00221 abort(); 00222 } 00223 memset(xbm, 0, sizeof(struct bmappair)*nrofbmaps); 00224 00225 nroffiles = 0; 00226 while (nroffiles < nrofbmaps && fgets(buf, MAX_BUF, fp) != NULL) { 00227 if (*buf == '#') 00228 continue; 00229 00230 p = (*buf == '\\') ? (buf+1) : buf; 00231 if (!(p = strtok(p, " \t")) || !(q = strtok(NULL, " \t\n"))) { 00232 LOG(llevDebug, "Warning, syntax error: %s\n", buf); 00233 continue; 00234 } 00235 value = atoi(p); 00236 xbm[nroffiles].name = strdup_local(q); 00237 00238 /* We need to calculate the checksum of the bmaps file 00239 * name->number mapping to send to the client. This does not 00240 * need to match what sum or other utility may come up with - 00241 * as long as we get the same results on the same real file 00242 * data, it does the job as it lets the client know if 00243 * the file has the same data or not. 00244 */ 00245 ROTATE_RIGHT(bmaps_checksum); 00246 bmaps_checksum += value&0xff; 00247 bmaps_checksum &= 0xffffffff; 00248 00249 ROTATE_RIGHT(bmaps_checksum); 00250 bmaps_checksum += (value>>8)&0xff; 00251 bmaps_checksum &= 0xffffffff; 00252 for (l = 0; l < strlen(q); l++) { 00253 ROTATE_RIGHT(bmaps_checksum); 00254 bmaps_checksum += q[l]; 00255 bmaps_checksum &= 0xffffffff; 00256 } 00257 00258 xbm[nroffiles].number = value; 00259 nroffiles++; 00260 if (value >= nrofpixmaps) 00261 nrofpixmaps = value+1; 00262 } 00263 fclose(fp); 00264 00265 LOG(llevDebug, "done (got %d/%d/%d)\n", nrofpixmaps, nrofbmaps, nroffiles); 00266 00267 new_faces = (New_Face *)malloc(sizeof(New_Face)*nrofpixmaps); 00268 if (new_faces == NULL) { 00269 LOG(llevError, "read_bmap_names: new_faces memory allocation failure.\n"); 00270 abort(); 00271 } 00272 00273 for (i = 0; i < nrofpixmaps; i++) { 00274 new_faces[i].name = ""; 00275 new_faces[i].number = i; 00276 new_faces[i].visibility = 0; 00277 new_faces[i].magicmap = 255; 00278 new_faces[i].smoothface = (uint16)-1; 00279 } 00280 00281 for (i = 0; i < nroffiles; i++) { 00282 new_faces[xbm[i].number].name = xbm[i].name; 00283 } 00284 00285 qsort(xbm, nroffiles, sizeof(struct bmappair), (int (*)(const void *, const void *))compar); 00286 00287 read_face_data(); 00288 00289 for (i = 0; i < nrofpixmaps; i++) { 00290 if (new_faces[i].magicmap == 255) { 00291 new_faces[i].magicmap = 0; 00292 } 00293 } 00294 /* Actually forcefully setting the colors here probably should not 00295 * be done - it could easily create confusion. 00296 */ 00297 blank_face = &new_faces[find_face(BLANK_FACE_NAME, 0)]; 00298 blank_face->magicmap = find_color("khaki")|FACE_FLOOR; 00299 00300 empty_face = &new_faces[find_face(EMPTY_FACE_NAME, 0)]; 00301 00302 smooth_face = &new_faces[find_face(SMOOTH_FACE_NAME, 0)]; 00303 } 00304 00324 unsigned find_face(const char *name, unsigned error) { 00325 struct bmappair *bp, tmp; 00326 char *p; 00327 00328 if ((p = strchr(name, '\n'))) 00329 *p = '\0'; 00330 00331 tmp.name = (char *)name; 00332 bp = (struct bmappair *)bsearch(&tmp, xbm, nroffiles, sizeof(struct bmappair), (int (*)(const void *, const void *))compar); 00333 00334 return bp ? bp->number : error; 00335 } 00336 00348 int read_smooth(void) { 00349 char buf[MAX_BUF], *p, *q; 00350 FILE *fp; 00351 int regular, smoothed, nrofsmooth = 0; 00352 00353 snprintf(buf, sizeof(buf), "%s/smooth", settings.datadir); 00354 LOG(llevDebug, "Reading smooth from %s...\n", buf); 00355 if ((fp = fopen(buf, "r")) == NULL) { 00356 LOG(llevError, "Cannot open smooth file %s: %s\n", strerror_local(errno, buf, sizeof(buf))); 00357 exit(-1); 00358 } 00359 00360 while (fgets(buf, MAX_BUF, fp) != NULL) { 00361 if (*buf == '#') 00362 continue; 00363 00364 p = strchr(buf, ' '); 00365 if (!p) 00366 continue; 00367 00368 *p = '\0'; 00369 q = buf; 00370 regular = find_face(q, (unsigned)-1); 00371 if (regular == (unsigned)-1) { 00372 LOG(llevError, "invalid regular face: %s\n", q); 00373 continue; 00374 } 00375 q = p+1; 00376 smoothed = find_face(q, (unsigned)-1); 00377 if (smoothed == (unsigned)-1) { 00378 LOG(llevError, "invalid smoothed face: %s\n", q); 00379 continue; 00380 } 00381 00382 new_faces[regular].smoothface = smoothed; 00383 00384 nrofsmooth++; 00385 } 00386 fclose(fp); 00387 00388 LOG(llevDebug, "done (got %d smooth entries)\n", nrofsmooth); 00389 return nrofsmooth; 00390 } 00391 00401 int find_smooth(uint16 face, uint16 *smoothed) { 00402 (*smoothed) = 0; 00403 00404 if (face < nrofpixmaps) { 00405 if (new_faces[face].smoothface == ((uint16)-1)) 00406 return 0; 00407 00408 (*smoothed) = new_faces[face].smoothface; 00409 return 1; 00410 } 00411 00412 return 0; 00413 } 00414 00418 void free_all_images(void) { 00419 int i; 00420 00421 for (i = 0; i < nroffiles; i++) 00422 free(xbm[i].name); 00423 free(xbm); 00424 free(new_faces); 00425 } 00426 00435 static void check_faceset_fallback(int faceset, int togo) { 00436 int fallback = facesets[faceset].fallback; 00437 00438 /* proper case - falls back to base set */ 00439 if (fallback == 0) 00440 return; 00441 00442 if (!facesets[fallback].prefix) { 00443 LOG(llevError, "Face set %d falls to non set faceset %d\n", faceset, fallback); 00444 abort(); 00445 } 00446 togo--; 00447 if (togo == 0) { 00448 LOG(llevError, "Infinite loop found in facesets. aborting.\n"); 00449 abort(); 00450 } 00451 check_faceset_fallback(fallback, togo); 00452 } 00453 00471 void read_client_images(void) { 00472 char filename[400]; 00473 char buf[HUGE_BUF]; 00474 char *cp, *cps[7]; 00475 FILE *infile; 00476 int num, len, compressed, fileno, i, badline; 00477 00478 memset(facesets, 0, sizeof(facesets)); 00479 snprintf(filename, sizeof(filename), "%s/image_info", settings.datadir); 00480 if ((infile = open_and_uncompress(filename, 0, &compressed)) == NULL) { 00481 LOG(llevError, "Unable to open %s\n", filename); 00482 abort(); 00483 } 00484 while (fgets(buf, HUGE_BUF-1, infile) != NULL) { 00485 badline = 0; 00486 00487 if (buf[0] == '#') 00488 continue; 00489 if (!(cps[0] = strtok(buf, ":"))) 00490 badline = 1; 00491 for (i = 1; i < 7; i++) { 00492 if (!(cps[i] = strtok(NULL, ":"))) 00493 badline = 1; 00494 } 00495 if (badline) { 00496 LOG(llevError, "Bad line in image_info file, ignoring line:\n %s", buf); 00497 } else { 00498 len = atoi(cps[0]); 00499 if (len >= MAX_FACE_SETS) { 00500 LOG(llevError, "To high a setnum in image_info file: %d > %d\n", len, MAX_FACE_SETS); 00501 abort(); 00502 } 00503 facesets[len].prefix = strdup_local(cps[1]); 00504 facesets[len].fullname = strdup_local(cps[2]); 00505 facesets[len].fallback = atoi(cps[3]); 00506 facesets[len].size = strdup_local(cps[4]); 00507 facesets[len].extension = strdup_local(cps[5]); 00508 facesets[len].comment = strdup_local(cps[6]); 00509 } 00510 } 00511 close_and_delete(infile, compressed); 00512 for (i = 0; i < MAX_FACE_SETS; i++) { 00513 if (facesets[i].prefix) 00514 check_faceset_fallback(i, MAX_FACE_SETS); 00515 } 00516 /* Loaded the faceset information - now need to load up the 00517 * actual faces. 00518 */ 00519 00520 for (fileno = 0; fileno < MAX_FACE_SETS; fileno++) { 00521 /* if prefix is not set, this is not used */ 00522 if (!facesets[fileno].prefix) 00523 continue; 00524 facesets[fileno].faces = calloc(nrofpixmaps, sizeof(face_info)); 00525 00526 snprintf(filename, sizeof(filename), "%s/crossfire.%d", settings.datadir, fileno); 00527 LOG(llevDebug, "Loading image file %s\n", filename); 00528 00529 if ((infile = open_and_uncompress(filename, 0, &compressed)) == NULL) { 00530 LOG(llevError, "Unable to open %s\n", filename); 00531 abort(); 00532 } 00533 while (fgets(buf, HUGE_BUF-1, infile) != NULL) { 00534 if (strncmp(buf, "IMAGE ", 6) != 0) { 00535 LOG(llevError, "read_client_images:Bad image line - not IMAGE, instead\n%s", buf); 00536 abort(); 00537 } 00538 num = atoi(buf+6); 00539 if (num < 0 || num >= nrofpixmaps) { 00540 LOG(llevError, "read_client_images: Image num %d not in 0..%d\n%s", num, nrofpixmaps, buf); 00541 abort(); 00542 } 00543 /* Skip accross the number data */ 00544 for (cp = buf+6; *cp != ' '; cp++) 00545 ; 00546 len = atoi(cp); 00547 if (len == 0 || len > MAX_IMAGE_SIZE) { 00548 LOG(llevError, "read_client_images: length not valid: %d > %d \n%s", len, MAX_IMAGE_SIZE, buf); 00549 abort(); 00550 } 00551 /* We don't actualy care about the name if the image that 00552 * is embedded in the image file, so just ignore it. 00553 */ 00554 facesets[fileno].faces[num].datalen = len; 00555 facesets[fileno].faces[num].data = malloc(len); 00556 if ((i = fread(facesets[fileno].faces[num].data, len, 1, infile)) != 1) { 00557 LOG(llevError, "read_client_images: Did not read desired amount of data, wanted %d, got %d\n%s", len, i, buf); 00558 abort(); 00559 } 00560 facesets[fileno].faces[num].checksum = 0; 00561 for (i = 0; i < len; i++) { 00562 ROTATE_RIGHT(facesets[fileno].faces[num].checksum); 00563 facesets[fileno].faces[num].checksum += facesets[fileno].faces[num].data[i]; 00564 facesets[fileno].faces[num].checksum &= 0xffffffff; 00565 } 00566 } 00567 close_and_delete(infile, compressed); 00568 } /* For fileno < MAX_FACE_SETS */ 00569 } 00570 00575 int is_valid_faceset(int fsn) { 00576 if (fsn >= 0 && fsn < MAX_FACE_SETS && facesets[fsn].prefix) 00577 return TRUE; 00578 return FALSE; 00579 } 00580 00584 void free_socket_images(void) { 00585 int num, q; 00586 00587 for (num = 0; num < MAX_FACE_SETS; num++) { 00588 if (facesets[num].prefix) { 00589 for (q = 0; q < nrofpixmaps; q++) 00590 if (facesets[num].faces[q].data) 00591 free(facesets[num].faces[q].data); 00592 free(facesets[num].prefix); 00593 free(facesets[num].fullname); 00594 free(facesets[num].size); 00595 free(facesets[num].extension); 00596 free(facesets[num].comment); 00597 free(facesets[num].faces); 00598 } 00599 } 00600 } 00601 00614 int get_face_fallback(int faceset, int imageno) { 00615 /* faceset 0 is supposed to have every image, so just return. Doing 00616 * so also prevents infinite loops in the case if it not having 00617 * the face, but in that case, we are likely to crash when we try 00618 * to access the data, but that is probably preferable to an infinite 00619 * loop. 00620 */ 00621 if (faceset == 0) 00622 return 0; 00623 00624 if (!facesets[faceset].prefix) { 00625 LOG(llevError, "get_face_fallback called with unused set (%d)?\n", faceset); 00626 return 0; /* use default set */ 00627 } 00628 if (facesets[faceset].faces[imageno].data) 00629 return faceset; 00630 return get_face_fallback(facesets[faceset].fallback, imageno); 00631 }