/* 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 See file, 'COPYING', for details. */ #pragma once #include #include #include // for faceextents_t #include namespace img { struct texture; } struct mbsp_t; struct mface_t; constexpr float LIGHT_ON_EPSILON = 0.1f; constexpr float LIGHT_ANGLE_EPSILON = 0.01f; constexpr float LIGHT_EQUAL_EPSILON = 0.001f; // FIXME: use maximum dimension of level constexpr float MAX_SKY_DIST = 1000000; struct lightsample_t { qvec3f color; qvec3f direction; }; // CHECK: isn't average a bad algorithm for color brightness? template constexpr float LightSample_Brightness(const T &color) { return ((color[0] + color[1] + color[2]) / 3.0); } /** * A directional light, emitted from "sky*" textured faces. */ class sun_t { public: qvec3f sunvec; float sunlight; qvec3f sunlight_color; bool dirt; float anglescale; int style; std::string suntexture; const img::texture *suntexture_value; }; class modelinfo_t; namespace settings { class worldspawn_keys; }; class lightmap_t { public: int style; std::vector samples; qvec3f bounce_color; }; using lightmapdict_t = std::vector; struct surfacelight_t; class raystream_occlusion_t; class raystream_intersection_t; struct lightsurf_t { const settings::worldspawn_keys *cfg; const modelinfo_t *modelinfo; const mbsp_t *bsp; const mface_t *face; /* these take precedence the values in modelinfo */ float minlight, maxlight, lightcolorscale = 1.0; float surflight_minlight_scale = 1.0; qvec3f minlight_color; bool nodirt, minlightMottle; bool curved; /*normals are interpolated for smooth lighting*/ /* for lit water. receive light from either front or back. */ bool twosided; int32_t object_channel_mask; qplane3f plane; qvec3f snormal; qvec3f tnormal; /* 16 in vanilla. engines will hate you if this is not power-of-two-and-at-least-one */ float lightmapscale = 0.f; faceextents_t extents, vanilla_extents; // width * height sample points in world space struct sample_data_t { qvec3f point; qvec3f normal; bool occluded; int32_t realfacenum; /* raw ambient occlusion amount per sample point, 0-1, where 1 is fully occluded. dirtgain/dirtscale are not applied yet */ float occlusion; }; std::vector samples; /* pvs for the entire light surface. generated by ORing together the pvs at each of the sample points */ std::vector pvs; std::vector leaves; // output width * extra int width; // output height * extra int height; lightmapdict_t lightmapsByStyle; // surface light stuff std::unique_ptr vpl; }; /* debug */ enum class debugmodes { none = 0, phong, phong_obj, dirt, bounce, bouncelights, debugoccluded, debugneighbours, phong_tangents, phong_bitangents, mottle }; enum class lightfile { none = 0, external = 1, bspx = 2, both = external | bspx, lit2 = 4, hdr = 8, bspxhdr = 16, }; /* tracelist is a std::vector of pointers to modelinfo_t to use for LOS tests */ extern std::vector tracelist; extern std::vector selfshadowlist; extern std::vector shadowworldonlylist; extern std::vector switchableshadowlist; extern int numDirtVectors; // other flags extern bool dirt_in_use; // should any dirtmapping take place? set in SetupDirt constexpr qvec3f vec3_white{255}; extern int dump_facenum; extern int dump_vertnum; constexpr int CHANNEL_MASK_DEFAULT = 1; class modelinfo_t : public settings::setting_container { public: static constexpr float DEFAULT_PHONG_ANGLE = 89.0; public: const mbsp_t *bsp; const dmodelh2_t *model; float lightmapscale; qvec3f offset; settings::setting_scalar minlight; // zero will apply no clamping; use lightignore instead to do that. // above zero, this controls the clamp value on the light, default 255 settings::setting_scalar maxlight; settings::setting_bool minlightMottle; settings::setting_scalar shadow; settings::setting_scalar shadowself; settings::setting_scalar shadowworldonly; settings::setting_scalar switchableshadow; settings::setting_int32 switchshadstyle; settings::setting_scalar dirt; settings::setting_scalar phong; settings::setting_scalar phong_angle; settings::setting_scalar alpha; settings::setting_color minlight_color; settings::setting_bool lightignore; settings::setting_scalar lightcolorscale; settings::setting_int32 object_channel_mask; settings::setting_scalar surflight_minlight_scale; settings::setting_scalar surflight_atten; settings::setting_bool autominlight; settings::setting_string autominlight_target; float getResolvedPhongAngle() const; bool isWorld() const; modelinfo_t(const mbsp_t *b, const dmodelh2_t *m, float lmscale); }; enum class visapprox_t { NONE, AUTO, VIS, RAYS }; enum class emissivequality_t { LOW, MEDIUM, HIGH }; enum class lightgrid_format_t { OCTREE }; // // worldspawn keys / command-line settings // enum { // Q1-style surface light copies SURFLIGHT_Q1 = 0, // Q2/Q3-style radiosity SURFLIGHT_RAD = 1 }; namespace settings { extern setting_group worldspawn_group; class worldspawn_keys : public virtual setting_container { public: setting_scalar scaledist; setting_scalar rangescale; setting_scalar global_anglescale; setting_scalar lightmapgamma; setting_bool addminlight; setting_scalar minlight; setting_scalar minlightMottle; setting_scalar maxlight; setting_color minlight_color; setting_bool spotlightautofalloff; // start index for switchable light styles, default 32 setting_int32 compilerstyle_start; // max index for switchable light styles, default 64 setting_int32 compilerstyle_max; /* dirt */ setting_bool dirt; setting_scalar dirtmode; setting_scalar dirtdepth; setting_scalar dirtscale; setting_scalar dirtgain; setting_scalar dirtangle; setting_bool minlight_dirt; /* phong */ setting_bool phongallowed; setting_scalar phongangle; /* bounce */ setting_int32 bounce; setting_bool bouncestyled; setting_scalar bouncescale; setting_scalar bouncecolorscale; setting_scalar bouncelightsubdivision; /* Q2 surface lights (mxd) */ setting_scalar surflightscale; setting_scalar surflightskyscale; setting_scalar surflightskydist; // "choplight" - arghrad3 name setting_scalar surflightsubdivision; setting_scalar surflight_minlight_scale; setting_scalar surflight_atten; /* sunlight */ /* sun_light, sun_color, sun_angle for http://www.bspquakeeditor.com/arghrad/ compatibility */ setting_scalar sunlight; setting_color sunlight_color; setting_scalar sun2; setting_color sun2_color; setting_scalar sunlight2; setting_color sunlight2_color; setting_scalar sunlight3; setting_color sunlight3_color; setting_scalar sunlight_dirt; setting_scalar sunlight2_dirt; /* defaults to straight down */ setting_mangle sunvec; /* defaults to straight down */ setting_mangle sun2vec; setting_scalar sun_deviance; setting_color sky_surface; setting_int32 surflight_radiosity; worldspawn_keys(); }; extern setting_group output_group; extern setting_group debug_group; extern setting_group postprocessing_group; extern setting_group experimental_group; class light_settings : public common_settings, public worldspawn_keys { public: // slight modification to setting_numeric that supports // a default value if a non-number is supplied after parsing class setting_soft : public setting_int32 { public: using setting_int32::setting_int32; bool parse(const std::string &setting_name, parser_base_t &parser, source source) override; std::string format() const override; }; class setting_extra : public setting_value { public: using setting_value::setting_value; bool parse(const std::string &setting_name, parser_base_t &parser, source source) override; std::string string_value() const override; std::string format() const override; }; void CheckNoDebugModeSet(); setting_bool surflight_dump; setting_scalar surflight_subdivide; setting_bool onlyents; setting_bool write_normals; setting_bool novanilla; setting_scalar gate; setting_int32 sunsamples; setting_bool arghradcompat; setting_bool nolighting; setting_vec3 debugface; setting_vec3 debugvert; setting_bool highlightseams; setting_soft soft; setting_set radlights; setting_int32 lightmap_scale; setting_extra extra; setting_enum emissivequality; setting_enum visapprox; setting_func lit; setting_func lit2; setting_func bspxlit; setting_func lux; setting_func bspxlux; setting_func bspxonly; setting_func bspx; setting_func hdr; setting_func bspxhdr; setting_scalar world_units_per_luxel; setting_bool litonly; setting_bool nolights; setting_int32 facestyles; setting_bool exportobj; setting_int32 lmshift; setting_bool lightgrid; setting_vec3 lightgrid_dist; setting_enum lightgrid_format; setting_func dirtdebug; setting_func bouncedebug; setting_func bouncelightsdebug; setting_func phongdebug; setting_func phongdebug_obj; setting_func debugoccluded; setting_func debugneighbours; setting_func debugmottle; setting_bool debug_lightgrid_octree; light_settings(); fs::path sourceMap; bitflags write_litfile = lightfile::none; bitflags write_luxfile = lightfile::none; debugmodes debugmode = debugmodes::none; void set_parameters(int argc, const char **argv) override; void initialize(int argc, const char **argv) override; void reset() override; // nb: split out because we want to print the summary later // since light loads stuff from worldspawn void light_postinitialize(int argc, const char **argv); }; }; // namespace settings extern settings::light_settings light_options; const std::unordered_map> &UncompressedVis(); bool IsOutputtingSupplementaryData(); std::span &LightSurfaces(); std::vector &EmissiveLightSurfaces(); extern std::vector extended_texinfo_flags; lightmap_t *Lightmap_ForStyle(lightmapdict_t *lightmaps, const int style, const lightsurf_t *lightsurf); // public functions void FixupGlobalSettings(); const modelinfo_t *ModelInfoForModel(const mbsp_t *bsp, int modelnum); /** * returns nullptr for "skip" faces */ const modelinfo_t *ModelInfoForFace(const mbsp_t *bsp, int facenum); const img::texture *Face_Texture(const mbsp_t *bsp, const mface_t *face); const qvec3b &Face_LookupTextureColor(const mbsp_t *bsp, const mface_t *face); const qvec3f &Face_LookupTextureBounceColor(const mbsp_t *bsp, const mface_t *face); void light_reset(); int light_main(int argc, const char **argv); int light_main(const std::vector &args);