Entity system allows organization of various kinds of entities in scenes. Programmers can define “solid” objects using geometric primitives, m15 models or display lists and specify their relationship. This is enough for most typical applications, but what to do when the programmer want to use different kinds of objects.
The answer is – use the function slot entity.
What is function slot
Function slot is the approach provided by the module allowing programmers to define their own, custom entities. All the geometry based entities in TBGL share some common properties and actions.
- Position, rotation, scale
- Colour, texture information
- User defined data
- Hierarchy
- Name
When creating user defined entity, it is safe to presume having all these options will be enabled for it. How to define the look? How to use the 3rd party rendering functions? How to actually create the custom entity?
- Custom entity, based on function slot approach, can be created in the following steps:
- define user defined type describing entity additional properties
- create entity of type “function slot”
- set it user data of choice
- write the function which will render custom primitive
- write action functions to control specific properties of the entity
Example
To demonstrate this simple approach, the technique will be explained on very basic example. Let’s presume we need special kind of entity – simple heat fan. It can be set to 2 states - turning, or stopped.
The first thing we need to do is design our data structure:
TYPE tFanEntity workingState AS BYTE END TYPE
Then we create the function slot entity, presuming our custom function will be represented by function Fan_Render. After the creation we supply some initial custom data to it.
DIM FanData AS tFanEntity FanData.workingState = 0 TBGL_EntityCreateFuncSlot( %sScene, %eFan, 0, “Fan_Render”) TBGL_EntitySetUserData(%sScene, %eFan, FanData)
SUB Fan_Render() ' -- Retrieve data DIM Data AS tFanData AT TBGL_EntityGetUserDataPointer(%sScene, %eFan) ' -- If in rotation state, let’s turn IF Data.WorkingState = 1 THEN TBGL_EntityTurn(%sScene, %eFan, 0, 0, 90/FrameRate) END IF ' -- Fan represented by two crossed thin boxes TBGL_Box(0.1, 2.0, 0.5) TBGL_Box(2.0, 0.1, 0.5) END SUB
As was mentioned earlier, we need to supply some more functions to be able to control the fan.
Doing this is very intuitive, all we need to do is get access to our fan data, and modify them as we need. All the changes to these properties can be then later reflected in the rendering routine.
The fan is simple object, so we will just need to control whether it turns or not. For this, we declare simple user function or sub with parameters, which will internally affect the fan properties.
SUB Fan_SetWorkingState( flag AS BYTE ) ' -- First we overlay structure over the memory of fan entity DIM Data AS tFanData AT TBGL_EntityGetUserDataPointer(%sScene, %eFan) ' -- Then we can set the properties, which will be immediately updated to entity Data.WorkingState = flag END SUB
Thinking more generally
It seems we have everything we need, but there is one problem with the solution proposed above – all actions are hardwired to %sScene scene and %eFan entity. This might be enough when we have only one entity of the kind and using one scene, but as we know, this is not the most common case.
How to make the functions usable for all entities of type “fan”? We need to properly identify the calling entity then we will be able to retrieve its custom data.
This is done by TBGL_CallingEntity command in conjunction with TBGL_tEntityIdentifier structure. It might sound complicated, but have a look at modified rendering routine below with changes marked in green:
SUB Fan_Render() DIM element AS TBGL_tEntityIdentifier AT TBGL_CallingEntity ' -- Retrieve data DIM Data AS tFanData AT TBGL_EntityGetUserDataPointer(element.scene, element.entity) ' -- If in rotation state, let's turn IF Data.WorkingState = 1 THEN TBGL_EntityTurn(element.scene, element.entity, 0, 0, 90/FrameRate) END IF ' -- Fan represented by two crossed thin boxes TBGL_Box (0.1, 2.0, 0.5) TBGL_Box (2.0, 0.1, 0.5) END SUB
Modifying action functions is even simpler, just by adding new parameters.
' -- Our custom actions SUB Fan_SetWorkingState( scene AS LONG, entity AS LONG, flag AS BYTE ) ' -- First we overlay structure over the memory of fan entity DIM Data AS tFanData AT TBGL_EntityGetUserDataPointer(scene, entity) ' -- Then we can set the properties, which will be immediately updated to entity Data.WorkingState = flag END SUB
Just a side note – unlike the case of the rendering function, which is fired internally by the TBGL_SceneRender command, we cannot use TBGL_CallingEntity here. This is because the entity control procedures, such as Fan_SetWorkingState in this case, are freely called directly by the programmer.
Conclusion
We have demonstrated the basics of creating custom entities, how to create custom rendering routine and how to modify the entity properties.
The full source code can be found and studied by opening the file from ThinBasic installation:
SampleScripts/TBGL/EntityBased/TBGL_CustomFanEntity.tBasic
The demonstrated example is very simple, so it is packed with other code in single file. For serious projects we recommend to organize custom entities in separated include files, which you can later easily incorporate to your project, and move from one application to another easily.
Rate this article