cvar_t r_textshadow = {CVAR_SAVE, "r_textshadow", "0", "draws a shadow on all text to improve readability (note: value controls offset, 1 = 1 pixel, 1.5 = 1.5 pixels, etc)"};
cvar_t r_textbrightness = {CVAR_SAVE, "r_textbrightness", "0", "additional brightness for text color codes (0 keeps colors as is, 1 makes them all white)"};
-cachepic_t *r_crosshairs[NUMCROSSHAIRS+1];
-
//=============================================================================
/* Support Routines */
return R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, &buffer[0][0], TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
}
-static char *pointerimage =
- "333333332......."
- "26777761........"
- "2655541........."
- "265541.........."
- "2654561........."
- "26414561........"
- "251.14561......."
- "21...14561......"
- "1.....141......."
- ".......1........"
+static rtexture_t *draw_generateditherpattern(void)
+{
+ int x, y;
+ unsigned char pixels[8][8];
+ for (y = 0;y < 8;y++)
+ for (x = 0;x < 8;x++)
+ pixels[y][x] = ((x^y) & 4) ? 254 : 0;
+ return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, pixels[0], TEXTYPE_PALETTE, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
+}
+
+typedef struct embeddedpic_s
+{
+ const char *name;
+ int width;
+ int height;
+ const char *pixels;
+}
+embeddedpic_t;
+
+static embeddedpic_t embeddedpics[] =
+{
+ {
+ "gfx/prydoncursor001", 16, 16,
+ "477777774......."
+ "77.....6........"
+ "7.....6........."
+ "7....6.........."
+ "7.....6........."
+ "7..6...6........"
+ "7.6.6...6......."
+ "76...6...6......"
+ "4.....6.6......."
+ ".......6........"
"................"
"................"
"................"
"................"
"................"
"................"
-;
-
-static rtexture_t *draw_generatemousepointer(void)
-{
- int i;
- unsigned char buffer[256][4];
- for (i = 0;i < 256;i++)
+ },
{
- if (pointerimage[i] == '.')
- {
- buffer[i][0] = 0;
- buffer[i][1] = 0;
- buffer[i][2] = 0;
- buffer[i][3] = 0;
- }
- else
- {
- buffer[i][0] = (pointerimage[i] - '0') * 16;
- buffer[i][1] = (pointerimage[i] - '0') * 16;
- buffer[i][2] = (pointerimage[i] - '0') * 16;
- buffer[i][3] = 255;
- }
- }
- return R_LoadTexture2D(drawtexturepool, "mousepointer", 16, 16, &buffer[0][0], TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
-}
-
-static char *crosshairtexdata[NUMCROSSHAIRS] =
-{
+ "ui/mousepointer", 16, 16,
+ "477777774......."
+ "77.....6........"
+ "7.....6........."
+ "7....6.........."
+ "7.....6........."
+ "7..6...6........"
+ "7.6.6...6......."
+ "76...6...6......"
+ "4.....6.6......."
+ ".......6........"
+ "................"
+ "................"
+ "................"
+ "................"
+ "................"
+ "................"
+ },
+ {
+ "gfx/crosshair1", 16, 16,
"................"
"................"
"................"
"................"
"................"
"................"
- ,
+ },
+ {
+ "gfx/crosshair2", 16, 16,
"................"
"................"
"................"
"................"
"................"
"................"
- ,
+ },
+ {
+ "gfx/crosshair3", 16, 16,
"................"
".......77......."
".......77......."
".......77......."
".......77......."
"................"
- ,
+ },
+ {
+ "gfx/crosshair4", 16, 16,
"................"
"................"
"................"
"........7......."
"........7......."
"................"
- ,
- "................"
+ },
+ {
+ "gfx/crosshair5", 8, 8,
+ "........"
+ "........"
+ "....7..."
+ "........"
+ "..7.7.7."
+ "........"
+ "....7..."
+ "........"
+ },
+ {
+ "gfx/crosshair6", 2, 2,
+ "77"
+ "77"
+ },
+ {
+ "gfx/crosshair7", 16, 16,
"................"
+ ".3............3."
+ "..5...2332...5.."
+ "...7.3....3.7..."
+ "....7......7...."
+ "...3.7....7.3..."
+ "..2...7..7...2.."
+ "..3..........3.."
+ "..3..........3.."
+ "..2...7..7...2.."
+ "...3.7....7.3..."
+ "....7......7...."
+ "...7.3....3.7..."
+ "..5...2332...5.."
+ ".3............3."
"................"
+ },
+ {
+ "gfx/editlights/cursor", 16, 16,
"................"
+ ".3............3."
+ "..5...2332...5.."
+ "...7.3....3.7..."
+ "....7......7...."
+ "...3.7....7.3..."
+ "..2...7..7...2.."
+ "..3..........3.."
+ "..3..........3.."
+ "..2...7..7...2.."
+ "...3.7....7.3..."
+ "....7......7...."
+ "...7.3....3.7..."
+ "..5...2332...5.."
+ ".3............3."
"................"
- "........7......."
+ },
+ {
+ "gfx/editlights/light", 16, 16,
"................"
- "........4......."
- ".....7.4.4.7...."
- "........4......."
"................"
- "........7......."
+ "......1111......"
+ "....11233211...."
+ "...1234554321..."
+ "...1356776531..."
+ "..124677776421.."
+ "..135777777531.."
+ "..135777777531.."
+ "..124677776421.."
+ "...1356776531..."
+ "...1234554321..."
+ "....11233211...."
+ "......1111......"
"................"
"................"
+ },
+ {
+ "gfx/editlights/noshadow", 16, 16,
"................"
"................"
- ,
+ "......1111......"
+ "....11233211...."
+ "...1234554321..."
+ "...1356226531..."
+ "..12462..26421.."
+ "..1352....2531.."
+ "..1352....2531.."
+ "..12462..26421.."
+ "...1356226531..."
+ "...1234554321..."
+ "....11233211...."
+ "......1111......"
"................"
"................"
+ },
+ {
+ "gfx/editlights/selection", 16, 16,
"................"
+ ".777752..257777."
+ ".742........247."
+ ".72..........27."
+ ".7............7."
+ ".5............5."
+ ".2............2."
"................"
"................"
+ ".2............2."
+ ".5............5."
+ ".7............7."
+ ".72..........27."
+ ".742........247."
+ ".777752..257777."
"................"
+ },
+ {
+ "gfx/editlights/cubemaplight", 16, 16,
"................"
- ".......55......."
- ".......55......."
"................"
+ "......2772......"
+ "....27755772...."
+ "..277533335772.."
+ "..753333333357.."
+ "..777533335777.."
+ "..735775577537.."
+ "..733357753337.."
+ "..733337733337.."
+ "..753337733357.."
+ "..277537735772.."
+ "....27777772...."
+ "......2772......"
"................"
"................"
+ },
+ {
+ "gfx/editlights/cubemapnoshadowlight", 16, 16,
"................"
"................"
+ "......2772......"
+ "....27722772...."
+ "..2772....2772.."
+ "..72........27.."
+ "..7772....2777.."
+ "..7.27722772.7.."
+ "..7...2772...7.."
+ "..7....77....7.."
+ "..72...77...27.."
+ "..2772.77.2772.."
+ "....27777772...."
+ "......2772......"
"................"
"................"
+ },
+ {NULL, 0, 0, NULL}
};
-static rtexture_t *draw_generatecrosshair(int num)
+static rtexture_t *draw_generatepic(const char *name)
{
- int i;
- char *in;
- unsigned char data[16*16][4];
- in = crosshairtexdata[num];
- for (i = 0;i < 16*16;i++)
- {
- if (in[i] == '.')
- {
- data[i][0] = 255;
- data[i][1] = 255;
- data[i][2] = 255;
- data[i][3] = 0;
- }
- else
- {
- data[i][0] = data[i][1] = data[i][2] = (unsigned char) ((int) (in[i] - '0') * 127 / 7 + 128);
- data[i][3] = 255;
- }
- }
- return R_LoadTexture2D(drawtexturepool, va("crosshair%i", num+1), 16, 16, &data[0][0], TEXTYPE_BGRA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
+ embeddedpic_t *p;
+ for (p = embeddedpics;p->name;p++)
+ if (!strcmp(name, p->name))
+ return R_LoadTexture2D(drawtexturepool, p->name, p->width, p->height, (const unsigned char *)p->pixels, TEXTYPE_PALETTE, TEXF_ALPHA | TEXF_PRECACHE, palette_bgra_embeddedpic);
+ if (!strcmp(name, "gfx/conchars"))
+ return draw_generateconchars();
+ if (!strcmp(name, "gfx/colorcontrol/ditherpattern"))
+ return draw_generateditherpattern();
+ Con_Printf("Draw_CachePic: failed to load %s\n", name);
+ return r_texture_notexture;
}
-static rtexture_t *draw_generateditherpattern(void)
-{
-#if 1
- int x, y;
- unsigned char data[8*8*4];
- for (y = 0;y < 8;y++)
- {
- for (x = 0;x < 8;x++)
- {
- data[(y*8+x)*4+0] = data[(y*8+x)*4+1] = data[(y*8+x)*4+2] = ((x^y) & 4) ? 255 : 0;
- data[(y*8+x)*4+3] = 255;
- }
- }
- return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, data, TEXTYPE_BGRA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
-#else
- unsigned char data[16];
- memset(data, 255, sizeof(data));
- data[0] = data[1] = data[2] = data[12] = data[13] = data[14] = 0;
- return R_LoadTexture2D(drawtexturepool, "ditherpattern", 2, 2, data, TEXTYPE_BGRA, TEXF_FORCENEAREST | TEXF_PRECACHE, NULL);
-#endif
-}
/*
================
flags = TEXF_ALPHA;
if (persistent)
flags |= TEXF_PRECACHE;
- if (!strcmp(path, "gfx/colorcontrol/ditherpattern"))
+ if (strcmp(path, "gfx/colorcontrol/ditherpattern"))
flags |= TEXF_CLAMP;
if(allow_compression && gl_texturecompression_2d.integer)
flags |= TEXF_COMPRESS;
}
}
- // if it's not found on disk, check if it's one of the builtin images
+ // if it's not found on disk, generate an image
if (pic->tex == NULL)
{
- if (pic->tex == NULL && !strcmp(path, "gfx/conchars"))
- pic->tex = draw_generateconchars();
- if (pic->tex == NULL && !strcmp(path, "ui/mousepointer"))
- pic->tex = draw_generatemousepointer();
- if (pic->tex == NULL && !strcmp(path, "gfx/prydoncursor001"))
- pic->tex = draw_generatemousepointer();
- if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1"))
- pic->tex = draw_generatecrosshair(0);
- if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2"))
- pic->tex = draw_generatecrosshair(1);
- if (pic->tex == NULL && !strcmp(path, "gfx/crosshair3"))
- pic->tex = draw_generatecrosshair(2);
- if (pic->tex == NULL && !strcmp(path, "gfx/crosshair4"))
- pic->tex = draw_generatecrosshair(3);
- if (pic->tex == NULL && !strcmp(path, "gfx/crosshair5"))
- pic->tex = draw_generatecrosshair(4);
- if (pic->tex == NULL && !strcmp(path, "gfx/crosshair6"))
- pic->tex = draw_generatecrosshair(5);
- if (pic->tex == NULL && !strcmp(path, "gfx/colorcontrol/ditherpattern"))
- pic->tex = draw_generateditherpattern();
- // default textures for light sprites
- // todo: improve them
- if (pic->tex == NULL && !strcmp(path, "gfx/editlights/cursor"))
- pic->tex = draw_generatecrosshair(0);
- if (pic->tex == NULL && !strcmp(path, "gfx/editlights/light"))
- pic->tex = draw_generatecrosshair(0);
- if (pic->tex == NULL && !strcmp(path, "gfx/editlights/noshadow"))
- pic->tex = draw_generatecrosshair(0);
- if (pic->tex == NULL && !strcmp(path, "gfx/editlights/cubemap"))
- pic->tex = draw_generatecrosshair(0);
- if (pic->tex == NULL && !strcmp(path, "gfx/editlights/selection"))
- pic->tex = draw_generatecrosshair(0);
- if (pic->tex == NULL)
- {
- // don't complain about missing gfx/crosshair images
- if (strncmp(path, "gfx/crosshair", 13))
- Con_Printf("Draw_CachePic: failed to load %s\n", path);
- pic->tex = r_texture_notexture;
- }
+ pic->tex = draw_generatepic(path);
pic->width = R_TextureWidth(pic->tex);
pic->height = R_TextureHeight(pic->tex);
}
for(i = 0; i < MAX_FONTS; ++i)
LoadFont(false, va("gfx/font_%s", dp_fonts[i].title), &dp_fonts[i]);
- for (i = 1;i <= NUMCROSSHAIRS;i++)
- r_crosshairs[i] = Draw_CachePic(va("gfx/crosshair%i", i), true);
-
// draw the loading screen so people have something to see in the newly opened window
SCR_UpdateLoadingScreen(true);
}
+++ /dev/null
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-// r_light.c
-
-#include "quakedef.h"
-#include "cl_collision.h"
-#include "r_shadow.h"
-
-cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
-cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
-
-static rtexture_t *lightcorona;
-static rtexturepool_t *lighttexturepool;
-
-void r_light_start(void)
-{
- float dx, dy;
- int x, y, a;
- unsigned char pixels[32][32][4];
- lighttexturepool = R_AllocTexturePool();
- for (y = 0;y < 32;y++)
- {
- dy = (y - 15.5f) * (1.0f / 16.0f);
- for (x = 0;x < 32;x++)
- {
- dx = (x - 15.5f) * (1.0f / 16.0f);
- a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
- a = bound(0, a, 255);
- pixels[y][x][0] = a;
- pixels[y][x][1] = a;
- pixels[y][x][2] = a;
- pixels[y][x][3] = 255;
- }
- }
- lightcorona = R_LoadTexture2D(lighttexturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE, NULL);
-}
-
-void r_light_shutdown(void)
-{
- lighttexturepool = NULL;
- lightcorona = NULL;
-}
-
-void r_light_newmap(void)
-{
- int i;
- for (i = 0;i < MAX_LIGHTSTYLES;i++)
- r_refdef.lightstylevalue[i] = 256; // normal light value
-}
-
-void R_Light_Init(void)
-{
- Cvar_RegisterVariable(&r_coronas);
- Cvar_RegisterVariable(&gl_flashblend);
- R_RegisterModule("R_Light", r_light_start, r_light_shutdown, r_light_newmap);
-}
-
-void R_DrawCoronas(void)
-{
- int i, lnum, flag;
- float cscale, scale;
- dlight_t *light;
- rtlight_t *rtlight;
- if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
- return;
- R_Mesh_Matrix(&identitymatrix);
- flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
- // FIXME: these traces should scan all render entities instead of cl.world
- for (lnum = 0, light = r_shadow_worldlightchain;light;light = light->next, lnum++)
- {
- rtlight = &light->rtlight;
- if (!(rtlight->flags & flag))
- continue;
- if (rtlight->corona * r_coronas.value <= 0)
- continue;
- if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != lnum)
- continue;
- cscale = rtlight->corona * r_coronas.value* 0.25f;
- scale = rtlight->radius * rtlight->coronasizescale;
- if (VectorDistance2(rtlight->shadoworigin, r_view.origin) < 16.0f * 16.0f)
- continue;
- if (CL_Move(r_view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
- continue;
- R_DrawSprite(GL_ONE, GL_ONE, lightcorona, NULL, true, false, rtlight->shadoworigin, r_view.right, r_view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
- }
- for (i = 0;i < r_refdef.numlights;i++)
- {
- rtlight = &r_refdef.lights[i];
- if (!(rtlight->flags & flag))
- continue;
- if (rtlight->corona <= 0)
- continue;
- if (VectorDistance2(rtlight->shadoworigin, r_view.origin) < 32.0f * 32.0f)
- continue;
- if (gl_flashblend.integer)
- {
- cscale = rtlight->corona * 1.0f;
- scale = rtlight->radius * rtlight->coronasizescale * 2.0f;
- }
- else
- {
- cscale = rtlight->corona * r_coronas.value* 0.25f;
- scale = rtlight->radius * rtlight->coronasizescale;
- }
- if (VectorLength(rtlight->color) * cscale < (1.0f / 256.0f))
- continue;
- if (CL_Move(r_view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
- continue;
- R_DrawSprite(GL_ONE, GL_ONE, lightcorona, NULL, true, false, rtlight->shadoworigin, r_view.right, r_view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
- }
-}
-
-/*
-=============================================================================
-
-LIGHT SAMPLING
-
-=============================================================================
-*/
-
-void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
-{
- VectorClear(diffusecolor);
- VectorClear(diffusenormal);
-
- if (!r_fullbright.integer && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
- {
- ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_ambient.value * (2.0f / 128.0f);
- r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
- }
- else
- VectorSet(ambientcolor, 1, 1, 1);
-
- if (dynamic)
- {
- int i;
- float f, v[3];
- rtlight_t *light;
- for (i = 0;i < r_refdef.numlights;i++)
- {
- light = &r_refdef.lights[i];
- Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
- f = 1 - VectorLength2(v);
- if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
- VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
- }
- }
-}
rtexture_t *r_shadow_attenuationgradienttexture;
rtexture_t *r_shadow_attenuation2dtexture;
rtexture_t *r_shadow_attenuation3dtexture;
+rtexture_t *r_shadow_lightcorona;
// lights are reloaded when this changes
char r_shadow_mapname[MAX_QPATH];
cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
+cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
+cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
static float r_shadow_attentable[ATTENTABLESIZE+1];
rtlight_t *r_shadow_compilingrtlight;
-dlight_t *r_shadow_worldlightchain;
+static memexpandablearray_t r_shadow_worldlightsarray;
dlight_t *r_shadow_selectedlight;
dlight_t r_shadow_bufferlight;
vec3_t r_editlights_cursorlocation;
// VorteX: custom editor light sprites
#define EDLIGHTSPRSIZE 8
-#define EDLIGHTSELECTSPRSIZE 12
cachepic_t *r_editlights_sprcursor;
cachepic_t *r_editlights_sprlight;
cachepic_t *r_editlights_sprnoshadowlight;
-cachepic_t *r_editlights_sprcubemap;
+cachepic_t *r_editlights_sprcubemaplight;
+cachepic_t *r_editlights_sprcubemapnoshadowlight;
cachepic_t *r_editlights_sprselection;
void r_shadow_start(void)
Cvar_RegisterVariable(&r_shadow_polygonfactor);
Cvar_RegisterVariable(&r_shadow_polygonoffset);
Cvar_RegisterVariable(&r_shadow_texture3d);
+ Cvar_RegisterVariable(&r_coronas);
+ Cvar_RegisterVariable(&gl_flashblend);
Cvar_RegisterVariable(&gl_ext_separatestencil);
Cvar_RegisterVariable(&gl_ext_stenciltwoside);
if (gamemode == GAME_TENEBRAE)
}
Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
R_Shadow_EditLights_Init();
- r_shadow_worldlightchain = NULL;
+ Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
maxshadowtriangles = 0;
shadowelements = NULL;
maxshadowvertices = 0;
CHECKGLERROR
}
+static void R_Shadow_MakeTextures_MakeCorona(void)
+{
+ float dx, dy;
+ int x, y, a;
+ unsigned char pixels[32][32][4];
+ for (y = 0;y < 32;y++)
+ {
+ dy = (y - 15.5f) * (1.0f / 16.0f);
+ for (x = 0;x < 32;x++)
+ {
+ dx = (x - 15.5f) * (1.0f / 16.0f);
+ a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
+ a = bound(0, a, 255);
+ pixels[y][x][0] = a;
+ pixels[y][x][1] = a;
+ pixels[y][x][2] = a;
+ pixels[y][x][3] = 255;
+ }
+ }
+ r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE, NULL);
+}
+
static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
{
float dist = sqrt(x*x+y*y+z*z);
r_shadow_attenuation3dtexture = NULL;
Mem_Free(data);
+ R_Shadow_MakeTextures_MakeCorona();
+
// Editor light sprites
r_editlights_sprcursor = Draw_CachePic("gfx/editlights/cursor", true);
r_editlights_sprlight = Draw_CachePic("gfx/editlights/light", true);
r_editlights_sprnoshadowlight = Draw_CachePic("gfx/editlights/noshadow", true);
- r_editlights_sprcubemap = Draw_CachePic("gfx/editlights/cubemap", true);
+ r_editlights_sprcubemaplight = Draw_CachePic("gfx/editlights/cubemaplight", true);
+ r_editlights_sprcubemapnoshadowlight = Draw_CachePic("gfx/editlights/cubemapnoshadowlight", true);
r_editlights_sprselection = Draw_CachePic("gfx/editlights/selection", true);
}
void R_Shadow_UncompileWorldLights(void)
{
+ size_t lightindex;
dlight_t *light;
- for (light = r_shadow_worldlightchain;light;light = light->next)
+ for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
+ {
+ light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (!light)
+ continue;
R_RTLight_Uncompile(&light->rtlight);
+ }
}
void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
void R_Shadow_DrawLightSprites(void);
void R_ShadowVolumeLighting(qboolean visible)
{
- int lnum, flag;
+ int flag;
+ int lnum;
+ size_t lightindex;
dlight_t *light;
if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
if (r_shadow_debuglight.integer >= 0)
{
- for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
- if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
- R_DrawRTLight(&light->rtlight, visible);
+ lightindex = r_shadow_debuglight.integer;
+ light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (light && (light->flags & flag))
+ R_DrawRTLight(&light->rtlight, visible);
}
else
- for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
- if (light->flags & flag)
+ {
+ for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
+ {
+ light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (light && (light->flags & flag))
R_DrawRTLight(&light->rtlight, visible);
+ }
+ }
if (r_refdef.rtdlight)
for (lnum = 0;lnum < r_refdef.numlights;lnum++)
R_DrawRTLight(&r_refdef.lights[lnum], visible);
R_Shadow_RenderMode_End();
}
+void R_DrawCoronas(void)
+{
+ int i, flag;
+ float cscale, scale;
+ size_t lightindex;
+ dlight_t *light;
+ rtlight_t *rtlight;
+ if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
+ return;
+ R_Mesh_Matrix(&identitymatrix);
+ flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+ // FIXME: these traces should scan all render entities instead of cl.world
+ for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
+ {
+ light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (!light)
+ continue;
+ rtlight = &light->rtlight;
+ if (!(rtlight->flags & flag))
+ continue;
+ if (rtlight->corona * r_coronas.value <= 0)
+ continue;
+ if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
+ continue;
+ cscale = rtlight->corona * r_coronas.value* 0.25f;
+ scale = rtlight->radius * rtlight->coronasizescale;
+ if (VectorDistance2(rtlight->shadoworigin, r_view.origin) < 16.0f * 16.0f)
+ continue;
+ if (CL_Move(r_view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
+ continue;
+ R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_view.right, r_view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
+ }
+ for (i = 0;i < r_refdef.numlights;i++)
+ {
+ rtlight = &r_refdef.lights[i];
+ if (!(rtlight->flags & flag))
+ continue;
+ if (rtlight->corona <= 0)
+ continue;
+ if (VectorDistance2(rtlight->shadoworigin, r_view.origin) < 32.0f * 32.0f)
+ continue;
+ if (gl_flashblend.integer)
+ {
+ cscale = rtlight->corona * 1.0f;
+ scale = rtlight->radius * rtlight->coronasizescale * 2.0f;
+ }
+ else
+ {
+ cscale = rtlight->corona * r_coronas.value* 0.25f;
+ scale = rtlight->radius * rtlight->coronasizescale;
+ }
+ if (VectorLength(rtlight->color) * cscale < (1.0f / 256.0f))
+ continue;
+ if (CL_Move(r_view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
+ continue;
+ R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_view.right, r_view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
+ }
+}
+
+
//static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
typedef struct suffixinfo_s
dlight_t *R_Shadow_NewWorldLight(void)
{
- dlight_t *light;
- light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
- light->next = r_shadow_worldlightchain;
- r_shadow_worldlightchain = light;
- return light;
+ return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
}
void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
void R_Shadow_FreeWorldLight(dlight_t *light)
{
- dlight_t **lightpointer;
+ if (r_shadow_selectedlight == light)
+ r_shadow_selectedlight = NULL;
R_RTLight_Uncompile(&light->rtlight);
- for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
- if (*lightpointer != light)
- Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
- *lightpointer = light->next;
- Mem_Free(light);
+ Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
}
void R_Shadow_ClearWorldLights(void)
{
- while (r_shadow_worldlightchain)
- R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
+ size_t lightindex;
+ dlight_t *light;
+ for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
+ {
+ light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (light)
+ R_Shadow_FreeWorldLight(light);
+ }
r_shadow_selectedlight = NULL;
R_Shadow_FreeCubemaps();
}
void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
// this is never batched (there can be only one)
- R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_editlights_sprcursor->tex, NULL, false, false, r_editlights_cursorlocation, r_view.right, r_view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE, 1, 1, 1, 0.5f);
+ R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprcursor->tex, r_editlights_sprcursor->tex, false, false, r_editlights_cursorlocation, r_view.right, r_view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE, 1, 1, 1, 1);
}
void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
float intensity;
- float scaling;
+ float s;
vec3_t spritecolor;
+ cachepic_t *pic;
// this is never batched (due to the ent parameter changing every time)
// so numsurfaces == 1 and surfacelist[0] == lightnumber
const dlight_t *light = (dlight_t *)ent;
- intensity = 1;
- scaling = 1;
- if (light->selected)
- scaling = 1.25 + 0.25*sin(realtime * M_PI * 1.5);
- // vortex: get sprites color (solve 0 0 0 colored light being invisible here)
- spritecolor[0] = max(0.1, light->color[0]);
- spritecolor[1] = max(0.1, light->color[1]);
- spritecolor[2] = max(0.1, light->color[2]);
+ s = EDLIGHTSPRSIZE;
+ intensity = 0.5f;
+ VectorScale(light->color, intensity, spritecolor);
+ if (VectorLength(spritecolor) < 0.1732f)
+ VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
+ if (VectorLength(spritecolor) > 1.0f)
+ VectorNormalize(spritecolor);
// draw light sprite
- if (!light->shadow)
- {
- intensity *= 0.5f;
- R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_editlights_sprnoshadowlight->tex, NULL, false, false, light->origin, r_view.right, r_view.up, EDLIGHTSPRSIZE*scaling, -EDLIGHTSPRSIZE*scaling, -EDLIGHTSPRSIZE*scaling, EDLIGHTSPRSIZE*scaling, spritecolor[0]*intensity, spritecolor[1]*intensity, spritecolor[2]*intensity, 1);
- }
+ if (light->cubemapname[0] && !light->shadow)
+ pic = r_editlights_sprcubemapnoshadowlight;
+ else if (light->cubemapname[0])
+ pic = r_editlights_sprcubemaplight;
+ else if (!light->shadow)
+ pic = r_editlights_sprnoshadowlight;
else
- R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_editlights_sprlight->tex, NULL, false, false, light->origin, r_view.right, r_view.up, EDLIGHTSELECTSPRSIZE*scaling, -EDLIGHTSELECTSPRSIZE*scaling, -EDLIGHTSELECTSPRSIZE*scaling, EDLIGHTSELECTSPRSIZE*scaling, spritecolor[0]*intensity, spritecolor[1]*intensity, spritecolor[2]*intensity, 1);
- // draw cubemap sprite over light
- if (light->cubemapname[0])
- R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_editlights_sprcubemap->tex, NULL, false, false, light->origin, r_view.right, r_view.up, EDLIGHTSPRSIZE*scaling, -EDLIGHTSPRSIZE*scaling, -EDLIGHTSPRSIZE*scaling, EDLIGHTSPRSIZE*scaling, spritecolor[0]*intensity, spritecolor[1]*intensity, spritecolor[2]*intensity, 1);
+ pic = r_editlights_sprlight;
+ R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, pic->tex, pic->tex, false, false, light->origin, r_view.right, r_view.up, s, -s, -s, s, spritecolor[0], spritecolor[1], spritecolor[2], 1);
// draw selection sprite if light is selected
if (light->selected)
- R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_editlights_sprselection->tex, NULL, false, false, light->origin, r_view.right, r_view.up, EDLIGHTSPRSIZE*scaling, -EDLIGHTSPRSIZE*scaling, -EDLIGHTSPRSIZE*scaling, EDLIGHTSPRSIZE*scaling, spritecolor[0]*intensity, spritecolor[1]*intensity, spritecolor[2]*intensity, 1);
+ R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprselection->tex, r_editlights_sprselection->tex, false, false, light->origin, r_view.right, r_view.up, s, -s, -s, s, 1, 1, 1, 1);
// VorteX todo: add normalmode/realtime mode light overlay sprites?
}
void R_Shadow_DrawLightSprites(void)
{
- int i;
+ size_t lightindex;
dlight_t *light;
-
- for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
- R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
+ for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
+ {
+ light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (light)
+ R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
+ }
R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
}
void R_Shadow_SelectLightInView(void)
{
float bestrating, rating, temp[3];
- dlight_t *best, *light;
+ dlight_t *best;
+ size_t lightindex;
+ dlight_t *light;
best = NULL;
bestrating = 0;
- for (light = r_shadow_worldlightchain;light;light = light->next)
+ for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
{
+ light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (!light)
+ continue;
VectorSubtract(light->origin, r_view.origin, temp);
rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
if (rating >= 0.95)
void R_Shadow_SaveWorldLights(void)
{
+ size_t lightindex;
dlight_t *light;
size_t bufchars, bufmaxchars;
char *buf, *oldbuf;
char name[MAX_QPATH];
char line[MAX_INPUTLINE];
- if (!r_shadow_worldlightchain)
+ if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
return;
if (r_refdef.worldmodel == NULL)
{
strlcat (name, ".rtlights", sizeof (name));
bufchars = bufmaxchars = 0;
buf = NULL;
- for (light = r_shadow_worldlightchain;light;light = light->next)
+ for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
{
+ light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (!light)
+ continue;
if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
R_Shadow_ClearWorldLights();
R_Shadow_LoadWorldLights();
- if (r_shadow_worldlightchain == NULL)
+ if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
{
R_Shadow_LoadLightsFile();
- if (r_shadow_worldlightchain == NULL)
+ if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
}
}
void R_Shadow_EditLights_EditAll_f(void)
{
+ size_t lightindex;
dlight_t *light;
if (!r_editlights.integer)
return;
}
- for (light = r_shadow_worldlightchain;light;light = light->next)
+ for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
{
+ light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (!light)
+ continue;
R_Shadow_SelectLight(light);
R_Shadow_EditLights_Edit_f();
}
void R_Shadow_EditLights_DrawSelectedLightProperties(void)
{
int lightnumber, lightcount;
+ size_t lightindex;
dlight_t *light;
float x, y;
char temp[256];
DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
lightnumber = -1;
lightcount = 0;
- for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
+ for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
+ {
+ light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (!light)
+ continue;
if (light == r_shadow_selectedlight)
- lightnumber = lightcount;
+ lightnumber = lightindex;
+ lightcount++;
+ }
sprintf(temp, "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
- sprintf(temp, "Total lights : %i", lightcount); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
+ sprintf(temp, "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
y += 8;
if (r_shadow_selectedlight == NULL)
return;
Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");
}
+
+
+/*
+=============================================================================
+
+LIGHT SAMPLING
+
+=============================================================================
+*/
+
+void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
+{
+ VectorClear(diffusecolor);
+ VectorClear(diffusenormal);
+
+ if (!r_fullbright.integer && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
+ {
+ ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_ambient.value * (2.0f / 128.0f);
+ r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
+ }
+ else
+ VectorSet(ambientcolor, 1, 1, 1);
+
+ if (dynamic)
+ {
+ int i;
+ float f, v[3];
+ rtlight_t *light;
+ for (i = 0;i < r_refdef.numlights;i++)
+ {
+ light = &r_refdef.lights[i];
+ Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
+ f = 1 - VectorLength2(v);
+ if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
+ VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
+ }
+ }
+}