Hey Ken. First of all: Evaldraw is really cool and handy. Thanks for that!
I have some suggestions for the user interface though:
- Couldn't you make the output window and the editor seperable? If the output window is really small you can't edit anything.
- Typing {,},[ or ] on a german layout is painful, you neet to press ALTGR-7,-8,-9 or -0 which makes the menu constantly pop up. IMHO ESC is enough to get to the menu... Or CTRL could be used instead...
Some things about functionality:
- How about getpix(x,y,&r,&g,&b)?
- How about (named)constants/#defines. I know that you can use static, but some thing don't seem to work with static variables! I get different results for static/normal variables...
I must add that I only recently stumpled across EVALDRAW, but I wish I had earlier.
And maybe if somebody else had any suggestions/ideas/... you could post it here...
regards
rarefluid
Awesoken at
make output window and editor seperable
I would rather not use the operating system to manage sub-windows. It makes the code less portable (if and when I choose to do it). Here are some suggestions:
* In the menus, select: View.. Font.. Transparent Background
* Click "FIT" on the window's title bar, then adjust the size of your window as you wish.
* Maximize the Evaldraw window
Typing {,},[ or ] on a german layout is painful
I did a hack so Right Alt (same scancode as ALTGR) will no longer activate the menu if it detects a non-English locale. Please let me know if it works.
getpix(x,y,&r,&g,&b)?
I could never see myself using such a function. However, I realize that not everyone programs the way I do. Therefore, I have added it to the current release.
some thing don't seem to work with static variables!
Please give me an example where static variables don't work. If it's a bug, I will fix it.
rarefluid at
Thanks a lot!
- Right ALT doesn't activate the menu anymore. Great! Much easier to type now!
- getpix() is really useful for "feedback" effects (pixel-warping, fake motion-blur) without having to create a (necessarily fixed-size) backbuffer array... I know it's lame and slow and everything ;-)
- Sure, transparent backgrounds work, and your can even restrict rendering to some size and use the rest for the editor and everything (I did that). Still, it would be easier with 2 windows... Its just a suggestion, seems you're updating evaldraw frequently and it would be some work for you, I know.
- I solved the static problem by using "static const". It seems initializations for "static" variables are not supported...
()
{
for(y = 0; y < 256; y++)
for(x = 0; x < 256; x++) {
//bla...
}
}
if I replace the 256 with:
static res = 256;
...
for(y = 0; y < res; y++)
...
I'd expect "res" to be 256 when the program recompiles and the program to work as before, but it doesn't draw anything anymore...
If I set "res" in code, it works:
static res;
res = 256;
....
Some more questions:
- I tried to use "static const" variables as array dimensions, but it didn't seem to work ("invalid dimension")?
If I define 2 consts after another it won't compile"
static const resh = 160;
static const resv = 128;
Message: "CONST already defined". Am I using constants wrong?!
- Is there a way to define global variables that have global scope, so that you don't need t pass every single lookup table to a function?
- Maybe "ERROR:" should state a line number to find errors more quickly. But you'd need a line(/column) display for the current editor window to make it really usefull...
thanks again for the quick answer and the update.
rarefluid
Awesoken at
Yup, these are some of the most important things missing from Evaldraw. I knew about all of them. Still, your input helps me to prioritize.
It seems initializations for "static" variables are not supported...
Correct. In the meantime, I've been using this technique for initialization:
static res;
if (numframes == 0) res = 256;
You can assume that static variables are zeroed at program start.
I tried to use "static const" variables as array dimensions.
"Const" is not supported. Currently, array dimensions must be declared as simple numbers or enum names. I plan to add support for expressions that evaluate to a constant at compile time.
Is there a way to define global variables that have global scope,
Not yet, but this one is high on my list.
Maybe "ERROR:" should state a line number..
Of course. Because I control the text editor, I could simply highlight the bad syntax - no need for line/column numbers.
redfaction at
Add a wrapper to glRotate,glpushmatrix and glpopmatrix will be really usefull....
I use a lot Evaldraw for democoding but there is not way of direct read of backbuffer (for fire, blur or another cool effects) can you add this ? (maybe not possible for compatibility/performance issues)
also there is some strange behaviour :
(x,y,&r&g&b){
//some code
r=result;
} //slow
(x,y,&r&g&b){
some code
b=result;
//fast
}
(x,y,&r&g&b){
//after some research I understood that r , g ,b should be always defined , not left as default
r=result;
g=0;
b=0;
}
Awesoken at
I really don't want to implement all of OpenGL. The matrix helper functions can be simulated by writing your own cover-up functions. I wrote the texture mapping stuff with OpenGL-like syntax only because people are familiar with it.
Use the recently added getpix() function to directly read the backbuffer.
Are you using r, g, or b as pointers to a function without writing them beforehand? This is a problem which I hope to fix someday. Those variable names (r, g, b) have no special meaning in "()" mode. It would help if you filled in "some code" with actual code so I can tell exactly what you are doing and why it's fast or slow.
redfaction at
some fast/slow example
()
r=0,g=0,b=0,ra=0;
for(x=0;x<xres;x++){
for(y=0;y<xres;y++){
getpix(x+1,y,ra,g,b);r=ra;
getpix(x-1,y,ra,g,b);r+=ra;
getpix(x,y+1,ra,g,b);r+=ra;
getpix(x,y-1,ra,g,b);r+=ra;
c=r;
setcol(c*255+c); //replace this by setcol(c*255); and this become really slower
setpix(x,y-3);
}
}
setcol(0xFFFFFF);
for(i=0;i<50;i++){
y=yres-20+rnd*20;
size=10+rnd*20;
x=rnd*(xres-size);
moveto(x+0,y);
lineto(x+size,y);
}
also glrotate call is easy to add in evaldraw no??? or you have "emulated" each ogl call by yourself???
i dont need every ogl calls but i think glrotate and push pop is not a luxury
redfaction at
evaldraw could be the perfect tool for making my 4k demo
but since there is no glRot or push its not possible
I'll use another tool
rarefluid at
redfaction said
evaldraw could be the perfect tool for making my 4k demo
but since there is no glRot or push its not possible
I'll use another tool
Doesn't make sense to me... Evaldraw is good for trying out algorithms quickly... Write your stuff in Evaldraw, port to C++. There you have your 4k. Where's the problem? Write your own glRot or push. If you can make a 4k, that should be no problem for you.
Awesoken at
also glrotate call is easy to add in evaldraw no??? or you have "emulated" each ogl call by yourself???
Evaldraw emulates OpenGL in software. I felt this was easier than writing (and debugging) new code to switch video modes in order to take advantage of hardware acceleration. You can emulate glRotate with your own function if you know the math. There's a 12-parameter form of setcam() which gives you full control over the camera orientation.
redfaction at
1d mode (x) use for sound is certainly full of memory leaks since each time I used it for a long period (1 hours for eg) , it used almost 700 mo of VM size so I need to restart it :(
Awesoken at
Redfaction, thanks for the report. I have looked into the problem, and I don't know a good solution for it yet. I'll explain what's going on: I'm running the compiled Evaldraw script in a separate thread. This is to protect from infinite loops. If for some reason the script freezes, I can simply end its thread, leaving the main program intact. Unfortunately, it's not as simple as that. The preferred way of ending threads is to call _endthread(); from inside the thread. This does not work for infinite loops. So instead, I call TerminateThread() from the main program. TerminateThread (for reasons I don't understand) refuses to free the thread's stack, leaving a memory leak of 1MB per thread per re-compile! I've been looking for a well-documented alternative, but haven't found anything that works yet. If anyone knows a reasonable solution, I would really appreciate it.
Jason at
Ken, this is my understanding:
Firstly, the MSDN documentation that says you can call _endthreadex() to end a thread is wrong. You should let the thread function exit like a normal function.
Secondly, TerminateThread() is sort of like killing a process. It terminates the thread on the spot with little or no clean up. Never use it. I see that you are using it to end infinite loops, so you have no other choice. But, at least attempt to end the thread normally first, since this is not the proper function for those situations.
Some links you may like to read:
http://www.flounder.com/badprogram.htm#AfxExitThread
http://www.flounder.com/badprogram.htm#TerminateThread
http://www.codeguru.com/forum/showthread.php?t=139881
Awesoken at
Interesting links, Jason. I was calling _endthread just before returning from the thread, so it wasn't affecting much. It looks like I have no choice but to rewrite my code without TerminateThread(). I thought of a way to do it, but it will take some effort. Basically, I would patch the backward jumps to nop instructions. This will require some hacking to the compiler, which I'm not excited about doing.
KillerQ13 at
Wouldn't it be possible to run the compiled code in a whole other process? One process could be the text editor while the the other would actually run the code. You could use all the various interprocess communication techniques to send the text from the editor to the compiler. They could each have their own thread to watch each other and make sure they haven't stopped responding...or maybe just the editor watching the compiler since the editor isn't likely to fail.
You could even make the compiler program accept stdin so you wouldn't even need the editor to run code. If you really wanted to, you could do something like this: type doubcube.kc > evaldraw.exe
KillerQ13 at
Sorry...I just realized that the last post didn't address the issue. It just offset the problem to another process with leaky memory. :P You'd have to kill the compliler and start another one on each change to be sure...which would take way too long and look weird.
I do have this new idea though...but it eats clock cycles. Before every jump, compile in a conditional jump to the end of the whole procedure. The condition is a boolean variable indicating termination. You could make this an optional feature like "Slower, memory safe mode". Oh!! Replace all jumps directly to the end of the procedure when you want termination...or do jumps not have all the same length in memory? (I'm working with basic functional knowledge of assembly and opcodes here.) If so, couldn't you just corrupt adjacent operations since they're not going to run anyways? You'd only have to worry about a jump at the end of the procedure (buffer overrun), in which case, make NOPs.
Awesoken at
Wouldn't it be possible to run the compiled code in a whole other process?
Actually, that is already possible! There is a note in EVALDRAW.TXT describing how to link EvalDraw and MoonEdit using a named pipe:
* KC scripts can now be sent to EVALDRAW using a named pipe (the benefit
being no disk access). Named pipes must begin with "\\.\pipe\". For
example: "evaldraw \\.\pipe\txt2evaldraw" This feature is mainly
intended for use with MoonEdit, allowing pure memory compiling.
That note is a little misleading because the version of MoonEdit that supports named pipes hasn't been released yet. I'll describe an alternate method. Add this line to the end of MoonEdit's ME.CFG:
bind f5 format savetxt "\F"; format shell evaldraw /qme "\F"
Then run MoonEdit from a directory where Evaldraw (and related data) exists. Press F5 to launch Evaldraw with MoonEdit's text buffer. With MoonEdit, you get the benefit of collaborative editing. Switching between editor and compiler is pretty seamless if you have a fast machine. The problem is you can't see the running program as you edit, making Evaldraw look like all the other compilers out there. I find this to be insufficient.
Before every jump, compile in a conditional jump to the end of the whole procedure. The condition is a boolean variable indicating termination.
I don't like that solution. I would only consider that for a system that had similar thread limitations to Windows, and didn't support self-modifying code.
Before every jump, compile in a conditional jump to the end of the whole procedure. ... make NOPs.
Filling NOPs will not work at all. Imagine what happens when the instruction pointer is inside a user function (drawkv6(), for example) and the Evaldraw script is modified at that time. Stack cleanup for drawkv6() would be missed and everything would go to hell pretty fast. Filling RETs would fail for the same reason.
In theory, any instruction could be made to clean the stack and return as soon as possible, but keeping track of the stack would be hell. The most practical method would be to modify the jump targets. Having them all branch to the end of the procedure relies on ESP being consistent at those places. While I think my compiler respects that, I don't like the idea of taking away the potential for future optimizations. If instead, I branch to the next instruction, I don't have to worry about stack management.
Jason at
Re: Suggestions for EVALDRAW
Awesoken said at
... So instead, I call TerminateThread() from the main program. TerminateThread (for reasons I don't understand) refuses to free the thread's stack, leaving a memory leak of 1MB per thread per re-compile!
I just ran across this: http://www.microsoft.com/msj/archive/SFFF.aspx Didn't read it, yet, but it looks like it dives into the details of TerminateThread().
(Btw, the new forum design / colors make it very difficult to read. It is hard to see where quotes of prior posts exit. It looks like my signature was mangled, as well -- actually, something just deleted the first character of it. Also, if you click on the messages section of the page, the mouse scroll wheel will not work.)
Edited by Jason at
David at
Re: The halting problem and evaldraw
If a process gets a chance to shut down cleanly, then it releases all of its resources. One way you could take advantage of this would be to run evaldraw in another thread in a child process. Using some sort of IPC, you could ask the child process to stop the evaldraw thread. If if the thread looks like it's hung, the child process then calls TerminateThread on the evaldraw thread and exits the process normally. Then main process would then need to (re)start a child process, which would start a new evaldraw thread. This is a brute force approach, but it is a solution that will work. I'm not sure if it would meet the real-time criteria, though, but you could get pretty close to that if the termination/restart was handled the right way.
Awesoken at
Re: Suggestions for EVALDRAW
Jason, that article looks very promising. I got the included kttest/killthrd app compiling.. I will definitely give that a try. Using processes could work too, although it sounds like more work - and less efficient overall. So now I know of 3 possible solutions: * Self-modifying code (hack backward jumps and function calls, and allow it to exit naturally) * TerminateThread replacement, written by a Microsoft guru with intimate knowledge of the OS (<- exactly the thing I was looking for) * Spawn processes instead of threads
redfaction at
Recently when using evaldraw in (x,y,&r,&g,&b) mode, i realise my algo was really slow.... I said myself it was ok since i'm using several calls to slow functions like sqrt for eg.... (when I say slow its something like 5-10 fps in 400x300 ...)
Yesterday I change the klock() call to numframes and bam everything went pretty faster!!!!! (30-40 fps ) why ????
what does the klock() function???? maybe a win32 api call ?? (normal if it will be called for every points... )
Awesoken at
If you need timing in the graphing modes, use the version with 't', ex: (x,y,t,&r,&g,&b) instead of (x,y,&r,&g,&b). The 't' is time in seconds since program recompile - exactly what klock() would return. Klock() uses QueryPerformanceCounter(), which on most machines takes between 1000 and 4000 clock cycles. Numframes is fast because its variable address is compiled directly into the code.
redfaction at
I use evaldraw mostly for two things:
- Old school 2D graphics effects - and Sound Synthesis I think it would be cool to have inside the editor some kind of trackbar linked to a variable. ex: 8 trackbars, (they are show only if needed, by options menu) after we can access it into script by a general variable ex : f[0] for trackbar0 f[1] for trackbar1 and so ..... each trackbar have a value between 0 and 1 for example
will be really usefull for testing directly some constants... and i think trackbar is something easy to implement in your interface....
Awesoken at
I know a good way to implement a trackbar ... but it's not high priority right now.
Actually, I've been working on EvalDraw a lot recently. The biggest change is thread termination without memory leaks. TerminateThread was a disaster, and the "KillThrd" library wasn't much better. I ended up using self-modifying code to break out of infinite loops. I still have a few kinks to work out, but if things go well, I should make a new release pretty soon.
redfaction at
now memory allocation problems while killing thread seems to be fixed, did you planned some new features for evaldraw????
what about my trackbar idea????? did you plan any plugin / source code release one day ????
Awesoken at
did you planned some new features for evaldraw?
Sure, I added a bunch of things in addition to the thread leak fix. I list it all in the history section of EVALDRAW.TXT.
did you plan any plugin / source code release one day ?
Sorry, I have no immediate plans to do that. Could I ask what you would change besides the trackbar idea?
redfaction at
about trackbar :
severals trackbar (ex: 8 trackbars) can be change from your interface and their value (ex : -1 => 1 or 0 => 1) can be directly accessed from code will be really usefull when doing sound synthesis or testing some 2d effects
redfaction at
Hi Ken,
I was wondering if there is any way to capture sound input (eg: from microphone) in evaldraw 1D mode ?
Would be very cool feature in order to create some realtime filters (you speak in a microphone and it apply some effects directly)... or to create some animations that react to sound (like in some winamp plugins).
Awesoken at
No, not currently. This feature has been on my list for years as low priority. Other unimplemented features which are related would be the ability to capture data from the serial port or external MIDI keyboard.