From 97579ebfbbfe4ed84d4cc1b39228ccc475f69b32 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sat, 11 Oct 2014 19:39:45 +0000 Subject: [PATCH] bugfixes: hexen2 players now have colourmaps again. doesn't crash with rgb player colours. hexen2 colour previews now work (as well as they did in actual hexen2, anyway) fix possible issue with 'bad type - needs fixing' color command now longer omits 0 values when displaying. readded support for all hexen2 palette lookup types. fixed some hexen2 image positions. using premultiplied alpha for pics as an easy fix for hexen2's various ugly halos. the checkerboard texture is back! fix q1 maps that have more than 32k clipplanes. new features: when associated with mdl etc file extensions, now opens up the modelviewer. also potentially changes gamedir (this applies to bsps too). multiplayer setup menu now supports selecting rgb colours (lower colour remains with the 14 team colours). press shift for the normal/hue colour selection instead. attempt to use bgra for texture uploads by default where available. reimplement possible support for 16bit textures. attempt to implement gamepad support for web port. untested, but should be completeish. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4764 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_ents.c | 5 + engine/client/cl_input.c | 2 +- engine/client/cl_main.c | 56 +++-- engine/client/image.c | 377 +++++++++++++++++++++++++++------ engine/client/input.h | 1 + engine/client/m_items.c | 91 ++++++-- engine/client/m_multi.c | 175 +++++++++++---- engine/client/menu.c | 31 ++- engine/client/menu.h | 2 +- engine/client/merged.h | 15 +- engine/client/r_2d.c | 17 +- engine/client/render.h | 2 +- engine/client/renderer.c | 3 + engine/client/sbar.c | 1 + engine/client/snd_al.c | 1 + engine/client/sys_win.c | 3 +- engine/client/vid.h | 1 + engine/client/view.c | 3 + engine/client/wad.c | 12 +- engine/common/cmd.c | 47 +++- engine/common/com_mesh.c | 7 +- engine/common/common.h | 19 +- engine/common/cvar.c | 2 + engine/common/fs.c | 137 +++++++++--- engine/common/net_wins.c | 2 +- engine/d3d/d3d11_image.c | 26 ++- engine/d3d/d3d11_shader.c | 3 - engine/d3d/d3d_image.c | 103 +++------ engine/d3d/d3d_shader.c | 15 ++ engine/d3d/vid_d3d11.c | 33 ++- engine/dotnet2005/ftequake.sln | 1 - engine/gl/gl_alias.c | 42 +++- engine/gl/gl_backend.c | 4 +- engine/gl/gl_bloom.c | 2 +- engine/gl/gl_draw.c | 42 +++- engine/gl/gl_model.c | 13 +- engine/gl/gl_rlight.c | 6 + engine/gl/gl_rmain.c | 4 +- engine/gl/gl_shader.c | 21 +- engine/gl/gl_vidcommon.c | 61 +++++- engine/gl/glquake.h | 11 - engine/gl/glsupp.h | 6 + engine/gl/shader.h | 6 +- engine/qclib/execloop.h | 14 +- engine/server/net_preparse.c | 6 +- engine/server/pr_cmds.c | 4 +- engine/server/server.h | 4 +- engine/server/sv_init.c | 6 + engine/server/sv_user.c | 3 +- engine/web/ftejslib.h | 6 +- engine/web/ftejslib.js | 85 +++++++- engine/web/gl_vidweb.c | 18 +- 52 files changed, 1185 insertions(+), 372 deletions(-) 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)