--- /dev/null
+
+// this code written by Forest Hale, on 2003-08-23, and placed into public domain
+// this code deals with quadratic splines (minimum of 3 points), the same kind used in Quake3 maps.
+
+// LordHavoc's rant on misuse of the name 'bezier': many people seem to think that bezier is a generic term for splines, but it is not, it is a term for a specific type of spline (minimum of 4 control points, cubic spline).
+
+#include "curves.h"
+
+void QuadraticSplineSubdivideFloat(int inpoints, int components, const float *in, int instride, float *out, int outstride)
+{
+ int s;
+ // the input (control points) is read as a stream of points, and buffered
+ // by the cpprev, cpcurr, and cpnext variables (to allow subdivision in
+ // overlapping memory buffers, even subdivision in-place with pre-spaced
+ // control points in the buffer)
+ // the output (resulting curve) is written as a stream of points
+ // this subdivision is meant to be repeated until the desired flatness
+ // level is reached
+ if (components == 1 && instride == (int)sizeof(float) && outstride == instride)
+ {
+ // simple case, single component and no special stride
+ float cpprev0 = 0, cpcurr0 = 0, cpnext0;
+ cpnext0 = *in++;
+ for (s = 0;s < inpoints - 1;s++)
+ {
+ cpprev0 = cpcurr0;
+ cpcurr0 = cpnext0;
+ if (s < inpoints - 1)
+ cpnext0 = *in++;
+ if (s > 0)
+ {
+ // 50% flattened control point
+ // cp1 = average(cp1, average(cp0, cp2));
+ *out++ = (cpcurr0 + (cpprev0 + cpnext0) * 0.5f) * 0.5f;
+ }
+ else
+ {
+ // copy the control point directly
+ *out++ = cpcurr0;
+ }
+ // midpoint
+ // mid = average(cp0, cp1);
+ *out++ = (cpcurr0 + cpnext0) * 0.5f;
+ }
+ // copy the final control point
+ *out++ = cpnext0;
+ }
+ else
+ {
+ // multiple components or stride is used (complex case)
+ int c;
+ float cpprev[4], cpcurr[4], cpnext[4];
+ // check if there are too many components for the buffers
+ if (components > 1)
+ {
+ // more components can be handled, but slowly, by calling self multiple times...
+ for (c = 0;c < components;c++, in++, out++)
+ QuadraticSplineSubdivideFloat(inpoints, 1, in, instride, out, outstride);
+ return;
+ }
+ for (c = 0;c < components;c++)
+ cpnext[c] = in[c];
+ (unsigned char *)in += instride;
+ for (s = 0;s < inpoints - 1;s++)
+ {
+ for (c = 0;c < components;c++)
+ cpprev[c] = cpcurr[c];
+ for (c = 0;c < components;c++)
+ cpcurr[c] = cpnext[c];
+ for (c = 0;c < components;c++)
+ cpnext[c] = in[c];
+ (unsigned char *)in += instride;
+ // the end points are copied as-is
+ if (s > 0)
+ {
+ // 50% flattened control point
+ // cp1 = average(cp1, average(cp0, cp2));
+ for (c = 0;c < components;c++)
+ out[c] = (cpcurr[c] + (cpprev[c] + cpnext[c]) * 0.5f) * 0.5f;
+ }
+ else
+ {
+ // copy the control point directly
+ for (c = 0;c < components;c++)
+ out[c] = cpcurr[c];
+ }
+ (unsigned char *)out += outstride;
+ // midpoint
+ // mid = average(cp0, cp1);
+ for (c = 0;c < components;c++)
+ out[c] = (cpcurr[c] + cpnext[c]) * 0.5f;
+ (unsigned char *)out += outstride;
+ }
+ // copy the final control point
+ for (c = 0;c < components;c++)
+ out[c] = cpnext[c];
+ //(unsigned char *)out += outstride;
+ }
+}
+
+// note: out must have enough room!
+// (see finalwidth/finalheight calcs below)
+void QuadraticSplinePatchSubdivideFloatBuffer(int cpwidth, int cpheight, int xlevel, int ylevel, int components, const float *in, float *out)
+{
+ int finalwidth, finalheight, xstep, ystep, x, y, c;
+ float *o;
+
+ // error out on various bogus conditions
+ if (xlevel < 0 || ylevel < 0 || xlevel > 16 || ylevel > 16 || cpwidth < 3 || cpheight < 3)
+ return;
+
+ xstep = 1 << xlevel;
+ ystep = 1 << ylevel;
+ finalwidth = (cpwidth - 1) * xstep + 1;
+ finalheight = (cpheight - 1) * ystep + 1;
+
+ for (y = 0;y < finalheight;y++)
+ for (x = 0;x < finalwidth;x++)
+ for (c = 0, o = out + (y * finalwidth + x) * components;c < components;c++)
+ o[c] = 0;
+
+ if (xlevel == 1 && ylevel == 0)
+ {
+ for (y = 0;y < finalheight;y++)
+ QuadraticSplineSubdivideFloat(cpwidth, components, in + y * cpwidth * components, sizeof(float) * components, out + y * finalwidth * components, sizeof(float) * components);
+ return;
+ }
+ if (xlevel == 0 && ylevel == 1)
+ {
+ for (x = 0;x < finalwidth;x++)
+ QuadraticSplineSubdivideFloat(cpheight, components, in + x * components, sizeof(float) * cpwidth * components, out + x * components, sizeof(float) * finalwidth * components);
+ return;
+ }
+
+ // copy control points into correct positions in destination buffer
+ for (y = 0;y < finalheight;y += ystep)
+ for (x = 0;x < finalwidth;x += xstep)
+ for (c = 0, o = out + (y * finalwidth + x) * components;c < components;c++)
+ o[c] = *in++;
+
+ // subdivide in place in the destination buffer
+ while (xstep > 1 || ystep > 1)
+ {
+ if (xstep > 1)
+ {
+ xstep >>= 1;
+ for (y = 0;y < finalheight;y += ystep)
+ QuadraticSplineSubdivideFloat(cpwidth, components, out + y * finalwidth * components, sizeof(float) * xstep * 2 * components, out + y * finalwidth * components, sizeof(float) * xstep * components);
+ cpwidth = (cpwidth - 1) * 2 + 1;
+ }
+ if (ystep > 1)
+ {
+ ystep >>= 1;
+ for (x = 0;x < finalwidth;x += xstep)
+ QuadraticSplineSubdivideFloat(cpheight, components, out + x * components, sizeof(float) * ystep * 2 * finalwidth * components, out + x * components, sizeof(float) * ystep * finalwidth * components);
+ cpheight = (cpheight - 1) * 2 + 1;
+ }
+ }
+}
+
+
--- /dev/null
+
+#ifndef CURVES_H
+#define CURVES_H
+
+void QuadraticSplineSubdivideFloat(int inpoints, int components, const float *in, int instride, float *out, int outstride);
+void QuadraticSplinePatchSubdivideFloatBuffer(int cpwidth, int cpheight, int xlevel, int ylevel, int components, const float *in, float *out);
+
+#endif
+
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\curves.c\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\cvar.c\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\curves.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\cvar.h\r
# End Source File\r
# Begin Source File\r
float varray_texcoord2f[4][65536*2];
float varray_texcoord3f[4][65536*3];
float varray_normal3f[65536*3];
+int earray_element3i[65536];
//===========================================================================
// vertex array caching subsystem
extern float varray_texcoord2f[4][65536*2];
extern float varray_texcoord3f[4][65536*3];
extern float varray_normal3f[65536*3];
+extern int earray_element3i[65536];
#endif
cvar_t r_floatbuildlightmap = {0, "r_floatbuildlightmap", "0"};
cvar_t r_detailtextures = {CVAR_SAVE, "r_detailtextures", "1"};
cvar_t r_surfaceworldnode = {0, "r_surfaceworldnode", "1"};
+cvar_t r_curves_subdivide_level = {0, "r_curves_subdivide_level", "0"};
static int dlightdivtable[32768];
R_Mesh_Draw(face->numvertices, face->numtriangles, face->data_element3i);
}
+#include "curves.h"
+
void R_Q3BSP_DrawFace_Patch(entity_render_t *ent, q3mface_t *face)
{
+ int *e, row0, row1, finalwidth, finalheight, x, y, xlevel = r_curves_subdivide_level.integer, ylevel = r_curves_subdivide_level.integer;
+ rmeshstate_t m;
+
+ finalwidth = ((face->patchsize[0] - 1) << xlevel) + 1;
+ finalheight = ((face->patchsize[1] - 1) << ylevel) + 1;
+
+ // generate vertex arrays
+ QuadraticSplinePatchSubdivideFloatBuffer(face->patchsize[0], face->patchsize[1], xlevel, ylevel, 3, face->data_vertex3f, varray_vertex3f);
+ QuadraticSplinePatchSubdivideFloatBuffer(face->patchsize[0], face->patchsize[1], xlevel, ylevel, 2, face->data_texcoordtexture2f, varray_texcoord2f[0]);
+ if (face->lightmaptexture)
+ QuadraticSplinePatchSubdivideFloatBuffer(face->patchsize[0], face->patchsize[1], xlevel, ylevel, 2, face->data_texcoordlightmap2f, varray_texcoord2f[1]);
+ else
+ QuadraticSplinePatchSubdivideFloatBuffer(face->patchsize[0], face->patchsize[1], xlevel, ylevel, 4, face->data_color4f, varray_color4f);
+
+ // generate elements
+ e = earray_element3i;
+ for (y = 0;y < finalheight - 1;y++)
+ {
+ row0 = (y + 0) * finalwidth;
+ row1 = (y + 1) * finalwidth;
+ for (x = 0;x < finalwidth - 1;x++)
+ {
+ *e++ = row0;
+ *e++ = row1;
+ *e++ = row0 + 1;
+ *e++ = row1;
+ *e++ = row1 + 1;
+ *e++ = row0 + 1;
+ row0++;
+ row1++;
+ }
+ }
+ for (x = 0;x < (finalwidth-1)*(finalheight-1)*6;x++)
+ if ((unsigned int)earray_element3i[x] >= (unsigned int)(finalwidth*finalheight))
+ Con_Printf("e[%i] = %i (> %i)\n", x, earray_element3i[x], finalwidth*finalheight);
+
+ memset(&m, 0, sizeof(m));
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_DepthMask(true);
+ GL_DepthTest(true);
+ m.tex[0] = R_GetTexture(face->texture->skin.base);
+ m.pointer_texcoord[0] = varray_texcoord2f[0];
+ if (face->lightmaptexture)
+ {
+ m.tex[1] = R_GetTexture(face->lightmaptexture);
+ m.pointer_texcoord[1] = varray_texcoord2f[1];
+ m.texrgbscale[1] = 2;
+ GL_Color(r_colorscale, r_colorscale, r_colorscale, 1);
+ }
+ else
+ {
+ m.texrgbscale[0] = 2;
+ GL_ColorPointer(varray_color4f);
+ }
+ R_Mesh_State_Texture(&m);
+ GL_VertexPointer(varray_vertex3f);
+ R_Mesh_Draw(finalwidth * finalheight, (finalwidth - 1) * (finalheight - 1) * 2, earray_element3i);
}
void R_Q3BSP_DrawFace(entity_render_t *ent, q3mface_t *face)
model = ent->model;
if (r_drawcollisionbrushes.integer < 2)
{
- if (ent == &cl_entities[0].render)
+ if (ent == &cl_entities[0].render && model->brushq3.num_pvsclusters && !r_novis.integer)
{
Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
pvs = model->brush.GetPVS(model, modelorg);
Cvar_RegisterVariable(&r_floatbuildlightmap);
Cvar_RegisterVariable(&r_detailtextures);
Cvar_RegisterVariable(&r_surfaceworldnode);
+ Cvar_RegisterVariable(&r_curves_subdivide_level);
R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
}
filematch.o host.o host_cmd.o image.o mathlib.o matrixlib.o \
model_alias.o model_brush.o model_shared.o model_sprite.o \
netconn.o lhnet.o palette.o portals.o protocol.o fs.o \
- sys_shared.o winding.o world.o wad.o zone.o
+ sys_shared.o winding.o world.o wad.o zone.o curves.o
COMMONOBJECTS= $(CLIENTOBJECTS) $(SERVEROBJECTS) $(SHAREDOBJECTS)
# note that builddate.c is very intentionally not compiled to a .o before
{
*out = LittleLong(*in);
if (*out < 0 || *out >= loadmodel->brushq3.num_vertices)
- Host_Error("Mod_Q3BSP_LoadTriangles: invalid vertexindex %i (%i vertices)\n", *out, loadmodel->brushq3.num_vertices);
+ {
+ Con_Printf("Mod_Q3BSP_LoadTriangles: invalid vertexindex %i (%i vertices), setting to 0\n", *out, loadmodel->brushq3.num_vertices);
+ *out = 0;
+ }
}
}
out->type = 0; // error
continue;
}
+ out->data_vertex3f = loadmodel->brushq3.data_vertex3f + out->firstvertex * 3;
+ out->data_texcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + out->firstvertex * 2;
+ out->data_texcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + out->firstvertex * 2;
+ out->data_svector3f = loadmodel->brushq3.data_svector3f + out->firstvertex * 3;
+ out->data_tvector3f = loadmodel->brushq3.data_tvector3f + out->firstvertex * 3;
+ out->data_normal3f = loadmodel->brushq3.data_normal3f + out->firstvertex * 3;
+ out->data_color4f = loadmodel->brushq3.data_color4f + out->firstvertex * 4;
+ out->data_element3i = loadmodel->brushq3.data_element3i + out->firstelement;
+ out->data_neighbor3i = loadmodel->brushq3.data_neighbor3i + out->firstelement;
switch(out->type)
{
case Q3FACETYPE_POLYGON:
case Q3FACETYPE_MESH:
- out->data_vertex3f = loadmodel->brushq3.data_vertex3f + out->firstvertex * 3;
- out->data_texcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + out->firstvertex * 2;
- out->data_texcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + out->firstvertex * 2;
- out->data_svector3f = loadmodel->brushq3.data_svector3f + out->firstvertex * 3;
- out->data_tvector3f = loadmodel->brushq3.data_tvector3f + out->firstvertex * 3;
- out->data_normal3f = loadmodel->brushq3.data_normal3f + out->firstvertex * 3;
- out->data_color4f = loadmodel->brushq3.data_color4f + out->firstvertex * 4;
- out->data_element3i = loadmodel->brushq3.data_element3i + out->firstelement;
- out->data_neighbor3i = loadmodel->brushq3.data_neighbor3i + out->firstelement;
break;
case Q3FACETYPE_PATCH:
patchsize[0] = LittleLong(in->specific.patch.patchsize[0]);
out->type = 0; // error
continue;
}
+ out->patchsize[0] = patchsize[0];
+ out->patchsize[1] = patchsize[1];
+ out->numelements = out->numtriangles = 0;
// FIXME: convert patch to triangles here!
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_PATCH not supported (yet)\n", i, out->texture->name);
- out->type = 0;
- continue;
+ //Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_PATCH not supported (yet)\n", i, out->texture->name);
+ //out->type = 0;
+ //continue;
break;
case Q3FACETYPE_FLARE:
Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name);
- out->type = 0;
- continue;
+ //out->type = 0;
+ //continue;
break;
}
for (j = 0, invalidelements = 0;j < out->numelements;j++)
q3dpvs_t *in;
int totalchains;
+ if (l->filelen == 0)
+ return;
+
in = (void *)(mod_base + l->fileofs);
if (l->filelen < 9)
Host_Error("Mod_Q3BSP_LoadPVS: funny lump size in %s",loadmodel->name);
-n darkplaces: fix a crash when changing level while using qe1 textures (Todd)
-n darkplaces: revert noclip movement to match nq for compatibility with mods that trap movement as input (MauveBib)
-n dpmod: make grapple off-hand (joe hill)
+0 darkplaces: add chase_pitch cvar to control pitch angle of chase camera, and chase_angle cvar to control yaw angle of chase camera, and add back chase_right cvar (Electro)
+0 darkplaces: add a scr_screenshot_jpeg_quality cvar (Electro)
+0 darkplaces: shadows are not working with model tag attachments (Electro)
+0 darkplaces: add automatic binding to whatever address the machine's hostname resolves to (in addition to 0.0.0.0); see original quake code for examples (yummyluv)
0 darkplaces: ability to disable fopen builtin access to read /, read data/, write data/, or disable fopen builtin entirely
0 darkplaces: add DP_GFX_QUAKE3MODELTAGS, DP_GFX_SKINFILES, and any other new extensions to the wiki
0 darkplaces: add DP_LITSUPPORT extension
1 darkplaces: display "No servers found" instead of a cursor when there are none (yummyluv)
1 darkplaces: don't accept connect packets after first one (tell Willis)
1 darkplaces: figure out what's causing skybox to go textureless occasionally (yummyluv)
-1 darkplaces: finish porting Quake2 keyboard stuff (such as clipboard) (Rick)
+1 darkplaces: finish porting Quake2 keyboard stuff (such as clipboard) (Rick, FrikaC)
1 darkplaces: fix lots of bugs and then retitle the website to get more publicity: DarkPlaces: Re-live Quake again...
1 darkplaces: fix stuck buttons during a level change (mercury82, tkimmet@ezworks.net) (further note: this is from the console becoming active temporarily and catching the key release when the player lets go during the loading stage, make it possible to release a button that was pressed before the console was activated, or make it execute -commands for all pressed binds when level starts)
1 darkplaces: make Host_Error call error reset functions on renderer subsystems? (models are already flushed)