I am trying to split a Rectangle into same-sized buckets, if there is not enough space at the border, the bucket is resized.
To determine the amount of Buckets, I use
int partitionsX = Math.Max((textureWidth / PartitionSize),1);
int partitionsY = Math.Max((textureHeight / PartitionSize), 1);
SampleBucket[] buckets = new SampleBucket[(partitionsX * partitionsY)];
for(int x=0; x < partitionsX; ++x)
{
for(int y = 0;y < partitionsY; ++y)
{
int idx = x + (y * partitionsX);
var bucketX = x * PartitionSize;
var bucketY = y * PartitionSize;
var bucketWidth = PartitionSize;
var bucketHeight = PartitionSize;
bucketWidth = Math.Min(bucketX + bucketWidth, (int)textureWidth) - bucketX;
bucketHeight = Math.Min(bucketY + bucketHeight, (int)textureHeight) - bucketY;
Debug.Assert(bucketWidth > 0);
Debug.Assert(bucketHeight > 0);
buckets[idx] = new SampleBucket()
{
X = bucketX,
Y = bucketY,
W = bucketWidth,
H = bucketHeight,
SampleLocations = Enumerable.Repeat(new SampleLocation() { Index = NOOP}, bucketWidth * bucketHeight).ToArray()
};
}
}
The problem occurs when I try to fill the buckets with my data.
foreach(var l in sampleLocations)
{
int bucketX = (int)(l.PixelX / PartitionSize); // PixelX/PixelY is absolute within the original texture/rectangle
int bucketY = (int)(l.PixelY / PartitionSize);
int bucketIdx = bucketX + bucketY * partitionsX;
Debug.Assert(bucketIdx < buckets.Length);
var bucket = buckets[bucketIdx]; // OOB occurs here, but I don't know where my mistake is
var locations = bucket.SampleLocations;
var sampleX = l.PixelX - bucket.X;
var sampleY = l.PixelY - bucket.Y;
var sampleIdx = sampleX + sampleY * bucket.W;
Debug.Assert(sampleIdx < locations.Length);
locations[sampleIdx] = l;
}
with textureWidth = 416, textureHeight = 452 and a SampleLocation at PixelX = 51 and PixelY = 448 I receive an Out of Bounds Bucket, when the PartitionSize is 32.
I triple checked the math but I can't find where my mistake is.
Demo with use-case that crashes: https://dotnetfiddle.net/VKYvpP
The lines where you determine the partitions X and Y is using integer math. This results in less buckets than required.
To resolve the issue, take the ceiling of size / partitionSize
.
int partitionsX = Math.Max((int)Math.Ceiling(textureWidth / (float)PartitionSize),1);
int partitionsY = Math.Max((int)Math.Ceiling(textureHeight / (float)PartitionSize), 1);