t2f[6] = v[1];t2f[7] = tex->t1;
break;
}
+ if (r_showparticleedges.integer)
+ {
+ R_DebugLine(v3f, v3f + 3);
+ R_DebugLine(v3f + 3, v3f + 6);
+ R_DebugLine(v3f + 6, v3f + 9);
+ R_DebugLine(v3f + 9, v3f);
+ }
}
// now render batches of particles based on blendmode and texture
R_UpdateVariables();
+ // this will be set back to 0 by R_RenderView during CL_VM_UpdateView
+ r_refdef.draw2dstage = 1;
+ R_ResetViewRendering2D_Common(0, NULL, NULL, 0, 0, vid.width, vid.height, vid_conwidth.integer, vid_conheight.integer);
+
// Quake uses clockwise winding, so these are swapped
r_refdef.view.cullface_front = GL_BACK;
r_refdef.view.cullface_back = GL_FRONT;
r_refdef.scene.numlights = 0;
// restore the view settings to the values that VM_CL_UpdateView received from the client code
r_refdef.view = csqc_original_r_refdef_view;
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = false;
VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin);
VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles);
cl.csqc_vidvars.drawworld = r_drawworld.integer != 0;
t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0;
prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t;
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = false;
+
// update the views
if (ismain)
{
texname = PRVM_G_STRING(OFS_PARM0);
drawflags = (int)PRVM_G_FLOAT(OFS_PARM1);
- // weird hacky way to figure out if this is a 2D HUD polygon or a scene polygon
- draw2d = (prog->argc >= 3 ? (int)PRVM_G_FLOAT(OFS_PARM2) : r_refdef.draw2dstage);
+ if (prog->argc >= 3)
+ draw2d = PRVM_G_FLOAT(OFS_PARM2) != 0;
+ else
+ {
+ // weird hacky way to figure out if this is a 2D HUD polygon or a scene
+ // polygon, for compatibility with mods aimed at old darkplaces versions
+ // - polygonbegin_guess2d is 0 if the most recent major call was
+ // clearscene, 1 if the most recent major call was drawpic (and similar)
+ // or renderscene
+ draw2d = prog->polygonbegin_guess2d;
+ }
// we need to remember whether this is a 2D or 3D mesh we're adding to
mod = draw2d ? CL_Mesh_UI() : CL_Mesh_CSQC();
{
VM_Cmd_Init(prog);
prog->polygonbegin_model = NULL;
+ prog->polygonbegin_guess2d = 0;
}
void CLVM_reset_cmd(prvm_prog_t *prog)
World_End(&cl.world);
VM_Cmd_Reset(prog);
prog->polygonbegin_model = NULL;
+ prog->polygonbegin_guess2d = 0;
}
// CSQC_UpdateView function does not call R_ClearScene as it should
r_refdef.scene.numentities = 0;
r_refdef.scene.numlights = 0;
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = false;
// pass in width and height as parameters (EXT_CSQC_1)
PRVM_G_FLOAT(OFS_PARM0) = vid.width;
PRVM_G_FLOAT(OFS_PARM1) = vid.height;
#define STRING_COLOR_RGB_TAG_CHAR 'x'
#define STRING_COLOR_RGB_TAG "^x"
-// all of these functions will set r_defdef.draw2dstage if not in 2D rendering mode (and of course prepare for 2D rendering in that case)
+// prepare for 2D rendering (sets r_refdef.draw2dstage = 1 and calls R_ResetViewRendering2D)
+void DrawQ_Start(void);
+// resets r_refdef.draw2dstage to 0
+void DrawQ_Finish(void);
+// batch draw the pending geometry in the CL_Mesh_UI() model and reset the model,
+// to be called by things like DrawQ_SetClipArea which make disruptive state changes.
+void DrawQ_FlushUI(void);
+// use this when changing r_refdef.view.* from e.g. csqc
+void DrawQ_RecalcView(void);
// draw an image (or a filled rectangle if pic == NULL)
void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags);
void DrawQ_ResetClipArea(void);
// draw a line
void DrawQ_Line(float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags);
-// resets r_refdef.draw2dstage
-void DrawQ_Finish(void);
-void DrawQ_RecalcView(void); // use this when changing r_refdef.view.* from e.g. csqc
-// batch draw the pending geometry in the CL_Mesh_UI() model and reset the model,
-// to be called by things like DrawQ_SetClipArea which make disruptive state changes.
-void DrawQ_FlushUI(void);
const char *Draw_GetPicName(cachepic_t *pic);
int Draw_GetPicWidth(cachepic_t *pic);
R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap, NULL, NULL);
}
-static void _DrawQ_Setup(void) // see R_ResetViewRendering2D
+void DrawQ_Start(void)
{
- if (r_refdef.draw2dstage == 1)
- return;
- DrawQ_FlushUI();
r_refdef.draw2dstage = 1;
R_ResetViewRendering2D_Common(0, NULL, NULL, 0, 0, vid.width, vid.height, vid_conwidth.integer, vid_conheight.integer);
}
dp_model_t *mod = CL_Mesh_UI();
msurface_t *surf;
int e0, e1, e2, e3;
- _DrawQ_Setup();
if (!pic)
pic = Draw_CachePic("white");
if (width == 0)
dp_model_t *mod = CL_Mesh_UI();
msurface_t *surf;
int e0, e1, e2, e3;
- _DrawQ_Setup();
if (!pic)
pic = Draw_CachePic("white");
if (width == 0)
tw = Draw_GetPicWidth(fnt->pic);
th = Draw_GetPicHeight(fnt->pic);
- _DrawQ_Setup();
-
if (!h) h = w;
if (!h) {
h = w = 1;
dp_model_t *mod = CL_Mesh_UI();
msurface_t *surf;
int e0, e1, e2, e3;
- _DrawQ_Setup();
if (!pic)
pic = Draw_CachePic("white");
if (width == 0)
msurface_t *surf;
int e0, e1, e2, e3;
float offsetx, offsety;
- _DrawQ_Setup();
// width is measured in real pixels
if (fabs(x2 - x1) > fabs(y2 - y1))
{
offsetx = 0;
- offsety = width * vid_conheight.value / vid.height;
+ offsety = 0.5f * width * vid_conheight.value / vid.height;
}
else
{
- offsetx = width * vid_conwidth.value / vid.width;
+ offsetx = 0.5f * width * vid_conwidth.value / vid.width;
offsety = 0;
}
surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
void DrawQ_SetClipArea(float x, float y, float width, float height)
{
int ix, iy, iw, ih;
- _DrawQ_Setup();
DrawQ_FlushUI();
// We have to convert the con coords into real coords
void DrawQ_ResetClipArea(void)
{
DrawQ_FlushUI();
- _DrawQ_Setup();
GL_ScissorTest(false);
}
cvar_t r_showcollisionbrushes_polygonfactor = {0, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
cvar_t r_showcollisionbrushes_polygonoffset = {0, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
cvar_t r_showdisabledepthtest = {0, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
+cvar_t r_showspriteedges = {0, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
+cvar_t r_showparticleedges = {0, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
cvar_t r_draw2d = {0, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
Cvar_RegisterVariable(&r_showdisabledepthtest);
+ Cvar_RegisterVariable(&r_showspriteedges);
+ Cvar_RegisterVariable(&r_showparticleedges);
Cvar_RegisterVariable(&r_drawportals);
Cvar_RegisterVariable(&r_drawentities);
Cvar_RegisterVariable(&r_draw2d);
void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
{
- DrawQ_Finish();
-
R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
}
void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
{
- DrawQ_Finish();
-
R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
GL_Color(1, 1, 1, 1);
rtexture_t *viewcolortexture = NULL;
int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
+ // finish any 2D rendering that was queued
+ DrawQ_Finish();
+
dpsoftrast_test = r_test.integer;
if (r_timereport_active)
r_refdef.view.matrix = originalmatrix;
CHECKGLERROR
+
+ // go back to 2d rendering
+ DrawQ_Start();
}
void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
}
+void R_DebugLine(vec3_t start, vec3_t end)
+{
+ dp_model_t *mod = CL_Mesh_UI();
+ msurface_t *surf;
+ int e0, e1, e2, e3;
+ float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
+ float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
+ float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
+ vec4_t w[2], s[2];
+
+ // transform to screen coords first
+ Vector4Set(w[0], start[0], start[1], start[2], 1);
+ Vector4Set(w[1], end[0], end[1], end[2], 1);
+ R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
+ R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
+ x1 = s[0][0] * vid_conwidth.value / vid.width;
+ y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
+ x2 = s[1][0] * vid_conwidth.value / vid.width;
+ y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
+ //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
+
+ // add the line to the UI mesh for drawing later
+
+ // width is measured in real pixels
+ if (fabs(x2 - x1) > fabs(y2 - y1))
+ {
+ offsetx = 0;
+ offsety = 0.5f * width * vid_conheight.value / vid.height;
+ }
+ else
+ {
+ offsetx = 0.5f * width * vid_conwidth.value / vid.width;
+ offsety = 0;
+ }
+ surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
+ e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
+ e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
+ e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
+ e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
+ Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
+ Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
+
+}
+
+
void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
{
int q;
VM_Cmd_Init(prog);
prog->polygonbegin_model = NULL;
+ prog->polygonbegin_guess2d = 0;
scene = R_GetScenePointer( RST_MENU );
//VM_Cmd_Init();
VM_Cmd_Reset(prog);
prog->polygonbegin_model = NULL;
+ prog->polygonbegin_guess2d = 0;
}
// stateful, so this tracks the last polygonbegin's choice of
// CL_Mesh_CSQC or CL_Mesh_UI for this polygon
dp_model_t *polygonbegin_model;
+ // indicates if polygonbegin should be interpreted as 2d
+ // (clearscene sets this to false, renderscene sets this to true, drawpic
+ // also sets this to true)
+ // note that in FTEQW polygonbegin with 2 args is handled very differently,
+ // where the behavior is always 3D unless DRAWFLAG_2D is passed, but
+ // DRAWFLAG_2D conflicts with our DRAWFLAG_SCREEN.
+ qboolean polygonbegin_guess2d;
// copies of some vars that were former read from sv
int num_edicts;
float sx, sy;
VM_SAFEPARMCOUNT(6,VM_drawcharacter);
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = true;
+
character = (char) PRVM_G_FLOAT(OFS_PARM1);
if(character == 0)
{
float sx, sy;
VM_SAFEPARMCOUNTRANGE(5,6,VM_drawstring);
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = true;
+
string = PRVM_G_STRING(OFS_PARM1);
pos = PRVM_G_VECTOR(OFS_PARM0);
scale = PRVM_G_VECTOR(OFS_PARM2);
VM_SAFEPARMCOUNTRANGE(5,6,VM_drawcolorcodedstring);
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = true;
+
if (prog->argc == 6) // full 6 parms, like normal drawstring
{
pos = PRVM_G_VECTOR(OFS_PARM0);
VM_SAFEPARMCOUNTRANGE(5,6,VM_drawpic);
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = true;
+
picname = PRVM_G_STRING(OFS_PARM1);
VM_CheckEmptyString(prog, picname);
VM_SAFEPARMCOUNT(8,VM_drawrotpic);
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = true;
+
picname = PRVM_G_STRING(OFS_PARM1);
VM_CheckEmptyString(prog, picname);
VM_SAFEPARMCOUNT(8,VM_drawsubpic);
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = true;
+
picname = PRVM_G_STRING(OFS_PARM2);
VM_CheckEmptyString(prog, picname);
VM_SAFEPARMCOUNT(5,VM_drawfill);
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = true;
pos = PRVM_G_VECTOR(OFS_PARM0);
size = PRVM_G_VECTOR(OFS_PARM1);
float x,y,w,h;
VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = true;
+
x = bound(0, PRVM_G_FLOAT(OFS_PARM0), vid_conwidth.integer);
y = bound(0, PRVM_G_FLOAT(OFS_PARM1), vid_conheight.integer);
w = bound(0, PRVM_G_FLOAT(OFS_PARM2) + PRVM_G_FLOAT(OFS_PARM0) - x, (vid_conwidth.integer - x));
{
VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = true;
+
DrawQ_ResetClipArea();
}
unsigned char flags;
VM_SAFEPARMCOUNT(6, VM_drawline);
+
+ // polygonbegin without draw2d arg has to guess
+ prog->polygonbegin_guess2d = true;
+
width = PRVM_G_FLOAT(OFS_PARM0);
c1 = PRVM_G_VECTOR(OFS_PARM1);
c2 = PRVM_G_VECTOR(OFS_PARM2);
R_CalcSprite_Vertex3f(vertex3f, org, left, up, frame->left, frame->right, frame->down, frame->up);
+ if (r_showspriteedges.integer)
+ for (i = 0; i < 4; i++)
+ R_DebugLine(vertex3f + i * 3, vertex3f + ((i + 1) % 4) * 3);
+
R_DrawCustomSurface_Texture(texture, &identitymatrix, texture->currentmaterialflags, 0, 4, 0, 2, false, false);
}
}
void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight);
void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight);
void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight);
+void R_DebugLine(vec3_t start, vec3_t end);
extern const float r_screenvertex3f[12];
+extern cvar_t r_showspriteedges;
+extern cvar_t r_showparticleedges;
extern cvar_t r_shadows;
extern cvar_t r_shadows_darken;
extern cvar_t r_shadows_drawafterrtlighting;