Save scene?

Blitz3D Forums/Blitz3D Programming/Save scene?

Yue(Posted 2016) [#1]
I would like to know how you can save a scene. For example, thinking of scheduled modeling, where a cube, sphere, save it to a file for later reload it is created. Is it possible to do this ?.


RemiD(Posted 2016) [#2]
you mean the meshes, materials, textures, (like with a modeling tool) or the positions orientations scales ? (like with a map editor)
in both cases, yes you can.
you need to define the structure of your file format and then you know how to write datas (to save it) and how to read datas (bytes, shorts, integers, floats, strings) (to be able to load it and recreate it)


Yue(Posted 2016) [#3]
Yes. Where Sample?


Yue(Posted 2016) [#4]



I'm really stuck on this. Some example of how to save a scene ?. For example I add cubes, screens, lights, etc. Save want and then load them. There someone has done this before ?.

If I remember correctly Gile [S] does this and it was written in Blitz3D. Please help.


_PJ_(Posted 2016) [#5]
There's no default, native way to actually export the 3D world contents.
Therefore, you will need to track the different objects and their properties.

You may require to retain certain information (for example, Light type, range, colour - camera fog details, primitive shapes, spriteviewmodes etc.) on CREATTION of the objects and store this (i.e. within the custom type) in order to preserve it for later saving/loading.


Type OBJECTS
	Field Entity
	;...etc
End Type

Function SaveScene(FilePath$)
	Local Count=0
	Local T.OBJECTS
	For T=Each OBJECTS
		Count=Count+1
	Next
	
	If Count
		Local File=WriteFile(FilePath)	
		WriteInt File,Count
		For T=Each OBJECTS
			WriteObject(File,T\Entity)
		Next
		CloseFile File
	End If
End Function

Function LoadScene(FilePath$)
	;If required?
	ClearWorld
	Delete Each OBJECTS
	;-----------------------------
	
	Local File=ReadFile(FilePath)
	
	Local Count=ReadInt(File)
	Local Iter
	For Iter=1 To Count
		ReadObject(File)
	Next
	
	CloseFile File
End Function

Function WriteChildren(File,Entity)
	Local Count=CountChildren(Entity)
	WriteInt File,Count
	If (Count)
		Local Children
		Local Child
		For Children=1 To Count
			Child=GetChild(Entity,Children)
			WriteObject(Entity,Children,True)
		Next
	End If
End Function

Function WriteObject(File,Entity,Child=False)
	WriteString File,Lower(EntityClass(Entity))
	WriteString File,EntityName(Entity)
	
	WriteFloat File,EntityX(File,Not Child)
	WriteFloat File,EntityY(File,Not Child)
	WriteFloat File,EntityZ(File,Not Child)
	WriteFloat File,EntityPitch(File,Not Child)
	WriteFloat File,EntityYaw(File,Not Child)
	WriteFloat File,EntityRoll(File,Not Child)
	
	Select Lower(EntityClass(Entity))
		Case"mesh":
			;GetMatElement may be helpful here - but I don't know enough about that command.
			;You will need to extract the triangles/vertices/surfaces etc. here ______________________________________________________________________
			WriteObjectTexture(File,Entity)
		Case "terrain":
			;Ideally, SaveImage() heightmap may be used instead.
			WriteInt File,TerrainSize(Entity)
			WriteObjectTexture(File,Entity)
		Case "plane":
			WriteObjectTexture(File,Entity)
		Case "sprite":
			;It might be good to track and store spriteviewmodes and scaling?  - The BLITZ3D+ userlib extends B3D with commmands to retrieve these after creation.
		Default:
			;It might be good to track and store light-range and light colours? - The BLITZ3D+ userlib extends B3D with commmands to retrieve these after creation.
			;It might be good to track and store range, viewport, fog etc? - The BLITZ3D+ userlib extends B3D with commmands to retrieve these after creation.
	End Select
	
	WriteChildren(File,Entity)
End Function

Function WriteObjectTexture(File,Entity)
	Local Layer
	Local Surface
	Local Surfaces
	Local Brush
	Local Texture
	Local Layers
	Local TexturePath$
	
	Local Count=CountSurfaces(Entity)
	
	For Surfaces=1 To Count
		Surface=GetSurface(Entity,Surfaces)
		Brush=GetSurfaceBrush(Surface)
		For Layers=0 To 7
			Texture=GetBrushTexture(Brush,Layers)
			TexturePath$=TextureName(Texture)
			WriteString File,TexturePath
			FreeTexture Texture
			FreeBrush Brush
		Next
		
	Next
End Function	
	
	;It is IMPERATIVE that the readeing format maintains the same structure as writing. Keep a track of the order in which things are read/written...
Function ReadObject(File,Child=False,Parent=0)
	
	Local Entity
	
	Local Class$=Lower(ReadString(File))
	
	Local Name$=ReadString(File)
	Local X#=ReadFloat(File)
	Local Y#=ReadFloat(File)
	Local Z#=ReadFloat(File)
	
	Local Pitch#=ReadFloat(File)
	Local Yaw#=ReadFloat(File)
	Local Roll#=ReadFloat(File)
	
	Select (Class)
		Case "mesh"
			Entity=CreateMesh(Parent)
			;Here you will read back all the triangles,surfaces/vertices etc______________________________________________________________________
			ReadObjectTexture(File,Entity)
		Case "terrain":
			;Ideally, LoadTerrain may be used instead.
			Local Size=ReadInt(File)
			Entity=CreateTerrain(Size,Parent)
			ReadObjectTexture(File,Entity)
		Case "plane":
			Entity=CreatePlane()
			ReadObjectTexture(File,Entity)
		Case "light":
			;It might be good to track and store light-range and light colours? - The BLITZ3D+ userlib extends B3D with commmands to retrieve these after creation.
			Entity=CreateLight()
		Case "camera":
			;It might be good to track and store range, viewport, fog etc? - The BLITZ3D+ userlib extends B3D with commmands to retrieve these after creation.
			Entity=CreateCamera()
		Case "mirror":
			Entity=CreateMirror(Parent)
		Case "pivot":
			Entity=CreatePivot(Parent)
		Case "sprite":
			Entity=CreateSprite(Parent)
	End Select
	
	PositionEntity Entity,X,Y,Z,Not(Child)
	RotateEntity Entity,Pitch,Yaw,Roll,Not(Child)
	
	NameEntity Entity,Name
	
	Local Children=ReadInt(File)
	If (Children) Then ReadChildren(File,Entity,Children)
	
	If Not(Child)
		Local T.OBJECTS=New OBJECTS
		T\Entity=Entity
	End If
	
End Function

Function ReadChildren(File,Entity,Count)
	Local Children
	Local Child
	For Children=1 To Count
		; Be wary of memory leaks here, you can only access this child enitty via its parent
		ReadObject(File,True,Entity)
	Next	
End Function

Function ReadObjectTexture(File,Entity)
	Local Layer
	Local Surface
	Local Surfaces
	Local Texture
	Local Layers
	Local TexturePath$
	Local Brush
	
	Local Count=CountSurfaces(Entity)
	
	For Surfaces=1 To Count
		Surface=GetSurface(Entity,Surfaces)
		For Layers=0 To 7
			TexturePath$=TextureName(Texture)
			If (FileType(TexturePath)=1)
				Texture=LoadTexture(TexturePath);Paramters must be tracked somewhere ...
				If Not(Brush) Then Brush=CreateBrush()
				BrushTexture Brush,Texture,0,Layers
			End If
			FreeTexture Texture ; I am hoping this does not affect the texture as applied to Brush - if so, then it should be Free'd afterwards (perhasp using an array of Texture[layer]
		Next
		If Brush Then PaintSurface Entity,Brush
		FreeBrush Brush
		Brush=0
	Next
End Function	



RemiD(Posted 2016) [#6]
here is what i use for one of my map editor :



Yue(Posted 2016) [#7]
Thanks guys, I have a starting point to implement this. I have always something new to learn. :)


jfk EO-11110(Posted 2016) [#8]
just as a general view:

you need to say eg. x=100 and then position the mesh at x. Now you can save x in a textfile, later read x and reposition the mesh.

Of course you need to store not only X, But anything: path/filename, texturefilw, pitch yaw roll x,y,z,scale,fx.... to successfully restore the object.

Furthermore, you need a list of these multiple params, for a list of objects. you can use arrays, types or banks for that. The easiest may be arrays, like:

maxo=65000
dim x#(maxo)

;define params, by user input, or by reading from file:
x(zz)=100
...
positionentity mesh(zz), x(zz), y(zz...
zz=zz +1; set index to next object

;pseudocode for loading:

zz=0
re=readfile("mysaveworld")
while not eof(re)
file$(zz)=readline(re)
x(zz)=readline(re)
y(zz)=readline(re)
z(zz)=readline(re)
mesh(zz)=loadmesh(file$(zz))
positionentity mesh(zz),x(zz),y(zz),z(zz)
zz=zz+1
wend
closefile re

;and saving:

num=zz
wr=writefile("mysaveworld")
for zz=0 to num-1
writeline wr,file$(zz)
writeline wr,x(zz)
writeline wr,y(zz)
writeline wr,z(zz)
next
closefile re


The best approach is to first make a list of all the properties that need to be stored, by systematicly go trough the command reference for entity and mesh handling. Also, by adding eg. an object descriptor in the first line of an object block/container in savefile, such as "light" you can execute an individual loading/restoring procedure.


_PJ_(Posted 2016) [#9]
.


Yue(Posted 2016) [#10]



This does not work for me, my
experiments return extraneous data, I think I'm doing well, but obviously not. Any suggestions?


RemiD(Posted 2016) [#11]
@yue>>you can only write/read lines (strings) in .txt files, if you want to write/read bytes, shorts, integers, floats, strings, you must create a binary file (just replace .txt by .whatyouwant)
if you really want to write/read integers/floats values in a .txt file, you need to convert the integer/float to a string before writting it and convert the string to integer/float after reading it.


Yue(Posted 2016) [#12]
RemiD, i change code on post. I confused.


Yue(Posted 2016) [#13]
Sample, "Escene.whatyouwant", Yes?


RemiD(Posted 2016) [#14]
"filename.ext" where ".ext" is the extension that you prefer, but try to avoid the already used ones to prevent confusion (not .txt, .decls, .dll, .exe, .com, etc...)
it could be mapname.yuemap


Yue(Posted 2016) [#15]
OK, Thanks You. Problem here.



Type TData
	
	
	Field x#, y#, Z#
	
	
End Type 

Local c%
Local t1.TData = New TData 


t1\x# = 1.0
t1\y# = 2.0
t1\Z# = 3.0

Local t2.TData = New TData 


t2\x# = 4.0
t2\y# = 5.0
t2\Z# = 6.0




Function Init_TData.TData( x#,y#,Z# )
	
	
	Local Da.TData = New TData 
	
	
	Da\x# = x#
	Da\y# = y#
	Da\Z# = Z#
	
	
	
	Return Da.TData 
	
	
	
	
End Function 


Local file% = WriteFile("Level.map")

For t.TData = Each TData 
	
	c% = c% + 1
	
Next 



If c% Then 
	
	
	For t.TData = Each TData 
		
		WriteInt   file%, c%
		WriteFloat file%,t1\x#
		WriteFloat file%,t1\y#
		WriteFloat file%,t1\Z#
		
		
	Next 
	
	
	
End If 
CloseFile(file%) 

Color 255, 0, 0
Print "Save Data.. Ok"
Print ( "__________________________________")
Print ( "Press Key load data")

Delete Each TData
WaitKey()


Print ( "Data Objetc" ) 

file% = OpenFile("Level.map")

c% = ReadInt( file% )



For n% = 1 To  c% 
	
	
	
	x# = ReadFloat(file%)
	y# = ReadFloat(file%)
   	z# = ReadFloat(file%)
		
	
	Init_TData(x#, y#, z# ) 
	
	
	
	
	
		
		
	
	
	
	
	
Next 


For TC.TData  = Each TData 
	
	
	
	Print TC\X#
	Print TC\Y#
	
Next 



WaitKey()








CloseFile file%

Delete Each TData



Return number error.



Yue(Posted 2016) [#16]

Problem here.
No return, 1,2,3,4,5,6 :(




Hardcoal(Posted 2016) [#17]
I was in shock when i learnt blitz3d that u cant actually save what you created..
it seems to me a basic essential thing to be implemented on a so called game engine..

But once you make it right (save map..) it will serve u forever


_PJ_(Posted 2016) [#18]
1) Not sure if Blitz3D ever referred to itself as a 'Game Engine', raher as a programming language based on Blitz

2) Everything you create with Blitz3D can and may be saved.

3) Either you save the bb files, the compiled executable, or export relevant data using CreateFile or WriteFile etc.

________________________


@Yue I think this may help:

If c% Then 
	

		
WriteInt   file%, c%; Keep this outside the loop.
	
	For t.TData = Each TData 
		WriteFloat file%,t\x#; Not using t1\ as this refers to a specific instance from earlier. t\ is the current iteration of TData objets
		WriteFloat file%,t\y#
		WriteFloat file%,t\Z#
		
		
	Next