/* * Copyright (C) 1999-2000 Id Software, Inc. * * q_math.c -- stateless support routines that are included in each code module */ #include "q_shared.h" int32_t nonansicast = 0; vec3_t vec3_origin = { 0, 0, 0 }; vec3_t axisDefault[3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; vec4_t colorTable[CT_MAX] = { { 0, 0, 0, 0 }, /* CT_NONE */ { 0, 0, 0, 1 }, /* CT_BLACK */ { 1, 0, 0, 1 }, /* CT_RED */ { 0, 1, 0, 1 }, /* CT_GREEN */ { 0, 0, 1, 1 }, /* CT_BLUE */ { 1, 1, 0, 1 }, /* CT_YELLOW */ { 1, 0, 1, 1 }, /* CT_MAGENTA */ { 0, 1, 1, 1 }, /* CT_CYAN */ { 0.071f, 0.271f, 0.29f, 1 }, /* CT_TEAL */ { 0.529f, 0.373f, 0.017f, 1 },/* CT_GOLD */ { 1, 1, 1, 1 }, /* CT_WHITE */ { 0.75f, 0.75f, 0.75f, 1 }, /* CT_LTGREY */ { 0.50f, 0.50f, 0.50f, 1 }, /* CT_MDGREY */ { 0.25f, 0.25f, 0.25f, 1 }, /* CT_DKGREY */ { 0.15f, 0.15f, 0.15f, 1 }, /* CT_DKGREY2 */ { 0.688f, 0.797f, 1, 1 }, /* CT_VLTORANGE -- needs values */ { 0.688f, 0.797f, 1, 1 }, /* CT_LTORANGE */ { 0.620f, 0.710f, 0.894f, 1 },/* CT_DKORANGE */ { 0.463f, 0.525f, 0.671f, 1 },/* CT_VDKORANGE */ { 0.616f, 0.718f, 0.898f, 1 },/* CT_VLTBLUE1 */ { 0.286f, 0.506f, 0.898f, 1 },/* CT_LTBLUE1 */ { 0.082f, 0.388f, 0.898f, 1 },/* CT_DKBLUE1 */ { 0.063f, 0.278f, 0.514f, 1 },/* CT_VDKBLUE1 */ { 0.302f, 0.380f, 0.612f, 1 },/* CT_VLTBLUE2 -- needs values */ { 0.196f, 0.314f, 0.612f, 1 },/* CT_LTBLUE2 */ { 0.060f, 0.227f, 0.611f, 1 },/* CT_DKBLUE2 */ { 0.043f, 0.161f, 0.459f, 1 },/* CT_VDKBLUE2 */ { 0.082f, 0.388f, 0.898f, 1 },/* CT_VLTBROWN1 -- needs values */ { 0.082f, 0.388f, 0.898f, 1 },/* CT_LTBROWN1 */ { 0.078f, 0.320f, 0.813f, 1 },/* CT_DKBROWN1 */ { 0.060f, 0.227f, 0.611f, 1 },/* CT_VDKBROWN1 */ { 1, 0.784f, 0.365f, 1 }, /* CT_VLTGOLD1 -- needs values */ { 1, 0.706f, 0.153f, 1 }, /* CT_LTGOLD1 */ { 0.733f, 0.514f, 0.086f, 1 },/* CT_DKGOLD1 */ { 0.549f, 0.384f, 0.063f, 1 },/* CT_VDKGOLD1 */ { 0.688f, 0.797f, 1, 1 }, /* CT_VLTPURPLE1 -- needs values */ { 0.688f, 0.797f, 1, 1 }, /* CT_LTPURPLE1 */ { 0.313f, 0.578f, 1, 1 }, /* CT_DKPURPLE1 */ { 0.031f, 0.110f, 0.341f, 1 },/* CT_VDKPURPLE1 */ { 0.688f, 0.797f, 1, 1 }, /* CT_VLTPURPLE2 -- needs values */ { 0.688f, 0.797f, 1, 1 }, /* CT_LTPURPLE2 */ { 0.688f, 0.797f, 1, 1 }, /* CT_DKPURPLE2 */ { 0.031f, 0.110f, 0.341f, 1 },/* CT_VDKPURPLE2 */ { 0.686f, 0.808f, 0.1f, 1 }, /* CT_VLTPURPLE3 */ { 0.188f, 0.494f, 1, 1 }, /* CT_LTPURPLE3 */ { 0.094f, 0.471f, 1, 1 }, /* CT_DKPURPLE3 */ { 0.067f, 0.325f, 0.749f, 1 },/* CT_VDKPURPLE3 */ { 1, 0.612f, 0.325f, 1 }, /* CT_VLTRED1 */ { 1, 0.478f, 0.098f, 1 }, /* CT_LTRED1 */ { 1, 0.438f, 0, 1 }, /* CT_DKRED1 */ { 0.784f, 0.329f, 0, 1 }, /* CT_VDKRED1 */ }; vec4_t colorBlack = { 0, 0, 0, 1 }; vec4_t colorRed = { 1, 0, 0, 1 }; vec4_t colorGreen = { 0, 1, 0, 1 }; vec4_t colorBlue = { 0, 0, 1, 1 }; vec4_t colorYellow = { 1, 1, 0, 1 }; vec4_t colorMagenta = { 1, 0, 1, 1 }; vec4_t colorCyan = { 0, 1, 1, 1 }; vec4_t colorWhite = { 1, 1, 1, 1 }; vec4_t colorLtGrey = { 0.75, 0.75, 0.75, 1 }; vec4_t colorMdGrey = { 0.5, 0.5, 0.5, 1 }; vec4_t colorDkGrey = { 0.25, 0.25, 0.25, 1 }; vec4_t g_color_table[8] = { { 0.0, 0.0, 0.0, 1.0 }, { 1.0, 0.0, 0.0, 1.0 }, { 0.0, 1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0 }, { 0.0, 1.0, 1.0, 1.0 }, { 1.0, 0.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0, 1.0 }, }; vec3_t bytedirs[NUMVERTEXNORMALS] = { { -0.525731f, 0.000000f, 0.850651f }, { -0.442863f, 0.238856f, 0.864188f }, { -0.295242f, 0.000000f, 0.955423f }, { -0.309017f, 0.500000f, 0.809017f }, { -0.162460f, 0.262866f, 0.951056f }, { 0.000000f, 0.000000f, 1.000000f }, { 0.000000f, 0.850651f, 0.525731f }, { -0.147621f, 0.716567f, 0.681718f }, { 0.147621f, 0.716567f, 0.681718f }, { 0.000000f, 0.525731f, 0.850651f }, { 0.309017f, 0.500000f, 0.809017f }, { 0.525731f, 0.000000f, 0.850651f }, { 0.295242f, 0.000000f, 0.955423f }, { 0.442863f, 0.238856f, 0.864188f }, { 0.162460f, 0.262866f, 0.951056f }, { -0.681718f, 0.147621f, 0.716567f }, { -0.809017f, 0.309017f, 0.500000f }, { -0.587785f, 0.425325f, 0.688191f }, { -0.850651f, 0.525731f, 0.000000f }, { -0.864188f, 0.442863f, 0.238856f }, { -0.716567f, 0.681718f, 0.147621f }, { -0.688191f, 0.587785f, 0.425325f }, { -0.500000f, 0.809017f, 0.309017f }, { -0.238856f, 0.864188f, 0.442863f }, { -0.425325f, 0.688191f, 0.587785f }, { -0.716567f, 0.681718f, -0.147621f }, { -0.500000f, 0.809017f, -0.309017f }, { -0.525731f, 0.850651f, 0.000000f }, { 0.000000f, 0.850651f, -0.525731f }, { -0.238856f, 0.864188f, -0.442863f }, { 0.000000f, 0.955423f, -0.295242f }, { -0.262866f, 0.951056f, -0.162460f }, { 0.000000f, 1.000000f, 0.000000f }, { 0.000000f, 0.955423f, 0.295242f }, { -0.262866f, 0.951056f, 0.162460f }, { 0.238856f, 0.864188f, 0.442863f }, { 0.262866f, 0.951056f, 0.162460f }, { 0.500000f, 0.809017f, 0.309017f }, { 0.238856f, 0.864188f, -0.442863f }, { 0.262866f, 0.951056f, -0.162460f }, { 0.500000f, 0.809017f, -0.309017f }, { 0.850651f, 0.525731f, 0.000000f }, { 0.716567f, 0.681718f, 0.147621f }, { 0.716567f, 0.681718f, -0.147621f }, { 0.525731f, 0.850651f, 0.000000f }, { 0.425325f, 0.688191f, 0.587785f }, { 0.864188f, 0.442863f, 0.238856f }, { 0.688191f, 0.587785f, 0.425325f }, { 0.809017f, 0.309017f, 0.500000f }, { 0.681718f, 0.147621f, 0.716567f }, { 0.587785f, 0.425325f, 0.688191f }, { 0.955423f, 0.295242f, 0.000000f }, { 1.000000f, 0.000000f, 0.000000f }, { 0.951056f, 0.162460f, 0.262866f }, { 0.850651f, -0.525731f, 0.000000f }, { 0.955423f, -0.295242f, 0.000000f }, { 0.864188f, -0.442863f, 0.238856f }, { 0.951056f, -0.162460f, 0.262866f }, { 0.809017f, -0.309017f, 0.500000f }, { 0.681718f, -0.147621f, 0.716567f }, { 0.850651f, 0.000000f, 0.525731f }, { 0.864188f, 0.442863f, -0.238856f }, { 0.809017f, 0.309017f, -0.500000f }, { 0.951056f, 0.162460f, -0.262866f }, { 0.525731f, 0.000000f, -0.850651f }, { 0.681718f, 0.147621f, -0.716567f }, { 0.681718f, -0.147621f, -0.716567f }, { 0.850651f, 0.000000f, -0.525731f }, { 0.809017f, -0.309017f, -0.500000f }, { 0.864188f, -0.442863f, -0.238856f }, { 0.951056f, -0.162460f, -0.262866f }, { 0.147621f, 0.716567f, -0.681718f }, { 0.309017f, 0.500000f, -0.809017f }, { 0.425325f, 0.688191f, -0.587785f }, { 0.442863f, 0.238856f, -0.864188f }, { 0.587785f, 0.425325f, -0.688191f }, { 0.688191f, 0.587785f, -0.425325f }, { -0.147621f, 0.716567f, -0.681718f }, { -0.309017f, 0.500000f, -0.809017f }, { 0.000000f, 0.525731f, -0.850651f }, { -0.525731f, 0.000000f, -0.850651f }, { -0.442863f, 0.238856f, -0.864188f }, { -0.295242f, 0.000000f, -0.955423f }, { -0.162460f, 0.262866f, -0.951056f }, { 0.000000f, 0.000000f, -1.000000f }, { 0.295242f, 0.000000f, -0.955423f }, { 0.162460f, 0.262866f, -0.951056f }, { -0.442863f, -0.238856f, -0.864188f }, { -0.309017f, -0.500000f, -0.809017f }, { -0.162460f, -0.262866f, -0.951056f }, { 0.000000f, -0.850651f, -0.525731f }, { -0.147621f, -0.716567f, -0.681718f }, { 0.147621f, -0.716567f, -0.681718f }, { 0.000000f, -0.525731f, -0.850651f }, { 0.309017f, -0.500000f, -0.809017f }, { 0.442863f, -0.238856f, -0.864188f }, { 0.162460f, -0.262866f, -0.951056f }, { 0.238856f, -0.864188f, -0.442863f }, { 0.500000f, -0.809017f, -0.309017f }, { 0.425325f, -0.688191f, -0.587785f }, { 0.716567f, -0.681718f, -0.147621f }, { 0.688191f, -0.587785f, -0.425325f }, { 0.587785f, -0.425325f, -0.688191f }, { 0.000000f, -0.955423f, -0.295242f }, { 0.000000f, -1.000000f, 0.000000f }, { 0.262866f, -0.951056f, -0.162460f }, { 0.000000f, -0.850651f, 0.525731f }, { 0.000000f, -0.955423f, 0.295242f }, { 0.238856f, -0.864188f, 0.442863f }, { 0.262866f, -0.951056f, 0.162460f }, { 0.500000f, -0.809017f, 0.309017f }, { 0.716567f, -0.681718f, 0.147621f }, { 0.525731f, -0.850651f, 0.000000f }, { -0.238856f, -0.864188f, -0.442863f }, { -0.500000f, -0.809017f, -0.309017f }, { -0.262866f, -0.951056f, -0.162460f }, { -0.850651f, -0.525731f, 0.000000f }, { -0.716567f, -0.681718f, -0.147621f }, { -0.716567f, -0.681718f, 0.147621f }, { -0.525731f, -0.850651f, 0.000000f }, { -0.500000f, -0.809017f, 0.309017f }, { -0.238856f, -0.864188f, 0.442863f }, { -0.262866f, -0.951056f, 0.162460f }, { -0.864188f, -0.442863f, 0.238856f }, { -0.809017f, -0.309017f, 0.500000f }, { -0.688191f, -0.587785f, 0.425325f }, { -0.681718f, -0.147621f, 0.716567f }, { -0.442863f, -0.238856f, 0.864188f }, { -0.587785f, -0.425325f, 0.688191f }, { -0.309017f, -0.500000f, 0.809017f }, { -0.147621f, -0.716567f, 0.681718f }, { -0.425325f, -0.688191f, 0.587785f }, { -0.162460f, -0.262866f, 0.951056f }, { 0.442863f, -0.238856f, 0.864188f }, { 0.162460f, -0.262866f, 0.951056f }, { 0.309017f, -0.500000f, 0.809017f }, { 0.147621f, -0.716567f, 0.681718f }, { 0.000000f, -0.525731f, 0.850651f }, { 0.425325f, -0.688191f, 0.587785f }, { 0.587785f, -0.425325f, 0.688191f }, { 0.688191f, -0.587785f, 0.425325f }, { -0.955423f, 0.295242f, 0.000000f }, { -0.951056f, 0.162460f, 0.262866f }, { -1.000000f, 0.000000f, 0.000000f }, { -0.850651f, 0.000000f, 0.525731f }, { -0.955423f, -0.295242f, 0.000000f }, { -0.951056f, -0.162460f, 0.262866f }, { -0.864188f, 0.442863f, -0.238856f }, { -0.951056f, 0.162460f, -0.262866f }, { -0.809017f, 0.309017f, -0.500000f }, { -0.864188f, -0.442863f, -0.238856f }, { -0.951056f, -0.162460f, -0.262866f }, { -0.809017f, -0.309017f, -0.500000f }, { -0.681718f, 0.147621f, -0.716567f }, { -0.681718f, -0.147621f, -0.716567f }, { -0.850651f, 0.000000f, -0.525731f }, { -0.688191f, 0.587785f, -0.425325f }, { -0.587785f, 0.425325f, -0.688191f }, { -0.425325f, 0.688191f, -0.587785f }, { -0.425325f, -0.688191f, -0.587785f }, { -0.587785f, -0.425325f, -0.688191f }, { -0.688191f, -0.587785f, -0.425325f } }; /*==============================================================*/ int32_t Q_rand(int32_t* seed) { *seed = (69069 * *seed + 1); return *seed; } float Q_random(int32_t *seed) { return (Q_rand(seed) & 0xffff) / (float)0x10000; } float Q_crandom(int32_t *seed) { return 2.0 * (Q_random(seed) - 0.5); } /*=======================================================*/ signed char ClampChar(int32_t i) { if (i < -128) { return -128; } if (i > 127) { return 127; } return i; } int16_t ClampShort(int32_t i) { if (i < (short)0x8000) { return (short)0x8000; } if (i > 0x7fff) { return 0x7fff; } return i; } /* this isn't a real cheap function to call! */ /** * Converts a direction vector into a byte */ int32_t DirToByte(vec3_t dir) { int32_t i, best; float d, bestd; if (dir == NULL) { return 0; } bestd = 0; best = 0; for (i = 0; i bestd) { bestd = d; best = i; } } return best; } /** * Converts a byte vector into a direction vector */ void ByteToDir(int32_t b, vec3_t dir) { if (b < 0 || b >= NUMVERTEXNORMALS) { VectorCopy(vec3_origin, dir); return; } VectorCopy(bytedirs[b], dir); } unsigned ColorBytes3(float r, float g, float b) { unsigned i; ((byte *)&i)[0] = r * 255; ((byte *)&i)[1] = g * 255; ((byte *)&i)[2] = b * 255; return i; } unsigned ColorBytes4(float r, float g, float b, float a) { unsigned i; ((byte *)&i)[0] = r * 255; ((byte *)&i)[1] = g * 255; ((byte *)&i)[2] = b * 255; ((byte *)&i)[3] = a * 255; return i; } float NormalizeColor(const vec3_t in, vec3_t out) { float max; max = in[0]; if (in[1] > max) { max = in[1]; } if (in[2] > max) { max = in[2]; } if (!max) { VectorClear(out); } else { out[0] = in[0] / max; out[1] = in[1] / max; out[2] = in[2] / max; } return max; } /*============================================================================*/ /* * \brief Returns false if the triangle is degenrate. * * The normal will point out of the clock for clockwise ordered points * */ qboolean PlaneFromPoints(vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c) { vec3_t d1, d2; VectorSubtract(b, a, d1); VectorSubtract(c, a, d2); CrossProduct(d2, d1, plane); if (VectorNormalize(plane) == 0) { return qfalse; } plane[3] = DotProduct(a, plane); return qtrue; } /** * RotatePointAroundVector * * This is not implemented very well... * */ void RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees) { float m[3][3]; float im[3][3]; float zrot[3][3]; float tmpmat[3][3]; float rot[3][3]; int32_t i; vec3_t vr, vup, vf; float rad; vf[0] = dir[0]; vf[1] = dir[1]; vf[2] = dir[2]; PerpendicularVector(vr, dir); CrossProduct(vr, vf, vup); m[0][0] = vr[0]; m[1][0] = vr[1]; m[2][0] = vr[2]; m[0][1] = vup[0]; m[1][1] = vup[1]; m[2][1] = vup[2]; m[0][2] = vf[0]; m[1][2] = vf[1]; m[2][2] = vf[2]; memcpy(im, m, sizeof(im)); im[0][1] = m[1][0]; im[0][2] = m[2][0]; im[1][0] = m[0][1]; im[1][2] = m[2][1]; im[2][0] = m[0][2]; im[2][1] = m[1][2]; memset(zrot, 0, sizeof(zrot)); zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F; rad = DEG2RAD(degrees); zrot[0][0] = cos(rad); zrot[0][1] = sin(rad); zrot[1][0] = -sin(rad); zrot[1][1] = cos(rad); MatrixMultiply(m, zrot, tmpmat); MatrixMultiply(tmpmat, im, rot); for (i = 0; i < 3; i++) { dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2]; } } /* =============== RotateAroundDirection =============== */ void RotateAroundDirection(vec3_t axis[3], float yaw) { /* create an arbitrary axis[1] */ PerpendicularVector(axis[1], axis[0]); /* rotate it around axis[0] by yaw */ if (yaw) { vec3_t temp; VectorCopy(axis[1], temp); RotatePointAroundVector(axis[1], axis[0], temp, yaw); } /* cross to get axis[2] */ CrossProduct(axis[0], axis[1], axis[2]); } void vectoangles(const vec3_t value1, vec3_t angles) { float forward; float yaw, pitch; if (value1[1] == 0 && value1[0] == 0) { yaw = 0; if (value1[2] > 0) { pitch = 90; } else { pitch = 270; } } else { if (value1[0]) { yaw = (atan2(value1[1], value1[0]) * 180 / M_PI); } else if (value1[1] > 0) { yaw = 90; } else { yaw = 270; } if (yaw < 0) { yaw += 360; } forward = sqrt(value1[0] * value1[0] + value1[1] * value1[1]); pitch = (atan2(value1[2], forward) * 180 / M_PI); if (pitch < 0) { pitch += 360; } } angles[PITCH] = -pitch; angles[YAW] = yaw; angles[ROLL] = 0; } /* ================= AnglesToAxis ================= */ void AnglesToAxis(const vec3_t angles, vec3_t axis[3]) { vec3_t right; /* angle vectors returns "right" instead of "y axis" */ AngleVectors(angles, axis[0], right, axis[2]); VectorSubtract(vec3_origin, right, axis[1]); } void AxisClear(vec3_t axis[3]) { axis[0][0] = 1; axis[0][1] = 0; axis[0][2] = 0; axis[1][0] = 0; axis[1][1] = 1; axis[1][2] = 0; axis[2][0] = 0; axis[2][1] = 0; axis[2][2] = 1; } void AxisCopy(vec3_t in[3], vec3_t out[3]) { VectorCopy(in[0], out[0]); VectorCopy(in[1], out[1]); VectorCopy(in[2], out[2]); } void ProjectPointOnPlane(vec3_t dst, const vec3_t p, const vec3_t normal) { float d; vec3_t n; float inv_denom; inv_denom = 1.0F / DotProduct(normal, normal); d = DotProduct(normal, p) * inv_denom; n[0] = normal[0] * inv_denom; n[1] = normal[1] * inv_denom; n[2] = normal[2] * inv_denom; dst[0] = p[0] - d * n[0]; dst[1] = p[1] - d * n[1]; dst[2] = p[2] - d * n[2]; } /** * * Given a normalized forward vector, create two * other perpendicular vectors * */ void MakeNormalVectors(const vec3_t forward, vec3_t right, vec3_t up) { float d; /* * this rotate and negate guarantees a vector * not colinear with the original */ right[1] = -forward[0]; right[2] = forward[1]; right[0] = forward[2]; d = DotProduct(right, forward); VectorMA(right, -d, forward, right); VectorNormalize(right); CrossProduct(right, forward, up); } void VectorRotate(vec3_t in, vec3_t matrix[3], vec3_t out) { out[0] = DotProduct(in, matrix[0]); out[1] = DotProduct(in, matrix[1]); out[2] = DotProduct(in, matrix[2]); } /*============================================================================ */ /* * float q_rsqrt( float number ) */ /** * Fast inverse square root. * * \param number number to calculate the inverse square root for * \return inverse square root of number */ float Q_rsqrt(float number) { long i; float x2, y; const float threehalfs = 1.5F; x2 = number * 0.5F; y = number; i = *(long *)&y; /* evil floating point bit level hacking */ i = 0x5f3759df - (i >> 1); /* what the fuck? */ y = *(float *)&i; y = y * (threehalfs - (x2 * y * y)); /* 1st iteration */ // y = y * ( threehalfs - ( x2 * y * y ) ); /* 2nd iteration, this can be removed */ return y; } double Q_fabs(double f) { int32_t tmp = *(int32_t *)&f; tmp &= 0x7FFFFFFF; return *(float *)&tmp; } //============================================================ /* =============== LerpAngle =============== */ float LerpAngle(float from, float to, float frac) { float a; if (to - from > 180) { to -= 360; } if (to - from < -180) { to += 360; } a = from + frac * (to - from); return a; } /** * AngleSubtract * * Always returns a value from -180 to 180 * */ float AngleSubtract(float a1, float a2) { float a; a = a1 - a2; while (a > 180) { a -= 360; } while (a < -180) { a += 360; } return a; } void AnglesSubtract(vec3_t v1, vec3_t v2, vec3_t v3) { v3[0] = AngleSubtract(v1[0], v2[0]); v3[1] = AngleSubtract(v1[1], v2[1]); v3[2] = AngleSubtract(v1[2], v2[2]); } float AngleMod(float a) { a = (360.0 / 65536) * ((int32_t)(a*(65536 / 360.0)) & 65535); return a; } /** * * AngleNormalize360 * * \param angle angle to normalize * \return angle normalized to the range [0 <= angle < 360] * */ float AngleNormalize360(float angle) { return (360.0 / 65536) * ((int32_t)(angle * (65536 / 360.0)) & 65535); } /** * * AngleNormalize180 * * \param angle angle to normalize * \return angle normalized to the range [-180 < angle <= 180] * */ float AngleNormalize180(float angle) { angle = AngleNormalize360(angle); if (angle > 180.0) { angle -= 360.0; } return angle; } /** * * AngleDelta * * \param angle1 first angle * \param angle2 second angle * \return the normalized delta from angle1 to angle2 * */ float AngleDelta(float angle1, float angle2) { return AngleNormalize180(angle1 - angle2); } /*============================================================*/ /* ================= SetPlaneSignbits ================= */ void SetPlaneSignbits(cplane_t *out) { int32_t bits, j; /* for fast box on planeside test */ bits = 0; for (j = 0; j<3; j++) { if (out->normal[j] < 0) { bits |= 1 << j; } } out->signbits = bits; } /* ================== BoxOnPlaneSide Returns 1, 2, or 1 + 2 // this is the slow, general version int32_t BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p) { 32_t i; float dist1, dist2; int32_t sides; vec3_t corners[2]; for (i=0 ; i<3 ; i++) { if (p->normal[i] < 0) { corners[0][i] = emins[i]; corners[1][i] = emaxs[i]; } else { corners[1][i] = emins[i]; corners[0][i] = emaxs[i]; } } dist1 = DotProduct (p->normal, corners[0]) - p->dist; dist2 = DotProduct (p->normal, corners[1]) - p->dist; sides = 0; if (dist1 >= 0) sides = 1; if (dist2 < 0) sides |= 2; return sides; } ================== */ #if !(defined __linux__ && defined __i386__ && !defined C_ONLY) || defined (__WIN32__) #if defined __LCC__ || defined C_ONLY || !id386 || defined (__WIN32__) int32_t BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, struct cplane_s *p) { float dist1, dist2; int32_t sides; /* fast axial cases */ if (p->type < 3) { if (p->dist <= emins[p->type]) return 1; if (p->dist >= emaxs[p->type]) return 2; return 3; } /* general case */ switch (p->signbits) { case 0: dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]; dist2 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]; break; case 1: dist1 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]; dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]; break; case 2: dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]; dist2 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]; break; case 3: dist1 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]; dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]; break; case 4: dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]; dist2 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]; break; case 5: dist1 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]; dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]; break; case 6: dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]; dist2 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]; break; case 7: dist1 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]; dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]; break; default: dist1 = dist2 = 0; /* shut up compiler */ break; } sides = 0; if (dist1 >= p->dist) sides = 1; if (dist2 < p->dist) sides |= 2; return sides; } #else #pragma warning( disable: 4035 ) __declspec(naked) int32_t BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, struct cplane_s *p) { static int32_t bops_initialized; static int32_t Ljmptab[8]; __asm { push ebx cmp bops_initialized, 1 je initialized mov bops_initialized, 1 mov Ljmptab[0 * 4], offset Lcase0 mov Ljmptab[1 * 4], offset Lcase1 mov Ljmptab[2 * 4], offset Lcase2 mov Ljmptab[3 * 4], offset Lcase3 mov Ljmptab[4 * 4], offset Lcase4 mov Ljmptab[5 * 4], offset Lcase5 mov Ljmptab[6 * 4], offset Lcase6 mov Ljmptab[7 * 4], offset Lcase7 initialized : mov edx, dword ptr[4 + 12 + esp] mov ecx, dword ptr[4 + 4 + esp] xor eax, eax mov ebx, dword ptr[4 + 8 + esp] mov al, byte ptr[17 + edx] cmp al, 8 jge Lerror fld dword ptr[0 + edx] fld st(0) jmp dword ptr[Ljmptab + eax * 4] Lcase0: fmul dword ptr[ebx] fld dword ptr[0 + 4 + edx] fxch st(2) fmul dword ptr[ecx] fxch st(2) fld st(0) fmul dword ptr[4 + ebx] fld dword ptr[0 + 8 + edx] fxch st(2) fmul dword ptr[4 + ecx] fxch st(2) fld st(0) fmul dword ptr[8 + ebx] fxch st(5) faddp st(3), st(0) fmul dword ptr[8 + ecx] fxch st(1) faddp st(3), st(0) fxch st(3) faddp st(2), st(0) jmp LSetSides Lcase1 : fmul dword ptr[ecx] fld dword ptr[0 + 4 + edx] fxch st(2) fmul dword ptr[ebx] fxch st(2) fld st(0) fmul dword ptr[4 + ebx] fld dword ptr[0 + 8 + edx] fxch st(2) fmul dword ptr[4 + ecx] fxch st(2) fld st(0) fmul dword ptr[8 + ebx] fxch st(5) faddp st(3), st(0) fmul dword ptr[8 + ecx] fxch st(1) faddp st(3), st(0) fxch st(3) faddp st(2), st(0) jmp LSetSides Lcase2 : fmul dword ptr[ebx] fld dword ptr[0 + 4 + edx] fxch st(2) fmul dword ptr[ecx] fxch st(2) fld st(0) fmul dword ptr[4 + ecx] fld dword ptr[0 + 8 + edx] fxch st(2) fmul dword ptr[4 + ebx] fxch st(2) fld st(0) fmul dword ptr[8 + ebx] fxch st(5) faddp st(3), st(0) fmul dword ptr[8 + ecx] fxch st(1) faddp st(3), st(0) fxch st(3) faddp st(2), st(0) jmp LSetSides Lcase3 : fmul dword ptr[ecx] fld dword ptr[0 + 4 + edx] fxch st(2) fmul dword ptr[ebx] fxch st(2) fld st(0) fmul dword ptr[4 + ecx] fld dword ptr[0 + 8 + edx] fxch st(2) fmul dword ptr[4 + ebx] fxch st(2) fld st(0) fmul dword ptr[8 + ebx] fxch st(5) faddp st(3), st(0) fmul dword ptr[8 + ecx] fxch st(1) faddp st(3), st(0) fxch st(3) faddp st(2), st(0) jmp LSetSides Lcase4 : fmul dword ptr[ebx] fld dword ptr[0 + 4 + edx] fxch st(2) fmul dword ptr[ecx] fxch st(2) fld st(0) fmul dword ptr[4 + ebx] fld dword ptr[0 + 8 + edx] fxch st(2) fmul dword ptr[4 + ecx] fxch st(2) fld st(0) fmul dword ptr[8 + ecx] fxch st(5) faddp st(3), st(0) fmul dword ptr[8 + ebx] fxch st(1) faddp st(3), st(0) fxch st(3) faddp st(2), st(0) jmp LSetSides Lcase5 : fmul dword ptr[ecx] fld dword ptr[0 + 4 + edx] fxch st(2) fmul dword ptr[ebx] fxch st(2) fld st(0) fmul dword ptr[4 + ebx] fld dword ptr[0 + 8 + edx] fxch st(2) fmul dword ptr[4 + ecx] fxch st(2) fld st(0) fmul dword ptr[8 + ecx] fxch st(5) faddp st(3), st(0) fmul dword ptr[8 + ebx] fxch st(1) faddp st(3), st(0) fxch st(3) faddp st(2), st(0) jmp LSetSides Lcase6 : fmul dword ptr[ebx] fld dword ptr[0 + 4 + edx] fxch st(2) fmul dword ptr[ecx] fxch st(2) fld st(0) fmul dword ptr[4 + ecx] fld dword ptr[0 + 8 + edx] fxch st(2) fmul dword ptr[4 + ebx] fxch st(2) fld st(0) fmul dword ptr[8 + ecx] fxch st(5) faddp st(3), st(0) fmul dword ptr[8 + ebx] fxch st(1) faddp st(3), st(0) fxch st(3) faddp st(2), st(0) jmp LSetSides Lcase7 : fmul dword ptr[ecx] fld dword ptr[0 + 4 + edx] fxch st(2) fmul dword ptr[ebx] fxch st(2) fld st(0) fmul dword ptr[4 + ecx] fld dword ptr[0 + 8 + edx] fxch st(2) fmul dword ptr[4 + ebx] fxch st(2) fld st(0) fmul dword ptr[8 + ecx] fxch st(5) faddp st(3), st(0) fmul dword ptr[8 + ebx] fxch st(1) faddp st(3), st(0) fxch st(3) faddp st(2), st(0) LSetSides: faddp st(2), st(0) fcomp dword ptr[12 + edx] xor ecx, ecx fnstsw ax fcomp dword ptr[12 + edx] and ah, 1 xor ah, 1 add cl, ah fnstsw ax and ah, 1 add ah, ah add cl, ah pop ebx mov eax, ecx ret Lerror : int 3 } } #pragma warning( default: 4035 ) #endif #endif /* ================= RadiusFromBounds ================= */ float RadiusFromBounds(const vec3_t mins, const vec3_t maxs) { int32_t i; vec3_t corner; float a, b; for (i = 0; i<3; i++) { a = fabs(mins[i]); b = fabs(maxs[i]); corner[i] = a > b ? a : b; } return VectorLength(corner); } void ClearBounds(vec3_t mins, vec3_t maxs) { mins[0] = mins[1] = mins[2] = 99999; maxs[0] = maxs[1] = maxs[2] = -99999; } void AddPointToBounds(const vec3_t v, vec3_t mins, vec3_t maxs) { if (v[0] < mins[0]) { mins[0] = v[0]; } if (v[0] > maxs[0]) { maxs[0] = v[0]; } if (v[1] < mins[1]) { mins[1] = v[1]; } if (v[1] > maxs[1]) { maxs[1] = v[1]; } if (v[2] < mins[2]) { mins[2] = v[2]; } if (v[2] > maxs[2]) { maxs[2] = v[2]; } } int32_t VectorCompare(const vec3_t v1, const vec3_t v2) { if (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2]) { return 0; } return 1; } vec_t VectorNormalize(vec3_t v) { float length, ilength; length = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; length = sqrt(length); if (length) { ilength = 1 / length; v[0] *= ilength; v[1] *= ilength; v[2] *= ilength; } return length; } /* * fast vector normalize routine that does not check to make sure * that length != 0, nor does it return length */ void VectorNormalizeFast(vec3_t v) { float ilength; ilength = Q_rsqrt(DotProduct(v, v)); v[0] *= ilength; v[1] *= ilength; v[2] *= ilength; } vec_t VectorNormalize2(const vec3_t v, vec3_t out) { float length, ilength; length = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; length = sqrt(length); if (length) { ilength = 1 / length; out[0] = v[0] * ilength; out[1] = v[1] * ilength; out[2] = v[2] * ilength; } else { VectorClear(out); } return length; } void _VectorMA(const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc) { vecc[0] = veca[0] + scale*vecb[0]; vecc[1] = veca[1] + scale*vecb[1]; vecc[2] = veca[2] + scale*vecb[2]; } vec_t _DotProduct(const vec3_t v1, const vec3_t v2) { return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; } void _VectorSubtract(const vec3_t veca, const vec3_t vecb, vec3_t out) { out[0] = veca[0] - vecb[0]; out[1] = veca[1] - vecb[1]; out[2] = veca[2] - vecb[2]; } void _VectorAdd(const vec3_t veca, const vec3_t vecb, vec3_t out) { out[0] = veca[0] + vecb[0]; out[1] = veca[1] + vecb[1]; out[2] = veca[2] + vecb[2]; } void _VectorCopy(const vec3_t in, vec3_t out) { out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; } void _VectorScale(const vec3_t in, vec_t scale, vec3_t out) { out[0] = in[0] * scale; out[1] = in[1] * scale; out[2] = in[2] * scale; } void CrossProduct(const vec3_t v1, const vec3_t v2, vec3_t cross) { cross[0] = v1[1] * v2[2] - v1[2] * v2[1]; cross[1] = v1[2] * v2[0] - v1[0] * v2[2]; cross[2] = v1[0] * v2[1] - v1[1] * v2[0]; } vec_t VectorLength(const vec3_t v) { return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); } vec_t VectorLengthSquared(const vec3_t v) { return (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); } vec_t Distance(const vec3_t p1, const vec3_t p2) { vec3_t v; VectorSubtract(p2, p1, v); return VectorLength(v); } vec_t DistanceSquared(const vec3_t p1, const vec3_t p2) { vec3_t v; VectorSubtract(p2, p1, v); return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; } void VectorInverse(vec3_t v) { v[0] = -v[0]; v[1] = -v[1]; v[2] = -v[2]; } void Vector4Scale(const vec4_t in, vec_t scale, vec4_t out) { out[0] = in[0] * scale; out[1] = in[1] * scale; out[2] = in[2] * scale; out[3] = in[3] * scale; } int32_t Q_log2(int32_t val) { int32_t answer; answer = 0; while ((val >>= 1) != 0) { answer++; } return answer; } /* ================= PlaneTypeForNormal ================= */ int32_t PlaneTypeForNormal(vec3_t normal) { if (normal[0] == 1.0) return PLANE_X; if (normal[1] == 1.0) return PLANE_Y; if (normal[2] == 1.0) return PLANE_Z; return PLANE_NON_AXIAL; } /* ================ MatrixMultiply ================ */ void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]) { out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1]; out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2]; out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0]; out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1]; out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2]; out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0]; out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1]; out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; } void AngleVectors(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) { float angle; static float sr, sp, sy, cr, cp, cy; /* static to help MS compiler fp bugs */ angle = angles[YAW] * (M_PI * 2 / 360); sy = sin(angle); cy = cos(angle); angle = angles[PITCH] * (M_PI * 2 / 360); sp = sin(angle); cp = cos(angle); angle = angles[ROLL] * (M_PI * 2 / 360); sr = sin(angle); cr = cos(angle); if (forward) { forward[0] = cp*cy; forward[1] = cp*sy; forward[2] = -sp; } if (right) { right[0] = (-1 * sr*sp*cy + -1 * cr*-sy); right[1] = (-1 * sr*sp*sy + -1 * cr*cy); right[2] = -1 * sr*cp; } if (up) { up[0] = (cr*sp*cy + -sr*-sy); up[1] = (cr*sp*sy + -sr*cy); up[2] = cr*cp; } } /* ** assumes "src" is normalized */ void PerpendicularVector(vec3_t dst, const vec3_t src) { int32_t pos; int32_t i; float minelem = 1.0F; vec3_t tempvec; /* ** find the smallest magnitude axially aligned vector ** bias towards using z instead of x or y */ /* for ( pos = 0, i = 0; i < 3; i++ ) */ for (pos = 0, i = 2; i >= 0; i--) { if (fabs(src[i]) < minelem) { pos = i; minelem = fabs(src[i]); } } tempvec[0] = tempvec[1] = tempvec[2] = 0.0F; tempvec[pos] = 1.0F; /* ** project the point onto the plane defined by src */ ProjectPointOnPlane(dst, tempvec, src); /* ** normalize the result */ VectorNormalize(dst); } /* ** flrandom Returns a float min <= x < max (exclusive; will get max - 0.00001; but never max */ float flrandom(float min, float max) { return (((rand() & 0x7FFF) * (max - min)) / 32768.0F) + min; } /* ** irandom Returns an integer min <= x <= max (ie inclusive) */ int32_t irandom(int32_t min, int32_t max) { max++; /* so it can round down */ return (((rand() & 0x7FFF) * (max - min)) >> 15) + min; } /* use for networking - normalizes a vector, then multiplies it by 65535.0, then calls snap vector on it guarantee's a short per vector instead of 4 bytes. */ void VectorShort(vec3_t vect) { VectorNormalize(vect); vect[0] *= 8191.0; vect[1] *= 8191.0; vect[2] *= 8191.0; SnapVector(vect); } void UnVectorShort(vec3_t vect) { vect[0] /= 8191.0; vect[1] /= 8191.0; vect[2] /= 8191.0; } float Q_powf(float x, int32_t y) { float r = x; for (y--; y>0; y--) r = r * r; return r; } /* TiM: Vector-Average. Good for calculating origins from bounding boxes */ void VectorAverage(vec3_t mins, vec3_t maxs, vec3_t result) { vec3_t temp; /*int32_t i; for ( i = 0; i < 3; i++ ) { result[i] = ( mins[i] + maxs[i] ) * 0.5; }*/ /* TiM: I 'unno... this way looks l33ter lol */ VectorAdd(mins, maxs, temp); VectorScale(temp, 0.5, result); } /* Rounds the argument to the next integer. Used by SnapVector. */ void init_tonextint(qboolean verbose) { float decimal = 0.9; nonansicast = (int32_t)decimal; if (verbose) { if (nonansicast) Com_Printf("Float to int32_t casting behaviour: round to next int\n"); else Com_Printf("Float to int32_t casting behaviour: ISO compliant\n"); } } float tonextint(float x) { int32_t casted; float rest; if (nonansicast) return (int32_t)x; casted = (int32_t)x; rest = x - (float)casted; if (rest >= 0.5f) return casted + 1; else if (rest <= -0.5f) return casted - 1; else return casted; } /************************************** atoul TiM - the stdlib function 'strtoul' isn't supported by the Q3 C library. I was thinking about converting it, but realised since I was only using a small part of it's functionality anyway, it'd be quicker to write my own based off the present code in Q3. Based off of the atoi code **************************************/ unsigned long atoul(const char *string) { unsigned long value; int32_t c; /* skip whitespace */ while (*string <= ' ') { if (!*string) { return 0; } string++; } /* read digits */ value = 0; do { c = *string++; if (c < '0' || c > '9') { break; } c -= '0'; value = value * 10 + c; } while (1); /* not handling 10e10 notation... */ return value; }