Author Topic: question about _MEMIMAGE / _MEMPUT  (Read 4008 times)

0 Members and 1 Guest are viewing this topic.

This topic contains a post which is marked as Best Answer. Press here if you would like to see it.

Offline MrFreyer

  • Newbie
  • Posts: 34
    • View Profile
question about _MEMIMAGE / _MEMPUT
« on: June 25, 2019, 02:01:31 am »
Hi,

I try to draw a (prefabricated) background tilemap on the screen, using the _MEMIMAGE and _MEMPUT commands. But sadly it doesn't work and don't know what I'm doing wrong...the background is just black.

It looks like this:
Quote
SCREEN _NEWIMAGE(600, 800, 32)
_DISPLAY

DIM mimage AS _MEM
DIM tilemapbackground AS LONG

'...load images with _LOADIMAGE

'...draw tilemapbackground with _PUTIMAGE

mimage = _MEMIMAGE(tilemapbackground)

'...

CLS

_MEMPUT mimage, mimage.OFFSET + 1, _WIDTH(0) * _HEIGHT(0) * 4 AS _UNSIGNED _BYTE

_DISPLAY

Thanks!

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: question about _MEMIMAGE / _MEMPUT
« Reply #1 on: June 25, 2019, 02:30:03 am »
Why not simply staying with _PUTIMAGE? With the following syntax:
        _PUTIMAGE (dx1, dy1), sourceHandle&, destHandle&, (sx1, sy1)-(sx2, sy2) 'portion of source to the top-left corner of the destination page
you may copy any cutout of the source image  (sx1, sy1)-(sx2, sy2) to any desired startposition on the destination (dx1, dy1).

If you really wanna use _MEMGET/PUT, then you first need the _MEM handles of both images (your tilemap and your screen), then you have to use _MEMGET to get one pixel of the source and then _MEMPUT  that pixel to your screen's _MEM handle, hence you have to use a nested loop for X/Y positions and run through all pixels of your desired tile. Also you have to correctly calculate the mem.OFFSET for each pixel, it's possible, but much more complicated than simply using _PUTIMAGE.
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: question about _MEMIMAGE / _MEMPUT
« Reply #2 on: June 25, 2019, 03:09:21 am »
Quote
SCREEN _NEWIMAGE(600, 800, 32)
_DISPLAY
DIM mimage AS _MEM
DIM tilemapbackground AS LONG
'...load images with _LOADIMAGE
'...draw tilemapbackground with _PUTIMAGE
mimage = _MEMIMAGE(tilemapbackground)

'...

CLS
_MEMPUT mimage, mimage.OFFSET + 1, _WIDTH(0) * _HEIGHT(0) * 4 AS _UNSIGNED _BYTE
_DISPLAY

This code contains many bugs. For example, the MEMPUT command should store data in memory for mimage. But at the beginning of the program is SCREEN NEWIMAGE, so the data is stored in a virtual (unvisible) screen. Another mystery to me is why you are trying to save 4 * _Unsigned _byte. I don't see anywhere decomposition of colors on alpha, red, green and blue. Why isn't the type for RGBA32 used correct unsigned long? Why is the _Display command on the second line when no action has been taken on the screen? How do you use the memput command to insert data when program has not previously generated or retrieved any image data with the MEMGET command?

Code: QB64: [Select]
  1. 'simple example how copy images with mem
  2.  
  3. imageA = _NEWIMAGE(800, 600, 32) 'as source image
  4. imageB = _NEWIMAGE(800, 600, 32) 'as dest image
  5. _DEST imageA 'draw to imageA, but not show it
  6. CIRCLE (400, 300), 150, &HFFFFFFFF
  7. PAINT (400, 300), &HFFFFFFFF, &HFFFFFFFF
  8. _DEST 0 'return to actual screen
  9.  
  10. a = _MEMIMAGE(imageA)
  11. b = _MEMIMAGE(imageB)
  12. DIM size(799 * 599) AS _UNSIGNED LONG
  13.  
  14. _MEMGET a, a.OFFSET, size()
  15. _MEMPUT b, b.OFFSET, size()
  16. ERASE size
  17.  
  18. SCREEN imageB
  19.  
  20.  

This is just a quick and simple example. Complications occur when copying an image from NEWIMAGE, 256 to a 32 bit image, when you have to pay attention to different offset, as RhoSigma writes. Other complications are when copying images with different resolutions, you have to watch it again, otherwise (with mem commands very easy) you create an error message "memory region out of range."
« Last Edit: June 25, 2019, 03:27:16 am by Petr »

Offline MrFreyer

  • Newbie
  • Posts: 34
    • View Profile
Re: question about _MEMIMAGE / _MEMPUT
« Reply #3 on: June 25, 2019, 04:18:16 am »
Why not simply staying with _PUTIMAGE? With the following syntax:
        _PUTIMAGE (dx1, dy1), sourceHandle&, destHandle&, (sx1, sy1)-(sx2, sy2) 'portion of source to the top-left corner of the destination page
you may copy any cutout of the source image  (sx1, sy1)-(sx2, sy2) to any desired startposition on the destination (dx1, dy1).

That's what I actual use.
See:

Code: QB64: [Select]
  1.  imagesectionY = cameraY - (screenwindow.height * 0.5) + 1
  2.     imagesectionX = cameraX - (screenwindow.width * 0.5) + 1
  3.  
  4.     SELECT CASE global.animationFrame
  5.         CASE 1: _PUTIMAGE (0, 0), drawlayerMapFrame1, 0, (imagesectionX, imagesectionY)-(imagesectionX + screenwindow.width, imagesectionY + screenwindow.height)
  6.         CASE 2: _PUTIMAGE (0, 0), drawlayerMapFrame2, 0, (imagesectionX, imagesectionY)-(imagesectionX + screenwindow.width, imagesectionY + screenwindow.height)
  7.         CASE 3: _PUTIMAGE (0, 0), drawlayerMapFrame3, 0, (imagesectionX, imagesectionY)-(imagesectionX + screenwindow.width, imagesectionY + screenwindow.height)
  8.         CASE 4: _PUTIMAGE (0, 0), drawlayerMapFrame4, 0, (imagesectionX, imagesectionY)-(imagesectionX + screenwindow.width, imagesectionY + screenwindow.height)
  9.         CASE 5: _PUTIMAGE (0, 0), drawlayerMapFrame5, 0, (imagesectionX, imagesectionY)-(imagesectionX + screenwindow.width, imagesectionY + screenwindow.height)
  10.         CASE 6: _PUTIMAGE (0, 0), drawlayerMapFrame6, 0, (imagesectionX, imagesectionY)-(imagesectionX + screenwindow.width, imagesectionY + screenwindow.height)
  11.         CASE 7: _PUTIMAGE (0, 0), drawlayerMapFrame7, 0, (imagesectionX, imagesectionY)-(imagesectionX + screenwindow.width, imagesectionY + screenwindow.height)
  12.         CASE 8: _PUTIMAGE (0, 0), drawlayerMapFrame8, 0, (imagesectionX, imagesectionY)-(imagesectionX + screenwindow.width, imagesectionY + screenwindow.height)
  13.     END SELECT
  14.  
(there are 8 different layers for an animated background...)

But there are also many objects that must be drawn. I thought that the _MEMIMAGE would be a much faster method.

This code contains many bugs. For example, the MEMPUT command should store data in memory for mimage. But at the beginning of the program is SCREEN NEWIMAGE, so the data is stored in a virtual (unvisible) screen. Another mystery to me is why you are trying to save 4 * _Unsigned _byte. I don't see anywhere decomposition of colors on alpha, red, green and blue. Why isn't the type for RGBA32 used correct unsigned long? Why is the _Display command on the second line when no action has been taken on the screen? How do you use the memput command to insert data when program has not previously generated or retrieved any image data with the MEMGET command?

This was just a smal example with some commands and things I use in the original code (_DISPLAY, alpha-transparency...).
So it's much more complicated with _MEMIMAGE if the datas are stored in a virtual screen? Okay, maybe I should stay with _PUTIMAGE ^^

Thanks.

Marked as best answer by MrFreyer on June 25, 2019, 08:30:59 am

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: question about _MEMIMAGE / _MEMPUT
« Reply #4 on: June 25, 2019, 04:26:55 am »
Hi,

I try to draw a (prefabricated) background tilemap on the screen, using the _MEMIMAGE and _MEMPUT commands. But sadly it doesn't work and don't know what I'm doing wrong...the background is just black.

It looks like this:
Thanks!

One thing to note: What you’re wanting to do involves TWO images — the visible screen, and then the tile map.  Your _MEMPUT changes a single pixel on the tile map, and as such, does absolutely nothing with the main screen.  What you’re wanting is more like this:

SCREEN _NEWIMAGE(600,800,32)
DIM VisibleImage AS _MEM, TileImage AS _MEM
VisibleImage = _MEMIMAGE(0)

....load image
....draw tile image
TileImage = _MEMIMAGE(tile image background)


.....

CLS
_MEMCOPY TileImage, TileImage.OFFSET, TileImage.SIZE TO VisibleImage, VisibleImage.OFFSET

^^^^. You’re not putting a single value on the tile set background; you’re wanting to copy the tile set background onto the visible screen
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline MrFreyer

  • Newbie
  • Posts: 34
    • View Profile
Re: question about _MEMIMAGE / _MEMPUT
« Reply #5 on: June 25, 2019, 12:33:10 pm »
^^^^. You’re not putting a single value on the tile set background; you’re wanting to copy the tile set background onto the visible screen

Thanks! Yeah, that's what I wanted. At the time, I got an "destination memory region out of range" error. Could this be related to the OFFSET?

EDIT:
It's in this Line:
_MEMCOPY TileImage, TileImage.OFFSET , TileImage.SIZE TO VisibleImage, VisibleImage.OFFSET

EDIT2:
Got it! It was because the TileImage was bigger in size than the VisibleImage. But that's okay and normal. I think I can manage this.
« Last Edit: June 26, 2019, 02:29:14 am by MrFreyer »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: question about _MEMIMAGE / _MEMPUT
« Reply #6 on: June 27, 2019, 12:40:44 pm »
If they’re different sizes, you’re better off just sticking to _PUTIMAGE to get the job done, since one screen needs to scale to fit the other.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline MrFreyer

  • Newbie
  • Posts: 34
    • View Profile
Re: question about _MEMIMAGE / _MEMPUT
« Reply #7 on: July 01, 2019, 04:53:25 am »
If they’re different sizes, you’re better off just sticking to _PUTIMAGE to get the job done, since one screen needs to scale to fit the other.

Of course, the tilemap and the screen have different sizes. I work around with the destination- and source-offsets and for now it works - and it's so much more faster, damn!

Its much more efficient if you use _MEMCOPY instead of _PUTIMAGE if you have a lot of sprites or tiles to draw.
Code: QB64: [Select]
  1.  FOR scanline = 1 TO screenwindow.height
  2.  _MEMCOPY TileImage, TileImage.OFFSET + ((map.width * 4) * (scanline - 1)), TileImage.SIZE + (screenwindow.width *4) - TileImage.SIZE  TO VisibleImage, VisibleImage.OFFSET + ((screenwindow.width * 4) * (scanline -1))
  3.  NEXT scanline
  4.  
I only have to change it a little bit, so that the camera x/y will be taken into account.