Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - kanonet

Pages: [1]
1
3D / Better support for shaders
« on: 2013-Mar-15 »
I did play around with shaders in last time and got some nice effects for the beginning. But it would be really useful if we could get some more feature to use them better/ more properly:

1. X_PUTSHADER needs to get extended to store other data types like:
GLB -> glsl shader
DGInt -> float (only thing that currently works)
array[2] -> vec2
array[3] -> vec3
array[4] -> vec4
array[9] -> mat3
array[16] -> mat4
sprite ID -> sampler2D (i need a way to input more textures/ offscreen buffers)
[ TYPE (of DGInts) -> C struct (of floats) ]
Cause its very much work (and a dirty work around) to break everything into many floats and pass each float on its own into the shader. We can not do this with INLINE on our own atm.

2. Extend X_GETCAMERAMATRIX (with optional parameter, or create a new command?) so that it can output each of the matrix:
modelviewmatrix
projectionmatrix
[texturematrix]
Yes we can do this with INLINE on our own, but Im not sure if it will work on all platforms. So a native solution would be awesome.


I understand that this are advanced features and that GLB is designed to be easy - but since I do not request to remove any feature, it will not get harder for anyone. Btw. i do not need to get these functions directly in GLB, it would be totally ok, if there were some easy to use C functions that we can use with INLINE on ALL platforms. Thank you for you work Kitty!

2
Bug Reports / V11: REDIM + FOREACH
« on: 2013-Jan-18 »
If you use REDIM [0] to 'delete' an integer array, array.count gets not updated, so FOREACH thinks the array is still big and calls the deleted entries too. LEN and BOUNDS work correct. The bug only happens with integer arrays and when you REDIM it to [0], all other values work fine, so do arrays of floats, string and types. I did only test V11.

Here is an example:
Code: GLBasic [Select]
LOCAL a%[]
DIM a[4]
FOR i%=0 TO a.count-1
        a[i]=i
NEXT
REDIM a[0]
DEBUG "count: "+(a.count)+"  len: "+LEN(a[])+"  bounds: "+BOUNDS(a[],0)+"\n"
DEBUG "elements with foreach:\n"
FOREACH b IN a[]
        DEBUG b+"\n"
NEXT
DEBUG "elements with for:\n"
FOR i%=0 TO LEN(a[])-1
        DEBUG a[i]+"\n"
NEXT
This is the output that i get from this example:
Code: GLBasic [Select]
count: 4  len: 0  bounds: 0
elements with foreach:
0
1
2
3
elements with for:

BTW. did I win a prize for finding the most exotic bug in the new year? :D

3
GLBasic - en / Something wired
« on: 2012-Jun-15 »
Ok i just found something really wired regarding to speed of GLB:
Code: GLBasic [Select]
LOCAL start=0
LOCAL stop=200000
LOCAL stepping=0.005

time0=GETTIMERALL()
FOR i=start TO stop STEP stepping
        value=1
NEXT
time0=GETTIMERALL()-time0
PRINT time0+" ms", 0,0
Displayed time after execution: about 89 ms

Code: GLBasic [Select]
LOCAL start=0
LOCAL stop=200000
LOCAL stepping=0.005

time0=GETTIMERALL()
FOR i=start TO stop STEP stepping
        value=1
NEXT
time0=GETTIMERALL()-time0
LOCAL s$=value
PRINT time0+" ms", 0,0
Displayed time after execution: about 112 ms

Im checking time for exactly the same code in both cases, but its significant slower if i convert the result to a string in an other part of the program (displaying the result with PRINT has the same effect). Does anyone has an idea why this happens?

4
If you ever wanted to be able to rotate X_SPRITEs or you want them to be faster (so you can create plenty of them, e.g. for a particle engine), than here is a solution for you:
My TSprite can get scaled, rotated and positioned anywhere in the 3D-scene, it will always turn to the camera (like X_SPRITE does), even if you use X_CAMERAUP (for a 6DOF camera). Its all encapsulated into one Type, for easy transfer to your projects.

Comparison with X_SPRITE:
differences:
  • its midhandled (centered)
  • need to get textured manually
  • scale=1 has alwasy the same size (1 unit in 3D environment), no matter what size the texture got
advantages:
  • rotation is possible
  • faster at least +5-400% on my machine (without texture ordering)
  • gives you the ability for texture ordering (+700-3200% more speed on my machine!  :O)
disadvantages:
  • you need to call more than one function
  • gl.gbas (or at least a part of it) and QSIN is needed in your project
  • maybe do not run on mobile devices (with OpenGL ES), i dont know, someone need to test this

How to use it:
At game start, define and initialise it:
Code: GLBasic [Select]
LOCAL sprite AS TSprite
sprite.Init()
In your gameloop render all your GLB 3D stuff, than make sprite.start(), draw your sprites and texture them, try to use as few X_SETTEXTURE as possible if some sprites use the same texture, just make only one X_SETTEXTURE and draw all sprites that use it (texture ordering). End your sprite drawing with sprite.stop(). Just use one start() and stop() pair each loop and draw all sprites between them. Do not use any GLB OpenGL calls between start() and stop()!
Code: GLBasic [Select]
sprite.Start()
        X_SETTEXTURE 0
        sprite.Draw()
        sprite.Draw()
        sprite.Draw()
        sprite.Draw()
        X_SETTEXTURE 1
        sprite.Draw()
        X_SETTEXTURE 2
        sprite.Draw()
        sprite.Draw()
sprite.Stop()

Ok, here is the code and a test program that show you how to use it (again^^) and let you compare the sprite techniques on your machine:
Code:
Code: GLBasic [Select]
// ------------------------------------------ //
// Project: TSprite
// Start: Sunday, July 24, 2011
// Autor: Kanonet
// Last Update: December 01, 2012
// For a newer Version go to: http://www.kanonet.de/downloads/libsprite
// ------------------------------------------ //

//?DEFINE gl_gbas               1               // define this, if you use gl.gbas; set it to zero or dont define it, if you do NOT use gl.gbas

TYPE TSprite
        // vertex coords
        m0#; m1#; m2#
        m4#; m5#
        m8#; m9#; m10#

        // normal coords
        nx#; ny#; nz#

        // texture coords
        t0x#=0; t0y#=1
        t1x#=1; t1y#=1
        t2x#=0; t2y#=0
        t3x#=1; t3y#=0

        // last drawn normal
        lastnormal AS char

        ?IF DEFINED( gl_gbas )
        ?ELSE
                INLINE
                        typedef unsigned int    GLenum;
                        typedef float           GLfloat;
                        #define GL_TRIANGLE_STRIP                                               0x0005
                        } extern "C" {
                                        void __stdcall glBegin( GLenum mode );
                                        void __stdcall glEnd( void );
                                        void __stdcall glVertex3f( GLfloat x , GLfloat y , GLfloat z );
                                        void __stdcall glNormal3f( GLfloat nx , GLfloat ny , GLfloat nz );
                                        void __stdcall glTexCoord2f( GLfloat s , GLfloat t );
                        } namespace __GLBASIC__ {
                ENDINLINE
        ?ENDIF

        // start drawing of sprites, call it one time  each loop: after X_CAMERA... and before you draw your sprites
        FUNCTION Init%:
                STATIC mat#[]
                X_GETCAMERAMATRIX mat[]
                ALIAS n2 AS mat[2]; ALIAS n10 AS mat[10]
                self.m0 = -mat[0]
                self.m4 = -mat[4]
                self.m8 = -mat[8]
                self.m1 = mat[1]
                self.m5 = mat[5]
                self.m9 = mat[9]
                self.m10=qInvSQR(n2*n2 + n10*n10)
                self.m2=n2*self.m10
                self.m10=n10*self.m10
                self.nx = n2
                self.ny = mat[6]
                self.nz = n10
                self.lastnormal = 0
        ENDFUNCTION

        // draw a spherical sprite (same like X_SPRITE)
        // needs to be after Start()
        // sprite will be midhandled (unlike X_SPRITE)
        FUNCTION Draw%: x#,y#,z#, Scale#=1.0, Rotation#=0.0
                STATIC xn#,xp#, yn#,yp#, zn#,zp#
                Scale# = Scale# * 0.5
                zn = qSIN( Rotation# + 90 ) * Scale#
                zp = qSIN( Rotation# ) * Scale#

                Rotation# = self.m1 * zp + self.m0 * zn
                xn = self.m1 * zn - self.m0 * zp
                xp = Rotation#+xn;  xn = Rotation#-xn
                Rotation# = self.m5 * zp + self.m4 * zn
                yn = self.m5 * zn - self.m4 * zp
                yp = Rotation#+yn;  yn = Rotation#-yn
                Rotation# = self.m9 * zp + self.m8 * zn
                zn = self.m9 * zn - self.m8 * zp
                zp = Rotation#+zn;  zn = Rotation#-zn

                ?IF DEFINED( gl_gbas )
                        glBegin( GL_TRIANGLE_STRIP )
                                IF self.lastnormal <> 1
                                        glNormal3f( self.nx, self.ny, self.nz )
                                        self.lastnormal = 1
                                ENDIF
                                glTexCoord2f( self.t0x, self.t0y )
                                glVertex3f( x# + xp, y# + yp, z# + zp )
                                glTexCoord2f( self.t1x, self.t1y )
                                glVertex3f( x# - xn, y# - yn, z# - zn )
                                glTexCoord2f( self.t2x, self.t2y )
                                glVertex3f( x# + xn, y# + yn, z# + zn )
                                glTexCoord2f( self.t3x, self.t3y )
                                glVertex3f( x# - xp, y# - yp, z# - zp )
                        glEnd()
                ?ELSE
                        INLINE
                                glBegin( GL_TRIANGLE_STRIP );
                                        if (this->lastnormal != 1) {
                                                glNormal3f( this->nx, this->ny, this->nz );
                                                this->lastnormal = 1;
                                        };
                                        glTexCoord2f( this->t0x, this->t0y );
                                        glVertex3f( x + xp, y + yp, z + zp );
                                        glTexCoord2f( this->t1x, this->t1y );
                                        glVertex3f( x - xn, y - yn, z - zn );
                                        glTexCoord2f( this->t2x, this->t2y );
                                        glVertex3f( x + xn, y + yn, z + zn );
                                        glTexCoord2f( this->t3x, this->t3y );
                                        glVertex3f( x - xp, y - yp, z - zp );
                                glEnd();
                        ENDINLINE
                ?ENDIF
        ENDFUNCTION

        // draw a cylindrical sprite (same like X_SPRITE)
        // needs to be after Start()
        // sprite will be midhandled (unlike X_SPRITE)
        FUNCTION Draw2%: x#,y#,z#, Scale#=1.0, Rotation#=0.0
                STATIC xn#,xp#, yn#,yp#, zn#,zp#
                Scale# = Scale# * 0.5
                zn = qSIN( Rotation# + 90 )*Scale#
                zp = qSIN( Rotation# )*Scale#

                Rotation# = self.m10 * zn
                xn = self.m10 * zp
                xp = Rotation#-xn;  xn = Rotation#+xn
                yp = zp + zn;  yn = zp - zn
                Rotation# = self.m2 * zn
                zn = self.m2 * zp
                zp = Rotation#-zn;  zn = Rotation#+zn

                ?IF DEFINED( gl_gbas )
                        glBegin( GL_TRIANGLE_STRIP )
                                IF self.lastnormal <> 2
                                        glNormal3f( self.m2, 0, self.m10 )
                                        self.lastnormal = 2
                                ENDIF
                                glTexCoord2f( self.t0x, self.t0y )
                                glVertex3f( x# - xp, y# + yp, z# + zp )
                                glTexCoord2f( self.t1x, self.t1y )
                                glVertex3f( x# + xn, y# - yn, z# - zn )
                                glTexCoord2f( self.t2x, self.t2y )
                                glVertex3f( x# - xn, y# + yn, z# + zn )
                                glTexCoord2f( self.t3x, self.t3y )
                                glVertex3f( x# + xp, y# - yp, z# - zp )
                        glEnd()
                ?ELSE
                        INLINE
                                glBegin( GL_TRIANGLE_STRIP );
                                        if (this->lastnormal != 2) {
                                                glNormal3f( this->m2, 0, this->m10 );
                                                this->lastnormal = 2;
                                        };
                                        glTexCoord2f( this->t0x, this->t0y );
                                        glVertex3f( x - xp, y + yp, z + zp );
                                        glTexCoord2f( this->t1x, this->t1y );
                                        glVertex3f( x + xn, y - yn, z - zn );
                                        glTexCoord2f( this->t2x, this->t2y );
                                        glVertex3f( x - xn, y + yn, z + zn );
                                        glTexCoord2f( this->t3x, this->t3y );
                                        glVertex3f( x + xp, y - yp, z - zp );
                                glEnd();
                        ENDINLINE
                ?ENDIF
        ENDFUNCTION

        // use this if you want to change texture coords
        // its way faster to change texture coords instead of changing texture with X_SETTEXTURE
        // it will affect all following draw()/draw2() calls, in all following loops!
        FUNCTION SetTextureCoords: t0x#, t0y#, t1x#, t1y#, t2x#, t2y#, t3x#, t3y#
                self.t0x = t0x;  self.t0y = t0y
                self.t1x = t1x;  self.t1y = t1y
                self.t2x = t2x;  self.t2y = t2y
                self.t3x = t3x;  self.t3y = t3y
        ENDFUNCTION

ENDTYPE
Test Program:
Code: GLBasic [Select]
// --------------------------------- //
// Project: TSprite
// Start: Sunday, July 24, 2011
// Autor: Kanonet
// Last Update: April 20, 2012

SETSCREEN 800,600,0
SYSTEMPOINTER TRUE
ALLOWESCAPE FALSE
AUTOPAUSE FALSE
LIMITFPS -1

// number of sprites to draw:
LOCAL count%=1000

LOCAL root%=SQR(count)/2, line%, row%, fps, timer, mx, my=15, mz=-4, selected%=1

// texture
DRAWRECT 0,0, 16, 16, RGB(0,0,255)
DRAWRECT 12,0, 4,8, RGB(255,127,0)
DRAWRECT 0,12, 4,4, RGB(255,0,63)
DRAWLINE 0,0, 16,16, 0xffffff
DRAWLINE 0,16, 16,0, 0xffffff
GRABSPRITE 0, 0,0, 16,16

// sprite
LOCAL sprite AS TSprite
sprite.Init()


// mainloop
REPEAT

        line=-root; row=-root

        // mouse for camera control:
        mx = mx + MOUSEAXIS(0)
        my = my + MOUSEAXIS(1)
        mz = mz + MOUSEAXIS(2)
        IF KEY(27) // + more sprites
                INC count
                root=SQR(count)/2
        ENDIF
        IF KEY(53) AND count>1 // - less sprites
                DEC count
                root=SQR(count)/2
        ENDIF
        IF KEY(2) THEN selected=1
        IF KEY(3) THEN selected=2
        IF KEY(4) THEN selected=3

        X_MAKE3D 0.1, 1000, 45
        X_CAMERA my*COS(mx)*root*0.2,mz*2,my*SIN(mx)*root*0.2, 0,0,0

        IF selected=1
                FOR i=1 TO count

                        X_SPRITE 0, 0, line, row, 0.06

                        INC row
                        IF row>root
                                row=-root
                                INC line
                        ENDIF
                NEXT
        ELSEIF selected=2
                sprite.Start()
                FOR i=1 TO count

                        X_SETTEXTURE 0, -1
                        sprite.Draw(0, line, row, 0.5)

                        INC row
                        IF row>root
                                row=-root
                                INC line
                        ENDIF
                NEXT
                sprite.Stop()
        ELSE
                sprite.Start()
                X_SETTEXTURE 0, -1
                FOR i=1 TO count

                        sprite.Draw(0, line, row, 0.5)

                        INC row
                        IF row>root
                                row=-root
                                INC line
                        ENDIF
                NEXT
                sprite.Stop()
        ENDIF

        X_MAKE2D
        ALPHAMODE 0.9
        DRAWRECT 0,0,800,60,RGB(70,70,70)
        PRINT "CAMERA CONTROL: MOVE MOUSE / MOUSE WHEEL    |    FPS: "+INTEGER(1000/(timer-fps)), 0,0
        PRINT "SPRITES CURRENTLY: "+count+"    |    PRESS (+) FOR MORE SPRITES AND (-) FOR LESS", 0,15
        PRINT "SELECT: (1) X_SPRITE    |    (2) TSPRITE    |    (3) TSPRITE WITH TEXTURE ORDERING", 0, 30
        PRINT "SELECTED: "+selected, 0, 45

        SHOWSCREEN
        fps=timer
        timer=GETTIMERALL()
UNTIL KEY(1)
END

Finally some test results (FPS), done on my T410s (see signature), which have to graphiccards (i can select one to use):
Intel HD Graphics - 1000 Sprites: 46 / 48 / 393
Intel HD Graphics - 2000 Sprites: 24 / 25 / 253
Intel HD Graphics - 3000 Sprites: 16 / 17 / 196
Intel HD Graphics - 4000 Sprites: 12 / 13 / 152
Intel HD Graphics - 5000 Sprites: 10 / 10 / 125
Intel HD Graphics - 7500 Sprites: 7 / 7 / 88
Intel HD Graphics - 10000 Sprites: 5 / 6 / 68
NVidia NVS 3100M - 1000 Sprites: 85 / 459 / 500 (cant do more)
NVidia NVS 3100M - 2000 Sprites: 50 / 256 / 500 (cant do more)
NVidia NVS 3100M - 3000 Sprites: 35 / 175 / 500 (cant do more)
NVidia NVS 3100M - 4000 Sprites: 27 / 134 / 500 (cant do more)
NVidia NVS 3100M - 5000 Sprites: 22 / 110 / 500 (cant do more)
NVidia NVS 3100M - 7500 Sprites: 15 / 74 / 480
NVidia NVS 3100M - 10000 Sprites: 11 / 56 / 370

I think here is the newes gl.gbas: http://www.glbasic.com/forum/index.php?topic=7801.msg66675#msg66675 it can run without this, but if you want to use it, you need to uncomment "//?DEFINE gl_gbas 1"
You can find newest QSIN (QQSIN) here: http://www.glbasic.com/forum/index.php?topic=6446.msg65027#msg65027 but i included it in this testprogram. ;)
Would be really good, if someone could test it on mobile devices.

Now i want someone to create a decent particle engine with this. :good:
Im pretty new to (directly) using OpenGL, which is hard cuz i dont know C. :giveup: So maybe there are better/faster ways to do this, so please point me at them. Any tips/ suggestions/ feedback are really welcome. <3

You always find the latest version on my website: http://www.kanonet.de/downloads/libsprite

5
DD-GUI / DDcreator
« on: 2012-Feb-28 »
If you like using DDgui in you project, but dont like to code the gui manually, this is what you need! You can just click your gui together and edit/position your widgets fast. If your gui is complete, just save it into a file. You still need to know how DDgui works, but it will save you some time and make it easier to create your gui.
Its all written in GLBasic and DDgui, so you can run it on any platform and expand it easily. If you fix some bugs, or add some features, please share them with use! ;)

How to use:
  • download and unzip the code
  • add a current version of "DDgui.gbas" (better always use a actual one)
  • compile and run program
  • you will see two windows, in the smaller one you can create and edit the gui, in the other one you see the result (this window is really just for showing you the result, any changes that you make here will get lost!)
  • create your gui ;)
  • hit the "save into file" button (code will get stored into "Form.gbas")
  • copy the gui code from "From.gbas" into your project and be happy :P

Screenshots:
       

If you like this or have any suggestions/question/criticism, please give me feedback.

Regards,
Kanonet

You always find the latest version on my website: http://www.kanonet.de/downloads/ddcreator

6
Bug Reports / Sock IP Funktionen kaputt?
« on: 2011-Nov-11 »
SOCK_TCPACCEPT( sock%, ip% )
ip% = SOCK_GETREMOTEIP( sock% )
In beiden fällen ist ip% immer 0.
Das Netzwerk funktioniert, ich kann empfangen und senden, wie es sein soll, es ist mir lediglich nicht möglich die IP des Clients/Servers zu ermitteln. Betrifft TCP, sowohl wenn sich Client und Server auf einen Rechner befinden, als auch, wenn sie auf verschiedenen laufen. Nicht getestet unter UDP.

EDIT: Auch zum Thema SOCK_...:
Interessanterweise habe ich gerade festgestellt, dass bei Kommunikation zwischen zwei Rechnern meine Firewall (Comodo) verhindert, dass ich feststellen kann, dass die Verbindung abgebrochen ist. Wenn der Client offline gegangen ist, erhält der Server über SOCK_RECV weiterhin -2 als Rückgabewert, statt der erwarteten und gewünschten 0. Irgendeine Idee, wie dies gelöst werden kann, ohne die Firewall zu deaktivieren?

7
GLBasic - de / Wie funktioniert REDIM?
« on: 2011-Nov-06 »
Ja, wie funktioniert REDIM eigentlich intern? Ich weiß, wie es einzusetzen ist, aber ich möchte gern wissen, wie es intern arbeitet, damit ich geschwindigkeitsabhängige Vorgänge noch besser optimieren kann.

Wenn ich schreibe:
Code: GLBasic [Select]
LOCAL a%[], b%[]

DIM a[100]
REDIM a[0]

REDIM b[100]
Würde dann b[] den nicht freigegebenen Speicher von a[] nutzen, oder könnte das ausschließlich a[] selbst? Und falls b[] dazu in der Lage wäre, wie sieht es aus, wenn a[] und b[] sich in verschiedenen Types, Functionen, Subs,... befinden?
Ich weiß nicht, ob dies außer Gernot jemand beantworten kann, auf jeden Fall bedanke ich mich für eure Hilfe.

Grüße.

EDIT: weil ich gerade dabei bin:
Es wäre sehr nützlich, wenn man FOREACH um ein optionales STEP -1 oder ähnliches erweitern könnte, damit man ein Array rückwärts durchsuchen kann, ohne auf die Geschwindigkeit von FOREACH verzichten zu müssen.

EDIT2: wieso gibt das folgende keinen Fehler/Programmcrash?:
Code: GLBasic [Select]
DIM a[1]
WHILE a[-1]=0
        DIMDEL a[], -1
WEND

8
Bug Reports / F10 hält Programm an
« on: 2011-Jun-05 »
Drückt man in laufendem Programm F10, wird das Programm so lange angehalten, bis wieder eine Taste gedrückt wird. Tritt sowohl im Debug, als auch im Releasemodus auf (sowohl in V9, als auch in V10), jedoch nur im Fenstermodus. Ist das ein Feature?

9
Ich hätte ein paar Änderungsvorschläge:

1. Wenn man bei einem GLBasic-Befehl F1 drückt kommt man zur zugehörigen Hilfeseite, drückt man bei einer eigenen Funktion/Sub F1 wird jedoch nur die Hilfe (mit der aktuell geöffneten Seite) nach vorn geholt.
Ich hätte gern, dass wenn ich beim Nutzen einer eigenen Funktion F1 drücke, der Cursor automatisch zur Funktionsdeklaration springt. Sollte natürlich auch bei Funktionen funktionieren, die in anderen .gbas Dateien deklariert wurden.

2. Befindet sich der Curser auf einem Funktionsnahmen erscheint dieser ja unten links mit seinen Parametern und eventuellen Kommentaren. Gibt es jedoch in mehreren Types gleichnamige Funktionen, wird immer die zuerst erstellte (?) angezeigt, auch wenn es sich eigentlich um eine andere handelt, was im Falle unterschiedlicher Parameter verwirrend sein kann. Es wäre natürlich angenehmer, wenn immer die aktuell verwendete Angezeigt werden würde, jedoch vermute ich, dass dies zu aufwändig zu implementieren wäre? Wobei dieser Punkt auch für die Umsetzung von 1. relevant ist...

3. Ich speichere gern Optionen und ähnliches in .ini-Dateien, welche ich dabei auch gern in der IDE öffne. nehme ich jetzt lediglich Änderungen in der Ini vor und drücke dann F5, wäre es wünschenswert, dass die IDE die Ini zwar speichert jedoch den Code nicht erneut compiliert (ist ja nicht nötig, da keine Änderungen vorgenommen wurden) sondern die .exe sofort startet. Sollte natürlich nicht nur für Inis, sondern sämtliche nicht .gbas (oder .gbap) Dateien so sein.

Gibt es eigentlich mittlerweile eigentlich die geplante (optional aktivierbare) Autovervollständigung?

Wäre schön, wenn das eine oder andere umgesetzt werden könnte, vielen Dank.
Grüße

10
Code Snippets / simple userdefined controls
« on: 2011-Feb-09 »
I created my own simple "key"-management, for user defined keys. A "key" can be a key from keyboard, mousemovement, mousebutton, joystickmovement or joystickbutton, you dont have to care about what the player use, the key-management will do all on its own. Keyboardlayouts are stored in .ini-files, i created one for us/uk and one for german keyboard, but of cause you can convert/create others for other countries (please share them with us/me!).

Its really simple to use:
1. create a new key:
Code: GLBasic [Select]
LOCAL attack AS Tkey

2. let the player define his key:
Code: GLBasic [Select]
REPEAT
        PRINT "Define control for attack",0,0
        SHOWSCREEN
UNTIL attack.SET()
or autoset it (usefull if you load keysettings from a ini-file):
Code: GLBasic [Select]
attack.SET(1, 57)
and you can add a secondary/alternativ key:
Code: GLBasic [Select]
attack.SET(2) or attack.SET(2, 28)

3. in your mainloop, check whether the player use the key:
Code: GLBasic [Select]
IF attack.DOWN() THEN DOSOMETHING()
This checks primary and secondary key.


TKey now informs you about keyup/-down event.:
//  0 = not pressed / nicht gedrückt
//  2 = just pressed / gerade runtergedrückt
//  1 = pressed / gedrückt (gehalten)
// -1 = release event / wieder losgelassen
Of cause it only works, if you use DOWN() in your loop...


The ini-files for us and german keyboard are attached, here is the code for the key-management:
Code: GLBasic [Select]
// --------------------------------- //
// Project: MyKey
// Autor: kanonet
// Start: Tuesday, February 08, 2011
// Last Update: December 6, 2012

GLOBAL KEY_mouse_sensitivity% = 2       // sensitivity of the mouse
GLOBAL KEY_joystick_sensitivity# = 0.35 // sensitivity of the joystick
GLOBAL KEY_keymap$[]
GLOBAL KEY_joystick_count%      // for intern use, do not change
GLOBAL KEY_ini_file$ = "keymap_us.ini"  // which INI file to read for keyboard layout


//! Type of a "key". It is possible to set a primary and a secondary "key".
//! "key" can be a key of the keyboard, a mousemovement, a mousebutton, a joystickmovement or a joystickbutton.
//! After a "key" was set with SET(), you can use DOWN() to check whether the player use it.
//? Typ eines "keys". Es ist möglich einen primären und einen sekundären "key" zu festzulegen.
//? "key" kann eine Taste der Tastatur, eine Mausbewegung, ein Mausbutton, eine Joystickbewegung oder ein Joystickbutton sein.
//? Nachdem ein "key" mit SET() gestzt wurde, kann mit DOWN() geprüft werden, ob er benutzt wird.
TYPE Tkey
        code%   // eventcode of the "key" if "key" is on the keyboard, code = scancode of the key
        name$
        code2%
        name2$
        state%

        //! Initialise/sets the "key". Can get used as often as its needed, until played sets a "key".
        //! You can change the "key" as often, as you want. You can define a alternativ "key" also.
        //? Initialisiert/setzt den "key". Kann beliebig oft aufgerufen werden, bis der Spieler einen "key" gesetzt hat.
        //? Ein gesetzter "key" kann beliebig oft geändert werden. Es kann außerdem auch ein alternativer "key" definiert werden.
        // \param num% - Optional, use function call to set the primary (num%=1) or secondary (num%=2) "key". | Optional, mit funltionsaufruf wird der primäre (num%=1) oder der sekundäre (num%=2) "key" festgelegt.
        // \param code% - Optional, only use this if you want to select a "key", not the player!  | code% - Optional, sollte nur genutz werden, wenn man selbst ein "key" setzen und dies nicht den Spieler überlassen will!
        // \return 0 if no "key" was set, otherwise code% of the "key". | 0 wenn kein "key" gesetzt wurde, ansonsten code% des gesetzten "keys".
        FUNCTION SET: num%=1, code%=0

                LOCAL event%, name$
                event=code

                IF NOT code     // only check for userinput if no key was specified

                        // check Keyboard
                        FOR i=1 TO 237
                                IF i=89 THEN i=153
                                IF KEY(i)
                                        event=i; BREAK
                                ENDIF
                        NEXT


                        IF NOT event

                                // check mouse
                                IF MOUSEAXIS(3); event=331
                                ELSEIF MOUSEAXIS(4); event=332
                                ELSEIF MOUSEAXIS(5); event=333
                                ELSEIF MOUSEAXIS(0)<-KEY_mouse_sensitivity; event=301
                                ELSEIF MOUSEAXIS(0)>KEY_mouse_sensitivity; event=302
                                ELSEIF MOUSEAXIS(1)<-KEY_mouse_sensitivity; event=311
                                ELSEIF MOUSEAXIS(1)>KEY_mouse_sensitivity; event=312
                                ELSEIF MOUSEAXIS(2)>0; event=321
                                ELSEIF MOUSEAXIS(2)<0; event=322
                                ELSE
                                        // check joystick
                                        KEY_joystick_count%=GETNUMJOYSTICKS()-1
                                        FOR i=0 TO KEY_joystick_count
                                                IF GETJOYX(i)<-KEY_joystick_sensitivity; event=401+i*100; BREAK
                                                ELSEIF GETJOYX(i)>KEY_joystick_sensitivity; event=402+i*100; BREAK
                                                ELSEIF GETJOYY(i)<-KEY_joystick_sensitivity; event=411+i*100; BREAK
                                                ELSEIF GETJOYY(i)>KEY_joystick_sensitivity; event=412+i*100; BREAK
                                                ELSEIF GETJOYZ(i)<-KEY_joystick_sensitivity; event=421+i*100; BREAK
                                                ELSEIF GETJOYZ(i)>KEY_joystick_sensitivity; event=422+i*100; BREAK
                                                ELSEIF GETJOYRX(i)<-KEY_joystick_sensitivity; event=403+i*100; BREAK
                                                ELSEIF GETJOYRX(i)>KEY_joystick_sensitivity; event=404+i*100; BREAK
                                                ELSEIF GETJOYRY(i)<-KEY_joystick_sensitivity; event=413+i*100; BREAK
                                                ELSEIF GETJOYRY(i)>KEY_joystick_sensitivity; event=414+i*100; BREAK
                                                ELSEIF GETJOYRZ(i)<-KEY_joystick_sensitivity; event=423+i*100; BREAK
                                                ELSEIF GETJOYRZ(i)>KEY_joystick_sensitivity; event=424+i*100; BREAK
                                                ELSEIF GETDIGIX(i)<-KEY_joystick_sensitivity; event=431+i*100; BREAK
                                                ELSEIF GETDIGIX(i)>KEY_joystick_sensitivity; event=432+i*100; BREAK
                                                ELSEIF GETDIGIY(i)<-KEY_joystick_sensitivity; event=441+i*100; BREAK
                                                ELSEIF GETDIGIY(i)>KEY_joystick_sensitivity; event=442+i*100; BREAK
                                                ELSE
                                                        FOR j=0 TO 31
                                                                IF GETJOYBUTTON(i, j); event=451+j+i*100; BREAK; ENDIF
                                                        NEXT
                                                ENDIF
                                        NEXT
                                ENDIF

                        ENDIF

                ENDIF

                // DIM array for the keyboardlayout
                IF KEY_keymap_Str.count <> 324
                        DIM KEY_keymap$[324]
                        LOCAL j=0
                        INIOPEN KEY_ini_file$

                        FOR i%=0 TO 452
                                IF i=238
                                        i=301
                                ELSEIF i=334
                                        i=400
                                ENDIF
                                KEY_keymap$[j]=INIGET$("keymap", i, "")
                                INC j
                        NEXT
                        INIOPEN ""
                ENDIF

                // give readable names
                SELECT event
                        CASE 0 TO 237; name$=KEY_keymap$[event]
                        CASE 301 TO 333; name$=KEY_keymap$[event-63]
                        CASE 401 TO (KEY_joystick_count*100+482)
                                code=MOD(event,100)
                                name$=GETJOYNAME$(event/100-4)
                                IF name$="" THEN name$=KEY_keymap$[271]+FORMAT$(2,0,event/100-3)
                                SELECT code
                                        CASE 1 TO 42; name$=name$+" "+KEY_keymap$[code+271]
                                        CASE 51 TO 82; name$=name$+" "+KEY_keymap$[322]+(code-50)
                                ENDSELECT
                        DEFAULT; name$=KEY_keymap$[323]
                ENDSELECT

                // write the key on specified slot
                IF num=2
                        IF event=self.code
                                event=0
                                name$=KEY_keymap$[0]
                        ENDIF
                        self.code2%=event
                        self.name2$=name$
                ELSE
                        IF event=self.code2
                                event=0
                                name$=KEY_keymap$[0]
                        ENDIF
                        self.code%=event
                        self.name$=name$
                ENDIF
                RETURN event

        ENDFUNCTION

        //! Detect whether a "key" is used by the player or not.
        //? Ermittelt ob ein "key" vom Spieler genutzt wird.
        // \return 0 if "key" is not in use, otherwise >0. (if "key" is mouse or joystick movementspeed will be returned)  | 0 wenn "key" nicht genutzt wird, ansonsten >0. (ist "key" Maus oder Joystick, wird die Bewegungsgeschwindigleit zurück gegeben)
        // \return TKey.state% will tell you, if key was used before: 0=not pressed, 2=just pressed, 1=pressed, -1=release event. | TKey.state% gibt zurück, ob key genutzt wurde: 0=nicht gedrückt, 2=gerade runtergedrückt, 1=gedrückt (gehalten), -1=wieder losgelassen.
        FUNCTION DOWN:

                STATIC joy, event%, KEY_joystick_sensitivity=0.2
                FOR i=0 TO 1
                        IF i=0
                                event=self.code
                        ELSE
                                event=self.code2
                        ENDIF

                        SELECT event
                                CASE 0; joy=0
                                CASE 1 TO 237   // check keyboard
                                        joy=KEY(event)
                                CASE 301 TO 350 // check mouse
                                        SELECT event
                                                CASE 301; joy=MOUSEAXIS(0)/20.; IF joy<0; joy=-joy; ELSE; joy=0; ENDIF
                                                CASE 302; joy=MOUSEAXIS(0)/20.; IF joy<0 THEN joy=0
                                                CASE 311; joy=MOUSEAXIS(1)/20.; IF joy<0; joy=-joy; ELSE; joy=0; ENDIF
                                                CASE 312; joy=MOUSEAXIS(1)/20.; IF joy<0 THEN joy=0
                                                CASE 321; joy=MOUSEAXIS(2)>0
                                                CASE 322; joy=MOUSEAXIS(2)<0
                                                CASE 331; joy=MOUSEAXIS(3)
                                                CASE 332; joy=MOUSEAXIS(4)
                                                CASE 333; joy=MOUSEAXIS(5)
                                        ENDSELECT
                                CASE 401 TO (KEY_joystick_count*100+482)        // check joytick
                                        joy=MOD(event,100)
                                        event=event/100-4
                                        SELECT joy
                                                CASE 1; joy=GETJOYX(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
                                                CASE 2; joy=GETJOYX(event); IF joy<KEY_joystick_sensitivity THEN joy=0
                                                CASE 11; joy=GETJOYY(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
                                                CASE 12; joy=GETJOYY(event); IF joy<KEY_joystick_sensitivity THEN joy=0
                                                CASE 21; joy=GETJOYZ(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
                                                CASE 22; joy=GETJOYZ(event); IF joy<KEY_joystick_sensitivity THEN joy=0
                                                CASE 3; joy=GETJOYRX(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
                                                CASE 4; joy=GETJOYRX(event); IF joy<KEY_joystick_sensitivity THEN joy=0
                                                CASE 13; joy=GETJOYRY(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
                                                CASE 14; joy=GETJOYRY(event); IF joy<KEY_joystick_sensitivity THEN joy=0
                                                CASE 23; joy=GETJOYRZ(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
                                                CASE 24; joy=GETJOYRZ(event); IF joy<KEY_joystick_sensitivity THEN joy=0
                                                CASE 31; joy=GETDIGIX(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
                                                CASE 32; joy=GETDIGIX(event); IF joy<KEY_joystick_sensitivity THEN joy=0
                                                CASE 41; joy=GETDIGIY(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
                                                CASE 42; joy=GETDIGIY(event); IF joy<KEY_joystick_sensitivity THEN joy=0
                                                CASE 51 TO 82; joy=SGN(GETJOYBUTTON(event, joy-51))
                                                DEFAULT; joy=0
                                        ENDSELECT
                                DEFAULT; joy=0
                        ENDSELECT
                        IF joy THEN BREAK
                NEXT
                // check if key was used before
                IF joy
                        IF self.state
                                self.state=1
                        ELSE
                                self.state=2
                        ENDIF
                ELSE
                        IF self.state>0
                                self.state=-1
                        ELSE
                                self.state=0
                        ENDIF
                ENDIF
                RETURN joy

        ENDFUNCTION

ENDTYPE
Please let me know what you think about this and report bugs. I dont have a real joystick/gamepad (i just used a virtual one) and my keyboard has no numpad/mediakeys, so it would be really nice if someone could test this for me. EDIT: Testing done by Ragaril, thank you!
EDIT2: small Update.
EDIT3: small Update. :P
EDIT4: there was a small typo in last Update. :-[

11
Code Snippets / Wegfindungsroutine
« on: 2010-Dec-18 »
Ich habe eine kleine Wegfindungsroutine geschrieben, sie basiert auf dem A*-Algorithmus und ermöglicht die Bewegung in acht Richtungen, also auch diagonal. Wegkosten können beachtet werden.
Aus Geschwindigkeitsgründen erfolgt die Wegsuche gleichzeitig vom Start- und dem Zielpunkt aus, was bei großen Karten zu kleineren Abweichungen in der Mitte führen kann.

Zur Benutzung:
Init_FindPath() einmal ausführen, also vor der Hauptschleife.
Advanced_FindPath() kann dann beliebig oft aufgerufen werden.
Parameter sind ähnlich Gernots FINDPATH(). Zu beachten ist noch, dass beide Routinen im Debugmodus signifikant verlangsamt werden, außerdem dauert die Berechnung um so länger, je mehr begehbare Felder es gibt.

Ich habe mich bemüht eine möglichst hohe Geschwindigkeit zu ermöglichen. Ich würde mich freuen, wenn es dem einen oder anderen nützen würde, und/oder ich weitere Verbesserungsvorschläge bekomme, vielleicht findet sich ja jemand in meine Kommentierung hinein. :D

Viele Grüße.

Hier die Routine in einem kleinen Beispiel, wollt ihr sie selbst nutzen, dann einfach die beiden Funktionen kopieren:

EDIT: ein kleiner aber gravierender Fehler wurde korrigiert. Schaut euch aber auch diesen Algorithmus an und entscheidet dann, was eure Bedürfnisse besser erfüllt.
Code: GLBasic [Select]
// --------------------------------- //
// Project: Wegfindung
// Autor: Kanonet
// Start: Tuesday, October 19, 2010
// Update: July 23, 2011
// IDE Version: 8.125

LOCAL map[]     // dies ist die Karte mit der die Wegfindungsrotiene arbeitet
GLOBAL AFP_mapmax_x%, AFP_mapmax_y%     // Größe der Karte; wir von Init_FindPath gesetzt

LOCAL x%, y%, zx%, zy%, lger[], lkan[], mx, my, mr, ml, timeger, timekan, mdown

Init_FindPath(map[], 80,60)     // Initialisierung der Wegfindung

SETSCREEN AFP_mapmax_x*10, AFP_mapmax_y*10, 0
SYSTEMPOINTER TRUE

x=0
y=2
zx=AFP_mapmax_x-1
zy=AFP_mapmax_y-1


REPEAT

        MOUSESTATE mx, my, mr, ml
        IF mr   // rechte Maustaste -> Startpunkt setzen
                x=mx/10
                y=my/10
        ELSEIF ml       // linke Maustaste -> Zielpunkt setzen
                zx=mx/10
                zy=my/10
        ELSEIF MOUSEAXIS(5) OR KEY(56)  // mittlere Maustaste -> passierbarkeit dieses Runkts der Karte ändern
                IF mdown=0
                        mdown=-map[mx/10][my/10]
                ENDIF
                IF KEY(29) OR KEY (157) THEN mdown=5
                map[mx/10][my/10]=mdown
        ELSE
                mdown=0
        ENDIF

        IF KEY(57)      // Wegsuchen starten und benötigte Zeit messen
                timeger=GETTIMERALL()
                FINDPATH(map[], lger[], 0.5, x, y, zx, zy)
                timeger=GETTIMERALL()-timeger
                timekan=GETTIMERALL()
                Advanced_FindPath(map[], lkan[], 1, x, y, zx, zy)
                timekan=GETTIMERALL()-timekan
        ENDIF

        FOR i=0 TO AFP_mapmax_x-1       // Karte zeichnen
                FOR j=0 TO AFP_mapmax_y-1
                        IF (map[i][j])<=0 THEN DRAWRECT 10*i, 10*j, 10, 10, RGB(255,255,255)
                        ALPHAMODE 0.5
                        IF map[i][j]>1 THEN DRAWRECT 10*i, 10*j, 10, 10, RGB(128,128,128+20*map[i][j])
                        ALPHAMODE 0
                NEXT
        NEXT

        FOR i=1 TO LEN(lger)-1  // Gernots Weg einzeichnen
                DRAWLINE 10*lger[i-1][0]+4,  10*lger[i-1][1]+4,  10*lger[i][0]+4,  10*lger[i][1]+4, RGB(255,0,0)
                DRAWRECT 10*lger[i][0]+3,  10*lger[i][1]+3, 3, 3, RGB(255,0,0)
        NEXT

        FOR i=1 TO LEN(lkan)-1  // Kanonets Weg einzeichnen
                DRAWLINE 10*lkan[i-1][0]+3,  10*lkan[i-1][1]+3,  10*lkan[i][0]+3,  10*lkan[i][1]+3, RGB(0,255,0)
                DRAWRECT 10*lkan[i][0]+2,  10*lkan[i][1]+2, 3, 3, RGB(0,255,0)
        NEXT

        PRINT "A", 10*x, 10*y   // Startpunkt markieren
        PRINT "Z", 10*zx, 10*zy // Zielpunkt markieren

        PRINT "Gernot: "+timeger+"ms "+LEN(lger)+" Schritte", 0, 0
        PRINT "Kanonet: "+timekan+"ms "+LEN(lkan)+" Schritte", 0, 10

        PRINT "[SPACE] - Weg suchen         [Maustasten] - Start/Ziel/Karte verändern", 135, 590

        SHOWSCREEN

        WAIT(20)        // Timer

UNTIL KEY(1)
END



//! Timerfunction - NOT NEEDED FOR PATHFINDING!
//! Its just to slow down the program.
//? Timerfunktion - WIRD NICHT FÜR DIE WEGFINDUNG BENÖTIGT!
//? Dient ledglich dazu, dass Programm zu verlangsamen.
// \param ms - Mainloop will last ms milliseconds. | Hauptschleife wird ms Millisekunden dauern.
// \return Nothing. | Nichts.
FUNCTION WAIT: ms
        STATIC WAIT_time
        WAIT_time = ms - GETTIMERALL() + WAIT_time
        IF WAIT_time<0 THEN WAIT_time=0
        SLEEP WAIT_time
        WAIT_time=GETTIMERALL()
ENDFUNCTION

//! Initialise the pathfinding. Use it once, before your mainloop.
//? Initialisiert die Wegfindung. Muss einmal ausgeführt werden, am besten vor der Hauptschleife.
// \param AFP_map[] - Map that that will be used for pathfinding. | Karte die durch die Weg genutz werden soll.
// \param x,y  - Size of the Map, you want to create. | Größe der Karte, die erzeugt werden soll.
// \return Nothing, but some global will be set. | Nichts, jedoch werden einige Globals erzeugt.
FUNCTION Init_FindPath: AFP_map[], x, y
        GLOBAL AFP_mapmax_x=x
        GLOBAL AFP_mapmax_y=y
        LOCAL i%
        DIM AFP_map[AFP_mapmax_x][AFP_mapmax_y] // Karte dimensionieren
        // alle Felder der Karte auf 1 setzen, sie als passierbar machen
        SETCURRENTDIR("..")
        SETCURRENTDIR("..")
        SETCURRENTDIR("Bismarck")
        SETCURRENTDIR("Karte")
        OPENFILE(1, "karte2.txt", 1)
        READLINE 1, AFP_mapmax_y
        READLINE 1, AFP_mapmax_y
        FOR x=0 TO AFP_mapmax_x-1
                FOR y=0 TO AFP_mapmax_y-1
                        READBYTE 1, i%
                        AFP_map[x][y]=-2*(i-0.5)
                NEXT
        NEXT
        CLOSEFILE 1

        // "Bewegungsrichtung" zur Erstellung weiterer Knoten
        GLOBAL AFP_dirx%[], AFP_diry%[], AFP_dirz%[]
        DIMDATA AFP_dirx[], 0, 1, 0, -1, 1, 1, -1, -1
        DIMDATA AFP_diry[], -1, 0, 1, 0, -1, 1, 1, -1
        DIM AFP_dirz[8]
        FOR i=0 TO 7
                AFP_dirz[i] = (AFP_dirx[i] AND AFP_diry[i])+1
        NEXT

        // map dient der Ermittlung der Entfernung des jeweils aktuellen Knotens zu Ziel, vorausberechnung erfolgt um Geschwindigkeit gut zu machen
        GLOBAL AFP_heuristic%[]
        DIM AFP_heuristic[AFP_mapmax_x][AFP_mapmax_y]
        FOR y=0 TO AFP_mapmax_y-1
                FOR x=0 TO AFP_mapmax_x-1
                        AFP_heuristic[x][y]=SQR(x*x+y*y)
                NEXT
        NEXT
ENDFUNCTION

//! This function search a path.
//? Diese Funktion sucht einen Weg.
// \param Look FINDPATH() for details about the parameters! | Details der Parameter können unter FINDPATH() nachgesehen werden.
// \param AFP_map[] - Map, where you search a path. | Karte, durch die ein Weg gefunden werden soll.
// \param heuristik - 0=sortest 1=cheapest Way. | 0=kürzester 1=günstigster Weg.
// \param startx,starty - Startpoint. | Startpunkt.
// \param endx,endy - Destination. | Zielpunkt.
// \return Path length, or 0 if no path was found. | Weglänge, oder 0 falls kein Weg gefunden wurde.
FUNCTION Advanced_FindPath: AFP_map[], loesung[], heuristik, startx%, starty%, endx%, endy%

        REDIM loesung[0]

        // Validität der Parameter prüfen
        IF startx=endx AND starty=endy THEN RETURN 0
        IF endx<0 OR endy<0 OR endx>AFP_mapmax_x-1 OR endy>AFP_mapmax_y-1 THEN RETURN 0
        IF startx<0 OR starty<0 OR startx>AFP_mapmax_x-1 OR starty>AFP_mapmax_y-1 THEN RETURN 0
        IF AFP_map[endx][endy]<=0 THEN RETURN 0
        IF AFP_map[startx][starty]<=0 THEN RETURN 0
        IF heuristik<0 OR heuristik>1 THEN heuristik=1

        STATIC nodemap[]        // dient primär der Kennzeichnung bereits besuchter Felder
        REDIM nodemap[0]
        REDIM nodemap[AFP_mapmax_x][AFP_mapmax_y][2]

        STATIC path[] AS TNode  // Zwischenspeicher des gefundenen Wegs
        REDIM path[0]

        // Variablen mit der Endung -s gehören zur Suche von Start, Variablen mit der Endung -g gehören zur Suche vom Ziel
        STATIC x%, y%, finish%, cost%, delta%, nodezahls%, nodezahlg%
        finish=0; nodezahls%=0; nodezahlg%=0


        STATIC opens[] AS TNode // Openlists für noch zu untersuchende Knoten
        REDIM opens[1]
        STATIC openg[] AS TNode
        REDIM openg[1]
        STATIC topen AS TNode

        STATIC nodes[] AS TNode // Closedlists für abschließend untersuchte Knoten
        REDIM nodes[1]
        STATIC nodeg[] AS TNode
        REDIM nodeg[1]
        STATIC tnode AS TNode

        // Startpunktdaten einlesen
        opens[0].x = startx
        opens[0].y = starty
        opens[0].cost = 0
        opens[0].parent = -1
        nodemap[startx][starty][0] = 1

        // Zielpunktdaten einlesen
        openg[0].x = endx
        openg[0].y = endy
        openg[0].cost = 0
        openg[0].parent = -1
        nodemap[endx][endy][0] = 2

        REPEAT  // Wegsuche beginnen

                // Wegsuche ausgehend vom Startpunkt
                x = 0; cost = 2147483647
                FOREACH topen IN opens[]        // Ermittlet günstigsten Open-Knoten
                        delta = AFP_heuristic[ABS(topen.x-endx)][ABS(topen.y-endy)]
                        IF topen.cost+delta<cost
                                cost = topen.cost+delta
                                y = x
                        ENDIF
                        INC x
                NEXT
                tnode = opens[y]
                DIMPUSH nodes[], tnode  // übernimmt den Knoten in die Closedlist und löscht ihn aus der Openlist
                DIMDEL opens[], y
                INC nodezahls

                FOR i=0 TO 7    // Untersuchung der 8 benachbarten Knoten
                        x = tnode.x + AFP_dirx[i]
                        y = tnode.y + AFP_diry[i]
                        IF x>-1 AND y>-1 AND x<AFP_mapmax_x AND y<AFP_mapmax_y // Knoten liegt auf der Karte
                                IF AFP_map[x][y]>0 AND AFP_map[x][tnode.y]>0 AND AFP_map[tnode.x][y]>0  // Knoten ist begehbar
                                        IF nodemap[x][y][0]=0   // Knoten wurde noch nicht besucht
                                                topen.x = x
                                                topen.y = y
                                                topen.parent = nodezahls
                                                topen.cost = tnode.cost + heuristik * (AFP_map[x][y]-1)  + AFP_dirz[i]
                                                DIMPUSH opens[], topen  // erzeuge neuen Openknoten
                                                nodemap[x][y][0]=1
                                                nodemap[x][y][1]=nodezahls
                                        ELSEIF nodemap[x][y][0]=2       // Knoten wurde bereits durch die andere Suchroutine erreicht -> Suche erfolgreich
                                                topen.x = x
                                                topen.y = y
                                                topen.parent = nodezahls
                                                topen.cost = tnode.cost + heuristik * (AFP_map[x][y]-1)  + AFP_dirz[i] + nodeg[nodemap[x][y][1]].cost
                                                DIMPUSH path[], topen   // erzeuge neuen Openknoten
                                                finish = 1
                                        ENDIF
                                ENDIF
                        ENDIF
                NEXT

                IF NOT LEN(opens[]) THEN finish=3 // Wenn kein Openknoten mehr existiert -> keine Verbindung zwischen Start und Ziel möglich -> Suche abbrechen

                IF finish THEN BREAK

                // Wegsuche ausgehend vom Zielpunkt
                x = 0; cost = 2147483647
                FOREACH topen IN openg[]        // Ermittlet günstigsten Open-Knoten
                        delta = AFP_heuristic[ABS(topen.x-startx)][ABS(topen.y-starty)]
                        IF topen.cost+delta<cost
                                cost = topen.cost+delta
                                y = x
                        ENDIF
                        INC x
                NEXT
                tnode = openg[y]
                DIMPUSH nodeg[], tnode  // übernimmt den Knoten in die Closedlist und löscht ihn aus der Openlist
                DIMDEL openg[], y
                INC nodezahlg

                FOR i=0 TO 7    // Untersuchung der 8 benachbarten Knoten
                        x = tnode.x + AFP_dirx[i]
                        y = tnode.y + AFP_diry[i]
                        IF x>-1 AND y>-1 AND x<AFP_mapmax_x AND y<AFP_mapmax_y // Knoten liegt auf der Karte
                                IF AFP_map[x][y]>0 AND AFP_map[x][tnode.y]>0 AND AFP_map[tnode.x][y]>0  // Knoten ist begehbar
                                        IF nodemap[x][y][0]=0   // Knoten wurde noch nicht besucht
                                                topen.x = x
                                                topen.y = y
                                                topen.parent = nodezahlg
                                                topen.cost = tnode.cost + heuristik * (AFP_map[x][y]-1)  + AFP_dirz[i]
                                                DIMPUSH openg[], topen  // erzeuge neuen Openknoten
                                                nodemap[x][y][0]=2
                                                nodemap[x][y][1]=nodezahlg
                                        ELSEIF nodemap[x][y][0]=1       // Knoten wurde bereits durch die andere Suchroutine erreicht -> Suche erfolgreich
                                                topen.x = x
                                                topen.y = y
                                                topen.parent = nodemap[x][y][1]
                                                topen.cost = tnode.cost + heuristik * (AFP_map[x][y]-1)  + AFP_dirz[i] + nodes[topen.parent].cost
                                                DIMPUSH path[], topen   // erzeuge neuen Openknoten
                                                nodemap[x][y][0]=2
                                                nodemap[x][y][1]=nodezahlg
                                                finish = 1
                                        ENDIF
                                ENDIF
                        ENDIF
                NEXT

                IF NOT LEN(openg[]) THEN finish=3 // Wenn kein Openknoten mehr existiert -> keine Verbindung zwischen Start und Ziel möglich -> Suche abbrechen

        UNTIL finish    // Wegsuche beendet

        IF finish=3 THEN RETURN 0       // es wurde kein Weg gefunden

    x = 0; y=0; cost = 2147483647
        FOREACH topen IN path[] // Ermittlet günstigsten Open-Knoten
                IF topen.cost<cost
                        cost = topen.cost
                        y = x
                ENDIF
                INC x
        NEXT
        topen = path[y]
        cost=topen.parent
        delta=nodemap[topen.x][topen.y][1]
        REDIM path[0]
        DIMPUSH path[], topen

        tnode = nodes[cost]     // gefundenen Pfad vom Startpunkt aus auswerten
        WHILE tnode.parent <> -1
                DIMPUSH path[], tnode
                tnode = nodes[tnode.parent]
        WEND
        DIMPUSH path[], tnode
        REDIM nodes[0]

        cost = LEN(path[])
        REDIM loesung[cost][2]
        FOR i=cost-1 TO 0 STEP -1
                loesung[i][0] = path[cost-i-1].x
                loesung[i][1] = path[cost-i-1].y
        NEXT
        REDIM path[0]

        IF nodezahlg    // gefundenen Pfad vom Zielpunkt aus auswerten
                tnode = nodeg[delta]
                WHILE tnode.parent <> -1
                delta=tnode.parent
                        DIMPUSH path[], tnode
                        tnode = nodeg[tnode.parent]
                WEND
                DIMPUSH path[], tnode
                REDIM nodeg[0]

                delta = cost+LEN(path[])
                REDIM loesung[delta][2]
                FOR i=delta-1 TO cost STEP -1
                        loesung[i][0] = path[i-cost].x
                        loesung[i][1] = path[i-cost].y
                NEXT
                REDIM path[0]
        ENDIF

        RETURN delta

ENDFUNCTION

// Knoten, ein (möglicher) Schritt zum Ziel
TYPE TNode
        cost%   // bisherige Wegkosten
        parent% // ID des Vorgängerknotens
        x%
        y%
ENDTYPE

12
Bug Reports / Licht/Schatten in 3d/ES
« on: 2010-Dec-11 »
Hallo,

habe hier mal ein kleines Testprojekt um ein paar Probleme zu dokumentieren, auf die ich gestoßen bin. Das Bild zeigt was ich meine:

1. Die gesamte Szene ist zu dunkel. Der Untergrund bspw. ist eigentlich weiß! Wenn ich kein Licht erzeuge ist alles ok, d.h. hell, erzeuge ich aber ein Licht (z.B. um Schatten erzeugen zu können), ist es so dunkel wie im Bild. Vermutlich ist das kein Bug, sondern nur ein Fehler meinerseits? Bitte um Hilfe.
2. Der Schattenwurf ist vollkommen falsch, es wirkt als würde das Licht viel niedriger hängen, als es hängt. Mir ist aufgefallen, dass dies nur bei skaliertem Mesh auftritt, behalte ich die Ursprungsgröße bei, sind die Schatten korrekt.
3. Eine "Lücke" im Schatten. Ich habe keine Ahnung, wie das kommt, aber mir ist folgendes aufgefallen: importiere ich das Objekt aus .md2 oder .obj tritt diese Lücke (und andere Fehler) auf, importiere ich aus .3ds gibt es diese Lücke nicht. Möglicherweise ein Fehler im 3d-Converter?

Beispielprojekt ist angehangen.

Vielen Danke.

Pages: [1]