In the previous version of this algorithm, the way to level down in the octree was to maintain the arrangement of sums and masks for each level, calculating these numbers by dividing by 2.
In the current version there was an improvement in this aspect, instead of calculating for each level these values and masks divided into 2 what we are going to do is multiply by two the position, this makes the sums per child are the same and the mask also.
See and example in 2d:
bitmask for a quadree of length 16
+------+ every line are the half of len!!
+------+
+------+
+------+
bitmask for this lines (in hex)
11555577eeaaaa88
and the sum for childres are:
sum[0..3]=(0,6,2,8)
for example for the pixel 6 (start in 0)
+------+
+---X--+
X------+
+-----X+
6
11555577eeaaaa88
the first level give me the child mask $7 (%0111 in binary) then can down to childrens 0,1 and 2.
the second level when children 0 are:
X=(6-sum[0])*2 ; 6 are the previous value, 0 are the children number
X=12
then new children mask is $a (%1010), only 1 and 3 children.
+------+
+---X--+
X------+
+-----X+
+-X+
+--+
+--X
+--+
The second level when children 1 are:
X=(6-sum[1])*2 ; 6 are the previous value, 1 are the children number
X=0
then new children mask is $1 (%0001), only children 0
+------+
+---X--+
X------+
+-----X+
+--+
+--+
+--+
X--+
Now in code:
The word for get the next child, in the stack, like parameters, there are the childrens order and the len of side rectangle.
:nextchild | norden len -- norden len
1 << swap | len norden
dup b> xy zz stack4!
$7 and 1 over << 1 - >r
3 << 'vecpos +
@+ xy swap - 1 << 'xy ! @ neg 'zz +! | new XY and ZZ
b@+ dup r> and popcnt swap 8 >> + 2 << b+ | calc of next node
b> $pixels >=? ( octcolor a! 0 ; ) drop | end of octree?
getyxmaskl | len bm
b@ and 0? ( drop prevchild ; )
fillchild | len norden
swap ;
the more complicated thing is the calc of next node. What this line does is, first, given the child to enter, calculate the mask that corresponds to the previous children, ( 1<<mask)-1 This mask serves to know how many children there are before the corresponding one, doing an AND with the children of the node and adding the offset to calculate the new address. The funny thing about this calculation is that use POPCNT, the only time I use this function.
prevchild, for up level
:prevchild | len -- ordenn len
1 >> 0? ( dup ; ) | duplicate len
stack2@2 $ffffffff and
4 >>> 0? ( 2drop prevchild ; ) | next child
stackvar
swap >b swap ;
A trick for avoid memory asignation is en stack2@2, only get 2 values from 4 stacked, and only when have children get this values to vars.
I need the mask $ffffffff because r3 is 64 bits and when get a value in 32, the procesor fill the sign (x64 rules) and I need this value without sign.
Remember, all the code is in
https://github.com/phreda4/r3vm/blob/master/r3/dev/cuboiso5.r3