• Print

Author Topic: Tilemap drawing sub  (Read 514 times)

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #30 on: February 28, 2013, 03:54:55 PM »
Quote from: SkyCharger001 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)

Hey, what do you know, it does work in the SDL version! I hope to post the optimized version later today.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #31 on: February 28, 2013, 05:37:16 PM »
Hey, can somebody help me out with this? It looks like only the black tiles are being drawn.

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.
    drawtilesfast 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


'This is a fast version of the drawtiles sub, using memory addresses.
SUB drawtilesfast (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.
tsw% = _WIDTH(tileset&)
tilesnum% = tsw% / tilewidth%

'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%

'Get the width and height for the new tile map image.
nw% = blocksx2% - blocksx1% + 1
nh% = blocksy2% - blocksy1% + 1

'Make a new image for the cropped version of the tile map.
tmc& = _NEWIMAGE(nw%, nh%, 32)
'Put the correct section of the tile map on the new image.
_PUTIMAGE (0, 0), tilemap&, tmc&, (blocksx1%, blocksy1%)-(blocksx2%, blocksy2%)

'Dim the mem.
DIM tmm AS _MEM
'Get the memimage.
tmm = _MEMIMAGE(tmc&)

'Make a new image for the cropped version of the tileset.
tsc& = _NEWIMAGE(tsw%, 1, 32)
'Put the bottom row of the tileset on the new image.
_PUTIMAGE (0, 0), tileset&, tsc&, (0, tileheight%)-(tilewidth% - 1, tileheight%)

'Dim the mem.
DIM tsm AS _MEM
'Get the memimage.
tsm = _MEMIMAGE(tsc&)

'Set the starting address.
addr1& = 0

'Loop through the tiles, from top to bottom.
FOR y% = 0 TO nh% - 1
    'Continue looping through the tiles, from left to right.
    FOR x% = 0 TO nw% - 1

        'Get the color indicating which tile to draw.
        c& = _MEMGET(tmm, tmm.OFFSET + addr1&, LONG)

        'Loop through the tileset.
        FOR i% = 0 TO tilesnum% - 1
            'If the color matches, that's our tile.
            c2& = _MEMGET(tsm, tsm.OFFSET + i% * tilewidth%, LONG)
            IF _RED32(c&) = _RED32(c2&) AND _GREEN32(c&) = _GREEN32(c2&) AND _BLUE32(c&) = _BLUE32(c2&) THEN EXIT FOR
        NEXT i%

        'Draw the tile.
        'Offset of tiles on screen might not be right (snapped to a grid?)
        _PUTIMAGE ((x% + blocksx1%) * tilewidth% + posx%, (y% + blocksy1%) * tileheight% + posy%), tileset&, , (i% * tilewidth%, 0)-((i% + 1) * tilewidth% - 1, tileheight% - 1)
        'Next pixel, 4 bytes (32 bits) later.
        addr1& = addr1& + 4
    NEXT x%
NEXT y%

'Clear the memory so we don't cause a leak.
_FREEIMAGE tmc&
_FREEIMAGE tsc&
END SUB

OlDosLover

  • Hero Member
  • *****
  • Posts: 3859
  • OlDosLover
    • Email
Re: Tilemap drawing sub (HELP?)
« Reply #32 on: March 01, 2013, 12:06:54 AM »
Hi all,
    Dont know about the code , im busy with some other stuff. Here's a link to Steve's mem guide . Its a good read , as the goody gets the baddy!
OlDosLover.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #33 on: March 01, 2013, 12:51:55 AM »
Quote from: OlDosLover on March 01, 2013, 12:06:54 AM
Hi all,
    Dont know about the code , im busy with some other stuff. Here's a link to Steve's mem guide . Its a good read , as the goody gets the baddy!
OlDosLover.

Hi.

That won't help.

Thanks.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #34 on: March 01, 2013, 02:23:15 PM »
Alright, I finally got it to work. The "fast" version is now fully functional, and the code is below. However, I noticed no significant speedup. In QB64-GL, when working with a bunch of really small tiles, drawtilesfast performed at least 25% faster than drawtiles, but in all other tests there was no noticeable performance increase. Oh, well. I guess every little bit of optimization helps.

EDIT: Wow, I removed the RGB32 checks and it's a lot faster now! It's actually even more of an optimization than switching to memory addresses. Well, I think drawtilesfast is about as optimized as it is going to get.

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&

'Fill the tile map with opaque black.
CLS

'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.
    drawtilesfast 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


'This is a fast version of the drawtiles sub, using memory addresses.
SUB drawtilesfast (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.
tsw% = _WIDTH(tileset&)
tilesnum% = tsw% / tilewidth%

'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%

'Get the width and height for the new tile map image.
nw% = blocksx2% - blocksx1% + 1
nh% = blocksy2% - blocksy1% + 1

'Make a new image for the cropped version of the tile map.
tmc& = _NEWIMAGE(nw%, nh%, 32)
'Put the correct section of the tile map on the new image.
_PUTIMAGE (0, 0), tilemap&, tmc&, (blocksx1%, blocksy1%)-(blocksx2%, blocksy2%)

'Dim the mem.
DIM tmm AS _MEM
'Get the memimage.
tmm = _MEMIMAGE(tmc&)

'Make a new image for the cropped version of the tileset.
tsc& = _NEWIMAGE(tsw%, 1, 32)
'Put the bottom row of the tileset on the new image.
_PUTIMAGE (0, 0 - tileheight%), tileset&, tsc&

'Dim the mem.
DIM tsm AS _MEM
'Get the memimage.
tsm = _MEMIMAGE(tsc&)

'Set the starting address.
addr1& = 0

'Loop through the tiles, from top to bottom.
FOR y% = 0 TO nh% - 1
    'Continue looping through the tiles, from left to right.
    FOR x% = 0 TO nw% - 1

        'Get the color indicating which tile to draw.
        c& = _MEMGET(tmm, tmm.OFFSET + addr1&, LONG)

        'Loop through the tileset.
        FOR i% = 0 TO tilesnum% - 1
            'If the color matches, that's our tile.
            IF c& = _MEMGET(tsm, tsm.OFFSET + i% * tilewidth% * 4, LONG) THEN EXIT FOR
        NEXT i%

        'Draw the tile.
        'Offset of tiles on screen might not be right (snapped to a grid?)
        _PUTIMAGE ((x% + blocksx1%) * tilewidth% + posx%, (y% + blocksy1%) * tileheight% + posy%), tileset&, , (i% * tilewidth%, 0)-((i% + 1) * tilewidth% - 1, tileheight% - 1)
        'Next pixel, 4 bytes (32 bits) later.
        addr1& = addr1& + 4
    NEXT x%
NEXT y%

'Clear the memory so we don't cause a leak.
_FREEIMAGE tmc&
_FREEIMAGE tsc&
END SUB
« Last Edit: March 01, 2013, 02:58:28 PM by fluffrabbit »

OlDosLover

  • Hero Member
  • *****
  • Posts: 3859
  • OlDosLover
    • Email
Re: Tilemap drawing sub
« Reply #35 on: March 02, 2013, 02:49:55 AM »
Hi all,
    Thanks i'll check it out later and report back to you. Thanks for sharing.
OlDosLover.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub
« Reply #36 on: March 02, 2013, 03:57:47 AM »
Quote from: OlDosLover on March 02, 2013, 02:49:55 AM
Hi all,
    Thanks i'll check it out later and report back to you. Thanks for sharing.
OlDosLover.

No problem. Routines like this benefit me and everyone else in the community. This took me several days too, but I've got nothing better to do. I just made a tile collision function based on the same code. The function and sub go nicely together. I'm calling it Tilefluff, in reference to my own username. I'm attaching a demo to show how it works.

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


FUNCTION tf_bumptiles% (posx%, posy%, sizex%, sizey%, tilemap&, colset&, tilewidth%, tileheight%)
'Get the width and height of the tile map.
mapwidth% = _WIDTH(tilemap&)
mapheight% = _HEIGHT(tilemap&)

'Get the width of the colset image.
csw% = _WIDTH(colset&)

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

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

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

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

'Get the width and height for the new tile map image.
nw% = blocksx2% - blocksx1% + 1
nh% = blocksy2% - blocksy1% + 1

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

'Make a new image for the cropped version of the tile map.
tmc& = _NEWIMAGE(nw%, nh%, 32)
'Put the correct section of the tile map on the new image.
_PUTIMAGE (0, 0), tilemap&, tmc&, (blocksx1%, blocksy1%)-(blocksx2%, blocksy2%)

'Dim the mem.
DIM tmm AS _MEM
'Get the memimage.
tmm = _MEMIMAGE(tmc&)

'Dim the mem.
DIM csm AS _MEM
'Get the memimage.
csm = _MEMIMAGE(colset&)

'Set the starting address.
addr1& = 0

thit% = 0

'Loop through the tiles, from top to bottom.
FOR y% = 0 TO nh% - 1
    'Continue looping through the tiles, from left to right.
    FOR x% = 0 TO nw% - 1

        'Get the color indicating which tile to draw.
        c& = _MEMGET(tmm, tmm.OFFSET + addr1&, LONG)

        'Loop through the tileset.
        FOR i% = 0 TO csw% - 1
            'If the color matches, that's our tile.
            IF c& = _MEMGET(csm, csm.OFFSET + i% * 4, LONG) THEN
                thit% = 1
                EXIT FOR
            END IF
        NEXT i%

        IF thit% = 1 THEN EXIT FOR
        addr1& = addr1& + 4
    NEXT x%
    IF thit% = 1 THEN EXIT FOR
NEXT y%

'Clear the memory so we don't cause a leak.
_FREEIMAGE tmc&
'Return whether or not we hit a tile.
tf_bumptiles% = thit%
END FUNCTION


SUB tf_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.
tsw% = _WIDTH(tileset&)
tilesnum% = tsw% / tilewidth%

'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%

'Get the width and height for the new tile map image.
nw% = blocksx2% - blocksx1% + 1
nh% = blocksy2% - blocksy1% + 1

'Make a new image for the cropped version of the tile map.
tmc& = _NEWIMAGE(nw%, nh%, 32)
'Put the correct section of the tile map on the new image.
_PUTIMAGE (0, 0), tilemap&, tmc&, (blocksx1%, blocksy1%)-(blocksx2%, blocksy2%)

'Dim the mem.
DIM tmm AS _MEM
'Get the memimage.
tmm = _MEMIMAGE(tmc&)

'Make a new image for the cropped version of the tileset.
tsc& = _NEWIMAGE(tsw%, 1, 32)
'Put the bottom row of the tileset on the new image.
_PUTIMAGE (0, 0 - tileheight%), tileset&, tsc&

'Dim the mem.
DIM tsm AS _MEM
'Get the memimage.
tsm = _MEMIMAGE(tsc&)

'Set the starting address.
addr1& = 0

'Loop through the tiles, from top to bottom.
FOR y% = 0 TO nh% - 1
    'Continue looping through the tiles, from left to right.
    FOR x% = 0 TO nw% - 1

        'Get the color indicating which tile to draw.
        c& = _MEMGET(tmm, tmm.OFFSET + addr1&, LONG)

        'Loop through the tileset.
        FOR i% = 0 TO tilesnum% - 1
            'If the color matches, that's our tile.
            IF c& = _MEMGET(tsm, tsm.OFFSET + i% * tilewidth% * 4, LONG) THEN EXIT FOR
        NEXT i%

        'Draw the tile.
        'Offset of tiles on screen might not be right (snapped to a grid?)
        _PUTIMAGE ((x% + blocksx1%) * tilewidth% + posx%, (y% + blocksy1%) * tileheight% + posy%), tileset&, , (i% * tilewidth%, 0)-((i% + 1) * tilewidth% - 1, tileheight% - 1)
        'Next pixel, 4 bytes (32 bits) later.
        addr1& = addr1& + 4
    NEXT x%
NEXT y%

'Clear the memory so we don't cause a leak.
_FREEIMAGE tmc&
_FREEIMAGE tsc&
END SUB

  • Print