/* 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. */ #include float scaledist = 1.0; float rangescale = 0.5; int worldminlight = 0; int sunlight = 0; const vec3_t vec3_white = { 255, 255, 255 }; vec3_t minlight_color = { 255, 255, 255 }; /* defaults to white light */ vec3_t sunlight_color = { 255, 255, 255 }; /* defaults to white light */ vec3_t sunmangle = { 0, 0, 16384 }; /* defaults to straight down */ byte *filebase; // start of lightmap data static byte *file_p; // start of free space after data static byte *file_end; // end of free space for lightmap data byte *lit_filebase; // start of litfile data static byte *lit_file_p; // start of free space after litfile data static byte *lit_file_end; // end of space for litfile data qboolean extrasamples; qboolean compress_ents; qboolean colored; qboolean nominlimit; qboolean nolightface[MAX_MAP_FACES]; vec3_t faceoffset[MAX_MAP_FACES]; byte * GetFileSpace(int size) { byte *buf; ThreadLock(); /* align to 4 byte boudaries */ file_p = (byte *)(((long)file_p + 3) & ~3); buf = file_p; file_p += size; ThreadUnlock(); if (file_p > file_end) Error("%s: overrun", __func__); return buf; } byte * GetLitFileSpace(int size) { byte *buf; ThreadLock(); /* align to 12 byte boundaries (match offets with 3 * GetFileSpace) */ if ((long)lit_file_p % 12) lit_file_p += 12 - ((long)lit_file_p % 12); buf = lit_file_p; lit_file_p += size; ThreadUnlock(); if (lit_file_p > lit_file_end) Error("%s: overrun", __func__); return buf; } static void * LightThread(void *junk) { int facenum; while (1) { facenum = GetThreadWork(); if (facenum == -1) return NULL; LightFace(facenum, nolightface[facenum], faceoffset[facenum]); } return NULL; } static void FindFaceOffsets(void) { int i, j; entity_t *ent; char name[20]; const char *classname; vec3_t org; memset(nolightface, 0, sizeof(nolightface)); for (j = dmodels[0].firstface; j < dmodels[0].numfaces; j++) nolightface[j] = 0; for (i = 1; i < nummodels; i++) { sprintf(name, "*%d", i); ent = FindEntityWithKeyPair("model", name); if (!ent) Error("%s: Couldn't find entity for model %s.\n", __func__, name); classname = ValueForKey(ent, "classname"); if (!strncmp(classname, "rotate_", 7)) { int start; int end; GetVectorForKey(ent, "origin", org); start = dmodels[i].firstface; end = start + dmodels[i].numfaces; for (j = start; j < end; j++) { nolightface[j] = 300; faceoffset[j][0] = org[0]; faceoffset[j][1] = org[1]; faceoffset[j][2] = org[2]; } } } } /* * ============= * LightWorld * ============= */ static void LightWorld(void) { if (dlightdata) free(dlightdata); if (colored) lightdatasize = MAX_MAP_LIGHTING; else lightdatasize = MAX_MAP_LIGHTING / 4; dlightdata = malloc(lightdatasize + 16); /* for alignment */ if (!dlightdata) Error("%s: allocation of %i bytes failed.", __func__, lightdatasize); memset(dlightdata, 0, lightdatasize + 16); if (colored) lightdatasize /= 4; /* align filebase to a 4 byte boundary */ filebase = file_p = (byte *)(((unsigned long)dlightdata + 3) & ~3); file_end = filebase + lightdatasize; if (colored) { /* litfile data stored in dlightdata, after the white light */ lit_filebase = file_end + 12 - ((unsigned long)file_end % 12); lit_file_p = lit_filebase; lit_file_end = lit_filebase + 3 * (MAX_MAP_LIGHTING / 4); } RunThreadsOn(0, numfaces, LightThread); logprint("Lighting Completed.\n\n"); lightdatasize = file_p - filebase; logprint("lightdatasize: %i\n", lightdatasize); } /* * ================== * main * light modelfile * ================== */ int main(int argc, const char **argv) { int i, bsp_version; double start; double end; char source[1024]; init_log("light.log"); logprint("----- TyrLight v0.99e -----\n" #if 0 "** Beta version " __DATE__ " " __TIME__ "\n" #endif ); numthreads = GetDefaultThreads(); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-threads")) { numthreads = atoi(argv[i + 1]); i++; } else if (!strcmp(argv[i], "-extra")) { extrasamples = true; logprint("extra sampling enabled\n"); } else if (!strcmp(argv[i], "-dist")) { scaledist = atof(argv[i + 1]); i++; } else if (!strcmp(argv[i], "-range")) { rangescale = atof(argv[i + 1]); i++; } else if (!strcmp(argv[i], "-light")) { worldminlight = atof(argv[i + 1]); i++; } else if (!strcmp(argv[i], "-compress")) { compress_ents = true; logprint("light entity compression enabled\n"); } else if (!strcmp(argv[i], "-lit")) { colored = true; } else if (!strcmp(argv[i], "-nominlimit")) { nominlimit = true; } else if (argv[i][0] == '-') Error("Unknown option \"%s\"", argv[i]); else break; } if (numthreads > 1) logprint("running with %d threads\n", numthreads); if (colored) logprint(".lit colored light output requested on command line.\n"); if (i != argc - 1) Error("usage: light [-threads num] [-light num] [-extra]\n" " [-dist n] [-range n] [-lit] [-compress]\n" " [-nominlimit] bspfile\n"); start = I_FloatTime(); strcpy(source, argv[i]); StripExtension(source); DefaultExtension(source, ".bsp"); bsp_version = LoadBSPFile(source); LoadEntities(); MakeTnodes(); FindFaceOffsets(); LightWorld(); WriteEntitiesToString(); WriteBSPFile(source, bsp_version); if (colored) WriteLitFile(source, LIT_VERSION); end = I_FloatTime(); logprint("%5.1f seconds elapsed\n", end - start); close_log(); return 0; }