diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 3163a3099..ee214469f 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -2713,15 +2713,6 @@ guess_pm_type: state->pm_type = PM_NORMAL; } -/* if (cl.lerpplayers[num].frame != state->frame) - { - cl.lerpplayers[num].oldframechange = cl.lerpplayers[num].framechange; - cl.lerpplayers[num].framechange = cl.time; - cl.lerpplayers[num].frame = state->frame; - - //don't care about position interpolation. - } -*/ TP_ParsePlayerInfo(oldstate, state, info); } @@ -2881,6 +2872,8 @@ void CL_LinkPlayers (void) continue; // not present this frame } + CL_UpdateNetFrameLerpState(false, state->frame, &cl.lerpplayers[j]); + #ifdef CSQC_DAT if (CSQC_DeltaPlayer(j, state)) continue; @@ -2983,7 +2976,6 @@ void CL_LinkPlayers (void) ent->skinnum = state->skinnum; - CL_UpdateNetFrameLerpState(false, state->frame, &cl.lerpplayers[j]); CL_LerpNetFrameState(FS_REG, &ent->framestate, &cl.lerpplayers[j]); // if (state->modelindex == cl_playerindex) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index d39f4bd8f..c42a92b8f 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -2666,9 +2666,15 @@ void CL_ReadPackets (void) if (cls.state >= ca_connected && realtime - cls.netchan.last_received > cl_timeout.value) { - Con_TPrintf (TLC_SERVERTIMEOUT); - CL_Disconnect (); - return; +#ifndef CLIENTONLY + /*don't timeout when we're the actual server*/ + if (!sv.state) +#endif + { + Con_TPrintf (TLC_SERVERTIMEOUT); + CL_Disconnect (); + return; + } } if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 6200fabe4..684d58827 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -4658,6 +4658,13 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n { Cam_SetAutoTrack(atoi(stufftext+5)); } + else if (!strncmp(stufftext, "//kickfile ", 11)) + { + flocation_t loc; + Cmd_TokenizeString(stufftext+2, false, false); + if (FS_FLocateFile(Cmd_Argv(1), FSLFRT_IFFOUND, &loc)) + Con_Printf("You have been kicked due to a modified file located at %s.\n", Cmd_Argv(0)); + } #ifdef PLUGINS else if (!strncmp(stufftext, "//tinfo ", 8)) { @@ -5200,11 +5207,11 @@ void CL_ParseServerMessage (void) cl.ackedinputsequence = cl.validsequence; break; - case svc_maxspeed : + case svc_maxspeed: cl.maxspeed[destsplit] = MSG_ReadFloat(); break; - case svc_entgravity : + case svc_entgravity: cl.entgravity[destsplit] = MSG_ReadFloat(); break; @@ -5270,11 +5277,11 @@ void CL_ParseServerMessage (void) case svcfte_cgamepacket: #ifdef HLCLIENT - if (CLHL_ParseGamePacket()); + if (CLHL_ParseGamePacket()) break; #endif #ifdef CSQC_DAT - if (CSQC_ParseGamePacket()); + if (CSQC_ParseGamePacket()) break; #endif Con_Printf("Unable to parse gamecode packet\n"); diff --git a/engine/client/client.h b/engine/client/client.h index 8172bca3c..e14671009 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -1052,6 +1052,8 @@ qboolean CSQC_DeltaPlayer(int playernum, player_state_t *state); void CSQC_DeltaStart(float time); qboolean CSQC_DeltaUpdate(entity_state_t *src); void CSQC_DeltaEnd(void); + +void CSQC_CvarChanged(cvar_t *var); #endif // @@ -1211,6 +1213,8 @@ extern qboolean editoractive; extern qboolean editormodal; void Editor_Draw(void); void Editor_Init(void); +struct progfuncs_s; +void Editor_ProgsKilled(struct progfuncs_s *dead); #endif void SCR_StringToRGB (char *rgbstring, float *rgb, float rgbinputscale); diff --git a/engine/client/image.c b/engine/client/image.c index 890759998..9944e0fb9 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -1178,7 +1178,7 @@ badjpeg: #endif goto badjpeg; } - if (cinfo.output_components!=3) + if (cinfo.output_components!=3 && cinfo.output_components != 1) { #ifdef _DEBUG Con_Printf("Bad number of components in JPEG: '%d', should be '3'.\n",cinfo.output_components); @@ -1192,21 +1192,45 @@ badjpeg: out=mem=BZ_Malloc(cinfo.output_height*cinfo.output_width*4); memset(out, 0, cinfo.output_height*cinfo.output_width*4); - while (cinfo.output_scanline < cinfo.output_height) + if (cinfo.output_components == 1) { - #ifdef DYNAMIC_LIBJPEG - (void) qjpeg_read_scanlines(&cinfo, buffer, 1); - #else - (void) jpeg_read_scanlines(&cinfo, buffer, 1); - #endif + while (cinfo.output_scanline < cinfo.output_height) + { + #ifdef DYNAMIC_LIBJPEG + (void) qjpeg_read_scanlines(&cinfo, buffer, 1); + #else + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + #endif - in = buffer[0]; - for (i = 0; i < cinfo.output_width; i++) - {//rgb to rgba - *out++ = *in++; - *out++ = *in++; - *out++ = *in++; - *out++ = 255; + in = buffer[0]; + for (i = 0; i < cinfo.output_width; i++) + {//rgb to rgba + *out++ = *in; + *out++ = *in; + *out++ = *in; + *out++ = 255; + in++; + } + } + } + else + { + while (cinfo.output_scanline < cinfo.output_height) + { + #ifdef DYNAMIC_LIBJPEG + (void) qjpeg_read_scanlines(&cinfo, buffer, 1); + #else + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + #endif + + in = buffer[0]; + for (i = 0; i < cinfo.output_width; i++) + {//rgb to rgba + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + *out++ = 255; + } } } @@ -2241,7 +2265,8 @@ int image_width, image_height; texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags) { qboolean alphaed; - char *buf, *data; + char *buf; + unsigned char *data; texid_t tex; // int h; char fname[MAX_QPATH], nicename[MAX_QPATH]; @@ -2332,6 +2357,35 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags) extern cvar_t vid_hardwaregamma; if (!(flags&IF_NOGAMMA) && !vid_hardwaregamma.value) BoostGamma(data, image_width, image_height); + + if (!(flags & IF_NOALPHA)) + { + unsigned int alpha_width, alpha_height, p; + char aname[MAX_QPATH]; + unsigned char *alphadata; + char *alph; + if (tex_path[i].args >= 3) + snprintf(aname, sizeof(aname)-1, tex_path[i].path, subpath, nicename, va("_alpha%s", tex_extensions[e].name)); + else + snprintf(aname, sizeof(aname)-1, tex_path[i].path, nicename, va("_alpha%s", tex_extensions[e].name)); + if ((alph = COM_LoadFile (aname, 5))) + { + if ((alphadata = Read32BitImageFile(alph, com_filesize, &alpha_width, &alpha_height, aname))) + { + if (alpha_width == image_width && alpha_height == image_height) + { + for (p = 0; p < alpha_width*alpha_height; p++) + { + data[(p<<2) + 3] = (alphadata[(p<<2) + 0] + alphadata[(p<<2) + 1] + alphadata[(p<<2) + 2])/3; + } + } + BZ_Free(alphadata); + } + BZ_Free(alph); + } + } + + TRACE(("dbg: Mod_LoadHiResTexture: %s loaded\n", name)); if (tex_path[i].args >= 3) { //if it came from a special subpath (eg: map specific), upload it using the subpath prefix diff --git a/engine/client/in_win.c b/engine/client/in_win.c index 7a3fb4946..640633c1f 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -1340,6 +1340,7 @@ static void ProcessMouse(mouse_t *mouse, float *movements, int pnum) #endif #ifdef PEXT_CSQC + if (mx || my) if (CSQC_MouseMove(mx, my)) { mx = 0; diff --git a/engine/client/keys.c b/engine/client/keys.c index ca40ef84c..6ec75218a 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -1312,7 +1312,7 @@ qboolean Key_MouseShouldBeFree(void) if (m_state == m_complex || m_state == m_plugin /*|| m_state == m_menu_dat*/) return true; } - if (key_dest == key_console) + if (key_dest == key_console || key_dest == key_editor) return true; #ifdef VM_UI @@ -1605,7 +1605,6 @@ void Key_Event (int pnum, int key, unsigned int unicode, qboolean down) // // during demo playback, most keys bring up the main menu // - if (cls.demoplayback && cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV && down && consolekeys[key] && key != K_TAB && key_dest == key_game) { M_ToggleMenu_f (); diff --git a/engine/client/m_options.c b/engine/client/m_options.c index c27d32e93..18c82d422 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -1740,6 +1740,9 @@ void M_Menu_Singleplayer_Cheats_f (void) extern cvar_t sv_gravity, sv_cheats, sv_maxspeed, skill; extern cvar_t host_mapname; #endif + #ifdef TEXTEDITOR + extern cvar_t debugger; + #endif int y; menu_t *menu = M_Options_Title(&y, sizeof(*info)); info = menu->data; @@ -1765,6 +1768,9 @@ void M_Menu_Singleplayer_Cheats_f (void) info->mapcombo = MC_AddCombo(menu,16, y, " Map", mapoptions_q1, currentmap); y+=8; MC_AddCheckBox(menu, 16, y, " Cheats", &sv_cheats,0); y+=8; #endif + #ifdef TEXTEDITOR + MC_AddCheckBox(menu, 16, y, " Debugger", &debugger, 0); y+=8; + #endif MC_AddConsoleCommand(menu, 16, y, " Toggle Godmode", "god\n"); y+=8; MC_AddConsoleCommand(menu, 16, y, " Toggle Flymode", "fly\n"); y+=8; MC_AddConsoleCommand(menu, 16, y, " Toggle Noclip", "noclip\n"); y+=8; diff --git a/engine/client/menu.h b/engine/client/menu.h index 99f8de7bd..ef77b9c0f 100644 --- a/engine/client/menu.h +++ b/engine/client/menu.h @@ -385,6 +385,7 @@ void M_DrawScalePic (int x, int y, int w, int h, mpic_t *pic); void M_FindKeysForCommand (int pnum, char *command, int *twokeys); void M_UnbindCommand (char *command); +void MP_CvarChanged(cvar_t *var); qboolean MP_Init (void); void MP_Shutdown (void); qboolean MP_Toggle(void); diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 5883f7874..0045dc889 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -1915,6 +1915,12 @@ static void P_LoadParticleSet(char *name, qboolean first) } } + if (!strcmp(name, "effectinfo")) + { + P_ImportEffectInfo_f(); + return; + } + FS_LoadFile(va("particles/%s.cfg", name), (void**)&file); if (!file) diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index d92551411..c68f09474 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -25,7 +25,7 @@ #include "pr_common.h" -#ifdef CLIENTONLY +#ifndef TEXTEDITOR //client only builds don't have a qc debugger #define QCEditor NULL #endif @@ -59,6 +59,8 @@ cvar_t pr_csmaxedicts = CVAR("pr_csmaxedicts", "3072"); //not tied to protocol n 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"); cvar_t pr_csqc_coreonerror = CVAR("pr_csqc_coreonerror", "1"); +extern cvar_t dpcompat_stats; +cvar_t dpcompat_corruptglobals = CVAR("dpcompat_corruptglobals", "0"); #define MASK_DELTA 1 @@ -140,6 +142,7 @@ typedef enum globalfunction(input_event, "CSQC_InputEvent"); \ globalfunction(input_frame, "CSQC_Input_Frame");/*EXT_CSQC_1*/ \ globalfunction(console_command, "CSQC_ConsoleCommand"); \ + globalfunction(gamecommand, "GameCommand"); /*DP extension*/\ \ globalfunction(ent_update, "CSQC_Ent_Update"); \ globalfunction(ent_remove, "CSQC_Ent_Remove"); \ @@ -232,15 +235,29 @@ static void CSQC_ChangeLocalPlayer(int lplayernum) csqcg.view_angles[1] = cl.viewangles[csqc_lplayernum][1]; csqcg.view_angles[2] = cl.viewangles[csqc_lplayernum][2]; } - + if (dpcompat_corruptglobals.ival) + { + if (csqcg.pmove_org) + { + csqcg.pmove_org[0] = cl.simorg[csqc_lplayernum][0]; + csqcg.pmove_org[1] = cl.simorg[csqc_lplayernum][1]; + csqcg.pmove_org[2] = cl.simorg[csqc_lplayernum][2]; + } + if (csqcg.input_angles) + { + csqcg.input_angles[0] = cl.viewangles[csqc_lplayernum][0]; + csqcg.input_angles[1] = cl.viewangles[csqc_lplayernum][1]; + csqcg.input_angles[2] = cl.viewangles[csqc_lplayernum][2]; + } + } } static void CSQC_FindGlobals(void) { -#define globalfloat(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0); -#define globalvector(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0); -#define globalentity(name,qcname) csqcg.name = (int*)PR_FindGlobal(csqcprogs, qcname, 0); -#define globalstring(name,qcname) csqcg.name = (string_t*)PR_FindGlobal(csqcprogs, qcname, 0); +#define globalfloat(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0, NULL); +#define globalvector(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0, NULL); +#define globalentity(name,qcname) csqcg.name = (int*)PR_FindGlobal(csqcprogs, qcname, 0, NULL); +#define globalstring(name,qcname) csqcg.name = (string_t*)PR_FindGlobal(csqcprogs, qcname, 0, NULL); #define globalfunction(name,qcname) csqcg.name = PR_FindFunction(csqcprogs,qcname,PR_ANY); csqcglobals @@ -262,6 +279,16 @@ static void CSQC_FindGlobals(void) *csqcg.maxclients = cl.allocated_client_slots; } +static void QCBUILTIN PF_cs_gettime (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int timer = G_FLOAT(OFS_PARM0); + switch(timer) + { + default: + G_FLOAT(OFS_RETURN) = cl.time; + break; + } +} //this is the list for all the csqc fields. @@ -1078,126 +1105,6 @@ static void QCBUILTIN PF_R_ClearScene (progfuncs_t *prinst, struct globalvars_s csqc_drawsbar = false; } -static void QCBUILTIN PF_R_SetViewFlag(progfuncs_t *prinst, struct globalvars_s *pr_globals) -{ - viewflags parametertype = G_FLOAT(OFS_PARM0); - float *p = G_VECTOR(OFS_PARM1); - - csqc_rebuildmatricies = true; - - G_FLOAT(OFS_RETURN) = 1; - switch(parametertype) - { - case VF_FOV: - r_refdef.fov_x = p[0]; - r_refdef.fov_y = p[1]; - break; - - case VF_FOVX: - r_refdef.fov_x = *p; - break; - - case VF_FOVY: - r_refdef.fov_y = *p; - break; - - case VF_AFOV: - { - float frustumx, frustumy; - frustumy = tan(p[0] * (M_PI/360)) * 0.75; - if (*prinst->callargc > 2) - frustumy *= G_FLOAT(OFS_PARM2); - frustumx = frustumy * vid.width / vid.height /* / vid.pixelheight*/; - r_refdef.fov_x = atan2(frustumx, 1) * (360/M_PI); - r_refdef.fov_y = atan2(frustumy, 1) * (360/M_PI); - } - break; - - case VF_ORIGIN: - VectorCopy(p, r_refdef.vieworg); - cl.crouch[csqc_lplayernum] = 0; - break; - - case VF_ORIGIN_Z: - cl.crouch[csqc_lplayernum] = 0; - case VF_ORIGIN_X: - case VF_ORIGIN_Y: - r_refdef.vieworg[parametertype-VF_ORIGIN_X] = *p; - break; - - case VF_ANGLES: - VectorCopy(p, r_refdef.viewangles); - break; - case VF_ANGLES_X: - case VF_ANGLES_Y: - case VF_ANGLES_Z: - r_refdef.viewangles[parametertype-VF_ANGLES_X] = *p; - break; - - case VF_CL_VIEWANGLES_V: - VectorCopy(p, cl.viewangles[csqc_lplayernum]); - break; - case VF_CL_VIEWANGLES_X: - case VF_CL_VIEWANGLES_Y: - case VF_CL_VIEWANGLES_Z: - cl.viewangles[csqc_lplayernum][parametertype-VF_CL_VIEWANGLES_X] = *p; - break; - - case VF_CARTESIAN_ANGLES: - Con_Printf(CON_WARNING "WARNING: CARTESIAN ANGLES ARE NOT YET SUPPORTED!\n"); - break; - - case VF_VIEWPORT: - r_refdef.vrect.x = p[0]; - r_refdef.vrect.y = p[1]; - p+=3; - r_refdef.vrect.width = p[0]; - r_refdef.vrect.height = p[1]; - break; - - case VF_SIZE_X: - r_refdef.vrect.width = *p; - break; - case VF_SIZE_Y: - r_refdef.vrect.height = *p; - break; - case VF_SIZE: - r_refdef.vrect.width = p[0]; - r_refdef.vrect.height = p[1]; - break; - - case VF_MIN_X: - r_refdef.vrect.x = *p; - break; - case VF_MIN_Y: - r_refdef.vrect.y = *p; - break; - case VF_MIN: - r_refdef.vrect.x = p[0]; - r_refdef.vrect.y = p[1]; - break; - - case VF_DRAWWORLD: - r_refdef.flags = (r_refdef.flags&~Q2RDF_NOWORLDMODEL) | (*p?0:Q2RDF_NOWORLDMODEL); - break; - case VF_ENGINESBAR: - csqc_drawsbar = *p; - break; - case VF_DRAWCROSSHAIR: - csqc_addcrosshair = *p; - break; - - case VF_PERSPECTIVE: - r_refdef.useperspective = *p; - break; - - default: - Con_DPrintf("SetViewFlag: %i not recognised\n", parametertype); - G_FLOAT(OFS_RETURN) = 0; - break; - } -} - static void QCBUILTIN PF_R_GetViewFlag(progfuncs_t *prinst, struct globalvars_s *pr_globals) { viewflags parametertype = G_FLOAT(OFS_PARM0); @@ -1316,6 +1223,133 @@ static void QCBUILTIN PF_R_GetViewFlag(progfuncs_t *prinst, struct globalvars_s } } +static void QCBUILTIN PF_R_SetViewFlag(progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + viewflags parametertype = G_FLOAT(OFS_PARM0); + float *p = G_VECTOR(OFS_PARM1); + + if (*prinst->callargc < 2) + { + csqc_deprecated("PF_R_SetViewFlag called with wrong argument count\n"); + PF_R_GetViewFlag(prinst, pr_globals); + return; + } + + csqc_rebuildmatricies = true; + + G_FLOAT(OFS_RETURN) = 1; + switch(parametertype) + { + case VF_FOV: + r_refdef.fov_x = p[0]; + r_refdef.fov_y = p[1]; + break; + + case VF_FOVX: + r_refdef.fov_x = *p; + break; + + case VF_FOVY: + r_refdef.fov_y = *p; + break; + + case VF_AFOV: + { + float frustumx, frustumy; + frustumy = tan(p[0] * (M_PI/360)) * 0.75; + if (*prinst->callargc > 2) + frustumy *= G_FLOAT(OFS_PARM2); + frustumx = frustumy * vid.width / vid.height /* / vid.pixelheight*/; + r_refdef.fov_x = atan2(frustumx, 1) * (360/M_PI); + r_refdef.fov_y = atan2(frustumy, 1) * (360/M_PI); + } + break; + + case VF_ORIGIN: + VectorCopy(p, r_refdef.vieworg); + cl.crouch[csqc_lplayernum] = 0; + break; + + case VF_ORIGIN_Z: + cl.crouch[csqc_lplayernum] = 0; + case VF_ORIGIN_X: + case VF_ORIGIN_Y: + r_refdef.vieworg[parametertype-VF_ORIGIN_X] = *p; + break; + + case VF_ANGLES: + VectorCopy(p, r_refdef.viewangles); + break; + case VF_ANGLES_X: + case VF_ANGLES_Y: + case VF_ANGLES_Z: + r_refdef.viewangles[parametertype-VF_ANGLES_X] = *p; + break; + + case VF_CL_VIEWANGLES_V: + VectorCopy(p, cl.viewangles[csqc_lplayernum]); + break; + case VF_CL_VIEWANGLES_X: + case VF_CL_VIEWANGLES_Y: + case VF_CL_VIEWANGLES_Z: + cl.viewangles[csqc_lplayernum][parametertype-VF_CL_VIEWANGLES_X] = *p; + break; + + case VF_CARTESIAN_ANGLES: + Con_Printf(CON_WARNING "WARNING: CARTESIAN ANGLES ARE NOT YET SUPPORTED!\n"); + break; + + case VF_VIEWPORT: + r_refdef.vrect.x = p[0]; + r_refdef.vrect.y = p[1]; + p+=3; + r_refdef.vrect.width = p[0]; + r_refdef.vrect.height = p[1]; + break; + + case VF_SIZE_X: + r_refdef.vrect.width = *p; + break; + case VF_SIZE_Y: + r_refdef.vrect.height = *p; + break; + case VF_SIZE: + r_refdef.vrect.width = p[0]; + r_refdef.vrect.height = p[1]; + break; + + case VF_MIN_X: + r_refdef.vrect.x = *p; + break; + case VF_MIN_Y: + r_refdef.vrect.y = *p; + break; + case VF_MIN: + r_refdef.vrect.x = p[0]; + r_refdef.vrect.y = p[1]; + break; + + case VF_DRAWWORLD: + r_refdef.flags = (r_refdef.flags&~Q2RDF_NOWORLDMODEL) | (*p?0:Q2RDF_NOWORLDMODEL); + break; + case VF_ENGINESBAR: + csqc_drawsbar = *p; + break; + case VF_DRAWCROSSHAIR: + csqc_addcrosshair = *p; + break; + + case VF_PERSPECTIVE: + r_refdef.useperspective = *p; + break; + + default: + Con_DPrintf("SetViewFlag: %i not recognised\n", parametertype); + G_FLOAT(OFS_RETURN) = 0; + break; + } +} + static void QCBUILTIN PF_R_RenderScene(progfuncs_t *prinst, struct globalvars_s *pr_globals) { if (cl.worldmodel) @@ -1354,11 +1388,10 @@ static void QCBUILTIN PF_R_RenderScene(progfuncs_t *prinst, struct globalvars_s R2D_DrawCrosshair(); } -static void QCBUILTIN PF_cs_getstatf(progfuncs_t *prinst, struct globalvars_s *pr_globals) +static void QCBUILTIN PF_cs_getstati(progfuncs_t *prinst, struct globalvars_s *pr_globals) { int stnum = G_FLOAT(OFS_PARM0); - float val = cl.statsf[csqc_lplayernum][stnum]; //copy float into the stat - G_FLOAT(OFS_RETURN) = val; + G_INT(OFS_RETURN) = cl.stats[csqc_lplayernum][stnum]; } static void QCBUILTIN PF_cs_getstatbits(progfuncs_t *prinst, struct globalvars_s *pr_globals) { //convert an int stat into a qc float. @@ -1376,7 +1409,7 @@ static void QCBUILTIN PF_cs_getstatbits(progfuncs_t *prinst, struct globalvars_s G_FLOAT(OFS_RETURN) = (((unsigned int)val)&(((1<>first; } else - G_FLOAT(OFS_RETURN) = val; + G_FLOAT(OFS_RETURN) = cl.statsf[csqc_lplayernum][stnum]; } static void QCBUILTIN PF_cs_getstats(progfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -1865,8 +1898,10 @@ static void QCBUILTIN PF_cs_trailparticles (progfuncs_t *prinst, struct globalva if (csqc_isdarkplaces) { - efnum = G_FLOAT(OFS_PARM1)-1; + efnum = G_FLOAT(OFS_PARM1); ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); + + efnum = pe->FindParticleType(COM_Effectinfo_ForNumber(efnum)); } else { @@ -1884,10 +1919,15 @@ static void QCBUILTIN PF_cs_particleeffectnum (progfuncs_t *prinst, struct globa { char *effectname = PR_GetStringOfs(prinst, OFS_PARM0); - //keep the effectinfo synced between server and client. - COM_Effectinfo_ForName(effectname); - - G_FLOAT(OFS_RETURN) = pe->FindParticleType(effectname)+1; + if (csqc_isdarkplaces) + { + //keep the effectinfo synced between server and client. + G_FLOAT(OFS_RETURN) = COM_Effectinfo_ForName(effectname); + } + else + { + G_FLOAT(OFS_RETURN) = pe->FindParticleType(effectname)+1; + } } static void QCBUILTIN PF_cs_sendevent (progfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -2234,6 +2274,11 @@ static void QCBUILTIN PF_cs_getplayerkey (progfuncs_t *prinst, struct globalvars if (pnum < 0 || pnum >= cl.allocated_client_slots) ret = ""; + else if (!strcmp(keyname, "viewentity")) //compat with DP. Yes, I know this is in the wrong place. + { + ret = buffer; + sprintf(ret, "%i", pnum+1); + } else if (!*cl.players[pnum].userinfo) ret = ""; //player isn't on the server. else if (!strcmp(keyname, "ping")) @@ -2260,11 +2305,6 @@ static void QCBUILTIN PF_cs_getplayerkey (progfuncs_t *prinst, struct globalvars ret = buffer; sprintf(ret, "%i", (int)cl.players[pnum].entertime); } - else if (!strcmp(keyname, "viewentity")) //compat with DP - { - ret = buffer; - sprintf(ret, "%i", pnum+1); - } #ifdef VOICECHAT else if (!strcmp(keyname, "voipspeaking")) { @@ -2998,10 +3038,16 @@ void CSQC_RunThreads(void) static void QCBUILTIN PF_cs_addprogs (progfuncs_t *prinst, struct globalvars_s *pr_globals) { char *s = PR_GetStringOfs(prinst, OFS_PARM0); + int newp; if (!s || !*s) - G_FLOAT(OFS_RETURN) = -1; + newp = -1; else - G_FLOAT(OFS_RETURN) = PR_LoadProgs(prinst, s, 0, NULL, 0); + { + newp = PR_LoadProgs(prinst, s, 0, NULL, 0); + if (newp >= 0) + PR_AutoCvarSetup(csqcprogs); + } + G_FLOAT(OFS_RETURN) = newp; } static void QCBUILTIN PF_cs_OpenPortal (progfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -4057,6 +4103,8 @@ void CSQC_PlayerStateToCSQC(int pnum, player_state_t *srcp, csqcedict_t *ent) ent->v->skin = srcp->skinnum; CSQC_LerpStateToCSQC(&cl.lerpplayers[pnum], ent, true); + ent->xv->lerpfrac = 1-(ent->xv->frame1time) / cl.lerpplayers[pnum].framelerpdeltatime; + ent->xv->lerpfrac = bound(0, ent->xv->lerpfrac, 1); VectorCopy(srcp->origin, ent->v->origin); @@ -4065,7 +4113,7 @@ void CSQC_PlayerStateToCSQC(int pnum, player_state_t *srcp, csqcedict_t *ent) VectorCopy(srcp->velocity, ent->v->velocity); ent->v->angles[0] *= -0.333; ent->v->colormap = pnum+1; - ent->xv->scale = srcp->scale/16.0f; + ent->xv->scale = srcp->scale; //ent->v->fatness = srcp->fatness; ent->xv->alpha = srcp->alpha/255.0f; @@ -4122,6 +4170,7 @@ qboolean CSQC_DeltaPlayer(int playernum, player_state_t *state) ent = (csqcedict_t *)ED_Alloc(csqcprogs); CSQC_PlayerStateToCSQC(playernum, state, ent); + ent->xv->drawmask = MASK_DELTA; *csqcg.self = EDICT_TO_PROG(csqcprogs, (void*)ent); @@ -4443,6 +4492,19 @@ static void QCBUILTIN PF_ReadServerEntityState(progfuncs_t *prinst, struct globa } #endif +static void QCBUILTIN PF_cs_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int action = G_FLOAT(OFS_PARM0); + float *pos = G_VECTOR(OFS_PARM1); + float radius = G_FLOAT(OFS_PARM2); + float quant = G_FLOAT(OFS_PARM3); +#if defined(TERRAIN) + G_FLOAT(OFS_RETURN) = Heightmap_Edit(csqc_world.worldmodel, action, pos, radius, quant); +#else + G_FLOAT(OFS_RETURN) = false; +#endif +} + #define PF_FixTen PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme //prefixes: @@ -4636,6 +4698,24 @@ static struct { {"shaderforname", PF_shaderforname, 238}, // #238 {"te_bloodqw", PF_cl_te_bloodqw, 239}, // #239 void te_bloodqw(vector org[, float count]) (FTE_TE_STANDARDEFFECTBUILTINS) +// {"checkpvs", PF_checkpvs, 240}, +// {"matchclientname", PF_matchclient, 241}, + {"sendpacket", PF_NoCSQC, 242}, //void(string dest, string content) sendpacket = #242; (FTE_QC_SENDPACKET) + +// {"bulleten", PF_bulleten, 243}, (removed builtin) + +#ifdef SQL + {"sqlconnect", PF_NoCSQC, 250}, // #250 float([string host], [string user], [string pass], [string defaultdb], [string driver]) sqlconnect (FTE_SQL) + {"sqldisconnect", PF_NoCSQC, 251}, // #251 void(float serveridx) sqldisconnect (FTE_SQL) + {"sqlopenquery", PF_NoCSQC, 252}, // #252 float(float serveridx, void(float serveridx, float queryidx, float rows, float columns, float eof) callback, float querytype, string query) sqlopenquery (FTE_SQL) + {"sqlclosequery", PF_NoCSQC, 253}, // #253 void(float serveridx, float queryidx) sqlclosequery (FTE_SQL) + {"sqlreadfield", PF_NoCSQC, 254}, // #254 string(float serveridx, float queryidx, float row, float column) sqlreadfield (FTE_SQL) + {"sqlerror", PF_NoCSQC, 255}, // #255 string(float serveridx, [float queryidx]) sqlerror (FTE_SQL) + {"sqlescape", PF_NoCSQC, 256}, // #256 string(float serveridx, string data) sqlescape (FTE_SQL) + {"sqlversion", PF_NoCSQC, 257}, // #257 string(float serveridx) sqlversion (FTE_SQL) + {"sqlreadfloat", PF_NoCSQC, 258}, // #258 float(float serveridx, float queryidx, float row, float column) sqlreadfloat (FTE_SQL) +#endif + {"stoi", PF_stoi, 259}, {"itos", PF_itos, 260}, {"stoh", PF_stoh, 261}, @@ -4657,6 +4737,7 @@ static struct { {"frameforname", PF_frameforname, 276},//void(float modidx, string framename) frameforname = #276 (FTE_CSQC_SKELETONOBJECTS) {"frameduration", PF_frameduration, 277},//void(float modidx, float framenum) frameduration = #277 (FTE_CSQC_SKELETONOBJECTS) + {"terrain_edit", PF_cs_terrain_edit, 278},//void(float action, vector pos, float radius, float quant) terrain_edit = #278 (??FTE_TERRAIN_EDIT??) //300 {"clearscene", PF_R_ClearScene, 300}, // #300 void() clearscene (EXT_CSQC) {"addentities", PF_R_AddEntityMask, 301}, // #301 void(float mask) addentities (EXT_CSQC) @@ -4701,7 +4782,7 @@ static struct { // {"?", PF_Fixme, 329}, // #329 EXT_CSQC_'DARKPLACES' //330 - {"getstatf", PF_cs_getstatf, 330}, // #330 float(float stnum) getstatf (EXT_CSQC) + {"getstati", PF_cs_getstati, 330}, // #330 float(float stnum) getstati (EXT_CSQC) {"getstatbits", PF_cs_getstatbits, 331}, // #331 float(float stnum) getstatbits (EXT_CSQC) {"getstats", PF_cs_getstats, 332}, // #332 string(float firststnum) getstats (EXT_CSQC) {"setmodelindex", PF_cs_SetModelIndex, 333}, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC) @@ -4720,7 +4801,7 @@ static struct { {"getkeybind", PF_cl_getkeybind, 342}, // #342 string(float keynum) getkeybind (EXT_CSQC) // {"?", PF_Fixme, 343}, // #343 -// {"?", PF_Fixme, 344}, // #344 + {"getmousepos", PF_cl_getmousepos, 344}, // #344 This is a DP extension {"getinputstate", PF_cs_getinputstate, 345}, // #345 float(float framenum) getinputstate (EXT_CSQC) {"setsensitivityscaler", PF_cs_setsensativityscaler, 346}, // #346 void(float sens) setsensitivityscaler (EXT_CSQC) @@ -4941,14 +5022,18 @@ static struct { {"argv_end_index", PF_argv_end_index, 516}, {"buf_cvarlist", PF_buf_cvarlist, 517}, {"cvar_description", PF_cvar_description, 518}, + + {"gettime", PF_cs_gettime, 519}, {"keynumtostring", PF_cl_keynumtostring, 520}, {"findkeysforcommand", PF_cl_findkeysforcommand, 521}, + {"sprintf", PF_sprintf, 627}, + {NULL} }; -static builtin_t pr_builtin[550]; +static builtin_t csqc_builtin[800]; @@ -5048,6 +5133,9 @@ void CSQC_Shutdown(void) CSQC_ForgetThreads(); CloseProgs(csqcprogs); } +#ifdef TEXTEDITOR + Editor_ProgsKilled(csqcprogs); +#endif csqcprogs = NULL; #ifdef USEODE @@ -5202,12 +5290,12 @@ qboolean CSQC_Init (unsigned int checksum) if (cl_nocsqc.value) return false; - for (i = 0; i < sizeof(pr_builtin)/sizeof(pr_builtin[0]); i++) - pr_builtin[i] = PF_Fixme; + for (i = 0; i < sizeof(csqc_builtin)/sizeof(csqc_builtin[0]); i++) + csqc_builtin[i] = PF_Fixme; for (i = 0; BuiltinList[i].bifunc; i++) { if (BuiltinList[i].ebfsnum) - pr_builtin[BuiltinList[i].ebfsnum] = BuiltinList[i].bifunc; + csqc_builtin[BuiltinList[i].ebfsnum] = BuiltinList[i].bifunc; } csqc_deprecated_warned = false; @@ -5239,8 +5327,8 @@ qboolean CSQC_Init (unsigned int checksum) csqcprogparms.memfree = PR_CB_Free;//void (*memfree) (void * mem); - csqcprogparms.globalbuiltins = pr_builtin;//builtin_t *globalbuiltins; //these are available to all progs - csqcprogparms.numglobalbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]); + csqcprogparms.globalbuiltins = csqc_builtin;//builtin_t *globalbuiltins; //these are available to all progs + csqcprogparms.numglobalbuiltins = sizeof(csqc_builtin)/sizeof(csqc_builtin[0]); csqcprogparms.autocompile = PR_COMPILEIGNORE;//enum {PR_NOCOMPILE, PR_COMPILENEXIST, PR_COMPILECHANGED, PR_COMPILEALWAYS} autocompile; @@ -5289,6 +5377,7 @@ qboolean CSQC_Init (unsigned int checksum) return false; } + PR_AutoCvarSetup(csqcprogs); PF_InitTempStrings(csqcprogs); @@ -5307,11 +5396,12 @@ qboolean CSQC_Init (unsigned int checksum) worldent = (csqcedict_t *)EDICT_NUM(csqcprogs, 0); worldent->isfree = false; + /*DP compat*/ str = (string_t*)csqcprogs->GetEdictFieldValue(csqcprogs, (edict_t*)worldent, "message", NULL); if (str) *str = PR_SetString(csqcprogs, cl.levelname); - str = (string_t*)PR_FindGlobal(csqcprogs, "mapname", 0); + str = (string_t*)PR_FindGlobal(csqcprogs, "mapname", 0, NULL); if (str) { char *s = Info_ValueForKey(cl.serverinfo, "map"); @@ -5400,14 +5490,14 @@ void PR_CSExtensionList_f(void) showflags = SHOW_ACTIVEEXT|SHOW_NOTACTIVEEXT; //make sure the info is valid - if (!pr_builtin[0]) + if (!csqc_builtin[0]) { - for (i = 0; i < sizeof(pr_builtin)/sizeof(pr_builtin[0]); i++) - pr_builtin[i] = PF_Fixme; + for (i = 0; i < sizeof(csqc_builtin)/sizeof(csqc_builtin[0]); i++) + csqc_builtin[i] = PF_Fixme; for (i = 0; BuiltinList[i].bifunc; i++) { if (BuiltinList[i].ebfsnum) - pr_builtin[BuiltinList[i].ebfsnum] = BuiltinList[i].bifunc; + csqc_builtin[BuiltinList[i].ebfsnum] = BuiltinList[i].bifunc; } } @@ -5419,7 +5509,7 @@ void PR_CSExtensionList_f(void) continue; //a reserved builtin. if (BuiltinList[i].bifunc == PF_Fixme) Con_Printf("^1%s:%i needs to be added\n", BuiltinList[i].name, BuiltinList[i].ebfsnum); - else if (pr_builtin[BuiltinList[i].ebfsnum] == BuiltinList[i].bifunc) + else if (csqc_builtin[BuiltinList[i].ebfsnum] == BuiltinList[i].bifunc) { if (showflags & SHOW_ACTIVEBI) Con_Printf("%s is active on %i\n", BuiltinList[i].name, BuiltinList[i].ebfsnum); @@ -5464,9 +5554,9 @@ void PR_CSExtensionList_f(void) Con_Printf("^4%s is not supported\n", extlist[i].name); break; } - if (pr_builtin[BuiltinList[bi].ebfsnum] != BuiltinList[bi].bifunc) + if (csqc_builtin[BuiltinList[bi].ebfsnum] != BuiltinList[bi].bifunc) { - if (pr_builtin[BuiltinList[bi].ebfsnum] == PF_Fixme) + if (csqc_builtin[BuiltinList[bi].ebfsnum] == PF_Fixme) { if (showflags & SHOW_NOTACTIVEEXT) Con_Printf("^4%s is not currently active (builtin: %s#%i)\n", extlist[i].name, BuiltinList[bi].name, BuiltinList[bi].ebfsnum); @@ -5493,18 +5583,53 @@ void PR_CSExtensionList_f(void) } } +void CSQC_Breakpoint_f(void) +{ + int wasset; + int isset; + char *filename = Cmd_Argv(1); + int line = atoi(Cmd_Argv(2)); + + if (!csqcprogs) + { + Con_Printf("CSQC not running\n"); + return; + } + wasset = svprogfuncs->ToggleBreak(csqcprogs, filename, line, 3); + isset = svprogfuncs->ToggleBreak(csqcprogs, filename, line, 2); + + if (wasset == isset) + Con_Printf("Breakpoint was not valid\n"); + else if (isset) + Con_Printf("Breakpoint has been set\n"); + else + Con_Printf("Breakpoint has been cleared\n"); + +} + +static void CSQC_GameCommand_f(void); void CSQC_RegisterCvarsAndThings(void) { PF_Common_RegisterCvars(); Cmd_AddCommand("coredump_csqc", CSQC_CoreDump); Cmd_AddCommand ("extensionlist_csqc", PR_CSExtensionList_f); - + Cmd_AddCommand("cl_cmd", CSQC_GameCommand_f); + Cmd_AddCommand("breakpoint_csqc", CSQC_Breakpoint_f); Cvar_Register(&pr_csmaxedicts, CSQCPROGSGROUP); Cvar_Register(&cl_csqcdebug, CSQCPROGSGROUP); Cvar_Register(&cl_nocsqc, CSQCPROGSGROUP); Cvar_Register(&pr_csqc_coreonerror, CSQCPROGSGROUP); + Cvar_Register(&dpcompat_corruptglobals, CSQCPROGSGROUP); +} + +void CSQC_CvarChanged(cvar_t *var) +{ + if (csqcprogs) + { + PR_AutoCvar(csqcprogs, var); + } } qboolean CSQC_DrawView(void) @@ -5626,6 +5751,17 @@ qboolean CSQC_ConsoleCommand(char *cmd) PR_ExecuteProgram (csqcprogs, csqcg.console_command); return G_FLOAT(OFS_RETURN); } +static void CSQC_GameCommand_f(void) +{ + void *pr_globals; + if (!csqcprogs || !csqcg.gamecommand) + return; + + pr_globals = PR_globals(csqcprogs, PR_CURRENT); + (((string_t *)pr_globals)[OFS_PARM0] = PR_TempString(csqcprogs, Cmd_Args())); + + PR_ExecuteProgram (csqcprogs, csqcg.gamecommand); +} #pragma message("do we really need the firstbyte parameter here?") qboolean CSQC_ParseTempEntity(unsigned char firstbyte) @@ -5643,7 +5779,25 @@ qboolean CSQC_ParseTempEntity(unsigned char firstbyte) qboolean CSQC_ParseGamePacket(void) { - return false; + int len = (unsigned short)MSG_ReadShort(); + int start = msg_readcount; + + void *pr_globals; + if (!csqcprogs || !csqcg.parse_tempentity) + { + MSG_ReadSkip(len); + return false; + } + + pr_globals = PR_globals(csqcprogs, PR_CURRENT); + PR_ExecuteProgram (csqcprogs, csqcg.parse_tempentity); + + if (msg_readcount != start + len) + { + Con_Printf("Gamecode misread a gamecode packet (%i bytes too much)\n", msg_readcount - (start+len)); + msg_readcount = start + len; + } + return true; } qboolean CSQC_LoadResource(char *resname, char *restype) diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 29aef255f..806ce55bb 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -9,6 +9,13 @@ #if defined(MENU_DAT) || defined(CSQC_DAT) +struct +{ + float *drawfont; + float *drawfontscale; +} mp_globs; + + int MP_TranslateFTEtoDPCodes(int code) { switch(code) @@ -343,12 +350,30 @@ void QCBUILTIN PF_CL_drawcolouredstring (progfuncs_t *prinst, struct globalvars_ float *pos = G_VECTOR(OFS_PARM0); char *text = PR_GetStringOfs(prinst, OFS_PARM1); float *size = G_VECTOR(OFS_PARM2); - float alpha = G_FLOAT(OFS_PARM3); -// float flag = G_FLOAT(OFS_PARM4); + float alpha = 0; + float flag = 0; + float r, g, b; conchar_t buffer[2048], *str; float px, py; + if (*prinst->callargc >= 6) + { + r = G_FLOAT(OFS_PARM3 + 0); + g = G_FLOAT(OFS_PARM3 + 1); + b = G_FLOAT(OFS_PARM3 + 2); + alpha = G_FLOAT(OFS_PARM4); + flag = G_FLOAT(OFS_PARM5); + } + else + { + r = 1; + g = 1; + b = 1; + alpha = G_FLOAT(OFS_PARM3); + flag = G_FLOAT(OFS_PARM4); + } + if (!text) { G_FLOAT(OFS_RETURN) = -1; //was null.. @@ -359,7 +384,7 @@ void QCBUILTIN PF_CL_drawcolouredstring (progfuncs_t *prinst, struct globalvars_ str = buffer; Font_BeginScaledString(font_conchar, pos[0], pos[1], &px, &py); - Font_ForceColour(1, 1, 1, alpha); + Font_ForceColour(r, g, b, alpha); while(*str) { px = Font_DrawScaleChar(px, py, size[0], size[1], *str++); @@ -377,9 +402,26 @@ void QCBUILTIN PF_CL_stringwidth(progfuncs_t *prinst, struct globalvars_s *pr_gl fontsize = G_FLOAT(OFS_PARM2); else fontsize = 1; + if (mp_globs.drawfontscale) + fontsize *= mp_globs.drawfontscale[1]; if (usecolours) { - G_FLOAT(OFS_RETURN) = COM_FunStringLength(text)*fontsize; + conchar_t buffer[2048], *str; + float px, py; + COM_ParseFunString(CON_WHITEMASK, text, buffer, sizeof(buffer), false); + str = buffer; + + Font_BeginScaledString(font_conchar, 0, 0, &px, &py); + while(*str) + { + px += Font_CharWidth(*str++); + } + Font_EndString(font_conchar); + + if (mp_globs.drawfontscale) + px *= mp_globs.drawfontscale[1]; + + G_FLOAT(OFS_RETURN) = px; } else { @@ -534,7 +576,7 @@ void QCBUILTIN PF_CL_drawcharacter (progfuncs_t *prinst, struct globalvars_s *pr Font_BeginScaledString(font_conchar, pos[0], pos[1], &x, &y); Font_ForceColour(rgb[0], rgb[1], rgb[2], alpha); - Font_DrawScaleChar(x, y, size[0], size[1], CON_WHITEMASK | 0xe000|(chara&0xff)); + Font_DrawScaleChar(x, y, size[0], size[1], CON_WHITEMASK | /*0xe000|*/(chara&0xff)); Font_InvalidateColour(); Font_EndString(font_conchar); @@ -561,9 +603,15 @@ void QCBUILTIN PF_CL_drawrawstring (progfuncs_t *prinst, struct globalvars_s *pr x = pos[0]; y = pos[1]; Font_ForceColour(rgb[0], rgb[1], rgb[2], alpha); + + if (mp_globs.drawfontscale) + { + size[0] *= mp_globs.drawfontscale[0]; + size[1] *= mp_globs.drawfontscale[1]; + } while(*text) { - x = Font_DrawScaleChar(x, y, size[0], size[1], CON_WHITEMASK|0xe000|(*text++&0xff)); + x = Font_DrawScaleChar(x, y, size[0], size[1], CON_WHITEMASK|/*0xe000|*/(*text++&0xff)); } Font_InvalidateColour(); Font_EndString(font_conchar); @@ -602,9 +650,6 @@ void QCBUILTIN PF_CL_drawgetimagesize (progfuncs_t *prinst, struct globalvars_s float *ret = G_VECTOR(OFS_RETURN); - if (!p) - p = R2D_SafeCachePic(va("%s.tga", picname)); - if (p) { ret[0] = p->width; @@ -743,7 +788,15 @@ void QCBUILTIN PF_parseentitydata(progfuncs_t *prinst, struct globalvars_s *pr_g void QCBUILTIN PF_mod (progfuncs_t *prinst, struct globalvars_s *pr_globals) { - G_FLOAT(OFS_RETURN) = (float)(((int)G_FLOAT(OFS_PARM0))%((int)G_FLOAT(OFS_PARM1))); + int a = G_FLOAT(OFS_PARM0); + int b = G_FLOAT(OFS_PARM1); + if (b == 0) + { + Con_Printf("mod by zero\n"); + G_FLOAT(OFS_RETURN) = 0; + } + else + G_FLOAT(OFS_RETURN) = a % b; } char *RemapCvarNameFromDPToFTE(char *name) @@ -836,7 +889,7 @@ void QCBUILTIN PF_nonfatalobjerror (progfuncs_t *prinst, struct globalvars_s *pr PR_StackTrace(prinst); - selfp = PR_FindGlobal(prinst, "self", PR_CURRENT); + selfp = PR_FindGlobal(prinst, "self", PR_CURRENT, NULL); if (selfp && selfp->_int) { ed = PROG_TO_EDICT(prinst, selfp->_int); @@ -970,7 +1023,7 @@ void QCBUILTIN PF_cl_getmousetarget (progfuncs_t *prinst, struct globalvars_s *p } //vector getmousepos(void) = #66; -void QCBUILTIN QCBUILTIN PF_cl_getmousepos (progfuncs_t *prinst, struct globalvars_s *pr_globals) +void QCBUILTIN PF_cl_getmousepos (progfuncs_t *prinst, struct globalvars_s *pr_globals) { float *ret = G_VECTOR(OFS_RETURN); extern int mousemove_x, mousemove_y; @@ -1608,7 +1661,7 @@ builtin_t menu_builtins[] = { PF_cin_getstate, // #464 PF_cin_restart, // #465 PF_drawline, // #466 - PF_drawcolorcodedstring, // #467 + PF_CL_drawcolouredstring, // #467 PF_CL_stringwidth, // #468 PF_CL_drawsubpic, // #469 @@ -1705,7 +1758,21 @@ builtin_t menu_builtins[] = { PF_M_gethostcacheindexforkey, PF_M_addwantedhostcachekey, PF_M_getextresponse, // #624 - PF_netaddress_resolve + PF_netaddress_resolve, + skip1 /*get gamedir info*/ + PF_sprintf, /*sprintf*/ + skip1 /*not listed in dp*/ + skip1 /*not listed in dp*/ + skip1 /*setkeybind*/ + skip1 /*getbindmaps*/ + skip1 /*setbindmaps*/ + skip1 /*crypto*/ + skip1 /*crypto*/ + skip1 /*crypto*/ + skip1 /*crypto*/ + skip1 /*crypto #637*/ + + }; int menu_numbuiltins = sizeof(menu_builtins)/sizeof(menu_builtins[0]); @@ -1757,6 +1824,9 @@ void MP_Shutdown (void) search_close_progs(menuprogs, true); CloseProgs(menuprogs); +#ifdef TEXTEDITOR + Editor_ProgsKilled(menuprogs); +#endif menuprogs = NULL; key_dest = key_game; @@ -1800,6 +1870,14 @@ void VARGS Menu_Abort (char *format, ...) MP_Shutdown(); } +void MP_CvarChanged(cvar_t *var) +{ + if (svprogfuncs) + { + PR_AutoCvar(svprogfuncs, var); + } +} + double menutime; qboolean MP_Init (void) { @@ -1875,10 +1953,14 @@ qboolean MP_Init (void) PF_InitTempStrings(menuprogs); - mp_time = (float*)PR_FindGlobal(menuprogs, "time", 0); + mp_time = (float*)PR_FindGlobal(menuprogs, "time", 0, NULL); if (mp_time) *mp_time = Sys_DoubleTime(); +#pragma message("disabled until csqc gets forked or some such") + //mp_globs.drawfont = (float*)PR_FindGlobal(menuprogs, "drawfont", 0, NULL); + //mp_globs.drawfontscale = (float*)PR_FindGlobal(menuprogs, "drawfontscale", 0, NULL); + menuentsize = PR_InitEnts(menuprogs, 8192); @@ -1923,7 +2005,7 @@ void MP_CoreDump_f(void) void MP_Reload_f(void) { MP_Shutdown(); - M_Init(); + MP_Init(); } void MP_RegisterCvarsAndCmds(void) diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 5a32803ef..8e2a76830 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -111,9 +111,10 @@ void R2D_Init(void) draw_backtile = R_RegisterShader("gfx/backtile.lmp", "{\n" -#ifdef USE_EGL - "program default2d\n" -#endif + "if $nofixed\n" + "[\n" + "program default2d\n" + "]\n" "nomipmaps\n" "{\n" "map $diffuse\n" @@ -219,9 +220,10 @@ void R2D_Init(void) ); shader_crosshair = R_RegisterShader("crosshairshader", "{\n" -#ifdef USE_EGL - "program default2d\n" -#endif + "if $nofixed\n" + "[\n" + "program default2d\n" + "]\n" "nomipmaps\n" "{\n" "map $diffuse\n" @@ -257,9 +259,9 @@ mpic_t *R2D_SafeCachePic (char *path) if (!qrenderer) return NULL; s = R_RegisterPic(path); - if (s->width) - return s; - return NULL; + if (s->flags & SHADER_NOIMAGE) + return NULL; + return s; } @@ -270,7 +272,7 @@ mpic_t *R2D_SafePicFromWad (char *name) shader_t *s; snprintf(newname, sizeof(newname), "gfx/%s.lmp", name); s = R_RegisterPic(newname); - if (s->width) + if (!(s->flags & SHADER_NOIMAGE)) return s; failedpic = name; return NULL; @@ -400,9 +402,10 @@ void R2D_TransPicTranslate (int x, int y, int width, int height, qbyte *pic, qby { translate_texture = R_AllocNewTexture(64, 64); translate_shader = R_RegisterShader("translatedpic", "{\n" -#ifdef USE_EGL - "program default2d\n" -#endif + "if $nofixed\n" + "[\n" + "program default2d\n" + "]\n" "nomipmaps\n" "{\n" "map $diffuse\n" diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 0168c649f..d839a1bf2 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -2045,11 +2045,6 @@ void Surf_DrawWorld (void) if (currentmodel->fromgame = fg_doom) GLR_DoomWorld(); else -#endif -#ifdef TERRAIN - if (currentmodel->type == mod_heightmap) - GL_DrawHeightmapModel(currententity); - else #endif { RSpeedRemark(); @@ -2093,6 +2088,13 @@ void Surf_DrawWorld (void) vis = D3_CalcVis(cl.worldmodel, r_refdef.vieworg); } else +#endif +#ifdef TERRAIN + if (currentmodel->type == mod_heightmap) + { + vis = NULL; + } + else #endif { //extern cvar_t temp1; @@ -2179,6 +2181,9 @@ static int Surf_LM_AllocBlock (int w, int h, int *x, int *y, shader_t *shader) } } + if (lightmap[texnum]->external) + lightmap_textures[texnum] = R_AllocNewTexture(LMBLOCK_WIDTH, LMBLOCK_HEIGHT); + /*not required, but using one lightmap per texture can result in better texture unit switching*/ if (lightmap[texnum]->shader != shader) continue; @@ -2277,6 +2282,9 @@ static int Surf_LM_FillBlock (int texnum, int w, int h, int x, int y) memset(lightmap[i]->lightmaps, 255, LMBLOCK_HEIGHT*LMBLOCK_HEIGHT*3); COM_StripExtension(cl.worldmodel->name, basename, sizeof(basename)); + if (!lightmap[i]->external) + R_DestroyTexture(lightmap_textures[i]); + lightmap[i]->external = true; lightmap_textures[i] = R_LoadHiResTexture(va("%s/lm_%04i", basename, i), NULL, IF_NOALPHA|IF_NOGAMMA); lightmap[i]->modified = false; } @@ -2445,6 +2453,14 @@ void Surf_DeInit(void) { int i; + if (lightmap_textures) + { + for (i = 0; i < numlightmaps; i++) + if (!lightmap[i] || lightmap[i]->external) + R_DestroyTexture(lightmap_textures[i]); + BZ_Free(lightmap_textures); + } + for (i = 0; i < numlightmaps; i++) { if (!lightmap[i]) @@ -2453,12 +2469,6 @@ void Surf_DeInit(void) lightmap[i] = NULL; } - if (lightmap_textures) - { - for (i = 0; i < numlightmaps; i++) - R_DestroyTexture(lightmap_textures[i]); - BZ_Free(lightmap_textures); - } if (lightmap) BZ_Free(lightmap); diff --git a/engine/client/render.h b/engine/client/render.h index 2f90e5b97..e56518c3d 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -211,6 +211,7 @@ typedef struct { struct mesh_s *meshchain; qboolean modified; qboolean deluxmodified; + qboolean external; glRect_t rectchange; glRect_t deluxrectchange; int allocated[LMBLOCK_WIDTH]; diff --git a/engine/client/textedit.c b/engine/client/textedit.c index 33815f456..4bfc4c01f 100644 --- a/engine/client/textedit.c +++ b/engine/client/textedit.c @@ -16,14 +16,15 @@ F11 will step through. #include "quakedef.h" #ifdef TEXTEDITOR -cvar_t alloweditor = SCVAR("alloweditor", "1"); //disallow loading editor for stepbystep debugging. -cvar_t editstripcr = SCVAR("edit_stripcr", "1"); //remove \r from eols (on load). -cvar_t editaddcr = SCVAR("edit_addcr", "1"); //make sure that each line ends with a \r (on save). -cvar_t edittabspacing = SCVAR("edit_tabsize", "4"); +static cvar_t alloweditor = SCVAR("alloweditor", "1"); //disallow loading editor for stepbystep debugging. +static cvar_t editstripcr = SCVAR("edit_stripcr", "1"); //remove \r from eols (on load). +static cvar_t editaddcr = SCVAR("edit_addcr", "1"); //make sure that each line ends with a \r (on save). +static cvar_t edittabspacing = SCVAR("edit_tabsize", "4"); +cvar_t debugger = SCVAR("debugger", "1"); #undef pr_trace -progfuncs_t *editprogfuncs; +static progfuncs_t *editprogfuncs; typedef struct fileblock_s { struct fileblock_s *next; @@ -37,7 +38,7 @@ typedef struct fileblock_s { static fileblock_t *cursorblock, *firstblock, *executionblock, *viewportystartblock; -void *E_Malloc(int size) +static void *E_Malloc(int size) { char *mem; mem = Z_Malloc(size); @@ -45,7 +46,7 @@ void *E_Malloc(int size) Sys_Error("Failed to allocate enough mem for editor\n"); return mem; } -void E_Free(void *mem) +static void E_Free(void *mem) { Z_Free(mem); } @@ -53,23 +54,23 @@ void E_Free(void *mem) #define GETBLOCK(s, ret) ret = (void *)E_Malloc(sizeof(fileblock_t) + s);ret->allocatedlength = s;ret->data = (char *)ret + sizeof(fileblock_t) -char OpenEditorFile[256]; +static char OpenEditorFile[256]; qboolean editoractive; //(export) qboolean editormodal; //doesn't return. (export) -qboolean editorblocking; -qboolean madechanges; -qboolean insertkeyhit=true; -qboolean useeval; +static qboolean editorblocking; +static qboolean madechanges; +static qboolean insertkeyhit=true; +static qboolean useeval; -char evalstring[256]; +static char evalstring[256]; -int executionlinenum; //step by step debugger -int cursorlinenum, cursorx; +static int executionlinenum; //step by step debugger +static int cursorlinenum, cursorx; -int viewportx; -int viewporty; +static int viewportx; +static int viewporty; static int VFS_GETC(vfsfile_t *fp) @@ -80,7 +81,7 @@ static int VFS_GETC(vfsfile_t *fp) } //newsize = number of chars, EXCLUDING terminator. -void MakeNewSize(fileblock_t *block, int newsize) //this is used to resize a block. It allocates a new one, copys the data frees the old one and links it into the right place +static void MakeNewSize(fileblock_t *block, int newsize) //this is used to resize a block. It allocates a new one, copys the data frees the old one and links it into the right place //it is called when the user is typing { fileblock_t *newblock; @@ -111,8 +112,8 @@ void MakeNewSize(fileblock_t *block, int newsize) //this is used to resize a blo cursorblock = newblock; } -int positionacross; -void GetCursorpos(void) +static int positionacross; +static void GetCursorpos(void) { int a; char *s; @@ -131,7 +132,7 @@ void GetCursorpos(void) } // positionacross = cursorofs; } -void SetCursorpos(void) +static void SetCursorpos(void) { int a=0; char *s; @@ -156,7 +157,7 @@ void SetCursorpos(void) } -void CloseEditor(void) +static void CloseEditor(void) { fileblock_t *b; @@ -183,7 +184,7 @@ void CloseEditor(void) executionlinenum = -1; } -qboolean EditorSaveFile(char *s) //returns true if succesful +static qboolean EditorSaveFile(char *s) //returns true if succesful { // FILE *F; @@ -233,7 +234,7 @@ qboolean EditorSaveFile(char *s) //returns true if succesful -void EditorNewFile() +static void EditorNewFile(void) { GETBLOCK(64, firstblock); GETBLOCK(64, firstblock->next); @@ -251,7 +252,7 @@ void EditorNewFile() editoractive = true; } -void EditorOpenFile(char *name) +static void EditorOpenFile(char *name) { int i; char line[8192]; @@ -445,22 +446,42 @@ void Editor_Key(int key, int unicode) break; case K_CTRL: break; + case K_MWHEELUP: + case K_UPARROW: case K_PGUP: GetCursorpos(); - {int a=(vid.height/8)/2; - while(a) {a--; - if (cursorblock->prev) { - cursorblock = cursorblock->prev; - cursorlinenum--; - } - } + int a; + if (key == K_PGUP) + a =(vid.height/8)/2; + else if (key == K_MWHEELUP) + a = 5; + else + a = 1; + while(a) + { + a--; + if (cursorblock->prev) + { + cursorblock = cursorblock->prev; + cursorlinenum--; + } + } } SetCursorpos(); break; + case K_MWHEELDOWN: + case K_DOWNARROW: case K_PGDN: GetCursorpos(); - {int a=(vid.height/8)/2; + { + int a; + if (key == K_PGDN) + a =(vid.height/8)/2; + else if (key == K_MWHEELDOWN) + a = 5; + else + a = 1; while(a) { a--; @@ -528,7 +549,7 @@ void Editor_Key(int key, int unicode) int f = 0; if (editprogfuncs) { - if (editprogfuncs->ToggleBreak(editprogfuncs, OpenEditorFile+4, cursorlinenum, 2)) + if (editprogfuncs->ToggleBreak(editprogfuncs, OpenEditorFile, cursorlinenum, 2)) f |= 1; else f |= 2; @@ -536,7 +557,7 @@ void Editor_Key(int key, int unicode) #ifndef CLIENTONLY else if (svprogfuncs) { - if (svprogfuncs->ToggleBreak(svprogfuncs, OpenEditorFile+4, cursorlinenum, 2)) + if (svprogfuncs->ToggleBreak(svprogfuncs, OpenEditorFile, cursorlinenum, 2)) f |= 1; else f |= 2; @@ -582,30 +603,6 @@ void Editor_Key(int key, int unicode) cursorx = cursorblock->datalength; break; - case K_MWHEELUP: - case K_UPARROW: - - GetCursorpos(); - if (cursorblock->prev) - { - cursorblock = cursorblock->prev; - cursorlinenum--; - } - SetCursorpos(); - break; - case K_MWHEELDOWN: - case K_DOWNARROW: - - GetCursorpos(); - if (cursorblock->next) - { - cursorblock = cursorblock->next; - cursorlinenum++; - } - - SetCursorpos(); - break; - case K_BACKSPACE: cursorx--; if (cursorx < 0) @@ -738,76 +735,24 @@ void Editor_Key(int key, int unicode) } } -void Draw_CursorLine(int ox, int y, fileblock_t *b) +static void Draw_Line(int x, int y, fileblock_t *b, int cursorx) { -#pragma message("Fixme: ") -/* - int x=0; - qbyte *d = b->data; - int cx; - int a = 0, i; - - int colour=COLOR_BLUE; - - int ts = edittabspacing.value; - if (ts < 1) - ts = 4; - ts*=8; - - if (b->flags & (FB_BREAK)) - colour = COLOR_RED; //red - - if (executionblock == b) - { - if (colour) //break point too - colour = COLOR_GREEN; //green - else - colour = COLOR_YELLOW; //yellow - } - - if (cursorx <= strlen(d)+1 && (int)(Sys_DoubleTime()*4.0) & 1) - cx = -1; - else - cx = cursorx; - for (i = 0; i < b->datalength; i++) - { - if (*d == '\t') - { - if (a == cx) - Draw_ColouredCharacter (x+ox, y, 11|CON_WHITEMASK); - x+=ts; - x-=x%ts; - d++; - a++; - continue; - } - if (x+ox< vid.width) - { - if (a == cx) - Draw_ColouredCharacter (x+ox, y, 11|CON_WHITEMASK); - else - Draw_ColouredCharacter (x+ox, y, (int)*d | (colour<data; + qbyte *c; int i; int colour=COLOR_WHITE; int ts = edittabspacing.value; + + if (cursorx >= 0) + c = d + cursorx; + else + c = NULL; + + Font_BeginString(font_conchar, x, y, &x, &y); + if (ts < 1) ts = 4; ts*=8; @@ -823,24 +768,38 @@ void Draw_NonCursorLine(int x, int y, fileblock_t *b) colour = COLOR_YELLOW; //yellow } + nx = x; + for (i = 0; i < b->datalength; i++) { if (*d == '\t') { + if (d == c) + Font_DrawChar(nx, y, (int)11 | (CON_WHITEMASK)); nx+=ts; - nx-=nx%ts; + nx-=(nx - x)%ts; d++; continue; } - if (x+nx < vid.width) - Draw_ColouredCharacter (x+nx, y, (int)*d | (colour<= d) + Font_DrawChar(nx, y, (int)11 | (CON_WHITEMASK)); + + Font_EndString(font_conchar); } -fileblock_t *firstline(void) +static fileblock_t *firstline(void) { int lines; fileblock_t *b; @@ -864,6 +823,7 @@ void Editor_Draw(void) { int x; int y; + int c; fileblock_t *b; if (key_dest != key_console) @@ -948,10 +908,11 @@ void Editor_Draw(void) b = firstline(); for (; b; b=b->next) { + c = -1; if (b == cursorblock) - Draw_CursorLine(x, y, b); - else - Draw_NonCursorLine(x, y, b); + if ((int)(Sys_DoubleTime()*4.0) & 1) + c = cursorx; + Draw_Line(x, y, b, c); y+=8; if (y > vid.height) @@ -983,7 +944,8 @@ void Editor_Draw(void) int QCLibEditor(progfuncs_t *prfncs, char *filename, int line, int nump, char **parms) { - if (editormodal || !developer.ival) + char *f1, *f2; + if (editormodal || line < 0 || !debugger.ival) return line; //whoops if (qrenderer == QR_NONE) @@ -1015,26 +977,18 @@ int QCLibEditor(progfuncs_t *prfncs, char *filename, int line, int nump, char ** editprogfuncs = prfncs; - if (!strncmp(OpenEditorFile, "src/", 4)) + f1 = OpenEditorFile; + f2 = filename; + if (!strncmp(f1, "src/", 4)) + f1 += 4; + if (!strncmp(f2, "src/", 4)) + f2 += 4; + if (!editoractive || strcmp(f1, f2)) { - if (!editoractive || strcmp(OpenEditorFile+4, filename)) - { - if (editoractive) - EditorSaveFile(OpenEditorFile); + if (editoractive) + EditorSaveFile(OpenEditorFile); - EditorOpenFile(filename); - } - - } - else - { - if (!editoractive || strcmp(OpenEditorFile, filename)) - { - if (editoractive) - EditorSaveFile(OpenEditorFile); - - EditorOpenFile(filename); - } + EditorOpenFile(filename); } for (cursorlinenum = 1, cursorblock = firstblock; cursorlinenum < line && cursorblock->next; cursorlinenum++) @@ -1063,7 +1017,16 @@ int QCLibEditor(progfuncs_t *prfncs, char *filename, int line, int nump, char ** return line; } -void Editor_f(void) +void Editor_ProgsKilled(progfuncs_t *dead) +{ + if (editprogfuncs == dead) + { + editprogfuncs = NULL; + editormodal = false; + } +} + +static void Editor_f(void) { if (Cmd_Argc() != 2) { @@ -1088,5 +1051,6 @@ void Editor_Init(void) Cvar_Register(&editstripcr, "Text editor"); Cvar_Register(&editaddcr, "Text editor"); Cvar_Register(&edittabspacing, "Text editor"); + Cvar_Register(&debugger, "Text editor"); } #endif diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 7a90e4ad4..4ea657d9b 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -2919,6 +2919,8 @@ void Cmd_Init (void) Cvar_Register(&com_fs_cache, "Filesystem"); Cvar_Register(&tp_disputablemacros, "Teamplay"); + Cvar_Register(&dpcompat_set, "Darkplaces compatibility"); + #ifndef SERVERONLY rcon_level.ival = atof(rcon_level.string); //client is restricted to not be allowed to change restrictions. #else diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index d595659d0..8367bf953 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -1288,7 +1288,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf, } if (frame2 >= inf->groups) { - Con_DPrintf("Too high frame %i (%s)\n", frame2, currententity->model->name); + Con_DPrintf("Too high frame %i (%s)\n", frame2, currententity->model->name); frame2 = frame1; } @@ -1848,6 +1848,8 @@ void Mod_LoadSkinFile(texnums_t *texnum, char *surfacename, int skinnumber, unsi texnum->shader = R_RegisterSkin(shadername); R_BuildDefaultTexnums(texnum, texnum->shader); + if (texnum->shader->flags & SHADER_NOIMAGE) + Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", texnum->shader->name, loadmodel->name); } #endif @@ -2213,6 +2215,16 @@ static void *Q1_LoadSkins_GL (daliasskintype_t *pskintype, unsigned int skintran "depthwrite\n" "}\n" "}\n"); + else if (skintranstype == 3) + texnums->shader = R_RegisterShader(skinname, + "{\n" + "{\n" + "map $diffuse\n" + "alphafunc ge128\n" + "rgbgen lightingDiffuse\n" + "depthwrite\n" + "}\n" + "}\n"); else if (skintranstype) texnums->shader = R_RegisterShader(skinname, "{\n" @@ -3639,6 +3651,9 @@ qboolean Mod_LoadQ3Model(model_t *mod, void *buffer) { texnum->shader = R_RegisterSkin(shadname); R_BuildDefaultTexnums(texnum, texnum->shader); + + if (texnum->shader->flags & SHADER_NOIMAGE) + Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", texnum->shader->name, loadmodel->name); } inshader++; @@ -4594,6 +4609,8 @@ qboolean Mod_LoadPSKModel(model_t *mod, void *buffer) Q_strncpyz(skin->name, matt[i].name, sizeof(skin->name)); gtexnums->shader = R_RegisterSkin(matt[i].name); R_BuildDefaultTexnums(gtexnums, gtexnums->shader); + if (gtexnums->shader->flags & SHADER_NOIMAGE) + Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", gtexnums->shader->name, loadmodel->name); gmdl[i].ofsskins = (char*)skin - (char*)&gmdl[i]; gmdl[i].numskins = 1; @@ -5138,7 +5155,7 @@ galisskeletaltransforms_t *IQM_ImportTransforms(int *resultcount, int inverts, f { galisskeletaltransforms_t *t, *r; unsigned int num_t = 0; - unsigned int 0; + unsigned int v, j; for (v = 0; v < inverts*4; v++) { if (vweight[v]) @@ -5149,12 +5166,12 @@ galisskeletaltransforms_t *IQM_ImportTransforms(int *resultcount, int inverts, f { for (j = 0; j < 4; j++) { - if (vweight[v<<2+j]) + if (vweight[(v<<2)+j]) { - t->boneindex = vbone[v<<2+j]; + t->boneindex = vbone[(v<<2)+j]; t->vertexindex = v; - VectorScale(vpos, vweight[v<<2+j]/255.0, t->org); - VectorScale(vnorm, vweight[v<<2+j]/255.0, t->normal); + VectorScale(vpos, vweight[(v<<2)+j]/255.0, t->org); + VectorScale(vnorm, vweight[(v<<2)+j]/255.0, t->normal); t++; } } @@ -5162,31 +5179,42 @@ galisskeletaltransforms_t *IQM_ImportTransforms(int *resultcount, int inverts, f return r; } -galiasinfo_t *Mod_ParseMD5MeshModel(char *buffer) +galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer) { struct iqmheader *h = (struct iqmheader *)buffer; struct iqmjoint *joint; struct iqmmesh *mesh; struct iqmvertexarray *varray; + struct iqmtriangle *tris; + unsigned int i, t, nt; + + char *strings; + + float *vpos = NULL, *tcoord = NULL, *vnorm = NULL, *vtang = NULL; + unsigned char *vbone = NULL, *vweight = NULL; + unsigned int type, fmt, size, offset; galiasinfo_t *gai; + galiasskin_t *skin; + texnums_t *texnum; + index_t *idx; - if (memcmp(h->magic, IQM_MAGIC, sizeof(h->magic)) + if (memcmp(h->magic, IQM_MAGIC, sizeof(h->magic))) { Con_Printf("%s: format not recognised\n", mod->name); - return false; + return NULL; } if (h->version != IQM_VERSION) { Con_Printf("%s: unsupported version\n", mod->name); - return false; + return NULL; } if (h->filesize != com_filesize) { Con_Printf("%s: size (%u != %u)\n", mod->name, h->filesize, com_filesize); - return false; + return NULL; } - +/* struct iqmjoint unsigned int name; int parent; @@ -5196,11 +5224,7 @@ galiasinfo_t *Mod_ParseMD5MeshModel(char *buffer) unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays; unsigned int num_triangles, ofs_triangles, ofs_adjacency; unsigned int num_joints, ofs_joints; - - - float *vpos = NULL, *tcoord = NULL, *vnorm = NULL, *vtang = NULL; - unsigned char *vbone = NULL, *vweight = NULL; - unsigned int type, fmt, size, offset; +*/ varray = (struct iqmvertexarray*)(buffer + h->ofs_vertexarrays); for (i = 0; i < h->num_vertexarrays; i++) @@ -5223,24 +5247,55 @@ galiasinfo_t *Mod_ParseMD5MeshModel(char *buffer) vweight = (unsigned char *)(buffer + offset); } - gai = Hunk_Alloc(sizeof(*gai)*h->num_meshes); + if (!h->num_meshes) + return NULL; + + strings = buffer + h->ofs_text; + + mesh = buffer + h->ofs_meshes; + tris = buffer + h->ofs_triangles; + + gai = Hunk_Alloc(sizeof(*gai)*h->num_meshes + sizeof(*skin)*h->num_meshes + sizeof(*texnum)*h->num_meshes); + skin = (galiasskin_t*)(gai + h->num_meshes); + texnum = (texnums_t*)(skin + h->num_meshes); for (i = 0; i < h->num_meshes; i++) { gai[i].nextsurf = (i == (h->num_meshes-1))?0:sizeof(*gai); gai[i].sharesverts = false; //used with models with two shaders using the same vertex - use last mesh's verts gai[i].sharesbones = i != 0; gai[i].numverts = LittleLong(mesh[i].num_vertexes); + gai[i].numskins = 1; + gai[i].ofsskins = (char*)&skin[i] - (char*)&gai[i]; + + Q_strncpyz(skin[i].name, strings+mesh[i].material, sizeof(skin[i].name)); + skin[i].skinwidth = 1; + skin[i].skinheight = 1; + skin[i].ofstexels = NULL; /*doesn't support 8bit colourmapping*/ + skin[i].skinspeed = 10; /*something to avoid div by 0*/ + skin[i].texnums = 1; + skin[i].ofstexnums = (char*)&texnum[i] - (char*)&skin[i]; + texnum[i].shader = R_RegisterSkin(skin[i].name); + offset = LittleLong(mesh[i].first_vertex); /*generate transforms for each vertex*/ gai[i].ofstransforms = (char*)IQM_ImportTransforms(&gai[i].numtransforms, gai[i].numverts, vpos+offset*3, tcoord+offset*2, vnorm+offset*3, vtang+offset*4, vbone+offset*4, vweight+offset*4) - (char*)gai; - } -galiasinfo_t - unsigned int name; - unsigned int material; - unsigned int first_vertex, num_vertexes; - unsigned int first_triangle, num_triangles; + + nt = 0;//LittleLong(mesh[i].num_triangles); + tris = buffer + LittleLong(h->ofs_triangles); + tris += LittleLong(mesh[i].first_triangle); + gai[i].numindexes = nt*3; + idx = Hunk_Alloc(sizeof(*idx)*gai[i].numindexes); + gai[i].ofs_indexes = (char*)idx - (char*)&gai[i]; + for (t = 0; t < nt; t++) + { + *idx++ = LittleShort(tris[t].vertex[0]); + *idx++ = LittleShort(tris[t].vertex[1]); + *idx++ = LittleShort(tris[t].vertex[2]); + } + } + return gai; } qboolean Mod_ParseIQMAnim(char *buffer, galiasinfo_t *prototype, void**poseofs, galiasgroup_t *gat) @@ -5251,11 +5306,12 @@ qboolean Mod_ParseIQMAnim(char *buffer, galiasinfo_t *prototype, void**poseofs, qboolean Mod_LoadInterQuakeModel(model_t *mod, void *buffer) { + unsigned int hunkstart, hunkend, hunktotal; galiasinfo_t *root; struct iqmheader *h = (struct iqmheader *)buffer; hunkstart = Hunk_LowMark(); - root = Mod_ParseMD5MeshModel(buffer); + root = Mod_ParseIQMMeshModel(mod, buffer); if (!root) return false; hunkend = Hunk_LowMark(); @@ -5693,6 +5749,8 @@ galiasinfo_t *Mod_ParseMD5MeshModel(char *buffer) #ifndef SERVERONLY texnum->shader = R_RegisterSkin(com_token); R_BuildDefaultTexnums(texnum, texnum->shader); + if (texnum->shader->flags & SHADER_NOIMAGE) + Con_Printf("Unable to load texture for shader \"%s\" for model \"%s\"\n", texnum->shader->name, loadmodel->name); #endif } else if (!strcmp(com_token, "numverts")) diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index 8984dadba..941bb1fb5 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -144,6 +144,9 @@ qboolean Mod_LoadQ1Model (model_t *mod, void *buffer); #ifdef PSKMODELS qboolean Mod_LoadPSKModel(model_t *mod, void *buffer); #endif +#ifdef INTERQUAKEMODELS + qboolean Mod_LoadInterQuakeModel(model_t *mod, void *buffer); +#endif #ifdef MD5MODELS qboolean Mod_LoadMD5MeshModel(model_t *mod, void *buffer); qboolean Mod_LoadCompositeAnim(model_t *mod, void *buffer); diff --git a/engine/common/common.c b/engine/common/common.c index 0099db264..aa57acc26 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -89,6 +89,8 @@ static char *safeargvs[NUM_SAFE_ARGVS] = cvar_t registered = CVARD("registered","0","Set if quake's pak1.pak is available"); cvar_t gameversion = CVARFD("gameversion","", CVAR_SERVERINFO, "gamecode version for server browsers"); +cvar_t gameversion_min = CVARD("gameversion_min","", "gamecode version for server browsers"); +cvar_t gameversion_max = CVARD("gameversion_max","", "gamecode version for server browsers"); cvar_t com_gamename = CVARD("com_gamename", "", "The game name used for dpmaster queries"); cvar_t com_modname = CVARD("com_modname", "", "dpmaster information"); cvar_t com_parseutf8 = CVARD("com_parseutf8", "0", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts."); //1 parse. 2 parse, but stop parsing that string if a char was malformed. @@ -3313,6 +3315,8 @@ void COM_Init (void) Cvar_Register (®istered, "Copy protection"); Cvar_Register (&gameversion, "Gamecode"); + Cvar_Register (&gameversion_min, "Gamecode"); + Cvar_Register (&gameversion_max, "Gamecode"); Cvar_Register (&com_parseutf8, "Internationalisation"); com_parseutf8.ival = 1; diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 4adba90a7..0a9ac1a6b 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -719,6 +719,19 @@ cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force) var->latched_string = NULL; } + if (var->flags & CVAR_TELLGAMECODE) + { +#ifndef CLIENTONLY + SVQ1_CvarChanged(var); +#endif +#ifdef MENU_DAT + MP_CvarChanged(var); +#endif +#ifdef CSQC_DAT + CSQC_CvarChanged(var); +#endif + } + return var; } diff --git a/engine/common/cvar.h b/engine/common/cvar.h index 452464f3a..2a5cd4f13 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -129,6 +129,7 @@ typedef struct cvar_group_s #define CVAR_NOUNSAFEEXPAND (1<<14) // do not expand cvar value when command is from gamecode #define CVAR_RULESETLATCH (1<<15) //latched by the ruleset #define CVAR_SHADERSYSTEM (1<<16) //change flushes shaders. +#define CVAR_TELLGAMECODE (1<<17) //tells the gamecode when it has changed, does not prevent changing, added as an optimisation #define CVAR_LASTFLAG CVAR_SHADERSYSTEM diff --git a/engine/common/fs.c b/engine/common/fs.c index 523b9ec2e..d998d6b7a 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -1633,7 +1633,7 @@ void COM_Gamedir (const char *dir) #endif } -#define DPCOMPAT "set dpcompat_set 1\nset dpcompat_trailparticles 1\n" +#define DPCOMPAT "set _cl_playermodel \"\"\n set dpcompat_set 1\n set dpcompat_trailparticles 1\nset dpcompat_corruptglobals 1\nset vid_pixelheight 1\n" #define NEXCFG DPCOMPAT "set r_particlesdesc effectinfo\nset sv_maxairspeed \"400\"\nset sv_jumpvelocity 270\nset sv_mintic \"0.01\"\ncl_nolerp 0\nset r_particlesdesc effectinfo\n" #define DMFCFG "set com_parseutf8 1\npm_airstep 1\n" #define HEX2CFG "set r_particlesdesc \"spikeset tsshaft h2part\"\nset sv_maxspeed 640\nset watervis 1\nset r_wateralpha 0.5\nset sv_pupglow 1\nset cl_model_bobbing 1\n" @@ -1659,6 +1659,7 @@ const gamemode_info_t gamemode_info[] = { {"Darkplaces-Hipnotic", "hipnotic", "-hipnotic", {NULL}, NULL, {"id1", "qw", "hipnotic", "fte"}, "Quake: Scourge of Armagon"}, {"Darkplaces-Rogue", "rogue", "-rogue", {NULL}, NULL, {"id1", "qw", "rogue", "fte"}, "Quake: Dissolution of Eternity"}, {"Nexuiz", "nexuiz", "-nexuiz", {"nexuiz.exe"}, NEXCFG, {"data", "ftedata"}, "Nexuiz"}, + {"Xonotic", "xonotic", "-xonotic", {"xonotic.exe"}, NEXCFG, {"data", "ftedata"}, "Xonotic"}, {"DMF", "dmf", "-dmf", {"base/src/progs.src"}, DMFCFG, {"base", }, "DMF"}, //supported commercial mods (some are currently only partially supported) diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index 0e5487439..10656c262 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -610,6 +610,9 @@ vfsfile_t *FSZIP_OpenVFS(void *handle, flocation_t *loc, const char *mode) if (strcmp(mode, "rb")) return NULL; //urm, unable to write/append + if (loc->len < 0) + return NULL; + vfsz = Z_Malloc(sizeof(vfszip_t)); vfsz->parent = zip; diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 7e7bb0bcc..2ac0619a1 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -15,6 +15,7 @@ static char *cvargroup_progs = "Progs variables"; cvar_t pr_brokenfloatconvert = SCVAR("pr_brokenfloatconvert", "0"); cvar_t pr_tempstringcount = SCVAR("pr_tempstringcount", "");//"16"); cvar_t pr_tempstringsize = SCVAR("pr_tempstringsize", "4096"); +cvar_t dpcompat_stats = CVAR("dpcompat_stats", "0"); static char *strtoupper(char *s) { @@ -54,6 +55,7 @@ void PF_Common_RegisterCvars(void) Cvar_Register (&pr_brokenfloatconvert, cvargroup_progs); Cvar_Register (&pr_tempstringcount, cvargroup_progs); Cvar_Register (&pr_tempstringsize, cvargroup_progs); + Cvar_Register (&dpcompat_stats, cvargroup_progs); } char *Translate(char *message); @@ -1951,6 +1953,15 @@ void QCBUILTIN PF_uri_unescape (progfuncs_t *prinst, struct globalvars_s *pr_gl RETURN_TSTRING(resultbuf); } +// uri_get() gets content from an URL and calls a callback "uri_get_callback" with it set as string; an unique ID of the transfer is returned +// returns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string +void QCBUILTIN PF_uri_get (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + Con_Printf("PF_uri_get: stub\n"); + + G_FLOAT(OFS_RETURN) = 0; +} + //////////////////////////////////////////////////// //Console functions @@ -2444,7 +2455,7 @@ void QCBUILTIN PF_externset (progfuncs_t *prinst, struct globalvars_s *pr_global char *varname = PF_VarString(prinst, 2, pr_globals); eval_t *var; - var = prinst->FindGlobal(prinst, varname, n); + var = PR_FindGlobal(prinst, varname, n, NULL); if (var) var->_int = v; @@ -2456,7 +2467,7 @@ void QCBUILTIN PF_externvalue (progfuncs_t *prinst, struct globalvars_s *pr_glob char *varname = PF_VarString(prinst, 1, pr_globals); eval_t *var; - var = prinst->FindGlobal(prinst, varname, n); + var = prinst->FindGlobal(prinst, varname, n, NULL); if (var) { @@ -2610,11 +2621,105 @@ void QCBUILTIN PF_localcmd (progfuncs_t *prinst, struct globalvars_s *pr_globals Cbuf_AddText (str, RESTRICT_INSECURE); } +void QCBUILTIN PF_sprintf (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + char result[1024]; + char *fmt = PR_GetStringOfs(prinst, OFS_PARM0); + Con_Printf("PF_sprintf: stub\n"); + Q_strncpyz(result, fmt, sizeof(result)); + RETURN_TSTRING(result); +} +#define DEF_SAVEGLOBAL (1u<<15) +static void PR_AutoCvarApply(progfuncs_t *prinst, eval_t *val, etype_t type, cvar_t *var) +{ + switch(type & ~DEF_SAVEGLOBAL) + { + case ev_float: + val->_float = var->value; + break; + case ev_integer: + val->_int = var->ival; + break; + case ev_string: + PR_RemoveProgsString(prinst, val->_int); + val->_int = PR_SetString(prinst, var->string); + break; + case ev_vector: + { + char res[128]; + char *vs = var->string; + vs = COM_ParseOut(vs, res, sizeof(res)); + val->_vector[0] = atof(com_token); + vs = COM_ParseOut(vs, res, sizeof(res)); + val->_vector[1] = atof(com_token); + vs = COM_ParseOut(vs, res, sizeof(res)); + val->_vector[2] = atof(com_token); + } + break; + } +} +/*called when a var has changed*/ +void PR_AutoCvar(progfuncs_t *prinst, cvar_t *var) +{ + char *gname; + eval_t *val; + etype_t type; + int n, p; + for (n = 0; n < 2; n++) + { + gname = n?var->name2:var->name; + if (!gname) + continue; + gname = va("autocvar_%s", gname); + + for (p = 0; p < prinst->numprogs; p++) + { + val = PR_FindGlobal(prinst, gname, p, &type); + if (val) + PR_AutoCvarApply(prinst, val, type, var); + } + } +} +void PR_FoundPrefixedGlobals(progfuncs_t *progfuncs, char *name, eval_t *val, etype_t type) +{ + cvar_t *var; + char *vals; + name += 9; //autocvar_ + + switch(type & ~DEF_SAVEGLOBAL) + { + case ev_float: + vals = va("%f", val->_float); + break; + case ev_integer: + vals = va("%i", val->_int); + break; + case ev_vector: + vals = va("%f %f %f", val->_vector[0], val->_vector[1], val->_vector[2]); + break; + case ev_string: + vals = PR_GetString(progfuncs, val->string); + break; + default: + return; + } + var = Cvar_Get(name, vals, 0, "autocvars"); + if (!var) + return; + var->flags |= CVAR_TELLGAMECODE; + + PR_AutoCvarApply(progfuncs, val, type, var); +} + +void PR_AutoCvarSetup(progfuncs_t *prinst) +{ + prinst->FindPrefixGlobals (prinst, "autocvar_", PR_FoundPrefixedGlobals); +} lh_extension_t QSG_Extensions[] = { diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 1074f9815..f072abe02 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -44,8 +44,6 @@ struct wedict_s #define PF_cin_getstate PF_Fixme #define PF_cin_restart PF_Fixme #define PF_drawline PF_Fixme -#define PF_drawcolorcodedstring PF_Fixme -#define PF_uri_get PF_Fixme #define PF_gecko_create PF_Fixme #define PF_gecko_destroy PF_Fixme #define PF_gecko_navigate PF_Fixme @@ -53,7 +51,6 @@ struct wedict_s #define PF_gecko_movemouse PF_Fixme #define PF_gecko_resize PF_Fixme #define PF_gecko_get_texture_extent PF_Fixme -#define PF_uri_get PF_Fixme #define PF_pointsound PF_Fixme #define PF_getsurfacepointattribute PF_Fixme @@ -141,6 +138,7 @@ void QCBUILTIN PF_atan (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_atan2 (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_tan (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_localcmd (progfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_sprintf (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_random (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_fclose (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_fputs (progfuncs_t *prinst, struct globalvars_s *pr_globals); @@ -166,13 +164,15 @@ void QCBUILTIN PF_crc16 (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_cvar_type (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_uri_escape (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_uri_unescape (progfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_uri_get (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_itos (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_stoi (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_stoh (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_htos (progfuncs_t *prinst, struct globalvars_s *pr_globals); void PR_fclose_progs (progfuncs_t *prinst); char *PF_VarString (progfuncs_t *prinst, int first, struct globalvars_s *pr_globals); - +void PR_AutoCvarSetup(progfuncs_t *prinst); +void PR_AutoCvar(progfuncs_t *prinst, cvar_t *var); @@ -245,6 +245,8 @@ void QCBUILTIN PF_CL_drawgetimagesize (progfuncs_t *prinst, struct globalvars_s void QCBUILTIN PF_CL_stringwidth (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_CL_drawsubpic (progfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_cl_getmousepos (progfuncs_t *prinst, struct globalvars_s *pr_globals); + void QCBUILTIN PF_cl_keynumtostring (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_cl_findkeysforcommand (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_cl_stringtokeynum(progfuncs_t *prinst, struct globalvars_s *pr_globals); diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index 18f0f866a..9ed711a7e 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -712,7 +712,7 @@ static qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel) return e->light_known-1; e->light_dir[0] = 0; e->light_dir[1] = 1; e->light_dir[2] = 0; - if (clmodel->engineflags & MDLF_FLAME) + if (clmodel->engineflags & MDLF_FLAME || r_fullbright.ival) { e->light_avg[0] = e->light_avg[1] = e->light_avg[2] = 1; e->light_range[0] = e->light_range[1] = e->light_range[2] = 0; @@ -1890,6 +1890,11 @@ void BE_GenModelBatches(batch_t **batches) if (!r_drawentities.ival) return; +#if defined(TERRAIN) + if (cl.worldmodel && cl.worldmodel->type == mod_heightmap) + GL_DrawHeightmapModel(batches, &r_worldentity); +#endif + // draw sprites seperately, because of alpha blending for (i=0 ; ist_array; case TC_GEN_LIGHTMAP: - return (float*)mesh->lmst_array; + if (!mesh->lmst_array) + return (float*)mesh->st_array; + else + return (float*)mesh->lmst_array; case TC_GEN_NORMAL: return (float*)mesh->normals_array; case TC_GEN_SVECTOR: @@ -1959,8 +1969,16 @@ static void BE_GeneratePassTC(const shaderpass_t *pass, int passno) } else if (pass->tcgen == TC_GEN_LIGHTMAP) { - GL_SelectVBO(shaderstate.sourcevbo->vbolmcoord); - qglTexCoordPointer(2, GL_FLOAT, 0, shaderstate.sourcevbo->lmcoord); + if (!shaderstate.sourcevbo->lmcoord) + { + GL_SelectVBO(shaderstate.sourcevbo->vbotexcoord); + qglTexCoordPointer(2, GL_FLOAT, 0, shaderstate.sourcevbo->texcoord); + } + else + { + GL_SelectVBO(shaderstate.sourcevbo->vbolmcoord); + qglTexCoordPointer(2, GL_FLOAT, 0, shaderstate.sourcevbo->lmcoord); + } } else if (pass->tcgen == TC_GEN_NORMAL) { @@ -3269,6 +3287,8 @@ void GLBE_DrawWorld (qbyte *vis) shaderstate.curentity = &r_worldentity; shaderstate.updatetime = cl.servertime; + BE_SelectEntity(&r_worldentity); + #if 0 {int i; for (i = 0; i < SHADER_SORT_COUNT; i++) @@ -3309,18 +3329,18 @@ void GLBE_DrawWorld (qbyte *vis) BE_SelectMode(BEM_DEPTHDARK); else BE_SelectMode(BEM_STANDARD); - + checkglerror(); RSpeedRemark(); GLBE_SubmitMeshes(true, batches); RSpeedEnd(RSPEED_WORLD); - + checkglerror(); #ifdef RTLIGHTS RSpeedRemark(); BE_SelectEntity(&r_worldentity); Sh_DrawLights(vis); RSpeedEnd(RSPEED_STENCILSHADOWS); #endif - + checkglerror(); if (r_refdef.gfog_alpha) { BE_SelectMode(BEM_FOG); diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index a352c6b49..90e84bdb1 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -254,9 +254,10 @@ void Font_Init(void) fontplanes.shader = R_RegisterShader("ftefont", "{\n" -#ifdef USE_EGL - "program default2d\n" -#endif + "if $nofixed\n" + "[\n" + "program default2d\n" + "]\n" "nomipmaps\n" "{\n" "map $diffuse\n" @@ -555,6 +556,21 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx) } } } + /*make tab invisible*/ + if (charidx == '\t' || charidx == '\n') + { + c = &f->chars[charidx]; + c->left = 0; + c->advance = f->charheight; + c->top = 0; + + c->texplane = 0; + c->bmx = 0; + c->bmy = 0; + c->bmw = 0; + c->bmh = 0; + return c; + } #ifdef AVAIL_FREETYPE if (f->face) @@ -949,14 +965,14 @@ void Font_Free(struct font_s *f) void Font_BeginString(struct font_s *font, int vx, int vy, int *px, int *py) { curfont = font; - *px = (vx*vid.rotpixelwidth) / (float)vid.width; - *py = (vy*vid.rotpixelheight) / (float)vid.height; + *px = (vx*(int)vid.rotpixelwidth) / (float)vid.width; + *py = (vy*(int)vid.rotpixelheight) / (float)vid.height; } void Font_BeginScaledString(struct font_s *font, float vx, float vy, float *px, float *py) { curfont = font; - *px = (vx*vid.rotpixelwidth) / (float)vid.width; - *py = (vy*vid.rotpixelheight) / (float)vid.height; + *px = vx; + *py = vy; } void Font_EndString(struct font_s *font) @@ -1273,10 +1289,10 @@ float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int ch if (c->texplane >= DEFAULTPLANE) { - sx = ((px+c->left));//*(int)vid.width) / (float)vid.rotpixelwidth; - sy = ((py+c->top));//*(int)vid.height) / (float)vid.rotpixelheight; - sw = ((curfont->charheight*cw));//*vid.width) / (float)vid.rotpixelwidth; - sh = ((curfont->charheight*ch));//*vid.height) / (float)vid.rotpixelheight; + sx = ((px+c->left)); + sy = ((py+c->top)); + sw = ((curfont->charheight*cw)); + sh = ((curfont->charheight*ch)); if (c->texplane == DEFAULTPLANE) v = Font_BeginChar(fontplanes.defaultfont); @@ -1285,10 +1301,10 @@ float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int ch } else { - sx = ((px+c->left));//*(int)vid.width) / (float)vid.rotpixelwidth; - sy = ((py+c->top));//*(int)vid.height) / (float)vid.rotpixelheight; - sw = ((c->bmw*cw));//*vid.width) / (float)vid.rotpixelwidth; - sh = ((c->bmh*ch));//*vid.height) / (float)vid.rotpixelheight; + sx = ((px+c->left)); + sy = ((py+c->top)); + sw = ((c->bmw*cw)); + sh = ((c->bmh*ch)); v = Font_BeginChar(fontplanes.texnum[c->texplane]); } diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index ec0c1321e..fa08ae9d9 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -20,6 +20,7 @@ typedef struct { char path[MAX_QPATH]; + char hmapname[MAX_QPATH]; unsigned short *heights; int terrainsize; float terrainscale; @@ -29,150 +30,159 @@ typedef struct { texid_t textures[SECTIONS*SECTIONS]; int displaylist[SECTIONS*SECTIONS]; //display lists are famous for being stupidly fast with heightmaps. unsigned short mins[SECTIONS*SECTIONS], maxs[SECTIONS*SECTIONS]; + + shader_t *skyshader; + shader_t *shader; + mesh_t mesh[SECTIONS*SECTIONS]; + mesh_t *amesh[SECTIONS*SECTIONS]; + mesh_t skymesh; + mesh_t *askymesh; + + qboolean modified[SECTIONS*SECTIONS]; } heightmap_t; -#ifdef GLQUAKE #define DISPLISTS //#define MULTITEXTURE //ATI suck. I don't know about anyone else (this goes at 1/5th the speed). -void GL_DrawHeightmapModel (entity_t *e) +void GL_DrawHeightmapModel (batch_t **batches, entity_t *e) { //a 512*512 heightmap //will draw 2 tris per square, drawn twice for detail //so a million triangles per frame if the whole thing is visible. //with 130 to 180fps, display lists rule! - int x, y, vx, vy; + int x, y, vx, vy, v; float subsize; int minx, miny; vec3_t mins, maxs; model_t *m = e->model; heightmap_t *hm = m->terrain; + mesh_t *mesh; + batch_t *b; + vbo_t *vbo; if (e->model == cl.worldmodel) { - qglColor4f(1, 1, 1, 1); - R_DrawSkyChain(NULL); - } - else - qglColor4fv(e->shaderRGBAf); - GL_CullFace(SHADER_CULL_BACK); + b = BE_GetTempBatch(); + if (b) + { + b->ent = e; + b->shader = hm->skyshader; + b->flags = 0; + b->mesh = &hm->askymesh; + b->mesh[0] = &hm->skymesh; + b->meshes = 1; + b->buildmeshes = NULL; + b->skin = &b->shader->defaulttextures; + b->texture = NULL; + // vbo = b->vbo = hm->vbo[x+y*SECTIONS]; + b->vbo = NULL; + b->next = batches[b->shader->sort]; + batches[b->shader->sort] = b; + } + } + + subsize = hm->terrainsize/SECTIONS; for (x = 0; x < hm->numsegs; x++) { - mins[0] = (x+0)*hm->terrainscale*hm->terrainsize/hm->numsegs; - maxs[0] = (x+1)*hm->terrainscale*hm->terrainsize/hm->numsegs; + mins[0] = (x+0)*subsize*hm->terrainscale; + maxs[0] = (x+1)*subsize*hm->terrainscale; for (y = 0; y < hm->numsegs; y++) { - mins[1] = (y+0)*hm->terrainscale*hm->terrainsize/hm->numsegs; - maxs[1] = (y+1)*hm->terrainscale*hm->terrainsize/hm->numsegs; - mins[2] = 0;//hm->mins[x+y*SECTIONS]; - mins[2] = 65535;//hm->maxs[x+y*SECTIONS]; + mins[1] = (y+0)*subsize*hm->terrainscale; + maxs[1] = (y+1)*subsize*hm->terrainscale; -// if (!BoundsIntersect(mins, maxs, r_refdef.vieworg, r_refdef.vieworg)) -// if (R_CullBox(mins, maxs)) -// continue; - -#ifdef DISPLISTS - if (!hm->displaylist[x+y*SECTIONS]) + mesh = &hm->mesh[x+y*SECTIONS]; + if (hm->modified[x+y*SECTIONS]) { - hm->displaylist[x+y*SECTIONS] = qglGenLists(1); - qglNewList(hm->displaylist[x+y*SECTIONS], GL_COMPILE_AND_EXECUTE); -#endif -#ifdef MULTITEXTURE - if (qglActiveTextureARB) + minx = x*subsize; + miny = y*subsize; + + hm->modified[x+y*SECTIONS] = false; + + hm->mins[x+y*SECTIONS] = 65536 * hm->heightscale; + hm->maxs[x+y*SECTIONS] = 0; + + if (!mesh->xyz_array) + mesh->xyz_array = BZ_Malloc(sizeof(vecV_t) * (subsize+1)*(subsize+1)); + if (!mesh->st_array) + mesh->st_array = BZ_Malloc(sizeof(vec2_t) * (subsize+1)*(subsize+1)); + if (!mesh->lmst_array) + mesh->lmst_array = BZ_Malloc(sizeof(vec2_t) * (subsize+1)*(subsize+1)); + mesh->numvertexes = 0; + /*64 quads across requires 65 verticies*/ + for (vx = 0; vx <= subsize; vx++) { - GL_MBind(0, hm->textures[x+y*SECTIONS]); - GL_MBind(1, hm->detailtexture); - qglEnable(GL_TEXTURE_2D); - - subsize = hm->terrainsize/SECTIONS; - minx = x*subsize; - miny = y*subsize; - - - qglBegin(GL_QUADS); - for (vx = 0; vx < subsize; vx++) + for (vy = 0; vy <= subsize; vy++) { - for (vy = 0; vy < subsize; vy++) - { - qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, vx/subsize, (vy+1)/subsize); - qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0, 1); - qglVertex3f((vx+minx)*hm->terrainscale, (vy+miny+1)*hm->terrainscale, hm->heights[vx + (vy+1)*hm->terrainsize]*hm->heightscale); - qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, (vx+1)/subsize, (vy+1)/subsize); - qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1, 1); - qglVertex3f((vx+minx+1)*hm->terrainscale, (vy+miny+1)*hm->terrainscale, hm->heights[vx+1 + (vy+1)*hm->terrainsize]*hm->heightscale); - qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, (vx+1)/subsize, vy/subsize); - qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1, 0); - qglVertex3f((vx+minx+1)*hm->terrainscale, (vy+miny)*hm->terrainscale, hm->heights[vx+1 + vy*hm->terrainsize]*hm->heightscale); - qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, vx/subsize, vy/subsize); - qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0, 0); - qglVertex3f((vx+minx)*hm->terrainscale, (vy+miny)*hm->terrainscale, hm->heights[vx + vy*hm->terrainsize]*hm->heightscale); - } + v = mesh->numvertexes++; + mesh->xyz_array[v][0] = (vx+minx)*hm->terrainscale; + mesh->xyz_array[v][1] = (vy+miny)*hm->terrainscale; + mesh->xyz_array[v][2] = hm->heights[(vx+minx) + (vy+miny)*hm->terrainsize]*hm->heightscale; + + if (hm->maxs[x+y*SECTIONS] < mesh->xyz_array[v][2]) + hm->maxs[x+y*SECTIONS] = mesh->xyz_array[v][2]; + if (hm->mins[x+y*SECTIONS] > mesh->xyz_array[v][2]) + hm->mins[x+y*SECTIONS] = mesh->xyz_array[v][2]; + + mesh->st_array[v][0] = mesh->xyz_array[v][0] / 64; + mesh->st_array[v][1] = mesh->xyz_array[v][1] / 64; + + mesh->lmst_array[v][0] = mesh->xyz_array[v][0] / 64; + mesh->lmst_array[v][1] = mesh->xyz_array[v][1] / 64; } - qglEnd(); - qglDisable(GL_TEXTURE_2D); - qglActiveTextureARB(GL_TEXTURE0_ARB); } - else -#endif - { //single texture - GL_MTBind(0, GL_TEXTURE_2D, hm->textures[x+y*SECTIONS]); - qglBegin(GL_QUADS); - subsize = hm->terrainsize/hm->numsegs; - minx = x*subsize; - miny = y*subsize; - for (vx = 0; vx < subsize; vx++) - { - for (vy = 0; vy < subsize; vy++) - { - qglTexCoord2f(vx/subsize, (vy+1)/subsize); - qglVertex3f((vx+minx)*hm->terrainscale, (vy+miny+1)*hm->terrainscale, hm->heights[vx+minx + (vy+miny+1)*hm->terrainsize]*hm->heightscale); - qglTexCoord2f((vx+1)/subsize, (vy+1)/subsize); - qglVertex3f((vx+minx+1)*hm->terrainscale, (vy+miny+1)*hm->terrainscale, hm->heights[vx+minx+1 + (vy+miny+1)*hm->terrainsize]*hm->heightscale); - qglTexCoord2f((vx+1)/subsize, vy/subsize); - qglVertex3f((vx+minx+1)*hm->terrainscale, (vy+miny)*hm->terrainscale, hm->heights[vx+minx+1 + (vy+miny)*hm->terrainsize]*hm->heightscale); - qglTexCoord2f(vx/subsize, vy/subsize); - qglVertex3f((vx+minx)*hm->terrainscale, (vy+miny)*hm->terrainscale, hm->heights[vx+minx + (vy+miny)*hm->terrainsize]*hm->heightscale); - } - } - qglEnd(); - GL_MTBind(0, GL_TEXTURE_2D, hm->detailtexture); - qglEnable(GL_BLEND); + if (!mesh->indexes) + mesh->indexes = BZ_Malloc(sizeof(index_t) * subsize*subsize*6); - qglBlendFunc (GL_ZERO, GL_SRC_COLOR); - qglBegin(GL_QUADS); - for (vx = 0; vx < subsize; vx++) + mesh->numindexes = 0; + for (vx = 0; vx < subsize; vx++) + { + for (vy = 0; vy < subsize; vy++) { - for (vy = 0; vy < subsize; vy++) - { - qglTexCoord2f(0, 1); - qglVertex3f((vx+minx)*hm->terrainscale, (vy+miny+1)*hm->terrainscale, hm->heights[vx+minx + (vy+miny+1)*hm->terrainsize]*hm->heightscale); - qglTexCoord2f(1, 1); - qglVertex3f((vx+minx+1)*hm->terrainscale, (vy+miny+1)*hm->terrainscale, hm->heights[vx+minx+1 + (vy+miny+1)*hm->terrainsize]*hm->heightscale); - qglTexCoord2f(1, 0); - qglVertex3f((vx+minx+1)*hm->terrainscale, (vy+miny)*hm->terrainscale, hm->heights[vx+minx+1 + (vy+miny)*hm->terrainsize]*hm->heightscale); - qglTexCoord2f(0, 0); - qglVertex3f((vx+minx)*hm->terrainscale, (vy+miny)*hm->terrainscale, hm->heights[vx+minx + (vy+miny)*hm->terrainsize]*hm->heightscale); - } + v = vx + vy*(subsize+1); + mesh->indexes[mesh->numindexes++] = v+0; + mesh->indexes[mesh->numindexes++] = v+1; + mesh->indexes[mesh->numindexes++] = v+subsize+1; + mesh->indexes[mesh->numindexes++] = v+1; + mesh->indexes[mesh->numindexes++] = v+1+subsize+1; + mesh->indexes[mesh->numindexes++] = v+subsize+1; } - qglEnd(); - qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - qglDisable(GL_BLEND); } -#ifdef DISPLISTS - qglEndList(); + + + //GL_BuildVBO(); } - else - { - qglCallList(hm->displaylist[x+y*SECTIONS]); - } -#endif + + mins[2] = hm->mins[x+y*SECTIONS]; + maxs[2] = hm->maxs[x+y*SECTIONS]; + + if (!BoundsIntersect(mins, maxs, r_refdef.vieworg, r_refdef.vieworg)) + if (R_CullBox(mins, maxs)) + continue; + + b = BE_GetTempBatch(); + if (!b) + continue; + b->ent = e; + b->shader = hm->shader; + b->flags = 0; + b->mesh = &hm->amesh[x+y*SECTIONS]; + b->mesh[0] = mesh; + b->meshes = 1; + b->buildmeshes = NULL; + b->skin = &b->shader->defaulttextures; + b->texture = NULL; + // vbo = b->vbo = hm->vbo[x+y*SECTIONS]; + b->vbo = NULL; + + b->next = batches[b->shader->sort]; + batches[b->shader->sort] = b; } } } -#endif unsigned int Heightmap_PointContentsHM(heightmap_t *hm, float clipmipsz, vec3_t org) { @@ -286,6 +296,7 @@ void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm) float x, y; float z; int sx, sy; + vec3_t d1, d2; x = org[0]/hm->terrainscale; y = org[1]/hm->terrainscale; @@ -299,23 +310,27 @@ void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm) //0, 1 //1, 1 //1, 0 - x = hm->heights[(sx+1)+(sy+1)*hm->terrainsize] - hm->heights[(sx+0)+(sy+1)*hm->terrainsize]; - y = hm->heights[(sx+1)+(sy+1)*hm->terrainsize] - hm->heights[(sx+1)+(sy+0)*hm->terrainsize]; + d1[0] = hm->terrainscale; + d1[1] = 0; + d1[2] = hm->heights[(sx+1)+(sy+1)*hm->terrainsize] - hm->heights[(sx+0)+(sy+1)*hm->terrainsize]; + d2[0] = 0; + d2[1] = hm->terrainscale; + d2[2] = hm->heights[(sx+1)+(sy+1)*hm->terrainsize] - hm->heights[(sx+1)+(sy+0)*hm->terrainsize]; } else { //0, 1 //1, 0 //0, 0 - x = hm->heights[(sx+1)+(sy+0)*hm->terrainsize] - hm->heights[(sx+0)+(sy+0)*hm->terrainsize]; - y = hm->heights[(sx+0)+(sy+1)*hm->terrainsize] - hm->heights[(sx+0)+(sy+0)*hm->terrainsize]; + d1[0] = hm->terrainscale; + d1[1] = 0; + d1[2] = hm->heights[(sx+0)+(sy+1)*hm->terrainsize] - hm->heights[(sx+0)+(sy+0)*hm->terrainsize]; + d2[0] = 0; + d2[1] = hm->terrainscale; + d2[2] = hm->heights[(sx+1)+(sy+0)*hm->terrainsize] - hm->heights[(sx+0)+(sy+0)*hm->terrainsize]; } - norm[0] = (-x*hm->heightscale)/hm->terrainscale; - norm[1] = (-y*hm->heightscale)/hm->terrainscale; - norm[2] = 1.0f/(float)sqrt(norm[0]*norm[0] + norm[1]*norm[1] + 1); - norm[0] *= norm[2]; - norm[1] *= norm[2]; + CrossProduct(d1, d2, norm); VectorNormalize(norm); } @@ -518,7 +533,7 @@ qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axi { vec3_t org; vec3_t dir; - int distleft; + float distleft; float dist; heightmap_t *hm = model->terrain; memset(trace, 0, sizeof(trace_t)); @@ -534,14 +549,14 @@ qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axi VectorCopy(start, org); VectorSubtract(end, start, dir); dist = VectorNormalize(dir); -/* if (dist < 10) + if (dist < 10 && dist) { //if less than 10 units, do at least 10 steps - VectorScale(dir, 10/dist, dir); + VectorScale(dir, 1/10.0f, dir); dist = 10; - }*/ + } distleft = dist; - while(distleft>=0) + while(distleft>0) { VectorAdd(org, dir, org); if (Heightmap_PointContentsHM(hm, mins[2], org) == FTECONTENTS_SOLID) @@ -554,7 +569,7 @@ qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axi trace->contents = Heightmap_PointContentsHM(hm, mins[2], end); - if (distleft < 0 && trace->contents != FTECONTENTS_SOLID) + if (distleft <= 0 && trace->contents != FTECONTENTS_SOLID) { //all the way trace->fraction = 1; VectorCopy(end, trace->endpos); @@ -619,12 +634,139 @@ int Heightmap_LeafForPoint (model_t *model, vec3_t point) //Heightmap_NativeBoxContents +enum +{ + ter_reload, + ter_save, + ter_set, + ter_smooth, + ter_raise, + ter_lower +}; +qboolean Heightmap_Edit(model_t *mod, int action, float *pos, float radius, float quant) +{ + unsigned short *tmp; + heightmap_t *hm = mod->terrain; + int size; + int x, y, min[2], max[2]; + float xd, yd, w; + vec2_t sc; + if (mod->type != mod_heightmap) + return false; + + size = hm->terrainsize; + + if (radius < 0.05) + radius = 0.05; + + sc[0] = pos[0] / hm->terrainscale; + sc[1] = pos[1] / hm->terrainscale; + radius = radius / hm->terrainscale; + quant /= hm->heightscale; + + min[0] = sc[0] - radius; + min[1] = sc[1] - radius; + max[0] = sc[0] + radius; + max[1] = sc[1] + radius; + + if (min[0] < 0) + min[0] = 0; + if (min[1] < 0) + min[1] = 0; + + if (max[0] > size) + max[0] = size; + if (max[1] < size) + max[1] = size; + + switch(action) + { + case ter_reload: + tmp = (unsigned short*)COM_LoadTempFile(hm->hmapname); + if (tmp) + x = com_filesize/2; + else + x = 0; + if (x > size*size) + x = size*size; + while (x-- > 0) + { + hm->heights[x] = LittleShort(tmp[x]); + } + break; + case ter_save: + tmp = Hunk_TempAlloc(size*size*2); + for (x = 0; x < size*size; x++) + { + tmp[x] = LittleShort(hm->heights[x]); + } + COM_WriteFile(hm->hmapname, tmp, size*size*2); + break; + case ter_set: + for (x = min[0]; x < max[0]; x++) + { + for (y = min[1]; y < max[1]; y++) + { + xd = sc[0] - x; + yd = sc[1] - y; + if (sqrt(xd*xd+yd*yd) < radius) + { + hm->heights[x + y*size] = quant; + hm->modified[(int)(x/(hm->terrainscale)) + (int)(y/(hm->terrainscale))*SECTIONS] = true; + } + } + } + break; + case ter_smooth: + case ter_raise: + for (x = min[0]; x < max[0]; x++) + { + for (y = min[1]; y < max[1]; y++) + { + xd = sc[0] - x; + yd = sc[1] - y; + w = sqrt(radius*radius - (xd*xd+yd*yd)); + if (w > 0) + { + w *= quant/radius; + hm->heights[x + y*size] += w; + hm->modified[(int)(x/(hm->terrainscale)) + (int)(y/(hm->terrainscale))*SECTIONS] = true; + } + } + } + break; + case ter_lower: + for (x = min[0]; x < max[0]; x++) + { + for (y = min[1]; y < max[1]; y++) + { + xd = sc[0] - x; + yd = sc[1] - y; + w = sqrt(radius*radius - (xd*xd+yd*yd)); + if (w > 0) + { + w *= quant/radius; + /*don't drop below 0*/ + if (hm->heights[x + y*size]-w < 0) + hm->heights[x + y*size] = 0; + else + hm->heights[x + y*size] -= w; + hm->modified[(int)(x/(hm->terrainscale)) + (int)(y/(hm->terrainscale))*SECTIONS] = true; + } + } + } + break; + } + + return true; +} + qboolean GL_LoadHeightmapModel (model_t *mod, void *buffer) { heightmap_t *hm; unsigned short *heightmap; int size; - int x; + int x, y; float skyrotate; vec3_t skyaxis; @@ -738,27 +880,51 @@ qboolean GL_LoadHeightmapModel (model_t *mod, void *buffer) mod->type = mod_heightmap; heightmap = (unsigned short*)COM_LoadTempFile(heightmapname); - - size = sqrt(com_filesize/2); - if (size % numsegs) + if (!heightmap) { - Con_Printf(CON_ERROR "%s, heightmap is not a multiple of %i\n", mod->name, numsegs); - return false; + size = 1024; + heightmap = Hunk_TempAlloc(size*size*2); + + for (x = 0; x < size; x++) + for (y = 0; y < size; y++) + { + heightmap[x+y*size] = 0; + } + } + else + { + size = sqrt(com_filesize/2); + if (size % numsegs) + { + Con_Printf(CON_ERROR "%s, heightmap is not a multiple of %i\n", mod->name, numsegs); + return false; + } } - hm = Hunk_Alloc(sizeof(*hm) + com_filesize); + hm = Hunk_Alloc(sizeof(*hm) + size*size*2); memset(hm, 0, sizeof(*hm)); + Q_strncpyz(hm->hmapname, heightmapname, sizeof(hm->hmapname)); hm->heights = (unsigned short*)(hm+1); for (x = 0; x < size*size; x++) { hm->heights[x] = LittleShort(heightmap[x]); } - memcpy(hm->heights, heightmap, com_filesize); hm->terrainsize = size; hm->terrainscale = worldsize; hm->heightscale = heightsize; hm->numsegs = numsegs; + hm->shader = R_RegisterShader(basetexname, + "{\n" + "{\n" + "map maps/test/ground.jpg\n" + "}\n" + "}\n" + ); + + hm->skyshader = R_RegisterCustom(va("skybox_%s", skyname), Shader_DefaultSkybox, NULL); + + mod->entities = COM_LoadHunkFile(entfile); if (qrenderer != QR_NONE) @@ -772,6 +938,7 @@ qboolean GL_LoadHeightmapModel (model_t *mod, void *buffer) for (y = 0; y < numsegs; y++) { hm->textures[x+y*SECTIONS] = R_LoadHiResTexture(va("%s%02ix%02i%s", basetexname, x, y, exttexname), "", IF_CLAMP|IF_NOGAMMA); + hm->modified[x+y*SECTIONS] = true; } } } diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index eae9e16ac..61a0326d3 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -659,6 +659,12 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) break; #endif +#ifdef INTERQUAKEMODELS + case ('I'<<0)+('N'<<8)+('T'<<16)+('E'<<24): + if (!Mod_LoadInterQuakeModel (mod, buf)) + continue; + break; +#endif //Binary Sprites #ifdef SP2MODELS @@ -3236,8 +3242,9 @@ void * RMod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum, pspriteframe->shader = R_RegisterShader(name, "{\n" "{\n" - "map $diffuse\n" - "alphafunc ge128\n" + "map $diffuse\n" + "alphafunc ge128\n" + "depthwrite\n" "rgbgen entity\n" "alphagen entity\n" "}\n" diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 65c104675..a8933f251 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -925,7 +925,7 @@ qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model); - +qboolean Heightmap_Edit(model_t *mod, int action, float *pos, float radius, float quant); #ifdef Q2BSPS diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index f94b8e56a..4c64ad8fa 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -117,7 +117,7 @@ void GLSCR_UpdateScreen (void) R2D_BrightenScreen(); if (key_dest == key_console) - Con_DrawConsole(vid_conheight.value/2, false); + Con_DrawConsole(vid.height/2, false); GL_EndRendering (); GL_DoSwap(); RSpeedEnd(RSPEED_TOTALREFRESH); diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index f746b0393..c92af57c2 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -227,6 +227,22 @@ static qboolean Shader_EvaluateCondition(char **ptr) else if (!Q_stricmp(token, "normalmap") ) conditiontrue = conditiontrue == !!gl_bump.value; + else if (!Q_stricmp(token, "gles") ) + { +#ifdef GLQUAKE + conditiontrue = conditiontrue == ((qrenderer == QR_OPENGL) && !!gl_config.gles); +#else + conditiontrue = conditiontrue == false; +#endif + } + else if (!Q_stricmp(token, "nofixed") ) + { +#ifdef GLQUAKE + conditiontrue = conditiontrue == ((qrenderer == QR_OPENGL) && !!gl_config.nofixedfunc); +#else + conditiontrue = conditiontrue == false; +#endif + } else if (!Q_stricmp(token, "glsl") ) { #ifdef GLQUAKE @@ -915,15 +931,15 @@ struct sbuiltin_s "}\n" "#endif\n" }, - {QR_OPENGL, 130, "defaultwall", - "#version 130\n" + {QR_OPENGL, 110, "defaultwall", + "!!cvarf gl_overbright\n" + "#version 110\n" "#ifdef VERTEX_SHADER\n" - "uniform mat4 m_modelview;\n" - "uniform mat4 m_projection;\n" - "in vec3 v_position;\n" - "in vec2 v_texcoord;\n" - "in vec2 v_lmcoord;\n" - "out vec2 tc, lm;\n" + "uniform mat4 m_modelview, m_projection;\n" + "attribute vec3 v_position;\n" + "attribute vec2 v_texcoord;\n" + "attribute vec2 v_lmcoord;\n" + "varying vec2 tc, lm;\n" "void main (void)\n" "{\n" @@ -939,14 +955,16 @@ struct sbuiltin_s //"uniform sampler2D s_t2;\n" /*tex_normalmap*/ //"uniform sampler2D s_t3;\n" /*tex_deluxmap*/ //"uniform sampler2D s_t4;\n" /*tex_fullbright*/ - "in vec2 tc, lm;\n" + "varying vec2 tc, lm;\n" + "uniform float cvar_gl_overbright;\n" "void main (void)\n" "{\n" - " gl_FragColor = texture2D(s_t0, tc) * texture2D(s_t1, lm);\n" + " gl_FragColor = texture2D(s_t0, tc) * texture2D(s_t1, lm) * vec4(cvar_gl_overbright, cvar_gl_overbright, cvar_gl_overbright, 1);\n" "}\n" "#endif\n" }, + /*FIXME: this doesn't match the gl3 version*/ {QR_OPENGL/*ES*/, 100, "defaultwall", "!!permu FULLBRIGHT\n" //"#version 100\n" @@ -1004,7 +1022,7 @@ struct sbuiltin_s "#ifdef FRAGMENT_SHADER\n" "uniform sampler2D watertexture;\n" "uniform mediump float e_time;\n" - "uniform lowp float r_wateralpha;\n" + "uniform lowp float cvar_r_wateralpha;\n" "void main (void)\n" "{\n" @@ -1013,7 +1031,7 @@ struct sbuiltin_s " ntc.t = tc.t + sin(tc.s+e_time)*0.125;\n" " lowp vec3 ts = vec3(texture2D(watertexture, ntc));\n" - " gl_FragColor = vec4(ts, r_wateralpha);\n" + " gl_FragColor = vec4(ts, cvar_r_wateralpha);\n" "}\n" "#endif\n" }, @@ -1022,17 +1040,21 @@ struct sbuiltin_s "#version 110\n" "varying vec2 tc;\n" "#ifdef VERTEX_SHADER\n" + "uniform mat4 m_modelview;\n" + "uniform mat4 m_projection;\n" + "attribute vec3 v_position;\n" + "attribute vec2 v_texcoord;\n" "void main (void)\n" "{\n" - " tc = gl_MultiTexCoord0.st;\n" - " gl_Position = ftransform();\n" + " tc = v_texcoord.st;\n" + " gl_Position = m_projection * m_modelview * vec4(v_position, 1.0);\n" "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" "uniform sampler2D s_t0;\n" "uniform float e_time;\n" - "uniform float r_wateralpha;\n" + "uniform float cvar_r_wateralpha;\n" "void main (void)\n" "{\n" @@ -1041,7 +1063,7 @@ struct sbuiltin_s " ntc.t = tc.t + sin(tc.s+e_time)*0.125;\n" " vec3 ts = vec3(texture2D(s_t0, ntc));\n" - " gl_FragColor = vec4(ts, r_wateralpha);\n" + " gl_FragColor = vec4(ts, cvar_r_wateralpha);\n" "}\n" "#endif\n" }, @@ -1091,12 +1113,15 @@ struct sbuiltin_s {QR_OPENGL, 110, "defaultsky", "#version 110\n" "#ifdef VERTEX_SHADER\n" + "uniform mat4 m_modelview;\n" + "uniform mat4 m_projection;\n" + "attribute vec3 v_position;\n" "varying vec3 pos;\n" "void main (void)\n" "{\n" - " pos = gl_Vertex.xyz;\n" - " gl_Position = ftransform();\n" + " pos = v_position.xyz;\n" + " gl_Position = m_projection * m_modelview * vec4(v_position, 1.0);\n" "}\n" "#endif\n" @@ -1447,7 +1472,7 @@ static void Shader_ProgAutoFields(program_t *prog, char **cvarfnames) if (!prog->handle[p].glsl) continue; GLSlang_UseProgram(prog->handle[p].glsl); - uniformloc = qglGetUniformLocationARB(prog->handle[p].glsl, u[i].name); + uniformloc = qglGetUniformLocationARB(prog->handle[p].glsl, va("cvar_%s", tmpname)); if (uniformloc != -1) qglUniform1fARB(uniformloc, cvar->value); } @@ -1791,6 +1816,7 @@ static qboolean ShaderPass_MapGen (shader_t *shader, shaderpass_t *pass, char *t { pass->texgen = T_GEN_DIFFUSE; pass->tcgen = TC_GEN_BASE; + shader->flags |= SHADER_NOIMAGE; } else if (!Q_stricmp (tname, "$normalmap")) { @@ -2626,6 +2652,7 @@ void Shader_Free (shader_t *shader) if (shader->bucket.data == shader) Hash_RemoveData(&shader_active_hash, shader->name, shader); + shader->bucket.data = NULL; #ifdef GLQUAKE if (qrenderer == QR_OPENGL && shader->prog) @@ -2657,6 +2684,25 @@ void Shader_Free (shader_t *shader) shader->numpasses = 0; } +void Shader_Reset(shader_t *s) +{ + char name[MAX_QPATH]; + int uses = s->uses; + shader_gen_t *defaultgen = s->generator; + const char *genargs = s->genargs; + texnums_t dt = s->defaulttextures; + Q_strncpyz(name, s->name, sizeof(name)); + Shader_Free(s); + memset(s, 0, sizeof(*s)); + + s->defaulttextures = dt; + s->generator = defaultgen; + s->genargs = genargs; + s->uses = uses; + Q_strncpyz(s->name, name, sizeof(s->name)); + Hash_Add(&shader_active_hash, s->name, s, &s->bucket); +} + void Shader_Shutdown (void) { int i; @@ -3057,14 +3103,9 @@ void Shader_Finish (shader_t *s) s->flags = 0; if (!(s->flags & SHADER_SKY)) { - char name[MAX_QPATH]; - Q_strncpyz(name, s->name, sizeof(name)); - Shader_Free(s); - memset(s, 0, sizeof(*s)); + Shader_Reset(s); - Q_strncpyz(s->name, name, sizeof(s->name)); - - Shader_DefaultScript(name, s, + Shader_DefaultScript(s->name, s, "{\n" "sort sky\n" "{\n" @@ -3078,6 +3119,9 @@ void Shader_Finish (shader_t *s) } } + if (TEXVALID(s->defaulttextures.base)) + s->flags &= ~SHADER_NOIMAGE; + if (!s->numpasses && !(s->flags & (SHADER_NODRAW|SHADER_SKY)) && !s->fog_dist) { pass = &s->passes[s->numpasses++]; @@ -3375,7 +3419,11 @@ void R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) /*dlights/realtime lighting needs some stuff*/ if (!TEXVALID(tn->base)) + { tn->base = R_LoadHiResTexture(shader->name, NULL, IF_NOALPHA); + } + if (TEXVALID(tn->base)) + shader->flags &= ~SHADER_NOIMAGE; if (gl_bump.ival) { @@ -3716,8 +3764,7 @@ void Shader_DefaultBSPQ1(char *shortname, shader_t *s, const void *args) return; builtin = NULL; /*if the r_skybox failed to load or whatever, reset and fall through and just use the regular sky*/ - Shader_Free(s); - memset (s, 0, sizeof(*s)); + Shader_Reset(s); } if (!builtin) builtin = ( @@ -3898,9 +3945,10 @@ void Shader_Default2D(char *shortname, shader_t *s, const void *genargs) { Shader_DefaultScript(shortname, s, "{\n" -#ifdef USE_EGL - "program default2d\n" -#endif + "if $nofixed\n" + "[\n" + "program default2d\n" + "]\n" "nomipmaps\n" "{\n" "clampmap $diffuse\n" @@ -3917,9 +3965,17 @@ void Shader_Default2D(char *shortname, shader_t *s, const void *genargs) { unsigned char data[4*4] = {0}; s->defaulttextures.base = R_LoadTexture8("black", 4, 4, data, 0, 0); + s->flags |= SHADER_NOIMAGE; + + s->width = 64; + s->height = 64; + } + else + { + s->flags &= ~SHADER_NOIMAGE; + s->width = image_width; + s->height = image_height; } - s->width = image_width; - s->height = image_height; } //loads a shader string into an existing shader object, and finalises it and stuff @@ -4010,10 +4066,7 @@ static qboolean Shader_ParseShader(char *shortname, char *usename, shader_t *s) return false; } - Shader_Free(s); - memset ( s, 0, sizeof( shader_t ) ); - Com_sprintf ( s->name, MAX_QPATH, "%s",usename ); // warning: format not a string literal and no format arguments - Hash_Add(&shader_active_hash, s->name, s, &s->bucket); + Shader_Reset(s); Shader_ReadShader(s, file); @@ -4037,6 +4090,10 @@ static int R_LoadShader ( char *name, shader_gen_t *defaultgen, const char *gena char shortname[MAX_QPATH]; shader_t *s; + if (!*name) + name = "gfx/white"; + + *(int*)shortname = 0; COM_StripExtension ( name, shortname, sizeof(shortname)); COM_CleanUpPath(shortname); @@ -4071,6 +4128,10 @@ static int R_LoadShader ( char *name, shader_gen_t *defaultgen, const char *gena s = &r_shaders[f]; + Q_strncpyz(s->name, shortname, sizeof(s->name)); + s->generator = defaultgen; + s->genargs = genargs; + if (ruleset_allow_shaders.ival) { #ifdef GLQUAKE @@ -4080,8 +4141,6 @@ static int R_LoadShader ( char *name, shader_gen_t *defaultgen, const char *gena { if (Shader_ParseShader(va("%s_gles2", shortname), shortname, s)) { - s->generator = defaultgen; - s->genargs = genargs; return f; } } @@ -4089,8 +4148,6 @@ static int R_LoadShader ( char *name, shader_gen_t *defaultgen, const char *gena { if (Shader_ParseShader(va("%s_glsl3", shortname), shortname, s)) { - s->generator = defaultgen; - s->genargs = genargs; return f; } } @@ -4098,8 +4155,6 @@ static int R_LoadShader ( char *name, shader_gen_t *defaultgen, const char *gena { if (Shader_ParseShader(va("%s_glsl", shortname), shortname, s)) { - s->generator = defaultgen; - s->genargs = genargs; return f; } } @@ -4111,8 +4166,6 @@ static int R_LoadShader ( char *name, shader_gen_t *defaultgen, const char *gena { if (Shader_ParseShader(va("%s_hlsl", shortname), shortname, s)) { - s->generator = defaultgen; - s->genargs = genargs; return f; } } @@ -4120,18 +4173,16 @@ static int R_LoadShader ( char *name, shader_gen_t *defaultgen, const char *gena #endif if (Shader_ParseShader(shortname, shortname, s)) { - s->generator = defaultgen; - s->genargs = genargs; return f; } } // make a default shader - if (defaultgen) + if (s->generator) { - memset(s, 0, sizeof(shader_t)); - Com_sprintf(s->name, MAX_QPATH, "%s", shortname); // warning: format not a string literal and no format arguments + Shader_Reset(s); + if (!strcmp(shortname, "textures/common/clip")) Shader_DefaultScript(shortname, s, "{\n" @@ -4139,13 +4190,13 @@ static int R_LoadShader ( char *name, shader_gen_t *defaultgen, const char *gena "surfaceparm nodlight\n" "}\n"); else - defaultgen(shortname, s, genargs); - Hash_Add(&shader_active_hash, s->name, s, &s->bucket); - s->generator = defaultgen; - s->genargs = genargs; - + s->generator(shortname, s, s->genargs); return f; } + else + { + r_shaders[i].uses = 0; + } return -1; } @@ -4154,9 +4205,6 @@ void Shader_DoReload(void) shader_t *s; unsigned int i; char shortname[MAX_QPATH]; - shader_gen_t *defaultgen; - const char *genargs; - texnums_t oldtn; if (shader_rescan_needed && ruleset_allow_shaders.ival) { @@ -4182,10 +4230,6 @@ void Shader_DoReload(void) if (!s->uses) continue; - defaultgen = s->generator; - genargs = s->genargs; - oldtn = s->defaulttextures; - strcpy(shortname, s->name); if (ruleset_allow_shaders.ival) { @@ -4194,33 +4238,20 @@ void Shader_DoReload(void) { if (Shader_ParseShader(va("%s_glsl", shortname), shortname, s)) { - s->generator = defaultgen; - s->genargs = genargs; - R_BuildDefaultTexnums(&oldtn, s); continue; } } #endif if (Shader_ParseShader(shortname, shortname, s)) { - s->generator = defaultgen; - s->genargs = genargs; - R_BuildDefaultTexnums(&oldtn, s); continue; } } if (s->generator) { - Shader_Free(s); - memset ( s, 0, sizeof( shader_t ) ); + Shader_Reset(s); - defaultgen(shortname, s, genargs); - - s->generator = defaultgen; - s->genargs = genargs; - Com_sprintf ( s->name, MAX_QPATH, "%s", shortname ); // warning: format not a string literal and no format arguments - Hash_Add(&shader_active_hash, s->name, s, &s->bucket); - R_BuildDefaultTexnums(&oldtn, s); + s->generator(shortname, s, s->genargs); } } } diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index a17465596..0705182db 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -714,48 +714,25 @@ static void SHM_MarkLeavesQ2(dlight_t *dl, unsigned char *lvis, unsigned char *v } #endif -static void SHM_MarkLeavesQ1(dlight_t *dl, unsigned char *lvis, unsigned char *vvis) +static void SHM_MarkLeavesQ1(dlight_t *dl, unsigned char *lvis) { mnode_t *node; int i; sh_shadowframe++; - if (!dl->die || !vvis) + //variation on mark leaves + for (i=0 ; inumleafs ; i++) { - //static - //variation on mark leaves - for (i=0 ; inumleafs ; i++) + if (lvis[i>>3] & (1<<(i&7))) { - if (lvis[i>>3] & (1<<(i&7)))// && vvis[i>>3] & (1<<(i&7))) + node = (mnode_t *)&cl.worldmodel->leafs[i+1]; + do { - node = (mnode_t *)&cl.worldmodel->leafs[i+1]; - do - { - if (node->shadowframe == sh_shadowframe) - break; - node->shadowframe = sh_shadowframe; - node = node->parent; - } while (node); - } - } - } - else - { - //dynamic lights will be discarded after this frame anyway, so only include leafs that are visible - //variation on mark leaves - for (i=0 ; inumleafs ; i++) - { - if (lvis[i>>3] & vvis[i>>3] & (1<<(i&7))) - { - node = (mnode_t *)&cl.worldmodel->leafs[i+1]; - do - { - if (node->shadowframe == sh_shadowframe) - break; - node->shadowframe = sh_shadowframe; - node = node->parent; - } while (node); - } + if (node->shadowframe == sh_shadowframe) + break; + node->shadowframe = sh_shadowframe; + node = node->parent; + } while (node); } } } @@ -893,7 +870,7 @@ static struct shadowmesh_s *SHM_BuildShadowVolumeMesh(dlight_t *dl, unsigned cha if (cl.worldmodel->fromgame == fg_quake || cl.worldmodel->fromgame == fg_halflife) { SHM_BeginShadowMesh(dl); - SHM_MarkLeavesQ1(dl, lvis, vvis); + SHM_MarkLeavesQ1(dl, lvis); SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes); } #ifdef Q3BSPS @@ -980,6 +957,8 @@ static struct shadowmesh_s *SHM_BuildShadowVolumeMesh(dlight_t *dl, unsigned cha static qboolean Sh_VisOverlaps(qbyte *v1, qbyte *v2) { int i, m; + if (!v2) + return false; m = (cl.worldmodel->numleafs-1)>>3; for (i=0 ; i= 2) /*|| - (!gl_config.gles && gl_config.glversion >= 3 && noncompat)*/; + if (gl_config.gles) + gl_config.nofixedfunc = gl_config.glversion >= 2; + else + { + /*in gl3.0 things are depricated but not removed*/ + /*in gl3.1 depricated things are removed unless compatibility is present*/ + if (gl_config.glversion >= 3.1) + gl_config.nofixedfunc = !GL_CheckExtension("GL_ARB_compatibility"); + else + gl_config.nofixedfunc = false; + } //multitexture gl_mtexable = false; @@ -1022,6 +1031,16 @@ void GL_Init(void *(*getglfunction) (char *name)) qglDrawRangeElements = GL_DrawRangeElementsEmul; } + else if (gl_config.nofixedfunc) + { + qglLoadMatrixf = NULL; + qglPolygonMode = NULL; + qglShadeModel = NULL; + qglDepthRange = NULL; + + qglEnableClientState = GL_ClientStateStub; + qglDisableClientState = GL_ClientStateStub; + } qglClearColor (0,0,0,0); //clear to black so that it looks a little nicer on start. qglClear(GL_COLOR_BUFFER_BIT); diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index e6f248234..681223204 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -1001,7 +1001,7 @@ qboolean VID_AttachGL (rendererstate_t *info) if ((opengl3 = qwglCreateContextAttribsARB(maindc, NULL, attribs))) { - qwglMakeCurrent(NULL, NULL); + qwglMakeCurrent(maindc, NULL); qwglDeleteContext(baseRC); baseRC = opengl3; diff --git a/engine/gl/gl_warp.c b/engine/gl/gl_warp.c index 5f24c5dbc..509937ea6 100644 --- a/engine/gl/gl_warp.c +++ b/engine/gl/gl_warp.c @@ -447,7 +447,7 @@ static void gl_skyspherecalc(int skytype) static void GL_SkyForceDepth(batch_t *batch) { - if (!cls.allow_skyboxes) //allow a little extra fps. + if (!cls.allow_skyboxes && batch->texture) //allow a little extra fps. { BE_SelectMode(BEM_DEPTHONLY); BE_DrawMesh_List(batch->shader, batch->meshes-batch->firstmesh, batch->mesh+batch->firstmesh, &batch->texture->vbo, &batch->shader->defaulttextures, batch->flags); diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 60bea31b6..8f6f02351 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -342,7 +342,7 @@ void GLQ3_LightGrid(model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_a // gl_heightmap.c // #ifdef GLQUAKE -void GL_DrawHeightmapModel (entity_t *e); +void GL_DrawHeightmapModel (batch_t **batch, entity_t *e); qboolean GL_LoadHeightmapModel (model_t *mod, void *buffer); #endif diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 5e2765b97..53f7ff237 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -367,7 +367,7 @@ struct shader_s SHADER_DEFORMV_BULGE = 1 << 5, SHADER_AUTOSPRITE = 1 << 6, SHADER_FLARE = 1 << 7, -// SHADER_REMOVED = 1 << 8, + SHADER_NOIMAGE = 1 << 8, SHADER_ENTITY_MERGABLE = 1 << 9, SHADER_VIDEOMAP = 1 << 10, SHADER_DEPTHWRITE = 1 << 11, diff --git a/engine/http/ftpserver.c b/engine/http/ftpserver.c index 7c74eb0ef..929055d74 100644 --- a/engine/http/ftpserver.c +++ b/engine/http/ftpserver.c @@ -525,18 +525,20 @@ iwboolean FTP_ServerThinkForConnection(FTPclient_t *cl) } if (cl->dataislisten) //accept a connect. { + int err; int _true = true; int temp; struct sockaddr_in adr; int adrlen = sizeof(adr); temp = accept(cl->datasock, (struct sockaddr *)&adr, &adrlen); + err = qerrno; closesocket(cl->datasock); cl->datasock = temp; cl->dataislisten = false; if (cl->datasock == INVALID_SOCKET) { - QueueMessageva (cl, "425 Your client connected too slowly - %i.\r\n", qerrno); + QueueMessageva (cl, "425 Your client connected too slowly - %i.\r\n", err); continue; } else diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index fff0b9532..5164c5dad 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -49,11 +49,11 @@ cont: //last statement may have been a breakpoint st = pr_statements + s; reeval: + switch (st->op & ~0x8000) #else st++; -#endif - switch (st->op) +#endif { case OP_ADD_F: OPC->_float = OPA->_float + OPB->_float; @@ -1109,14 +1109,6 @@ if (pr_typecurrent != 0) st = &pr_statements[s]; //let the user move execution pr_xstatement = s = st-pr_statements; -#if 0 //fakeop stuff - not practical, the rest of the code is more optimised, st needs to point at the correct statement - memcpy(&fakeop, st, sizeof(dstatement_t)); //don't hit the new statement as a break point, cos it's probably the same one. - fakeop.op &= ~0x8000; - st = &fakeop; //a little remapping... -#else - st->op &= ~0x8000; //just remove the breakpoint and go around again, but this time in the debugger. -#endif - goto reeval; //reexecute } pr_xstatement = st-pr_statements; diff --git a/engine/qclib/initlib.c b/engine/qclib/initlib.c index d0f0fe242..eeb214e26 100644 --- a/engine/qclib/initlib.c +++ b/engine/qclib/initlib.c @@ -252,7 +252,44 @@ func_t PR_FindFunc(progfuncs_t *progfuncs, char *funcname, progsnum_t pnum) return 0; } -eval_t *PR_FindGlobal(progfuncs_t *progfuncs, char *globname, progsnum_t pnum) +void QC_FindPrefixedGlobals(progfuncs_t *progfuncs, char *prefix, void (*found) (progfuncs_t *progfuncs, char *name, union eval_s *val, etype_t type) ) +{ + unsigned int i; + ddef16_t *def16; + ddef32_t *def32; + int len = strlen(prefix); + unsigned int pnum; + + for (pnum = 0; pnum < maxprogs; pnum++) + { + if (!pr_progstate[pnum].progs) + continue; + + switch(pr_progstate[pnum].structtype) + { + case PST_DEFAULT: + case PST_KKQWSV: + for (i=1 ; inumglobaldefs ; i++) + { + def16 = &pr_progstate[pnum].globaldefs16[i]; + if (!strncmp(def16->s_name+progfuncs->stringtable,prefix, len)) + found(progfuncs, def16->s_name+progfuncs->stringtable, (eval_t *)&pr_progstate[pnum].globals[def16->ofs], def16->type); + } + break; + case PST_QTEST: + case PST_FTE32: + for (i=1 ; inumglobaldefs ; i++) + { + def32 = &pr_progstate[pnum].globaldefs32[i]; + if (!strncmp(def32->s_name+progfuncs->stringtable,prefix, len)) + found(progfuncs, def32->s_name+progfuncs->stringtable, (eval_t *)&pr_progstate[pnum].globals[def32->ofs], def32->type); + } + break; + } + } +} + +eval_t *PR_FindGlobal(progfuncs_t *progfuncs, char *globname, progsnum_t pnum, etype_t *type) { unsigned int i; ddef16_t *var16; @@ -266,7 +303,7 @@ eval_t *PR_FindGlobal(progfuncs_t *progfuncs, char *globname, progsnum_t pnum) { if (!pr_progstate[i].progs) continue; - ev = PR_FindGlobal(progfuncs, globname, i); + ev = PR_FindGlobal(progfuncs, globname, i, type); if (ev) return ev; } @@ -281,12 +318,16 @@ eval_t *PR_FindGlobal(progfuncs_t *progfuncs, char *globname, progsnum_t pnum) if (!(var16 = ED_FindGlobalFromProgs16(progfuncs, globname, pnum))) return NULL; + if (type) + *type = var16->type; return (eval_t *)&pr_progstate[pnum].globals[var16->ofs]; case PST_QTEST: case PST_FTE32: if (!(var32 = ED_FindGlobalFromProgs32(progfuncs, globname, pnum))) return NULL; + if (type) + *type = var32->type; return (eval_t *)&pr_progstate[pnum].globals[var32->ofs]; } Sys_Error("Error with def size (PR_FindGlobal)"); @@ -646,7 +687,8 @@ progfuncs_t deffuncs = { PR_StringToNative, 0, PR_QueryField, - QC_ClearEdict + QC_ClearEdict, + QC_FindPrefixedGlobals }; #undef printf diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index 7bbae0dc1..a67b36851 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -502,10 +502,17 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val) sprintf (line, "%s", PR_StringToNative(progfuncs, val->string)); break; case ev_entity: -// if (val->edict >= maxedicts) + fielddef = ED_FindField(progfuncs, "classname"); + if (fielddef && val->edict < sv_num_edicts) + { + edictrun_t *ed; + string_t *v; + ed = (edictrun_t *)EDICT_NUM(progfuncs, val->edict); + v = (string_t *)((char *)edvars(ed) + fielddef->ofs*4); + sprintf (line, "entity %i(%s)", val->edict, PR_StringToNative(progfuncs, *v)); + } + else sprintf (line, "entity %i", val->edict); -// else -// sprintf (line, "entity %i", NUM_FOR_EDICT(progfuncs, (struct edict_s *)PROG_TO_EDICT(progfuncs, val->edict)) ); break; case ev_function: if (!val->function) @@ -3095,7 +3102,7 @@ retry: if (progfuncs->stringtablesize + progfuncs->stringtable < pr_strings + pr_progs->numstrings) progfuncs->stringtablesize = (pr_strings + pr_progs->numstrings) - progfuncs->stringtable; - eval = PR_FindGlobal(progfuncs, "thisprogs", progstype); + eval = PR_FindGlobal(progfuncs, "thisprogs", progstype, NULL); if (eval) eval->prog = progstype; @@ -3157,7 +3164,7 @@ retry: break; } - eval = PR_FindGlobal(progfuncs, "__ext__fasttrackarrays", PR_CURRENT); + eval = PR_FindGlobal(progfuncs, "__ext__fasttrackarrays", PR_CURRENT, NULL); if (eval) //we support these opcodes eval->_float = true; diff --git a/engine/qclib/pr_multi.c b/engine/qclib/pr_multi.c index 1cac75dbd..cc49641b8 100644 --- a/engine/qclib/pr_multi.c +++ b/engine/qclib/pr_multi.c @@ -90,6 +90,8 @@ progsnum_t PR_LoadProgs(progfuncs_t *progfuncs, char *s, int headercrc, builtin_ { current_progstate->builtins = builtins; current_progstate->numbuiltins = numbuiltins; + if (a <= progfuncs->numprogs) + progfuncs->numprogs = a+1; #ifdef QCJIT if (prinst->usejit) diff --git a/engine/qclib/progsint.h b/engine/qclib/progsint.h index e1c25dcc5..e6d170482 100644 --- a/engine/qclib/progsint.h +++ b/engine/qclib/progsint.h @@ -445,7 +445,7 @@ var(unsigned int, addressablesize); } prinst_t; extern vec3_t vec3_origin; -eval_t *PR_FindGlobal(progfuncs_t *prfuncs, char *globname, progsnum_t pnum); +eval_t *PR_FindGlobal(progfuncs_t *prfuncs, char *globname, progsnum_t pnum, etype_t *type); ddef16_t *ED_FindTypeGlobalFromProgs16 (progfuncs_t *progfuncs, char *name, progsnum_t prnum, int type); ddef32_t *ED_FindTypeGlobalFromProgs32 (progfuncs_t *progfuncs, char *name, progsnum_t prnum, int type); ddef16_t *ED_FindGlobalFromProgs16 (progfuncs_t *progfuncs, char *name, progsnum_t prnum); diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index 8a0f94d37..1e9b61255 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -86,7 +86,7 @@ struct progfuncs_s { char *(*saveent) (progfuncs_t *prinst, char *buf, int *size, struct edict_s *ed); //will save just one entities vars struct edict_s *(*restoreent) (progfuncs_t *prinst, char *buf, int *size, struct edict_s *ed); //will restore the entity that had it's values saved (can use NULL for ed) - union eval_s *(*FindGlobal) (progfuncs_t *prinst, char *name, progsnum_t num); //find a pointer to the globals value + union eval_s *(*FindGlobal) (progfuncs_t *prinst, char *name, progsnum_t num, etype_t *type); //find a pointer to the globals value char *(*AddString) (progfuncs_t *prinst, char *val, int minlength); //dump a string into the progs memory (for setting globals and whatnot) void *(*Tempmem) (progfuncs_t *prinst, int ammount, char *whatfor); //grab some mem for as long as the progs stays loaded @@ -137,6 +137,7 @@ struct progfuncs_s { int (*QueryField) (progfuncs_t *prinst, unsigned int fieldoffset, etype_t *type, char **name, evalc_t *fieldcache); //find info on a field definition at an offset void (*EntClear) (progfuncs_t *progfuncs, struct edict_s *e); + void (*FindPrefixGlobals) (progfuncs_t *progfuncs, char *prefix, void (*found) (progfuncs_t *progfuncs, char *name, union eval_s *val, etype_t type) ); }; typedef struct progexterns_s { @@ -249,7 +250,7 @@ typedef union eval_s #define PR_PrintEdict(pf,ed) (*pf->PrintEdict) (pf, ed) #define PR_FindFunction(pf, name, num) (*pf->FindFunction) (pf, name, num) -#define PR_FindGlobal(pf, name, progs) (*pf->FindGlobal) (pf, name, progs) +#define PR_FindGlobal(pf, name, progs, type) (*pf->FindGlobal) (pf, name, progs, type) #define PR_AddString(pf, ed, len) (*pf->AddString) (pf, ed, len) #define PR_Alloc(pf,size) (*pf->Tempmem) (pf, size) diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 6427d684a..9bdd11c42 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -178,7 +178,6 @@ extern char qccmsourcedir[]; void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath) { char fullname[1024]; - char *stripfrom; int doubledots; char *end = fullname; @@ -187,6 +186,7 @@ void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath) return; doubledots = 0; + /*count how far up we need to go*/ while(!strncmp(newfile, "../", 3) || !strncmp(newfile, "..\\", 3)) { newfile+=3; @@ -195,26 +195,31 @@ void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath) currentfile += strlen(rootpath); //could this be bad? - for(stripfrom = currentfile+strlen(currentfile)-1; stripfrom>currentfile; stripfrom--) - { - if (*stripfrom == '/' || *stripfrom == '\\') - { - if (doubledots>0) - doubledots--; - else - { - stripfrom++; - break; - } - } - } - strcpy(end, rootpath); end = end+strlen(end); + strcpy(fullname, rootpath); + end = fullname+strlen(end); if (*fullname && end[-1] != '/') { strcpy(end, "/"); end = end+strlen(end); } - strncpy(end, currentfile, stripfrom - currentfile); end += stripfrom - currentfile; *end = '\0'; + strcpy(end, currentfile); + end = end+strlen(end); + + while (end > fullname) + { + end--; + /*stop at the slash, unless we're meant to go further*/ + if (*end == '/' || *end == '\\') + { + if (!doubledots) + { + end++; + break; + } + doubledots--; + } + } + strcpy(end, newfile); QCC_Include(fullname); diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 694d1149e..669cb6f2d 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -2858,7 +2858,7 @@ void QCC_main (int argc, char **argv) //as part of the quake engine MAX_REGS = 65536; MAX_STRINGS = 1000000; - MAX_GLOBALS = 32768; + MAX_GLOBALS = 65535; MAX_FIELDS = 2048; MAX_STATEMENTS = 0x80000; MAX_FUNCTIONS = 16384; diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index 903ec5560..7fb83a5f6 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -575,6 +575,7 @@ static int multicastpos; //writecoord*3 offset static int multicasttype; static int requireextension; static qboolean ignoreprotocol; +static int te_515sevilhackworkaround; #define svc_setfrags 14 #define svc_updatecolors 17 @@ -713,6 +714,22 @@ void NPP_NQFlush(void) case svc_temp_entity: switch (buffer[1]) { + default: + if (te_515sevilhackworkaround) + { + /*shift the data up by two bytes, but don't care about the first byte*/ + memmove(buffer+3, buffer+1, bufferlen-1); + + /*replace the svc itself*/ + buffer[0] = svcfte_cgamepacket; + + /*add a length in the 2nd/3rd bytes*/ + buffer[1] = (bufferlen-1); + buffer[2] = (bufferlen-1) >> 8; + + bufferlen += 2; + } + break; case TENQ_EXPLOSION2: //happens with rogue. bufferlen -= 2; //trim the colour buffer[1] = TE_EXPLOSION; @@ -852,6 +869,7 @@ void NPP_NQWriteByte(int dest, qbyte data) //replacement write func (nq to qw) break; case svc_sound: case svc_temp_entity: + te_515sevilhackworkaround = false; break; case svc_setangle: protocollen = sizeof(qbyte) + destprim->anglesize*3; @@ -1044,6 +1062,7 @@ void NPP_NQWriteByte(int dest, qbyte data) //replacement write func (nq to qw) default: protocollen = sizeof(buffer); + te_515sevilhackworkaround = true; Con_Printf("NQWriteByte: bad tempentity %i\n", data); PR_StackTrace(svprogfuncs); break; @@ -1456,6 +1475,22 @@ void NPP_QWFlush(void) case svc_temp_entity: switch(minortype) { + default: + if (te_515sevilhackworkaround) + { + /*shift the data up by two bytes*/ + memmove(buffer+3, buffer+1, bufferlen-1); + + /*replace the svc itself*/ + buffer[0] = svcfte_cgamepacket; + + /*add a length in the 2nd/3rd bytes*/ + buffer[1] = (bufferlen-1); + buffer[2] = (bufferlen-1) >> 8; + + bufferlen += 2; + } + break; case TEQW_LIGHTNINGBLOOD: case TEQW_BLOOD: //needs to be converted to a particle { diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 96efdeba4..2fd6da43c 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -61,6 +61,7 @@ cvar_t pr_fixbrokenqccarrays = SCVARF("pr_fixbrokenqccarrays", "1", CVAR_LATCH); cvar_t pr_maxedicts = SCVARF("pr_maxedicts", "2048", CVAR_LATCH); cvar_t pr_no_playerphysics = SCVARF("pr_no_playerphysics", "0", CVAR_LATCH); +cvar_t pr_no_parsecommand = SCVARF("pr_no_parsecommand", "0", 0); cvar_t progs = CVARAF("progs", "", "sv_progs", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_NOTFROMSERVER); cvar_t qc_nonetaccess = SCVAR("qc_nonetaccess", "0"); //prevent write_... builtins from doing anything. This means we can run any mod, specific to any engine, on the condition that it also has a qw or nq crc. @@ -496,6 +497,9 @@ void PR_Deinit(void) Z_FreeTags(Z_QC_TAG); } +#ifdef TEXTEDITOR + Editor_ProgsKilled(svprogfuncs); +#endif svprogfuncs=NULL; //clear out function pointers (so changing game modes cannot lead to confusions) @@ -524,12 +528,12 @@ void PR_LoadGlabalStruct(void) int i; int *v; nqglobalvars_t *pr_globals = pr_nqglobal_struct; -#define globalfloat(need,name) ((nqglobalvars_t*)pr_nqglobal_struct)->name = (float *)PR_FindGlobal(svprogfuncs, #name, 0); if (need && !((nqglobalvars_t*)pr_globals)->name) SV_Error("Could not find \""#name"\" export in progs\n"); -#define globalint(need,name) ((nqglobalvars_t*)pr_globals)->name = (int *)PR_FindGlobal(svprogfuncs, #name, 0); if (need && !((nqglobalvars_t*)pr_globals)->name) SV_Error("Could not find export \""#name"\" in progs\n"); -#define globalstring(need,name) ((nqglobalvars_t*)pr_globals)->name = (int *)PR_FindGlobal(svprogfuncs, #name, 0); if (need && !((nqglobalvars_t*)pr_globals)->name) SV_Error("Could not find export \""#name"\" in progs\n"); -#define globalvec(need,name) ((nqglobalvars_t*)pr_globals)->V_##name = (vec3_t *)PR_FindGlobal(svprogfuncs, #name, 0); if (need && !((nqglobalvars_t*)pr_globals)->V_##name) SV_Error("Could not find export \""#name"\" in progs\n"); -#define globalvec_(need,name) ((nqglobalvars_t*)pr_globals)->name = (vec3_t *)PR_FindGlobal(svprogfuncs, #name, 0); if (need && !((nqglobalvars_t*)pr_globals)->name) SV_Error("Could not find export \""#name"\" in progs\n"); -#define globalfunc(need,name) ((nqglobalvars_t*)pr_globals)->name = (func_t *)PR_FindGlobal(svprogfuncs, #name, 0); if (need && !((nqglobalvars_t*)pr_globals)->name) {static func_t strippedout; strippedout = PR_FindFunction(svprogfuncs, #name, 0); if (strippedout) ((nqglobalvars_t*)pr_globals)->name = &strippedout; else SV_Error("Could not find function \""#name"\" in progs\n"); } +#define globalfloat(need,name) ((nqglobalvars_t*)pr_nqglobal_struct)->name = (float *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !((nqglobalvars_t*)pr_globals)->name) SV_Error("Could not find \""#name"\" export in progs\n"); +#define globalint(need,name) ((nqglobalvars_t*)pr_globals)->name = (int *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !((nqglobalvars_t*)pr_globals)->name) SV_Error("Could not find export \""#name"\" in progs\n"); +#define globalstring(need,name) ((nqglobalvars_t*)pr_globals)->name = (int *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !((nqglobalvars_t*)pr_globals)->name) SV_Error("Could not find export \""#name"\" in progs\n"); +#define globalvec(need,name) ((nqglobalvars_t*)pr_globals)->V_##name = (vec3_t *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !((nqglobalvars_t*)pr_globals)->V_##name) SV_Error("Could not find export \""#name"\" in progs\n"); +#define globalvec_(need,name) ((nqglobalvars_t*)pr_globals)->name = (vec3_t *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !((nqglobalvars_t*)pr_globals)->name) SV_Error("Could not find export \""#name"\" in progs\n"); +#define globalfunc(need,name) ((nqglobalvars_t*)pr_globals)->name = (func_t *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !((nqglobalvars_t*)pr_globals)->name) {static func_t strippedout; strippedout = PR_FindFunction(svprogfuncs, #name, 0); if (strippedout) ((nqglobalvars_t*)pr_globals)->name = &strippedout; else SV_Error("Could not find function \""#name"\" in progs\n"); } // globalint(pad); globalint (true, self); //we need the qw ones, but any in standard quake and not quakeworld, we don't really care about. globalint (true, other); @@ -587,7 +591,7 @@ void PR_LoadGlabalStruct(void) memset(&evalc_pitch_speed, 0, sizeof(evalc_pitch_speed)); for (i = 0; i < NUM_SPAWN_PARMS; i++) - spawnparamglobals[i] = (float *)PR_FindGlobal(svprogfuncs, va("parm%i", i+1), 0); + spawnparamglobals[i] = (float *)PR_FindGlobal(svprogfuncs, va("parm%i", i+1), 0, NULL); #define ensurefloat(name,var) if (!((nqglobalvars_t*)pr_globals)->name) ((nqglobalvars_t*)pr_globals)->name = &var; @@ -599,19 +603,19 @@ void PR_LoadGlabalStruct(void) // qtest renames and missing variables if (!((nqglobalvars_t*)pr_globals)->V_trace_plane_normal) { - ((nqglobalvars_t*)pr_globals)->V_trace_plane_normal = (vec3_t *)PR_FindGlobal(svprogfuncs, "trace_normal", 0); + ((nqglobalvars_t*)pr_globals)->V_trace_plane_normal = (vec3_t *)PR_FindGlobal(svprogfuncs, "trace_normal", 0, NULL); if (!((nqglobalvars_t*)pr_globals)->V_trace_plane_normal) SV_Error("Could not find export trace_plane_normal in progs\n"); } if (!((nqglobalvars_t*)pr_globals)->V_trace_endpos) { - ((nqglobalvars_t*)pr_globals)->V_trace_endpos = (vec3_t *)PR_FindGlobal(svprogfuncs, "trace_impact", 0); + ((nqglobalvars_t*)pr_globals)->V_trace_endpos = (vec3_t *)PR_FindGlobal(svprogfuncs, "trace_impact", 0, NULL); if (!((nqglobalvars_t*)pr_globals)->V_trace_endpos) SV_Error("Could not find export trace_endpos in progs\n"); } if (!((nqglobalvars_t*)pr_globals)->trace_fraction) { - ((nqglobalvars_t*)pr_globals)->trace_fraction = (float *)PR_FindGlobal(svprogfuncs, "trace_frac", 0); + ((nqglobalvars_t*)pr_globals)->trace_fraction = (float *)PR_FindGlobal(svprogfuncs, "trace_frac", 0, NULL); if (!((nqglobalvars_t*)pr_globals)->trace_fraction) SV_Error("Could not find export trace_fraction in progs\n"); } @@ -669,7 +673,7 @@ void PR_LoadGlabalStruct(void) QC_AddSharedVar(svprogfuncs, (int *)((nqglobalvars_t*)pr_nqglobal_struct)->other-v, 1); QC_AddSharedVar(svprogfuncs, (int *)((nqglobalvars_t*)pr_nqglobal_struct)->time-v, 1); - pr_items2 = !!PR_FindGlobal(svprogfuncs, "items2", 0); + pr_items2 = !!PR_FindGlobal(svprogfuncs, "items2", 0, NULL); SV_ClearQCStats(); @@ -826,6 +830,8 @@ progsnum_t AddProgs(char *name) Con_Printf("Loaded %s\n", name); + PR_AutoCvarSetup(svprogfuncs); + if (!svs.numprogs) { PF_InitTempStrings(svprogfuncs); @@ -1055,6 +1061,7 @@ void PR_Init(void) Cvar_Register(&pr_maxedicts, cvargroup_progs); Cvar_Register(&pr_no_playerphysics, cvargroup_progs); + Cvar_Register(&pr_no_parsecommand, cvargroup_progs); for (i = 0; i < MAXADDONS; i++) { @@ -1098,6 +1105,14 @@ void PR_Init(void) #endif } +void SVQ1_CvarChanged(cvar_t *var) +{ + if (svprogfuncs) + { + PR_AutoCvar(svprogfuncs, var); + } +} + void SV_RegisterH2CustomTents(void); void Q_InitProgs(void) { @@ -1563,6 +1578,10 @@ qboolean PR_KrimzonParseCommand(char *s) if (!svprogfuncs) return false; + /*some people are irresponsible*/ + if (pr_no_parsecommand.ival) + return false; + if (gfuncs.ParseClientCommand) { //the QC is expected to send it back to use via a builtin. @@ -8711,6 +8730,19 @@ static void QCBUILTIN PF_SendPacket(progfuncs_t *prinst, struct globalvars_s *pr NET_SendPacket(NS_SERVER, strlen(contents), contents, to); } +static void QCBUILTIN PF_sv_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int action = G_FLOAT(OFS_PARM0); + float *pos = G_VECTOR(OFS_PARM1); + float radius = G_FLOAT(OFS_PARM2); + float quant = G_FLOAT(OFS_PARM3); +#if defined(TERRAIN) + G_FLOAT(OFS_RETURN) = Heightmap_Edit(sv.world.worldmodel, action, pos, radius, quant); +#else + G_FLOAT(OFS_RETURN) = false; +#endif +} + BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"fixme", PF_Fixme, 0, 0, 0}, {"ignore", PF_Ignore, 0, 0, 0}, @@ -9016,8 +9048,11 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"clientstat", PF_clientstat, 0, 0, 0, 232}, //EXT_CSQC {"globalstat", PF_globalstat, 0, 0, 0, 233}, //EXT_CSQC_1 actually //END EXT_CSQC - {"isbackbuffered", PF_isbackbuffered, 0, 0, 0, 234}, + {"isbackbuffered", PF_isbackbuffered, 0, 0, 0, 234}, + //{"rotatevectorsbyangle", PF_rotatevectorsbyangles,0,0,0, 235}, // #235 + //{"rotatevectorsbymatrix", PF_rotatevectorsbymatrix,0,0,0, 236}, // #236 {"skinforname", PF_skinforname, 0, 0, 0, 237}, // #237 + {"shaderforname", PF_Fixme, 0, 0, 0, 238}, {"te_bloodqw", PF_te_bloodqw, 0, 0, 0, 239}, {"checkpvs", PF_checkpvs, 0, 0, 0, 240}, @@ -9042,9 +9077,25 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"stoh", PF_stoh, 0, 0, 0, 261}, {"htos", PF_htos, 0, 0, 0, 262}, +#if 0 + {"skel_create", PF_skel_create, 0, 0, 0, 263},//float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS) + {"skel_build", PF_skel_build, 0, 0, 0, 264},//float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS) + {"skel_get_numbones",PF_skel_get_numbones,0, 0, 0, 265},//float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) + {"skel_get_bonename",PF_skel_get_bonename,0, 0, 0, 266},//string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) (returns tempstring) + {"skel_get_boneparent",PF_skel_get_boneparent,0,0, 0, 267},//float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS) + {"skel_find_bone", PF_skel_find_bone, 0, 0, 0, 268},//float(float skel, string tagname) skel_get_boneidx = #268; // (FTE_CSQC_SKELETONOBJECTS) + {"skel_get_bonerel",PF_skel_get_bonerel,0, 0, 0, 269},//vector(float skel, float bonenum) skel_get_bonerel = #269; // (FTE_CSQC_SKELETONOBJECTS) (sets v_forward etc) + {"skel_get_boneabs",PF_skel_get_boneabs,0, 0, 0, 270},//vector(float skel, float bonenum) skel_get_boneabs = #270; // (FTE_CSQC_SKELETONOBJECTS) (sets v_forward etc) + {"skel_set_bone", PF_skel_set_bone, 0, 0, 0, 271},//void(float skel, float bonenum, vector org) skel_set_bone = #271; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc) + {"skel_mul_bone", PF_skel_mul_bone, 0, 0, 0, 272},//void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc) + {"skel_mul_bones", PF_skel_mul_bones, 0, 0, 0, 273},//void(float skel, float startbone, float endbone, vector org) skel_mul_bone = #273; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc) + {"skel_copybones", PF_skel_copybones, 0, 0, 0, 274},//void(float skeldst, float skelsrc, float startbone, float entbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS) + {"skel_delete", PF_skel_delete, 0, 0, 0, 275},//void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) +#endif {"frameforname", PF_frameforname, 0, 0, 0, 276},//void(float modidx, string framename) frameforname = #276 (FTE_CSQC_SKELETONOBJECTS) {"frameduration", PF_frameduration, 0, 0, 0, 277},//float(float modidx, float framenum) frameduration = #277 (FTE_CSQC_SKELETONOBJECTS) + {"terrain_edit", PF_sv_terrain_edit, 0, 0, 0, 278},//void(float action, vector pos, float radius, float quant) terrain_edit = #278 (??FTE_TERRAIN_EDIT?? //EXT_CSQC // {"setmodelindex", PF_sv_SetModelIndex,0, 0, 0, 333}, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC) @@ -9268,6 +9319,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"precache_vwep_model",PF_precache_vwep_model,0,0, 0, 532}, // #532 float(string mname) precache_vwep_model + {"sprintf", PF_sprintf, 0, 0, 0, 627}, + //don't exceed sizeof(pr_builtin)/sizeof(pr_builtin[0]) (currently 1024) without modifing the size of pr_builtin {NULL} diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index aa3a00b8f..0da3ae941 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -463,7 +463,7 @@ static eval_t *Q1QVMPF_GetEdictFieldValue(progfuncs_t *pf, edict_t *e, char *fie return NULL; } -static eval_t *Q1QVMPF_FindGlobal (progfuncs_t *prinst, char *name, progsnum_t num) +static eval_t *Q1QVMPF_FindGlobal (progfuncs_t *prinst, char *name, progsnum_t num, etype_t *type) { return NULL; } diff --git a/engine/server/progs.h b/engine/server/progs.h index 18cf59480..b6d4c0304 100644 --- a/engine/server/progs.h +++ b/engine/server/progs.h @@ -28,6 +28,8 @@ struct edict_s; #define NUM_SPAWN_PARMS 64 //moved from server.h because of include ordering :(. + +void SVQ1_CvarChanged(cvar_t *var); #define NewGetEdictFieldValue GetEdictFieldValue void Q_SetProgsParms(qboolean forcompiler); void PR_Deinit(void); diff --git a/engine/server/savegame.c b/engine/server/savegame.c index f028c5556..3ffe4ea60 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -703,10 +703,10 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea if (!ignoreplayers) { - eval = PR_FindGlobal(svprogfuncs, "startspot", 0); + eval = PR_FindGlobal(svprogfuncs, "startspot", 0, NULL); if (eval) eval->_int = (int)PR_NewString(svprogfuncs, startspot, 0); - eval = PR_FindGlobal(svprogfuncs, "ClientReEnter", 0); + eval = PR_FindGlobal(svprogfuncs, "ClientReEnter", 0, NULL); if (eval) for (i=0 ; i= 'A' && level[i] <= 'Z') - level[i] = level[i] - 'A' + 'a'; - } - snprintf (expanded, sizeof(expanded), "maps/%s.bsp", level); - if (!COM_FCheckExists (expanded)) - { - snprintf (expanded, sizeof(expanded), "maps/%s.cm", level); - if (!COM_FCheckExists (expanded)) + //doesn't exist, so try lowercase. Q3 does this. + for (j = 0; j < sizeof(level) && level[j]; j++) { - // FTE is still a Quake engine so report BSP missing - snprintf (expanded, sizeof(expanded), "maps/%s.bsp", level); - Con_TPrintf (STL_CANTFINDMAP, expanded); - return; + if (level[j] >= 'A' && level[j] <= 'Z') + level[j] = level[j] - 'A' + 'a'; } + snprintf (expanded, sizeof(expanded), exts[i], level); + if (COM_FCheckExists (expanded)) + break; + } + if (!exts[i]) + { + // FTE is still a Quake engine so report BSP missing + snprintf (expanded, sizeof(expanded), exts[0], level); + Con_TPrintf (STL_CANTFINDMAP, expanded); + return; } } } diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 6783055ba..943b96933 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -1093,15 +1093,13 @@ void SVDP_EmitEntitiesUpdate (client_t *client, packet_entities_t *to, sizebuf_t int SV_HullNumForPlayer(int h2hull, float *mins, float *maxs) { - vec3_t size; int diff; int best; int hullnum, i; if (sv.world.worldmodel->fromgame != fg_quake) { - VectorSubtract (maxs, mins, size); - return size[2]; //clients are expected to decide themselves. + return -mins[2] + 32; //clients are expected to decide themselves. } if (h2hull) diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 436751d00..e7f1ffe2a 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -357,7 +357,7 @@ void SV_SaveSpawnparms (qboolean dontsave) continue; // call the progs to get default spawn parms for the new client - if (PR_FindGlobal(svprogfuncs, "ClientReEnter", 0)) + if (PR_FindGlobal(svprogfuncs, "ClientReEnter", 0, NULL)) {//oooh, evil. char buffer[65536]; int bufsize = sizeof(buffer); @@ -844,11 +844,16 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us } else { + char *exts[] = {"maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", NULL}; strcpy (sv.name, server); - sprintf (sv.modelname,"maps/%s.bsp", server); + sprintf (sv.modelname, exts[0], server); if (!COM_FCheckExists(sv.modelname)) - if (COM_FCheckExists(va("maps/%s.cm", server))) - sprintf (sv.modelname,"maps/%s.cm", server); + { + if (COM_FCheckExists(va(exts[1], server))) + sprintf (sv.modelname,exts[1], server); + else if (COM_FCheckExists(va(exts[2], server))) + sprintf (sv.modelname,exts[2], server); + } } sv.state = ss_loading; sv.world.worldmodel = Mod_ForName (sv.modelname, true); @@ -1224,20 +1229,20 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us cvar_t *cv; if (coop.value) { - eval = PR_FindGlobal(svprogfuncs, "coop", 0); + eval = PR_FindGlobal(svprogfuncs, "coop", 0, NULL); if (eval) eval->_float = coop.value; } else { - eval = PR_FindGlobal(svprogfuncs, "deathmatch", 0); + eval = PR_FindGlobal(svprogfuncs, "deathmatch", 0, NULL); if (eval) eval->_float = deathmatch.value; } cv = Cvar_Get("randomclass", "0", CVAR_LATCH, "Hexen2"); - eval = PR_FindGlobal(svprogfuncs, "randomclass", 0); + eval = PR_FindGlobal(svprogfuncs, "randomclass", 0, NULL); if (eval && cv) eval->_float = cv->value; cv = Cvar_Get("cl_playerclass", "1", CVAR_USERINFO|CVAR_ARCHIVE, "Hexen2"); - eval = PR_FindGlobal(svprogfuncs, "cl_playerclass", 0); + eval = PR_FindGlobal(svprogfuncs, "cl_playerclass", 0, NULL); if (eval && cv) eval->_float = cv->value; } else @@ -1459,7 +1464,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us if (svprogfuncs && startspot) { eval_t *eval; - eval = PR_FindGlobal(svprogfuncs, "startspot", 0); + eval = PR_FindGlobal(svprogfuncs, "startspot", 0, NULL); if (eval) eval->string = PR_NewString(svprogfuncs, startspot, 0); } diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index f69f35483..66df972cb 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -1082,7 +1082,7 @@ void SVC_GetInfo (char *challenge, int fullstatus) if (svprogfuncs) { - v = PR_FindGlobal(svprogfuncs, "worldstatus", PR_ANY); + v = PR_FindGlobal(svprogfuncs, "worldstatus", PR_ANY, NULL); if (v) gamestatus = PR_GetString(svprogfuncs, v->string); else diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 1e9d1234d..032520653 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -1349,7 +1349,7 @@ void SV_QCStatGlobal(int type, char *globalname, int statnum) if (type < 0) return; - glob = svprogfuncs->FindGlobal(svprogfuncs, globalname, PR_ANY); + glob = svprogfuncs->FindGlobal(svprogfuncs, globalname, PR_ANY, NULL); if (!glob) { Con_Printf("couldn't find named global for csqc stat (%s)\n", globalname); @@ -1398,6 +1398,7 @@ void SV_ClearQCStats(void) numqcstats = 0; } +extern cvar_t dpcompat_stats; void SV_UpdateQCStats(edict_t *ent, int *statsi, char **statss, float *statsf) { char *s; @@ -1425,6 +1426,11 @@ void SV_UpdateQCStats(edict_t *ent, int *statsi, char **statss, float *statsf) case ev_float: statsf[qcstats[i].statnum] = eval->_float; break; + case ev_vector: + statsf[qcstats[i].statnum+0] = eval->_vector[0]; + statsf[qcstats[i].statnum+1] = eval->_vector[1]; + statsf[qcstats[i].statnum+2] = eval->_vector[2]; + break; case ev_integer: statsi[qcstats[i].statnum] = eval->_int; break; @@ -1607,31 +1613,6 @@ void SV_UpdateClientStats (client_t *client, int pnum) #ifdef PEXT_CSQC if ((client->fteprotocolextensions & PEXT_CSQC) && (sv.csqcchecksum || progstype == PROG_H2)) { - if (statsf[i] && statsf[i] - (float)(int)statsf[i] == 0) - { - statsi[i] = statsf[i]; - statsf[i] = 0; - } - else if (statsf[i] != client->statsf[i]) - { - client->statsf[i] = statsf[i]; -// client->statsi[i] = statsi[i]; - if (pnum) - { - ClientReliableWrite_Begin(client->controller, svcfte_choosesplitclient, 8); - ClientReliableWrite_Byte(client->controller, pnum); - ClientReliableWrite_Byte(client->controller, svcfte_updatestatfloat); - ClientReliableWrite_Byte(client->controller, i); - ClientReliableWrite_Float(client->controller, statsf[i]); - } - else - { - ClientReliableWrite_Begin(client, svcfte_updatestatfloat, 6); - ClientReliableWrite_Byte(client, i); - ClientReliableWrite_Float(client, statsf[i]); - } - } - if (statss[i] || client->statss[i]) if (strcmp(statss[i]?statss[i]:"", client->statss[i]?client->statss[i]:"")) { @@ -1652,14 +1633,63 @@ void SV_UpdateClientStats (client_t *client, int pnum) } } } - else + if (dpcompat_stats.ival) + { + if (statsf[i]) + { + statsi[i] = statsf[i]; + statsf[i] = 0; + } + } #endif - if (!statsi[i]) - statsi[i] = statsf[i]; - if (statsi[i] != client->statsi[i]) + + if (statsf[i]) + { + if (statsf[i] != client->statsf[i]) + { + if (statsf[i] - (float)(int)statsf[i] == 0 && statsf[i] >= 0 && statsf[i] <= 255) + { + if (pnum) + { + ClientReliableWrite_Begin(client->controller, svcfte_choosesplitclient, 5); + ClientReliableWrite_Byte(client->controller, pnum); + ClientReliableWrite_Byte(client->controller, svc_updatestat); + ClientReliableWrite_Byte(client->controller, i); + ClientReliableWrite_Byte(client->controller, statsf[i]); + } + else + { + ClientReliableWrite_Begin(client, svc_updatestat, 3); + ClientReliableWrite_Byte(client, i); + ClientReliableWrite_Byte(client, statsf[i]); + } + } + else + { + if (pnum) + { + ClientReliableWrite_Begin(client->controller, svcfte_choosesplitclient, 8); + ClientReliableWrite_Byte(client->controller, pnum); + ClientReliableWrite_Byte(client->controller, svcfte_updatestatfloat); + ClientReliableWrite_Byte(client->controller, i); + ClientReliableWrite_Float(client->controller, statsf[i]); + } + else + { + ClientReliableWrite_Begin(client, svcfte_updatestatfloat, 6); + ClientReliableWrite_Byte(client, i); + ClientReliableWrite_Float(client, statsf[i]); + } + } + client->statsf[i] = statsf[i]; + /*make sure statsf is correct*/ + client->statsi[i] = statsf[i]; + } + } + else if (statsi[i] != client->statsi[i]) { client->statsi[i] = statsi[i]; - client->statsf[i] = 0; + client->statsf[i] = statsi[i]; if (statsi[i] >=0 && statsi[i] <= 255) { diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 8b9bf9b47..89a415343 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -406,6 +406,13 @@ void SVNQ_New_f (void) char message[2048]; int i; + if (!host_client->pextknown) + { + MSG_WriteByte (&host_client->netchan.message, svc_stufftext); + MSG_WriteString (&host_client->netchan.message, "cmd pext\n"); + return; + } + MSG_WriteByte (&host_client->netchan.message, svc_print); sprintf (message, "%c\n%s server\n", 2, version_string()); MSG_WriteString (&host_client->netchan.message,message); @@ -436,6 +443,18 @@ void SVNQ_New_f (void) } MSG_WriteByte (&host_client->netchan.message, svc_serverdata); + + if (host_client->fteprotocolextensions) + { + MSG_WriteLong (&host_client->netchan.message, PROTOCOL_VERSION_FTE); + MSG_WriteLong (&host_client->netchan.message, host_client->fteprotocolextensions); + } + if (host_client->fteprotocolextensions2) + { + MSG_WriteLong (&host_client->netchan.message, PROTOCOL_VERSION_FTE2); + MSG_WriteLong (&host_client->netchan.message, host_client->fteprotocolextensions2); + } + switch(host_client->protocol) { #ifdef NQPROT @@ -1119,9 +1138,15 @@ void SV_PreSpawn_f (void) if (!sv.demofile || (sv.demofile && !sv.democausesreconnect)) //demo playing causes no check. If it's the return level, check anyway to avoid that loophole. #endif { + char *msg; SV_ClientTPrintf (host_client, PRINT_HIGH, STL_MAPCHEAT, sv.modelname, check, sv.world.worldmodel->checksum, sv.world.worldmodel->checksum2); + + + msg = va("\n//kickfile \"%s\"\n", sv.modelname); + ClientReliableWrite_Begin (host_client, svc_stufftext, 3+strlen(msg)); + ClientReliableWrite_String (host_client, msg); SV_DropClient (host_client); return; } @@ -1567,7 +1592,7 @@ void SV_Begin_Core(client_t *split) if (svprogfuncs) { eval_t *eval, *eval2; - eval = PR_FindGlobal(svprogfuncs, "ClientReEnter", 0); + eval = PR_FindGlobal(svprogfuncs, "ClientReEnter", 0, NULL); if (eval && split->spawninfo) { globalvars_t *pr_globals = PR_globals(svprogfuncs, PR_CURRENT); @@ -4762,6 +4787,37 @@ void SVNQ_Ping_f(void) } } +void SV_Pext_f(void) +{ + int i; + char *tag; + char *val; + + if (host_client->pextknown) + return; + host_client->pextknown = true; + + for (i = 1; i < Cmd_Argc(); ) + { + tag = Cmd_Argv(i++); + val = Cmd_Argv(i++); + switch(strtoul(tag, NULL, 0)) + { + case PROTOCOL_VERSION_FTE: + host_client->fteprotocolextensions = strtoul(val, NULL, 0) & svs.fteprotocolextensions; + break; + case PROTOCOL_VERSION_FTE2: + host_client->fteprotocolextensions2 = strtoul(val, NULL, 0) & svs.fteprotocolextensions2; + break; + } + } + + if (ISNQCLIENT(host_client)) + SVNQ_New_f(); + else + SV_New_f(); +} + ucmd_t nqucmds[] = { {"new", SVNQ_New_f, true}, @@ -4803,6 +4859,15 @@ ucmd_t nqucmds[] = {"topten", Rank_ListTop10_f}, #endif + {"pext", SV_Pext_f}, + +#ifdef VOICECHAT + {"voicetarg", SV_Voice_Target_f}, + {"vignore", SV_Voice_Ignore_f}, /*ignore/mute specific player*/ + {"muteall", SV_Voice_MuteAll_f}, /*disables*/ + {"unmuteall", SV_Voice_UnmuteAll_f}, /*reenables*/ +#endif + {NULL, NULL} }; /* @@ -6284,6 +6349,12 @@ void SVQ2_ExecuteClientMessage (client_t *cl) if (cl->state == cs_zombie) return; // disconnect command break; + +#ifdef PEXT2_VOICECHAT + case clc_voicechat: + SV_VoiceReadPacket(); + break; +#endif } } } @@ -6474,6 +6545,12 @@ void SVNQ_ExecuteClientMessage (client_t *cl) case clcdp_ackdownloaddata: SV_DarkPlacesDownloadAck(host_client); break; + +#ifdef PEXT2_VOICECHAT + case clc_voicechat: + SV_VoiceReadPacket(); + break; +#endif } } } diff --git a/engine/server/world.c b/engine/server/world.c index 75024d320..c8942d32e 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -928,6 +928,12 @@ qboolean TransformedTrace (struct model_s *model, int hulloverride, int frame, v trace->inopen = true; //probably wrong... VectorCopy (end, trace->endpos); + if (IS_NAN(end[0]) || IS_NAN(end[1]) || IS_NAN(end[2])) + { + Con_DPrintf("Nan in traceline\n"); + return false; + } + // don't rotate non bsp ents. Too small to bother. if (model) {