]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_shared.c
S_GetEntChallelPosition -> S_GetEntChannelPosition
[xonotic/darkplaces.git] / model_shared.c
index b9b140e02444c82426a33435d198955bc2cc190e..38fc917269a14b26d5db03ced6fc276fd475a515 100644 (file)
@@ -92,6 +92,7 @@ static void mod_shutdown(void)
                        Mod_UnloadModel(mod);
 
        Mod_FreeQ3Shaders();
+       Mod_Skeletal_FreeBuffers();
 }
 
 static void mod_newmap(void)
@@ -148,7 +149,6 @@ Mod_Init
 static void Mod_Print(void);
 static void Mod_Precache (void);
 static void Mod_Decompile_f(void);
-static void Mod_BuildVBOs(void);
 static void Mod_GenerateLightmaps_f(void);
 void Mod_Init (void)
 {
@@ -283,7 +283,7 @@ void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, fl
 {
        dp_model_t *mod = (dp_model_t *) pass;
        animscene_t *anim = &mod->animscenes[i];
-       dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d", i);
+       dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d_anim", i);
        anim->firstframe = bound(0, start, mod->num_poses - 1);
        anim->framecount = bound(1, len, mod->num_poses - anim->firstframe);
        anim->framerate = max(1, fps);
@@ -312,6 +312,31 @@ void Mod_FrameGroupify(dp_model_t *mod, const char *buf)
        Mod_FrameGroupify_ParseGroups(buf, Mod_FrameGroupify_ParseGroups_Store, mod);
 }
 
+void Mod_FindPotentialDeforms(dp_model_t *mod)
+{
+       int i, j;
+       texture_t *texture;
+       mod->wantnormals = false;
+       mod->wanttangents = false;
+       for (i = 0;i < mod->num_textures;i++)
+       {
+               texture = mod->data_textures + i;
+               if (texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
+                       mod->wantnormals = true;
+               for (j = 0;j < Q3MAXDEFORMS;j++)
+               {
+                       if (texture->deforms[j].deform == Q3DEFORM_AUTOSPRITE)
+                       {
+                               mod->wanttangents = true;
+                               mod->wantnormals = true;
+                               break;
+                       }
+                       if (texture->deforms[j].deform != Q3DEFORM_NONE)
+                               mod->wantnormals = true;
+               }
+       }
+}
+
 /*
 ==================
 Mod_LoadModel
@@ -433,7 +458,7 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
                num = LittleLong(*((int *)buf));
                // call the apropriate loader
                loadmodel = mod;
-                    if (!strcasecmp(FS_FileExtension(mod->name), "obj")) Mod_OBJ_Load(mod, buf, bufend);
+               if (!strcasecmp(FS_FileExtension(mod->name), "obj")) Mod_OBJ_Load(mod, buf, bufend);
                else if (!memcmp(buf, "IDPO", 4)) Mod_IDP0_Load(mod, buf, bufend);
                else if (!memcmp(buf, "IDP2", 4)) Mod_IDP2_Load(mod, buf, bufend);
                else if (!memcmp(buf, "IDP3", 4)) Mod_IDP3_Load(mod, buf, bufend);
@@ -443,11 +468,14 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
                else if (!memcmp(buf, "ZYMOTICMODEL", 12)) Mod_ZYMOTICMODEL_Load(mod, buf, bufend);
                else if (!memcmp(buf, "DARKPLACESMODEL", 16)) Mod_DARKPLACESMODEL_Load(mod, buf, bufend);
                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 Con_Printf("Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name);
                Mem_Free(buf);
 
+               Mod_FindPotentialDeforms(mod);
+                                       
                buf = FS_LoadFile (va("%s.framegroups", mod->name), tempmempool, false, &filesize);
                if(buf)
                {
@@ -655,12 +683,13 @@ void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtria
                int element[2];
        }
        edgehashentry_t;
-       edgehashentry_t *edgehash[TRIANGLEEDGEHASH], *edgehashentries, edgehashentriesbuffer[TRIANGLEEDGEHASH*3], *hash;
-       memset(edgehash, 0, sizeof(edgehash));
-       edgehashentries = edgehashentriesbuffer;
+       static edgehashentry_t **edgehash;
+       edgehashentry_t *edgehashentries, *hash;
+       if (!numtriangles)
+               return;
+       edgehash = Mem_Alloc(tempmempool, TRIANGLEEDGEHASH * sizeof(*edgehash));
        // if there are too many triangles for the stack array, allocate larger buffer
-       if (numtriangles > TRIANGLEEDGEHASH)
-               edgehashentries = (edgehashentry_t *)Mem_Alloc(tempmempool, numtriangles * 3 * sizeof(edgehashentry_t));
+       edgehashentries = (edgehashentry_t *)Mem_Alloc(tempmempool, numtriangles * 3 * sizeof(edgehashentry_t));
        // find neighboring triangles
        for (i = 0, e = elements, n = neighbors;i < numtriangles;i++, e += 3, n += 3)
        {
@@ -709,8 +738,8 @@ void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtria
                CL_KeepaliveMessage(false);
        }
        // free the allocated buffer
-       if (edgehashentries != edgehashentriesbuffer)
-               Mem_Free(edgehashentries);
+       Mem_Free(edgehashentries);
+       Mem_Free(edgehash);
 }
 #else
 // very slow but simple way
@@ -1148,6 +1177,8 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh)
 {
        if (!vid.support.arb_vertex_buffer_object)
                return;
+       if (mesh->vbo)
+               return;
 
        // element buffer is easy because it's just one array
        if (mesh->numtriangles)
@@ -1482,7 +1513,7 @@ static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
                        end = ((unsigned char *) (&shader->Q3SHADERINFO_COMPARE_END)) + sizeof(shader->Q3SHADERINFO_COMPARE_END);
                        start2 = (unsigned char *) (&entry->shader.Q3SHADERINFO_COMPARE_START);
                        if(memcmp(start, start2, end - start))
-                               Con_Printf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name);
+                               Con_DPrintf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name);
                        else
                                Con_DPrintf("Shader '%s' already defined\n", shader->name);
                        return;
@@ -1510,6 +1541,7 @@ static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
 }
 
 extern cvar_t r_picmipworld;
+extern cvar_t mod_q3shader_default_offsetmapping;
 void Mod_LoadQ3Shaders(void)
 {
        int j;
@@ -1550,13 +1582,15 @@ void Mod_LoadQ3Shaders(void)
                        shader.reflectfactor = 1;
                        Vector4Set(shader.reflectcolor4f, 1, 1, 1, 1);
                        shader.r_water_wateralpha = 1;
+                       shader.offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
+                       shader.offsetscale = 1;
                        shader.specularscalemod = 1;
                        shader.specularpowermod = 1;
 
                        strlcpy(shader.name, com_token, sizeof(shader.name));
                        if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
                        {
-                               Con_Printf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
+                               Con_DPrintf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
                                break;
                        }
                        while (COM_ParseToken_QuakeC(&text, false))
@@ -1592,7 +1626,11 @@ void Mod_LoadQ3Shaders(void)
                                                {
                                                        if (j < TEXTURE_MAXFRAMES + 4)
                                                        {
-                                                               strlcpy(parameter[j], com_token, sizeof(parameter[j]));
+                                                               // remap dp_water to dpwater, dp_reflect to dpreflect, etc.
+                                                               if(j == 0 && !strncasecmp(com_token, "dp_", 3))
+                                                                       dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
+                                                               else
+                                                                       strlcpy(parameter[j], com_token, sizeof(parameter[j]));
                                                                numparameters = j + 1;
                                                        }
                                                        if (!COM_ParseToken_QuakeC(&text, true))
@@ -1600,12 +1638,12 @@ void Mod_LoadQ3Shaders(void)
                                                }
                                                //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
                                                //      parameter[j][0] = 0;
-                                               if (developer.integer >= 100)
+                                               if (developer_insane.integer)
                                                {
-                                                       Con_Printf("%s %i: ", shader.name, shader.numlayers - 1);
+                                                       Con_DPrintf("%s %i: ", shader.name, shader.numlayers - 1);
                                                        for (j = 0;j < numparameters;j++)
-                                                               Con_Printf(" %s", parameter[j]);
-                                                       Con_Print("\n");
+                                                               Con_DPrintf(" %s", parameter[j]);
+                                                       Con_DPrint("\n");
                                                }
                                                if (numparameters >= 2 && !strcasecmp(parameter[0], "blendfunc"))
                                                {
@@ -1797,7 +1835,7 @@ void Mod_LoadQ3Shaders(void)
                                                        shader.textureblendalpha = true;
                                                }
                                        }
-                                       layer->texflags = TEXF_ALPHA | TEXF_PRECACHE;
+                                       layer->texflags = TEXF_ALPHA;
                                        if (!(shader.surfaceparms & Q3SURFACEPARM_NOMIPMAPS))
                                                layer->texflags |= TEXF_MIPMAP;
                                        if (!(shader.textureflags & Q3TEXTUREFLAG_NOPICMIP))
@@ -1811,7 +1849,11 @@ void Mod_LoadQ3Shaders(void)
                                {
                                        if (j < TEXTURE_MAXFRAMES + 4)
                                        {
-                                               strlcpy(parameter[j], com_token, sizeof(parameter[j]));
+                                               // remap dp_water to dpwater, dp_reflect to dpreflect, etc.
+                                               if(j == 0 && !strncasecmp(com_token, "dp_", 3))
+                                                       dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
+                                               else
+                                                       strlcpy(parameter[j], com_token, sizeof(parameter[j]));
                                                numparameters = j + 1;
                                        }
                                        if (!COM_ParseToken_QuakeC(&text, true))
@@ -1821,12 +1863,12 @@ void Mod_LoadQ3Shaders(void)
                                //      parameter[j][0] = 0;
                                if (fileindex == 0 && !strcasecmp(com_token, "}"))
                                        break;
-                               if (developer.integer >= 100)
+                               if (developer_insane.integer)
                                {
-                                       Con_Printf("%s: ", shader.name);
+                                       Con_DPrintf("%s: ", shader.name);
                                        for (j = 0;j < numparameters;j++)
-                                               Con_Printf(" %s", parameter[j]);
-                                       Con_Print("\n");
+                                               Con_DPrintf(" %s", parameter[j]);
+                                       Con_DPrint("\n");
                                }
                                if (numparameters < 1)
                                        continue;
@@ -1903,6 +1945,10 @@ void Mod_LoadQ3Shaders(void)
                                        shader.dpshadow = true;
                                else if (!strcasecmp(parameter[0], "dpnoshadow"))
                                        shader.dpnoshadow = true;
+                               else if (!strcasecmp(parameter[0], "dpreflectcube"))
+                                       strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube));
+                               else if (!strcasecmp(parameter[0], "dpmeshcollisions"))
+                                       shader.dpmeshcollisions = true;
                                else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
                                {
                                        // some q3 skies don't have the sky parm set
@@ -1927,19 +1973,23 @@ void Mod_LoadQ3Shaders(void)
                                        shader.textureflags |= Q3TEXTUREFLAG_NOPICMIP;
                                else if (!strcasecmp(parameter[0], "polygonoffset"))
                                        shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET;
-                               else if (!strcasecmp(parameter[0], "dp_refract") && numparameters >= 5)
+                               else if (!strcasecmp(parameter[0], "dprefract") && numparameters >= 5)
                                {
                                        shader.textureflags |= Q3TEXTUREFLAG_REFRACTION;
                                        shader.refractfactor = atof(parameter[1]);
                                        Vector4Set(shader.refractcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), 1);
                                }
-                               else if (!strcasecmp(parameter[0], "dp_reflect") && numparameters >= 6)
+                               else if (!strcasecmp(parameter[0], "dpreflect") && numparameters >= 6)
                                {
                                        shader.textureflags |= Q3TEXTUREFLAG_REFLECTION;
                                        shader.reflectfactor = atof(parameter[1]);
                                        Vector4Set(shader.reflectcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), atof(parameter[5]));
                                }
-                               else if (!strcasecmp(parameter[0], "dp_water") && numparameters >= 12)
+                               else if (!strcasecmp(parameter[0], "dpcamera"))
+                               {
+                                       shader.textureflags |= Q3TEXTUREFLAG_CAMERA;
+                               }
+                               else if (!strcasecmp(parameter[0], "dpwater") && numparameters >= 12)
                                {
                                        shader.textureflags |= Q3TEXTUREFLAG_WATERSHADER;
                                        shader.reflectmin = atof(parameter[1]);
@@ -1950,14 +2000,26 @@ void Mod_LoadQ3Shaders(void)
                                        Vector4Set(shader.reflectcolor4f, atof(parameter[8]), atof(parameter[9]), atof(parameter[10]), 1);
                                        shader.r_water_wateralpha = atof(parameter[11]);
                                }
-                               else if (!strcasecmp(parameter[0], "dp_glossintensitymod") && numparameters >= 2)
+                               else if (!strcasecmp(parameter[0], "dpglossintensitymod") && numparameters >= 2)
                                {
                                        shader.specularscalemod = atof(parameter[1]);
                                }
-                               else if (!strcasecmp(parameter[0], "dp_glossexponentmod") && numparameters >= 2)
+                               else if (!strcasecmp(parameter[0], "dpglossexponentmod") && numparameters >= 2)
                                {
                                        shader.specularpowermod = atof(parameter[1]);
                                }
+                               else if (!strcasecmp(parameter[0], "dpoffsetmapping") && numparameters >= 3)
+                               {
+                                       if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "off"))
+                                               shader.offsetmapping = OFFSETMAPPING_OFF;
+                                       else if (!strcasecmp(parameter[1], "default"))
+                                               shader.offsetmapping = OFFSETMAPPING_DEFAULT;
+                                       else if (!strcasecmp(parameter[1], "linear"))
+                                               shader.offsetmapping = OFFSETMAPPING_LINEAR;
+                                       else if (!strcasecmp(parameter[1], "relief"))
+                                               shader.offsetmapping = OFFSETMAPPING_RELIEF;
+                                       shader.offsetscale = atof(parameter[2]);
+                               }
                                else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2)
                                {
                                        int i, deformindex;
@@ -2024,7 +2086,7 @@ void Mod_LoadQ3Shaders(void)
                        }
                        // fix up multiple reflection types
                        if(shader.textureflags & Q3TEXTUREFLAG_WATERSHADER)
-                               shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION);
+                               shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION | Q3TEXTUREFLAG_CAMERA);
 
                        Q3Shader_AddToHash (&shader);
                }
@@ -2066,8 +2128,11 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool
                texflagsmask &= ~TEXF_PICMIP;
        if(!(defaulttexflags & TEXF_COMPRESS))
                texflagsmask &= ~TEXF_COMPRESS;
-       texture->specularscalemod = 1; // unless later loaded from the shader
-       texture->specularpowermod = 1; // unless later loaded from the shader
+       // unless later loaded from the shader
+       texture->offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
+       texture->offsetscale = 1;
+       texture->specularscalemod = 1;
+       texture->specularpowermod = 1; 
        // WHEN ADDING DEFAULTS HERE, REMEMBER TO SYNC TO SHADER LOADING ABOVE
        // HERE, AND Q1BSP LOADING
        // JUST GREP FOR "specularscalemod = 1".
@@ -2107,6 +2172,8 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool
                        texture->basematerialflags |= MATERIALFLAG_REFLECTION;
                if (shader->textureflags & Q3TEXTUREFLAG_WATERSHADER)
                        texture->basematerialflags |= MATERIALFLAG_WATERSHADER;
+               if (shader->textureflags & Q3TEXTUREFLAG_CAMERA)
+                       texture->basematerialflags |= MATERIALFLAG_CAMERA;
                texture->customblendfunc[0] = GL_ONE;
                texture->customblendfunc[1] = GL_ZERO;
                if (shader->numlayers > 0)
@@ -2205,33 +2272,94 @@ nothing                GL_ZERO GL_ONE
                texture->reflectfactor = shader->reflectfactor;
                Vector4Copy(shader->reflectcolor4f, texture->reflectcolor4f);
                texture->r_water_wateralpha = shader->r_water_wateralpha;
+               texture->offsetmapping = shader->offsetmapping;
+               texture->offsetscale = shader->offsetscale;
                texture->specularscalemod = shader->specularscalemod;
                texture->specularpowermod = shader->specularpowermod;
+               if (shader->dpreflectcube[0])
+                       texture->reflectcubetexture = R_GetCubemap(shader->dpreflectcube);
+
+               // set up default supercontents (on q3bsp this is overridden by the q3bsp loader)
+               texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
+               if (shader->surfaceparms & Q3SURFACEPARM_LAVA         ) texture->supercontents  = SUPERCONTENTS_LAVA         ;
+               if (shader->surfaceparms & Q3SURFACEPARM_SLIME        ) texture->supercontents  = SUPERCONTENTS_SLIME        ;
+               if (shader->surfaceparms & Q3SURFACEPARM_WATER        ) texture->supercontents  = SUPERCONTENTS_WATER        ;
+               if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID     ) texture->supercontents  = 0                          ;
+               if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP   ) texture->supercontents  = SUPERCONTENTS_PLAYERCLIP   ;
+               if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP      ) texture->supercontents  = SUPERCONTENTS_MONSTERCLIP  ;
+               if (shader->surfaceparms & Q3SURFACEPARM_SKY          ) texture->supercontents  = SUPERCONTENTS_SKY          ;
+
+       //      if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW  ) texture->supercontents |= SUPERCONTENTS_ALPHASHADOW  ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL   ) texture->supercontents |= SUPERCONTENTS_AREAPORTAL   ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->supercontents |= SUPERCONTENTS_CLUSTERPORTAL;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_DETAIL       ) texture->supercontents |= SUPERCONTENTS_DETAIL       ;
+               if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER   ) texture->supercontents |= SUPERCONTENTS_DONOTENTER   ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_FOG          ) texture->supercontents |= SUPERCONTENTS_FOG          ;
+               if (shader->surfaceparms & Q3SURFACEPARM_LAVA         ) texture->supercontents |= SUPERCONTENTS_LAVA         ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER  ) texture->supercontents |= SUPERCONTENTS_LIGHTFILTER  ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS   ) texture->supercontents |= SUPERCONTENTS_METALSTEPS   ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE     ) texture->supercontents |= SUPERCONTENTS_NODAMAGE     ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT     ) texture->supercontents |= SUPERCONTENTS_NODLIGHT     ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_NODRAW       ) texture->supercontents |= SUPERCONTENTS_NODRAW       ;
+               if (shader->surfaceparms & Q3SURFACEPARM_NODROP       ) texture->supercontents |= SUPERCONTENTS_NODROP       ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT     ) texture->supercontents |= SUPERCONTENTS_NOIMPACT     ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP   ) texture->supercontents |= SUPERCONTENTS_NOLIGHTMAP   ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS      ) texture->supercontents |= SUPERCONTENTS_NOMARKS      ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS    ) texture->supercontents |= SUPERCONTENTS_NOMIPMAPS    ;
+               if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID     ) texture->supercontents &=~SUPERCONTENTS_SOLID        ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN       ) texture->supercontents |= SUPERCONTENTS_ORIGIN       ;
+               if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP   ) texture->supercontents |= SUPERCONTENTS_PLAYERCLIP   ;
+               if (shader->surfaceparms & Q3SURFACEPARM_SKY          ) texture->supercontents |= SUPERCONTENTS_SKY          ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_SLICK        ) texture->supercontents |= SUPERCONTENTS_SLICK        ;
+               if (shader->surfaceparms & Q3SURFACEPARM_SLIME        ) texture->supercontents |= SUPERCONTENTS_SLIME        ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL   ) texture->supercontents |= SUPERCONTENTS_STRUCTURAL   ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_TRANS        ) texture->supercontents |= SUPERCONTENTS_TRANS        ;
+               if (shader->surfaceparms & Q3SURFACEPARM_WATER        ) texture->supercontents |= SUPERCONTENTS_WATER        ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT   ) texture->supercontents |= SUPERCONTENTS_POINTLIGHT   ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_HINT         ) texture->supercontents |= SUPERCONTENTS_HINT         ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_DUST         ) texture->supercontents |= SUPERCONTENTS_DUST         ;
+               if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP      ) texture->supercontents |= SUPERCONTENTS_BOTCLIP      | SUPERCONTENTS_MONSTERCLIP;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID    ) texture->supercontents |= SUPERCONTENTS_LIGHTGRID    ;
+       //      if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL   ) texture->supercontents |= SUPERCONTENTS_ANTIPORTAL   ;
+
+               if (shader->dpmeshcollisions)
+                       texture->basematerialflags |= MATERIALFLAG_MESHCOLLISIONS;
        }
        else if (!strcmp(texture->name, "noshader") || !texture->name[0])
        {
-               if (developer.integer >= 100)
-                       Con_Printf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", loadmodel->name, name);
+               if (developer_extra.integer)
+                       Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", loadmodel->name, name);
                texture->surfaceparms = 0;
+               texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
        }
        else if (!strcmp(texture->name, "common/nodraw") || !strcmp(texture->name, "textures/common/nodraw"))
        {
-               if (developer.integer >= 100)
-                       Con_Printf("^1%s:^7 using fallback nodraw material for ^3\"%s\"\n", loadmodel->name, name);
+               if (developer_extra.integer)
+                       Con_DPrintf("^1%s:^7 using fallback nodraw material for ^3\"%s\"\n", loadmodel->name, name);
                texture->surfaceparms = 0;
                texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
+               texture->supercontents = SUPERCONTENTS_SOLID;
        }
        else
        {
-               if (developer.integer >= 100)
-                       Con_Printf("^1%s:^7 No shader found for texture ^3\"%s\"\n", loadmodel->name, texture->name);
+               if (developer_extra.integer)
+                       Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", loadmodel->name, texture->name);
                texture->surfaceparms = 0;
                if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW)
+               {
                        texture->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
+                       texture->supercontents = SUPERCONTENTS_SOLID;
+               }
                else if (texture->surfaceflags & Q3SURFACEFLAG_SKY)
+               {
                        texture->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
+                       texture->supercontents = SUPERCONTENTS_SKY;
+               }
                else
+               {
                        texture->basematerialflags |= MATERIALFLAG_WALL;
+                       texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
+               }
                texture->numskinframes = 1;
                if(cls.state == ca_dedicated)
                {
@@ -2480,9 +2608,9 @@ void Mod_MakeSortedSurfaces(dp_model_t *mod)
        Mem_Free(numsurfacesfortexture);
 }
 
-static void Mod_BuildVBOs(void)
+void Mod_BuildVBOs(void)
 {
-       if (developer.integer && loadmodel->surfmesh.data_element3s && loadmodel->surfmesh.data_element3i)
+       if (gl_paranoid.integer && loadmodel->surfmesh.data_element3s && loadmodel->surfmesh.data_element3i)
        {
                int i;
                for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
@@ -2497,6 +2625,9 @@ static void Mod_BuildVBOs(void)
 
        if (!vid.support.arb_vertex_buffer_object)
                return;
+       // only build a vbo if one has not already been created (this is important for brush models which load specially)
+       if (loadmodel->surfmesh.vbo)
+               return;
 
        // element buffer is easy because it's just one array
        if (loadmodel->surfmesh.num_triangles)
@@ -2649,9 +2780,7 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
        int transformindex;
        int poseindex;
        int cornerindex;
-       float modelscale;
        const int *e;
-       const float *pose;
        size_t l;
        size_t outbufferpos = 0;
        size_t outbuffermax = 0x100000;
@@ -2660,16 +2789,6 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
        l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "version 1\nnodes\n");
        if (l > 0)
                outbufferpos += l;
-       modelscale = 1;
-       if(model->num_poses >= 0)
-               modelscale = sqrt(model->data_poses[0] * model->data_poses[0] + model->data_poses[1] * model->data_poses[1] + model->data_poses[2] * model->data_poses[2]);
-       if(fabs(modelscale - 1) > 1e-4)
-       {
-               if(firstpose == 0) // only print the when writing the reference pose
-                       Con_Printf("The model has an old-style model scale of %f\n", modelscale);
-       }
-       else
-               modelscale = 1;
        for (transformindex = 0;transformindex < model->num_bones;transformindex++)
        {
                if (outbufferpos >= outbuffermax >> 1)
@@ -2688,17 +2807,17 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
        l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\nskeleton\n");
        if (l > 0)
                outbufferpos += l;
-       for (poseindex = 0, pose = model->data_poses + model->num_bones * 12 * firstpose;poseindex < numposes;poseindex++)
+       for (poseindex = 0;poseindex < numposes;poseindex++)
        {
                countframes++;
                l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "time %i\n", poseindex);
                if (l > 0)
                        outbufferpos += l;
-               for (transformindex = 0;transformindex < model->num_bones;transformindex++, pose += 12)
+               for (transformindex = 0;transformindex < model->num_bones;transformindex++)
                {
-                       float a, b, c;
                        float angles[3];
-                       float mtest[3][4];
+                       float mtest[4][3];
+                       matrix4x4_t posematrix;
                        if (outbufferpos >= outbuffermax >> 1)
                        {
                                outbuffermax *= 2;
@@ -2710,32 +2829,21 @@ 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...
-                       mtest[0][0] = pose[ 0];
-                       mtest[0][1] = pose[ 4];
-                       mtest[0][2] = pose[ 8];
-                       mtest[0][3] = pose[ 3];
-                       mtest[1][0] = pose[ 1];
-                       mtest[1][1] = pose[ 5];
-                       mtest[1][2] = pose[ 9];
-                       mtest[1][3] = pose[ 7];
-                       mtest[2][0] = pose[ 2];
-                       mtest[2][1] = pose[ 6];
-                       mtest[2][2] = pose[10];
-                       mtest[2][3] = pose[11];
+                       Matrix4x4_FromBonePose6s(&posematrix, model->num_posescale, model->data_poses6s + 6*(model->num_bones * poseindex + transformindex));
+                       Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]);
                        AnglesFromVectors(angles, mtest[0], mtest[2], false);
                        if (angles[0] >= 180) angles[0] -= 360;
                        if (angles[1] >= 180) angles[1] -= 360;
                        if (angles[2] >= 180) angles[2] -= 360;
 
-                       a = DEG2RAD(angles[ROLL]);
-                       b = DEG2RAD(angles[PITCH]);
-                       c = DEG2RAD(angles[YAW]);
-
 #if 0
 {
+                       float a = DEG2RAD(angles[ROLL]);
+                       float b = DEG2RAD(angles[PITCH]);
+                       float c = DEG2RAD(angles[YAW]);
                        float cy, sy, cp, sp, cr, sr;
-                       float test[3][4];
-                       // smd matrix construction, for comparing to non-transposed m
+                       float test[4][3];
+                       // smd matrix construction, for comparing
                        sy = sin(c);
                        cy = cos(c);
                        sp = sin(b);
@@ -2744,20 +2852,20 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
                        cr = cos(a);
 
                        test[0][0] = cp*cy;
-                       test[1][0] = cp*sy;
-                       test[2][0] = -sp;
-                       test[0][1] = sr*sp*cy+cr*-sy;
+                       test[0][1] = cp*sy;
+                       test[0][2] = -sp;
+                       test[1][0] = sr*sp*cy+cr*-sy;
                        test[1][1] = sr*sp*sy+cr*cy;
-                       test[2][1] = sr*cp;
-                       test[0][2] = (cr*sp*cy+-sr*-sy);
-                       test[1][2] = (cr*sp*sy+-sr*cy);
+                       test[1][2] = sr*cp;
+                       test[2][0] = (cr*sp*cy+-sr*-sy);
+                       test[2][1] = (cr*sp*sy+-sr*cy);
                        test[2][2] = cr*cp;
-                       test[0][3] = pose[3];
-                       test[1][3] = pose[7];
-                       test[2][3] = pose[11];
+                       test[3][0] = pose[9];
+                       test[3][1] = pose[10];
+                       test[3][2] = pose[11];
 }
 #endif
-                       l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f\n", transformindex, pose[3] * modelscale, pose[7] * modelscale, pose[11] * modelscale, DEG2RAD(angles[ROLL]), DEG2RAD(angles[PITCH]), DEG2RAD(angles[YAW]));
+                       l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f\n", transformindex, mtest[3][0], mtest[3][1], mtest[3][2], DEG2RAD(angles[ROLL]), DEG2RAD(angles[PITCH]), DEG2RAD(angles[YAW]));
                        if (l > 0)
                                outbufferpos += l;
                }
@@ -2792,12 +2900,19 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
                                        const float *v = model->surfmesh.data_vertex3f + index * 3;
                                        const float *vn = model->surfmesh.data_normal3f + index * 3;
                                        const float *vt = model->surfmesh.data_texcoordtexture2f + index * 2;
-                                       const int *wi = model->surfmesh.data_vertexweightindex4i + index * 4;
-                                       const float *wf = model->surfmesh.data_vertexweightinfluence4f + index * 4;
-                                            if (wf[3]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 4 %i %f %i %f %i %f %i %f\n", wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0], wi[1], wf[1], wi[2], wf[2], wi[3], wf[3]);
-                                       else if (wf[2]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 3 %i %f %i %f %i %f\n"      , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0], wi[1], wf[1], wi[2], wf[2]);
-                                       else if (wf[1]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 2 %i %f %i %f\n"            , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0], wi[1], wf[1]);
-                                       else            l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f\n"                          , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1]);
+                                       const int b = model->surfmesh.blends[index];
+                                       if (b < model->num_bones)
+                                               l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f\n"                          , b, v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1]);
+                                       else
+                                       {
+                                               const blendweights_t *w = model->surfmesh.data_blendweights + b - model->num_bones;
+                                               const unsigned char *wi = w->index;
+                                               const unsigned char *wf = w->influence;
+                                           if (wf[3]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 4 %i %f %i %f %i %f %i %f\n", wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0]/255.0f, wi[1], wf[1]/255.0f, wi[2], wf[2]/255.0f, wi[3], wf[3]/255.0f);
+                                               else if (wf[2]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 3 %i %f %i %f %i %f\n"      , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0]/255.0f, wi[1], wf[1]/255.0f, wi[2], wf[2]/255.0f);
+                                               else if (wf[1]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 2 %i %f %i %f\n"            , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0]/255.0f, wi[1], wf[1]/255.0f);
+                                               else            l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f\n"                          , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1]);
+                                       }
                                        if (l > 0)
                                                outbufferpos += l;
                                }
@@ -2833,8 +2948,10 @@ static void Mod_Decompile_f(void)
        char animname2[MAX_QPATH];
        char zymtextbuffer[16384];
        char dpmtextbuffer[16384];
+       char framegroupstextbuffer[16384];
        int zymtextsize = 0;
        int dpmtextsize = 0;
+       int framegroupstextsize = 0;
 
        if (Cmd_Argc() != 2)
        {
@@ -2896,16 +3013,20 @@ static void Mod_Decompile_f(void)
                                // individual frame
                                // check for additional frames with same name
                                for (l = 0, k = strlen(animname);animname[l];l++)
-                                       if ((animname[l] < '0' || animname[l] > '9') && animname[l] != '_')
+                                       if(animname[l] < '0' || animname[l] > '9')
                                                k = l + 1;
+                               if(k > 0 && animname[k-1] == '_')
+                                       --k;
                                animname[k] = 0;
                                count = mod->num_poses - first;
                                for (j = i + 1;j < mod->numframes;j++)
                                {
                                        strlcpy(animname2, mod->animscenes[j].name, sizeof(animname2));
                                        for (l = 0, k = strlen(animname2);animname2[l];l++)
-                                               if ((animname2[l] < '0' || animname2[l] > '9') && animname2[l] != '_')
+                                               if(animname2[l] < '0' || animname2[l] > '9')
                                                        k = l + 1;
+                                       if(k > 0 && animname[k-1] == '_')
+                                               --k;
                                        animname2[k] = 0;
                                        if (strcmp(animname2, animname) || mod->animscenes[j].framecount > 1)
                                        {
@@ -2922,19 +3043,26 @@ static void Mod_Decompile_f(void)
                        Mod_Decompile_SMD(mod, outname, first, count, false);
                        if (zymtextsize < (int)sizeof(zymtextbuffer) - 100)
                        {
-                               l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "scene %s.smd fps %g\n", animname, mod->animscenes[i].framerate);
+                               l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
                                if (l > 0) zymtextsize += l;
                        }
                        if (dpmtextsize < (int)sizeof(dpmtextbuffer) - 100)
                        {
-                               l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "scene %s.smd\n", animname);
+                               l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
                                if (l > 0) dpmtextsize += l;
                        }
+                       if (framegroupstextsize < (int)sizeof(framegroupstextbuffer) - 100)
+                       {
+                               l = dpsnprintf(framegroupstextbuffer + framegroupstextsize, sizeof(framegroupstextbuffer) - framegroupstextsize, "%d %d %f %d // %s\n", first, count, mod->animscenes[i].framerate, mod->animscenes[i].loop, animname);
+                               if (l > 0) framegroupstextsize += l;
+                       }
                }
                if (zymtextsize)
                        FS_WriteFile(va("%s_decompiled/out_zym.txt", basename), zymtextbuffer, (fs_offset_t)zymtextsize);
                if (dpmtextsize)
                        FS_WriteFile(va("%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize);
+               if (framegroupstextsize)
+                       FS_WriteFile(va("%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize);
        }
 }
 
@@ -3068,6 +3196,79 @@ static float mod_generatelightmaps_offsets[3][MAX_LIGHTMAPSAMPLES][3];
 static int mod_generatelightmaps_numlights;
 static lightmaplight_t *mod_generatelightmaps_lightinfo;
 
+extern int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color);
+extern cvar_t r_shadow_lightattenuationdividebias;
+extern cvar_t r_shadow_lightattenuationlinearscale;
+
+static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir)
+{
+       int i;
+       int index;
+       int result;
+       float relativepoint[3];
+       float color[3];
+       float dir[3];
+       float dist;
+       float dist2;
+       float intensity;
+       float sample[5*3];
+       float lightorigin[3];
+       float lightradius;
+       float lightradius2;
+       float lightiradius;
+       float lightcolor[3];
+       trace_t trace;
+       for (i = 0;i < 5*3;i++)
+               sample[i] = 0.0f;
+       for (index = 0;;index++)
+       {
+               result = R_Shadow_GetRTLightInfo(index, lightorigin, &lightradius, lightcolor);
+               if (result < 0)
+                       break;
+               if (result == 0)
+                       continue;
+               lightradius2 = lightradius * lightradius;
+               VectorSubtract(lightorigin, pos, relativepoint);
+               dist2 = VectorLength2(relativepoint);
+               if (dist2 >= lightradius2)
+                       continue;
+               lightiradius = 1.0f / lightradius;
+               dist = sqrt(dist2) * lightiradius;
+               intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
+               if (intensity <= 0)
+                       continue;
+               if (model && model->TraceLine)
+               {
+                       model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_VISBLOCKERMASK);
+                       if (trace.fraction < 1)
+                               continue;
+               }
+               // scale down intensity to add to both ambient and diffuse
+               //intensity *= 0.5f;
+               VectorNormalize(relativepoint);
+               VectorScale(lightcolor, intensity, color);
+               VectorMA(sample    , 0.5f            , color, sample    );
+               VectorMA(sample + 3, relativepoint[0], color, sample + 3);
+               VectorMA(sample + 6, relativepoint[1], color, sample + 6);
+               VectorMA(sample + 9, relativepoint[2], color, sample + 9);
+               // calculate a weighted average light direction as well
+               intensity *= VectorLength(color);
+               VectorMA(sample + 12, intensity, relativepoint, sample + 12);
+       }
+       // calculate the direction we'll use to reduce the sample to a directional light source
+       VectorCopy(sample + 12, dir);
+       //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
+       VectorNormalize(dir);
+       // extract the diffuse color along the chosen direction and scale it
+       diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
+       diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
+       diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
+       // subtract some of diffuse from ambient
+       VectorMA(sample, -0.333f, diffuse, ambient);
+       // store the normalized lightdir
+       VectorCopy(dir, lightdir);
+}
+
 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const dp_model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs)
 {
        int surfaceindex;
@@ -3076,12 +3277,12 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const
        const float *vertex3f = model->surfmesh.data_vertex3f;
        const int *element3i = model->surfmesh.data_element3i;
        const int *e;
-       double v2[3][3];
+       float v2[3][3];
        for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->nummodelsurfaces;surfaceindex++, surface++)
        {
                if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs))
                        continue;
-               if (R_GetCurrentTexture(surface->texture)->currentmaterialflags & MATERIALFLAG_NOSHADOW)
+               if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW)
                        continue;
                for (triangleindex = 0, e = element3i + 3*surface->num_firsttriangle;triangleindex < surface->num_triangles;triangleindex++, e += 3)
                {
@@ -3097,7 +3298,7 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, l
 {
        int maxnodes = 1<<14;
        svbsp_node_t *nodes;
-       double origin[3];
+       float origin[3];
        float mins[3];
        float maxs[3];
        svbsp_t svbsp;
@@ -3132,7 +3333,6 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, l
        Mem_Free(nodes);
 }
 
-extern int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color);
 static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model)
 {
        int index;
@@ -3199,8 +3399,6 @@ static qboolean Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, co
        return num == -1; // true if empty, false if solid (shadowed)
 }
 
-extern cvar_t r_shadow_lightattenuationdividebias;
-extern cvar_t r_shadow_lightattenuationlinearscale;
 static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *normal, float *sample, int numoffsets, const float *offsets)
 {
        int i;
@@ -3373,14 +3571,16 @@ static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model)
        if (model->brushq3.data_lightmaps)
        {
                for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
-                       R_FreeTexture(model->brushq3.data_lightmaps[i]);
+                       if (model->brushq3.data_lightmaps[i])
+                               R_FreeTexture(model->brushq3.data_lightmaps[i]);
                Mem_Free(model->brushq3.data_lightmaps);
                model->brushq3.data_lightmaps = NULL;
        }
        if (model->brushq3.data_deluxemaps)
        {
                for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
-                       R_FreeTexture(model->brushq3.data_deluxemaps[i]);
+                       if (model->brushq3.data_deluxemaps[i])
+                               R_FreeTexture(model->brushq3.data_deluxemaps[i]);
                Mem_Free(model->brushq3.data_deluxemaps);
                model->brushq3.data_deluxemaps = NULL;
        }
@@ -3454,12 +3654,20 @@ static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model)
                        model->surfmesh.data_tvector3f[outvertexindex*3+2] = oldsurfmesh.data_tvector3f[vertexindex*3+2];
                        model->surfmesh.data_texcoordtexture2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+0];
                        model->surfmesh.data_texcoordtexture2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+1];
-                       model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+0];
-                       model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+1];
-                       model->surfmesh.data_lightmapcolor4f[outvertexindex*4+0] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+0];
-                       model->surfmesh.data_lightmapcolor4f[outvertexindex*4+1] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+1];
-                       model->surfmesh.data_lightmapcolor4f[outvertexindex*4+2] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+2];
-                       model->surfmesh.data_lightmapcolor4f[outvertexindex*4+3] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+3];
+                       if (oldsurfmesh.data_texcoordlightmap2f)
+                       {
+                               model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+0];
+                               model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+1];
+                       }
+                       if (oldsurfmesh.data_lightmapcolor4f)
+                       {
+                               model->surfmesh.data_lightmapcolor4f[outvertexindex*4+0] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+0];
+                               model->surfmesh.data_lightmapcolor4f[outvertexindex*4+1] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+1];
+                               model->surfmesh.data_lightmapcolor4f[outvertexindex*4+2] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+2];
+                               model->surfmesh.data_lightmapcolor4f[outvertexindex*4+3] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+3];
+                       }
+                       else
+                               Vector4Set(model->surfmesh.data_lightmapcolor4f + 4*outvertexindex, 1, 1, 1, 1);
                        model->surfmesh.data_element3i[surface->num_firsttriangle*3+i] = outvertexindex;
                        outvertexindex++;
                }
@@ -3554,7 +3762,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
        float lm_basescalepixels;
        int lm_borderpixels;
        int lm_texturesize;
-       int lm_maxpixels;
+       //int lm_maxpixels;
        const int *e;
        lightmaptriangle_t *triangle;
        unsigned char *lightmappixels;
@@ -3567,7 +3775,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
        lm_basescalepixels = 1.0f / max(0.0001f, mod_generatelightmaps_unitspersample.value);
        lm_borderpixels = mod_generatelightmaps_borderpixels.integer;
        lm_texturesize = bound(lm_borderpixels*2+1, 64, (int)vid.maxtexturesize_2d);
-       lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1);
+       //lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1);
        Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize);
        lightmapnumber = 0;
        for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
@@ -3632,7 +3840,9 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
        lightmapnumber++;
        Mod_AllocLightmap_Free(&lmstate);
 
-       // now together lightmap textures
+       // now put triangles together into lightmap textures, and do not allow
+       // triangles of a surface to go into different textures (as that would
+       // require rewriting the surface list)
        model->brushq3.deluxemapping_modelspace = true;
        model->brushq3.deluxemapping = true;
        model->brushq3.num_mergedlightmaps = lightmapnumber;
@@ -3740,8 +3950,8 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
 
        for (lightmapindex = 0;lightmapindex < model->brushq3.num_mergedlightmaps;lightmapindex++)
        {
-               model->brushq3.data_lightmaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va("lightmap%i", lightmapindex), lm_texturesize, lm_texturesize, lightmappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
-               model->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va("deluxemap%i", lightmapindex), lm_texturesize, lm_texturesize, deluxemappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+               model->brushq3.data_lightmaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va("lightmap%i", lightmapindex), lm_texturesize, lm_texturesize, lightmappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR, NULL);
+               model->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va("deluxemap%i", lightmapindex), lm_texturesize, lm_texturesize, deluxemappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR, NULL);
        }
 
        if (lightmappixels)
@@ -3758,6 +3968,21 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
                lightmapindex = mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle].lightmapindex;
                surface->lightmaptexture = model->brushq3.data_lightmaps[lightmapindex];
                surface->deluxemaptexture = model->brushq3.data_deluxemaps[lightmapindex];
+               surface->lightmapinfo = NULL;
+       }
+
+       model->brush.LightPoint = Mod_GenerateLightmaps_LightPoint;
+       model->brushq1.lightdata = NULL;
+       model->brushq1.lightmapupdateflags = NULL;
+       model->brushq1.firstrender = false;
+       model->brushq1.num_lightstyles = 0;
+       model->brushq1.data_lightstyleinfo = NULL;
+       for (i = 0;i < model->brush.numsubmodels;i++)
+       {
+               model->brush.submodels[i]->brushq1.lightmapupdateflags = NULL;
+               model->brush.submodels[i]->brushq1.firstrender = false;
+               model->brush.submodels[i]->brushq1.num_lightstyles = 0;
+               model->brush.submodels[i]->brushq1.data_lightstyleinfo = NULL;
        }
 }