Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » EasyToUse Dynamic Color Gradiant Generator

This thread is locked; no one can reply to it. rss feed Print
EasyToUse Dynamic Color Gradiant Generator
da_flo
Member #1,907
February 2002
avatar

Quote:

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".

Yes. I immediatly noticed that. :)

Quote:

Don't know what is causing it though, but i suppose your algorithm could be reporting a wrong distance

I thought it was that at first, but I can't see where my algo would fail. It's behaving as expected in the other cases. Well, I know that's no proof ;D, but I just think it works correctly. (I can't really explain)

Quote:

It could also be caused by the inaccuracy

I somehow doubt it. I thought of it too, but I have difficulty to see why. And I'm quite sure there is a mathematical reason to this, which is perhaps visually accentuated by the algorithm and the inaccuracy of the lookup table.

Anyway, I have thought of an algorithm which will get rid of the inaccuracy of my current method when the slope of the polynomial is too high, but I'll have to drop the lookup tables. It will be reliable in all cases, and will have a custom precision. I'll code it and try it if I find enough time (damn... Speedhack is beginning tomorrow :()

In fact, the inaccuracy problem appears above all when the range is small and the slope of the curve is big. Here are some pictures which show it quite nicely :
poly1int.png
poly2int.png
By the way, in a new version (I keep a backup before every major change) I changed the lookup table to floats, just to see. Of course we still have the same problem, but it smoothes things up :). See:
poly1float.png
poly2float.png

Also, I tried to play with funky polynomials, which have lots of extrema (so necessarily of higher degree), so with several areas where 2 points have the smallest distance, and sometimes even 3. I thought it will be fun. And it was. See :
funkypoly1.png
funkypoly2.png
funkypoly3.png
funkypoly4.png

In the fourth picture, I played with the exp modifier so that we can see things better (I was still using the old modifier code, by the way). It caused some nice bug because of the lookup table and the accuracy of the distance calculation method, as you can see... ;D

________________________________________________________________________

I also had some nice ideas about your C++ port, Dennis. Well, don't worry, normally this won't disturb your current development ;) (otherwise I'll begin to feel guilty ;)).

First, your whole code isn't really specifically related to allegro. You only use a putpixel and a bitmap in the rendering function. So I think it would be nice to keep the core module (the one which handle the ca list, and has the rendering method) independent of allegro or any graphics API. You could have a 'virtual void plot(int x, int y, int r, int g, int b)' virtual method which will be called from by rendering method. Then all we have to do is to derive a new graphics API specific class from the core class, which will have the bitmap or the device context as a member and implement the plot method. That way the gradient generator can easily be used with allegro, wxwidgets, or any other graphics/GUI API. :)
[EDIT]
According to that post, have a virtual plot function which will be called a lot of time will probably add much overhead and be slow. :( Well, there might be another way to achieve this, but won't be as elegant.
[/EDIT]

Then, for the polynomial thing, I think you should have a generic functional curve ca class, which will handle the distance calculation and the stuff, and have a virtual method to compute the coordinates of the points on the curve. That way we can easily have derived class for polynomials or any other kind of functions. We could have cool sine waves, or anything the user/programmer will think of. :) (easy to use since all the user has to do is derive a new class and implement the value calculation. It's just a few lines).

Also, since you want to keep different kinds of distance calculations for those functionnal curves, you'll probably want the distance calculation to be virtual, so that we can have different derived classes depending on the algorithm wanted, no ? :)

The more I think about your C++ port, the more I think it's going to be great. It will be really nice to use, it will be a true new API that programmers will be able to use. :) I don't know how you're going to handle it though. Do you think you'll make it a lib, or only header files and source modules the user will have to add to their project ? Well, perhaps a lib is a bit too much for it... I don't know.

:). I'm really enjoying playing with your code (the old C version ;)), and I'm really getting interested in this project. If you need help, I'd be really happy to contribute. If you want me to code some modules, such as the functionnal curves and other fancy maths object, I'd be glad to help you. :)

Richard Phipps
Member #1,632
November 2001
avatar

da_flo
Member #1,907
February 2002
avatar

Ooops. I didn't notice. I just put them when I felt like it (eh, I was perhaps feeling really happy in this post. :P). And I forgot I put that much... :o

Sorry. ;D

Dennis
Member #1,090
July 2003
avatar

Don't worry the C++ port, will be excellent.
Targetsystem stays Allegro, so the thing will be crossplatform.
The first release will include a GUI(using Allegro's GUI functions).
It will support different languages and the user will be able to make own translations by adding a language specific textfile.

There is really no need in giving me hints on how to do the class hierarchy(I even felt a little insulted when you pointed on those obvious things with virtual functions. Again don't worry about that. Each attractor class will have just one single function(and that is NOT the distance function;)) that is called by the render method of the gradient class and it will of course be virtual and by that every derived attractor will be free to add thousands of other functions to its' private scope and then act on the given pixel as weird or cool as it wants.)

Other features that i have planned:
-blending over images (can already easily be put into the C-version by getting initial color values from the target bitmap inside the render function, instead of setting them to 0(the fr,fg,fb values))
-arbitrary size rendering at arbitrary position (like calling with a starting point and a width and height attribute, so you can even render to bitmaps without covering their whole area)
-export gradient as code (I already wanted to have this on the first C version, but after seeing my first image i got so excited that i could not resist publishing it)
-saving and loading to and from textfiles (will even be hand-editable)
...this list will probably grow during the process of porting, as it will not just be a 1:1 port...

And now, please wait patiently for the port. It will take a lot longer than i originally thought, because there are so many NEW features i think of, that i want to have in it and also i won't release it until the GUI is done and everything is working. (Will take at least a week if not longer, because also i can't stop playing around with the old version sometimes.;D And thanks for offering but i don't want your help, because i want to code everything myself.(at least for the initial release))

Your polynomial tests are looking interesting, especially those where the polynomials are "dotted".:)
I also made another cool polynomial.(Watch out for the image of the day for tomorrow;))

da_flo
Member #1,907
February 2002
avatar

Quote:

Don't worry the C++ port, will be excellent.

I'm not worrying. ;)

Quote:

Targetsystem stays Allegro, so the thing will be crossplatform.

Okay then. But I still think it would be better if it did not directly depend on allegro, and if we could use any graphics or GUI API with it.

Quote:

There is really no need in giving me hints on how to do the class hierarchy(I even felt a little insulted when you pointed on those obvious things with virtual functions.

I didn't intend to insult you. Sorry if I there was a misunderstanding. :-[
I was not giving you hints, I was only describing in details how I would implement some ideas that just came to my mind and that I found worthwhile.

Quote:

Each attractor class will have just one single function(and that is NOT the distance function;))

Quote:

every derived attractor will be free to add thousands of other functions to its' private scope and then act on the given pixel as weird or cool as it wants.

Uh ? What will this single function be ? ??? I can't really see your class design, and I'm really curious about it. :)
I just hope that with this new design adding new attractors will remain as simple for the programmer... But then again I'm not criticizing your work, and I totally trust your C++ fu. :)

Quote:

And now, please wait patiently for the port.

But I am waiting patiently for it. :P

Quote:

And thanks for offering but i don't want your help, because i want to code everything myself.(at least for the initial release)

I understand. That's pretty normal.

Sorry, I was really getting excited about your work and about this gradient generator, and I've perhaps gone a bit too far in my previous post. ;D

( PS : I don't want to look stubborn, but I still think some of my ideas were really interesting. And also you didn't say anything about the fact having an abstract class for functionnal curves, so that we can have any functionnal curve, and not only polynomial attractors. :-/)

______________________________________________________________________________

In other news, I kept playing with the polynomial attractors, and I now have an accurate distance calculation algorithm. :)
In fact, the idea I said I had was really bullsh*t. But then I found a true idea ;D, using 3 clever lookup tables. I didn't add custom precision yet, but that won't be too hard, IMO.

So rendered the same example as before, y=x^2 with a range of 10, and here is the result : yay.png.
I even tried to use a range of 1, and it perfectly plotted the polynomial curves. See : thin2.png.
Nice. :)

Then I still have to improve it, because it has some serious problems, particularly when the polynomial curve goes really far beyond the y bounds of the screen, for example for high degrees and/or small units. I quickly becomes a memory hell and either it's awfully (and uselessly) slow or it screws everythings up.
I'll add x and y bounds to the part of the curve handled. That way I'll get rid of my problem, and I'll be able to use small bits of curves as attractors, which will be quite nice to play with. :) I began to code it very late yesterday night, so I couldn't do it. I'll be able to work on it once speehack is over (or once I have withdrawn from speedhack ;D).

Dennis
Member #1,090
July 2003
avatar

da_flo said:

Uh ? What will this single function be ????
I just hope that with this new design adding new attractors will remain as simple for the programmer...

The function will be cleverly choosen.;)
Your hopes will not be dissapointed. It will be even easier for the programmer than it is now. (And i did not say there would be no distance method at all, just in case you wondered about that.;))

da_flo said:

I still think some of my ideas were really interesting. And also you didn't say anything about the fact having an abstract class for functionnal curves, so that we can have any functionnal curve, and not only polynomial attractors.

I'm not saying that i will not add that. Also i'm not saying that i will add it. But if i add it, it would be done properly, so that the user can enter the function definition in a freeform string, just like if he'd write it down to paper. That would require writing an advanced string parser though and usage of clever operator and operands stacks and trees. Since the other features i planned will already be taking more time, it is more likely that it will not be in. But of course, i you still want to, you can later add it yourself.8-)

But i don't want to distract you from speedhack now, and as i already said the C++ port is not nearly done yet. (Some parts of it are still in the planning phase...;))

da_flo
Member #1,907
February 2002
avatar

Quote:

But i don't want to distract you from speedhack now, and as i already said the C++ port is not nearly done yet. (Some parts of it are still in the planning phase...;))

Well, I'm having annoying computer problems, particularly with my network connection. All of this is pissing me off, and I haven't started speedhack yet. I'm in such a bad mood that i don't even know if I'm going to do it, finally. >:(

And you're not distracting me at all. You're only answering to my questions and my ideas. It's rather me that have been distracting you from your C++ port for the past few days. ;)

And the fact that the C++ port isn't nearly quite done isn't a problem. I still have many things to do with functionnal curves attractors and my distance calculation algorithms ;D. (by the way, did you look at my new pictures and what I said about my new accurate algo ?)

Dennis
Member #1,090
July 2003
avatar

da_flo said:

It's rather me that have been distracting you from your C++ port for the past few days.

yes...>:( (don't take that too seriously;))

da_flo said:

by the way, did you look at my new pictures and what I said about my new accurate algo ?

I looked at the pictures and i think you did not post your new algo.
By the way: Is it really necessary to have 3 look up tables. Would it not be sufficient to have one additional table where for each y it holds a list including multiple values for the missing x pixels?;) (or maybe the other way round, does not matter too much...except that the table will be easier to calculate if having an x table with lists for the missing y values)

da_flo
Member #1,907
February 2002
avatar

Quote:

Would it not be sufficient to have one additional table where for each y it holds a list including multiple values for the missing x pixels?

hmm. I thought about it in my bed yesterday night (I didn't even had this idea before...), and I didn't think it would really work easily. But after all, if I look at it more closely, perhaps it would work.

But my method is not really more complicated or eats much more computing or memory power, and is really elegant mathematically speaking, IMO. :)

Dennis
Member #1,090
July 2003
avatar

I think i just found the best and fastest method of all(:)):
(look at the piccy then read the description)
http://homepages.compuserve.de/DennisTapier/allegroforum/distance.png
The Algo-Idea to that:
first: Compute distance to function value.
second: Simultaneously trace in whole pixel steps a line to the left and one to the right.
break conditions:
If one trace hits an y position where it is smallerOrEqual than "function value at that position plus the 'rise' value" or bigger than "function value at that position minus 'fall' value", you can stop tracing into the opposite direction and break the trace loop.
If traces in both directions hit the end of the lookup table without any result you can stop tracing as well.
result: if the trace did not find anything the calc from first is the distance.
if the trace did hit anything(there is always just one candidate for a smaller distance found from tracing, cause if one side is succesfull the other is automatically farther away!) take the smaller value of (trace distance,distance to function value).

Hope it gets clear, I was too lazy to give a more detailed explaination.:)

[edit] Because of the y rising downwards you have to switch some plus and minus and blah in the above description but the idea stays the same. The fun thing: NO squareroots are involved!!! ('cause the tracelength-count can directly be taken...;))[/edit]

[edit2]it can be optimized even more by just storing a 'high' and a 'low' for each x position(don't extra store 'rise' and 'fall') then for the trace position a simple low<=y<high(or high<=y<low for y rising downwards) will do sufficient for stopping the trace[/edit2]

[edit3]
Trace in either direction can also stop if that directions' tracelengthcount exceeds the 'range' of the polynomial or if that directions tracelengthcount exceeds the distance to the function value.[/edit3]

[EDIT4](too bad i spotted a flaw: For a pixel to the bottem right or left of the minimum in the above example, it would report a wrong distance...>:()[/edit4]

[edit5]
...ok but coming around that flaw is easy:). If the trace was unsuccesfull in both directions:
store the distance to the function value as current result
then calculate the distance to x-1's function value and the distance to x+1's function value (euclidean distance)
if both are bigger than the current result, stop
if one of them is smaller than the current result, store the smaller one as the current result and go on calculating the distance to subsequent function values but only in that direction where the distance was smaller
as soon as you find a distance that is bigger than the current result you can stop and return the current result!:)
If i don't overlook sth. this algo should now be absolutely flawless and very quick in most cases and still quick in cases where the trace was unsuccesfull.
Damn, i'm good! ;D
[/edit5]

da_flo
Member #1,907
February 2002
avatar

Okay. I'll take a closer look at it later. :)

(Must... stay... away... from... allegro.cc)
(Luckily, I currently cannot access to the internet from my coding computer ;D)

Dennis
Member #1,090
July 2003
avatar

da_flo said:

Must... stay... away... from... allegro.cc

Yeah, i must say i'm really becoming obsessed about the thing.:D

Make sure you don't miss my edits above as they describe pitfalls you could encounter, if you were very tired already.;)

------------------
[edit](should have been an additional post)
I thought about portability again and i plan now, as you suggested, to keep the core functionality system independent.
But i will not use a virtual putpixel function. I found a better solution: The gradient generator class will be a template, in which the exchangable type will be a customized bitmap type, that the programmer has to supply(i will supply one for the allegro version).
That customized bitmap type will be required to have some specific methods then(like get_width, get_pixel, put_pixel...) but basically be kept simple.
By that, virtual function calls to pixel putting functions are avoided, because the platform specific code for the gradient generator is already generated at compile-time.
The attractors and the gradient generator classes will use an internally device-independent pixel format, which the customized bitmap will be responsible for to convert correctly.(Will be very easy to implement for the allegro specific bitmap type, because of makecol.:))
So far so good. The basic planning phase should be completed soon.(Playing around with the old version and writing so much around here and thinking of other things, kept me from making any major progress with the implementation.;D)

da_flo
Member #1,907
February 2002
avatar

Quote:

da_flo said:
Must... stay... away... from... allegro.cc

Yeah, i must say i'm really becoming obsessed about the thing.:D

I meant : I must stay away from allegro.cc. ;D For speedhack reasons...

Quote:

I thought about portability again and i plan now, as you suggested, to keep the core functionality system independent.

:) :) (Nothing more to add)

Quote:

So far so good. The basic planning phase should be completed soon.

Okay. Keep going and good luck ! :D

PS : Hey, you will be able to post new message now ;)
I'm currently busy with speedhack, so I can wait a while for the code for the IOTD. That way you won't be stuck again if you want to post a new message apart from the IOTD code. ;)

Dennis
Member #1,090
July 2003
avatar

Well then here's the IOTD code:

col_att_list3 test;
  init_ca_list3(&test);
  add_to_ca_list3(&test,CA_POINT,CA_ABSORB,1.8,1.0,320,240,0,255,255,200,NULL);
  add_to_ca_list3(&test,CA_VBAR,CA_ATTRACT,1.8,0.33,320,0,255,255,100,320,NULL);
  add_to_ca_list3(&test,CA_HBAR,CA_ATTRACT,1.8,0.33,0,240,255,255,100,240,NULL);
  add_to_ca_list3(&test,CA_POLYNOMIAL,CA_ABSORB,1.8,0.39,0,0,100,100,0,200,
                  make_polynomial(5,100,320,240,-1.0,0.0,5.0,0.0,-4.0,0.0));
  add_to_ca_list3(&test,CA_POLYNOMIAL,CA_ATTRACT,1.8,0.39,0,0,50,150,255,200,
                  make_polynomial(5,100,320,240,-1.0,0.0,5.0,0.0,-4.0,0.0));
  render_col_grad_to_bitmap3(backb,&test); /* backb must be a valid 32bpp bitmap 640x480 in dimensions */
  save_tga("./polycool.tga",backb,NULL);
  kill_ca_list3(&test);

(you can make backb 1600x1200 but then you must also multiply all positions and ranges by 2.5)

I'll try to resist coming back for a whole week.:)

Edward Sheets
Member #4,734
June 2004
avatar

Dennis said:

I'll try to resist coming back for a whole week.:)

Don't do that! This has been one of the most educational and productive threads ever :D

Good job with the Dynamic Color Gradient Generator. It's very kool.

---

Note: carving a pentagram on the top of a container of spoiled yogurt does not summon a yogurt demon. -Kikaru

Dennis
Member #1,090
July 2003
avatar

Hey, thanks a lot!:)

But i definitely need to cut back on my visits, or else nothing ever gets done.
Maybe i'll report my progress once a day or so.

(As everyone can see i could not even resist coming back for a few hours:P)

[edit sunday 14th]
Progress:
-implemented customRGB type meant for greater precision during color mixing
-implemented the GLOBAL attractor type as the base class from which all other attractor types will be derived from
(thats all for today as the lord said sth. like "Men shalt rest on the seventh day!";))

[edit Monday 15th]
Progress:
-implemented the HBAR and VBAR attractor classes
-the "it will be easier than it is now to write new attractor types"-feature fell victim to the polymorphic design and to my effort in making the maintenance and extendability of the gradient generator itself easier, but the good thing about it is, that writing new attractor types will be somewhat normed, not hacky and finally introducing the new types to the gradient generator will be easier

[edit Wednesday 17th]
Progress:
-implemented POINT, CIRCLE and FCIRCLE attractor classes
-made plans and calculations for a POINTE class(point attractor with an elliptic range)
-also played with the thought of a rotated ELLIPTIC attractor class and thought of making POINTE rotated as well

da_flo
Member #1,907
February 2002
avatar

Okay I'm back after this exhausting speedhack and a small break.

As for the distance calculation, I'll post a detailed comment once I'm motivated enough to analyse your method in details and give a good explanation of mine.;) (Seems like I'm getting tired of writing long and complicated posts. But be sure I'll do it !). I'll just say now that my method is flawless too, quite quick too, and above all mathematically very clear and elegant ! ;D (well, that's why it seems appealing to me. We don't have quite the same concerns sometimes ;)

Quote:

made plans and calculations for a POINTE class(point attractor with an elliptic range)

Nice idea. That way of generalizing is really the one I like to play with. :)

Quote:

also played with the thought of a rotated ELLIPTIC attractor class and thought of making POINTE rotated as well

In fact, I was thinking of making every attractor rotated, even POINT for consitency.
The attractors, instead of being defined by a (x,y) pair of coordinates, would then be defined by (alpha, x', y'), where (x', y') are the coordinates relative to the axes rotated by the angle alpha around the origin ( x==x' and y==y' for alpha = 0 mod 2*Pi). That way it will be really general and quite elegant. All you'd have to do when doing the distance calculation would be converting the (x,y) coordinates of the current point to (x',y') and do the calculation as usual in the new coordinates. And if you're concerned with speed, you can always use sin and cos lookup tables, of course. ;)
(Note : I am not giving you hints, just explaining my method in details ;))

Also, having elliptic attractors will be quite nice. And there should be a way to easily calculate the distance to an ellipse, using the properties of the normals to an ellipse. (I would have to dig into my geometry courses, though ;D)

Dennis
Member #1,090
July 2003
avatar

da_flo said:

And there should be a way to easily calculate the distance to an ellipse,

It is in fact easy and i already made all the calculations, generalized for rotated ellipse and point"e".
(I'll not write it down here, because it's just basic trigonometry combined with some simple IR^2-vector math and i hate writing math in ascii(and in english) and besides it would almost already look like the code itself, so it would be twice the work in half the time.;)(another reason **))
For the pointe the calculations are almost the same, just a little different, because the distance to the ellipse is in the case of the elliptic range around a point not of any matter.
In the pointe case, only the distance to the center of the ellipse matters and its' relative percentage of the length of the vector to the point "on the ellipse" at the same angle inside the ellipses' rotated system.(Sounds a little odd, but if you could see what i see in my (slightly messy)sketch it becomes obvious.)

I think you don't even need to dig in any geometry books for that. Just draw a sketch of a cartesian coordinate system(y grows downwards) then put a rotated(angle grows clockwise) ellipse somewhere with attributes "center(x0,y0)","width","height","angle(rotation around its center)", then start using your brain.:)

(**see the difference: ..I don't feed you every (annoying) detail, by that i give you the chance to find a way(which may turn out to be different from mine) yourself and i don't already lead your thoughts into any specific direction.)

da_flo said:

(Note : I am not giving you hints, just explaining my method in details;))

Very wise of you to put that comment.(Kept me from exploding into 1000 pieces, but maybe it is just me who gets angry that easily.);)

[edit]
I hope your silence does not mean that you hate me now, because you might have misunderstood me. It is not that i would not appreciate your or anyone's help in general. It is just that i (for some weird reason i don't even know myself) get annoyed if i'm swamped with lot's of detailed help, which i did not explicitely ask for and especially if it is for a topic i (think i) perfectly know well enough myself. I don't know, there is probably no excuse for my harsh response to you.:-/

[progress Thursday 18th]
-implemented the POINTE (rotated elliptic range) color attractor type
-fixed lots of conceptual errors in all other types
(i have not yet tested a single attractor, because the gradient_gen class is not implemented yet. because of that, i decided that after implementing the polynomial type and the ellipse type i will put a "new attractor lock" onto me, and then write the gradient generator class first, so i can at least test, if the attractors so far are actually working, because coding without actually seeing something from time to time is starting to get boring:))

[progress Saturday 20th]
-implemented rotated ELLIPSE color attractor type
-decided to make a rotated BAR and a rotated POLYNOMIAL attractor(of course the rotated bar would already be included in the POLYNOMIAL but for a simple bar, distance calculations can be made less complicated and faster)
(rotations pivot will always be the center of the attractors themselves)

[progress Thursday 23rd]
-did not do anything since saturday, hoping to implement the POLYNOMIAL attractor today, if i can finally manage to stop playing "Bunkermaster":o



Go to: