/* =============== FindTexinfo Returns a global texinfo number =============== */ int FindTexinfo (texinfo_t *t) { int i, j; texinfo_t *tex; // set the special flag if (miptex[t->miptex][0] == '*' || !options.SolidMap && !Q_strncasecmp (miptex[t->miptex], "sky",3) ) t->flags |= TEX_SPECIAL; tex = texinfo; for (i=0 ; i<numtexinfo;i++, tex++) { if (t->miptex != tex->miptex) continue; if (t->flags != tex->flags) continue; for (j=0 ; j<8 ; j++) if (t->vecs[0][j] != tex->vecs[0][j]) break; if (j != 8) continue; return i; } // allocate a new texture ExtendArray(texinfo, i); texinfo[i] = *t; numtexinfo++; return i; }
int FindMiptex (char *name) { int i; for (i=0 ; i<nummiptex ; i++) { if (!Q_strncasecmp(name, miptex[i], sizeof(char16))) return i; } ExtendArray(miptex, i); CleanupName (name, miptex[i]); nummiptex++; return i; }
/* =============== FindPlane Returns a global plane number and the side that will be the front =============== */ int FindPlane (plane_t *dplane, int *side) { int i; plane_t *dp, pl; vec_t dot; dot = VectorLength(dplane->normal); if (dot < 1.0 - ANGLEEPSILON || dot > 1.0 + ANGLEEPSILON) Message (MSGERR, "FindPlane: Normalization error"); pl = *dplane; NormalizePlane (&pl); if (DotProduct(pl.normal, dplane->normal) > 0) *side = 0; else *side = 1; dp = planes; for (i=0 ; i<numbrushplanes;i++, dp++) { dot = DotProduct (dp->normal, pl.normal); if (dot > 1.0 - ANGLEEPSILON && fabs(dp->dist - pl.dist) < DISTEPSILON ) { // regular match return i; } } if (validfacesactive) ExtendArray(validfaces, numbrushplanes); ExtendArray(planes, numbrushplanes); planes[numbrushplanes] = pl; numbrushplanes++; return numbrushplanes-1; }
static void ExtendStacks( ElArray *arrayPtr, /* Array of elements to copy onto stacks. */ int leaf) /* If zero, then don't copy exact leaf * elements. */ { register int count; register Element *elPtr; ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); for (elPtr = arrayPtr->els, count = arrayPtr->numUsed; count > 0; elPtr++, count--) { if (!(elPtr->flags & (NODE|WILDCARD)) && !leaf) { continue; } tsdPtr->stacks[elPtr->flags] = ExtendArray(tsdPtr->stacks[elPtr->flags], elPtr); } }
void Tk_AddOption( Tk_Window tkwin, /* Window token; option will be associated * with main window for this window. */ CONST char *name, /* Multi-element name of option. */ CONST char *value, /* String value for option. */ int priority) /* Overall priority level to use for this * option, such as TK_USER_DEFAULT_PRIO or * TK_INTERACTIVE_PRIO. Must be between 0 and * TK_MAX_PRIO. */ { TkWindow *winPtr = ((TkWindow *) tkwin)->mainPtr->winPtr; register ElArray **arrayPtrPtr; register Element *elPtr; Element newEl; register CONST char *p; CONST char *field; int count, firstField; ptrdiff_t length; #define TMP_SIZE 100 char tmp[TMP_SIZE+1]; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (winPtr->mainPtr->optionRootPtr == NULL) { OptionInit(winPtr->mainPtr); } tsdPtr->cachedWindow = NULL;/* Invalidate the cache. */ /* * Compute the priority for the new element, including both the overall * level and the serial number (to disambiguate with the level). */ if (priority < 0) { priority = 0; } else if (priority > TK_MAX_PRIO) { priority = TK_MAX_PRIO; } newEl.priority = (priority << 24) + tsdPtr->serial; tsdPtr->serial++; /* * Parse the option one field at a time. */ arrayPtrPtr = &(((TkWindow *) tkwin)->mainPtr->optionRootPtr); p = name; for (firstField = 1; ; firstField = 0) { /* * Scan the next field from the name and convert it to a Tk_Uid. Must * copy the field before calling Tk_Uid, so that a terminating NULL * may be added without modifying the source string. */ if (*p == '*') { newEl.flags = WILDCARD; p++; } else { newEl.flags = 0; } field = p; while ((*p != 0) && (*p != '.') && (*p != '*')) { p++; } length = p - field; if (length > TMP_SIZE) { length = TMP_SIZE; } strncpy(tmp, field, (size_t) length); tmp[length] = 0; newEl.nameUid = Tk_GetUid(tmp); if (isupper(UCHAR(*field))) { newEl.flags |= CLASS; } if (*p != 0) { /* * New element will be a node. If this option can't possibly apply * to this main window, then just skip it. Otherwise, add it to * the parent, if it isn't already there, and descend into it. */ newEl.flags |= NODE; if (firstField && !(newEl.flags & WILDCARD) && (newEl.nameUid != winPtr->nameUid) && (newEl.nameUid != winPtr->classUid)) { return; } for (elPtr = (*arrayPtrPtr)->els, count = (*arrayPtrPtr)->numUsed; ; elPtr++, count--) { if (count == 0) { newEl.child.arrayPtr = NewArray(5); *arrayPtrPtr = ExtendArray(*arrayPtrPtr, &newEl); arrayPtrPtr = &((*arrayPtrPtr) ->nextToUse[-1].child.arrayPtr); break; } if ((elPtr->nameUid == newEl.nameUid) && (elPtr->flags == newEl.flags)) { arrayPtrPtr = &(elPtr->child.arrayPtr); break; } } if (*p == '.') { p++; } } else { /* * New element is a leaf. Add it to the parent, if it isn't * already there. If it exists already, keep whichever value has * highest priority. */ newEl.child.valueUid = Tk_GetUid(value); for (elPtr = (*arrayPtrPtr)->els, count = (*arrayPtrPtr)->numUsed; ; elPtr++, count--) { if (count == 0) { *arrayPtrPtr = ExtendArray(*arrayPtrPtr, &newEl); return; } if ((elPtr->nameUid == newEl.nameUid) && (elPtr->flags == newEl.flags)) { if (elPtr->priority < newEl.priority) { elPtr->priority = newEl.priority; elPtr->child.valueUid = newEl.child.valueUid; } return; } } } } }
/* ================ 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; }