Blitz3d Types
Posted: Mon May 25, 2009 12:33 am
This tutorial was written by MarkCW
"Types are known as objects because they can hold a collection of variables. This feature of the language allows object-based programming which is a limited form of object-oriented programming. Types are stored at runtime in a linked list which is accessed every time you use one of the type-related commands ie. After, Before, Delete, Each, First, Handle, Insert, Last, New, Null, Object.
To create a type the first thing you need is a type structure with some fields in it. Next you create an instance of the type, an instance is a pointer or reference to a type object. Finally you can set and get type fields using the "pointer\field" syntax.
Type pointers themselves can't be treated like a normal variable, for example if you do this the compiler will throw an error.
This is because a type pointer stores an address which can't be accessed directly, but what if you want to store a bunch of types in an array? No problem, arrays can be assigned a type or you can use the Handle command.
Handle takes a type pointer and returns a runtime index number which represents the pointer. An important thing to remember is that a pointer won't be indexed until you pass it to Handle. To be precise, the counter starts at zero and increments every time you pass it a new pointer. When you delete a type its index is reset and that number isn't used again.
The Object command is the reverse of Handle, it takes a type handle and returns the pointer to it. If the handle doesn't exist it will return Null. Using a null pointer will throw a runtime error so you may need to check it exists before you access it. If you store type handles in an integer array you can then access the pointers using Object. Handle and Object are useful because they give us more ways to access types.
When you delete a type its place in the type list is deleted and all the objects after it are moved up the list. So if you're only using a For Each loop to access your types you won't need to check for null pointers, but other methods will usually need a null pointer check. Another way to access types is with the First, Last, After and Before commands. First returns the first pointer in a type list, similarly Last returns the last one, After returns the pointer after a specified pointer and likewise Before returns the one before it. Insert moves a pointer from one place to another in a type list, so it's one way to sort a list, another way would be to just sort handles in an array.
Functions also accept types as parameters and return values. This gives us a workaround with arrays, we can't pass arrays as parameters but we can pass a static array stored in a type. Another feature of types is that you can nest types in other types which is a basic form of inheritance. Nested types will not exist when you create their parent object, so they need to be created after the parent. Also, like variables we can use the Local command when creating types in functions to avoid a conflict with a global of the same name. An alternative to passing and returning types is to use Object and Handle. The advantage of this is more flexibility, for example you can pass all types in one parameter using Handle which can be used to create a form of polymorphism.
Note: inheritance is the ability to form new types of objects using objects that have already been defined. Polymorphism is the ability to handle different data types.
In Blitz3D, there is a well-known trick to accessing types from an entity. It relies on the fact that entities have names which are never used so we can store a type handle there without any problems. This lets us store as much extra information about entities as we want.
Images aren't entities so what if you want to store extra information about images? You can create functions to simulate NameEntity and EntityName. You could use arrays but they are not dynamic, fortunately banks are so they are the best choice. Banks can be resized without loss of data so we can have as many entries as we need.
In the following example, the first integer in the bank is reserved for counting the number of existing entries and then images are associated with a type by storing them as a double entry. The SetImageType function creates a new entry or changes the type handle if the entry already exists. GetImageType returns the type handle for an image. DeleteImageType removes an entry and then all the entries after it are moved up.
That's it! I have tried to cover all the main ways you can use types. If you think I missed something important then let me know so I can add it to this tutorial."
"Types are known as objects because they can hold a collection of variables. This feature of the language allows object-based programming which is a limited form of object-oriented programming. Types are stored at runtime in a linked list which is accessed every time you use one of the type-related commands ie. After, Before, Delete, Each, First, Handle, Insert, Last, New, Null, Object.
To create a type the first thing you need is a type structure with some fields in it. Next you create an instance of the type, an instance is a pointer or reference to a type object. Finally you can set and get type fields using the "pointer\field" syntax.
Code: Select all
;Example 1: How to create a type
Type MYTYPE
Field myinteger,myfloat#,mystring$
Field myintegerarray[2],myfloatarray#[2],mystringarray$[2]
End Type
SeedRnd(MilliSecs())
pType.MYTYPE=New MYTYPE
pType\myinteger=101
pType\myfloat#=1.23
pType\mystring$="foo"
pType\myintegerarray[0]=Rand(-10,10)
pType\myfloatarray#[1]=Rnd(-10.5,10.5)
pType\mystringarray$[2]="bar"
Print "myinteger="+pType\myinteger
Print "myfloat#="+pType\myfloat#
Print "mystring$="+pType\mystring$
Print "myintegerarray[0]="+pType\myintegerarray[0]
Print "myfloatarray#[1]="+pType\myfloatarray#[1]
Print "mystringarray$[2]="+pType\mystringarray$[2]
WaitKey()
End
Code: Select all
Print pType
Code: Select all
Print Handle(pType)
Code: Select all
;Example 2: How Handle and type arrays work
Type MYTYPE
Field myinteger,myfloat#,mystring$
End Type
Dim pArray.MYTYPE(4)
pArray(3)=New MYTYPE
pArray(2)=New MYTYPE
pArray(1)=New MYTYPE
Print "pArray(1)="+Handle(pArray(1))
Print "pArray(2)="+Handle(pArray(2))
Print "pArray(3)="+Handle(pArray(3))
Delete pArray(2)
pArray(4)=New MYTYPE
For id=1 To 4
Print "pArray("+id+")="+Handle(pArray(id))
Next
For pTemp.MYTYPE=Each MYTYPE
Print "pTemp="+Handle(pTemp)
Next
For id=1 To 4
pTemp.MYTYPE=pArray(id)
Print "pTemp="+Handle(pTemp)+" pArray("+id+")="+Handle(pArray(id))
Next
WaitKey()
End
Code: Select all
;Example 3: How Object and handle arrays work
Type MYTYPE
Field myinteger,myfloat#,mystring$
End Type
Dim myHandle(4)
For id=1 To 3
pTemp.MYTYPE=New MYTYPE
myHandle(id)=Handle(pTemp)
Print "myHandle("+id+")="+myHandle(id)
Next
Delete Object.MYTYPE(myHandle(2))
pTemp.MYTYPE=New MYTYPE
myHandle(4)=Handle(pTemp)
For pTemp.MYTYPE=Each MYTYPE
Print "pTemp="+Handle(pTemp)
Next
For id=1 To 4
pTemp.MYTYPE=Object.MYTYPE(myHandle(id))
Print "pTemp="+Handle(pTemp)+" myHandle("+id+")="+myHandle(id)
Next
WaitKey()
End
Code: Select all
;Example 4: How First, Last, After, Before and Insert work
Type MYTYPE
Field myinteger,myfloat#,mystring$
End Type
For id=1 To 5
pTemp.MYTYPE=New MYTYPE
Next
Delete First MYTYPE
pTemp.MYTYPE=First MYTYPE
For id=1 To 5
If pTemp<>Null
Print "First/After Loop="+Handle(pTemp)
pTemp=After pTemp
EndIf
Next
pTemp.MYTYPE=Last MYTYPE
For id=1 To 5
If pTemp<>Null
Print "Last/Before Loop="+Handle(pTemp)
pTemp=Before pTemp
EndIf
Next
Insert Last MYTYPE After First MYTYPE
Insert Last MYTYPE Before First MYTYPE
For pTemp.MYTYPE=Each MYTYPE
Print "Shuffled List="+Handle(pTemp)
Next
For pOuter.MYTYPE=Each MYTYPE
For pInner.MYTYPE=Each MYTYPE
pTemp.MYTYPE=After pInner
If Handle(pInner)>Handle(pTemp) And pTemp<>Null
Insert pInner After pTemp
EndIf
Next
Next
For pTemp.MYTYPE=Each MYTYPE
Print "Sorted by Handle="+Handle(pTemp)
Next
WaitKey()
End
Note: inheritance is the ability to form new types of objects using objects that have already been defined. Polymorphism is the ability to handle different data types.
Code: Select all
;Example 5: How types in functions work
Type MYTYPE
Field myint,myptr.MYNESTED
End Type
Type MYNESTED
Field myfloat#
End Type
Dim myHandle(4)
For id=1 To 4
pTemp.MYTYPE=TypeContructor()
Next
For pTemp.MYTYPE=Each MYTYPE
Print "pTemp="+Handle(pTemp)+" myptr="+Handle(pTemp\myptr)
Next
pTemp.MYTYPE=First MYTYPE
TypeUpdate(pTemp,101)
Print "myint="+pTemp\myint
For pTemp.MYTYPE=Each MYTYPE
TypeDestructor(pTemp)
Next
For id=1 To 4
myHandle(id)=HandleContructor()
Next
For pTemp.MYTYPE=Each MYTYPE
Print "pTemp="+Handle(pTemp)+" myptr="+Handle(pTemp\myptr)
Next
HandleUpdate(myHandle(1),1.23)
pTemp.MYTYPE=Object.MYTYPE(myHandle(1))
Print "myptr\myfloat#="+pTemp\myptr\myfloat#
For id=1 To 4
HandleDestructor(myHandle(id))
Next
WaitKey()
End
Function TypeContructor.MYTYPE(myparameter=0)
Local pType.MYTYPE=New MYTYPE
pType\myptr=New MYNESTED
pType\myint=myparameter
Return pType
End Function
Function HandleContructor(myparameter=0)
Local pType.MYTYPE=New MYTYPE
pType\myptr=New MYNESTED
pType\myint=myparameter
Return Handle(pType)
End Function
Function TypeDestructor(pType.MYTYPE)
Delete pType\myptr
Delete pType
End Function
Function HandleDestructor(myHandle=0)
Local pType.MYTYPE=Object.MYTYPE(myHandle)
Delete pType\myptr
Delete pType
End Function
Function TypeUpdate(pType.MYTYPE,myparameter=0)
If pType=Null Then Return False
pType\myint=pType\myint+myparameter
Return True
End Function
Function HandleUpdate(myHandle=0,myparameter#=0)
Local pType.MYTYPE=Object.MYTYPE(myHandle)
If pType<>Null
pType\myptr\myfloat#=myparameter#
EndIf
End Function
Code: Select all
;Example 6: How to associate a type with an entity
Type ENTITY
Field x#,y#,z#
End Type
Graphics3D 320,240,0,2
SetBuffer BackBuffer()
camera=CreateCamera()
light=CreateLight()
pTemp.ENTITY=New ENTITY
pTemp\x#=6.4
pTemp\y#=6.4
entity1=CreateMesh()
NameEntity entity1,Handle(pTemp)
Print "entity1="+EntityName(entity1)
pTemp.ENTITY=New ENTITY
pTemp\x#=12.8
pTemp\y#=12.8
entity2=CreateMesh()
NameEntity entity2,Handle(pTemp)
Print "entity2="+EntityName(entity2)
pTemp.ENTITY=Object.ENTITY(EntityName(entity1))
Print "pTemp\x="+pTemp\x#+" pTemp\y="+pTemp\y#
pTemp.ENTITY=Object.ENTITY(EntityName(entity2))
Print "pTemp\x="+pTemp\x#+" pTemp\y="+pTemp\y#
WaitKey()
End
In the following example, the first integer in the bank is reserved for counting the number of existing entries and then images are associated with a type by storing them as a double entry. The SetImageType function creates a new entry or changes the type handle if the entry already exists. GetImageType returns the type handle for an image. DeleteImageType removes an entry and then all the entries after it are moved up.
Code: Select all
;Example 7: How to associate a type with an image using a bank
Global bImageType=CreateBank(4)
Type IMAGE
Field x,y,w,h
End Type
Graphics 320,240,0,2
SetBuffer BackBuffer()
pTemp.IMAGE=New IMAGE
pTemp\w=64
pTemp\h=64
image1=CreateImage(pTemp\w,pTemp\h)
SetImageType(image1,Handle(pTemp))
Print "image1="+GetImageType(image1)
pTemp.IMAGE=New IMAGE
pTemp\w=128
pTemp\h=128
image2=CreateImage(pTemp\w,pTemp\h)
SetImageType(image2,Handle(pTemp))
Print "image2="+GetImageType(image2)
pTemp.IMAGE=Object.IMAGE(GetImageType(image1))
Print "pTemp\w="+pTemp\w+" pTemp\h="+pTemp\h
pTemp.IMAGE=Object.IMAGE(GetImageType(image2))
Print "pTemp\w="+pTemp\w+" pTemp\h="+pTemp\h
Print "BankSize="+BankSize(bImageType)
Print PeekInt(bImageType,0)
For id=4 To BankSize(bImageType)-4 Step 8
Print PeekInt(bImageType,id)+" "+PeekInt(bImageType,id+4)
Next
Delete Object.IMAGE(GetImageType(image1))
DeleteImageType(image1)
FreeImage image1
Print "BankSize="+BankSize(bImageType)
Print PeekInt(bImageType,0)
For id=4 To BankSize(bImageType)-4 Step 8
Print PeekInt(bImageType,id)+" "+PeekInt(bImageType,id+4)
Next
WaitKey()
End
Function SetImageType(image=0,typeid=0)
Local id,found
If image=0 Then Return False
For id=4 To BankSize(bImageType)-4 Step 8
If image=PeekInt(bImageType,id)
found=True
Exit
EndIf
Next
If found=True
id=PeekInt(bImageType,0)
PokeInt bImageType,id*8,typeid
Else
id=PeekInt(bImageType,0)+1
ResizeBank bImageType,4+(id*8)
PokeInt bImageType,0,id
PokeInt bImageType,(id*8)-4,image
PokeInt bImageType,id*8,typeid
EndIf
End Function
Function GetImageType(image=0)
Local id,found
If image=0 Then Return False
For id=4 To BankSize(bImageType)-4 Step 8
If image=PeekInt(bImageType,id)
found=True
Return PeekInt(bImageType,id+4)
EndIf
Next
If found=False Then RuntimeError "Image entry not found"
End Function
Function DeleteImageType(image=0)
Local id,at
If image=0 Then Return False
For id=4 To BankSize(bImageType)-4 Step 8
If image=PeekInt(bImageType,id)
at=id+8
Exit
EndIf
Next
If at>0
CopyBank bImageType,at,bImageType,at-8,BankSize(bImageType)-at
id=PeekInt(bImageType,0)-1
ResizeBank bImageType,4+(id*8)
PokeInt bImageType,0,id
EndIf
End Function