diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 6b59fad94..0a53a0f88 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -3471,6 +3471,7 @@ void CL_LinkPacketEntities (void) else if (state->colormap > 0 && state->colormap <= cl.allocated_client_slots) { ent->playerindex = state->colormap-1; + ent->h2playerclass = cl.players[ent->playerindex].h2playerclass; ent->topcolour = cl.players[ent->playerindex].ttopcolor; ent->bottomcolour = cl.players[ent->playerindex].tbottomcolor; } @@ -4697,6 +4698,10 @@ void CL_LinkViewModel(void) plnum = r_refdef.playerview->playernum; plstate = &cl.inframes[parsecountmod].playerstate[plnum]; +/* ent.topcolour = TOP_DEFAULT;//cl.players[plnum].ttopcolor; + ent.bottomcolour = cl.players[plnum].tbottomcolor; + ent.h2playerclass = cl.players[plnum].h2playerclass; +*/ CLQ1_AddPowerupShell(V_AddEntity(&ent), true, plstate?plstate->effects:0); if (alpha < 1 && qrenderer == QR_OPENGL) diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 9d69215b4..7ee6585f5 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -1550,7 +1550,7 @@ void CL_SendCmd (double frametime, qboolean mainloop) CL_ProxyMenuHooks(); - if (cls.demoplayback != DPB_NONE || !cls.state) + if (cls.demoplayback != DPB_NONE || cls.state <= ca_demostart) { cursor_active = false; if (!cls.state || cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 341508aab..889daeb15 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1625,9 +1625,13 @@ void CL_Color_f (void) if (Cmd_Argc() == 1) { - Con_TPrintf ("\"color\" is \"%s %s\"\n", - Info_ValueForKey (cls.userinfo[pnum], "topcolor"), - Info_ValueForKey (cls.userinfo[pnum], "bottomcolor") ); + char *t = Info_ValueForKey (cls.userinfo[pnum], "topcolor"); + char *b = Info_ValueForKey (cls.userinfo[pnum], "bottomcolor"); + if (!*t) + t = "0"; + if (!*b) + b = "0"; + Con_TPrintf ("\"color\" is \"%s %s\"\n", t, b); Con_TPrintf ("usage: color <0xRRGGBB> [0xRRGGBB]\n"); return; } @@ -3880,10 +3884,11 @@ void Host_RunFileNotify(struct dl_download *dl) #define HRF_MANIFEST (1<<13) #define HRF_BSP (1<<14) #define HRF_PACKAGE (1<<15) +#define HRF_MODEL (1<<16) #define HRF_ACTION (HRF_OVERWRITE|HRF_NOOVERWRITE|HRF_ABORT) #define HRF_DEMO (HRF_DEMO_MVD|HRF_DEMO_QWD|HRF_DEMO_DM2|HRF_DEMO_DEM) -#define HRF_FILETYPES (HRF_DEMO|HRF_QTVINFO|HRF_MANIFEST|HRF_BSP|HRF_PACKAGE) +#define HRF_FILETYPES (HRF_DEMO|HRF_QTVINFO|HRF_MANIFEST|HRF_BSP|HRF_PACKAGE|HRF_MODEL) typedef struct { unsigned int flags; vfsfile_t *srcfile; @@ -4024,6 +4029,8 @@ static qboolean isurl(char *url) return /*!strncmp(url, "data:", 5) || */!strncmp(url, "http://", 7) || !strncmp(url, "https://", 8); } +qboolean FS_FixupGamedirForExternalFile(char *input, char *filename, size_t fnamelen); + void Host_DoRunFile(hrf_t *f) { char qname[MAX_QPATH]; @@ -4078,22 +4085,25 @@ void Host_DoRunFile(hrf_t *f) //if we get here, we have no mime type to give us any clues. COM_FileExtension(f->fname, ext, sizeof(ext)); - if (!strcmp(ext, "qwd")) + if (!Q_strcasecmp(ext, "qwd")) f->flags |= HRF_DEMO_QWD; - else if (!strcmp(ext, "mvd")) + else if (!Q_strcasecmp(ext, "mvd")) f->flags |= HRF_DEMO_MVD; - else if (!strcmp(ext, "dm2")) + else if (!Q_strcasecmp(ext, "dm2")) f->flags |= HRF_DEMO_DM2; - else if (!strcmp(ext, "dem")) + else if (!Q_strcasecmp(ext, "dem")) f->flags |= HRF_DEMO_DEM; - else if (!strcmp(ext, "qtv")) + else if (!Q_strcasecmp(ext, "qtv")) f->flags |= HRF_QTVINFO; - else if (!strcmp(ext, "fmf")) + else if (!Q_strcasecmp(ext, "fmf")) f->flags |= HRF_MANIFEST; - else if (!strcmp(ext, "bsp")) + else if (!Q_strcasecmp(ext, "bsp")) f->flags |= HRF_BSP; - else if (!strcmp(ext, "pak") || !strcmp(ext, "pk3")) + else if (!Q_strcasecmp(ext, "pak") || !Q_strcasecmp(ext, "pk3") || !Q_strcasecmp(ext, "pk4") || !Q_strcasecmp(ext, "wad")) f->flags |= HRF_PACKAGE; + else if (!Q_strcasecmp(ext, "mdl") || !Q_strcasecmp(ext, "md2") || !Q_strcasecmp(ext, "md3") || !Q_strcasecmp(ext, "iqm") + || !Q_strcasecmp(ext, "psk") || !Q_strcasecmp(ext, "zym") || !Q_strcasecmp(ext, "dpm") || !Q_strcasecmp(ext, "spr") || !Q_strcasecmp(ext, "spr2")) + f->flags |= HRF_MODEL; //if we still don't know what it is, give up. if (!(f->flags & HRF_FILETYPES)) @@ -4111,7 +4121,8 @@ void Host_DoRunFile(hrf_t *f) if (f->flags & HRF_DEMO) { //play directly via system path, no prompts needed - Cbuf_AddText(va("playdemo \"#%s\"\n", f->fname), RESTRICT_LOCAL); + FS_FixupGamedirForExternalFile(f->fname, loadcommand, sizeof(loadcommand)); + Cbuf_AddText(va("playdemo \"%s\"\n", loadcommand), RESTRICT_LOCAL); f->flags |= HRF_ABORT; Host_DoRunFile(f); @@ -4121,9 +4132,18 @@ void Host_DoRunFile(hrf_t *f) { char shortname[MAX_QPATH]; COM_StripExtension(COM_SkipPath(f->fname), shortname, sizeof(shortname)); - snprintf(qname, sizeof(qname), "maps/%s.bsp", shortname); + if (FS_FixupGamedirForExternalFile(f->fname, qname, sizeof(qname)) && !Q_strncasecmp(qname, "maps/", 5)) + { + COM_StripExtension(qname+5, loadcommand, sizeof(loadcommand)); + Cbuf_AddText(va("map \"%s\"\n", loadcommand), RESTRICT_LOCAL); + f->flags |= HRF_ABORT; + Host_DoRunFile(f); + return; + } + snprintf(loadcommand, sizeof(loadcommand), "map \"%s\"\n", shortname); snprintf(displayname, sizeof(displayname), "map: %s", shortname); + snprintf(qname, sizeof(qname), "maps/%s.bsp", shortname); } else if (f->flags & HRF_PACKAGE) { @@ -4175,6 +4195,14 @@ void Host_DoRunFile(hrf_t *f) } } } + else if (f->flags & HRF_MODEL) + { + FS_FixupGamedirForExternalFile(f->fname, loadcommand, sizeof(loadcommand)); + Cbuf_AddText(va("modelviewer \"%s\"\n", loadcommand), RESTRICT_LOCAL); + f->flags |= HRF_ABORT; + Host_DoRunFile(f); + return; + } else if (!(f->flags & HRF_QTVINFO)) { Con_Printf("Host_DoRunFile: filetype not handled\n"); diff --git a/engine/client/image.c b/engine/client/image.c index b701ce73a..d5566eaaf 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -1,5 +1,5 @@ #include "quakedef.h" -#include "glquake.h" +#include "shader.h" //FIXME texid_t GL_FindTextureFallback (const char *identifier, unsigned int flags, void *fallback, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt); @@ -2743,7 +2743,7 @@ static struct {2, "override/%s%s", 1} /*tenebrae compatibility*/ }; -static void Image_MipMap (qbyte *in, int inwidth, int inheight, qbyte *out, int outwidth, int outheight) +static void Image_MipMap8888 (qbyte *in, int inwidth, int inheight, qbyte *out, int outwidth, int outheight) { int i, j; qbyte *inrow; @@ -2806,37 +2806,40 @@ static void Image_GenerateMips(struct pendingtextureinfo *mips, unsigned int fla if (mips->type != PTI_2D) return; //blurgh + if (flags & IF_NOMIPMAP) + return; + switch(mips->encoding) { case PTI_RGBA8: case PTI_RGBX8: case PTI_BGRA8: case PTI_BGRX8: + for (mip = 1; mip < 32; mip++) + { + mips->mip[mip].width = mips->mip[mip-1].width >> 1; + mips->mip[mip].height = mips->mip[mip-1].height >> 1; + if (mips->mip[mip].width < 1 && mips->mip[mip].height < 1) + break; + if (mips->mip[mip].width < 1) + mips->mip[mip].width = 1; + if (mips->mip[mip].height < 1) + mips->mip[mip].height = 1; + mips->mip[mip].datasize = ((mips->mip[mip].width+3)&~3) * mips->mip[mip].height*4; + mips->mip[mip].data = BZ_Malloc(mips->mip[mip].datasize); + mips->mip[mip].needfree = true; + + Image_MipMap8888(mips->mip[mip-1].data, mips->mip[mip-1].width, mips->mip[mip-1].height, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height); + mips->mipcount = mip+1; + } break; + case PTI_RGBA4444: + case PTI_RGB565: + case PTI_RGBA5551: + return; //convert to 16bit afterwards. always mipmap at 8 bit, to try to preserve what little precision there is. default: return; //not supported. } - - if (flags & IF_NOMIPMAP) - return; - - for (mip = 1; mip < 32; mip++) - { - mips->mip[mip].width = mips->mip[mip-1].width >> 1; - mips->mip[mip].height = mips->mip[mip-1].height >> 1; - if (mips->mip[mip].width < 1 && mips->mip[mip].height < 1) - break; - if (mips->mip[mip].width < 1) - mips->mip[mip].width = 1; - if (mips->mip[mip].height < 1) - mips->mip[mip].height = 1; - mips->mip[mip].datasize = ((mips->mip[mip].width+3)&~3) * mips->mip[mip].height*4; - mips->mip[mip].data = BZ_Malloc(mips->mip[mip].datasize); - mips->mip[mip].needfree = true; - - Image_MipMap(mips->mip[mip-1].data, mips->mip[mip-1].width, mips->mip[mip-1].height, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height); - mips->mipcount = mip+1; - } } //stolen from DP @@ -3071,12 +3074,12 @@ static unsigned int * Image_GenerateNormalMap(qbyte *pixels, unsigned int *nmap, static void Image_RoundDimensions(int *scaled_width, int *scaled_height, unsigned int flags) { - if (r_config.texture_non_power_of_two) //NPOT is a simple extension that relaxes errors. + if (sh_config.texture_non_power_of_two) //NPOT is a simple extension that relaxes errors. { //lax form TRACE(("dbg: GL_RoundDimensions: GL_ARB_texture_non_power_of_two\n")); } - else if ((flags & IF_CLAMP) && (flags & IF_NOMIPMAP) && r_config.texture_non_power_of_two_pic) + else if ((flags & IF_CLAMP) && (flags & IF_NOMIPMAP) && sh_config.texture_non_power_of_two_pic) { //more strict form TRACE(("dbg: GL_RoundDimensions: GL_OES_texture_npot\n")); @@ -3091,7 +3094,7 @@ static void Image_RoundDimensions(int *scaled_width, int *scaled_height, unsigne ; /*round npot textures down if we're running on an embedded system*/ - if (r_config.npot_rounddown) + if (sh_config.npot_rounddown) { if (*scaled_width != width) *scaled_width >>= 1; @@ -3114,12 +3117,12 @@ static void Image_RoundDimensions(int *scaled_width, int *scaled_height, unsigne TRACE(("dbg: GL_RoundDimensions: %f\n", gl_max_size.value)); - if (r_config.maxtexturesize) + if (sh_config.texture_maxsize) { - if (*scaled_width > r_config.maxtexturesize) - *scaled_width = r_config.maxtexturesize; - if (*scaled_height > r_config.maxtexturesize) - *scaled_height = r_config.maxtexturesize; + if (*scaled_width > sh_config.texture_maxsize) + *scaled_width = sh_config.texture_maxsize; + if (*scaled_height > sh_config.texture_maxsize) + *scaled_height = sh_config.texture_maxsize; } if (!(flags & IF_UIPIC)) { @@ -3138,6 +3141,221 @@ static void Image_RoundDimensions(int *scaled_width, int *scaled_height, unsigne *scaled_height = 1; } +//may operate in place +static void Image_8888to565(qbyte *in, unsigned short *out, unsigned int w, unsigned int h, qboolean bgra) +{ + unsigned int p = w*h; + unsigned short tmp; + + if (bgra) + { + while(p-->0) + { + tmp = ((*in++>>3) << 0);//b + tmp |= ((*in++>>2) << 5);//g + tmp |= ((*in++>>3) << 11);//r + in++; + *out++ = tmp; + } + } + else + { + while(p-->0) + { + tmp = ((*in++>>3) << 11);//r + tmp |= ((*in++>>2) << 5);//g + tmp |= ((*in++>>3) << 0);//b + in++; + *out++ = tmp; + } + } +} +//may operate in place +static void Image_8888to1555(qbyte *in, unsigned short *out, unsigned int w, unsigned int h, qboolean bgra) +{ + unsigned int p = w*h; + unsigned short tmp; + if (bgra) + { + while(p-->0) + { + tmp = ((*in++>>3) << 0);//b + tmp |= ((*in++>>3) << 5);//g + tmp |= ((*in++>>3) << 10);//r + tmp |= ((*in++>>7) << 15);//a + *out++ = tmp; + } + } + else + { + while(p-->0) + { + tmp = ((*in++>>3) << 10);//r + tmp |= ((*in++>>3) << 5);//g + tmp |= ((*in++>>3) << 0);//b + tmp |= ((*in++>>7) << 15);//a + *out++ = tmp; + } + } +} +//may operate in place +static void Image_8888to5551(qbyte *in, unsigned short *out, unsigned int w, unsigned int h, qboolean bgra) +{ + unsigned int p = w*h; + unsigned short tmp; + if (bgra) + { + while(p-->0) + { + tmp = ((*in++>>3) << 1);//b + tmp |= ((*in++>>3) << 6);//g + tmp |= ((*in++>>3) << 11);//r + tmp |= ((*in++>>7) << 0);//a + *out++ = tmp; + } + } + else + { + while(p-->0) + { + tmp = ((*in++>>3) << 11);//r + tmp |= ((*in++>>3) << 6);//g + tmp |= ((*in++>>3) << 1);//b + tmp |= ((*in++>>7) << 0);//a + *out++ = tmp; + } + } +} +//may operate in place +static void Image_8888to4444(qbyte *in, unsigned short *out, unsigned int w, unsigned int h, qboolean bgra) +{ + unsigned int p = w*h; + unsigned short tmp; + + if (bgra) + { + while(p-->0) + { + tmp = ((*in++>>4) << 4);//b + tmp |= ((*in++>>4) << 8);//g + tmp |= ((*in++>>4) << 12);//r + tmp |= ((*in++>>4) << 0);//a + *out++ = tmp; + } + } + else + { + while(p-->0) + { + tmp = ((*in++>>4) << 12);//r + tmp |= ((*in++>>4) << 8);//g + tmp |= ((*in++>>4) << 4);//b + tmp |= ((*in++>>4) << 0);//a + *out++ = tmp; + } + } +} +//may operate in place +static void Image_8888toARGB4444(qbyte *in, unsigned short *out, unsigned int w, unsigned int h, qboolean bgra) +{ + unsigned int p = w*h; + unsigned short tmp; + + if (bgra) + { + while(p-->0) + { + tmp = ((*in++>>4) << 0);//b + tmp |= ((*in++>>4) << 4);//g + tmp |= ((*in++>>4) << 8);//r + tmp |= ((*in++>>4) << 12);//a + *out++ = tmp; + } + } + else + { + while(p-->0) + { + tmp = ((*in++>>4) << 8);//r + tmp |= ((*in++>>4) << 4);//g + tmp |= ((*in++>>4) << 0);//b + tmp |= ((*in++>>4) << 12);//a + *out++ = tmp; + } + } +} + +static void Image_ChangeFormat(struct pendingtextureinfo *mips, uploadfmt_t origfmt) +{ + int mip; + + if (mips->type != PTI_2D) + return; //blurgh + + //if that format isn't supported/desired, try converting it. + if (sh_config.texfmt[PTI_RGBX8]) + return; + + //should we just use 5551 always? + if (mips->encoding == PTI_RGBX8 || mips->encoding == PTI_BGRX8) + { + /*if (0) + { //prevent discolouration. + if (sh_config.texfmt[PTI_RGBA5551]) + { + for (mip = 0; mip < mips->mipcount; mip++) + Image_8888to5551(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRX8); + mips->encoding = PTI_RGBA5551; + } + else + { + for (mip = 0; mip < mips->mipcount; mip++) + Image_8888to1555(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRX8); + mips->encoding = PTI_ARGB1555; + } + } + else*/ + { + for (mip = 0; mip < mips->mipcount; mip++) + Image_8888to565(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRX8); + mips->encoding = PTI_RGB565; + } + } + else if (mips->encoding == PTI_RGBA8 || mips->encoding == PTI_BGRA8) + { + if (origfmt == TF_TRANS8 || origfmt == TF_TRANS8_FULLBRIGHT || origfmt == TF_H2_TRANS8_0 || !(sh_config.texfmt[PTI_RGBA4444] || sh_config.texfmt[PTI_ARGB4444])) + { //1-bit alpha is okay for these textures. + if (sh_config.texfmt[PTI_RGBA5551]) + { + for (mip = 0; mip < mips->mipcount; mip++) + Image_8888to5551(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRA8); + mips->encoding = PTI_RGBA5551; + } + else + { + for (mip = 0; mip < mips->mipcount; mip++) + Image_8888to1555(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRA8); + mips->encoding = PTI_ARGB1555; + } + } + else + { + if (sh_config.texfmt[PTI_RGBA4444]) + { + for (mip = 0; mip < mips->mipcount; mip++) + Image_8888to4444(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRA8); + mips->encoding = PTI_RGBA4444; + } + else + { + for (mip = 0; mip < mips->mipcount; mip++) + Image_8888toARGB4444(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRA8); + mips->encoding = PTI_ARGB4444; + } + } + } +} + //resamples and depalettes as required static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flags, void *rawdata, void *palettedata, int imgwidth, int imgheight, uploadfmt_t fmt, qboolean freedata) { @@ -3169,27 +3387,17 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag mips->encoding = PTI_BGRA8; break; case TF_SOLID8: - mips->encoding = PTI_RGBX8; rgbadata = BZ_Malloc(imgwidth * imgheight*4); - for (i = 0; i < imgwidth * imgheight; i++) - { - rgbadata[i] = d_8to24rgbtable[((qbyte*)rawdata)[i]]; + if (sh_config.texfmt[PTI_BGRX8]) + { //bgra8 is typically faster when supported. + mips->encoding = PTI_BGRX8; + for (i = 0; i < imgwidth * imgheight; i++) + rgbadata[i] = d_8to24bgrtable[((qbyte*)rawdata)[i]]; } - if (freedata) - BZ_Free(rawdata); - freedata = true; - break; - case TF_H2_TRANS8_0: - mips->encoding = PTI_RGBX8; - rgbadata = BZ_Malloc(imgwidth * imgheight*4); - for (i = 0; i < imgwidth * imgheight; i++) + else { - if (((qbyte*)rawdata)[i] == 0) - { - rgbadata[i] = 0; - mips->encoding = PTI_RGBA8; - } - else + mips->encoding = PTI_RGBX8; + for (i = 0; i < imgwidth * imgheight; i++) rgbadata[i] = d_8to24rgbtable[((qbyte*)rawdata)[i]]; } if (freedata) @@ -3197,21 +3405,25 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag freedata = true; break; case TF_TRANS8: - mips->encoding = PTI_RGBX8; - rgbadata = BZ_Malloc(imgwidth * imgheight*4); - for (i = 0; i < imgwidth * imgheight; i++) + case TF_H2_TRANS8_0: { - if (((qbyte*)rawdata)[i] == 0xff) + qbyte ref = (fmt==TF_H2_TRANS8_0)?0:0xff; + mips->encoding = PTI_RGBX8; + rgbadata = BZ_Malloc(imgwidth * imgheight*4); + for (i = 0; i < imgwidth * imgheight; i++) { - rgbadata[i] = 0; - mips->encoding = PTI_RGBA8; + if (((qbyte*)rawdata)[i] == ref) + {//fixme: blend non-0xff neighbours. no, just use premultiplied alpha instead, where it matters. + rgbadata[i] = 0; + mips->encoding = PTI_RGBA8; + } + else + rgbadata[i] = d_8to24rgbtable[((qbyte*)rawdata)[i]]; } - else - rgbadata[i] = d_8to24rgbtable[((qbyte*)rawdata)[i]]; + if (freedata) + BZ_Free(rawdata); + freedata = true; } - if (freedata) - BZ_Free(rawdata); - freedata = true; break; case TF_TRANS8_FULLBRIGHT: mips->encoding = PTI_RGBA8; @@ -3289,6 +3501,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag freedata = true; break; +#ifdef HEXEN2 case TF_H2_T7G1: /*8bit data, odd indexes give greyscale transparence*/ mips->encoding = PTI_RGBA8; rgbadata = BZ_Malloc(imgwidth * imgheight*4); @@ -3307,8 +3520,22 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag BZ_Free(rawdata); freedata = true; break; -// case TF_H2_T4A4: /*8bit data, weird packing*/ -// break; + case TF_H2_T4A4: /*8bit data, weird packing*/ + mips->encoding = PTI_RGBA8; + rgbadata = BZ_Malloc(imgwidth * imgheight*4); + for (i = 0; i < imgwidth * imgheight; i++) + { + static const int ColorIndex[16] = {0, 31, 47, 63, 79, 95, 111, 127, 143, 159, 175, 191, 199, 207, 223, 231}; + static const unsigned ColorPercent[16] = {25, 51, 76, 102, 114, 127, 140, 153, 165, 178, 191, 204, 216, 229, 237, 247}; + qbyte p = ((qbyte*)rawdata)[i]; + rgbadata[i] = d_8to24rgbtable[ColorIndex[p>>4]] & 0x00ffffff; + rgbadata[i] |= ( int )ColorPercent[p&15] << 24; + } + if (freedata) + BZ_Free(rawdata); + freedata = true; + break; +#endif } if (flags & IF_NOALPHA) @@ -3321,15 +3548,24 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag case PTI_BGRA8: mips->encoding = PTI_RGBX8; break; + case PTI_RGBA4444: + case PTI_RGBA5551: + break; //erk case PTI_S3RGBA1: //mostly compatible, but I don't want to push it. case PTI_S3RGBA3: case PTI_S3RGBA5: //erk. meh. break; + case PTI_RGB565: case PTI_RGBX8: case PTI_BGRX8: case PTI_S3RGB1: break; + case PTI_DEPTH16: + case PTI_DEPTH24: + case PTI_DEPTH32: + case PTI_DEPTH24_8: + break; } //FIXME: fill alpha channel with 255? } @@ -3400,6 +3636,7 @@ static qboolean Image_LoadRawTexture(texid_t tex, unsigned int flags, void *rawd return false; } Image_GenerateMips(mips, flags); + Image_ChangeFormat(mips, fmt); tex->width = imgwidth; tex->height = imgheight; @@ -3756,7 +3993,7 @@ void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t b) /*still failed? attempt to load quake lmp files, which have no real format id (hence why they're not above)*/ Q_strncpyz(fname, nicename, sizeof(fname)); COM_DefaultExtension(fname, ".lmp", sizeof(fname)); - if ((buf = COM_LoadFile (fname, 5, &fsize))) + if (!(tex->flags & IF_NOPCX) && (buf = COM_LoadFile (fname, 5, &fsize))) { if (Image_LoadTextureFromMemory(tex, tex->flags, nicename, fname, buf, fsize)) return; @@ -3875,13 +4112,17 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned tex = Image_FindTexture(identifier, subpath, flags); if (tex) { + if (!fallbackdata || tex->status != TEX_FAILED) + { #ifdef LOADERTHREAD - Sys_UnlockMutex(com_resourcemutex); + Sys_UnlockMutex(com_resourcemutex); #endif - return tex; //already exists + return tex; //already exists + } + tex->flags = flags; } - - tex = Image_CreateTexture_Internal(identifier, subpath, flags); + else + tex = Image_CreateTexture_Internal(identifier, subpath, flags); tex->status = TEX_LOADING; if (fallbackdata) @@ -3950,6 +4191,8 @@ void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, in mips.type = (flags & IF_3DMAP)?PTI_3D:PTI_2D; if (!Image_GenMip0(&mips, flags, data, palette, width, height, fmt, false)) return; + Image_GenerateMips(&mips, flags); + Image_ChangeFormat(&mips, fmt); rf->IMG_LoadTextureMips(tex, &mips); tex->status = TEX_LOADED; } diff --git a/engine/client/input.h b/engine/client/input.h index bb21ae92a..6ca3e300c 100644 --- a/engine/client/input.h +++ b/engine/client/input.h @@ -47,6 +47,7 @@ int CL_TargettedSplit(qboolean nowrap); //specific events for the system-specific input code to call. may be called outside the main thread (so long as you don't call these simultaneously - ie: use a mutex or only one input thread). void IN_KeyEvent(int devid, int down, int keycode, int unicode); //don't use IN_KeyEvent for mice if you ever use abs mice... void IN_MouseMove(int devid, int abs, float x, float y, float z, float size); +void IN_JoystickAxisEvent(int devid, int axis, float value); //system-specific functions void INS_Move (float *movements, int pnum); diff --git a/engine/client/m_items.c b/engine/client/m_items.c index 97fa480fc..5435f0c04 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -90,27 +90,60 @@ menu_t *currentmenu; menu_t *firstmenu; menuoption_t *M_NextSelectableItem(menu_t *m, menuoption_t *old); +#ifdef HEXEN2 +//this function is so fucked up. +//firstly, the source image uses 0 for transparent instead of 255. this means we need special handling. *sigh*. +//secondly we have to avoid sampling too much of the image, because i chars seem to have stray white pixels in them +//thirdly, we hard-code (by eye) the space between chars, which should be different for any character pair. +//but we're lazy so we don't consider the next char. italic fonts are annoying like that. feel free to refudge it. void Draw_Hexen2BigFontString(int x, int y, const char *text) { + int c; int sx, sy; mpic_t *p; - unsigned int hack; //FIXME: threads can't cope - hack = d_8to24rgbtable[0]; - d_8to24rgbtable[0] = 0; - p = R2D_SafeCachePic ("gfx/menu/bigfont.lmp"); - d_8to24rgbtable[0] = hack; + p = R_RegisterShader ("gfx/menu/bigfont.lmp", SUF_2D, + "{\n" + "if $nofixed\n" + "program default2d\n" + "endif\n" + "affine\n" + "nomipmaps\n" + "{\n" + "clampmap $diffuse\n" + "rgbgen vertex\n" + "alphagen vertex\n" + "blendfunc gl_one gl_one_minus_src_alpha\n" + "}\n" + "sort additive\n" + "}\n"); + if (!p->defaulttextures.base) + { + void *file; + qofs_t fsize = FS_LoadFile("gfx/menu/bigfont.lmp", &file); + if (file) + { + unsigned int w = ((unsigned int*)file)[0]; + unsigned int h = ((unsigned int*)file)[1]; + p->defaulttextures.base = R_LoadReplacementTexture("gfx/menu/bigfont.lmp", NULL, IF_NOPCX|IF_PREMULTIPLYALPHA|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP, (qbyte*)file+8, w, h, TF_H2_TRANS8_0); + FS_FreeFile(file); //got image data + } + else + p->defaulttextures.base = R_LoadHiResTexture("gfx/menu/bigfont.lmp", NULL, IF_PREMULTIPLYALPHA|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP); + } while(*text) { - if (*text >= 'a' && *text <= 'z') + c = *text++; + if (c >= 'a' && c <= 'z') { - sx = ((*text-'a')%8)*20; - sy = ((*text-'a')/8)*20; + sx = ((c-'a')%8)*20; + sy = ((c-'a')/8)*20; } - else if (*text >= 'A' && *text <= 'Z') + else if (c >= 'A' && c <= 'Z') { - sx = ((*text-'A')%8)*20; - sy = ((*text-'A')/8)*20; + c = c - 'A' + 'a'; + sx = ((c-'a')%8)*20; + sy = ((c-'a')/8)*20; } else// if (*text <= ' ') { @@ -118,11 +151,41 @@ void Draw_Hexen2BigFontString(int x, int y, const char *text) sy=-1; } if(sx>=0) - R2D_SubPic(x, y, 20, 20, p, sx, sy, 20*8, 20*4); - x+=20; - text++; + R2D_SubPic(x, y, 18, 20, p, sx, sy, 20*8, 20*4); + + switch(c) + { + case 'a': x+=15; break; + case 'b': x+=15; break; + case 'c': x+=15; break; + case 'd': x+=15; break; + case 'e': x+=15; break; + case 'f': x+=15; break; + case 'g': x+=15; break; + case 'h': x+=15; break; + case 'i': x+=10; break; + case 'j': x+=15; break; + case 'k': x+=18; break; + case 'l': x+=15; break; + case 'm': x+=18; break; + case 'n': x+=15; break; + case 'o': x+=15; break; + case 'p': x+=15; break; + case 'q': x+=18; break; + case 'r': x+=18; break; + case 's': x+=13; break; + case 't': x+=15; break; + case 'u': x+=15; break; + case 'v': x+=12; break; + case 'w': x+=15; break; + case 'x': x+=18; break; + case 'y': x+=15; break; + case 'z': x+=18; break; + default: x+=20; break; + } } } +#endif mpic_t *QBigFontWorks(void) { diff --git a/engine/client/m_multi.c b/engine/client/m_multi.c index 7efaa459f..8f2526a0f 100644 --- a/engine/client/m_multi.c +++ b/engine/client/m_multi.c @@ -123,14 +123,15 @@ typedef struct { int ticlass; #endif menucombo_t *modeledit; - int topcolour; - int lowercolour; + unsigned int topcolour; + unsigned int lowercolour; int tiwidth, tiheight; qbyte translationimage[128*128]; } setupmenu_t; qboolean ApplySetupMenu (union menuoption_s *option,struct menu_s *menu, int key) { + char bot[64], top[64]; setupmenu_t *info = menu->data; if (key != K_ENTER && key != K_KP_ENTER) return false; @@ -142,52 +143,130 @@ qboolean ApplySetupMenu (union menuoption_s *option,struct menu_s *menu, int key if (info->classedit) Cvar_SetValue(Cvar_FindVar("cl_playerclass"), info->classedit->selectedoption+1); #endif - Cbuf_AddText(va("color %i %i\n", info->lowercolour, info->topcolour), RESTRICT_LOCAL); + if (info->lowercolour >= 16) + Q_snprintfz(bot, sizeof(bot), "0x%x", info->lowercolour&0xffffff); + else + Q_snprintfz(bot, sizeof(bot), "%i", info->lowercolour); + if (info->topcolour >= 16) + Q_snprintfz(top, sizeof(top), "0x%x", info->topcolour&0xffffff); + else + Q_snprintfz(top, sizeof(top), "%i", info->topcolour); + Cbuf_AddText(va("color %s %s\n", bot, top), RESTRICT_LOCAL); S_LocalSound ("misc/menu2.wav"); M_RemoveMenu(menu); return true; } -qboolean SetupMenuColour (union menuoption_s *option,struct menu_s *menu, int key) -{ - setupmenu_t *info = menu->data; - if (*option->button.text == 'T') - { - if (key == K_ENTER || key == K_KP_ENTER || key == K_RIGHTARROW) - { - info->topcolour ++; - if (info->topcolour>=14) - info->topcolour=0; - S_LocalSound ("misc/menu2.wav"); - return true; - } - if (key == K_LEFTARROW) - { - info->topcolour --; - if (info->topcolour<=0) - info->topcolour=13; - S_LocalSound ("misc/menu2.wav"); - return true; - } +//http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c +static void rgbtohsv(unsigned int rgb, vec3_t result) +{ + int r = (rgb>>16)&0xff, g = (rgb>>8)&0xff, b = (rgb>>0)&0xff; + float maxc = max(r, max(g, b)), minc = min(r, min(g, b)); + float h, s, l = (maxc + minc) / 2; + + float d = maxc - minc; + if (maxc) + s = d / maxc; + else + s = 0; + + if(maxc == minc) + { + h = 0; // achromatic } else { - if (key == K_ENTER || key == K_KP_ENTER || key == K_RIGHTARROW) + if (maxc == r) + h = (g - b) / d + ((g < b) ? 6 : 0); + else if (maxc == g) + h = (b - r) / d + 2; + else + h = (r - g) / d + 4; + h /= 6; + } + + result[0] = h; + result[1] = s; + result[2] = l; +}; + +//http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c +static unsigned int hsvtorgb(float inh, float s, float v) +{ + int r, g, b; + float h = inh - (int)floor(inh); + int i = h * 6; + float f = h * 6 - i; + float p = v * (1 - s); + float q = v * (1 - f * s); + float t = v * (1 - (1 - f) * s); + switch(i) + { + default: + case 0: r = v*0xff, g = t*0xff, b = p*0xff; break; + case 1: r = q*0xff, g = v*0xff, b = p*0xff; break; + case 2: r = p*0xff, g = v*0xff, b = t*0xff; break; + case 3: r = p*0xff, g = q*0xff, b = v*0xff; break; + case 4: r = t*0xff, g = p*0xff, b = v*0xff; break; + case 5: r = v*0xff, g = p*0xff, b = q*0xff; break; + } + + return 0xff000000 | (r<<16)|(g<<8)|(b<<0); +}; + +qboolean SetupMenuColour (union menuoption_s *option,struct menu_s *menu, int key) +{ + extern qboolean keydown[K_MAX]; + setupmenu_t *info = menu->data; + unsigned int *ptr = (*option->button.text == 'T')?&info->topcolour:&info->lowercolour; + + //okay, this is a bit weird. + //fte supports rgb colours, but we only allow hue to be chosen via the menu (people picking pure black are annoying, also conversions and precisions limit us) + //for NQ compat, we stick to old-skool values (so we don't end up with far too many teams) + //but we give the top free reign. + //unless they hold shift, in which case it switches around + //this allows for whatever you want + if (key == K_ENTER || key == K_KP_ENTER || key == K_RIGHTARROW) + { + if ((keydown[K_LSHIFT] || keydown[K_RSHIFT]) ^ (ptr == &info->topcolour)) { - info->lowercolour ++; - if (info->lowercolour>=14) - info->lowercolour=0; - S_LocalSound ("misc/menu2.wav"); - return true; + vec3_t hsv; + rgbtohsv(*ptr, hsv); + *ptr = hsvtorgb(hsv[0]+1/128.0, 1, 1);//hsv[1], hsv[2]); } - if (key == K_LEFTARROW) + else { - info->lowercolour --; - if (info->lowercolour<=0) - info->lowercolour=13; - S_LocalSound ("misc/menu2.wav"); - return true; + if (*ptr >= 13 || *ptr >= 16) + *ptr = 0; + else + *ptr += 1; } + S_LocalSound ("misc/menu2.wav"); + return true; + } + if (key == K_DEL) + { + *ptr = 0; + S_LocalSound ("misc/menu2.wav"); + return true; + } + if (key == K_LEFTARROW) + { + if ((keydown[K_LSHIFT] || keydown[K_RSHIFT]) ^ (ptr == &info->topcolour)) + { + vec3_t hsv; + rgbtohsv(*ptr, hsv); + *ptr = hsvtorgb(hsv[0]-1/128.0, 1, 1);//hsv[1], hsv[2]); + } + else + { + if (*ptr==0 || *ptr >= 16) + *ptr=12; + else + *ptr -= 1; + } + S_LocalSound ("misc/menu2.wav"); + return true; } return false; } @@ -285,6 +364,7 @@ void MSetup_TransDraw (int x, int y, menucustom_t *option, menu_t *menu) mpic_t *p; void *f; qboolean reloadtimage = false; + unsigned int pc = 0; if (info->skinedit && info->skinedit->modified) { @@ -292,10 +372,14 @@ void MSetup_TransDraw (int x, int y, menucustom_t *option, menu_t *menu) reloadtimage = true; } #ifdef HEXEN2 - if (info->classedit && info->classedit->selectedoption != info->ticlass) + if (info->classedit) { - info->ticlass = info->classedit->selectedoption; - reloadtimage = true; + if (info->classedit->selectedoption != info->ticlass) + { + info->ticlass = info->classedit->selectedoption; + reloadtimage = true; + } + pc = info->ticlass+1; } #endif @@ -327,10 +411,10 @@ void MSetup_TransDraw (int x, int y, menucustom_t *option, menu_t *menu) R2D_ImageColours(1,1,1,1); p = R2D_SafeCachePic ("gfx/bigbox.lmp"); - if (p) + if (R_GetShaderSizes(p, NULL, NULL, false)>0) R2D_ScalePic (x-12, y-8, 72, 72, p); - M_BuildTranslationTable(info->topcolour, info->lowercolour, translationTable); + M_BuildTranslationTable(pc, info->topcolour, info->lowercolour, translationTable); R2D_TransPicTranslate (x, y, info->tiwidth, info->tiheight, info->translationimage, translationTable); } @@ -390,10 +474,6 @@ void M_Menu_Setup_f (void) menu = M_CreateMenu(sizeof(setupmenu_t)); info = menu->data; - MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp"); - MC_AddCenterPicture(menu, 4, 24, "gfx/p_multi.lmp"); - - // MC_AddPicture(menu, 72, 32, Draw_CachePic ("gfx/mp_menu.lmp") ); menu->selecteditem = (menuoption_t*) @@ -417,7 +497,12 @@ void M_Menu_Setup_f (void) } else #endif + { + MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp"); + MC_AddCenterPicture(menu, 4, 24, "gfx/p_multi.lmp"); + (info->skinedit = MC_AddEdit(menu, 64, 160, 72, "Your skin", skin.string)); + } ci = MC_AddCustom(menu, 172+32, 88, NULL, 0); ci->draw = MSetup_TransDraw; diff --git a/engine/client/menu.c b/engine/client/menu.c index 5e1476677..c25b1bd3f 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -183,11 +183,10 @@ void M_PrintWhite (int cx, int cy, qbyte *str) Draw_FunString(cx + ((vid.width - 320)>>1), cy, str); } -void M_BuildTranslationTable(int top, int bottom, unsigned int *translationTable) +void M_BuildTranslationTable(unsigned int pc, unsigned int top, unsigned int bottom, unsigned int *translationTable) { int j; #ifdef HEXEN2 - int pc = Cvar_Get("cl_playerclass", "1", 0, "Hexen2")->value; if (h2playertranslations && pc) { int i; @@ -200,9 +199,33 @@ void M_BuildTranslationTable(int top, int bottom, unsigned int *translationTable for(i=0;i<255;i++) { if (bottom > 0 && (colorB[i] != 255)) - translationTable[i] = d_8to24rgbtable[sourceB[i]] | 0xff000000; + { + if (bottom >= 16) + { + unsigned int v = d_8to24rgbtable[colorB[i]]; + v = max(max((v>>0)&0xff, (v>>8)&0xff), (v>>16)&0xff); + *((unsigned char*)&translationTable[i]+0) = (((bottom&0xff0000)>>16)*v)>>8; + *((unsigned char*)&translationTable[i]+1) = (((bottom&0x00ff00)>> 8)*v)>>8; + *((unsigned char*)&translationTable[i]+2) = (((bottom&0x0000ff)>> 0)*v)>>8; + *((unsigned char*)&translationTable[i]+3) = 0xff; + } + else + translationTable[i] = d_8to24rgbtable[sourceB[i]] | 0xff000000; + } else if (top > 0 && (colorA[i] != 255)) - translationTable[i] = d_8to24rgbtable[sourceA[i]] | 0xff000000; + { + if (top >= 16) + { + unsigned int v = d_8to24rgbtable[colorA[i]]; + v = max(max((v>>0)&0xff, (v>>8)&0xff), (v>>16)&0xff); + *((unsigned char*)&translationTable[i]+0) = (((top&0xff0000)>>16)*v)>>8; + *((unsigned char*)&translationTable[i]+1) = (((top&0x00ff00)>> 8)*v)>>8; + *((unsigned char*)&translationTable[i]+2) = (((top&0x0000ff)>> 0)*v)>>8; + *((unsigned char*)&translationTable[i]+3) = 0xff; + } + else + translationTable[i] = d_8to24rgbtable[sourceA[i]] | 0xff000000; + } else translationTable[i] = d_8to24rgbtable[i] | 0xff000000; } diff --git a/engine/client/menu.h b/engine/client/menu.h index ca0ac1250..a41eb6826 100644 --- a/engine/client/menu.h +++ b/engine/client/menu.h @@ -442,7 +442,7 @@ void M_DrawServers(void); void M_SListKey(int key); //drawing funcs -void M_BuildTranslationTable(int top, int bottom, unsigned int *translationTable); +void M_BuildTranslationTable(unsigned int pc, unsigned int top, unsigned int bottom, unsigned int *translationTable); void M_DrawCharacter (int cx, int line, unsigned int num); void M_Print (int cx, int cy, qbyte *str); void M_PrintWhite (int cx, int cy, qbyte *str); diff --git a/engine/client/merged.h b/engine/client/merged.h index c0aef8c3d..9bab65002 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -258,15 +258,28 @@ struct pendingtextureinfo } type; enum { + //these formats are specified as direct byte access PTI_RGBA8, //rgba byte ordering PTI_RGBX8, //rgb pad byte ordering PTI_BGRA8, //alpha channel PTI_BGRX8, //no alpha channel + //these formats are specified in native endian order + PTI_RGB565, //16bit alphaless format. + PTI_RGBA4444, //16bit format (gl) + PTI_ARGB4444, //16bit format (d3d) + PTI_RGBA5551, //16bit alpha format (gl). + PTI_ARGB1555, //16bit alpha format (d3d). //compressed formats PTI_S3RGB1, PTI_S3RGBA1, PTI_S3RGBA3, - PTI_S3RGBA5 + PTI_S3RGBA5, + //depth formats + PTI_DEPTH16, + PTI_DEPTH24, + PTI_DEPTH32, + PTI_DEPTH24_8 +#define PTI_MAX PTI_DEPTH24_8+1 } encoding; //0 int mipcount; struct diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 51534dd92..0cda681de 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -175,8 +175,8 @@ void R2D_Init(void) nogloss[i] = glossval; nonorm[i] = normval; } - missing_texture = R_LoadHiResTexture("no_texture", NULL, IF_NEAREST); - if (!TEXVALID(missing_texture)) + missing_texture = R_LoadHiResTexture("no_texture", NULL, IF_NEAREST|IF_NOWORKER); + if (!TEXLOADED(missing_texture)) missing_texture = R_LoadTexture8("no_texture", 16, 16, (unsigned char*)r_notexture_mip + r_notexture_mip->offsets[0], IF_NOALPHA|IF_NOGAMMA, 0); missing_texture_gloss = R_LoadTexture("no_texture_gloss", 4, 4, TF_RGBA32, (unsigned char*)nogloss, IF_NOGAMMA); missing_texture_normal = R_LoadTexture("no_texture_normal", 4, 4, TF_RGBA32, (unsigned char*)nonorm, IF_NOGAMMA); @@ -194,12 +194,13 @@ void R2D_Init(void) "map $diffuse\n" "}\n" "}\n"); - if (!TEXVALID(draw_backtile->defaulttextures.base)) - draw_backtile->defaulttextures.base = R_LoadHiResTexture("gfx/backtile", NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP); - if (!TEXVALID(draw_backtile->defaulttextures.base)) - draw_backtile->defaulttextures.base = R_LoadHiResTexture("gfx/menu/backtile", NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP); - if (!TEXVALID(draw_backtile->defaulttextures.base)) - draw_backtile->defaulttextures.base = R_LoadHiResTexture("pics/backtile", NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP); + TEXDOWAIT(draw_backtile->defaulttextures.base); + if (!TEXLOADED(draw_backtile->defaulttextures.base)) + draw_backtile->defaulttextures.base = R_LoadHiResTexture("gfx/backtile", NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_NOWORKER); + if (!TEXLOADED(draw_backtile->defaulttextures.base)) + draw_backtile->defaulttextures.base = R_LoadHiResTexture("gfx/menu/backtile", NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_NOWORKER); + if (!TEXLOADED(draw_backtile->defaulttextures.base)) + draw_backtile->defaulttextures.base = R_LoadHiResTexture("pics/backtile", NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_NOWORKER); shader_draw_fill = R_RegisterShader("fill_opaque", SUF_NONE, "{\n" diff --git a/engine/client/render.h b/engine/client/render.h index 1fe252003..ca4e51492 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -359,7 +359,7 @@ enum imageflags /*WARNING: If the above are changed, be sure to change shader pass flags*/ IF_NOPICMIP = 1<<5, - IF_NOALPHA = 1<<6, + IF_NOALPHA = 1<<6, /*hint rather than requirement*/ IF_NOGAMMA = 1<<7, IF_3DMAP = 1<<8, /*waning - don't test directly*/ IF_CUBEMAP = 1<<9, /*waning - don't test directly*/ diff --git a/engine/client/renderer.c b/engine/client/renderer.c index c0da9787a..0afbda391 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -30,6 +30,7 @@ qboolean vid_isfullscreen; #define SCREENOPTIONS "Screen Options" unsigned int d_8to24rgbtable[256]; +unsigned int d_8to24bgrtable[256]; extern int gl_anisotropy_factor; @@ -989,8 +990,10 @@ void R_GenPaletteLookup(void) pal += 3; d_8to24rgbtable[i] = (255<<24) + (r<<0) + (g<<8) + (b<<16); + d_8to24bgrtable[i] = (255<<24) + (b<<0) + (g<<8) + (r<<16); } d_8to24rgbtable[255] &= 0xffffff; // 255 is transparent + d_8to24bgrtable[255] &= 0xffffff; // 255 is transparent } qboolean R_ApplyRenderer (rendererstate_t *newr) diff --git a/engine/client/sbar.c b/engine/client/sbar.c index e0197e570..15ec1b872 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -834,6 +834,7 @@ void Sbar_Start (void) //if one of these fails, skip the entire status bar. } #ifdef HEXEN2 + sbar_hexen2 = false; if (W_SafeGetLumpName("tinyfont")) sbar_hexen2 = true; // if (sb_nums[0][0] && sb_nums[0][0]->width < 13) diff --git a/engine/client/snd_al.c b/engine/client/snd_al.c index 5baebcc87..abf17bddb 100644 --- a/engine/client/snd_al.c +++ b/engine/client/snd_al.c @@ -66,6 +66,7 @@ FIXME: a capture device would be useful (voice chat). #ifdef FTE_TARGET_WEB //emscripten sucks. AL_API void (AL_APIENTRY alSpeedOfSound)( ALfloat value ) {} +#define alGetError() alGetError(NULL) #endif #else diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index e3acd17de..f645e868d 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -3258,6 +3258,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin return 0; } + /* GetModuleFileName(NULL, cwd, sizeof(cwd)-1); for (e = cwd+strlen(cwd)-1; e >= cwd; e--) { @@ -3267,7 +3268,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin break; } } - +*/ } } diff --git a/engine/client/vid.h b/engine/client/vid.h index 7fac47eed..8460edd96 100644 --- a/engine/client/vid.h +++ b/engine/client/vid.h @@ -83,6 +83,7 @@ typedef struct extern viddef_t vid; // global video state extern unsigned int d_8to24rgbtable[256]; +extern unsigned int d_8to24bgrtable[256]; #ifdef GLQUAKE //called when gamma ramps need to be reapplied diff --git a/engine/client/view.c b/engine/client/view.c index 1c8e2ad2a..d44a2f734 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -1309,6 +1309,9 @@ void V_CalcRefdef (playerview_t *pv) vec3_t camorg, camdir; trace_t tr; float len; + //r_refdef.viewangles[0] += chase_pitch.value; + //r_refdef.viewangles[1] += chase_yaw.value; + //r_refdef.viewangles[2] += chase_roll.value; AngleVectors(r_refdef.viewangles, axis[0], axis[1], axis[2]); VectorScale(axis[0], -chase_back.value, camdir); VectorMA(camdir, -chase_up.value, pv->gravitydir, camdir); diff --git a/engine/client/wad.c b/engine/client/wad.c index f451e799f..f53b8ccdb 100644 --- a/engine/client/wad.c +++ b/engine/client/wad.c @@ -629,15 +629,13 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel, char *data, char *mapname) //a } else if (!strcmp("fog", key)) //q1 extension. FIXME: should be made temporary. { - int oel = Cmd_ExecLevel; void CL_Fog_f(void); key[0] = 'f'; - key[1] = ' '; - Q_strncpyz(key+2, token, sizeof(key)-2); - Cmd_TokenizeString(key, false, false); - Cmd_ExecLevel=RESTRICT_LOCAL; - CL_Fog_f(); - Cmd_ExecLevel=oel; + key[1] = 'o'; + key[2] = 'g'; + key[3] = ' '; + Q_strncpyz(key+4, token, sizeof(key)-4); + Cbuf_AddText(key, RESTRICT_INSECURE); } else if (!strncmp("cvar_", key, 5)) //override cvars so mappers don't end up hacking cvars and fucking over configs (at least in other engines). { diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 9dfcc68e4..479f3ad84 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // cmd.c -- Quake script command processing module #include "quakedef.h" +#include "fs.h" cvar_t rcon_level = SCVAR("rcon_level", "20"); cvar_t cmd_maxbuffersize = SCVAR("cmd_maxbuffersize", "65536"); @@ -185,6 +186,11 @@ void Cbuf_Init (void) cmd_text[level].waitattime = -1; } +static void Cbuf_WorkerAddText(void *ctx, void *data, size_t a, size_t b) +{ + Cbuf_AddText(data, a); + Z_Free(data); +} /* ============ Cbuf_AddText @@ -196,6 +202,12 @@ void Cbuf_AddText (const char *text, int level) { int l; + if (!Sys_IsThread(NULL)) + { + COM_AddWork(0, Cbuf_WorkerAddText, NULL, Z_StrDup(text), level, 0); + return; + } + if (level > sizeof(cmd_text)/sizeof(cmd_text[0]) || level < 0) { Con_Printf("Bad execution level\n"); @@ -509,6 +521,10 @@ void Cmd_Exec_f (void) { char *f, *s; char name[256]; + flocation_t loc; + qboolean untrusted; + vfsfile_t *file; + size_t l; if (Cmd_Argc () != 2) { @@ -528,18 +544,27 @@ void Cmd_Exec_f (void) else Q_strncpyz(name, Cmd_Argv(1), sizeof(name)); - if (!qofs_Error(FS_LoadFile(name, (void **)&f))) - ; - else if (!qofs_Error(FS_LoadFile(va("%s.cfg", name), (void **)&f))) - ; - else + if (!FS_FLocateFile(name, FSLFRT_IFFOUND, &loc) && !FS_FLocateFile(va("%s.cfg", name), FSLFRT_IFFOUND, &loc)) { - Con_TPrintf ("couldn't exec %s\n",name); + Con_TPrintf ("couldn't exec %s\n", name); + return; + } + file = FS_OpenReadLocation(&loc); + if (!file) + { + Con_TPrintf ("couldn't exec %s. check permissions.\n", name); return; } if (cl_warncmd.ival || developer.ival) Con_TPrintf ("execing %s\n",name); + l = VFS_GETLEN(file); + f = BZ_Malloc(l+1); + f[l] = 0; + VFS_READ(file, f, l); + VFS_CLOSE(file); + untrusted = !!(loc.search->flags&SPF_UNTRUSTED); + s = f; if (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') { @@ -554,13 +579,13 @@ void Cmd_Exec_f (void) int cfgdepth = COM_FDepthFile(name, true); int defdepth = COM_FDepthFile("default.cfg", true); if (defdepth < cfgdepth) - Cbuf_InsertText("exec default.cfg\n", ((Cmd_FromGamecode() || com_file_untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), false); + Cbuf_InsertText("exec default.cfg\n", ((Cmd_FromGamecode() || untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), false); } // don't execute anything if it was from server (either the stuffcmd/localcmd, or the file) - if (!strcmp(name, "default.cfg") && !(Cmd_FromGamecode() || com_file_untrusted)) - Cbuf_InsertText ("\ncvar_lockdefaults 1\n", ((Cmd_FromGamecode() || com_file_untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), false); - Cbuf_InsertText (s, ((Cmd_FromGamecode() || com_file_untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), true); - FS_FreeFile(f); + if (!strcmp(name, "default.cfg") && !(Cmd_FromGamecode() || untrusted)) + Cbuf_InsertText ("\ncvar_lockdefaults 1\n", ((Cmd_FromGamecode() || untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), false); + Cbuf_InsertText (s, ((Cmd_FromGamecode() || untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), true); + BZ_Free(f); } diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index d659dce51..8f26cb528 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -3251,12 +3251,17 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize) //skins skinstart = (daliasskintype_t *)((char*)pq1inmodel+hdrsize); +#ifdef HEXEN2 if( mod->flags & MFH2_TRANSPARENT ) skintranstype = TF_H2_T7G1; //hexen2 - else if( mod->flags & MFH2_HOLEY ) + else +#endif + if( mod->flags & MFH2_HOLEY ) skintranstype = TF_H2_TRANS8_0; //hexen2 +#ifdef HEXEN2 else if( mod->flags & MFH2_SPECIAL_TRANS ) skintranstype = TF_H2_T4A4; //hexen2 +#endif else skintranstype = TF_SOLID8; diff --git a/engine/common/common.h b/engine/common/common.h index 39c8f1665..37742a9e8 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -336,8 +336,6 @@ char *VARGS va(const char *format, ...) LIKEPRINTF(1); //============================================================================ -extern qboolean com_file_copyprotected; -extern qboolean com_file_untrusted; struct cache_user_s; extern char com_gamepath[MAX_OSPATH]; @@ -365,6 +363,22 @@ void COM_WriteFile (const char *filename, const void *data, int len); #define qofs_Error(o) ((o) == ~0ul) #endif +typedef struct searchpathfuncs_s searchpathfuncs_t; +typedef struct searchpath_s +{ + searchpathfuncs_t *handle; + + unsigned int flags; + + char logicalpath[MAX_OSPATH]; //printable hunam-readable location of the package. generally includes a system path, including nested packages. + char purepath[256]; //server tracks the path used to load them so it can tell the client + int crc_check; //client sorts packs according to this checksum + int crc_reply; //client sends a different crc back to the server, for the paks it's actually loaded. + int orderkey; //used to check to see if the paths were actually changed or not. + + struct searchpath_s *next; + struct searchpath_s *nextpure; +} searchpath_t; typedef struct { struct searchpath_s *search; //used to say which filesystem driver to open the file from int index; //used by the filesystem driver as a simple reference to the file @@ -405,7 +419,6 @@ typedef struct vfsfile_s char dbgname[MAX_QPATH]; #endif } vfsfile_t; -typedef struct searchpathfuncs_s searchpathfuncs_t; #define VFS_CLOSE(vf) ((vf)->Close(vf)) #define VFS_TELL(vf) ((vf)->Tell(vf)) diff --git a/engine/common/cvar.c b/engine/common/cvar.c index e939402d1..bbe729f8a 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -679,6 +679,8 @@ cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force) { //fixme: force should probably be a latch bitmask char *latch=NULL; + COM_AssertMainThread("Cvar_SetCore"); + if (!var) return NULL; diff --git a/engine/common/fs.c b/engine/common/fs.c index 7d17b7cd9..6aa3aa304 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -161,10 +161,6 @@ char pubgamedirfile[MAX_OSPATH]; //like gamedirfile, but not set to the fte-only -//the various COM_LoadFiles set these on return -qboolean com_file_copyprotected;//file should not be available for download. -qboolean com_file_untrusted; //file was downloaded inside a package - char com_gamepath[MAX_OSPATH]; //c:\games\quake char com_homepath[MAX_OSPATH]; //c:\users\foo\my docs\fte\quake qboolean com_homepathenabled; @@ -490,23 +486,6 @@ ftemanifest_t *FS_Manifest_Parse(const char *fname, const char *data) //====================================================================================================== - -typedef struct searchpath_s -{ - searchpathfuncs_t *handle; - - unsigned int flags; - - char logicalpath[MAX_OSPATH]; //printable hunam-readable location of the package. generally includes a system path, including nested packages. - char purepath[256]; //server tracks the path used to load them so it can tell the client - int crc_check; //client sorts packs according to this checksum - int crc_reply; //client sends a different crc back to the server, for the paks it's actually loaded. - int orderkey; //used to check to see if the paths were actually changed or not. - - struct searchpath_s *next; - struct searchpath_s *nextpure; -} searchpath_t; - static ftemanifest_t *fs_manifest; //currently active manifest. static searchpath_t *com_searchpaths; static searchpath_t *com_purepaths; @@ -945,9 +924,6 @@ int FS_FLocateFile(const char *filename, FSLF_ReturnType_e returntype, flocation search->flags |= fs_referencetype; } loc->search = search; - - com_file_copyprotected = !!(search->flags & SPF_COPYPROTECTED); - com_file_untrusted = !!(search->flags & SPF_UNTRUSTED); break; } } @@ -970,8 +946,6 @@ int FS_FLocateFile(const char *filename, FSLF_ReturnType_e returntype, flocation search->flags |= fs_referencetype; } loc->search = search; - com_file_copyprotected = !!(search->flags & SPF_COPYPROTECTED); - com_file_untrusted = !!(search->flags & SPF_UNTRUSTED); break; } } @@ -1455,8 +1429,6 @@ vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative r if (loc.search) { - com_file_copyprotected = !!(loc.search->flags & SPF_COPYPROTECTED); - com_file_untrusted = !!(loc.search->flags & SPF_UNTRUSTED); return VFS_Filter(filename, loc.search->handle->OpenVFS(loc.search->handle, &loc, mode)); } @@ -1474,8 +1446,6 @@ vfsfile_t *FS_OpenReadLocation(flocation_t *location) { if (location->search) { - com_file_copyprotected = !!(location->search->flags & SPF_COPYPROTECTED); - com_file_untrusted = !!(location->search->flags & SPF_UNTRUSTED); return VFS_Filter(NULL, location->search->handle->OpenVFS(location->search->handle, location, "rb")); } return NULL; @@ -3974,6 +3944,113 @@ void FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man), } } +//attempts to find a new basedir for 'input', changing to it as appropriate +//returns fixed up filename relative to the new gamedir. +//input must be an absolute path. +qboolean FS_FixupGamedirForExternalFile(char *input, char *filename, size_t fnamelen) +{ + char syspath[MAX_OSPATH]; + char gamepath[MAX_OSPATH]; + void *iterator; + char *sep,*bs; + char *src = NULL; + + Q_strncpyz(filename, input, fnamelen); + + iterator = NULL; + while(COM_IteratePaths(&iterator, syspath, sizeof(syspath), gamepath, sizeof(gamepath))) + { + if (!Q_strncasecmp(syspath, filename, strlen(syspath))) + { + src = filename+strlen(syspath); + memmove(filename, src, strlen(src)+1); + break; + } + } + if (!src) + { + for(;;) + { + sep = strchr(filename, '\\'); + if (sep) + *sep = '/'; + else + break; + } + for (sep = NULL;;) + { + bs = sep; + sep = strrchr(filename, '/'); + if (bs) + *bs = '/'; + if (sep) + { + int game; + *sep = 0; + if (strchr(filename, '/')) //make sure there's always at least one / + { + char temp[MAX_OSPATH]; + Q_snprintfz(temp, sizeof(temp), "%s/", filename); + game = FS_IdentifyDefaultGameFromDir(temp); + if (game != -1) + { + static char newbase[MAX_OSPATH]; + if (!host_parms.basedir || strcmp(host_parms.basedir, filename)) + { + Con_Printf("switching basedir+game to %s for %s\n", filename, input); + Q_strncpyz(newbase, filename, sizeof(newbase)); + host_parms.basedir = newbase; + FS_ChangeGame(FS_GenerateLegacyManifest(NULL, 0, true, game), true); + } + *sep = '/'; + sep = NULL; + src = filename+strlen(host_parms.basedir); + memmove(filename, src, strlen(src)+1); + break; + } + } + } + else + break; + } + if (sep) + *sep = '/'; + } + if (!src && host_parms.binarydir && !Q_strncasecmp(host_parms.binarydir, filename, strlen(host_parms.binarydir))) + { + src = filename+strlen(host_parms.binarydir); + memmove(filename, src, strlen(src)+1); + } + if (!src && host_parms.basedir && !Q_strncasecmp(host_parms.basedir, filename, strlen(host_parms.basedir))) + { + src = filename+strlen(host_parms.basedir); + memmove(filename, src, strlen(src)+1); + } + if (!src) + { + Q_snprintfz(filename, fnamelen, "#%s", input); + return false; + } + if (*filename == '/' || *filename == '\\') + memmove(filename, filename+1, strlen(filename+1)+1); + + sep = strchr(filename, '/'); + bs = strchr(filename, '\\'); + if (bs && (!sep || bs < sep)) + sep = bs; + if (sep) + { + Con_Printf("switching gamedir for %s\n", filename); + *sep = 0; + COM_Gamedir(filename); + memmove(filename, sep+1, strlen(sep+1)+1); + return true; + } + Q_snprintfz(filename, fnamelen, "#%s", input); + return false; +} + + void FS_ChangeGame_f(void) { int i; diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index f8e607cb8..0616c7dcf 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -173,7 +173,7 @@ int NetadrToSockadr (netadr_t *a, struct sockaddr_qstorage *s) return sizeof(struct sockaddr_ipx); #endif default: - Sys_Error("Bad type - needs fixing"); + Sys_Error("NetadrToSockadr: Bad type %i", a->type); return 0; } } diff --git a/engine/d3d/d3d11_image.c b/engine/d3d/d3d11_image.c index c5b0e57fe..6542c3704 100644 --- a/engine/d3d/d3d11_image.c +++ b/engine/d3d/d3d11_image.c @@ -133,13 +133,31 @@ qboolean D3D11_LoadTextureMips(image_t *tex, struct pendingtextureinfo *mips) else if (mips->type == PTI_3D) return false; //nyi +//d3d11.1 formats +#define DXGI_FORMAT_B4G4R4A4_UNORM 115 + switch(mips->encoding) { - case PTI_RGBA8: - tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + default: + return false; + case PTI_RGB565: + tdesc.Format = DXGI_FORMAT_B5G6R5_UNORM; break; - case PTI_RGBX8: - tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; //d3d11 has no alphaless format. be sure to proprly disable alpha in the shader. +// case PTI_RGBA5551: +// tdesc.Format = DXGI_FORMAT_A1B5G5R5_UNORM; +// break; + case PTI_ARGB1555: + tdesc.Format = DXGI_FORMAT_B5G5R5A1_UNORM; + break; + case PTI_RGBA4444: + tdesc.Format = DXGI_FORMAT_B4G4R4A4_UNORM; + break; +// case PTI_ARGB4444: +// tdesc.Format = DXGI_FORMAT_A4B4G4R4_UNORM; +// break; + case PTI_RGBA8: + case PTI_RGBX8: //d3d11 has no alphaless format. be sure to proprly disable alpha in the shader. + tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; break; case PTI_BGRA8: tdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; diff --git a/engine/d3d/d3d11_shader.c b/engine/d3d/d3d11_shader.c index c5320a5d7..d4a03e5f9 100644 --- a/engine/d3d/d3d11_shader.c +++ b/engine/d3d/d3d11_shader.c @@ -535,8 +535,6 @@ qboolean D3D11Shader_Init(unsigned int flevel) {NULL,NULL} }; - memset(&sh_config, 0, sizeof(sh_config)); - for (ver = 47; ver >= 33; ver--) { shaderlib = Sys_LoadLibrary(va("D3dcompiler_%i.dll", ver), (ver>=40)?funcsnew:funcsold); @@ -565,7 +563,6 @@ qboolean D3D11Shader_Init(unsigned int flevel) sh_config.pCreateProgram = D3D11Shader_CreateProgram; sh_config.pProgAutoFields = NULL; - sh_config.texture_non_power_of_two = true; sh_config.tex_env_combine = 1; sh_config.nv_tex_env_combine4 = 1; sh_config.env_add = 1; diff --git a/engine/d3d/d3d_image.c b/engine/d3d/d3d_image.c index 307aac8f2..36d0d9300 100644 --- a/engine/d3d/d3d_image.c +++ b/engine/d3d/d3d_image.c @@ -8,78 +8,6 @@ #include extern LPDIRECT3DDEVICE9 pD3DDev9; -static void Upload_Texture_32(LPDIRECT3DTEXTURE9 tex, unsigned int *data, int width, int height, unsigned int flags) -{ - int x, y; - unsigned int *dest; - unsigned char swapbuf[4]; - unsigned char swapbuf2[4]; - D3DLOCKED_RECT lock; - - D3DSURFACE_DESC desc; - IDirect3DTexture9_GetLevelDesc(tex, 0, &desc); - - IDirect3DTexture9_LockRect(tex, 0, &lock, NULL, D3DLOCK_NOSYSLOCK); - - if (width == desc.Width && height == desc.Height) - { - for (y = 0; y < height; y++) - { - dest = (unsigned int *)((char *)lock.pBits + lock.Pitch*y); - for (x = 0; x < width; x++) - { - *(unsigned int*)swapbuf2 = *(unsigned int*)swapbuf = data[x]; - swapbuf[0] = swapbuf2[2]; - swapbuf[2] = swapbuf2[0]; - dest[x] = *(unsigned int*)swapbuf; - } - data += width; - } - } - else - { - int x, y; - int iny; - unsigned int *row, *inrow; - - for (y = 0; y < desc.Height; y++) - { - row = (unsigned int*)((char *)lock.pBits + lock.Pitch*y); - iny = (y * height) / desc.Height; - inrow = data + width*iny; - for (x = 0; x < desc.Width; x++) - { - *(unsigned int*)swapbuf2 = *(unsigned int*)swapbuf = inrow[(x * width)/desc.Width]; - swapbuf[0] = swapbuf2[2]; - swapbuf[2] = swapbuf2[0]; - row[x] = *(unsigned int*)swapbuf; - } - } - } - -#if 0 //D3DUSAGE_AUTOGENMIPMAP so this isn't needed - if (!(flags & IF_NOMIPMAP)) - { - int max = IDirect3DTexture9_GetLevelCount(tex); - for (i = 1; i < max; i++) - { - width = desc.Width; - height = desc.Height; - data = lock.pBits; - IDirect3DTexture9_LockRect(tex, i, &lock, NULL, D3DLOCK_NOSYSLOCK|D3DLOCK_DISCARD); - IDirect3DTexture9_GetLevelDesc(tex, i, &desc); - D3D_MipMap(lock.pBits, desc.Width, desc.Height, data, width, height); - IDirect3DTexture9_UnlockRect(tex, i-1); - } - IDirect3DTexture9_UnlockRect(tex, i-1); - } - else -#endif - IDirect3DTexture9_UnlockRect(tex, 0); -} - - - void D3D9_DestroyTexture (texid_t tex) { if (!tex) @@ -99,14 +27,33 @@ qboolean D3D9_LoadTextureMips(image_t *tex, struct pendingtextureinfo *mips) D3DSURFACE_DESC desc; IDirect3DTexture9 *dt; qboolean swap = false; + unsigned int pixelsize = 4; switch(mips->encoding) { + case PTI_RGB565: + pixelsize = 2; + fmt = D3DFMT_R5G6B5; + break; + case PTI_RGBA4444://not supported on d3d9 + return false; + case PTI_ARGB4444: + pixelsize = 2; + fmt = D3DFMT_A4R4G4B4; + break; + case PTI_RGBA5551://not supported on d3d9 + return false; + case PTI_ARGB1555: + pixelsize = 2; + fmt = D3DFMT_A1R5G5B5; + break; case PTI_RGBA8: +// fmt = D3DFMT_A8B8G8R8; /*how do we check fmt = D3DFMT_A8R8G8B8; swap = true; break; case PTI_RGBX8: +// fmt = D3DFMT_X8B8G8R8; fmt = D3DFMT_X8R8G8B8; swap = true; break; @@ -119,9 +66,15 @@ qboolean D3D9_LoadTextureMips(image_t *tex, struct pendingtextureinfo *mips) //too lazy to support these for now case PTI_S3RGB1: - case PTI_S3RGBA1: + case PTI_S3RGBA1: //d3d doesn't distinguish between these +// fmt = D3DFMT_DXT1; +// break; case PTI_S3RGBA3: +// fmt = D3DFMT_DXT3; +// break; case PTI_S3RGBA5: +// fmt = D3DFMT_DXT5; +// break; return false; default: //no idea @@ -158,8 +111,8 @@ qboolean D3D9_LoadTextureMips(image_t *tex, struct pendingtextureinfo *mips) } else { - for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*4) - memcpy(out, in, mips->mip[i].width*4); + for (y = 0, out = lock.pBits, in = mips->mip[i].data; y < mips->mip[i].height; y++, out += lock.Pitch, in += mips->mip[i].width*pixelsize) + memcpy(out, in, mips->mip[i].width*pixelsize); } IDirect3DTexture9_UnlockRect(dt, i); } diff --git a/engine/d3d/d3d_shader.c b/engine/d3d/d3d_shader.c index 0eee23d2d..d6fdbce75 100644 --- a/engine/d3d/d3d_shader.c +++ b/engine/d3d/d3d_shader.c @@ -351,6 +351,8 @@ void D3D9Shader_DeleteProg(program_t *prog, unsigned int permu) void D3D9Shader_Init(void) { + D3DCAPS9 caps; + dllfunction_t funcs[] = { {(void**)&pD3DXCompileShader, "D3DXCompileShader"}, @@ -378,9 +380,22 @@ void D3D9Shader_Init(void) sh_config.pProgAutoFields = D3D9Shader_ProgAutoFields; sh_config.texture_non_power_of_two = 0; + sh_config.texture_non_power_of_two_pic = 0; sh_config.tex_env_combine = 1; sh_config.nv_tex_env_combine4 = 1; sh_config.env_add = 1; + + //FIXME: check caps + sh_config.texfmt[PTI_RGBX8] = true; //fixme: shouldn't support + sh_config.texfmt[PTI_RGBA8] = true; //fixme: shouldn't support + sh_config.texfmt[PTI_BGRX8] = true; + sh_config.texfmt[PTI_BGRA8] = true; + sh_config.texfmt[PTI_RGB565] = true; + sh_config.texfmt[PTI_ARGB1555] = true; + sh_config.texfmt[PTI_ARGB4444] = true; + + IDirect3DDevice9_GetDeviceCaps(pD3DDev9, &caps); + sh_config.texture_maxsize = min(caps.MaxTextureWidth, caps.MaxTextureHeight); } #endif diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index fce747707..ac3a66999 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -657,6 +657,7 @@ static qboolean D3D11_VID_Init(rendererstate_t *info, unsigned char *palette) #else static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN func, IDXGIAdapter *adapt) { + UINT support; int flags = 0;//= D3D11_CREATE_DEVICE_SINGLETHREADED; D3D_DRIVER_TYPE drivertype; DXGI_SWAP_CHAIN_DESC scd; @@ -740,17 +741,35 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA { } - r_config.texture_non_power_of_two = flevel>=D3D_FEATURE_LEVEL_10_0; //npot MUST be supported on all d3d10+ cards. - r_config.texture_non_power_of_two_pic = true; //always supported in d3d11, supposedly. - r_config.npot_rounddown = false; + memset(&sh_config, 0, sizeof(sh_config)); + sh_config.texture_non_power_of_two = flevel>=D3D_FEATURE_LEVEL_10_0; //npot MUST be supported on all d3d10+ cards. + sh_config.texture_non_power_of_two_pic = true; //always supported in d3d11, supposedly, even with d3d9 devices. + sh_config.npot_rounddown = false; if (flevel>=D3D_FEATURE_LEVEL_11_0) - r_config.maxtexturesize = 16384; + sh_config.texture_maxsize = 16384; else if (flevel>=D3D_FEATURE_LEVEL_10_0) - r_config.maxtexturesize = 8192; + sh_config.texture_maxsize = 8192; else if (flevel>=D3D_FEATURE_LEVEL_9_3) - r_config.maxtexturesize = 4096; + sh_config.texture_maxsize = 4096; else - r_config.maxtexturesize = 2048; + sh_config.texture_maxsize = 2048; + +//11.1 formats +#define DXGI_FORMAT_B4G4R4A4_UNORM 115 + + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B5G6R5_UNORM, &support); sh_config.texfmt[PTI_RGB565] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B5G5R5A1_UNORM, &support); sh_config.texfmt[PTI_ARGB1555] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B4G4R4A4_UNORM, &support); sh_config.texfmt[PTI_ARGB4444] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_R8G8B8A8_UNORM, &support); sh_config.texfmt[PTI_RGBA8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8A8_UNORM, &support); sh_config.texfmt[PTI_BGRA8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8X8_UNORM, &support); sh_config.texfmt[PTI_BGRX8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC1_UNORM, &support); sh_config.texfmt[PTI_S3RGBA1] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC2_UNORM, &support); sh_config.texfmt[PTI_S3RGBA3] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC3_UNORM, &support); sh_config.texfmt[PTI_S3RGBA5] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + + //these formats are not officially supported as specified, but noone cares + sh_config.texfmt[PTI_RGBX8] = sh_config.texfmt[PTI_RGBA8]; + sh_config.texfmt[PTI_S3RGB1] = sh_config.texfmt[PTI_S3RGBA1]; vid.numpages = scd.BufferCount; if (!D3D11Shader_Init(flevel)) diff --git a/engine/dotnet2005/ftequake.sln b/engine/dotnet2005/ftequake.sln index 8158bcdc8..5e524812c 100644 --- a/engine/dotnet2005/ftequake.sln +++ b/engine/dotnet2005/ftequake.sln @@ -630,7 +630,6 @@ Global {74542CA7-48C1-4664-9007-66F751131EA3}.Release|Win32.Build.0 = Release|Win32 {74542CA7-48C1-4664-9007-66F751131EA3}.Release|x64.ActiveCfg = Release|Win32 {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.D3DDebug|Win32.ActiveCfg = Debug|Win32 - {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.D3DDebug|Win32.Build.0 = Debug|Win32 {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.D3DDebug|x64.ActiveCfg = Debug|Win32 {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.D3DRelease|Win32.ActiveCfg = Release|Win32 {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.D3DRelease|Win32.Build.0 = Release|Win32 diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index ae0554a40..231af832b 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -751,7 +751,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e } if (!original) { - if (skins->numframes && skins->frame[subframe].texels) + if (skins && skins->numframes && skins->frame[subframe].texels) { original = skins->frame[subframe].texels; inwidth = skins->skinwidth; @@ -764,8 +764,16 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e inheight = 0; } } - tinwidth = skins->skinwidth; - tinheight = skins->skinheight; + if (skins) + { + tinwidth = skins->skinwidth; + tinheight = skins->skinheight; + } + else + { + tinwidth = inwidth; + tinheight = inheight; + } if (original) { int i, j; @@ -835,9 +843,33 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e { translate32[i] = d_8to24rgbtable[i]; if (tc > 0 && (colorA[i] != 255)) - translate32[i] = d_8to24rgbtable[sourceA[i]]; + { + if (tc >= 16) + { + unsigned int v = d_8to24rgbtable[colorA[i]]; + v = max(max((v>>0)&0xff, (v>>8)&0xff), (v>>16)&0xff); + *((unsigned char*)&translate32[i]+0) = (((tc&0xff0000)>>16)*v)>>8; + *((unsigned char*)&translate32[i]+1) = (((tc&0x00ff00)>> 8)*v)>>8; + *((unsigned char*)&translate32[i]+2) = (((tc&0x0000ff)>> 0)*v)>>8; + *((unsigned char*)&translate32[i]+3) = 0xff; + } + else + translate32[i] = d_8to24rgbtable[sourceA[i]]; + } if (bc > 0 && (colorB[i] != 255)) - translate32[i] = d_8to24rgbtable[sourceB[i]]; + { + if (bc >= 16) + { + unsigned int v = d_8to24rgbtable[colorB[i]]; + v = max(max((v>>0)&0xff, (v>>8)&0xff), (v>>16)&0xff); + *((unsigned char*)&translate32[i]+0) = (((bc&0xff0000)>>16)*v)>>8; + *((unsigned char*)&translate32[i]+1) = (((bc&0x00ff00)>> 8)*v)>>8; + *((unsigned char*)&translate32[i]+2) = (((bc&0x0000ff)>> 0)*v)>>8; + *((unsigned char*)&translate32[i]+3) = 0xff; + } + else + translate32[i] = d_8to24rgbtable[sourceB[i]]; + } } translate32[0] = 0; } diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 2ed87d0e5..7924c2f66 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -1010,7 +1010,7 @@ static void T_Gen_CurrentRender(int tmu) if (r_refdef.recurse) return; - if (gl_config.texture_non_power_of_two_limited) + if (sh_config.texture_non_power_of_two_pic) { vwidth = pwidth; vheight = pheight; @@ -3044,7 +3044,7 @@ static void BE_Program_Set_Attributes(const program_t *prog, unsigned int perm, break; case SP_RENDERTEXTURESCALE: - if (gl_config.texture_non_power_of_two_limited) + if (sh_config.texture_non_power_of_two_pic) { param4[0] = 1; param4[1] = 1; diff --git a/engine/gl/gl_bloom.c b/engine/gl/gl_bloom.c index 35c54546a..01f1189fd 100644 --- a/engine/gl/gl_bloom.c +++ b/engine/gl/gl_bloom.c @@ -181,7 +181,7 @@ qboolean R_CanBloom(void) return false; if (!gl_config.arb_shader_objects) return false; - if (!gl_config.texture_non_power_of_two_limited) + if (!sh_config.texture_non_power_of_two_pic) return false; return true; diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index c30521b15..39da371c6 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -59,9 +59,6 @@ Draw_Init */ void GLDraw_Init (void) { - r_config.maxtexturesize = 256; - qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &r_config.maxtexturesize); - R2D_Init(); TRACE(("dbg: GLDraw_ReInit: GL_BeginRendering\n")); @@ -277,6 +274,18 @@ qboolean GL_LoadTextureMips(texid_t tex, struct pendingtextureinfo *mips) int targ, targface; int i, j; + if (gl_config.gles) + { + //gles requires that the internal format must match format + //this means we can't specify 24.0 modes with a 24.8 datatype. + //arguably we shouldn't do this anyway, but there are differences that q3 shaders can notice. + //fixme: move elsewhere? + if (mips->encoding == PTI_RGBX8) + mips->encoding = PTI_RGBA8; + if (mips->encoding == PTI_BGRX8) + mips->encoding = PTI_BGRA8; + } + if (!tex->num) qglGenTextures(1, &tex->num); @@ -335,6 +344,15 @@ qboolean GL_LoadTextureMips(texid_t tex, struct pendingtextureinfo *mips) default: qglTexImage3D(targface, i, GL_RGBA, size, size, size, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); break; + case PTI_RGBA4444: + qglTexImage3D(targface, i, GL_RGBA, size, size, size, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, mips->mip[i].data); + break; + case PTI_RGBA5551: + qglTexImage3D(targface, i, GL_RGBA, size, size, size, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, mips->mip[i].data); + break; + case PTI_RGB565: + qglTexImage3D(targface, i, GL_RGB, size, size, size, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, mips->mip[i].data); + break; } if (mips->mip[i].needfree) @@ -358,6 +376,7 @@ qboolean GL_LoadTextureMips(texid_t tex, struct pendingtextureinfo *mips) } switch(mips->encoding) { + //32bit formats case PTI_RGBX8: qglTexImage2D(targface, j, GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); break; @@ -371,6 +390,23 @@ qboolean GL_LoadTextureMips(texid_t tex, struct pendingtextureinfo *mips) default: qglTexImage2D(targface, j, GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); break; + //16bit formats + case PTI_RGBA4444: + qglTexImage2D(targface, j, GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, mips->mip[i].data); + break; + case PTI_RGBA5551: + qglTexImage2D(targface, j, GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, mips->mip[i].data); + break; + case PTI_ARGB4444: + qglTexImage2D(targface, j, GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV, mips->mip[i].data); + break; + case PTI_ARGB1555: + qglTexImage2D(targface, j, GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV, mips->mip[i].data); + break; + case PTI_RGB565: + qglTexImage2D(targface, j, GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, mips->mip[i].data); + break; + //compressed formats case PTI_S3RGB1: qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data); break; diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index a76d5c286..df951fdf6 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -3553,8 +3553,7 @@ static qboolean Mod_LoadLeafs (model_t *loadmodel, qbyte *mod_base, lump_t *l, i p = LittleLong(in->contents); out->contents = p; - out->firstmarksurface = loadmodel->marksurfaces + - (unsigned short)LittleShort(in->firstmarksurface); + out->firstmarksurface = loadmodel->marksurfaces + (unsigned short)LittleShort(in->firstmarksurface); out->nummarksurfaces = (unsigned short)LittleShort(in->nummarksurfaces); p = LittleLong(in->visofs); @@ -3878,8 +3877,14 @@ qboolean Mod_LoadClipnodes (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboo for (i=0 ; iplanenum = LittleLong(ins->planenum); - out->children[0] = LittleShort(ins->children[0]); - out->children[1] = LittleShort(ins->children[1]); + out->children[0] = (unsigned short)LittleShort(ins->children[0]); + out->children[1] = (unsigned short)LittleShort(ins->children[1]); + + //if these 'overflow', then they're meant to refer to contents instead, and should be negative + if (out->children[0] >= count) + out->children[0] -= 0x10000; + if (out->children[1] >= count) + out->children[1] -= 0x10000; } } diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index e1a35b084..54c1d8a72 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -73,7 +73,10 @@ void R_AnimateLight (void) { int v1, v2, vd; if (!cl_lightstyle[j].length) + { + d_lightstylevalue[j] = 256; continue; + } if (cl_lightstyle[j].map[0] == '=') { @@ -401,6 +404,9 @@ void R_GenDlightBatches(batch_t *batches[]) int i, j, sort; dlight_t *l; batch_t *b; + if (!r_lightprepass.ival) + return; + if (!lpplight_shader) lpplight_shader = R_RegisterShader("lpp_light", SUF_NONE, "{\n" diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index a4e32756f..fd69a6328 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -1303,7 +1303,7 @@ static void R_RenderMotionBlur(void) shader_t *shader; //figure out the size of our texture. - if (gl_config.texture_non_power_of_two_limited) + if (sh_config.texture_non_power_of_two_pic) { //we can use any size, supposedly vwidth = vid.pixelwidth; vheight = vid.pixelheight; @@ -1618,7 +1618,7 @@ void GLR_RenderView (void) } //disable stuff if its simply not supported. - if (dofbo || !gl_config.arb_shader_objects || !gl_config.ext_framebuffer_objects || !gl_config.texture_non_power_of_two_limited) + if (dofbo || !gl_config.arb_shader_objects || !gl_config.ext_framebuffer_objects || !sh_config.texture_non_power_of_two_pic) r_refdef.flags &= ~(RDF_ALLPOSTPROC); //block all of this stuff diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index f3660342b..0b7877e34 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -43,7 +43,6 @@ static qboolean shader_rescan_needed; static char **saveshaderbody; sh_config_t sh_config; -r_config_t r_config; //cvars that affect shader generation cvar_t r_vertexlight = CVARFD("r_vertexlight", "0", CVAR_SHADERSYSTEM, "Hack loaded shaders to remove detail pass and lightmap sampling for faster rendering."); @@ -1266,7 +1265,10 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip if (!sh_config.pValidateProgram(prog, name, p, (p & PERMUTATION_SKELETAL)?true:onefailed, blobfile)) { if (!(p & PERMUTATION_SKELETAL)) + { onefailed = true; //don't flag it if skeletal failed. + continue; + } if (!p) break; } @@ -3973,11 +3975,7 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) if (r_loadbumpmapping) { if (!TEXVALID(tn->bump)) - tn->bump = R_LoadHiResTexture(va("%s_norm", imagename), subpath, IF_NOALPHA); - if (!TEXVALID(tn->bump)) - tn->bump = R_LoadHiResTexture(va("%s_bump", imagename), subpath, IF_NOALPHA); - if (!TEXVALID(tn->bump)) - tn->bump = R_LoadHiResTexture(va("normalmaps/%s", imagename), subpath, IF_NOALPHA); + tn->bump = R_LoadHiResTexture(va("%s_norm", imagename), subpath, IF_TRYBUMP); } TEXASSIGN(shader->defaulttextures.bump, tn->bump); } @@ -4740,13 +4738,13 @@ void Shader_Default2D(const char *shortname, shader_t *s, const void *genargs) "clampmap $diffuse\n" "rgbgen vertex\n" "alphagen vertex\n" - "blendfunc gl_src_alpha gl_one_minus_src_alpha\n" + "blendfunc gl_one gl_one_minus_src_alpha\n" "}\n" "sort additive\n" "}\n" ); - TEXASSIGN(s->defaulttextures.base, R_LoadHiResTexture(s->name, NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP)); + TEXASSIGN(s->defaulttextures.base, R_LoadHiResTexture(s->name, NULL, IF_PREMULTIPLYALPHA|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP)); } qboolean Shader_ReadShaderTerms(shader_t *s, char **shadersource, int parsemode, int *conddepth, int maxconddepth, int *cond) @@ -5341,6 +5339,13 @@ int R_GetShaderSizes(shader_t *shader, int *width, int *height, qboolean blockti break; } } + if (i == shader->numpasses) + { //this shader has no textures from which to source a width and height + if (!shader->width) + shader->width = 64; + if (!shader->height) + shader->height = 64; + } } if (shader->width && shader->height) { diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index be1aac6c7..ef73cd0ac 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -603,21 +603,20 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) //geforcefx apparently software emulates it, so gl<3 is bad. if (GL_CheckExtension("GL_ARB_texture_non_power_of_two")) { - gl_config.texture_non_power_of_two = true; + sh_config.texture_non_power_of_two = true; //gles2 has limited npot as standard, which is sufficient to make the hud not look like poo. lets use it. - if ((gl_config.gles && gl_config.glversion >= 2) || gl_config.texture_non_power_of_two) - gl_config.texture_non_power_of_two_limited = true; - r_config.texture_non_power_of_two_pic = true; + if ((gl_config.gles && gl_config.glversion >= 2) || sh_config.texture_non_power_of_two) + sh_config.texture_non_power_of_two_pic = true; } else if (GL_CheckExtension("GL_OES_texture_npot")) { - r_config.texture_non_power_of_two = false; - r_config.texture_non_power_of_two_pic = true; + sh_config.texture_non_power_of_two = false; + sh_config.texture_non_power_of_two_pic = true; } else { - r_config.texture_non_power_of_two = false; - r_config.texture_non_power_of_two_pic = false; + sh_config.texture_non_power_of_two = false; + sh_config.texture_non_power_of_two_pic = false; } // if (GL_CheckExtension("GL_SGIS_generate_mipmap")) //a suprising number of implementations have this broken. @@ -1659,6 +1658,8 @@ GLhandleARB GLSlang_ValidateProgram(GLhandleARB program, const char *name, qbool char *nullconstants = NULL; GLint linked; + if (!program) + return (GLhandleARB)0; qglGetProgramParameteriv_(program, GL_OBJECT_LINK_STATUS_ARB, &linked); if(!linked) @@ -2072,6 +2073,8 @@ void GL_Init(void *(*getglfunction) (char *name)) gl_version = qglGetString (GL_VERSION); Con_SafePrintf ("GL_VERSION: %s\n", gl_version); + memset(&sh_config, 0, sizeof(sh_config)); + GL_CheckExtensions (getglfunction); if ((gl_config.gles && gl_config.glversion >= 3) || (!gl_config.gles && gl_config.glversion >= 2)) @@ -2124,11 +2127,29 @@ void GL_Init(void *(*getglfunction) (char *name)) qglGetError(); /*suck up the invalid operation error for non-debug contexts*/ #endif + sh_config.texture_maxsize = 256; //early minidrivers might not implement this, but anything else should. + qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &sh_config.texture_maxsize); + //always supported + sh_config.texfmt[PTI_RGBA8] = true; + if (GL_CheckExtension("GL_EXT_texture_compression_s3tc")) + { + sh_config.texfmt[PTI_S3RGB1] = true; + sh_config.texfmt[PTI_S3RGBA1] = true; + sh_config.texfmt[PTI_S3RGBA3] = true; + sh_config.texfmt[PTI_S3RGBA5] = true; + } - memset(&sh_config, 0, sizeof(sh_config)); if (gl_config.gles) { + sh_config.texfmt[PTI_RGBX8] = sh_config.texfmt[PTI_RGBA8]; //FIXME: this is faked with PTI_RGBA8 + + sh_config.texfmt[PTI_RGB565] = !gl_config.webgl_ie; //ie sucks and doesn't support things that webgl requires it to support. + sh_config.texfmt[PTI_RGBA4444] = !gl_config.webgl_ie; + sh_config.texfmt[PTI_RGBA5551] = !gl_config.webgl_ie; + sh_config.texfmt[PTI_BGRA8] = false; + sh_config.texfmt[PTI_BGRX8] = sh_config.texfmt[PTI_BGRA8]; + sh_config.minver = 100; sh_config.maxver = 110; sh_config.blobpath = "gles/%s.blob"; @@ -2137,6 +2158,27 @@ void GL_Init(void *(*getglfunction) (char *name)) } else { + sh_config.texfmt[PTI_RGBX8] = true; //proper support + + //these require stuff like GL_UNSIGNED_SHORT_5_5_5_1 etc, which needs gl 1.2+ + if (gl_config.glversion >= 1.2) + { + //16bit formats + sh_config.texfmt[PTI_RGB565] = true; + sh_config.texfmt[PTI_RGBA4444] = true; + sh_config.texfmt[PTI_RGBA5551] = true; + //bgr formats + if (GL_CheckExtension("GL_EXT_bgra")) + { + //32bit formats + sh_config.texfmt[PTI_BGRX8] = true; + sh_config.texfmt[PTI_BGRA8] = true; + //16bit formats + sh_config.texfmt[PTI_ARGB4444] = true; + sh_config.texfmt[PTI_ARGB1555] = true; + } + } + sh_config.minver = gl_config.arb_shader_objects?110:0; sh_config.maxver = gl_config.arb_shader_objects?gl_config.maxglslversion:0; sh_config.blobpath = "glsl/%s.blob"; @@ -2144,7 +2186,6 @@ void GL_Init(void *(*getglfunction) (char *name)) sh_config.shadernamefmt = "%s_glsl"; } - sh_config.texture_non_power_of_two = gl_config.texture_non_power_of_two; sh_config.progs_supported = gl_config.arb_shader_objects; sh_config.progs_required = gl_config_nofixedfunc; diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 1c1564b77..2377fe04f 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -60,15 +60,6 @@ typedef struct builddata_s void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b); //data === builddata_t -//optional features common to all renderers, so I don't have to check to see which one it is all the time. -typedef struct { - qboolean texture_non_power_of_two; //all npot is okay - qboolean texture_non_power_of_two_pic; //npot only works with clamp-to-edge mipless images. - qboolean npot_rounddown; //memory limited systems can say that they want to use less ram. - int maxtexturesize; //biggest image size supported -} r_config_t; -extern r_config_t r_config; - #ifdef GLQUAKE #if defined(ANDROID) /*FIXME: actually just to use standard GLES headers instead of full GL*/ #if 1 @@ -226,8 +217,6 @@ typedef struct { qboolean arb_texture_env_dot3; qboolean arb_texture_cube_map; - qboolean texture_non_power_of_two; //full npot support. - qboolean texture_non_power_of_two_limited; //mipless,clamped npot works, but generic npot doesn't. qboolean arb_texture_compression; // qboolean arb_fragment_program; diff --git a/engine/gl/glsupp.h b/engine/gl/glsupp.h index cdcc6d60c..571b7b471 100644 --- a/engine/gl/glsupp.h +++ b/engine/gl/glsupp.h @@ -52,6 +52,12 @@ extern qlpMTex2FUNC qglMultiTexCoord2fARB; #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 /*opengl 1.2*/ #endif +#ifndef GL_UNSIGNED_SHORT_4_4_4_4_REV +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#endif +#ifndef GL_UNSIGNED_SHORT_1_5_5_5_REV +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#endif #ifndef GL_UNSIGNED_SHORT_4_4_4_4 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #endif diff --git a/engine/gl/shader.h b/engine/gl/shader.h index f69a8f0e3..facb7d95f 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -632,7 +632,11 @@ typedef struct unsigned int minver; //lowest glsl version usable unsigned int maxver; //highest glsl version usable - qboolean texture_non_power_of_two; + qboolean texfmt[PTI_MAX]; //which texture formats are supported (renderable not implied) + unsigned int texture_maxsize; //max size of a 2d texture + qboolean texture_non_power_of_two; //full support for npot + qboolean texture_non_power_of_two_pic; //npot only works with clamp-to-edge mipless images. + qboolean npot_rounddown; //memory limited systems can say that they want to use less ram. qboolean tex_env_combine; qboolean nv_tex_env_combine4; qboolean env_add; diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index a2fcc309d..2e5d37d0a 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -451,13 +451,13 @@ reeval: if ((unsigned)OPA->edict >= (unsigned)sv_num_edicts) { pr_xstatement = st-pr_statements; - if (PR_RunWarning (&progfuncs->funcs, "OP_LOAD references invalid entity %i in %s", OPA->edict, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name))) { st--; goto cont; } - PR_RunError (&progfuncs->funcs, "OP_LOAD references invalid entity %i in %s", OPA->edict, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + OPC->_int = 0; + break; } ed = PROG_TO_EDICT(progfuncs, OPA->edict); #ifdef PARANOID @@ -471,7 +471,15 @@ reeval: if ((unsigned)OPA->edict >= (unsigned)sv_num_edicts) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "OP_LOAD_V references invalid entity %i in %s", OPA->edict, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + if (PR_RunWarning (&progfuncs->funcs, "OP_LOAD_V references invalid entity %i in %s", OPA->edict, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name))) + { + st--; + goto cont; + } + OPC->_vector[0] = 0; + OPC->_vector[1] = 0; + OPC->_vector[2] = 0; + break; } ed = PROG_TO_EDICT(progfuncs, OPA->edict); #ifdef PARANOID diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index a9e60e038..2f7fc40ab 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -342,7 +342,7 @@ void NPP_QWWriteString(int dest, char *data) { NPP_NQWriteString(dest, data); } -void NPP_QWWriteEntity(int dest, short data) +void NPP_QWWriteEntity(int dest, int data) { NPP_NQWriteEntity(dest, data); } @@ -1487,7 +1487,7 @@ void NPP_NQWriteString(int dest, const char *data) //replacement write func (nq nullterms--; NPP_NQCheckFlush(); } -void NPP_NQWriteEntity(int dest, short data) //replacement write func (nq to qw) +void NPP_NQWriteEntity(int dest, int data) //replacement write func (nq to qw) { NPP_NQCheckDest(dest); if (!bufferlen) @@ -2150,7 +2150,7 @@ void NPP_QWWriteString(int dest, const char *data) //replacement write func (nq NPP_QWCheckFlush(); #endif } -void NPP_QWWriteEntity(int dest, short data) //replacement write func (nq to qw) +void NPP_QWWriteEntity(int dest, int data) //replacement write func (nq to qw) { if (data >= 0x8000) { diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 182f242a4..22d1121d4 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -4728,13 +4728,13 @@ void QCBUILTIN PF_WriteEntity (pubprogfuncs_t *prinst, struct globalvars_s *pr_g if (progstype != PROG_QW) { - NPP_NQWriteEntity(dest, (short)G_EDICTNUM(prinst, OFS_PARM1)); + NPP_NQWriteEntity(dest, G_EDICTNUM(prinst, OFS_PARM1)); return; } #ifdef NQPROT else { - NPP_QWWriteEntity(dest, (short)G_EDICTNUM(prinst, OFS_PARM1)); + NPP_QWWriteEntity(dest, G_EDICTNUM(prinst, OFS_PARM1)); return; } #else diff --git a/engine/server/server.h b/engine/server/server.h index 1edc5cd32..786fa89d3 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -1270,7 +1270,7 @@ void NPP_NQWriteAngle(int dest, float data); void NPP_NQWriteCoord(int dest, float data); void NPP_NQWriteFloat(int dest, float data); void NPP_NQWriteString(int dest, const char *data); -void NPP_NQWriteEntity(int dest, short data); +void NPP_NQWriteEntity(int dest, int data); void NPP_QWWriteByte(int dest, qbyte data); void NPP_QWWriteChar(int dest, char data); @@ -1280,7 +1280,7 @@ void NPP_QWWriteAngle(int dest, float data); void NPP_QWWriteCoord(int dest, float data); void NPP_QWWriteFloat(int dest, float data); void NPP_QWWriteString(int dest, const char *data); -void NPP_QWWriteEntity(int dest, short data); +void NPP_QWWriteEntity(int dest, int data); diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 7b0aede34..0721bd24e 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -260,6 +260,12 @@ void SVNQ_CreateBaseline (void) svent->baseline.modelindex = playermodel; } svent->baseline.modelindex&=255; //FIXME + + if (!svent->baseline.modelindex) + { + memcpy(&svent->baseline, &nullentitystate, sizeof(entity_state_t)); + svent->baseline.number = entnum; + } } } diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 2eab45042..afbefcefe 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // sv_user.c -- server code for moving users #include "quakedef.h" +#include "fs.h" #ifndef CLIENTONLY #include "pr_common.h" @@ -2813,7 +2814,7 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam if (found) { - protectedpak = com_file_copyprotected; + protectedpak = loc->search && (loc->search->flags & SPF_COPYPROTECTED); // special check for maps, if it came from a pak file, don't allow download if (protectedpak) diff --git a/engine/web/ftejslib.h b/engine/web/ftejslib.h index 0d6d5db16..ce9611cf4 100644 --- a/engine/web/ftejslib.h +++ b/engine/web/ftejslib.h @@ -29,6 +29,8 @@ void emscriptenfte_abortmainloop(const char *caller); //avoid all of emscripten's sdl emulation. //this resolves input etc issues. unsigned long emscriptenfte_ticks_ms(void); +void emscriptenfte_polljoyevents(void); +void emscriptenfte_settitle(const char *text); int emscriptenfte_setupcanvas( int width, int height, @@ -36,6 +38,8 @@ int emscriptenfte_setupcanvas( void(*Mouse)(int devid,int abs,float x,float y,float z,float size), void(*Button)(int devid, int down, int mbutton), int(*Keyboard)(int devid, int down, int keycode, int unicode), - void(*LoadFile)(char *newhash, int filehandle) + void(*LoadFile)(char *newhash, int filehandle), + void(*buttonevent)(int joydev, int button, int ispressed), + void(*axisevent)(int joydev, int axis, float value) ); diff --git a/engine/web/ftejslib.js b/engine/web/ftejslib.js index 8491db864..7cabd3555 100644 --- a/engine/web/ftejslib.js +++ b/engine/web/ftejslib.js @@ -199,24 +199,88 @@ mergeInto(LibraryManager.library, reader.readAsArrayBuffer(file); } break; + case 'gamepadconnected': + var gp = e.gamepad; + if (FTEH.gamepads === undefined) + FTEH.gamepads = []; + FTEH.gamepads[gp.index] = gp; + console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.", gp.index, gp.id, gp.buttons.length, gp.axes.length); + break; + case 'gamepaddisconnected': + var gp = e.gamepad; + delete FTEH.gamepads[gp.index]; + if (FTEC.evcb.jaxis) //try and clear out the axis when released. + for (var j = 0; j < 6; j+=1) + Runtime.dynCall('viid', FTEC.evcb.jaxis, [gp.index, j, 0]); + if (FTEC.evcb.jbutton) //try and clear out the axis when released. + for (var j = 0; j < 32+4; j+=1) + Runtime.dynCall('viid', FTEC.evcb.jbutton, [gp.index, j, 0]); + console.log("Gamepad disconnected from index %d: %s", gp.index, gp.id); + break; default: console.log(event); break; } } }, - emscriptenfte_setupcanvas__deps: ['$FTEC', '$Browser', 'emscriptenfte_buf_createfromarraybuf'], - emscriptenfte_setupcanvas : function(nw,nh,evresz,evm,evb,evk,evf) + emscriptenfte_polljoyevents : function(be,ae) { - FTEC.evcb.resize = evresz; - FTEC.evcb.mouse = evm; - FTEC.evcb.button = evb; - FTEC.evcb.key = evk; - FTEC.evcb.loadfile = evf; + //with events, we can do unplug stuff properly. + //otherwise hot unplug might be buggy. + var gamepads; + if (FTEH.gamepads !== undefined) + gamepads = FTEH.gamepads; + else + gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads : []); + + if (gamepads !== undefined) + for (var i = 0; i < gamepads.length; i+=1) + { + var gp = gamepads[i]; + if (gp === undefined) + continue; + for (var j = 0; j < gp.buttons.length; j+=1) + { + var b = gp.buttons[j]; + var p; + if (typeof(b) == "object") + { + p = b.pressed; + if (b.lastframe != p) + { //cache it to avoid spam + b.lastframe = p; + Runtime.dynCall('viii', FTEC.evcb.jbutton, [gp.index, j, p]); + } + } + else + {//old chrome bug + p = b==1.0; + //warning: no cache. this is going to be spammy. + Runtime.dynCall('viii', FTEC.evcb.jbutton, [gp.index, j, p]); + } + } + for (var j = 0; j < gp.axes.length; j+=1) + Runtime.dynCall('viid', FTEC.evcb.jaxis, [gp.index, j, gp.axes[j]]); + } + }, + emscriptenfte_setupcanvas__deps: ['$FTEC', '$Browser', 'emscriptenfte_buf_createfromarraybuf'], + emscriptenfte_setupcanvas : function(nw,nh,evresize,evmouse,evmbutton,evkey,evfile,evjbutton,evjaxis) + { + FTEC.evcb.resize = evresize; + FTEC.evcb.mouse = evmouse; + FTEC.evcb.button = evmbutton; + FTEC.evcb.key = evkey; + FTEC.evcb.loadfile = evfile; + FTEC.evcb.jbutton = evjbutton; + FTEC.evcb.jaxis = evjaxis; + + if ('GamepadEvent' in window) + FTEH.gamepads = []; //don't bother ever trying to poll if we can use gamepad events. this will hopefully avoid weirdness. + if (!FTEC.donecb) { FTEC.donecb = 1; - var events = ['mousedown', 'mouseup', 'mousemove', 'wheel', 'mousewheel', 'mouseout', 'keypress', 'keydown', 'keyup', 'touchstart', 'touchend', 'touchcancel', 'touchleave', 'touchmove', 'dragenter', 'dragover', 'drop']; + var events = ['mousedown', 'mouseup', 'mousemove', 'wheel', 'mousewheel', 'mouseout', 'keypress', 'keydown', 'keyup', 'touchstart', 'touchend', 'touchcancel', 'touchleave', 'touchmove', 'dragenter', 'dragover', 'drop', 'gamepadconnected', 'gamepaddisconnected']; events.forEach(function(event) { Module['canvas'].addEventListener(event, FTEC.handleevent, true); @@ -273,7 +337,10 @@ mergeInto(LibraryManager.library, return 1; }, - + emscriptenfte_settitle : function(txt) + { + document.title = Pointer_stringify(txt); + }, emscriptenfte_abortmainloop : function(msg) { msg = Pointer_stringify(msg); diff --git a/engine/web/gl_vidweb.c b/engine/web/gl_vidweb.c index 62f478b81..226553d7a 100644 --- a/engine/web/gl_vidweb.c +++ b/engine/web/gl_vidweb.c @@ -18,6 +18,13 @@ static void *GLVID_getsdlglfunction(char *functionname) return NULL; } +static void IN_JoystickButtonEvent(int joydevid, int button, int ispressed) +{ + if (button >= 32+4) + return; + IN_KeyEvent(joydevid, ispressed, K_JOY1+button, 0); +} + static void VID_Resized(int width, int height) { extern cvar_t vid_conautoscale, vid_conwidth; @@ -176,7 +183,9 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) IN_MouseMove, DOM_ButtonEvent, DOM_KeyEvent, - DOM_LoadFile + DOM_LoadFile, + IN_JoystickButtonEvent, + IN_JoystickAxisEvent )) { Con_Printf("Couldn't set up canvas\n"); @@ -200,7 +209,7 @@ void GLVID_DeInit (void) { ActiveApp = false; - emscriptenfte_setupcanvas(-1, -1, NULL, NULL, NULL, NULL, NULL); + emscriptenfte_setupcanvas(-1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } @@ -240,12 +249,13 @@ qboolean GLVID_ApplyGammaRamps (unsigned short *ramps) void GLVID_SetCaption(char *text) { -// SDL_WM_SetCaption( text, NULL ); + emscriptenfte_settitle(text); } void Sys_SendKeyEvents(void) { - /*callbacks happen outside our code, we don't need to poll for events*/ + /*most callbacks happen outside our code, we don't need to poll for events - except for joysticks*/ + emscriptenfte_polljoyevents(); } /*various stuff for joysticks, which we don't support in this port*/ void INS_Shutdown (void)