123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660 |
- #ifdef SYSTEM_WIN32
- #pragma warning(disable:4996)
- #endif
- #pragma warning(disable:4018) // '<' : signed/unsigned mismatch
- #include "csg.h"
- int g_nummapbrushes;
- brush_t g_mapbrushes[MAX_MAP_BRUSHES];
- int g_numbrushsides;
- side_t g_brushsides[MAX_MAP_SIDES];
- int g_nMapFileVersion;
- static const vec3_t s_baseaxis[18] = {
- {0, 0, 1}, {1, 0, 0}, {0, -1, 0}, // floor
- {0, 0, -1}, {1, 0, 0}, {0, -1, 0}, // ceiling
- {1, 0, 0}, {0, 1, 0}, {0, 0, -1}, // west wall
- {-1, 0, 0}, {0, 1, 0}, {0, 0, -1}, // east wall
- {0, 1, 0}, {1, 0, 0}, {0, 0, -1}, // south wall
- {0, -1, 0}, {1, 0, 0}, {0, 0, -1}, // north wall
- };
- // =====================================================================================
- // TextureAxisFromPlane
- // =====================================================================================
- void TextureAxisFromPlane(const plane_t* const pln, vec3_t xv, vec3_t yv)
- {
- int bestaxis;
- vec_t dot, best;
- int i;
- best = 0;
- bestaxis = 0;
- for (i = 0; i < 6; i++)
- {
- dot = DotProduct(pln->normal, s_baseaxis[i * 3]);
- if (dot > best)
- {
- best = dot;
- bestaxis = i;
- }
- }
- VectorCopy(s_baseaxis[bestaxis * 3 + 1], xv);
- VectorCopy(s_baseaxis[bestaxis * 3 + 2], yv);
- }
- #define ScaleCorrection (1.0/128.0)
- // =====================================================================================
- // CopySKYtoCLIP
- // clips a particluar sky brush
- // =====================================================================================
- static void CopySKYtoCLIP(const brush_t* const b)
- {
- int i;
- entity_t* mapent;
- brush_t* newbrush;
- if (b->contents != CONTENTS_SKY)
- Error("[MOD] CopySKYtoCLIP: Got a NON-SKY for passed brush! (%s)",b->contents );
- hlassert(b->contents == CONTENTS_SKY); // Only SKY brushes should be passed down to this function(sanity check)
- hlassert(b->entitynum == 0); // SKY must be in worldspawn entity
- mapent = &g_entities[b->entitynum];
- mapent->numbrushes++;
- newbrush = &g_mapbrushes[g_nummapbrushes];
- newbrush->entitynum = b->entitynum;
- newbrush->brushnum = g_nummapbrushes - mapent->firstbrush;
- newbrush->firstside = g_numbrushsides;
- newbrush->numsides = b->numsides;
- newbrush->contents = CONTENTS_CLIP;
- newbrush->noclip = 0;
- for (i = 0; i < b->numsides; i++)
- {
- int j;
- side_t* side = &g_brushsides[g_numbrushsides];
- *side = g_brushsides[b->firstside + i];
- safe_strncpy(side->td.name, "CLIP", sizeof(side->td.name));
- for (j = 0; j < NUM_HULLS; j++)
- {
- newbrush->hulls[j].faces = NULL;
- newbrush->hulls[j].bounds = b->hulls[j].bounds;
- }
- g_numbrushsides++;
- hlassume(g_numbrushsides < MAX_MAP_SIDES, assume_MAX_MAP_SIDES);
- }
- g_nummapbrushes++;
- hlassume(g_nummapbrushes < MAX_MAP_BRUSHES, assume_MAX_MAP_BRUSHES);
- }
- // =====================================================================================
- // HandleSKYCLIP
- // clips the whole sky, unconditional of g_skyclip
- // =====================================================================================
- static void HandleSKYCLIP()
- {
- int i;
- int last;
- entity_t* e = &g_entities[0];
- for (i = e->firstbrush, last = e->firstbrush + e->numbrushes; i < last; i++)
- {
- if (g_mapbrushes[i].contents == CONTENTS_SKY)
- {
- CopySKYtoCLIP(&g_mapbrushes[i]);
- }
- }
- }
- // =====================================================================================
- // CheckForInvisible
- // see if a brush is part of an invisible entity (KGP)
- // =====================================================================================
- #ifdef HLCSG_NULLIFY_INVISIBLE
- static bool CheckForInvisible(entity_t* mapent)
- {
- using namespace std;
- string keyval(ValueForKey(mapent,"classname"));
- if(g_invisible_items.count(keyval))
- { return true; }
- keyval.assign(ValueForKey(mapent,"targetname"));
- if(g_invisible_items.count(keyval))
- { return true; }
- keyval.assign(ValueForKey(mapent,"zhlt_invisible"));
- if(!keyval.empty() && strcmp(keyval.c_str(),"0"))
- { return true; }
- return false;
- }
- #endif
- // =====================================================================================
- // ParseBrush
- // parse a brush from script
- // =====================================================================================
- static contents_t ParseBrush(entity_t* mapent)
- {
- brush_t* b;
- int i, j;
- side_t* side;
- contents_t contents;
- bool ok;
- #ifdef HLCSG_NULLIFY_INVISIBLE // KGP
- bool nullify = CheckForInvisible(mapent);
- #endif
- hlassume(g_nummapbrushes < MAX_MAP_BRUSHES, assume_MAX_MAP_BRUSHES);
- b = &g_mapbrushes[g_nummapbrushes];
- g_nummapbrushes++;
- b->firstside = g_numbrushsides;
- b->entitynum = g_numentities - 1;
- b->brushnum = g_nummapbrushes - mapent->firstbrush - 1;
- #ifdef HLCSG_CLIPECONOMY // AJM
- b->noclip = 0;
- #endif
- mapent->numbrushes++;
- ok = GetToken(true);
- while (ok)
- {
- g_TXcommand = 0;
- if (!strcmp(g_token, "}"))
- {
- break;
- }
- hlassume(g_numbrushsides < MAX_MAP_SIDES, assume_MAX_MAP_SIDES);
- side = &g_brushsides[g_numbrushsides];
- g_numbrushsides++;
- b->numsides++;
- // read the three point plane definition
- for (i = 0; i < 3; i++)
- {
- if (i != 0)
- {
- GetToken(true);
- }
- if (strcmp(g_token, "("))
- {
- Error("Parsing Entity %i, Brush %i, Side %i : Expecting '(' got '%s'",
- b->entitynum, b->brushnum, b->numsides, g_token);
- }
- for (j = 0; j < 3; j++)
- {
- GetToken(false);
- side->planepts[i][j] = atof(g_token);
- }
- GetToken(false);
- if (strcmp(g_token, ")"))
- {
- Error("Parsing Entity %i, Brush %i, Side %i : Expecting ')' got '%s'",
- b->entitynum, b->brushnum, b->numsides, g_token);
- }
- }
- // read the texturedef
- GetToken(false);
- _strupr(g_token);
- #ifdef HLCSG_NULLIFY_INVISIBLE
- if(nullify && strncmp(g_token,"BEVEL",5) && strncmp(g_token,"ORIGIN",6))
- { safe_strncpy(g_token,"NULL",sizeof(g_token)); }
- #endif
- safe_strncpy(side->td.name, g_token, sizeof(side->td.name));
- if (g_nMapFileVersion < 220) // Worldcraft 2.1-, Radiant
- {
- GetToken(false);
- side->td.vects.valve.shift[0] = atof(g_token);
- GetToken(false);
- side->td.vects.valve.shift[1] = atof(g_token);
- GetToken(false);
- side->td.vects.valve.rotate = atof(g_token);
- GetToken(false);
- side->td.vects.valve.scale[0] = atof(g_token);
- GetToken(false);
- side->td.vects.valve.scale[1] = atof(g_token);
- }
- else // Worldcraft 2.2+
- {
- // texture U axis
- GetToken(false);
- if (strcmp(g_token, "["))
- {
- hlassume(false, assume_MISSING_BRACKET_IN_TEXTUREDEF);
- }
- GetToken(false);
- side->td.vects.valve.UAxis[0] = atof(g_token);
- GetToken(false);
- side->td.vects.valve.UAxis[1] = atof(g_token);
- GetToken(false);
- side->td.vects.valve.UAxis[2] = atof(g_token);
- GetToken(false);
- side->td.vects.valve.shift[0] = atof(g_token);
- GetToken(false);
- if (strcmp(g_token, "]"))
- {
- Error("missing ']' in texturedef (U)");
- }
- // texture V axis
- GetToken(false);
- if (strcmp(g_token, "["))
- {
- Error("missing '[' in texturedef (V)");
- }
- GetToken(false);
- side->td.vects.valve.VAxis[0] = atof(g_token);
- GetToken(false);
- side->td.vects.valve.VAxis[1] = atof(g_token);
- GetToken(false);
- side->td.vects.valve.VAxis[2] = atof(g_token);
- GetToken(false);
- side->td.vects.valve.shift[1] = atof(g_token);
- GetToken(false);
- if (strcmp(g_token, "]"))
- {
- Error("missing ']' in texturedef (V)");
- }
- // Texture rotation is implicit in U/V axes.
- GetToken(false);
- side->td.vects.valve.rotate = 0;
- // texure scale
- GetToken(false);
- side->td.vects.valve.scale[0] = atof(g_token);
- GetToken(false);
- side->td.vects.valve.scale[1] = atof(g_token);
- }
- ok = GetToken(true); // Done with line, this reads the first item from the next line
- if ((g_TXcommand == '1' || g_TXcommand == '2'))
- {
- // We are QuArK mode and need to translate some numbers to align textures its way
- // from QuArK, the texture vectors are given directly from the three points
- vec3_t TexPt[2];
- int k;
- float dot22, dot23, dot33, mdet, aa, bb, dd;
- k = g_TXcommand - '0';
- for (j = 0; j < 3; j++)
- {
- TexPt[1][j] = (side->planepts[k][j] - side->planepts[0][j]) * ScaleCorrection;
- }
- k = 3 - k;
- for (j = 0; j < 3; j++)
- {
- TexPt[0][j] = (side->planepts[k][j] - side->planepts[0][j]) * ScaleCorrection;
- }
- dot22 = DotProduct(TexPt[0], TexPt[0]);
- dot23 = DotProduct(TexPt[0], TexPt[1]);
- dot33 = DotProduct(TexPt[1], TexPt[1]);
- mdet = dot22 * dot33 - dot23 * dot23;
- if (mdet < 1E-6 && mdet > -1E-6)
- {
- aa = bb = dd = 0;
- Warning
- ("Degenerate QuArK-style brush texture : Entity %i, Brush %i @ (%f,%f,%f) (%f,%f,%f) (%f,%f,%f)",
- b->entitynum, b->brushnum, side->planepts[0][0], side->planepts[0][1], side->planepts[0][2],
- side->planepts[1][0], side->planepts[1][1], side->planepts[1][2], side->planepts[2][0],
- side->planepts[2][1], side->planepts[2][2]);
- }
- else
- {
- mdet = 1.0 / mdet;
- aa = dot33 * mdet;
- bb = -dot23 * mdet;
- //cc = -dot23*mdet; // cc = bb
- dd = dot22 * mdet;
- }
- for (j = 0; j < 3; j++)
- {
- side->td.vects.quark.vects[0][j] = aa * TexPt[0][j] + bb * TexPt[1][j];
- side->td.vects.quark.vects[1][j] = -( /*cc */ bb * TexPt[0][j] + dd * TexPt[1][j]);
- }
- side->td.vects.quark.vects[0][3] = -DotProduct(side->td.vects.quark.vects[0], side->planepts[0]);
- side->td.vects.quark.vects[1][3] = -DotProduct(side->td.vects.quark.vects[1], side->planepts[0]);
- }
- side->td.txcommand = g_TXcommand; // Quark stuff, but needs setting always
- };
- b->contents = contents = CheckBrushContents(b);
- //
- // origin brushes are removed, but they set
- // the rotation origin for the rest of the brushes
- // in the entity
- //
- if (contents == CONTENTS_ORIGIN)
- {
- char string[MAXTOKEN];
- vec3_t origin;
- b->contents = CONTENTS_SOLID;
- CreateBrush(mapent->firstbrush + b->brushnum); // to get sizes
- b->contents = contents;
- for (i = 0; i < NUM_HULLS; i++)
- {
- b->hulls[i].faces = NULL;
- }
- if (b->entitynum != 0) // Ignore for WORLD (code elsewhere enforces no ORIGIN in world message)
- {
- VectorAdd(b->hulls[0].bounds.m_Mins, b->hulls[0].bounds.m_Maxs, origin);
- VectorScale(origin, 0.5, origin);
-
- safe_snprintf(string, MAXTOKEN, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
- SetKeyValue(&g_entities[b->entitynum], "origin", string);
- }
- }
- return contents;
- }
- // =====================================================================================
- // ParseMapEntity
- // parse an entity from script
- // =====================================================================================
- bool ParseMapEntity()
- {
- bool all_clip = true;
- int this_entity;
- entity_t* mapent;
- epair_t* e;
- if (!GetToken(true))
- {
- return false;
- }
- this_entity = g_numentities;
- if (strcmp(g_token, "{"))
- {
- Error("Parsing Entity %i, expected '{' got '%s'", this_entity, g_token);
- }
- hlassume(g_numentities < MAX_MAP_ENTITIES, assume_MAX_MAP_ENTITIES);
- g_numentities++;
- mapent = &g_entities[this_entity];
- mapent->firstbrush = g_nummapbrushes;
- mapent->numbrushes = 0;
- while (1)
- {
- if (!GetToken(true))
- Error("ParseEntity: EOF without closing brace");
- if (!strcmp(g_token, "}")) // end of our context
- break;
- if (!strcmp(g_token, "{")) // must be a brush
- {
- contents_t contents = ParseBrush(mapent);
- if ((contents != CONTENTS_CLIP) && (contents != CONTENTS_ORIGIN))
- all_clip = false;
- }
- else // else assume an epair
- {
- e = ParseEpair();
- if (!strcmp(e->key, "mapversion"))
- {
- g_nMapFileVersion = atoi(e->value);
- }
- e->next = mapent->epairs;
- mapent->epairs = e;
- }
- }
- if (mapent->numbrushes && all_clip)
- Fatal(assume_NO_VISIBILE_BRUSHES, "Entity %i has no visible brushes\n", this_entity);
- CheckFatal();
-
- #ifdef ZHLT_DETAIL // AJM
- if (!strcmp(ValueForKey(mapent, "classname"), "info_detail") && g_bDetailBrushes && this_entity != 0)
- {
- // mark all of the brushes in this entity as contents_detail
- for (int i = mapent->firstbrush; i < mapent->firstbrush + mapent->numbrushes; i++)
- {
- g_mapbrushes[i].contents = CONTENTS_DETAIL;
- }
- // move these brushes to worldspawn
- {
- brush_t* temp;
- int newbrushes;
- int worldbrushes;
- int i;
- newbrushes = mapent->numbrushes;
- worldbrushes = g_entities[0].numbrushes;
- temp = (brush_t*)Alloc(newbrushes * sizeof(brush_t));
- memcpy(temp, g_mapbrushes + mapent->firstbrush, newbrushes * sizeof(brush_t));
- for (i = 0; i < newbrushes; i++)
- {
- temp[i].entitynum = 0;
- }
- // make space to move the brushes (overlapped copy)
- memmove(g_mapbrushes + worldbrushes + newbrushes,
- g_mapbrushes + worldbrushes, sizeof(brush_t) * (g_nummapbrushes - worldbrushes - newbrushes));
- // copy the new brushes down
- memcpy(g_mapbrushes + worldbrushes, temp, sizeof(brush_t) * newbrushes);
- // fix up indexes
- g_numentities--;
- g_entities[0].numbrushes += newbrushes;
- for (i = 1; i < g_numentities; i++)
- {
- g_entities[i].firstbrush += newbrushes;
- }
- memset(mapent, 0, sizeof(*mapent));
- Free(temp);
- }
- // delete this entity
- g_numentities--;
- return true;
- }
- #endif
- #ifdef ZHLT_INFO_COMPILE_PARAMETERS // AJM
- if (!strcmp(ValueForKey(mapent, "classname"), "info_compile_parameters"))
- {
- GetParamsFromEnt(mapent);
- }
- #endif
- // if its the worldspawn entity and we need to skyclip, then do it
- if ((this_entity == 0) && g_skyclip) // first entitiy
- {
- HandleSKYCLIP();
- }
- // if the given entity only has one brush and its an origin brush
- if ((mapent->numbrushes == 1) && (g_mapbrushes[mapent->firstbrush].contents == CONTENTS_ORIGIN))
- {
- brushhull_t* hull = g_mapbrushes[mapent->firstbrush].hulls;
- Error("Entity %i, contains ONLY an origin brush near (%.0f,%.0f,%.0f)\n",
- this_entity, hull->bounds.m_Mins[0], hull->bounds.m_Mins[1], hull->bounds.m_Mins[2]);
- }
- GetVectorForKey(mapent, "origin", mapent->origin);
- // group entities are just for editor convenience
- // toss all brushes into the world entity
- if (!g_onlyents && !strcmp("func_group", ValueForKey(mapent, "classname")))
- {
- // this is pretty gross, because the brushes are expected to be
- // in linear order for each entity
- brush_t* temp;
- int newbrushes;
- int worldbrushes;
- int i;
- newbrushes = mapent->numbrushes;
- worldbrushes = g_entities[0].numbrushes;
- temp = (brush_t*)Alloc(newbrushes * sizeof(brush_t));
- memcpy(temp, g_mapbrushes + mapent->firstbrush, newbrushes * sizeof(brush_t));
- for (i = 0; i < newbrushes; i++)
- {
- temp[i].entitynum = 0;
- }
- // make space to move the brushes (overlapped copy)
- memmove(g_mapbrushes + worldbrushes + newbrushes,
- g_mapbrushes + worldbrushes, sizeof(brush_t) * (g_nummapbrushes - worldbrushes - newbrushes));
- // copy the new brushes down
- memcpy(g_mapbrushes + worldbrushes, temp, sizeof(brush_t) * newbrushes);
- // fix up indexes
- g_numentities--;
- g_entities[0].numbrushes += newbrushes;
- for (i = 1; i < g_numentities; i++)
- {
- g_entities[i].firstbrush += newbrushes;
- }
- memset(mapent, 0, sizeof(*mapent));
- Free(temp);
- }
- return true;
- }
- // =====================================================================================
- // CountEngineEntities
- // =====================================================================================
- unsigned int CountEngineEntities()
- {
- unsigned int x;
- unsigned num_engine_entities = 0;
- entity_t* mapent = g_entities;
- // for each entity in the map
- for (x=0; x<g_numentities; x++, mapent++)
- {
- const char* classname = ValueForKey(mapent, "classname");
- // if its a light_spot or light_env, dont include it as an engine entity!
- if (classname)
- {
- if ( !strncasecmp(classname, "light", 5)
- || !strncasecmp(classname, "light_spot", 10)
- || !strncasecmp(classname, "light_environment", 17)
- )
- {
- const char* style = ValueForKey(mapent, "style");
- const char* targetname = ValueForKey(mapent, "targetname");
- // lightspots and lightenviroments dont have a targetname or style
- if (!strlen(targetname) && !atoi(style))
- {
- continue;
- }
- }
- }
- num_engine_entities++;
- }
- return num_engine_entities;
- }
- // =====================================================================================
- // LoadMapFile
- // wrapper for LoadScriptFile
- // parse in script entities
- // =====================================================================================
- const char* ContentsToString(const contents_t type);
- void LoadMapFile(const char* const filename)
- {
- unsigned num_engine_entities;
- LoadScriptFile(filename);
- g_numentities = 0;
- while (ParseMapEntity())
- {
- }
- // AJM debug
- /*
- for (int i = 0; i < g_numentities; i++)
- {
- Log("entity: %i - %i brushes - %s\n", i, g_entities[i].numbrushes, ValueForKey(&g_entities[i], "classname"));
- }
- Log("total entities: %i\ntotal brushes: %i\n\n", g_numentities, g_nummapbrushes);
- for (i = g_entities[0].firstbrush; i < g_entities[0].firstbrush + g_entities[0].numbrushes; i++)
- {
- Log("worldspawn brush %i: contents %s\n", i, ContentsToString((contents_t)g_mapbrushes[i].contents));
- }
- */
- num_engine_entities = CountEngineEntities();
- hlassume(num_engine_entities < MAX_ENGINE_ENTITIES, assume_MAX_ENGINE_ENTITIES);
- CheckFatal();
- Verbose("Load map:%s\n", filename);
- Verbose("%5i brushes\n", g_nummapbrushes);
- Verbose("%5i map entities \n", g_numentities - num_engine_entities);
- Verbose("%5i engine entities\n", num_engine_entities);
- // AJM: added in
- #ifdef HLCSG_AUTOWAD
- GetUsedTextures();
- #endif
- }
|