EntityHidden(), BufferWidth()...lotsa new commands

Blitz3D Forums/Blitz3D Programming/EntityHidden(), BufferWidth()...lotsa new commands

JoshK(Posted 2004) [#1]
This will increase the functionality of Blitz3D:
http://www.leadwerks.com/files/blitz3dlib.zip

New commands:

;Entity
EntityHidden%(entity)
NextEntity%(entity)
LastEntity%(entity)
EntityX_#(entity)
EntityY_#(entity)
EntityZ_#(entity)
EntityOriginX#(entity)
EntityOriginY#(entity)
EntityOriginZ#(entity)
PositionEntity_(entity,x#,y#,z#)
TranslateEntity_(entity,x#,y#,z#)
AlignEntity(entity1,entity2)
EntityScaleX#(entity)
EntityScaleY#(entity)
EntityScaleZ#(entity)
GetEntityFX%(entity)
GetEntityOrder%(entity)
GetEntityRadius#(entity) : "GetEntityRadiusX"
GetEntityRadiusY#(entity)
GetEntityBoxX#(entity)
GetEntityBoxY#(entity)
GetEntityBoxZ#(entity)
GetEntityBoxWidth#(entity)
GetEntityBoxHeight#(entity)
GetEntityBoxDepth#(entity)
EntityMoved%(entity)

;Camera
GetCameraZoom#(entity)
GetCameraViewportX%(entity)
GetCameraViewportY%(entity)
GetCameraViewportWidth%(entity)
GetCameraViewportHeight%(entity)
CameraRangeFar#(camera)

;Texture
GetTextureFlags%(texture)
GetTextureBlend%(texture)
GetTextureCoords%(texture)
GetTextureScaleU#(texture)
GetTextureScaleV#(texture)
GetTexturePositionU#(texture)
GetTexturePositionV#(texture)
GetTextureAngle#(texture)

;Brush
GetBrushFX%(brush)
GetBrushShininess#(brush)
GetBrushAlpha#(brush)

;Graphics
BufferWidth%(buffer)
BufferHeight%(buffer)
BufferDepth%(buffer)


REDi(Posted 2004) [#2]
Great job halo, very handy indeed.

BTW I think you would be allowed to release these in a compiled DLL.

Quote from http://www.purebasic.com/faq.php3

Is it allowed to use DLLs made with PureBasic in other projects ?

Generally yes. You can make DLLs including PureBasic commands for your own projects without any restrictions. But it's not allowed to release simple "wrapper" Dlls to include PureBasic commands in other programming languages.



You are not wrapping "Purebasic commands" here, you are creating your own :)

AFAIK This is what your not allowed to do... "simple wrapper"
ProcedureDLL.l _PeekL(address.l)
   ProcedureReturn PeekL(address.l)
EndProcedure

as it just wraps Purebasics own commands.


REDi(Posted 2004) [#3]
Damn that was quick ;)


CyberHeater(Posted 2004) [#4]
awesome...


Pinete(Posted 2004) [#5]
It seems a fantastic addition!
Please, Could someone explain me how to introduce these
commands in Blitz3D and the way to call them?
Is like the rest of the functions?

Thanks in advance!


_PJ_(Posted 2004) [#6]

EntityHidden%(entity)
NextEntity%(entity)
LastEntity%(entity)



Wooo!!! That's enough for me! Im totally grateful already :)


Genexi2(Posted 2004) [#7]
I wonder why Mark couldnt have did half of those for us natively in Blitz....either way, nice job there Halo. :)

Startin to really like those texture commands there......

Pin, you gotta unpack the decls file and the dll to the b3d\userlibs folder, and make sure that blitz3d.dll has that folder its in in the packed file, or else you'll have to edit the directory of the dll in the decls file.


JoshK(Posted 2004) [#8]
It's pretty cool that you can sort through the entities...they are linked lists.

EntityExists() is also possible.


Eole(Posted 2004) [#9]
Great Job !

Thank a lot


Ross C(Posted 2004) [#10]
Hey Halo, What is the point of:

EntityX_#(entity)
EntityY_#(entity)
EntityZ_#(entity)

Aren't they just the EntityX() y and z blitz commands?

Very nice lib though, i'm gonna use it. Thanks :)


JoshK(Posted 2004) [#11]
It's more for writing commands in a DLL, like a physics system or something that directly accesses the matrices.


JoshK(Posted 2004) [#12]
Here is a cool one:
Function FirstEntity()
p=CreatePivot()
Repeat
	p=LastEntity(p)
	Until Not LastEntity(p)
Return p
End Function


Use it like this:
entity=FirstEntity()
While entity
	Select EntityName(entity)
		Case "Monster" UpdateMonster entity
		End Select

	entity=NextEntity(entity)
	Wend



JoshK(Posted 2004) [#13]
Here's another. Associate a bank with an entity to store special parameters:

Function EntityBank(entity)
bank=PeekL(entity+240)
If bank=1065353216
	bank=CreateBank()
	PokeL entity+240,bank
	EndIf
Return bank
End Function



N(Posted 2004) [#14]
Wow, these're suprisingly useful. Thank you very much, halo.

I could see the Next/LastEntity procedures being used to write a basic garbage collector.


AntonyWells(Posted 2004) [#15]
I downloaded textureCoords one before Halo, when you originally psoted it. Is this the same code? If so, it doesn't work.

It either returns 0 or some very high number. Would be a nice function to have, is why I'm pointing it out.

Nice work with the other stuff though.


Jager(Posted 2004) [#16]
Now for the dumbies .. can we have a description for each command to see how useful they are? Maybe how they differ from similar BB3d Commands?

One thing that really annoys me about BB3D is lists of types nested within other types are all globals! eg

Type soldier
....
End type

Type BattleUnit
field unitsoldier.soldier
end type

If one was to loop through all the unitsoldiers in a unit, you'd hope to only see soldiers for that unit but no, we get the lot. A if condition has to added.

Any chance of adding a command to get rid of this annoying feature? :) (joking, just having a whinge)

Apart from the above feature, I'm finding BB3D an excellent language to develop my wargame, thanks!


Ziltch(Posted 2004) [#17]
>EntityExists() is also possible.

After all the reasons posted , thread after thread explaining why we could never have this command!

A lesson to all the people that said it could not be done!

Thanks for helping to keep Blitz3d growing.


N(Posted 2004) [#18]
Here's one:

Graphics3D 800,600,32,2

Function GetEntity(Name$)
	Local P,Entity
	P = CreatePivot()
	Entity = P
	While LastEntity(Entity) <> 0
		Entity = LastEntity(Entity)
	Wend
	
	While NextEntity(Entity) <> 0
		Entity = NextEntity(Entity)
		If EntityName(Entity) = Name$ Then
			FreeEntity P
			Return Entity
		EndIf
	Wend
	
	FreeEntity P
	Return 0
End Function

For N = 0 To 31
	C = CreateCube()
	If N = 13 Then
		NameEntity C,"Google"
		D = C
	EndIf
Next

Print EntityName(D) + "  " + D
Print EntityName(GetEntity("Google")) + "  " + GetEntity("Google")

WaitKey


And a variant on that, which is a basic EntityExists():

Function EntityExists(Exists)
	Local P,Entity
	P = CreatePivot()
	Entity = P
	While LastEntity(Entity) <> 0
		Entity = LastEntity(Entity)
	Wend
	
	While NextEntity(Entity) <> 0
		Entity = NextEntity(Entity)
		If Entity = Exists Then
			FreeEntity P
			Return True
		EndIf
	Wend
	
	FreeEntity P
	Return False
End Function


Just trying to put these to use.


AbbaRue(Posted 2004) [#19]
These new commands look awsome, but how does one use them.
I get userlib not found error.
Can someone give me a blitz3D program example that works with some of these new commands?


JoshK(Posted 2004) [#20]
Here's another:

#BLITZ_CAMERAFLAGS=608

ProcedureDLL.l GetCameraClsMode(*entity,mode)
flags=PeekL(*entity+#BLITZ_CAMERAFLAGS)
Select mode
Case 0
If (1 & flags)
ProcedureReturn 1
EndIf
Case 1
If (256 & flags)
ProcedureReturn 1
EndIf
EndSelect
EndProcedure


Why isn't this thread sticky?


DJWoodgate(Posted 2004) [#21]

Why isn't this thread sticky?



Probably because its very easily broken by a future update. (Unless the structures are going to be set in stone which seems a bit unlikely). All this stuff should really be available in Blitz. But that's probably whistling down the wind, so keep up the good work!

Abarue, you probably get userlib not found because Halo sticks his DLLs in a subdir. So you did not extract with paths to Blitz3d\userlibs. Alternatively just alter the decls header.


JaviCervera(Posted 2004) [#22]
This is awesome


JoshK(Posted 2004) [#23]
If the Blitz structures change, all you have to do is update the constants.


AbbaRue(Posted 2004) [#24]
Thanks DJWoodgate That is what was wrong, the decls header used a subdirectory.
I keep all my DLLs in the main userlibs folder.


DJWoodgate(Posted 2004) [#25]

If the Blitz structures change, all you have to do is update the constants.



I suppose so. In any event I guess these structures are not likely to change anytime soon.

Getting into the spirit of things then the Camera Cls colors are floats at 596,600,604. Multiply by 255 to get the Integer equivalent.

Ditto camera fog colors at 616,620,624
Camera fog range floats at 628,632
Camera fog mode at 636

Camera Near is a float at 640. Do not write to this or Camerazoom, it will not have the desired effect.There are a whole raft of matrix calculations done when blitz changes these values itself, which are not fired if you modify them directly. The matrix values produced seem to occur between about 648 and 844.

NextEntity, LastEntity should perhaps be called NextSibling, PrevSibling.

Parent is at +12
Firstchild is at +16
LastChild is at +20

Entityname (if one is defined) is addressed at entity+32
Stored as a packed array of bytes, low to high order, zero terminated, with length at entity+36

There are three transform matrices stored as floats in the entity structure, the first extends from +88-132 in col,row order. This seems to be the the local transform matrix and modifcations to this require setting the entityrefesh flag as Halo calls it at +44. Perhaps better called the transform flags. Writes are possible but not always actioned. Still looking into this.
The second is stored from +176-220 and is based on the first but modified by the parents transforms in some way. You can write this, but there is not much point because it will be overwritten by the parents values.
The third is stored at 516-560 and in my tests so far seems to be a copy of the second matrix. I suspect these are the values returned by the GetMatElement function, and these can not be written to so blitz must be modifying them continously.


DJWoodgate(Posted 2004) [#26]
BTW. I doubt EntityExists is as straightforward as some are proposing. As far as I can see there is no guarantee that a particular memory address will remain unique. All you can say is that there is an entity at a given adress, it may or may not be the original one, though I suspect it will be of the same class. So some additional management is required, as was always the case.


JoshK(Posted 2004) [#27]
Entity exists tells you whether the specified address indicates a valid entity. Whether or not the entity is the one you happen to be thinking of at the time is, of course, out of the scope of the function.

'Sibling' implies a hierarchel organization, when there is none here.


JaviCervera(Posted 2004) [#28]
GetTextureFlags() does not work correctly for me, using Blitz3D 1.87


JoshK(Posted 2004) [#29]
That's what you get, when you get it for free. There's no reason not to poke around in it yourself.


DJWoodgate(Posted 2004) [#30]

'Sibling' implies a hierarchel organization, when there is none here.



Yes there is. That's why I implied it. Your NextEntity and LastEntity functions follow links to the next and previous entities at the same level in the hierarchy.

To continue...

Light values are encoded in another structure addressed at light+576:
Lighttype Int at +0 (1=Point, 2=Spot, 3=directional) (yes, you can write this location).
Lightcolors are floats at +4,8,12,16 (RGBA) (These are the diffuse values in DirectX speak)
Light Global x,y,z position is stored at +52,56,60
Lightrange is a float at +88 stored as 1.0/lightrange.
lightconeangles are floats at +96,100 stored as radians. (multiply by 57.2957795 to get degrees)

This structure merits further investigation...

Light rotation effects floats at +64,68,72. I suspect these values are in fact the lights normalized global direction vector in x,y,z.

The float at +76 seems to control the maximum range of the light (for point and spot lights). This is not at all like LightRange (or the other attenuation parameters mentioned below) which define how the light falls off, this defines where the light stops altogether. Quite a useful one.

Additional attenuation parameters seem to be stored as floats at +84 and +92 though they are always zero by default. I suspect they correspond to the Constant and Quadratic attenuation terms in the lighting equation, so LightRange itself just alters the Linear term. (Try values between 0 and 1 for the Constant term and between 0.001 and 0.02 for the quadratic term).

There is another float at +80 which seems to alter the attenuation for spotlights in some way. I suspect it changes the the way light falls off between the inner and outer angles. (see article referenced below)

The values at +20,24,28,32 are floats that store the specular color of the light (RGBA). (lets you change the color/intensity of those nice shiny highlights enabled by EntityShininess)

The values at +36,40,44,48 are floats that define the ambient light level. (it seems you can specify an ambient light level for each light, as well as an overall ambient level in DX7)

Diffuse, ambient and specular colors all have an alpha component. I just need to figure out how to use them. They probably have limited applicability.

You can achieve some interesting results by tweaking some or all of these additional parameters. Shame they are not available natively because they all seem fully functional.

This article explains what is available DirectX wise. Yeah its DX8 but most of it seems to be applicable to DX7.
http://www.andypike.com/tutorials/directx8/007.asp
Then of course there is MSDN... http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndir3d/html/dx7light.asp

Might have a "poke" around on the materials side of things next.


JoshK(Posted 2004) [#31]
No they don't. They go through all the entities that exist, in the order they were created, regardless of hierarchy.


sswift(Posted 2004) [#32]
"GetTextureFlags() does not work correctly for me, using Blitz3D 1.87"

As nice as some of these commands may be you should know what there's a chance they will break with each new version of Blitz released.


Beaker(Posted 2004) [#33]
sswift - try and read the thread before posting! :)


DJWoodgate(Posted 2004) [#34]

No they don't. They go through all the entities that exist, in the order they were created, regardless of hierarchy.



Well they clearly link only to siblings here. Could you post some code showing how you achieve sequential access. I need some basis for comparison. Hmmm. Unless you have updated the DLL to change their behaviour? Because Entity+4 and Entity+8 are the sibling links. Parent and child links are also available as mentioned above. If you are only using +4,8 then maybe things have changed.


[edit]
It's now pretty obvious your code is based on an old version. My info is based on 1.87. For some obscure reason I choose to use the latest version. But I guess I would be reluctant to upgrade if I had a lot of code in production based on these sort of hacks, because it is no five minute job uncovering changes in structures/methods. (Another warning to the unwary). Anyways, ignoring the potential inconveniences...

EntityAutofade values floats at +604,608 (for meshes)
Autofade flag int at +600 (1 if autofade enabled).
Number of surfaces int at +648

Entitycolor, Shininess, FX etc
Brush Stuctures are addressed at entity+580 and 584.
In my tests so far they both address the same structure, unless entityautofade is enabled.
The address changes between 2 or more locations, probably to support tweening and autofade. In that respect the address at +584 may yield more accurate results in respect of current alpha.
setting the byte at entity+588 refreshes the entity with the contents of this structure.
The brush structure is described below. Note the structure is linked directly, there is no offset+0 address.
........................

A brush structure is addressed at brush+0
BrushBlend is an int at +4
Highest Texture layer used is an int at +8
Brushcolor are floats at +16,20,24. These relate to the diffuse colors.
BrushShininess is a float at +28
Brushalpha is a float at +32
BrushFX is an int at +40
I have not found a way to manipulate Ambient or specular colors yet or even know where they are stored. I expect blitz just hardwires them as it does the emmisive colors when you use fx 1.


For each texture layer 2 texture structs are addressed
The first at +44,60,76,92,108,124,140,156
The second at +172,176,180,184,188,192,196,200
In the first structure addressed at +44 etc (which is the texturebuffer structure)...
TextureFlags are stored in an int at +0 (see note below).
buffer width and height and depth are ints at +92,96,100
The second struct address is also the struct addressed at Texture+0 (See below)

............

A Texture structure is addressed at texture+0
TextureBlend at +24
TextureCoords at +28.
TextureScale at +36,40
TexturePosition at +44,48
textureRotation at +52
Transform matrix floats stored at +60,64,68,72,76,80,84,88
Xscale at 60, Xskew at 64, Yskew at 72, Yscale at 76, Xoffset at 84, Yoffset at 88.
Setting the bytes at +56,57 to 1 "activates" these values.
Another struct addressed at +4
In this struct the texture name string is addressed at +8 and the length of this string is at +12

Have not found textureflags reliably yet though, this structure is a bit exotic. [edit] OK, Found them...

Note: Texture Flags are stored in the Int at texturebuffer+0. Bit 13 (4096) is always set (for whatever reason). If bit 3 (masking) is set then bits 1 and 2 will also be set. Texturebuffer+104 is set to 4 if the texture is masked otherwise it is set to 2. I suspect some of the Ints that follow this relate to pixel format and masks, but I have not figured those out yet, that is a whole other ball game.


sswift(Posted 2004) [#35]
"sswift - try and read the thread before posting! :)"

Read an entire thread full of Halo? No thanks!


JoshK(Posted 2004) [#36]
This guy is so creepy.


JoshK(Posted 2004) [#37]
Seems like my texture offsets are all wrong. I don't know if they were ever right, because I never really used them.

I am trying to write a texture shader userlib, where you just call CreateShader(texture), set some properties, then call UpdateShaders() before each render. Anyone know where the texture position, scale, and rotation are stored? This would be a really cool way to have all the q3a shaders, and it would be largely automated. Mark?


DJWoodgate(Posted 2004) [#38]

If the Blitz structures change, all you have to do is update the constants.
....
Seems like my texture offsets are all wrong. I don't know if they were ever right, because I never really used them.



See above.


JoshK(Posted 2004) [#39]
Ha...I found them, sucka.

Proceduredll.f TextureU(texture)
texture=PeekL(texture)
ProcedureReturn -PeekF(texture+44)
EndProcedure

ProcedureDLL.f TextureV(texture)
texture=PeekL(texture)
ProcedureReturn -PeekF(texture+48)
EndProcedure

ProcedureDLL.f TextureScaleU(texture)
texture=PeekL(texture)
ProcedureReturn (1.0/PeekF(texture+36))
EndProcedure

ProcedureDLL.f TextureScaleV(texture)
texture=PeekL(texture)
ProcedureReturn (1.0/PeekF(texture+40))
EndProcedure

ProcedureDLL.f TextureAngle(texture)
texture=PeekL(texture)
ProcedureReturn (-360.0*PeekF(texture+52))/2.0/3.14159265
EndProcedure


DJWoodgate(Posted 2004) [#40]
Well done ;)


JoshK(Posted 2004) [#41]
Hey anyone know where the vertex bones are in the surface structure? The vertices are just a buffer at an offset at surf+28, and I can find all the other vert values, but...


JoshK(Posted 2004) [#42]
SURFACE_VERTEXARRAY=28
-stores vertex data
-vertices are 64-byte structures

x=0
y=4
z=8
nx=12
ny=16
nz=20
RGBA=24
u0=28
v0=32
u1=36
v1=40

And then 44-60 are mystery values. What could they be? 44, 52, and 60 appear to be pointers. 48 and 56 are equal to 0. Bones must be in there somewhere, but what are these other values?


SURFACE_TRIANGLEARRAY=44
-triangles are stored as shorts in this array


DJWoodgate(Posted 2004) [#43]
I have updated my post above with additional information I have found for the Light structure for those who might be interested. Once again though I would not recommend using these in anger because these locations may well change. Nice to see all this functionality is lurking beneath the surface though, doncha think?


Ice9(Posted 2004) [#44]
You may be able to do this without the pb .dll
by using the kernel32.dll

Here's the old thread.
http://www.blitzbasic.com/Community/posts.php?topic=27669


DJWoodgate(Posted 2004) [#45]
In fact I have been using the Blitzmem dll posted by ZJP as part of his excellent realtime image processing submission.

http://www.blitzbasic.co.nz/Community/posts.php?topic=34301


Panno(Posted 2004) [#46]
thats so cool
dont try this at home !


Ziltch(Posted 2004) [#47]
I am trying to get an EntityFX value but am having no luck.
The offset of 724 mentioned above I guess is for an older version of blitz.

Has anyone figured out how to retrieve it?


DJWoodgate(Posted 2004) [#48]
I think it can be accessed via a brush structure addressed at 580 or 584. See my earlier post above.


Ziltch(Posted 2004) [#49]
Thanks David , once again!
I got the EntityFx info from brush at 584 offset 40.


ryan scott(Posted 2004) [#50]
just found this - it sure looks good.

no docs so a few questions:

a little confusion with PositionEntity_ what is the reason for this? same as EntityX_ (the answer to which seems to be, if you aren't writing dlls, you don't need to know)

Is there any easy way to SET the origin? (other than messing with FitMesh or PositionMesh? PositionOrigin makes more sense)

Does entitymoved tell you if it was moved since the last time you checked entitymoved, or the last updateworld, or what?


alignentity, does it simply put them right on top of each other, and same rotation?

I'm not asking for the world for free, but would be nice to not have to guess quite so much!


DrakeX(Posted 2004) [#51]
ooooooooooomgomgomgomgomg i love you halo. these commands round out the missing holes in B3D that have annoyed me for a year, the missing "get" counterpart commands. thank you so much :)

i tried to decipher what all that junk at entity pointers meant, but i just didn't get it. you rock!


Jeremy Alessi(Posted 2004) [#52]
Sweet!


Maxus(Posted 2006) [#53]
What format MD2 models in the memory Blitz3D?


CakeMonitor(Posted 2006) [#54]
I need BufferWidth() and BufferHeight() functions, but this download link is broken.

Anyone know where I can get the lib (or and alternative one which provides the BufferWidth() and BufferHeight() functions)?


Thanks


@rtur(Posted 2006) [#55]
ProcedureDLL BufferWidth(buffer)
ProcedureReturn PeekL(buffer+92)
EndProcedure

ProcedureDLL BufferHeight(buffer)
ProcedureReturn PeekL(buffer+96)
EndProcedure

ProcedureDLL BufferDepth(buffer)
ProcedureReturn PeekL(buffer+100)
EndProcedure


CakeMonitor(Posted 2006) [#56]
ProcedureDLL ?
PeekL() ?

Are we both talking Blitz3D here?
I haven't downloaded any DLL as the link is broken. Do I need to have bought PureBasic for this stuff to work?


I assume in Blitz3D I would use PeekInt() instead of PeekL() to read 4 bytes from a memory bank, but how do I get it to treat a graphics buffer as a bank?

PeekInt(GraphicsBuffer(),92) does not work.

Thanks again


CakeMonitor(Posted 2006) [#57]
ok, nevermind.

I found me10afull.zip on the Leadwerks website and it has all the DLLs and decals I need.


Kalisme(Posted 2006) [#58]
Where can I find it?


bytecode77(Posted 2006) [#59]
the link is broken :(...
can you giv it to me or can you may activate the link up there?
please!


Pinete(Posted 2006) [#60]
hi,
give me your mail address and I will send to you
:)

regards,


Steven Noyce(Posted 2006) [#61]
Can you e-mail it to me also? Blitznerd@...


Pinete(Posted 2006) [#62]
sent.. sorry for the delay!
:)


Red Ocktober(Posted 2006) [#63]
very generous josh...

kudos to you for a nice job as well...

--Mike


Naughty Alien(Posted 2006) [#64]
hey Pinete, can you email me too xyboots@...


bytecode77(Posted 2006) [#65]
my email is in my signature..just click onto my name!


bytecode77(Posted 2006) [#66]
ok, thx...
i have put the libs into the userlibs folder and started my program...but he didn't find the functions :(...


jfk EO-11110(Posted 2006) [#67]
This surely can be done with onboard libraries only, like the kernel32.dll.

It was explained here:
http://www.blitzbasic.com/Community/posts.php?topic=57663
GetBrushAlpha() was used as an example

EDIT 2: Man I am such a fool, this thread is 2 years old! x_x


bytecode77(Posted 2006) [#68]
thx:)

ps: this thread isnt 2 years old! one year before a few posts have been written here and a few days before :) so u can say that you are not a fool, indeed :D


Kalisme(Posted 2006) [#69]
if anyone can send it to me... YAY! :D
my Email is: kalisme@...


Panno(Posted 2006) [#70]
here to please : POWERASM1@...


Naughty Alien(Posted 2006) [#71]
..I have this lib somewhere on archive disc..if you buy me a beer I'll do it for ya :))


Billp(Posted 2006) [#72]
Wrote a couple of function using the camera viewport commands and thought someone might find useful, it records frames from the camera passed to it and saves them as an AnimImage.

Theses functions require Leadwerks blitz3d.dll and decls
The example is the bouncing ball demo from blitz

the Animation in this example is saved in the current directory as "temp.bmp"



Mikele(Posted 2006) [#73]
blitz3dlib