
EasyToUse Dynamic Color Gradiant Generator 
Dennis
Member #1,090
July 2003

Martin: I wanted to edit my post, but now that you already answered, i'll just post what i wanted to add to my previous one;)) Time to clean up the mess, i created: Now i understand that my (width*height)*width distance calculations would still be wrong, because all your green pixels would be ignored in it(regardless if the were to be rendered or not). Please verify the following: Those assumptions about how the units would (positively) affect inaccuracy are just rough guesses for a simple x*x. Of course it depends a lot on the f'(x)(the higher that, the less the accuracy of the unoptimized algorithm) values in every point. to make sure the fun aspect of the whole thing is not forgotten init_ca_list3(&test3); add_to_ca_list3(&test3,CA_POINT,CA_ATTRACT,1.0,1.0,0,0, 200,200,0, 500,NULL); add_to_ca_list3(&test3,CA_POINT,CA_ATTRACT,1.0,1.0,639,479,0,200,0,500,NULL); add_to_ca_list3(&test3,CA_POINT,CA_ATTRACT,1.0,1.0,320,240,0,0,200,500,NULL); add_to_ca_list3(&test3,CA_GLOBAL,CA_ATTRACT,1.0,1.0,40,0,255,255,255,0,NULL); add_to_ca_list3(&test3,CA_POLYNOMIAL,CA_ATTRACT,1.0,1.0,0,0,255,200,0,200, make_polynomial(3,320,320,240,1.0,0,0,0)); add_to_ca_list3(&test3,CA_POLYNOMIAL,CA_ABSORB,1.0,1.0,0,0,0,255,128,100, make_polynomial(3,320,320,240,1.0,0,0,0)); render_col_grad_to_bitmap3(backb,&test3); /* backb must be a valid 32bpp bitmap 640x480 in dimensions */ save_tga("./fun.tga",backb,NULL); kill_ca_list3(&test3); [EDIT] Martin said: (unmathematically : in a very close place around a point the function value is nearly equal to the tangent. Since the tangent is not at right angle to the distance, you get closer to A by moving right over it, so by moving right a bit on the curve you also get closer to point A) the closest point then lies between those two  B. I understand that's not a mathematical proof, but I think one could base the proof upon this idea. That is clear but there is a flaw in that argument. Your point "a" is very close to the peak P, while my point "a" is far away, you would have to put your point way off above your image, if you were to assume for it the same position as my point "a".(You can't just zoom in on the peak and move "a". You have to have "a" stay where it was and thus it won't be visible on the area you zoomed in.) Also i'm sure that your point "a" would NOT lay inside my area "A". It would more likely be to the right of it, so the closest point to that would indeed not be at the peak but i did never say so. It only applies for points in Area "A". [[EDIT 2]  0xDB  @dennisbusch_de  
Martin Cerny
Member #3,931
October 2003

DB said: That is clear but there is a flaw in that argument. Not true  the image is not important, however it's scaled or points moved, the premise for the argument is that tangent is not at right angle to the distance. I though about it a bit and I think I could make serious mathematical proof of the fact that if the tangent is not at right angle to the distance, then there is a point on the curve, which is closer. Hence the only situation when there is no point closer is when the tangent is at right angle to distance.
Baba 
da_flo
Member #1,907
February 2002

Quote: I though about it a bit and I think I could make serious mathematical proof of the fact that if the tangent is not at right angle to the distance, then there is a point on the curve, which is closer. Hence the only situation when there is no point closer is when the tangent is at right angle to distance. Proving that The closest distance of a point to a curve is always at right angle to the tangent at the closest point of the curve is quite easy. I made it in a few minutes this morning, just let me some time to write it in english and upload it. 
Dennis
Member #1,090
July 2003

Martin said: Not true  the image is not important, however it's scaled or points moved, the premise for the argument is that tangent is not at right angle to the distance. I though about it a bit and I think I could make serious mathematical proof of the fact that if the tangent is not at right angle to the distance, then there is a point on the curve, which is closer.
No need to prove it. I reconsidered my drawing to be totally wrong. I can see that myself now. Your argument with the circle around "a" that will intersect with the curve another time has opened my eyes now. [edit] [edit2]  0xDB  @dennisbusch_de  
Martin Cerny
Member #3,931
October 2003

Quote: Still i have no idea which algorithm will be better. The simplest way would be to try. When you finish the object version, I can easily extend your object for polynomial attractor and override it's distance method and constuctor and then we will be able to do some FPS checks. EDIT: Ain't it funny we spent a very big part of this thread arguing about such an unimportant minor thing? And nearly noone interrupted us.;D
Baba 
Dennis
Member #1,090
July 2003

I edited while you posted. I don't know when the object version will be done, i wanted to start today but i spend the entire day arguing with you.;) Martin said: Ain't it funny we spent a very big part of this thread arguing about such an unimportant minor thing? And nearly noone interrupted us.;D Funny yes, unimportant no. You did a good job defending your algorithm and proved me wrong several times, which is good, because otherwise i would have never even bothered to think of your method as a considerable alternative.:)  0xDB  @dennisbusch_de  
da_flo
Member #1,907
February 2002

Quote: No need to prove it. Well, I went through all the hassle writing it and scanning it while you answered, so I'm posting it anyway. Sorry for the handwritten proof, that was the easier way for me do to that. I hope it's clear and readable enough. I'm not used to writing maths in english. Well, you probably don't care, but here it is. By the way, I followed the thread by didn't read all the explanations, so if you want a third point of view, tell me and I'll try to go deep into it. 
Dennis
Member #1,090
July 2003

da_flo:  0xDB  @dennisbusch_de  
Martin Cerny
Member #3,931
October 2003

da_flo: you seem to better in math than I am, so I'll try to explain my ideas with calulating the distance directly  maybe you could find a way out: notation: f'(x) is a derivative of function f(x) //hope derivative is the right term I tried two ways to calculate the distance  first I tried to qualify the function of distance from point A to a point on the curve according to it's x coordinate d(x) and then find a minimum through derivation. That leads quickly to problems, because for polynomial of nth degree d(x) is of 2nth degree and so it's derivation (which you have to solve) is of (2n1)th degree. Other idea was to start with x=A1 and calculate the derivation f'(x) and move 'left' (substract a little number from x) if (f'(x) > 0) && (f(x) > A1) or (f'(x) < 0) && (f(x) < A1) and move 'right' otherwise. And continue doing this until the distance A,[x,f(x)] will stop getting lower. Thus you could get quite good result within good time. Hope everything was clear enough. I can't figure out anything better now.
Baba 
Richard Phipps
Member #1,632
November 2001

Just checked the program out, looks great! This could come in very useful for some menu backgrounds. 
Dennis
Member #1,090
July 2003

Thanks:), that's one of the things i also had in mind for the generator. I hope you did not miss that the latest version3 has a small inconsistency in it for the polynomials. /* using "Horner Scheme" to compute function value */ cy=PN>co[PN>he]*cx; for(j=(int)PN>he1; j>0; j) cy = (PN>co[j] + cy)*cx; cy = cy + PN>co[0];
[edit]  0xDB  @dennisbusch_de  
da_flo
Member #1,907
February 2002

Okay, I tried to look at it, Martin. I didn't spend much time, and didn't find any efficient way to do it. So I really don't know how to do. I'm not really used to numerical computing. I'm learning rather theorical maths, not engineering maths. (and besides I still have a lot to learn... ) Dennis' suggestion of computing the distance to SCREEN_W points of the curve and taking the minimum is quite heavy, and is still an approximation (and using as many points as the screen width is quite arbitrary anyway. It's only quite accurate because SCREEN_W is big enough). Besides, if we want to be rigorous, we have to consider a part of the polynomial which is outside the screen, otherwise we could have some strange effects near the screen borders for some polynomials. As a conclusion, there seems to be no fast way to do it. If we want to keep the graphical fun (as Dennis said), we should forget the mathematical aspect a bit. I'll try to play with Dennis' code and add some accurate distance computation, regardless of speed. I'll post screenshots of the 2 versions, to see if the difference is really worth it.  I was also thinking of a new kind of attractors/absorbers : You could use circles. There the distance will be easy to compute. Let's assume you have a circle of radius R. If d is the distance from the point to the center of the circle, then the distance to the circle is abs(dR). I'll try to test it if I can, but if you feel like adding it yourself, Dennis, don't hesitate. 
miran
Member #2,407
June 2002

Quote: You could use circles. Good idea. That will make nice rings  
Dennis
Member #1,090
July 2003

da_flo said: I'll try to test it if I can, but if you feel like adding it yourself, Dennis, don't hesitate. I will not add any features/attractors until i have ported the entire old version3 to CPP using proper class hierarchy, as this will make adding new attractor types easier in the future. Circles are a good idea.(i already mentioned it on page2 of this thread;)) Now i got to read the rest of all post offline, because my online bill is exploding(already 67 only for this month...yeah dial up sucks:/).  0xDB  @dennisbusch_de  
da_flo
Member #1,907
February 2002

Quote: (i already mentioned it on page2 of this thread;)) Oooops. Also, we might have to types of circles : circles (like the ones I've describes), giving rings, and "plain circles" where the distance is dR if d > R, and 0 otherwise. That could give nice gradients, like sun effects or other things... Offtopic : That's my 666th post. I'm doomed.

Dennis
Member #1,090
July 2003

da_flo said: and "plain circles" where the distance is dR if d > R, and 0 otherwise. That's also a nice idea. In the current version sun effects can be achieved by having two or more point attractors at the same position with different ranges and selecting clever color combinations so they get mixed like you want them to in the center.;) This was my 685th post, i did not pay attention to my 666th, but i don't feel doomed, however i'll probably stay away from allegro.cc for a day or two now, so that i'll hopefully find the time to do the CPP port.:)  0xDB  @dennisbusch_de  
da_flo
Member #1,907
February 2002

I started looking at the gradient generator more closely. Well, in fact I never played much with the GUI, and didn't really get the working of the algo. (I know, shame on me ) I saw the role the distance to the ca played, but didn't see the ca had a range. That leads to really neat results, but I don't know why but I was rather expecting rather some kind of infinite range, with color interpolation towards infinity, with an interpolation fonction like f(d) = (d/(d+1))^n, which interpolates from 0 for d=0 to 1 for d=infinity. Well, perhaps is it I that has a twisted mind. That's just the way I would have created a gradient generator. Then I tried the linearity and multiplier parameters. Since the modifiers are applied to the distance before checking for the range, it's messing a with the range. The linearity factor doesn't cause many problems, but the multiplier is more worrying. I think you should apply the modifiers to d/next>range rather than d, after the range check, and drop the multiplier (keep only the linearity parameter). I hope I was clear enough. So was this behaviour intended or not ? I'm not asking you to change it, it's just a (useful, IMO) suggestion. 
Dennis
Member #1,090
July 2003

[edit] added more fixes from two posts below, redownload attachment[/edit] It is both feature and bug.:) A "visually" fixed version3 with much more useful behaviour is attached. Snippet from the new readme: Version 3fix2 (Aug. 10th 2005) (version 1 and 2 stripped(==declared obsolete)) Whereas in the unfixed version p and exp did exactly what was described, their behaviour lead to "visually odd" results. In this fixed version p is used to modify the intensity of the color. And exp is used to modify the "falloff" behaviour of the intensity in respect to the distance from the attractor. (Check the three examples in "main" to see the difference.) Changes in detail: The old "effect_modify" was deleted And "render_col_grad_to_bitmap3" was changed *** in PN_DESC the coefficient type was changed to double grrrr to the ellipse(...) make sure you place a "." before the variables pass as coefficients to "make_polynomial", even if you want to pass just 0 or else you'll get wrong behaviour, because of stupid type promotion in the ellipse grrr (bet your donkey that the next version will not use the ellipse but rather a pointer to a dynamic length array!) *** (Still the original behaviour of version1 can be achieved by setting p=1.0,exp=1.0) Version 3: (Aug. 6th 2005) (introducing polynomial attractors CA_POLYNOMIAL) Check newly defined PN_DESC starting at line 156 and the accompanied support
 0xDB  @dennisbusch_de  
da_flo
Member #1,907
February 2002

Okay. I played with your code yesterday night and did some things for fun. First, I must say that I had some trouble to get your code to work. for(i=(int)he+1; i>=0; i) work>co<i>=va_arg(marker,double); It has to be he, not he+1, otherwise it cannot work ! It should even sigsev with he+1, but it didn't ! (that would have helped me ). No offense intended, but I really hated you when I finally figured it out. I wanted to make some comments on your code too. At first, the polynomial code seemed quited messy, and I was confused because you use ints everywhere, for the coordinates as well as for the lookup table, and your unit. Of course I understand it's for a matter of efficiency, and that you won't loose much accuracy that way. But hey I often make some kinds of image generating programs, and I'm often not concerned by speed, and use floats everywhere... For example, I would rather have used floats and used a 'scale' parameter to convert everything to screen coordinates when drawing. Well, I'm not trying to criticize your work, I'm only describing the way I usually work. Then, I implemented an algorithm to actually compute the distance to the polynomial curve. I used your first idea in a slightly optimized and more rigorous way. d=abs(P(x)y) , then the distance is less than d, and we only have to check the points in a circle of radius d. Then I check the points of the curve from xd to x+d, and take the minimum. This method has some drawbacks. First, we have to check some points which are outside the screen. To do that, I create an extended plut table, with a plut_offset parameter giving the number of points outside the screen on the left and on the right. The real problem is that, for example for P(x) = x^2, the curves decreases very quickly, therefor for some points, d=abs(P(x)y) is very big, which leads to a huge lookup table and a huge number of calculations. But there's a way to speed it up, now that you have fixed the range/modifier problem. In fact, if the distance is greater than the range, it's useless. Thus if the first d is greater than range, we can check the points from xrange to x+range only. So, I rendered your example using my own distance calculation, and attached the result, just so that we can compare the two methods, for fun. I'm not saying that we should use that algorithm. It depends on your priorities, whether you're concerned with speed, like if you want your algorithm to be used almost in real time in games (and in that case after all, people are free not to use polynomials if they want full speed ), or if you want to do prerendered gradients where the speed doesn't matter as long as you have the picture (That's usually my way of thinking. I'm a computer barbarian and I love it ). If you're interested (even just for fun), I can post my code later, with a new version using the range to optimize it a bit. 
Dennis
Member #1,090
July 2003

da_flo said: It has to be he, not he+1, otherwise it cannot work ! It should even sigsev with he+1, but it didn't ! (that would have helped me ). No offense intended, but I really hated you when I finally figured it out.;)
Uhhh of course slaps hand at his head. My stupid mistake.:o You can't blame me for the float to double thing though, that's your stupid compilers fault. If it promotes one float to double it should promote all float through the entire programme, imho.>:( Here's a hotifxreplacement for "make_plut" and "make_polynomial"(left float as float but will be changed in the CPP port): [EDIT]FORGET about the hotfix, it made things even worse as polynomials totally ignored all "co"s except the first one...GIMME A BREAK!:P [/EDIT] But that REALLY was the last fix to the old version.;)  0xDB  @dennisbusch_de  
da_flo
Member #1,907
February 2002

Okay, first, comments on your message : Quote: You can't blame me for the float to double thing though, that's your stupid compilers fault
Go say that to all the people using various flavours of gcc. Quote:
[EDIT]FORGET about the hotfix, it made things even worse as polynomials totally ignored all "co"s except the first one...GIMME A BREAK!:P [/EDIT] I don't know what your fix is, since I didn't read your new code. But my fixed version seems to work. You can take a look at the one I'll attach "later" in this post if you want. Quote: THE CPP VERSION WILL DEFINITELY USE A POINTER TO A VARIABLE LENGTH ARRAY AND NOT THAT !#*$5'ED UP ELLIPSE(...) I nearly always code in C++ but almost never used the STL (shame on me...), but most C++ guys would tell you to use STL vectors to do that. Quote: However i must recommend that you give me a break from the old version now, or else i'll never finish the port.;)
Sorry if I prevent you from working on the C++ version. That was not my goal. Here I come to the distance to the polynomial curve. (wow. That was seamless... ) So I rewrote my code, now using the ca range to make it easier and faster. And the code really is simple now ! So, to do it, I needed to make the polynomial aware of the range of the ca. Because of your structures, I had to had a 'range' member to 'PN_DESC' and make an ugly hack : /* In wcolgradgen.cpp */ void set_pn_range(ppolynomial PN,int range) { if(PN) { PN>range=range; PN>changed=1; } }
/* in void render_col_grad_to_bitmap3(BITMAP *bmp, col_att_list3* pcal) */ if(next>PN) { if( (next>PN>w) != bmp>w) /* if target bitmap has different width than lookup table... */ set_pn_w(next>PN,bmp>w); /* makes sure that the lookup table will be calculated for evey xpixel position */ if( (next>PN>range) != next>range ) set_pn_range(next>PN, next>range); } Then I modified the make_plut function :
And finally of course I modified distance_to_ca3 : :)
My whole modified and fixed code is attached to the post. Feel free to play with it, so that we can see if it's worth adding it to the new version. Personnaly I like it, but I don't know about the speed concerns. :/ And I almost forgot : I didn't add the 'custom lookup table precision' thing, because it would have been quite messy, with ugly coordinates conversion, and because I just didn't feel like it. Later perhaps. :P 
Dennis
Member #1,090
July 2003

da_flo said:
Sorry if I prevent you from working on the C++ version. That was not my goal.
Oh, no need for excuses. Bugs are there to get fixed, and especially the weird behaviour of p and exp had already bugged(!) me for some longer time(and judging from Miran's earlier comments about it, i think he was not too happy with that behaviour either). da_flo said: Feel free to play with it, so that we can see if it's worth adding it to the new version. Personnaly I like it, but I don't know about the speed concerns.:/
We can test it, as soon as the new version is done. There you'll not need to hack, because the polynomial derived class will of course have access to the range attribute. All you'd need to do is inherit it and override the distance method and probably the lookuptablecreation method. ...maybe i'll even test your function later this evening, but i really need a pause from the stuff now...;) [edit] da_flo said: Go say that to all the people using various flavours of gcc. Yes, i already said in my edit that it is also the same way with MSVC, so MSVC is also a stupid compiler and as i also said a better(as in "less error prone" solution will be used in the port. da_flo said: I don't know what your fix is. Multiple things. First the p and exp behaviour, second the he+1 bug and last but not least speed improvements by saving a few unnecessary calculations in the render function.:)  0xDB  @dennisbusch_de  
da_flo
Member #1,907
February 2002

Hey, I was playing with the polynomials "fun" example at the top of the 4th page, using my distance calculation and changing parameters, and I noticed some strange behaviour of the polynomial attractors, even using my supposedtobeaccurate method. Then I tried it with very simple examples, with only one polynomial attractor and a global attractor for the background. And what I found was really disturbing. Look at the picture I attached. When the range is big enough, you can see darker lines where the radius of curvature of the polynomial curve has a minimum value. When I saw that, I was really disturbed, and couldn't say if it was a bug in my code (which would have surprised me, since it seemed to work well with the first examples, and I couldn't see how such a "bug" could occur ), or mathematical properties, or an optical illusion... or several of these things at the same time ! Now I'm quite sure it's not a bug, and I can somehow feel what the mathematical reasons are, but thats still bugging me, because it just doesn't feel natural. And also, the contrast might have been accentuated, by some kind of optical illusion, and my laptop screen shifts the colors and the constrast of the gradients, especially when I look my screen from further back. What do you guys think of it ? Can you see what I mean ? Does it disturb you ? Does it feel natural ? Do you think that maths and polynomials are great ? 
Richard Phipps
Member #1,632
November 2001

You know if the random element was combined with some kind of 'genetic breeding' it could be even easier to get good results, by selecting your favourite pictures to combine and mutate from a pool. 
Dennis
Member #1,090
July 2003

da_flo said: What do you guys think of it ? Can you see what I mean ? Does it disturb you ? Does it feel natural ?
If you observe your pictures closely(don't know why i immediately spotted it), you will find that those "dark lines" are appearing along curves of other pixels that are not on the polynomial but for which there are always at least TWO points on the polynomial with EQUAL distance to the points on the "dark line". Disturbing?  0xDB  @dennisbusch_de  

