Noel,
This is not just an interoperability issue, this is a fundamental and performant language feature, only to benefit BMax and it's community. I'm not sure I understand how it "over" complicates the code - it indeed does the opposite, by simplifying it. See my previous examples above.
In essence it is syntatically very similar to a regular "Type" declaration in bmax. I don't even see a need to elevate this to an 'object' type, I think it is fine to treat it like any other first class data type (int, float, byte, etc).
I think you've made a point in favour of a 'C' style struct by suggesting that if you have the need to write code that works with C (or infact Delphi, .Net). To elaborate, by using pointers or writing a type that must create memory blocks that imitate the layour of a complex data structure (I've dropped the 'c' name, because interoping could invole any language with this ability), you've considerably over-complicated your code, reduced readability and maintainability.
You've now introduced additional memory requirements to create this 'fake' structure (which will be accessed by either memcopy's or peeks/pokes), overhead in copying to and from this structure and therefore performance.
Here is a more realistic example:
Noel, this is what you would have to do, and I think you may agree that adding a 'C' structured type is far less of an 'overcomplication' than the hoops required in this example ;-)
Type colourargb
Field a:Byte
Field b:Byte
Field g:Byte
Field r:Byte
End Type
' struct size 4 bytes
Type vert3
Field x:Double
Field y:Double
Field z:Double
Field normal:Double
Field colour:colourargb
End Type
' struct size 36 bytes
Type cube
Field name:Byte[32]
Field verts:vert3[8]
End Type
' struct size 320 bytes
Print "colourargb size: " + SizeOf(colourargb)
Print "vert3 size: " + SizeOf(vert3)
Print "cube size: " + SizeOf cube
Local mycube:cube = New cube
Print "mycube size: " + SizeOf mycube
For i = 0 Until mycube.verts.length
mycube.verts[i] = New vert3
mycube.verts[i].colour = New colourargb
Next
' cube size is 320 bytes
' layout:
' 0..31 : name
' 32..319 : vert3[8]
' vert3 size is 36 bytes
' layout:
' 0..7 : x
' 8..15 : y
' 16..23 : z
' 24..31 : normal
' 32..6 : colourargb
' colourargb size is 4 bytes
' layout:
' 0 : a
' 1 : g
' 2 : b
' 3 : r
' create bank:
Local cubemem:TBank = CreateBank(320)
' copy cube.name
For i = 0 Until mycube.name.length
PokeByte(cubemem, i, mycube.name[i])
Next
vert3size = 36
vert3start = 32
offset = 0
' copy cube.verts
For i = 0 Until mycube.verts.length
PokeDouble(cubemem, i * vert3size + offset, mycube.verts[i].x)
offset :+ 8
PokeDouble(cubemem, i * vert3size + offset, mycube.verts[i].y)
offset :+ 8
PokeDouble(cubemem, i * vert3size + offset, mycube.verts[i].z)
offset :+ 8
PokeDouble(cubemem, i * vert3size + offset, mycube.verts[i].normal)
offset :+ 8
PokeByte(cubemem, i * vert3size + offset, mycube.verts[i].colour.a)
offset :+ 1
PokeByte(cubemem, i * vert3size + offset, mycube.verts[i].colour.b)
offset :+ 1
PokeByte(cubemem, i * vert3size + offset, mycube.verts[i].colour.g)
offset :+ 1
PokeByte(cubemem, i * vert3size + offset, mycube.verts[i].colour.r)
offset = 0
Next
' now we can pass packed data structure off to external library
' call some lib function
' upon return, where the data may have been modified, we must copy
' back to our local objects
offset = 0
' copy cube.verts
For i = 0 Until mycube.verts.length
mycube.verts[i].x = PeekDouble(cubemem, i * vert3size + offset)
offset :+ 8
mycube.verts[i].y = PeekDouble(cubemem, i * vert3size + offset)
offset :+ 8
mycube.verts[i].z = PeekDouble(cubemem, i * vert3size + offset)
offset :+ 8
mycube.verts[i].normal = PeekDouble(cubemem, i * vert3size + offset)
offset :+ 8
mycube.verts[i].colour.a = PeekByte(cubemem, i * vert3size + offset)
offset :+ 1
mycube.verts[i].colour.b = PeekByte(cubemem, i * vert3size + offset)
offset :+ 1
mycube.verts[i].colour.g = PeekByte(cubemem, i * vert3size + offset)
offset :+ 1
mycube.verts[i].colour.r = PeekByte(cubemem, i * vert3size + offset)
offset = 0
Next
With a 'C' style or complex data type, it would be as simple as:
CType colourargb
Field a:Byte
Field b:Byte
Field g:Byte
Field r:Byte
End CType
' struct size 4 bytes
CType vert3
Field x:Double
Field y:Double
Field z:Double
Field normal:Double
Field colour:colourargb
End CType
' struct size 36 bytes
CType cube
Field name:Byte[32]
Field verts:vert3[8]
End CType
' struct size 320 bytes
Print "colourargb size: " + SizeOf(colourargb)
Print "vert3 size: " + SizeOf(vert3)
Print "cube size: " + SizeOf cube
Local mycube:cube = New cube
' call external lib function, passing mycube pointer directly
' no need to copy back to anything, as it was already modified in place.
So, aside from reducing the complexity, we have reduced:
Original:
mem allocs : 18
mem pokes (copy to bank) : 96
mem peeks (copy from bank): 64
Proposed 'c' style:
mem allocs : 1
mem pokes : 0
mem peeks : 0
That is 145 memory operations down to 1. Not bad. This also doesn't change based on the number of vertices in our 'object', cube in this case.
Let's extrapolate that out a little, to some arbitrary object with 1000 vertices:
Original:
mem allocs : 2002
mem peeks : 16032
mem pokes : 16000
Proposed 'c' style:
mem allocs : 1
mem pokes : 0
mem peeks : 0
Quite a difference.
Cheers,
Stu