void ComputeAbsolute(face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3) { vec3_t ex,ey,ez; // local axis base #ifdef _DEBUG if (g_qeglobals.m_bBrushPrimitMode) Sys_Printf("Warning : illegal call of ComputeAbsolute in brush primitive mode\n"); #endif // compute first local axis base TextureAxisFromPlane(&f->plane, ex, ey); CrossProduct(ex, ey, ez); vec3_t aux; VectorCopy(ex, aux); VectorScale(aux, -f->texdef.shift[0], aux); VectorCopy(aux, p1); VectorCopy(ey, aux); VectorScale(aux, -f->texdef.shift[1], aux); VectorAdd(p1, aux, p1); VectorCopy(p1, p2); VectorAdd(p2, ex, p2); VectorCopy(p1, p3); VectorAdd(p3, ey, p3); VectorCopy(ez, aux); VectorScale(aux, -f->texdef.rotate, aux); VectorRotate(p1, aux, p1); VectorRotate(p2, aux, p2); VectorRotate(p3, aux, p3); // computing rotated local axis base vec3_t rex,rey; VectorCopy(ex, rex); VectorRotate(rex, aux, rex); VectorCopy(ey, rey); VectorRotate(rey, aux, rey); ComputeScale(rex,rey,p1,f); ComputeScale(rex,rey,p2,f); ComputeScale(rex,rey,p3,f); // project on normal plane // along ez // assumes plane normal is normalized ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p1); ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p2); ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p3); };
void ComputeAbsolute( face_s* f, edVec3_c& p1, edVec3_c& p2, edVec3_c& p3 ) { edVec3_c ex, ey, ez; // local axis base #ifdef _DEBUG if ( g_qeglobals.m_bBrushPrimitMode ) Sys_Printf( "Warning : illegal call of ComputeAbsolute in brush primitive mode\n" ); #endif // compute first local axis base TextureAxisFromPlane( f->plane, ex, ey ); ez.crossProduct( ex, ey ); edVec3_c aux = ex * -f->texdef.shift[0]; p1 = aux; aux = ey * -f->texdef.shift[1]; p1 += aux; p2 = p1; p2 += ex; p3 = p1; p3 += ey; aux = ez; aux *= -f->texdef.rotate; VectorRotate( p1, aux, p1 ); VectorRotate( p2, aux, p2 ); VectorRotate( p3, aux, p3 ); // computing rotated local axis base edVec3_c rex = ex; VectorRotate( rex, aux, rex ); edVec3_c rey = ey; VectorRotate( rey, aux, rey ); ComputeScale( rex, rey, p1, f ); ComputeScale( rex, rey, p2, f ); ComputeScale( rex, rey, p3, f ); // project on normal plane // along ez // assumes plane normal is normalized f->plane.projectOnPlane( ez, p1 ); f->plane.projectOnPlane( ez, p2 ); f->plane.projectOnPlane( ez, p3 ); };
void ComputeAbsolute(face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3) { vec3_t ex,ey,ez; // local axis base // compute first local axis base TextureAxisFromPlane(&f->plane, ex, ey); CrossProduct(ex, ey, ez); vec3_t aux; VectorCopy(ex, aux); VectorScale(aux, -f->texdef.shift[0], aux); VectorCopy(aux, p1); VectorCopy(ey, aux); VectorScale(aux, -f->texdef.shift[1], aux); VectorAdd(p1, aux, p1); VectorCopy(p1, p2); VectorAdd(p2, ex, p2); VectorCopy(p1, p3); VectorAdd(p3, ey, p3); VectorCopy(ez, aux); VectorScale(aux, -f->texdef.rotate, aux); VectorRotate(p1, aux, p1); VectorRotate(p2, aux, p2); VectorRotate(p3, aux, p3); // computing rotated local axis base vec3_t rex,rey; VectorCopy(ex, rex); VectorRotate(rex, aux, rex); VectorCopy(ey, rey); VectorRotate(rey, aux, rey); ComputeScale(rex,rey,p1,f); ComputeScale(rex,rey,p2,f); ComputeScale(rex,rey,p3,f); // project on normal plane // along ez // assumes plane normal is normalized ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p1); ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p2); ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p3); };
void EmitTextureCoordinates(float *xyzst,qtexture_t *q,face_t *f) { float s,t,ns,nt,ang,sinv,cosv; vec3_t vecs[2]; texdef_t *td; // get natural texture axis TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]); td = &f->texdef; ang = td->rotate/180.0f*pMath_PI; sinv = sin(ang); cosv = cos(ang); if (!td->scale[0]) td->scale[0] = 1.0f; if (!td->scale[1]) td->scale[1] = 1.0f; s = Math_DotProduct(xyzst,vecs[0]); t = Math_DotProduct(xyzst,vecs[1]); ns = cosv * s - sinv * t; nt = sinv * s + cosv * t; s = ns/td->scale[0] + td->shift[0]; t = nt/td->scale[1] + td->shift[1]; // gl scales everything from 0 to 1 s /= q->width; t /= q->height; xyzst[3] = s; xyzst[4] = t; }
int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, const Vector& origin) { Vector vecs[2]; int sv, tv; vec_t ang, sinv, cosv; vec_t ns, nt; texinfo_t tx; int i, j; if (!bt->name[0]) return 0; memset (&tx, 0, sizeof(tx)); // HLTOOLS - add support for texture vectors stored in the map file if (g_nMapFileVersion < 220) { TextureAxisFromPlane(plane, vecs[0], vecs[1]); } if (!bt->textureWorldUnitsPerTexel[0]) bt->textureWorldUnitsPerTexel[0] = 1; if (!bt->textureWorldUnitsPerTexel[1]) bt->textureWorldUnitsPerTexel[1] = 1; float shiftScaleU = 1.0f / 16.0f; float shiftScaleV = 1.0f / 16.0f; if (g_nMapFileVersion < 220) { // rotate axis if (bt->rotate == 0) { sinv = 0 ; cosv = 1; } else if (bt->rotate == 90) { sinv = 1 ; cosv = 0; } else if (bt->rotate == 180) { sinv = 0 ; cosv = -1; } else if (bt->rotate == 270) { sinv = -1 ; cosv = 0; } else { ang = bt->rotate / 180 * M_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.textureVecsTexelsPerWorldUnits[i][j] = vecs[i][j] / bt->textureWorldUnitsPerTexel[i]; tx.lightmapVecsLuxelsPerWorldUnits[i][j] = tx.textureVecsTexelsPerWorldUnits[i][j] / 16.0f; } } } else { tx.textureVecsTexelsPerWorldUnits[0][0] = bt->UAxis[0] / bt->textureWorldUnitsPerTexel[0]; tx.textureVecsTexelsPerWorldUnits[0][1] = bt->UAxis[1] / bt->textureWorldUnitsPerTexel[0]; tx.textureVecsTexelsPerWorldUnits[0][2] = bt->UAxis[2] / bt->textureWorldUnitsPerTexel[0]; tx.textureVecsTexelsPerWorldUnits[1][0] = bt->VAxis[0] / bt->textureWorldUnitsPerTexel[1]; tx.textureVecsTexelsPerWorldUnits[1][1] = bt->VAxis[1] / bt->textureWorldUnitsPerTexel[1]; tx.textureVecsTexelsPerWorldUnits[1][2] = bt->VAxis[2] / bt->textureWorldUnitsPerTexel[1]; tx.lightmapVecsLuxelsPerWorldUnits[0][0] = bt->UAxis[0] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[0][1] = bt->UAxis[1] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[0][2] = bt->UAxis[2] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[1][0] = bt->VAxis[0] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[1][1] = bt->VAxis[1] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[1][2] = bt->VAxis[2] / bt->lightmapWorldUnitsPerLuxel; shiftScaleU = bt->textureWorldUnitsPerTexel[0] / bt->lightmapWorldUnitsPerLuxel; shiftScaleV = bt->textureWorldUnitsPerTexel[1] / bt->lightmapWorldUnitsPerLuxel; } tx.textureVecsTexelsPerWorldUnits[0][3] = bt->shift[0] + DOT_PRODUCT( origin, tx.textureVecsTexelsPerWorldUnits[0] ); tx.textureVecsTexelsPerWorldUnits[1][3] = bt->shift[1] + DOT_PRODUCT( origin, tx.textureVecsTexelsPerWorldUnits[1] ); tx.lightmapVecsLuxelsPerWorldUnits[0][3] = shiftScaleU * bt->shift[0] + DOT_PRODUCT( origin, tx.lightmapVecsLuxelsPerWorldUnits[0] ); tx.lightmapVecsLuxelsPerWorldUnits[1][3] = shiftScaleV * bt->shift[1] + DOT_PRODUCT( origin, tx.lightmapVecsLuxelsPerWorldUnits[1] ); tx.flags = bt->flags; tx.texdata = FindOrCreateTexData( bt->name ); // find the texinfo return FindOrCreateTexInfo( tx ); }
/* ================= ParseRawBrush parses the sides into buildBrush->sides[], nothing else. no validation, back plane removal, etc. ================= */ static void ParseRawBrush( bool onlyLights ) { side_t *side; float planePoints[3][3]; int planenum; char name[MAX_SHADERPATH]; char shader[MAX_SHADERPATH]; shaderInfo_t *si; token_t token; vects_t vects; int flags; buildBrush->numsides = 0; buildBrush->detail = false; if( g_bBrushPrimit == BRUSH_RADIANT ) Com_CheckToken( mapfile, "{" ); while( 1 ) { if( !Com_ReadToken( mapfile, SC_ALLOW_NEWLINES|SC_COMMENT_SEMICOLON, &token )) break; if( !com.stricmp( token.string, "}" )) break; if( g_bBrushPrimit == BRUSH_RADIANT ) { while( 1 ) { if( com.strcmp( token.string, "(" )) Com_ReadToken( mapfile, 0, &token ); else break; Com_ReadToken( mapfile, SC_ALLOW_NEWLINES, &token ); } } Com_SaveToken( mapfile, &token ); if( buildBrush->numsides >= MAX_BUILD_SIDES ) Sys_Break( "Entity %i, Brush %i MAX_BUILD_SIDES\n", buildBrush->entityNum, buildBrush->brushNum ); side = &buildBrush->sides[ buildBrush->numsides ]; Mem_Set( side, 0, sizeof( *side )); buildBrush->numsides++; // read the three point plane definition Com_Parse1DMatrix( mapfile, 3, planePoints[0] ); Com_Parse1DMatrix( mapfile, 3, planePoints[1] ); Com_Parse1DMatrix( mapfile, 3, planePoints[2] ); // read the texture matrix if( g_bBrushPrimit == BRUSH_RADIANT ) Com_Parse2DMatrix( mapfile, 2, 3, (float *)side->texMat ); // read the texturedef or shadername Com_ReadToken( mapfile, SC_ALLOW_PATHNAMES|SC_PARSE_GENERIC, &token ); com.strncpy( name, token.string, sizeof( name )); if( g_bBrushPrimit == BRUSH_WORLDCRAFT_22 || g_bBrushPrimit == BRUSH_GEARCRAFT_40 ) // Worldcraft 2.2+ { // texture U axis Com_ReadToken( mapfile, 0, &token ); if( com.strcmp( token.string, "[" )) Sys_Break( "missing '[' in texturedef (U)\n" ); Com_ReadFloat( mapfile, false, &vects.hammer.UAxis[0] ); Com_ReadFloat( mapfile, false, &vects.hammer.UAxis[1] ); Com_ReadFloat( mapfile, false, &vects.hammer.UAxis[2] ); Com_ReadFloat( mapfile, false, &vects.hammer.shift[0] ); Com_ReadToken( mapfile, 0, &token ); if( com.strcmp( token.string, "]" )) Sys_Break( "missing ']' in texturedef (U)\n" ); // texture V axis Com_ReadToken( mapfile, 0, &token ); if( com.strcmp( token.string, "[" )) Sys_Break( "missing '[' in texturedef (V)\n" ); Com_ReadFloat( mapfile, false, &vects.hammer.VAxis[0] ); Com_ReadFloat( mapfile, false, &vects.hammer.VAxis[1] ); Com_ReadFloat( mapfile, false, &vects.hammer.VAxis[2] ); Com_ReadFloat( mapfile, false, &vects.hammer.shift[1] ); Com_ReadToken( mapfile, 0, &token ); if( com.strcmp( token.string, "]" )) Sys_Break( "missing ']' in texturedef (V)\n"); // texture rotation is implicit in U/V axes. Com_ReadToken( mapfile, 0, &token ); vects.hammer.rotate = 0; // texure scale Com_ReadFloat( mapfile, false, &vects.hammer.scale[0] ); Com_ReadFloat( mapfile, false, &vects.hammer.scale[1] ); if( g_bBrushPrimit == BRUSH_GEARCRAFT_40 ) { Com_ReadLong( mapfile, false, &flags ); // read gearcraft flags Com_SkipRestOfLine( mapfile ); // gearcraft lightmap scale and rotate if( flags & GEARBOX_DETAIL ) side->compileFlags |= C_DETAIL; } } else if( g_bBrushPrimit == BRUSH_WORLDCRAFT_21 || g_bBrushPrimit == BRUSH_QUARK ) { // worldcraft 2.1-, old Radiant, QuArK Com_ReadFloat( mapfile, false, &vects.hammer.shift[0] ); Com_ReadFloat( mapfile, false, &vects.hammer.shift[1] ); Com_ReadFloat( mapfile, false, &vects.hammer.rotate ); Com_ReadFloat( mapfile, false, &vects.hammer.scale[0] ); Com_ReadFloat( mapfile, SC_COMMENT_SEMICOLON, &vects.hammer.scale[1] ); } // set default flags and values com.sprintf( shader, "textures/%s", name ); if( onlyLights ) si = &shaderInfo[0]; else si = ShaderInfoForShader( shader ); side->shaderInfo = si; side->surfaceFlags = si->surfaceFlags; side->contentFlags = si->contentFlags; side->compileFlags = si->compileFlags; side->value = si->value; // bias texture shift for non-radiant sides if( g_bBrushPrimit != BRUSH_RADIANT && si->globalTexture == false ) { vects.hammer.shift[0] -= (floor( vects.hammer.shift[0] / si->shaderWidth ) * si->shaderWidth); vects.hammer.shift[1] -= (floor( vects.hammer.shift[1] / si->shaderHeight ) * si->shaderHeight); } // historically, there are 3 integer values at the end of a brushside line in a .map file. // in quake 3, the only thing that mattered was the first of these three values, which // was previously the content flags. and only then did a single bit matter, the detail // bit. because every game has its own special flags for specifying detail, the // traditionally game-specified BASECONT_DETAIL flag was overridden for Q3Map 2.3.0 // by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but // is stored in compileFlags, as opposed to contentFlags, for multiple-game // portability. :sigh: if( g_bBrushPrimit != BRUSH_QUARK && Com_ReadToken( mapfile, SC_COMMENT_SEMICOLON, &token )) { // overwrite shader values directly from .map file Com_SaveToken( mapfile, &token ); Com_ReadLong( mapfile, false, &flags ); Com_ReadLong( mapfile, false, NULL ); Com_ReadLong( mapfile, false, NULL ); if( flags & C_DETAIL ) side->compileFlags |= C_DETAIL; } if( mapfile->TXcommand == '1' || mapfile->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 texMat[2]; float dot22, dot23, dot33, mdet, aa, bb, dd; int j, k; g_bBrushPrimit = BRUSH_QUARK; // we can detect it only here k = mapfile->TXcommand - '0'; for( j = 0; j < 3; j++ ) texMat[1][j] = (planePoints[k][j] - planePoints[0][j]) * (0.0078125f); // QuArK magic value k = 3 - k; for( j = 0; j < 3; j++ ) texMat[0][j] = (planePoints[k][j] - planePoints[0][j]) * (0.0078125f); // QuArK magic value dot22 = DotProduct( texMat[0], texMat[0] ); dot23 = DotProduct( texMat[0], texMat[1] ); dot33 = DotProduct( texMat[1], texMat[1] ); mdet = dot22 * dot33 - dot23 * dot23; if( mdet < 1E-6 && mdet > -1E-6 ) { aa = bb = dd = 0; MsgDev( D_WARN, "Entity %i, Brush %i: degenerate QuArK-style texture: \n", buildBrush->entityNum, buildBrush->brushNum ); } else { mdet = 1.0 / mdet; aa = dot33 * mdet; bb = -dot23 * mdet; dd = dot22 * mdet; } for( j = 0; j < 3; j++ ) { vects.quark.vecs[0][j] = aa * texMat[0][j] + bb * texMat[1][j]; vects.quark.vecs[1][j] = -(bb * texMat[0][j] + dd * texMat[1][j]); } vects.quark.vecs[0][3] = -DotProduct( vects.quark.vecs[0], planePoints[0] ); vects.quark.vecs[1][3] = -DotProduct( vects.quark.vecs[1], planePoints[0] ); } // find the plane number planenum = MapPlaneFromPoints( planePoints ); if( planenum == -1 ) { MsgDev( D_ERROR, "Entity %i, Brush %i: plane with no normal\n", buildBrush->entityNum, buildBrush->brushNum ); continue; } side->planenum = planenum; if( g_bBrushPrimit == BRUSH_QUARK ) { // QuArK format completely matched with internal // FIXME: don't calculate vecs, use QuArK texMat instead ? Mem_Copy( side->vecs, vects.quark.vecs, sizeof( side->vecs )); } else if( g_bBrushPrimit != BRUSH_RADIANT ) { vec3_t vecs[2]; float ang, sinv, cosv, ns, nt; int i, j, sv, tv; if( g_bBrushPrimit == BRUSH_WORLDCRAFT_21 ) TextureAxisFromPlane( &mapplanes[planenum], vecs[0], vecs[1] ); if( !vects.hammer.scale[0] ) vects.hammer.scale[0] = 1.0f; if( !vects.hammer.scale[1] ) vects.hammer.scale[1] = 1.0f; if( g_bBrushPrimit == BRUSH_WORLDCRAFT_21 ) { // rotate axis if( vects.hammer.rotate == 0 ) { sinv = 0; cosv = 1; } else if( vects.hammer.rotate == 90 ) { sinv = 1; cosv = 0; } else if( vects.hammer.rotate == 180 ) { sinv = 0; cosv = -1; } else if( vects.hammer.rotate == 270 ) { sinv = -1; cosv = 0; } else { ang = vects.hammer.rotate / 180 * M_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++ ) side->vecs[i][j] = vecs[i][j] / vects.hammer.scale[i]; } else if( g_bBrushPrimit == BRUSH_WORLDCRAFT_22 || g_bBrushPrimit == BRUSH_GEARCRAFT_40 ) { float scale; scale = 1.0f / vects.hammer.scale[0]; VectorScale( vects.hammer.UAxis, scale, side->vecs[0] ); scale = 1.0f / vects.hammer.scale[1]; VectorScale( vects.hammer.VAxis, scale, side->vecs[1] ); } // add shifts side->vecs[0][3] = vects.hammer.shift[0]; side->vecs[1][3] = vects.hammer.shift[1]; } } if( g_bBrushPrimit == BRUSH_RADIANT ) { Com_SaveToken( mapfile, &token ); Com_CheckToken( mapfile, "}" ); Com_CheckToken( mapfile, "}" ); } }
/** * @sa BaseLightForFace */ int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, const vec3_t origin, qboolean isTerrain) { vec3_t vecs[2]; int sv, tv; vec_t ang, sinv, cosv; dBspTexinfo_t tx, *tc; int i, j, k; float shift[2]; vec3_t scaledOrigin; if (!bt->name[0]) return 0; OBJZERO(tx); Q_strncpyz(tx.texture, bt->name, sizeof(tx.texture)); TextureAxisFromPlane(plane, vecs[0], vecs[1], isTerrain); /* dot product of a vertex location with the [4] part will produce a * texcoord (s or t depending on the first index) */ VectorScale(origin, 1.0 / bt->scale[0], scaledOrigin); shift[0] = DotProduct(scaledOrigin, vecs[0]); VectorScale(origin, 1.0 / bt->scale[1], scaledOrigin); shift[1] = DotProduct(scaledOrigin, vecs[1]); if (!bt->scale[0]) bt->scale[0] = 1; if (!bt->scale[1]) bt->scale[1] = 1; /* rotate axis */ if (bt->rotate == 0) { sinv = 0; cosv = 1; } else if (bt->rotate == 90) { sinv = 1; cosv = 0; } else if (bt->rotate == 180) { sinv = 0; cosv = -1; } else if (bt->rotate == 270) { sinv = -1; cosv = 0; } else { ang = bt->rotate * torad; sinv = sin(ang); cosv = cos(ang); } shift[0] = cosv * shift[0] - sinv * shift[1]; shift[1] = sinv * shift[0] + cosv * shift[1]; 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++) { const vec_t ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; const vec_t 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] / bt->scale[i]; /* texture offsets */ tx.vecs[0][3] = bt->shift[0] + shift[0]; tx.vecs[1][3] = bt->shift[1] + shift[1]; tx.surfaceFlags = bt->surfaceFlags; tx.value = bt->value; /* find the texinfo */ tc = curTile->texinfo; for (i = 0; i < curTile->numtexinfo; i++, tc++) { if (tc->surfaceFlags != tx.surfaceFlags) continue; if (tc->value != tx.value) continue; if (!Q_streq(tc->texture, tx.texture)) continue; for (j = 0; j < 2; j++) { for (k = 0; k < 4; k++) { if (tc->vecs[j][k] != tx.vecs[j][k]) goto skip; } } return i; skip:; } if (curTile->numtexinfo >= MAX_MAP_TEXINFO) Sys_Error("MAX_MAP_TEXINFO overflow"); *tc = tx; curTile->numtexinfo++; return i; }
void ParseBrushFace (entity_t *ent, mbrush_t **brushpointer, brushtype_t brushtype) { int i, j, sv, tv, hltexdef, facecontents, faceflags, facevalue, q2brushface, q3brushface, bpface; vec_t planepts[3][3], t1[3], t2[3], d, rotate, scale[2], vecs[2][4], ang, sinv, cosv, ns, nt, bp[2][3]; mface_t *f, *f2; plane_t plane; texinfo_t tx; mbrush_t *b; if (brushtype == BRUSHTYPE_PATCHDEF2 || brushtype == BRUSHTYPE_PATCHDEF3) return; // read the three point plane definition if (strcmp (token, "(") ) Error ("parsing brush on line %d\n", scriptline); GetToken (false); planepts[0][0] = atof(token); GetToken (false); planepts[0][1] = atof(token); GetToken (false); planepts[0][2] = atof(token); GetToken (false); if (!strcmp(token, ")")) { GetToken (false); if (strcmp(token, "(")) Error("parsing brush on line %d\n", scriptline); GetToken (false); planepts[1][0] = atof(token); GetToken (false); planepts[1][1] = atof(token); GetToken (false); planepts[1][2] = atof(token); GetToken (false); if (strcmp(token, ")")) Error("parsing brush on line %d\n", scriptline); GetToken (false); if (strcmp(token, "(")) Error("parsing brush on line %d\n", scriptline); GetToken (false); planepts[2][0] = atof(token); GetToken (false); planepts[2][1] = atof(token); GetToken (false); planepts[2][2] = atof(token); GetToken (false); if (strcmp(token, ")")) Error("parsing brush on line %d\n", scriptline); // convert points to a plane VectorSubtract(planepts[0], planepts[1], t1); VectorSubtract(planepts[2], planepts[1], t2); CrossProduct(t1, t2, plane.normal); VectorNormalize(plane.normal); plane.dist = DotProduct(planepts[1], plane.normal); } else { // oh, it's actually a 4 value plane plane.normal[0] = planepts[0][0]; plane.normal[1] = planepts[0][1]; plane.normal[2] = planepts[0][2]; plane.dist = -atof(token); GetToken (false); if (strcmp(token, ")")) Error("parsing brush on line %d\n", scriptline); } // read the texturedef memset (&tx, 0, sizeof(tx)); GetToken (false); bpface = false; hltexdef = false; if (!strcmp(token, "(")) { // brush primitives, utterly insane bpface = true; // ( GetToken(false); // ( GetToken(false); bp[0][0] = atof(token); GetToken(false); bp[0][1] = atof(token); GetToken(false); bp[0][2] = atof(token); GetToken(false); // ) GetToken(false); // ( GetToken(false); bp[1][0] = atof(token); GetToken(false); bp[1][1] = atof(token); GetToken(false); bp[1][2] = atof(token); GetToken(false); // ) GetToken (false); GetToken (false); tx.miptex = FindMiptex (token); rotate = 0; scale[0] = 1; scale[1] = 1; } else { // if the texture name contains a / then this is a q2/q3 brushface // strip off the path, wads don't use a path on texture names tx.miptex = FindMiptex (token); GetToken (false); if (!strcmp(token, "[")) { hltexdef = true; // S vector GetToken(false); vecs[0][0] = (vec_t)atof(token); GetToken(false); vecs[0][1] = (vec_t)atof(token); GetToken(false); vecs[0][2] = (vec_t)atof(token); GetToken(false); vecs[0][3] = (vec_t)atof(token); // ] GetToken(false); // [ GetToken(false); // T vector GetToken(false); vecs[1][0] = (vec_t)atof(token); GetToken(false); vecs[1][1] = (vec_t)atof(token); GetToken(false); vecs[1][2] = (vec_t)atof(token); GetToken(false); vecs[1][3] = (vec_t)atof(token); // ] GetToken(false); // rotation (unused - implicit in tex coords) GetToken(false); rotate = 0; } else { vecs[0][3] = (vec_t)atof(token); // LordHavoc: float coords GetToken (false); vecs[1][3] = (vec_t)atof(token); // LordHavoc: float coords GetToken (false); rotate = atof(token); // LordHavoc: float coords } GetToken (false); scale[0] = (vec_t)atof(token); // LordHavoc: was already float coords GetToken (false); scale[1] = (vec_t)atof(token); // LordHavoc: was already float coords } // q3 .map properties, currently unused but parsed facecontents = 0; faceflags = 0; facevalue = 0; q2brushface = false; q3brushface = false; if (GetToken (false)) { q2brushface = true; facecontents = atoi(token); if (GetToken (false)) { faceflags = atoi(token); if (GetToken (false)) { q2brushface = false; q3brushface = true; facevalue = atoi(token); } } } // skip trailing info (the 3 q3 .map parameters for example) while (GetToken (false)); if (DotProduct(plane.normal, plane.normal) < 0.1) { printf ("WARNING: brush plane with no normal on line %d\n", scriptline); return; } if (bpface) { // fake proper texture vectors from QuakeEd style TextureAxisFromPlane(&plane, vecs[0], vecs[1], true); // FIXME: deal with the bp stuff here printf("warning: brush primitive texturing not yet supported (line %d)\n", scriptline); // generic texturing tx.vecs[0][0] = vecs[0][0]; tx.vecs[0][1] = vecs[0][1]; tx.vecs[0][2] = vecs[0][2]; tx.vecs[0][3] = vecs[0][3]; tx.vecs[1][0] = vecs[1][0]; tx.vecs[1][1] = vecs[1][1]; tx.vecs[1][2] = vecs[1][2]; tx.vecs[1][3] = vecs[1][3]; } else { if (hltexdef) { for (i = 0; i < 2; i++) { d = 1.0 / (scale[i] ? scale[i] : 1.0); for (j = 0; j < 3; j++) tx.vecs[i][j] = vecs[i][j] * d; tx.vecs[i][3] = vecs[i][3] /*+ DotProduct(origin, tx.vecs[i])*/; // Sajt: ripped the commented out bit from the HL compiler code, not really sure what it is exactly doing // 'origin': origin set on bmodel by origin brush or origin key } } else { // fake proper texture vectors from QuakeEd style TextureAxisFromPlane(&plane, vecs[0], vecs[1], q3brushface); // 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 * (Q_PI / 180);sinv = sin(ang);cosv = cos(ang);} // LordHavoc: I don't quite understand this for (sv = 0;sv < 2 && !vecs[0][sv];sv++); for (tv = 0;tv < 2 && !vecs[1][tv];tv++); for (i = 0;i < 2;i++) { // rotate 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; // scale and store into texinfo d = 1.0 / (scale[i] ? scale[i] : 1.0); for (j = 0;j < 3;j++) tx.vecs[i][j] = vecs[i][j] * d; tx.vecs[i][3] = vecs[i][3]; } } } /* // LordHavoc: fix for CheckFace: point off plane errors in some maps (most notably QOOLE ones), // and hopefully preventing most 'portal clipped away' warnings VectorNormalize (plane.normal); for (j = 0;j < 3;j++) plane.normal[j] = (Q_rint((vec_t) plane.normal[j] * (vec_t) 8.0)) * (vec_t) (1.0 / 8.0); VectorNormalize (plane.normal); plane.dist = DotProduct (t3, plane.normal); d = (Q_rint(plane.dist * 8.0)) * (1.0 / 8.0); //if (fabs(d - plane.dist) >= (0.4 / 8.0)) // printf("WARNING: correcting minor math errors in brushface on line %d\n", scriptline); plane.dist = d; */ /* VectorNormalize (plane.normal); plane.dist = DotProduct (t3, plane.normal); VectorCopy(plane.normal, v); //for (j = 0;j < 3;j++) // v[j] = (Q_rint((vec_t) v[j] * (vec_t) 32.0)) * (vec_t) (1.0 / 32.0); VectorNormalize (v); d = (Q_rint(DotProduct (t3, v) * 8.0)) * (1.0 / 8.0); // if deviation is too high, warn (frequently happens on QOOLE maps) if (fabs(DotProduct(v, plane.normal) - 1.0) > (0.5 / 32.0) || fabs(d - plane.dist) >= (0.25 / 8.0)) printf("WARNING: minor misalignment of brushface on line %d\n" "normal %f %f %f (l: %f d: %f)\n" "rounded to %f %f %f (l: %f d: %f r: %f)\n", scriptline, (vec_t) plane.normal[0], (vec_t) plane.normal[1], (vec_t) plane.normal[2], (vec_t) sqrt(DotProduct(plane.normal, plane.normal)), (vec_t) DotProduct (t3, plane.normal), (vec_t) v[0], (vec_t) v[1], (vec_t) v[2], (vec_t) sqrt(DotProduct(v, v)), (vec_t) DotProduct(t3, v), (vec_t) d); //VectorCopy(v, plane.normal); //plane.dist = d; */ b = *brushpointer; if (b) { // 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) { printf ("WARNING: brush with duplicate plane (first point is at %g %g %g, .map file line number %d)\n", planepts[0][0], planepts[0][1], planepts[0][2], scriptline); return; } } else { b = &mapbrushes[nummapbrushes]; nummapbrushes++; b->next = ent->brushes; ent->brushes = b; *brushpointer = b; } f = qmalloc(sizeof(mface_t)); f->next = b->faces; b->faces = f; f->plane = plane; f->texinfo = FindTexinfo (&tx); nummapbrushfaces++; }
void AbsoluteToLocal( const class edPlane_c& normal2, face_s* f, edVec3_c& p1, edVec3_c& p2, edVec3_c& p3 ) { edVec3_c ex, ey, ez; #ifdef _DEBUG if ( g_qeglobals.m_bBrushPrimitMode ) Sys_Printf( "Warning : illegal call of AbsoluteToLocal in brush primitive mode\n" ); #endif // computing new local axis base TextureAxisFromPlane( normal2, ex, ey ); ez.crossProduct( ex, ey ); // projecting back on (ex,ey) Back( ez, p1 ); Back( ez, p2 ); Back( ez, p3 ); edVec3_c aux = p2 - p1; float x = aux.dotProduct( ex ); float y = aux.dotProduct( ey ); f->texdef.rotate = RAD2DEG( atan2( y, x ) ); // computing rotated local axis base aux = ez; aux *= f->texdef.rotate; edVec3_c rex = ex; VectorRotate( rex, aux, rex ); edVec3_c rey = ey; VectorRotate( rey, aux, rey ); // scale aux = p2 - p1; f->texdef.scale[0] = aux.dotProduct( rex ); aux = p3 - p1; f->texdef.scale[1] = aux.dotProduct( rey ); // shift // only using p1 x = rex.dotProduct( p1 ); y = rey.dotProduct( p1 ); x /= f->texdef.scale[0]; y /= f->texdef.scale[1]; p1 = rex * x; aux = rey * y; aux *= y; p1 += aux; aux = ez * -f->texdef.rotate; VectorRotate( p1, aux, p1 ); f->texdef.shift[0] = -p1.dotProduct( ex ); f->texdef.shift[1] = -p1.dotProduct( ey ); // stored rot is good considering local axis base // change it if necessary f->texdef.rotate = -f->texdef.rotate; Clamp( f->texdef.shift[0], f->d_texture->width ); Clamp( f->texdef.shift[1], f->d_texture->height ); Clamp( f->texdef.rotate, 360 ); }
static void SetTexinfo_QuakeEd(const plane_t *plane, const int shift[2], int rotate, const vec_t scale[2], texinfo_t *out) { int i, j; vec3_t vecs[2]; int sv, tv; vec_t ang, sinv, cosv; vec_t ns, nt; TextureAxisFromPlane(plane, vecs[0], vecs[1]); /* Normalize the Texture rotation */ rotate %= 360; while (rotate < 0) rotate += 360; // rotate axis switch (rotate) { case 0: sinv = 0; cosv = 1; break; case 90: sinv = 1; cosv = 0; break; case 180: sinv = 0; cosv = -1; break; case 270: sinv = -1; cosv = 0; break; default: ang = (vec_t)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++) /* Interpret zero scale as no scaling */ out->vecs[i][j] = vecs[i][j] / (scale[i] ? scale[i] : 1); out->vecs[0][3] = shift[0]; out->vecs[1][3] = shift[1]; }
void AbsoluteToLocal(plane_t normal2, face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3) { vec3_t ex,ey,ez; // computing new local axis base TextureAxisFromPlane(&normal2, ex, ey); CrossProduct(ex, ey, ez); // projecting back on (ex,ey) Back(ez,p1); Back(ez,p2); Back(ez,p3); vec3_t aux; // rotation VectorCopy(p2, aux); VectorSubtract(aux, p1,aux); float x = DotProduct(aux,ex); float y = DotProduct(aux,ey); f->texdef.rotate = 180 * atan2(y,x) / Q_PI; vec3_t rex,rey; // computing rotated local axis base VectorCopy(ez, aux); VectorScale(aux, f->texdef.rotate, aux); VectorCopy(ex, rex); VectorRotate(rex, aux, rex); VectorCopy(ey, rey); VectorRotate(rey, aux, rey); // scale VectorCopy(p2, aux); VectorSubtract(aux, p1, aux); f->texdef.scale[0] = DotProduct(aux, rex); VectorCopy(p3, aux); VectorSubtract(aux, p1, aux); f->texdef.scale[1] = DotProduct(aux, rey); // shift // only using p1 x = DotProduct(rex,p1); y = DotProduct(rey,p1); x /= f->texdef.scale[0]; y /= f->texdef.scale[1]; VectorCopy(rex, p1); VectorScale(p1, x, p1); VectorCopy(rey, aux); VectorScale(aux, y, aux); VectorAdd(p1, aux, p1); VectorCopy(ez, aux); VectorScale(aux, -f->texdef.rotate, aux); VectorRotate(p1, aux, p1); f->texdef.shift[0] = -DotProduct(p1, ex); f->texdef.shift[1] = -DotProduct(p1, ey); // stored rot is good considering local axis base // change it if necessary f->texdef.rotate = -f->texdef.rotate; Clamp(f->texdef.shift[0], f->d_texture->width); Clamp(f->texdef.shift[1], f->d_texture->height); Clamp(f->texdef.rotate, 360); }
/* ================= 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; }
/* ================= ParseBrush ================= */ void ParseBrush (void) { int i, j, sv, tv, hltexdef; vec_t planepts[3][3], t1[3], t2[3], d, rotate, scale[2], vecs[2][4], ang, sinv, cosv, ns, nt; mbrush_t *b; mface_t *f, *f2; plane_t plane; texinfo_t tx; b = &mapbrushes[nummapbrushes]; nummapbrushes++; b->next = mapent->brushes; mapent->brushes = b; do { if (!GetToken (true)) break; if (!strcmp (token, "}") ) break; // read the three point plane definition for (i = 0;i < 3;i++) { if (i != 0) GetToken (true); if (strcmp (token, "(") ) Error ("parsing brush on line %d\n", scriptline); for (j = 0;j < 3;j++) { GetToken (false); planepts[i][j] = atof(token); // LordHavoc: float coords } GetToken (false); if (strcmp (token, ")") ) Error ("parsing brush on line %d\n", scriptline); } //fflush(stdout); // convert points to a plane VectorSubtract(planepts[0], planepts[1], t1); VectorSubtract(planepts[2], planepts[1], t2); CrossProduct(t1, t2, plane.normal); VectorNormalize(plane.normal); plane.dist = DotProduct(planepts[1], plane.normal); // read the texturedef memset (&tx, 0, sizeof(tx)); GetToken (false); tx.miptex = FindMiptex (token); GetToken (false); if ((hltexdef = !strcmp(token, "["))) { // S vector GetToken(false); vecs[0][0] = atof(token); GetToken(false); vecs[0][1] = atof(token); GetToken(false); vecs[0][2] = atof(token); GetToken(false); vecs[0][3] = atof(token); // ] GetToken(false); // [ GetToken(false); // T vector GetToken(false); vecs[1][0] = atof(token); GetToken(false); vecs[1][1] = atof(token); GetToken(false); vecs[1][2] = atof(token); GetToken(false); vecs[1][3] = atof(token); // ] GetToken(false); } else { vecs[0][3] = atof(token); // LordHavoc: float coords GetToken (false); vecs[1][3] = atof(token); // LordHavoc: float coords } GetToken (false); rotate = atof(token); // LordHavoc: float coords GetToken (false); scale[0] = atof(token); // LordHavoc: was already float coords GetToken (false); scale[1] = atof(token); // LordHavoc: was already float coords // 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) { printf ("WARNING: brush with duplicate plane (first point is at %g %g %g, .map file line number %d)\n", planepts[0][0], planepts[0][1], planepts[0][2], scriptline); continue; } if (DotProduct(plane.normal, plane.normal) < 0.1) { printf ("WARNING: brush plane with no normal on line %d\n", scriptline); continue; } /* // LordHavoc: fix for CheckFace: point off plane errors in some maps (most notably QOOLE ones), // and hopefully preventing most 'portal clipped away' warnings VectorNormalize (plane.normal); for (j = 0;j < 3;j++) plane.normal[j] = (Q_rint((vec_t) plane.normal[j] * (vec_t) 8.0)) * (vec_t) (1.0 / 8.0); VectorNormalize (plane.normal); plane.dist = DotProduct (t3, plane.normal); d = (Q_rint(plane.dist * 8.0)) * (1.0 / 8.0); //if (fabs(d - plane.dist) >= (0.4 / 8.0)) // printf("WARNING: correcting minor math errors in brushface on line %d\n", scriptline); plane.dist = d; */ /* VectorNormalize (plane.normal); plane.dist = DotProduct (t3, plane.normal); VectorCopy(plane.normal, v); //for (j = 0;j < 3;j++) // v[j] = (Q_rint((vec_t) v[j] * (vec_t) 32.0)) * (vec_t) (1.0 / 32.0); VectorNormalize (v); d = (Q_rint(DotProduct (t3, v) * 8.0)) * (1.0 / 8.0); // if deviation is too high, warn (frequently happens on QOOLE maps) if (fabs(DotProduct(v, plane.normal) - 1.0) > (0.5 / 32.0) || fabs(d - plane.dist) >= (0.25 / 8.0)) printf("WARNING: minor misalignment of brushface on line %d\n" "normal %f %f %f (l: %f d: %f)\n" "rounded to %f %f %f (l: %f d: %f r: %f)\n", scriptline, (vec_t) plane.normal[0], (vec_t) plane.normal[1], (vec_t) plane.normal[2], (vec_t) sqrt(DotProduct(plane.normal, plane.normal)), (vec_t) DotProduct (t3, plane.normal), (vec_t) v[0], (vec_t) v[1], (vec_t) v[2], (vec_t) sqrt(DotProduct(v, v)), (vec_t) DotProduct(t3, v), (vec_t) d); //VectorCopy(v, plane.normal); //plane.dist = d; */ if (!hltexdef) { // fake proper texture vectors from QuakeEd style TextureAxisFromPlane(&plane, vecs[0], vecs[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 * (Q_PI / 180);sinv = sin(ang);cosv = cos(ang);} // LordHavoc: I don't quite understand this for (sv = 0;sv < 2 && !vecs[0][sv];sv++); for (tv = 0;tv < 2 && !vecs[1][tv];tv++); for (i = 0;i < 2;i++) { // rotate 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; // scale and store into texinfo d = 1.0 / (scale[i] ? scale[i] : 1.0); for (j = 0;j < 3;j++) tx.vecs[i][j] = vecs[i][j] * d; tx.vecs[i][3] = vecs[i][3]; } f = malloc(sizeof(mface_t)); f->next = b->faces; b->faces = f; f->plane = plane; f->texinfo = FindTexinfo (&tx); nummapbrushfaces++; } while (1); }
static void SetTexinfo_QuakeEd(int shift[2], int rotate, vec_t scale[2], texinfo_t *tx) { int i, j; vec3_t vecs[2]; int sv, tv; vec_t ang, sinv, cosv; vec_t ns, nt; TextureAxisFromPlane(&(map.rgFaces[map.iFaces].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 = (vec_t)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]; }
void ParseBrush (void) { mbrush_t *b; mface_t *f, *f2; vec3_t planepts[3]; vec3_t t1, t2, t3; int i,j; texinfo_t tx; double d; float shift[2], rotate, scale[2]; char name[64]; b = &mapbrushes[nummapbrushes]; do { if (!GetToken (true)) break; if (!strcmp (token, "}") ) break; // read the three point plane definition for (i=0 ; i<3 ; i++) { if (i != 0) GetToken (true); if (strcmp (token, "(") ) logerror ("parsing brush"); // jkrige - was Error() for (j=0 ; j<3 ; j++) { GetToken (false); // jkrige - floating point texture support //planepts[i][j] = atoi(token); planepts[i][j] = atof(token); // jkrige - floating point texture support } GetToken (false); if (strcmp (token, ")") ) logerror ("parsing brush"); // jkrige - was Error() } // read the texturedef memset (&tx, 0, sizeof(tx)); GetToken (false); strcpy (name, token); // JDC 8/8/97: for origin texture tx.miptex = FindMiptex (token); GetToken (false); shift[0] = atoi(token); GetToken (false); shift[1] = atoi(token); GetToken (false); rotate = atoi(token); GetToken (false); scale[0] = atof(token); GetToken (false); scale[1] = atof(token); GetToken (false); b->Light = atol(token); // 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) { logprint ("WARNING: brush with duplicate plane\n"); continue; } f = malloc(sizeof(mface_t)); f->next = b->faces; b->faces = f; // 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)) { logprint ("WARNING: brush plane with no normal\n"); b->faces = f->next; free (f); break; } VectorNormalize (f->plane.normal); f->plane.dist = DotProduct (t3, f->plane.normal); // // fake proper texture vectors from QuakeEd style // { vec3_t vecs[2]; int sv, tv; float ang, sinv, cosv; float 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); } while (1); // JDC 8/8/97 // origin brushes are removed, but they set // the rotation origin for the rest of the brushes // in the entity // if (Q_strncasecmp (name, "origin",6)) { // keep it nummapbrushes++; b->next = mapent->brushes; mapent->brushes = b; } else { // don't save the brush, just use as entity origin char string[32]; vec3_t origin; if (num_entities == 1) logerror ("Origin brushes not allowed in world"); // jkrige - was Error() BrushOrigin (b, origin); sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); SetKeyValue (mapent, "origin", string); VectorCopy (origin, mapent->origin); memset (b, 0, sizeof(*b)); } }
/* ================= ParseBrush ================= */ void ParseBrush (void) { mbrush_t *b; mface_t *f, *f2; vec3_t planepts[3]; vec3_t t1, t2, t3; int i,j; texinfo_t tx; vec_t d; float shift[2], rotate, scale[2]; b = &mapbrushes[nummapbrushes]; nummapbrushes++; b->next = mapent->brushes; mapent->brushes = b; do { if (!GetToken (true)) break; if (!strcmp (token, "}") ) break; // read the three point plane definition for (i=0 ; i<3 ; i++) { if (i != 0) GetToken (true); if (strcmp (token, "(") ) Error ("parsing brush"); for (j=0 ; j<3 ; j++) { GetToken (false); planepts[i][j] = atof(token); // LordHavoc: float coords } GetToken (false); if (strcmp (token, ")") ) Error ("parsing brush"); } fflush(stdout); // read the texturedef memset (&tx, 0, sizeof(tx)); GetToken (false); tx.miptex = FindMiptex (token); GetToken (false); shift[0] = atof(token); // LordHavoc: float coords GetToken (false); shift[1] = atof(token); // LordHavoc: float coords GetToken (false); rotate = atof(token); // LordHavoc: float coords GetToken (false); scale[0] = atof(token); // LordHavoc: was already float coords GetToken (false); scale[1] = atof(token); // LordHavoc: was already float coords // 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) { printf ("WARNING: brush with duplicate plane\n"); continue; } f = malloc(sizeof(mface_t)); f->next = b->faces; b->faces = f; // 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)) { printf ("WARNING: brush plane with no normal\n"); b->faces = f->next; free (f); break; } VectorNormalize (f->plane.normal); f->plane.dist = DotProduct (t3, f->plane.normal); // // fake proper texture vectors from QuakeEd style // { vec3_t vecs[2]; int sv, tv; float ang, sinv, cosv; float 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); } while (1); }
void BeginTexturingFace (brush_t *b, face_t *f, qtexture_t *q) { vec3_t pvecs[2]; int sv, tv; float ang, sinv, cosv; float ns, nt; int i,j; float shade; // get natural texture axis TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]); // set shading for face shade = SetShadeForPlane(&f->plane); if (camera.draw_mode == cd_texture && !b->owner->eclass->fixedsize) { f->d_color[0] = f->d_color[1] = f->d_color[2] = shade; } else { f->d_color[0] = shade*q->color[0]; f->d_color[1] = shade*q->color[1]; f->d_color[2] = shade*q->color[2]; } if (camera.draw_mode != cd_texture) return; if (!f->texdef.scale[0]) f->texdef.scale[0] = 1; if (!f->texdef.scale[1]) f->texdef.scale[1] = 1; // rotate axis if (f->texdef.rotate == 0) { sinv = 0 ; cosv = 1; } else if (f->texdef.rotate == 90) { sinv = 1 ; cosv = 0; } else if (f->texdef.rotate == 180) { sinv = 0 ; cosv = -1; } else if (f->texdef.rotate == 270) { sinv = -1 ; cosv = 0; } else { ang = f->texdef.rotate / 180.0f*pMath_PI; sinv = sin(ang); cosv = cos(ang); } if (pvecs[0][0]) sv = 0; else if (pvecs[0][1]) sv = 1; else sv = 2; if (pvecs[1][0]) tv = 0; else if (pvecs[1][1]) tv = 1; else tv = 2; for (i=0 ; i<2 ; i++) { ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv]; nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv]; vecs[i][sv] = ns; vecs[i][tv] = nt; } for (i=0 ; i<2 ; i++) for (j=0 ; j<3 ; j++) vecs[i][j] = vecs[i][j] / f->texdef.scale[i]; }
int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, const Vector& origin) { Vector vecs[2]; int sv, tv; vec_t ang, sinv, cosv; vec_t ns, nt; texinfo_t tx, *tc; int i, j, k; if (!bt->name[0]) return 0; memset (&tx, 0, sizeof(tx)); // HLTOOLS - add support for texture vectors stored in the map file if (g_nMapFileVersion < 220) { TextureAxisFromPlane(plane, vecs[0], vecs[1]); } if (!bt->textureWorldUnitsPerTexel[0]) bt->textureWorldUnitsPerTexel[0] = 1; if (!bt->textureWorldUnitsPerTexel[1]) bt->textureWorldUnitsPerTexel[1] = 1; if (g_nMapFileVersion < 220) { // rotate axis if (bt->rotate == 0) { sinv = 0 ; cosv = 1; } else if (bt->rotate == 90) { sinv = 1 ; cosv = 0; } else if (bt->rotate == 180) { sinv = 0 ; cosv = -1; } else if (bt->rotate == 270) { sinv = -1 ; cosv = 0; } else { ang = bt->rotate / 180 * M_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.textureVecsTexelsPerWorldUnits[i][j] = vecs[i][j] / bt->textureWorldUnitsPerTexel[i]; tx.lightmapVecsLuxelsPerWorldUnits[i][j] = tx.textureVecsTexelsPerWorldUnits[i][j] / 16.0f; } } } else { tx.textureVecsTexelsPerWorldUnits[0][0] = bt->UAxis[0] / bt->textureWorldUnitsPerTexel[0]; tx.textureVecsTexelsPerWorldUnits[0][1] = bt->UAxis[1] / bt->textureWorldUnitsPerTexel[0]; tx.textureVecsTexelsPerWorldUnits[0][2] = bt->UAxis[2] / bt->textureWorldUnitsPerTexel[0]; tx.textureVecsTexelsPerWorldUnits[1][0] = bt->VAxis[0] / bt->textureWorldUnitsPerTexel[1]; tx.textureVecsTexelsPerWorldUnits[1][1] = bt->VAxis[1] / bt->textureWorldUnitsPerTexel[1]; tx.textureVecsTexelsPerWorldUnits[1][2] = bt->VAxis[2] / bt->textureWorldUnitsPerTexel[1]; tx.lightmapVecsLuxelsPerWorldUnits[0][0] = bt->UAxis[0] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[0][1] = bt->UAxis[1] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[0][2] = bt->UAxis[2] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[1][0] = bt->VAxis[0] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[1][1] = bt->VAxis[1] / bt->lightmapWorldUnitsPerLuxel; tx.lightmapVecsLuxelsPerWorldUnits[1][2] = bt->VAxis[2] / bt->lightmapWorldUnitsPerLuxel; } tx.textureVecsTexelsPerWorldUnits[0][3] = bt->shift[0] + DOT_PRODUCT( origin, tx.textureVecsTexelsPerWorldUnits[0] ); tx.textureVecsTexelsPerWorldUnits[1][3] = bt->shift[1] + DOT_PRODUCT( origin, tx.textureVecsTexelsPerWorldUnits[1] ); tx.lightmapVecsLuxelsPerWorldUnits[0][3] = bt->shift[0] + DOT_PRODUCT( origin, tx.lightmapVecsLuxelsPerWorldUnits[0] ); tx.lightmapVecsLuxelsPerWorldUnits[1][3] = bt->shift[1] + DOT_PRODUCT( origin, tx.lightmapVecsLuxelsPerWorldUnits[1] ); tx.flags = bt->flags; // // find the texinfo // if ( numtexinfo >= MAX_MAP_TEXINFO ) { Error( "Map has too many texinfos, MAX_MAP_TEXINFO == %i\n", MAX_MAP_TEXINFO ); } tc = texinfo; tx.texdata = FindTexData( bt->name ); for (i=0 ; i<numtexinfo ; i++, tc++) { if (tc->flags != tx.flags) continue; bool skip = false; for (j=0 ; j<2 && !skip; j++) { if ( tc->texdata != tx.texdata ) { skip = true; break; } for (k=0 ; k<4 && !skip; k++) { if (tc->textureVecsTexelsPerWorldUnits[j][k] != tx.textureVecsTexelsPerWorldUnits[j][k]) { skip = true; break; } if( tc->lightmapVecsLuxelsPerWorldUnits[j][k] != tx.lightmapVecsLuxelsPerWorldUnits[j][k] ) { skip = true; break; } } } if ( skip ) { continue; } return i; } *tc = tx; if ( onlyents ) { Error( "FindOrCreateTexInfo: Tried to create new texinfo during -onlyents compile!\n" ); } numtexinfo++; return i; }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int TexinfoForBrushTexture(plane_t *plane, brush_texture_t *bt, vec3_t origin) { vec3_t vecs[2]; int sv, tv; vec_t ang, sinv, cosv; vec_t ns, nt; texinfo_t tx, *tc; int i, j, k; float shift[2]; brush_texture_t anim; int mt; if (!bt->name[0]) return 0; memset (&tx, 0, sizeof(tx)); strcpy (tx.texture, bt->name); TextureAxisFromPlane(plane, vecs[0], vecs[1]); shift[0] = DotProduct (origin, vecs[0]); shift[1] = DotProduct (origin, vecs[1]); if (!bt->scale[0]) bt->scale[0] = 1; if (!bt->scale[1]) bt->scale[1] = 1; // rotate axis if (bt->rotate == 0) { sinv = 0 ; cosv = 1; } else if (bt->rotate == 90) { sinv = 1 ; cosv = 0; } else if (bt->rotate == 180) { sinv = 0 ; cosv = -1; } else if (bt->rotate == 270) { sinv = -1 ; cosv = 0; } else { ang = bt->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] / bt->scale[i]; tx.vecs[0][3] = bt->shift[0] + shift[0]; tx.vecs[1][3] = bt->shift[1] + shift[1]; tx.flags = bt->flags; tx.value = bt->value; // // find the texinfo // tc = texinfo; for (i=0 ; i<numtexinfo ; i++, tc++) { if (tc->flags != tx.flags) continue; if (tc->value != tx.value) continue; for (j=0 ; j<2 ; j++) { if (strcmp (tc->texture, tx.texture)) goto skip; for (k=0 ; k<4 ; k++) { if (tc->vecs[j][k] != tx.vecs[j][k]) goto skip; } } return i; skip:; } *tc = tx; numtexinfo++; // load the next animation mt = FindMiptex (bt->name); if (textureref[mt].animname[0]) { anim = *bt; strcpy (anim.name, textureref[mt].animname); tc->nexttexinfo = TexinfoForBrushTexture (plane, &anim, origin); } else tc->nexttexinfo = -1; return i; } //end of the function TexinfoForBrushTexture
// ===================================================================================== // TexinfoForBrushTexture // ===================================================================================== int TexinfoForBrushTexture(const plane_t* const plane, brush_texture_t* bt, const vec3_t origin) { vec3_t vecs[2]; int sv, tv; vec_t ang, sinv, cosv; vec_t ns, nt; texinfo_t tx; texinfo_t* tc; int i, j, k; memset(&tx, 0, sizeof(tx)); if(!strncmp(bt->name,"BEVEL",5)) { tx.flags |= TEX_BEVEL; safe_strncpy(bt->name,"NULL",5); } tx.miptex = FindMiptex(bt->name); // Note: FindMiptex() still needs to be called here to add it to the global miptex array // Very Sleazy Hack 104 - since the tx.miptex index will be bogus after we sort the miptex array later // Put the string name of the miptex in this "index" until after we are done sorting it in WriteMiptex(). tx.miptex = texmap64_store(strdup(bt->name)); // set the special flag if (bt->name[0] == '*' || !strncasecmp(bt->name, "sky", 3) // ===================================================================================== //Cpt_Andrew - Env_Sky Check // ===================================================================================== || !strncasecmp(bt->name, "env_sky", 5) // ===================================================================================== || !strncasecmp(bt->name, "clip", 4) || !strncasecmp(bt->name, "origin", 6) #ifdef ZHLT_NULLTEX // AJM || !strncasecmp(bt->name, "null", 4) #endif || !strncasecmp(bt->name, "aaatrigger", 10) ) { tx.flags |= TEX_SPECIAL; } if (bt->txcommand) { memcpy(tx.vecs, bt->vects.quark.vects, sizeof(tx.vecs)); if (origin[0] || origin[1] || origin[2]) { tx.vecs[0][3] += DotProduct(origin, tx.vecs[0]); tx.vecs[1][3] += DotProduct(origin, tx.vecs[1]); } } else { if (g_nMapFileVersion < 220) { TextureAxisFromPlane(plane, vecs[0], vecs[1]); } if (!bt->vects.valve.scale[0]) { bt->vects.valve.scale[0] = 1; } if (!bt->vects.valve.scale[1]) { bt->vects.valve.scale[1] = 1; } if (g_nMapFileVersion < 220) { // rotate axis if (bt->vects.valve.rotate == 0) { sinv = 0; cosv = 1; } else if (bt->vects.valve.rotate == 90) { sinv = 1; cosv = 0; } else if (bt->vects.valve.rotate == 180) { sinv = 0; cosv = -1; } else if (bt->vects.valve.rotate == 270) { sinv = -1; cosv = 0; } else { ang = bt->vects.valve.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] / bt->vects.valve.scale[i]; } } } else { vec_t scale; scale = 1 / bt->vects.valve.scale[0]; VectorScale(bt->vects.valve.UAxis, scale, tx.vecs[0]); scale = 1 / bt->vects.valve.scale[1]; VectorScale(bt->vects.valve.VAxis, scale, tx.vecs[1]); } tx.vecs[0][3] = bt->vects.valve.shift[0] + DotProduct(origin, tx.vecs[0]); tx.vecs[1][3] = bt->vects.valve.shift[1] + DotProduct(origin, tx.vecs[1]); } // // find the g_texinfo // ThreadLock(); tc = g_texinfo; for (i = 0; i < g_numtexinfo; i++, tc++) { // Sleazy hack 104, Pt 3 - Use strcmp on names to avoid dups if (strcmp(texmap64_retrieve((tc->miptex)), texmap64_retrieve((tx.miptex))) != 0) { continue; } if (tc->flags != tx.flags) { continue; } for (j = 0; j < 2; j++) { for (k = 0; k < 4; k++) { if (tc->vecs[j][k] != tx.vecs[j][k]) { goto skip; } } } ThreadUnlock(); return i; skip:; } hlassume(g_numtexinfo < MAX_MAP_TEXINFO, assume_MAX_MAP_TEXINFO); *tc = tx; g_numtexinfo++; ThreadUnlock(); return i; }