]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_shared.c
Don't set MATERIALFLAG_NOSHADOW on SKY materials. They need to cast shadows to preve...
[xonotic/darkplaces.git] / model_shared.c
index d9948aeab8ba7d5e413b11ce616049ff063af5e8..8688b13e3fceb37ec4c25653638e15bb189532e7 100644 (file)
@@ -63,7 +63,7 @@ static q3shader_data_t* q3shader_data;
 static void mod_start(void)
 {
        int i, count;
-       int nummodels = Mem_ExpandableArray_IndexRange(&models);
+       int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
        dp_model_t *mod;
 
        SCR_PushLoadingScreen(false, "Loading models", 1.0);
@@ -86,7 +86,7 @@ static void mod_start(void)
 static void mod_shutdown(void)
 {
        int i;
-       int nummodels = Mem_ExpandableArray_IndexRange(&models);
+       int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
        dp_model_t *mod;
 
        for (i = 0;i < nummodels;i++)
@@ -100,8 +100,8 @@ static void mod_shutdown(void)
 static void mod_newmap(void)
 {
        msurface_t *surface;
-       int i, j, k, surfacenum, ssize, tsize;
-       int nummodels = Mem_ExpandableArray_IndexRange(&models);
+       int i, j, k, l, surfacenum, ssize, tsize;
+       int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
        dp_model_t *mod;
 
        for (i = 0;i < nummodels;i++)
@@ -110,10 +110,11 @@ static void mod_newmap(void)
                {
                        for (j = 0;j < mod->num_textures && mod->data_textures;j++)
                        {
-                               for (k = 0;k < mod->data_textures[j].numskinframes;k++)
-                                       R_SkinFrame_MarkUsed(mod->data_textures[j].skinframes[k]);
-                               for (k = 0;k < mod->data_textures[j].backgroundnumskinframes;k++)
-                                       R_SkinFrame_MarkUsed(mod->data_textures[j].backgroundskinframes[k]);
+                               // note that materialshaderpass and backgroundshaderpass point to shaderpasses[] and so do the pre/post shader ranges, so this catches all of them...
+                               for (l = 0; l < Q3SHADER_MAXLAYERS; l++)
+                                       if (mod->data_textures[j].shaderpasses[l])
+                                               for (k = 0; k < mod->data_textures[j].shaderpasses[l]->numframes; k++)
+                                                       R_SkinFrame_MarkUsed(mod->data_textures[j].shaderpasses[l]->skinframes[k]);
                        }
                        if (mod->brush.solidskyskinframe)
                                R_SkinFrame_MarkUsed(mod->brush.solidskyskinframe);
@@ -200,12 +201,6 @@ void Mod_UnloadModel (dp_model_t *mod)
        used = mod->used;
        if (mod->mempool)
        {
-               if (mod->surfmesh.vertex3fbuffer)
-                       R_Mesh_DestroyMeshBuffer(mod->surfmesh.vertex3fbuffer);
-               mod->surfmesh.vertex3fbuffer = NULL;
-               if (mod->surfmesh.vertexmeshbuffer)
-                       R_Mesh_DestroyMeshBuffer(mod->surfmesh.vertexmeshbuffer);
-               mod->surfmesh.vertexmeshbuffer = NULL;
                if (mod->surfmesh.data_element3i_indexbuffer)
                        R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3i_indexbuffer);
                mod->surfmesh.data_element3i_indexbuffer = NULL;
@@ -354,7 +349,9 @@ static void Mod_FindPotentialDeforms(dp_model_t *mod)
        for (i = 0;i < mod->num_textures;i++)
        {
                texture = mod->data_textures + i;
-               if (texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
+               if (texture->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
+                       mod->wantnormals = true;
+               if (texture->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
                        mod->wantnormals = true;
                for (j = 0;j < Q3MAXDEFORMS;j++)
                {
@@ -507,7 +504,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 || !memcmp(buf, "BSP2", 4)) Mod_Q1BSP_Load(mod, buf, bufend);
+               else if (num == BSPVERSION || num == 30 || !memcmp(buf, "BSP2", 4) || !memcmp(buf, "2PSB", 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);
 
@@ -539,7 +536,7 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
 void Mod_ClearUsed(void)
 {
        int i;
-       int nummodels = Mem_ExpandableArray_IndexRange(&models);
+       int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
        dp_model_t *mod;
        for (i = 0;i < nummodels;i++)
                if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0])
@@ -549,7 +546,7 @@ void Mod_ClearUsed(void)
 void Mod_PurgeUnused(void)
 {
        int i;
-       int nummodels = Mem_ExpandableArray_IndexRange(&models);
+       int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
        dp_model_t *mod;
        for (i = 0;i < nummodels;i++)
        {
@@ -579,10 +576,10 @@ dp_model_t *Mod_FindName(const char *name, const char *parentname)
        // if we're not dedicatd, the renderer calls will crash without video
        Host_StartVideo();
 
-       nummodels = Mem_ExpandableArray_IndexRange(&models);
+       nummodels = (int)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++)
@@ -632,7 +629,7 @@ Reloads all models if they have changed
 void Mod_Reload(void)
 {
        int i, count;
-       int nummodels = Mem_ExpandableArray_IndexRange(&models);
+       int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
        dp_model_t *mod;
 
        SCR_PushLoadingScreen(false, "Reloading models", 1.0);
@@ -663,7 +660,7 @@ Mod_Print
 static void Mod_Print(void)
 {
        int i;
-       int nummodels = Mem_ExpandableArray_IndexRange(&models);
+       int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
        dp_model_t *mod;
 
        Con_Print("Loaded models:\n");
@@ -927,7 +924,7 @@ static void Mod_BuildBumpVectors(const float *v0, const float *v1, const float *
 void Mod_BuildTextureVectorsFromNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const float *texcoord2f, const float *normal3f, const int *elements, float *svector3f, float *tvector3f, qboolean areaweighting)
 {
        int i, tnum;
-       float sdir[3], tdir[3], normal[3], *sv, *tv;
+       float sdir[3], tdir[3], normal[3], *svec, *tvec;
        const float *v0, *v1, *v2, *tc0, *tc1, *tc2, *n;
        float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
        const int *e;
@@ -993,14 +990,14 @@ void Mod_BuildTextureVectorsFromNormals(int firstvertex, int numvertices, int nu
        // make the tangents completely perpendicular to the surface normal, and
        // then normalize them
        // 16 assignments, 2 divide, 2 sqrt, 2 negates, 14 adds, 24 multiplies
-       for (i = 0, sv = svector3f + 3 * firstvertex, tv = tvector3f + 3 * firstvertex, n = normal3f + 3 * firstvertex;i < numvertices;i++, sv += 3, tv += 3, n += 3)
+       for (i = 0, svec = svector3f + 3 * firstvertex, tvec = tvector3f + 3 * firstvertex, n = normal3f + 3 * firstvertex;i < numvertices;i++, svec += 3, tvec += 3, n += 3)
        {
-               f = -DotProduct(sv, n);
-               VectorMA(sv, f, n, sv);
-               VectorNormalize(sv);
-               f = -DotProduct(tv, n);
-               VectorMA(tv, f, n, tv);
-               VectorNormalize(tv);
+               f = -DotProduct(svec, n);
+               VectorMA(svec, f, n, svec);
+               VectorNormalize(svec);
+               f = -DotProduct(tvec, n);
+               VectorMA(tvec, f, n, tvec);
+               VectorNormalize(tvec);
        }
 }
 
@@ -1235,21 +1232,13 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool)
                }
        }
 
-       // upload r_vertexmesh_t array as a buffer
-       if (mesh->vertexmesh && !mesh->vertexmeshbuffer)
-               mesh->vertexmeshbuffer = R_Mesh_CreateMeshBuffer(mesh->vertexmesh, mesh->numverts * sizeof(*mesh->vertexmesh), loadmodel->name, false, false, false);
-
-       // upload vertex3f array as a buffer
-       if (mesh->vertex3f && !mesh->vertex3fbuffer)
-               mesh->vertex3fbuffer = R_Mesh_CreateMeshBuffer(mesh->vertex3f, mesh->numverts * sizeof(float[3]), loadmodel->name, false, false, false);
-
        // upload short indices as a buffer
        if (mesh->element3s && !mesh->element3s_indexbuffer)
-               mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), loadmodel->name, true, false, true);
+               mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), loadmodel->name, true, false, false, true);
 
        // upload int indices as a buffer
        if (mesh->element3i && !mesh->element3i_indexbuffer && !mesh->element3s)
-               mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), loadmodel->name, true, false, false);
+               mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), loadmodel->name, true, false, false, false);
 
        // vertex buffer is several arrays and we put them in the same buffer
        //
@@ -1258,21 +1247,23 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool)
        // other hand animated models don't use a lot of vertices anyway...
        if (!mesh->vbo_vertexbuffer && !vid.useinterleavedarrays)
        {
-               size_t size;
+               int size;
                unsigned char *mem;
                size = 0;
+               mesh->vbooffset_vertexmesh         = size;if (mesh->vertexmesh        ) size += mesh->numverts * sizeof(r_vertexmesh_t);
                mesh->vbooffset_vertex3f           = size;if (mesh->vertex3f          ) size += mesh->numverts * sizeof(float[3]);
                mesh->vbooffset_svector3f          = size;if (mesh->svector3f         ) size += mesh->numverts * sizeof(float[3]);
                mesh->vbooffset_tvector3f          = size;if (mesh->tvector3f         ) size += mesh->numverts * sizeof(float[3]);
                mesh->vbooffset_normal3f           = size;if (mesh->normal3f          ) size += mesh->numverts * sizeof(float[3]);
                mesh->vbooffset_texcoord2f         = size;if (mesh->texcoord2f        ) size += mesh->numverts * sizeof(float[2]);
                mem = (unsigned char *)Mem_Alloc(tempmempool, size);
+               if (mesh->vertexmesh        ) memcpy(mem + mesh->vbooffset_vertexmesh        , mesh->vertexmesh        , mesh->numverts * sizeof(r_vertexmesh_t));
                if (mesh->vertex3f          ) memcpy(mem + mesh->vbooffset_vertex3f          , mesh->vertex3f          , mesh->numverts * sizeof(float[3]));
                if (mesh->svector3f         ) memcpy(mem + mesh->vbooffset_svector3f         , mesh->svector3f         , mesh->numverts * sizeof(float[3]));
                if (mesh->tvector3f         ) memcpy(mem + mesh->vbooffset_tvector3f         , mesh->tvector3f         , mesh->numverts * sizeof(float[3]));
                if (mesh->normal3f          ) memcpy(mem + mesh->vbooffset_normal3f          , mesh->normal3f          , mesh->numverts * sizeof(float[3]));
                if (mesh->texcoord2f        ) memcpy(mem + mesh->vbooffset_texcoord2f        , mesh->texcoord2f        , mesh->numverts * sizeof(float[2]));
-               mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, "shadowmesh", false, false, false);
+               mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, "shadowmesh", false, false, false, false);
                Mem_Free(mem);
        }
 }
@@ -1361,10 +1352,6 @@ void Mod_ShadowMesh_Free(shadowmesh_t *mesh)
        shadowmesh_t *nextmesh;
        for (;mesh;mesh = nextmesh)
        {
-               if (mesh->vertex3fbuffer)
-                       R_Mesh_DestroyMeshBuffer(mesh->vertex3fbuffer);
-               if (mesh->vertexmeshbuffer)
-                       R_Mesh_DestroyMeshBuffer(mesh->vertexmeshbuffer);
                if (mesh->element3i_indexbuffer)
                        R_Mesh_DestroyMeshBuffer(mesh->element3i_indexbuffer);
                if (mesh->element3s_indexbuffer)
@@ -1594,7 +1581,7 @@ static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
        unsigned short hash = CRC_Block_CaseInsensitive ((const unsigned char *)shader->name, strlen (shader->name));
        q3shader_hash_entry_t* entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
        q3shader_hash_entry_t* lastEntry = NULL;
-       while (entry != NULL)
+       do
        {
                if (strcasecmp (entry->shader.name, shader->name) == 0)
                {
@@ -1627,6 +1614,7 @@ static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
                lastEntry = entry;
                entry = entry->chain;
        }
+       while (entry != NULL);
        if (entry == NULL)
        {
                if (lastEntry->shader.name[0] != 0)
@@ -1653,6 +1641,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;
@@ -1706,7 +1695,7 @@ void Mod_LoadQ3Shaders(void)
                                                break;
                                        }
                                        // name
-                                       j = strlen(com_token)+1;
+                                       j = (int)strlen(com_token)+1;
                                        custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j);
                                        strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1);
                                        // value
@@ -1733,6 +1722,22 @@ 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.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 +1745,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 +2010,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 +2022,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;
@@ -2245,6 +2258,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;
@@ -2356,30 +2381,6 @@ void Mod_LoadQ3Shaders(void)
                        // hide this shader if a cvar said it should be killed
                        if (shader.dpshaderkill)
                                shader.numlayers = 0;
-                       // pick the primary layer to render with
-                       if (shader.numlayers)
-                       {
-                               shader.backgroundlayer = -1;
-                               shader.primarylayer = 0;
-                               // if lightmap comes first this is definitely an ordinary texture
-                               // if the first two layers have the correct blendfuncs and use vertex alpha, it is a blended terrain shader
-                               if ((shader.layers[shader.primarylayer].texturename != NULL)
-                                 && !strcasecmp(shader.layers[shader.primarylayer].texturename[0], "$lightmap"))
-                               {
-                                       shader.backgroundlayer = -1;
-                                       shader.primarylayer = 1;
-                               }
-                               else if (shader.numlayers >= 2
-                               &&   shader.layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX
-                               &&  (shader.layers[0].blendfunc[0] == GL_ONE       && shader.layers[0].blendfunc[1] == GL_ZERO                && !shader.layers[0].alphatest)
-                               && ((shader.layers[1].blendfunc[0] == GL_SRC_ALPHA && shader.layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
-                               ||  (shader.layers[1].blendfunc[0] == GL_ONE       && shader.layers[1].blendfunc[1] == GL_ZERO                &&  shader.layers[1].alphatest)))
-                               {
-                                       // terrain blending or other effects
-                                       shader.backgroundlayer = 0;
-                                       shader.primarylayer = 1;
-                               }
-                       }
                        // fix up multiple reflection types
                        if(shader.textureflags & Q3TEXTUREFLAG_WATERSHADER)
                                shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION | Q3TEXTUREFLAG_CAMERA);
@@ -2411,15 +2412,59 @@ q3shaderinfo_t *Mod_LookupQ3Shader(const char *name)
        return NULL;
 }
 
-qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags)
+texture_shaderpass_t *Mod_CreateShaderPass(skinframe_t *skinframe)
+{
+       texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(loadmodel->mempool, sizeof(*shaderpass));
+       shaderpass->framerate = 0.0f;
+       shaderpass->numframes = 1;
+       shaderpass->blendfunc[0] = GL_ONE;
+       shaderpass->blendfunc[1] = GL_ZERO;
+       shaderpass->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
+       shaderpass->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
+       shaderpass->alphatest = false;
+       shaderpass->tcgen.tcgen = Q3TCGEN_TEXTURE;
+       shaderpass->skinframes[0] = skinframe;
+       return shaderpass;
+}
+
+texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename)
 {
        int j;
+       texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(loadmodel->mempool, sizeof(*shaderpass));
+       shaderpass->alphatest = layer->alphatest != 0;
+       shaderpass->framerate = layer->framerate;
+       shaderpass->numframes = layer->numframes;
+       shaderpass->blendfunc[0] = layer->blendfunc[0];
+       shaderpass->blendfunc[1] = layer->blendfunc[1];
+       shaderpass->rgbgen = layer->rgbgen;
+       shaderpass->alphagen = layer->alphagen;
+       shaderpass->tcgen = layer->tcgen;
+       for (j = 0; j < Q3MAXTCMODS && layer->tcmods[j].tcmod != Q3TCMOD_NONE; j++)
+               shaderpass->tcmods[j] = layer->tcmods[j];
+       for (j = 0; j < layer->numframes; j++)
+       {
+               if (cls.state == ca_dedicated)
+               {
+                       shaderpass->skinframes[j] = NULL;
+               }
+               else if (!(shaderpass->skinframes[j] = R_SkinFrame_LoadExternal(layer->texturename[j], texflags, false)))
+               {
+                       Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (frame %i) for layer %i of shader ^2\"%s\"\n", loadmodel->name, layer->texturename[j], j, layerindex, texturename);
+                       shaderpass->skinframes[j] = R_SkinFrame_LoadMissing();
+               }
+       }
+       return shaderpass;
+}
+
+qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags)
+{
        int texflagsmask, texflagsor;
        qboolean success = true;
        q3shaderinfo_t *shader;
        if (!name)
                name = "";
        strlcpy(texture->name, name, sizeof(texture->name));
+       texture->basealpha = 1.0f;
        shader = name[0] ? Mod_LookupQ3Shader(name) : NULL;
 
        texflagsmask = ~0;
@@ -2439,8 +2484,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)
@@ -2453,7 +2498,7 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool
 
                if (shader->surfaceparms & Q3SURFACEPARM_SKY)
                {
-                       texture->basematerialflags = MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
+                       texture->basematerialflags = MATERIALFLAG_SKY;
                        if (shader->skyboxname[0])
                        {
                                // quake3 seems to append a _ to the skybox name, so this must do so as well
@@ -2484,6 +2529,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];
@@ -2523,51 +2569,99 @@ nothing                GL_ZERO GL_ONE
                }
                if (!shader->lighting)
                        texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
-               if (shader->primarylayer >= 0)
+
+               // here be dragons: convert quake3 shaders to material
+               if (shader->numlayers > 0)
                {
-                       q3shaderinfo_layer_t* primarylayer = shader->layers + shader->primarylayer;
-                       // copy over many primarylayer parameters
-                       texture->rgbgen = primarylayer->rgbgen;
-                       texture->alphagen = primarylayer->alphagen;
-                       texture->tcgen = primarylayer->tcgen;
-                       memcpy(texture->tcmods, primarylayer->tcmods, sizeof(texture->tcmods));
-                       // load the textures
-                       texture->numskinframes = primarylayer->numframes;
-                       texture->skinframerate = primarylayer->framerate;
-                       for (j = 0;j < primarylayer->numframes;j++)
+                       int i;
+                       int terrainbackgroundlayer = -1;
+                       int lightmaplayer = -1;
+                       int alphagenspecularlayer = -1;
+                       int rgbgenvertexlayer = -1;
+                       int rgbgendiffuselayer = -1;
+                       int materiallayer = -1;
+                       int endofprelayers = 0;
+                       int firstpostlayer = 0;
+                       int shaderpassindex = 0;
+                       for (i = 0; i < shader->numlayers; i++)
                        {
-                               if(cls.state == ca_dedicated)
-                               {
-                                       texture->skinframes[j] = NULL;
-                               }
-                               else if (!(texture->skinframes[j] = R_SkinFrame_LoadExternal(primarylayer->texturename[j], (primarylayer->texflags & texflagsmask) | texflagsor, false)))
-                               {
-                                       Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (frame %i) for shader ^2\"%s\"\n", loadmodel->name, primarylayer->texturename[j], j, texture->name);
-                                       texture->skinframes[j] = R_SkinFrame_LoadMissing();
-                               }
+                               if (shader->layers[i].texturename != NULL && !strcasecmp(shader->layers[i].texturename[0], "$lightmap"))
+                                       lightmaplayer = i;
+                               if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_VERTEX)
+                                       rgbgenvertexlayer = i;
+                               if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE)
+                                       rgbgendiffuselayer = i;
+                               if (shader->layers[i].alphagen.alphagen == Q3ALPHAGEN_LIGHTINGSPECULAR)
+                                       alphagenspecularlayer = i;
                        }
-               }
-               if (shader->backgroundlayer >= 0)
-               {
-                       q3shaderinfo_layer_t* backgroundlayer = shader->layers + shader->backgroundlayer;
-                       // copy over one secondarylayer parameter
-                       memcpy(texture->backgroundtcmods, backgroundlayer->tcmods, sizeof(texture->backgroundtcmods));
-                       // load the textures
-                       texture->backgroundnumskinframes = backgroundlayer->numframes;
-                       texture->backgroundskinframerate = backgroundlayer->framerate;
-                       for (j = 0;j < backgroundlayer->numframes;j++)
+                       if (shader->numlayers >= 2
+                        && shader->layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX
+                        && (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ZERO && !shader->layers[0].alphatest)
+                        && ((shader->layers[1].blendfunc[0] == GL_SRC_ALPHA && shader->layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
+                                || (shader->layers[1].blendfunc[0] == GL_ONE && shader->layers[1].blendfunc[1] == GL_ZERO && shader->layers[1].alphatest)))
                        {
-                               if(cls.state == ca_dedicated)
-                               {
-                                       texture->skinframes[j] = NULL;
-                               }
-                               else if (!(texture->backgroundskinframes[j] = R_SkinFrame_LoadExternal(backgroundlayer->texturename[j], (backgroundlayer->texflags & texflagsmask) | texflagsor, false)))
-                               {
-                                       Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (background frame %i) for shader ^2\"%s\"\n", loadmodel->name, backgroundlayer->texturename[j], j, texture->name);
-                                       texture->backgroundskinframes[j] = R_SkinFrame_LoadMissing();
-                               }
+                               // terrain blend or certain other effects involving alphatest over a regular layer
+                               terrainbackgroundlayer = 0;
+                               materiallayer = 1;
+                               // terrain may be vertex lit (in which case both layers are rgbGen vertex) or lightmapped (in which ase the third layer is lightmap)
+                               firstpostlayer = lightmaplayer >= 0 ? lightmaplayer + 1 : materiallayer + 1;
                        }
+                       else if (lightmaplayer == 0)
+                       {
+                               // ordinary texture but with $lightmap before diffuse
+                               materiallayer = 1;
+                               firstpostlayer = lightmaplayer + 2;
+                       }
+                       else if (lightmaplayer >= 1)
+                       {
+                               // ordinary texture - we don't properly apply lighting to the prelayers, but oh well...
+                               endofprelayers = lightmaplayer - 1;
+                               materiallayer = lightmaplayer - 1;
+                               firstpostlayer = lightmaplayer + 1;
+                       }
+                       else if (rgbgenvertexlayer >= 0)
+                       {
+                               // map models with baked lighting
+                               materiallayer = rgbgenvertexlayer;
+                               endofprelayers = rgbgenvertexlayer;
+                               firstpostlayer = rgbgenvertexlayer + 1;
+                       }
+                       else if (rgbgendiffuselayer >= 0)
+                       {
+                               // entity models with dynamic lighting
+                               materiallayer = rgbgendiffuselayer;
+                               endofprelayers = rgbgendiffuselayer;
+                               firstpostlayer = rgbgendiffuselayer + 1;
+                               // player models often have specular as a pass after diffuse - we don't currently make use of that specular texture (would need to meld it into the skinframe)...
+                               if (alphagenspecularlayer >= 0)
+                                       firstpostlayer = alphagenspecularlayer + 1;
+                       }
+                       else
+                       {
+                               // special effects shaders - treat first as primary layer and do everything else as post
+                               endofprelayers = 0;
+                               materiallayer = 0;
+                               firstpostlayer = 1;
+                       }
+                       // convert the main material layer
+                       // FIXME: if alphagenspecularlayer is used, we should pass a specular texture name to R_SkinFrame_LoadExternal and have it load that texture instead of the assumed name for _gloss texture
+                       if (materiallayer >= 0)
+                               texture->materialshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[materiallayer], materiallayer, (shader->layers[materiallayer].texflags & texflagsmask) | texflagsor, texture->name);
+                       // convert the terrain background blend layer (if any)
+                       if (terrainbackgroundlayer >= 0)
+                               texture->backgroundshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[terrainbackgroundlayer], terrainbackgroundlayer, (shader->layers[terrainbackgroundlayer].texflags & texflagsmask) | texflagsor, texture->name);
+                       // convert the prepass layers (if any)
+                       texture->startpreshaderpass = shaderpassindex;
+                       for (i = 0; i < endofprelayers; i++)
+                               texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[i], i, (shader->layers[i].texflags & texflagsmask) | texflagsor, texture->name);
+                       texture->endpreshaderpass = shaderpassindex;
+                       texture->startpostshaderpass = shaderpassindex;
+                       // convert the postpass layers (if any)
+                       for (i = firstpostlayer; i < shader->numlayers; i++)
+                               texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[i], i, (shader->layers[i].texflags & texflagsmask) | texflagsor, texture->name);
+                       texture->startpostshaderpass = shaderpassindex;
                }
+
                if (shader->dpshadow)
                        texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW;
                if (shader->dpnoshadow)
@@ -2700,7 +2794,7 @@ nothing                GL_ZERO GL_ONE
                }
                else if (texture->surfaceflags & Q3SURFACEFLAG_SKY)
                {
-                       texture->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
+                       texture->basematerialflags |= MATERIALFLAG_SKY;
                        texture->supercontents = SUPERCONTENTS_SKY;
                }
                else
@@ -2708,20 +2802,22 @@ nothing                GL_ZERO GL_ONE
                        texture->basematerialflags |= MATERIALFLAG_WALL;
                        texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
                }
-               texture->numskinframes = 1;
                if(cls.state == ca_dedicated)
                {
-                       texture->skinframes[0] = NULL;
+                       texture->materialshaderpass = NULL;
                        success = false;
                }
                else
                {
                        if (fallback)
                        {
-                               if ((texture->skinframes[0] = R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false)))
+                               texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false));
+                               if (texture->materialshaderpass->skinframes[0])
                                {
-                                       if(texture->skinframes[0]->hasalpha)
+                                       if (texture->materialshaderpass->skinframes[0]->hasalpha)
                                                texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
+                                       if (texture->q2contents)
+                                               texture->supercontents = Mod_Q2BSP_SuperContentsFromNativeContents(loadmodel, texture->q2contents);
                                }
                                else
                                        success = false;
@@ -2734,12 +2830,12 @@ nothing                GL_ZERO GL_ONE
        }
        // init the animation variables
        texture->currentframe = texture;
-       if (texture->numskinframes < 1)
-               texture->numskinframes = 1;
-       if (!texture->skinframes[0])
-               texture->skinframes[0] = R_SkinFrame_LoadMissing();
-       texture->currentskinframe = texture->skinframes[0];
-       texture->backgroundcurrentskinframe = texture->backgroundskinframes[0];
+       if (!texture->materialshaderpass)
+               texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadMissing());
+       if (!texture->materialshaderpass->skinframes[0])
+               texture->materialshaderpass->skinframes[0] = R_SkinFrame_LoadMissing();
+       texture->currentskinframe = texture->materialshaderpass ? texture->materialshaderpass->skinframes[0] : NULL;
+       texture->backgroundcurrentskinframe = texture->backgroundshaderpass ? texture->backgroundshaderpass->skinframes[0] : NULL;
        return success;
 }
 
@@ -2939,7 +3035,7 @@ void Mod_MakeSortedSurfaces(dp_model_t *mod)
        for (j = 0;j < mod->nummodelsurfaces;j++)
        {
                const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
-               int t = (int)(surface->texture - mod->data_textures);
+               t = (int)(surface->texture - mod->data_textures);
                numsurfacesfortexture[t]++;
        }
        j = 0;
@@ -2951,7 +3047,7 @@ void Mod_MakeSortedSurfaces(dp_model_t *mod)
        for (j = 0;j < mod->nummodelsurfaces;j++)
        {
                const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
-               int t = (int)(surface->texture - mod->data_textures);
+               t = (int)(surface->texture - mod->data_textures);
                mod->sortedmodelsurfaces[firstsurfacefortexture[t]++] = j + mod->firstmodelsurface;
        }
        Mem_Free(firstsurfacefortexture);
@@ -2978,12 +3074,12 @@ void Mod_BuildVBOs(void)
 
        // build r_vertexmesh_t array
        // (compressed interleaved array for D3D)
-       if (!loadmodel->surfmesh.vertexmesh && vid.useinterleavedarrays)
+       if (!loadmodel->surfmesh.data_vertexmesh && vid.useinterleavedarrays)
        {
                int vertexindex;
                int numvertices = loadmodel->surfmesh.num_vertices;
                r_vertexmesh_t *vertexmesh;
-               loadmodel->surfmesh.vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*loadmodel->surfmesh.vertexmesh));
+               loadmodel->surfmesh.data_vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(r_vertexmesh_t));
                for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++)
                {
                        VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexmesh->vertex3f);
@@ -2995,24 +3091,20 @@ 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);
                }
        }
 
-       // upload r_vertexmesh_t array as a buffer
-       if (loadmodel->surfmesh.vertexmesh && !loadmodel->surfmesh.vertexmeshbuffer)
-               loadmodel->surfmesh.vertexmeshbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.vertexmesh, loadmodel->surfmesh.num_vertices * sizeof(*loadmodel->surfmesh.vertexmesh), loadmodel->name, false, false, false);
-
-       // upload vertex3f array as a buffer
-       if (loadmodel->surfmesh.data_vertex3f && !loadmodel->surfmesh.vertex3fbuffer)
-               loadmodel->surfmesh.vertex3fbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3]), loadmodel->name, false, false, false);
-
        // upload short indices as a buffer
        if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer)
-               loadmodel->surfmesh.data_element3s_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles * sizeof(short[3]), loadmodel->name, true, false, true);
+               loadmodel->surfmesh.data_element3s_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles * sizeof(short[3]), loadmodel->name, true, false, false, true);
 
        // upload int indices as a buffer
        if (loadmodel->surfmesh.data_element3i && !loadmodel->surfmesh.data_element3i_indexbuffer && !loadmodel->surfmesh.data_element3s)
-               loadmodel->surfmesh.data_element3i_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(int[3]), loadmodel->name, true, false, false);
+               loadmodel->surfmesh.data_element3i_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(int[3]), loadmodel->name, true, false, false, false);
 
        // only build a vbo if one has not already been created (this is important for brush models which load specially)
        // vertex buffer is several arrays and we put them in the same buffer
@@ -3022,9 +3114,10 @@ void Mod_BuildVBOs(void)
        // other hand animated models don't use a lot of vertices anyway...
        if (!loadmodel->surfmesh.vbo_vertexbuffer && !vid.useinterleavedarrays)
        {
-               size_t size;
+               int size;
                unsigned char *mem;
                size = 0;
+               loadmodel->surfmesh.vbooffset_vertexmesh         = size;if (loadmodel->surfmesh.data_vertexmesh        ) size += loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t);
                loadmodel->surfmesh.vbooffset_vertex3f           = size;if (loadmodel->surfmesh.data_vertex3f          ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
                loadmodel->surfmesh.vbooffset_svector3f          = size;if (loadmodel->surfmesh.data_svector3f         ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
                loadmodel->surfmesh.vbooffset_tvector3f          = size;if (loadmodel->surfmesh.data_tvector3f         ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
@@ -3032,7 +3125,10 @@ 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_vertexmesh        ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertexmesh        , loadmodel->surfmesh.data_vertexmesh        , loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t));
                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]));
                if (loadmodel->surfmesh.data_tvector3f         ) memcpy(mem + loadmodel->surfmesh.vbooffset_tvector3f         , loadmodel->surfmesh.data_tvector3f         , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
@@ -3040,7 +3136,9 @@ 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]));
-               loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false);
+               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, false);
                Mem_Free(mem);
        }
 }
@@ -3408,7 +3506,7 @@ static void Mod_Decompile_f(void)
                        {
                                // individual frame
                                // check for additional frames with same name
-                               for (l = 0, k = strlen(animname);animname[l];l++)
+                               for (l = 0, k = (int)strlen(animname);animname[l];l++)
                                        if(animname[l] < '0' || animname[l] > '9')
                                                k = l + 1;
                                if(k > 0 && animname[k-1] == '_')
@@ -3418,7 +3516,7 @@ static void Mod_Decompile_f(void)
                                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++)
+                                       for (l = 0, k = (int)strlen(animname2);animname2[l];l++)
                                                if(animname2[l] < '0' || animname2[l] > '9')
                                                        k = l + 1;
                                        if(k > 0 && animname[k-1] == '_')
@@ -3462,14 +3560,14 @@ static void Mod_Decompile_f(void)
        }
 }
 
-void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, int width, int height)
+void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, mempool_t *mempool, int width, int height)
 {
        int y;
        memset(state, 0, sizeof(*state));
        state->width = width;
        state->height = height;
        state->currentY = 0;
-       state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(loadmodel->mempool, state->height * sizeof(*state->rows));
+       state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(mempool, state->height * sizeof(*state->rows));
        for (y = 0;y < state->height;y++)
        {
                state->rows[y].currentX = 0;
@@ -3634,7 +3732,7 @@ static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos
                        continue;
                if (model && model->TraceLine)
                {
-                       model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_VISBLOCKERMASK);
+                       model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_VISBLOCKERMASK, SUPERCONTENTS_SKY);
                        if (trace.fraction < 1)
                                continue;
                }
@@ -3836,7 +3934,7 @@ static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *nor
                                if (!normal)
                                {
                                        // for light grid we'd better check visibility of the offset point
-                                       cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, pos, offsetpos, SUPERCONTENTS_VISBLOCKERMASK);
+                                       cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, pos, offsetpos, SUPERCONTENTS_VISBLOCKERMASK, SUPERCONTENTS_SKY);
                                        if (trace.fraction < 1)
                                                VectorLerp(pos, trace.fraction, offsetpos, offsetpos);
                                }
@@ -4014,15 +4112,6 @@ static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model)
        if (model->surfmesh.num_vertices > 65536)
                model->surfmesh.data_element3s = NULL;
 
-       if (model->surfmesh.vertexmesh)
-               Mem_Free(model->surfmesh.vertexmesh);
-       model->surfmesh.vertexmesh = NULL;
-       if (model->surfmesh.vertex3fbuffer)
-               R_Mesh_DestroyMeshBuffer(model->surfmesh.vertex3fbuffer);
-       model->surfmesh.vertex3fbuffer = NULL;
-       if (model->surfmesh.vertexmeshbuffer)
-               R_Mesh_DestroyMeshBuffer(model->surfmesh.vertexmeshbuffer);
-       model->surfmesh.vertexmeshbuffer = NULL;
        if (model->surfmesh.data_element3i_indexbuffer)
                R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer);
        model->surfmesh.data_element3i_indexbuffer = NULL;
@@ -4181,7 +4270,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
        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);
-       Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize);
+       Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
        lightmapnumber = 0;
        for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
        {
@@ -4229,7 +4318,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
                                surfaceindex = -1;
                                lightmapnumber = 0;
                                Mod_AllocLightmap_Free(&lmstate);
-                               Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize);
+                               Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
                                break;
                        }
                        // if we have maxed out the lightmap size, and this triangle does
@@ -4367,7 +4456,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;