GLBasic forum

Codesnippets => Code Snippets => Topic started by: AndyH on 2008-Jan-24

Title: Array of BYTEs
Post by: AndyH on 2008-Jan-24
Hi

How would I best go about storing level data for a scrolling tile map in memory with GLB?

I tried DIM tiles[100][100] but there are currently two things that concern me about this.

1) Having an array this large makes debugging unusably slow.  I've posted a bug about this in the bug forum.  Every press of F10 to trace the next line refreshes the Variables panel in the editor, and it takes a long time to do it when you have large arrays.  Hopefully this can be optimised though in a future build of GLB?

2) Storing an array of tiles using the GLB number data type is going to be wasteful on memory - I think each number is going to be either 64 bits or 32 bits on Windows/ PPC/ GP2X, meaning between 4 and 8 bytes per number required to store it.  If so I'd need 40,000 bytes to store a 100x100 tilemap (which isn't very big in game map terms).

All I need is bytes which for the same example requires only 10,000 bytes in total.  This will all add up.  

I see there is a OPENFILE - READBYTE  (BTW there's no mention of these commands in the contents under Commands by Category -> Input-Output) for reading bytes from a file, but I think we need to have a CREATEBANK( memory_size ) command with a POKEBYTE, POKEWORD, POKELONG and PEEKBYTE, PEEKWORD, PEEKLONG commands to read and write to this memory bank.   Unless there is a better way built in.
Title: Array of BYTEs
Post by: Kitty Hello on 2008-Jan-24
New code: (needs V6 or later)
Code (glbasic) Select

// If this is not a seperate file, you must end the main() function first

// Just a quick test to ensure it's working
CREATEBANK(0, 128)
POKELONG(0, 0, 0x01234567)
POKEBYTE(0, 4, 0x70)
POKELONG(0, 5, 0xffff00ff)

LOCAL a%, b%, c%
a = PEEKLONG(0, 0)
b = PEEKBYTE(0, 4)
c = PEEKLONG(0, 5)

IF a=0x01234567 AND b=0x70 AND c=0xffff00ff
DEBUG "ok, works!"
ENDIF


FUNCTION _foo:
ENDFUNCTION

// Global variable for storing the bank pointers
INLINE
DGArray<unsigned char*> gMemBanks;
class MemBank_cleaner
{
   public:
   ~MemBank_cleaner()
   {
      for(int i=0; i<(int)LEN(gMemBanks); ++i)
         FREEBANK(i);
   }
} gMemBankClean;
ENDINLINE

FUNCTION CREATEBANK: index%, memsz%
INLINE
if(LEN(gMemBanks) <= index)
   REDIM(gMemBanks, index+1);
   gMemBanks(index) = new unsigned char[memsz];
ENDINLINE
ENDFUNCTION

FUNCTION POKEBYTE: ibank%, position%, value%
INLINE
   gMemBanks(ibank)[position] = (unsigned char)value;
ENDINLINE
ENDFUNCTION

FUNCTION PEEKBYTE%: ibank%, position%
INLINE
   return (int)gMemBanks(ibank)[position];
ENDINLINE
ENDFUNCTION

FUNCTION POKELONG: ibank%, position%, value%
INLINE
unsigned char* pBytes = &gMemBanks(ibank)[position];
   *((int*)pBytes) = value;
ENDINLINE
ENDFUNCTION


FUNCTION PEEKLONG%: ibank%, position%
INLINE
unsigned char* pBytes = &gMemBanks(ibank)[position];
   return *((int*)pBytes);
ENDINLINE
ENDFUNCTION


FUNCTION FREEBANK: ibank%
INLINE
   if(gMemBanks(ibank))
   {
      delete[] gMemBanks(ibank);
      gMemBanks(ibank) = 0L;
   }
ENDINLINE
ENDFUNCTION


FUNCTION WRITEBANK: ibank%, ifile%, ifrom%, ilen%
FOR i% = ifrom TO ifrom+ilen-1
WRITEBYTE ifile%, PEEKBYTE(ibank%, i%)
NEXT
ENDFUNCTION

FUNCTION READBANK: ibank%, ifile%, ifrom%, ilen%
LOCAL val%
FOR i% = ifrom TO ifrom+ilen-1
READBYTE ifile%, val%
POKEBYTE(ibank%, i%, val%)
NEXT
ENDFUNCTION




Old code:
Code (glbasic) Select
// If this is not a seperate file, you must end the main() function first
FUNCTION _foo:
ENDFUNCTION

// Global variable for storing the bank pointers
INLINE
DGArray<unsigned char*> gMemBanks;
class MemBank_cleaner
{
  public:
  ~MemBank_cleaner()
  {
     for(int i=0; i<(int)LEN(gMemBanks); ++i)
        FREEBANK(i);
  }
} gMemBankClean;
ENDINLINE

FUNCTION CREATEBANK: index, memsz
INLINE
if(LEN(gMemBanks) <= index)
  REDIM(gMemBanks, index+1);
  gMemBanks(index) = new unsigned char[(int)memsz];
ENDINLINE
ENDFUNCTION

FUNCTION POKEBYTE: ibank, position, value
INLINE
  gMemBanks(ibank)[(int)position] = (unsigned char)value;
ENDINLINE
ENDFUNCTION

FUNCTION PEEKBYTE: ibank, position
INLINE
  return (DGInt)gMemBanks(ibank)[(int)position];
ENDINLINE
ENDFUNCTION

FUNCTION FREEBANK: ibank
INLINE
  if(gMemBanks(ibank))
  {
     delete[] gMemBanks(ibank);
     gMemBanks(ibank) = 0L;
  }
ENDINLINE
ENDFUNCTION

(untested)
Title: Array of BYTEs
Post by: AndyH on 2008-Jan-24
Magic!  many thanks, will try out when I get home. :)
Title: Array of BYTEs
Post by: bigsofty on 2008-Jan-24
Handy for me too, THANKS! :D
Title: Array of BYTEs
Post by: Kitty Hello on 2008-Jan-24
If it works, I consider making these default commands.
Title: Array of BYTEs
Post by: AndyH on 2008-Jan-24
That would be the best solution to have it built in to the language - something I'm sure many people would like to use.  Will help with my collision map solution too :)
Title: Array of BYTEs
Post by: bigsofty on 2008-Jan-24
Banks are always handy beasts for large amounts of data manipulation.
Title: Array of BYTEs
Post by: AndyH on 2008-Jan-25
the INLINE code seems to work ok, just remove the third parameter (value) from the PEEKBYTE function.

Notice I have to start from bank 1 (not 0) and you have to be careful not to poke outside of your memory array.  Also guessing we'll get memory leaks if we don't free the bank up before stopping the app, or if creating banks on the same bank ID, the previous bank on that ID won't be destroyed?

Guess these will be ironed out when the in-built version of these commands are done :)
Title: Array of BYTEs
Post by: Moru on 2008-Jan-25
That sounds very handy, was a bit worried about this too for my future projects when I finaly have time for them :-)
Title: Array of BYTEs
Post by: Kitty Hello on 2008-Jan-25
OK, fixed. You can start with index 0 now, and the value is off.
When you quit an application, the "new" memory will be deleted automatically. You don't recursively allocate this memory, thus it's no memory leak. It's not nice, though.
Wait.... I'll insert a cleanup, too to make it safe.
Title: Array of BYTEs
Post by: AndyH on 2008-Jan-25
Thanks, lots of good stuff coming in the next update then :)
Title: Array of BYTEs
Post by: AndyH on 2008-Jan-25
With the new code above (in a separate file from the main source code) I get this error:


compiling:
C:\Users\AndyH\AppData\Local\Temp\glbasic\gpc_temp2.cpp: In function `void __static_initialization_and_destruction_0(int, int)':
C:\Users\AndyH\AppData\Local\Temp\glbasic\gpc_temp2.cpp:21: error: `__GLBASIC__::MemBank_cleaner::~MemBank_cleaner()' is private
C:\Users\AndyH\AppData\Local\Temp\glbasic\gpc_temp2.cpp:25: error: within this context
*** FATAL ERROR - Please post this output in the forum
Title: Array of BYTEs
Post by: Kitty Hello on 2008-Jan-26
fixed. Sorry.
Title: Array of BYTEs
Post by: AndyH on 2008-Jan-26
Thanks Gernot, this code is helping a lot.

That all works now on the PC, however the Create Bank command seems to lock up the Pocket PC.  I've created a test project.  Made a second source code file called MemBanks.gbas and copied your code into that.

In the main program source code I have put this:

Code (glbasic) Select
SETSCREEN 320,240,0
LIMITFPS 60


PRINT "About to create banks - mousewait",0,0
SHOWSCREEN
MOUSEWAIT

CREATEBANK(0, 100*100)

PRINT "Now to populate banks - mousewait",0,0
SHOWSCREEN
MOUSEWAIT

FOR y=0 TO 99
FOR x=0 TO 99
POKEBYTE(0, x+(y*10), RND(1))
NEXT
NEXT

PRINT "Now to PEEKBYTES - mousewait",0,0
SHOWSCREEN
MOUSEWAIT

FOR y=0 TO 10
FOR x=0 TO 10
PRINT PEEKBYTE(0, x+(y*10)), 20+x*6, 20+y*6
NEXT
NEXT

PRINT "Now to free banks - mousewait",0,0
SHOWSCREEN
MOUSEWAIT
FREEBANK(0)

PRINT "Done - mousewait",0,0
SHOWSCREEN
MOUSEWAIT
On the PC works fine.  On the Pocket PC it displays the About to create banks message, but click the mouse and it calls CREATEBANK but does not return and the program locks up.  Have to do a reset.

The very first version of your code (before you added the class) was working.  Any ideas?
Title: Array of BYTEs
Post by: AndyH on 2008-Jan-26
Found out what is having the problem on the PPC version:

Code (glbasic) Select
FUNCTION CREATEBANK: index, memsz
INLINE
if(LEN(gMemBanks) <= index)
   REDIM(gMemBanks, index+1);
   //FREEBANK(index);
   gMemBanks(index) = new unsigned char[(int)memsz];
ENDINLINE
ENDFUNCTION
Comment out the FREEBANK during the creation of the bank and it works.  Calling FREEBANK at the end of my app works too, just not from inside the CREATEBANK INLINE code.
Title: Re: Array of BYTEs
Post by: Heiko on 2008-Oct-21
need some other commands too.

ReadBytes  (http://www.blitzforum.de/help/ReadBytes)
ReadInt      (http://www.blitzforum.de/help/ReadInt)
Title: Re: Array of BYTEs
Post by: Kitty Hello on 2008-Oct-21
OK, I added a new version which has PEEKLONG and POKELONG, too.

However! You need V6 to compile it, and the IDE currently does not display function names ending with % properly. The compiler works, however.
Title: Re: Array of BYTEs
Post by: Heiko on 2008-Oct-25
Gernot can you make this one command too?

ReadBytes (bank, stream, start, anzahl)   // read anzahl of bytes beginning at start in the file was opened.return anzahl sucessfully read bytes and writes the bytes in the bank created with CreateBank.

here german link for help : http://www.blitzforum.de/help/ReadBytes

perhaps WriteBytes too.

Start reading in the bank at start and write it to file was opened.

and useful can be resizebank and copybank.

I hope its not to much hard work for you.

Big thanks.
Title: Re: Array of BYTEs
Post by: Hemlos on 2008-Oct-25
Quote from: Heiko on 2008-Oct-25
ReadBytes (bank, stream, start, anzahl)   // read anzahl of bytes beginning at start in the file was opened.return anzahl sucessfully read bytes and writes the bytes in the bank created with CreateBank.


Not sure why you need something like that..

readbyte,1,dat$
dimpush bank[],dat$

Isnt this the same thing?

btw,What is anzahl?
Title: Re: Array of BYTEs
Post by: Moru on 2008-Oct-25
http://dict.tu-chemnitz.de/dings.cgi?lang=en&service=deen&opterrors=0&optpro=0&query=anzahl&iservice=&comment=

in this case "number of" I guess
Title: Re: Array of BYTEs
Post by: Kitty Hello on 2008-Oct-27
Write to file or what?
Title: Re: Array of BYTEs
Post by: Heiko on 2008-Oct-27
yes, read out a bank at "start" with number of "anzahl" return the number of truely read datas and write it at the same time to the stream open with open file.

The same like WriteBytes wich write Bytes from a streamed file at "start" in file number of "anzahl" write to a bank created with CreateBank at position 0, i think.

Now you know?
Title: Re: Array of BYTEs
Post by: Kitty Hello on 2008-Oct-27
OK, update.
Title: Re: Array of BYTEs
Post by: Heiko on 2008-Oct-27
cool job gernot, thanks.
one question if you have anytime a little time for it.

CopyBank and ResizeBank are useful....too.

But perhaps at this time not important.