So piss on the many who already supported your shadow system by purchasing? doh..
I'm not pissing on anyone. You knew what you were getting when you purchased it, and that's precisely what I provided you with. I never promised that I would keep optimizing the code forever, day in and day out. There's a million ways I could optimize this system, and many of the others I have.
The simple fact is, I can't AFFORD to spend time on something which isn't going to bring in any revenue. If I work on this all week, then I'm NOT working on something else which might actually bring in some real money. I won't be developing ANYTHING if I don't have a steady source of income here soon.
I understand as well that "working forever for free" on it makes little sense when the engine you wrote it for is on its last breaths
Yes, that too. I'm quite frankly surprised that as many people emailed me as they did asking for the update. I thought most Blitz users had given up on Blitz3D.
but I am wondering why to spend some money while at the same time the author says that he can make his product better but he just don't want to do it.
Whether I optimize the systems further or not doesn't change the state they are in right now. You should not purchase a product under the expectation that it will do what you want at some point in the future. You should buy it if it meets your needs right now.
Also, keep in mind that most companies CHARGE for updates. Photoshop, 3D Studio Max... Anything used by commercial developers who expect there to be updates, those updates COST MONEY.
I don't charge for updates. And yet here I am, making an update for a product which doesn't even sell one copy a month, years after release, FOR FREE, and you're complaining because I admitted that I don't have time to spend two weeks making a complete overhaul of the shadow system? The thing makes so little money I've considered GIVING IT AWAY FOR FREE. The only reason I haven't yet is because I still don't have some major product on the market which is bringing in a decent amount of revenue for me, so $20 every month or so is still welcome... but not nearly enough to justify major changes to a system which will become obsolete the second Mark releases BlitMax 3D.
Also the reason I even mentioned that I could optimize the system is to let people know that it is possible for you to optimize it yourself if you really need that speed.
Here, I'll even show you how:
; -------------------------------------------------------------------------------------------------------------------
; This function sets a mesh as being capable of receiving a shadow.
;
; Animated meshes cannot receive shadows because Blitz does not return the current locations of it's vertices, it
; returns the locations of them in the model's default pose.
;
; Remember that while you can position the entity receving a shadow, you CANNOT scale or rotate it.
;
; If you need to scale or rotate your receiver, you'll have to scale or rotate the whole mesh before you set it to
; receive shadows. And if you want to change that scale or rotation at any time, you will need to disable it and then
; reenable it after making the change.
;
; Another important thing to note is that children of an entity receiving shadows will not automatically receive
; shadows themselves. You must set each entity to recieve shadows individually.
;
; Lastly, all shadow casting objects will cast shadows onto all objets marked as receivers.
;
;
; *** BELOW NOT YET IMPLEMENTED ***
;
; Dot# is a parameter which lets you exclude polygons which aren't facing up.
; This can greatly speed up shadow rendering and save you the effort of building special models specifically for casting shadows onto.
;
; Dot# works as follows:
;
; A dot product is done with the polygon's normal and a normal which points up.
;
; If the two vectors point in the same direction, the dot product will be 1. Therefore specifying a Dot# of 1 will include only those polygons which face straight up.
; If the two vectors point in opposite directions, the dot product will be -1. Therfore specifying a Dot# of -1, which is the default, will include all polygons.
; If the two vectors point 90 degrees to one another, the dot product will be 0. Therefore specifying a Dot# of 0 will include floors and walls, but not ceilings.
;
; You may specify a value for Dot# which is any of these values or any value between them. And because of floating point inaccuracies, if you want to include only
; floors, you should probably set Dot# to be a little less than 1, like 0.99 or something. Otherwise some floor tiles which look like they're on the horizontal plane may be missed.
; -------------------------------------------------------------------------------------------------------------------
Function Receive_Shadow(Receiver, Group=0, Dot#=-1)
Local ThisReceiver.Shadow_Receiver
Local Surfaces, Vertices, Tris
Local LOOP_Surface, LOOP_Verts
Local Surface_Handle, Surface
Local Min_X#=$FFFFFFF, Max_X#=-$FFFFFFF
Local Min_Y#=$FFFFFFF, Max_Y#=-$FFFFFFF
Local Min_Z#=$FFFFFFF, Max_Z#=-$FFFFFFF
Local Vx#, Vy#, Vz#
Local Vertex, Tri, FirstVertex
ThisReceiver = New Shadow_Receiver
ThisReceiver\Entity = Receiver
; Count the number of vertices and triangles in the receiver.
Surfaces = CountSurfaces(ThisReceiver\Entity)
For LOOP_Surface = 1 To Surfaces
Surface = GetSurface(ThisReceiver\Entity, LOOP_Surface)
Vertices = Vertices + CountVertices(Surface)
Tris = Tris + CountTriangles(Surface)
Next
ThisReceiver\Vertices = Vertices
ThisReceiver\Tris = Tris
; Create the banks needed to store the vertex and triangle data for this receiver.
; Floats
ThisReceiver\Bank_Vx = CreateBank(Vertices*4)
ThisReceiver\Bank_Vy = CreateBank(Vertices*4)
ThisReceiver\Bank_Vz = CreateBank(Vertices*4)
ThisReceiver\Bank_Vnx = CreateBank(Vertices*4)
ThisReceiver\Bank_Vny = CreateBank(Vertices*4)
ThisReceiver\Bank_Vnz = CreateBank(Vertices*4)
; Longints
ThisReceiver\Bank_TriV0 = CreateBank(Tris*4)
ThisReceiver\Bank_TriV1 = CreateBank(Tris*4)
ThisReceiver\Bank_TriV2 = CreateBank(Tris*4)
; Store the vertex and triangle data.
Surfaces = CountSurfaces(ThisReceiver\Entity)
For LOOP_Surface = 1 To Surfaces
Surface = GetSurface(ThisReceiver\Entity, LOOP_Surface)
Vertices = CountVertices(Surface)
For LOOP_Verts = 0 To Vertices-1
PokeFloat ThisReceiver\Bank_Vx, Vertex*4, VertexX#(Surface, LOOP_Verts)
PokeFloat ThisReceiver\Bank_Vy, Vertex*4, VertexY#(Surface, LOOP_Verts)
PokeFloat ThisReceiver\Bank_Vz, Vertex*4, VertexZ#(Surface, LOOP_Verts)
PokeFloat ThisReceiver\Bank_Vnx, Vertex*4, VertexNX#(Surface, LOOP_Verts)
PokeFloat ThisReceiver\Bank_Vny, Vertex*4, VertexNY#(Surface, LOOP_Verts)
PokeFloat ThisReceiver\Bank_Vnz, Vertex*4, VertexNZ#(Surface, LOOP_Verts)
Vertex = Vertex + 1
Next
Tris = CountTriangles(Surface)
For LOOP_Tris = 0 To Tris-1
PokeInt ThisReceiver\Bank_TriV0, Tri*4, FirstVertex + TriangleVertex(Surface, Loop_Tris, 0)
PokeInt ThisReceiver\Bank_TriV1, Tri*4, FirstVertex + TriangleVertex(Surface, Loop_Tris, 1)
PokeInt ThisReceiver\Bank_TriV2, Tri*4, FirstVertex + TriangleVertex(Surface, Loop_Tris, 2)
Tri = Tri + 1
Next
FirstVertex = FirstVertex + Vertices
Next
; Find the minimum and maximum extents of the reciever on each axis.
; Surfaces = CountSurfaces(ThisReceiver\Entity)
; For LOOP_Surface = 1 To Surfaces
; Surface_Handle = GetSurface(ThisReceiver\Entity, LOOP_Surface)
; Verts = CountVertices(Surface_Handle)
; For LOOP_Verts = 0 To Verts-1
; Vx# = VertexX#(Surface_Handle, LOOP_Verts)
; Vy# = VertexY#(Surface_Handle, LOOP_Verts)
; Vz# = VertexZ#(Surface_Handle, LOOP_Verts)
; If Vx# < Min_X# Then Min_X# = Vx#
; If Vy# < Min_Y# Then Min_Y# = Vy#
; If Vz# < Min_Z# Then Min_Z# = Vz#
; If Vx# > Max_X# Then Max_X# = Vx#
; If Vy# > Max_Y# Then Max_Y# = Vy#
; If Vz# > Max_Z# Then Max_Z# = Vz#
; Next
; Next
; Get the radius of the sphere which completely encloses this receiver.
; Loop through all vertices in all surfaces of the reciever.
Surfaces = CountSurfaces(ThisReceiver\Entity)
For LOOP_Surface = 1 To Surfaces
Surface_Handle = GetSurface(ThisReceiver\Entity, LOOP_Surface)
Verts = CountVertices(Surface_Handle)
For LOOP_Verts = 0 To Verts-1
VX# = VertexX#(Surface_Handle, LOOP_Verts)
VY# = VertexY#(Surface_Handle, LOOP_Verts)
VZ# = VertexZ#(Surface_Handle, LOOP_Verts)
; Compute vertex distance^2
VR# = VX#*VX# + VY#*VY# + VZ#*VZ#
If Radius# < VR# Then Radius# = VR#
Next
Next
; Store the receiver's true radius.
ThisReceiver\Radius# = Sqr(Radius#)
; Create one shadow mesh for this receiver for every caster/light pair.
For Loop.Caster_Set = Each Caster_Set
ThisShadow.Shadow = New Shadow
ThisShadow\Mesh = CreateMesh()
SURFACE_Shadow = CreateSurface(ThisShadow\Mesh)
Next
End Function
See how that function creates a receiver type, and stores all the polygon and vertex data in a bank? Well, if you don't want to bother spending the time to split your level up manually into small sections, then the next best thing would be to go into this function and modify it so that when you input one receiver into it, it creates several. All you have to do is split your object into a grid of whatever granularity you want, say, cubes 1 meter on a side, and then figure out which polygons should be assigned to each cube, with no polygon being assigned to more than one. Then make banks to hold those polygons and the vertices that go with them, and calculate the bounding spheres for them and voila, the shadow system will be much faster. You don't even need to know any 3D math to do it either. Just use the first vertex of the triangle to decide what cube it belongs in. And that's just if X > N and X < N2 etc.
But this is something you can do just by splitting up your level in your 3D app. A lot of people don't bother to do that properly though, and then complain the system is too slow in their game. So it's not like the system isn't already optimized. This is just a "convenience" feature really. Saves you the effort of doing that work by hand, mainly.
And yes, there's other ways you could split that up for even more speed, but a grid is by far the easiest to implement and doesn't require an overhaul of the whole system, and I doubt you'd get much more out of using octrees since you're not gonna subdivide each receiver that much. I suppose if you were absolutely insane and had a million polygon terrain with grass on it and you wanted to cast shadows onto the grass, then maybe you might want octrees, but I'm not even sure Blitz could handle that.