Author Topic: Array of BYTEs  (Read 10176 times)

Offline AndyH

  • Dr. Type
  • ****
  • Posts: 383
    • View Profile
    • http://www.ovine.net/
Array of BYTEs
« 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.

Offline Kitty Hello

  • code monkey
  • Administrator
  • Prof. Inline
  • *******
  • Posts: 10766
  • here on my island the sea says 'hello'
    • View Profile
    • http://www.glbasic.com
Array of BYTEs
« Reply #1 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)
« Last Edit: 2008-Oct-27 by Kitty Hello »

Offline AndyH

  • Dr. Type
  • ****
  • Posts: 383
    • View Profile
    • http://www.ovine.net/
Array of BYTEs
« Reply #2 on: 2008-Jan-24 »
Magic!  many thanks, will try out when I get home. :)

Offline bigsofty

  • Community Developer
  • Prof. Inline
  • ******
  • Posts: 2706
    • View Profile
Array of BYTEs
« Reply #3 on: 2008-Jan-24 »
Handy for me too, THANKS! :D
Cheers,

Ian.

“It is practically impossible to teach good programming style to students that have had prior exposure to BASIC.  As potential programmers, they are mentally mutilated beyond hope of regeneration.”
(E. W. Dijkstra)

Offline Kitty Hello

  • code monkey
  • Administrator
  • Prof. Inline
  • *******
  • Posts: 10766
  • here on my island the sea says 'hello'
    • View Profile
    • http://www.glbasic.com
Array of BYTEs
« Reply #4 on: 2008-Jan-24 »
If it works, I consider making these default commands.

Offline AndyH

  • Dr. Type
  • ****
  • Posts: 383
    • View Profile
    • http://www.ovine.net/
Array of BYTEs
« Reply #5 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 :)

Offline bigsofty

  • Community Developer
  • Prof. Inline
  • ******
  • Posts: 2706
    • View Profile
Array of BYTEs
« Reply #6 on: 2008-Jan-24 »
Banks are always handy beasts for large amounts of data manipulation.
Cheers,

Ian.

“It is practically impossible to teach good programming style to students that have had prior exposure to BASIC.  As potential programmers, they are mentally mutilated beyond hope of regeneration.”
(E. W. Dijkstra)

Offline AndyH

  • Dr. Type
  • ****
  • Posts: 383
    • View Profile
    • http://www.ovine.net/
Array of BYTEs
« Reply #7 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 :)

Offline Moru

  • Administrator
  • Prof. Inline
  • *******
  • Posts: 1792
    • View Profile
    • Homepage
Array of BYTEs
« Reply #8 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 :-)

Offline Kitty Hello

  • code monkey
  • Administrator
  • Prof. Inline
  • *******
  • Posts: 10766
  • here on my island the sea says 'hello'
    • View Profile
    • http://www.glbasic.com
Array of BYTEs
« Reply #9 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.

Offline AndyH

  • Dr. Type
  • ****
  • Posts: 383
    • View Profile
    • http://www.ovine.net/
Array of BYTEs
« Reply #10 on: 2008-Jan-25 »
Thanks, lots of good stuff coming in the next update then :)

Offline AndyH

  • Dr. Type
  • ****
  • Posts: 383
    • View Profile
    • http://www.ovine.net/
Array of BYTEs
« Reply #11 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

Offline Kitty Hello

  • code monkey
  • Administrator
  • Prof. Inline
  • *******
  • Posts: 10766
  • here on my island the sea says 'hello'
    • View Profile
    • http://www.glbasic.com
Array of BYTEs
« Reply #12 on: 2008-Jan-26 »
fixed. Sorry.

Offline AndyH

  • Dr. Type
  • ****
  • Posts: 383
    • View Profile
    • http://www.ovine.net/
Array of BYTEs
« Reply #13 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?

Offline AndyH

  • Dr. Type
  • ****
  • Posts: 383
    • View Profile
    • http://www.ovine.net/
Array of BYTEs
« Reply #14 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.