diff --git a/include/light/entities.hh b/include/light/entities.hh index ba81511a..b92d0126 100644 --- a/include/light/entities.hh +++ b/include/light/entities.hh @@ -75,6 +75,7 @@ public: lockable_vec_t light, atten, formula, spotangle, spotangle2, style, anglescale; lockable_vec_t dirtscale, dirtgain, dirt, deviance, samples, projfov, bouncescale; lockable_vec_t dirt_off_radius, dirt_on_radius; + lockable_vec_t sun; //mxd lockable_bool_t bleed; lockable_vec3_t origin, color, mangle, projangle; lockable_string_t project_texture; @@ -111,6 +112,7 @@ public: bouncescale { "bouncescale", 1.0f }, dirt_off_radius { "dirt_off_radius", 0.0f }, dirt_on_radius { "dirt_on_radius", 0.0f }, + sun { "sun", 0 }, //mxd bleed { "bleed", false }, origin { "origin", 0, 0, 0 }, color { "color", 255.0f, 255.0f, 255.0f, vec3_transformer_t::NORMALIZE_COLOR_TO_255 }, @@ -130,6 +132,7 @@ public: &light, &atten, &formula, &spotangle, &spotangle2, &style, &bleed, &anglescale, &dirtscale, &dirtgain, &dirt, &deviance, &samples, &projfov, &bouncescale, &dirt_off_radius, &dirt_on_radius, + &sun, //mxd &origin, &color, &mangle, &projangle, &project_texture }}; } diff --git a/light/entities.cc b/light/entities.cc index 63f0cb7f..d606aebe 100644 --- a/light/entities.cc +++ b/light/entities.cc @@ -386,7 +386,7 @@ Dirt_ResolveFlag(const globalconfig_t &cfg, int dirtInt) * ============= */ static void -AddSun(const globalconfig_t &cfg, vec3_t sunvec, vec_t light, const vec3_t color, int dirtInt) +AddSun(const globalconfig_t &cfg, vec3_t sunvec, vec_t light, const vec3_t color, int dirtInt, float sun_anglescale) { if (light == 0.0f) return; @@ -397,7 +397,7 @@ AddSun(const globalconfig_t &cfg, vec3_t sunvec, vec_t light, const vec3_t color VectorScale(sun.sunvec, -16384, sun.sunvec); sun.sunlight = light; VectorCopy(color, sun.sunlight_color); - sun.anglescale = cfg.global_anglescale.floatValue(); + sun.anglescale = sun_anglescale; sun.dirt = Dirt_ResolveFlag(cfg, dirtInt); // add to list @@ -422,17 +422,13 @@ AddSun(const globalconfig_t &cfg, vec3_t sunvec, vec_t light, const vec3_t color * ============= */ static void -SetupSun(const globalconfig_t &cfg, vec_t light, const vec3_t color, const vec3_t sunvec_in) +SetupSun(const globalconfig_t &cfg, vec_t light, const vec3_t color, const vec3_t sunvec_in, const float sun_anglescale, const float sun_deviance, const int sunlight_dirt) { vec3_t sunvec; int i; - int sun_num_samples = sunsamples; - - if (cfg.sun_deviance.floatValue() == 0) { - sun_num_samples = 1; - } else { - logprint("using _sunlight_penumbra of %f degrees from worldspawn.\n", cfg.sun_deviance.floatValue()); - } + int sun_num_samples = (sun_deviance == 0 ? 1 : sunsamples); //mxd + float sun_deviance_rad = DEG2RAD(sun_deviance); //mxd + float sun_deviance_sq = sun_deviance * sun_deviance; //mxd VectorCopy(sunvec_in, sunvec); VectorNormalize(sunvec); @@ -460,10 +456,10 @@ SetupSun(const globalconfig_t &cfg, vec_t light, const vec3_t color, const vec3_ /* jitter the angles (loop to keep random sample within sun->deviance steridians) */ do { - da = ( Random() * 2.0f - 1.0f ) * DEG2RAD(cfg.sun_deviance.floatValue()); - de = ( Random() * 2.0f - 1.0f ) * DEG2RAD(cfg.sun_deviance.floatValue()); + da = ( Random() * 2.0f - 1.0f ) * sun_deviance_rad; + de = ( Random() * 2.0f - 1.0f ) * sun_deviance_rad; } - while ( ( da * da + de * de ) > ( cfg.sun_deviance.floatValue() * cfg.sun_deviance.floatValue() ) ); + while ( ( da * da + de * de ) > sun_deviance_sq ); angle += da; elevation += de; @@ -475,18 +471,42 @@ SetupSun(const globalconfig_t &cfg, vec_t light, const vec3_t color, const vec3_ //printf( "sun %d is using vector %f %f %f\n", i, direction[0], direction[1], direction[2]); - AddSun(cfg, direction, light, color, cfg.sunlight_dirt.intValue()); + AddSun(cfg, direction, light, color, sunlight_dirt, sun_anglescale); } } static void SetupSuns(const globalconfig_t &cfg) { - SetupSun(cfg, cfg.sunlight.floatValue(), *cfg.sunlight_color.vec3Value(), *cfg.sunvec.vec3Value()); + for (light_t &entity : all_lights) { + //mxd. Arghrad-style sun setup + if (entity.sun.intValue() == 1 && entity.light.intValue() > 0) { + // Set sun vector + vec3_t sunvec; + if (entity.targetent) { + vec3_t target_pos; + EntDict_VectorForKey(*entity.targetent, "origin", target_pos); + VectorSubtract(target_pos, *entity.origin.vec3Value(), sunvec); + } else if (VectorLengthSq(*entity.mangle.vec3Value()) > 0) { + VectorCopy(*entity.mangle.vec3Value(), sunvec); + } else { // Use { 0, 0, 0 } as sun target... + logprint("WARNING: sun missing target, { 0 0 0 } used.\n"); + VectorCopy(*entity.origin.vec3Value(), sunvec); + } + + // Add the sun + SetupSun(cfg, entity.light.floatValue(), *entity.color.vec3Value(), sunvec, entity.anglescale.floatValue(), entity.deviance.floatValue(), entity.dirt.intValue()); + + // Disable the light itself... + entity.light.setFloatValue(0.0f); + } + } + + SetupSun(cfg, cfg.sunlight.floatValue(), *cfg.sunlight_color.vec3Value(), *cfg.sunvec.vec3Value(), cfg.global_anglescale.floatValue(), cfg.sun_deviance.floatValue(), cfg.sunlight_dirt.intValue()); if (cfg.sun2.floatValue() != 0) { logprint("creating sun2\n"); - SetupSun(cfg, cfg.sun2.floatValue(), *cfg.sun2_color.vec3Value(), *cfg.sun2vec.vec3Value()); + SetupSun(cfg, cfg.sun2.floatValue(), *cfg.sun2_color.vec3Value(), *cfg.sun2vec.vec3Value(), cfg.global_anglescale.floatValue(), cfg.sun_deviance.floatValue(), cfg.sunlight_dirt.intValue()); } } @@ -552,14 +572,14 @@ SetupSkyDome(const globalconfig_t &cfg) /* insert top hemisphere light */ if (sunlight2value > 0) { - AddSun(cfg, direction, sunlight2value, *cfg.sunlight2_color.vec3Value(), cfg.sunlight2_dirt.intValue()); + AddSun(cfg, direction, sunlight2value, *cfg.sunlight2_color.vec3Value(), cfg.sunlight2_dirt.intValue(), cfg.global_anglescale.floatValue()); } direction[ 2 ] = -direction[ 2 ]; /* insert bottom hemisphere light */ if (sunlight3value > 0) { - AddSun(cfg, direction, sunlight3value, *cfg.sunlight3_color.vec3Value(), cfg.sunlight2_dirt.intValue()); + AddSun(cfg, direction, sunlight3value, *cfg.sunlight3_color.vec3Value(), cfg.sunlight2_dirt.intValue(), cfg.global_anglescale.floatValue()); } /* move */ @@ -575,13 +595,13 @@ SetupSkyDome(const globalconfig_t &cfg) VectorSet( direction, 0.0f, 0.0f, -1.0f ); if (sunlight2value > 0) { - AddSun(cfg, direction, sunlight2value, *cfg.sunlight2_color.vec3Value(), cfg.sunlight2_dirt.intValue()); + AddSun(cfg, direction, sunlight2value, *cfg.sunlight2_color.vec3Value(), cfg.sunlight2_dirt.intValue(), cfg.global_anglescale.floatValue()); } VectorSet( direction, 0.0f, 0.0f, 1.0f ); if (sunlight3value > 0) { - AddSun(cfg, direction, sunlight3value, *cfg.sunlight3_color.vec3Value(), cfg.sunlight2_dirt.intValue()); + AddSun(cfg, direction, sunlight3value, *cfg.sunlight3_color.vec3Value(), cfg.sunlight2_dirt.intValue(), cfg.global_anglescale.floatValue()); } } diff --git a/man/light.1 b/man/light.1 index d6df28b8..1d906127 100644 --- a/man/light.1 +++ b/man/light.1 @@ -382,6 +382,21 @@ Specifies the yaw/pitch/roll angles for a texture projection (overriding mangle) .IP "\fB""_bouncescale"" ""n""\fP" Scales the amount of light that is contributed by bounces. Default is 1.0, 0.0 disables bounce lighting for this light. +.IP "\fB""_sun"" ""n""\fP" +Set to 1 to make this entity a sun, as an alternative to using the sunlight worldspawn keys. +If the light targets an info_null entity, the direction towards that entity sets sun direction. +The light itself is disabled, so it can be placed anywhere in the map. + +The following light properties correspond to these sunlight settings: +.nf + light => _sunlight + mangle => _sunlight_mangle + deviance => _sunlight_penumbra + _color => _sunlight_color + _dirt => _sunlight_dirt + _anglescale => _anglescale +.fi + .SH "OTHER INFORMATION" The "\\b" escape sequence toggles red text on/off, you can use this in any strings in the map file. e.g. "message" "Here is \\bsome red text\\b..." diff --git a/testmaps/suntest.map b/testmaps/suntest.map new file mode 100644 index 00000000..f85e4cdd --- /dev/null +++ b/testmaps/suntest.map @@ -0,0 +1,137 @@ +// Game: Quake +// Format: Standard +// entity 0 +{ +"classname" "worldspawn" +"wad" "free_wad.wad" +// brush 0 +{ +( -192 128 240 ) ( -192 129 240 ) ( -192 128 241 ) sky3 -192 -0 -0 1 1 +( 896 256 272 ) ( 896 256 273 ) ( 896 257 272 ) sky3 -192 -0 -0 1 1 +( -64 -192 240 ) ( -64 -192 241 ) ( -63 -192 240 ) sky3 -0 -0 -0 1 1 +( 64 992 272 ) ( 65 992 272 ) ( 64 992 273 ) sky3 -0 -0 -0 1 1 +( 64 256 288 ) ( 64 257 288 ) ( 65 256 288 ) sky3 -0 64 -0 1 1 +( -64 128 240 ) ( -63 128 240 ) ( -64 129 240 ) sky3 -0 64 -0 1 1 +} +// brush 1 +{ +( -192 96 208 ) ( -192 97 208 ) ( -192 96 209 ) sky3 -0 64 -0 1 1 +( -160 224 240 ) ( -160 224 241 ) ( -160 225 240 ) sky3 -0 64 -0 1 1 +( -64 -160 208 ) ( -64 -160 209 ) ( -63 -160 208 ) sky3 -0 64 -0 1 1 +( 64 960 240 ) ( 65 960 240 ) ( 64 960 241 ) sky3 -0 64 -0 1 1 +( 64 224 240 ) ( 64 225 240 ) ( 65 224 240 ) sky3 -0 64 -0 1 1 +( -64 96 -480 ) ( -63 96 -480 ) ( -64 97 -480 ) sky3 -0 64 -0 1 1 +} +// brush 2 +{ +( -192 128 208 ) ( -192 129 208 ) ( -192 128 209 ) sky3 -0 64 -0 1 1 +( 896 256 240 ) ( 896 256 241 ) ( 896 257 240 ) sky3 -0 64 -0 1 1 +( -64 960 208 ) ( -64 960 209 ) ( -63 960 208 ) sky3 -0 64 -0 1 1 +( 64 992 240 ) ( 65 992 240 ) ( 64 992 241 ) sky3 -0 64 -0 1 1 +( 64 256 240 ) ( 64 257 240 ) ( 65 256 240 ) sky3 -0 64 -0 1 1 +( -64 128 -480 ) ( -63 128 -480 ) ( -64 129 -480 ) sky3 -0 64 -0 1 1 +} +// brush 3 +{ +( -192 128 208 ) ( -192 129 208 ) ( -192 128 209 ) sky3 -0 64 -0 1 1 +( 896 256 240 ) ( 896 256 241 ) ( 896 257 240 ) sky3 -0 64 -0 1 1 +( -64 -192 208 ) ( -64 -192 209 ) ( -63 -192 208 ) sky3 -0 64 -0 1 1 +( 64 -160 240 ) ( 65 -160 240 ) ( 64 -160 241 ) sky3 -0 64 -0 1 1 +( 64 256 240 ) ( 64 257 240 ) ( 65 256 240 ) sky3 -0 64 -0 1 1 +( -64 128 -480 ) ( -63 128 -480 ) ( -64 129 -480 ) sky3 -0 64 -0 1 1 +} +// brush 4 +{ +( 864 96 208 ) ( 864 97 208 ) ( 864 96 209 ) sky3 -0 64 -0 1 1 +( 896 224 240 ) ( 896 224 241 ) ( 896 225 240 ) sky3 -0 64 -0 1 1 +( 992 -160 208 ) ( 992 -160 209 ) ( 993 -160 208 ) sky3 -0 64 -0 1 1 +( 1120 960 240 ) ( 1121 960 240 ) ( 1120 960 241 ) sky3 -0 64 -0 1 1 +( 1120 224 240 ) ( 1120 225 240 ) ( 1121 224 240 ) sky3 -0 64 -0 1 1 +( 992 96 -480 ) ( 993 96 -480 ) ( 992 97 -480 ) sky3 -0 64 -0 1 1 +} +// brush 5 +{ +( -192 128 -528 ) ( -192 129 -528 ) ( -192 128 -527 ) brownwirewall -192 -0 -0 1 1 +( 896 256 -496 ) ( 896 256 -495 ) ( 896 257 -496 ) brownwirewall -192 -0 -0 1 1 +( -64 -192 -528 ) ( -64 -192 -527 ) ( -63 -192 -528 ) brownwirewall -0 -0 -0 1 1 +( 64 992 -496 ) ( 65 992 -496 ) ( 64 992 -495 ) brownwirewall -0 -0 -0 1 1 +( 64 256 -480 ) ( 64 257 -480 ) ( 65 256 -480 ) brownwirewall -0 64 -0 1 1 +( -64 128 -528 ) ( -63 128 -528 ) ( -64 129 -528 ) brownwirewall -0 64 -0 1 1 +} +// brush 6 +{ +( 736 576 -480 ) ( 832 576 -448 ) ( 832 576 -480 ) brownwirewall -32 -0 -0 1 1 +( 736 832 -480 ) ( 736 960 -448 ) ( 736 832 -448 ) brownwirewall -0 -0 -0 1 1 +( 736 832 -480 ) ( 832 960 -480 ) ( 736 960 -480 ) brownwirewall -32 -0 -0 1 1 +( 736 832 -192 ) ( 832 960 -192 ) ( 832 832 -192 ) brownwirewall -32 -0 -0 1 1 +( 736 960 -480 ) ( 832 960 -448 ) ( 736 960 -448 ) brownwirewall -32 -0 -0 1 1 +( 864 832 -480 ) ( 864 960 -448 ) ( 864 960 -480 ) brownwirewall -0 -0 -0 1 1 +} +// brush 7 +{ +( 608 864 -480 ) ( 704 864 -448 ) ( 704 864 -480 ) brownwirewall -32 -0 -0 1 1 +( 256 832 -480 ) ( 256 960 -448 ) ( 256 832 -448 ) brownwirewall -0 -0 -0 1 1 +( 608 832 -480 ) ( 704 960 -480 ) ( 608 960 -480 ) brownwirewall -32 -0 -0 1 1 +( 608 832 -192 ) ( 704 960 -192 ) ( 704 832 -192 ) brownwirewall -32 -0 -0 1 1 +( 608 960 -480 ) ( 704 960 -448 ) ( 608 960 -448 ) brownwirewall -32 -0 -0 1 1 +( 736 832 -480 ) ( 736 960 -448 ) ( 736 960 -480 ) brownwirewall -0 -0 -0 1 1 +} +// brush 8 +{ +( 64 320 -480 ) ( 128 320 -448 ) ( 128 320 -480 ) swall1b 0 0 0 1 1 +( 64 320 -480 ) ( 64 448 -448 ) ( 64 320 -448 ) swall1b 0 0 0 1 1 +( 64 320 -480 ) ( 128 448 -480 ) ( 64 448 -480 ) swall1b 0 0 0 1 1 +( 64 320 -128 ) ( 128 448 -128 ) ( 128 320 -128 ) swall1b -0 -0 -0 1 1 +( 64 448 -480 ) ( 128 448 -448 ) ( 64 448 -448 ) swall1b 0 0 0 1 1 +( 128 320 -480 ) ( 128 448 -448 ) ( 128 448 -480 ) swall1b 0 0 0 1 1 +} +// brush 9 +{ +( 192 64 -480 ) ( 256 64 -448 ) ( 256 64 -480 ) swall1b -0 -0 -0 1 1 +( 192 64 -480 ) ( 192 192 -448 ) ( 192 64 -448 ) swall1b -0 -0 -0 1 1 +( 192 64 -480 ) ( 256 192 -480 ) ( 192 192 -480 ) swall1b -0 -0 -0 1 1 +( 192 64 -128 ) ( 256 192 -128 ) ( 256 64 -128 ) swall1b -0 -0 -0 1 1 +( 192 192 -480 ) ( 256 192 -448 ) ( 192 192 -448 ) swall1b -0 -0 -0 1 1 +( 256 64 -480 ) ( 256 192 -448 ) ( 256 192 -480 ) swall1b -0 -0 -0 1 1 +} +} +// entity 1 +{ +"classname" "light" +"origin" "712 872 -24" +"angle" "-0" +"_sun" "1" +"target" "sun1targ" +"light" "200" +"_color" "255 100 100" +} +// entity 2 +{ +"classname" "info_null" +"origin" "616 744 -472" +"angle" "-0" +"targetname" "sun1targ" +} +// entity 3 +{ +"classname" "info_player_start" +"origin" "144 560 -456" +"angle" "-0" +} +// entity 4 +{ +"classname" "light" +"origin" "88 600 -248" +"angle" "-0" +"_sun" "1" +"target" "sun2targ" +"light" "200" +"_color" "100 100 255" +} +// entity 5 +{ +"classname" "info_null" +"origin" "184 728 -344" +"angle" "180" +"targetname" "sun2targ" +}