From bae63427a5451ac0b911f7535844e63e3f7dad14 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sat, 6 Apr 2013 03:36:00 +0000 Subject: [PATCH] Desperate attempt to boost framerates with webgl. Models now use static vbos, because we ought to. Yeah yeah, extra memory usage etc. Reduced size of streamed ebo by reallocating on each mesh. Hopefully the browser won't scan so much memory now. Reordered attribute indicies in an attempt to comply with possible absurd gl behaviour that emscripten warns about. Fixed an issue with if statements in shaders. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4289 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/merged.h | 40 ++++++++++- engine/client/r_2d.c | 8 +-- engine/client/renderer.c | 4 ++ engine/common/com_mesh.c | 76 ++++++++++++++++++--- engine/common/com_mesh.h | 28 ++++++-- engine/common/fs_win32.c | 1 + engine/common/net_wins.c | 136 ++++++++++++++++++++++++++----------- engine/common/netinc.h | 1 + engine/d3d/d3d11_backend.c | 12 ++++ engine/d3d/d3d_backend.c | 13 +++- engine/d3d/vid_d3d.c | 5 ++ engine/d3d/vid_d3d11.c | 5 ++ engine/gl/gl_alias.c | 4 +- engine/gl/gl_backend.c | 44 +++++++++--- engine/gl/gl_model.h | 24 ------- engine/gl/gl_shader.c | 6 +- engine/gl/gl_vidcommon.c | 5 ++ engine/gl/shader.h | 22 +++++- 18 files changed, 331 insertions(+), 103 deletions(-) diff --git a/engine/client/merged.h b/engine/client/merged.h index 0514695ef..e8c5611f6 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -185,6 +185,37 @@ typedef struct texid_s texid_tf; #define TEXASSIGNF(d,s) memcpy(&d,&s,sizeof(d)) #define TEXVALID(t) 1 #endif + +//small context for easy vbo creation. +typedef struct +{ + unsigned int maxsize; + unsigned int pos; + int vboid[2]; +} vbobctx_t; + +typedef struct vboarray_s +{ + union + { + void *dummy; +#ifdef GLQUAKE + struct + { + int vbo; + void *addr; + } gl; +#endif +#if defined(D3D9QUAKE) || defined(D3D11QUAKE) + struct + { + void *buff; + unsigned int offs; + } d3d; +#endif + }; +} vboarray_t; + typedef struct texnums_s { texid_t base; texid_t bump; @@ -311,7 +342,10 @@ typedef struct rendererinfo_s { void (*BE_SelectDLight)(struct dlight_s *dl, vec3_t colour); /*check to see if an ent should be drawn for the selected light*/ qboolean (*BE_LightCullModel)(vec3_t org, struct model_s *model); - + void (*BE_VBO_Begin)(vbobctx_t *ctx, unsigned int maxsize); + void (*BE_VBO_Data)(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray); + void (*BE_VBO_Finish)(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray); + void (*BE_VBO_Destroy)(vboarray_t *vearray); char *alignment; } rendererinfo_t; @@ -340,3 +374,7 @@ typedef struct rendererinfo_s { #define BE_DrawMesh_Single rf->BE_DrawMesh_Single #define BE_SubmitMeshes rf->BE_SubmitMeshes #define BE_DrawWorld rf->BE_DrawWorld +#define BE_VBO_Begin rf->BE_VBO_Begin +#define BE_VBO_Data rf->BE_VBO_Data +#define BE_VBO_Finish rf->BE_VBO_Finish +#define BE_VBO_Destroy rf->BE_VBO_Destroy diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 7d2247454..4ab74092a 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -356,13 +356,7 @@ void R2D_Image(float x, float y, float w, float h, float s1, float t1, float s2, { if (!pic) return; -/* - if (w == 0 && h == 0) - { - w = pic->width; - h = pic->height; - } -*/ + draw_mesh_xyz[0][0] = x; draw_mesh_xyz[0][1] = y; draw_mesh_st[0][0] = s1; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 8faba8293..ac0c669c4 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -883,6 +883,10 @@ rendererinfo_t dedicatedrendererinfo = { NULL, NULL, NULL, + NULL, + NULL, + NULL, + NULL, "" }; diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index a2b608e38..1036503be 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -1120,6 +1120,9 @@ struct vec3_t *anorm; vec3_t *anorms; vec3_t *anormt; + + vbo_t vbo; + vbo_t *vbop; } meshcache; //#define SSE_INTRINSICS @@ -1451,7 +1454,7 @@ void Alias_Shutdown(void) meshcache.numcoords = 0; } -qboolean Alias_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, int surfnum, entity_t *e, qboolean usebones) +qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, int surfnum, entity_t *e, qboolean usebones) { extern cvar_t r_nolerp; galiasgroup_t *g1, *g2; @@ -1505,6 +1508,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, int surfnum, ent mesh->normals_array = meshcache.anorm; mesh->snormals_array = meshcache.anorms; mesh->tnormals_array = meshcache.anormt; + *vbop = meshcache.vbop; #ifdef SKELETALMODELS if (meshcache.usebonepose) @@ -1535,6 +1539,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, int surfnum, ent #ifdef SKELETALMODELS meshcache.usebonepose = NULL; + *vbop = meshcache.vbop = NULL; if (inf->ofs_skel_xyz && !inf->ofs_skel_weight) { //if we have skeletal xyz info, but no skeletal weights, then its a partial model that cannot possibly be animated. @@ -1544,6 +1549,20 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, int surfnum, ent mesh->normals_array = (vec3_t*)((char*)inf + inf->ofs_skel_norm); mesh->snormals_array = (vec3_t*)((char*)inf + inf->ofs_skel_svect); mesh->tnormals_array = (vec3_t*)((char*)inf + inf->ofs_skel_tvect); + + meshcache.vbo.indicies = inf->vboindicies; + meshcache.vbo.indexcount = inf->numindexes; + meshcache.vbo.vertcount = inf->numverts; + meshcache.vbo.texcoord = inf->vbotexcoords; + meshcache.vbo.coord = inf->vbo_skel_verts; + memset(&meshcache.vbo.coord2, 0, sizeof(meshcache.vbo.coord2)); + meshcache.vbo.normals = inf->vbo_skel_normals; + meshcache.vbo.svector = inf->vbo_skel_svector; + meshcache.vbo.tvector = inf->vbo_skel_tvector; + meshcache.vbo.bonenums = inf->vbo_skel_bonenum; + meshcache.vbo.boneweights = inf->vbo_skel_bweight; + if (meshcache.vbo.indicies.dummy) + *vbop = meshcache.vbop = &meshcache.vbo; } else if (inf->numbones) { @@ -1669,18 +1688,33 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, int surfnum, ent mesh->snormals_array = (vec3_t *)((char *)p1 + p1->ofssvector); mesh->tnormals_array = (vec3_t *)((char *)p1 + p1->ofstvector); + meshcache.vbo.indicies = inf->vboindicies; + meshcache.vbo.indexcount = inf->numindexes; + meshcache.vbo.vertcount = inf->numverts; + meshcache.vbo.texcoord = inf->vbotexcoords; + meshcache.vbo.normals = p1->vbonormals; + meshcache.vbo.svector = p1->vbosvector; + meshcache.vbo.tvector = p1->vbotvector; + if (p1 == p2 || r_nolerp.ival) { + meshcache.vbo.coord = p1->vboverts; + memset(&meshcache.vbo.coord2, 0, sizeof(meshcache.vbo.coord2)); mesh->xyz_array = (vecV_t *)((char *)p1 + p1->ofsverts); mesh->xyz2_array = NULL; } else { + meshcache.vbo.coord = p1->vboverts; + meshcache.vbo.coord2 = p2->vboverts; mesh->xyz_blendw[0] = 1-lerp; mesh->xyz_blendw[1] = lerp; mesh->xyz_array = (vecV_t *)((char *)p1 + p1->ofsverts); mesh->xyz2_array = (vecV_t *)((char *)p2 + p2->ofsverts); } + + if (meshcache.vbo.indicies.dummy) + *vbop = meshcache.vbop = &meshcache.vbo; } } @@ -1689,6 +1723,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, int surfnum, ent meshcache.anorm = mesh->normals_array; meshcache.anorms = mesh->snormals_array; meshcache.anormt = mesh->tnormals_array; + meshcache.vbop = *vbop; #ifdef SKELETALMODELS if (meshcache.usebonepose) @@ -1969,6 +2004,7 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups) return frames; } +//called for non-skeletal model formats. void Mod_BuildTextureVectors(galiasinfo_t *galias) //vec3_t *vc, vec2_t *tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, index_t *idx, int numidx, int numverts) { @@ -1980,10 +2016,22 @@ void Mod_BuildTextureVectors(galiasinfo_t *galias) vec3_t *nv, *sv, *tv; vec2_t *tc; index_t *idx; + int vbospace = 0; + vbobctx_t vboctx; idx = (index_t*)((char*)galias + galias->ofs_indexes); tc = (vec2_t*)((char*)galias + galias->ofs_st_array); group = (galiasgroup_t*)((char*)galias + galias->groupofs); + + //determine the amount of space we need for our vbos. + vbospace += sizeof(*tc) * galias->numverts; + for (i = 0; i < galias->groups; i++) + { + vbospace += group[i].numposes * galias->numverts * (sizeof(vecV_t)+sizeof(vec3_t)*3); + } + BE_VBO_Begin(&vboctx, vbospace); + BE_VBO_Data(&vboctx, tc, sizeof(*tc) * galias->numverts, &galias->vbotexcoords); + for (i = 0; i < galias->groups; i++, group++) { pose = (galiaspose_t*)((char*)group + group->poseofs); @@ -1991,17 +2039,27 @@ void Mod_BuildTextureVectors(galiasinfo_t *galias) { vc = (vecV_t *)((char*)pose + pose->ofsverts); nv = (vec3_t *)((char*)pose + pose->ofsnormals); - if (pose->ofssvector == 0) - continue; - if (pose->ofstvector == 0) - continue; - sv = (vec3_t *)((char*)pose + pose->ofssvector); - tv = (vec3_t *)((char*)pose + pose->ofstvector); + if (pose->ofssvector != 0 && pose->ofstvector != 0) + { + sv = (vec3_t *)((char*)pose + pose->ofssvector); + tv = (vec3_t *)((char*)pose + pose->ofstvector); - Mod_AccumulateTextureVectors(vc, tc, nv, sv, tv, idx, galias->numindexes); - Mod_NormaliseTextureVectors(nv, sv, tv, galias->numverts); + Mod_AccumulateTextureVectors(vc, tc, nv, sv, tv, idx, galias->numindexes); + Mod_NormaliseTextureVectors(nv, sv, tv, galias->numverts); + } + else + { //shouldn't really happen... make error? + sv = NULL; + tv = NULL; + } + + BE_VBO_Data(&vboctx, vc, sizeof(*vc) * galias->numverts, &pose->vboverts); + BE_VBO_Data(&vboctx, nv, sizeof(*nv) * galias->numverts, &pose->vbonormals); + BE_VBO_Data(&vboctx, sv, sizeof(*sv) * galias->numverts, &pose->vbosvector); + BE_VBO_Data(&vboctx, tv, sizeof(*tv) * galias->numverts, &pose->vbotvector); } } + BE_VBO_Finish(&vboctx, idx, sizeof(*idx) * galias->numindexes, &galias->vboindicies); #endif } diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index e2e0ddcc8..cf8fdfd41 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -47,6 +47,15 @@ typedef struct { int ofs_skel_tvect; int ofs_skel_idx; int ofs_skel_weight; + + vboarray_t vboindicies; + vboarray_t vbotexcoords; + vboarray_t vbo_skel_verts; + vboarray_t vbo_skel_normals; + vboarray_t vbo_skel_svector; + vboarray_t vbo_skel_tvector; + vboarray_t vbo_skel_bonenum; + vboarray_t vbo_skel_bweight; #endif //these exist only in the root mesh. @@ -56,7 +65,8 @@ typedef struct { } galiasinfo_t; //frame is an index into this -typedef struct { +typedef struct +{ #ifdef SKELETALMODELS qboolean isheirachical; //for models with transforms, states that bones need to be transformed from their parent. //this is actually bad, and can result in bones shortening as they interpolate. @@ -68,12 +78,18 @@ typedef struct { char name[64]; } galiasgroup_t; -typedef struct { +typedef struct +{ int ofsverts; #ifndef SERVERONLY int ofsnormals; int ofstvector; int ofssvector; + + vboarray_t vboverts; + vboarray_t vbonormals; + vboarray_t vbosvector; + vboarray_t vbotvector; #endif vec3_t scale; @@ -82,13 +98,15 @@ typedef struct { typedef struct galiasbone_s galiasbone_t; #ifdef SKELETALMODELS -struct galiasbone_s { +struct galiasbone_s +{ char name[32]; int parent; float inverse[12]; }; -typedef struct { +typedef struct +{ //skeletal poses refer to this. int vertexindex; int boneindex; @@ -128,7 +146,7 @@ float *Alias_GetBonePositions(galiasinfo_t *inf, framestate_t *fstate, float *bu #ifdef SKELETALMODELS void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout); #endif -qboolean Alias_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, int surfnum, entity_t *e, qboolean allowskel); +qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, int surfnum, entity_t *e, qboolean allowskel); void Alias_FlushCache(void); void Alias_Shutdown(void); diff --git a/engine/common/fs_win32.c b/engine/common/fs_win32.c index 74de94e17..e64db408e 100644 --- a/engine/common/fs_win32.c +++ b/engine/common/fs_win32.c @@ -13,6 +13,7 @@ #define w32filefuncs osfilefuncs typedef struct { + searchpathfuncs_t funcs; HANDLE changenotification; int hashdepth; char rootpath[1]; diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index d91cb3913..957570db3 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -22,7 +22,6 @@ struct sockaddr; #include "quakedef.h" #include "netinc.h" -#include #ifdef _WIN32 #define USE_GETHOSTNAME_LOCALLISTING @@ -1829,7 +1828,6 @@ qboolean FTENET_NATPMP_GetPacket(struct ftenet_generic_connection_s *con) unsigned int now = Sys_Milliseconds(); if (now - pmp->refreshtime > PMP_POLL_TIME) //weird logic to cope with wrapping { -Con_Printf("nat-pmp refresh (%u - %u > %u)\n", now, pmp->refreshtime, PMP_POLL_TIME); pmp->refreshtime = now; FTENET_NATPMP_Refresh(pmp, pmp->natadr.port, pmp->col); } @@ -2483,13 +2481,16 @@ typedef struct ftenet_tcpconnect_stream_s { enum { - TCPC_UNKNOWN, - TCPC_UNFRAMED, //something else is doing the framing (ie: we're running in emscripten and over some hidden websocket connection) - TCPC_QIZMO, - TCPC_WEBSOCKET + TCPC_UNKNOWN, //waiting to see what they send us. + TCPC_UNFRAMED, //something else is doing the framing (ie: we're running in emscripten and over some hidden websocket connection) + TCPC_HTTPCLIENT, //we're sending a file to this victim. + TCPC_QIZMO, //'qizmo\n' handshake, followed by packets prefixed with a 16bit packet length. + TCPC_WEBSOCKETU, //utf-8 encoded data. + TCPC_WEBSOCKETB, //binary encoded data (subprotocol = 'binary') } clienttype; char inbuffer[3000]; char outbuffer[3000]; + vfsfile_t *file; float timeouttime; netadr_t remoteaddr; struct ftenet_tcpconnect_stream_s *next; @@ -2537,6 +2538,7 @@ void tobase64(unsigned char *out, int outlen, unsigned char *in, int inlen) *out = 0; } +#include "fs.h" int SHA1(char *digest, int maxdigestsize, char *string); qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon) { @@ -2574,11 +2576,17 @@ qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon) //due to the above checks about invalid sockets, the socket is always open for st below. if (st->timeouttime < timeval) + { + Con_Printf ("tcp peer %s timed out\n", NET_AdrToString (adr, sizeof(adr), st->remoteaddr)); goto closesvstream; + } ret = recv(st->socketnum, st->inbuffer+st->inlen, sizeof(st->inbuffer)-st->inlen, 0); if (ret == 0) + { + Con_Printf ("tcp peer %s closed connection\n", NET_AdrToString (adr, sizeof(adr), st->remoteaddr)); goto closesvstream; + } else if (ret == -1) { err = qerrno; @@ -2748,12 +2756,12 @@ closesvstream: //optionally will be Origin=url, Sec-WebSocket-Protocol=FTEWebSocket, Sec-WebSocket-Extensions //other fields will be ignored. - //FIXME: reply with 426 Upgrade Required if wsversion is not supported - - if (!stricmp(arg[WCATTR_UPGRADE], "websocket") && !stricmp(arg[WCATTR_CONNECTION], "Upgrade")) + if (!stricmp(arg[WCATTR_UPGRADE], "websocket") && (!stricmp(arg[WCATTR_CONNECTION], "Upgrade") || !stricmp(arg[WCATTR_CONNECTION], "keep-alive, Upgrade"))) { if (atoi(arg[WCATTR_WSVER]) != 13) { + Con_Printf("Outdated websocket request from %s. got version %i, expected version 13\n", arg[WCATTR_URL], NET_AdrToString (adr, sizeof(adr), st->remoteaddr), arg[WCATTR_WSVER]); + memmove(st->inbuffer, st->inbuffer+i, st->inlen - (i)); st->inlen -= i; resp = va( "HTTP/1.1 426 Upgrade Required\r\n" @@ -2773,6 +2781,8 @@ closesvstream: tobase64(acceptkey, sizeof(acceptkey), sha1digest, SHA1(sha1digest, sizeof(sha1digest), va("%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", arg[WCATTR_WSKEY]))); + Con_Printf("Websocket request for %s from %s\n", arg[WCATTR_URL], NET_AdrToString (adr, sizeof(adr), st->remoteaddr)); + resp = va( "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" @@ -2783,7 +2793,10 @@ closesvstream: send(st->socketnum, resp, strlen(resp), 0); //and the connection is okay - st->clienttype = TCPC_WEBSOCKET; + if (!strcmp(arg[WCATTR_WSPROTO], "binary")) + st->clienttype = TCPC_WEBSOCKETB; //emscripten doesn't give us a choice, but its compact. + else + st->clienttype = TCPC_WEBSOCKETU; //nacl supports only utf-8 encoded data, at least at the time I implemented it. } } else @@ -2814,19 +2827,23 @@ closesvstream: "" ); } - /*else if (!strcmp(arg[WCATTR_URL], "/index.html") || !strcmp(arg[WCATTR_URL], "/")) +/* else if ((!strcmp(arg[WCATTR_URL], "/ftewebgl.html") || !strcmp(arg[WCATTR_URL], "/ftewebgl.html.fmf") || !strcmp(arg[WCATTR_URL], "/pak0.pak")) && ((st->file = VFSOS_Open(va("C:/Incoming/vm%s", arg[WCATTR_URL]), "rb")))) { + Con_Printf("Downloading %s to %s\n", arg[WCATTR_URL], NET_AdrToString (adr, sizeof(adr), st->remoteaddr)); resp = va( "HTTP/1.1 200 Ok\r\n" - "Connection: Close\r\n" "Content-Type: text/html\r\n" - "\r\n" - - "This is a Quake WebSocket server, not an http server.
\r\n" - ""FULLENGINENAME"" + "Content-Length: %i\r\n" + "\r\n", + VFS_GETLEN(st->file) ); - }*/ + send(st->socketnum, resp, strlen(resp), 0); + st->clienttype = TCPC_HTTPCLIENT; + continue; + } +*/ else { + Con_Printf("Invalid download request %s to %s\n", arg[WCATTR_URL], NET_AdrToString (adr, sizeof(adr), st->remoteaddr)); resp = va( "HTTP/1.1 404 Ok\r\n" "Connection: Close\r\n" "Content-Type: text/html\r\n" @@ -2852,6 +2869,31 @@ handshakeerror: } break; + case TCPC_HTTPCLIENT: + if (st->outlen) + { /*try and flush the old data*/ + int done; + done = send(st->socketnum, st->outbuffer, st->outlen, 0); + if (done > 0) + { + memmove(st->outbuffer, st->outbuffer + done, st->outlen - done); + st->outlen -= done; + + st->timeouttime = timeval + 30; + } + } + if (!st->outlen) + { + st->outlen = VFS_READ(st->file, st->outbuffer, sizeof(st->outbuffer)); + if (st->outlen <= 0) + { + VFS_CLOSE(st->file); + st->file = NULL; + st->clienttype = TCPC_UNKNOWN; + Con_Printf ("Outgoing file transfer complete\n"); + } + } + continue; case TCPC_QIZMO: if (st->inlen < 2) continue; @@ -2887,7 +2929,8 @@ handshakeerror: net_message.currentbit = 0; net_from = st->remoteaddr; return true; - case TCPC_WEBSOCKET: + case TCPC_WEBSOCKETU: + case TCPC_WEBSOCKETB: while (st->inlen >= 2) { unsigned short ctrl = ((unsigned char*)st->inbuffer)[0]<<8 | ((unsigned char*)st->inbuffer)[1]; @@ -3008,7 +3051,7 @@ handshakeerror: } break; case 2: /*binary frame*/ - Con_Printf ("websocket binary frame from %s\n", NET_AdrToString (adr, sizeof(adr), st->remoteaddr)); +// Con_Printf ("websocket binary frame from %s\n", NET_AdrToString (adr, sizeof(adr), st->remoteaddr)); net_message.cursize = paylen; if (net_message.cursize >= sizeof(net_message_buffer) ) { @@ -3119,16 +3162,25 @@ qboolean FTENET_TCPConnect_SendPacket(ftenet_generic_connection_t *gcon, int len memcpy(st->outbuffer, data, length); st->outlen = length; break; - case TCPC_WEBSOCKET: + case TCPC_WEBSOCKETU: + case TCPC_WEBSOCKETB: { /*as a server, we don't need the mask stuff*/ - unsigned short ctrl = 0x8100; + unsigned short ctrl = (st->clienttype==TCPC_WEBSOCKETB)?0x8200:0x8100; unsigned int paylen = 0; unsigned int payoffs = 2; int i; - for (i = 0; i < length; i++) + switch((ctrl>>8) & 0xf) { - paylen += (((char*)data)[i] == 0 || ((unsigned char*)data)[i] >= 0x80)?2:1; + case 1: + for (i = 0; i < length; i++) + { + paylen += (((char*)data)[i] == 0 || ((unsigned char*)data)[i] >= 0x80)?2:1; + } + break; + default: + paylen = length; + break; } if (paylen >= 126) { @@ -3145,23 +3197,31 @@ qboolean FTENET_TCPConnect_SendPacket(ftenet_generic_connection_t *gcon, int len st->outbuffer[2] = paylen>>8; st->outbuffer[3] = paylen&0xff; } - /*utf8ify the data*/ - for (i = 0; i < length; i++) + switch((ctrl>>8) & 0xf) { - if (!((unsigned char*)data)[i]) - { /*0 is encoded as 0x100 to avoid safety checks*/ - st->outbuffer[payoffs++] = 0xc0 | (0x100>>6); - st->outbuffer[payoffs++] = 0x80 | (0x100&0x3f); - } - else if (((unsigned char*)data)[i] >= 0x80) - { /*larger bytes require markup*/ - st->outbuffer[payoffs++] = 0xc0 | (((unsigned char*)data)[i]>>6); - st->outbuffer[payoffs++] = 0x80 | (((unsigned char*)data)[i]&0x3f); - } - else - { /*lower 7 bits are as-is*/ - st->outbuffer[payoffs++] = ((char*)data)[i]; + case 1:/*utf8ify the data*/ + for (i = 0; i < length; i++) + { + if (!((unsigned char*)data)[i]) + { /*0 is encoded as 0x100 to avoid safety checks*/ + st->outbuffer[payoffs++] = 0xc0 | (0x100>>6); + st->outbuffer[payoffs++] = 0x80 | (0x100&0x3f); + } + else if (((unsigned char*)data)[i] >= 0x80) + { /*larger bytes require markup*/ + st->outbuffer[payoffs++] = 0xc0 | (((unsigned char*)data)[i]>>6); + st->outbuffer[payoffs++] = 0x80 | (((unsigned char*)data)[i]&0x3f); + } + else + { /*lower 7 bits are as-is*/ + st->outbuffer[payoffs++] = ((char*)data)[i]; + } } + break; + default: //raw data + memcpy(st->outbuffer+payoffs, data, length); + payoffs += length; + break; } st->outlen = payoffs; } diff --git a/engine/common/netinc.h b/engine/common/netinc.h index 02dae0cca..e8e69461e 100644 --- a/engine/common/netinc.h +++ b/engine/common/netinc.h @@ -126,6 +126,7 @@ #include #include #include + #include #include #include diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index d765b148e..72487a2f8 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -2915,5 +2915,17 @@ void D3D11BE_DrawWorld (qboolean drawworld, qbyte *vis) BE_RotateForEntity(&r_worldentity, NULL); } +void D3D11BE_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize) +{ +} +void D3D11BE_VBO_Data(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray) +{ +} +void D3D11BE_VBO_Finish(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray) +{ +} +void D3D11BE_VBO_Destroy(vboarray_t *vearray) +{ +} #endif diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index 3b771e833..e8f1c9a58 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -3162,6 +3162,17 @@ void D3D9BE_DrawWorld (qboolean drawworld, qbyte *vis) BE_RotateForEntity(&r_worldentity, NULL); } - +void D3D9BE_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize) +{ +} +void D3D9BE_VBO_Data(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray) +{ +} +void D3D9BE_VBO_Finish(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray) +{ +} +void D3D9BE_VBO_Destroy(vboarray_t *vearray) +{ +} #endif diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index ff75cbe6f..6747e4af9 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -1311,6 +1311,11 @@ rendererinfo_t d3d9rendererinfo = D3D9BE_SelectDLight, D3D9BE_LightCullModel, + D3D9BE_VBO_Begin, + D3D9BE_VBO_Data, + D3D9BE_VBO_Finish, + D3D9BE_VBO_Destroy, + "no more" }; diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index 17d635f94..16816e68a 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -1386,6 +1386,11 @@ rendererinfo_t d3d11rendererinfo = D3D11BE_SelectDLight, D3D11BE_LightCullModel, + D3D11BE_VBO_Begin, + D3D11BE_VBO_Data, + D3D11BE_VBO_Finish, + D3D11BE_VBO_Destroy, + "no more" }; #endif diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index 212096bd8..3797ad673 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -968,7 +968,7 @@ void R_GAlias_DrawBatch(batch_t *batch) { if (batch->surf_first == surfnum) { - needrecolour = Alias_GAliasBuildMesh(&mesh, inf, surfnum, e, batch->shader->prog && batch->shader->prog->permu[PERMUTATION_SKELETAL].handle.glsl); + needrecolour = Alias_GAliasBuildMesh(&mesh, &batch->vbo, inf, surfnum, e, batch->shader->prog && batch->shader->prog->permu[PERMUTATION_SKELETAL].handle.glsl); batch->mesh = &meshl; return; } @@ -1387,7 +1387,7 @@ void R_DrawGAliasShadowVolume(entity_t *e, vec3_t lightpos, float radius) { if (inf->ofs_trineighbours) { - Alias_GAliasBuildMesh(&mesh, inf, surfnum, e, false); + Alias_GAliasBuildMesh(&mesh, NULL, inf, surfnum, e, false); R_CalcFacing(&mesh, lightorg); R_ProjectShadowVolume(&mesh, lightorg); R_DrawShadowVolume(&mesh); diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 137d5f114..beaeb445a 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -149,8 +149,6 @@ struct { unsigned int streamvbo_offset; unsigned int streamvbo_length; int streamebo; - unsigned int streamebo_offset; - unsigned int streamebo_length; int pendingtexcoordparts[SHADER_TMU_MAX]; int pendingtexcoordvbo[SHADER_TMU_MAX]; @@ -1333,7 +1331,6 @@ void GLBE_Init(void) qglGenBuffersARB(1, &shaderstate.streamvbo); qglGenBuffersARB(1, &shaderstate.streamebo); shaderstate.streamvbo_length = shaderstate.streamvbo_offset = 65536*16 * 64*sizeof(vec_t); - shaderstate.streamebo_length = shaderstate.streamebo_offset = 65536*16 * sizeof(index_t); } #endif } @@ -3830,15 +3827,9 @@ static qboolean BE_GenTempMeshVBO(vbo_t **vbo, mesh_t *m) } //and finally the elements array, which is a much simpler affair - if (shaderstate.streamebo_offset + m->numindexes*sizeof(*m->indexes)) - { - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, shaderstate.streamebo_length, NULL, GL_STREAM_DRAW_ARB); - shaderstate.streamebo_offset = 0; - } - qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, shaderstate.streamebo_offset, sizeof(*m->indexes) * m->numindexes, m->indexes); - shaderstate.dummyvbo.indicies.gl.addr = (void*)shaderstate.streamebo_offset; + qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(*m->indexes) * m->numindexes, m->indexes, GL_STREAM_DRAW_ARB); + shaderstate.dummyvbo.indicies.gl.addr = (void*)NULL; shaderstate.dummyvbo.indicies.gl.vbo = shaderstate.streamebo; - shaderstate.streamebo_offset += sizeof(*m->indexes) * m->numindexes; } else { @@ -4847,4 +4838,35 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis) TRACE(("GLBE_DrawWorld: drawn everything\n")); } + +void GLBE_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize) +{ + ctx->maxsize = maxsize; + ctx->pos = 0; + qglGenBuffersARB(2, ctx->vboid); + GL_SelectVBO(ctx->vboid[0]); + //WARNING: in emscripten/webgl, we should probably not pass null. + qglBufferDataARB(GL_ARRAY_BUFFER_ARB, ctx->maxsize, NULL, GL_STATIC_DRAW_ARB); +} +void GLBE_VBO_Data(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray) +{ + qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, ctx->pos, size, data); + varray->gl.vbo = ctx->vboid[0]; + varray->gl.addr = (void*)ctx->pos; + ctx->pos += size; +} + +void GLBE_VBO_Finish(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray) +{ + if (ctx->pos > ctx->maxsize) + Sys_Error("BE_VBO_Finish: too much data given\n"); + GL_SelectEBO(ctx->vboid[1]); + qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, esize, edata, GL_STATIC_DRAW_ARB); + earray->gl.vbo = ctx->vboid[1]; + earray->gl.addr = NULL; +} +void GLBE_VBO_Destroy(vboarray_t *vearray) +{ + qglDeleteBuffersARB(1, &vearray->gl.vbo); +} #endif diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index d73c6bf30..c2b970715 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -242,30 +242,6 @@ typedef struct mplane_s qbyte pad[2]; } mplane_t; -typedef struct vboarray_s -{ - union - { - void *dummy; - -#ifdef GLQUAKE - struct - { - int vbo; - void *addr; - } gl; -#endif - -#if defined(D3D9QUAKE) || defined(D3D11QUAKE) - struct - { - void *buff; - unsigned int offs; - } d3d; -#endif - }; -} vboarray_t; - typedef struct vbo_s { unsigned int numvisible; diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 12ee42c96..1b160f168 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -373,7 +373,8 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr) Con_Printf("Shader_EvaluateCondition: '%s' is not a cvar\n", token); return conditiontrue; } - token = COM_ParseExt(ptr, false, false); + if (*token) + token = COM_ParseExt(ptr, false, false); cv->flags |= CVAR_SHADERSYSTEM; if (*token) { @@ -403,7 +404,8 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr) conditiontrue = conditiontrue == !!cv->value; } } - token = COM_ParseExt(ptr, false, false); + if (*token) + token = COM_ParseExt(ptr, false, false); if (!strcmp(token, "&&")) return Shader_EvaluateCondition(shader, ptr) && conditiontrue; if (!strcmp(token, "||")) diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index b1a60addf..7fd71411f 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -1708,6 +1708,11 @@ rendererinfo_t openglrendererinfo = { GLBE_SelectDLight, GLBE_LightCullModel, + GLBE_VBO_Begin, + GLBE_VBO_Data, + GLBE_VBO_Finish, + GLBE_VBO_Destroy, + "" }; diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 61bb3e993..900d73763 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -275,8 +275,6 @@ enum{ enum shaderattribs_e { - VATTR_LEG_VERTEX, - VATTR_VERTEX1, VATTR_VERTEX2, VATTR_COLOUR, @@ -291,12 +289,18 @@ enum shaderattribs_e VATTR_LMCOORD3, VATTR_LMCOORD4, + VATTR_LEG_VERTEX, //note: traditionally this is actually index 0. + //however, implementations are allowed to directly alias, or remap, + //so we're never quite sure if 0 is enabled or not when using legacy functions. + //as a result, we use legacy verticies always and never custom attribute 0 if we have any fixed function support. + //we then depend upon gl_Vertex always being supported by the glsl compiler. + //this is likely needed anyway to ensure that ftransform works properly and in all cases for stencil shadows. VATTR_LEG_COLOUR, VATTR_LEG_ELEMENTS, VATTR_LEG_TMU0, - VATTR_LEG_FIRST=VATTR_LEG_COLOUR + VATTR_LEG_FIRST=VATTR_LEG_VERTEX }; typedef struct { @@ -514,6 +518,10 @@ void GLBE_SelectEntity(entity_t *ent); void GLBE_SelectDLight(dlight_t *dl, vec3_t colour); void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop); void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destcol, texid_t destdepth, qboolean usedepth); +void GLBE_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize); +void GLBE_VBO_Data(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray); +void GLBE_VBO_Finish(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray); +void GLBE_VBO_Destroy(vboarray_t *vearray); #endif #ifdef D3D9QUAKE void D3D9BE_Init(void); @@ -530,6 +538,10 @@ void D3D9BE_DrawWorld (qboolean drawworld, qbyte *vis); qboolean D3D9BE_LightCullModel(vec3_t org, model_t *model); void D3D9BE_SelectEntity(entity_t *ent); void D3D9BE_SelectDLight(dlight_t *dl, vec3_t colour); +void D3D9BE_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize); +void D3D9BE_VBO_Data(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray); +void D3D9BE_VBO_Finish(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray); +void D3D9BE_VBO_Destroy(vboarray_t *vearray); qboolean D3D9Shader_CreateProgram (program_t *prog, char *sname, int permu, char **precompilerconstants, char *vert, char *frag); int D3D9Shader_FindUniform(union programhandle_u *h, int type, char *name); @@ -558,6 +570,10 @@ void D3D11Shader_Init(void); void D3D11BE_Reset(qboolean before); void D3D11BE_SetupViewCBuffer(void); void D3D11_UploadLightmap(lightmapinfo_t *lm); +void D3D11BE_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize); +void D3D11BE_VBO_Data(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray); +void D3D11BE_VBO_Finish(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray); +void D3D11BE_VBO_Destroy(vboarray_t *vearray); #endif //Asks the backend to invoke DrawMeshChain for each surface, and to upload lightmaps as required