Posted: 11th Apr 2015 3:40
Thanks so much to MonoCoder for the thread explaining the structure of Get Vertexdata Ptr() over here: http://forum.thegamecreators.com/?m=forum_view&t=213904&b=6
A few days back I was experimenting with combining lots of objects together into a single object to see if I could improve my FPS. I'm not sure how many people run into this problem, but it turns out DBPro won't allow an object to have an indexdata count more than 65535, for whatever reason (legacy support? ), which limits the amount of vertex/index data you can add with 'add mesh to vertexdata' - once the indexdata reaches the limit, you can't add anything else :/
Anyway, thanks to Monocoder's awesome thread I managed to put together an alternative system for adding vertexdata which gets around the limit, meaning you can have pretty much an infinite number of indicies per object!
Basically all it does is copy object's vertexdata and indexdata to a new chunk memory and manipulate it from there, so all the standard vertexdata commands still work fine for setting position, UV, etc

Here's the command list:
All the pointers used as parameters should be the pointer returned by Get Vertexdata Ptr() when that limb or mesh is locked!
+ Code Snippet
vertexdata_setupobject(ptr) - Sets up an object for custom vertexdata editing - this only needs to be called for objects you plan to add or remove verticies/indicies from (not the objects/meshes you're adding TO this object).

vertexdata_adddata(dest_ptr, source_ptr) - Add the verticies and indicies from the object/mesh at 'source_ptr' to the one at 'dest_ptr' - both objects need to be the same FVF format, because I'm too lazy to find a way to automatically convert them :/

vertexdata_removedata(ptr, vertex_start, vertex_end, index_start, index_end) - Deletes all vertexdata entries between (and including) vertex_start and vertex_end (and does the same with indexdata entries and index_start/index_end) from the object at 'ptr'

vertexdata_freeobject(ptr) - This needs to be called on any objects that were set up before they're deleted (including before the program closes) to free the memory set up for vertexdata, otherwise you'll get a crash (probably caused by DBPro trying to delete memory it didn't allocate itself)


And here's the code (with a small example):
+ Code Snippet
disable escapekey
sync on : autocam off
ink rgb(180, 100, 100)
set camera range 1, 15000 : position camera -3000, 250, -3000
obj_ptr as dword : mesh_ptr as dword
vertexcount as integer : newvertexcount as integer : indexcount as integer
xpos# as float : zpos# as float
`Make a cube mesh for adding to the vertexdata
make object cube 1, 100 : make mesh from object 1, 1
lock vertexdata for mesh 1 : mesh_ptr = get vertexdata ptr() : unlock vertexdata
delete object 1
`Make the main object and set it up for the system
make object box 2, 10000, 10000, 10000
lock vertexdata for limb 2, 0 : obj_ptr = get vertexdata ptr() : unlock vertexdata
vertexdata_setupobject(obj_ptr)
lock vertexdata for limb 2, 0
`Get rid of the object's verticies/indicies since it's only there as a base
vertexdata_deletedata(obj_ptr, 0, 23, 0, 35)
`Add 2500 cubes to the main object
for i = 1 to 2500
    vertexcount = get vertexdata vertex count()
    vertexdata_adddata(obj_ptr, mesh_ptr)
    newvertexcount = get vertexdata vertex count()
    xpos# = -5000 + random(10000) : zpos# = -5000 + random(10000)
    for k = vertexcount to newvertexcount - 1
        set vertexdata position k, xpos# + get vertexdata position x(k), get vertexdata position y(k), zpos# + get vertexdata position z(k)
    next k
next i
vertexcount = get vertexdata vertex count() : indexcount = get vertexdata index count()
unlock vertexdata
do
    text 0, 0, "Vertex count: " + str$(vertexcount) + "/Index count: " + str$(indexcount)
    text 0, 20, "Over 65535 incidies! :D"
    if keystate(17) = 1 then move camera 3.0
    if keystate(31) = 1 then move camera -3.0
    rotate camera clamp(camera angle x() + mousemovey() / 4.0, -90, 90), camera angle y() + mousemovex() / 4.0, camera angle z()
    `Free up the object before exit so it doesn't crash
    if escapekey() = 1 then vertexdata_freeobject(obj_ptr) : delete object 2 : end
    sync
loop

function vertexdata_setupobject(ptr as dword)
oldvertexptr as dword : oldindexptr as dword : vertexptr as dword : indexptr as dword
memblock as integer : mesh as integer
`Ptr + 4 = FVF type
`Ptr + 8 = FVF size (should always be 32 since I'm probably only gonna bother with FVF 274)
`Ptr + 20 = Pointer to vertexdata
`Ptr + 24 = Pointer to indexdata
`Ptr + 28 = Vertex count
`Ptr + 32 = Index count
`Ptr + 36 = Weird draw option which should always be 4
`Ptr + 40 = Vertex count (again, for some reason)
`Ptr + 44 = The number of polygons that are drawn
oldvertexptr = peek dword(ptr + 20) : oldindexptr = peek dword(ptr + 24)
vertexptr = alloc(peek dword(ptr + 8) * peek dword(ptr + 28))
copy memory vertexptr, oldvertexptr, peek dword(ptr + 8) * peek dword(ptr + 28)
poke dword ptr + 20, vertexptr
indexptr = alloc(peek dword(ptr + 32) * 2) `Indexdata entries are stored as words, which are 2 bytes big
if oldindexptr > 0 then copy memory indexptr, peek dword(ptr + 24), peek dword(ptr + 32) * 2
poke dword ptr + 24, indexptr

`There's a small memory leak here, because oldvertexptr and oldindexptr still exist as memory chunks created by DBPro
`Unfortunately you can't free them with 'delete memory' or 'free' - however, you CAN get rid of them by creating a blank mesh, and setting it's vertex/index pointers to oldvertexdata and oldindexdata
`That still leaves a tiny chunk of memory which DBPro sets aside for the blank mesh's vertexdata/indexdata, but for real, that's a really tiny chunk of memory, so it shouldn't ruin anything :)
if get vertexdata ptr() > 0 then exit prompt "Vertexdata error - Was setting up object with ID " + str$(ptr) + " - make sure nothing has it's vertexdata locked before you set up an object!", "Check your code!"
memblock = find free memblock() : mesh = find free mesh()
make memblock memblock, 12 : write memblock dword memblock, 0, peek dword(ptr + 4) : write memblock dword memblock, 4, peek dword(ptr + 8) : write memblock dword memblock, 8, 0
make mesh from memblock mesh, memblock : delete memblock memblock
lock vertexdata for mesh mesh : ptr = get vertexdata ptr() : poke dword ptr + 20, oldvertexptr : poke dword ptr + 24, oldindexptr : unlock vertexdata
delete mesh mesh
endfunction

function vertexdata_adddata(dest_ptr as dword, source_ptr as dword)
dest_vertexptr as dword : dest_indexptr as dword
source_vertexptr as dword : source_indexptr as dword
dest_vertexcount as integer : dest_indexcount as integer : fvfsize as integer
source_vertexcount as integer : source_indexcount as integer
if peek dword(dest_ptr + 4) <> peek dword(source_ptr + 4) then exit prompt "Vertexdata error - Destination FVF (" + str$(peek dword(dest_ptr + 4)) + ") and source FVF (" + str$(peek dword(source_ptr + 4)) + ") aren't the same :'/", "Check your code!" : end

dest_vertexcount = peek dword(dest_ptr + 28) : dest_indexcount = peek dword(dest_ptr + 32) : fvfsize = peek dword(dest_ptr + 8)

source_vertexptr = peek dword(source_ptr + 20) : source_indexptr = peek dword(source_ptr + 24)
source_vertexcount = peek dword(source_ptr + 28) : source_indexcount = peek dword(source_ptr + 32)
`Recreate the vertex and index memory with enough space for the new entries
`Vertex memory
dest_vertexptr = realloc(peek dword(dest_ptr + 20), (dest_vertexcount + source_vertexcount) * fvfsize)
copy memory dest_vertexptr + (dest_vertexcount * fvfsize), source_vertexptr, source_vertexcount * fvfsize
poke dword dest_ptr + 20, dest_vertexptr
`Index memory
if source_indexptr > 0
    dest_indexptr = realloc(peek dword(dest_ptr + 24), (dest_indexcount + source_indexcount) * 2)
    for i = 0 to (source_indexcount - 1) * 2 step 2
        `Add the destination vertex count to the index data, cause otherwise it's going to point to the wrong verticies :/
        `That also kind of means you can't set the data byte by byte, since you can't add the vertex count to each individual byte, that'd be mental
        poke word dest_indexptr + (dest_indexcount * 2) + i, dest_vertexcount + peek word(source_indexptr + i)
    next i
    poke dword dest_ptr + 24, dest_indexptr
endif
`Vertex count
poke dword dest_ptr + 28, dest_vertexcount + source_vertexcount
poke dword dest_ptr + 40, dest_vertexcount + source_vertexcount `The vertex count is written again here for some reason :s
`Index count
poke dword dest_ptr + 32, dest_indexcount + source_indexcount
`Polygon draw count
if source_indexcount = 0 : poke dword dest_ptr + 44, peek dword(dest_ptr + 44) + (source_vertexcount / 3) : else : poke dword dest_ptr + 44, peek dword(dest_ptr + 44) + (source_indexcount / 3) : endif
endfunction

function vertexdata_deletedata(ptr as dword, vertex_start as integer, vertex_end as integer, index_start as integer, index_end as integer)
old_vertexptr as dword : old_indexptr as dword
vertex_ptr as dword : index_ptr as dword
fvfsize as integer : vertex_count as integer : index_count as integer
old_vertexptr = peek dword(ptr + 20) : old_indexptr = peek dword(ptr + 24)
fvfsize = peek dword(ptr + 8) : vertex_count = peek dword(ptr + 28) : index_count = peek dword(ptr + 32)
`Copy the vertexdata memory to a new location, skipping the stuff between vertex_start and vertex_end
vertex_ptr = alloc((vertex_count - ((vertex_end - vertex_start) + 1)) * fvfsize)
copy memory vertex_ptr, old_vertexptr, vertex_start * fvfsize
copy memory vertex_ptr + (vertex_start * fvfsize), old_vertexptr + ((vertex_end + 1) * fvfsize), ((vertex_count - 1) - vertex_end) * fvfsize
free old_vertexptr : poke dword ptr + 20, vertex_ptr
`Do the same thing with the indexdata - copy the data across word by word, so it can be adjusted (cause the verticies they point to aren't valid anymore if any vertexdata's been deleted)
index_ptr = alloc((index_count - ((index_end - index_start) + 1)) * 2)
for i = 0 to (index_start - 1) * 2 step 2
    value = peek word(old_indexptr + i)
    if value => vertex_start and value <= vertex_end then value = 0 `This shouldn't really happen, since you probably want to also delete the indicies which correspond to the verticies you delete - so if any index values get set to 0, you've probably screwed up!
    if value > vertex_end then value = value - ((vertex_end - vertex_start) + 1)
    poke word index_ptr + i, value
next i
for i = 0 to (((index_count - 1) - index_end) - 1) * 2 step 2
    value = peek word(old_indexptr + ((index_end + 1) * 2) + i)
    if value => vertex_start and value <= vertex_end then value = 0
    if value > vertex_end then value = value - ((vertex_end - vertex_start) + 1)
    poke word index_ptr + (index_start * 2) + i, value
next i
free old_indexptr : poke dword ptr + 24, index_ptr
`Update vertexdata information
`Vertex count
vertex_count = vertex_count - ((vertex_end - vertex_start) + 1)
poke dword ptr + 28, vertex_count
poke dword ptr + 40, vertex_count
`Index count
index_count = index_count - ((index_end - index_start) + 1)
poke dword ptr + 32, index_count
`Polygon draw count
if index_count = 0 : poke dword ptr + 44, vertex_count / 3 : else : poke dword ptr + 44, index_count / 3 : endif
endfunction

function vertexdata_freeobject(ptr as dword)
free peek dword(ptr + 20) : free peek dword(ptr + 24)
poke dword ptr + 20, 0 : poke dword ptr + 24, 0
endfunction


Unfortunately, since this is a little hacky and DBPro isn't supposed to support objects with more than 65535 indicies, there's a few things you can't do with this method (as far as I know):
Use meshes (as targets for lots of indexdata) - If you try and turn a mesh with indexdata > 65535 into an object, you'll get a crash, so you need to use 'lock vertexdata for limb' instead

Save the object - Trying to save an object past the limit as a DBO gets you a crash instead

Have an object with more than 65535 verticies - unfortunately each indexdata entry is stored as a word with a maximum value of 65535, so even though you can have unlimited indexdata, you're limited to 65535 verticies per object (since indexdata entries can't reference verticies above that value)

Feel free to do whatever you want with this, hope it helps someone