Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

Code Snippets / [DBP] - Very Basic 3D Scene Editor - Making Of - Step by step

Author
Message
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 10th Apr 2014 02:39 Edited at: 18th Jan 2015 19:00
Very Basic 3D Scene Editor - Making Of - Step by step


I start a thread in which I'll show the Making Of a 3d scene editor.
It will be released on several posts, each focusing on some specific task.
Basically, this program will allow to load objects or create primitive, place them, apply texture and load/save scene.
So very basic stuff... still structured and flexible enough to add new features.
Some topics focused: Windowing with BlueGUI, Camera control, Gizmo control, entity editing with properties sheets, load texture, save/load scene in xml...
Some plugins are needed:
Matrix1DLLs(IanM)
HGUI/BlueGUI(Humanoid/R.Knight)(OpenSorce)
Advanced2d(Diggsey)
XML(Madbit)
Extended Rotation(Madbit)

Q:Why this is in snippets board, it looks like a WIP ???
A:It's sitting on the fence between one and the other. I have not enough to show now for a WIP but It's can be considered like several completed snippets
Q:What skills are required ???
A:Beginner/Intermediate. But some basic knowledge of 3D maths and linear algebra


Summary
1. Setup a window with BlueGUI
2. Camera control
3. Adding a toolbar
4. Property lists
5. More property lists cell types
6. Overview of the core structures
7. EditorObject
8. Entity, Module, ModuleClass and SceneEditor
9. ToolWindow and EntityList
10. EntityEditor
11. Module Definition and Module Editors
12. Resources
13. Materials
14. Load and Save scenes
15. Gizmos

And what's next ???

All hail the new flesh
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 10th Apr 2014 02:39 Edited at: 6th Oct 2014 17:35
1. Setup a window with BlueGUI

We want here a window that does not stretch when resized. A simple way to do that is define the dbp window borderless at desktop size and set it as a child viewport of another window. But this causes some minors problems like the deactivated titlebar. fortunately, this can be solved with some handlings...
other trick is event handling, I sometime read:

If EventType() = .... Then DoThis()

I don't like it. because during execution of DoThis(), events can occur and this bad for responsiveness.
My method is to empty the event queue, storing the events into variables, and then process them.
Last issue: except the main loop, dont use do/loop while/endwhile repeat/until for loops. This because they perform some engine sync. use for/next instead is much faster...



Don't forget the gui.dba file. This one will be used on all the project, there is a few constants definition added



All hail the new flesh
seppgirty
FPSC Developer
14
Years of Service
User Offline
Joined: 3rd Jul 2009
Location: pittsburgh, pa.
Posted: 12th Apr 2014 01:26
Looking forward to this set of tutorials.

gamer, lover, filmmaker
Rick the Programmer
20
Years of Service
User Offline
Joined: 23rd Mar 2004
Location: Maryland
Posted: 12th Apr 2014 01:33
I'm working on something similar. I'm quite interested in seeing what kind of insight you'll offer

Ask not for whom the bell tolls;
It tolls for ye!
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 13th Apr 2014 00:34
Thank you for your interest..
The first posts will be dedicated to basic UI and control, in order to have a base to let some visual results
Then I introduce the internal structures and dive into them
Finally, give polish by improving some parts.
This editor is "basic", but will be flexible enough to add new features.
I.e although limited to "objects", a component-based entity system will be able to describe potentially "anything in the 3D space"
I plan approximatively ten topics, and I'll try at least one/week!

!!!
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 16th Apr 2014 17:43 Edited at: 15th May 2014 16:10
2. Camera Control

Let's start 3D with camera control !
For the 3D maths, we will use Extented Rotation plugin. Thanks to this plugin, we can ditch
the native dbp 3d math commands. Indeed, they have an annoying behavior: when the screen
is lost, the data is destroyed and have to be recreated. As the result, nothing can be stored safely here!
what the hell is this ???!!!??!?!!

We need at least 3 types of motion: a translate, a rotate and a zoom.

We need some variables
Global CameraDXMat As DWORD
Global CameraCenterDXVec3 As DWORD

Global CameraDist#
Global CameraYaw#
Global CameraPitch#
Global CameraFOVLevel
Global CameraRange#


CameraCenter is the point around which the camera rotates, look at and located at a fixed distance.



The zoom is controled by the Field Of View with the mousewheel.

the main loop part:


And the capture functions:


The capture are loops in the main loop. we still have to handle some app things, like the GUI events.



Improvement ideas:
More camera motions, e.g move forward/backward. Coords displayed in a status..

Merging all together (Download)

All hail the new flesh

Attachments

Login to view attachments
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 23rd Apr 2014 17:08 Edited at: 23rd Apr 2014 17:35
3. Adding a toolbar

With this toolbar, we'll select The edit mode. They are:
- Select entity
- Position entity
- Rotate entity
- Scale entity
- Editor light

The Pos/Rot/Scale buttons just display the corresponding transform gizmos.
The editor light activates the default light editmode

I often use this tip: store the "current value" of a gadget in its GadgetData instead
of a global variable.


There's no particular coding difficulty in this step.
There is just a minor issue: the toolbar button images doesnot take transparency into account,
but there's a simple workaround: provide image with alpha, paste it on a button-colored-background and grab.


Source organization
We start in this step to organize the source in a better way.
The variable and functions are regrouped a source file according to their related structure.


Merging all together (Download)

All hail the new flesh

Attachments

Login to view attachments
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 1st May 2014 17:16 Edited at: 6th Oct 2014 18:06
4. Property Lists

We'll need dialog boxes. Potentially a lot.
Those who have already programmed dialog boxes with Blue know, it takes a lot of time to write.
So we need a way to speed up the process, this way is the property list.
Instead of creating and handling the gadgets individually, we use
predefined blocks of gadgets arranged sequentially:



How does it works:

The property list is created easyly:


Remember, the event queue is emptied at the beginning of the main loop and the event are stored in variables


Interacting with the property list is just as easy.
The proplist is provided with a few events: "Validate", "Edit", "Click" and "Select".
then, the PropList_GetEvents() function runs the internal function of all the cells to figure out if one has changed:

Simple and quick!!


The demo

In this step, only the "Edit" and "Label" are available. But other cell types will be regularly added in the next step!


The Proplist functions:


The Cells functions, a "Create" and "Process" function by cell type:


As usual, dont forget the gui.dba included in the first step post!

All hail the new flesh
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 15th May 2014 16:04 Edited at: 6th Oct 2014 17:56
5. More Property list cell types

Boolean & Enable




ComboBox




Button




Vector




Resource Selector




Color Selector




ListBox




Code to add in the demo:
...
PropListCell_Enable = PropList_AddEnable(PropList, "Enabled", true)
PropListCell_Boolean = PropList_AddBoolean(PropList, "Boolean", true)
PropListCell_ComboBox = PropList_AddComboBox(PropList, "ComboBox", "Item 1;Item 2;Item 3;Item 4")
PropListCell_Button = PropList_AddButton(PropList, "Button")
PropListCell_Vector = PropList_AddVector(PropList, "Vector", 1.0, 2.0, 3.0)
PropListCell_Color = PropList_AddColorRGB(PropList, "Color", 0x0000ff)
PropListCell_ResSel = PropList_AddResourceSelector(PropList, "ResourceSelector", "My resource")
...
...
If PropListCell_IsChanged(PropListCell_Boolean) Then Print Console "Boolean changed: ", PropListCell_GetValue(PropListCell_Boolean, 0), CRLF$()
If PropListCell_IsChanged(PropListCell_Enable) Then Print Console "Enable changed: ", PropListCell_GetValue(PropListCell_Enable, 0), CRLF$()
If PropListCell_IsChanged(PropListCell_ComboBox) Then Print Console "Enable changed: ", PropListCell_GetValue(PropListCell_ComboBox, 0), CRLF$()
If PropListCell_IsChanged(PropListCell_Color) Then Print Console "Color clicked: "+Hex$(PropListCell_GetValue(PropListCell_Color, 0)), CRLF$()
If PropListCell_IsChanged(PropListCell_Button) Then Print Console "Button clicked: ", PropListCell_GetValue(PropListCell_Button, 0), CRLF$()
If PropListCell_IsChanged(PropListCell_ResSel) Then Print Console "ResSel clicked: ", PropListCell_GetValue(PropListCell_ResSel, 2), CRLF$()
If PropListCell_IsChanged(PropListCell_Vector)
v1# = Val(PropListCell_GetText(PropListCell_Vector, 0))
v2# = Val(PropListCell_GetText(PropListCell_Vector, 1))
v3# = Val(PropListCell_GetText(PropListCell_Vector, 2))
Print Console "Vector changed: ", v1#, " ", v2#, " ", v3#, CRLF$()
EndIf
...


The Property List Demo project file (Download)

All hail the new flesh

Attachments

Login to view attachments
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 2nd Jun 2014 14:07
New cell types added!
In the next post, we get straight to the heart of the matter with overview of core structures..

All hail the new flesh
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 2nd Jul 2014 20:27 Edited at: 12th Aug 2014 21:30
I'm quite busy these months so I've less time for coding..
That I can say is I have it 90% finished, but as you know, the last 10% are as long as the rest..


6. Overview of the core structures

"Structure". In an OOP langage, I would have said "Class". By "Structure", I mean mainly an UDT array and a collection of functions related to it. The array can be dynamic (elements can be added or removed) or table (element are defined at the beginning of the program). It can also be a singleton, in this case the array is replaced by variables.

App s
Globals variables and functions

UI s
BlueGUI Toolbar and fonts

Screen s
Handles the DBP window

ToolWindows t
Process dialog windows, retain pos/dims, process modal/nonmodal

Project s
Load, Save project. MediaPath. XML.

Camera s
Handles editor camera !!

Light s
Handles editor default light !!

SceneEditor s
Handles Entities in the scene

Entity d
Something in the 3D space. Contain a list of Modules

Module d
Group of properties related to specific part of an Entity

ModuleClass t
List of predefined functions to interact with a Module

ModuleEditors s
A ModuleEditor per ModuleClass. UI Part to edit a Module

EntityEditor s
UI Part to edit an Entity

EntityList s
The Entities contained in the scene
(Entity parenting is not implemented but left possible)

EditorObject d
Intermediate layer between "Object" Entities and DBP Objects

Gizmo s
3D Handles to edit the transform of an Entity. 3 types: Position / Rotation / Scale

Selector s
UI Dialog to select a resource

Resource d
Handle textures, objects.. Filename (Can also be procedural!). Take the usage count into account (=The same resource can be used several times)

MaterialEditor s
UI Part to edit material.
(Note: The materials are builtin (fully editable materials would have result a huge work..))

Structures with Dynamic elements
First, here's the naming I use, considering a structure named "Entity" taken as example..
UDT Name: TEntity
Array Name: Dim Entities(0) As TEntity
Function prefix: Entity_ for a particular Entity action(except deletion), otherwise Entities_

These structures are given a common set of variables and functions

NextFreeEntity: Next availaible slot of the array
Id: Id value

The availables element slots are maintained in a linked list
Element 0, that isn't used, contains the first of the list. If 0, a new array element is inserted.
Each new element receives an Id value. Althought the app uses the slot number,
the Id can be used for remapping the indices value and check the slot availability.

NewEntity(): Alloc a new slot index
DeleteEntity(): Free the slot, deleted when in the bottom else added in available slots list.. !Doesnot release the data.
DestroyEntity(): Release the data and free the slot
Clean(): Delete all the unused slots at the bottom of the array
FlushAll(): Release the data of all slots and Reset all the array
RestoreAll(): Call Restore() on all the used slots..

Release(): Release the data but keep the slot
Restore(): Called to restore the data when the screen is lost. Sometimes, the same function is called to init the data of the slot

All hail the new flesh
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 2nd Aug 2014 18:07
Just a word to say that i'm still working on it and
what I planned is almost finished!!!
I think I'll be able to continue my posts soon..
In the meanwhile, I can deliver a preview of what it look like!



All hail the new flesh
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 12th Aug 2014 21:43
Finished!
This gizmo part was quite massive piece of coding..
I can now clean/split the code and continue my posts..

I updated the step 6

Also feel free to to comment this project, this will keep me motivated!

All hail the new flesh
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 12th Aug 2014 21:44 Edited at: 12th Aug 2014 21:51
7. EditorObject

The EditorObject structure is an intermediate layer between "Object" Entities and DBP Objects
Doing this let some higher level structures being separated of DBP objects, this reduce design complexity..
We can also handle here some functionalities such as selecting, display the wireframe mesh of the object.

The EditorObject is created with CreateEditorObject(Source, ObjectType, Param1, Param2, Param3, Transform As DWORD)
Source is a related user data. Later, it'll be used to store the entity number..
Right now, here is 3 types of visual: Mesh, Cube and Sphere
The role of Param1,2,3 changes according to ObjectType..
Transform is 3x3 table (pos/rot/scl, X/Y/Z)




Merging All Together (Download)

All hail the new flesh

Attachments

Login to view attachments
GreenDixy
15
Years of Service
User Offline
Joined: 24th Jul 2008
Location: Toronto
Posted: 14th Aug 2014 07:05
amazing work Le Verdier !!

.:: Http://DeanWorks.Ca ::.
My software never has bugs. It just develops random features.
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 29th Aug 2014 20:48
Thank you GreenDixy!..

All hail the new flesh
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 29th Aug 2014 20:50 Edited at: 18th Sep 2014 19:03
8. Entity, Module, ModuleClass and SceneEditor

ENTITY

It is the key structure of the editor. By "Entity", I mean "something in the 3D space".
This editor is limited to objects but an entity could be anything else like a light, a camera...
An Entity is made of "modules".
By adding a module to the Entity, we add some new features to it
e.g: Let take a default cube mesh.. Add a "transform" and this cube is now movable, rotatable and scalable.
Add a "render object" and a material can be applied..
This design make the editor very flexible..!!
The modules are stored in a linked list. A "LastItem" variable is added so that the list is easier to handle..

UDT:
Type TEntity
NextFreeEntity, Id

Flags `b0:Enabled
UIData `Will be used to interact with the entity list
Transform As DWORD
EditorObject
FirstModule, LastModule
Material
QueryNext
EndType

Functions:
Entities_QuerySameMaterial(Material)
Entity_AddModule(Entity, Module)


MODULE & MODULE CLASS

Modules consist of two things: data in memory and a class.
A class is collection of functions to interact with these datas.
Some management bits are also defined here

UDT:
Type TModule
Id, NextFreeModule

PreviousModule, NextModule `for the linked list..
Flags `b0:Enabled b1:Retain Window b2:Updated
ModuleClass
ModuleData As DWORD
EndType

Functions: Mainly getter/setter:
Module_Edit(Module) Class caller for edit function
Module_CloseEdit(Module)
Module_SetEnabled(Module, Enabled)
Module_GetEnabled(Module)
Module_SetRetained(Module, Retained)
Module_GetRetained(Module)
Module_SetUpdated(Module, Updated)
Module_GetUpdated(Module)


UDT:
Type TModuleClass
Name$, NameHash
PropertyCount

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


No functions..

Helper functions:
AddModuleClass(Name$, PropertyCount)
GetModuleClass(Name$)


The function pointers are defined at the beginning of the app with The M1U function Get Ptr To Function()




SCENEEDITOR

This part of the app deals with entity creation, deletion and selection

Variables:
SceneEditorSelectedEntity
SceneEditorEntityPosX#
SceneEditorEntityPosY#
SceneEditorEntityPosZ#

Functions:
SceneEditor_BuildSceneAfterLoad()
SceneEditor_GetSelectedEntity()
SceneEditor_EntityUnderPoint(X, Y)
SceneEditor_SetNewEntityPosition(X#, Y#, Z#)
SceneEditor_DeleteSelectedEntity()
SceneEditor_SelectEntity(Entity)
SceneEditor_ApplyMaterial(Material, Entity)
SceneEditor_DetachMaterial(Entity)
SceneEditor_AddEntity_Object(Mesh, MeshId)
SceneEditor_AddEntity_Cube()
SceneEditor_AddEntity_Sphere()
SceneEditor_SetEntityEnabled(Entity, Enabled)


Merging All Together (Download)
The app look like the previous step but scene is now created with entities, which can now be selected with mouse..
(when toolbar button 2/3/4 is selected..)

All hail the new flesh

Attachments

Login to view attachments
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 18th Sep 2014 18:55 Edited at: 18th Sep 2014 19:05
9. ToolWindow and EntityList

TOOLWINDOW
The app interface has quite a bit dialog windows, this is a small structure to handle their window gadget.
The two interesting features here are retaining the pos/dims when a window is closed and reopened, Modal/Non-modal processing


UDT
Type TToolWindow
Window
Caption$
X, Y, W, H
Style
EndType


Functions
ToolWindow_Set(ToolWindow, X, Y, W, H, Resizable, Caption$)
ToolWindow_Open(ToolWindow)
ToolWindow_OpenResizable(ToolWindow)
ToolWindow_Close(ToolWindow)
ToolWindow_BeginModal(ToolWindow)
ToolWindow_EndModal()



To process non modal, just include the processing function call in the main loop:


The modal processing consists in running only one window and wait the user to close it.
All other windows are disabled during this time!


ENTITYLIST
Theorically, this should be a simple linked list with all the entities..
But something very different is used: a BlueGUI TreeView!!
The reasons:
-It is not implememented here but later, I would like Entity parenting.
-We need anyway to display the entities name set to the UI so that the user can select..,
a tree struture functions already exist via the treeview gadget, so just use them!

Variables
EntityListTreeView
EntityListRootTVI

EntityListCubeCount
EntityListSphereCount
EntityListObjectCount


Functions:
EntityList_CreateRoot()
EntityList_AddEntity(Entity, Name$)
EntityList_SelectEntity(Entity)


Helper Function:
CreateEntityList()

The treeview items and entities are binded with the UIData variable in the Entity structure and the TVI Data.
The gadget must not be deleted as it containt project data!
When its toolwindow is closed, the gadget is hidden and its parent window changed..


TreeView Additional functions
Some TreeView features needed but not present in Blue. Recreated here with user32dll calls:

TreeView_SetItemTextBold(TreeView, Item, TextBold)
TreeView_SetItemData(TreeView, Item, ItemData)
TreeView_GetItemData(TreeView, Item)
TreeView_ExpandItem(TreeView, Item)


Merging All Together (Download)
The EntityList Window is opened in View menu

All hail the new flesh

Attachments

Login to view attachments
GreenDixy
15
Years of Service
User Offline
Joined: 24th Jul 2008
Location: Toronto
Posted: 21st Sep 2014 21:25
Great work, As always.

.:: Http://DeanWorks.Ca ::.
My software never has bugs. It just develops random features.
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 6th Oct 2014 18:02 Edited at: 6th Oct 2014 18:08

A short post before the next step scheduled this week ..

I updated the property list part, this had to be fixed before the next step:
- New cell type added: the ListBox
- New event: Select
- Button fixed
and
- The whole property List Demo project file
- !A new gui.dba file used on all the project!

All hail the new flesh
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 10th Oct 2014 12:28 Edited at: 10th Oct 2014 12:33
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...



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)

All hail the new flesh

Attachments

Login to view attachments
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
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



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:


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!

All hail the new flesh

Attachments

Login to view attachments
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 26th Nov 2014 16:45 Edited at: 26th Nov 2014 16:58
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")





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)

All hail the new flesh

Attachments

Login to view attachments
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 19th Dec 2014 19:26 Edited at: 19th Dec 2014 19:32
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".




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:




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)

All hail the new flesh

Attachments

Login to view attachments
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 2nd Jan 2015 20:26 Edited at: 2nd Jan 2015 20:33
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:



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...



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):



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):



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)

All hail the new flesh

Attachments

Login to view attachments
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 18th Jan 2015 18:56 Edited at: 18th Jan 2015 19:15
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)

All hail the new flesh

Attachments

Login to view attachments
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 18th Jan 2015 18:57 Edited at: 18th Jan 2015 19:01
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!

All hail the new flesh
Sasuke
18
Years of Service
User Offline
Joined: 2nd Dec 2005
Location: Milton Keynes UK
Posted: 13th Feb 2015 05: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

Quote: "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.

"Get in the Van!" - Van B
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
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!

All hail the new flesh
Le Verdier
12
Years of Service
User Offline
Joined: 10th Jan 2012
Location: In the mosh-pit
Posted: 19th Feb 2015 12:33 Edited at: 19th Feb 2015 12:34
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

All hail the new flesh

Attachments

Login to view attachments

Login to post a reply

Server time is: 2024-03-28 08:21:28
Your offset time is: 2024-03-28 08:21:28