Forum archive
Evaldraw
- Ken:
Just been playing with evaldraw and I think its brilliant. Will be playing with it some more :).
Just going through the samples and was puzzled with this piece of code from ROPE.kc
(x,y,z,&r,&g,&b)
s = 0; r = 0; g = 0; b = 0;
for(v=8,a=z*PI;v<11;v++,a+=PI*2/3)
if ((x-cos(a)*.25)^2 + (y-sin(a)*.25)^2 < .25^2)
{
r += .05*v;
g += .04*v;
b += .03*v;
s++;
}
if (s == 0) return(0);
f = 256/s; r *= f; g *= f; b *= f;
s
^ - The S is the return value. If It is postive voxel is displayed. When not voxel is not displayed.
- Wouldn't it be better to return 1 instead, since s is non-negative, and s==0 is already handled?
- This is an interesting question. I think no. Returning an fixed value takes 8 byte more. On my pc returning s uses 909 cc/vox, returning 1 uses 940 cc/vox.Edited at
- I would have thought that, since all the code is compiled and optimised, there'd be a way of getting an optimisation out of returning a constant.
- You're right, I should have returned a 1 there. That was probably a remnant of test code and not about optimizing cc/vox. All optimizers have their quirks. I try not to do optimizations like that unless they make sense. It could just be one of those lucky cases where the bytes or registers happen to align right. BTW, I never look at code size when programming in EVALDRAW.
I cleaned up ROPE.KC. This is what it will look like in my next release:
(x,y,z,&r,&g,&b)
c = 0; r = 0; g = 0; b = 0;
for(v=8,a=z*PI;v<11;v++,a+=PI*2/3)
if ((x-cos(a)*.25)^2 + (y-sin(a)*.25)^2 < .25^2)
{
r += v*.05;
g += v*.04;
b += v*.03;
c++;
}
if (c) { c = 256/c; r *= c; g *= c; b *= c; }
c - Thanks Ken, I understand it now.
- Thanks for clearing that up.
I hope you don't mind, but I had a go at optimising the for loop so it only has to do 2 trig functions. Readability suffers a bit though.
Pity there's no way of automatically doing things like this.for(v=8,a=z*PI,cosa=cos(a),sina=sin(a); v<11; v++,cosa=-1/2*cosa-sqr(3)/2*sina,sina=-2*sina-sqr(3)*cosa)
if ((x-cosa*.25)^2 + (y-sina*.25)^2 < .25^2)
{
r+=v*.05;
g+=v*.04;
b+=v*.03;
c++;
}
Just out of curiosity: when Evaldraw calls the function, does it return a high precision number, or just a boolean value telling Evaldraw whether or not to add the voxel?
If it's the latter, I would have expected returning a constant to be faster because the function can skip a check for positivity. - Nice idea with the trig rotation. BTW, you didn't need to simplify cos(PI*2/3) and sin(PI*2/3) - EVALDRAW has no trouble simplifying constants : ) I modified counting_pine's algorithm a little. It runs faster for these reasons:
1. Divide by 4 (or multiply by 0.25) now happens 2x instead of 6x per voxel.
2. It is faster to do 2D rotation by calculating the new cos & sin values independently of each other. This way, you give the CPU two half-size dependency chains to work with rather than 1 long one.
(x,y,z,&r,&g,&b)
c = 0; r = 0; g = 0; b = 0;
a = z*PI;
qc = cos(a)/4;
qs = sin(a)/4;
for(v=8;v<11;v++)
{
if ((x-qc)^2 + (y-qs)^2 < .25^2)
{
r += v*.05;
g += v*.04;
b += v*.03;
c++;
}
oqc = qc; //Rotate (qc,qs) 120 degrees
qc = qc*cos(PI*2/3) + qs*sin(PI*2/3);
qs = qs*cos(PI*2/3) -oqc*sin(PI*2/3);
}
if (c) { c = 256/c; r *= c; g *= c; b *= c; }
c - Thanks. To be honest, I didn't actually simplify cos(PI*2/3) and sin(PI*2/3), I just knew them better in surd form :)
If you include the trig rotation in the next release, could you put the original code in under an "if(0)" or something? It's probably easier to follow.
By the way, does this make it any faster? r,g and b only seem to differ by a constant multiple.(x,y,z,&r,&g,&b)
c = 0; r = 0; g = 0; b = 0;
a = z*PI;
qc = cos(a)/4;
qs = sin(a)/4;
for(v=8;v<11;v++)
{
if ((x-qc)^2 + (y-qs)^2 < .25^2)
{
r += v;
c++;
}
oqc = qc; //Rotate (qc,qs) 120 degrees
qc = qc*cos(PI*2/3) + qs*sin(PI*2/3);
qs = qs*cos(PI*2/3) -oqc*sin(PI*2/3);
}
if (c) { r *= .05*256/c; g = r*.04/.05; b = r*.03/.05; }
c