From 6adb05d9161bed999c21da6b9e48fd4414d9dad1 Mon Sep 17 00:00:00 2001 From: Spoike Date: Thu, 30 Jul 2015 16:26:15 +0000 Subject: [PATCH] autotrack is now over-complicated. demo_jump with no args tells the current time (separate from map time or anything) implement batching for text+csqcpolys to reduce draw calls. qclib supports pointer(inc casts) evaluation. fteqccgui now has a lame variables window thing. probably I'll get harassed about it. add brush_calcfacepoints builtin for csaddon to use to preview brush edits. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4952 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_cam.c | 256 +++++++++++++++++++++++++++++++------- engine/client/cl_demo.c | 6 + engine/client/cl_main.c | 4 + engine/client/cl_screen.c | 4 + engine/client/image.c | 2 +- engine/client/pr_csqc.c | 209 +++++++++++++++++++++---------- engine/client/r_2d.c | 16 +++ engine/client/renderer.c | 5 +- engine/client/sbar.c | 106 ++++++++++------ engine/client/snd_ov.c | 8 +- engine/client/view.c | 17 ++- engine/common/pr_common.h | 1 + engine/d3d/vid_d3d.c | 4 + engine/gl/gl_draw.h | 2 + engine/gl/gl_font.c | 36 ++++-- engine/gl/gl_heightmap.c | 132 +++++++++++++++++--- engine/gl/gl_screen.c | 2 + engine/gl/gl_shader.c | 4 +- engine/qclib/pr_exec.c | 72 ++++++++++- engine/qclib/qccgui.c | 156 ++++++++++++++++++++++- engine/server/pr_cmds.c | 19 +-- 21 files changed, 859 insertions(+), 202 deletions(-) diff --git a/engine/client/cl_cam.c b/engine/client/cl_cam.c index 3982bfd52..5b2ae2ccd 100644 --- a/engine/client/cl_cam.c +++ b/engine/client/cl_cam.c @@ -67,7 +67,12 @@ void Cam_AutoTrack_Update(const char *mode) autotrack_statsrule = NULL; if (!*mode || !Q_strcasecmp(mode, "auto")) { - if (cl_hightrack.ival) + if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) + { + autotrackmode = TM_STATS; + autotrack_statsrule = Z_StrDup(""); //default + } + else if (cl_hightrack.ival) autotrackmode = TM_HIGHTRACK; else autotrackmode = TM_MODHINTS; @@ -80,6 +85,11 @@ void Cam_AutoTrack_Update(const char *mode) autotrackmode = TM_MODHINTS; else if (!Q_strcasecmp(mode, "user") || !Q_strcasecmp(mode, "off")) autotrackmode = TM_USER; + else if (!Q_strcasecmp(mode, "stats")) + { + autotrackmode = TM_STATS; + autotrack_statsrule = NULL; + } else { autotrackmode = TM_STATS; @@ -94,47 +104,131 @@ static void Cam_AutoTrack_f(void) Cam_AutoTrack_Update(NULL); } - -static float CL_TrackScore(player_info_t *pl, char *rule) +static float CL_TrackScoreProp(player_info_t *pl, char rule, float *weights) { - float score = 0; - float val; - int r; - while (*rule) + float r; + switch(rule) { - r = *rule++; - if (r == 'f') - val = pl->frags; - else if (r == 'l') - val = pl->ping; - else if (r == 'h') - val = pl->statsf[STAT_HEALTH]; - else if (r == 'q') - val = (pl->stats[STAT_ITEMS] & IT_QUAD)?1:0; - else if (r == 'p') - val = (pl->stats[STAT_ITEMS] & IT_INVULNERABILITY)?1:0; - else if (r == 's') - { - int i = strtol(rule, &rule, 10); - val = pl->statsf[i]; - } - else if (r == '#') - val = strtod(rule, &rule); - else - val = 0; - - if (*rule == '*') - { - val *= strtod(rule+1, &rule); - } - - score += val; - if (*rule == '+') - rule++; - else - break; + case 'a': //armour value + return pl->statsf[STAT_ARMOR]; + case 'h': + return pl->statsf[STAT_HEALTH]; + case 'A': //armour type + if (pl->stats[STAT_ITEMS] & IT_ARMOR3) r = weights[10]; + else if (pl->stats[STAT_ITEMS] & IT_ARMOR2) r = weights[9]; + else if (pl->stats[STAT_ITEMS] & IT_ARMOR1) r = weights[8]; + else r = 0; + return r; + case 'W': //best weapon + r = 0; + if (r < weights[0] && (pl->stats[STAT_ITEMS] & IT_AXE)) r = weights[0]; + if (r < weights[1] && (pl->stats[STAT_ITEMS] & IT_SHOTGUN)) r = weights[1]; + if (r < weights[2] && (pl->stats[STAT_ITEMS] & IT_SUPER_SHOTGUN)) r = weights[2]; + if (r < weights[3] && (pl->stats[STAT_ITEMS] & IT_NAILGUN)) r = weights[3]; + if (r < weights[4] && (pl->stats[STAT_ITEMS] & IT_SUPER_NAILGUN)) r = weights[4]; + if (r < weights[5] && (pl->stats[STAT_ITEMS] & IT_GRENADE_LAUNCHER)) r = weights[5]; + if (r < weights[6] && (pl->stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER)) r = weights[6]; + if (r < weights[7] && (pl->stats[STAT_ITEMS] & IT_LIGHTNING)) r = weights[7]; + return r; + case 'p': //powerups held + r = 0; + r += (pl->stats[STAT_ITEMS] & IT_INVISIBILITY)?weights[11]:0; + r += (pl->stats[STAT_ITEMS] & IT_QUAD)?weights[12]:0; + r += (pl->stats[STAT_ITEMS] & IT_INVULNERABILITY)?weights[13]:0; + return r; + case 'f': //frags + return pl->frags; +// case 'F': //team frags +// return 0; + case 'g': //deaths + return Stats_GetDeaths(pl - cl.players); + case 'u': //userid + return pl - cl.players; + default: + return 0; } - return score; +} +#define PRI_TOP 2 +#define PRI_ADD 2 +#define PRI_MUL 1 +#define PRI_VAL 0 +static float CL_TrackScore(player_info_t *pl, char **rule, float *weights, int pri) +{ + float l, r; + char *s = *rule; + while (*s == ' ' || *s == '\t') + s++; + if (!pri) + { + if (*s == '(') + { + l = CL_TrackScore(pl, &s, weights, PRI_TOP); + while (*s == ' ' || *s == '\t') + s++; + if (*s == ')') + s++; + } + else if (*s == '%') + { + l = CL_TrackScoreProp(pl, *++s, weights); + s++; + } + else if (*s == '#') + { + int i = strtoul(s+1, &s, 0); + if (i >= 0 && i < MAX_CL_STATS) + l = pl->statsf[i]; + else + l = 0; + } + else + l = strtod(s, &s); + while (*s == ' ' || *s == '\t') + s++; + } + else + l = CL_TrackScore(pl, &s, weights, pri-1); + + for (;;) + { + if (pri == PRI_MUL) + { + if (*s == '*') + { + s++; + r = CL_TrackScore(pl, &s, weights, pri-1); + l *= r; + continue; + } + else if (*s == '/') + { + s++; + r = CL_TrackScore(pl, &s, weights, pri-1); + l /= r; + continue; + } + } + else if (pri == PRI_ADD) + { + if (*s == '+') + { + s++; + r = CL_TrackScore(pl, &s, weights, pri-1); + l += r; + continue; + } + else if (*s == '-') + { + s++; + r = CL_TrackScore(pl, &s, weights, pri-1); + l -= r; + continue; + } + } + break; + } + *rule = s; + return l; } static qboolean CL_MayTrack(int seat, int player) { @@ -154,14 +248,60 @@ static qboolean CL_MayTrack(int seat, int player) static int CL_FindHighTrack(int seat, char *rule) { int j = -1; - int i, k; + int i; float max, score; player_info_t *s; + float weights[14]; + char *p; + + if (rule && *rule == '[') + { + rule++; + weights[0] = strtod(rule, &rule); //axe + weights[1] = strtod(rule, &rule); //shot + weights[2] = strtod(rule, &rule); //sshot + weights[3] = strtod(rule, &rule); //nail + weights[4] = strtod(rule, &rule); //snail + weights[5] = strtod(rule, &rule); //gren + weights[6] = strtod(rule, &rule); //rock + weights[7] = strtod(rule, &rule); //lg + weights[8] = strtod(rule, &rule); //ga + weights[9] = strtod(rule, &rule); //ya + weights[10] = strtod(rule, &rule); //ra + weights[11] = strtod(rule, &rule); //ring + weights[12] = strtod(rule, &rule); //quad + weights[13] = strtod(rule, &rule); //pent + if (*rule == ']') + rule++; + } + else + { + weights[0] = 1; //axe + weights[1] = 2; //shot + weights[2] = 3; //sshot + weights[3] = 2; //nail + weights[4] = 3; //snail + weights[5] = 3; //gren + weights[6] = 8; //rock + weights[7] = 8; //lg + weights[8] = 1; //ga + weights[9] = 2; //ya + weights[10] = 3; //ra + weights[11] = 500; //ring + weights[12] = 900; //quad + weights[13] = 1000; //pent + } + + if (!rule || !*rule) + rule = "%a * %A + 50 * %W + %p + %f"; //set a default to the currently tracked player, to reuse the current player we're tracking if someone lower equalises. j = cl.playerview[seat].cam_spec_track; if (CL_MayTrack(seat, j)) - max = CL_TrackScore(&cl.players[j], rule); + { + p = rule; + max = CL_TrackScore(&cl.players[j], &p, weights, PRI_TOP); + } else { max = -9999; @@ -171,17 +311,39 @@ static int CL_FindHighTrack(int seat, char *rule) for (i = 0; i < cl.allocated_client_slots; i++) { s = &cl.players[i]; - score = CL_TrackScore(s, rule); + if (j == i) //this was our default. + continue; + if (!CL_MayTrack(seat, i)) + continue; + if (cl.teamplay && seat && cl.playerview[0].cam_spec_track >= 0 && strcmp(cl.players[cl.playerview[0].cam_spec_track].team, s->team)) + continue; //when using multiview, keep tracking the team + p = rule; + score = CL_TrackScore(s, &p, weights, PRI_TOP); if (score > max) { + max = score; + j = i; + } + } + if (j == -1 && cl.teamplay && seat) + { + //do it again, but with the teamplay check inverted + for (i = 0; i < cl.allocated_client_slots; i++) + { + s = &cl.players[i]; if (j == i) //this was our default. continue; if (!CL_MayTrack(seat, i)) continue; - if (cl.teamplay && seat && cl.playerview[0].cam_spec_track >= 0 && strcmp(cl.players[cl.playerview[0].cam_spec_track].team, s->team)) + if (!(cl.teamplay && seat && cl.playerview[0].cam_spec_track >= 0 && strcmp(cl.players[cl.playerview[0].cam_spec_track].team, s->team))) continue; //when using multiview, keep tracking the team - max = CL_TrackScore(s, rule); - j = i; + p = rule; + score = CL_TrackScore(s, &p, weights, PRI_TOP); + if (score > max) + { + max = score; + j = i; + } } } return j; @@ -194,10 +356,10 @@ static int CL_AutoTrack_Choose(int seat) best = cl.autotrack_killer; if (autotrackmode == TM_MODHINTS && seat == 0 && cl.autotrack_hint >= 0) best = cl.autotrack_hint; - if (autotrackmode == TM_STATS && cls.demoplayback == DPB_MVD) + if (autotrackmode == TM_STATS && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)) best = CL_FindHighTrack(seat, autotrack_statsrule); if (autotrackmode == TM_HIGHTRACK || best == -1) - best = CL_FindHighTrack(seat, "f"); + best = CL_FindHighTrack(seat, "%f"); //TM_USER should generally avoid autotracking cl.autotrack_killer = best; //killer should continue to track whatever is currently tracked until its changed by frag message parsing return best; diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 36838b182..cd84fc672 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -390,6 +390,12 @@ void CL_DemoJump_f(void) return; } + if (Cmd_Argc() < 2) + { + Con_Printf("current time %.1f.\n", demtime); + return; + } + if (*s == '+' || *s == '-') { if (colon) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index bc043c26a..34174261e 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" #include "winquake.h" +#include "gl_draw.h" #include #include "netinc.h" #include "cl_master.h" @@ -4968,6 +4969,9 @@ double Host_Frame (double time) scr_chatmode = 0; SCR_UpdateScreen (); + + if (R2D_Flush) + R2D_Flush(); } if (host_speeds.ival) diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index a751b5e96..7e67d0d2c 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // cl_screen.c -- master for refresh, status bar, console, chat, notify, etc #include "quakedef.h" +#include "gl_draw.h" #ifdef GLQUAKE #include "glquake.h"//would prefer not to have this #endif @@ -2594,5 +2595,8 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud) SCR_DrawCursor(); SCR_DrawSimMTouchCursor(); + if (R2D_Flush) + R2D_Flush(); + RSpeedEnd(RSPEED_2D); } diff --git a/engine/client/image.c b/engine/client/image.c index 737a580cf..dfddefffb 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -4732,7 +4732,7 @@ void Image_Shutdown(void) i++; } if (i) - Con_Printf("Destroyed %i/%i images\n", j, i); + Con_DPrintf("Destroyed %i/%i images\n", j, i); } //load the named file, without failing. diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index ee5ddb003..ca525db87 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" +#include "gl_draw.h" /* @@ -111,6 +112,7 @@ extern sfx_t *cl_sfx_r_exp3; globalfunction(parse_damage, "CSQC_Parse_Damage"); \ globalfunction(input_event, "CSQC_InputEvent"); \ globalfunction(input_frame, "CSQC_Input_Frame");/*EXT_CSQC_1*/ \ + globalfunction(rendererrestarted, "CSQC_RendererRestarted"); \ globalfunction(console_command, "CSQC_ConsoleCommand"); \ globalfunction(console_link, "CSQC_ConsoleLink"); \ globalfunction(gamecommand, "GameCommand"); /*DP extension*/\ @@ -1170,37 +1172,105 @@ static void QCBUILTIN PF_R_AddEntityMask(pubprogfuncs_t *prinst, struct globalva //vbuff_delete(vboidx), vboidx=0 static shader_t *csqc_poly_shader; +static int csqc_poly_origvert; +static int csqc_poly_origidx; static int csqc_poly_startvert; static int csqc_poly_startidx; static int csqc_poly_flags; static int csqc_poly_2d; +static void CSQC_PolyFlush(void) +{ + mesh_t mesh; + R2D_Flush = NULL; + + //make sure there's actually something there... + if (cl_numstrisvert == csqc_poly_origvert) + return; + + if (!csqc_poly_2d) + { + scenetris_t *t; + /*regular 3d polys are inserted into a 'scene trisoup' that the backend can then source from (multiple times, depending on how its drawn)*/ + if (cl_numstris == cl_maxstris) + { + cl_maxstris+=8; + cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris); + } + t = &cl_stris[cl_numstris++]; + t->shader = csqc_poly_shader; + t->flags = csqc_poly_flags; + t->firstidx = csqc_poly_origidx; + t->firstvert = csqc_poly_origvert; + + t->numidx = cl_numstrisidx - t->firstidx; + t->numvert = cl_numstrisvert-csqc_poly_origvert; + } + else + { + /*2d polys need to be flushed now*/ + memset(&mesh, 0, sizeof(mesh)); + + mesh.istrifan = (csqc_poly_origvert == csqc_poly_startvert); + mesh.xyz_array = cl_strisvertv + csqc_poly_origvert; + mesh.st_array = cl_strisvertt + csqc_poly_origvert; + mesh.colors4f_array[0] = cl_strisvertc + csqc_poly_origvert; + mesh.indexes = cl_strisidx + csqc_poly_origidx; + mesh.numindexes = cl_numstrisidx - csqc_poly_origidx; + mesh.numvertexes = cl_numstrisvert-csqc_poly_origvert; + /*undo the positions so we don't draw the same verts more than once*/ + cl_numstrisvert = csqc_poly_origvert; + cl_numstrisidx = csqc_poly_origvert; + + BE_DrawMesh_Single(csqc_poly_shader, &mesh, NULL, csqc_poly_flags); + } + + //must call begin before the next poly + csqc_poly_shader = NULL; +} + // #306 void(string texturename) R_BeginPolygon (EXT_CSQC_???) void QCBUILTIN PF_R_PolygonBegin(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - csqc_poly_flags = (prinst->callargc > 1)?G_FLOAT(OFS_PARM1):0; + shader_t *shader; + int flags = (prinst->callargc > 1)?G_FLOAT(OFS_PARM1):0; + qboolean twod; if (prinst->callargc > 2) - csqc_poly_2d = G_FLOAT(OFS_PARM2); + twod = G_FLOAT(OFS_PARM2); else if (csqc_isdarkplaces) { - csqc_poly_2d = !csqc_dp_lastwas3d; + twod = !csqc_dp_lastwas3d; csqc_deprecated("guessing 2d mode based upon random builtin calls"); } else - csqc_poly_2d = csqc_poly_flags & 4; + twod = flags & 4; - if ((csqc_poly_flags & 3) == 1) - csqc_poly_flags = BEF_FORCEADDITIVE; + if ((flags & 3) == 1) + flags = BEF_FORCEADDITIVE; else - csqc_poly_flags = BEF_NOSHADOWS; - if (csqc_isdarkplaces) - csqc_poly_flags |= BEF_FORCETWOSIDED; + flags = BEF_NOSHADOWS; + if (csqc_isdarkplaces || (flags & 0x400)) + flags |= BEF_FORCETWOSIDED; if (csqc_poly_2d) - csqc_poly_shader = R_RegisterPic(PR_GetStringOfs(prinst, OFS_PARM0)); + shader = R_RegisterPic(PR_GetStringOfs(prinst, OFS_PARM0)); else - csqc_poly_shader = R_RegisterSkin(PR_GetStringOfs(prinst, OFS_PARM0), NULL); + shader = R_RegisterSkin(PR_GetStringOfs(prinst, OFS_PARM0), NULL); + + if (R2D_Flush && (R2D_Flush != CSQC_PolyFlush || csqc_poly_shader != shader || csqc_poly_flags != flags || csqc_poly_2d != twod)) + R2D_Flush(); + if (!R2D_Flush) + { //this is where our current (2d) batch starts + csqc_poly_origvert = cl_numstrisvert; + csqc_poly_origidx = cl_numstrisidx; + } + R2D_Flush = CSQC_PolyFlush; + csqc_poly_shader = shader; + csqc_poly_flags = flags; + csqc_poly_2d = twod; + + //this is where our current poly starts csqc_poly_startvert = cl_numstrisvert; csqc_poly_startidx = cl_numstrisidx; } @@ -1226,10 +1296,10 @@ void QCBUILTIN PF_R_PolygonVertex(pubprogfuncs_t *prinst, struct globalvars_s *p // #308 void() R_EndPolygon (EXT_CSQC_???) void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - scenetris_t *t; int i; int nv; int flags = csqc_poly_flags; + int first; if (!csqc_poly_shader) return; @@ -1237,24 +1307,26 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g nv = cl_numstrisvert-csqc_poly_startvert; if (nv == 2) flags |= BEF_LINES; - - /*if the shader didn't change, continue with the old poly*/ - if (cl_numstris && cl_stris[cl_numstris-1].shader == csqc_poly_shader && cl_stris[cl_numstris-1].flags == flags) - t = &cl_stris[cl_numstris-1]; else + flags &= ~BEF_LINES; + + if (flags != csqc_poly_flags) { - if (cl_numstris == cl_maxstris) - { - cl_maxstris+=8; - cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris); - } - t = &cl_stris[cl_numstris++]; - t->shader = csqc_poly_shader; - t->flags = flags; - t->firstidx = cl_numstrisidx; - t->firstvert = csqc_poly_startvert; - t->numvert = 0; - t->numidx = 0; + int sv = cl_numstrisvert - nv; + cl_numstrisvert -= nv; + CSQC_PolyFlush(); + + csqc_poly_origvert = cl_numstrisvert; + csqc_poly_origidx = cl_numstrisidx; + R2D_Flush = CSQC_PolyFlush; + csqc_poly_flags = flags; + csqc_poly_startvert = cl_numstrisvert; + csqc_poly_startidx = cl_numstrisidx; + + memcpy(cl_strisvertv+cl_numstrisvert, cl_strisvertv + sv, sizeof(*cl_strisvertv) * nv); + memcpy(cl_strisvertt+cl_numstrisvert, cl_strisvertt + sv, sizeof(*cl_strisvertt) * nv); + memcpy(cl_strisvertc+cl_numstrisvert, cl_strisvertc + sv, sizeof(*cl_strisvertc) * nv); + cl_numstrisvert += nv; } if (flags & BEF_LINES) @@ -1266,11 +1338,12 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx); } + first = csqc_poly_startvert - csqc_poly_origvert; /*build the line list fan out of triangles*/ for (i = 1; i < nv; i++) { - cl_strisidx[cl_numstrisidx++] = t->numvert + i-1; - cl_strisidx[cl_numstrisidx++] = t->numvert + i; + cl_strisidx[cl_numstrisidx++] = first + i-1; + cl_strisidx[cl_numstrisidx++] = first + i; } } else @@ -1282,42 +1355,19 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx); } + first = csqc_poly_startvert - csqc_poly_origvert; /*build the triangle fan out of triangles*/ for (i = 2; i < nv; i++) { - cl_strisidx[cl_numstrisidx++] = t->numvert + 0; - cl_strisidx[cl_numstrisidx++] = t->numvert + i-1; - cl_strisidx[cl_numstrisidx++] = t->numvert + i; + cl_strisidx[cl_numstrisidx++] = first + 0; + cl_strisidx[cl_numstrisidx++] = first + i-1; + cl_strisidx[cl_numstrisidx++] = first + i; } } - if (csqc_poly_2d) - { - mesh_t mesh; - memset(&mesh, 0, sizeof(mesh)); - - mesh.istrifan = true; - mesh.xyz_array = cl_strisvertv + csqc_poly_startvert; - mesh.st_array = cl_strisvertt + csqc_poly_startvert; - mesh.colors4f_array[0] = cl_strisvertc + csqc_poly_startvert; - mesh.indexes = cl_strisidx + csqc_poly_startidx; - mesh.numindexes = cl_numstrisidx - csqc_poly_startidx; - mesh.numvertexes = cl_numstrisvert-csqc_poly_startvert; - /*undo the positions so we don't draw the same verts more than once*/ - cl_numstrisvert = csqc_poly_startvert; - cl_numstrisidx = csqc_poly_startidx; - - BE_DrawMesh_Single(csqc_poly_shader, &mesh, NULL, csqc_poly_flags); - } - else - { - t->numidx = cl_numstrisidx - t->firstidx; - t->numvert += cl_numstrisvert-csqc_poly_startvert; - - /*set up ready for the next poly*/ - csqc_poly_startvert = cl_numstrisvert; - csqc_poly_startidx = cl_numstrisidx; - } + /*set up ready for the next poly*/ + csqc_poly_startvert = cl_numstrisvert; + csqc_poly_startidx = cl_numstrisidx; } @@ -1420,6 +1470,9 @@ static void QCBUILTIN PF_cs_unproject (pubprogfuncs_t *prinst, struct globalvars //clear scene, and set up the default stuff. static void QCBUILTIN PF_R_ClearScene (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { + if (R2D_Flush) + R2D_Flush(); + if (prinst->callargc > 0) CSQC_ChangeLocalPlayer(G_FLOAT(OFS_PARM0)); @@ -1596,6 +1649,9 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_ return; } + if (R2D_Flush) + R2D_Flush(); + csqc_rebuildmatricies = true; G_FLOAT(OFS_RETURN) = 1; @@ -1792,6 +1848,8 @@ void R2D_PolyBlend (void); void R_DrawNameTags(void); static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { + if (R2D_Flush) + R2D_Flush(); csqc_poly_shader = NULL; if (csqc_worldchanged) @@ -5128,6 +5186,7 @@ static struct { {"brush_delete", PF_brush_delete, 0}, {"brush_selected", PF_brush_selected, 0}, {"brush_getfacepoints", PF_brush_getfacepoints, 0}, + {"brush_calcfacepoints", PF_brush_calcfacepoints,0}, {"brush_findinvolume", PF_brush_findinvolume, 0}, {"touchtriggers", PF_touchtriggers, 279},//void() touchtriggers = #279; @@ -5693,7 +5752,7 @@ void CSQC_Event_Think(world_t *w, wedict_t *s) PR_ExecuteProgram (w->progs, s->v->think); } -void CSQC_Event_Sound (float *origin, wedict_t *wentity, int channel, const char *sample, int volume, float attenuation, int pitchadj, float timeoffset) +void CSQC_Event_Sound (float *origin, wedict_t *wentity, int channel, const char *sample, int volume, float attenuation, int pitchadj, float timeoffset, unsigned int flags) { int i; vec3_t originbuf; @@ -5709,7 +5768,7 @@ void CSQC_Event_Sound (float *origin, wedict_t *wentity, int channel, const char origin = wentity->v->origin; } - S_StartSound(NUM_FOR_EDICT(csqcprogs, (edict_t*)wentity), channel, S_PrecacheSound(sample), origin, volume, attenuation, timeoffset, pitchadj, 0); + S_StartSound(NUM_FOR_EDICT(csqcprogs, (edict_t*)wentity), channel, S_PrecacheSound(sample), origin, volume, attenuation, timeoffset, pitchadj, flags); } qboolean CSQC_Event_ContentsTransition(world_t *w, wedict_t *ent, int oldwatertype, int newwatertype) @@ -6199,6 +6258,10 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks csqcmapentitydataloaded = false; csqc_world.physicstime = 0.1; + + + if (cls.state == ca_disconnected) + CSQC_WorldLoaded(); } return true; //success! @@ -6218,6 +6281,18 @@ void CSQC_RendererRestarted(void) } //FIXME: registered shaders + + //let the csqc know that its rendertargets got purged + if (csqcg.rendererrestarted) + PR_ExecuteProgram(csqcprogs, csqcg.rendererrestarted); + //in case it drew to any render targets. + if (R2D_Flush) + R2D_Flush(); + if (*r_refdef.rt_destcolour[0].texname) + { + Q_strncpyz(r_refdef.rt_destcolour[0].texname, "", sizeof(r_refdef.rt_destcolour[0].texname)); + BE_RenderToTextureUpdate2d(true); + } } void CSQC_WorldLoaded(void) @@ -6233,14 +6308,14 @@ void CSQC_WorldLoaded(void) CSQC_FindGlobals(false); csqcmapentitydataloaded = true; - csqcmapentitydata = cl.worldmodel->entities; + csqcmapentitydata = cl.worldmodel?cl.worldmodel->entities:NULL; csqc_world.worldmodel = cl.worldmodel; World_RBE_Start(&csqc_world); worldent = (csqcedict_t *)EDICT_NUM(csqcprogs, 0); worldent->v->solid = SOLID_BSP; - csqc_setmodel(csqcprogs, worldent, 1); + csqc_setmodel(csqcprogs, worldent, cl.worldmodel?1:0); worldent->readonly = false; //just in case @@ -6595,8 +6670,8 @@ qboolean CSQC_DrawView(void) if (cl.paused) *csqcg.frametime = 0; //apparently people can't cope with microstutter when they're using this as a test to see if the game is paused. else - *csqcg.frametime = bound(0, cl.time - oldtime, 0.1); - oldtime = cl.time; + *csqcg.frametime = bound(0, cl.servertime - oldtime, 0.1); + oldtime = cl.servertime; } else *csqcg.frametime = host_frametime; @@ -6671,6 +6746,8 @@ qboolean CSQC_DrawView(void) else PR_ExecuteProgram(csqcprogs, csqcg.f_updateview); + if (R2D_Flush) + R2D_Flush(); if (*r_refdef.rt_destcolour[0].texname) { Q_strncpyz(r_refdef.rt_destcolour[0].texname, "", sizeof(r_refdef.rt_destcolour[0].texname)); diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 80ae4832e..b0be818af 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -58,6 +58,7 @@ static void QDECL R2D_Crosshair_Callback(struct cvar_s *var, char *oldvalue); static void QDECL R2D_CrosshairImage_Callback(struct cvar_s *var, char *oldvalue); static void QDECL R2D_CrosshairColor_Callback(struct cvar_s *var, char *oldvalue); +void (*R2D_Flush)(void); //We need this for minor things though, so we'll just use the slow accurate method. //this is unlikly to be called too often. @@ -410,6 +411,9 @@ void R2D_Image(float x, float y, float w, float h, float s1, float t1, float s2, return; } + if (R2D_Flush) + R2D_Flush(); + draw_mesh_xyz[0][0] = x; draw_mesh_xyz[0][1] = y; draw_mesh_st[0][0] = s1; @@ -447,6 +451,9 @@ void R2D_Image2dQuad(vec2_t points[], vec2_t texcoords[], mpic_t *pic) return; } + if (R2D_Flush) + R2D_Flush(); + for (i = 0; i < 4; i++) { Vector2Copy(points[i], draw_mesh_xyz[i]); @@ -459,6 +466,9 @@ void R2D_Image2dQuad(vec2_t points[], vec2_t texcoords[], mpic_t *pic) /*draws a block of the current colour on the screen*/ void R2D_FillBlock(float x, float y, float w, float h) { + if (R2D_Flush) + R2D_Flush(); + draw_mesh_xyz[0][0] = x; draw_mesh_xyz[0][1] = y; @@ -479,6 +489,9 @@ void R2D_FillBlock(float x, float y, float w, float h) void R2D_Line(float x1, float y1, float x2, float y2, shader_t *shader) { + if (R2D_Flush) + R2D_Flush(); + VectorSet(draw_mesh_xyz[0], x1, y1, 0); Vector2Set(draw_mesh_st[0], 0, 0); @@ -632,6 +645,9 @@ void R2D_TileClear (float x, float y, float w, float h) R2D_ImageColours(1,1,1,1); + if (R2D_Flush) + R2D_Flush(); + draw_mesh_xyz[0][0] = x; draw_mesh_xyz[0][1] = y; draw_mesh_st[0][0] = newsl; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 7c08d3ea9..e80e9ff24 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -1078,7 +1078,8 @@ qboolean R_ApplyRenderer (rendererstate_t *newr) return false; time = Sys_DoubleTime(); - M_Shutdown(false); + + M_RemoveAllMenus(true); Media_CaptureDemoEnd(); R_ShutdownRenderer(true); Con_DPrintf("video shutdown took %f seconds\n", Sys_DoubleTime() - time); @@ -1691,7 +1692,7 @@ void R_RestartRenderer (rendererstate_t *newr) SCR_EndLoadingPlaque(); TRACE(("dbg: R_RestartRenderer_f success\n")); - M_Reinit(); +// M_Reinit(); } void R_RestartRenderer_f (void) diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 8db8b6fa1..be5e990c9 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -3112,21 +3112,21 @@ ping time frags name if (p < 0 || p > 999) p = 999; \ sprintf(num, "%4i", p); \ Draw_FunStringWidth(x, y, num, 4*8, false, false); \ -}) +},) #define COLUMN_PL COLUMN(pl, 2*8, \ { \ int p = s->pl; \ sprintf(num, "%2i", p); \ Draw_FunStringWidth(x, y, num, 2*8, false, false); \ -}) +},) #define COLUMN_TIME COLUMN(time, 4*8, \ { \ total = realtime - s->realentertime; \ minutes = (int)total/60; \ sprintf (num, "%4i", minutes); \ Draw_FunStringWidth(x, y, num, 4*8, false, false); \ -}) +},) #define COLUMN_FRAGS COLUMN(frags, 5*8, \ { \ int cx; int cy; \ @@ -3136,12 +3136,6 @@ ping time frags name } \ else \ { \ - if (largegame) \ - Sbar_FillPC(x, y+1, 40, 3, top); \ - else \ - Sbar_FillPC(x, y, 40, 4, top); \ - Sbar_FillPC(x, y+4, 40, 4, bottom); \ - \ f = s->frags; \ sprintf(num, "%3i",f); \ \ @@ -3162,6 +3156,15 @@ ping time frags name } \ Font_EndString(font_default); \ } \ +},{ \ + if (!s->spectator) \ + { \ + if (largegame) \ + Sbar_FillPC(x, y+1, 40, 3, top); \ + else \ + Sbar_FillPC(x, y, 40, 4, top); \ + Sbar_FillPC(x, y+4, 40, 4, bottom); \ + } \ }) #define COLUMN_TEAMNAME COLUMN(team, 4*8, \ { \ @@ -3169,13 +3172,13 @@ ping time frags name { \ Draw_FunStringWidth(x, y, s->team, 4*8, false, false); \ } \ -}) -#define COLUMN_NAME COLUMN(name, (cl.teamplay ? 12*8 : 16*8), {Draw_FunStringWidth(x, y, s->name, (cl.teamplay ? 12*8 : 16*8), false, false);}) -#define COLUMN_KILLS COLUMN(kils, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetKills(k)), 4*8, false, false);}) -#define COLUMN_TKILLS COLUMN(tkil, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTKills(k)), 4*8, false, false);}) -#define COLUMN_DEATHS COLUMN(dths, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetDeaths(k)), 4*8, false, false);}) -#define COLUMN_TOUCHES COLUMN(tchs, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTouches(k)), 4*8, false, false);}) -#define COLUMN_CAPS COLUMN(caps, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetCaptures(k)), 4*8, false, false);}) +},) +#define COLUMN_NAME COLUMN(name, (cl.teamplay ? 12*8 : 16*8), {Draw_FunStringWidth(x, y, s->name, (cl.teamplay ? 12*8 : 16*8), false, false);},) +#define COLUMN_KILLS COLUMN(kils, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetKills(k)), 4*8, false, false);},) +#define COLUMN_TKILLS COLUMN(tkil, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTKills(k)), 4*8, false, false);},) +#define COLUMN_DEATHS COLUMN(dths, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetDeaths(k)), 4*8, false, false);},) +#define COLUMN_TOUCHES COLUMN(tchs, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTouches(k)), 4*8, false, false);},) +#define COLUMN_CAPS COLUMN(caps, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetCaptures(k)), 4*8, false, false);},) @@ -3184,7 +3187,7 @@ ping time frags name enum { -#define COLUMN(title, width, code) COLUMN##title, +#define COLUMN(title, width, code, fill) COLUMN##title, ALLCOLUMNS #undef COLUMN COLUMN_MAX @@ -3270,7 +3273,7 @@ void Sbar_DeathmatchOverlay (int start) rank_width = 0; -#define COLUMN(title, cwidth, code) if (rank_width+(cwidth)+8 <= gr.width) {showcolumns |= (1<name[0]) + continue; + + y += skip; + if (y > vid.height-10) + break; + + x = startx; +#define COLUMN(title, width, code, fills) \ if (showcolumns & (1<= vid.height-10) // we ran over the screen size, squish largegame = true; - - R2D_ImageColours(1.0, 1.0, 1.0, 1.0); } void Sbar_ChatModeOverlay(playerview_t *pv) @@ -3578,6 +3605,20 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv) x = sbar_rect.x + 320 + 4; + for (f = i, py = y; f < scoreboardlines && py < sbar_rect.y + sbar_rect.height - 8 + 1; f++) + { + k = fragsort[f]; + s = &cl.players[k]; + if (!s->name[0]) + continue; + // draw ping + top = Sbar_TopColour(s); + bottom = Sbar_BottomColour(s); + + Sbar_FillPC ( x, py+1, 40, 3, top); + Sbar_FillPC ( x, py+4, 40, 4, bottom); + py += 8; + } for (/* */ ; i < scoreboardlines && y < sbar_rect.y + sbar_rect.height - 8 + 1; i++) { k = fragsort[i]; @@ -3585,13 +3626,6 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv) if (!s->name[0]) continue; - // draw ping - top = Sbar_TopColour(s); - bottom = Sbar_BottomColour(s); - - Sbar_FillPC ( x, y+1, 40, 3, top); - Sbar_FillPC ( x, y+4, 40, 4, bottom); - // draw number f = s->frags; sprintf (num, "%3i",f); diff --git a/engine/client/snd_ov.c b/engine/client/snd_ov.c index 403d931ed..fb034a229 100644 --- a/engine/client/snd_ov.c +++ b/engine/client/snd_ov.c @@ -95,10 +95,6 @@ qboolean S_LoadOVSound (sfx_t *s, qbyte *data, int datalen, int sndspeed) buffer->decodedbytecount = 0; buffer->s = s; s->decoder.buf = buffer; - s->decoder.decodedata = OV_DecodeSome; - s->decoder.querydata = OV_Query; - s->decoder.purge = OV_CancelDecoder; - s->decoder.ended = OV_CancelDecoder; if (!OV_StartDecode(data, datalen, buffer)) { @@ -115,6 +111,10 @@ qboolean S_LoadOVSound (sfx_t *s, qbyte *data, int datalen, int sndspeed) s->loadstate = SLS_FAILED; //failed! return false; } + s->decoder.decodedata = OV_DecodeSome; + s->decoder.querydata = OV_Query; + s->decoder.purge = OV_CancelDecoder; + s->decoder.ended = OV_CancelDecoder; s->decoder.decodedata(s, NULL, 0, 100); diff --git a/engine/client/view.c b/engine/client/view.c index 96bfad5c9..aec2e1ac2 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "winquake.h" #include "glquake.h" +#include "gl_draw.h" #include // for isdigit(); @@ -1466,12 +1467,12 @@ entity_t *CL_EntityNum(int num) #endif float CalcFov (float fov_x, float width, float height); -void SCR_VRectForPlayer(vrect_t *vrect, int pnum) +static void SCR_VRectForPlayer(vrect_t *vrect, int pnum, unsigned maxseats) { #if MAX_SPLITS > 4 #pragma warning "Please change this function to cope with the new MAX_SPLITS value" #endif - switch(cl.splitclients) + switch(maxseats) { case 1: vrect->width = vid.fbvwidth; @@ -1828,7 +1829,7 @@ void R_DrawNameTags(void) if ((!cl.spectator && !cls.demoplayback || !scr_autoid.ival) && (!cl.teamplay || !scr_autoid_team.ival)) return; - if (cls.state != ca_active || !cl.validsequence) + if (cls.state != ca_active || !cl.validsequence || cl.intermission) return; if (r_refdef.playerview->cam_state != CAM_FREECAM && r_refdef.playerview->cam_spec_track >= 0) @@ -2048,16 +2049,20 @@ void V_RenderPlayerViews(playerview_t *pv) void V_RenderView (void) { int viewnum; + int maxviews = cl.splitclients; Surf_LessenStains(); if (cls.state != ca_active) return; + if (cl.intermission) + maxviews = 1; + R_PushDlights (); r_secondaryview = 0; - for (viewnum = 0; viewnum < cl.splitclients; viewnum++) + for (viewnum = 0; viewnum < maxviews; viewnum++) { V_ClearRefdef(&cl.playerview[viewnum]); if (viewnum) @@ -2085,7 +2090,9 @@ void V_RenderView (void) RSpeedEnd(RSPEED_LINKENTITIES); } } - SCR_VRectForPlayer(&r_refdef.grect, viewnum); + if (R2D_Flush) + R2D_Flush(); + SCR_VRectForPlayer(&r_refdef.grect, viewnum, maxviews); V_RenderPlayerViews(r_refdef.playerview); #ifdef PLUGINS diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 15f08bbea..b88fd35e7 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -277,6 +277,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g void QCBUILTIN PF_brush_delete(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_brush_selected(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_brush_getfacepoints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_brush_calcfacepoints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_brush_findinvolume(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_touchtriggers(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index 9cf493648..c7911313c 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -1026,6 +1026,8 @@ static void (D3D9_SCR_UpdateScreen) (void) } } + if (R2D_Flush) + R2D_Flush(); D3D9_Set2D(); R2D_BrightenScreen(); @@ -1051,6 +1053,8 @@ static void (D3D9_SCR_UpdateScreen) (void) RSpeedEnd(RSPEED_TOTALREFRESH); RSpeedShow(); + if (R2D_Flush) + R2D_Flush(); d3d9error(IDirect3DDevice9_EndScene(pD3DDev9)); d3d9error(IDirect3DDevice9_Present(pD3DDev9, NULL, NULL, NULL, NULL)); diff --git a/engine/gl/gl_draw.h b/engine/gl/gl_draw.h index b9a866966..73f56d0db 100644 --- a/engine/gl/gl_draw.h +++ b/engine/gl/gl_draw.h @@ -40,6 +40,8 @@ void R2D_FadeScreen (void); void R2D_Init(void); void R2D_Shutdown(void); +extern void (*R2D_Flush)(void); //if set, something is queued and must be flushed at some point. if its set to what you will set it to, then you can build onto your batch yourself. + void R2D_PolyBlend (void); void R2D_BrightenScreen (void); diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index b245d5bd7..70efa9445 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -2,6 +2,7 @@ #ifndef SERVERONLY #include "shader.h" +#include "gl_draw.h" #ifdef _WIN32 #include @@ -392,6 +393,7 @@ void Font_Init(void) //flush the font buffer, by drawing it to the screen static void Font_Flush(void) { + R2D_Flush = NULL; if (!font_foremesh.numindexes) return; if (fontplanes.planechanged) @@ -419,7 +421,7 @@ static int Font_BeginChar(texid_t tex) { int fvert; - if (font_foremesh.numindexes == FONT_CHAR_BUFFER*6 || font_texture != tex) + if (font_foremesh.numindexes >= FONT_CHAR_BUFFER*6 || font_texture != tex) { Font_Flush(); TEXASSIGNF(font_texture, tex); @@ -1521,7 +1523,9 @@ void Font_Free(struct font_s *f) //maps a given virtual screen coord to a pixel coord, which matches the font's height/width values void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py) { - Font_Flush(); + if (R2D_Flush && curfont != font) + R2D_Flush(); + R2D_Flush = Font_Flush; curfont = font; *px = (vx*(int)vid.rotpixelwidth) / (float)vid.width; @@ -1530,8 +1534,6 @@ void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py) curfont_scale[0] = curfont->charheight; curfont_scale[1] = curfont->charheight; curfont_scaled = false; - - font_colourmask = ~0u; //force the colour to be recalculated. } void Font_Transform(float vx, float vy, int *px, int *py) { @@ -1542,7 +1544,9 @@ void Font_Transform(float vx, float vy, int *px, int *py) } void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py) { - Font_Flush(); + if (R2D_Flush && curfont != font) + R2D_Flush(); + R2D_Flush = Font_Flush; curfont = font; *px = (vx*(float)vid.rotpixelwidth) / (float)vid.width; @@ -1560,13 +1564,14 @@ void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, curfont_scale[0] = (szx * (float)vid.rotpixelheight) / (curfont->charheight * (float)vid.height); curfont_scale[1] = (szy * (float)vid.rotpixelheight) / (curfont->charheight * (float)vid.height); - font_colourmask = ~0u; //force the colour to be recalculated. } void Font_EndString(struct font_s *font) { - Font_Flush(); - curfont = NULL; +// Font_Flush(); +// curfont = NULL; + + R2D_Flush = Font_Flush; } //obtains the font's row height (each row of chars should be drawn using this increment) @@ -1779,7 +1784,10 @@ void Font_ForceColour(float r, float g, float b, float a) return; if (font_colourmask & CON_NONCLEARBG) + { Font_Flush(); + R2D_Flush = Font_Flush; + } font_colourmask = CON_WHITEMASK; font_foretint[0] = r; @@ -1853,7 +1861,10 @@ int Font_DrawChar(int px, int py, unsigned int charflags, unsigned int codepoint { vec4_t rgba; if (font_colourmask & CON_NONCLEARBG) + { Font_Flush(); + R2D_Flush = Font_Flush; + } font_colourmask = col; rgba[0] = ((col>>CON_RICHRSHIFT)&0xf)*0x11; @@ -1899,7 +1910,10 @@ int Font_DrawChar(int px, int py, unsigned int charflags, unsigned int codepoint { vec4_t rgba; if ((col ^ font_colourmask) & CON_NONCLEARBG) + { Font_Flush(); + R2D_Flush = Font_Flush; + } font_colourmask = col; col = (charflags&CON_FGMASK)>>CON_FGSHIFT; @@ -2077,7 +2091,10 @@ float Font_DrawScaleChar(float px, float py, unsigned int charflags, unsigned in { vec4_t rgba; if (font_backcolour[3]) + { Font_Flush(); + R2D_Flush = Font_Flush; + } font_colourmask = col; rgba[0] = ((col>>CON_RICHRSHIFT)&0xf)*0x11; @@ -2119,7 +2136,10 @@ float Font_DrawScaleChar(float px, float py, unsigned int charflags, unsigned in { vec4_t rgba; if (font_backcolour[3] != ((charflags & CON_NONCLEARBG)?127:0)) + { Font_Flush(); + R2D_Flush = Font_Flush; + } font_colourmask = col; col = (charflags&CON_FGMASK)>>CON_FGSHIFT; diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 75b758302..8f5edb5f6 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -3274,9 +3274,11 @@ unsigned int Heightmap_PointContentsHM(heightmap_t *hm, float clipmipsz, vec3_t return hm->exteriorcontents; if (sx >= hm->maxsegx || sy >= hm->maxsegy) return hm->exteriorcontents; - s = Terr_GetSection(hm, sx, sy, TGS_TRYLOAD); - if (!s) + s = Terr_GetSection(hm, sx, sy, TGS_TRYLOAD | TGS_ANYSTATE); + if (!s || s->loadstate != TSLS_LOADED) { + if (s && s->loadstate == TSLS_FAILED) + return hm->exteriorcontents; return FTECONTENTS_SOLID; } @@ -3590,17 +3592,20 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty) else if (sy < tr->hm->firstsegy || sy >= tr->hm->maxsegy) return;//s = NULL; else - s = Terr_GetSection(tr->hm, sx, sy, TGS_TRYLOAD|TGS_WAITLOAD); + s = Terr_GetSection(tr->hm, sx, sy, TGS_TRYLOAD|TGS_WAITLOAD|TGS_ANYSTATE); - if (!s) + if (!s || s->loadstate != TSLS_LOADED) { - //you're not allowed to walk into sections that have not loaded. - //might as well check the entire section instead of just one tile - Vector4Set(n[0], 1, 0, 0, (tx/(SECTHEIGHTSIZE-1) + 1 - CHUNKBIAS)*tr->hm->sectionsize); - Vector4Set(n[1], -1, 0, 0, -(tx/(SECTHEIGHTSIZE-1) + 0 - CHUNKBIAS)*tr->hm->sectionsize); - Vector4Set(n[2], 0, 1, 0, (ty/(SECTHEIGHTSIZE-1) + 1 - CHUNKBIAS)*tr->hm->sectionsize); - Vector4Set(n[3], 0, -1, 0, -(ty/(SECTHEIGHTSIZE-1) + 0 - CHUNKBIAS)*tr->hm->sectionsize); - Heightmap_Trace_Brush(tr, n, 4); + if ((tr->contents & tr->hm->exteriorcontents) || s->loadstate != TSLS_FAILED) + { + //you're not allowed to walk into sections that have not loaded. + //might as well check the entire section instead of just one tile + Vector4Set(n[0], 1, 0, 0, (tx/(SECTHEIGHTSIZE-1) + 1 - CHUNKBIAS)*tr->hm->sectionsize); + Vector4Set(n[1], -1, 0, 0, -(tx/(SECTHEIGHTSIZE-1) + 0 - CHUNKBIAS)*tr->hm->sectionsize); + Vector4Set(n[2], 0, 1, 0, (ty/(SECTHEIGHTSIZE-1) + 1 - CHUNKBIAS)*tr->hm->sectionsize); + Vector4Set(n[3], 0, -1, 0, -(ty/(SECTHEIGHTSIZE-1) + 0 - CHUNKBIAS)*tr->hm->sectionsize); + Heightmap_Trace_Brush(tr, n, 4); + } return; } @@ -4576,14 +4581,20 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g if (!mod || !mod->terrain) { - if (mod) + if (mod && mod->loadstate == MLS_LOADING) + COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING); + if (mod && mod->loadstate == MLS_LOADED) { char basename[MAX_QPATH]; COM_FileBase(mod->name, basename, sizeof(basename)); mod->terrain = Mod_LoadTerrainInfo(mod, basename, true); - G_FLOAT(OFS_RETURN) = !!mod->terrain; + hm = mod->terrain; + if (!hm) + return; + Terr_FinishTerrain(mod); } - return; + else + return; } hm = mod->terrain; @@ -5400,8 +5411,24 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t * brushes_t *out; vec2_t mins, maxs; vec2_t lm; + if (!hm) - return NULL; + { + if (model && model->loadstate == MLS_LOADING) + COM_WorkerPartialSync(model, &model->loadstate, MLS_LOADING); + if (model && model->loadstate == MLS_LOADED) + { + char basename[MAX_QPATH]; + COM_FileBase(model->name, basename, sizeof(basename)); + model->terrain = Mod_LoadTerrainInfo(model, basename, true); + hm = model->terrain; + if (!hm) + return NULL; + Terr_FinishTerrain(model); + } + else + return NULL; + } hm->wbrushes = BZ_Realloc(hm->wbrushes, sizeof(*hm->wbrushes) * (hm->numbrushes+1)); out = &hm->wbrushes[hm->numbrushes]; @@ -5815,7 +5842,22 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g G_INT(OFS_RETURN) = 0; if (!hm) - return; + { + if (mod && mod->loadstate == MLS_LOADING) + COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING); + if (mod && mod->loadstate == MLS_LOADED) + { + char basename[MAX_QPATH]; + COM_FileBase(mod->name, basename, sizeof(basename)); + mod->terrain = Mod_LoadTerrainInfo(mod, basename, true); + hm = mod->terrain; + if (!hm) + return; + Terr_FinishTerrain(mod); + } + else + return; + } planes = alloca(sizeof(*planes) * numfaces); faces = alloca(sizeof(*faces) * numfaces); @@ -5940,6 +5982,61 @@ void QCBUILTIN PF_brush_selected(pubprogfuncs_t *prinst, struct globalvars_s *pr } } } + + + +// {"brush_calcfacepoints",PF_brush_calcfacepoints,0,0, 0, 0, D("int(int faceid, brushface_t *in_faces, int numfaces, vector *points, int maxpoints)", "Determines the points of the specified face, if the specified brush were to actually be created.")}, +void QCBUILTIN PF_brush_calcfacepoints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + unsigned int faceid = G_INT(OFS_PARM0); + unsigned int numfaces = G_INT(OFS_PARM2); + qcbrushface_t *in_faces = validateqcpointer(prinst, G_INT(OFS_PARM1), sizeof(*in_faces), numfaces); + unsigned int maxpoints = G_INT(OFS_PARM4); + vec3_t *out_verts = validateqcpointer(prinst, G_INT(OFS_PARM3), sizeof(*out_verts), maxpoints); + vecV_t facepoints[256]; + vec4_t planes[256]; + unsigned int j, numpoints; + + faceid--; + if (faceid < 0 || faceid >= numfaces) + { + G_INT(OFS_RETURN) = 0; + return; + } + + //make sure this isn't a dupe face + for (j = 0; j < faceid; j++) + { + if (in_faces[j].planenormal[0] == in_faces[faceid].planenormal[0] && + in_faces[j].planenormal[1] == in_faces[faceid].planenormal[1] && + in_faces[j].planenormal[2] == in_faces[faceid].planenormal[2] && + in_faces[j].planedist == in_faces[faceid].planedist) + { + G_INT(OFS_RETURN) = 0; + return; + } + } + + //generate a list that Terr_GenerateBrushFace can actually use, silly, but lets hope this isn't needed to be nippy + for (j = 0; j < numfaces; j++) + { + VectorCopy(in_faces[j].planenormal, planes[j]); + planes[j][3] = in_faces[j].planedist; + } + + //generate points now (so we know the correct mins+maxs for the brush, and whether the plane is relevent) + numpoints = Terr_GenerateBrushFace(facepoints, countof(facepoints), planes, numfaces, planes[faceid]); + G_INT(OFS_RETURN) = numpoints; + if (numpoints > maxpoints) + numpoints = maxpoints; + + //... and copy them out without padding. yeah, silly. + for (j = 0; j < numpoints; j++) + { + VectorCopy(facepoints[j], out_verts[j]); + } +} + // {"brush_getfacepoints",PF_brush_getfacepoints,0,0, 0, 0, D("int(float modelid, int brushid, int faceid, vector *points, int maxpoints)", "Allows you to easily set transient visual properties of a brush. If brush/face is -1, applies to all. returns old value. selectedstate=-1 changes nothing (called for its return value).")}, void QCBUILTIN PF_brush_getfacepoints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -6057,7 +6154,8 @@ void Terr_WriteBrushInfo(vfsfile_t *file, brushes_t *br) point[1] = br->faces[i].points[1]; point[2] = br->faces[i].points[2]; - VFS_PRINTF(file, "\n( %g %g %g ) ( %g %g %g ) ( %g %g %g ) \"%s\" [ %g %g %g %g ] [ %g %g %g %g ] 0 1 1", + //%.9g is 'meant' to be lossless for a standard ieee single-precision float. (%.17g for a double) + VFS_PRINTF(file, "\n( %.9g %.9g %.9g ) ( %.9g %.9g %.9g ) ( %.9g %.9g %.9g ) \"%s\" [ %.9g %.9g %.9g %.9g ] [ %.9g %.9g %.9g %.9g ] 0 1 1", point[0][0], point[0][1], point[0][2], point[1][0], point[1][1], point[1][2], point[2][0], point[2][1], point[2][2], diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index 417896134..f44d8c947 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -225,6 +225,8 @@ void GLSCR_UpdateScreen (void) RSpeedEnd(RSPEED_TOTALREFRESH); RSpeedShow(); + if (R2D_Flush) + R2D_Flush(); RSpeedRemark(); GL_EndRendering (); diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 1496d2e61..1c24dfda1 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -5465,7 +5465,7 @@ static qboolean Shader_ParseShader(char *parsename, shader_t *s) } void R_UnloadShader(shader_t *shader) { - if (shader->uses-- == 1) + if (--shader->uses == 0) Shader_Free(shader); } static shader_t *R_LoadShader (const char *name, unsigned int usageflags, shader_gen_t *defaultgen, const char *genargs) @@ -5493,6 +5493,8 @@ static shader_t *R_LoadShader (const char *name, unsigned int usageflags, shader //q3 has a separate (internal) shader for every lightmap. if (!((s->usageflags ^ usageflags) & SUF_LIGHTMAP)) { + if (!s->uses) + break; s->uses++; return s; } diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index 21f6a38f2..3239ed8af 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -602,6 +602,7 @@ pbool LocateDebugTerm(progfuncs_t *progfuncs, char *key, eval_t **result, etype_ char *c, *c2; etype_t type = ev_void; struct edictrun_s *ed; + etype_t ptrtype = ev_void; c = strchr(key, '.'); if (c) *c = '\0'; @@ -722,6 +723,43 @@ pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *ppf, char *key) return true; } +static char *PR_ParseCast(char *key, etype_t *t, pbool *isptr) +{ + extern char *basictypenames[]; + int type; + *t = ev_void; + *isptr = false; + while(*key == ' ') + key++; + if (*key == '(') + { + key++; + for (type = 0; type < 10; type++) + { + if (!strncmp(key, basictypenames[type], strlen(basictypenames[type]))) + { + key += strlen(basictypenames[type]); + while(*key == ' ') + key++; + if (*key == '*') + { + *isptr = true; + key++; + } + *t = type; + break; + } + } + if (type == 10) + return NULL; + + while(*key == ' ') + key++; + if (*key++ != ')') + return NULL; + } + return key; +} char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *ppf, char *key) { progfuncs_t *progfuncs = (progfuncs_t*)ppf; @@ -731,12 +769,44 @@ char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *ppf, char *key) char *assignment; etype_t type; eval_t fakeval; + extern char *basictypenames[]; + if (*key == '*') + { + int ptr; + eval_t v; + etype_t cast; + pbool isptr; + type = ev_void; + key = PR_ParseCast(key+1, &cast, &isptr); + if (!key || !isptr) + return "(unable to evaluate)"; + if (*key == '&') + { + if (!LocateDebugTerm(progfuncs, key+1, &val, &type, &fakeval) && val != &fakeval) + return "(unable to evaluate)"; + v._int = (char*)val - progfuncs->funcs.stringtable; + val = &v; + type = ev_pointer; + } + else + { + if (!LocateDebugTerm(progfuncs, key, &val, &type, &fakeval) && val != &fakeval) + return "(unable to evaluate)"; + } + if (type == ev_integer || type == ev_string || type == ev_pointer) + ptr = val->_int; + else if (type == ev_float) + ptr = val->_float; + else + return "(unable to evaluate)"; + return PR_ValueString(progfuncs, cast, (eval_t*)(progfuncs->funcs.stringtable + ptr), true); + } if (*key == '&') { if (!LocateDebugTerm(progfuncs, key+1, &val, &type, &fakeval) && val != &fakeval) return "(unable to evaluate)"; - QC_snprintfz(buf, sizeof(buf), "%#x", (char*)val - progfuncs->funcs.stringtable); + QC_snprintfz(buf, sizeof(buf), "(%s*)%#x", ((type>=10)?"???":basictypenames[type]), (char*)val - progfuncs->funcs.stringtable); return buf; } diff --git a/engine/qclib/qccgui.c b/engine/qclib/qccgui.c index 6ad6aca1d..f8fb3f087 100644 --- a/engine/qclib/qccgui.c +++ b/engine/qclib/qccgui.c @@ -568,6 +568,7 @@ pbool resetprogssrc; //progs.src was changed, reload project info. HWND mainwindow; HWND gamewindow; HWND mdibox; +HWND watches; HWND optionsmenu; HWND outputwindow; HWND outputbox; @@ -2762,13 +2763,27 @@ static LRESULT CALLBACK EngineWndProc(HWND hWnd,UINT message, free(ctx); } if (hWnd == gamewindow) + { gamewindow = NULL; + PostMessage(mainwindow, WM_SIZE, 0, 0); + } break; case WM_USER: //engine broke. show code. if (lParam) SetForegroundWindow(mainwindow); EditFile((char*)lParam, wParam-1, true); + + if (watches) + { + char text[MAX_PATH]; + int i, lim = ListView_GetItemCount(watches); + for (i = 0; i < lim; i++) + { + ListView_GetItemText(watches, i, 0, text, sizeof(text)); + EngineCommandWndf(hWnd, "qcinspect \"%s\" \"%s\"\n", text, ""); //term, scope + } + } break; case WM_USER+1: //engine loaded a progs, reset breakpoints. @@ -2809,6 +2824,17 @@ static LRESULT CALLBACK EngineWndProc(HWND hWnd,UINT message, SendMessage(tooltip_editor->editpane, SCI_CALLTIPSHOW, (WPARAM)tooltip_position, (LPARAM)tip); } + if (watches) + { + char text[MAX_PATH]; + int i, lim = ListView_GetItemCount(watches); + for (i = 0; i < lim; i++) + { + ListView_GetItemText(watches, i, 0, text, sizeof(text)); + if (!strcmp(text, varname)) + ListView_SetItemText(watches, i, 1, varvalue); + } + } free((char*)lParam); } break; @@ -3038,6 +3064,7 @@ void RunEngine(void) enginewindow_t *e = (enginewindow_t*)(LONG_PTR)GetWindowLongPtr(gamewindow, GWLP_USERDATA); } // SendMessage(mdibox, WM_MDIACTIVATE, (WPARAM)gamewindow, 0); + PostMessage(mainwindow, WM_SIZE, 0, 0); } @@ -3692,6 +3719,37 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message, 0, 0, 320, 200, hWnd, (HMENU) 0xCAC, ghInstance, (LPSTR) &ccs); ShowWindow(mdibox, SW_SHOW); + watches = CreateWindow(WC_LISTVIEW, (LPCTSTR) NULL, + WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_EDITLABELS, + 0, 0, 320, 200, hWnd, (HMENU) 0xCAD, ghInstance, NULL); + ShowWindow(watches, SW_SHOW); + + if (watches) + { + LVCOLUMN col; + LVITEM newi; +// ListView_SetUnicodeFormat(watches, TRUE); + ListView_SetExtendedListViewStyle(watches, LVS_EX_GRIDLINES); + memset(&col, 0, sizeof(col)); + col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; + col.fmt = LVCFMT_LEFT; + col.cx = 320; + col.pszText = "Variable"; + ListView_InsertColumn(watches, 0, &col); + col.pszText = "Value"; + ListView_InsertColumn(watches, 1, &col); + + + + memset(&newi, 0, sizeof(newi)); + + newi.pszText = ""; + newi.mask = LVIF_TEXT | LVIF_PARAM; + newi.lParam = ~0; + newi.iSubItem = 0; + ListView_InsertItem(watches, &newi); + } + projecttree = CreateWindow(WC_TREEVIEW, (LPCTSTR) NULL, WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | TVS_HASBUTTONS |TVS_LINESATROOT|TVS_HASLINES, @@ -3732,12 +3790,23 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message, GetClientRect(mainwindow, &rect); if (projecttree) { + int mdiheight, watchheight; SetWindowPos(projecttree, NULL, 0, 0, 192, rect.bottom-rect.top - 34 - 48, 0); SetWindowPos(search_name, NULL, 0, rect.bottom-rect.top - 33 - 48, 192, 24, 0); SetWindowPos(search_gotodef, NULL, 0, rect.bottom-rect.top - 33 - 24, 192/2, 24, 0); SetWindowPos(search_grep, NULL, 192/2, rect.bottom-rect.top - 33 - 24, 192/2, 24, 0); - SetWindowPos(mdibox?mdibox:outputbox, NULL, 192, 0, rect.right-rect.left-192, rect.bottom-rect.top - 32, 0); + + if (gamewindow) + watchheight = (ListView_GetItemCount(watches) + 2) * 16; + else + watchheight = 0; + mdiheight = (rect.bottom-rect.top) - 32; + if (watchheight > mdiheight/2) + watchheight = mdiheight/2; + mdiheight -= watchheight; + SetWindowPos(watches, NULL, 192, mdiheight, rect.right-rect.left-192, watchheight, 0); + SetWindowPos(mdibox?mdibox:outputbox, NULL, 192, 0, rect.right-rect.left-192, mdiheight, 0); } else SetWindowPos(mdibox?mdibox:outputbox, NULL, 0, 0, rect.right-rect.left, rect.bottom-rect.top - 32, 0); @@ -3796,9 +3865,9 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message, GetWindowText(search_name, greptext, sizeof(greptext)-1); return true; } - if (i>0 && i <= NUMBUTTONS) + if (i>=20 && i < 20+NUMBUTTONS) { - buttons[i-1].washit = 1; + buttons[i-20].washit = 1; break; } if (i < IDM_FIRSTCHILD) @@ -3831,7 +3900,84 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message, int oldlen; int newlen; nm = (NMHDR*)lParam; - if (nm->hwndFrom == projecttree) + if (nm->hwndFrom == watches) + { + NMLISTVIEW *lnm = (NMLISTVIEW*)nm; + switch(nm->code) + { + case LVN_BEGINLABELEDITA: + return FALSE; //false to allow... + case LVN_BEGINLABELEDITW: +// OutputDebugString("Begin EditW\n"); + return FALSE; //false to allow... + case LVN_ENDLABELEDITA: + if (((NMLVDISPINFOA*)nm)->item.iItem == ListView_GetItemCount(watches)-1) + { + LVITEM newi; + memset(&newi, 0, sizeof(newi)); + newi.iItem = ListView_GetItemCount(watches); + newi.pszText = ""; + newi.mask = LVIF_TEXT | LVIF_PARAM; + newi.lParam = ~0; + newi.iSubItem = 0; + ListView_InsertItem(watches, &newi); + } + EngineCommandf("qcinspect \"%s\" \"%s\"\n", ((NMLVDISPINFOA*)nm)->item.pszText, ""); //term, scope + PostMessage(mainwindow, WM_SIZE, 0, 0); + return TRUE; //true to allow... +/* case LVN_ENDLABELEDITW: +// OutputDebugString("End EditW\n"); + if (((NMLVDISPINFOW*)nm)->item.iItem == ListView_GetItemCount(watches)-1) + { + LVITEM newi; + memset(&newi, 0, sizeof(newi)); + newi.iItem = ListView_GetItemCount(watches); + newi.pszText = ""; + newi.mask = LVIF_TEXT | LVIF_PARAM; + newi.lParam = ~0; + newi.iSubItem = 0; + ListView_InsertItem(watches, &newi); + } + EngineCommandf("qcinspect \"%s\" \"%s\"\n", ((NMLVDISPINFOW*)nm)->item.pszText, ""); //term, scope + return TRUE; //true to allow... +*/ + case LVN_ITEMCHANGING: +// OutputDebugString("Changing\n"); + return FALSE; //false to allow... + case LVN_ITEMCHANGED: +// OutputDebugString("Changed\n"); + return FALSE; + case LVN_GETDISPINFOA: +// OutputDebugString("LVN_GETDISPINFOA\n"); + return FALSE; +// case LVN_GETDISPINFOW: +// OutputDebugString("LVN_GETDISPINFOW\n"); +// return FALSE; + case NM_DBLCLK: +// OutputDebugString("NM_DBLCLK\n"); + { + NMITEMACTIVATE *ia = (NMITEMACTIVATE*)nm; + LVHITTESTINFO ht; + memset(&ht, 0, sizeof(ht)); + ht.pt = ia->ptAction; + ListView_SubItemHitTest(watches, &ht); + ListView_EditLabel(watches, ht.iItem); + } + return TRUE; + case LVN_ITEMACTIVATE: +// OutputDebugString("LVN_ITEMACTIVATE\n"); + return FALSE; //must return false + case LVN_COLUMNCLICK: +// OutputDebugString("LVN_COLUMNCLICK\n"); + break; + default: +// sprintf(filename, "%i\n", nm->code); +// OutputDebugString(filename); + break; + } + return FALSE; + } + else if (nm->hwndFrom == projecttree) { switch(nm->code) { @@ -4856,7 +5002,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin WS_CHILD | WS_VISIBLE, 0, 0, 5, 5, mainwindow, - (HMENU)(LONG_PTR)(i+1), + (HMENU)(LONG_PTR)(i+20), ghInstance, NULL); } diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 6b7a603cd..86a73b11d 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -681,11 +681,11 @@ void PR_LoadGlabalStruct(qboolean muted) int i; int *v; globalptrs_t *pr_globals = pr_global_ptrs; -#define globalfloat(need,name) (pr_globals)->name = (float *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static float fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_Printf("Could not find \""#name"\" export in progs\n");} -#define globalint(need,name) (pr_globals)->name = (int *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static int fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_Printf("Could not find \""#name"\" export in progs\n");} -#define globalstring(need,name) (pr_globals)->name = (int *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static string_t fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_Printf("Could not find \""#name"\" export in progs\n");} -#define globalvec(need,name) (pr_globals)->name = (vec3_t *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static vec3_t fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_Printf("Could not find \""#name"\" export in progs\n");} -#define globalfunc(need,name) (pr_globals)->name = (func_t *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (!(pr_globals)->name) {static func_t stripped##name; stripped##name = PR_FindFunction(svprogfuncs, #name, 0); if (stripped##name) (pr_globals)->name = &stripped##name; else if (need && !muted) Con_Printf("Could not find function \""#name"\" in progs\n"); } +#define globalfloat(need,name) (pr_globals)->name = (float *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static float fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_DPrintf("Could not find \""#name"\" export in progs\n");} +#define globalint(need,name) (pr_globals)->name = (int *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static int fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_DPrintf("Could not find \""#name"\" export in progs\n");} +#define globalstring(need,name) (pr_globals)->name = (int *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static string_t fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_DPrintf("Could not find \""#name"\" export in progs\n");} +#define globalvec(need,name) (pr_globals)->name = (vec3_t *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static vec3_t fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_DPrintf("Could not find \""#name"\" export in progs\n");} +#define globalfunc(need,name) (pr_globals)->name = (func_t *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (!(pr_globals)->name) {static func_t stripped##name; stripped##name = PR_FindFunction(svprogfuncs, #name, 0); if (stripped##name) (pr_globals)->name = &stripped##name; else if (need && !muted) Con_DPrintf("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); @@ -773,7 +773,7 @@ void PR_LoadGlabalStruct(qboolean muted) static vec3_t fallback_trace_plane_normal; (pr_globals)->trace_plane_normal = &fallback_trace_plane_normal; if (!muted) - Con_Printf("Could not find export trace_plane_normal in progs\n"); + Con_DPrintf("Could not find trace_plane_normal export in progs\n"); } } if (!(pr_globals)->trace_endpos) @@ -784,7 +784,7 @@ void PR_LoadGlabalStruct(qboolean muted) static vec3_t fallback_trace_endpos; (pr_globals)->trace_endpos = &fallback_trace_endpos; if (!muted) - Con_Printf("Could not find export trace_endpos in progs\n"); + Con_DPrintf("Could not find trace_endpos export in progs\n"); } } if (!(pr_globals)->trace_fraction) @@ -795,7 +795,7 @@ void PR_LoadGlabalStruct(qboolean muted) static float fallback_trace_fraction; (pr_globals)->trace_fraction = &fallback_trace_fraction; if (!muted) - Con_Printf("Could not find export trace_fraction in progs\n"); + Con_DPrintf("Could not find trace_fraction export in progs\n"); } } ensureglobal(serverflags, zero_default); @@ -9622,7 +9622,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"brush_delete", PF_brush_delete, 0, 0, 0, 0, D("void(float modelidx, int brushid)", "Destroys the specified brush.")}, {"brush_selected", PF_brush_selected, 0, 0, 0, 0, D("float(float modelid, int brushid, int faceid, float selectedstate)", "Allows you to easily set transient visual properties of a brush. returns old value. selectedstate=-1 changes nothing (called for its return value).")}, {"brush_getfacepoints",PF_brush_getfacepoints,0,0, 0, 0, D("int(float modelid, int brushid, int faceid, vector *points, int maxpoints)", "Returns the list of verticies surrounding the given face. If face is 0, returns the center of the brush (if space for 1 point) or the mins+maxs (if space for 2 points).")}, -// {"brush_calcfacepoints",PF_brush_calcfacepoints,0,0, 0, 0, D("int(brushface_t *in_faces, int numfaces, int faceid, vector *points, int maxpoints)", "Returns the list of verticies surrounding the given face. If face is 0, returns the center of the brush (if space for 1 point) or the mins+maxs (if space for 2 points). Returns 0 if a face is degenerate.")}, + {"brush_calcfacepoints",PF_brush_calcfacepoints,0,0, 0, 0, D("int(int faceid, brushface_t *in_faces, int numfaces, vector *points, int maxpoints)", "Determines the points of the specified face, if the specified brush were to actually be created.")}, {"brush_findinvolume",PF_brush_findinvolume,0, 0, 0, 0, D("int(float modelid, vector *planes, float *dists, int numplanes, int *out_brushes, int *out_faces, int maxresults)", "Allows you to easily obtain a list of brushes+faces within the given bounding region. If out_faces is not null, the same brush might be listed twice.")}, // {"brush_editplane", PF_brush_editplane, 0, 0, 0, 0, D("float(float modelid, int brushid, int faceid, in brushface *face)", "Changes a surface's texture info.")}, // {"brush_transformselected",PF_brush_transformselected,0,0,0, 0, D("int(float modelid, int brushid, float *matrix)", "Transforms selected brushes by the given transform")}, @@ -10711,6 +10711,7 @@ void PR_DumpPlatform_f(void) {"CSQC_Parse_Event", "void()", CS, "Called when the client receives an SVC_CGAMEPACKET. The csqc should read the data or call the error builtin if it does not recognise the message."}, {"CSQC_InputEvent", "float(float evtype, float scanx, float chary, float devid)", CS, "Called whenever a key is pressed, the mouse is moved, etc. evtype will be one of the IE_* constants. The other arguments vary depending on the evtype. Key presses are not guarenteed to have both scan and unichar values set at the same time."}, {"CSQC_Input_Frame", "__used void()", CS, "Called just before each time clientcommandframe is updated. You can edit the input_* globals in order to apply your own player inputs within csqc, which may allow you a convienient way to pass certain info to ssqc."}, + {"CSQC_RendererRestarted", "void(void)", CS, "Called by the engine after the video was restarted. This serves to notify the CSQC that any render targets that it may have cached were purged, and will need to be regenerated."}, {"CSQC_ConsoleCommand", "float(string cmd)", CS, "Called if the user uses any console command registed via registercommand."}, {"CSQC_ConsoleLink", "float(string text, string info)", CS, "Called if the user clicks a ^[text\\infokey\\infovalue^] link. Use infoget to read/check each supported key. Return true if you wish the engine to not attempt to handle the link itself."}, {"CSQC_Ent_Update", "void(float isnew)", CS},