]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_brush.c
More MacOS X stuff. The correct test for MacOS X in preprocessor seems to
[xonotic/darkplaces.git] / model_brush.c
index e927d009b90d0442b4029699aee9cbe15d91da46..13b4df27a227aedfe6ac3ede1aba90fcf226a8a4 100644 (file)
@@ -36,8 +36,9 @@ cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
 cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
 cvar_t mod_q3bsp_curves_subdivide_level = {0, "mod_q3bsp_curves_subdivide_level", "2"};
 cvar_t mod_q3bsp_curves_collisions = {0, "mod_q3bsp_curves_collisions", "1"};
-cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "1"};
+cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "0"};
 
+static void Mod_Q1BSP_Collision_Init (void);
 void Mod_BrushInit(void)
 {
 //     Cvar_RegisterVariable(&r_subdivide_size);
@@ -50,6 +51,7 @@ void Mod_BrushInit(void)
        Cvar_RegisterVariable(&mod_q3bsp_curves_collisions);
        Cvar_RegisterVariable(&mod_q3bsp_optimizedtraceline);
        memset(mod_q1bsp_novis, 0xff, sizeof(mod_q1bsp_novis));
+       Mod_Q1BSP_Collision_Init();
 }
 
 static mleaf_t *Mod_Q1BSP_PointInLeaf(model_t *model, const vec3_t p)
@@ -416,11 +418,17 @@ loc0:
                        // if the first leaf is solid, set startsolid
                        if (t->trace->allsolid)
                                t->trace->startsolid = true;
+#if COLLISIONPARANOID >= 3
+                       Con_Printf("S");
+#endif
                        return HULLCHECKSTATE_SOLID;
                }
                else
                {
                        t->trace->allsolid = false;
+#if COLLISIONPARANOID >= 3
+                       Con_Printf("E");
+#endif
                        return HULLCHECKSTATE_EMPTY;
                }
        }
@@ -444,6 +452,9 @@ loc0:
        {
                if (t2 < 0)
                {
+#if COLLISIONPARANOID >= 3
+                       Con_Printf("<");
+#endif
                        num = node->children[1];
                        goto loc0;
                }
@@ -453,6 +464,9 @@ loc0:
        {
                if (t2 >= 0)
                {
+#if COLLISIONPARANOID >= 3
+                       Con_Printf(">");
+#endif
                        num = node->children[0];
                        goto loc0;
                }
@@ -461,6 +475,9 @@ loc0:
 
        // the line intersects, find intersection point
        // LordHavoc: this uses the original trace for maximum accuracy
+#if COLLISIONPARANOID >= 3
+       Con_Printf("M");
+#endif
        if (plane->type < 3)
        {
                t1 = t->start[plane->type] - plane->dist;
@@ -506,9 +523,36 @@ loc0:
        midf = t1 / (t1 - t2);
        t->trace->fraction = bound(0.0f, midf, 1.0);
 
+#if COLLISIONPARANOID >= 3
+       Con_Printf("D");
+#endif
        return HULLCHECKSTATE_DONE;
 }
 
+#if COLLISIONPARANOID < 2
+static int Mod_Q1BSP_RecursiveHullCheckPoint(RecursiveHullCheckTraceInfo_t *t, int num)
+{
+       while (num >= 0)
+               num = t->hull->clipnodes[num].children[(t->hull->planes[t->hull->clipnodes[num].planenum].type < 3 ? t->start[t->hull->planes[t->hull->clipnodes[num].planenum].type] : DotProduct(t->hull->planes[t->hull->clipnodes[num].planenum].normal, t->start)) < t->hull->planes[t->hull->clipnodes[num].planenum].dist];
+       num = Mod_Q1BSP_SuperContentsFromNativeContents(NULL, num);
+       t->trace->startsupercontents |= num;
+       if (num & SUPERCONTENTS_LIQUIDSMASK)
+               t->trace->inwater = true;
+       if (num == 0)
+               t->trace->inopen = true;
+       if (num & t->trace->hitsupercontentsmask)
+       {
+               t->trace->allsolid = t->trace->startsolid = true;
+               return HULLCHECKSTATE_SOLID;
+       }
+       else
+       {
+               t->trace->allsolid = t->trace->startsolid = false;
+               return HULLCHECKSTATE_EMPTY;
+       }
+}
+#endif
+
 static void Mod_Q1BSP_TraceBox(struct model_s *model, int frame, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask)
 {
        // this function currently only supports same size start and end
@@ -526,7 +570,9 @@ static void Mod_Q1BSP_TraceBox(struct model_s *model, int frame, trace_t *trace,
                rhc.hull = &model->brushq1.hulls[0]; // 0x0x0
        else if (model->brush.ishlbsp)
        {
-               if (boxsize[0] <= 32)
+               // LordHavoc: this has to have a minor tolerance (the .1) because of
+               // minor float precision errors from the box being transformed around
+               if (boxsize[0] < 32.1)
                {
                        if (boxsize[2] < 54) // pick the nearest of 36 or 72
                                rhc.hull = &model->brushq1.hulls[3]; // 32x32x36
@@ -538,7 +584,9 @@ static void Mod_Q1BSP_TraceBox(struct model_s *model, int frame, trace_t *trace,
        }
        else
        {
-               if (boxsize[0] <= 32)
+               // LordHavoc: this has to have a minor tolerance (the .1) because of
+               // minor float precision errors from the box being transformed around
+               if (boxsize[0] < 32.1)
                        rhc.hull = &model->brushq1.hulls[1]; // 32x32x56
                else
                        rhc.hull = &model->brushq1.hulls[2]; // 64x64x88
@@ -546,7 +594,113 @@ static void Mod_Q1BSP_TraceBox(struct model_s *model, int frame, trace_t *trace,
        VectorSubtract(boxstartmins, rhc.hull->clip_mins, rhc.start);
        VectorSubtract(boxendmins, rhc.hull->clip_mins, rhc.end);
        VectorSubtract(rhc.end, rhc.start, rhc.dist);
+#if COLLISIONPARANOID >= 2
+       Con_Printf("t(%f %f %f,%f %f %f,%i %f %f %f)", rhc.start[0], rhc.start[1], rhc.start[2], rhc.end[0], rhc.end[1], rhc.end[2], rhc.hull - model->brushq1.hulls, rhc.hull->clip_mins[0], rhc.hull->clip_mins[1], rhc.hull->clip_mins[2]);
+       Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end);
+       Con_Printf("\n");
+#else
+       if (DotProduct(rhc.dist, rhc.dist))
+               Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end);
+       else
+               Mod_Q1BSP_RecursiveHullCheckPoint(&rhc, rhc.hull->firstclipnode);
+#endif
+}
+
+static hull_t box_hull;
+static dclipnode_t box_clipnodes[6];
+static mplane_t box_planes[6];
+
+static void Mod_Q1BSP_Collision_Init (void)
+{
+       int             i;
+       int             side;
+
+       //Set up the planes and clipnodes so that the six floats of a bounding box
+       //can just be stored out and get a proper hull_t structure.
+
+       box_hull.clipnodes = box_clipnodes;
+       box_hull.planes = box_planes;
+       box_hull.firstclipnode = 0;
+       box_hull.lastclipnode = 5;
+
+       for (i = 0;i < 6;i++)
+       {
+               box_clipnodes[i].planenum = i;
+
+               side = i&1;
+
+               box_clipnodes[i].children[side] = CONTENTS_EMPTY;
+               if (i != 5)
+                       box_clipnodes[i].children[side^1] = i + 1;
+               else
+                       box_clipnodes[i].children[side^1] = CONTENTS_SOLID;
+
+               box_planes[i].type = i>>1;
+               box_planes[i].normal[i>>1] = 1;
+       }
+}
+
+void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask, int boxsupercontents)
+{
+#if 1
+       colbrushf_t cbox;
+       colplanef_t cbox_planes[6];
+       cbox.supercontents = boxsupercontents;
+       cbox.numplanes = 6;
+       cbox.numpoints = 0;
+       cbox.numtriangles = 0;
+       cbox.planes = cbox_planes;
+       cbox.points = NULL;
+       cbox.elements = NULL;
+       cbox.markframe = 0;
+       cbox.mins[0] = 0;
+       cbox.mins[1] = 0;
+       cbox.mins[2] = 0;
+       cbox.maxs[0] = 0;
+       cbox.maxs[1] = 0;
+       cbox.maxs[2] = 0;
+       cbox_planes[0].normal[0] =  1;cbox_planes[0].normal[1] =  0;cbox_planes[0].normal[2] =  0;cbox_planes[0].dist = cmaxs[0] - mins[0];
+       cbox_planes[1].normal[0] = -1;cbox_planes[1].normal[1] =  0;cbox_planes[1].normal[2] =  0;cbox_planes[1].dist = maxs[0] - cmins[0];
+       cbox_planes[2].normal[0] =  0;cbox_planes[2].normal[1] =  1;cbox_planes[2].normal[2] =  0;cbox_planes[2].dist = cmaxs[1] - mins[1];
+       cbox_planes[3].normal[0] =  0;cbox_planes[3].normal[1] = -1;cbox_planes[3].normal[2] =  0;cbox_planes[3].dist = maxs[1] - cmins[1];
+       cbox_planes[4].normal[0] =  0;cbox_planes[4].normal[1] =  0;cbox_planes[4].normal[2] =  1;cbox_planes[4].dist = cmaxs[2] - mins[2];
+       cbox_planes[5].normal[0] =  0;cbox_planes[5].normal[1] =  0;cbox_planes[5].normal[2] = -1;cbox_planes[5].dist = maxs[2] - cmins[2];
+       memset(trace, 0, sizeof(trace_t));
+       trace->hitsupercontentsmask = hitsupercontentsmask;
+       trace->fraction = 1;
+       Collision_TraceLineBrushFloat(trace, start, end, &cbox, &cbox);
+#else
+       RecursiveHullCheckTraceInfo_t rhc;
+       // fill in a default trace
+       memset(&rhc, 0, sizeof(rhc));
+       memset(trace, 0, sizeof(trace_t));
+       //To keep everything totally uniform, bounding boxes are turned into small
+       //BSP trees instead of being compared directly.
+       // create a temp hull from bounding box sizes
+       box_planes[0].dist = cmaxs[0] - mins[0];
+       box_planes[1].dist = cmins[0] - maxs[0];
+       box_planes[2].dist = cmaxs[1] - mins[1];
+       box_planes[3].dist = cmins[1] - maxs[1];
+       box_planes[4].dist = cmaxs[2] - mins[2];
+       box_planes[5].dist = cmins[2] - maxs[2];
+#if COLLISIONPARANOID >= 3
+       Con_Printf("box_planes %f:%f %f:%f %f:%f\ncbox %f %f %f:%f %f %f\nbox %f %f %f:%f %f %f\n", box_planes[0].dist, box_planes[1].dist, box_planes[2].dist, box_planes[3].dist, box_planes[4].dist, box_planes[5].dist, cmins[0], cmins[1], cmins[2], cmaxs[0], cmaxs[1], cmaxs[2], mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]);
+#endif
+       // trace a line through the generated clipping hull
+       //rhc.boxsupercontents = boxsupercontents;
+       rhc.hull = &box_hull;
+       rhc.trace = trace;
+       rhc.trace->hitsupercontentsmask = hitsupercontentsmask;
+       rhc.trace->fraction = 1;
+       rhc.trace->allsolid = true;
+       VectorCopy(start, rhc.start);
+       VectorCopy(end, rhc.end);
+       VectorSubtract(rhc.end, rhc.start, rhc.dist);
        Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end);
+       VectorMA(rhc.start, rhc.trace->fraction, rhc.dist, rhc.trace->endpos);
+       if (rhc.trace->startsupercontents)
+               rhc.trace->startsupercontents = boxsupercontents;
+#endif
 }
 
 static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const mnode_t *node, float x, float y, float startz, float endz)
@@ -709,6 +863,11 @@ static void Mod_Q1BSP_DecompressVis(const qbyte *in, const qbyte *inend, qbyte *
                        *out++ = c;
                else
                {
+                       if (in == inend)
+                       {
+                               Con_DPrintf("Mod_Q1BSP_DecompressVis: input underrun on model \"%s\"\n", loadmodel->name);
+                               return;
+                       }
                        for (c = *in++;c > 0;c--)
                        {
                                if (out == outend)
@@ -3304,6 +3463,12 @@ static void Mod_Q3BSP_LoadTextures(lump_t *l)
        q3dtexture_t *in;
        q3mtexture_t *out;
        int i, count;
+       int j, c;
+       fssearch_t *search;
+       char *f;
+       const char *text;
+       int flags;
+       char shadername[Q3PATHLENGTH];
 
        in = (void *)(mod_base + l->fileofs);
        if (l->filelen % sizeof(*in))
@@ -3316,19 +3481,157 @@ static void Mod_Q3BSP_LoadTextures(lump_t *l)
 
        for (i = 0;i < count;i++, in++, out++)
        {
+               out->number = i;
                strlcpy (out->name, in->name, sizeof (out->name));
                out->surfaceflags = LittleLong(in->surfaceflags);
                out->nativecontents = LittleLong(in->contents);
                out->supercontents = Mod_Q3BSP_SuperContentsFromNativeContents(loadmodel, out->nativecontents);
-               out->renderflags = 0;
-               if (!strcmp(out->name, "caulk") || !strcmp(out->name, "common/caulk") || !strcmp(out->name, "textures/common/caulk"))
-                       out->renderflags |= Q3MTEXTURERENDERFLAGS_NODRAW;
-               if (!strncmp(out->name, "textures/skies/", 15))
-                       out->renderflags |= Q3MTEXTURERENDERFLAGS_SKY;
-
-               out->number = i;
                Mod_LoadSkinFrame(&out->skin, out->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true);
+               out->surfaceparms = -1;
+       }
+
+       // do a quick parse of shader files to get surfaceparms
+       if ((search = FS_Search("scripts/*.shader", true, false)))
+       {
+               for (i = 0;i < search->numfilenames;i++)
+               {
+                       if ((f = FS_LoadFile(search->filenames[i], false)))
+                       {
+                               text = f;
+                               while (COM_ParseToken(&text, false))
+                               {
+                                       snprintf(shadername, sizeof(shadername), "%s", com_token);
+                                       flags = 0;
+                                       if (COM_ParseToken(&text, false) && !strcmp(com_token, "{"))
+                                       {
+                                               while (COM_ParseToken(&text, false))
+                                               {
+                                                       if (!strcmp(com_token, "}"))
+                                                               break;
+                                                       else if (!strcmp(com_token, "{"))
+                                                       {
+                                                               while (COM_ParseToken(&text, false))
+                                                               {
+                                                                       if (!strcmp(com_token, "}"))
+                                                                               break;
+                                                               }
+                                                       }
+                                                       else if (!strcmp(com_token, "surfaceparm"))
+                                                       {
+                                                               if (COM_ParseToken(&text, true) && strcmp(com_token, "\n"))
+                                                               {
+                                                                       if (!strcmp(com_token, "alphashadow"))
+                                                                               flags |= Q3SURFACEPARM_ALPHASHADOW;
+                                                                       else if (!strcmp(com_token, "areaportal"))
+                                                                               flags |= Q3SURFACEPARM_AREAPORTAL;
+                                                                       else if (!strcmp(com_token, "clusterportal"))
+                                                                               flags |= Q3SURFACEPARM_CLUSTERPORTAL;
+                                                                       else if (!strcmp(com_token, "detail"))
+                                                                               flags |= Q3SURFACEPARM_DETAIL;
+                                                                       else if (!strcmp(com_token, "donotenter"))
+                                                                               flags |= Q3SURFACEPARM_DONOTENTER;
+                                                                       else if (!strcmp(com_token, "fog"))
+                                                                               flags |= Q3SURFACEPARM_FOG;
+                                                                       else if (!strcmp(com_token, "lava"))
+                                                                               flags |= Q3SURFACEPARM_LAVA;
+                                                                       else if (!strcmp(com_token, "lightfilter"))
+                                                                               flags |= Q3SURFACEPARM_LIGHTFILTER;
+                                                                       else if (!strcmp(com_token, "metalsteps"))
+                                                                               flags |= Q3SURFACEPARM_METALSTEPS;
+                                                                       else if (!strcmp(com_token, "nodamage"))
+                                                                               flags |= Q3SURFACEPARM_NODAMAGE;
+                                                                       else if (!strcmp(com_token, "nodlight"))
+                                                                               flags |= Q3SURFACEPARM_NODLIGHT;
+                                                                       else if (!strcmp(com_token, "nodraw"))
+                                                                               flags |= Q3SURFACEPARM_NODRAW;
+                                                                       else if (!strcmp(com_token, "nodrop"))
+                                                                               flags |= Q3SURFACEPARM_NODROP;
+                                                                       else if (!strcmp(com_token, "noimpact"))
+                                                                               flags |= Q3SURFACEPARM_NOIMPACT;
+                                                                       else if (!strcmp(com_token, "nolightmap"))
+                                                                               flags |= Q3SURFACEPARM_NOLIGHTMAP;
+                                                                       else if (!strcmp(com_token, "nomarks"))
+                                                                               flags |= Q3SURFACEPARM_NOMARKS;
+                                                                       else if (!strcmp(com_token, "nomipmaps"))
+                                                                               flags |= Q3SURFACEPARM_NOMIPMAPS;
+                                                                       else if (!strcmp(com_token, "nonsolid"))
+                                                                               flags |= Q3SURFACEPARM_NONSOLID;
+                                                                       else if (!strcmp(com_token, "origin"))
+                                                                               flags |= Q3SURFACEPARM_ORIGIN;
+                                                                       else if (!strcmp(com_token, "playerclip"))
+                                                                               flags |= Q3SURFACEPARM_PLAYERCLIP;
+                                                                       else if (!strcmp(com_token, "sky"))
+                                                                               flags |= Q3SURFACEPARM_SKY;
+                                                                       else if (!strcmp(com_token, "slick"))
+                                                                               flags |= Q3SURFACEPARM_SLICK;
+                                                                       else if (!strcmp(com_token, "slime"))
+                                                                               flags |= Q3SURFACEPARM_SLIME;
+                                                                       else if (!strcmp(com_token, "structural"))
+                                                                               flags |= Q3SURFACEPARM_STRUCTURAL;
+                                                                       else if (!strcmp(com_token, "trans"))
+                                                                               flags |= Q3SURFACEPARM_TRANS;
+                                                                       else if (!strcmp(com_token, "water"))
+                                                                               flags |= Q3SURFACEPARM_WATER;
+                                                                       else
+                                                                               Con_Printf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[i], com_token);
+                                                                       if (!COM_ParseToken(&text, true) || strcmp(com_token, "\n"))
+                                                                       {
+                                                                               Con_Printf("%s parsing error: surfaceparm only takes one parameter.\n", search->filenames[i]);
+                                                                               goto parseerror;
+                                                                       }
+                                                               }
+                                                               else
+                                                               {
+                                                                       Con_Printf("%s parsing error: surfaceparm expects a parameter.\n", search->filenames[i]);
+                                                                       goto parseerror;
+                                                               }
+                                                       }
+                                                       else
+                                                       {
+                                                               // look for linebreak or }
+                                                               while(COM_ParseToken(&text, true) && strcmp(com_token, "\n") && strcmp(com_token, "}"));
+                                                               // break out to top level if it was }
+                                                               if (!strcmp(com_token, "}"))
+                                                                       break;
+                                                       }
+                                               }
+                                               // add shader to list (shadername and flags)
+                                               // actually here we just poke into the texture settings
+                                               for (j = 0, out = loadmodel->brushq3.data_textures;j < loadmodel->brushq3.num_textures;j++, out++)
+                                                       if (!strcmp(out->name, shadername))
+                                                               out->surfaceparms = flags;
+                                       }
+                                       else
+                                       {
+                                               Con_Printf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[i], com_token);
+                                               goto parseerror;
+                                       }
+                               }
+parseerror:
+                               Mem_Free(f);
+                       }
+               }
+       }
+
+       c = 0;
+       for (j = 0, out = loadmodel->brushq3.data_textures;j < loadmodel->brushq3.num_textures;j++, out++)
+       {
+               if (out->surfaceparms == -1)
+               {
+                       c++;
+                       Con_DPrintf("%s: No shader found for texture \"%s\"\n", loadmodel->name, out->name);
+                       out->surfaceparms = 0;
+                       // these are defaults
+                       if (!strcmp(out->name, "caulk") || !strcmp(out->name, "common/caulk") || !strcmp(out->name, "textures/common/caulk")
+                        || !strcmp(out->name, "nodraw") || !strcmp(out->name, "common/nodraw") || !strcmp(out->name, "textures/common/nodraw"))
+                               out->surfaceparms |= Q3SURFACEPARM_NODRAW;
+                       if (!strncmp(out->name, "textures/skies/", 15))
+                               out->surfaceparms |= Q3SURFACEPARM_SKY;
+                       if (R_TextureHasAlpha(out->skin.base))
+                               out->surfaceparms |= Q3SURFACEPARM_TRANS;
+               }
        }
+       Con_DPrintf("%s: %i textures missing shaders\n", loadmodel->name, c);
 }
 
 static void Mod_Q3BSP_LoadPlanes(lump_t *l)
@@ -4173,9 +4476,9 @@ static void Mod_Q3BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientc
        // FIXME: write this
        if (!model->brushq3.num_lightgrid)
        {
-               ambientcolor[0] += 128;
-               ambientcolor[1] += 128;
-               ambientcolor[2] += 128;
+               ambientcolor[0] = 1;
+               ambientcolor[1] = 1;
+               ambientcolor[2] = 1;
                return;
        }
        Matrix4x4_Transform(&model->brushq3.num_lightgrid_indexfromworld, p, transformed);
@@ -4669,7 +4972,7 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer)
                mod->radius2 = modelradius * modelradius;
 
                for (j = 0;j < mod->brushq3.data_thismodel->numfaces;j++)
-                       if (mod->brushq3.data_thismodel->firstface[j].texture->renderflags & Q3MTEXTURERENDERFLAGS_SKY)
+                       if (mod->brushq3.data_thismodel->firstface[j].texture->surfaceflags & Q3SURFACEFLAG_SKY)
                                break;
                if (j < mod->brushq3.data_thismodel->numfaces)
                        mod->DrawSky = R_Q3BSP_DrawSky;