diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 40c6d2fdf..a0c3e877e 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -28,8 +28,9 @@ int demoframe; int cls_lastto; int cls_lasttype; -void CL_PlayDemo(char *demoname); +void CL_PlayDemo(char *demoname, qboolean usesystempath); char lastdemoname[256]; +static qboolean lastdemowassystempath; extern cvar_t qtvcl_forceversion1; extern cvar_t qtvcl_eztvextensions; @@ -414,7 +415,7 @@ void CL_DemoJump_f(void) else { Con_Printf("Rewinding demo\n"); - CL_PlayDemo(lastdemoname); + CL_PlayDemo(lastdemoname, lastdemowassystempath); //now fastparse it. cls.demoseektime = newtime; @@ -1567,9 +1568,14 @@ void CL_PlayDemo_f (void) #endif demoname = Cmd_Argv(1); - if (*demoname == '#' && Cmd_FromGamecode()) - return; - CL_PlayDemo(demoname); + if (*demoname == '#') + { + if (Cmd_FromGamecode()) + return; + CL_PlayDemo(demoname+1, true); + } + else + CL_PlayDemo(demoname, false); } void CL_DemoStreamFullyDownloaded(struct dl_download *dl) @@ -1581,7 +1587,7 @@ void CL_DemoStreamFullyDownloaded(struct dl_download *dl) cls.demoindownload = NULL; } //dl is provided so that we can receive files via chunked/gziped http downloads and on systems that don't provide sockets etc. its tracked so we can cancel the download if the client aborts playback early. -void CL_PlayDemoStream(vfsfile_t *file, struct dl_download *dl, char *filename, int demotype, float bufferdelay) +void CL_PlayDemoStream(vfsfile_t *file, struct dl_download *dl, char *filename, qboolean issyspath, int demotype, float bufferdelay) { int protocol = CP_UNKNOWN; @@ -1640,6 +1646,7 @@ void CL_PlayDemoStream(vfsfile_t *file, struct dl_download *dl, char *filename, if (filename) { Q_strncpyz (lastdemoname, filename, sizeof(lastdemoname)); + lastdemowassystempath = issyspath; Con_Printf ("Playing demo from %s.\n", filename); } @@ -1661,15 +1668,15 @@ void CL_PlayDemoStream(vfsfile_t *file, struct dl_download *dl, char *filename, TP_ExecTrigger ("f_demostart"); } -vfsfile_t *CL_OpenFileInZipOrSys(char *name) +vfsfile_t *CL_OpenFileInZipOrSys(char *name, qboolean usesystempath) { - if (*name == '#') - return VFSOS_Open(name+1, "rb"); + if (usesystempath) + return VFSOS_Open(name, "rb"); else return CL_OpenFileInPackage(NULL, name); } //tries to determine the demo type -void CL_PlayDemoFile(vfsfile_t *f, char *demoname) +void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath) { qofs_t start; @@ -1695,7 +1702,7 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname) VFS_SEEK(f, start); if (len > 5 && type == svcq2_serverdata && protocol == PROTOCOL_VERSION_Q2) { - CL_PlayDemoStream(f, NULL, demoname, DPB_QUAKE2, 0); + CL_PlayDemoStream(f, NULL, demoname, issyspath, DPB_QUAKE2, 0); return; } } @@ -1722,7 +1729,7 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname) ft *= -1; if (chr == '\n') { - CL_PlayDemoStream(f, NULL, demoname, DPB_NETQUAKE, 0); + CL_PlayDemoStream(f, NULL, demoname, issyspath, DPB_NETQUAKE, 0); return; } VFS_SEEK(f, start); @@ -1735,9 +1742,9 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname) //mvd and qwd have no identifying markers, other than the extension. if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "mvd") || !Q_strcasecmp(demoname + strlen(demoname) - 6, "mvd.gz")) - CL_PlayDemoStream(f, NULL, demoname, DPB_MVD, 0); + CL_PlayDemoStream(f, NULL, demoname, issyspath, DPB_MVD, 0); else - CL_PlayDemoStream(f, NULL, demoname, DPB_QUAKEWORLD, 0); + CL_PlayDemoStream(f, NULL, demoname, issyspath, DPB_QUAKEWORLD, 0); } #ifdef WEBCLIENT void CL_PlayDownloadedDemo(struct dl_download *dl) @@ -1746,12 +1753,12 @@ void CL_PlayDownloadedDemo(struct dl_download *dl) Con_Printf("Failed to download %s\n", dl->url); else { - CL_PlayDemoFile(dl->file, dl->url); + CL_PlayDemoFile(dl->file, dl->url, false); dl->file = NULL; } } #endif -void CL_PlayDemo(char *demoname) +void CL_PlayDemo(char *demoname, qboolean usesystempath) { char name[256]; vfsfile_t *f; @@ -1761,13 +1768,13 @@ void CL_PlayDemo(char *demoname) // Q_strncpyz (name, demoname, sizeof(name)); COM_DefaultExtension (name, ".qwd", sizeof(name)); - f = CL_OpenFileInZipOrSys(name); + f = CL_OpenFileInZipOrSys(name, usesystempath); if (!f) { Q_strncpyz (name, demoname, sizeof(name)); COM_DefaultExtension (name, ".dem", sizeof(name)); - if (*name == '#') - f = VFSOS_Open(name+1, "rb"); + if (usesystempath) + f = VFSOS_Open(name, "rb"); else f = FS_OpenVFS(name, "rb", FS_GAME); } @@ -1775,8 +1782,8 @@ void CL_PlayDemo(char *demoname) { Q_strncpyz (name, demoname, sizeof(name)); COM_DefaultExtension (name, ".mvd", sizeof(name)); - if (*name == '#') - f = VFSOS_Open(name+1, "rb"); + if (usesystempath) + f = VFSOS_Open(name, "rb"); else f = FS_OpenVFS(name, "rb", FS_GAME); } @@ -1788,7 +1795,7 @@ void CL_PlayDemo(char *demoname) } Q_strncpyz (lastdemoname, demoname, sizeof(lastdemoname)); - CL_PlayDemoFile(f, name); + CL_PlayDemoFile(f, name, usesystempath); } /*used with qtv*/ @@ -2017,7 +2024,7 @@ void CL_QTVPoll (void) if (streamavailable) { - CL_PlayDemoStream(qtvrequest, NULL, NULL, iseztv?DPB_EZTV:DPB_MVD, BUFFERTIME); + CL_PlayDemoStream(qtvrequest, NULL, NULL, false, iseztv?DPB_EZTV:DPB_MVD, BUFFERTIME); qtvrequest = NULL; demo_resetcache(qtvrequestsize - (tail-qtvrequestbuffer), tail); return; @@ -2302,7 +2309,7 @@ void CL_QTVPlay_f (void) if (raw) { VFS_WRITE(newf, msg, msglen); - CL_PlayDemoStream(qtvrequest, NULL, qtvhostname, DPB_MVD, BUFFERTIME); + CL_PlayDemoStream(qtvrequest, NULL, qtvhostname, false, DPB_MVD, BUFFERTIME); } else { diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 92bb6a77a..a4ab640bc 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -489,6 +489,7 @@ void FlushEntityPacket (void) void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t *olds, entity_state_t *baseline) { + unsigned int predbits = 0; unsigned int bits; bits = MSG_ReadByte(); @@ -534,7 +535,7 @@ void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t * if (bits & UF_ORIGINZ) news->origin[2] = MSG_ReadCoord(); - if (bits & UF_PREDINFO) + if ((bits & UF_PREDINFO) && !(cls.fteprotocolextensions2 & PEXT2_PREDINFO)) { /*predicted stuff gets more precise angles*/ if (bits & UF_ANGLESXZ) @@ -571,7 +572,6 @@ void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t * news->u.q1.velocity[2] = 0; if (bits & UF_PREDINFO) { - unsigned int predbits; predbits = MSG_ReadByte(); if (predbits & UFP_FORWARD) @@ -606,15 +606,41 @@ void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t * news->u.q1.msec = MSG_ReadByte(); else news->u.q1.msec = 0; - if (predbits & UFP_WEAPONFRAME) + + if (cls.fteprotocolextensions2 & PEXT2_PREDINFO) { - news->u.q1.weaponframe = MSG_ReadByte(); - if (news->u.q1.weaponframe & 0x80) - news->u.q1.weaponframe = (news->u.q1.weaponframe & 127) | (MSG_ReadByte()<<7); + if (predbits & UFP_VIEWANGLE) + { + if (bits & UF_ANGLESXZ) + { + news->u.q1.vangle[0] = MSG_ReadShort(); + news->u.q1.vangle[2] = MSG_ReadShort(); + } + if (bits & UF_ANGLESY) + news->u.q1.vangle[1] = MSG_ReadShort(); + } + } + else + { + if (predbits & UFP_WEAPONFRAME_OLD) + { + news->u.q1.weaponframe = MSG_ReadByte(); + if (news->u.q1.weaponframe & 0x80) + news->u.q1.weaponframe = (news->u.q1.weaponframe & 127) | (MSG_ReadByte()<<7); + } } } else + { news->u.q1.msec = 0; + } + + if (!(predbits & UFP_VIEWANGLE) || (cls.fteprotocolextensions2 & PEXT2_PREDINFO)) + { + news->u.q1.vangle[0] = ANGLE2SHORT(news->angles[0]); + news->u.q1.vangle[1] = ANGLE2SHORT(news->angles[1]); + news->u.q1.vangle[2] = ANGLE2SHORT(news->angles[2]); + } if (bits & UF_MODEL) { @@ -2774,8 +2800,9 @@ static void CL_LerpNetFrameState(int fsanim, framestate_t *fs, lerpents_t *le) fs->g[fsanim].frametime[0] = cl.servertime - le->newframestarttime; fs->g[fsanim].frametime[1] = cl.servertime - le->oldframestarttime; - fs->g[fsanim].lerpfrac = 1-(fs->g[fsanim].frametime[0]) / le->framelerpdeltatime; - fs->g[fsanim].lerpfrac = bound(0, fs->g[FS_REG].lerpfrac, 1); + fs->g[fsanim].lerpweight[0] = (fs->g[fsanim].frametime[0]) / le->framelerpdeltatime; + fs->g[fsanim].lerpweight[0] = bound(0, fs->g[FS_REG].lerpweight[0], 1); + fs->g[fsanim].lerpweight[1] = 1 - fs->g[fsanim].lerpweight[0]; } static void CL_UpdateNetFrameLerpState(qboolean force, unsigned int curframe, lerpents_t *le) @@ -3548,9 +3575,9 @@ void CL_LinkPacketEntities (void) #ifdef RAGDOLL if (model && model->dollinfo) rag_updatedeltaent(ent, le); +#endif ent->framestate.g[FS_REG].frame[0] &= ~0x8000; ent->framestate.g[FS_REG].frame[1] &= ~0x8000; -#endif CLQ1_AddShadow(ent); CLQ1_AddPowerupShell(ent, false, state->effects); @@ -4193,8 +4220,10 @@ void CL_AddFlagModels (entity_t *ent, int team) if (cl_flagindex == -1) return; - for (i = 0; i < 2; i++) + for (i = 0; i < FRAME_BLENDS; i++) { + if (!ent->framestate.g[FS_REG].lerpweight[i]) + continue; f = 14; if (ent->framestate.g[FS_REG].frame[i] >= 29 && ent->framestate.g[FS_REG].frame[i] <= 40) { if (ent->framestate.g[FS_REG].frame[i] >= 29 && ent->framestate.g[FS_REG].frame[i] <= 34) { //axpain @@ -4219,7 +4248,7 @@ void CL_AddFlagModels (entity_t *ent, int team) else if (ent->framestate.g[FS_REG].frame[i] >= 112 && ent->framestate.g[FS_REG].frame[i] <= 118) f = f + 7; //shotattack } - offs += f + ((i==0)?(ent->framestate.g[FS_REG].lerpfrac):(1-ent->framestate.g[FS_REG].lerpfrac)); + offs += f * ent->framestate.g[FS_REG].lerpweight[i]; } newent = CL_NewTempEntity (); @@ -4246,7 +4275,7 @@ void CL_AddFlagModels (entity_t *ent, int team) void CL_AddVWeapModel(entity_t *player, model_t *model) { entity_t *newent; - vec3_t angles; +// vec3_t angles; if (!model) return; newent = CL_NewTempEntity (); @@ -4260,9 +4289,7 @@ void CL_AddVWeapModel(entity_t *player, model_t *model) newent->model = model; newent->framestate = player->framestate; - VectorCopy(newent->angles, angles); - angles[0]*=-1; - AngleVectors(angles, newent->axis[0], newent->axis[1], newent->axis[2]); + AngleVectors(newent->angles, newent->axis[0], newent->axis[1], newent->axis[2]); VectorInverse(newent->axis[1]); } @@ -4485,8 +4512,9 @@ void CL_LinkPlayers (void) } } + if (model && model->type == mod_alias) + angles[0]*=-1; //carmack screwed up when he added alias models - they pitch the wrong way. VectorCopy(angles, ent->angles); - angles[0]*=-1; AngleVectors(angles, ent->axis[0], ent->axis[1], ent->axis[2]); VectorInverse(ent->axis[1]); @@ -4676,8 +4704,9 @@ void CL_LinkViewModel(void) ent.framestate.g[FS_REG].frame[1] = pv->vm.oldframe; ent.framestate.g[FS_REG].frametime[0] = realtime - pv->vm.lerptime; ent.framestate.g[FS_REG].frametime[1] = realtime - pv->vm.oldlerptime; - ent.framestate.g[FS_REG].lerpfrac = 1-(realtime-pv->vm.lerptime)/pv->vm.frameduration; - ent.framestate.g[FS_REG].lerpfrac = bound(0, ent.framestate.g[FS_REG].lerpfrac, 1); + ent.framestate.g[FS_REG].lerpweight[0] = (realtime-pv->vm.lerptime)/pv->vm.frameduration; + ent.framestate.g[FS_REG].lerpweight[0] = bound(0, ent.framestate.g[FS_REG].lerpweight[0], 1); + ent.framestate.g[FS_REG].lerpweight[1] = 1-ent.framestate.g[FS_REG].lerpweight[0]; } ent.flags |= RF_WEAPONMODEL|RF_DEPTHHACK|RF_NOSHADOW; @@ -4766,6 +4795,8 @@ void CL_SetSolidEntities (void) pent = &pmove.physents[pmove.numphysent]; memset(pent, 0, sizeof(physent_t)); pent->model = cl.model_precache[state->modelindex]; + if (pent->model->loadstate != MLS_LOADED) + continue; VectorCopy (state->angles, pent->angles); pent->angles[0]*=-1; } diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 3490dd28a..b2fc8281a 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -501,6 +501,22 @@ cvar_t cl_pitchspeed = SCVAR("cl_pitchspeed","150"); cvar_t cl_anglespeedkey = SCVAR("cl_anglespeedkey","1.5"); + +void CL_GatherButtons (usercmd_t *cmd, int pnum) +{ + unsigned int bits = 0; + if (in_attack .state[pnum] & 3) bits |= 1; in_attack.state[pnum] &= ~2; + if (in_jump .state[pnum] & 3) bits |= 2; in_jump.state[pnum] &= ~2; + if (in_use .state[pnum] & 3) bits |= 4; in_use.state[pnum] &= ~2; + if (in_button3.state[pnum] & 3) bits |= 4; in_button3.state[pnum] &= ~2; //yup, flag 4 twice. + if (in_button4.state[pnum] & 3) bits |= 8; in_button4.state[pnum] &= ~2; + if (in_button5.state[pnum] & 3) bits |= 16; in_button5.state[pnum] &= ~2; + if (in_button6.state[pnum] & 3) bits |= 32; in_button6.state[pnum] &= ~2; + if (in_button7.state[pnum] & 3) bits |= 64; in_button7.state[pnum] &= ~2; + if (in_button8.state[pnum] & 3) bits |= 128; in_button8.state[pnum] &= ~2; + cmd->buttons = bits; +} + /* ================ CL_AdjustAngles @@ -604,6 +620,8 @@ void CL_BaseMove (usercmd_t *cmd, int pnum, float extra, float wantfps) cmd->forwardmove += scale*cl_forwardspeed.value * CL_KeyState (&in_forward, pnum, true); cmd->forwardmove -= scale*(*cl_backspeed.string?cl_backspeed.value:cl_forwardspeed.value) * CL_KeyState (&in_back, pnum, true); } + + CL_GatherButtons(cmd, pnum); } void CL_ClampPitch (int pnum) @@ -836,17 +854,7 @@ void CL_FinishMove (usercmd_t *cmd, int msecs, int pnum) // figure button bits // - bits = 0; - if (in_attack .state[pnum] & 3) bits |= 1; in_attack.state[pnum] &= ~2; - if (in_jump .state[pnum] & 3) bits |= 2; in_jump.state[pnum] &= ~2; - if (in_use .state[pnum] & 3) bits |= 4; in_use.state[pnum] &= ~2; - if (in_button3.state[pnum] & 3) bits |= 4; in_button3.state[pnum] &= ~2; //yup, flag 4 twice. - if (in_button4.state[pnum] & 3) bits |= 8; in_button4.state[pnum] &= ~2; - if (in_button5.state[pnum] & 3) bits |= 16; in_button5.state[pnum] &= ~2; - if (in_button6.state[pnum] & 3) bits |= 32; in_button6.state[pnum] &= ~2; - if (in_button7.state[pnum] & 3) bits |= 64; in_button7.state[pnum] &= ~2; - if (in_button8.state[pnum] & 3) bits |= 128; in_button8.state[pnum] &= ~2; - cmd->buttons = bits; + CL_GatherButtons(cmd, pnum); // send milliseconds of time to apply the move cmd->msec = msecs; diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index c88d312c1..aed7c6b3e 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1247,7 +1247,7 @@ CL_ClearState */ void CL_ClearState (void) { - int i; + int i, j; #ifndef CLIENTONLY #define serverrunning (sv.state != ss_dead) #define tolocalserver NET_IsLoopBackAddress(&cls.netchan.remote_address) @@ -1311,6 +1311,12 @@ void CL_ClearState (void) if (cl.particle_ssname[i]) free(cl.particle_ssname[i]); } + if (cl.particle_csprecaches) + { + for (i = 0; i < MAX_CSPARTICLESPRE; i++) + if (cl.particle_csname[i]) + free(cl.particle_csname[i]); + } { downloadlist_t *next; @@ -1328,6 +1334,13 @@ void CL_ClearState (void) } } + for (i = 0; i < MAX_SPLITS; i++) + { + for (j = 0; j < MAX_CL_STATS; j++) + if (cl.playerview[i].statsstr[j]) + Z_Free(cl.playerview[i].statsstr[j]); + } + // wipe the entire cl structure memset (&cl, 0, sizeof(cl)); @@ -3953,7 +3966,7 @@ typedef struct { int waitingformanifest; void Host_DoRunFile(hrf_t *f); -void CL_PlayDemoStream(vfsfile_t *file, struct dl_download *, char *filename, int demotype, float bufferdelay); +void CL_PlayDemoStream(vfsfile_t *file, struct dl_download *, char *filename, qboolean issyspath, int demotype, float bufferdelay); void CL_ParseQTVDescriptor(vfsfile_t *f, const char *name); void Host_RunFileDownloaded(struct dl_download *dl) @@ -4031,12 +4044,12 @@ void Host_BeginFileDownload(struct dl_download *dl, char *mimetype) } if (f->flags & HRF_DEMO_QWD) - CL_PlayDemoStream((dl->file = VFSPIPE_Open()), dl, f->fname, DPB_QUAKEWORLD, 0); + CL_PlayDemoStream((dl->file = VFSPIPE_Open()), dl, f->fname, true, DPB_QUAKEWORLD, 0); else if (f->flags & HRF_DEMO_MVD) - CL_PlayDemoStream((dl->file = VFSPIPE_Open()), dl, f->fname, DPB_MVD, 0); + CL_PlayDemoStream((dl->file = VFSPIPE_Open()), dl, f->fname, true, DPB_MVD, 0); #ifdef Q2CLIENT else if (f->flags & HRF_DEMO_DM2) - CL_PlayDemoStream((dl->file = VFSPIPE_Open()), dl, f->fname, DPB_QUAKE2, 0); + CL_PlayDemoStream((dl->file = VFSPIPE_Open()), dl, f->fname, true, DPB_QUAKE2, 0); #endif #ifdef NQPROT //fixme: the demo code can't handle the cd track like this. diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 141136e2a..83287e8fb 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -3373,6 +3373,7 @@ Con_DPrintf ("CL_SignonReply: %i\n", cls.signon); CL_SendClientCommand(true, "playermodel %s", model.string); CL_SendClientCommand(true, "playerskin %s", skin.string); + /* #ifdef PEXT_CSQC { char *s; @@ -3380,6 +3381,7 @@ Con_DPrintf ("CL_SignonReply: %i\n", cls.signon); CSQC_Init(false, *s?true:false, atoi(s)); } #endif + */ } break; @@ -4604,35 +4606,38 @@ void CL_ServerInfo (void) CL_SetStat ===================== */ -static void CL_SetStat_Internal (int pnum, int stat, int value) +static void CL_SetStat_Internal (int pnum, int stat, int ivalue, float fvalue) { int j; - if (cl.playerview[pnum].stats[stat] != value) + if (cl.playerview[pnum].stats[stat] != ivalue) Sbar_Changed (); if (stat == STAT_ITEMS) { // set flash times for (j=0 ; j<32 ; j++) - if ( (value & (1<= sizeof(funcs)) return (qintptr_t)&funcs; diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 62f181c94..43c10c069 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -458,7 +458,6 @@ void CL_CalcCrouch (playerview_t *pv) VectorSubtract(pv->simorg, pv->oldorigin, delta); teleported = Length(delta)>48; - VectorCopy (pv->simorg, pv->oldorigin); if (teleported) { @@ -471,6 +470,15 @@ void CL_CalcCrouch (playerview_t *pv) return; } + //check if we moved in the x/y axis. if we didn't then we're on a moving platform and shouldn't be crouching. +/* VectorMA(pv->oldorigin, pv->oldz-orgz, pv->gravitydir, pv->oldorigin); + VectorSubtract(pv->simorg, pv->oldorigin, delta); + if (Length(delta)<0.001) + pv->oldz = orgz; +*/ + VectorCopy (pv->simorg, pv->oldorigin); + + if (pv->onground && orgz - pv->oldz > 0) { if (orgz - pv->oldz > movevars.stepheight+2) @@ -758,6 +766,10 @@ static void CL_EntStateToPlayerState(player_state_t *plstate, entity_state_t *st plstate->viewangles[0] *= -3; plstate->viewangles[2] = V_CalcRoll(plstate->viewangles, plstate->velocity); + plstate->viewangles[0] = SHORT2ANGLE(state->u.q1.vangle[0]); + plstate->viewangles[1] = SHORT2ANGLE(state->u.q1.vangle[1]); + plstate->viewangles[2] = SHORT2ANGLE(state->u.q1.vangle[2]); + a[0] = ((-192-state->u.q1.gravitydir[0])/256.0f) * 360; a[1] = (state->u.q1.gravitydir[1]/256.0f) * 360; a[2] = 0; @@ -790,9 +802,9 @@ static void CL_EntStateToPlayerCommand(usercmd_t *cmd, entity_state_t *state, fl cmd->sidemove = state->u.q1.movement[1]; cmd->upmove = state->u.q1.movement[2]; - cmd->angles[0] = state->angles[0] * -3 *65536/360.0; - cmd->angles[1] = state->angles[1] * 65536/360.0; - cmd->angles[2] = state->angles[2] * 65536/360.0; + cmd->angles[0] = state->u.q1.vangle[0];// * -3 *65536/360.0; + cmd->angles[1] = state->u.q1.vangle[1];// * 65536/360.0; + cmd->angles[2] = state->u.q1.vangle[2];// * 65536/360.0; } void CL_PredictEntityMovement(entity_state_t *estate, float age) @@ -993,14 +1005,14 @@ void CL_PredictMovePNum (int seat) //we're only interested in inbound frames, not outbound, but its outbound frames that contain the prediction timing, so we need to look that up //(note that in qw, inframe[i].ack==i holds true, but this code tries to be generic for unsyncronised protocols) //(note that in nq, using outbound times means we'll skip over dupe states without noticing, and input packets with dupes should also be handled gracefully) -// Con_DPrintf("in:%i:%i out:%i:%i ack:%i\n", cls.netchan.incoming_sequence, cl.validsequence, cls.netchan.outgoing_sequence,cl.movesequence, cl.ackedmovesequence); + Con_DPrintf("in:%i:%i out:%i:%i ack:%i\n", cls.netchan.incoming_sequence, cl.validsequence, cls.netchan.outgoing_sequence,cl.movesequence, cl.ackedmovesequence); for (i = cl.validsequence; i >= cls.netchan.incoming_sequence - UPDATE_MASK; i--) { int out; //skip frames which were not received, or are otherwise invalid. yay packetloss if (cl.inframes[i & UPDATE_MASK].frameid != i || cl.inframes[i & UPDATE_MASK].invalid) { -// Con_DPrintf("stale incoming command %i\n", i); + Con_DPrintf("stale incoming command %i\n", i); continue; } @@ -1009,7 +1021,7 @@ void CL_PredictMovePNum (int seat) backdate = &cl.outframes[out & UPDATE_MASK]; if (backdate->cmd_sequence != out) { -// Con_DPrintf("stale outgoing command %i (%i:%i:%i)\n", i, out, backdate->cmd_sequence, backdate->server_message_num); + Con_DPrintf("stale outgoing command %i (%i:%i:%i)\n", i, out, backdate->cmd_sequence, backdate->server_message_num); continue; } //okay, looks valid @@ -1024,12 +1036,12 @@ void CL_PredictMovePNum (int seat) totime = fromtime; fromframe = i; fromtime = backdate->senttime; - if (fromtime < simtime) + if (fromtime < simtime && fromframe != toframe) break; //okay, we found the first frame that is older, no need to continue looking } } -// Con_DPrintf("sim%f, %i(%i-%i): old%f, cur%f\n", simtime, cl.ackedmovesequence, fromframe, toframe, fromtime, totime); + Con_DPrintf("sim%f, %i(%i-%i): old%f, cur%f\n", simtime, cl.ackedmovesequence, fromframe, toframe, fromtime, totime); if (pv->cam_locked && cl.spectator && pv->viewentity && pv->viewentity <= cl.allocated_client_slots) { diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index e81e1cc7b..8b1ea53e8 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -223,6 +223,7 @@ float scr_disabled_time; float oldsbar = 0; void SCR_ScreenShot_f (void); +void SCR_ScreenShot_Mega_f(void); void SCR_RSShot_f (void); void SCR_CPrint_f(void); @@ -1174,6 +1175,7 @@ void SCR_Init (void) // // register our commands // + Cmd_AddCommand ("screenshot_mega",SCR_ScreenShot_Mega_f); Cmd_AddCommand ("screenshot",SCR_ScreenShot_f); Cmd_AddCommand ("sizeup",SCR_SizeUp_f); Cmd_AddCommand ("sizedown",SCR_SizeDown_f); @@ -2114,6 +2116,75 @@ void SCR_ScreenShot_f (void) Con_Printf ("Couldn't write %s\n", sysname); } +void SCR_ScreenShot_Mega_f(void) +{ + int width; + int height; + qbyte *rgbbuffer; + char filename[MAX_QPATH]; + + //poke the various modes into redrawing the screen (without huds), to avoid any menus or console drawn over the top of the current backbuffer. + //FIXME: clear-to-black first + qboolean okay = false; + + char *screenyname = Cmd_Argv(1); + unsigned int fbwidth = strtoul(Cmd_Argv(2), NULL, 0); + unsigned int fbheight = strtoul(Cmd_Argv(3), NULL, 0); + + if (qrenderer <= QR_HEADLESS) + { + Con_Printf("No renderer active\n"); + return; + } + + if (!fbwidth) + fbwidth = sh_config.texture_maxsize; + fbwidth = bound(0, fbwidth, sh_config.texture_maxsize); + if (!fbheight) + fbheight = (fbwidth * 3)/4; + fbheight = bound(0, fbheight, sh_config.texture_maxsize); + if (!*screenyname) + screenyname = "megascreeny"; + + Q_snprintfz(filename, sizeof(filename), "%s-%s", scr_sshot_prefix.string, screenyname); + COM_DefaultExtension (filename, scr_sshot_type.string, sizeof(filename)); + + Q_strncpyz(r_refdef.rt_destcolour[0].texname, "megascreeny", sizeof(r_refdef.rt_destcolour[0].texname)); + R2D_RT_Configure(r_refdef.rt_destcolour[0].texname, fbwidth, fbheight, 1); + BE_RenderToTextureUpdate2d(true); + + R2D_FillBlock(0, 0, vid.fbvwidth, vid.fbvheight); + +#ifdef VM_CG + if (!okay && CG_Refresh()) + okay = true; +#endif +#ifdef CSQC_DAT + if (!okay && CSQC_DrawView()) + okay = true; +#endif + if (!okay && r_worldentity.model) + { + V_RenderView (); + okay = true; + } + + //okay, we drew something, we're good to save a screeny. + if (okay) + { + rgbbuffer = VID_GetRGBInfo(0, &width, &height); + if (rgbbuffer) + { + SCR_ScreenShot(filename, rgbbuffer, width, height); + BZ_Free(rgbbuffer); + } + } + + R2D_RT_Configure(r_refdef.rt_destcolour[0].texname, 0, 0, 0); + Q_strncpyz(r_refdef.rt_destcolour[0].texname, "", sizeof(r_refdef.rt_destcolour[0].texname)); + BE_RenderToTextureUpdate2d(true); +} + // from gl_draw.c qbyte *draw_chars; // 8*8 graphic characters diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 3a78a3921..db8f713ef 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -3703,7 +3703,8 @@ void CL_UpdateExplosions (void) ent->model = ex->model; ent->framestate.g[FS_REG].frame[1] = (int)f+firstframe; ent->framestate.g[FS_REG].frame[0] = of+firstframe; - ent->framestate.g[FS_REG].lerpfrac = (f - (int)f); + ent->framestate.g[FS_REG].lerpweight[1] = (f - (int)f); + ent->framestate.g[FS_REG].lerpweight[0] = 1-ent->framestate.g[FS_REG].lerpweight[1]; ent->shaderRGBAf[3] = (1.0 - f/(numframes))*(ex->startalpha-ex->endalpha) + ex->endalpha; ent->flags = ex->flags; ent->scale = scale; diff --git a/engine/client/cl_ui.c b/engine/client/cl_ui.c index b27e03665..ccd83ab4b 100644 --- a/engine/client/cl_ui.c +++ b/engine/client/cl_ui.c @@ -395,7 +395,8 @@ void VQ3_AddEntity(const q3refEntity_t *q3) ent.framestate.g[FS_REG].frame[0] = q3->frame; ent.framestate.g[FS_REG].frame[1] = q3->oldframe; memcpy(ent.axis, q3->axis, sizeof(q3->axis)); - ent.framestate.g[FS_REG].lerpfrac = q3->backlerp; + ent.framestate.g[FS_REG].lerpweight[1] = q3->backlerp; + ent.framestate.g[FS_REG].lerpweight[0] = 1 - ent.framestate.g[FS_REG].lerpweight[1]; if (q3->reType == RT_SPRITE) { ent.scale = q3->radius; @@ -508,7 +509,8 @@ int VM_LerpTag(void *out, model_t *model, int f1, int f2, float l2, char *tagnam memset(&fstate, 0, sizeof(fstate)); fstate.g[FS_REG].frame[0] = f1; fstate.g[FS_REG].frame[1] = f2; - fstate.g[FS_REG].lerpfrac = l2; + fstate.g[FS_REG].lerpweight[0] = 1 - l2; + fstate.g[FS_REG].lerpweight[1] = l2; tagnum = Mod_TagNumForName(model, tagname); found = Mod_GetTag(model, tagnum, &fstate, tr); diff --git a/engine/client/client.h b/engine/client/client.h index 7605efc55..42991df35 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -1452,9 +1452,10 @@ void Media_EndedTrack(void); //cd is no longer running, media code needs to pick void Media_Send_Command(cin_t *cin, const char *command); void Media_Send_MouseMove(cin_t *cin, float x, float y); void Media_Send_Resize(cin_t *cin, int x, int y); -void Media_Send_GetSize(cin_t *cin, int *x, int *y); +void Media_Send_GetSize(cin_t *cin, int *x, int *y, float *aspect); void Media_Send_KeyEvent(cin_t *cin, int button, int unicode, int event); void Media_Send_Reset(cin_t *cin); +void Media_Send_GetPositions(cin_t *cin, qboolean *active, float *curtime, float *duration); void MVD_Interpolate(void); diff --git a/engine/client/clq2_ents.c b/engine/client/clq2_ents.c index 171b0e79c..1895bbffa 100644 --- a/engine/client/clq2_ents.c +++ b/engine/client/clq2_ents.c @@ -1274,7 +1274,8 @@ void CLQ2_AddPacketEntities (q2frame_t *frame) // pmm //====== ent.framestate.g[FS_REG].frame[1] = cent->prev.frame; - ent.framestate.g[FS_REG].lerpfrac = cl.lerpfrac; + ent.framestate.g[FS_REG].lerpweight[0] = 1-cl.lerpfrac; + ent.framestate.g[FS_REG].lerpweight[1] = cl.lerpfrac; if (renderfx & (Q2RF_FRAMELERP|Q2RF_BEAM)) { // step origin discretely, because the frames @@ -1302,7 +1303,8 @@ void CLQ2_AddPacketEntities (q2frame_t *frame) ent.shaderRGBAf[2] = ((d_8to24rgbtable[ent.skinnum & 0xFF] >> 16) & 0xFF)/255.0; ent.shaderRGBAf[3] = 0.30; ent.model = NULL; - ent.framestate.g[FS_REG].lerpfrac = 1; + ent.framestate.g[FS_REG].lerpweight[0] = 0; + ent.framestate.g[FS_REG].lerpweight[1] = 1; ent.rtype = RT_BEAM; } else @@ -1456,13 +1458,14 @@ void CLQ2_AddPacketEntities (q2frame_t *frame) //pmm /*lerp the ent now*/ - fwds = ent.framestate.g[FS_REG].lerpfrac; - back = 1 - ent.framestate.g[FS_REG].lerpfrac; + fwds = ent.framestate.g[FS_REG].lerpweight[1]; + back = ent.framestate.g[FS_REG].lerpweight[0]; for (i = 0; i < 3; i++) { ent.origin[i] = ent.origin[i]*fwds + ent.oldorigin[i]*back; } - ent.framestate.g[FS_REG].lerpfrac = back; + ent.framestate.g[FS_REG].lerpweight[0] = fwds; + ent.framestate.g[FS_REG].lerpweight[1] = back; // add to refresh list V_AddEntity (&ent); @@ -1821,7 +1824,8 @@ void CLQ2_AddViewWeapon (q2player_state_t *ps, q2player_state_t *ops) gun.playerindex = -1; gun.flags = Q2RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL; - gun.framestate.g[FS_REG].lerpfrac = 1-cl.lerpfrac; + gun.framestate.g[FS_REG].lerpweight[0] = cl.lerpfrac; + gun.framestate.g[FS_REG].lerpweight[1] = 1-cl.lerpfrac; VectorCopy (gun.origin, gun.oldorigin); // don't lerp at all V_AddEntity (&gun); } diff --git a/engine/client/image.c b/engine/client/image.c index 3ed9d040b..f0aebbf7b 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -38,6 +38,9 @@ extern cvar_t gl_picmip2d; extern cvar_t gl_picmip; extern cvar_t r_shadow_bumpscale_basetexture; extern cvar_t r_shadow_bumpscale_bumpmap; +extern cvar_t r_shadow_heightscale_basetexture; +extern cvar_t r_shadow_heightscale_bumpmap; + static bucket_t *imagetablebuckets[256]; static hashtable_t imagetable; @@ -2332,7 +2335,6 @@ static qboolean Image_ReadDDSFile(texid_t tex, unsigned int flags, char *fname, ddsheader fmtheader; if (*(int*)filedata != *(int*)"DDS ") return false; - filedata+=4; memcpy(&fmtheader, filedata+4, sizeof(fmtheader)); if (fmtheader.dwSize != sizeof(fmtheader)) @@ -3024,10 +3026,10 @@ void Image_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *o } //ripped from tenebrae -static unsigned int * Image_GenerateNormalMap(qbyte *pixels, unsigned int *nmap, int w, int h, float scale) +static unsigned int * Image_GenerateNormalMap(qbyte *pixels, unsigned int *nmap, int w, int h, float scale, float offsetscale) { int i, j, wr, hr; - unsigned char r, g, b; + unsigned char r, g, b, height; float sqlen, reciplen, nx, ny, nz; const float oneOver255 = 1.0f/255.0f; @@ -3065,7 +3067,8 @@ static unsigned int * Image_GenerateNormalMap(qbyte *pixels, unsigned int *nmap, /* The highest resolution mipmap level always has a unit length magnitude. */ - nmap[i*w+j] = LittleLong ((pixels[i*wr + j] << 24)|(b << 16)|(g << 8)|(r)); // Added support for big endian. + height = bound(0, (pixels[i*wr + j]*offsetscale)+(255*(1-offsetscale)), 255); + nmap[i*w+j] = LittleLong((height << 24)|(b << 16)|(g << 8)|(r)); // Added support for big endian. } } @@ -3471,7 +3474,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag unsigned int rgb = d_8to24rgbtable[((qbyte*)rawdata)[i]]; heights[i] = (((rgb>>16)&0xff) + ((rgb>>8)&0xff) + ((rgb>>0)&0xff))/3; } - Image_GenerateNormalMap(heights, rgbadata, imgwidth, imgheight, r_shadow_bumpscale_basetexture.value?r_shadow_bumpscale_basetexture.value:4); + Image_GenerateNormalMap(heights, rgbadata, imgwidth, imgheight, r_shadow_bumpscale_basetexture.value?r_shadow_bumpscale_basetexture.value:4, r_shadow_heightscale_basetexture.value); } if (freedata) BZ_Free(rawdata); @@ -3480,7 +3483,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag case TF_HEIGHT8: mips->encoding = PTI_RGBA8; rgbadata = BZ_Malloc(imgwidth * imgheight*4); - Image_GenerateNormalMap(rawdata, rgbadata, imgwidth, imgheight, r_shadow_bumpscale_bumpmap.value); + Image_GenerateNormalMap(rawdata, rgbadata, imgwidth, imgheight, r_shadow_bumpscale_bumpmap.value, r_shadow_heightscale_bumpmap.value); if (freedata) BZ_Free(rawdata); freedata = true; @@ -3507,8 +3510,9 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag freedata = true; break; case TF_8PAL32: + if (!palettedata) { - Con_Printf("TF_8PAL24: no palette"); + Con_Printf("TF_8PAL32: no palette"); if (freedata) BZ_Free(rawdata); return false; @@ -3654,13 +3658,13 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag return true; } //loads from a single mip. takes ownership of the data. -static qboolean Image_LoadRawTexture(texid_t tex, unsigned int flags, void *rawdata, int imgwidth, int imgheight, uploadfmt_t fmt) +static qboolean Image_LoadRawTexture(texid_t tex, unsigned int flags, void *rawdata, void *palettedata, int imgwidth, int imgheight, uploadfmt_t fmt) { struct pendingtextureinfo *mips; mips = Z_Malloc(sizeof(*mips)); mips->type = (flags & IF_3DMAP)?PTI_3D:PTI_2D; - if (!Image_GenMip0(mips, flags, rawdata, NULL, imgwidth, imgheight, fmt, true)) + if (!Image_GenMip0(mips, flags, rawdata, palettedata, imgwidth, imgheight, fmt, true)) { Z_Free(mips); return false; @@ -3738,7 +3742,7 @@ qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname, } } - if (Image_LoadRawTexture(tex, flags, rgbadata, imgwidth, imgheight, TF_RGBA32)) + if (Image_LoadRawTexture(tex, flags, rgbadata, NULL, imgwidth, imgheight, TF_RGBA32)) { BZ_Free(filedata); @@ -3889,6 +3893,15 @@ void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t b) if (!tex->fallbackdata || (gl_load24bit.ival && !(tex->flags & IF_NOREPLACE))) { + Q_snprintfz(fname, sizeof(fname), "dds/%s.dds", nicename); + if ((buf = COM_LoadFile (fname, 5, &fsize))) + { + Q_snprintfz(iname, sizeof(iname), "dds/%s", nicename); /*should be safe if its null*/ + if (Image_LoadTextureFromMemory(tex, tex->flags, iname, fname, buf, fsize)) + return; + } + + if (strchr(nicename, '/') || strchr(nicename, '\\')) //never look in a root dir for the pic i = 0; else @@ -4003,7 +4016,7 @@ void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t b) if ((d = ReadTargaFile(buf, fsize, &w, &h, &a, 2))) //Only load a greyscale image. { BZ_Free(buf); - if (Image_LoadRawTexture(tex, tex->flags, d, w, h, TF_HEIGHT8)) + if (Image_LoadRawTexture(tex, tex->flags, d, NULL, w, h, TF_HEIGHT8)) { BZ_Free(tex->fallbackdata); tex->fallbackdata = NULL; @@ -4037,7 +4050,7 @@ void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t b) buf = W_GetTexture(nicename, &imgwidth, &imgheight, &alphaed); if (buf) { - if (Image_LoadRawTexture(tex, tex->flags, buf, imgwidth, imgheight, TF_RGBA32)) + if (Image_LoadRawTexture(tex, tex->flags, buf, NULL, imgwidth, imgheight, TF_RGBA32)) { BZ_Free(tex->fallbackdata); tex->fallbackdata = NULL; @@ -4050,12 +4063,11 @@ void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t b) if (tex->fallbackdata) { - if (Image_LoadRawTexture(tex, tex->flags, tex->fallbackdata, tex->fallbackwidth, tex->fallbackheight, tex->fallbackfmt)) + if (Image_LoadRawTexture(tex, tex->flags, tex->fallbackdata, (char*)tex->fallbackdata+(tex->fallbackwidth*tex->fallbackheight), tex->fallbackwidth, tex->fallbackheight, tex->fallbackfmt)) { tex->fallbackdata = NULL; return; } - BZ_Free(tex->fallbackdata); tex->fallbackdata = NULL; } @@ -4235,7 +4247,7 @@ typedef struct { char *name; char *legacyname; - int minimize, minmip, maximize; + int maximize, minmip, minimize; } texmode_t; static texmode_t texmodes[] = { {"n", "GL_NEAREST", 0, -1, 0}, diff --git a/engine/client/keys.c b/engine/client/keys.c index 9a8ae5dc1..1e0c013b8 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -431,13 +431,14 @@ void Con_ExecuteLine(console_t *con, char *line) Cbuf_AddText (line, RESTRICT_LOCAL); else { + char *exec = NULL; if (line[0] == '\\' || line[0] == '/') - Cbuf_AddText (line+1, RESTRICT_LOCAL); // skip the > + exec = line+1; // skip the slash else if (cl_chatmode.value == 2 && Cmd_IsCommand(line)) - Cbuf_AddText (line, RESTRICT_LOCAL); // valid command + exec = line; // valid command #ifdef Q2CLIENT else if (cls.protocol == CP_QUAKE2) - Cbuf_AddText (line, RESTRICT_LOCAL); // send the command to the server via console, and let the server convert to chat + exec = line; // send the command to the server via console, and let the server convert to chat #endif else if (*line) { // convert to a chat message @@ -448,8 +449,29 @@ void Con_ExecuteLine(console_t *con, char *line) else Cbuf_AddText ("say ", RESTRICT_LOCAL); waschat = true; + Cbuf_AddText (line, RESTRICT_LOCAL); } - Cbuf_AddText (line, RESTRICT_LOCAL); // skip the > + } + + if (exec) + { +#ifdef TEXTEDITOR + extern qboolean editormodal; + if (editormodal) + { + char cvarname[128]; + COM_ParseOut(exec, cvarname, sizeof(cvarname)); + if (Cvar_FindVar(cvarname) && !strchr(line, ';') && !strchr(line, '\n')) + { + Con_Printf ("]%s\n",line); + Cmd_ExecuteString(exec, RESTRICT_SERVER); + return; + } + + Con_Footerf(false, "Commands cannot be execed while debugging QC"); + } +#endif + Cbuf_AddText (exec, RESTRICT_LOCAL); } } @@ -1888,6 +1910,9 @@ qboolean Key_MouseShouldBeFree(void) if (key_dest_absolutemouse & key_dest_mask) return true; + if (Key_Dest_Has(kdm_editor)) + return true; + // if (!ActiveApp) // return true; diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index d332596b2..a0669fcb7 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -1090,12 +1090,6 @@ char *Media_NextTrack(int musicchannelnum) #undef lTime -#ifdef OFFSCREENGECKO -#include "offscreengecko/embedding.h" -#include "offscreengecko/browser.h" -#endif - - ///temporary residence for media handling #include "roq.h" @@ -1282,7 +1276,7 @@ struct cin_s void (*cursormove) (struct cin_s *cin, float posx, float posy); //pos is 0-1 void (*key) (struct cin_s *cin, int code, int unicode, int event); qboolean (*setsize) (struct cin_s *cin, int width, int height); - void (*getsize) (struct cin_s *cin, int *width, int *height); + void (*getsize) (struct cin_s *cin, int *width, int *height, float *aspect); void (*changestream) (struct cin_s *cin, const char *streamname); @@ -1295,6 +1289,7 @@ struct cin_s qbyte *outpalette; int outunchanged; qboolean ended; + float filmpercentage; texid_t texture; @@ -1322,14 +1317,6 @@ struct cin_s } avi; #endif -#ifdef OFFSCREENGECKO - struct { - OSGK_Browser *gbrowser; - int bwidth; - int bheight; - } gecko; -#endif - #ifdef PLUGINS struct { void *ctx; @@ -1411,6 +1398,7 @@ qboolean Media_WinAvi_DecodeFrame(cin_t *cin, qboolean nosound) Con_DPrintf("Dropped %i frame(s)\n", (newframei - cin->currentframe)-1); cin->currentframe = newframei; + cin->filmpercentage = (float)cin->currentframe / cin->avi.num_frames; if (newframei>=cin->avi.num_frames) { @@ -1711,10 +1699,9 @@ static qboolean Media_Plugin_DecodeFrame(cin_t *cin, qboolean nosound) cin->outunchanged = (cin->outdata==NULL); - if (cin->outtype != TF_INVALID) - return true; - cin->ended = true; - return false; + cin->filmpercentage = 0; + cin->ended = (cin->outtype == TF_INVALID); + return !cin->ended; } static void Media_Plugin_DoneFrame(cin_t *cin) { @@ -1774,7 +1761,7 @@ qboolean Media_Plugin_SetSize(cin_t *cin, int width, int height) currentplug = oldplug; return result; } -void Media_Plugin_GetSize(cin_t *cin, int *width, int *height) +void Media_Plugin_GetSize(cin_t *cin, int *width, int *height, float *aspect) { struct plugin_s *oldplug = currentplug; currentplug = cin->plugin.plug; @@ -1875,6 +1862,8 @@ qboolean Media_Roq_DecodeFrame (cin_t *cin, qboolean nosound) qbyte *framedata; + cin->filmpercentage = cin->roq.roqfilm->frame_num / cin->roq.roqfilm->num_frames; + cin->filmlasttime = (float)realtime; if (!(curtimenextframetime)) //roq file was read properly @@ -2121,286 +2110,6 @@ cin_t *Media_Cin_TryLoad(char *name) //Quake2 CIN Support ////////////////////////////////////////////////////////////////////////////////// -//Gecko Support - -#ifdef OFFSCREENGECKO - -int (VARGS *posgk_release) (OSGK_BaseObject* obj); - -OSGK_Browser* (VARGS *posgk_browser_create) (OSGK_Embedding* embedding, int width, int height); -void (VARGS *posgk_browser_resize) (OSGK_Browser* browser, int width, int height); -void (VARGS *posgk_browser_navigate) (OSGK_Browser* browser, const char* uri); -const unsigned char* (VARGS *posgk_browser_lock_data) (OSGK_Browser* browser, int* isDirty); -void (VARGS *posgk_browser_unlock_data) (OSGK_Browser* browser, const unsigned char* data); - -void (VARGS *posgk_browser_event_mouse_move) (OSGK_Browser* browser, int x, int y); -void (VARGS *posgk_browser_event_mouse_button) (OSGK_Browser* browser, OSGK_MouseButton button, OSGK_MouseButtonEventType eventType); -int (VARGS *posgk_browser_event_key) (OSGK_Browser* browser, unsigned int key, OSGK_KeyboardEventType eventType); - -OSGK_EmbeddingOptions* (VARGS *posgk_embedding_options_create) (void); -OSGK_Embedding* (VARGS *posgk_embedding_create2) (unsigned int apiVer, OSGK_EmbeddingOptions* options, OSGK_GeckoResult* geckoResult); -void (VARGS *posgk_embedding_options_set_profile_dir) (OSGK_EmbeddingOptions* options, const char* profileDir, const char* localProfileDir); -void (VARGS *posgk_embedding_options_add_search_path) (OSGK_EmbeddingOptions* options, const char* path); - -dllhandle_t geckodll; -dllfunction_t gecko_functions[] = -{ - {(void**)&posgk_release, "osgk_release"}, - - {(void**)&posgk_browser_create, "osgk_browser_create"}, - {(void**)&posgk_browser_resize, "osgk_browser_resize"}, - {(void**)&posgk_browser_navigate, "osgk_browser_navigate"}, - {(void**)&posgk_browser_lock_data, "osgk_browser_lock_data"}, - {(void**)&posgk_browser_unlock_data, "osgk_browser_unlock_data"}, - - {(void**)&posgk_browser_event_mouse_move, "osgk_browser_event_mouse_move"}, - {(void**)&posgk_browser_event_mouse_button, "osgk_browser_event_mouse_button"}, - {(void**)&posgk_browser_event_key, "osgk_browser_event_key"}, - - {(void**)&posgk_embedding_options_create, "osgk_embedding_options_create"}, - {(void**)&posgk_embedding_create2, "osgk_embedding_create2"}, - {(void**)&posgk_embedding_options_set_profile_dir, "osgk_embedding_options_set_profile_dir"}, - {(void**)&posgk_embedding_options_add_search_path, "osgk_embedding_options_add_search_path"}, - {NULL} -}; -OSGK_Embedding *gecko_embedding; - -void Media_Gecko_Shutdown(struct cin_s *cin) -{ - posgk_release(&cin->gecko.gbrowser->baseobj); -} - -qboolean Media_Gecko_DecodeFrame(cin_t *cin, qboolean nosound) -{ - cin->outdata = (char*)posgk_browser_lock_data(cin->gecko.gbrowser, &cin->outunchanged); - cin->outwidth = cin->gecko.bwidth; - cin->outheight = cin->gecko.bheight; - cin->outtype = TF_BGRA32; - return !!cin->gecko.gbrowser; -} - -void Media_Gecko_DoneFrame(cin_t *cin) -{ - posgk_browser_unlock_data(cin->gecko.gbrowser, cin->outdata); - cin->outdata = NULL; -} - -void Media_Gecko_MoveCursor (struct cin_s *cin, float posx, float posy) -{ - posgk_browser_event_mouse_move(cin->gecko.gbrowser, posx*cin->gecko.bwidth, posy*cin->gecko.bheight); -} - -void Media_Gecko_KeyPress (struct cin_s *cin, int code, int unicode, int event) -{ - if (code >= K_MOUSE1 && code < K_MOUSE10) - { - posgk_browser_event_mouse_button(cin->gecko.gbrowser, code - K_MOUSE1, (event==3)?2:event); - } - else - { - switch(code) - { - case K_BACKSPACE: - code = OSGKKey_Backspace; - break; - case K_TAB: - code = OSGKKey_Tab; - break; - case K_ENTER: - code = OSGKKey_Return; - break; - case K_LSHIFT: - case K_RSHIFT: - code = OSGKKey_Shift; - break; - case K_LCTRL: - case K_RCTRL: - code = OSGKKey_Control; - break; - case K_LALT: - case K_RALT: - code = OSGKKey_Alt; - break; - case K_CAPSLOCK: - code = OSGKKey_CapsLock; - break; - case K_ESCAPE: - code = OSGKKey_Escape; - break; - case K_SPACE: - code = OSGKKey_Space; - break; - case K_PGUP: - code = OSGKKey_PageUp; - break; - case K_PGDN: - code = OSGKKey_PageDown; - break; - case K_END: - code = OSGKKey_End; - break; - case K_HOME: - code = OSGKKey_Home; - break; - case K_LEFTARROW: - code = OSGKKey_Left; - break; - case K_UPARROW: - code = OSGKKey_Up; - break; - case K_RIGHTARROW: - code = OSGKKey_Right; - break; - case K_DOWNARROW: - code = OSGKKey_Down; - break; - case K_INS: - code = OSGKKey_Insert; - break; - case K_DEL: - code = OSGKKey_Delete; - break; - case K_F1: - code = OSGKKey_F1; - break; - case K_F2: - code = OSGKKey_F2; - break; - case K_F3: - code = OSGKKey_F3; - break; - case K_F4: - code = OSGKKey_F4; - break; - case K_F5: - code = OSGKKey_F5; - break; - case K_F6: - code = OSGKKey_F6; - break; - case K_F7: - code = OSGKKey_F7; - break; - case K_F8: - code = OSGKKey_F8; - break; - case K_F9: - code = OSGKKey_F9; - break; - case K_F10: - code = OSGKKey_F10; - break; - case K_F11: - code = OSGKKey_F11; - break; - case K_F12: - code = OSGKKey_F12; - break; - case K_KP_NUMLOCK: - code = OSGKKey_NumLock; - break; - case K_SCRLCK: - code = OSGKKey_ScrollLock; - break; - case K_LWIN: - code = OSGKKey_Meta; - break; - default: - code = unicode; - break; - } - posgk_browser_event_key(cin->gecko.gbrowser, code, kePress); - //posgk_browser_event_key(cin->gecko.gbrowser, code, event); - } -} - -qboolean Media_Gecko_SetSize (struct cin_s *cin, int width, int height) -{ - if (width < 4 || height < 4) - return false; - - posgk_browser_resize(cin->gecko.gbrowser, width, height); - cin->gecko.bwidth = width; - cin->gecko.bheight = height; - return true; -} - -void Media_Gecko_GetSize (struct cin_s *cin, int *width, int *height) -{ - *width = cin->gecko.bwidth; - *height = cin->gecko.bheight; -} - -void Media_Gecko_ChangeStream (struct cin_s *cin, char *streamname) -{ - posgk_browser_navigate(cin->gecko.gbrowser, streamname); -} - -cin_t *Media_Gecko_TryLoad(char *name) -{ - char xulprofiledir[MAX_OSPATH]; - cin_t *cin; - - if (!strncmp(name, "http://", 7)) - { - OSGK_GeckoResult result; - - OSGK_EmbeddingOptions *opts; - - if (!gecko_embedding) - { - geckodll = Sys_LoadLibrary("OffscreenGecko", gecko_functions); - if (!geckodll) - { - Con_Printf("OffscreenGecko not installed\n"); - return NULL; - } - - opts = posgk_embedding_options_create(); - if (!opts) - return NULL; - - posgk_embedding_options_add_search_path(opts, "./xulrunner/"); - if (FS_NativePath("xulrunner_profile/", FS_ROOT, xulprofiledir, sizeof(xulprofiledir))) - posgk_embedding_options_set_profile_dir(opts, xulprofiledir, 0); - - gecko_embedding = posgk_embedding_create2(OSGK_API_VERSION, opts, &result); - posgk_release(&opts->baseobj); - if (!gecko_embedding) - return NULL; - } - - cin = Z_Malloc(sizeof(cin_t)); - cin->filmtype = MFT_OFSGECKO; - cin->decodeframe = Media_Gecko_DecodeFrame; - cin->doneframe = Media_Gecko_DoneFrame; - cin->shutdown = Media_Gecko_Shutdown; - - cin->cursormove = Media_Gecko_MoveCursor; - cin->key = Media_Gecko_KeyPress; - cin->setsize = Media_Gecko_SetSize; - cin->getsize = Media_Gecko_GetSize; - cin->changestream = Media_Gecko_ChangeStream; - - cin->gecko.bwidth = 1024; - cin->gecko.bheight = 1024; - - cin->gecko.gbrowser = posgk_browser_create(gecko_embedding, cin->gecko.bwidth, cin->gecko.bheight); - if (!cin->gecko.gbrowser) - { - Con_Printf("osgk_browser_create failed, your version of xulrunner is likely unsupported\n"); - Z_Free(cin); - return NULL; - } - posgk_browser_navigate(cin->gecko.gbrowser, name); - return cin; - } - return NULL; -} -#endif - -//Gecko Support -////////////////////////////////////////////////////////////////////////////////// qboolean Media_PlayingFullScreen(void) { @@ -2434,11 +2143,6 @@ cin_t *Media_StartCin(char *name) if (!name || !*name) //clear only. return NULL; -#ifdef OFFSCREENGECKO - if (!cin) - cin = Media_Gecko_TryLoad(name); -#endif - if (!cin) cin = Media_Static_TryLoad(name); @@ -2678,14 +2382,6 @@ texid_tf Media_UpdateForShader(cin_t *cin) } #endif -void Media_Send_Command(cin_t *cin, const char *command) -{ - if (!cin) - cin = R_ShaderGetCinematic(videoshader); - if (!cin || !cin->changestream) - return; - cin->changestream(cin, command); -} void Media_Send_KeyEvent(cin_t *cin, int button, int unicode, int event) { if (!cin) @@ -2710,20 +2406,48 @@ void Media_Send_Resize(cin_t *cin, int x, int y) return; cin->setsize(cin, x, y); } -void Media_Send_GetSize(cin_t *cin, int *x, int *y) +void Media_Send_GetSize(cin_t *cin, int *x, int *y, float *aspect) { + *x = 0; + *y = 0; + *aspect = 0; if (!cin) cin = R_ShaderGetCinematic(videoshader); if (!cin || !cin->getsize) return; - cin->getsize(cin, x, y); + cin->getsize(cin, x, y, aspect); } void Media_Send_Reset(cin_t *cin) { if (!cin || !cin->rewind) cin->rewind(cin); } - +void Media_Send_Command(cin_t *cin, const char *command) +{ + if (!cin) + cin = R_ShaderGetCinematic(videoshader); + if (cin && cin->changestream) + cin->changestream(cin, command); + else if (cin && cin->rewind && !strcmp(command, "cmd:rewind")) + cin->rewind(cin); +} +void Media_Send_GetPositions(cin_t *cin, qboolean *active, float *curtime, float *duration) +{ + if (!cin) + cin = R_ShaderGetCinematic(videoshader); + if (cin) + { + *active = true && !cin->ended; + *curtime = Sys_DoubleTime() - cin->filmstarttime; + *duration = cin->filmpercentage; + } + else + { + *active = false; + *curtime = 0; + *duration = 0; + } +} void Media_PlayFilm_f (void) @@ -3449,7 +3173,7 @@ void Media_CaptureDemoEnd(void) if (recordingdemo) Media_StopRecordFilm_f(); } -void CL_PlayDemo(char *demoname); +void CL_PlayDemo(char *demoname, qboolean usesystempath); void Media_RecordDemo_f(void) { if (Cmd_Argc() < 2) @@ -3457,7 +3181,7 @@ void Media_RecordDemo_f(void) if (Cmd_FromGamecode()) return; - CL_PlayDemo(Cmd_Argv(1)); + CL_PlayDemo(Cmd_Argv(1), false); if (Cmd_Argc() > 2) Cmd_ShiftArgs(1, false); Media_RecordFilm_f(); @@ -4174,6 +3898,7 @@ void Media_Init(void) #endif Media_RegisterEncoder(NULL, &capture_raw); + Cmd_AddCommand("playvideo", Media_PlayFilm_f); Cmd_AddCommand("playfilm", Media_PlayFilm_f); Cmd_AddCommand("cinematic", Media_PlayFilm_f); Cmd_AddCommand("music_fforward", Media_FForward_f); diff --git a/engine/client/m_multi.c b/engine/client/m_multi.c index 8f2526a0f..54b3992f9 100644 --- a/engine/client/m_multi.c +++ b/engine/client/m_multi.c @@ -278,7 +278,7 @@ typedef struct { int match; } q2skinsearch_t; -int QDECL q2skin_enumerate(const char *name, qofs_t fsize, void *parm, searchpathfuncs_t *spath) +int QDECL q2skin_enumerate(const char *name, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath) { char blah[MAX_QPATH]; q2skinsearch_t *s = parm; diff --git a/engine/client/m_single.c b/engine/client/m_single.c index cb3ce6678..ea503f9c0 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -568,7 +568,7 @@ static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key) if (extnum == info->numext) //wasn't on our list of extensions. extnum = 0; - Cbuf_AddText(va("%s \"%s%s\"\n", info->command[extnum], (info->fsroot==FS_ROOT)?"#":"", info->selected->name), RESTRICT_LOCAL); + Cbuf_AddText(va("%s \"%s%s\"\n", info->command[extnum], (info->fsroot==FS_SYSTEM)?"#":"", info->selected->name), RESTRICT_LOCAL); M_RemoveMenu(menu); } } @@ -577,7 +577,7 @@ static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key) return false; } -static int QDECL DemoAddItem(const char *filename, qofs_t size, void *parm, searchpathfuncs_t *spath) +static int QDECL DemoAddItem(const char *filename, qofs_t size, time_t modified, void *parm, searchpathfuncs_t *spath) { int extnum; demomenu_t *menu = parm; @@ -769,18 +769,18 @@ static void ShowDemoMenu (menu_t *menu, const char *path) if (s && strchr(s+1, '/')) { Q_snprintfz(match, sizeof(match), "%s../", info->path); - DemoAddItem(match, 0, info, NULL); + DemoAddItem(match, 0, 0, info, NULL); } } else if (*info->path) { Q_snprintfz(match, sizeof(match), "%s../", info->path); - DemoAddItem(match, 0, info, NULL); + DemoAddItem(match, 0, 0, info, NULL); } else if (info->fsroot == FS_GAME) { Q_snprintfz(match, sizeof(match), "../"); - DemoAddItem(match, 0, info, NULL); + DemoAddItem(match, 0, 0, info, NULL); } if (info->fsroot == FS_SYSTEM) { diff --git a/engine/client/merged.h b/engine/client/merged.h index 688689fce..61281d829 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -23,14 +23,15 @@ typedef enum #define MAX_BONE_CONTROLLERS 5 #endif +#define FRAME_BLENDS 4 #define FST_BASE 0 //base frames #define FS_REG 1 //regular frames #define FS_COUNT 2 //regular frames typedef struct { - struct { - int frame[2]; - float frametime[2]; - float lerpfrac; + struct framestateregion_s { + int frame[FRAME_BLENDS]; + float frametime[FRAME_BLENDS]; + float lerpweight[FRAME_BLENDS]; #ifdef HALFLIFEMODELS float subblendfrac; //hl models are weird @@ -78,6 +79,7 @@ void R2D_ConsoleBackground (int firstline, int lastline, qboolean forceopaque); void R2D_EditorBackground (void); void R2D_Image(float x, float y, float w, float h, float s1, float t1, float s2, float t2, mpic_t *pic); +void R2D_Image2dQuad(vec2_t points[], vec2_t texcoords[], mpic_t *pic); void R2D_ImageColours(float r, float g, float b, float a); void R2D_ImagePaletteColour(unsigned int i, float a); @@ -105,10 +107,10 @@ extern void SCR_EraseCenterString (void); extern void SCR_CenterPrint (int pnum, char *str, qboolean skipgamecode); void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int defaultmask, unsigned int fieldflags); -#define CPRINT_BALIGN (1<<0) //B +#define CPRINT_LALIGN (1<<0) //L #define CPRINT_TALIGN (1<<1) //T -#define CPRINT_LALIGN (1<<2) //L -#define CPRINT_RALIGN (1<<3) //R +#define CPRINT_RALIGN (1<<2) //R +#define CPRINT_BALIGN (1<<3) //B #define CPRINT_BACKGROUND (1<<4) //P #define CPRINT_OBITUARTY (1<<16) //O (show at 2/3rds from top) diff --git a/engine/client/net_master.c b/engine/client/net_master.c index e9fcf0697..002ed2e1c 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -275,6 +275,8 @@ void SV_Master_Worker_Resolved(void *ctx, void *data, size_t a, size_t b) { switch (master->protocol) { + case MP_UNSPECIFIED: + case MP_NETQUAKE: case MP_DPMASTER: na->port = BigShort (27950); break; case MP_QUAKE2: na->port = BigShort (27000); break; //FIXME: verify case MP_QUAKE3: na->port = BigShort (27950); break; diff --git a/engine/client/pr_clcmd.c b/engine/client/pr_clcmd.c index 8d29363f7..5eddfcfd2 100644 --- a/engine/client/pr_clcmd.c +++ b/engine/client/pr_clcmd.c @@ -359,7 +359,7 @@ void QCBUILTIN PF_cl_runningserver (pubprogfuncs_t *prinst, struct globalvars_s #ifndef NOMEDIA // #487 float(string name) gecko_create -void QCBUILTIN PF_cs_gecko_create (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +void QCBUILTIN PF_cs_media_create_http (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { const char *shadername = PR_GetStringOfs(prinst, OFS_PARM0); cin_t *cin; @@ -385,17 +385,17 @@ void QCBUILTIN PF_cs_gecko_create (pubprogfuncs_t *prinst, struct globalvars_s * G_FLOAT(OFS_RETURN) = 0; } // #488 void(string name) gecko_destroy -void QCBUILTIN PF_cs_gecko_destroy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +void QCBUILTIN PF_cs_media_destroy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { const char *shader = PR_GetStringOfs(prinst, OFS_PARM0); cin_t *cin; cin = R_ShaderFindCinematic(shader); if (!cin) return; - Media_Send_Reset(cin); //FIXME + Media_Send_Reset(cin); //FIXME. unloading shaders can be dangerous } // #489 void(string name, string URI) gecko_navigate -void QCBUILTIN PF_cs_gecko_navigate (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +void QCBUILTIN PF_cs_media_command (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { const char *shader = PR_GetStringOfs(prinst, OFS_PARM0); const char *command = PR_GetStringOfs(prinst, OFS_PARM1); @@ -406,7 +406,7 @@ void QCBUILTIN PF_cs_gecko_navigate (pubprogfuncs_t *prinst, struct globalvars_s Media_Send_Command(cin, command); } // #490 float(string name, float key, float eventtype) gecko_keyevent -void QCBUILTIN PF_cs_gecko_keyevent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +void QCBUILTIN PF_cs_media_keyevent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { const char *shader = PR_GetStringOfs(prinst, OFS_PARM0); int key = G_FLOAT(OFS_PARM1); @@ -418,7 +418,7 @@ void QCBUILTIN PF_cs_gecko_keyevent (pubprogfuncs_t *prinst, struct globalvars_s Media_Send_KeyEvent(cin, MP_TranslateQCtoFTECodes(key), (key>127)?0:key, eventtype); } // #491 void(string name, float x, float y) gecko_mousemove -void QCBUILTIN PF_cs_gecko_mousemove (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +void QCBUILTIN PF_cs_media_mousemove (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { const char *shader = PR_GetStringOfs(prinst, OFS_PARM0); float posx = G_FLOAT(OFS_PARM1); @@ -430,7 +430,7 @@ void QCBUILTIN PF_cs_gecko_mousemove (pubprogfuncs_t *prinst, struct globalvars_ Media_Send_MouseMove(cin, posx, posy); } // #492 void(string name, float w, float h) gecko_resize -void QCBUILTIN PF_cs_gecko_resize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +void QCBUILTIN PF_cs_media_resize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { const char *shader = PR_GetStringOfs(prinst, OFS_PARM0); float sizex = G_FLOAT(OFS_PARM1); @@ -442,25 +442,34 @@ void QCBUILTIN PF_cs_gecko_resize (pubprogfuncs_t *prinst, struct globalvars_s * Media_Send_Resize(cin, sizex, sizey); } // #493 vector(string name) gecko_get_texture_extent -void QCBUILTIN PF_cs_gecko_get_texture_extent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +void QCBUILTIN PF_cs_media_get_texture_extent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { const char *shader = PR_GetStringOfs(prinst, OFS_PARM0); float *ret = G_VECTOR(OFS_RETURN); - int sx, sy; + int sx = 0, sy = 0; + float aspect = 0; cin_t *cin; cin = R_ShaderFindCinematic(shader); if (cin) - { - Media_Send_GetSize(cin, &sx, &sy); - } - else - { - sx = 0; - sy = 0; - } + Media_Send_GetSize(cin, &sx, &sy, &aspect); ret[0] = sx; ret[1] = sy; - ret[2] = 0; + ret[2] = aspect; +} +void QCBUILTIN PF_cs_media_getposition (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + const char *shader = PR_GetStringOfs(prinst, OFS_PARM0); + float *ret = G_VECTOR(OFS_RETURN); + qboolean active = false; + float curtime = 0; + float duration = 0; + cin_t *cin; + cin = R_ShaderFindCinematic(shader); + if (cin) + Media_Send_GetPositions(cin, &active, &curtime, &duration); + ret[0] = active; + ret[1] = curtime; + ret[2] = duration; } #endif @@ -683,4 +692,33 @@ void QCBUILTIN PF_cl_SetBindMap (pubprogfuncs_t *prinst, struct globalvars_s *pr G_FLOAT(OFS_RETURN) = 0; } +//evil builtins to pretend to be a server. +void QCBUILTIN PF_cl_sprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + //this is a bit pointless for menus as it doesn't know player names or anything. +#ifndef CLIENTONLY + int clientnum = G_FLOAT(OFS_PARM0); + char *str = PF_VarString(prinst, 1, pr_globals); + if (sv.active && clientnum < sv.allocated_client_slots && svs.clients[clientnum].state >= cs_connected) + SV_PrintToClient(&svs.clients[clientnum], PRINT_HIGH, str); +#endif +} +void QCBUILTIN PF_cl_bprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ +#ifndef CLIENTONLY + char *str = PF_VarString(prinst, 0, pr_globals); + if (sv.active) + SV_BroadcastPrintf(PRINT_HIGH, "%s", str); +#endif +} +void QCBUILTIN PF_cl_clientcount (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ +#ifndef CLIENTONLY + if (sv.active) + G_FLOAT(OFS_RETURN) = sv.allocated_client_slots; + else + G_FLOAT(OFS_RETURN) = 0; +#endif +} + #endif diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index ba8573e7b..b32db9644 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -75,7 +75,7 @@ static qboolean csqc_worldchanged; //make sure any caches are rebuilt properly b static char csqc_printbuffer[8192]; #define CSQCPROGSGROUP "CSQC progs control" -cvar_t pr_csqc_maxedicts = CVAR("pr_csqc_maxedicts", "8192"); //not tied to protocol nor server. +cvar_t pr_csqc_maxedicts = CVAR("pr_csqc_maxedicts", "65536"); //not tied to protocol nor server. cvar_t pr_csqc_memsize = CVAR("pr_csqc_memsize", "-1"); cvar_t cl_csqcdebug = CVAR("cl_csqcdebug", "0"); //prints entity numbers which arrive (so I can tell people not to apply it to players...) cvar_t cl_nocsqc = CVAR("cl_nocsqc", "0"); @@ -180,6 +180,9 @@ extern sfx_t *cl_sfx_r_exp3; globalvector(input_cursor_start, "input_cursor_trace_start"); /*float filled by getinputstate*/ \ globalvector(input_cursor_impact, "input_cursor_trace_endpos"); /*float filled by getinputstate*/ \ globalfloat(input_cursor_entitynumber, "input_cursor_entitynumber"); /*float filled by getinputstate*/ \ + \ + globalfloat(autocvar_vid_conwidth, "autocvar_vid_conwidth"); /*float hackfix for dp mods*/ \ + globalfloat(autocvar_vid_conheight, "autocvar_vid_conheight"); /*float hackfix for dp mods*/ \ typedef struct { @@ -203,6 +206,7 @@ static csqcglobals_t csqcg; playerview_t csqc_nullview; void VARGS CSQC_Abort (char *format, ...); //an error occured. +static void cs_set_input_state (usercmd_t *cmd); //fixme: we should be using entity numbers, not view numbers. static void CSQC_ChangeLocalPlayer(int seat) @@ -235,19 +239,31 @@ static void CSQC_ChangeLocalPlayer(int seat) csqcg.view_angles[1] = csqc_playerview->viewangles[1]; csqcg.view_angles[2] = csqc_playerview->viewangles[2]; } - if (dpcompat_corruptglobals.ival || csqc_isdarkplaces) + if ((dpcompat_corruptglobals.ival || csqc_isdarkplaces) && (unsigned int)seat < MAX_SPLITS) { + extern usercmd_t independantphysics[MAX_SPLITS]; + int i; + usercmd_t *cmd = &independantphysics[seat]; + usercmd_t tmp = *cmd; + cmd = &tmp; + for (i=0 ; i<3 ; i++) + cmd->angles[i] = ((int)(csqc_playerview->viewangles[i]*65536.0/360)&65535); + if (!cmd->msec) + CL_BaseMove (cmd, seat, 0, 72); + cmd->msec = (realtime - cl.outframes[(cl.movesequence-1)&UPDATE_MASK].senttime)*1000; + cs_set_input_state(cmd); + if (csqcg.pmove_org) { csqcg.pmove_org[0] = csqc_playerview->simorg[0]; csqcg.pmove_org[1] = csqc_playerview->simorg[1]; csqcg.pmove_org[2] = csqc_playerview->simorg[2]; } - if (csqcg.input_angles) + if (csqcg.pmove_vel) { - csqcg.input_angles[0] = csqc_playerview->viewangles[0]; - csqcg.input_angles[1] = csqc_playerview->viewangles[1]; - csqcg.input_angles[2] = csqc_playerview->viewangles[2]; + csqcg.pmove_vel[0] = csqc_playerview->simvel[0]; + csqcg.pmove_vel[1] = csqc_playerview->simvel[1]; + csqcg.pmove_vel[2] = csqc_playerview->simvel[2]; } } } @@ -359,7 +375,7 @@ typedef struct csqcedict_s /*the above is shared with qclib*/ link_t area; pvscache_t pvsinfo; -#ifdef USEODE +#ifdef USERBE entityode_t ode; #endif qbyte solidtype; @@ -415,9 +431,8 @@ static int csqcentsize; static const char *csqcmapentitydata; static qboolean csqcmapentitydataloaded; -qboolean csqc_deprecated_warned; -#define csqc_deprecated(s) do {if (!csqc_deprecated_warned){Con_Printf("csqc warning: %s\n", s); PR_StackTrace (prinst, false); csqc_deprecated_warned = true;}}while(0) - +static unsigned int csqc_deprecated_warned; +#define csqc_deprecated(s) do {if (!csqc_deprecated_warned++){Con_Printf("csqc warning: %s\n", s); PR_StackTrace (prinst, false);}}while(0) static model_t *CSQC_GetModelForIndex(int index); @@ -454,7 +469,8 @@ static void cs_getframestate(csqcedict_t *in, unsigned int rflags, framestate_t out->g[FST_BASE].frame[0] = in->xv->baseframe; out->g[FST_BASE].frame[1] = in->xv->baseframe2; - out->g[FST_BASE].lerpfrac = in->xv->baselerpfrac; + out->g[FST_BASE].lerpweight[1] = in->xv->baselerpfrac; + out->g[FST_BASE].lerpweight[0] = 1-out->g[FST_BASE].lerpweight[1]; if (rflags & CSQCRF_FRAMETIMESARESTARTTIMES) { out->g[FST_BASE].frametime[0] = *csqcg.simtime - in->xv->baseframe1time; @@ -470,16 +486,25 @@ static void cs_getframestate(csqcedict_t *in, unsigned int rflags, framestate_t //and the normal frames. out->g[FS_REG].frame[0] = in->v->frame; out->g[FS_REG].frame[1] = in->xv->frame2; - out->g[FS_REG].lerpfrac = in->xv->lerpfrac; - if (rflags & CSQCRF_FRAMETIMESARESTARTTIMES) + out->g[FS_REG].frame[2] = in->xv->frame3; + out->g[FS_REG].frame[3] = in->xv->frame4; + out->g[FS_REG].lerpweight[1] = in->xv->lerpfrac; + out->g[FS_REG].lerpweight[2] = in->xv->lerpfrac3; + out->g[FS_REG].lerpweight[3] = in->xv->lerpfrac4; + out->g[FS_REG].lerpweight[0] = 1-(out->g[FS_REG].lerpweight[1]+out->g[FS_REG].lerpweight[2]+out->g[FS_REG].lerpweight[3]); + if ((rflags & CSQCRF_FRAMETIMESARESTARTTIMES) || csqc_isdarkplaces) { out->g[FS_REG].frametime[0] = *csqcg.simtime - in->xv->frame1time; out->g[FS_REG].frametime[1] = *csqcg.simtime - in->xv->frame2time; + out->g[FS_REG].frametime[2] = 0;//*csqcg.simtime - in->xv->frame3time; + out->g[FS_REG].frametime[3] = 0;//*csqcg.simtime - in->xv->frame4time; } else { out->g[FS_REG].frametime[0] = in->xv->frame1time; out->g[FS_REG].frametime[1] = in->xv->frame2time; + out->g[FS_REG].frametime[2] = 0;//in->xv->frame3time; + out->g[FS_REG].frametime[3] = 0;//in->xv->frame4time; } @@ -551,16 +576,32 @@ static void QCBUILTIN PF_cvar (pubprogfuncs_t *prinst, struct globalvars_s *pr_g //too specific to the prinst's builtins. static void QCBUILTIN PF_Fixme (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { + int binum; + char fname[MAX_QPATH]; + if (!prinst->GetBuiltinCallInfo(prinst, &binum, fname, sizeof(fname))) + { + binum = 0; + strcpy(fname, "?unknown?"); + } + Con_Printf("\n"); - prinst->RunError(prinst, "\nBuiltin %i not implemented.\nCSQC is not compatible.", prinst->lastcalledbuiltinnumber); + prinst->RunError(prinst, "\nBuiltin %i:%s not implemented.\nCSQC is not compatible.", binum, fname); PR_BIError (prinst, "bulitin not implemented"); } static void QCBUILTIN PF_NoCSQC (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { + int binum; + char fname[MAX_QPATH]; + if (!prinst->GetBuiltinCallInfo(prinst, &binum, fname, sizeof(fname))) + { + binum = 0; + strcpy(fname, "?unknown?"); + } + Con_Printf("\n"); - prinst->RunError(prinst, "\nBuiltin %i does not make sense in csqc.\nCSQC is not compatible.", prinst->lastcalledbuiltinnumber); + prinst->RunError(prinst, "\nBuiltin %i:%s does not make sense in csqc.\nCSQC is not compatible.", binum, fname); PR_BIError (prinst, "bulitin not implemented"); } @@ -1715,7 +1756,7 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars static void QCBUILTIN PF_cs_getstati(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { int stnum = G_FLOAT(OFS_PARM0); - if (stnum >= 128) + if (stnum >= 128 && csqc_isdarkplaces) G_FLOAT(OFS_RETURN) = csqc_playerview->statsf[stnum]; else G_INT(OFS_RETURN) = csqc_playerview->stats[stnum]; @@ -1736,6 +1777,8 @@ static void QCBUILTIN PF_cs_getstatbits(pubprogfuncs_t *prinst, struct globalvar count = 1; G_FLOAT(OFS_RETURN) = (((unsigned int)val)&(((1<>first; } + else if (csqc_isdarkplaces) + G_FLOAT(OFS_RETURN) = (int)csqc_playerview->statsf[stnum]; //stupid. mods like xonotic have a stupid hud if they're actually given any precision else G_FLOAT(OFS_RETURN) = csqc_playerview->statsf[stnum]; } @@ -1782,13 +1825,12 @@ static void QCBUILTIN PF_cs_SetSize (pubprogfuncs_t *prinst, struct globalvars_s e = G_WEDICT(prinst, OFS_PARM0); if (e->isfree) { - Con_TPrintf("%s edict was free\n", "setsize"); - prinst->pr_trace = 1; + PR_RunWarning(prinst, "%s edict was free\n", "setsize"); return; } if (e->readonly) { - Con_TPrintf("setsize on entity %i\n", e->entnum); + PR_RunWarning(prinst, "setsize on entity %i\n", e->entnum); return; } min = G_VECTOR(OFS_PARM1); @@ -2290,7 +2332,7 @@ static void QCBUILTIN PF_objerror (pubprogfuncs_t *prinst, struct globalvars_s * Con_Printf("%s", s); if (developer.value) - prinst->pr_trace = 2; + prinst->debug_trace = 2; else { ED_Free (prinst, ed); @@ -2354,8 +2396,8 @@ static void QCBUILTIN PF_cs_trailparticles (pubprogfuncs_t *prinst, struct globa float *start = G_VECTOR(OFS_PARM2); float *end = G_VECTOR(OFS_PARM3); - if (G_INT(OFS_PARM1) >= MAX_EDICTS) - { + if ((unsigned int)G_INT(OFS_PARM1) >= MAX_EDICTS) + { //ents can't be negative, nor can they be huge (like floats are if expressed as an integer) efnum = G_FLOAT(OFS_PARM1); ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); } @@ -2662,11 +2704,13 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo { unsigned int msecs; - csqcedict_t *ent; - if (prinst->callargc >= 1) - ent = (void*)G_EDICT(prinst, OFS_PARM0); - else - ent = NULL; + csqcedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0); + int mt = ent->v->movetype; + if (prinst->callargc < 1) + { + csqc_deprecated("runplayerphysics with no ent"); + return; + } if (!cl.worldmodel) return; //urm.. @@ -2693,47 +2737,30 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo pmove.safeorigin_known = false; pmove.capsule = false; //FIXME - if (ent) - { - int mt = ent->v->movetype; - if (ent->xv->entnum) - pmove.skipent = ent->xv->entnum; - else - pmove.skipent = -1; - mt &= 255; - switch(mt) - { - default: - case MOVETYPE_WALK: - pmove.pm_type = PM_NORMAL; - break; - case MOVETYPE_NOCLIP: - pmove.pm_type = PM_SPECTATOR; - break; - case MOVETYPE_FLY: - pmove.pm_type = PM_FLY; - break; - } - pmove.jump_held = (int)ent->xv->pmove_flags & PMF_JUMP_HELD; - pmove.waterjumptime = 0; - VectorCopy(ent->v->origin, pmove.origin); - VectorCopy(ent->v->velocity, pmove.velocity); - VectorCopy(ent->v->maxs, pmove.player_maxs); - VectorCopy(ent->v->mins, pmove.player_mins); - } + if (ent->xv->entnum) + pmove.skipent = ent->xv->entnum; else + pmove.skipent = -1; + mt &= 255; + switch(mt) { - csqc_deprecated("runplayerphysics with no ent"); - - if (csqcg.pmove_jump_held) - pmove.jump_held = *csqcg.pmove_jump_held; - if (csqcg.pmove_waterjumptime) - pmove.waterjumptime = *csqcg.pmove_waterjumptime; - VectorCopy(csqcg.pmove_org, pmove.origin); - VectorCopy(csqcg.pmove_vel, pmove.velocity); - VectorCopy(csqcg.pmove_maxs, pmove.player_maxs); - VectorCopy(csqcg.pmove_mins, pmove.player_mins); + default: + case MOVETYPE_WALK: + pmove.pm_type = PM_NORMAL; + break; + case MOVETYPE_NOCLIP: + pmove.pm_type = PM_SPECTATOR; + break; + case MOVETYPE_FLY: + pmove.pm_type = PM_FLY; + break; } + pmove.jump_held = (int)ent->xv->pmove_flags & PMF_JUMP_HELD; + pmove.waterjumptime = 0; + VectorCopy(ent->v->origin, pmove.origin); + VectorCopy(ent->v->velocity, pmove.velocity); + VectorCopy(ent->v->maxs, pmove.player_maxs); + VectorCopy(ent->v->mins, pmove.player_mins); CL_SetSolidEntities(); @@ -2746,29 +2773,16 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo PM_PlayerMove(1); } - if (ent) - { - VectorCopy(pmove.angles, ent->v->angles); - ent->v->angles[0] *= -1/3.0f; - VectorCopy(pmove.origin, ent->v->origin); - VectorCopy(pmove.velocity, ent->v->velocity); - ent->xv->pmove_flags = 0; - ent->xv->pmove_flags += pmove.jump_held ? PMF_JUMP_HELD : 0; - ent->xv->pmove_flags += pmove.onladder ? PMF_LADDER : 0; + VectorCopy(pmove.angles, ent->v->angles); + ent->v->angles[0] *= -1/3.0f; //FIXME + VectorCopy(pmove.origin, ent->v->origin); + VectorCopy(pmove.velocity, ent->v->velocity); + ent->xv->pmove_flags = 0; + ent->xv->pmove_flags += pmove.jump_held ? PMF_JUMP_HELD : 0; + ent->xv->pmove_flags += pmove.onladder ? PMF_LADDER : 0; - //fixme: touch triggers? - World_LinkEdict (&csqc_world, (wedict_t*)ent, true); - } - else - { - //Legacy path - if (csqcg.pmove_jump_held) - *csqcg.pmove_jump_held = pmove.jump_held; - if (csqcg.pmove_waterjumptime) - *csqcg.pmove_waterjumptime = pmove.waterjumptime; - VectorCopy(pmove.origin, csqcg.pmove_org); - VectorCopy(pmove.velocity, csqcg.pmove_vel); - } + //fixme: touch triggers? + World_LinkEdict (&csqc_world, (wedict_t*)ent, true); } static void QCBUILTIN PF_cs_getentitytoken (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -3675,7 +3689,7 @@ static void QCBUILTIN PF_cs_addprogs (pubprogfuncs_t *prinst, struct globalvars_ newp = -1; else { - newp = PR_LoadProgs(prinst, s, NULL, 0); + newp = PR_LoadProgs(prinst, s); if (newp >= 0) PR_ProgsAdded(csqcprogs, newp, s); } @@ -3694,7 +3708,7 @@ static void QCBUILTIN PF_cs_OpenPortal (pubprogfuncs_t *prinst, struct globalvar portal = G_FLOAT(OFS_PARM0); //old legacy crap. else portal = G_WEDICT(prinst, OFS_PARM0)->xv->style; //read the func_areaportal's style field. - CMQ2_SetAreaPortalState(portal, state); + CMQ2_SetAreaPortalState(cl.worldmodel, portal, state); } #endif */ @@ -3706,7 +3720,7 @@ static void QCBUILTIN PF_cs_OpenPortal (pubprogfuncs_t *prinst, struct globalvar int area1 = portal->pvsinfo.areanum, area2 = portal->pvsinfo.areanum2; if (area1 == area2 || area1<0 || area2<0) return; - CMQ3_SetAreaPortalState(portal->pvsinfo.areanum, portal->pvsinfo.areanum2, state); + CMQ3_SetAreaPortalState(cl.worldmodel, portal->pvsinfo.areanum, portal->pvsinfo.areanum2, state); } #endif } @@ -3827,10 +3841,7 @@ static void QCBUILTIN PF_rotatevectorsbytag (pubprogfuncs_t *prinst, struct glob static void QCBUILTIN PF_cs_break (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - Con_Printf ("break statement\n"); -#ifdef TEXTEDITOR - prinst->pr_trace++; -#endif + PR_RunWarning (prinst, "break statement\n"); } //fixme merge with ssqc @@ -4694,6 +4705,7 @@ static void QCBUILTIN PF_resourcestatus(pubprogfuncs_t *prinst, struct globalvar } } +void QCBUILTIN PF_CL_DrawTextField (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); #define PF_FixTen PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme @@ -4969,7 +4981,7 @@ static struct { // {"?", PF_Fixme, 313}, // #313 //2d (immediate) operations -// {"drawtextfield", PF_CL_DrawTextField, 314}, + {"drawtextfield", PF_CL_DrawTextField, 0/*314*/}, {"drawline", PF_CL_drawline, 315}, // #315 void(float width, vector pos1, vector pos2) drawline (EXT_CSQC) {"iscachedpic", PF_CL_is_cached_pic, 316}, // #316 float(string name) iscachedpic (EXT_CSQC) {"precache_pic", PF_CL_precache_pic, 317}, // #317 string(string name, float trywad) precache_pic (EXT_CSQC) @@ -4979,6 +4991,7 @@ static struct { {"drawcharacter", PF_CL_drawcharacter, 320}, // #320 float(vector position, float character, vector scale, vector rgb, float alpha [, float flag]) drawcharacter (EXT_CSQC, [EXT_CSQC_???]) {"drawrawstring", PF_CL_drawrawstring, 321}, // #321 float(vector position, string text, vector scale, vector rgb, float alpha [, float flag]) drawstring (EXT_CSQC, [EXT_CSQC_???]) {"drawpic", PF_CL_drawpic, 322}, // #322 float(vector position, string pic, vector size, vector rgb, float alpha [, float flag]) drawpic (EXT_CSQC, [EXT_CSQC_???]) + {"drawrotpic", PF_CL_drawrotpic, 0}, {"drawfill", PF_CL_drawfill, 323}, // #323 float(vector position, vector size, vector rgb, float alpha [, float flag]) drawfill (EXT_CSQC, [EXT_CSQC_???]) {"drawsetcliparea", PF_CL_drawsetcliparea, 324}, // #324 void(float x, float y, float width, float height) drawsetcliparea (EXT_CSQC_???) {"drawresetcliparea", PF_CL_drawresetcliparea, 325}, // #325 void(void) drawresetcliparea (EXT_CSQC_???) @@ -4986,6 +4999,7 @@ static struct { {"drawstring", PF_CL_drawcolouredstring, 326}, // #326 {"stringwidth", PF_CL_stringwidth, 327}, // #327 EXT_CSQC_'DARKPLACES' {"drawsubpic", PF_CL_drawsubpic, 328}, // #328 EXT_CSQC_'DARKPLACES' + {"drawrotsubpic", PF_CL_drawrotsubpic, 0}, // {"?", PF_Fixme, 329}, // #329 EXT_CSQC_'DARKPLACES' //330 @@ -4997,6 +5011,7 @@ static struct { {"particleeffectnum", PF_cs_particleeffectnum, 335}, // #335 float(string effectname) particleeffectnum (EXT_CSQC) {"trailparticles", PF_cs_trailparticles, 336}, // #336 void(float effectnum, entity ent, vector start, vector end) trailparticles (EXT_CSQC), + {"trailparticles_dp", PF_cs_trailparticles, 336}, // #336 DP sucks {"pointparticles", PF_cs_pointparticles, 337}, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC) {"cprint", PF_cl_cprint, 338}, // #338 void(string s) cprint (EXT_CSQC) @@ -5126,6 +5141,8 @@ static struct { {"search_end", PF_search_end, 445}, // #445 void search_end(float handle) (DP_QC_FS_SEARCH) {"search_getsize", PF_search_getsize, 446}, // #446 float search_getsize(float handle) (DP_QC_FS_SEARCH) {"search_getfilename", PF_search_getfilename,447}, // #447 string search_getfilename(float handle, float num) (DP_QC_FS_SEARCH) + {"search_getfilesize", PF_search_getfilesize, 0}, + {"search_getfilemtime", PF_search_getfilemtime, 0}, {"cvar_string", PF_cvar_string, 448}, // #448 string(float n) cvar_string (DP_QC_CVAR_STRING) {"findflags", PF_FindFlags, 449}, // #449 entity(entity start, .entity fld, float match) findflags (DP_QC_FINDFLAGS) @@ -5200,13 +5217,14 @@ static struct { #ifndef NOMEDIA //DP_GECKO_SUPPORT - {"gecko_create", PF_cs_gecko_create, 487}, // #487 float(string name) gecko_create( string name ) - {"gecko_destroy", PF_cs_gecko_destroy, 488}, // #488 void(string name) gecko_destroy( string name ) - {"gecko_navigate", PF_cs_gecko_navigate, 489}, // #489 void(string name) gecko_navigate( string name, string URI ) - {"gecko_keyevent", PF_cs_gecko_keyevent, 490}, // #490 float(string name) gecko_keyevent( string name, float key, float eventtype ) - {"gecko_mousemove", PF_cs_gecko_mousemove, 491}, // #491 void gecko_mousemove( string name, float x, float y ) - {"gecko_resize", PF_cs_gecko_resize, 492}, // #492 void gecko_resize( string name, float w, float h ) - {"gecko_get_texture_extent",PF_cs_gecko_get_texture_extent, 493}, // #493 vector gecko_get_texture_extent( string name ) + {"gecko_create", PF_cs_media_create_http, 487}, // #487 float(string name) gecko_create( string name ) + {"gecko_destroy", PF_cs_media_destroy, 488}, // #488 void(string name) gecko_destroy( string name ) + {"gecko_navigate", PF_cs_media_command, 489}, // #489 void(string name) gecko_navigate( string name, string URI ) + {"gecko_keyevent", PF_cs_media_keyevent, 490}, // #490 float(string name) gecko_keyevent( string name, float key, float eventtype ) + {"gecko_mousemove", PF_cs_media_mousemove, 491}, // #491 void gecko_mousemove( string name, float x, float y ) + {"gecko_resize", PF_cs_media_resize, 492}, // #492 void gecko_resize( string name, float w, float h ) + {"gecko_get_texture_extent",PF_cs_media_get_texture_extent, 493}, // #493 vector gecko_get_texture_extent( string name ) + {"media_getposition", PF_cs_media_getposition}, #endif //DP_QC_CRC16 @@ -5217,13 +5235,15 @@ static struct { //DP_QC_ENTITYDATA {"numentityfields", PF_numentityfields, 496}, // #496 float() numentityfields + {"findentityfield", PF_findentityfield, 0}, + {"entityfieldref", PF_entityfieldref, 0}, {"entityfieldname", PF_entityfieldname, 497}, // #497 string(float fieldnum) entityfieldname {"entityfieldtype", PF_entityfieldtype, 498}, // #498 float(float fieldnum) entityfieldtype {"getentityfieldstring", PF_getentityfieldstring, 499}, // #499 string(float fieldnum, entity ent) getentityfieldstring {"putentityfieldstring", PF_putentityfieldstring, 500}, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring //DP_SV_WRITEPICTURE - {"WritePicture", PF_ReadPicture, 501}, // #501 void(float to, string s, float sz) WritePicture + {"ReadPicture", PF_ReadPicture, 501}, // #501 void(float to, string s, float sz) WritePicture {"boxparticles", PF_cs_boxparticles, 502}, @@ -5265,7 +5285,7 @@ static struct { // {"matchpattern", PF_Fixme, 538}, // {"undefined", PF_Fixme, 539}, -#ifdef USEODE +#ifdef USERBE {"physics_enable", PF_physics_enable, 540}, {"physics_addforce", PF_physics_addforce, 541}, {"physics_addtorque", PF_physics_addtorque, 542}, @@ -5335,6 +5355,28 @@ int PR_CSQC_BuiltinValid(char *name, int num) static builtin_t csqc_builtin[800]; +static int PDECL PR_CSQC_MapNamedBuiltin(pubprogfuncs_t *progfuncs, int headercrc, const char *builtinname) +{ + int i, binum; + for (i = 0;BuiltinList[i].name;i++) + { + if (!strcmp(BuiltinList[i].name, builtinname) && BuiltinList[i].bifunc != PF_Fixme) + { + for (binum = sizeof(csqc_builtin)/sizeof(csqc_builtin[0]); --binum; ) + { + if (csqc_builtin[binum] && csqc_builtin[binum] != PF_Fixme && BuiltinList[i].bifunc) + continue; + csqc_builtin[binum] = BuiltinList[i].bifunc; + return binum; + } + Con_Printf("No more builtin slots to allocate for %s\n", builtinname); + break; + } + } + Con_DPrintf("Unknown csqc builtin: %s\n", builtinname); + return 0; +} + @@ -5415,9 +5457,12 @@ pbool QDECL CSQC_EntFree (struct edict_s *e) Mod_WipeSkin(ent->skinobject); ent->skinobject = 0; -#ifdef USEODE - World_ODE_RemoveFromEntity(&csqc_world, (wedict_t*)ent); - World_ODE_RemoveJointFromEntity(&csqc_world, (wedict_t*)ent); +#ifdef USERBE + if (csqc_world.rbe) + { + csqc_world.rbe->RemoveFromEntity(&csqc_world, (wedict_t*)ent); + csqc_world.rbe->RemoveJointFromEntity(&csqc_world, (wedict_t*)ent); + } #endif return true; @@ -5509,9 +5554,8 @@ void CSQC_Shutdown(void) Cmd_RemoveCommands(CS_ConsoleCommand_f); -#ifdef USEODE - World_ODE_End(&csqc_world); -#endif + if (csqc_world.rbe) + csqc_world.rbe->End(&csqc_world); Z_Free(csqcdelta_pack_new.e); memset(&csqcdelta_pack_new, 0, sizeof(csqcdelta_pack_new)); @@ -5536,6 +5580,12 @@ void CSQC_Shutdown(void) in_sensitivityscale = 1; csqc_world.num_edicts = 0; + + if (csqc_deprecated_warned>1) + { + Con_Printf("total %u csqc deprecation warnings suppressed\n", csqc_deprecated_warned-1); + csqc_deprecated_warned = 0; + } } //when the qclib needs a file, it calls out to this function. @@ -5800,8 +5850,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks csqcprogparms.cwstateop = CSQC_CWStateOp;//CWStateOp; csqcprogparms.thinktimeop = CSQC_ThinkTimeOp;//ThinkTimeOp; - //used when loading a game - csqcprogparms.builtinsfor = NULL;//builtin_t *(*builtinsfor) (int num); //must return a pointer to the builtins that were used before the state was saved. + csqcprogparms.MapNamedBuiltin = PR_CSQC_MapNamedBuiltin; csqcprogparms.loadcompleate = NULL;//void (*loadcompleate) (int edictsize); //notification to reset any pointers. csqcprogparms.memalloc = PR_CB_Malloc;//void *(*memalloc) (int size); //small string allocation malloced and freed randomly @@ -5853,14 +5902,14 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks csqc_isdarkplaces = false; if (csdatenabled || csqc_singlecheats || anycsqc) { - csprogsnum = PR_LoadProgs(csqcprogs, "csprogs.dat", NULL, 0); + csprogsnum = PR_LoadProgs(csqcprogs, "csprogs.dat"); if (csprogsnum == -1) Con_DPrintf("Loaded csprogs.dat\n"); } if (csqc_singlecheats || anycsqc) { - csaddonnum = PR_LoadProgs(csqcprogs, "csaddon.dat", NULL, 0); + csaddonnum = PR_LoadProgs(csqcprogs, "csaddon.dat"); if (csaddonnum >= 0) Con_DPrintf("loaded csaddon.dat...\n"); else @@ -5898,7 +5947,10 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks } } - CSQC_FindGlobals(); + if (csqc_isdarkplaces) + memset(&csqcg, 0, sizeof(csqcg)); + else + CSQC_FindGlobals(); csqcentsize = PR_InitEnts(csqcprogs, pr_csqc_maxedicts.value); @@ -5973,13 +6025,15 @@ void CSQC_WorldLoaded(void) return; if (csqcmapentitydataloaded) return; + + if (csqc_isdarkplaces) + CSQC_FindGlobals(); + csqcmapentitydataloaded = true; csqcmapentitydata = cl.worldmodel->entities; csqc_world.worldmodel = cl.worldmodel; -#ifdef USEODE - World_ODE_Start(&csqc_world); -#endif + World_RBE_Start(&csqc_world); worldent = (csqcedict_t *)EDICT_NUM(csqcprogs, 0); worldent->v->solid = SOLID_BSP; @@ -5987,6 +6041,18 @@ void CSQC_WorldLoaded(void) worldent->readonly = false; //just in case + if (csqc_isdarkplaces) + { + if (csqcg.init_function) + { + void *pr_globals = PR_globals(csqcprogs, PR_CURRENT); + G_FLOAT(OFS_PARM0) = CSQC_API_VERSION; //api version + (((string_t *)pr_globals)[OFS_PARM1] = PR_TempString(csqcprogs, FULLENGINENAME)); + G_FLOAT(OFS_PARM2) = version_number(); + PR_ExecuteProgram(csqcprogs, csqcg.init_function); + } + } + if (csqcg.worldloaded) PR_ExecuteProgram(csqcprogs, csqcg.worldloaded); csqcmapentitydata = NULL; @@ -6297,9 +6363,15 @@ qboolean CSQC_DrawView(void) if (host_frametime > mintic) host_frametime = mintic; - #ifdef USEODE - World_ODE_Frame(&csqc_world, host_frametime, 800); - #endif +#ifdef USERBE + if (csqc_world.rbe) + { +#ifdef RAGDOLL + rag_doallanimations(&sv.world); +#endif + csqc_world.rbe->Frame(&csqc_world, host_frametime, 800); + } +#endif World_Physics_Frame(&csqc_world); csqc_world.physicstime += host_frametime; @@ -6365,6 +6437,11 @@ qboolean CSQC_DrawView(void) CSQC_RunThreads(); //wake up any qc threads + if (csqcg.autocvar_vid_conwidth) + *csqcg.autocvar_vid_conwidth = vid.width; + if (csqcg.autocvar_vid_conheight) + *csqcg.autocvar_vid_conheight = vid.height; + //EXT_CSQC_1 { void *pr_globals = PR_globals(csqcprogs, PR_CURRENT); @@ -6378,6 +6455,13 @@ qboolean CSQC_DrawView(void) else PR_ExecuteProgram(csqcprogs, csqcg.f_updateview); + if (*r_refdef.rt_destcolour[0].texname) + { + Q_strncpyz(r_refdef.rt_destcolour[0].texname, "", sizeof(r_refdef.rt_destcolour[0].texname)); + BE_RenderToTextureUpdate2d(true); + } + + return true; } diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 82faae722..179d42d0f 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -475,6 +475,51 @@ void QCBUILTIN PF_CL_drawpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl r2d_be_flags = 0; } +void QCBUILTIN PF_CL_drawrotpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + float *pivot = G_VECTOR(OFS_PARM0); + float *mins = G_VECTOR(OFS_PARM1); + float *maxs = G_VECTOR(OFS_PARM2); + const char *picname = PR_GetStringOfs(prinst, OFS_PARM3); + float *rgb = G_VECTOR(OFS_PARM4); + float alpha = G_FLOAT(OFS_PARM5); + float angle = (G_FLOAT(OFS_PARM6) * M_PI)/180; + int flag = prinst->callargc >= 8?(int) G_FLOAT(OFS_PARM7):0; + + vec2_t points[4]; + vec2_t tcoords[4]; + vec2_t saxis; + vec2_t taxis; + + mpic_t *p; + + p = R2D_SafeCachePic(picname); + if (!p) + p = R2D_SafePicFromWad(picname); + + saxis[0] = cos(angle); + saxis[1] = sin(angle); + taxis[0] = -sin(angle); + taxis[1] = cos(angle); + + Vector2MA(pivot, mins[0], saxis, points[0]); Vector2MA(points[0], mins[1], taxis, points[0]); + Vector2MA(pivot, maxs[0], saxis, points[1]); Vector2MA(points[1], mins[1], taxis, points[1]); + Vector2MA(pivot, maxs[0], saxis, points[2]); Vector2MA(points[2], maxs[1], taxis, points[2]); + Vector2MA(pivot, mins[0], saxis, points[3]); Vector2MA(points[3], maxs[1], taxis, points[3]); + + Vector2Set(tcoords[0], 0, 0); + Vector2Set(tcoords[1], 1, 0); + Vector2Set(tcoords[2], 1, 1); + Vector2Set(tcoords[3], 0, 1); + + r2d_be_flags = PF_SelectDPDrawFlag(flag); + R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha); + R2D_Image2dQuad(points, tcoords, p); + r2d_be_flags = 0; + + G_FLOAT(OFS_RETURN) = 1; +} + void QCBUILTIN PF_CL_drawsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { float *pos = G_VECTOR(OFS_PARM0); @@ -503,7 +548,50 @@ void QCBUILTIN PF_CL_drawsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr G_FLOAT(OFS_RETURN) = 1; } +void QCBUILTIN PF_CL_drawrotsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + float *pivot = G_VECTOR(OFS_PARM0); + float *mins = G_VECTOR(OFS_PARM1); + float *maxs = G_VECTOR(OFS_PARM2); + const char *picname = PR_GetStringOfs(prinst, OFS_PARM3); + float *srcPos = G_VECTOR(OFS_PARM4); + float *srcSize = G_VECTOR(OFS_PARM5); + float *rgb = G_VECTOR(OFS_PARM6); + float alpha = G_FLOAT(OFS_PARM7+0); + float angle = (G_FLOAT(OFS_PARM7+1) * M_PI) / 180; + int flag = prinst->callargc >= 8?(int) G_FLOAT(OFS_PARM7+2):0; + vec2_t points[4], tcoords[4]; + vec2_t saxis; + vec2_t taxis; + mpic_t *p; + + saxis[0] = cos(angle); + saxis[1] = sin(angle); + taxis[0] = -sin(angle); + taxis[1] = cos(angle); + + p = R2D_SafeCachePic(picname); + if (!p) + p = R2D_SafePicFromWad(picname); + + Vector2MA(pivot, mins[0], saxis, points[0]); Vector2MA(points[0], mins[1], taxis, points[0]); + Vector2MA(pivot, maxs[0], saxis, points[1]); Vector2MA(points[1], mins[1], taxis, points[1]); + Vector2MA(pivot, maxs[0], saxis, points[2]); Vector2MA(points[2], maxs[1], taxis, points[2]); + Vector2MA(pivot, mins[0], saxis, points[3]); Vector2MA(points[3], maxs[1], taxis, points[3]); + + Vector2Set(tcoords[0], srcPos[0] , srcPos[1] ); + Vector2Set(tcoords[1], srcPos[0]+srcSize[0] , srcPos[1] ); + Vector2Set(tcoords[2], srcPos[0]+srcSize[0] , srcPos[1]+srcSize[1] ); + Vector2Set(tcoords[3], srcPos[0] , srcPos[1]+srcSize[1] ); + + r2d_be_flags = PF_SelectDPDrawFlag(flag); + R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha); + R2D_Image2dQuad(points, tcoords, p); + r2d_be_flags = 0; + + G_FLOAT(OFS_RETURN) = 1; +} @@ -540,7 +628,7 @@ void QCBUILTIN PF_CL_precache_pic (pubprogfuncs_t *prinst, struct globalvars_s * CL_CheckOrEnqueDownloadFile(str, str, 0); } - if (pic) + if (pic && R_GetShaderSizes(pic, NULL, NULL, true)) G_INT(OFS_RETURN) = G_INT(OFS_PARM0); else G_INT(OFS_RETURN) = 0; @@ -1061,7 +1149,10 @@ void QCBUILTIN PF_nonfatalobjerror (pubprogfuncs_t *prinst, struct globalvars_s if (developer.value) - prinst->pr_trace = 2; + { //enable tracing. + PR_RunWarning(prinst, "======OBJECT ERROR======\n%s\n", s); + return; + } else { ED_Free (prinst, ed); @@ -1099,9 +1190,16 @@ void QCBUILTIN PF_clientstate (pubprogfuncs_t *prinst, struct globalvars_s *pr_g //too specific to the prinst's builtins. static void QCBUILTIN PF_Fixme (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - Con_Printf("\n"); + int binum; + char fname[MAX_QPATH]; + if (!prinst->GetBuiltinCallInfo(prinst, &binum, fname, sizeof(fname))) + { + binum = 0; + strcpy(fname, "?unknown?"); + } - prinst->RunError(prinst, "\nBuiltin %i not implemented.\nMenu is not compatible.", prinst->lastcalledbuiltinnumber); + Con_Printf("\n"); + prinst->RunError(prinst, "\nBuiltin %i:%s not implemented.\nMenu is not compatible.", binum, fname); PR_BIError (prinst, "bulitin not implemented"); } @@ -1541,13 +1639,13 @@ static void QCBUILTIN PF_m_precache_model(pubprogfuncs_t *prinst, struct globalv static void QCBUILTIN PF_m_setmodel(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { menuedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0); - string_t modelname = G_INT(OFS_PARM1); //FIXME: zone it or something? + const char *modelname = PR_GetStringOfs(prinst, OFS_PARM1); eval_t *modelval = prinst->GetEdictFieldValue(prinst, (void*)ent, "model", &menuc_eval.model); eval_t *minsval = prinst->GetEdictFieldValue(prinst, (void*)ent, "mins", &menuc_eval.mins); eval_t *maxsval = prinst->GetEdictFieldValue(prinst, (void*)ent, "maxs", &menuc_eval.maxs); - model_t *mod = Mod_ForName(prinst->StringToNative(prinst, modelname), MLV_WARN); + model_t *mod = Mod_ForName(modelname, MLV_WARN); if (modelval) - modelval->string = modelname; + modelval->string = G_INT(OFS_PARM1); //lets hope garbage collection is enough. if (mod && minsval) VectorCopy(mod->mins, minsval->_vector); if (mod && maxsval) @@ -1608,7 +1706,8 @@ static qboolean CopyMenuEdictToEntity(pubprogfuncs_t *prinst, menuedict_t *in, e out->skinnum = skinval?skinval->_float:0; out->framestate.g[FS_REG].frame[0] = frame1val?frame1val->_float:0; out->framestate.g[FS_REG].frame[1] = frame2val?frame2val->_float:0; - out->framestate.g[FS_REG].lerpfrac = lerpfracval?lerpfracval->_float:0; + out->framestate.g[FS_REG].lerpweight[1] = lerpfracval?lerpfracval->_float:0; + out->framestate.g[FS_REG].lerpweight[0] = 1-out->framestate.g[FS_REG].lerpweight[1]; out->framestate.g[FS_REG].frametime[0] = frame1timeval?frame1timeval->_float:0; out->framestate.g[FS_REG].frametime[1] = frame2timeval?frame2timeval->_float:0; @@ -1663,6 +1762,43 @@ static void QCBUILTIN PF_m_renderscene(pubprogfuncs_t *prinst, struct globalvars void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); + +static void QCBUILTIN PF_menu_cprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + char *str = PF_VarString(prinst, 0, pr_globals); + SCR_CenterPrint(0, str, true); +} +static void QCBUILTIN PF_cl_changelevel (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ +#ifndef CLIENTONLY + const char *nextmap = PR_GetStringOfs(prinst, OFS_PARM0); + if (sv.active || !cls.state) + { + char buf[1024]; + Cbuf_AddText(va("changelevel %s\n", COM_QuotedString(nextmap, buf, sizeof(buf), false)), RESTRICT_INSECURE); + } +#endif +} +static void QCBUILTIN PF_crash (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int binum; + char fname[MAX_QPATH]; + //allow people to rename it or whatever + if (!prinst->GetBuiltinCallInfo(prinst, &binum, fname, sizeof(fname))) + { + binum = 0; + strcpy(fname, "?unknown?"); + } + + prinst->RunError(prinst, "\n%s called", fname); +} +static void QCBUILTIN PF_stackdump (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + prinst->StackTrace(prinst, true); +} +#define PF_cl_clientcommand PF_Fixme +#define PF_altstr_ins PF_Fixme //insert after, apparently + static struct { char *name; builtin_t bifunc; @@ -1672,9 +1808,9 @@ static struct { {"error", PF_error, 2}, {"objerror", PF_nonfatalobjerror, 3}, {"print", PF_print, 4}, - {"bprint", PF_Fixme, 5}, - {"msprint", PF_Fixme, 6}, - {"cprint", PF_Fixme, 7}, + {"bprint", PF_cl_bprint, 5}, + {"msprint", PF_cl_sprint, 6}, + {"cprint", PF_menu_cprint, 7}, {"normalize", PF_normalize, 8}, {"vlen", PF_vlen, 9}, {"vectoyaw", PF_vectoyaw, 10}, @@ -1728,10 +1864,10 @@ static struct { {"tokenize", PF_Tokenize, 58}, {"argv", PF_ArgV, 59}, {"isserver", PF_isserver, 60}, - {"clientcount", PF_Fixme, 61}, //float clientcount(void) = #61; + {"clientcount", PF_cl_clientcount, 61}, //float clientcount(void) = #61; {"clientstate", PF_clientstate, 62}, - {"clientcommand", PF_Fixme, 63}, //void clientcommand(float client, string s) = #63; - {"changelevel", PF_Fixme, 64}, //void changelevel(string map) = #64; + {"clientcommand", PF_cl_clientcommand, 63}, //void clientcommand(float client, string s) = #63; + {"changelevel", PF_cl_changelevel, 64}, //void changelevel(string map) = #64; {"localsound", PF_localsound, 65}, {"getmousepos", PF_cl_getmousepos, 66}, {"gettime", PF_gettime, 67}, @@ -1739,12 +1875,14 @@ static struct { {"loadfromfile", PF_loadfromfile, 69}, {"mod", PF_mod, 70}, {"cvar_string", PF_menu_cvar_string, 71}, - {"crash", PF_Fixme, 72}, //void crash(void) = #72; - {"stackdump", PF_Fixme, 73}, //void stackdump(void) = #73; + {"crash", PF_crash, 72}, //void crash(void) = #72; + {"stackdump", PF_stackdump, 73}, //void stackdump(void) = #73; {"search_begin", PF_search_begin, 74}, {"search_end", PF_search_end, 75}, {"search_getsize", PF_search_getsize, 76}, {"search_getfilename", PF_search_getfilename, 77}, + {"search_getfilesize", PF_search_getfilesize, 0}, + {"search_getfilemtime", PF_search_getfilemtime, 0}, {"chr2str", PF_chr2str, 78}, {"etof", PF_etof, 79}, {"ftoe", PF_ftoe, 80}, @@ -1753,7 +1891,7 @@ static struct { {"altstr_prepare", PF_altstr_prepare, 83}, {"altstr_get", PF_altstr_get, 84}, {"altstr_set", PF_altstr_set, 85}, - {"altstr_ins", PF_Fixme, 86}, + {"altstr_ins", PF_altstr_ins, 86}, {"findflags", PF_FindFlags, 87}, {"findchainflags", PF_menu_findchainflags, 88}, {"mcvar_defstring", PF_cvar_defstring, 89}, @@ -1840,6 +1978,7 @@ static struct { {"drawcharacter", PF_CL_drawcharacter, 454}, {"drawrawstring", PF_CL_drawrawstring, 455}, {"drawpic", PF_CL_drawpic, 456}, + {"drawrotpic", PF_CL_drawrotpic, 0}, {"drawfill", PF_CL_drawfill, 457}, {"drawsetcliparea", PF_CL_drawsetcliparea, 458}, {"drawresetcliparea", PF_CL_drawresetcliparea, 459}, @@ -1853,6 +1992,7 @@ static struct { {"drawstring", PF_CL_drawcolouredstring, 467}, {"stringwidth", PF_CL_stringwidth, 468}, {"drawsubpic", PF_CL_drawsubpic, 469}, + {"drawrotsubpic", PF_CL_drawrotsubpic, 0}, //470 //MERGES WITH CLIENT+SERVER BUILTIN MAPPINGS BELOW {"asin", PF_asin, 471}, @@ -1871,16 +2011,19 @@ static struct { {"strreplace", PF_strreplace, 484}, {"strireplace", PF_strireplace, 485}, //486 - {"gecko_create", PF_cs_gecko_create, 487}, - {"gecko_destroy", PF_cs_gecko_destroy, 488}, - {"gecko_navigate", PF_cs_gecko_navigate, 489}, - {"gecko_keyevent", PF_cs_gecko_keyevent, 490}, - {"gecko_mousemove", PF_cs_gecko_mousemove, 491}, - {"gecko_resize", PF_cs_gecko_resize, 492}, - {"gecko_get_texture_extent",PF_cs_gecko_get_texture_extent,493}, + {"gecko_create", PF_cs_media_create_http, 487}, + {"gecko_destroy", PF_cs_media_destroy, 488}, + {"gecko_navigate", PF_cs_media_command, 489}, + {"gecko_keyevent", PF_cs_media_keyevent, 490}, + {"gecko_mousemove", PF_cs_media_mousemove, 491}, + {"gecko_resize", PF_cs_media_resize, 492}, + {"gecko_get_texture_extent",PF_cs_media_get_texture_extent,493}, + {"media_getposition", PF_cs_media_getposition}, {"crc16", PF_crc16, 494}, {"cvar_type", PF_cvar_type, 495}, {"numentityfields", PF_numentityfields, 496}, + {"findentityfield", PF_findentityfield, 0}, + {"entityfieldref", PF_entityfieldref, 0}, {"entityfieldname", PF_entityfieldname, 497}, {"entityfieldtype", PF_entityfieldtype, 498}, {"getentityfieldstring", PF_getentityfieldstring, 499}, @@ -1945,7 +2088,7 @@ static struct { {"crypto_getmyidstatus", PF_crypto_getmyidfp, 641}, {NULL} }; -builtin_t menu_builtins[1024]; +static builtin_t menu_builtins[1024]; int MP_BuiltinValid(char *name, int num) @@ -1979,6 +2122,28 @@ static void MP_SetupBuiltins(void) } } +static int PDECL PR_Menu_MapNamedBuiltin(pubprogfuncs_t *progfuncs, int headercrc, const char *builtinname) +{ + int i, binum; + for (i = 0;BuiltinList[i].name;i++) + { + if (!strcmp(BuiltinList[i].name, builtinname) && BuiltinList[i].bifunc != PF_Fixme) + { + for (binum = sizeof(menu_builtins)/sizeof(menu_builtins[0]); --binum; ) + { + if (menu_builtins[binum] && menu_builtins[binum] != PF_Fixme && BuiltinList[i].bifunc) + continue; + menu_builtins[binum] = BuiltinList[i].bifunc; + return binum; + } + Con_Printf("No more builtin slots to allocate for %s\n", builtinname); + break; + } + } + Con_DPrintf("Unknown menu builtin: %s\n", builtinname); + return 0; +} + void M_Init_Internal (void); void M_DeInit_Internal (void); @@ -2119,9 +2284,7 @@ qboolean MP_Init (void) menuprogparms.cstateop = NULL;//CStateOp; menuprogparms.cwstateop = NULL;//CWStateOp; menuprogparms.thinktimeop = NULL;//ThinkTimeOp; - - //used when loading a game - menuprogparms.builtinsfor = NULL;//builtin_t *(*builtinsfor) (int num); //must return a pointer to the builtins that were used before the state was saved. + menuprogparms.MapNamedBuiltin = PR_Menu_MapNamedBuiltin; menuprogparms.loadcompleate = NULL;//void (*loadcompleate) (int edictsize); //notification to reset any pointers. menuprogparms.memalloc = PR_CB_Malloc;//void *(*memalloc) (int size); //small string allocation malloced and freed randomly @@ -2138,7 +2301,6 @@ qboolean MP_Init (void) menuprogparms.sv_edicts = (struct edict_s **)&menu_edicts; menuprogparms.sv_num_edicts = &num_menu_edicts; - menuprogparms.useeditor = NULL;//sorry... QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms); menuprogparms.useeditor = QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms); menuprogparms.user = &menu_world; menu_world.keydestmask = kdm_menu; @@ -2150,7 +2312,7 @@ qboolean MP_Init (void) Con_DPrintf("Initializing menu.dat\n"); menu_world.progs = InitProgs(&menuprogparms); PR_Configure(menu_world.progs, 64*1024*1024, 1, pr_enable_profiling.ival); - mprogs = PR_LoadProgs(menu_world.progs, "menu.dat", NULL, 0); + mprogs = PR_LoadProgs(menu_world.progs, "menu.dat"); if (mprogs < 0) //no per-progs builtins. { //failed to load or something diff --git a/engine/client/pr_skelobj.c b/engine/client/pr_skelobj.c index 85b29d566..56093b7a7 100644 --- a/engine/client/pr_skelobj.c +++ b/engine/client/pr_skelobj.c @@ -59,8 +59,8 @@ typedef struct doll_s int numbodies; int numjoints; int numbones; - odebodyinfo_t *body; - odejointinfo_t *joint; + rbebodyinfo_t *body; + rbejointinfo_t *joint; struct { //easy lookup table for bone->body. @@ -71,7 +71,7 @@ typedef struct doll_s typedef struct { - odebody_t odebody; + rbebody_t odebody; // int ownerent; /*multiple of 12*/ // int flags; @@ -100,7 +100,7 @@ typedef struct skelobject_s unsigned int numbodies; body_t *body; int numjoints; - odejoint_t *joint; + rbejoint_t *joint; doll_t *doll; wedict_t *entity; //only valid for dolls. #endif @@ -293,11 +293,11 @@ typedef struct { int numbones; galiasbone_t *bones; - odebodyinfo_t *body; - odejointinfo_t *joint; + rbebodyinfo_t *body; + rbejointinfo_t *joint; - odebodyinfo_t defbody; - odejointinfo_t defjoint; + rbebodyinfo_t defbody; + rbejointinfo_t defjoint; } dollcreatectx_t; static dollcreatectx_t *rag_createdoll(model_t *mod, const char *fname, int numbones) { @@ -1088,7 +1088,7 @@ static void rag_uninstanciate(skelobject_t *sko) for (i = 0; i < sko->numbodies; i++) { - World_ODE_RagDestroyBody(sko->world, &sko->body[i].odebody); + sko->world->rbe->RagDestroyBody(sko->world, &sko->body[i].odebody); } BZ_Free(sko->body); sko->body = NULL; @@ -1096,7 +1096,7 @@ static void rag_uninstanciate(skelobject_t *sko) for (i = 0; i < sko->numjoints; i++) { - World_ODE_RagDestroyJoint(sko->world, &sko->joint[i]); + sko->world->rbe->RagDestroyJoint(sko->world, &sko->joint[i]); } BZ_Free(sko->joint); sko->joint = NULL; @@ -1105,7 +1105,7 @@ static void rag_uninstanciate(skelobject_t *sko) sko->doll->uses--; sko->doll = NULL; } -void rag_genbodymatrix(skelobject_t *sko, odebodyinfo_t *dollbody, float *emat, float *result) +void rag_genbodymatrix(skelobject_t *sko, rbebodyinfo_t *dollbody, float *emat, float *result) { float *bmat; int bone = dollbody->bone; @@ -1144,8 +1144,8 @@ qboolean rag_instanciate(skelobject_t *sko, doll_t *doll, float *emat, wedict_t int numbones; galiasbone_t *bones = Mod_GetBoneInfo(sko->model, &numbones); int bone; - odebody_t *body1, *body2; - odejointinfo_t *j; + rbebody_t *body1, *body2; + rbejointinfo_t *j; sko->numbodies = doll->numbodies; sko->body = BZ_Malloc(sizeof(*sko->body) * sko->numbodies); sko->doll = doll; @@ -1164,7 +1164,7 @@ qboolean rag_instanciate(skelobject_t *sko, doll_t *doll, float *emat, wedict_t Matrix3x4_Invert_Simple(bones[doll->body[i].bone].inverse, bodymat); else rag_genbodymatrix(sko, &doll->body[i], emat, bodymat); - if (!World_ODE_RagCreateBody(sko->world, &sko->body[i].odebody, &doll->body[i], bodymat, ent)) + if (!sko->world->rbe->RagCreateBody(sko->world, &sko->body[i].odebody, &doll->body[i], bodymat, ent)) return false; } sko->numjoints = doll->numjoints; @@ -1197,7 +1197,7 @@ qboolean rag_instanciate(skelobject_t *sko, doll_t *doll, float *emat, wedict_t VectorNormalize2(j->axis, aaa2[1]); VectorNormalize2(j->axis2, aaa2[2]); - World_ODE_RagCreateJoint(sko->world, &sko->joint[i], j, body1, body2, aaa2); + sko->world->rbe->RagCreateJoint(sko->world, &sko->joint[i], j, body1, body2, aaa2); } //now the joints have all their various properties, move the bones to their real positions. @@ -1205,7 +1205,7 @@ qboolean rag_instanciate(skelobject_t *sko, doll_t *doll, float *emat, wedict_t for (i = 0; i < sko->numbodies; i++) { rag_genbodymatrix(sko, &doll->body[i], emat, bodymat); - World_ODE_RagMatrixToBody(&sko->body[i].odebody, bodymat); + sko->world->rbe->RagMatrixToBody(&sko->body[i].odebody, bodymat); } sko->doll->numdefaultanimated = sko->numanimated; @@ -1253,7 +1253,7 @@ void rag_derive(skelobject_t *sko, skelobject_t *asko, float *emat) "}\n" "}\n"); - World_ODE_RagMatrixFromBody(sko->world, &sko->body[i].odebody, bodymat); + sko->world->rbe->RagMatrixFromBody(sko->world, &sko->body[i].odebody, bodymat); switch(doll->body[i].geomshape) { @@ -1283,7 +1283,7 @@ void rag_derive(skelobject_t *sko, skelobject_t *asko, float *emat) { if (!doll->joint[i].draw) continue; - World_ODE_RagMatrixFromJoint(&sko->joint[i], &doll->joint[i], bodymat); + sko->world->rbe->RagMatrixFromJoint(&sko->joint[i], &doll->joint[i], bodymat); // CLQ1_AddOrientedCube(debugshader, mins, maxs, bodymat, 0, 0.2, 0, 1); if (!lineshader) @@ -1319,7 +1319,7 @@ void rag_derive(skelobject_t *sko, skelobject_t *asko, float *emat) if (doll->bone[i].bodyidx >= 0) { //bones with a body are given an absolute pose matching that body. - World_ODE_RagMatrixFromBody(sko->world, &sko->body[doll->bone[i].bodyidx].odebody, bodymat); + sko->world->rbe->RagMatrixFromBody(sko->world, &sko->body[doll->bone[i].bodyidx].odebody, bodymat); //that body matrix is in world space, so transform to model space for our result R_ConcatTransforms((void*)invemat, (void*)bodymat, (void*)((float*)bmat+i*12)); } @@ -1372,7 +1372,7 @@ void rag_doallanimations(world_t *world) { if (!sko->body[j].animstrength) continue; - World_ODE_RagMatrixToBody(&sko->body[j].odebody, sko->body[j].animmatrix); + sko->world->rbe->RagMatrixToBody(&sko->body[j].odebody, sko->body[j].animmatrix); } } } @@ -1412,7 +1412,7 @@ void rag_updatedeltaent(entity_t *ent, lerpents_t *le) if (mod->dollinfo) { w = &csqc_world; - if (!w->ode.ode) + if (!w->rbe) return; if (!le->skeletalobject) @@ -1508,9 +1508,9 @@ void QCBUILTIN PF_skel_ragedit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g return; } - if (!sko->world->ode.ode) + if (!sko->world->rbe) { - Con_DPrintf("PF_skel_ragedit: ODE not enabled\n"); + Con_DPrintf("PF_skel_ragedit: rigid body system not enabled\n"); return; } @@ -1531,7 +1531,7 @@ void QCBUILTIN PF_skel_ragedit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g { int idx = rag_finddolljoint(sko->doll, Cmd_Argv(1)); int enable = atoi(Cmd_Argv(2)); - World_ODE_RagEnableJoint(&sko->joint[idx], enable); + sko->world->rbe->RagEnableJoint(&sko->joint[idx], enable); G_FLOAT(OFS_RETURN) = 1; return; } @@ -2141,6 +2141,7 @@ void QCBUILTIN PF_gettaginfo (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl world_t *w = prinst->parms->user; wedict_t *ent = G_WEDICT(prinst, OFS_PARM0); int tagnum = G_FLOAT(OFS_PARM1); + int chain = 10; int modelindex = ent->v->modelindex; @@ -2149,6 +2150,7 @@ void QCBUILTIN PF_gettaginfo (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl float transent[12]; float transforms[12]; float result[12]; + float result2[12]; framestate_t fstate; @@ -2159,17 +2161,22 @@ void QCBUILTIN PF_gettaginfo (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl bonemat_fromidentity(transforms); } - if (ent->xv->tag_entity) - { -#ifdef warningmsg - #pragma warningmsg("PF_gettaginfo: This function doesn't honour attachments") -#endif - Con_Printf("bug: PF_gettaginfo doesn't support attachments\n"); - } - bonemat_fromentity(w, ent, transent); R_ConcatTransforms((void*)transent, (void*)transforms, (void*)result); + while (ent->xv->tag_entity && chain --> 0) + { + w->Get_FrameState(w, ent, &fstate); + if (!Mod_GetTag(mod, tagnum, &fstate, transforms)) + bonemat_fromidentity(transforms); + + bonemat_fromentity(w, ent, transent); + R_ConcatTransforms((void*)transforms, (void*)result, (void*)result2); + R_ConcatTransforms((void*)transent, (void*)result2, (void*)result); + + ent = PROG_TO_WEDICT(prinst, ent->xv->tag_entity); + } + bonemat_toqcvectors(result, w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_RETURN)); } diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index cb8f1cb55..6cd34e4aa 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -442,6 +442,29 @@ void R2D_Image(float x, float y, float w, float h, float s1, float t1, float s2, BE_DrawMesh_Single(pic, &draw_mesh, NULL, &pic->defaulttextures, r2d_be_flags); } +void R2D_Image2dQuad(vec2_t points[], vec2_t texcoords[], mpic_t *pic) +{ + int i; + if (!pic) + return; + + //don't draw pics if they have an image which is still loading. + for (i = 0; i < pic->numpasses; i++) + { + if (pic->passes[i].texgen == T_GEN_SINGLEMAP && pic->passes[i].anim_frames[0] && pic->passes[i].anim_frames[0]->status == TEX_LOADING) + return; + if (pic->passes[i].texgen == T_GEN_DIFFUSE && pic->defaulttextures.base && pic->defaulttextures.base->status == TEX_LOADING) + return; + } + + for (i = 0; i < 4; i++) + { + Vector2Copy(points[i], draw_mesh_xyz[i]); + Vector2Copy(texcoords[i], draw_mesh_st[i]); + } + + BE_DrawMesh_Single(pic, &draw_mesh, NULL, &pic->defaulttextures, r2d_be_flags); +} /*draws a block of the current colour on the screen*/ void R2D_FillBlock(float x, float y, float w, float h) diff --git a/engine/client/render.h b/engine/client/render.h index 13931fdc1..986c1c2f8 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -561,7 +561,6 @@ extern cvar_t r_clear; extern cvar_t gl_poly; extern cvar_t gl_affinemodels; extern cvar_t gl_nohwblend; -extern cvar_t gl_reporttjunctions; extern cvar_t r_coronas, r_flashblend, r_flashblendscale; extern cvar_t r_lightstylesmooth; extern cvar_t r_lightstylesmooth_limit; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 63ef181da..0340b4163 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -356,6 +356,9 @@ cvar_t r_lightprepass = CVARFD("r_lightprepass", "0", CVAR_SHADERSYSTEM, "E cvar_t r_shadow_bumpscale_basetexture = CVARD ("r_shadow_bumpscale_basetexture", "0", "bumpyness scaler for generation of fallback normalmap textures from models"); cvar_t r_shadow_bumpscale_bumpmap = CVARD ("r_shadow_bumpscale_bumpmap", "4", "bumpyness scaler for _bump textures"); +cvar_t r_shadow_heightscale_basetexture = CVARD ("r_shadow_heightscale_basetexture", "0", "scaler for generation of height maps from legacy paletted content."); +cvar_t r_shadow_heightscale_bumpmap = CVARD ("r_shadow_heightscale_bumpmap", "1", "height scaler for 8bit _bump textures"); + cvar_t r_glsl_offsetmapping = CVARFD ("r_glsl_offsetmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Enables the use of paralax mapping, adding fake depth to textures."); cvar_t r_glsl_offsetmapping_scale = CVAR ("r_glsl_offsetmapping_scale", "0.04"); cvar_t r_glsl_offsetmapping_reliefmapping = CVARFD("r_glsl_offsetmapping_reliefmapping", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes the paralax sampling mode to be a bit nicer. r_glsl_offsetmapping must be set."); @@ -430,8 +433,8 @@ void GLRenderer_Init(void) Cvar_Register (&gl_maxshadowlights, GLRENDEREROPTIONS); Cvar_Register (&r_shadow_bumpscale_basetexture, GLRENDEREROPTIONS); Cvar_Register (&r_shadow_bumpscale_bumpmap, GLRENDEREROPTIONS); - - Cvar_Register (&gl_reporttjunctions, GLRENDEREROPTIONS); + Cvar_Register (&r_shadow_heightscale_basetexture, GLRENDEREROPTIONS); + Cvar_Register (&r_shadow_heightscale_bumpmap, GLRENDEREROPTIONS); Cvar_Register (&gl_motionblur, GLRENDEREROPTIONS); Cvar_Register (&gl_motionblurscale, GLRENDEREROPTIONS); diff --git a/engine/client/snd_al.c b/engine/client/snd_al.c index f4c8f0d6b..124e37b0f 100644 --- a/engine/client/snd_al.c +++ b/engine/client/snd_al.c @@ -559,6 +559,8 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned { if (!S_LoadSound(sfx)) return; //can't load it + if (sfx->loadstate != SLS_LOADED) + return; //not available yet if (sfx->decoder.decodedata) { int offset; diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index 29b7db2d8..f131365dd 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -459,7 +459,7 @@ void Sys_SaveClipboard(char *text) } -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { DIR *dir; char apath[MAX_OSPATH]; @@ -517,7 +517,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const { Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":""); - if (!func(file, st.st_size, parm, spath)) + if (!func(file, st.st_size, st.st_mtime, parm, spath)) { closedir(dir); return false; diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index 740e08dea..261980430 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -410,7 +410,7 @@ int Sys_DebugLog(char *file, char *fmt, ...) return 1; } -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t modtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { DIR *dir; char apath[MAX_OSPATH]; @@ -468,7 +468,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const { Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":""); - if (!func(file, st.st_size, parm, spath)) + if (!func(file, st.st_size, st.st_mtime, parm, spath)) { Con_DPrintf("giving up on search after finding %s\n", file); closedir(dir); diff --git a/engine/client/sys_sdl.c b/engine/client/sys_sdl.c index 25b3cb087..bfca27a48 100644 --- a/engine/client/sys_sdl.c +++ b/engine/client/sys_sdl.c @@ -160,7 +160,7 @@ void Sys_Quit (void) //SDL provides no file enumeration facilities. #if defined(_WIN32) #include -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { HANDLE r; WIN32_FIND_DATA fd; @@ -207,7 +207,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const if (wildcmp(match, fd.cFileName)) { Q_snprintfz(file, sizeof(file), "%s%s/", apath2, fd.cFileName); - go = func(file, fd.nFileSizeLow, parm, spath); + go = func(file, fd.nFileSizeLow, 0, parm, spath); } } else @@ -215,7 +215,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const if (wildcmp(match, fd.cFileName)) { Q_snprintfz(file, sizeof(file), "%s%s", apath2, fd.cFileName); - go = func(file, fd.nFileSizeLow, parm, spath); + go = func(file, fd.nFileSizeLow, 0, parm, spath); } } } @@ -226,7 +226,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const } #elif defined(linux) || defined(__unix__) || defined(__MACH__) #include -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { DIR *dir; char apath[MAX_OSPATH]; @@ -284,7 +284,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const { Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":""); - if (!func(file, st.st_size, parm, spath)) + if (!func(file, st.st_size, st.st_mtime, parm, spath)) { closedir(dir); return false; @@ -300,7 +300,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const return true; } #else -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, void *), void *parm, void *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, void *), void *parm, void *spath) { Con_Printf("Warning: Sys_EnumerateFiles not implemented\n"); return false; diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index b107da002..36b77b480 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -149,7 +149,7 @@ qboolean Sys_Rename (char *oldfname, char *newfname) } //enumeratefiles is recursive for */* to work -static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) +static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) { qboolean go; @@ -247,7 +247,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(utf8) + 2 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s/", tmproot+matchstart, utf8); - go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), 0, parm, spath); } } } @@ -258,7 +258,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(utf8) + 1 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s", tmproot+matchstart, utf8); - go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), 0, parm, spath); } } } @@ -1021,7 +1021,15 @@ qboolean Sys_Rename (char *oldfname, char *newfname) return !rename(oldfname, newfname); } -static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) +static time_t Sys_FileTimeToTime(FILETIME ft) +{ + ULARGE_INTEGER ull; + ull.LowPart = ft.dwLowDateTime; + ull.HighPart = ft.dwHighDateTime; + return ull.QuadPart / 10000000ULL - 11644473600ULL; +} + +static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) { qboolean go; if (!WinNT) @@ -1109,7 +1117,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(fd.cFileName) + 2 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s/", tmproot+matchstart, fd.cFileName); - go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), Sys_FileTimeToTime(fd.ftLastWriteTime), parm, spath); } } } @@ -1120,7 +1128,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(fd.cFileName) + 1 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s", tmproot+matchstart, fd.cFileName); - go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), Sys_FileTimeToTime(fd.ftLastWriteTime), parm, spath); } } } @@ -1224,7 +1232,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(utf8) + 2 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s/", tmproot+matchstart, utf8); - go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), Sys_FileTimeToTime(fd.ftLastWriteTime), parm, spath); } } } @@ -1235,7 +1243,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(utf8) + 1 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s", tmproot+matchstart, utf8); - go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), Sys_FileTimeToTime(fd.ftLastWriteTime), parm, spath); } } } @@ -1245,7 +1253,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart } return go; } -int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) { char fullmatch[MAX_OSPATH]; int start; diff --git a/engine/client/textedit.c b/engine/client/textedit.c index 48f5371a8..46a3d1a6a 100644 --- a/engine/client/textedit.c +++ b/engine/client/textedit.c @@ -10,8 +10,8 @@ F6 will list the stack. F7 will compile. F8 will move execution F9 will set a break point. -F10 will apply code changes. -F11 will step through. +F10 will step over. +F11 will step into. */ #include "quakedef.h" @@ -86,6 +86,7 @@ static char OpenEditorFile[256]; qboolean editoractive; //(export) qboolean editormodal; //doesn't return. (export) +int editorstep; static qboolean madechanges; static qboolean editenabled; static qboolean insertkeyhit=true; @@ -207,6 +208,7 @@ static void CloseEditor(void) madechanges = false; editormodal = false; + editorstep = DEBUG_TRACE_OFF; firstblock = NULL; @@ -288,7 +290,7 @@ static void EditorNewFile(void) editenabled = true; } -static void EditorOpenFile(char *name, qboolean readonly) +static void EditorOpenFile(const char *name, qboolean readonly) { int i; char line[8192]; @@ -455,7 +457,7 @@ void Editor_Key(int key, int unicode) { case K_ESCAPE: if (editprogfuncs) - editprogfuncs->pr_trace = 0; + editprogfuncs->debug_trace = DEBUG_TRACE_OFF; useeval = false; return; case K_F3: @@ -628,8 +630,7 @@ void Editor_Key(int key, int unicode) break; case K_F5: /*stop debugging*/ editormodal = false; - if (editprogfuncs) - editprogfuncs->pr_trace = false; + editorstep = DEBUG_TRACE_OFF; break; case K_F6: if (editprogfuncs) @@ -676,12 +677,17 @@ void Editor_Key(int key, int unicode) cursorblock->flags &= ~FB_BREAK; } break; - case K_F10: //save+apply changes, supposedly - EditorSaveFile(OpenEditorFile); - Cbuf_AddText("applycompile\n", RESTRICT_LOCAL); + case K_F10: + editormodal = false; + editorstep = DEBUG_TRACE_OVER; break; case K_F11: //single step editormodal = false; + editorstep = DEBUG_TRACE_INTO; + break; + case K_F12: //save+apply changes, supposedly + EditorSaveFile(OpenEditorFile); + Cbuf_AddText("applycompile\n", RESTRICT_LOCAL); break; // case K_STOP: case K_ESCAPE: @@ -695,6 +701,7 @@ void Editor_Key(int key, int unicode) else CloseEditor(); editormodal = false; + editorstep = DEBUG_TRACE_ABORT; break; case K_HOME: @@ -1199,11 +1206,17 @@ void Editor_Draw(void) */ } -int QCLibEditor(pubprogfuncs_t *prfncs, char *filename, int line, int statement, int nump, char **parms) +int QCLibEditor(pubprogfuncs_t *prfncs, const char *filename, int *line, int *statement, int nump, char **parms) { - char *f1, *f2; - if (editormodal || (line < 0 && !statement) || !pr_debugger.ival) - return line; //whoops + const char *f1, *f2; + if (!pr_debugger.ival) + { + Con_Printf("Set %s to trace\n", pr_debugger.name); + return DEBUG_TRACE_OFF; //get lost + } + //we can cope with no line info by displaying asm + if (editormodal || !statement) + return DEBUG_TRACE_OFF; //whoops if (qrenderer == QR_NONE) { @@ -1212,14 +1225,12 @@ int QCLibEditor(pubprogfuncs_t *prfncs, char *filename, int line, int statement, char *r; vfsfile_t *f; - if (line == -1) - return -1; f = FS_OpenVFS(filename, "rb", FS_GAME); if (!f) - Con_Printf("%s - %i\n", filename, line); + Con_Printf("%s - %i\n", filename, *line); else { - for (i = 0; i < line; i++) + for (i = 0; i < *line; i++) { VFS_GETS(f, buffer, sizeof(buffer)); } @@ -1229,7 +1240,7 @@ int QCLibEditor(pubprogfuncs_t *prfncs, char *filename, int line, int statement, VFS_CLOSE(f); } //PF_break(NULL); - return line; + return DEBUG_TRACE_OUT; } editprogfuncs = prfncs; @@ -1245,7 +1256,7 @@ int QCLibEditor(pubprogfuncs_t *prfncs, char *filename, int line, int statement, if (!strncmp(f2, "source/", 7)) f2 += 7; - stepasm = line < 0; + stepasm = !line; if (stepasm) { @@ -1255,7 +1266,7 @@ int QCLibEditor(pubprogfuncs_t *prfncs, char *filename, int line, int statement, E_Free(firstblock->next); E_Free(firstblock); - cursorlinenum = statement; + cursorlinenum = *statement; firstblock = GenAsm(cursorlinenum); cursorblock = firstblock; @@ -1286,7 +1297,7 @@ int QCLibEditor(pubprogfuncs_t *prfncs, char *filename, int line, int statement, EditorOpenFile(filename, true); } - for (cursorlinenum = 1, cursorblock = firstblock; cursorlinenum < line && cursorblock->next; cursorlinenum++) + for (cursorlinenum = 1, cursorblock = firstblock; cursorlinenum < *line && cursorblock->next; cursorlinenum++) cursorblock=cursorblock->next; } @@ -1298,6 +1309,7 @@ int QCLibEditor(pubprogfuncs_t *prfncs, char *filename, int line, int statement, { double oldrealtime = realtime; editormodal = true; + editorstep = DEBUG_TRACE_OFF; while(editormodal && editoractive && editprogfuncs) { @@ -1317,9 +1329,13 @@ int QCLibEditor(pubprogfuncs_t *prfncs, char *filename, int line, int statement, } if (stepasm) - return -executionlinenum; + { + *line = 0; + *statement = executionlinenum; + } else - return executionlinenum; + *line = executionlinenum; + return editorstep; } void Editor_ProgsKilled(pubprogfuncs_t *dead) @@ -1328,6 +1344,7 @@ void Editor_ProgsKilled(pubprogfuncs_t *dead) { editprogfuncs = NULL; editormodal = false; + editorstep = DEBUG_TRACE_OFF; } } diff --git a/engine/client/view.c b/engine/client/view.c index cd400a7d6..44d7d7f84 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -1206,8 +1206,8 @@ void V_ClearRefdef(playerview_t *pv) r_refdef.grect.x = 0; r_refdef.grect.y = 0; - r_refdef.grect.width = vid.width; - r_refdef.grect.height = vid.height; + r_refdef.grect.width = vid.fbvwidth;//vid.width; + r_refdef.grect.height = vid.fbvheight;//vid.height; r_refdef.afov = scr_fov.value; //will have a better value applied if fov is bad. this allows setting. r_refdef.fov_x = 0; @@ -1404,8 +1404,8 @@ void SCR_VRectForPlayer(vrect_t *vrect, int pnum) switch(cl.splitclients) { case 1: - vrect->width = vid.width; - vrect->height = vid.height; + vrect->width = vid.fbvwidth; + vrect->height = vid.fbvheight; vrect->x = 0; vrect->y = 0; @@ -1423,8 +1423,8 @@ void SCR_VRectForPlayer(vrect_t *vrect, int pnum) && ffov.value >= 0 /*panoramic view always stacks player views*/ ) { //over twice as wide as high, assume dual moniter, horizontal. - vrect->width = vid.width/cl.splitclients; - vrect->height = vid.height; + vrect->width = vid.fbvwidth/cl.splitclients; + vrect->height = vid.fbvheight; vrect->x = 0 + vrect->width*pnum; vrect->y = 0; } @@ -1432,8 +1432,8 @@ void SCR_VRectForPlayer(vrect_t *vrect, int pnum) #endif { //stack them vertically - vrect->width = vid.width; - vrect->height = vid.height/cl.splitclients; + vrect->width = vid.fbvwidth; + vrect->height = vid.fbvheight/cl.splitclients; vrect->x = 0; vrect->y = 0 + vrect->height*pnum; } @@ -1441,8 +1441,8 @@ void SCR_VRectForPlayer(vrect_t *vrect, int pnum) break; case 4: //4 squares - vrect->width = vid.width/2; - vrect->height = vid.height/2; + vrect->width = vid.fbvwidth/2; + vrect->height = vid.fbvheight/2; vrect->x = (pnum&1) * vrect->width; vrect->y = (pnum&2)/2 * vrect->height; break; @@ -1503,7 +1503,8 @@ void R_DrawNameTags(void) int buflen; int x, y; - buflen = 0; + sprintf(asciibuffer, "entity %i ", e->entnum); + buflen = strlen(asciibuffer); entstr = w->progs->saveent(w->progs, asciibuffer, &buflen, sizeof(asciibuffer), (edict_t*)e); //will save just one entities vars if (entstr) { diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index d9c285c04..bf7c38c34 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -237,10 +237,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PLUGINS //qvm/dll plugins. #define SUPPORT_ICE //Interactive Connectivity Establishment protocol, for peer-to-peer connections -#ifdef _DEBUG -// #define OFFSCREENGECKO //FIXME: move to plugin and remove from engine -#endif - #define CSQC_DAT //support for csqc #define MENU_DAT //support for menu.dat @@ -441,10 +437,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #if defined(CSQC_DAT) || !defined(CLIENTONLY) //use ode only if we have a constant world state, and the library is enbled in some form. - #define USEODE 1 - #if !(defined(ODE_STATIC) || defined(ODE_DYNAMIC)) - #undef USEODE - #endif + #define USERBE #endif #if defined(ZYMOTICMODELS) || defined(MD5MODELS) || defined(DPMMODELS) || defined(PSKMODELS) || defined(INTERQUAKEMODELS) @@ -453,7 +446,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #if (defined(CSQC_DAT) || !defined(CLIENTONLY)) && defined(SKELETALMODELS) #define SKELETALOBJECTS //the skeletal objects API is only used if we actually have skeletal models, and gamecode that uses the builtins. #endif -#if !defined(USEODE) || !defined(SKELETALMODELS) +#if !defined(USERBE) || !defined(SKELETALMODELS) #undef RAGDOLL //not possible to ragdoll if we don't have certain other features. #endif diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 8f26cb528..506e46792 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -1116,7 +1116,7 @@ static void R_LerpFrames(mesh_t *mesh, galiaspose_t *p1, galiaspose_t *p2, float #ifdef SKELETALMODELS /* - returns the up-to-4 skeletal bone poses to blend together. + returns the up-to-8 skeletal bone poses to blend together. return value is the number of blends that are actually live. */ typedef struct @@ -1124,85 +1124,86 @@ typedef struct skeltype_t skeltype; //the skeletal type of this bone block. all blocks should have the same result or the whole thing is unusable or whatever. int firstbone; //first bone of interest int endbone; //the first bone of the next group (ie: if first is 0, this is the count) - float frac[4]; //weight of this animation (1 if lerpcount is 1) - float *pose[4]; //pointer to the raw frame data for bone 0. + float frac[8]; //weight of this animation (1 if lerpcount is 1) + float *pose[8]; //pointer to the raw frame data for bone 0. int lerpcount; //number of pose+frac entries. } skellerps_t; -static void Alias_BuildSkelLerps(skellerps_t *lerps, int numbones, galiasgroup_t *g1, galiasgroup_t *g2, float lerpfrac, float fg1time, float fg2time) +static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, struct framestateregion_s *fs, int numbones, galiasinfo_t *inf) { - int frame1; - int frame2; + unsigned int frame1; + unsigned int frame2; float mlerp; //minor lerp, poses within a group. int l = 0; - if (g1 == g2) - lerpfrac = 0; - if (fg1time < 0) - fg1time = 0; - mlerp = (fg1time)*g1->rate; - frame1=mlerp; - frame2=frame1+1; - mlerp-=frame1; - if (g1->loop) + galiasgroup_t *g; + unsigned int b; + float totalweight = 0; + for (b = 0; b < FRAME_BLENDS; b++) { - frame1=frame1%g1->numposes; - frame2=frame2%g1->numposes; - } - else - { - frame1=(frame1>g1->numposes-1)?g1->numposes-1:frame1; - frame2=(frame2>g1->numposes-1)?g1->numposes-1:frame2; + if (fs->lerpweight[b]) + { + unsigned int frame = fs->frame[b]; + float time = fs->frametime[b]; + if (frame >= inf->groups) + continue;//frame = (unsigned)frame%inf->groups; + + g = &inf->groupofs[frame]; + if (!g->numposes) + continue; //err... + + mlerp = time*g->rate; + frame1=mlerp; + frame2=frame1+1; + mlerp-=frame1; + if (g->loop) + { //loop normally. + frame1=frame1%g->numposes; + frame2=frame2%g->numposes; + } + else + { + frame1=(frame1>g->numposes-1)?g->numposes-1:frame1; + frame2=(frame2>g->numposes-1)?g->numposes-1:frame2; + } + + if (!l) + lerps->skeltype = g->skeltype; + else if (lerps->skeltype != g->skeltype) + continue; //oops, can't cope with mixed blend types + + if (frame1 == frame2 || r_noframegrouplerp.ival) + mlerp = 0; + lerps->frac[l] = (1-mlerp)*fs->lerpweight[b]; + if (lerps->frac[l]>0) + { + totalweight += lerps->frac[l]; + lerps->pose[l++] = g->boneofs + numbones*12*frame1; + } + lerps->frac[l] = (mlerp)*fs->lerpweight[b]; + if (lerps->frac[l]>0) + { + totalweight += lerps->frac[l]; + lerps->pose[l++] = g->boneofs + numbones*12*frame2; + } + } } - if (frame1 == frame2 || r_noframegrouplerp.ival) - mlerp = 0; - lerps->frac[l] = (1-mlerp)*(1-lerpfrac); - if (lerps->frac[l]>0) - lerps->pose[l++] = g1->boneofs + numbones*12*frame1; - lerps->frac[l] = (mlerp)*(1-lerpfrac); - if (lerps->frac[l]>0) - lerps->pose[l++] = g1->boneofs + numbones*12*frame2; - - if (lerpfrac) - { - if (fg2time < 0) - fg2time = 0; - mlerp = (fg2time)*g2->rate; - frame1=mlerp; - frame2=frame1+1; - mlerp-=frame1; - if (g2->loop) + if (l && totalweight != 1) + { //don't rescale if some animation got dropped. + totalweight = 1 / totalweight; + for (b = 0; b < l; b++) { - frame1=frame1%g2->numposes; - frame2=frame2%g2->numposes; + lerps->frac[l] *= totalweight; } - else - { - frame1=(frame1>g2->numposes-1)?g2->numposes-1:frame1; - frame2=(frame2>g2->numposes-1)?g2->numposes-1:frame2; - } - if (frame1 == frame2 || r_noframegrouplerp.ival) - mlerp = 0; - lerps->frac[l] = (1-mlerp)*(lerpfrac); - if (lerps->frac[l]>0) - lerps->pose[l++] = g2->boneofs + numbones*12*frame1; - lerps->frac[l] = (mlerp)*(lerpfrac); - if (lerps->frac[l]>0) - lerps->pose[l++] = g2->boneofs + numbones*12*frame2; } lerps->lerpcount = l; + return l > 0; } /* finds the various blend info. returns number of bone blocks used. */ static int Alias_FindRawSkelData(galiasinfo_t *inf, framestate_t *fstate, skellerps_t *lerps, size_t firstbone, size_t lastbone) { - galiasgroup_t *g1, *g2; - - int frame1, frame2; - float f1time, f2time; - float f2ness; - int bonegroup; int cbone = 0; int endbone; @@ -1220,13 +1221,7 @@ static int Alias_FindRawSkelData(galiasinfo_t *inf, framestate_t *fstate, skelle if (endbone == cbone) continue; - frame1 = fstate->g[bonegroup].frame[0]; - frame2 = fstate->g[bonegroup].frame[1]; - f1time = fstate->g[bonegroup].frametime[0]; - f2time = fstate->g[bonegroup].frametime[1]; - f2ness = fstate->g[bonegroup].lerpfrac; - - if (!inf->groups) //if there's no animations in this model, use the base pose instead. + if (!inf->groups || !Alias_BuildSkelLerps(lerps, &fstate->g[bonegroup], inf->numbones, inf)) //if there's no animations in this model, use the base pose instead. { if (!inf->baseframeofs) continue; //nope, not happening. @@ -1235,34 +1230,6 @@ static int Alias_FindRawSkelData(galiasinfo_t *inf, framestate_t *fstate, skelle lerps->pose[0] = inf->baseframeofs; lerps->lerpcount = 1; } - else - { - if (frame1 < 0) - { - if (frame2 < 0) - { - if (bonegroup != FS_COUNT-1) - continue; //just ignore this group - frame2 = 0; - } - frame1 = frame2; - } - else if (frame2 < 0) - frame2 = frame1; - if (frame1 >= inf->groups) - frame1 %= inf->groups; - if (frame2 >= inf->groups) - frame2 %= inf->groups; - - //the higher level merges old/new anims, but we still need to blend between automated frame-groups. - g1 = &inf->groupofs[frame1]; - g2 = &inf->groupofs[frame2]; - - if (g2->skeltype != g1->skeltype) - g2 = g1; - lerps->skeltype = g1->skeltype; - Alias_BuildSkelLerps(lerps, inf->numbones, g1, g2, f2ness, f1time, f2time); - } lerps->firstbone = cbone; lerps->endbone = endbone; cbone = endbone; @@ -1814,7 +1781,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in { frame1 = e->framestate.g[FS_REG].frame[0]; frame2 = e->framestate.g[FS_REG].frame[1]; - lerp = e->framestate.g[FS_REG].lerpfrac; + lerp = e->framestate.g[FS_REG].lerpweight[1]; //FIXME fg1time = e->framestate.g[FS_REG].frametime[0]; //fg2time = e->framestate.g[FS_REG].frametime[1]; @@ -4018,7 +3985,7 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res frame2 = fstate->g[FS_REG].frame[1]; //f1time = fstate->g[FS_REG].frametime[0]; //f2time = fstate->g[FS_REG].frametime[1]; - f2ness = fstate->g[FS_REG].lerpfrac; + f2ness = fstate->g[FS_REG].lerpweight[1]; if (tagnum <= 0 || tagnum > inf->numtags) return false; @@ -5888,7 +5855,7 @@ qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t fsize) #else m->numskins = skinfiles; - skin = ZG_Malloc(&mod->memgroup, (sizeof(galiasskin_t)+sizeof(skinframe_t*))*skinfiles); + skin = ZG_Malloc(&mod->memgroup, (sizeof(galiasskin_t)+sizeof(skinframe_t))*skinfiles); skinframe = (skinframe_t*)(skin+skinfiles); for (j = 0; j < skinfiles; j++, skinframe++) { @@ -6093,7 +6060,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize) galiasinfo_t *gai=NULL; #ifndef SERVERONLY galiasskin_t *skin=NULL; - skinframe_t *frame=NULL; + skinframe_t *skinframe=NULL; int skinfiles; #endif galiasgroup_t *fgroup=NULL; @@ -6254,7 +6221,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize) else orgbaf = NULL; dalloc(skin, h->num_meshes*skinfiles); - dalloc(frame, h->num_meshes*skinfiles); + dalloc(skinframe, h->num_meshes*skinfiles); #endif dalloc(fgroup, numgroups); dalloc(oposebase, 12*h->num_joints); @@ -6417,10 +6384,10 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize) skin->skinheight = 1; skin->skinspeed = 10; /*something to avoid div by 0*/ skin->numframes = 1; //non-sequenced skins. - skin->frame = frame; + skin->frame = skinframe; skin++; - Q_strncpyz(frame[j].shadername, strings+mesh[i].material, sizeof(frame[j].shadername)); + Q_strncpyz(skinframe[j].shadername, strings+mesh[i].material, sizeof(skinframe[j].shadername)); } #endif @@ -7321,7 +7288,7 @@ void Alias_Register(void) Mod_RegisterModelFormatMagic(NULL, "Zymotic Model (zym)", (('O'<<24)+('M'<<16)+('Y'<<8)+'Z'), Mod_LoadZymoticModel); #endif #ifdef DPMMODELS - Mod_RegisterModelFormatMagic(NULL, "DarkPlaces Model (dpm)", (('K'<<24)+('R'<<16)+('A'<<8)+'D'), Mod_LoadDarkPlacesModel); +// Mod_RegisterModelFormatMagic(NULL, "DarkPlaces Model (dpm)", (('K'<<24)+('R'<<16)+('A'<<8)+'D'), Mod_LoadDarkPlacesModel); #endif #ifdef PSKMODELS Mod_RegisterModelFormatMagic(NULL, "Unreal Interchange Model (psk)", ('A'<<0)+('C'<<8)+('T'<<16)+('R'<<24), Mod_LoadPSKModel); diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index 60b7cd592..3a5e731dc 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -1,3 +1,6 @@ +#ifdef __cplusplus +extern "C" { +#endif #include "hash.h" #include "shader.h" @@ -182,11 +185,20 @@ typedef struct void (QDECL *ConcatTransforms) (float in1[3][4], float in2[3][4], float out[3][4]); void (QDECL *M3x4_Invert) (const float *in1, float *out); - void (QDECL *StripExtension) (const char *in, char *out, int outlen); + void (QDECL *VectorAngles)(float *forward, float *up, float *result); + void (QDECL *AngleVectors)(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); void (QDECL *GenMatrixPosQuat4Scale)(vec3_t pos, vec4_t quat, vec3_t scale, float result[12]); + + void (QDECL *StripExtension) (const char *in, char *out, int outlen); void (QDECL *ForceConvertBoneData)(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, size_t destbonecount); + + void (QDECL *LinkEdict)(world_t *w, wedict_t *ed, qboolean touchtriggers); + qboolean (QDECL *RegisterPhysicsEngine)(const char *enginename, void(QDECL*World_Bullet_Start)(world_t*world)); //returns false if there's already one active. + void (QDECL *UnregisterPhysicsEngine)(const char *enginename); //returns false if there's already one active. + qboolean (QDECL *GenerateCollisionMesh)(world_t *world, model_t *mod, wedict_t *ed, vec3_t geomcenter); + void (QDECL *ReleaseCollisionMesh) (wedict_t *ed); } modplugfuncs_t; -#define MODPLUGFUNCS_VERSION 1 +#define MODPLUGFUNCS_VERSION 2 #ifdef SKELETALMODELS void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout); @@ -210,3 +222,7 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize); void Mod_AccumulateTextureVectors(vecV_t *vc, vec2_t *tc, vec3_t *nv, vec3_t *sv, vec3_t *tv, index_t *idx, int numidx); void Mod_AccumulateMeshTextureVectors(mesh_t *mesh); void Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v); + +#ifdef __cplusplus +}; +#endif \ No newline at end of file diff --git a/engine/common/com_phys_bullet.cpp b/engine/common/com_phys_bullet.cpp new file mode 100644 index 000000000..074e2d0e9 --- /dev/null +++ b/engine/common/com_phys_bullet.cpp @@ -0,0 +1,1763 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +//can either be built as a separate dll or statically linked in the engine (will still be treated as if dynamically) +//to enable as static, add the file to the makefile/project and edit engine/common/plugin.c to list Plug_$foo_Init + + +#ifndef FTEPLUGIN +#define FTEENGINE +#define FTEPLUGIN +#define pCvar_Register Cvar_Get +#define pCvar_GetFloat(x) Cvar_FindVar(x)->value +#define pSys_Error Sys_Error +#define Plug_Init Plug_Bullet_Init +#pragma comment(lib,"../../plugins/bullet/libs/bullet_dbg.lib") +#endif + +#include "../../plugins/plugin.h" +#include "../../plugins/engine.h" + +#include "pr_common.h" +#include "com_mesh.h" + +#ifndef FTEENGINE +#define BZ_Malloc malloc +#define BZ_Free free +#define Z_Free BZ_Free +static vec3_t vec3_origin; +static int VectorCompare (const vec3_t v1, const vec3_t v2) +{ + int i; + for (i=0 ; i<3 ; i++) + if (v1[i] != v2[i]) + return 0; + return 1; +} + +#endif +static modplugfuncs_t *modfuncs; + + +//============================================================================ +// physics engine support +//============================================================================ + +#define DEG2RAD(d) (d * M_PI * (1/180.0f)) +#define RAD2DEG(d) ((d*180) / M_PI) + +#include + + +static void World_Bullet_RunCmd(world_t *world, rbecommandqueue_t *cmd); + +void World_Bullet_Init(void) +{ + pCvar_Register("physics_bullet_enable", "1", 0, "Bullet"); + pCvar_Register("physics_bullet_maxiterationsperframe", "10", 0, "Bullet"); + pCvar_Register("physics_bullet_framerate", "60", 0, "Bullet"); +} + +void World_Bullet_Shutdown(void) +{ +} + +typedef struct bulletcontext_s +{ + rigidbodyengine_t funcs; + + qboolean hasextraobjs; +// void *ode_space; +// void *ode_contactgroup; + // number of constraint solver iterations to use (for dWorldStepFast) +// int ode_iterations; + // actual step (server frametime / ode_iterations) +// vec_t ode_step; + // max velocity for a 1-unit radius object at current step to prevent + // missed collisions +// vec_t ode_movelimit; + rbecommandqueue_t *cmdqueuehead; + rbecommandqueue_t *cmdqueuetail; + + + world_t *gworld; + + + btBroadphaseInterface *broadphase; + btDefaultCollisionConfiguration *collisionconfig; + btCollisionDispatcher *collisiondispatcher; + btSequentialImpulseConstraintSolver *solver; + btDiscreteDynamicsWorld *dworld; + btOverlapFilterCallback *ownerfilter; +} bulletcontext_t; + +class QCFilterCallback : public btOverlapFilterCallback +{ + // return true when pairs need collision + virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const + { + //dimensions don't collide + bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; + collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); + + //owners don't collide (unless one is world, obviouslyish) + if (collides) + { + btRigidBody *b1 = (btRigidBody*)proxy0->m_clientObject; + btRigidBody *b2 = (btRigidBody*)proxy1->m_clientObject; + //don't let two qc-controlled entities collide in Bullet, that's the job of quake. + if (b1->isStaticOrKinematicObject() && b2->isStaticOrKinematicObject()) + return false; + wedict_t *e1 = (wedict_t*)b1->getUserPointer(); + wedict_t *e2 = (wedict_t*)b2->getUserPointer(); + if ((e1->v->solid == SOLID_TRIGGER && e2->v->solid != SOLID_BSP) || + (e2->v->solid == SOLID_TRIGGER && e1->v->solid != SOLID_BSP)) + return false; //triggers only collide with bsp objects. + if (e1->entnum && e2->entnum) + collides = e1->v->owner != e2->entnum && e2->v->owner != e1->entnum; + } + + return collides; + } +}; + +static void QDECL World_Bullet_End(world_t *world) +{ + struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe; + world->rbe = NULL; + delete ctx->dworld; + delete ctx->solver; + delete ctx->collisionconfig; + delete ctx->collisiondispatcher; + delete ctx->broadphase; + delete ctx->ownerfilter; + Z_Free(ctx); +} + +static void QDECL World_Bullet_RemoveJointFromEntity(world_t *world, wedict_t *ed) +{ + ed->ode.ode_joint_type = 0; +// if(ed->ode.ode_joint) +// dJointDestroy((dJointID)ed->ode.ode_joint); + ed->ode.ode_joint = NULL; +} + +static void QDECL World_Bullet_RemoveFromEntity(world_t *world, wedict_t *ed) +{ + struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe; + btRigidBody *body; + btCollisionShape *geom; + if (!ed->ode.ode_physics) + return; + + // entity is not physics controlled, free any physics data + ed->ode.ode_physics = qfalse; + + body = (btRigidBody*)ed->ode.ode_body; + ed->ode.ode_body = NULL; + if (body) + ctx->dworld->removeRigidBody (body); + + geom = (btCollisionShape*)ed->ode.ode_geom; + ed->ode.ode_geom = NULL; + if (ed->ode.ode_geom) + delete geom; + + //FIXME: joints + modfuncs->ReleaseCollisionMesh(ed); + if(ed->ode.ode_massbuf) + BZ_Free(ed->ode.ode_massbuf); + ed->ode.ode_massbuf = NULL; +} + +static void World_Bullet_Frame_BodyToEntity(world_t *world, wedict_t *ed) +{ + return; + +#if 0 + model_t *model; + const float *avel; + const float *o; + const float *r; // for some reason dBodyGetRotation returns a [3][4] matrix + const float *vel; + btRigidBody *body = (btRigidBody*)ed->ode.ode_body; + int movetype; + float bodymatrix[16]; + float entitymatrix[16]; + vec3_t angles; + vec3_t avelocity; + vec3_t forward, left, up; + vec3_t origin; + vec3_t spinvelocity; + vec3_t velocity; + if (!body) + return; + + movetype = (int)ed->v->movetype; + if (movetype != MOVETYPE_PHYSICS) + { + switch((int)ed->xv->jointtype) + { + // TODO feed back data from physics + case JOINTTYPE_POINT: + break; + case JOINTTYPE_HINGE: + break; + case JOINTTYPE_SLIDER: + break; + case JOINTTYPE_UNIVERSAL: + break; + case JOINTTYPE_HINGE2: + break; + case JOINTTYPE_FIXED: + break; + } + return; + } + // store the physics engine data into the entity + + btTransform trans; + body->getMotionState()->getWorldTransform(trans); +// o = dBodyGetPosition(body); +// r = dBodyGetRotation(body); +// vel = dBodyGetLinearVel(body); +// avel = dBodyGetAngularVel(body); +// VectorCopy(o, origin); +// forward[0] = r[0]; +// forward[1] = r[4]; +// forward[2] = r[8]; +// left[0] = r[1]; +// left[1] = r[5]; +// left[2] = r[9]; +// up[0] = r[2]; +// up[1] = r[6]; +// up[2] = r[10]; + vel = body->getLinearVelocity(); + avel = body->getAngularVelocity(); + VectorCopy(vel, velocity); + VectorCopy(avel, spinvelocity); + trans.getBasis().getOpenGLSubMatrix(bodymatrix); + foo Matrix4x4_RM_FromVectors(bodymatrix, forward, left, up, origin); + foo Matrix4_Multiply(ed->ode.ode_offsetimatrix, bodymatrix, entitymatrix); + foo Matrix3x4_RM_ToVectors(entitymatrix, forward, left, up, origin); + + VectorAngles(forward, up, angles); + angles[0]*=-1; + + avelocity[PITCH] = RAD2DEG(spinvelocity[PITCH]); + avelocity[YAW] = RAD2DEG(spinvelocity[ROLL]); + avelocity[ROLL] = RAD2DEG(spinvelocity[YAW]); + + if (ed->v->modelindex) + { + model = world->Get_CModel(world, ed->v->modelindex); + if (!model || model->type == mod_alias) + { + angles[PITCH] *= -1; + avelocity[PITCH] *= -1; + } + } + + VectorCopy(origin, ed->v->origin); + VectorCopy(velocity, ed->v->velocity); + //VectorCopy(forward, ed->xv->axis_forward); + //VectorCopy(left, ed->xv->axis_left); + //VectorCopy(up, ed->xv->axis_up); + //VectorCopy(spinvelocity, ed->xv->spinvelocity); + VectorCopy(angles, ed->v->angles); + VectorCopy(avelocity, ed->v->avelocity); + + // values for BodyFromEntity to check if the qc modified anything later + VectorCopy(origin, ed->ode.ode_origin); + VectorCopy(velocity, ed->ode.ode_velocity); + VectorCopy(angles, ed->ode.ode_angles); + VectorCopy(avelocity, ed->ode.ode_avelocity); +// ed->ode.ode_gravity = (qboolean)dBodyGetGravityMode(body); + + World_LinkEdict(world, ed, true); +#endif +} + +static void World_Bullet_Frame_JointFromEntity(world_t *world, wedict_t *ed) +{ +#if 0 + dJointID j = 0; + dBodyID b1 = 0; + dBodyID b2 = 0; + int movetype = 0; + int jointtype = 0; + int enemy = 0, aiment = 0; + wedict_t *o; + vec3_t origin, velocity, angles, forward, left, up, movedir; + vec_t CFM, ERP, FMax, Stop, Vel; + VectorClear(origin); + VectorClear(velocity); + VectorClear(angles); + VectorClear(movedir); + movetype = (int)ed->v->movetype; + jointtype = (int)ed->xv->jointtype; + enemy = ed->v->enemy; + aiment = ed->v->aiment; + VectorCopy(ed->v->origin, origin); + VectorCopy(ed->v->velocity, velocity); + VectorCopy(ed->v->angles, angles); + VectorCopy(ed->v->movedir, movedir); + if(movetype == MOVETYPE_PHYSICS) + jointtype = 0; // can't have both + + o = (wedict_t*)PROG_TO_EDICT(world->progs, enemy); + if(o->isfree || o->ode.ode_body == 0) + enemy = 0; + o = (wedict_t*)PROG_TO_EDICT(world->progs, aiment); + if(o->isfree || o->ode.ode_body == 0) + aiment = 0; + // see http://www.ode.org/old_list_archives/2006-January/017614.html + // we want to set ERP? make it fps independent and work like a spring constant + // note: if movedir[2] is 0, it becomes ERP = 1, CFM = 1.0 / (H * K) + if(movedir[0] > 0 && movedir[1] > 0) + { + float K = movedir[0]; + float D = movedir[1]; + float R = 2.0 * D * sqrt(K); // we assume D is premultiplied by sqrt(sprungMass) + CFM = 1.0 / (world->ode.ode_step * K + R); // always > 0 + ERP = world->ode.ode_step * K * CFM; + Vel = 0; + FMax = 0; + Stop = movedir[2]; + } + else if(movedir[1] < 0) + { + CFM = 0; + ERP = 0; + Vel = movedir[0]; + FMax = -movedir[1]; // TODO do we need to multiply with world.physics.ode_step? + Stop = movedir[2] > 0 ? movedir[2] : dInfinity; + } + else // movedir[0] > 0, movedir[1] == 0 or movedir[0] < 0, movedir[1] >= 0 + { + CFM = 0; + ERP = 0; + Vel = 0; + FMax = 0; + Stop = dInfinity; + } + if(jointtype == ed->ode.ode_joint_type && VectorCompare(origin, ed->ode.ode_joint_origin) && VectorCompare(velocity, ed->ode.ode_joint_velocity) && VectorCompare(angles, ed->ode.ode_joint_angles) && enemy == ed->ode.ode_joint_enemy && aiment == ed->ode.ode_joint_aiment && VectorCompare(movedir, ed->ode.ode_joint_movedir)) + return; // nothing to do + AngleVectorsFLU(angles, forward, left, up); + switch(jointtype) + { + case JOINTTYPE_POINT: + j = dJointCreateBall(world->ode.ode_world, 0); + break; + case JOINTTYPE_HINGE: + j = dJointCreateHinge(world->ode.ode_world, 0); + break; + case JOINTTYPE_SLIDER: + j = dJointCreateSlider(world->ode.ode_world, 0); + break; + case JOINTTYPE_UNIVERSAL: + j = dJointCreateUniversal(world->ode.ode_world, 0); + break; + case JOINTTYPE_HINGE2: + j = dJointCreateHinge2(world->ode.ode_world, 0); + break; + case JOINTTYPE_FIXED: + j = dJointCreateFixed(world->ode.ode_world, 0); + break; + case 0: + default: + // no joint + j = 0; + break; + } + if(ed->ode.ode_joint) + { + //Con_Printf("deleted old joint %i\n", (int) (ed - prog->edicts)); + dJointAttach(ed->ode.ode_joint, 0, 0); + dJointDestroy(ed->ode.ode_joint); + } + ed->ode.ode_joint = (void *) j; + ed->ode.ode_joint_type = jointtype; + ed->ode.ode_joint_enemy = enemy; + ed->ode.ode_joint_aiment = aiment; + VectorCopy(origin, ed->ode.ode_joint_origin); + VectorCopy(velocity, ed->ode.ode_joint_velocity); + VectorCopy(angles, ed->ode.ode_joint_angles); + VectorCopy(movedir, ed->ode.ode_joint_movedir); + if(j) + { + //Con_Printf("made new joint %i\n", (int) (ed - prog->edicts)); + dJointSetData(j, (void *) ed); + if(enemy) + b1 = (dBodyID)((WEDICT_NUM(world->progs, enemy))->ode.ode_body); + if(aiment) + b2 = (dBodyID)((WEDICT_NUM(world->progs, aiment))->ode.ode_body); + dJointAttach(j, b1, b2); + + switch(jointtype) + { + case JOINTTYPE_POINT: + dJointSetBallAnchor(j, origin[0], origin[1], origin[2]); + break; + case JOINTTYPE_HINGE: + dJointSetHingeAnchor(j, origin[0], origin[1], origin[2]); + dJointSetHingeAxis(j, forward[0], forward[1], forward[2]); + dJointSetHingeParam(j, dParamFMax, FMax); + dJointSetHingeParam(j, dParamHiStop, Stop); + dJointSetHingeParam(j, dParamLoStop, -Stop); + dJointSetHingeParam(j, dParamStopCFM, CFM); + dJointSetHingeParam(j, dParamStopERP, ERP); + dJointSetHingeParam(j, dParamVel, Vel); + break; + case JOINTTYPE_SLIDER: + dJointSetSliderAxis(j, forward[0], forward[1], forward[2]); + dJointSetSliderParam(j, dParamFMax, FMax); + dJointSetSliderParam(j, dParamHiStop, Stop); + dJointSetSliderParam(j, dParamLoStop, -Stop); + dJointSetSliderParam(j, dParamStopCFM, CFM); + dJointSetSliderParam(j, dParamStopERP, ERP); + dJointSetSliderParam(j, dParamVel, Vel); + break; + case JOINTTYPE_UNIVERSAL: + dJointSetUniversalAnchor(j, origin[0], origin[1], origin[2]); + dJointSetUniversalAxis1(j, forward[0], forward[1], forward[2]); + dJointSetUniversalAxis2(j, up[0], up[1], up[2]); + dJointSetUniversalParam(j, dParamFMax, FMax); + dJointSetUniversalParam(j, dParamHiStop, Stop); + dJointSetUniversalParam(j, dParamLoStop, -Stop); + dJointSetUniversalParam(j, dParamStopCFM, CFM); + dJointSetUniversalParam(j, dParamStopERP, ERP); + dJointSetUniversalParam(j, dParamVel, Vel); + dJointSetUniversalParam(j, dParamFMax2, FMax); + dJointSetUniversalParam(j, dParamHiStop2, Stop); + dJointSetUniversalParam(j, dParamLoStop2, -Stop); + dJointSetUniversalParam(j, dParamStopCFM2, CFM); + dJointSetUniversalParam(j, dParamStopERP2, ERP); + dJointSetUniversalParam(j, dParamVel2, Vel); + break; + case JOINTTYPE_HINGE2: + dJointSetHinge2Anchor(j, origin[0], origin[1], origin[2]); + dJointSetHinge2Axis1(j, forward[0], forward[1], forward[2]); + dJointSetHinge2Axis2(j, velocity[0], velocity[1], velocity[2]); + dJointSetHinge2Param(j, dParamFMax, FMax); + dJointSetHinge2Param(j, dParamHiStop, Stop); + dJointSetHinge2Param(j, dParamLoStop, -Stop); + dJointSetHinge2Param(j, dParamStopCFM, CFM); + dJointSetHinge2Param(j, dParamStopERP, ERP); + dJointSetHinge2Param(j, dParamVel, Vel); + dJointSetHinge2Param(j, dParamFMax2, FMax); + dJointSetHinge2Param(j, dParamHiStop2, Stop); + dJointSetHinge2Param(j, dParamLoStop2, -Stop); + dJointSetHinge2Param(j, dParamStopCFM2, CFM); + dJointSetHinge2Param(j, dParamStopERP2, ERP); + dJointSetHinge2Param(j, dParamVel2, Vel); + break; + case JOINTTYPE_FIXED: + break; + case 0: + default: + break; + } +#undef SETPARAMS + + } +#endif +} + +static qboolean QDECL World_Bullet_RagMatrixToBody(rbebody_t *bodyptr, float *mat) +{ + btRigidBody *body; + +/* + dVector3 r[3]; + + r[0][0] = mat[0]; + r[0][1] = mat[1]; + r[0][2] = mat[2]; + r[1][0] = mat[4]; + r[1][1] = mat[5]; + r[1][2] = mat[6]; + r[2][0] = mat[8]; + r[2][1] = mat[9]; + r[2][2] = mat[10]; + + dBodySetPosition(bodyptr->ode_body, mat[3], mat[7], mat[11]); + dBodySetRotation(bodyptr->ode_body, r[0]); + dBodySetLinearVel(bodyptr->ode_body, 0, 0, 0); + dBodySetAngularVel(bodyptr->ode_body, 0, 0, 0); +*/ + return qtrue; +} +static qboolean QDECL World_Bullet_RagCreateBody(world_t *world, rbebody_t *bodyptr, rbebodyinfo_t *bodyinfo, float *mat, wedict_t *ent) +{ +/* + dMass mass; + float radius; + if (!world->ode.ode_space) + return false; + world->ode.hasodeents = true; //I don't like this, but we need the world etc to be solid. + world->ode.hasextraobjs = true; + + switch(bodyinfo->geomshape) + { + case GEOMTYPE_CAPSULE: + radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1]) * 0.5; + bodyptr->ode_geom = (void *)dCreateCapsule(world->ode.ode_space, radius, bodyinfo->dimensions[2]); + dMassSetCapsuleTotal(&mass, bodyinfo->mass, 3, radius, bodyinfo->dimensions[2]); + //aligned along the geom's local z axis + break; + case GEOMTYPE_SPHERE: + //radius + radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1] + bodyinfo->dimensions[2]) / 3; + bodyptr->ode_geom = dCreateSphere(world->ode.ode_space, radius); + dMassSetSphereTotal(&mass, bodyinfo->mass, radius); + //aligned along the geom's local z axis + break; + case GEOMTYPE_CYLINDER: + //radius, length + radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1]) * 0.5; + bodyptr->ode_geom = dCreateCylinder(world->ode.ode_space, radius, bodyinfo->dimensions[2]); + dMassSetCylinderTotal(&mass, bodyinfo->mass, 3, radius, bodyinfo->dimensions[2]); + //alignment is irreleevnt, thouse I suppose it might be scaled wierdly. + break; + default: + case GEOMTYPE_BOX: + //diameter + bodyptr->ode_geom = dCreateBox(world->ode.ode_space, bodyinfo->dimensions[0], bodyinfo->dimensions[1], bodyinfo->dimensions[2]); + dMassSetBoxTotal(&mass, bodyinfo->mass, bodyinfo->dimensions[0], bodyinfo->dimensions[1], bodyinfo->dimensions[2]); + //monkey + break; + } + bodyptr->ode_body = dBodyCreate(world->ode.ode_world); + dBodySetMass(bodyptr->ode_body, &mass); + dGeomSetBody(bodyptr->ode_geom, bodyptr->ode_body); + dGeomSetData(bodyptr->ode_geom, (void*)ent); +*/ + return World_Bullet_RagMatrixToBody(bodyptr, mat); +} + +static void QDECL World_Bullet_RagMatrixFromJoint(rbejoint_t *joint, rbejointinfo_t *info, float *mat) +{ +/* + dVector3 dr3; + switch(info->type) + { + case JOINTTYPE_POINT: + dJointGetBallAnchor(joint->ode_joint, dr3); + mat[3] = dr3[0]; + mat[7] = dr3[1]; + mat[11] = dr3[2]; + VectorClear(mat+4); + VectorClear(mat+8); + break; + + case JOINTTYPE_HINGE: + dJointGetHingeAnchor(joint->ode_joint, dr3); + mat[3] = dr3[0]; + mat[7] = dr3[1]; + mat[11] = dr3[2]; + + dJointGetHingeAxis(joint->ode_joint, dr3); + VectorCopy(dr3, mat+4); + VectorClear(mat+8); + + CrossProduct(mat+4, mat+8, mat+0); + return; + break; + case JOINTTYPE_HINGE2: + dJointGetHinge2Anchor(joint->ode_joint, dr3); + mat[3] = dr3[0]; + mat[7] = dr3[1]; + mat[11] = dr3[2]; + + dJointGetHinge2Axis1(joint->ode_joint, dr3); + VectorCopy(dr3, mat+4); + dJointGetHinge2Axis2(joint->ode_joint, dr3); + VectorCopy(dr3, mat+8); + break; + + case JOINTTYPE_SLIDER: + //no anchor point... + //get the two bodies and average their origin for a somewhat usable representation of an anchor. + { + const dReal *p1, *p2; + dReal n[3]; + dBodyID b1 = dJointGetBody(joint->ode_joint, 0), b2 = dJointGetBody(joint->ode_joint, 1); + if (b1) + p1 = dBodyGetPosition(b1); + else + { + p1 = n; + VectorClear(n); + } + if (b2) + p2 = dBodyGetPosition(b2); + else + p2 = p1; + dJointGetSliderAxis(joint->ode_joint, dr3 + 0); + VectorInterpolate(p1, 0.5, p2, dr3); + mat[3] = dr3[0]; + mat[7] = dr3[1]; + mat[11] = dr3[2]; + + VectorClear(mat+4); + VectorClear(mat+8); + } + break; + + case JOINTTYPE_UNIVERSAL: + dJointGetUniversalAnchor(joint->ode_joint, dr3); + mat[3] = dr3[0]; + mat[7] = dr3[1]; + mat[11] = dr3[2]; + + dJointGetUniversalAxis1(joint->ode_joint, dr3); + VectorCopy(dr3, mat+4); + dJointGetUniversalAxis2(joint->ode_joint, dr3); + VectorCopy(dr3, mat+8); + + CrossProduct(mat+4, mat+8, mat+0); + return; + break; + } + AngleVectorsFLU(vec3_origin, mat+0, mat+4, mat+8); +*/ +} + +static void QDECL World_Bullet_RagMatrixFromBody(world_t *world, rbebody_t *bodyptr, float *mat) +{ +/* + const dReal *o = dBodyGetPosition(bodyptr->ode_body); + const dReal *r = dBodyGetRotation(bodyptr->ode_body); + mat[0] = r[0]; + mat[1] = r[1]; + mat[2] = r[2]; + mat[3] = o[0]; + + mat[4] = r[4]; + mat[5] = r[5]; + mat[6] = r[6]; + mat[7] = o[1]; + + mat[8] = r[8]; + mat[9] = r[9]; + mat[10] = r[10]; + mat[11] = o[2]; +*/ +} +static void QDECL World_Bullet_RagEnableJoint(rbejoint_t *joint, qboolean enabled) +{ +/* + if (enabled) + dJointEnable(joint->ode_joint); + else + dJointDisable(joint->ode_joint); +*/ +} +static void QDECL World_Bullet_RagCreateJoint(world_t *world, rbejoint_t *joint, rbejointinfo_t *info, rbebody_t *body1, rbebody_t *body2, vec3_t aaa2[3]) +{ +/* + switch(info->type) + { + case JOINTTYPE_POINT: + joint->ode_joint = dJointCreateBall(world->ode.ode_world, 0); + break; + case JOINTTYPE_HINGE: + joint->ode_joint = dJointCreateHinge(world->ode.ode_world, 0); + break; + case JOINTTYPE_SLIDER: + joint->ode_joint = dJointCreateSlider(world->ode.ode_world, 0); + break; + case JOINTTYPE_UNIVERSAL: + joint->ode_joint = dJointCreateUniversal(world->ode.ode_world, 0); + break; + case JOINTTYPE_HINGE2: + joint->ode_joint = dJointCreateHinge2(world->ode.ode_world, 0); + break; + case JOINTTYPE_FIXED: + joint->ode_joint = dJointCreateFixed(world->ode.ode_world, 0); + break; + default: + joint->ode_joint = NULL; + break; + } + if (joint->ode_joint) + { + //Con_Printf("made new joint %i\n", (int) (ed - prog->edicts)); +// dJointSetData(joint->ode_joint, NULL); + dJointAttach(joint->ode_joint, body1?body1->ode_body:NULL, body2?body2->ode_body:NULL); + + switch(info->type) + { + case JOINTTYPE_POINT: + dJointSetBallAnchor(joint->ode_joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]); + break; + case JOINTTYPE_HINGE: + dJointSetHingeAnchor(joint->ode_joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]); + dJointSetHingeAxis(joint->ode_joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]); + dJointSetHingeParam(joint->ode_joint, dParamFMax, info->FMax); + dJointSetHingeParam(joint->ode_joint, dParamHiStop, info->HiStop); + dJointSetHingeParam(joint->ode_joint, dParamLoStop, info->LoStop); + dJointSetHingeParam(joint->ode_joint, dParamStopCFM, info->CFM); + dJointSetHingeParam(joint->ode_joint, dParamStopERP, info->ERP); + dJointSetHingeParam(joint->ode_joint, dParamVel, info->Vel); + break; + case JOINTTYPE_SLIDER: + dJointSetSliderAxis(joint->ode_joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]); + dJointSetSliderParam(joint->ode_joint, dParamFMax, info->FMax); + dJointSetSliderParam(joint->ode_joint, dParamHiStop, info->HiStop); + dJointSetSliderParam(joint->ode_joint, dParamLoStop, info->LoStop); + dJointSetSliderParam(joint->ode_joint, dParamStopCFM, info->CFM); + dJointSetSliderParam(joint->ode_joint, dParamStopERP, info->ERP); + dJointSetSliderParam(joint->ode_joint, dParamVel, info->Vel); + break; + case JOINTTYPE_UNIVERSAL: + dJointSetUniversalAnchor(joint->ode_joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]); + dJointSetUniversalAxis1(joint->ode_joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]); + dJointSetUniversalAxis2(joint->ode_joint, aaa2[2][0], aaa2[2][1], aaa2[2][2]); + dJointSetUniversalParam(joint->ode_joint, dParamFMax, info->FMax); + dJointSetUniversalParam(joint->ode_joint, dParamHiStop, info->HiStop); + dJointSetUniversalParam(joint->ode_joint, dParamLoStop, info->LoStop); + dJointSetUniversalParam(joint->ode_joint, dParamStopCFM, info->CFM); + dJointSetUniversalParam(joint->ode_joint, dParamStopERP, info->ERP); + dJointSetUniversalParam(joint->ode_joint, dParamVel, info->Vel); + dJointSetUniversalParam(joint->ode_joint, dParamFMax2, info->FMax2); + dJointSetUniversalParam(joint->ode_joint, dParamHiStop2, info->HiStop2); + dJointSetUniversalParam(joint->ode_joint, dParamLoStop2, info->LoStop2); + dJointSetUniversalParam(joint->ode_joint, dParamStopCFM2, info->CFM2); + dJointSetUniversalParam(joint->ode_joint, dParamStopERP2, info->ERP2); + dJointSetUniversalParam(joint->ode_joint, dParamVel2, info->Vel2); + break; + case JOINTTYPE_HINGE2: + dJointSetHinge2Anchor(joint->ode_joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]); + dJointSetHinge2Axis1(joint->ode_joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]); + dJointSetHinge2Axis2(joint->ode_joint, aaa2[2][0], aaa2[2][1], aaa2[2][2]); + dJointSetHinge2Param(joint->ode_joint, dParamFMax, info->FMax); + dJointSetHinge2Param(joint->ode_joint, dParamHiStop, info->HiStop); + dJointSetHinge2Param(joint->ode_joint, dParamLoStop, info->LoStop); + dJointSetHinge2Param(joint->ode_joint, dParamStopCFM, info->CFM); + dJointSetHinge2Param(joint->ode_joint, dParamStopERP, info->ERP); + dJointSetHinge2Param(joint->ode_joint, dParamVel, info->Vel); + dJointSetHinge2Param(joint->ode_joint, dParamFMax2, info->FMax2); + dJointSetHinge2Param(joint->ode_joint, dParamHiStop2, info->HiStop2); + dJointSetHinge2Param(joint->ode_joint, dParamLoStop2, info->LoStop2); + dJointSetHinge2Param(joint->ode_joint, dParamStopCFM2, info->CFM2); + dJointSetHinge2Param(joint->ode_joint, dParamStopERP2, info->ERP2); + dJointSetHinge2Param(joint->ode_joint, dParamVel2, info->Vel2); + break; + case JOINTTYPE_FIXED: + dJointSetFixed(joint->ode_joint); + break; + } + } +*/ +} + +static void QDECL World_Bullet_RagDestroyBody(world_t *world, rbebody_t *bodyptr) +{ +/* + if (bodyptr->ode_geom) + dGeomDestroy(bodyptr->ode_geom); + bodyptr->ode_geom = NULL; + if (bodyptr->ode_body) + dBodyDestroy(bodyptr->ode_body); + bodyptr->ode_body = NULL; +*/ +} + +static void QDECL World_Bullet_RagDestroyJoint(world_t *world, rbejoint_t *joint) +{ +/* + if (joint->ode_joint) + dJointDestroy(joint->ode_joint); + joint->ode_joint = NULL; +*/ +} + +//bullet gives us a handy way to get/set motion states. we can cheesily update entity fields this way. +class QCMotionState : public btMotionState +{ + wedict_t *edict; + qboolean dirty; + btTransform trans; + world_t *world; + + +public: + void ReloadMotionState(void) + { + vec3_t offset; + vec3_t axis[3]; + btVector3 org; + modfuncs->AngleVectors(edict->v->angles, axis[0], axis[1], axis[2]); + VectorNegate(axis[1], axis[1]); + VectorAvg(edict->ode.ode_mins, edict->ode.ode_maxs, offset); + VectorMA(edict->v->origin, offset[0]*1, axis[0], org); + VectorMA(org, offset[1]*1, axis[1], org); + VectorMA(org, offset[2]*1, axis[2], org); + + trans.setBasis(btMatrix3x3(axis[0][0], axis[1][0], axis[2][0], + axis[0][1], axis[1][1], axis[2][1], + axis[0][2], axis[1][2], axis[2][2])); + trans.setOrigin(org); + } + QCMotionState(wedict_t *ed, world_t *w) + { + dirty = qtrue; + edict = ed; + world = w; + + ReloadMotionState(); + } + virtual ~QCMotionState() + { + } + + virtual void getWorldTransform(btTransform &worldTrans) const + { + worldTrans = trans; + } + + virtual void setWorldTransform(const btTransform &worldTrans) + { + vec3_t fwd, left, up, offset; + trans = worldTrans; + + btVector3 pos = worldTrans.getOrigin(); + VectorCopy(worldTrans.getBasis().getColumn(0), fwd); + VectorCopy(worldTrans.getBasis().getColumn(1), left); + VectorCopy(worldTrans.getBasis().getColumn(2), up); + VectorAvg(edict->ode.ode_mins, edict->ode.ode_maxs, offset); + VectorMA(pos, offset[0]*-1, fwd, pos); + VectorMA(pos, offset[1]*-1, left, pos); + VectorMA(pos, offset[2]*-1, up, edict->v->origin); + + modfuncs->VectorAngles(fwd, up, edict->v->angles); + if (edict->v->modelindex) + { + model_t *model = world->Get_CModel(world, edict->v->modelindex); + if (!model || model->type == mod_alias) + ; + else + edict->v->angles[PITCH] *= -1; + } + + //so it doesn't get rebuilt + VectorCopy(edict->v->origin, edict->ode.ode_origin); + VectorCopy(edict->v->angles, edict->ode.ode_angles); + +// World_LinkEdict(world, edict, false); + +// if(mSceneNode == nullptr) +// return; // silently return before we set a node + +// btQuaternion rot = worldTrans.getRotation(); +// mSceneNode ->setOrientation(rot.w(), rot.x(), rot.y(), rot.z()); +// btVector3 pos = worldTrans.getOrigin(); +// mSceneNode ->setPosition(pos.x(), pos.y(), pos.z()); + } +}; + +static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed) +{ + bulletcontext_t *ctx = (bulletcontext_t*)world->rbe; + btRigidBody *body = NULL; + btScalar mass; + float test; + void *dataID; + model_t *model; + int axisindex; + int modelindex = 0; + int movetype = MOVETYPE_NONE; + int solid = SOLID_NOT; + int geomtype = GEOMTYPE_SOLID; + qboolean modified = qfalse; + vec3_t angles; + vec3_t avelocity; + vec3_t entmaxs; + vec3_t entmins; + vec3_t forward; + vec3_t geomcenter; + vec3_t geomsize; + vec3_t left; + vec3_t origin; + vec3_t spinvelocity; + vec3_t up; + vec3_t velocity; + vec_t f; + vec_t length; + vec_t massval = 1.0f; +// vec_t movelimit; + vec_t radius; + vec_t scale; + vec_t spinlimit; + qboolean gravity; + + geomtype = (int)ed->xv->geomtype; + solid = (int)ed->v->solid; + movetype = (int)ed->v->movetype; + scale = ed->xv->scale?ed->xv->scale:1; + modelindex = 0; + model = NULL; + + if (!geomtype) + { + switch((int)ed->v->solid) + { + case SOLID_NOT: geomtype = GEOMTYPE_NONE; break; + case SOLID_TRIGGER: geomtype = GEOMTYPE_NONE; break; + case SOLID_BSP: geomtype = GEOMTYPE_TRIMESH; break; + case SOLID_PHYSICS_TRIMESH: geomtype = GEOMTYPE_TRIMESH; break; + case SOLID_PHYSICS_BOX: geomtype = GEOMTYPE_BOX; break; + case SOLID_PHYSICS_SPHERE: geomtype = GEOMTYPE_SPHERE; break; + case SOLID_PHYSICS_CAPSULE: geomtype = GEOMTYPE_CAPSULE; break; + case SOLID_PHYSICS_CYLINDER:geomtype = GEOMTYPE_CYLINDER; break; + default: geomtype = GEOMTYPE_BOX; break; + } + } + + switch(geomtype) + { + case GEOMTYPE_TRIMESH: + modelindex = (int)ed->v->modelindex; + model = world->Get_CModel(world, modelindex); + if (!model || model->loadstate != MLS_LOADED) + { + model = NULL; + modelindex = 0; + } + if (model) + { + VectorScale(model->mins, scale, entmins); + VectorScale(model->maxs, scale, entmaxs); + if (ed->xv->mass) + massval = ed->xv->mass; + } + else + { + modelindex = 0; + massval = 1.0f; + } + massval = 0; //bullet does not support trisoup moving through the world. + break; + case GEOMTYPE_BOX: + case GEOMTYPE_SPHERE: + case GEOMTYPE_CAPSULE: + case GEOMTYPE_CAPSULE_X: + case GEOMTYPE_CAPSULE_Y: + case GEOMTYPE_CAPSULE_Z: + case GEOMTYPE_CYLINDER: + case GEOMTYPE_CYLINDER_X: + case GEOMTYPE_CYLINDER_Y: + case GEOMTYPE_CYLINDER_Z: + VectorCopy(ed->v->mins, entmins); + VectorCopy(ed->v->maxs, entmaxs); + if (ed->xv->mass) + massval = ed->xv->mass; + break; + default: +// case GEOMTYPE_NONE: + if (ed->ode.ode_physics) + World_Bullet_RemoveFromEntity(world, ed); + return; + } + + VectorSubtract(entmaxs, entmins, geomsize); + if (DotProduct(geomsize,geomsize) == 0) + { + // we don't allow point-size physics objects... + if (ed->ode.ode_physics) + World_Bullet_RemoveFromEntity(world, ed); + return; + } + + // check if we need to create or replace the geom + if (!ed->ode.ode_physics + || !VectorCompare(ed->ode.ode_mins, entmins) + || !VectorCompare(ed->ode.ode_maxs, entmaxs) + || ed->ode.ode_modelindex != modelindex) + { + btCollisionShape *geom; + + modified = qtrue; + World_Bullet_RemoveFromEntity(world, ed); + ed->ode.ode_physics = qtrue; + VectorCopy(entmins, ed->ode.ode_mins); + VectorCopy(entmaxs, ed->ode.ode_maxs); + ed->ode.ode_modelindex = modelindex; + VectorAvg(entmins, entmaxs, geomcenter); + ed->ode.ode_movelimit = min(geomsize[0], min(geomsize[1], geomsize[2])); + +/* memset(ed->ode.ode_offsetmatrix, 0, sizeof(ed->ode.ode_offsetmatrix)); + ed->ode.ode_offsetmatrix[0] = 1; + ed->ode.ode_offsetmatrix[5] = 1; + ed->ode.ode_offsetmatrix[10] = 1; + ed->ode.ode_offsetmatrix[3] = -geomcenter[0]; + ed->ode.ode_offsetmatrix[7] = -geomcenter[1]; + ed->ode.ode_offsetmatrix[11] = -geomcenter[2]; +*/ + ed->ode.ode_mass = massval; + + switch(geomtype) + { + case GEOMTYPE_TRIMESH: +// foo Matrix4x4_Identity(ed->ode.ode_offsetmatrix); + geom = NULL; + if (!model) + { + Con_Printf("entity %i (classname %s) has no model\n", NUM_FOR_EDICT(world->progs, (edict_t*)ed), PR_GetString(world->progs, ed->v->classname)); + if (ed->ode.ode_physics) + World_Bullet_RemoveFromEntity(world, ed); + return; + } + if (!modfuncs->GenerateCollisionMesh(world, model, ed, geomcenter)) + { + if (ed->ode.ode_physics) + World_Bullet_RemoveFromEntity(world, ed); + return; + } + +// foo Matrix4x4_RM_CreateTranslate(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]); + + { + btTriangleIndexVertexArray *tiva = new btTriangleIndexVertexArray(); + btIndexedMesh mesh; + mesh.m_vertexType = PHY_FLOAT; + mesh.m_indexType = PHY_INTEGER; + mesh.m_numTriangles = ed->ode.ode_numtriangles; + mesh.m_numVertices = ed->ode.ode_numvertices; + mesh.m_triangleIndexBase = (const unsigned char*)ed->ode.ode_element3i; + mesh.m_triangleIndexStride = sizeof(*ed->ode.ode_element3i)*3; + mesh.m_vertexBase = (const unsigned char*)ed->ode.ode_vertex3f; + mesh.m_vertexStride = sizeof(*ed->ode.ode_vertex3f)*3; + tiva->addIndexedMesh(mesh); + geom = new btBvhTriangleMeshShape(tiva, true); + } + break; + + case GEOMTYPE_BOX: + geom = new btBoxShape(btVector3(geomsize[0], geomsize[1], geomsize[2]) * 0.5); + break; + + case GEOMTYPE_SPHERE: + geom = new btSphereShape(geomsize[0] * 0.5f); + break; + + case GEOMTYPE_CAPSULE: + case GEOMTYPE_CAPSULE_X: + case GEOMTYPE_CAPSULE_Y: + case GEOMTYPE_CAPSULE_Z: + if (geomtype == GEOMTYPE_CAPSULE) + { + // the qc gives us 3 axis radius, the longest axis is the capsule axis + axisindex = 0; + if (geomsize[axisindex] < geomsize[1]) + axisindex = 1; + if (geomsize[axisindex] < geomsize[2]) + axisindex = 2; + } + else + axisindex = geomtype-GEOMTYPE_CAPSULE_X; + if (axisindex == 0) + radius = min(geomsize[1], geomsize[2]) * 0.5f; + else if (axisindex == 1) + radius = min(geomsize[0], geomsize[2]) * 0.5f; + else + radius = min(geomsize[0], geomsize[1]) * 0.5f; + length = geomsize[axisindex] - radius*2; + if (length <= 0) + { + radius -= (1 - length)*0.5; + length = 1; + } + if (axisindex == 0) + geom = new btCapsuleShapeX(radius, length); + else if (axisindex == 1) + geom = new btCapsuleShape(radius, length); + else + geom = new btCapsuleShapeZ(radius, length); + break; + + case GEOMTYPE_CYLINDER: + case GEOMTYPE_CYLINDER_X: + case GEOMTYPE_CYLINDER_Y: + case GEOMTYPE_CYLINDER_Z: + if (geomtype == GEOMTYPE_CYLINDER) + { + // the qc gives us 3 axis radius, the longest axis is the capsule axis + axisindex = 0; + if (geomsize[axisindex] < geomsize[1]) + axisindex = 1; + if (geomsize[axisindex] < geomsize[2]) + axisindex = 2; + } + else + axisindex = geomtype-GEOMTYPE_CYLINDER_X; + if (axisindex == 0) + geom = new btCylinderShapeX(btVector3(geomsize[0], geomsize[1], geomsize[2])*0.5); + else if (axisindex == 1) + geom = new btCylinderShape(btVector3(geomsize[0], geomsize[1], geomsize[2])*0.5); + else + geom = new btCylinderShapeZ(btVector3(geomsize[0], geomsize[1], geomsize[2])*0.5); + break; + + default: +// Con_Printf("World_Bullet_BodyFromEntity: unrecognized solid value %i was accepted by filter\n", solid); + if (ed->ode.ode_physics) + World_Bullet_RemoveFromEntity(world, ed); + return; + } +// Matrix3x4_InvertTo4x4_Simple(ed->ode.ode_offsetmatrix, ed->ode.ode_offsetimatrix); +// ed->ode.ode_massbuf = BZ_Malloc(sizeof(dMass)); +// memcpy(ed->ode.ode_massbuf, &mass, sizeof(dMass)); + + ed->ode.ode_geom = (void *)geom; + } + + //non-moving objects need to be static objects (and thus need 0 mass) + if (movetype != MOVETYPE_PHYSICS && movetype != MOVETYPE_WALK) //enabling kinematic objects for everything else destroys framerates (!movetype || movetype == MOVETYPE_PUSH) + massval = 0; + + //if the mass changes, we'll need to create a new body (but not the shape, so invalidate the current one) + if (ed->ode.ode_mass != massval) + { + ed->ode.ode_mass = massval; + body = (btRigidBody*)ed->ode.ode_body; + if (body) + ctx->dworld->removeRigidBody(body); + ed->ode.ode_body = NULL; + } + +// if(ed->ode.ode_geom) +// dGeomSetData(ed->ode.ode_geom, (void*)ed); + if (movetype == MOVETYPE_PHYSICS && ed->ode.ode_mass) + { + if (ed->ode.ode_body == NULL) + { +// ed->ode.ode_body = (void *)(body = dBodyCreate(world->ode.ode_world)); +// dGeomSetBody(ed->ode.ode_geom, body); +// dBodySetData(body, (void*)ed); +// dBodySetMass(body, (dMass *) ed->ode.ode_massbuf); + + btVector3 fallInertia(0, 0, 0); + ((btCollisionShape*)ed->ode.ode_geom)->calculateLocalInertia(ed->ode.ode_mass, fallInertia); + btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(ed->ode.ode_mass, new QCMotionState(ed,world), (btCollisionShape*)ed->ode.ode_geom, fallInertia); + body = new btRigidBody(fallRigidBodyCI); + body->setUserPointer(ed); +// btTransform trans; +// trans.setFromOpenGLMatrix(ed->ode.ode_offsetmatrix); +// body->setCenterOfMassTransform(trans); + ed->ode.ode_body = (void*)body; + + //continuous collision detection prefers using a sphere within the object. tbh I have no idea what values to specify. + body->setCcdMotionThreshold((geomsize[0]+geomsize[1]+geomsize[2])*(4/3)); + body->setCcdSweptSphereRadius((geomsize[0]+geomsize[1]+geomsize[2])*(0.5/3)); + + ctx->dworld->addRigidBody(body, ed->xv->dimension_solid, ed->xv->dimension_hit); + + modified = qtrue; + } + } + else + { + if (ed->ode.ode_body == NULL) + { + btRigidBody::btRigidBodyConstructionInfo rbci(ed->ode.ode_mass, new QCMotionState(ed,world), (btCollisionShape*)ed->ode.ode_geom, btVector3(0, 0, 0)); + body = new btRigidBody(rbci); + body->setUserPointer(ed); +// btTransform trans; +// trans.setFromOpenGLMatrix(ed->ode.ode_offsetmatrix); +// body->setCenterOfMassTransform(trans); + ed->ode.ode_body = (void*)body; + if (ed->ode.ode_mass) + body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + else + body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT); + ctx->dworld->addRigidBody(body, ed->xv->dimension_solid, ed->xv->dimension_hit); + + modified = qtrue; + } + } + + body = (btRigidBody*)ed->ode.ode_body; + + // get current data from entity + gravity = qtrue; + VectorCopy(ed->v->origin, origin); + VectorCopy(ed->v->velocity, velocity); + VectorCopy(ed->v->angles, angles); + VectorCopy(ed->v->avelocity, avelocity); + if (ed == world->edicts || (ed->xv->gravity && ed->xv->gravity <= 0.01)) + gravity = qfalse; + + // compatibility for legacy entities +// if (!DotProduct(forward,forward) || solid == SOLID_BSP) + { + vec3_t qangles, qavelocity; + VectorCopy(angles, qangles); + VectorCopy(avelocity, qavelocity); + + if (ed->v->modelindex) + { + model = world->Get_CModel(world, ed->v->modelindex); + if (!model || model->type == mod_alias) + { + qangles[PITCH] *= -1; + qavelocity[PITCH] *= -1; + } + } + + modfuncs->AngleVectors(qangles, forward, left, up); + VectorNegate(left,left); + // convert single-axis rotations in avelocity to spinvelocity + // FIXME: untested math - check signs + VectorSet(spinvelocity, DEG2RAD(qavelocity[PITCH]), DEG2RAD(qavelocity[ROLL]), DEG2RAD(qavelocity[YAW])); + } + + // compatibility for legacy entities + switch (solid) + { + case SOLID_BBOX: + case SOLID_SLIDEBOX: + case SOLID_CORPSE: + VectorSet(forward, 1, 0, 0); + VectorSet(left, 0, 1, 0); + VectorSet(up, 0, 0, 1); + VectorSet(spinvelocity, 0, 0, 0); + break; + } + + + // we must prevent NANs... + test = DotProduct(origin,origin) + DotProduct(forward,forward) + DotProduct(left,left) + DotProduct(up,up) + DotProduct(velocity,velocity) + DotProduct(spinvelocity,spinvelocity); + if (IS_NAN(test)) + { + modified = qtrue; + //Con_Printf("Fixing NAN values on entity %i : .classname = \"%s\" .origin = '%f %f %f' .velocity = '%f %f %f' .axis_forward = '%f %f %f' .axis_left = '%f %f %f' .axis_up = %f %f %f' .spinvelocity = '%f %f %f'\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.classname)->string), origin[0], origin[1], origin[2], velocity[0], velocity[1], velocity[2], forward[0], forward[1], forward[2], left[0], left[1], left[2], up[0], up[1], up[2], spinvelocity[0], spinvelocity[1], spinvelocity[2]); + Con_Printf("Fixing NAN values on entity %i : .classname = \"%s\" .origin = '%f %f %f' .velocity = '%f %f %f' .angles = '%f %f %f' .avelocity = '%f %f %f'\n", NUM_FOR_EDICT(world->progs, (edict_t*)ed), PR_GetString(world->progs, ed->v->classname), origin[0], origin[1], origin[2], velocity[0], velocity[1], velocity[2], angles[0], angles[1], angles[2], avelocity[0], avelocity[1], avelocity[2]); + test = DotProduct(origin,origin); + if (IS_NAN(test)) + VectorClear(origin); + test = DotProduct(forward,forward) * DotProduct(left,left) * DotProduct(up,up); + if (IS_NAN(test)) + { + VectorSet(angles, 0, 0, 0); + VectorSet(forward, 1, 0, 0); + VectorSet(left, 0, 1, 0); + VectorSet(up, 0, 0, 1); + } + test = DotProduct(velocity,velocity); + if (IS_NAN(test)) + VectorClear(velocity); + test = DotProduct(spinvelocity,spinvelocity); + if (IS_NAN(test)) + { + VectorClear(avelocity); + VectorClear(spinvelocity); + } + } + + // check if the qc edited any position data + if ( + 0//!VectorCompare(origin, ed->ode.ode_origin) + || !VectorCompare(velocity, ed->ode.ode_velocity) + //|| !VectorCompare(angles, ed->ode.ode_angles) + || !VectorCompare(avelocity, ed->ode.ode_avelocity) + || gravity != ed->ode.ode_gravity) + modified = qtrue; + + // store the qc values into the physics engine + body = (btRigidBody*)ed->ode.ode_body; + if (modified && body) + { +// dVector3 r[3]; + float entitymatrix[16]; + float bodymatrix[16]; + +#if 0 + Con_Printf("entity %i got changed by QC\n", (int) (ed - prog->edicts)); + if(!VectorCompare(origin, ed->ode.ode_origin)) + Con_Printf(" origin: %f %f %f -> %f %f %f\n", ed->ode.ode_origin[0], ed->ode.ode_origin[1], ed->ode.ode_origin[2], origin[0], origin[1], origin[2]); + if(!VectorCompare(velocity, ed->ode.ode_velocity)) + Con_Printf(" velocity: %f %f %f -> %f %f %f\n", ed->ode.ode_velocity[0], ed->ode.ode_velocity[1], ed->ode.ode_velocity[2], velocity[0], velocity[1], velocity[2]); + if(!VectorCompare(angles, ed->ode.ode_angles)) + Con_Printf(" angles: %f %f %f -> %f %f %f\n", ed->ode.ode_angles[0], ed->ode.ode_angles[1], ed->ode.ode_angles[2], angles[0], angles[1], angles[2]); + if(!VectorCompare(avelocity, ed->ode.ode_avelocity)) + Con_Printf(" avelocity: %f %f %f -> %f %f %f\n", ed->ode.ode_avelocity[0], ed->ode.ode_avelocity[1], ed->ode.ode_avelocity[2], avelocity[0], avelocity[1], avelocity[2]); + if(gravity != ed->ode.ode_gravity) + Con_Printf(" gravity: %i -> %i\n", ed->ide.ode_gravity, gravity); +#endif + + // values for BodyFromEntity to check if the qc modified anything later + VectorCopy(origin, ed->ode.ode_origin); + VectorCopy(velocity, ed->ode.ode_velocity); + VectorCopy(angles, ed->ode.ode_angles); + VectorCopy(avelocity, ed->ode.ode_avelocity); + ed->ode.ode_gravity = gravity; + +// foo Matrix4x4_RM_FromVectors(entitymatrix, forward, left, up, origin); +// foo Matrix4_Multiply(ed->ode.ode_offsetmatrix, entitymatrix, bodymatrix); +// foo Matrix3x4_RM_ToVectors(bodymatrix, forward, left, up, origin); + +// r[0][0] = forward[0]; +// r[1][0] = forward[1]; +// r[2][0] = forward[2]; +// r[0][1] = left[0]; +// r[1][1] = left[1]; +// r[2][1] = left[2]; +// r[0][2] = up[0]; +// r[1][2] = up[1]; +// r[2][2] = up[2]; + + QCMotionState *ms = (QCMotionState*)body->getMotionState(); + ms->ReloadMotionState(); + body->setMotionState(ms); + body->setLinearVelocity(btVector3(velocity[0], velocity[1], velocity[2])); + body->setAngularVelocity(btVector3(spinvelocity[0], spinvelocity[1], spinvelocity[2])); +// body->setGravity(btVector3(ed->xv->gravitydir[0], ed->xv->gravitydir[1], ed->xv->gravitydir[2]) * ed->xv->gravity); + + //something changed. make sure it still falls over appropriately + body->setActivationState(1); + } + +/* FIXME: check if we actually need this insanity with bullet (ode sucks). + if(body) + { + // limit movement speed to prevent missed collisions at high speed + btVector3 ovelocity = body->getLinearVelocity(); + btVector3 ospinvelocity = body->getAngularVelocity(); + movelimit = ed->ode.ode_movelimit * world->ode.ode_movelimit; + test = DotProduct(ovelocity,ovelocity); + if (test > movelimit*movelimit) + { + // scale down linear velocity to the movelimit + // scale down angular velocity the same amount for consistency + f = movelimit / sqrt(test); + VectorScale(ovelocity, f, velocity); + VectorScale(ospinvelocity, f, spinvelocity); + body->setLinearVelocity(btVector3(velocity[0], velocity[1], velocity[2])); + body->setAngularVelocity(btVector3(spinvelocity[0], spinvelocity[1], spinvelocity[2])); + } + + // make sure the angular velocity is not exploding + spinlimit = physics_bullet_spinlimit.value; + test = DotProduct(ospinvelocity,ospinvelocity); + if (test > spinlimit) + { + body->setAngularVelocity(btVector3(0, 0, 0)); + } + } +*/ +} + +/* +#define MAX_CONTACTS 16 +static void VARGS nearCallback (void *data, dGeomID o1, dGeomID o2) +{ + world_t *world = (world_t *)data; + dContact contact[MAX_CONTACTS]; // max contacts per collision pair + dBodyID b1; + dBodyID b2; + dJointID c; + int i; + int numcontacts; + + float bouncefactor1 = 0.0f; + float bouncestop1 = 60.0f / 800.0f; + float bouncefactor2 = 0.0f; + float bouncestop2 = 60.0f / 800.0f; + float erp; + dVector3 grav; + wedict_t *ed1, *ed2; + + if (dGeomIsSpace(o1) || dGeomIsSpace(o2)) + { + // colliding a space with something + dSpaceCollide2(o1, o2, data, &nearCallback); + // Note we do not want to test intersections within a space, + // only between spaces. + //if (dGeomIsSpace(o1)) dSpaceCollide(o1, data, &nearCallback); + //if (dGeomIsSpace(o2)) dSpaceCollide(o2, data, &nearCallback); + return; + } + + b1 = dGeomGetBody(o1); + b2 = dGeomGetBody(o2); + + // at least one object has to be using MOVETYPE_PHYSICS or we just don't care + if (!b1 && !b2) + return; + + // exit without doing anything if the two bodies are connected by a joint + if (b1 && b2 && dAreConnectedExcluding(b1, b2, dJointTypeContact)) + return; + + ed1 = (wedict_t *) dGeomGetData(o1); + ed2 = (wedict_t *) dGeomGetData(o2); + if (ed1 == ed2 && ed1) + { + //ragdolls don't make contact with the bbox of the doll entity + //the origional entity should probably not be solid anyway. + //these bodies should probably not collide against bboxes of other entities with ragdolls either, but meh. + if (ed1->ode.ode_body == b1 || ed2->ode.ode_body == b2) + return; + } + if(!ed1 || ed1->isfree) + ed1 = world->edicts; + if(!ed2 || ed2->isfree) + ed2 = world->edicts; + + // generate contact points between the two non-space geoms + numcontacts = dCollide(o1, o2, MAX_CONTACTS, &(contact[0].geom), sizeof(contact[0])); + if (numcontacts) + { + if(ed1 && ed1->v->touch) + { + world->Event_Touch(world, ed1, ed2); + } + if(ed2 && ed2->v->touch) + { + world->Event_Touch(world, ed2, ed1); + } + + // if either ent killed itself, don't collide + if ((ed1&&ed1->isfree) || (ed2&&ed2->isfree)) + return; + } + + if(ed1) + { + if (ed1->xv->bouncefactor) + bouncefactor1 = ed1->xv->bouncefactor; + + if (ed1->xv->bouncestop) + bouncestop1 = ed1->xv->bouncestop; + } + + if(ed2) + { + if (ed2->xv->bouncefactor) + bouncefactor2 = ed2->xv->bouncefactor; + + if (ed2->xv->bouncestop) + bouncestop2 = ed2->xv->bouncestop; + } + + if ((ed2->entnum&&ed1->v->owner == ed2->entnum) || (ed1->entnum&&ed2->v->owner == ed1->entnum)) + return; + + // merge bounce factors and bounce stop + if(bouncefactor2 > 0) + { + if(bouncefactor1 > 0) + { + // TODO possibly better logic to merge bounce factor data? + if(bouncestop2 < bouncestop1) + bouncestop1 = bouncestop2; + if(bouncefactor2 > bouncefactor1) + bouncefactor1 = bouncefactor2; + } + else + { + bouncestop1 = bouncestop2; + bouncefactor1 = bouncefactor2; + } + } + dWorldGetGravity(world->ode.ode_world, grav); + bouncestop1 *= fabs(grav[2]); + + erp = (DotProduct(ed1->v->velocity, ed1->v->velocity) > DotProduct(ed2->v->velocity, ed2->v->velocity)) ? ed1->xv->erp : ed2->xv->erp; + + // add these contact points to the simulation + for (i = 0;i < numcontacts;i++) + { + contact[i].surface.mode = (physics_bullet_contact_mu.value != -1 ? dContactApprox1 : 0) | + (physics_bullet_contact_erp.value != -1 ? dContactSoftERP : 0) | + (physics_bullet_contact_cfm.value != -1 ? dContactSoftCFM : 0) | + (bouncefactor1 > 0 ? dContactBounce : 0); + contact[i].surface.mu = physics_bullet_contact_mu.value; + if (ed1->xv->friction) + contact[i].surface.mu *= ed1->xv->friction; + if (ed2->xv->friction) + contact[i].surface.mu *= ed2->xv->friction; + contact[i].surface.mu2 = 0; + contact[i].surface.soft_erp = physics_bullet_contact_erp.value + erp; + contact[i].surface.soft_cfm = physics_bullet_contact_cfm.value; + contact[i].surface.bounce = bouncefactor1; + contact[i].surface.bounce_vel = bouncestop1; + c = dJointCreateContact(world->ode.ode_world, world->ode.ode_contactgroup, contact + i); + dJointAttach(c, b1, b2); + } +} +*/ + +static void QDECL World_Bullet_Frame(world_t *world, double frametime, double gravity) +{ + struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe; + if (world->rbe_hasphysicsents || ctx->hasextraobjs) + { + int i; + wedict_t *ed; + +// world->ode.ode_iterations = bound(1, physics_bullet_iterationsperframe.ival, 1000); +// world->ode.ode_step = frametime / world->ode.ode_iterations; +// world->ode.ode_movelimit = physics_bullet_movelimit.value / world->ode.ode_step; + + + // copy physics properties from entities to physics engine + for (i = 0;i < world->num_edicts;i++) + { + ed = (wedict_t*)EDICT_NUM(world->progs, i); + if (!ed->isfree) + World_Bullet_Frame_BodyFromEntity(world, ed); + } + // oh, and it must be called after all bodies were created + for (i = 0;i < world->num_edicts;i++) + { + ed = (wedict_t*)EDICT_NUM(world->progs, i); + if (!ed->isfree) + World_Bullet_Frame_JointFromEntity(world, ed); + } + while(ctx->cmdqueuehead) + { + rbecommandqueue_t *cmd = ctx->cmdqueuehead; + ctx->cmdqueuehead = cmd->next; + if (!cmd->next) + ctx->cmdqueuetail = NULL; + World_Bullet_RunCmd(world, cmd); + Z_Free(cmd); + } + + ctx->dworld->setGravity(btVector3(0, 0, -gravity)); + + ctx->dworld->stepSimulation(frametime, max(0, pCvar_GetFloat("physics_bullet_maxiterationsperframe")), 1/bound(1, pCvar_GetFloat("physics_bullet_framerate"), 500)); + + // set the tolerance for closeness of objects +// dWorldSetContactSurfaceLayer(world->ode.ode_world, max(0, physics_bullet_contactsurfacelayer.value)); + + // run collisions for the current world state, creating JointGroup +// dSpaceCollide(world->ode.ode_space, (void *)world, nearCallback); + + // run physics (move objects, calculate new velocities) +// if (physics_bullet_worldquickstep.ival) +// { +// dWorldSetQuickStepNumIterations(world->ode.ode_world, bound(1, physics_bullet_worldquickstep_iterations.ival, 200)); +// dWorldQuickStep(world->ode.ode_world, world->ode.ode_step); +// } +// else +// dWorldStep(world->ode.ode_world, world->ode.ode_step); + + // clear the JointGroup now that we're done with it +// dJointGroupEmpty(world->ode.ode_contactgroup); + + if (world->rbe_hasphysicsents) + { + // copy physics properties from physics engine to entities + for (i = 1;i < world->num_edicts;i++) + { + ed = (wedict_t*)EDICT_NUM(world->progs, i); + if (!ed->isfree) + World_Bullet_Frame_BodyToEntity(world, ed); + } + } + } +} + +static void World_Bullet_RunCmd(world_t *world, rbecommandqueue_t *cmd) +{ + btRigidBody *body = (btRigidBody*)(cmd->edict->ode.ode_body); + switch(cmd->command) + { + case RBECMD_ENABLE: + if (body) + body->setActivationState(1); + break; + case RBECMD_DISABLE: + if (body) + body->setActivationState(0); + break; + case RBECMD_FORCE: + if (body) + { + body->setActivationState(1); + body->applyForce(btVector3(cmd->v1[0], cmd->v1[1], cmd->v1[2]), btVector3(cmd->v2[0], cmd->v2[1], cmd->v2[2])); + } + break; + case RBECMD_TORQUE: + if (cmd->edict->ode.ode_body) + { + body->setActivationState(1); + body->applyTorque(btVector3(cmd->v1[0], cmd->v1[1], cmd->v1[2])); + } + break; + } +} + +static void QDECL World_Bullet_PushCommand(world_t *world, rbecommandqueue_t *val) +{ + struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe; + rbecommandqueue_t *cmd = (rbecommandqueue_t*)BZ_Malloc(sizeof(*cmd)); + world->rbe_hasphysicsents = qtrue; //just in case. + memcpy(cmd, val, sizeof(*cmd)); + cmd->next = NULL; + //add on the end of the queue, so that order is preserved. + if (ctx->cmdqueuehead) + { + rbecommandqueue_t *ot = ctx->cmdqueuetail; + ot->next = ctx->cmdqueuetail = cmd; + } + else + ctx->cmdqueuetail = ctx->cmdqueuehead = cmd; +} + +static void QDECL World_Bullet_TraceEntity(world_t *world, vec3_t start, vec3_t end, wedict_t *ed) +{ + struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe; + btCollisionShape *shape = (btCollisionShape*)ed->ode.ode_geom; + + class myConvexResultCallback : public btCollisionWorld::ConvexResultCallback + { + public: + virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) + { + return 0; + } + } result; + + btTransform from(btMatrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1), btVector3(start[0], start[1], start[2])); + btTransform to(btMatrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1), btVector3(end[0], end[1], end[2])); + ctx->dworld->convexSweepTest((btConvexShape*)shape, from, to, result, 1); +} + +static void QDECL World_Bullet_Start(world_t *world) +{ + struct bulletcontext_s *ctx; + if (world->rbe) + return; //no thanks, we already have one. somehow. + + if (!pCvar_GetFloat("physics_bullet_enable")) + return; + + ctx = (struct bulletcontext_s*)BZ_Malloc(sizeof(*ctx)); + memset(ctx, 0, sizeof(*ctx)); + ctx->gworld = world; + ctx->funcs.End = World_Bullet_End; + ctx->funcs.RemoveJointFromEntity = World_Bullet_RemoveJointFromEntity; + ctx->funcs.RemoveFromEntity = World_Bullet_RemoveFromEntity; + ctx->funcs.RagMatrixToBody = World_Bullet_RagMatrixToBody; + ctx->funcs.RagCreateBody = World_Bullet_RagCreateBody; + ctx->funcs.RagMatrixFromJoint = World_Bullet_RagMatrixFromJoint; + ctx->funcs.RagMatrixFromBody = World_Bullet_RagMatrixFromBody; + ctx->funcs.RagEnableJoint = World_Bullet_RagEnableJoint; + ctx->funcs.RagCreateJoint = World_Bullet_RagCreateJoint; + ctx->funcs.RagDestroyBody = World_Bullet_RagDestroyBody; + ctx->funcs.RagDestroyJoint = World_Bullet_RagDestroyJoint; + ctx->funcs.Frame = World_Bullet_Frame; + ctx->funcs.PushCommand = World_Bullet_PushCommand; + world->rbe = &ctx->funcs; + + + ctx->broadphase = new btDbvtBroadphase(); + ctx->collisionconfig = new btDefaultCollisionConfiguration(); + ctx->collisiondispatcher = new btCollisionDispatcher(ctx->collisionconfig); + ctx->solver = new btSequentialImpulseConstraintSolver; + ctx->dworld = new btDiscreteDynamicsWorld(ctx->collisiondispatcher, ctx->broadphase, ctx->solver, ctx->collisionconfig); + + ctx->ownerfilter = new QCFilterCallback(); + ctx->dworld->getPairCache()->setOverlapFilterCallback(ctx->ownerfilter); + + + + ctx->dworld->setGravity(btVector3(0, -10, 0)); + +/* + if(physics_bullet_world_erp.value >= 0) + dWorldSetERP(world->ode.ode_world, physics_bullet_world_erp.value); + if(physics_bullet_world_cfm.value >= 0) + dWorldSetCFM(world->ode.ode_world, physics_bullet_world_cfm.value); + if (physics_bullet_world_damping.ival) + { + dWorldSetLinearDamping(world->ode.ode_world, (physics_bullet_world_damping_linear.value >= 0) ? (physics_bullet_world_damping_linear.value * physics_bullet_world_damping.value) : 0); + dWorldSetLinearDampingThreshold(world->ode.ode_world, (physics_bullet_world_damping_linear_threshold.value >= 0) ? (physics_bullet_world_damping_linear_threshold.value * physics_bullet_world_damping.value) : 0); + dWorldSetAngularDamping(world->ode.ode_world, (physics_bullet_world_damping_angular.value >= 0) ? (physics_bullet_world_damping_angular.value * physics_bullet_world_damping.value) : 0); + dWorldSetAngularDampingThreshold(world->ode.ode_world, (physics_bullet_world_damping_angular_threshold.value >= 0) ? (physics_bullet_world_damping_angular_threshold.value * physics_bullet_world_damping.value) : 0); + } + else + { + dWorldSetLinearDamping(world->ode.ode_world, 0); + dWorldSetLinearDampingThreshold(world->ode.ode_world, 0); + dWorldSetAngularDamping(world->ode.ode_world, 0); + dWorldSetAngularDampingThreshold(world->ode.ode_world, 0); + } + if (physics_bullet_autodisable.ival) + { + dWorldSetAutoDisableSteps(world->ode.ode_world, bound(1, physics_bullet_autodisable_steps.ival, 100)); + dWorldSetAutoDisableTime(world->ode.ode_world, physics_bullet_autodisable_time.value); + dWorldSetAutoDisableAverageSamplesCount(world->ode.ode_world, bound(1, physics_bullet_autodisable_threshold_samples.ival, 100)); + dWorldSetAutoDisableLinearThreshold(world->ode.ode_world, physics_bullet_autodisable_threshold_linear.value); + dWorldSetAutoDisableAngularThreshold(world->ode.ode_world, physics_bullet_autodisable_threshold_angular.value); + dWorldSetAutoDisableFlag (world->ode.ode_world, true); + } + else + dWorldSetAutoDisableFlag (world->ode.ode_world, false); + */ +} + +static qintptr_t QDECL World_Bullet_Shutdown(qintptr_t *args) +{ + if (modfuncs) + modfuncs->UnregisterPhysicsEngine("Bullet"); + return 0; +} + +static bool World_Bullet_DoInit(void) +{ + if (!modfuncs || !modfuncs->RegisterPhysicsEngine) + Con_Printf("Bullet plugin failed: Engine doesn't support physics engine plugins.\n"); + else if (!modfuncs->RegisterPhysicsEngine("Bullet", World_Bullet_Start)) + Con_Printf("Bullet plugin failed: Engine already has a physics plugin active.\n"); + else + { + World_Bullet_Init(); + return true; + } + return false; +} + +#define ARGNAMES ,version +static BUILTINR(modplugfuncs_t*, Mod_GetPluginModelFuncs, (int version)); +#undef ARGNAMES + +extern "C" qintptr_t Plug_Init(qintptr_t *args) +{ + CHECKBUILTIN(Mod_GetPluginModelFuncs); + + if (BUILTINISVALID(Mod_GetPluginModelFuncs)) + { + modfuncs = pMod_GetPluginModelFuncs(sizeof(modplugfuncs_t)); + if (modfuncs && modfuncs->version < MODPLUGFUNCS_VERSION) + modfuncs = NULL; + } + + Plug_Export("Shutdown", World_Bullet_Shutdown); + return World_Bullet_DoInit(); +} + + diff --git a/engine/common/com_phys_ode.c b/engine/common/com_phys_ode.c index fa4d9a903..ab2bbb85a 100644 --- a/engine/common/com_phys_ode.c +++ b/engine/common/com_phys_ode.c @@ -24,11 +24,56 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Originally written by LordHavoc. */ -#include "quakedef.h" -#include "pr_common.h" -#include "glquake.h" +//if we're not building as an fte-specific plugin, we must be being built as part of the fte engine itself. +//(no, we don't want to act as a plugin for ezquake...) +#ifndef FTEPLUGIN +#define FTEENGINE +#define FTEPLUGIN +#define pCvar_Register Cvar_Get +#define pCvar_GetFloat(x) Cvar_FindVar(x)->value +#define pSys_Error Sys_Error +#define Plug_Init Plug_ODE_Init +#endif -#ifdef USEODE +#include "../../plugins/plugin.h" +#include "../../plugins/engine.h" + +#ifdef USERBE + +#include "pr_common.h" +#include "com_mesh.h" + +#ifndef FTEENGINE +#define BZ_Malloc malloc +#define BZ_Free free +#define Z_Free BZ_Free +static vec3_t vec3_origin; +static int VectorCompare (const vec3_t v1, const vec3_t v2) +{ + int i; + for (i=0 ; i<3 ; i++) + if (v1[i] != v2[i]) + return 0; + return 1; +} + +#endif + + +#define ARGNAMES ,name,funcs +static BUILTINR(dllhandle_t *, Sys_LoadLibrary, (const char *name,dllfunction_t *funcs)); +#undef ARGNAMES +#define ARGNAMES ,hdl +static BUILTIN(void, Sys_CloseLibrary, (dllhandle_t *hdl)); +#undef ARGNAMES +#define ARGNAMES ,version +static BUILTINR(modplugfuncs_t*, Mod_GetPluginModelFuncs, (int version)); +#undef ARGNAMES +#define ARGNAMES ,name,defaultval,flags,description,groupname +static BUILTINR(cvar_t*, Cvar_GetNVFDG, (const char *name, const char *defaultval, unsigned int flags, const char *description, const char *groupname)); +#undef ARGNAMES + +static modplugfuncs_t *modfuncs; //============================================================================ // physics engine support @@ -38,32 +83,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //#define ODE_DYNAMIC 1 //#endif -cvar_t physics_ode_enable = CVARD("physics_ode_enable", IFMINIMAL("0", "1"), "Enables the use of ODE physics, but only if the mod supports it."); -cvar_t physics_ode_quadtree_depth = CVARDP4(0, "physics_ode_quadtree_depth","5", "desired subdivision level of quadtree culling space"); -cvar_t physics_ode_contactsurfacelayer = CVARDP4(0, "physics_ode_contactsurfacelayer","0", "allows objects to overlap this many units to reduce jitter"); -cvar_t physics_ode_worldquickstep = CVARDP4(0, "physics_ode_worldquickstep","1", "use dWorldQuickStep rather than dWorldStep"); -cvar_t physics_ode_worldquickstep_iterations = CVARDP4(0, "physics_ode_worldquickstep_iterations","20", "parameter to dWorldQuickStep"); -//physics_ode_worldstepfast dWorldStepFast1 is not present in more recent versions of ODE. thus we don't use it ever. -cvar_t physics_ode_contact_mu = CVARDP4(0, "physics_ode_contact_mu", "1", "contact solver mu parameter - friction pyramid approximation 1 (see ODE User Guide)"); -cvar_t physics_ode_contact_erp = CVARDP4(0, "physics_ode_contact_erp", "0.96", "contact solver erp parameter - Error Restitution Percent (see ODE User Guide)"); -cvar_t physics_ode_contact_cfm = CVARDP4(0, "physics_ode_contact_cfm", "0", "contact solver cfm parameter - Constraint Force Mixing (see ODE User Guide)"); -cvar_t physics_ode_world_damping = CVARDP4(0, "physics_ode_world_damping", "1", "enabled damping scale (see ODE User Guide), this scales all damping values, be aware that behavior depends of step type"); -cvar_t physics_ode_world_damping_linear = CVARDP4(0, "physics_ode_world_damping_linear", "0.005", "world linear damping scale (see ODE User Guide); use defaults when set to -1"); -cvar_t physics_ode_world_damping_linear_threshold = CVARDP4(0, "physics_ode_world_damping_linear_threshold", "0.01", "world linear damping threshold (see ODE User Guide); use defaults when set to -1"); -cvar_t physics_ode_world_damping_angular = CVARDP4(0, "physics_ode_world_damping_angular", "0.005", "world angular damping scale (see ODE User Guide); use defaults when set to -1"); -cvar_t physics_ode_world_damping_angular_threshold = CVARDP4(0, "physics_ode_world_damping_angular_threshold", "0.01", "world angular damping threshold (see ODE User Guide); use defaults when set to -1"); -cvar_t physics_ode_world_erp = CVARDP4(0, "physics_ode_world_erp", "-1", "world solver erp parameter - Error Restitution Percent (see ODE User Guide); use defaults when set to -1"); -cvar_t physics_ode_world_cfm = CVARDP4(0, "physics_ode_world_cfm", "-1", "world solver cfm parameter - Constraint Force Mixing (see ODE User Guide); not touched when -1"); -cvar_t physics_ode_iterationsperframe = CVARDP4(0, "physics_ode_iterationsperframe", "4", "divisor for time step, runs multiple physics steps per frame"); -cvar_t physics_ode_movelimit = CVARDP4(0, "physics_ode_movelimit", "0.5", "clamp velocity if a single move would exceed this percentage of object thickness, to prevent flying through walls"); -cvar_t physics_ode_spinlimit = CVARDP4(0, "physics_ode_spinlimit", "10000", "reset spin velocity if it gets too large"); -cvar_t physics_ode_autodisable = CVARDP4(0, "physics_ode_autodisable", "1", "automatic disabling of objects which dont move for long period of time, makes object stacking a lot faster"); -cvar_t physics_ode_autodisable_steps = CVARDP4(0, "physics_ode_autodisable_steps", "10", "how many steps object should be dormant to be autodisabled"); -cvar_t physics_ode_autodisable_time = CVARDP4(0, "physics_ode_autodisable_time", "0", "how many seconds object should be dormant to be autodisabled"); -cvar_t physics_ode_autodisable_threshold_linear = CVARDP4(0, "physics_ode_autodisable_threshold_linear", "0.2", "body will be disabled if it's linear move below this value"); -cvar_t physics_ode_autodisable_threshold_angular = CVARDP4(0, "physics_ode_autodisable_threshold_angular", "0.3", "body will be disabled if it's angular move below this value"); -cvar_t physics_ode_autodisable_threshold_samples = CVARDP4(0, "physics_ode_autodisable_threshold_samples", "5", "average threshold with this number of samples"); - // LordHavoc: this large chunk of definitions comes from the ODE library // include files. @@ -1168,19 +1187,65 @@ static dllfunction_t odefuncs[] = }; // Handle for ODE DLL -dllhandle_t *ode_dll = NULL; +static dllhandle_t *ode_dll = NULL; #endif -static void World_ODE_RunCmd(world_t *world, odecommandqueue_t *cmd); -void World_ODE_Init(void) +static cvar_t *physics_ode_enable; +static cvar_t *physics_ode_quadtree_depth; +static cvar_t *physics_ode_contactsurfacelayer; +static cvar_t *physics_ode_worldquickstep; +static cvar_t *physics_ode_worldquickstep_iterations; +static cvar_t *physics_ode_contact_mu; +static cvar_t *physics_ode_contact_erp; +static cvar_t *physics_ode_contact_cfm; +static cvar_t *physics_ode_world_damping; +static cvar_t *physics_ode_world_damping_linear; +static cvar_t *physics_ode_world_damping_linear_threshold; +static cvar_t *physics_ode_world_damping_angular; +static cvar_t *physics_ode_world_damping_angular_threshold; +static cvar_t *physics_ode_world_erp; +static cvar_t *physics_ode_world_cfm; +static cvar_t *physics_ode_iterationsperframe; +static cvar_t *physics_ode_movelimit; +static cvar_t *physics_ode_spinlimit; +static cvar_t *physics_ode_autodisable; +static cvar_t *physics_ode_autodisable_steps; +static cvar_t *physics_ode_autodisable_time; +static cvar_t *physics_ode_autodisable_threshold_linear; +static cvar_t *physics_ode_autodisable_threshold_angular; +static cvar_t *physics_ode_autodisable_threshold_samples; + +struct odectx_s +{ + rigidbodyengine_t pub; + + qboolean hasextraobjs; + dWorldID dworld; + void *space; + void *contactgroup; + // number of constraint solver iterations to use (for dWorldStepFast) + int iterations; + // actual step (server frametime / ode_iterations) + vec_t step; + // max velocity for a 1-unit radius object at current step to prevent + // missed collisions + vec_t movelimit; + rbecommandqueue_t *cmdqueuehead; + rbecommandqueue_t *cmdqueuetail; +}; + + +static void World_ODE_RunCmd(world_t *world, rbecommandqueue_t *cmd); + +static void World_ODE_Init(void) { #ifdef ODE_DYNAMIC const char* dllname = { -# if defined(WIN64) +# if defined(_WIN64) "libode1" -# elif defined(WIN32) +# elif defined(_WIN32) "ode_double" # elif defined(MACOSX) "libode.1.dylib" @@ -1190,34 +1255,35 @@ void World_ODE_Init(void) }; #endif - Cvar_Register(&physics_ode_enable, "ODE Physics Library"); - Cvar_Register(&physics_ode_quadtree_depth, "ODE Physics Library"); - Cvar_Register(&physics_ode_contactsurfacelayer, "ODE Physics Library"); - Cvar_Register(&physics_ode_worldquickstep, "ODE Physics Library"); - Cvar_Register(&physics_ode_worldquickstep_iterations, "ODE Physics Library"); - Cvar_Register(&physics_ode_contact_mu, "ODE Physics Library"); - Cvar_Register(&physics_ode_contact_erp, "ODE Physics Library"); - Cvar_Register(&physics_ode_contact_cfm, "ODE Physics Library"); - Cvar_Register(&physics_ode_world_damping, "ODE Physics Library"); - Cvar_Register(&physics_ode_world_damping_linear, "ODE Physics Library"); - Cvar_Register(&physics_ode_world_damping_linear_threshold, "ODE Physics Library"); - Cvar_Register(&physics_ode_world_damping_angular, "ODE Physics Library"); - Cvar_Register(&physics_ode_world_damping_angular_threshold, "ODE Physics Library"); - Cvar_Register(&physics_ode_world_erp, "ODE Physics Library"); - Cvar_Register(&physics_ode_world_cfm, "ODE Physics Library"); - Cvar_Register(&physics_ode_iterationsperframe, "ODE Physics Library"); - Cvar_Register(&physics_ode_movelimit, "ODE Physics Library"); - Cvar_Register(&physics_ode_spinlimit, "ODE Physics Library"); - Cvar_Register(&physics_ode_autodisable, "ODE Physics Library"); - Cvar_Register(&physics_ode_autodisable_steps, "ODE Physics Library"); - Cvar_Register(&physics_ode_autodisable_time, "ODE Physics Library"); - Cvar_Register(&physics_ode_autodisable_threshold_linear, "ODE Physics Library"); - Cvar_Register(&physics_ode_autodisable_threshold_angular, "ODE Physics Library"); - Cvar_Register(&physics_ode_autodisable_threshold_samples, "ODE Physics Library"); + + physics_ode_enable = pCvar_GetNVFDG("physics_ode_enable", "1", 0, "Enables the use of ODE physics, but only if the mod supports it.", "ODE Physics Library"); + physics_ode_quadtree_depth = pCvar_GetNVFDG("physics_ode_quadtree_depth", "5", 0, "desired subdivision level of quadtree culling space", "ODE Physics Library"); + physics_ode_contactsurfacelayer = pCvar_GetNVFDG("physics_ode_contactsurfacelayer", "0", 0, "allows objects to overlap this many units to reduce jitter", "ODE Physics Library"); + physics_ode_worldquickstep = pCvar_GetNVFDG("physics_ode_worldquickstep", "1", 0, "use dWorldQuickStep rather than dWorldStep", "ODE Physics Library"); + physics_ode_worldquickstep_iterations = pCvar_GetNVFDG("physics_ode_worldquickstep_iterations", "20", 0, "parameter to dWorldQuickStep", "ODE Physics Library"); + physics_ode_contact_mu = pCvar_GetNVFDG("physics_ode_contact_mu", "1", 0, "contact solver mu parameter - friction pyramid approximation 1 (see ODE User Guide)", "ODE Physics Library"); + physics_ode_contact_erp = pCvar_GetNVFDG("physics_ode_contact_erp", "0.96", 0, "contact solver erp parameter - Error Restitution Percent (see ODE User Guide)", "ODE Physics Library"); + physics_ode_contact_cfm = pCvar_GetNVFDG("physics_ode_contact_cfm", "0", 0, "contact solver cfm parameter - Constraint Force Mixing (see ODE User Guide)", "ODE Physics Library"); + physics_ode_world_damping = pCvar_GetNVFDG("physics_ode_world_damping", "1", 0, "enabled damping scale (see ODE User Guide), this scales all damping values, be aware that behavior depends of step type", "ODE Physics Library"); + physics_ode_world_damping_linear = pCvar_GetNVFDG("physics_ode_world_damping_linear", "0.005",0, "world linear damping scale (see ODE User Guide); use defaults when set to -1", "ODE Physics Library"); + physics_ode_world_damping_linear_threshold = pCvar_GetNVFDG("physics_ode_world_damping_linear_threshold", "0.01", 0, "world linear damping threshold (see ODE User Guide); use defaults when set to -1", "ODE Physics Library"); + physics_ode_world_damping_angular = pCvar_GetNVFDG("physics_ode_world_damping_angular", "0.005",0, "world angular damping scale (see ODE User Guide); use defaults when set to -1", "ODE Physics Library"); + physics_ode_world_damping_angular_threshold = pCvar_GetNVFDG("physics_ode_world_damping_angular_threshold", "0.01", 0, "world angular damping threshold (see ODE User Guide); use defaults when set to -1", "ODE Physics Library"); + physics_ode_world_erp = pCvar_GetNVFDG("physics_ode_world_erp", "-1", 0, "world solver erp parameter - Error Restitution Percent (see ODE User Guide); use defaults when set to -1", "ODE Physics Library"); + physics_ode_world_cfm = pCvar_GetNVFDG("physics_ode_world_cfm", "-1", 0, "world solver cfm parameter - Constraint Force Mixing (see ODE User Guide); not touched when -1", "ODE Physics Library"); + physics_ode_iterationsperframe = pCvar_GetNVFDG("physics_ode_iterationsperframe", "4", 0, "divisor for time step, runs multiple physics steps per frame", "ODE Physics Library"); + physics_ode_movelimit = pCvar_GetNVFDG("physics_ode_movelimit", "0.5", 0, "clamp velocity if a single move would exceed this percentage of object thickness, to prevent flying through walls","ODE Physics Library"); + physics_ode_spinlimit = pCvar_GetNVFDG("physics_ode_spinlimit", "10000",0, "reset spin velocity if it gets too large", "ODE Physics Library"); + physics_ode_autodisable = pCvar_GetNVFDG("physics_ode_autodisable", "1", 0, "automatic disabling of objects which dont move for long period of time, makes object stacking a lot faster", "ODE Physics Library"); + physics_ode_autodisable_steps = pCvar_GetNVFDG("physics_ode_autodisable_steps", "10", 0, "how many steps object should be dormant to be autodisabled", "ODE Physics Library"); + physics_ode_autodisable_time = pCvar_GetNVFDG("physics_ode_autodisable_time", "0", 0, "how many seconds object should be dormant to be autodisabled", "ODE Physics Library"); + physics_ode_autodisable_threshold_linear = pCvar_GetNVFDG("physics_ode_autodisable_threshold_linear", "0.2", 0, "body will be disabled if it's linear move below this value", "ODE Physics Library"); + physics_ode_autodisable_threshold_angular = pCvar_GetNVFDG("physics_ode_autodisable_threshold_angular", "0.3", 0, "body will be disabled if it's angular move below this value", "ODE Physics Library"); + physics_ode_autodisable_threshold_samples = pCvar_GetNVFDG("physics_ode_autodisable_threshold_samples", "5", 0, "average threshold with this number of samples", "ODE Physics Library"); #ifdef ODE_DYNAMIC // Load the DLL - ode_dll = Sys_LoadLibrary(dllname, odefuncs); + ode_dll = pSys_LoadLibrary(dllname, odefuncs); if (ode_dll) #endif { @@ -1235,7 +1301,7 @@ void World_ODE_Init(void) # else Con_Printf("ode library not compiled for double precision - incompatible! Not using ODE physics.\n"); # endif - Sys_CloseLibrary(ode_dll); + pSys_CloseLibrary(ode_dll); ode_dll = NULL; } #endif @@ -1244,13 +1310,11 @@ void World_ODE_Init(void) #ifdef ODE_DYNAMIC if (!ode_dll) { - physics_ode_enable.flags |= CVAR_NOSET; - Cvar_ForceSet(&physics_ode_enable, "0"); } #endif } -void World_ODE_Shutdown(void) +static void World_ODE_Shutdown(void) { #ifdef ODE_DYNAMIC if (ode_dll) @@ -1258,83 +1322,23 @@ void World_ODE_Shutdown(void) { dCloseODE(); #ifdef ODE_DYNAMIC - Sys_CloseLibrary(ode_dll); + pSys_CloseLibrary(ode_dll); ode_dll = NULL; #endif } } -static void World_ODE_Enable(world_t *world) +static void QDECL World_ODE_End(world_t *world) { - dVector3 center, extents; - if (world->ode.ode) - return; - - if (!physics_ode_enable.ival) - return; - -#ifdef ODE_DYNAMIC - if (!ode_dll) - return; -#endif - world->ode.ode = true; - VectorAvg(world->worldmodel->mins, world->worldmodel->maxs, center); - VectorSubtract(world->worldmodel->maxs, center, extents); - world->ode.ode_world = dWorldCreate(); - world->ode.ode_space = dQuadTreeSpaceCreate(NULL, center, extents, bound(1, physics_ode_quadtree_depth.ival, 10)); - world->ode.ode_contactgroup = dJointGroupCreate(0); - - - if(physics_ode_world_erp.value >= 0) - dWorldSetERP(world->ode.ode_world, physics_ode_world_erp.value); - if(physics_ode_world_cfm.value >= 0) - dWorldSetCFM(world->ode.ode_world, physics_ode_world_cfm.value); - if (physics_ode_world_damping.ival) - { - dWorldSetLinearDamping(world->ode.ode_world, (physics_ode_world_damping_linear.value >= 0) ? (physics_ode_world_damping_linear.value * physics_ode_world_damping.value) : 0); - dWorldSetLinearDampingThreshold(world->ode.ode_world, (physics_ode_world_damping_linear_threshold.value >= 0) ? (physics_ode_world_damping_linear_threshold.value * physics_ode_world_damping.value) : 0); - dWorldSetAngularDamping(world->ode.ode_world, (physics_ode_world_damping_angular.value >= 0) ? (physics_ode_world_damping_angular.value * physics_ode_world_damping.value) : 0); - dWorldSetAngularDampingThreshold(world->ode.ode_world, (physics_ode_world_damping_angular_threshold.value >= 0) ? (physics_ode_world_damping_angular_threshold.value * physics_ode_world_damping.value) : 0); - } - else - { - dWorldSetLinearDamping(world->ode.ode_world, 0); - dWorldSetLinearDampingThreshold(world->ode.ode_world, 0); - dWorldSetAngularDamping(world->ode.ode_world, 0); - dWorldSetAngularDampingThreshold(world->ode.ode_world, 0); - } - if (physics_ode_autodisable.ival) - { - dWorldSetAutoDisableSteps(world->ode.ode_world, bound(1, physics_ode_autodisable_steps.ival, 100)); - dWorldSetAutoDisableTime(world->ode.ode_world, physics_ode_autodisable_time.value); - dWorldSetAutoDisableAverageSamplesCount(world->ode.ode_world, bound(1, physics_ode_autodisable_threshold_samples.ival, 100)); - dWorldSetAutoDisableLinearThreshold(world->ode.ode_world, physics_ode_autodisable_threshold_linear.value); - dWorldSetAutoDisableAngularThreshold(world->ode.ode_world, physics_ode_autodisable_threshold_angular.value); - dWorldSetAutoDisableFlag (world->ode.ode_world, true); - } - else - dWorldSetAutoDisableFlag (world->ode.ode_world, false); + struct odectx_s *ctx = (struct odectx_s*)world->rbe; + world->rbe = NULL; + dWorldDestroy(ctx->dworld); + dSpaceDestroy(ctx->space); + dJointGroupDestroy(ctx->contactgroup); + Z_Free(ctx); } -void World_ODE_Start(world_t *world) -{ - if (world->ode.ode) - return; - World_ODE_Enable(world); -} - -void World_ODE_End(world_t *world) -{ - if (world->ode.ode) - { - dWorldDestroy(world->ode.ode_world); - dSpaceDestroy(world->ode.ode_space); - dJointGroupDestroy(world->ode.ode_contactgroup); - world->ode.ode = false; - } -} - -void World_ODE_RemoveJointFromEntity(world_t *world, wedict_t *ed) +static void QDECL World_ODE_RemoveJointFromEntity(world_t *world, wedict_t *ed) { ed->ode.ode_joint_type = 0; if(ed->ode.ode_joint) @@ -1342,7 +1346,7 @@ void World_ODE_RemoveJointFromEntity(world_t *world, wedict_t *ed) ed->ode.ode_joint = NULL; } -void World_ODE_RemoveFromEntity(world_t *world, wedict_t *ed) +static void QDECL World_ODE_RemoveFromEntity(world_t *world, wedict_t *ed) { if (!ed->ode.ode_physics) return; @@ -1379,14 +1383,7 @@ void World_ODE_RemoveFromEntity(world_t *world, wedict_t *ed) } ed->ode.ode_body = NULL; - if (ed->ode.ode_vertex3f) - BZ_Free(ed->ode.ode_vertex3f); - ed->ode.ode_vertex3f = NULL; - ed->ode.ode_numvertices = 0; - if (ed->ode.ode_element3i) - BZ_Free(ed->ode.ode_element3i); - ed->ode.ode_element3i = NULL; - ed->ode.ode_numtriangles = 0; + modfuncs->ReleaseCollisionMesh(ed); if(ed->ode.ode_massbuf) BZ_Free(ed->ode.ode_massbuf); ed->ode.ode_massbuf = NULL; @@ -1486,11 +1483,12 @@ static void World_ODE_Frame_BodyToEntity(world_t *world, wedict_t *ed) VectorCopy(avelocity, ed->ode.ode_avelocity); ed->ode.ode_gravity = dBodyGetGravityMode(body); - World_LinkEdict(world, ed, true); + modfuncs->LinkEdict(world, ed, true); } static void World_ODE_Frame_JointFromEntity(world_t *world, wedict_t *ed) { + struct odectx_s *ctx = (struct odectx_s*)world->rbe; dJointID j = 0; dBodyID b1 = 0; dBodyID b2 = 0; @@ -1529,8 +1527,8 @@ static void World_ODE_Frame_JointFromEntity(world_t *world, wedict_t *ed) float K = movedir[0]; float D = movedir[1]; float R = 2.0 * D * sqrt(K); // we assume D is premultiplied by sqrt(sprungMass) - CFM = 1.0 / (world->ode.ode_step * K + R); // always > 0 - ERP = world->ode.ode_step * K * CFM; + CFM = 1.0 / (ctx->step * K + R); // always > 0 + ERP = ctx->step * K * CFM; Vel = 0; FMax = 0; Stop = movedir[2]; @@ -1557,22 +1555,22 @@ static void World_ODE_Frame_JointFromEntity(world_t *world, wedict_t *ed) switch(jointtype) { case JOINTTYPE_POINT: - j = dJointCreateBall(world->ode.ode_world, 0); + j = dJointCreateBall(ctx->dworld, 0); break; case JOINTTYPE_HINGE: - j = dJointCreateHinge(world->ode.ode_world, 0); + j = dJointCreateHinge(ctx->dworld, 0); break; case JOINTTYPE_SLIDER: - j = dJointCreateSlider(world->ode.ode_world, 0); + j = dJointCreateSlider(ctx->dworld, 0); break; case JOINTTYPE_UNIVERSAL: - j = dJointCreateUniversal(world->ode.ode_world, 0); + j = dJointCreateUniversal(ctx->dworld, 0); break; case JOINTTYPE_HINGE2: - j = dJointCreateHinge2(world->ode.ode_world, 0); + j = dJointCreateHinge2(ctx->dworld, 0); break; case JOINTTYPE_FIXED: - j = dJointCreateFixed(world->ode.ode_world, 0); + j = dJointCreateFixed(ctx->dworld, 0); break; case 0: default: @@ -1673,179 +1671,7 @@ static void World_ODE_Frame_JointFromEntity(world_t *world, wedict_t *ed) } } -static qboolean GenerateCollisionMesh_BSP(world_t *world, model_t *mod, wedict_t *ed, vec3_t geomcenter) -{ - unsigned int sno; - msurface_t *surf; - mesh_t *mesh; - unsigned int numverts; - unsigned int numindexes,i; - - numverts = 0; - numindexes = 0; - for (sno = 0; sno < mod->nummodelsurfaces; sno++) - { - surf = &mod->surfaces[sno+mod->firstmodelsurface]; - if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) - continue; - - if (surf->mesh) - { - mesh = surf->mesh; - numverts += mesh->numvertexes; - numindexes += mesh->numindexes; - } - else - { - numverts += surf->numedges; - numindexes += (surf->numedges-2) * 3; - } - } - if (!numindexes) - { - Con_DPrintf("entity %i (classname %s) has no geometry\n", NUM_FOR_EDICT(world->progs, (edict_t*)ed), PR_GetString(world->progs, ed->v->classname)); - return false; - } - ed->ode.ode_element3i = BZ_Malloc(numindexes*sizeof(*ed->ode.ode_element3i)); - ed->ode.ode_vertex3f = BZ_Malloc(numverts*sizeof(vec3_t)); - - numverts = 0; - numindexes = 0; - for (sno = 0; sno < mod->nummodelsurfaces; sno++) - { - surf = &mod->surfaces[sno+mod->firstmodelsurface]; - if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) - continue; - - if (surf->mesh) - { - mesh = surf->mesh; - for (i = 0; i < mesh->numvertexes; i++) - VectorSubtract(mesh->xyz_array[i], geomcenter, (ed->ode.ode_vertex3f + 3*(numverts+i))); - for (i = 0; i < mesh->numindexes; i+=3) - { - //flip the triangles as we go - ed->ode.ode_element3i[numindexes+i+0] = numverts+mesh->indexes[i+2]; - ed->ode.ode_element3i[numindexes+i+1] = numverts+mesh->indexes[i+1]; - ed->ode.ode_element3i[numindexes+i+2] = numverts+mesh->indexes[i+0]; - } - numverts += mesh->numvertexes; - numindexes += i; - } - else - { - float *vec; - medge_t *edge; - int lindex; - for (i = 0; i < surf->numedges; i++) - { - lindex = mod->surfedges[surf->firstedge + i]; - - if (lindex > 0) - { - edge = &mod->edges[lindex]; - vec = mod->vertexes[edge->v[0]].position; - } - else - { - edge = &mod->edges[-lindex]; - vec = mod->vertexes[edge->v[1]].position; - } - - VectorSubtract(vec, geomcenter, (ed->ode.ode_vertex3f + 3*(numverts+i))); - } - for (i = 2; i < surf->numedges; i++) - { - //quake is backwards, not ode - ed->ode.ode_element3i[numindexes++] = numverts+i; - ed->ode.ode_element3i[numindexes++] = numverts+i-1; - ed->ode.ode_element3i[numindexes++] = numverts; - } - numverts += surf->numedges; - } - } - - ed->ode.ode_numvertices = numverts; - ed->ode.ode_numtriangles = numindexes/3; - return true; -} - -#include "com_mesh.h" -static qboolean GenerateCollisionMesh_Alias(world_t *world, model_t *mod, wedict_t *ed, vec3_t geomcenter) -{ - mesh_t mesh; - unsigned int numverts; - unsigned int numindexes,i; - galiasinfo_t *inf; - unsigned int surfnum = 0; - entity_t re; - - numverts = 0; - numindexes = 0; - - //fill in the parts of the entity_t that Alias_GAliasBuildMesh needs. - world->Get_FrameState(world, ed, &re.framestate); - re.fatness = ed->xv->fatness; - re.model = mod; - - inf = Mod_Extradata (mod); - while(inf) - { - numverts += inf->numverts; - numindexes += inf->numindexes; - inf = inf->nextsurf; - } - - if (!numindexes) - { - Con_DPrintf("entity %i (classname %s) has no geometry\n", NUM_FOR_EDICT(world->progs, (edict_t*)ed), PR_GetString(world->progs, ed->v->classname)); - return false; - } - ed->ode.ode_element3i = BZ_Malloc(numindexes*sizeof(*ed->ode.ode_element3i)); - ed->ode.ode_vertex3f = BZ_Malloc(numverts*sizeof(vec3_t)); - - numverts = 0; - numindexes = 0; - - inf = Mod_Extradata (mod); - while(inf) - { - Alias_GAliasBuildMesh(&mesh, NULL, inf, surfnum++, &re, false); - for (i = 0; i < mesh.numvertexes; i++) - VectorSubtract(mesh.xyz_array[i], geomcenter, (ed->ode.ode_vertex3f + 3*(numverts+i))); - for (i = 0; i < mesh.numindexes; i+=3) - { - //flip the triangles as we go - ed->ode.ode_element3i[numindexes+i+0] = numverts+mesh.indexes[i+2]; - ed->ode.ode_element3i[numindexes+i+1] = numverts+mesh.indexes[i+1]; - ed->ode.ode_element3i[numindexes+i+2] = numverts+mesh.indexes[i+0]; - } - numverts += inf->numverts; - numindexes += inf->numindexes; - inf = inf->nextsurf; - } - - Alias_FlushCache(); //it got built using an entity on the stack, make sure other stuff doesn't get hurt. - - ed->ode.ode_numvertices = numverts; - ed->ode.ode_numtriangles = numindexes/3; - return true; -} - -static qboolean GenerateCollisionMesh(world_t *world, model_t *mod, wedict_t *ed, vec3_t geomcenter) -{ - switch(mod->type) - { - case mod_brush: - return GenerateCollisionMesh_BSP(world, mod, ed, geomcenter); - case mod_alias: - return GenerateCollisionMesh_Alias(world, mod, ed, geomcenter); - default: - return false; //panic! - } -} - -qboolean World_ODE_RagMatrixToBody(odebody_t *bodyptr, float *mat) +static qboolean QDECL World_ODE_RagMatrixToBody(rbebody_t *bodyptr, float *mat) { dVector3 r[3]; @@ -1859,67 +1685,65 @@ qboolean World_ODE_RagMatrixToBody(odebody_t *bodyptr, float *mat) r[2][1] = mat[9]; r[2][2] = mat[10]; - dBodySetPosition(bodyptr->ode_body, mat[3], mat[7], mat[11]); - dBodySetRotation(bodyptr->ode_body, r[0]); - dBodySetLinearVel(bodyptr->ode_body, 0, 0, 0); - dBodySetAngularVel(bodyptr->ode_body, 0, 0, 0); + dBodySetPosition(bodyptr->body, mat[3], mat[7], mat[11]); + dBodySetRotation(bodyptr->body, r[0]); + dBodySetLinearVel(bodyptr->body, 0, 0, 0); + dBodySetAngularVel(bodyptr->body, 0, 0, 0); return true; } -qboolean World_ODE_RagCreateBody(world_t *world, odebody_t *bodyptr, odebodyinfo_t *bodyinfo, float *mat, wedict_t *ent) +static qboolean QDECL World_ODE_RagCreateBody(world_t *world, rbebody_t *bodyptr, rbebodyinfo_t *bodyinfo, float *mat, wedict_t *ent) { + struct odectx_s *ctx = (struct odectx_s*)world->rbe; dMass mass; float radius; - if (!world->ode.ode_space) - return false; - world->ode.hasodeents = true; //I don't like this, but we need the world etc to be solid. - world->ode.hasextraobjs = true; + ctx->hasextraobjs = true; switch(bodyinfo->geomshape) { case GEOMTYPE_CAPSULE: radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1]) * 0.5; - bodyptr->ode_geom = (void *)dCreateCapsule(world->ode.ode_space, radius, bodyinfo->dimensions[2]); + bodyptr->geom = (void *)dCreateCapsule(ctx->space, radius, bodyinfo->dimensions[2]); dMassSetCapsuleTotal(&mass, bodyinfo->mass, 3, radius, bodyinfo->dimensions[2]); //aligned along the geom's local z axis break; case GEOMTYPE_SPHERE: //radius radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1] + bodyinfo->dimensions[2]) / 3; - bodyptr->ode_geom = dCreateSphere(world->ode.ode_space, radius); + bodyptr->geom = dCreateSphere(ctx->space, radius); dMassSetSphereTotal(&mass, bodyinfo->mass, radius); //aligned along the geom's local z axis break; case GEOMTYPE_CYLINDER: //radius, length radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1]) * 0.5; - bodyptr->ode_geom = dCreateCylinder(world->ode.ode_space, radius, bodyinfo->dimensions[2]); + bodyptr->geom = dCreateCylinder(ctx->space, radius, bodyinfo->dimensions[2]); dMassSetCylinderTotal(&mass, bodyinfo->mass, 3, radius, bodyinfo->dimensions[2]); //alignment is irreleevnt, thouse I suppose it might be scaled wierdly. break; default: case GEOMTYPE_BOX: //diameter - bodyptr->ode_geom = dCreateBox(world->ode.ode_space, bodyinfo->dimensions[0], bodyinfo->dimensions[1], bodyinfo->dimensions[2]); + bodyptr->geom = dCreateBox(ctx->space, bodyinfo->dimensions[0], bodyinfo->dimensions[1], bodyinfo->dimensions[2]); dMassSetBoxTotal(&mass, bodyinfo->mass, bodyinfo->dimensions[0], bodyinfo->dimensions[1], bodyinfo->dimensions[2]); //monkey break; } - bodyptr->ode_body = dBodyCreate(world->ode.ode_world); - dBodySetMass(bodyptr->ode_body, &mass); - dGeomSetBody(bodyptr->ode_geom, bodyptr->ode_body); - dGeomSetData(bodyptr->ode_geom, (void*)ent); + bodyptr->body = dBodyCreate(ctx->dworld); + dBodySetMass(bodyptr->body, &mass); + dGeomSetBody(bodyptr->geom, bodyptr->body); + dGeomSetData(bodyptr->geom, (void*)ent); return World_ODE_RagMatrixToBody(bodyptr, mat); } -void World_ODE_RagMatrixFromJoint(odejoint_t *joint, odejointinfo_t *info, float *mat) +static void QDECL World_ODE_RagMatrixFromJoint(rbejoint_t *joint, rbejointinfo_t *info, float *mat) { dVector3 dr3; switch(info->type) { case JOINTTYPE_POINT: - dJointGetBallAnchor(joint->ode_joint, dr3); + dJointGetBallAnchor(joint->joint, dr3); mat[3] = dr3[0]; mat[7] = dr3[1]; mat[11] = dr3[2]; @@ -1928,12 +1752,12 @@ void World_ODE_RagMatrixFromJoint(odejoint_t *joint, odejointinfo_t *info, float break; case JOINTTYPE_HINGE: - dJointGetHingeAnchor(joint->ode_joint, dr3); + dJointGetHingeAnchor(joint->joint, dr3); mat[3] = dr3[0]; mat[7] = dr3[1]; mat[11] = dr3[2]; - dJointGetHingeAxis(joint->ode_joint, dr3); + dJointGetHingeAxis(joint->joint, dr3); VectorCopy(dr3, mat+4); VectorClear(mat+8); @@ -1941,14 +1765,14 @@ void World_ODE_RagMatrixFromJoint(odejoint_t *joint, odejointinfo_t *info, float return; break; case JOINTTYPE_HINGE2: - dJointGetHinge2Anchor(joint->ode_joint, dr3); + dJointGetHinge2Anchor(joint->joint, dr3); mat[3] = dr3[0]; mat[7] = dr3[1]; mat[11] = dr3[2]; - dJointGetHinge2Axis1(joint->ode_joint, dr3); + dJointGetHinge2Axis1(joint->joint, dr3); VectorCopy(dr3, mat+4); - dJointGetHinge2Axis2(joint->ode_joint, dr3); + dJointGetHinge2Axis2(joint->joint, dr3); VectorCopy(dr3, mat+8); break; @@ -1958,7 +1782,7 @@ void World_ODE_RagMatrixFromJoint(odejoint_t *joint, odejointinfo_t *info, float { const dReal *p1, *p2; dReal n[3]; - dBodyID b1 = dJointGetBody(joint->ode_joint, 0), b2 = dJointGetBody(joint->ode_joint, 1); + dBodyID b1 = dJointGetBody(joint->joint, 0), b2 = dJointGetBody(joint->joint, 1); if (b1) p1 = dBodyGetPosition(b1); else @@ -1970,7 +1794,7 @@ void World_ODE_RagMatrixFromJoint(odejoint_t *joint, odejointinfo_t *info, float p2 = dBodyGetPosition(b2); else p2 = p1; - dJointGetSliderAxis(joint->ode_joint, dr3 + 0); + dJointGetSliderAxis(joint->joint, dr3 + 0); VectorInterpolate(p1, 0.5, p2, dr3); mat[3] = dr3[0]; mat[7] = dr3[1]; @@ -1982,14 +1806,14 @@ void World_ODE_RagMatrixFromJoint(odejoint_t *joint, odejointinfo_t *info, float break; case JOINTTYPE_UNIVERSAL: - dJointGetUniversalAnchor(joint->ode_joint, dr3); + dJointGetUniversalAnchor(joint->joint, dr3); mat[3] = dr3[0]; mat[7] = dr3[1]; mat[11] = dr3[2]; - dJointGetUniversalAxis1(joint->ode_joint, dr3); + dJointGetUniversalAxis1(joint->joint, dr3); VectorCopy(dr3, mat+4); - dJointGetUniversalAxis2(joint->ode_joint, dr3); + dJointGetUniversalAxis2(joint->joint, dr3); VectorCopy(dr3, mat+8); CrossProduct(mat+4, mat+8, mat+0); @@ -1999,10 +1823,10 @@ void World_ODE_RagMatrixFromJoint(odejoint_t *joint, odejointinfo_t *info, float AngleVectorsFLU(vec3_origin, mat+0, mat+4, mat+8); } -void World_ODE_RagMatrixFromBody(world_t *world, odebody_t *bodyptr, float *mat) +static void QDECL World_ODE_RagMatrixFromBody(world_t *world, rbebody_t *bodyptr, float *mat) { - const dReal *o = dBodyGetPosition(bodyptr->ode_body); - const dReal *r = dBodyGetRotation(bodyptr->ode_body); + const dReal *o = dBodyGetPosition(bodyptr->body); + const dReal *r = dBodyGetRotation(bodyptr->body); mat[0] = r[0]; mat[1] = r[1]; mat[2] = r[2]; @@ -2018,129 +1842,131 @@ void World_ODE_RagMatrixFromBody(world_t *world, odebody_t *bodyptr, float *mat) mat[10] = r[10]; mat[11] = o[2]; } -void World_ODE_RagEnableJoint(odejoint_t *joint, qboolean enabled) +static void QDECL World_ODE_RagEnableJoint(rbejoint_t *joint, qboolean enabled) { if (enabled) - dJointEnable(joint->ode_joint); + dJointEnable(joint->joint); else - dJointDisable(joint->ode_joint); + dJointDisable(joint->joint); } -void World_ODE_RagCreateJoint(world_t *world, odejoint_t *joint, odejointinfo_t *info, odebody_t *body1, odebody_t *body2, vec3_t aaa2[3]) +static void QDECL World_ODE_RagCreateJoint(world_t *world, rbejoint_t *joint, rbejointinfo_t *info, rbebody_t *body1, rbebody_t *body2, vec3_t aaa2[3]) { + struct odectx_s *ctx = (struct odectx_s*)world->rbe; switch(info->type) { case JOINTTYPE_POINT: - joint->ode_joint = dJointCreateBall(world->ode.ode_world, 0); + joint->joint = dJointCreateBall(ctx->dworld, 0); break; case JOINTTYPE_HINGE: - joint->ode_joint = dJointCreateHinge(world->ode.ode_world, 0); + joint->joint = dJointCreateHinge(ctx->dworld, 0); break; case JOINTTYPE_SLIDER: - joint->ode_joint = dJointCreateSlider(world->ode.ode_world, 0); + joint->joint = dJointCreateSlider(ctx->dworld, 0); break; case JOINTTYPE_UNIVERSAL: - joint->ode_joint = dJointCreateUniversal(world->ode.ode_world, 0); + joint->joint = dJointCreateUniversal(ctx->dworld, 0); break; case JOINTTYPE_HINGE2: - joint->ode_joint = dJointCreateHinge2(world->ode.ode_world, 0); + joint->joint = dJointCreateHinge2(ctx->dworld, 0); break; case JOINTTYPE_FIXED: - joint->ode_joint = dJointCreateFixed(world->ode.ode_world, 0); + joint->joint = dJointCreateFixed(ctx->dworld, 0); break; default: - joint->ode_joint = NULL; + joint->joint = NULL; break; } - if (joint->ode_joint) + if (joint->joint) { //Con_Printf("made new joint %i\n", (int) (ed - prog->edicts)); // dJointSetData(joint->ode_joint, NULL); - dJointAttach(joint->ode_joint, body1?body1->ode_body:NULL, body2?body2->ode_body:NULL); + dJointAttach(joint->joint, body1?body1->body:NULL, body2?body2->body:NULL); switch(info->type) { case JOINTTYPE_POINT: - dJointSetBallAnchor(joint->ode_joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]); + dJointSetBallAnchor(joint->joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]); break; case JOINTTYPE_HINGE: - dJointSetHingeAnchor(joint->ode_joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]); - dJointSetHingeAxis(joint->ode_joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]); - dJointSetHingeParam(joint->ode_joint, dParamFMax, info->FMax); - dJointSetHingeParam(joint->ode_joint, dParamHiStop, info->HiStop); - dJointSetHingeParam(joint->ode_joint, dParamLoStop, info->LoStop); - dJointSetHingeParam(joint->ode_joint, dParamStopCFM, info->CFM); - dJointSetHingeParam(joint->ode_joint, dParamStopERP, info->ERP); - dJointSetHingeParam(joint->ode_joint, dParamVel, info->Vel); + dJointSetHingeAnchor(joint->joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]); + dJointSetHingeAxis(joint->joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]); + dJointSetHingeParam(joint->joint, dParamFMax, info->FMax); + dJointSetHingeParam(joint->joint, dParamHiStop, info->HiStop); + dJointSetHingeParam(joint->joint, dParamLoStop, info->LoStop); + dJointSetHingeParam(joint->joint, dParamStopCFM, info->CFM); + dJointSetHingeParam(joint->joint, dParamStopERP, info->ERP); + dJointSetHingeParam(joint->joint, dParamVel, info->Vel); break; case JOINTTYPE_SLIDER: - dJointSetSliderAxis(joint->ode_joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]); - dJointSetSliderParam(joint->ode_joint, dParamFMax, info->FMax); - dJointSetSliderParam(joint->ode_joint, dParamHiStop, info->HiStop); - dJointSetSliderParam(joint->ode_joint, dParamLoStop, info->LoStop); - dJointSetSliderParam(joint->ode_joint, dParamStopCFM, info->CFM); - dJointSetSliderParam(joint->ode_joint, dParamStopERP, info->ERP); - dJointSetSliderParam(joint->ode_joint, dParamVel, info->Vel); + dJointSetSliderAxis(joint->joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]); + dJointSetSliderParam(joint->joint, dParamFMax, info->FMax); + dJointSetSliderParam(joint->joint, dParamHiStop, info->HiStop); + dJointSetSliderParam(joint->joint, dParamLoStop, info->LoStop); + dJointSetSliderParam(joint->joint, dParamStopCFM, info->CFM); + dJointSetSliderParam(joint->joint, dParamStopERP, info->ERP); + dJointSetSliderParam(joint->joint, dParamVel, info->Vel); break; case JOINTTYPE_UNIVERSAL: - dJointSetUniversalAnchor(joint->ode_joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]); - dJointSetUniversalAxis1(joint->ode_joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]); - dJointSetUniversalAxis2(joint->ode_joint, aaa2[2][0], aaa2[2][1], aaa2[2][2]); - dJointSetUniversalParam(joint->ode_joint, dParamFMax, info->FMax); - dJointSetUniversalParam(joint->ode_joint, dParamHiStop, info->HiStop); - dJointSetUniversalParam(joint->ode_joint, dParamLoStop, info->LoStop); - dJointSetUniversalParam(joint->ode_joint, dParamStopCFM, info->CFM); - dJointSetUniversalParam(joint->ode_joint, dParamStopERP, info->ERP); - dJointSetUniversalParam(joint->ode_joint, dParamVel, info->Vel); - dJointSetUniversalParam(joint->ode_joint, dParamFMax2, info->FMax2); - dJointSetUniversalParam(joint->ode_joint, dParamHiStop2, info->HiStop2); - dJointSetUniversalParam(joint->ode_joint, dParamLoStop2, info->LoStop2); - dJointSetUniversalParam(joint->ode_joint, dParamStopCFM2, info->CFM2); - dJointSetUniversalParam(joint->ode_joint, dParamStopERP2, info->ERP2); - dJointSetUniversalParam(joint->ode_joint, dParamVel2, info->Vel2); + dJointSetUniversalAnchor(joint->joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]); + dJointSetUniversalAxis1(joint->joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]); + dJointSetUniversalAxis2(joint->joint, aaa2[2][0], aaa2[2][1], aaa2[2][2]); + dJointSetUniversalParam(joint->joint, dParamFMax, info->FMax); + dJointSetUniversalParam(joint->joint, dParamHiStop, info->HiStop); + dJointSetUniversalParam(joint->joint, dParamLoStop, info->LoStop); + dJointSetUniversalParam(joint->joint, dParamStopCFM, info->CFM); + dJointSetUniversalParam(joint->joint, dParamStopERP, info->ERP); + dJointSetUniversalParam(joint->joint, dParamVel, info->Vel); + dJointSetUniversalParam(joint->joint, dParamFMax2, info->FMax2); + dJointSetUniversalParam(joint->joint, dParamHiStop2, info->HiStop2); + dJointSetUniversalParam(joint->joint, dParamLoStop2, info->LoStop2); + dJointSetUniversalParam(joint->joint, dParamStopCFM2, info->CFM2); + dJointSetUniversalParam(joint->joint, dParamStopERP2, info->ERP2); + dJointSetUniversalParam(joint->joint, dParamVel2, info->Vel2); break; case JOINTTYPE_HINGE2: - dJointSetHinge2Anchor(joint->ode_joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]); - dJointSetHinge2Axis1(joint->ode_joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]); - dJointSetHinge2Axis2(joint->ode_joint, aaa2[2][0], aaa2[2][1], aaa2[2][2]); - dJointSetHinge2Param(joint->ode_joint, dParamFMax, info->FMax); - dJointSetHinge2Param(joint->ode_joint, dParamHiStop, info->HiStop); - dJointSetHinge2Param(joint->ode_joint, dParamLoStop, info->LoStop); - dJointSetHinge2Param(joint->ode_joint, dParamStopCFM, info->CFM); - dJointSetHinge2Param(joint->ode_joint, dParamStopERP, info->ERP); - dJointSetHinge2Param(joint->ode_joint, dParamVel, info->Vel); - dJointSetHinge2Param(joint->ode_joint, dParamFMax2, info->FMax2); - dJointSetHinge2Param(joint->ode_joint, dParamHiStop2, info->HiStop2); - dJointSetHinge2Param(joint->ode_joint, dParamLoStop2, info->LoStop2); - dJointSetHinge2Param(joint->ode_joint, dParamStopCFM2, info->CFM2); - dJointSetHinge2Param(joint->ode_joint, dParamStopERP2, info->ERP2); - dJointSetHinge2Param(joint->ode_joint, dParamVel2, info->Vel2); + dJointSetHinge2Anchor(joint->joint, aaa2[0][0], aaa2[0][1], aaa2[0][2]); + dJointSetHinge2Axis1(joint->joint, aaa2[1][0], aaa2[1][1], aaa2[1][2]); + dJointSetHinge2Axis2(joint->joint, aaa2[2][0], aaa2[2][1], aaa2[2][2]); + dJointSetHinge2Param(joint->joint, dParamFMax, info->FMax); + dJointSetHinge2Param(joint->joint, dParamHiStop, info->HiStop); + dJointSetHinge2Param(joint->joint, dParamLoStop, info->LoStop); + dJointSetHinge2Param(joint->joint, dParamStopCFM, info->CFM); + dJointSetHinge2Param(joint->joint, dParamStopERP, info->ERP); + dJointSetHinge2Param(joint->joint, dParamVel, info->Vel); + dJointSetHinge2Param(joint->joint, dParamFMax2, info->FMax2); + dJointSetHinge2Param(joint->joint, dParamHiStop2, info->HiStop2); + dJointSetHinge2Param(joint->joint, dParamLoStop2, info->LoStop2); + dJointSetHinge2Param(joint->joint, dParamStopCFM2, info->CFM2); + dJointSetHinge2Param(joint->joint, dParamStopERP2, info->ERP2); + dJointSetHinge2Param(joint->joint, dParamVel2, info->Vel2); break; case JOINTTYPE_FIXED: - dJointSetFixed(joint->ode_joint); + dJointSetFixed(joint->joint); break; } } } -void World_ODE_RagDestroyBody(world_t *world, odebody_t *bodyptr) +static void QDECL World_ODE_RagDestroyBody(world_t *world, rbebody_t *bodyptr) { - if (bodyptr->ode_geom) - dGeomDestroy(bodyptr->ode_geom); - bodyptr->ode_geom = NULL; - if (bodyptr->ode_body) - dBodyDestroy(bodyptr->ode_body); - bodyptr->ode_body = NULL; + if (bodyptr->geom) + dGeomDestroy(bodyptr->geom); + bodyptr->geom = NULL; + if (bodyptr->body) + dBodyDestroy(bodyptr->body); + bodyptr->body = NULL; } -void World_ODE_RagDestroyJoint(world_t *world, odejoint_t *joint) +static void QDECL World_ODE_RagDestroyJoint(world_t *world, rbejoint_t *joint) { - if (joint->ode_joint) - dJointDestroy(joint->ode_joint); - joint->ode_joint = NULL; + if (joint->joint) + dJointDestroy(joint->joint); + joint->joint = NULL; } static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) { + struct odectx_s *ctx = (struct odectx_s*)world->rbe; dBodyID body = (dBodyID)ed->ode.ode_body; dMass mass; float test; @@ -2288,7 +2114,7 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) World_ODE_RemoveFromEntity(world, ed); return; } - if (!GenerateCollisionMesh(world, model, ed, geomcenter)) + if (!modfuncs->GenerateCollisionMesh(world, model, ed, geomcenter)) { if (ed->ode.ode_physics) World_ODE_RemoveFromEntity(world, ed); @@ -2299,17 +2125,17 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) // now create the geom dataID = dGeomTriMeshDataCreate(); dGeomTriMeshDataBuildSingle(dataID, (void*)ed->ode.ode_vertex3f, sizeof(float[3]), ed->ode.ode_numvertices, ed->ode.ode_element3i, ed->ode.ode_numtriangles*3, sizeof(int[3])); - ed->ode.ode_geom = (void *)dCreateTriMesh(world->ode.ode_space, dataID, NULL, NULL, NULL); + ed->ode.ode_geom = (void *)dCreateTriMesh(ctx->space, dataID, NULL, NULL, NULL); dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]); break; case GEOMTYPE_BOX: Matrix4x4_RM_CreateTranslate(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]); - ed->ode.ode_geom = (void *)dCreateBox(world->ode.ode_space, geomsize[0], geomsize[1], geomsize[2]); + ed->ode.ode_geom = (void *)dCreateBox(ctx->space, geomsize[0], geomsize[1], geomsize[2]); dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]); break; case GEOMTYPE_SPHERE: Matrix4x4_RM_CreateTranslate(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]); - ed->ode.ode_geom = (void *)dCreateSphere(world->ode.ode_space, geomsize[0] * 0.5f); + ed->ode.ode_geom = (void *)dCreateSphere(ctx->space, geomsize[0] * 0.5f); dMassSetSphereTotal(&mass, massval, geomsize[0] * 0.5f); break; case GEOMTYPE_CAPSULE: @@ -2354,7 +2180,7 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) // because we want to support more than one axisindex, we have to // create a transform, and turn on its cleanup setting (which will // cause the child to be destroyed when it is destroyed) - ed->ode.ode_geom = (void *)dCreateCapsule(world->ode.ode_space, radius, length); + ed->ode.ode_geom = (void *)dCreateCapsule(ctx->space, radius, length); dMassSetCapsuleTotal(&mass, massval, axisindex+1, radius, length); break; case GEOMTYPE_CYLINDER: @@ -2399,11 +2225,11 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) // because we want to support more than one axisindex, we have to // create a transform, and turn on its cleanup setting (which will // cause the child to be destroyed when it is destroyed) - ed->ode.ode_geom = (void *)dCreateCylinder(world->ode.ode_space, radius, length); + ed->ode.ode_geom = (void *)dCreateCylinder(ctx->space, radius, length); dMassSetCylinderTotal(&mass, massval, axisindex+1, radius, length); break; default: - Sys_Error("World_ODE_BodyFromEntity: unrecognized solid value %i was accepted by filter\n", solid); + pSys_Error(va("World_ODE_BodyFromEntity: unrecognized solid value %i was accepted by filter\n", solid)); } Matrix3x4_InvertTo4x4_Simple(ed->ode.ode_offsetmatrix, ed->ode.ode_offsetimatrix); ed->ode.ode_massbuf = BZ_Malloc(sizeof(dMass)); @@ -2416,7 +2242,7 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) { if (ed->ode.ode_body == NULL) { - ed->ode.ode_body = (void *)(body = dBodyCreate(world->ode.ode_world)); + ed->ode.ode_body = (void *)(body = dBodyCreate(ctx->dworld)); dGeomSetBody(ed->ode.ode_geom, body); dBodySetData(body, (void*)ed); dBodySetMass(body, (dMass *) ed->ode.ode_massbuf); @@ -2599,7 +2425,7 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) // limit movement speed to prevent missed collisions at high speed const dReal *ovelocity = dBodyGetLinearVel(body); const dReal *ospinvelocity = dBodyGetAngularVel(body); - movelimit = ed->ode.ode_movelimit * world->ode.ode_movelimit; + movelimit = ctx->movelimit * ctx->movelimit; test = DotProduct(ovelocity,ovelocity); if (test > movelimit*movelimit) { @@ -2613,7 +2439,7 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) } // make sure the angular velocity is not exploding - spinlimit = physics_ode_spinlimit.value; + spinlimit = physics_ode_spinlimit->value; test = DotProduct(ospinvelocity,ospinvelocity); if (test > spinlimit) { @@ -2626,6 +2452,7 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) static void VARGS nearCallback (void *data, dGeomID o1, dGeomID o2) { world_t *world = (world_t *)data; + struct odectx_s *ctx = (struct odectx_s*)world->rbe; dContact contact[MAX_CONTACTS]; // max contacts per collision pair dBodyID b1; dBodyID b2; @@ -2734,7 +2561,7 @@ static void VARGS nearCallback (void *data, dGeomID o1, dGeomID o2) bouncefactor1 = bouncefactor2; } } - dWorldGetGravity(world->ode.ode_world, grav); + dWorldGetGravity(ctx->dworld, grav); bouncestop1 *= fabs(grav[2]); erp = (DotProduct(ed1->v->velocity, ed1->v->velocity) > DotProduct(ed2->v->velocity, ed2->v->velocity)) ? ed1->xv->erp : ed2->xv->erp; @@ -2742,37 +2569,38 @@ static void VARGS nearCallback (void *data, dGeomID o1, dGeomID o2) // add these contact points to the simulation for (i = 0;i < numcontacts;i++) { - contact[i].surface.mode = (physics_ode_contact_mu.value != -1 ? dContactApprox1 : 0) | - (physics_ode_contact_erp.value != -1 ? dContactSoftERP : 0) | - (physics_ode_contact_cfm.value != -1 ? dContactSoftCFM : 0) | + contact[i].surface.mode = (physics_ode_contact_mu->value != -1 ? dContactApprox1 : 0) | + (physics_ode_contact_erp->value != -1 ? dContactSoftERP : 0) | + (physics_ode_contact_cfm->value != -1 ? dContactSoftCFM : 0) | (bouncefactor1 > 0 ? dContactBounce : 0); - contact[i].surface.mu = physics_ode_contact_mu.value; + contact[i].surface.mu = physics_ode_contact_mu->value; if (ed1->xv->friction) contact[i].surface.mu *= ed1->xv->friction; if (ed2->xv->friction) contact[i].surface.mu *= ed2->xv->friction; contact[i].surface.mu2 = 0; - contact[i].surface.soft_erp = physics_ode_contact_erp.value + erp; - contact[i].surface.soft_cfm = physics_ode_contact_cfm.value; + contact[i].surface.soft_erp = physics_ode_contact_erp->value + erp; + contact[i].surface.soft_cfm = physics_ode_contact_cfm->value; contact[i].surface.bounce = bouncefactor1; contact[i].surface.bounce_vel = bouncestop1; - c = dJointCreateContact(world->ode.ode_world, world->ode.ode_contactgroup, contact + i); + c = dJointCreateContact(ctx->dworld, ctx->contactgroup, contact + i); dJointAttach(c, b1, b2); } } -void World_ODE_Frame(world_t *world, double frametime, double gravity) +static void QDECL World_ODE_Frame(world_t *world, double frametime, double gravity) { - if (world->ode.ode && (world->ode.hasodeents || world->ode.hasextraobjs)) + struct odectx_s *ctx = (struct odectx_s*)world->rbe; + if (world->rbe_hasphysicsents || ctx->hasextraobjs) { int i; wedict_t *ed; - world->ode.ode_iterations = bound(1, physics_ode_iterationsperframe.ival, 1000); - world->ode.ode_step = frametime / world->ode.ode_iterations; - world->ode.ode_movelimit = physics_ode_movelimit.value / world->ode.ode_step; + ctx->iterations = bound(1, physics_ode_iterationsperframe->ival, 1000); + ctx->step = frametime / ctx->iterations; + ctx->movelimit = physics_ode_movelimit->value / ctx->step; - if (world->ode.hasodeents || world->ode.hasextraobjs) + if (world->rbe_hasphysicsents || ctx->hasextraobjs) { // copy physics properties from entities to physics engine for (i = 0;i < world->num_edicts;i++) @@ -2788,47 +2616,41 @@ void World_ODE_Frame(world_t *world, double frametime, double gravity) if (!ed->isfree) World_ODE_Frame_JointFromEntity(world, ed); } - while(world->ode.cmdqueuehead) + while(ctx->cmdqueuehead) { - odecommandqueue_t *cmd = world->ode.cmdqueuehead; - world->ode.cmdqueuehead = cmd->next; + rbecommandqueue_t *cmd = ctx->cmdqueuehead; + ctx->cmdqueuehead = cmd->next; if (!cmd->next) - world->ode.cmdqueuetail = NULL; + ctx->cmdqueuetail = NULL; World_ODE_RunCmd(world, cmd); Z_Free(cmd); } } - for (i = 0;i < world->ode.ode_iterations;i++) + for (i = 0;i < ctx->iterations;i++) { - if (world->ode.hasextraobjs) - { -#ifdef RAGDOLL - rag_doallanimations(world); -#endif - } // set the gravity - dWorldSetGravity(world->ode.ode_world, 0, 0, -gravity); + dWorldSetGravity(ctx->dworld, 0, 0, -gravity); // set the tolerance for closeness of objects - dWorldSetContactSurfaceLayer(world->ode.ode_world, max(0, physics_ode_contactsurfacelayer.value)); + dWorldSetContactSurfaceLayer(ctx->dworld, max(0, physics_ode_contactsurfacelayer->value)); // run collisions for the current world state, creating JointGroup - dSpaceCollide(world->ode.ode_space, (void *)world, nearCallback); + dSpaceCollide(ctx->space, (void *)world, nearCallback); // run physics (move objects, calculate new velocities) - if (physics_ode_worldquickstep.ival) + if (physics_ode_worldquickstep->ival) { - dWorldSetQuickStepNumIterations(world->ode.ode_world, bound(1, physics_ode_worldquickstep_iterations.ival, 200)); - dWorldQuickStep(world->ode.ode_world, world->ode.ode_step); + dWorldSetQuickStepNumIterations(ctx->dworld, bound(1, physics_ode_worldquickstep_iterations->ival, 200)); + dWorldQuickStep(ctx->dworld, ctx->step); } else - dWorldStep(world->ode.ode_world, world->ode.ode_step); + dWorldStep(ctx->dworld, ctx->step); // clear the JointGroup now that we're done with it - dJointGroupEmpty(world->ode.ode_contactgroup); + dJointGroupEmpty(ctx->contactgroup); } - if (world->ode.hasodeents) + if (world->rbe_hasphysicsents) { // copy physics properties from physics engine to entities for (i = 1;i < world->num_edicts;i++) @@ -2841,26 +2663,111 @@ void World_ODE_Frame(world_t *world, double frametime, double gravity) } } -static void World_ODE_RunCmd(world_t *world, odecommandqueue_t *cmd) +static void QDECL World_ODE_PushCommand(world_t *world, rbecommandqueue_t *val) +{ + struct odectx_s *ctx = (struct odectx_s*)world->rbe; + rbecommandqueue_t *cmd = (rbecommandqueue_t*)BZ_Malloc(sizeof(*cmd)); + world->rbe_hasphysicsents = qtrue; //just in case. + memcpy(cmd, val, sizeof(*cmd)); + cmd->next = NULL; + //add on the end of the queue, so that order is preserved. + if (ctx->cmdqueuehead) + { + rbecommandqueue_t *ot = ctx->cmdqueuetail; + ot->next = ctx->cmdqueuetail = cmd; + } + else + ctx->cmdqueuetail = ctx->cmdqueuehead = cmd; +} + +static void QDECL World_ODE_Start(world_t *world) +{ + struct odectx_s *ctx; + dVector3 center, extents; + if (world->rbe) + return; + +#ifdef ODE_DYNAMIC + if (!ode_dll) + return; +#endif + + ctx = BZ_Malloc(sizeof(*ctx)); + memset(ctx, 0, sizeof(*ctx)); + world->rbe = &ctx->pub; + + VectorAvg(world->worldmodel->mins, world->worldmodel->maxs, center); + VectorSubtract(world->worldmodel->maxs, center, extents); + ctx->dworld = dWorldCreate(); + ctx->space = dQuadTreeSpaceCreate(NULL, center, extents, bound(1, pCvar_GetFloat("physics_ode_quadtree_depth"), 10)); + ctx->contactgroup = dJointGroupCreate(0); + + ctx->pub.End = World_ODE_End; + ctx->pub.RemoveJointFromEntity = World_ODE_RemoveJointFromEntity; + ctx->pub.RemoveFromEntity = World_ODE_RemoveFromEntity; + ctx->pub.RagMatrixToBody = World_ODE_RagMatrixToBody; + ctx->pub.RagCreateBody = World_ODE_RagCreateBody; + ctx->pub.RagMatrixFromJoint = World_ODE_RagMatrixFromJoint; + ctx->pub.RagMatrixFromBody = World_ODE_RagMatrixFromBody; + ctx->pub.RagEnableJoint = World_ODE_RagEnableJoint; + ctx->pub.RagCreateJoint = World_ODE_RagCreateJoint; + ctx->pub.RagDestroyBody = World_ODE_RagDestroyBody; + ctx->pub.RagDestroyJoint = World_ODE_RagDestroyJoint; + ctx->pub.Frame = World_ODE_Frame; + ctx->pub.PushCommand = World_ODE_PushCommand; + + if(physics_ode_world_erp->value >= 0) + dWorldSetERP(ctx->dworld, physics_ode_world_erp->value); + if(physics_ode_world_cfm->value >= 0) + dWorldSetCFM(ctx->dworld, physics_ode_world_cfm->value); + if (physics_ode_world_damping->value) + { + dWorldSetLinearDamping(ctx->dworld, (physics_ode_world_damping_linear->value >= 0) ? (physics_ode_world_damping_linear->value * physics_ode_world_damping->value) : 0); + dWorldSetLinearDampingThreshold(ctx->dworld, (physics_ode_world_damping_linear_threshold->value >= 0) ? (physics_ode_world_damping_linear_threshold->value * physics_ode_world_damping->value) : 0); + dWorldSetAngularDamping(ctx->dworld, (physics_ode_world_damping_angular->value >= 0) ? (physics_ode_world_damping_angular->value * physics_ode_world_damping->value) : 0); + dWorldSetAngularDampingThreshold(ctx->dworld, (physics_ode_world_damping_angular_threshold->value >= 0) ? (physics_ode_world_damping_angular_threshold->value * physics_ode_world_damping->value) : 0); + } + else + { + dWorldSetLinearDamping(ctx->dworld, 0); + dWorldSetLinearDampingThreshold(ctx->dworld, 0); + dWorldSetAngularDamping(ctx->dworld, 0); + dWorldSetAngularDampingThreshold(ctx->dworld, 0); + } + if (physics_ode_autodisable->ival) + { + dWorldSetAutoDisableSteps(ctx->dworld, bound(1, physics_ode_autodisable_steps->ival, 100)); + dWorldSetAutoDisableTime(ctx->dworld, physics_ode_autodisable_time->value); + dWorldSetAutoDisableAverageSamplesCount(ctx->dworld, bound(1, physics_ode_autodisable_threshold_samples->ival, 100)); + dWorldSetAutoDisableLinearThreshold(ctx->dworld, physics_ode_autodisable_threshold_linear->value); + dWorldSetAutoDisableAngularThreshold(ctx->dworld, physics_ode_autodisable_threshold_angular->value); + dWorldSetAutoDisableFlag (ctx->dworld, true); + } + else + dWorldSetAutoDisableFlag (ctx->dworld, false); +} + + +static void World_ODE_RunCmd(world_t *world, rbecommandqueue_t *cmd) { switch(cmd->command) { - case ODECMD_ENABLE: + case RBECMD_ENABLE: if (cmd->edict->ode.ode_body) dBodyEnable(cmd->edict->ode.ode_body); break; - case ODECMD_DISABLE: + case RBECMD_DISABLE: if (cmd->edict->ode.ode_body) dBodyDisable(cmd->edict->ode.ode_body); break; - case ODECMD_FORCE: + case RBECMD_FORCE: if (cmd->edict->ode.ode_body) { dBodyEnable(cmd->edict->ode.ode_body); dBodyAddForceAtPos(cmd->edict->ode.ode_body, cmd->v1[0], cmd->v1[1], cmd->v1[2], cmd->v2[0], cmd->v2[1], cmd->v2[2]); } break; - case ODECMD_TORQUE: + case RBECMD_TORQUE: if (cmd->edict->ode.ode_body) { dBodyEnable(cmd->edict->ode.ode_body); @@ -2870,55 +2777,53 @@ static void World_ODE_RunCmd(world_t *world, odecommandqueue_t *cmd) } } -static odecommandqueue_t *physics_queuecommand(world_t *world) +static qintptr_t QDECL Plug_ODE_Shutdown(qintptr_t *args) { - odecommandqueue_t *cmd = Z_Malloc(sizeof(*cmd)); - world->ode.hasodeents = true; //just in case. - - //add on the end of the queue, so that order is preserved. - if (world->ode.cmdqueuehead) - { - odecommandqueue_t *ot = world->ode.cmdqueuetail; - ot->next = world->ode.cmdqueuetail = cmd; - } - else - world->ode.cmdqueuetail = world->ode.cmdqueuehead = cmd; - return cmd; + World_ODE_Shutdown(); + if (modfuncs) + modfuncs->UnregisterPhysicsEngine("ODE"); + return 0; } -void QCBUILTIN PF_physics_enable(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +qintptr_t Plug_Init(qintptr_t *args) { - wedict_t*e = G_WEDICT(prinst, OFS_PARM0); - int isenable = G_FLOAT(OFS_PARM1); - world_t *world = prinst->parms->user; - odecommandqueue_t *cmd = physics_queuecommand(world); - - cmd->command = isenable?ODECMD_ENABLE:ODECMD_DISABLE; - cmd->edict = e; -} -void QCBUILTIN PF_physics_addforce(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) -{ - wedict_t*e = G_WEDICT(prinst, OFS_PARM0); - float *force = G_VECTOR(OFS_PARM1); - float *relative_ofs = G_VECTOR(OFS_PARM2); - world_t *world = prinst->parms->user; - odecommandqueue_t *cmd = physics_queuecommand(world); - - cmd->command = ODECMD_FORCE; - cmd->edict = e; - VectorCopy(force, cmd->v1); - VectorCopy(relative_ofs, cmd->v2); -} -void QCBUILTIN PF_physics_addtorque(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) -{ - wedict_t*e = G_WEDICT(prinst, OFS_PARM0); - float *torque = G_VECTOR(OFS_PARM1); - world_t *world = prinst->parms->user; - odecommandqueue_t *cmd = physics_queuecommand(world); - - cmd->command = ODECMD_TORQUE; - cmd->edict = e; - VectorCopy(torque, cmd->v1); -} - + CHECKBUILTIN(Mod_GetPluginModelFuncs); + CHECKBUILTIN(Cvar_GetNVFDG); +#ifndef ODE_STATIC + CHECKBUILTIN(Sys_LoadLibrary); + CHECKBUILTIN(Sys_CloseLibrary); #endif + + if (BUILTINISVALID(Mod_GetPluginModelFuncs)) + { + modfuncs = pMod_GetPluginModelFuncs(sizeof(modplugfuncs_t)); + if (modfuncs && modfuncs->version < MODPLUGFUNCS_VERSION) + modfuncs = NULL; + } + if (!modfuncs || !BUILTINISVALID(Cvar_GetNVFDG)) + { + Con_Printf("ODE plugin failed: Engine too old.\n"); + return false; + } +#ifndef ODE_STATIC + if (!BUILTINISVALID(Sys_LoadLibrary) || !BUILTINISVALID(Sys_CloseLibrary)) + { + Con_Printf("ODE plugin failed: Engine too old.\n"); + return false; + } +#endif + + if (!modfuncs || !modfuncs->RegisterPhysicsEngine) + Con_Printf("ODE plugin failed: Engine doesn't support physics engine plugins.\n"); + else if (!modfuncs->RegisterPhysicsEngine("ODE", World_ODE_Start)) + Con_Printf("ODE plugin failed: Engine already has a physics plugin active.\n"); + else + { + Plug_Export("Shutdown", Plug_ODE_Shutdown); + World_ODE_Init(); + return true; + } + return false; +} +#endif + diff --git a/engine/common/common.c b/engine/common/common.c index 6892464cf..d4f81a620 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -4592,13 +4592,6 @@ void COM_Version_f (void) #endif Con_Printf("Misc:"); -#ifdef ODE_STATIC - Con_Printf(" ODE(static)"); -#elif defined(USEODE) - Con_Printf(" ODE(dynamic)"); -#else - Con_Printf(" ^h(disabled: ODE)^7"); -#endif #ifdef SUBSERVERS Con_Printf(" mapcluster(enabled)"); #else diff --git a/engine/common/common.h b/engine/common/common.h index b38559ce2..cc01a767a 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -527,7 +527,7 @@ qbyte *COM_LoadFile (const char *path, int usehunk, size_t *filesize); qboolean COM_LoadMapPackFile(const char *name, qofs_t offset); void COM_FlushTempoaryPacks(void); -void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm); +void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm); extern struct cvar_s registered; extern qboolean standard_quake; //fixme: remove diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 148219a99..d2c544f96 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -1133,7 +1133,7 @@ qboolean Cvar_Register (cvar_t *variable, const char *groupname) return true; } -cvar_t *Cvar_Get(const char *name, const char *defaultvalue, int flags, const char *group) +cvar_t *Cvar_Get2(const char *name, const char *defaultvalue, int flags, const char *description, const char *group) { cvar_t *var; int old; @@ -1151,12 +1151,19 @@ cvar_t *Cvar_Get(const char *name, const char *defaultvalue, int flags, const ch } return var; } + if (!description) + description = ""; - var = (cvar_t*)Z_Malloc(sizeof(cvar_t)+strlen(name)+1); + var = (cvar_t*)Z_Malloc(sizeof(cvar_t)+strlen(name)+1+(description?(strlen(description)+1):0)); var->name = (char *)(var+1); strcpy(var->name, name); var->string = (char*)defaultvalue; var->flags = flags|CVAR_POINTER|CVAR_USERCREATED; + if (description) + { + var->description = var->name+strlen(var->name)+1; + strcpy(var->description, description); + } if (!Cvar_Register(var, group)) return NULL; diff --git a/engine/common/cvar.h b/engine/common/cvar.h index 1ab6c4c4b..520a45f88 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -149,7 +149,8 @@ typedef struct cvar_group_s //an alias #define CVAR_SAVE CVAR_ARCHIVE -cvar_t *Cvar_Get (const char *var_name, const char *value, int flags, const char *groupname); +cvar_t *Cvar_Get2 (const char *var_name, const char *value, int flags, const char *description, const char *groupname); +#define Cvar_Get(n,v,f,g) Cvar_Get2(n,v,f,NULL,g) void Cvar_LockFromServer(cvar_t *var, const char *str); diff --git a/engine/common/fs.c b/engine/common/fs.c index f12c038a8..0a43ace2b 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -593,7 +593,7 @@ COM_Dir_f ============ */ -static int QDECL COM_Dir_List(const char *name, qofs_t size, void *parm, searchpathfuncs_t *spath) +static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void *parm, searchpathfuncs_t *spath) { searchpath_t *s; for (s=com_searchpaths ; s ; s=s->next) @@ -1757,7 +1757,7 @@ void FS_FreeFile(void *file) -void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *, qofs_t, void *, searchpathfuncs_t*), void *parm) +void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t*), void *parm) { searchpath_t *search; for (search = com_searchpaths; search ; search = search->next) @@ -1828,7 +1828,7 @@ typedef struct { const char *puredesc; } wildpaks_t; -static int QDECL FS_AddWildDataFiles (const char *descriptor, qofs_t size, void *vparam, searchpathfuncs_t *funcs) +static int QDECL FS_AddWildDataFiles (const char *descriptor, qofs_t size, time_t mtime, void *vparam, searchpathfuncs_t *funcs) { wildpaks_t *param = vparam; vfsfile_t *vfs; @@ -4025,7 +4025,7 @@ typedef struct qboolean (*callback)(void *usr, ftemanifest_t *man); void *usr; } fmfenums_t; -static int QDECL FS_EnumerateFMFs(const char *fname, qofs_t fsize, void *inf, searchpathfuncs_t *spath) +static int QDECL FS_EnumerateFMFs(const char *fname, qofs_t fsize, time_t mtime, void *inf, searchpathfuncs_t *spath) { fmfenums_t *e = inf; vfsfile_t *f = NULL; diff --git a/engine/common/fs.h b/engine/common/fs.h index 15e921e86..c48576b00 100644 --- a/engine/common/fs.h +++ b/engine/common/fs.h @@ -39,7 +39,7 @@ struct searchpathfuncs_s //note that if rawfile and offset are set, many Com_FileOpens will read the raw file //otherwise ReadFile will be called instead. void (QDECL *ReadFile)(searchpathfuncs_t *handle, flocation_t *loc, char *buffer); //reads the entire file in one go (size comes from loc, so make sure the loc is valid, this is for performance with compressed archives) - int (QDECL *EnumerateFiles)(searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm); + int (QDECL *EnumerateFiles)(searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm); int (QDECL *GeneratePureCRC) (searchpathfuncs_t *handle, int seed, int usepure); diff --git a/engine/common/fs_pak.c b/engine/common/fs_pak.c index f8dd395eb..78093e3f0 100644 --- a/engine/common/fs_pak.c +++ b/engine/common/fs_pak.c @@ -133,7 +133,7 @@ static unsigned int QDECL FSPAK_FLocate(searchpathfuncs_t *handle, flocation_t * } return FF_NOTFOUND; } -static int QDECL FSPAK_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, void *, searchpathfuncs_t *spath), void *parm) +static int QDECL FSPAK_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *spath), void *parm) { pack_t *pak = (pack_t*)handle; int num; @@ -142,7 +142,8 @@ static int QDECL FSPAK_EnumerateFiles (searchpathfuncs_t *handle, const char *ma { if (wildcmp(match, pak->files[num].name)) { - if (!func(pak->files[num].name, pak->files[num].filelen, parm, handle)) + //FIXME: time 0? maybe use the pak's mtime? + if (!func(pak->files[num].name, pak->files[num].filelen, 0, parm, handle)) return false; } } diff --git a/engine/common/fs_stdio.c b/engine/common/fs_stdio.c index 0e12b5205..0de99e4b0 100644 --- a/engine/common/fs_stdio.c +++ b/engine/common/fs_stdio.c @@ -224,7 +224,7 @@ static qboolean QDECL FSSTDIO_PollChanges(searchpathfuncs_t *handle) // stdiopath_t *np = handle; return true; //can't verify that or not, so we have to assume the worst } -static int QDECL FSSTDIO_RebuildFSHash(const char *filename, qofs_t filesize, void *data, searchpathfuncs_t *spath) +static int QDECL FSSTDIO_RebuildFSHash(const char *filename, qofs_t filesize, time_t mtime, void *data, searchpathfuncs_t *spath) { stdiopath_t *sp = (void*)spath; void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle) = data; @@ -310,7 +310,7 @@ static void QDECL FSSTDIO_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, fclose(f); } -static int QDECL FSSTDIO_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, void *, searchpathfuncs_t *spath), void *parm) +static int QDECL FSSTDIO_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *spath), void *parm) { stdiopath_t *sp = (stdiopath_t*)handle; return Sys_EnumerateFiles(sp->rootpath, match, func, parm, handle); diff --git a/engine/common/fs_win32.c b/engine/common/fs_win32.c index 1ef7a4bf2..49015c6de 100644 --- a/engine/common/fs_win32.c +++ b/engine/common/fs_win32.c @@ -351,7 +351,7 @@ static qboolean QDECL VFSW32_PollChanges(searchpathfuncs_t *handle) } return result; } -static int QDECL VFSW32_RebuildFSHash(const char *filename, qofs_t filesize, void *handle, searchpathfuncs_t *spath) +static int QDECL VFSW32_RebuildFSHash(const char *filename, qofs_t filesize, time_t mtime, void *handle, searchpathfuncs_t *spath) { vfsw32path_t *wp = (void*)spath; if (filename[strlen(filename)-1] == '/') @@ -446,7 +446,7 @@ static void QDECL VFSW32_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, c fread(buffer, 1, loc->len, f); fclose(f); } -static int QDECL VFSW32_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, void *, searchpathfuncs_t *spath), void *parm) +static int QDECL VFSW32_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *spath), void *parm) { vfsw32path_t *wp = (vfsw32path_t*)handle; return Sys_EnumerateFiles(wp->rootpath, match, func, parm, handle); diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index 98b88a480..71dcb375e 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -2,6 +2,7 @@ #include "fs.h" #ifdef AVAIL_ZLIB +#define ZIPCRYPT #ifndef ZEXPORT #define ZEXPORT VARGS @@ -58,6 +59,9 @@ static int (ZEXPORT *qinflate) (z_streamp strm, int flush) ZSTATIC(inflate); static int (ZEXPORT *qinflateInit2_) (z_streamp strm, int windowBits, const char *version, int stream_size) ZSTATIC(inflateInit2_); //static uLong (ZEXPORT *qcrc32) (uLong crc, const Bytef *buf, uInt len) ZSTATIC(crc32); +#ifdef ZIPCRYPT +static const uLongf *(ZEXPORT *qget_crc_table) (void) ZSTATIC(get_crc_table); +#endif #define qinflateInit2(strm, windowBits) \ qinflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) @@ -71,6 +75,9 @@ qboolean LibZ_Init(void) {(void*)&qinflate, "inflate"}, {(void*)&qinflateInit2_, "inflateInit2_"}, // {(void*)&qcrc32, "crc32"}, +#ifdef ZIPCRYPT + {(void*)&qget_crc_table, "get_crc_table"}, +#endif {NULL, NULL} }; if (!ZLIB_LOADED()) @@ -247,6 +254,7 @@ typedef struct char name[MAX_QPATH]; qofs_t localpos; //location of local header qofs_t filelen; //uncompressed size + time_t mtime; unsigned int crc; unsigned int flags; } zpackfile_t; @@ -254,6 +262,7 @@ typedef struct #define ZFL_STORED 2 //direct access is okay #define ZFL_SYMLINK 4 //file is a symlink #define ZFL_CORRUPT 8 //file is corrupt or otherwise unreadable. +#define ZFL_WEAKENCRYPT 16 //traditional zip encryption typedef struct zipfile_s @@ -381,7 +390,7 @@ static void QDECL FSZIP_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, ch VFS_CLOSE(f); } -static int QDECL FSZIP_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, void *, searchpathfuncs_t *spath), void *parm) +static int QDECL FSZIP_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *spath), void *parm) { zipfile_t *zip = (void*)handle; int num; @@ -390,7 +399,7 @@ static int QDECL FSZIP_EnumerateFiles (searchpathfuncs_t *handle, const char *ma { if (wildcmp(match, zip->files[num].name)) { - if (!func(zip->files[num].name, zip->files[num].filelen, parm, &zip->pub)) + if (!func(zip->files[num].name, zip->files[num].filelen, zip->files[num].mtime, parm, &zip->pub)) return false; } } @@ -437,25 +446,114 @@ struct decompressstate unsigned char outbuffer[16384]; unsigned int readoffset; +#ifdef ZIPCRYPT + qboolean encrypted; + unsigned int cryptkey[3]; + unsigned int initialkey[3]; + const int * crctable; +#endif + z_stream strm; }; -struct decompressstate *FSZIP_Decompress_Init(zipfile_t *source, qofs_t start, qofs_t csize, qofs_t usize) +#ifdef ZIPCRYPT +#define CRC32(c, b) ((*(st->crctable+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +static void FSZIP_UpdateKeys(struct decompressstate *st, unsigned char ch) +{ + st->cryptkey[0] = CRC32(st->cryptkey[0], ch); + st->cryptkey[1] += (st->cryptkey[0] & 0xffu); + st->cryptkey[1] = st->cryptkey[1] * 0x8088405u + 1; + ch = st->cryptkey[1] >> 24; + st->cryptkey[2] = CRC32(st->cryptkey[2], ch); +} +static unsigned char FSZIP_DecryptByte(struct decompressstate *st) +{ + unsigned int temp; + temp = (st->cryptkey[2]&0xffff) | 2; + return ((temp * (temp ^ 1)) >> 8) & 0xff; +} + +static qboolean FSZIP_SetupCrytoKeys(struct decompressstate *st, const char *password, char *cryptheader, unsigned int crc) +{ + unsigned int u; + st->crctable = qget_crc_table(); + st->encrypted = true; + st->cryptkey[0] = 0x12345678; + st->cryptkey[1] = 0x23456789; + st->cryptkey[2] = 0x34567890; + while (*password) + FSZIP_UpdateKeys(st, *password++); + + for (u = 0; u < 12; u++) + { + unsigned char ch = cryptheader[u] ^ FSZIP_DecryptByte(st); + FSZIP_UpdateKeys(st, ch); + cryptheader[u] = ch; + } + + memcpy(st->initialkey, st->cryptkey, sizeof(st->initialkey)); + + //cryptheader[11] should be the high byte of the file's crc + //[10] might be the second byte, but also might not be. + if (cryptheader[11] != (unsigned char)(crc>>24)) + return false; +// if (cryptheader[10] != (unsigned char)(crc>>16)) +// return false; + return true; +} +static void FSZIP_DecryptBlock(struct decompressstate *st, char *block, size_t blocksize) +{ + while (blocksize--) + { + unsigned char temp = *block ^ FSZIP_DecryptByte(st); + FSZIP_UpdateKeys(st, temp); + *block++ = temp; + } +} +#endif + +static struct decompressstate *FSZIP_Decompress_Init(zipfile_t *source, qofs_t start, qofs_t csize, qofs_t usize, char *filename, char *password, unsigned int crc) { struct decompressstate *st; if (!ZLIB_LOADED()) + { + Con_Printf("zlib not available\n"); return NULL; + } st = Z_Malloc(sizeof(*st)); + st->source = source; + +#ifdef ZIPCRYPT + if (password && csize >= 12) + { + char entropy[12]; + if (Sys_LockMutex(source->mutex)) + { + VFS_SEEK(source->raw, start); + VFS_READ(source->raw, entropy, sizeof(entropy)); + Sys_UnlockMutex(source->mutex); + } + if (!FSZIP_SetupCrytoKeys(st, password, entropy, crc)) + { + Con_Printf("Invalid password, cannot decrypt %s\n", filename); + Z_Free(st); + return NULL; + } + start += sizeof(entropy); + csize -= sizeof(entropy); + } +#endif + st->cstart = st->cofs = start; st->cend = start + csize; st->usize = usize; st->strm.data_type = Z_UNKNOWN; - st->source = source; qinflateInit2(&st->strm, -MAX_WBITS); return st; } -qofs_t FSZIP_Decompress_Read(struct decompressstate *st, qbyte *buffer, qofs_t bytes) +static qofs_t FSZIP_Decompress_Read(struct decompressstate *st, qbyte *buffer, qofs_t bytes) { qboolean eof = false; int err; @@ -500,6 +598,10 @@ qofs_t FSZIP_Decompress_Read(struct decompressstate *st, qbyte *buffer, qofs_t b st->strm.avail_in = 0; st->strm.next_in = st->inbuffer; st->cofs += st->strm.avail_in; +#ifdef ZIPCRYPT + if (st->encrypted) + FSZIP_DecryptBlock(st, st->inbuffer, st->strm.avail_in); +#endif } if (!st->strm.avail_in) eof = true; @@ -513,12 +615,12 @@ qofs_t FSZIP_Decompress_Read(struct decompressstate *st, qbyte *buffer, qofs_t b return read; } -void FSZIP_Decompress_Destroy(struct decompressstate *st) +static void FSZIP_Decompress_Destroy(struct decompressstate *st) { qinflateEnd(&st->strm); Z_Free(st); } -vfsfile_t *FSZIP_Decompress_ToTempFile(struct decompressstate *decompress) +static vfsfile_t *FSZIP_Decompress_ToTempFile(struct decompressstate *decompress) { //if they're going to seek on a file in a zip, let's just copy it out qofs_t cstart = decompress->cstart, csize = decompress->cend - cstart; qofs_t upos = 0, usize = decompress->usize; @@ -527,6 +629,11 @@ vfsfile_t *FSZIP_Decompress_ToTempFile(struct decompressstate *decompress) qbyte buffer[16384]; vfsfile_t *defer; zipfile_t *source = decompress->source; + qboolean encrypted = decompress->encrypted; + unsigned int cryptkeys[3]; + const uLongf *crctab = decompress->crctable; + + memcpy(cryptkeys, decompress->initialkey, sizeof(cryptkeys)); defer = FS_OpenTemp(); if (defer) @@ -534,7 +641,11 @@ vfsfile_t *FSZIP_Decompress_ToTempFile(struct decompressstate *decompress) FSZIP_Decompress_Destroy(decompress); decompress = NULL; - nc = FSZIP_Decompress_Init(source, cstart, csize, usize); + nc = FSZIP_Decompress_Init(source, cstart, csize, usize, NULL, NULL, 0); + nc->encrypted = encrypted; + nc->crctable = crctab; + memcpy(nc->initialkey, cryptkeys, sizeof(nc->initialkey)); + memcpy(nc->cryptkey, cryptkeys, sizeof(nc->cryptkey)); while (upos < usize) { @@ -565,7 +676,7 @@ struct decompressstate // unsigned char outbuffer[16384]; // unsigned int readoffset; }; -struct decompressstate *FSZIP_Decompress_Init(zipfile_t *source, qofs_t start, qofs_t csize, qofs_t usize) +struct decompressstate *FSZIP_Decompress_Init(zipfile_t *source, qofs_t start, qofs_t csize, qofs_t usize, char *filename, char *password, unsigned int crc) { return NULL; } @@ -623,6 +734,9 @@ static int QDECL VFSZIP_ReadBytes (struct vfsfile_s *file, void *buffer, int byt else read = 0; + if (read < bytestoread) + ((char*)buffer)[read] = 0; + vfsz->pos += read; return read; } @@ -637,6 +751,7 @@ static qboolean QDECL VFSZIP_Seek (struct vfsfile_s *file, qofs_t pos) if (vfsz->decompress) { //if they're going to seek on a file in a zip, let's just copy it out vfsz->defer = FSZIP_Decompress_ToTempFile(vfsz->decompress); + vfsz->decompress = NULL; if (vfsz->defer) return VFS_SEEK(vfsz->defer, pos); return false; @@ -722,7 +837,12 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo if (flags & ZFL_DEFLATED) { - vfsz->decompress = FSZIP_Decompress_Init(zip, vfsz->startpos, datasize, vfsz->length); +#ifdef ZIPCRYPT + char *password = (flags & ZFL_WEAKENCRYPT)?Cvar_Get("fs_zip_password", "thisispublic", 0, "Filesystem")->string:NULL; +#else + char *password = NULL; +#endif + vfsz->decompress = FSZIP_Decompress_Init(zip, vfsz->startpos, datasize, vfsz->length, zip->files[loc->index].name, password, zip->files[loc->index].crc); if (!vfsz->decompress) { /* @@ -794,9 +914,10 @@ struct zipinfo }; struct zipcentralentry { - unsigned char *fname; - qofs_t cesize; - unsigned int flags; + unsigned char *fname; + qofs_t cesize; + unsigned int flags; + time_t mtime; //PK12 unsigned short version_madeby; @@ -991,6 +1112,8 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce entry->fname = data+entry->cesize; entry->cesize += entry->fnane_len; + entry->mtime = 0; + //parse extra if (entry->extra_len) { @@ -1030,11 +1153,30 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce extra += 4; } break; + case 0x000a: //NTFS extra field + //0+4: reserved + //4+2: subtag(must be 1, for times) + //6+2: subtagsize(times: must be == 8*3+4) + //8+8: mtime + //16+8: atime + //24+8: ctime + if (extrachunk_len >= 32 && LittleU2FromPtr(extra+4) == 1 && LittleU2FromPtr(extra+6) == 8*3) + entry->mtime = LittleU8FromPtr(extra+8) / 10000000ULL - 11644473600ULL; + else + Con_Printf("zip: unsupported ntfs subchunk %x\n", extrachunk_tag); + extra += extrachunk_len; + break; + case 0x5455: + if (extra[0] & 1) + entry->mtime = LittleU4FromPtr(extra+1); + //access and creation do NOT exist in the central header. + extra += extrachunk_len; + break; default: /* Con_Printf("Unknown chunk %x\n", extrachunk_tag); - case 0x000a: //NTFS (timestamps) case 0x5455: //extended timestamp case 0x7875: //unix uid/gid + case 0x9901: //aes crypto */ extra += extrachunk_len; break; } @@ -1061,8 +1203,16 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce } if (entry->gflags & (1u<<0)) //encrypted + { +#ifdef ZIPCRYPT + entry->flags |= ZFL_WEAKENCRYPT; +#else entry->flags |= ZFL_CORRUPT; - else if (entry->gflags & (1u<<5)) //is patch data +#endif + } + + + if (entry->gflags & (1u<<5)) //is patch data entry->flags |= ZFL_CORRUPT; else if (entry->gflags & (1u<<6)) //strong encryption entry->flags |= ZFL_CORRUPT; @@ -1076,7 +1226,7 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce //7: tokenize else if (entry->cmethod == 8) entry->flags |= ZFL_DEFLATED; - //8: deflate64 - patented. sometimes written by microsoft's crap. only minor improvements. + //8: deflate64 - patented. sometimes written by microsoft's crap, so this might be problematic. only minor improvements. //10: implode //12: bzip2 // else if (entry->cmethod == 12) @@ -1088,6 +1238,9 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce //98: ppmd else entry->flags |= ZFL_CORRUPT; //unsupported compression method. + + if ((entry->flags & ZFL_WEAKENCRYPT) && !(entry->flags & ZFL_DEFLATED)) + entry->flags |= ZFL_CORRUPT; //only support decryption with deflate. return true; } @@ -1165,6 +1318,7 @@ static qboolean FSZIP_EnumerateCentralDirectory(zipfile_t *zip, struct zipinfo * f->filelen = entry.usize; f->localpos = entry.localheaderoffset+info->zipoffset; f->flags = entry.flags; + f->mtime = entry.mtime; ofs += entry.cesize; f++; @@ -1377,7 +1531,8 @@ searchpathfuncs_t *QDECL FSZIP_LoadArchive (vfsfile_t *packhandle, const char *d #if 0 - +//our download protocol permits requesting various different parts of the file. +//this means that its theoretically possible to download sections pk3s such that we can skip blocks that contain files that we already have. typedef struct { diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 455487f98..861a4ccc4 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -62,7 +62,6 @@ static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3 static unsigned int CM_NativeContents(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs); static unsigned int Q2BSP_PointContents(model_t *mod, vec3_t axis[3], vec3_t p); static int CM_PointCluster (model_t *mod, vec3_t p); -extern mplane_t *box_planes; float RadiusFromBounds (vec3_t mins, vec3_t maxs) { @@ -325,68 +324,69 @@ typedef struct cmodel_s /*used to trace*/ static int checkcount; -static int numbrushsides; -static q2cbrushside_t *map_brushsides; +typedef struct cminfo_s +{ + int numbrushsides; + q2cbrushside_t *brushsides; -static q2mapsurface_t *map_surfaces; + q2mapsurface_t *surfaces; -static int numleafbrushes; -static q2cbrush_t *map_leafbrushes[MAX_Q2MAP_LEAFBRUSHES]; + int numleafbrushes; + q2cbrush_t *leafbrushes[MAX_Q2MAP_LEAFBRUSHES]; -static int numcmodels; -static cmodel_t *map_cmodels; + int numcmodels; + cmodel_t *cmodels; -static int numbrushes; -static q2cbrush_t *map_brushes; + int numbrushes; + q2cbrush_t *brushes; -static int numvisibility; -static q2dvis_t *map_q2vis; -static q3dvis_t *map_q3pvs; -static q3dvis_t *map_q3phs; + int numvisibility; + q2dvis_t *q2vis; + q3dvis_t *q3pvs; + q3dvis_t *q3phs; -static int numareas = 1; -static q2carea_t map_q2areas[MAX_Q2MAP_AREAS]; -static q3carea_t map_q3areas[MAX_CM_AREAS]; + int numareas; + q2carea_t q2areas[MAX_Q2MAP_AREAS]; + q3carea_t q3areas[MAX_CM_AREAS]; + int numareaportals; + q2dareaportal_t areaportals[MAX_Q2MAP_AREAPORTALS]; -static int numareaportals; -static q2dareaportal_t map_areaportals[MAX_Q2MAP_AREAPORTALS]; + //list of mesh surfaces within the leaf + q3cmesh_t cmeshes[MAX_CM_PATCHES]; + int numcmeshes; + int *leafcmeshes; + int numleafcmeshes; + int maxleafcmeshes; -//(deprecated) patch collisions -static q3cpatch_t map_patches[MAX_CM_PATCHES]; -static int numpatches; -static int *map_leafpatches; -static int numleafpatches; -static int maxleafpatches; + //FIXME: remove the below + //(deprecated) patch collisions + q3cpatch_t patches[MAX_CM_PATCHES]; + int numpatches; + int *leafpatches; + int numleafpatches; + int maxleafpatches; + //FIXME: remove the above -//list of mesh surfaces within the leaf -static q3cmesh_t map_cmeshes[MAX_CM_PATCHES]; -static int numcmeshes; -static int *map_leafcmeshes; -static int numleafcmeshes; -static int maxleafcmeshes; + int floodvalid; + qbyte portalopen[MAX_Q2MAP_AREAPORTALS]; //memset will work if it's a qbyte, really it should be a qboolean -static int numclusters = 1; + int mapisq3; +} cminfo_t; static q2mapsurface_t nullsurface; -static int floodvalid; - -static qbyte portalopen[MAX_Q2MAP_AREAPORTALS]; //memset will work if it's a qbyte, really it should be a qboolean - -static int mapisq3; cvar_t map_noareas = SCVAR("map_noareas", "0"); //1 for lack of mod support. cvar_t map_noCurves = SCVARF("map_noCurves", "0", CVAR_CHEAT); cvar_t map_autoopenportals = SCVAR("map_autoopenportals", "1"); //1 for lack of mod support. cvar_t r_subdivisions = SCVAR("r_subdivisions", "2"); -int CM_NumInlineModels (model_t *model); -cmodel_t *CM_InlineModel (char *name); +static int CM_NumInlineModels (model_t *model); +static cmodel_t *CM_InlineModel (model_t *model, char *name); void CM_InitBoxHull (void); -static void FloodAreaConnections (void); +static void FloodAreaConnections (cminfo_t *prv); -static vecV_t *map_verts; //3points static int numvertexes; - +static vecV_t *map_verts; //3points static vec2_t *map_vertstmexcoords; static vec2_t *map_vertlstmexcoords[MAXRLIGHTMAPS]; static vec4_t *map_colors4f_array[MAXRLIGHTMAPS]; @@ -394,14 +394,11 @@ static vec3_t *map_normals_array; //static vec3_t *map_svector_array; //static vec3_t *map_tvector_array; -q3cface_t *map_faces; -static int numfaces; - static index_t *map_surfindexes; static int map_numsurfindexes; - - +q3cface_t *map_faces; +static int numfaces; @@ -943,7 +940,7 @@ static void CM_CreatePatch(model_t *loadmodel, q3cpatch_t *patch, q2mapsurface_t CM_CreatePatchesForLeafs ================= */ -qboolean CM_CreatePatchesForLeafs (model_t *loadmodel) +qboolean CM_CreatePatchesForLeafs (model_t *loadmodel, cminfo_t *prv) { int i, j, k; mleaf_t *leaf; @@ -961,9 +958,9 @@ qboolean CM_CreatePatchesForLeafs (model_t *loadmodel) for (i = 0, leaf = loadmodel->leafs; i < loadmodel->numleafs; i++, leaf++) { leaf->numleafpatches = 0; - leaf->firstleafpatch = numleafpatches; + leaf->firstleafpatch = prv->numleafpatches; leaf->numleafcmeshes = 0; - leaf->firstleafcmesh = numleafcmeshes; + leaf->firstleafcmesh = prv->numleafcmeshes; if (leaf->cluster == -1) continue; @@ -982,7 +979,7 @@ qboolean CM_CreatePatchesForLeafs (model_t *loadmodel) continue; if (face->shadernum < 0 || face->shadernum >= loadmodel->numtextures) continue; - surf = &map_surfaces[face->shadernum]; + surf = &prv->surfaces[face->shadernum]; if (!surf->c.value) //surface has no contents value, so can't ever block anything. continue; @@ -996,35 +993,35 @@ qboolean CM_CreatePatchesForLeafs (model_t *loadmodel) if (!(surf->c.flags & q3bsp_surf_meshcollision_flag.ival) && !q3bsp_surf_meshcollision_force.ival) continue; - if (numleafcmeshes >= maxleafcmeshes) + if (prv->numleafcmeshes >= prv->maxleafcmeshes) { - maxleafcmeshes *= 2; - maxleafcmeshes += 16; - if (numleafcmeshes > maxleafcmeshes) + prv->maxleafcmeshes *= 2; + prv->maxleafcmeshes += 16; + if (prv->numleafcmeshes > prv->maxleafcmeshes) { //detect overflow Con_Printf (CON_ERROR "CM_CreateCMeshesForLeafs: map is insanely huge!\n"); return false; } - map_leafcmeshes = realloc(map_leafcmeshes, sizeof(*map_leafcmeshes) * maxleafcmeshes); + prv->leafcmeshes = realloc(prv->leafcmeshes, sizeof(*prv->leafcmeshes) * prv->maxleafcmeshes); } // the patch was already built if (checkout[k] != -1) { - map_leafcmeshes[numleafcmeshes] = checkout[k]; - cmesh = &map_cmeshes[checkout[k]]; + prv->leafcmeshes[prv->numleafcmeshes] = checkout[k]; + cmesh = &prv->cmeshes[checkout[k]]; } else { - if (numcmeshes >= MAX_CM_PATCHES) + if (prv->numcmeshes >= MAX_CM_PATCHES) { Con_Printf (CON_ERROR "CM_CreatePatchesForLeafs: map has too many patches\n"); return false; } - cmesh = &map_cmeshes[numcmeshes]; - map_leafcmeshes[numleafcmeshes] = numcmeshes; - checkout[k] = numcmeshes++; + cmesh = &prv->cmeshes[prv->numcmeshes]; + prv->leafcmeshes[prv->numleafcmeshes] = prv->numcmeshes; + checkout[k] = prv->numcmeshes++; //gcc warns without this cast @@ -1048,7 +1045,7 @@ qboolean CM_CreatePatchesForLeafs (model_t *loadmodel) leaf->contents |= surf->c.value; leaf->numleafcmeshes++; - numleafcmeshes++; + prv->numleafcmeshes++; break; case MST_PATCH: @@ -1058,35 +1055,35 @@ qboolean CM_CreatePatchesForLeafs (model_t *loadmodel) if ( !surf->c.value || (surf->c.flags & Q3SURF_NONSOLID) ) continue; - if (numleafpatches >= maxleafpatches) + if (prv->numleafpatches >= prv->maxleafpatches) { - maxleafpatches *= 2; - maxleafpatches += 16; - if (numleafpatches > maxleafpatches) + prv->maxleafpatches *= 2; + prv->maxleafpatches += 16; + if (prv->numleafpatches > prv->maxleafpatches) { //detect overflow Con_Printf (CON_ERROR "CM_CreatePatchesForLeafs: map is insanely huge!\n"); return false; } - map_leafpatches = realloc(map_leafpatches, sizeof(*map_leafpatches) * maxleafpatches); + prv->leafpatches = realloc(prv->leafpatches, sizeof(*prv->leafpatches) * prv->maxleafpatches); } // the patch was already built if (checkout[k] != -1) { - map_leafpatches[numleafpatches] = checkout[k]; - patch = &map_patches[checkout[k]]; + prv->leafpatches[prv->numleafpatches] = checkout[k]; + patch = &prv->patches[checkout[k]]; } else { - if (numpatches >= MAX_CM_PATCHES) + if (prv->numpatches >= MAX_CM_PATCHES) { Con_Printf (CON_ERROR "CM_CreatePatchesForLeafs: map has too many patches\n"); return false; } - patch = &map_patches[numpatches]; - map_leafpatches[numleafpatches] = numpatches; - checkout[k] = numpatches++; + patch = &prv->patches[prv->numpatches]; + prv->leafpatches[prv->numleafpatches] = prv->numpatches; + checkout[k] = prv->numpatches++; //gcc warns without this cast CM_CreatePatch (loadmodel, patch, surf, (const vec_t *)(map_verts + face->firstvert), face->patch.cp ); @@ -1094,7 +1091,7 @@ qboolean CM_CreatePatchesForLeafs (model_t *loadmodel) leaf->contents |= patch->surface->c.value; leaf->numleafpatches++; - numleafpatches++; + prv->numleafpatches++; break; } } @@ -1120,6 +1117,7 @@ CMod_LoadSubmodels */ qboolean CModQ2_LoadSubmodels (model_t *loadmodel, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)loadmodel->meshinfo; q2dmodel_t *in; cmodel_t *out; int i, j, count; @@ -1143,8 +1141,8 @@ qboolean CModQ2_LoadSubmodels (model_t *loadmodel, qbyte *mod_base, lump_t *l) return false; } - out = map_cmodels = ZG_Malloc(&loadmodel->memgroup, count * sizeof(*map_cmodels)); - numcmodels = count; + out = prv->cmodels = ZG_Malloc(&loadmodel->memgroup, count * sizeof(*prv->cmodels)); + prv->numcmodels = count; for (i=0 ; inumsurfaces = LittleLong (in->numfaces); } - AddPointToBounds(map_cmodels[0].mins, loadmodel->mins, loadmodel->maxs); - AddPointToBounds(map_cmodels[0].maxs, loadmodel->mins, loadmodel->maxs); + AddPointToBounds(prv->cmodels[0].mins, loadmodel->mins, loadmodel->maxs); + AddPointToBounds(prv->cmodels[0].maxs, loadmodel->mins, loadmodel->maxs); return true; } @@ -1173,6 +1171,7 @@ CMod_LoadSurfaces */ qboolean CModQ2_LoadSurfaces (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; q2texinfo_t *in; q2mapsurface_t *out; int i, count; @@ -1193,7 +1192,7 @@ qboolean CModQ2_LoadSurfaces (model_t *mod, qbyte *mod_base, lump_t *l) // Host_Error ("Map has too many surfaces"); mod->numtexinfo = count; - out = map_surfaces = ZG_Malloc(&mod->memgroup, count * sizeof(*map_surfaces)); + out = prv->surfaces = ZG_Malloc(&mod->memgroup, count * sizeof(*prv->surfaces)); for ( i=0 ; imeshinfo; q2dbrush_t *in; q2cbrush_t *out; int i, count; @@ -1624,16 +1624,16 @@ qboolean CModQ2_LoadBrushes (model_t *mod, qbyte *mod_base, lump_t *l) return false; } - map_brushes = ZG_Malloc(&mod->memgroup, sizeof(*out) * (count+1)); + prv->brushes = ZG_Malloc(&mod->memgroup, sizeof(*out) * (count+1)); - out = map_brushes; + out = prv->brushes; - numbrushes = count; + prv->numbrushes = count; for (i=0 ; ibrushside = &map_brushsides[LittleLong(in->firstside)]; + out->brushside = &prv->brushsides[LittleLong(in->firstside)]; out->numsides = LittleLong(in->numsides); out->contents = LittleLong(in->contents); } @@ -1674,7 +1674,7 @@ qboolean CModQ2_LoadLeafs (model_t *mod, qbyte *mod_base, lump_t *l) } out = ZG_Malloc(&mod->memgroup, sizeof(*out) * (count+1)); - numclusters = 0; + mod->numclusters = 0; mod->leafs = out; mod->numleafs = count; @@ -1702,8 +1702,8 @@ qboolean CModQ2_LoadLeafs (model_t *mod, qbyte *mod_base, lump_t *l) (unsigned short)LittleShort(in->firstleafface); out->nummarksurfaces = (unsigned short)LittleShort(in->numleaffaces); - if (out->cluster >= numclusters) - numclusters = out->cluster + 1; + if (out->cluster >= mod->numclusters) + mod->numclusters = out->cluster + 1; } out = mod->leafs; @@ -1777,6 +1777,7 @@ CMod_LoadLeafBrushes */ qboolean CModQ2_LoadLeafBrushes (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; int i; q2cbrush_t **out; unsigned short *in; @@ -1802,11 +1803,11 @@ qboolean CModQ2_LoadLeafBrushes (model_t *mod, qbyte *mod_base, lump_t *l) return false; } - out = map_leafbrushes; - numleafbrushes = count; + out = prv->leafbrushes; + prv->numleafbrushes = count; for ( i=0 ; ibrushes + (unsigned short)(short)LittleShort (*in); return true; } @@ -1818,6 +1819,7 @@ CMod_LoadBrushSides */ qboolean CModQ2_LoadBrushSides (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; int i, j; q2cbrushside_t *out; q2dbrushside_t *in; @@ -1839,8 +1841,8 @@ qboolean CModQ2_LoadBrushSides (model_t *mod, qbyte *mod_base, lump_t *l) return false; } - out = map_brushsides = ZG_Malloc(&mod->memgroup, sizeof(*out) * count); - numbrushsides = count; + out = prv->brushsides = ZG_Malloc(&mod->memgroup, sizeof(*out) * count); + prv->numbrushsides = count; for ( i=0 ; isurface = &map_surfaces[j]; + out->surface = &prv->surfaces[j]; } return true; @@ -1865,6 +1867,7 @@ CMod_LoadAreas */ qboolean CModQ2_LoadAreas (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; int i; q2carea_t *out; q2darea_t *in; @@ -1884,8 +1887,8 @@ qboolean CModQ2_LoadAreas (model_t *mod, qbyte *mod_base, lump_t *l) return false; } - out = map_q2areas; - numareas = count; + out = prv->q2areas; + prv->numareas = count; for ( i=0 ; imeshinfo; int i; q2dareaportal_t *out; q2dareaportal_t *in; @@ -1924,8 +1928,8 @@ qboolean CModQ2_LoadAreaPortals (model_t *mod, qbyte *mod_base, lump_t *l) return false; } - out = map_areaportals; - numareaportals = count; + out = prv->areaportals; + prv->numareaportals = count; for ( i=0 ; imeshinfo; int i; - numvisibility = l->filelen; + prv->numvisibility = l->filelen; // if (l->filelen > MAX_Q2MAP_VISIBILITY) // { // Con_Printf (CON_ERROR "Map has too large visibility lump\n"); // return false; // } - map_q2vis = ZG_Malloc(&mod->memgroup, l->filelen); - memcpy (map_q2vis, mod_base + l->fileofs, l->filelen); + prv->q2vis = ZG_Malloc(&mod->memgroup, l->filelen); + memcpy (prv->q2vis, mod_base + l->fileofs, l->filelen); - mod->vis = map_q2vis; + mod->vis = prv->q2vis; - map_q2vis->numclusters = LittleLong (map_q2vis->numclusters); - for (i=0 ; inumclusters ; i++) + prv->q2vis->numclusters = LittleLong (prv->q2vis->numclusters); + for (i=0 ; iq2vis->numclusters ; i++) { - map_q2vis->bitofs[i][0] = LittleLong (map_q2vis->bitofs[i][0]); - map_q2vis->bitofs[i][1] = LittleLong (map_q2vis->bitofs[i][1]); + prv->q2vis->bitofs[i][0] = LittleLong (prv->q2vis->bitofs[i][0]); + prv->q2vis->bitofs[i][1] = LittleLong (prv->q2vis->bitofs[i][1]); } - mod->numclusters = map_q2vis->numclusters; + mod->numclusters = prv->q2vis->numclusters; return true; } @@ -2017,6 +2022,7 @@ qboolean CModQ3_LoadMarksurfaces (model_t *loadmodel, qbyte *mod_base, lump_t *l qboolean CModQ3_LoadSubmodels (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; q3dmodel_t *in; cmodel_t *out; int i, j, count; @@ -2042,15 +2048,15 @@ qboolean CModQ3_LoadSubmodels (model_t *mod, qbyte *mod_base, lump_t *l) return false; } - out = map_cmodels = ZG_Malloc(&mod->memgroup, count * sizeof(*map_cmodels)); - numcmodels = count; + out = prv->cmodels = ZG_Malloc(&mod->memgroup, count * sizeof(*prv->cmodels)); + prv->numcmodels = count; if (count > 1) bleaf = ZG_Malloc(&mod->memgroup, (count-1) * sizeof(*bleaf)); else bleaf = NULL; - mapisq3 = true; + prv->mapisq3 = true; for (i=0 ; inum_brushes = LittleLong(in->num_brushes); bleaf->numleafbrushes = LittleLong ( in->num_brushes ); - bleaf->firstleafbrush = numleafbrushes; + bleaf->firstleafbrush = prv->numleafbrushes; bleaf->contents = 0; - leafbrush = &map_leafbrushes[numleafbrushes]; + leafbrush = &prv->leafbrushes[prv->numleafbrushes]; for ( j = 0; j < bleaf->numleafbrushes; j++, leafbrush++ ) { - *leafbrush = map_brushes + LittleLong ( in->firstbrush ) + j; + *leafbrush = prv->brushes + LittleLong ( in->firstbrush ) + j; bleaf->contents |= (*leafbrush)->contents; } - numleafbrushes += bleaf->numleafbrushes; + prv->numleafbrushes += bleaf->numleafbrushes; bleaf++; } //submodels } - AddPointToBounds(map_cmodels[0].mins, mod->mins, mod->maxs); - AddPointToBounds(map_cmodels[0].maxs, mod->mins, mod->maxs); + AddPointToBounds(prv->cmodels[0].mins, mod->mins, mod->maxs); + AddPointToBounds(prv->cmodels[0].maxs, mod->mins, mod->maxs); return true; } qboolean CModQ3_LoadShaders (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; dq3shader_t *in; q2mapsurface_t *out; int i, count; @@ -2121,7 +2128,7 @@ qboolean CModQ3_LoadShaders (model_t *mod, qbyte *mod_base, lump_t *l) // Host_Error ("Map has too many shaders"); mod->numtexinfo = count; - out = map_surfaces = ZG_Malloc(&mod->memgroup, count*sizeof(*out)); + out = prv->surfaces = ZG_Malloc(&mod->memgroup, count*sizeof(*out)); mod->texinfo = ZG_Malloc(&mod->memgroup, sizeof(mtexinfo_t)*(count*2+1)); //+1 is 'noshader' for flares. mod->numtextures = count*2+1; @@ -2427,6 +2434,7 @@ Mod_LoadFogs */ qboolean CModQ3_LoadFogs (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; dfog_t *in; mfog_t *out; q2cbrush_t *brush; @@ -2452,7 +2460,7 @@ qboolean CModQ3_LoadFogs (model_t *mod, qbyte *mod_base, lump_t *l) continue; } - brush = map_brushes + LittleLong ( in->brushNum ); + brush = prv->brushes + LittleLong ( in->brushNum ); brushsides = brush->brushside; visibleside = brushsides + LittleLong ( in->visibleSide ); @@ -2783,6 +2791,7 @@ void CModQ3_BuildSurfMesh(model_t *mod, msurface_t *out, builddata_t *bd) qboolean CModQ3_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; extern cvar_t r_vertexlight; q3dface_t *in; msurface_t *out; @@ -2848,7 +2857,7 @@ qboolean CModQ3_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) CategorizePlane(pl); } - if (map_surfaces[LittleLong(in->shadernum)].c.value == 0 || map_surfaces[LittleLong(in->shadernum)].c.value & Q3CONTENTS_TRANSLUCENT) + if (prv->surfaces[LittleLong(in->shadernum)].c.value == 0 || prv->surfaces[LittleLong(in->shadernum)].c.value & Q3CONTENTS_TRANSLUCENT) //q3dm10's thingie is 0 out->flags |= SURF_DRAWALPHA; @@ -2860,7 +2869,7 @@ qboolean CModQ3_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) else out->fog = mod->fogs + LittleLong(in->fognum); - if (map_surfaces[LittleLong(in->shadernum)].c.flags & (Q3SURF_NODRAW | Q3SURF_SKIP)) + if (prv->surfaces[LittleLong(in->shadernum)].c.flags & (Q3SURF_NODRAW | Q3SURF_SKIP)) { out->mesh = &mesh[surfnum]; out->mesh->numindexes = 0; @@ -2894,6 +2903,7 @@ qboolean CModQ3_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) qboolean CModRBSP_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; extern cvar_t r_vertexlight; rbspface_t *in; msurface_t *out; @@ -2956,7 +2966,7 @@ qboolean CModRBSP_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) CategorizePlane(pl); } - if (map_surfaces[in->shadernum].c.value == 0 || map_surfaces[in->shadernum].c.value & Q3CONTENTS_TRANSLUCENT) + if (prv->surfaces[in->shadernum].c.value == 0 || prv->surfaces[in->shadernum].c.value & Q3CONTENTS_TRANSLUCENT) //q3dm10's thingie is 0 out->flags |= SURF_DRAWALPHA; @@ -2968,7 +2978,7 @@ qboolean CModRBSP_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) else out->fog = mod->fogs + in->fognum; - if (map_surfaces[LittleLong(in->shadernum)].c.flags & (Q3SURF_NODRAW | Q3SURF_SKIP)) + if (prv->surfaces[LittleLong(in->shadernum)].c.flags & (Q3SURF_NODRAW | Q3SURF_SKIP)) { out->mesh = &mesh[surfnum]; out->mesh->numindexes = 0; @@ -3064,6 +3074,7 @@ qboolean CModQ3_LoadNodes (model_t *loadmodel, qbyte *mod_base, lump_t *l) qboolean CModQ3_LoadBrushes (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; q3dbrush_t *in; q2cbrush_t *out; int i, count; @@ -3083,17 +3094,17 @@ qboolean CModQ3_LoadBrushes (model_t *mod, qbyte *mod_base, lump_t *l) return false; } - map_brushes = ZG_Malloc(&mod->memgroup, sizeof(*out) * (count+1)); + prv->brushes = ZG_Malloc(&mod->memgroup, sizeof(*out) * (count+1)); - out = map_brushes; + out = prv->brushes; - numbrushes = count; + prv->numbrushes = count; for (i=0 ; ishadernum ); - out->contents = map_surfaces[shaderref].c.value; - out->brushside = &map_brushsides[LittleLong ( in->firstside )]; + out->contents = prv->surfaces[shaderref].c.value; + out->brushside = &prv->brushsides[LittleLong ( in->firstside )]; out->numsides = LittleLong ( in->num_sides ); } @@ -3102,6 +3113,7 @@ qboolean CModQ3_LoadBrushes (model_t *mod, qbyte *mod_base, lump_t *l) qboolean CModQ3_LoadLeafs (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; int i, j; mleaf_t *out; q3dleaf_t *in; @@ -3130,7 +3142,6 @@ qboolean CModQ3_LoadLeafs (model_t *mod, qbyte *mod_base, lump_t *l) } out = ZG_Malloc(&mod->memgroup, sizeof(*out) * (count+1)); - numclusters = 0; mod->leafs = out; mod->numleafs = count; @@ -3161,13 +3172,13 @@ qboolean CModQ3_LoadLeafs (model_t *mod, qbyte *mod_base, lump_t *l) for (j=0 ; jnumleafbrushes ; j++) { - brush = map_leafbrushes[out->firstleafbrush + j]; + brush = prv->leafbrushes[out->firstleafbrush + j]; out->contents |= brush->contents; } - if (out->area >= numareas) + if (out->area >= prv->numareas) { - numareas = out->area + 1; + prv->numareas = out->area + 1; } } @@ -3214,6 +3225,7 @@ qboolean CModQ3_LoadPlanes (model_t *loadmodel, qbyte *mod_base, lump_t *l) qboolean CModQ3_LoadLeafBrushes (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; int i; q2cbrush_t **out; int *in; @@ -3239,17 +3251,18 @@ qboolean CModQ3_LoadLeafBrushes (model_t *mod, qbyte *mod_base, lump_t *l) return false; } - out = map_leafbrushes; - numleafbrushes = count; + out = prv->leafbrushes; + prv->numleafbrushes = count; for ( i=0 ; ibrushes + LittleLong (*in); return true; } qboolean CModQ3_LoadBrushSides (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; int i, j; q2cbrushside_t *out; q3dbrushside_t *in; @@ -3271,8 +3284,8 @@ qboolean CModQ3_LoadBrushSides (model_t *mod, qbyte *mod_base, lump_t *l) return false; } - out = map_brushsides = ZG_Malloc(&mod->memgroup, sizeof(*out) * count); - numbrushsides = count; + out = prv->brushsides = ZG_Malloc(&mod->memgroup, sizeof(*out) * count); + prv->numbrushsides = count; for ( i=0 ; isurface = &map_surfaces[j]; + out->surface = &prv->surfaces[j]; } return true; @@ -3292,6 +3305,7 @@ qboolean CModQ3_LoadBrushSides (model_t *mod, qbyte *mod_base, lump_t *l) qboolean CModRBSP_LoadBrushSides (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; int i, j; q2cbrushside_t *out; rbspbrushside_t *in; @@ -3313,8 +3327,8 @@ qboolean CModRBSP_LoadBrushSides (model_t *mod, qbyte *mod_base, lump_t *l) return false; } - out = map_brushsides = ZG_Malloc(&mod->memgroup, sizeof(*out) * count); - numbrushsides = count; + out = prv->brushsides = ZG_Malloc(&mod->memgroup, sizeof(*out) * count); + prv->numbrushsides = count; for ( i=0 ; isurface = &map_surfaces[j]; + out->surface = &prv->surfaces[j]; } return true; @@ -3334,6 +3348,8 @@ qboolean CModRBSP_LoadBrushSides (model_t *mod, qbyte *mod_base, lump_t *l) qboolean CModQ3_LoadVisibility (model_t *mod, qbyte *mod_base, lump_t *l) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; + unsigned int numclusters; if (l->filelen == 0) { int i; @@ -3344,22 +3360,22 @@ qboolean CModQ3_LoadVisibility (model_t *mod, qbyte *mod_base, lump_t *l) numclusters++; - map_q3pvs = ZG_Malloc(&mod->memgroup, sizeof(*map_q3pvs) + (numclusters+7)/8 * numclusters); - memset (map_q3pvs, 0xff, sizeof(*map_q3pvs) + (numclusters+7)/8 * numclusters); - map_q3pvs->numclusters = numclusters; - numvisibility = 0; - map_q3pvs->rowsize = (map_q3pvs->numclusters+7)/8; + prv->q3pvs = ZG_Malloc(&mod->memgroup, sizeof(*prv->q3pvs) + (numclusters+7)/8 * numclusters); + memset (prv->q3pvs, 0xff, sizeof(*prv->q3pvs) + (numclusters+7)/8 * numclusters); + prv->q3pvs->numclusters = numclusters; + prv->numvisibility = 0; + prv->q3pvs->rowsize = (prv->q3pvs->numclusters+7)/8; } else { - numvisibility = l->filelen; + prv->numvisibility = l->filelen; - map_q3pvs = ZG_Malloc(&mod->memgroup, l->filelen); - mod->vis = (q2dvis_t *)map_q3pvs; - memcpy (map_q3pvs, mod_base + l->fileofs, l->filelen); + prv->q3pvs = ZG_Malloc(&mod->memgroup, l->filelen); + mod->vis = (q2dvis_t *)prv->q3pvs; + memcpy (prv->q3pvs, mod_base + l->fileofs, l->filelen); - numclusters = map_q3pvs->numclusters = LittleLong (map_q3pvs->numclusters); - map_q3pvs->rowsize = LittleLong (map_q3pvs->rowsize); + numclusters = prv->q3pvs->numclusters = LittleLong (prv->q3pvs->numclusters); + prv->q3pvs->rowsize = LittleLong (prv->q3pvs->rowsize); } mod->numclusters = numclusters; @@ -3538,7 +3554,7 @@ int CM_GetQ2Palette (void) } #endif -void CM_OpenAllPortals(char *ents) //this is a compleate hack. About as compleate as possible. +void CM_OpenAllPortals(model_t *mod, char *ents) //this is a compleate hack. About as compleate as possible. { //q2 levels contain a thingie called area portals. Basically, doors can seperate two areas and //the engine knows when this portal is open, and weather to send ents from both sides of the door //or not. It's not just ents, but also walls. We want to just open them by default and hope the @@ -3578,7 +3594,7 @@ void CM_OpenAllPortals(char *ents) //this is a compleate hack. About as compleat if (!strcmp(name, "func_areaportal")) { - CMQ2_SetAreaPortalState(atoi(style), true); + CMQ2_SetAreaPortalState(mod, atoi(style), true); } } @@ -3590,6 +3606,7 @@ void CM_OpenAllPortals(char *ents) //this is a compleate hack. About as compleat #ifndef CLIENTONLY void CMQ3_CalcPHS (model_t *mod) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; int rowbytes, rowwords; int i, j, k, l, index; int bitbyte; @@ -3601,15 +3618,15 @@ void CMQ3_CalcPHS (model_t *mod) Con_DPrintf ("Building PHS...\n"); - map_q3phs = ZG_Malloc(&mod->memgroup, sizeof(*map_q3phs) + map_q3pvs->rowsize * map_q3pvs->numclusters); + prv->q3phs = ZG_Malloc(&mod->memgroup, sizeof(*prv->q3phs) + prv->q3pvs->rowsize * prv->q3pvs->numclusters); - rowwords = map_q3pvs->rowsize / sizeof(int); - rowbytes = map_q3pvs->rowsize; + rowwords = prv->q3pvs->rowsize / sizeof(int); + rowbytes = prv->q3pvs->rowsize; - memset ( map_q3phs, 0, sizeof(*map_q3phs) + map_q3pvs->rowsize * map_q3pvs->numclusters ); + memset ( prv->q3phs, 0, sizeof(*prv->q3phs) + prv->q3pvs->rowsize * prv->q3pvs->numclusters ); - map_q3phs->rowsize = map_q3pvs->rowsize; - map_q3phs->numclusters = numclusters = map_q3pvs->numclusters; + prv->q3phs->rowsize = prv->q3pvs->rowsize; + prv->q3phs->numclusters = numclusters = prv->q3pvs->numclusters; if (!numclusters) return; @@ -3627,8 +3644,8 @@ void CMQ3_CalcPHS (model_t *mod) } count = 0; - scan = (qbyte *)map_q3pvs->data; - dest = (unsigned int *)(map_q3phs->data); + scan = (qbyte *)prv->q3pvs->data; + dest = (unsigned int *)(prv->q3phs->data); for (i=0 ; idata) + index*rowwords; + src = (unsigned int *)(prv->q3pvs->data) + index*rowwords; for (l=0 ; lname, loadname, sizeof(loadname)); // free old stuff - numcmodels = 0; - numvisibility = 0; - box_planes = NULL; //so its rebuilt + mod->meshinfo = prv = ZG_Malloc(&mod->memgroup, sizeof(*prv)); + prv->numcmodels = 0; + prv->numvisibility = 0; mod->type = mod_brush; if (!mod->name[0]) { - map_cmodels = ZG_Malloc(&mod->memgroup, 1 * sizeof(*map_cmodels)); + prv->cmodels = ZG_Malloc(&mod->memgroup, 1 * sizeof(*prv->cmodels)); mod->leafs = ZG_Malloc(&mod->memgroup, 1 * sizeof(*mod->leafs)); - numcmodels = 1; - numclusters = 1; - numareas = 1; + prv->numcmodels = 1; + prv->numareas = 1; *checksum = 0; - map_cmodels[0].headnode = (mnode_t*)mod->leafs; //directly start with the empty leaf - return &map_cmodels[0]; // cinematic servers won't have anything at all + prv->cmodels[0].headnode = (mnode_t*)mod->leafs; //directly start with the empty leaf + return &prv->cmodels[0]; // cinematic servers won't have anything at all } // @@ -3865,7 +3882,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole case 1: //rbsp/fbsp case Q3BSPVERSION+1: //rtcw case Q3BSPVERSION: - mapisq3 = true; + prv->mapisq3 = true; mod->fromgame = fg_quake3; for (i=0 ; imapisq3 = true; noerrors = noerrors && CModQ3_LoadShaders (mod, mod_base, &header.lumps[Q3LUMP_SHADERS]); noerrors = noerrors && CModQ3_LoadPlanes (mod, mod_base, &header.lumps[Q3LUMP_PLANES]); if (header.version == 1) @@ -4029,8 +4046,8 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole for ( i = 0; i < 3; i++ ) { - lg->gridMins[i] = lg->gridSize[i] * ceil( (map_cmodels->mins[i] + 1) / lg->gridSize[i] ); - maxs = lg->gridSize[i] * floor( (map_cmodels->maxs[i] - 1) / lg->gridSize[i] ); + lg->gridMins[i] = lg->gridSize[i] * ceil( (prv->cmodels->mins[i] + 1) / lg->gridSize[i] ); + maxs = lg->gridSize[i] * floor( (prv->cmodels->maxs[i] - 1) / lg->gridSize[i] ); lg->gridBounds[i] = (maxs - lg->gridMins[i])/lg->gridSize[i] + 1; } @@ -4038,7 +4055,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole } #endif - if (!CM_CreatePatchesForLeafs (mod)) //for clipping + if (!CM_CreatePatchesForLeafs (mod, prv)) //for clipping { BZ_Free(map_faces); return NULL; @@ -4051,7 +4068,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole break; #endif case Q2BSPVERSION: - mapisq3 = false; + prv->mapisq3 = false; mod->engineflags |= MDLF_NEEDOVERBRIGHT; for (i=0 ; iportalopen, 1, sizeof(prv->portalopen)); //open them all. Used for progs that havn't got a clue. else - memset (portalopen, 0, sizeof(portalopen)); //make them start closed. - FloodAreaConnections (); + memset (prv->portalopen, 0, sizeof(prv->portalopen)); //make them start closed. + FloodAreaConnections (prv); mod->checksum = mod->checksum2 = *checksum; @@ -4170,9 +4187,9 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole mod->numsubmodels = CM_NumInlineModels(mod); - mod->hulls[0].firstclipnode = map_cmodels[0].headnode-mod->nodes; - mod->rootnode = map_cmodels[0].headnode; - mod->nummodelsurfaces = map_cmodels[0].numsurfaces; + mod->hulls[0].firstclipnode = prv->cmodels[0].headnode-mod->nodes; + mod->rootnode = prv->cmodels[0].headnode; + mod->nummodelsurfaces = prv->cmodels[0].numsurfaces; #ifndef SERVERONLY if (qrenderer != QR_NONE) @@ -4200,7 +4217,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole Q_strncpyz(mod->name, name, sizeof(mod->name)); memset(&mod->memgroup, 0, sizeof(mod->memgroup)); - bm = CM_InlineModel (name); + bm = CM_InlineModel (wmod, name); @@ -4249,7 +4266,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole mod->terrain = Mod_LoadTerrainInfo(mod, loadname, false); #endif - return &map_cmodels[0]; + return &prv->cmodels[0]; } /* @@ -4257,8 +4274,9 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole CM_InlineModel ================== */ -cmodel_t *CM_InlineModel (char *name) +static cmodel_t *CM_InlineModel (model_t *model, char *name) { + cminfo_t *prv = (cminfo_t*)model->meshinfo; int num; if (!name) @@ -4268,25 +4286,27 @@ cmodel_t *CM_InlineModel (char *name) num = atoi (name+1); - if (num < 1 || num >= numcmodels) + if (num < 1 || num >= prv->numcmodels) Host_Error ("CM_InlineModel: bad number"); - return &map_cmodels[num]; + return &prv->cmodels[num]; } int CM_NumClusters (model_t *model) { - return numclusters; + return model->numclusters; } int CM_ClusterSize (model_t *model) { - return map_q3pvs->rowsize ? map_q3pvs->rowsize : MAX_MAP_LEAFS / 8; + cminfo_t *prv = (cminfo_t*)model->meshinfo; + return prv->q3pvs->rowsize ? prv->q3pvs->rowsize : MAX_MAP_LEAFS / 8; } -int CM_NumInlineModels (model_t *model) +static int CM_NumInlineModels (model_t *model) { - return numcmodels; + cminfo_t *prv = (cminfo_t*)model->meshinfo; + return prv->numcmodels; } int CM_LeafContents (model_t *model, int leafnum) @@ -4312,12 +4332,24 @@ int CM_LeafArea (model_t *model, int leafnum) //======================================================================= +#define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist) -mplane_t *box_planes; -int box_headnode; -q2cbrush_t *box_brush; -mleaf_t box_leaf[2]; //solid, empty -model_t box_model; +mplane_t box_planes[6]; +model_t box_model; +q2cbrush_t box_brush; +q2cbrushside_t box_sides[6]; +static qboolean BM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace); +static unsigned int BM_NativeContents(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs) +{ + unsigned int j; + q2cbrushside_t *brushside = box_sides; + for ( j = 0; j < 6; j++, brushside++ ) + { + if ( PlaneDiff (p, brushside->plane) > 0 ) + return 0; + } + return FTECONTENTS_BODY; +} /* =================== @@ -4331,11 +4363,10 @@ void CM_InitBoxHull (void) { int i; int side; - mnode_t *c; mplane_t *p; q2cbrushside_t *s; - +/* #ifndef CLIENTONLY box_model.funcs.FatPVS = Q2BSP_FatPVS; box_model.funcs.EdictInFatPVS = Q2BSP_EdictInFatPVS; @@ -4347,51 +4378,26 @@ void CM_InitBoxHull (void) #endif box_model.funcs.ClusterPVS = CM_ClusterPVS; box_model.funcs.ClusterForPoint = CM_PointCluster; - box_model.funcs.NativeContents = CM_NativeContents; - box_model.funcs.NativeTrace = CM_NativeTrace; +*/ + box_model.funcs.NativeContents = BM_NativeContents; + box_model.funcs.NativeTrace = BM_NativeTrace; - box_model.nodes = ZG_Malloc(&box_model.memgroup, sizeof(mnode_t)*6); - box_planes = ZG_Malloc(&box_model.memgroup, sizeof(mplane_t)*12); - if (numbrushes+1 > SANITY_MAX_MAP_BRUSHES - || numleafbrushes+1 > MAX_Q2MAP_LEAFBRUSHES) - Host_Error ("Not enough room for box tree"); - box_brush = &map_brushes[numbrushes]; - box_brush->numsides = 6; - box_brush->brushside = ZG_Malloc(&box_model.memgroup, sizeof(q2cbrushside_t)*6); - box_brush->contents = Q2CONTENTS_MONSTER; - - box_leaf[0].contents = Q2CONTENTS_MONSTER; - box_leaf[0].firstleafbrush = numleafbrushes; - box_leaf[0].numleafbrushes = 1; - box_leaf[1].contents = 0; - box_leaf[1].firstleafbrush = numleafbrushes; - box_leaf[1].numleafbrushes = 1; - box_model.leafs = box_leaf; - - box_model.rootnode = box_model.nodes; box_model.loadstate = MLS_LOADED; - map_leafbrushes[numleafbrushes] = box_brush; + box_brush.contents = FTECONTENTS_BODY; + box_brush.numsides = 6; + box_brush.brushside = box_sides; for (i=0 ; i<6 ; i++) { side = i&1; // brush sides - s = &box_brush->brushside[i]; + s = &box_sides[i]; s->plane = box_planes + (i*2+side); s->surface = &nullsurface; - // nodes - c = &box_model.nodes[i]; - c->plane = box_planes + (i*2); - c->childnum[side] = -1 - 1; //empty leaf - if (i != 5) - c->childnum[side^1] = box_headnode+i + 1; - else - c->childnum[side^1] = -1 - 0; //solid leaf - // planes p = &box_planes[i*2]; p->type = i>>1; @@ -4566,9 +4572,9 @@ CM_PointContents ================== */ -#define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist) int CM_PointContents (model_t *mod, vec3_t p) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; int i, j, contents; mleaf_t *leaf; q2cbrush_t *brush; @@ -4593,7 +4599,7 @@ int CM_PointContents (model_t *mod, vec3_t p) for (i = 0; i < leaf->numleafbrushes; i++) { - brush = map_leafbrushes[leaf->firstleafbrush + i]; + brush = prv->leafbrushes[leaf->firstleafbrush + i]; // check if brush actually adds something to contents if ( (contents & brush->contents) == brush->contents ) { @@ -4620,6 +4626,7 @@ int CM_PointContents (model_t *mod, vec3_t p) unsigned int CM_NativeContents(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs) { + cminfo_t *prv = (cminfo_t*)model->meshinfo; int contents; if (!DotProduct(mins, mins) && !DotProduct(maxs, maxs)) return CM_PointContents(model, p); @@ -4647,7 +4654,7 @@ unsigned int CM_NativeContents(struct model_s *model, int hulloverride, int fram { //q3 is more complex for (i = 0; i < leaf->numleafbrushes; i++) { - brush = map_leafbrushes[leaf->firstleafbrush + i]; + brush = prv->leafbrushes[leaf->firstleafbrush + i]; // check if brush actually adds something to contents if ( (contents & brush->contents) == brush->contents ) { @@ -4691,8 +4698,7 @@ int CM_TransformedPointContents (model_t *mod, vec3_t p, int headnode, vec3_t or VectorSubtract (p, origin, p_l); // rotate start and end into the models frame of reference - if (headnode != box_headnode && - (angles[0] || angles[1] || angles[2]) ) + if (angles[0] || angles[1] || angles[2]) { AngleVectors (angles, forward, right, up); @@ -5332,7 +5338,7 @@ static void CM_TestBoxInPatch (vec3_t mins, vec3_t maxs, vec3_t p1, CM_TraceToLeaf ================ */ -static void CM_TraceToLeaf (mleaf_t *leaf) +static void CM_TraceToLeaf (cminfo_t *prv, mleaf_t *leaf) { int k, j; q2cbrush_t *b; @@ -5346,7 +5352,7 @@ static void CM_TraceToLeaf (mleaf_t *leaf) // trace line against all brushes in the leaf for (k=0 ; knumleafbrushes ; k++) { - b = map_leafbrushes[leaf->firstleafbrush+k]; + b = prv->leafbrushes[leaf->firstleafbrush+k]; if (b->checkcount == checkcount) continue; // already checked this brush in another leaf b->checkcount = checkcount; @@ -5358,15 +5364,15 @@ static void CM_TraceToLeaf (mleaf_t *leaf) return; } - if (!mapisq3 || map_noCurves.value) + if (!prv->mapisq3 || map_noCurves.value) return; // trace line against all patches in the leaf for (k = 0; k < leaf->numleafpatches; k++) { - patchnum = map_leafpatches[leaf->firstleafpatch+k]; + patchnum = prv->leafpatches[leaf->firstleafpatch+k]; - patch = &map_patches[patchnum]; + patch = &prv->patches[patchnum]; if (patch->checkcount == checkcount) continue; // already checked this patch in another leaf patch->checkcount = checkcount; @@ -5384,8 +5390,8 @@ static void CM_TraceToLeaf (mleaf_t *leaf) for (k = 0; k < leaf->numleafcmeshes; k++) { - patchnum = map_leafcmeshes[leaf->firstleafcmesh+k]; - cmesh = &map_cmeshes[patchnum]; + patchnum = prv->leafcmeshes[leaf->firstleafcmesh+k]; + cmesh = &prv->cmeshes[patchnum]; if (cmesh->checkcount == checkcount) continue; // already checked this patch in another leaf cmesh->checkcount = checkcount; @@ -5406,7 +5412,7 @@ static void CM_TraceToLeaf (mleaf_t *leaf) CM_TestInLeaf ================ */ -static void CM_TestInLeaf (mleaf_t *leaf) +static void CM_TestInLeaf (cminfo_t *prv, mleaf_t *leaf) { int k, j; int patchnum; @@ -5419,7 +5425,7 @@ static void CM_TestInLeaf (mleaf_t *leaf) // trace line against all brushes in the leaf for (k=0 ; knumleafbrushes ; k++) { - b = map_leafbrushes[leaf->firstleafbrush+k]; + b = prv->leafbrushes[leaf->firstleafbrush+k]; if (b->checkcount == checkcount) continue; // already checked this brush in another leaf b->checkcount = checkcount; @@ -5431,15 +5437,15 @@ static void CM_TestInLeaf (mleaf_t *leaf) return; } - if (!mapisq3 || map_noCurves.value) + if (!prv->mapisq3 || map_noCurves.value) return; // trace line against all patches in the leaf for (k = 0; k < leaf->numleafpatches; k++) { - patchnum = map_leafpatches[leaf->firstleafpatch+k]; + patchnum = prv->leafpatches[leaf->firstleafpatch+k]; - patch = &map_patches[patchnum]; + patch = &prv->patches[patchnum]; if (patch->checkcount == checkcount) continue; // already checked this patch in another leaf patch->checkcount = checkcount; @@ -5457,8 +5463,8 @@ static void CM_TestInLeaf (mleaf_t *leaf) for (k = 0; k < leaf->numleafcmeshes; k++) { - patchnum = map_leafcmeshes[leaf->firstleafcmesh+k]; - cmesh = &map_cmeshes[patchnum]; + patchnum = prv->leafcmeshes[leaf->firstleafcmesh+k]; + cmesh = &prv->cmeshes[patchnum]; if (cmesh->checkcount == checkcount) continue; // already checked this patch in another leaf cmesh->checkcount = checkcount; @@ -5498,7 +5504,7 @@ static void CM_RecursiveHullCheck (model_t *mod, int num, float p1f, float p2f, // if < 0, we are in a leaf node if (num < 0) { - CM_TraceToLeaf (&mod->leafs[-1-num]); + CM_TraceToLeaf (mod->meshinfo, &mod->leafs[-1-num]); return; } @@ -5728,7 +5734,7 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, numleafs = CM_BoxLeafnums_headnode (mod, c1, c2, leafs, sizeof(leafs)/sizeof(leafs[0]), mod->hulls[0].firstclipnode, &topnode); for (i=0 ; ileafs[leafs[i]]); + CM_TestInLeaf (mod->meshinfo, &mod->leafs[leafs[i]]); if (trace_trace.allsolid) break; } @@ -5759,6 +5765,42 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, return trace_trace; } +static qboolean BM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace) +{ + int i; + memset (trace, 0, sizeof(*trace)); + trace_truefraction = 1; + trace_nearfraction = 1; + trace->fraction = 1; + trace->truefraction = 1; + trace->surface = &(nullsurface.c); + + if (contents & FTECONTENTS_BODY) + { + trace_contents = contents; + VectorCopy (start, trace_start); + VectorCopy (end, trace_end); + VectorCopy (mins, trace_mins); + VectorCopy (maxs, trace_maxs); + + CM_ClipBoxToBrush (trace_mins, trace_maxs, trace_start, trace_end, trace, &box_brush); + } + + if (trace_nearfraction == 1) + { + trace_trace.fraction = 1; + VectorCopy (trace_end, trace_trace.endpos); + } + else + { + if (trace_nearfraction<0) + trace_nearfraction=0; + trace_trace.fraction = trace_nearfraction; + for (i=0 ; i<3 ; i++) + trace_trace.endpos[i] = trace_start[i] + trace_trace.fraction * (trace_end[i] - trace_start[i]); + } + return trace->fraction != 1; +} static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace) { if (axis) @@ -5979,16 +6021,17 @@ qbyte *Mod_ClusterPVS (int cluster, model_t *model) model); } */ -static void CM_DecompressVis (qbyte *in, qbyte *out) +static void CM_DecompressVis (model_t *mod, qbyte *in, qbyte *out) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; int c; qbyte *out_p; int row; - row = (numclusters+7)>>3; + row = (mod->numclusters+7)>>3; out_p = out; - if (!in || !numvisibility) + if (!in || !prv->numvisibility) { // no vis info, so make all visible while (row) { @@ -6028,53 +6071,55 @@ static qbyte phsrow[MAX_MAP_LEAFS/8]; qbyte *CM_ClusterPVS (model_t *mod, int cluster, qbyte *buffer, unsigned int buffersize) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; if (!buffer) { buffer = pvsrow; buffersize = sizeof(pvsrow); } - if (buffersize < (numclusters+7)>>3) + if (buffersize < (mod->numclusters+7)>>3) Sys_Error("CM_ClusterPVS with too small a buffer\n"); if (mod->fromgame != fg_quake2) { - if (cluster != -1 && map_q3pvs->numclusters) + if (cluster != -1 && prv->q3pvs->numclusters) { - return (qbyte *)map_q3pvs->data + cluster * map_q3pvs->rowsize; + return (qbyte *)prv->q3pvs->data + cluster * prv->q3pvs->rowsize; } else { - memset (buffer, 0, (numclusters+7)>>3); + memset (buffer, 0, (mod->numclusters+7)>>3); return buffer; } } if (cluster == -1) - memset (buffer, 0, (numclusters+7)>>3); + memset (buffer, 0, (mod->numclusters+7)>>3); else - CM_DecompressVis (((qbyte*)map_q2vis) + map_q2vis->bitofs[cluster][DVIS_PVS], buffer); + CM_DecompressVis (mod, ((qbyte*)prv->q2vis) + prv->q2vis->bitofs[cluster][DVIS_PVS], buffer); return buffer; } qbyte *CM_ClusterPHS (model_t *mod, int cluster) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; if (mod->fromgame != fg_quake2) { - if (cluster != -1 && map_q3phs->numclusters) + if (cluster != -1 && prv->q3phs->numclusters) { - return (qbyte *)map_q3phs->data + cluster * map_q3phs->rowsize; + return (qbyte *)prv->q3phs->data + cluster * prv->q3phs->rowsize; } else { - memset (phsrow, 0, (numclusters+7)>>3); + memset (phsrow, 0, (mod->numclusters+7)>>3); return phsrow; } } if (cluster == -1) - memset (phsrow, 0, (numclusters+7)>>3); + memset (phsrow, 0, (mod->numclusters+7)>>3); else - CM_DecompressVis (((qbyte*)map_q2vis) + map_q2vis->bitofs[cluster][DVIS_PHS], phsrow); + CM_DecompressVis (mod, ((qbyte*)prv->q2vis) + prv->q2vis->bitofs[cluster][DVIS_PHS], phsrow); return phsrow; } @@ -6087,11 +6132,11 @@ AREAPORTALS =============================================================================== */ -static void FloodArea_r (q2carea_t *area, int floodnum) +static void FloodArea_r (cminfo_t *prv, q2carea_t *area, int floodnum) { int i; - if (area->floodvalid == floodvalid) + if (area->floodvalid == prv->floodvalid) { if (area->floodnum == floodnum) return; @@ -6099,22 +6144,22 @@ static void FloodArea_r (q2carea_t *area, int floodnum) } area->floodnum = floodnum; - area->floodvalid = floodvalid; - if (mapisq3) + area->floodvalid = prv->floodvalid; + if (prv->mapisq3) { - for (i=0 ; inumareas ; i++) { - if (map_q3areas[area - map_q2areas].numareaportals[i]>0) - FloodArea_r (&map_q2areas[i], floodnum); + if (prv->q3areas[area - prv->q2areas].numareaportals[i]>0) + FloodArea_r (prv, &prv->q2areas[i], floodnum); } } else { - q2dareaportal_t *p = &map_areaportals[area->firstareaportal]; + q2dareaportal_t *p = &prv->areaportals[area->firstareaportal]; for (i=0 ; inumareaportals ; i++, p++) { - if (portalopen[p->portalnum]) - FloodArea_r (&map_q2areas[p->otherarea], floodnum); + if (prv->portalopen[p->portalnum]) + FloodArea_r (prv, &prv->q2areas[p->otherarea], floodnum); } } } @@ -6126,77 +6171,84 @@ FloodAreaConnections ==================== */ -static void FloodAreaConnections (void) +static void FloodAreaConnections (cminfo_t *prv) { int i; q2carea_t *area; int floodnum; // all current floods are now invalid - floodvalid++; + prv->floodvalid++; floodnum = 0; // area 0 is not used - for (i=0 ; inumareas ; i++) { - area = &map_q2areas[i]; - if (area->floodvalid == floodvalid) + area = &prv->q2areas[i]; + if (area->floodvalid == prv->floodvalid) continue; // already flooded into floodnum++; - FloodArea_r (area, floodnum); + FloodArea_r (prv, area, floodnum); } } -void VARGS CMQ2_SetAreaPortalState (unsigned int portalnum, qboolean open) +void CMQ2_SetAreaPortalState (model_t *mod, unsigned int portalnum, qboolean open) { - if (mapisq3) + cminfo_t *prv; + if (!mod) return; - if (portalnum > numareaportals) + prv = (cminfo_t*)mod->meshinfo; + if (prv->mapisq3) + return; + if (portalnum > prv->numareaportals) Host_Error ("areaportal > numareaportals"); - if (portalopen[portalnum] == open) + if (prv->portalopen[portalnum] == open) return; - portalopen[portalnum] = open; - FloodAreaConnections (); + prv->portalopen[portalnum] = open; + FloodAreaConnections (prv); return; } -void CMQ3_SetAreaPortalState (unsigned int area1, unsigned int area2, qboolean open) +void CMQ3_SetAreaPortalState (model_t *mod, unsigned int area1, unsigned int area2, qboolean open) { - if (!mapisq3) + cminfo_t *prv = (cminfo_t*)mod->meshinfo; + if (!prv->mapisq3) return; // Host_Error ("CMQ3_SetAreaPortalState on non-q3 map"); - if (area1 >= numareas || area2 >= numareas) + if (area1 >= prv->numareas || area2 >= prv->numareas) Host_Error ("CMQ3_SetAreaPortalState: area > numareas"); if (open) { - map_q3areas[area1].numareaportals[area2]++; - map_q3areas[area2].numareaportals[area1]++; + prv->q3areas[area1].numareaportals[area2]++; + prv->q3areas[area2].numareaportals[area1]++; } else { - map_q3areas[area1].numareaportals[area2]--; - map_q3areas[area2].numareaportals[area1]--; + prv->q3areas[area1].numareaportals[area2]--; + prv->q3areas[area2].numareaportals[area1]--; } - FloodAreaConnections(); + FloodAreaConnections(prv); } qboolean VARGS CM_AreasConnected (model_t *mod, unsigned int area1, unsigned int area2) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; + if (map_noareas.value) return true; if (area1 == ~0 || area2 == ~0) return area1 == area2; - if (area1 > numareas || area2 > numareas) + if (area1 > prv->numareas || area2 > prv->numareas) Host_Error ("area > numareas"); - if (map_q2areas[area1].floodnum == map_q2areas[area2].floodnum) + if (prv->q2areas[area1].floodnum == prv->q2areas[area2].floodnum) return true; return false; } @@ -6214,11 +6266,12 @@ This is used by the client refreshes to cull visibility */ int CM_WriteAreaBits (model_t *mod, qbyte *buffer, int area) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; int i; int floodnum; int bytes; - bytes = (numareas+7)>>3; + bytes = (prv->numareas+7)>>3; if (map_noareas.value) { // for debugging, send everything @@ -6228,10 +6281,10 @@ int CM_WriteAreaBits (model_t *mod, qbyte *buffer, int area) { memset (buffer, 0, bytes); - floodnum = map_q2areas[area].floodnum; - for (i=0 ; iq2areas[area].floodnum; + for (i=0 ; inumareas ; i++) { - if (map_q2areas[i].floodnum == floodnum || !area) + if (prv->q2areas[i].floodnum == floodnum || !area) buffer[i>>3] |= 1<<(i&7); } } @@ -6246,9 +6299,10 @@ CM_WritePortalState Writes the portal state to a savegame file =================== */ -void CM_WritePortalState (vfsfile_t *f) +void CM_WritePortalState (model_t *mod, vfsfile_t *f) { - VFS_WRITE(f, portalopen, sizeof(portalopen)); + cminfo_t *prv = (cminfo_t*)mod->meshinfo; + VFS_WRITE(f, prv->portalopen, sizeof(prv->portalopen)); } /* @@ -6259,16 +6313,17 @@ Reads the portal state from a savegame file and recalculates the area connections =================== */ -void CM_ReadPortalState (vfsfile_t *f) +void CM_ReadPortalState (model_t *mod, vfsfile_t *f) { + cminfo_t *prv = (cminfo_t*)mod->meshinfo; size_t result; - result = VFS_READ(f, portalopen, sizeof(portalopen)); // do something with result + result = VFS_READ(f, prv->portalopen, sizeof(prv->portalopen)); // do something with result - if (result != sizeof(portalopen)) - Con_Printf("CM_ReadPortalState() fread: expected %lu, result was %u\n",(long unsigned int)sizeof(portalopen),(unsigned int)result); + if (result != sizeof(prv->portalopen)) + Con_Printf("CM_ReadPortalState() fread: expected %u, result was %u\n",(unsigned int)sizeof(prv->portalopen),(unsigned int)result); - FloodAreaConnections (); + FloodAreaConnections (prv); } /* @@ -6334,7 +6389,5 @@ void CM_Init(void) //register cvars. } void CM_Shutdown(void) { - ZG_FreeGroup(&box_model.memgroup); - box_planes = NULL; } #endif diff --git a/engine/common/mathlib.c b/engine/common/mathlib.c index 21b8dd6df..2f3f666a5 100644 --- a/engine/common/mathlib.c +++ b/engine/common/mathlib.c @@ -160,18 +160,6 @@ float anglemod(float a) return a; } -/* -================== -BOPS_Error - -Split out like this for ASM to call. -================== -*/ -void VARGS BOPS_Error (void) -{ - Sys_Error ("BoxOnPlaneSide: Bad signbits"); -} - /* ================== BoxOnPlaneSide @@ -200,6 +188,7 @@ int VARGS BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, mplane_t *p) // general case switch (p->signbits) { + default: case 0: dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; @@ -232,10 +221,6 @@ dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; break; - default: - dist1 = dist2 = 0; // shut up compiler - BOPS_Error (); - break; } #if 0 @@ -313,7 +298,7 @@ void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up) CrossProduct(right, forward, up); } -void VectorAngles(float *forward, float *up, float *result) //up may be NULL +void QDECL VectorAngles(float *forward, float *up, float *result) //up may be NULL { float yaw, pitch, roll; @@ -666,7 +651,7 @@ void FloorDivMod (double numer, double denom, int *quotient, int q, r; double x; -#ifndef PARANOID +#ifdef PARANOID if (denom <= 0.0) Sys_Error ("FloorDivMod: bad denominator %f\n", denom); diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index 27da9753b..b8aebdd62 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -90,6 +90,7 @@ extern vec3_t vec3_origin; #define Vector2Clear(a) ((a)[0]=(a)[1]=0) #define Vector2Copy(a,b) do{(b)[0]=(a)[0];(b)[1]=(a)[1];}while(0) #define Vector2Set(r,x,y) do{(r)[0] = x; (r)[1] = y;}while(0) +#define Vector2MA(a,s,b,c) do{(c)[0] = (a)[0] + (s)*(b)[0];(c)[1] = (a)[1] + (s)*(b)[1];}while(0) #define Vector2Interpolate(a, bness, b, c) FloatInterpolate((a)[0], bness, (b)[0], (c)[0]),FloatInterpolate((a)[1], bness, (b)[1], (c)[1]) #define Vector4Copy(a,b) do{(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];(b)[3]=(a)[3];}while(0) @@ -131,7 +132,7 @@ typedef struct { void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); float anglemod (float a); void QDECL AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); -void VectorAngles (float *forward, float *up, float *angles); //up may be NULL +void QDECL VectorAngles (float *forward, float *up, float *angles); //up may be NULL void VARGS BOPS_Error (void); int VARGS BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane); void ClearBounds (vec3_t mins, vec3_t maxs); diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index 455b7d5c3..5c4e43def 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -88,7 +88,7 @@ cvar_t net_mtu = CVARD("net_mtu", "1440", "Specifies a maximum udp payload size, cvar_t net_compress = CVARD("net_compress", "0", "Enables huffman compression of network packets."); cvar_t pext_replacementdeltas = CVAR("pext_replacementdeltas", "1"); -cvar_t pext_nqpredinfo = CVAR("debug_pext_nqpredinfo", "0"); +cvar_t pext_predinfo = CVAR("debug_pext_predinfo", "0"); /*returns the entire bitmask of supported+enabled extensions*/ unsigned int Net_PextMask(int maskset, qboolean fornq) @@ -198,7 +198,7 @@ unsigned int Net_PextMask(int maskset, qboolean fornq) if (pext_replacementdeltas.ival) mask |= PEXT2_REPLACEMENTDELTAS; - if (/*fornq &&*/ pext_nqpredinfo.ival) + if (/*fornq &&*/ pext_predinfo.ival) mask |= PEXT2_PREDINFO; if (MAX_CLIENTS != QWMAX_CLIENTS) @@ -242,7 +242,7 @@ void Netchan_Init (void) Q_snprintfz(qportstr, sizeof(qportstr), "%i", port); qport.string = qportstr; - Cvar_Register (&pext_nqpredinfo, "Protocol Extensions"); + Cvar_Register (&pext_predinfo, "Protocol Extensions"); Cvar_Register (&pext_replacementdeltas, "Protocol Extensions"); Cvar_Register (&showpackets, "Networking"); Cvar_Register (&showdrop, "Networking"); diff --git a/engine/common/plugin.c b/engine/common/plugin.c index f189d60e1..dbcb20c92 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -15,6 +15,22 @@ cvar_t plug_sbar = SCVAR("plug_sbar", "1"); cvar_t plug_loaddefault = SCVAR("plug_loaddefault", "1"); +qintptr_t Plug_Bullet_Init(qintptr_t *args); +qintptr_t Plug_ODE_Init(qintptr_t *args); +struct +{ + const char *name; + qintptr_t (*initfunction)(qintptr_t *args); +} staticplugins[] = +{ +#ifdef USERBE +// {"Bullet", Plug_Bullet_Init}, + {"ODE", Plug_ODE_Init}, +#endif + {NULL} +}; + + #ifdef GLQUAKE #include "glquake.h" #endif @@ -22,7 +38,7 @@ cvar_t plug_loaddefault = SCVAR("plug_loaddefault", "1"); //custom plugin builtins. typedef qintptr_t (EXPORT_FN *Plug_Builtin_t)(void *offset, quintptr_t mask, const qintptr_t *arg); void Plug_RegisterBuiltin(char *name, Plug_Builtin_t bi, int flags); -#define PLUG_BIF_DLLONLY 1 +#define PLUG_BIF_DLLONLY 1 //WARNING: it is not enough to just specify this flag, but also the builtin code must return if there is an offset passed. #define PLUG_BIF_QVMONLY 2 #define PLUG_BIF_NEEDSRENDERER 4 @@ -120,6 +136,8 @@ void Plug_RegisterBuiltin(char *name, Plug_Builtin_t bi, int flags) static qintptr_t VARGS Plug_GetNativePointer(void *offset, quintptr_t mask, const qintptr_t *args) { char *p = (char *)VM_POINTER(args[0]); + if (offset) //QVMs are not allowed to call this + return 0; #ifdef SUPPORT_ICE if (!strcmp(p, ICE_API_CURRENT)) return (qintptr_t)&iceapi; @@ -152,7 +170,7 @@ static void Plug_RegisterBuiltinIndex(char *name, Plug_Builtin_t bi, int flags, } */ -static qintptr_t Plug_FindBuiltin(qboolean native, char *p) +static qintptr_t Plug_FindBuiltin(qboolean native, const char *p) { int i; for (i = 0; i < numplugbuiltins; i++) @@ -228,15 +246,15 @@ static qintptr_t EXPORT_FN Plug_SystemCallsNative(qintptr_t arg, ...) Sys_Error("DLL Plugin tried calling invalid builtin %i", (int)arg); return 0; } +qintptr_t (QDECL *plugin_syscall)( qintptr_t arg, ... ) = Plug_SystemCallsNative; - -plugin_t *Plug_Load(char *file, int type) +plugin_t *Plug_Load(const char *file, int type) { plugin_t *newplug; for (newplug = plugs; newplug; newplug = newplug->next) { - if (!stricmp(newplug->name, file)) + if (!Q_strcasecmp(newplug->name, file)) return newplug; } @@ -248,11 +266,21 @@ plugin_t *Plug_Load(char *file, int type) newplug->vm = VM_Create(va("fteplug_%s", file), Plug_SystemCallsNative, NULL); if (!newplug->vm && (type & PLUG_QVM)) newplug->vm = VM_Create(file, NULL, Plug_SystemCallsVM); + if (!newplug->vm && (type & PLUG_NATIVE)) + { + unsigned int u; + for (u = 0; staticplugins[u].name; u++) + { + if (!Q_strcasecmp(file, staticplugins[u].name)) + newplug->vm = VM_CreateBuiltin(file, Plug_SystemCallsNative, staticplugins[u].initfunction); + break; + } + } currentplug = newplug; if (newplug->vm) { - Con_TPrintf("Created plugin %s\n", file); + Con_DPrintf("Created plugin %s\n", file); newplug->next = plugs; plugs = newplug; @@ -278,7 +306,7 @@ plugin_t *Plug_Load(char *file, int type) return newplug; } -static int QDECL Plug_Emumerated (const char *name, qofs_t size, void *param, searchpathfuncs_t *spath) +static int QDECL Plug_Emumerated (const char *name, qofs_t size, time_t mtime, void *param, searchpathfuncs_t *spath) { char vmname[MAX_QPATH]; Q_strncpyz(vmname, name, sizeof(vmname)); @@ -288,7 +316,7 @@ static int QDECL Plug_Emumerated (const char *name, qofs_t size, void *param, se return true; } -static int QDECL Plug_EnumeratedRoot (const char *name, qofs_t size, void *param, searchpathfuncs_t *spath) +static int QDECL Plug_EnumeratedRoot (const char *name, qofs_t size, time_t mtime, void *param, searchpathfuncs_t *spath) { char vmname[MAX_QPATH]; int len; @@ -328,6 +356,19 @@ static qintptr_t VARGS Plug_Sys_Milliseconds(void *offset, quintptr_t mask, cons { return Sys_DoubleTime()*1000; } +static qintptr_t VARGS Plug_Sys_LoadLibrary(void *offset, quintptr_t mask, const qintptr_t *arg) +{ + if (offset) + return 0; + return (qintptr_t)Sys_LoadLibrary(VM_POINTER(arg[0]), VM_POINTER(arg[1])); +} +static qintptr_t VARGS Plug_Sys_CloseLibrary(void *offset, quintptr_t mask, const qintptr_t *arg) +{ + if (offset) + return 0; + Sys_CloseLibrary(VM_POINTER(arg[0])); + return 1; +} static qintptr_t VARGS Plug_ExportToEngine(void *offset, quintptr_t mask, const qintptr_t *arg) { char *name = (char*)VM_POINTER(arg[0]); @@ -403,6 +444,10 @@ static qintptr_t VARGS Plug_ExportNative(void *offset, quintptr_t mask, const qi { void *func; char *name = (char*)VM_POINTER(arg[0]); + + if (offset) //QVMs are not allowed to call this + return 0; + arg++; func = ((void**)arg)[0]; @@ -456,6 +501,18 @@ static qintptr_t VARGS Plug_ExportNative(void *offset, quintptr_t mask, const qi return 1; } +static qintptr_t VARGS Plug_Cvar_GetNVFDG(void *offset, quintptr_t mask, const qintptr_t *arg) +{ + char *name = VM_POINTER(arg[0]); + char *defaultvalue = VM_POINTER(arg[1]); + unsigned int flags = VM_LONG(arg[2]); + char *description = VM_POINTER(arg[3]); + char *groupname = VM_POINTER(arg[4]); + + return (qintptr_t)Cvar_Get2(name, defaultvalue, flags&1, description, groupname); +} + + typedef struct { //Make SURE that the engine has resolved all cvar pointers into globals before this happens. plugin_t *plugin; @@ -926,7 +983,7 @@ qintptr_t VARGS Plug_VFS_Open(void *offset, quintptr_t mask, const qintptr_t *ar char *fname = VM_POINTER(arg[0]); vfsfile_t **handle = VM_POINTER(arg[1]); char *mode = VM_POINTER(arg[2]); - *handle = FS_OpenVFS(fname, mode, FS_GAME); + *handle = offset?NULL:FS_OpenVFS(fname, mode, FS_GAME); if (*handle) return true; return false; @@ -1282,7 +1339,7 @@ void Plug_Initialise(qboolean fromgamedir) Cmd_AddCommand("plug_load", Plug_Load_f); Cmd_AddCommand("plug_list", Plug_List_f); - Plug_RegisterBuiltin("Plug_GetNativePointer", Plug_GetNativePointer, 0);//plugin wishes to find a builtin number. + Plug_RegisterBuiltin("Plug_GetNativePointer", Plug_GetNativePointer, PLUG_BIF_DLLONLY);//plugin wishes to get a native interface. Plug_RegisterBuiltin("Plug_GetEngineFunction", Plug_GetBuiltin, 0);//plugin wishes to find a builtin number. Plug_RegisterBuiltin("Plug_ExportToEngine", Plug_ExportToEngine, 0); //plugin has a call back that we might be interested in. Plug_RegisterBuiltin("Plug_ExportNative", Plug_ExportNative, PLUG_BIF_DLLONLY); @@ -1304,6 +1361,7 @@ void Plug_Initialise(qboolean fromgamedir) Plug_RegisterBuiltin("Cvar_SetFloat", Plug_Cvar_SetFloat, 0); Plug_RegisterBuiltin("Cvar_GetString", Plug_Cvar_GetString, 0); Plug_RegisterBuiltin("Cvar_GetFloat", Plug_Cvar_GetFloat, 0); + Plug_RegisterBuiltin("Cvar_GetNVFDG", Plug_Cvar_GetNVFDG, PLUG_BIF_DLLONLY); #ifdef HAVE_PACKET Plug_RegisterBuiltin("Net_TCPListen", Plug_Net_TCPListen, 0); @@ -1338,11 +1396,15 @@ void Plug_Initialise(qboolean fromgamedir) Plug_RegisterBuiltin("ReadInputBuffer", Plug_ReadInputBuffer, 0); Plug_RegisterBuiltin("UpdateInputBuffer", Plug_UpdateInputBuffer, 0); + Plug_RegisterBuiltin("Sys_LoadLibrary", Plug_Sys_LoadLibrary, PLUG_BIF_DLLONLY); + Plug_RegisterBuiltin("Sys_CloseLibrary", Plug_Sys_CloseLibrary, PLUG_BIF_DLLONLY); + Plug_Client_Init(); } if (plug_loaddefault.value) { + unsigned int u; if (!fromgamedir) { FS_NativePath("", FS_BINARYPATH, nat, sizeof(nat)); @@ -1353,6 +1415,10 @@ void Plug_Initialise(qboolean fromgamedir) { COM_EnumerateFiles("plugins/*.qvm", Plug_Emumerated, ".qvm"); } + for (u = 0; staticplugins[u].name; u++) + { + Plug_Load(staticplugins[u].name, PLUG_NATIVE); + } } } @@ -1659,7 +1725,7 @@ void Plug_Close(plugin_t *plug) } if (!com_fatalerror) - Con_Printf("Closing plugin %s\n", plug->name); + Con_DPrintf("Closing plugin %s\n", plug->name); //ensure any active contexts provided by the plugin are closed (stuff with destroy callbacks) #if defined(PLUGINS) && !defined(NOMEDIA) && !defined(SERVERONLY) @@ -1805,4 +1871,16 @@ void Plug_Shutdown(qboolean preliminary) } } + +//for built-in plugins +qboolean Plug_Export(const char *name, qintptr_t(QDECL *func)(qintptr_t *args)) +{ + qintptr_t args[] = {(qintptr_t)name, (qintptr_t)func}; + return Plug_ExportToEngine(NULL, ~(size_t)0, args); +} +void *pPlug_GetEngineFunction(const char *funcname) +{ + return (void*)Plug_FindBuiltin(true, funcname); +} + #endif diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 9601d6cc2..2f36d43d8 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -24,6 +24,8 @@ cvar_t pr_enable_uriget = CVAR("pr_enable_uriget", "1"); cvar_t pr_enable_profiling = CVARD("pr_enable_profiling", "0", "Enables profiling support. Will run more slowly. Change the map and then use the profile_ssqc/profile_csqc commands to see the results."); int tokenizeqc(const char *str, qboolean dpfuckage); +void PF_buf_shutdown(pubprogfuncs_t *prinst); + void skel_info_f(void); void skel_generateragdoll_f(void); void PF_Common_RegisterCvars(void) @@ -98,7 +100,7 @@ static int debuggerstacky; #include void INS_UpdateGrabs(int fullscreen, int activeapp); #endif -int QCLibEditor(pubprogfuncs_t *prinst, char *filename, int line, int statement, int nump, char **parms); +int QCLibEditor(pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, int nump, char **parms); void QCLoadBreakpoints(const char *vmname, const char *progsname) { //this asks the gui to reapply any active breakpoints and waits for them so that any spawn functions can be breakpointed properly. #if defined(_WIN32) && !defined(SERVERONLY) && !defined(FTE_SDL) @@ -106,11 +108,11 @@ void QCLoadBreakpoints(const char *vmname, const char *progsname) if (isPlugin >= 2) { Sys_SendKeyEvents(); - debuggerresume = false; + debuggerresume = -1; printf("qcreloaded \"%s\" \"%s\"\n", vmname, progsname); fflush(stdout); INS_UpdateGrabs(false, false); - while(debuggerresume != 2) + while(debuggerresume == -1) { Sleep(10); Sys_SendKeyEvents(); @@ -120,25 +122,48 @@ void QCLoadBreakpoints(const char *vmname, const char *progsname) } extern cvar_t pr_sourcedir; pubprogfuncs_t *debuggerinstance; +const char *debuggerfile; size_t debuggerwnd; qboolean QCExternalDebuggerCommand(char *text) { if ((!strncmp(text, "qcstep", 6) && (text[6] == 0 || text[6] == ' ')) || (!strncmp(text, "qcresume", 8) && (text[8] == 0 || text[8] == ' '))) { - int l; +// int l; if (text[2] == 's') { - debuggerresume = true; - l = atoi(text+7); + text += 6; + while(*text==' ' || *text=='\t') + text++; + if (!strncmp(text, "out", 3)) + debuggerresume = DEBUG_TRACE_OUT; + else if (!strncmp(text, "over", 3)) + debuggerresume = DEBUG_TRACE_OVER; + else + debuggerresume = DEBUG_TRACE_INTO; +// l = atoi(text+7); } else { - l = atoi(text+9); - debuggerresume = 2; +// l = atoi(text+9); + debuggerresume = DEBUG_TRACE_OFF; + } +// if (l) +// debuggerresumeline = l; + } + else if (!strncmp(text, "qcjump ", 7)) + { + char file[MAX_QPATH]; + char linebuf[32]; + text += 7; + text = COM_ParseOut(text, file, sizeof(file)); + text = COM_ParseOut(text, linebuf, sizeof(linebuf)); + + if (debuggerinstance && debuggerfile && !Q_strcasecmp(file, debuggerfile)) + { + debuggerresumeline = atoi(linebuf); + debuggerresume = DEBUG_TRACE_NORESUME; //'resume' from the debugger only to break again, so we know the new line number (if they tried setting the line to a blank one) } - if (l) - debuggerresumeline = l; } else if (!strncmp(text, "debuggerwnd ", 11)) { @@ -243,23 +268,34 @@ qboolean QCExternalDebuggerCommand(char *text) return true; } -int QDECL QCEditor (pubprogfuncs_t *prinst, char *filename, int line, int statement, int nump, char **parms) +int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, char *reason) { #if defined(_WIN32) && !defined(SERVERONLY) && !defined(FTE_SDL) if (isPlugin >= 2) { - if (!*filename) //don't try editing an empty line, it won't work - return line; + if (!*filename || !line || !*line) //don't try editing an empty line, it won't work + return DEBUG_TRACE_OFF; Sys_SendKeyEvents(); - debuggerresume = false; - debuggerresumeline = line; + debuggerresume = -1; + debuggerresumeline = *line; if (debuggerwnd) SetForegroundWindow((HWND)debuggerwnd); - printf("qcstep \"%s\":%i\n", filename, line); + if (reason) + { + char tmpbuffer[8192]; + printf("qcfault \"%s\":%i %s\n", filename, *line, COM_QuotedString(reason, tmpbuffer, sizeof(tmpbuffer), false)); + } + else + printf("qcstep \"%s\":%i\n", filename, *line); fflush(stdout); INS_UpdateGrabs(false, false); debuggerinstance = prinst; - while(!debuggerresume) + debuggerfile = filename; + if (reason) + Con_Footerf(false, "^bDebugging: %s", reason); + else + Con_Footerf(false, "^bDebugging"); + while(debuggerresume == -1) { Sleep(10); Sys_SendKeyEvents(); @@ -267,7 +303,7 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, char *filename, int line, int statem if (qrenderer) { //FIXME: display a stack trace and locals instead - R2D_ImageColours((sin(Sys_DoubleTime())+1)*0.5,0, 0, 1); + R2D_ImageColours(0.1, 0, 0, 1); R2D_FillBlock(0, 0, vid.width, vid.height); Con_DrawConsole(vid.height/2, true); //draw console at half-height debuggerstacky = vid.height/2; @@ -277,26 +313,15 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, char *filename, int line, int statem VID_SwapBuffers(); } } + *line = debuggerresumeline; debuggerinstance = NULL; - if (debuggerresume == 2) - prinst->pr_trace = false; - return debuggerresumeline; + debuggerfile = NULL; + return debuggerresume; } #endif #ifdef TEXTEDITOR - if (!parms) - return QCLibEditor(prinst, filename, line, statement, nump, parms); - else - { - static char oldfuncname[64]; - if (!nump && !strncmp(oldfuncname, *parms, sizeof(oldfuncname))) - { - Con_Printf("Executing %s: %s\n", *parms, filename); - Q_strncpyz(oldfuncname, *parms, sizeof(oldfuncname)); - } - return line; - } + return QCLibEditor(prinst, filename, line, statement, 0, NULL); #else { int i; @@ -304,12 +329,10 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, char *filename, int line, int statem char *r; vfsfile_t *f; - if (line == -1) - return line; #ifndef CLIENTONLY SV_EndRedirect(); #endif - if (developer.value) + if (developer.value && line) { f = FS_OpenVFS(filename, "rb", FS_GAME); } @@ -321,10 +344,15 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, char *filename, int line, int statem f = FS_OpenVFS(buffer, "rb", FS_GAME); } if (!f) - Con_Printf("-%s - %i\n", filename, line); + { + if (reason) + Con_Printf("-%s - %i: %s\n", filename, line?*line:*statement, reason); + else + Con_Printf("-%s - %i\n", filename, line?*line:*statement); + } else { - for (i = 0; i < line; i++) + for (i = 0; i < *line; i++) { VFS_GETS(f, buffer, sizeof(buffer)); } @@ -335,7 +363,7 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, char *filename, int line, int statem } } //PF_break(NULL); - return line; + return DEBUG_TRACE_OVER; #endif } @@ -461,8 +489,7 @@ void VARGS PR_BIError(pubprogfuncs_t *progfuncs, char *format, ...) if (developer.value || !progfuncs) { struct globalvars_s *pr_globals = PR_globals(progfuncs, PR_CURRENT); - Con_Printf("%s\n", string); - progfuncs->pr_trace = 1; + PR_RunWarning(progfuncs, "%s\n", string); G_INT(OFS_RETURN)=0; //just in case it was a float and should be an ent... G_INT(OFS_RETURN+1)=0; G_INT(OFS_RETURN+2)=0; @@ -2023,6 +2050,7 @@ void PF_fcloseall (pubprogfuncs_t *prinst) PF_fclose_i(i); } tokenizeqc("", false); + PF_buf_shutdown(prinst); //might as well put this here } @@ -2052,9 +2080,12 @@ typedef struct prvmsearch_s { int handle; pubprogfuncs_t *fromprogs; //share across menu/server int entries; - char **names; - int *sizes; - + struct + { + char *name; + qofs_t size; + time_t mtime; + } *entry; struct prvmsearch_s *next; } prvmsearch_t; prvmsearch_t *prvmsearches; @@ -2082,10 +2113,9 @@ void search_close (pubprogfuncs_t *prinst, int handle) for (i = 0; i < s->entries; i++) { - BZ_Free(s->names[i]); + BZ_Free(s->entry[i].name); } - BZ_Free(s->names); - BZ_Free(s->sizes); + BZ_Free(s->entry); BZ_Free(s); return; @@ -2116,10 +2146,9 @@ void search_close_progs(pubprogfuncs_t *prinst, qboolean complain) for (i = 0; i < s->entries; i++) { - BZ_Free(s->names[i]); + BZ_Free(s->entry[i].name); } - BZ_Free(s->names); - BZ_Free(s->sizes); + BZ_Free(s->entry); BZ_Free(s); if (prev) @@ -2137,15 +2166,15 @@ void search_close_progs(pubprogfuncs_t *prinst, qboolean complain) prvm_nextsearchhandle = 0; //might as well. } -int QDECL search_enumerate(const char *name, qofs_t fsize, void *parm, searchpathfuncs_t *spath) +int QDECL search_enumerate(const char *name, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath) { prvmsearch_t *s = parm; - s->names = BZ_Realloc(s->names, ((s->entries+64)&~63) * sizeof(char*)); - s->sizes = BZ_Realloc(s->sizes, ((s->entries+64)&~63) * sizeof(int)); - s->names[s->entries] = BZ_Malloc(strlen(name)+1); - strcpy(s->names[s->entries], name); - s->sizes[s->entries] = fsize; + s->entry = BZ_Realloc(s->entry, ((s->entries+64)&~63) * sizeof(*s->entry)); + s->entry[s->entries].name = BZ_Malloc(strlen(name)+1); + strcpy(s->entry[s->entries].name, name); + s->entry[s->entries].size = fsize; + s->entry[s->entries].mtime = mtime; s->entries++; return true; @@ -2222,7 +2251,64 @@ void QCBUILTIN PF_search_getfilename (pubprogfuncs_t *prinst, struct globalvars_ if (num < 0 || num >= s->entries) return; - RETURN_TSTRING(s->names[num]); + RETURN_TSTRING(s->entry[num].name); + return; + } + } + + PF_Warningf(prinst, "Search handle wasn't valid\n"); +} +void QCBUILTIN PF_search_getfilesize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int handle = G_FLOAT(OFS_PARM0); + int num = G_FLOAT(OFS_PARM1); + prvmsearch_t *s; + G_INT(OFS_RETURN) = 0; + + for (s = prvmsearches; s; s = s->next) + { + if (s->handle == handle) + { //close it down. + if (s->fromprogs != prinst) + { + PF_Warningf(prinst, "Search handle wasn't valid with that progs\n"); + return; + } + + if (num < 0 || num >= s->entries) + return; + G_FLOAT(OFS_RETURN) = s->entry[num].size; + return; + } + } + + PF_Warningf(prinst, "Search handle wasn't valid\n"); +} +void QCBUILTIN PF_search_getfilemtime (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int handle = G_FLOAT(OFS_PARM0); + int num = G_FLOAT(OFS_PARM1); + prvmsearch_t *s; + char timestr[128]; + G_INT(OFS_RETURN) = 0; + + for (s = prvmsearches; s; s = s->next) + { + if (s->handle == handle) + { //close it down. + if (s->fromprogs != prinst) + { + PF_Warningf(prinst, "Search handle wasn't valid with that progs\n"); + return; + } + + if (num < 0 || num >= s->entries) + return; + if (s->entry[num].mtime != 0) //return null/empty if the time isn't set/known. + { + strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&s->entry[num].mtime)); + RETURN_TSTRING(timestr); + } return; } } @@ -3259,6 +3345,19 @@ void QCBUILTIN PF_buf_create (pubprogfuncs_t *prinst, struct globalvars_s *pr_g { int i; + const char *type = ((prinst->callargc>0)?PR_GetStringOfs(prinst, OFS_PARM0):"string"); + unsigned int flags = ((prinst->callargc>1)?G_FLOAT(OFS_PARM1):0); + + if (!Q_strcasecmp(type, "string")) + ; + else + { + G_FLOAT(OFS_RETURN) = -1; + return; + } + + //flags&1 == saved. apparently. + for (i = 0; i < NUMSTRINGBUFS; i++) { if (!strbuflist[i].prinst) @@ -4172,8 +4271,7 @@ void QCBUILTIN PF_mod (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) if (n == 0) { - Con_Printf("mod by zero\n"); - prinst->pr_trace = 1; + PR_RunWarning(prinst, "mod by zero\n"); G_FLOAT(OFS_RETURN) = 0; } else @@ -4589,7 +4687,6 @@ void QCBUILTIN PF_externrefcall (pubprogfuncs_t *prinst, struct globalvars_s *pr for (i = OFS_PARM0; i < OFS_PARM5; i+=3) VectorCopy(G_VECTOR(i+(2*3)), G_VECTOR(i)); - prinst->pr_trace++; //continue debugging. PR_ExecuteProgram(prinst, f); } @@ -4656,7 +4753,6 @@ void QCBUILTIN PF_externcall (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl for (i = OFS_PARM0; i < OFS_PARM5; i+=3) VectorCopy(G_VECTOR(i+(2*3)), G_VECTOR(i)); - prinst->pr_trace++; //continue debugging PR_ExecuteProgram(prinst, f); } else @@ -4672,19 +4768,18 @@ void QCBUILTIN PF_externcall (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl VectorCopy(G_VECTOR(i+(1*3)), G_VECTOR(i)); G_INT(OFS_PARM0) = failedst; - prinst->pr_trace++; //continue debugging PR_ExecuteProgram(prinst, f); } } void QCBUILTIN PF_traceon (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - prinst->pr_trace = true; + prinst->debug_trace = DEBUG_TRACE_INTO; } void QCBUILTIN PF_traceoff (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - prinst->pr_trace = false; + prinst->debug_trace = DEBUG_TRACE_OFF; } void QCBUILTIN PF_coredump (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -4707,36 +4802,7 @@ void QCBUILTIN PF_eprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_global void QCBUILTIN PF_break (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { -#ifdef SERVERONLY //new break code - char *s; - - //I would like some sort of network activity here, - //but I don't want to mess up the sequence and stuff - //It should be possible, but would mean that I would - //need to alter the client, or rewrite a bit of the server.. - - if (pr_globals) - Con_Printf("Break Statement\n"); - else if (developer.value!=2) - return; //non developers cann't step. - for(;;) - { - s=Sys_ConsoleInput(); - if (s) - { - if (!*s) - break; - else - Con_Printf("%s\n", svprogfuncs->EvaluateDebugString(svprogfuncs, s)); - } - } -#elif defined(TEXTEDITOR) - prinst->pr_trace++; -#else //old break code -Con_Printf ("break statement\n"); -*(int *)-4 = 0; // dump to debugger -// PR_RunError ("break statement"); -#endif + PR_RunWarning (prinst, "break statement"); } void QCBUILTIN PF_error (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -4757,7 +4823,7 @@ void QCBUILTIN PF_error (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals { // SV_Error ("Program error: %s", s); PF_break(prinst, pr_globals); - prinst->pr_trace = 2; + prinst->debug_trace = DEBUG_TRACE_INTO; } else { @@ -5172,6 +5238,34 @@ void QCBUILTIN PF_numentityfields (pubprogfuncs_t *prinst, struct globalvars_s * prinst->FieldInfo(prinst, &count); G_FLOAT(OFS_RETURN) = count; } +void QCBUILTIN PF_findentityfield (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + const char *fieldname = PR_GetStringOfs(prinst, OFS_PARM0); + unsigned int count = 0, fidx; + fdef_t *fdef; + fdef = prinst->FieldInfo(prinst, &count); + G_FLOAT(OFS_RETURN) = 0; + for (fidx = 0; fidx < count; fidx++) + { + if (!strcmp(fdef->name, fieldname)) + { + G_FLOAT(OFS_RETURN) = fidx; + break; + } + } +} +void QCBUILTIN PF_entityfieldref (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + unsigned int fidx = G_FLOAT(OFS_PARM0); + unsigned int count = 0; + fdef_t *fdef; + fdef = prinst->FieldInfo(prinst, &count); + G_INT(OFS_RETURN) = 0; + if (fidx < count) + { + G_INT(OFS_RETURN) = fdef[fidx].ofs; + } +} //string(float fieldnum) void QCBUILTIN PF_entityfieldname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -5256,8 +5350,51 @@ void QCBUILTIN PF_checkcommand (pubprogfuncs_t *prinst, struct globalvars_s *pr_ G_FLOAT(OFS_RETURN) = 0; } +#ifdef USERBE +void QCBUILTIN PF_physics_enable(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + wedict_t*e = G_WEDICT(prinst, OFS_PARM0); + int isenable = G_FLOAT(OFS_PARM1); + world_t *world = prinst->parms->user; + rbecommandqueue_t cmd; + + cmd.command = isenable?RBECMD_ENABLE:RBECMD_DISABLE; + cmd.edict = e; + if (world->rbe) + world->rbe->PushCommand(world, &cmd); +} +void QCBUILTIN PF_physics_addforce(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + wedict_t*e = G_WEDICT(prinst, OFS_PARM0); + float *force = G_VECTOR(OFS_PARM1); + float *relative_ofs = G_VECTOR(OFS_PARM2); + world_t *world = prinst->parms->user; + rbecommandqueue_t cmd; + cmd.command = RBECMD_FORCE; + cmd.edict = e; + VectorCopy(force, cmd.v1); + VectorCopy(relative_ofs, cmd.v2); + + if (world->rbe) + world->rbe->PushCommand(world, &cmd); +} +void QCBUILTIN PF_physics_addtorque(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + wedict_t*e = G_WEDICT(prinst, OFS_PARM0); + float *torque = G_VECTOR(OFS_PARM1); + world_t *world = prinst->parms->user; + rbecommandqueue_t cmd; + + cmd.command = RBECMD_TORQUE; + cmd.edict = e; + VectorCopy(torque, cmd.v1); + + if (world->rbe) + world->rbe->PushCommand(world, &cmd); +} +#endif @@ -5497,13 +5634,13 @@ lh_extension_t QSG_Extensions[] = { {"DP_EF_FULLBRIGHT"}, //Rerouted to hexen2 support. {"DP_EF_NODRAW"}, //implemented by sending it with no modelindex {"DP_EF_RED"}, - {"DP_ENT_COLORMOD"}, +// {"DP_ENT_COLORMOD"}, {"DP_ENT_CUSTOMCOLORMAP"}, {"DP_ENT_EXTERIORMODELTOCLIENT"}, //only in dp6 currently {"DP_ENT_GLOW"}, {"DP_ENT_VIEWMODEL"}, {"DP_GECKO_SUPPORT", 7, NULL, {"gecko_create", "gecko_destroy", "gecko_navigate", "gecko_keyevent", "gecko_mousemove", "gecko_resize", "gecko_get_texture_extent"}}, - {"DP_GFX_QUAKE3MODELTAGS"}, +// {"DP_GFX_QUAKE3MODELTAGS"}, {"DP_GFX_SKINFILES"}, {"DP_GFX_SKYBOX"}, //according to the spec. :) {"DP_HALFLIFE_MAP_CVAR"}, diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index dd5ae2a5a..ac4f6ad49 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -34,7 +34,7 @@ struct wedict_s link_t area; pvscache_t pvsinfo; -#ifdef USEODE +#ifdef USERBE entityode_t ode; #endif /*the above is shared with ssqc*/ @@ -46,15 +46,14 @@ struct wedict_s #define PF_cin_getstate PF_Fixme #define PF_cin_restart PF_Fixme #define PF_drawline PF_Fixme -#define PF_gecko_create PF_Fixme -#define PF_gecko_destroy PF_Fixme -#define PF_gecko_navigate PF_Fixme -#define PF_gecko_keyevent PF_Fixme -#define PF_gecko_movemouse PF_Fixme -#define PF_gecko_resize PF_Fixme -#define PF_gecko_get_texture_extent PF_Fixme +#define PF_media_create_http PF_Fixme +#define PF_media_destroy PF_Fixme +#define PF_media_command PF_Fixme +#define PF_media_keyevent PF_Fixme +#define PF_media_movemouse PF_Fixme +#define PF_media_resize PF_Fixme +#define PF_media_get_texture_extent PF_Fixme -#define PF_gecko_mousemove PF_Fixme #define PF_WritePicture PF_Fixme #define PF_ReadPicture PF_Fixme @@ -166,6 +165,8 @@ void QCBUILTIN PF_search_begin (pubprogfuncs_t *prinst, struct globalvars_s *pr_ void QCBUILTIN PF_search_end (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_search_getsize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_search_getfilename (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_search_getfilesize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_search_getfilemtime (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_isfunction (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_callfunction (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_writetofile(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); @@ -188,6 +189,8 @@ char *PF_VarString (pubprogfuncs_t *prinst, int first, struct globalvars_s *pr_g void PR_ProgsAdded(pubprogfuncs_t *prinst, int newprogs, const char *modulename); void PR_AutoCvar(pubprogfuncs_t *prinst, cvar_t *var); void QCBUILTIN PF_numentityfields (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_findentityfield (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_entityfieldref (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_entityfieldname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_entityfieldtype (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_getentityfieldstring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); @@ -338,6 +341,8 @@ void QCBUILTIN PF_CL_drawresetcliparea (pubprogfuncs_t *prinst, struct globalvar void QCBUILTIN PF_CL_drawgetimagesize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_CL_stringwidth (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_CL_drawsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_CL_drawrotpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_CL_drawrotsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_CL_findfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); #if defined(CSQC_DAT) && !defined(SERVERONLY) @@ -375,13 +380,14 @@ void QCBUILTIN PF_cl_setmousetarget (pubprogfuncs_t *prinst, struct globalvars_s void QCBUILTIN PF_cl_getmousetarget (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_cl_playingdemo (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_cl_runningserver (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); -void QCBUILTIN PF_cs_gecko_create (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); -void QCBUILTIN PF_cs_gecko_destroy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); -void QCBUILTIN PF_cs_gecko_navigate (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); -void QCBUILTIN PF_cs_gecko_keyevent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); -void QCBUILTIN PF_cs_gecko_mousemove (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); -void QCBUILTIN PF_cs_gecko_resize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); -void QCBUILTIN PF_cs_gecko_get_texture_extent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cs_media_create_http (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cs_media_destroy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cs_media_command (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cs_media_keyevent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cs_media_mousemove (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cs_media_resize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cs_media_get_texture_extent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cs_media_getposition (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); typedef enum{ SLIST_HOSTCACHEVIEWCOUNT, SLIST_HOSTCACHETOTALCOUNT, @@ -394,6 +400,10 @@ typedef enum{ } hostcacheglobal_t; void QCBUILTIN PF_shaderforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cl_sprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cl_bprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cl_clientcount (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); + void search_close_progs(pubprogfuncs_t *prinst, qboolean complain); void QCBUILTIN PF_buf_create (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); @@ -432,11 +442,11 @@ void QCBUILTIN PF_gettime (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa void QCBUILTIN PF_whichpack (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); -int QDECL QCEditor (pubprogfuncs_t *prinst, char *filename, int line, int statement, int nump, char **parms); +int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, char *reason); void PR_Common_Shutdown(pubprogfuncs_t *progs, qboolean errored); - - +//FIXME +pbool PR_RunWarning (pubprogfuncs_t *ppf, char *error, ...); /*these are server ones, provided by pr_cmds.c, as required by pr_q1qvm.c*/ diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 61db0d2f7..09135df49 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -73,7 +73,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PEXT2_PRYDONCURSOR 0x00000001 #define PEXT2_VOICECHAT 0x00000002 #define PEXT2_SETANGLEDELTA 0x00000004 -#define PEXT2_REPLACEMENTDELTAS 0x00000008 +#define PEXT2_REPLACEMENTDELTAS 0x00000008 //weaponframe was part of the entity state. that flag is now the player's v_angle. #define PEXT2_MAXPLAYERS 0x00000010 //Client is able to cope with more players than 32. abs max becomes 255, due to colormap issues. #define PEXT2_PREDINFO 0x00000020 //movevar stats, NQ input sequences+acks. @@ -628,7 +628,8 @@ enum clcq2_ops_e #define UFP_VELOCITYXY (1u<<4) #define UFP_VELOCITYZ (1u<<5) #define UFP_MSEC (1u<<6) -#define UFP_WEAPONFRAME (1u<<7) +#define UFP_WEAPONFRAME_OLD (1u<<7) //no longer used. just a stat now that I rewrote stat deltas. +#define UFP_VIEWANGLE (1u<<7) #define UF_REMOVE UF_16BIT /*special flag, slightly more compact (we can reuse the 16bit flag as its not important)*/ @@ -974,6 +975,7 @@ typedef struct entity_state_s /*info to predict other players, so I don't get yelled at if fte were to stop supporting it*/ qbyte pmovetype; qbyte msec; + short vangle[3]; unsigned short weaponframe; short movement[3]; diff --git a/engine/common/q3common.c b/engine/common/q3common.c index 93f681022..f5e8cbd97 100644 --- a/engine/common/q3common.c +++ b/engine/common/q3common.c @@ -187,7 +187,7 @@ typedef struct { int bufferleft; int skip; } vmsearch_t; -static int QDECL VMEnum(const char *match, qofs_t size, void *args, searchpathfuncs_t *spath) +static int QDECL VMEnum(const char *match, qofs_t size, time_t mtime, void *args, searchpathfuncs_t *spath) { char *check; int newlen; @@ -211,13 +211,13 @@ static int QDECL VMEnum(const char *match, qofs_t size, void *args, searchpathfu return true; } -static int QDECL IfFound(const char *match, qofs_t size, void *args, searchpathfuncs_t *spath) +static int QDECL IfFound(const char *match, qofs_t size, time_t modtime, void *args, searchpathfuncs_t *spath) { *(qboolean*)args = true; return true; } -static int QDECL VMEnumMods(const char *match, qofs_t size, void *args, searchpathfuncs_t *spath) +static int QDECL VMEnumMods(const char *match, qofs_t size, time_t modtime, void *args, searchpathfuncs_t *spath) { char *check; char desc[1024]; diff --git a/engine/common/qvm.c b/engine/common/qvm.c index 82364aa44..c2756dcc9 100644 --- a/engine/common/qvm.c +++ b/engine/common/qvm.c @@ -49,7 +49,8 @@ typedef enum vm_type_e { VM_NONE, VM_NATIVE, - VM_BYTECODE + VM_BYTECODE, + VM_BUILTIN } vm_type_t; struct vm_s { @@ -899,13 +900,17 @@ void VM_PrintInfo(vm_t *vm) { qvm_t *qvm; - Con_Printf("%s (%p): ", vm->name, vm->hInst); +// Con_Printf("%s (%p): ", vm->name, vm->hInst); + Con_Printf("%s: ", vm->name); switch(vm->type) { case VM_NATIVE: Con_Printf("native\n"); break; + case VM_BUILTIN: + Con_Printf("built in\n"); + break; case VM_BYTECODE: Con_Printf("interpreted\n"); @@ -923,6 +928,17 @@ void VM_PrintInfo(vm_t *vm) } } +vm_t *VM_CreateBuiltin(const char *name, sys_calldll_t syscalldll, qintptr_t (*init)(qintptr_t *args)) +{ + vm_t *vm = Z_Malloc(sizeof(vm_t)); + Q_strncpyz(vm->name, name, sizeof(vm->name)); + vm->syscalldll = syscalldll; + vm->syscallqvm = NULL; + vm->hInst = init; + vm->type = VM_BUILTIN; + return vm; +} + /* ** VM_Create */ @@ -987,6 +1003,7 @@ void VM_Destroy(vm_t *vm) if(vm->hInst) QVM_UnLoadVM(vm->hInst); break; + case VM_BUILTIN: case VM_NONE: break; } @@ -1033,6 +1050,7 @@ void *VM_MemoryBase(vm_t *vm) switch(vm->type) { case VM_NATIVE: + case VM_BUILTIN: return NULL; case VM_BYTECODE: return ((qvm_t*)vm->hInst)->ds; @@ -1059,6 +1077,7 @@ qboolean VM_NonNative(vm_t *vm) case VM_BYTECODE: return sizeof(int) != sizeof(void*); case VM_NATIVE: + case VM_BUILTIN: return false; default: return false; @@ -1071,28 +1090,33 @@ qboolean VM_NonNative(vm_t *vm) qintptr_t VARGS VM_Call(vm_t *vm, qintptr_t instruction, ...) { va_list argptr; - qintptr_t arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7; + qintptr_t arg[8]; if(!vm) Sys_Error("VM_Call with NULL vm"); va_start(argptr, instruction); - arg0=va_arg(argptr, qintptr_t); - arg1=va_arg(argptr, qintptr_t); - arg2=va_arg(argptr, qintptr_t); - arg3=va_arg(argptr, qintptr_t); - arg4=va_arg(argptr, qintptr_t); - arg5=va_arg(argptr, qintptr_t); - arg6=va_arg(argptr, qintptr_t); - arg7=va_arg(argptr, qintptr_t); + arg[0]=va_arg(argptr, qintptr_t); + arg[1]=va_arg(argptr, qintptr_t); + arg[2]=va_arg(argptr, qintptr_t); + arg[3]=va_arg(argptr, qintptr_t); + arg[4]=va_arg(argptr, qintptr_t); + arg[5]=va_arg(argptr, qintptr_t); + arg[6]=va_arg(argptr, qintptr_t); + arg[7]=va_arg(argptr, qintptr_t); va_end(argptr); switch(vm->type) { case VM_NATIVE: - return vm->vmMain(instruction, arg0, arg1, arg2, arg3, arg4, arg5, arg6); + return vm->vmMain(instruction, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6]); case VM_BYTECODE: - return QVM_ExecVM(vm->hInst, instruction, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + return QVM_ExecVM(vm->hInst, instruction, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7]); + + case VM_BUILTIN: + if (!instruction) + instruction = (qintptr_t)vm->hInst; + return ((qintptr_t(*)(qintptr_t*))instruction)(arg); case VM_NONE: return 0; diff --git a/engine/common/sys.h b/engine/common/sys.h index ad0b42608..8f0aa6f2a 100644 --- a/engine/common/sys.h +++ b/engine/common/sys.h @@ -87,7 +87,7 @@ void Sys_ServerActivity(void); void Sys_SendKeyEvents (void); // Perform Key_Event () callbacks until the input que is empty -int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath); +int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t modtime, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath); void Sys_Vibrate(float count); diff --git a/engine/common/vm.h b/engine/common/vm.h index caf7040eb..a7139c4f6 100644 --- a/engine/common/vm.h +++ b/engine/common/vm.h @@ -60,6 +60,7 @@ typedef struct vm_s vm_t; // ------------------------- * interface * ------------------------- void VM_PrintInfo(vm_t *vm); +vm_t *VM_CreateBuiltin(const char *name, sys_calldll_t syscalldll, qintptr_t (*init)(qintptr_t *args)); vm_t *VM_Create(const char *name, sys_calldll_t syscalldll, sys_callqvm_t syscallqvm); void VM_Destroy(vm_t *vm); //qboolean VM_Restart(vm_t *vm); diff --git a/engine/common/world.h b/engine/common/world.h index b2ae955e5..42caceaf3 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -148,6 +148,25 @@ typedef struct vec3_t laggedpos; } laggedentinfo_t; +#ifdef USERBE +typedef struct +{ + void (QDECL *End)(struct world_s *world); + void (QDECL *RemoveJointFromEntity)(struct world_s *world, wedict_t *ed); + void (QDECL *RemoveFromEntity)(struct world_s *world, wedict_t *ed); + qboolean (QDECL *RagMatrixToBody)(rbebody_t *bodyptr, float *mat); + qboolean (QDECL *RagCreateBody)(struct world_s *world, rbebody_t *bodyptr, rbebodyinfo_t *bodyinfo, float *mat, wedict_t *ent); + void (QDECL *RagMatrixFromJoint)(rbejoint_t *joint, rbejointinfo_t *info, float *mat); + void (QDECL *RagMatrixFromBody)(struct world_s *world, rbebody_t *bodyptr, float *mat); + void (QDECL *RagEnableJoint)(rbejoint_t *joint, qboolean enabled); + void (QDECL *RagCreateJoint)(struct world_s *world, rbejoint_t *joint, rbejointinfo_t *info, rbebody_t *body1, rbebody_t *body2, vec3_t aaa2[3]); + void (QDECL *RagDestroyBody)(struct world_s *world, rbebody_t *bodyptr); + void (QDECL *RagDestroyJoint)(struct world_s *world, rbejoint_t *joint); + void (QDECL *Frame)(struct world_s *world, double frametime, double gravity); + void (QDECL *PushCommand)(struct world_s *world, rbecommandqueue_t *cmd); +} rigidbodyengine_t; +#endif + struct world_s { void (*Event_Touch)(struct world_s *w, wedict_t *s, wedict_t *o); @@ -199,32 +218,41 @@ struct world_s float *drawfontscale; } g; -#ifdef USEODE - worldode_t ode; +#ifdef USERBE + qboolean rbe_hasphysicsents; + rigidbodyengine_t *rbe; #endif }; typedef struct world_s world_t; void PF_Common_RegisterCvars(void); -#ifdef USEODE -void World_ODE_RemoveFromEntity(world_t *world, wedict_t *ed); -void World_ODE_RemoveJointFromEntity(world_t *world, wedict_t *ed); -void World_ODE_Frame(world_t *world, double frametime, double gravity); -void World_ODE_Init(void); -void World_ODE_Start(world_t *world); -void World_ODE_End(world_t *world); -void World_ODE_Shutdown(void); -qboolean World_ODE_RagCreateBody(world_t *world, odebody_t *bodyptr, odebodyinfo_t *bodyinfo, float *mat, wedict_t *ent); -qboolean World_ODE_RagMatrixToBody(odebody_t *bodyptr, float *mat); -void World_ODE_RagMatrixFromBody(world_t *world, odebody_t *bodyptr, float *mat); -void World_ODE_RagDestroyBody(world_t *world, odebody_t *bodyptr); -void World_ODE_RagCreateJoint(world_t *world, odejoint_t *joint, odejointinfo_t *info, odebody_t *body1, odebody_t *body2, vec3_t aaa2[3]); -void World_ODE_RagEnableJoint(odejoint_t *joint, qboolean enabled); -void World_ODE_RagMatrixFromJoint(odejoint_t *joint, odejointinfo_t *info, float *mat); -void World_ODE_RagDestroyJoint(world_t *world, odejoint_t *joint); -#endif + + +qboolean QDECL World_RegisterPhysicsEngine(const char *enginename, void(QDECL*World_Bullet_Start)(world_t*world)); +void QDECL World_UnregisterPhysicsEngine(const char *enginename); +qboolean QDECL World_GenerateCollisionMesh(world_t *world, model_t *mod, wedict_t *ed, vec3_t geomcenter); +void QDECL World_ReleaseCollisionMesh(wedict_t *ed); + + + + + + + + + + + + + + + + + +void World_RBE_Start(world_t *world); + void World_ClearWorld (world_t *w); // called after the world model has been loaded, before linking any entities @@ -234,7 +262,7 @@ void World_UnlinkEdict (wedict_t *ent); // so it doesn't clip against itself // flags ent->v.modified -void World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers); +void QDECL World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers); // Needs to be called any time an entity changes origin, mins, maxs, or solid // flags ent->v.modified // sets ent->v.absmin and ent->v.absmax diff --git a/engine/dotnet2005/ftequake.sln b/engine/dotnet2005/ftequake.sln index 5e524812c..74a8400e7 100644 --- a/engine/dotnet2005/ftequake.sln +++ b/engine/dotnet2005/ftequake.sln @@ -2,6 +2,7 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "FTEQuake", "..\setup\setup.vdproj", "{E0EE8B50-3A75-42A9-B80A-787675979B0C}" ProjectSection(ProjectDependencies) = postProject + {82285268-9C3B-44AD-BBE7-40670F9D2628} = {82285268-9C3B-44AD-BBE7-40670F9D2628} {9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {9767E236-8454-44E9-8999-CD5BDAFBE9BA} {72269FEE-293D-40BC-A7AE-E429F4496869} = {72269FEE-293D-40BC-A7AE-E429F4496869} EndProjectSection @@ -9,9 +10,6 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "botlib", "botlib.vcproj", "{0018E098-B12A-4E4D-9B22-6772DA287080}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fteqcc", "..\qclib\dotnet2005\qcc.vcproj", "{2866F783-6B44-4655-A38D-D53874037454}" - ProjectSection(ProjectDependencies) = postProject - {9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {9767E236-8454-44E9-8999-CD5BDAFBE9BA} - EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qtvprox", "..\..\fteqtv\dotnet2005\qtvprox.vcproj", "{62669E6C-7E18-4E4D-BA54-DFBE29E7D24E}" EndProject @@ -53,6 +51,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "targets", "targets", "{EB5D EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "emscripten", "emscripten.vcproj", "{75D91BDE-CC30-4C53-BF33-5F69EF13A61B}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bulletplug", "..\..\plugins\bullet\bulletplug.vcproj", "{82285268-9C3B-44AD-BBE7-40670F9D2628}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "odeplug", "..\..\plugins\odeplug\odeplug.vcproj", "{ED16B405-BDCD-4EB8-BF70-761964301368}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution D3DDebug|Win32 = D3DDebug|Win32 @@ -660,6 +662,78 @@ Global {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.Release|Win32.ActiveCfg = Release|Win32 {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.Release|Win32.Build.0 = Release|Win32 {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.Release|x64.ActiveCfg = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.D3DDebug|Win32.ActiveCfg = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.D3DDebug|Win32.Build.0 = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.D3DDebug|x64.ActiveCfg = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.D3DRelease|Win32.ActiveCfg = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.D3DRelease|Win32.Build.0 = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.D3DRelease|x64.ActiveCfg = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.Debug Dedicated Server|Win32.ActiveCfg = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.Debug Dedicated Server|Win32.Build.0 = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.Debug Dedicated Server|x64.ActiveCfg = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.Debug|Win32.ActiveCfg = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.Debug|Win32.Build.0 = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.Debug|x64.ActiveCfg = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.GLDebug|Win32.ActiveCfg = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.GLDebug|Win32.Build.0 = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.GLDebug|x64.ActiveCfg = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.GLRelease|Win32.ActiveCfg = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.GLRelease|Win32.Build.0 = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.GLRelease|x64.ActiveCfg = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.MDebug|Win32.ActiveCfg = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.MDebug|Win32.Build.0 = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.MDebug|x64.ActiveCfg = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.MinGLDebug|Win32.ActiveCfg = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.MinGLDebug|Win32.Build.0 = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.MinGLDebug|x64.ActiveCfg = Debug|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.MinGLRelease|Win32.ActiveCfg = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.MinGLRelease|Win32.Build.0 = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.MinGLRelease|x64.ActiveCfg = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.MRelease|Win32.ActiveCfg = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.MRelease|Win32.Build.0 = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.MRelease|x64.ActiveCfg = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.Release Dedicated Server|Win32.ActiveCfg = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.Release Dedicated Server|Win32.Build.0 = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.Release Dedicated Server|x64.ActiveCfg = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.Release|Win32.ActiveCfg = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.Release|Win32.Build.0 = Release|Win32 + {82285268-9C3B-44AD-BBE7-40670F9D2628}.Release|x64.ActiveCfg = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.D3DDebug|Win32.ActiveCfg = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.D3DDebug|Win32.Build.0 = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.D3DDebug|x64.ActiveCfg = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.D3DRelease|Win32.ActiveCfg = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.D3DRelease|Win32.Build.0 = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.D3DRelease|x64.ActiveCfg = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.Debug Dedicated Server|Win32.ActiveCfg = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.Debug Dedicated Server|Win32.Build.0 = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.Debug Dedicated Server|x64.ActiveCfg = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.Debug|Win32.ActiveCfg = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.Debug|Win32.Build.0 = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.Debug|x64.ActiveCfg = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.GLDebug|Win32.ActiveCfg = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.GLDebug|Win32.Build.0 = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.GLDebug|x64.ActiveCfg = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.GLRelease|Win32.ActiveCfg = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.GLRelease|Win32.Build.0 = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.GLRelease|x64.ActiveCfg = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.MDebug|Win32.ActiveCfg = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.MDebug|Win32.Build.0 = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.MDebug|x64.ActiveCfg = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.MinGLDebug|Win32.ActiveCfg = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.MinGLDebug|Win32.Build.0 = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.MinGLDebug|x64.ActiveCfg = Debug|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.MinGLRelease|Win32.ActiveCfg = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.MinGLRelease|Win32.Build.0 = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.MinGLRelease|x64.ActiveCfg = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.MRelease|Win32.ActiveCfg = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.MRelease|Win32.Build.0 = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.MRelease|x64.ActiveCfg = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.Release Dedicated Server|Win32.ActiveCfg = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.Release Dedicated Server|Win32.Build.0 = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.Release Dedicated Server|x64.ActiveCfg = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.Release|Win32.ActiveCfg = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.Release|Win32.Build.0 = Release|Win32 + {ED16B405-BDCD-4EB8-BF70-761964301368}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -677,6 +751,8 @@ Global {72269FEE-293D-40BC-A7AE-E429F4496869} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} {6ABD62A3-C5A0-43E8-BA4F-84606057774F} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} {74542CA7-48C1-4664-9007-66F751131EA3} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} + {82285268-9C3B-44AD-BBE7-40670F9D2628} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} + {ED16B405-BDCD-4EB8-BF70-761964301368} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution AMDCaProjectFile = C:\Games\Quake\wip\engine\dotnet2005\CodeAnalyst\ftequake.caw diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index ce5992222..b0e63b38a 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -1696,7 +1696,7 @@ PreprocessorDefinitions="NDEBUG;GLQUAKE;WIN32;_WINDOWS;BOTLIB_STATIC;MULTITHREAD" StringPooling="true" ExceptionHandling="0" - BufferSecurityCheck="true" + BufferSecurityCheck="false" EnableEnhancedInstructionSet="2" FloatingPointModel="2" RuntimeTypeInfo="false" @@ -25331,178 +25331,6 @@ /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -32040,6 +31868,358 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + encoding) { + case PTI_DEPTH16: + qglTexImage2D(targface, j, gl_config.gles?GL_DEPTH_COMPONENT:GL_DEPTH_COMPONENT16_ARB, mips->mip[i].width, mips->mip[i].height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, mips->mip[i].data); + break; + case PTI_DEPTH24: + qglTexImage2D(targface, j, gl_config.gles?GL_DEPTH_COMPONENT:GL_DEPTH_COMPONENT24_ARB, mips->mip[i].width, mips->mip[i].height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, mips->mip[i].data); + break; + case PTI_DEPTH32: + qglTexImage2D(targface, j, gl_config.gles?GL_DEPTH_COMPONENT:GL_DEPTH_COMPONENT32_ARB, mips->mip[i].width, mips->mip[i].height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, mips->mip[i].data); + break; + case PTI_DEPTH24_8: + qglTexImage2D(targface, j, GL_DEPTH24_STENCIL8_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, mips->mip[i].data); + break; //32bit formats case PTI_RGBX8: qglTexImage2D(targface, j, GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); @@ -466,6 +479,8 @@ void GL_UpdateFiltering(image_t *imagelist, int filtermip[3], int filterpic[3], // change all the existing mipmap texture objects for (img=imagelist ; img ; img=img->next) { + if (img->status != TEX_LOADED) + continue; switch((img->flags & IF_TEXTYPE) >> IF_TEXTYPESHIFT) { case 0: @@ -478,8 +493,6 @@ void GL_UpdateFiltering(image_t *imagelist, int filtermip[3], int filterpic[3], targ = GL_TEXTURE_CUBE_MAP_ARB; break; } - if (img->status != TEX_LOADED) - continue; GL_MTBind(0, targ, img); GL_Texturemode_Apply(targ, img->flags); diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index d55efdf7a..f514578b0 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -1033,8 +1033,8 @@ int CM_HeadnodeForBox (struct model_s *mod, vec3_t mins, vec3_t maxs); struct trace_s CM_TransformedBoxTrace (struct model_s *mod, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask, vec3_t origin, vec3_t angles); struct model_s *CM_TempBoxModel(vec3_t mins, vec3_t maxs); -void VARGS CMQ2_SetAreaPortalState (unsigned int portalnum, qboolean open); -void CMQ3_SetAreaPortalState (unsigned int area1, unsigned int area2, qboolean open); +void CMQ2_SetAreaPortalState (model_t *mod, unsigned int portalnum, qboolean open); +void CMQ3_SetAreaPortalState (model_t *mod, unsigned int area1, unsigned int area2, qboolean open); #endif diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index bef9caddb..28f735583 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -57,7 +57,6 @@ extern cvar_t r_bloom; extern cvar_t r_wireframe_smooth; cvar_t gl_affinemodels = SCVAR("gl_affinemodels","0"); -cvar_t gl_reporttjunctions = SCVAR("gl_reporttjunctions","0"); cvar_t gl_finish = SCVAR("gl_finish","0"); cvar_t gl_dither = SCVAR("gl_dither", "1"); extern cvar_t r_stereo_separation; @@ -455,7 +454,7 @@ void R_SetupGL (float stereooffset) fov_x = r_refdef.fov_x;//+sin(cl.time)*5; fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5; - if (*r_refdef.rt_destcolour[0].texname || *r_refdef.rt_depth.texname) + if ((*r_refdef.rt_destcolour[0].texname || *r_refdef.rt_depth.texname) && strcmp(r_refdef.rt_destcolour[0].texname, "megascreeny")) { r_refdef.pxrect.y = r_refdef.pxrect.maxheight - (r_refdef.pxrect.height+r_refdef.pxrect.y); fov_y *= -1; @@ -564,6 +563,7 @@ void R_RenderScene (void) int stereomode; int i; int tmpvisents = cl_numvisedicts; /*world rendering is allowed to add additional ents, but we don't want to keep them for recursive views*/ + int cull = r_refdef.flipcull; stereomode = r_stereo_method.ival; if (stereomode == 1) @@ -629,7 +629,10 @@ void R_RenderScene (void) break; } if (i) + { + GL_ForceDepthWritable(); qglClear (GL_DEPTH_BUFFER_BIT); + } TRACE(("dbg: calling R_SetupGL\n")); R_SetupGL (stereooffset[i]); @@ -681,6 +684,8 @@ void R_RenderScene (void) case 5: break; } + + r_refdef.flipcull = cull; } /*generates a new modelview matrix, as well as vpn vectors*/ static void R_MirrorMatrix(plane_t *plane) @@ -1242,7 +1247,7 @@ void R_Clear (qboolean fbo) //for performance, we clear the depth at the same time we clear colour, so we can skip clearing depth here the first time around each frame. //but for multiple scenes, we do need to clear depth still. //fbos always get cleared depth, just in case (colour fbos may contain junk, but hey). - qglClear (GL_DEPTH_BUFFER_BIT); + qglClear (GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT); } if (!fbo) depthcleared = false; diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index 8e8e047e7..417896134 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -57,7 +57,7 @@ WARNING: be very careful calling this from elsewhere, because the refresh needs almost the entire 256k of stack space! ================== */ - +void SCR_DrawCursor(void); void GLSCR_UpdateScreen (void) { int uimenu; @@ -124,6 +124,7 @@ void GLSCR_UpdateScreen (void) if (key_dest_mask & kdm_console) Con_DrawConsole(vid.height/2, false); + SCR_DrawCursor(); GL_EndRendering (); VID_SwapBuffers(); RSpeedEnd(RSPEED_TOTALREFRESH); @@ -257,6 +258,14 @@ char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight) int i, c; qbyte *ret; + *truewidth = vid.pixelwidth; + *trueheight = vid.pixelheight; + + if (*r_refdef.rt_destcolour[0].texname) + { + R2D_RT_GetTexture(r_refdef.rt_destcolour[0].texname, truewidth, trueheight); + } + /*if (1) { float *p; @@ -280,10 +289,10 @@ char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight) qbyte *p; // gles only guarantees GL_RGBA/GL_UNSIGNED_BYTE so downconvert and resize - ret = BZ_Malloc(prepadbytes + vid.pixelwidth*vid.pixelheight*4); - qglReadPixels (0, 0, vid.pixelwidth, vid.pixelheight, GL_RGBA, GL_UNSIGNED_BYTE, ret + prepadbytes); + ret = BZ_Malloc(prepadbytes + (*truewidth)*(*trueheight)*4); + qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGBA, GL_UNSIGNED_BYTE, ret + prepadbytes); - c = vid.pixelwidth*vid.pixelheight; + c = (*truewidth)*(*trueheight); p = ret + prepadbytes; for (i = 1; i < c; i++) { @@ -291,20 +300,17 @@ char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight) p[i*3+1]=p[i*4+1]; p[i*3+2]=p[i*4+2]; } - ret = BZ_Realloc(ret, prepadbytes + vid.pixelwidth*vid.pixelheight*3); + ret = BZ_Realloc(ret, prepadbytes + (*truewidth)*(*trueheight)*3); } else { - ret = BZ_Malloc(prepadbytes + vid.pixelwidth*vid.pixelheight*3); - qglReadPixels (0, 0, vid.pixelwidth, vid.pixelheight, GL_RGB, GL_UNSIGNED_BYTE, ret + prepadbytes); + ret = BZ_Malloc(prepadbytes + (*truewidth)*(*trueheight)*3); + qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGB, GL_UNSIGNED_BYTE, ret + prepadbytes); } - *truewidth = vid.pixelwidth; - *trueheight = vid.pixelheight; - if (gammaworks) { - c = prepadbytes+vid.pixelwidth*vid.pixelheight*3; + c = prepadbytes+(*truewidth), (*trueheight)*3; for (i=prepadbytes ; iflags |= SHADER_PASS_LINEAR; } else - name = NULL; + break; } // if (shader->flags & SHADER_SKY) @@ -1844,6 +1844,47 @@ static void Shader_DiffuseMap(shader_t *shader, shaderpass_t *pass, char **ptr) token = Shader_ParseString(ptr); shader->defaulttextures.base = R_LoadHiResTexture(token, NULL, 0); } +static void Shader_SpecularMap(shader_t *shader, shaderpass_t *pass, char **ptr) +{ + char *token; + token = Shader_ParseString(ptr); + shader->defaulttextures.specular = R_LoadHiResTexture(token, NULL, 0); +} +static void Shader_BumpMap(shader_t *shader, shaderpass_t *pass, char **ptr) +{ + char *token; + token = Shader_ParseString(ptr); + shader->defaulttextures.bump = R_LoadHiResTexture(token, NULL, 0); +} +static void Shader_FullbrightMap(shader_t *shader, shaderpass_t *pass, char **ptr) +{ + char *token; + token = Shader_ParseString(ptr); + shader->defaulttextures.fullbright = R_LoadHiResTexture(token, NULL, 0); +} +static void Shader_UpperMap(shader_t *shader, shaderpass_t *pass, char **ptr) +{ + char *token; + token = Shader_ParseString(ptr); + shader->defaulttextures.upperoverlay = R_LoadHiResTexture(token, NULL, 0); +} +static void Shader_LowerMap(shader_t *shader, shaderpass_t *pass, char **ptr) +{ + char *token; + token = Shader_ParseString(ptr); + shader->defaulttextures.loweroverlay = R_LoadHiResTexture(token, NULL, 0); +} + +static qboolean Shaderpass_MapGen (shader_t *shader, shaderpass_t *pass, char *tname); +static void Shader_ProgMap(shader_t *shader, shaderpass_t *pass, char **ptr) +{ + //fixme +// Shaderpass_BlendFunc (shader, pass, ptr); +} +static void Shader_ProgBlendFunc(shader_t *shader, shaderpass_t *pass, char **ptr) +{ + //fixme +} static void Shader_Translucent(shader_t *shader, shaderpass_t *pass, char **ptr) { @@ -1971,8 +2012,11 @@ static shaderkey_t shaderkeys[] = /*doom3 compat*/ {"diffusemap", Shader_DiffuseMap}, //macro for "{\nstage diffusemap\nmap \n}" - {"bumpmap", NULL}, //macro for "{\nstage bumpmap\nmap \n}" - {"specularmap", NULL}, //macro for "{\nstage specularmap\nmap \n}" + {"bumpmap", Shader_BumpMap}, //macro for "{\nstage bumpmap\nmap \n}" + {"specularmap", Shader_SpecularMap},//macro for "{\nstage specularmap\nmap \n}" + {"fullbrightmap", Shader_FullbrightMap},//macro for "{\nstage specularmap\nmap \n}" + {"uppermap", Shader_UpperMap},//macro for "{\nstage specularmap\nmap \n}" + {"lowermap", Shader_LowerMap},//macro for "{\nstage specularmap\nmap \n}" {"discrete", NULL}, {"nonsolid", NULL}, {"noimpact", NULL}, @@ -1981,6 +2025,10 @@ static shaderkey_t shaderkeys[] = {"nooverlays", NULL}, {"nofragment", NULL}, + /*simpler parsing for fte shaders*/ + {"progblendfunc", Shader_ProgBlendFunc}, + {"progmap", Shader_ProgMap}, + {NULL, NULL} }; @@ -2018,6 +2066,7 @@ static qboolean Shaderpass_MapGen (shader_t *shader, shaderpass_t *pass, char *t else if (!Q_stricmp (tname, "$diffuse")) { pass->texgen = T_GEN_DIFFUSE; + shader->flags |= SHADER_HASDIFFUSE; } else if (!Q_stricmp (tname, "$normalmap")) { @@ -2110,6 +2159,7 @@ static void Shaderpass_Map (shader_t *shader, shaderpass_t *pass, char **ptr) pass->anim_frames[0] = r_nulltex; token = Shader_ParseString (ptr); + flags = Shader_SetImageFlags (shader, pass, &token); if (!Shaderpass_MapGen(shader, pass, token)) { @@ -2128,6 +2178,8 @@ static void Shaderpass_Map (shader_t *shader, shaderpass_t *pass, char **ptr) if (pass->tcgen == TC_GEN_UNSPECIFIED) pass->tcgen = TC_GEN_BASE; + if (!*shader->mapname && pass->tcgen == TC_GEN_BASE) + Q_strncpyz(shader->mapname, token, sizeof(shader->mapname)); pass->anim_frames[0] = Shader_FindImage (token, flags); } } @@ -2854,7 +2906,7 @@ void Shader_Free (shader_t *shader) -int QDECL Shader_InitCallback (const char *name, qofs_t size, void *param, searchpathfuncs_t *spath) +int QDECL Shader_InitCallback (const char *name, qofs_t size, time_t mtime, void *param, searchpathfuncs_t *spath) { Shader_MakeCache(name); return true; @@ -3288,12 +3340,12 @@ void Shader_Readpass (shader_t *shader, char **ptr) case ST_BUMPMAP: if (pass->texgen == T_GEN_SINGLEMAP) shader->defaulttextures.bump = pass->anim_frames[0]; - ignore = true; + ignore = true; //fixme: scrolling etc may be important. but we're not doom3. break; case ST_SPECULARMAP: if (pass->texgen == T_GEN_SINGLEMAP) shader->defaulttextures.specular = pass->anim_frames[0]; - ignore = true; + ignore = true; //fixme: scrolling etc may be important. but we're not doom3. break; } } @@ -3526,6 +3578,7 @@ void Shader_Programify (shader_t *s) s->prog = Shader_FindGeneric(va("%s%s", prog, mask), qrenderer); s->numpasses = 0; s->passes[s->numpasses++].texgen = T_GEN_DIFFUSE; + s->flags |= SHADER_HASDIFFUSE; if (modellighting) { @@ -3534,6 +3587,7 @@ void Shader_Programify (shader_t *s) s->passes[s->numpasses++].texgen = T_GEN_FULLBRIGHT; s->passes[s->numpasses++].texgen = T_GEN_NORMALMAP; s->passes[s->numpasses++].texgen = T_GEN_SPECULAR; + s->flags |= SHADER_HASTOPBOTTOM | SHADER_HASFULLBRIGHT | SHADER_HASNORMALMAP | SHADER_HASGLOSS; } else if (lightmap) { @@ -3542,6 +3596,7 @@ void Shader_Programify (shader_t *s) s->passes[s->numpasses++].texgen = T_GEN_DELUXMAP; s->passes[s->numpasses++].texgen = T_GEN_FULLBRIGHT; s->passes[s->numpasses++].texgen = T_GEN_SPECULAR; + s->flags |= SHADER_HASFULLBRIGHT | SHADER_HASNORMALMAP | SHADER_HASGLOSS; } } @@ -3942,6 +3997,23 @@ void Shader_UpdateRegistration (void) } */ +/* + if (*shader_diffusemapname) + { + if (!s->defaulttextures.base) + s->defaulttextures.base = Shader_FindImage (va("%s.tga", shader_diffusemapname), 0); + if (!s->defaulttextures.bump) + s->defaulttextures.bump = Shader_FindImage (va("%s_norm.tga", shader_diffusemapname), 0); + if (!s->defaulttextures.fullbright) + s->defaulttextures.fullbright = Shader_FindImage (va("%s_glow.tga", shader_diffusemapname), 0); + if (!s->defaulttextures.specular) + s->defaulttextures.specular = Shader_FindImage (va("%s_gloss.tga", shader_diffusemapname), 0); + if (!s->defaulttextures.upperoverlay) + s->defaulttextures.upperoverlay = Shader_FindImage (va("%s_shirt.tga", shader_diffusemapname), 0); + if (!s->defaulttextures.loweroverlay) + s->defaulttextures.loweroverlay = Shader_FindImage (va("%s_pants.tga", shader_diffusemapname), 0); //stupid yanks... + } +*/ void Shader_DefaultSkin(const char *shortname, shader_t *s, const void *args); void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) { @@ -3962,10 +4034,10 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) if (!TEXVALID(shader->defaulttextures.base)) { /*dlights/realtime lighting needs some stuff*/ + if (!TEXVALID(tn->base) && *shader->mapname)// && (shader->flags & SHADER_HASDIFFUSE)) + tn->base = R_LoadHiResTexture(shader->mapname, NULL, 0); if (!TEXVALID(tn->base)) - { tn->base = R_LoadHiResTexture(imagename, subpath, (*imagename=='{')?0:IF_NOALPHA); - } TEXASSIGN(shader->defaulttextures.base, tn->base); } @@ -3974,8 +4046,10 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) if (!TEXVALID(shader->defaulttextures.bump)) { - if (r_loadbumpmapping) + if (r_loadbumpmapping || (shader->flags & SHADER_HASNORMALMAP)) { + if (!TEXVALID(tn->bump) && *shader->mapname && (shader->flags & SHADER_HASNORMALMAP)) + tn->bump = R_LoadHiResTexture(va("%s_norm", shader->mapname), NULL, IF_TRYBUMP); if (!TEXVALID(tn->bump)) tn->bump = R_LoadHiResTexture(va("%s_norm", imagename), subpath, IF_TRYBUMP); } @@ -3986,6 +4060,8 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) { if (shader->flags & SHADER_HASTOPBOTTOM) { + if (!TEXVALID(tn->loweroverlay) && *shader->mapname) + tn->loweroverlay = R_LoadHiResTexture(va("%s_pants", shader->mapname), NULL, 0); if (!TEXVALID(tn->loweroverlay)) tn->loweroverlay = R_LoadHiResTexture(va("%s_pants", imagename), subpath, 0); /*how rude*/ } @@ -3996,6 +4072,8 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) { if (shader->flags & SHADER_HASTOPBOTTOM) { + if (!TEXVALID(tn->upperoverlay) && *shader->mapname) + tn->upperoverlay = R_LoadHiResTexture(va("%s_shirt", shader->mapname), NULL, 0); if (!TEXVALID(tn->upperoverlay)) tn->upperoverlay = R_LoadHiResTexture(va("%s_shirt", imagename), subpath, 0); } @@ -4007,6 +4085,8 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) extern cvar_t gl_specular; if ((shader->flags & SHADER_HASGLOSS) && gl_specular.value && gl_load24bit.value) { + if (!TEXVALID(tn->specular) && *shader->mapname) + tn->specular = R_LoadHiResTexture(va("%s_gloss", shader->mapname), NULL, 0); if (!TEXVALID(tn->specular)) tn->specular = R_LoadHiResTexture(va("%s_gloss", imagename), subpath, 0); } @@ -4018,8 +4098,10 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) extern cvar_t r_fb_bmodels; if ((shader->flags & SHADER_HASFULLBRIGHT) && r_fb_bmodels.value && gl_load24bit.value) { + if (!TEXVALID(tn->fullbright) && *shader->mapname) + tn->fullbright = R_LoadHiResTexture(va("%s_luma", shader->mapname), NULL, 0); if (!TEXVALID(tn->fullbright)) - tn->specular = R_LoadHiResTexture(va("%s_luma", imagename), subpath, 0); + tn->fullbright = R_LoadHiResTexture(va("%s_luma", imagename), subpath, 0); } TEXASSIGN(shader->defaulttextures.fullbright, tn->fullbright); } @@ -4730,24 +4812,41 @@ void Shader_Default2D(const char *shortname, shader_t *s, const void *genargs) { if (Shader_ParseShader("default2d", s)) return; - Shader_DefaultScript(shortname, s, - "{\n" - "if $nofixed\n" - "program default2d\n" - "endif\n" - "affine\n" - "nomipmaps\n" + if (sh_config.progs_supported) + { + //hexen2 needs premultiplied alpha to avoid looking ugly + //but that results in problems where things are drawn with alpha not 0, so scale vertex colour by alpha in the fragment program + Shader_DefaultScript(shortname, s, "{\n" - "clampmap $diffuse\n" - "rgbgen vertex\n" - "alphagen vertex\n" - "blendfunc gl_one gl_one_minus_src_alpha\n" + "affine\n" + "nomipmaps\n" + "program default2d#PREMUL\n" + "{\n" + "map $diffuse\n" + "blend gl_one gl_one_minus_src_alpha\n" + "}\n" + "sort additive\n" "}\n" - "sort additive\n" - "}\n" - ); - - TEXASSIGN(s->defaulttextures.base, R_LoadHiResTexture(s->name, NULL, IF_PREMULTIPLYALPHA|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP)); + ); + TEXASSIGN(s->defaulttextures.base, R_LoadHiResTexture(s->name, NULL, IF_PREMULTIPLYALPHA|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP)); + } + else + { + Shader_DefaultScript(shortname, s, + "{\n" + "affine\n" + "nomipmaps\n" + "{\n" + "clampmap $diffuse\n" + "rgbgen vertex\n" + "alphagen vertex\n" + "blendfunc gl_src_alpha gl_one_minus_src_alpha\n" + "}\n" + "sort additive\n" + "}\n" + ); + TEXASSIGN(s->defaulttextures.base, R_LoadHiResTexture(s->name, NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP)); + } } qboolean Shader_ReadShaderTerms(shader_t *s, char **shadersource, int parsemode, int *conddepth, int maxconddepth, int *cond) diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 5acc0210a..da4dfd148 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -2263,6 +2263,19 @@ void GL_Init(void *(*getglfunction) (char *name)) sh_config.texfmt[PTI_ARGB1555] = true; } } + if (!gl_config.gles && (gl_config.glversion >= 1.4 || GL_CheckExtension("GL_ARB_depth_texture"))) + { //depth formats + sh_config.texfmt[PTI_DEPTH16] = true; + sh_config.texfmt[PTI_DEPTH24] = true; + sh_config.texfmt[PTI_DEPTH32] = true; + } + else if (gl_config.gles && GL_CheckExtension("GL_OES_depth_texture")) + { //16+32, not 24. + sh_config.texfmt[PTI_DEPTH16] = true; + sh_config.texfmt[PTI_DEPTH32] = true; + } + if (GL_CheckExtension("GL_EXT_packed_depth_stencil")) + sh_config.texfmt[PTI_DEPTH24_8] = true; sh_config.minver = gl_config.arb_shader_objects?110:0; sh_config.maxver = gl_config.arb_shader_objects?gl_config.maxglslversion:0; diff --git a/engine/gl/glsupp.h b/engine/gl/glsupp.h index 16dcd524a..d57d04b9b 100644 --- a/engine/gl/glsupp.h +++ b/engine/gl/glsupp.h @@ -133,8 +133,15 @@ extern qlpMTex2FUNC qglMultiTexCoord2fARB; #define GL_DEPTH_TEXTURE_MODE_ARB 0x884B #endif +//GL_OES_depth_texture adds this because gles otherwise lacks it. +#ifndef GL_UNSIGNED_INT +#define GL_UNSIGNED_INT 0x1405 +#endif + #ifndef GL_EXT_packed_depth_stencil #define GL_DEPTH24_STENCIL8_EXT 0x88F0 +#define GL_DEPTH_STENCIL_EXT 0x84F9 +#define GL_UNSIGNED_INT_24_8_EXT 0x84FA #endif #ifndef GL_ARB_shadow diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index beef1ec81..fdac4a8b4 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -477,7 +477,12 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "uniform sampler2D s_t0;\n" "void main ()\n" "{\n" -"gl_FragColor = texture2D(s_t0, tc) * vc;\n" +"vec4 f = vc;\n" +"#ifdef PREMUL\n" +"f.rgb *= f.a;\n" +"#endif\n" +"f *= texture2D(s_t0, tc);\n" +"gl_FragColor = f;\n" "}\n" "#endif\n" }, diff --git a/engine/gl/shader.h b/engine/gl/shader.h index ff026a11d..6f9328143 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -485,6 +485,7 @@ enum struct shader_s { char name[MAX_QPATH]; + char mapname[MAX_QPATH]; enum { SUF_NONE = 0, SUF_LIGHTMAP = 1<<0, //$lightmap passes are valid. otherwise collapsed to an rgbgen @@ -542,6 +543,7 @@ struct shader_s SHADER_HASGLOSS = 1 << 24, //needs a _spec texture, if possible. SHADER_NOSHADOWS = 1 << 25, //don't cast shadows SHADER_HASFULLBRIGHT = 1 << 26, //needs a fullbright texture, if possible. + SHADER_HASDIFFUSE = 1 << 27, //has a T_GEN_DIFFUSE pass } flags; program_t *prog; @@ -627,7 +629,7 @@ typedef struct #define FBO_TEX_DEPTH 32 //internal #define FBO_TEX_STENCIL 64 //internal - +#ifndef __cplusplus //C++ sucks typedef struct { char *progpath; //path to use for glsl/hlsl @@ -655,6 +657,7 @@ typedef struct void (*pProgAutoFields) (program_t *prog, char **cvarnames, int *cvartypes); } sh_config_t; extern sh_config_t sh_config; +#endif #ifdef GLSLONLY #define gl_config_nofixedfunc true diff --git a/engine/http/ftpserver.c b/engine/http/ftpserver.c index eb6623d4b..325a67b82 100644 --- a/engine/http/ftpserver.c +++ b/engine/http/ftpserver.c @@ -134,7 +134,7 @@ void FTP_ServerShutdown(void) } //we ought to filter this to remove duplicates. -static int QDECL SendFileNameTo(const char *rawname, qofs_t size, void *param, searchpathfuncs_t *spath) +static int QDECL SendFileNameTo(const char *rawname, qofs_t size, time_t mtime, void *param, searchpathfuncs_t *spath) { SOCKET socket = *(SOCKET*)param; // int i; diff --git a/engine/libs/mingw64-libs/jerror.h b/engine/libs/mingw64-libs/jerror.h index 1cfb2b19d..a4b661f71 100755 --- a/engine/libs/mingw64-libs/jerror.h +++ b/engine/libs/mingw64-libs/jerror.h @@ -2,7 +2,7 @@ * jerror.h * * Copyright (C) 1994-1997, Thomas G. Lane. - * Modified 1997-2009 by Guido Vollbeding. + * Modified 1997-2012 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -106,11 +106,11 @@ JMESSAGE(JERR_QUANT_COMPONENTS, "Cannot quantize more than %d color components") JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_BEFORE, "Invalid JPEG file structure: %s before SOF") JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") -JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") diff --git a/engine/libs/mingw64-libs/jmorecfg.h b/engine/libs/mingw64-libs/jmorecfg.h index 928d052c8..2407edbef 100755 --- a/engine/libs/mingw64-libs/jmorecfg.h +++ b/engine/libs/mingw64-libs/jmorecfg.h @@ -2,7 +2,7 @@ * jmorecfg.h * * Copyright (C) 1991-1997, Thomas G. Lane. - * Modified 1997-2009 by Guido Vollbeding. + * Modified 1997-2012 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -210,6 +210,26 @@ typedef unsigned int JDIMENSION; #endif +/* The noreturn type identifier is used to declare functions + * which cannot return. + * Compilers can thus create more optimized code and perform + * better checks for warnings and errors. + * Static analyzer tools can make improved inferences about + * execution paths and are prevented from giving false alerts. + * + * Unfortunately, the proposed specifications of corresponding + * extensions in the Dec 2011 ISO C standard revision (C11), + * GCC, MSVC, etc. are not viable. + * Thus we introduce a user defined type to declare noreturn + * functions at least for clarity. A proper compiler would + * have a suitable noreturn type to match in place of void. + */ + +#ifndef HAVE_NORETURN_T +typedef void noreturn_t; +#endif + + /* Here is the pseudo-keyword for declaring pointers that must be "far" * on 80x86 machines. Most of the specialized coding for 80x86 is handled * by just saying "FAR *" where such a pointer is needed. In a few places @@ -232,15 +252,16 @@ typedef unsigned int JDIMENSION; * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. */ -#ifndef HAVE_BOOLEAN -typedef int boolean; -#endif +#ifdef HAVE_BOOLEAN #ifndef FALSE /* in case these macros already exist */ #define FALSE 0 /* values of boolean */ #endif #ifndef TRUE #define TRUE 1 #endif +#else +typedef enum { FALSE = 0, TRUE = 1 } boolean; +#endif /* @@ -312,9 +333,7 @@ typedef int boolean; * the offsets will also change the order in which colormap data is organized. * RESTRICTIONS: * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. - * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not - * useful if you are using JPEG color spaces other than YCbCr or grayscale. - * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * 2. The color quantizer modules will not behave desirably if RGB_PIXELSIZE * is not 3 (they don't understand about dummy color components!). So you * can't use color quantization if you change that value. */ diff --git a/engine/libs/mingw64-libs/jpeglib.h b/engine/libs/mingw64-libs/jpeglib.h index 5039d4bf4..0a6dac44c 100755 --- a/engine/libs/mingw64-libs/jpeglib.h +++ b/engine/libs/mingw64-libs/jpeglib.h @@ -2,7 +2,7 @@ * jpeglib.h * * Copyright (C) 1991-1998, Thomas G. Lane. - * Modified 2002-2009 by Guido Vollbeding. + * Modified 2002-2012 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -33,11 +33,13 @@ extern "C" { #endif #endif -/* Version ID for the JPEG library. - * Might be useful for tests like "#if JPEG_LIB_VERSION >= 80". +/* Version IDs for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 90". */ -#define JPEG_LIB_VERSION 80 /* Version 8.0 */ +#define JPEG_LIB_VERSION 90 /* Compatibility version 9.0 */ +#define JPEG_LIB_VERSION_MAJOR 9 +#define JPEG_LIB_VERSION_MINOR 0 /* Various constants determining the sizes of things. @@ -45,7 +47,7 @@ extern "C" { * if you want to be compatible. */ -#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE 8 /* The basic DCT block is 8x8 coefficients */ #define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ #define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ #define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ @@ -219,6 +221,13 @@ typedef enum { JCS_YCCK /* Y/Cb/Cr/K */ } J_COLOR_SPACE; +/* Supported color transforms. */ + +typedef enum { + JCT_NONE = 0, + JCT_SUBTRACT_GREEN = 1 +} J_COLOR_TRANSFORM; + /* DCT/IDCT algorithm options. */ typedef enum { @@ -367,7 +376,10 @@ struct jpeg_compress_struct { UINT16 X_density; /* Horizontal pixel density */ UINT16 Y_density; /* Vertical pixel density */ boolean write_Adobe_marker; /* should an Adobe marker be written? */ - + + J_COLOR_TRANSFORM color_transform; + /* Color transform identifier, writes LSE marker if nonzero */ + /* State variable: index of next scanline to be written to * jpeg_write_scanlines(). Application may use this to control its * processing loop, e.g., "while (next_scanline < image_height)". @@ -587,6 +599,9 @@ struct jpeg_decompress_struct { boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + J_COLOR_TRANSFORM color_transform; + /* Color transform identifier derived from LSE marker, otherwise zero */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ /* Aside from the specific data retained from APPn markers known to the @@ -679,7 +694,7 @@ struct jpeg_decompress_struct { struct jpeg_error_mgr { /* Error exit handler: does not return to caller */ - JMETHOD(void, error_exit, (j_common_ptr cinfo)); + JMETHOD(noreturn_t, error_exit, (j_common_ptr cinfo)); /* Conditionally emit a trace or warning message */ JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); /* Routine that actually outputs a trace or error message */ diff --git a/engine/libs/mingw64-libs/jversion.h b/engine/libs/mingw64-libs/jversion.h index daf9db243..232085f13 100644 --- a/engine/libs/mingw64-libs/jversion.h +++ b/engine/libs/mingw64-libs/jversion.h @@ -1,14 +1,14 @@ -/* - * jversion.h - * - * Copyright (C) 1991-2010, Thomas G. Lane, Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains software version identification. - */ - - -#define JVERSION "8b 16-May-2010" - -#define JCOPYRIGHT "Copyright (C) 2010, Thomas G. Lane, Guido Vollbeding" +/* + * jversion.h + * + * Copyright (C) 1991-2013, Thomas G. Lane, Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains software version identification. + */ + + +#define JVERSION "9 13-Jan-2013" + +#define JCOPYRIGHT "Copyright (C) 2013, Thomas G. Lane, Guido Vollbeding" diff --git a/engine/libs/mingw64-libs/libjpeg.a b/engine/libs/mingw64-libs/libjpeg.a index 14ae372b8..d5dcea860 100755 Binary files a/engine/libs/mingw64-libs/libjpeg.a and b/engine/libs/mingw64-libs/libjpeg.a differ diff --git a/engine/libs/mingw64-libs/libogg.a b/engine/libs/mingw64-libs/libogg.a index d8d895fde..4f2cecf9a 100644 Binary files a/engine/libs/mingw64-libs/libogg.a and b/engine/libs/mingw64-libs/libogg.a differ diff --git a/engine/libs/mingw64-libs/libvorbis.a b/engine/libs/mingw64-libs/libvorbis.a index 1b8f870fb..ba28d58dd 100644 Binary files a/engine/libs/mingw64-libs/libvorbis.a and b/engine/libs/mingw64-libs/libvorbis.a differ diff --git a/engine/libs/mingw64-libs/libvorbisfile.a b/engine/libs/mingw64-libs/libvorbisfile.a index ef0fc37f2..2c98ee87e 100644 Binary files a/engine/libs/mingw64-libs/libvorbisfile.a and b/engine/libs/mingw64-libs/libvorbisfile.a differ diff --git a/engine/libs/mingw64-libs/libz.a b/engine/libs/mingw64-libs/libz.a index f4c5c9579..42263a32f 100755 Binary files a/engine/libs/mingw64-libs/libz.a and b/engine/libs/mingw64-libs/libz.a differ diff --git a/engine/libs/mingw64-libs/zconf.h b/engine/libs/mingw64-libs/zconf.h index 02ce56c43..996fff292 100755 --- a/engine/libs/mingw64-libs/zconf.h +++ b/engine/libs/mingw64-libs/zconf.h @@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2010 Jean-loup Gailly. + * Copyright (C) 1995-2013 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -15,11 +15,13 @@ * this permanently in zconf.h using "./configure --zprefix". */ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET /* all linked symbols */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits # define _tr_flush_block z__tr_flush_block # define _tr_init z__tr_init # define _tr_stored_block z__tr_stored_block @@ -27,9 +29,11 @@ # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 @@ -40,44 +44,53 @@ # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams +# define deflatePending z_deflatePending # define deflatePrime z_deflatePrime # define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep # define deflateSetDictionary z_deflateSetDictionary # define deflateSetHeader z_deflateSetHeader # define deflateTune z_deflateTune # define deflate_copyright z_deflate_copyright # define get_crc_table z_get_crc_table -# define gz_error z_gz_error -# define gz_intmax z_gz_intmax -# define gz_strwinerror z_gz_strwinerror -# define gzbuffer z_gzbuffer -# define gzclearerr z_gzclearerr -# define gzclose z_gzclose -# define gzclose_r z_gzclose_r -# define gzclose_w z_gzclose_w -# define gzdirect z_gzdirect -# define gzdopen z_gzdopen -# define gzeof z_gzeof -# define gzerror z_gzerror -# define gzflush z_gzflush -# define gzgetc z_gzgetc -# define gzgets z_gzgets -# define gzoffset z_gzoffset -# define gzoffset64 z_gzoffset64 -# define gzopen z_gzopen -# define gzopen64 z_gzopen64 -# define gzprintf z_gzprintf -# define gzputc z_gzputc -# define gzputs z_gzputs -# define gzread z_gzread -# define gzrewind z_gzrewind -# define gzseek z_gzseek -# define gzseek64 z_gzseek64 -# define gzsetparams z_gzsetparams -# define gztell z_gztell -# define gztell64 z_gztell64 -# define gzungetc z_gzungetc -# define gzwrite z_gzwrite +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzvprintf z_gzvprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd @@ -92,16 +105,22 @@ # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 # define inflateSetDictionary z_inflateSetDictionary +# define inflateGetDictionary z_inflateGetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine +# define inflateResetKeep z_inflateResetKeep # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table -# define uncompress z_uncompress +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif # define zError z_zError -# define zcalloc z_zcalloc -# define zcfree z_zcfree +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif # define zlibCompileFlags z_zlibCompileFlags # define zlibVersion z_zlibVersion @@ -111,7 +130,9 @@ # define alloc_func z_alloc_func # define charf z_charf # define free_func z_free_func -# define gzFile z_gzFile +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif # define gz_header z_gz_header # define gz_headerp z_gz_headerp # define in_func z_in_func @@ -197,6 +218,12 @@ # endif #endif +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + /* Some Mac compilers merge all .h files incorrectly: */ #if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) # define NO_DUMMY_DECL @@ -243,6 +270,14 @@ # endif #endif +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have @@ -356,12 +391,47 @@ typedef uLong FAR uLongf; typedef Byte *voidp; #endif -#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#if 1 /* was set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif +#if 1 /* was set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + #ifdef STDC -# include /* for off_t */ +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif #endif /* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and @@ -370,21 +440,38 @@ typedef uLong FAR uLongf; * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ -#if -_LARGEFILE64_SOURCE - -1 == 1 +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif -#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# ifndef z_off_t -# define z_off_t off_t +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif # endif #endif -#ifndef SEEK_SET +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ @@ -394,18 +481,14 @@ typedef uLong FAR uLongf; # define z_off_t long #endif -#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +#if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else -# define z_off64_t z_off_t -#endif - -#if defined(__OS400__) -# define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif #endif /* MVS linker does not support external names larger than 8 bytes */ diff --git a/engine/libs/mingw64-libs/zlib.h b/engine/libs/mingw64-libs/zlib.h index bfbba83e8..3e0c7672a 100755 --- a/engine/libs/mingw64-libs/zlib.h +++ b/engine/libs/mingw64-libs/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.5, April 19th, 2010 + version 1.2.8, April 28th, 2013 - Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -24,8 +24,8 @@ The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ #ifndef ZLIB_H @@ -37,11 +37,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.5" -#define ZLIB_VERNUM 0x1250 +#define ZLIB_VERSION "1.2.8" +#define ZLIB_VERNUM 0x1280 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 5 +#define ZLIB_VER_REVISION 8 #define ZLIB_VER_SUBREVISION 0 /* @@ -83,15 +83,15 @@ typedef void (*free_func) OF((voidpf opaque, voidpf address)); struct internal_state; typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ + z_const Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ + uLong total_in; /* total number of input bytes read so far */ Bytef *next_out; /* next output byte should be put there */ uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ + uLong total_out; /* total number of bytes output so far */ - char *msg; /* last error message, NULL if no error */ + z_const char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ @@ -327,8 +327,9 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); Z_FINISH can be used immediately after deflateInit if all the compression is to be done in a single step. In this case, avail_out must be at least the - value returned by deflateBound (see below). If deflate does not return - Z_STREAM_END, then it must be called again as described above. + value returned by deflateBound (see below). Then deflate is guaranteed to + return Z_STREAM_END. If not enough output space is provided, deflate will + not return Z_STREAM_END, and it must be called again as described above. deflate() sets strm->adler to the adler32 checksum of all input read so far (that is, total_in bytes). @@ -451,23 +452,29 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; - avail_out must be large enough to hold all the uncompressed data. (The size - of the uncompressed data may have been saved by the compressor for this - purpose.) The next operation on this stream must be inflateEnd to deallocate - the decompression state. The use of Z_FINISH is never required, but can be - used to inform inflate that a faster approach may be used for the single - inflate() call. + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK or Z_TREES is used. + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the adler32 checksum of the dictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the adler32 checksum of all output produced so far (that is, + strm->adler to the Adler-32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed adler32 checksum is equal to that saved by the compressor and returns Z_STREAM_END @@ -478,7 +485,9 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); initializing with inflateInit2(). Any information contained in the gzip header is not retained, so applications that need that information should instead use raw inflate, see inflateInit2() below, or inflateBack() and - perform their own processing of the gzip header and trailer. + perform their own processing of the gzip header and trailer. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + producted so far. The CRC-32 is checked against the gzip trailer. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has @@ -580,10 +589,15 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, uInt dictLength)); /* Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any call - of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly @@ -610,8 +624,8 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, @@ -688,9 +702,29 @@ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be - called before deflate(). + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. */ +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, int bits, int value)); @@ -703,8 +737,9 @@ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, than or equal to 16, and that many of the least significant bits of value will be inserted in the output. - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, @@ -790,10 +825,11 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the adler32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called - immediately after inflateInit2() or inflateReset() and before any call of - inflate() to set the dictionary. The application must insure that the - dictionary that was used for compression is provided. + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is @@ -803,19 +839,38 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, inflate(). */ +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); /* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been - found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the - success case, the application may save the current current value of total_in - which indicates where valid compressed data was found. In the error case, - the application may repeatedly call inflateSync, providing more input each - time, until success or end of the input data. + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, @@ -962,12 +1017,13 @@ ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the paramaters are invalid, Z_MEM_ERROR if the internal state could not be + the parameters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, @@ -975,11 +1031,12 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, out_func out, void FAR *out_desc)); /* inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is more efficient than inflate() for - file i/o applications in that it avoids copying between the output and the - sliding window by simply making the window itself the output buffer. This - function trusts the application to not change the output buffer passed by - the output function, at least until inflateBack() returns. + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. @@ -1088,6 +1145,7 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); 27-31: 0 (reserved) */ +#ifndef Z_SOLO /* utility functions */ @@ -1149,10 +1207,11 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. */ - /* gzip file access functions */ /* @@ -1162,7 +1221,7 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, wrapper, documented in RFC 1952, wrapped around a deflate stream. */ -typedef voidp gzFile; /* opaque gzip file descriptor */ +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); @@ -1172,13 +1231,28 @@ ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of - deflateInit2 for more information about the strategy parameter.) Also "a" - can be used instead of "w" to request that the gzip stream that will be - written be appended to the file. "+" will result in an error, since reading - and writing to the same gzip file is not supported. + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was @@ -1197,7 +1271,11 @@ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since - gzdopen does not close fd if it fails. + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not @@ -1235,14 +1313,26 @@ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); /* Reads the given number of uncompressed bytes from the compressed file. If - the input file was not in gzip format, gzread copies the given number of - bytes into the buffer. + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. After reaching the end of a gzip stream in the input, gzread will continue - to read, looking for another gzip stream, or failing that, reading the rest - of the input file directly without decompression. The entire input file - will be read if gzread is called until it returns less than the requested - len. + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. @@ -1256,7 +1346,7 @@ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, error. */ -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of @@ -1301,7 +1391,10 @@ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); /* Reads one byte from the compressed file. gzgetc returns this byte or -1 - in case of end of file or error. + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. */ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); @@ -1397,9 +1490,7 @@ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); /* Returns true (1) if file is being copied directly while reading, or false - (0) if file is a gzip stream being decompressed. This state can change from - false to true while reading the input file if the end of a gzip stream is - reached, but is followed by data that is not another gzip stream. + (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. @@ -1408,6 +1499,13 @@ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) */ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); @@ -1419,7 +1517,8 @@ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a - file operation error, or Z_OK on success. + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); @@ -1457,6 +1556,7 @@ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); file that is being written concurrently. */ +#endif /* !Z_SOLO */ /* checksum functions */ @@ -1492,16 +1592,17 @@ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is Z_NULL, this function returns the required - initial value for the for the crc. Pre- and post-conditioning (one's - complement) is performed within this function so it shouldn't be done by the - application. + initial value for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. Usage example: @@ -1544,17 +1645,42 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); #define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) #define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) #define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, sizeof(z_stream)) + ZLIB_VERSION, (int)sizeof(z_stream)) + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#endif /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if @@ -1562,7 +1688,7 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */ -#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +#ifdef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); @@ -1571,14 +1697,23 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); #endif -#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 -# define gzopen gzopen64 -# define gzseek gzseek64 -# define gztell gztell64 -# define gzoffset gzoffset64 -# define adler32_combine adler32_combine64 -# define crc32_combine crc32_combine64 -# ifdef _LARGEFILE64_SOURCE +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); @@ -1595,6 +1730,13 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + /* hack for buggy compilers */ #if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) struct internal_state {int dummy;}; @@ -1603,8 +1745,21 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif #ifdef __cplusplus } diff --git a/engine/libs/mingw64-libs/zutil.h b/engine/libs/mingw64-libs/zutil.h index 258fa8879..24ab06b1c 100755 --- a/engine/libs/mingw64-libs/zutil.h +++ b/engine/libs/mingw64-libs/zutil.h @@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2010 Jean-loup Gailly. + * Copyright (C) 1995-2013 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -13,7 +13,7 @@ #ifndef ZUTIL_H #define ZUTIL_H -#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) +#ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL @@ -21,7 +21,7 @@ #include "zlib.h" -#ifdef STDC +#if defined(STDC) && !defined(Z_SOLO) # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) # include # endif @@ -29,6 +29,10 @@ # include #endif +#ifdef Z_SOLO + typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ +#endif + #ifndef local # define local static #endif @@ -40,13 +44,13 @@ typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; -extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) + return (strm->msg = ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ @@ -78,16 +82,18 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) # define OS_CODE 0x00 -# if defined(__TURBOC__) || defined(__BORLANDC__) -# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) - /* Allow compilation with ANSI keywords only enabled */ - void _Cdecl farfree( void *block ); - void *_Cdecl farmalloc( unsigned long nbytes ); -# else -# include +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include # endif -# else /* MSC or DJGPP */ -# include # endif #endif @@ -107,18 +113,20 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #ifdef OS2 # define OS_CODE 0x06 -# ifdef M_I86 +# if defined(M_I86) && !defined(Z_SOLO) # include # endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 0x07 -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef Z_SOLO +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif # endif # endif #endif @@ -153,14 +161,15 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # endif #endif -#if defined(__BORLANDC__) +#if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 #pragma warn -8066 #endif /* provide prototypes for these when building zlib without LFS */ -#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); #endif @@ -177,42 +186,7 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* functions */ -#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#if defined(__CYGWIN__) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#ifndef HAVE_VSNPRINTF -# ifdef MSDOS - /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), - but for now we just assume it doesn't. */ -# define NO_vsnprintf -# endif -# ifdef __TURBOC__ -# define NO_vsnprintf -# endif -# ifdef WIN32 - /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) -# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) -# define vsnprintf _vsnprintf -# endif -# endif -# endif -# ifdef __SASC -# define NO_vsnprintf -# endif -#endif -#ifdef VMS -# define NO_vsnprintf -#endif - -#if defined(pyr) +#if defined(pyr) || defined(Z_SOLO) # define NO_MEMCPY #endif #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) @@ -261,14 +235,19 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # define Tracecv(c,x) #endif - -voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, - unsigned size)); -void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); + void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#endif #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + #endif /* ZUTIL_H */ diff --git a/engine/qclib/cmdlib.h b/engine/qclib/cmdlib.h index 4e7859091..e146ad01c 100644 --- a/engine/qclib/cmdlib.h +++ b/engine/qclib/cmdlib.h @@ -37,6 +37,10 @@ int QCC_tell (int handle); int QC_strcasecmp (const char *s1, const char *s2); +void QC_strlcat(char *dest, const char *src, size_t destsize); +void QC_strlcpy(char *dest, const char *src, size_t destsize); +void QC_strnlcpy(char *dest, const char *src, size_t srclen, size_t destsize); + #ifdef _MSC_VER #define QC_vsnprintf _vsnprintf static void VARGS QC_snprintfz (char *dest, size_t size, const char *fmt, ...) diff --git a/engine/qclib/comprout.c b/engine/qclib/comprout.c index 220811aac..ce12c04e3 100644 --- a/engine/qclib/comprout.c +++ b/engine/qclib/comprout.c @@ -91,10 +91,7 @@ pbool CompileParams(progfuncs_t *progfuncs, int doall, int nump, char **parms) PostCompile(); if (*errorfile) { - if (!externs->useeditor) - printf("Error in %s on line %i\n", errorfile, errorline); - else - externs->useeditor(&progfuncs->funcs, errorfile, errorline, 0, nump, parms); + printf("Error in %s on line %i\n", errorfile, errorline); } return false; } @@ -118,8 +115,6 @@ int PDECL Comp_Begin(pubprogfuncs_t *progfuncs, int nump, char **parms) if (setjmp(qcccompileerror)) { PostCompile(); - if (*errorfile) - progfuncs->parms->useeditor(&qccprogfuncs->funcs, errorfile, errorline, 0, nump, parms); return false; } @@ -134,8 +129,6 @@ int PDECL Comp_Continue(pubprogfuncs_t *progfuncs) if (setjmp(qcccompileerror)) { PostCompile(); - if (*errorfile && progfuncs->parms->useeditor) - progfuncs->parms->useeditor(progfuncs, errorfile, errorline, 0, comp_nump, comp_parms); return false; } @@ -145,9 +138,6 @@ int PDECL Comp_Continue(pubprogfuncs_t *progfuncs) { PostCompile(); - if (*errorfile && progfuncs->parms->useeditor) - progfuncs->parms->useeditor(progfuncs, errorfile, errorline, 0 , comp_nump, comp_parms); - return false; } diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index a56b046b1..c673db6e3 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -31,18 +31,16 @@ #error Bad cont size #endif -#ifdef DEBUGABLE -#define OPCODE (progfuncs->funcs.pr_trace?(st->op & ~0x8000):st->op) -#else -#define OPCODE (st->op) -#endif - #define ENGINEPOINTER(p) ((char*)(p) - progfuncs->funcs.stringtable) #define QCPOINTER(p) (eval_t *)(p->_int+progfuncs->funcs.stringtable) #define QCPOINTERM(p) (eval_t *)((p)+progfuncs->funcs.stringtable) #define QCPOINTERWRITEFAIL(p,sz) ((unsigned int)p->_int-1 >= prinst.addressableused-1-sz) //disallows null writes #define QCPOINTERREADFAIL(p,sz) ((unsigned int)p->_int >= prinst.addressableused-sz) //permits null reads + + +#define QCFAULT return (pr_xstatement=(st-pr_statements)-1),PR_HandleFault + //rely upon just st { #ifdef DEBUGABLE @@ -69,20 +67,23 @@ cont: //last statement may have been a breakpoint } prinst.watch_old = *prinst.watch_ptr; // prinst.watch_ptr = NULL; - if (progfuncs->funcs.pr_trace<1) - progfuncs->funcs.pr_trace=1; //this is what it's for - } + progfuncs->funcs.debug_trace=DEBUG_TRACE_INTO; //this is what it's for - if (progfuncs->funcs.pr_trace) - s=ShowStep(progfuncs, s); + s=ShowStep(progfuncs, s, "Watchpoint hit"); + } + else if (progfuncs->funcs.debug_trace) + s=ShowStep(progfuncs, s, NULL); st = pr_statements + s; pr_xfunction->profile+=1; + op = (progfuncs->funcs.debug_trace?(st->op & ~0x8000):st->op); reeval: #else st++; + op = st->op; #endif - switch (OPCODE) + + switch (op) { case OP_ADD_F: OPC->_float = OPA->_float + OPB->_float; @@ -338,8 +339,7 @@ reeval: { if (OPB->_int == -1) break; - pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + QCFAULT(&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); } ptr = QCPOINTER(OPB); ptr->_float = (float)OPA->_int; @@ -349,8 +349,7 @@ reeval: { if (OPB->_int == -1) break; - pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + QCFAULT(&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); } ptr = QCPOINTER(OPB); ptr->_int = (int)OPA->_float; @@ -365,8 +364,7 @@ reeval: { if (OPB->_int == -1) break; - pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); ptr->_int = OPA->_int; @@ -376,8 +374,7 @@ reeval: { if (OPB->_int == -1) break; - pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); ptr->_vector[0] = OPA->_vector[0]; @@ -388,8 +385,7 @@ reeval: case OP_STOREP_C: //store character in a string if (QCPOINTERWRITEFAIL(OPB, sizeof(char))) { - pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); *(unsigned char *)ptr = (char)OPA->_float; @@ -400,7 +396,7 @@ reeval: if ((unsigned)OPA->edict >= (unsigned)sv_num_edicts) { pr_xstatement = st-pr_statements; - if (PR_RunWarning (&progfuncs->funcs, "OP_ADDRESS references invalid entity in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name))) + if (PR_RunWarning (&progfuncs->funcs, "OP_ADDRESS references invalid entity in %s\n", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name))) { st--; goto cont; @@ -421,7 +417,7 @@ reeval: d16 = ED_GlobalAtOfs16(progfuncs, st->a); f = ED_FieldAtOfs(progfuncs, OPB->_int + progfuncs->funcs.fieldadjust); pr_xstatement = st-pr_statements; - if (PR_RunWarning(&progfuncs->funcs, "assignment to read-only entity %i in %s (%s.%s)", OPA->edict, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), d16?PR_StringToNative(&progfuncs->funcs, d16->s_name):NULL, f?f->name:NULL)) + if (PR_RunWarning(&progfuncs->funcs, "assignment to read-only entity %i in %s (%s.%s)\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), d16?PR_StringToNative(&progfuncs->funcs, d16->s_name):NULL, f?f->name:NULL)) { st--; goto cont; @@ -451,7 +447,7 @@ reeval: if ((unsigned)OPA->edict >= (unsigned)sv_num_edicts) { pr_xstatement = st-pr_statements; - if (PR_RunWarning (&progfuncs->funcs, "OP_LOAD references invalid entity %i in %s", OPA->edict, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name))) + if (PR_RunWarning (&progfuncs->funcs, "OP_LOAD references invalid entity %i in %s\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name))) { st--; goto cont; @@ -471,7 +467,7 @@ reeval: if ((unsigned)OPA->edict >= (unsigned)sv_num_edicts) { pr_xstatement = st-pr_statements; - if (PR_RunWarning (&progfuncs->funcs, "OP_LOAD_V references invalid entity %i in %s", OPA->edict, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name))) + if (PR_RunWarning (&progfuncs->funcs, "OP_LOAD_V references invalid entity %i in %s\n", OPA->edict, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name))) { st--; goto cont; @@ -565,10 +561,10 @@ reeval: RUNAWAYCHECK(); pr_xstatement = st-pr_statements; - if (OPCODE > OP_CALL8) - progfuncs->funcs.callargc = OPCODE - (OP_CALL1H-1); + if (op > OP_CALL8) + progfuncs->funcs.callargc = op - (OP_CALL1H-1); else - progfuncs->funcs.callargc = OPCODE - OP_CALL0; + progfuncs->funcs.callargc = op - OP_CALL0; fnum = OPA->function; glob = NULL; //try to derestrict it. @@ -583,26 +579,23 @@ reeval: char *msg = fnum?"OP_CALL references invalid function in %s\n":"NULL function from qc (inside %s).\n"; PR_SwitchProgsParms(progfuncs, callerprogs); - //break/skip the instruction. + glob = pr_globals; + if (!progfuncs->funcs.debug_trace) + QCFAULT(&progfuncs->funcs, msg, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + + //skip the instruction if they just try stepping over it anyway. PR_StackTrace(&progfuncs->funcs, 0); printf(msg, PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); - glob = pr_globals; -#ifndef DEBUGABLE - progfuncs->funcs.pr_trace++; - st--; - goto cont; -#else pr_globals[OFS_RETURN] = 0; pr_globals[OFS_RETURN+1] = 0; pr_globals[OFS_RETURN+2] = 0; break; -#endif } newf = &pr_cp_functions[fnum & ~0xff000000]; - if (newf->first_statement < 0) + if (newf->first_statement <= 0) { // negative statements are built in functions /*calling a builtin in another progs may affect that other progs' globals instead, is the theory anyway, so args and stuff need to move over*/ if (pr_typecurrent != 0) @@ -613,7 +606,6 @@ reeval: } i = -newf->first_statement; // p = pr_typecurrent; - progfuncs->funcs.lastcalledbuiltinnumber = i; if (i < externs->numglobalbuiltins) { #ifndef QCGC @@ -630,16 +622,10 @@ reeval: } else { - i -= externs->numglobalbuiltins; - if (i >= current_progstate->numbuiltins) - { - // if (newf->first_statement == -0x7fffffff) - // ((builtin_t)newf->profile) (progfuncs, (struct globalvars_s *)current_progstate->globals); - // else - PR_RunError (&progfuncs->funcs, "Bad builtin call number - %i", -newf->first_statement); - } - else - current_progstate->builtins [i] (&progfuncs->funcs, (struct globalvars_s *)current_progstate->globals); +// if (newf->first_statement == -0x7fffffff) +// ((builtin_t)newf->profile) (progfuncs, (struct globalvars_s *)current_progstate->globals); +// else + PR_RunError (&progfuncs->funcs, "Bad builtin call number - %i", -newf->first_statement); } // memcpy(&pr_progstate[p].globals[OFS_RETURN], ¤t_progstate->globals[OFS_RETURN], sizeof(vec3_t)); PR_SwitchProgsParms(progfuncs, (progsnum_t)callerprogs); @@ -836,7 +822,7 @@ reeval: OPC->_vector[2] = ptr->_vector[2]; break; - case OP_XOR_I: + case OP_BITXOR_I: OPC->_int = OPA->_int ^ OPB->_int; break; case OP_RSHIFT_I: @@ -1044,7 +1030,7 @@ reeval: //the case opcodes depend upon the preceding switch. //otherwise the switch itself is much like a goto //don't embed the case/caserange checks directly into the switch so that custom caseranges can be potentially be implemented with hybrid emulation. - switchcomparison = OPCODE - OP_SWITCH_F; + switchcomparison = op - OP_SWITCH_F; switchref = OPA; RUNAWAYCHECK(); st += (sofs)st->b - 1; // offset the s++ @@ -1207,12 +1193,13 @@ reeval: if ((unsigned int)OPA->_int < (unsigned int)st->c || (unsigned int)OPA->_int >= (unsigned int)st->b) { printf("Progs boundcheck failed. Value is %i. Must be between %u and %u\n", OPA->_int, st->c, st->b); - s=ShowStep(progfuncs, st - pr_statements); + QCFAULT(&progfuncs->funcs, "Progs boundcheck failed. Value is %i. Must be between %u and %u\n", OPA->_int, st->c, st->b); +/* s=ShowStepf(progfuncs, st - pr_statements, "Progs boundcheck failed. Value is %i. Must be between %u and %u\n", OPA->_int, st->c, st->b); if (st == pr_statements + s) PR_RunError(&progfuncs->funcs, "unable to resume boundcheck"); st = pr_statements + s; return s; - } +*/ } break; /* case OP_PUSH: OPC->_int = ENGINEPOINTER(&localstack[localstack_used+pr_spushed]); @@ -1235,18 +1222,19 @@ reeval: break; */ default: - if (st->op & 0x8000) //break point! + if (op & 0x8000) //break point! { - pr_xstatement = s = st-pr_statements; - - printf("Break point hit in %s.\n", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); - if (progfuncs->funcs.pr_trace<1) - progfuncs->funcs.pr_trace=1; //this is what it's for - - s = ShowStep(progfuncs, s); - st = &pr_statements[s]; //let the user move execution - pr_xstatement = s = st-pr_statements; - + op &= ~0x8000; + s = st-pr_statements; + if (pr_xstatement != s) + { + pr_xstatement = s; + printf("Break point hit in %s.\n", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + s = ShowStep(progfuncs, s, NULL); + st = &pr_statements[s]; //let the user move execution + pr_xstatement = s = st-pr_statements; + op = st->op & ~0x8000; + } goto reeval; //reexecute } pr_xstatement = st-pr_statements; diff --git a/engine/qclib/initlib.c b/engine/qclib/initlib.c index 29bbb7e57..1c2a0f9eb 100644 --- a/engine/qclib/initlib.c +++ b/engine/qclib/initlib.c @@ -902,7 +902,7 @@ const char *ASMCALL PR_StringToNative (pubprogfuncs_t *ppf, string_t str) int i = str & ~STRING_SPECMASK; if (i >= prinst.numallocedstrings) { - if (!progfuncs->funcs.pr_trace) //don't spam this + if (!progfuncs->funcs.debug_trace) //don't spam this PR_RunWarning(&progfuncs->funcs, "invalid static string %x\n", str); return ""; } @@ -910,7 +910,7 @@ const char *ASMCALL PR_StringToNative (pubprogfuncs_t *ppf, string_t str) return prinst.allocedstrings[i]; else { - if (!progfuncs->funcs.pr_trace) + if (!progfuncs->funcs.debug_trace) PR_RunWarning(&progfuncs->funcs, "invalid static string %x\n", str); return ""; //urm, was freed... } @@ -920,7 +920,7 @@ const char *ASMCALL PR_StringToNative (pubprogfuncs_t *ppf, string_t str) unsigned int i = str & ~STRING_SPECMASK; if (i >= prinst.numtempstrings || !prinst.tempstrings[i]) { - if (!progfuncs->funcs.pr_trace) + if (!progfuncs->funcs.debug_trace) PR_RunWarning(&progfuncs->funcs, "invalid temp string %x\n", str); return ""; } @@ -929,7 +929,7 @@ const char *ASMCALL PR_StringToNative (pubprogfuncs_t *ppf, string_t str) if ((unsigned int)str >= (unsigned int)prinst.addressableused) { - if (!progfuncs->funcs.pr_trace) + if (!progfuncs->funcs.debug_trace) PR_RunWarning(&progfuncs->funcs, "invalid string offset %x\n", str); return ""; } @@ -1273,8 +1273,7 @@ pubprogfuncs_t deffuncs = { PR_ForkStack, PR_ResumeThread, PR_AbortStack, - - 0, //called builtin number + PR_GetBuiltinCallInfo, QC_RegisterFieldVar, diff --git a/engine/qclib/pr_comp.h b/engine/qclib/pr_comp.h index a018622b9..991710195 100644 --- a/engine/qclib/pr_comp.h +++ b/engine/qclib/pr_comp.h @@ -222,7 +222,7 @@ enum qcop_e { OP_DIV_VF, - OP_XOR_I, //140 + OP_BITXOR_I, //140 OP_RSHIFT_I, OP_LSHIFT_I, @@ -365,8 +365,8 @@ enum qcop_e { OP_LOADA_STRUCT, OP_STOREP_P, - OP_BINARYNOT_F, - OP_BINARYNOT_I, + OP_BITNOT_F, + OP_BITNOT_I, OP_EQ_P, OP_NE_P, @@ -393,6 +393,10 @@ enum qcop_e { OP_MOD_I, OP_MOD_V, + OP_BITXOR_F, //140 + OP_RSHIFT_F, + OP_LSHIFT_F, + OP_NUMOPS }; diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index 7f2dae4ff..5592e615c 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -102,8 +102,7 @@ struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *ppf) if (i >= maxedicts-2) { - printf("Running out of edicts\n"); - progfuncs->funcs.pr_trace = 1; //trip the debugger whilst it's still valid + PR_RunWarning(&progfuncs->funcs, "Running out of edicts\n"); } if (i >= maxedicts-1) { @@ -1782,7 +1781,6 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, int *bufofs, int bufmax, AddS (qcva("progs %i {\n", a)); AddS (qcva("\"filename\" \"%s\"\n", pr_progstate[a].filename)); AddS (qcva("\"crc\" \"%i\"\n", pr_progstate[a].progs->crc)); - AddS (qcva("\"numbuiltins\" \"%i\"\n", pr_progstate[a].numbuiltins)); AddS ("}\n"); } } @@ -1979,8 +1977,8 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl {file = QCC_COM_Parse(file); strcpy(filename, qcc_token);} else if (!strcmp("crc", qcc_token)) {file = QCC_COM_Parse(file); header_crc = atoi(qcc_token);} - else if (!strcmp("numbuiltins", qcc_token)) - {file = QCC_COM_Parse(file); numbuiltins = atoi(qcc_token);} + else if (!strcmp("numbuiltins", qcc_token)) //no longer supported. + {file = QCC_COM_Parse(file); /*qcc_token unused*/} else if (qcc_token[0] == '}') //end of block break; else @@ -1988,17 +1986,6 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl } PR_ReallyLoadProgs(progfuncs, filename, &pr_progstate[num], true); - if (!externs->builtinsfor) - { - // Sys_Error("Couldn't reset the builtin functions"); - current_progstate->builtins = NULL; //these are specific, we assume the global ones were set via pr_configure - current_progstate->numbuiltins = 0; - } - else - { - current_progstate->builtins = externs->builtinsfor(num, header_crc); - current_progstate->numbuiltins = numbuiltins; - } if (num == 0 && oldglobals) { @@ -3332,6 +3319,15 @@ retry: if (progfuncs->funcs.stringtablesize + progfuncs->funcs.stringtable < pr_strings + pr_progs->numstrings) progfuncs->funcs.stringtablesize = (pr_strings + pr_progs->numstrings) - progfuncs->funcs.stringtable; + if (externs->MapNamedBuiltin) + { + for (i=0,fnc2=pr_cp_functions; inumfunctions; i++, fnc2++) + { + if (i && !fnc2->first_statement) + fnc2->first_statement = -externs->MapNamedBuiltin(&progfuncs->funcs, pr_progs->crc, PR_StringToNative(&progfuncs->funcs, fnc2->s_name)); + } + } + eval = PR_FindGlobal(&progfuncs->funcs, "thisprogs", progstype, NULL); if (eval) eval->prog = progstype; diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index 70480a2a5..4c623ae3e 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -367,56 +367,6 @@ void PDECL PR_StackTrace (pubprogfuncs_t *ppf, int showlocals) } } -/* -============ -PR_RunError - -Aborts the currently executing function -============ -*/ -void VARGS PR_RunError (pubprogfuncs_t *progfuncs, char *error, ...) -{ - va_list argptr; - char string[1024]; - - va_start (argptr,error); - Q_vsnprintf (string,sizeof(string)-1, error,argptr); - va_end (argptr); - -// { -// void SV_EndRedirect (void); -// SV_EndRedirect(); -// } - -// PR_PrintStatement (pr_statements + pr_xstatement); - PR_StackTrace (progfuncs, true); - progfuncs->parms->Printf ("\n"); - -//editbadfile(pr_strings + pr_xfunction->s_file, -1); - -// pr_depth = 0; // dump the stack so host_error can shutdown functions -// prinst->exitdepth = 0; - - progfuncs->parms->Abort ("%s", string); -} - -pbool PR_RunWarning (pubprogfuncs_t *progfuncs, char *error, ...) -{ - va_list argptr; - char string[1024]; - - va_start (argptr,error); - Q_vsnprintf (string,sizeof(string)-1, error,argptr); - va_end (argptr); - - progfuncs->parms->Printf ("%s, %s\n", string, ((progfuncs->pr_trace)?"ignoring":"enabling trace")); - PR_StackTrace (progfuncs, false); - - if (progfuncs->pr_trace++ == 0) - return true; - return false; -} - /* ============================================================================ PR_ExecuteProgram @@ -440,6 +390,9 @@ int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, mfunction_t *f, int progsn pr_stack[pr_depth].f = pr_xfunction; pr_stack[pr_depth].progsnum = progsnum; pr_stack[pr_depth].pushed = pr_spushed; + pr_stack[pr_depth].stepping = progfuncs->funcs.debug_trace; + if (progfuncs->funcs.debug_trace == DEBUG_TRACE_OVER) + progfuncs->funcs.debug_trace = DEBUG_TRACE_OFF; if (prinst.profiling) { pr_stack[pr_depth].timestamp = Sys_GetClock(); @@ -515,6 +468,9 @@ int ASMCALL PR_LeaveFunction (progfuncs_t *progfuncs) PR_SwitchProgsParms(progfuncs, pr_stack[pr_depth].progsnum); pr_spushed = pr_stack[pr_depth].pushed; + if (!progfuncs->funcs.debug_trace) + progfuncs->funcs.debug_trace = pr_stack[pr_depth].stepping; + if (prinst.profiling) { unsigned long long cycles; @@ -812,62 +768,68 @@ char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *ppf, char *key) */ if (assignment) { - assignment++; - while(*assignment == ' ') - assignment++; + char *str = assignment+1; + while(*str == ' ') + str++; switch (type&~DEF_SAVEGLOBAL) { case ev_string: #ifdef QCGC - *(string_t *)val = PR_AllocTempString(&progfuncs->funcs, assignment); + *(string_t *)val = PR_AllocTempString(&progfuncs->funcs, str); #else *(string_t *)val = PR_StringToProgs(&progfuncs->funcs, ED_NewString (&progfuncs->funcs, assignment, 0, true)); #endif break; case ev_float: - if (assignment[0] == '0' && (assignment[1] == 'x' || assignment[1] == 'X')) - *(float*)val = strtoul(assignment, NULL, 0); + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + *(float*)val = strtoul(str, NULL, 0); else - *(float *)val = (float)atof (assignment); + *(float *)val = (float)atof (str); break; case ev_integer: - *(int *)val = atoi (assignment); + *(int *)val = atoi (str); break; -/* case ev_vector: - strcpy (string, assignment); - v = string; - w = string; - for (i=0 ; i<3 ; i++) + case ev_vector: { - while (*v && *v != ' ') - v++; - *v = 0; - ((float *)d)[i] = (float)atof (w); - w = v = v+1; + int i; + if (*str == '\'') + str++; + for (i = 0; i < 3; i++) + { + while(*str == ' ' || *str == '\t') + str++; + ((float *)val)[i] = strtod(str, &str); + } + while(*str == ' ' || *str == '\t') + str++; + if (*str == '\'') + str++; } break; -*/ + case ev_entity: - if (!EDICT_NUM(progfuncs, atoi (assignment))) + if (!EDICT_NUM(progfuncs, atoi (str))) return "(invalid entity)"; - *(int *)val = EDICT_TO_PROG(progfuncs, EDICT_NUM(progfuncs, atoi (assignment))); + *(int *)val = EDICT_TO_PROG(progfuncs, EDICT_NUM(progfuncs, atoi (str))); break; case ev_field: - fdef = ED_FindField (progfuncs, assignment); + fdef = ED_FindField (progfuncs, str); if (!fdef) { - size_t l,nl = strlen(assignment); + size_t l,nl = strlen(str); + + *assignment = '='; + strcpy(buf, "Can't find field "); l = strlen(buf); if (nl > sizeof(buf)-l-2) nl = sizeof(buf)-l-2; - memcpy(buf+l, assignment, nl); - assignment[l+nl+0] = '\n'; - assignment[l+nl+1] = 0; + memcpy(buf+l, str, nl); + buf[l+nl+1] = 0; return buf; } *(int *)val = G_INT(fdef->ofs); @@ -878,32 +840,30 @@ char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *ppf, char *key) mfunction_t *func; int i; int progsnum = -1; - char *s = assignment; - if (s[0] && s[1] == ':') + if (str[0] && str[1] == ':') { - progsnum = atoi(s); - s+=2; + progsnum = atoi(str); + str+=2; } - else if (s[0] && s[1] && s[2] == ':') + else if (str[0] && str[1] && str[2] == ':') { - progsnum = atoi(s); - s+=3; + progsnum = atoi(str); + str+=3; } - func = ED_FindFunction (progfuncs, s, &i, progsnum); + func = ED_FindFunction (progfuncs, str, &i, progsnum); if (!func) { - size_t l,nl = strlen(s); + size_t l,nl = strlen(str); - assignment[-1] = '='; + *assignment = '='; strcpy(buf, "Can't find field "); l = strlen(buf); if (nl > sizeof(buf)-l-2) nl = sizeof(buf)-l-2; - memcpy(buf+l, assignment, nl); - assignment[l+nl+0] = '\n'; - assignment[l+nl+1] = 0; + memcpy(buf+l, str, nl); + buf[l+nl+1] = 0; return buf; } *(func_t *)val = (func - pr_progstate[i].functions) | (i<<24); @@ -914,7 +874,7 @@ char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *ppf, char *key) break; } - assignment[-1] = '='; + *assignment = '='; } QC_snprintfz(buf, sizeof(buf), "%s", PR_ValueString(progfuncs, type, val, true)); @@ -1046,6 +1006,8 @@ int PDECL PR_ToggleBreakpoint(pubprogfuncs_t *ppf, char *filename, int linenum, Sys_Error("Bad structtype"); op = 0; } + if (ret) //if its set, only set one breakpoint statement, not all of them. + return true; } goto cont; } @@ -1125,16 +1087,19 @@ cont: return ret; } -int ShowStep(progfuncs_t *progfuncs, int statement) +int ShowStep(progfuncs_t *progfuncs, int statement, char *fault) { // return statement; // texture realcursortex; static int lastline = 0; -static char *lastfile = 0; +static int ignorestatement = 0; // +static const char *lastfile = 0; int pn = pr_typecurrent; int i; const mfunction_t *f = pr_xfunction; + int faultline; + int debugaction; pr_xstatement = statement; if (!externs->useeditor) @@ -1145,50 +1110,183 @@ static char *lastfile = 0; if (f && externs->useeditor) { - if (pr_progstate[pn].linenums) + for(;;) //for DEBUG_TRACE_NORESUME handling { - if (lastline == pr_progstate[pn].linenums[statement] && lastfile == f->s_file+progfuncs->funcs.stringtable) - return statement; //no info/same line as last time - - lastline = pr_progstate[pn].linenums[statement]; - } - else - lastline = -1; - lastfile = f->s_file+progfuncs->funcs.stringtable; - - lastline = externs->useeditor(&progfuncs->funcs, lastfile, lastline, statement, 0, NULL); - if (!pr_progstate[pn].linenums) - return statement; - if (lastline <= 0) - return -lastline; - - if (pr_progstate[pn].linenums[statement] != lastline) - { - for (i = f->first_statement; ; i++) + if (pr_progstate[pn].linenums) { - if (lastline == pr_progstate[pn].linenums[i]) + if (lastline == pr_progstate[pn].linenums[statement] && lastfile == f->s_file+progfuncs->funcs.stringtable && statement == ignorestatement && !fault) { - return i; + ignorestatement++; + return statement; //no info/same line as last time } - else if (lastline <= pr_progstate[pn].linenums[i]) + + lastline = pr_progstate[pn].linenums[statement]; + } + else + lastline = -1; + lastfile = PR_StringToNative(&progfuncs->funcs, f->s_file); + + faultline = lastline; + debugaction = externs->useeditor(&progfuncs->funcs, lastfile, ((lastline>0)?&lastline:NULL), &statement, fault); + + //if they changed the line to execute, we need to find a statement that is on that line + if (lastline && faultline != lastline) + { + switch(pr_progstate[pn].structtype) { - return statement; + case PST_FTE32: + case PST_KKQWSV: + { + dstatement32_t *st = pr_progstate[pn].statements; + unsigned int *lnos = pr_progstate[pn].linenums; + for (i = f->first_statement; ; i++) + { + if (lastline == lnos[i]) + { + statement = i; + break; + } + else if (lastline <= lnos[i]) + break; + else if (st[i].op == OP_DONE) + break; + } + } + break; + case PST_DEFAULT: + case PST_QTEST: + { + dstatement16_t *st = pr_progstate[pn].statements; + unsigned int *lnos = pr_progstate[pn].linenums; + for (i = f->first_statement; ; i++) + { + if (lastline == lnos[i]) + { + statement = i; + break; + } + else if (lastline <= lnos[i]) + break; + else if (st[i].op == OP_DONE) + break; + } + } } } + + if (debugaction == DEBUG_TRACE_NORESUME) + continue; + else if(debugaction == DEBUG_TRACE_ABORT) + progfuncs->funcs.parms->Abort ("Debugging terminated"); + else if (debugaction == DEBUG_TRACE_OUT) + { + //clear tracing for now, but ensure that it'll be reactivated once we reach the caller (if from qc) + progfuncs->funcs.debug_trace = DEBUG_TRACE_OFF; + if (pr_depth) + pr_stack[pr_depth-1].stepping = DEBUG_TRACE_INTO; + } + else //some other debug action. maybe resume. + progfuncs->funcs.debug_trace = debugaction; + break; } } else if (f) //annoying. { if (*(f->s_file+progfuncs->funcs.stringtable)) //if we can't get the filename, then it was stripped, and debugging it like this is useless if (externs->useeditor) - externs->useeditor(&progfuncs->funcs, f->s_file+progfuncs->funcs.stringtable, -1, 0, 0, NULL); + externs->useeditor(&progfuncs->funcs, f->s_file+progfuncs->funcs.stringtable, NULL, NULL, fault); return statement; } - + ignorestatement = statement+1; return statement; } +int ShowStepf(progfuncs_t *progfuncs, int statement, char *fault, ...) +{ + va_list argptr; + char faultstring[1024]; + va_start (argptr,fault); + Q_vsnprintf (faultstring,sizeof(faultstring)-1, fault,argptr); + va_end (argptr); + return ShowStep(progfuncs, statement, faultstring); +} + + +//called by the qcvm when executing some statement that cannot be execed. +int PR_HandleFault (pubprogfuncs_t *ppf, char *error, ...) +{ + progfuncs_t *progfuncs = (progfuncs_t *)ppf; + va_list argptr; + char string[1024]; + int resumestatement; + + va_start (argptr,error); + Q_vsnprintf (string,sizeof(string)-1, error,argptr); + va_end (argptr); + + PR_StackTrace (ppf, true); + ppf->parms->Printf ("%s\n", string); + + resumestatement = ShowStep(progfuncs, pr_xstatement, string); + + if (resumestatement == 0) + { + PR_AbortStack(ppf); + return prinst.continuestatement; +// ppf->parms->Abort ("%s", string); + } + return resumestatement; +} + +/* +============ +PR_RunError + +Aborts the currently executing function +============ +*/ +void VARGS PR_RunError (pubprogfuncs_t *progfuncs, char *error, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,error); + Q_vsnprintf (string,sizeof(string)-1, error,argptr); + va_end (argptr); + +// PR_PrintStatement (pr_statements + pr_xstatement); + PR_StackTrace (progfuncs, true); + progfuncs->parms->Printf ("\n"); + +//editbadfile(pr_strings + pr_xfunction->s_file, -1); + + progfuncs->parms->Abort ("%s", string); +} + +pbool PR_RunWarning (pubprogfuncs_t *ppf, char *error, ...) +{ + progfuncs_t *progfuncs = (progfuncs_t *)ppf; + va_list argptr; + char string[1024]; + + va_start (argptr,error); + Q_vsnprintf (string,sizeof(string)-1, error,argptr); + va_end (argptr); + + progfuncs->funcs.parms->Printf ("%s", string); + if (pr_depth != 0) + PR_StackTrace (ppf, false); + + if (progfuncs->funcs.debug_trace == 0) + { + progfuncs->funcs.debug_trace = DEBUG_TRACE_INTO; + return true; + } + return false; +} + + static pbool casecmp_f(progfuncs_t *progfuncs, eval_t *ref, eval_t *val) {return ref->_float == val->_float;} static pbool casecmp_i(progfuncs_t *progfuncs, eval_t *ref, eval_t *val) {return ref->_int == val->_int;} static pbool casecmp_v(progfuncs_t *progfuncs, eval_t *ref, eval_t *val) {return ref->_vector[0] == val->_vector[0] && @@ -1249,6 +1347,7 @@ static int PR_ExecuteCode16 (progfuncs_t *fte_restrict progfuncs, int s, int *ft float *fte_restrict glob = pr_globals; float tmpf; int tmpi; + unsigned short op; eval_t *switchref = (eval_t*)glob; @@ -1258,7 +1357,7 @@ static int PR_ExecuteCode16 (progfuncs_t *fte_restrict progfuncs, int s, int *ft #define INTSIZE 16 st = &pr_statements16[s]; - while (progfuncs->funcs.pr_trace || prinst.watch_ptr || prinst.profiling) + while (progfuncs->funcs.debug_trace || prinst.watch_ptr || prinst.profiling) { #ifdef FTE_TARGET_WEB cont16: @@ -1308,13 +1407,15 @@ static int PR_ExecuteCode32 (progfuncs_t *fte_restrict progfuncs, int s, int *ft int tmpi; eval_t *switchref = (eval_t*)glob; + unsigned int op; + #define OPA ((eval_t *)&glob[st->a]) #define OPB ((eval_t *)&glob[st->b]) #define OPC ((eval_t *)&glob[st->c]) #define INTSIZE 32 st = &pr_statements32[s]; - while (progfuncs->funcs.pr_trace || prinst.watch_ptr || prinst.profiling) + while (progfuncs->funcs.debug_trace || prinst.watch_ptr || prinst.profiling) { #define DEBUGABLE #ifdef SEPARATEINCLUDES @@ -1458,22 +1559,16 @@ void PDECL PR_ExecuteProgram (pubprogfuncs_t *ppf, func_t fnum) (*externs->globalbuiltins[i]) (&progfuncs->funcs, (struct globalvars_s *)current_progstate->globals); else { - i -= externs->numglobalbuiltins; - if (i > current_progstate->numbuiltins) - { - printf ("Bad builtin call number %i (from exe)\n", -f->first_statement); - // PR_MoveParms(p, pr_typecurrent); - PR_SwitchProgs(progfuncs, initial_progs); - return; - } - current_progstate->builtins [i] (&progfuncs->funcs, (struct globalvars_s *)current_progstate->globals); + printf ("Bad builtin call number %i (from exe)\n", -f->first_statement); + // PR_MoveParms(p, pr_typecurrent); + PR_SwitchProgs(progfuncs, initial_progs); } PR_SwitchProgsParms(progfuncs, initial_progs); return; } - if (progfuncs->funcs.pr_trace) - progfuncs->funcs.pr_trace--; + //forget about any tracing if its active. control returning to the engine should not look like its calling some random function. + progfuncs->funcs.debug_trace = 0; // make a stack frame prinst.exitdepth = pr_depth; @@ -1697,3 +1792,27 @@ void PDECL PR_AbortStack (pubprogfuncs_t *ppf) prinst.continuestatement = 0; } +pbool PDECL PR_GetBuiltinCallInfo (pubprogfuncs_t *ppf, int *builtinnum, char *function, size_t sizeoffunction) +{ + progfuncs_t *progfuncs = (progfuncs_t*)ppf; + int st = pr_xstatement; + int op; + int a; + const char *fname; + op = pr_statements16[st].op; + a = pr_statements16[st].a; + + *builtinnum = 0; + *function = 0; + if ((op >= OP_CALL0 && op <= OP_CALL8) || (op >= OP_CALL1H && op <= OP_CALL8H)) + { + a = ((eval_t *)&pr_globals[a])->function; + + *builtinnum = -current_progstate->functions[a].first_statement; + fname = PR_StringToNative(ppf, current_progstate->functions[a].s_name); + strncpy(function, fname, sizeoffunction-1); + function[sizeoffunction-1] = 0; + return true; + } + return false; +} \ No newline at end of file diff --git a/engine/qclib/pr_multi.c b/engine/qclib/pr_multi.c index 4d7ab3cc8..e1c8ff925 100644 --- a/engine/qclib/pr_multi.c +++ b/engine/qclib/pr_multi.c @@ -4,7 +4,6 @@ //#define MAPPING_DEBUG //#define MAPPING_PARANOID //may actually break unions, so beware. -void PR_SetBuiltins(int type); /* progstate_t *pr_progstate; progsnum_t pr_typecurrent; @@ -94,7 +93,7 @@ pbool PR_SwitchProgsParms(progfuncs_t *progfuncs, progsnum_t newpr) //from 2 to return PR_SwitchProgs(progfuncs, newpr); } -progsnum_t PDECL PR_LoadProgs(pubprogfuncs_t *ppf, const char *s, builtin_t *builtins, int numbuiltins) +progsnum_t PDECL PR_LoadProgs(pubprogfuncs_t *ppf, const char *s) { progfuncs_t *progfuncs = (progfuncs_t*)ppf; unsigned int a; @@ -108,8 +107,6 @@ progsnum_t PDECL PR_LoadProgs(pubprogfuncs_t *ppf, const char *s, builtin_t *bui current_progstate = &pr_progstate[a]; if (PR_ReallyLoadProgs(progfuncs, s, &pr_progstate[a], false)) //try and load it { - current_progstate->builtins = builtins; - current_progstate->numbuiltins = numbuiltins; if (a <= progfuncs->funcs.numprogs) progfuncs->funcs.numprogs = a+1; diff --git a/engine/qclib/progsint.h b/engine/qclib/progsint.h index 947b08dac..e48ec47fe 100644 --- a/engine/qclib/progsint.h +++ b/engine/qclib/progsint.h @@ -60,9 +60,10 @@ typedef struct sharedvar_s } sharedvar_t; typedef struct { - int s; mfunction_t *f; - int progsnum; + unsigned char stepping; + unsigned char progsnum; + int s; int pushed; unsigned long long timestamp; } prstack_t; @@ -331,9 +332,6 @@ typedef struct progstate_s char filename[128]; - builtin_t *builtins; - int numbuiltins; - int *linenums; //debug versions only progstructtype_t structtype; @@ -375,7 +373,7 @@ void PR_Init (void); pbool PR_RunWarning (pubprogfuncs_t *progfuncs, char *error, ...); void PDECL PR_ExecuteProgram (pubprogfuncs_t *progfuncs, func_t fnum); -int PDECL PR_LoadProgs(pubprogfuncs_t *progfncs, const char *s, builtin_t *builtins, int numbuiltins); +int PDECL PR_LoadProgs(pubprogfuncs_t *progfncs, const char *s); int PR_ReallyLoadProgs (progfuncs_t *progfuncs, const char *filename, progstate_t *progstate, pbool complain); void *PRHunkAlloc(progfuncs_t *progfuncs, int ammount, char *name); @@ -527,13 +525,13 @@ pbool PDECL ED_ParseEval (pubprogfuncs_t *progfuncs, eval_t *eval, int type, con //pr_multi.c -void PR_SetBuiltins(int type); extern vec3_t vec3_origin; struct qcthread_s *PDECL PR_ForkStack (pubprogfuncs_t *progfuncs); void PDECL PR_ResumeThread (pubprogfuncs_t *progfuncs, struct qcthread_s *thread); void PDECL PR_AbortStack (pubprogfuncs_t *progfuncs); +pbool PDECL PR_GetBuiltinCallInfo (pubprogfuncs_t *ppf, int *builtinnum, char *function, size_t sizeoffunction); eval_t *PDECL PR_FindGlobal(pubprogfuncs_t *prfuncs, const char *globname, progsnum_t pnum, etype_t *type); ddef16_t *ED_FindTypeGlobalFromProgs16 (progfuncs_t *progfuncs, const char *name, progsnum_t prnum, int type); diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index e8439da1b..416d84134 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -53,6 +53,7 @@ typedef struct { } evalc_t; #define sizeofevalc sizeof(evalc_t) typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer, ev_integer, ev_variant, ev_struct, ev_union, ev_accessor} etype_t; +enum {DEBUG_TRACE_OFF, DEBUG_TRACE_INTO, DEBUG_TRACE_OVER, DEBUG_TRACE_UNBREAK, DEBUG_TRACE_OUT, DEBUG_TRACE_ABORT, DEBUG_TRACE_NORESUME}; typedef struct fdef_s { @@ -72,7 +73,7 @@ struct pubprogfuncs_s void (PDECL *CloseProgs) (pubprogfuncs_t *inst); void (PDECL *Configure) (pubprogfuncs_t *prinst, size_t addressablesize, int max_progs, pbool enableprofiling); //configure buffers and memory. Used to reset and must be called first. Flushes a running VM. - progsnum_t (PDECL *LoadProgs) (pubprogfuncs_t *prinst, const char *s, builtin_t *builtins, int numbuiltins); //load a progs + progsnum_t (PDECL *LoadProgs) (pubprogfuncs_t *prinst, const char *s); //load a progs int (PDECL *InitEnts) (pubprogfuncs_t *prinst, int max_ents); //returns size of edicts for use with nextedict macro void (PDECL *ExecuteProgram) (pubprogfuncs_t *prinst, func_t fnum); //start execution struct globalvars_s *(PDECL *globals) (pubprogfuncs_t *prinst, progsnum_t num); //get the globals of a progs @@ -116,7 +117,7 @@ struct pubprogfuncs_s char *(PDECL *EvaluateDebugString) (pubprogfuncs_t *prinst, char *key); //evaluate a string and return it's value (according to current progs) (expands edict vars) - int pr_trace; //start calling the editor for each line executed + int debug_trace; //start calling the editor for each line executed void (PDECL *StackTrace) (pubprogfuncs_t *prinst, int showlocals); @@ -140,7 +141,7 @@ struct pubprogfuncs_s void (PDECL *RunThread) (pubprogfuncs_t *prinst, struct qcthread_s *thread); void (PDECL *AbortStack) (pubprogfuncs_t *prinst); //annigilates the current stack, positioning on a return statement. It is expected that this is only used via a builtin! - int lastcalledbuiltinnumber; //useful with non-implemented opcodes. + pbool (PDECL *GetBuiltinCallInfo) (pubprogfuncs_t *prinst, int *builtinnum, char *function, size_t sizeoffunction); //call to query the qc's name+index for the builtin int (PDECL *RegisterFieldVar) (pubprogfuncs_t *prinst, unsigned int type, char *name, signed long requestedpos, signed long originalofs); @@ -195,14 +196,14 @@ typedef struct progexterns_s { //used when loading a game - builtin_t *(PDECL *builtinsfor) (int num, int headercrc); //must return a pointer to the builtins that were used before the state was saved. + int (PDECL *MapNamedBuiltin) (pubprogfuncs_t *prinst, int headercrc, const char *builtinname); //return 0 for not found. void (PDECL *loadcompleate) (int edictsize); //notification to reset any pointers. pbool (PDECL *badfield) (pubprogfuncs_t *prinst, struct edict_s *ent, const char *keyname, const char *value); //called for any fields that are not registered void *(VARGS *memalloc) (int size); //small string allocation malloced and freed randomly by the executor. (use malloc if you want) void (VARGS *memfree) (void * mem); - int (PDECL *useeditor) (pubprogfuncs_t *prinst, char *filename, int line, int statement, int nump, char **parms); //called on syntax errors or step-by-step debugging. + int (PDECL *useeditor) (pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, char *reason); //called on syntax errors or step-by-step debugging. line and statement(if line was set to 0) can be used to change the next line. return value is the new debug state to use/step. void (PDECL *addressablerelocated) (pubprogfuncs_t *progfuncs, char *oldb, char *newb, int oldlen); //called when the progs memory was resized. you must fix up all pointers to globals, strings, fields, addressable blocks. builtin_t *globalbuiltins; //these are available to all progs @@ -243,7 +244,7 @@ typedef union eval_s #ifndef DLL_PROG #define PR_Configure(pf, memsize, max_progs, profiling) (*pf->Configure) (pf, memsize, max_progs, profiling) -#define PR_LoadProgs(pf, s, builtins, numb) (*pf->LoadProgs) (pf, s, builtins, numb) +#define PR_LoadProgs(pf, s) (*pf->LoadProgs) (pf, s) #define PR_InitEnts(pf, maxents) (*pf->InitEnts) (pf, maxents) #define PR_ExecuteProgram(pf, fnum) (*pf->ExecuteProgram) (pf, fnum) #define PR_globals(pf, num) (*pf->globals) (pf, num) diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index 568fb4938..cd5a97f91 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -544,6 +544,7 @@ extern pbool flag_debugmacros; extern pbool flag_filetimes; extern pbool flag_typeexplicit; extern pbool flag_noboundchecks; +extern pbool flag_guiannotate; extern pbool opt_overlaptemps; extern pbool opt_shortenifnots; @@ -683,6 +684,7 @@ enum { WARN_EXTENSION_USED, //extension that frikqcc also understands WARN_IFSTRING_USED, WARN_LAXCAST, //some errors become this with a compiler flag + WARN_TYPEMISMATCHREDECOPTIONAL, WARN_UNDESIRABLECONVENTION, WARN_SAMENAMEASGLOBAL, WARN_CONSTANTCOMPARISON, diff --git a/engine/qclib/qcc_cmdlib.c b/engine/qclib/qcc_cmdlib.c index be20c6e29..380fffa75 100644 --- a/engine/qclib/qcc_cmdlib.c +++ b/engine/qclib/qcc_cmdlib.c @@ -123,6 +123,40 @@ void SetEndian(void) } +void QC_strlcat(char *dest, const char *src, size_t destsize) +{ + size_t curlen = strlen(dest); + if (!destsize) + return; //err + dest += curlen; + while(*src && ++curlen < destsize) + *dest++ = *src++; + if (*src) + printf("QC_strlcpy: truncation\n"); + *dest = 0; +} +void QC_strlcpy(char *dest, const char *src, size_t destsize) +{ + size_t curlen = strlen(dest); + if (!destsize) + return; //err + while(*src && ++curlen < destsize) + *dest++ = *src++; + if (*src) + printf("QC_strlcpy: truncation\n"); + *dest = 0; +} +void QC_strnlcpy(char *dest, const char *src, size_t srclen, size_t destsize) +{ + size_t curlen = strlen(dest); + if (!destsize) + return; //err + for(; *src && srclen > 0 && ++curlen < destsize; srclen--) + *dest++ = *src++; + if (srclen) + printf("QC_strlcpy: truncation\n"); + *dest = 0; +} #if !defined(MINIMAL) && !defined(OMIT_QCC) /* diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 1d44b6c14..eeffc47a3 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -85,6 +85,7 @@ pbool flag_assume_integer; //5 - is that an integer or a float? qcc says float. pbool flag_filetimes; pbool flag_typeexplicit; //no implicit type conversions, you must do the casts yourself. pbool flag_noboundchecks; //Disable generation of bound check instructions. +pbool flag_guiannotate; pbool opt_overlaptemps; //reduce numpr_globals by reuse of temps. When they are not needed they are freed for reuse. The way this is implemented is better than frikqcc's. (This is the single most important optimisation) pbool opt_assignments; //STORE_F isn't used if an operation wrote to a temp. @@ -293,7 +294,7 @@ QCC_opcode_t pr_opcodes[] = {6, "=", "STOREP_FLD", 6, ASSOC_RIGHT, &type_pointer, &type_field, &type_field}, {6, "=", "STOREP_FNC", 6, ASSOC_RIGHT, &type_pointer, &type_function, &type_function}, - {6, "", "RETURN", -1, ASSOC_LEFT, &type_float, &type_void, &type_void}, + {6, "", "RETURN", -1, ASSOC_LEFT, &type_vector, &type_void, &type_void}, {6, "!", "NOT_F", -1, ASSOC_LEFT, &type_float, &type_void, &type_float}, {6, "!", "NOT_V", -1, ASSOC_LEFT, &type_vector, &type_void, &type_float}, @@ -430,7 +431,7 @@ QCC_opcode_t pr_opcodes[] = {7, "/", "DIV_VF", 3, ASSOC_LEFT, &type_vector, &type_float, &type_float}, - {7, "^", "XOR_I", 3, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "^", "BITXOR_I", 3, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, {7, ">>", "RSHIFT_I", 3, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, {7, "<<", "LSHIFT_I", 3, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, @@ -585,8 +586,8 @@ QCC_opcode_t pr_opcodes[] = {7, "=", "LOADA_STRUCT", 6, ASSOC_LEFT, &type_float, &type_integer, &type_float}, {7, "=", "STOREP_P", 6, ASSOC_RIGHT, &type_pointer, &type_pointer, &type_pointer}, - {7, "~", "BINARYNOT_F", -1, ASSOC_LEFT, &type_float, &type_void, &type_float}, - {7, "~", "BINARYNOT_I", -1, ASSOC_LEFT, &type_integer, &type_void, &type_integer}, + {7, "~", "BITNOT_F", -1, ASSOC_LEFT, &type_float, &type_void, &type_float}, + {7, "~", "BITNOT_I", -1, ASSOC_LEFT, &type_integer, &type_void, &type_integer}, {7, "==", "EQ_P", 5, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, {7, "!=", "NE_P", 5, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, @@ -611,6 +612,10 @@ QCC_opcode_t pr_opcodes[] = {7, "%", "MOD_I", 6, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, {7, "%", "MOD_V", 6, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, + {7, "^", "BITXOR_F", 3, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {7, ">>", "RSHIFT_F", 3, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {7, "<<", "LSHIFT_F", 3, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {0, NULL} }; @@ -758,7 +763,8 @@ QCC_opcode_t *opcodes_orstore[] = }; QCC_opcode_t *opcodes_xorstore[] = { - &pr_opcodes[OP_XOR_I], + &pr_opcodes[OP_BITXOR_I], + &pr_opcodes[OP_BITXOR_F], NULL }; QCC_opcode_t *opcodes_andstore[] = @@ -858,9 +864,13 @@ QCC_opcode_t *opcodeprioritized[TOP_PRIORITY+1][128] = &pr_opcodes[OP_BITOR_IF], &pr_opcodes[OP_BITOR_FI], - &pr_opcodes[OP_XOR_I], + &pr_opcodes[OP_BITXOR_I], &pr_opcodes[OP_RSHIFT_I], &pr_opcodes[OP_LSHIFT_I], + + &pr_opcodes[OP_BITXOR_F], + &pr_opcodes[OP_RSHIFT_F], + &pr_opcodes[OP_LSHIFT_F], &pr_opcodes[OP_MOD_F], &pr_opcodes[OP_MOD_I], @@ -1255,7 +1265,7 @@ pbool QCC_OPCodeValid(QCC_opcode_t *op) case OP_LOADP_V: return true; - case OP_XOR_I: + case OP_BITXOR_I: case OP_RSHIFT_I: case OP_LSHIFT_I: return true; @@ -1615,7 +1625,7 @@ static void QCC_RemapLockedTemp(temp_t *t, int firststatement, int laststatement def = QCC_PR_DummyDef(type_float, NULL, pr_scope, t->size==1?0:t->size, newofs, false, 0); #ifdef WRITEASM - sprintf(buffer, "locked_%i", t->ofs); + sprintf(buffer, "locked_%i", t->ofs-FIRST_TEMP); def->name = qccHunkAlloc(strlen(buffer)+1); strcpy(def->name, buffer); #endif @@ -1633,7 +1643,7 @@ static void QCC_RemapLockedTemp(temp_t *t, int firststatement, int laststatement def = QCC_PR_DummyDef(type_float, NULL, pr_scope, t->size==1?0:t->size, newofs, false, 0); #ifdef WRITEASM - sprintf(buffer, "locked_%i", t->ofs); + sprintf(buffer, "locked_%i", t->ofs-FIRST_TEMP); def->name = qccHunkAlloc(strlen(buffer)+1); strcpy(def->name, buffer); #endif @@ -1703,9 +1713,9 @@ static const char *QCC_VarAtOffset(unsigned int ofs, unsigned int size) if (ofs >= t->ofs && ofs < t->ofs + t->size) { if (size < t->size) - sprintf(message, "temp_%i_%c", t->ofs, 'x' + (ofs-t->ofs)%3); + QC_snprintfz(message, sizeof(message), "temp_%i_%c", t->ofs - FIRST_TEMP, 'x' + (ofs-t->ofs)%3); else - sprintf(message, "temp_%i", t->ofs); + QC_snprintfz(message, sizeof(message), "temp_%i", t->ofs - FIRST_TEMP); return message; } } @@ -1723,12 +1733,12 @@ static const char *QCC_VarAtOffset(unsigned int ofs, unsigned int size) if (size < var->type->size) { if (var->type->type == ev_vector) - sprintf(message, "%s_%c", var->name, 'x' + (ofs-var->ofs)%3); + QC_snprintfz(message, sizeof(message), "%s_%c", var->name, 'x' + (ofs-var->ofs)%3); else - sprintf(message, "%s+%i", var->name, ofs-var->ofs); + QC_snprintfz(message, sizeof(message), "%s+%i", var->name, ofs-var->ofs); } else - sprintf(message, "%s", var->name); + QC_snprintfz(message, sizeof(message), "%s", var->name); return message; } } @@ -1747,23 +1757,60 @@ static const char *QCC_VarAtOffset(unsigned int ofs, unsigned int size) switch(var->type->type) { case ev_string: - sprintf(message, "\"%.1020s\"", &strings[((int *)qcc_pr_globals)[var->ofs]]); +dumpstring: + { + char *in = &strings[((int *)qcc_pr_globals)[var->ofs]], *out=message; + char *end = out+sizeof(message)-3; + *out++ = '\"'; + for(; out < end && *in; in++) + { + if (*in == '\n') + { + *out++ = '\\'; + *out++ = 'n'; + } + else if (*in == '\t') + { + *out++ = '\\'; + *out++ = 't'; + } + else if (*in == '\r') + { + *out++ = '\\'; + *out++ = 'r'; + } + else if (*in == '\"') + { + *out++ = '\\'; + *out++ = '"'; + } + else if (*in == '\'') + { + *out++ = '\\'; + *out++ = '\''; + } + else + *out++ = *in; + } + *out++ = '\"'; + *out++ = 0; + } return message; case ev_integer: - sprintf(message, "%ii", ((int *)qcc_pr_globals)[var->ofs]); + QC_snprintfz(message, sizeof(message), "%ii", ((int *)qcc_pr_globals)[var->ofs]); return message; case ev_float: - sprintf(message, "%gf", qcc_pr_globals[var->ofs]); + QC_snprintfz(message, sizeof(message), "%gf", qcc_pr_globals[var->ofs]); return message; case ev_vector: - sprintf(message, "'%g %g %g'", qcc_pr_globals[var->ofs], qcc_pr_globals[var->ofs+1], qcc_pr_globals[var->ofs+2]); + QC_snprintfz(message, sizeof(message), "'%g %g %g'", qcc_pr_globals[var->ofs], qcc_pr_globals[var->ofs+1], qcc_pr_globals[var->ofs+2]); return message; default: - sprintf(message, "IMMEDIATE"); + QC_snprintfz(message, sizeof(message), "IMMEDIATE"); return message; } } - sprintf(message, "%s", var->name); + QC_snprintfz(message, sizeof(message), "%s", var->name); return message; } } @@ -1783,31 +1830,30 @@ static const char *QCC_VarAtOffset(unsigned int ofs, unsigned int size) switch(var->type->type) { case ev_string: - sprintf(message, "\"%.1020s\"", &strings[((int *)qcc_pr_globals)[var->ofs]]); - return message; + goto dumpstring; case ev_integer: - sprintf(message, "%ii", ((int *)qcc_pr_globals)[var->ofs]); + QC_snprintfz(message, sizeof(message), "%ii", ((int *)qcc_pr_globals)[var->ofs]); return message; case ev_float: - sprintf(message, "%gf", qcc_pr_globals[var->ofs]); + QC_snprintfz(message, sizeof(message), "%gf", qcc_pr_globals[var->ofs]); return message; case ev_vector: - sprintf(message, "'%g %g %g'", qcc_pr_globals[var->ofs], qcc_pr_globals[var->ofs+1], qcc_pr_globals[var->ofs+2]); + QC_snprintfz(message, sizeof(message), "'%g %g %g'", qcc_pr_globals[var->ofs], qcc_pr_globals[var->ofs+1], qcc_pr_globals[var->ofs+2]); return message; default: - sprintf(message, "IMMEDIATE"); + QC_snprintfz(message, sizeof(message), "IMMEDIATE"); return message; } } if (size < var->type->size) { if (var->type->type == ev_vector) - sprintf(message, "%s_%c", var->name, 'x' + (ofs-var->ofs)%3); + QC_snprintfz(message, sizeof(message), "%s_%c", var->name, 'x' + (ofs-var->ofs)%3); else - sprintf(message, "%s+%i", var->name, ofs-var->ofs); + QC_snprintfz(message, sizeof(message), "%s+%i", var->name, ofs-var->ofs); } else - sprintf(message, "%s", var->name); + QC_snprintfz(message, sizeof(message), "%s", var->name); return message; } } @@ -1816,20 +1862,20 @@ static const char *QCC_VarAtOffset(unsigned int ofs, unsigned int size) if (size >= 3) { if (ofs >= OFS_RETURN && ofs < OFS_PARM0) - sprintf(message, "return"); + QC_snprintfz(message, sizeof(message), "return"); else if (ofs >= OFS_PARM0 && ofs < RESERVED_OFS) - sprintf(message, "parm%i", (ofs-OFS_PARM0)/3); + QC_snprintfz(message, sizeof(message), "parm%i", (ofs-OFS_PARM0)/3); else - sprintf(message, "offset_%i", ofs); + QC_snprintfz(message, sizeof(message), "offset_%i", ofs); } else { if (ofs >= OFS_RETURN && ofs < OFS_PARM0) - sprintf(message, "return_%c", 'x' + ofs-OFS_RETURN); + QC_snprintfz(message, sizeof(message), "return_%c", 'x' + ofs-OFS_RETURN); else if (ofs >= OFS_PARM0 && ofs < RESERVED_OFS) - sprintf(message, "parm%i_%c", (ofs-OFS_PARM0)/3, 'x' + (ofs-OFS_PARM0)%3); + QC_snprintfz(message, sizeof(message), "parm%i_%c", (ofs-OFS_PARM0)/3, 'x' + (ofs-OFS_PARM0)%3); else - sprintf(message, "offset_%i", ofs); + QC_snprintfz(message, sizeof(message), "offset_%i", ofs); } return message; } @@ -1894,6 +1940,15 @@ pbool QCC_Temp_Describe(QCC_def_t *def, char *buffer, int buffersize) return true; } +static int QCC_PR_RoundFloatConst(int ofs) +{ + float val = G_FLOAT(ofs); + int ival = val; + if (val != (float)ival) + QCC_PR_ParseWarning(WARN_CONSTANTCOMPARISON, "Constant float operand not an integer value"); + return ival; +} + QCC_statement_t *QCC_PR_SimpleStatement( int op, int var_a, int var_b, int var_c, int force); QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var_b, QCC_statement_t **outstatement, unsigned int flags) @@ -1960,7 +2015,7 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t return nd; } break; - case OP_XOR_I: + case OP_BITXOR_I: optres_constantarithmatic++; return QCC_MakeIntConst(G_INT(var_a->ofs) ^ G_INT(var_b->ofs)); case OP_RSHIFT_I: @@ -1969,12 +2024,21 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t case OP_LSHIFT_I: optres_constantarithmatic++; return QCC_MakeIntConst(G_INT(var_a->ofs) << G_INT(var_b->ofs)); + case OP_BITXOR_F: + optres_constantarithmatic++; + return QCC_MakeFloatConst(QCC_PR_RoundFloatConst(var_a->ofs) ^ QCC_PR_RoundFloatConst(var_b->ofs)); + case OP_RSHIFT_F: + optres_constantarithmatic++; + return QCC_MakeFloatConst(QCC_PR_RoundFloatConst(var_a->ofs) >> QCC_PR_RoundFloatConst(var_b->ofs)); + case OP_LSHIFT_F: + optres_constantarithmatic++; + return QCC_MakeFloatConst(QCC_PR_RoundFloatConst(var_a->ofs) << QCC_PR_RoundFloatConst(var_b->ofs)); case OP_BITOR_F: optres_constantarithmatic++; - return QCC_MakeFloatConst((float)((int)G_FLOAT(var_a->ofs) | (int)G_FLOAT(var_b->ofs))); + return QCC_MakeFloatConst(QCC_PR_RoundFloatConst(var_a->ofs) | QCC_PR_RoundFloatConst(var_b->ofs)); case OP_BITAND_F: optres_constantarithmatic++; - return QCC_MakeFloatConst((float)((int)G_FLOAT(var_a->ofs) & (int)G_FLOAT(var_b->ofs))); + return QCC_MakeFloatConst(QCC_PR_RoundFloatConst(var_a->ofs) & QCC_PR_RoundFloatConst(var_b->ofs)); case OP_MUL_F: optres_constantarithmatic++; return QCC_MakeFloatConst(G_FLOAT(var_a->ofs) * G_FLOAT(var_b->ofs)); @@ -2047,12 +2111,18 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t optres_constantarithmatic++; return QCC_MakeFloatConst(G_FLOAT(var_a->ofs) - G_INT(var_b->ofs)); - case OP_AND_F: + case OP_AND_I: optres_constantarithmatic++; return QCC_MakeIntConst(G_INT(var_a->ofs) && G_INT(var_b->ofs)); - case OP_OR_F: + case OP_OR_I: optres_constantarithmatic++; return QCC_MakeIntConst(G_INT(var_a->ofs) || G_INT(var_b->ofs)); + case OP_AND_F: + optres_constantarithmatic++; + return QCC_MakeIntConst(G_FLOAT(var_a->ofs) && G_FLOAT(var_b->ofs)); + case OP_OR_F: + optres_constantarithmatic++; + return QCC_MakeIntConst(G_FLOAT(var_a->ofs) || G_FLOAT(var_b->ofs)); case OP_MUL_V: //mul_f is actually a dot-product optres_constantarithmatic++; return QCC_MakeFloatConst( G_FLOAT(var_a->ofs) * G_FLOAT(var_b->ofs+0) + @@ -2099,6 +2169,10 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t case OP_NOT_I: optres_constantarithmatic++; return QCC_MakeIntConst(!G_INT(var_a->ofs)); + case OP_BITNOT_F: + return QCC_MakeFloatConst(~QCC_PR_RoundFloatConst(var_a->ofs)); + case OP_BITNOT_I: + return QCC_MakeIntConst(~G_INT(var_a->ofs)); case OP_CONV_FTOI: optres_constantarithmatic++; return QCC_MakeIntConst(G_FLOAT(var_a->ofs)); @@ -2125,7 +2199,7 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t break; case OP_BITAND_F: case OP_AND_F: - if (G_FLOAT(var_a->ofs) != 0) + if (QCC_PR_RoundFloatConst(var_a->ofs) != 0) { optres_constantarithmatic++; QCC_UnFreeTemp(var_b); @@ -2727,6 +2801,15 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t op = pr_opcodes+OP_STORE_F; break; + case OP_BITXOR_F: + numstatements--; +// a = (a & ~b) | (b & ~a); + var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITNOT_F], var_b, NULL, NULL, STFL_PRESERVEA); + var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_F], var_a, var_c, NULL, STFL_PRESERVEA); + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_BITNOT_F], var_a, NULL, NULL, 0); + var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_BITAND_F], var_b, var_a, NULL, 0); + return QCC_PR_StatementFlags(&pr_opcodes[OP_BITOR_F], var_c, var_a, NULL, STFL_PRESERVEA); + case OP_IF_S: var_c = QCC_PR_GetDef(type_string, "string_null", NULL, true, 0, false); numstatements--; @@ -2823,12 +2906,12 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t var_a = var_c; break; - case OP_BINARYNOT_I: + case OP_BITNOT_I: op = &pr_opcodes[OP_SUB_I]; var_b = var_a; var_a = QCC_MakeIntConst(~0); break; - case OP_BINARYNOT_F: + case OP_BITNOT_F: op = &pr_opcodes[OP_SUB_F]; var_b = var_a; var_a = QCC_MakeFloatConst(-1); //divVerent says -1 is safe, even with floats. I guess I'm just too paranoid. @@ -5538,18 +5621,21 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, QCC_type_t *basetype) if (numfunctions >= MAX_FUNCTIONS) QCC_Error(ERR_INTERNAL, "Too many function defs"); + if (!strcmp(basetype->name, "mitem_desktop")) + pr_scope = NULL; + pr_scope = NULL; memset(basictypefield, 0, sizeof(basictypefield)); // QCC_PR_EmitFieldsForMembers(basetype, basictypefield); - pr_source_line = 0; + pr_source_line = pr_token_line_last = scope->s_line; pr_scope = scope; df = &functions[numfunctions]; numfunctions++; - df->s_file = 0; + df->s_file = scope->s_file; df->s_name = QCC_CopyString(scope->name); df->first_statement = numstatements; df->parm_size[0] = 1; @@ -6412,9 +6498,9 @@ QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags) e = QCC_PR_Expression (NOT_PRIORITY, EXPR_DISALLOW_COMMA|EXPR_WARN_ABOVE_1); t = e->type->type; if (t == ev_float) - e2 = QCC_PR_Statement (&pr_opcodes[OP_BINARYNOT_F], e, 0, NULL); + e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_F], e, 0, NULL); else if (t == ev_integer) - e2 = QCC_PR_Statement (&pr_opcodes[OP_BINARYNOT_I], e, 0, NULL); //functions are integer values too. + e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_I], e, 0, NULL); //functions are integer values too. else { e2 = NULL; // shut up compiler warning; @@ -6988,6 +7074,27 @@ QCC_def_t *QCC_LoadFromArray(QCC_def_t *base, QCC_def_t *index, QCC_type_t *t, p base->references++; + if (base->type->type == ev_field && base->constant && !base->initialized && flag_noboundchecks && flag_fasttrackarrays) + { + int i; + //denormalised floats means we could do: + //return (add_f: base + (mul_f: index*1i)) + //make sure the array has no gaps + //the initialised thing is to ensure that it doesn't contain random consecutive system fields that might get remapped weirdly by an engine. + for (i = 1; i < base->arraysize; i++) + { + if (G_INT(base->ofs+i) != G_INT(base->ofs+i-1)+1) + break; + } + //its contiguous. we'll do this in two instructions. + if (i == base->arraysize) + { + //denormalised floats means we could do: + //return (add_f: base + (mul_f: index*1i)) + return QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_F], base, QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_F], index, QCC_MakeIntConst(1), NULL, 0), NULL, 0); + } + } + funcretr = QCC_PR_GetDef(NULL, qcva("ArrayGet*%s", base->name), base->scope, false, 0, GDF_CONST|(base->scope?GDF_STATIC:0)); if (!funcretr) { @@ -9828,6 +9935,77 @@ void QCC_Marshal_Locals(int firststatement, int laststatement) } #ifdef WRITEASM +void QCC_WriteGUIAsmFunction(QCC_def_t *sc, unsigned int firststatement) +{ + unsigned int i; +// QCC_type_t *type; + char typebuf[512]; + + char line[2048]; + extern int currentsourcefile; + +// type = sc->type; + + for (i = firststatement; i < (unsigned int)numstatements; i++) + { + line[0] = 0; + QC_strlcat(line, pr_opcodes[statements[i].op].opname, sizeof(line)); + + if (pr_opcodes[statements[i].op].type_a != &type_void) + { +// if (strlen(pr_opcodes[statements[i].op].opname)<6) +// QC_strlcat(line, " ", sizeof(line)); + if (pr_opcodes[statements[i].op].type_a) + QC_snprintfz(typebuf, sizeof(typebuf), " %s/*%i*/", QCC_VarAtOffset(statements[i].a, (*pr_opcodes[statements[i].op].type_a)->size), statements[i].a); + else + QC_snprintfz(typebuf, sizeof(typebuf), " %i", statements[i].a); + QC_strlcat(line, typebuf, sizeof(line)); + if (pr_opcodes[statements[i].op].type_b != &type_void) + { + if (pr_opcodes[statements[i].op].type_b) + QC_snprintfz(typebuf, sizeof(typebuf), ", %s/*%i*/", QCC_VarAtOffset(statements[i].b, (*pr_opcodes[statements[i].op].type_b)->size), statements[i].b); + else + QC_snprintfz(typebuf, sizeof(typebuf), ", %i", statements[i].b); + QC_strlcat(line, typebuf, sizeof(line)); + if (pr_opcodes[statements[i].op].type_c != &type_void && (pr_opcodes[statements[i].op].associative==ASSOC_LEFT || statements[i].c)) + { + if (pr_opcodes[statements[i].op].type_c) + QC_snprintfz(typebuf, sizeof(typebuf), ", %s/*%i*/", QCC_VarAtOffset(statements[i].c, (*pr_opcodes[statements[i].op].type_c)->size), statements[i].c); + else + QC_snprintfz(typebuf, sizeof(typebuf), ", %i", statements[i].c); + QC_strlcat(line, typebuf, sizeof(line)); + } + } + else + { + if (pr_opcodes[statements[i].op].type_c != &type_void) + { + if (pr_opcodes[statements[i].op].type_c) + QC_snprintfz(typebuf, sizeof(typebuf), ", %s/*%i*/", QCC_VarAtOffset(statements[i].c, (*pr_opcodes[statements[i].op].type_c)->size), statements[i].c); + else + QC_snprintfz(typebuf, sizeof(typebuf), ", %i", statements[i].c); + QC_strlcat(line, typebuf, sizeof(line)); + } + } + } + else + { + if (pr_opcodes[statements[i].op].type_c != &type_void) + { + if (pr_opcodes[statements[i].op].type_c) + QC_snprintfz(typebuf, sizeof(typebuf), " %s/*%i*/", QCC_VarAtOffset(statements[i].c, (*pr_opcodes[statements[i].op].type_c)->size), statements[i].c); + else + QC_snprintfz(typebuf, sizeof(typebuf), " %i", statements[i].c); + QC_strlcat(line, typebuf, sizeof(line)); + } + } + if (currentsourcefile) + printf("code: %s:%i: %i:%s;\n", strings+sc->s_file, statements[i].linenum, currentsourcefile, line); + else + printf("code: %s:%i: %s;\n", strings+sc->s_file, statements[i].linenum, line); + } +} + void QCC_WriteAsmFunction(QCC_def_t *sc, unsigned int firststatement, gofs_t firstparm) { unsigned int i; @@ -9836,6 +10014,9 @@ void QCC_WriteAsmFunction(QCC_def_t *sc, unsigned int firststatement, gofs_t fir QCC_def_t *param; char typebuf[512]; + if (flag_guiannotate) + QCC_WriteGUIAsmFunction(sc, firststatement); + if (!asmfile) return; @@ -9966,6 +10147,8 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type) binum = pr_immediate._int; else QCC_PR_ParseError (ERR_BADBUILTINIMMEDIATE, "Bad builtin immediate"); + if (!binum) + printf("omg!\n"); f->builtin = binum; QCC_PR_Lex (); @@ -10317,6 +10500,7 @@ QCC_def_t *QCC_PR_EmitArrayGetVector(QCC_def_t *array) s_file = array->s_file; func = QCC_PR_GetDef(ftype, qcva("ArrayGetVec*%s", array->name), NULL, true, 0, false); + pr_source_line = pr_token_line_last = array->s_line; //thankfully these functions are emitted after compilation. pr_scope = func; if (numfunctions >= MAX_FUNCTIONS) @@ -10339,7 +10523,7 @@ QCC_def_t *QCC_PR_EmitArrayGetVector(QCC_def_t *array) QCC_PR_ArrayRecurseDivideUsingVectors(array, temp, 0, numslots); - QCC_PR_Statement(pr_opcodes+OP_RETURN, QCC_MakeFloatConst(0), 0, NULL); //err... we didn't find it, give up. + QCC_PR_Statement(pr_opcodes+OP_RETURN, QCC_MakeVectorConst(0,0,0), 0, NULL); //err... we didn't find it, give up. QCC_PR_Statement(pr_opcodes+OP_DONE, 0, 0, NULL); //err... we didn't find it, give up. G_FUNCTION(func->ofs) = df - functions; @@ -10361,6 +10545,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *ar QCC_statement_t *st; QCC_def_t *eq; + QCC_statement_t *bc1=NULL, *bc2=NULL; QCC_def_t *fasttrackpossible; int numslots; @@ -10390,7 +10575,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *ar df = &functions[numfunctions]; numfunctions++; - pr_source_line = thearray->s_line; //thankfully these functions are emitted after compilation. + pr_source_line = pr_token_line_last = thearray->s_line; //thankfully these functions are emitted after compilation. df->s_file = thearray->s_file; df->s_name = QCC_CopyString(scope->name); df->first_statement = numstatements; @@ -10418,6 +10603,9 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *ar st->b = &statements[numstatements] - st; } + if (!flag_noboundchecks) + QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_IF_I, QCC_PR_Statement(pr_opcodes+OP_LT_F, index, QCC_MakeFloatConst(0), NULL), 0, &bc1)); + if (vectortrick) { QCC_def_t *div3, *intdiv3, *ret; @@ -10426,6 +10614,9 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *ar //we need to work out which part, x/y/z that it's stored in. //0,1,2 = i - ((int)i/3 *) 3; + if (!flag_noboundchecks) + QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_IF_I, QCC_PR_Statement(pr_opcodes+OP_GE_F, index, QCC_MakeFloatConst(numslots), NULL), 0, &bc2)); + div3 = QCC_PR_GetDef(type_float, "div3___", thearray, true, 0, false); intdiv3 = QCC_PR_GetDef(type_float, "intdiv3___", thearray, true, 0, false); @@ -10478,8 +10669,19 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *ar QCC_PR_ArrayRecurseDivideRegular(thearray, index, 0, numslots); } - QCC_PR_Statement(pr_opcodes+OP_RETURN, QCC_MakeFloatConst(0), 0, NULL); - + if (bc1) + bc1->b = &statements[numstatements] - bc1; + if (bc2) + bc2->b = &statements[numstatements] - bc2; + if (1) + { + QCC_def_t *errfnc = QCC_PR_GetDef(NULL, "error", NULL, false, 0, false); + QCC_def_t *errmsg = QCC_MakeStringConst("bounds check failed\n"); + QCC_FreeTemp(QCC_PR_GenerateFunctionCall(NULL, errfnc, &errmsg, &type_string, 1)); + } + //we get here if they tried reading beyond the end of the array with bounds checks disabled. just return the last valid element. + QCC_PR_Statement(pr_opcodes+OP_RETURN, 0, 0, &st); + st->a = thearray->ofs + (numslots-1) * thearray->type->size; QCC_PR_Statement(pr_opcodes+OP_DONE, 0, 0, NULL); df->parm_start = locals_start; @@ -10541,6 +10743,7 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *ar QCC_def_t *fasttrackpossible; int numslots; + QCC_statement_t *bc1=NULL, *bc2=NULL; if (thearray->type->type == ev_vector) numslots = thearray->arraysize; @@ -10561,7 +10764,7 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *ar df = &functions[numfunctions]; numfunctions++; - pr_source_line = thearray->s_line; //thankfully these functions are emitted after compilation. + pr_source_line = pr_token_line_last = thearray->s_line; //thankfully these functions are emitted after compilation. df->s_file = thearray->s_file; df->s_name = QCC_CopyString(scope->name); df->first_statement = numstatements; @@ -10582,7 +10785,8 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *ar //note that the array size is coded into the globals, one index before the array. QCC_PR_Statement3(&pr_opcodes[OP_CONV_FTOI], index, NULL, index, true); //address stuff is integer based, but standard qc (which this accelerates in supported engines) only supports floats - QCC_PR_SimpleStatement (OP_BOUNDCHECK, index->ofs, ((int*)qcc_pr_globals)[thearray->ofs-1]+1, 0, true);//annoy the programmer. :p + if (!flag_noboundchecks) + QCC_PR_SimpleStatement (OP_BOUNDCHECK, index->ofs, ((int*)qcc_pr_globals)[thearray->ofs-1]+1, 0, true);//annoy the programmer. :p if (thearray->type->type == ev_vector)//shift it upwards for larger types QCC_PR_Statement3(&pr_opcodes[OP_MUL_I], index, QCC_MakeIntConst(thearray->type->size), index, true); QCC_PR_Statement3(&pr_opcodes[OP_GLOBALADDRESS], thearray, index, index, true); //comes with built in add @@ -10597,8 +10801,24 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *ar } QCC_PR_Statement3(pr_opcodes+OP_BITAND_F, index, index, index, false); + if (!flag_noboundchecks) + QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_IF_I, QCC_PR_Statement(pr_opcodes+OP_LT_F, index, QCC_MakeFloatConst(0), NULL), 0, &bc1)); + if (!flag_noboundchecks) + QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_IF_I, QCC_PR_Statement(pr_opcodes+OP_GT_F, index, QCC_MakeFloatConst(numslots-1), NULL), 0, &bc2)); + QCC_PR_ArraySetRecurseDivide(thearray, index, value, 0, numslots); + if (bc1) + bc1->b = &statements[numstatements] - bc1; + if (bc2) + bc2->b = &statements[numstatements] - bc2; + if (bc1 || bc2) + { + QCC_def_t *errfnc = QCC_PR_GetDef(NULL, "error", NULL, false, 0, false); + QCC_def_t *errmsg = QCC_MakeStringConst("bounds check failed\n"); + QCC_FreeTemp(QCC_PR_GenerateFunctionCall(NULL, errfnc, &errmsg, &type_string, 1)); + } + QCC_PR_Statement(pr_opcodes+OP_DONE, 0, 0, NULL); @@ -10887,7 +11107,7 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool //this is a hack. droptofloor was wrongly declared in vanilla qc, which causes problems with replacement extensions.qc. //yes, this is a selfish lazy hack for this, there's probably a better way, but at least we spit out a warning still. QCC_PR_ParseWarning (WARN_LAXCAST, "%s builtin was wrongly defined as %s. ignoring invalid dupe definition",name, TypeName(type, typebuf1, sizeof(typebuf1))); - QCC_PR_ParsePrintDef(WARN_DUPLICATEDEFINITION, def); + QCC_PR_ParsePrintDef(WARN_LAXCAST, def); } else { @@ -10901,8 +11121,8 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool { //if the second def simply has no ..., don't bother warning about it. - QCC_PR_ParseWarning (WARN_LAXCAST, "Optional arguments differ on redeclaration of %s. %s, should be %s",name, TypeName(type, typebuf1, sizeof(typebuf1)), TypeName(def->type, typebuf2, sizeof(typebuf2))); - QCC_PR_ParsePrintDef(WARN_DUPLICATEDEFINITION, def); + QCC_PR_ParseWarning (WARN_TYPEMISMATCHREDECOPTIONAL, "Optional arguments differ on redeclaration of %s. %s, should be %s",name, TypeName(type, typebuf1, sizeof(typebuf1)), TypeName(def->type, typebuf2, sizeof(typebuf2))); + QCC_PR_ParsePrintDef(WARN_TYPEMISMATCHREDECOPTIONAL, def); if (type->type == ev_function) { @@ -11158,8 +11378,10 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type QCC_def_t *parentfunc = pr_scope; QCC_function_t *f; QCC_dfunction_t *df; + char fname[256]; tmp = NULL; + *fname = 0; def->references++; pr_scope = def; @@ -11172,17 +11394,41 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type binum = (int)pr_immediate._float; else if (pr_token_type == tt_immediate && pr_immediate_type == type_integer) binum = pr_immediate._int; - else + else if (pr_token_type == tt_immediate && pr_immediate_type == type_string) + strncpy(fname, pr_immediate_string, sizeof(fname)); + else if (pr_token_type == tt_name) + strncpy(fname, pr_token, sizeof(fname)); + else QCC_PR_ParseError (ERR_BADBUILTINIMMEDIATE, "Bad builtin immediate"); QCC_PR_Lex(); + if (!*fname && QCC_PR_CheckToken (":")) + strncpy(fname, QCC_PR_ParseName(), sizeof(fname)); + + //if the builtin already exists, just use that dfunction instead if (def->initialized) - for (i = 0; i < numfunctions; i++) { - if (functions[i].first_statement == -binum) + if (*fname) { - tmp = QCC_MakeIntConst(i); - break; + for (i = 1; i < numfunctions; i++) + { + if (!strcmp(strings+functions[i].s_name, fname) && functions[i].first_statement == -binum) + { + tmp = QCC_MakeIntConst(i); + break; + } + } + } + else + { + for (i = 1; i < numfunctions; i++) + { + if (!strcmp(strings+functions[i].s_name, def->name) && functions[i].first_statement == -binum) + { + tmp = QCC_MakeIntConst(i); + break; + } + } } } @@ -11222,6 +11468,19 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type QCC_PR_ParseErrorPrintDef (ERR_REDECLARATION, def, "redeclaration of function body"); } f = QCC_PR_ParseImmediateStatements (type); + + //allow dupes if its a builtin + if (!f->code && def->initialized) + { + for (i = 1; i < numfunctions; i++) + { + if (functions[i].first_statement == -f->builtin) + { + tmp = QCC_MakeIntConst(i); + break; + } + } + } } if (!tmp) { @@ -11240,7 +11499,9 @@ void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *def, QCC_type_t *type else df->first_statement = f->code; - if (f->builtin && opt_function_names) + if (*fname) + df->s_name = QCC_CopyString (fname); + else if (f->builtin && opt_function_names && df->first_statement) optres_function_names += strlen(f->def->name); else df->s_name = QCC_CopyString (f->def->name); @@ -12269,9 +12530,10 @@ void QCC_PR_ParseDefs (char *classname) else def->constant = 1; - if (def->constant) + if (!def->initialized && def->constant) { unsigned int i; + def->initialized = true; //if the field already has a value, don't allocate new field space for it as that would confuse things. //otherwise allocate new space. if (*(int *)&qcc_pr_globals[def->ofs]) diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index aa049a86e..3200935b6 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -701,7 +701,7 @@ pbool QCC_PR_Precompiler(void) if (strlen(msg) >= sizeof(QCC_copyright)) QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n"); - strncpy(QCC_copyright, msg, sizeof(QCC_copyright)-1); + QC_strlcpy(QCC_copyright, msg, sizeof(QCC_copyright)-1); } else if (!strncmp(directive, "pack", 4)) { @@ -927,7 +927,7 @@ pbool QCC_PR_Precompiler(void) { if (strlen(msg) >= sizeof(QCC_copyright)) QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n"); - strncpy(QCC_copyright, msg, sizeof(QCC_copyright)-1); + QC_strlcpy(QCC_copyright, msg, sizeof(QCC_copyright)-1); } else if (!QC_strcasecmp(qcc_token, "compress")) { @@ -1109,7 +1109,7 @@ pbool QCC_PR_Precompiler(void) p--; } } - sprintf(destfile, "%s", s2); + QC_snprintfz(destfile, sizeof(destfile), "%s", s2); while (p>0) { @@ -2145,7 +2145,7 @@ void QCC_PR_ExpandMacro(void) if (i < 0) QCC_PR_ParseError (ERR_BADFRAMEMACRO, "Unknown frame macro $%s", pr_token); - sprintf (pr_token,"%d", i); + QC_snprintfz(pr_token, sizeof(pr_token),"%d", i); pr_token_type = tt_immediate; pr_immediate_type = type_float; pr_immediate._float = (float)i; @@ -2335,8 +2335,7 @@ void QCC_PR_LexGrab (void) if (*pr_framemodelname) QCC_PR_MacroFrame(pr_framemodelname, pr_macrovalue); - strncpy(pr_framemodelname, pr_token, sizeof(pr_framemodelname)-1); - pr_framemodelname[sizeof(pr_framemodelname)-1] = '\0'; + QC_strlcpy(pr_framemodelname, pr_token, sizeof(pr_framemodelname)); i = QCC_PR_FindMacro(pr_framemodelname); if (i) @@ -2769,8 +2768,7 @@ int QCC_PR_CheckCompConst(void) || *end == '#') break; } - strncpy(pr_token, pr_file_p, end-pr_file_p); - pr_token[end-pr_file_p]='\0'; + QC_strnlcpy(pr_token, pr_file_p, end-pr_file_p, sizeof(pr_token)); // printf("%s\n", pr_token); c = pHash_Get(&compconstantstable, pr_token); @@ -3166,7 +3164,7 @@ void QCC_PR_Lex (void) return; } - if (c == '#' && !(pr_file_p[1]=='-' || (pr_file_p[1]>='0' && pr_file_p[1] <='9'))) //hash and not number + if (c == '#' && !(pr_file_p[1]=='\"' || pr_file_p[1]=='-' || (pr_file_p[1]>='0' && pr_file_p[1] <='9'))) //hash and not number { pr_file_p++; if (!QCC_PR_CheckCompConst()) @@ -4692,7 +4690,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) QCC_Error(ERR_INTERNAL, "Nested function declaration"); isnull = (QCC_PR_CheckImmediate("0") || QCC_PR_CheckImmediate("0i")); - sprintf(membername, "%s::%s", classname, parmname); + QC_snprintfz(membername, sizeof(membername), "%s::%s", classname, parmname); if (isnull) { def = QCC_PR_GetDef(newparm, membername, NULL, true, 0, 0); @@ -4800,7 +4798,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) //static members are technically just funny-named globals, and do not generate fields. if (isnonvirt || isstatic || (newparm->type == ev_function && !arraysize)) { - sprintf(membername, "%s::%s", classname, parmname); + QC_snprintfz(membername, sizeof(membername), "%s::%s", classname, parmname); QCC_PR_GetDef(newparm, membername, NULL, true, 0, GDF_CONST); if (isnonvirt || isstatic) @@ -4872,7 +4870,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) d = QCC_PR_GetDef(NULL, parmname, NULL, 0, 0, GDF_CONST); if (!d) { //don't go all weird with unioning generic fields - sprintf(membername, "::%s%i", basictypenames[newparm->type], basicindex+1); + QC_snprintfz(membername, sizeof(membername), "::%s%i", basictypenames[newparm->type], basicindex+1); d = QCC_PR_GetDef(NULL, membername, NULL, 0, 0, GDF_CONST); if (!d) { @@ -4887,7 +4885,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) //and make sure we can do member::__fname //actually, that seems pointless. - sprintf(membername, "%s::"MEMBERFIELDNAME, classname, parmname); + QC_snprintfz(membername, sizeof(membername), "%s::"MEMBERFIELDNAME, classname, parmname); // printf("define %s -> %s\n", membername, d->name); d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, 0, d->ofs, true, (isnull?0:GDF_CONST)|(opt_classfields?GDF_STRIP:0)); d->references++; //always referenced, so you can inherit safely. @@ -4920,7 +4918,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) { QCC_def_t *d; //if there's a constructor, make sure the spawnfunc_ function is defined so that its available to maps. - sprintf(membername, "spawnfunc_%s", classname); + QC_snprintfz(membername, sizeof(membername), "spawnfunc_%s", classname); d = QCC_PR_GetDef(type_function, membername, NULL, true, 0, GDF_CONST); d->timescalled++; d->references++; diff --git a/engine/qclib/qccgui.c b/engine/qclib/qccgui.c index 24b47da3f..9ecf8985b 100644 --- a/engine/qclib/qccgui.c +++ b/engine/qclib/qccgui.c @@ -72,6 +72,9 @@ void GUI_RevealOptions(void); #define SCI_CALLTIPCANCEL 2201 #define SCI_SETMARGINSENSITIVEN 2246 #define SCI_SETMOUSEDWELLTIME 2264 +#define SCI_CHARLEFT 2304 +#define SCI_CHARRIGHT 2306 +#define SCI_BACKTAB 2328 #define SCI_SEARCHANCHOR 2366 #define SCI_SEARCHNEXT 2367 #define SCI_BRACEHIGHLIGHTINDICATOR 2498 @@ -80,6 +83,22 @@ void GUI_RevealOptions(void); #define SCI_BRACEHIGHLIGHT 2351 #define SCI_BRACEBADLIGHT 2352 #define SCI_BRACEMATCH 2353 +#define SCI_ANNOTATIONSETTEXT 2540 +#define SCI_ANNOTATIONGETTEXT 2541 +#define SCI_ANNOTATIONSETSTYLE 2542 +#define SCI_ANNOTATIONGETSTYLE 2543 +#define SCI_ANNOTATIONSETSTYLES 2544 +#define SCI_ANNOTATIONGETSTYLES 2545 +#define SCI_ANNOTATIONGETLINES 2546 +#define SCI_ANNOTATIONCLEARALL 2547 +#define ANNOTATION_HIDDEN 0 +#define ANNOTATION_STANDARD 1 +#define ANNOTATION_BOXED 2 +#define ANNOTATION_INDENTED 3 +#define SCI_ANNOTATIONSETVISIBLE 2548 +#define SCI_ANNOTATIONGETVISIBLE 2549 +#define SCI_ANNOTATIONSETSTYLEOFFSET 2550 +#define SCI_ANNOTATIONGETSTYLEOFFSET 2551 #define SCI_AUTOCSETORDER 2660 #define SCI_SETLEXER 4001 #define SCI_SETPROPERTY 4004 @@ -473,6 +492,8 @@ char greptext[256]; extern char enginebinary[MAX_PATH]; extern char enginebasedir[MAX_PATH]; extern char enginecommandline[8192]; +extern QCC_def_t *sourcefilesdefs[]; +extern int sourcefilesnumdefs; void RunCompiler(char *args, pbool quick); void RunEngine(void); @@ -546,6 +567,8 @@ static void FindNextScintilla(editor_t *editor, char *findtext) MessageBox(editor->editpane, "No more occurences found", "FTE Editor", 0); } } +char *WordUnderCursor(editor_t *editor, char *word, int wordsize, char *term, int termsize, int position); +pbool GenAutoCompleteList(char *prefix, char *buffer, int buffersize); //available in xp+ typedef LRESULT (CALLBACK *SUBCLASSPROC)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); @@ -553,75 +576,67 @@ BOOL (WINAPI * pSetWindowSubclass)(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR LRESULT (WINAPI *pDefSubclassProc)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK MySubclassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { - if (uMsg == WM_KEYDOWN) + editor_t *editor; + if (uMsg == WM_CHAR || uMsg == WM_UNICHAR) { - if (wParam == VK_F3) + switch(wParam) { - char buffer[128]; - GetWindowText(search_name, buffer, sizeof(buffer)); - if (*buffer == 0) - SetFocus(search_name); - else + case VK_SPACE: { - editor_t *editor; - for (editor = editors; editor; editor = editor->next) + BYTE keystate[256]; + GetKeyboardState(keystate); + if ((keystate[VK_CONTROL] | keystate[VK_LCONTROL]) & 128) { - if (editor->editpane == hWnd) - break; - } - if (editor->scintilla) - { - FindNextScintilla(editor, buffer); + for (editor = editors; editor; editor = editor->next) + { + if (editor->editpane == hWnd) + break; + } + if (editor->scintilla) + { + if (!SendMessage(editor->editpane, SCI_AUTOCACTIVE, 0, 0)) + { + char buffer[65536]; + char prefixbuffer[128]; + char *pre = WordUnderCursor(editor, prefixbuffer, sizeof(prefixbuffer), NULL, 0, SendMessage(editor->editpane, SCI_GETCURRENTPOS, 0, 0)); + if (pre && *pre) + if (GenAutoCompleteList(pre, buffer, sizeof(buffer))) + { + SendMessage(editor->editpane, SCI_AUTOCSETFILLUPS, 0, (LPARAM)".,[<>(*/+-=\t\n"); + SendMessage(editor->editpane, SCI_AUTOCSHOW, strlen(pre), (LPARAM)buffer); + } + return FALSE; + } + } } } - return 0; + break; } - if (wParam == VK_F5) + } + if (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN) + { + switch(wParam) { - EngineGiveFocus(); - if (!EngineCommandf("qcresume\n")) - RunEngine(); - return 0; - } - if (wParam == VK_F7) - { - buttons[ID_COMPILE].washit = true; - return 0; - } - if (wParam == VK_F8) - { -// if (!EngineCommandf("qcjump\n")) -// RunEngine(); - return 0; - } - if (wParam == VK_F9) - { - editor_t *editor; - int mode; - for (editor = editors; editor; editor = editor->next) + case VK_F3: { - if (editor->editpane == hWnd) - break; + char buffer[128]; + GetWindowText(search_name, buffer, sizeof(buffer)); + if (*buffer == 0) + SetFocus(search_name); + else + { + editor_t *editor; + for (editor = editors; editor; editor = editor->next) + { + if (editor->editpane == hWnd) + break; + } + if (editor->scintilla) + { + FindNextScintilla(editor, buffer); + } + } } - if (editor->scintilla) - { - mode = !(SendMessage(editor->editpane, SCI_MARKERGET, editor->curline, 0) & 1); - SendMessage(editor->editpane, mode?SCI_MARKERADD:SCI_MARKERDELETE, editor->curline, 0); - } - else - mode = 2; - - EngineCommandf("qcbreakpoint %i \"%s\" %i\n", mode, editor->filename, editor->curline+1); - return 0; - } - if (wParam == VK_F11) - { - EngineCommandf("qcstep over\n"); - return 0; - } - if (wParam == VK_F11) - { - EngineCommandf("qcstep into\n"); return 0; } } @@ -812,6 +827,7 @@ enum { IDM_OPENNEW, IDM_GREP, IDM_GOTODEF, + IDM_OUTPUT_WINDOW, IDM_SAVE, IDM_RECOMPILE, IDM_FIND, @@ -819,10 +835,16 @@ enum { IDM_UNDO, IDM_REDO, IDM_ABOUT, - IDM_HIGHTLIGHT, IDM_CASCADE, IDM_TILE_HORIZ, IDM_TILE_VERT, + IDM_DEBUG_REBUILD, + IDM_DEBUG_SETNEXT, + IDM_DEBUG_RUN, + IDM_DEBUG_STEPOVER, + IDM_DEBUG_STEPINTO, + IDM_DEBUG_STEPOUT, + IDM_DEBUG_TOGGLEBREAK, IDI_O_LEVEL0, IDI_O_LEVEL1, @@ -849,7 +871,6 @@ void EditorReload(editor_t *editor); int EditorSave(editor_t *edit); void EditFile(char *name, int line); pbool EditorModified(editor_t *e); -int Rehighlight(editor_t *edit); void QueryOpenFile(void) { @@ -882,7 +903,7 @@ void GenericMenu(WPARAM wParam) break; case IDM_ABOUT: - MessageBox(NULL, "FTE QuakeC Compiler ("__DATE__" "__TIME__")\nWritten by Forethought Entertainment.\n\nIt has a few cool features, like a semi-useful IDE.\n\nSupports:\nPrecompiler (with macros)\nArrays\n+= / -= / *= / /= operations.\nSwitch statements\nfor loops\nLots of optimisations.", "About", 0); + MessageBox(NULL, "FTE QuakeC Compiler ("__DATE__" "__TIME__")\nWritten by Forethought Entertainment, whoever that is.\n\n", "About", 0); break; case IDM_CASCADE: @@ -894,6 +915,32 @@ void GenericMenu(WPARAM wParam) case IDM_TILE_VERT: SendMessage(mdibox, WM_MDITILE, MDITILE_VERTICAL, 0); break; + + + case IDM_OUTPUT_WINDOW: + if (outputwindow && outputbox) + { + SetFocus(outputwindow); + SetFocus(outputbox); + } + break; + case IDM_DEBUG_RUN: + EngineGiveFocus(); + if (!EngineCommandf("qcresume\n")) + RunEngine(); + return; + case IDM_DEBUG_REBUILD: + buttons[ID_COMPILE].washit = true; + return; + case IDM_DEBUG_STEPOVER: + EngineCommandf("qcstep over\n"); + return; + case IDM_DEBUG_STEPINTO: + EngineCommandf("qcstep into\n"); + return; + case IDM_DEBUG_STEPOUT: + EngineCommandf("qcstep out\n"); + return; } } @@ -952,9 +999,6 @@ void EditorMenu(editor_t *editor, WPARAM wParam) GoToDefinition(buffer); } break; - case IDM_HIGHTLIGHT: - Rehighlight(editor); - break; case IDM_UNDO: Edit_Undo(editor->editpane); @@ -963,6 +1007,23 @@ void EditorMenu(editor_t *editor, WPARAM wParam) Edit_Redo(editor->editpane); break; + case IDM_DEBUG_TOGGLEBREAK: + { + int mode; + if (editor->scintilla) + { + mode = !(SendMessage(editor->editpane, SCI_MARKERGET, editor->curline, 0) & 1); + SendMessage(editor->editpane, mode?SCI_MARKERADD:SCI_MARKERDELETE, editor->curline, 0); + } + else + mode = 2; + + EngineCommandf("qcbreakpoint %i \"%s\" %i\n", mode, editor->filename, editor->curline+1); + } + return; + case IDM_DEBUG_SETNEXT: + EngineCommandf("qcjump \"%s\" %i\n", editor->filename, editor->curline+1); + return; default: GenericMenu(wParam); break; @@ -1073,23 +1134,27 @@ pbool GenAutoCompleteList(char *prefix, char *buffer, int buffersize) int prefixlen = strlen(prefix); int usedbuffer = 0; int l; - for (def = pr.def_head.next; def; def = def->next) + int fno; + for (fno = 0; fno < sourcefilesnumdefs; fno++) { - if (def->scope) - continue; //ignore locals, because we don't know where we are, and they're probably irrelevent. - - //make sure it has the right prefix - if (!strncmp(def->name, prefix, prefixlen)) - //but ignore it if its one of those special things that you're not meant to know about. - if (strcmp(def->name, "IMMEDIATE") && !strchr(def->name, ':') && !strchr(def->name, '.') && !strchr(def->name, '*') && !strchr(def->name, '[')) + for (def = sourcefilesdefs[fno]; def; def = def->next) { - l = strlen(def->name); - if (l && usedbuffer+2+l < buffersize) + if (def->scope) + continue; //ignore locals, because we don't know where we are, and they're probably irrelevent. + + //make sure it has the right prefix + if (!strncmp(def->name, prefix, prefixlen)) + //but ignore it if its one of those special things that you're not meant to know about. + if (strcmp(def->name, "IMMEDIATE") && !strchr(def->name, ':') && !strchr(def->name, '.') && !strchr(def->name, '*') && !strchr(def->name, '[')) { - if (usedbuffer) - buffer[usedbuffer++] = ' '; - memcpy(buffer+usedbuffer, def->name, l); - usedbuffer += l; + l = strlen(def->name); + if (l && usedbuffer+2+l < buffersize) + { + if (usedbuffer) + buffer[usedbuffer++] = ' '; + memcpy(buffer+usedbuffer, def->name, l); + usedbuffer += l; + } } } } @@ -1114,14 +1179,13 @@ char *GetTooltipText(editor_t *editor, int pos, pbool dwell) return NULL; else if (globalstable.numbuckets) { - char *funcname; QCC_def_t *def; + int fno; + int line; char *macro = QCC_PR_CheckCompConstTooltip(defname, buffer, buffer + sizeof(buffer)); if (macro && *macro) return macro; - funcname = ""; //FIXME - if (dwell) { tooltip_editor = NULL; @@ -1131,15 +1195,31 @@ char *GetTooltipText(editor_t *editor, int pos, pbool dwell) *tooltip_comment = 0; } - def = QCC_PR_GetDef(NULL, defname, NULL, false, 0, GDF_SILENT); + line = SendMessage(editor->editpane, SCI_LINEFROMPOSITION, pos, 0); + + //FIXME: we may need to display types too + for (fno = 0, def = NULL; fno < sourcefilesnumdefs; fno++) + { + for (def = sourcefilesdefs[fno]; def; def = def->next) + { + if (def->scope) + continue; + if (!strcmp(def->name, defname)) + { + //FIXME: look at the scope's function to find the start+end of the function and filter based upon that, to show locals + break; + } + } + } + if (def) { char typebuf[1024]; //note function argument names do not persist beyond the function def. we might be able to read the function's localdefs for them, but that's unreliable/broken with builtins where they're most needed. if (def->comment) - _snprintf(buffer, sizeof(buffer)-1, "%s %s\r\n%s", TypeName(def->type, typebuf, sizeof(typebuf)), def->name, def->comment); + QC_snprintfz(buffer, sizeof(buffer)-1, "%s %s\r\n%s", TypeName(def->type, typebuf, sizeof(typebuf)), def->name, def->comment); else - _snprintf(buffer, sizeof(buffer)-1, "%s %s", TypeName(def->type, typebuf, sizeof(typebuf)), def->name); + QC_snprintfz(buffer, sizeof(buffer)-1, "%s %s", TypeName(def->type, typebuf, sizeof(typebuf)), def->name); if (dwell) { @@ -1159,7 +1239,7 @@ char *GetTooltipText(editor_t *editor, int pos, pbool dwell) tooltip_position = pos; tooltip_editor = editor; - EngineCommandf("qcinspect \"%s\" \"%s\"\n", term, funcname); + EngineCommandf("qcinspect \"%s\" \"%s\"\n", term, (def && def->scope)?def->scope->name:""); if (text) SendMessage(editor->editpane, SCI_CALLTIPSHOW, (WPARAM)pos, (LPARAM)text); @@ -1170,6 +1250,39 @@ char *GetTooltipText(editor_t *editor, int pos, pbool dwell) else return NULL;//"Type info not available. Compile first."; } + +//scans the preceeding line(s) to find the ideal indentation for the highlighted line +//indentbuf may contain spaces or tabs. preferably tabs. +static void scin_get_line_indent(HWND editpane, int lineidx, char *indentbuf, size_t sizeofbuf) +{ + int i; + int len; + while (lineidx --> 0) + { + len = SendMessage(editpane, SCI_LINELENGTH, lineidx, 0); + *indentbuf = 0; + if (len+2 < sizeofbuf) + { + //FIXME: ignore whitespace + len = SendMessage(editpane, SCI_GETLINE, lineidx, (LPARAM)indentbuf); + for (i = 0; i < len; i++) + { + if (indentbuf[i] == ' ' || indentbuf[i] == '\t') + continue; + break; + } + if (i == len) + continue; + + if (len >= 3 && indentbuf[len-3] == '{') + indentbuf[i++] = '\t'; //add an indent + indentbuf[i] = 0; + return; + } + } + *indentbuf = 0; //failed +} + static LRESULT CALLBACK EditorWndProc(HWND hWnd,UINT message, WPARAM wParam,LPARAM lParam) { @@ -1355,14 +1468,56 @@ static LRESULT CALLBACK EditorWndProc(HWND hWnd,UINT message, if (s) SendMessage(editor->editpane, SCI_CALLTIPSHOW, (WPARAM)pos, (LPARAM)s); } - else if (!SendMessage(editor->editpane, SCI_AUTOCACTIVE, 0, 0)) + else if (not->ch == '}') + { //if the first char on the line, fix up indents to match previous-1 + char prevline[65536]; + char newline[4096]; + int pos = SendMessage(editor->editpane, SCI_GETCURRENTPOS, 0, 0); + int lineidx = SendMessage(editor->editpane, SCI_LINEFROMPOSITION, pos, 0); + int linestart = SendMessage(editor->editpane, SCI_POSITIONFROMLINE, lineidx, 0); + int plen; + int nlen = SendMessage(editor->editpane, SCI_LINELENGTH, lineidx, 0); + if (nlen >= sizeof(newline)) + break; + nlen = SendMessage(editor->editpane, SCI_GETLINE, lineidx, (LPARAM)newline); + if (linestart > 2) + { + scin_get_line_indent(editor->editpane, lineidx, prevline, sizeof(prevline)); + plen = strlen(prevline); + if (plen > nlen) + break; //already indented a bit or something + if (!strncmp(prevline, newline, plen)) //same indent + { + SendMessage(editor->editpane, SCI_CHARLEFT, 0, 0); //move to the indent + SendMessage(editor->editpane, SCI_BACKTAB, 0, 0); //do shift-tab to un-indent the current selection (one line supposedly) + SendMessage(editor->editpane, SCI_CHARRIGHT, 0, 0); //and move back to the right of the } + } + } + } + else if (not->ch == '\r' || not->ch == '\n') + { + char linebuf[65536]; + int pos = SendMessage(editor->editpane, SCI_GETCURRENTPOS, 0, 0); + int lineidx = SendMessage(editor->editpane, SCI_LINEFROMPOSITION, pos, 0); + int linestart = SendMessage(editor->editpane, SCI_POSITIONFROMLINE, lineidx, 0); + int len = SendMessage(editor->editpane, SCI_LINELENGTH, lineidx, 0); + if (pos == linestart) + { + scin_get_line_indent(editor->editpane, lineidx, linebuf, sizeof(linebuf)); + SendMessage(editor->editpane, EM_REPLACESEL, 0, (LPARAM)linebuf); + } + } + else if (0)//(!SendMessage(editor->editpane, SCI_AUTOCACTIVE, 0, 0)) { char buffer[65536]; char prefixbuffer[128]; char *pre = WordUnderCursor(editor, prefixbuffer, sizeof(prefixbuffer), NULL, 0, SendMessage(editor->editpane, SCI_GETCURRENTPOS, 0, 0)); if (pre && *pre) if (GenAutoCompleteList(pre, buffer, sizeof(buffer))) + { + SendMessage(editor->editpane, SCI_AUTOCSETFILLUPS, 0, (LPARAM)"\t\n"); SendMessage(editor->editpane, SCI_AUTOCSHOW, strlen(pre), (LPARAM)buffer); + } } break; case SCN_SAVEPOINTREACHED: @@ -1436,346 +1591,8 @@ static LRESULT CALLBACK EditorWndProc(HWND hWnd,UINT message, return 0; } -#if 1 -static DWORD lastcolour; -int GUIEmitText(HWND wnd, int start, char *text, int len) -{ - int c, cr; - DWORD colour; - CHARFORMAT cf; - - if (!len) - return start; - - c = text[len]; - text[len] = '\0'; - Edit_SetSel(wnd,start,start); - Edit_ReplaceSel(wnd,text); - - if (!strcmp(text, "void")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "float")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "vector")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "entity")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "local")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "string")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "struct")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "class")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "union")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "const")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "var")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "nosave")) - colour = RGB(0, 0, 255); - - else if (!strcmp(text, "goto")) - colour = RGB(255, 0, 0); - else if (!strcmp(text, "thinktime")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "if")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "else")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "switch")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "case")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "default")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "break")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "continue")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "do")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "while")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "for")) - colour = RGB(0, 0, 255); - else if (!strcmp(text, "return")) - colour = RGB(0, 0, 255); - - else if (!strcmp(text, "self")) - colour = RGB(0, 0, 127); - else if (!strcmp(text, "this")) - colour = RGB(0, 0, 127); - else if (!strcmp(text, "other")) - colour = RGB(0, 0, 127); - else if (!strcmp(text, "world")) - colour = RGB(0, 0, 127); - else if (!strcmp(text, "time")) - colour = RGB(0, 0, 127); - - - else if (!strcmp(text, "#define")) - colour = RGB(0, 128, 255); - else if (!strcmp(text, "#ifdef")) - colour = RGB(0, 128, 255); - else if (!strcmp(text, "#ifndef")) - colour = RGB(0, 128, 255); - else if (!strcmp(text, "#else")) - colour = RGB(0, 128, 255); - else if (!strcmp(text, "#endif")) - colour = RGB(0, 128, 255); - else if (!strcmp(text, "#undef")) - colour = RGB(0, 128, 255); - else if (!strcmp(text, "#pragma")) - colour = RGB(0, 128, 255); - else if (!strcmp(text, "#includelist")) - colour = RGB(0, 128, 255); - else if (!strcmp(text, "#endlist")) - colour = RGB(0, 128, 255); - - - else if (*text == '\"') - colour = RGB(128, 0, 0); - - else if (!strncmp(text, "//", 2)) - colour = RGB(0, 127, 0); - else if (!strncmp(text, "/*", 2)) - colour = RGB(0, 127, 0); - else - colour = RGB(0, 0, 0); - - text[len] = c; - - cr = 0; - for (c = 0; c < len; c++) - if (text[c] == '\r') - cr++; - if (cr) - len-=cr; - - if (colour == lastcolour) - return start+len; - - lastcolour = colour; - - Edit_SetSel(wnd,start,start+len); - memset(&cf, 0, sizeof(cf)); - cf.cbSize = sizeof(cf); - cf.dwMask = CFM_COLOR; - cf.crTextColor = colour; - SendMessage(wnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); - Edit_SetSel(wnd,start+len,start+len); - - return start + len; -} -void GUIFormattingPrint(HWND wnd, char *msg) -{ - int len=Edit_GetTextLength(wnd); - char *start; - CHARRANGE chrg; - lastcolour = RGB(0,0,0); - SendMessage(wnd, WM_SETREDRAW, false, 0); - chrg.cpMin = chrg.cpMax = 0; - SendMessage(wnd, EM_EXSETSEL, 0, (LPARAM) &chrg); - - for(start = msg;;) - { - if (!*msg) - break; - else if (*msg == '/' && msg[1] == '/') - { - len = GUIEmitText(wnd, len, start, msg - start); - start = msg; - - msg+=2; - while(*msg && *msg != '\n' && *msg != '\r') - msg++; - } - else if (*msg == '/' && msg[1] == '*') - { - len = GUIEmitText(wnd, len, start, msg - start); - start = msg; - msg+=2; - while(*msg) - { - if (msg[0] == '*' && msg[1] == '/') - { - msg+=2; - break; - } - msg++; - } - } - else if (*msg == '#' || *msg == '_' || (*msg >= 'A' && *msg <= 'Z') || (*msg >= 'a' && *msg <= 'z')) - { - len = GUIEmitText(wnd, len, start, msg - start); - start = msg; - msg++; - while (*msg == '_' || (*msg >= 'A' && *msg <= 'Z') || (*msg >= 'a' && *msg <= 'z' || *msg >= '0' && *msg <= '9')) - msg++; - } - else if (*msg == '\"') - { - len = GUIEmitText(wnd, len, start, msg - start); - start = msg; - msg++; - while(*msg) - { - if (*msg == '\\') - msg++; - else if (*msg == '\"') - { - msg++; - break; - } - - msg++; - } - } -/* else if (*msg <= ' ') - { - while (*msg <= ' ' && *msg) - msg++; - }*/ - else - { - msg++; - continue; - } - - len = GUIEmitText(wnd, len, start, msg - start); - start = msg; - } - len = GUIEmitText(wnd, len, start, msg - start); - start = msg; - SendMessage(wnd, WM_SETREDRAW, true, 0); -} - -int Rehighlight(editor_t *edit) -{ - int len; - char *file; - - CHARRANGE chrg; - POINT scrollpos; - - SendMessage(edit->editpane, EM_SETEVENTMASK, 0, 0); - - SendMessage(edit->editpane, EM_GETSCROLLPOS, 0, (LPARAM)&scrollpos); - SendMessage(edit->editpane, EM_EXGETSEL, 0, (LPARAM) &chrg); - - len = Edit_GetTextLength(edit->editpane); - file = malloc(len+1); - if (!file) - { - MessageBox(NULL, "Save failed - not enough mem", "Error", 0); - return false; - } - Edit_GetText(edit->editpane, file, len); - file[len] = '\0'; - - SetWindowText(edit->editpane,""); - -// GUIPrint(edit->editpane, file); - GUIFormattingPrint(edit->editpane, file); - free(file); - -// Edit_SetSel(edit->editpane, Edit_LineIndex(neweditor->editpane, 0), Edit_LineIndex(neweditor->editpane, 0)); - - InvalidateRect(edit->editpane, NULL, true); - InvalidateRect(edit->window, NULL, true); - - SendMessage(edit->editpane, EM_SETEVENTMASK, 0, ENM_SELCHANGE|ENM_CHANGE); - - SendMessage(edit->editpane, EM_SETSCROLLPOS, 0, (LPARAM)&scrollpos); - SendMessage(edit->editpane, EM_EXSETSEL, 0, (LPARAM) &chrg); - - UpdateWindow(edit->editpane); - RedrawWindow(edit->window, NULL, NULL, 0); - - return true; -} -#else -static void chunkcolour(HWND pane, int start, int end, DWORD colour) -{ - CHARFORMAT cf; - if (colour == RGB(0,0,0)) - return; //don't need to - Edit_SetSel(pane,start,end); - memset(&cf, 0, sizeof(cf)); - cf.cbSize = sizeof(cf); - cf.dwMask = CFM_COLOR; - cf.crTextColor = colour; - SendMessage(pane, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); -} -void GUIFormattingPrint(HWND wnd, char *msg) -{ -} -int Rehighlight(editor_t *edit) -{ - char *file; - int c, last, len; - DWORD color; - CHARRANGE chrg; - POINT scrollpos; - - //Dsiable redraws - SendMessage(edit->editpane, WM_SETREDRAW, false, 0); - - //Don't notify us for a bit.. - SendMessage(edit->editpane, EM_SETEVENTMASK, 0, 0); - - //get state so we can restore scroll positions and things. - SendMessage(edit->editpane, EM_GETSCROLLPOS, 0, (LPARAM)&scrollpos); - SendMessage(edit->editpane, EM_EXGETSEL, 0, (LPARAM) &chrg); - - - len = Edit_GetTextLength(edit->editpane); - file = malloc(len+1); - if (!file) - { - MessageBox(NULL, "Highlight failed - not enough mem", "Error", 0); - return false; - } - Edit_GetText(edit->editpane, file, len); - file[len] = '\0'; - SetWindowText(edit->editpane,file); //this is so that we guarentee that the \rs or whatever that windows insists on inserting don't get in the way - - color = RGB(0,0,0); - for (last = 0, c = 0; c < len; c++) - { - if (file[c] == '/' && file[c+1] == '/') //do special syntax - { - chunkcolour(edit->editpane, last, c, color); - last = c; - - while(file[c] != '\n') - c++; - color = RGB(0, 127, 0); - } - else - { - chunkcolour(edit->editpane, last, c, color); - last = c; - - while(file[c] >= 'a' && file[c] <= 'z' || file[c] >= 'A' && file[c] <= 'Z' || file[c] == '_') - c++; - - color = RGB(rand(), rand(), rand()); - } - } - - free(file); - - //reenable drawing - SendMessage(edit->editpane, WM_SETREDRAW, true, 0); -} -#endif - unsigned short *QCC_makeutf16(char *mem, unsigned int len, int *outlen); -void EditorReload(editor_t *editor) +static void EditorReload(editor_t *editor) { struct stat sbuf; int flen; @@ -1860,7 +1677,8 @@ void EditFile(char *name, int line) if (QCC_FileSize(name) == -1) { - MessageBox(NULL, "File not found.", "Error", 0); + QC_snprintfz(title, sizeof(title), "File not found.\n%s", name); + MessageBox(NULL, title, "Error", 0); return; } @@ -1893,7 +1711,6 @@ void EditFile(char *name, int line) AppendMenu(menunavig, 0, IDM_GOTODEF, "Go to definition"); AppendMenu(menunavig, 0, IDM_OPENDOCU, "Open selected file"); AppendMenu(menuhelp, 0, IDM_ABOUT, "About"); -// AppendMenu(menu, 0, IDM_HIGHTLIGHT, "H&ighlight"); } @@ -3015,7 +2832,7 @@ void OptionsDialog(void) height++; } - cflagsshown = 2; + cflagsshown = 0; for (i = 0; compiler_flag[i].enabled; i++) { if (compiler_flag[i].flags & FLAG_HIDDENINGUI) @@ -3024,21 +2841,23 @@ void OptionsDialog(void) cflagsshown++; } - height = (height-1)/2; + height = (height+1)/2; - while (cflagsshown > ((480-(88+40))/16)*(flagcolums)) + height *= 16; + + height += 112; + + while (cflagsshown*16 > height*flagcolums) flagcolums++; - if (height < (cflagsshown+flagcolums-1)/flagcolums) - height = (cflagsshown+flagcolums-1)/flagcolums; + if (height < (cflagsshown*16)/flagcolums) + height = (cflagsshown*16)/flagcolums; r.right = 408 + flagcolums*168; if (r.right < 640) r.right = 640; - height *= 16; - - height += 88+40; + height += 88; r.left = GetSystemMetrics(SM_CXSCREEN)/2-320; r.top = GetSystemMetrics(SM_CYSCREEN)/2-240; @@ -3053,7 +2872,7 @@ void OptionsDialog(void) r.left, r.top, r.right-r.left, r.bottom-r.top, NULL, NULL, ghInstance, NULL); subsection = CreateWindow("BUTTON", "Optimisations", WS_CHILD|WS_VISIBLE|BS_GROUPBOX, - 0, 0, 400, height-40*4-8, optionsmenu, NULL, ghInstance, NULL); + 0, 0, 400, height-40*4+24, optionsmenu, NULL, ghInstance, NULL); num = 0; for (i = 0; optimisations[i].enabled; i++) @@ -3085,42 +2904,42 @@ void OptionsDialog(void) CreateWindow("BUTTON","O0", WS_CHILD | WS_VISIBLE, - 8,height-40*5-8,64,32, + 8,height-40*5+24,64,32, optionsmenu, (HMENU)IDI_O_LEVEL0, ghInstance, NULL); CreateWindow("BUTTON","O1", WS_CHILD | WS_VISIBLE, - 8+64,height-40*5-8,64,32, + 8+64,height-40*5+24,64,32, optionsmenu, (HMENU)IDI_O_LEVEL1, ghInstance, NULL); CreateWindow("BUTTON","O2", WS_CHILD | WS_VISIBLE, - 8+64*2,height-40*5-8,64,32, + 8+64*2,height-40*5+24,64,32, optionsmenu, (HMENU)IDI_O_LEVEL2, ghInstance, NULL); CreateWindow("BUTTON","O3", WS_CHILD | WS_VISIBLE, - 8+64*3,height-40*5-8,64,32, + 8+64*3,height-40*5+24,64,32, optionsmenu, (HMENU)IDI_O_LEVEL3, ghInstance, NULL); CreateWindow("BUTTON","Debug", WS_CHILD | WS_VISIBLE, - 8+64*4,height-40*5-8,64,32, + 8+64*4,height-40*5+24,64,32, optionsmenu, (HMENU)IDI_O_DEBUG, ghInstance, NULL); CreateWindow("BUTTON","Default", WS_CHILD | WS_VISIBLE, - 8+64*5,height-40*5-8,64,32, + 8+64*5,height-40*5+24,64,32, optionsmenu, (HMENU)IDI_O_DEFAULT, ghInstance, @@ -3337,17 +3156,21 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message, AppendMenu(m, 0, IDM_UNDO, "Undo Ctrl+Z"); AppendMenu(m, 0, IDM_REDO, "Redo Ctrl+Y"); AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()), "&Navigation"); - AppendMenu(m, 0, IDM_GOTODEF, "Go to definition"); + AppendMenu(m, 0, IDM_GOTODEF, "Go to definition\tF12"); AppendMenu(m, 0, IDM_OPENDOCU, "Open selected file"); + AppendMenu(m, 0, IDM_OUTPUT_WINDOW, "Show Output Window\tF6"); AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = windowmenu = CreateMenu()), "&Window"); AppendMenu(m, 0, IDM_CASCADE, "Cascade"); AppendMenu(m, 0, IDM_TILE_HORIZ, "Tile Horizontally"); AppendMenu(m, 0, IDM_TILE_VERT, "Tile Vertically"); AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()), "&Debug"); - AppendMenu(m, 0, IDM_CASCADE, "Rebuild\tF7"); - AppendMenu(m, 0, IDM_TILE_HORIZ, "Run/Resume\tF5"); - AppendMenu(m, 0, IDM_TILE_HORIZ, "Step Into\tF11"); - AppendMenu(m, 0, IDM_TILE_VERT, "Set Breakpoint\tF9"); + AppendMenu(m, 0, IDM_DEBUG_REBUILD, "Rebuild\tF7"); + AppendMenu(m, 0, IDM_DEBUG_SETNEXT, "Set Next Statement\tF8"); + AppendMenu(m, 0, IDM_DEBUG_RUN, "Run/Resume\tF5"); + AppendMenu(m, 0, IDM_DEBUG_STEPOVER, "Step Over\tF10"); + AppendMenu(m, 0, IDM_DEBUG_STEPINTO, "Step Into\tF11"); + AppendMenu(m, 0, IDM_DEBUG_STEPOUT, "Step Out\tShift-F11"); + AppendMenu(m, 0, IDM_DEBUG_TOGGLEBREAK, "Set Breakpoint\tF9"); AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()), "&Help"); AppendMenu(m, 0, IDM_ABOUT, "About"); @@ -3669,6 +3492,7 @@ int GUIprintf(const char *msg, ...) if (!*buf) { + editor_t *ed; /*clear text*/ SetWindowText(outputbox,""); outlen = 0; @@ -3680,6 +3504,13 @@ int GUIprintf(const char *msg, ...) /*colour background to default*/ TreeView_SetBkColor(projecttree, -1); outstatus = 0; + + + for (ed = editors; ed; ed = ed->next) + { + if (ed->scintilla) + SendMessage(ed->editpane, SCI_ANNOTATIONCLEARALL, 0, 0); + } return 0; } @@ -3710,9 +3541,64 @@ int GUIprintf(const char *msg, ...) if (*s == '\n') { *s = '\0'; - if (*st) - outlen = GUIEmitOutputText(outputbox, outlen, st, strlen(st), col); - outlen = GUIEmitOutputText(outputbox, outlen, rn, 1, col); + if (!strncmp(st, "code: ", 6)) + st+=6; + else + { + if (*st) + outlen = GUIEmitOutputText(outputbox, outlen, st, strlen(st), col); + outlen = GUIEmitOutputText(outputbox, outlen, rn, 1, col); + } + + { + char *colon1 = strchr(st, ':'); + if (colon1) + { + char *colon2 = strchr(colon1+1, ':'); + if (colon2) + { + unsigned int line; + char *validation; + *colon1 = 0; + line = strtoul(colon1+1, &validation, 10); + if (validation == colon2) + { + editor_t *ed; + colon2++; + while(*colon2 == ' ' || *colon2 == '\t') + colon2++; + for (ed = editors; ed; ed = ed->next) + { + if (!stricmp(ed->filename, st)) + { + if (ed->scintilla) + { + if (!SendMessage(ed->editpane, SCI_ANNOTATIONGETLINES, line-1, 0)) + { + SendMessage(ed->editpane, SCI_ANNOTATIONSETVISIBLE, ANNOTATION_BOXED, 0); + SendMessage(ed->editpane, SCI_ANNOTATIONSETTEXT, line-1, (LPARAM)colon2); + } + else + { + char buf[8192]; + int clen = SendMessage(ed->editpane, SCI_ANNOTATIONGETTEXT, line-1, (LPARAM)NULL); + if (clen+1+strlen(colon2) < sizeof(buf)) + { + clen = SendMessage(ed->editpane, SCI_ANNOTATIONGETTEXT, line-1, (LPARAM)buf); + buf[clen++] = '\n'; + memcpy(buf+clen, colon2, strlen(colon2)+1); +// SendMessage(ed->editpane, SCI_ANNOTATIONSETVISIBLE, ANNOTATION_BOXED, 0); + SendMessage(ed->editpane, SCI_ANNOTATIONSETTEXT, line-1, (LPARAM)buf); + } + } + } + break; + } + } + } + } + } + } st = s+1; } @@ -4047,7 +3933,17 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin { {FCONTROL|FVIRTKEY, 'S', IDM_SAVE}, {FCONTROL|FVIRTKEY, 'F', IDM_FIND}, - {FCONTROL|FVIRTKEY, 'R', IDM_RECOMPILE} + {FCONTROL|FVIRTKEY, 'R', IDM_RECOMPILE}, +// {FVIRTKEY, VK_F4, IDM_NEXTERROR}, + {FVIRTKEY, VK_F5, IDM_DEBUG_RUN}, + {FVIRTKEY, VK_F6, IDM_OUTPUT_WINDOW}, + {FVIRTKEY, VK_F7, IDM_DEBUG_REBUILD}, + {FVIRTKEY, VK_F8, IDM_DEBUG_SETNEXT}, + {FVIRTKEY, VK_F9, IDM_DEBUG_TOGGLEBREAK}, + {FVIRTKEY, VK_F10, IDM_DEBUG_STEPOVER}, + {FVIRTKEY, VK_F11, IDM_DEBUG_STEPINTO}, + {FSHIFT|FVIRTKEY, VK_F11, IDM_DEBUG_STEPOUT}, + {FVIRTKEY, VK_F12, IDM_GOTODEF} }; ghInstance= hInstance; diff --git a/engine/qclib/qccguistuff.c b/engine/qclib/qccguistuff.c index 1b271dbd5..3fd49bd9e 100644 --- a/engine/qclib/qccguistuff.c +++ b/engine/qclib/qccguistuff.c @@ -310,9 +310,19 @@ void GUI_ParseCommandLine(char *args) } else if (isfirst && *args != '-' && *args != '/') { + pbool qt = *args == '\"'; l = 0; + if (qt) + args++; while (*args != ' ' && *args) + { + if (qt && *args == '\"') + { + args++; + break; + } progssrcname[l++] = *args++; + } progssrcname[l] = 0; args = strrchr(progssrcname, '\\'); diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index b041b415d..c93e87f28 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -21,6 +21,7 @@ int writeasm; pbool verbose; pbool qcc_nopragmaoptimise; extern unsigned int locals_marshalled; +extern int qccpersisthunk; pbool QCC_PR_SimpleGetToken (void); void QCC_PR_LexWhitespace (pbool inhibitpreprocessor); @@ -46,6 +47,8 @@ int numtemps; #define MAXSOURCEFILESLIST 8 char sourcefileslist[MAXSOURCEFILESLIST][1024]; +QCC_def_t *sourcefilesdefs[MAXSOURCEFILESLIST]; +int sourcefilesnumdefs; int currentsourcefile; int numsourcefiles; extern char *compilingfile; @@ -177,6 +180,7 @@ struct { {" F305", WARN_CASEINSENSITIVEFRAMEMACRO}, {" F306", WARN_SAMENAMEASGLOBAL}, {" F307", WARN_STRICTTYPEMISMATCH}, + {" F308", WARN_TYPEMISMATCHREDECOPTIONAL}, //frikqcc errors //Q608: PrecacheSound: numsounds @@ -289,6 +293,7 @@ compiler_flag_t compiler_flag[] = { {&output_parms, 0, "parms", "Define offset parms", "if PARM0 PARM1 etc should be defined by the compiler. These are useful if you make use of the asm keyword for function calls, or you wish to create your own variable arguments. This is an easy way to break decompilers."}, //controls weather to define PARMx for the parms (note - this can screw over some decompilers) {&autoprototype, 0, "autoproto", "Automatic Prototyping","Causes compilation to take two passes instead of one. The first pass, only the definitions are read. The second pass actually compiles your code. This means you never have to remember to prototype functions again."}, //so you no longer need to prototype functions and things in advance. {&writeasm, 0, "wasm", "Dump Assembler", "Writes out a qc.asm which contains all your functions but in assembler. This is a great way to look for bugs in fteqcc, but can also be used to see exactly what your functions turn into, and thus how to optimise statements better."}, //spit out a qc.asm file, containing an assembler dump of the ENTIRE progs. (Doesn't include initialisation of constants) + {&flag_guiannotate, FLAG_MIDCOMPILE,"annotate", "Annotate Sourcecode", "Annotate source code with assembler statements on compile (requires gui)."}, {&flag_ifstring, FLAG_MIDCOMPILE,"ifstring", "if(string) fix", "Causes if(string) to behave identically to if(string!="") This is most useful with addons of course, but also has adverse effects with FRIK_FILE's fgets, where it becomes impossible to determin the end of the file. In such a case, you can still use asm {IF string 2;RETURN} to detect eof and leave the function."}, //correction for if(string) no-ifstring to get the standard behaviour. {&flag_iffloat, FLAG_MIDCOMPILE,"iffloat","if(-0.0) fix","Fixes certain floating point logic."}, {&flag_acc, 0, "acc", "Reacc support", "Reacc is a pascall like compiler. It was released before the Quake source was released. This flag has a few effects. It sorts all qc files in the current directory into alphabetical order to compile them. It also allows Reacc global/field distinctions, as well as allows ¦ as EOF. Whilst case insensitivity and lax type checking are supported by reacc, they are seperate compiler flags in fteqcc."}, //reacc like behaviour of src files. @@ -330,6 +335,16 @@ struct { {0, NULL} }; + +const char *QCC_VersionString(void) +{ +#ifdef SVNVERSION + if (strcmp(SVNVERSION, "-")) + return "FTEQCC: " STRINGIFY(SVNVERSION) " (" __DATE__")"; +#endif + return "FTEQCC: " __DATE__; +} + /* ================= BspModels @@ -820,11 +835,11 @@ pbool QCC_WriteData (int crc) if (def->type->type == ev_vector || (def->type->type == ev_field && def->type->aux_type->type == ev_vector)) { //do the references, so we don't get loadsa not referenced VEC_HULL_MINS_x s_file = def->s_file; - sprintf(element, "%s_x", def->name); + QC_snprintfz (element, sizeof(element), "%s_x", def->name); comp_x = QCC_PR_GetDef(NULL, element, def->scope, false, 0, false); - sprintf(element, "%s_y", def->name); + QC_snprintfz (element, sizeof(element), "%s_y", def->name); comp_y = QCC_PR_GetDef(NULL, element, def->scope, false, 0, false); - sprintf(element, "%s_z", def->name); + QC_snprintfz (element, sizeof(element), "%s_z", def->name); comp_z = QCC_PR_GetDef(NULL, element, def->scope, false, 0, false); h = def->references; @@ -1616,39 +1631,39 @@ char *QCC_PR_ValueString (etype_t type, void *val) switch (type) { case ev_string: - sprintf (line, "%s", QCC_PR_String(strings + *(int *)val)); + QC_snprintfz (line, sizeof(line), "%s", QCC_PR_String(strings + *(int *)val)); break; case ev_entity: - sprintf (line, "entity %i", *(int *)val); + QC_snprintfz (line, sizeof(line), "entity %i", *(int *)val); break; case ev_function: f = functions + *(int *)val; if (!f) - sprintf (line, "undefined function"); + QC_snprintfz (line, sizeof(line), "undefined function"); else - sprintf (line, "%s()", strings + f->s_name); + QC_snprintfz (line, sizeof(line), "%s()", strings + f->s_name); break; case ev_field: def = QCC_PR_DefForFieldOfs ( *(int *)val ); - sprintf (line, ".%s", def->name); + QC_snprintfz (line, sizeof(line), ".%s", def->name); break; case ev_void: - sprintf (line, "void"); + QC_snprintfz (line, sizeof(line), "void"); break; case ev_float: - sprintf (line, "%5.1f", *(float *)val); + QC_snprintfz (line, sizeof(line), "%5.1f", *(float *)val); break; case ev_integer: - sprintf (line, "%i", *(int *)val); + QC_snprintfz (line, sizeof(line), "%i", *(int *)val); break; case ev_vector: - sprintf (line, "'%5.1f %5.1f %5.1f'", ((float *)val)[0], ((float *)val)[1], ((float *)val)[2]); + QC_snprintfz (line, sizeof(line), "'%5.1f %5.1f %5.1f'", ((float *)val)[0], ((float *)val)[1], ((float *)val)[2]); break; case ev_pointer: - sprintf (line, "pointer"); + QC_snprintfz (line, sizeof(line), "pointer"); break; default: - sprintf (line, "bad type %i", type); + QC_snprintfz (line, sizeof(line), "bad type %i", type); break; } @@ -1674,14 +1689,14 @@ padded to 20 field width def = pr_global_defs[ofs]; if (!def) // Error ("PR_GlobalString: no def for %i", ofs); - sprintf (line,"%i(?""?""?)", ofs); + QC_snprintfz (line, sizeof(line), "%i(?""?""?)", ofs); else - sprintf (line,"%i(%s)", ofs, def->name); + QC_snprintfz (line, sizeof(line), "%i(%s)", ofs, def->name); i = strlen(line); for ( ; i<16 ; i++) - strcat (line," "); - strcat (line," "); + Q_strlcat (line," ", sizeof(line)); + Q_strlcat (line," ", sizeof(line)); return line; } @@ -1701,10 +1716,10 @@ char *QCC_PR_GlobalString (gofs_t ofs) if (def->initialized && def->type->type != ev_function) { s = QCC_PR_ValueString (def->type->type, &qcc_pr_globals[ofs]); - sprintf (line,"%i(%s)", ofs, s); + QC_snprintfz (line, sizeof(line), "%i(%s)", ofs, s); } else - sprintf (line,"%i(%s)", ofs, def->name); + QC_snprintfz (line, sizeof(line), "%i(%s)", ofs, def->name); i = strlen(line); for ( ; i<16 ; i++) @@ -1857,7 +1872,7 @@ void QCC_PR_BeginCompilation (void *memory, int memsize) QCC_PR_GetDef(type_vector, "RETURN", NULL, true, 0, false)->references++; for (i = 0; i < MAX_PARMS; i++) { - sprintf(name, "PARM%i", i); + QC_snprintfz (name, sizeof(name), "PARM%i", i); QCC_PR_GetDef(type_vector, name, NULL, true, 0, false)->references++; } } @@ -2054,7 +2069,7 @@ static void Add3(char *p, unsigned short *crc, char *file) unsigned short QCC_PR_WriteProgdefs (char *filename) { -#define ADD2(p) strncat(file, p, PROGDEFS_MAX_SIZE-1 - strlen(file)) //no crc (later changes) +#define ADD2(p) QC_strlcat(file, p, sizeof(file)) //no crc (later changes) char file[PROGDEFS_MAX_SIZE]; QCC_def_t *d; int f; @@ -3088,6 +3103,7 @@ pbool QCC_main (int argc, char **argv) //as part of the quake engine extern QCC_type_t *pr_classtype; int p; + extern int qccpersisthunk; #ifndef QCCONLY char destfile2[1024], *s2; @@ -3100,8 +3116,15 @@ pbool QCC_main (int argc, char **argv) //as part of the quake engine return false; } - if (!PreCompile()) - return false; + if (currentsourcefile && qccpersisthunk && numsourcefiles) + QCC_PR_ResetErrorScope(); //don't clear the ram if we're retaining def info + else + { + memset(sourcefilesdefs, 0, sizeof(sourcefilesdefs)); + sourcefilesnumdefs = 0; + if (!PreCompile()) + return false; + } SetEndian(); @@ -3186,7 +3209,8 @@ pbool QCC_main (int argc, char **argv) //as part of the quake engine */ time(&long_time); - strftime(QCC_copyright, sizeof(QCC_copyright), "Compiled [%Y/%m/%d]", localtime( &long_time )); + strftime(QCC_copyright, sizeof(QCC_copyright), "Compiled [%Y/%m/%d]. ", localtime( &long_time )); + QC_strlcat(QCC_copyright, QCC_VersionString(), sizeof(QCC_copyright)); for (p = 0; p < 5; p++) strcpy(QCC_Packname[p], ""); @@ -3380,6 +3404,8 @@ memset(pr_immediate_string, 0, sizeof(pr_immediate_string)); if (currentsourcefile) printf("-------------------------------------\n"); + else + printf("%s\n", QCC_VersionString()); sprintf (qccmprogsdat, "%s%s", qccmsourcedir, sourcefileslist[currentsourcefile++]); printf ("Source file: %s\n", qccmprogsdat); @@ -3541,7 +3567,11 @@ void QCC_ContinueCompile(void) if (!qccmsrc) { if (parseonly) + { qcc_compileactive = false; + sourcefilesdefs[currentsourcefile] = qccpersisthunk?pr.def_head.next:NULL; + sourcefilesnumdefs = sourcefilesnumdefs+1; + } else { if (autoprototype) @@ -3661,6 +3691,9 @@ void QCC_FinishCompile(void) // report / copy the data files QCC_CopyFiles (); + sourcefilesdefs[currentsourcefile] = qccpersisthunk?pr.def_head.next:NULL; + sourcefilesnumdefs = sourcefilesnumdefs+1; + if (donesomething) { if (verbose) @@ -3800,7 +3833,11 @@ void new_QCC_ContinueCompile(void) { if (!parseonly) QCC_FinishCompile(); - + else + { + sourcefilesdefs[currentsourcefile] = qccpersisthunk?pr.def_head.next:NULL; + sourcefilesnumdefs = sourcefilesnumdefs+1; + } PostCompile(); if (!QCC_main(myargc, myargv)) return; diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index 2f7fc40ab..d3622ee16 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -786,7 +786,7 @@ void NPP_NQFlush(void) memmove(buffer+3, buffer+1, bufferlen-1); /*add a length in the 2nd/3rd bytes, if needed*/ - buffer[1] = (bufferlen-1); + buffer[1] = (bufferlen-1) & 0xff; buffer[2] = (bufferlen-1) >> 8; bufferlen += 2; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index e907faac4..be9b819f1 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -100,6 +100,8 @@ unsigned int h2infoplaque[2]; /*hexen2 stat*/ static void PRSV_ClearThreads(void); void PR_fclose_progs(pubprogfuncs_t*); void PF_InitTempStrings(pubprogfuncs_t *prinst); +static int PDECL PR_SSQC_MapNamedBuiltin(pubprogfuncs_t *progfuncs, int headercrc, const char *builtinname); +static void QCBUILTIN PF_Fixme (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void PR_DumpPlatform_f(void); @@ -136,7 +138,6 @@ typedef struct { qboolean obsolete; } BuiltinList_t; builtin_t pr_builtin[1024]; -extern BuiltinList_t BuiltinList[]; struct { func_t ChatMessage; //mvdsv parsing of 'say' commands @@ -221,18 +222,12 @@ pbool PDECL ED_CanFree (edict_t *ed) if (ed == (edict_t*)sv.world.edicts) { if (developer.value) - { - Con_TPrintf("cannot free world entity\n"); - PR_StackTrace(svprogfuncs, false); - svprogfuncs->pr_trace = 1; - } + PR_RunWarning(svprogfuncs, "cannot free world entity\n"); return false; } if (NUM_FOR_EDICT(svprogfuncs, ed) <= sv.allocated_client_slots) { - Con_TPrintf("cannot free player entities\n"); - PR_StackTrace(svprogfuncs, false); - svprogfuncs->pr_trace = 1; + PR_RunWarning(svprogfuncs, "cannot free player entities\n"); return false; } World_UnlinkEdict ((wedict_t*)ed); // unlink from world bsp @@ -266,9 +261,12 @@ pbool PDECL ED_CanFree (edict_t *ed) ed->xv->SendEntity = 0; sv.csqcentversion[ed->entnum] += 1; -#ifdef USEODE - World_ODE_RemoveFromEntity(&sv.world, (wedict_t*)ed); - World_ODE_RemoveJointFromEntity(&sv.world, (wedict_t*)ed); +#ifdef USERBE + if (sv.world.rbe) + { + sv.world.rbe->RemoveFromEntity(&sv.world, (wedict_t*)ed); + sv.world.rbe->RemoveJointFromEntity(&sv.world, (wedict_t*)ed); + } #endif @@ -477,6 +475,7 @@ static void SVPR_Get_FrameState(world_t *w, wedict_t *ent, framestate_t *fstate) { memset(fstate, 0, sizeof(*fstate)); fstate->g[FS_REG].frame[0] = ent->v->frame; + fstate->g[FS_REG].lerpweight[0] = 1; } static void SVPR_Event_Touch(world_t *w, wedict_t *s, wedict_t *o) @@ -571,8 +570,7 @@ void Q_SetProgsParms(qboolean forcompiler) svprogparms.thinktimeop = ThinkTimeOp; #endif - //used when loading a game - svprogparms.builtinsfor = NULL;//builtin_t *(*builtinsfor) (int num); //must return a pointer to the builtins that were used before the state was saved. + svprogparms.MapNamedBuiltin = PR_SSQC_MapNamedBuiltin; svprogparms.loadcompleate = NULL;//void (*loadcompleate) (int edictsize); //notification to reset any pointers. svprogparms.badfield = SV_BadField; @@ -590,7 +588,7 @@ void Q_SetProgsParms(qboolean forcompiler) svprogparms.sv_edicts = (edict_t**)&sv.world.edicts; svprogparms.sv_num_edicts = &sv.world.num_edicts; - svprogparms.useeditor = QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms); + svprogparms.useeditor = QCEditor; //until its properly tested if (pr_ssqc_memsize.ival == -2) @@ -640,9 +638,8 @@ void PR_Deinit(void) } } -#ifdef USEODE - World_ODE_End(&sv.world); -#endif + if (sv.world.rbe) + sv.world.rbe->End(&sv.world); #ifdef SQL SQL_KillServers(); @@ -940,7 +937,7 @@ progsnum_t AddProgs(const char *name) // svprogparms.autocompile = PR_COMPILECHANGED; - num = PR_LoadProgs (svprogfuncs, name, NULL, 0); + num = PR_LoadProgs (svprogfuncs, name); sv.world.usesolidcorpse = (progstype != PROG_H2); if (!i && num != -1) { @@ -1337,6 +1334,7 @@ void Q_InitProgs(void) Q_SetProgsParms(false); + memset(pr_builtin, 0, sizeof(pr_builtin)); // load progs to get entity field count PR_Configure(svprogfuncs, pr_ssqc_memsize.ival, MAX_PROGS, pr_enable_profiling.ival); @@ -1695,9 +1693,7 @@ void Q_InitProgs(void) SV_RegisterH2CustomTents(); #endif -#ifdef USEODE - World_ODE_Start(&sv.world); -#endif + World_RBE_Start(&sv.world); } qboolean PR_QCChat(char *text, int say_type) @@ -2219,31 +2215,14 @@ static void QCBUILTIN PF_objerror (pubprogfuncs_t *prinst, struct globalvars_s * /* ED_Print (ed); */ prinst->ED_Print(prinst, ed); - Con_Printf("%s", s); - if (developer.value) - prinst->pr_trace = 2; - else - { - Con_Printf("Program error: %s\n", s); - if (developer.value) - { - struct globalvars_s *pr_globals = PR_globals(prinst, PR_CURRENT); - prinst->pr_trace = 1; - G_INT(OFS_RETURN)=0; //just in case it was a float and should be an ent... - G_INT(OFS_RETURN+1)=0; - G_INT(OFS_RETURN+2)=0; - } - else - { - ED_Free (prinst, ed); - PR_StackTrace(prinst, true); - PR_AbortStack(prinst); - } + PR_RunWarning(prinst, "Program error: %s\n", s); - if (sv.time > 10) - Cbuf_AddText("restart\n", RESTRICT_LOCAL); - } + ED_Free (prinst, ed); + PR_AbortStack(prinst); + +// if (sv.time > 10) +// Cbuf_AddText("restart\n", RESTRICT_LOCAL); } @@ -2305,10 +2284,7 @@ static void QCBUILTIN PF_setsize (pubprogfuncs_t *prinst, struct globalvars_s *p if (e->isfree) { if (progstype != PROG_H2) - { - Con_TPrintf("%s edict was free\n", "setsize"); - prinst->pr_trace = 1; - } + PR_RunWarning(prinst, "%s edict was free\n", "setsize"); return; } if (e->readonly) @@ -5187,11 +5163,7 @@ void QCBUILTIN PF_logfrag (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa if (!fraglog_details.ival) return; //not logging any details else if (fraglog_details.ival == 7) - { //compat with mvdsv. - time_t t = time (NULL); - struct tm *tm = gmtime(&t); - Q_snprintfz(s, sizeof(s)-2, "\\frag\\"); - } + Q_snprintfz(s, sizeof(s)-2, "\\frag\\"); //compat with mvdsv. else if (fraglog_details.ival == 1) strcpy(s, "\\");//vanilla compat else //specify what info is actually in there @@ -5407,39 +5379,6 @@ void QCBUILTIN PF_multicast (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo SV_Multicast (o, to); } - -static void QCBUILTIN PF_Fixme (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) -{ -int i; -qboolean printedheader = false; - - SV_EndRedirect(); - - for (i = 0; BuiltinList[i].bifunc; i++) - { - if (BuiltinList[i].ebfsnum == prinst->lastcalledbuiltinnumber) - { - if (!printedheader) - { - Con_Printf( "\n" - "Mod forgot to ensure support for builtin %i\n" - "Please consult the extensionlist_ssqc command.\n" - "Possible builtins:\n", prinst->lastcalledbuiltinnumber); - printedheader = true; - } - Con_Printf("%s\n", BuiltinList[i].name); - } - } - - Con_Printf("\n"); - - if (progstype == PROG_QW) - prinst->RunError(prinst, "\nBuiltin %i not implemented.\nMods designed for mvdsv may need pr_imitatemvdsv to be enabled.", prinst->lastcalledbuiltinnumber); - else - prinst->RunError(prinst, "\nBuiltin %i not implemented.\nMod is not compatible.", prinst->lastcalledbuiltinnumber); - PR_BIError (prinst, "builtin not implemented"); -} - static void QCBUILTIN PF_Ignore(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { G_INT(OFS_RETURN) = 0; @@ -5868,38 +5807,6 @@ void PR_SQLCycle(void) - -int PR_EnableEBFSBuiltin(const char *name, int binum) -{ - int i; - for (i = 0;BuiltinList[i].name;i++) - { - if (!strcmp(BuiltinList[i].name, name) && BuiltinList[i].bifunc != PF_Fixme) - { - if (!binum) - binum = BuiltinList[i].ebfsnum; - if (!pr_overridebuiltins.value) - { - if (pr_builtin[binum] != NULL && pr_builtin[binum] != PF_Fixme) - { - if (pr_builtin[binum] == BuiltinList[i].bifunc) //it is already this function. - return binum; - - return 0; //already used... ? - } - } - - pr_builtin[binum] = BuiltinList[i].bifunc; - - return binum; - } - } - - return 0; //not known -} - - - lh_extension_t *checkfteextensioncl(int mask, const char *name) //true if the cient extension mask matches an extension name { int i; @@ -6375,7 +6282,7 @@ static void QCBUILTIN PF_OpenPortal (pubprogfuncs_t *prinst, struct globalvars_s ClientReliableWrite_Short(client, portal | (state<<15)); } } - CMQ2_SetAreaPortalState(portal, state); + CMQ2_SetAreaPortalState(sv.world.worldmodel, portal, state); } #endif #ifdef Q3BSPS @@ -6407,7 +6314,7 @@ static void QCBUILTIN PF_OpenPortal (pubprogfuncs_t *prinst, struct globalvars_s } } } - CMQ3_SetAreaPortalState(portal->pvsinfo.areanum, portal->pvsinfo.areanum2, state); + CMQ3_SetAreaPortalState(sv.world.worldmodel, portal->pvsinfo.areanum, portal->pvsinfo.areanum2, state); } #endif } @@ -8711,7 +8618,8 @@ static void QCBUILTIN PF_globalstat(pubprogfuncs_t *prinst, struct globalvars_s static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { unsigned int i, n; - extern qbyte playertouch[]; + extern qbyte *playertouch; + extern size_t playertouchmax; unsigned int msecs; extern cvar_t sv_gravity; edict_t *ent = G_EDICT(prinst, OFS_PARM0); @@ -8844,7 +8752,7 @@ static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars continue; n = pmove.physents[pmove.touchindex[i]].info; touched = EDICT_NUM(svprogfuncs, n); - if (!touched->v->touch || (playertouch[n/8]&(1<<(n%8)))) + if (!touched->v->touch || n >= playertouchmax || (playertouch[n/8]&(1<<(n%8)))) continue; sv.world.Event_Touch(&sv.world, (wedict_t*)touched, (wedict_t*)ent); @@ -9281,28 +9189,29 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"WriteEntity", PF_WriteEntity, 59, 59, 59, 0, "void(float to, entity val)"}, //59 #ifndef QUAKETC - {"swritebyte", PF_qtSingle_WriteByte}, //52 - {"swritechar", PF_qtSingle_WriteChar}, //53 - {"swriteshort", PF_qtSingle_WriteShort}, //54 - {"swritelong", PF_qtSingle_WriteLong}, //55 - {"swritecoord", PF_qtSingle_WriteCoord}, //56 - {"swriteangle", PF_qtSingle_WriteAngle}, //57 - {"swritestring", PF_qtSingle_WriteString}, //58 - {"swriteentity", PF_qtSingle_WriteEntity}, + {"swritebyte", PF_qtSingle_WriteByte, 0, 0, 0, 0, D("void(float val)", "A legacy of qtest - like WriteByte, except writes explicitly to the MSG_ONE target."), true}, //52 + {"swritechar", PF_qtSingle_WriteChar, 0, 0, 0, 0, D("void(float val)", NULL), true}, //53 + {"swriteshort", PF_qtSingle_WriteShort, 0, 0, 0, 0, D("void(float val)", NULL), true}, //54 + {"swritelong", PF_qtSingle_WriteLong, 0, 0, 0, 0, D("void(float val)", NULL), true}, //55 + {"swritecoord", PF_qtSingle_WriteCoord, 0, 0, 0, 0, D("void(float val)", NULL), true}, //56 + {"swriteangle", PF_qtSingle_WriteAngle, 0, 0, 0, 0, D("void(float val)", NULL), true}, //57 + {"swritestring", PF_qtSingle_WriteString, 0, 0, 0, 0, D("void(string val)", NULL), true}, //58 + {"swriteentity", PF_qtSingle_WriteEntity, 0, 0, 0, 0, D("void(entity val)", NULL), true}, - {"bwritebyte", PF_qtBroadcast_WriteByte}, //59 - {"bwritechar", PF_qtBroadcast_WriteChar}, //60 - {"bwriteshort", PF_qtBroadcast_WriteShort}, //61 - {"bwritelong", PF_qtBroadcast_WriteLong}, //62 - {"bwritecoord", PF_qtBroadcast_WriteCoord}, //63 - {"bwriteangle", PF_qtBroadcast_WriteAngle}, //64 - {"bwritestring", PF_qtBroadcast_WriteString}, //65 - {"bwriteentity", PF_qtBroadcast_WriteEntity}, //66 + {"bwritebyte", PF_qtBroadcast_WriteByte, 0, 0, 0, 0, D("void(float byte)", "A legacy of qtest - like WriteByte, except writes explicitly to the MSG_ALL target."), true}, //59 + {"bwritechar", PF_qtBroadcast_WriteChar, 0, 0, 0, 0, D("void(float val)", NULL), true}, //60 + {"bwriteshort", PF_qtBroadcast_WriteShort, 0, 0, 0, 0, D("void(float val)", NULL), true}, //61 + {"bwritelong", PF_qtBroadcast_WriteLong, 0, 0, 0, 0, D("void(float val)", NULL), true}, //62 + {"bwritecoord", PF_qtBroadcast_WriteCoord, 0, 0, 0, 0, D("void(float val)", NULL), true}, //63 + {"bwriteangle", PF_qtBroadcast_WriteAngle, 0, 0, 0, 0, D("void(float val)", NULL), true}, //64 + {"bwritestring", PF_qtBroadcast_WriteString, 0, 0, 0, 0, D("void(string val)", NULL), true}, //65 + {"bwriteentity", PF_qtBroadcast_WriteEntity, 0, 0, 0, 0, D("void(entity val)", NULL), true}, //66 #endif {"sin", PF_Sin, 0, 0, 62, 60, "float(float angle)"}, //60 {"cos", PF_Cos, 0, 0, 61, 61, "float(float angle)"}, //61 {"sqrt", PF_Sqrt, 0, 0, 84, 62, "float(float value)"}, //62 + {"modulo", PF_mod, 0, 0, 0, 0, "float(float a, float n)"}, //62 {"changepitch", PF_changepitch, 0, 0, 0, 63, "void(entity ent)"}, {"tracetoss", PF_TraceToss, 0, 0, 0, 64, "void(entity ent, entity ignore)"}, @@ -9427,7 +9336,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"randomvec", PF_randomvector, 0, 0, 0, 91, D("vector()", "Returns a vector with random values. Each axis is independantly a value between -1 and 1 inclusive.")}, {"getlight", PF_sv_getlight, 0, 0, 0, 92, "vector(vector org)"},// (DP_QC_GETLIGHT), - {"registercvar", PF_registercvar, 0, 0, 0, 93, D("void(string cvarname, string defaultvalue)", "Creates a new cvar on the fly. If it does not already exist, it will be given the specified value. If it does exist, this is a no-op.\nThis builtin has the limitation that it does not apply to configs or commandlines. Such configs will need to use the set or seta command causing this builtin to be a noop.\nIn engines that support it, you will generally find the autocvar feature easier and more efficient to use.")}, + {"registercvar", PF_registercvar, 0, 0, 0, 93, D("float(string cvarname, string defaultvalue)", "Creates a new cvar on the fly. If it does not already exist, it will be given the specified value. If it does exist, this is a no-op.\nThis builtin has the limitation that it does not apply to configs or commandlines. Such configs will need to use the set or seta command causing this builtin to be a noop.\nIn engines that support it, you will generally find the autocvar feature easier and more efficient to use.")}, {"min", PF_min, 0, 0, 0, 94, D("float(float a, float b, ...)", "Returns the lowest value of its arguments.")},// (DP_QC_MINMAXBOUND) {"max", PF_max, 0, 0, 0, 95, D("float(float a, float b, ...)", "Returns the highest value of its arguments.")},// (DP_QC_MINMAXBOUND) {"bound", PF_bound, 0, 0, 0, 96, D("float(float minimum, float val, float maximum)", "Returns val, unless minimum is higher, or maximum is less.")},// (DP_QC_MINMAXBOUND) @@ -9476,6 +9385,12 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs //end telejano //fte extras + +// {"findlist_string", PF_FindListString, 0, 0, 0, 0, D("entity*(.string fld, string match)", "Return a list of entities with the given string field set to the given value.")}, +// {"findlist_float", PF_FindListFloat, 0, 0, 0, 0, D("entity*(.__variant fld, __variant match)", "Return a list of entities with the given field set to the given value.")}, +// {"findlist_radius", PF_FindListRadius, 0, 0, 0, 0, D("entity*(vector pos, float radius)", "Return a list of entities with the given string field set to the given value.")}, +// {"traceboxptr", PF_TraceBox, 0, 0, 0, 0, D("typedef struct {\nfloat allsolid;\nfloat startsolid;\nfloat fraction;\nfloat truefraction;\nentity ent;\nvector endpos;\nvector plane_normal;\nfloat plane_dist;\nint surfaceflags;\nint contents;\n} trace_t;\nvoid(trace_t *trace, vector start, vector mins, vector maxs, vector end, float nomonsters, entity forent)", "Like regular tracebox, except doesn't doesn't use any evil globals.")}, + {"getmodelindex", PF_getmodelindex, 0, 0, 0, 200, D("float(string modelname, optional float queryonly)", "Acts as an alternative to precache_model(foo);setmodel(bar, foo); return bar.modelindex;\nIf queryonly is set and the model was not previously precached, the builtin will return 0 without needlessly precaching the model.")}, {"externcall", PF_externcall, 0, 0, 0, 201, D("__variant(float prnum, string funcname, ...)", "Directly call a function in a different/same progs by its name.\nprnum=0 is the 'default' or 'main' progs.\nprnum=-1 means current progs.\nprnum=-2 will scan through the active progs and will use the first it finds.")}, {"addprogs", PF_addprogs, 0, 0, 0, 202, D("float(string progsname)", "Loads an additional .dat file into the current qcvm. The returned handle can be used with any of the externcall/externset/externvalue builtins.\nThere are cvars that allow progs to be loaded automatically.")}, @@ -9624,8 +9539,10 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs //maths stuff that uses the current view settings. {"unproject", PF_Fixme, 0, 0, 0, 310, D("vector (vector v)", "Transform a 2d screen-space point (with depth) into a 3d world-space point, according the various origin+angle+fov etc settings set via setproperty.")},// (EXT_CSQC) {"project", PF_Fixme, 0, 0, 0, 311, D("vector (vector v)", "Transform a 3d world-space point into a 2d screen-space point, according the various origin+angle+fov etc settings set via setproperty.")},// (EXT_CSQC) - + //312 + //313 //2d (immediate) operations + {"drawtextfield", PF_Fixme, 0, 0, 0, 0/*314*/, D("void(vector pos, vector size, float alignflags, string text)", "Draws a multi-line block of text, including word wrapping and alignment. alignflags bits are RTLB, typically 3.")},// (EXT_CSQC) {"drawline", PF_Fixme, 0, 0, 0, 315, D("void(float width, vector pos1, vector pos2, vector rgb, float alpha, optional float drawflag)", "Draws a 2d line between the two 2d points.")},// (EXT_CSQC) {"iscachedpic", PF_Fixme, 0, 0, 0, 316, D("float(string name)", "Checks to see if the image is currently loaded. Engines might lie, or cache between maps.")},// (EXT_CSQC) {"precache_pic", PF_Fixme, 0, 0, 0, 317, D("string(string name, optional float trywad)", "Forces the engine to load the named image. If trywad is specified, the specified name must any lack path and extension.")},// (EXT_CSQC) @@ -9642,6 +9559,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"drawstring", PF_Fixme, 0, 0, 0, 326, D("float(vector position, string text, vector size, vector rgb, float alpha, float drawflag)", "Draws a string, interpreting markup and recolouring as appropriate.")},// #326 {"stringwidth", PF_Fixme, 0, 0, 0, 327, D("float(string text, float usecolours, optional vector fontsize)", "Calculates the width of the screen in virtual pixels. If usecolours is 1, markup that does not affect the string width will be ignored. Will always be decoded as UTF-8 if UTF-8 is globally enabled.\nIf the char size is not specified, '8 8 0' will be assumed.")},// EXT_CSQC_'DARKPLACES' {"drawsubpic", PF_Fixme, 0, 0, 0, 328, D("void(vector pos, vector sz, string pic, vector srcpos, vector srcsz, vector rgb, float alpha, optional float drawflag)", "Draws a rescaled subsection of an image to the screen.")},// #328 EXT_CSQC_'DARKPLACES' + {"drawrotpic", PF_Fixme, 0, 0, 0, 0, D("void(vector pivot, vector mins, vector maxs, string pic, vector rgb, float alpha, float angle)", "Draws an image rotating at the pivot. To rotate in the center, use mins+maxs of half the size with mins negated. Angle is in degrees.")}, + {"drawrotsubpic", PF_Fixme, 0, 0, 0, 0, D("void(vector pivot, vector mins, vector maxs, string pic, vector txmin, vector txsize, vector rgb, vector alphaandangles)", "Overcomplicated draw function for over complicated people. Positions follow drawrotpic, while texture coords follow drawsubpic. Due to argument count limitations in builtins, the alpha value and angles are combined into separate fields of a vector (tip: use fteqcc's [alpha, angle] feature.")}, //330 {"getstati", PF_Fixme, 0, 0, 0, 330, D("float(float stnum)", "Retrieves the numerical value of the given EV_INTEGER or EV_ENTITY stat (converted to a float).")},// (EXT_CSQC) @@ -9653,8 +9572,9 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"modelnameforindex",PF_Fixme, 0, 0, 0, 334, D("string(float mdlindex)", "Retrieves the name of the model based upon a precache index. This can be used to reduce csqc network traffic by enabling model matching.")},// {"particleeffectnum",PF_sv_particleeffectnum,0,0,0, 335, D("float(string effectname)", "Precaches the named particle effect. If your effect name is of the form 'foo.bar' then particles/foo.cfg will be loaded by the client if foo.bar was not already defined.\nDifferent engines will have different particle systems, this specifies the QC API only.")},// (EXT_CSQC) - {"trailparticles", PF_sv_trailparticles,0, 0, 0, 336, D("void(float effectnum, entity ent, vector start, vector end)", "Draws the given effect between the two named points. If ent is not world, distances will be cached in the entity in order to avoid framerate dependancies. The entity is not otherwise used.")},// (EXT_CSQC), - {"pointparticles", PF_sv_pointparticles,0, 0, 0, 337, D("void(float effectnum, vector origin, optional vector dir, optional float count)", "Spawn a load of particles from the given effect at the given point traveling or aiming along the direction specified. The number of particles are scaled by the count argument.")},// (EXT_CSQC) + {"trailparticles", PF_sv_trailparticles,0,0, 0, 336, D("void(float effectnum, entity ent, vector start, vector end)", "Draws the given effect between the two named points. If ent is not world, distances will be cached in the entity in order to avoid framerate dependancies. The entity is not otherwise used.")},// (EXT_CSQC), +// {"trailparticles_dp",PF_sv_trailparticles,0,0, 0, 336, D("void(entity ent, float effectnum, vector start, vector end)", "DarkPlaces got the argument order wrong, and failed to fix it due to apathy.")},// (EXT_CSQC), + {"pointparticles", PF_sv_pointparticles,0,0, 0, 337, D("void(float effectnum, vector origin, optional vector dir, optional float count)", "Spawn a load of particles from the given effect at the given point traveling or aiming along the direction specified. The number of particles are scaled by the count argument.")},// (EXT_CSQC) {"cprint", PF_Fixme, 0, 0, 0, 338, D("void(string s, ...)", "Print into the center of the screen just as ssqc's centerprint would appear.")},//(EXT_CSQC) {"print", PF_print, 0, 0, 0, 339, D("void(string s, ...)", "Unconditionally print on the local system's console, even in ssqc (doesn't care about the value of the developer cvar).")},//(EXT_CSQC) @@ -9826,6 +9746,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"search_end", PF_search_end, 0, 0, 0, 445, "void(searchhandle handle)"}, {"search_getsize", PF_search_getsize, 0, 0, 0, 446, D("float(searchhandle handle)", "Retrieves the number of files that were found.")}, {"search_getfilename", PF_search_getfilename,0, 0, 0, 447, D("string(searchhandle handle, float num)", "Retrieves name of one of the files that was found by the initial search.")}, + {"search_getfilesize", PF_search_getfilesize,0, 0, 0, 0, D("float(searchhandle handle, float num)", "Retrieves the size of one of the files that was found by the initial search.")}, + {"search_getfilemtime", PF_search_getfilemtime,0,0, 0, 0, D("string(searchhandle handle, float num)", "Retrieves modification time of one of the files.")}, {"cvar_string", PF_cvar_string, 0, 0, 0, 448, "string(string cvarname)"},//DP_QC_CVAR_STRING {"findflags", PF_FindFlags, 0, 0, 0, 449, "entity(entity start, .float fld, float match)"},//DP_QC_FINDFLAGS {"findchainflags", PF_sv_findchainflags,0, 0, 0, 450, "entity(.float fld, float match)"},//DP_QC_FINDCHAINFLAGS @@ -9868,18 +9790,21 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"strreplace", PF_strreplace, 0, 0, 0, 484, "string(string search, string replace, string subject)"},//DP_QC_STRREPLACE {"strireplace", PF_strireplace, 0, 0, 0, 485, "string(string search, string replace, string subject)"},//DP_QC_STRREPLACE {"getsurfacepointattribute",PF_getsurfacepointattribute,0,0,0, 486, "vector(entity e, float s, float n, float a)"},//DP_QC_GETSURFACEPOINTATTRIBUTE - {"gecko_create", PF_gecko_create, 0, 0, 0, 487, "float(string name)"},//DP_GECKO_SUPPORT - {"gecko_destroy", PF_gecko_destroy, 0, 0, 0, 488, "void(string name)"},//DP_GECKO_SUPPORT - {"gecko_navigate", PF_gecko_navigate, 0, 0, 0, 489, "void(string name, string URI)"},//DP_GECKO_SUPPORT - {"gecko_keyevent", PF_gecko_keyevent, 0, 0, 0, 490, "float(string name, float key, float eventtype)"},//DP_GECKO_SUPPORT - {"gecko_mousemove", PF_gecko_mousemove, 0, 0, 0, 491, "void(string name, float x, float y)"},//DP_GECKO_SUPPORT - {"gecko_resize", PF_gecko_resize, 0, 0, 0, 492, "void(string name, float w, float h)"},//DP_GECKO_SUPPORT - {"gecko_get_texture_extent",PF_gecko_get_texture_extent,0,0,0, 493, "vector(string name)"},//DP_GECKO_SUPPORT + {"gecko_create", PF_Fixme, 0, 0, 0, 487, D("float(string name)", "Create a new 'browser tab' shader with the specified name that can then be drawn via drawpic. In order to function correctly, this builtin depends upon external plugins being available. Use gecko_navigate to navigate it to a page of your choosing.")},//DP_GECKO_SUPPORT + {"gecko_destroy", PF_Fixme, 0, 0, 0, 488, D("void(string name)", "Destroy a shader.")},//DP_GECKO_SUPPORT + {"gecko_navigate", PF_Fixme, 0, 0, 0, 489, D("void(string name, string URI)", "Sends a command to the media decoder attached to the specified shader. In the case of a browser decoder, this changes the url that the browser displays. 'cmd:[un]focus' will tell the decoder that it has focus.")},//DP_GECKO_SUPPORT + {"gecko_keyevent", PF_Fixme, 0, 0, 0, 490, D("float(string name, float key, float eventtype)", "Send a key event to a media decoder. This applies only to interactive decoders like browsers.")},//DP_GECKO_SUPPORT + {"gecko_mousemove", PF_Fixme, 0, 0, 0, 491, D("void(string name, float x, float y)", "Sets a media decoder shader's mouse position. Values should be 0-1.")},//DP_GECKO_SUPPORT + {"gecko_resize", PF_Fixme, 0, 0, 0, 492, D("void(string name, float w, float h)", "Request to resize a media decoder.")},//DP_GECKO_SUPPORT + {"gecko_get_texture_extent",PF_Fixme, 0, 0, 0, 493, D("vector(string name)", "Query a media decoder for its current pixel size.")},//DP_GECKO_SUPPORT +// {"media_getposition",PF_Fixme, 0, 0, 0, 0, D("vector(string name)", "Query a media decoder to for if its loaded, its time, and its duration.")}, {"crc16", PF_crc16, 0, 0, 0, 494, "float(float caseinsensitive, string s, ...)"},//DP_QC_CRC16 {"cvar_type", PF_cvar_type, 0, 0, 0, 495, "float(string name)"},//DP_QC_CVAR_TYPE - {"numentityfields", PF_numentityfields, 0, 0, 0, 496, "float()"},//DP_QC_ENTITYDATA - {"entityfieldname", PF_entityfieldname, 0, 0, 0, 497, "string(float fieldnum)"},//DP_QC_ENTITYDATA - {"entityfieldtype", PF_entityfieldtype, 0, 0, 0, 498, "float(float fieldnum)"},//DP_QC_ENTITYDATA + {"numentityfields", PF_numentityfields, 0, 0, 0, 496, D("float()", "Gives the number of named entity fields. Note that this is not the size of an entity, but rather just the number of unique names (ie: vectors use 4 names rather than 3).")},//DP_QC_ENTITYDATA + {"findentityfield", PF_findentityfield, 0, 0, 0, 0, D("float(string fieldname)", "Find a field index by name.")}, + {"entityfieldref", PF_entityfieldref, 0, 0, 0, 0, D(".__variant(float fieldnum)", "Returns a field value that can be directly used to read entity fields. Be sure to validate the type with entityfieldtype before using.")},//DP_QC_ENTITYDATA + {"entityfieldname", PF_entityfieldname, 0, 0, 0, 497, D("string(float fieldnum)", "Retrieves the name of the given entity field.")},//DP_QC_ENTITYDATA + {"entityfieldtype", PF_entityfieldtype, 0, 0, 0, 498, D("float(float fieldnum)", "Provides information about the type of the field specified by the field num. Returns one of the EV_ values.")},//DP_QC_ENTITYDATA {"getentityfieldstring",PF_getentityfieldstring,0,0, 0, 499, "string(float fieldnum, entity ent)"},//DP_QC_ENTITYDATA {"putentityfieldstring",PF_putentityfieldstring,0,0, 0, 500, "float(float fieldnum, entity ent, string s)"},//DP_QC_ENTITYDATA {"WritePicture", PF_WritePicture, 0, 0, 0, 501, D("void(float to, string s, float sz)", "Encodes the named image across the network as-is adhering to some size limit. In FTE, this simply writes the string and is equivelent to writestring and sz is ignored. WritePicture should be paired with ReadPicture in csqc.")},//DP_SV_WRITEPICTURE @@ -9899,7 +9824,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"tokenize_console",PF_tokenize_console,0, 0, 0, 514, "float(string str)"}, {"argv_start_index",PF_argv_start_index,0, 0, 0, 515, "float(float idx)"}, {"argv_end_index", PF_argv_end_index, 0, 0, 0, 516, "float(float idx)"}, - {"buf_cvarlist", PF_buf_cvarlist, 0, 0, 0, 517, "void(strbuf strbuf)"}, + {"buf_cvarlist", PF_buf_cvarlist, 0, 0, 0, 517, "void(strbuf strbuf, string pattern, string antipattern)"}, {"cvar_description",PF_cvar_description,0, 0, 0, 518, "string(string cvarname)"}, {"gettime", PF_gettime, 0, 0, 0, 519, "float(optional float timetype)"}, {"keynumtostring_omgwtf",PF_Fixme, 0, 0, 0, 520, "string(float keynum)"}, //excessive third version in dp's csqc. @@ -9928,7 +9853,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs // {"matchpattern", PF_Fixme, 0, 0, 0, 538, "float(string s, string pattern, float matchrule)"}, // {"undefined", PF_Fixme, 0, 0, 0, 539, ""}, -#ifdef USEODE +#ifdef USERBE {"physics_enable", PF_physics_enable, 0, 0, 0, 540, D("void(entity e, float physics_enabled)", "Enable or disable the physics attached to a MOVETYPE_PHYSICS entity. Entities which have been disabled in this way will stop taking so much cpu time.")}, {"physics_addforce",PF_physics_addforce,0, 0, 0, 541, D("void(entity e, vector force, vector relative_ofs)", "Apply some impulse directional force upon a MOVETYPE_PHYSICS entity.")}, {"physics_addtorque",PF_physics_addtorque,0, 0, 0, 542, D("void(entity e, vector torque)", "Apply some impulse rotational force upon a MOVETYPE_PHYSICS entity.")}, @@ -9987,14 +9912,102 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {NULL} }; +static void QCBUILTIN PF_Fixme (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int binum; + char fname[MAX_QPATH]; + int i; + qboolean printedheader = false; + + SV_EndRedirect(); + if (!prinst->GetBuiltinCallInfo(prinst, &binum, fname, sizeof(fname))) + { + binum = 0; + strcpy(fname, "?unknown?"); + } + + if (binum) + for (i = 0; BuiltinList[i].bifunc; i++) + { + if (BuiltinList[i].ebfsnum == binum) + { + if (!printedheader) + { + Con_Printf( "\n" + "Mod forgot to ensure support for builtin %i:%s\n" + "Please consult the extensionlist_ssqc command.\n" + "Possible builtins:\n", binum, fname); + printedheader = true; + } + Con_Printf("%s\n", BuiltinList[i].name); + } + } + + Con_Printf("\n"); + + if (progstype == PROG_QW) + prinst->RunError(prinst, "\nBuiltin %i:%s not implemented.\nMods designed for mvdsv may need pr_imitatemvdsv to be enabled.", binum, fname); + else + prinst->RunError(prinst, "\nBuiltin %i:%s not implemented.\nMod is not compatible.", binum, fname); + PR_BIError (prinst, "builtin not implemented"); +} +int PR_EnableEBFSBuiltin(const char *name, int binum) +{ + int i; + for (i = 0;BuiltinList[i].name;i++) + { + if (!strcmp(BuiltinList[i].name, name) && BuiltinList[i].bifunc != PF_Fixme) + { + if (!binum) + binum = BuiltinList[i].ebfsnum; + if (!pr_overridebuiltins.value) + { + if (pr_builtin[binum] != NULL && pr_builtin[binum] != PF_Fixme) + { + if (pr_builtin[binum] == BuiltinList[i].bifunc) //it is already this function. + return binum; + + return 0; //already used... ? + } + } + + pr_builtin[binum] = BuiltinList[i].bifunc; + + return binum; + } + } + + return 0; //not known +} + +static int PDECL PR_SSQC_MapNamedBuiltin(pubprogfuncs_t *progfuncs, int headercrc, const char *builtinname) +{ + int i, binum; + for (i = 0;BuiltinList[i].name;i++) + { + if (!strcmp(BuiltinList[i].name, builtinname) && BuiltinList[i].bifunc != PF_Fixme) + { + for (binum = sizeof(pr_builtin)/sizeof(pr_builtin[0]); --binum; ) + { + if (pr_builtin[binum] && pr_builtin[binum] != PF_Fixme && BuiltinList[i].bifunc) + continue; + pr_builtin[binum] = BuiltinList[i].bifunc; + return binum; + } + Con_Printf("No more builtin slots to allocate for %s\n", builtinname); + break; + } + } + Con_DPrintf("Unknown ssqc builtin: %s\n", builtinname); + return 0; +} + void PR_ResetBuiltins(progstype_t type) //fix all nulls to PF_FIXME and add any extras that have a big number. { int i; int builtincount[sizeof(pr_builtin)/sizeof(pr_builtin[0])]; - memset(pr_builtin, 0, sizeof(pr_builtin)); - if (type == PROG_QW) { for (i = 0; BuiltinList[i].name; i++) @@ -11145,6 +11158,9 @@ void PR_DumpPlatform_f(void) for (i = 0; i < QSG_Extensions_count; i++) { + if (!QSG_Extensions[i].name || *QSG_Extensions[i].name == '?' || *QSG_Extensions[i].name == '_') + continue; //FIXME! + if (QSG_Extensions[i].description) VFS_PRINTF(f, "#define %s /* %s */\n", QSG_Extensions[i].name, QSG_Extensions[i].description); else @@ -11308,6 +11324,8 @@ void PR_DumpPlatform_f(void) if (BuiltinList[i].bifunc != PF_Fixme && BuiltinList[i].bifunc != PF_Ignore) { + if (!idx) //no index is a dynamically linked builtin, and can thus be usable in any gamecode mode (so long as its ssqc anyway) + nd |= NQ|QW|H2; if (BuiltinList[i].ebfsnum == idx) nd |= NQ|QW; if (BuiltinList[i].nqnum == idx) @@ -11318,177 +11336,173 @@ void PR_DumpPlatform_f(void) nd |= H2; } - if (idx) - { - if (PR_CSQC_BuiltinValid(BuiltinList[i].name, idx)) - nd |= CS; + if (PR_CSQC_BuiltinValid(BuiltinList[i].name, idx)) + nd |= CS; #ifdef MENU_DAT - if (MP_BuiltinValid(BuiltinList[i].name, idx)) - nd |= MENU; + if (MP_BuiltinValid(BuiltinList[i].name, idx)) + nd |= MENU; #endif - - if (!nd) - { - /*no idea what its for*/ - BuiltinList[i].obsolete = true; - nd = d; /*don't switch ifdefs*/ - } - nd |= (~targ & ALL); - if (!(nd & targ)) - continue; - if ((nd&targ) != (d&targ)) - { - if (d != (ALL & ~targ)) - VFS_PRINTF(f, "#endif\n"); + + if (!nd) /*no idea what its for*/ + continue; + nd |= (~targ & ALL); + if (!(nd & targ)) + continue; + if ((nd&targ) != (d&targ)) + { + if (d != (ALL & ~targ)) + VFS_PRINTF(f, "#endif\n"); - if (((nd | (~targ)) & ALL) == ALL) - d = ALL & ~targ; - else - { - d = nd; - switch(d & (ALL & targ)) - { - case 0: - continue; - case QW: - VFS_PRINTF(f, "#if defined(QWSSQC)\n"); - break; - case NQ: - VFS_PRINTF(f, "#if defined(NQSSQC)\n"); - break; - case QW|NQ: - VFS_PRINTF(f, "#ifdef SSQC\n"); - break; - case CS: - VFS_PRINTF(f, "#ifdef CSQC\n"); - break; - case QW|CS: - VFS_PRINTF(f, "#if defined(CSQC) || defined(QWSSQC)\n"); - break; - case NQ|CS: - VFS_PRINTF(f, "#if defined(CSQC) || defined(NQSSQC)\n"); - break; - case NQ|CS|QW: - VFS_PRINTF(f, "#if defined(CSQC) || defined(SSQC)\n"); - break; - case MENU: - VFS_PRINTF(f, "#ifdef MENU\n"); - break; - case QW|MENU: - VFS_PRINTF(f, "#if defined(QWSSQC) || defined(MENU)\n"); - break; - case NQ|MENU: - VFS_PRINTF(f, "#if defined(NQSSQC) || defined(MENU)\n"); - break; - case QW|NQ|MENU: - VFS_PRINTF(f, "#if defined(SSQC) || defined(MENU)\n"); - break; - case CS|MENU: - VFS_PRINTF(f, "#if defined(CSQC) || defined(MENU)\n"); - break; - case QW|CS|MENU: - VFS_PRINTF(f, "#if defined(CSQC) || defined(QWSSQC) || defined(MENU)\n"); - break; - case NQ|CS|MENU: - VFS_PRINTF(f, "#if defined(CSQC) || defined(NQSSQC) || defined(MENU)\n"); - break; - case H2: - VFS_PRINTF(f, "#ifdef H2\n"); - break; - case H2|QW: - VFS_PRINTF(f, "#if defined(H2) || defined(QWSSQC)\n"); - break; - case H2|NQ: - VFS_PRINTF(f, "#if defined(H2) || defined(NQSSQC)\n"); - break; - case H2|QW|NQ: - VFS_PRINTF(f, "#if defined(H2) || defined(SSQC)\n"); - break; - case H2|CS: - VFS_PRINTF(f, "#if defined(H2) || defined(CSQC)\n"); - break; - case H2|QW|CS: - VFS_PRINTF(f, "#if defined(H2) || defined(CSQC) || defined(QWSSQC)\n"); - break; - case H2|NQ|CS: - VFS_PRINTF(f, "#if defined(H2) || defined(CSQC) || defined(NQSSQC)\n"); - break; - case H2|NQ|CS|QW: - VFS_PRINTF(f, "#if defined(H2) || defined(CSQC) || defined(SSQC)\n"); - break; - case H2|MENU: - VFS_PRINTF(f, "#if defined(H2) || defined(MENU)\n"); - break; - case H2|QW|MENU: - VFS_PRINTF(f, "#if defined(H2) || defined(QWSSQC) || defined(MENU)\n"); - break; - case H2|NQ|MENU: - VFS_PRINTF(f, "#if defined(H2) || defined(NQSSQC) || defined(MENU)\n"); - break; - case H2|QW|NQ|MENU: - VFS_PRINTF(f, "#if defined(H2) || defined(SSQC) || defined(MENU)\n"); - break; - case H2|CS|MENU: - VFS_PRINTF(f, "#if defined(H2) || defined(CSQC) || defined(MENU)\n"); - break; - case H2|QW|CS|MENU: - VFS_PRINTF(f, "#if defined(H2) || defined(CSQC) || defined(QWSSQC) || defined(MENU)\n"); - break; - case H2|NQ|CS|MENU: - VFS_PRINTF(f, "#if defined(H2) || defined(CSQC) || defined(NQSSQC) || defined(MENU)\n"); - break; - case ALL: - VFS_PRINTF(f, "#if 1\n"); - break; - default: - VFS_PRINTF(f, "#if 0 //???\n"); - break; - } - } - } - VFS_PRINTF(f, "%s%s %s = #%u;", BuiltinList[i].obsolete?"//":"", BuiltinList[i].prototype, BuiltinList[i].name, idx); - nd = 0; - for (j = 0; j < QSG_Extensions_count; j++) - { - for (k = 0; k < QSG_Extensions[j].numbuiltins; k++) - { - if (!strcmp(QSG_Extensions[j].builtinnames[k], BuiltinList[i].name)) - { - if (!nd) - VFS_PRINTF(f, " /* Part of "); - else - VFS_PRINTF(f, ", "); - nd++; - VFS_PRINTF(f, "%s", QSG_Extensions[j].name); - } - } - } - if (BuiltinList[i].biglongdesc) - { - char *line = BuiltinList[i].biglongdesc; - char *term; - if (!nd) - VFS_PRINTF(f, " /*"); - while(*line) - { - VFS_PRINTF(f, "\n\t\t"); - term = line; - while(*term && *term != '\n') - term++; - VFS_WRITE(f, line, term - line); - if (*term == '\n') - { - term++; - } - line = term; - } - VFS_PRINTF(f, " */\n\n"); - } - else if (nd) - VFS_PRINTF(f, "*/\n"); + if (((nd | (~targ)) & ALL) == ALL) + d = ALL & ~targ; else - VFS_PRINTF(f, "\n"); + { + d = nd; + switch(d & (ALL & targ)) + { + case 0: + continue; + case QW: + VFS_PRINTF(f, "#if defined(QWSSQC)\n"); + break; + case NQ: + VFS_PRINTF(f, "#if defined(NQSSQC)\n"); + break; + case QW|NQ: + VFS_PRINTF(f, "#ifdef SSQC\n"); + break; + case CS: + VFS_PRINTF(f, "#ifdef CSQC\n"); + break; + case QW|CS: + VFS_PRINTF(f, "#if defined(CSQC) || defined(QWSSQC)\n"); + break; + case NQ|CS: + VFS_PRINTF(f, "#if defined(CSQC) || defined(NQSSQC)\n"); + break; + case NQ|CS|QW: + VFS_PRINTF(f, "#if defined(CSQC) || defined(SSQC)\n"); + break; + case MENU: + VFS_PRINTF(f, "#ifdef MENU\n"); + break; + case QW|MENU: + VFS_PRINTF(f, "#if defined(QWSSQC) || defined(MENU)\n"); + break; + case NQ|MENU: + VFS_PRINTF(f, "#if defined(NQSSQC) || defined(MENU)\n"); + break; + case QW|NQ|MENU: + VFS_PRINTF(f, "#if defined(SSQC) || defined(MENU)\n"); + break; + case CS|MENU: + VFS_PRINTF(f, "#if defined(CSQC) || defined(MENU)\n"); + break; + case QW|CS|MENU: + VFS_PRINTF(f, "#if defined(CSQC) || defined(QWSSQC) || defined(MENU)\n"); + break; + case NQ|CS|MENU: + VFS_PRINTF(f, "#if defined(CSQC) || defined(NQSSQC) || defined(MENU)\n"); + break; + case H2: + VFS_PRINTF(f, "#ifdef H2\n"); + break; + case H2|QW: + VFS_PRINTF(f, "#if defined(H2) || defined(QWSSQC)\n"); + break; + case H2|NQ: + VFS_PRINTF(f, "#if defined(H2) || defined(NQSSQC)\n"); + break; + case H2|QW|NQ: + VFS_PRINTF(f, "#if defined(H2) || defined(SSQC)\n"); + break; + case H2|CS: + VFS_PRINTF(f, "#if defined(H2) || defined(CSQC)\n"); + break; + case H2|QW|CS: + VFS_PRINTF(f, "#if defined(H2) || defined(CSQC) || defined(QWSSQC)\n"); + break; + case H2|NQ|CS: + VFS_PRINTF(f, "#if defined(H2) || defined(CSQC) || defined(NQSSQC)\n"); + break; + case H2|NQ|CS|QW: + VFS_PRINTF(f, "#if defined(H2) || defined(CSQC) || defined(SSQC)\n"); + break; + case H2|MENU: + VFS_PRINTF(f, "#if defined(H2) || defined(MENU)\n"); + break; + case H2|QW|MENU: + VFS_PRINTF(f, "#if defined(H2) || defined(QWSSQC) || defined(MENU)\n"); + break; + case H2|NQ|MENU: + VFS_PRINTF(f, "#if defined(H2) || defined(NQSSQC) || defined(MENU)\n"); + break; + case H2|QW|NQ|MENU: + VFS_PRINTF(f, "#if defined(H2) || defined(SSQC) || defined(MENU)\n"); + break; + case H2|CS|MENU: + VFS_PRINTF(f, "#if defined(H2) || defined(CSQC) || defined(MENU)\n"); + break; + case H2|QW|CS|MENU: + VFS_PRINTF(f, "#if defined(H2) || defined(CSQC) || defined(QWSSQC) || defined(MENU)\n"); + break; + case H2|NQ|CS|MENU: + VFS_PRINTF(f, "#if defined(H2) || defined(CSQC) || defined(NQSSQC) || defined(MENU)\n"); + break; + case ALL: + VFS_PRINTF(f, "#if 1\n"); + break; + default: + VFS_PRINTF(f, "#if 0 //???\n"); + break; + } + } } + if (idx) + VFS_PRINTF(f, "%s%s %s = #%u;", BuiltinList[i].obsolete?"//":"", BuiltinList[i].prototype, BuiltinList[i].name, idx); + else + VFS_PRINTF(f, "%s%s %s = #%u/*:%s*/;", BuiltinList[i].obsolete?"//":"", BuiltinList[i].prototype, BuiltinList[i].name, idx, BuiltinList[i].name); + nd = 0; + for (j = 0; j < QSG_Extensions_count; j++) + { + for (k = 0; k < QSG_Extensions[j].numbuiltins; k++) + { + if (!strcmp(QSG_Extensions[j].builtinnames[k], BuiltinList[i].name)) + { + if (!nd) + VFS_PRINTF(f, " /* Part of "); + else + VFS_PRINTF(f, ", "); + nd++; + VFS_PRINTF(f, "%s", QSG_Extensions[j].name); + } + } + } + if (BuiltinList[i].biglongdesc) + { + char *line = BuiltinList[i].biglongdesc; + char *term; + if (!nd) + VFS_PRINTF(f, " /*"); + while(*line) + { + VFS_PRINTF(f, "\n\t\t"); + term = line; + while(*term && *term != '\n') + term++; + VFS_WRITE(f, line, term - line); + if (*term == '\n') + { + term++; + } + line = term; + } + VFS_PRINTF(f, " */\n\n"); + } + else if (nd) + VFS_PRINTF(f, "*/\n"); + else + VFS_PRINTF(f, "\n"); } if (d != (ALL & ~targ)) VFS_PRINTF(f, "#endif\n"); @@ -11504,8 +11518,8 @@ void PR_DumpPlatform_f(void) { VFS_PRINTF(f, "accessor strbuf : float\n{\n" - "\tget float asfloat[float idx] = {return stof(bufstr_get(this, idx));};\n" - "\tset float asfloat[float idx] = {bufstr_set(this, idx, ftos(value));};\n" + "\tinline get float asfloat[float idx] = {return stof(bufstr_get(this, idx));};\n" + "\tinline set float asfloat[float idx] = {bufstr_set(this, idx, ftos(value));};\n" "\tget string[float] = bufstr_get;\n" "\tset string[float] = bufstr_set;\n" "\tget float length = buf_getsize;\n" @@ -11517,23 +11531,26 @@ void PR_DumpPlatform_f(void) "};\n"); VFS_PRINTF(f, "accessor hashtable : float\n{\n" - "\tget vector v[string key] = {return hash_get(this, key, '0 0 0', EV_VECTOR);};\n" - "\tset vector v[string key] = {hash_add(this, key, value, 1, EV_VECTOR);};\n" - "\tget string s[string key] = {return hash_get(this, key, \"\", EV_STRING);};\n" - "\tset string s[string key] = {hash_add(this, key, value, 1, EV_STRING);};\n" - "\tget string f[string key] = {return hash_get(this, key, 0.0, EV_FLOAT);};\n" - "\tset string f[string key] = {hash_add(this, key, value, 1, EV_FLOAT);};\n" - "\tget __variant[string key] = {return hash_get(this, key, __NULL__);};\n" - "\tset __variant[string key] = {hash_add(this, key, value, 1);};\n" + "\tinline get vector v[string key] = {return hash_get(this, key, '0 0 0', EV_VECTOR);};\n" + "\tinline set vector v[string key] = {hash_add(this, key, value, 1, EV_VECTOR);};\n" + "\tinline get string s[string key] = {return hash_get(this, key, \"\", EV_STRING);};\n" + "\tinline set string s[string key] = {hash_add(this, key, value, 1, EV_STRING);};\n" + "\tinline get string f[string key] = {return hash_get(this, key, 0.0, EV_FLOAT);};\n" + "\tinline set string f[string key] = {hash_add(this, key, value, 1, EV_FLOAT);};\n" + "\tinline get __variant[string key] = {return hash_get(this, key, __NULL__);};\n" + "\tinline set __variant[string key] = {hash_add(this, key, value, 1);};\n" "};\n"); VFS_PRINTF(f, "accessor infostring : string\n{\n" "\tget string[string] = infoget;\n" +#ifdef QCGC + "\tinline set* string[string] = {(*this) = infoadd(*this, value);};\n" +#endif "};\n"); VFS_PRINTF(f, "accessor filestream : float\n{\n" "\tget string = fgets;\n" - "\tset string = {fputs(this,value);};\n" + "\tinline set string = {fputs(this,value);};\n" "};\n"); } diff --git a/engine/server/progdefs.h b/engine/server/progdefs.h index 1cda8fd6f..2a5a512a3 100644 --- a/engine/server/progdefs.h +++ b/engine/server/progdefs.h @@ -267,9 +267,13 @@ and the extension fields are added on the end and can have extra vm-specific stu #define csqcextfields \ comfieldfloat(entnum,"This is the number of the entity that the ssqc is using.") \ comfieldfloat(frame2,"This is typically the old frame of the entity. if lerpfrac is 1, .frame will be ignored and .frame2 will be used solely. lerpfrac 0.5 will give an even 50/50 blend.") /*EXT_CSQC_1*/\ + comfieldfloat(frame3,"Some people just don't understand how to use framegroups...") /**/\ + comfieldfloat(frame4,NULL) /**/\ comfieldfloat(frame1time,"This controls the time into the framegroup/animation named by .frame, you should increment this value according to frametime or to distance moved, depending on the sort of animation you're attempting. You may wish to avoid incrementing this while lerpfrac is still changing, to avoid wasting parts of the animation.") /*EXT_CSQC_1*/\ comfieldfloat(frame2time,".frame2 equivelent of frame1time.") /*EXT_CSQC_1*/\ comfieldfloat(lerpfrac,"The value 0 means the entity will animate using only .frame, which will be jerky. As this value is incremented, more of frame2 will be used. If you wish to use .frame2 as the 'old' frame, it is generally recommended to start this field with the value 1, to decrement it by frametime, and when it drops below 0 add 1 to it and update .frame2 and .frame to lerp into the new frame.") /*EXT_CSQC_1*/\ + comfieldfloat(lerpfrac3,NULL) /**/\ + comfieldfloat(lerpfrac4,NULL) /**/\ comfieldfloat(renderflags,NULL)\ comfieldfloat(forceshader,"Contains a shader handle used to replace all surfaces upon the entity.")/*FTE_CSQC_SHADERS*/\ \ @@ -365,12 +369,12 @@ comextqcfields } comentvars_t; #endif -#ifdef USEODE +#ifdef USERBE typedef struct { - void *ode_body; - void *ode_geom; -} odebody_t; + void *body; + void *geom; +} rbebody_t; typedef struct { //doll info @@ -385,12 +389,12 @@ typedef struct int geomshape; vec3_t dimensions; float mass; -} odebodyinfo_t; +} rbebodyinfo_t; typedef struct { - void *ode_joint; -} odejoint_t; + void *joint; +} rbejoint_t; typedef struct { //doll info @@ -412,24 +416,24 @@ typedef struct float Vel, Vel2; vec3_t offset, offset2; vec3_t axis, axis2; -} odejointinfo_t; +} rbejointinfo_t; -enum odecommands_e +enum rbecommands_e { - ODECMD_ENABLE, - ODECMD_DISABLE, - ODECMD_FORCE, - ODECMD_TORQUE, + RBECMD_ENABLE, + RBECMD_DISABLE, + RBECMD_FORCE, + RBECMD_TORQUE, }; -typedef struct odecommandqueue_s +typedef struct rbecommandqueue_s { - struct odecommandqueue_s *next; - enum odecommands_e command; + struct rbecommandqueue_s *next; + enum rbecommands_e command; struct wedict_s *edict; vec3_t v1; vec3_t v2; -} odecommandqueue_t; +} rbecommandqueue_t; typedef struct { @@ -473,23 +477,4 @@ typedef struct int dummy; } skeljointode_t; */ -typedef struct -{ - // for ODE physics engine - qboolean ode; // if true then ode is activated - qboolean hasodeents; // if true then we have some ode body somewhere, and we consume more cycles processing full physics, instead of trying to skip as much as we can - qboolean hasextraobjs; - void *ode_world; - void *ode_space; - void *ode_contactgroup; - // number of constraint solver iterations to use (for dWorldStepFast) - int ode_iterations; - // actual step (server frametime / ode_iterations) - vec_t ode_step; - // max velocity for a 1-unit radius object at current step to prevent - // missed collisions - vec_t ode_movelimit; - odecommandqueue_t *cmdqueuehead; - odecommandqueue_t *cmdqueuetail; -} worldode_t; #endif diff --git a/engine/server/progs.h b/engine/server/progs.h index dd9523845..b44b8a947 100644 --- a/engine/server/progs.h +++ b/engine/server/progs.h @@ -82,7 +82,7 @@ typedef struct edict_s /*these are shared with csqc*/ link_t area; pvscache_t pvsinfo; -#ifdef USEODE +#ifdef USERBE entityode_t ode; #endif qbyte solidtype; diff --git a/engine/server/savegame.c b/engine/server/savegame.c index f6dd98174..fb01f293b 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -981,7 +981,7 @@ void SV_SaveLevelCache(char *savedir, qboolean dontharmgame) for (i=0 ; ientnum, true, client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS); @@ -423,7 +423,7 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) if (!writtenheader) { writtenheader=true; - MSG_WriteByte(msg, svcfte_csqcentities); + MSG_WriteByte(msg, ISDPCLIENT(client)?svcdp_csqcentities:svcfte_csqcentities); } // Con_Printf("Sending remove packet %i\n", en); @@ -808,7 +808,8 @@ void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, #define UF_MOVETYPE UF_EFFECTS2 /*this flag isn't present in the header itself*/ #define UF_RESET2 UF_EXTEND1 /*so new ents are reset 3 times to avoid weird baselines*/ #define UF_UNUSED UF_EXTEND2 /**/ -#define UF_WEAPONFRAME UF_EXTEND3 +#define UF_WEAPONFRAME_OLD UF_EXTEND3 +#define UF_VIEWANGLES UF_EXTEND3 /**/ static unsigned int SVFTE_DeltaPredCalcBits(entity_state_t *from, entity_state_t *to) { @@ -841,7 +842,7 @@ static unsigned int SVFTE_DeltaCalcBits(entity_state_t *from, entity_state_t *to if (from->u.q1.pmovetype != to->u.q1.pmovetype) bits |= UF_PREDINFO|UF_MOVETYPE; if (from->u.q1.weaponframe != to->u.q1.weaponframe) - bits |= UF_PREDINFO|UF_WEAPONFRAME; + bits |= UF_PREDINFO|UF_WEAPONFRAME_OLD; if (to->u.q1.pmovetype) { if (SVFTE_DeltaPredCalcBits(from, to)) @@ -924,7 +925,7 @@ static unsigned int SVFTE_DeltaCalcBits(entity_state_t *from, entity_state_t *to return bits; } -static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_t *msg) +static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_t *msg, unsigned int pext2) { unsigned int predbits = 0; if (bits & UF_MOVETYPE) @@ -932,10 +933,22 @@ static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_ bits &= ~UF_MOVETYPE; predbits |= UFP_MOVETYPE; } - if (bits & UF_WEAPONFRAME) + if (pext2 & PEXT2_PREDINFO) { - bits &= ~UF_WEAPONFRAME; - predbits |= UFP_WEAPONFRAME; + if (bits & UF_VIEWANGLES) + { + bits &= ~UF_VIEWANGLES; + bits |= UF_PREDINFO; + predbits |= UFP_VIEWANGLE; + } + } + else + { + if (bits & UF_WEAPONFRAME_OLD) + { + bits &= ~UF_WEAPONFRAME_OLD; + predbits |= UFP_WEAPONFRAME_OLD; + } } /*check if we need more precision*/ @@ -984,7 +997,7 @@ static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_ if (bits & UF_ORIGINZ) MSG_WriteCoord(msg, state->origin[2]); - if (bits & UF_PREDINFO) + if ((bits & UF_PREDINFO) && !(pext2 & PEXT2_PREDINFO)) { /*if we have pred info, use more precise angles*/ if (bits & UF_ANGLESXZ) { @@ -1035,15 +1048,31 @@ static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_ MSG_WriteShort(msg, state->u.q1.velocity[2]); if (predbits & UFP_MSEC) MSG_WriteByte(msg, state->u.q1.msec); - if (predbits & UFP_WEAPONFRAME) + if (pext2 & PEXT2_PREDINFO) { - if (state->u.q1.weaponframe > 127) - { - MSG_WriteByte(msg, 128 | (state->u.q1.weaponframe & 127)); - MSG_WriteByte(msg, state->u.q1.weaponframe>>7); + if (predbits & UFP_VIEWANGLE) + { /*if we have pred info, use more precise angles*/ + if (bits & UF_ANGLESXZ) + { + MSG_WriteShort(msg, state->u.q1.vangle[0]); + MSG_WriteShort(msg, state->u.q1.vangle[2]); + } + if (bits & UF_ANGLESY) + MSG_WriteShort(msg, state->u.q1.vangle[1]); + } + } + else + { + if (predbits & UFP_WEAPONFRAME_OLD) + { + if (state->u.q1.weaponframe > 127) + { + MSG_WriteByte(msg, 128 | (state->u.q1.weaponframe & 127)); + MSG_WriteByte(msg, state->u.q1.weaponframe>>7); + } + else + MSG_WriteByte(msg, state->u.q1.weaponframe); } - else - MSG_WriteByte(msg, state->u.q1.weaponframe); } } @@ -1133,13 +1162,13 @@ static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_ } /*dump out the delta from baseline (used for baselines and statics, so has no svc)*/ -void SVFTE_EmitBaseline(entity_state_t *to, qboolean numberisimportant, sizebuf_t *msg) +void SVFTE_EmitBaseline(entity_state_t *to, qboolean numberisimportant, sizebuf_t *msg, client_t *client) { unsigned int bits; if (numberisimportant) MSG_WriteEntity(msg, to->number); bits = UF_RESET | SVFTE_DeltaCalcBits(&nullentitystate, to); - SVFTE_WriteUpdate(bits, to, msg); + SVFTE_WriteUpdate(bits, to, msg, client->fteprotocolextensions2); } /*SVFTE_EmitPacketEntities @@ -1232,10 +1261,22 @@ void SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizebuf_t //even if prediction is disabled, we want to force velocity info to be sent for the local player. This is used by view bob and things. if (client->edict && j == client->edict->entnum && (n->u.q1.velocity[0] || n->u.q1.velocity[1] || n->u.q1.velocity[2])) client->pendingentbits[j] |= UF_PREDINFO; + + //spectators(and mvds) should be told the actual view angles of the person they're trying to track + if (j <= sv.allocated_client_slots && (!client->edict || j == client->spec_track)) +// if (client->pendingentbits[j]) + { + if (o->u.q1.vangle[0] != n->u.q1.vangle[0] || o->u.q1.vangle[2] != n->u.q1.vangle[2]) + client->pendingentbits[j] |= UF_ANGLESXZ; + if (o->u.q1.vangle[1] != n->u.q1.vangle[1]) + client->pendingentbits[j] |= UF_ANGLESY; + client->pendingentbits[j] |= UF_VIEWANGLES; + } } *o = *n; j++; } + /*gaps are dead entities*/ for (; j < client->sentents.num_entities; j++) { @@ -1312,7 +1353,7 @@ void SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizebuf_t resendbits[outno] = bits; SV_EmitDeltaEntIndex(msg, j, false, true); - SVFTE_WriteUpdate(bits, &client->sentents.entities[j], msg); + SVFTE_WriteUpdate(bits, &client->sentents.entities[j], msg, client->fteprotocolextensions2); } resendnum[outno++] = j; } @@ -2902,7 +2943,7 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli if ((state->number-1) < (unsigned int)sv.allocated_client_slots && (client == &svs.clients[state->number-1] || client == svs.clients[state->number-1].controller || (client && (!client->edict || client->spec_track == state->number)))) if (!client || !(client->fteprotocolextensions2 & PEXT2_PREDINFO)) state->u.q1.weaponframe = ent->v->weaponframe; - if ((state->number-1) < (unsigned int)sv.allocated_client_slots && ent->v->movetype) + if ((state->number-1) < (unsigned int)sv.allocated_client_slots && ent->v->movetype && client) { client_t *cl = &svs.clients[state->number-1]; if (cl->isindependant) @@ -2928,12 +2969,21 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli } //fixme: deal with fixangles - if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) - if (state->u.q1.pmovetype && (state->u.q1.pmovetype != MOVETYPE_TOSS && state->u.q1.pmovetype != MOVETYPE_BOUNCE)) + if (client->fteprotocolextensions2 & PEXT2_PREDINFO) { - state->angles[0] = ent->v->v_angle[0]/-3.0; - state->angles[1] = ent->v->v_angle[1]; - state->angles[2] = ent->v->v_angle[2]; + state->u.q1.vangle[0] = ANGLE2SHORT(ent->v->v_angle[0]); + state->u.q1.vangle[1] = ANGLE2SHORT(ent->v->v_angle[1]); + state->u.q1.vangle[2] = ANGLE2SHORT(ent->v->v_angle[2]); + } + else + { + if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) + if (state->u.q1.pmovetype && (state->u.q1.pmovetype != MOVETYPE_TOSS && state->u.q1.pmovetype != MOVETYPE_BOUNCE)) + { + state->angles[0] = ent->v->v_angle[0]/-3.0; + state->angles[1] = ent->v->v_angle[1]; + state->angles[2] = ent->v->v_angle[2]; + } } } diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index b1997ff96..76c1df03e 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -626,6 +626,7 @@ void SV_UnspawnServer (void) //terminate the running server. svs.allocated_client_slots = 0; SV_FlushLevelCache(); NET_CloseServer (); + SV_RunCmdCleanup(); } void SV_UpdateMaxPlayers(int newmax) @@ -1343,6 +1344,8 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us ent->v->modelindex = 1; // world model ent->v->solid = SOLID_BSP; ent->v->movetype = MOVETYPE_PUSH; + VectorCopy(sv.world.worldmodel->mins, ent->v->mins); + VectorCopy(sv.world.worldmodel->maxs, ent->v->maxs); if (progstype == PROG_QW && pr_imitatemvdsv.value>0) { diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 815ec5f9d..35350c2ff 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -215,10 +215,6 @@ void SV_Shutdown (void) SV_UnspawnServer(); -#ifdef USEODE - World_ODE_Shutdown(); -#endif - if (sv.mvdrecording) SV_MVDStop (0, false); @@ -397,6 +393,7 @@ or crashing. */ void SV_DropClient (client_t *drop) { + unsigned int i; laggedpacket_t *lp; sizebuf_t termmsg; char termbuf[64]; @@ -618,6 +615,12 @@ void SV_DropClient (client_t *drop) memset(&drop->sentents.entities, 0, sizeof(drop->sentents.entities)); } + for (i = 0; i < MAX_CL_STATS; i++) + { + Z_Free(drop->statss[i]); + drop->statss[i] = NULL; + } + if (drop->csqcentversions) Z_Free(drop->csqcentversions); drop->csqcentversions = NULL; @@ -4946,10 +4949,6 @@ void SV_Init (quakeparms_t *parms) SV_Demo_Init(); #endif -#ifdef USEODE - World_ODE_Init(); -#endif - #ifdef SVRANKING Rank_RegisterCommands(); #endif diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index ab1792fdc..76a02db44 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -682,7 +682,7 @@ typedef struct #define SORT_NO 0 #define SORT_BY_DATE 1 -int QDECL Sys_listdirFound(const char *fname, qofs_t fsize, void *uptr, searchpathfuncs_t *spath) +int QDECL Sys_listdirFound(const char *fname, qofs_t fsize, time_t mtime, void *uptr, searchpathfuncs_t *spath) { file_t *f; dir_t *dir = uptr; diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index e5d997b62..420b93b5d 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -2150,13 +2150,13 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent) #endif break; +#ifdef USERBE case MOVETYPE_PHYSICS: if (WPhys_RunThink(w, ent)) World_LinkEdict (w, ent, true); -#ifdef USEODE - w->ode.hasodeents = true; -#endif + w->rbe_hasphysicsents = true; break; +#endif default: // SV_Error ("SV_Physics: bad movetype %i on %s", (int)ent->v->movetype, PR_GetString(w->progs, ent->v->classname)); break; @@ -2309,7 +2309,7 @@ void World_Physics_Frame(world_t *w) { if (!svs.clients[i-1].isindependant) { - if (sv_nqplayerphysics.ival || svs.clients[i-1].state < cs_spawned) + if (sv_nqplayerphysics.ival || SV_PlayerPhysicsQC || svs.clients[i-1].state < cs_spawned) { WPhys_RunEntity (w, ent); WPhys_RunNewmis (w); @@ -2503,8 +2503,14 @@ qboolean SV_Physics (void) PRSV_RunThreads(); -#ifdef USEODE - World_ODE_Frame(&sv.world, host_frametime, sv_gravity.value); +#ifdef USERBE + if (sv.world.rbe) + { +#ifdef RAGDOLL + rag_doallanimations(&sv.world); +#endif + sv.world.rbe->Frame(&sv.world, host_frametime, sv_gravity.value); + } #endif diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 483192e55..cb1853af0 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -1882,9 +1882,10 @@ void SV_UpdateClientStats (client_t *client, int pnum, sizebuf_t *msg, client_fr n = ""; if (strcmp(o, n)) client->pendingstats[(i+MAX_CL_STATS)>>5u] |= 1u<<((i+MAX_CL_STATS)&0x1f); + //FIXME: we could always just run the QCGC on the player's string stats too. wouldn't need string compares that way if (client->statss) Z_Free(client->statss[i]); - client->statss[i] = Z_StrDup(statss[i]); + client->statss[i] = (statss[i]&&*statss[i])?Z_StrDup(statss[i]):NULL; } } @@ -1926,7 +1927,7 @@ void SV_UpdateClientStats (client_t *client, int pnum, sizebuf_t *msg, client_fr MSG_WriteByte(msg, svcfte_choosesplitclient); MSG_WriteByte(msg, pnum); } - MSG_WriteByte(msg, svcqw_updatestatbyte); + MSG_WriteByte(msg, ISNQCLIENT(client)?svcdp_updatestatbyte:svcqw_updatestatbyte); MSG_WriteByte(msg, i); MSG_WriteByte(msg, ival); } @@ -1937,7 +1938,7 @@ void SV_UpdateClientStats (client_t *client, int pnum, sizebuf_t *msg, client_fr MSG_WriteByte(msg, svcfte_choosesplitclient); MSG_WriteByte(msg, pnum); } - MSG_WriteByte(msg, svcqw_updatestatlong); + MSG_WriteByte(msg, ISNQCLIENT(client)?svcnq_updatestatlong:svcqw_updatestatlong); MSG_WriteByte(msg, i); MSG_WriteLong(msg, ival); } @@ -2137,7 +2138,7 @@ void SV_UpdateClientStats (client_t *client, int pnum, sizebuf_t *msg, client_fr qboolean SV_CanTrack(client_t *client, int entity) { - if (entity < 0 || entity > sv.allocated_client_slots || svs.clients[entity-1].state != cs_spawned || svs.clients[entity-1].spectator) + if (entity < 0 || entity >= sv.allocated_client_slots || svs.clients[entity-1].state != cs_spawned || svs.clients[entity-1].spectator) return false; return true; } @@ -2561,9 +2562,9 @@ void SV_UpdateToReliableMessages (void) SV_FlushBroadcasts(); } -#ifdef _MSC_VER -#pragma optimize( "", off ) -#endif +//#ifdef _MSC_VER +//#pragma optimize( "", off ) +//#endif @@ -2827,9 +2828,9 @@ void SV_SendClientMessages (void) SV_CleanupEnts(); } -#ifdef _MSC_VER -#pragma optimize( "", on ) -#endif +//#ifdef _MSC_VER +//#pragma optimize( "", on ) +//#endif void SV_WriteMVDMessage (sizebuf_t *msg, int type, int to, float time); diff --git a/engine/server/sv_sys_unix.c b/engine/server/sv_sys_unix.c index 20894c574..2785bd837 100644 --- a/engine/server/sv_sys_unix.c +++ b/engine/server/sv_sys_unix.c @@ -746,7 +746,7 @@ int main(int argc, char *argv[]) -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { DIR *dir; char apath[MAX_OSPATH]; @@ -804,7 +804,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const { Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":""); - if (!func(file, st.st_size, parm, spath)) + if (!func(file, st.st_size, st.st_mtime, parm, spath)) { closedir(dir); return false; diff --git a/engine/server/sv_sys_win.c b/engine/server/sv_sys_win.c index 7c6bc6b35..fd1762828 100644 --- a/engine/server/sv_sys_win.c +++ b/engine/server/sv_sys_win.c @@ -499,7 +499,15 @@ qboolean Sys_Rename (char *oldfname, char *newfname) return !rename(oldfname, newfname); } -static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) +static time_t Sys_FileTimeToTime(FILETIME ft) +{ + ULARGE_INTEGER ull; + ull.LowPart = ft.dwLowDateTime; + ull.HighPart = ft.dwHighDateTime; + return ull.QuadPart / 10000000ULL - 11644473600ULL; +} + +static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) { qboolean go; if (!WinNT) @@ -587,7 +595,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(fd.cFileName) + 2 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s/", tmproot+matchstart, fd.cFileName); - go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), Sys_FileTimeToTime(fd.ftLastWriteTime), parm, spath); } } } @@ -598,7 +606,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(fd.cFileName) + 1 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s", tmproot+matchstart, fd.cFileName); - go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), Sys_FileTimeToTime(fd.ftLastWriteTime), parm, spath); } } } @@ -702,7 +710,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(utf8) + 2 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s/", tmproot+matchstart, utf8); - go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), Sys_FileTimeToTime(fd.ftLastWriteTime), parm, spath); } } } @@ -713,7 +721,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(utf8) + 1 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s", tmproot+matchstart, utf8); - go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), Sys_FileTimeToTime(fd.ftLastWriteTime), parm, spath); } } } @@ -723,7 +731,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart } return go; } -int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) { char fullmatch[MAX_OSPATH]; int start; diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 43a883d58..4408c129c 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -119,11 +119,6 @@ extern char cvargroup_servercontrol[]; extern cvar_t pausable; - -void SV_PreRunCmd(void); -void SV_RunCmd (usercmd_t *ucmd, qboolean recurse); -void SV_PostRunCmd(void); - /* ============================================================ @@ -1264,7 +1259,7 @@ void SV_SendClientPrespawnInfo(client_t *client) if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) { MSG_WriteByte(&client->netchan.message, svcfte_spawnstatic2); - SVFTE_EmitBaseline(state, false, &client->netchan.message); + SVFTE_EmitBaseline(state, false, &client->netchan.message, client); continue; } if (client->fteprotocolextensions & PEXT_SPAWNSTATIC2) @@ -1329,7 +1324,7 @@ void SV_SendClientPrespawnInfo(client_t *client) else if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) { MSG_WriteByte(&client->netchan.message, svcfte_spawnbaseline2); - SVFTE_EmitBaseline(state, true, &client->netchan.message); + SVFTE_EmitBaseline(state, true, &client->netchan.message, client); } else if (client->fteprotocolextensions & PEXT_SPAWNSTATIC2) { @@ -1391,9 +1386,9 @@ void SV_SendClientPrespawnInfo(client_t *client) MSG_WriteByte (&client->netchan.message, 0); //invalid modelindex. at least try to give something else MSG_WriteByte (&client->netchan.message, state->modelindex); - MSG_WriteByte (&client->netchan.message, state->frame&255); - MSG_WriteByte (&client->netchan.message, (int)state->colormap); - MSG_WriteByte (&client->netchan.message, (int)state->skinnum); + MSG_WriteByte (&client->netchan.message, state->frame & 0xff); + MSG_WriteByte (&client->netchan.message, state->colormap & 0xff); + MSG_WriteByte (&client->netchan.message, state->skinnum & 0xff); for (i=0 ; i<3 ; i++) { MSG_WriteCoord(&client->netchan.message, state->origin[i]); @@ -5844,11 +5839,25 @@ SV_PreRunCmd =========== Done before running a player command. Clears the touch array */ -qbyte playertouch[(MAX_EDICTS+7)/8]; +qbyte *playertouch; +size_t playertouchmax; void SV_PreRunCmd(void) { - memset(playertouch, 0, sizeof(playertouch)); + size_t max = MAX_EDICTS;//(sv.world.num_edicts+7)&~7; + if (max > playertouchmax) + { + playertouchmax = max; + BZ_Free(playertouch); + playertouch = BZ_Malloc((playertouchmax>>3)+1); + } + memset(playertouch, 0, playertouchmax>>3); +} +void SV_RunCmdCleanup(void) +{ + BZ_Free(playertouch); + playertouch = NULL; + playertouchmax = 0; } /* @@ -5862,9 +5871,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse) edict_t *ent; int i, n; int oldmsec; - double tmp_time; qboolean jumpable; - char adr[MAX_ADR_SIZE]; vec3_t new_vel; vec3_t old_vel; @@ -5892,6 +5899,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse) if ((tmp_time = realtime - host_client->last_check) >= sv_cheatspeedchecktime.value) { + double tmp_time; tmp_time = tmp_time * 1000.0 * sv_cheatpc.value/100.0; if (host_client->msecs > tmp_time && isPlugin < 2) //debugging can result in WEIRD timings, so don't warn about weird timings if we're likely to get blocked out for long periods @@ -5904,6 +5912,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse) if (host_client->msec_cheating >= 2) { + char adr[MAX_ADR_SIZE]; SV_BroadcastTPrintf(PRINT_HIGH, "%s was kicked for speedcheating (%s)\n", host_client->name, NET_AdrToString(adr, sizeof(adr), &host_client->netchan.remote_address)); @@ -6370,8 +6379,10 @@ if (sv_player->v->health > 0 && before && !after ) continue; n = pmove.physents[pmove.touchindex[i]].info; ent = EDICT_NUM(svprogfuncs, n); - if (playertouch[n/8]&(1<<(n%8))) + + if (n >= playertouchmax || playertouch[n>>3]&(1<<(n&7))) continue; + playertouch[n>>3] |= 1 << (n&7); if (ent->v->touch) { @@ -6382,7 +6393,6 @@ if (sv_player->v->health > 0 && before && !after ) } sv.world.Event_Touch(&sv.world, (wedict_t*)ent, (wedict_t*)sv_player); } - playertouch[n/8] |= 1 << (n%8); if (sv_player->v->touch && !ent->isfree) sv.world.Event_Touch(&sv.world, (wedict_t*)sv_player, (wedict_t*)ent); @@ -7121,7 +7131,7 @@ void SVNQ_ReadClientMove (usercmd_t *move) timesincelast = cltime - move->fservertime; move->fservertime = cltime; - move->servertime = move->fservertime; + move->servertime = move->fservertime*1000; frame->ping_time = sv.time - cltime; diff --git a/engine/server/svq2_game.c b/engine/server/svq2_game.c index b9b6346ef..9f69fd5e2 100644 --- a/engine/server/svq2_game.c +++ b/engine/server/svq2_game.c @@ -746,6 +746,11 @@ void SVQ2_InitWorld(void) sv.world.Get_CModel = SVQ2_GetCModel; } +static void QDECL PFQ2_SetAreaPortalState(unsigned int p, qboolean s) +{ + CMQ2_SetAreaPortalState(sv.world.worldmodel, p, s); +} + qboolean SVQ2_InitGameProgs(void) { extern cvar_t maxclients; @@ -820,7 +825,7 @@ qboolean SVQ2_InitGameProgs(void) import.AddCommandString = AddCommandString; import.DebugGraph = Q2SCR_DebugGraph; - import.SetAreaPortalState = CMQ2_SetAreaPortalState; + import.SetAreaPortalState = PFQ2_SetAreaPortalState; import.AreasConnected = PFQ2_AreasConnected; if (sv.world.worldmodel && (sv.world.worldmodel->fromgame == fg_quake || sv.world.worldmodel->fromgame == fg_halflife)) diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index d53aa793e..2b2024a08 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -757,7 +757,7 @@ static void SVQ3_Adjust_Area_Portal_State(q3sharedEntity_t *ge, qboolean open) q3serverEntity_t *se = SENTITY_FOR_GENTITY(ge); if (se->areanum == -1 || se->areanum2 == -1) //not linked properly. return; - CMQ3_SetAreaPortalState(se->areanum, se->areanum2, open); + CMQ3_SetAreaPortalState(sv.world.worldmodel, se->areanum, se->areanum2, open); } #define VALIDATEPOINTER(o,l) if ((int)o + l >= mask || VM_POINTER(o) < offset) SV_Error("Call to game trap %u passes invalid pointer\n", (unsigned int)fn); //out of bounds. diff --git a/engine/server/world.c b/engine/server/world.c index 425c96924..3ffd93aeb 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -450,7 +450,7 @@ SV_LinkEdict =============== */ -void World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers) +void QDECL World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers) { areanode_t *node; @@ -2080,4 +2080,273 @@ trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t } #endif +static void (QDECL *world_current_physics_engine)(world_t*world); +qboolean QDECL World_RegisterPhysicsEngine(const char *enginename, void(QDECL*startupfunc)(world_t*world)) +{ + if (world_current_physics_engine) + return false; //no thanks, we already have one. + world_current_physics_engine = startupfunc; + return true; +} +void QDECL World_ShutdownPhysics(world_t *world) +{ + unsigned int u; + wedict_t *ed; + if (!world->rbe) + return; + + for (u = 0; u < world->num_edicts; u++) + { + ed = WEDICT_NUM(world->progs, u); + world->rbe->RemoveJointFromEntity(world, ed); + world->rbe->RemoveFromEntity(world, ed); + } + world->rbe->End(world); +} +void QDECL World_UnregisterPhysicsEngine(const char *enginename) +{ +#ifdef RAGDOLL +// rag_uninstanciateall(); +#endif + +#if defined(CSQC_DAT) && !defined(SERVERONLY) + { + extern world_t csqc_world; + World_ShutdownPhysics(&csqc_world); + } +#endif +#if !defined(CLIENTONLY) + World_ShutdownPhysics(&sv.world); +#endif + + world_current_physics_engine = NULL; +} +void World_RBE_Start(world_t *world) +{ + if (world_current_physics_engine) + world_current_physics_engine(world); +} + + +#ifdef USERBE +static qboolean GenerateCollisionMesh_BSP(world_t *world, model_t *mod, wedict_t *ed, vec3_t geomcenter) +{ + unsigned int sno; + msurface_t *surf; + mesh_t *mesh; + unsigned int numverts; + unsigned int numindexes,i; + + numverts = 0; + numindexes = 0; + for (sno = 0; sno < mod->nummodelsurfaces; sno++) + { + surf = &mod->surfaces[sno+mod->firstmodelsurface]; + if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) + continue; + + if (surf->mesh) + { + mesh = surf->mesh; + numverts += mesh->numvertexes; + numindexes += mesh->numindexes; + } + else + { + numverts += surf->numedges; + numindexes += (surf->numedges-2) * 3; + } + } + if (!numindexes) + { + Con_DPrintf("entity %i (classname %s) has no geometry\n", NUM_FOR_EDICT(world->progs, (edict_t*)ed), PR_GetString(world->progs, ed->v->classname)); + return false; + } + ed->ode.ode_element3i = (int*)BZ_Malloc(numindexes*sizeof(*ed->ode.ode_element3i)); + ed->ode.ode_vertex3f = (float*)BZ_Malloc(numverts*sizeof(vec3_t)); + + numverts = 0; + numindexes = 0; + for (sno = 0; sno < mod->nummodelsurfaces; sno++) + { + surf = &mod->surfaces[sno+mod->firstmodelsurface]; + if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) + continue; + + if (surf->mesh) + { + mesh = surf->mesh; + for (i = 0; i < mesh->numvertexes; i++) + VectorSubtract(mesh->xyz_array[i], geomcenter, (ed->ode.ode_vertex3f + 3*(numverts+i))); + for (i = 0; i < mesh->numindexes; i+=3) + { + //flip the triangles as we go + ed->ode.ode_element3i[numindexes+i+0] = numverts+mesh->indexes[i+2]; + ed->ode.ode_element3i[numindexes+i+1] = numverts+mesh->indexes[i+1]; + ed->ode.ode_element3i[numindexes+i+2] = numverts+mesh->indexes[i+0]; + } + numverts += mesh->numvertexes; + numindexes += i; + } + else + { + float *vec; + medge_t *edge; + int lindex; + for (i = 0; i < surf->numedges; i++) + { + lindex = mod->surfedges[surf->firstedge + i]; + + if (lindex > 0) + { + edge = &mod->edges[lindex]; + vec = mod->vertexes[edge->v[0]].position; + } + else + { + edge = &mod->edges[-lindex]; + vec = mod->vertexes[edge->v[1]].position; + } + + VectorSubtract(vec, geomcenter, (ed->ode.ode_vertex3f + 3*(numverts+i))); + } + for (i = 2; i < surf->numedges; i++) + { + //quake is backwards, not ode + ed->ode.ode_element3i[numindexes++] = numverts+i; + ed->ode.ode_element3i[numindexes++] = numverts+i-1; + ed->ode.ode_element3i[numindexes++] = numverts; + } + numverts += surf->numedges; + } + } + + ed->ode.ode_numvertices = numverts; + ed->ode.ode_numtriangles = numindexes/3; + return true; +} + +#include "com_mesh.h" +static qboolean GenerateCollisionMesh_Alias(world_t *world, model_t *mod, wedict_t *ed, vec3_t geomcenter) +{ + mesh_t mesh; + unsigned int numverts; + unsigned int numindexes,i; + galiasinfo_t *inf; + unsigned int surfnum = 0; + entity_t re; + + numverts = 0; + numindexes = 0; + + //fill in the parts of the entity_t that Alias_GAliasBuildMesh needs. + world->Get_FrameState(world, ed, &re.framestate); + re.fatness = ed->xv->fatness; + re.model = mod; + + inf = (galiasinfo_t*)Mod_Extradata (mod); + while(inf) + { + numverts += inf->numverts; + numindexes += inf->numindexes; + inf = inf->nextsurf; + } + + if (!numindexes) + { + Con_DPrintf("entity %i (classname %s) has no geometry\n", NUM_FOR_EDICT(world->progs, (edict_t*)ed), PR_GetString(world->progs, ed->v->classname)); + return false; + } + ed->ode.ode_element3i = (int*)BZ_Malloc(numindexes*sizeof(*ed->ode.ode_element3i)); + ed->ode.ode_vertex3f = (float*)BZ_Malloc(numverts*sizeof(vec3_t)); + + numverts = 0; + numindexes = 0; + + inf = (galiasinfo_t*)Mod_Extradata (mod); + while(inf) + { + Alias_GAliasBuildMesh(&mesh, NULL, inf, surfnum++, &re, false); + for (i = 0; i < mesh.numvertexes; i++) + VectorSubtract(mesh.xyz_array[i], geomcenter, (ed->ode.ode_vertex3f + 3*(numverts+i))); + for (i = 0; i < mesh.numindexes; i+=3) + { + //flip the triangles as we go + ed->ode.ode_element3i[numindexes+i+0] = numverts+mesh.indexes[i+2]; + ed->ode.ode_element3i[numindexes+i+1] = numverts+mesh.indexes[i+1]; + ed->ode.ode_element3i[numindexes+i+2] = numverts+mesh.indexes[i+0]; + } + numverts += inf->numverts; + numindexes += inf->numindexes; + inf = inf->nextsurf; + } + + Alias_FlushCache(); //it got built using an entity on the stack, make sure other stuff doesn't get hurt. + + ed->ode.ode_numvertices = numverts; + ed->ode.ode_numtriangles = numindexes/3; + return true; +} + +//Bullet has a fit if we have any degenerate triangles, so make sure we can determine some surface normal +static void World_Bullet_CleanupMesh(wedict_t *ed) +{ + float *v1, *v2, *v3; + vec3_t d1, d2, cr; + int in, out; + for (in = 0, out = 0; in < ed->ode.ode_numtriangles*3; in+=3) + { + v1 = &ed->ode.ode_vertex3f[ed->ode.ode_element3i[in+0]*3]; + v2 = &ed->ode.ode_vertex3f[ed->ode.ode_element3i[in+1]*3]; + v3 = &ed->ode.ode_vertex3f[ed->ode.ode_element3i[in+2]*3]; + VectorSubtract(v3, v1, d1); + VectorSubtract(v2, v1, d2); + CrossProduct(d1, d2, cr); + if (DotProduct(cr,cr) == 0) + continue; + ed->ode.ode_element3i[out+0] = ed->ode.ode_element3i[in+0]; + ed->ode.ode_element3i[out+1] = ed->ode.ode_element3i[in+1]; + ed->ode.ode_element3i[out+2] = ed->ode.ode_element3i[in+2]; + out+=3; + } + ed->ode.ode_numtriangles = out/3; +} + +qboolean QDECL World_GenerateCollisionMesh(world_t *world, model_t *mod, wedict_t *ed, vec3_t geomcenter) +{ + qboolean result; + switch(mod->type) + { + case mod_brush: + result = GenerateCollisionMesh_BSP(world, mod, ed, geomcenter); + break; + case mod_alias: + result = GenerateCollisionMesh_Alias(world, mod, ed, geomcenter); + break; + case mod_heightmap: + case mod_halflife: + case mod_sprite: + case mod_dummy: + default: + return false; //panic! + } + + if (result) + { + World_Bullet_CleanupMesh(ed); + if (ed->ode.ode_numtriangles > 0) + return true; + } + return false; +} +void QDECL World_ReleaseCollisionMesh(wedict_t *ed) +{ + BZ_Free(ed->ode.ode_element3i); + ed->ode.ode_element3i = NULL; + BZ_Free(ed->ode.ode_vertex3f); + ed->ode.ode_vertex3f = NULL; + ed->ode.ode_numvertices = 0; + ed->ode.ode_numtriangles = 0; +} +#endif #endif diff --git a/engine/shaders/glsl/default2d.glsl b/engine/shaders/glsl/default2d.glsl index eeacb71d3..5f6e459ae 100644 --- a/engine/shaders/glsl/default2d.glsl +++ b/engine/shaders/glsl/default2d.glsl @@ -20,6 +20,11 @@ void main () uniform sampler2D s_t0; void main () { - gl_FragColor = texture2D(s_t0, tc) * vc; + vec4 f = vc; +#ifdef PREMUL + f.rgb *= f.a; +#endif + f *= texture2D(s_t0, tc); + gl_FragColor = f; } #endif diff --git a/engine/web/fs_web.c b/engine/web/fs_web.c index e7419ea10..b6000f180 100644 --- a/engine/web/fs_web.c +++ b/engine/web/fs_web.c @@ -180,7 +180,7 @@ static qboolean QDECL FSWEB_PollChanges(searchpathfuncs_t *handle) // webpath_t *np = handle; return true; //can't verify that or not, so we have to assume the worst } -static int QDECL FSWEB_RebuildFSHash(const char *filename, qofs_t filesize, void *data, searchpathfuncs_t *spath) +static int QDECL FSWEB_RebuildFSHash(const char *filename, qofs_t filesize, time_t mtime, void *data, searchpathfuncs_t *spath) { webpath_t *sp = (void*)spath; void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle) = data; @@ -254,7 +254,7 @@ static void QDECL FSWEB_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, ch VFS_CLOSE(f); } -static int QDECL FSWEB_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, void *, searchpathfuncs_t *spath), void *parm) +static int QDECL FSWEB_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *spath), void *parm) { webpath_t *sp = (webpath_t*)handle; return Sys_EnumerateFiles(sp->rootpath, match, func, parm, handle); diff --git a/engine/web/sys_web.c b/engine/web/sys_web.c index 385cf6a62..55a6357f5 100644 --- a/engine/web/sys_web.c +++ b/engine/web/sys_web.c @@ -115,7 +115,7 @@ void Sys_Quit (void) exit (0); } -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { Con_DPrintf("Warning: Sys_EnumerateFiles not implemented\n"); return true; diff --git a/fteqtv/protocol.h b/fteqtv/protocol.h index 1ab91f175..c6ef9c713 100644 --- a/fteqtv/protocol.h +++ b/fteqtv/protocol.h @@ -215,20 +215,20 @@ enum { #define PEXT_SETVIEW 0x00000001 -#define PEXT_SCALE 0x00000002 +#define PEXT_SCALE 0x00000002 //obsoleted by PEXT2_REPLACEMENTDELTAS #define PEXT_LIGHTSTYLECOL 0x00000004 -#define PEXT_TRANS 0x00000008 +#define PEXT_TRANS 0x00000008 //obsoleted by PEXT2_REPLACEMENTDELTAS #define PEXT_VIEW2 0x00000010 -//#define PEXT_BULLETENS 0x00000020 //obsolete +//#define PEXT_BULLETENS 0x00000020 //no longer supported #define PEXT_ACCURATETIMINGS 0x00000040 #define PEXT_SOUNDDBL 0x00000080 //revised startsound protocol -#define PEXT_FATNESS 0x00000100 //GL only (or servers) +#define PEXT_FATNESS 0x00000100 //obsoleted by PEXT2_REPLACEMENTDELTAS #define PEXT_HLBSP 0x00000200 -#define PEXT_TE_BULLET 0x00000400 -#define PEXT_HULLSIZE 0x00000800 -#define PEXT_MODELDBL 0x00001000 -#define PEXT_ENTITYDBL 0x00002000 //max of 1024 ents instead of 512 -#define PEXT_ENTITYDBL2 0x00004000 //max of 1024 ents instead of 512 +#define PEXT_TE_BULLET 0x00000400 //obsoleted by fully custom particle effects. its an ooold extension, okay? :/ +#define PEXT_HULLSIZE 0x00000800 //obsoleted by PEXT2_REPLACEMENTDELTAS +#define PEXT_MODELDBL 0x00001000 //obsoleted by PEXT2_REPLACEMENTDELTAS +#define PEXT_ENTITYDBL 0x00002000 //max of 1024 ents instead of 512. obsoleted by PEXT2_REPLACEMENTDELTAS +#define PEXT_ENTITYDBL2 0x00004000 //max of 2048 ents instead of 512 #define PEXT_FLOATCOORDS 0x00008000 //supports floating point origins. //#define PEXT_VWEAP 0x00010000 //cause an extra qbyte to be sent, and an extra list of models for vweaps. #define PEXT_Q2BSP 0x00020000 @@ -236,22 +236,23 @@ enum { #define PEXT_COLOURMOD 0x00080000 //this replaces an older value which would rarly have caried any actual data. #define PEXT_SPLITSCREEN 0x00100000 #define PEXT_HEXEN2 0x00200000 //more stats and working particle builtin. -#define PEXT_SPAWNSTATIC2 0x00400000 //Sends an entity delta instead of a baseline. +#define PEXT_SPAWNSTATIC2 0x00400000 //Sends an entity delta instead of a baseline. obsoleted by PEXT2_REPLACEMENTDELTAS #define PEXT_CUSTOMTEMPEFFECTS 0x00800000 //supports custom temp ents. -#define PEXT_256PACKETENTITIES 0x01000000 //Client can recieve 256 packet entities. +#define PEXT_256PACKETENTITIES 0x01000000 //Client can recieve 256 packet entities. obsoleted by PEXT2_REPLACEMENTDELTAS //#define PEXT_NEVERUSED 0x02000000 #define PEXT_SHOWPIC 0x04000000 #define PEXT_SETATTACHMENT 0x08000000 //md3 tags (needs networking, they need to lerp). //#define PEXT_NEVERUSED 0x10000000 #define PEXT_CHUNKEDDOWNLOADS 0x20000000 //alternate file download method. Hopefully it'll give quadroupled download speed, especially on higher pings. -#define PEXT_CSQC 0x40000000 //csqc additions -#define PEXT_DPFLAGS 0x80000000 //extra flags for viewmodel/externalmodel and possible other persistant style flags. +#define PEXT_CSQC 0x40000000 //csqc additions. extra stats, particle svcs +#define PEXT_DPFLAGS 0x80000000 //extra flags for viewmodel/externalmodel and possible other persistant style flags. obsoleted by PEXT2_REPLACEMENTDELTAS #define PEXT2_PRYDONCURSOR 0x00000001 #define PEXT2_VOICECHAT 0x00000002 #define PEXT2_SETANGLEDELTA 0x00000004 -#define PEXT2_REPLACEMENTDELTAS 0x00000008 +#define PEXT2_OLDREPLACEMENTDELTAS 0x00000008 //weaponframe was part of the entity state. that flag is now the player's v_angle. #define PEXT2_MAXPLAYERS 0x00000010 //Client is able to cope with more players than 32. abs max becomes 255, due to colormap issues. +#define PEXT2_REPLACEMENTDELTAS 0x00000040 //#define PEXT2_PK3DOWNLOADS 0x10000000 //retrieve a list of pk3s/pk3s/paks for downloading (with optional URL and crcs) diff --git a/plugins/plugin.c b/plugins/plugin.c index 14e7ebf28..cf272f710 100644 --- a/plugins/plugin.c +++ b/plugins/plugin.c @@ -415,7 +415,7 @@ void NATIVEEXPORT dllEntry(qintptr_t (QDECL *funcptr)(qintptr_t,...)) #endif vmvideo_t vid; -qintptr_t Plug_UpdateVideo(qintptr_t *args) +qintptr_t QDECL Plug_UpdateVideo(qintptr_t *args) { vid.width = args[0]; vid.height = args[1]; @@ -423,7 +423,7 @@ qintptr_t Plug_UpdateVideo(qintptr_t *args) return true; } -qintptr_t Plug_InitAPI(qintptr_t *args) +qintptr_t QDECL Plug_InitAPI(qintptr_t *args) { #ifdef Q3_VM Plug_GetEngineFunction = (void*)args[0]; diff --git a/plugins/plugin.h b/plugins/plugin.h index c24686185..762a87cae 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -146,7 +146,7 @@ int Q_vsnprintf(char *buffer, size_t maxlen, const char *format, va_list vargs); #endif #ifndef NATIVEEXPORT -#define NATIVEEXPORT +#define NATIVEEXPORT QDECL #endif @@ -185,10 +185,11 @@ typedef struct { - - //Basic builtins: EBUILTIN(funcptr_t, Plug_GetEngineFunction, (const char *funcname)); //set up in vmMain, use this to get all other builtins + +#ifdef FTEENGINE +#else #ifndef Q3_VM EBUILTIN(qboolean, Plug_ExportNative, (const char *funcname, void *func)); //set up in vmMain, use this to get all other builtins #endif @@ -278,15 +279,16 @@ EBUILTIN(float, sqrt, (float f)); EBUILTIN(float, cos, (float f)); EBUILTIN(float, sin, (float f)); #endif +#endif -typedef qintptr_t (*export_t) (qintptr_t *args); +typedef qintptr_t (QDECL *export_t) (qintptr_t *args); char *va(const char *format, ...); qintptr_t Plug_Init(qintptr_t *args); qboolean Plug_Export(const char *name, export_t func); void Con_Printf(const char *format, ...); void Con_DPrintf(const char *format, ...); //not a particuarly efficient implementation, so beware. void Sys_Errorf(const char *format, ...); -void Q_strncpyz(char *d, const char *s, int n); +void QDECL Q_strncpyz(char *d, const char *s, int n);