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 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

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)
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;

View file

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

View file

@ -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
}

View file

@ -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);

View file

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

View file

@ -22,7 +22,6 @@ struct sockaddr;
#include "quakedef.h"
#include "netinc.h"
#include <sys/time.h>
#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:
"</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"
"Connection: Close\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"This is a Quake WebSocket server, not an http server.<br/>\r\n"
"<a href='"ENGINEWEBSITE"'>"FULLENGINENAME"</a>"
"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;
}

View file

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

View file

@ -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

View file

@ -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

View file

@ -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"
};

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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;

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);
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, "||"))

View file

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

View file

@ -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