Posted: 10th Oct 2014 12:28
10. Entity Editor


Entity Editor is a dialog box. So PropertyList part is finally merged to the project !!

It is called in view menu or Enter key and edits the selected entity. With this dialog we can:
- Show/hide entity
- Change entity name
- Call a module editor


First, as usual, an overview of the structure:

ENTITY EDITOR

Variables:
EntityEditorPropList
EntityEditorPropCell_Enabled
EntityEditorPropCell_Name
EntityEditorPropCell_ModuleList

EntityEditorEntity
EntityEditorEntityName$

Functions:
EntityEditor_Open(Entity, Window)
EntityEditor_Close()
EntityEditor_Process(EventMouseDblcGadget, EventReturnKeyDownGadget)

Helper function:
ShowEntityEditorWindow(Entity)


Let us look at how it operates. Note that the same logic is applied to other editors of the app.

Global EntityEditorEntity, EntityEditorEntityName$
The structure is a singleton -> The edition is single-instance.

The editor is called with ShowEntityEditorWindow(Entity)
If Entity is 0 The dialog is closed if it was opened. If the same Entity was already opened, the dialog window is simply brought to front!


EntityEditor_Open(Entity, Window)
Notice the EntityEditor and the parent toolwindow have separated logics..

EntityEditorPropList = CreatePropList(0, 0, 320, 320, UIFont, UIBoldFont, Window)
Enabled = Entities(Entity).Flags && %1
EntityEditorPropCell_Enabled = PropList_AddEnable(EntityEditorPropList, "Enabled", Enabled)
EntityEditorEntityName$ = GetTreeViewItemText(EntityListTreeView, Entities(Entity).UIData)
EntityEditorPropCell_Name = PropList_AddEdit(EntityEditorPropList, "Name", EntityEditorEntityName$)
PropList_AddLabel(EntityEditorPropList, "Modules (Double Click to edit)")
EntityEditorPropCell_ModuleList = PropList_AddListBox(EntityEditorPropList, 104)

Creates easyly the gadgets of the dialog. We begin here to get the benefit of time invested in writing the propertylist!!!

Module = Entities(Entity).FirstModule
If Module
For j = 0 To 1
print console "AutoOpenModule ", Module, " ", Module_GetRetained(Module), crlf$()
AddItem ListBoxGadget, ModuleClasses(Modules(Module).ModuleClass).Name$
If Module_GetRetained(Module) Then Module_Edit(Module)
Module = Modules(Module).NextModule
j = (Module = 0)
Next j
EndIf

This populates the modules listbox and introduce us the retain mechanism. 3 management bits are defined in a module.(Step 8...)
One is the retain bit. The module editors are called from the entity editor. If the entity is closed so the module editors do.
But if the entity is opened again, the module editors will be automatically opened according to their last state.
This spare us lot of mouse handlings!!


If Module_GetRetained(Module) Then Module_Edit(Module)

Calls the function defined in the module class (Step 8...)
In this step, these are just placeholders... nevertheless, I left some debug messages in the console so that we can see the retain values in action.
We realize here the power of function pointers and "class design".. I wonder if it would have been possible to write a such app
if function pointers were not supported by DBPro...

+ Code Snippet
Function ShowTransformEditorWindow(TransformModule)

debugprint "ShowTransformEditorWindow() ", TransformModule, CRLF$()
debugprint "A Transform module editor will be here soon!", CRLF$()

EndFunction


EntityEditor_Process(EventMouseDblcGadget, EventReturnKeyDownGadget)
I've already said that, but processing the propertylist is easy!:

If EventMouseDblcGadget Then PropList_SelectGadget(EntityEditorPropList, EventMouseDblcGadget)
If EventReturnKeyDownGadget Then PropList_ValidateGadget(EntityEditorPropList, EventReturnKeyDownGadget)

If PropList_GetEvents(EntityEditorPropList)
If PropListCell_IsChanged(EntityEditorPropCell_Enabled)
...
EndIf

If PropListCell_IsChanged(EntityEditorPropCell_Name)
...
EndIf

If PropListCell_IsChanged(EntityEditorPropCell_ModuleList)
...
EndIf
EndIf


Just a few lines are needed in the app main loop to process non-modal:


Window = ToolWindows(APPTOOLWINDOW_ENTITYEDITOR).Window: If Window
EntityEditor_Process(EventMouseDblcGadget, EventReturnKeyDownGadget)
If EventCloseWindow = Window Then ShowEntityEditorWindow(0)
EndIf


Voila, that's all for today !


Merging All Together (Download)
Posted: 2nd Nov 2014 12:20
11. Module Definition and Module Editors


The Module Definition and Module Editors are located in the respectives Module(..).dba files, which regroup all the module related code.

3 Modules are revealed in this step: "Transform", "Cube" and "Sphere". The two others, "Mesh" and "Object Render" will be in the next steps.

So in a module file we find:
- Module Constants definition
- Module Functions
- Module Editor call function
- Module Editor variables and functions
- Module Load function
- Entity Update function


A part of these corresponds to the module class definition
+ Code Snippet
Type TModuleClass
	Name$, NameHash
	PropertyCount

	OnCreateInstanceFunction As DWORD
	OnReleaseFunction As DWORD
	OnEditFunction As DWORD
	OnUpdateFunction As DWORD
	TranslateToXMLFunction As DWORD
EndType



Let's look to "ModuleSphere.dba", taken here as example.

Module Constants

#Constant MODULESPHERE_ROWSINDEX 0
#Constant MODULESPHERE_COLUMNSINDEX 4

These are offsets of properties in module memory space.

Module Functions
OnCreateInstanceFunction is called to init data in memory space other than zero:

Function ModuleSphere_SetDefaultValues(ModuleData As DWORD)

Poke Integer ModuleData+MODULESPHERE_ROWSINDEX, 9
Poke Integer ModuleData+MODULESPHERE_COLUMNSINDEX, 9

EndFunction

Rem Note about this sphere: rows and columns indices are not the values, but indices in a table


OnReleaseFunction is called when the module is deleted.

In order to lighten this step, TranslateToXMLFunction and Load function will be discussed in the Load&Save topic..


Module Editor call function
defined in OnEditFunction:
ShowSphereEditorWindow(SphereModule)



Module Editor variables and functions
Module Editors are dialog boxes to edit specific part of an entity. They are opened from the Entity Editor.
As said in the previous step, The editors follow the same logic.

Global SphereEditorPropList
Global SphereEditorPropCell_Enable
Global SphereEditorPropCell_Rows
Global SphereEditorPropCell_Columns

Global SphereEditorModule

SphereEditor_Open(SphereModule, Window)
SphereEditor_Close()
SphereEditor_Process(EventMouseDownGadget, EventReturnKeyDownGadget)


_InvalidateCells()
and _RefreshCells(). For modules which have properties that can be changed outside the editor
(e.g. a transform changed with gizmos..)



Entity Update function
This function applies the module properties changes to entity.
Defined in OnUpdateFunction:

Function UpdateEntity_SphereMesh(Entity, Module)

Local SphereModuleData As DWORD


EditorObject = Entities(Entity).EditorObject
If EditorObject
SphereModuleData = Modules(Module).ModuleData
EditorObjects(EditorObject).Param1 = Peek Integer(SphereModuleData+MODULESPHERE_ROWSINDEX)+3
EditorObjects(EditorObject).Param2 = Peek Integer(SphereModuleData+MODULESPHERE_COLUMNSINDEX)+3

EditorObject_Clear(EditorObject)
EditorObject_Restore(EditorObject)

If Entities(Entity).Transform Then EditorObject_ApplyTransform(EditorObject)
EndIf

EndFunction



Updating the entity
The process of Updating the entity is done asynchronously by marking the "Updated" management bit of the module:
...
If PropList_GetEvents(SphereEditorPropList)
...
Module_SetUpdated(SphereEditorModule, true)
EndIf
...

The updating action, (by calling the Entity Update function) is done in the main loop:

+ Code Snippet
Rem - Update Entity changes -
		Entity = SceneEditor_GetSelectedEntity()
		If Entity
			Module = Entities(Entity).FirstModule
			If Module
				For j = false To true
					If Module_GetUpdated(Module)
						FunctionPtr = ModuleClasses(Modules(Module).ModuleClass).OnUpdateFunction
						If FunctionPtr Then Call Function Ptr FunctionPtr, Entity, Module
						Module_SetUpdated(Module, false)
					EndIf
					Module = Modules(Module).NextModule
					j = (Module = 0)
				Next j
			EndIf
		EndIf


Doing this keeps some separation between components of the app!

Module Enable
Each module module have a enable checkbox. But I haven't implemented this functionnality yet!


Merging All Together (Download)
And as usual, feel free to comment this project!
Posted: 26th Nov 2014 16:45
12. Resources

This is an important and not so easy part.
In a few words, resources are links to externals files such as textures, meshes...(and that's all, so far..)
So that these files are managed in a unified system!


Media Folder
Modern editors rely on an "Asset Database". Unfortunatly, I can't afford a such thing in this small project..
So I have opted for the good old companion folder, that includes the project files.
(but including files from folder other than this is of course possible !)
An upside of this is the possibility to move or copy a whole project to another folder easyly.


Set Media Folder in Edit Menu
The first thing to do before including resource is to define the Media Folder.
If not defined, the load button in the resource loader will appear grayed.


Overview of the structure

Type TResource
Id, NextFreeResource

UsageCount
Procedure As DWORD
ProcedureData As DWORD
Desc$
FilePath$
FileName$
EngineRef
ThumbnailImage
EndType

Variables
UsageCount: A resource can be used several times. The resource has to be released when this reaches 0.
Procedure: Function that operates the resource
ProcedureData: Parameters to the function
Desc$: Comment text to be displayed in the resource loader!
FilePath$: Absolute path to the file
FileName$: Filename only. Also the title of the resource in the resource loader..
EngineRef: DBP Reference, i.e image number, mesh number..
ThumbnailImage: DBP Image displayed in the resource loader!


Functions
Resource_GetProcName(Resource)
Resource_GetFileName$(Resource)
Resource_GetRef(Resource)
Resource_ReleaseRef(Resource)

Helper function
CreateResource(Procedure As DWORD, ProcedureData As DWORD, FileName$) where Procedure is a function pointer to the resource procedure!


The resource procedure
The differents types of resource must have their own operations for creating, deleting, loading....
so why not use the "class design", like the modules??
This is powerful but quite heavy.
This time, I use something lighter. This is made possible because there is not so much interaction with the app..
There is only one function for a resource type. e.g:
TextureResourceProc(Resource, Op$)
Where Op$ is the operation name (available operations are "create", "delete", "restore", "procname")


+ Code Snippet
Function TextureResourceProc(Resource, Op$)

	Op$ = Fast Lower$(Op$)

	If Op$ = "create"
		Image = Reserve Free Image()
		Load Image Resource_GetFileName$(Resource), Image

		Resources(Resource).EngineRef = Image
		Resources(Resource).ThumbnailImage = ThumbnailTexImg
	EndIf

	If Op$ = "delete"
		Image = Resources(Resource).EngineRef
		Delete Image Image
		Release Reserved Image Image
		Resources(Resource).EngineRef = 0
	EndIf

	If Op$ = "restore"
		Image = Resources(Resource).EngineRef
		Load Image Resource_GetFileName$(Resource), Image
	EndIf

	If Op$ = "procname" Then ResourceString$ = "Texture"

EndFunction true



Resource selector
Resource selector is a modal window for selecting a resource. From this window, we can choose an existing resource
or load a new file. In this case a new resource is created.


Mesh Module
Once the resource system done, let's start using it !
A new module, Mesh Module, is revealed. We can import mesh files in addition to primitives.


To Do
Better Thumbnails. Right now, the thumbnails in the selector simply depict the resource type of the resource. It would be cool to show the content...
Error control. If file loading fails the app crashes. There is some M1U features to solve this...

Merging All Together (Download)
Posted: 19th Dec 2014 19:26
13. Materials


Let's add some color and texture to our white objects!
Objects appereance is a vast domain.. so you'll find here a limited implementation, which takes shape
of 2 material types available.. As the rest of the project, the main point here is the principle, not the quantity..

Materials are instances of material types. Material types looks like both modules and resources.
They have data in memory, a procedure and an editor. That means that material types are built-in!


Overview of the structure

Type TMaterial
Name$

Procedure As DWORD
ProcedureData As DWORD
ProcedureTarget

OnEditFunction As DWORD
TranslateToXMLFunction As DWORD

ThumbnailImage
EndType

Variables
Name$: Self explanatory!
Procedure: Function that operates the material
ProcedureData: Parameters to the function
ProcedureTarget: Target object. Set before calling the procedure
OnEditFunction: Function pointer to material editor
ThumbnailImage: DBP Image displayed in the material loader!

Helper function
Function CreateMaterial(Name$, Procedure As DWORD)
Function CopyMaterial(SourceMaterial)


The Material procedure
As the resources, Materials are given a procedure. The available operations are "create", "delete", "copy"
"apply", "update", "detach" and "defaultname".

+ Code Snippet
Function StdLightingMaterialProc(Material, Op$)

Local ProcData As DWORD


	If Material = 0 Then ExitFunction false

	Op$ = Fast Lower$(Op$)

	If Op$ = "create"
		Materials(Material).OnEditFunction = Get Ptr To Function("ShowMaterialStdLightingEditorWindow")
		Materials(Material).TranslateToXMLFunction = Get Ptr To Function("MaterialStdLighting_TranslateToXML")

		Size = 16
		ProcData = Make Memory(Size)
		Fill Memory ProcData, 0, Size
		Materials(Material).ProcedureData = ProcData

		Materials(Material).ThumbnailImage = ThumbnailMat1Img

		Poke Integer ProcData+MATERIALSTDLIGHTING_DIFFUSE, RGB(255, 0, 255)
		Poke Integer ProcData+MATERIALSTDLIGHTING_SPECULAR, RGB(255, 255, 255)
		Poke Integer ProcData+MATERIALSTDLIGHTING_EMISSIVE, 0
		Poke Integer ProcData+MATERIALSTDLIGHTING_AMBIENT, RGB(255, 255, 255)
	EndIf

	If Op$ = "delete"
		ProcData = Materials(Material).ProcedureData
		Delete Memory ProcData
	EndIf

	If Op$ = "copy"
		Size = 16
		ProcData = Make Memory(Size)
		Copy Memory ProcData, Materials(Material).ProcedureData, Size
		ExitFunction ProcData
	EndIf

	If Op$ = "apply" Then Op$ = "update"

	If Op$ = "update"
		ProcData = Materials(Material).ProcedureData
    	Object = Materials(Material).ProcedureTarget
		Set Object Diffuse Object, Peek Integer(ProcData+MATERIALSTDLIGHTING_DIFFUSE)
		Set Object Specular Object, Peek Integer(ProcData+MATERIALSTDLIGHTING_SPECULAR)
		Set Object Specular Power Object, 0
		Set Object Emissive Object, Peek Integer(ProcData+MATERIALSTDLIGHTING_EMISSIVE)
		Set Object Ambience Object, Peek Integer(ProcData+MATERIALSTDLIGHTING_AMBIENT)
	EndIf

	If Op$ = "detach"
    	Object = Materials(Material).ProcedureTarget
		Set Object Diffuse Object, RGB(255, 255, 255)
		Set Object Specular Object, 0
		Set Object Emissive Object, 0
		Set Object Ambience Object, RGB(255, 255, 255)
	EndIf

	If Op$ = "defaultname" Then Materials(Material).Name$ = "StdLighting"

EndFunction true



Base materials
A new material is created by copying an existing one in the material list. The first ones are the base materials,
and they can't be deleted.


Applying a material to an Entity
A Material variable is defined in the Entity but this task belongs to The SceneEditor structure:

+ Code Snippet
Function SceneEditor_ApplyMaterial(Material, Entity)

	If Material = 0 Then ExitFunction

	Entities(Entity).Material = Material

	EditorObject = Entities(Entity).EditorObject
	If EditorObject = 0 Then ExitFunction

	Materials(Material).ProcedureTarget = EditorObjects(EditorObject).Object
	Call Function Ptr Materials(Material).Procedure, Material, "apply"

EndFunction


Function SceneEditor_DetachMaterial(Entity)

	Material = Entities(Entity).Material
	If Material = 0 Then ExitFunction

	Materials(Material).ProcedureTarget = EditorObjects(Entities(Entity).EditorObject).Object
	Call Function Ptr Materials(Material).Procedure, Material, "detach"

	Entities(Entity).Material = 0

EndFunction



Material editors
The Material editors follow the same design as the module editors with the same set of functions:

ShowMaterialStdLightingEditorWindow(Material)
MaterialStdLightingEditor_Open(Material, Window)
MaterialStdLightingEditor_RefreshCells()
MaterialStdLightingEditor_Process(EventReturnKeyDownGadget, EventMouseDownGadget, EventMouseUpGadget)


Updating a material
When a Material editor is opened, the entities with this material are selected with MaterialEditor_SelectTargets(Material) function.
Targets are the DBP objects, stored in a array..
If a value is changed in the editor, MaterialEditor_UpdateSelectedEntities() runs the "update" operation on all the selected targets..


ObjectRender Module
ObjectRender Module is revealed! It allows: Select a material, open the material editor with the entity material and detach the material.
(other options like lighting, culling.. will come later...)


Merging All Together (Download)
Posted: 2nd Jan 2015 20:26
14. Load and save scenes

The file format I have chosen is XML.
Let's get straight in the heart of the matter with a sample file:

+ Code Snippet
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<LV3D>
	<Settings MediaPath="media\"/>
	<Resource Type="Mesh" FilePath="" FileName="Object1.x"/>
	<Resource Type="Mesh" FilePath="Folder1\" FileName="Object2.x"/>
	<Resource Type="Mesh" FilePath="Folder1\" FileName="Object3.x"/>
	<Resource Type="Texture" FilePath="" FileName="Texture1.bmp"/>
	<Material Procedure="StdLighting" Name="Std Lighting 1">
		<StdLighting Diffuse="FFFF00FF" Specular="FFFFFF" Emissive="0" Ambient="FFFFFF"/>
	</Material>
	<Material Procedure="SingleTexture" Name="Single Texture 1">
		<SingleTexture TextureResource="4"/>
	</Material>
	<Material Procedure="StdLighting" Name="Std Lighting 2">
		<StdLighting Diffuse="FFFF00FF" Specular="0" Emissive="0" Ambient="0"/>
	</Material>
	<Camera Yaw="18" Pitch="39" FOVLevel="0" XC="0.512499928474" YC="0.471866965294" ZC="0.230144843459"/>
	<Light Yaw="0" Pitch="90"/>
	<EntityList>
		<Entity Name="Cube 0" Enabled="1">
			<ModuleTransform Enabled="1" PosX="-1" PosY="0" PosZ="0" RotX="0" RotY="0" RotZ="0" SclX="1" SclY="1" SclZ="1"/>
			<ModuleCube Enabled="1"/>
			<ModuleObjRender Enabled="1" Material="1" EnObjLight="1"/>
		</Entity>
		<Entity Name="Sphere 0" Enabled="1">
			<ModuleTransform Enabled="1" PosX="1" PosY="0" PosZ="0.5" RotX="0" RotY="0" RotZ="0" SclX="1" SclY="1" SclZ="1"/>
			<ModuleSphere Enabled="1" RowsIndex="9" ColumnsIndex="9"/>
			<ModuleObjRender Enabled="1" Material="2" EnObjLight="1"/>
		</Entity>
		<Entity Name="Object 1" Enabled="1">
			<ModuleTransform Enabled="1" PosX="1" PosY="0" PosZ="2" RotX="0" RotY="0" RotZ="0" SclX="1" SclY="1" SclZ="1"/>
			<ModuleMesh Enabled="1" MeshResource="3"/>
			<ModuleObjRender Enabled="1" Material="1" EnObjLight="1"/>
		</Entity>
	</EntityList>
</LV3D>


Basically it is a text file, so saving it has no particular difficulty.
But loading it is a different kettle of fish. Because it needs a complete parsing.
For that task, we'll use the Madbit's XML plugin, it will let us spare a lot of time!!


Saving a scene

If you've looked to the source, you may have noticed these mysterious ..._TranslateToXML void functions.
You've have likely guessed what they do: converting data values of the component into a XML formatted String...

+ Code Snippet
Function ModuleTransform_TranslateToXML(Module)

Local ModuleData As DWORD


	s$ = "<ModuleTransform"+XMLAttr("Enabled", Str$(Module_GetEnabled(Module)))
	ModuleData = Modules(Module).ModuleData
	s$ = s$+XMLAttr("PosX", Str$(Peek Float(ModuleData+MODULETRANSFORM_POSITIONX)))
	s$ = s$+XMLAttr("PosY", Str$(Peek Float(ModuleData+MODULETRANSFORM_POSITIONY)))
	s$ = s$+XMLAttr("PosZ", Str$(Peek Float(ModuleData+MODULETRANSFORM_POSITIONZ)))
	s$ = s$+XMLAttr("RotX", Str$(Peek Float(ModuleData+MODULETRANSFORM_ROTATIONX)))
	s$ = s$+XMLAttr("RotY", Str$(Peek Float(ModuleData+MODULETRANSFORM_ROTATIONY)))
	s$ = s$+XMLAttr("RotZ", Str$(Peek Float(ModuleData+MODULETRANSFORM_ROTATIONZ)))
	s$ = s$+XMLAttr("SclX", Str$(Peek Float(ModuleData+MODULETRANSFORM_SCALEX)))
	s$ = s$+XMLAttr("SclY", Str$(Peek Float(ModuleData+MODULETRANSFORM_SCALEY)))
	s$ = s$+XMLAttr("SclZ", Str$(Peek Float(ModuleData+MODULETRANSFORM_SCALEZ)))+"/>"

EndFunction s$

...

Function XMLAttr(AttrName$, AttrString$)

	s$ = " "+AttrName$+"="+Quote$(AttrString$)

EndFunction s$


Saving a scene consists mainly to scan the project components in a defined order and call the translate function
to write the XML nodes (also named XML Elements).
-Settings
-Resources
-Materials
-Camera
-Light
-Entity List, for each Entity, the modules


Loading a scene

The Project_Load(FileName$) function seems quite short (A file validity check is done before in the load command):

+ Code Snippet
Function Project_Load(FileName$)

	ProjectFileName$ = ""

	XML Open Document FileName$, 1

	XML Load Document 1

	XML Get Root Element 1, 1

	ProjectMediaPath$ = "": Rem - Settings -
	ProjectMediaPathLen = 0

	_Project_LoadXMLChildElements(1, "LV3D")

	XML Release Element 1
	XML Close Document 1

	ProjectFileName$ = FileName$

EndFunction true


Loading a scene consists of
-Scan the root node
-Scan the child nodes
-For each node, scan the attributes
-If here, scan the child nodes...

The hard part is done in the _Project_LoadXMLChildElements(), that is a recursive function to traverse the node hierarchy!


Loading a node

So we have _TranslateToXML functions to save components. Of course we have a load counterpart!
And these functions are given a SetProperty_ prefix (they are not a part of the structure, unlike _TranslateToXML):

+ Code Snippet
Function SetProperty_ModuleSphere(PropertyName$, Value$)

	PropertyName$ = Fast Upper$(PropertyName$)

	If PropertyName$ = "#BEGIN"
		Entity = TreeView_GetItemData(EntityListTreeView, GetGadgetData(EntityListTreeView))
		SphereEditorModule = CreateModule(GetModuleClass("Sphere (Mesh)"))
		Entity_AddModule(Entity, SphereEditorModule)
		ExitFunction true
	EndIf
	If PropertyName$ = "#END" Then SphereEditorModule = 0: ExitFunction true
	If PropertyName$ = "ENABLED"
		ExitFunction true
	EndIf
	If PropertyName$ = "ROWSINDEX"
		Entity = TreeView_GetItemData(EntityListTreeView, GetGadgetData(EntityListTreeView))
		Poke Integer Modules(SphereEditorModule).ModuleData+MODULESPHERE_ROWSINDEX, IntVal(Value$)
		ExitFunction true
	EndIf
	If PropertyName$ = "COLUMNSINDEX"
		Entity = TreeView_GetItemData(EntityListTreeView, GetGadgetData(EntityListTreeView))
		Poke Integer Modules(SphereEditorModule).ModuleData+MODULESPHERE_COLUMNSINDEX, IntVal(Value$)
		ExitFunction true
	EndIf

EndFunction true


For each attribute scanned, the corresponding SetProperty_ function is called.
The secret lies in the function name. It is the same name of the XML Node.

<ModuleSphere Enabled="1" RowsIndex="9" ColumnsIndex="9"/>
|Node name | |Attribute| ...

So the function pointer can be solved using Get Ptr To Function():
Get Ptr To Function("SetProperty_"+XML Get Element Name(XMLElement))

The SetProperty_ function is also called at beginning and the end of the node with dummy attributes #BEGIN and #END.


Load & New commands

There is no particular difficulty with Save and a Save As command.. But Load is different...
Load involves drastic changes with the structures, all project data are erased.
It is better not to do this in the main loop but to set this a part of app flowchart:



So there is several ways to init a project:
- Create a new blank project (App start, New Project)
- Load from a file (Load project!)

Now, when the app is being written, It can be very time saving to automatically start with a test project.
this is included as a part of the project init..
- Create a debug scene
- Load a debug scene


Deffered scene building

When a project is loading, the data is created as the XML are scanned.
The visual part of creating the object is done after the file is loaded with the SceneEditor_BuildSceneAfterLoad() function


Merging All Together (Download)
Posted: 18th Jan 2015 18:56
15. Gizmos


We are there, we've finally reached the final part of this project!

Gizmos are 3D handles to easyly manipulate the transform of an entity.
They are shown with the 3 corresponding buttons in the toolbar.
There are 3 types of gizmos: Move, Rotate and Scale.
Move & Scale have several modes, switched with the central yellow button..


How It works

Gizmo functions:
Gizmo_Create(Camera)
Gizmo_IsChanged()
Gizmo_IsCapturing()
Gizmo_Update(MX, MY, MClick)
Gizmo_SetActiveObject(Object)
Gizmo_Hide()
Gizmo_SetSize(Size#)
Gizmo_SelectMoveGizmo()
Gizmo_SelectRotateGizmo()
Gizmo_SelectScaleGizmo()

An overlapping camera is used to render the arrows/circles objects.
That means that this second camera has to be updated in same time as editor camera..
(I do not like this so much.. another solution is to custom draw the objects, but It would have been even more work..)
As the code is quite massive, I unfortunaly lack time to go into more technical details..



The Modes

Move, Global Space


Move, Entity Space


Move, Ground & Wall mode


This one needs some explanations: The gizmos acts on a single axis except in this mode, which acts on a plane.
The camera pitch is taken into account to figure out on which plane the object is moved.
For "verticals" angles, the object is moved to the XZ plane (the "ground")
For "Horizontals" angles, the object is moved to the a plane perpendicular to ground and facing the camera (the "Wall")

Rotate


Scale, Non-uniform


Scale, Uniform



Black Highlight

sometime the axis is highlighted in black. This means that the gizmo can't be moved,
due to a division by 0/near 0 security in the maths...


Merging All Together (Download)
Posted: 18th Jan 2015 18:57
And what's next ???

This project has reached a milestone but not its end for me, as I need it for an AppGameKit project (When 3D is completed...)

I have an infinite list of ideas and improvements but poor in time.
I'm switching to C++/DirectX. So it was my last DBP project, as DBP is no longer updated.

I also want to thank everyone who followed this project, hoping to have been useful..
According to interest, I may continue add new features and keep on post opensource.
But it will definitively leave the "Code Snippets" land!..

So feel free to comment and feedback!
Posted: 13th Feb 2015 5:30
This is incredible work Le Verdier, just want to thank you for sharing this with the community, really great and descriptive work. I had a little chuckle to myself every time I looked this because your work contradicted the title. It's like as the project got more advanced it got further away from the title

I'm switching to C++/DirectX. So it was my last DBP project, as DBP is no longer updated.

I have been considering the same thing because it actually looking like a problem when it comes to future projects in DBP. If there's no push for a new updates or a new DBP soon I will have to make the move also although C++/DirectX would be completely knew for me, though I imagine I could grasp it quickly since I can understand most C++ sources even if I've never programmed with them.
Posted: 14th Feb 2015 16:13
Thanks for the kind words...
I'm quite new too, I don't expect convincing results before months..
Gone are the days of quick coding and results !!
But I'm sure it is the right choice..

So this editor is my only living project with DBP.
And there will be some updates on this thread soon!
Posted: 19th Feb 2015 12:33
This project is entering in a new phase of small updates,
but as I said, leaves the tutorial land...

I may also silently fix some minor issues, some of them appeared when I splitted the code..
And with the workarounds I used to solve some ?? ?? ?? bugs, I wouldn't be surprised if you found some inconstancies..


V0.9.01
-A new name: LVEditor !!!!!
-Added "Plain" mesh module
-Gizmo now is restored properly
-Added Description text in texture resource


Source