diff --git a/Source/Contents/Models/ModelActorBounds.cpp b/Source/Contents/Models/ModelActorBounds.cpp index 47772e99..6595bc48 100644 --- a/Source/Contents/Models/ModelActorBounds.cpp +++ b/Source/Contents/Models/ModelActorBounds.cpp @@ -17,10 +17,45 @@ namespace { // INLINED float InverseLength(float squared) { - const float root = SquareRoot(squared); - return static_cast(1.0 / static_cast(root)); + return 1.0f / SquareRoot(squared); } + // INLINED + __forceinline void TransformCorner(float* corner, float x, float y, float z, const float* matrix) { + corner[0] = ((x * matrix[0] + y * matrix[3]) + z * matrix[6]) + matrix[9]; + corner[1] = ((x * matrix[1] + y * matrix[4]) + z * matrix[7]) + matrix[10]; + corner[2] = ((x * matrix[2] + y * matrix[5]) + z * matrix[8]) + matrix[11]; + } + + // INLINED + __forceinline void SetAxis(float* direction, const float* row) { + direction[0] = row[0]; + direction[1] = row[1]; + direction[2] = row[2]; + const float inverse = InverseLength((direction[0] * direction[0] + direction[1] * direction[1]) + direction[2] * direction[2]); + direction[0] = inverse * direction[0]; + direction[1] = inverse * direction[1]; + direction[2] = inverse * direction[2]; + } + + struct BoundsCorner { + float values[3]; + + // INLINED + BoundsCorner() { + values[0] = 0.0f; + values[1] = 0.0f; + values[2] = 0.0f; + } + + // INLINED + __forceinline void Set(float x, float y, float z) { + values[0] = x; + values[1] = y; + values[2] = z; + } + }; + // INLINED float Coordinate(const float* point, const float* matrix, unsigned axis) { return ((point[0] * matrix[axis] + point[1] * matrix[axis + 3]) + point[2] * matrix[axis + 6]) + matrix[axis + 9]; @@ -31,24 +66,37 @@ namespace { __forceinline void C3dActor::FinishBounds(const float* bounds, bool modern) { for (unsigned axis = 0; axis < 3; ++axis) { this->minimum[axis] = 100000; + } + + for (unsigned axis = 0; axis < 3; ++axis) { this->maximum[axis] = -100000; } + BoundsCorner points[8]; + points[0].Set(bounds[0], bounds[1], bounds[2]); + points[1].Set(bounds[3], bounds[1], bounds[2]); + points[2].Set(bounds[0], bounds[4], bounds[2]); + points[3].Set(bounds[3], bounds[4], bounds[2]); + points[4].Set(bounds[0], bounds[1], bounds[5]); + points[5].Set(bounds[3], bounds[1], bounds[5]); + points[6].Set(bounds[0], bounds[4], bounds[5]); + points[7].Set(bounds[3], bounds[4], bounds[5]); + for (unsigned corner = 0; corner < 8; ++corner) { - const float point[3] = { - bounds[(corner & 1u) ? 3 : 0], bounds[(corner == 2 || corner == 3 || corner == 6 || corner == 7) ? 4 : 1], bounds[corner >= 4 ? 5 : 2] - }; + float* stored = this->corners[corner]; + stored[0] = Coordinate(points[corner].values, this->transform.values, 0); + stored[1] = Coordinate(points[corner].values, this->transform.values, 1); + stored[2] = Coordinate(points[corner].values, this->transform.values, 2); for (unsigned axis = 0; axis < 3; ++axis) { - const float value = Coordinate(point, this->transform.values, axis); - this->corners[corner][axis] = value; - - if (this->minimum[axis] > value) { - this->minimum[axis] = value; + if (this->minimum[axis] > stored[axis]) { + this->minimum[axis] = stored[axis]; } + } - if (value > this->maximum[axis]) { - this->maximum[axis] = value; + for (unsigned axis = 0; axis < 3; ++axis) { + if (stored[axis] > this->maximum[axis]) { + this->maximum[axis] = stored[axis]; } } } @@ -57,6 +105,9 @@ __forceinline void C3dActor::FinishBounds(const float* bounds, bool modern) { const float low = Coordinate(bounds, this->transform.values, axis); const float high = Coordinate(bounds + 3, this->transform.values, axis); this->oriented.center[axis] = (modern || axis == 2 ? high + low : low + high) * 0.5f; + } + + for (unsigned axis = 0; axis < 3; ++axis) { this->oriented.halfSize[axis] = Absolute((bounds[axis + 3] - bounds[axis]) * this->scale[axis]) * 0.5f; } @@ -66,16 +117,9 @@ __forceinline void C3dActor::FinishBounds(const float* bounds, bool modern) { axes.AppendXRotation(Radians(this->rotation[0])); axes.AppendZRotation(Radians(this->rotation[2])); - for (unsigned axis = 0; axis < 3; ++axis) { - float* direction = this->oriented.axes[axis]; - direction[0] = axes.values[axis * 3]; - direction[1] = axes.values[axis * 3 + 1]; - direction[2] = axes.values[axis * 3 + 2]; - const float inverse = InverseLength((direction[0] * direction[0] + direction[1] * direction[1]) + direction[2] * direction[2]); - direction[0] = inverse * direction[0]; - direction[1] = inverse * direction[1]; - direction[2] = inverse * direction[2]; - } + SetAxis(this->oriented.axes[0], axes.values); + SetAxis(this->oriented.axes[1], axes.values + 3); + SetAxis(this->oriented.axes[2], axes.values + 6); for (ModelVolume* volume : this->volumes) { volume->transform.MakeXRotation(Radians(volume->rotation[0])); @@ -86,16 +130,15 @@ __forceinline void C3dActor::FinishBounds(const float* bounds, bool modern) { matrix combined; combined.Compose(volume->transform, this->transform); - for (unsigned corner = 0; corner < 8; ++corner) { - const float point[3] = { - (corner == 1 || corner == 2 || corner == 5 || corner == 6) ? volume->size[0] : -volume->size[0], - (corner == 2 || corner == 3 || corner == 6 || corner == 7) ? volume->size[1] : -volume->size[1], corner >= 4 ? volume->size[2] : -volume->size[2] - }; - - for (unsigned axis = 0; axis < 3; ++axis) { - volume->corners[corner][axis] = Coordinate(point, combined.values, axis); - } - } + const float* size = volume->size; + TransformCorner(volume->corners[0], -size[0], -size[1], -size[2], combined.values); + TransformCorner(volume->corners[1], size[0], -size[1], -size[2], combined.values); + TransformCorner(volume->corners[2], size[0], size[1], -size[2], combined.values); + TransformCorner(volume->corners[3], -size[0], size[1], -size[2], combined.values); + TransformCorner(volume->corners[4], -size[0], -size[1], size[2], combined.values); + TransformCorner(volume->corners[5], size[0], -size[1], size[2], combined.values); + TransformCorner(volume->corners[6], size[0], size[1], size[2], combined.values); + TransformCorner(volume->corners[7], -size[0], size[1], size[2], combined.values); } this->dirty = 1;