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
This commit is contained in:
Spoike 2013-04-06 03:36:00 +00:00
parent 90b07d7bb6
commit bae63427a5
18 changed files with 331 additions and 103 deletions

View File

@ -185,6 +185,37 @@ typedef struct texid_s texid_tf;
#define TEXASSIGNF(d,s) memcpy(&d,&s,sizeof(d)) #define TEXASSIGNF(d,s) memcpy(&d,&s,sizeof(d))
#define TEXVALID(t) 1 #define TEXVALID(t) 1
#endif #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 { typedef struct texnums_s {
texid_t base; texid_t base;
texid_t bump; texid_t bump;
@ -311,7 +342,10 @@ typedef struct rendererinfo_s {
void (*BE_SelectDLight)(struct dlight_s *dl, vec3_t colour); void (*BE_SelectDLight)(struct dlight_s *dl, vec3_t colour);
/*check to see if an ent should be drawn for the selected light*/ /*check to see if an ent should be drawn for the selected light*/
qboolean (*BE_LightCullModel)(vec3_t org, struct model_s *model); 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; char *alignment;
} rendererinfo_t; } rendererinfo_t;
@ -340,3 +374,7 @@ typedef struct rendererinfo_s {
#define BE_DrawMesh_Single rf->BE_DrawMesh_Single #define BE_DrawMesh_Single rf->BE_DrawMesh_Single
#define BE_SubmitMeshes rf->BE_SubmitMeshes #define BE_SubmitMeshes rf->BE_SubmitMeshes
#define BE_DrawWorld rf->BE_DrawWorld #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

View File

@ -356,13 +356,7 @@ void R2D_Image(float x, float y, float w, float h, float s1, float t1, float s2,
{ {
if (!pic) if (!pic)
return; return;
/*
if (w == 0 && h == 0)
{
w = pic->width;
h = pic->height;
}
*/
draw_mesh_xyz[0][0] = x; draw_mesh_xyz[0][0] = x;
draw_mesh_xyz[0][1] = y; draw_mesh_xyz[0][1] = y;
draw_mesh_st[0][0] = s1; draw_mesh_st[0][0] = s1;

View File

@ -883,6 +883,10 @@ rendererinfo_t dedicatedrendererinfo = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL,
NULL,
NULL,
NULL,
"" ""
}; };

View File

@ -1120,6 +1120,9 @@ struct
vec3_t *anorm; vec3_t *anorm;
vec3_t *anorms; vec3_t *anorms;
vec3_t *anormt; vec3_t *anormt;
vbo_t vbo;
vbo_t *vbop;
} meshcache; } meshcache;
//#define SSE_INTRINSICS //#define SSE_INTRINSICS
@ -1451,7 +1454,7 @@ void Alias_Shutdown(void)
meshcache.numcoords = 0; 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; extern cvar_t r_nolerp;
galiasgroup_t *g1, *g2; 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->normals_array = meshcache.anorm;
mesh->snormals_array = meshcache.anorms; mesh->snormals_array = meshcache.anorms;
mesh->tnormals_array = meshcache.anormt; mesh->tnormals_array = meshcache.anormt;
*vbop = meshcache.vbop;
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
if (meshcache.usebonepose) if (meshcache.usebonepose)
@ -1535,6 +1539,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, int surfnum, ent
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
meshcache.usebonepose = NULL; meshcache.usebonepose = NULL;
*vbop = meshcache.vbop = NULL;
if (inf->ofs_skel_xyz && !inf->ofs_skel_weight) 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. //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->normals_array = (vec3_t*)((char*)inf + inf->ofs_skel_norm);
mesh->snormals_array = (vec3_t*)((char*)inf + inf->ofs_skel_svect); mesh->snormals_array = (vec3_t*)((char*)inf + inf->ofs_skel_svect);
mesh->tnormals_array = (vec3_t*)((char*)inf + inf->ofs_skel_tvect); 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) 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->snormals_array = (vec3_t *)((char *)p1 + p1->ofssvector);
mesh->tnormals_array = (vec3_t *)((char *)p1 + p1->ofstvector); 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) 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->xyz_array = (vecV_t *)((char *)p1 + p1->ofsverts);
mesh->xyz2_array = NULL; mesh->xyz2_array = NULL;
} }
else else
{ {
meshcache.vbo.coord = p1->vboverts;
meshcache.vbo.coord2 = p2->vboverts;
mesh->xyz_blendw[0] = 1-lerp; mesh->xyz_blendw[0] = 1-lerp;
mesh->xyz_blendw[1] = lerp; mesh->xyz_blendw[1] = lerp;
mesh->xyz_array = (vecV_t *)((char *)p1 + p1->ofsverts); mesh->xyz_array = (vecV_t *)((char *)p1 + p1->ofsverts);
mesh->xyz2_array = (vecV_t *)((char *)p2 + p2->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.anorm = mesh->normals_array;
meshcache.anorms = mesh->snormals_array; meshcache.anorms = mesh->snormals_array;
meshcache.anormt = mesh->tnormals_array; meshcache.anormt = mesh->tnormals_array;
meshcache.vbop = *vbop;
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
if (meshcache.usebonepose) if (meshcache.usebonepose)
@ -1969,6 +2004,7 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
return frames; return frames;
} }
//called for non-skeletal model formats.
void Mod_BuildTextureVectors(galiasinfo_t *galias) 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) //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; vec3_t *nv, *sv, *tv;
vec2_t *tc; vec2_t *tc;
index_t *idx; index_t *idx;
int vbospace = 0;
vbobctx_t vboctx;
idx = (index_t*)((char*)galias + galias->ofs_indexes); idx = (index_t*)((char*)galias + galias->ofs_indexes);
tc = (vec2_t*)((char*)galias + galias->ofs_st_array); tc = (vec2_t*)((char*)galias + galias->ofs_st_array);
group = (galiasgroup_t*)((char*)galias + galias->groupofs); 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++) for (i = 0; i < galias->groups; i++, group++)
{ {
pose = (galiaspose_t*)((char*)group + group->poseofs); pose = (galiaspose_t*)((char*)group + group->poseofs);
@ -1991,17 +2039,27 @@ void Mod_BuildTextureVectors(galiasinfo_t *galias)
{ {
vc = (vecV_t *)((char*)pose + pose->ofsverts); vc = (vecV_t *)((char*)pose + pose->ofsverts);
nv = (vec3_t *)((char*)pose + pose->ofsnormals); nv = (vec3_t *)((char*)pose + pose->ofsnormals);
if (pose->ofssvector == 0) if (pose->ofssvector != 0 && pose->ofstvector != 0)
continue; {
if (pose->ofstvector == 0) sv = (vec3_t *)((char*)pose + pose->ofssvector);
continue; tv = (vec3_t *)((char*)pose + pose->ofstvector);
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_AccumulateTextureVectors(vc, tc, nv, sv, tv, idx, galias->numindexes);
Mod_NormaliseTextureVectors(nv, sv, tv, galias->numverts); 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 #endif
} }

View File

@ -47,6 +47,15 @@ typedef struct {
int ofs_skel_tvect; int ofs_skel_tvect;
int ofs_skel_idx; int ofs_skel_idx;
int ofs_skel_weight; 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 #endif
//these exist only in the root mesh. //these exist only in the root mesh.
@ -56,7 +65,8 @@ typedef struct {
} galiasinfo_t; } galiasinfo_t;
//frame is an index into this //frame is an index into this
typedef struct { typedef struct
{
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
qboolean isheirachical; //for models with transforms, states that bones need to be transformed from their parent. 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. //this is actually bad, and can result in bones shortening as they interpolate.
@ -68,12 +78,18 @@ typedef struct {
char name[64]; char name[64];
} galiasgroup_t; } galiasgroup_t;
typedef struct { typedef struct
{
int ofsverts; int ofsverts;
#ifndef SERVERONLY #ifndef SERVERONLY
int ofsnormals; int ofsnormals;
int ofstvector; int ofstvector;
int ofssvector; int ofssvector;
vboarray_t vboverts;
vboarray_t vbonormals;
vboarray_t vbosvector;
vboarray_t vbotvector;
#endif #endif
vec3_t scale; vec3_t scale;
@ -82,13 +98,15 @@ typedef struct {
typedef struct galiasbone_s galiasbone_t; typedef struct galiasbone_s galiasbone_t;
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
struct galiasbone_s { struct galiasbone_s
{
char name[32]; char name[32];
int parent; int parent;
float inverse[12]; float inverse[12];
}; };
typedef struct { typedef struct
{
//skeletal poses refer to this. //skeletal poses refer to this.
int vertexindex; int vertexindex;
int boneindex; int boneindex;
@ -128,7 +146,7 @@ float *Alias_GetBonePositions(galiasinfo_t *inf, framestate_t *fstate, float *bu
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout); void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout);
#endif #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_FlushCache(void);
void Alias_Shutdown(void); void Alias_Shutdown(void);

View File

@ -13,6 +13,7 @@
#define w32filefuncs osfilefuncs #define w32filefuncs osfilefuncs
typedef struct { typedef struct {
searchpathfuncs_t funcs;
HANDLE changenotification; HANDLE changenotification;
int hashdepth; int hashdepth;
char rootpath[1]; char rootpath[1];

View File

@ -22,7 +22,6 @@ struct sockaddr;
#include "quakedef.h" #include "quakedef.h"
#include "netinc.h" #include "netinc.h"
#include <sys/time.h>
#ifdef _WIN32 #ifdef _WIN32
#define USE_GETHOSTNAME_LOCALLISTING #define USE_GETHOSTNAME_LOCALLISTING
@ -1829,7 +1828,6 @@ qboolean FTENET_NATPMP_GetPacket(struct ftenet_generic_connection_s *con)
unsigned int now = Sys_Milliseconds(); unsigned int now = Sys_Milliseconds();
if (now - pmp->refreshtime > PMP_POLL_TIME) //weird logic to cope with wrapping 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; pmp->refreshtime = now;
FTENET_NATPMP_Refresh(pmp, pmp->natadr.port, pmp->col); FTENET_NATPMP_Refresh(pmp, pmp->natadr.port, pmp->col);
} }
@ -2483,13 +2481,16 @@ typedef struct ftenet_tcpconnect_stream_s {
enum enum
{ {
TCPC_UNKNOWN, 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_UNFRAMED, //something else is doing the framing (ie: we're running in emscripten and over some hidden websocket connection)
TCPC_QIZMO, TCPC_HTTPCLIENT, //we're sending a file to this victim.
TCPC_WEBSOCKET 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; } clienttype;
char inbuffer[3000]; char inbuffer[3000];
char outbuffer[3000]; char outbuffer[3000];
vfsfile_t *file;
float timeouttime; float timeouttime;
netadr_t remoteaddr; netadr_t remoteaddr;
struct ftenet_tcpconnect_stream_s *next; struct ftenet_tcpconnect_stream_s *next;
@ -2537,6 +2538,7 @@ void tobase64(unsigned char *out, int outlen, unsigned char *in, int inlen)
*out = 0; *out = 0;
} }
#include "fs.h"
int SHA1(char *digest, int maxdigestsize, char *string); int SHA1(char *digest, int maxdigestsize, char *string);
qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon) 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. //due to the above checks about invalid sockets, the socket is always open for st below.
if (st->timeouttime < timeval) if (st->timeouttime < timeval)
{
Con_Printf ("tcp peer %s timed out\n", NET_AdrToString (adr, sizeof(adr), st->remoteaddr));
goto closesvstream; goto closesvstream;
}
ret = recv(st->socketnum, st->inbuffer+st->inlen, sizeof(st->inbuffer)-st->inlen, 0); ret = recv(st->socketnum, st->inbuffer+st->inlen, sizeof(st->inbuffer)-st->inlen, 0);
if (ret == 0) if (ret == 0)
{
Con_Printf ("tcp peer %s closed connection\n", NET_AdrToString (adr, sizeof(adr), st->remoteaddr));
goto closesvstream; goto closesvstream;
}
else if (ret == -1) else if (ret == -1)
{ {
err = qerrno; err = qerrno;
@ -2748,12 +2756,12 @@ closesvstream:
//optionally will be Origin=url, Sec-WebSocket-Protocol=FTEWebSocket, Sec-WebSocket-Extensions //optionally will be Origin=url, Sec-WebSocket-Protocol=FTEWebSocket, Sec-WebSocket-Extensions
//other fields will be ignored. //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") || !stricmp(arg[WCATTR_CONNECTION], "keep-alive, Upgrade")))
if (!stricmp(arg[WCATTR_UPGRADE], "websocket") && !stricmp(arg[WCATTR_CONNECTION], "Upgrade"))
{ {
if (atoi(arg[WCATTR_WSVER]) != 13) 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)); memmove(st->inbuffer, st->inbuffer+i, st->inlen - (i));
st->inlen -= i; st->inlen -= i;
resp = va( "HTTP/1.1 426 Upgrade Required\r\n" 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]))); 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" resp = va( "HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n" "Upgrade: websocket\r\n"
"Connection: Upgrade\r\n" "Connection: Upgrade\r\n"
@ -2783,7 +2793,10 @@ closesvstream:
send(st->socketnum, resp, strlen(resp), 0); send(st->socketnum, resp, strlen(resp), 0);
//and the connection is okay //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 else
@ -2814,19 +2827,23 @@ closesvstream:
"</html>" "</html>"
); );
} }
/*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" resp = va( "HTTP/1.1 200 Ok\r\n"
"Connection: Close\r\n"
"Content-Type: text/html\r\n" "Content-Type: text/html\r\n"
"\r\n" "Content-Length: %i\r\n"
"\r\n",
"This is a Quake WebSocket server, not an http server.<br/>\r\n" VFS_GETLEN(st->file)
"<a href='"ENGINEWEBSITE"'>"FULLENGINENAME"</a>"
); );
}*/ send(st->socketnum, resp, strlen(resp), 0);
st->clienttype = TCPC_HTTPCLIENT;
continue;
}
*/
else 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" resp = va( "HTTP/1.1 404 Ok\r\n"
"Connection: Close\r\n" "Connection: Close\r\n"
"Content-Type: text/html\r\n" "Content-Type: text/html\r\n"
@ -2852,6 +2869,31 @@ handshakeerror:
} }
break; 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: case TCPC_QIZMO:
if (st->inlen < 2) if (st->inlen < 2)
continue; continue;
@ -2887,7 +2929,8 @@ handshakeerror:
net_message.currentbit = 0; net_message.currentbit = 0;
net_from = st->remoteaddr; net_from = st->remoteaddr;
return true; return true;
case TCPC_WEBSOCKET: case TCPC_WEBSOCKETU:
case TCPC_WEBSOCKETB:
while (st->inlen >= 2) while (st->inlen >= 2)
{ {
unsigned short ctrl = ((unsigned char*)st->inbuffer)[0]<<8 | ((unsigned char*)st->inbuffer)[1]; unsigned short ctrl = ((unsigned char*)st->inbuffer)[0]<<8 | ((unsigned char*)st->inbuffer)[1];
@ -3008,7 +3051,7 @@ handshakeerror:
} }
break; break;
case 2: /*binary frame*/ 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; net_message.cursize = paylen;
if (net_message.cursize >= sizeof(net_message_buffer) ) 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); memcpy(st->outbuffer, data, length);
st->outlen = length; st->outlen = length;
break; break;
case TCPC_WEBSOCKET: case TCPC_WEBSOCKETU:
case TCPC_WEBSOCKETB:
{ {
/*as a server, we don't need the mask stuff*/ /*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 paylen = 0;
unsigned int payoffs = 2; unsigned int payoffs = 2;
int i; 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) 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[2] = paylen>>8;
st->outbuffer[3] = paylen&0xff; st->outbuffer[3] = paylen&0xff;
} }
/*utf8ify the data*/ switch((ctrl>>8) & 0xf)
for (i = 0; i < length; i++)
{ {
if (!((unsigned char*)data)[i]) case 1:/*utf8ify the data*/
{ /*0 is encoded as 0x100 to avoid safety checks*/ for (i = 0; i < length; i++)
st->outbuffer[payoffs++] = 0xc0 | (0x100>>6); {
st->outbuffer[payoffs++] = 0x80 | (0x100&0x3f); if (!((unsigned char*)data)[i])
} { /*0 is encoded as 0x100 to avoid safety checks*/
else if (((unsigned char*)data)[i] >= 0x80) st->outbuffer[payoffs++] = 0xc0 | (0x100>>6);
{ /*larger bytes require markup*/ st->outbuffer[payoffs++] = 0x80 | (0x100&0x3f);
st->outbuffer[payoffs++] = 0xc0 | (((unsigned char*)data)[i]>>6); }
st->outbuffer[payoffs++] = 0x80 | (((unsigned char*)data)[i]&0x3f); else if (((unsigned char*)data)[i] >= 0x80)
} { /*larger bytes require markup*/
else st->outbuffer[payoffs++] = 0xc0 | (((unsigned char*)data)[i]>>6);
{ /*lower 7 bits are as-is*/ st->outbuffer[payoffs++] = 0x80 | (((unsigned char*)data)[i]&0x3f);
st->outbuffer[payoffs++] = ((char*)data)[i]; }
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; st->outlen = payoffs;
} }

View File

@ -126,6 +126,7 @@
#include <netdb.h> #include <netdb.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <sys/time.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>

View File

@ -2915,5 +2915,17 @@ void D3D11BE_DrawWorld (qboolean drawworld, qbyte *vis)
BE_RotateForEntity(&r_worldentity, NULL); 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 #endif

View File

@ -3162,6 +3162,17 @@ void D3D9BE_DrawWorld (qboolean drawworld, qbyte *vis)
BE_RotateForEntity(&r_worldentity, NULL); 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 #endif

View File

@ -1311,6 +1311,11 @@ rendererinfo_t d3d9rendererinfo =
D3D9BE_SelectDLight, D3D9BE_SelectDLight,
D3D9BE_LightCullModel, D3D9BE_LightCullModel,
D3D9BE_VBO_Begin,
D3D9BE_VBO_Data,
D3D9BE_VBO_Finish,
D3D9BE_VBO_Destroy,
"no more" "no more"
}; };

View File

@ -1386,6 +1386,11 @@ rendererinfo_t d3d11rendererinfo =
D3D11BE_SelectDLight, D3D11BE_SelectDLight,
D3D11BE_LightCullModel, D3D11BE_LightCullModel,
D3D11BE_VBO_Begin,
D3D11BE_VBO_Data,
D3D11BE_VBO_Finish,
D3D11BE_VBO_Destroy,
"no more" "no more"
}; };
#endif #endif

View File

@ -968,7 +968,7 @@ void R_GAlias_DrawBatch(batch_t *batch)
{ {
if (batch->surf_first == surfnum) 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; batch->mesh = &meshl;
return; return;
} }
@ -1387,7 +1387,7 @@ void R_DrawGAliasShadowVolume(entity_t *e, vec3_t lightpos, float radius)
{ {
if (inf->ofs_trineighbours) if (inf->ofs_trineighbours)
{ {
Alias_GAliasBuildMesh(&mesh, inf, surfnum, e, false); Alias_GAliasBuildMesh(&mesh, NULL, inf, surfnum, e, false);
R_CalcFacing(&mesh, lightorg); R_CalcFacing(&mesh, lightorg);
R_ProjectShadowVolume(&mesh, lightorg); R_ProjectShadowVolume(&mesh, lightorg);
R_DrawShadowVolume(&mesh); R_DrawShadowVolume(&mesh);

View File

@ -149,8 +149,6 @@ struct {
unsigned int streamvbo_offset; unsigned int streamvbo_offset;
unsigned int streamvbo_length; unsigned int streamvbo_length;
int streamebo; int streamebo;
unsigned int streamebo_offset;
unsigned int streamebo_length;
int pendingtexcoordparts[SHADER_TMU_MAX]; int pendingtexcoordparts[SHADER_TMU_MAX];
int pendingtexcoordvbo[SHADER_TMU_MAX]; int pendingtexcoordvbo[SHADER_TMU_MAX];
@ -1333,7 +1331,6 @@ void GLBE_Init(void)
qglGenBuffersARB(1, &shaderstate.streamvbo); qglGenBuffersARB(1, &shaderstate.streamvbo);
qglGenBuffersARB(1, &shaderstate.streamebo); qglGenBuffersARB(1, &shaderstate.streamebo);
shaderstate.streamvbo_length = shaderstate.streamvbo_offset = 65536*16 * 64*sizeof(vec_t); shaderstate.streamvbo_length = shaderstate.streamvbo_offset = 65536*16 * 64*sizeof(vec_t);
shaderstate.streamebo_length = shaderstate.streamebo_offset = 65536*16 * sizeof(index_t);
} }
#endif #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 //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, sizeof(*m->indexes) * m->numindexes, m->indexes, GL_STREAM_DRAW_ARB);
{ shaderstate.dummyvbo.indicies.gl.addr = (void*)NULL;
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;
shaderstate.dummyvbo.indicies.gl.vbo = shaderstate.streamebo; shaderstate.dummyvbo.indicies.gl.vbo = shaderstate.streamebo;
shaderstate.streamebo_offset += sizeof(*m->indexes) * m->numindexes;
} }
else else
{ {
@ -4847,4 +4838,35 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
TRACE(("GLBE_DrawWorld: drawn everything\n")); 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 #endif

View File

@ -242,30 +242,6 @@ typedef struct mplane_s
qbyte pad[2]; qbyte pad[2];
} mplane_t; } 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 typedef struct vbo_s
{ {
unsigned int numvisible; unsigned int numvisible;

View File

@ -373,7 +373,8 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr)
Con_Printf("Shader_EvaluateCondition: '%s' is not a cvar\n", token); Con_Printf("Shader_EvaluateCondition: '%s' is not a cvar\n", token);
return conditiontrue; return conditiontrue;
} }
token = COM_ParseExt(ptr, false, false); if (*token)
token = COM_ParseExt(ptr, false, false);
cv->flags |= CVAR_SHADERSYSTEM; cv->flags |= CVAR_SHADERSYSTEM;
if (*token) if (*token)
{ {
@ -403,7 +404,8 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr)
conditiontrue = conditiontrue == !!cv->value; conditiontrue = conditiontrue == !!cv->value;
} }
} }
token = COM_ParseExt(ptr, false, false); if (*token)
token = COM_ParseExt(ptr, false, false);
if (!strcmp(token, "&&")) if (!strcmp(token, "&&"))
return Shader_EvaluateCondition(shader, ptr) && conditiontrue; return Shader_EvaluateCondition(shader, ptr) && conditiontrue;
if (!strcmp(token, "||")) if (!strcmp(token, "||"))

View File

@ -1708,6 +1708,11 @@ rendererinfo_t openglrendererinfo = {
GLBE_SelectDLight, GLBE_SelectDLight,
GLBE_LightCullModel, GLBE_LightCullModel,
GLBE_VBO_Begin,
GLBE_VBO_Data,
GLBE_VBO_Finish,
GLBE_VBO_Destroy,
"" ""
}; };

View File

@ -275,8 +275,6 @@ enum{
enum shaderattribs_e enum shaderattribs_e
{ {
VATTR_LEG_VERTEX,
VATTR_VERTEX1, VATTR_VERTEX1,
VATTR_VERTEX2, VATTR_VERTEX2,
VATTR_COLOUR, VATTR_COLOUR,
@ -291,12 +289,18 @@ enum shaderattribs_e
VATTR_LMCOORD3, VATTR_LMCOORD3,
VATTR_LMCOORD4, 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_COLOUR,
VATTR_LEG_ELEMENTS, VATTR_LEG_ELEMENTS,
VATTR_LEG_TMU0, VATTR_LEG_TMU0,
VATTR_LEG_FIRST=VATTR_LEG_COLOUR VATTR_LEG_FIRST=VATTR_LEG_VERTEX
}; };
typedef struct { typedef struct {
@ -514,6 +518,10 @@ void GLBE_SelectEntity(entity_t *ent);
void GLBE_SelectDLight(dlight_t *dl, vec3_t colour); void GLBE_SelectDLight(dlight_t *dl, vec3_t colour);
void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop); 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_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 #endif
#ifdef D3D9QUAKE #ifdef D3D9QUAKE
void D3D9BE_Init(void); void D3D9BE_Init(void);
@ -530,6 +538,10 @@ void D3D9BE_DrawWorld (qboolean drawworld, qbyte *vis);
qboolean D3D9BE_LightCullModel(vec3_t org, model_t *model); qboolean D3D9BE_LightCullModel(vec3_t org, model_t *model);
void D3D9BE_SelectEntity(entity_t *ent); void D3D9BE_SelectEntity(entity_t *ent);
void D3D9BE_SelectDLight(dlight_t *dl, vec3_t colour); 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); 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); 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_Reset(qboolean before);
void D3D11BE_SetupViewCBuffer(void); void D3D11BE_SetupViewCBuffer(void);
void D3D11_UploadLightmap(lightmapinfo_t *lm); 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 #endif
//Asks the backend to invoke DrawMeshChain for each surface, and to upload lightmaps as required //Asks the backend to invoke DrawMeshChain for each surface, and to upload lightmaps as required