//traverses the tree, but on a thread task void DrawOnThread(ThreadDrawer thread, DrawState state, IDraw[] children, BinaryNode[] nodes, bool treeIsOptimized) { if (left == 0) { ThreadDrawnInstance inst; inst.childCount = this.childCount; inst.firstChild = this.firstChild; if (thread.instanceCount == thread.instances.Length) { Array.Resize(ref thread.instances, thread.instances.Length * 2); } thread.instances[thread.instanceCount] = inst; thread.instanceCount++; } else { if (treeIsOptimized) { uint firstChild = this.firstChild; firstChild <<= ChildCountShift; uint lastChild = this.childCount; lastChild <<= ChildCountShift; // actually lastChild + 1 uint count = lastChild - firstChild; ushort firstChildIndex = this.firstChild; ThreadDrawnInstance inst; while (count > ushort.MaxValue) { if (thread.instanceCount == thread.instances.Length) { Array.Resize(ref thread.instances, thread.instances.Length * 2); } firstChildIndex += ushort.MaxValue / ChildCount; count -= ushort.MaxValue; inst.childCount = ushort.MaxValue; inst.firstChild = firstChildIndex; thread.instances[thread.instanceCount++] = inst; } if (thread.instanceCount == thread.instances.Length) { Array.Resize(ref thread.instances, thread.instances.Length * 2); } inst.childCount = (ushort)count; inst.firstChild = firstChildIndex; thread.instances[thread.instanceCount++] = inst; } else { nodes[left].DrawOnThread(thread, state, children, nodes, treeIsOptimized); nodes[right].DrawOnThread(thread, state, children, nodes, treeIsOptimized); } } }
//traverses the tree, but on a thread task public void DrawOnThread(ThreadDrawer thread, DrawState state, float[] boundsMin, float[] boundsMax, int axis, IDraw[] children, BinaryNode[] nodes, bool isIdentityMatrix, bool treeIsOptimized) { boundsMin[axis] = min; boundsMax[axis] = max; Vector3 localMin = new Vector3(), localMax = new Vector3(); localMin.X = boundsMin[0]; localMin.Y = boundsMin[1]; localMin.Z = boundsMin[2]; localMax.X = boundsMax[0]; localMax.Y = boundsMax[1]; localMax.Z = boundsMax[2]; ContainmentType type; if (!isIdentityMatrix) { type = state.Culler.IntersectBox(ref localMin, ref localMax); } else { type = state.Culler.IntersectWorldBox(ref localMin, ref localMax); } switch (type) { case ContainmentType.Contains: DrawOnThread(thread, state, children, nodes, treeIsOptimized); break; case ContainmentType.Intersects: if (left == 0) { ThreadDrawnInstance inst; inst.childCount = this.childCount; inst.firstChild = this.firstChild; if (thread.cullTestInstanceCount == thread.cullTestInstances.Length) { Array.Resize(ref thread.cullTestInstances, thread.cullTestInstances.Length * 2); } thread.cullTestInstances[thread.cullTestInstanceCount] = inst; thread.cullTestInstanceCount++; } else { nodes[left].DrawOnThread(thread, state, boundsMin, boundsMax, axis == 2 ? 0 : axis + 1, children, nodes, isIdentityMatrix, treeIsOptimized); boundsMin[0] = localMin.X; boundsMin[1] = localMin.Y; boundsMin[2] = localMin.Z; boundsMax[0] = localMax.X; boundsMax[1] = localMax.Y; boundsMax[2] = localMax.Z; nodes[right].DrawOnThread(thread, state, boundsMin, boundsMax, axis == 2 ? 0 : axis + 1, children, nodes, isIdentityMatrix, treeIsOptimized); boundsMin[0] = localMin.X; boundsMin[1] = localMin.Y; boundsMin[2] = localMin.Z; boundsMax[0] = localMax.X; boundsMax[1] = localMax.Y; boundsMax[2] = localMax.Z; } break; } }
//similar to a normal draw, but stops when depth == threadLevel, and then runs a thread process from there private void DrawItemsThread(DrawState state, ushort node, int depth, ref int index, float[] boundsMin, float[] boundsMax) { boundsMin[depth % 3] = allNodes[node].min; boundsMax[depth % 3] = allNodes[node].max; Vector3 localMin = new Vector3(), localMax = new Vector3(); localMin.X = boundsMin[0]; localMin.Y = boundsMin[1]; localMin.Z = boundsMin[2]; localMax.X = boundsMax[0]; localMax.Y = boundsMax[1]; localMax.Z = boundsMax[2]; ContainmentType type; if (!threads[0].idenityMatrix) { type = state.Culler.IntersectBox(ref localMin, ref localMax); } else { type = state.Culler.IntersectWorldBox(ref localMin, ref localMax); } switch (type) { case ContainmentType.Contains: allNodes[node].Draw(state, allChildren, allNodes, IsOptimizedState); break; case ContainmentType.Intersects: if (allNodes[node].left == 0 || depth == threadLevel) { ThreadDrawer thread = this.threads[index++]; for (int i = 0; i < 3; i++) { thread.minBuffer[i] = boundsMin[i]; thread.maxBuffer[i] = boundsMax[i]; } //carry on from here on a thread task thread.startIndex = node; thread.callback = state.Application.ThreadPool.QueueTask(thread, state); } else { DrawItemsThread(state, allNodes[node].left, depth + 1, ref index, boundsMin, boundsMax); boundsMin[0] = localMin.X; boundsMin[1] = localMin.Y; boundsMin[2] = localMin.Z; boundsMax[0] = localMax.X; boundsMax[1] = localMax.Y; boundsMax[2] = localMax.Z; DrawItemsThread(state, allNodes[node].right, depth + 1, ref index, boundsMin, boundsMax); boundsMin[0] = localMin.X; boundsMin[1] = localMin.Y; boundsMin[2] = localMin.Z; boundsMax[0] = localMax.X; boundsMax[1] = localMax.Y; boundsMax[2] = localMax.Z; } break; } }