]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_alias.c
removed OffscreenGecko support because it is not maintained
[xonotic/darkplaces.git] / model_alias.c
index 214c960d6a606600ebb53162d0387fdab1ebbcf9..f1bdb3a98d570bb6ca162b5066465cbb25d0b1d1 100644 (file)
@@ -40,29 +40,42 @@ cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "suppor
 
 float mod_md3_sin[320];
 
-static size_t Mod_Skeltal_AnimateVertices_maxbonepose = 0;
-static void *Mod_Skeltal_AnimateVertices_bonepose = NULL;
+static size_t Mod_Skeletal_AnimateVertices_maxbonepose = 0;
+static void *Mod_Skeletal_AnimateVertices_bonepose = NULL;
 void Mod_Skeletal_FreeBuffers(void)
 {
-       if(Mod_Skeltal_AnimateVertices_bonepose)
-               Mem_Free(Mod_Skeltal_AnimateVertices_bonepose);
-       Mod_Skeltal_AnimateVertices_maxbonepose = 0;
-       Mod_Skeltal_AnimateVertices_bonepose = NULL;
+       if(Mod_Skeletal_AnimateVertices_bonepose)
+               Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
+       Mod_Skeletal_AnimateVertices_maxbonepose = 0;
+       Mod_Skeletal_AnimateVertices_bonepose = NULL;
 }
 void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes)
 {
-       if(Mod_Skeltal_AnimateVertices_maxbonepose < nbytes)
+       if(Mod_Skeletal_AnimateVertices_maxbonepose < nbytes)
        {
-               if(Mod_Skeltal_AnimateVertices_bonepose)
-                       Mem_Free(Mod_Skeltal_AnimateVertices_bonepose);
-               Mod_Skeltal_AnimateVertices_bonepose = Z_Malloc(nbytes);
-               Mod_Skeltal_AnimateVertices_maxbonepose = nbytes;
+               if(Mod_Skeletal_AnimateVertices_bonepose)
+                       Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
+               Mod_Skeletal_AnimateVertices_bonepose = Z_Malloc(nbytes);
+               Mod_Skeletal_AnimateVertices_maxbonepose = nbytes;
        }
-       return Mod_Skeltal_AnimateVertices_bonepose;
+       return Mod_Skeletal_AnimateVertices_bonepose;
 }
 
 void Mod_Skeletal_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
 {
+
+       if (!model->surfmesh.num_vertices)
+               return;
+
+       if (!model->num_bones)
+       {
+               if (vertex3f) memcpy(vertex3f, model->surfmesh.data_vertex3f, model->surfmesh.num_vertices*sizeof(float[3]));
+               if (normal3f) memcpy(normal3f, model->surfmesh.data_normal3f, model->surfmesh.num_vertices*sizeof(float[3]));
+               if (svector3f) memcpy(svector3f, model->surfmesh.data_svector3f, model->surfmesh.num_vertices*sizeof(float[3]));
+               if (tvector3f) memcpy(tvector3f, model->surfmesh.data_tvector3f, model->surfmesh.num_vertices*sizeof(float[3]));
+               return;
+       }
+
 #ifdef SSE_POSSIBLE
        if(r_skeletal_use_sse_defined)
                if(r_skeletal_use_sse.integer)
@@ -516,19 +529,51 @@ static void Mod_Alias_CalculateBoundingBox(void)
        qboolean firstvertex = true;
        float dist, yawradius, radius;
        float *v;
-       float *vertex3f;
-       frameblend_t frameblend[MAX_FRAMEBLENDS];
-       memset(frameblend, 0, sizeof(frameblend));
-       frameblend[0].lerp = 1;
-       vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
        VectorClear(loadmodel->normalmins);
        VectorClear(loadmodel->normalmaxs);
        yawradius = 0;
        radius = 0;
-       for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
+       if (loadmodel->AnimateVertices)
+       {
+               float *vertex3f;
+               frameblend_t frameblend[MAX_FRAMEBLENDS];
+               memset(frameblend, 0, sizeof(frameblend));
+               frameblend[0].lerp = 1;
+               vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
+               for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
+               {
+                       loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
+                       for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
+                       {
+                               if (firstvertex)
+                               {
+                                       firstvertex = false;
+                                       VectorCopy(v, loadmodel->normalmins);
+                                       VectorCopy(v, loadmodel->normalmaxs);
+                               }
+                               else
+                               {
+                                       if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
+                                       if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
+                                       if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
+                                       if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
+                                       if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
+                                       if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
+                               }
+                               dist = v[0] * v[0] + v[1] * v[1];
+                               if (yawradius < dist)
+                                       yawradius = dist;
+                               dist += v[2] * v[2];
+                               if (radius < dist)
+                                       radius = dist;
+                       }
+               }
+               if (vertex3f)
+                       Mem_Free(vertex3f);
+       }
+       else
        {
-               loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
-               for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
+               for (vnum = 0, v = loadmodel->surfmesh.data_vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
                {
                        if (firstvertex)
                        {
@@ -553,8 +598,6 @@ static void Mod_Alias_CalculateBoundingBox(void)
                                radius = dist;
                }
        }
-       if (vertex3f)
-               Mem_Free(vertex3f);
        radius = sqrt(radius);
        yawradius = sqrt(yawradius);
        loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
@@ -787,6 +830,7 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *ski
        texture->currentmaterialflags = texture->basematerialflags;
        texture->offsetmapping = OFFSETMAPPING_DEFAULT;
        texture->offsetscale = 1;
+       texture->offsetbias = 0;
        texture->specularscalemod = 1;
        texture->specularpowermod = 1;
        texture->surfaceflags = 0;
@@ -877,7 +921,6 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->modeldatatypestring = "MDL";
 
        loadmodel->type = mod_alias;
-       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -1058,10 +1101,13 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
                loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
        }
        Mod_MDL_LoadFrames (startframes, numverts, vertremap);
+       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
+       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; // needed during loading, may be cleared by code later in this function
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
        Mod_Alias_CalculateBoundingBox();
        Mod_Alias_MorphMesh_CompileFrames();
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
 
        Mem_Free(vertst);
        Mem_Free(vertremap);
@@ -1180,7 +1226,8 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
        surface->num_firstvertex = 0;
        surface->num_vertices = loadmodel->surfmesh.num_vertices;
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
+       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
 
        if (!loadmodel->surfmesh.isanimated)
        {
@@ -1191,6 +1238,15 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
                loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
                loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
        }
+
+       // because shaders can do somewhat unexpected things, check for unusual features now
+       for (i = 0;i < loadmodel->num_textures;i++)
+       {
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
+                       mod->DrawSky = R_Q1BSP_DrawSky;
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
+                       mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
+       }
 }
 
 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
@@ -1225,7 +1281,6 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->modeldatatypestring = "MD2";
 
        loadmodel->type = mod_alias;
-       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -1430,10 +1485,13 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
 
        Mem_Free(vertremap);
 
+       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
+       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; // needed during loading, may be cleared by code later in this function
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
        Mod_Alias_CalculateBoundingBox();
        Mod_Alias_MorphMesh_CompileFrames();
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
 
        surface = loadmodel->data_surfaces;
        surface->texture = loadmodel->data_textures;
@@ -1442,8 +1500,6 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
        surface->num_firstvertex = 0;
        surface->num_vertices = loadmodel->surfmesh.num_vertices;
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
-
        if (!loadmodel->surfmesh.isanimated)
        {
                Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
@@ -1453,6 +1509,15 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
                loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
                loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
        }
+
+       // because shaders can do somewhat unexpected things, check for unusual features now
+       for (i = 0;i < loadmodel->num_textures;i++)
+       {
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
+                       mod->DrawSky = R_Q1BSP_DrawSky;
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
+                       mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
+       }
 }
 
 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
@@ -1482,7 +1547,6 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->modeldatatypestring = "MD3";
 
        loadmodel->type = mod_alias;
-       loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -1621,15 +1685,15 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
        if (loadmodel->surfmesh.data_element3s)
                for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
                        loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
+       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
+       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; // needed during loading, may be cleared by code later in this function
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
        Mod_Alias_MorphMesh_CompileFrames();
        Mod_Alias_CalculateBoundingBox();
        Mod_FreeSkinFiles(skinfiles);
        Mod_MakeSortedSurfaces(loadmodel);
-
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1
-            || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
 
        if (!loadmodel->surfmesh.isanimated)
        {
@@ -1640,6 +1704,15 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
                loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
                loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
        }
+
+       // because shaders can do somewhat unexpected things, check for unusual features now
+       for (i = 0;i < loadmodel->num_textures;i++)
+       {
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
+                       mod->DrawSky = R_Q1BSP_DrawSky;
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
+                       mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
+       }
 }
 
 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
@@ -1714,7 +1787,6 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                return;
        }
 
-       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -1817,6 +1889,8 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        meshvertices = pheader->numverts;
        meshtriangles = pheader->numtris;
 
+       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
        loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
@@ -2008,8 +2082,6 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
-
        if (!loadmodel->surfmesh.isanimated)
        {
                Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
@@ -2019,6 +2091,15 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
                loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
        }
+
+       // because shaders can do somewhat unexpected things, check for unusual features now
+       for (i = 0;i < loadmodel->num_textures;i++)
+       {
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
+                       mod->DrawSky = R_Q1BSP_DrawSky;
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
+                       mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
+       }
 }
 
 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
@@ -2077,7 +2158,6 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                return;
        }
 
-       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -2130,6 +2210,8 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
        loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
+       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
        // do most allocations as one merged chunk
        data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short)) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
        loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
@@ -2365,8 +2447,6 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
-
        if (!loadmodel->surfmesh.isanimated)
        {
                Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
@@ -2376,6 +2456,15 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
                loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
        }
+
+       // because shaders can do somewhat unexpected things, check for unusual features now
+       for (i = 0;i < loadmodel->num_textures;i++)
+       {
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
+                       mod->DrawSky = R_Q1BSP_DrawSky;
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
+                       mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
+       }
 }
 
 // no idea why PSK/PSA files contain weird quaternions but they do...
@@ -2409,7 +2498,6 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->modeldatatypestring = "PSK";
 
        loadmodel->type = mod_alias;
-       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -2773,6 +2861,8 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
        loadmodel->surfmesh.num_vertices = meshvertices;
        loadmodel->surfmesh.num_triangles = meshtriangles;
+       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
        // do most allocations as one merged chunk
        size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0)  + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0);
        data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
@@ -2953,8 +3043,6 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
        Mod_Alias_CalculateBoundingBox();
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
-
        if (!loadmodel->surfmesh.isanimated)
        {
                Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
@@ -2964,6 +3052,15 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
                loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
        }
+
+       // because shaders can do somewhat unexpected things, check for unusual features now
+       for (i = 0;i < loadmodel->num_textures;i++)
+       {
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
+                       mod->DrawSky = R_Q1BSP_DrawSky;
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
+                       mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
+       }
 }
 
 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
@@ -2979,14 +3076,16 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        int *outelements;
        const int *inneighbors;
        int *outneighbors;
-       float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector;
+       float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
        // this pointers into the file data are read only through Little* functions so they can be unaligned memory
        const float *vnormal = NULL;
        const float *vposition = NULL;
        const float *vtangent = NULL;
        const float *vtexcoord = NULL;
+       const float *vcolor4f = NULL;
        const unsigned char *vblendindexes = NULL;
        const unsigned char *vblendweights = NULL;
+       const unsigned char *vcolor4ub = NULL;
        const unsigned short *framedata = NULL;
        // temporary memory allocations (because the data in the file may be misaligned)
        iqmanim_t *anims = NULL;
@@ -3047,12 +3146,6 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        header.num_extensions = LittleLong(header.num_extensions);
        header.ofs_extensions = LittleLong(header.ofs_extensions);
 
-       if (header.num_triangles < 1 || header.num_vertexes < 3 || header.num_vertexarrays < 1 || header.num_meshes < 1)
-       {
-               Con_Printf("%s has no geometry\n", loadmodel->name);
-               return;
-       }
-
        if (header.version == 1)
        {
                if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
@@ -3140,6 +3233,12 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        if (va.format == IQM_UBYTE && va.size == 4)
                                vblendweights = (const unsigned char *)(pbase + va.offset);
                        break;
+               case IQM_COLOR:
+                       if (va.format == IQM_FLOAT && va.size == 4)
+                               vcolor4f = (const float *)(pbase + va.offset);
+                       if (va.format == IQM_UBYTE && va.size == 4)
+                               vcolor4ub = (const unsigned char *)(pbase + va.offset);
+                       break;
                }
        }
        if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
@@ -3150,7 +3249,6 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
 
        text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
 
-       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -3177,12 +3275,14 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
        loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
+       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
 
        meshvertices = header.num_vertexes;
        meshtriangles = header.num_triangles;
 
        // do most allocations as one merged chunk
-       data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + meshvertices * sizeof(float[14]) + (vblendindexes && vblendweights ? meshvertices * sizeof(unsigned short) : 0) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
+       data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + meshvertices * (sizeof(float[14]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0)) + (vblendindexes && vblendweights ? meshvertices * sizeof(unsigned short) : 0) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
        loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
        loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
        loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
@@ -3198,6 +3298,10 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
        loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
        loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
+       if (vcolor4f || vcolor4ub)
+       {
+               loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
+       }
        loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
        loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
        loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
@@ -3604,6 +3708,35 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                }
        }
 
+       if (vcolor4f)
+       {
+               outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
+               // this unaligned memory access is safe (LittleFloat reads as bytes)
+               for (i = 0;i < (int)header.num_vertexes;i++)
+               {
+                       outcolor[0] = LittleFloat(vcolor4f[0]);
+                       outcolor[1] = LittleFloat(vcolor4f[1]);
+                       outcolor[2] = LittleFloat(vcolor4f[2]);
+                       outcolor[3] = LittleFloat(vcolor4f[3]);
+                       vcolor4f += 4;
+                       outcolor += 4;
+               }
+       }
+       else if (vcolor4ub)
+       {
+               outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
+               // this unaligned memory access is safe (all bytes)
+               for (i = 0;i < (int)header.num_vertexes;i++)
+               {
+                       outcolor[0] = vcolor4ub[0] * (1.0f / 128.0f);
+                       outcolor[1] = vcolor4ub[1] * (1.0f / 128.0f);
+                       outcolor[2] = vcolor4ub[2] * (1.0f / 128.0f);
+                       outcolor[3] = vcolor4ub[3] * (1.0f / 128.0f);
+                       vcolor4ub += 4;
+                       outcolor += 4;
+               }
+       }
+
        // load meshes
        for (i = 0;i < (int)header.num_meshes;i++)
        {
@@ -3644,9 +3777,7 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        if (!header.ofs_bounds)
                Mod_Alias_CalculateBoundingBox();
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
-
-       if (!loadmodel->surfmesh.isanimated)
+       if (!loadmodel->surfmesh.isanimated && loadmodel->surfmesh.num_triangles >= 1)
        {
                Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
                loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
@@ -3660,4 +3791,13 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        if (joint1       ) Mem_Free(joint1       );joint1        = NULL;
        if (pose         ) Mem_Free(pose         );pose          = NULL;
        if (pose1        ) Mem_Free(pose1        );pose1         = NULL;
+
+       // because shaders can do somewhat unexpected things, check for unusual features now
+       for (i = 0;i < loadmodel->num_textures;i++)
+       {
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
+                       mod->DrawSky = R_Q1BSP_DrawSky;
+               if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
+                       mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
+       }
 }