Since the textures are typically squares sized power-of-two * power-of-two, you can divide them into n sub-squares on each end, where n is a power-of-two as well. This will guarantee smooth wrapping of the texture.
Any other number can cause problems, because the number won't be divisible by it (the factorisation of 2n only has 2s in it), and either it will end with a part of a square, or the squares that you'll put in the texture won't have perfectly equal sizes.
1D example
Let's take a 1D texture first. The index in a loop is going to vary from 1 to, for example, 64. We only need to divide that number by the desired number of segments to get the number of pixels we want in one segment:
int texSize = 64;
const int desiredSegmentCount = 8;
int segmentSize = texSize / desiredSegmentCount; // 8
Now, when iterating, we can obtain the number of segment by taking the index divided by segment size:
for (int i = 0; i < texSize; ++i) {
const int segmentNum = i / segmentSize;
}
And once we have the segment number, it's easy to assess whether it's odd or even by doing segmentNum % 2
(optionally adding == 0
for clarity).
Hence, the full loop would look like:
for (int i = 0; i < texSize; ++i) {
const int segmentNum = i / segmentSize;
const bool isEven = (segmentNum % 2) == 0;
if (isEven) {
// output red pixel
} else {
// output blue pixel
}
}
Expansion to 2D
When we add another dimension, it gets only slightly more complicated. We can still assume that sizes are gonna be numbers, because we deal with squares only. The loop needs to loop across another dimension though:
for (int i = 0; i < texSize; ++i) {
for (int j = 0; j < texSize; ++j) {
const int segmentNum = i / segmentSize;
const bool isEven = (segmentNum % 2) == 0;
if (isEven) {
// output red pixel
} else {
// output blue pixel
}
}
}
This should produce a striped texture. Now we need to add actual dependency on the row, as well as on the column.
The condition for "if" becomes a truth table:
| odd | even j
-----|------------------
odd | blue | red
even | red | blue
i
That's something you should immediately recognize as a XOR operation, which for booleans actually is the same as (!=)
operator. Now the code below should be perfectly clear:
for (int i = 0; i < texSize; ++i) {
for (int j = 0; j < texSize; ++j) {
const int segmentNumI = i / segmentSize;
const int segmentNumJ = j / segmentSize;
const bool isEvenI = (segmentNumI % 2) == 0;
const bool isEvenJ = (segmentNumJ % 2) == 0;
const bool redPixel = isEvenI != isEvenJ;
if (redPixel) {
// output red pixel
} else {
// output blue pixel
}
}
}
fmod
equation looks fishy as well, but maybe there's some magic in it. – Bartek Banachewicz