]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_shared.c
implemented gpu-skinning (vertex shader skeletal animation), can be
[xonotic/darkplaces.git] / model_shared.c
index 92cf45a5bf30d49f81e4b2c41acb10ddbee65ce9..0c4fe1759c63359576b002e563e67072cc1599fc 100644 (file)
@@ -507,7 +507,7 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
                else if (!memcmp(buf, "ACTRHEAD", 8)) Mod_PSKMODEL_Load(mod, buf, bufend);
                else if (!memcmp(buf, "INTERQUAKEMODEL", 16)) Mod_INTERQUAKEMODEL_Load(mod, buf, bufend);
                else if (strlen(mod->name) >= 4 && !strcmp(mod->name + strlen(mod->name) - 4, ".map")) Mod_MAP_Load(mod, buf, bufend);
-               else if (num == BSPVERSION || num == 30) Mod_Q1BSP_Load(mod, buf, bufend);
+               else if (num == BSPVERSION || num == 30 || !memcmp(buf, "BSP2", 4)) Mod_Q1BSP_Load(mod, buf, bufend);
                else Con_Printf("Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name);
                Mem_Free(buf);
 
@@ -582,7 +582,7 @@ dp_model_t *Mod_FindName(const char *name, const char *parentname)
        nummodels = Mem_ExpandableArray_IndexRange(&models);
 
        if (!name[0])
-               Host_Error ("Mod_ForName: NULL name");
+               Host_Error ("Mod_ForName: empty name");
 
        // search the currently loaded models
        for (i = 0;i < nummodels;i++)
@@ -1391,7 +1391,7 @@ void Mod_CreateCollisionMesh(dp_model_t *mod)
        for (k = 0;k < mod->nummodelsurfaces;k++)
        {
                surface = mod->data_surfaces + mod->firstmodelsurface + k;
-               if (!strcmp(surface->texture->name, "collision")) // found collision mesh
+               if (!strcmp(surface->texture->name, "collision") || !strcmp(surface->texture->name, "collisionconvex")) // found collision mesh
                {
                        usesinglecollisionmesh = true;
                        numcollisionmeshtriangles = surface->num_triangles;
@@ -1653,6 +1653,7 @@ extern cvar_t mod_q3shader_default_offsetmapping_bias;
 extern cvar_t mod_q3shader_default_polygonoffset;
 extern cvar_t mod_q3shader_default_polygonfactor;
 extern cvar_t mod_q3shader_force_addalpha;
+extern cvar_t mod_q3shader_force_terrain_alphaflag;
 void Mod_LoadQ3Shaders(void)
 {
        int j;
@@ -1665,8 +1666,8 @@ void Mod_LoadQ3Shaders(void)
        int numparameters;
        char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH];
        char *custsurfaceparmnames[256]; // VorteX: q3map2 has 64 but well, someone will need more
-       unsigned long custsurfaceparms[256]; 
-       int numcustsurfaceparms;
+       unsigned long custsurfaceflags[256]; 
+       int numcustsurfaceflags;
        qboolean dpshaderkill;
 
        Mod_FreeQ3Shaders();
@@ -1680,7 +1681,7 @@ void Mod_LoadQ3Shaders(void)
                q3shaders_mem, sizeof (char**), 256);
 
        // parse custinfoparms.txt
-       numcustsurfaceparms = 0;
+       numcustsurfaceflags = 0;
        if ((text = f = (char *)FS_LoadFile("scripts/custinfoparms.txt", tempmempool, false, NULL)) != NULL)
        {
                if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
@@ -1700,21 +1701,21 @@ void Mod_LoadQ3Shaders(void)
                                        if (!strcasecmp(com_token, "}"))
                                                break;  
                                        // register surfaceflag
-                                       if (numcustsurfaceparms >= 256)
+                                       if (numcustsurfaceflags >= 256)
                                        {
                                                Con_Printf("scripts/custinfoparms.txt: surfaceflags section parsing error - max 256 surfaceflags exceeded\n");
                                                break;
                                        }
                                        // name
                                        j = strlen(com_token)+1;
-                                       custsurfaceparmnames[numcustsurfaceparms] = (char *)Mem_Alloc(tempmempool, j);
-                                       strlcpy(custsurfaceparmnames[numcustsurfaceparms], com_token, j+1);
+                                       custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j);
+                                       strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1);
                                        // value
                                        if (COM_ParseToken_QuakeC(&text, false))
-                                               custsurfaceparms[numcustsurfaceparms] = strtol(com_token, NULL, 0);
+                                               custsurfaceflags[numcustsurfaceflags] = strtol(com_token, NULL, 0);
                                        else
-                                               custsurfaceparms[numcustsurfaceparms] = 0;
-                                       numcustsurfaceparms++;
+                                               custsurfaceflags[numcustsurfaceflags] = 0;
+                                       numcustsurfaceflags++;
                                }
                        }
                }
@@ -1733,6 +1734,24 @@ void Mod_LoadQ3Shaders(void)
                while (COM_ParseToken_QuakeC(&text, false))
                {
                        memset (&shader, 0, sizeof(shader));
+                       shader.name[0] = 0;
+                       shader.surfaceparms = 0;
+                       shader.surfaceflags = 0;
+                       shader.textureflags = 0;
+                       shader.numlayers = 0;
+                       shader.lighting = false;
+                       shader.vertexalpha = false;
+                       shader.textureblendalpha = false;
+                       shader.primarylayer = 0;
+                       shader.backgroundlayer = 0;
+                       shader.skyboxname[0] = 0;
+                       shader.deforms[0].deform = Q3DEFORM_NONE;
+                       shader.dpnortlight = false;
+                       shader.dpshadow = false;
+                       shader.dpnoshadow = false;
+                       shader.dpmeshcollisions = false;
+                       shader.dpshaderkill = false;
+                       shader.dpreflectcube[0] = 0;
                        shader.reflectmin = 0;
                        shader.reflectmax = 1;
                        shader.refractfactor = 1;
@@ -1740,13 +1759,19 @@ void Mod_LoadQ3Shaders(void)
                        shader.reflectfactor = 1;
                        Vector4Set(shader.reflectcolor4f, 1, 1, 1, 1);
                        shader.r_water_wateralpha = 1;
+                       shader.r_water_waterscroll[0] = 0;
+                       shader.r_water_waterscroll[1] = 0;
                        shader.offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
                        shader.offsetscale = mod_q3shader_default_offsetmapping_scale.value;
                        shader.offsetbias = mod_q3shader_default_offsetmapping_bias.value;
-                       shader.specularscalemod = 1;
-                       shader.specularpowermod = 1;
                        shader.biaspolygonoffset = mod_q3shader_default_polygonoffset.value;
                        shader.biaspolygonfactor = mod_q3shader_default_polygonfactor.value;
+                       shader.transparentsort = TRANSPARENTSORT_DISTANCE;
+                       shader.specularscalemod = 1;
+                       shader.specularpowermod = 1;
+                       shader.rtlightambient = 0;
+                       // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
+                       // JUST GREP FOR "specularscalemod = 1".
 
                        strlcpy(shader.name, com_token, sizeof(shader.name));
                        if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
@@ -1999,6 +2024,8 @@ void Mod_LoadQ3Shaders(void)
                                                {
                                                        // multilayer terrain shader or similar
                                                        shader.textureblendalpha = true;
+                                                       if (mod_q3shader_force_terrain_alphaflag.integer)
+                                                               shader.layers[0].texflags |= TEXF_ALPHA;
                                                }
                                        }
 
@@ -2009,7 +2036,7 @@ void Mod_LoadQ3Shaders(void)
                                                if(layer->blendfunc[0] == GL_ONE && layer->blendfunc[1] == GL_ONE)
                                                        layer->blendfunc[0] = GL_SRC_ALPHA;
                                        }
-
+                                       
                                        layer->texflags = 0;
                                        if (layer->alphatest)
                                                layer->texflags |= TEXF_ALPHA;
@@ -2129,19 +2156,21 @@ void Mod_LoadQ3Shaders(void)
                                                shader.surfaceparms |= Q3SURFACEPARM_POINTLIGHT;
                                        else if (!strcasecmp(parameter[1], "antiportal"))
                                                shader.surfaceparms |= Q3SURFACEPARM_ANTIPORTAL;
+                                       else if (!strcasecmp(parameter[1], "skip"))
+                                               ; // shader.surfaceparms |= Q3SURFACEPARM_SKIP; FIXME we don't have enough #defines for this any more, and the engine doesn't need this one anyway
                                        else
                                        {
                                                // try custom surfaceparms
-                                               for (j = 0; j < numcustsurfaceparms; j++)
+                                               for (j = 0; j < numcustsurfaceflags; j++)
                                                {
                                                        if (!strcasecmp(custsurfaceparmnames[j], parameter[1]))
                                                        {
-                                                               shader.surfaceparms |= custsurfaceparms[j];
+                                                               shader.surfaceflags |= custsurfaceflags[j];
                                                                break;
                                                        }
                                                }
                                                // failed all
-                                               if (j == numcustsurfaceparms)
+                                               if (j == numcustsurfaceflags)
                                                        Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
                                        }
                                }
@@ -2243,6 +2272,18 @@ void Mod_LoadQ3Shaders(void)
                                                        shader.biaspolygonoffset = 0;
                                        }
                                }
+                               else if (!strcasecmp(parameter[0], "dptransparentsort") && numparameters >= 2)
+                               {
+                                       shader.textureflags |= Q3TEXTUREFLAG_TRANSPARENTSORT;
+                                       if (!strcasecmp(parameter[1], "sky"))
+                                               shader.transparentsort = TRANSPARENTSORT_SKY;
+                                       else if (!strcasecmp(parameter[1], "distance"))
+                                               shader.transparentsort = TRANSPARENTSORT_DISTANCE;
+                                       else if (!strcasecmp(parameter[1], "hud"))
+                                               shader.transparentsort = TRANSPARENTSORT_HUD;
+                                       else
+                                               Con_DPrintf("%s parsing warning: unknown dptransparentsort category \"%s\", or not enough arguments\n", search->filenames[fileindex], parameter[1]);
+                               }
                                else if (!strcasecmp(parameter[0], "dprefract") && numparameters >= 5)
                                {
                                        shader.textureflags |= Q3TEXTUREFLAG_REFRACTION;
@@ -2388,7 +2429,7 @@ void Mod_LoadQ3Shaders(void)
        }
        FS_FreeSearch(search);
        // free custinfoparm values
-       for (j = 0; j < numcustsurfaceparms; j++)
+       for (j = 0; j < numcustsurfaceflags; j++)
                Mem_Free(custsurfaceparmnames[j]);
 }
 
@@ -2437,8 +2478,8 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool
        texture->specularscalemod = 1;
        texture->specularpowermod = 1; 
        texture->rtlightambient = 0;
-       // WHEN ADDING DEFAULTS HERE, REMEMBER TO SYNC TO SHADER LOADING ABOVE
-       // HERE, AND Q1BSP LOADING
+       texture->transparentsort = TRANSPARENTSORT_DISTANCE;
+       // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
        // JUST GREP FOR "specularscalemod = 1".
 
        if (shader)
@@ -2482,6 +2523,7 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool
                        texture->basematerialflags |= MATERIALFLAG_CAMERA;
                texture->customblendfunc[0] = GL_ONE;
                texture->customblendfunc[1] = GL_ZERO;
+               texture->transparentsort = shader->transparentsort;
                if (shader->numlayers > 0)
                {
                        texture->customblendfunc[0] = shader->layers[0].blendfunc[0];
@@ -2572,6 +2614,8 @@ nothing                GL_ZERO GL_ONE
                        texture->basematerialflags |= MATERIALFLAG_NOSHADOW;
                if (shader->dpnortlight)
                        texture->basematerialflags |= MATERIALFLAG_NORTLIGHT;
+               if (shader->vertexalpha)
+                       texture->basematerialflags |= MATERIALFLAG_ALPHAGEN_VERTEX;
                memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms));
                texture->reflectmin = shader->reflectmin;
                texture->reflectmax = shader->reflectmax;
@@ -2633,7 +2677,7 @@ nothing                GL_ZERO GL_ONE
        //      if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID    ) texture->supercontents |= SUPERCONTENTS_LIGHTGRID    ;
        //      if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL   ) texture->supercontents |= SUPERCONTENTS_ANTIPORTAL   ;
 
-               texture->surfaceflags = 0;
+               texture->surfaceflags = shader->surfaceflags;
                if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW  ) texture->surfaceflags |= Q3SURFACEFLAG_ALPHASHADOW  ;
        //      if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL   ) texture->surfaceflags |= Q3SURFACEFLAG_AREAPORTAL   ;
        //      if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->surfaceflags |= Q3SURFACEFLAG_CLUSTERPORTAL;
@@ -2991,6 +3035,10 @@ void Mod_BuildVBOs(void)
                        Vector2Copy(loadmodel->surfmesh.data_texcoordtexture2f + 2*vertexindex, vertexmesh->texcoordtexture2f);
                        if (loadmodel->surfmesh.data_texcoordlightmap2f)
                                Vector2Scale(loadmodel->surfmesh.data_texcoordlightmap2f + 2*vertexindex, 1.0f, vertexmesh->texcoordlightmap2f);
+                       if (loadmodel->surfmesh.data_skeletalindex4ub)
+                               Vector4Copy(loadmodel->surfmesh.data_skeletalindex4ub + 4*vertexindex, vertexmesh->skeletalindex4ub);
+                       if (loadmodel->surfmesh.data_skeletalweight4ub)
+                               Vector4Copy(loadmodel->surfmesh.data_skeletalweight4ub + 4*vertexindex, vertexmesh->skeletalweight4ub);
                }
        }
 
@@ -3028,6 +3076,8 @@ void Mod_BuildVBOs(void)
                loadmodel->surfmesh.vbooffset_texcoordtexture2f  = size;if (loadmodel->surfmesh.data_texcoordtexture2f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
                loadmodel->surfmesh.vbooffset_texcoordlightmap2f = size;if (loadmodel->surfmesh.data_texcoordlightmap2f) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
                loadmodel->surfmesh.vbooffset_lightmapcolor4f    = size;if (loadmodel->surfmesh.data_lightmapcolor4f   ) size += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
+               loadmodel->surfmesh.vbooffset_skeletalindex4ub   = size;if (loadmodel->surfmesh.data_skeletalindex4ub  ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
+               loadmodel->surfmesh.vbooffset_skeletalweight4ub  = size;if (loadmodel->surfmesh.data_skeletalweight4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
                mem = (unsigned char *)Mem_Alloc(tempmempool, size);
                if (loadmodel->surfmesh.data_vertex3f          ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertex3f          , loadmodel->surfmesh.data_vertex3f          , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
                if (loadmodel->surfmesh.data_svector3f         ) memcpy(mem + loadmodel->surfmesh.vbooffset_svector3f         , loadmodel->surfmesh.data_svector3f         , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
@@ -3036,11 +3086,14 @@ void Mod_BuildVBOs(void)
                if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordtexture2f , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2]));
                if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordlightmap2f, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2]));
                if (loadmodel->surfmesh.data_lightmapcolor4f   ) memcpy(mem + loadmodel->surfmesh.vbooffset_lightmapcolor4f   , loadmodel->surfmesh.data_lightmapcolor4f   , loadmodel->surfmesh.num_vertices * sizeof(float[4]));
+               if (loadmodel->surfmesh.data_skeletalindex4ub  ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalindex4ub  , loadmodel->surfmesh.data_skeletalindex4ub  , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
+               if (loadmodel->surfmesh.data_skeletalweight4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalweight4ub , loadmodel->surfmesh.data_skeletalweight4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
                loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false);
                Mem_Free(mem);
        }
 }
 
+extern cvar_t mod_obj_orientation;
 static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename)
 {
        int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0;
@@ -3108,7 +3161,10 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha
                        memcpy(outbuffer, oldbuffer, outbufferpos);
                        Z_Free(oldbuffer);
                }
-               l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[2], v[1], vn[0], vn[2], vn[1], vt[0], 1-vt[1]);
+               if(mod_obj_orientation.integer)
+                       l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[2], v[1], vn[0], vn[2], vn[1], vt[0], 1-vt[1]);
+               else
+                       l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1-vt[1]);
                if (l > 0)
                        outbufferpos += l;
        }
@@ -3138,7 +3194,10 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha
                                a = e[0]+1;
                                b = e[1]+1;
                                c = e[2]+1;
-                               l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,b,b,b,c,c,c);
+                               if(mod_obj_orientation.integer)
+                                       l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,b,b,b,c,c,c);
+                               else
+                                       l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,c,c,c,b,b,b);
                                if (l > 0)
                                        outbufferpos += l;
                        }
@@ -3213,7 +3272,7 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
 
                        // strangely the smd angles are for a transposed matrix, so we
                        // have to generate a transposed matrix, then convert that...
-                       Matrix4x4_FromBonePose6s(&posematrix, model->num_posescale, model->data_poses6s + 6*(model->num_bones * poseindex + transformindex));
+                       Matrix4x4_FromBonePose7s(&posematrix, model->num_posescale, model->data_poses7s + 7*(model->num_bones * poseindex + transformindex));
                        Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]);
                        AnglesFromVectors(angles, mtest[0], mtest[2], false);
                        if (angles[0] >= 180) angles[0] -= 360;
@@ -3348,6 +3407,11 @@ static void Mod_Decompile_f(void)
        FS_StripExtension(inname, basename, sizeof(basename));
 
        mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL);
+       if (!mod)
+       {
+               Con_Print("No such model\n");
+               return;
+       }
        if (mod->brush.submodel)
        {
                // if we're decompiling a submodel, be sure to give it a proper name based on its parent
@@ -3355,11 +3419,6 @@ static void Mod_Decompile_f(void)
                dpsnprintf(basename, sizeof(basename), "%s/%s", outname, mod->name);
                outname[0] = 0;
        }
-       if (!mod)
-       {
-               Con_Print("No such model\n");
-               return;
-       }
        if (!mod->surfmesh.num_triangles)
        {
                Con_Print("Empty model (or sprite)\n");
@@ -4356,7 +4415,6 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
        for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
        {
                surface = model->data_surfaces + surfaceindex;
-               e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
                if (!surface->num_triangles)
                        continue;
                lightmapindex = mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle].lightmapindex;