Copy From 1 TImage To Another?
BlitzMax Forums/BlitzMax Beginners Area/Copy From 1 TImage To Another?
| ||
Is there a way to copy a rect section from 1 TImage to another TImage? Thanks. |
| ||
You can lock the image to get a pixmap, which you can pass to PixmapWindow() to select a rectangular region, then use LoadImage() to load the pixmap into the other TImageRectImage:TImage = LoadImage(PixmapWindow(LockImage(FirstImage),10,10,32,32)) |
| ||
or the tpixmap paste method or drawimage/grabimage. |
| ||
DrawImage and GrabImage is probably much faster. |
| ||
hello. DrawImage and GrabImage involve plus data movement. Please, if is plus faster i need understanding. thanks, Paposo |
| ||
Yikes.. looks like it's going to be more difficult than I had planned. I've never used pixmaps, or locked images, so not quite sure where to go. In a nut shell I have 2 textures (TImage) loaded, each 512x512 and I want to be able to copy any size rect from one to the other. Speed isn't an issue since it will happen between levels and not during game play. I use transparent png files so hopefully any solutions eventually will support that as well. hmm.. in the copy function it looks as if I need to: a) Convert both textures to Pixmaps. b) Copy from 1 pixmap to the other as needed. c) Convert the resulting pixmap back to the texture. Notice I posted in the beginner section, :) so any help is much appreciated. Thanks. |
| ||
Should be easy to adapt it to your needs... think i didn't care about destinations alpha (only sources alpha). To make it a DrawImageOnImage you will need to lock the given destination pixmap and use that instead of a given pixmap. The Rect thing has to be put into the for-loops (from i:int = xstart to xend). Function ARGB_Alpha:Int(ARGB:Int) Return Int((ARGB & $FF000000:Int) / $1000000:Int) End Function Function ARGB_Red:Int(ARGB:Int) Return Int((ARGB & $00FF0000:Int) / $10000:Int) End Function Function ARGB_Green:Int(ARGB:Int) Return Int((ARGB & $0000FF00:Int) / $100:Int) End Function Function ARGB_Blue:Int(ARGB:Int) Return (ARGB & $000000FF:Int) End Function Function ARGB_Color:Int(alpha:Int,red:Int,green:Int,blue:Int) Return (Int(alpha*$1000000)+Int(blue*$10000)+Int(green*$100)+Int(RED)) End Function Function DrawOnPixmap(image:TImage,framenr:Int=0, Pixmap:TPixmap, x:Int, y:Int) Local TempPix:TPixmap = Null If framenr = 0 Then TempPix= LockImage(image) If framenr > 0 Then TempPix= LockImage(image, Framenr) For Local i:Int = 0 To ImageWidth(image)-1 For Local j:Int = 0 To ImageHeight(image)-1 If x+1 < pixmap.width And y+j < pixmap.height Local sourcepixel:Int = ReadPixel(TempPix, i,j) Local destpixel:Int = ReadPixel(pixmap, x+i,y+j) ' Local destA:Int = ARGB_Alpha(destpixel) Local sourceA:Int = ARGB_Alpha(sourcepixel) If sourceA <> -1 Then If sourceA< -1 Then sourceA = -sourceA Local destR:Int = ARGB_Red(destpixel) Local destG:Int = ARGB_Green(destpixel) Local destB:Int = ARGB_Blue(destpixel) Local SourceR:Int = ARGB_Red(Sourcepixel) Local SourceG:Int = ARGB_Green(Sourcepixel) Local SourceB:Int = ARGB_Blue(Sourcepixel) sourceR = Int( Float(sourceA/255.0)*sourceR) + Int(Float((255-sourceA)/255.0)*destR) sourceG = Int( Float(sourceA/255.0)*sourceG) + Int(Float((255-sourceA)/255.0)*destG) sourceB = Int( Float(sourceA/255.0)*sourceB) + Int(Float((255-sourceA)/255.0)*destB) sourcepixel = ARGB_Color(255, sourceR, sourceG, sourceB) EndIf If sourceA <> 0 Then WritePixel(Pixmap, x+i,y+j, sourcepixel) EndIf Next Next If framenr = 0 UnlockImage(image) If framenr > 0 UnlockImage(image, framenr) End Function bye MB |
| ||
I looked into this a while back and then realised I could code my game a different way without the need to copy an image. |
| ||
It might be best to keep a copy of both images in pixmaps and whenever the pixmaps are modified, then reload the pixmaps back into the images. That way you won't need to GrabImage() or LockImage() first. This example uses MemCopy() to copy a row of pixels from one image to the next. Just use your own image in the example and point Const Filename to that image. The second image is just the first one flipped vertically. Click on either image to copy the cursor square from one to the other . |
| ||
Thanks TomToad, the demo seems to work, but any way to wrap this up into one nice function such as: CopyImageToImage(srcTImage:TImage,srcx:int,srcy:int,srcwidth:int,srcheight:int,dstTImage,dstx:int,dsty:int) I would be most grateful if this could be done. And then you need to post it in the code archive for all to use. :) Thanks! |
| ||
Anything you do with a pixmap is going to be much slower than anything you do with images. DrawImage and GrabImage are probably faster regardless of whether it seems like you're shifting more data around. The GPU is usually 10 times or more faster than dealing with pixmaps. The pixmaps have to be transferred over the graphics bus which is quite a slow process. |
| ||
hehe if someone "functionalises" it, I'll snaffle it too :-) I always found GrabImage to be quite slow (especially on an 800x600 screen) like 200+ms, because it has to come down from VRAM to RAM which the GFX cards are not really designed for. |
| ||
If you're not worried about masking then you can do something like this: Otherwise you can try this which I have cleaned up slightly: |
| ||
GrabImage grabs a pixmap as well as an turning it into an image? It shouldn't have to. For example glCopyTexSubImage2D copies an area from the backbuffer into an existing texture without ever going to main memory and it's fast enough that you could do it at least a few times per frame at 60hz. |
| ||
thinking about this today and realized there was no need to store an extra copy of the pixmaps since the TImage already had a pixmap copy. When you LockImage(), it returns the copy of the pixmap, and the next time you draw the image, the pixmap will be copied into VRAM automatically. So here is a Functionalized version, with some bounds checking as well. |
| ||
Mr.Toad, someday when I get all BlitxMax braniac, I hope to return the favor. This is a very valuable function I'm sure others will have a need for at some point. Thank you for taking the time to code this. :) Do you know if there is any scenario where this will not work? (16,24,32bit modes?, OGL or DX?) It appears to be cross platform compatible. One thing I like about it, you could use it to copy over new sprite images from a source texture onto your game texture without having to change your main loop code. Speed is not an issue since this would be done between levels, etc. ;) |
| ||
Hot stuff. Thanks TomToad! Hope you don't mind but I've added it to my framework and credited you. |
| ||
ImaginaryHuman: Yeah it is, but first its a GL only function and second I'm not sure if it is OpenGL 1.2 compliant which is what BM enforces on Max2D. If one used the DX surface commands the whole stuff including setBuffer would be implementable again and work but then the GL user would be pissed again. You see the problem? :) |
| ||
@MGE Developer: I tried it out with 16, 24, and 32 bit modes. Both OpenGL and DirectX works. I couldn't test 24 bit on OpenGL because my card apparently only supports 16 and 32 bit modes with OpenGL. I did think of one possible problem. It would be with byte alignment. Shouldn't be a problem now since I believe BMax is optimized for 32 bit on all platforms, but if it were to change and BMax were optimized for 64 bit, then the above code will break. I tried to locate a byte-align field for the pixmaps, but there doesn't seem to be one. You could go the safe route and rewrite the above to use ReadPixel and WritePixel in a loop, but that would be much slower than MemCopy() and would bog down the program if you needed to copy a lot of data each loop. @Grey Alien: Thanks. Glad you can find some use for it. :) In all your studying of BMAX, by chance have you figured out how to find the byte alignment of a pixmap? |
| ||
TomToad: No I'm afraid not. BMax is pretty big and most of my study has been high level objects or Windows API calls rather than graphics functions. I pretty sure something like that was possible in BPlus. Why not start a thread about it? |
| ||
Using TomToad's suggestion of using Read/Write pixel, here's a modified version complete with 4 copy modes; Normal, Mirror,Flip,Mirror&Flip. Speed ofcourse is slower, but using it real time was never my intended use. Thanks again TomToad, this is the exact routine I had in mind when the topic was first created. :)Function CopyImageToImage(Source:TImage,SX:Int,SY:Int,SWidth:Int,SHeight:Int,Dest:TImage,DX:Int,DY:Int,flags:Int=0) ' ' flags: 0 = Normal 1 = Mirror 2 = Flip 3 = Mirror and Flip ' Local SourcePix:TPixmap = LockImage(Source) Local DestPix:TPixmap = LockImage(Dest) Local SourceWidth:Int = PixmapWidth(SourcePix) Local SourceHeight:Int = PixmapHeight(SourcePix) Local DestWidth:Int = PixmapWidth(DestPix) Local DestHeight:Int = PixmapHeight(DestPix) If SX < SourceWidth And SY < SourceHeight And DX < DestWidth And DY < DestHeight If SX+SWidth > SourceWidth Then SWidth = SourceWidth - SX If SY+SHeight > SourceHeight Then SHeight = SourceHeight - SY If DX+SWidth > DestWidth Then SWidth = DestWidth - DX If DY+SHeight > DestHeight Then SHeight = DestHeight - DY Select flags Case 0 ' Normal For Local py:Int = 0 To SHeight-1 For Local px:Int = 0 To SWidth- 1 WritePixel(DestPix,DX+px,DY+py,ReadPixel(SourcePix,SX+px,SY+py)) Next Next Case 1 ' Mirror For Local py:Int = 0 To SHeight-1 For Local px:Int = 0 To SWidth- 1 WritePixel(DestPix,DX+px,DY+py,ReadPixel(SourcePix,(SX+(SWidth-1))-px,SY+py)) Next Next Case 2 ' Flip For Local py:Int = 0 To SHeight-1 For Local px:Int = 0 To SWidth- 1 WritePixel(DestPix,DX+px,DY+py,ReadPixel(SourcePix,SX+px,(SY+(SHeight-1))-py)) Next Next Case 3 ' Mirror and Flip For Local py:Int = 0 To SHeight-1 For Local px:Int = 0 To SWidth- 1 WritePixel(DestPix,DX+px,DY+py,ReadPixel(SourcePix,(SX+(SWidth-1))-px,(SY+(SHeight-1))-py)) Next Next End Select EndIf UnlockImage(Source) UnlockImage(Dest) End Function |
| ||
Hey so that's more advanced cool. Presume you've tested it. Now MGE Developer, may I place this in my framework please? |
| ||
I wonder if a render to texture routine would make this usable for realtime? |
| ||
Yes but it will fail on a lot of systems (ie nearly any intel or other onboard which means 70%+ of all users) |
| ||
Why does render to texture fail on some systems? |
| ||
Why does render to texture fail on some systems? Not a problem with GFX cards nowadays, even integrated intel! |
| ||
Explain that to those users not waisting money on new systems every 2 years. Even thought, I bought my tablet in Jan 07 and have a GMA900 in, so don't bet on anything beeing available. Until recently intel didn't even fullfill the T&L compliant level (GMA900 definitely does not or its drivers are just that crappy that they break the T part over and over again). And even now, Intel only supports exactly that part that is needed to get Microsofts Vista ready logo, not the least bit more *Intel X3100 CPU to VGA adapter erm GPU* (ie its ok for aero but still a class 4 GPU with any other onboard from SiS, S3 and Intel and far far behind even the worst ATI or NVIDIA onboard performance and capability wise. Even GeForce 4200 Ti were worlds faster) |
| ||
Yes glCopyTexSubImage2D is OpenGL only, so no DX implementation, but it is a part of GL 1.2 and can be compiled with standard BlitzMax without any extensions. It's way faster than anything that could be done with the CPU. If you are going to go with the CPU version, then I recommend getting rid of WritePixel and ReadPixel and replace them with pointer access ie basepointer[offset]=whatever. That removes the overhead of having to `look up` the pixmap for every single writepixel call and to calculate the offset based on coordinates. For a small routine that you're calling many thousands of times like that you should be looking to optimize it. Keeping one pointer and doing pointer access will show you a speed boost. |
| ||
"Now MGE Developer, may I place this in my framework please?" Ofcourse! I added it to mine as well. ;) |
| ||
thx |
| ||
*b0mp* Function CopyImageToImage(Source:TImage ,SX:Int,SY:Int,SWidth:Int,SHeight:Int,Dest:TImage Var,DX:Int,DY:Int,flags:Int=0) It needs Var :P I randomly needed a function like this today.. \o/ |