1
0
Fork 0
forked from fte/fteqw

qcc: allow variable definitions inside for statements. these are strictly subscoped.

csaddon: implement convenient vertex dragging. not bug free, but should be sufficiently functional.
small optimisation for r_loadlit 2.
sdl2: now supports hardware cursors, supposedly. also ensures the window title is set to something that isn't obviously weird.
fix #water replacements not being loaded. again.
.map loading now ignores all lightstyles, instead of many lights being completely black.
.map loading can now properly cope with angled surfaces without the player getting stuck.
try to avoid missing d3d11 definitions issue.
tp_disputablemacros no longer blocks say commands, but does block +forward etc. supposedly.
fix timer precision issue that appears in sdl builds. not sure why it wasn't visible in other cases though.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4989 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-09-18 20:30:10 +00:00
parent 12dd83c20f
commit cc875358fd
23 changed files with 900 additions and 232 deletions

View file

@ -4748,7 +4748,7 @@ double Host_Frame (double time)
realtime = newrealtime;
if (oldrealtime > realtime)
oldrealtime = 0;
oldrealtime = realtime;
if (cl.gamespeed<0.1)
cl.gamespeed = 1;
@ -4831,7 +4831,10 @@ double Host_Frame (double time)
#ifndef CLIENTONLY
if (sv.state && cls.state != ca_active)
{
maxfpsignoreserver = false;
maxfps = 0;
}
else
#endif
if ((cl_netfps.value>0 || cls.demoplayback || cl_threadedphysics.ival))

View file

@ -13,6 +13,7 @@ void M_Script_Option (menu_t *menu, char *optionvalue)
menuoption_t *mo;
char buf[8192];
int level;
Cbuf_AddText("wait\n", RESTRICT_LOCAL);
@ -32,7 +33,8 @@ void M_Script_Option (menu_t *menu, char *optionvalue)
}
}
Cmd_TokenizeString(buf, false, false);
Cmd_ExpandString(menu->data, buf, sizeof(buf), RESTRICT_SERVER, true, true);
level = RESTRICT_SERVER;
Cmd_ExpandString(menu->data, buf, sizeof(buf), &level, true, true);
//and execute it as-is
Cbuf_AddText(buf, RESTRICT_LOCAL);

View file

@ -463,11 +463,15 @@ typedef struct {
char *ext[64];
int numext;
int dragscroll;
int mousedownpos;
demoitem_t *items;
} demomenu_t;
static void M_DemoDraw(int x, int y, menucustom_t *control, menu_t *menu)
{
extern qboolean keydown[K_MAX];
char *text;
demomenu_t *info = menu->data;
demoitem_t *item, *lostit;
@ -499,20 +503,50 @@ static void M_DemoDraw(int x, int y, menucustom_t *control, menu_t *menu)
if (!item)
info->firstitem = info->items;
if (!info->dragscroll && keydown[K_MOUSE1])
{
info->dragscroll = 1;
info->mousedownpos = mousecursor_y;
}
if (info->dragscroll && keydown[K_MOUSE1])
{
if (info->mousedownpos >= mousecursor_y+8)
{
info->dragscroll = 2;
info->mousedownpos -= 8;
if (info->firstitem->next)
{
if (info->firstitem == info->selected)
info->selected = info->firstitem->next;
info->firstitem = info->firstitem->next;
}
}
if (info->mousedownpos+8 <= mousecursor_y)
{
info->dragscroll = 2;
info->mousedownpos += 8;
if (info->firstitem->prev)
{
if (ty <= 24)
info->selected = info->selected->prev;
info->firstitem = info->firstitem->prev;
}
}
}
item = info->firstitem;
while(item)
{
if (y+8 >= vid.height)
if (y >= vid.height)
return;
if (!item->isdir)
text = va("%-32.32s%6iKB", item->name+info->pathlen, item->size/1024);
else
text = item->name+info->pathlen;
if (item == info->selected)
Draw_AltFunString(x, y+8, text);
Draw_AltFunString(x, y, text);
else
Draw_FunString(x, y+8, text);
Draw_FunString(x, y, text);
y+=8;
item = item->next;
}
@ -521,6 +555,7 @@ static void ShowDemoMenu (menu_t *menu, const char *path);
static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key, unsigned int unicode)
{
demomenu_t *info = menu->data;
demoitem_t *it;
int i;
switch (key)
@ -557,6 +592,26 @@ static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key, unsigned
info->selected = info->selected->next;
}
break;
case K_MOUSE1:
if (info->dragscroll == 2)
{
info->dragscroll = 0;
break;
}
it = info->firstitem;
i = (mousecursor_y - control->common.posy) / 8;
while(i > 0 && it && it->next)
{
it = it->next;
i--;
}
if (info->selected != it)
{
info->selected = it;
info->dragscroll = 0;
break;
}
//fallthrough
case K_ENTER:
case K_KP_ENTER:
if (info->selected)
@ -574,6 +629,9 @@ static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key, unsigned
if (extnum == info->numext) //wasn't on our list of extensions.
extnum = 0;
if (!info->command[extnum])
return true; //FIXME: archives
Cbuf_AddText(va("%s \"%s%s\"\n", info->command[extnum], (info->fs->fsroot==FS_SYSTEM)?"#":"", info->selected->name), RESTRICT_LOCAL);
if (!shift_down)
M_RemoveMenu(menu);

View file

@ -470,7 +470,7 @@ struct llightinfo_s;
void LightFace (struct relight_ctx_s *ctx, struct llightinfo_s *threadctx, int surfnum); //version that is aware of bsp trees
void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *threadctx, qbyte surf_styles[4], qbyte *surf_rgbsamples, qbyte *surf_deluxesamples, vec4_t surf_plane, vec4_t surf_texplanes[2], vec2_t exactmins, vec2_t exactmaxs, int texmins[2], int texsize[2], float lmscale); //special version that doesn't know what a face is or anything.
struct relight_ctx_s *LightStartup(struct relight_ctx_s *ctx, struct model_s *model, qboolean shadows);
void LightReloadEntities(struct relight_ctx_s *ctx, char *entstring);
void LightReloadEntities(struct relight_ctx_s *ctx, char *entstring, qboolean ignorestyles);
void LightShutdown(struct relight_ctx_s *ctx, struct model_s *mod);
extern const size_t lightthreadctxsize;
#endif

View file

@ -73,22 +73,18 @@ void Sys_Printf (char *fmt, ...)
unsigned int Sys_Milliseconds(void)
{
static int first = true;
static unsigned long oldtime = 0, curtime = 0;
unsigned long newtime;
static unsigned long starttime = 0;
unsigned long now;
newtime = SDL_GetTicks();
now = SDL_GetTicks();
if (first)
{
first = false;
oldtime = newtime;
starttime = now;
}
if (newtime < oldtime)
Con_Printf("Sys_Milliseconds stepped backwards!\n");
else
curtime += newtime - oldtime;
oldtime = newtime;
return curtime;
return now - starttime;
}
//return the current time, in the form of a double

View file

@ -1639,6 +1639,7 @@ char *TP_LocationName (vec3_t location)
vec3_t vec;
static qbool recursive;
static char buf[MAX_LOC_NAME];
int level;
if (!loc_numentries || (cls.state != ca_active))
return tp_name_someplace.string;
@ -1668,7 +1669,8 @@ char *TP_LocationName (vec3_t location)
}
recursive = true;
Cmd_ExpandString (locdata[minnum].name, buf, sizeof(buf), Cmd_ExecLevel, true, false);
level = Cmd_ExecLevel;
Cmd_ExpandString (locdata[minnum].name, buf, sizeof(buf), &level, true, false);
recursive = false;
return buf;
@ -3376,12 +3378,14 @@ void TP_UpdateAutoStatus(void)
{
char newstatusbuf[sizeof(vars.autoteamstatus)];
char *newstatus;
int level;
if (vars.autoteamstatus_time > realtime || !*tp_autostatus.string)
return;
vars.autoteamstatus_time = realtime + 3;
newstatus = Cmd_ExpandString(tp_autostatus.string, newstatusbuf, sizeof(newstatusbuf), tp_autostatus.restriction, true, true);
level = tp_autostatus.restriction;
newstatus = Cmd_ExpandString(tp_autostatus.string, newstatusbuf, sizeof(newstatusbuf), &level, true, true);
newstatus = TP_ParseMacroString(newstatus);
if (!strcmp(newstatus, vars.autoteamstatus))
@ -3737,7 +3741,8 @@ void CL_Say (qboolean team, char *extra)
!strchr(s, '\x0d') /* explicit $\ in message overrides cl_fakename */)
{
char buf[1024];
Cmd_ExpandString (cl_fakename.string, buf, sizeof(buf), Cmd_ExecLevel, true, true);
int level = Cmd_ExecLevel;
Cmd_ExpandString (cl_fakename.string, buf, sizeof(buf), &level, true, true);
strcpy (buf, TP_ParseMacroString (buf));
Q_snprintfz (sendtext, sizeof(sendtext), "\x0d%s: ", TP_ParseFunChars(buf));
}

View file

@ -96,9 +96,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define AVAIL_DINPUT
#define AVAIL_DDRAW
#define AVAIL_DSOUND
// #define AVAIL_XAUDIO2
#define AVAIL_D3D
#endif
#ifdef WINRT
#define AVAIL_XAUDIO2
#endif
#define AVAIL_XZDEC
#if !defined(MINIMAL) && !defined(NPFTE) && !defined(NPQTV)

View file

@ -98,7 +98,7 @@ void Cmd_AddMacro(char *s, char *(*f)(void), int disputableintentions)
macro_count++;
}
char *TP_MacroString (char *s, int *len)
char *TP_MacroString (char *s, int *newaccesslevel, int *len)
{
int i;
macro_command_t *macro;
@ -110,7 +110,7 @@ char *TP_MacroString (char *s, int *len)
{
if (macro->disputableintentions)
if (!tp_disputablemacros.ival)
continue;
*newaccesslevel = 0;
if (len)
*len = strlen(macro->name);
return macro->func();
@ -1244,7 +1244,7 @@ void Cmd_ShiftArgs (int ammount, qboolean expandstring)
}
}
char *Cmd_ExpandCvar(char *cvarname, int maxaccesslevel, int *len)
char *Cmd_ExpandCvar(char *cvarname, int maxaccesslevel, int *newaccesslevel, int *len)
{
char *ret = NULL, *end, *namestart;
char *fixup = NULL, fixval=0;
@ -1291,6 +1291,9 @@ char *Cmd_ExpandCvar(char *cvarname, int maxaccesslevel, int *len)
if (var->restriction <= maxaccesslevel && !((var->flags & CVAR_NOUNSAFEEXPAND) && Cmd_IsInsecure()))
{
ret = var->string;
if (var->flags & CVAR_TEAMPLAYTAINT) //if we're only allowed to expand this for teamplay, then switch access levels
*newaccesslevel = 0;
}
}
*fixup = fixval;
@ -1312,7 +1315,7 @@ If not SERVERONLY, also expands $macro expressions
Note: dest must point to a 1024 byte buffer
================
*/
char *Cmd_ExpandString (char *data, char *dest, int destlen, int maxaccesslevel, qboolean expandcvars, qboolean expandmacros)
char *Cmd_ExpandString (char *data, char *dest, int destlen, int *accesslevel, qboolean expandcvars, qboolean expandmacros)
{
unsigned int c;
char buf[255];
@ -1322,6 +1325,7 @@ char *Cmd_ExpandString (char *data, char *dest, int destlen, int maxaccesslevel,
char *bestvar;
int name_length, var_length;
qboolean striptrailing;
int maxaccesslevel = *accesslevel;
len = 0;
@ -1349,9 +1353,9 @@ char *Cmd_ExpandString (char *data, char *dest, int destlen, int maxaccesslevel,
data++;
buf[i++] = c;
buf[i] = 0;
if (expandcvars && (str = Cmd_ExpandCvar(buf+striptrailing, maxaccesslevel, &var_length)))
if (expandcvars && (str = Cmd_ExpandCvar(buf+striptrailing, maxaccesslevel, accesslevel, &var_length)))
bestvar = str;
if (expandmacros && (str = TP_MacroString (buf+striptrailing, &var_length)))
if (expandmacros && (str = TP_MacroString (buf+striptrailing, accesslevel, &var_length)))
bestvar = str;
}
@ -2122,7 +2126,7 @@ void Cmd_ExecuteString (char *text, int level)
char dest[8192];
text = Cmd_ExpandString(text, dest, sizeof(dest), level, !Cmd_IsInsecure()?true:false, true);
text = Cmd_ExpandString(text, dest, sizeof(dest), &level, !Cmd_IsInsecure()?true:false, true);
Cmd_TokenizeString (text, level == RESTRICT_LOCAL?true:false, false);
// execute the command line
@ -2137,6 +2141,9 @@ void Cmd_ExecuteString (char *text, int level)
if (strcmp (cmd_argv[0],cmd->name))
break; //yes, I know we found it... (but it's the wrong case, go for an alias or cvar instead FIRST)
if (!level)
break;
if ((cmd->restriction?cmd->restriction:rcon_level.ival) > level)
Con_TPrintf("cmd '%s' was restricted.\n", cmd_argv[0]);
else if (!cmd->function)
@ -2186,15 +2193,20 @@ void Cmd_ExecuteString (char *text, int level)
return;
#endif
if ((a->restriction?a->restriction:rcon_level.ival) > level)
{
Con_TPrintf("alias '%s' was restricted.\n", cmd_argv[0]);
return;
}
if (a->execlevel)
execlevel = a->execlevel;
else
if (!level)
execlevel = level;
else
{
if ((a->restriction?a->restriction:rcon_level.ival) > level)
{
Con_TPrintf("alias '%s' was restricted.\n", cmd_argv[0]);
return;
}
if (a->execlevel)
execlevel = a->execlevel;
else
execlevel = level;
}
Cbuf_InsertText ("\n", execlevel, false);
@ -2220,7 +2232,35 @@ void Cmd_ExecuteString (char *text, int level)
if (Cvar_Command (level))
return;
if (!level)
{
char *tpcmds[] =
{
"if", "wait", /*would be nice to include alias in here*/
"say", "say_team", "echo", /*display stuff, because it would be useless otherwise*/
"set_tp", "set", "set_calc", "inc", /*because scripting variables is fun. not.*/
"tp_point", "tp_pickup", "tp_took" /*updates what the $took etc macros are allowed to generate*/
};
if (cmd)
{
for (level = 0; level < countof(tpcmds); level++)
{
if (!strcmp(cmd_argv[0], tpcmds[level]))
{
int olev = Cmd_ExecLevel;
Cmd_ExecLevel = 0;
if (!cmd->function)
Cmd_ForwardToServer ();
else
cmd->function();
Cmd_ExecLevel = olev;
return;
}
}
}
Con_TPrintf("'%s' is not permitted in combination with teamplay macros.\n", cmd_argv[0]);
return;
}
if (cmd) //go for skipped ones
{
@ -2843,7 +2883,7 @@ elseif:
}
skipws:
while(*end <= ' ' && *end) //skip leading whitespace.
while(*end == ' ' || *end == '\t') //skip leading whitespace.
end++;
for (ws = end + strlen(end)-1; ws >= end && *ws <= ' '; ws--) //skip trailing
@ -2855,9 +2895,12 @@ skipws:
goto skipws;
}
while (*end == ' ' || *end == '\t')
end++;
if (!*end)
{
if (ret && *ret) //equation was true.
if (is_true(ret)) //equation was true.
{
trueblock = true;
Cbuf_ExecBlock(level);
@ -3028,7 +3071,7 @@ void Cmd_set_f(void)
forceflags = 0;
}
var = Cvar_Get (name, text, 0, "Custom variables");
var = Cvar_Get (name, text, CVAR_TEAMPLAYTAINT, "Custom variables");
mark = If_Token_GetMark();
@ -3061,6 +3104,9 @@ void Cmd_set_f(void)
Cvar_Set(var, text);
var->flags |= CVAR_USERCREATED | forceflags;
if (Cmd_ExecLevel == RESTRICT_TEAMPLAY)
var->flags |= CVAR_TEAMPLAYTAINT;
if (!strncmp(Cmd_Argv(0), "seta", 4))
var->flags |= CVAR_ARCHIVE;
}
@ -3114,7 +3160,13 @@ void Cvar_Inc_f (void)
delta = (c == 3) ? atof (Cmd_Argv(2)) : 1;
Cvar_SetValue (var, var->value + delta);
if (Cmd_ExecLevel == RESTRICT_TEAMPLAY || (var->flags & CVAR_TEAMPLAYTAINT))
{
Cvar_SetValue (var, var->value + delta);
var->flags |= CVAR_TEAMPLAYTAINT;
}
else
Cvar_SetValue (var, var->value + delta);
}
void Cmd_WriteConfig_f(void)

View file

@ -133,9 +133,10 @@ void Cmd_ExecuteString (char *text, int restrictionlevel);
void Cmd_Args_Set(const char *newargs);
#define RESTRICT_MAX_TOTAL 31
#define RESTRICT_MAX_USER 29 //1-64 it's all about bit size. This is max settable. servers are +1 or +2
#define RESTRICT_DEFAULT 20 //rcon get's 63, local always gets 64
#define RESTRICT_MIN 1 //rcon get's 63, local always gets 64
#define RESTRICT_MAX_USER 29
#define RESTRICT_DEFAULT 20
#define RESTRICT_MIN 1
#define RESTRICT_TEAMPLAY 0
#define RESTRICT_MAX RESTRICT_MAX_USER
@ -161,7 +162,7 @@ void Cmd_MessageTrigger (char *message, int type);
void Cmd_ShiftArgs (int ammount, qboolean expandstring);
char *Cmd_ExpandString (char *data, char *dest, int destlen, int maxaccesslevel, qboolean expandcvars, qboolean expandmacros);
char *Cmd_ExpandString (char *data, char *dest, int destlen, int *accesslevel, qboolean expandcvars, qboolean expandmacros);
qboolean If_EvaluateBoolean(const char *text, int restriction);
extern cvar_t rcon_level;

View file

@ -812,6 +812,8 @@ cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
var->value = Q_atof (var->string);
var->ival = Q_atoi (var->string);
var->flags &= ~CVAR_TEAMPLAYTAINT;
{
char *str = COM_Parse(var->string);
var->vec4[0] = atof(com_token);
@ -1016,9 +1018,9 @@ void Cvar_SetValue (cvar_t *var, float value)
{
char val[32];
if (value == (int)value)
sprintf (val, "%i",(int)value); //make it look nicer.
else
// if (value == (int)value)
// sprintf (val, "%i",(int)value); //make it look nicer.
// else
sprintf (val, "%g",value);
Cvar_Set (var, val);
}
@ -1238,7 +1240,7 @@ qboolean Cvar_Command (int level)
if (!v)
return false;
if ((v->restriction?v->restriction:rcon_level.ival) > level)
if (!level || (v->restriction?v->restriction:rcon_level.ival) > level)
{
Con_Printf ("You do not have the priveledges for %s\n", v->name);
return true;

View file

@ -141,6 +141,7 @@ typedef struct cvar_group_s
#define CVAR_CONFIGDEFAULT (1<<18) //this cvar's default value has been changed to match a config.
#define CVAR_NOSAVE (1<<19) //this cvar should never be saved. ever.
#define CVAR_NORESET (1<<20) //cvar is not reset by various things.
#define CVAR_TEAMPLAYTAINT (1<<21) //current value contains the evaluation of a teamplay macro.
#define CVAR_LASTFLAG CVAR_SHADERSYSTEM

View file

@ -80,8 +80,13 @@ enum
rht_empty,
rht_impact
};
vec3_t rht_start, rht_end;
static int Q1BSP_RecursiveHullTrace (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
struct rhtctx_s
{
vec3_t start, end;
mclipnode_t *clipnodes;
mplane_t *planes;
};
static int Q1BSP_RecursiveHullTrace (struct rhtctx_s *ctx, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
{
mclipnode_t *node;
mplane_t *plane;
@ -116,8 +121,8 @@ reenter:
/*its a node*/
/*get the node info*/
node = hull->clipnodes + num;
plane = hull->planes + node->planenum;
node = ctx->clipnodes + num;
plane = ctx->planes + node->planenum;
if (plane->type < 3)
{
@ -146,13 +151,13 @@ reenter:
if (plane->type < 3)
{
t1 = rht_start[plane->type] - plane->dist;
t2 = rht_end[plane->type] - plane->dist;
t1 = ctx->start[plane->type] - plane->dist;
t2 = ctx->end[plane->type] - plane->dist;
}
else
{
t1 = DotProduct (plane->normal, rht_start) - plane->dist;
t2 = DotProduct (plane->normal, rht_end) - plane->dist;
t1 = DotProduct (plane->normal, ctx->start) - plane->dist;
t2 = DotProduct (plane->normal, ctx->end) - plane->dist;
}
side = t1 < 0;
@ -160,12 +165,12 @@ reenter:
midf = t1 / (t1 - t2);
if (midf < p1f) midf = p1f;
if (midf > p2f) midf = p2f;
VectorInterpolate(rht_start, midf, rht_end, mid);
VectorInterpolate(ctx->start, midf, ctx->end, mid);
rht = Q1BSP_RecursiveHullTrace(hull, node->children[side], p1f, midf, p1, mid, trace);
rht = Q1BSP_RecursiveHullTrace(ctx, node->children[side], p1f, midf, p1, mid, trace);
if (rht != rht_empty)
return rht;
rht = Q1BSP_RecursiveHullTrace(hull, node->children[side^1], midf, p2f, mid, p2, trace);
rht = Q1BSP_RecursiveHullTrace(ctx, node->children[side^1], midf, p2f, mid, p2, trace);
if (rht != rht_solid)
return rht;
@ -184,14 +189,14 @@ reenter:
midf = (t1 - DIST_EPSILON) / (t1 - t2);
}
t1 = DotProduct (trace->plane.normal, rht_start) - trace->plane.dist;
t2 = DotProduct (trace->plane.normal, rht_end) - trace->plane.dist;
t1 = DotProduct (trace->plane.normal, ctx->start) - trace->plane.dist;
t2 = DotProduct (trace->plane.normal, ctx->end) - trace->plane.dist;
midf = (t1 - DIST_EPSILON) / (t1 - t2);
midf = bound(0, midf, 1);
trace->fraction = midf;
VectorCopy (mid, trace->endpos);
VectorInterpolate(rht_start, midf, rht_end, trace->endpos);
VectorInterpolate(ctx->start, midf, ctx->end, trace->endpos);
return rht_impact;
}
@ -219,9 +224,12 @@ qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f,
}
else
{
VectorCopy(p1, rht_start);
VectorCopy(p2, rht_end);
return Q1BSP_RecursiveHullTrace(hull, num, p1f, p2f, p1, p2, trace) != rht_impact;
struct rhtctx_s ctx;
VectorCopy(p1, ctx.start);
VectorCopy(p2, ctx.end);
ctx.clipnodes = hull->clipnodes;
ctx.planes = hull->planes;
return Q1BSP_RecursiveHullTrace(&ctx, num, p1f, p2f, p1, p2, trace) != rht_impact;
}
}
@ -832,6 +840,7 @@ hull_t *Q1BSP_ChooseHull(model_t *model, int forcehullnum, vec3_t mins, vec3_t m
hull = &model->hulls[forcehullnum-1];
else
{
#ifdef HEXEN2
if (model->hulls[5].available)
{ //choose based on hexen2 sizes.
@ -847,6 +856,7 @@ hull_t *Q1BSP_ChooseHull(model_t *model, int forcehullnum, vec3_t mins, vec3_t m
hull = &model->hulls[5];
}
else
#endif
{
if (size[0] < 3 || !model->hulls[1].available)
hull = &model->hulls[0];
@ -931,8 +941,12 @@ qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3]
hull = Q1BSP_ChooseHull(model, forcehullnum, mins, maxs, offset);
// offset[0] = 0;
// offset[1] = 0;
//fix for hexen2 monsters half-walking into walls.
// if (forent.flags & FL_MONSTER)
// {
// offset[0] = 0;
// offset[1] = 0;
// }
if (axis)
{

View file

@ -703,7 +703,7 @@ static qboolean D3D11_VID_Init(rendererstate_t *info, unsigned char *palette)
scd.Format = info->srgb?DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:DXGI_FORMAT_B8G8R8A8_UNORM;
scd.Stereo = info->stereo;
scd.SampleDesc.Count = d3d11multisample_count = max(1,info->multisample);
scd.SampleDesc.Quality = d3d11multisample_quality = (d3d11multisample_count>1)?D3D11_STANDARD_MULTISAMPLE_PATTERN:0;
scd.SampleDesc.Quality = d3d11multisample_quality = (d3d11multisample_count>1)?~0:0;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.BufferCount = 2+info->triplebuffer; //rt only supports fullscreen, so the frontbuffer needs to be created by us.
scd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
@ -782,7 +782,7 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = hWnd;
scd.SampleDesc.Count = d3d11multisample_count = max(1, info->multisample); //as we're starting up windowed (and switching to fullscreen after), the frontbuffer is handled by windows.
scd.SampleDesc.Quality = d3d11multisample_quality = (d3d11multisample_count>1)?D3D11_STANDARD_MULTISAMPLE_PATTERN:0;
scd.SampleDesc.Quality = d3d11multisample_quality = 0;
scd.Windowed = TRUE;
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;// | DXGI_SWAP_CHAIN_FLAG_NONPREROTATED;

View file

@ -270,6 +270,7 @@ typedef struct
{
unsigned int contents;
unsigned int id; //networked/gamecode id.
unsigned int axialplanes; //+x,+y,+z,-x,-y,-z. used for bevel stuff.
unsigned int numplanes;
qboolean selected; //different shader stuff
vec4_t *planes;
@ -362,6 +363,7 @@ typedef struct heightmap_s
char *texmask; //for editing - visually masks off the areas which CANNOT accept this texture
qboolean entsdirty; //ents were edited, so we need to reload all lighting...
struct relight_ctx_s *relightcontext;
struct llightinfo_s *lightthreadmem;
qboolean inheritedlightthreadmem;
@ -3511,7 +3513,7 @@ typedef struct {
#endif
} hmtrace_t;
static int Heightmap_Trace_Brush(hmtrace_t *tr, vec4_t *planes, int numplanes)
static int Heightmap_Trace_Brush(hmtrace_t *tr, vec4_t *planes, int numplanes, brushes_t *brushinfo)
{
qboolean startout;
float *enterplane;
@ -3592,6 +3594,91 @@ static int Heightmap_Trace_Brush(hmtrace_t *tr, vec4_t *planes, int numplanes)
}
}
//non-point traces need to clip against the brush's edges
if (brushinfo && tr->shape != ispoint && brushinfo->axialplanes != 0x3f)
{
static vec3_t axis[] = {{1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1}};
for (i = 0; i < 6; i++)
{
// if (brushinfo->axialplanes & (1u<<i))
// continue; //should have already checked this plane.
if (i >= 3)
{
/*calculate the distance based upon the shape of the object we're tracing for*/
switch(tr->shape)
{
default:
case isbox:
dist = -tr->maxs[i-3];
dist = -brushinfo->mins[i-3] - dist;
break;
case iscapsule:
dist = -tr->up[i-3];
dist = dist*(tr->capsulesize[(dist<0)?1:2]) - tr->capsulesize[0];
dist = -brushinfo->mins[i-3] - dist;
break;
case ispoint:
dist = -brushinfo->mins[i-3];
break;
}
d1 = -tr->start[i-3] - dist;
d2 = -tr->end[i-3] - dist;
}
else
{
switch(tr->shape)
{
default:
case isbox:
dist = brushinfo->maxs[i] - tr->mins[i];
break;
case iscapsule:
dist = tr->up[i];
dist = dist*(tr->capsulesize[(dist<0)?1:2]) - tr->capsulesize[0];
dist = brushinfo->maxs[i] - dist;
break;
case ispoint:
dist = brushinfo->maxs[i];
break;
}
d1 = (tr->start[i]) - dist;
d2 = (tr->end[i]) - dist;
}
//if we're fully outside any plane, then we cannot possibly enter the brush, skip to the next one
if (d1 > 0 && d2 >= d1)
return false;
if (d1 > 0)
startout = true;
//if we're fully inside the plane, then whatever is happening is not relevent for this plane
if (d1 <= 0 && d2 <= 0)
continue;
f = (d1) / (d1-d2);
if (d1 > d2)
{
//entered the brush. favour the furthest fraction to avoid extended edges (yay for convex shapes)
if (enterfrac < f)
{
enterfrac = f;
nearfrac = (d1 - (0.03125)) / (d1-d2);
enterplane = axis[i];
enterdist = dist;
}
}
else
{
//left the brush, favour the nearest plane (smallest frac)
if (exitfrac > f)
{
exitfrac = f;
}
}
}
}
if (!startout)
{
@ -3752,7 +3839,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
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);
Heightmap_Trace_Brush(tr, n, 4, NULL);
}
return;
}
@ -3813,7 +3900,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
n[3][3] = DotProduct(n[3], s->ents[i]->ent.origin) + -model->mins[1];
n[4][3] = DotProduct(n[4], s->ents[i]->ent.origin) + model->maxs[2];
n[5][3] = DotProduct(n[5], s->ents[i]->ent.origin) + -model->mins[2];
Heightmap_Trace_Brush(tr, n, 6);
Heightmap_Trace_Brush(tr, n, 6, NULL);
}
else
{
@ -3858,7 +3945,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
//top
Vector4Set(n[4], 0, 0, 1, s->heights[(tx+0)+(ty+0)*SECTHEIGHTSIZE]);
Heightmap_Trace_Brush(tr, n, 5);
Heightmap_Trace_Brush(tr, n, 5, NULL);
return;
case HMM_TERRAIN:
VectorSet(p[0], tr->htilesize*(sx+0), tr->htilesize*(sy+0), s->heights[(tx+0)+(ty+0)*SECTHEIGHTSIZE]);
@ -3895,7 +3982,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
n[5][3] = max(p[0][2], p[2][2]);
n[5][3] = max(n[5][3], p[3][2]);
Heightmap_Trace_Brush(tr, n, 6);
Heightmap_Trace_Brush(tr, n, 6, NULL);
}
{
@ -3921,7 +4008,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
n[5][3] = max(p[0][2], p[1][2]);
n[5][3] = max(n[5][3], p[3][2]);
Heightmap_Trace_Brush(tr, n, 6);
Heightmap_Trace_Brush(tr, n, 6, NULL);
}
}
else
@ -3950,7 +4037,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
n[5][3] = max(p[0][2], p[1][2]);
n[5][3] = max(n[5][3], p[2][2]);
Heightmap_Trace_Brush(tr, n, 6);
Heightmap_Trace_Brush(tr, n, 6, NULL);
}
{
VectorSubtract(p[3], p[2], d[0]);
@ -3975,7 +4062,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
n[5][3] = max(p[1][2], p[2][2]);
n[5][3] = max(n[5][3], p[3][2]);
Heightmap_Trace_Brush(tr, n, 6);
Heightmap_Trace_Brush(tr, n, 6, NULL);
}
}
break;
@ -4168,7 +4255,7 @@ qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec
hmtrace.absmins[1] > brushes->maxs[1] ||
hmtrace.absmins[2] > brushes->maxs[2])
continue;
face = Heightmap_Trace_Brush(&hmtrace, brushes->planes, brushes->numplanes);
face = Heightmap_Trace_Brush(&hmtrace, brushes->planes, brushes->numplanes, brushes);
if (face)
{
trace->brush_id = brushes->id;
@ -4829,6 +4916,11 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
mod->entities[oldlen + newlen] = 0;
Z_Free(olds);
G_FLOAT(OFS_RETURN) = oldlen + newlen;
if (mod->terrain)
{
hm = mod->terrain;
hm->entsdirty = true;
}
}
return;
case ter_ents_get:
@ -5258,12 +5350,19 @@ static size_t Terr_GenerateBrushFace(vecV_t *points, size_t maxpoints, vec4_t *p
size_t numverts;
//generate some huge quad/poly aligned with the plane
vec3_t tmp = {0.1,0.04,0.96};
vec3_t tmp;
vec3_t right, forward;
double t;
// if (face[2] != 1)
// return 0;
t = fabs(face[2]);
if (t > fabs(face[0]) && t > fabs(face[1]))
VectorSet(tmp, 1, 0, 0);
else
VectorSet(tmp, 0, 0, 1);
CrossProduct(face, tmp, right);
VectorNormalize(right);
CrossProduct(face, right, forward);
@ -5318,11 +5417,13 @@ static size_t Terr_GenerateBrushFace(vecV_t *points, size_t maxpoints, vec4_t *p
{
for (a = 0; a < 3; a++)
{
//if its within 1/1000th of a qu, just call it okay.
if ((int)points[p][a] * 1000 == (int)(points[p][a]*1000))
points[p][a] = floor(cverts[p][a] + 0.5);
float f = cverts[p][a];
int rounded = floor(f + 0.5);
//if its within 1/1000th of a qu, just round it.
if (fabs(f - rounded) < 0.001)
points[p][a] = rounded;
else
points[p][a] = cverts[p][a];
points[p][a] = f;
}
}
@ -5362,6 +5463,21 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
//allocate lightmap space for all surfaces, and then rebuild all textures.
//if a surface is modified, clear its lightmap to -1 and when its batches are rebuilt, it'll unlight naturally.
if (hm->entsdirty)
{
model_t *mod = e->model;
if (mod->submodelof)
mod = mod->submodelof;
hm->entsdirty = false;
LightReloadEntities(hm->relightcontext, mod->entities, true);
//FIXME: figure out some way to hint this without having to relight the entire frigging world.
for (bt = hm->brushtextures; bt; bt = bt->next)
for (i = 0, br = hm->wbrushes; i < hm->numbrushes; i++, br++)
for (j = 0; j < br->numplanes; j++)
br->faces[j].relight = true;
}
if (hm->recalculatebrushlighting && !r_fullbright.ival)
{
unsigned int lmcount;
@ -5782,6 +5898,7 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t *
out = &hm->wbrushes[hm->numbrushes];
out->selected = false;
out->contents = brush->contents;
out->axialplanes = 0;
out->planes = BZ_Malloc((sizeof(*out->planes)+sizeof(*out->faces)) * brush->numplanes);
out->faces = (void*)(out->planes+brush->numplanes);
@ -5816,6 +5933,19 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t *
Vector4Copy(brush->faces[iface].stdir[0], out->faces[oface].stdir[0]);
Vector4Copy(brush->faces[iface].stdir[1], out->faces[oface].stdir[1]);
if (out->planes[oface][0] == 1)
out->axialplanes |= 1u<<0;
else if (out->planes[oface][1] == 1)
out->axialplanes |= 1u<<1;
else if (out->planes[oface][2] == 1)
out->axialplanes |= 1u<<2;
else if (out->planes[oface][0] == -1)
out->axialplanes |= 1u<<3;
else if (out->planes[oface][1] == -1)
out->axialplanes |= 1u<<4;
else if (out->planes[oface][2] == -1)
out->axialplanes |= 1u<<5;
//make sure this stuff is rebuilt properly.
out->faces[oface].tex->rebuild = true;
@ -6675,6 +6805,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
model_t *submod = NULL;
#ifdef RUNTIMELIGHTING
hm->entsdirty = true;
hm->relightcontext = LightStartup(NULL, mod, false);
hm->lightthreadmem = BZ_Malloc(lightthreadctxsize);
hm->inheritedlightthreadmem = false;
@ -6791,6 +6922,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
{
//parse a plane
//Quake: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname 0 -32 rotation sscale tscale
//hexen2: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname 0 -32 rotation sscale tscale utterlypointless
//Valve: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname [x y z d] [x y z d] rotation sscale tscale
//fte : ( px py pz pd ) texname [sx sy sz sd] [tx ty tz td] 0 1 1
brushtex_t *bt;
@ -6900,6 +7032,13 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
entities = COM_ParseOut(entities, token, sizeof(token));
scale[1] = atof(token);
//hexen2 has some extra junk that is useless - some 'light' value, but its never used and should normally be -1.
while (*entities == ' ' || *entities == '\t')
entities++;
if (*entities == '-' || (*entities >= '0' && *entities <= '9'))
entities = COM_ParseOut(entities, token, sizeof(token));
//okay, that's all the actual parsing, now try to make sense of this plane.
if (p == 4)
{ //parsed an actual plane
VectorCopy(points[0], planes[numplanes]);
@ -7073,7 +7212,10 @@ qboolean QDECL Terr_LoadTerrainModel (model_t *mod, void *buffer, size_t bufsize
#ifdef RUNTIMELIGHTING
if (hm->relightcontext)
LightReloadEntities(hm->relightcontext, mod->entities);
{
LightReloadEntities(hm->relightcontext, mod->entities, true);
hm->entsdirty = false;
}
#endif
return true;

View file

@ -3285,6 +3285,9 @@ static void Mod_Batches_Build(model_t *mod, builddata_t *bd)
if (!mod->textures)
return;
if (mod->firstmodelsurface + mod->nummodelsurfaces > mod->numsurfaces)
Sys_Error("submodel %s surface range is out of bounds\n", mod->name);
if (bd)
meshlist = NULL;
else
@ -4801,7 +4804,7 @@ TRACE(("LoadBrushModel %i\n", __LINE__));
if (lightmodel == mod)
{
lightcontext = LightStartup(NULL, lightmodel, true);
LightReloadEntities(lightcontext, lightmodel->entities);
LightReloadEntities(lightcontext, lightmodel->entities, false);
}
#endif
TRACE(("LoadBrushModel %i\n", __LINE__));

View file

@ -4580,6 +4580,10 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *fallbackname, cons
*imagename = 0;
}
//for water texture replacements
while((h = strchr(imagename, '*')))
*h = '#';
loadflags &= shader->flags;
//skins can use an alternative path in certain cases, to work around dodgy models.

View file

@ -46,6 +46,62 @@ static void *GLVID_getsdlglfunction(char *functionname)
#endif
}
#if SDL_MAJOR_VERSION >= 2
void *GLVID_CreateCursor (char *filename, float hotx, float hoty, float scale)
{
int width;
int height;
SDL_Cursor *curs;
SDL_Surface *surf;
qbyte *rgbadata_start;
qboolean hasalpha;
void *filedata;
int filelen;
if (!filename || !*filename)
return NULL;
filelen = FS_LoadFile(filename, &filedata);
if (!filedata)
return NULL;
rgbadata_start = Read32BitImageFile(filedata, filelen, &width, &height, &hasalpha, "cursor");
FS_FreeFile(filedata);
if (!rgbadata_start)
return NULL;
if (scale != 1)
{
int nw,nh;
qbyte *nd;
nw = width * scale;
nh = height * scale;
if (nw <= 0 || nh <= 0 || nw > 128 || nh > 128) //don't go crazy.
return NULL;
nd = BZ_Malloc(nw*nh*4);
Image_ResampleTexture((unsigned int*)rgbadata_start, width, height, (unsigned int*)nd, nw, nh);
width = nw;
height = nh;
BZ_Free(rgbadata_start);
rgbadata_start = nd;
}
surf = SDL_CreateRGBSurfaceFrom(rgbadata_start, width, height, 32, width*4, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
curs = SDL_CreateColorCursor(surf, hotx, hoty);
SDL_FreeSurface(surf);
BZ_Free(rgbadata_start);
return curs;
}
qboolean GLVID_SetCursor (void *cursor)
{
SDL_SetCursor(cursor);
return !!cursor;
}
void GLVID_DestroyCursor (void *cursor)
{
SDL_FreeCursor(cursor);
}
#endif
qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
{
int flags = 0;
@ -133,6 +189,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
Con_Printf("Couldn't set video mode: %s\n", SDL_GetError());
return false;
}
CL_UpdateWindowTitle();
#if SDL_PATCHLEVEL >= 1
SDL_GL_GetDrawableSize(sdlwindow, &vid.pixelwidth, &vid.pixelheight); //get the proper physical size.
#else
@ -207,6 +264,12 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
}
#endif
#if SDL_MAJOR_VERSION >= 2
rf->VID_CreateCursor = GLVID_CreateCursor;
rf->VID_DestroyCursor = GLVID_DestroyCursor;
rf->VID_SetCursor = GLVID_SetCursor;
#endif
return true;
}

View file

@ -144,7 +144,7 @@ struct relight_ctx_s *LightStartup(struct relight_ctx_s *ctx, model_t *model, qb
ctx->models[ctx->nummodels++] = model;
return ctx;
}
void LightReloadEntities(struct relight_ctx_s *ctx, char *entstring)
void LightReloadEntities(struct relight_ctx_s *ctx, char *entstring, qboolean ignorestyles)
{
#define DEFAULTLIGHTLEVEL 300
mentity_t *mapent;
@ -254,6 +254,8 @@ void LightReloadEntities(struct relight_ctx_s *ctx, char *entstring)
mapent->style = switchedstyle++;
}
if (ignorestyles)
mapent->style = 0;
ctx->num_entities++;
}
@ -771,7 +773,7 @@ void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *l, qbyte surf_s
if (!surf_rgbsamples)
return;
memset (l, 0, sizeof(*l));
// memset (l, 0, sizeof(*l));
l->ctx = ctx;
//
@ -796,7 +798,11 @@ void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *l, qbyte surf_s
i = 0;
#ifndef UTILITY
for (; surf_styles[i] != 255 && i < 4; i++)
{
l->lightstyles[i] = surf_styles[i];
memset(&l->lightmaps[i], 0, sizeof(l->lightmaps[i][0])*l->numsurfpt);
memset(&l->lightnorm[i], 0, sizeof(l->lightnorm[i][0])*l->numsurfpt);
}
#endif
l->numlightstyles = i;
for ( ; i<MAXQ1LIGHTMAPS ; i++)

View file

@ -172,10 +172,10 @@ reeval:
OPC->_int = (int)(OPA->_int >= OPB->_int);
break;
case OP_GE_IF:
OPC->_float = (float)(OPA->_int >= OPB->_float);
OPC->_int = (float)(OPA->_int >= OPB->_float);
break;
case OP_GE_FI:
OPC->_float = (float)(OPA->_float >= OPB->_int);
OPC->_int = (float)(OPA->_float >= OPB->_int);
break;
case OP_LE_F:
@ -185,10 +185,10 @@ reeval:
OPC->_int = (int)(OPA->_int <= OPB->_int);
break;
case OP_LE_IF:
OPC->_float = (float)(OPA->_int <= OPB->_float);
OPC->_int = (float)(OPA->_int <= OPB->_float);
break;
case OP_LE_FI:
OPC->_float = (float)(OPA->_float <= OPB->_int);
OPC->_int = (float)(OPA->_float <= OPB->_int);
break;
case OP_GT_F:
@ -198,10 +198,10 @@ reeval:
OPC->_int = (int)(OPA->_int > OPB->_int);
break;
case OP_GT_IF:
OPC->_float = (float)(OPA->_int > OPB->_float);
OPC->_int = (float)(OPA->_int > OPB->_float);
break;
case OP_GT_FI:
OPC->_float = (float)(OPA->_float > OPB->_int);
OPC->_int = (float)(OPA->_float > OPB->_int);
break;
case OP_LT_F:
@ -211,10 +211,10 @@ reeval:
OPC->_int = (int)(OPA->_int < OPB->_int);
break;
case OP_LT_IF:
OPC->_float = (float)(OPA->_int < OPB->_float);
OPC->_int = (float)(OPA->_int < OPB->_float);
break;
case OP_LT_FI:
OPC->_float = (float)(OPA->_float < OPB->_int);
OPC->_int = (float)(OPA->_float < OPB->_int);
break;
case OP_AND_F:
@ -244,7 +244,7 @@ reeval:
OPC->_float = (float)(OPA->_float == OPB->_float);
break;
case OP_EQ_IF:
OPC->_float = (float)(OPA->_int == OPB->_float);
OPC->_int = (float)(OPA->_int == OPB->_float);
break;
case OP_EQ_FI:
OPC->_float = (float)(OPA->_float == OPB->_int);

View file

@ -900,7 +900,7 @@ void QCC_PR_NewLine (pbool incomment);
#define GDF_STATIC 2
#define GDF_CONST 4
#define GDF_STRIP 8 //always stripped, regardless of optimisations. used for class member fields
#define GDF_SILENT 16 //used by the gui, to suppress ALL warnings.
#define GDF_SILENT 16 //used by the gui, to suppress ALL warnings associated with querying the def.
#define GDF_INLINE 32 //attempt to inline calls to this function
#define GDF_USED 64 //don't strip this, ever.
QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, struct QCC_function_s *scope, pbool allocate, int arraysize, unsigned int flags);

View file

@ -173,6 +173,7 @@ QCC_sref_t QCC_PR_GenerateFunctionCall (QCC_sref_t newself, QCC_sref_t func, QCC
void QCC_Marshal_Locals(int firststatement, int laststatement);
QCC_sref_t QCC_PR_ParseArrayPointer (QCC_sref_t d, pbool allowarrayassign, pbool makestructpointers);
QCC_sref_t QCC_LoadFromArray(QCC_sref_t base, QCC_sref_t index, QCC_type_t *t, pbool preserve);
void QCC_PR_ParseInitializerDef(QCC_def_t *def);
QCC_ref_t *QCC_DefToRef(QCC_ref_t *ref, QCC_sref_t def); //ref is a buffer to write into, to avoid excessive allocs
QCC_sref_t QCC_RefToDef(QCC_ref_t *ref, pbool freetemps);
@ -8905,6 +8906,8 @@ void QCC_PR_ParseStatement (void)
{
int old_numstatements;
int numtemp, i;
QCC_def_t *subscopestop;
QCC_def_t *subscopestart = pr.local_tail;
QCC_statement_t temp[256];
@ -8914,9 +8917,23 @@ void QCC_PR_ParseStatement (void)
QCC_PR_Expect("(");
if (!QCC_PR_CheckToken(";"))
{
QCC_PR_DiscardExpression(TOP_PRIORITY, 0);
do
{
QCC_type_t *type = QCC_PR_ParseType (false, true);
if (type)
{
d = QCC_PR_GetDef (type, QCC_PR_ParseName(), pr_scope, true, 0, 0);
QCC_PR_Expect("=");
QCC_PR_ParseInitializerDef(d);
QCC_FreeDef(d);
QCC_FreeDef(d);
}
else
QCC_PR_DiscardExpression(TOP_PRIORITY, EXPR_DISALLOW_COMMA);
} while(QCC_PR_CheckToken(","));
QCC_PR_Expect(";");
}
subscopestop = pr_subscopedlocals?NULL:pr.local_tail->nextlocal;
QCC_ClobberDef(NULL);
@ -8991,6 +9008,18 @@ void QCC_PR_ParseStatement (void)
num_continues = continues;
}
//remove any new locals from the hashtable.
//typically this is just the stuff inside the for(here;;)
for (d = subscopestart->nextlocal; d != subscopestop; d = d->nextlocal)
{
if (!d->subscoped_away)
{
pHash_RemoveData(&localstable, d->name, d);
d->subscoped_away = true;
}
}
return;
}
if (QCC_PR_CheckKeyword(keyword_do, "do"))

View file

@ -163,6 +163,9 @@ typedef struct
int numidx;
vector *p;
int *i;
int selectedvert1;
int selectedvert2;
} vertsoup_t;
vertsoup_t vertedit;
brushface_t tmp_faces[64];
@ -184,6 +187,7 @@ enum int
BT_MERGE,
BT_PUSHFACE,
BT_CREATE,
BT_CREATEDRAG,
BT_CLONEDISPLACE,
BT_SLICE,
BT_MOVETEXTURE,
@ -229,7 +233,7 @@ void(brushface_t *fa) reset_texturecoords =
static int(brushface_t *fa, int famax, vector *points, int numpoints, float height) BrushFromPoints =
{
int count = 0, p;
int count = 0;
fa->planenormal = normalize(cross(points[2] - points[0], points[1] - points[0]));
fa->planedist = bt_point[0] * fa->planenormal + height;
@ -244,7 +248,7 @@ static int(brushface_t *fa, int famax, vector *points, int numpoints, float heig
fa++;
count = 2;
for (p = 0; p < numpoints; p++)
for (int p = 0; p < numpoints; p++)
{
int n = p + 1;
if (n == numpoints)
@ -256,7 +260,7 @@ static int(brushface_t *fa, int famax, vector *points, int numpoints, float heig
fa++;
count++;
}
return count;
}
@ -265,7 +269,7 @@ vector(vector guess) brush_snappoint =
{
if (nogrid)
return guess;
int facenum, points, point;
int facenum, points;
float bestdist = autocvar_ca_grid*autocvar_ca_grid; //worst case value so we don't snap to grid when there's a vertex 0.001qu away from the grid.
vector best = guess * (1.0/autocvar_ca_grid);
best_x = rint(best_x); //snap to grid
@ -276,9 +280,9 @@ vector(vector guess) brush_snappoint =
//find surfaces within 32qu of the point (via plane volume). use a tetrahedron instead if you want something more circular
for (facenum = 0; facenum < axis.length; facenum++)
dists[facenum] = (guess * axis[facenum]) + autocvar_ca_grid;
int brushnum, numbrushes = brush_findinvolume(selectedbrushmodel, axis, dists, 6, brushlist, __NULL__, brushlist.length);
int numbrushes = brush_findinvolume(selectedbrushmodel, axis, dists, 6, brushlist, __NULL__, brushlist.length);
for (brushnum = 0; brushnum < numbrushes; brushnum++)
for (int brushnum = 0; brushnum < numbrushes; brushnum++)
{
for (facenum = 0; ; )
{
@ -287,7 +291,7 @@ vector(vector guess) brush_snappoint =
break; //end of face list, I guess
//walk the faces we found and use the point if its nearer than our previous guess.
for (point = 0; point < points; point++)
for (int point = 0; point < points; point++)
{
vector disp = facepoints[point] - guess;
float dist = disp*disp;
@ -341,8 +345,7 @@ static void brushface_translate(brushface_t *fa, int numfaces, vector displaceme
//translate before+after first in order to deal with pivots.
static void brushface_rotate(brushface_t *fa, int numfaces)
{
int i;
for (i = 0; i < numfaces; i++, fa++)
for (int i = 0; i < numfaces; i++, fa++)
{
vector orig = fa->planenormal;
fa->planenormal[0] = orig * v_forward;
@ -412,14 +415,13 @@ vector(vector p1, vector p2, vector norm, float dist) planelinepoint =
int(brushface_t *faces, int numfaces, vector *points, int numpoints) isconcave =
{
int result = 0;
int f, p;
//if any of the points are outside the brush, then we know that one of the planes cut straight through in a concavey kind of way
for(f = 0; f < numfaces; f++)
for(int f = 0; f < numfaces; f++)
{
vector n = faces[f].planenormal;
float d = faces[f].planedist + EPSILON; //epsilon to cover precision issues
for (p = 0; p < numpoints; p++)
for (int p = 0; p < numpoints; p++)
{
if (points[p] * n > d)
{
@ -598,6 +600,7 @@ void(brushface_t *faces, int numfaces, vector col, float alpha) DrawQCBrushTextu
{
//this is unfortunate. the built in shaders expect to use lightmaps. we don't have those.
//because lightmaps are special things, we end up in a real mess. so lets just make sure there's a shader now, because we can.
//FIXME: we don't manage to pick up the size of the original wad image
shaderforname(faces[f].shadername,
sprintf("{"
"{\n"
@ -616,65 +619,130 @@ void(brushface_t *faces, int numfaces, vector col, float alpha) DrawQCBrushTextu
}
};
#if 0
void(vertsoup_t *soup, brushface_t **trifaces, brushface_t **splits, int internalsplits, int drawit) Rebrushify_r =
void(vector *p, int points, string shader, vector col, float alpha) DrawAxisExtensions =
{
//clip the soup by the internal splits.
//if any triangle is outside, remove that plane from the sub-brush
//add the splits to the volume. call it done.
brushface_t faces[64];
int numfaces;
int point;
for(point = 0; point+2 < vertedit.numidx; point+=3)
R_BeginPolygon(shader);
for (int point = 0; point < points; point++)
{
vector v1 = vertedit.p[vertedit.i[point+0]];
vector v2 = vertedit.p[vertedit.i[point+1]];
vector v3 = vertedit.p[vertedit.i[point+2]];
if ( v1 * s->planenormal < s->planedist &&
v2 * s->planenormal < s->planedist &&
v3 * s->planenormal < s->planedist)
continue;
}
if (drawit)
{
//draw it wireframe without depth testing
DrawQCBrushWireframe(faces, numfaces, "chop", '1 0 0');
R_PolygonVertex(p[point] + [ 64, 0, 0], '0 0', col, alpha);
R_PolygonVertex(p[point] + [-64, 0, 0], '0 0', col, alpha);
R_EndPolygon();
R_PolygonVertex(p[point] + [0, 64, 0], '0 0', col, alpha);
R_PolygonVertex(p[point] + [0, -64, 0], '0 0', col, alpha);
R_EndPolygon();
R_PolygonVertex(p[point] + [0, 0, 64], '0 0', col, alpha);
R_PolygonVertex(p[point] + [0, 0, -64], '0 0', col, alpha);
R_EndPolygon();
}
};
#endif
static float(vertsoup_t *soup, int *idx, __inout vector norm, __inout float dist) planenormal =
{
vector v1 = soup->p[idx[0]];
vector v2 = soup->p[idx[1]];
vector v3 = soup->p[idx[2]];
vector d1 = v3 - v1;
vector d2 = v2 - v1;
vector d3 = v3 - v2;
norm = normalize(cross(d1, d2));
dist = norm * v1;
if (!d1 || !d2 || !d3 || !norm)
return FALSE;
return TRUE;
};
void(vertsoup_t *soup, int drawit) Rebrushify =
{
brushface_t *internalsplit[64];
brushface_t faces[64];
brushface_t *trifaces[128];
int numfaces, f, point;
string shader = 0;
vector n;
float d;
tmp_numfaces = brush_get(selectedbrushmodel, selectedbrush, tmp_faces, tmp_faces.length, &tmp_contents);
//if any triangle's neighbour opposes it, reform the edge across the quad to try to keep it convex.
for(point = 0; point+2 < soup->numidx; point+=3)
{
int p1 = soup->i[point+0];
int p2 = soup->i[point+1];
int p3 = soup->i[point+2];
if (!planenormal(soup, &soup->i[point], n, d))
continue; //degenerate
d += EPSILON;
for(f = point+3; f+2 < soup->numidx; f+=3)
{
int o1 = soup->i[f+0];
int o2 = soup->i[f+1];
int o3 = soup->i[f+2];
int o;
p1p2edge:
if (o2 == p1 && o1 == p2)
o = o3;
else if (o3 == p1 && o2 == p2)
o = o1;
else if (o1 == p1 && o3 == p2)
o = o2;
else
goto p2p3edge;
if (soup->p[o] * n > d)
{
soup->i[f+0] = p3;
soup->i[f+1] = o;
soup->i[f+2] = p2;
p2 = o;
}
continue;
p2p3edge:
if (o2 == p2 && o1 == p3)
o = o3;
else if (o3 == p2 && o2 == p3)
o = o1;
else if (o1 == p2 && o3 == p3)
o = o2;
else
goto p3p1edge;
if (soup->p[o] * n > d)
{
soup->i[f+0] = p1;
soup->i[f+1] = o;
soup->i[f+2] = p3;
p3 = o;
}
continue;
p3p1edge:
if (o2 == p3 && o1 == p1)
o = o3;
else if (o3 == p3 && o2 == p1)
o = o1;
else if (o1 == p3 && o3 == p1)
o = o2;
else
continue;
if (soup->p[o] * n > d)
{
soup->i[f+0] = p2;
soup->i[f+1] = o;
soup->i[f+2] = p1;
p1 = o;
}
continue;
}
soup->i[point+0] = p1;
soup->i[point+1] = p2;
soup->i[point+2] = p3;
}
//generate the plane info
numfaces = 0;
for(point = 0; point+2 < vertedit.numidx; point+=3)
for(point = 0; point+2 < soup->numidx; point+=3)
{
vector v1 = vertedit.p[vertedit.i[point+0]];
vector v2 = vertedit.p[vertedit.i[point+1]];
vector v3 = vertedit.p[vertedit.i[point+2]];
vector d1 = v3 - v1;
vector d2 = v2 - v1;
vector d3 = v3 - v2;
vector n = normalize(cross(d1, d2));
float d = n * v1;
if (!d1 || !d2 || !d3 || !n)
{
trifaces[point/3] = 0;
if (!planenormal(soup, &soup->i[point], n, d))
continue; //a degenerate triangle is one that probably got merged or something
}
for (f = 0; f < numfaces; f++)
{
@ -682,10 +750,7 @@ void(vertsoup_t *soup, int drawit) Rebrushify =
break;
}
if (f < numfaces)
{
trifaces[point/3] = &faces[f];
continue; //duplicate plane
}
for (f = 0; f < tmp_numfaces; f++)
{
@ -702,7 +767,6 @@ void(vertsoup_t *soup, int drawit) Rebrushify =
faces[numfaces].sbias = tmp_faces[f].sbias;
faces[numfaces].tdir = tmp_faces[f].tdir;
faces[numfaces].tbias = tmp_faces[f].tbias;
trifaces[point/3] = &faces[numfaces];
numfaces++;
break;
}
@ -720,7 +784,6 @@ void(vertsoup_t *soup, int drawit) Rebrushify =
faces[numfaces].planenormal = n;
faces[numfaces].planedist = d;
reset_texturecoords(&faces[numfaces]);
trifaces[point/3] = &faces[numfaces];
numfaces++;
}
@ -740,20 +803,20 @@ void(vertsoup_t *soup, int drawit) Rebrushify =
{
n = faces[f].planenormal;
d = faces[f].planedist;
for (point = 0; point < vertedit.numidx; point++) //would ideally use points, but I want to cover dead ones
for (point = 0; point < soup->numidx; point++) //would ideally use points, but I want to cover dead ones
{
if (vertedit.p[vertedit.i[point]] * n > d + EPSILON)
if (soup->p[soup->i[point]] * n > d + EPSILON)
{
internalsplit[internals++] = &faces[f];
internals++;
break;
}
}
}
cprint(sprintf("%i internal splits, %i faces\n", internals, numfaces));
// Rebrushify_r(soup, trifaces, internalsplit, internals, drawit);
if (numfaces <= 3)
return; //can't possibly be valid.
if (drawit)
{
//draw it wireframe WITH depth testing
@ -763,7 +826,7 @@ void(vertsoup_t *soup, int drawit) Rebrushify =
DrawQCBrushTextured(faces, numfaces, '0.7 0.7 0.7', 1);
//draw it wireframe without depth testing
DrawQCBrushWireframe(faces, numfaces, "chop", '0 0 1', 1);
DrawQCBrushWireframe(faces, numfaces, "chop", internals?'1 0 0':'0 0 1', 1);
}
else
{
@ -772,8 +835,8 @@ void(vertsoup_t *soup, int drawit) Rebrushify =
selectedbrush = brush_history_create(selectedbrushmodel, faces, numfaces, 1i);
selectedbrushface = 0;
vertedit.numidx = 0;
vertedit.numverts = 0;
soup->numidx = 0;
soup->numverts = 0;
}
};
@ -787,6 +850,8 @@ void(void) Debrushify =
vector p;
vector *np;
static int fi[64];
vertedit.numidx = 0;
vertedit.numverts = 0;
for (i = 0; ; )
{
points = brush_getfacepoints(selectedbrushmodel, selectedbrush, ++i, facepoints, facepoints.length);
@ -834,6 +899,48 @@ void(void) Debrushify =
}
};
//determines only the various points of the brush, without duplicates. doesn't care about indexes.
void(brushface_t *faces, int numfaces) DebrushifyLite =
{
int points, k;
vector p;
vector *np;
int fi[64];
vertedit.numidx = 0;
vertedit.numverts = 0;
for (int i = 0; ; )
{
points = brush_calcfacepoints(++i, faces, numfaces, facepoints, facepoints.length);
if (!points)
break;
for (int j = 0; j < points; j++)
{
p = facepoints[j];
p_x = floor(p_x + 0.5); //gah, bloomin inprecision.
p_y = floor(p_y + 0.5);
p_z = floor(p_z + 0.5);
for (k = 0; k < vertedit.numverts; k++)
{ //try to be nice and re-use verts.
if (vertedit.p[k] == p)
break;
}
if (k == vertedit.numverts)
{
//if it wasn't found, we need to allocate a new one
np = memalloc(sizeof(*np) * (vertedit.numverts+1));
memcpy(np, vertedit.p, sizeof(*np) * vertedit.numverts);
memfree(vertedit.p);
vertedit.p = np;
np += vertedit.numverts;
vertedit.numverts += 1;
*np = p;
}
fi[j] = k;
}
}
};
void(vector mousepos) editor_brushes_add =
{
vector col = '0 0 0';
@ -841,8 +948,10 @@ void(vector mousepos) editor_brushes_add =
int facenum;
float intensity = (sin(gettime(5)*4)+1)*0.05;
vector displace, tmp;
float bestdist, dist;
vector mid;
if ((brushtool == BT_PUSHFACE || brushtool == BT_CLONEDISPLACE || brushtool == BT_MOVE || brushtool == BT_MOVETEXTURE) && bt_points)
if ((mousetool == BT_VERTEXEDIT || mousetool == BT_CREATEDRAG || brushtool == BT_PUSHFACE || brushtool == BT_CLONEDISPLACE || brushtool == BT_MOVE || brushtool == BT_MOVETEXTURE) && bt_points)
{
makevectors(input_angles);
vector dir = v_forward;
@ -851,7 +960,8 @@ void(vector mousepos) editor_brushes_add =
tmp = normalize(mousefar-mousenear) + mousenear;
tmp = planelinepoint(mousenear, tmp, dir, bt_point[0] * dir); //find where the cursor impacts the screen grid (moved along the view vector to match where the drag was last frame)
displace = tmp - bt_point[0];
displace = brush_snappoint(displace);
if (mousetool != BT_VERTEXEDIT && mousetool != BT_CREATEDRAG)
displace = brush_snappoint(displace);
if (altdown) //if alt is held, rotate the move by 90 degrees, and move ONLY in the axial dir instead of the screen's xy plane
bt_displace_z = (displace * v_right + displace * v_up);
else
@ -860,6 +970,9 @@ void(vector mousepos) editor_brushes_add =
bt_displace_y = displace * axialize(v_up);
}
displace = bt_displace_x * axialize(v_right) + bt_displace_y * axialize(v_up) - bt_displace_z * axialize(v_forward);
if (mousetool == BT_VERTEXEDIT)
displace = brush_snappoint(displace+bt_point[0]);
}
else if (brushtool == BT_ROTATE)
{
@ -898,7 +1011,7 @@ void(vector mousepos) editor_brushes_add =
"nodepthtest\n"
"}\n"
"}");
if (mousetool == BT_VERTEXEDIT && vertedit.numidx)
{
#if 0
@ -913,6 +1026,7 @@ void(vector mousepos) editor_brushes_add =
R_EndPolygon();
}
#endif
#if 1
//draw the wires (no depth)
R_BeginPolygon("chop");
for(point = 0; point+2 < vertedit.numidx; point+=3)
@ -928,6 +1042,21 @@ void(vector mousepos) editor_brushes_add =
R_PolygonVertex(vertedit.p[vertedit.i[point+0]], '0 0', col, 1);
R_EndPolygon();
}
#endif
DrawAxisExtensions(vertedit.p, vertedit.numverts, "terrainedit", '1 0.3 0.3', 1);
if (mousedown)
{
if (bt_points == 1 && vertedit.selectedvert1 != -1)
{
if (vertedit.selectedvert2 != -1)
vertedit.p[vertedit.selectedvert2] = displace + bt_point[2];
vertedit.p[vertedit.selectedvert1] = displace + bt_point[1];
}
}
else
bt_points = 0;
Rebrushify(&vertedit, TRUE);
}
@ -940,6 +1069,56 @@ void(vector mousepos) editor_brushes_add =
DrawQCBrushWireframe(tmp_faces, tmp_numfaces, "chop", '1 0 0', 1);
}
}
else if (mousetool == BT_CREATEDRAG)
{
if (bt_points)
{
displace -= axialize(v_forward)*autocvar_ca_grid;
mid = bt_point[0];
displace = brush_snappoint(mid + displace);
mid = brush_snappoint(mid);
displace = displace - mid;
tmp_faces[0].planenormal = '1 0 0';
tmp_faces[1].planenormal = '-1 0 0';
tmp_faces[2].planenormal = '0 1 0';
tmp_faces[3].planenormal = '0 -1 0';
tmp_faces[4].planenormal = '0 0 1';
tmp_faces[5].planenormal = '0 0 -1';
tmp_faces[0].planedist = mid[0];
tmp_faces[1].planedist = -mid[0];
tmp_faces[2].planedist = mid[1];
tmp_faces[3].planedist = -mid[1];
tmp_faces[4].planedist = mid[2];
tmp_faces[5].planedist = -mid[2];
tmp_numfaces = 6;
tmp_contents = 1;
tmp_faces[0 + (displace_x<0.0)].planedist += fabs(displace_x);
tmp_faces[2 + (displace_y<0.0)].planedist += fabs(displace_y);
tmp_faces[4 + (displace_z<0.0)].planedist += fabs(displace_z);
for (facenum = 0; facenum < tmp_numfaces; facenum++)
{
tmp_faces[facenum].shadername = autocvar_ca_newbrushtexture;
reset_texturecoords(&tmp_faces[facenum]);
}
DrawQCBrushWireframe(tmp_faces, tmp_numfaces, "chop", '1 0 0', 1);
if (!mousedown)
{
brush_selected(selectedbrushmodel, selectedbrush, -1, FALSE);
selectedbrush = brush_history_create(selectedbrushmodel, tmp_faces, tmp_numfaces, tmp_contents);
brush_selected(selectedbrushmodel, selectedbrush, selectedbrushface, TRUE);
bt_points = 0;
mousetool = BT_NONE;
}
}
else
mousedown = FALSE;
}
else if ((mousetool == BT_PUSHFACE || mousetool == BT_MOVETEXTURE || mousetool == BT_MOVE || mousetool == BT_CLONEDISPLACE || mousetool == BT_ROTATE) && bt_points)
{
tmp_numfaces = brush_get(selectedbrushmodel, selectedbrush, tmp_faces, tmp_faces.length, &tmp_contents);
@ -1022,6 +1201,9 @@ void(vector mousepos) editor_brushes_add =
//draw it wireframe WITH depth testing
DrawQCBrushWireframe(tmp_faces, tmp_numfaces, "terrainedit", '0 0 1', 1);
DebrushifyLite(tmp_faces, tmp_numfaces);
DrawAxisExtensions(vertedit.p, vertedit.numverts, "terrainedit", '0 0 0.3', 1);
if (!mousedown)
{
brush_selected(selectedbrushmodel, selectedbrush, -1, FALSE);
@ -1053,13 +1235,10 @@ void(vector mousepos) editor_brushes_add =
//draw the other side wireframe
DrawQCBrushWireframe(tmp_faces, tmp_numfaces+1, "chop", '0 1 0', 1);
}
else
else if (selectedbrush)
{
if (brushtool == BT_PUSHFACE)
{ //selected face (not brush) follows cursor when we're not actively dragging a face
float bestdist = 0, dist;
vector mid;
for(facenum = 0;;)
{
points = brush_getfacepoints(selectedbrushmodel, selectedbrush, ++facenum, facepoints, facepoints.length);
@ -1115,6 +1294,10 @@ void(vector mousepos) editor_brushes_add =
R_PolygonVertex(facepoints[0], '0 0', col, 1);
R_EndPolygon();
}
tmp_numfaces = brush_get(selectedbrushmodel, selectedbrush, tmp_faces, tmp_faces.length, &tmp_contents);
DebrushifyLite(tmp_faces, tmp_numfaces);
DrawAxisExtensions(vertedit.p, vertedit.numverts, "terrainedit", '0 0 0.3', 1);
}
// editor_drawbbox(selectedbrush);
@ -1179,11 +1362,78 @@ void(vector mousepos) editor_brushes_add =
void(vector mousepos) editor_brushes_overlay =
{
int point;
vector mid;
float dist, bestdist;
if (vertedit.numidx)
{
if (!mousedown)
{
for(vertedit.selectedvert1 = -1, vertedit.selectedvert2 = -1, point = 0, bestdist = 16*16; point < vertedit.numverts; point++)
{
mid = project(vertedit.p[point]);
dist = (mousepos_x - mid_x) * (mousepos_x - mid_x) + (mousepos_y - mid_y) * (mousepos_y - mid_y);
if (dist < bestdist && mid_z > 0)
{
bestdist = dist;
vertedit.selectedvert1 = point;
}
}
for(point = 0; point < vertedit.numidx; point+=3)
{
mid = project(0.5*(vertedit.p[vertedit.i[point+0]] + vertedit.p[vertedit.i[point+1]]));
dist = (mousepos_x - mid_x) * (mousepos_x - mid_x) + (mousepos_y - mid_y) * (mousepos_y - mid_y);
if (dist < bestdist && mid_z > 0)
{
bestdist = dist;
vertedit.selectedvert1 = vertedit.i[point+0];
vertedit.selectedvert2 = vertedit.i[point+1];
}
mid = project(0.5*(vertedit.p[vertedit.i[point+1]] + vertedit.p[vertedit.i[point+2]]));
dist = (mousepos_x - mid_x) * (mousepos_x - mid_x) + (mousepos_y - mid_y) * (mousepos_y - mid_y);
if (dist < bestdist && mid_z > 0)
{
bestdist = dist;
vertedit.selectedvert1 = vertedit.i[point+1];
vertedit.selectedvert2 = vertedit.i[point+2];
}
mid = project(0.5*(vertedit.p[vertedit.i[point+2]] + vertedit.p[vertedit.i[point+0]]));
dist = (mousepos_x - mid_x) * (mousepos_x - mid_x) + (mousepos_y - mid_y) * (mousepos_y - mid_y);
if (dist < bestdist && mid_z > 0)
{
bestdist = dist;
vertedit.selectedvert1 = vertedit.i[point+2];
vertedit.selectedvert2 = vertedit.i[point+0];
}
}
}
if (vertedit.selectedvert1 != -1)
{
mid = project(vertedit.p[vertedit.selectedvert1]);
if (mid_z >= 0)
drawfill([mid_x,mid_y] - '2 2', [4,4], [0.2,0.2,1], 1, 0);
}
if (vertedit.selectedvert2 != -1)
{
mid = project(vertedit.p[vertedit.selectedvert2]);
if (mid_z >= 0)
drawfill([mid_x,mid_y] - '2 2', [4,4], [0.2,0.2,1], 1, 0);
}
drawrawstring('0 32 0', "Vertex Editor", '8 8 0', '1 1 1', 1);
return;
}
switch(brushtool)
{
case BT_CLONEDISPLACE:
drawrawstring('0 32 0', "Clone", '8 8 0', '1 1 1', 1);
break;
case BT_CREATEDRAG:
drawrawstring('0 32 0', "Drag+Create", '8 8 0', '1 1 1', 1);
break;
case BT_CREATE:
drawrawstring('0 32 0', "Paint+Create", '8 8 0', '1 1 1', 1);
break;
@ -1204,12 +1454,16 @@ void(vector mousepos) editor_brushes_overlay =
case BT_MOVETEXTURE:
drawrawstring('0 32 0', "Move Texture", '8 8 0', '1 1 1', 1);
break;
case BT_VERTEXEDIT:
drawrawstring('0 32 0', "Vertex Editor", '8 8 0', '1 1 1', 1);
break;
}
};
#define brusheditormodes
//#append brusheditormodes brusheditormode("move", BT_MOVE)
#append brusheditormodes brusheditormode("clone", BT_CLONEDISPLACE)
#append brusheditormodes brusheditormode("draw", BT_CREATEDRAG)
#append brusheditormodes brusheditormode("rotate", BT_ROTATE)
#append brusheditormodes brusheditormode("pushface", BT_PUSHFACE)
#append brusheditormodes brusheditormode("scrolltex", BT_MOVETEXTURE)
@ -1306,7 +1560,7 @@ brusheditormodes
localcmd("menubind 0 40 \"brushedit_redo\" \"Redo\"\n");
localcmd("menubind 0 48 \"brushedit_nogrid\" \"Disable Grid\"\n");
float foo = 48;
float foo = 56;
#define brusheditormode(n,v) localcmd(sprintf("menubind 0 %g \"+brushedit_"n"\" \""n"\"\n", foo)); foo+=8;
brusheditormodes
#undef brusheditormode
@ -1337,6 +1591,8 @@ float(float key, float unic, vector mousepos) editor_brushes_key =
t = o + normalize(t)*8192;
if (key == K_ESCAPE)
{
vertedit.numidx = 0;
vertedit.numverts = 0;
if (brushtool)
brushtool = BT_NONE;
else
@ -1349,16 +1605,37 @@ float(float key, float unic, vector mousepos) editor_brushes_key =
}
if (key == K_MOUSE1)
{
if (vertedit.numidx)
{
if (vertedit.selectedvert1 != -1)
{
mousedown = TRUE;
mousetool = BT_VERTEXEDIT;
if (vertedit.selectedvert2 != -1)
{
bt_point[0] = 0.5 * (vertedit.p[vertedit.selectedvert1] + vertedit.p[vertedit.selectedvert2]);
bt_point[1] = vertedit.p[vertedit.selectedvert1] - bt_point[0];
bt_point[2] = vertedit.p[vertedit.selectedvert2] - bt_point[0];
}
else
bt_point[0] = vertedit.p[vertedit.selectedvert1];
bt_point[1] = vertedit.p[vertedit.selectedvert1] - bt_point[0];
bt_points = 1;
bt_displace = '0 0 0';
}
return TRUE;
}
traceline(o, t, TRUE, world);
float tracemodel = trace_ent.modelindex;
if (brushtool == BT_PUSHFACE && selectedbrushface)
if (brushtool == BT_CREATEDRAG || (brushtool == BT_PUSHFACE && selectedbrushface))
{
trace_brush_faceid = selectedbrushface;
trace_brush_id = selectedbrush;
tracemodel = selectedbrushmodel;
}
if (brushtool != BT_PUSHFACE && brushtool != BT_MOVETEXTURE)
else if (brushtool != BT_PUSHFACE && brushtool != BT_MOVETEXTURE)
trace_brush_faceid = 0;
if (brushtool == BT_SLICE || brushtool == BT_CREATE)
@ -1410,21 +1687,36 @@ float(float key, float unic, vector mousepos) editor_brushes_key =
selectedbrush = trace_brush_id;
selectedbrushface = trace_brush_faceid;
selectedbrushmodel = tracemodel;
brush_selected(selectedbrushmodel, selectedbrush, selectedbrushface, TRUE);
if (trace_brush_faceid)
brush_selected(selectedbrushmodel, selectedbrush, selectedbrushface, TRUE);
vertedit.numidx = 0;
vertedit.numverts = 0;
if (selectedbrushface && (brushtool == BT_PUSHFACE || brushtool == BT_MOVETEXTURE))
{
mousedown = TRUE;
mousetool = brushtool;
vertedit.selectedvert1 = -1;
vertedit.selectedvert2 = -1;
bt_point[0] = brush_snappoint(trace_endpos);
bt_points = 1;
bt_displace = '0 0 0';
}
}
else if (selectedbrush == trace_brush_id && selectedbrushface == trace_brush_faceid && selectedbrushmodel == tracemodel)
{
mousedown = TRUE;
mousetool = brushtool;
vertedit.selectedvert1 = -1;
vertedit.selectedvert2 = -1;
bt_point[0] = brush_snappoint(trace_endpos);
bt_points = 1;
bt_displace = '0 0 0';
}
if (brushtool == BT_VERTEXEDIT && !vertedit.numidx && selectedbrush)
{
mousedown = FALSE;
Debrushify();
brush_selected(selectedbrushmodel, selectedbrush, selectedbrushface, TRUE);
}
@ -1433,11 +1725,13 @@ float(float key, float unic, vector mousepos) editor_brushes_key =
if (key == K_ENTER)
{
if (mousetool == BT_VERTEXEDIT)
if (vertedit.numidx)
{
Rebrushify(&vertedit, FALSE);
mousetool = BT_NONE;
bt_points = 0;
vertedit.numidx = 0;
vertedit.numverts = 0;
mousedown = FALSE;
return TRUE;
}
@ -1508,31 +1802,7 @@ float(float key, float unic, vector mousepos) editor_brushes_key =
}
return TRUE;
}
if (vertedit.numidx)
{
vector dir = '0 0 0';
makevectors(input_angles);
if (key == K_KP_PLUS)
dir = axialize(v_up);
else if (key == K_KP_MINUS)
dir = -axialize(v_up);
else if (key == K_KP_UPARROW)
dir = axialize(v_forward);
else if (key == K_KP_DOWNARROW)
dir = -axialize(v_forward);
else if (key == K_KP_RIGHTARROW)
dir = axialize(v_right);
else if (key == K_KP_LEFTARROW)
dir = -axialize(v_right);
if (dir != '0 0 0')
{
vertedit.p[0] += dir;
return TRUE;
}
}
}
/* if (key == 's')
{

View file

@ -22,6 +22,8 @@ typedef struct
static entedit_t *editents;
static int numents;
static int entsdirty;
static float entsapplytime;
struct
{ //FIXME: should probably parse quakeed comments or something.
@ -173,38 +175,43 @@ void(float num) editor_ents_delete =
}
};
void() updatemodelents =
{
entsdirty = FALSE;
self = world;
terrain_edit(TEREDIT_ENTS_WIPE);
for (int e = 0; e < numents; e++)
{
local entedit_t *ent = &editents[e];
string n;
n = "{\n";
for (int i = 0; ; i++)
{
string key, value;
key = hash_getkey(ent->fields, i);
if not (key)
break;
value = ent->fields[key];
//inject markup into the value so that it doesn't get too corrupted
value = strreplace("\\", "\\\\", value);
value = strreplace("\"", "\\\"", value);
value = strreplace("\n", "\\n", value);
//these are more optional
value = strreplace("\t", "\\t", value);
value = strreplace("\r", "\\r", value);
n = strcat(n, key, " \"", value, "\"\n");
}
n = strcat(n, "}\n");
terrain_edit(TEREDIT_ENTS_CONCAT, n);
}
};
float(float mode) editor_ents_poll =
{
if (mode != MODE_ENTSEDIT)
{
int i, e;
self = world;
terrain_edit(TEREDIT_ENTS_WIPE);
for (e = 0; e < numents; e++)
{
local entedit_t *ent = &editents[e];
string n;
n = "{\n";
for (i = 0; ; i++)
{
string key, value;
key = hash_getkey(ent->fields, i);
if not (key)
break;
value = ent->fields[key];
//inject markup into the value so that it doesn't get too corrupted
value = strreplace("\\", "\\\\", value);
value = strreplace("\"", "\\\"", value);
value = strreplace("\n", "\\n", value);
//these are more optional
value = strreplace("\t", "\\t", value);
value = strreplace("\r", "\\r", value);
n = strcat(n, key, " \"", value, "\"\n");
}
n = strcat(n, "}\n");
terrain_edit(TEREDIT_ENTS_CONCAT, n);
}
{
updatemodelents();
localcmd("mod_terrain_save\n"); //saves a .ent if its a bsp, a .map if it has brushes, and a .hmp if otherwise. or something.
ca_checksave = __NULL__;
return TRUE;
@ -214,6 +221,9 @@ float(float mode) editor_ents_poll =
void() editor_ents_edited =
{
ca_checksave = editor_ents_poll;
entsdirty = TRUE;
entsapplytime = cltime+2;
}
inline float(string model) modelindexforname =
@ -433,6 +443,8 @@ float(float key, float unic, vector mousepos) editor_ents_key =
float bestfrac = 1;
int bestent = selectedent, e;
//FIXME: we need some click+drag moving like the brush editor has
if (mousepos_x < 128)
{
editfieldtype = editkey?2:1;
@ -623,4 +635,7 @@ void(vector mousepos) editor_ents_overlay =
drawrawstring(pos, sprintf("%s: <UNDEFINED>", editkey==""?"<UNMNAMED>":editkey), '8 8 0', '0 0 1', 1);
pos_y += 8;
}
if (entsdirty && cltime > entsapplytime)
updatemodelents();
};