Openb3d wrapper (Part 3)

BlitzMax Forums/MiniB3D Module/Openb3d wrapper (Part 3)

markcw(Posted 2015) [#1]
Since the 2nd thread has exceeded 250 posts I have started a new thread. So please post new issues here. Thanks.

Download: You can download the latest version of the wrapper with examples and my small fixes to the C++ source HERE. Now available courtesy of GitHub.
You can find the official Openb3d libraries and source HERE.

To install MinGW follow this guide.

The original thread about Openb3d is here and the Freebasic thread is here.
Other Openb3d wrapper threads: 1st, 2nd.

New for version 1.1:
Added:
-3d actions: ActMoveBy, ActTurnBy, ActMoveTo, ActTurnTo, and many more
-Physics features: CreateConstraints and CreateRigidBody; with the last one, it's possible to define position, scale and rotation of an entity by linking it to four other entities (usually pivots): if that entities are controlled by constraints, the main entity can be controlled in a physically realistic way
-Particle system: emitters can be made with CreateEmitter (even an "emitter of emitters" is possible)
-if a light is created with a negative light type, it won't cast shadows
-DepthBufferToTex: with no args it uses the back buffer, otherwise it can render the depth buffer from a camera (like in CameraToTex)

Fixed:
-Collisions crashed when an entity made with CopyEntity was erased, it doesn't crash any more
-Dynamic collisions didn't work for scaled entities, or child entities; now they work
-HideEntity now works on lights
-Finally, it's possible to load textures from different directories; path info in texture name is now used: if the file cannot be found, a warning is emitted and the file is searched in current directory (or in the directory where the 3d model using that texture is located).
-CreateGeosphere now build a model with correct texture mapping
-When updating a child entity, only its matrix is recalculated, not the entire tree (should be slightly faster)
-PaintEntity and TextureFilter now should work
-fixed a bug in static shadows



Hezkore(Posted 2015) [#2]
My god, there's no end to this thread heh.
You and angros should just open up your own forum.

But I've noticed a weird thing with CreateTerrain().
It always seems to create really weird corners.
I tried looping through the terrain and use ModifyTerrain to set the same height everywhere, but it doesn't seem to set the corner height.




angros47(Posted 2015) [#3]
Yes, it's a small bug...
It's because the terrain is recursively divided, and the height of each vertex is evaluated only once at each subdivision: since four corners are never divided (even at the lowest LOD they are the same), theis height is never set during rendering.

To fix it, you should assign a height inside the function RecreateROAM: something like:

v[0][1] = height[(int)(v[0][0]*size+ v[0][2])] * vsize

For v[1], v[2] and v[3] too


markcw(Posted 2015) [#4]
That fix for RecreateROAM worked, so thanks Angros, but I'm having a problem with the Windows builds (some kind of MAV with every example) so just don't update until I get that fixed.


angros47(Posted 2015) [#5]
The "official" fix for RecreateROAM should be that:

	v[0][0] = 0.0; 		v[0][2] = size;
	v[0][1] = height[(int)size] * vsize;

	v[1][0] = size; 	v[1][2] = size;
	v[1][1] = height[(int)(size*(size+1))] * vsize;

	v[2][0] = size; 	v[2][2] = 0;
	v[2][1] = height[(int)(size*size)] * vsize;

	v[3][0] = 0.0; 		v[3][2] = 0;
	v[3][1] = height[0] * vsize;


(if, for example, I know that v[0][0] is 0, there is no point in using it in the expression)

Meanwhile, I am experimenting a little with Python... I just managed to get, under Ubuntu, a window showing a cube rendered with OpenB3D. Maybe having Blitz3d-like commands in Python could be a nice feature...


Hezkore(Posted 2015) [#6]
Is the terrain not affected by lights?




angros47(Posted 2015) [#7]
Lights hould affect terrains, unless you disabled that with EntityFX.

But the upper light, in your picture, seems to affect the terrain... and the lower light seems not to affect even crates.


Hezkore(Posted 2015) [#8]
The top light doesn't affect the terrain, the 2D flare is only rendered above it.
The bottom light doesn't have a very long range, but it does light up the ground and box in the background (same mesh)
So it should affect the terrain too.
Even it I move the light around it never affects the terrain.
No FX has been used with the terrain, only EntityTexture and ModifyTerrain.

I'll explore a bit, see if I can figure out what's causing it to not light correctly.


markcw(Posted 2015) [#9]
If someone could just test the latest version of the repo for me on Windows Vista/6 or higher then that would be great. I suspect I may have a slightly broken install of MinGW but I'm not sure. Just build it and run any example/s (to see if it crashes straight away). Thanks.


feeble1(Posted 2015) [#10]
With the exception of the usual load3ds and loadx issues, everything runs great on my box:
Windows 7.


markcw(Posted 2015) [#11]
Thanks feeble! Then it is probably my MinGW libs.

Edit: well when I reverted to MinGW 4.6.1 it worked! I remember I didn't edit the bat file to copy the lib files over to bmx/lib but when I tried upgrading to 4.8.1 tdm properly it now produces an 'undefined reference to pthread_blah' error. So I copied all libs in gcc/lib and gcc/lib/mingw/4.8.1 and deleted all dll.a files but it still gives the same error so I'm just going to revert to 4.6.1 again.


RustyKristi(Posted 2015) [#12]
Hi munch, so this won't work on MinGW 4.8.1? I'm trying some examples right now and it does nothing but compiles ok.


markcw(Posted 2015) [#13]
Yeah, afaik. There's probably a way to get it working but for now I'm leaving it. I haven't tried 4.7 but it should work. Edit: yes 4.7.1 works fine.


RustyKristi(Posted 2015) [#14]
Ok thanks.


markcw(Posted 2015) [#15]
No worries.


RustyKristi(Posted 2015) [#16]
Hey munch,

I tried with 4.7.1 as per instructions here:
http://www.blitzmax.com/Community/posts.php?topic=95220

copied 2 bin files and manually copied the whole mingw lib directory to blitzmax/lib. The batch file fails btw on the copying libs part

Same thing, compiles ok but does not run. MiniB3D works fine though.


markcw(Posted 2015) [#17]
The bat file shouldn't fail. You need to edit the three paths at the top (dirMinGW, minGWVersionString, dirBlitzmax) AND the path to the 2nd lib folder the line with "..\lib\gcc\mingw32\..". If you manually copy all libs you will need to delete any files ending in "dll.a".

Did you rebuild all modules? If you have a lot of mods you can just do a makemods in cmd starting with brl.mod, then pub, then maxgui then openb3d.


RustyKristi(Posted 2015) [#18]
Thanks munch, still weird the bat file does not work and I missed that dll.a delete part but it works now! :)


RustyKristi(Posted 2015) [#19]
Btw, is there support that I can use this with Brucey's BMXNG? Do I just copy the lib folder because as I see it there's MinGW (4.8.1) included in the release already.


markcw(Posted 2015) [#20]
No, this hasn't been tested to see if it works with Bmx-NG, my priority is Win/Mac/Linux. There is a separate module b3d.mod that Brucey maintains for Bmx-NG.


RustyKristi(Posted 2015) [#21]
Ok thank you for that info


markcw(Posted 2015) [#22]
Well I should have said I intend to make sure it is working with Bmx-NG when I get the time, for the 64bit.


RustyKristi(Posted 2015) [#23]
got it, thanks. I was also wondering about how postprocessing shaders work in openb3d. I can only see material shaders on the examples.


markcw(Posted 2015) [#24]
There aren't any yet, but I plan on adding those too.


Hezkore(Posted 2015) [#25]
Is there any way to get all the entities created?
Like a global list containing all entities.


markcw(Posted 2015) [#26]
Yes it's the global entity_list in TEntity, currently you have to use CopyList(TEntity.entity_list) before you do an EachIn loop to update the list but I'm plainning to internalize CopyList so it won't be needed then.


Hezkore(Posted 2015) [#27]
Alright, thanks!
But wouldn't it be really slow to copy the list?
I want to hide everything before each RenderWorld, so that means I'd have to do CopyList each frame.

And I have a question about BackBufferToTex.
I'm using it to draw my textures with BeginMax2D.
But since I'm clearing the screen with black before drawing my texture, I can't get alpha to work.
Is there any way to clear the screen without covering it with a color?

UPDATE: Nevermind, I used glClearColor(0, 0, 0, 0) to clear with 0 alpha.


markcw(Posted 2015) [#28]
It's up to you where you use CopyList, in this case if you free or create an entity you need to call CopyList then, but if it's code that isn't being called every frame you can just drop it before any EachIn loops.


Hezkore(Posted 2015) [#29]
I wanted to hide every entity before each frame, as I do multiple renders to get alpha and other effects working and don't want to manually hide everything.

Also, does OpenB3D not handle OBJ files?
For some reason I thought it did...

And a question about shadows.
Is it possible to disable self shadows?
So that meshes doesn't cast shadows on themselves, it looks very weird in some situations.


angros47(Posted 2015) [#30]
OpenB3D does not handle .OBJ files directly, you need to use some external libraries like AssImp, or use some of the existing code for BlitzMax or Blitz3D, or convert your model to another format.

The issue has already been discussed one year ago:

http://www.blitzbasic.com/Community/post.php?topic=102556&post=1236018

About shadows: there is no command to disable self-shadowing... but remember that in the real world an object acutally casts a shadow on itself.


Hezkore(Posted 2015) [#31]
Thanks for the OBJ information!

And yeah shadows may work like that in the real world, but the shadows in the engine are far from real world shadows heh.
My trashcan and street lamp for example are very tall, and when the sun shines from above, the long edges start to flicker black because of the shadow they cast on themselves.
I guess the trick/solution would be to make them a bit thinner or thicker at the bottom.

Anyways, is there a way to get the Bumpmap shaders to support transparent parts?


Cocopino(Posted 2015) [#32]
Hi, I am getting really strange and inconsistent results using LoadAnimSeq.
I am using a human.b3d file that contains a rigged mesh and several anim.b3d files that contain the animations.

A small program that outlines the problem(s)

SuperStrict

Import angros.b3dglgraphics

Graphics3D 1600, 900
Local cam:TCamera = CreateCamera()

Local sequence:Int = 1

Local human:TMesh = LoadAnimMesh("media\\meshes\\human.b3d")
Local human2:TEntity = LoadAnimMesh("media\\meshes\\human.b3d")

Local head:TEntity = human.FindChild("Head")
Local head2:TEntity = human2.FindChild("Head")

PositionEntity cam, 0, 180, -500
PointEntity cam, human

Local light:TLight = createlight(2)
light.PositionEntity(500, 1000, -100)
PointEntity(light, human)

human.MoveEntity(-70, 0, 0)
human2.MoveEntity(70, 0, 0)

AmbientLight(200, 200, 200)

Local anim:Int[10]
anim[1] = human.LoadAnimSeq("media\\anims\\human_anim_1.b3d")
anim[2] = human.LoadAnimSeq("media\\anims\\human_anim_2.b3d")
anim[3] = human.LoadAnimSeq("media\\anims\\human_anim_3.b3d")

Local anim2:Int[10]
anim2[1] = human2.LoadAnimSeq("media\\anims\\human_anim_1.b3d")
anim2[2] = human2.LoadAnimSeq("media\\anims\\human_anim_2.b3d")
anim2[3] = human2.LoadAnimSeq("media\\anims\\human_anim_3.b3d")

While Not KeyDown(KEY_ESCAPE)

	If KeyHit(KEY_1) sequence = 1
	If KeyHit(KEY_2) sequence = 2
	If KeyHit(KEY_3) sequence = 3

	If Not Animating(human)
		Animate(human, 3, 1, anim[sequence])
		Animate(human2, 3, 1, anim2[sequence])
	EndIf

	UpdateWorld()
	RenderWorld()

	BeginMax2D
	DrawText(EntityVisible(cam, human), 5, 5)
	DrawText(EntityX(head, True) + "," + EntityY(head, True) + "," + EntityZ(head, True), 5, 20)

	DrawText(EntityVisible(cam, human2), 5, 45)
	DrawText(EntityX(head2, True) + "," + EntityY(head2, True) + "," + EntityZ(head2, True), 5, 60)
	EndMax2D
	
	Flip(1)

Wend


Running it several times in a row yields completely different results:

- Sometimes, all is well from the start.
- Sometimes, human (using TMesh) is visible but human2 is not.
- Sometimes, human2 is visible but human is not. The animation of human2 will now sometimes be slowed down severely.
- Sometimes the program crashes completely on UpdateWorld_( anim_speed ), line 205 in TGlobal.bmx

When a mesh is not visible, the global position of the head child is all over the place. I've seen extremely large numbers like +e35, or extremely small ones. Sometimes it says #QNAN which I assume is "Not A Number".

I've deinstalled the minib3d module so cannot test that now but when using these same animations in Blitz3D all is fine...
Any ideas?
Thanks!


Hezkore(Posted 2015) [#33]
Here's another problem for you guys!

If you create a shadow from a mesh and compare that mesh against a camera picks PickEntity(), it doesn't work!

I've made an example of it here


markcw(Posted 2015) [#34]
Anyways, is there a way to get the Bumpmap shaders to support transparent parts?


Yes, assuming you're using bumpmap2 and a png with alpha channel then add these lines to the frag shader:
uniform sampler2D alphaMap;
...
vec4 alpha_color = texture2D(alphaMap, vec2(texCoords));
gl_FragColor = vec4(totalLighting, alpha_color.a);

Then add to the bumpmap example:
ShaderTexture(shader2,LoadTexture("media/alpha_map.png"),"alphaMap",2)
...
EntityFX(wall1,32) ; EntityFX(wall2,32) ' etc 



angros47(Posted 2015) [#35]
@Hezkore: I tried the same experiment in FreeBasic, and looks like CameraPick works even with shadows with vanilla OpenB3D.

@Cocopino
I can't do any test without the 3d models.


Cocopino(Posted 2015) [#36]
Hi Angros, here you go, hope it helps.
https://www.dropbox.com/s/2h6mggup5fdu083/4angros.zip?dl=0

Thanks for looking into it.


angros47(Posted 2015) [#37]
I ported your code in FreeBasic and tried it under linux with vanilla OpenB3D.

Here is the ported code:

#Include "openb3d.bi"


ScreenRes 800,600,32,,&h10002
Graphics3D 800,600

var cam=CreateCamera()
PositionEntity cam,0,50,-100

var light=CreateLight(2)
PositionEntity light,1000,1000,-1000

var ground=CreatePlane(2)
EntityAlpha ground,0.5
EntityColor ground,200,0,200

var hero = LoadAnimMesh("media\\meshes\\hero.b3d")
var head = FindChild(hero,"mixamorig:Head")

var hero2 = LoadAnimMesh("media\\meshes\\hero.b3d")
var head2 = FindChild(hero2,"mixamorig:Head")

PointEntity(cam,hero)
CameraRange(cam, 0.5, 9999)

MoveEntity(hero,25,0,0)

var anim1 = LoadAnimSeq(hero,"media\\anims\\anim_1.b3d")
var anim2 = LoadAnimSeq(hero,"media\\anims\\anim_2.b3d")
var anim3 = LoadAnimSeq(hero,"media\\anims\\anim_3.b3d")
var anim4 = LoadAnimSeq(hero,"media\\anims\\anim_4.b3d")

var anim5 = LoadAnimSeq(hero2,"media\\anims\\anim_1.b3d")
var anim6 = LoadAnimSeq(hero2,"media\\anims\\anim_2.b3d")
var anim7 = LoadAnimSeq(hero2,"media\\anims\\anim_3.b3d")
var anim8 = LoadAnimSeq(hero2,"media\\anims\\anim_4.b3d")

While Not multikey(1)
	
	If multikey(2) Then Animate(hero,3,1,anim1):Animate(hero2,3,1,anim5):
	If multikey(3) Then Animate(hero,3,1,anim2):Animate(hero2,3,1,anim6):
	If multikey(4) Then Animate(hero,3,1,anim3):Animate(hero2,3,1,anim7):
	If multikey(5) Then Animate(hero,3,1,anim4):Animate(hero2,3,1,anim8):
	
	UpdateWorld
	RenderWorld
	
	'Text(5,5,EntityX(head,1) + "," + EntityY(head,1) + "," + EntityZ(head,1))
	'Text(5,20,EntityVisible(cam, hero))
	
	Flip
Wend
End


Both heroes are visible, and seems to be animated correctly. I didn't manage to reproduce your issue.


markcw(Posted 2015) [#38]
So from tests it seems the PickEntity issue is a problem with the wrapper and the lights on terrain is with Openb3d, also I haven't tested but it looks like the LoadAnimSeq is a prrolem with the wrapper. So far no solutions.


angros47(Posted 2015) [#39]
About the issue of lights and terrain, I need to know a thing: does the issue occur only on terrains created by CreateTerrain, or also with terrains made with LoadTerrain?

The terrain in Hezkore picture is flat, so maybe it has been made with CreateTerrain; try replacing it with a LoadTerrain (and load a square, black image of the size of the terrain); tell me if the issue still occurs.

Because I made some tests, and the bug seems to affect only CreateTerrain. There is a simple way to fix: you have to call the method "UpdateNormals" of the terrain object (don't confuse with UpdateNormals for mesh, that is the method called by "functions.cpp"); when a terrain is loaded, it is called automatically, but it's not called with CreateTerrain.

It also need to be called after you use some ModifyTerrain commands, otherwise lightning won't be correct. It's not called by the ModifyTerrain routine otherwise it would be performed too many time, with excessive slow down.


markcw(Posted 2015) [#40]
Yes, it was CreateTerrain I was working with and now I test it LoadTerrain is affected by lights. I just wrapped UpdateNormals and tested it with CreateTerrain/ModifyTerrain and your fix worked, so thanks! I still need to wrap terrains fully so I'll do that next.

One thing I notice is that when the terrain is flat it doesn't seem to reflect light as you would expect but add some bumps and it looks fine then.


Cocopino(Posted 2015) [#41]
Hi Angros, Munch, I can confirm LoadAnimSeq working correctly in both FreeBasic+OpenB3d and in Blitz3D. So it probably has something to do with the wrapper.

One weird thing I noticed is that in the dropbox download of post #36, I can change from animation 1 to 4 (this seems to be working correctly some/most of the times I tried). Now for the weird part: this does not seem to have to do with the animation itself: because if I rename anim_2.b3d to anim_4.b3d and vice versa, I still can change from 1 to 4 most of the times, while switching to anim_2 crashes or behaves unexpectedly.


markcw(Posted 2015) [#42]
Hi Cocopino, I tested your code in Linux and both examples seem to work fine but in the zip example you had a mistake where you are using hero.LoadAnimSeq instead of hero2.LoadAnimSeq, which was causing a crash.


ErikT(Posted 2015) [#43]
I'm getting a compiler error: "Module does not match commandline module" on building bmax code. I've followed the mingw install instructions by Brucey, built all modules and placed the bmx files in my project folder. Not sure what else I need to do?


markcw(Posted 2015) [#44]
Have you checked the module scope folder is named "openb3d.mod"?


Hezkore(Posted 2015) [#45]
Hey munch, the "fix-stencil-shadow-crashes" push by ProPuke on Github solved a lot of random crashes that were causing me a lot of problems!


RustyKristi(Posted 2015) [#46]
@ErikT

The Blitzmax version is different from NG, as munch mentioned and is working for me right now on both.

Vanilla BMX:
openb3d.mod
|_ openb3d.mod
|_ b3dglgraphics.mod
|_ openb3dlib.mod

BNX-NG:
b3d.mod
|_ openb3d.mod
|_ b3dglgraphics.mod
|_ b3dglsdlgraphics.mod
|_ newtondynamics.mod
|_ b3d.mod

using MingW 4.7.1


ErikT(Posted 2015) [#47]
Okay thanks :) I'll try out NG then.


BlitzSupport(Posted 2015) [#48]
Just noticed "DepthBufferToTex" the other day! Had a bit of fun learning how to access and display it:



Next job will be to figure out how to access it from a shader!

Before I get too far ahead, have I done anything stupid/wasteful here?


Hezkore(Posted 2015) [#49]
I haven't looked at your code, but I made my own camera type that has a quad infront of it that I render the 3D world to from a second camera.
I then just apply any shader I want to that quad.
Right now I have a color adjust and greyscale shader on it.
I did have bloom also, but found a simpler way to do that.


BlitzSupport(Posted 2015) [#50]
Any chance of posting a simple example, Hezkore?

Failing that, can anyone see what I'm doing wrong here? (Should this even work the way I'm expecting?!)

I'm attempting to simply amend my 'depthtex' texture here (displayed on a full-screen sprite) with a very simple shader, but where I'm expecting it to return all in red, it just remains the same.

I am groping a little blindly here (cross-referencing the examples and some old Max3D shaders I did years ago), but if anyone can point me in the right direction to simply amend the texture colours via a fragment shader I'll be happy!



shader.glsl:



Also, is there any way to test if a shader compiled correctly? Even with deliberate typos, they seem to load!


Hezkore(Posted 2015) [#51]
I guess I could share it once I'm by the computer.

You can use InitShader or something like that to test for shader errors.
I think it was shown/used in an example or in the previous part 2 thread.


Hezkore(Posted 2015) [#52]
Here's my TShaderCam code, along with an example for greyscale and color adjusting.
I'm not sure if I should ask for any credits for sharing this...
Not that it's very advanced, but it took some time to figure out!
I guess, just use it as you want, but I'd be really happy if you (anyone) gave me some creds if you do end up using this. :)

*LINK REMOVED, SEE POST #55 FOR NEW VERSION*

And BlitzSupport, TShaderCam has shader error checking.
The example included has that part enabled, so if you're still wondering how to check for shader errors you can check that out.


And while I'm at it, I guess I should also share the FBO module with depth testing enabled that I'm using for bloom, screen dirt and smoke/fog in my 3D world.
With it you can draw the 3D world or your Max2D stuff to a separate image and render it ontop of everything.

https://bitbucket.org/Hezkore/fbo

For bloom I render the world normally once, then make everything EXCEPT for the bloom objects 100% black and render that to an FBO with low resolution.
Then I render the FBO a couple of times ontop of the normal world (in Max2D) with the light blend mode.
It's not the best looking bloom, but it works alright as glow in my GTA2-ish top-down game.

Here's a random test scene from my little editor.
Notice how the neon sign glows a bit.



BlitzSupport(Posted 2015) [#53]
Excellent, thanks for posting! I'll have a good look at this.

Been playing with some really simple shaders tonight, and about to try and get my depth buffer stuff working again, so hopefully your work will help me figure out what I need... much appreciated!

That last screenshot is really nice, some subtle effects going on there.


RustyKristi(Posted 2015) [#54]
Thanks for sharing Hezkore. :-) Just tried it and it looks great! will this be included in official repo?


Hezkore(Posted 2015) [#55]
I think a better way would be to create a type of shader camera that attaches itself to a normal camera entity.
That way you could use all your normal Entity functions for moving the camera around.

Basically something like...
myCamera = CreateCamera()

myShaderCamera = CreateShaderCamera(myCamera)
myShaderCamera.Shader(Blah,Blah)
myShaderCamera.Quality(0.25)

etc.

So then you'd only work with "myCamera", like you normally would.
All the normal entity functions would work and act as expected.

Then to render you'd do...
myShaderCamera.Render()
Instead of RenderWorld()

It'd be easier to implement in existing projects and it'd be easy to switch between which camera to render with since myCamera.Render() would act the same way as myShaderCamera.Render().
But without any shaders applied of course!
So for machines that can't handle the screen shaders, you could just render with the normal camera to skip the shaders.


UPDATE: I have created a camera that works like this.
I also accidentally rendered the world twice in the old example, so that's been fixed too.
Here's the new link: *LINK REMOVED, SEE POST #60 FOR NEW LINK*


BlitzSupport(Posted 2015) [#56]
Interesting, will take a look tomorrow (didn't really stick to the plan tonight!), but thanks again, Hezkore, hopefully it will point me in the right direction!


ErikT(Posted 2015) [#57]
Hmm. On compiling with BMK-NG I get:

Compile Error: Unable to find overload for rotatemesh(TMesh,Int,Int,Int)
[C:/Progs/BlitzMaxNG/mod/openb3d.mod/openb3d.mod/inc/TMesh.bmx;142;0]

NG version: 0.62.3.08


ErikT(Posted 2015) [#58]
Uh oh, looks like I forgot about the libraries themselves. Downloaded and placed them in my own project folder and now it works great.

But I thought Build Modules/Rebuild All Modules already built the libraries for me? So where do those fresh builds get placed? (Sorry about all the stupid questions :P)


markcw(Posted 2015) [#59]
Sorry Erik, I don't think I can help as I still haven't tried out Bmxng myself. It does seem likely your Mingw install is missing something.

Hezkore, thanks a lot for the shader demo! It should help me trying to add postfx shaders to the wrapper (I'm busy at the moment so sorry for the lack of response).


Hezkore(Posted 2015) [#60]
I decided to make my shader camera into a module.
You can find it at https://bitbucket.org/Hezkore/shader-camera
I also set the camera range for the "screen camera" very low, so there's an even lower chance of it rendering anything of the actual 3D world.
So make sure you update to the new version!


markcw(Posted 2015) [#61]
About the "fix-stencil-shadow-crashes" push by ProPuke on Github. Thanks for pointing that out Hezkore!

Angros, if you're wondering about ProPuke's changes you should be able to see them HERE.


angros47(Posted 2015) [#62]
I'd have to make some changes in those files, for the next version...

For now, I am testing some changes in the files mesh.cpp, global.cpp...

In the new version, there will be a lot of lines like:
#ifdef gles2

Of course, since I am compiling with standard opengl, I will need your help for testing.


markcw(Posted 2015) [#63]
Sounds great Angros! So assuming you mean testing gles2, what platforms would I need for that?


angros47(Posted 2015) [#64]
Angle, Android, Emscripten... you choose.

I don't have gles2 installed, I am using opengl and removing all unsupported commands like glLoadIdentity, so I will need someone with a true gles2 install to test (not easy: Angle seems to require Visual Studio, Emscripten requires 64 bit, Android requires ND... )


Hezkore(Posted 2015) [#65]
Is there a way to disable the shader I've set for an Entity?


angros47(Posted 2015) [#66]
Set it to 0


Brucey(Posted 2015) [#67]
so I will need someone with a true gles2 install to test

I'm sure someone around here will be able to assist :-)


markcw(Posted 2015) [#68]
Is there a way to disable the shader I've set for an Entity?
>Set it to 0

Do you mean the shader variable or the "ShaderMat" variable in the Surface class? I haven't wrapped this variable yet.

By the way, could you explain what the "ambient_shader" variable in the Global class is for?

I'm sure someone around here will be able to assist :-)

Great! I don't have an Android phone but I should get someone's old one soon, so will hopefully be able to beta test too.


Hezkore(Posted 2015) [#69]
I've made some Android and iOS games, so I have a bunch of devices if something needs testing. Along with Macs and PCs with Linux and Windows.

And about removing the shader.
After I've used ShadeEntity to bind a shader to my Entity, is there a way to remove that?
So that it works like a normal Entity again that uses EntityTexture and all that.


angros47(Posted 2015) [#70]
As I've said: to remove the shader, just use ShadeEntity again, on the same entity, using 0 instead of a shader

if you used something like:
shadeentity cube,shader


to disable the shader just use:

shadeentity cube,0



BlitzSupport(Posted 2015) [#71]
I actually tried this last night, using Null, and it gave an error relating to accessing a Null object:


' Using Local shader:TShader...

	If KeyHit (KEY_SPACE)
		toggle = 1 - toggle
		If toggle
			ShadeEntity sprite, Null
		Else
			ShadeEntity sprite, shader
		EndIf
	EndIf


(Changing to 0 gives an error due to wrong type for the shader parameter.)


angros47(Posted 2015) [#72]
I tested it in FreeBasic, and it worked (but FreeBasic calls library functions directly).

I am not sure how the wrapper works, but you should be able to use ShadeEntity_ (with the underscore) to bypass the wrapper code that gives the error.


markcw(Posted 2015) [#73]
Yes, it's because ShadeEntity calls the method material.ShadeEntity and it's erroring when that's null. It just needs to be changed to call as a function. For now this should work:
ShadeEntity_( TEntity.GetInstance(sprite),Null )


feeble1(Posted 2015) [#74]
I was playing around with OpenB3d, MiniB3d, and Blitz3d. Something about UpdateWorld was a little different. Its not game breaking or bug inducing (I don't think), but it is interesting.

Import openb3d.b3dglgraphics
'Import sidesign.minib3d
Graphics3D 640,480

camera=CreateCamera()
	RotateEntity camera,45,0,0
	PositionEntity camera,2,5,-5

AmbientLight 255,255,255

ball=CreateSphere()
	EntityColor ball,0,0,255
	EntityType ball,1

box=CreateCube(box)
	PositionEntity box,4,0,0
	EntityType box,2

Collisions 1, 2, 2, 2

While Not KeyHit( KEY_ESCAPE ) And Not AppTerminate()
	'openb3d is much more particular than miniB3d Or B3d about UpdateWorld placement
	UpdateWorld
	
	MoveEntity ball,(KeyDown(KEY_RIGHT)-KeyDown(KEY_LEFT))*.05,0,0
	
	If CountCollisions(ball) Then End
	
	'UpdateWorld
	RenderWorld	

	Flip
Wend
End


OpenB3d is much more particular about where you call UpdateWorld.


markcw(Posted 2015) [#75]
Sorry for the delay, we had a wedding in the family (not me). :)

I have just wrapped TTerrain fully, except for the terrain collisions in tree.h (TColTree in minib3d) because it seems they are only for internal use and are not possible to access (since they get deleted quickly). So now I am just mulling whether anyone will need the shader variables (in shadermat.h and shaderobject.h). Could do with a second opinion on that.

I tried to get Openb3d working on ubuntu with Freebasic so I can test this shadow camerapick bug. I can run the OpenGL examples but not code I take from the Openb3d thread. I am wondering if I am missing Glee.c or something.

Anyway, happy Christmas (or holidays) to everyone!


angros47(Posted 2015) [#76]
What error do you get in Ubuntu?


markcw(Posted 2015) [#77]
Hi Angros! I'm sure I just don't know what I'm doing. The FBWiki is very helpful though.

I have extracted Openb3d for FB to FreeBASIC-1.04/examples/graphics/openb3d and copied some code from your thread.

The error is: "error while loading shared libraries: libOpenB3D.so: cannot open shared object file: No such file or directory".

Edit: so it seems I need to install the Openb3d shared library, but I don't know what files need to go where.


angros47(Posted 2015) [#78]
If the library is in the same directory of the compiled file, you can launch it using this command:

LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH  ./yourfile


instead of just using
./yourfile


With this trick, you tell linux to look for shared libraries in current directory, too (otherwise you'd need to put the library in a system directory)


markcw(Posted 2015) [#79]
Thanks, that worked but how do I install Openb3d so I don't have to do that every time I run a FB exe? I tried copying the .bi files to /usr/local/include and the .so to /usr/local/lib but it still can't find them. Do I need any symlinks?

I converted the shadowpick.zip example by Hezkore to FB and tested it, still no idea what's wrong though.

I notice you can't use the Text command in FB, I tried using code by Westbeam saved as 2d2.bi with the equivalent command myFont.print 10,10,"supertext" but it didn't work.


angros47(Posted 2015) [#80]
You are using wrong directories: correct directory for the .so file is "/usr/lib" (no "local")


markcw(Posted 2015) [#81]
Ahh, thank you!

I have fixed the shadow Camerapick bug. I tested older versions until I found which commit it broke in, then in the changes log I saw it was when I added variables to TShadowObject. So I regressed just that file and when that worked I narrowed it down to InitFields. It was the Parent variable, I realize I can't just call Createobject it must be checked with Getobject or you may end up with duplicate objects in the lists, which in this case confused Camerapick.

If you want a quick fix then change line 99 in TShadowObject.bmx to:
Parent=TMesh( TEntity.GetObject(inst) )



markcw(Posted 2015) [#82]
Angros, playing around with your particles example it seems as soon as I create any meshes, even another sprite, then the particles don't work.


angros47(Posted 2015) [#83]
Can you post an example?


markcw(Posted 2015) [#84]
Sure. It's just your example with a line added. I've noticed it just affects the emitter stuff. So the swarm example works with meshes as it doesn't use the emitter stuff.
 #Include "openb3d.bi"


    ScreenRes 800,600,32,,&h10002
    Graphics3d 800,600

    Var camera=createCamera
    Var light=createLight

var cube=createsprite()
	var cube2=createsprite() ' <-
var t=createtexture (1,1)
entitytexture cube,t
spriterendermode cube,3
particletrail cube,200
particlecolor cube,-255,-255,0,-1

var p=createparticleemitter(cube)

emitterrate p,1
emitterparticlelife p, 500
emittervariance p,.5
emitterparticlespeed p,.3
emittervector p,0,-.004,0

var p2=copyentity(p)
moveentity p2,10,0,0
var zz=0
moveentity camera,0,1,-15
p=p2

    Do

        if multikey(72) then turnentity p,-1,0,0
        if multikey(80) then turnentity p,1,0,0
        if multikey(77) then turnentity p,0,-1,0
        if multikey(75) then turnentity p,0,1,0
        if multikey(2) and zz=0 then freeentity p:zz=1

        updateworld '1
        renderworld
        Flip
    Loop Until MultiKey(1)



angros47(Posted 2015) [#85]
Ok, you've just found a bug. To fix it, in the file "particle.cpp", just before the line:

	glColorPointer(4,GL_FLOAT,0,&surf->vert_col[0]);


add the line:

	glBindBuffer(GL_ARRAY_BUFFER,0); // reset - necessary for when non-vbo surf follows vbo surf



markcw(Posted 2015) [#86]
I've updated the repo now. Quite a few changes and just in time for Christmas! ho ho ho :)

- particles with meshes fix
- terrain corners not set fix
- wrapped terrain fields and methods
(meshinfo and mechcollider in coltree/tree were not wrapped because I couldn't get access them)
- ShadeEntity erroring on null shader
- changed any other functions that may use a null object
- GetObject checks for CreateObject in InitFields
- some more doc comments
- sl_shimmer example, heat haze postprocess effect using CameraToTex
- sl_depthfield example, depth of field postprocess effect using CameraToTex/DepthbufferToTex
- particle example, how to do a smoke effect with TParticleEmitter
- new methods for when using GL 2.0, CameraToTexEXT/DepthbufferToTexEXT - no MAV now
- CameraViewport's inverted y parameter was the wrong value when switching cameras
- THarwareInfo new extensions, FBOSupport and DepthStencil used in CameraToTexEXT
- changes to CameraToTex/DepthbufferToTex in texture.cpp (see sl_depthfield)

The changes to texture.cpp were not essential but I noticed they improved the rendering, in sl_depthfield you can see ugly "ghost edges" artifacts around the meshes from the depth buffer but with my changes these are gone.

Also the CameraToTexEXT/DepthbufferToTexEXT were added when I was reminded that CameraToTex MAVs in GL 2.0. It may not be worth supporting 2.0 but it's nice to have it. Just for fun I tested on a Mac with GL 1.4 and everything errored out. He he


markcw(Posted 2015) [#87]
Angros! I've been playing with the particle commands a bit and noticed a few things. EmitterVector sets the direction as well as the speed but shouldn't it just be a direction? Also EmitterParticleSpeed only effects things on the z axis. I also wonder how I would effect the particles alpha, so it would fade with time. Should I use the EmitterParticleFunction for this?

Here is an example converted to FB for smoke so you see what I mean (images are on my repo).

Edit: I forgot to mention ParticleColor. It doesn't seem to work. Have I missed something?

Finally, I was looking at bloom shaders which are basically a blur in two passes which means you need access to two (maybe even three) framebuffer objects. This is a bit beyond me but maybe you will know what to do. I read it can be done by multiple renders instead but surely this would be slower? I was thinking of a DoublebufferToTex command...


angros47(Posted 2015) [#88]
EmitterVector sets a vector: and a vector has a magnitude (a speed, in that case) and a direction. Anyway, that vector affects particles only AFTER they have been emitted: it's used to simulate gravity, and wind. To set direction of the emitted particle, just turn the emitter (TurnEntity and RotateEntity work on emitters): particles will be emitted in the direction the emitter is facing, at the speed set by EmitterParticleSpeed (that's why it only affect z axis)

To set alpha, rotations and other parameters (color, size... whatever you want) you should use EmitterParticleFunction.

ParticleColor only works on particles that have a trail (sprites with SpriteRenderMode set to 3), and does not affect the particle itself, but only its trail (by default the trail is set to 0, so you don't see anything); ParticleVector can move the trail (i.e. to simulate a smoke trail in the wind). The trail always start with the colour of the particle, and changes according to ParticleColor (a red flame can become gray smoke, then fade away). Every sprite with mode 3 can leave a trail, and if the trail has a vector a single sprite could act as a mini-emitter (actually, I implemented that as a poor-man way to create emitters before adding the "Emitter" entity). By combining the two solution you could achieve complex effects (fire with smoke, for example)

What do you mean with "DoublebufferToTex"? Even with double buffering, rendering always happen on one buffer, not on two. You can render the same image on many textures using many times CameraToTex (with the same camera, if you want), then post-process the texture as you wish.


markcw(Posted 2015) [#89]
Ok thanks. One problem I found with SpriteRenderMode 3 is the sprites are scaled to always be the same size no matter the distance from the camera, I think this is a bug as I don't see why anyone would want this.

DoublebufferToTex was meant to be about using a second framebuffer object with GL_COLOR_ATTACHMENT1. It seems you need to use glDrawBuffers to draw multiple buffers as in beanage's fbo mod.


angros47(Posted 2015) [#90]
With SpriteRenderMode 3 sprites are rendered using GL_POINTS, and not all implementations of OpenGL act in the same way (older implementation don't even texture them). But usually this is not an issue for particles.

As far as I know, usually a buffer is rendered on a simple quad mesh for post-processing (it's not the most efficient way, but it's the most compatible solution)


Hezkore(Posted 2015) [#91]
Hey I haven't been able to pin point the exact problem here.
But for some reason when I use flag 64 with LoadTexture it affects other textures as well. (Flag 64 is Spherical environment map)
When I load a texture with it and then use BrushTexture() and PaintSurface(), it seems to apply to a lot of other textures as well.
It doesn't do that when I use original MiniB3D.

It's like it doesn't reset sometimes, for some reason, and keeps it on.




angros47(Posted 2015) [#92]
Maybe it's my mistake... I never tried using it on entities with many surfaces/textures.

in the file "mesh.cpp", locate the lines:

			if (DisableCubeSphereMapping!=0){
				glDisable(GL_TEXTURE_CUBE_MAP);
				glDisable(GL_TEXTURE_GEN_S);
				glDisable(GL_TEXTURE_GEN_T);
				glDisable(GL_TEXTURE_GEN_R);
				DisableCubeSphereMapping=0;
			}


and remove the line "DisableCubeSphereMapping=0;"

Please tell me as soon as possible if that fixed the issue.


Hezkore(Posted 2015) [#93]
I'll give it a go as soon as munch updates the source! :)

And while I'm here I might as well ask...
Is there a way to pass raw GL blend functions?
I'm reading the the Quake 3 shaders and it's throwing me a lot of "GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA" and such.
It'd be nice if I could just apply that directly to a texture instead of trying to figure out what it is via the built-in TextureBlend modes.
Something like TextureBlendGL(texture:TTexture,source:int,destination:int)


angros47(Posted 2015) [#94]
It's a nice idea, and I was thinking to add something similar in the next version: maybe a material could have two callback functions (one to enable, one to disable parameters)


markcw(Posted 2015) [#95]
Well I tried to reproduce this but wasn't able to. I just made two cubes in one mesh and applied a spheremap to one and normal texture to the other. So I've just added the fix by Angros to the repo as requested but I don't see why you can't just edit the C++ yourself for this Hezkore.


Hezkore(Posted 2015) [#96]
@munch I honestly didn't know I could just edit the source.
I thought I would have to compile much more than the module then.

@angros47 Your fix works! \o/
And about the Quake 3 shaders.
They're not "real" shaders, they don't use LoadShader or anything like that. (that was too slow anyways)
So if TextureBlendGL gets implemented, I'd like it outside of the shader part.

Oh and btw, is there a way to quickly load a shader multiple times?
I have a bunch of surfaces that all use the same shader but with different textures, and doing LoadShader for each surface takes forever.


markcw(Posted 2015) [#97]
Well, no the module is independent from anything other than brl, pub and maxgui modules, openb3dlib has the c++ library and openb3d has the bmx wrapper.

Do you know how to use BMK as explained in "users guide/bmk" or do you just use "build modules"? That works but I prefer commandline. If you don't then all you do is open cmd/terminal, type "cd blitzmax/bin" ("cd ../" goes up a directory) then "bmk makemods -a -d openb3d" prefixing with "./" if in unix which builds only debug mode. If you want both debug and release just use "bmk makemods -a openb3d" but it's slower.


angros47(Posted 2015) [#98]
In OpenB3D a "material" is more than a shader, since it contains the vertex shader, the fragment shader, and the textures: it could contain only shaders, or only textures (i.e. to use a 3d texture you have to use materials); so, I don't see any reason why it shouldn't contain a callback function, too.

Maybe I could add a "UseTexture" command, to use entity textures in shader instead of material textures (so the same shader could work with many entities and different textures)... I'll have a look at it.


Hezkore(Posted 2015) [#99]
Thanks for all the help guys!

I think I've found another issue, this time with BrushFX 16, disable backface culling and BrushBlend 6, additive.
It works fine but only on the faces that would normally be culled!



UPDATE: False alarm, it was all my fault!
I had another face overlaying it, sorry guys. :)

Once again, thanks for all the help.


markcw(Posted 2015) [#100]
Oh good! :)

Nice art Hezkore. By the way couldn't you just use a sprite for the fire? I never used 2 quads like that, what's the technique called?


Hezkore(Posted 2015) [#101]
The art is from Quake 3, infact the whole level is loaded directly from the Quake 3 BSP files.
So I haven't actually made the fire, just loaded it from the Quake 3 level file.
Krischan posted a BSP loader and I'm trying to improve on it by adding most of the unsupported stuff, like the texture scripts/shaders that Quake 3 uses and some special geometry.
But it's very hard when the texture scripts use blending functions like "gl_dst_color gl_zero" and you can't really get those effects with just the 3 different BrushBlend() modes.
All I really can get to work as it should is the additive stuff.
That's why I suggested TextureBlendGL or BrushBlendGL or just SurfaceBlendGL so that I could get the correct effects.


markcw(Posted 2015) [#102]
Ok I have added a new function SurfaceGLBlendFunc(surf,sfactor,dfactor) with example. It seems to work fine. I probably should add SurfaceFX and SurfaceAlpha instead of using the pointers.


Hezkore(Posted 2015) [#103]
Good work munch!

I've give it a go now, but I can't seem to get the results I want...
Maybe what I'm asking for is really advanced or something, I don't know?

Basically the Quake 3 texture scripts layers textures above each other, and each texture has its own blending mode for how it should blend with the previous texture.
Or in the case of the first/bottom texture, how it blends with the background/rest of the world.

So what I've done is created a new surface for each layered texture and then applied SurfaceGLBlendFunc to that surface.
But it doesn't seem to blend with whatever's under it.

I've created an example here showing the issue - blendtest.zip
When you first run it, it's going to look just fine.
And what's how I want it to look!
But you can uncomment Attempt 1 and 2, which uses SurfaceGLBlendFunc, and see that it doesn't quite work the same way.
Attempt 2 would be the best way since I wouldn't have to make a bunch of surfaces ontop of each other. (way better FPS)
But for that I would need BrushGLBlendFunc.
What am I doing wrong?

As I said, it might be that what I'm asking for is something really advanced that needs a real beefy 3D engine, I don't know, I'm not that good at 3D in general.
But it seemed so easy when I read the texture scripts and it just said how each texture would blend with the next one.


markcw(Posted 2015) [#104]
Hezkore, I realize you need access to brush and surface so I changed it to BrushGLBlendFunc and then just pass surf.brush to it. I also added TextureGLTexEnv for a TextureBlend equivalent, it allows up to 12 TexEnv calls per texture and the counter can be reset if the 2nd parameter is void (or zero). I couldn't get an add blend working with your TextureBlend example, this TexEnv stuff can get very complex. The only thing similar I could get was alpha+multiply. Also you need to set fx=32 or alpha<1 for BlendFunc to work. Here is my changes to your code. And you don't need to use brush.blend[0] just use BrushBlend(), same for BrushAlpha().




Hezkore(Posted 2015) [#105]
Hmm I'm still having some problems with BrushGLBlendFunc.
Try for example GL_DST_COLOR, GL_SRC_ALPHA which should look like this:



But looks like this:



Everything ALMOST works, but it seems the background messes up all the time for some reason.


markcw(Posted 2015) [#106]
You need to set the glColor to 0 for that mode to work, it defaults to 1. I also was able to get the same mode with glTexEnv but I don't really understand it. Changes below.




Hezkore(Posted 2015) [#107]
Ah cool, I'll do some experimenting with this.
Thanks a bunch!

Btw. why doesn't .copy() from TSurface return a copy of the surface?


markcw(Posted 2015) [#108]
Okay. As far as I tested (just a valid instance), the surface.copy() method works.


Hezkore(Posted 2015) [#109]
Hmm I'm trying to copy a surface to another mesh, but no matter what I do it ends up being different (odd vert positions) than the original.
100% sure it's my fault though.
There's no function for something like that, is there?


markcw(Posted 2015) [#110]
I tried out a proper surface.copy and you're right it's not working but I wonder how you got any results since the copied surface needs to be added to the mesh surf_list before it works. The code that works in minib3d max2d.bmx is:
Local teapot1:TMesh=LoadMesh("../media/teapot.b3d")
Local surf:TSurface=GetSurface(teapot1,1)
Local surf2:TSurface=surf.copy()
Local teapot:TMesh=CreateMesh()
ListAddLast teapot.surf_list,surf2


I need an equivalent to ListAddLast which will be ListPushBack teapot.surf_list,surf2[,teapot]. I will also internalize CopyList.

About BrushGLBlendFunc. I've been testing with THIS and can see the results are different. I added the same function to minib3d and got the same results so it's not really a bug although I don't understand why it works so differently, but I will see how many blend modes I can get.


markcw(Posted 2016) [#111]
I had a few bugs to fix but have got it working! I just need to internalize copylist now.

I improved the copylist c++ code, it needed to loop through all items to reset the counter which might cause trouble if anything other than a full copy is done, so now you can break out of a loop since the counter is a global and gets reset in the size functions.

I have listpushback working tested on child_list and surf_list. I've tested some lists but not all, I'll need to do that. I should have an update soon. :)


Hezkore(Posted 2016) [#112]
Wow, awesome munch!!
Is it possible to get a CopySurface(surface,toMesh) function of some sort?

Thanks for your hard work.


markcw(Posted 2016) [#113]
Thanks Hezkore. Your feedback has been great by the way, it's really pushed the progress forward so thanks. It's really getting to a stable stage now.

Yes, I see why CopySurface is nice. Looking at the types with copy methods, it would be nice to have CopyBrush too.

Edit: oh wait, I think I know what you mean now, like this:
Local teapot:TMesh=LoadMesh("../media/teapot.b3d")
Local surf:TSurface=GetSurface(teapot,1)
...
Local teapot2:TMesh=CreateMesh()
Local surf2:TSurface=CopySurface(surf,teapot2)
...instead of...
Local surf2:TSurface=surf.copy()
Local teapot2:TMesh=CreateMesh()
ListPushBack teapot2.surf_list,surf2,teapot2


I had a bit of trouble with getting these lists working nicely, first I had to discover that in c++ I was forgetting to use a break after a nested switch case (causing code to 'break' he he), then I forgot to reset the global list index in some size functions, and then I missed that I shouldn't call ClearList after a Super.CopyList in CopyList. Those things cost me several hours of wasted time!


Hezkore(Posted 2016) [#114]
Yeah the engine/wrapper is turning out great!
And I'm glad to know I'm helping, I wasn't sure if I was helping or just in the way by bugging you about every little thing I find hehe.

I've been hoping this project wouldn't get abandoned like all other 3D engine projects.
And all your hard work (and angros of course!) has really shown that you guys are dedicated to finishing up this engine!

I'm slowly but surely trying out everything I need to get a game going in this engine.
Atm. I'm making sure that I can get some decent levels loaded into it.
Next step is to get animated models loaded, and that step has gotten me a bit worried.
I know there are no plans to support loading other model file formats, but do you guys have any suggestions on how I could get animated models from Maya into this engine?
I've been asking this a lot but I still haven't managed to get it fully working.

And yes, the CopySurface example is exactly what I had in mind. :)


Krischan(Posted 2016) [#115]
I've reviewed the current version yesterday - it looks very nice at the current stage but I have two issues with the Geosphere in which I'm most interested for my space game, but first an impressive shot with a 2048 pixel wide height/colormap at close distance:



Now to the problems:

1. there is a clear UV glitch in the texture mapping, see screenshot. The heightmap has the same problem, looks like the Starkiller base in the new Star Wars movie. Use these two textures and this nearly vanilla code to check it yourself: hm.jpg cm.jpg





2. Would it be possible to use a Cubemap Cross instead of a Spheremap? As you know, a Spheremap has pinched poles, lesser information and it's hard to subdivide with detail noise to get a really detailed planet. Without cubemaps the use of geospheres is very limited if you want high quality subdivided planets.



By the way, my new planet generation algorithm creates cube heightmap gems like this one in a few seconds :-) The two spheremaps above were generated out of this one and in a cube colormap it would look like this one (with a small stiching problem I couldn't figure out yet).


angros47(Posted 2016) [#116]
Internally geosphere.cpp doesn't use a sphere map or a cube map; it uses a format called TOAST projection (Tessellated Octahedral Adaptive Subdivision Transform); I got the idea from here:

http://www.worldwidetelescope.org/docs/worldwidetelescopeprojectionreference.html

The map should be like this one:


Unfortunately, how many heightmap can you find in this format? About 0. Either you create your one, or use another solution, since most heightmaps are distributed as equirectangular projections. So, I chose to use equirectangular format, and I added a simple routine that convert the height map into a TOAST projection when it is loaded. There are other ways to project a sphere map (i.e. Mercator), but they all have some flaws (i.e. in a Mercator map poles cannot be represented); equirectangular is the simplest one, and it has already been used in OpenB3D (and even in original Blitz3D) to texture spheres.

Also, a cubemap cross is the worst way to store a texture or an heightmap: an image file is always a rectangle, and look at the example you posted: you have 6 faces at a resolution 1024*1024 (total=6291456 pixels) and your image is 4096*3072 (total=12582912 pixels): it uses exactly twice the memory (and a planetary map can be a BIG image, you aren't allowed to store it in an inefficient way).

Also, cubemaps used with LoadTexture command are not stored as crosses, but as strips, so it would not be consistent. IMHO, you should modify your algorithm to output equirectangular images (or, if you are feeling brave, you could try to directly output a TOAST projection and directly store it inside the geosphere class)

The glitch happens because on a TOAST projection this line coincide with map border; I always considered it a minor glitch, because I ran all my tests using an earth map, and on earth that line fell in the ocean. I'll see if I can fix it.


Krischan(Posted 2016) [#117]
I never saw this projection before, interesting. And yes, I know that the cubemap cross is suboptimal, my generator puts out 6 separate textures but in a cross you can view them better and get an idea how the planet looks like - internally I can make whatever I want with them. A cubemap cross always contains six quadratic textures. But I'll still prefer a cubemap over other projection styles as it still stores the most information by a minimal cost of distortion as far as I know and you can manipulate it very easy as its - quadratic/cubic! Forget about spherical projections, I only use them for small survey maps calculated from the cubemap information.

So please add cubemap support for your geospheres. I would like to create something like this with it:




markcw(Posted 2016) [#118]
Hi Angros, I think it would be *really* cool if OpenB3d supported back to OpenGL 1.4. Have you any interest in this?

I have two old MacBooks that are limited to 1.4 and I would love to run OpenB3d on them. Here is a thread discussing it.


angros47(Posted 2016) [#119]
@Krischan
To achieve a LOD spherical terrain there are two possible approaches: one is the geodesic sphere, the other is the quadrilateralized spherical cube.

In a quadrilateralized spherical cube, you start from a cube, subdivide it into 12 right triangles, and recursively split each triangle in two other right triangles (the same algorithm used in regular terrains).

In a geodesic sphere, you start from a platonic solid (usually an icosahedron, but a tetrahedron or an octahedron are just as good), subdivide it into 4, 8, 20 equilateral triangles, and then recursively split each triangle into four equilateral triangles.

Internally, OpenB3D uses the geodesic sphere (shortened in GeoSphere) approach, because I find it to be the best solution to avoid cracks (with no need to use skirts or other "dirty" tricks)

In quadrilateralized spherical cube, a cubemap would be the best solution to store the textures; in a geosphere, the best solution is to use a texture tailored for the starting platonic solid; for an icosahedron, it would be something like:



since it's still suboptimal, I looked for alternatives: as I've said, there is no need to start with an icosahedron, any platonic solid will work, and an octahedron is easier to texture: the top of the octahedron can be projected to a square, the bottom can be mapped to four right triangles (with just a slight distortion)... and all the geosphere can be mapped on a single, square picture (hence the TOAST projection).

Since, as I've said, you can't find many maps in this format, the loader must convert the map from a more common format; which one? Well, have a look on wikipedia:

https://en.wikipedia.org/wiki/List_of_map_projections

There are about 80 different formats, and each one has advantages and disadvantages.

To be able to load other formats a converter to TOAST would be needed... something like this:

http://jonaszeitler.se/cubemap-toastmap-generator/

I don't think it's a good idea to put in into the library... but it could be an extension.

@munch
What do you mean? OpenGL 1.4 uses fixed function pipeline, and OpenB3D should work perfectly on it, as long as you don't use custom shaders.

In the thread you linked, they said that shader support in 1.4 is an extension, so it's not official: it means that different implementations might support different features, so your shader might work perfectly on a computer, and crash on another (even if it still has version 1.4).

Even worse, most of the GLSL features in 1.4 are deprecated (like the gl_Vertex, gl_Color attributes), so you'd have to rewrite most of your program anyway.

And shaders are not like multitexturing, that just didn't work on some version, without harm (if you try to use a multi-texture mesh with a very old driver version, you will see only the first texture, but the program still run); with shaders, if you dare to use even one feature on a driver not supporting it, the whole program crashes (or becomes unusable).


Thareh(Posted 2016) [#120]
Nice stuff, I'm currently having some fun playing around with this! :)

One thing I can't get to work is playing an animation backwards though (with negative speed), is this broken or am I doing something wrong? =P

Thanks!


markcw(Posted 2016) [#121]
It works here in the examples for b3d and md2. Are you using SetAnimTime?


markcw(Posted 2016) [#122]
I know there are no plans to support loading other model file formats, but do you guys have any suggestions on how I could get animated models from Maya into this engine?

Googling this it seems there are two ways:
Use Maya 8.5 and the Maya Blitz3D Exporter v2
Or I think the best bet, to export to FBX (v 2010) and use FragMotion to export b3d as in Irrlicht Engine.
Milkshape3d also support FBX but not sure if it has fbx 2010.


Hezkore(Posted 2016) [#123]
Ah! I haven't tried the FragMotion way before, I'll give that a go.
Thanks!

Any news about the CopySurface function?


Thareh(Posted 2016) [#124]
It works here in the examples for b3d and md2. Are you using SetAnimTime?

Alright, nope I'm using the Animate command - it works very well playing the animation in a normal fashion but backwards the animation just freezes =P

Should I stop using the Animate command and start using SetAnimTime instead?

Thanks,
-- Thareh


Krischan(Posted 2016) [#125]
Angros, my Planet Generator currently works like this:

- Load 2-3 alpha faded Heightmaps with Craters, Hills, Cracks etc. as Textures
- Place a few hundred Sprites spherical around the Camera, pointing to it
- The sprites are textured and scaled randomly and blended to overlap
- With a certain amount of Sprites, a detailed Planet Surface "forms"
- Grab six Camera views: Front, Right, Back, Left, Top, Bottom with FoV=90°
- Normalize the greyscale values to 0...255 = Heightmap
- Apply a color gradiant to the six images using the height information = Colormap
- Optional: calculate a Spheremap out of the 6 Heightmaps
- Optional: calculate a Normalmap out of the 6 Heightmaps
- Optional: Emboss the Colormap / Spheremap = polish

This method has the disadvantage that you can't zoom in very much as I always have only 256 height steps and the detail depends on the resolution of the source heightmaps. But... the speed is priceless. I can create a detailed Planet Texture like above (2048x1024 from 6x512x512 sides) in 750ms without any shader support. I tried many methods to achieve results like that but they were either too slow or too complex (with GPU shaders I don't understand right now). And I want to avoid additional Layers of complexity. Well, for a CLOD planet like in the video above I must subdivide or mix the cubefaces with Simplex Noise to get more details when approaching the surface.

So my base/source are six Cube-Height-Maps. How would you achieve this?


markcw(Posted 2016) [#126]
Hezkore, yes I have CopySurface working, it's just surf.copy and then listpushback. I'm currently stuck on internalizing copylist, I need an addlist for optimizing performance.


Thareh(Posted 2016) [#127]
I tried the included "zombie.b3d" now as well, and backwards animation doesn't work with that either =P and also I don't think the "transition" parameter works as intended on the Animation command as well, it's supposed to smooth the transition between the last frame and the first frame when looping the animation if I understand it correctly? Right now it just creates a delay before the first frame the first time the animation runs =P

Perhaps this is just on my computer?

Thanks,
-- Thareh


Hezkore(Posted 2016) [#128]
Is there any way to rotate a clamped texture around its center instead of top left?
What I've done is used VertexTexCoords and offset U and V with -0.5
And then with PositionTexture I've done done +0.5
Which works with textures that aren't clamped.
But with a clamped texture I just get a blurry mess.

UPDARTE: Managed to get it working.
But now to another question...
Is it possible to set a Texture brightness/color?

And another question.
Is it possible to change a texture in a brush realtime?
I've loaded about 6 or so textures, and I've painted a mesh with a brush and I'd like to switch out texture[0] in the brush to one of the 6 textures I've loaded.


Hezkore(Posted 2016) [#129]
I've made an example of my brush texture switching issue I mentioned above - textest.zip
Pressing Key 1 switches to the first texture, while pressing 2 or 3 switches to the second texture.
It seems to register that the texture is switched (since it doesn't scroll anymore) but the image isn't updated.
The method I've used for Key 3 works with MiniB3D.


angros47(Posted 2016) [#130]
Here is the patched version of Geosphere.cpp. It should fix both the texturing issue and the "Starkiller" bug. I have to do some more tests.

/*
 *  geosphere.cpp
 *  openb3d
 *
 *
 */

#ifdef linux
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#endif

#ifdef WIN32
#include <gl\GLee.h>
#endif

#ifdef __APPLE__
#include "GLee.h"
#endif


#include "global.h"
#include "entity.h"
#include "camera.h"
#include "brush.h"
#include "geosphere.h"
#include "pick.h"


#include "stb_image.h"
#include "string_helper.h"
#include "file.h"
#include "tree.h"


static Line Ray;
static float radius;

static vector<float> vertices;


Geosphere* Geosphere::CopyEntity(Entity* parent_ent){

	// new terr
	Geosphere* geo=new Geosphere;

	// copy contents of child list before adding parent
	list<Entity*>::iterator it;
	for(it=child_list.begin();it!=child_list.end();it++){
		Entity* ent=*it;
		ent->CopyEntity(geo);
	}

	// lists

	// add parent, add to list
	geo->AddParent(*parent_ent);
	entity_list.push_back(geo);

	// add to collision entity list
	if(collision_type!=0){
		CollisionPair::ent_lists[collision_type].push_back(geo);
	}

	// add to pick entity list
	if(pick_mode){
		Pick::ent_list.push_back(geo);
	}

	// update matrix
	if(geo->parent){
		geo->mat.Overwrite(geo->parent->mat);
	}else{
		geo->mat.LoadIdentity();
	}

	// copy entity info

	geo->mat.Multiply(mat);

	geo->px=px;
	geo->py=py;
	geo->pz=pz;
	geo->sx=sx;
	geo->sy=sy;
	geo->sz=sz;
	geo->rx=rx;
	geo->ry=ry;
	geo->rz=rz;
	geo->qw=qw;
	geo->qx=qx;
	geo->qy=qy;
	geo->qz=qz;

	geo->name=name;
	geo->class_name=class_name;
	geo->order=order;
	geo->hide=false;

	geo->cull_radius=cull_radius;
	geo->radius_x=radius_x;
	geo->radius_y=radius_y;
	geo->box_x=box_x;
	geo->box_y=box_y;
	geo->box_z=box_z;
	geo->box_w=box_w;
	geo->box_h=box_h;
	geo->box_d=box_d;
	geo->collision_type=collision_type;
	geo->pick_mode=pick_mode;
	geo->obscurer=obscurer;

	//copy terrain info
	geo->brush=brush;

	geo->ShaderMat=ShaderMat;
	//geo->EqToToast=0;


	geo->size=size;
	geo->vsize=vsize;
	geo->hsize=hsize;
	for (int i = 0; i<= ROAM_LMAX+1; i++){
		geo->level2dzsize[i] = level2dzsize[i];
	}
	int tsize=size;
	geo->height=new float[(tsize+1)*(tsize+1)];
	for (int i = 0; i<= (tsize+1)*(tsize+1); i++){
		geo->height[i]=height[i];
	}
	geo->NormalsMap=new float[(tsize+1)*(tsize+1)*5];
	for (int i = 0; i<= (tsize+1)*(tsize+1)*5; i++){
		geo->NormalsMap[i]=NormalsMap[i];
	}

	mesh_info=C_NewMeshInfo();
	geo->c_col_tree=C_CreateColTree(mesh_info);
	C_DeleteMeshInfo(mesh_info);

	terrain_list.push_back(geo);


	return geo;

}

Geosphere* Geosphere::CreateGeosphere(int tsize, Entity* parent_ent){

	Geosphere* geo=new Geosphere;

	for (int i = 0; i<= ROAM_LMAX; i++){
		geo->level2dzsize[i] = 0;
	}
        int lmax=(int)(log(tsize)/log(2)-3.0);
	if (lmax>=ROAM_LMAX) lmax=ROAM_LMAX;


	const float LOD[20]={1700000,800000,40000,10000,5000,1000,200,10,1,0.1,0.005,
	0.001,0.0005,0.0002,0.0001,0.00005,0.00002,0.00001,0.000005,0.000002};

	for (int i = 0; i<= lmax; i++){
		geo->level2dzsize[i] = tsize*LOD[i];/*1000000000.0*(float)pow((float)tsize/8192 / sqrt((float)(1 << i)),2);	// <-------------terrain detail here*/
	}

	geo->ShaderMat=Global::ambient_shader;
	//geo->EqToToast=0;

	//terr->brush=new brush;
	mesh_info=C_NewMeshInfo();
	geo->c_col_tree=C_CreateColTree(mesh_info);
	C_DeleteMeshInfo(mesh_info);
	geo->AddParent(*parent_ent);
	terrain_list.push_back(geo);
	if (tsize!=0){
		geo->size=tsize/2;
		geo->hsize=tsize/4;

		geo->vsize=.05;
		geo->height=new float[(tsize+1)*(tsize+1)];
		geo->NormalsMap=new float[(tsize+1)*(tsize+1)*5];

		geo->EquirectangularToTOAST();

	}

	return geo;

}

void Geosphere::UpdateTerrain(){

	glBindBuffer(GL_ARRAY_BUFFER,0);

	RecreateGeoROAM();

	glDisable(GL_ALPHA_TEST);

	if (order!=0){
		glDisable(GL_DEPTH_TEST);
		glDepthMask(GL_FALSE);
	}else{
		glEnable(GL_DEPTH_TEST);
		glDepthMask(GL_TRUE);
	}

	switch(brush.blend){
		case 0:
			glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); // alpha
			break;
		case 1:
			glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); // alpha
			break;
		case 2:
			glBlendFunc(GL_DST_COLOR,GL_ZERO); // multiply
			break;
		case 3:
			glBlendFunc(GL_SRC_ALPHA,GL_ONE); // additive and alpha
			break;
		}

	float ambient_red,ambient_green,ambient_blue;

	// fx flag 1 - full bright ***todo*** disable all lights?
	if (brush.fx & 1){
		if(Global::fx1!=true){
			Global::fx1=true;
			glDisableClientState(GL_NORMAL_ARRAY);
		}
		ambient_red  =1.0;
		ambient_green=1.0;
		ambient_blue =1.0;
	}else{
		if(Global::fx1!=false){
			Global::fx1=false;
			glEnableClientState(GL_NORMAL_ARRAY);
		}
		ambient_red  =Global::ambient_red;
		ambient_green=Global::ambient_green;
		ambient_blue =Global::ambient_blue;
	}

	// fx flag 2 - vertex colours
	/*if(brush.fx&2){

			glEnable(GL_COLOR_MATERIAL);
	}else{
			glDisable(GL_COLOR_MATERIAL);
	}*/
	if(Global::fx2!=false){
		Global::fx2=false;
		glDisableClientState(GL_COLOR_ARRAY);
		glDisable(GL_COLOR_MATERIAL);
	}


	// fx flag 4 - flatshaded
	if(brush.fx&4){
		glShadeModel(GL_FLAT);
	}else{
		glShadeModel(GL_SMOOTH);
	}

	// fx flag 8 - disable fog
	if(brush.fx&8){
		if(Global::fog_enabled==true){ // only disable if fog enabled in camera update
			glDisable(GL_FOG);
		}
	}

	// fx flag 16 - disable backface culling
	if(brush.fx&16){
		glDisable(GL_CULL_FACE);
	}else{
		glEnable(GL_CULL_FACE);
	}

	// light + material color

	float ambient[]={ambient_red,ambient_green,ambient_blue};
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient);

	float mat_ambient[]={brush.red,brush.green,brush.blue,brush.alpha};
	float mat_diffuse[]={brush.red,brush.green,brush.blue,brush.alpha};
	float mat_specular[]={brush.shine,brush.shine,brush.shine,brush.shine};
	float mat_shininess[]={100.0}; // upto 128

	glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,mat_ambient);
	glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,mat_diffuse);
	glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
	glMaterialfv(GL_FRONT_AND_BACK,GL_SHININESS,mat_shininess);

	// textures

	int tex_count=0;

	if(ShaderMat!=NULL){
		ShaderMat->TurnOn(mat, 0, &vertices);
	}

	tex_count=brush.no_texs;

	int DisableCubeSphereMapping=0;
	for(int ix=0;ix<tex_count;ix++){

		if(brush.tex[ix]){

			// Main brush texture takes precedent over surface brush texture
			unsigned int texture=0;
			int tex_flags=0,tex_blend=0;
			float tex_u_scale=1.0,tex_v_scale=1.0,tex_u_pos=0.0,tex_v_pos=0.0,tex_ang=0.0;
			int tex_cube_mode=0;


			texture=brush.cache_frame[ix];
			tex_flags=brush.tex[ix]->flags;
			tex_blend=brush.tex[ix]->blend;
			//tex_coords=brush.tex[ix]->coords;
			tex_u_scale=brush.tex[ix]->u_scale;
			tex_v_scale=brush.tex[ix]->v_scale;
			tex_u_pos=brush.tex[ix]->u_pos;
			tex_v_pos=brush.tex[ix]->v_pos;
			tex_ang=brush.tex[ix]->angle;
			tex_cube_mode=brush.tex[ix]->cube_mode;
			//frame=brush.tex_frame;

			glActiveTexture(GL_TEXTURE0+ix);
			glClientActiveTexture(GL_TEXTURE0+ix);

			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D,texture); // call before glTexParameteri

			// masked texture flag
			if(tex_flags&4){
				glEnable(GL_ALPHA_TEST);
			}else{
				glDisable(GL_ALPHA_TEST);
			}

			// mipmapping texture flag
			if(tex_flags&8){
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
			}else{
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
			}

			// clamp u flag
			if(tex_flags&16){
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
			}else{
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
			}

			// clamp v flag
			if(tex_flags&32){
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
			}else{
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
			}

				// ***!ES***

			// spherical environment map texture flag
			if(tex_flags&64){
				glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
				glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
				glEnable(GL_TEXTURE_GEN_S);
				glEnable(GL_TEXTURE_GEN_T);
				DisableCubeSphereMapping=1;
			}/*else{
				glDisable(GL_TEXTURE_GEN_S);
				glDisable(GL_TEXTURE_GEN_T);
			}*/

				// cubic environment map texture flag
				if(tex_flags&128){

					glEnable(GL_TEXTURE_CUBE_MAP);
					glBindTexture(GL_TEXTURE_CUBE_MAP,texture); // call before glTexParameteri

					glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
					glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
					glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);
					glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
					glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MAG_FILTER,GL_NEAREST);

					glEnable(GL_TEXTURE_GEN_S);
					glEnable(GL_TEXTURE_GEN_T);
					glEnable(GL_TEXTURE_GEN_R);
					//glEnable(GL_TEXTURE_GEN_Q)

					if(tex_cube_mode==1){
						glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_REFLECTION_MAP);
						glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_REFLECTION_MAP);
						glTexGeni(GL_R,GL_TEXTURE_GEN_MODE,GL_REFLECTION_MAP);
					}

					if(tex_cube_mode==2){
						glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_NORMAL_MAP);
						glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_NORMAL_MAP);
						glTexGeni(GL_R,GL_TEXTURE_GEN_MODE,GL_NORMAL_MAP);
					}
					DisableCubeSphereMapping=1;

				}else  if (DisableCubeSphereMapping!=0){

					glDisable(GL_TEXTURE_CUBE_MAP);

					// only disable tex gen s and t if sphere mapping isn't using them
					if((tex_flags & 64)==0){
						glDisable(GL_TEXTURE_GEN_S);
						glDisable(GL_TEXTURE_GEN_T);
					}

					glDisable(GL_TEXTURE_GEN_R);
					//glDisable(GL_TEXTURE_GEN_Q)

				}


			switch(tex_blend){
				case 0: glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
				break;
				case 1: glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
				break;
				case 2: glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
				//case 2 glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB_EXT,GL_MODULATE);
				break;
				case 3: glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_ADD);
				break;
				case 4:
					glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
					glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_DOT3_RGB_EXT);
					break;
				case 5:
					glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
					glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_MODULATE);
					glTexEnvi(GL_TEXTURE_ENV,GL_RGB_SCALE,2.0);
					break;
				default: glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
			}

			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glTexCoordPointer(2,GL_FLOAT,32,&vertices[6]);


			// reset texture matrix
			glMatrixMode(GL_TEXTURE);
			glLoadIdentity();

			if(tex_u_pos!=0.0 || tex_v_pos!=0.0){
				glTranslatef(tex_u_pos,tex_v_pos,0.0);
			}
			if(tex_ang!=0.0){
				glRotatef(tex_ang,0.0,0.0,1.0);
			}
			if(tex_u_scale!=1.0 || tex_v_scale!=1.0){
				glScalef(tex_u_scale,tex_v_scale,1.0);
			}

			// ***!ES***
			// if spheremap flag=true then flip tex
			if(tex_flags&64){
				glScalef(1.0,-1.0,-1.0);
			}

			// if cubemap flag=true then manipulate texture matrix so that cubemap is displayed properly
			if(tex_flags&128){

				glScalef(1.0,-1.0,-1.0);

				// get current modelview matrix (set in last camera update)
				float mod_mat[16];
				glGetFloatv(GL_MODELVIEW_MATRIX,&mod_mat[0]);

				// get rotational inverse of current modelview matrix
				Matrix new_mat;
				new_mat.LoadIdentity();

				new_mat.grid[0][0] = mod_mat[0];
				new_mat.grid[1][0] = mod_mat[1];
				new_mat.grid[2][0] = mod_mat[2];

				new_mat.grid[0][1] = mod_mat[4];
				new_mat.grid[1][1] = mod_mat[5];
				new_mat.grid[2][1] = mod_mat[6];

				new_mat.grid[0][2] = mod_mat[8];
				new_mat.grid[1][2] = mod_mat[9];
				new_mat.grid[2][2] = mod_mat[10];

				glMultMatrixf(&new_mat.grid[0][0]);

			}


		}

	}

	// draw tris
	glMatrixMode(GL_MODELVIEW);

	glPushMatrix();
	glMultMatrixf(&mat.grid[0][0]);
	glVertexPointer(3,GL_FLOAT,32,&vertices[0]);
	glNormalPointer(GL_FLOAT,32,&vertices[3]);

	glDrawArrays(GL_TRIANGLES, 0, triangleindex*3);
	glPopMatrix();

	// disable all texture layers
	for(int ix=0;ix<tex_count;ix++){

		glActiveTexture(GL_TEXTURE0+ix);
		glClientActiveTexture(GL_TEXTURE0+ix);

		// reset texture matrix
		glMatrixMode(GL_TEXTURE);
		glLoadIdentity();

		glDisable(GL_TEXTURE_2D);

		// ***!ES***
		if (DisableCubeSphereMapping!=0){
			glDisable(GL_TEXTURE_CUBE_MAP);
			glDisable(GL_TEXTURE_GEN_S);
			glDisable(GL_TEXTURE_GEN_T);
			glDisable(GL_TEXTURE_GEN_R);
			//DisableCubeSphereMapping=0;
		}

	}
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);


	if (brush.fx&8 && Global::fog_enabled==true){
		glEnable(GL_FOG);
	}

	if(ShaderMat!=NULL){
		ShaderMat->TurnOff();
	}


}

void Geosphere::RecreateGeoROAM(){

	/*xcf = eyepoint->EntityX();
	ycf = eyepoint->EntityY();
	zcf = -eyepoint->EntityZ();*/

	TFormPoint(eyepoint->EntityX(true), eyepoint->EntityY(true), eyepoint->EntityZ(true), 0, this);
	xcf = tformed_x;
	ycf = tformed_y;
	zcf = -tformed_z;

	//int i;

	float h1= (height[(int)hsize*(int)size+ (int)hsize]*vsize+1)*size;
	float h2= (height[(int) size*(int)size+ (int)hsize]*vsize+1)*size;
	float h3= (height[(int)hsize*(int)size+ (int) size]*vsize+1)*size;
	float h4=-(height[(int)    0*(int)size+ (int)hsize]*vsize+1)*size;
	float h5=-(height[(int)hsize*(int)size]*vsize+1)*size;
	float h6=-(height[0]*vsize+1)*size;


	float v[9][5]={
	{ 0,  h1,  0, hsize, hsize},

	{ h2,  0,  0, size, hsize},
	{ 0,  0,  h3, hsize, size},
	{ h4,  0,  0, 1, hsize},
	{ 0,  0,  h5, hsize, 1},

	{ 0,  h6,  0, size, size},
	{ 0,  h6,  0, 1, size},
	{ 0,  h6,  0, 1, 1},
	{ 0,  h6,  0, size, 1}};



	// diamond radius - apply entity scale
	float rx=EntityScaleX(true);
	float ry=EntityScaleY(true);
	float rz=EntityScaleZ(true);
	if(rx>=ry && rx>=rz){
		dradius=abs(rx);
	}else if(ry>=rx && ry>=rz){
		dradius=abs(ry);
	}else{
		dradius=abs(rz);
	}


	//MQ_GetMatrix(tmat, true);


	triangleindex = 0;

	vertices.clear();

	geosub( 0, v[0], v[1], v[2]);
	geosub( 0, v[0], v[2], v[3]);
	geosub( 0, v[0], v[3], v[4]);
	geosub( 0, v[0], v[4], v[1]);

	geosub( 0, v[2], v[1], v[5]);
	geosub( 0, v[3], v[2], v[6]);
	geosub( 0, v[4], v[3], v[7]);
	geosub( 0, v[1], v[4], v[8]);




}

void Geosphere::geosub(int l, float v2[], float v1[], float v0[]){

	float vc[3][5];			/* New (split) vertices */
	float ds;			/* maximum midpoint displacement */
	float dx,dy,dz;			/* difference vector */
	float rd;			/* squared sphere bound radius */
	float nx[3],ny[3], nz[3];
	float rc, rc0, rc1, rc2;	/* squared distance from vc To camera position */

	if (l < ROAM_LMAX) {
		ds = level2dzsize[l];

		/* compute radius of diamond bounding sphere (squared) */
		float x,y,z;
		x = (v0[0] + v1[0] + v2[0]) / 3;
		y = (v0[1] + v1[1] + v2[1]) / 3;
		z = (v0[2] + v1[2] + v2[2]) / 3;
		rd = 0.0;
		dx = v0[0] - x;
		dy = v0[1] - y;
		dz = v0[2] - z;
		rc = dx * dx + dy * dy + dz * dz;
		if (rc > rd) {rd = rc;}
		dx = v1[0] - x;
		dy = v1[1] - y;
		dz = v1[2] - z;
		rc = dx * dx + dy * dy + dz * dz;
		if (rc > rd) {rd = rc;}
		dx = v2[0] - x;
		dy = v2[1] - y;
		dz = v2[2] - z;
		rc = dx * dx + dy * dy + dz * dz;
		if (rc > rd) {rd = rc;}
		rd = sqrt(rd)*dradius;


		float vcx=x;
		float vcy=y;
		float vcz=-z;
		mat.TransformVec(vcx, vcy, vcz, 1);

		for (int i = 0 ;i<= 5; i++){
			float d = eyepoint->frustum[i][0] * vcx + eyepoint->frustum[i][1] * vcy - eyepoint->frustum[i][2] * vcz + eyepoint->frustum[i][3];
			if (d <= -rd) return;//{ds=ds/10; break;}
			//m = m << 1;
		}

		/* compute distance from split point To camera (squared) */
		/*dx = x - xcf;
		dy = y - ycf;
		dz = z - zcf;
		rc = dx*dx+dy*dy+dz*dz;*/
		nx[0]=(v0[0]+v1[0])/2;
		ny[0]=(v0[1]+v1[1])/2;
		nz[0]=(v0[2]+v1[2])/2;

		dx = nx[0] - xcf;
		dy = ny[0] - ycf;
		dz = nz[0] - zcf;
		rc0 = dx*dx+dy*dy+dz*dz;
		rc=rc0;

		nx[1]=(v1[0]+v2[0])/2;
		ny[1]=(v1[1]+v2[1])/2;
		nz[1]=(v1[2]+v2[2])/2;

		dx = nx[1] - xcf;
		dy = ny[1] - ycf;
		dz = nz[1] - zcf;
		rc1 = dx*dx+dy*dy+dz*dz;
		if (rc>rc1) {rc=rc1;}

		nx[2]=(v2[0]+v0[0])/2;
		ny[2]=(v2[1]+v0[1])/2;
		nz[2]=(v2[2]+v0[2])/2;

		dx = nx[2] - xcf;
		dy = ny[2] - ycf;
		dz = nz[2] - zcf;
		rc2 = dx*dx+dy*dy+dz*dz;
		if (rc>rc2) {rc=rc2;}



		/* If not error large on screen, recursively split */
		if (ds > rc) {/*<---------terrain detail here*/

			float d,h;
			/*float nx, ny, nz, d, h, ts;

			ts=size/(1<<l)*4.8;//size*size/l/l*11.973;
			ts*=ts;*/

			l++;

			/*nx=(v0[0]+v1[0])/2;
			ny=(v0[1]+v1[1])/2;
			nz=(v0[2]+v1[2])/2;

			dx = nx - xcf;
			dy = ny - ycf;
			dz = nz - zcf;
			rc = dx*dx+dy*dy+dz*dz+ts;*/


			vc[0][3]=(v0[3]+v1[3])/2; vc[0][4]=(v0[4]+v1[4])/2;
			h=height[(int)vc[0][3]*(int)size+ (int)vc[0][4]]*vsize+1;
			if (ds > rc0) {
				d=sqrt(nx[0]*nx[0]+ny[0]*ny[0]+nz[0]*nz[0])/(size)/h;
			}else{
				d=1;
			}
			vc[0][0]=nx[0]/d; vc[0][1]=ny[0]/d; vc[0][2]=nz[0]/d; 


			/*nx=(v1[0]+v2[0])/2;
			ny=(v1[1]+v2[1])/2;
			nz=(v1[2]+v2[2])/2;

			dx = nx - xcf;
			dy = ny - ycf;
			dz = nz - zcf;
			rc = dx*dx+dy*dy+dz*dz+ts;*/

			vc[1][3]=(v1[3]+v2[3])/2; vc[1][4]=(v1[4]+v2[4])/2;
			h=height[(int)vc[1][3]*(int)size+ (int)vc[1][4]]*vsize+1;
			if (ds > rc1) {
				d=sqrt(nx[1]*nx[1]+ny[1]*ny[1]+nz[1]*nz[1])/(size)/h;
			}else{
				d=1;
			}
			vc[1][0]=nx[1]/d; vc[1][1]=ny[1]/d; vc[1][2]=nz[1]/d; 


			/*nx=(v2[0]+v0[0])/2;
			ny=(v2[1]+v0[1])/2;
			nz=(v2[2]+v0[2])/2;

			dx = nx - xcf;
			dy = ny - ycf;
			dz = nz - zcf;
			rc = dx*dx+dy*dy+dz*dz+ts;*/

			vc[2][3]=(v2[3]+v0[3])/2; vc[2][4]=(v2[4]+v0[4])/2;
			h=height[(int)vc[2][3]*(int)size+ (int)vc[2][4]]*vsize+1;
			if (ds > rc2) {
				d=sqrt(nx[2]*nx[2]+ny[2]*ny[2]+nz[2]*nz[2])/(size)/h;
			}else{
				d=1;
			}
			vc[2][0]=nx[2]/d; vc[2][1]=ny[2]/d; vc[2][2]=nz[2]/d; 

			geosub(l, v0, vc[2], vc[0]);
			geosub(l, v1, vc[0], vc[1]);
			geosub(l, v2, vc[1], vc[2]);
			geosub(l, vc[2], vc[1], vc[0]);

			return;
		}

	 }

	float *n0, *n1, *n2;

	n0=&NormalsMap[5*(int)((int)v0[3]*(int)size+ v0[4])];
	n1=&NormalsMap[5*(int)((int)v1[3]*(int)size+ v1[4])];
	n2=&NormalsMap[5*(int)((int)v2[3]*(int)size+ v2[4])];

	vertices.push_back(v0[0]); vertices.push_back(v0[1]); vertices.push_back(v0[2]);
	vertices.push_back(n0[0]); vertices.push_back(n0[1]); vertices.push_back(n0[2]);
	vertices.push_back(n0[3]);
	vertices.push_back(n0[4]);


	vertices.push_back(v1[0]); vertices.push_back(v1[1]); vertices.push_back(v1[2]);
	vertices.push_back(n1[0]); vertices.push_back(n1[1]); vertices.push_back(n1[2]);
	vertices.push_back(n1[3]);
	vertices.push_back(n1[4]);


	vertices.push_back(v2[0]); vertices.push_back(v2[1]); vertices.push_back(v2[2]);
	vertices.push_back(n2[0]); vertices.push_back(n2[1]); vertices.push_back(n2[2]);
	vertices.push_back(n2[3]);
	vertices.push_back(n2[4]);

	triangleindex++;


}


void Geosphere::TOASTsub(int l, float v2[], float v1[], float v0[]){

	float vc[3][5];	/* New (split) vertices */

	if (l > 0) {
		l--;
		float nx, ny, nz, d;

		nx=(v0[0]+v1[0])/2;
		ny=(v0[1]+v1[1])/2;
		nz=(v0[2]+v1[2])/2;

		vc[0][3]=(v0[3]+v1[3])/2; vc[0][4]=(v0[4]+v1[4])/2;
		d=sqrt(nx*nx+ny*ny+nz*nz);
		vc[0][0]=nx/d; vc[0][1]=ny/d; vc[0][2]=nz/d; 


		nx=(v1[0]+v2[0])/2;
		ny=(v1[1]+v2[1])/2;
		nz=(v1[2]+v2[2])/2;

		vc[1][3]=(v1[3]+v2[3])/2; vc[1][4]=(v1[4]+v2[4])/2;
		d=sqrt(nx*nx+ny*ny+nz*nz);
		vc[1][0]=nx/d; vc[1][1]=ny/d; vc[1][2]=nz/d; 


		nx=(v2[0]+v0[0])/2;
		ny=(v2[1]+v0[1])/2;
		nz=(v2[2]+v0[2])/2;

		vc[2][3]=(v2[3]+v0[3])/2; vc[2][4]=(v2[4]+v0[4])/2;
		d=sqrt(nx*nx+ny*ny+nz*nz);
		vc[2][0]=nx/d; vc[2][1]=ny/d; vc[2][2]=nz/d; 

		TOASTsub(l, v0, vc[2], vc[0]);
		TOASTsub(l, v1, vc[0], vc[1]);
		TOASTsub(l, v2, vc[1], vc[2]);
		TOASTsub(l, vc[2], vc[1], vc[0]);

		return;
	}

	/*float ax,ay,az,bx,by,bz;
	float nx,ny,nz,ns;
	float h0,h1,h2;

	h0=height[(int)v0[3]*(int)size+ (int)v0[4]]*vsize+1;
	h1=height[(int)v1[3]*(int)size+ (int)v1[4]]*vsize+1;
	h2=height[(int)v2[3]*(int)size+ (int)v2[4]]*vsize+1;

	ax = h1*v1[0]-h0*v0[0];
	ay = h1*v1[1]-h0*v0[1];
	az = h1*v1[2]-h0*v0[2];
	bx = h2*v2[0]-h1*v1[0];
	by = h2*v2[1]-h1*v1[1];
	bz = h2*v2[2]-h1*v1[2];
	nx = ( ay * bz ) - ( az * by );
	ny = ( az * bx ) - ( ax * bz );
	nz = ( ax * by ) - ( ay * bx );
	ns = sqrt( nx * nx + ny*ny + nz*nz );
	if (ns != 0) ns = 1;
	nx /= ns;
	ny /= ns;
	nz /= ns;
	NormalsMap[5*(int)((int)v0[3]*(int)size+ v0[4])]=nx;
	NormalsMap[5*(int)((int)v0[3]*(int)size+ v0[4])+1]=ny;
	NormalsMap[5*(int)((int)v0[3]*(int)size+ v0[4])+2]=nz;

	NormalsMap[5*(int)((int)v1[3]*(int)size+ v1[4])]=nx;
	NormalsMap[5*(int)((int)v1[3]*(int)size+ v1[4])+1]=ny;
	NormalsMap[5*(int)((int)v1[3]*(int)size+ v1[4])+2]=nz;

	NormalsMap[5*(int)((int)v2[3]*(int)size+ v2[4])]=nx;
	NormalsMap[5*(int)((int)v2[3]*(int)size+ v2[4])+1]=ny;
	NormalsMap[5*(int)((int)v2[3]*(int)size+ v2[4])+2]=nz;*/


	float u,v;
	u=0.5f * (-1.0 +atan2( v0[2] , v0[0] ) * (-1 / M_PI ));
	v=acos( v0[1] ) * ( 1 / M_PI );
	NormalsMap[5*(int)((int)v0[3]*(int)size+ v0[4])+3]=u*size;
	NormalsMap[5*(int)((int)v0[3]*(int)size+ v0[4])+4]=v*size;

	u=0.5f * (-1.0 +atan2( v1[2] , v1[0] ) * (-1 / M_PI ));
	v=acos( v1[1] ) * ( 1 / M_PI );
	NormalsMap[5*(int)((int)v1[3]*(int)size+ v1[4])+3]=u*size;
	NormalsMap[5*(int)((int)v1[3]*(int)size+ v1[4])+4]=v*size;

	u=0.5f * (-1.0 +atan2( v2[2] , v2[0] ) * (-1 / M_PI ));
	v=acos( v2[1] ) * ( 1 / M_PI );
	NormalsMap[5*(int)((int)v2[3]*(int)size+ v2[4])+3]=u*size;
	NormalsMap[5*(int)((int)v2[3]*(int)size+ v2[4])+4]=v*size;

}



void Geosphere::ModifyGeosphere (int x, int y, float new_height){
	/*int width=size*2;		//Most accurate approach: it wastes a lot of memory
	if (EqToToast==0){	//First time: must create a look-up map to convert equirectangular coords to TOAST coords
		EqToToast=new int[(int)(size+1)*width];
		for (int y=0;y<size;y++){
			for (int x=0;x<size;x++){
				int x1=-NormalsMap[5*(x*(int)size+ y)+3]*2;
				int y1=NormalsMap[5*(x*(int)size+ y)+4];

				//geo->height[x*(int)geo->size+y]=((float)*(buffer+x1+y1*width))/255.0;
				if (x1+y1*width<0) {
					x1=0; y1=0;
				}
				EqToToast[x1+y1*width]=x*(int)size+y;
			}
		}
	}

	height[EqToToast[x+y*width]]=new_height;*/


	//Less accurate approach: some lines might be distorted, but for little changes on a map should be good enough

	float r=sqrt((x % (int)hsize)*(x % (int)hsize)+(hsize-(x % (int)hsize))*(hsize-(x % (int)hsize)))/hsize;


	if (x<hsize){
		if (y<=hsize){

			r=(r*(hsize-y)+1*y)/hsize;
			y=y/r;

			x=x* y/hsize;
			y=y-x;
		}else{
			r=(r*(y-hsize)+1*(2*hsize-y))/hsize;
			y=2*hsize-(2*hsize-y)/r;

			x=y-(x*(y-2*hsize)/hsize)-hsize;
			y=y-x;
		}
	}else if (x<hsize*2){
		x=hsize*2-x;
		if (y<=hsize){

			r=(r*(hsize-y)+1*y)/hsize;
			y=y/r;

			x=x* y/hsize;
			y=x-y;
		}else{

			r=(r*(y-hsize)+1*(2*hsize-y))/hsize;
			y=2*hsize-(2*hsize-y)/r;


			x=y-(x*(y-2*hsize)/hsize)-hsize;
			y=x-y;
		}
	}else if (x<hsize*3){
		x=x-hsize*2;
		if (y<=hsize){

			r=(r*(hsize-y)+1*y)/hsize;
			y=y/r;

			x=-x* y/hsize;
			y=-y-x;
		}else{
			r=(r*(y-hsize)+1*(2*hsize-y))/hsize;
			y=2*hsize-(2*hsize-y)/r;

			x=(x*(y-2*hsize)/hsize)+hsize-y;
			y=-y-x;
		}
	}else{
		x=hsize*4-x;
		if (y<=hsize) {

			r=(r*(hsize-y)+1*y)/hsize;
			y=y/r;

			x=-x* y/hsize;
			y=x+y;
		}else{
			r=(r*(y-hsize)+1*(2*hsize-y))/hsize;
			y=2*hsize-(2*hsize-y)/r;

			x=(x*(y-2*hsize)/hsize)+hsize-y;
			y=x+y;
		}
	
	}
	x+=hsize;
	y+=hsize;
	height[x+y*(int)size]=new_height;
}

void Geosphere::EquirectangularToTOAST (){
	/*for (int x=0; x<size*2; x++){
		for (int y=0; y<size; y++){
			int x1=x, y1=y;
			EquirectangularToTOAST (x1, y1);

			NormalsMap[5*(x1*(int)size+ y1)+3]=x/2;
			NormalsMap[5*(x1*(int)size+ y1)+4]=y;
		}
	}*/
	float v[9][5]={
	{ 0,  1,  0, hsize, hsize},
	{ 1,  0,  0, size, hsize},
	{ 0,  0,  1, hsize, size},
	{-1,  0,  0, 1, hsize},
	{ 0,  0, -1, hsize, 1},

	{ 0, -1,  0, size, size},
	{ 0, -1,  0, 1, size},
	{ 0, -1,  0, 1, 1},
	{ 0, -1,  0, size, 1}};

	int l=(int)(log(hsize)/log(2));

	TOASTsub( l, v[0], v[1], v[2]);
	TOASTsub( l, v[0], v[2], v[3]);
	TOASTsub( l, v[0], v[3], v[4]);
	TOASTsub( l, v[0], v[4], v[1]);

	TOASTsub( l, v[2], v[1], v[5]);
	TOASTsub( l, v[3], v[2], v[6]);
	TOASTsub( l, v[4], v[3], v[7]);
	TOASTsub( l, v[1], v[4], v[8]);

}

void Geosphere::UpdateNormals (int preserve){
		for (int y=0;y<size;y++){
			for (int x=0;x<size;x++){
				float theta=-M_PI*(NormalsMap[5*(x*(int)size+ y)+3]-hsize)/size*2;
				float phi=M_PI*(NormalsMap[5*(x*(int)size+ y)+4])/size;
				if (preserve==0){
					NormalsMap[5*(x*(int)size+ y)]=sin(phi) * cos(theta);
					NormalsMap[5*(x*(int)size+ y)+1]=cos(phi);
					NormalsMap[5*(x*(int)size+ y)+2]=sin(phi) * sin(theta);
				}else{
					float a,b,c, d,e,f;
					a=sin(phi) * cos(theta);
					b=cos(phi);
					c=sin(phi) * sin(theta);

					d=NormalsMap[5*(x*(int)size+ y)];
					e=NormalsMap[5*(x*(int)size+ y)+1];
					f=NormalsMap[5*(x*(int)size+ y)+2];

					NormalsMap[5*(x*(int)size+ y)]=a*e+c*d;
					NormalsMap[5*(x*(int)size+ y)+1]=b*e+f;
					NormalsMap[5*(x*(int)size+ y)+2]=c*e-a*d;

				}
			}
		}
}

Geosphere* Geosphere::LoadGeosphere(string filename,Entity* parent_ent){
	//filename=Strip(filename); // get rid of path info

	filename=File::ResourceFilePath(filename);
	/*if(File::ResourceFilePath(filename)==""){
		cout << "Error: Cannot Find Terrain: " << filename << endl;
		return NULL;
	}*/

	string filename_left=Left(filename,Len(filename)-4);
	string filename_right=Right(filename,3);

	//const char* c_filename_left=filename_left.c_str();
	//const char* c_filename_right=filename_right.c_str();

	Geosphere* geo;

	unsigned char* pixels;

	int width,height;

	pixels=stbi_load(filename.c_str(),&width,&height,0,1);   //Memory leak fixed by D.J.Peters

	short* tmpNormals=0;		//An equirectangular normal maps

	// all OK ?
	if (pixels!=NULL) {
		// work with a copy of the pixel pointer
		unsigned char* buffer=pixels;

		tmpNormals=new short[(width+1)*(height+1)*2];	// Build an equirectangular normals map, that will be used to build
								// the final normals map in TOAST projection.
		for (int x=1;x<=width;x++){
			for (int y=1;y<=height-2;y++){
				tmpNormals[2*(y*(int)width+x)]=((short)*(buffer+(x-1)+y*width)) - ((short)*(buffer+(x+1)+y*width));
				tmpNormals[2*(y*(int)width+x)+1]=((short)*(buffer+x+(y-1)*width)) - ((short)*(buffer+x+(y+1)*width));
			}
		}


		geo=Geosphere::CreateGeosphere(width, parent_ent);

		for (int y=0;y<geo->size;y++){
			for (int x=0;x<=geo->size;x++){
				int x1=geo->NormalsMap[5*(x*(int)geo->size+ y)+3]*2;
				int y1=geo->NormalsMap[5*(x*(int)geo->size+ y)+4];

				if (x1+y1*width<0) {
					x1=0; y1=0;
				}

				geo->height[x*(int)geo->size+y]=((float)*(buffer+x1+y1*width))/255.0;
				if (x<geo->size) {
					geo->NormalsMap[5*(x*(int)geo->size+ y)]=(float)tmpNormals[2*(y1*(int)width+x1)];
					geo->NormalsMap[5*(x*(int)geo->size+ y)+1]=256;
					geo->NormalsMap[5*(x*(int)geo->size+ y)+2]=(float)tmpNormals[2*(y1*(int)width+x1)+1];
				}
			}
		}
		stbi_image_free(pixels);
		pixels=NULL;
	} else {
		// create a dummy terrain only as a dirty fallback
		height =128;
		geo=Geosphere::CreateGeosphere(256, parent_ent);
		//geo->height=new float[(width+1)*(width+1)];
		for (int x=0;x<=geo->size-1;x++){
			for (int y=0;y<=geo->size-1;y++){
				geo->height[x*(int)geo->size+y]=0.0f;
			}
		}
	}


	geo->UpdateNormals(true);
	delete tmpNormals;

	return geo;
}

void Geosphere::TreeCheck(CollisionInfo* ci){
	Ray=ci->coll_line;
	radius=ci->radius;

	TFormPoint(Ray.o.x, Ray.o.y, Ray.o.z, 0, this);
	xcf = tformed_x;
	ycf = tformed_y;
	zcf = -tformed_z;


	//int i;
	float h1= (height[(int)hsize*(int)size+ (int)hsize]*vsize+1)*size;
	float h2= (height[(int) size*(int)size+ (int)hsize]*vsize+1)*size;
	float h3= (height[(int)hsize*(int)size+ (int) size]*vsize+1)*size;
	float h4=-(height[(int)    0*(int)size+ (int)hsize]*vsize+1)*size;
	float h5=-(height[(int)hsize*(int)size]*vsize+1)*size;
	float h6=-(height[0]*vsize+1)*size;


	float v[9][5]={
	{ 0,  h1,  0, hsize, hsize},

	{ h2,  0,  0, size, hsize},
	{ 0,  0,  h3, hsize, size},
	{ h4,  0,  0, 0, hsize},
	{ 0,  0,  h5, hsize, 0},

	{ 0,  h6,  0, size, size},
	{ 0,  h6,  0, 0, size},
	{ 0,  h6,  0, 0, 0},
	{ 0,  h6,  0, size, 0}};


	// diamond radius - apply entity scale
	float rx=EntityScaleX(true);
	float ry=EntityScaleY(true);
	float rz=EntityScaleZ(true);
	if(rx>=ry && rx>=rz){
		dradius=abs(rx);
	}else if(ry>=rx && ry>=rz){
		dradius=abs(ry);
	}else{
		dradius=abs(rz);
	}


	//MQ_GetMatrix(tmat, true);



	if(c_col_tree!=NULL){
		C_DeleteColTree(c_col_tree);
		c_col_tree=NULL;
	}

	mesh_info=C_NewMeshInfo();
	triangleindex = 0;


	/* recurse on the two base triangles */
	c_col_tree_geosub( 0, v[0], v[1], v[2]);
	c_col_tree_geosub( 0, v[0], v[2], v[3]);
	c_col_tree_geosub( 0, v[0], v[3], v[4]);
	c_col_tree_geosub( 0, v[0], v[4], v[1]);

	c_col_tree_geosub( 0, v[2], v[1], v[5]);
	c_col_tree_geosub( 0, v[3], v[2], v[6]);
	c_col_tree_geosub( 0, v[4], v[3], v[7]);
	c_col_tree_geosub( 0, v[1], v[4], v[8]);

	c_col_tree=C_CreateColTree(mesh_info);
	C_DeleteMeshInfo(mesh_info);



}

void Geosphere::c_col_tree_geosub(int l, float v2[], float v1[], float v0[]){

	float vc[3][5];	/* New (split) vertices */
	float ds;	/* maximum midpoint displacement */
	float dx,dy,dz;	/* difference vector */
	float rd;	/* squared sphere bound radius */
	float rc;	/* squared distance from vc To camera position */

	if (l < ROAM_LMAX) {
		ds = level2dzsize[l];

		/* compute radius of diamond bounding sphere (squared) */
		float x,y,z;
		x = (v0[0] + v1[0] + v2[0]) / 3;
		y = (v0[1] + v1[1] + v2[1]) / 3;
		z = (v0[2] + v1[2] + v2[2]) / 3;
		rd = 0.0;
		dx = v0[0] - x;
		dy = v0[1] - y;
		dz = v0[2] - z;
		rc = dx * dx + dy * dy + dz * dz;
		if (rc > rd) {rd = rc;}
		dx = v1[0] - x;
		dy = v1[1] - y;
		dz = v1[2] - z;
		rc = dx * dx + dy * dy + dz * dz;
		if (rc > rd) {rd = rc;}
		dx = v2[0] - x;
		dy = v2[1] - y;
		dz = v2[2] - z;
		rc = dx * dx + dy * dy + dz * dz;
		if (rc > rd) {rd = rc;}
		rd = sqrt(rd)*dradius;


		float vcx=x;
		float vcy=y;
		float vcz=-z;
		mat.TransformVec(vcx, vcy, vcz, 1);

		/*Is triangle on the collision line?*/

		Vector Sphere;
		Sphere.x=vcx;
		Sphere.y=vcy;
		Sphere.z=vcz;
		Line dst( Sphere-Ray.o,Ray.d );

		float a=dst.d.dot(dst.d);
		if( !a ) return;
		float b=dst.o.dot(dst.d)*2;
		float c=dst.o.dot(dst.o)-rd*rd;
		float d=b*b-4*a*c;

		if (d<0) return;


		/* compute distance from split point To camera (squared) */
		dx = x - xcf;
		dy = y - ycf;
		dz = z - zcf;
		rc = dx*dx+dy*dy+dz*dz;

		/* If not error large on screen, recursively split */
		if (ds > rc) {/*<---------terrain detail here*/
			l++;
			float nx, ny, nz, d, h;

			nx=(v0[0]+v1[0])/2;
			ny=(v0[1]+v1[1])/2;
			nz=(v0[2]+v1[2])/2;

			vc[0][3]=(v0[3]+v1[3])/2; vc[0][4]=(v0[4]+v1[4])/2;
			h=height[(int)vc[0][3]*(int)size+ (int)vc[0][4]]*vsize+1;
			d=sqrt(nx*nx+ny*ny+nz*nz)/(size)/h;

			vc[0][0]=nx/d; vc[0][1]=ny/d; vc[0][2]=nz/d; 


			nx=(v1[0]+v2[0])/2;
			ny=(v1[1]+v2[1])/2;
			nz=(v1[2]+v2[2])/2;

			vc[1][3]=(v1[3]+v2[3])/2; vc[1][4]=(v1[4]+v2[4])/2;
			h=height[(int)vc[1][3]*(int)size+ (int)vc[1][4]]*vsize+1;
			d=sqrt(nx*nx+ny*ny+nz*nz)/(size)/h;

			vc[1][0]=nx/d; vc[1][1]=ny/d; vc[1][2]=nz/d; 


			nx=(v2[0]+v0[0])/2;
			ny=(v2[1]+v0[1])/2;
			nz=(v2[2]+v0[2])/2;
			vc[2][3]=(v2[3]+v0[3])/2; vc[2][4]=(v2[4]+v0[4])/2;
			h=height[(int)vc[2][3]*(int)size+ (int)vc[2][4]]*vsize+1;
			d=sqrt(nx*nx+ny*ny+nz*nz)/(size)/h;

			vc[2][0]=nx/d; vc[2][1]=ny/d; vc[2][2]=nz/d; 

			c_col_tree_geosub(l, v0, vc[2], vc[0]);
			c_col_tree_geosub(l, v1, vc[0], vc[1]);
			c_col_tree_geosub(l, v2, vc[1], vc[2]);
			c_col_tree_geosub(l, vc[2], vc[1], vc[0]);

			return;
		}

	 }

	//add to collisiontree
	C_AddVertex(mesh_info,v0[0],v0[1],-v0[2],0);
	C_AddVertex(mesh_info,v1[0],v1[1],-v1[2],0);
	C_AddVertex(mesh_info,v2[0],v2[1],-v2[2],0);
	C_AddTriangle(mesh_info, triangleindex, triangleindex*3+2, triangleindex*3+1, triangleindex*3+0, 0);
	triangleindex++;
}

void Geosphere::FreeEntity(){

	delete[] height;
	delete[] NormalsMap;		
	//delete[] EqToToast;		

	terrain_list.remove(this);
	delete c_col_tree;

	Entity::FreeEntity();

	delete this;

	return;

}




markcw(Posted 2016) [#131]
Thareh, I've tested in Ubuntu & Win7 with the latest version and can't reproduce your problem.

Hezkore, thanks for the example! The smiley face .jpg must be in the progressive format which Openb3d doesn't support in it's stb image decoders. Also Openb3d Textures are a little bit different to Minib3d so swapping out tex[0] won't work but BrushTexture(brush, tex) does the job.

Currently, things are a bit broken in the repo, cubemaps, tex render, maybe more, I've checked back to the ProPuke merge and it's fine so just use that for now.


Hezkore(Posted 2016) [#132]
I've switched out the jpg for a png.
And I've also tried
	If KeyHit(KEY_1) Then BrushTexture(GetSurfaceBrush(quad.GetSurface(1)), tex1)
	If KeyHit(KEY_2) Then BrushTexture(GetSurfaceBrush(quad.GetSurface(1)), tex2)
But I'm still not getting any results.


markcw(Posted 2016) [#133]
Oh right, no you shouldn't use GetSurfaceBrush as it creates a new brush, you need the current brush handle.
	If KeyHit(KEY_3) Then BrushTexture(quad.GetSurface(1).brush, tex2)



Hezkore(Posted 2016) [#134]
Ah yes, that works!
Is it possible for a TextureColor function?
The Quake shaders/scripts have blinking parts where they basically have a texture with additive blend mode go from RGB 0,0,0 to 255,255,255.
I'd also like to use it for the lightmap.


markcw(Posted 2016) [#135]
Textures don't have colors themselves, brushes have them, does BrushColor not work?


Hezkore(Posted 2016) [#136]
Well BrushColor would apply colour to the entire brush, which includes many textures. Making the entire thing blink instead of individual parts.

The brushes for Quake might be something like:
Texture 0 would be the floor texture.
Texture 1 would maybe be some fire texture or something.
Texture 2 might be a frame around the fire texture.
And Texture 3 could be the blinky stuff ontop of the frame.

If I did BrushColor the entire thing would "blink".
What I need is for Texture 3 to only blink.

The lightmap goes ontop of everything too (Texture 4 in this case) so BrushColor would also change the lightmap colour, which would look pretty trippy heh.

With a TextureColor function, we could have those blinky parts.
And also adjust the colour/light of the lightmap if needed.

I'm also wondering if there's a way to disable texture caching?
Loading the same texture twice and then rotating one seems to rotate both.
I'd like load the same texture twice and have them as individual textures.
Loading the textures with different flags does the trick.
So I'm thinking like perhaps another flag?
Flag 1024 could be the no caching flag.


markcw(Posted 2016) [#137]
About TextureColor. Can you use surf.VertexColor? There's also an unused surf.SurfaceColor.


Hezkore(Posted 2016) [#138]
VertexColor would only change the bottom texture if anything, wouldn't it?

I've found a trick for the texture caching problem.
If I for example load "tech.tga" I can load the same texture but with "tecH.tga" (notice the capital H) and it'll think it's a new texture file.
Dirty trick, but it works for now.


angros47(Posted 2016) [#139]
Don't use that trick, because it will cause unexpected results on different operating systems: in Windows, the file system is not case sensitive, so "tech.tga" and "tecH.tga" refers to the same file, but on linux (and also on OSX, Android and IOS) they are different files, and you will get a "Cannot find resource file"


Hezkore(Posted 2016) [#140]
We did it this way - https://github.com/propuke/openb3d.mod
He'll look into Texture color later.


markcw(Posted 2016) [#141]
Ok, progress report for anyone watching!

I'm nearly ready for an update, Addlist is in and working (yay)! Just a few issues need to be cleared up, at the mo, currently I need to check what objects need a createobject. I need to test all lists work properly and what pushback funcs aren't going to be needed.

I removed createobject from TEntity and reintroduced the Abstract methods CopyEntity/Update which probably has fixed a few bugs. I've gone for stability with Copy/Addlist which means it loops through the list everytime the func is called instead of incrementing an iterator. I found when you do that with a vector it just crashes.


Hezkore(Posted 2016) [#142]
Keep up the good work munch!

I have a tip for you though.
If you change line 139 in openb3d.mod\inc\TMesh.bmx from
RotateMesh mesh,0,-90,0
to
mesh.RotateMesh(0, -90, 0)
The module will compile in BMX-NG. :)


markcw(Posted 2016) [#143]
Ok, the repo is updated at last! :)

New changes are:
- removed all unneeded CreateObject's
- added ent.exists field to know if entity was freed, use instead of ent=Null
- removed TCollision.bmx, no need for it - the Collision functions cover everything
- internalized CopyList and AddList - field lists use CopyList, global lists AddList, no need for CopyList now
- fixed child_list not loading when ent has bones, waits for all bones to load
- added ListPushBack method for adding objects to field lists - global lists not supported, like ListAddLast
- reintroduced using GraphicsHeight to invert CameraViewport - vheight didn't work
- added TDebug for Minib3d debug functions
- added list removal in FreeEntity, FreeShadow and FreeTexture
- added list reset in ClearWorld (and cpp fix where root_ent should not be freed)
- added CopyBrush, CopySurface and CopyTexture functions (and cpp changes by ProPuke)
- added TPick AddList to EntityPickMode and CopyEntity functions
- fixed no breaks in nested switches causing errors in data.cpp
- improved the way iter list functions work in data.cpp
- added geosphere.cpp changes by Angros


markcw(Posted 2016) [#144]
Just updated TMatrix2 to be TMatrix.

I tested with feeble's Newton demo and the bug where the boxes vanish below -15M has gone.

Edit: Oops, just missed updating openb3dlib.bmx.


Hezkore(Posted 2016) [#145]
Hmm using ProPukes version I can do
myTexture = LoadTexture(name, flags).CopyTexture()
and that works fine, but with yours I need to specify a brush, which is a bit of an issue for me. :S


markcw(Posted 2016) [#146]
Hi Hezkore, I should have said I changed CopyTexture to be 'copy tex to brush' because I thought it might be good to have both options, that and the tex.Copy() method. If this is not anything anyone will want I can change it? I also changed ProPuke's cpp copy function a bit and I was wondering if I should even add a glGenTextures so it is a unique texture you can then draw to?

Currently I'm filling in the spaces in the docs and working on some examples.


Hezkore(Posted 2016) [#147]
Ah okay, I didn't know .Copy() existed.
Then all is fine, thank you!

I noticed it's not possible to load incbin models.
Is there a way this could be fixed in the future?
I mean stuff like this
Incbin "mesh.b3d"
LoadMesh("incbin::mesh.b3d")



markcw(Posted 2016) [#148]
Hi Hezkore, glad to know tex.Copy is ok with you. I would like to clarify if you want to draw to this copy (via glGenTextures) or if you just need to get around the cache issue mentioned.
I'm also wondering if there's a way to disable texture caching?
Loading the same texture twice and then rotating one seems to rotate both.
I'd like load the same texture twice and have them as individual textures.


Re: incbin, I think as with Minib3d your best option here is to use Brucey's version of koriolis.zipstream as mentioned here: http://www.blitzmax.com/Community/posts.php?topic=105651

@Angros, how's the GLES stuff going?

EDIT: I have been testing the Action functions and found a few issues.
- First was I think it would be better if there was an option to loop an action (and any appended ones) and to stop an action would be useful for vector/newtonian functions.
- Then there seems to be a random Mesa error report "Mesa 10.1.3 implementation error: Bad attrib flag in PopAttrib" which happens when I use FreeAction. At other times there is a random DrawText bug rendering black background - no blending.
- There is also a random segfault with FreeAction (could it be related to the mesa error?). I double-checked this wasn't my code, it happens maybe 1/10 times.
- I had to change Action::action_list to public as I wanted to access it to free finished actions.
- When I wrapped "int act" after the action is over sometimes it is random data instead of being zero.



Also a few other issues.
- FreeEntity you should be calling child_list.remove(this) after the child_list loop.
- ClearWorld there is no code to deal with brush's since Minib3d never implemented it. EDIT: looking at the b3d src it uses something called a set which must be a custom list, bbCreateBrush, bbGetSurfaceBrush and bbGetEntityBrush insert and bbFreeBrush erases, so it doesn't include internal brushes in Entity and Brush.
- GetMatElement just returns 0 in functions.cpp when it should be ent->mat->grid[row,col].


Hezkore(Posted 2016) [#149]
I just needed it to get around the caching problem.
I'm still scratching my head about how to colour the textures though.
Something like ColorTexture(r,g,b)


markcw(Posted 2016) [#150]
Well, as mentioned I think the way to do that is by creating separate surfaces and then using surfaceColor or vertexColor.


Hezkore(Posted 2016) [#151]
Vertex colour won't work in my situation, I only want to change the colour of a couple textures in my brush, vertex colour would affect the entire brush, even lightmap parts.
And I tired multiple surfaces, but my PC came to a crawling speed, seeing as how entire levels use multiple textures that change colours. I basically end up with too many surfaces!


markcw(Posted 2016) [#152]
Well I guess the only other option would be to draw to the texture and therefore change its color.


Hezkore(Posted 2016) [#153]
Yeah, but it changes every frame.
Seems very slow... Unless there was some sort of PixmapToTexture function hehe
But that would still probably be very slow.


markcw(Posted 2016) [#154]
If your texture is only a few pixels it shouldn't matter, right?


Hezkore(Posted 2016) [#155]
It's the Quake 3 textures, and they're pretty big. :/


markcw(Posted 2016) [#156]
Ok, I must misunderstand what you're talking about, sorry I'm watching Sweeny Todd! Hehe


Hezkore(Posted 2016) [#157]
Cool movie heh
I sent you a mail to the email you've got registered here at the forum.


markcw(Posted 2016) [#158]
Another update! This time I filled in all the docs blanks but some other things too.

- nice actions example taken from bOGL demo - FreeAction bug (MAVs every time in Win7)
- updated particle example
- voxelsprite example - ugly rendering issue when using first and last splices
- issue with rigidbody being flattened so no constraints example
- action_list and act vars to TAction
- changed cls_depth name to cls_color in StencilClsMode to prevent confusion
- removed rest of collision code in data.cpp


angros47(Posted 2016) [#159]
What happens with rigidbody?


markcw(Posted 2016) [#160]
Well sorry I've no screenies but here's test code. It basically just flattens the body mesh like a pancake, although it is being affected by the constraints.



angros47(Posted 2016) [#161]
Of course the mesh is flattened: constraints are not connected!

A constraint will ONLY keep the same distance between two objects: you connect every cube to a ball, but you didn't put constraints between cubes, so every cube can change position relative to any other: and if the rigid body has to follow cubes, it is deformed.

You should create a constraint between every cube entity and each other (it means, 6 constraints), to connect them like the vertices of irregular tetrahedron (if you are not sure of the distance, use EntityDistance); it is an undeformable shape, and will make the rigid body undeformable, too.


markcw(Posted 2016) [#162]
Ok thanks Angros, I created a constraint tetrahedron with 6 edges from 4 cubes and attached 4 spheres to those but the cube body is distorted into a parallelogram shape now. How can I retain the original shape of the mesh?




angros47(Posted 2016) [#163]
The first cube must be in the center of the mesh (I mean the 0,0,0 relative coords... with FitMesh, it might not be the real center). The other three cubes must be, respectively, forward, up, and on the right (or left): they will define three axis, that can define position and rotation of the mesh; if the three axis are not perpendicular, the mesh is distorted; if one axis is longer than others, the mesh will be longer/larger.

Actually, the coordinates of these four points are used to build a matrix, that is directly applied to the rigid body (all the stuff about scaling, rotations and position is bypassed)


markcw(Posted 2016) [#164]
Thanks again Angros, I have a working rigidbody now. It's pretty cool but I notice the rigidbody mesh gets distorted as the constraints are moved, so it looks like it's made of jelly. I decided to get around this I could get the angle of each axis and position of the center and apply it to the mesh without using a rigidbody. I'm also wondering how I can apply this to make a kart with four wheels moving about a terrain.




angros47(Posted 2016) [#165]
Constraints are used to build a sort of "skeleton": you should use four pivot to control the rigid body (I. E. The kart), but this is the bare minimum: you can add other pivots on the angles, and on the four wheels, and link them to the structure.

Let's say you have four wheels: you set collision with ground for each one, then you create a constraint between each wheel and each other (constraints will for a rectangle with diagonals ), providing an invisible "frame" for the car. Try it, and you will see that the wheels will act as in a real car. Then, you can add to the frame other pivot, and use them with a rigid body to draw the car chassis.


markcw(Posted 2016) [#166]
Ok thanks I will try that.

Btw, Spinduluz is working on a fork of openb3d.mod HERE. He's added DDS textures and zip archives via koriolis.zipstream.


FBEpyon(Posted 2016) [#167]
@munch / agros47 - Is there a way to add a function for getting ScreenToWorldPoint(camera:TCamera, x:Int, y:int, z:Int)?

Return Function:

WorldPointX()
WorldPointY()
WorldPointZ()

The only reason I ask is I'm trying to do a mouse drag on an orthographic projection to move my map around, and there is no way to just grab the position of the mouse and translate it into screen location with out interacting with another entity.

Unity3D uses something similar to this called ScreenToWorldPoint: http://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html

Sorry to bother you on this, but figured it would be a nice feature of the camera entity, or if you have another solution that would be great..

Thanks,

FBEpyon


Hezkore(Posted 2016) [#168]
Doesn't CameraPick work for that?
Have a quad pickable before the CameraPick and then hide it after the pick.


FBEpyon(Posted 2016) [#169]
I have played with the CameraPick() many of times, but it requires a mesh to interact with.

I even tried putting a plane on the screen and picked the vertex from that plane to see were in the World_Space I was and then re-hide it. Didn't seem to work very well (could of done something wrong though).

ScreenToWorldPoint takes the ScreenX / ScreenY and transforms it into World_Space X/Y/Z for you without any form of interaction with another entity.

Also forgot to mention this is really only useful for Orthographic projection, which was mentioned earlier. This is because in normal frustum mode you would use LinePick, CameraPick, Etc. Orthographic doesn't really care about depth other than object Z-Ordering.

Thanks,

FBEpyon


angros47(Posted 2016) [#170]
CameraPick can work on terrains, too, not only on meshes.

Converting 2d screen coordinates to world coordinates with no entity is pointless, because every screen location could map to infinite world locations : in a simple orthographic projection, the point in the middle of the screen could map to coordinates 0,0,0 as well as 0,0,1 (any value of z will project on the same pixel), so how can it be converted?

Anyway, in an orthographic projection you can just map x and x to world coordinates, and add camera coordinates to get absolute position.


Spinduluz(Posted 2016) [#171]

Ok thanks I will try that.

Btw, Spinduluz is working on a fork of openb3d.mod HERE. He's added DDS textures and zip archives via koriolis.zipstream.



These are actually the small changes done to OpenB3D.
I've put a lot of effort to ensure that objects are actually freed when you free them.

It's a cool library but it's plauged with memory/resource leaks. (Yeah I know it's in beta stage but still)
While this is not a problem for small demos and such it might be a problem in larger projects.

Especially if resources are updated often and the game/application should be able to run for hours.

But like I said. Still a cool library.


markcw(Posted 2016) [#172]
Well thanks a lot for your improvements, Spinduluz! I will be happy to add them all to my repo.

I meant to mention about the memory leak fixes but forgot. As you said, an important issue in big projects.


Hezkore(Posted 2016) [#173]
I have some problems with LinePick and PickedNX().
If the LinePick radius is set to anything greater than 0 and the pick starts really close/inside a wall, PickedNX/Y/Z will return odd values.
It's easy to test by LinePicking every frame and going through a wall, make sure LinePick radius is greater than 0, the higher the better.
If radius is 0 everything works just fine.
It's causing some issues with my sliding collision code.

I'll make an example of this if needed, but it might take a day or two as I'm not by the computer.

Oh and the same problem exists in MiniB3D.


Hezkore(Posted 2016) [#174]
Here's an example of it, run it from your Examples folder.
SuperStrict
Framework openb3d.B3dglgraphics

Graphics3D(1280, 720, 0, 2)

Local cam:TCamera = CreateCamera()
PositionEntity cam, 150, 40, -187

Local light:TLight=CreateLight(1)
RotateEntity light,90,0,0

Local mesh:TMesh=LoadMesh("../media/test.b3d")
ScaleMesh mesh, 10, 10, 10
EntityPickMode(mesh, 2)

Local lastPick:TEntity
Local lastNX:Float

While Not KeyDown(KEY_ESCAPE)
	MoveEntity(cam, 0, 0, 0.025)
	
	lastPick = LinePick(EntityX(cam), EntityY(cam), EntityZ(cam), 0, 0, 2, 5)
	If lastPick Then lastNX = PickedNZ()
	
	RenderWorld()
	Text(GraphicsWidth() / 2, GraphicsHeight() / 2, "PickedNZ = " + lastNX)
	
	Flip(1)
	
	'End demo
	If EntityZ(cam) >= - 181 Then End
Wend
End



Hezkore(Posted 2016) [#175]
I also have a request for the future.
With MiniB3D you didn't have to create a graphics window for things to run.
That was perfect for things like dedicated servers.
But with OpenB3D it just crashes if no window is created.
Is that something that could be fixed in the future?


angros47(Posted 2016) [#176]
Minib3d uses the graphic library of Blitz max, that creates it's window. OpenB3D is language independent, so it can't use specific features (in Freebasic the routine that creates a window is different from BlitzMax, for example )


Hezkore(Posted 2016) [#177]
Okay...
Well what's up with PickedNX()? (example above)


angros47(Posted 2016) [#178]
does the linepick problem occur even in Blitz3d?


Hezkore(Posted 2016) [#179]
Sorry, I've never used Blitz3D so I have no idea.
But the normals shouldn't be any different no matter how deep into the wall I go anyways.


angros47(Posted 2016) [#180]
Radius is unrelated with how deep you go into the wall; to define how deep you go, you need to use the three picking directions. Radius means the "thickness" of the picking line (if radius is greater than 0, the picking line becomes a cylinder); with a picking cylinder, picking can happen on many points of a surface at the same time, so exact picking coordinates and normals become meaningless (but you can still know the picked entity).

Anyway, why did you use LinePick instead of EntityPick? In your example I think EntityPick would be simpler to use.


Hezkore(Posted 2016) [#181]
I know what radius is and sure I could have used EntityPick heh.
I'm just showing you a way to make the PickedNX() function bug out.
The walls normal doesn't ever change, but according to PickedNX it does change, which is incorrect.


angros47(Posted 2016) [#182]
The collision routine is the same used for standard collision tests, so I don't know where the bug could be. I'd need to know if original Blitz3D has the same behavior.


markcw(Posted 2016) [#183]
I tested with B3d and the example Hezkore made behaves the same as in Minib3d/Openb3d ie. it starts of -1.0 then as the camera moves the normal goes down to -0.25.




angros47(Posted 2016) [#184]
Well, so I don't think it can be considered a bug, since Blitz3D has been used for years with no complaints about it; maybe this is not the most intuitive behavior, but it's consistent with legacy code.

Thank you for testing!


Naughty Alien(Posted 2016) [#185]
..hi guys..i have trouble building openb3d modules..may i know requirements for successful build, please..


Cocopino(Posted 2016) [#186]
@Naughty Alien

Problem might be MingW:
http://www.blitzmax.com/Community/posts.php?topic=95220


markcw(Posted 2016) [#187]
Yes, it's probably an issue with the Mingw version or it could be the lib folder issue with legacy Bmx which the batch file is meant to resolve.

On win7 I use mingw 32bit 4.7.1 (not sure if it's tdm version) as I had trouble using 4.8.1 with legacy Bmx (will double-check that). Using Bmx NG I am using tdm gcc 4.8.1 64bit with no issues I can find.

I always used Brucey's Mingw guide but there's now a new howto by TomToad here: http://www.blitzmax.com/Community/posts.php?topic=105745

I will try to supply module binaries. I'll need to find out what version is compatible with legacy Bmx.


RGR(Posted 2016) [#188]
.


markcw(Posted 2016) [#189]
@Naughty Alien, I've uploaded the archive .a and preprocessed include .i files built with the same gcc version as legacy Bmx 1.50. So now as long as you haven't rebuilt brl/pub/maxgui mods with some other mingw version it should work, otherwise you'll need to make a clean install, or rebuild with gcc 4.6.1.

So the story is: I found out the gnu binutils ar and ld display the version with --version which was "2.21.1" for Bmx 1.50 this is then listed by Nuwen Mingw HERE which shows the gcc version was 4.6.1 at that time. This version is not available from Nuwen now but there is a working link to it HERE by Armitage 1982. There is a version of gcc 4.6.1 by TDM HERE which did build Openb3d but it's a slightly later version of binutils "2.21.53" which may cause conflicts, although it's probably fine I didn't want to use it.


markcw(Posted 2016) [#190]
@RGR, your comment about Mingw being off-putting and the "crazy" module system were valid criticisms so no need to delete it. I have found Bmx a struggle and still do so I know what you mean. It would be nice to have a Mingw-less install of Bmx to encourage people to dip into Bmx more as it really is a nice language. I think I'll make one with selected 3rd-party modules. Edit: I decided this was a bad idea! Instead I wrote a new MinGW guide in Bmx tutorials.

Following the Bmx open-source thread HERE it seems to work with tdm 5.0.1 now so will have to investigate. The official repo is source only but it has an installer. Edit: works well with 32 and 64 bit tdm 5.1.0.


Cocopino(Posted 2016) [#191]
Hi!

Is it possible to manipulate (rotate/scale) bones of an animated mesh?
I tried doing this with Findchild but it seems the rotation stored in the animation always prevails. For example, I'd like a character to look around during a walking animation by rotating the neck bone.


feeble1(Posted 2016) [#192]
I would animate the head separately and then parent it to the neck bone, so that the character can look around while walking or standing. You can rotate bones, but it is best (less problematic) in your modeling software.


Cocopino(Posted 2016) [#193]
Hmmm... but the model now consists of one group/mesh, so that would involve work using 3D tools I am not too skilled with. Also, would this not lead to a strangely looking mesh around the neck area?
And furthermore, the model also has jaw bones, to make him "talk", so if I'll probably run into the same problem again when trying to do that...


feeble1(Posted 2016) [#194]
Perhaps, everyone's implementation will be a bit different. It sounds a lot like you want to run multiple animations on the same model, I have no idea how to do this. Unfortunately, the important part of game development seems to be hiding the hacky way you made things work ;)


Cocopino(Posted 2016) [#195]
Yes, game development seems to need a lot more workarounds than normal programming :)

I have done this before however, and it was not hard at all. I could just animate a model, and set the rotation of a child entity manually during the animation. Might have been Leadwerks though instead of B3d/minib3d.


angros47(Posted 2016) [#196]
It's possible to manipulate bones, as long as you are using animation mode 4 (manual mode).


Cocopino(Posted 2016) [#197]
I would like to mimic this Blitz3D behavior (uses the well known zombie mesh):

Graphics3D 1600,900

SetBuffer BackBuffer()
camera=CreateCamera()
zombie=LoadAnimMesh("zombie.b3d")
PositionEntity(camera,0,0,-50)
PointEntity(camera,zombie)

Animate (zombie,1,0.3)

Local joint1 = FindChild(zombie,"Joint8")
Local joint2 = FindChild(zombie,"Joint11")

While Not KeyHit(1)
	
	UpdateWorld
	
	RotateEntity(joint1,50,50,50)
	RotateEntity(joint2,50,50,50)
	
	RenderWorld
	Flip
	
Wend


Is that possible using openB3d?


angros47(Posted 2016) [#198]
Yes, it's possible with a trick:

	i=i+.3
	SetAnimTime zombie,i: Animate (zombie,4)
	RotateEntity(joint1,50,50,50)
	RotateEntity(joint2,50,50,50)
	UpdateWorld
	
	RenderWorld
	Flip


Bones needs to be moved BEFORE the UpdateWorld command (differently from Blitz3D, in OpenB3D the mesh is not deformed according to bones unless UpdateWorld is called). But UpdateWorld would also execute the animation, so you cannot use animation mode 1; to still have the animation running, you need to set the frame manually (by using SetAnimTime), set again animation mode 4 (SetAnimTime by default set mode -1), perform your joint rotation, and THEN call UpdateWorld.


Cocopino(Posted 2016) [#199]
Yes, that did it, thanks!

The following code worked as planned:
Strict

Import openb3d.b3dglgraphics

Graphics3D 1600, 900

Local camera:TCamera = CreateCamera()
Local zombie:TMesh = LoadAnimMesh("zombie.b3d")

PositionEntity(camera, 0, 0, -50)
PointEntity(camera,zombie)

Local joint1:TEntity = FindChild(zombie, "Joint8")
Local joint2:TEntity = FindChild(zombie, "Joint11")

Local frame:Float = 0.0
While Not KeyHit(KEY_ESCAPE)

	frame:+0.3
	SetAnimTime (zombie, frame)
	Animate (zombie, 4)
	RotateEntity(joint1,50,50,50)
	RotateEntity(joint2,50,50,50)
	UpdateWorld()

	RenderWorld()
	Flip()
	
Wend



Cocopino(Posted 2016) [#200]
Is there also a trick I could use to attach a textured mesh to an animated character when the texture has been loaded with flag 2 (alpha), for example hair?

In Blitz3D, when using a semi transparent texture like this:
local hair = LoadAnimMesh("hair.b3d")
local tex = LoadTexture("hair.png",2)
EntityTexture(hair,tex)
EntityParent(hair,character)
Animate(character)

,the hair would look fine from any angle.

When trying the same in openB3d, (part of) the hair mesh sometimes disappears/becomes invisible, e.g. when the camera is placed low to the ground or when the arm of the character gets in between the camera and the hair mesh.

Thanks again!


angros47(Posted 2016) [#201]
I am not sure I have understand... maybe it is a problem of alpha sorting. Can you post a screenshot?


Cocopino(Posted 2016) [#202]
Yes, it's probably an alpha sorting problem.
I will try to create a Blitz3d + OpenB3d example using the same assets and similar code.


angros47(Posted 2016) [#203]
Meanwhile, try to set
EntityFX hair,32
to force alpha sorting


Cocopino(Posted 2016) [#204]
Hi Angros, I tried to create a small example but the problem did not occur on a very simple animated mesh with just one texture.
It only exists when the parent has textures with the alpha flag of it's own, but I can certainly work around that.

Thanks again!


feeble1(Posted 2016) [#205]
Just to report on the MinGW issue: 5.1.0 and 4.7.1 will not successfully build OpenB3D (running Windows 7).
It works great if I do not build the module and enable debug mode or if I use 4.6.1.
Not a big deal but the 0.8 version of the module seems to build just fine on all three.


markcw(Posted 2016) [#206]
Hmm, it worked for me.

You can only use MinGW 5.1.0 with OS Bmx (or Bmx NG), if you're using legacy Bmx you should use 4.6.1 of either Nuwen or TDM. 4.7.1 does seem to work but there may be some compiler conflicts as bmk and bcc were built with 4.6.1.


feeble1(Posted 2016) [#207]
So far I have had the best and most consistent results with 4.6.1 TDM, even 4.7.1 TDM messes up now and then. Its kind of fun to play around with though.


Cocopino(Posted 2016) [#208]
Hi, does FreeEntity work entirely as it should?
I've mocked up a small test (adjust mediadir as needed):

but the program will slowly but surely eat up more ram.


markcw(Posted 2016) [#209]
Yes there are memory leaks in FreeEntity, for one the brush is not freed, also the strings probably need freed too. More than that needs done I would think.

Also, posted this in another thread which may be useful to repost here.

Brucey's version of Openb3d hasn't been updated in yonks, so don't use it until he updates it to v1.1. My version (vanilla) now works in NG after Brucey's bug fixes (and maybe Brucey's), and vanilla Minib3d works too. So make sure you have the latest bcc source.


markcw(Posted 2016) [#210]
Actually, using your example with Task manager>Resource monitor it only went from 40% used physical memory to 50% and leveled off at that, although I only tested for a few minutes.


Cocopino(Posted 2016) [#211]
Ok, I made another test, a much simpler one.
This one just loads, and then destroys meshes ad infinitum.

Blitz3D version:
Graphics3D 1024, 768, 32,2

Local cam=CreateCamera()
Local mesh = LoadMesh("media/zombie.b3d")
PositionEntity cam,0,10,-30

While Not KeyDown(1)

    FreeEntity(mesh)
    UpdateWorld()
    mesh = LoadMesh("media/zombie.b3d")
    UpdateWorld()
    
	RenderWorld()
	Flip()
	
Wend


OpenB3d (FreeBasic):
#Include "openb3d.bi"

ScreenRes 1024,768,32,,&h10002
Graphics3D 1024,768

var cam=CreateCamera()
var mesh = loadMesh("media/zombie.b3d")
PositionEntity cam,0,10,-30

While Not multikey(1)

    freeentity(mesh)
    UpdateWorld()

    mesh = loadMesh("media/zombie.b3d")
    UpdateWorld()

    RenderWorld()
	Flip()

Wend


The RAM taken by the Blitz3D version will stay around 25MB for a long time while the OpenB3D version will eventually crash because of taking more than 2GB.
Using assets like this will not happen in a real game of course but this still could pose a problem when there's lots of loading involved and/or the player will be playing for several hours.


angros47(Posted 2016) [#212]
If you replace the "LoadMesh" with "CreateMesh" it does not happen... maybe the issue is in model.cpp, not in FreeEntity. I've found some memory leaks in it...


Naughty Alien(Posted 2016) [#213]
..for some reason, i cant get OB3D work..i guess its about compiler..can someone post me step by step tutorial, how to get it right with BMX?

EDIT:
Got it work..i have installed wrong MinGW...


Cocopino(Posted 2016) [#214]
@Angros
If you replace the "LoadMesh" with "CreateMesh" it does not happen

But CreateMesh creates a completely empty mesh, right? The things that stay in memory are more likely textures, brushes, child entities or other artifacts.

Is it possible to load animated, textured meshes and delete and reload them when needed without the program increasing in memory?

@Naughty Alien
I had the same problem at first. Solution in post #186 worked for me but maybe you should try the replies by Munch first.


Naughty Alien(Posted 2016) [#215]
..this is rather minimalistic, but very nice little engine..what 3D formats are supported?? And animation wise, is it hardware or software skinning(if supported)?


markcw(Posted 2016) [#216]
i cant get OB3D work..i guess its about compiler..can someone post me step by step tutorial, how to get it right with BMX?

I wrote a MinGW install guide HERE. To summarize, if using legacy Bmx use TDM 4.6.1, if OS Bmx (or Bmx NG) TDM 5.1.0 is probably best but whatever you prefer.

what 3D formats are supported?? And animation wise, is it hardware or software skinning

It's basically Minib3d in C++ with extra bits from Warner engine (quats, terrain) and Extended (shader, shadow, md2) and some other features like particles (but no physics engine).

So formats are .3ds .x .b3d .md2 (no .bsp yet) and animation is software skinning, assuming hardware is writing a shader to load the bones.


angros47(Posted 2016) [#217]
@Cocopino

I mean, commands like CreateCube, CreateSphere seems not to trigger the memory leak. Instead, using CopyEntity does. I already found many leaks (i.e. in CopySurface, or in FreeEntity for bones). I'll work on it

@Naughty Alien
B3D is fully supported, and so MD2 (but you need to texture it manually, because PCX textures aren't supported). 3DS is partially supported (no animations), and so DirectX .X (no animation, text format only, and only version 0302).

Animations use software skinning (maybe it's slower, but works everywhere), plus a special hardware mode taken from the MiniB3D Monkey port: all frames are pre-calculated in software, then loaded in the video memory: it's less smooth, since there is no tweening, but it requires almost no computation neither from the CPU, nor from the GPU; it uses more video memory, but makes instancing possible, so if you have many copies of the same mesh, it could actually use less memory)


Cocopino(Posted 2016) [#218]

I already found many leaks (i.e. in CopySurface, or in FreeEntity for bones). I'll work on it



Thanks!
Can I be of assistance, e.g. would it be helpful to write a program showing which commands do not "clean up well"?


angros47(Posted 2016) [#219]
There are too many fixes needed, listing all of them here is impractical. So, I release the version 1.12 that contains all the patches.

https://sourceforge.net/projects/minib3d/files/


Cocopino(Posted 2016) [#220]
Angros... you're the man!

Tested the example in #211 again and memory hardly goes up at all, but instead stays within the same regions as the Blitz3D version does. Many thanks, that must have been pretty boring work ;)


markcw(Posted 2016) [#221]
Updated the wrapper for 1.12 fixes. Thanks Angros!


Cocopino(Posted 2016) [#222]
Thanks both!


BlitzMan(Posted 2016) [#223]
Hi guys
Is this wrapper stable enough at the moment to actually make a game with,or
should i wait a while longer.

Good Job Guys

thnx


feeble1(Posted 2016) [#224]
@munch Would you take additions to your examples folder?



Also, what the odds of getting an AddSurface or FreeSurface command?

I absolutely love CopyBrush btw!


markcw(Posted 2016) [#225]
Updated again with FreeObject fixes.

Two questions Angros:
- where is the "Bug that made particles crash" fix
- why are you using in global.cpp ClearWorld "Global::root_ent->FreeEntity()" instead of "Global::root_ent->child_list.clear()"

@BlitzMan, it's pretty stable now since these updates, there may be a few issues yet though.


angros47(Posted 2016) [#226]
1) This one:
http://www.blitzbasic.com/Community/post.php?topic=105082&post=1284809

It wasn't yet fixed in the vanilla version

2) because FreeEntity also deletes objects, calling their destructor, and is recursive


Cocopino(Posted 2016) [#227]
@BlitzMan

If you were planning on using minib3d or Blitz3D otherwise - go for it!
As you can see it's still being updated, that's the biggest advantage, and it's much faster, and much more portable (OpenGL vs DX7) than Blitz3d. Command set is almost exactly the same so porting would be very easy should it fail. Also, only real users can make it better.

You could start with writing some small proof of concept programs taking away your biggest "will it work?" fears. (at least, that's what I plan to do)


feeble1(Posted 2016) [#228]
There are far more commands in OpenB3D than in Blitz3D!


markcw(Posted 2016) [#229]
@feeble1, thanks I'll add it but it has uncovered a bug with CopyBrush (error: free(): invalid pointer - delete object that's not there) and I'm not sure what is going on there so need to investigate.

@Angros, thanks I had the fix for 1. For 2 I just can't see how you can add new entities after ClearWorld. Shouldn't you have a root_ent=new after the FreeEntity?

Also, I'll be splitting the wrapper into 2 mods soon, Blitz3d and extended functions, just so it is easier to read the help.


angros47(Posted 2016) [#230]
Actually, ClearWorld is seldom used, so I never tested it. Maybe you need to add a line like:

Global::root_ent=new Pivot();


after the FreeEntity.

What is the bug in CopyBrush?


markcw(Posted 2016) [#231]
Well what I'm doing is in function.cpp
void ReplaceBrush(Brush* brush, Brush* brush2){
	if(brush!=NULL) delete brush;
printf("replacebrush=%p\n",brush);
	brush=brush2;
	return;
}

And then in openb3dlib.bmx
Function CopyBrush:TBrush( brush:TBrush,surf:TSurface )
	Local brush2:TBrush=brush.Copy()
	ReplaceBrush_( TBrush.GetInstance(surf.brush),TBrush.GetInstance(brush2) )
	surf.brush=brush2
	Return brush2
End Function

And then running the copybrush example by feeble1 it errors with free() invalid pointer in ubuntu (but seems ok in win) but if I comment out the FreeEntity line its fine. After debugging it seems the pointer for surf->brush in data.cpp is slightly different to the one created in Surface::Surface.


feeble1(Posted 2016) [#232]
It seems to run fine in Win 7, but seems to randomly error when threaded. Not consistent enough to show where.


Cocopino(Posted 2016) [#233]
What is the accepted, or the least resource intensive, way to use a fullscreen (not single mesh) shader effect?
Do I need to use CameraToTex and then render that texture to a sprite, does anyone have an example?

Thanks!


Hezkore(Posted 2016) [#234]
@Cocopino
https://bitbucket.org/Hezkore/shader-camera
I haven't tested it since last year, so it might not work with newer versions.


Cocopino(Posted 2016) [#235]
Thanks, I will look into that :)


Cocopino(Posted 2016) [#236]
Hi Hezkore,

If I change the example by texturing Mesh2, or by using a loaded model instead of CreateCone(), ShaderCamera does not render anything anymore, it's just a black screen. The regular camera still works fine (showing the textured cone).

I did not look at the code too closely but does it work like this:
1. render the main camera to texture
2. texture a sprite using this texture
3. use a shader on the sprite
4. show the sprite fullscreen with the second camera
?

Because if it does, I don't understand why it's not working... Any ideas?


RustyKristi(Posted 2016) [#237]
Hey munch, I was wondering if there's this sl_dof.bmx example included. I would like to check that out and seems I can't find any good links. It was mentioned here by you.

http://www.blitzbasic.com/Community/post.php?topic=102556&post=1246878

Thanks.


markcw(Posted 2016) [#238]
That was added a while ago as sl_depthfield.bmx - I got the shader from source by klepto and used it instead of another I have as it was faster and seemed to look better but I don't think it's as pronounced as some dof pics I've seen so some work still needed.


RustyKristi(Posted 2016) [#239]
Ah right thanks, that will do! :D This is awesome btw


RustyKristi(Posted 2016) [#240]
Hey munch,

I have noticed that when you activate the postfx examples, the camera kinda steps back away a bit. It's not a big deal, but just curious as to why.

thanks again.


markcw(Posted 2016) [#241]
I did that because sl_shimmer was visibly wrapping the pixels top/bottom so I just moved the sprite in a bit to cover that as I didn't know how to clamp uvs in the shader code. It's not needed in sl_depthfield so maybe I'll change it. So just change this line to 1.
MoveEntity screensprite,0,0,0.99 ' just under 1.0, instead of clamping uvs



RustyKristi(Posted 2016) [#242]
Thanks munch! works great :D


RustyKristi(Posted 2016) [#243]
Quick question munch, may I ask how do you load or combine multiple postfx on the screensprite? aside from doing it on the shader file which obviously requires a bit more knowledge.


Hezkore(Posted 2016) [#244]
I've made this function that updates the Max2D canvas correctly when using OpenB3D.
And doesn't have that annoying bug where for a few frames the Max2D canvas is incorrect after a resize.
It also doesn't assume that your canvas is covering the entire window.
So instead of this:


And all that "TResize.PopResize()" and "TResize.DoResize(win,can,cam)" stuff.
You can instead just call this before rendering.



Hezkore(Posted 2016) [#245]
Just downloaded the newest version and it's crashing on a lot of random places.
FreeVBO seems to be the cause of most crashes.


markcw(Posted 2016) [#246]
What was your previous version?

I doubt I can reproduce, so try previous commits here until it's fixed and post the commit date.


Hezkore(Posted 2016) [#247]
I'm not sure what version the old one was...
But it happens quite often with my "Tile Maker" (tilemaker.bmx) which you can find at: https://bitbucket.org/Hezkore/retro-dungeon-crawler
Jump to line 67 and uncomment "FreeEntity(mesh)"


Hezkore(Posted 2016) [#248]
Also, I'm wondering if there's any way to remove the filtering on textures?
I'd like small textures to be big pixels instead of smoothed.
ClearTextureFilters() doesn't help.


markcw(Posted 2016) [#249]
Also, what the odds of getting an AddSurface or FreeSurface command?

I absolutely love CopyBrush btw!

I've added Add/FreeSurface not tested. CopyBrush/Texture/Surface are now wrappers for Copy so they just return a copy. I was going to add ReplaceBrush/Tex/Surf but I realized this creates a problem either you cause a memory leak or you delete something that may be in use. So that is better managed by the end program.

Quick question munch, may I ask how do you load or combine multiple postfx on the screensprite?

Openb3d only uses one framebuffer object (there may be a reason) so you have to use CameraToTex every time you want to render another pass with a shader. I'm sure this is slower than using two FBOs but I don't know how to add this.

I've made this function that updates the Max2D canvas correctly when using OpenB3D.

Thanks, I added your function, what was I thinking!

Also, I'm wondering if there's any way to remove the filtering on textures?

I'm sure this is the tex.flag set in LoadTexture (which doesn't seem to be working when I set it which may be a problem with pointers in the wrapper) this sets glTexParameter GL_LINEAR which should disable mipmaps but it doesn't seem to work.


RustyKristi(Posted 2016) [#250]
Openb3d only uses one framebuffer object (there may be a reason) so you have to use CameraToTex every time you want to render another pass with a shader. I'm sure this is slower than using two FBOs but I don't know how to add this.


Thanks munch, I don't mind trying it so how would you go about in rendering another pass in OpenB3D? It seems I am stuck with "currentTexture" and got no clue how to line up another shader texture to camera.


Local shader:TShader=LoadShader("","shaders/shadervert.glsl", "shaders/shaderfrag.glsl")
ShaderTexture(shader,colortex,"currentTexture",0) 
ShadeEntity(screensprite, shader)

...

While
...
CameraToTex colortex, camera
...
Wend



Hezkore(Posted 2016) [#251]
I'm sure this is the tex.flag set in LoadTexture (which doesn't seem to be working when I set it which may be a problem with pointers in the wrapper) this sets glTexParameter GL_LINEAR which should disable mipmaps but it doesn't seem to work.


Is that something angros will have to fix?


angros47(Posted 2016) [#252]
Openb3d only uses one framebuffer object (there may be a reason)


The reason is just that I added the command CameraToTex with the purpose to render on textures (i.e. for cubemapped reflections), not with shader tricks in mind, and so one FBO was enough. Also, it made the syntax very simple: just one command, with two parametes (the camera, and the texture). It's possible to add more FBOs, of course, but syntax would become quirky and incompatible with current one, breaking down some existing code. Also, to make a generic, all purpose command, being able to use many FBO is not enough, you'd need to be able to set what you want in each of them (one with colors only, one with normal mapping only, one with depth buffer only... or maybe one with colors and depth buffer, one with normal and stencil buffer, and so on). It could be done, but how the syntax of such a command would be? Understanding it might be harder than re-writing a specific render for the single purpose one wants. Anyway, if someone has any suggestions, I'll see what can be done.


markcw(Posted 2016) [#253]
Well the CameraToTex frame parameter is not used so this could be changed to flags to support new options with zero being the current code. Just expanding it to allow 2 (or 3 at the most) FBOs for postfx shaders like bloom and 2-pass blur would be enough for me, there's already a working depthbuffertotex example and I can't see anyone needing a stencilbuffertotex. I was trying to do a 2-pass postfx shader but haven't got it working yet (it sort of fails after a while) but fps was better than I expected.


angros47(Posted 2016) [#254]
And how could it return all the FBO needed? As texture frames, maybe? Currently, there is no easy way to access specific frames of a texture from a shader.

Or maybe, a new class could be added, that contains FBO arrays, to be used only with shaders. And a command CameraToFBO, or something similar.


markcw(Posted 2016) [#255]
Actually, I've just managed to get a 2 pass postfx shader going (see sl_shimmer2.bmx) and the fps is okay 11 (vs 17 for 1 shader) on ubuntu so I think this will do fine!