--- deliantra/server/common/image.C 2006/09/08 16:51:42 1.5 +++ deliantra/server/common/image.C 2012/11/11 05:53:11 1.43 @@ -1,428 +1,108 @@ /* - * static char *rcsid_image_c = - * "$Id: image.C,v 1.5 2006/09/08 16:51:42 root Exp $"; + * This file is part of Deliantra, the Roguelike Realtime MMORPG. + * + * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team + * + * Deliantra is free software: you can redistribute it and/or modify it under + * the terms of the Affero GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the Affero GNU General Public License + * and the GNU General Public License along with this program. If not, see + * . + * + * The authors can be reached via e-mail to */ -/* - CrossFire, A Multiplayer game for X-windows - - Copyright (C) 2002 Mark Wedel & Crossfire Development Team - Copyright (C) 1992 Frank Tore Johansen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - The maintainer of this code can be reached at crossfire-devel@real-time.com -*/ - - #include #include -New_Face *new_faces; - -/* bmappair and xbm are used when looking for the image id numbers - * of a face by name. xbm is sorted alphabetically so that bsearch - * can be used to quickly find the entry for a name. the number is - * then an index into the new_faces array. - * This data is redundant with new_face information - the difference - * is that this data gets sorted, and that doesn't necessarily happen - * with the new_face data - when accessing new_face[some number], - * that some number corresponds to the face at that number - for - * xbm, it may not. At current time, these do in fact match because - * the bmaps file is created in a sorted order. - */ - -struct bmappair -{ - char *name; - unsigned int number; -}; - -void free (bmappair *); // guard to catch free when delete should be used - -static struct bmappair *xbm=NULL; - -/* Following can just as easily be pointers, but - * it is easier to keep them like this. - */ -New_Face *blank_face, *dark_faces[3], *empty_face, *smooth_face; - - -/* nroffiles is the actual number of bitmaps defined. - * nrofpixmaps is the number of bitmaps loaded. With - * the automatic generation of the bmaps file, this is now equal - * to nroffiles. - * - * The xbm array (which contains name and number information, and - * is then sorted) contains nroffiles entries. the xbm_names - * array (which is used for converting the numeric face to - * a name) contains nrofpixmaps entries. - */ -static int nroffiles = 0; -int nrofpixmaps = 0; - -/** - * id is the face to smooth, smooth is the 16x2 face used to smooth id. - */ -struct smoothing : zero_initialised -{ - uint16 id; - uint16 smooth; -}; - -void free (smoothing *); // guard to catch free when delete should be used - -/** - * Contains all defined smoothing entries. smooth is an array of nrofsmooth - * entries. It is sorted by smooth[].id. - */ -static struct smoothing *smooth=NULL; -int nrofsmooth=0; - -/* the only thing this table is used for now is to - * translate the colorname in the magicmap field of the - * face into a numeric index that is then sent to the - * client for magic map commands. The order of this table - * must match that of the NDI colors in include/newclient.h. - */ -static const char *const colorname[] = { -"black", /* 0 */ -"white", /* 1 */ -"blue", /* 2 */ -"red", /* 3 */ -"orange", /* 4 */ -"light_blue", /* 5 */ -"dark_orange", /* 6 */ -"green", /* 7 */ -"light_green", /* 8 */ -"grey", /* 9 */ -"brown", /* 10 */ -"yellow", /* 11 */ -"khaki" /* 12 */ -}; - -static int compar (const struct bmappair *a, const struct bmappair *b) { - return strcmp (a->name, b->name); -} -static int compar_smooth (const struct smoothing *a, const struct smoothing *b) { - if (a->idid) - return -1; - if (b->idid) - return 1; - return 0; -} - +#include "face.h" +#include "crc.h" -/* - * Returns the matching color in the coloralias if found, - * 0 otherwise. Note that 0 will actually be black, so there is no - * way the calling function can tell if an error occurred or not - */ +faceidx blank_face, empty_face, magicmouth_face; -static uint8 find_color(const char *name) { - uint8 i; - for(i=0;i faces; -/* This reads the lib/faces file, getting color and visibility information. - * it is called by ReadBmapNames. - */ +static std::vector faces_freelist; -static void ReadFaceData(void) +faceidx face_alloc () { - char buf[MAX_BUF], *cp; - New_Face *on_face=NULL; - FILE *fp; - - sprintf(buf,"%s/faces", settings.datadir); - LOG(llevDebug,"Reading faces from %s...",buf); - if ((fp=fopen(buf,"r"))==NULL) { - LOG(llevError, "Cannot open faces file %s: %s\n", buf, strerror(errno)); - exit(-1); - } - while (fgets(buf, MAX_BUF, fp)!=NULL) { - if (*buf=='#') continue; - if (!strncmp(buf,"end",3)) { - on_face = NULL; - } - else if (!strncmp(buf,"face",4)) { - int tmp; - - cp = buf + 5; - cp[strlen(cp)-1] = '\0'; /* remove newline */ - - if ((tmp=FindFace(cp,-1))==-1) { - LOG(llevError,"Could not find face %s\n", cp); - continue; - } - on_face = &new_faces[tmp]; - on_face->visibility=0; - } - else if (on_face==NULL) { - LOG(llevError,"Got line with no face set: %s\n", buf); - } - else if (!strncmp(buf,"color_fg",8)) { - cp = buf + 9; - cp[strlen(cp)-1] = '\0'; - if (on_face->magicmap==255) on_face->magicmap=find_color(cp); - } - else if (!strncmp(buf,"color_bg",8)) { - /* ignore it */ - } - else if (!strncmp(buf,"visibility",10)) { - on_face->visibility = atoi(buf + 11); - } - else if (!strncmp(buf,"magicmap",8)) { - cp=buf+9; - cp[strlen(cp)-1] = '\0'; - on_face->magicmap=find_color(cp); - } - else if (!strncmp(buf,"is_floor",8)) { - int value = atoi(buf+9); - if (value) on_face->magicmap |= FACE_FLOOR; - } - else LOG(llevDebug,"Got unknown line in faces file: %s\n", buf); - } - LOG(llevDebug,"done\n"); - fclose(fp); -} + faceidx idx; -/* This reads the bmaps file to get all the bitmap names and - * stuff. It only needs to be done once, because it is player - * independent (ie, what display the person is on will not make a - * difference.) - */ - -void ReadBmapNames (void) { - char buf[MAX_BUF], *p, *q; - FILE *fp; - int value, nrofbmaps = 0, i; - size_t l; - - bmaps_checksum=0; - sprintf (buf,"%s/bmaps", settings.datadir); - LOG(llevDebug,"Reading bmaps from %s...",buf); - if ((fp=fopen(buf,"r"))==NULL) { - LOG(llevError, "Cannot open bmaps file %s: %s\n", buf, strerror(errno)); - exit(-1); - } - - /* First count how many bitmaps we have, so we can allocate correctly */ - while (fgets (buf, MAX_BUF, fp)!=NULL) - if(buf[0] != '#' && buf[0] != '\n' ) - nrofbmaps++; - rewind(fp); - - xbm = new bmappair [nrofbmaps]; - memset (xbm, 0, sizeof (struct bmappair) * nrofbmaps); - - while(nroffiles < nrofbmaps && fgets (buf, MAX_BUF, fp) != NULL) { - if (*buf == '#') - continue; - - p = (*buf == '\\') ? (buf + 1): buf; - if (!(p = strtok (p , " \t")) || !(q = strtok (NULL , " \t\n"))) { - LOG(llevDebug,"Warning, syntax error: %s\n", buf); - continue; - } - value = atoi (p); - xbm[nroffiles].name = strdup_local(q); - - /* We need to calculate the checksum of the bmaps file - * name->number mapping to send to the client. This does not - * need to match what sum or other utility may come up with - - * as long as we get the same results on the same real file - * data, it does the job as it lets the client know if - * the file has the same data or not. - */ - ROTATE_RIGHT(bmaps_checksum); - bmaps_checksum += value & 0xff; - bmaps_checksum &= 0xffffffff; - - ROTATE_RIGHT(bmaps_checksum); - bmaps_checksum += (value >> 8) & 0xff; - bmaps_checksum &= 0xffffffff; - for (l=0; l= nrofpixmaps) - nrofpixmaps = value+1; + if (!faces_freelist.empty ()) + { + idx = faces_freelist.back (); + faces_freelist.pop_back (); } - fclose(fp); + else + { + idx = faces.size (); - LOG(llevDebug,"done (got %d/%d/%d)\n",nrofpixmaps,nrofbmaps,nroffiles); + if (!idx) // skip index 0 + idx = 1; - new_faces = new New_Face [nrofpixmaps]; - for (i = 0; i < nrofpixmaps; i++) { - new_faces[i].name = ""; - new_faces[i].number = i; - new_faces[i].visibility=0; - new_faces[i].magicmap=255; - } - for (i = 0; i < nroffiles; i++) { - new_faces[xbm[i].number].name = xbm[i].name; + faces.resize (idx + 1); } - // non-pod datatype, likely not allowed - qsort (xbm, nroffiles, sizeof(struct bmappair), (int (*)(const void*, const void*))compar); + return idx; +} - ReadFaceData(); +void +faceinfo::unref () +{ + if (--refcnt) + return; - for (i = 0; i < nrofpixmaps; i++) { - if (new_faces[i].magicmap==255) { -#if 0 /* Useful for initial debugging, not needed now */ - LOG(llevDebug,"Face %s still had default magicmap, resetting to black\n", - new_faces[i].name); -#endif - new_faces[i].magicmap=0; - } - } - /* Actually forcefully setting the colors here probably should not - * be done - it could easily create confusion. - */ - blank_face = &new_faces[FindFace(BLANK_FACE_NAME, 0)]; - blank_face->magicmap = find_color ("khaki") | FACE_FLOOR; - - empty_face = &new_faces[FindFace(EMPTY_FACE_NAME, 0)]; - - dark_faces[0] = &new_faces[FindFace (DARK_FACE1_NAME,0)]; - dark_faces[1] = &new_faces[FindFace (DARK_FACE2_NAME,0)]; - dark_faces[2] = &new_faces[FindFace (DARK_FACE3_NAME,0)]; + refcnt = 1; - smooth_face = &new_faces[FindFace(SMOOTH_FACE_NAME,0)]; } -/* This returns an the face number of face 'name'. Number is constant - * during an invocation, but not necessarily between versions (this - * is because the faces are arranged in alphabetical order, so - * if a face is removed or added, all faces after that will now - * have a different number. - * - * the parameter error determines behaviour. If a face is - * not found, then error is returned. This can be useful if - * you want some default face used, or can be set to negative - * so that it will be known that the face could not be found - * (needed in client, so that it will know to request that image - * from the server) - */ -int FindFace (const char *name, int error) { - struct bmappair *bp, tmp; - char *p; - - if (!name) - return error; - - if ((p = strchr (name, '\n'))) - *p = '\0'; +faceidx +face_find (const char *name, faceidx defidx) +{ + if (!name) + return defidx; - tmp.name = (char *)name; - bp = (struct bmappair *)bsearch - (&tmp, xbm, nroffiles, sizeof(struct bmappair), (int (*)(const void*, const void*))compar); + facehash_t::iterator i = facehash.find (name); - return bp ? bp->number : error; + return i == facehash.end () + ? defidx : i->second; } -/* Reads the smooth file to know how to smooth datas. - * the smooth file if made of 2 elements lines. - * lines starting with # are comment - * the first element of line is face to smooth - * the next element is the 16x2 faces picture - * used for smoothing - */ -int ReadSmooth (void) { - char buf[MAX_BUF], *p, *q; - FILE *fp; - int smoothcount = 0; - - bmaps_checksum=0; - sprintf (buf,"%s/smooth", settings.datadir); - LOG(llevDebug,"Reading smooth from %s...",buf); - if ((fp=fopen(buf,"r"))==NULL) { - LOG(llevError, "Cannot open smooth file %s: %s\n", strerror(errno)); - exit(-1); - } +faceinfo * +face_info (faceidx idx) +{ + assert (0 < (faceidx)-1); // faceidx must be unsigned - /* First count how many smooth we have, so we can allocate correctly */ - while (fgets (buf, MAX_BUF, fp)!=NULL) - if(buf[0] != '#' && buf[0] != '\n' ) - smoothcount++; - rewind(fp); - - smooth = new smoothing [smoothcount]; - - while(nrofsmooth < smoothcount && fgets (buf, MAX_BUF, fp)!=NULL) { - if (*buf == '#') - continue; - p=strchr(buf,' '); - if (!p) - continue; - *p='\0'; - q=buf; - smooth[nrofsmooth].id=FindFace(q,0); - q=p+1; - smooth[nrofsmooth].smooth=FindFace(q,0); - nrofsmooth++; - } - fclose(fp); + if (idx >= faces.size ()) + return 0; - LOG(llevDebug,"done (got %d smooth entries)\n",nrofsmooth); - qsort (smooth, nrofsmooth, sizeof(struct smoothing), (int (*)(const void*, const void*))compar_smooth); - return nrofsmooth; + return &faces [idx]; } -/** - * Find the smooth face for a given face. - * - * @param face the face to find the smoothing face for - * - * @param smoothed return value: set to smooth face - * - * @return 1=smooth face found, 0=no smooth face found - */ -int FindSmooth (uint16 face, uint16* smoothed) { - struct smoothing *bp, tmp; +facedata * +faceinfo::data (int faceset) const +{ + if (!face [faceset].chksum_len) + faceset = 0; - tmp.id = face; - bp = (struct smoothing *)bsearch - (&tmp, smooth, nrofsmooth, sizeof(struct smoothing), (int (*)(const void*, const void*))compar_smooth); - (*smoothed)=0; - if (bp) - (*smoothed)=bp->smooth; - return bp ? 1 : 0; + return (facedata *)(face + faceset); } -/** - * Deallocates memory allocated by ReadBmapNames() and ReadSmooth(). - */ -void free_all_images(void) +facedata * +face_data (faceidx idx, int faceset) { - int i; - - for (i=0; idata (faceset); - delete [] xbm; - delete [] new_faces; - delete [] smooth; + return 0; } +