/* 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include constexpr vec_t ON_EPSILON = 0.1; constexpr vec_t ANGLE_EPSILON = 0.001; constexpr vec_t EQUAL_EPSILON = 0.001; // FIXME: use maximum dimension of level constexpr vec_t MAX_SKY_DIST = 1000000; struct lightsample_t { qvec3d color, 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: qvec3d sunvec; vec_t sunlight; qvec3d sunlight_color; bool dirt; float anglescale; int style; std::string suntexture; }; /* for vanilla this would be 18. some engines allow higher limits though, which will be needed if we're scaling lightmap * resolution. */ /*with extra sampling, lit+lux etc, we need at least 46mb space per thread. yes, that's a lot. on the plus side, * it doesn't affect bsp complexity (actually, can simplify it a little)*/ constexpr size_t MAXDIMENSION = 255 + 1; struct texorg_t { qmat4x4f texSpaceToWorld; const gtexinfo_t *texinfo; vec_t planedist; }; class modelinfo_t; class globalconfig_t; class lightmap_t { public: int style; lightsample_t *samples; // new'ed array of numpoints //FIXME: this is stupid, we shouldn't need to allocate // extra data here for -extra4 }; using lightmapdict_t = std::vector; /*Warning: this stuff needs explicit initialisation*/ struct lightsurf_t { const globalconfig_t *cfg; const modelinfo_t *modelinfo; const mbsp_t *bsp; const mface_t *face; /* these take precedence the values in modelinfo */ vec_t minlight; qvec3d minlight_color; bool nodirt; qplane3d plane; qvec3d snormal; qvec3d tnormal; /* 16 in vanilla. engines will hate you if this is not power-of-two-and-at-least-one */ float lightmapscale; bool curved; /*normals are interpolated for smooth lighting*/ int texmins[2]; int texsize[2]; qvec2d exactmid; qvec3d midpoint; int numpoints; qvec3d *points; // new'ed array of numpoints qvec3d *normals; // new'ed array of numpoints bool *occluded; // new'ed array of numpoints int *realfacenums; // new'ed array of numpoints /* raw ambient occlusion amount per sample point, 0-1, where 1 is fully occluded. dirtgain/dirtscale are not applied yet */ float *occlusion; // new'ed array of numpoints /* for sphere culling */ qvec3d origin; vec_t radius; /* for AABB culling */ aabb3d bounds = qvec3d(0); // for radiosity qvec3d radiosity; qvec3d texturecolor; /* stuff used by CalcPoint */ texorg_t texorg; int width, height; /* for lit water. receive light from either front or back. */ bool twosided; // ray batch stuff raystream_occlusion_t *occlusion_stream; raystream_intersection_t *intersection_stream; lightmapdict_t lightmapsByStyle; }; /* debug */ extern bool debug_highlightseams; enum debugmode_t { debugmode_none = 0, debugmode_phong, debugmode_phong_obj, debugmode_dirt, debugmode_bounce, debugmode_bouncelights, debugmode_debugoccluded, debugmode_debugneighbours, debugmode_phong_tangents, debugmode_phong_bitangents }; extern debugmode_t debugmode; /* 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 extern float fadegate; extern int softsamples; constexpr qvec3d vec3_white { 255 }; extern float surflight_subdivide; extern int sunsamples; extern int dump_facenum; extern bool dump_face; extern int dump_vertnum; extern bool dump_vert; extern bool arghradcompat; // mxd class modelinfo_t { static constexpr vec_t DEFAULT_PHONG_ANGLE = 89.0; using strings = std::vector; public: const mbsp_t *bsp; const dmodelh2_t *model; float lightmapscale; qvec3d offset{}; lockable_vec_t minlight{"minlight", 0}; lockable_vec_t shadow{"shadow", 0}; lockable_vec_t shadowself{strings{"shadowself", "selfshadow"}, 0}; lockable_vec_t shadowworldonly{"shadowworldonly", 0}; lockable_vec_t switchableshadow{"switchableshadow", 0}; lockable_vec_t switchshadstyle{"switchshadstyle", 0}; lockable_vec_t dirt{"dirt", 0}; lockable_vec_t phong{"phong", 0}; lockable_vec_t phong_angle{"phong_angle", 0}; lockable_vec_t alpha{"alpha", 1.0}; lockable_vec3_t minlight_color{ strings{"minlight_color", "mincolor"}, 255.0, 255.0, 255.0, vec3_transformer_t::NORMALIZE_COLOR_TO_255}; lockable_bool_t lightignore{"lightignore", false}; float getResolvedPhongAngle() const { const float s = phong_angle.floatValue(); if (s != 0) { return s; } if (phong.intValue() > 0) { return DEFAULT_PHONG_ANGLE; } return 0; } bool isWorld() const { return &bsp->dmodels[0] == model; } modelinfo_t(const mbsp_t *b, const dmodelh2_t *m, float lmscale) : bsp{b}, model{m}, lightmapscale{lmscale} { } settingsdict_t settings() { return {{&minlight, &shadow, &shadowself, &shadowworldonly, &switchableshadow, &switchshadstyle, &dirt, &phong, &phong_angle, &alpha, &minlight_color, &lightignore}}; } }; // // worldspawn keys / command-line settings // class globalconfig_t { using strings = std::vector; public: lockable_vec_t scaledist{"dist", 1.0, 0.0, 100.0}; lockable_vec_t rangescale{"range", 0.5, 0.0, 100.0}; lockable_vec_t global_anglescale{strings{"anglescale", "anglesense"}, 0.5, 0.0, 1.0}; lockable_vec_t lightmapgamma{"gamma", 1.0, 0.0, 100.0}; lockable_bool_t addminlight{"addmin", false}; lockable_vec_t minlight{strings{"light", "minlight"}, 0}; lockable_vec3_t minlight_color{ strings{"minlight_color", "mincolor"}, 255.0, 255.0, 255.0, vec3_transformer_t::NORMALIZE_COLOR_TO_255}; lockable_bool_t spotlightautofalloff{"spotlightautofalloff", false}; // mxd lockable_vec_t compilerstyle_start{ "compilerstyle_start", 32}; // start index for switchable light styles, default 32 (FIXME: should be int) /* dirt */ lockable_bool_t globalDirt{ strings{"dirt", "dirty"}, false}; // apply dirt to all lights (unless they override it) + sunlight + minlight? lockable_vec_t dirtMode{"dirtmode", 0.0f}; lockable_vec_t dirtDepth{"dirtdepth", 128.0, 1.0, std::numeric_limits::infinity()}; lockable_vec_t dirtScale{"dirtscale", 1.0, 0.0, 100.0}; lockable_vec_t dirtGain{"dirtgain", 1.0, 0.0, 100.0}; lockable_vec_t dirtAngle{"dirtangle", 88.0, 0.0, 90.0}; lockable_bool_t minlightDirt{"minlight_dirt", false}; // apply dirt to minlight? /* phong */ lockable_bool_t phongallowed{"phong", true}; lockable_vec_t phongangle{"phong_angle", 0}; /* bounce */ lockable_bool_t bounce{"bounce", false}; lockable_bool_t bouncestyled{"bouncestyled", false}; lockable_vec_t bouncescale{"bouncescale", 1.0, 0.0, 100.0}; lockable_vec_t bouncecolorscale{"bouncecolorscale", 0.0, 0.0, 1.0}; /* Q2 surface lights (mxd) */ lockable_vec_t surflightscale{"surflightscale", 0.3}; // Strange defaults to match arghrad3 look... lockable_vec_t surflightbouncescale{"surflightbouncescale", 0.1}; lockable_vec_t surflightsubdivision{ strings{"surflightsubdivision", "choplight"}, 16.0, 1.0, 8192.0}; // "choplight" - arghrad3 name /* sunlight */ /* sun_light, sun_color, sun_angle for http://www.bspquakeeditor.com/arghrad/ compatibility */ lockable_vec_t sunlight{strings{"sunlight", "sun_light"}, 0.0}; /* main sun */ lockable_vec3_t sunlight_color{ strings{"sunlight_color", "sun_color"}, 255.0, 255.0, 255.0, vec3_transformer_t::NORMALIZE_COLOR_TO_255}; lockable_vec_t sun2{"sun2", 0.0}; /* second sun */ lockable_vec3_t sun2_color{"sun2_color", 255.0, 255.0, 255.0, vec3_transformer_t::NORMALIZE_COLOR_TO_255}; lockable_vec_t sunlight2{"sunlight2", 0.0}; /* top sky dome */ lockable_vec3_t sunlight2_color{ strings{"sunlight2_color", "sunlight_color2"}, 255.0, 255.0, 255.0, vec3_transformer_t::NORMALIZE_COLOR_TO_255}; lockable_vec_t sunlight3{"sunlight3", 0.0}; /* bottom sky dome */ lockable_vec3_t sunlight3_color{ strings{"sunlight3_color", "sunlight_color3"}, 255.0, 255.0, 255.0, vec3_transformer_t::NORMALIZE_COLOR_TO_255}; lockable_vec_t sunlight_dirt{"sunlight_dirt", 0.0}; lockable_vec_t sunlight2_dirt{"sunlight2_dirt", 0.0}; lockable_vec3_t sunvec{strings{"sunlight_mangle", "sun_mangle", "sun_angle"}, 0.0, -90.0, 0.0, vec3_transformer_t::MANGLE_TO_VEC}; /* defaults to straight down */ lockable_vec3_t sun2vec{ "sun2_mangle", 0.0, -90.0, 0.0, vec3_transformer_t::MANGLE_TO_VEC}; /* defaults to straight down */ lockable_vec_t sun_deviance{"sunlight_penumbra", 0.0, 0.0, 180.0}; lockable_vec3_t sky_surface{ strings{"sky_surface", "sun_surface"}, 0, 0, 0} /* arghrad surface lights on sky faces */; settingsdict_t settings() { return {{&scaledist, &rangescale, &global_anglescale, &lightmapgamma, &addminlight, &minlight, &minlight_color, &spotlightautofalloff, // mxd &compilerstyle_start, &globalDirt, &dirtMode, &dirtDepth, &dirtScale, &dirtGain, &dirtAngle, &minlightDirt, &phongallowed, &bounce, &bouncestyled, &bouncescale, &bouncecolorscale, &surflightscale, &surflightbouncescale, &surflightsubdivision, // mxd &sunlight, &sunlight_color, &sun2, &sun2_color, &sunlight2, &sunlight2_color, &sunlight3, &sunlight3_color, &sunlight_dirt, &sunlight2_dirt, &sunvec, &sun2vec, &sun_deviance, &sky_surface}}; } }; extern uint8_t *filebase; extern uint8_t *lit_filebase; extern uint8_t *lux_filebase; extern int oversample; extern int write_litfile; extern int write_luxfile; extern bool onlyents; extern bool scaledonly; extern std::vector extended_texinfo_flags; extern bool novisapprox; extern bool nolights; extern bool litonly; extern bool skiplighting; extern bool write_normals; extern bool surflight_dump; extern std::filesystem::path mapfilename; // public functions lockable_setting_t *FindSetting(std::string name); void SetGlobalSetting(std::string name, std::string value, bool cmdline); void FixupGlobalSettings(void); void GetFileSpace(uint8_t **lightdata, uint8_t **colordata, uint8_t **deluxdata, int size); void GetFileSpace_PreserveOffsetInBsp(uint8_t **lightdata, uint8_t **colordata, uint8_t **deluxdata, int lightofs); 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); int light_main(int argc, const char **argv);