/* ================ LoadMapFile ================ */ void LoadMapFile (char *filename) { char *buf; Message (MSGVERBOSE, "------ LoadMapFile ------"); LoadFile (filename, (void **)&buf); StartTokenParsing (buf); num_entities = 0; while (ParseEntity ()) { } FreeOther (buf); if (num_entities == 0) Message(MSGERR, "No entities in map"); if (PlayerStarts == 0) Message (MSGWARNCRIT, "No info_player_start entity in level"); if (strlen(MapTitle) != 0) Message (MSGALWAYS, "Title: \"%s\"", MapTitle); Message (MSGVERBOSE, "%6i faces", nummapfaces); Message (MSGVERBOSE, "%6i brushes", nummapbrushes); Message (MSGVERBOSE, "%6i entities", num_entities); Message (MSGVERBOSE, "%6i miptex", nummiptex); Message (MSGVERBOSE, "%6i texinfo", numtexinfo); }
static void DropBrush (mbrush_t *b) { mface_t *f, *f2; for (f = b->faces; f != NULL; f = f2) { f2 = f->next; FreeOther (f); } b->faces = NULL; }
HSDrawOtherData* HSDrawData::AllocOther(HSDrawOtherData* pData,BOOL bForce /*= FALSE*/) { FreeOther(); if( m_pHSExternAlloc ) { if( bForce || pData ) { m_pOtherData = (HSDrawOtherData*)(*m_pHSExternAlloc) ( (long)pData,HSDrawOtherDataType ); } } return m_pOtherData; }
void SetKeyValue (entity_t *ent, char *key, char *value) { epair_t *ep; for (ep=ent->epairs ; ep ; ep=ep->next) if (!strcmp (ep->key, key) ) { FreeOther (ep->value); ep->value = copystring(value); return; } ep = AllocOther (sizeof(*ep)); ep->next = ent->epairs; ent->epairs = ep; ep->key = copystring(key); ep->value = copystring(value); }
/* ================ ParseEntity ================ */ qboolean ParseEntity (void) { epair_t *ep; entity_t *world; mbrush_t *b, *next; int Line, i; char *Classname; static int WorldSpawns = 0; if (!GetToken (true)) return false; Line = scriptline; if (strcmp (token, "{") ) Message (MSGERR, "Invalid entity format, { not found on line %d", Line); ExtendArray(entities, num_entities); mapent = &entities[num_entities]; mapent->Line = Line; num_entities++; do { if (!GetToken (true)) Message (MSGERR, "ParseEntity: EOF without closing brace"); if (!strcmp (token, "}") ) break; if (!strcmp (token, "{") ) ParseBrush (); else ParseEpair (); } while (1); Classname = ValueForKey(mapent, "classname"); if (strlen(Classname) == 0) Message (MSGERR, "No classname in entity on line %d", Line); // Missing classname if (!stricmp(Classname, "worldspawn")) { if (++WorldSpawns > 1) Message (MSGERR, "Multiple world entities on line %d", Line); // Multiple worlds if (!options.onlyents && !mapent->brushes) Message (MSGERR, "No world brushes on line %d", Line); // No world brushes // Get map title strcpy(MapTitle, ValueForKey(mapent, "message")); // Translate into simplified Quake character set for (i = 0; MapTitle[i] != '\0'; ++i) { MapTitle[i] &= 0x7F; // Ignore colour bit if (MapTitle[i] >= 0x12 && MapTitle[i] <= 0x1B) MapTitle[i] += 0x1E; // Extra 0-9 area else if (MapTitle[i] == 0x10) MapTitle[i] = '['; // Extra bracket else if (MapTitle[i] == 0x11) MapTitle[i] = ']'; // Extra bracket if (!isprint(MapTitle[i] & 0xFF)) MapTitle[i] = ' '; } } else if (options.noents && strnicmp(Classname, "info_player_", 12)) { // Only world and players allowed; drop entity for (ep = mapent->epairs; ep; ep = ep->next) FreeOther (ep->value); memset (mapent, 0, sizeof(entity_t)); --num_entities; return true; } else if (options.group && !stricmp(Classname, "func_group")) { // Move entity brushes into world world = &entities[0]; for (b = mapent->brushes; b; b = next) { next = b->next; b->next = world->brushes; world->brushes = b; } for (ep = mapent->epairs; ep; ep = ep->next) FreeOther (ep->value); memset (mapent, 0, sizeof(entity_t)); --num_entities; return true; } if (num_entities == 1 && WorldSpawns == 0) Message (MSGERR, "World is not first entity on line %d", Line); // World is not first entity GetVectorForKey (mapent, "origin", mapent->origin); return true; }
/* ================= ParseBrush ================= */ void ParseBrush (void) { mbrush_t *b; mface_t *f, *f2; vec3_t planepts[3]; vec3_t t1, t2, t3, VAxis[2]; int i, j, Faces; texinfo_t tx; vec_t d; vec_t shift[2], rotate, scale[2]; qboolean ok, Valve220; ExtendArray(mapbrushes, nummapbrushes); b = &mapbrushes[nummapbrushes]; b->Line = scriptline; ok = GetToken (true); while (ok) { txcommand = 0; if (!strcmp (token, "}") ) { if (!options.onlyents) { if (InvalidBrush(b, &Faces)) { // Too few faces in brush or not closed; drop it DropBrush (b); nummapfaces -= Faces; // Note: texinfo array is not corrected here return; } } if (options.SortFace) SortFaces(b); break; } // read the three point plane definition for (i=0 ; i<3 ; i++) { if (i != 0) GetToken (true); if (strcmp (token, "(") ) Message (MSGERR, "Invalid brush plane format on line %d", scriptline); for (j=0 ; j<3 ; j++) { GetToken (false); planepts[i][j] = atof(token); // AR: atof } GetToken (false); if (strcmp (token, ")") ) Message (MSGERR, "Invalid brush plane format on line %d", scriptline); } // read the texturedef memset (&tx, 0, sizeof(tx)); GetToken (false); if (options.Q2Map) Q2ToQ1Tex (token); // Check texture name length if (strlen(token) > sizeof(char16) - 1) Message (MSGERR, "Texture name \"%s\" too long on line %d", token, scriptline); if (options.SolidMap && num_entities == 1 && token[0] == '*' || options.noents && num_entities > 1) { // No liquid worldbrushes or only worldbrushes allowed; drop brush DropBrush (b); while (GetToken(true) && strcmp(token, "}")) ; return; } Valve220 = false; tx.miptex = FindMiptex (token); GetToken (false); if (!strcmp (token, "[")) { // Valve 220 map import Valve220 = true; GetValveTex (VAxis[0]); } shift[0] = atoi(token); GetToken (false); if (Valve220) { // Skip ] GetToken (false); GetValveTex (VAxis[1]); } shift[1] = atoi(token); GetToken (false); if (Valve220) GetToken (false); // Skip ] rotate = atoi(token); GetToken (false); scale[0] = atof(token); GetToken (false); scale[1] = atof(token); if (options.Q2Map) { // Skip extra Q2 style face info GetToken (false); GetToken (false); GetToken (false); } ok = GetToken (true); // Note : scriptline normally gets advanced here // if the three points are all on a previous plane, it is a // duplicate plane for (f2 = b->faces ; f2 ; f2=f2->next) { for (i=0 ; i<3 ; i++) { d = DotProduct(planepts[i],f2->plane.normal) - f2->plane.dist; if (d < -ON_EPSILON || d > ON_EPSILON) break; } if (i==3) break; } if (f2) { Message (MSGWARN, "Brush with duplicate plane on line %d", scriptline - 1); continue; } f = AllocOther(sizeof(mface_t)); // convert to a vector / dist plane for (j=0 ; j<3 ; j++) { t1[j] = planepts[0][j] - planepts[1][j]; t2[j] = planepts[2][j] - planepts[1][j]; t3[j] = planepts[1][j]; } CrossProduct(t1,t2, f->plane.normal); if (VectorCompare (f->plane.normal, vec3_origin)) { Message (MSGWARN, "Brush plane with no normal on line %d", scriptline - 1); FreeOther (f); continue; } VectorNormalize (f->plane.normal); f->plane.dist = DotProduct (t3, f->plane.normal); f->next = b->faces; b->faces = f; if (txcommand=='1' || txcommand=='2') { // from QuArK, the texture vectors are given directly from the three points vec3_t TexPt[2]; int k; vec_t dot22, dot23, dot33, mdet, aa, bb, dd; k = txcommand-'0'; for (j=0; j<3; j++) TexPt[1][j] = (planepts[k][j] - planepts[0][j]) * ScaleCorrection; k = 3-k; for (j=0; j<3; j++) TexPt[0][j] = (planepts[k][j] - 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; Message (MSGWARN, "Degenerate QuArK-style brush texture on line %d", scriptline - 1); } 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++) { tx.vecs[0][j] = aa * TexPt[0][j] + bb * TexPt[1][j]; tx.vecs[1][j] = -(/*cc*/ bb * TexPt[0][j] + dd * TexPt[1][j]); } tx.vecs[0][3] = -DotProduct(tx.vecs[0], planepts[0]); tx.vecs[1][3] = -DotProduct(tx.vecs[1], planepts[0]); } else if (Valve220) { // Valve 220 texturedef vec3_t vec; vec_t tscale; // Prevent division by zero if (!scale[0]) scale[0] = 1; if (!scale[1]) scale[1] = 1; // FIXME: If origin brushes are in use, this is where to fix their tex alignment!!! for (i = 0; i < 2; ++i) { tscale = 1 / scale[i]; VectorScale(VAxis[i], tscale, vec); for (j = 0; j < 3; ++j) tx.vecs[i][j] = (float)vec[j]; tx.vecs[i][3] = (float)shift[i] + DotProduct(vec3_origin, vec); } } else // // fake proper texture vectors from QuakeEd style // { vec3_t vecs[2]; int sv, tv; vec_t ang, sinv, cosv; vec_t ns, nt; TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]); if (!scale[0]) scale[0] = 1; if (!scale[1]) scale[1] = 1; // rotate axis if (rotate == 0) { sinv = 0 ; cosv = 1; } else if (rotate == 90) { sinv = 1 ; cosv = 0; } else if (rotate == 180) { sinv = 0 ; cosv = -1; } else if (rotate == 270) { sinv = -1 ; cosv = 0; } else { ang = rotate / 180 * Q_PI; sinv = sin(ang); cosv = cos(ang); } if (vecs[0][0]) sv = 0; else if (vecs[0][1]) sv = 1; else sv = 2; if (vecs[1][0]) tv = 0; else if (vecs[1][1]) tv = 1; else tv = 2; for (i=0 ; i<2 ; i++) { ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; vecs[i][sv] = ns; vecs[i][tv] = nt; } for (i=0 ; i<2 ; i++) for (j=0 ; j<3 ; j++) tx.vecs[i][j] = vecs[i][j] / scale[i]; tx.vecs[0][3] = shift[0]; tx.vecs[1][3] = shift[1]; } // unique the texinfo f->texinfo = FindTexinfo (&tx); nummapfaces++; }; nummapbrushes++; b->next = mapent->brushes; mapent->brushes = b; }