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:
parent
12dd83c20f
commit
cc875358fd
23 changed files with 900 additions and 232 deletions
|
@ -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')
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue