diff --git a/gltf.wgsl b/gltf.wgsl index 1246b3b..5bbc840 100644 --- a/gltf.wgsl +++ b/gltf.wgsl @@ -79,7 +79,7 @@ fn lighting(position: vec3f, normal: vec3f) -> vec3f { let d = 0.9; let eyePosition = vec3f(d, d / 2, d); - let lightPosition = vec3f(1, 1, 1); + let lightPosition = vec3f(100, 100, 100); let lightVector = normalize(lightPosition - position); let ndotl = max(dot(lightVector, normal), 0.0); let intensity = (ndotl + 0.3) / 1.3; @@ -95,5 +95,5 @@ fn fragmentMain(input: FragmentInput) -> @location(0) vec4f let intensity = lighting(input.positionWorld, normalize(input.normal)); let color = textureSample(colorTexture, linearSampler, input.texture); - return vec4(color.xyz, 1.0); + return vec4(color.xyz * intensity, 1.0); } diff --git a/index.js b/index.js index 4629252..b8597c4 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ import { getPath } from "./common.js"; import { loadGltf } from "./index2.js"; +import { loadLight } from "./light.js"; if (!navigator.gpu) { throw new Error("WebGPU not supported on this browser."); @@ -441,18 +442,150 @@ function render() } //requestAnimationFrame(render); -const gltfRenderer = await loadGltf(device, canvasFormat, memory2, module); +const matrixSize = 4 * 4 * 4; +const float4Size = 4 * 4; +const float3Size = 4 * 3; +const viewUniformBufferSize = (matrixSize * 2) + (float4Size * 1); + +const viewUniformBuffer = device.createBuffer({ + label: "view uniform buffer", + size: viewUniformBufferSize, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, +}); + +const cameraStateSize = (float3Size * 3) + (4 * 3) + (float3Size * 1); + +const viewStateAddress = module.instance.exports.mem_alloc(viewUniformBufferSize); +const cameraStateAddress = module.instance.exports.mem_alloc(cameraStateSize); + +module.instance.exports.camera_init(cameraStateAddress); + +const gltfRenderer = await loadGltf(device, canvasFormat, viewUniformBuffer, memory2, module); +const lightRenderer = await loadLight(device, canvasFormat, viewUniformBuffer); + + +const KEY = { + A: 65, + B: 66, + C: 67, + D: 68, + E: 69, + F: 70, + G: 71, + H: 72, + I: 73, + J: 74, + K: 75, + L: 76, + M: 77, + N: 78, + O: 79, + P: 80, + Q: 81, + R: 82, + S: 83, + T: 84, + U: 85, + V: 86, + W: 87, + X: 88, + Y: 89, + Z: 90, + + Left: 37, + Up: 38, + Right: 39, + Down: 40, +}; + +const keyCodes = new Set(Object.values(KEY)); +const keyState = {}; +for (const code of Object.values(KEY)) { + keyState[code] = false; +} + +function handleKeydown(e) +{ + //console.log(e.keyCode); + if (keyCodes.has(e.keyCode)) { + keyState[e.keyCode] = true; + } +} + +function handleKeyup(e) +{ + if (keyCodes.has(e.keyCode)) { + keyState[e.keyCode] = false; + } +} + +window.addEventListener('keydown', handleKeydown, false); +window.addEventListener('keyup', handleKeyup, false); + +function updateView() +{ + const lu = keyState[KEY.W] === true; + const ll = keyState[KEY.A] === true; + const ld = keyState[KEY.S] === true; + const lr = keyState[KEY.D] === true; + + const lal = keyState[KEY.Q] === true; + const lar = keyState[KEY.E] === true; + + const ru = keyState[KEY.Up] === true; + const rl = keyState[KEY.Left] === true; + const rd = keyState[KEY.Down] === true; + const rr = keyState[KEY.Right] === true; + + module.instance.exports.camera_move(cameraStateAddress, + lu, ll, ld, lr, + lal, lar, + ru, rl, rd, rr); + + const aspect = canvas.width / canvas.height; + + module.instance.exports.camera_view_projection(cameraStateAddress, + viewStateAddress, + aspect); + + device.queue.writeBuffer(viewUniformBuffer, 0, + memory2.buffer, viewStateAddress, + viewUniformBufferSize); +} function render2() { recreateDepth(); const colorView = context.getCurrentTexture().createView(); - const aspect = canvas.width / canvas.height; - rotate.instance.exports.rotate(tick * 0.01, aspect, 0); - device.queue.writeBuffer(gltfRenderer.uniformBuffer, 0, uniformArray, 0, gltfRenderer.uniformBufferSize / 4); + updateView(); + + { + const encoder = device.createCommandEncoder(); + const renderPass = encoder.beginRenderPass({ + colorAttachments: [{ + view: colorView, + loadOp: "clear", + clearValue: { r: 0.2, g: 0.2, b: 0.4, a: 1 }, + storeOp: "store", + }], + depthStencilAttachment: { + view: depthTexture.createView(), + depthClearValue: 1.0, + depthLoadOp: 'clear', + depthStoreOp: 'store', + }, + }); + + gltfRenderer.render(renderPass); + lightRenderer.render(renderPass); + + renderPass.end(); + + const commandBuffer = encoder.finish(); + device.queue.submit([commandBuffer]); + } - gltfRenderer.render(device, colorView, depthTexture); requestAnimationFrame(render2); } requestAnimationFrame(render2); diff --git a/index2.js b/index2.js index d98818d..7da1713 100644 --- a/index2.js +++ b/index2.js @@ -1,7 +1,6 @@ import { getPath } from "./common.js"; import { parseGltfChunks, vertexBufferLayouts, primitiveAccessors, splitGltf } from "./gltf.js"; - function loadGltfNode(module, handle, gltf, nodeIndex) { const node = gltf.json.nodes[nodeIndex]; @@ -37,7 +36,7 @@ function printMatrix(m, o) } class GltfRenderer { - constructor(device, canvasFormat, shaderModule, gltf, texture) + constructor(device, canvasFormat, viewUniformBuffer, shaderModule, gltf, texture) { this.gltf = gltf; @@ -153,13 +152,6 @@ class GltfRenderer { ////////////////////////////////////////////////////////////////////// const matrixSize = 4 * 4 * 4; - this.uniformBufferSize = matrixSize * 2; - this.uniformBuffer = device.createBuffer({ - label: "gltf uniform 0", - size: this.uniformBufferSize, - usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, - }); - this.nodeBufferSize = matrixSize * this.gltf.json.nodes.length; this.nodeBuffer = device.createBuffer({ label: "gltf node buffer", @@ -173,7 +165,7 @@ class GltfRenderer { layout: bindGroupLayouts[0], entries: [{ binding: 0, - resource: { buffer: this.uniformBuffer }, + resource: { buffer: viewUniformBuffer }, }, { binding: 1, resource: { buffer: this.nodeBuffer }, @@ -235,33 +227,12 @@ class GltfRenderer { return lastKey; } - render(device, colorView, depthTexture) + render(renderPass) { - const encoder = device.createCommandEncoder(); - const renderPass = encoder.beginRenderPass({ - colorAttachments: [{ - view: colorView, - loadOp: "clear", - clearValue: { r: 0.2, g: 0.2, b: 0.4, a: 1 }, - storeOp: "store", - }], - depthStencilAttachment: { - view: depthTexture.createView(), - depthClearValue: 1.0, - depthLoadOp: 'clear', - depthStoreOp: 'store', - }, - }); - var lastKey = undefined; for (let nodeIndex of this.gltf.json.scenes[0].nodes) { lastKey = this.renderNode(renderPass, lastKey, nodeIndex); } - - renderPass.end(); - - const commandBuffer = encoder.finish(); - device.queue.submit([commandBuffer]); } } @@ -333,8 +304,14 @@ async function loadTextures(device, memory, module, gltf) return textures; } -async function loadGltf(device, canvasFormat, memory, module) +async function loadGltf(device, canvasFormat, viewUniformBuffer, memory, module) { + const code = await getPath("gltf.wgsl"); + const shaderModule = device.createShaderModule({ + label: "gltf module", + code: await code, + }); + const gltf = await splitGltf("gltf/lamp.gltf", "gltf/lamp.bin"); const nodesHandle = loadGltfNodes(module, gltf); @@ -348,13 +325,7 @@ async function loadGltf(device, canvasFormat, memory, module) const textures = await loadTextures(device, memory, module, gltf); - const code = await getPath("gltf.wgsl"); - const shaderModule = device.createShaderModule({ - label: "gltf module", - code: await code, - }); - - const renderer = new GltfRenderer(device, canvasFormat, shaderModule, gltf, textures[0]); + const renderer = new GltfRenderer(device, canvasFormat, viewUniformBuffer, shaderModule, gltf, textures[2]); console.log(renderer.nodeBuffer); device.queue.writeBuffer(renderer.nodeBuffer, 0, memory.buffer, nodesHandle, (4 * 4 * 4) * gltf.json.nodes.length); diff --git a/light.js b/light.js new file mode 100644 index 0000000..830661b --- /dev/null +++ b/light.js @@ -0,0 +1,160 @@ +import { getPath } from "./common.js"; + +function parseHeader(buffer) +{ + const array = new Uint32Array(buffer); + /* + console.log("index count", icosphereU32[0]); + console.log("index buffer offset", icosphereU32[1]); + console.log("index buffer size", icosphereU32[2]); + console.log("vertex buffer offset", icosphereU32[3]); + console.log("vertex buffer size", icosphereU32[4]); + */ + + return { + indexCount: array[0], + indexOffset: array[1], + indexSize: array[2], + vertexOffset: array[3], + vertexSize: array[4], + }; +} + +class LightRenderer { + constructor(device, canvasFormat, viewUniformBuffer, + shaderModule, binBuffer, label) + { + ////////////////////////////////////////////////////////////////////// + // buffer + ////////////////////////////////////////////////////////////////////// + + const header = parseHeader(binBuffer); + this.header = header; + + this.buffer = device.createBuffer({ + label: `${label} renderer buffer`, + size: header.indexSize + header.vertexSize, + usage: GPUBufferUsage.INDEX | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, + }); + this.indexOffset = 0; + this.vertexOffset = header.indexSize; + + device.queue.writeBuffer(this.buffer, this.indexOffset, + binBuffer, header.indexOffset, header.indexSize); + device.queue.writeBuffer(this.buffer, this.vertexOffset, + binBuffer, header.vertexOffset, header.vertexSize); + + ////////////////////////////////////////////////////////////////////// + // pipeline + ////////////////////////////////////////////////////////////////////// + + const bindGroupLayouts = [ + device.createBindGroupLayout({ + label: `${label} view matrix bind group layout`, + entries: [{ + binding: 0, + visibility: GPUShaderStage.VERTEX, + buffer: { type: "uniform" } + },/* { + binding: 1, + visibility: GPUShaderStage.VERTEX, + buffer: { type: "read-only-storage" } + }*/] + }), + ]; + + const pipelineLayout = device.createPipelineLayout({ + label: `${label} pipeline layout`, + bindGroupLayouts: bindGroupLayouts, + }); + + const vertexBufferLayouts = [{ + arrayStride: 36, + attributes: [{ + format: "float32x3", + offset: 0, + shaderLocation: 0, + }, { + format: "float32x2", + offset: 12, + shaderLocation: 1, + }, { + format: "float16x4", + offset: 20, + shaderLocation: 2, + }, { + format: "float16x4", + offset: 28, + shaderLocation: 3, + }], + stepMode: "vertex", + }]; + + this.renderPipeline = device.createRenderPipeline({ + label: `${label} pipeline`, + layout: pipelineLayout, + vertex: { + module: shaderModule, + entryPoint: "vertexMain", + buffers: vertexBufferLayouts, + }, + fragment: { + module: shaderModule, + entryPoint: "fragmentMain", + targets: [{ + format: canvasFormat, + }] + }, + primitive: { + topology: "triangle-list", + }, + depthStencil: { + depthWriteEnabled: true, + depthCompare: "less", + format: "depth24plus", + }, + }); + + ////////////////////////////////////////////////////////////////////// + // bind group + ////////////////////////////////////////////////////////////////////// + + this.bindGroups = [ + device.createBindGroup({ + label: `${label} bind group`, + layout: bindGroupLayouts[0], + entries: [{ + binding: 0, + resource: { buffer: viewUniformBuffer }, + }], + }), + ]; + } + + render(renderPass) + { + renderPass.setPipeline(this.renderPipeline); + renderPass.setVertexBuffer(0, this.buffer, this.vertexOffset, this.header.vertexSize); + renderPass.setIndexBuffer(this.buffer, "uint16", this.indexOffset, this.header.indexSize); + renderPass.setBindGroup(0, this.bindGroups[0]); + renderPass.drawIndexed(this.header.indexCount); + } +} + +async function loadLight(device, canvasFormat, viewUniformBuffer) +{ + const lightWgsl = getPath("light.wgsl"); + const shaderModule = device.createShaderModule({ + label: "light shader", + code: await lightWgsl, + }); + + const response = await fetch("obj/icosphere.bin"); + const binBuffer = await response.arrayBuffer(); + + const renderer = new LightRenderer(device, canvasFormat, viewUniformBuffer, + shaderModule, binBuffer, "light"); + return renderer; +} + +export { loadLight }; diff --git a/light.wgsl b/light.wgsl new file mode 100644 index 0000000..0167707 --- /dev/null +++ b/light.wgsl @@ -0,0 +1,35 @@ +struct Configuration { + matrix: mat4x4f, + matrixWorld: mat4x4f, +}; + +@group(0) @binding(0) var config: Configuration; + +struct VertexInput { + @location(0) position: vec3f, + @location(1) texture: vec2f, + @location(2) normal: vec4f, + @location(3) tangent: vec4f, +}; + +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) texture: vec2f, +}; + +@vertex +fn vertexMain(input: VertexInput) -> VertexOutput +{ + let position = vec4f(input.position, 1); + + var output: VertexOutput; + output.position = config.matrix * position; + output.texture = input.texture; + return output; +} + +@fragment +fn fragmentMain(input: VertexOutput) -> @location(0) vec4f +{ + return vec4(1, 0, 0, 1.0); +} diff --git a/obj/icosphere.bin b/obj/icosphere.bin new file mode 100644 index 0000000..1a5fa99 Binary files /dev/null and b/obj/icosphere.bin differ diff --git a/obj/icosphere.obj b/obj/icosphere.obj new file mode 100644 index 0000000..c3328a6 --- /dev/null +++ b/obj/icosphere.obj @@ -0,0 +1,269 @@ +# Blender 5.2.0 LTS +# www.blender.org +o Icosphere +v 0.000000 -1.000000 0.000000 +v 0.723607 -0.447220 0.525725 +v -0.276388 -0.447220 0.850649 +v -0.894426 -0.447216 0.000000 +v -0.276388 -0.447220 -0.850649 +v 0.723607 -0.447220 -0.525725 +v 0.276388 0.447220 0.850649 +v -0.723607 0.447220 0.525725 +v -0.723607 0.447220 -0.525725 +v 0.276388 0.447220 -0.850649 +v 0.894426 0.447216 0.000000 +v 0.000000 1.000000 0.000000 +v -0.162456 -0.850654 0.499995 +v 0.425323 -0.850654 0.309011 +v 0.262869 -0.525738 0.809012 +v 0.850648 -0.525736 0.000000 +v 0.425323 -0.850654 -0.309011 +v -0.525730 -0.850652 0.000000 +v -0.688189 -0.525736 0.499997 +v -0.162456 -0.850654 -0.499995 +v -0.688189 -0.525736 -0.499997 +v 0.262869 -0.525738 -0.809012 +v 0.951058 0.000000 0.309013 +v 0.951058 0.000000 -0.309013 +v 0.000000 0.000000 1.000000 +v 0.587786 0.000000 0.809017 +v -0.951058 0.000000 0.309013 +v -0.587786 0.000000 0.809017 +v -0.587786 0.000000 -0.809017 +v -0.951058 0.000000 -0.309013 +v 0.587786 0.000000 -0.809017 +v 0.000000 0.000000 -1.000000 +v 0.688189 0.525736 0.499997 +v -0.262869 0.525738 0.809012 +v -0.850648 0.525736 0.000000 +v -0.262869 0.525738 -0.809012 +v 0.688189 0.525736 -0.499997 +v 0.162456 0.850654 0.499995 +v 0.525730 0.850652 0.000000 +v -0.425323 0.850654 0.309011 +v -0.425323 0.850654 -0.309011 +v 0.162456 0.850654 -0.499995 +vn 0.1024 -0.9435 0.3151 +vn 0.7002 -0.6617 0.2680 +vn -0.2680 -0.9435 0.1947 +vn -0.2680 -0.9435 -0.1947 +vn 0.1024 -0.9435 -0.3151 +vn 0.9050 -0.3304 0.2680 +vn 0.0247 -0.3304 0.9435 +vn -0.8897 -0.3304 0.3151 +vn -0.5746 -0.3304 -0.7488 +vn 0.5346 -0.3304 -0.7779 +vn 0.8026 -0.1256 0.5831 +vn -0.3066 -0.1256 0.9435 +vn -0.9921 -0.1256 -0.0000 +vn -0.3066 -0.1256 -0.9435 +vn 0.8026 -0.1256 -0.5831 +vn 0.4089 0.6617 0.6284 +vn -0.4713 0.6617 0.5831 +vn -0.7002 0.6617 -0.2680 +vn 0.0385 0.6617 -0.7488 +vn 0.7240 0.6617 -0.1947 +vn 0.2680 0.9435 -0.1947 +vn 0.4911 0.7947 -0.3568 +vn 0.4089 0.6617 -0.6284 +vn -0.1024 0.9435 -0.3151 +vn -0.1876 0.7947 -0.5773 +vn -0.4713 0.6617 -0.5831 +vn -0.3313 0.9435 -0.0000 +vn -0.6071 0.7947 -0.0000 +vn -0.7002 0.6617 0.2680 +vn -0.1024 0.9435 0.3151 +vn -0.1876 0.7947 0.5773 +vn 0.0385 0.6617 0.7488 +vn 0.2680 0.9435 0.1947 +vn 0.4911 0.7947 0.3568 +vn 0.7240 0.6617 0.1947 +vn 0.8897 0.3304 -0.3151 +vn 0.7947 0.1876 -0.5773 +vn 0.5746 0.3304 -0.7488 +vn -0.0247 0.3304 -0.9435 +vn -0.3035 0.1876 -0.9342 +vn -0.5346 0.3304 -0.7779 +vn -0.9050 0.3304 -0.2680 +vn -0.9822 0.1876 -0.0000 +vn -0.9050 0.3304 0.2680 +vn -0.5346 0.3304 0.7779 +vn -0.3035 0.1876 0.9342 +vn -0.0247 0.3304 0.9435 +vn 0.5746 0.3304 0.7488 +vn 0.7947 0.1876 0.5773 +vn 0.8897 0.3304 0.3151 +vn 0.3066 0.1256 -0.9435 +vn 0.3035 -0.1876 -0.9342 +vn 0.0247 -0.3304 -0.9435 +vn -0.8026 0.1256 -0.5831 +vn -0.7947 -0.1876 -0.5773 +vn -0.8897 -0.3304 -0.3151 +vn -0.8026 0.1256 0.5831 +vn -0.7947 -0.1876 0.5773 +vn -0.5746 -0.3304 0.7488 +vn 0.3066 0.1256 0.9435 +vn 0.3035 -0.1876 0.9342 +vn 0.5346 -0.3304 0.7779 +vn 0.9921 0.1256 -0.0000 +vn 0.9822 -0.1876 -0.0000 +vn 0.9050 -0.3304 -0.2680 +vn 0.4713 -0.6617 -0.5831 +vn 0.1876 -0.7947 -0.5773 +vn -0.0385 -0.6617 -0.7488 +vn -0.4089 -0.6617 -0.6284 +vn -0.4911 -0.7947 -0.3568 +vn -0.7240 -0.6617 -0.1947 +vn -0.7240 -0.6617 0.1947 +vn -0.4911 -0.7947 0.3568 +vn -0.4089 -0.6617 0.6284 +vn 0.7002 -0.6617 -0.2680 +vn 0.6071 -0.7947 -0.0000 +vn 0.3313 -0.9435 -0.0000 +vn -0.0385 -0.6617 0.7488 +vn 0.1876 -0.7947 0.5773 +vn 0.4713 -0.6617 0.5831 +vt 0.181819 0.000000 +vt 0.227273 0.078731 +vt 0.136365 0.078731 +vt 0.272728 0.157461 +vt 0.318182 0.078731 +vt 0.363637 0.157461 +vt 0.909091 0.000000 +vt 0.954545 0.078731 +vt 0.863636 0.078731 +vt 0.727273 0.000000 +vt 0.772727 0.078731 +vt 0.681818 0.078731 +vt 0.545455 0.000000 +vt 0.590909 0.078731 +vt 0.500000 0.078731 +vt 0.318182 0.236191 +vt 0.090910 0.157461 +vt 0.181819 0.157461 +vt 0.136365 0.236191 +vt 0.818182 0.157461 +vt 0.909091 0.157461 +vt 0.863636 0.236191 +vt 0.636364 0.157461 +vt 0.727273 0.157461 +vt 0.681818 0.236191 +vt 0.454546 0.157461 +vt 0.545455 0.157461 +vt 0.500000 0.236191 +vt 0.227273 0.236191 +vt 0.045455 0.236191 +vt 0.772727 0.236191 +vt 0.590909 0.236191 +vt 0.409092 0.236191 +vt 0.181819 0.314921 +vt 0.272728 0.314921 +vt 0.227273 0.393651 +vt 0.000000 0.314921 +vt 0.090910 0.314921 +vt 0.045455 0.393651 +vt 0.727273 0.314921 +vt 0.818182 0.314921 +vt 0.772727 0.393651 +vt 0.545455 0.314921 +vt 0.636364 0.314921 +vt 0.590909 0.393651 +vt 0.363637 0.314921 +vt 0.454546 0.314921 +vt 0.409092 0.393651 +vt 0.500000 0.393651 +vt 0.454546 0.472382 +vt 0.681818 0.393651 +vt 0.636364 0.472382 +vt 0.863636 0.393651 +vt 0.818182 0.472382 +vt 0.909091 0.314921 +vt 0.136365 0.393651 +vt 0.090910 0.472382 +vt 0.318182 0.393651 +vt 0.272728 0.472382 +vt 0.954545 0.236191 +vt 1.000000 0.157461 +vt 0.409092 0.078731 +vt 0.363637 0.000000 +s 0 +f 1/1/1 14/2/1 13/3/1 +f 2/4/2 14/5/2 16/6/2 +f 1/7/3 13/8/3 18/9/3 +f 1/10/4 18/11/4 20/12/4 +f 1/13/5 20/14/5 17/15/5 +f 2/4/6 16/6/6 23/16/6 +f 3/17/7 15/18/7 25/19/7 +f 4/20/8 19/21/8 27/22/8 +f 5/23/9 21/24/9 29/25/9 +f 6/26/10 22/27/10 31/28/10 +f 2/4/11 23/16/11 26/29/11 +f 3/17/12 25/19/12 28/30/12 +f 4/20/13 27/22/13 30/31/13 +f 5/23/14 29/25/14 32/32/14 +f 6/26/15 31/28/15 24/33/15 +f 7/34/16 33/35/16 38/36/16 +f 8/37/17 34/38/17 40/39/17 +f 9/40/18 35/41/18 41/42/18 +f 10/43/19 36/44/19 42/45/19 +f 11/46/20 37/47/20 39/48/20 +f 39/48/21 42/49/21 12/50/21 +f 39/48/22 37/47/22 42/49/22 +f 37/47/23 10/43/23 42/49/23 +f 42/45/24 41/51/24 12/52/24 +f 42/45/25 36/44/25 41/51/25 +f 36/44/26 9/40/26 41/51/26 +f 41/42/27 40/53/27 12/54/27 +f 41/42/28 35/41/28 40/53/28 +f 35/41/29 8/55/29 40/53/29 +f 40/39/30 38/56/30 12/57/30 +f 40/39/31 34/38/31 38/56/31 +f 34/38/32 7/34/32 38/56/32 +f 38/36/33 39/58/33 12/59/33 +f 38/36/34 33/35/34 39/58/34 +f 33/35/35 11/46/35 39/58/35 +f 24/33/36 37/47/36 11/46/36 +f 24/33/37 31/28/37 37/47/37 +f 31/28/38 10/43/38 37/47/38 +f 32/32/39 36/44/39 10/43/39 +f 32/32/40 29/25/40 36/44/40 +f 29/25/41 9/40/41 36/44/41 +f 30/31/42 35/41/42 9/40/42 +f 30/31/43 27/22/43 35/41/43 +f 27/22/44 8/55/44 35/41/44 +f 28/30/45 34/38/45 8/37/45 +f 28/30/46 25/19/46 34/38/46 +f 25/19/47 7/34/47 34/38/47 +f 26/29/48 33/35/48 7/34/48 +f 26/29/49 23/16/49 33/35/49 +f 23/16/50 11/46/50 33/35/50 +f 31/28/51 32/32/51 10/43/51 +f 31/28/52 22/27/52 32/32/52 +f 22/27/53 5/23/53 32/32/53 +f 29/25/54 30/31/54 9/40/54 +f 29/25/55 21/24/55 30/31/55 +f 21/24/56 4/20/56 30/31/56 +f 27/22/57 28/60/57 8/55/57 +f 27/22/58 19/21/58 28/60/58 +f 19/21/59 3/61/59 28/60/59 +f 25/19/60 26/29/60 7/34/60 +f 25/19/61 15/18/61 26/29/61 +f 15/18/62 2/4/62 26/29/62 +f 23/16/63 24/33/63 11/46/63 +f 23/16/64 16/6/64 24/33/64 +f 16/6/65 6/26/65 24/33/65 +f 17/15/66 22/27/66 6/26/66 +f 17/15/67 20/14/67 22/27/67 +f 20/14/68 5/23/68 22/27/68 +f 20/12/69 21/24/69 5/23/69 +f 20/12/70 18/11/70 21/24/70 +f 18/11/71 4/20/71 21/24/71 +f 18/9/72 19/21/72 4/20/72 +f 18/9/73 13/8/73 19/21/73 +f 13/8/74 3/61/74 19/21/74 +f 16/6/75 17/62/75 6/26/75 +f 16/6/76 14/5/76 17/62/76 +f 14/5/77 1/63/77 17/62/77 +f 13/3/78 15/18/78 3/17/78 +f 13/3/79 14/2/79 15/18/79 +f 14/2/80 2/4/80 15/18/80 diff --git a/src/Makefile b/src/Makefile index 74f0455..6986c8f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -5,9 +5,9 @@ CFLAGS = \ -g \ -O3 \ -flto \ + -ffast-math \ -nostdlib \ -I$(MINIZ) \ - -I.. \ -I. \ -Werror \ -Wfatal-errors \ @@ -29,6 +29,9 @@ LDFLAGS = \ -Wl,--export=node_init_translation \ -Wl,--export=png_build_crc_table \ -Wl,--export=png_decode \ + -Wl,--export=camera_move \ + -Wl,--export=camera_init \ + -Wl,--export=camera_view_projection \ -Wl,--import-undefined \ -Wl,--print-map \ -Wl,--import-memory \ @@ -45,7 +48,8 @@ PNG_OBJ = \ stdlib.o \ $(MINIZ)/miniz_tinfl.o \ memory.o \ - node.o + node.o \ + camera.o module.wasm: $(PNG_OBJ) clang++ $(CFLAGS) $(LDFLAGS) -o $@ $^ diff --git a/src/camera.cpp b/src/camera.cpp new file mode 100644 index 0000000..89e9a2b --- /dev/null +++ b/src/camera.cpp @@ -0,0 +1,138 @@ +#include "directxmath/DirectXMath.h" + +#include "camera.h" + +struct CameraState { + XMFLOAT3 eye; + XMFLOAT3 look; + XMFLOAT3 up; + float fov; + float pitch; + float yaw; + + XMFLOAT3 light_position; +}; + +struct ViewState { + XMFLOAT4X4 viewProj; + XMFLOAT4X4 lightViewProj; + XMFLOAT4 lightPosition; +}; + +static inline XMMATRIX camera_view(CameraState const * state) +{ + XMMATRIX view = XMMatrixLookToRH(XMLoadFloat3(&state->eye), + XMLoadFloat3(&state->look), + XMLoadFloat3(&state->up)); + return view; +} + +static inline XMMATRIX camera_projection(CameraState const * state, float aspect) +{ + float near_z = 0.01; + float far_z = 1000.0; + + XMMATRIX projection = XMMatrixPerspectiveFovRH(state->fov, + aspect, + near_z, + far_z); + return projection; +}; + +extern "C" void log(float x); + +static inline float min(float a, float b) +{ + return a < b ? a : b; +} + +static inline float max(float a, float b) +{ + return a > b ? a : b; +} + +void camera_move(CameraState * state, + int lu, int ll, int ld, int lr, + int lal, int lar, + int ru, int rl, int rd, int rr) +{ + const float linearSpeed = 0.1; + const float rotationalSpeed = 0.01; + XMFLOAT3 move = {0, 0, 0}; + + if (ll) + move.x -= 1.0; + if (lr) + move.x += 1.0; + if (lu) + move.z -= 1.0; + if (ld) + move.z += 1.0; + if (lal) + move.y += 1.0; + if (lar) + move.y -= 1.0; + //XMStoreFloat3(&move, XMVector3Normalize(XMLoadFloat3(&move))); + + if (rl) + state->yaw += rotationalSpeed; + if (rr) + state->yaw -= rotationalSpeed; + if (ru) + state->pitch += rotationalSpeed; + if (rd) + state->pitch -= rotationalSpeed; + + state->pitch = min(state->pitch, XM_PIDIV4); + state->pitch = max(state->pitch, -XM_PIDIV4); + + float sinyaw; + float cosyaw; + XMScalarSinCos(&sinyaw, &cosyaw, state->yaw); + + // eye + float x = move.x * -cosyaw - move.z * sinyaw; + float y = move.y; + float z = move.x * sinyaw - move.z * cosyaw; + state->eye.x += x * linearSpeed; + state->eye.y += y * linearSpeed; + state->eye.z += z * linearSpeed; + + // look + float sinpitch; + float cospitch; + XMScalarSinCos(&sinpitch, &cospitch, state->pitch); + state->look.x = cospitch * sinyaw; + state->look.y = sinpitch; + state->look.z = cospitch * cosyaw; +} + +void camera_init(CameraState * camera_state) +{ + camera_state->fov = XMConvertToRadians(45 * 1.5); + + camera_state->yaw = XM_PI; + camera_state->pitch = 0.0f; + + camera_state->up = {0, 1, 0}; + camera_state->look = {0, 0, -1}; + camera_state->eye = {0, 0, 5}; + + camera_state->light_position = {1, 1, 1}; +} + +void camera_view_projection(CameraState const * camera_state, + ViewState * view_state, + float aspect) +{ + XMMATRIX view = camera_view(camera_state); + XMMATRIX projection = camera_projection(camera_state, aspect); + + XMMATRIX view_projection = view * projection; + + XMMATRIX light_world = XMMatrixTranslationFromVector(XMLoadFloat3(&camera_state->light_position)); + + XMStoreFloat4x4(&view_state->viewProj, view_projection); + XMStoreFloat4x4(&view_state->lightViewProj, light_world * view_projection); + XMStoreFloat4(&view_state->lightPosition, XMLoadFloat3(&camera_state->light_position)); +} diff --git a/src/camera.h b/src/camera.h new file mode 100644 index 0000000..6906e42 --- /dev/null +++ b/src/camera.h @@ -0,0 +1,13 @@ +struct CameraState; +struct ViewState; + +extern "C" { + void camera_move(CameraState * camera_state, + int lu, int ll, int ld, int lr, + int lal, int lar, + int ru, int rl, int rd, int rr); + void camera_init(CameraState * camera_state); + void camera_view_projection(CameraState const * camera_state, + ViewState * view_state, + float aspect); +}; diff --git a/src/directxmath/DirectXCollision.h b/src/directxmath/DirectXCollision.h new file mode 100644 index 0000000..121ae1a --- /dev/null +++ b/src/directxmath/DirectXCollision.h @@ -0,0 +1,369 @@ +//------------------------------------------------------------------------------------- +// DirectXCollision.h -- C++ Collision Math library +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// +// https://go.microsoft.com/fwlink/?LinkID=615560 +//------------------------------------------------------------------------------------- + +#pragma once + +#include "DirectXMath.h" + +namespace DirectX +{ + + enum ContainmentType + { + DISJOINT = 0, + INTERSECTS = 1, + CONTAINS = 2 + }; + + enum PlaneIntersectionType + { + FRONT = 0, + INTERSECTING = 1, + BACK = 2 + }; + + struct BoundingBox; + struct BoundingOrientedBox; + struct BoundingFrustum; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4324 4820) + // C4324: alignment padding warnings + // C4820: Off by default noise +#endif + + //------------------------------------------------------------------------------------- + // Bounding sphere + //------------------------------------------------------------------------------------- + struct BoundingSphere + { + XMFLOAT3 Center; // Center of the sphere. + float Radius; // Radius of the sphere. + + // Creators + BoundingSphere() noexcept : Center(0, 0, 0), Radius(1.f) {} + + BoundingSphere(const BoundingSphere&) = default; + BoundingSphere& operator=(const BoundingSphere&) = default; + + BoundingSphere(BoundingSphere&&) = default; + BoundingSphere& operator=(BoundingSphere&&) = default; + + constexpr BoundingSphere(_In_ const XMFLOAT3& center, _In_ float radius) noexcept + : Center(center), Radius(radius) {} + + // Methods + void XM_CALLCONV Transform(_Out_ BoundingSphere& Out, _In_ FXMMATRIX M) const noexcept; + void XM_CALLCONV Transform(_Out_ BoundingSphere& Out, _In_ float Scale, _In_ FXMVECTOR Rotation, _In_ FXMVECTOR Translation) const noexcept; + // Transform the sphere + + ContainmentType XM_CALLCONV Contains(_In_ FXMVECTOR Point) const noexcept; + ContainmentType XM_CALLCONV Contains(_In_ FXMVECTOR V0, _In_ FXMVECTOR V1, _In_ FXMVECTOR V2) const noexcept; + ContainmentType Contains(_In_ const BoundingSphere& sh) const noexcept; + ContainmentType Contains(_In_ const BoundingBox& box) const noexcept; + ContainmentType Contains(_In_ const BoundingOrientedBox& box) const noexcept; + ContainmentType Contains(_In_ const BoundingFrustum& fr) const noexcept; + + bool Intersects(_In_ const BoundingSphere& sh) const noexcept; + bool Intersects(_In_ const BoundingBox& box) const noexcept; + bool Intersects(_In_ const BoundingOrientedBox& box) const noexcept; + bool Intersects(_In_ const BoundingFrustum& fr) const noexcept; + + bool XM_CALLCONV Intersects(_In_ FXMVECTOR V0, _In_ FXMVECTOR V1, _In_ FXMVECTOR V2) const noexcept; + // Triangle-sphere test + + PlaneIntersectionType XM_CALLCONV Intersects(_In_ FXMVECTOR Plane) const noexcept; + // Plane-sphere test + + bool XM_CALLCONV Intersects(_In_ FXMVECTOR Origin, _In_ FXMVECTOR Direction, _Out_ float& Dist) const noexcept; + // Ray-sphere test + + ContainmentType XM_CALLCONV ContainedBy(_In_ FXMVECTOR Plane0, _In_ FXMVECTOR Plane1, _In_ FXMVECTOR Plane2, + _In_ GXMVECTOR Plane3, _In_ HXMVECTOR Plane4, _In_ HXMVECTOR Plane5) const noexcept; + // Test sphere against six planes (see BoundingFrustum::GetPlanes) + + // Static methods + static void CreateMerged(_Out_ BoundingSphere& Out, _In_ const BoundingSphere& S1, _In_ const BoundingSphere& S2) noexcept; + + static void CreateFromBoundingBox(_Out_ BoundingSphere& Out, _In_ const BoundingBox& box) noexcept; + static void CreateFromBoundingBox(_Out_ BoundingSphere& Out, _In_ const BoundingOrientedBox& box) noexcept; + + static void CreateFromPoints(_Out_ BoundingSphere& Out, _In_ size_t Count, + _In_reads_bytes_(sizeof(XMFLOAT3) + Stride * (Count - 1)) const XMFLOAT3* pPoints, _In_ size_t Stride) noexcept; + + static void CreateFromFrustum(_Out_ BoundingSphere& Out, _In_ const BoundingFrustum& fr) noexcept; + }; + + //------------------------------------------------------------------------------------- + // Axis-aligned bounding box + //------------------------------------------------------------------------------------- + struct BoundingBox + { + static constexpr size_t CORNER_COUNT = 8; + + XMFLOAT3 Center; // Center of the box. + XMFLOAT3 Extents; // Distance from the center to each side. + + // Creators + BoundingBox() noexcept : Center(0, 0, 0), Extents(1.f, 1.f, 1.f) {} + + BoundingBox(const BoundingBox&) = default; + BoundingBox& operator=(const BoundingBox&) = default; + + BoundingBox(BoundingBox&&) = default; + BoundingBox& operator=(BoundingBox&&) = default; + + constexpr BoundingBox(_In_ const XMFLOAT3& center, _In_ const XMFLOAT3& extents) noexcept + : Center(center), Extents(extents) {} + + // Methods + void XM_CALLCONV Transform(_Out_ BoundingBox& Out, _In_ FXMMATRIX M) const noexcept; + void XM_CALLCONV Transform(_Out_ BoundingBox& Out, _In_ float Scale, _In_ FXMVECTOR Rotation, _In_ FXMVECTOR Translation) const noexcept; + + void GetCorners(_Out_writes_(8) XMFLOAT3* Corners) const noexcept; + // Gets the 8 corners of the box + + ContainmentType XM_CALLCONV Contains(_In_ FXMVECTOR Point) const noexcept; + ContainmentType XM_CALLCONV Contains(_In_ FXMVECTOR V0, _In_ FXMVECTOR V1, _In_ FXMVECTOR V2) const noexcept; + ContainmentType Contains(_In_ const BoundingSphere& sh) const noexcept; + ContainmentType Contains(_In_ const BoundingBox& box) const noexcept; + ContainmentType Contains(_In_ const BoundingOrientedBox& box) const noexcept; + ContainmentType Contains(_In_ const BoundingFrustum& fr) const noexcept; + + bool Intersects(_In_ const BoundingSphere& sh) const noexcept; + bool Intersects(_In_ const BoundingBox& box) const noexcept; + bool Intersects(_In_ const BoundingOrientedBox& box) const noexcept; + bool Intersects(_In_ const BoundingFrustum& fr) const noexcept; + + bool XM_CALLCONV Intersects(_In_ FXMVECTOR V0, _In_ FXMVECTOR V1, _In_ FXMVECTOR V2) const noexcept; + // Triangle-Box test + + PlaneIntersectionType XM_CALLCONV Intersects(_In_ FXMVECTOR Plane) const noexcept; + // Plane-box test + + bool XM_CALLCONV Intersects(_In_ FXMVECTOR Origin, _In_ FXMVECTOR Direction, _Out_ float& Dist) const noexcept; + // Ray-Box test + + ContainmentType XM_CALLCONV ContainedBy(_In_ FXMVECTOR Plane0, _In_ FXMVECTOR Plane1, _In_ FXMVECTOR Plane2, + _In_ GXMVECTOR Plane3, _In_ HXMVECTOR Plane4, _In_ HXMVECTOR Plane5) const noexcept; + // Test box against six planes (see BoundingFrustum::GetPlanes) + + // Static methods + static void CreateMerged(_Out_ BoundingBox& Out, _In_ const BoundingBox& b1, _In_ const BoundingBox& b2) noexcept; + + static void CreateFromSphere(_Out_ BoundingBox& Out, _In_ const BoundingSphere& sh) noexcept; + + static void XM_CALLCONV CreateFromPoints(_Out_ BoundingBox& Out, _In_ FXMVECTOR pt1, _In_ FXMVECTOR pt2) noexcept; + static void CreateFromPoints(_Out_ BoundingBox& Out, _In_ size_t Count, + _In_reads_bytes_(sizeof(XMFLOAT3) + Stride * (Count - 1)) const XMFLOAT3* pPoints, _In_ size_t Stride) noexcept; + }; + + //------------------------------------------------------------------------------------- + // Oriented bounding box + //------------------------------------------------------------------------------------- + struct BoundingOrientedBox + { + static constexpr size_t CORNER_COUNT = 8; + + XMFLOAT3 Center; // Center of the box. + XMFLOAT3 Extents; // Distance from the center to each side. + XMFLOAT4 Orientation; // Unit quaternion representing rotation (box -> world). + + // Creators + BoundingOrientedBox() noexcept : Center(0, 0, 0), Extents(1.f, 1.f, 1.f), Orientation(0, 0, 0, 1.f) {} + + BoundingOrientedBox(const BoundingOrientedBox&) = default; + BoundingOrientedBox& operator=(const BoundingOrientedBox&) = default; + + BoundingOrientedBox(BoundingOrientedBox&&) = default; + BoundingOrientedBox& operator=(BoundingOrientedBox&&) = default; + + constexpr BoundingOrientedBox(_In_ const XMFLOAT3& center, _In_ const XMFLOAT3& extents, _In_ const XMFLOAT4& orientation) noexcept + : Center(center), Extents(extents), Orientation(orientation) {} + + // Methods + void XM_CALLCONV Transform(_Out_ BoundingOrientedBox& Out, _In_ FXMMATRIX M) const noexcept; + void XM_CALLCONV Transform(_Out_ BoundingOrientedBox& Out, _In_ float Scale, _In_ FXMVECTOR Rotation, _In_ FXMVECTOR Translation) const noexcept; + + void GetCorners(_Out_writes_(8) XMFLOAT3* Corners) const noexcept; + // Gets the 8 corners of the box + + ContainmentType XM_CALLCONV Contains(_In_ FXMVECTOR Point) const noexcept; + ContainmentType XM_CALLCONV Contains(_In_ FXMVECTOR V0, _In_ FXMVECTOR V1, _In_ FXMVECTOR V2) const noexcept; + ContainmentType Contains(_In_ const BoundingSphere& sh) const noexcept; + ContainmentType Contains(_In_ const BoundingBox& box) const noexcept; + ContainmentType Contains(_In_ const BoundingOrientedBox& box) const noexcept; + ContainmentType Contains(_In_ const BoundingFrustum& fr) const noexcept; + + bool Intersects(_In_ const BoundingSphere& sh) const noexcept; + bool Intersects(_In_ const BoundingBox& box) const noexcept; + bool Intersects(_In_ const BoundingOrientedBox& box) const noexcept; + bool Intersects(_In_ const BoundingFrustum& fr) const noexcept; + + bool XM_CALLCONV Intersects(_In_ FXMVECTOR V0, _In_ FXMVECTOR V1, _In_ FXMVECTOR V2) const noexcept; + // Triangle-OrientedBox test + + PlaneIntersectionType XM_CALLCONV Intersects(_In_ FXMVECTOR Plane) const noexcept; + // Plane-OrientedBox test + + bool XM_CALLCONV Intersects(_In_ FXMVECTOR Origin, _In_ FXMVECTOR Direction, _Out_ float& Dist) const noexcept; + // Ray-OrientedBox test + + ContainmentType XM_CALLCONV ContainedBy(_In_ FXMVECTOR Plane0, _In_ FXMVECTOR Plane1, _In_ FXMVECTOR Plane2, + _In_ GXMVECTOR Plane3, _In_ HXMVECTOR Plane4, _In_ HXMVECTOR Plane5) const noexcept; + // Test OrientedBox against six planes (see BoundingFrustum::GetPlanes) + + // Static methods + static void CreateFromBoundingBox(_Out_ BoundingOrientedBox& Out, _In_ const BoundingBox& box) noexcept; + + static void CreateFromPoints(_Out_ BoundingOrientedBox& Out, _In_ size_t Count, + _In_reads_bytes_(sizeof(XMFLOAT3) + Stride * (Count - 1)) const XMFLOAT3* pPoints, _In_ size_t Stride) noexcept; + }; + + //------------------------------------------------------------------------------------- + // Bounding frustum + //------------------------------------------------------------------------------------- + struct BoundingFrustum + { + static constexpr size_t CORNER_COUNT = 8; + + XMFLOAT3 Origin; // Origin of the frustum (and projection). + XMFLOAT4 Orientation; // Quaternion representing rotation. + + float RightSlope; // Positive X (X/Z) + float LeftSlope; // Negative X + float TopSlope; // Positive Y (Y/Z) + float BottomSlope; // Negative Y + float Near, Far; // Z of the near plane and far plane. + + // Creators + BoundingFrustum() noexcept : + Origin(0, 0, 0), Orientation(0, 0, 0, 1.f), RightSlope(1.f), LeftSlope(-1.f), + TopSlope(1.f), BottomSlope(-1.f), Near(0), Far(1.f) {} + + BoundingFrustum(const BoundingFrustum&) = default; + BoundingFrustum& operator=(const BoundingFrustum&) = default; + + BoundingFrustum(BoundingFrustum&&) = default; + BoundingFrustum& operator=(BoundingFrustum&&) = default; + + constexpr BoundingFrustum(_In_ const XMFLOAT3& origin, _In_ const XMFLOAT4& orientation, + _In_ float rightSlope, _In_ float leftSlope, _In_ float topSlope, _In_ float bottomSlope, + _In_ float nearPlane, _In_ float farPlane) noexcept + : Origin(origin), Orientation(orientation), + RightSlope(rightSlope), LeftSlope(leftSlope), TopSlope(topSlope), BottomSlope(bottomSlope), + Near(nearPlane), Far(farPlane) {} + BoundingFrustum(_In_ CXMMATRIX Projection, bool rhcoords = false) noexcept; + + // Methods + void XM_CALLCONV Transform(_Out_ BoundingFrustum& Out, _In_ FXMMATRIX M) const noexcept; + void XM_CALLCONV Transform(_Out_ BoundingFrustum& Out, _In_ float Scale, _In_ FXMVECTOR Rotation, _In_ FXMVECTOR Translation) const noexcept; + + void GetCorners(_Out_writes_(8) XMFLOAT3* Corners) const noexcept; + // Gets the 8 corners of the frustum + + ContainmentType XM_CALLCONV Contains(_In_ FXMVECTOR Point) const noexcept; + ContainmentType XM_CALLCONV Contains(_In_ FXMVECTOR V0, _In_ FXMVECTOR V1, _In_ FXMVECTOR V2) const noexcept; + ContainmentType Contains(_In_ const BoundingSphere& sp) const noexcept; + ContainmentType Contains(_In_ const BoundingBox& box) const noexcept; + ContainmentType Contains(_In_ const BoundingOrientedBox& box) const noexcept; + ContainmentType Contains(_In_ const BoundingFrustum& fr) const noexcept; + // Frustum-Frustum test + + bool Intersects(_In_ const BoundingSphere& sh) const noexcept; + bool Intersects(_In_ const BoundingBox& box) const noexcept; + bool Intersects(_In_ const BoundingOrientedBox& box) const noexcept; + bool Intersects(_In_ const BoundingFrustum& fr) const noexcept; + + bool XM_CALLCONV Intersects(_In_ FXMVECTOR V0, _In_ FXMVECTOR V1, _In_ FXMVECTOR V2) const noexcept; + // Triangle-Frustum test + + PlaneIntersectionType XM_CALLCONV Intersects(_In_ FXMVECTOR Plane) const noexcept; + // Plane-Frustum test + + bool XM_CALLCONV Intersects(_In_ FXMVECTOR rayOrigin, _In_ FXMVECTOR Direction, _Out_ float& Dist) const noexcept; + // Ray-Frustum test + + ContainmentType XM_CALLCONV ContainedBy(_In_ FXMVECTOR Plane0, _In_ FXMVECTOR Plane1, _In_ FXMVECTOR Plane2, + _In_ GXMVECTOR Plane3, _In_ HXMVECTOR Plane4, _In_ HXMVECTOR Plane5) const noexcept; + // Test frustum against six planes (see BoundingFrustum::GetPlanes) + + void GetPlanes(_Out_opt_ XMVECTOR* NearPlane, _Out_opt_ XMVECTOR* FarPlane, _Out_opt_ XMVECTOR* RightPlane, + _Out_opt_ XMVECTOR* LeftPlane, _Out_opt_ XMVECTOR* TopPlane, _Out_opt_ XMVECTOR* BottomPlane) const noexcept; + // Create 6 Planes representation of Frustum + + // Static methods + static void XM_CALLCONV CreateFromMatrix(_Out_ BoundingFrustum& Out, _In_ FXMMATRIX Projection, bool rhcoords = false) noexcept; + }; + + //----------------------------------------------------------------------------- + // Triangle intersection testing routines. + //----------------------------------------------------------------------------- + namespace TriangleTests + { + bool XM_CALLCONV Intersects(_In_ FXMVECTOR Origin, _In_ FXMVECTOR Direction, _In_ FXMVECTOR V0, _In_ GXMVECTOR V1, _In_ HXMVECTOR V2, _Out_ float& Dist) noexcept; + // Ray-Triangle + + bool XM_CALLCONV Intersects(_In_ FXMVECTOR A0, _In_ FXMVECTOR A1, _In_ FXMVECTOR A2, _In_ GXMVECTOR B0, _In_ HXMVECTOR B1, _In_ HXMVECTOR B2) noexcept; + // Triangle-Triangle + + PlaneIntersectionType XM_CALLCONV Intersects(_In_ FXMVECTOR V0, _In_ FXMVECTOR V1, _In_ FXMVECTOR V2, _In_ GXMVECTOR Plane) noexcept; + // Plane-Triangle + + ContainmentType XM_CALLCONV ContainedBy(_In_ FXMVECTOR V0, _In_ FXMVECTOR V1, _In_ FXMVECTOR V2, + _In_ GXMVECTOR Plane0, _In_ HXMVECTOR Plane1, _In_ HXMVECTOR Plane2, + _In_ CXMVECTOR Plane3, _In_ CXMVECTOR Plane4, _In_ CXMVECTOR Plane5) noexcept; + // Test a triangle against six planes at once (see BoundingFrustum::GetPlanes) + } + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + /**************************************************************************** + * + * Implementation + * + ****************************************************************************/ + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4068 4365 4616 6001) + // C4068/4616: ignore unknown pragmas + // C4365: Off by default noise + // C6001: False positives +#endif + +#ifdef _PREFAST_ +#pragma prefast(push) +#pragma prefast(disable : 25000, "FXMVECTOR is 16 bytes") +#pragma prefast(disable : 26495, "Union initialization confuses /analyze") +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wfloat-equal" +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +#endif + +#include "DirectXCollision.inl" + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#ifdef _PREFAST_ +#pragma prefast(pop) +#endif +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +} // namespace DirectX diff --git a/src/directxmath/DirectXCollision.inl b/src/directxmath/DirectXCollision.inl new file mode 100644 index 0000000..7dc222c --- /dev/null +++ b/src/directxmath/DirectXCollision.inl @@ -0,0 +1,4815 @@ +//------------------------------------------------------------------------------------- +// DirectXCollision.inl -- C++ Collision Math library +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// +// https://go.microsoft.com/fwlink/?LinkID=615560 +//------------------------------------------------------------------------------------- + +#pragma once + +XMGLOBALCONST XMVECTORF32 g_BoxOffset[8] = +{ + { { { -1.0f, -1.0f, 1.0f, 0.0f } } }, + { { { 1.0f, -1.0f, 1.0f, 0.0f } } }, + { { { 1.0f, 1.0f, 1.0f, 0.0f } } }, + { { { -1.0f, 1.0f, 1.0f, 0.0f } } }, + { { { -1.0f, -1.0f, -1.0f, 0.0f } } }, + { { { 1.0f, -1.0f, -1.0f, 0.0f } } }, + { { { 1.0f, 1.0f, -1.0f, 0.0f } } }, + { { { -1.0f, 1.0f, -1.0f, 0.0f } } }, +}; + +XMGLOBALCONST XMVECTORF32 g_RayEpsilon = { { { 1e-20f, 1e-20f, 1e-20f, 1e-20f } } }; +XMGLOBALCONST XMVECTORF32 g_RayNegEpsilon = { { { -1e-20f, -1e-20f, -1e-20f, -1e-20f } } }; +XMGLOBALCONST XMVECTORF32 g_FltMin = { { { -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX } } }; +XMGLOBALCONST XMVECTORF32 g_FltMax = { { { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX } } }; + +namespace MathInternal +{ + + //----------------------------------------------------------------------------- + // Return true if any of the elements of a 3 vector are equal to 0xffffffff. + // Slightly more efficient than using XMVector3EqualInt. + //----------------------------------------------------------------------------- + inline bool XMVector3AnyTrue(_In_ FXMVECTOR V) noexcept + { + // Duplicate the fourth element from the first element. + XMVECTOR C = XMVectorSwizzle(V); + + return XMComparisonAnyTrue(XMVector4EqualIntR(C, XMVectorTrueInt())); + } + + + //----------------------------------------------------------------------------- + // Return true if all of the elements of a 3 vector are equal to 0xffffffff. + // Slightly more efficient than using XMVector3EqualInt. + //----------------------------------------------------------------------------- + inline bool XMVector3AllTrue(_In_ FXMVECTOR V) noexcept + { + // Duplicate the fourth element from the first element. + XMVECTOR C = XMVectorSwizzle(V); + + return XMComparisonAllTrue(XMVector4EqualIntR(C, XMVectorTrueInt())); + } + +#if defined(_PREFAST_) || !defined(NDEBUG) + + XMGLOBALCONST XMVECTORF32 g_UnitVectorEpsilon = { { { 1.0e-4f, 1.0e-4f, 1.0e-4f, 1.0e-4f } } }; + XMGLOBALCONST XMVECTORF32 g_UnitQuaternionEpsilon = { { { 1.0e-4f, 1.0e-4f, 1.0e-4f, 1.0e-4f } } }; + XMGLOBALCONST XMVECTORF32 g_UnitPlaneEpsilon = { { { 1.0e-4f, 1.0e-4f, 1.0e-4f, 1.0e-4f } } }; + + //----------------------------------------------------------------------------- + // Return true if the vector is a unit vector (length == 1). + //----------------------------------------------------------------------------- + inline bool XMVector3IsUnit(_In_ FXMVECTOR V) noexcept + { + XMVECTOR Difference = XMVectorSubtract(XMVector3Length(V), XMVectorSplatOne()); + return XMVector4Less(XMVectorAbs(Difference), g_UnitVectorEpsilon); + } + + //----------------------------------------------------------------------------- + // Return true if the quaterion is a unit quaternion. + //----------------------------------------------------------------------------- + inline bool XMQuaternionIsUnit(_In_ FXMVECTOR Q) noexcept + { + XMVECTOR Difference = XMVectorSubtract(XMVector4Length(Q), XMVectorSplatOne()); + return XMVector4Less(XMVectorAbs(Difference), g_UnitQuaternionEpsilon); + } + + //----------------------------------------------------------------------------- + // Return true if the plane is a unit plane. + //----------------------------------------------------------------------------- + inline bool XMPlaneIsUnit(_In_ FXMVECTOR Plane) noexcept + { + XMVECTOR Difference = XMVectorSubtract(XMVector3Length(Plane), XMVectorSplatOne()); + return XMVector4Less(XMVectorAbs(Difference), g_UnitPlaneEpsilon); + } + +#endif // _PREFAST_ || !NDEBUG + + //----------------------------------------------------------------------------- + inline XMVECTOR XMPlaneTransform(_In_ FXMVECTOR Plane, _In_ FXMVECTOR Rotation, _In_ FXMVECTOR Translation) noexcept + { + XMVECTOR vNormal = XMVector3Rotate(Plane, Rotation); + XMVECTOR vD = XMVectorSubtract(XMVectorSplatW(Plane), XMVector3Dot(vNormal, Translation)); + + return XMVectorInsert<0, 0, 0, 0, 1>(vNormal, vD); + } + + //----------------------------------------------------------------------------- + // Return the point on the line segement (S1, S2) nearest the point P. + //----------------------------------------------------------------------------- + inline XMVECTOR PointOnLineSegmentNearestPoint(_In_ FXMVECTOR S1, _In_ FXMVECTOR S2, _In_ FXMVECTOR P) noexcept + { + XMVECTOR Dir = XMVectorSubtract(S2, S1); + XMVECTOR Projection = XMVectorSubtract(XMVector3Dot(P, Dir), XMVector3Dot(S1, Dir)); + XMVECTOR LengthSq = XMVector3Dot(Dir, Dir); + + XMVECTOR t = XMVectorMultiply(Projection, XMVectorReciprocal(LengthSq)); + XMVECTOR Point = XMVectorMultiplyAdd(t, Dir, S1); + + // t < 0 + XMVECTOR SelectS1 = XMVectorLess(Projection, XMVectorZero()); + Point = XMVectorSelect(Point, S1, SelectS1); + + // t > 1 + XMVECTOR SelectS2 = XMVectorGreater(Projection, LengthSq); + Point = XMVectorSelect(Point, S2, SelectS2); + + return Point; + } + + //----------------------------------------------------------------------------- + // Test if the point (P) on the plane of the triangle is inside the triangle + // (V0, V1, V2). + //----------------------------------------------------------------------------- + inline XMVECTOR XM_CALLCONV PointOnPlaneInsideTriangle(_In_ FXMVECTOR P, _In_ FXMVECTOR V0, _In_ FXMVECTOR V1, _In_ GXMVECTOR V2) noexcept + { + // Compute the triangle normal. + XMVECTOR N = XMVector3Cross(XMVectorSubtract(V2, V0), XMVectorSubtract(V1, V0)); + + // Compute the cross products of the vector from the base of each edge to + // the point with each edge vector. + XMVECTOR C0 = XMVector3Cross(XMVectorSubtract(P, V0), XMVectorSubtract(V1, V0)); + XMVECTOR C1 = XMVector3Cross(XMVectorSubtract(P, V1), XMVectorSubtract(V2, V1)); + XMVECTOR C2 = XMVector3Cross(XMVectorSubtract(P, V2), XMVectorSubtract(V0, V2)); + + // If the cross product points in the same direction as the normal the the + // point is inside the edge (it is zero if is on the edge). + XMVECTOR Zero = XMVectorZero(); + XMVECTOR Inside0 = XMVectorGreaterOrEqual(XMVector3Dot(C0, N), Zero); + XMVECTOR Inside1 = XMVectorGreaterOrEqual(XMVector3Dot(C1, N), Zero); + XMVECTOR Inside2 = XMVectorGreaterOrEqual(XMVector3Dot(C2, N), Zero); + + // If the point inside all of the edges it is inside. + return XMVectorAndInt(XMVectorAndInt(Inside0, Inside1), Inside2); + } + + //----------------------------------------------------------------------------- + inline bool SolveCubic(_In_ float e, _In_ float f, _In_ float g, _Out_ float* t, _Out_ float* u, _Out_ float* v) noexcept + { + float p, q, h, rc, d, theta, costh3, sinth3; + + p = f - e * e / 3.0f; + q = g - e * f / 3.0f + e * e * e * 2.0f / 27.0f; + h = q * q / 4.0f + p * p * p / 27.0f; + + if (h > 0) + { + *t = *u = *v = 0.f; + return false; // only one real root + } + + if ((h == 0) && (q == 0)) // all the same root + { + *t = -e / 3; + *u = -e / 3; + *v = -e / 3; + + return true; + } + + d = sqrtf(q * q / 4.0f - h); + if (d < 0) + rc = -powf(-d, 1.0f / 3.0f); + else + rc = powf(d, 1.0f / 3.0f); + + theta = XMScalarACos(-q / (2.0f * d)); + costh3 = XMScalarCos(theta / 3.0f); + sinth3 = sqrtf(3.0f) * XMScalarSin(theta / 3.0f); + *t = 2.0f * rc * costh3 - e / 3.0f; + *u = -rc * (costh3 + sinth3) - e / 3.0f; + *v = -rc * (costh3 - sinth3) - e / 3.0f; + + return true; + } + + //----------------------------------------------------------------------------- + inline XMVECTOR CalculateEigenVector(_In_ float m11, _In_ float m12, _In_ float m13, + _In_ float m22, _In_ float m23, _In_ float m33, _In_ float e) noexcept + { + float fTmp[3]; + fTmp[0] = m12 * m23 - m13 * (m22 - e); + fTmp[1] = m13 * m12 - m23 * (m11 - e); + fTmp[2] = (m11 - e) * (m22 - e) - m12 * m12; + + XMVECTOR vTmp = XMLoadFloat3(reinterpret_cast(fTmp)); + + if (XMVector3Equal(vTmp, XMVectorZero())) // planar or linear + { + float f1, f2, f3; + + // we only have one equation - find a valid one + if ((m11 - e != 0) || (m12 != 0) || (m13 != 0)) + { + f1 = m11 - e; f2 = m12; f3 = m13; + } + else if ((m12 != 0) || (m22 - e != 0) || (m23 != 0)) + { + f1 = m12; f2 = m22 - e; f3 = m23; + } + else if ((m13 != 0) || (m23 != 0) || (m33 - e != 0)) + { + f1 = m13; f2 = m23; f3 = m33 - e; + } + else + { + // error, we'll just make something up - we have NO context + f1 = 1.0f; f2 = 0.0f; f3 = 0.0f; + } + + if (f1 == 0) + vTmp = XMVectorSetX(vTmp, 0.0f); + else + vTmp = XMVectorSetX(vTmp, 1.0f); + + if (f2 == 0) + vTmp = XMVectorSetY(vTmp, 0.0f); + else + vTmp = XMVectorSetY(vTmp, 1.0f); + + if (f3 == 0) + { + vTmp = XMVectorSetZ(vTmp, 0.0f); + // recalculate y to make equation work + if (m12 != 0) + vTmp = XMVectorSetY(vTmp, -f1 / f2); + } + else + { + vTmp = XMVectorSetZ(vTmp, (f2 - f1) / f3); + } + } + + if (XMVectorGetX(XMVector3LengthSq(vTmp)) > 1e-5f) + { + return XMVector3Normalize(vTmp); + } + else + { + // Multiply by a value large enough to make the vector non-zero. + vTmp = XMVectorScale(vTmp, 1e5f); + return XMVector3Normalize(vTmp); + } + } + + //----------------------------------------------------------------------------- + inline bool CalculateEigenVectors(_In_ float m11, _In_ float m12, _In_ float m13, + _In_ float m22, _In_ float m23, _In_ float m33, + _In_ float e1, _In_ float e2, _In_ float e3, + _Out_ XMVECTOR* pV1, _Out_ XMVECTOR* pV2, _Out_ XMVECTOR* pV3) noexcept + { + *pV1 = DirectX::MathInternal::CalculateEigenVector(m11, m12, m13, m22, m23, m33, e1); + *pV2 = DirectX::MathInternal::CalculateEigenVector(m11, m12, m13, m22, m23, m33, e2); + *pV3 = DirectX::MathInternal::CalculateEigenVector(m11, m12, m13, m22, m23, m33, e3); + + bool v1z = false; + bool v2z = false; + bool v3z = false; + + XMVECTOR Zero = XMVectorZero(); + + if (XMVector3Equal(*pV1, Zero)) + v1z = true; + + if (XMVector3Equal(*pV2, Zero)) + v2z = true; + + if (XMVector3Equal(*pV3, Zero)) + v3z = true; + + bool e12 = (fabsf(XMVectorGetX(XMVector3Dot(*pV1, *pV2))) > 0.1f); // check for non-orthogonal vectors + bool e13 = (fabsf(XMVectorGetX(XMVector3Dot(*pV1, *pV3))) > 0.1f); + bool e23 = (fabsf(XMVectorGetX(XMVector3Dot(*pV2, *pV3))) > 0.1f); + + if ((v1z && v2z && v3z) || (e12 && e13 && e23) || + (e12 && v3z) || (e13 && v2z) || (e23 && v1z)) // all eigenvectors are 0- any basis set + { + *pV1 = g_XMIdentityR0.v; + *pV2 = g_XMIdentityR1.v; + *pV3 = g_XMIdentityR2.v; + return true; + } + + if (v1z && v2z) + { + XMVECTOR vTmp = XMVector3Cross(g_XMIdentityR1, *pV3); + if (XMVectorGetX(XMVector3LengthSq(vTmp)) < 1e-5f) + { + vTmp = XMVector3Cross(g_XMIdentityR0, *pV3); + } + *pV1 = XMVector3Normalize(vTmp); + *pV2 = XMVector3Cross(*pV3, *pV1); + return true; + } + + if (v3z && v1z) + { + XMVECTOR vTmp = XMVector3Cross(g_XMIdentityR1, *pV2); + if (XMVectorGetX(XMVector3LengthSq(vTmp)) < 1e-5f) + { + vTmp = XMVector3Cross(g_XMIdentityR0, *pV2); + } + *pV3 = XMVector3Normalize(vTmp); + *pV1 = XMVector3Cross(*pV2, *pV3); + return true; + } + + if (v2z && v3z) + { + XMVECTOR vTmp = XMVector3Cross(g_XMIdentityR1, *pV1); + if (XMVectorGetX(XMVector3LengthSq(vTmp)) < 1e-5f) + { + vTmp = XMVector3Cross(g_XMIdentityR0, *pV1); + } + *pV2 = XMVector3Normalize(vTmp); + *pV3 = XMVector3Cross(*pV1, *pV2); + return true; + } + + if ((v1z) || e12) + { + *pV1 = XMVector3Cross(*pV2, *pV3); + return true; + } + + if ((v2z) || e23) + { + *pV2 = XMVector3Cross(*pV3, *pV1); + return true; + } + + if ((v3z) || e13) + { + *pV3 = XMVector3Cross(*pV1, *pV2); + return true; + } + + return true; + } + + //----------------------------------------------------------------------------- + inline bool CalculateEigenVectorsFromCovarianceMatrix(_In_ float Cxx, _In_ float Cyy, _In_ float Czz, + _In_ float Cxy, _In_ float Cxz, _In_ float Cyz, + _Out_ XMVECTOR* pV1, _Out_ XMVECTOR* pV2, _Out_ XMVECTOR* pV3) noexcept + { + // Calculate the eigenvalues by solving a cubic equation. + float e = -(Cxx + Cyy + Czz); + float f = Cxx * Cyy + Cyy * Czz + Czz * Cxx - Cxy * Cxy - Cxz * Cxz - Cyz * Cyz; + float g = Cxy * Cxy * Czz + Cxz * Cxz * Cyy + Cyz * Cyz * Cxx - Cxy * Cyz * Cxz * 2.0f - Cxx * Cyy * Czz; + + float ev1, ev2, ev3; + if (!DirectX::MathInternal::SolveCubic(e, f, g, &ev1, &ev2, &ev3)) + { + // set them to arbitrary orthonormal basis set + *pV1 = g_XMIdentityR0.v; + *pV2 = g_XMIdentityR1.v; + *pV3 = g_XMIdentityR2.v; + return false; + } + + return DirectX::MathInternal::CalculateEigenVectors(Cxx, Cxy, Cxz, Cyy, Cyz, Czz, ev1, ev2, ev3, pV1, pV2, pV3); + } + + //----------------------------------------------------------------------------- + inline void XM_CALLCONV FastIntersectTrianglePlane( + FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2, + GXMVECTOR Plane, + XMVECTOR& Outside, XMVECTOR& Inside) noexcept + { + // Plane0 + XMVECTOR Dist0 = XMVector4Dot(V0, Plane); + XMVECTOR Dist1 = XMVector4Dot(V1, Plane); + XMVECTOR Dist2 = XMVector4Dot(V2, Plane); + + XMVECTOR MinDist = XMVectorMin(Dist0, Dist1); + MinDist = XMVectorMin(MinDist, Dist2); + + XMVECTOR MaxDist = XMVectorMax(Dist0, Dist1); + MaxDist = XMVectorMax(MaxDist, Dist2); + + XMVECTOR Zero = XMVectorZero(); + + // Outside the plane? + Outside = XMVectorGreater(MinDist, Zero); + + // Fully inside the plane? + Inside = XMVectorLess(MaxDist, Zero); + } + + //----------------------------------------------------------------------------- + inline void FastIntersectSpherePlane(_In_ FXMVECTOR Center, _In_ FXMVECTOR Radius, _In_ FXMVECTOR Plane, + _Out_ XMVECTOR& Outside, _Out_ XMVECTOR& Inside) noexcept + { + XMVECTOR Dist = XMVector4Dot(Center, Plane); + + // Outside the plane? + Outside = XMVectorGreater(Dist, Radius); + + // Fully inside the plane? + Inside = XMVectorLess(Dist, XMVectorNegate(Radius)); + } + + //----------------------------------------------------------------------------- + inline void FastIntersectAxisAlignedBoxPlane(_In_ FXMVECTOR Center, _In_ FXMVECTOR Extents, _In_ FXMVECTOR Plane, + _Out_ XMVECTOR& Outside, _Out_ XMVECTOR& Inside) noexcept + { + // Compute the distance to the center of the box. + XMVECTOR Dist = XMVector4Dot(Center, Plane); + + // Project the axes of the box onto the normal of the plane. Half the + // length of the projection (sometime called the "radius") is equal to + // h(u) * abs(n dot b(u))) + h(v) * abs(n dot b(v)) + h(w) * abs(n dot b(w)) + // where h(i) are extents of the box, n is the plane normal, and b(i) are the + // axes of the box. In this case b(i) = [(1,0,0), (0,1,0), (0,0,1)]. + XMVECTOR Radius = XMVector3Dot(Extents, XMVectorAbs(Plane)); + + // Outside the plane? + Outside = XMVectorGreater(Dist, Radius); + + // Fully inside the plane? + Inside = XMVectorLess(Dist, XMVectorNegate(Radius)); + } + + //----------------------------------------------------------------------------- + inline void XM_CALLCONV FastIntersectOrientedBoxPlane( + _In_ FXMVECTOR Center, _In_ FXMVECTOR Extents, _In_ FXMVECTOR Axis0, + _In_ GXMVECTOR Axis1, + _In_ HXMVECTOR Axis2, _In_ HXMVECTOR Plane, + _Out_ XMVECTOR& Outside, _Out_ XMVECTOR& Inside) noexcept + { + // Compute the distance to the center of the box. + XMVECTOR Dist = XMVector4Dot(Center, Plane); + + // Project the axes of the box onto the normal of the plane. Half the + // length of the projection (sometime called the "radius") is equal to + // h(u) * abs(n dot b(u))) + h(v) * abs(n dot b(v)) + h(w) * abs(n dot b(w)) + // where h(i) are extents of the box, n is the plane normal, and b(i) are the + // axes of the box. + XMVECTOR Radius = XMVector3Dot(Plane, Axis0); + Radius = XMVectorInsert<0, 0, 1, 0, 0>(Radius, XMVector3Dot(Plane, Axis1)); + Radius = XMVectorInsert<0, 0, 0, 1, 0>(Radius, XMVector3Dot(Plane, Axis2)); + Radius = XMVector3Dot(Extents, XMVectorAbs(Radius)); + + // Outside the plane? + Outside = XMVectorGreater(Dist, Radius); + + // Fully inside the plane? + Inside = XMVectorLess(Dist, XMVectorNegate(Radius)); + } + + //----------------------------------------------------------------------------- + inline void XM_CALLCONV FastIntersectFrustumPlane( + _In_ FXMVECTOR Point0, _In_ FXMVECTOR Point1, _In_ FXMVECTOR Point2, + _In_ GXMVECTOR Point3, + _In_ HXMVECTOR Point4, _In_ HXMVECTOR Point5, + _In_ CXMVECTOR Point6, _In_ CXMVECTOR Point7, _In_ CXMVECTOR Plane, + _Out_ XMVECTOR& Outside, _Out_ XMVECTOR& Inside) noexcept + { + // Find the min/max projection of the frustum onto the plane normal. + XMVECTOR Min, Max, Dist; + + Min = Max = XMVector3Dot(Plane, Point0); + + Dist = XMVector3Dot(Plane, Point1); + Min = XMVectorMin(Min, Dist); + Max = XMVectorMax(Max, Dist); + + Dist = XMVector3Dot(Plane, Point2); + Min = XMVectorMin(Min, Dist); + Max = XMVectorMax(Max, Dist); + + Dist = XMVector3Dot(Plane, Point3); + Min = XMVectorMin(Min, Dist); + Max = XMVectorMax(Max, Dist); + + Dist = XMVector3Dot(Plane, Point4); + Min = XMVectorMin(Min, Dist); + Max = XMVectorMax(Max, Dist); + + Dist = XMVector3Dot(Plane, Point5); + Min = XMVectorMin(Min, Dist); + Max = XMVectorMax(Max, Dist); + + Dist = XMVector3Dot(Plane, Point6); + Min = XMVectorMin(Min, Dist); + Max = XMVectorMax(Max, Dist); + + Dist = XMVector3Dot(Plane, Point7); + Min = XMVectorMin(Min, Dist); + Max = XMVectorMax(Max, Dist); + + XMVECTOR PlaneDist = XMVectorNegate(XMVectorSplatW(Plane)); + + // Outside the plane? + Outside = XMVectorGreater(Min, PlaneDist); + + // Fully inside the plane? + Inside = XMVectorLess(Max, PlaneDist); + } + +} // namespace MathInternal + + +/**************************************************************************** + * + * BoundingSphere + * + ****************************************************************************/ + +//----------------------------------------------------------------------------- +// Transform a sphere by an angle preserving transform. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void XM_CALLCONV BoundingSphere::Transform(BoundingSphere& Out, FXMMATRIX M) const noexcept +{ + // Load the center of the sphere. + XMVECTOR vCenter = XMLoadFloat3(&Center); + + // Transform the center of the sphere. + XMVECTOR C = XMVector3Transform(vCenter, M); + + XMVECTOR dX = XMVector3Dot(M.r[0], M.r[0]); + XMVECTOR dY = XMVector3Dot(M.r[1], M.r[1]); + XMVECTOR dZ = XMVector3Dot(M.r[2], M.r[2]); + + XMVECTOR d = XMVectorMax(dX, XMVectorMax(dY, dZ)); + + // Store the center sphere. + XMStoreFloat3(&Out.Center, C); + + // Scale the radius of the pshere. + float Scale = sqrtf(XMVectorGetX(d)); + Out.Radius = Radius * Scale; +} + +_Use_decl_annotations_ +inline void XM_CALLCONV BoundingSphere::Transform(BoundingSphere& Out, float Scale, FXMVECTOR Rotation, FXMVECTOR Translation) const noexcept +{ + // Load the center of the sphere. + XMVECTOR vCenter = XMLoadFloat3(&Center); + + // Transform the center of the sphere. + vCenter = XMVectorAdd(XMVector3Rotate(XMVectorScale(vCenter, Scale), Rotation), Translation); + + // Store the center sphere. + XMStoreFloat3(&Out.Center, vCenter); + + // Scale the radius of the pshere. + Out.Radius = Radius * Scale; +} + + +//----------------------------------------------------------------------------- +// Point in sphere test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType XM_CALLCONV BoundingSphere::Contains(FXMVECTOR Point) const noexcept +{ + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vRadius = XMVectorReplicatePtr(&Radius); + + XMVECTOR DistanceSquared = XMVector3LengthSq(XMVectorSubtract(Point, vCenter)); + XMVECTOR RadiusSquared = XMVectorMultiply(vRadius, vRadius); + + return XMVector3LessOrEqual(DistanceSquared, RadiusSquared) ? CONTAINS : DISJOINT; +} + + +//----------------------------------------------------------------------------- +// Triangle in sphere test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType XM_CALLCONV BoundingSphere::Contains(FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2) const noexcept +{ + if (!Intersects(V0, V1, V2)) + return DISJOINT; + + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vRadius = XMVectorReplicatePtr(&Radius); + XMVECTOR RadiusSquared = XMVectorMultiply(vRadius, vRadius); + + XMVECTOR DistanceSquared = XMVector3LengthSq(XMVectorSubtract(V0, vCenter)); + XMVECTOR Inside = XMVectorLessOrEqual(DistanceSquared, RadiusSquared); + + DistanceSquared = XMVector3LengthSq(XMVectorSubtract(V1, vCenter)); + Inside = XMVectorAndInt(Inside, XMVectorLessOrEqual(DistanceSquared, RadiusSquared)); + + DistanceSquared = XMVector3LengthSq(XMVectorSubtract(V2, vCenter)); + Inside = XMVectorAndInt(Inside, XMVectorLessOrEqual(DistanceSquared, RadiusSquared)); + + return (XMVector3EqualInt(Inside, XMVectorTrueInt())) ? CONTAINS : INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Sphere in sphere test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingSphere::Contains(const BoundingSphere& sh) const noexcept +{ + XMVECTOR Center1 = XMLoadFloat3(&Center); + float r1 = Radius; + + XMVECTOR Center2 = XMLoadFloat3(&sh.Center); + float r2 = sh.Radius; + + XMVECTOR V = XMVectorSubtract(Center2, Center1); + + XMVECTOR Dist = XMVector3Length(V); + + float d = XMVectorGetX(Dist); + + return (r1 + r2 >= d) ? ((r1 - r2 >= d) ? CONTAINS : INTERSECTS) : DISJOINT; +} + + +//----------------------------------------------------------------------------- +// Axis-aligned box in sphere test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingSphere::Contains(const BoundingBox& box) const noexcept +{ + if (!box.Intersects(*this)) + return DISJOINT; + + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vRadius = XMVectorReplicatePtr(&Radius); + XMVECTOR RadiusSq = XMVectorMultiply(vRadius, vRadius); + + XMVECTOR boxCenter = XMLoadFloat3(&box.Center); + XMVECTOR boxExtents = XMLoadFloat3(&box.Extents); + + XMVECTOR InsideAll = XMVectorTrueInt(); + + XMVECTOR offset = XMVectorSubtract(boxCenter, vCenter); + + for (size_t i = 0; i < BoundingBox::CORNER_COUNT; ++i) + { + XMVECTOR C = XMVectorMultiplyAdd(boxExtents, g_BoxOffset[i], offset); + XMVECTOR d = XMVector3LengthSq(C); + InsideAll = XMVectorAndInt(InsideAll, XMVectorLessOrEqual(d, RadiusSq)); + } + + return (XMVector3EqualInt(InsideAll, XMVectorTrueInt())) ? CONTAINS : INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Oriented box in sphere test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingSphere::Contains(const BoundingOrientedBox& box) const noexcept +{ + if (!box.Intersects(*this)) + return DISJOINT; + + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vRadius = XMVectorReplicatePtr(&Radius); + XMVECTOR RadiusSq = XMVectorMultiply(vRadius, vRadius); + + XMVECTOR boxCenter = XMLoadFloat3(&box.Center); + XMVECTOR boxExtents = XMLoadFloat3(&box.Extents); + XMVECTOR boxOrientation = XMLoadFloat4(&box.Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(boxOrientation)); + + XMVECTOR InsideAll = XMVectorTrueInt(); + + for (size_t i = 0; i < BoundingOrientedBox::CORNER_COUNT; ++i) + { + XMVECTOR C = XMVectorAdd(XMVector3Rotate(XMVectorMultiply(boxExtents, g_BoxOffset[i]), boxOrientation), boxCenter); + XMVECTOR d = XMVector3LengthSq(XMVectorSubtract(vCenter, C)); + InsideAll = XMVectorAndInt(InsideAll, XMVectorLessOrEqual(d, RadiusSq)); + } + + return (XMVector3EqualInt(InsideAll, XMVectorTrueInt())) ? CONTAINS : INTERSECTS; + +} + + +//----------------------------------------------------------------------------- +// Frustum in sphere test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingSphere::Contains(const BoundingFrustum& fr) const noexcept +{ + if (!fr.Intersects(*this)) + return DISJOINT; + + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vRadius = XMVectorReplicatePtr(&Radius); + XMVECTOR RadiusSq = XMVectorMultiply(vRadius, vRadius); + + XMVECTOR vOrigin = XMLoadFloat3(&fr.Origin); + XMVECTOR vOrientation = XMLoadFloat4(&fr.Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + // Build the corners of the frustum. + XMVECTOR vRightTop = XMVectorSet(fr.RightSlope, fr.TopSlope, 1.0f, 0.0f); + XMVECTOR vRightBottom = XMVectorSet(fr.RightSlope, fr.BottomSlope, 1.0f, 0.0f); + XMVECTOR vLeftTop = XMVectorSet(fr.LeftSlope, fr.TopSlope, 1.0f, 0.0f); + XMVECTOR vLeftBottom = XMVectorSet(fr.LeftSlope, fr.BottomSlope, 1.0f, 0.0f); + XMVECTOR vNear = XMVectorReplicatePtr(&fr.Near); + XMVECTOR vFar = XMVectorReplicatePtr(&fr.Far); + + XMVECTOR Corners[BoundingFrustum::CORNER_COUNT]; + Corners[0] = XMVectorMultiply(vRightTop, vNear); + Corners[1] = XMVectorMultiply(vRightBottom, vNear); + Corners[2] = XMVectorMultiply(vLeftTop, vNear); + Corners[3] = XMVectorMultiply(vLeftBottom, vNear); + Corners[4] = XMVectorMultiply(vRightTop, vFar); + Corners[5] = XMVectorMultiply(vRightBottom, vFar); + Corners[6] = XMVectorMultiply(vLeftTop, vFar); + Corners[7] = XMVectorMultiply(vLeftBottom, vFar); + + XMVECTOR InsideAll = XMVectorTrueInt(); + for (size_t i = 0; i < BoundingFrustum::CORNER_COUNT; ++i) + { + XMVECTOR C = XMVectorAdd(XMVector3Rotate(Corners[i], vOrientation), vOrigin); + XMVECTOR d = XMVector3LengthSq(XMVectorSubtract(vCenter, C)); + InsideAll = XMVectorAndInt(InsideAll, XMVectorLessOrEqual(d, RadiusSq)); + } + + return (XMVector3EqualInt(InsideAll, XMVectorTrueInt())) ? CONTAINS : INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Sphere vs. sphere test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingSphere::Intersects(const BoundingSphere& sh) const noexcept +{ + // Load A. + XMVECTOR vCenterA = XMLoadFloat3(&Center); + XMVECTOR vRadiusA = XMVectorReplicatePtr(&Radius); + + // Load B. + XMVECTOR vCenterB = XMLoadFloat3(&sh.Center); + XMVECTOR vRadiusB = XMVectorReplicatePtr(&sh.Radius); + + // Distance squared between centers. + XMVECTOR Delta = XMVectorSubtract(vCenterB, vCenterA); + XMVECTOR DistanceSquared = XMVector3LengthSq(Delta); + + // Sum of the radii squared. + XMVECTOR RadiusSquared = XMVectorAdd(vRadiusA, vRadiusB); + RadiusSquared = XMVectorMultiply(RadiusSquared, RadiusSquared); + + return XMVector3LessOrEqual(DistanceSquared, RadiusSquared); +} + + +//----------------------------------------------------------------------------- +// Box vs. sphere test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingSphere::Intersects(const BoundingBox& box) const noexcept +{ + return box.Intersects(*this); +} + +_Use_decl_annotations_ +inline bool BoundingSphere::Intersects(const BoundingOrientedBox& box) const noexcept +{ + return box.Intersects(*this); +} + + +//----------------------------------------------------------------------------- +// Frustum vs. sphere test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingSphere::Intersects(const BoundingFrustum& fr) const noexcept +{ + return fr.Intersects(*this); +} + + +//----------------------------------------------------------------------------- +// Triangle vs sphere test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool XM_CALLCONV BoundingSphere::Intersects(FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2) const noexcept +{ + // Load the sphere. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vRadius = XMVectorReplicatePtr(&Radius); + + // Compute the plane of the triangle (has to be normalized). + XMVECTOR N = XMVector3Normalize(XMVector3Cross(XMVectorSubtract(V1, V0), XMVectorSubtract(V2, V0))); + + // Assert that the triangle is not degenerate. + assert(!XMVector3Equal(N, XMVectorZero())); + + // Find the nearest feature on the triangle to the sphere. + XMVECTOR Dist = XMVector3Dot(XMVectorSubtract(vCenter, V0), N); + + // If the center of the sphere is farther from the plane of the triangle than + // the radius of the sphere, then there cannot be an intersection. + XMVECTOR NoIntersection = XMVectorLess(Dist, XMVectorNegate(vRadius)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(Dist, vRadius)); + + // Project the center of the sphere onto the plane of the triangle. + XMVECTOR Point = XMVectorNegativeMultiplySubtract(N, Dist, vCenter); + + // Is it inside all the edges? If so we intersect because the distance + // to the plane is less than the radius. + XMVECTOR Intersection = DirectX::MathInternal::PointOnPlaneInsideTriangle(Point, V0, V1, V2); + + // Find the nearest point on each edge. + XMVECTOR RadiusSq = XMVectorMultiply(vRadius, vRadius); + + // Edge 0,1 + Point = DirectX::MathInternal::PointOnLineSegmentNearestPoint(V0, V1, vCenter); + + // If the distance to the center of the sphere to the point is less than + // the radius of the sphere then it must intersect. + Intersection = XMVectorOrInt(Intersection, XMVectorLessOrEqual(XMVector3LengthSq(XMVectorSubtract(vCenter, Point)), RadiusSq)); + + // Edge 1,2 + Point = DirectX::MathInternal::PointOnLineSegmentNearestPoint(V1, V2, vCenter); + + // If the distance to the center of the sphere to the point is less than + // the radius of the sphere then it must intersect. + Intersection = XMVectorOrInt(Intersection, XMVectorLessOrEqual(XMVector3LengthSq(XMVectorSubtract(vCenter, Point)), RadiusSq)); + + // Edge 2,0 + Point = DirectX::MathInternal::PointOnLineSegmentNearestPoint(V2, V0, vCenter); + + // If the distance to the center of the sphere to the point is less than + // the radius of the sphere then it must intersect. + Intersection = XMVectorOrInt(Intersection, XMVectorLessOrEqual(XMVector3LengthSq(XMVectorSubtract(vCenter, Point)), RadiusSq)); + + return XMVector4EqualInt(XMVectorAndCInt(Intersection, NoIntersection), XMVectorTrueInt()); +} + + +//----------------------------------------------------------------------------- +// Sphere-plane intersection +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline PlaneIntersectionType XM_CALLCONV BoundingSphere::Intersects(FXMVECTOR Plane) const noexcept +{ + assert(DirectX::MathInternal::XMPlaneIsUnit(Plane)); + + // Load the sphere. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vRadius = XMVectorReplicatePtr(&Radius); + + // Set w of the center to one so we can dot4 with a plane. + vCenter = XMVectorInsert<0, 0, 0, 0, 1>(vCenter, XMVectorSplatOne()); + + XMVECTOR Outside, Inside; + DirectX::MathInternal::FastIntersectSpherePlane(vCenter, vRadius, Plane, Outside, Inside); + + // If the sphere is outside any plane it is outside. + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return FRONT; + + // If the sphere is inside all planes it is inside. + if (XMVector4EqualInt(Inside, XMVectorTrueInt())) + return BACK; + + // The sphere is not inside all planes or outside a plane it intersects. + return INTERSECTING; +} + + +//----------------------------------------------------------------------------- +// Compute the intersection of a ray (Origin, Direction) with a sphere. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool XM_CALLCONV BoundingSphere::Intersects(FXMVECTOR Origin, FXMVECTOR Direction, float& Dist) const noexcept +{ + assert(DirectX::MathInternal::XMVector3IsUnit(Direction)); + + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vRadius = XMVectorReplicatePtr(&Radius); + + // l is the vector from the ray origin to the center of the sphere. + XMVECTOR l = XMVectorSubtract(vCenter, Origin); + + // s is the projection of the l onto the ray direction. + XMVECTOR s = XMVector3Dot(l, Direction); + + XMVECTOR l2 = XMVector3Dot(l, l); + + XMVECTOR r2 = XMVectorMultiply(vRadius, vRadius); + + // m2 is squared distance from the center of the sphere to the projection. + XMVECTOR m2 = XMVectorNegativeMultiplySubtract(s, s, l2); + + XMVECTOR NoIntersection; + + // If the ray origin is outside the sphere and the center of the sphere is + // behind the ray origin there is no intersection. + NoIntersection = XMVectorAndInt(XMVectorLess(s, XMVectorZero()), XMVectorGreater(l2, r2)); + + // If the squared distance from the center of the sphere to the projection + // is greater than the radius squared the ray will miss the sphere. + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(m2, r2)); + + // The ray hits the sphere, compute the nearest intersection point. + XMVECTOR q = XMVectorSqrt(XMVectorSubtract(r2, m2)); + XMVECTOR t1 = XMVectorSubtract(s, q); + XMVECTOR t2 = XMVectorAdd(s, q); + + XMVECTOR OriginInside = XMVectorLessOrEqual(l2, r2); + XMVECTOR t = XMVectorSelect(t1, t2, OriginInside); + + if (XMVector4NotEqualInt(NoIntersection, XMVectorTrueInt())) + { + // Store the x-component to *pDist. + XMStoreFloat(&Dist, t); + return true; + } + + Dist = 0.f; + return false; +} + + +//----------------------------------------------------------------------------- +// Test a sphere vs 6 planes (typically forming a frustum). +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType XM_CALLCONV BoundingSphere::ContainedBy( + FXMVECTOR Plane0, FXMVECTOR Plane1, FXMVECTOR Plane2, + GXMVECTOR Plane3, + HXMVECTOR Plane4, HXMVECTOR Plane5) const noexcept +{ + // Load the sphere. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vRadius = XMVectorReplicatePtr(&Radius); + + // Set w of the center to one so we can dot4 with a plane. + vCenter = XMVectorInsert<0, 0, 0, 0, 1>(vCenter, XMVectorSplatOne()); + + XMVECTOR Outside, Inside; + + // Test against each plane. + DirectX::MathInternal::FastIntersectSpherePlane(vCenter, vRadius, Plane0, Outside, Inside); + + XMVECTOR AnyOutside = Outside; + XMVECTOR AllInside = Inside; + + DirectX::MathInternal::FastIntersectSpherePlane(vCenter, vRadius, Plane1, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectSpherePlane(vCenter, vRadius, Plane2, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectSpherePlane(vCenter, vRadius, Plane3, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectSpherePlane(vCenter, vRadius, Plane4, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectSpherePlane(vCenter, vRadius, Plane5, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + // If the sphere is outside any plane it is outside. + if (XMVector4EqualInt(AnyOutside, XMVectorTrueInt())) + return DISJOINT; + + // If the sphere is inside all planes it is inside. + if (XMVector4EqualInt(AllInside, XMVectorTrueInt())) + return CONTAINS; + + // The sphere is not inside all planes or outside a plane, it may intersect. + return INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Creates a bounding sphere that contains two other bounding spheres +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingSphere::CreateMerged(BoundingSphere& Out, const BoundingSphere& S1, const BoundingSphere& S2) noexcept +{ + XMVECTOR Center1 = XMLoadFloat3(&S1.Center); + float r1 = S1.Radius; + + XMVECTOR Center2 = XMLoadFloat3(&S2.Center); + float r2 = S2.Radius; + + XMVECTOR V = XMVectorSubtract(Center2, Center1); + + XMVECTOR Dist = XMVector3Length(V); + + float d = XMVectorGetX(Dist); + + if (r1 + r2 >= d) + { + if (r1 - r2 >= d) + { + Out = S1; + return; + } + else if (r2 - r1 >= d) + { + Out = S2; + return; + } + } + + XMVECTOR N = XMVectorDivide(V, Dist); + + float t1 = XMMin(-r1, d - r2); + float t2 = XMMax(r1, d + r2); + float t_5 = (t2 - t1) * 0.5f; + + XMVECTOR NCenter = XMVectorAdd(Center1, XMVectorMultiply(N, XMVectorReplicate(t_5 + t1))); + + XMStoreFloat3(&Out.Center, NCenter); + Out.Radius = t_5; +} + + +//----------------------------------------------------------------------------- +// Create sphere enscribing bounding box +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingSphere::CreateFromBoundingBox(BoundingSphere& Out, const BoundingBox& box) noexcept +{ + Out.Center = box.Center; + XMVECTOR vExtents = XMLoadFloat3(&box.Extents); + Out.Radius = XMVectorGetX(XMVector3Length(vExtents)); +} + +_Use_decl_annotations_ +inline void BoundingSphere::CreateFromBoundingBox(BoundingSphere& Out, const BoundingOrientedBox& box) noexcept +{ + // Bounding box orientation is irrelevant because a sphere is rotationally invariant + Out.Center = box.Center; + XMVECTOR vExtents = XMLoadFloat3(&box.Extents); + Out.Radius = XMVectorGetX(XMVector3Length(vExtents)); +} + + +//----------------------------------------------------------------------------- +// Find the approximate smallest enclosing bounding sphere for a set of +// points. Exact computation of the smallest enclosing bounding sphere is +// possible but is slower and requires a more complex algorithm. +// The algorithm is based on Jack Ritter, "An Efficient Bounding Sphere", +// Graphics Gems. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingSphere::CreateFromPoints(BoundingSphere& Out, size_t Count, const XMFLOAT3* pPoints, size_t Stride) noexcept +{ + assert(Count > 0); + assert(pPoints); + + // Find the points with minimum and maximum x, y, and z + XMVECTOR MinX, MaxX, MinY, MaxY, MinZ, MaxZ; + + MinX = MaxX = MinY = MaxY = MinZ = MaxZ = XMLoadFloat3(pPoints); + + for (size_t i = 1; i < Count; ++i) + { + XMVECTOR Point = XMLoadFloat3(reinterpret_cast(reinterpret_cast(pPoints) + i * Stride)); + + float px = XMVectorGetX(Point); + float py = XMVectorGetY(Point); + float pz = XMVectorGetZ(Point); + + if (px < XMVectorGetX(MinX)) + MinX = Point; + + if (px > XMVectorGetX(MaxX)) + MaxX = Point; + + if (py < XMVectorGetY(MinY)) + MinY = Point; + + if (py > XMVectorGetY(MaxY)) + MaxY = Point; + + if (pz < XMVectorGetZ(MinZ)) + MinZ = Point; + + if (pz > XMVectorGetZ(MaxZ)) + MaxZ = Point; + } + + // Use the min/max pair that are farthest apart to form the initial sphere. + XMVECTOR DeltaX = XMVectorSubtract(MaxX, MinX); + XMVECTOR DistX = XMVector3Length(DeltaX); + + XMVECTOR DeltaY = XMVectorSubtract(MaxY, MinY); + XMVECTOR DistY = XMVector3Length(DeltaY); + + XMVECTOR DeltaZ = XMVectorSubtract(MaxZ, MinZ); + XMVECTOR DistZ = XMVector3Length(DeltaZ); + + XMVECTOR vCenter; + XMVECTOR vRadius; + + if (XMVector3Greater(DistX, DistY)) + { + if (XMVector3Greater(DistX, DistZ)) + { + // Use min/max x. + vCenter = XMVectorLerp(MaxX, MinX, 0.5f); + vRadius = XMVectorScale(DistX, 0.5f); + } + else + { + // Use min/max z. + vCenter = XMVectorLerp(MaxZ, MinZ, 0.5f); + vRadius = XMVectorScale(DistZ, 0.5f); + } + } + else // Y >= X + { + if (XMVector3Greater(DistY, DistZ)) + { + // Use min/max y. + vCenter = XMVectorLerp(MaxY, MinY, 0.5f); + vRadius = XMVectorScale(DistY, 0.5f); + } + else + { + // Use min/max z. + vCenter = XMVectorLerp(MaxZ, MinZ, 0.5f); + vRadius = XMVectorScale(DistZ, 0.5f); + } + } + + // Add any points not inside the sphere. + for (size_t i = 0; i < Count; ++i) + { + XMVECTOR Point = XMLoadFloat3(reinterpret_cast(reinterpret_cast(pPoints) + i * Stride)); + + XMVECTOR Delta = XMVectorSubtract(Point, vCenter); + + XMVECTOR Dist = XMVector3Length(Delta); + + if (XMVector3Greater(Dist, vRadius)) + { + // Adjust sphere to include the new point. + vRadius = XMVectorScale(XMVectorAdd(vRadius, Dist), 0.5f); + vCenter = XMVectorAdd(vCenter, XMVectorMultiply(XMVectorSubtract(XMVectorReplicate(1.0f), XMVectorDivide(vRadius, Dist)), Delta)); + } + } + + XMStoreFloat3(&Out.Center, vCenter); + XMStoreFloat(&Out.Radius, vRadius); +} + + +//----------------------------------------------------------------------------- +// Create sphere containing frustum +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingSphere::CreateFromFrustum(BoundingSphere& Out, const BoundingFrustum& fr) noexcept +{ + XMFLOAT3 Corners[BoundingFrustum::CORNER_COUNT]; + fr.GetCorners(Corners); + CreateFromPoints(Out, BoundingFrustum::CORNER_COUNT, Corners, sizeof(XMFLOAT3)); +} + + +/**************************************************************************** + * + * BoundingBox + * + ****************************************************************************/ + +//----------------------------------------------------------------------------- +// Transform an axis aligned box by an angle preserving transform. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void XM_CALLCONV BoundingBox::Transform(BoundingBox& Out, FXMMATRIX M) const noexcept +{ + // Load center and extents. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + + // Compute and transform the corners and find new min/max bounds. + XMVECTOR Corner = XMVectorMultiplyAdd(vExtents, g_BoxOffset[0], vCenter); + Corner = XMVector3Transform(Corner, M); + + XMVECTOR Min, Max; + Min = Max = Corner; + + for (size_t i = 1; i < CORNER_COUNT; ++i) + { + Corner = XMVectorMultiplyAdd(vExtents, g_BoxOffset[i], vCenter); + Corner = XMVector3Transform(Corner, M); + + Min = XMVectorMin(Min, Corner); + Max = XMVectorMax(Max, Corner); + } + + // Store center and extents. + XMStoreFloat3(&Out.Center, XMVectorScale(XMVectorAdd(Min, Max), 0.5f)); + XMStoreFloat3(&Out.Extents, XMVectorScale(XMVectorSubtract(Max, Min), 0.5f)); +} + +_Use_decl_annotations_ +inline void XM_CALLCONV BoundingBox::Transform(BoundingBox& Out, float Scale, FXMVECTOR Rotation, FXMVECTOR Translation) const noexcept +{ + assert(DirectX::MathInternal::XMQuaternionIsUnit(Rotation)); + + // Load center and extents. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + + XMVECTOR VectorScale = XMVectorReplicate(Scale); + + // Compute and transform the corners and find new min/max bounds. + XMVECTOR Corner = XMVectorMultiplyAdd(vExtents, g_BoxOffset[0], vCenter); + Corner = XMVectorAdd(XMVector3Rotate(XMVectorMultiply(Corner, VectorScale), Rotation), Translation); + + XMVECTOR Min, Max; + Min = Max = Corner; + + for (size_t i = 1; i < CORNER_COUNT; ++i) + { + Corner = XMVectorMultiplyAdd(vExtents, g_BoxOffset[i], vCenter); + Corner = XMVectorAdd(XMVector3Rotate(XMVectorMultiply(Corner, VectorScale), Rotation), Translation); + + Min = XMVectorMin(Min, Corner); + Max = XMVectorMax(Max, Corner); + } + + // Store center and extents. + XMStoreFloat3(&Out.Center, XMVectorScale(XMVectorAdd(Min, Max), 0.5f)); + XMStoreFloat3(&Out.Extents, XMVectorScale(XMVectorSubtract(Max, Min), 0.5f)); +} + + +//----------------------------------------------------------------------------- +// Get the corner points of the box +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingBox::GetCorners(XMFLOAT3* Corners) const noexcept +{ + assert(Corners != nullptr); + + // Load the box + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + + for (size_t i = 0; i < CORNER_COUNT; ++i) + { + XMVECTOR C = XMVectorMultiplyAdd(vExtents, g_BoxOffset[i], vCenter); + XMStoreFloat3(&Corners[i], C); + } +} + + +//----------------------------------------------------------------------------- +// Point in axis-aligned box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType XM_CALLCONV BoundingBox::Contains(FXMVECTOR Point) const noexcept +{ + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + + return XMVector3InBounds(XMVectorSubtract(Point, vCenter), vExtents) ? CONTAINS : DISJOINT; +} + + +//----------------------------------------------------------------------------- +// Triangle in axis-aligned box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType XM_CALLCONV BoundingBox::Contains(FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2) const noexcept +{ + if (!Intersects(V0, V1, V2)) + return DISJOINT; + + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + + XMVECTOR d = XMVectorAbs(XMVectorSubtract(V0, vCenter)); + XMVECTOR Inside = XMVectorLessOrEqual(d, vExtents); + + d = XMVectorAbs(XMVectorSubtract(V1, vCenter)); + Inside = XMVectorAndInt(Inside, XMVectorLessOrEqual(d, vExtents)); + + d = XMVectorAbs(XMVectorSubtract(V2, vCenter)); + Inside = XMVectorAndInt(Inside, XMVectorLessOrEqual(d, vExtents)); + + return (XMVector3EqualInt(Inside, XMVectorTrueInt())) ? CONTAINS : INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Sphere in axis-aligned box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingBox::Contains(const BoundingSphere& sh) const noexcept +{ + XMVECTOR SphereCenter = XMLoadFloat3(&sh.Center); + XMVECTOR SphereRadius = XMVectorReplicatePtr(&sh.Radius); + + XMVECTOR BoxCenter = XMLoadFloat3(&Center); + XMVECTOR BoxExtents = XMLoadFloat3(&Extents); + + XMVECTOR BoxMin = XMVectorSubtract(BoxCenter, BoxExtents); + XMVECTOR BoxMax = XMVectorAdd(BoxCenter, BoxExtents); + + // Find the distance to the nearest point on the box. + // for each i in (x, y, z) + // if (SphereCenter(i) < BoxMin(i)) d2 += (SphereCenter(i) - BoxMin(i)) ^ 2 + // else if (SphereCenter(i) > BoxMax(i)) d2 += (SphereCenter(i) - BoxMax(i)) ^ 2 + + XMVECTOR d = XMVectorZero(); + + // Compute d for each dimension. + XMVECTOR LessThanMin = XMVectorLess(SphereCenter, BoxMin); + XMVECTOR GreaterThanMax = XMVectorGreater(SphereCenter, BoxMax); + + XMVECTOR MinDelta = XMVectorSubtract(SphereCenter, BoxMin); + XMVECTOR MaxDelta = XMVectorSubtract(SphereCenter, BoxMax); + + // Choose value for each dimension based on the comparison. + d = XMVectorSelect(d, MinDelta, LessThanMin); + d = XMVectorSelect(d, MaxDelta, GreaterThanMax); + + // Use a dot-product to square them and sum them together. + XMVECTOR d2 = XMVector3Dot(d, d); + + if (XMVector3Greater(d2, XMVectorMultiply(SphereRadius, SphereRadius))) + return DISJOINT; + + XMVECTOR InsideAll = XMVectorLessOrEqual(XMVectorAdd(BoxMin, SphereRadius), SphereCenter); + InsideAll = XMVectorAndInt(InsideAll, XMVectorLessOrEqual(SphereCenter, XMVectorSubtract(BoxMax, SphereRadius))); + InsideAll = XMVectorAndInt(InsideAll, XMVectorGreater(XMVectorSubtract(BoxMax, BoxMin), SphereRadius)); + + return (XMVector3EqualInt(InsideAll, XMVectorTrueInt())) ? CONTAINS : INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Axis-aligned box in axis-aligned box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingBox::Contains(const BoundingBox& box) const noexcept +{ + XMVECTOR CenterA = XMLoadFloat3(&Center); + XMVECTOR ExtentsA = XMLoadFloat3(&Extents); + + XMVECTOR CenterB = XMLoadFloat3(&box.Center); + XMVECTOR ExtentsB = XMLoadFloat3(&box.Extents); + + XMVECTOR MinA = XMVectorSubtract(CenterA, ExtentsA); + XMVECTOR MaxA = XMVectorAdd(CenterA, ExtentsA); + + XMVECTOR MinB = XMVectorSubtract(CenterB, ExtentsB); + XMVECTOR MaxB = XMVectorAdd(CenterB, ExtentsB); + + // for each i in (x, y, z) if a_min(i) > b_max(i) or b_min(i) > a_max(i) then return false + XMVECTOR Disjoint = XMVectorOrInt(XMVectorGreater(MinA, MaxB), XMVectorGreater(MinB, MaxA)); + + if (DirectX::MathInternal::XMVector3AnyTrue(Disjoint)) + return DISJOINT; + + // for each i in (x, y, z) if a_min(i) <= b_min(i) and b_max(i) <= a_max(i) then A contains B + XMVECTOR Inside = XMVectorAndInt(XMVectorLessOrEqual(MinA, MinB), XMVectorLessOrEqual(MaxB, MaxA)); + + return DirectX::MathInternal::XMVector3AllTrue(Inside) ? CONTAINS : INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Oriented box in axis-aligned box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingBox::Contains(const BoundingOrientedBox& box) const noexcept +{ + if (!box.Intersects(*this)) + return DISJOINT; + + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + + // Subtract off the AABB center to remove a subtract below + XMVECTOR oCenter = XMVectorSubtract(XMLoadFloat3(&box.Center), vCenter); + + XMVECTOR oExtents = XMLoadFloat3(&box.Extents); + XMVECTOR oOrientation = XMLoadFloat4(&box.Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(oOrientation)); + + XMVECTOR Inside = XMVectorTrueInt(); + + for (size_t i = 0; i < BoundingOrientedBox::CORNER_COUNT; ++i) + { + XMVECTOR C = XMVectorAdd(XMVector3Rotate(XMVectorMultiply(oExtents, g_BoxOffset[i]), oOrientation), oCenter); + XMVECTOR d = XMVectorAbs(C); + Inside = XMVectorAndInt(Inside, XMVectorLessOrEqual(d, vExtents)); + } + + return (XMVector3EqualInt(Inside, XMVectorTrueInt())) ? CONTAINS : INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Frustum in axis-aligned box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingBox::Contains(const BoundingFrustum& fr) const noexcept +{ + if (!fr.Intersects(*this)) + return DISJOINT; + + XMFLOAT3 Corners[BoundingFrustum::CORNER_COUNT]; + fr.GetCorners(Corners); + + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + + XMVECTOR Inside = XMVectorTrueInt(); + + for (size_t i = 0; i < BoundingFrustum::CORNER_COUNT; ++i) + { + XMVECTOR Point = XMLoadFloat3(&Corners[i]); + XMVECTOR d = XMVectorAbs(XMVectorSubtract(Point, vCenter)); + Inside = XMVectorAndInt(Inside, XMVectorLessOrEqual(d, vExtents)); + } + + return (XMVector3EqualInt(Inside, XMVectorTrueInt())) ? CONTAINS : INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Sphere vs axis-aligned box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingBox::Intersects(const BoundingSphere& sh) const noexcept +{ + XMVECTOR SphereCenter = XMLoadFloat3(&sh.Center); + XMVECTOR SphereRadius = XMVectorReplicatePtr(&sh.Radius); + + XMVECTOR BoxCenter = XMLoadFloat3(&Center); + XMVECTOR BoxExtents = XMLoadFloat3(&Extents); + + XMVECTOR BoxMin = XMVectorSubtract(BoxCenter, BoxExtents); + XMVECTOR BoxMax = XMVectorAdd(BoxCenter, BoxExtents); + + // Find the distance to the nearest point on the box. + // for each i in (x, y, z) + // if (SphereCenter(i) < BoxMin(i)) d2 += (SphereCenter(i) - BoxMin(i)) ^ 2 + // else if (SphereCenter(i) > BoxMax(i)) d2 += (SphereCenter(i) - BoxMax(i)) ^ 2 + + XMVECTOR d = XMVectorZero(); + + // Compute d for each dimension. + XMVECTOR LessThanMin = XMVectorLess(SphereCenter, BoxMin); + XMVECTOR GreaterThanMax = XMVectorGreater(SphereCenter, BoxMax); + + XMVECTOR MinDelta = XMVectorSubtract(SphereCenter, BoxMin); + XMVECTOR MaxDelta = XMVectorSubtract(SphereCenter, BoxMax); + + // Choose value for each dimension based on the comparison. + d = XMVectorSelect(d, MinDelta, LessThanMin); + d = XMVectorSelect(d, MaxDelta, GreaterThanMax); + + // Use a dot-product to square them and sum them together. + XMVECTOR d2 = XMVector3Dot(d, d); + + return XMVector3LessOrEqual(d2, XMVectorMultiply(SphereRadius, SphereRadius)); +} + + +//----------------------------------------------------------------------------- +// Axis-aligned box vs. axis-aligned box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingBox::Intersects(const BoundingBox& box) const noexcept +{ + XMVECTOR CenterA = XMLoadFloat3(&Center); + XMVECTOR ExtentsA = XMLoadFloat3(&Extents); + + XMVECTOR CenterB = XMLoadFloat3(&box.Center); + XMVECTOR ExtentsB = XMLoadFloat3(&box.Extents); + + XMVECTOR MinA = XMVectorSubtract(CenterA, ExtentsA); + XMVECTOR MaxA = XMVectorAdd(CenterA, ExtentsA); + + XMVECTOR MinB = XMVectorSubtract(CenterB, ExtentsB); + XMVECTOR MaxB = XMVectorAdd(CenterB, ExtentsB); + + // for each i in (x, y, z) if a_min(i) > b_max(i) or b_min(i) > a_max(i) then return false + XMVECTOR Disjoint = XMVectorOrInt(XMVectorGreater(MinA, MaxB), XMVectorGreater(MinB, MaxA)); + + return !DirectX::MathInternal::XMVector3AnyTrue(Disjoint); +} + + +//----------------------------------------------------------------------------- +// Oriented box vs. axis-aligned box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingBox::Intersects(const BoundingOrientedBox& box) const noexcept +{ + return box.Intersects(*this); +} + + +//----------------------------------------------------------------------------- +// Frustum vs. axis-aligned box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingBox::Intersects(const BoundingFrustum& fr) const noexcept +{ + return fr.Intersects(*this); +} + + +//----------------------------------------------------------------------------- +// Triangle vs. axis aligned box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool XM_CALLCONV BoundingBox::Intersects(FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2) const noexcept +{ + XMVECTOR Zero = XMVectorZero(); + + // Load the box. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + + XMVECTOR BoxMin = XMVectorSubtract(vCenter, vExtents); + XMVECTOR BoxMax = XMVectorAdd(vCenter, vExtents); + + // Test the axes of the box (in effect test the AAB against the minimal AAB + // around the triangle). + XMVECTOR TriMin = XMVectorMin(XMVectorMin(V0, V1), V2); + XMVECTOR TriMax = XMVectorMax(XMVectorMax(V0, V1), V2); + + // for each i in (x, y, z) if a_min(i) > b_max(i) or b_min(i) > a_max(i) then disjoint + XMVECTOR Disjoint = XMVectorOrInt(XMVectorGreater(TriMin, BoxMax), XMVectorGreater(BoxMin, TriMax)); + if (DirectX::MathInternal::XMVector3AnyTrue(Disjoint)) + return false; + + // Test the plane of the triangle. + XMVECTOR Normal = XMVector3Cross(XMVectorSubtract(V1, V0), XMVectorSubtract(V2, V0)); + XMVECTOR Dist = XMVector3Dot(Normal, V0); + + // Assert that the triangle is not degenerate. + assert(!XMVector3Equal(Normal, Zero)); + + // for each i in (x, y, z) if n(i) >= 0 then v_min(i)=b_min(i), v_max(i)=b_max(i) + // else v_min(i)=b_max(i), v_max(i)=b_min(i) + XMVECTOR NormalSelect = XMVectorGreater(Normal, Zero); + XMVECTOR V_Min = XMVectorSelect(BoxMax, BoxMin, NormalSelect); + XMVECTOR V_Max = XMVectorSelect(BoxMin, BoxMax, NormalSelect); + + // if n dot v_min + d > 0 || n dot v_max + d < 0 then disjoint + XMVECTOR MinDist = XMVector3Dot(V_Min, Normal); + XMVECTOR MaxDist = XMVector3Dot(V_Max, Normal); + + XMVECTOR NoIntersection = XMVectorGreater(MinDist, Dist); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(MaxDist, Dist)); + + // Move the box center to zero to simplify the following tests. + XMVECTOR TV0 = XMVectorSubtract(V0, vCenter); + XMVECTOR TV1 = XMVectorSubtract(V1, vCenter); + XMVECTOR TV2 = XMVectorSubtract(V2, vCenter); + + // Test the edge/edge axes (3*3). + XMVECTOR e0 = XMVectorSubtract(TV1, TV0); + XMVECTOR e1 = XMVectorSubtract(TV2, TV1); + XMVECTOR e2 = XMVectorSubtract(TV0, TV2); + + // Make w zero. + e0 = XMVectorInsert<0, 0, 0, 0, 1>(e0, Zero); + e1 = XMVectorInsert<0, 0, 0, 0, 1>(e1, Zero); + e2 = XMVectorInsert<0, 0, 0, 0, 1>(e2, Zero); + + XMVECTOR Axis; + XMVECTOR p0, p1, p2; + XMVECTOR Min, Max; + XMVECTOR Radius; + + // Axis == (1,0,0) x e0 = (0, -e0.z, e0.y) + Axis = XMVectorPermute(e0, XMVectorNegate(e0)); + p0 = XMVector3Dot(TV0, Axis); + // p1 = XMVector3Dot( V1, Axis ); // p1 = p0; + p2 = XMVector3Dot(TV2, Axis); + Min = XMVectorMin(p0, p2); + Max = XMVectorMax(p0, p2); + Radius = XMVector3Dot(vExtents, XMVectorAbs(Axis)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(Min, Radius)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(Max, XMVectorNegate(Radius))); + + // Axis == (1,0,0) x e1 = (0, -e1.z, e1.y) + Axis = XMVectorPermute(e1, XMVectorNegate(e1)); + p0 = XMVector3Dot(TV0, Axis); + p1 = XMVector3Dot(TV1, Axis); + // p2 = XMVector3Dot( V2, Axis ); // p2 = p1; + Min = XMVectorMin(p0, p1); + Max = XMVectorMax(p0, p1); + Radius = XMVector3Dot(vExtents, XMVectorAbs(Axis)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(Min, Radius)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(Max, XMVectorNegate(Radius))); + + // Axis == (1,0,0) x e2 = (0, -e2.z, e2.y) + Axis = XMVectorPermute(e2, XMVectorNegate(e2)); + p0 = XMVector3Dot(TV0, Axis); + p1 = XMVector3Dot(TV1, Axis); + // p2 = XMVector3Dot( V2, Axis ); // p2 = p0; + Min = XMVectorMin(p0, p1); + Max = XMVectorMax(p0, p1); + Radius = XMVector3Dot(vExtents, XMVectorAbs(Axis)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(Min, Radius)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(Max, XMVectorNegate(Radius))); + + // Axis == (0,1,0) x e0 = (e0.z, 0, -e0.x) + Axis = XMVectorPermute(e0, XMVectorNegate(e0)); + p0 = XMVector3Dot(TV0, Axis); + // p1 = XMVector3Dot( V1, Axis ); // p1 = p0; + p2 = XMVector3Dot(TV2, Axis); + Min = XMVectorMin(p0, p2); + Max = XMVectorMax(p0, p2); + Radius = XMVector3Dot(vExtents, XMVectorAbs(Axis)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(Min, Radius)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(Max, XMVectorNegate(Radius))); + + // Axis == (0,1,0) x e1 = (e1.z, 0, -e1.x) + Axis = XMVectorPermute(e1, XMVectorNegate(e1)); + p0 = XMVector3Dot(TV0, Axis); + p1 = XMVector3Dot(TV1, Axis); + // p2 = XMVector3Dot( V2, Axis ); // p2 = p1; + Min = XMVectorMin(p0, p1); + Max = XMVectorMax(p0, p1); + Radius = XMVector3Dot(vExtents, XMVectorAbs(Axis)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(Min, Radius)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(Max, XMVectorNegate(Radius))); + + // Axis == (0,0,1) x e2 = (e2.z, 0, -e2.x) + Axis = XMVectorPermute(e2, XMVectorNegate(e2)); + p0 = XMVector3Dot(TV0, Axis); + p1 = XMVector3Dot(TV1, Axis); + // p2 = XMVector3Dot( V2, Axis ); // p2 = p0; + Min = XMVectorMin(p0, p1); + Max = XMVectorMax(p0, p1); + Radius = XMVector3Dot(vExtents, XMVectorAbs(Axis)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(Min, Radius)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(Max, XMVectorNegate(Radius))); + + // Axis == (0,0,1) x e0 = (-e0.y, e0.x, 0) + Axis = XMVectorPermute(e0, XMVectorNegate(e0)); + p0 = XMVector3Dot(TV0, Axis); + // p1 = XMVector3Dot( V1, Axis ); // p1 = p0; + p2 = XMVector3Dot(TV2, Axis); + Min = XMVectorMin(p0, p2); + Max = XMVectorMax(p0, p2); + Radius = XMVector3Dot(vExtents, XMVectorAbs(Axis)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(Min, Radius)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(Max, XMVectorNegate(Radius))); + + // Axis == (0,0,1) x e1 = (-e1.y, e1.x, 0) + Axis = XMVectorPermute(e1, XMVectorNegate(e1)); + p0 = XMVector3Dot(TV0, Axis); + p1 = XMVector3Dot(TV1, Axis); + // p2 = XMVector3Dot( V2, Axis ); // p2 = p1; + Min = XMVectorMin(p0, p1); + Max = XMVectorMax(p0, p1); + Radius = XMVector3Dot(vExtents, XMVectorAbs(Axis)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(Min, Radius)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(Max, XMVectorNegate(Radius))); + + // Axis == (0,0,1) x e2 = (-e2.y, e2.x, 0) + Axis = XMVectorPermute(e2, XMVectorNegate(e2)); + p0 = XMVector3Dot(TV0, Axis); + p1 = XMVector3Dot(TV1, Axis); + // p2 = XMVector3Dot( V2, Axis ); // p2 = p0; + Min = XMVectorMin(p0, p1); + Max = XMVectorMax(p0, p1); + Radius = XMVector3Dot(vExtents, XMVectorAbs(Axis)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(Min, Radius)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(Max, XMVectorNegate(Radius))); + + return XMVector4NotEqualInt(NoIntersection, XMVectorTrueInt()); +} + + +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline PlaneIntersectionType XM_CALLCONV BoundingBox::Intersects(FXMVECTOR Plane) const noexcept +{ + assert(DirectX::MathInternal::XMPlaneIsUnit(Plane)); + + // Load the box. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + + // Set w of the center to one so we can dot4 with a plane. + vCenter = XMVectorInsert<0, 0, 0, 0, 1>(vCenter, XMVectorSplatOne()); + + XMVECTOR Outside, Inside; + DirectX::MathInternal::FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane, Outside, Inside); + + // If the box is outside any plane it is outside. + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return FRONT; + + // If the box is inside all planes it is inside. + if (XMVector4EqualInt(Inside, XMVectorTrueInt())) + return BACK; + + // The box is not inside all planes or outside a plane it intersects. + return INTERSECTING; +} + + +//----------------------------------------------------------------------------- +// Compute the intersection of a ray (Origin, Direction) with an axis aligned +// box using the slabs method. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool XM_CALLCONV BoundingBox::Intersects(FXMVECTOR Origin, FXMVECTOR Direction, float& Dist) const noexcept +{ + assert(DirectX::MathInternal::XMVector3IsUnit(Direction)); + + // Load the box. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + + // Adjust ray origin to be relative to center of the box. + XMVECTOR TOrigin = XMVectorSubtract(vCenter, Origin); + + // Compute the dot product againt each axis of the box. + // Since the axii are (1,0,0), (0,1,0), (0,0,1) no computation is necessary. + XMVECTOR AxisDotOrigin = TOrigin; + XMVECTOR AxisDotDirection = Direction; + + // if (fabs(AxisDotDirection) <= Epsilon) the ray is nearly parallel to the slab. + XMVECTOR IsParallel = XMVectorLessOrEqual(XMVectorAbs(AxisDotDirection), g_RayEpsilon); + + // Test against all three axii simultaneously. + XMVECTOR InverseAxisDotDirection = XMVectorReciprocal(AxisDotDirection); + XMVECTOR t1 = XMVectorMultiply(XMVectorSubtract(AxisDotOrigin, vExtents), InverseAxisDotDirection); + XMVECTOR t2 = XMVectorMultiply(XMVectorAdd(AxisDotOrigin, vExtents), InverseAxisDotDirection); + + // Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't + // use the results from any directions parallel to the slab. + XMVECTOR t_min = XMVectorSelect(XMVectorMin(t1, t2), g_FltMin, IsParallel); + XMVECTOR t_max = XMVectorSelect(XMVectorMax(t1, t2), g_FltMax, IsParallel); + + // t_min.x = maximum( t_min.x, t_min.y, t_min.z ); + // t_max.x = minimum( t_max.x, t_max.y, t_max.z ); + t_min = XMVectorMax(t_min, XMVectorSplatY(t_min)); // x = max(x,y) + t_min = XMVectorMax(t_min, XMVectorSplatZ(t_min)); // x = max(max(x,y),z) + t_max = XMVectorMin(t_max, XMVectorSplatY(t_max)); // x = min(x,y) + t_max = XMVectorMin(t_max, XMVectorSplatZ(t_max)); // x = min(min(x,y),z) + + // if ( t_min > t_max ) return false; + XMVECTOR NoIntersection = XMVectorGreater(XMVectorSplatX(t_min), XMVectorSplatX(t_max)); + + // if ( t_max < 0.0f ) return false; + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(XMVectorSplatX(t_max), XMVectorZero())); + + // if (IsParallel && (-Extents > AxisDotOrigin || Extents < AxisDotOrigin)) return false; + XMVECTOR ParallelOverlap = XMVectorInBounds(AxisDotOrigin, vExtents); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorAndCInt(IsParallel, ParallelOverlap)); + + if (!DirectX::MathInternal::XMVector3AnyTrue(NoIntersection)) + { + // Store the x-component to *pDist + XMStoreFloat(&Dist, t_min); + return true; + } + + Dist = 0.f; + return false; +} + + +//----------------------------------------------------------------------------- +// Test an axis alinged box vs 6 planes (typically forming a frustum). +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType XM_CALLCONV BoundingBox::ContainedBy( + FXMVECTOR Plane0, FXMVECTOR Plane1, FXMVECTOR Plane2, + GXMVECTOR Plane3, + HXMVECTOR Plane4, HXMVECTOR Plane5) const noexcept +{ + // Load the box. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + + // Set w of the center to one so we can dot4 with a plane. + vCenter = XMVectorInsert<0, 0, 0, 0, 1>(vCenter, XMVectorSplatOne()); + + XMVECTOR Outside, Inside; + + // Test against each plane. + DirectX::MathInternal::FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane0, Outside, Inside); + + XMVECTOR AnyOutside = Outside; + XMVECTOR AllInside = Inside; + + DirectX::MathInternal::FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane1, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane2, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane3, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane4, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane5, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + // If the box is outside any plane it is outside. + if (XMVector4EqualInt(AnyOutside, XMVectorTrueInt())) + return DISJOINT; + + // If the box is inside all planes it is inside. + if (XMVector4EqualInt(AllInside, XMVectorTrueInt())) + return CONTAINS; + + // The box is not inside all planes or outside a plane, it may intersect. + return INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Create axis-aligned box that contains two other bounding boxes +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingBox::CreateMerged(BoundingBox& Out, const BoundingBox& b1, const BoundingBox& b2) noexcept +{ + XMVECTOR b1Center = XMLoadFloat3(&b1.Center); + XMVECTOR b1Extents = XMLoadFloat3(&b1.Extents); + + XMVECTOR b2Center = XMLoadFloat3(&b2.Center); + XMVECTOR b2Extents = XMLoadFloat3(&b2.Extents); + + XMVECTOR Min = XMVectorSubtract(b1Center, b1Extents); + Min = XMVectorMin(Min, XMVectorSubtract(b2Center, b2Extents)); + + XMVECTOR Max = XMVectorAdd(b1Center, b1Extents); + Max = XMVectorMax(Max, XMVectorAdd(b2Center, b2Extents)); + + assert(XMVector3LessOrEqual(Min, Max)); + + XMStoreFloat3(&Out.Center, XMVectorScale(XMVectorAdd(Min, Max), 0.5f)); + XMStoreFloat3(&Out.Extents, XMVectorScale(XMVectorSubtract(Max, Min), 0.5f)); +} + + +//----------------------------------------------------------------------------- +// Create axis-aligned box that contains a bounding sphere +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingBox::CreateFromSphere(BoundingBox& Out, const BoundingSphere& sh) noexcept +{ + XMVECTOR spCenter = XMLoadFloat3(&sh.Center); + XMVECTOR shRadius = XMVectorReplicatePtr(&sh.Radius); + + XMVECTOR Min = XMVectorSubtract(spCenter, shRadius); + XMVECTOR Max = XMVectorAdd(spCenter, shRadius); + + assert(XMVector3LessOrEqual(Min, Max)); + + XMStoreFloat3(&Out.Center, XMVectorScale(XMVectorAdd(Min, Max), 0.5f)); + XMStoreFloat3(&Out.Extents, XMVectorScale(XMVectorSubtract(Max, Min), 0.5f)); +} + + +//----------------------------------------------------------------------------- +// Create axis-aligned box from min/max points +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void XM_CALLCONV BoundingBox::CreateFromPoints(BoundingBox& Out, FXMVECTOR pt1, FXMVECTOR pt2) noexcept +{ + XMVECTOR Min = XMVectorMin(pt1, pt2); + XMVECTOR Max = XMVectorMax(pt1, pt2); + + // Store center and extents. + XMStoreFloat3(&Out.Center, XMVectorScale(XMVectorAdd(Min, Max), 0.5f)); + XMStoreFloat3(&Out.Extents, XMVectorScale(XMVectorSubtract(Max, Min), 0.5f)); +} + + +//----------------------------------------------------------------------------- +// Find the minimum axis aligned bounding box containing a set of points. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingBox::CreateFromPoints(BoundingBox& Out, size_t Count, const XMFLOAT3* pPoints, size_t Stride) noexcept +{ + assert(Count > 0); + assert(pPoints); + + // Find the minimum and maximum x, y, and z + XMVECTOR vMin, vMax; + + vMin = vMax = XMLoadFloat3(pPoints); + + for (size_t i = 1; i < Count; ++i) + { + XMVECTOR Point = XMLoadFloat3(reinterpret_cast(reinterpret_cast(pPoints) + i * Stride)); + + vMin = XMVectorMin(vMin, Point); + vMax = XMVectorMax(vMax, Point); + } + + // Store center and extents. + XMStoreFloat3(&Out.Center, XMVectorScale(XMVectorAdd(vMin, vMax), 0.5f)); + XMStoreFloat3(&Out.Extents, XMVectorScale(XMVectorSubtract(vMax, vMin), 0.5f)); +} + + +/**************************************************************************** + * + * BoundingOrientedBox + * + ****************************************************************************/ + +//----------------------------------------------------------------------------- +// Transform an oriented box by an angle preserving transform. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void XM_CALLCONV BoundingOrientedBox::Transform(BoundingOrientedBox& Out, FXMMATRIX M) const noexcept +{ + // Load the box. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + // Composite the box rotation and the transform rotation. + XMMATRIX nM; + nM.r[0] = XMVector3Normalize(M.r[0]); + nM.r[1] = XMVector3Normalize(M.r[1]); + nM.r[2] = XMVector3Normalize(M.r[2]); + nM.r[3] = g_XMIdentityR3; + XMVECTOR Rotation = XMQuaternionRotationMatrix(nM); + vOrientation = XMQuaternionMultiply(vOrientation, Rotation); + + // Transform the center. + vCenter = XMVector3Transform(vCenter, M); + + // Scale the box extents. + XMVECTOR dX = XMVector3Length(M.r[0]); + XMVECTOR dY = XMVector3Length(M.r[1]); + XMVECTOR dZ = XMVector3Length(M.r[2]); + + XMVECTOR VectorScale = XMVectorSelect(dY, dX, g_XMSelect1000); + VectorScale = XMVectorSelect(dZ, VectorScale, g_XMSelect1100); + vExtents = XMVectorMultiply(vExtents, VectorScale); + + // Store the box. + XMStoreFloat3(&Out.Center, vCenter); + XMStoreFloat3(&Out.Extents, vExtents); + XMStoreFloat4(&Out.Orientation, vOrientation); +} + +_Use_decl_annotations_ +inline void XM_CALLCONV BoundingOrientedBox::Transform(BoundingOrientedBox& Out, float Scale, FXMVECTOR Rotation, FXMVECTOR Translation) const noexcept +{ + assert(DirectX::MathInternal::XMQuaternionIsUnit(Rotation)); + + // Load the box. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + // Composite the box rotation and the transform rotation. + vOrientation = XMQuaternionMultiply(vOrientation, Rotation); + + // Transform the center. + XMVECTOR VectorScale = XMVectorReplicate(Scale); + vCenter = XMVectorAdd(XMVector3Rotate(XMVectorMultiply(vCenter, VectorScale), Rotation), Translation); + + // Scale the box extents. + vExtents = XMVectorMultiply(vExtents, VectorScale); + + // Store the box. + XMStoreFloat3(&Out.Center, vCenter); + XMStoreFloat3(&Out.Extents, vExtents); + XMStoreFloat4(&Out.Orientation, vOrientation); +} + + +//----------------------------------------------------------------------------- +// Get the corner points of the box +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingOrientedBox::GetCorners(XMFLOAT3* Corners) const noexcept +{ + assert(Corners != nullptr); + + // Load the box + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + for (size_t i = 0; i < CORNER_COUNT; ++i) + { + XMVECTOR C = XMVectorAdd(XMVector3Rotate(XMVectorMultiply(vExtents, g_BoxOffset[i]), vOrientation), vCenter); + XMStoreFloat3(&Corners[i], C); + } +} + + +//----------------------------------------------------------------------------- +// Point in oriented box test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType XM_CALLCONV BoundingOrientedBox::Contains(FXMVECTOR Point) const noexcept +{ + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + // Transform the point to be local to the box. + XMVECTOR TPoint = XMVector3InverseRotate(XMVectorSubtract(Point, vCenter), vOrientation); + + return XMVector3InBounds(TPoint, vExtents) ? CONTAINS : DISJOINT; +} + + +//----------------------------------------------------------------------------- +// Triangle in oriented bounding box +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType XM_CALLCONV BoundingOrientedBox::Contains(FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2) const noexcept +{ + // Load the box center & orientation. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + // Transform the triangle vertices into the space of the box. + XMVECTOR TV0 = XMVector3InverseRotate(XMVectorSubtract(V0, vCenter), vOrientation); + XMVECTOR TV1 = XMVector3InverseRotate(XMVectorSubtract(V1, vCenter), vOrientation); + XMVECTOR TV2 = XMVector3InverseRotate(XMVectorSubtract(V2, vCenter), vOrientation); + + BoundingBox box; + box.Center = XMFLOAT3(0.0f, 0.0f, 0.0f); + box.Extents = Extents; + + // Use the triangle vs axis aligned box intersection routine. + return box.Contains(TV0, TV1, TV2); +} + + +//----------------------------------------------------------------------------- +// Sphere in oriented bounding box +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingOrientedBox::Contains(const BoundingSphere& sh) const noexcept +{ + XMVECTOR SphereCenter = XMLoadFloat3(&sh.Center); + XMVECTOR SphereRadius = XMVectorReplicatePtr(&sh.Radius); + + XMVECTOR BoxCenter = XMLoadFloat3(&Center); + XMVECTOR BoxExtents = XMLoadFloat3(&Extents); + XMVECTOR BoxOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(BoxOrientation)); + + // Transform the center of the sphere to be local to the box. + // BoxMin = -BoxExtents + // BoxMax = +BoxExtents + SphereCenter = XMVector3InverseRotate(XMVectorSubtract(SphereCenter, BoxCenter), BoxOrientation); + + // Find the distance to the nearest point on the box. + // for each i in (x, y, z) + // if (SphereCenter(i) < BoxMin(i)) d2 += (SphereCenter(i) - BoxMin(i)) ^ 2 + // else if (SphereCenter(i) > BoxMax(i)) d2 += (SphereCenter(i) - BoxMax(i)) ^ 2 + + XMVECTOR d = XMVectorZero(); + + // Compute d for each dimension. + XMVECTOR LessThanMin = XMVectorLess(SphereCenter, XMVectorNegate(BoxExtents)); + XMVECTOR GreaterThanMax = XMVectorGreater(SphereCenter, BoxExtents); + + XMVECTOR MinDelta = XMVectorAdd(SphereCenter, BoxExtents); + XMVECTOR MaxDelta = XMVectorSubtract(SphereCenter, BoxExtents); + + // Choose value for each dimension based on the comparison. + d = XMVectorSelect(d, MinDelta, LessThanMin); + d = XMVectorSelect(d, MaxDelta, GreaterThanMax); + + // Use a dot-product to square them and sum them together. + XMVECTOR d2 = XMVector3Dot(d, d); + XMVECTOR SphereRadiusSq = XMVectorMultiply(SphereRadius, SphereRadius); + + if (XMVector4Greater(d2, SphereRadiusSq)) + return DISJOINT; + + // See if we are completely inside the box + XMVECTOR SMin = XMVectorSubtract(SphereCenter, SphereRadius); + XMVECTOR SMax = XMVectorAdd(SphereCenter, SphereRadius); + + return (XMVector3InBounds(SMin, BoxExtents) && XMVector3InBounds(SMax, BoxExtents)) ? CONTAINS : INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Axis aligned box vs. oriented box. Constructs an oriented box and uses +// the oriented box vs. oriented box test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingOrientedBox::Contains(const BoundingBox& box) const noexcept +{ + // Make the axis aligned box oriented and do an OBB vs OBB test. + BoundingOrientedBox obox(box.Center, box.Extents, XMFLOAT4(0.f, 0.f, 0.f, 1.f)); + return Contains(obox); +} + + +//----------------------------------------------------------------------------- +// Oriented bounding box in oriented bounding box +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingOrientedBox::Contains(const BoundingOrientedBox& box) const noexcept +{ + if (!Intersects(box)) + return DISJOINT; + + // Load the boxes + XMVECTOR aCenter = XMLoadFloat3(&Center); + XMVECTOR aExtents = XMLoadFloat3(&Extents); + XMVECTOR aOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(aOrientation)); + + XMVECTOR bCenter = XMLoadFloat3(&box.Center); + XMVECTOR bExtents = XMLoadFloat3(&box.Extents); + XMVECTOR bOrientation = XMLoadFloat4(&box.Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(bOrientation)); + + XMVECTOR offset = XMVectorSubtract(bCenter, aCenter); + + for (size_t i = 0; i < CORNER_COUNT; ++i) + { + // Cb = rotate( bExtents * corneroffset[i], bOrientation ) + bcenter + // Ca = invrotate( Cb - aCenter, aOrientation ) + + XMVECTOR C = XMVectorAdd(XMVector3Rotate(XMVectorMultiply(bExtents, g_BoxOffset[i]), bOrientation), offset); + C = XMVector3InverseRotate(C, aOrientation); + + if (!XMVector3InBounds(C, aExtents)) + return INTERSECTS; + } + + return CONTAINS; +} + + +//----------------------------------------------------------------------------- +// Frustum in oriented bounding box +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingOrientedBox::Contains(const BoundingFrustum& fr) const noexcept +{ + if (!fr.Intersects(*this)) + return DISJOINT; + + XMFLOAT3 Corners[BoundingFrustum::CORNER_COUNT]; + fr.GetCorners(Corners); + + // Load the box + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + for (size_t i = 0; i < BoundingFrustum::CORNER_COUNT; ++i) + { + XMVECTOR C = XMVector3InverseRotate(XMVectorSubtract(XMLoadFloat3(&Corners[i]), vCenter), vOrientation); + + if (!XMVector3InBounds(C, vExtents)) + return INTERSECTS; + } + + return CONTAINS; +} + + +//----------------------------------------------------------------------------- +// Sphere vs. oriented box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingOrientedBox::Intersects(const BoundingSphere& sh) const noexcept +{ + XMVECTOR SphereCenter = XMLoadFloat3(&sh.Center); + XMVECTOR SphereRadius = XMVectorReplicatePtr(&sh.Radius); + + XMVECTOR BoxCenter = XMLoadFloat3(&Center); + XMVECTOR BoxExtents = XMLoadFloat3(&Extents); + XMVECTOR BoxOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(BoxOrientation)); + + // Transform the center of the sphere to be local to the box. + // BoxMin = -BoxExtents + // BoxMax = +BoxExtents + SphereCenter = XMVector3InverseRotate(XMVectorSubtract(SphereCenter, BoxCenter), BoxOrientation); + + // Find the distance to the nearest point on the box. + // for each i in (x, y, z) + // if (SphereCenter(i) < BoxMin(i)) d2 += (SphereCenter(i) - BoxMin(i)) ^ 2 + // else if (SphereCenter(i) > BoxMax(i)) d2 += (SphereCenter(i) - BoxMax(i)) ^ 2 + + XMVECTOR d = XMVectorZero(); + + // Compute d for each dimension. + XMVECTOR LessThanMin = XMVectorLess(SphereCenter, XMVectorNegate(BoxExtents)); + XMVECTOR GreaterThanMax = XMVectorGreater(SphereCenter, BoxExtents); + + XMVECTOR MinDelta = XMVectorAdd(SphereCenter, BoxExtents); + XMVECTOR MaxDelta = XMVectorSubtract(SphereCenter, BoxExtents); + + // Choose value for each dimension based on the comparison. + d = XMVectorSelect(d, MinDelta, LessThanMin); + d = XMVectorSelect(d, MaxDelta, GreaterThanMax); + + // Use a dot-product to square them and sum them together. + XMVECTOR d2 = XMVector3Dot(d, d); + + return XMVector4LessOrEqual(d2, XMVectorMultiply(SphereRadius, SphereRadius)) ? true : false; +} + + +//----------------------------------------------------------------------------- +// Axis aligned box vs. oriented box. Constructs an oriented box and uses +// the oriented box vs. oriented box test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingOrientedBox::Intersects(const BoundingBox& box) const noexcept +{ + // Make the axis aligned box oriented and do an OBB vs OBB test. + BoundingOrientedBox obox(box.Center, box.Extents, XMFLOAT4(0.f, 0.f, 0.f, 1.f)); + return Intersects(obox); +} + + +//----------------------------------------------------------------------------- +// Fast oriented box / oriented box intersection test using the separating axis +// theorem. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingOrientedBox::Intersects(const BoundingOrientedBox& box) const noexcept +{ + // Build the 3x3 rotation matrix that defines the orientation of B relative to A. + XMVECTOR A_quat = XMLoadFloat4(&Orientation); + XMVECTOR B_quat = XMLoadFloat4(&box.Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(A_quat)); + assert(DirectX::MathInternal::XMQuaternionIsUnit(B_quat)); + + XMVECTOR Q = XMQuaternionMultiply(A_quat, XMQuaternionConjugate(B_quat)); + XMMATRIX R = XMMatrixRotationQuaternion(Q); + + // Compute the translation of B relative to A. + XMVECTOR A_cent = XMLoadFloat3(&Center); + XMVECTOR B_cent = XMLoadFloat3(&box.Center); + XMVECTOR t = XMVector3InverseRotate(XMVectorSubtract(B_cent, A_cent), A_quat); + + // + // h(A) = extents of A. + // h(B) = extents of B. + // + // a(u) = axes of A = (1,0,0), (0,1,0), (0,0,1) + // b(u) = axes of B relative to A = (r00,r10,r20), (r01,r11,r21), (r02,r12,r22) + // + // For each possible separating axis l: + // d(A) = sum (for i = u,v,w) h(A)(i) * abs( a(i) dot l ) + // d(B) = sum (for i = u,v,w) h(B)(i) * abs( b(i) dot l ) + // if abs( t dot l ) > d(A) + d(B) then disjoint + // + + // Load extents of A and B. + XMVECTOR h_A = XMLoadFloat3(&Extents); + XMVECTOR h_B = XMLoadFloat3(&box.Extents); + + // Rows. Note R[0,1,2]X.w = 0. + XMVECTOR R0X = R.r[0]; + XMVECTOR R1X = R.r[1]; + XMVECTOR R2X = R.r[2]; + + R = XMMatrixTranspose(R); + + // Columns. Note RX[0,1,2].w = 0. + XMVECTOR RX0 = R.r[0]; + XMVECTOR RX1 = R.r[1]; + XMVECTOR RX2 = R.r[2]; + + // Absolute value of rows. + XMVECTOR AR0X = XMVectorAbs(R0X); + XMVECTOR AR1X = XMVectorAbs(R1X); + XMVECTOR AR2X = XMVectorAbs(R2X); + + // Absolute value of columns. + XMVECTOR ARX0 = XMVectorAbs(RX0); + XMVECTOR ARX1 = XMVectorAbs(RX1); + XMVECTOR ARX2 = XMVectorAbs(RX2); + + // Test each of the 15 possible seperating axii. + XMVECTOR d, d_A, d_B; + + // l = a(u) = (1, 0, 0) + // t dot l = t.x + // d(A) = h(A).x + // d(B) = h(B) dot abs(r00, r01, r02) + d = XMVectorSplatX(t); + d_A = XMVectorSplatX(h_A); + d_B = XMVector3Dot(h_B, AR0X); + XMVECTOR NoIntersection = XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B)); + + // l = a(v) = (0, 1, 0) + // t dot l = t.y + // d(A) = h(A).y + // d(B) = h(B) dot abs(r10, r11, r12) + d = XMVectorSplatY(t); + d_A = XMVectorSplatY(h_A); + d_B = XMVector3Dot(h_B, AR1X); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = a(w) = (0, 0, 1) + // t dot l = t.z + // d(A) = h(A).z + // d(B) = h(B) dot abs(r20, r21, r22) + d = XMVectorSplatZ(t); + d_A = XMVectorSplatZ(h_A); + d_B = XMVector3Dot(h_B, AR2X); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = b(u) = (r00, r10, r20) + // d(A) = h(A) dot abs(r00, r10, r20) + // d(B) = h(B).x + d = XMVector3Dot(t, RX0); + d_A = XMVector3Dot(h_A, ARX0); + d_B = XMVectorSplatX(h_B); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = b(v) = (r01, r11, r21) + // d(A) = h(A) dot abs(r01, r11, r21) + // d(B) = h(B).y + d = XMVector3Dot(t, RX1); + d_A = XMVector3Dot(h_A, ARX1); + d_B = XMVectorSplatY(h_B); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = b(w) = (r02, r12, r22) + // d(A) = h(A) dot abs(r02, r12, r22) + // d(B) = h(B).z + d = XMVector3Dot(t, RX2); + d_A = XMVector3Dot(h_A, ARX2); + d_B = XMVectorSplatZ(h_B); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = a(u) x b(u) = (0, -r20, r10) + // d(A) = h(A) dot abs(0, r20, r10) + // d(B) = h(B) dot abs(0, r02, r01) + d = XMVector3Dot(t, XMVectorPermute(RX0, XMVectorNegate(RX0))); + d_A = XMVector3Dot(h_A, XMVectorSwizzle(ARX0)); + d_B = XMVector3Dot(h_B, XMVectorSwizzle(AR0X)); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = a(u) x b(v) = (0, -r21, r11) + // d(A) = h(A) dot abs(0, r21, r11) + // d(B) = h(B) dot abs(r02, 0, r00) + d = XMVector3Dot(t, XMVectorPermute(RX1, XMVectorNegate(RX1))); + d_A = XMVector3Dot(h_A, XMVectorSwizzle(ARX1)); + d_B = XMVector3Dot(h_B, XMVectorSwizzle(AR0X)); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = a(u) x b(w) = (0, -r22, r12) + // d(A) = h(A) dot abs(0, r22, r12) + // d(B) = h(B) dot abs(r01, r00, 0) + d = XMVector3Dot(t, XMVectorPermute(RX2, XMVectorNegate(RX2))); + d_A = XMVector3Dot(h_A, XMVectorSwizzle(ARX2)); + d_B = XMVector3Dot(h_B, XMVectorSwizzle(AR0X)); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = a(v) x b(u) = (r20, 0, -r00) + // d(A) = h(A) dot abs(r20, 0, r00) + // d(B) = h(B) dot abs(0, r12, r11) + d = XMVector3Dot(t, XMVectorPermute(RX0, XMVectorNegate(RX0))); + d_A = XMVector3Dot(h_A, XMVectorSwizzle(ARX0)); + d_B = XMVector3Dot(h_B, XMVectorSwizzle(AR1X)); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = a(v) x b(v) = (r21, 0, -r01) + // d(A) = h(A) dot abs(r21, 0, r01) + // d(B) = h(B) dot abs(r12, 0, r10) + d = XMVector3Dot(t, XMVectorPermute(RX1, XMVectorNegate(RX1))); + d_A = XMVector3Dot(h_A, XMVectorSwizzle(ARX1)); + d_B = XMVector3Dot(h_B, XMVectorSwizzle(AR1X)); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = a(v) x b(w) = (r22, 0, -r02) + // d(A) = h(A) dot abs(r22, 0, r02) + // d(B) = h(B) dot abs(r11, r10, 0) + d = XMVector3Dot(t, XMVectorPermute(RX2, XMVectorNegate(RX2))); + d_A = XMVector3Dot(h_A, XMVectorSwizzle(ARX2)); + d_B = XMVector3Dot(h_B, XMVectorSwizzle(AR1X)); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = a(w) x b(u) = (-r10, r00, 0) + // d(A) = h(A) dot abs(r10, r00, 0) + // d(B) = h(B) dot abs(0, r22, r21) + d = XMVector3Dot(t, XMVectorPermute(RX0, XMVectorNegate(RX0))); + d_A = XMVector3Dot(h_A, XMVectorSwizzle(ARX0)); + d_B = XMVector3Dot(h_B, XMVectorSwizzle(AR2X)); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = a(w) x b(v) = (-r11, r01, 0) + // d(A) = h(A) dot abs(r11, r01, 0) + // d(B) = h(B) dot abs(r22, 0, r20) + d = XMVector3Dot(t, XMVectorPermute(RX1, XMVectorNegate(RX1))); + d_A = XMVector3Dot(h_A, XMVectorSwizzle(ARX1)); + d_B = XMVector3Dot(h_B, XMVectorSwizzle(AR2X)); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // l = a(w) x b(w) = (-r12, r02, 0) + // d(A) = h(A) dot abs(r12, r02, 0) + // d(B) = h(B) dot abs(r21, r20, 0) + d = XMVector3Dot(t, XMVectorPermute(RX2, XMVectorNegate(RX2))); + d_A = XMVector3Dot(h_A, XMVectorSwizzle(ARX2)); + d_B = XMVector3Dot(h_B, XMVectorSwizzle(AR2X)); + NoIntersection = XMVectorOrInt(NoIntersection, + XMVectorGreater(XMVectorAbs(d), XMVectorAdd(d_A, d_B))); + + // No seperating axis found, boxes must intersect. + return XMVector4NotEqualInt(NoIntersection, XMVectorTrueInt()) ? true : false; +} + + +//----------------------------------------------------------------------------- +// Frustum vs. oriented box test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingOrientedBox::Intersects(const BoundingFrustum& fr) const noexcept +{ + return fr.Intersects(*this); +} + + +//----------------------------------------------------------------------------- +// Triangle vs. oriented box test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool XM_CALLCONV BoundingOrientedBox::Intersects(FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2) const noexcept +{ + // Load the box center & orientation. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + // Transform the triangle vertices into the space of the box. + XMVECTOR TV0 = XMVector3InverseRotate(XMVectorSubtract(V0, vCenter), vOrientation); + XMVECTOR TV1 = XMVector3InverseRotate(XMVectorSubtract(V1, vCenter), vOrientation); + XMVECTOR TV2 = XMVector3InverseRotate(XMVectorSubtract(V2, vCenter), vOrientation); + + BoundingBox box; + box.Center = XMFLOAT3(0.0f, 0.0f, 0.0f); + box.Extents = Extents; + + // Use the triangle vs axis aligned box intersection routine. + return box.Intersects(TV0, TV1, TV2); +} + + +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline PlaneIntersectionType XM_CALLCONV BoundingOrientedBox::Intersects(FXMVECTOR Plane) const noexcept +{ + assert(DirectX::MathInternal::XMPlaneIsUnit(Plane)); + + // Load the box. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + XMVECTOR BoxOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(BoxOrientation)); + + // Set w of the center to one so we can dot4 with a plane. + vCenter = XMVectorInsert<0, 0, 0, 0, 1>(vCenter, XMVectorSplatOne()); + + // Build the 3x3 rotation matrix that defines the box axes. + XMMATRIX R = XMMatrixRotationQuaternion(BoxOrientation); + + XMVECTOR Outside, Inside; + DirectX::MathInternal::FastIntersectOrientedBoxPlane(vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane, Outside, Inside); + + // If the box is outside any plane it is outside. + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return FRONT; + + // If the box is inside all planes it is inside. + if (XMVector4EqualInt(Inside, XMVectorTrueInt())) + return BACK; + + // The box is not inside all planes or outside a plane it intersects. + return INTERSECTING; +} + + +//----------------------------------------------------------------------------- +// Compute the intersection of a ray (Origin, Direction) with an oriented box +// using the slabs method. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool XM_CALLCONV BoundingOrientedBox::Intersects(FXMVECTOR Origin, FXMVECTOR Direction, float& Dist) const noexcept +{ + assert(DirectX::MathInternal::XMVector3IsUnit(Direction)); + + static const XMVECTORU32 SelectY = { { { XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_0 } } }; + static const XMVECTORU32 SelectZ = { { { XM_SELECT_0, XM_SELECT_0, XM_SELECT_1, XM_SELECT_0 } } }; + + // Load the box. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + // Get the boxes normalized side directions. + XMMATRIX R = XMMatrixRotationQuaternion(vOrientation); + + // Adjust ray origin to be relative to center of the box. + XMVECTOR TOrigin = XMVectorSubtract(vCenter, Origin); + + // Compute the dot product againt each axis of the box. + XMVECTOR AxisDotOrigin = XMVector3Dot(R.r[0], TOrigin); + AxisDotOrigin = XMVectorSelect(AxisDotOrigin, XMVector3Dot(R.r[1], TOrigin), SelectY); + AxisDotOrigin = XMVectorSelect(AxisDotOrigin, XMVector3Dot(R.r[2], TOrigin), SelectZ); + + XMVECTOR AxisDotDirection = XMVector3Dot(R.r[0], Direction); + AxisDotDirection = XMVectorSelect(AxisDotDirection, XMVector3Dot(R.r[1], Direction), SelectY); + AxisDotDirection = XMVectorSelect(AxisDotDirection, XMVector3Dot(R.r[2], Direction), SelectZ); + + // if (fabs(AxisDotDirection) <= Epsilon) the ray is nearly parallel to the slab. + XMVECTOR IsParallel = XMVectorLessOrEqual(XMVectorAbs(AxisDotDirection), g_RayEpsilon); + + // Test against all three axes simultaneously. + XMVECTOR InverseAxisDotDirection = XMVectorReciprocal(AxisDotDirection); + XMVECTOR t1 = XMVectorMultiply(XMVectorSubtract(AxisDotOrigin, vExtents), InverseAxisDotDirection); + XMVECTOR t2 = XMVectorMultiply(XMVectorAdd(AxisDotOrigin, vExtents), InverseAxisDotDirection); + + // Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't + // use the results from any directions parallel to the slab. + XMVECTOR t_min = XMVectorSelect(XMVectorMin(t1, t2), g_FltMin, IsParallel); + XMVECTOR t_max = XMVectorSelect(XMVectorMax(t1, t2), g_FltMax, IsParallel); + + // t_min.x = maximum( t_min.x, t_min.y, t_min.z ); + // t_max.x = minimum( t_max.x, t_max.y, t_max.z ); + t_min = XMVectorMax(t_min, XMVectorSplatY(t_min)); // x = max(x,y) + t_min = XMVectorMax(t_min, XMVectorSplatZ(t_min)); // x = max(max(x,y),z) + t_max = XMVectorMin(t_max, XMVectorSplatY(t_max)); // x = min(x,y) + t_max = XMVectorMin(t_max, XMVectorSplatZ(t_max)); // x = min(min(x,y),z) + + // if ( t_min > t_max ) return false; + XMVECTOR NoIntersection = XMVectorGreater(XMVectorSplatX(t_min), XMVectorSplatX(t_max)); + + // if ( t_max < 0.0f ) return false; + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(XMVectorSplatX(t_max), XMVectorZero())); + + // if (IsParallel && (-Extents > AxisDotOrigin || Extents < AxisDotOrigin)) return false; + XMVECTOR ParallelOverlap = XMVectorInBounds(AxisDotOrigin, vExtents); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorAndCInt(IsParallel, ParallelOverlap)); + + if (!DirectX::MathInternal::XMVector3AnyTrue(NoIntersection)) + { + // Store the x-component to *pDist + XMStoreFloat(&Dist, t_min); + return true; + } + + Dist = 0.f; + return false; +} + + +//----------------------------------------------------------------------------- +// Test an oriented box vs 6 planes (typically forming a frustum). +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType XM_CALLCONV BoundingOrientedBox::ContainedBy( + FXMVECTOR Plane0, FXMVECTOR Plane1, FXMVECTOR Plane2, + GXMVECTOR Plane3, + HXMVECTOR Plane4, HXMVECTOR Plane5) const noexcept +{ + // Load the box. + XMVECTOR vCenter = XMLoadFloat3(&Center); + XMVECTOR vExtents = XMLoadFloat3(&Extents); + XMVECTOR BoxOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(BoxOrientation)); + + // Set w of the center to one so we can dot4 with a plane. + vCenter = XMVectorInsert<0, 0, 0, 0, 1>(vCenter, XMVectorSplatOne()); + + // Build the 3x3 rotation matrix that defines the box axes. + XMMATRIX R = XMMatrixRotationQuaternion(BoxOrientation); + + XMVECTOR Outside, Inside; + + // Test against each plane. + DirectX::MathInternal::FastIntersectOrientedBoxPlane(vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane0, Outside, Inside); + + XMVECTOR AnyOutside = Outside; + XMVECTOR AllInside = Inside; + + DirectX::MathInternal::FastIntersectOrientedBoxPlane(vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane1, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectOrientedBoxPlane(vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane2, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectOrientedBoxPlane(vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane3, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectOrientedBoxPlane(vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane4, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectOrientedBoxPlane(vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane5, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + // If the box is outside any plane it is outside. + if (XMVector4EqualInt(AnyOutside, XMVectorTrueInt())) + return DISJOINT; + + // If the box is inside all planes it is inside. + if (XMVector4EqualInt(AllInside, XMVectorTrueInt())) + return CONTAINS; + + // The box is not inside all planes or outside a plane, it may intersect. + return INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Create oriented bounding box from axis-aligned bounding box +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingOrientedBox::CreateFromBoundingBox(BoundingOrientedBox& Out, const BoundingBox& box) noexcept +{ + Out.Center = box.Center; + Out.Extents = box.Extents; + Out.Orientation = XMFLOAT4(0.f, 0.f, 0.f, 1.f); +} + + +//----------------------------------------------------------------------------- +// Find the approximate minimum oriented bounding box containing a set of +// points. Exact computation of minimum oriented bounding box is possible but +// is slower and requires a more complex algorithm. +// The algorithm works by computing the inertia tensor of the points and then +// using the eigenvectors of the intertia tensor as the axes of the box. +// Computing the intertia tensor of the convex hull of the points will usually +// result in better bounding box but the computation is more complex. +// Exact computation of the minimum oriented bounding box is possible but the +// best know algorithm is O(N^3) and is significanly more complex to implement. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingOrientedBox::CreateFromPoints(BoundingOrientedBox& Out, size_t Count, const XMFLOAT3* pPoints, size_t Stride) noexcept +{ + assert(Count > 0); + assert(pPoints != nullptr); + + XMVECTOR CenterOfMass = XMVectorZero(); + + // Compute the center of mass and inertia tensor of the points. + for (size_t i = 0; i < Count; ++i) + { + XMVECTOR Point = XMLoadFloat3(reinterpret_cast(reinterpret_cast(pPoints) + i * Stride)); + + CenterOfMass = XMVectorAdd(CenterOfMass, Point); + } + + CenterOfMass = XMVectorMultiply(CenterOfMass, XMVectorReciprocal(XMVectorReplicate(float(Count)))); + + // Compute the inertia tensor of the points around the center of mass. + // Using the center of mass is not strictly necessary, but will hopefully + // improve the stability of finding the eigenvectors. + XMVECTOR XX_YY_ZZ = XMVectorZero(); + XMVECTOR XY_XZ_YZ = XMVectorZero(); + + for (size_t i = 0; i < Count; ++i) + { + XMVECTOR Point = XMVectorSubtract(XMLoadFloat3(reinterpret_cast(reinterpret_cast(pPoints) + i * Stride)), CenterOfMass); + + XX_YY_ZZ = XMVectorAdd(XX_YY_ZZ, XMVectorMultiply(Point, Point)); + + XMVECTOR XXY = XMVectorSwizzle(Point); + XMVECTOR YZZ = XMVectorSwizzle(Point); + + XY_XZ_YZ = XMVectorAdd(XY_XZ_YZ, XMVectorMultiply(XXY, YZZ)); + } + + XMVECTOR v1, v2, v3; + + // Compute the eigenvectors of the inertia tensor. + DirectX::MathInternal::CalculateEigenVectorsFromCovarianceMatrix(XMVectorGetX(XX_YY_ZZ), XMVectorGetY(XX_YY_ZZ), + XMVectorGetZ(XX_YY_ZZ), + XMVectorGetX(XY_XZ_YZ), XMVectorGetY(XY_XZ_YZ), + XMVectorGetZ(XY_XZ_YZ), + &v1, &v2, &v3); + + // Put them in a matrix. + XMMATRIX R; + + R.r[0] = XMVectorSetW(v1, 0.f); + R.r[1] = XMVectorSetW(v2, 0.f); + R.r[2] = XMVectorSetW(v3, 0.f); + R.r[3] = g_XMIdentityR3.v; + + // Multiply by -1 to convert the matrix into a right handed coordinate + // system (Det ~= 1) in case the eigenvectors form a left handed + // coordinate system (Det ~= -1) because XMQuaternionRotationMatrix only + // works on right handed matrices. + XMVECTOR Det = XMMatrixDeterminant(R); + + if (XMVector4Less(Det, XMVectorZero())) + { + R.r[0] = XMVectorMultiply(R.r[0], g_XMNegativeOne.v); + R.r[1] = XMVectorMultiply(R.r[1], g_XMNegativeOne.v); + R.r[2] = XMVectorMultiply(R.r[2], g_XMNegativeOne.v); + } + + // Get the rotation quaternion from the matrix. + XMVECTOR vOrientation = XMQuaternionRotationMatrix(R); + + // Make sure it is normal (in case the vectors are slightly non-orthogonal). + vOrientation = XMQuaternionNormalize(vOrientation); + + // Rebuild the rotation matrix from the quaternion. + R = XMMatrixRotationQuaternion(vOrientation); + + // Build the rotation into the rotated space. + XMMATRIX InverseR = XMMatrixTranspose(R); + + // Find the minimum OBB using the eigenvectors as the axes. + XMVECTOR vMin, vMax; + + vMin = vMax = XMVector3TransformNormal(XMLoadFloat3(pPoints), InverseR); + + for (size_t i = 1; i < Count; ++i) + { + XMVECTOR Point = XMVector3TransformNormal(XMLoadFloat3(reinterpret_cast(reinterpret_cast(pPoints) + i * Stride)), + InverseR); + + vMin = XMVectorMin(vMin, Point); + vMax = XMVectorMax(vMax, Point); + } + + // Rotate the center into world space. + XMVECTOR vCenter = XMVectorScale(XMVectorAdd(vMin, vMax), 0.5f); + vCenter = XMVector3TransformNormal(vCenter, R); + + // Store center, extents, and orientation. + XMStoreFloat3(&Out.Center, vCenter); + XMStoreFloat3(&Out.Extents, XMVectorScale(XMVectorSubtract(vMax, vMin), 0.5f)); + XMStoreFloat4(&Out.Orientation, vOrientation); +} + + +/**************************************************************************** + * + * BoundingFrustum + * + ****************************************************************************/ + +_Use_decl_annotations_ +inline BoundingFrustum::BoundingFrustum(CXMMATRIX Projection, bool rhcoords) noexcept +{ + CreateFromMatrix(*this, Projection, rhcoords); +} + + +//----------------------------------------------------------------------------- +// Transform a frustum by an angle preserving transform. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void XM_CALLCONV BoundingFrustum::Transform(BoundingFrustum& Out, FXMMATRIX M) const noexcept +{ + // Load the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + // Composite the frustum rotation and the transform rotation + XMMATRIX nM; + nM.r[0] = XMVector3Normalize(M.r[0]); + nM.r[1] = XMVector3Normalize(M.r[1]); + nM.r[2] = XMVector3Normalize(M.r[2]); + nM.r[3] = g_XMIdentityR3; + XMVECTOR Rotation = XMQuaternionRotationMatrix(nM); + vOrientation = XMQuaternionMultiply(vOrientation, Rotation); + + // Transform the center. + vOrigin = XMVector3Transform(vOrigin, M); + + // Store the frustum. + XMStoreFloat3(&Out.Origin, vOrigin); + XMStoreFloat4(&Out.Orientation, vOrientation); + + // Scale the near and far distances (the slopes remain the same). + XMVECTOR dX = XMVector3Dot(M.r[0], M.r[0]); + XMVECTOR dY = XMVector3Dot(M.r[1], M.r[1]); + XMVECTOR dZ = XMVector3Dot(M.r[2], M.r[2]); + + XMVECTOR d = XMVectorMax(dX, XMVectorMax(dY, dZ)); + float Scale = sqrtf(XMVectorGetX(d)); + + Out.Near = Near * Scale; + Out.Far = Far * Scale; + + // Copy the slopes. + Out.RightSlope = RightSlope; + Out.LeftSlope = LeftSlope; + Out.TopSlope = TopSlope; + Out.BottomSlope = BottomSlope; +} + +_Use_decl_annotations_ +inline void XM_CALLCONV BoundingFrustum::Transform(BoundingFrustum& Out, float Scale, FXMVECTOR Rotation, FXMVECTOR Translation) const noexcept +{ + assert(DirectX::MathInternal::XMQuaternionIsUnit(Rotation)); + + // Load the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + // Composite the frustum rotation and the transform rotation. + vOrientation = XMQuaternionMultiply(vOrientation, Rotation); + + // Transform the origin. + vOrigin = XMVectorAdd(XMVector3Rotate(XMVectorScale(vOrigin, Scale), Rotation), Translation); + + // Store the frustum. + XMStoreFloat3(&Out.Origin, vOrigin); + XMStoreFloat4(&Out.Orientation, vOrientation); + + // Scale the near and far distances (the slopes remain the same). + Out.Near = Near * Scale; + Out.Far = Far * Scale; + + // Copy the slopes. + Out.RightSlope = RightSlope; + Out.LeftSlope = LeftSlope; + Out.TopSlope = TopSlope; + Out.BottomSlope = BottomSlope; +} + + +//----------------------------------------------------------------------------- +// Get the corner points of the frustum +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingFrustum::GetCorners(XMFLOAT3* Corners) const noexcept +{ + assert(Corners != nullptr); + + // Load origin and orientation of the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + // Build the corners of the frustum. + XMVECTOR vRightTop = XMVectorSet(RightSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR vRightBottom = XMVectorSet(RightSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR vLeftTop = XMVectorSet(LeftSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR vLeftBottom = XMVectorSet(LeftSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR vNear = XMVectorReplicatePtr(&Near); + XMVECTOR vFar = XMVectorReplicatePtr(&Far); + + // Returns 8 corners position of bounding frustum. + // Near Far + // 0----1 4----5 + // | | | | + // | | | | + // 3----2 7----6 + + XMVECTOR vCorners[CORNER_COUNT]; + vCorners[0] = XMVectorMultiply(vLeftTop, vNear); + vCorners[1] = XMVectorMultiply(vRightTop, vNear); + vCorners[2] = XMVectorMultiply(vRightBottom, vNear); + vCorners[3] = XMVectorMultiply(vLeftBottom, vNear); + vCorners[4] = XMVectorMultiply(vLeftTop, vFar); + vCorners[5] = XMVectorMultiply(vRightTop, vFar); + vCorners[6] = XMVectorMultiply(vRightBottom, vFar); + vCorners[7] = XMVectorMultiply(vLeftBottom, vFar); + + for (size_t i = 0; i < CORNER_COUNT; ++i) + { + XMVECTOR C = XMVectorAdd(XMVector3Rotate(vCorners[i], vOrientation), vOrigin); + XMStoreFloat3(&Corners[i], C); + } +} + + +//----------------------------------------------------------------------------- +// Point in frustum test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType XM_CALLCONV BoundingFrustum::Contains(FXMVECTOR Point) const noexcept +{ + // Build frustum planes. + XMVECTOR Planes[6]; + Planes[0] = XMVectorSet(0.0f, 0.0f, -1.0f, Near); + Planes[1] = XMVectorSet(0.0f, 0.0f, 1.0f, -Far); + Planes[2] = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f); + Planes[3] = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f); + Planes[4] = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f); + Planes[5] = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f); + + // Load origin and orientation. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + // Transform point into local space of frustum. + XMVECTOR TPoint = XMVector3InverseRotate(XMVectorSubtract(Point, vOrigin), vOrientation); + + // Set w to one. + TPoint = XMVectorInsert<0, 0, 0, 0, 1>(TPoint, XMVectorSplatOne()); + + XMVECTOR Zero = XMVectorZero(); + XMVECTOR Outside = Zero; + + // Test point against each plane of the frustum. + for (size_t i = 0; i < 6; ++i) + { + XMVECTOR Dot = XMVector4Dot(TPoint, Planes[i]); + Outside = XMVectorOrInt(Outside, XMVectorGreater(Dot, Zero)); + } + + return XMVector4NotEqualInt(Outside, XMVectorTrueInt()) ? CONTAINS : DISJOINT; +} + + +//----------------------------------------------------------------------------- +// Triangle vs frustum test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType XM_CALLCONV BoundingFrustum::Contains(FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2) const noexcept +{ + // Load origin and orientation of the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + // Create 6 planes (do it inline to encourage use of registers) + XMVECTOR NearPlane = XMVectorSet(0.0f, 0.0f, -1.0f, Near); + NearPlane = DirectX::MathInternal::XMPlaneTransform(NearPlane, vOrientation, vOrigin); + NearPlane = XMPlaneNormalize(NearPlane); + + XMVECTOR FarPlane = XMVectorSet(0.0f, 0.0f, 1.0f, -Far); + FarPlane = DirectX::MathInternal::XMPlaneTransform(FarPlane, vOrientation, vOrigin); + FarPlane = XMPlaneNormalize(FarPlane); + + XMVECTOR RightPlane = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f); + RightPlane = DirectX::MathInternal::XMPlaneTransform(RightPlane, vOrientation, vOrigin); + RightPlane = XMPlaneNormalize(RightPlane); + + XMVECTOR LeftPlane = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f); + LeftPlane = DirectX::MathInternal::XMPlaneTransform(LeftPlane, vOrientation, vOrigin); + LeftPlane = XMPlaneNormalize(LeftPlane); + + XMVECTOR TopPlane = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f); + TopPlane = DirectX::MathInternal::XMPlaneTransform(TopPlane, vOrientation, vOrigin); + TopPlane = XMPlaneNormalize(TopPlane); + + XMVECTOR BottomPlane = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f); + BottomPlane = DirectX::MathInternal::XMPlaneTransform(BottomPlane, vOrientation, vOrigin); + BottomPlane = XMPlaneNormalize(BottomPlane); + + return TriangleTests::ContainedBy(V0, V1, V2, NearPlane, FarPlane, RightPlane, LeftPlane, TopPlane, BottomPlane); +} + + +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingFrustum::Contains(const BoundingSphere& sh) const noexcept +{ + // Load origin and orientation of the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + // Create 6 planes (do it inline to encourage use of registers) + XMVECTOR NearPlane = XMVectorSet(0.0f, 0.0f, -1.0f, Near); + NearPlane = DirectX::MathInternal::XMPlaneTransform(NearPlane, vOrientation, vOrigin); + NearPlane = XMPlaneNormalize(NearPlane); + + XMVECTOR FarPlane = XMVectorSet(0.0f, 0.0f, 1.0f, -Far); + FarPlane = DirectX::MathInternal::XMPlaneTransform(FarPlane, vOrientation, vOrigin); + FarPlane = XMPlaneNormalize(FarPlane); + + XMVECTOR RightPlane = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f); + RightPlane = DirectX::MathInternal::XMPlaneTransform(RightPlane, vOrientation, vOrigin); + RightPlane = XMPlaneNormalize(RightPlane); + + XMVECTOR LeftPlane = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f); + LeftPlane = DirectX::MathInternal::XMPlaneTransform(LeftPlane, vOrientation, vOrigin); + LeftPlane = XMPlaneNormalize(LeftPlane); + + XMVECTOR TopPlane = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f); + TopPlane = DirectX::MathInternal::XMPlaneTransform(TopPlane, vOrientation, vOrigin); + TopPlane = XMPlaneNormalize(TopPlane); + + XMVECTOR BottomPlane = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f); + BottomPlane = DirectX::MathInternal::XMPlaneTransform(BottomPlane, vOrientation, vOrigin); + BottomPlane = XMPlaneNormalize(BottomPlane); + + return sh.ContainedBy(NearPlane, FarPlane, RightPlane, LeftPlane, TopPlane, BottomPlane); +} + + +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingFrustum::Contains(const BoundingBox& box) const noexcept +{ + // Load origin and orientation of the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + // Create 6 planes (do it inline to encourage use of registers) + XMVECTOR NearPlane = XMVectorSet(0.0f, 0.0f, -1.0f, Near); + NearPlane = DirectX::MathInternal::XMPlaneTransform(NearPlane, vOrientation, vOrigin); + NearPlane = XMPlaneNormalize(NearPlane); + + XMVECTOR FarPlane = XMVectorSet(0.0f, 0.0f, 1.0f, -Far); + FarPlane = DirectX::MathInternal::XMPlaneTransform(FarPlane, vOrientation, vOrigin); + FarPlane = XMPlaneNormalize(FarPlane); + + XMVECTOR RightPlane = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f); + RightPlane = DirectX::MathInternal::XMPlaneTransform(RightPlane, vOrientation, vOrigin); + RightPlane = XMPlaneNormalize(RightPlane); + + XMVECTOR LeftPlane = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f); + LeftPlane = DirectX::MathInternal::XMPlaneTransform(LeftPlane, vOrientation, vOrigin); + LeftPlane = XMPlaneNormalize(LeftPlane); + + XMVECTOR TopPlane = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f); + TopPlane = DirectX::MathInternal::XMPlaneTransform(TopPlane, vOrientation, vOrigin); + TopPlane = XMPlaneNormalize(TopPlane); + + XMVECTOR BottomPlane = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f); + BottomPlane = DirectX::MathInternal::XMPlaneTransform(BottomPlane, vOrientation, vOrigin); + BottomPlane = XMPlaneNormalize(BottomPlane); + + return box.ContainedBy(NearPlane, FarPlane, RightPlane, LeftPlane, TopPlane, BottomPlane); +} + + +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingFrustum::Contains(const BoundingOrientedBox& box) const noexcept +{ + // Load origin and orientation of the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + // Create 6 planes (do it inline to encourage use of registers) + XMVECTOR NearPlane = XMVectorSet(0.0f, 0.0f, -1.0f, Near); + NearPlane = DirectX::MathInternal::XMPlaneTransform(NearPlane, vOrientation, vOrigin); + NearPlane = XMPlaneNormalize(NearPlane); + + XMVECTOR FarPlane = XMVectorSet(0.0f, 0.0f, 1.0f, -Far); + FarPlane = DirectX::MathInternal::XMPlaneTransform(FarPlane, vOrientation, vOrigin); + FarPlane = XMPlaneNormalize(FarPlane); + + XMVECTOR RightPlane = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f); + RightPlane = DirectX::MathInternal::XMPlaneTransform(RightPlane, vOrientation, vOrigin); + RightPlane = XMPlaneNormalize(RightPlane); + + XMVECTOR LeftPlane = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f); + LeftPlane = DirectX::MathInternal::XMPlaneTransform(LeftPlane, vOrientation, vOrigin); + LeftPlane = XMPlaneNormalize(LeftPlane); + + XMVECTOR TopPlane = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f); + TopPlane = DirectX::MathInternal::XMPlaneTransform(TopPlane, vOrientation, vOrigin); + TopPlane = XMPlaneNormalize(TopPlane); + + XMVECTOR BottomPlane = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f); + BottomPlane = DirectX::MathInternal::XMPlaneTransform(BottomPlane, vOrientation, vOrigin); + BottomPlane = XMPlaneNormalize(BottomPlane); + + return box.ContainedBy(NearPlane, FarPlane, RightPlane, LeftPlane, TopPlane, BottomPlane); +} + + +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType BoundingFrustum::Contains(const BoundingFrustum& fr) const noexcept +{ + // Load origin and orientation of the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + // Create 6 planes (do it inline to encourage use of registers) + XMVECTOR NearPlane = XMVectorSet(0.0f, 0.0f, -1.0f, Near); + NearPlane = DirectX::MathInternal::XMPlaneTransform(NearPlane, vOrientation, vOrigin); + NearPlane = XMPlaneNormalize(NearPlane); + + XMVECTOR FarPlane = XMVectorSet(0.0f, 0.0f, 1.0f, -Far); + FarPlane = DirectX::MathInternal::XMPlaneTransform(FarPlane, vOrientation, vOrigin); + FarPlane = XMPlaneNormalize(FarPlane); + + XMVECTOR RightPlane = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f); + RightPlane = DirectX::MathInternal::XMPlaneTransform(RightPlane, vOrientation, vOrigin); + RightPlane = XMPlaneNormalize(RightPlane); + + XMVECTOR LeftPlane = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f); + LeftPlane = DirectX::MathInternal::XMPlaneTransform(LeftPlane, vOrientation, vOrigin); + LeftPlane = XMPlaneNormalize(LeftPlane); + + XMVECTOR TopPlane = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f); + TopPlane = DirectX::MathInternal::XMPlaneTransform(TopPlane, vOrientation, vOrigin); + TopPlane = XMPlaneNormalize(TopPlane); + + XMVECTOR BottomPlane = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f); + BottomPlane = DirectX::MathInternal::XMPlaneTransform(BottomPlane, vOrientation, vOrigin); + BottomPlane = XMPlaneNormalize(BottomPlane); + + return fr.ContainedBy(NearPlane, FarPlane, RightPlane, LeftPlane, TopPlane, BottomPlane); +} + + +//----------------------------------------------------------------------------- +// Exact sphere vs frustum test. The algorithm first checks the sphere against +// the planes of the frustum, then if the plane checks were indeterminate finds +// the nearest feature (plane, line, point) on the frustum to the center of the +// sphere and compares the distance to the nearest feature to the radius of the +// sphere +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingFrustum::Intersects(const BoundingSphere& sh) const noexcept +{ + XMVECTOR Zero = XMVectorZero(); + + // Build the frustum planes. + XMVECTOR Planes[6]; + Planes[0] = XMVectorSet(0.0f, 0.0f, -1.0f, Near); + Planes[1] = XMVectorSet(0.0f, 0.0f, 1.0f, -Far); + Planes[2] = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f); + Planes[3] = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f); + Planes[4] = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f); + Planes[5] = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f); + + // Normalize the planes so we can compare to the sphere radius. + Planes[2] = XMVector3Normalize(Planes[2]); + Planes[3] = XMVector3Normalize(Planes[3]); + Planes[4] = XMVector3Normalize(Planes[4]); + Planes[5] = XMVector3Normalize(Planes[5]); + + // Load origin and orientation of the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + // Load the sphere. + XMVECTOR vCenter = XMLoadFloat3(&sh.Center); + XMVECTOR vRadius = XMVectorReplicatePtr(&sh.Radius); + + // Transform the center of the sphere into the local space of frustum. + vCenter = XMVector3InverseRotate(XMVectorSubtract(vCenter, vOrigin), vOrientation); + + // Set w of the center to one so we can dot4 with the plane. + vCenter = XMVectorInsert<0, 0, 0, 0, 1>(vCenter, XMVectorSplatOne()); + + // Check against each plane of the frustum. + XMVECTOR Outside = XMVectorFalseInt(); + XMVECTOR InsideAll = XMVectorTrueInt(); + XMVECTOR CenterInsideAll = XMVectorTrueInt(); + + XMVECTOR Dist[6]; + + for (size_t i = 0; i < 6; ++i) + { + Dist[i] = XMVector4Dot(vCenter, Planes[i]); + + // Outside the plane? + Outside = XMVectorOrInt(Outside, XMVectorGreater(Dist[i], vRadius)); + + // Fully inside the plane? + InsideAll = XMVectorAndInt(InsideAll, XMVectorLessOrEqual(Dist[i], XMVectorNegate(vRadius))); + + // Check if the center is inside the plane. + CenterInsideAll = XMVectorAndInt(CenterInsideAll, XMVectorLessOrEqual(Dist[i], Zero)); + } + + // If the sphere is outside any of the planes it is outside. + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return false; + + // If the sphere is inside all planes it is fully inside. + if (XMVector4EqualInt(InsideAll, XMVectorTrueInt())) + return true; + + // If the center of the sphere is inside all planes and the sphere intersects + // one or more planes then it must intersect. + if (XMVector4EqualInt(CenterInsideAll, XMVectorTrueInt())) + return true; + + // The sphere may be outside the frustum or intersecting the frustum. + // Find the nearest feature (face, edge, or corner) on the frustum + // to the sphere. + + // The faces adjacent to each face are: + static const size_t adjacent_faces[6][4] = + { + { 2, 3, 4, 5 }, // 0 + { 2, 3, 4, 5 }, // 1 + { 0, 1, 4, 5 }, // 2 + { 0, 1, 4, 5 }, // 3 + { 0, 1, 2, 3 }, // 4 + { 0, 1, 2, 3 } + }; // 5 + + XMVECTOR Intersects = XMVectorFalseInt(); + + // Check to see if the nearest feature is one of the planes. + for (size_t i = 0; i < 6; ++i) + { + // Find the nearest point on the plane to the center of the sphere. + XMVECTOR Point = XMVectorNegativeMultiplySubtract(Planes[i], Dist[i], vCenter); + + // Set w of the point to one. + Point = XMVectorInsert<0, 0, 0, 0, 1>(Point, XMVectorSplatOne()); + + // If the point is inside the face (inside the adjacent planes) then + // this plane is the nearest feature. + XMVECTOR InsideFace = XMVectorTrueInt(); + + for (size_t j = 0; j < 4; j++) + { + size_t plane_index = adjacent_faces[i][j]; + + InsideFace = XMVectorAndInt(InsideFace, + XMVectorLessOrEqual(XMVector4Dot(Point, Planes[plane_index]), Zero)); + } + + // Since we have already checked distance from the plane we know that the + // sphere must intersect if this plane is the nearest feature. + Intersects = XMVectorOrInt(Intersects, + XMVectorAndInt(XMVectorGreater(Dist[i], Zero), InsideFace)); + } + + if (XMVector4EqualInt(Intersects, XMVectorTrueInt())) + return true; + + // Build the corners of the frustum. + XMVECTOR vRightTop = XMVectorSet(RightSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR vRightBottom = XMVectorSet(RightSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR vLeftTop = XMVectorSet(LeftSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR vLeftBottom = XMVectorSet(LeftSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR vNear = XMVectorReplicatePtr(&Near); + XMVECTOR vFar = XMVectorReplicatePtr(&Far); + + XMVECTOR Corners[CORNER_COUNT]; + Corners[0] = XMVectorMultiply(vRightTop, vNear); + Corners[1] = XMVectorMultiply(vRightBottom, vNear); + Corners[2] = XMVectorMultiply(vLeftTop, vNear); + Corners[3] = XMVectorMultiply(vLeftBottom, vNear); + Corners[4] = XMVectorMultiply(vRightTop, vFar); + Corners[5] = XMVectorMultiply(vRightBottom, vFar); + Corners[6] = XMVectorMultiply(vLeftTop, vFar); + Corners[7] = XMVectorMultiply(vLeftBottom, vFar); + + // The Edges are: + static const size_t edges[12][2] = + { + { 0, 1 }, { 2, 3 }, { 0, 2 }, { 1, 3 }, // Near plane + { 4, 5 }, { 6, 7 }, { 4, 6 }, { 5, 7 }, // Far plane + { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 }, + }; // Near to far + + XMVECTOR RadiusSq = XMVectorMultiply(vRadius, vRadius); + + // Check to see if the nearest feature is one of the edges (or corners). + for (size_t i = 0; i < 12; ++i) + { + size_t ei0 = edges[i][0]; + size_t ei1 = edges[i][1]; + + // Find the nearest point on the edge to the center of the sphere. + // The corners of the frustum are included as the endpoints of the edges. + XMVECTOR Point = DirectX::MathInternal::PointOnLineSegmentNearestPoint(Corners[ei0], Corners[ei1], vCenter); + + XMVECTOR Delta = XMVectorSubtract(vCenter, Point); + + XMVECTOR DistSq = XMVector3Dot(Delta, Delta); + + // If the distance to the center of the sphere to the point is less than + // the radius of the sphere then it must intersect. + Intersects = XMVectorOrInt(Intersects, XMVectorLessOrEqual(DistSq, RadiusSq)); + } + + if (XMVector4EqualInt(Intersects, XMVectorTrueInt())) + return true; + + // The sphere must be outside the frustum. + return false; +} + + +//----------------------------------------------------------------------------- +// Exact axis aligned box vs frustum test. Constructs an oriented box and uses +// the oriented box vs frustum test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingFrustum::Intersects(const BoundingBox& box) const noexcept +{ + // Make the axis aligned box oriented and do an OBB vs frustum test. + BoundingOrientedBox obox(box.Center, box.Extents, XMFLOAT4(0.f, 0.f, 0.f, 1.f)); + return Intersects(obox); +} + + +//----------------------------------------------------------------------------- +// Exact oriented box vs frustum test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingFrustum::Intersects(const BoundingOrientedBox& box) const noexcept +{ + static const XMVECTORU32 SelectY = { { { XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_0 } } }; + static const XMVECTORU32 SelectZ = { { { XM_SELECT_0, XM_SELECT_0, XM_SELECT_1, XM_SELECT_0 } } }; + + XMVECTOR Zero = XMVectorZero(); + + // Build the frustum planes. + XMVECTOR Planes[6]; + Planes[0] = XMVectorSet(0.0f, 0.0f, -1.0f, Near); + Planes[1] = XMVectorSet(0.0f, 0.0f, 1.0f, -Far); + Planes[2] = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f); + Planes[3] = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f); + Planes[4] = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f); + Planes[5] = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f); + + // Load origin and orientation of the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR FrustumOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(FrustumOrientation)); + + // Load the box. + XMVECTOR Center = XMLoadFloat3(&box.Center); + XMVECTOR Extents = XMLoadFloat3(&box.Extents); + XMVECTOR BoxOrientation = XMLoadFloat4(&box.Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(BoxOrientation)); + + // Transform the oriented box into the space of the frustum in order to + // minimize the number of transforms we have to do. + Center = XMVector3InverseRotate(XMVectorSubtract(Center, vOrigin), FrustumOrientation); + BoxOrientation = XMQuaternionMultiply(BoxOrientation, XMQuaternionConjugate(FrustumOrientation)); + + // Set w of the center to one so we can dot4 with the plane. + Center = XMVectorInsert<0, 0, 0, 0, 1>(Center, XMVectorSplatOne()); + + // Build the 3x3 rotation matrix that defines the box axes. + XMMATRIX R = XMMatrixRotationQuaternion(BoxOrientation); + + // Check against each plane of the frustum. + XMVECTOR Outside = XMVectorFalseInt(); + XMVECTOR InsideAll = XMVectorTrueInt(); + XMVECTOR CenterInsideAll = XMVectorTrueInt(); + + for (size_t i = 0; i < 6; ++i) + { + // Compute the distance to the center of the box. + XMVECTOR Dist = XMVector4Dot(Center, Planes[i]); + + // Project the axes of the box onto the normal of the plane. Half the + // length of the projection (sometime called the "radius") is equal to + // h(u) * abs(n dot b(u))) + h(v) * abs(n dot b(v)) + h(w) * abs(n dot b(w)) + // where h(i) are extents of the box, n is the plane normal, and b(i) are the + // axes of the box. + XMVECTOR Radius = XMVector3Dot(Planes[i], R.r[0]); + Radius = XMVectorSelect(Radius, XMVector3Dot(Planes[i], R.r[1]), SelectY); + Radius = XMVectorSelect(Radius, XMVector3Dot(Planes[i], R.r[2]), SelectZ); + Radius = XMVector3Dot(Extents, XMVectorAbs(Radius)); + + // Outside the plane? + Outside = XMVectorOrInt(Outside, XMVectorGreater(Dist, Radius)); + + // Fully inside the plane? + InsideAll = XMVectorAndInt(InsideAll, XMVectorLessOrEqual(Dist, XMVectorNegate(Radius))); + + // Check if the center is inside the plane. + CenterInsideAll = XMVectorAndInt(CenterInsideAll, XMVectorLessOrEqual(Dist, Zero)); + } + + // If the box is outside any of the planes it is outside. + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return false; + + // If the box is inside all planes it is fully inside. + if (XMVector4EqualInt(InsideAll, XMVectorTrueInt())) + return true; + + // If the center of the box is inside all planes and the box intersects + // one or more planes then it must intersect. + if (XMVector4EqualInt(CenterInsideAll, XMVectorTrueInt())) + return true; + + // Build the corners of the frustum. + XMVECTOR vRightTop = XMVectorSet(RightSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR vRightBottom = XMVectorSet(RightSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR vLeftTop = XMVectorSet(LeftSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR vLeftBottom = XMVectorSet(LeftSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR vNear = XMVectorReplicatePtr(&Near); + XMVECTOR vFar = XMVectorReplicatePtr(&Far); + + XMVECTOR Corners[CORNER_COUNT]; + Corners[0] = XMVectorMultiply(vRightTop, vNear); + Corners[1] = XMVectorMultiply(vRightBottom, vNear); + Corners[2] = XMVectorMultiply(vLeftTop, vNear); + Corners[3] = XMVectorMultiply(vLeftBottom, vNear); + Corners[4] = XMVectorMultiply(vRightTop, vFar); + Corners[5] = XMVectorMultiply(vRightBottom, vFar); + Corners[6] = XMVectorMultiply(vLeftTop, vFar); + Corners[7] = XMVectorMultiply(vLeftBottom, vFar); + + // Test against box axes (3) + { + // Find the min/max values of the projection of the frustum onto each axis. + XMVECTOR FrustumMin, FrustumMax; + + FrustumMin = XMVector3Dot(Corners[0], R.r[0]); + FrustumMin = XMVectorSelect(FrustumMin, XMVector3Dot(Corners[0], R.r[1]), SelectY); + FrustumMin = XMVectorSelect(FrustumMin, XMVector3Dot(Corners[0], R.r[2]), SelectZ); + FrustumMax = FrustumMin; + + for (size_t i = 1; i < BoundingOrientedBox::CORNER_COUNT; ++i) + { + XMVECTOR Temp = XMVector3Dot(Corners[i], R.r[0]); + Temp = XMVectorSelect(Temp, XMVector3Dot(Corners[i], R.r[1]), SelectY); + Temp = XMVectorSelect(Temp, XMVector3Dot(Corners[i], R.r[2]), SelectZ); + + FrustumMin = XMVectorMin(FrustumMin, Temp); + FrustumMax = XMVectorMax(FrustumMax, Temp); + } + + // Project the center of the box onto the axes. + XMVECTOR BoxDist = XMVector3Dot(Center, R.r[0]); + BoxDist = XMVectorSelect(BoxDist, XMVector3Dot(Center, R.r[1]), SelectY); + BoxDist = XMVectorSelect(BoxDist, XMVector3Dot(Center, R.r[2]), SelectZ); + + // The projection of the box onto the axis is just its Center and Extents. + // if (min > box_max || max < box_min) reject; + XMVECTOR Result = XMVectorOrInt(XMVectorGreater(FrustumMin, XMVectorAdd(BoxDist, Extents)), + XMVectorLess(FrustumMax, XMVectorSubtract(BoxDist, Extents))); + + if (DirectX::MathInternal::XMVector3AnyTrue(Result)) + return false; + } + + // Test against edge/edge axes (3*6). + XMVECTOR FrustumEdgeAxis[6]; + + FrustumEdgeAxis[0] = vRightTop; + FrustumEdgeAxis[1] = vRightBottom; + FrustumEdgeAxis[2] = vLeftTop; + FrustumEdgeAxis[3] = vLeftBottom; + FrustumEdgeAxis[4] = XMVectorSubtract(vRightTop, vLeftTop); + FrustumEdgeAxis[5] = XMVectorSubtract(vLeftBottom, vLeftTop); + + for (size_t i = 0; i < 3; ++i) + { + for (size_t j = 0; j < 6; j++) + { + // Compute the axis we are going to test. + XMVECTOR Axis = XMVector3Cross(R.r[i], FrustumEdgeAxis[j]); + + // Find the min/max values of the projection of the frustum onto the axis. + XMVECTOR FrustumMin, FrustumMax; + + FrustumMin = FrustumMax = XMVector3Dot(Axis, Corners[0]); + + for (size_t k = 1; k < CORNER_COUNT; k++) + { + XMVECTOR Temp = XMVector3Dot(Axis, Corners[k]); + FrustumMin = XMVectorMin(FrustumMin, Temp); + FrustumMax = XMVectorMax(FrustumMax, Temp); + } + + // Project the center of the box onto the axis. + XMVECTOR Dist = XMVector3Dot(Center, Axis); + + // Project the axes of the box onto the axis to find the "radius" of the box. + XMVECTOR Radius = XMVector3Dot(Axis, R.r[0]); + Radius = XMVectorSelect(Radius, XMVector3Dot(Axis, R.r[1]), SelectY); + Radius = XMVectorSelect(Radius, XMVector3Dot(Axis, R.r[2]), SelectZ); + Radius = XMVector3Dot(Extents, XMVectorAbs(Radius)); + + // if (center > max + radius || center < min - radius) reject; + Outside = XMVectorOrInt(Outside, XMVectorGreater(Dist, XMVectorAdd(FrustumMax, Radius))); + Outside = XMVectorOrInt(Outside, XMVectorLess(Dist, XMVectorSubtract(FrustumMin, Radius))); + } + } + + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return false; + + // If we did not find a separating plane then the box must intersect the frustum. + return true; +} + + +//----------------------------------------------------------------------------- +// Exact frustum vs frustum test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool BoundingFrustum::Intersects(const BoundingFrustum& fr) const noexcept +{ + // Load origin and orientation of frustum B. + XMVECTOR OriginB = XMLoadFloat3(&Origin); + XMVECTOR OrientationB = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(OrientationB)); + + // Build the planes of frustum B. + XMVECTOR AxisB[6]; + AxisB[0] = XMVectorSet(0.0f, 0.0f, -1.0f, 0.0f); + AxisB[1] = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); + AxisB[2] = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f); + AxisB[3] = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f); + AxisB[4] = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f); + AxisB[5] = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f); + + XMVECTOR PlaneDistB[6]; + PlaneDistB[0] = XMVectorNegate(XMVectorReplicatePtr(&Near)); + PlaneDistB[1] = XMVectorReplicatePtr(&Far); + PlaneDistB[2] = XMVectorZero(); + PlaneDistB[3] = XMVectorZero(); + PlaneDistB[4] = XMVectorZero(); + PlaneDistB[5] = XMVectorZero(); + + // Load origin and orientation of frustum A. + XMVECTOR OriginA = XMLoadFloat3(&fr.Origin); + XMVECTOR OrientationA = XMLoadFloat4(&fr.Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(OrientationA)); + + // Transform frustum A into the space of the frustum B in order to + // minimize the number of transforms we have to do. + OriginA = XMVector3InverseRotate(XMVectorSubtract(OriginA, OriginB), OrientationB); + OrientationA = XMQuaternionMultiply(OrientationA, XMQuaternionConjugate(OrientationB)); + + // Build the corners of frustum A (in the local space of B). + XMVECTOR RightTopA = XMVectorSet(fr.RightSlope, fr.TopSlope, 1.0f, 0.0f); + XMVECTOR RightBottomA = XMVectorSet(fr.RightSlope, fr.BottomSlope, 1.0f, 0.0f); + XMVECTOR LeftTopA = XMVectorSet(fr.LeftSlope, fr.TopSlope, 1.0f, 0.0f); + XMVECTOR LeftBottomA = XMVectorSet(fr.LeftSlope, fr.BottomSlope, 1.0f, 0.0f); + XMVECTOR NearA = XMVectorReplicatePtr(&fr.Near); + XMVECTOR FarA = XMVectorReplicatePtr(&fr.Far); + + RightTopA = XMVector3Rotate(RightTopA, OrientationA); + RightBottomA = XMVector3Rotate(RightBottomA, OrientationA); + LeftTopA = XMVector3Rotate(LeftTopA, OrientationA); + LeftBottomA = XMVector3Rotate(LeftBottomA, OrientationA); + + XMVECTOR CornersA[CORNER_COUNT]; + CornersA[0] = XMVectorMultiplyAdd(RightTopA, NearA, OriginA); + CornersA[1] = XMVectorMultiplyAdd(RightBottomA, NearA, OriginA); + CornersA[2] = XMVectorMultiplyAdd(LeftTopA, NearA, OriginA); + CornersA[3] = XMVectorMultiplyAdd(LeftBottomA, NearA, OriginA); + CornersA[4] = XMVectorMultiplyAdd(RightTopA, FarA, OriginA); + CornersA[5] = XMVectorMultiplyAdd(RightBottomA, FarA, OriginA); + CornersA[6] = XMVectorMultiplyAdd(LeftTopA, FarA, OriginA); + CornersA[7] = XMVectorMultiplyAdd(LeftBottomA, FarA, OriginA); + + // Check frustum A against each plane of frustum B. + XMVECTOR Outside = XMVectorFalseInt(); + XMVECTOR InsideAll = XMVectorTrueInt(); + + for (size_t i = 0; i < 6; ++i) + { + // Find the min/max projection of the frustum onto the plane normal. + XMVECTOR Min, Max; + + Min = Max = XMVector3Dot(AxisB[i], CornersA[0]); + + for (size_t j = 1; j < CORNER_COUNT; j++) + { + XMVECTOR Temp = XMVector3Dot(AxisB[i], CornersA[j]); + Min = XMVectorMin(Min, Temp); + Max = XMVectorMax(Max, Temp); + } + + // Outside the plane? + Outside = XMVectorOrInt(Outside, XMVectorGreater(Min, PlaneDistB[i])); + + // Fully inside the plane? + InsideAll = XMVectorAndInt(InsideAll, XMVectorLessOrEqual(Max, PlaneDistB[i])); + } + + // If the frustum A is outside any of the planes of frustum B it is outside. + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return false; + + // If frustum A is inside all planes of frustum B it is fully inside. + if (XMVector4EqualInt(InsideAll, XMVectorTrueInt())) + return true; + + // Build the corners of frustum B. + XMVECTOR RightTopB = XMVectorSet(RightSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR RightBottomB = XMVectorSet(RightSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR LeftTopB = XMVectorSet(LeftSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR LeftBottomB = XMVectorSet(LeftSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR NearB = XMVectorReplicatePtr(&Near); + XMVECTOR FarB = XMVectorReplicatePtr(&Far); + + XMVECTOR CornersB[BoundingFrustum::CORNER_COUNT]; + CornersB[0] = XMVectorMultiply(RightTopB, NearB); + CornersB[1] = XMVectorMultiply(RightBottomB, NearB); + CornersB[2] = XMVectorMultiply(LeftTopB, NearB); + CornersB[3] = XMVectorMultiply(LeftBottomB, NearB); + CornersB[4] = XMVectorMultiply(RightTopB, FarB); + CornersB[5] = XMVectorMultiply(RightBottomB, FarB); + CornersB[6] = XMVectorMultiply(LeftTopB, FarB); + CornersB[7] = XMVectorMultiply(LeftBottomB, FarB); + + // Build the planes of frustum A (in the local space of B). + XMVECTOR AxisA[6]; + XMVECTOR PlaneDistA[6]; + + AxisA[0] = XMVectorSet(0.0f, 0.0f, -1.0f, 0.0f); + AxisA[1] = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); + AxisA[2] = XMVectorSet(1.0f, 0.0f, -fr.RightSlope, 0.0f); + AxisA[3] = XMVectorSet(-1.0f, 0.0f, fr.LeftSlope, 0.0f); + AxisA[4] = XMVectorSet(0.0f, 1.0f, -fr.TopSlope, 0.0f); + AxisA[5] = XMVectorSet(0.0f, -1.0f, fr.BottomSlope, 0.0f); + + AxisA[0] = XMVector3Rotate(AxisA[0], OrientationA); + AxisA[1] = XMVectorNegate(AxisA[0]); + AxisA[2] = XMVector3Rotate(AxisA[2], OrientationA); + AxisA[3] = XMVector3Rotate(AxisA[3], OrientationA); + AxisA[4] = XMVector3Rotate(AxisA[4], OrientationA); + AxisA[5] = XMVector3Rotate(AxisA[5], OrientationA); + + PlaneDistA[0] = XMVector3Dot(AxisA[0], CornersA[0]); // Re-use corner on near plane. + PlaneDistA[1] = XMVector3Dot(AxisA[1], CornersA[4]); // Re-use corner on far plane. + PlaneDistA[2] = XMVector3Dot(AxisA[2], OriginA); + PlaneDistA[3] = XMVector3Dot(AxisA[3], OriginA); + PlaneDistA[4] = XMVector3Dot(AxisA[4], OriginA); + PlaneDistA[5] = XMVector3Dot(AxisA[5], OriginA); + + // Check each axis of frustum A for a seperating plane (5). + for (size_t i = 0; i < 6; ++i) + { + // Find the minimum projection of the frustum onto the plane normal. + XMVECTOR Min; + + Min = XMVector3Dot(AxisA[i], CornersB[0]); + + for (size_t j = 1; j < CORNER_COUNT; j++) + { + XMVECTOR Temp = XMVector3Dot(AxisA[i], CornersB[j]); + Min = XMVectorMin(Min, Temp); + } + + // Outside the plane? + Outside = XMVectorOrInt(Outside, XMVectorGreater(Min, PlaneDistA[i])); + } + + // If the frustum B is outside any of the planes of frustum A it is outside. + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return false; + + // Check edge/edge axes (6 * 6). + XMVECTOR FrustumEdgeAxisA[6]; + FrustumEdgeAxisA[0] = RightTopA; + FrustumEdgeAxisA[1] = RightBottomA; + FrustumEdgeAxisA[2] = LeftTopA; + FrustumEdgeAxisA[3] = LeftBottomA; + FrustumEdgeAxisA[4] = XMVectorSubtract(RightTopA, LeftTopA); + FrustumEdgeAxisA[5] = XMVectorSubtract(LeftBottomA, LeftTopA); + + XMVECTOR FrustumEdgeAxisB[6]; + FrustumEdgeAxisB[0] = RightTopB; + FrustumEdgeAxisB[1] = RightBottomB; + FrustumEdgeAxisB[2] = LeftTopB; + FrustumEdgeAxisB[3] = LeftBottomB; + FrustumEdgeAxisB[4] = XMVectorSubtract(RightTopB, LeftTopB); + FrustumEdgeAxisB[5] = XMVectorSubtract(LeftBottomB, LeftTopB); + + for (size_t i = 0; i < 6; ++i) + { + for (size_t j = 0; j < 6; j++) + { + // Compute the axis we are going to test. + XMVECTOR Axis = XMVector3Cross(FrustumEdgeAxisA[i], FrustumEdgeAxisB[j]); + + // Find the min/max values of the projection of both frustums onto the axis. + XMVECTOR MinA, MaxA; + XMVECTOR MinB, MaxB; + + MinA = MaxA = XMVector3Dot(Axis, CornersA[0]); + MinB = MaxB = XMVector3Dot(Axis, CornersB[0]); + + for (size_t k = 1; k < CORNER_COUNT; k++) + { + XMVECTOR TempA = XMVector3Dot(Axis, CornersA[k]); + MinA = XMVectorMin(MinA, TempA); + MaxA = XMVectorMax(MaxA, TempA); + + XMVECTOR TempB = XMVector3Dot(Axis, CornersB[k]); + MinB = XMVectorMin(MinB, TempB); + MaxB = XMVectorMax(MaxB, TempB); + } + + // if (MinA > MaxB || MinB > MaxA) reject + Outside = XMVectorOrInt(Outside, XMVectorGreater(MinA, MaxB)); + Outside = XMVectorOrInt(Outside, XMVectorGreater(MinB, MaxA)); + } + } + + // If there is a seperating plane, then the frustums do not intersect. + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return false; + + // If we did not find a separating plane then the frustums intersect. + return true; +} + + +//----------------------------------------------------------------------------- +// Triangle vs frustum test. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool XM_CALLCONV BoundingFrustum::Intersects(FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2) const noexcept +{ + // Build the frustum planes (NOTE: D is negated from the usual). + XMVECTOR Planes[6]; + Planes[0] = XMVectorSet(0.0f, 0.0f, -1.0f, -Near); + Planes[1] = XMVectorSet(0.0f, 0.0f, 1.0f, Far); + Planes[2] = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f); + Planes[3] = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f); + Planes[4] = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f); + Planes[5] = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f); + + // Load origin and orientation of the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + // Transform triangle into the local space of frustum. + XMVECTOR TV0 = XMVector3InverseRotate(XMVectorSubtract(V0, vOrigin), vOrientation); + XMVECTOR TV1 = XMVector3InverseRotate(XMVectorSubtract(V1, vOrigin), vOrientation); + XMVECTOR TV2 = XMVector3InverseRotate(XMVectorSubtract(V2, vOrigin), vOrientation); + + // Test each vertex of the triangle against the frustum planes. + XMVECTOR Outside = XMVectorFalseInt(); + XMVECTOR InsideAll = XMVectorTrueInt(); + + for (size_t i = 0; i < 6; ++i) + { + XMVECTOR Dist0 = XMVector3Dot(TV0, Planes[i]); + XMVECTOR Dist1 = XMVector3Dot(TV1, Planes[i]); + XMVECTOR Dist2 = XMVector3Dot(TV2, Planes[i]); + + XMVECTOR MinDist = XMVectorMin(Dist0, Dist1); + MinDist = XMVectorMin(MinDist, Dist2); + XMVECTOR MaxDist = XMVectorMax(Dist0, Dist1); + MaxDist = XMVectorMax(MaxDist, Dist2); + + XMVECTOR PlaneDist = XMVectorSplatW(Planes[i]); + + // Outside the plane? + Outside = XMVectorOrInt(Outside, XMVectorGreater(MinDist, PlaneDist)); + + // Fully inside the plane? + InsideAll = XMVectorAndInt(InsideAll, XMVectorLessOrEqual(MaxDist, PlaneDist)); + } + + // If the triangle is outside any of the planes it is outside. + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return false; + + // If the triangle is inside all planes it is fully inside. + if (XMVector4EqualInt(InsideAll, XMVectorTrueInt())) + return true; + + // Build the corners of the frustum. + XMVECTOR vRightTop = XMVectorSet(RightSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR vRightBottom = XMVectorSet(RightSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR vLeftTop = XMVectorSet(LeftSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR vLeftBottom = XMVectorSet(LeftSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR vNear = XMVectorReplicatePtr(&Near); + XMVECTOR vFar = XMVectorReplicatePtr(&Far); + + XMVECTOR Corners[CORNER_COUNT]; + Corners[0] = XMVectorMultiply(vRightTop, vNear); + Corners[1] = XMVectorMultiply(vRightBottom, vNear); + Corners[2] = XMVectorMultiply(vLeftTop, vNear); + Corners[3] = XMVectorMultiply(vLeftBottom, vNear); + Corners[4] = XMVectorMultiply(vRightTop, vFar); + Corners[5] = XMVectorMultiply(vRightBottom, vFar); + Corners[6] = XMVectorMultiply(vLeftTop, vFar); + Corners[7] = XMVectorMultiply(vLeftBottom, vFar); + + // Test the plane of the triangle. + XMVECTOR Normal = XMVector3Cross(XMVectorSubtract(V1, V0), XMVectorSubtract(V2, V0)); + XMVECTOR Dist = XMVector3Dot(Normal, V0); + + XMVECTOR MinDist, MaxDist; + MinDist = MaxDist = XMVector3Dot(Corners[0], Normal); + for (size_t i = 1; i < CORNER_COUNT; ++i) + { + XMVECTOR Temp = XMVector3Dot(Corners[i], Normal); + MinDist = XMVectorMin(MinDist, Temp); + MaxDist = XMVectorMax(MaxDist, Temp); + } + + Outside = XMVectorOrInt(XMVectorGreater(MinDist, Dist), XMVectorLess(MaxDist, Dist)); + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return false; + + // Check the edge/edge axes (3*6). + XMVECTOR TriangleEdgeAxis[3]; + TriangleEdgeAxis[0] = XMVectorSubtract(V1, V0); + TriangleEdgeAxis[1] = XMVectorSubtract(V2, V1); + TriangleEdgeAxis[2] = XMVectorSubtract(V0, V2); + + XMVECTOR FrustumEdgeAxis[6]; + FrustumEdgeAxis[0] = vRightTop; + FrustumEdgeAxis[1] = vRightBottom; + FrustumEdgeAxis[2] = vLeftTop; + FrustumEdgeAxis[3] = vLeftBottom; + FrustumEdgeAxis[4] = XMVectorSubtract(vRightTop, vLeftTop); + FrustumEdgeAxis[5] = XMVectorSubtract(vLeftBottom, vLeftTop); + + for (size_t i = 0; i < 3; ++i) + { + for (size_t j = 0; j < 6; j++) + { + // Compute the axis we are going to test. + XMVECTOR Axis = XMVector3Cross(TriangleEdgeAxis[i], FrustumEdgeAxis[j]); + + // Find the min/max of the projection of the triangle onto the axis. + XMVECTOR MinA, MaxA; + + XMVECTOR Dist0 = XMVector3Dot(V0, Axis); + XMVECTOR Dist1 = XMVector3Dot(V1, Axis); + XMVECTOR Dist2 = XMVector3Dot(V2, Axis); + + MinA = XMVectorMin(Dist0, Dist1); + MinA = XMVectorMin(MinA, Dist2); + MaxA = XMVectorMax(Dist0, Dist1); + MaxA = XMVectorMax(MaxA, Dist2); + + // Find the min/max of the projection of the frustum onto the axis. + XMVECTOR MinB, MaxB; + + MinB = MaxB = XMVector3Dot(Axis, Corners[0]); + + for (size_t k = 1; k < CORNER_COUNT; k++) + { + XMVECTOR Temp = XMVector3Dot(Axis, Corners[k]); + MinB = XMVectorMin(MinB, Temp); + MaxB = XMVectorMax(MaxB, Temp); + } + + // if (MinA > MaxB || MinB > MaxA) reject; + Outside = XMVectorOrInt(Outside, XMVectorGreater(MinA, MaxB)); + Outside = XMVectorOrInt(Outside, XMVectorGreater(MinB, MaxA)); + } + } + + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return false; + + // If we did not find a separating plane then the triangle must intersect the frustum. + return true; +} + + +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline PlaneIntersectionType XM_CALLCONV BoundingFrustum::Intersects(FXMVECTOR Plane) const noexcept +{ + assert(DirectX::MathInternal::XMPlaneIsUnit(Plane)); + + // Load origin and orientation of the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + // Set w of the origin to one so we can dot4 with a plane. + vOrigin = XMVectorInsert<0, 0, 0, 0, 1>(vOrigin, XMVectorSplatOne()); + + // Build the corners of the frustum (in world space). + XMVECTOR RightTop = XMVectorSet(RightSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR RightBottom = XMVectorSet(RightSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR LeftTop = XMVectorSet(LeftSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR LeftBottom = XMVectorSet(LeftSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR vNear = XMVectorReplicatePtr(&Near); + XMVECTOR vFar = XMVectorReplicatePtr(&Far); + + RightTop = XMVector3Rotate(RightTop, vOrientation); + RightBottom = XMVector3Rotate(RightBottom, vOrientation); + LeftTop = XMVector3Rotate(LeftTop, vOrientation); + LeftBottom = XMVector3Rotate(LeftBottom, vOrientation); + + XMVECTOR Corners0 = XMVectorMultiplyAdd(RightTop, vNear, vOrigin); + XMVECTOR Corners1 = XMVectorMultiplyAdd(RightBottom, vNear, vOrigin); + XMVECTOR Corners2 = XMVectorMultiplyAdd(LeftTop, vNear, vOrigin); + XMVECTOR Corners3 = XMVectorMultiplyAdd(LeftBottom, vNear, vOrigin); + XMVECTOR Corners4 = XMVectorMultiplyAdd(RightTop, vFar, vOrigin); + XMVECTOR Corners5 = XMVectorMultiplyAdd(RightBottom, vFar, vOrigin); + XMVECTOR Corners6 = XMVectorMultiplyAdd(LeftTop, vFar, vOrigin); + XMVECTOR Corners7 = XMVectorMultiplyAdd(LeftBottom, vFar, vOrigin); + + XMVECTOR Outside, Inside; + DirectX::MathInternal::FastIntersectFrustumPlane(Corners0, Corners1, Corners2, Corners3, + Corners4, Corners5, Corners6, Corners7, + Plane, Outside, Inside); + + // If the frustum is outside any plane it is outside. + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return FRONT; + + // If the frustum is inside all planes it is inside. + if (XMVector4EqualInt(Inside, XMVectorTrueInt())) + return BACK; + + // The frustum is not inside all planes or outside a plane it intersects. + return INTERSECTING; +} + + +//----------------------------------------------------------------------------- +// Ray vs. frustum test +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline bool XM_CALLCONV BoundingFrustum::Intersects(FXMVECTOR rayOrigin, FXMVECTOR Direction, float& Dist) const noexcept +{ + // If ray starts inside the frustum, return a distance of 0 for the hit + if (Contains(rayOrigin) == CONTAINS) + { + Dist = 0.0f; + return true; + } + + // Build the frustum planes. + XMVECTOR Planes[6]; + Planes[0] = XMVectorSet(0.0f, 0.0f, -1.0f, Near); + Planes[1] = XMVectorSet(0.0f, 0.0f, 1.0f, -Far); + Planes[2] = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f); + Planes[3] = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f); + Planes[4] = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f); + Planes[5] = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f); + + // Load origin and orientation of the frustum. + XMVECTOR frOrigin = XMLoadFloat3(&Origin); + XMVECTOR frOrientation = XMLoadFloat4(&Orientation); + + // This algorithm based on "Fast Ray-Convex Polyhedron Intersectin," in James Arvo, ed., Graphics Gems II pp. 247-250 + float tnear = -FLT_MAX; + float tfar = FLT_MAX; + + for (size_t i = 0; i < 6; ++i) + { + XMVECTOR Plane = DirectX::MathInternal::XMPlaneTransform(Planes[i], frOrientation, frOrigin); + Plane = XMPlaneNormalize(Plane); + + XMVECTOR AxisDotOrigin = XMPlaneDotCoord(Plane, rayOrigin); + XMVECTOR AxisDotDirection = XMVector3Dot(Plane, Direction); + + if (XMVector3LessOrEqual(XMVectorAbs(AxisDotDirection), g_RayEpsilon)) + { + // Ray is parallel to plane - check if ray origin is inside plane's + if (XMVector3Greater(AxisDotOrigin, g_XMZero)) + { + // Ray origin is outside half-space. + Dist = 0.f; + return false; + } + } + else + { + // Ray not parallel - get distance to plane. + float vd = XMVectorGetX(AxisDotDirection); + float vn = XMVectorGetX(AxisDotOrigin); + float t = -vn / vd; + if (vd < 0.0f) + { + // Front face - T is a near point. + if (t > tfar) + { + Dist = 0.f; + return false; + } + if (t > tnear) + { + // Hit near face. + tnear = t; + } + } + else + { + // back face - T is far point. + if (t < tnear) + { + Dist = 0.f; + return false; + } + if (t < tfar) + { + // Hit far face. + tfar = t; + } + } + } + } + + // Survived all tests. + // Note: if ray originates on polyhedron, may want to change 0.0f to some + // epsilon to avoid intersecting the originating face. + float distance = (tnear >= 0.0f) ? tnear : tfar; + if (distance >= 0.0f) + { + Dist = distance; + return true; + } + + Dist = 0.f; + return false; +} + + +//----------------------------------------------------------------------------- +// Test a frustum vs 6 planes (typically forming another frustum). +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline ContainmentType XM_CALLCONV BoundingFrustum::ContainedBy( + FXMVECTOR Plane0, FXMVECTOR Plane1, FXMVECTOR Plane2, + GXMVECTOR Plane3, + HXMVECTOR Plane4, HXMVECTOR Plane5) const noexcept +{ + // Load origin and orientation of the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + assert(DirectX::MathInternal::XMQuaternionIsUnit(vOrientation)); + + // Set w of the origin to one so we can dot4 with a plane. + vOrigin = XMVectorInsert<0, 0, 0, 0, 1>(vOrigin, XMVectorSplatOne()); + + // Build the corners of the frustum (in world space). + XMVECTOR RightTop = XMVectorSet(RightSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR RightBottom = XMVectorSet(RightSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR LeftTop = XMVectorSet(LeftSlope, TopSlope, 1.0f, 0.0f); + XMVECTOR LeftBottom = XMVectorSet(LeftSlope, BottomSlope, 1.0f, 0.0f); + XMVECTOR vNear = XMVectorReplicatePtr(&Near); + XMVECTOR vFar = XMVectorReplicatePtr(&Far); + + RightTop = XMVector3Rotate(RightTop, vOrientation); + RightBottom = XMVector3Rotate(RightBottom, vOrientation); + LeftTop = XMVector3Rotate(LeftTop, vOrientation); + LeftBottom = XMVector3Rotate(LeftBottom, vOrientation); + + XMVECTOR Corners0 = XMVectorMultiplyAdd(RightTop, vNear, vOrigin); + XMVECTOR Corners1 = XMVectorMultiplyAdd(RightBottom, vNear, vOrigin); + XMVECTOR Corners2 = XMVectorMultiplyAdd(LeftTop, vNear, vOrigin); + XMVECTOR Corners3 = XMVectorMultiplyAdd(LeftBottom, vNear, vOrigin); + XMVECTOR Corners4 = XMVectorMultiplyAdd(RightTop, vFar, vOrigin); + XMVECTOR Corners5 = XMVectorMultiplyAdd(RightBottom, vFar, vOrigin); + XMVECTOR Corners6 = XMVectorMultiplyAdd(LeftTop, vFar, vOrigin); + XMVECTOR Corners7 = XMVectorMultiplyAdd(LeftBottom, vFar, vOrigin); + + XMVECTOR Outside, Inside; + + // Test against each plane. + DirectX::MathInternal::FastIntersectFrustumPlane(Corners0, Corners1, Corners2, Corners3, + Corners4, Corners5, Corners6, Corners7, + Plane0, Outside, Inside); + + XMVECTOR AnyOutside = Outside; + XMVECTOR AllInside = Inside; + + DirectX::MathInternal::FastIntersectFrustumPlane(Corners0, Corners1, Corners2, Corners3, + Corners4, Corners5, Corners6, Corners7, + Plane1, Outside, Inside); + + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectFrustumPlane(Corners0, Corners1, Corners2, Corners3, + Corners4, Corners5, Corners6, Corners7, + Plane2, Outside, Inside); + + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectFrustumPlane(Corners0, Corners1, Corners2, Corners3, + Corners4, Corners5, Corners6, Corners7, + Plane3, Outside, Inside); + + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectFrustumPlane(Corners0, Corners1, Corners2, Corners3, + Corners4, Corners5, Corners6, Corners7, + Plane4, Outside, Inside); + + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectFrustumPlane(Corners0, Corners1, Corners2, Corners3, + Corners4, Corners5, Corners6, Corners7, + Plane5, Outside, Inside); + + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + // If the frustum is outside any plane it is outside. + if (XMVector4EqualInt(AnyOutside, XMVectorTrueInt())) + return DISJOINT; + + // If the frustum is inside all planes it is inside. + if (XMVector4EqualInt(AllInside, XMVectorTrueInt())) + return CONTAINS; + + // The frustum is not inside all planes or outside a plane, it may intersect. + return INTERSECTS; +} + + +//----------------------------------------------------------------------------- +// Build the 6 frustum planes from a frustum. +// +// The intended use for these routines is for fast culling to a view frustum. +// When the volume being tested against a view frustum is small relative to the +// view frustum it is usually either inside all six planes of the frustum +// (CONTAINS) or outside one of the planes of the frustum (DISJOINT). If neither +// of these cases is true then it may or may not be intersecting the frustum +// (INTERSECTS) +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void BoundingFrustum::GetPlanes(XMVECTOR* NearPlane, XMVECTOR* FarPlane, XMVECTOR* RightPlane, + XMVECTOR* LeftPlane, XMVECTOR* TopPlane, XMVECTOR* BottomPlane) const noexcept +{ + // Load origin and orientation of the frustum. + XMVECTOR vOrigin = XMLoadFloat3(&Origin); + XMVECTOR vOrientation = XMLoadFloat4(&Orientation); + + if (NearPlane) + { + XMVECTOR vNearPlane = XMVectorSet(0.0f, 0.0f, -1.0f, Near); + vNearPlane = DirectX::MathInternal::XMPlaneTransform(vNearPlane, vOrientation, vOrigin); + *NearPlane = XMPlaneNormalize(vNearPlane); + } + + if (FarPlane) + { + XMVECTOR vFarPlane = XMVectorSet(0.0f, 0.0f, 1.0f, -Far); + vFarPlane = DirectX::MathInternal::XMPlaneTransform(vFarPlane, vOrientation, vOrigin); + *FarPlane = XMPlaneNormalize(vFarPlane); + } + + if (RightPlane) + { + XMVECTOR vRightPlane = XMVectorSet(1.0f, 0.0f, -RightSlope, 0.0f); + vRightPlane = DirectX::MathInternal::XMPlaneTransform(vRightPlane, vOrientation, vOrigin); + *RightPlane = XMPlaneNormalize(vRightPlane); + } + + if (LeftPlane) + { + XMVECTOR vLeftPlane = XMVectorSet(-1.0f, 0.0f, LeftSlope, 0.0f); + vLeftPlane = DirectX::MathInternal::XMPlaneTransform(vLeftPlane, vOrientation, vOrigin); + *LeftPlane = XMPlaneNormalize(vLeftPlane); + } + + if (TopPlane) + { + XMVECTOR vTopPlane = XMVectorSet(0.0f, 1.0f, -TopSlope, 0.0f); + vTopPlane = DirectX::MathInternal::XMPlaneTransform(vTopPlane, vOrientation, vOrigin); + *TopPlane = XMPlaneNormalize(vTopPlane); + } + + if (BottomPlane) + { + XMVECTOR vBottomPlane = XMVectorSet(0.0f, -1.0f, BottomSlope, 0.0f); + vBottomPlane = DirectX::MathInternal::XMPlaneTransform(vBottomPlane, vOrientation, vOrigin); + *BottomPlane = XMPlaneNormalize(vBottomPlane); + } +} + + +//----------------------------------------------------------------------------- +// Build a frustum from a persepective projection matrix. The matrix may only +// contain a projection; any rotation, translation or scale will cause the +// constructed frustum to be incorrect. +//----------------------------------------------------------------------------- +_Use_decl_annotations_ +inline void XM_CALLCONV BoundingFrustum::CreateFromMatrix(BoundingFrustum& Out, FXMMATRIX Projection, bool rhcoords) noexcept +{ + // Corners of the projection frustum in NDC space. + static XMVECTORF32 NDCPoints[6] = + { + { { { 1.0f, 0.0f, 1.0f, 1.0f } } }, // right (at far plane) + { { { -1.0f, 0.0f, 1.0f, 1.0f } } }, // left + { { { 0.0f, 1.0f, 1.0f, 1.0f } } }, // top + { { { 0.0f, -1.0f, 1.0f, 1.0f } } }, // bottom + + { { { 0.0f, 0.0f, 0.0f, 1.0f } } }, // near + { { { 0.0f, 0.0f, 1.0f, 1.0f } } } // far + }; + + XMVECTOR Determinant; + XMMATRIX matInverse = XMMatrixInverse(&Determinant, Projection); + + // Compute the frustum corners in world space. + XMVECTOR Points[6]; + + for (size_t i = 0; i < 6; ++i) + { + // Transform point. + Points[i] = XMVector4Transform(NDCPoints[i], matInverse); + } + + Out.Origin = XMFLOAT3(0.0f, 0.0f, 0.0f); + Out.Orientation = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f); + + // Compute the slopes. + Points[0] = XMVectorMultiply(Points[0], XMVectorReciprocal(XMVectorSplatZ(Points[0]))); + Points[1] = XMVectorMultiply(Points[1], XMVectorReciprocal(XMVectorSplatZ(Points[1]))); + Points[2] = XMVectorMultiply(Points[2], XMVectorReciprocal(XMVectorSplatZ(Points[2]))); + Points[3] = XMVectorMultiply(Points[3], XMVectorReciprocal(XMVectorSplatZ(Points[3]))); + + Out.RightSlope = XMVectorGetX(Points[0]); + Out.LeftSlope = XMVectorGetX(Points[1]); + Out.TopSlope = XMVectorGetY(Points[2]); + Out.BottomSlope = XMVectorGetY(Points[3]); + + // Compute near and far. + Points[4] = XMVectorMultiply(Points[4], XMVectorReciprocal(XMVectorSplatW(Points[4]))); + Points[5] = XMVectorMultiply(Points[5], XMVectorReciprocal(XMVectorSplatW(Points[5]))); + + if (rhcoords) + { + Out.Near = XMVectorGetZ(Points[5]); + Out.Far = XMVectorGetZ(Points[4]); + } + else + { + Out.Near = XMVectorGetZ(Points[4]); + Out.Far = XMVectorGetZ(Points[5]); + } +} + + +/**************************************************************************** + * + * TriangleTests + * + ****************************************************************************/ + +namespace TriangleTests +{ + + //----------------------------------------------------------------------------- + // Compute the intersection of a ray (Origin, Direction) with a triangle + // (V0, V1, V2). Return true if there is an intersection and also set *pDist + // to the distance along the ray to the intersection. + // + // The algorithm is based on Moller, Tomas and Trumbore, "Fast, Minimum Storage + // Ray-Triangle Intersection", Journal of Graphics Tools, vol. 2, no. 1, + // pp 21-28, 1997. + //----------------------------------------------------------------------------- + _Use_decl_annotations_ + inline bool XM_CALLCONV Intersects( + FXMVECTOR Origin, FXMVECTOR Direction, FXMVECTOR V0, + GXMVECTOR V1, + HXMVECTOR V2, float& Dist) noexcept + { + assert(DirectX::MathInternal::XMVector3IsUnit(Direction)); + + XMVECTOR Zero = XMVectorZero(); + + XMVECTOR e1 = XMVectorSubtract(V1, V0); + XMVECTOR e2 = XMVectorSubtract(V2, V0); + + // p = Direction ^ e2; + XMVECTOR p = XMVector3Cross(Direction, e2); + + // det = e1 * p; + XMVECTOR det = XMVector3Dot(e1, p); + + XMVECTOR u, v, t; + + if (XMVector3GreaterOrEqual(det, g_RayEpsilon)) + { + // Determinate is positive (front side of the triangle). + XMVECTOR s = XMVectorSubtract(Origin, V0); + + // u = s * p; + u = XMVector3Dot(s, p); + + XMVECTOR NoIntersection = XMVectorLess(u, Zero); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(u, det)); + + // q = s ^ e1; + XMVECTOR q = XMVector3Cross(s, e1); + + // v = Direction * q; + v = XMVector3Dot(Direction, q); + + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(v, Zero)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(XMVectorAdd(u, v), det)); + + // t = e2 * q; + t = XMVector3Dot(e2, q); + + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(t, Zero)); + + if (XMVector4EqualInt(NoIntersection, XMVectorTrueInt())) + { + Dist = 0.f; + return false; + } + } + else if (XMVector3LessOrEqual(det, g_RayNegEpsilon)) + { + // Determinate is negative (back side of the triangle). + XMVECTOR s = XMVectorSubtract(Origin, V0); + + // u = s * p; + u = XMVector3Dot(s, p); + + XMVECTOR NoIntersection = XMVectorGreater(u, Zero); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(u, det)); + + // q = s ^ e1; + XMVECTOR q = XMVector3Cross(s, e1); + + // v = Direction * q; + v = XMVector3Dot(Direction, q); + + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(v, Zero)); + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorLess(XMVectorAdd(u, v), det)); + + // t = e2 * q; + t = XMVector3Dot(e2, q); + + NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(t, Zero)); + + if (XMVector4EqualInt(NoIntersection, XMVectorTrueInt())) + { + Dist = 0.f; + return false; + } + } + else + { + // Parallel ray. + Dist = 0.f; + return false; + } + + t = XMVectorDivide(t, det); + + // (u / det) and (v / dev) are the barycentric cooridinates of the intersection. + + // Store the x-component to *pDist + XMStoreFloat(&Dist, t); + + return true; + } + + + //----------------------------------------------------------------------------- + // Test if two triangles intersect. + // + // The final test of algorithm is based on Shen, Heng, and Tang, "A Fast + // Triangle-Triangle Overlap Test Using Signed Distances", Journal of Graphics + // Tools, vol. 8, no. 1, pp 17-23, 2003 and Guigue and Devillers, "Fast and + // Robust Triangle-Triangle Overlap Test Using Orientation Predicates", Journal + // of Graphics Tools, vol. 8, no. 1, pp 25-32, 2003. + // + // The final test could be considered an edge-edge separating plane test with + // the 9 possible cases narrowed down to the only two pairs of edges that can + // actaully result in a seperation. + //----------------------------------------------------------------------------- + _Use_decl_annotations_ + inline bool XM_CALLCONV Intersects(FXMVECTOR A0, FXMVECTOR A1, FXMVECTOR A2, GXMVECTOR B0, HXMVECTOR B1, HXMVECTOR B2) noexcept + { + static const XMVECTORU32 SelectY = { { { XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_0 } } }; + static const XMVECTORU32 SelectZ = { { { XM_SELECT_0, XM_SELECT_0, XM_SELECT_1, XM_SELECT_0 } } }; + static const XMVECTORU32 Select0111 = { { { XM_SELECT_0, XM_SELECT_1, XM_SELECT_1, XM_SELECT_1 } } }; + static const XMVECTORU32 Select1011 = { { { XM_SELECT_1, XM_SELECT_0, XM_SELECT_1, XM_SELECT_1 } } }; + static const XMVECTORU32 Select1101 = { { { XM_SELECT_1, XM_SELECT_1, XM_SELECT_0, XM_SELECT_1 } } }; + + XMVECTOR Zero = XMVectorZero(); + + // Compute the normal of triangle A. + XMVECTOR N1 = XMVector3Cross(XMVectorSubtract(A1, A0), XMVectorSubtract(A2, A0)); + + // Assert that the triangle is not degenerate. + assert(!XMVector3Equal(N1, Zero)); + + // Test points of B against the plane of A. + XMVECTOR BDist = XMVector3Dot(N1, XMVectorSubtract(B0, A0)); + BDist = XMVectorSelect(BDist, XMVector3Dot(N1, XMVectorSubtract(B1, A0)), SelectY); + BDist = XMVectorSelect(BDist, XMVector3Dot(N1, XMVectorSubtract(B2, A0)), SelectZ); + + // Ensure robustness with co-planar triangles by zeroing small distances. + uint32_t BDistIsZeroCR; + XMVECTOR BDistIsZero = XMVectorGreaterR(&BDistIsZeroCR, g_RayEpsilon, XMVectorAbs(BDist)); + BDist = XMVectorSelect(BDist, Zero, BDistIsZero); + + uint32_t BDistIsLessCR; + XMVECTOR BDistIsLess = XMVectorGreaterR(&BDistIsLessCR, Zero, BDist); + + uint32_t BDistIsGreaterCR; + XMVECTOR BDistIsGreater = XMVectorGreaterR(&BDistIsGreaterCR, BDist, Zero); + + // If all the points are on the same side we don't intersect. + if (XMComparisonAllTrue(BDistIsLessCR) || XMComparisonAllTrue(BDistIsGreaterCR)) + return false; + + // Compute the normal of triangle B. + XMVECTOR N2 = XMVector3Cross(XMVectorSubtract(B1, B0), XMVectorSubtract(B2, B0)); + + // Assert that the triangle is not degenerate. + assert(!XMVector3Equal(N2, Zero)); + + // Test points of A against the plane of B. + XMVECTOR ADist = XMVector3Dot(N2, XMVectorSubtract(A0, B0)); + ADist = XMVectorSelect(ADist, XMVector3Dot(N2, XMVectorSubtract(A1, B0)), SelectY); + ADist = XMVectorSelect(ADist, XMVector3Dot(N2, XMVectorSubtract(A2, B0)), SelectZ); + + // Ensure robustness with co-planar triangles by zeroing small distances. + uint32_t ADistIsZeroCR; + XMVECTOR ADistIsZero = XMVectorGreaterR(&ADistIsZeroCR, g_RayEpsilon, XMVectorAbs(ADist)); + ADist = XMVectorSelect(ADist, Zero, ADistIsZero); + + uint32_t ADistIsLessCR; + XMVECTOR ADistIsLess = XMVectorGreaterR(&ADistIsLessCR, Zero, ADist); + + uint32_t ADistIsGreaterCR; + XMVECTOR ADistIsGreater = XMVectorGreaterR(&ADistIsGreaterCR, ADist, Zero); + + // If all the points are on the same side we don't intersect. + if (XMComparisonAllTrue(ADistIsLessCR) || XMComparisonAllTrue(ADistIsGreaterCR)) + return false; + + // Special case for co-planar triangles. + if (XMComparisonAllTrue(ADistIsZeroCR) || XMComparisonAllTrue(BDistIsZeroCR)) + { + XMVECTOR Axis, Dist, MinDist; + + // Compute an axis perpindicular to the edge (points out). + Axis = XMVector3Cross(N1, XMVectorSubtract(A1, A0)); + Dist = XMVector3Dot(Axis, A0); + + // Test points of B against the axis. + MinDist = XMVector3Dot(B0, Axis); + MinDist = XMVectorMin(MinDist, XMVector3Dot(B1, Axis)); + MinDist = XMVectorMin(MinDist, XMVector3Dot(B2, Axis)); + if (XMVector4GreaterOrEqual(MinDist, Dist)) + return false; + + // Edge (A1, A2) + Axis = XMVector3Cross(N1, XMVectorSubtract(A2, A1)); + Dist = XMVector3Dot(Axis, A1); + + MinDist = XMVector3Dot(B0, Axis); + MinDist = XMVectorMin(MinDist, XMVector3Dot(B1, Axis)); + MinDist = XMVectorMin(MinDist, XMVector3Dot(B2, Axis)); + if (XMVector4GreaterOrEqual(MinDist, Dist)) + return false; + + // Edge (A2, A0) + Axis = XMVector3Cross(N1, XMVectorSubtract(A0, A2)); + Dist = XMVector3Dot(Axis, A2); + + MinDist = XMVector3Dot(B0, Axis); + MinDist = XMVectorMin(MinDist, XMVector3Dot(B1, Axis)); + MinDist = XMVectorMin(MinDist, XMVector3Dot(B2, Axis)); + if (XMVector4GreaterOrEqual(MinDist, Dist)) + return false; + + // Edge (B0, B1) + Axis = XMVector3Cross(N2, XMVectorSubtract(B1, B0)); + Dist = XMVector3Dot(Axis, B0); + + MinDist = XMVector3Dot(A0, Axis); + MinDist = XMVectorMin(MinDist, XMVector3Dot(A1, Axis)); + MinDist = XMVectorMin(MinDist, XMVector3Dot(A2, Axis)); + if (XMVector4GreaterOrEqual(MinDist, Dist)) + return false; + + // Edge (B1, B2) + Axis = XMVector3Cross(N2, XMVectorSubtract(B2, B1)); + Dist = XMVector3Dot(Axis, B1); + + MinDist = XMVector3Dot(A0, Axis); + MinDist = XMVectorMin(MinDist, XMVector3Dot(A1, Axis)); + MinDist = XMVectorMin(MinDist, XMVector3Dot(A2, Axis)); + if (XMVector4GreaterOrEqual(MinDist, Dist)) + return false; + + // Edge (B2,B0) + Axis = XMVector3Cross(N2, XMVectorSubtract(B0, B2)); + Dist = XMVector3Dot(Axis, B2); + + MinDist = XMVector3Dot(A0, Axis); + MinDist = XMVectorMin(MinDist, XMVector3Dot(A1, Axis)); + MinDist = XMVectorMin(MinDist, XMVector3Dot(A2, Axis)); + if (XMVector4GreaterOrEqual(MinDist, Dist)) + return false; + + return true; + } + + // + // Find the single vertex of A and B (ie the vertex on the opposite side + // of the plane from the other two) and reorder the edges so we can compute + // the signed edge/edge distances. + // + // if ( (V0 >= 0 && V1 < 0 && V2 < 0) || + // (V0 > 0 && V1 <= 0 && V2 <= 0) || + // (V0 <= 0 && V1 > 0 && V2 > 0) || + // (V0 < 0 && V1 >= 0 && V2 >= 0) ) then V0 is singular; + // + // If our singular vertex is not on the positive side of the plane we reverse + // the triangle winding so that the overlap comparisons will compare the + // correct edges with the correct signs. + // + XMVECTOR ADistIsLessEqual = XMVectorOrInt(ADistIsLess, ADistIsZero); + XMVECTOR ADistIsGreaterEqual = XMVectorOrInt(ADistIsGreater, ADistIsZero); + + XMVECTOR AA0, AA1, AA2; + bool bPositiveA; + + if (DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(ADistIsGreaterEqual, ADistIsLess, Select0111)) || + DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(ADistIsGreater, ADistIsLessEqual, Select0111))) + { + // A0 is singular, crossing from positive to negative. + AA0 = A0; AA1 = A1; AA2 = A2; + bPositiveA = true; + } + else if (DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(ADistIsLessEqual, ADistIsGreater, Select0111)) || + DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(ADistIsLess, ADistIsGreaterEqual, Select0111))) + { + // A0 is singular, crossing from negative to positive. + AA0 = A0; AA1 = A2; AA2 = A1; + bPositiveA = false; + } + else if (DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(ADistIsGreaterEqual, ADistIsLess, Select1011)) || + DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(ADistIsGreater, ADistIsLessEqual, Select1011))) + { + // A1 is singular, crossing from positive to negative. + AA0 = A1; AA1 = A2; AA2 = A0; + bPositiveA = true; + } + else if (DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(ADistIsLessEqual, ADistIsGreater, Select1011)) || + DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(ADistIsLess, ADistIsGreaterEqual, Select1011))) + { + // A1 is singular, crossing from negative to positive. + AA0 = A1; AA1 = A0; AA2 = A2; + bPositiveA = false; + } + else if (DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(ADistIsGreaterEqual, ADistIsLess, Select1101)) || + DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(ADistIsGreater, ADistIsLessEqual, Select1101))) + { + // A2 is singular, crossing from positive to negative. + AA0 = A2; AA1 = A0; AA2 = A1; + bPositiveA = true; + } + else if (DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(ADistIsLessEqual, ADistIsGreater, Select1101)) || + DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(ADistIsLess, ADistIsGreaterEqual, Select1101))) + { + // A2 is singular, crossing from negative to positive. + AA0 = A2; AA1 = A1; AA2 = A0; + bPositiveA = false; + } + else + { + assert(false); + return false; + } + + XMVECTOR BDistIsLessEqual = XMVectorOrInt(BDistIsLess, BDistIsZero); + XMVECTOR BDistIsGreaterEqual = XMVectorOrInt(BDistIsGreater, BDistIsZero); + + XMVECTOR BB0, BB1, BB2; + bool bPositiveB; + + if (DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(BDistIsGreaterEqual, BDistIsLess, Select0111)) || + DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(BDistIsGreater, BDistIsLessEqual, Select0111))) + { + // B0 is singular, crossing from positive to negative. + BB0 = B0; BB1 = B1; BB2 = B2; + bPositiveB = true; + } + else if (DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(BDistIsLessEqual, BDistIsGreater, Select0111)) || + DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(BDistIsLess, BDistIsGreaterEqual, Select0111))) + { + // B0 is singular, crossing from negative to positive. + BB0 = B0; BB1 = B2; BB2 = B1; + bPositiveB = false; + } + else if (DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(BDistIsGreaterEqual, BDistIsLess, Select1011)) || + DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(BDistIsGreater, BDistIsLessEqual, Select1011))) + { + // B1 is singular, crossing from positive to negative. + BB0 = B1; BB1 = B2; BB2 = B0; + bPositiveB = true; + } + else if (DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(BDistIsLessEqual, BDistIsGreater, Select1011)) || + DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(BDistIsLess, BDistIsGreaterEqual, Select1011))) + { + // B1 is singular, crossing from negative to positive. + BB0 = B1; BB1 = B0; BB2 = B2; + bPositiveB = false; + } + else if (DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(BDistIsGreaterEqual, BDistIsLess, Select1101)) || + DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(BDistIsGreater, BDistIsLessEqual, Select1101))) + { + // B2 is singular, crossing from positive to negative. + BB0 = B2; BB1 = B0; BB2 = B1; + bPositiveB = true; + } + else if (DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(BDistIsLessEqual, BDistIsGreater, Select1101)) || + DirectX::MathInternal::XMVector3AllTrue(XMVectorSelect(BDistIsLess, BDistIsGreaterEqual, Select1101))) + { + // B2 is singular, crossing from negative to positive. + BB0 = B2; BB1 = B1; BB2 = B0; + bPositiveB = false; + } + else + { + assert(false); + return false; + } + + XMVECTOR Delta0, Delta1; + + // Reverse the direction of the test depending on whether the singular vertices are + // the same sign or different signs. + if (bPositiveA ^ bPositiveB) + { + Delta0 = XMVectorSubtract(BB0, AA0); + Delta1 = XMVectorSubtract(AA0, BB0); + } + else + { + Delta0 = XMVectorSubtract(AA0, BB0); + Delta1 = XMVectorSubtract(BB0, AA0); + } + + // Check if the triangles overlap on the line of intersection between the + // planes of the two triangles by finding the signed line distances. + XMVECTOR Dist0 = XMVector3Dot(Delta0, XMVector3Cross(XMVectorSubtract(BB2, BB0), XMVectorSubtract(AA2, AA0))); + if (XMVector4Greater(Dist0, Zero)) + return false; + + XMVECTOR Dist1 = XMVector3Dot(Delta1, XMVector3Cross(XMVectorSubtract(BB1, BB0), XMVectorSubtract(AA1, AA0))); + if (XMVector4Greater(Dist1, Zero)) + return false; + + return true; + } + + + //----------------------------------------------------------------------------- + // Ray-triangle test + //----------------------------------------------------------------------------- + _Use_decl_annotations_ + inline PlaneIntersectionType XM_CALLCONV Intersects(FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2, GXMVECTOR Plane) noexcept + { + XMVECTOR One = XMVectorSplatOne(); + + assert(DirectX::MathInternal::XMPlaneIsUnit(Plane)); + + // Set w of the points to one so we can dot4 with a plane. + XMVECTOR TV0 = XMVectorInsert<0, 0, 0, 0, 1>(V0, One); + XMVECTOR TV1 = XMVectorInsert<0, 0, 0, 0, 1>(V1, One); + XMVECTOR TV2 = XMVectorInsert<0, 0, 0, 0, 1>(V2, One); + + XMVECTOR Outside, Inside; + DirectX::MathInternal::FastIntersectTrianglePlane(TV0, TV1, TV2, Plane, Outside, Inside); + + // If the triangle is outside any plane it is outside. + if (XMVector4EqualInt(Outside, XMVectorTrueInt())) + return FRONT; + + // If the triangle is inside all planes it is inside. + if (XMVector4EqualInt(Inside, XMVectorTrueInt())) + return BACK; + + // The triangle is not inside all planes or outside a plane it intersects. + return INTERSECTING; + } + + + //----------------------------------------------------------------------------- + // Test a triangle vs 6 planes (typically forming a frustum). + //----------------------------------------------------------------------------- + _Use_decl_annotations_ + inline ContainmentType XM_CALLCONV ContainedBy( + FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2, + GXMVECTOR Plane0, + HXMVECTOR Plane1, HXMVECTOR Plane2, + CXMVECTOR Plane3, CXMVECTOR Plane4, CXMVECTOR Plane5) noexcept + { + XMVECTOR One = XMVectorSplatOne(); + + // Set w of the points to one so we can dot4 with a plane. + XMVECTOR TV0 = XMVectorInsert<0, 0, 0, 0, 1>(V0, One); + XMVECTOR TV1 = XMVectorInsert<0, 0, 0, 0, 1>(V1, One); + XMVECTOR TV2 = XMVectorInsert<0, 0, 0, 0, 1>(V2, One); + + XMVECTOR Outside, Inside; + + // Test against each plane. + DirectX::MathInternal::FastIntersectTrianglePlane(TV0, TV1, TV2, Plane0, Outside, Inside); + + XMVECTOR AnyOutside = Outside; + XMVECTOR AllInside = Inside; + + DirectX::MathInternal::FastIntersectTrianglePlane(TV0, TV1, TV2, Plane1, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectTrianglePlane(TV0, TV1, TV2, Plane2, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectTrianglePlane(TV0, TV1, TV2, Plane3, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectTrianglePlane(TV0, TV1, TV2, Plane4, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + DirectX::MathInternal::FastIntersectTrianglePlane(TV0, TV1, TV2, Plane5, Outside, Inside); + AnyOutside = XMVectorOrInt(AnyOutside, Outside); + AllInside = XMVectorAndInt(AllInside, Inside); + + // If the triangle is outside any plane it is outside. + if (XMVector4EqualInt(AnyOutside, XMVectorTrueInt())) + return DISJOINT; + + // If the triangle is inside all planes it is inside. + if (XMVector4EqualInt(AllInside, XMVectorTrueInt())) + return CONTAINS; + + // The triangle is not inside all planes or outside a plane, it may intersect. + return INTERSECTS; + } + +} // namespace TriangleTests diff --git a/directxmath/directxmath.h b/src/directxmath/DirectXMath.h similarity index 84% rename from directxmath/directxmath.h rename to src/directxmath/DirectXMath.h index ad46269..37b70c1 100644 --- a/directxmath/directxmath.h +++ b/src/directxmath/DirectXMath.h @@ -1,30 +1,25 @@ //------------------------------------------------------------------------------------- // DirectXMath.h -- SIMD C++ Math library // -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // -// http://go.microsoft.com/fwlink/?LinkID=615560 +// https://go.microsoft.com/fwlink/?LinkID=615560 //------------------------------------------------------------------------------------- #pragma once -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#endif - #ifndef __cplusplus #error DirectX Math requires C++ #endif -#define DIRECTX_MATH_VERSION 314 +#define DIRECTX_MATH_VERSION 321 #if defined(_MSC_VER) && (_MSC_VER < 1910) #error DirectX Math requires Visual C++ 2017 or later. #endif -#if defined(_MSC_VER) && !defined(_M_ARM) && !defined(_M_ARM64) && !defined(_M_HYBRID_X86_ARM64) && (!_MANAGED) && (!_M_CEE) && (!defined(_M_IX86_FP) || (_M_IX86_FP > 1)) && !defined(_XM_NO_INTRINSICS_) && !defined(_XM_VECTORCALL_) +#if defined(_MSC_VER) && !defined(_M_ARM) && !defined(_M_ARM64) && !defined(_M_HYBRID_X86_ARM64) && !defined(_M_ARM64EC) && (!_MANAGED) && (!_M_CEE) && (!defined(_M_IX86_FP) || (_M_IX86_FP > 1)) && !defined(_XM_NO_INTRINSICS_) && !defined(_XM_VECTORCALL_) #define _XM_VECTORCALL_ 1 #endif @@ -37,7 +32,9 @@ #endif #ifndef XM_DEPRECATED -#ifdef __GNUC__ +#if (__cplusplus >= 201402L) +#define XM_DEPRECATED [[deprecated]] +#elif defined(__GNUC__) #define XM_DEPRECATED __attribute__ ((deprecated)) #else #define XM_DEPRECATED __declspec(deprecated("This is deprecated and will be removed in a future version.")) @@ -85,25 +82,33 @@ #endif #if !defined(_XM_ARM_NEON_INTRINSICS_) && !defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) -#if (defined(_M_IX86) || defined(_M_X64) || __i386__ || __x86_64__) && !defined(_M_HYBRID_X86_ARM64) +#if (defined(_M_IX86) || defined(_M_X64) || __i386__ || __x86_64__ || __powerpc64__) && !defined(_M_HYBRID_X86_ARM64) && !defined(_M_ARM64EC) #define _XM_SSE_INTRINSICS_ -#elif defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __arm__ || __aarch64__ +#elif defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __arm__ || __aarch64__ #define _XM_ARM_NEON_INTRINSICS_ #elif !defined(_XM_NO_INTRINSICS_) #error DirectX Math does not support this target #endif #endif // !_XM_ARM_NEON_INTRINSICS_ && !_XM_SSE_INTRINSICS_ && !_XM_NO_INTRINSICS_ -#if !defined(_XM_NO_XMVECTOR_OVERLOADS_) && (defined(__clang__) || defined(__GNUC__)) +#if defined(_XM_SSE_INTRINSICS_) && defined(_MSC_VER) && (_MSC_VER >= 1920) && !defined(__clang__) && !defined(_XM_SVML_INTRINSICS_) && !defined(_XM_DISABLE_INTEL_SVML_) +#define _XM_SVML_INTRINSICS_ +#endif + +#if !defined(_XM_NO_XMVECTOR_OVERLOADS_) && (defined(__clang__) || defined(__GNUC__)) && !defined(_XM_NO_INTRINSICS_) #define _XM_NO_XMVECTOR_OVERLOADS_ #endif +#ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4514 4820) // C4514/4820: Off by default noise +#endif //#include #include +#ifdef _MSC_VER #pragma warning(pop) +#endif #ifndef _XM_NO_INTRINSICS_ @@ -111,11 +116,15 @@ #pragma warning(push) #pragma warning(disable : 4987) // C4987: Off by default noise +#endif +#if defined(_MSC_VER) || defined(__MINGW32__) #include +#endif +#ifdef _MSC_VER #pragma warning(pop) #endif -#if (defined(__clang__) || defined(__GNUC__)) && (__x86_64__ || __i386__) +#if (defined(__clang__) || defined(__GNUC__)) && (__x86_64__ || __i386__) && !defined(__MINGW32__) && !defined(_MSC_VER) #include #endif @@ -136,7 +145,7 @@ #endif #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64)) +#if defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC)) #include #else #include @@ -147,11 +156,14 @@ #include "sal.h" //#include #define assert(x) -#define isnan(x) __builtin_isnan(x) +#define isnan(x) (false) #define floorf(x) __builtin_floorf(x) #define sqrtf(x) __builtin_sqrtf(x) #define expf(x) __builtin_expf(x) +#define exp2f(x) __builtin_exp2f(x) #define logf(x) __builtin_logf(x) +#define log2f(x) __builtin_log2f(x) +#define log10f(x) __builtin_log10f(x) #define powf(x, y) __builtin_powf(x, y) #define fabsf(x) __builtin_fabsf(x) #define sinf(x) __builtin_sinf(x) @@ -164,18 +176,25 @@ #define coshf(x) __builtin_coshf(x) #define atanf(x) __builtin_atanf(x) #define atan2f(x, y) __builtin_atan2f(x, y) -#define isinf(x) __builtin_isinf(x) +#define isinf(x) (false) #define ceilf(x) __builtin_ceilf(x) #define modff(x, y) __builtin_modff(x, y) #include +#ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4005 4668) // C4005/4668: Old header issue +#endif #include +#ifdef _MSC_VER #pragma warning(pop) +#endif -#ifdef __GNUC__ +#if (__cplusplus >= 201703L) +#define XM_ALIGNED_DATA(x) alignas(x) +#define XM_ALIGNED_STRUCT(x) struct alignas(x) +#elif defined(__GNUC__) #define XM_ALIGNED_DATA(x) __attribute__ ((aligned(x))) #define XM_ALIGNED_STRUCT(x) struct __attribute__ ((aligned(x))) #else @@ -183,6 +202,10 @@ #define XM_ALIGNED_STRUCT(x) __declspec(align(x)) struct #endif +#if (__cplusplus >= 202002L) +#include +#endif + /**************************************************************************** * * Conditional intrinsics @@ -215,11 +238,17 @@ #define XM_PERMUTE_PS( v, c ) _mm_shuffle_ps((v), (v), c ) #endif +#if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 11)) || defined(__powerpc64__) +#define XM_LOADU_SI16( p ) _mm_cvtsi32_si128(*reinterpret_cast(p)) +#else +#define XM_LOADU_SI16( p ) _mm_loadu_si16(p) +#endif + #endif // _XM_SSE_INTRINSICS_ && !_XM_NO_INTRINSICS_ #if defined(_XM_ARM_NEON_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) -#if defined(__clang__) +#if defined(__clang__) || defined(__GNUC__) #define XM_PREFETCH( a ) __builtin_prefetch(a) #elif defined(_MSC_VER) #define XM_PREFETCH( a ) __prefetch(a) @@ -291,7 +320,11 @@ namespace DirectX constexpr uint32_t XM_CRMASK_CR6FALSE = 0x00000020; constexpr uint32_t XM_CRMASK_CR6BOUNDS = XM_CRMASK_CR6FALSE; +#if defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __arm__ || __aarch64__ + constexpr size_t XM_CACHE_LINE_SIZE = 128; +#else constexpr size_t XM_CACHE_LINE_SIZE = 64; +#endif /**************************************************************************** @@ -310,20 +343,20 @@ namespace DirectX #undef XMComparisonAnyOutOfBounds #endif - // Unit conversion + // Unit conversion - inline constexpr float XMConvertToRadians(float fDegrees) noexcept { return fDegrees * (XM_PI / 180.0f); } - inline constexpr float XMConvertToDegrees(float fRadians) noexcept { return fRadians * (180.0f / XM_PI); } + constexpr float XMConvertToRadians(float fDegrees) noexcept { return fDegrees * (XM_PI / 180.0f); } + constexpr float XMConvertToDegrees(float fRadians) noexcept { return fRadians * (180.0f / XM_PI); } // Condition register evaluation proceeding a recording (R) comparison - inline constexpr bool XMComparisonAllTrue(uint32_t CR) noexcept { return (((CR)&XM_CRMASK_CR6TRUE) == XM_CRMASK_CR6TRUE); } - inline constexpr bool XMComparisonAnyTrue(uint32_t CR) noexcept { return (((CR)&XM_CRMASK_CR6FALSE) != XM_CRMASK_CR6FALSE); } - inline constexpr bool XMComparisonAllFalse(uint32_t CR) noexcept { return (((CR)&XM_CRMASK_CR6FALSE) == XM_CRMASK_CR6FALSE); } - inline constexpr bool XMComparisonAnyFalse(uint32_t CR) noexcept { return (((CR)&XM_CRMASK_CR6TRUE) != XM_CRMASK_CR6TRUE); } - inline constexpr bool XMComparisonMixed(uint32_t CR) noexcept { return (((CR)&XM_CRMASK_CR6) == 0); } - inline constexpr bool XMComparisonAllInBounds(uint32_t CR) noexcept { return (((CR)&XM_CRMASK_CR6BOUNDS) == XM_CRMASK_CR6BOUNDS); } - inline constexpr bool XMComparisonAnyOutOfBounds(uint32_t CR) noexcept { return (((CR)&XM_CRMASK_CR6BOUNDS) != XM_CRMASK_CR6BOUNDS); } + constexpr bool XMComparisonAllTrue(uint32_t CR) noexcept { return (CR & XM_CRMASK_CR6TRUE) == XM_CRMASK_CR6TRUE; } + constexpr bool XMComparisonAnyTrue(uint32_t CR) noexcept { return (CR & XM_CRMASK_CR6FALSE) != XM_CRMASK_CR6FALSE; } + constexpr bool XMComparisonAllFalse(uint32_t CR) noexcept { return (CR & XM_CRMASK_CR6FALSE) == XM_CRMASK_CR6FALSE; } + constexpr bool XMComparisonAnyFalse(uint32_t CR) noexcept { return (CR & XM_CRMASK_CR6TRUE) != XM_CRMASK_CR6TRUE; } + constexpr bool XMComparisonMixed(uint32_t CR) noexcept { return (CR & XM_CRMASK_CR6) == 0; } + constexpr bool XMComparisonAllInBounds(uint32_t CR) noexcept { return (CR & XM_CRMASK_CR6BOUNDS) == XM_CRMASK_CR6BOUNDS; } + constexpr bool XMComparisonAnyOutOfBounds(uint32_t CR) noexcept { return (CR & XM_CRMASK_CR6BOUNDS) != XM_CRMASK_CR6BOUNDS; } /**************************************************************************** @@ -332,12 +365,14 @@ namespace DirectX * ****************************************************************************/ +#ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4068 4201 4365 4324 4820) - // C4068: ignore unknown pragmas - // C4201: nonstandard extension used : nameless struct/union - // C4365: Off by default noise - // C4324/4820: padding warnings + // C4068: ignore unknown pragmas + // C4201: nonstandard extension used : nameless struct/union + // C4365: Off by default noise + // C4324/4820: padding warnings +#endif #ifdef _PREFAST_ #pragma prefast(push) @@ -360,11 +395,11 @@ namespace DirectX // Vector intrinsic: Four 32 bit floating point components aligned on a 16 byte // boundary and mapped to hardware vector registers #if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) - typedef __m128 XMVECTOR; + using XMVECTOR = __m128; #elif defined(_XM_ARM_NEON_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) - typedef float32x4_t XMVECTOR; + using XMVECTOR = float32x4_t; #else - typedef __vector4 XMVECTOR; + using XMVECTOR = __vector4; #endif // Fix-up for (1st-3rd) XMVECTOR parameters that are pass-in-register for x86, ARM, ARM64, and vector call; by reference otherwise @@ -374,15 +409,15 @@ namespace DirectX typedef const XMVECTOR& FXMVECTOR; #endif - // Fix-up for (4th) XMVECTOR parameter to pass in-register for ARM, ARM64, and x64 vector call; by reference otherwise -#if ( defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || (_XM_VECTORCALL_ && !defined(_M_IX86) ) || __arm__ || __aarch64__ ) && !defined(_XM_NO_INTRINSICS_) + // Fix-up for (4th) XMVECTOR parameter to pass in-register for ARM, ARM64, and vector call; by reference otherwise +#if ( defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || _XM_VECTORCALL_ || __arm__ || __aarch64__ ) && !defined(_XM_NO_INTRINSICS_) typedef const XMVECTOR GXMVECTOR; #else typedef const XMVECTOR& GXMVECTOR; #endif // Fix-up for (5th & 6th) XMVECTOR parameter to pass in-register for ARM64 and vector call; by reference otherwise -#if ( defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || _XM_VECTORCALL_ || __aarch64__ ) && !defined(_XM_NO_INTRINSICS_) +#if ( defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || _XM_VECTORCALL_ || __aarch64__ ) && !defined(_XM_NO_INTRINSICS_) typedef const XMVECTOR HXMVECTOR; #else typedef const XMVECTOR& HXMVECTOR; @@ -403,10 +438,14 @@ namespace DirectX inline operator XMVECTOR() const noexcept { return v; } inline operator const float* () const noexcept { return f; } -#if !defined(_XM_NO_INTRINSICS_) && defined(_XM_SSE_INTRINSICS_) + #ifdef _XM_NO_INTRINSICS_ + #elif defined(_XM_SSE_INTRINSICS_) inline operator __m128i() const noexcept { return _mm_castps_si128(v); } inline operator __m128d() const noexcept { return _mm_castps_pd(v); } -#endif + #elif defined(_XM_ARM_NEON_INTRINSICS_) && (defined(__GNUC__) || defined(_ARM64_DISTINCT_NEON_TYPES)) + inline operator int32x4_t() const noexcept { return vreinterpretq_s32_f32(v); } + inline operator uint32x4_t() const noexcept { return vreinterpretq_u32_f32(v); } + #endif }; XM_ALIGNED_STRUCT(16) XMVECTORI32 @@ -418,10 +457,14 @@ namespace DirectX }; inline operator XMVECTOR() const noexcept { return v; } -#if !defined(_XM_NO_INTRINSICS_) && defined(_XM_SSE_INTRINSICS_) + #ifdef _XM_NO_INTRINSICS_ + #elif defined(_XM_SSE_INTRINSICS_) inline operator __m128i() const noexcept { return _mm_castps_si128(v); } inline operator __m128d() const noexcept { return _mm_castps_pd(v); } -#endif + #elif defined(_XM_ARM_NEON_INTRINSICS_) && (defined(__GNUC__) || defined(_ARM64_DISTINCT_NEON_TYPES)) + inline operator int32x4_t() const noexcept { return vreinterpretq_s32_f32(v); } + inline operator uint32x4_t() const noexcept { return vreinterpretq_u32_f32(v); } + #endif }; XM_ALIGNED_STRUCT(16) XMVECTORU8 @@ -433,10 +476,14 @@ namespace DirectX }; inline operator XMVECTOR() const noexcept { return v; } -#if !defined(_XM_NO_INTRINSICS_) && defined(_XM_SSE_INTRINSICS_) + #ifdef _XM_NO_INTRINSICS_ + #elif defined(_XM_SSE_INTRINSICS_) inline operator __m128i() const noexcept { return _mm_castps_si128(v); } inline operator __m128d() const noexcept { return _mm_castps_pd(v); } -#endif + #elif defined(_XM_ARM_NEON_INTRINSICS_) && (defined(__GNUC__) || defined(_ARM64_DISTINCT_NEON_TYPES)) + inline operator int32x4_t() const noexcept { return vreinterpretq_s32_f32(v); } + inline operator uint32x4_t() const noexcept { return vreinterpretq_u32_f32(v); } + #endif }; XM_ALIGNED_STRUCT(16) XMVECTORU32 @@ -448,10 +495,14 @@ namespace DirectX }; inline operator XMVECTOR() const noexcept { return v; } -#if !defined(_XM_NO_INTRINSICS_) && defined(_XM_SSE_INTRINSICS_) + #ifdef _XM_NO_INTRINSICS_ + #elif defined(_XM_SSE_INTRINSICS_) inline operator __m128i() const noexcept { return _mm_castps_si128(v); } inline operator __m128d() const noexcept { return _mm_castps_pd(v); } -#endif + #elif defined(_XM_ARM_NEON_INTRINSICS_) && (defined(__GNUC__) || defined(_ARM64_DISTINCT_NEON_TYPES)) + inline operator int32x4_t() const noexcept { return vreinterpretq_s32_f32(v); } + inline operator uint32x4_t() const noexcept { return vreinterpretq_u32_f32(v); } + #endif }; //------------------------------------------------------------------------------ @@ -461,10 +512,10 @@ namespace DirectX XMVECTOR XM_CALLCONV operator+ (FXMVECTOR V) noexcept; XMVECTOR XM_CALLCONV operator- (FXMVECTOR V) noexcept; - XMVECTOR& XM_CALLCONV operator+= (XMVECTOR& V1, FXMVECTOR V2) noexcept; - XMVECTOR& XM_CALLCONV operator-= (XMVECTOR& V1, FXMVECTOR V2) noexcept; - XMVECTOR& XM_CALLCONV operator*= (XMVECTOR& V1, FXMVECTOR V2) noexcept; - XMVECTOR& XM_CALLCONV operator/= (XMVECTOR& V1, FXMVECTOR V2) noexcept; + XMVECTOR& XM_CALLCONV operator+= (XMVECTOR& V1, FXMVECTOR V2) noexcept; + XMVECTOR& XM_CALLCONV operator-= (XMVECTOR& V1, FXMVECTOR V2) noexcept; + XMVECTOR& XM_CALLCONV operator*= (XMVECTOR& V1, FXMVECTOR V2) noexcept; + XMVECTOR& XM_CALLCONV operator/= (XMVECTOR& V1, FXMVECTOR V2) noexcept; XMVECTOR& operator*= (XMVECTOR& V, float S) noexcept; XMVECTOR& operator/= (XMVECTOR& V, float S) noexcept; @@ -485,7 +536,7 @@ namespace DirectX struct XMMATRIX; // Fix-up for (1st) XMMATRIX parameter to pass in-register for ARM64 and vector call; by reference otherwise -#if ( defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || _XM_VECTORCALL_ || __aarch64__ ) && !defined(_XM_NO_INTRINSICS_) +#if ( defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || _XM_VECTORCALL_ || __aarch64__ ) && !defined(_XM_NO_INTRINSICS_) typedef const XMMATRIX FXMMATRIX; #else typedef const XMMATRIX& FXMMATRIX; @@ -496,11 +547,11 @@ namespace DirectX #ifdef _XM_NO_INTRINSICS_ struct XMMATRIX -#else + #else XM_ALIGNED_STRUCT(16) XMMATRIX -#endif + #endif { -#ifdef _XM_NO_INTRINSICS_ + #ifdef _XM_NO_INTRINSICS_ union { XMVECTOR r[4]; @@ -513,22 +564,22 @@ namespace DirectX }; float m[4][4]; }; -#else + #else XMVECTOR r[4]; -#endif + #endif XMMATRIX() = default; XMMATRIX(const XMMATRIX&) = default; -#if defined(_MSC_VER) && (_MSC_FULL_VER < 191426431) + #if defined(_MSC_VER) && (_MSC_FULL_VER < 191426431) XMMATRIX& operator= (const XMMATRIX& M) noexcept { r[0] = M.r[0]; r[1] = M.r[1]; r[2] = M.r[2]; r[3] = M.r[3]; return *this; } -#else + #else XMMATRIX& operator=(const XMMATRIX&) = default; XMMATRIX(XMMATRIX&&) = default; XMMATRIX& operator=(XMMATRIX&&) = default; -#endif + #endif constexpr XMMATRIX(FXMVECTOR R0, FXMVECTOR R1, FXMVECTOR R2, CXMVECTOR R3) noexcept : r{ R0,R1,R2,R3 } {} XMMATRIX(float m00, float m01, float m02, float m03, @@ -537,19 +588,19 @@ namespace DirectX float m30, float m31, float m32, float m33) noexcept; explicit XMMATRIX(_In_reads_(16) const float* pArray) noexcept; -#ifdef _XM_NO_INTRINSICS_ + #ifdef _XM_NO_INTRINSICS_ float operator() (size_t Row, size_t Column) const noexcept { return m[Row][Column]; } float& operator() (size_t Row, size_t Column) noexcept { return m[Row][Column]; } -#endif + #endif XMMATRIX operator+ () const noexcept { return *this; } XMMATRIX operator- () const noexcept; - XMMATRIX& XM_CALLCONV operator+= (FXMMATRIX M) noexcept; - XMMATRIX& XM_CALLCONV operator-= (FXMMATRIX M) noexcept; - XMMATRIX& XM_CALLCONV operator*= (FXMMATRIX M) noexcept; - XMMATRIX& operator*= (float S) noexcept; - XMMATRIX& operator/= (float S) noexcept; + XMMATRIX& XM_CALLCONV operator+= (FXMMATRIX M) noexcept; + XMMATRIX& XM_CALLCONV operator-= (FXMMATRIX M) noexcept; + XMMATRIX& XM_CALLCONV operator*= (FXMMATRIX M) noexcept; + XMMATRIX& operator*= (float S) noexcept; + XMMATRIX& operator/= (float S) noexcept; XMMATRIX XM_CALLCONV operator+ (FXMMATRIX M) const noexcept; XMMATRIX XM_CALLCONV operator- (FXMMATRIX M) const noexcept; @@ -577,21 +628,17 @@ namespace DirectX constexpr XMFLOAT2(float _x, float _y) noexcept : x(_x), y(_y) {} explicit XMFLOAT2(_In_reads_(2) const float* pArray) noexcept : x(pArray[0]), y(pArray[1]) {} + + #if (__cplusplus >= 202002L) + bool operator == (const XMFLOAT2&) const = default; + auto operator <=> (const XMFLOAT2&) const = default; + #endif }; // 2D Vector; 32 bit floating point components aligned on a 16 byte boundary XM_ALIGNED_STRUCT(16) XMFLOAT2A : public XMFLOAT2 { - XMFLOAT2A() = default; - - XMFLOAT2A(const XMFLOAT2A&) = default; - XMFLOAT2A& operator=(const XMFLOAT2A&) = default; - - XMFLOAT2A(XMFLOAT2A&&) = default; - XMFLOAT2A& operator=(XMFLOAT2A&&) = default; - - constexpr XMFLOAT2A(float _x, float _y) noexcept : XMFLOAT2(_x, _y) {} - explicit XMFLOAT2A(_In_reads_(2) const float* pArray) noexcept : XMFLOAT2(pArray) {} + using XMFLOAT2::XMFLOAT2; }; //------------------------------------------------------------------------------ @@ -611,6 +658,11 @@ namespace DirectX constexpr XMINT2(int32_t _x, int32_t _y) noexcept : x(_x), y(_y) {} explicit XMINT2(_In_reads_(2) const int32_t* pArray) noexcept : x(pArray[0]), y(pArray[1]) {} + + #if (__cplusplus >= 202002L) + bool operator == (const XMINT2&) const = default; + auto operator <=> (const XMINT2&) const = default; + #endif }; // 2D Vector; 32 bit unsigned integer components @@ -629,6 +681,11 @@ namespace DirectX constexpr XMUINT2(uint32_t _x, uint32_t _y) noexcept : x(_x), y(_y) {} explicit XMUINT2(_In_reads_(2) const uint32_t* pArray) noexcept : x(pArray[0]), y(pArray[1]) {} + + #if (__cplusplus >= 202002L) + bool operator == (const XMUINT2&) const = default; + auto operator <=> (const XMUINT2&) const = default; + #endif }; //------------------------------------------------------------------------------ @@ -649,21 +706,17 @@ namespace DirectX constexpr XMFLOAT3(float _x, float _y, float _z) noexcept : x(_x), y(_y), z(_z) {} explicit XMFLOAT3(_In_reads_(3) const float* pArray) noexcept : x(pArray[0]), y(pArray[1]), z(pArray[2]) {} + + #if (__cplusplus >= 202002L) + bool operator == (const XMFLOAT3&) const = default; + auto operator <=> (const XMFLOAT3&) const = default; + #endif }; // 3D Vector; 32 bit floating point components aligned on a 16 byte boundary XM_ALIGNED_STRUCT(16) XMFLOAT3A : public XMFLOAT3 { - XMFLOAT3A() = default; - - XMFLOAT3A(const XMFLOAT3A&) = default; - XMFLOAT3A& operator=(const XMFLOAT3A&) = default; - - XMFLOAT3A(XMFLOAT3A&&) = default; - XMFLOAT3A& operator=(XMFLOAT3A&&) = default; - - constexpr XMFLOAT3A(float _x, float _y, float _z) noexcept : XMFLOAT3(_x, _y, _z) {} - explicit XMFLOAT3A(_In_reads_(3) const float* pArray) noexcept : XMFLOAT3(pArray) {} + using XMFLOAT3::XMFLOAT3; }; //------------------------------------------------------------------------------ @@ -684,6 +737,11 @@ namespace DirectX constexpr XMINT3(int32_t _x, int32_t _y, int32_t _z) noexcept : x(_x), y(_y), z(_z) {} explicit XMINT3(_In_reads_(3) const int32_t* pArray) noexcept : x(pArray[0]), y(pArray[1]), z(pArray[2]) {} + + #if (__cplusplus >= 202002L) + bool operator == (const XMINT3&) const = default; + auto operator <=> (const XMINT3&) const = default; + #endif }; // 3D Vector; 32 bit unsigned integer components @@ -703,6 +761,11 @@ namespace DirectX constexpr XMUINT3(uint32_t _x, uint32_t _y, uint32_t _z) noexcept : x(_x), y(_y), z(_z) {} explicit XMUINT3(_In_reads_(3) const uint32_t* pArray) noexcept : x(pArray[0]), y(pArray[1]), z(pArray[2]) {} + + #if (__cplusplus >= 202002L) + bool operator == (const XMUINT3&) const = default; + auto operator <=> (const XMUINT3&) const = default; + #endif }; //------------------------------------------------------------------------------ @@ -724,21 +787,17 @@ namespace DirectX constexpr XMFLOAT4(float _x, float _y, float _z, float _w) noexcept : x(_x), y(_y), z(_z), w(_w) {} explicit XMFLOAT4(_In_reads_(4) const float* pArray) noexcept : x(pArray[0]), y(pArray[1]), z(pArray[2]), w(pArray[3]) {} + + #if (__cplusplus >= 202002L) + bool operator == (const XMFLOAT4&) const = default; + auto operator <=> (const XMFLOAT4&) const = default; + #endif }; // 4D Vector; 32 bit floating point components aligned on a 16 byte boundary XM_ALIGNED_STRUCT(16) XMFLOAT4A : public XMFLOAT4 { - XMFLOAT4A() = default; - - XMFLOAT4A(const XMFLOAT4A&) = default; - XMFLOAT4A& operator=(const XMFLOAT4A&) = default; - - XMFLOAT4A(XMFLOAT4A&&) = default; - XMFLOAT4A& operator=(XMFLOAT4A&&) = default; - - constexpr XMFLOAT4A(float _x, float _y, float _z, float _w) noexcept : XMFLOAT4(_x, _y, _z, _w) {} - explicit XMFLOAT4A(_In_reads_(4) const float* pArray) noexcept : XMFLOAT4(pArray) {} + using XMFLOAT4::XMFLOAT4; }; //------------------------------------------------------------------------------ @@ -760,6 +819,11 @@ namespace DirectX constexpr XMINT4(int32_t _x, int32_t _y, int32_t _z, int32_t _w) noexcept : x(_x), y(_y), z(_z), w(_w) {} explicit XMINT4(_In_reads_(4) const int32_t* pArray) noexcept : x(pArray[0]), y(pArray[1]), z(pArray[2]), w(pArray[3]) {} + + #if (__cplusplus >= 202002L) + bool operator == (const XMINT4&) const = default; + auto operator <=> (const XMINT4&) const = default; + #endif }; // 4D Vector; 32 bit unsigned integer components @@ -780,12 +844,19 @@ namespace DirectX constexpr XMUINT4(uint32_t _x, uint32_t _y, uint32_t _z, uint32_t _w) noexcept : x(_x), y(_y), z(_z), w(_w) {} explicit XMUINT4(_In_reads_(4) const uint32_t* pArray) noexcept : x(pArray[0]), y(pArray[1]), z(pArray[2]), w(pArray[3]) {} + + #if (__cplusplus >= 202002L) + bool operator == (const XMUINT4&) const = default; + auto operator <=> (const XMUINT4&) const = default; + #endif }; #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgnu-anonymous-struct" #pragma clang diagnostic ignored "-Wnested-anon-types" +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" #endif //------------------------------------------------------------------------------ @@ -816,11 +887,34 @@ namespace DirectX float m20, float m21, float m22) noexcept : _11(m00), _12(m01), _13(m02), _21(m10), _22(m11), _23(m12), - _31(m20), _32(m21), _33(m22) {} + _31(m20), _32(m21), _33(m22) + {} explicit XMFLOAT3X3(_In_reads_(9) const float* pArray) noexcept; - float operator() (size_t Row, size_t Column) const noexcept { return m[Row][Column]; } + float operator() (size_t Row, size_t Column) const noexcept { return m[Row][Column]; } float& operator() (size_t Row, size_t Column) noexcept { return m[Row][Column]; } + + #if (__cplusplus >= 202002L) + constexpr bool operator == (const XMFLOAT3X3& M) const noexcept + { + return _11 == M._11 && _12 == M._12 && _13 == M._13 + && _21 == M._21 && _22 == M._22 && _23 == M._23 + && _31 == M._31 && _32 == M._32 && _33 == M._33; + } + + constexpr auto operator <=> (const XMFLOAT3X3& M) const noexcept + { + if (auto cmp = _11 <=> M._11; cmp != 0) return cmp; + if (auto cmp = _12 <=> M._12; cmp != 0) return cmp; + if (auto cmp = _13 <=> M._13; cmp != 0) return cmp; + if (auto cmp = _21 <=> M._21; cmp != 0) return cmp; + if (auto cmp = _22 <=> M._22; cmp != 0) return cmp; + if (auto cmp = _23 <=> M._23; cmp != 0) return cmp; + if (auto cmp = _31 <=> M._31; cmp != 0) return cmp; + if (auto cmp = _32 <=> M._32; cmp != 0) return cmp; + return _33 <=> M._33; + } + #endif }; //------------------------------------------------------------------------------ @@ -855,30 +949,44 @@ namespace DirectX : _11(m00), _12(m01), _13(m02), _21(m10), _22(m11), _23(m12), _31(m20), _32(m21), _33(m22), - _41(m30), _42(m31), _43(m32) {} + _41(m30), _42(m31), _43(m32) + {} explicit XMFLOAT4X3(_In_reads_(12) const float* pArray) noexcept; - float operator() (size_t Row, size_t Column) const noexcept { return m[Row][Column]; } + float operator() (size_t Row, size_t Column) const noexcept { return m[Row][Column]; } float& operator() (size_t Row, size_t Column) noexcept { return m[Row][Column]; } + + #if (__cplusplus >= 202002L) + constexpr bool operator == (const XMFLOAT4X3& M) const noexcept + { + return _11 == M._11 && _12 == M._12 && _13 == M._13 + && _21 == M._21 && _22 == M._22 && _23 == M._23 + && _31 == M._31 && _32 == M._32 && _33 == M._33 + && _41 == M._41 && _42 == M._42 && _43 == M._43; + } + + constexpr auto operator <=> (const XMFLOAT4X3& M) const noexcept + { + if (auto cmp = _11 <=> M._11; cmp != 0) return cmp; + if (auto cmp = _12 <=> M._12; cmp != 0) return cmp; + if (auto cmp = _13 <=> M._13; cmp != 0) return cmp; + if (auto cmp = _21 <=> M._21; cmp != 0) return cmp; + if (auto cmp = _22 <=> M._22; cmp != 0) return cmp; + if (auto cmp = _23 <=> M._23; cmp != 0) return cmp; + if (auto cmp = _31 <=> M._31; cmp != 0) return cmp; + if (auto cmp = _32 <=> M._32; cmp != 0) return cmp; + if (auto cmp = _33 <=> M._33; cmp != 0) return cmp; + if (auto cmp = _41 <=> M._41; cmp != 0) return cmp; + if (auto cmp = _42 <=> M._42; cmp != 0) return cmp; + return _43 <=> M._43; + } + #endif }; // 4x3 Row-major Matrix: 32 bit floating point components aligned on a 16 byte boundary XM_ALIGNED_STRUCT(16) XMFLOAT4X3A : public XMFLOAT4X3 { - XMFLOAT4X3A() = default; - - XMFLOAT4X3A(const XMFLOAT4X3A&) = default; - XMFLOAT4X3A& operator=(const XMFLOAT4X3A&) = default; - - XMFLOAT4X3A(XMFLOAT4X3A&&) = default; - XMFLOAT4X3A& operator=(XMFLOAT4X3A&&) = default; - - constexpr XMFLOAT4X3A(float m00, float m01, float m02, - float m10, float m11, float m12, - float m20, float m21, float m22, - float m30, float m31, float m32) noexcept : - XMFLOAT4X3(m00, m01, m02, m10, m11, m12, m20, m21, m22, m30, m31, m32) {} - explicit XMFLOAT4X3A(_In_reads_(12) const float* pArray) noexcept : XMFLOAT4X3(pArray) {} + using XMFLOAT4X3::XMFLOAT4X3; }; //------------------------------------------------------------------------------ @@ -910,29 +1018,43 @@ namespace DirectX float m20, float m21, float m22, float m23) noexcept : _11(m00), _12(m01), _13(m02), _14(m03), _21(m10), _22(m11), _23(m12), _24(m13), - _31(m20), _32(m21), _33(m22), _34(m23) {} + _31(m20), _32(m21), _33(m22), _34(m23) + {} explicit XMFLOAT3X4(_In_reads_(12) const float* pArray) noexcept; - float operator() (size_t Row, size_t Column) const noexcept { return m[Row][Column]; } + float operator() (size_t Row, size_t Column) const noexcept { return m[Row][Column]; } float& operator() (size_t Row, size_t Column) noexcept { return m[Row][Column]; } + + #if (__cplusplus >= 202002L) + constexpr bool operator == (const XMFLOAT3X4& M) const noexcept + { + return _11 == M._11 && _12 == M._12 && _13 == M._13 && _14 == M._14 + && _21 == M._21 && _22 == M._22 && _23 == M._23 && _24 == M._24 + && _31 == M._31 && _32 == M._32 && _33 == M._33 && _34 == M._34; + } + + constexpr auto operator <=> (const XMFLOAT3X4& M) const noexcept + { + if (auto cmp = _11 <=> M._11; cmp != 0) return cmp; + if (auto cmp = _12 <=> M._12; cmp != 0) return cmp; + if (auto cmp = _13 <=> M._13; cmp != 0) return cmp; + if (auto cmp = _14 <=> M._14; cmp != 0) return cmp; + if (auto cmp = _21 <=> M._21; cmp != 0) return cmp; + if (auto cmp = _22 <=> M._22; cmp != 0) return cmp; + if (auto cmp = _23 <=> M._23; cmp != 0) return cmp; + if (auto cmp = _24 <=> M._24; cmp != 0) return cmp; + if (auto cmp = _31 <=> M._31; cmp != 0) return cmp; + if (auto cmp = _32 <=> M._32; cmp != 0) return cmp; + if (auto cmp = _33 <=> M._33; cmp != 0) return cmp; + return _34 <=> M._34; + } + #endif }; // 3x4 Column-major Matrix: 32 bit floating point components aligned on a 16 byte boundary XM_ALIGNED_STRUCT(16) XMFLOAT3X4A : public XMFLOAT3X4 { - XMFLOAT3X4A() = default; - - XMFLOAT3X4A(const XMFLOAT3X4A&) = default; - XMFLOAT3X4A& operator=(const XMFLOAT3X4A&) = default; - - XMFLOAT3X4A(XMFLOAT3X4A&&) = default; - XMFLOAT3X4A& operator=(XMFLOAT3X4A&&) = default; - - constexpr XMFLOAT3X4A(float m00, float m01, float m02, float m03, - float m10, float m11, float m12, float m13, - float m20, float m21, float m22, float m23) noexcept : - XMFLOAT3X4(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23) {} - explicit XMFLOAT3X4A(_In_reads_(12) const float* pArray) noexcept : XMFLOAT3X4(pArray) {} + using XMFLOAT3X4::XMFLOAT3X4; }; //------------------------------------------------------------------------------ @@ -966,30 +1088,48 @@ namespace DirectX : _11(m00), _12(m01), _13(m02), _14(m03), _21(m10), _22(m11), _23(m12), _24(m13), _31(m20), _32(m21), _33(m22), _34(m23), - _41(m30), _42(m31), _43(m32), _44(m33) {} + _41(m30), _42(m31), _43(m32), _44(m33) + {} explicit XMFLOAT4X4(_In_reads_(16) const float* pArray) noexcept; - float operator() (size_t Row, size_t Column) const noexcept { return m[Row][Column]; } + float operator() (size_t Row, size_t Column) const noexcept { return m[Row][Column]; } float& operator() (size_t Row, size_t Column) noexcept { return m[Row][Column]; } + + #if (__cplusplus >= 202002L) + constexpr bool operator == (const XMFLOAT4X4& M) const noexcept + { + return _11 == M._11 && _12 == M._12 && _13 == M._13 && _14 == M._14 + && _21 == M._21 && _22 == M._22 && _23 == M._23 && _24 == M._24 + && _31 == M._31 && _32 == M._32 && _33 == M._33 && _34 == M._34 + && _41 == M._41 && _42 == M._42 && _43 == M._43 && _44 == M._44; + } + + constexpr auto operator <=> (const XMFLOAT4X4& M) const noexcept + { + if (auto cmp = _11 <=> M._11; cmp != 0) return cmp; + if (auto cmp = _12 <=> M._12; cmp != 0) return cmp; + if (auto cmp = _13 <=> M._13; cmp != 0) return cmp; + if (auto cmp = _14 <=> M._14; cmp != 0) return cmp; + if (auto cmp = _21 <=> M._21; cmp != 0) return cmp; + if (auto cmp = _22 <=> M._22; cmp != 0) return cmp; + if (auto cmp = _23 <=> M._23; cmp != 0) return cmp; + if (auto cmp = _24 <=> M._24; cmp != 0) return cmp; + if (auto cmp = _31 <=> M._31; cmp != 0) return cmp; + if (auto cmp = _32 <=> M._32; cmp != 0) return cmp; + if (auto cmp = _33 <=> M._33; cmp != 0) return cmp; + if (auto cmp = _34 <=> M._34; cmp != 0) return cmp; + if (auto cmp = _41 <=> M._41; cmp != 0) return cmp; + if (auto cmp = _42 <=> M._42; cmp != 0) return cmp; + if (auto cmp = _43 <=> M._43; cmp != 0) return cmp; + return _44 <=> M._44; + } + #endif }; // 4x4 Matrix: 32 bit floating point components aligned on a 16 byte boundary XM_ALIGNED_STRUCT(16) XMFLOAT4X4A : public XMFLOAT4X4 { - XMFLOAT4X4A() = default; - - XMFLOAT4X4A(const XMFLOAT4X4A&) = default; - XMFLOAT4X4A& operator=(const XMFLOAT4X4A&) = default; - - XMFLOAT4X4A(XMFLOAT4X4A&&) = default; - XMFLOAT4X4A& operator=(XMFLOAT4X4A&&) = default; - - constexpr XMFLOAT4X4A(float m00, float m01, float m02, float m03, - float m10, float m11, float m12, float m13, - float m20, float m21, float m22, float m23, - float m30, float m31, float m32, float m33) noexcept - : XMFLOAT4X4(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {} - explicit XMFLOAT4X4A(_In_reads_(16) const float* pArray) noexcept : XMFLOAT4X4(pArray) {} + using XMFLOAT4X4::XMFLOAT4X4; }; //////////////////////////////////////////////////////////////////////////////// @@ -997,12 +1137,12 @@ namespace DirectX #ifdef __clang__ #pragma clang diagnostic pop #endif - #ifdef _PREFAST_ #pragma prefast(pop) #endif - +#ifdef _MSC_VER #pragma warning(pop) +#endif /**************************************************************************** * @@ -1250,9 +1390,11 @@ namespace DirectX XMVECTOR XM_CALLCONV XMVectorReciprocalSqrtEst(FXMVECTOR V) noexcept; XMVECTOR XM_CALLCONV XMVectorReciprocalSqrt(FXMVECTOR V) noexcept; XMVECTOR XM_CALLCONV XMVectorExp2(FXMVECTOR V) noexcept; + XMVECTOR XM_CALLCONV XMVectorExp10(FXMVECTOR V) noexcept; XMVECTOR XM_CALLCONV XMVectorExpE(FXMVECTOR V) noexcept; XMVECTOR XM_CALLCONV XMVectorExp(FXMVECTOR V) noexcept; XMVECTOR XM_CALLCONV XMVectorLog2(FXMVECTOR V) noexcept; + XMVECTOR XM_CALLCONV XMVectorLog10(FXMVECTOR V) noexcept; XMVECTOR XM_CALLCONV XMVectorLogE(FXMVECTOR V) noexcept; XMVECTOR XM_CALLCONV XMVectorLog(FXMVECTOR V) noexcept; XMVECTOR XM_CALLCONV XMVectorPow(FXMVECTOR V1, FXMVECTOR V2) noexcept; @@ -1332,17 +1474,17 @@ namespace DirectX XMVECTOR XM_CALLCONV XMVector2LinePointDistance(FXMVECTOR LinePoint1, FXMVECTOR LinePoint2, FXMVECTOR Point) noexcept; XMVECTOR XM_CALLCONV XMVector2IntersectLine(FXMVECTOR Line1Point1, FXMVECTOR Line1Point2, FXMVECTOR Line2Point1, GXMVECTOR Line2Point2) noexcept; XMVECTOR XM_CALLCONV XMVector2Transform(FXMVECTOR V, FXMMATRIX M) noexcept; - XMFLOAT4* XM_CALLCONV XMVector2TransformStream(_Out_writes_bytes_(sizeof(XMFLOAT4) + OutputStride * (VectorCount - 1)) XMFLOAT4* pOutputStream, + XMFLOAT4* XM_CALLCONV XMVector2TransformStream(_Out_writes_bytes_(sizeof(XMFLOAT4) + OutputStride * (VectorCount - 1)) XMFLOAT4* pOutputStream, _In_ size_t OutputStride, _In_reads_bytes_(sizeof(XMFLOAT2) + InputStride * (VectorCount - 1)) const XMFLOAT2* pInputStream, _In_ size_t InputStride, _In_ size_t VectorCount, _In_ FXMMATRIX M) noexcept; XMVECTOR XM_CALLCONV XMVector2TransformCoord(FXMVECTOR V, FXMMATRIX M) noexcept; - XMFLOAT2* XM_CALLCONV XMVector2TransformCoordStream(_Out_writes_bytes_(sizeof(XMFLOAT2) + OutputStride * (VectorCount - 1)) XMFLOAT2* pOutputStream, + XMFLOAT2* XM_CALLCONV XMVector2TransformCoordStream(_Out_writes_bytes_(sizeof(XMFLOAT2) + OutputStride * (VectorCount - 1)) XMFLOAT2* pOutputStream, _In_ size_t OutputStride, _In_reads_bytes_(sizeof(XMFLOAT2) + InputStride * (VectorCount - 1)) const XMFLOAT2* pInputStream, _In_ size_t InputStride, _In_ size_t VectorCount, _In_ FXMMATRIX M) noexcept; XMVECTOR XM_CALLCONV XMVector2TransformNormal(FXMVECTOR V, FXMMATRIX M) noexcept; - XMFLOAT2* XM_CALLCONV XMVector2TransformNormalStream(_Out_writes_bytes_(sizeof(XMFLOAT2) + OutputStride * (VectorCount - 1)) XMFLOAT2* pOutputStream, + XMFLOAT2* XM_CALLCONV XMVector2TransformNormalStream(_Out_writes_bytes_(sizeof(XMFLOAT2) + OutputStride * (VectorCount - 1)) XMFLOAT2* pOutputStream, _In_ size_t OutputStride, _In_reads_bytes_(sizeof(XMFLOAT2) + InputStride * (VectorCount - 1)) const XMFLOAT2* pInputStream, _In_ size_t InputStride, _In_ size_t VectorCount, _In_ FXMMATRIX M) noexcept; @@ -1394,23 +1536,23 @@ namespace DirectX XMVECTOR XM_CALLCONV XMVector3Rotate(FXMVECTOR V, FXMVECTOR RotationQuaternion) noexcept; XMVECTOR XM_CALLCONV XMVector3InverseRotate(FXMVECTOR V, FXMVECTOR RotationQuaternion) noexcept; XMVECTOR XM_CALLCONV XMVector3Transform(FXMVECTOR V, FXMMATRIX M) noexcept; - XMFLOAT4* XM_CALLCONV XMVector3TransformStream(_Out_writes_bytes_(sizeof(XMFLOAT4) + OutputStride * (VectorCount - 1)) XMFLOAT4* pOutputStream, + XMFLOAT4* XM_CALLCONV XMVector3TransformStream(_Out_writes_bytes_(sizeof(XMFLOAT4) + OutputStride * (VectorCount - 1)) XMFLOAT4* pOutputStream, _In_ size_t OutputStride, _In_reads_bytes_(sizeof(XMFLOAT3) + InputStride * (VectorCount - 1)) const XMFLOAT3* pInputStream, _In_ size_t InputStride, _In_ size_t VectorCount, _In_ FXMMATRIX M) noexcept; XMVECTOR XM_CALLCONV XMVector3TransformCoord(FXMVECTOR V, FXMMATRIX M) noexcept; - XMFLOAT3* XM_CALLCONV XMVector3TransformCoordStream(_Out_writes_bytes_(sizeof(XMFLOAT3) + OutputStride * (VectorCount - 1)) XMFLOAT3* pOutputStream, + XMFLOAT3* XM_CALLCONV XMVector3TransformCoordStream(_Out_writes_bytes_(sizeof(XMFLOAT3) + OutputStride * (VectorCount - 1)) XMFLOAT3* pOutputStream, _In_ size_t OutputStride, _In_reads_bytes_(sizeof(XMFLOAT3) + InputStride * (VectorCount - 1)) const XMFLOAT3* pInputStream, _In_ size_t InputStride, _In_ size_t VectorCount, _In_ FXMMATRIX M) noexcept; XMVECTOR XM_CALLCONV XMVector3TransformNormal(FXMVECTOR V, FXMMATRIX M) noexcept; - XMFLOAT3* XM_CALLCONV XMVector3TransformNormalStream(_Out_writes_bytes_(sizeof(XMFLOAT3) + OutputStride * (VectorCount - 1)) XMFLOAT3* pOutputStream, + XMFLOAT3* XM_CALLCONV XMVector3TransformNormalStream(_Out_writes_bytes_(sizeof(XMFLOAT3) + OutputStride * (VectorCount - 1)) XMFLOAT3* pOutputStream, _In_ size_t OutputStride, _In_reads_bytes_(sizeof(XMFLOAT3) + InputStride * (VectorCount - 1)) const XMFLOAT3* pInputStream, _In_ size_t InputStride, _In_ size_t VectorCount, _In_ FXMMATRIX M) noexcept; XMVECTOR XM_CALLCONV XMVector3Project(FXMVECTOR V, float ViewportX, float ViewportY, float ViewportWidth, float ViewportHeight, float ViewportMinZ, float ViewportMaxZ, FXMMATRIX Projection, CXMMATRIX View, CXMMATRIX World) noexcept; - XMFLOAT3* XM_CALLCONV XMVector3ProjectStream(_Out_writes_bytes_(sizeof(XMFLOAT3) + OutputStride * (VectorCount - 1)) XMFLOAT3* pOutputStream, + XMFLOAT3* XM_CALLCONV XMVector3ProjectStream(_Out_writes_bytes_(sizeof(XMFLOAT3) + OutputStride * (VectorCount - 1)) XMFLOAT3* pOutputStream, _In_ size_t OutputStride, _In_reads_bytes_(sizeof(XMFLOAT3) + InputStride * (VectorCount - 1)) const XMFLOAT3* pInputStream, _In_ size_t InputStride, _In_ size_t VectorCount, @@ -1418,7 +1560,7 @@ namespace DirectX _In_ FXMMATRIX Projection, _In_ CXMMATRIX View, _In_ CXMMATRIX World) noexcept; XMVECTOR XM_CALLCONV XMVector3Unproject(FXMVECTOR V, float ViewportX, float ViewportY, float ViewportWidth, float ViewportHeight, float ViewportMinZ, float ViewportMaxZ, FXMMATRIX Projection, CXMMATRIX View, CXMMATRIX World) noexcept; - XMFLOAT3* XM_CALLCONV XMVector3UnprojectStream(_Out_writes_bytes_(sizeof(XMFLOAT3) + OutputStride * (VectorCount - 1)) XMFLOAT3* pOutputStream, + XMFLOAT3* XM_CALLCONV XMVector3UnprojectStream(_Out_writes_bytes_(sizeof(XMFLOAT3) + OutputStride * (VectorCount - 1)) XMFLOAT3* pOutputStream, _In_ size_t OutputStride, _In_reads_bytes_(sizeof(XMFLOAT3) + InputStride * (VectorCount - 1)) const XMFLOAT3* pInputStream, _In_ size_t InputStride, _In_ size_t VectorCount, @@ -1468,7 +1610,7 @@ namespace DirectX XMVECTOR XM_CALLCONV XMVector4AngleBetweenNormals(FXMVECTOR N1, FXMVECTOR N2) noexcept; XMVECTOR XM_CALLCONV XMVector4AngleBetweenVectors(FXMVECTOR V1, FXMVECTOR V2) noexcept; XMVECTOR XM_CALLCONV XMVector4Transform(FXMVECTOR V, FXMMATRIX M) noexcept; - XMFLOAT4* XM_CALLCONV XMVector4TransformStream(_Out_writes_bytes_(sizeof(XMFLOAT4) + OutputStride * (VectorCount - 1)) XMFLOAT4* pOutputStream, + XMFLOAT4* XM_CALLCONV XMVector4TransformStream(_Out_writes_bytes_(sizeof(XMFLOAT4) + OutputStride * (VectorCount - 1)) XMFLOAT4* pOutputStream, _In_ size_t OutputStride, _In_reads_bytes_(sizeof(XMFLOAT4) + InputStride * (VectorCount - 1)) const XMFLOAT4* pInputStream, _In_ size_t InputStride, _In_ size_t VectorCount, _In_ FXMMATRIX M) noexcept; @@ -1491,7 +1633,7 @@ namespace DirectX XMVECTOR XM_CALLCONV XMMatrixDeterminant(FXMMATRIX M) noexcept; _Success_(return) - bool XM_CALLCONV XMMatrixDecompose(_Out_ XMVECTOR* outScale, _Out_ XMVECTOR* outRotQuat, _Out_ XMVECTOR* outTrans, _In_ FXMMATRIX M) noexcept; + bool XM_CALLCONV XMMatrixDecompose(_Out_ XMVECTOR* outScale, _Out_ XMVECTOR* outRotQuat, _Out_ XMVECTOR* outTrans, _In_ FXMMATRIX M) noexcept; XMMATRIX XM_CALLCONV XMMatrixIdentity() noexcept; XMMATRIX XM_CALLCONV XMMatrixSet(float m00, float m01, float m02, float m03, @@ -1505,8 +1647,13 @@ namespace DirectX XMMATRIX XM_CALLCONV XMMatrixRotationX(float Angle) noexcept; XMMATRIX XM_CALLCONV XMMatrixRotationY(float Angle) noexcept; XMMATRIX XM_CALLCONV XMMatrixRotationZ(float Angle) noexcept; + + // Rotates about y-axis (Yaw), then x-axis (Pitch), then z-axis (Roll) XMMATRIX XM_CALLCONV XMMatrixRotationRollPitchYaw(float Pitch, float Yaw, float Roll) noexcept; + + // Rotates about y-axis (Angles.y), then x-axis (Angles.x), then z-axis (Angles.z) XMMATRIX XM_CALLCONV XMMatrixRotationRollPitchYawFromVector(FXMVECTOR Angles) noexcept; + XMMATRIX XM_CALLCONV XMMatrixRotationNormal(FXMVECTOR NormalAxis, float Angle) noexcept; XMMATRIX XM_CALLCONV XMMatrixRotationAxis(FXMVECTOR Axis, float Angle) noexcept; XMMATRIX XM_CALLCONV XMMatrixRotationQuaternion(FXMVECTOR Quaternion) noexcept; @@ -1568,8 +1715,13 @@ namespace DirectX XMVECTOR XM_CALLCONV XMQuaternionBaryCentricV(FXMVECTOR Q0, FXMVECTOR Q1, FXMVECTOR Q2, GXMVECTOR F, HXMVECTOR G) noexcept; XMVECTOR XM_CALLCONV XMQuaternionIdentity() noexcept; + + // Rotates about y-axis (Yaw), then x-axis (Pitch), then z-axis (Roll) XMVECTOR XM_CALLCONV XMQuaternionRotationRollPitchYaw(float Pitch, float Yaw, float Roll) noexcept; + + // Rotates about y-axis (Angles.y), then x-axis (Angles.x), then z-axis (Angles.z) XMVECTOR XM_CALLCONV XMQuaternionRotationRollPitchYawFromVector(FXMVECTOR Angles) noexcept; + XMVECTOR XM_CALLCONV XMQuaternionRotationNormal(FXMVECTOR NormalAxis, float Angle) noexcept; XMVECTOR XM_CALLCONV XMQuaternionRotationAxis(FXMVECTOR Axis, float Angle) noexcept; XMVECTOR XM_CALLCONV XMQuaternionRotationMatrix(FXMMATRIX M) noexcept; @@ -1596,11 +1748,15 @@ namespace DirectX XMVECTOR XM_CALLCONV XMPlaneNormalize(FXMVECTOR P) noexcept; XMVECTOR XM_CALLCONV XMPlaneIntersectLine(FXMVECTOR P, FXMVECTOR LinePoint1, FXMVECTOR LinePoint2) noexcept; void XM_CALLCONV XMPlaneIntersectPlane(_Out_ XMVECTOR* pLinePoint1, _Out_ XMVECTOR* pLinePoint2, _In_ FXMVECTOR P1, _In_ FXMVECTOR P2) noexcept; - XMVECTOR XM_CALLCONV XMPlaneTransform(FXMVECTOR P, FXMMATRIX M) noexcept; - XMFLOAT4* XM_CALLCONV XMPlaneTransformStream(_Out_writes_bytes_(sizeof(XMFLOAT4) + OutputStride * (PlaneCount - 1)) XMFLOAT4* pOutputStream, + + // Transforms a plane given an inverse transpose matrix + XMVECTOR XM_CALLCONV XMPlaneTransform(FXMVECTOR P, FXMMATRIX ITM) noexcept; + + // Transforms an array of planes given an inverse transpose matrix + XMFLOAT4* XM_CALLCONV XMPlaneTransformStream(_Out_writes_bytes_(sizeof(XMFLOAT4) + OutputStride * (PlaneCount - 1)) XMFLOAT4* pOutputStream, _In_ size_t OutputStride, _In_reads_bytes_(sizeof(XMFLOAT4) + InputStride * (PlaneCount - 1)) const XMFLOAT4* pInputStream, - _In_ size_t InputStride, _In_ size_t PlaneCount, _In_ FXMMATRIX M) noexcept; + _In_ size_t InputStride, _In_ size_t PlaneCount, _In_ FXMMATRIX ITM) noexcept; XMVECTOR XM_CALLCONV XMPlaneFromPointNormal(FXMVECTOR Point, FXMVECTOR Normal) noexcept; XMVECTOR XM_CALLCONV XMPlaneFromPoints(FXMVECTOR Point1, FXMVECTOR Point2, FXMVECTOR Point3) noexcept; @@ -1638,6 +1794,9 @@ namespace DirectX XMVECTOR XM_CALLCONV XMColorRGBToYUV_HD(FXMVECTOR rgb) noexcept; XMVECTOR XM_CALLCONV XMColorYUVToRGB_HD(FXMVECTOR yuv) noexcept; + XMVECTOR XM_CALLCONV XMColorRGBToYUV_UHD(FXMVECTOR rgb) noexcept; + XMVECTOR XM_CALLCONV XMColorYUVToRGB_UHD(FXMVECTOR yuv) noexcept; + XMVECTOR XM_CALLCONV XMColorRGBToXYZ(FXMVECTOR rgb) noexcept; XMVECTOR XM_CALLCONV XMColorXYZToRGB(FXMVECTOR xyz) noexcept; @@ -1687,15 +1846,15 @@ namespace DirectX #undef XMMax #endif - template inline T XMMin(T a, T b) { return (a < b) ? a : b; } - template inline T XMMax(T a, T b) { return (a > b) ? a : b; } + template inline T XMMin(T a, T b) noexcept { return (a < b) ? a : b; } + template inline T XMMax(T a, T b) noexcept { return (a > b) ? a : b; } //------------------------------------------------------------------------------ #if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) // PermuteHelper internal template (SSE only) - namespace Internal + namespace MathInternal { // Slow path fallback for permutes that do not map to a single SSE shuffle opcode. template struct PermuteHelper @@ -1756,25 +1915,25 @@ namespace DirectX static_assert(PermuteZ <= 7, "PermuteZ template parameter out of range"); static_assert(PermuteW <= 7, "PermuteW template parameter out of range"); -#if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) - const uint32_t Shuffle = _MM_SHUFFLE(PermuteW & 3, PermuteZ & 3, PermuteY & 3, PermuteX & 3); + #if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) + constexpr uint32_t Shuffle = _MM_SHUFFLE(PermuteW & 3, PermuteZ & 3, PermuteY & 3, PermuteX & 3); - const bool WhichX = PermuteX > 3; - const bool WhichY = PermuteY > 3; - const bool WhichZ = PermuteZ > 3; - const bool WhichW = PermuteW > 3; + constexpr bool WhichX = PermuteX > 3; + constexpr bool WhichY = PermuteY > 3; + constexpr bool WhichZ = PermuteZ > 3; + constexpr bool WhichW = PermuteW > 3; - return Internal::PermuteHelper::Permute(V1, V2); -#else + return MathInternal::PermuteHelper::Permute(V1, V2); + #else return XMVectorPermute(V1, V2, PermuteX, PermuteY, PermuteZ, PermuteW); -#endif + #endif } // Special-case permute templates - template<> inline XMVECTOR XM_CALLCONV XMVectorPermute<0, 1, 2, 3>(FXMVECTOR V1, FXMVECTOR) noexcept { return V1; } - template<> inline XMVECTOR XM_CALLCONV XMVectorPermute<4, 5, 6, 7>(FXMVECTOR, FXMVECTOR V2) noexcept { return V2; } + template<> constexpr XMVECTOR XM_CALLCONV XMVectorPermute<0, 1, 2, 3>(FXMVECTOR V1, FXMVECTOR) noexcept { return V1; } + template<> constexpr XMVECTOR XM_CALLCONV XMVectorPermute<4, 5, 6, 7>(FXMVECTOR, FXMVECTOR V2) noexcept { return V2; } #if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) template<> inline XMVECTOR XM_CALLCONV XMVectorPermute<0, 1, 4, 5>(FXMVECTOR V1, FXMVECTOR V2) noexcept { return _mm_movelh_ps(V1, V2); } @@ -1852,17 +2011,17 @@ namespace DirectX static_assert(SwizzleZ <= 3, "SwizzleZ template parameter out of range"); static_assert(SwizzleW <= 3, "SwizzleW template parameter out of range"); -#if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) + #if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) return XM_PERMUTE_PS(V, _MM_SHUFFLE(SwizzleW, SwizzleZ, SwizzleY, SwizzleX)); -#else + #else return XMVectorSwizzle(V, SwizzleX, SwizzleY, SwizzleZ, SwizzleW); -#endif + #endif } // Specialized swizzles - template<> inline XMVECTOR XM_CALLCONV XMVectorSwizzle<0, 1, 2, 3>(FXMVECTOR V) noexcept { return V; } + template<> constexpr XMVECTOR XM_CALLCONV XMVectorSwizzle<0, 1, 2, 3>(FXMVECTOR V) noexcept { return V; } #if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) template<> inline XMVECTOR XM_CALLCONV XMVectorSwizzle<0, 1, 0, 1>(FXMVECTOR V) noexcept { return _mm_movelh_ps(V, V); } @@ -1951,16 +2110,18 @@ namespace DirectX * ****************************************************************************/ - // The purpose of the following global constants is to prevent redundant - // reloading of the constants when they are referenced by more than one - // separate inline math routine called within the same function. Declaring - // a constant locally within a routine is sufficient to prevent redundant - // reloads of that constant when that single routine is called multiple - // times in a function, but if the constant is used (and declared) in a - // separate math routine it would be reloaded. + // The purpose of the following global constants is to prevent redundant + // reloading of the constants when they are referenced by more than one + // separate inline math routine called within the same function. Declaring + // a constant locally within a routine is sufficient to prevent redundant + // reloads of that constant when that single routine is called multiple + // times in a function, but if the constant is used (and declared) in a + // separate math routine it would be reloaded. #ifndef XMGLOBALCONST -#if defined(__GNUC__) && !defined(__MINGW32__) +#if __cplusplus >= 201703L +#define XMGLOBALCONST inline constexpr +#elif defined(__GNUC__) && !defined(__MINGW32__) #define XMGLOBALCONST extern const __attribute__((weak)) #else #define XMGLOBALCONST extern const __declspec(selectany) @@ -2101,6 +2262,8 @@ namespace DirectX XMGLOBALCONST XMVECTORF32 g_XMLogEst7 = { { { -0.010578f, -0.010578f, -0.010578f, -0.010578f } } }; XMGLOBALCONST XMVECTORF32 g_XMLgE = { { { +1.442695f, +1.442695f, +1.442695f, +1.442695f } } }; XMGLOBALCONST XMVECTORF32 g_XMInvLgE = { { { +6.93147182e-1f, +6.93147182e-1f, +6.93147182e-1f, +6.93147182e-1f } } }; + XMGLOBALCONST XMVECTORF32 g_XMLg10 = { { { +3.321928f, +3.321928f, +3.321928f, +3.321928f } } }; + XMGLOBALCONST XMVECTORF32 g_XMInvLg10 = { { { +3.010299956e-1f, +3.010299956e-1f, +3.010299956e-1f, +3.010299956e-1f } } }; XMGLOBALCONST XMVECTORF32 g_UByteMax = { { { 255.0f, 255.0f, 255.0f, 255.0f } } }; XMGLOBALCONST XMVECTORF32 g_ByteMin = { { { -127.0f, -127.0f, -127.0f, -127.0f } } }; XMGLOBALCONST XMVECTORF32 g_ByteMax = { { { 127.0f, 127.0f, 127.0f, 127.0f } } }; @@ -2114,12 +2277,14 @@ namespace DirectX * ****************************************************************************/ +#ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4068 4214 4204 4365 4616 4640 6001 6101) - // C4068/4616: ignore unknown pragmas - // C4214/4204: nonstandard extension used - // C4365/4640: Off by default noise - // C6001/6101: False positives + // C4068/4616: ignore unknown pragmas + // C4214/4204: nonstandard extension used + // C4365/4640: Off by default noise + // C6001/6101: False positives +#endif #ifdef _PREFAST_ #pragma prefast(push) @@ -2129,28 +2294,31 @@ namespace DirectX #ifdef __clang__ #pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wfloat-equal" #pragma clang diagnostic ignored "-Wundefined-reinterpret-cast" +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" #endif //------------------------------------------------------------------------------ inline XMVECTOR XM_CALLCONV XMVectorSetBinaryConstant(uint32_t C0, uint32_t C1, uint32_t C2, uint32_t C3) noexcept { -#if defined(_XM_NO_INTRINSICS_) + #if defined(_XM_NO_INTRINSICS_) XMVECTORU32 vResult; vResult.u[0] = (0 - (C0 & 1)) & 0x3F800000; vResult.u[1] = (0 - (C1 & 1)) & 0x3F800000; vResult.u[2] = (0 - (C2 & 1)) & 0x3F800000; vResult.u[3] = (0 - (C3 & 1)) & 0x3F800000; return vResult.v; -#elif defined(_XM_ARM_NEON_INTRINSICS_) + #elif defined(_XM_ARM_NEON_INTRINSICS_) XMVECTORU32 vResult; vResult.u[0] = (0 - (C0 & 1)) & 0x3F800000; vResult.u[1] = (0 - (C1 & 1)) & 0x3F800000; vResult.u[2] = (0 - (C2 & 1)) & 0x3F800000; vResult.u[3] = (0 - (C3 & 1)) & 0x3F800000; return vResult.v; -#else // XM_SSE_INTRINSICS_ + #else // XM_SSE_INTRINSICS_ static const XMVECTORU32 g_vMask1 = { { { 1, 1, 1, 1 } } }; // Move the parms to a vector __m128i vTemp = _mm_set_epi32(static_cast(C3), static_cast(C2), static_cast(C1), static_cast(C0)); @@ -2161,7 +2329,7 @@ namespace DirectX // 0xFFFFFFFF -> 1.0f, 0x00000000 -> 0.0f vTemp = _mm_and_si128(vTemp, g_XMOne); return _mm_castsi128_ps(vTemp); -#endif + #endif } //------------------------------------------------------------------------------ @@ -2170,27 +2338,27 @@ namespace DirectX { assert(IntConstant >= -16 && IntConstant <= 15); assert(DivExponent < 32); -#if defined(_XM_NO_INTRINSICS_) + #if defined(_XM_NO_INTRINSICS_) using DirectX::XMConvertVectorIntToFloat; XMVECTORI32 V = { { { IntConstant, IntConstant, IntConstant, IntConstant } } }; return XMConvertVectorIntToFloat(V.v, DivExponent); -#elif defined(_XM_ARM_NEON_INTRINSICS_) - // Splat the int + #elif defined(_XM_ARM_NEON_INTRINSICS_) + // Splat the int int32x4_t vScale = vdupq_n_s32(IntConstant); // Convert to a float XMVECTOR vResult = vcvtq_f32_s32(vScale); // Convert DivExponent into 1.0f/(1<(&vScale)[0]); return vResult; -#else // XM_SSE_INTRINSICS_ - // Splat the int + #else // XM_SSE_INTRINSICS_ + // Splat the int __m128i vScale = _mm_set1_epi32(IntConstant); // Convert to a float XMVECTOR vResult = _mm_cvtepi32_ps(vScale); @@ -2201,7 +2369,7 @@ namespace DirectX // Multiply by the reciprocal (Perform a right shift by DivExponent) vResult = _mm_mul_ps(vResult, _mm_castsi128_ps(vScale)); return vResult; -#endif + #endif } //------------------------------------------------------------------------------ @@ -2209,39 +2377,35 @@ namespace DirectX inline XMVECTOR XM_CALLCONV XMVectorSplatConstantInt(int32_t IntConstant) noexcept { assert(IntConstant >= -16 && IntConstant <= 15); -#if defined(_XM_NO_INTRINSICS_) + #if defined(_XM_NO_INTRINSICS_) XMVECTORI32 V = { { { IntConstant, IntConstant, IntConstant, IntConstant } } }; return V.v; -#elif defined(_XM_ARM_NEON_INTRINSICS_) + #elif defined(_XM_ARM_NEON_INTRINSICS_) int32x4_t V = vdupq_n_s32(IntConstant); return reinterpret_cast(&V)[0]; -#else // XM_SSE_INTRINSICS_ + #else // XM_SSE_INTRINSICS_ __m128i V = _mm_set1_epi32(IntConstant); return _mm_castsi128_ps(V); -#endif + #endif } -#include "directxmath/directxmathconvert.inl" -#include "directxmath/directxmathvector.inl" -#include "directxmath/directxmathmatrix.inl" -#include "directxmath/directxmathmisc.inl" +#include "DirectXMathConvert.inl" +#include "DirectXMathVector.inl" +#include "DirectXMathMatrix.inl" +#include "DirectXMathMisc.inl" #ifdef __clang__ #pragma clang diagnostic pop #endif - #ifdef _PREFAST_ #pragma prefast(pop) #endif - +#ifdef _MSC_VER #pragma warning(pop) +#endif } // namespace DirectX using namespace DirectX; - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif diff --git a/directxmath/directxmathconvert.inl b/src/directxmath/DirectXMathConvert.inl similarity index 90% rename from directxmath/directxmathconvert.inl rename to src/directxmath/DirectXMathConvert.inl index dbf153c..f5e5e48 100644 --- a/directxmath/directxmathconvert.inl +++ b/src/directxmath/DirectXMathConvert.inl @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------------- // DirectXMathConvert.inl -- SIMD C++ Math library // -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // -// http://go.microsoft.com/fwlink/?LinkID=615560 +// https://go.microsoft.com/fwlink/?LinkID=615560 //------------------------------------------------------------------------------------- #pragma once @@ -15,11 +15,13 @@ * ****************************************************************************/ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +#ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4701) // C4701: false positives +#endif inline XMVECTOR XM_CALLCONV XMConvertVectorIntToFloat ( @@ -32,14 +34,16 @@ inline XMVECTOR XM_CALLCONV XMConvertVectorIntToFloat float fScale = 1.0f / static_cast(1U << DivExponent); uint32_t ElementIndex = 0; XMVECTOR Result; - do { + do + { auto iTemp = static_cast(VInt.vector4_u32[ElementIndex]); Result.vector4_f32[ElementIndex] = static_cast(iTemp)* fScale; - } while (++ElementIndex < 4); + } + while (++ElementIndex < 4); return Result; #elif defined(_XM_ARM_NEON_INTRINSICS_) - float fScale = 1.0f / (float)(1U << DivExponent); - float32x4_t vResult = vcvtq_f32_s32(VInt); + float fScale = 1.0f / static_cast(1U << DivExponent); + float32x4_t vResult = vcvtq_f32_s32(vreinterpretq_s32_f32(VInt)); return vmulq_n_f32(vResult, fScale); #else // _XM_SSE_INTRINSICS_ // Convert to floats @@ -67,7 +71,8 @@ inline XMVECTOR XM_CALLCONV XMConvertVectorFloatToInt auto fScale = static_cast(1U << MulExponent); uint32_t ElementIndex = 0; XMVECTOR Result; - do { + do + { int32_t iResult; float fTemp = VFloat.vector4_f32[ElementIndex] * fScale; if (fTemp <= -(65536.0f * 32768.0f)) @@ -78,23 +83,25 @@ inline XMVECTOR XM_CALLCONV XMConvertVectorFloatToInt { iResult = 0x7FFFFFFF; } - else { + else + { iResult = static_cast(fTemp); } Result.vector4_u32[ElementIndex] = static_cast(iResult); - } while (++ElementIndex < 4); + } + while (++ElementIndex < 4); return Result; #elif defined(_XM_ARM_NEON_INTRINSICS_) - float32x4_t vResult = vmulq_n_f32(VFloat, (float)(1U << MulExponent)); + float32x4_t vResult = vmulq_n_f32(VFloat, static_cast(1U << MulExponent)); // In case of positive overflow, detect it uint32x4_t vOverflow = vcgtq_f32(vResult, g_XMMaxInt); // Float to int conversion int32x4_t vResulti = vcvtq_s32_f32(vResult); // If there was positive overflow, set to 0x7FFFFFFF - vResult = vandq_u32(vOverflow, g_XMAbsMask); - vOverflow = vbicq_u32(vResulti, vOverflow); - vOverflow = vorrq_u32(vOverflow, vResult); - return vOverflow; + vResult = vreinterpretq_f32_u32(vandq_u32(vOverflow, g_XMAbsMask)); + vOverflow = vbicq_u32(vreinterpretq_u32_s32(vResulti), vOverflow); + vOverflow = vorrq_u32(vOverflow, vreinterpretq_u32_f32(vResult)); + return vreinterpretq_f32_u32(vOverflow); #else // _XM_SSE_INTRINSICS_ XMVECTOR vResult = _mm_set_ps1(static_cast(1U << MulExponent)); vResult = _mm_mul_ps(vResult, VFloat); @@ -123,13 +130,15 @@ inline XMVECTOR XM_CALLCONV XMConvertVectorUIntToFloat float fScale = 1.0f / static_cast(1U << DivExponent); uint32_t ElementIndex = 0; XMVECTOR Result; - do { + do + { Result.vector4_f32[ElementIndex] = static_cast(VUInt.vector4_u32[ElementIndex])* fScale; - } while (++ElementIndex < 4); + } + while (++ElementIndex < 4); return Result; #elif defined(_XM_ARM_NEON_INTRINSICS_) - float fScale = 1.0f / (float)(1U << DivExponent); - float32x4_t vResult = vcvtq_f32_u32(VUInt); + float fScale = 1.0f / static_cast(1U << DivExponent); + float32x4_t vResult = vcvtq_f32_u32(vreinterpretq_u32_f32(VUInt)); return vmulq_n_f32(vResult, fScale); #else // _XM_SSE_INTRINSICS_ // For the values that are higher than 0x7FFFFFFF, a fixup is needed @@ -167,7 +176,8 @@ inline XMVECTOR XM_CALLCONV XMConvertVectorFloatToUInt auto fScale = static_cast(1U << MulExponent); uint32_t ElementIndex = 0; XMVECTOR Result; - do { + do + { uint32_t uResult; float fTemp = VFloat.vector4_f32[ElementIndex] * fScale; if (fTemp <= 0.0f) @@ -178,22 +188,24 @@ inline XMVECTOR XM_CALLCONV XMConvertVectorFloatToUInt { uResult = 0xFFFFFFFFU; } - else { + else + { uResult = static_cast(fTemp); } Result.vector4_u32[ElementIndex] = uResult; - } while (++ElementIndex < 4); + } + while (++ElementIndex < 4); return Result; #elif defined(_XM_ARM_NEON_INTRINSICS_) - float32x4_t vResult = vmulq_n_f32(VFloat, (float)(1U << MulExponent)); + float32x4_t vResult = vmulq_n_f32(VFloat, static_cast(1U << MulExponent)); // In case of overflow, detect it uint32x4_t vOverflow = vcgtq_f32(vResult, g_XMMaxUInt); // Float to int conversion uint32x4_t vResulti = vcvtq_u32_f32(vResult); // If there was overflow, set to 0xFFFFFFFFU - vResult = vbicq_u32(vResulti, vOverflow); - vOverflow = vorrq_u32(vOverflow, vResult); - return vOverflow; + vResult = vreinterpretq_f32_u32(vbicq_u32(vResulti, vOverflow)); + vOverflow = vorrq_u32(vOverflow, vreinterpretq_u32_f32(vResult)); + return vreinterpretq_f32_u32(vOverflow); #else // _XM_SSE_INTRINSICS_ XMVECTOR vResult = _mm_set_ps1(static_cast(1U << MulExponent)); vResult = _mm_mul_ps(vResult, VFloat); @@ -218,7 +230,9 @@ inline XMVECTOR XM_CALLCONV XMConvertVectorFloatToUInt #endif } +#ifdef _MSC_VER #pragma warning(pop) +#endif /**************************************************************************** * @@ -226,7 +240,7 @@ inline XMVECTOR XM_CALLCONV XMConvertVectorFloatToUInt * ****************************************************************************/ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ _Use_decl_annotations_ inline XMVECTOR XM_CALLCONV XMLoadInt(const uint32_t* pSource) noexcept { @@ -240,7 +254,7 @@ inline XMVECTOR XM_CALLCONV XMLoadInt(const uint32_t* pSource) noexcept return V; #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t zero = vdupq_n_u32(0); - return vld1q_lane_u32(pSource, zero, 0); + return vreinterpretq_f32_u32(vld1q_lane_u32(pSource, zero, 0)); #elif defined(_XM_SSE_INTRINSICS_) return _mm_load_ss(reinterpret_cast(pSource)); #endif @@ -281,7 +295,7 @@ inline XMVECTOR XM_CALLCONV XMLoadInt2(const uint32_t* pSource) noexcept #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x2_t x = vld1_u32(pSource); uint32x2_t zero = vdup_n_u32(0); - return vcombine_u32(x, zero); + return vreinterpretq_f32_u32(vcombine_u32(x, zero)); #elif defined(_XM_SSE_INTRINSICS_) return _mm_castpd_ps(_mm_load_sd(reinterpret_cast(pSource))); #endif @@ -301,13 +315,13 @@ inline XMVECTOR XM_CALLCONV XMLoadInt2A(const uint32_t* pSource) noexcept V.vector4_u32[3] = 0; return V; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) uint32x2_t x = vld1_u32_ex(pSource, 64); #else uint32x2_t x = vld1_u32(pSource); #endif uint32x2_t zero = vdup_n_u32(0); - return vcombine_u32(x, zero); + return vreinterpretq_f32_u32(vcombine_u32(x, zero)); #elif defined(_XM_SSE_INTRINSICS_) return _mm_castpd_ps(_mm_load_sd(reinterpret_cast(pSource))); #endif @@ -348,7 +362,7 @@ inline XMVECTOR XM_CALLCONV XMLoadFloat2A(const XMFLOAT2A* pSource) noexcept V.vector4_f32[3] = 0.f; return V; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) float32x2_t x = vld1_f32_ex(reinterpret_cast(pSource), 64); #else float32x2_t x = vld1_f32(reinterpret_cast(pSource)); @@ -434,7 +448,7 @@ inline XMVECTOR XM_CALLCONV XMLoadInt3(const uint32_t* pSource) noexcept uint32x2_t x = vld1_u32(pSource); uint32x2_t zero = vdup_n_u32(0); uint32x2_t y = vld1_lane_u32(pSource + 2, zero, 0); - return vcombine_u32(x, y); + return vreinterpretq_f32_u32(vcombine_u32(x, y)); #elif defined(_XM_SSE4_INTRINSICS_) __m128 xy = _mm_castpd_ps(_mm_load_sd(reinterpret_cast(pSource))); __m128 z = _mm_load_ss(reinterpret_cast(pSource + 2)); @@ -461,12 +475,12 @@ inline XMVECTOR XM_CALLCONV XMLoadInt3A(const uint32_t* pSource) noexcept return V; #elif defined(_XM_ARM_NEON_INTRINSICS_) // Reads an extra integer which is zero'd -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) uint32x4_t V = vld1q_u32_ex(pSource, 128); #else uint32x4_t V = vld1q_u32(pSource); #endif - return vsetq_lane_u32(0, V, 3); + return vreinterpretq_f32_u32(vsetq_lane_u32(0, V, 3)); #elif defined(_XM_SSE4_INTRINSICS_) __m128 xy = _mm_castpd_ps(_mm_load_sd(reinterpret_cast(pSource))); __m128 z = _mm_load_ss(reinterpret_cast(pSource + 2)); @@ -521,12 +535,16 @@ inline XMVECTOR XM_CALLCONV XMLoadFloat3A(const XMFLOAT3A* pSource) noexcept return V; #elif defined(_XM_ARM_NEON_INTRINSICS_) // Reads an extra float which is zero'd -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) float32x4_t V = vld1q_f32_ex(reinterpret_cast(pSource), 128); #else float32x4_t V = vld1q_f32(reinterpret_cast(pSource)); #endif return vsetq_lane_f32(0, V, 3); +#elif defined(_XM_SSE4_INTRINSICS_) + // Reads an extra float which is zero'd + __m128 V = _mm_load_ps(&pSource->x); + return _mm_blend_ps(_mm_setzero_ps(), V, 0x7); #elif defined(_XM_SSE_INTRINSICS_) // Reads an extra float which is zero'd __m128 V = _mm_load_ps(&pSource->x); @@ -614,7 +632,7 @@ inline XMVECTOR XM_CALLCONV XMLoadInt4(const uint32_t* pSource) noexcept V.vector4_u32[3] = pSource[3]; return V; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vld1q_u32(pSource); + return vreinterpretq_f32_u32(vld1q_u32(pSource)); #elif defined(_XM_SSE_INTRINSICS_) __m128i V = _mm_loadu_si128(reinterpret_cast(pSource)); return _mm_castsi128_ps(V); @@ -635,10 +653,10 @@ inline XMVECTOR XM_CALLCONV XMLoadInt4A(const uint32_t* pSource) noexcept V.vector4_u32[3] = pSource[3]; return V; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) return vld1q_u32_ex(pSource, 128); #else - return vld1q_u32(pSource); + return vreinterpretq_f32_u32(vld1q_u32(pSource)); #endif #elif defined(_XM_SSE_INTRINSICS_) __m128i V = _mm_load_si128(reinterpret_cast(pSource)); @@ -679,7 +697,7 @@ inline XMVECTOR XM_CALLCONV XMLoadFloat4A(const XMFLOAT4A* pSource) noexcept V.vector4_f32[3] = pSource->w; return V; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) return vld1q_f32_ex(reinterpret_cast(pSource), 128); #else return vld1q_f32(reinterpret_cast(pSource)); @@ -780,8 +798,8 @@ inline XMMATRIX XM_CALLCONV XMLoadFloat3x3(const XMFLOAT3X3* pSource) noexcept float32x4_t T = vextq_f32(v0, v1, 3); XMMATRIX M; - M.r[0] = vandq_u32(v0, g_XMMask3); - M.r[1] = vandq_u32(T, g_XMMask3); + M.r[0] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(v0), g_XMMask3)); + M.r[1] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(T), g_XMMask3)); M.r[2] = vcombine_f32(vget_high_f32(v1), v2); M.r[3] = g_XMIdentityR3; return M; @@ -846,9 +864,9 @@ inline XMMATRIX XM_CALLCONV XMLoadFloat4x3(const XMFLOAT4X3* pSource) noexcept float32x4_t T3 = vextq_f32(v2, v2, 1); XMMATRIX M; - M.r[0] = vandq_u32(v0, g_XMMask3); - M.r[1] = vandq_u32(T1, g_XMMask3); - M.r[2] = vandq_u32(T2, g_XMMask3); + M.r[0] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(v0), g_XMMask3)); + M.r[1] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(T1), g_XMMask3)); + M.r[2] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(T2), g_XMMask3)); M.r[3] = vsetq_lane_f32(1.f, T3, 3); return M; #elif defined(_XM_SSE_INTRINSICS_) @@ -867,11 +885,18 @@ inline XMMATRIX XM_CALLCONV XMLoadFloat4x3(const XMFLOAT4X3* pSource) noexcept // vTemp2 = x2,y2,z2,z2 vTemp2 = XM_PERMUTE_PS(vTemp2, _MM_SHUFFLE(1, 1, 0, 2)); // vTemp1 = x1,y1,z1,0 - vTemp1 = _mm_and_ps(vTemp1, g_XMMask3); // vTemp2 = x2,y2,z2,0 - vTemp2 = _mm_and_ps(vTemp2, g_XMMask3); // vTemp3 = x3,y3,z3,0 +#ifdef _XM_SSE4_INTRINSICS_ + XMVECTOR zero = _mm_setzero_ps(); + vTemp1 = _mm_blend_ps(zero, vTemp1, 0x7); + vTemp2 = _mm_blend_ps(zero, vTemp2, 0x7); + vTemp3 = _mm_blend_ps(zero, vTemp3, 0x7); +#else + vTemp1 = _mm_and_ps(vTemp1, g_XMMask3); + vTemp2 = _mm_and_ps(vTemp2, g_XMMask3); vTemp3 = _mm_and_ps(vTemp3, g_XMMask3); +#endif // vTemp4i = x4,y4,z4,0 __m128i vTemp4i = _mm_srli_si128(_mm_castps_si128(vTemp4), 32 / 8); // vTemp4i = x4,y4,z4,1.0f @@ -915,7 +940,7 @@ inline XMMATRIX XM_CALLCONV XMLoadFloat4x3A(const XMFLOAT4X3A* pSource) noexcept return M; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) float32x4_t v0 = vld1q_f32_ex(&pSource->m[0][0], 128); float32x4_t v1 = vld1q_f32_ex(&pSource->m[1][1], 128); float32x4_t v2 = vld1q_f32_ex(&pSource->m[2][2], 128); @@ -930,9 +955,9 @@ inline XMMATRIX XM_CALLCONV XMLoadFloat4x3A(const XMFLOAT4X3A* pSource) noexcept float32x4_t T3 = vextq_f32(v2, v2, 1); XMMATRIX M; - M.r[0] = vandq_u32(v0, g_XMMask3); - M.r[1] = vandq_u32(T1, g_XMMask3); - M.r[2] = vandq_u32(T2, g_XMMask3); + M.r[0] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(v0), g_XMMask3)); + M.r[1] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(T1), g_XMMask3)); + M.r[2] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(T2), g_XMMask3)); M.r[3] = vsetq_lane_f32(1.f, T3, 3); return M; #elif defined(_XM_SSE_INTRINSICS_) @@ -951,11 +976,18 @@ inline XMMATRIX XM_CALLCONV XMLoadFloat4x3A(const XMFLOAT4X3A* pSource) noexcept // vTemp2 = x2,y2,z2,z2 vTemp2 = XM_PERMUTE_PS(vTemp2, _MM_SHUFFLE(1, 1, 0, 2)); // vTemp1 = x1,y1,z1,0 - vTemp1 = _mm_and_ps(vTemp1, g_XMMask3); // vTemp2 = x2,y2,z2,0 - vTemp2 = _mm_and_ps(vTemp2, g_XMMask3); // vTemp3 = x3,y3,z3,0 +#ifdef _XM_SSE4_INTRINSICS_ + XMVECTOR zero = _mm_setzero_ps(); + vTemp1 = _mm_blend_ps(zero, vTemp1, 0x7); + vTemp2 = _mm_blend_ps(zero, vTemp2, 0x7); + vTemp3 = _mm_blend_ps(zero, vTemp3, 0x7); +#else + vTemp1 = _mm_and_ps(vTemp1, g_XMMask3); + vTemp2 = _mm_and_ps(vTemp2, g_XMMask3); vTemp3 = _mm_and_ps(vTemp3, g_XMMask3); +#endif // vTemp4i = x4,y4,z4,0 __m128i vTemp4i = _mm_srli_si128(_mm_castps_si128(vTemp4), 32 / 8); // vTemp4i = x4,y4,z4,1.0f @@ -1012,9 +1044,9 @@ inline XMMATRIX XM_CALLCONV XMLoadFloat3x4(const XMFLOAT3X4* pSource) noexcept float32x4_t T3 = vcombine_f32(vTemp0.val[3], rh); XMMATRIX M = {}; - M.r[0] = vandq_u32(T0, g_XMMask3); - M.r[1] = vandq_u32(T1, g_XMMask3); - M.r[2] = vandq_u32(T2, g_XMMask3); + M.r[0] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(T0), g_XMMask3)); + M.r[1] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(T1), g_XMMask3)); + M.r[2] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(T2), g_XMMask3)); M.r[3] = vsetq_lane_f32(1.f, T3, 3); return M; #elif defined(_XM_SSE_INTRINSICS_) @@ -1077,7 +1109,7 @@ inline XMMATRIX XM_CALLCONV XMLoadFloat3x4A(const XMFLOAT3X4A* pSource) noexcept return M; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) float32x2x4_t vTemp0 = vld4_f32_ex(&pSource->_11, 128); float32x4_t vTemp1 = vld1q_f32_ex(&pSource->_31, 128); #else @@ -1096,9 +1128,9 @@ inline XMMATRIX XM_CALLCONV XMLoadFloat3x4A(const XMFLOAT3X4A* pSource) noexcept float32x4_t T3 = vcombine_f32(vTemp0.val[3], rh); XMMATRIX M = {}; - M.r[0] = vandq_u32(T0, g_XMMask3); - M.r[1] = vandq_u32(T1, g_XMMask3); - M.r[2] = vandq_u32(T2, g_XMMask3); + M.r[0] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(T0), g_XMMask3)); + M.r[1] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(T1), g_XMMask3)); + M.r[2] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(T2), g_XMMask3)); M.r[3] = vsetq_lane_f32(1.f, T3, 3); return M; #elif defined(_XM_SSE_INTRINSICS_) @@ -1208,7 +1240,7 @@ inline XMMATRIX XM_CALLCONV XMLoadFloat4x4A(const XMFLOAT4X4A* pSource) noexcept #elif defined(_XM_ARM_NEON_INTRINSICS_) XMMATRIX M; -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) M.r[0] = vld1q_f32_ex(reinterpret_cast(&pSource->_11), 128); M.r[1] = vld1q_f32_ex(reinterpret_cast(&pSource->_21), 128); M.r[2] = vld1q_f32_ex(reinterpret_cast(&pSource->_31), 128); @@ -1283,7 +1315,7 @@ inline void XM_CALLCONV XMStoreInt2 pDestination[0] = V.vector4_u32[0]; pDestination[1] = V.vector4_u32[1]; #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x2_t VL = vget_low_u32(V); + uint32x2_t VL = vget_low_u32(vreinterpretq_u32_f32(V)); vst1_u32(pDestination, VL); #elif defined(_XM_SSE_INTRINSICS_) _mm_store_sd(reinterpret_cast(pDestination), _mm_castps_pd(V)); @@ -1304,8 +1336,8 @@ inline void XM_CALLCONV XMStoreInt2A pDestination[0] = V.vector4_u32[0]; pDestination[1] = V.vector4_u32[1]; #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x2_t VL = vget_low_u32(V); -#ifdef _MSC_VER + uint32x2_t VL = vget_low_u32(vreinterpretq_u32_f32(V)); +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) vst1_u32_ex(pDestination, VL, 64); #else vst1_u32(pDestination, VL); @@ -1350,7 +1382,7 @@ inline void XM_CALLCONV XMStoreFloat2A pDestination->y = V.vector4_f32[1]; #elif defined(_XM_ARM_NEON_INTRINSICS_) float32x2_t VL = vget_low_f32(V); -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) vst1_f32_ex(reinterpret_cast(pDestination), VL, 64); #else vst1_f32(reinterpret_cast(pDestination), VL); @@ -1373,9 +1405,9 @@ inline void XM_CALLCONV XMStoreSInt2 pDestination->x = static_cast(V.vector4_f32[0]); pDestination->y = static_cast(V.vector4_f32[1]); #elif defined(_XM_ARM_NEON_INTRINSICS_) - int32x2_t v = vget_low_s32(V); - v = vcvt_s32_f32(v); - vst1_s32(reinterpret_cast(pDestination), v); + float32x2_t v = vget_low_f32(V); + int32x2_t iv = vcvt_s32_f32(v); + vst1_s32(reinterpret_cast(pDestination), iv); #elif defined(_XM_SSE_INTRINSICS_) // In case of positive overflow, detect it XMVECTOR vOverflow = _mm_cmpgt_ps(V, g_XMMaxInt); @@ -1443,7 +1475,7 @@ inline void XM_CALLCONV XMStoreInt3 pDestination[1] = V.vector4_u32[1]; pDestination[2] = V.vector4_u32[2]; #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x2_t VL = vget_low_u32(V); + uint32x2_t VL = vget_low_u32(vreinterpretq_u32_f32(V)); vst1_u32(pDestination, VL); vst1q_lane_u32(pDestination + 2, *reinterpret_cast(&V), 2); #elif defined(_XM_SSE_INTRINSICS_) @@ -1468,8 +1500,8 @@ inline void XM_CALLCONV XMStoreInt3A pDestination[1] = V.vector4_u32[1]; pDestination[2] = V.vector4_u32[2]; #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x2_t VL = vget_low_u32(V); -#ifdef _MSC_VER + uint32x2_t VL = vget_low_u32(vreinterpretq_u32_f32(V)); +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) vst1_u32_ex(pDestination, VL, 64); #else vst1_u32(pDestination, VL); @@ -1526,7 +1558,7 @@ inline void XM_CALLCONV XMStoreFloat3A pDestination->z = V.vector4_f32[2]; #elif defined(_XM_ARM_NEON_INTRINSICS_) float32x2_t VL = vget_low_f32(V); -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) vst1_f32_ex(reinterpret_cast(pDestination), VL, 64); #else vst1_f32(reinterpret_cast(pDestination), VL); @@ -1634,7 +1666,7 @@ inline void XM_CALLCONV XMStoreInt4 pDestination[2] = V.vector4_u32[2]; pDestination[3] = V.vector4_u32[3]; #elif defined(_XM_ARM_NEON_INTRINSICS_) - vst1q_u32(pDestination, V); + vst1q_u32(pDestination, vreinterpretq_u32_f32(V)); #elif defined(_XM_SSE_INTRINSICS_) _mm_storeu_si128(reinterpret_cast<__m128i*>(pDestination), _mm_castps_si128(V)); #endif @@ -1656,10 +1688,10 @@ inline void XM_CALLCONV XMStoreInt4A pDestination[2] = V.vector4_u32[2]; pDestination[3] = V.vector4_u32[3]; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) vst1q_u32_ex(pDestination, V, 128); #else - vst1q_u32(pDestination, V); + vst1q_u32(pDestination, vreinterpretq_u32_f32(V)); #endif #elif defined(_XM_SSE_INTRINSICS_) _mm_store_si128(reinterpret_cast<__m128i*>(pDestination), _mm_castps_si128(V)); @@ -1703,7 +1735,7 @@ inline void XM_CALLCONV XMStoreFloat4A pDestination->z = V.vector4_f32[2]; pDestination->w = V.vector4_f32[3]; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) vst1q_f32_ex(reinterpret_cast(pDestination), V, 128); #else vst1q_f32(reinterpret_cast(pDestination), V); @@ -1913,7 +1945,7 @@ inline void XM_CALLCONV XMStoreFloat4x3A pDestination->m[3][2] = M.r[3].vector4_f32[2]; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) float32x4_t T1 = vextq_f32(M.r[0], M.r[1], 1); float32x4_t T2 = vbslq_f32(g_XMMask3, M.r[0], T1); vst1q_f32_ex(&pDestination->m[0][0], T2, 128); @@ -2057,7 +2089,7 @@ inline void XM_CALLCONV XMStoreFloat3x4A float32x4x2_t T0 = vzipq_f32(P0.val[0], P1.val[0]); float32x4x2_t T1 = vzipq_f32(P0.val[1], P1.val[1]); -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) vst1q_f32_ex(&pDestination->m[0][0], T0.val[0], 128); vst1q_f32_ex(&pDestination->m[1][0], T0.val[1], 128); vst1q_f32_ex(&pDestination->m[2][0], T1.val[0], 128); @@ -2166,7 +2198,7 @@ inline void XM_CALLCONV XMStoreFloat4x4A pDestination->m[3][3] = M.r[3].vector4_f32[3]; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) vst1q_f32_ex(reinterpret_cast(&pDestination->_11), M.r[0], 128); vst1q_f32_ex(reinterpret_cast(&pDestination->_21), M.r[1], 128); vst1q_f32_ex(reinterpret_cast(&pDestination->_31), M.r[2], 128); diff --git a/directxmath/directxmathmatrix.inl b/src/directxmath/DirectXMathMatrix.inl similarity index 89% rename from directxmath/directxmathmatrix.inl rename to src/directxmath/DirectXMathMatrix.inl index 606a5c6..cc4ee07 100644 --- a/directxmath/directxmathmatrix.inl +++ b/src/directxmath/DirectXMathMatrix.inl @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------------- // DirectXMathMatrix.inl -- SIMD C++ Math library // -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // -// http://go.microsoft.com/fwlink/?LinkID=615560 +// https://go.microsoft.com/fwlink/?LinkID=615560 //------------------------------------------------------------------------------------- #pragma once @@ -15,13 +15,13 @@ * ****************************************************************************/ - //------------------------------------------------------------------------------ - // Comparison operations - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +// Comparison operations +//------------------------------------------------------------------------------ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ -#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma float_control(push) #pragma float_control(precise, on) #endif @@ -32,8 +32,9 @@ inline bool XM_CALLCONV XMMatrixIsNaN(FXMMATRIX M) noexcept #if defined(_XM_NO_INTRINSICS_) size_t i = 16; auto pWork = reinterpret_cast(&M.m[0][0]); - do { - // Fetch value into integer unit + do + { + // Fetch value into integer unit uint32_t uTest = pWork[0]; // Remove sign uTest &= 0x7FFFFFFFU; @@ -44,27 +45,30 @@ inline bool XM_CALLCONV XMMatrixIsNaN(FXMMATRIX M) noexcept break; // NaN found } ++pWork; // Next entry - } while (--i); + } + while (--i); return (i != 0); // i == 0 if nothing matched #elif defined(_XM_ARM_NEON_INTRINSICS_) // Load in registers - XMVECTOR vX = M.r[0]; - XMVECTOR vY = M.r[1]; - XMVECTOR vZ = M.r[2]; - XMVECTOR vW = M.r[3]; + float32x4_t vX = M.r[0]; + float32x4_t vY = M.r[1]; + float32x4_t vZ = M.r[2]; + float32x4_t vW = M.r[3]; // Test themselves to check for NaN - vX = vmvnq_u32(vceqq_f32(vX, vX)); - vY = vmvnq_u32(vceqq_f32(vY, vY)); - vZ = vmvnq_u32(vceqq_f32(vZ, vZ)); - vW = vmvnq_u32(vceqq_f32(vW, vW)); + uint32x4_t xmask = vmvnq_u32(vceqq_f32(vX, vX)); + uint32x4_t ymask = vmvnq_u32(vceqq_f32(vY, vY)); + uint32x4_t zmask = vmvnq_u32(vceqq_f32(vZ, vZ)); + uint32x4_t wmask = vmvnq_u32(vceqq_f32(vW, vW)); // Or all the results - vX = vorrq_u32(vX, vZ); - vY = vorrq_u32(vY, vW); - vX = vorrq_u32(vX, vY); + xmask = vorrq_u32(xmask, zmask); + ymask = vorrq_u32(ymask, wmask); + xmask = vorrq_u32(xmask, ymask); // If any tested true, return true - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vX), vget_high_u8(vX)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1); + uint8x8x2_t vTemp = vzip_u8( + vget_low_u8(vreinterpretq_u8_u32(xmask)), + vget_high_u8(vreinterpretq_u8_u32(xmask))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1); return (r != 0); #elif defined(_XM_SSE_INTRINSICS_) // Load in registers @@ -87,7 +91,7 @@ inline bool XM_CALLCONV XMMatrixIsNaN(FXMMATRIX M) noexcept #endif } -#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma float_control(pop) #endif @@ -99,8 +103,9 @@ inline bool XM_CALLCONV XMMatrixIsInfinite(FXMMATRIX M) noexcept #if defined(_XM_NO_INTRINSICS_) size_t i = 16; auto pWork = reinterpret_cast(&M.m[0][0]); - do { - // Fetch value into integer unit + do + { + // Fetch value into integer unit uint32_t uTest = pWork[0]; // Remove sign uTest &= 0x7FFFFFFFU; @@ -110,27 +115,35 @@ inline bool XM_CALLCONV XMMatrixIsInfinite(FXMMATRIX M) noexcept break; // INF found } ++pWork; // Next entry - } while (--i); + } + while (--i); return (i != 0); // i == 0 if nothing matched #elif defined(_XM_ARM_NEON_INTRINSICS_) + // Load in registers + float32x4_t vX = M.r[0]; + float32x4_t vY = M.r[1]; + float32x4_t vZ = M.r[2]; + float32x4_t vW = M.r[3]; // Mask off the sign bits - XMVECTOR vTemp1 = vandq_u32(M.r[0], g_XMAbsMask); - XMVECTOR vTemp2 = vandq_u32(M.r[1], g_XMAbsMask); - XMVECTOR vTemp3 = vandq_u32(M.r[2], g_XMAbsMask); - XMVECTOR vTemp4 = vandq_u32(M.r[3], g_XMAbsMask); + vX = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(vX), g_XMAbsMask)); + vY = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(vY), g_XMAbsMask)); + vZ = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(vZ), g_XMAbsMask)); + vW = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(vW), g_XMAbsMask)); // Compare to infinity - vTemp1 = vceqq_f32(vTemp1, g_XMInfinity); - vTemp2 = vceqq_f32(vTemp2, g_XMInfinity); - vTemp3 = vceqq_f32(vTemp3, g_XMInfinity); - vTemp4 = vceqq_f32(vTemp4, g_XMInfinity); + uint32x4_t xmask = vceqq_f32(vX, g_XMInfinity); + uint32x4_t ymask = vceqq_f32(vY, g_XMInfinity); + uint32x4_t zmask = vceqq_f32(vZ, g_XMInfinity); + uint32x4_t wmask = vceqq_f32(vW, g_XMInfinity); // Or the answers together - vTemp1 = vorrq_u32(vTemp1, vTemp2); - vTemp3 = vorrq_u32(vTemp3, vTemp4); - vTemp1 = vorrq_u32(vTemp1, vTemp3); - // If any are infinity, the signs are true. - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vTemp1), vget_high_u8(vTemp1)); - uint16x4x2_t vTemp5 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp5.val[1], 1); + xmask = vorrq_u32(xmask, zmask); + ymask = vorrq_u32(ymask, wmask); + xmask = vorrq_u32(xmask, ymask); + // If any tested true, return true + uint8x8x2_t vTemp = vzip_u8( + vget_low_u8(vreinterpretq_u8_u32(xmask)), + vget_high_u8(vreinterpretq_u8_u32(xmask))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1); return (r != 0); #elif defined(_XM_SSE_INTRINSICS_) // Mask off the sign bits @@ -187,16 +200,16 @@ inline bool XM_CALLCONV XMMatrixIsIdentity(FXMMATRIX M) noexcept uOne |= uZero; return (uOne == 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) - XMVECTOR vTemp1 = vceqq_f32(M.r[0], g_XMIdentityR0); - XMVECTOR vTemp2 = vceqq_f32(M.r[1], g_XMIdentityR1); - XMVECTOR vTemp3 = vceqq_f32(M.r[2], g_XMIdentityR2); - XMVECTOR vTemp4 = vceqq_f32(M.r[3], g_XMIdentityR3); - vTemp1 = vandq_u32(vTemp1, vTemp2); - vTemp3 = vandq_u32(vTemp3, vTemp4); - vTemp1 = vandq_u32(vTemp1, vTemp3); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vTemp1), vget_high_u8(vTemp1)); - uint16x4x2_t vTemp5 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp5.val[1], 1); + uint32x4_t xmask = vceqq_f32(M.r[0], g_XMIdentityR0); + uint32x4_t ymask = vceqq_f32(M.r[1], g_XMIdentityR1); + uint32x4_t zmask = vceqq_f32(M.r[2], g_XMIdentityR2); + uint32x4_t wmask = vceqq_f32(M.r[3], g_XMIdentityR3); + xmask = vandq_u32(xmask, zmask); + ymask = vandq_u32(ymask, wmask); + xmask = vandq_u32(xmask, ymask); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(xmask)), vget_high_u8(vreinterpretq_u8_u32(xmask))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1); return (r == 0xFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp1 = _mm_cmpeq_ps(M.r[0], g_XMIdentityR0); @@ -265,10 +278,10 @@ inline XMMATRIX XM_CALLCONV XMMatrixMultiply float32x2_t VL = vget_low_f32(M1.r[0]); float32x2_t VH = vget_high_f32(M1.r[0]); // Perform the operation on the first row - XMVECTOR vX = vmulq_lane_f32(M2.r[0], VL, 0); - XMVECTOR vY = vmulq_lane_f32(M2.r[1], VL, 1); - XMVECTOR vZ = vmlaq_lane_f32(vX, M2.r[2], VH, 0); - XMVECTOR vW = vmlaq_lane_f32(vY, M2.r[3], VH, 1); + float32x4_t vX = vmulq_lane_f32(M2.r[0], VL, 0); + float32x4_t vY = vmulq_lane_f32(M2.r[1], VL, 1); + float32x4_t vZ = vmlaq_lane_f32(vX, M2.r[2], VH, 0); + float32x4_t vW = vmlaq_lane_f32(vY, M2.r[3], VH, 1); mResult.r[0] = vaddq_f32(vZ, vW); // Repeat for the other 3 rows VL = vget_low_f32(M1.r[1]); @@ -478,10 +491,10 @@ inline XMMATRIX XM_CALLCONV XMMatrixMultiplyTranspose float32x2_t VL = vget_low_f32(M1.r[0]); float32x2_t VH = vget_high_f32(M1.r[0]); // Perform the operation on the first row - XMVECTOR vX = vmulq_lane_f32(M2.r[0], VL, 0); - XMVECTOR vY = vmulq_lane_f32(M2.r[1], VL, 1); - XMVECTOR vZ = vmlaq_lane_f32(vX, M2.r[2], VH, 0); - XMVECTOR vW = vmlaq_lane_f32(vY, M2.r[3], VH, 1); + float32x4_t vX = vmulq_lane_f32(M2.r[0], VL, 0); + float32x4_t vY = vmulq_lane_f32(M2.r[1], VL, 1); + float32x4_t vZ = vmlaq_lane_f32(vX, M2.r[2], VH, 0); + float32x4_t vW = vmlaq_lane_f32(vY, M2.r[3], VH, 1); float32x4_t r0 = vaddq_f32(vZ, vW); // Repeat for the other 3 rows VL = vget_low_f32(M1.r[1]); @@ -1403,9 +1416,9 @@ inline XMMATRIX XM_CALLCONV XMMatrixScalingFromVector(FXMVECTOR Scale) noexcept #elif defined(_XM_ARM_NEON_INTRINSICS_) XMMATRIX M; - M.r[0] = vandq_u32(Scale, g_XMMaskX); - M.r[1] = vandq_u32(Scale, g_XMMaskY); - M.r[2] = vandq_u32(Scale, g_XMMaskZ); + M.r[0] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(Scale), g_XMMaskX)); + M.r[1] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(Scale), g_XMMaskY)); + M.r[2] = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(Scale), g_XMMaskZ)); M.r[3] = g_XMIdentityR3.v; return M; #elif defined(_XM_SSE_INTRINSICS_) @@ -1455,12 +1468,12 @@ inline XMMATRIX XM_CALLCONV XMMatrixRotationX(float Angle) noexcept float fCosAngle; XMScalarSinCos(&fSinAngle, &fCosAngle, Angle); - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); - XMVECTOR T1 = vsetq_lane_f32(fCosAngle, Zero, 1); + float32x4_t T1 = vsetq_lane_f32(fCosAngle, Zero, 1); T1 = vsetq_lane_f32(fSinAngle, T1, 2); - XMVECTOR T2 = vsetq_lane_f32(-fSinAngle, Zero, 1); + float32x4_t T2 = vsetq_lane_f32(-fSinAngle, Zero, 1); T2 = vsetq_lane_f32(fCosAngle, T2, 2); XMMATRIX M; @@ -1528,12 +1541,12 @@ inline XMMATRIX XM_CALLCONV XMMatrixRotationY(float Angle) noexcept float fCosAngle; XMScalarSinCos(&fSinAngle, &fCosAngle, Angle); - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); - XMVECTOR T0 = vsetq_lane_f32(fCosAngle, Zero, 0); + float32x4_t T0 = vsetq_lane_f32(fCosAngle, Zero, 0); T0 = vsetq_lane_f32(-fSinAngle, T0, 2); - XMVECTOR T2 = vsetq_lane_f32(fSinAngle, Zero, 0); + float32x4_t T2 = vsetq_lane_f32(fSinAngle, Zero, 0); T2 = vsetq_lane_f32(fCosAngle, T2, 2); XMMATRIX M; @@ -1601,12 +1614,12 @@ inline XMMATRIX XM_CALLCONV XMMatrixRotationZ(float Angle) noexcept float fCosAngle; XMScalarSinCos(&fSinAngle, &fCosAngle, Angle); - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); - XMVECTOR T0 = vsetq_lane_f32(fCosAngle, Zero, 0); + float32x4_t T0 = vsetq_lane_f32(fCosAngle, Zero, 0); T0 = vsetq_lane_f32(fSinAngle, T0, 1); - XMVECTOR T1 = vsetq_lane_f32(-fSinAngle, Zero, 0); + float32x4_t T1 = vsetq_lane_f32(-fSinAngle, Zero, 0); T1 = vsetq_lane_f32(fCosAngle, T1, 1); XMMATRIX M; @@ -1646,8 +1659,41 @@ inline XMMATRIX XM_CALLCONV XMMatrixRotationRollPitchYaw float Roll ) noexcept { +#if defined(_XM_NO_INTRINSICS_) + float cp = cosf(Pitch); + float sp = sinf(Pitch); + + float cy = cosf(Yaw); + float sy = sinf(Yaw); + + float cr = cosf(Roll); + float sr = sinf(Roll); + + XMMATRIX M; + M.m[0][0] = cr * cy + sr * sp * sy; + M.m[0][1] = sr * cp; + M.m[0][2] = sr * sp * cy - cr * sy; + M.m[0][3] = 0.0f; + + M.m[1][0] = cr * sp * sy - sr * cy; + M.m[1][1] = cr * cp; + M.m[1][2] = sr * sy + cr * sp * cy; + M.m[1][3] = 0.0f; + + M.m[2][0] = cp * sy; + M.m[2][1] = -sp; + M.m[2][2] = cp * cy; + M.m[2][3] = 0.0f; + + M.m[3][0] = 0.0f; + M.m[3][1] = 0.0f; + M.m[3][2] = 0.0f; + M.m[3][3] = 1.0f; + return M; +#else XMVECTOR Angles = XMVectorSet(Pitch, Yaw, Roll, 0.0f); return XMMatrixRotationRollPitchYawFromVector(Angles); +#endif } //------------------------------------------------------------------------------ @@ -1657,8 +1703,69 @@ inline XMMATRIX XM_CALLCONV XMMatrixRotationRollPitchYawFromVector FXMVECTOR Angles // ) noexcept { - XMVECTOR Q = XMQuaternionRotationRollPitchYawFromVector(Angles); - return XMMatrixRotationQuaternion(Q); +#if defined(_XM_NO_INTRINSICS_) + float cp = cosf(Angles.vector4_f32[0]); + float sp = sinf(Angles.vector4_f32[0]); + + float cy = cosf(Angles.vector4_f32[1]); + float sy = sinf(Angles.vector4_f32[1]); + + float cr = cosf(Angles.vector4_f32[2]); + float sr = sinf(Angles.vector4_f32[2]); + + XMMATRIX M; + M.m[0][0] = cr * cy + sr * sp * sy; + M.m[0][1] = sr * cp; + M.m[0][2] = sr * sp * cy - cr * sy; + M.m[0][3] = 0.0f; + + M.m[1][0] = cr * sp * sy - sr * cy; + M.m[1][1] = cr * cp; + M.m[1][2] = sr * sy + cr * sp * cy; + M.m[1][3] = 0.0f; + + M.m[2][0] = cp * sy; + M.m[2][1] = -sp; + M.m[2][2] = cp * cy; + M.m[2][3] = 0.0f; + + M.m[3][0] = 0.0f; + M.m[3][1] = 0.0f; + M.m[3][2] = 0.0f; + M.m[3][3] = 1.0f; + return M; +#else + static const XMVECTORF32 Sign = { { { 1.0f, -1.0f, -1.0f, 1.0f } } }; + + XMVECTOR SinAngles, CosAngles; + XMVectorSinCos(&SinAngles, &CosAngles, Angles); + + XMVECTOR P0 = XMVectorPermute(SinAngles, CosAngles); + XMVECTOR Y0 = XMVectorPermute(SinAngles, CosAngles); + XMVECTOR P1 = XMVectorPermute(SinAngles, CosAngles); + XMVECTOR Y1 = XMVectorPermute(SinAngles, CosAngles); + XMVECTOR P2 = XMVectorPermute(SinAngles, CosAngles); + XMVECTOR P3 = XMVectorPermute(SinAngles, CosAngles); + XMVECTOR Y2 = XMVectorSplatX(SinAngles); + XMVECTOR NS = XMVectorNegate(SinAngles); + + XMVECTOR Q0 = XMVectorMultiply(P0, Y0); + XMVECTOR Q1 = XMVectorMultiply(P1, Sign.v); + Q1 = XMVectorMultiply(Q1, Y1); + XMVECTOR Q2 = XMVectorMultiply(P2, Y2); + Q2 = XMVectorMultiplyAdd(Q2, P3, Q1); + + XMVECTOR V0 = XMVectorPermute(Q0, Q2); + XMVECTOR V1 = XMVectorPermute(Q0, Q2); + XMVECTOR V2 = XMVectorPermute(Q0, NS); + + XMMATRIX M; + M.r[0] = XMVectorSelect(g_XMZero, V0, g_XMSelect1110.v); + M.r[1] = XMVectorSelect(g_XMZero, V1, g_XMSelect1110.v); + M.r[2] = XMVectorSelect(g_XMZero, V2, g_XMSelect1110.v); + M.r[3] = g_XMIdentityR3; + return M; +#endif } //------------------------------------------------------------------------------ @@ -1770,8 +1877,42 @@ inline XMMATRIX XM_CALLCONV XMMatrixRotationAxis inline XMMATRIX XM_CALLCONV XMMatrixRotationQuaternion(FXMVECTOR Quaternion) noexcept { -#if defined(_XM_NO_INTRINSICS_) || defined(_XM_ARM_NEON_INTRINSICS_) +#if defined(_XM_NO_INTRINSICS_) + float qx = Quaternion.vector4_f32[0]; + float qxx = qx * qx; + + float qy = Quaternion.vector4_f32[1]; + float qyy = qy * qy; + + float qz = Quaternion.vector4_f32[2]; + float qzz = qz * qz; + + float qw = Quaternion.vector4_f32[3]; + + XMMATRIX M; + M.m[0][0] = 1.f - 2.f * qyy - 2.f * qzz; + M.m[0][1] = 2.f * qx * qy + 2.f * qz * qw; + M.m[0][2] = 2.f * qx * qz - 2.f * qy * qw; + M.m[0][3] = 0.f; + + M.m[1][0] = 2.f * qx * qy - 2.f * qz * qw; + M.m[1][1] = 1.f - 2.f * qxx - 2.f * qzz; + M.m[1][2] = 2.f * qy * qz + 2.f * qx * qw; + M.m[1][3] = 0.f; + + M.m[2][0] = 2.f * qx * qz + 2.f * qy * qw; + M.m[2][1] = 2.f * qy * qz - 2.f * qx * qw; + M.m[2][2] = 1.f - 2.f * qxx - 2.f * qyy; + M.m[2][3] = 0.f; + + M.m[3][0] = 0.f; + M.m[3][1] = 0.f; + M.m[3][2] = 0.f; + M.m[3][3] = 1.0f; + return M; + +#elif defined(_XM_ARM_NEON_INTRINSICS_) static const XMVECTORF32 Constant1110 = { { { 1.0f, 1.0f, 1.0f, 0.0f } } }; XMVECTOR Q0 = XMVectorAdd(Quaternion, Quaternion); @@ -2166,7 +2307,7 @@ inline XMMATRIX XM_CALLCONV XMMatrixPerspectiveLH #elif defined(_XM_ARM_NEON_INTRINSICS_) float TwoNearZ = NearZ + NearZ; float fRange = FarZ / (FarZ - NearZ); - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); XMMATRIX M; M.r[0] = vsetq_lane_f32(TwoNearZ / ViewWidth, Zero, 0); M.r[1] = vsetq_lane_f32(TwoNearZ / ViewHeight, Zero, 1); @@ -2253,7 +2394,7 @@ inline XMMATRIX XM_CALLCONV XMMatrixPerspectiveRH #elif defined(_XM_ARM_NEON_INTRINSICS_) float TwoNearZ = NearZ + NearZ; float fRange = FarZ / (NearZ - FarZ); - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); XMMATRIX M; M.r[0] = vsetq_lane_f32(TwoNearZ / ViewWidth, Zero, 0); @@ -2351,7 +2492,7 @@ inline XMMATRIX XM_CALLCONV XMMatrixPerspectiveFovLH float fRange = FarZ / (FarZ - NearZ); float Height = CosFov / SinFov; float Width = Height / AspectRatio; - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); XMMATRIX M; M.r[0] = vsetq_lane_f32(Width, Zero, 0); @@ -2378,10 +2519,10 @@ inline XMMATRIX XM_CALLCONV XMMatrixPerspectiveFovLH XMVECTOR vTemp = _mm_setzero_ps(); // Copy x only vTemp = _mm_move_ss(vTemp, vValues); - // CosFov / SinFov,0,0,0 + // Height / AspectRatio,0,0,0 XMMATRIX M; M.r[0] = vTemp; - // 0,Height / AspectRatio,0,0 + // 0,Height,0,0 vTemp = vValues; vTemp = _mm_and_ps(vTemp, g_XMMaskY); M.r[1] = vTemp; @@ -2452,7 +2593,7 @@ inline XMMATRIX XM_CALLCONV XMMatrixPerspectiveFovRH float fRange = FarZ / (NearZ - FarZ); float Height = CosFov / SinFov; float Width = Height / AspectRatio; - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); XMMATRIX M; M.r[0] = vsetq_lane_f32(Width, Zero, 0); @@ -2478,10 +2619,10 @@ inline XMMATRIX XM_CALLCONV XMMatrixPerspectiveFovRH XMVECTOR vTemp = _mm_setzero_ps(); // Copy x only vTemp = _mm_move_ss(vTemp, vValues); - // CosFov / SinFov,0,0,0 + // Height / AspectRatio,0,0,0 XMMATRIX M; M.r[0] = vTemp; - // 0,Height / AspectRatio,0,0 + // 0,Height,0,0 vTemp = vValues; vTemp = _mm_and_ps(vTemp, g_XMMaskY); M.r[1] = vTemp; @@ -2549,7 +2690,7 @@ inline XMMATRIX XM_CALLCONV XMMatrixPerspectiveOffCenterLH float ReciprocalWidth = 1.0f / (ViewRight - ViewLeft); float ReciprocalHeight = 1.0f / (ViewTop - ViewBottom); float fRange = FarZ / (FarZ - NearZ); - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); XMMATRIX M; M.r[0] = vsetq_lane_f32(TwoNearZ * ReciprocalWidth, Zero, 0); @@ -2647,7 +2788,7 @@ inline XMMATRIX XM_CALLCONV XMMatrixPerspectiveOffCenterRH float ReciprocalWidth = 1.0f / (ViewRight - ViewLeft); float ReciprocalHeight = 1.0f / (ViewTop - ViewBottom); float fRange = FarZ / (NearZ - FarZ); - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); XMMATRIX M; M.r[0] = vsetq_lane_f32(TwoNearZ * ReciprocalWidth, Zero, 0); @@ -2737,7 +2878,7 @@ inline XMMATRIX XM_CALLCONV XMMatrixOrthographicLH #elif defined(_XM_ARM_NEON_INTRINSICS_) float fRange = 1.0f / (FarZ - NearZ); - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); XMMATRIX M; M.r[0] = vsetq_lane_f32(2.0f / ViewWidth, Zero, 0); M.r[1] = vsetq_lane_f32(2.0f / ViewHeight, Zero, 1); @@ -2821,7 +2962,7 @@ inline XMMATRIX XM_CALLCONV XMMatrixOrthographicRH #elif defined(_XM_ARM_NEON_INTRINSICS_) float fRange = 1.0f / (NearZ - FarZ); - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); XMMATRIX M; M.r[0] = vsetq_lane_f32(2.0f / ViewWidth, Zero, 0); M.r[1] = vsetq_lane_f32(2.0f / ViewHeight, Zero, 1); @@ -2910,7 +3051,7 @@ inline XMMATRIX XM_CALLCONV XMMatrixOrthographicOffCenterLH float ReciprocalWidth = 1.0f / (ViewRight - ViewLeft); float ReciprocalHeight = 1.0f / (ViewTop - ViewBottom); float fRange = 1.0f / (FarZ - NearZ); - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); XMMATRIX M; M.r[0] = vsetq_lane_f32(ReciprocalWidth + ReciprocalWidth, Zero, 0); M.r[1] = vsetq_lane_f32(ReciprocalHeight + ReciprocalHeight, Zero, 1); @@ -3010,7 +3151,7 @@ inline XMMATRIX XM_CALLCONV XMMatrixOrthographicOffCenterRH float ReciprocalWidth = 1.0f / (ViewRight - ViewLeft); float ReciprocalHeight = 1.0f / (ViewTop - ViewBottom); float fRange = 1.0f / (NearZ - FarZ); - const XMVECTOR Zero = vdupq_n_f32(0); + const float32x4_t Zero = vdupq_n_f32(0); XMMATRIX M; M.r[0] = vsetq_lane_f32(ReciprocalWidth + ReciprocalWidth, Zero, 0); M.r[1] = vsetq_lane_f32(ReciprocalHeight + ReciprocalHeight, Zero, 1); @@ -3072,7 +3213,7 @@ inline XMMATRIX XM_CALLCONV XMMatrixOrthographicOffCenterRH * ****************************************************************************/ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ inline XMMATRIX::XMMATRIX ( @@ -3164,7 +3305,7 @@ inline XMMATRIX& XMMATRIX::operator/= (float S) noexcept r[3] = XMVectorDivide(r[3], vS); return *this; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ +#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ float32x4_t vS = vdupq_n_f32(S); r[0] = vdivq_f32(r[0], vS); r[1] = vdivq_f32(r[1], vS); @@ -3178,7 +3319,7 @@ inline XMMATRIX& XMMATRIX::operator/= (float S) noexcept R0 = vmul_f32(S0, R0); S0 = vrecps_f32(R0, vS); R0 = vmul_f32(S0, R0); - float32x4_t Reciprocal = vcombine_u32(R0, R0); + float32x4_t Reciprocal = vcombine_f32(R0, R0); r[0] = vmulq_f32(r[0], Reciprocal); r[1] = vmulq_f32(r[1], Reciprocal); r[2] = vmulq_f32(r[2], Reciprocal); @@ -3251,7 +3392,7 @@ inline XMMATRIX XMMATRIX::operator/ (float S) const noexcept R.r[3] = XMVectorDivide(r[3], vS); return R; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ +#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ float32x4_t vS = vdupq_n_f32(S); XMMATRIX R; R.r[0] = vdivq_f32(r[0], vS); @@ -3266,7 +3407,7 @@ inline XMMATRIX XMMATRIX::operator/ (float S) const noexcept R0 = vmul_f32(S0, R0); S0 = vrecps_f32(R0, vS); R0 = vmul_f32(S0, R0); - float32x4_t Reciprocal = vcombine_u32(R0, R0); + float32x4_t Reciprocal = vcombine_f32(R0, R0); XMMATRIX R; R.r[0] = vmulq_f32(r[0], Reciprocal); R.r[1] = vmulq_f32(r[1], Reciprocal); @@ -3291,7 +3432,7 @@ inline XMMATRIX XM_CALLCONV operator* ( float S, FXMMATRIX M -) noexcept + ) noexcept { XMMATRIX R; R.r[0] = XMVectorScale(M.r[0], S); @@ -3307,7 +3448,7 @@ inline XMMATRIX XM_CALLCONV operator* * ****************************************************************************/ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ _Use_decl_annotations_ inline XMFLOAT3X3::XMFLOAT3X3(const float* pArray) noexcept { @@ -3327,7 +3468,7 @@ inline XMFLOAT3X3::XMFLOAT3X3(const float* pArray) noexcept * ****************************************************************************/ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ _Use_decl_annotations_ inline XMFLOAT4X3::XMFLOAT4X3(const float* pArray) noexcept { @@ -3384,7 +3525,7 @@ inline XMFLOAT3X4::XMFLOAT3X4(const float* pArray) noexcept * ****************************************************************************/ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ _Use_decl_annotations_ inline XMFLOAT4X4::XMFLOAT4X4(const float* pArray) noexcept { diff --git a/directxmath/directxmathmisc.inl b/src/directxmath/DirectXMathMisc.inl similarity index 88% rename from directxmath/directxmathmisc.inl rename to src/directxmath/DirectXMathMisc.inl index aca863b..b22827b 100644 --- a/directxmath/directxmathmisc.inl +++ b/src/directxmath/DirectXMathMisc.inl @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------------- // DirectXMathMisc.inl -- SIMD C++ Math library // -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // -// http://go.microsoft.com/fwlink/?LinkID=615560 +// https://go.microsoft.com/fwlink/?LinkID=615560 //------------------------------------------------------------------------------------- #pragma once @@ -15,11 +15,11 @@ * ****************************************************************************/ - //------------------------------------------------------------------------------ - // Comparison operations - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +// Comparison operations +//------------------------------------------------------------------------------ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ inline bool XM_CALLCONV XMQuaternionEqual ( @@ -120,12 +120,12 @@ inline XMVECTOR XM_CALLCONV XMQuaternionMultiply vResult = vmlaq_f32(vResult, Q2X, ControlWZYX); // Mul by Q1ZWXY - vTemp = vrev64q_u32(vTemp); + vTemp = vreinterpretq_f32_u32(vrev64q_u32(vreinterpretq_u32_f32(vTemp))); Q2Y = vmulq_f32(Q2Y, vTemp); vResult = vmlaq_f32(vResult, Q2Y, ControlZWXY); // Mul by Q1YXWZ - vTemp = vrev64q_u32(vTemp); + vTemp = vreinterpretq_f32_u32(vrev64q_u32(vreinterpretq_u32_f32(vTemp))); vTemp = vcombine_f32(vget_high_f32(vTemp), vget_low_f32(vTemp)); Q2Z = vmulq_f32(Q2Z, vTemp); vResult = vmlaq_f32(vResult, Q2Z, ControlYXWZ); @@ -228,8 +228,6 @@ inline XMVECTOR XM_CALLCONV XMQuaternionConjugate(FXMVECTOR Q) noexcept inline XMVECTOR XM_CALLCONV XMQuaternionInverse(FXMVECTOR Q) noexcept { - const XMVECTOR Zero = XMVectorZero(); - XMVECTOR L = XMVector4LengthSq(Q); XMVECTOR Conjugate = XMQuaternionConjugate(Q); @@ -237,7 +235,7 @@ inline XMVECTOR XM_CALLCONV XMQuaternionInverse(FXMVECTOR Q) noexcept XMVECTOR Result = XMVectorDivide(Conjugate, L); - Result = XMVectorSelect(Result, Zero, Control); + Result = XMVectorSelect(Result, g_XMZero, Control); return Result; } @@ -582,9 +580,30 @@ inline XMVECTOR XM_CALLCONV XMQuaternionRotationRollPitchYaw float Roll ) noexcept { +#if defined(_XM_NO_INTRINSICS_) + const float halfpitch = Pitch * 0.5f; + float cp = cosf(halfpitch); + float sp = sinf(halfpitch); + + const float halfyaw = Yaw * 0.5f; + float cy = cosf(halfyaw); + float sy = sinf(halfyaw); + + const float halfroll = Roll * 0.5f; + float cr = cosf(halfroll); + float sr = sinf(halfroll); + + XMVECTORF32 vResult = { { { + cr * sp * cy + sr * cp * sy, + cr * cp * sy - sr * sp * cy, + sr * cp * cy - cr * sp * sy, + cr * cp * cy + sr * sp * sy + } } }; + return vResult; +#else XMVECTOR Angles = XMVectorSet(Pitch, Yaw, Roll, 0.0f); - XMVECTOR Q = XMQuaternionRotationRollPitchYawFromVector(Angles); - return Q; + return XMQuaternionRotationRollPitchYawFromVector(Angles); +#endif } //------------------------------------------------------------------------------ @@ -594,6 +613,27 @@ inline XMVECTOR XM_CALLCONV XMQuaternionRotationRollPitchYawFromVector FXMVECTOR Angles // ) noexcept { +#if defined(_XM_NO_INTRINSICS_) + const float halfpitch = Angles.vector4_f32[0] * 0.5f; + float cp = cosf(halfpitch); + float sp = sinf(halfpitch); + + const float halfyaw = Angles.vector4_f32[1] * 0.5f; + float cy = cosf(halfyaw); + float sy = sinf(halfyaw); + + const float halfroll = Angles.vector4_f32[2] * 0.5f; + float cr = cosf(halfroll); + float sr = sinf(halfroll); + + XMVECTORF32 vResult = { { { + cr * sp * cy + sr * cp * sy, + cr * cp * sy - sr * sp * cy, + sr * cp * cy - cr * sp * sy, + cr * cp * cy + sr * sp * sy + } } }; + return vResult; +#else static const XMVECTORF32 Sign = { { { 1.0f, -1.0f, -1.0f, 1.0f } } }; XMVECTOR HalfAngles = XMVectorMultiply(Angles, g_XMOneHalf.v); @@ -615,6 +655,7 @@ inline XMVECTOR XM_CALLCONV XMQuaternionRotationRollPitchYawFromVector XMVECTOR Q = XMVectorMultiplyAdd(Q1, R1, Q0); return Q; +#endif } //------------------------------------------------------------------------------ @@ -728,74 +769,74 @@ inline XMVECTOR XM_CALLCONV XMQuaternionRotationMatrix(FXMMATRIX M) noexcept static const XMVECTORU32 Select0110 = { { { XM_SELECT_0, XM_SELECT_1, XM_SELECT_1, XM_SELECT_0 } } }; static const XMVECTORU32 Select0010 = { { { XM_SELECT_0, XM_SELECT_0, XM_SELECT_1, XM_SELECT_0 } } }; - XMVECTOR r0 = M.r[0]; - XMVECTOR r1 = M.r[1]; - XMVECTOR r2 = M.r[2]; + float32x4_t r0 = M.r[0]; + float32x4_t r1 = M.r[1]; + float32x4_t r2 = M.r[2]; - XMVECTOR r00 = vdupq_lane_f32(vget_low_f32(r0), 0); - XMVECTOR r11 = vdupq_lane_f32(vget_low_f32(r1), 1); - XMVECTOR r22 = vdupq_lane_f32(vget_high_f32(r2), 0); + float32x4_t r00 = vdupq_lane_f32(vget_low_f32(r0), 0); + float32x4_t r11 = vdupq_lane_f32(vget_low_f32(r1), 1); + float32x4_t r22 = vdupq_lane_f32(vget_high_f32(r2), 0); // x^2 >= y^2 equivalent to r11 - r00 <= 0 - XMVECTOR r11mr00 = vsubq_f32(r11, r00); - XMVECTOR x2gey2 = vcleq_f32(r11mr00, g_XMZero); + float32x4_t r11mr00 = vsubq_f32(r11, r00); + uint32x4_t x2gey2 = vcleq_f32(r11mr00, g_XMZero); // z^2 >= w^2 equivalent to r11 + r00 <= 0 - XMVECTOR r11pr00 = vaddq_f32(r11, r00); - XMVECTOR z2gew2 = vcleq_f32(r11pr00, g_XMZero); + float32x4_t r11pr00 = vaddq_f32(r11, r00); + uint32x4_t z2gew2 = vcleq_f32(r11pr00, g_XMZero); // x^2 + y^2 >= z^2 + w^2 equivalent to r22 <= 0 - XMVECTOR x2py2gez2pw2 = vcleq_f32(r22, g_XMZero); + uint32x4_t x2py2gez2pw2 = vcleq_f32(r22, g_XMZero); // (4*x^2, 4*y^2, 4*z^2, 4*w^2) - XMVECTOR t0 = vmulq_f32(XMPMMP, r00); - XMVECTOR x2y2z2w2 = vmlaq_f32(t0, XMMPMP, r11); + float32x4_t t0 = vmulq_f32(XMPMMP, r00); + float32x4_t x2y2z2w2 = vmlaq_f32(t0, XMMPMP, r11); x2y2z2w2 = vmlaq_f32(x2y2z2w2, XMMMPP, r22); x2y2z2w2 = vaddq_f32(x2y2z2w2, g_XMOne); // (r01, r02, r12, r11) t0 = vextq_f32(r0, r0, 1); - XMVECTOR t1 = vextq_f32(r1, r1, 1); + float32x4_t t1 = vextq_f32(r1, r1, 1); t0 = vcombine_f32(vget_low_f32(t0), vrev64_f32(vget_low_f32(t1))); // (r10, r20, r21, r10) t1 = vextq_f32(r2, r2, 3); - XMVECTOR r10 = vdupq_lane_f32(vget_low_f32(r1), 0); + float32x4_t r10 = vdupq_lane_f32(vget_low_f32(r1), 0); t1 = vbslq_f32(Select0110, t1, r10); // (4*x*y, 4*x*z, 4*y*z, unused) - XMVECTOR xyxzyz = vaddq_f32(t0, t1); + float32x4_t xyxzyz = vaddq_f32(t0, t1); // (r21, r20, r10, r10) t0 = vcombine_f32(vrev64_f32(vget_low_f32(r2)), vget_low_f32(r10)); // (r12, r02, r01, r12) - XMVECTOR t2 = vcombine_f32(vrev64_f32(vget_high_f32(r0)), vrev64_f32(vget_low_f32(r0))); - XMVECTOR t3 = vdupq_lane_f32(vget_high_f32(r1), 0); + float32x4_t t2 = vcombine_f32(vrev64_f32(vget_high_f32(r0)), vrev64_f32(vget_low_f32(r0))); + float32x4_t t3 = vdupq_lane_f32(vget_high_f32(r1), 0); t1 = vbslq_f32(Select0110, t2, t3); // (4*x*w, 4*y*w, 4*z*w, unused) - XMVECTOR xwywzw = vsubq_f32(t0, t1); + float32x4_t xwywzw = vsubq_f32(t0, t1); xwywzw = vmulq_f32(XMMPMP, xwywzw); // (4*x*x, 4*x*y, 4*x*z, 4*x*w) t0 = vextq_f32(xyxzyz, xyxzyz, 3); t1 = vbslq_f32(Select0110, t0, x2y2z2w2); t2 = vdupq_lane_f32(vget_low_f32(xwywzw), 0); - XMVECTOR tensor0 = vbslq_f32(g_XMSelect1110, t1, t2); + float32x4_t tensor0 = vbslq_f32(g_XMSelect1110, t1, t2); // (4*y*x, 4*y*y, 4*y*z, 4*y*w) t0 = vbslq_f32(g_XMSelect1011, xyxzyz, x2y2z2w2); t1 = vdupq_lane_f32(vget_low_f32(xwywzw), 1); - XMVECTOR tensor1 = vbslq_f32(g_XMSelect1110, t0, t1); + float32x4_t tensor1 = vbslq_f32(g_XMSelect1110, t0, t1); // (4*z*x, 4*z*y, 4*z*z, 4*z*w) t0 = vextq_f32(xyxzyz, xyxzyz, 1); t1 = vcombine_f32(vget_low_f32(t0), vrev64_f32(vget_high_f32(xwywzw))); - XMVECTOR tensor2 = vbslq_f32(Select0010, x2y2z2w2, t1); + float32x4_t tensor2 = vbslq_f32(Select0010, x2y2z2w2, t1); // (4*w*x, 4*w*y, 4*w*z, 4*w*w) - XMVECTOR tensor3 = vbslq_f32(g_XMSelect1110, xwywzw, x2y2z2w2); + float32x4_t tensor3 = vbslq_f32(g_XMSelect1110, xwywzw, x2y2z2w2); // Select the row of the tensor-product matrix that has the largest // magnitude. @@ -925,11 +966,11 @@ inline void XM_CALLCONV XMQuaternionToAxisAngle * ****************************************************************************/ - //------------------------------------------------------------------------------ - // Comparison operations - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +// Comparison operations +//------------------------------------------------------------------------------ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ inline bool XM_CALLCONV XMPlaneEqual ( @@ -1176,7 +1217,7 @@ inline void XM_CALLCONV XMPlaneIntersectPlane inline XMVECTOR XM_CALLCONV XMPlaneTransform ( FXMVECTOR P, - FXMMATRIX M + FXMMATRIX ITM ) noexcept { XMVECTOR W = XMVectorSplatW(P); @@ -1184,10 +1225,10 @@ inline XMVECTOR XM_CALLCONV XMPlaneTransform XMVECTOR Y = XMVectorSplatY(P); XMVECTOR X = XMVectorSplatX(P); - XMVECTOR Result = XMVectorMultiply(W, M.r[3]); - Result = XMVectorMultiplyAdd(Z, M.r[2], Result); - Result = XMVectorMultiplyAdd(Y, M.r[1], Result); - Result = XMVectorMultiplyAdd(X, M.r[0], Result); + XMVECTOR Result = XMVectorMultiply(W, ITM.r[3]); + Result = XMVectorMultiplyAdd(Z, ITM.r[2], Result); + Result = XMVectorMultiplyAdd(Y, ITM.r[1], Result); + Result = XMVectorMultiplyAdd(X, ITM.r[0], Result); return Result; } @@ -1195,12 +1236,12 @@ inline XMVECTOR XM_CALLCONV XMPlaneTransform _Use_decl_annotations_ inline XMFLOAT4* XM_CALLCONV XMPlaneTransformStream ( - XMFLOAT4* pOutputStream, + XMFLOAT4* pOutputStream, size_t OutputStride, const XMFLOAT4* pInputStream, size_t InputStride, size_t PlaneCount, - FXMMATRIX M + FXMMATRIX ITM ) noexcept { return XMVector4TransformStream(pOutputStream, @@ -1208,7 +1249,7 @@ inline XMFLOAT4* XM_CALLCONV XMPlaneTransformStream pInputStream, InputStride, PlaneCount, - M); + ITM); } //------------------------------------------------------------------------------ @@ -1257,11 +1298,11 @@ inline XMVECTOR XM_CALLCONV XMPlaneFromPoints * ****************************************************************************/ - //------------------------------------------------------------------------------ - // Comparison operations - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +// Comparison operations +//------------------------------------------------------------------------------ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ inline bool XM_CALLCONV XMColorEqual ( @@ -1358,8 +1399,8 @@ inline XMVECTOR XM_CALLCONV XMColorNegative(FXMVECTOR vColor) noexcept } } }; return vResult.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - XMVECTOR vTemp = veorq_u32(vColor, g_XMNegate3); - return vaddq_f32(vTemp, g_XMOne3); + uint32x4_t vTemp = veorq_u32(vreinterpretq_u32_f32(vColor), g_XMNegate3); + return vaddq_f32(vreinterpretq_f32_u32(vTemp), g_XMOne3); #elif defined(_XM_SSE_INTRINSICS_) // Negate only x,y and z. XMVECTOR vTemp = _mm_xor_ps(vColor, g_XMNegate3); @@ -1520,7 +1561,7 @@ inline XMVECTOR XM_CALLCONV XMColorRGBToHSL(FXMVECTOR rgb) noexcept //------------------------------------------------------------------------------ -namespace Internal +namespace MathInternal { inline XMVECTOR XM_CALLCONV XMColorHue2Clr(FXMVECTOR p, FXMVECTOR q, FXMVECTOR h) noexcept @@ -1558,7 +1599,7 @@ namespace Internal return p; } -} // namespace Internal +} // namespace MathInternal inline XMVECTOR XM_CALLCONV XMColorHSLToRGB(FXMVECTOR hsl) noexcept { @@ -1588,9 +1629,9 @@ inline XMVECTOR XM_CALLCONV XMColorHSLToRGB(FXMVECTOR hsl) noexcept XMVECTOR p = XMVectorSubtract(XMVectorMultiply(g_XMTwo, l), q); - XMVECTOR r = DirectX::Internal::XMColorHue2Clr(p, q, XMVectorAdd(h, oneThird)); - XMVECTOR g = DirectX::Internal::XMColorHue2Clr(p, q, h); - XMVECTOR b = DirectX::Internal::XMColorHue2Clr(p, q, XMVectorSubtract(h, oneThird)); + XMVECTOR r = DirectX::MathInternal::XMColorHue2Clr(p, q, XMVectorAdd(h, oneThird)); + XMVECTOR g = DirectX::MathInternal::XMColorHue2Clr(p, q, h); + XMVECTOR b = DirectX::MathInternal::XMColorHue2Clr(p, q, XMVectorSubtract(h, oneThird)); XMVECTOR rg = XMVectorSelect(g, r, g_XMSelect1000); XMVECTOR ba = XMVectorSelect(hsl, b, g_XMSelect1110); @@ -1683,41 +1724,41 @@ inline XMVECTOR XM_CALLCONV XMColorHSVToRGB(FXMVECTOR hsv) noexcept switch (ii) { case 0: // rgb = vtp - { - XMVECTOR vt = XMVectorSelect(t, v, g_XMSelect1000); - _rgb = XMVectorSelect(p, vt, g_XMSelect1100); - } - break; + { + XMVECTOR vt = XMVectorSelect(t, v, g_XMSelect1000); + _rgb = XMVectorSelect(p, vt, g_XMSelect1100); + } + break; case 1: // rgb = qvp - { - XMVECTOR qv = XMVectorSelect(v, q, g_XMSelect1000); - _rgb = XMVectorSelect(p, qv, g_XMSelect1100); - } - break; + { + XMVECTOR qv = XMVectorSelect(v, q, g_XMSelect1000); + _rgb = XMVectorSelect(p, qv, g_XMSelect1100); + } + break; case 2: // rgb = pvt - { - XMVECTOR pv = XMVectorSelect(v, p, g_XMSelect1000); - _rgb = XMVectorSelect(t, pv, g_XMSelect1100); - } - break; + { + XMVECTOR pv = XMVectorSelect(v, p, g_XMSelect1000); + _rgb = XMVectorSelect(t, pv, g_XMSelect1100); + } + break; case 3: // rgb = pqv - { - XMVECTOR pq = XMVectorSelect(q, p, g_XMSelect1000); - _rgb = XMVectorSelect(v, pq, g_XMSelect1100); - } - break; + { + XMVECTOR pq = XMVectorSelect(q, p, g_XMSelect1000); + _rgb = XMVectorSelect(v, pq, g_XMSelect1100); + } + break; case 4: // rgb = tpv - { - XMVECTOR tp = XMVectorSelect(p, t, g_XMSelect1000); - _rgb = XMVectorSelect(v, tp, g_XMSelect1100); - } - break; + { + XMVECTOR tp = XMVectorSelect(p, t, g_XMSelect1000); + _rgb = XMVectorSelect(v, tp, g_XMSelect1100); + } + break; default: // rgb = vpq - { - XMVECTOR vp = XMVectorSelect(p, v, g_XMSelect1000); - _rgb = XMVectorSelect(q, vp, g_XMSelect1100); - } - break; + { + XMVECTOR vp = XMVectorSelect(p, v, g_XMSelect1000); + _rgb = XMVectorSelect(q, vp, g_XMSelect1100); + } + break; } return XMVectorSelect(hsv, _rgb, g_XMSelect1110); @@ -1779,6 +1820,33 @@ inline XMVECTOR XM_CALLCONV XMColorYUVToRGB_HD(FXMVECTOR yuv) noexcept //------------------------------------------------------------------------------ +inline XMVECTOR XM_CALLCONV XMColorRGBToYUV_UHD(FXMVECTOR rgb) noexcept +{ + static const XMVECTORF32 Scale0 = { { { 0.2627f, -0.1215f, 0.6150f, 0.0f } } }; + static const XMVECTORF32 Scale1 = { { { 0.6780f, -0.3136f, -0.5655f, 0.0f } } }; + static const XMVECTORF32 Scale2 = { { { 0.0593f, 0.4351f, -0.0495f, 0.0f } } }; + + XMMATRIX M(Scale0, Scale1, Scale2, g_XMZero); + XMVECTOR clr = XMVector3Transform(rgb, M); + + return XMVectorSelect(rgb, clr, g_XMSelect1110); +} + +//------------------------------------------------------------------------------ + +inline XMVECTOR XM_CALLCONV XMColorYUVToRGB_UHD(FXMVECTOR yuv) noexcept +{ + static const XMVECTORF32 Scale1 = { { { 0.0f, -0.1891f, 2.1620f, 0.0f } } }; + static const XMVECTORF32 Scale2 = { { { 1.1989f, -0.4645f, 0.0f, 0.0f } } }; + + XMMATRIX M(g_XMOne, Scale1, Scale2, g_XMZero); + XMVECTOR clr = XMVector3Transform(yuv, M); + + return XMVectorSelect(yuv, clr, g_XMSelect1110); +} + +//------------------------------------------------------------------------------ + inline XMVECTOR XM_CALLCONV XMColorRGBToXYZ(FXMVECTOR rgb) noexcept { static const XMVECTORF32 Scale0 = { { { 0.4887180f, 0.1762044f, 0.0000000f, 0.0f } } }; @@ -1899,13 +1967,13 @@ inline XMVECTOR XM_CALLCONV XMColorSRGBToRGB(FXMVECTOR srgb) noexcept * ****************************************************************************/ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ inline bool XMVerifyCPUSupport() noexcept { -#if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) +#if defined(_XM_SSE_INTRINSICS_) && !defined(__powerpc64__) && !defined(_XM_NO_INTRINSICS_) int CPUInfo[4] = { -1 }; -#if defined(__clang__) || defined(__GNUC__) +#if (defined(__clang__) || defined(__GNUC__)) && !defined(_MSC_VER) && !defined(__MINGW32__) __cpuid(0, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]); #else __cpuid(CPUInfo, 0); @@ -1919,7 +1987,7 @@ inline bool XMVerifyCPUSupport() noexcept return false; #endif -#if defined(__clang__) || defined(__GNUC__) +#if (defined(__clang__) || defined(__GNUC__)) && !defined(_MSC_VER) && !defined(__MINGW32__) __cpuid(1, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]); #else __cpuid(CPUInfo, 1); @@ -1954,7 +2022,7 @@ inline bool XMVerifyCPUSupport() noexcept return false; // No SSE2/SSE support #if defined(__AVX2__) || defined(_XM_AVX2_INTRINSICS_) -#if defined(__clang__) || defined(__GNUC__) +#if (defined(__clang__) || defined(__GNUC__)) && !defined(_MSC_VER) && !defined(__MINGW32__) __cpuid_count(7, 0, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]); #else __cpuidex(CPUInfo, 7, 0); diff --git a/directxmath/directxmathvector.inl b/src/directxmath/DirectXMathVector.inl similarity index 88% rename from directxmath/directxmathvector.inl rename to src/directxmath/DirectXMathVector.inl index f76d597..068310d 100644 --- a/directxmath/directxmathvector.inl +++ b/src/directxmath/DirectXMathVector.inl @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------------- // DirectXMathVector.inl -- SIMD C++ Math library // -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // -// http://go.microsoft.com/fwlink/?LinkID=615560 +// https://go.microsoft.com/fwlink/?LinkID=615560 //------------------------------------------------------------------------------------- #pragma once @@ -37,12 +37,12 @@ * ****************************************************************************/ - //------------------------------------------------------------------------------ - // Assignment operations - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +// Assignment operations +//------------------------------------------------------------------------------ - //------------------------------------------------------------------------------ - // Return a vector with all elements equaling zero +//------------------------------------------------------------------------------ +// Return a vector with all elements equaling zero inline XMVECTOR XM_CALLCONV XMVectorZero() noexcept { #if defined(_XM_NO_INTRINSICS_) @@ -97,7 +97,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSetInt #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x2_t V0 = vcreate_u32(static_cast(x) | (static_cast(y) << 32)); uint32x2_t V1 = vcreate_u32(static_cast(z) | (static_cast(w) << 32)); - return vcombine_u32(V0, V1); + return vreinterpretq_f32_u32(vcombine_u32(V0, V1)); #elif defined(_XM_SSE_INTRINSICS_) __m128i V = _mm_set_epi32(static_cast(w), static_cast(z), static_cast(y), static_cast(x)); return _mm_castsi128_ps(V); @@ -156,7 +156,7 @@ inline XMVECTOR XM_CALLCONV XMVectorReplicateInt(uint32_t Value) noexcept vResult.u[3] = Value; return vResult.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vdupq_n_u32(Value); + return vreinterpretq_f32_u32(vdupq_n_u32(Value)); #elif defined(_XM_SSE_INTRINSICS_) __m128i vTemp = _mm_set1_epi32(static_cast(Value)); return _mm_castsi128_ps(vTemp); @@ -177,7 +177,7 @@ inline XMVECTOR XM_CALLCONV XMVectorReplicateIntPtr(const uint32_t* pValue) noex vResult.u[3] = Value; return vResult.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vld1q_dup_u32(pValue); + return vreinterpretq_f32_u32(vld1q_dup_u32(pValue)); #elif defined(_XM_SSE_INTRINSICS_) return _mm_load_ps1(reinterpret_cast(pValue)); #endif @@ -191,7 +191,7 @@ inline XMVECTOR XM_CALLCONV XMVectorTrueInt() noexcept XMVECTORU32 vResult = { { { 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU } } }; return vResult.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vdupq_n_s32(-1); + return vreinterpretq_f32_s32(vdupq_n_s32(-1)); #elif defined(_XM_SSE_INTRINSICS_) __m128i V = _mm_set1_epi32(-1); return _mm_castsi128_ps(V); @@ -206,7 +206,7 @@ inline XMVECTOR XM_CALLCONV XMVectorFalseInt() noexcept XMVECTORF32 vResult = { { { 0.0f, 0.0f, 0.0f, 0.0f } } }; return vResult; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vdupq_n_u32(0); + return vreinterpretq_f32_u32(vdupq_n_u32(0)); #elif defined(_XM_SSE_INTRINSICS_) return _mm_setzero_ps(); #endif @@ -316,7 +316,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSplatInfinity() noexcept vResult.u[3] = 0x7F800000; return vResult.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vdupq_n_u32(0x7F800000); + return vreinterpretq_f32_u32(vdupq_n_u32(0x7F800000)); #elif defined(_XM_SSE_INTRINSICS_) return g_XMInfinity; #endif @@ -334,7 +334,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSplatQNaN() noexcept vResult.u[3] = 0x7FC00000; return vResult.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vdupq_n_u32(0x7FC00000); + return vreinterpretq_f32_u32(vdupq_n_u32(0x7FC00000)); #elif defined(_XM_SSE_INTRINSICS_) return g_XMQNaN; #endif @@ -352,7 +352,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSplatEpsilon() noexcept vResult.u[3] = 0x34000000; return vResult.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vdupq_n_u32(0x34000000); + return vreinterpretq_f32_u32(vdupq_n_u32(0x34000000)); #elif defined(_XM_SSE_INTRINSICS_) return g_XMEpsilon; #endif @@ -370,7 +370,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSplatSignMask() noexcept vResult.u[3] = 0x80000000U; return vResult.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vdupq_n_u32(0x80000000U); + return vreinterpretq_f32_u32(vdupq_n_u32(0x80000000U)); #elif defined(_XM_SSE_INTRINSICS_) __m128i V = _mm_set1_epi32(static_cast(0x80000000)); return _mm_castsi128_ps(V); @@ -555,7 +555,7 @@ inline uint32_t XM_CALLCONV XMVectorGetIntX(FXMVECTOR V) noexcept #if defined(_XM_NO_INTRINSICS_) return V.vector4_u32[0]; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vgetq_lane_u32(V, 0); + return vgetq_lane_u32(vreinterpretq_u32_f32(V), 0); #elif defined(_XM_SSE_INTRINSICS_) return static_cast(_mm_cvtsi128_si32(_mm_castps_si128(V))); #endif @@ -567,7 +567,7 @@ inline uint32_t XM_CALLCONV XMVectorGetIntY(FXMVECTOR V) noexcept #if defined(_XM_NO_INTRINSICS_) return V.vector4_u32[1]; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vgetq_lane_u32(V, 1); + return vgetq_lane_u32(vreinterpretq_u32_f32(V), 1); #elif defined(_XM_SSE4_INTRINSICS_) __m128i V1 = _mm_castps_si128(V); return static_cast(_mm_extract_epi32(V1, 1)); @@ -583,7 +583,7 @@ inline uint32_t XM_CALLCONV XMVectorGetIntZ(FXMVECTOR V) noexcept #if defined(_XM_NO_INTRINSICS_) return V.vector4_u32[2]; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vgetq_lane_u32(V, 2); + return vgetq_lane_u32(vreinterpretq_u32_f32(V), 2); #elif defined(_XM_SSE4_INTRINSICS_) __m128i V1 = _mm_castps_si128(V); return static_cast(_mm_extract_epi32(V1, 2)); @@ -599,7 +599,7 @@ inline uint32_t XM_CALLCONV XMVectorGetIntW(FXMVECTOR V) noexcept #if defined(_XM_NO_INTRINSICS_) return V.vector4_u32[3]; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vgetq_lane_u32(V, 3); + return vgetq_lane_u32(vreinterpretq_u32_f32(V), 3); #elif defined(_XM_SSE4_INTRINSICS_) __m128i V1 = _mm_castps_si128(V); return static_cast(_mm_extract_epi32(V1, 3)); @@ -971,7 +971,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSetIntX(FXMVECTOR V, uint32_t x) noexcept } } }; return U.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vsetq_lane_u32(x, V, 0); + return vreinterpretq_f32_u32(vsetq_lane_u32(x, vreinterpretq_u32_f32(V), 0)); #elif defined(_XM_SSE_INTRINSICS_) __m128i vTemp = _mm_cvtsi32_si128(static_cast(x)); XMVECTOR vResult = _mm_move_ss(V, _mm_castsi128_ps(vTemp)); @@ -991,7 +991,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSetIntY(FXMVECTOR V, uint32_t y) noexcept } } }; return U.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vsetq_lane_u32(y, V, 1); + return vreinterpretq_f32_u32(vsetq_lane_u32(y, vreinterpretq_u32_f32(V), 1)); #elif defined(_XM_SSE4_INTRINSICS_) __m128i vResult = _mm_castps_si128(V); vResult = _mm_insert_epi32(vResult, static_cast(y), 1); @@ -1021,7 +1021,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSetIntZ(FXMVECTOR V, uint32_t z) noexcept } } }; return U.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vsetq_lane_u32(z, V, 2); + return vreinterpretq_f32_u32(vsetq_lane_u32(z, vreinterpretq_u32_f32(V), 2)); #elif defined(_XM_SSE4_INTRINSICS_) __m128i vResult = _mm_castps_si128(V); vResult = _mm_insert_epi32(vResult, static_cast(z), 2); @@ -1051,7 +1051,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSetIntW(FXMVECTOR V, uint32_t w) noexcept } } }; return U.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vsetq_lane_u32(w, V, 3); + return vreinterpretq_f32_u32(vsetq_lane_u32(w, vreinterpretq_u32_f32(V), 3)); #elif defined(_XM_SSE4_INTRINSICS_) __m128i vResult = _mm_castps_si128(V); vResult = _mm_insert_epi32(vResult, static_cast(w), 3); @@ -1100,7 +1100,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSetIntXPtr(FXMVECTOR V, const uint32_t* x) n } } }; return U.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vld1q_lane_u32(x, *reinterpret_cast(&V), 0); + return vreinterpretq_f32_u32(vld1q_lane_u32(x, *reinterpret_cast(&V), 0)); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_load_ss(reinterpret_cast(x)); XMVECTOR vResult = _mm_move_ss(V, vTemp); @@ -1122,7 +1122,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSetIntYPtr(FXMVECTOR V, const uint32_t* y) n } } }; return U.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vld1q_lane_u32(y, *reinterpret_cast(&V), 1); + return vreinterpretq_f32_u32(vld1q_lane_u32(y, *reinterpret_cast(&V), 1)); #elif defined(_XM_SSE_INTRINSICS_) // Swap y and x XMVECTOR vResult = XM_PERMUTE_PS(V, _MM_SHUFFLE(3, 2, 0, 1)); @@ -1150,7 +1150,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSetIntZPtr(FXMVECTOR V, const uint32_t* z) n } } }; return U.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vld1q_lane_u32(z, *reinterpret_cast(&V), 2); + return vreinterpretq_f32_u32(vld1q_lane_u32(z, *reinterpret_cast(&V), 2)); #elif defined(_XM_SSE_INTRINSICS_) // Swap z and x XMVECTOR vResult = XM_PERMUTE_PS(V, _MM_SHUFFLE(3, 0, 1, 2)); @@ -1178,7 +1178,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSetIntWPtr(FXMVECTOR V, const uint32_t* w) n } } }; return U.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vld1q_lane_u32(w, *reinterpret_cast(&V), 3); + return vreinterpretq_f32_u32(vld1q_lane_u32(w, *reinterpret_cast(&V), 3)); #elif defined(_XM_SSE_INTRINSICS_) // Swap w and x XMVECTOR vResult = XM_PERMUTE_PS(V, _MM_SHUFFLE(0, 2, 1, 3)); @@ -1225,8 +1225,8 @@ inline XMVECTOR XM_CALLCONV XMVectorSwizzle }; uint8x8x2_t tbl; - tbl.val[0] = vget_low_f32(V); - tbl.val[1] = vget_high_f32(V); + tbl.val[0] = vreinterpret_u8_f32(vget_low_f32(V)); + tbl.val[1] = vreinterpret_u8_f32(vget_high_f32(V)); uint32x2_t idx = vcreate_u32(static_cast(ControlElement[E0]) | (static_cast(ControlElement[E1]) << 32)); const uint8x8_t rL = vtbl2_u8(tbl, vreinterpret_u8_u32(idx)); @@ -1234,23 +1234,28 @@ inline XMVECTOR XM_CALLCONV XMVectorSwizzle idx = vcreate_u32(static_cast(ControlElement[E2]) | (static_cast(ControlElement[E3]) << 32)); const uint8x8_t rH = vtbl2_u8(tbl, vreinterpret_u8_u32(idx)); - return vcombine_f32(rL, rH); + return vcombine_f32(vreinterpret_f32_u8(rL), vreinterpret_f32_u8(rH)); #elif defined(_XM_AVX_INTRINSICS_) unsigned int elem[4] = { E0, E1, E2, E3 }; __m128i vControl = _mm_loadu_si128(reinterpret_cast(&elem[0])); return _mm_permutevar_ps(V, vControl); +#else +#if defined(__GNUC__) && !defined(__clang__) + // workaround some GCC optimization behavior that breaks this function + XMVECTORU32 T; + T.v = V; + auto aPtr = reinterpret_cast(&T); #else auto aPtr = reinterpret_cast(&V); +#endif - XMVECTOR Result; - auto pWork = reinterpret_cast(&Result); + XMVECTORU32 vResult; + vResult.u[0] = aPtr[E0]; + vResult.u[1] = aPtr[E1]; + vResult.u[2] = aPtr[E2]; + vResult.u[3] = aPtr[E3]; - pWork[0] = aPtr[E0]; - pWork[1] = aPtr[E1]; - pWork[2] = aPtr[E2]; - pWork[3] = aPtr[E3]; - - return Result; + return vResult.v; #endif } @@ -1282,10 +1287,10 @@ inline XMVECTOR XM_CALLCONV XMVectorPermute }; uint8x8x4_t tbl; - tbl.val[0] = vget_low_f32(V1); - tbl.val[1] = vget_high_f32(V1); - tbl.val[2] = vget_low_f32(V2); - tbl.val[3] = vget_high_f32(V2); + tbl.val[0] = vreinterpret_u8_f32(vget_low_f32(V1)); + tbl.val[1] = vreinterpret_u8_f32(vget_high_f32(V1)); + tbl.val[2] = vreinterpret_u8_f32(vget_low_f32(V2)); + tbl.val[3] = vreinterpret_u8_f32(vget_high_f32(V2)); uint32x2_t idx = vcreate_u32(static_cast(ControlElement[PermuteX]) | (static_cast(ControlElement[PermuteY]) << 32)); const uint8x8_t rL = vtbl4_u8(tbl, vreinterpret_u8_u32(idx)); @@ -1293,7 +1298,7 @@ inline XMVECTOR XM_CALLCONV XMVectorPermute idx = vcreate_u32(static_cast(ControlElement[PermuteZ]) | (static_cast(ControlElement[PermuteW]) << 32)); const uint8x8_t rH = vtbl4_u8(tbl, vreinterpret_u8_u32(idx)); - return vcombine_f32(rL, rH); + return vcombine_f32(vreinterpret_f32_u8(rL), vreinterpret_f32_u8(rH)); #elif defined(_XM_AVX_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) static const XMVECTORU32 three = { { { 3, 3, 3, 3 } } }; @@ -1313,29 +1318,38 @@ inline XMVECTOR XM_CALLCONV XMVectorPermute #else const uint32_t* aPtr[2]; + +#if defined(__GNUC__) && !defined(__clang__) + // workaround some GCC optimization behavior that breaks this function + XMVECTORU32 T1; + T1.v = V1; + XMVECTORU32 T2; + T2.v = V2; + aPtr[0] = reinterpret_cast(&T1); + aPtr[1] = reinterpret_cast(&T2); +#else aPtr[0] = reinterpret_cast(&V1); aPtr[1] = reinterpret_cast(&V2); +#endif - XMVECTOR Result; - auto pWork = reinterpret_cast(&Result); - + XMVECTORU32 vResult; const uint32_t i0 = PermuteX & 3; const uint32_t vi0 = PermuteX >> 2; - pWork[0] = aPtr[vi0][i0]; + vResult.u[0] = aPtr[vi0][i0]; const uint32_t i1 = PermuteY & 3; const uint32_t vi1 = PermuteY >> 2; - pWork[1] = aPtr[vi1][i1]; + vResult.u[1] = aPtr[vi1][i1]; const uint32_t i2 = PermuteZ & 3; const uint32_t vi2 = PermuteZ >> 2; - pWork[2] = aPtr[vi2][i2]; + vResult.u[2] = aPtr[vi2][i2]; const uint32_t i3 = PermuteW & 3; const uint32_t vi3 = PermuteW >> 2; - pWork[3] = aPtr[vi3][i3]; + vResult.u[3] = aPtr[vi3][i3]; - return Result; + return vResult.v; #endif } @@ -1369,7 +1383,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSelectControl int32x2_t V1 = vcreate_s32(static_cast(VectorIndex2) | (static_cast(VectorIndex3) << 32)); int32x4_t vTemp = vcombine_s32(V0, V1); // Any non-zero entries become 0xFFFFFFFF else 0 - return vcgtq_s32(vTemp, g_XMZero); + return vreinterpretq_f32_u32(vcgtq_s32(vTemp, g_XMZero)); #else XMVECTOR ControlVector; const uint32_t ControlElement[] = @@ -1417,7 +1431,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSelect return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vbslq_f32(Control, V2, V1); + return vbslq_f32(vreinterpretq_u32_f32(Control), V2, V1); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp1 = _mm_andnot_ps(Control, V1); XMVECTOR vTemp2 = _mm_and_ps(V2, Control); @@ -1536,7 +1550,7 @@ inline XMVECTOR XM_CALLCONV XMVectorEqual return Control.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vceqq_f32(V1, V2); + return vreinterpretq_f32_u32(vceqq_f32(V1, V2)); #elif defined(_XM_SSE_INTRINSICS_) return _mm_cmpeq_ps(V1, V2); #endif @@ -1576,9 +1590,9 @@ inline XMVECTOR XM_CALLCONV XMVectorEqualR #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vceqq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1); + uint8x8x2_t vTemp = vzip_u8(vreinterpret_u8_u32(vget_low_u32(vResult)), vreinterpret_u8_u32(vget_high_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1); uint32_t CR = 0; if (r == 0xFFFFFFFFU) { @@ -1591,7 +1605,7 @@ inline XMVECTOR XM_CALLCONV XMVectorEqualR CR = XM_CRMASK_CR6FALSE; } *pCR = CR; - return vResult; + return vreinterpretq_f32_u32(vResult); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpeq_ps(V1, V2); uint32_t CR = 0; @@ -1633,7 +1647,7 @@ inline XMVECTOR XM_CALLCONV XMVectorEqualInt return Control.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vceqq_u32(V1, V2); + return vreinterpretq_f32_u32(vceqq_s32(vreinterpretq_s32_f32(V1), vreinterpretq_s32_f32(V2))); #elif defined(_XM_SSE_INTRINSICS_) __m128i V = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2)); return _mm_castsi128_ps(V); @@ -1669,10 +1683,10 @@ inline XMVECTOR XM_CALLCONV XMVectorEqualIntR return Control; #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x4_t vResult = vceqq_u32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1); + uint32x4_t vResult = vceqq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2)); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1); uint32_t CR = 0; if (r == 0xFFFFFFFFU) { @@ -1685,7 +1699,7 @@ inline XMVECTOR XM_CALLCONV XMVectorEqualIntR CR = XM_CRMASK_CR6FALSE; } *pCR = CR; - return vResult; + return vreinterpretq_f32_u32(vResult); #elif defined(_XM_SSE_INTRINSICS_) __m128i V = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2)); int iTemp = _mm_movemask_ps(_mm_castsi128_ps(V)); @@ -1734,10 +1748,10 @@ inline XMVECTOR XM_CALLCONV XMVectorNearEqual #elif defined(_XM_ARM_NEON_INTRINSICS_) float32x4_t vDelta = vsubq_f32(V1, V2); -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) return vacleq_f32(vDelta, Epsilon); #else - return vcleq_f32(vabsq_f32(vDelta), Epsilon); + return vreinterpretq_f32_u32(vcleq_f32(vabsq_f32(vDelta), Epsilon)); #endif #elif defined(_XM_SSE_INTRINSICS_) // Get the difference @@ -1770,7 +1784,7 @@ inline XMVECTOR XM_CALLCONV XMVectorNotEqual return Control.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vmvnq_u32(vceqq_f32(V1, V2)); + return vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(V1, V2))); #elif defined(_XM_SSE_INTRINSICS_) return _mm_cmpneq_ps(V1, V2); #endif @@ -1795,7 +1809,8 @@ inline XMVECTOR XM_CALLCONV XMVectorNotEqualInt return Control.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vmvnq_u32(vceqq_u32(V1, V2)); + return vreinterpretq_f32_u32(vmvnq_u32( + vceqq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2)))); #elif defined(_XM_SSE_INTRINSICS_) __m128i V = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2)); return _mm_xor_ps(_mm_castsi128_ps(V), g_XMNegOneMask); @@ -1821,7 +1836,7 @@ inline XMVECTOR XM_CALLCONV XMVectorGreater return Control.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vcgtq_f32(V1, V2); + return vreinterpretq_f32_u32(vcgtq_f32(V1, V2)); #elif defined(_XM_SSE_INTRINSICS_) return _mm_cmpgt_ps(V1, V2); #endif @@ -1862,9 +1877,9 @@ inline XMVECTOR XM_CALLCONV XMVectorGreaterR #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcgtq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1); uint32_t CR = 0; if (r == 0xFFFFFFFFU) { @@ -1877,7 +1892,7 @@ inline XMVECTOR XM_CALLCONV XMVectorGreaterR CR = XM_CRMASK_CR6FALSE; } *pCR = CR; - return vResult; + return vreinterpretq_f32_u32(vResult); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpgt_ps(V1, V2); uint32_t CR = 0; @@ -1915,7 +1930,7 @@ inline XMVECTOR XM_CALLCONV XMVectorGreaterOrEqual return Control.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vcgeq_f32(V1, V2); + return vreinterpretq_f32_u32(vcgeq_f32(V1, V2)); #elif defined(_XM_SSE_INTRINSICS_) return _mm_cmpge_ps(V1, V2); #endif @@ -1956,9 +1971,9 @@ inline XMVECTOR XM_CALLCONV XMVectorGreaterOrEqualR #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcgeq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1); uint32_t CR = 0; if (r == 0xFFFFFFFFU) { @@ -1971,7 +1986,7 @@ inline XMVECTOR XM_CALLCONV XMVectorGreaterOrEqualR CR = XM_CRMASK_CR6FALSE; } *pCR = CR; - return vResult; + return vreinterpretq_f32_u32(vResult); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpge_ps(V1, V2); uint32_t CR = 0; @@ -2009,7 +2024,7 @@ inline XMVECTOR XM_CALLCONV XMVectorLess return Control.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vcltq_f32(V1, V2); + return vreinterpretq_f32_u32(vcltq_f32(V1, V2)); #elif defined(_XM_SSE_INTRINSICS_) return _mm_cmplt_ps(V1, V2); #endif @@ -2034,7 +2049,7 @@ inline XMVECTOR XM_CALLCONV XMVectorLessOrEqual return Control.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vcleq_f32(V1, V2); + return vreinterpretq_f32_u32(vcleq_f32(V1, V2)); #elif defined(_XM_SSE_INTRINSICS_) return _mm_cmple_ps(V1, V2); #endif @@ -2060,14 +2075,14 @@ inline XMVECTOR XM_CALLCONV XMVectorInBounds #elif defined(_XM_ARM_NEON_INTRINSICS_) // Test if less than or equal - XMVECTOR vTemp1 = vcleq_f32(V, Bounds); + uint32x4_t vTemp1 = vcleq_f32(V, Bounds); // Negate the bounds - XMVECTOR vTemp2 = vnegq_f32(Bounds); + uint32x4_t vTemp2 = vreinterpretq_u32_f32(vnegq_f32(Bounds)); // Test if greater or equal (Reversed) - vTemp2 = vcleq_f32(vTemp2, V); + vTemp2 = vcleq_f32(vreinterpretq_f32_u32(vTemp2), V); // Blend answers vTemp1 = vandq_u32(vTemp1, vTemp2); - return vTemp1; + return vreinterpretq_f32_u32(vTemp1); #elif defined(_XM_SSE_INTRINSICS_) // Test if less than or equal XMVECTOR vTemp1 = _mm_cmple_ps(V, Bounds); @@ -2112,16 +2127,16 @@ inline XMVECTOR XM_CALLCONV XMVectorInBoundsR #elif defined(_XM_ARM_NEON_INTRINSICS_) // Test if less than or equal - XMVECTOR vTemp1 = vcleq_f32(V, Bounds); + uint32x4_t vTemp1 = vcleq_f32(V, Bounds); // Negate the bounds - XMVECTOR vTemp2 = vnegq_f32(Bounds); + uint32x4_t vTemp2 = vreinterpretq_u32_f32(vnegq_f32(Bounds)); // Test if greater or equal (Reversed) - vTemp2 = vcleq_f32(vTemp2, V); + vTemp2 = vcleq_f32(vreinterpretq_f32_u32(vTemp2), V); // Blend answers vTemp1 = vandq_u32(vTemp1, vTemp2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vTemp1), vget_high_u8(vTemp1)); - uint16x4x2_t vTemp3 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp3.val[1], 1); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vTemp1)), vget_high_u8(vreinterpretq_u8_u32(vTemp1))); + uint16x4x2_t vTemp3 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp3.val[1]), 1); uint32_t CR = 0; if (r == 0xFFFFFFFFU) { @@ -2129,7 +2144,7 @@ inline XMVECTOR XM_CALLCONV XMVectorInBoundsR CR = XM_CRMASK_CR6BOUNDS; } *pCR = CR; - return vTemp1; + return vreinterpretq_f32_u32(vTemp1); #elif defined(_XM_SSE_INTRINSICS_) // Test if less than or equal XMVECTOR vTemp1 = _mm_cmple_ps(V, Bounds); @@ -2153,7 +2168,7 @@ inline XMVECTOR XM_CALLCONV XMVectorInBoundsR //------------------------------------------------------------------------------ -#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma float_control(push) #pragma float_control(precise, on) #endif @@ -2171,17 +2186,37 @@ inline XMVECTOR XM_CALLCONV XMVectorIsNaN(FXMVECTOR V) noexcept return Control.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - // Test against itself. NaN is always not equal +#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) + XMVECTORU32 vResult = { { { + isnan(vgetq_lane_f32(V, 0)) ? 0xFFFFFFFFU : 0, + isnan(vgetq_lane_f32(V, 1)) ? 0xFFFFFFFFU : 0, + isnan(vgetq_lane_f32(V, 2)) ? 0xFFFFFFFFU : 0, + isnan(vgetq_lane_f32(V, 3)) ? 0xFFFFFFFFU : 0 } } }; + return vResult.v; +#else +// Test against itself. NaN is always not equal uint32x4_t vTempNan = vceqq_f32(V, V); // Flip results - return vmvnq_u32(vTempNan); + return vreinterpretq_f32_u32(vmvnq_u32(vTempNan)); +#endif #elif defined(_XM_SSE_INTRINSICS_) - // Test against itself. NaN is always not equal +#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) + XM_ALIGNED_DATA(16) float tmp[4]; + _mm_store_ps(tmp, V); + XMVECTORU32 vResult = { { { + isnan(tmp[0]) ? 0xFFFFFFFFU : 0, + isnan(tmp[1]) ? 0xFFFFFFFFU : 0, + isnan(tmp[2]) ? 0xFFFFFFFFU : 0, + isnan(tmp[3]) ? 0xFFFFFFFFU : 0 } } }; + return vResult.v; +#else +// Test against itself. NaN is always not equal return _mm_cmpneq_ps(V, V); #endif +#endif } -#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma float_control(pop) #endif @@ -2201,11 +2236,11 @@ inline XMVECTOR XM_CALLCONV XMVectorIsInfinite(FXMVECTOR V) noexcept #elif defined(_XM_ARM_NEON_INTRINSICS_) // Mask off the sign bit - uint32x4_t vTemp = vandq_u32(V, g_XMAbsMask); + uint32x4_t vTemp = vandq_u32(vreinterpretq_u32_f32(V), g_XMAbsMask); // Compare to infinity - vTemp = vceqq_f32(vTemp, g_XMInfinity); + vTemp = vceqq_f32(vreinterpretq_f32_u32(vTemp), g_XMInfinity); // If any are infinity, the signs are true. - return vTemp; + return vreinterpretq_f32_u32(vTemp); #elif defined(_XM_SSE_INTRINSICS_) // Mask off the sign bit __m128 vTemp = _mm_and_ps(V, g_XMAbsMask); @@ -2272,10 +2307,10 @@ inline XMVECTOR XM_CALLCONV XMVectorMax //------------------------------------------------------------------------------ -namespace Internal +namespace MathInternal { // Round to nearest (even) a.k.a. banker's rounding - inline float round_to_nearest(float x) + inline float round_to_nearest(float x) noexcept { float i = floorf(x); x -= i; @@ -2295,7 +2330,7 @@ namespace Internal } } -#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma float_control(push) #pragma float_control(precise, on) #endif @@ -2305,25 +2340,24 @@ inline XMVECTOR XM_CALLCONV XMVectorRound(FXMVECTOR V) noexcept #if defined(_XM_NO_INTRINSICS_) XMVECTORF32 Result = { { { - Internal::round_to_nearest(V.vector4_f32[0]), - Internal::round_to_nearest(V.vector4_f32[1]), - Internal::round_to_nearest(V.vector4_f32[2]), - Internal::round_to_nearest(V.vector4_f32[3]) + MathInternal::round_to_nearest(V.vector4_f32[0]), + MathInternal::round_to_nearest(V.vector4_f32[1]), + MathInternal::round_to_nearest(V.vector4_f32[2]), + MathInternal::round_to_nearest(V.vector4_f32[3]) } } }; return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ +#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ return vrndnq_f32(V); #else - uint32x4_t sign = vandq_u32(V, g_XMNegativeZero); - uint32x4_t sMagic = vorrq_u32(g_XMNoFraction, sign); + uint32x4_t sign = vandq_u32(vreinterpretq_u32_f32(V), g_XMNegativeZero); + float32x4_t sMagic = vreinterpretq_f32_u32(vorrq_u32(g_XMNoFraction, sign)); float32x4_t R1 = vaddq_f32(V, sMagic); R1 = vsubq_f32(R1, sMagic); float32x4_t R2 = vabsq_f32(V); uint32x4_t mask = vcleq_f32(R2, g_XMNoFraction); - XMVECTOR vResult = vbslq_f32(mask, R1, V); - return vResult; + return vbslq_f32(mask, R1, V); #endif #elif defined(_XM_SSE4_INTRINSICS_) return _mm_round_ps(V, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); @@ -2341,7 +2375,7 @@ inline XMVECTOR XM_CALLCONV XMVectorRound(FXMVECTOR V) noexcept #endif } -#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma float_control(pop) #endif @@ -2374,18 +2408,18 @@ inline XMVECTOR XM_CALLCONV XMVectorTruncate(FXMVECTOR V) noexcept return Result; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ +#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ return vrndq_f32(V); #else float32x4_t vTest = vabsq_f32(V); - vTest = vcltq_f32(vTest, g_XMNoFraction); + vTest = vreinterpretq_f32_u32(vcltq_f32(vTest, g_XMNoFraction)); int32x4_t vInt = vcvtq_s32_f32(V); - XMVECTOR vResult = vcvtq_f32_s32(vInt); + float32x4_t vResult = vcvtq_f32_s32(vInt); // All numbers less than 8388608 will use the round to int // All others, use the ORIGINAL value - return vbslq_f32(vTest, vResult, V); + return vbslq_f32(vreinterpretq_u32_f32(vTest), vResult, V); #endif #elif defined(_XM_SSE4_INTRINSICS_) return _mm_round_ps(V, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); @@ -2421,21 +2455,21 @@ inline XMVECTOR XM_CALLCONV XMVectorFloor(FXMVECTOR V) noexcept } } }; return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ +#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ return vrndmq_f32(V); #else float32x4_t vTest = vabsq_f32(V); - vTest = vcltq_f32(vTest, g_XMNoFraction); + vTest = vreinterpretq_f32_u32(vcltq_f32(vTest, g_XMNoFraction)); // Truncate int32x4_t vInt = vcvtq_s32_f32(V); - XMVECTOR vResult = vcvtq_f32_s32(vInt); - XMVECTOR vLarger = vcgtq_f32(vResult, V); + float32x4_t vResult = vcvtq_f32_s32(vInt); + uint32x4_t vLargerMask = vcgtq_f32(vResult, V); // 0 -> 0, 0xffffffff -> -1.0f - vLarger = vcvtq_f32_s32(vLarger); + float32x4_t vLarger = vcvtq_f32_s32(vreinterpretq_s32_u32(vLargerMask)); vResult = vaddq_f32(vResult, vLarger); // All numbers less than 8388608 will use the round to int // All others, use the ORIGINAL value - return vbslq_f32(vTest, vResult, V); + return vbslq_f32(vreinterpretq_u32_f32(vTest), vResult, V); #endif #elif defined(_XM_SSE4_INTRINSICS_) return _mm_floor_ps(V); @@ -2472,21 +2506,21 @@ inline XMVECTOR XM_CALLCONV XMVectorCeiling(FXMVECTOR V) noexcept } } }; return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ +#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ return vrndpq_f32(V); #else float32x4_t vTest = vabsq_f32(V); - vTest = vcltq_f32(vTest, g_XMNoFraction); + vTest = vreinterpretq_f32_u32(vcltq_f32(vTest, g_XMNoFraction)); // Truncate int32x4_t vInt = vcvtq_s32_f32(V); - XMVECTOR vResult = vcvtq_f32_s32(vInt); - XMVECTOR vSmaller = vcltq_f32(vResult, V); + float32x4_t vResult = vcvtq_f32_s32(vInt); + uint32x4_t vSmallerMask = vcltq_f32(vResult, V); // 0 -> 0, 0xffffffff -> -1.0f - vSmaller = vcvtq_f32_s32(vSmaller); + float32x4_t vSmaller = vcvtq_f32_s32(vreinterpretq_s32_u32(vSmallerMask)); vResult = vsubq_f32(vResult, vSmaller); // All numbers less than 8388608 will use the round to int // All others, use the ORIGINAL value - return vbslq_f32(vTest, vResult, V); + return vbslq_f32(vreinterpretq_u32_f32(vTest), vResult, V); #endif #elif defined(_XM_SSE4_INTRINSICS_) return _mm_ceil_ps(V); @@ -2529,8 +2563,7 @@ inline XMVECTOR XM_CALLCONV XMVectorClamp return Result; #elif defined(_XM_ARM_NEON_INTRINSICS_) - XMVECTOR vResult; - vResult = vmaxq_f32(Min, V); + float32x4_t vResult = vmaxq_f32(Min, V); vResult = vminq_f32(Max, vResult); return vResult; #elif defined(_XM_SSE_INTRINSICS_) @@ -2553,7 +2586,7 @@ inline XMVECTOR XM_CALLCONV XMVectorSaturate(FXMVECTOR V) noexcept #elif defined(_XM_ARM_NEON_INTRINSICS_) // Set <0 to 0 - XMVECTOR vResult = vmaxq_f32(V, vdupq_n_f32(0)); + float32x4_t vResult = vmaxq_f32(V, vdupq_n_f32(0)); // Set>1 to 1 return vminq_f32(vResult, vdupq_n_f32(1.0f)); #elif defined(_XM_SSE_INTRINSICS_) @@ -2585,7 +2618,7 @@ inline XMVECTOR XM_CALLCONV XMVectorAndInt return Result; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vandq_u32(V1, V2); + return vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2))); #elif defined(_XM_SSE_INTRINSICS_) return _mm_and_ps(V1, V2); #endif @@ -2610,7 +2643,7 @@ inline XMVECTOR XM_CALLCONV XMVectorAndCInt return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vbicq_u32(V1, V2); + return vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2))); #elif defined(_XM_SSE_INTRINSICS_) __m128i V = _mm_andnot_si128(_mm_castps_si128(V2), _mm_castps_si128(V1)); return _mm_castsi128_ps(V); @@ -2636,7 +2669,7 @@ inline XMVECTOR XM_CALLCONV XMVectorOrInt return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return vorrq_u32(V1, V2); + return vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2))); #elif defined(_XM_SSE_INTRINSICS_) __m128i V = _mm_or_si128(_mm_castps_si128(V1), _mm_castps_si128(V2)); return _mm_castsi128_ps(V); @@ -2662,8 +2695,8 @@ inline XMVECTOR XM_CALLCONV XMVectorNorInt return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x4_t Result = vorrq_u32(V1, V2); - return vbicq_u32(g_XMNegOneMask, Result); + uint32x4_t Result = vorrq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2)); + return vreinterpretq_f32_u32(vbicq_u32(g_XMNegOneMask, Result)); #elif defined(_XM_SSE_INTRINSICS_) __m128i Result; Result = _mm_or_si128(_mm_castps_si128(V1), _mm_castps_si128(V2)); @@ -2691,7 +2724,7 @@ inline XMVECTOR XM_CALLCONV XMVectorXorInt return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - return veorq_u32(V1, V2); + return vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2))); #elif defined(_XM_SSE_INTRINSICS_) __m128i V = _mm_xor_si128(_mm_castps_si128(V1), _mm_castps_si128(V2)); return _mm_castsi128_ps(V); @@ -2766,8 +2799,8 @@ inline XMVECTOR XM_CALLCONV XMVectorSum(FXMVECTOR V) noexcept return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ - XMVECTOR vTemp = vpaddq_f32(V, V); +#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ + float32x4_t vTemp = vpaddq_f32(V, V); return vpaddq_f32(vTemp, vTemp); #else float32x2_t v1 = vget_low_f32(V); @@ -2817,17 +2850,17 @@ inline XMVECTOR XM_CALLCONV XMVectorAddAngles #elif defined(_XM_ARM_NEON_INTRINSICS_) // Adjust the angles - XMVECTOR vResult = vaddq_f32(V1, V2); + float32x4_t vResult = vaddq_f32(V1, V2); // Less than Pi? uint32x4_t vOffset = vcltq_f32(vResult, g_XMNegativePi); vOffset = vandq_u32(vOffset, g_XMTwoPi); // Add 2Pi to all entries less than -Pi - vResult = vaddq_f32(vResult, vOffset); + vResult = vaddq_f32(vResult, vreinterpretq_f32_u32(vOffset)); // Greater than or equal to Pi? vOffset = vcgeq_f32(vResult, g_XMPi); vOffset = vandq_u32(vOffset, g_XMTwoPi); // Sub 2Pi to all entries greater than Pi - vResult = vsubq_f32(vResult, vOffset); + vResult = vsubq_f32(vResult, vreinterpretq_f32_u32(vOffset)); return vResult; #elif defined(_XM_SSE_INTRINSICS_) // Adjust the angles @@ -2906,12 +2939,12 @@ inline XMVECTOR XM_CALLCONV XMVectorSubtractAngles uint32x4_t vOffset = vcltq_f32(vResult, g_XMNegativePi); vOffset = vandq_u32(vOffset, g_XMTwoPi); // Add 2Pi to all entries less than -Pi - vResult = vaddq_f32(vResult, vOffset); + vResult = vaddq_f32(vResult, vreinterpretq_f32_u32(vOffset)); // Greater than or equal to Pi? vOffset = vcgeq_f32(vResult, g_XMPi); vOffset = vandq_u32(vOffset, g_XMTwoPi); // Sub 2Pi to all entries greater than Pi - vResult = vsubq_f32(vResult, vOffset); + vResult = vsubq_f32(vResult, vreinterpretq_f32_u32(vOffset)); return vResult; #elif defined(_XM_SSE_INTRINSICS_) // Adjust the angles @@ -2971,7 +3004,7 @@ inline XMVECTOR XM_CALLCONV XMVectorMultiplyAdd } } }; return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ +#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ return vfmaq_f32(V3, V1, V2); #else return vmlaq_f32(V3, V1, V2); @@ -2998,7 +3031,7 @@ inline XMVECTOR XM_CALLCONV XMVectorDivide } } }; return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ +#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ return vdivq_f32(V1, V2); #else // 2 iterations of Newton-Raphson refinement of reciprocal @@ -3032,7 +3065,7 @@ inline XMVECTOR XM_CALLCONV XMVectorNegativeMultiplySubtract } } }; return Result; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ +#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ return vfmsq_f32(V3, V1, V2); #else return vmlsq_f32(V3, V1, V2); @@ -3098,7 +3131,7 @@ inline XMVECTOR XM_CALLCONV XMVectorReciprocal(FXMVECTOR V) noexcept } } }; return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ +#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ float32x4_t one = vdupq_n_f32(1.0f); return vdivq_f32(one, V); #else @@ -3233,15 +3266,13 @@ inline XMVECTOR XM_CALLCONV XMVectorReciprocalSqrt(FXMVECTOR V) noexcept inline XMVECTOR XM_CALLCONV XMVectorExp2(FXMVECTOR V) noexcept { #if defined(_XM_NO_INTRINSICS_) - XMVECTORF32 Result = { { { - powf(2.0f, V.vector4_f32[0]), - powf(2.0f, V.vector4_f32[1]), - powf(2.0f, V.vector4_f32[2]), - powf(2.0f, V.vector4_f32[3]) + exp2f(V.vector4_f32[0]), + exp2f(V.vector4_f32[1]), + exp2f(V.vector4_f32[2]), + exp2f(V.vector4_f32[3]) } } }; - return Result; - + return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) int32x4_t itrunc = vcvtq_s32_f32(V); float32x4_t ftrunc = vcvtq_f32_s32(itrunc); @@ -3257,11 +3288,11 @@ inline XMVECTOR XM_CALLCONV XMVectorExp2(FXMVECTOR V) noexcept int32x4_t biased = vaddq_s32(itrunc, g_XMExponentBias); biased = vshlq_n_s32(biased, 23); - float32x4_t result0 = XMVectorDivide(biased, poly); + float32x4_t result0 = XMVectorDivide(vreinterpretq_f32_s32(biased), poly); biased = vaddq_s32(itrunc, g_XM253); biased = vshlq_n_s32(biased, 23); - float32x4_t result1 = XMVectorDivide(biased, poly); + float32x4_t result1 = XMVectorDivide(vreinterpretq_f32_s32(biased), poly); result1 = vmulq_f32(g_XMMinNormal.v, result1); // Use selection to handle the cases @@ -3275,27 +3306,30 @@ inline XMVECTOR XM_CALLCONV XMVectorExp2(FXMVECTOR V) noexcept // if (V < 128) -> result0 // else -> +inf - int32x4_t comp = vcltq_s32(V, g_XMBin128); + uint32x4_t comp = vcltq_s32(vreinterpretq_s32_f32(V), g_XMBin128); float32x4_t result2 = vbslq_f32(comp, result0, g_XMInfinity); comp = vcltq_s32(itrunc, g_XMSubnormalExponent); float32x4_t result3 = vbslq_f32(comp, result1, result0); - comp = vcltq_s32(V, g_XMBinNeg150); + comp = vcltq_s32(vreinterpretq_s32_f32(V), g_XMBinNeg150); float32x4_t result4 = vbslq_f32(comp, result3, g_XMZero); - int32x4_t sign = vandq_s32(V, g_XMNegativeZero); + int32x4_t sign = vandq_s32(vreinterpretq_s32_f32(V), g_XMNegativeZero); comp = vceqq_s32(sign, g_XMNegativeZero); float32x4_t result5 = vbslq_f32(comp, result4, result2); - int32x4_t t0 = vandq_s32(V, g_XMQNaNTest); - int32x4_t t1 = vandq_s32(V, g_XMInfinity); - t0 = vceqq_s32(t0, g_XMZero); - t1 = vceqq_s32(t1, g_XMInfinity); + int32x4_t t0 = vandq_s32(vreinterpretq_s32_f32(V), g_XMQNaNTest); + int32x4_t t1 = vandq_s32(vreinterpretq_s32_f32(V), g_XMInfinity); + t0 = vreinterpretq_s32_u32(vceqq_s32(t0, g_XMZero)); + t1 = vreinterpretq_s32_u32(vceqq_s32(t1, g_XMInfinity)); int32x4_t isNaN = vbicq_s32(t1, t0); - float32x4_t vResult = vbslq_f32(isNaN, g_XMQNaN, result5); + float32x4_t vResult = vbslq_f32(vreinterpretq_u32_s32(isNaN), g_XMQNaN, result5); return vResult; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_exp2_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) __m128i itrunc = _mm_cvttps_epi32(V); __m128 ftrunc = _mm_cvtepi32_ps(itrunc); @@ -3366,6 +3400,30 @@ inline XMVECTOR XM_CALLCONV XMVectorExp2(FXMVECTOR V) noexcept //------------------------------------------------------------------------------ +inline XMVECTOR XM_CALLCONV XMVectorExp10(FXMVECTOR V) noexcept +{ +#if defined(_XM_NO_INTRINSICS_) + + XMVECTORF32 Result = { { { + powf(10.0f, V.vector4_f32[0]), + powf(10.0f, V.vector4_f32[1]), + powf(10.0f, V.vector4_f32[2]), + powf(10.0f, V.vector4_f32[3]) + } } }; + return Result.v; + +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_exp10_ps(V); + return Result; +#else + // exp10(V) = exp2(vin*log2(10)) + XMVECTOR Vten = XMVectorMultiply(g_XMLg10, V); + return XMVectorExp2(Vten); +#endif +} + +//------------------------------------------------------------------------------ + inline XMVECTOR XM_CALLCONV XMVectorExpE(FXMVECTOR V) noexcept { #if defined(_XM_NO_INTRINSICS_) @@ -3378,131 +3436,13 @@ inline XMVECTOR XM_CALLCONV XMVectorExpE(FXMVECTOR V) noexcept } } }; return Result.v; -#elif defined(_XM_ARM_NEON_INTRINSICS_) +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_exp_ps(V); + return Result; +#else // expE(V) = exp2(vin*log2(e)) - float32x4_t Ve = vmulq_f32(g_XMLgE, V); - - int32x4_t itrunc = vcvtq_s32_f32(Ve); - float32x4_t ftrunc = vcvtq_f32_s32(itrunc); - float32x4_t y = vsubq_f32(Ve, ftrunc); - - float32x4_t poly = vmlaq_f32(g_XMExpEst6, g_XMExpEst7, y); - poly = vmlaq_f32(g_XMExpEst5, poly, y); - poly = vmlaq_f32(g_XMExpEst4, poly, y); - poly = vmlaq_f32(g_XMExpEst3, poly, y); - poly = vmlaq_f32(g_XMExpEst2, poly, y); - poly = vmlaq_f32(g_XMExpEst1, poly, y); - poly = vmlaq_f32(g_XMOne, poly, y); - - int32x4_t biased = vaddq_s32(itrunc, g_XMExponentBias); - biased = vshlq_n_s32(biased, 23); - float32x4_t result0 = XMVectorDivide(biased, poly); - - biased = vaddq_s32(itrunc, g_XM253); - biased = vshlq_n_s32(biased, 23); - float32x4_t result1 = XMVectorDivide(biased, poly); - result1 = vmulq_f32(g_XMMinNormal.v, result1); - - // Use selection to handle the cases - // if (V is NaN) -> QNaN; - // else if (V sign bit set) - // if (V > -150) - // if (V.exponent < -126) -> result1 - // else -> result0 - // else -> +0 - // else - // if (V < 128) -> result0 - // else -> +inf - - int32x4_t comp = vcltq_s32(Ve, g_XMBin128); - float32x4_t result2 = vbslq_f32(comp, result0, g_XMInfinity); - - comp = vcltq_s32(itrunc, g_XMSubnormalExponent); - float32x4_t result3 = vbslq_f32(comp, result1, result0); - - comp = vcltq_s32(Ve, g_XMBinNeg150); - float32x4_t result4 = vbslq_f32(comp, result3, g_XMZero); - - int32x4_t sign = vandq_s32(Ve, g_XMNegativeZero); - comp = vceqq_s32(sign, g_XMNegativeZero); - float32x4_t result5 = vbslq_f32(comp, result4, result2); - - int32x4_t t0 = vandq_s32(Ve, g_XMQNaNTest); - int32x4_t t1 = vandq_s32(Ve, g_XMInfinity); - t0 = vceqq_s32(t0, g_XMZero); - t1 = vceqq_s32(t1, g_XMInfinity); - int32x4_t isNaN = vbicq_s32(t1, t0); - - float32x4_t vResult = vbslq_f32(isNaN, g_XMQNaN, result5); - return vResult; -#elif defined(_XM_SSE_INTRINSICS_) - // expE(V) = exp2(vin*log2(e)) - __m128 Ve = _mm_mul_ps(g_XMLgE, V); - - __m128i itrunc = _mm_cvttps_epi32(Ve); - __m128 ftrunc = _mm_cvtepi32_ps(itrunc); - __m128 y = _mm_sub_ps(Ve, ftrunc); - - __m128 poly = XM_FMADD_PS(y, g_XMExpEst7, g_XMExpEst6); - poly = XM_FMADD_PS(poly, y, g_XMExpEst5); - poly = XM_FMADD_PS(poly, y, g_XMExpEst4); - poly = XM_FMADD_PS(poly, y, g_XMExpEst3); - poly = XM_FMADD_PS(poly, y, g_XMExpEst2); - poly = XM_FMADD_PS(poly, y, g_XMExpEst1); - poly = XM_FMADD_PS(poly, y, g_XMOne); - - __m128i biased = _mm_add_epi32(itrunc, g_XMExponentBias); - biased = _mm_slli_epi32(biased, 23); - __m128 result0 = _mm_div_ps(_mm_castsi128_ps(biased), poly); - - biased = _mm_add_epi32(itrunc, g_XM253); - biased = _mm_slli_epi32(biased, 23); - __m128 result1 = _mm_div_ps(_mm_castsi128_ps(biased), poly); - result1 = _mm_mul_ps(g_XMMinNormal.v, result1); - - // Use selection to handle the cases - // if (V is NaN) -> QNaN; - // else if (V sign bit set) - // if (V > -150) - // if (V.exponent < -126) -> result1 - // else -> result0 - // else -> +0 - // else - // if (V < 128) -> result0 - // else -> +inf - - __m128i comp = _mm_cmplt_epi32(_mm_castps_si128(Ve), g_XMBin128); - __m128i select0 = _mm_and_si128(comp, _mm_castps_si128(result0)); - __m128i select1 = _mm_andnot_si128(comp, g_XMInfinity); - __m128i result2 = _mm_or_si128(select0, select1); - - comp = _mm_cmplt_epi32(itrunc, g_XMSubnormalExponent); - select1 = _mm_and_si128(comp, _mm_castps_si128(result1)); - select0 = _mm_andnot_si128(comp, _mm_castps_si128(result0)); - __m128i result3 = _mm_or_si128(select0, select1); - - comp = _mm_cmplt_epi32(_mm_castps_si128(Ve), g_XMBinNeg150); - select0 = _mm_and_si128(comp, result3); - select1 = _mm_andnot_si128(comp, g_XMZero); - __m128i result4 = _mm_or_si128(select0, select1); - - __m128i sign = _mm_and_si128(_mm_castps_si128(Ve), g_XMNegativeZero); - comp = _mm_cmpeq_epi32(sign, g_XMNegativeZero); - select0 = _mm_and_si128(comp, result4); - select1 = _mm_andnot_si128(comp, result2); - __m128i result5 = _mm_or_si128(select0, select1); - - __m128i t0 = _mm_and_si128(_mm_castps_si128(Ve), g_XMQNaNTest); - __m128i t1 = _mm_and_si128(_mm_castps_si128(Ve), g_XMInfinity); - t0 = _mm_cmpeq_epi32(t0, g_XMZero); - t1 = _mm_cmpeq_epi32(t1, g_XMInfinity); - __m128i isNaN = _mm_andnot_si128(t0, t1); - - select0 = _mm_and_si128(isNaN, g_XMQNaN); - select1 = _mm_andnot_si128(isNaN, result5); - __m128i vResult = _mm_or_si128(select0, select1); - - return _mm_castsi128_ps(vResult); + XMVECTOR Ve = XMVectorMultiply(g_XMLgE, V); + return XMVectorExp2(Ve); #endif } @@ -3517,9 +3457,9 @@ inline XMVECTOR XM_CALLCONV XMVectorExp(FXMVECTOR V) noexcept #if defined(_XM_SSE_INTRINSICS_) -namespace Internal +namespace MathInternal { - inline __m128i multi_sll_epi32(__m128i value, __m128i count) + inline __m128i multi_sll_epi32(__m128i value, __m128i count) noexcept { __m128i v = _mm_shuffle_epi32(value, _MM_SHUFFLE(0, 0, 0, 0)); __m128i c = _mm_shuffle_epi32(count, _MM_SHUFFLE(0, 0, 0, 0)); @@ -3550,7 +3490,7 @@ namespace Internal return _mm_castps_si128(result); } - inline __m128i multi_srl_epi32(__m128i value, __m128i count) + inline __m128i multi_srl_epi32(__m128i value, __m128i count) noexcept { __m128i v = _mm_shuffle_epi32(value, _MM_SHUFFLE(0, 0, 0, 0)); __m128i c = _mm_shuffle_epi32(count, _MM_SHUFFLE(0, 0, 0, 0)); @@ -3581,7 +3521,7 @@ namespace Internal return _mm_castps_si128(result); } - inline __m128i GetLeadingBit(const __m128i value) + inline __m128i GetLeadingBit(const __m128i value) noexcept { static const XMVECTORI32 g_XM0000FFFF = { { { 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF } } }; static const XMVECTORI32 g_XM000000FF = { { { 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF } } }; @@ -3617,56 +3557,54 @@ namespace Internal r = _mm_or_si128(r, s); return r; } -} // namespace Internal +} // namespace MathInternal #endif // _XM_SSE_INTRINSICS_ #if defined(_XM_ARM_NEON_INTRINSICS_) -namespace Internal +namespace MathInternal { - inline int32x4_t GetLeadingBit(const int32x4_t value) + inline int32x4_t GetLeadingBit(const int32x4_t value) noexcept { static const XMVECTORI32 g_XM0000FFFF = { { { 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF } } }; static const XMVECTORI32 g_XM000000FF = { { { 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF } } }; static const XMVECTORI32 g_XM0000000F = { { { 0x0000000F, 0x0000000F, 0x0000000F, 0x0000000F } } }; static const XMVECTORI32 g_XM00000003 = { { { 0x00000003, 0x00000003, 0x00000003, 0x00000003 } } }; - int32x4_t v = value, r, c, b, s; - - c = vcgtq_s32(v, g_XM0000FFFF); // c = (v > 0xFFFF) - b = vshrq_n_u32(c, 31); // b = (c ? 1 : 0) - r = vshlq_n_s32(b, 4); // r = (b << 4) + uint32x4_t c = vcgtq_s32(value, g_XM0000FFFF); // c = (v > 0xFFFF) + int32x4_t b = vshrq_n_s32(vreinterpretq_s32_u32(c), 31); // b = (c ? 1 : 0) + int32x4_t r = vshlq_n_s32(b, 4); // r = (b << 4) r = vnegq_s32(r); - v = vshlq_u32(v, r); // v = (v >> r) + int32x4_t v = vshlq_s32(value, r); // v = (v >> r) - c = vcgtq_s32(v, g_XM000000FF); // c = (v > 0xFF) - b = vshrq_n_u32(c, 31); // b = (c ? 1 : 0) - s = vshlq_n_s32(b, 3); // s = (b << 3) + c = vcgtq_s32(v, g_XM000000FF); // c = (v > 0xFF) + b = vshrq_n_s32(vreinterpretq_s32_u32(c), 31); // b = (c ? 1 : 0) + int32x4_t s = vshlq_n_s32(b, 3); // s = (b << 3) s = vnegq_s32(s); - v = vshlq_u32(v, s); // v = (v >> s) - r = vorrq_s32(r, s); // r = (r | s) + v = vshlq_s32(v, s); // v = (v >> s) + r = vorrq_s32(r, s); // r = (r | s) - c = vcgtq_s32(v, g_XM0000000F); // c = (v > 0xF) - b = vshrq_n_u32(c, 31); // b = (c ? 1 : 0) - s = vshlq_n_s32(b, 2); // s = (b << 2) + c = vcgtq_s32(v, g_XM0000000F); // c = (v > 0xF) + b = vshrq_n_s32(vreinterpretq_s32_u32(c), 31); // b = (c ? 1 : 0) + s = vshlq_n_s32(b, 2); // s = (b << 2) s = vnegq_s32(s); - v = vshlq_u32(v, s); // v = (v >> s) - r = vorrq_s32(r, s); // r = (r | s) + v = vshlq_s32(v, s); // v = (v >> s) + r = vorrq_s32(r, s); // r = (r | s) - c = vcgtq_s32(v, g_XM00000003); // c = (v > 0x3) - b = vshrq_n_u32(c, 31); // b = (c ? 1 : 0) - s = vshlq_n_s32(b, 1); // s = (b << 1) + c = vcgtq_s32(v, g_XM00000003); // c = (v > 0x3) + b = vshrq_n_s32(vreinterpretq_s32_u32(c), 31); // b = (c ? 1 : 0) + s = vshlq_n_s32(b, 1); // s = (b << 1) s = vnegq_s32(s); - v = vshlq_u32(v, s); // v = (v >> s) - r = vorrq_s32(r, s); // r = (r | s) + v = vshlq_s32(v, s); // v = (v >> s) + r = vorrq_s32(r, s); // r = (r | s) - s = vshrq_n_u32(v, 1); + s = vshrq_n_s32(v, 1); r = vorrq_s32(r, s); return r; } -} // namespace Internal +} // namespace MathInternal #endif @@ -3675,39 +3613,35 @@ namespace Internal inline XMVECTOR XM_CALLCONV XMVectorLog2(FXMVECTOR V) noexcept { #if defined(_XM_NO_INTRINSICS_) - - const float fScale = 1.4426950f; // (1.0f / logf(2.0f)); - XMVECTORF32 Result = { { { - logf(V.vector4_f32[0]) * fScale, - logf(V.vector4_f32[1]) * fScale, - logf(V.vector4_f32[2]) * fScale, - logf(V.vector4_f32[3]) * fScale + log2f(V.vector4_f32[0]), + log2f(V.vector4_f32[1]), + log2f(V.vector4_f32[2]), + log2f(V.vector4_f32[3]) } } }; return Result.v; - #elif defined(_XM_ARM_NEON_INTRINSICS_) - int32x4_t rawBiased = vandq_s32(V, g_XMInfinity); - int32x4_t trailing = vandq_s32(V, g_XMQNaNTest); - int32x4_t isExponentZero = vceqq_s32(g_XMZero, rawBiased); + int32x4_t rawBiased = vandq_s32(vreinterpretq_s32_f32(V), g_XMInfinity); + int32x4_t trailing = vandq_s32(vreinterpretq_s32_f32(V), g_XMQNaNTest); + uint32x4_t isExponentZero = vceqq_s32(vreinterpretq_s32_f32(g_XMZero), rawBiased); // Compute exponent and significand for normals. - int32x4_t biased = vshrq_n_u32(rawBiased, 23); + int32x4_t biased = vshrq_n_s32(rawBiased, 23); int32x4_t exponentNor = vsubq_s32(biased, g_XMExponentBias); int32x4_t trailingNor = trailing; // Compute exponent and significand for subnormals. - int32x4_t leading = Internal::GetLeadingBit(trailing); + int32x4_t leading = MathInternal::GetLeadingBit(trailing); int32x4_t shift = vsubq_s32(g_XMNumTrailing, leading); int32x4_t exponentSub = vsubq_s32(g_XMSubnormalExponent, shift); - int32x4_t trailingSub = vshlq_u32(trailing, shift); + int32x4_t trailingSub = vshlq_s32(trailing, shift); trailingSub = vandq_s32(trailingSub, g_XMQNaNTest); - int32x4_t e = vbslq_f32(isExponentZero, exponentSub, exponentNor); - int32x4_t t = vbslq_f32(isExponentZero, trailingSub, trailingNor); + int32x4_t e = vbslq_s32(isExponentZero, exponentSub, exponentNor); + int32x4_t t = vbslq_s32(isExponentZero, trailingSub, trailingNor); // Compute the approximation. - int32x4_t tmp = vorrq_s32(g_XMOne, t); - float32x4_t y = vsubq_f32(tmp, g_XMOne); + int32x4_t tmp = vorrq_s32(vreinterpretq_s32_f32(g_XMOne), t); + float32x4_t y = vsubq_f32(vreinterpretq_f32_s32(tmp), g_XMOne); float32x4_t log2 = vmlaq_f32(g_XMLogEst6, g_XMLogEst7, y); log2 = vmlaq_f32(g_XMLogEst5, log2, y); @@ -3726,27 +3660,30 @@ inline XMVECTOR XM_CALLCONV XMVectorLog2(FXMVECTOR V) noexcept // if (V is zero) -> -inf // else -> -QNaN - int32x4_t isInfinite = vandq_s32((V), g_XMAbsMask); - isInfinite = vceqq_s32(isInfinite, g_XMInfinity); + uint32x4_t isInfinite = vandq_u32(vreinterpretq_u32_f32(V), g_XMAbsMask); + isInfinite = vceqq_u32(isInfinite, g_XMInfinity); - int32x4_t isGreaterZero = vcgtq_s32((V), g_XMZero); - int32x4_t isNotFinite = vcgtq_s32((V), g_XMInfinity); - int32x4_t isPositive = vbicq_s32(isGreaterZero, isNotFinite); + uint32x4_t isGreaterZero = vcgtq_f32(V, g_XMZero); + uint32x4_t isNotFinite = vcgtq_f32(V, g_XMInfinity); + uint32x4_t isPositive = vbicq_u32(isGreaterZero, isNotFinite); - int32x4_t isZero = vandq_s32((V), g_XMAbsMask); - isZero = vceqq_s32(isZero, g_XMZero); + uint32x4_t isZero = vandq_u32(vreinterpretq_u32_f32(V), g_XMAbsMask); + isZero = vceqq_u32(isZero, g_XMZero); - int32x4_t t0 = vandq_s32((V), g_XMQNaNTest); - int32x4_t t1 = vandq_s32((V), g_XMInfinity); - t0 = vceqq_s32(t0, g_XMZero); - t1 = vceqq_s32(t1, g_XMInfinity); - int32x4_t isNaN = vbicq_s32(t1, t0); + uint32x4_t t0 = vandq_u32(vreinterpretq_u32_f32(V), g_XMQNaNTest); + uint32x4_t t1 = vandq_u32(vreinterpretq_u32_f32(V), g_XMInfinity); + t0 = vceqq_u32(t0, g_XMZero); + t1 = vceqq_u32(t1, g_XMInfinity); + uint32x4_t isNaN = vbicq_u32(t1, t0); float32x4_t result = vbslq_f32(isInfinite, g_XMInfinity, log2); - tmp = vbslq_f32(isZero, g_XMNegInfinity, g_XMNegQNaN); - result = vbslq_f32(isPositive, result, tmp); + float32x4_t tmp2 = vbslq_f32(isZero, g_XMNegInfinity, g_XMNegQNaN); + result = vbslq_f32(isPositive, result, tmp2); result = vbslq_f32(isNaN, g_XMQNaN, result); return result; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_log2_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) __m128i rawBiased = _mm_and_si128(_mm_castps_si128(V), g_XMInfinity); __m128i trailing = _mm_and_si128(_mm_castps_si128(V), g_XMQNaNTest); @@ -3758,10 +3695,10 @@ inline XMVECTOR XM_CALLCONV XMVectorLog2(FXMVECTOR V) noexcept __m128i trailingNor = trailing; // Compute exponent and significand for subnormals. - __m128i leading = Internal::GetLeadingBit(trailing); + __m128i leading = MathInternal::GetLeadingBit(trailing); __m128i shift = _mm_sub_epi32(g_XMNumTrailing, leading); __m128i exponentSub = _mm_sub_epi32(g_XMSubnormalExponent, shift); - __m128i trailingSub = Internal::multi_sll_epi32(trailing, shift); + __m128i trailingSub = MathInternal::multi_sll_epi32(trailing, shift); trailingSub = _mm_and_si128(trailingSub, g_XMQNaNTest); __m128i select0 = _mm_and_si128(isExponentZero, exponentSub); @@ -3831,6 +3768,170 @@ inline XMVECTOR XM_CALLCONV XMVectorLog2(FXMVECTOR V) noexcept //------------------------------------------------------------------------------ +inline XMVECTOR XM_CALLCONV XMVectorLog10(FXMVECTOR V) noexcept +{ +#if defined(_XM_NO_INTRINSICS_) + + XMVECTORF32 Result = { { { + log10f(V.vector4_f32[0]), + log10f(V.vector4_f32[1]), + log10f(V.vector4_f32[2]), + log10f(V.vector4_f32[3]) + } } }; + return Result.v; + +#elif defined(_XM_ARM_NEON_INTRINSICS_) + int32x4_t rawBiased = vandq_s32(vreinterpretq_s32_f32(V), g_XMInfinity); + int32x4_t trailing = vandq_s32(vreinterpretq_s32_f32(V), g_XMQNaNTest); + uint32x4_t isExponentZero = vceqq_s32(g_XMZero, rawBiased); + + // Compute exponent and significand for normals. + int32x4_t biased = vshrq_n_s32(rawBiased, 23); + int32x4_t exponentNor = vsubq_s32(biased, g_XMExponentBias); + int32x4_t trailingNor = trailing; + + // Compute exponent and significand for subnormals. + int32x4_t leading = MathInternal::GetLeadingBit(trailing); + int32x4_t shift = vsubq_s32(g_XMNumTrailing, leading); + int32x4_t exponentSub = vsubq_s32(g_XMSubnormalExponent, shift); + int32x4_t trailingSub = vshlq_s32(trailing, shift); + trailingSub = vandq_s32(trailingSub, g_XMQNaNTest); + int32x4_t e = vbslq_s32(isExponentZero, exponentSub, exponentNor); + int32x4_t t = vbslq_s32(isExponentZero, trailingSub, trailingNor); + + // Compute the approximation. + int32x4_t tmp = vorrq_s32(g_XMOne, t); + float32x4_t y = vsubq_f32(vreinterpretq_f32_s32(tmp), g_XMOne); + + float32x4_t log2 = vmlaq_f32(g_XMLogEst6, g_XMLogEst7, y); + log2 = vmlaq_f32(g_XMLogEst5, log2, y); + log2 = vmlaq_f32(g_XMLogEst4, log2, y); + log2 = vmlaq_f32(g_XMLogEst3, log2, y); + log2 = vmlaq_f32(g_XMLogEst2, log2, y); + log2 = vmlaq_f32(g_XMLogEst1, log2, y); + log2 = vmlaq_f32(g_XMLogEst0, log2, y); + log2 = vmlaq_f32(vcvtq_f32_s32(e), log2, y); + + log2 = vmulq_f32(g_XMInvLg10, log2); + + // if (x is NaN) -> QNaN + // else if (V is positive) + // if (V is infinite) -> +inf + // else -> log2(V) + // else + // if (V is zero) -> -inf + // else -> -QNaN + + uint32x4_t isInfinite = vandq_u32(vreinterpretq_u32_f32(V), g_XMAbsMask); + isInfinite = vceqq_u32(isInfinite, g_XMInfinity); + + uint32x4_t isGreaterZero = vcgtq_s32(vreinterpretq_s32_f32(V), g_XMZero); + uint32x4_t isNotFinite = vcgtq_s32(vreinterpretq_s32_f32(V), g_XMInfinity); + uint32x4_t isPositive = vbicq_u32(isGreaterZero, isNotFinite); + + uint32x4_t isZero = vandq_u32(vreinterpretq_u32_f32(V), g_XMAbsMask); + isZero = vceqq_u32(isZero, g_XMZero); + + uint32x4_t t0 = vandq_u32(vreinterpretq_u32_f32(V), g_XMQNaNTest); + uint32x4_t t1 = vandq_u32(vreinterpretq_u32_f32(V), g_XMInfinity); + t0 = vceqq_u32(t0, g_XMZero); + t1 = vceqq_u32(t1, g_XMInfinity); + uint32x4_t isNaN = vbicq_u32(t1, t0); + + float32x4_t result = vbslq_f32(isInfinite, g_XMInfinity, log2); + float32x4_t tmp2 = vbslq_f32(isZero, g_XMNegInfinity, g_XMNegQNaN); + result = vbslq_f32(isPositive, result, tmp2); + result = vbslq_f32(isNaN, g_XMQNaN, result); + return result; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_log10_ps(V); + return Result; +#elif defined(_XM_SSE_INTRINSICS_) + __m128i rawBiased = _mm_and_si128(_mm_castps_si128(V), g_XMInfinity); + __m128i trailing = _mm_and_si128(_mm_castps_si128(V), g_XMQNaNTest); + __m128i isExponentZero = _mm_cmpeq_epi32(g_XMZero, rawBiased); + + // Compute exponent and significand for normals. + __m128i biased = _mm_srli_epi32(rawBiased, 23); + __m128i exponentNor = _mm_sub_epi32(biased, g_XMExponentBias); + __m128i trailingNor = trailing; + + // Compute exponent and significand for subnormals. + __m128i leading = MathInternal::GetLeadingBit(trailing); + __m128i shift = _mm_sub_epi32(g_XMNumTrailing, leading); + __m128i exponentSub = _mm_sub_epi32(g_XMSubnormalExponent, shift); + __m128i trailingSub = MathInternal::multi_sll_epi32(trailing, shift); + trailingSub = _mm_and_si128(trailingSub, g_XMQNaNTest); + + __m128i select0 = _mm_and_si128(isExponentZero, exponentSub); + __m128i select1 = _mm_andnot_si128(isExponentZero, exponentNor); + __m128i e = _mm_or_si128(select0, select1); + + select0 = _mm_and_si128(isExponentZero, trailingSub); + select1 = _mm_andnot_si128(isExponentZero, trailingNor); + __m128i t = _mm_or_si128(select0, select1); + + // Compute the approximation. + __m128i tmp = _mm_or_si128(g_XMOne, t); + __m128 y = _mm_sub_ps(_mm_castsi128_ps(tmp), g_XMOne); + + __m128 log2 = XM_FMADD_PS(g_XMLogEst7, y, g_XMLogEst6); + log2 = XM_FMADD_PS(log2, y, g_XMLogEst5); + log2 = XM_FMADD_PS(log2, y, g_XMLogEst4); + log2 = XM_FMADD_PS(log2, y, g_XMLogEst3); + log2 = XM_FMADD_PS(log2, y, g_XMLogEst2); + log2 = XM_FMADD_PS(log2, y, g_XMLogEst1); + log2 = XM_FMADD_PS(log2, y, g_XMLogEst0); + log2 = XM_FMADD_PS(log2, y, _mm_cvtepi32_ps(e)); + + log2 = _mm_mul_ps(g_XMInvLg10, log2); + + // if (x is NaN) -> QNaN + // else if (V is positive) + // if (V is infinite) -> +inf + // else -> log2(V) + // else + // if (V is zero) -> -inf + // else -> -QNaN + + __m128i isInfinite = _mm_and_si128(_mm_castps_si128(V), g_XMAbsMask); + isInfinite = _mm_cmpeq_epi32(isInfinite, g_XMInfinity); + + __m128i isGreaterZero = _mm_cmpgt_epi32(_mm_castps_si128(V), g_XMZero); + __m128i isNotFinite = _mm_cmpgt_epi32(_mm_castps_si128(V), g_XMInfinity); + __m128i isPositive = _mm_andnot_si128(isNotFinite, isGreaterZero); + + __m128i isZero = _mm_and_si128(_mm_castps_si128(V), g_XMAbsMask); + isZero = _mm_cmpeq_epi32(isZero, g_XMZero); + + __m128i t0 = _mm_and_si128(_mm_castps_si128(V), g_XMQNaNTest); + __m128i t1 = _mm_and_si128(_mm_castps_si128(V), g_XMInfinity); + t0 = _mm_cmpeq_epi32(t0, g_XMZero); + t1 = _mm_cmpeq_epi32(t1, g_XMInfinity); + __m128i isNaN = _mm_andnot_si128(t0, t1); + + select0 = _mm_and_si128(isInfinite, g_XMInfinity); + select1 = _mm_andnot_si128(isInfinite, _mm_castps_si128(log2)); + __m128i result = _mm_or_si128(select0, select1); + + select0 = _mm_and_si128(isZero, g_XMNegInfinity); + select1 = _mm_andnot_si128(isZero, g_XMNegQNaN); + tmp = _mm_or_si128(select0, select1); + + select0 = _mm_and_si128(isPositive, result); + select1 = _mm_andnot_si128(isPositive, tmp); + result = _mm_or_si128(select0, select1); + + select0 = _mm_and_si128(isNaN, g_XMQNaN); + select1 = _mm_andnot_si128(isNaN, result); + result = _mm_or_si128(select0, select1); + + return _mm_castsi128_ps(result); +#endif +} + +//------------------------------------------------------------------------------ + inline XMVECTOR XM_CALLCONV XMVectorLogE(FXMVECTOR V) noexcept { #if defined(_XM_NO_INTRINSICS_) @@ -3844,27 +3945,27 @@ inline XMVECTOR XM_CALLCONV XMVectorLogE(FXMVECTOR V) noexcept return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - int32x4_t rawBiased = vandq_s32(V, g_XMInfinity); - int32x4_t trailing = vandq_s32(V, g_XMQNaNTest); - int32x4_t isExponentZero = vceqq_s32(g_XMZero, rawBiased); + int32x4_t rawBiased = vandq_s32(vreinterpretq_s32_f32(V), g_XMInfinity); + int32x4_t trailing = vandq_s32(vreinterpretq_s32_f32(V), g_XMQNaNTest); + uint32x4_t isExponentZero = vceqq_s32(g_XMZero, rawBiased); // Compute exponent and significand for normals. - int32x4_t biased = vshrq_n_u32(rawBiased, 23); + int32x4_t biased = vshrq_n_s32(rawBiased, 23); int32x4_t exponentNor = vsubq_s32(biased, g_XMExponentBias); int32x4_t trailingNor = trailing; // Compute exponent and significand for subnormals. - int32x4_t leading = Internal::GetLeadingBit(trailing); + int32x4_t leading = MathInternal::GetLeadingBit(trailing); int32x4_t shift = vsubq_s32(g_XMNumTrailing, leading); int32x4_t exponentSub = vsubq_s32(g_XMSubnormalExponent, shift); - int32x4_t trailingSub = vshlq_u32(trailing, shift); + int32x4_t trailingSub = vshlq_s32(trailing, shift); trailingSub = vandq_s32(trailingSub, g_XMQNaNTest); - int32x4_t e = vbslq_f32(isExponentZero, exponentSub, exponentNor); - int32x4_t t = vbslq_f32(isExponentZero, trailingSub, trailingNor); + int32x4_t e = vbslq_s32(isExponentZero, exponentSub, exponentNor); + int32x4_t t = vbslq_s32(isExponentZero, trailingSub, trailingNor); // Compute the approximation. int32x4_t tmp = vorrq_s32(g_XMOne, t); - float32x4_t y = vsubq_f32(tmp, g_XMOne); + float32x4_t y = vsubq_f32(vreinterpretq_f32_s32(tmp), g_XMOne); float32x4_t log2 = vmlaq_f32(g_XMLogEst6, g_XMLogEst7, y); log2 = vmlaq_f32(g_XMLogEst5, log2, y); @@ -3885,27 +3986,30 @@ inline XMVECTOR XM_CALLCONV XMVectorLogE(FXMVECTOR V) noexcept // if (V is zero) -> -inf // else -> -QNaN - int32x4_t isInfinite = vandq_s32((V), g_XMAbsMask); - isInfinite = vceqq_s32(isInfinite, g_XMInfinity); + uint32x4_t isInfinite = vandq_u32(vreinterpretq_u32_f32(V), g_XMAbsMask); + isInfinite = vceqq_u32(isInfinite, g_XMInfinity); - int32x4_t isGreaterZero = vcgtq_s32((V), g_XMZero); - int32x4_t isNotFinite = vcgtq_s32((V), g_XMInfinity); - int32x4_t isPositive = vbicq_s32(isGreaterZero, isNotFinite); + uint32x4_t isGreaterZero = vcgtq_s32(vreinterpretq_s32_f32(V), g_XMZero); + uint32x4_t isNotFinite = vcgtq_s32(vreinterpretq_s32_f32(V), g_XMInfinity); + uint32x4_t isPositive = vbicq_u32(isGreaterZero, isNotFinite); - int32x4_t isZero = vandq_s32((V), g_XMAbsMask); - isZero = vceqq_s32(isZero, g_XMZero); + uint32x4_t isZero = vandq_u32(vreinterpretq_u32_f32(V), g_XMAbsMask); + isZero = vceqq_u32(isZero, g_XMZero); - int32x4_t t0 = vandq_s32((V), g_XMQNaNTest); - int32x4_t t1 = vandq_s32((V), g_XMInfinity); - t0 = vceqq_s32(t0, g_XMZero); - t1 = vceqq_s32(t1, g_XMInfinity); - int32x4_t isNaN = vbicq_s32(t1, t0); + uint32x4_t t0 = vandq_u32(vreinterpretq_u32_f32(V), g_XMQNaNTest); + uint32x4_t t1 = vandq_u32(vreinterpretq_u32_f32(V), g_XMInfinity); + t0 = vceqq_u32(t0, g_XMZero); + t1 = vceqq_u32(t1, g_XMInfinity); + uint32x4_t isNaN = vbicq_u32(t1, t0); float32x4_t result = vbslq_f32(isInfinite, g_XMInfinity, log2); - tmp = vbslq_f32(isZero, g_XMNegInfinity, g_XMNegQNaN); - result = vbslq_f32(isPositive, result, tmp); + float32x4_t tmp2 = vbslq_f32(isZero, g_XMNegInfinity, g_XMNegQNaN); + result = vbslq_f32(isPositive, result, tmp2); result = vbslq_f32(isNaN, g_XMQNaN, result); return result; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_log_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) __m128i rawBiased = _mm_and_si128(_mm_castps_si128(V), g_XMInfinity); __m128i trailing = _mm_and_si128(_mm_castps_si128(V), g_XMQNaNTest); @@ -3917,10 +4021,10 @@ inline XMVECTOR XM_CALLCONV XMVectorLogE(FXMVECTOR V) noexcept __m128i trailingNor = trailing; // Compute exponent and significand for subnormals. - __m128i leading = Internal::GetLeadingBit(trailing); + __m128i leading = MathInternal::GetLeadingBit(trailing); __m128i shift = _mm_sub_epi32(g_XMNumTrailing, leading); __m128i exponentSub = _mm_sub_epi32(g_XMSubnormalExponent, shift); - __m128i trailingSub = Internal::multi_sll_epi32(trailing, shift); + __m128i trailingSub = MathInternal::multi_sll_epi32(trailing, shift); trailingSub = _mm_and_si128(trailingSub, g_XMQNaNTest); __m128i select0 = _mm_and_si128(isExponentZero, exponentSub); @@ -4023,6 +4127,9 @@ inline XMVECTOR XM_CALLCONV XMVectorPow powf(vgetq_lane_f32(V1, 3), vgetq_lane_f32(V2, 3)) } } }; return vResult.v; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_pow_ps(V1, V2); + return Result; #elif defined(_XM_SSE_INTRINSICS_) XM_ALIGNED_DATA(16) float a[4]; XM_ALIGNED_DATA(16) float b[4]; @@ -4136,10 +4243,10 @@ inline XMVECTOR XM_CALLCONV XMVectorSin(FXMVECTOR V) noexcept XMVECTOR x = XMVectorModAngles(V); // Map in [-pi/2,pi/2] with sin(y) = sin(x). - uint32x4_t sign = vandq_u32(x, g_XMNegativeZero); + uint32x4_t sign = vandq_u32(vreinterpretq_u32_f32(x), g_XMNegativeZero); uint32x4_t c = vorrq_u32(g_XMPi, sign); // pi when x >= 0, -pi when x < 0 float32x4_t absx = vabsq_f32(x); - float32x4_t rflx = vsubq_f32(c, x); + float32x4_t rflx = vsubq_f32(vreinterpretq_f32_u32(c), x); uint32x4_t comp = vcleq_f32(absx, g_XMHalfPi); x = vbslq_f32(comp, x, rflx); @@ -4163,6 +4270,9 @@ inline XMVECTOR XM_CALLCONV XMVectorSin(FXMVECTOR V) noexcept Result = vmlaq_f32(g_XMOne, Result, x2); Result = vmulq_f32(Result, x); return Result; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_sin_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) // Force the value within the bounds of pi XMVECTOR x = XMVectorModAngles(V); @@ -4220,13 +4330,13 @@ inline XMVECTOR XM_CALLCONV XMVectorCos(FXMVECTOR V) noexcept XMVECTOR x = XMVectorModAngles(V); // Map in [-pi/2,pi/2] with cos(y) = sign*cos(x). - uint32x4_t sign = vandq_u32(x, g_XMNegativeZero); + uint32x4_t sign = vandq_u32(vreinterpretq_u32_f32(x), g_XMNegativeZero); uint32x4_t c = vorrq_u32(g_XMPi, sign); // pi when x >= 0, -pi when x < 0 float32x4_t absx = vabsq_f32(x); - float32x4_t rflx = vsubq_f32(c, x); + float32x4_t rflx = vsubq_f32(vreinterpretq_f32_u32(c), x); uint32x4_t comp = vcleq_f32(absx, g_XMHalfPi); x = vbslq_f32(comp, x, rflx); - sign = vbslq_f32(comp, g_XMOne, g_XMNegativeOne); + float32x4_t fsign = vbslq_f32(comp, g_XMOne, g_XMNegativeOne); float32x4_t x2 = vmulq_f32(x, x); @@ -4246,7 +4356,10 @@ inline XMVECTOR XM_CALLCONV XMVectorCos(FXMVECTOR V) noexcept Result = vmlaq_f32(vConstants, Result, x2); Result = vmlaq_f32(g_XMOne, Result, x2); - Result = vmulq_f32(Result, sign); + Result = vmulq_f32(Result, fsign); + return Result; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_cos_ps(V); return Result; #elif defined(_XM_SSE_INTRINSICS_) // Map V to x in [-pi,pi]. @@ -4326,13 +4439,13 @@ inline void XM_CALLCONV XMVectorSinCos XMVECTOR x = XMVectorModAngles(V); // Map in [-pi/2,pi/2] with cos(y) = sign*cos(x). - uint32x4_t sign = vandq_u32(x, g_XMNegativeZero); + uint32x4_t sign = vandq_u32(vreinterpretq_u32_f32(x), g_XMNegativeZero); uint32x4_t c = vorrq_u32(g_XMPi, sign); // pi when x >= 0, -pi when x < 0 float32x4_t absx = vabsq_f32(x); - float32x4_t rflx = vsubq_f32(c, x); + float32x4_t rflx = vsubq_f32(vreinterpretq_f32_u32(c), x); uint32x4_t comp = vcleq_f32(absx, g_XMHalfPi); x = vbslq_f32(comp, x, rflx); - sign = vbslq_f32(comp, g_XMOne, g_XMNegativeOne); + float32x4_t fsign = vbslq_f32(comp, g_XMOne, g_XMNegativeOne); float32x4_t x2 = vmulq_f32(x, x); @@ -4370,7 +4483,9 @@ inline void XM_CALLCONV XMVectorSinCos Result = vmlaq_f32(vConstants, Result, x2); Result = vmlaq_f32(g_XMOne, Result, x2); - *pCos = vmulq_f32(Result, sign); + *pCos = vmulq_f32(Result, fsign); +#elif defined(_XM_SVML_INTRINSICS_) + *pSin = _mm_sincos_ps(pCos, V); #elif defined(_XM_SSE_INTRINSICS_) // Force the value within the bounds of pi XMVECTOR x = XMVectorModAngles(V); @@ -4446,6 +4561,9 @@ inline XMVECTOR XM_CALLCONV XMVectorTan(FXMVECTOR V) noexcept tanf(V.vector4_f32[3]) } } }; return Result.v; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_tan_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) || defined(_XM_ARM_NEON_INTRINSICS_) static const XMVECTORF32 TanCoefficients0 = { { { 1.0f, -4.667168334e-1f, 2.566383229e-2f, -3.118153191e-4f } } }; @@ -4472,7 +4590,7 @@ inline XMVECTOR XM_CALLCONV XMVectorTan(FXMVECTOR V) noexcept VC = XMVectorNegativeMultiplySubtract(VA, C1, VC); #if defined(_XM_ARM_NEON_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) - VB = vcvtq_u32_f32(VB); + VB = vreinterpretq_f32_u32(vcvtq_u32_f32(VB)); #elif defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_) reinterpret_cast<__m128i*>(&VB)[0] = _mm_cvttps_epi32(VB); #else @@ -4545,6 +4663,9 @@ inline XMVECTOR XM_CALLCONV XMVectorSinH(FXMVECTOR V) noexcept XMVECTOR E2 = XMVectorExp(V2); return vsubq_f32(E1, E2); +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_sinh_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) static const XMVECTORF32 Scale = { { { 1.442695040888963f, 1.442695040888963f, 1.442695040888963f, 1.442695040888963f } } }; // 1.0f / ln(2.0f) @@ -4577,6 +4698,9 @@ inline XMVECTOR XM_CALLCONV XMVectorCosH(FXMVECTOR V) noexcept XMVECTOR E1 = XMVectorExp(V1); XMVECTOR E2 = XMVectorExp(V2); return vaddq_f32(E1, E2); +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_cosh_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) static const XMVECTORF32 Scale = { { { 1.442695040888963f, 1.442695040888963f, 1.442695040888963f, 1.442695040888963f } } }; // 1.0f / ln(2.0f) @@ -4608,6 +4732,9 @@ inline XMVECTOR XM_CALLCONV XMVectorTanH(FXMVECTOR V) noexcept E = vmlaq_f32(g_XMOneHalf.v, E, g_XMOneHalf.v); E = XMVectorReciprocal(E); return vsubq_f32(g_XMOne.v, E); +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_tanh_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) static const XMVECTORF32 Scale = { { { 2.8853900817779268f, 2.8853900817779268f, 2.8853900817779268f, 2.8853900817779268f } } }; // 2.0f / ln(2.0f) @@ -4671,6 +4798,9 @@ inline XMVECTOR XM_CALLCONV XMVectorASin(FXMVECTOR V) noexcept t0 = vbslq_f32(nonnegative, t0, t1); t0 = vsubq_f32(g_XMHalfPi, t0); return t0; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_asin_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) __m128 nonnegative = _mm_cmpge_ps(V, g_XMZero); __m128 mvalue = _mm_sub_ps(g_XMZero, V); @@ -4767,6 +4897,9 @@ inline XMVECTOR XM_CALLCONV XMVectorACos(FXMVECTOR V) noexcept float32x4_t t1 = vsubq_f32(g_XMPi, t0); t0 = vbslq_f32(nonnegative, t0, t1); return t0; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_acos_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) __m128 nonnegative = _mm_cmpge_ps(V, g_XMZero); __m128 mvalue = _mm_sub_ps(g_XMZero, V); @@ -4829,10 +4962,10 @@ inline XMVECTOR XM_CALLCONV XMVectorATan(FXMVECTOR V) noexcept float32x4_t absV = vabsq_f32(V); float32x4_t invV = XMVectorReciprocal(V); uint32x4_t comp = vcgtq_f32(V, g_XMOne); - uint32x4_t sign = vbslq_f32(comp, g_XMOne, g_XMNegativeOne); + float32x4_t sign = vbslq_f32(comp, g_XMOne, g_XMNegativeOne); comp = vcleq_f32(absV, g_XMOne); sign = vbslq_f32(comp, g_XMZero, sign); - uint32x4_t x = vbslq_f32(comp, V, invV); + float32x4_t x = vbslq_f32(comp, V, invV); float32x4_t x2 = vmulq_f32(x, x); @@ -4869,6 +5002,9 @@ inline XMVECTOR XM_CALLCONV XMVectorATan(FXMVECTOR V) noexcept comp = vceqq_f32(sign, g_XMZero); Result = vbslq_f32(comp, Result, result1); return Result; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_atan_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) __m128 absV = XMVectorAbs(V); __m128 invV = _mm_div_ps(g_XMOne, V); @@ -4941,6 +5077,9 @@ inline XMVECTOR XM_CALLCONV XMVectorATan2 atan2f(Y.vector4_f32[3], X.vector4_f32[3]) } } }; return Result.v; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_atan2_ps(Y, X); + return Result; #else // Return the inverse tangent of Y / X in the range of -Pi to Pi with the following exceptions: @@ -5017,10 +5156,10 @@ inline XMVECTOR XM_CALLCONV XMVectorSinEst(FXMVECTOR V) noexcept XMVECTOR x = XMVectorModAngles(V); // Map in [-pi/2,pi/2] with sin(y) = sin(x). - uint32x4_t sign = vandq_u32(x, g_XMNegativeZero); + uint32x4_t sign = vandq_u32(vreinterpretq_u32_f32(x), g_XMNegativeZero); uint32x4_t c = vorrq_u32(g_XMPi, sign); // pi when x >= 0, -pi when x < 0 float32x4_t absx = vabsq_f32(x); - float32x4_t rflx = vsubq_f32(c, x); + float32x4_t rflx = vsubq_f32(vreinterpretq_f32_u32(c), x); uint32x4_t comp = vcleq_f32(absx, g_XMHalfPi); x = vbslq_f32(comp, x, rflx); @@ -5037,6 +5176,9 @@ inline XMVECTOR XM_CALLCONV XMVectorSinEst(FXMVECTOR V) noexcept Result = vmlaq_f32(g_XMOne, Result, x2); Result = vmulq_f32(Result, x); return Result; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_sin_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) // Force the value within the bounds of pi XMVECTOR x = XMVectorModAngles(V); @@ -5086,13 +5228,13 @@ inline XMVECTOR XM_CALLCONV XMVectorCosEst(FXMVECTOR V) noexcept XMVECTOR x = XMVectorModAngles(V); // Map in [-pi/2,pi/2] with cos(y) = sign*cos(x). - uint32x4_t sign = vandq_u32(x, g_XMNegativeZero); + uint32x4_t sign = vandq_u32(vreinterpretq_u32_f32(x), g_XMNegativeZero); uint32x4_t c = vorrq_u32(g_XMPi, sign); // pi when x >= 0, -pi when x < 0 float32x4_t absx = vabsq_f32(x); - float32x4_t rflx = vsubq_f32(c, x); + float32x4_t rflx = vsubq_f32(vreinterpretq_f32_u32(c), x); uint32x4_t comp = vcleq_f32(absx, g_XMHalfPi); x = vbslq_f32(comp, x, rflx); - sign = vbslq_f32(comp, g_XMOne, g_XMNegativeOne); + float32x4_t fsign = vbslq_f32(comp, g_XMOne, g_XMNegativeOne); float32x4_t x2 = vmulq_f32(x, x); @@ -5105,7 +5247,10 @@ inline XMVECTOR XM_CALLCONV XMVectorCosEst(FXMVECTOR V) noexcept Result = vmlaq_f32(vConstants, Result, x2); Result = vmlaq_f32(g_XMOne, Result, x2); - Result = vmulq_f32(Result, sign); + Result = vmulq_f32(Result, fsign); + return Result; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_cos_ps(V); return Result; #elif defined(_XM_SSE_INTRINSICS_) // Map V to x in [-pi,pi]. @@ -5177,13 +5322,13 @@ inline void XM_CALLCONV XMVectorSinCosEst XMVECTOR x = XMVectorModAngles(V); // Map in [-pi/2,pi/2] with cos(y) = sign*cos(x). - uint32x4_t sign = vandq_u32(x, g_XMNegativeZero); + uint32x4_t sign = vandq_u32(vreinterpretq_u32_f32(x), g_XMNegativeZero); uint32x4_t c = vorrq_u32(g_XMPi, sign); // pi when x >= 0, -pi when x < 0 float32x4_t absx = vabsq_f32(x); - float32x4_t rflx = vsubq_f32(c, x); + float32x4_t rflx = vsubq_f32(vreinterpretq_f32_u32(c), x); uint32x4_t comp = vcleq_f32(absx, g_XMHalfPi); x = vbslq_f32(comp, x, rflx); - sign = vbslq_f32(comp, g_XMOne, g_XMNegativeOne); + float32x4_t fsign = vbslq_f32(comp, g_XMOne, g_XMNegativeOne); float32x4_t x2 = vmulq_f32(x, x); @@ -5207,7 +5352,7 @@ inline void XM_CALLCONV XMVectorSinCosEst Result = vmlaq_f32(vConstants, Result, x2); Result = vmlaq_f32(g_XMOne, Result, x2); - *pCos = vmulq_f32(Result, sign); + *pCos = vmulq_f32(Result, fsign); #elif defined(_XM_SSE_INTRINSICS_) // Force the value within the bounds of pi XMVECTOR x = XMVectorModAngles(V); @@ -5265,6 +5410,9 @@ inline XMVECTOR XM_CALLCONV XMVectorTanEst(FXMVECTOR V) noexcept tanf(V.vector4_f32[3]) } } }; return Result.v; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_tan_ps(V); + return Result; #else XMVECTOR OneOverPi = XMVectorSplatW(g_XMTanEstCoefficients.v); @@ -5329,6 +5477,9 @@ inline XMVECTOR XM_CALLCONV XMVectorASinEst(FXMVECTOR V) noexcept t0 = vbslq_f32(nonnegative, t0, t1); t0 = vsubq_f32(g_XMHalfPi, t0); return t0; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_asin_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) __m128 nonnegative = _mm_cmpge_ps(V, g_XMZero); __m128 mvalue = _mm_sub_ps(g_XMZero, V); @@ -5399,6 +5550,9 @@ inline XMVECTOR XM_CALLCONV XMVectorACosEst(FXMVECTOR V) noexcept float32x4_t t1 = vsubq_f32(g_XMPi, t0); t0 = vbslq_f32(nonnegative, t0, t1); return t0; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_acos_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) __m128 nonnegative = _mm_cmpge_ps(V, g_XMZero); __m128 mvalue = _mm_sub_ps(g_XMZero, V); @@ -5448,10 +5602,10 @@ inline XMVECTOR XM_CALLCONV XMVectorATanEst(FXMVECTOR V) noexcept float32x4_t absV = vabsq_f32(V); float32x4_t invV = XMVectorReciprocalEst(V); uint32x4_t comp = vcgtq_f32(V, g_XMOne); - uint32x4_t sign = vbslq_f32(comp, g_XMOne, g_XMNegativeOne); + float32x4_t sign = vbslq_f32(comp, g_XMOne, g_XMNegativeOne); comp = vcleq_f32(absV, g_XMOne); sign = vbslq_f32(comp, g_XMZero, sign); - uint32x4_t x = vbslq_f32(comp, V, invV); + float32x4_t x = vbslq_f32(comp, V, invV); float32x4_t x2 = vmulq_f32(x, x); @@ -5476,6 +5630,9 @@ inline XMVECTOR XM_CALLCONV XMVectorATanEst(FXMVECTOR V) noexcept comp = vceqq_f32(sign, g_XMZero); Result = vbslq_f32(comp, Result, result1); return Result; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_atan_ps(V); + return Result; #elif defined(_XM_SSE_INTRINSICS_) __m128 absV = XMVectorAbs(V); __m128 invV = _mm_div_ps(g_XMOne, V); @@ -5534,6 +5691,9 @@ inline XMVECTOR XM_CALLCONV XMVectorATan2Est atan2f(Y.vector4_f32[3], X.vector4_f32[3]), } } }; return Result.v; +#elif defined(_XM_SVML_INTRINSICS_) + XMVECTOR Result = _mm_atan2_ps(Y, X); + return Result; #else static const XMVECTORF32 ATan2Constants = { { { XM_PI, XM_PIDIV2, XM_PIDIV4, 2.3561944905f /* Pi*3/4 */ } } }; @@ -5742,7 +5902,7 @@ inline XMVECTOR XM_CALLCONV XMVectorHermiteV T3 = vmlaq_f32(T2, T3, CatMulT3); // T3 now has the pre-result. // I need to add t.y only - T2 = vandq_u32(T, g_XMMaskY); + T2 = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(T), g_XMMaskY)); T3 = vaddq_f32(T3, T2); // Add 1.0f to x T3 = vaddq_f32(T3, g_XMIdentityR0); @@ -6037,11 +6197,11 @@ inline XMVECTOR XM_CALLCONV XMVectorBaryCentricV * ****************************************************************************/ - //------------------------------------------------------------------------------ - // Comparison operations - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +// Comparison operations +//------------------------------------------------------------------------------ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ inline bool XM_CALLCONV XMVector2Equal ( @@ -6053,7 +6213,7 @@ inline bool XM_CALLCONV XMVector2Equal return (((V1.vector4_f32[0] == V2.vector4_f32[0]) && (V1.vector4_f32[1] == V2.vector4_f32[1])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x2_t vTemp = vceq_f32(vget_low_f32(V1), vget_low_f32(V2)); - return (vget_lane_u64(vTemp, 0) == 0xFFFFFFFFFFFFFFFFU); + return (vget_lane_u64(vreinterpret_u64_u32(vTemp), 0) == 0xFFFFFFFFFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpeq_ps(V1, V2); // z and w are don't care @@ -6087,7 +6247,7 @@ inline uint32_t XM_CALLCONV XMVector2EqualR #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x2_t vTemp = vceq_f32(vget_low_f32(V1), vget_low_f32(V2)); - uint64_t r = vget_lane_u64(vTemp, 0); + uint64_t r = vget_lane_u64(vreinterpret_u64_u32(vTemp), 0); uint32_t CR = 0; if (r == 0xFFFFFFFFFFFFFFFFU) { @@ -6126,8 +6286,8 @@ inline bool XM_CALLCONV XMVector2EqualInt #if defined(_XM_NO_INTRINSICS_) return (((V1.vector4_u32[0] == V2.vector4_u32[0]) && (V1.vector4_u32[1] == V2.vector4_u32[1])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x2_t vTemp = vceq_u32(vget_low_u32(V1), vget_low_u32(V2)); - return (vget_lane_u64(vTemp, 0) == 0xFFFFFFFFFFFFFFFFU); + uint32x2_t vTemp = vceq_u32(vget_low_u32(vreinterpretq_u32_f32(V1)), vget_low_u32(vreinterpretq_u32_f32(V2))); + return (vget_lane_u64(vreinterpret_u64_u32(vTemp), 0) == 0xFFFFFFFFFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) __m128i vTemp = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2)); return (((_mm_movemask_ps(_mm_castsi128_ps(vTemp)) & 3) == 3) != 0); @@ -6158,8 +6318,8 @@ inline uint32_t XM_CALLCONV XMVector2EqualIntR return CR; #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x2_t vTemp = vceq_u32(vget_low_u32(V1), vget_low_u32(V2)); - uint64_t r = vget_lane_u64(vTemp, 0); + uint32x2_t vTemp = vceq_u32(vget_low_u32(vreinterpretq_u32_f32(V1)), vget_low_u32(vreinterpretq_u32_f32(V2))); + uint64_t r = vget_lane_u64(vreinterpret_u64_u32(vTemp), 0); uint32_t CR = 0; if (r == 0xFFFFFFFFFFFFFFFFU) { @@ -6201,13 +6361,13 @@ inline bool XM_CALLCONV XMVector2NearEqual return ((dx <= Epsilon.vector4_f32[0]) && (dy <= Epsilon.vector4_f32[1])); #elif defined(_XM_ARM_NEON_INTRINSICS_) - float32x2_t vDelta = vsub_f32(vget_low_u32(V1), vget_low_u32(V2)); -#ifdef _MSC_VER + float32x2_t vDelta = vsub_f32(vget_low_f32(V1), vget_low_f32(V2)); +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) uint32x2_t vTemp = vacle_f32(vDelta, vget_low_u32(Epsilon)); #else - uint32x2_t vTemp = vcle_f32(vabs_f32(vDelta), vget_low_u32(Epsilon)); + uint32x2_t vTemp = vcle_f32(vabs_f32(vDelta), vget_low_f32(Epsilon)); #endif - uint64_t r = vget_lane_u64(vTemp, 0); + uint64_t r = vget_lane_u64(vreinterpret_u64_u32(vTemp), 0); return (r == 0xFFFFFFFFFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) // Get the difference @@ -6234,7 +6394,7 @@ inline bool XM_CALLCONV XMVector2NotEqual return (((V1.vector4_f32[0] != V2.vector4_f32[0]) || (V1.vector4_f32[1] != V2.vector4_f32[1])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x2_t vTemp = vceq_f32(vget_low_f32(V1), vget_low_f32(V2)); - return (vget_lane_u64(vTemp, 0) != 0xFFFFFFFFFFFFFFFFU); + return (vget_lane_u64(vreinterpret_u64_u32(vTemp), 0) != 0xFFFFFFFFFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpeq_ps(V1, V2); // z and w are don't care @@ -6253,8 +6413,8 @@ inline bool XM_CALLCONV XMVector2NotEqualInt #if defined(_XM_NO_INTRINSICS_) return (((V1.vector4_u32[0] != V2.vector4_u32[0]) || (V1.vector4_u32[1] != V2.vector4_u32[1])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x2_t vTemp = vceq_u32(vget_low_u32(V1), vget_low_u32(V2)); - return (vget_lane_u64(vTemp, 0) != 0xFFFFFFFFFFFFFFFFU); + uint32x2_t vTemp = vceq_u32(vget_low_u32(vreinterpretq_u32_f32(V1)), vget_low_u32(vreinterpretq_u32_f32(V2))); + return (vget_lane_u64(vreinterpret_u64_u32(vTemp), 0) != 0xFFFFFFFFFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) __m128i vTemp = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2)); return (((_mm_movemask_ps(_mm_castsi128_ps(vTemp)) & 3) != 3) != 0); @@ -6273,7 +6433,7 @@ inline bool XM_CALLCONV XMVector2Greater return (((V1.vector4_f32[0] > V2.vector4_f32[0]) && (V1.vector4_f32[1] > V2.vector4_f32[1])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x2_t vTemp = vcgt_f32(vget_low_f32(V1), vget_low_f32(V2)); - return (vget_lane_u64(vTemp, 0) == 0xFFFFFFFFFFFFFFFFU); + return (vget_lane_u64(vreinterpret_u64_u32(vTemp), 0) == 0xFFFFFFFFFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpgt_ps(V1, V2); // z and w are don't care @@ -6306,7 +6466,7 @@ inline uint32_t XM_CALLCONV XMVector2GreaterR #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x2_t vTemp = vcgt_f32(vget_low_f32(V1), vget_low_f32(V2)); - uint64_t r = vget_lane_u64(vTemp, 0); + uint64_t r = vget_lane_u64(vreinterpret_u64_u32(vTemp), 0); uint32_t CR = 0; if (r == 0xFFFFFFFFFFFFFFFFU) { @@ -6345,7 +6505,7 @@ inline bool XM_CALLCONV XMVector2GreaterOrEqual return (((V1.vector4_f32[0] >= V2.vector4_f32[0]) && (V1.vector4_f32[1] >= V2.vector4_f32[1])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x2_t vTemp = vcge_f32(vget_low_f32(V1), vget_low_f32(V2)); - return (vget_lane_u64(vTemp, 0) == 0xFFFFFFFFFFFFFFFFU); + return (vget_lane_u64(vreinterpret_u64_u32(vTemp), 0) == 0xFFFFFFFFFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpge_ps(V1, V2); return (((_mm_movemask_ps(vTemp) & 3) == 3) != 0); @@ -6377,7 +6537,7 @@ inline uint32_t XM_CALLCONV XMVector2GreaterOrEqualR #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x2_t vTemp = vcge_f32(vget_low_f32(V1), vget_low_f32(V2)); - uint64_t r = vget_lane_u64(vTemp, 0); + uint64_t r = vget_lane_u64(vreinterpret_u64_u32(vTemp), 0); uint32_t CR = 0; if (r == 0xFFFFFFFFFFFFFFFFU) { @@ -6416,7 +6576,7 @@ inline bool XM_CALLCONV XMVector2Less return (((V1.vector4_f32[0] < V2.vector4_f32[0]) && (V1.vector4_f32[1] < V2.vector4_f32[1])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x2_t vTemp = vclt_f32(vget_low_f32(V1), vget_low_f32(V2)); - return (vget_lane_u64(vTemp, 0) == 0xFFFFFFFFFFFFFFFFU); + return (vget_lane_u64(vreinterpret_u64_u32(vTemp), 0) == 0xFFFFFFFFFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmplt_ps(V1, V2); return (((_mm_movemask_ps(vTemp) & 3) == 3) != 0); @@ -6435,7 +6595,7 @@ inline bool XM_CALLCONV XMVector2LessOrEqual return (((V1.vector4_f32[0] <= V2.vector4_f32[0]) && (V1.vector4_f32[1] <= V2.vector4_f32[1])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x2_t vTemp = vcle_f32(vget_low_f32(V1), vget_low_f32(V2)); - return (vget_lane_u64(vTemp, 0) == 0xFFFFFFFFFFFFFFFFU); + return (vget_lane_u64(vreinterpret_u64_u32(vTemp), 0) == 0xFFFFFFFFFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmple_ps(V1, V2); return (((_mm_movemask_ps(vTemp) & 3) == 3) != 0); @@ -6465,7 +6625,7 @@ inline bool XM_CALLCONV XMVector2InBounds // Blend answers ivTemp1 = vand_u32(ivTemp1, ivTemp2); // x and y in bounds? - return (vget_lane_u64(ivTemp1, 0) == 0xFFFFFFFFFFFFFFFFU); + return (vget_lane_u64(vreinterpret_u64_u32(ivTemp1), 0) == 0xFFFFFFFFFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) // Test if less than or equal XMVECTOR vTemp1 = _mm_cmple_ps(V, Bounds); @@ -6482,7 +6642,7 @@ inline bool XM_CALLCONV XMVector2InBounds //------------------------------------------------------------------------------ -#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma float_control(push) #pragma float_control(precise, on) #endif @@ -6493,20 +6653,30 @@ inline bool XM_CALLCONV XMVector2IsNaN(FXMVECTOR V) noexcept return (XMISNAN(V.vector4_f32[0]) || XMISNAN(V.vector4_f32[1])); #elif defined(_XM_ARM_NEON_INTRINSICS_) +#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) + return isnan(vgetq_lane_f32(V, 0)) || isnan(vgetq_lane_f32(V, 1)); +#else float32x2_t VL = vget_low_f32(V); // Test against itself. NaN is always not equal uint32x2_t vTempNan = vceq_f32(VL, VL); // If x or y are NaN, the mask is zero - return (vget_lane_u64(vTempNan, 0) != 0xFFFFFFFFFFFFFFFFU); + return (vget_lane_u64(vreinterpret_u64_u32(vTempNan), 0) != 0xFFFFFFFFFFFFFFFFU); +#endif #elif defined(_XM_SSE_INTRINSICS_) - // Test against itself. NaN is always not equal +#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) + XM_ALIGNED_DATA(16) float tmp[4]; + _mm_store_ps(tmp, V); + return isnan(tmp[0]) || isnan(tmp[1]); +#else +// Test against itself. NaN is always not equal XMVECTOR vTempNan = _mm_cmpneq_ps(V, V); // If x or y are NaN, the mask is non-zero return ((_mm_movemask_ps(vTempNan) & 3) != 0); #endif +#endif } -#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma float_control(pop) #endif @@ -6520,11 +6690,11 @@ inline bool XM_CALLCONV XMVector2IsInfinite(FXMVECTOR V) noexcept XMISINF(V.vector4_f32[1])); #elif defined(_XM_ARM_NEON_INTRINSICS_) // Mask off the sign bit - uint32x2_t vTemp = vand_u32(vget_low_f32(V), vget_low_f32(g_XMAbsMask)); + uint32x2_t vTemp = vand_u32(vget_low_u32(vreinterpretq_u32_f32(V)), vget_low_u32(g_XMAbsMask)); // Compare to infinity - vTemp = vceq_f32(vTemp, vget_low_f32(g_XMInfinity)); + vTemp = vceq_f32(vreinterpret_f32_u32(vTemp), vget_low_f32(g_XMInfinity)); // If any are infinity, the signs are true. - return vget_lane_u64(vTemp, 0) != 0; + return vget_lane_u64(vreinterpret_u64_u32(vTemp), 0) != 0; #elif defined(_XM_SSE_INTRINSICS_) // Mask off the sign bit __m128 vTemp = _mm_and_ps(V, g_XMAbsMask); @@ -7135,7 +7305,7 @@ inline XMVECTOR XM_CALLCONV XMVector2RefractV // Result = RefractionIndex * Incident - Normal * R float32x2_t vResult = vmul_f32(RIL, IL); vResult = vmls_f32(vResult, vTemp, NL); - vResult = vand_u32(vResult, vMask); + vResult = vreinterpret_f32_u32(vand_u32(vreinterpret_u32_f32(vResult), vMask)); return vcombine_f32(vResult, vResult); #elif defined(_XM_SSE_INTRINSICS_) // Result = RefractionIndex * Incident - Normal * (RefractionIndex * dot(Incident, Normal) + @@ -7414,16 +7584,16 @@ inline XMFLOAT4* XM_CALLCONV XMVector2TransformStream XMVECTOR Result = XMVectorMultiplyAdd(Y, row1, row3); Result = XMVectorMultiplyAdd(X, row0, Result); -#ifdef _PREFAST_ -#pragma prefast(push) -#pragma prefast(disable : 26015, "PREfast noise: Esp:1307" ) -#endif + #ifdef _PREFAST_ + #pragma prefast(push) + #pragma prefast(disable : 26015, "PREfast noise: Esp:1307" ) + #endif XMStoreFloat4(reinterpret_cast(pOutputVector), Result); -#ifdef _PREFAST_ -#pragma prefast(pop) -#endif + #ifdef _PREFAST_ + #pragma prefast(pop) + #endif pInputVector += InputStride; pOutputVector += OutputStride; @@ -7854,16 +8024,16 @@ inline XMFLOAT2* XM_CALLCONV XMVector2TransformCoordStream Result = XMVectorDivide(Result, W); -#ifdef _PREFAST_ -#pragma prefast(push) -#pragma prefast(disable : 26015, "PREfast noise: Esp:1307" ) -#endif + #ifdef _PREFAST_ + #pragma prefast(push) + #pragma prefast(disable : 26015, "PREfast noise: Esp:1307" ) + #endif XMStoreFloat2(reinterpret_cast(pOutputVector), Result); -#ifdef _PREFAST_ -#pragma prefast(pop) -#endif + #ifdef _PREFAST_ + #pragma prefast(pop) + #endif pInputVector += InputStride; pOutputVector += OutputStride; @@ -7914,11 +8084,11 @@ inline XMFLOAT2* XM_CALLCONV XMVector2TransformCoordStream XM_PREFETCH(pInputVector + (XM_CACHE_LINE_SIZE * 3)); -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ + #if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ V.val[0] = vdivq_f32(vResult0, W); V.val[1] = vdivq_f32(vResult1, W); -#else - // 2 iterations of Newton-Raphson refinement of reciprocal + #else + // 2 iterations of Newton-Raphson refinement of reciprocal float32x4_t Reciprocal = vrecpeq_f32(W); float32x4_t S = vrecpsq_f32(Reciprocal, W); Reciprocal = vmulq_f32(S, Reciprocal); @@ -7927,7 +8097,7 @@ inline XMFLOAT2* XM_CALLCONV XMVector2TransformCoordStream V.val[0] = vmulq_f32(vResult0, Reciprocal); V.val[1] = vmulq_f32(vResult1, Reciprocal); -#endif + #endif vst2q_f32(reinterpret_cast(pOutputVector), V); pOutputVector += sizeof(XMFLOAT2) * 4; @@ -7948,11 +8118,11 @@ inline XMFLOAT2* XM_CALLCONV XMVector2TransformCoordStream V = vget_high_f32(vResult); float32x2_t W = vdup_lane_f32(V, 1); -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ + #if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ V = vget_low_f32(vResult); V = vdiv_f32(V, W); -#else - // 2 iterations of Newton-Raphson refinement of reciprocal for W + #else + // 2 iterations of Newton-Raphson refinement of reciprocal for W float32x2_t Reciprocal = vrecpe_f32(W); float32x2_t S = vrecps_f32(Reciprocal, W); Reciprocal = vmul_f32(S, Reciprocal); @@ -7961,7 +8131,7 @@ inline XMFLOAT2* XM_CALLCONV XMVector2TransformCoordStream V = vget_low_f32(vResult); V = vmul_f32(V, Reciprocal); -#endif + #endif vst1_f32(reinterpret_cast(pOutputVector), V); pOutputVector += OutputStride; @@ -8392,16 +8562,16 @@ inline XMFLOAT2* XM_CALLCONV XMVector2TransformNormalStream XMVECTOR Result = XMVectorMultiply(Y, row1); Result = XMVectorMultiplyAdd(X, row0, Result); -#ifdef _PREFAST_ -#pragma prefast(push) -#pragma prefast(disable : 26015, "PREfast noise: Esp:1307" ) -#endif + #ifdef _PREFAST_ + #pragma prefast(push) + #pragma prefast(disable : 26015, "PREfast noise: Esp:1307" ) + #endif XMStoreFloat2(reinterpret_cast(pOutputVector), Result); -#ifdef _PREFAST_ -#pragma prefast(pop) -#endif + #ifdef _PREFAST_ + #pragma prefast(pop) + #endif pInputVector += InputStride; pOutputVector += OutputStride; @@ -8755,11 +8925,11 @@ inline XMFLOAT2* XM_CALLCONV XMVector2TransformNormalStream * ****************************************************************************/ - //------------------------------------------------------------------------------ - // Comparison operations - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +// Comparison operations +//------------------------------------------------------------------------------ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ inline bool XM_CALLCONV XMVector3Equal ( @@ -8771,9 +8941,9 @@ inline bool XM_CALLCONV XMVector3Equal return (((V1.vector4_f32[0] == V2.vector4_f32[0]) && (V1.vector4_f32[1] == V2.vector4_f32[1]) && (V1.vector4_f32[2] == V2.vector4_f32[2])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vceqq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return ((vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU) == 0xFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return ((vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU) == 0xFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpeq_ps(V1, V2); return (((_mm_movemask_ps(vTemp) & 7) == 7) != 0); @@ -8805,9 +8975,9 @@ inline uint32_t XM_CALLCONV XMVector3EqualR return CR; #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vceqq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU; + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU; uint32_t CR = 0; if (r == 0xFFFFFFU) @@ -8846,10 +9016,10 @@ inline bool XM_CALLCONV XMVector3EqualInt #if defined(_XM_NO_INTRINSICS_) return (((V1.vector4_u32[0] == V2.vector4_u32[0]) && (V1.vector4_u32[1] == V2.vector4_u32[1]) && (V1.vector4_u32[2] == V2.vector4_u32[2])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x4_t vResult = vceqq_u32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return ((vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU) == 0xFFFFFFU); + uint32x4_t vResult = vceqq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2)); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return ((vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU) == 0xFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) __m128i vTemp = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2)); return (((_mm_movemask_ps(_mm_castsi128_ps(vTemp)) & 7) == 7) != 0); @@ -8880,10 +9050,10 @@ inline uint32_t XM_CALLCONV XMVector3EqualIntR } return CR; #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x4_t vResult = vceqq_u32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU; + uint32x4_t vResult = vceqq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2)); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU; uint32_t CR = 0; if (r == 0xFFFFFFU) @@ -8931,14 +9101,14 @@ inline bool XM_CALLCONV XMVector3NearEqual (dz <= Epsilon.vector4_f32[2])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) float32x4_t vDelta = vsubq_f32(V1, V2); -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) uint32x4_t vResult = vacleq_f32(vDelta, Epsilon); #else uint32x4_t vResult = vcleq_f32(vabsq_f32(vDelta), Epsilon); #endif - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return ((vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU) == 0xFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return ((vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU) == 0xFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) // Get the difference XMVECTOR vDelta = _mm_sub_ps(V1, V2); @@ -8964,9 +9134,9 @@ inline bool XM_CALLCONV XMVector3NotEqual return (((V1.vector4_f32[0] != V2.vector4_f32[0]) || (V1.vector4_f32[1] != V2.vector4_f32[1]) || (V1.vector4_f32[2] != V2.vector4_f32[2])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vceqq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return ((vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU) != 0xFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return ((vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU) != 0xFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpeq_ps(V1, V2); return (((_mm_movemask_ps(vTemp) & 7) != 7) != 0); @@ -8984,10 +9154,10 @@ inline bool XM_CALLCONV XMVector3NotEqualInt #if defined(_XM_NO_INTRINSICS_) return (((V1.vector4_u32[0] != V2.vector4_u32[0]) || (V1.vector4_u32[1] != V2.vector4_u32[1]) || (V1.vector4_u32[2] != V2.vector4_u32[2])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x4_t vResult = vceqq_u32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return ((vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU) != 0xFFFFFFU); + uint32x4_t vResult = vceqq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2)); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return ((vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU) != 0xFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) __m128i vTemp = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2)); return (((_mm_movemask_ps(_mm_castsi128_ps(vTemp)) & 7) != 7) != 0); @@ -9006,9 +9176,9 @@ inline bool XM_CALLCONV XMVector3Greater return (((V1.vector4_f32[0] > V2.vector4_f32[0]) && (V1.vector4_f32[1] > V2.vector4_f32[1]) && (V1.vector4_f32[2] > V2.vector4_f32[2])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcgtq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return ((vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU) == 0xFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return ((vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU) == 0xFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpgt_ps(V1, V2); return (((_mm_movemask_ps(vTemp) & 7) == 7) != 0); @@ -9041,9 +9211,9 @@ inline uint32_t XM_CALLCONV XMVector3GreaterR #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcgtq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU; + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU; uint32_t CR = 0; if (r == 0xFFFFFFU) @@ -9083,9 +9253,9 @@ inline bool XM_CALLCONV XMVector3GreaterOrEqual return (((V1.vector4_f32[0] >= V2.vector4_f32[0]) && (V1.vector4_f32[1] >= V2.vector4_f32[1]) && (V1.vector4_f32[2] >= V2.vector4_f32[2])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcgeq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return ((vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU) == 0xFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return ((vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU) == 0xFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpge_ps(V1, V2); return (((_mm_movemask_ps(vTemp) & 7) == 7) != 0); @@ -9119,9 +9289,9 @@ inline uint32_t XM_CALLCONV XMVector3GreaterOrEqualR #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcgeq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU; + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU; uint32_t CR = 0; if (r == 0xFFFFFFU) @@ -9161,9 +9331,9 @@ inline bool XM_CALLCONV XMVector3Less return (((V1.vector4_f32[0] < V2.vector4_f32[0]) && (V1.vector4_f32[1] < V2.vector4_f32[1]) && (V1.vector4_f32[2] < V2.vector4_f32[2])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcltq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return ((vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU) == 0xFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return ((vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU) == 0xFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmplt_ps(V1, V2); return (((_mm_movemask_ps(vTemp) & 7) == 7) != 0); @@ -9182,9 +9352,9 @@ inline bool XM_CALLCONV XMVector3LessOrEqual return (((V1.vector4_f32[0] <= V2.vector4_f32[0]) && (V1.vector4_f32[1] <= V2.vector4_f32[1]) && (V1.vector4_f32[2] <= V2.vector4_f32[2])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcleq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return ((vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU) == 0xFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return ((vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU) == 0xFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmple_ps(V1, V2); return (((_mm_movemask_ps(vTemp) & 7) == 7) != 0); @@ -9213,9 +9383,9 @@ inline bool XM_CALLCONV XMVector3InBounds // Blend answers ivTemp1 = vandq_u32(ivTemp1, ivTemp2); // in bounds? - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(ivTemp1), vget_high_u8(ivTemp1)); - uint16x4x2_t vTemp3 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return ((vget_lane_u32(vTemp3.val[1], 1) & 0xFFFFFFU) == 0xFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(ivTemp1)), vget_high_u8(vreinterpretq_u8_u32(ivTemp1))); + uint16x4x2_t vTemp3 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return ((vget_lane_u32(vreinterpret_u32_u16(vTemp3.val[1]), 1) & 0xFFFFFFU) == 0xFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) // Test if less than or equal XMVECTOR vTemp1 = _mm_cmple_ps(V, Bounds); @@ -9234,7 +9404,7 @@ inline bool XM_CALLCONV XMVector3InBounds //------------------------------------------------------------------------------ -#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma float_control(push) #pragma float_control(precise, on) #endif @@ -9248,21 +9418,31 @@ inline bool XM_CALLCONV XMVector3IsNaN(FXMVECTOR V) noexcept XMISNAN(V.vector4_f32[2])); #elif defined(_XM_ARM_NEON_INTRINSICS_) - // Test against itself. NaN is always not equal +#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) + return isnan(vgetq_lane_f32(V, 0)) || isnan(vgetq_lane_f32(V, 1)) || isnan(vgetq_lane_f32(V, 2)); +#else +// Test against itself. NaN is always not equal uint32x4_t vTempNan = vceqq_f32(V, V); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vTempNan), vget_high_u8(vTempNan)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vTempNan)), vget_high_u8(vreinterpretq_u8_u32(vTempNan))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); // If x or y or z are NaN, the mask is zero - return ((vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU) != 0xFFFFFFU); + return ((vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU) != 0xFFFFFFU); +#endif #elif defined(_XM_SSE_INTRINSICS_) - // Test against itself. NaN is always not equal +#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) + XM_ALIGNED_DATA(16) float tmp[4]; + _mm_store_ps(tmp, V); + return isnan(tmp[0]) || isnan(tmp[1]) || isnan(tmp[2]); +#else +// Test against itself. NaN is always not equal XMVECTOR vTempNan = _mm_cmpneq_ps(V, V); // If x or y or z are NaN, the mask is non-zero return ((_mm_movemask_ps(vTempNan) & 7) != 0); #endif +#endif } -#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma float_control(pop) #endif @@ -9276,13 +9456,13 @@ inline bool XM_CALLCONV XMVector3IsInfinite(FXMVECTOR V) noexcept XMISINF(V.vector4_f32[2])); #elif defined(_XM_ARM_NEON_INTRINSICS_) // Mask off the sign bit - uint32x4_t vTempInf = vandq_u32(V, g_XMAbsMask); + uint32x4_t vTempInf = vandq_u32(vreinterpretq_u32_f32(V), g_XMAbsMask); // Compare to infinity - vTempInf = vceqq_f32(vTempInf, g_XMInfinity); + vTempInf = vceqq_f32(vreinterpretq_f32_u32(vTempInf), g_XMInfinity); // If any are infinity, the signs are true. - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vTempInf), vget_high_u8(vTempInf)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return ((vget_lane_u32(vTemp2.val[1], 1) & 0xFFFFFFU) != 0); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vTempInf)), vget_high_u8(vreinterpretq_u8_u32(vTempInf))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return ((vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) & 0xFFFFFFU) != 0); #elif defined(_XM_SSE_INTRINSICS_) // Mask off the sign bit __m128 vTemp = _mm_and_ps(V, g_XMAbsMask); @@ -9374,8 +9554,8 @@ inline XMVECTOR XM_CALLCONV XMVector3Cross XMVECTOR vResult = vmulq_f32(vcombine_f32(v1yx, v1xy), vcombine_f32(v2zz, v2yx)); vResult = vmlsq_f32(vResult, vcombine_f32(v1zz, v1yx), vcombine_f32(v2yx, v2xy)); - vResult = veorq_u32(vResult, g_XMFlipY); - return vandq_u32(vResult, g_XMMask3); + vResult = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(vResult), g_XMFlipY)); + return vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(vResult), g_XMMask3)); #elif defined(_XM_SSE_INTRINSICS_) // y1,z1,x1,w1 XMVECTOR vTemp1 = XM_PERMUTE_PS(V1, _MM_SHUFFLE(3, 0, 2, 1)); @@ -9738,8 +9918,8 @@ inline XMVECTOR XM_CALLCONV XMVector3Normalize(FXMVECTOR V) noexcept v2 = vmul_f32(S1, R1); // Normalize XMVECTOR vResult = vmulq_f32(V, vcombine_f32(v2, v2)); - vResult = vbslq_f32(vcombine_f32(VEqualsZero, VEqualsZero), vdupq_n_f32(0), vResult); - return vbslq_f32(vcombine_f32(VEqualsInf, VEqualsInf), g_XMQNaN, vResult); + vResult = vbslq_f32(vcombine_u32(VEqualsZero, VEqualsZero), vdupq_n_f32(0), vResult); + return vbslq_f32(vcombine_u32(VEqualsInf, VEqualsInf), g_XMQNaN, vResult); #elif defined(_XM_SSE4_INTRINSICS_) XMVECTOR vLengthSq = _mm_dp_ps(V, V, 0x7f); // Prepare for the division @@ -9954,10 +10134,12 @@ inline XMVECTOR XM_CALLCONV XMVector3RefractV R = vmulq_f32(R, RefractionIndex); R = vmlsq_f32(g_XMOne, R, RefractionIndex); - uint32x4_t vResult = vcleq_f32(R, g_XMZero); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - if (vget_lane_u32(vTemp2.val[1], 1) == 0xFFFFFFFFU) + uint32x4_t isrzero = vcleq_f32(R, g_XMZero); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(isrzero)), vget_high_u8(vreinterpretq_u8_u32(isrzero))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + + float32x4_t vResult; + if (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) == 0xFFFFFFFFU) { // Total internal reflection vResult = g_XMZero; @@ -10690,12 +10872,12 @@ inline XMFLOAT3* XM_CALLCONV XMVector3TransformCoordStream XM_PREFETCH(pInputVector + (XM_CACHE_LINE_SIZE * 5)); -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ + #if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ V.val[0] = vdivq_f32(vResult0, W); V.val[1] = vdivq_f32(vResult1, W); V.val[2] = vdivq_f32(vResult2, W); -#else - // 2 iterations of Newton-Raphson refinement of reciprocal + #else + // 2 iterations of Newton-Raphson refinement of reciprocal float32x4_t Reciprocal = vrecpeq_f32(W); float32x4_t S = vrecpsq_f32(Reciprocal, W); Reciprocal = vmulq_f32(S, Reciprocal); @@ -10705,7 +10887,7 @@ inline XMFLOAT3* XM_CALLCONV XMVector3TransformCoordStream V.val[0] = vmulq_f32(vResult0, Reciprocal); V.val[1] = vmulq_f32(vResult1, Reciprocal); V.val[2] = vmulq_f32(vResult2, Reciprocal); -#endif + #endif vst3q_f32(reinterpret_cast(pOutputVector), V); pOutputVector += sizeof(XMFLOAT3) * 4; @@ -10729,10 +10911,10 @@ inline XMFLOAT3* XM_CALLCONV XMVector3TransformCoordStream VH = vget_high_f32(vResult); XMVECTOR W = vdupq_lane_f32(VH, 1); -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ + #if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ vResult = vdivq_f32(vResult, W); -#else - // 2 iterations of Newton-Raphson refinement of reciprocal for W + #else + // 2 iterations of Newton-Raphson refinement of reciprocal for W float32x4_t Reciprocal = vrecpeq_f32(W); float32x4_t S = vrecpsq_f32(Reciprocal, W); Reciprocal = vmulq_f32(S, Reciprocal); @@ -10740,7 +10922,7 @@ inline XMFLOAT3* XM_CALLCONV XMVector3TransformCoordStream Reciprocal = vmulq_f32(S, Reciprocal); vResult = vmulq_f32(vResult, Reciprocal); -#endif + #endif VL = vget_low_f32(vResult); vst1_f32(reinterpret_cast(pOutputVector), VL); @@ -11640,12 +11822,12 @@ inline XMFLOAT3* XM_CALLCONV XMVector3ProjectStream XM_PREFETCH(pInputVector + (XM_CACHE_LINE_SIZE * 5)); -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ + #if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ vResult0 = vdivq_f32(vResult0, W); vResult1 = vdivq_f32(vResult1, W); vResult2 = vdivq_f32(vResult2, W); -#else - // 2 iterations of Newton-Raphson refinement of reciprocal + #else + // 2 iterations of Newton-Raphson refinement of reciprocal float32x4_t Reciprocal = vrecpeq_f32(W); float32x4_t S = vrecpsq_f32(Reciprocal, W); Reciprocal = vmulq_f32(S, Reciprocal); @@ -11655,7 +11837,7 @@ inline XMFLOAT3* XM_CALLCONV XMVector3ProjectStream vResult0 = vmulq_f32(vResult0, Reciprocal); vResult1 = vmulq_f32(vResult1, Reciprocal); vResult2 = vmulq_f32(vResult2, Reciprocal); -#endif + #endif V.val[0] = vmlaq_f32(OffsetX, vResult0, ScaleX); V.val[1] = vmlaq_f32(OffsetY, vResult1, ScaleY); @@ -11688,10 +11870,10 @@ inline XMFLOAT3* XM_CALLCONV XMVector3ProjectStream VH = vget_high_f32(vResult); XMVECTOR W = vdupq_lane_f32(VH, 1); -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ + #if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ vResult = vdivq_f32(vResult, W); -#else - // 2 iterations of Newton-Raphson refinement of reciprocal for W + #else + // 2 iterations of Newton-Raphson refinement of reciprocal for W float32x4_t Reciprocal = vrecpeq_f32(W); float32x4_t S = vrecpsq_f32(Reciprocal, W); Reciprocal = vmulq_f32(S, Reciprocal); @@ -11699,7 +11881,7 @@ inline XMFLOAT3* XM_CALLCONV XMVector3ProjectStream Reciprocal = vmulq_f32(S, Reciprocal); vResult = vmulq_f32(vResult, Reciprocal); -#endif + #endif vResult = vmlaq_f32(Offset, vResult, Scale); @@ -12199,12 +12381,12 @@ inline XMFLOAT3* XM_CALLCONV XMVector3UnprojectStream XM_PREFETCH(pInputVector + (XM_CACHE_LINE_SIZE * 5)); -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ + #if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ V.val[0] = vdivq_f32(vResult0, W); V.val[1] = vdivq_f32(vResult1, W); V.val[2] = vdivq_f32(vResult2, W); -#else - // 2 iterations of Newton-Raphson refinement of reciprocal + #else + // 2 iterations of Newton-Raphson refinement of reciprocal float32x4_t Reciprocal = vrecpeq_f32(W); float32x4_t S = vrecpsq_f32(Reciprocal, W); Reciprocal = vmulq_f32(S, Reciprocal); @@ -12214,7 +12396,7 @@ inline XMFLOAT3* XM_CALLCONV XMVector3UnprojectStream V.val[0] = vmulq_f32(vResult0, Reciprocal); V.val[1] = vmulq_f32(vResult1, Reciprocal); V.val[2] = vmulq_f32(vResult2, Reciprocal); -#endif + #endif vst3q_f32(reinterpret_cast(pOutputVector), V); pOutputVector += sizeof(XMFLOAT3) * 4; @@ -12253,10 +12435,10 @@ inline XMFLOAT3* XM_CALLCONV XMVector3UnprojectStream VH = vget_high_f32(vResult); XMVECTOR W = vdupq_lane_f32(VH, 1); -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || __aarch64__ + #if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __aarch64__ vResult = vdivq_f32(vResult, W); -#else - // 2 iterations of Newton-Raphson refinement of reciprocal for W + #else + // 2 iterations of Newton-Raphson refinement of reciprocal for W float32x4_t Reciprocal = vrecpeq_f32(W); float32x4_t S = vrecpsq_f32(Reciprocal, W); Reciprocal = vmulq_f32(S, Reciprocal); @@ -12264,7 +12446,7 @@ inline XMFLOAT3* XM_CALLCONV XMVector3UnprojectStream Reciprocal = vmulq_f32(S, Reciprocal); vResult = vmulq_f32(vResult, Reciprocal); -#endif + #endif VL = vget_low_f32(vResult); vst1_f32(reinterpret_cast(pOutputVector), VL); @@ -12608,11 +12790,11 @@ inline XMFLOAT3* XM_CALLCONV XMVector3UnprojectStream * ****************************************************************************/ - //------------------------------------------------------------------------------ - // Comparison operations - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +// Comparison operations +//------------------------------------------------------------------------------ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ inline bool XM_CALLCONV XMVector4Equal ( @@ -12624,9 +12806,9 @@ inline bool XM_CALLCONV XMVector4Equal return (((V1.vector4_f32[0] == V2.vector4_f32[0]) && (V1.vector4_f32[1] == V2.vector4_f32[1]) && (V1.vector4_f32[2] == V2.vector4_f32[2]) && (V1.vector4_f32[3] == V2.vector4_f32[3])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vceqq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return (vget_lane_u32(vTemp2.val[1], 1) == 0xFFFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) == 0xFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpeq_ps(V1, V2); return ((_mm_movemask_ps(vTemp) == 0x0f) != 0); @@ -12665,9 +12847,9 @@ inline uint32_t XM_CALLCONV XMVector4EqualR #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vceqq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1); uint32_t CR = 0; if (r == 0xFFFFFFFFU) @@ -12706,10 +12888,10 @@ inline bool XM_CALLCONV XMVector4EqualInt #if defined(_XM_NO_INTRINSICS_) return (((V1.vector4_u32[0] == V2.vector4_u32[0]) && (V1.vector4_u32[1] == V2.vector4_u32[1]) && (V1.vector4_u32[2] == V2.vector4_u32[2]) && (V1.vector4_u32[3] == V2.vector4_u32[3])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x4_t vResult = vceqq_u32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return (vget_lane_u32(vTemp2.val[1], 1) == 0xFFFFFFFFU); + uint32x4_t vResult = vceqq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2)); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) == 0xFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) __m128i vTemp = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2)); return ((_mm_movemask_ps(_mm_castsi128_ps(vTemp)) == 0xf) != 0); @@ -12745,10 +12927,10 @@ inline uint32_t XM_CALLCONV XMVector4EqualIntR return CR; #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x4_t vResult = vceqq_u32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1); + uint32x4_t vResult = vceqq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2)); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1); uint32_t CR = 0; if (r == 0xFFFFFFFFU) @@ -12796,14 +12978,14 @@ inline bool XM_CALLCONV XMVector4NearEqual (dw <= Epsilon.vector4_f32[3])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) float32x4_t vDelta = vsubq_f32(V1, V2); -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) && !defined(_ARM64_DISTINCT_NEON_TYPES) uint32x4_t vResult = vacleq_f32(vDelta, Epsilon); #else uint32x4_t vResult = vcleq_f32(vabsq_f32(vDelta), Epsilon); #endif - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return (vget_lane_u32(vTemp2.val[1], 1) == 0xFFFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) == 0xFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) // Get the difference XMVECTOR vDelta = _mm_sub_ps(V1, V2); @@ -12828,9 +13010,9 @@ inline bool XM_CALLCONV XMVector4NotEqual return (((V1.vector4_f32[0] != V2.vector4_f32[0]) || (V1.vector4_f32[1] != V2.vector4_f32[1]) || (V1.vector4_f32[2] != V2.vector4_f32[2]) || (V1.vector4_f32[3] != V2.vector4_f32[3])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vceqq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return (vget_lane_u32(vTemp2.val[1], 1) != 0xFFFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) != 0xFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpneq_ps(V1, V2); return ((_mm_movemask_ps(vTemp)) != 0); @@ -12850,10 +13032,10 @@ inline bool XM_CALLCONV XMVector4NotEqualInt #if defined(_XM_NO_INTRINSICS_) return (((V1.vector4_u32[0] != V2.vector4_u32[0]) || (V1.vector4_u32[1] != V2.vector4_u32[1]) || (V1.vector4_u32[2] != V2.vector4_u32[2]) || (V1.vector4_u32[3] != V2.vector4_u32[3])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) - uint32x4_t vResult = vceqq_u32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return (vget_lane_u32(vTemp2.val[1], 1) != 0xFFFFFFFFU); + uint32x4_t vResult = vceqq_u32(vreinterpretq_u32_f32(V1), vreinterpretq_u32_f32(V2)); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) != 0xFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) __m128i vTemp = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2)); return ((_mm_movemask_ps(_mm_castsi128_ps(vTemp)) != 0xF) != 0); @@ -12874,9 +13056,9 @@ inline bool XM_CALLCONV XMVector4Greater return (((V1.vector4_f32[0] > V2.vector4_f32[0]) && (V1.vector4_f32[1] > V2.vector4_f32[1]) && (V1.vector4_f32[2] > V2.vector4_f32[2]) && (V1.vector4_f32[3] > V2.vector4_f32[3])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcgtq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return (vget_lane_u32(vTemp2.val[1], 1) == 0xFFFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) == 0xFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpgt_ps(V1, V2); return ((_mm_movemask_ps(vTemp) == 0x0f) != 0); @@ -12913,9 +13095,9 @@ inline uint32_t XM_CALLCONV XMVector4GreaterR #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcgtq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1); uint32_t CR = 0; if (r == 0xFFFFFFFFU) @@ -12955,9 +13137,9 @@ inline bool XM_CALLCONV XMVector4GreaterOrEqual return (((V1.vector4_f32[0] >= V2.vector4_f32[0]) && (V1.vector4_f32[1] >= V2.vector4_f32[1]) && (V1.vector4_f32[2] >= V2.vector4_f32[2]) && (V1.vector4_f32[3] >= V2.vector4_f32[3])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcgeq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return (vget_lane_u32(vTemp2.val[1], 1) == 0xFFFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) == 0xFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmpge_ps(V1, V2); return ((_mm_movemask_ps(vTemp) == 0x0f) != 0); @@ -12994,9 +13176,9 @@ inline uint32_t XM_CALLCONV XMVector4GreaterOrEqualR #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcgeq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - uint32_t r = vget_lane_u32(vTemp2.val[1], 1); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + uint32_t r = vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1); uint32_t CR = 0; if (r == 0xFFFFFFFFU) @@ -13036,9 +13218,9 @@ inline bool XM_CALLCONV XMVector4Less return (((V1.vector4_f32[0] < V2.vector4_f32[0]) && (V1.vector4_f32[1] < V2.vector4_f32[1]) && (V1.vector4_f32[2] < V2.vector4_f32[2]) && (V1.vector4_f32[3] < V2.vector4_f32[3])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcltq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return (vget_lane_u32(vTemp2.val[1], 1) == 0xFFFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) == 0xFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmplt_ps(V1, V2); return ((_mm_movemask_ps(vTemp) == 0x0f) != 0); @@ -13059,9 +13241,9 @@ inline bool XM_CALLCONV XMVector4LessOrEqual return (((V1.vector4_f32[0] <= V2.vector4_f32[0]) && (V1.vector4_f32[1] <= V2.vector4_f32[1]) && (V1.vector4_f32[2] <= V2.vector4_f32[2]) && (V1.vector4_f32[3] <= V2.vector4_f32[3])) != 0); #elif defined(_XM_ARM_NEON_INTRINSICS_) uint32x4_t vResult = vcleq_f32(V1, V2); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return (vget_lane_u32(vTemp2.val[1], 1) == 0xFFFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vResult)), vget_high_u8(vreinterpretq_u8_u32(vResult))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) == 0xFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) XMVECTOR vTemp = _mm_cmple_ps(V1, V2); return ((_mm_movemask_ps(vTemp) == 0x0f) != 0); @@ -13093,9 +13275,9 @@ inline bool XM_CALLCONV XMVector4InBounds // Blend answers ivTemp1 = vandq_u32(ivTemp1, ivTemp2); // in bounds? - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(ivTemp1), vget_high_u8(ivTemp1)); - uint16x4x2_t vTemp3 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return (vget_lane_u32(vTemp3.val[1], 1) == 0xFFFFFFFFU); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(ivTemp1)), vget_high_u8(vreinterpretq_u8_u32(ivTemp1))); + uint16x4x2_t vTemp3 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return (vget_lane_u32(vreinterpret_u32_u16(vTemp3.val[1]), 1) == 0xFFFFFFFFU); #elif defined(_XM_SSE_INTRINSICS_) // Test if less than or equal XMVECTOR vTemp1 = _mm_cmple_ps(V, Bounds); @@ -13114,7 +13296,7 @@ inline bool XM_CALLCONV XMVector4InBounds //------------------------------------------------------------------------------ -#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma float_control(push) #pragma float_control(precise, on) #endif @@ -13127,21 +13309,31 @@ inline bool XM_CALLCONV XMVector4IsNaN(FXMVECTOR V) noexcept XMISNAN(V.vector4_f32[2]) || XMISNAN(V.vector4_f32[3])); #elif defined(_XM_ARM_NEON_INTRINSICS_) - // Test against itself. NaN is always not equal +#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) + return isnan(vgetq_lane_f32(V, 0)) || isnan(vgetq_lane_f32(V, 1)) || isnan(vgetq_lane_f32(V, 2)) || isnan(vgetq_lane_f32(V, 3)); +#else +// Test against itself. NaN is always not equal uint32x4_t vTempNan = vceqq_f32(V, V); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vTempNan), vget_high_u8(vTempNan)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vTempNan)), vget_high_u8(vreinterpretq_u8_u32(vTempNan))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); // If any are NaN, the mask is zero - return (vget_lane_u32(vTemp2.val[1], 1) != 0xFFFFFFFFU); + return (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) != 0xFFFFFFFFU); +#endif #elif defined(_XM_SSE_INTRINSICS_) - // Test against itself. NaN is always not equal +#if defined(__clang__) && defined(__FINITE_MATH_ONLY__) + XM_ALIGNED_DATA(16) float tmp[4]; + _mm_store_ps(tmp, V); + return isnan(tmp[0]) || isnan(tmp[1]) || isnan(tmp[2]) || isnan(tmp[3]); +#else +// Test against itself. NaN is always not equal XMVECTOR vTempNan = _mm_cmpneq_ps(V, V); // If any are NaN, the mask is non-zero return (_mm_movemask_ps(vTempNan) != 0); #endif +#endif } -#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if !defined(_XM_NO_INTRINSICS_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma float_control(pop) #endif @@ -13158,13 +13350,13 @@ inline bool XM_CALLCONV XMVector4IsInfinite(FXMVECTOR V) noexcept #elif defined(_XM_ARM_NEON_INTRINSICS_) // Mask off the sign bit - uint32x4_t vTempInf = vandq_u32(V, g_XMAbsMask); + uint32x4_t vTempInf = vandq_u32(vreinterpretq_u32_f32(V), g_XMAbsMask); // Compare to infinity - vTempInf = vceqq_f32(vTempInf, g_XMInfinity); + vTempInf = vceqq_f32(vreinterpretq_f32_u32(vTempInf), g_XMInfinity); // If any are infinity, the signs are true. - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vTempInf), vget_high_u8(vTempInf)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - return (vget_lane_u32(vTemp2.val[1], 1) != 0); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(vTempInf)), vget_high_u8(vreinterpretq_u8_u32(vTempInf))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + return (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) != 0); #elif defined(_XM_SSE_INTRINSICS_) // Mask off the sign bit XMVECTOR vTemp = _mm_and_ps(V, g_XMAbsMask); @@ -13245,7 +13437,7 @@ inline XMVECTOR XM_CALLCONV XMVector4Cross return Result.v; #elif defined(_XM_ARM_NEON_INTRINSICS_) - const float32x2_t select = vget_low_f32(g_XMMaskX); + const uint32x2_t select = vget_low_u32(g_XMMaskX); // Term1: V2zwyz * V3wzwy const float32x2_t v2xy = vget_low_f32(V2); @@ -13334,7 +13526,7 @@ inline XMVECTOR XM_CALLCONV XMVector4Cross XMVECTOR vTemp2 = XM_PERMUTE_PS(V2, _MM_SHUFFLE(1, 3, 2, 3)); vTemp3 = XM_PERMUTE_PS(vTemp3, _MM_SHUFFLE(1, 3, 0, 1)); vResult = XM_FNMADD_PS(vTemp2, vTemp3, vResult); - // term1 * V1yxxx + // term1 * V1yxxx XMVECTOR vTemp1 = XM_PERMUTE_PS(V1, _MM_SHUFFLE(0, 0, 0, 1)); vResult = _mm_mul_ps(vResult, vTemp1); @@ -13708,8 +13900,8 @@ inline XMVECTOR XM_CALLCONV XMVector4Normalize(FXMVECTOR V) noexcept v2 = vmul_f32(S1, R1); // Normalize XMVECTOR vResult = vmulq_f32(V, vcombine_f32(v2, v2)); - vResult = vbslq_f32(vcombine_f32(VEqualsZero, VEqualsZero), vdupq_n_f32(0), vResult); - return vbslq_f32(vcombine_f32(VEqualsInf, VEqualsInf), g_XMQNaN, vResult); + vResult = vbslq_f32(vcombine_u32(VEqualsZero, VEqualsZero), vdupq_n_f32(0), vResult); + return vbslq_f32(vcombine_u32(VEqualsInf, VEqualsInf), g_XMQNaN, vResult); #elif defined(_XM_SSE4_INTRINSICS_) XMVECTOR vLengthSq = _mm_dp_ps(V, V, 0xff); // Prepare for the division @@ -13934,10 +14126,12 @@ inline XMVECTOR XM_CALLCONV XMVector4RefractV R = vmulq_f32(R, RefractionIndex); R = vmlsq_f32(g_XMOne, R, RefractionIndex); - uint32x4_t vResult = vcleq_f32(R, g_XMZero); - uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vResult), vget_high_u8(vResult)); - uint16x4x2_t vTemp2 = vzip_u16(vTemp.val[0], vTemp.val[1]); - if (vget_lane_u32(vTemp2.val[1], 1) == 0xFFFFFFFFU) + uint32x4_t isrzero = vcleq_f32(R, g_XMZero); + uint8x8x2_t vTemp = vzip_u8(vget_low_u8(vreinterpretq_u8_u32(isrzero)), vget_high_u8(vreinterpretq_u8_u32(isrzero))); + uint16x4x2_t vTemp2 = vzip_u16(vreinterpret_u16_u8(vTemp.val[0]), vreinterpret_u16_u8(vTemp.val[1])); + + float32x4_t vResult; + if (vget_lane_u32(vreinterpret_u32_u16(vTemp2.val[1]), 1) == 0xFFFFFFFFU) { // Total internal reflection vResult = g_XMZero; @@ -14144,16 +14338,16 @@ inline XMFLOAT4* XM_CALLCONV XMVector4TransformStream Result = XMVectorMultiplyAdd(Y, row1, Result); Result = XMVectorMultiplyAdd(X, row0, Result); -#ifdef _PREFAST_ -#pragma prefast(push) -#pragma prefast(disable : 26015, "PREfast noise: Esp:1307" ) -#endif + #ifdef _PREFAST_ + #pragma prefast(push) + #pragma prefast(disable : 26015, "PREfast noise: Esp:1307" ) + #endif XMStoreFloat4(reinterpret_cast(pOutputVector), Result); -#ifdef _PREFAST_ -#pragma prefast(pop) -#endif + #ifdef _PREFAST_ + #pragma prefast(pop) + #endif pInputVector += InputStride; pOutputVector += OutputStride; @@ -14510,7 +14704,7 @@ inline XMFLOAT4* XM_CALLCONV XMVector4TransformStream #ifndef _XM_NO_XMVECTOR_OVERLOADS_ - //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ inline XMVECTOR XM_CALLCONV operator+ (FXMVECTOR V) noexcept { @@ -14530,7 +14724,7 @@ inline XMVECTOR& XM_CALLCONV operator+= ( XMVECTOR& V1, FXMVECTOR V2 -) noexcept + ) noexcept { V1 = XMVectorAdd(V1, V2); return V1; @@ -14542,7 +14736,7 @@ inline XMVECTOR& XM_CALLCONV operator-= ( XMVECTOR& V1, FXMVECTOR V2 -) noexcept + ) noexcept { V1 = XMVectorSubtract(V1, V2); return V1; @@ -14554,7 +14748,7 @@ inline XMVECTOR& XM_CALLCONV operator*= ( XMVECTOR& V1, FXMVECTOR V2 -) noexcept + ) noexcept { V1 = XMVectorMultiply(V1, V2); return V1; @@ -14566,7 +14760,7 @@ inline XMVECTOR& XM_CALLCONV operator/= ( XMVECTOR& V1, FXMVECTOR V2 -) noexcept + ) noexcept { V1 = XMVectorDivide(V1, V2); return V1; @@ -14578,7 +14772,7 @@ inline XMVECTOR& operator*= ( XMVECTOR& V, const float S -) noexcept + ) noexcept { V = XMVectorScale(V, S); return V; @@ -14590,7 +14784,7 @@ inline XMVECTOR& operator/= ( XMVECTOR& V, const float S -) noexcept + ) noexcept { XMVECTOR vS = XMVectorReplicate(S); V = XMVectorDivide(V, vS); @@ -14603,7 +14797,7 @@ inline XMVECTOR XM_CALLCONV operator+ ( FXMVECTOR V1, FXMVECTOR V2 -) noexcept + ) noexcept { return XMVectorAdd(V1, V2); } @@ -14614,7 +14808,7 @@ inline XMVECTOR XM_CALLCONV operator- ( FXMVECTOR V1, FXMVECTOR V2 -) noexcept + ) noexcept { return XMVectorSubtract(V1, V2); } @@ -14625,7 +14819,7 @@ inline XMVECTOR XM_CALLCONV operator* ( FXMVECTOR V1, FXMVECTOR V2 -) noexcept + ) noexcept { return XMVectorMultiply(V1, V2); } @@ -14636,7 +14830,7 @@ inline XMVECTOR XM_CALLCONV operator/ ( FXMVECTOR V1, FXMVECTOR V2 -) noexcept + ) noexcept { return XMVectorDivide(V1, V2); } @@ -14647,7 +14841,7 @@ inline XMVECTOR XM_CALLCONV operator* ( FXMVECTOR V, const float S -) noexcept + ) noexcept { return XMVectorScale(V, S); } @@ -14658,7 +14852,7 @@ inline XMVECTOR XM_CALLCONV operator/ ( FXMVECTOR V, const float S -) noexcept + ) noexcept { XMVECTOR vS = XMVectorReplicate(S); return XMVectorDivide(V, vS); @@ -14670,7 +14864,7 @@ inline XMVECTOR XM_CALLCONV operator* ( float S, FXMVECTOR V -) noexcept + ) noexcept { return XMVectorScale(V, S); } diff --git a/src/node.cpp b/src/node.cpp index 89ce8f7..ac6ba38 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -3,7 +3,7 @@ #include "memory.h" #include "node.h" -#include "directxmath/directxmath.h" +#include "directxmath/DirectXMath.h" size_t node_alloc(int count) { diff --git a/sal.h b/src/sal.h similarity index 100% rename from sal.h rename to src/sal.h