• Print

Author Topic: Tilemap drawing sub  (Read 513 times)

SkyCharger001

  • Hero Member
  • *****
  • Posts: 1594
Re: Tilemap drawing sub (HELP?)
« Reply #15 on: February 27, 2013, 05:15:16 AM »
I think I can see the problem: Tmap is defined as a text-image.
the last 2 rows cause a single-line-scroll when printed to without ";" which could be ruining Tmap as it's only 2 rows high.

another thing, I have found how to easily separate color-attributes from tile-attributes in a tile-renderer. (allows a tile to be rendered in multiple color-combinations)
Use a 256-color image for the tileset. (using all 256 colors would be overkill for this, so I recommend using no more then 8)
Use a 32-bit image for display

when a tile is needed, set the tile-set palette to the desired colors, and THEN use _putimage.
set _clearcolor to _NONE when rendering background and 0 when rendering sprites. (sprites will have transparency, but background will not)

PS How to access palette via _mem?
« Last Edit: February 27, 2013, 02:52:48 PM by SkyCharger001 »

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #16 on: February 27, 2013, 01:17:43 PM »
Quote from: SkyCharger001 on February 27, 2013, 05:15:16 AM
I think I can see the problem: Tmap is defined as a text-image.
the last 2 rows cause a single-line-scroll when printed to without ";" which could be ruining Tmap as it's only 2 rows high.

The ampersand (&) is the type suffix for both the tilemap and tileset pointer. They are not text-images. They are _NEWIMAGE images.

I thought I was only using the new graphics commands. Please help me understand.

SkyCharger001

  • Hero Member
  • *****
  • Posts: 1594
Re: Tilemap drawing sub (HELP?)
« Reply #17 on: February 27, 2013, 02:52:21 PM »
Quote from: fluffrabbit on February 27, 2013, 01:17:43 PM
Quote from: SkyCharger001 on February 27, 2013, 05:15:16 AM
I think I can see the problem: Tmap is defined as a text-image.
the last 2 rows cause a single-line-scroll when printed to without ";" which could be ruining Tmap as it's only 2 rows high.

The ampersand (&) is the type suffix for both the tilemap and tileset pointer. They are not text-images. They are _NEWIMAGE images.

I thought I was only using the new graphics commands. Please help me understand.
your using _newimage(x,y) instead of _newimage(x,y,colordepth) which means they are created as _newimage(x,y,0) which creates a textmode image, not a graphics image.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #18 on: February 27, 2013, 03:54:53 PM »
Quote from: SkyCharger001 on February 27, 2013, 02:52:21 PM
Quote from: fluffrabbit on February 27, 2013, 01:17:43 PM
Quote from: SkyCharger001 on February 27, 2013, 05:15:16 AM
I think I can see the problem: Tmap is defined as a text-image.
the last 2 rows cause a single-line-scroll when printed to without ";" which could be ruining Tmap as it's only 2 rows high.

The ampersand (&) is the type suffix for both the tilemap and tileset pointer. They are not text-images. They are _NEWIMAGE images.

I thought I was only using the new graphics commands. Please help me understand.
your using _newimage(x,y) instead of _newimage(x,y,colordepth) which means they are created as _newimage(x,y,0) which creates a textmode image, not a graphics image.

I tried switching it to _NEWIMAGE(x,y,32), but it didn't work.

TerryRitchie

  • Hero Member
  • *****
  • Posts: 2264
  • FORMAT C:\ /Q /U /AUTOTEST (How to repair Win8)
    • Email
Re: Tilemap drawing sub (HELP?)
« Reply #19 on: February 27, 2013, 04:08:22 PM »
Quote from: fluffrabbit on February 26, 2013, 08:20:04 PM
I've made tile-based games before, but never in immediate mode like this. That's what makes this special. Somebody please tell me what the hell is going on.

I can't even begin to imagine what you mean by this?  I'm going to be posting my Frogger game in a few days which uses tiles in a 16x16 grid on a 224x256 screen (original Frogger screen) expanded to a 672x768 screen effectively zooming the game by a factor of 3.  It doesn't use the sprite library either, as I wanted to demonstrate to my students how to handle a tile based game through raw code.  Perhaps it will help you.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #20 on: February 27, 2013, 04:12:37 PM »
Quote from: TerryRitchie on February 27, 2013, 04:08:22 PM
Quote from: fluffrabbit on February 26, 2013, 08:20:04 PM
I've made tile-based games before, but never in immediate mode like this. That's what makes this special. Somebody please tell me what the hell is going on.

I can't even begin to imagine what you mean by this?  I'm going to be posting my Frogger game in a few days which uses tiles in a 16x16 grid on a 224x256 screen (original Frogger screen) expanded to a 672x768 screen effectively zooming the game by a factor of 3.  It doesn't use the sprite library either, as I wanted to demonstrate to my students how to handle a tile based game through raw code.  Perhaps it will help you.

I doubt it. I've already made a tile-based game (Brazilian Clown Car), but not in immediate mode. Let there be no arrays, but only images, one for the tileset and one for the tilemap.

OlDosLover

  • Hero Member
  • *****
  • Posts: 3859
  • OlDosLover
    • Email
Re: Tilemap drawing sub (HELP?)
« Reply #21 on: February 27, 2013, 09:48:18 PM »
Hi all,
    For some reason the sub drawtiles is called once per loop of the main loop. The for next isnt producing 4 separate point color values. As only one point is produced out of the for next it is only capable to drawing 1 tile per loop of the main loop. Look at the variables that are produced and printed during each  loop of the main loop.

Code: [Select]
'I declare this work to be public domain.
DIM SHARED z(1 TO 4) AS LONG
SCREEN _NEWIMAGE(640, 480, 32)

tmap& = _NEWIMAGE(2, 2, 32)
_DEST tmap&

PRESET (0, 0), _RGB(0, 0, 0)
PRESET (1, 0), _RGB(255, 0, 0)
PRESET (0, 1), _RGB(0, 0, 255)
PRESET (1, 1), _RGB(0, 255, 0)

_SOURCE tmap&

z(1) = POINT(0, 0)
z(2) = POINT(1, 0)
z(3) = POINT(0, 1)
z(4) = POINT(1, 1)

_DEST 0
PRINT z(1)
PRINT z(2)
PRINT z(3)
PRINT z(4)
PRINT
PRINT "Press a key to continue"
dummy$ = INPUT$(1)

tset& = _NEWIMAGE(128, 33, 32)
_DEST tset&

PRESET (0, 32), _RGB(0, 0, 0)
CIRCLE (16, 16), 5, _RGB(255, 255, 255)

PRESET (32, 32), _RGB(255, 0, 0)
CIRCLE (48, 16), 5, _RGB(255, 0, 0)

PRESET (64, 32), _RGB(0, 0, 255)
CIRCLE (80, 16), 5, _RGB(0, 0, 255)

PRESET (96, 32), _RGB(0, 255, 0)
CIRCLE (112, 16), 5, _RGB(0, 255, 0)

_DEST 0

DO
  drawtiles 50, 50, tmap&, tset&, 32, 32
  _DISPLAY
LOOP
SYSTEM

SUB drawtiles (posx%, posy%, tilemap&, tileset&, tilewidth%, tileheight%)
mapwidth% = _WIDTH(tilemap&)
mapheight% = _HEIGHT(tilemap&)

tilesnum% = _WIDTH(tileset&) / tilewidth%

oldsource& = _SOURCE

blocksx1% = posx% / tilewidth% - 1
IF blocksx1% < 0 THEN blocksx1% = 0
IF blocksx1% > mapwidth% - 1 THEN blocksx1% = mapwidth% - 1

blocksx2% = (posx% + _WIDTH(_DEST)) / tilewidth%
IF blocksx2% < 0 THEN blocksx2% = 0
IF blocksx2% > mapwidth% - 1 THEN blocksx2% = mapwidth% - 1

blocksy1% = posy% / tileheight% - 1
IF blocksy1% < 0 THEN blocksy1% = 0
IF blocksy1% > mapheight% - 1 THEN blocksy1% = mapheight% - 1

blocksy2% = (posy% + _HEIGHT(_DEST)) / tileheight%
IF blocksy2% < 0 THEN blocksy2% = 0
IF blocksy2% > mapheight% - 1 THEN blocksy2% = mapheight% - 1

FOR y% = blocksy1% TO blocksy2%
  FOR x% = blocksx1% TO blocksx2%
    _SOURCE tilemap&
    c& = POINT(x%, y%)
    PRINT "Current point color = "; c&; "y%="; y%, "x%="; x%
    IF c& = z(1) THEN SOUND 600, 1
    IF c& = z(2) THEN SOUND 800, 1
    IF c& = z(3) THEN SOUND 1000, 1
    IF c& = z(4) THEN SOUND 1200, 1
    PRINT "MapW="; mapwidth%; " MapH="; mapheight%; " TileSum="; tilesnum%; " blocksx1%="; blocksx1%; " blocksx2%="; blocksx2%

    'Offset of tiles on screen might not be right (snapped to a grid?)
    _SOURCE tileset&
    FOR i% = 1 TO tilesnum%
      IF c& = POINT((i% - 1) * tilewidth%, tileheight%) THEN EXIT FOR
    NEXT i%
    '_PUTIMAGE (x% * tilewidth%, y% * tileheight%), tileset&, , ((i% - 1) * tilewidth%, 0)-(i% * tilewidth% - 1, tileheight% - 1)
    ofx% = 1
    ofy% = 1
    'LINE (x% * tilewidth% + ofx%, y% * tileheight% + ofy%)-((x% + 1) * tilewidth% + ofx%, (y% + 1) * tileheight% + ofy%), _RGB(0, 255, 0), BF
  NEXT x%
NEXT y%

_SOURCE oldsource&
_DELAY 1
END SUB
    What would really help others (like me) to better understand what your code is doing would be to use lots of comments explaining better whats spose to happen.
OlDosLover.
« Last Edit: February 27, 2013, 10:09:53 PM by OlDosLover »

TerryRitchie

  • Hero Member
  • *****
  • Posts: 2264
  • FORMAT C:\ /Q /U /AUTOTEST (How to repair Win8)
    • Email
Re: Tilemap drawing sub (HELP?)
« Reply #22 on: February 27, 2013, 10:32:59 PM »
What do you mean by "immediate mode"?

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #23 on: February 28, 2013, 01:04:28 AM »
Quote from: TerryRitchie on February 27, 2013, 10:32:59 PM
What do you mean by "immediate mode"?
http://en.wikipedia.org/wiki/Immediate_mode
I use QB64's images instead of arrays. No data is passed through the function that isn't an image. It's self-contained and has to be called every frame, because it's just a drawing command. The other way to do it would be to precalculate an array using some other command outside of the function, but I am skipping that step. There is a slight performance penalty, but I think it's well worth it if it means the code is that much shorter.

Quote from: OlDosLover on February 27, 2013, 09:48:18 PM
Hi all,
    For some reason the sub drawtiles is called once per loop of the main loop. The for next isnt producing 4 separate point color values. As only one point is produced out of the for next it is only capable to drawing 1 tile per loop of the main loop. Look at the variables that are produced and printed during each  loop of the main loop.
(code)
What would really help others (like me) to better understand what your code is doing would be to use lots of comments explaining better whats spose to happen.
OlDosLover.

Oh, thank you. That actually clarifies a little bit. My brain still hurts, though. I commented my code and added in a debugging thing. The problem is that the grid only seems to be rendering 1-1.

EDIT: It's done! It's fixed! Enjoy!

Code: [Select]
'I declare this work to be public domain.

'Set up the screen mode (640x480 @ 32 bits per pixel)
SCREEN _NEWIMAGE(640, 480, 32)

'Make a tile map image. This will be the map of the game world.
tmap& = _NEWIMAGE(200, 2, 32)
'Set drawing operations to the tile map image.
_DEST tmap&

'Give each pixel a different color, referencing the 4 different tiles...
PRESET (0, 0), _RGB(0, 0, 0)
PRESET (1, 0), _RGB(255, 0, 0)
PRESET (0, 1), _RGB(0, 0, 255)
PRESET (1, 1), _RGB(0, 255, 0)

'Make a tileset image. This will contain the actual tile images.
tset& = _NEWIMAGE(128, 33, 32)
'Set drawing operations to the tileset image.
_DEST tset&

'Draw 4 circles, 1 for each tile.
'Below each tile, put a dot representing the tile color.
PRESET (0, 32), _RGB(0, 0, 0)
CIRCLE (16, 16), 5, _RGB(255, 255, 255)

PRESET (32, 32), _RGB(255, 0, 0)
CIRCLE (48, 16), 5, _RGB(255, 0, 0)

PRESET (64, 32), _RGB(0, 0, 255)
CIRCLE (80, 16), 5, _RGB(0, 0, 255)

PRESET (96, 32), _RGB(0, 255, 0)
CIRCLE (112, 16), 5, _RGB(0, 255, 0)

'Set drawing operations back to the screen.
_DEST 0

'Starting position is 0,0
px% = 0
py% = -16

'Begin our main loop.
DO
    px% = px% - 1
    'Call the drawtiles sub with parameters:
    'Offset 50 pixels on X and Y axis.
    'Use tile map image tmap& and use tileset image tset&.
    'Tile size is 32x32.
    drawtiles px%, py%, tmap&, tset&, 32, 32
    'Refresh the screen.
    _DISPLAY
    'Keep it at max 60 FPS.
    _LIMIT 60
    'Clear the screen.
    CLS
LOOP
'After the loop, quit the program.
SYSTEM

'This is our drawtiles sub, an immediate mode tile renderer.
SUB drawtiles (posx%, posy%, tilemap&, tileset&, tilewidth%, tileheight%)
'Get the width and height of the tile map.
mapwidth% = _WIDTH(tilemap&)
mapheight% = _HEIGHT(tilemap&)

'Count the number of tiles based on the width of the tileset image.
tilesnum% = _WIDTH(tileset&) / tilewidth%

'Get the current drawing source buffer, for use later.
oldsource& = _SOURCE

'Determine the leftmost tiles to draw.
blocksx1% = -1 - posx% / tilewidth%
IF blocksx1% < 0 THEN blocksx1% = 0
IF blocksx1% > mapwidth% - 1 THEN blocksx1% = mapwidth% - 1

'Determine the rightmost tiles to draw.
blocksx2% = (_WIDTH(_DEST) - posx%) / tilewidth%
IF blocksx2% < 0 THEN blocksx2% = 0
IF blocksx2% > mapwidth% - 1 THEN blocksx2% = mapwidth% - 1

'Determine the topmost tiles to draw.
blocksy1% = -1 - posy% / tileheight%
IF blocksy1% < 0 THEN blocksy1% = 0
IF blocksy1% > mapheight% - 1 THEN blocksy1% = mapheight% - 1

'Determine the bottommost tiles to draw.
blocksy2% = (_HEIGHT(_DEST) - posy%) / tileheight%
IF blocksy2% < 0 THEN blocksy2% = 0
IF blocksy2% > mapheight% - 1 THEN blocksy2% = mapheight% - 1

'Debug code
'PRINT "blocksx1%"; blocksx1%
'PRINT "blocksy1%"; blocksy1%
'PRINT "blocksx2%"; blocksx2%
'PRINT "blocksy2%"; blocksy2%

'Loop through the tiles, from top to bottom.
FOR y% = blocksy1% TO blocksy2%
    'Continue looping through the tiles, from left to right.
    FOR x% = blocksx1% TO blocksx2%
        'Set the source image to the tile map.
        _SOURCE tilemap&
        'Get the color indicating which tile to draw.
        c& = POINT(x%, y%)
        'Set the source image to the tileset image.
        _SOURCE tileset&
        'Loop through the tileset.
        FOR i% = 0 TO tilesnum% - 1
            'If the color matches, that's our tile.
            c2& = POINT(i% * tilewidth%, tileheight%)
            IF _RED32(c&) = _RED32(c2&) AND _GREEN32(c&) = _GREEN32(c2&) AND _BLUE32(c&) = _BLUE32(c2&) THEN EXIT FOR
        NEXT i%

        'More debug code.
        'PRINT i%
        'END

        'Draw the tile.
        'Offset of tiles on screen might not be right (snapped to a grid?)
        _PUTIMAGE (x% * tilewidth% + posx%, y% * tileheight% + posy%), tileset&, , (i% * tilewidth%, 0)-((i% + 1) * tilewidth% - 1, tileheight% - 1)
    NEXT x%
NEXT y%

'Set the source image back to where it was.
_SOURCE oldsource&
END SUB
« Last Edit: February 28, 2013, 02:34:37 AM by fluffrabbit »

OlDosLover

  • Hero Member
  • *****
  • Posts: 3859
  • OlDosLover
    • Email
Re: Tilemap drawing sub (HELP?)
« Reply #24 on: February 28, 2013, 06:36:49 AM »
Hi all,
    Congrats on the fix. The comments make it much easier to follow in the concept of what is happening now and much easier for others (me) to read. The debug code i find invaluable in all programs. Nice peice of specialist code.
   
Quote
It's self-contained and has to be called every frame, because it's just a drawing command. The other way to do it would be to precalculate an array using some other command outside of the function, but I am skipping that step

    Point is pretty slow. Perhaps you should make a test case with your method and the precalculate shared array to compare just  how much slower yours is compared to conventional way.
OlDosLover.

unseenmachine

  • Hero Member
  • *****
  • Posts: 3285
  • A fish, a fish, a fishy o!
Re: Tilemap drawing sub (HELP?)
« Reply #25 on: February 28, 2013, 09:18:36 AM »
Quote
It's self-contained and has to be called every frame, because it's just a drawing command. The other way to do it would be to precalculate an array using some other command outside of the function, but I am skipping that step

GDK uses pre calc arrays for it's tile engine portion as i found without them it's not really practical to use tilesheets. I've got no access to proper internet at the moment so i can't really help but if you look up some of my older games (pokemon and qb world are what i can remember of the top of my head) but you should be able to gleen something of uses from it. Lachie used it to make a pixel by pixel scrolling tile engine so he might be able to help out to.

Unseen 
UnseenGDK Download : http://dl.dropbox.com/u/8822351/UnseenGDK.bm
GDK Tutorial : http://dl.dropbox.com/u/8822351/UnseenGDK_Tutorial.doc
VQB02 : http://dl.dropbox.com/u/8822351/VQB02.zip

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #26 on: February 28, 2013, 10:03:16 AM »
There must be a faster way to access the tile data without using an array. I will look into _MEMIMAGE. It shouldn't be hard to just add an extra variable to the FOR-NEXT loop (a memory address) and add bytes to it as the coordinates are being looped through. Of course, before the loop, the tilemap and tileset images would be cropped for fast memory access.

EDIT: I forgot, an image handle is a memory address. This shouldn't take long at all.

EDIT 2: How do I read from a memory addresses? PEEK and INP appear to be limited to 16-bit addresses and _MEM isn't supported in the SDL version!

EDIT 3: It appears that _MEMGET is supported in the SDL version, but not documented in the editor. I'll see if I can use that.

EDIT 4: Nope, apparently _MEMGET would require a _MEMIMAGE command to get the image data. So, I guess that there is no way to speed up this code until QB64-GL becomes an official supported release and everybody is using it. Oh, well. It's not like the drawtiles sub is particularly slow. Next, I might try to see if I can make a tile collision detection function based on the same code.
« Last Edit: February 28, 2013, 11:19:43 AM by fluffrabbit »

OlDosLover

  • Hero Member
  • *****
  • Posts: 3859
  • OlDosLover
    • Email
Re: Tilemap drawing sub (HELP?)
« Reply #27 on: February 28, 2013, 11:31:55 AM »
Hi all,
    Hi ya unseenmachine , its been a while mate!. Steve is the resident MEM guru. Probably best to wait for him to wade in. He has put a tutorial out on _MEM somewhere , in discussion i think.
OlDosLover.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #28 on: February 28, 2013, 01:04:18 PM »
Quote from: OlDosLover on February 28, 2013, 11:31:55 AM
Hi all,
    Hi ya unseenmachine , its been a while mate!. Steve is the resident MEM guru. Probably best to wait for him to wade in. He has put a tutorial out on _MEM somewhere , in discussion i think.
OlDosLover.

I think I can make use of the image data directly using _MEMGET(addr1&,0,LONG). It will take some work, but I think I've got it for now.

EDIT: %&!#$!!!!!!!!!! _MEMGET expects a parameter of type _MEM, but I can't cast a pointer as a _MEM! >:( Maybe I could use the pointer as the offset and use a dummy _MEM? I'll have to work on it.

EDIT 2: Well, this doesn't work:

Code: [Select]
SCREEN _NEWIMAGE(640, 480, 32)
DIM dum AS _MEM
im& = _LOADIMAGE("image.png")
LINE (0, 0)-(_WIDTH(_DEST) - 1, _HEIGHT(_DEST) - 1), _MEMGET(dum, im&, LONG), BF
« Last Edit: February 28, 2013, 01:43:19 PM by fluffrabbit »

SkyCharger001

  • Hero Member
  • *****
  • Posts: 1594
Re: Tilemap drawing sub (HELP?)
« Reply #29 on: February 28, 2013, 03:11:41 PM »
Quote from: fluffrabbit on February 28, 2013, 01:04:18 PM
Quote from: OlDosLover on February 28, 2013, 11:31:55 AM
Hi all,
    Hi ya unseenmachine , its been a while mate!. Steve is the resident MEM guru. Probably best to wait for him to wade in. He has put a tutorial out on _MEM somewhere , in discussion i think.
OlDosLover.

I think I can make use of the image data directly using _MEMGET(addr1&,0,LONG). It will take some work, but I think I've got it for now.

EDIT: %&!#$!!!!!!!!!! _MEMGET expects a parameter of type _MEM, but I can't cast a pointer as a _MEM! >:( Maybe I could use the pointer as the offset and use a dummy _MEM? I'll have to work on it.

EDIT 2: Well, this doesn't work:

Code: [Select]
SCREEN _NEWIMAGE(640, 480, 32)
DIM dum AS _MEM
im& = _LOADIMAGE("image.png")
LINE (0, 0)-(_WIDTH(_DEST) - 1, _HEIGHT(_DEST) - 1), _MEMGET(dum, im&, LONG), BF
dum=_memimage(im&)
_memget(dum,dum.offset,long)
im& is a double pointer (it points to the pointer of the image)


  • Print