From: havoc Date: Sat, 17 Oct 2009 21:17:29 +0000 (+0000) Subject: implemented real support for QW skins (pants, shirt, glow, cropped pcx X-Git-Tag: xonotic-v0.1.0preview~1287 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=980ac035e70ad26a44913dabebe4be5726f966ac implemented real support for QW skins (pants, shirt, glow, cropped pcx decoding) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9348 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/gl_rmain.c b/gl_rmain.c index 29bd2d4b..cef68dc5 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -191,8 +191,15 @@ unsigned int r_queries[R_MAX_OCCLUSION_QUERIES]; unsigned int r_numqueries; unsigned int r_maxqueries; -char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH]; -skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD]; +typedef struct r_qwskincache_s +{ + char name[MAX_QPATH]; + skinframe_t *skinframe; +} +r_qwskincache_t; + +static r_qwskincache_t *r_qwskincache; +static int r_qwskincache_size; /// vertex coordinates for a quad that covers the screen exactly const float r_screenvertex3f[12] = @@ -2430,7 +2437,8 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl int basepixels_height; skinframe_t *skinframe; - *has_alpha = false; + if (has_alpha) + *has_alpha = false; if (cls.state == ca_dedicated) return NULL; @@ -2474,7 +2482,8 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl if (j < basepixels_width * basepixels_height * 4) { // has transparent pixels - *has_alpha = true; + if (has_alpha) + *has_alpha = true; pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); for (j = 0;j < image_width * image_height * 4;j += 4) { @@ -2532,8 +2541,7 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain) { - qboolean has_alpha; - return R_SkinFrame_LoadExternal_CheckAlpha(name, textureflags, complain, &has_alpha); + return R_SkinFrame_LoadExternal_CheckAlpha(name, textureflags, complain, NULL); } static rtexture_t *R_SkinFrame_TextureForSkinLayer(const unsigned char *in, int width, int height, const char *name, const unsigned int *palette, int textureflags, qboolean force) @@ -2715,8 +2723,8 @@ void gl_main_start(void) r_maxqueries = 0; memset(r_queries, 0, sizeof(r_queries)); - memset(r_qwskincache, 0, sizeof(r_qwskincache)); - memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe)); + r_qwskincache = NULL; + r_qwskincache_size = 0; // set up r_skinframe loading system for textures memset(&r_skinframe, 0, sizeof(r_skinframe)); @@ -2753,8 +2761,8 @@ void gl_main_shutdown(void) r_maxqueries = 0; memset(r_queries, 0, sizeof(r_queries)); - memset(r_qwskincache, 0, sizeof(r_qwskincache)); - memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe)); + r_qwskincache = NULL; + r_qwskincache_size = 0; // clear out the r_skinframe state Mem_ExpandableArray_FreeArray(&r_skinframe.array); @@ -2785,6 +2793,10 @@ void gl_main_newmap(void) // FIXME: move this code to client int l; char *entities, entname[MAX_QPATH]; + if (r_qwskincache) + Mem_Free(r_qwskincache); + r_qwskincache = NULL; + r_qwskincache_size = 0; if (cl.worldmodel) { strlcpy(entname, cl.worldmodel->name, sizeof(entname)); @@ -5413,6 +5425,33 @@ void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *t Matrix4x4_Concat(texmatrix, &matrix, &temp); } +void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname) +{ + int textureflags = TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP | TEXF_COMPRESS; + char name[MAX_QPATH]; + skinframe_t *skinframe; + unsigned char pixels[296*194]; + strlcpy(cache->name, skinname, sizeof(cache->name)); + dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name); + if (developer_loading.integer) + Con_Printf("loading %s\n", name); + skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false); + if (!skinframe || !skinframe->base) + { + unsigned char *f; + fs_offset_t filesize; + skinframe = NULL; + f = FS_LoadFile(name, tempmempool, true, &filesize); + if (f) + { + if (LoadPCX_QWSkin(f, filesize, pixels, 296, 194)) + skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height); + Mem_Free(f); + } + } + cache->skinframe = skinframe; +} + texture_t *R_GetCurrentTexture(texture_t *t) { int i; @@ -5455,14 +5494,16 @@ texture_t *R_GetCurrentTexture(texture_t *t) // update currentskinframe to be a qw skin or animation frame if ((i = ent->entitynumber - 1) >= 0 && i < cl.maxclients && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[i].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) { - if (strcmp(r_qwskincache[i], cl.scores[i].qw_skin)) + if (!r_qwskincache || r_qwskincache_size != cl.maxclients) { - strlcpy(r_qwskincache[i], cl.scores[i].qw_skin, sizeof(r_qwskincache[i])); - if (developer_loading.integer) - Con_Printf("loading skins/%s\n", r_qwskincache[i]); - r_qwskincache_skinframe[i] = R_SkinFrame_LoadExternal(va("skins/%s", r_qwskincache[i]), TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP | TEXF_COMPRESS, developer.integer > 0); + r_qwskincache_size = cl.maxclients; + if (r_qwskincache) + Mem_Free(r_qwskincache); + r_qwskincache = Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size); } - t->currentskinframe = r_qwskincache_skinframe[i]; + if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin)) + R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin); + t->currentskinframe = r_qwskincache[i].skinframe; if (t->currentskinframe == NULL) t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->shadertime)) % t->numskinframes]; } diff --git a/image.c b/image.c index d5123408..968fabf6 100644 --- a/image.c +++ b/image.c @@ -248,7 +248,6 @@ unsigned char* LoadPCX_BGRA (const unsigned char *f, int filesize) else a[x++] = dataByte; } - fin += pcx.bytes_per_line - image_width; // the number of bytes per line is always forced to an even number while(x < image_width) a[x++] = 0; } @@ -268,6 +267,85 @@ unsigned char* LoadPCX_BGRA (const unsigned char *f, int filesize) return image_buffer; } +/* +============ +LoadPCX +============ +*/ +qboolean LoadPCX_QWSkin(const unsigned char *f, int filesize, unsigned char *pixels, int outwidth, int outheight) +{ + pcx_t pcx; + unsigned char *a; + const unsigned char *fin, *enddata; + int x, y, x2, dataByte, pcxwidth, pcxheight; + + if (filesize < (int)sizeof(pcx) + 768) + return false; + + image_width = outwidth; + image_height = outheight; + fin = f; + + memcpy(&pcx, fin, sizeof(pcx)); + fin += sizeof(pcx); + + // LordHavoc: big-endian support ported from QF newtree + pcx.xmax = LittleShort (pcx.xmax); + pcx.xmin = LittleShort (pcx.xmin); + pcx.ymax = LittleShort (pcx.ymax); + pcx.ymin = LittleShort (pcx.ymin); + pcx.hres = LittleShort (pcx.hres); + pcx.vres = LittleShort (pcx.vres); + pcx.bytes_per_line = LittleShort (pcx.bytes_per_line); + pcx.palette_type = LittleShort (pcx.palette_type); + + pcxwidth = pcx.xmax + 1 - pcx.xmin; + pcxheight = pcx.ymax + 1 - pcx.ymin; + if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 || pcx.bits_per_pixel != 8 || pcxwidth > 4096 || pcxheight > 4096 || pcxwidth <= 0 || pcxheight <= 0) + return false; + + enddata = f + filesize - 768; + + for (y = 0;y < outheight && fin < enddata;y++) + { + a = pixels + y * outwidth; + // pad the output with blank lines if needed + if (y >= pcxheight) + { + memset(a, 0, outwidth); + continue; + } + for (x = 0;x < pcxwidth;) + { + if (fin >= enddata) + return false; + dataByte = *fin++; + if(dataByte >= 0xC0) + { + x2 = x + (dataByte & 0x3F); + if (fin >= enddata) + return false; + if (x2 > pcxwidth) + return false; + dataByte = *fin++; + for (;x < x2;x++) + if (x < outwidth) + a[x] = dataByte; + } + else + { + if (x < outwidth) // truncate to destination width + a[x] = dataByte; + x++; + } + } + while(x < outwidth) + a[x++] = 0; + } + + return true; +} + /* ========================================================= diff --git a/image.h b/image.h index 98358124..a8f25a15 100644 --- a/image.h +++ b/image.h @@ -26,6 +26,9 @@ unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize); // loads a texture, as pixel data unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qboolean allowFixtrans); +// loads an 8bit pcx image into a 296x194x8bit buffer, with cropping as needed +qboolean LoadPCX_QWSkin(const unsigned char *f, int filesize, unsigned char *pixels, int outwidth, int outheight); + // loads a texture, as a texture rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans);