]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_brush.c
new option -capturedemo to capture a demo to an AVI file;
[xonotic/darkplaces.git] / model_brush.c
index ca78e3ce7bd8a5a670988b2617c77ed765b30206..660c4df77dfa7504aea387485d825ca0a106cba0 100644 (file)
@@ -4570,7 +4570,10 @@ Q3 shader blendfuncs actually used in the game (* = supported by DP)
                                out->skinframerate = shader->primarylayer->framerate;
                                for (j = 0;j < shader->primarylayer->numframes;j++)
                                        if (!(out->skinframes[j] = R_SkinFrame_LoadExternal(shader->primarylayer->texturename[j], ((shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | ((!r_picmipworld.integer || (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP)) ? 0 : TEXF_PICMIP) | (shader->primarylayer->clampmap ? TEXF_CLAMP : 0), false)))
+                                       {
                                                Con_DPrintf("%s: could not load texture \"%s\" (frame %i) for shader \"%s\"\n", loadmodel->name, shader->primarylayer->texturename[j], j, out->name);
+                                               out->skinframes[j] = R_SkinFrame_LoadMissing();
+                                       }
                        }
                        if (shader->backgroundlayer)
                        {
@@ -4825,7 +4828,7 @@ static void Mod_Q3BSP_LoadTriangles(lump_t *l)
 static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
 {
        q3dlightmap_t *in;
-       int i, j, count, power, power2, mask, endlightmap;
+       int i, j, count, power, power2, mask, endlightmap, mergewidth, mergeheight;
        unsigned char *c;
 
        if (!l->filelen)
@@ -4892,7 +4895,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
 
        // figure out what the most reasonable merge power is within limits
        loadmodel->brushq3.num_lightmapmergepower = 0;
-       for (power = 1;power <= mod_q3bsp_lightmapmergepower.integer && (1 << power) <= gl_max_texture_size && (1 << (power * 2)) < 4 * (count >> loadmodel->brushq3.deluxemapping);power++)
+       for (power = 1;power <= mod_q3bsp_lightmapmergepower.integer && (128 << power) <= gl_max_texture_size && (1 << (power * 2)) < 4 * (count >> loadmodel->brushq3.deluxemapping);power++)
                loadmodel->brushq3.num_lightmapmergepower = power;
        loadmodel->brushq3.num_lightmapmerge = 1 << loadmodel->brushq3.num_lightmapmergepower;
 
@@ -4905,25 +4908,54 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
        if (loadmodel->texturepool == NULL && cls.state != ca_dedicated)
                loadmodel->texturepool = R_AllocTexturePool();
 
-       j = 128 << loadmodel->brushq3.num_lightmapmergepower;
-       if (loadmodel->brushq3.data_lightmaps)
-               for (i = 0;i < loadmodel->brushq3.num_mergedlightmaps;i++)
-                       loadmodel->brushq3.data_lightmaps[i] = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", i), j, j, NULL, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
-
-       if (loadmodel->brushq3.data_deluxemaps)
-               for (i = 0;i < loadmodel->brushq3.num_mergedlightmaps;i++)
-                       loadmodel->brushq3.data_deluxemaps[i] = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%04i", i), j, j, NULL, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
-
-       power = loadmodel->brushq3.num_lightmapmergepower;
-       power2 = power * 2;
-       mask = (1 << power) - 1;
-       for (i = 0;i < count;i++)
+       if (loadmodel->brushq3.num_lightmapmergepower > 0)
        {
-               j = i >> loadmodel->brushq3.deluxemapping;
-               if (loadmodel->brushq3.deluxemapping && (i & 1))
-                       R_UpdateTexture(loadmodel->brushq3.data_deluxemaps[j >> power2], in[i].rgb, (j & mask) * 128, ((j >> power) & mask) * 128, 128, 128);
-               else
-                       R_UpdateTexture(loadmodel->brushq3.data_lightmaps [j >> power2], in[i].rgb, (j & mask) * 128, ((j >> power) & mask) * 128, 128, 128);
+               power = loadmodel->brushq3.num_lightmapmergepower;
+               power2 = power * 2;
+               mask = (1 << power) - 1;
+               for (i = 0;i < count;i++)
+               {
+                       // figure out which merged lightmap texture this fits into
+                       int lightmapindex = i >> (loadmodel->brushq3.deluxemapping + power2);
+                       // if the lightmap has not been allocated yet, create it
+                       if (!loadmodel->brushq3.data_lightmaps[lightmapindex])
+                       {
+                               // create a lightmap only as large as necessary to hold the
+                               // remaining 128x128 blocks
+                               // if there are multiple merged lightmap textures then they will
+                               // all be full size except the last one which may be smaller
+                               // because it only needs to the remaining blocks, and it will often
+                               // be odd sizes like 2048x512 due to only being 25% full or so.
+                               j = (count >> loadmodel->brushq3.deluxemapping) - (lightmapindex << power2);
+                               for (mergewidth = 1;mergewidth < j && mergewidth < (1 << power);mergewidth *= 2)
+                                       ;
+                               for (mergeheight = 1;mergewidth*mergeheight < j && mergeheight < (1 << power);mergeheight *= 2)
+                                       ;
+                               Con_DPrintf("lightmap merge texture #%i is %ix%i (%i of %i used)\n", lightmapindex, mergewidth*128, mergeheight*128, min(j, mergewidth*mergeheight), mergewidth*mergeheight);
+                               loadmodel->brushq3.data_lightmaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", lightmapindex), mergewidth * 128, mergeheight * 128, NULL, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+                               if (loadmodel->brushq3.data_deluxemaps)
+                                       loadmodel->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%04i", lightmapindex), mergewidth * 128, mergeheight * 128, NULL, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+                       }
+                       mergewidth = R_TextureWidth(loadmodel->brushq3.data_lightmaps[lightmapindex]) / 128;
+                       mergeheight = R_TextureHeight(loadmodel->brushq3.data_lightmaps[lightmapindex]) / 128;
+                       j = (i >> loadmodel->brushq3.deluxemapping) & ((1 << power2) - 1);
+                       if (loadmodel->brushq3.deluxemapping && (i & 1))
+                               R_UpdateTexture(loadmodel->brushq3.data_deluxemaps[lightmapindex], in[i].rgb, (j % mergewidth) * 128, (j / mergewidth) * 128, 128, 128);
+                       else
+                               R_UpdateTexture(loadmodel->brushq3.data_lightmaps     [lightmapindex], in[i].rgb, (j % mergewidth) * 128, (j / mergewidth) * 128, 128, 128);
+               }
+       }
+       else
+       {
+               for (i = 0;i < count;i++)
+               {
+                       // figure out which merged lightmap texture this fits into
+                       int lightmapindex = i >> loadmodel->brushq3.deluxemapping;
+                       if (loadmodel->brushq3.deluxemapping && (i & 1))
+                               loadmodel->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%04i", lightmapindex), 128, 128, in[i].rgb, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+                       else
+                               loadmodel->brushq3.data_lightmaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", lightmapindex), 128, 128, in[i].rgb, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+               }
        }
 }
 
@@ -4932,7 +4964,7 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l)
        q3dface_t *in, *oldin;
        msurface_t *out, *oldout;
        int i, oldi, j, n, count, invalidelements, patchsize[2], finalwidth, finalheight, xtess, ytess, finalvertices, finaltriangles, firstvertex, firstelement, type, oldnumtriangles, oldnumtriangles2, meshvertices, meshtriangles, numvertices, numtriangles;
-       float lightmaptcbase[2], lightmaptcscale;
+       float lightmaptcbase[2], lightmaptcscale[2];
        //int *originalelement3i;
        //int *originalneighbor3i;
        float *originalvertex3f;
@@ -5229,18 +5261,22 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l)
                VectorClear(out->maxs);
                if (out->num_vertices)
                {
-                       int lightmapindex = LittleLong(in->lightmapindex);
-                       if (lightmapindex >= 0 && cls.state != ca_dedicated)
+                       if (cls.state != ca_dedicated && out->lightmaptexture)
                        {
-                               lightmapindex >>= loadmodel->brushq3.deluxemapping;
-                               lightmaptcscale = 1.0f / loadmodel->brushq3.num_lightmapmerge;
-                               lightmaptcbase[0] = ((lightmapindex                                             ) & (loadmodel->brushq3.num_lightmapmerge - 1)) * lightmaptcscale;
-                               lightmaptcbase[1] = ((lightmapindex >> loadmodel->brushq3.num_lightmapmergepower) & (loadmodel->brushq3.num_lightmapmerge - 1)) * lightmaptcscale;
+                               // figure out which part of the merged lightmap this fits into
+                               int lightmapindex = LittleLong(in->lightmapindex) >> loadmodel->brushq3.deluxemapping;
+                               int mergewidth = R_TextureWidth(out->lightmaptexture) / 128;
+                               int mergeheight = R_TextureHeight(out->lightmaptexture) / 128;
+                               lightmapindex &= mergewidth * mergeheight - 1;
+                               lightmaptcscale[0] = 1.0f / mergewidth;
+                               lightmaptcscale[1] = 1.0f / mergeheight;
+                               lightmaptcbase[0] = (lightmapindex % mergewidth) * lightmaptcscale[0];
+                               lightmaptcbase[1] = (lightmapindex / mergewidth) * lightmaptcscale[1];
                                // modify the lightmap texcoords to match this region of the merged lightmap
                                for (j = 0, v = loadmodel->surfmesh.data_texcoordlightmap2f + 2 * out->num_firstvertex;j < out->num_vertices;j++, v += 2)
                                {
-                                       v[0] = v[0] * lightmaptcscale + lightmaptcbase[0];
-                                       v[1] = v[1] * lightmaptcscale + lightmaptcbase[1];
+                                       v[0] = v[0] * lightmaptcscale[0] + lightmaptcbase[0];
+                                       v[1] = v[1] * lightmaptcscale[1] + lightmaptcbase[1];
                                }
                        }
                        VectorCopy((loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), out->mins);
@@ -5546,7 +5582,7 @@ static void Mod_Q3BSP_LoadPVS(lump_t *l)
 static void Mod_Q3BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
 {
        int i, j, k, index[3];
-       float transformed[3], blend1, blend2, blend, yaw, pitch, sinpitch, stylescale;
+       float transformed[3], blend1, blend2, blend, stylescale;
        q3dlightgrid_t *a, *s;
 
        // scale lighting by lightstyle[0] so that darkmode in dpmod works properly
@@ -5592,12 +5628,12 @@ static void Mod_Q3BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientc
                                s = a + (k * model->brushq3.num_lightgrid_isize[1] + j) * model->brushq3.num_lightgrid_isize[0] + i;
                                VectorMA(ambientcolor, blend * (1.0f / 128.0f), s->ambientrgb, ambientcolor);
                                VectorMA(diffusecolor, blend * (1.0f / 128.0f), s->diffusergb, diffusecolor);
-                               pitch = s->diffusepitch * M_PI / 128;
-                               yaw = s->diffuseyaw * M_PI / 128;
-                               sinpitch = sin(pitch);
-                               diffusenormal[0] += blend * (cos(yaw) * sinpitch);
-                               diffusenormal[1] += blend * (sin(yaw) * sinpitch);
-                               diffusenormal[2] += blend * (cos(pitch));
+                               // this uses the mod_md3_sin table because the values are
+                               // already in the 0-255 range, the 64+ bias fetches a cosine
+                               // instead of a sine value
+                               diffusenormal[0] += blend * (mod_md3_sin[64 + s->diffuseyaw] * mod_md3_sin[s->diffusepitch]);
+                               diffusenormal[1] += blend * (mod_md3_sin[     s->diffuseyaw] * mod_md3_sin[s->diffusepitch]);
+                               diffusenormal[2] += blend * (mod_md3_sin[64 + s->diffusepitch]);
                                //Con_Printf("blend %f: ambient %i %i %i, diffuse %i %i %i, diffusepitch %i diffuseyaw %i (%f %f, normal %f %f %f)\n", blend, s->ambientrgb[0], s->ambientrgb[1], s->ambientrgb[2], s->diffusergb[0], s->diffusergb[1], s->diffusergb[2], s->diffusepitch, s->diffuseyaw, pitch, yaw, (cos(yaw) * cospitch), (sin(yaw) * cospitch), (-sin(pitch)));
                        }
                }