void Mod_SetOrthoBounds( float *mins, float *maxs ) { if( clgame.drawFuncs.GL_OrthoBounds ) { clgame.drawFuncs.GL_OrthoBounds( mins, maxs ); } Vector2Average( maxs, mins, world_orthocenter ); Vector2Subtract( maxs, world_orthocenter, world_orthohalf ); }
void GameAsteroid::CalculateParameters(bool moveToCenter, Vector3 direction, float randomMuliplier) { Vector2 toCenter = Vector2Make(0, 0); Vector2 center = _delegate->FieldCenter(); if (moveToCenter) { Vector2 position = GetPosition(); toCenter = Vector2Subtract(center, position); toCenter = Vector2Normalize(toCenter); } Vector2 random = Vector2Make(cosf(_random), sinf(_random)); _moveVector = Vector3Make(toCenter.x * 2.0 + random.x *randomMuliplier + direction.x , toCenter.y * 2.0 + random.y * randomMuliplier + direction.y, 0); float timex = center.x / _moveVector.x; float timey = center.y / _moveVector.y; float time = ____max(timey, timex) / 7; _existTimer = new MAXAnimationWait(time); _existTimer->_delegate = this; MAXAnimationManager::SharedAnimationManager()->AddAnimation(_existTimer); }
/** * @brief Calculates normals and tangents for all frames and does vertex merging based on smoothness * @param mesh The mesh to calculate normals for * @param nFrames How many frames the mesh has * @param smoothness How aggressively should normals be smoothed; value is compared with dotproduct of vectors to decide if they should be merged * @sa R_ModCalcNormalsAndTangents */ void R_ModCalcUniqueNormalsAndTangents (mAliasMesh_t *mesh, int nFrames, float smoothness) { int i, j; vec3_t triangleNormals[MAX_ALIAS_TRIS]; vec3_t triangleTangents[MAX_ALIAS_TRIS]; vec3_t triangleBitangents[MAX_ALIAS_TRIS]; const mAliasVertex_t *vertexes = mesh->vertexes; mAliasCoord_t *stcoords = mesh->stcoords; mAliasVertex_t *newVertexes; mAliasComplexVertex_t tmpVertexes[MAX_ALIAS_VERTS]; vec3_t tmpBitangents[MAX_ALIAS_VERTS]; mAliasCoord_t *newStcoords; const int numIndexes = mesh->num_tris * 3; const int32_t *indexArray = mesh->indexes; int32_t *newIndexArray; int indRemap[MAX_ALIAS_VERTS]; int sharedTris[MAX_ALIAS_VERTS]; int numVerts = 0; newIndexArray = (int32_t *)Mem_PoolAlloc(sizeof(int32_t) * numIndexes, vid_modelPool, 0); /* calculate per-triangle surface normals */ for (i = 0, j = 0; i < numIndexes; i += 3, j++) { vec3_t dir1, dir2; vec2_t dir1uv, dir2uv; /* calculate two mostly perpendicular edge directions */ VectorSubtract(vertexes[indexArray[i + 0]].point, vertexes[indexArray[i + 1]].point, dir1); VectorSubtract(vertexes[indexArray[i + 2]].point, vertexes[indexArray[i + 1]].point, dir2); Vector2Subtract(stcoords[indexArray[i + 0]], stcoords[indexArray[i + 1]], dir1uv); Vector2Subtract(stcoords[indexArray[i + 2]], stcoords[indexArray[i + 1]], dir2uv); /* we have two edge directions, we can calculate a third vector from * them, which is the direction of the surface normal */ CrossProduct(dir1, dir2, triangleNormals[j]); /* then we use the texture coordinates to calculate a tangent space */ if ((dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]) != 0.0) { const float frac = 1.0 / (dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]); vec3_t tmp1, tmp2; /* calculate tangent */ VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1); VectorMul(dir1uv[1] * frac, dir2, tmp2); VectorAdd(tmp1, tmp2, triangleTangents[j]); /* calculate bitangent */ VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1); VectorMul(dir1uv[0] * frac, dir2, tmp2); VectorAdd(tmp1, tmp2, triangleBitangents[j]); } else { const float frac = 1.0 / (0.00001); vec3_t tmp1, tmp2; /* calculate tangent */ VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1); VectorMul(dir1uv[1] * frac, dir2, tmp2); VectorAdd(tmp1, tmp2, triangleTangents[j]); /* calculate bitangent */ VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1); VectorMul(dir1uv[0] * frac, dir2, tmp2); VectorAdd(tmp1, tmp2, triangleBitangents[j]); } /* normalize */ VectorNormalizeFast(triangleNormals[j]); VectorNormalizeFast(triangleTangents[j]); VectorNormalizeFast(triangleBitangents[j]); Orthogonalize(triangleTangents[j], triangleBitangents[j]); } /* do smoothing */ for (i = 0; i < numIndexes; i++) { const int idx = (i - i % 3) / 3; VectorCopy(triangleNormals[idx], tmpVertexes[i].normal); VectorCopy(triangleTangents[idx], tmpVertexes[i].tangent); VectorCopy(triangleBitangents[idx], tmpBitangents[i]); for (j = 0; j < numIndexes; j++) { const int idx2 = (j - j % 3) / 3; /* don't add a vertex with itself */ if (j == i) continue; /* only average normals if vertices have the same position * and the normals aren't too far apart to start with */ if (VectorEqual(vertexes[indexArray[i]].point, vertexes[indexArray[j]].point) && DotProduct(triangleNormals[idx], triangleNormals[idx2]) > smoothness) { /* average the normals */ VectorAdd(tmpVertexes[i].normal, triangleNormals[idx2], tmpVertexes[i].normal); /* if the tangents match as well, average them too. * Note that having matching normals without matching tangents happens * when the order of vertices in two triangles sharing the vertex * in question is different. This happens quite frequently if the * modeler does not go out of their way to avoid it. */ if (Vector2Equal(stcoords[indexArray[i]], stcoords[indexArray[j]]) && DotProduct(triangleTangents[idx], triangleTangents[idx2]) > smoothness && DotProduct(triangleBitangents[idx], triangleBitangents[idx2]) > smoothness) { /* average the tangents */ VectorAdd(tmpVertexes[i].tangent, triangleTangents[idx2], tmpVertexes[i].tangent); VectorAdd(tmpBitangents[i], triangleBitangents[idx2], tmpBitangents[i]); } } } VectorNormalizeFast(tmpVertexes[i].normal); VectorNormalizeFast(tmpVertexes[i].tangent); VectorNormalizeFast(tmpBitangents[i]); } /* assume all vertices are unique until proven otherwise */ for (i = 0; i < numIndexes; i++) indRemap[i] = -1; /* merge vertices that have become identical */ for (i = 0; i < numIndexes; i++) { vec3_t n, b, t, v; if (indRemap[i] != -1) continue; for (j = i + 1; j < numIndexes; j++) { if (Vector2Equal(stcoords[indexArray[i]], stcoords[indexArray[j]]) && VectorEqual(vertexes[indexArray[i]].point, vertexes[indexArray[j]].point) && (DotProduct(tmpVertexes[i].normal, tmpVertexes[j].normal) > smoothness) && (DotProduct(tmpVertexes[i].tangent, tmpVertexes[j].tangent) > smoothness)) { indRemap[j] = i; newIndexArray[j] = numVerts; } } VectorCopy(tmpVertexes[i].normal, n); VectorCopy(tmpVertexes[i].tangent, t); VectorCopy(tmpBitangents[i], b); /* normalization here does shared-vertex smoothing */ VectorNormalizeFast(n); VectorNormalizeFast(t); VectorNormalizeFast(b); /* Grahm-Schmidt orthogonalization */ VectorMul(DotProduct(t, n), n, v); VectorSubtract(t, v, t); VectorNormalizeFast(t); /* calculate handedness */ CrossProduct(n, t, v); tmpVertexes[i].tangent[3] = (DotProduct(v, b) < 0.0) ? -1.0 : 1.0; VectorCopy(n, tmpVertexes[i].normal); VectorCopy(t, tmpVertexes[i].tangent); newIndexArray[i] = numVerts++; indRemap[i] = i; } for (i = 0; i < numVerts; i++) sharedTris[i] = 0; for (i = 0; i < numIndexes; i++) sharedTris[newIndexArray[i]]++; /* set up reverse-index that maps Vertex objects to a list of triangle verts */ mesh->revIndexes = (mIndexList_t *)Mem_PoolAlloc(sizeof(mIndexList_t) * numVerts, vid_modelPool, 0); for (i = 0; i < numVerts; i++) { mesh->revIndexes[i].length = 0; mesh->revIndexes[i].list = (int32_t *)Mem_PoolAlloc(sizeof(int32_t) * sharedTris[i], vid_modelPool, 0); } /* merge identical vertexes, storing only unique ones */ newVertexes = (mAliasVertex_t *)Mem_PoolAlloc(sizeof(mAliasVertex_t) * numVerts * nFrames, vid_modelPool, 0); newStcoords = (mAliasCoord_t *)Mem_PoolAlloc(sizeof(mAliasCoord_t) * numVerts, vid_modelPool, 0); for (i = 0; i < numIndexes; i++) { const int idx = indexArray[indRemap[i]]; const int idx2 = newIndexArray[i]; /* add vertex to new vertex array */ VectorCopy(vertexes[idx].point, newVertexes[idx2].point); Vector2Copy(stcoords[idx], newStcoords[idx2]); mesh->revIndexes[idx2].list[mesh->revIndexes[idx2].length++] = i; } /* copy over the points from successive frames */ for (i = 1; i < nFrames; i++) { for (j = 0; j < numIndexes; j++) { const int idx = indexArray[indRemap[j]] + (mesh->num_verts * i); const int idx2 = newIndexArray[j] + (numVerts * i); VectorCopy(vertexes[idx].point, newVertexes[idx2].point); } } /* copy new arrays back into original mesh */ Mem_Free(mesh->stcoords); Mem_Free(mesh->indexes); Mem_Free(mesh->vertexes); mesh->num_verts = numVerts; mesh->vertexes = newVertexes; mesh->stcoords = newStcoords; mesh->indexes = newIndexArray; }
/** * @brief Calculates a per-vertex tangentspace basis and stores it in GL arrays attached to the mesh * @param mesh The mesh to calculate normals for * @param framenum The animation frame to calculate normals for * @param translate The frame translation for the given animation frame * @param backlerp Whether to store the results in the GL arrays for the previous keyframe or the next keyframe * @sa R_ModCalcUniqueNormalsAndTangents */ static void R_ModCalcNormalsAndTangents (mAliasMesh_t *mesh, int framenum, const vec3_t translate, qboolean backlerp) { int i, j; mAliasVertex_t *vertexes = &mesh->vertexes[framenum * mesh->num_verts]; mAliasCoord_t *stcoords = mesh->stcoords; const int numIndexes = mesh->num_tris * 3; const int32_t *indexArray = mesh->indexes; vec3_t triangleNormals[MAX_ALIAS_TRIS]; vec3_t triangleTangents[MAX_ALIAS_TRIS]; vec3_t triangleBitangents[MAX_ALIAS_TRIS]; float *texcoords, *verts, *normals, *tangents; /* set up array pointers for either the previous keyframe or the next keyframe */ texcoords = mesh->texcoords; if (backlerp) { verts = mesh->verts; normals = mesh->normals; tangents = mesh->tangents; } else { verts = mesh->next_verts; normals = mesh->next_normals; tangents = mesh->next_tangents; } /* calculate per-triangle surface normals and tangents*/ for (i = 0, j = 0; i < numIndexes; i += 3, j++) { vec3_t dir1, dir2; vec2_t dir1uv, dir2uv; /* calculate two mostly perpendicular edge directions */ VectorSubtract(vertexes[indexArray[i + 0]].point, vertexes[indexArray[i + 1]].point, dir1); VectorSubtract(vertexes[indexArray[i + 2]].point, vertexes[indexArray[i + 1]].point, dir2); Vector2Subtract(stcoords[indexArray[i + 0]], stcoords[indexArray[i + 1]], dir1uv); Vector2Subtract(stcoords[indexArray[i + 2]], stcoords[indexArray[i + 1]], dir2uv); /* we have two edge directions, we can calculate a third vector from * them, which is the direction of the surface normal */ CrossProduct(dir1, dir2, triangleNormals[j]); /* normalize */ VectorNormalizeFast(triangleNormals[j]); /* then we use the texture coordinates to calculate a tangent space */ if ((dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]) != 0.0) { const float frac = 1.0 / (dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]); vec3_t tmp1, tmp2; /* calculate tangent */ VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1); VectorMul(dir1uv[1] * frac, dir2, tmp2); VectorAdd(tmp1, tmp2, triangleTangents[j]); /* calculate bitangent */ VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1); VectorMul(dir1uv[0] * frac, dir2, tmp2); VectorAdd(tmp1, tmp2, triangleBitangents[j]); /* normalize */ VectorNormalizeFast(triangleTangents[j]); VectorNormalizeFast(triangleBitangents[j]); } else { VectorClear(triangleTangents[j]); VectorClear(triangleBitangents[j]); } } /* for each vertex */ for (i = 0; i < mesh->num_verts; i++) { vec3_t n, b, v; vec4_t t; const int len = mesh->revIndexes[i].length; const int32_t *list = mesh->revIndexes[i].list; VectorClear(n); VectorClear(t); VectorClear(b); /* for each vertex that got mapped to this one (ie. for each triangle this vertex is a part of) */ for (j = 0; j < len; j++) { const int32_t idx = list[j] / 3; VectorAdd(n, triangleNormals[idx], n); VectorAdd(t, triangleTangents[idx], t); VectorAdd(b, triangleBitangents[idx], b); } /* normalization here does shared-vertex smoothing */ VectorNormalizeFast(n); VectorNormalizeFast(t); VectorNormalizeFast(b); /* Grahm-Schmidt orthogonalization */ Orthogonalize(t, n); /* calculate handedness */ CrossProduct(n, t, v); t[3] = (DotProduct(v, b) < 0.0) ? -1.0 : 1.0; /* copy this vertex's info to all the right places in the arrays */ for (j = 0; j < len; j++) { const int32_t idx = list[j]; const int meshIndex = mesh->indexes[list[j]]; Vector2Copy(stcoords[meshIndex], (texcoords + (2 * idx))); VectorAdd(vertexes[meshIndex].point, translate, (verts + (3 * idx))); VectorCopy(n, (normals + (3 * idx))); Vector4Copy(t, (tangents + (4 * idx))); } } }
static boolean MakeTextureMatrix( decalProjector_t *dp, vec4_t projection, bspDrawVert_t *a, bspDrawVert_t *b, bspDrawVert_t *c ) { int i, j; double bb, s, t, d; dvec3_t pa, pb, pc; dvec3_t bary, xyz; dvec3_t vecs[ 3 ], axis[ 3 ], lengths; /* project triangle onto plane of projection */ d = DotProduct( a->xyz, projection ) - projection[ 3 ]; VectorMA( a->xyz, -d, projection, pa ); d = DotProduct( b->xyz, projection ) - projection[ 3 ]; VectorMA( b->xyz, -d, projection, pb ); d = DotProduct( c->xyz, projection ) - projection[ 3 ]; VectorMA( c->xyz, -d, projection, pc ); /* two methods */ #if 1 { /* old code */ /* calculate barycentric basis for the triangle */ bb = (b->st[ 0 ] - a->st[ 0 ]) * (c->st[ 1 ] - a->st[ 1 ]) - (c->st[ 0 ] - a->st[ 0 ]) * (b->st[ 1 ] - a->st[ 1 ]); if( fabs( bb ) < 0.00000001 ) return false; /* calculate texture origin */ #if 0 s = 0.0; t = 0.0; bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb; bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb; bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb; origin[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ]; origin[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ]; origin[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ]; #endif /* calculate s vector */ s = a->st[ 0 ] + 1.0; t = a->st[ 1 ] + 0.0; bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb; bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb; bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb; xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ]; xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ]; xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ]; //% VectorSubtract( xyz, origin, vecs[ 0 ] ); VectorSubtract( xyz, pa, vecs[ 0 ] ); /* calculate t vector */ s = a->st[ 0 ] + 0.0; t = a->st[ 1 ] + 1.0; bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb; bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb; bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb; xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ]; xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ]; xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ]; //% VectorSubtract( xyz, origin, vecs[ 1 ] ); VectorSubtract( xyz, pa, vecs[ 1 ] ); /* calcuate r vector */ VectorScale( projection, -1.0, vecs[ 2 ] ); /* calculate transform axis */ for( i = 0; i < 3; i++ ) lengths[ i ] = DVectorNormalize( vecs[ i ], axis[ i ] ); for( i = 0; i < 2; i++ ) for( j = 0; j < 3; j++ ) dp->texMat[ i ][ j ] = lengths[ i ] > 0.0 ? (axis[ i ][ j ] / lengths[ i ]) : 0.0; //% dp->texMat[ i ][ j ] = fabs( vecs[ i ][ j ] ) > 0.0 ? (1.0 / vecs[ i ][ j ]) : 0.0; //% dp->texMat[ i ][ j ] = axis[ i ][ j ] > 0.0 ? (1.0 / axis[ i ][ j ]) : 0.0; /* calculalate translation component */ dp->texMat[ 0 ][ 3 ] = a->st[ 0 ] - DotProduct( a->xyz, dp->texMat[ 0 ] ); dp->texMat[ 1 ][ 3 ] = a->st[ 1 ] - DotProduct( a->xyz, dp->texMat[ 1 ] ); } #else { int k; dvec3_t origin, deltas[ 3 ]; double texDeltas[ 3 ][ 2 ]; double delta, texDelta; /* new code */ /* calculate deltas */ VectorSubtract( pa, pb, deltas[ 0 ] ); VectorSubtract( pa, pc, deltas[ 1 ] ); VectorSubtract( pb, pc, deltas[ 2 ] ); Vector2Subtract( a->st, b->st, texDeltas[ 0 ] ); Vector2Subtract( a->st, c->st, texDeltas[ 1 ] ); Vector2Subtract( b->st, c->st, texDeltas[ 2 ] ); /* walk st */ for( i = 0; i < 2; i++ ) { /* walk xyz */ for( j = 0; j < 3; j++ ) { /* clear deltas */ delta = 0.0; texDelta = 0.0; /* walk deltas */ for( k = 0; k < 3; k++ ) { if( fabs( deltas[ k ][ j ] ) > delta && fabs( texDeltas[ k ][ i ] ) > texDelta ) { delta = deltas[ k ][ j ]; texDelta = texDeltas[ k ][ i ]; } } /* set texture matrix component */ if( fabs( delta ) > 0.0 ) dp->texMat[ i ][ j ] = texDelta / delta; else dp->texMat[ i ][ j ] = 0.0; } /* set translation component */ dp->texMat[ i ][ 3 ] = a->st[ i ] - DotProduct( pa, dp->texMat[ i ] ); } } #endif /* debug code */ #if 1 MsgDev( D_NOTE, "Mat: [ %f %f %f %f ] [ %f %f %f %f ] Theta: %f (%f)\n", dp->texMat[ 0 ][ 0 ], dp->texMat[ 0 ][ 1 ], dp->texMat[ 0 ][ 2 ], dp->texMat[ 0 ][ 3 ], dp->texMat[ 1 ][ 0 ], dp->texMat[ 1 ][ 1 ], dp->texMat[ 1 ][ 2 ], dp->texMat[ 1 ][ 3 ], RAD2DEG( acos( DotProduct( dp->texMat[ 0 ], dp->texMat[ 1 ] ) ) ), RAD2DEG( acos( DotProduct( axis[ 0 ], axis[ 1 ] ) ) ) ); MsgDev( D_NOTE, "XYZ: %f %f %f ST: %f %f ST(t): %f %f\n", a->xyz[ 0 ], a->xyz[ 1 ], a->xyz[ 2 ], a->st[ 0 ], a->st[ 1 ], DotProduct( a->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ], DotProduct( a->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ] ); #endif /* test texture matrix */ s = DotProduct( a->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ]; t = DotProduct( a->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ]; if( fabs( s - a->st[ 0 ] ) > 0.01 || fabs( t - a->st[ 1 ] ) > 0.01 ) { MsgDev( D_ERROR, "Bad texture matrix! (A) (%f, %f) != (%f, %f)\n", s, t, a->st[ 0 ], a->st[ 1 ] ); //% return false; } s = DotProduct( b->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ]; t = DotProduct( b->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ]; if( fabs( s - b->st[ 0 ] ) > 0.01 || fabs( t - b->st[ 1 ] ) > 0.01 ) { MsgDev( D_ERROR, "Bad texture matrix! (B) (%f, %f) != (%f, %f)\n", s, t, b->st[ 0 ], b->st[ 1 ] ); //% return false; } s = DotProduct( c->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ]; t = DotProduct( c->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ]; if( fabs( s - c->st[ 0 ] ) > 0.01 || fabs( t - c->st[ 1 ] ) > 0.01 ) { MsgDev( D_ERROR, "Bad texture matrix! (C) (%f, %f) != (%f, %f)\n", s, t, c->st[ 0 ], c->st[ 1 ] ); //% return false; } /* disco */ return true; }