]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
implemented real support for QW skins (pants, shirt, glow, cropped pcx
[xonotic/darkplaces.git] / gl_rmain.c
index 251572afe4a2884e270a84bb13a7d16b1cac6e8a..cef68dc50b3089d41912d2068b995b84ddbcaa2e 100644 (file)
@@ -79,7 +79,7 @@ cvar_t r_shadows_drawafterrtlighting = {CVAR_SAVE, "r_shadows_drawafterrtlightin
 cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
 cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
-cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "2", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
+cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "4", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
 cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
 cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
 
@@ -191,8 +191,15 @@ unsigned int r_queries[R_MAX_OCCLUSION_QUERIES];
 unsigned int r_numqueries;
 unsigned int r_maxqueries;
 
-char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH];
-skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD];
+typedef struct r_qwskincache_s
+{
+       char name[MAX_QPATH];
+       skinframe_t *skinframe;
+}
+r_qwskincache_t;
+
+static r_qwskincache_t *r_qwskincache;
+static int r_qwskincache_size;
 
 /// vertex coordinates for a quad that covers the screen exactly
 const float r_screenvertex3f[12] =
@@ -2430,7 +2437,8 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl
        int basepixels_height;
        skinframe_t *skinframe;
 
-       *has_alpha = false;
+       if (has_alpha)
+               *has_alpha = false;
 
        if (cls.state == ca_dedicated)
                return NULL;
@@ -2474,7 +2482,8 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl
                if (j < basepixels_width * basepixels_height * 4)
                {
                        // has transparent pixels
-                       *has_alpha = true;
+                       if (has_alpha)
+                               *has_alpha = true;
                        pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
                        for (j = 0;j < image_width * image_height * 4;j += 4)
                        {
@@ -2532,8 +2541,7 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl
 
 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
 {
-       qboolean has_alpha;
-       return R_SkinFrame_LoadExternal_CheckAlpha(name, textureflags, complain, &has_alpha);
+       return R_SkinFrame_LoadExternal_CheckAlpha(name, textureflags, complain, NULL);
 }
 
 static rtexture_t *R_SkinFrame_TextureForSkinLayer(const unsigned char *in, int width, int height, const char *name, const unsigned int *palette, int textureflags, qboolean force)
@@ -2715,8 +2723,8 @@ void gl_main_start(void)
        r_maxqueries = 0;
        memset(r_queries, 0, sizeof(r_queries));
 
-       memset(r_qwskincache, 0, sizeof(r_qwskincache));
-       memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
+       r_qwskincache = NULL;
+       r_qwskincache_size = 0;
 
        // set up r_skinframe loading system for textures
        memset(&r_skinframe, 0, sizeof(r_skinframe));
@@ -2753,8 +2761,8 @@ void gl_main_shutdown(void)
        r_maxqueries = 0;
        memset(r_queries, 0, sizeof(r_queries));
 
-       memset(r_qwskincache, 0, sizeof(r_qwskincache));
-       memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
+       r_qwskincache = NULL;
+       r_qwskincache_size = 0;
 
        // clear out the r_skinframe state
        Mem_ExpandableArray_FreeArray(&r_skinframe.array);
@@ -2785,6 +2793,10 @@ void gl_main_newmap(void)
        // FIXME: move this code to client
        int l;
        char *entities, entname[MAX_QPATH];
+       if (r_qwskincache)
+               Mem_Free(r_qwskincache);
+       r_qwskincache = NULL;
+       r_qwskincache_size = 0;
        if (cl.worldmodel)
        {
                strlcpy(entname, cl.worldmodel->name, sizeof(entname));
@@ -3269,6 +3281,45 @@ static void R_View_UpdateEntityLighting (void)
        }
 }
 
+#define MAX_LINEOFSIGHTTRACES 64
+
+static qboolean R_CanSeeBox(int numsamples, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
+{
+       int i;
+       vec3_t boxmins, boxmaxs;
+       vec3_t start;
+       vec3_t end;
+       dp_model_t *model = r_refdef.scene.worldmodel;
+       
+       if (!model || !model->brush.TraceLineOfSight)
+               return true;
+
+       // expand the box a little
+       boxmins[0] = (enlarge+1) * entboxmins[0] - enlarge * entboxmaxs[0];
+       boxmaxs[0] = (enlarge+1) * entboxmaxs[0] - enlarge * entboxmins[0];
+       boxmins[1] = (enlarge+1) * entboxmins[1] - enlarge * entboxmaxs[1];
+       boxmaxs[1] = (enlarge+1) * entboxmaxs[1] - enlarge * entboxmins[1];
+       boxmins[2] = (enlarge+1) * entboxmins[2] - enlarge * entboxmaxs[2];
+       boxmaxs[2] = (enlarge+1) * entboxmaxs[2] - enlarge * entboxmins[2];
+
+       // try center
+       VectorCopy(eye, start);
+       VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end);
+       if (model->brush.TraceLineOfSight(model, start, end))
+               return true;
+
+       // try various random positions
+       for (i = 0;i < numsamples;i++)
+       {
+               VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
+               if (model->brush.TraceLineOfSight(model, start, end))
+                       return true;
+       }
+
+       return false;
+}
+
+
 static void R_View_UpdateEntityVisible (void)
 {
        int i, renderimask;
@@ -3297,7 +3348,7 @@ static void R_View_UpdateEntityVisible (void)
                                ent = r_refdef.scene.entities[i];
                                if(r_refdef.viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & (RENDER_VIEWMODEL + RENDER_NOCULL)) && !(ent->model && (ent->model->name[0] == '*')))
                                {
-                                       if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.scene.worldmodel, r_refdef.view.origin, ent->mins, ent->maxs))
+                                       if(R_CanSeeBox(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.view.origin, ent->mins, ent->maxs))
                                                ent->last_trace_visibility = realtime;
                                        if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
                                                r_refdef.viewcache.entityvisible[i] = 0;
@@ -4073,6 +4124,9 @@ void R_Bloom_MakeTexture(void)
        brighten = r_bloom_brighten.value;
        if (r_hdr.integer)
                brighten *= r_hdr_range.value;
+       brighten = sqrt(brighten);
+       if(range >= 1)
+               brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
        R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
        R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0);
 
@@ -4080,6 +4134,7 @@ void R_Bloom_MakeTexture(void)
        {
                // blend on at multiple vertical offsets to achieve a vertical blur
                // TODO: do offset blends using GLSL
+               // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
                GL_BlendFunc(GL_ONE, GL_ZERO);
                for (x = -range;x <= range;x++)
                {
@@ -4100,8 +4155,10 @@ void R_Bloom_MakeTexture(void)
                        // black at the edges
                        // (probably not realistic but looks good enough)
                        //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
-                       //r = (dir ? 1.0f : brighten)/(range*2+1);
-                       r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range));
+                       //r = brighten/(range*2+1);
+                       r = brighten / (range * 2 + 1);
+                       if(range >= 1)
+                               r *= (1 - x*x/(float)(range*range));
                        GL_Color(r, r, r, 1);
                        R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
                        r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
@@ -5368,6 +5425,33 @@ void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *t
        Matrix4x4_Concat(texmatrix, &matrix, &temp);
 }
 
+void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
+{
+       int textureflags = TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP | TEXF_COMPRESS;
+       char name[MAX_QPATH];
+       skinframe_t *skinframe;
+       unsigned char pixels[296*194];
+       strlcpy(cache->name, skinname, sizeof(cache->name));
+       dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
+       if (developer_loading.integer)
+               Con_Printf("loading %s\n", name);
+       skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
+       if (!skinframe || !skinframe->base)
+       {
+               unsigned char *f;
+               fs_offset_t filesize;
+               skinframe = NULL;
+               f = FS_LoadFile(name, tempmempool, true, &filesize);
+               if (f)
+               {
+                       if (LoadPCX_QWSkin(f, filesize, pixels, 296, 194))
+                               skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
+                       Mem_Free(f);
+               }
+       }
+       cache->skinframe = skinframe;
+}
+
 texture_t *R_GetCurrentTexture(texture_t *t)
 {
        int i;
@@ -5410,14 +5494,16 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        // update currentskinframe to be a qw skin or animation frame
        if ((i = ent->entitynumber - 1) >= 0 && i < cl.maxclients && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[i].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl"))
        {
-               if (strcmp(r_qwskincache[i], cl.scores[i].qw_skin))
+               if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
                {
-                       strlcpy(r_qwskincache[i], cl.scores[i].qw_skin, sizeof(r_qwskincache[i]));
-                       if (developer_loading.integer)
-                               Con_Printf("loading skins/%s\n", r_qwskincache[i]);
-                       r_qwskincache_skinframe[i] = R_SkinFrame_LoadExternal(va("skins/%s", r_qwskincache[i]), TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP | TEXF_COMPRESS, developer.integer > 0);
+                       r_qwskincache_size = cl.maxclients;
+                       if (r_qwskincache)
+                               Mem_Free(r_qwskincache);
+                       r_qwskincache = Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
                }
-               t->currentskinframe = r_qwskincache_skinframe[i];
+               if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
+                       R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
+               t->currentskinframe = r_qwskincache[i].skinframe;
                if (t->currentskinframe == NULL)
                        t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->shadertime)) % t->numskinframes];
        }