Ah, I see...
Well, you can't really multithread core DBPro functions such as creating objects as they aren't thread safe.
You could however have the other thread create the memblock layout (or whatever you're using) for the mesh and then do a much faster copying of that memory into the actual buffers from the main program.
I wrote a simple example of how you can create a separate thread to overcome the issue of blocking functions (in the example IanM's console input functionality). Note that this requires Mattrix1Utilities to compile:
#constant true 1
#constant false 0
rem Load libraries
#constant kernel32 1
load dll "kernel32.dll", kernel32
rem Setup rendering engine
sync on
sync rate 60
backdrop on
color backdrop 0xff000000
rem Create a memory buffer.
rem This will be used to allow the main and the console thread to communicate.
rem The memory layout of the buffer is as such (this is of course completely arbitrary and just something I chose to use here):
rem =====================================================================================================
rem # Offset Datatype Description #
rem # #
rem # 0 BYTE Lock; the buffer contents is locked to the main thread (1), the #
rem # worker thread (2) or none of them. Since bytes can be assumed to be #
rem # atomic, it should be safe to concurrently read and write to this #
rem # value. #
rem # #
rem # 1 DWORD Type; denotes the type of the following bytes. #
rem # 5 BYTE* Data depending on the type value. A maximum of 256 bytes is allowed #
rem =====================================================================================================
pBuffer = alloc zeroed(261)
rem Buffer data types
#constant BT_NOTHING 0
#constant BT_COLOR_OBJECT 1
#constant BT_COLOR_BACKDROP 2
#constant BT_MINIMIZE 3
#constant BT_MAXIMIZE 4
#constant BT_RESTORE 5
#constant BT_CHANGE_TITLE 6
#constant BT_CLOSE 7
rem Maximum number of buffer operation types
#constant BT__MAXCOUNT 7
rem Lock-holders
#constant LOCK_NONE 0
#constant LOCK_MAIN_PROC 1
#constant LOCK_CONSOLE_PROC 2
rem Spawn worker thread and send it the pointer to the shared buffer as a parameter
pThreadId = alloc(4)
hThread = CreateThread(0, 0, get ptr to function("ThreadProc"), pBuffer, 0, pThreadId)
threadID = peek dword(pThreadId)
free pThreadId
rem Create a cube and have the main thread rotate it while the console thread handles input
obj = 1
make object cube obj, 1
rem Main loop
while not quit
rem Is the shared memory not locked by the other thread? If it is we'll leave it alone until such time that it is unlocked.
if peek byte(pBuffer) = LOCK_NONE
rem The buffer isn't locked; lock it for reading
poke byte pBuffer, LOCK_MAIN_PROC
select peek dword(pBuffer + 1)
case BT_CLOSE
quit = true
endcase
case BT_COLOR_OBJECT
color object obj, peek dword(pBuffer + 5)
endcase
case BT_COLOR_BACKDROP
color backdrop peek dword(pBuffer + 5)
endcase
case BT_MINIMIZE
minimize window
endcase
case BT_MAXIMIZE
maximize window
endcase
case BT_RESTORE
restore window
endcase
case BT_CHANGE_TITLE
set window title peek string(pBuffer + 5)
endcase
endselect
rem Since we have handled the operation, we overwrite it with BT_NONE in the shared buffer as
rem a simple solution to mark it as being handled (if we don't do this it won't change until
rem the console thread overwrites it and as such this part of the main thread will keep applying
rem the last operation repeatedly until then).
poke dword pBuffer + 1, BT_NOTHING
rem Unlock the buffer again
poke byte pBuffer, LOCK_NONE
endif
rem Main process logic; for us that just means to rotate the cube...
yrotate object obj, wrapvalue(object angle y(obj) + 1)
fpsString$ = "FPS: " + str$(screen fps())
text screen width() - text width(fpsString$) - 10, 0, fpsString$
sync
rem Sleep a bit so as to not hog the processor unnecessarily much
call dll kernel32, "Sleep", 1
endwhile
rem If we get here, the console thread has signalled it's finished (BT_EXIT); free it's shared memory
free pBuffer
end
rem Worker thread function. This will be run as a separate thread.
rem Note that you should «not» call any core DBPro functions from here, except maybe some math since it isn't thread safe.
rem I'll use it to write pixels to the shared buffer we set up earlier at regular intervals.
function ThreadProc(pBuffer as dword)
rem Allocate some local memory; we will use this to copy to the shared buffer when it is available
pData = alloc zeroed(260)
open console
set console foreground 15
print console "You may type commands here that will be transmitted to the main thread " + crlf$() + " upon pressting the return key." + crlf$()
print console "Type 'help' or '?' to display a list of available commands." + crlf$() + "--------------------------------------" + crlf$() + crlf$()
rem GET CONSOLE CHARACTER$() is a blocking function. That means that if you use it in your main thread your program won't continue until the user actually
rem types a character to the console. But with our separate thread we can do this at the same time as the main process is allowed to do its own thing.
while not quit
rem Reset
poke dword pData, BT_NOTHING
s$ = ""
c = 0
errCount = 0
rem Repeat until the user presses the return key
print console "> "
repeat
if c <> 0
s$ = s$ + chr$(c)
print console chr$(c);
endif
c = asc(get console char$())
until c = 10 or c = 13
print console crlf$()
rem Parse the input
s$ = fast upper$(s$)
s$ = replace all$(replace all$(s$, tab$(), " "), " ", " ") ` Remove extraneous spaces
split string s$, " "
if get split word$(1) = "EXIT" or get split word$(1) = "QUIT"
poke dword pData, BT_CLOSE
quit = true
endif
if get split word$(1) = "COLOR"
if get split word$(2) = "BACKDROP" or get split word$(2) = "OBJECT"
if split count() >= 3
if fast left$(get split word$(3), 2) = "0X"
col = hex to decimal(fast right$(get split word$(3), fast len(get split word$(3)) - 2))
else
col = val(get split word$(3))
endif
rem What should we colour again?
if get split word$(2) = "BACKDROP"
op = BT_COLOR_BACKDROP
else
op = BT_COLOR_OBJECT
endif
rem Write message to the local buffer
poke dword pData, op
poke dword pData + 4, col
else
if errCount = 0 then PrintCommandError("Invalid command arguments.") : inc errCount
endif
else
if errCount = 0 then PrintCommandError("Command not recognized.") : inc errCount
endif
endif
if get split word$(1) = "MINIMIZE"
poke dword pData, BT_MINIMIZE
endif
if get split word$(1) = "MAXIMIZE"
poke dword pData, BT_MAXIMIZE
endif
if get split word$(1) = "RESTORE"
poke dword pData, BT_RESTORE
endif
if split count() >= 3
if get split word$(1) = "SET" and get split word$(2) = "WINDOW" and get split word$(3) = "TITLE"
if split count() >= 4
title$ = get split word$(4)
for w = 5 to split count()
title$ = title$ + " " + get split word$(w)
next w
poke dword pData, BT_CHANGE_TITLE
poke string pData + 4, title$, 255 ` Save last byte for null termination
else
if errCount = 0 then PrintCommandError("Invalid command arguments.") : inc errCount
endif
endif
endif
rem Was a valid command entered?
if peek dword(pData) <> BT_NOTHING
rem Wait for the shared buffer to be flagged as not being in use
while peek byte(pBuffer) <> LOCK_NONE
call dll kernel32, "Sleep", 1
endwhile
poke byte pBuffer, LOCK_CONSOLE_PROC
rem Copy our command data to the shared buffer
copy memory pBuffer + 1, pData, 260
rem Unlock the buffer
poke byte pBuffer, LOCK_NONE
else
rem Unless the user asked for the command help list, we have encountered invalid input if we get here
if get split word$(1) = "HELP" or get split word$(1) = "?"
PrintCommandHelp()
else
if errCount = 0 then PrintCommandError("Command not recognized.") : inc errCount
endif
endif
endwhile
rem Free local memory
free pData
close console
rem The thread will end upon returning from this function.
rem Take note that this function «must» return a DWORD (I suppose integers would be automatically cast too).
rem The convention is to return a zero unless the thread failed.
endfunction 0
rem Functions can be called from any threads. This one will be used by the console handler to display error messages.
function PrintCommandError(msg as string)
set console foreground 12
print console " > " + msg + crlf$()
set console foreground 15
endfunction
rem And this one is used to display command documentation.
function PrintCommandHelp()
set console foreground 6
print console "**********************************************************"; crlf$()
print console "* COMMAND REFERENCE *"; crlf$()
print console "*** ***"; crlf$()
print console "* HELP / ? - Displays this message. *"; crlf$()
print console "* QUIT / EXIT - Closes the command thread *"; crlf$()
print console "* and instructs the main *"; crlf$()
print console "* thread to terminate too. *"; crlf$()
print console "* COLOR BACKDROP 0xaarrggbb - Sets the backdrop colour *"; crlf$()
print console "* of the main window. *"; crlf$()
print console "* a(lpha), r(ed), g(reen) *"; crlf$()
print console "* b(lue). *"; crlf$()
print console "* COLOR OBJECT 0xaarrggbb - Sets the cube colour. *"; crlf$()
print console "* MINIMIZE - Minimizes the main window *"; crlf$()
print console "* MAXIMIZE - Maximizes the main window *"; crlf$()
print console "* RESTORE - Restores the main window *"; crlf$()
print console "* SET WINDOW TITLE <title> - Changes the title of the *"; crlf$()
print console "* main window to whatever *"; crlf$()
print console "* follows the command. *"; crlf$()
print console "**********************************************************"; crlf$(); crlf$()
set console foreground 15
endfunction
rem Wrapper functions
function CreateThread(lpThreadAttribs as dword, dwStackSize as dword, lpStartAddress as dword, lpParam as dword, dwCreationFlags as dword, lpThreadId as dword)
handle = call dll(kernel32, "CreateThread", lpThreadAttribs, dwStackSize, lpStartAddress, lpParam, dwCreationFlags, lpThreadId)
endfunction handle
Hope it helps
"Why do programmers get Halloween and Christmas mixed up?" Because Oct(31) = Dec(25)