Writing Transparency to PNG?

BlitzMax Forums/BlitzMax Programming/Writing Transparency to PNG?

Endive(Posted 2015) [#1]
How do I generate images with an alpha channel suitable for saving as png for later use with alphablend?

Maskblend is not suitable because the image must include translucent parts.

The images must be generated in Blitzmax, I can't just use photoshop.

EDIT: hell with it, I will just roll my own with writepixel.


Derron(Posted 2015) [#2]
Writepixel is the only "vanilla" solution when trying to run it "headless" and without a graphics context...


- Create a Pixmap / Image with the correct format (rgba instead of rgb)
- store your image data
- savepng

my little image helper:
https://github.com/GWRon/Dig/blob/master/base.gfx.imagehelper.bmx

contains "ColorizePixmapCopy()" which allows to have some colorization modes: Multiply, NegativeMultiply and Overlay ... maybe you need the formulas to do so ...


bye
Ron


Fielder(Posted 2015) [#3]
(edit) wrong post


Endive(Posted 2015) [#4]
I will look into your image helper. It can have a graphics context. I will write my own anyway so I understand it but I will use your source code as an example.

As an aside, can one render with OpenGL and save the resultant images in the normal way in Blitz?


Endive(Posted 2015) [#5]
I am now writing to a pixmap using writepixel and bresenham line routines. I cannot, however, get the pixmap to be transparent. It appears to be opaque from the very beginning.

This is the creation code:
Global pixmap:TPixmap = CreatePixmap(800,600,PF_BGRA8888)


I have setblend ALPHABLEND set. I can draw lines to the pixmap to mousex(),mousey(), and when I draw the pixmap itself, the lines I've drawn on it show up. But the background is opaque black.

Ideas?

I can just save a timage, load it up in photoshop to a PNG and do my transparency and glow there but I would like to understand how to do this myself.


Kryzon(Posted 2015) [#6]
As soon as you create it it may be filled with garbage (random memory).
Try using pixmap.ClearPixels( 0 ) to fill it with transparent black. Then change the pixels to what you want.


Endive(Posted 2015) [#7]
I already tried clearpixels(0). I will write a simple test program to see if I can either get it to work or not work and go from there. Is the pixel format in my createpixmap command correct?


dw817(Posted 2015) [#8]
Hi Endive:

* I'm not sure entirely what you want. Here is an example I wrote for you which will load an image, show it, select the transparent color, then display it again over a colored background to prove it is transparent:

Strict
Global i
Graphics 640,480
SetClsColor 50,100,150
Cls
For i=0 To 479
  SetColor Sin(i/2.0)*128,Sin(i)*128,Sin(i*2)*128
  DrawLine 0,i,639,i
Next
SetColor 255,255,255
Global img:TImage=LoadImage("critter in red.png")
DrawImage img,0,0
img.SetPixmap(0,MaskPixmap(LockImage(img),255,0,0))
DrawImage img,128,0
Flip
WaitKey

Source image:


If you need to save an image with transparency in effect, that is different code. But this is the easy way to have it so you don't have to create and save any new images.


Kryzon(Posted 2015) [#9]
Is the pixel format in my createpixmap command correct?

Correct for what? All the formats work, so you choose the one that's appropriate for what you need.
If it's for pixel manipulation I think PF_ARGB8888 is more common, there's more code around that's written around that (extracting each A,R,G,B component etc.).

If it's for display, both the OpenGL and Direct3D Max2D drivers convert the pixmap to the format needed for display, so the source format won't make a difference.
- https://github.com/maxmods/brl.mod/blob/master/glmax2d.mod/glmax2d.bmx#L257
- https://github.com/maxmods/brl.mod/blob/master/d3d9max2d.mod/d3d9max2d.bmx#L102


Endive(Posted 2015) [#10]
dw817, Thank you. But I need translucency, not just maskimage. I want to be able to create and save PNG images with an alpha channel in software, and be able to write translucent (not transparent) pixels to them.

Kryzon:

If it's for pixel manipulation I think PF_ARGB8888 is more common, there's more code around that's written around that (extracting each A,R,G,B component etc.

PF_ARGB8888 ends with a black image with no transparency. I will write a simple test case and put it up here for you to dissect if you want.


dw817(Posted 2015) [#11]
Endive:

* That there is the 64 dollar question. I haven't been able to discover recording custom alpha channels to PNGs myself. I think - it's not possible unless you write your OWN image saving routine.

Understand that when you write alpha to the screen, all you can read back are the affected pixels, not the INPUT values of where they came from.

If you find different, please let me know as I suspect that will be useful information for everyone.

If you just want images to appear at half level, like a ghost, you can skip recording alpha transparency and just use SETALPHA .5, display your image, and SETALPHA 1 to return back again for normal drawing.


Endive(Posted 2015) [#12]
I think one of these other guys is going to know this, they know EVERYTHING.

I don't even really care though if I can generate my spritesheet at runtime. I just need to be able to successfully write alpha pixels to a transparent pixmap, then I can blit off of that.

Also in my program when I try to do img.setpixmap I get "identifier "setpixmap" not found."


Matty(Posted 2015) [#13]
Not sure if I'm barking up the wrong tree here but....

if you want to take an image from the screen and capture the alpha channel used with the image then you can do so with two draws. One over black background, one over white, read the pixels and the difference in average rgb values between the two images is your alpha value (or perhaps inversed).

eg:

where rgb average difference between two images = 0 then alpha = 255 (no transparency)
where rgb average difference between two images = 255 then alpha = 0 (full transparency)
where rgb average difference is between 0 and 255 the alpha is 255 - the difference.

Once you've calculated the alpha for each pixel you can save it.


Floyd(Posted 2015) [#14]
If you read a pixel value, call it ARGB, with ReadPixel then you can set the alpha "by hand".

		ARGB :& $00FFFFFF  ' alpha set to zero, RGB unchanged.
		ARGB :| $40000000  ' alpha set to $40 ( 25% ), RGB unchanged.



xlsior(Posted 2015) [#15]
FWIW, Matty has some code in the archives that writes a TGA with transparent background: http://www.blitzbasic.com/codearcs/codearcs.php?code=3198
(second snippet on the page)


(I did notice that photoshop didn't properly read the transparancy in the output tga file, but paint.net did)


Derron(Posted 2015) [#16]
The following works as expected

saveTransparentPNG.bmx:
SuperStrict

Framework Brl.StandardIO
'Import Brl.Pixmap 'imported via PngLoader already
'Import Pub.LibPNG 'imported via PngLoader already
Import Brl.PngLoader


global pix:TPixMap = CreatePixmap(100,100, PF_RGBA8888)
pix.clearPixels(0)

For local x:int = 0 until 100
	For local y:int = 0 until 100
		'reading rgba from int would be:
		'Local r:Byte = col	
		'Local g:Byte = col Shr 8
		'Local b:Byte = col Shr 16
		'Local a:Byte = col Shr 24
		'storing rgba in int would be:
		'Int( r | g Shl 8 | b Shl 16 | a Shl 24 )
		local col:int = Int( (x*2) | 255 Shl 8 | 255 Shl 16 | (y*2) Shl 24 )
		pix.WritePixel(x, y, col)
	Next
Next

SavePixmapPNG(pix, "saveTransparentPNG.png")


Result:



Like said: in software rendering everything is possible - and even does not need a graphics context (good for scripting). Of course you need to have your own line/oval/rect-functions (including potential antialiasing).
To draw fonts, you just take the "glyph-pixmaps" contained in the TImageFont and "render" it on your pixmap. For more regarding fonts, check out my bitmapfont-file (in the Dig-Framework).


bye
Ron


dw817(Posted 2015) [#17]
Beautiful coding, Ron !

I'm saving that one for the books for future reference. You are indeed showing you can save ALPHA and not just at an ON or OFF level but values in-between.

Nicely done ! This does open up some interesting animation possibilities.

I am reading the code ... I'm a little confused about how (x*2) is ALPHA ? Isn't that the BLUE channel ? Further the direction you are going would seem to appear like the ALPHA would be more solid on the right instead of the left ?
0 ALPHA is fully transparent
255 ALPHA is fully solid ?


Derron(Posted 2015) [#18]
See that comment:
'storing rgba in int would be:
'Int( r | g Shl 8 | b Shl 16 | a Shl 24 )


Read again: I store r.g.b.a - so red, green, blue and alpha
Each of them is stored in the following way: 0 = nothing and 255 = maximum. For "alpha" this means: 0 = transparent and 255 = full opaque.


So what does the following do?
For local x:int = 0 until 100
	For local y:int = 0 until 100
		local col:int = Int( (x*2) | 255 Shl 8 | 255 Shl 16 | (y*2) Shl 24 )
		pix.WritePixel(x, y, col)
	Next

It does for every "column" in the pixmap loop through every "row".
In every row we use the color consisting of "twice the column number" for red, then full green, full blue and an "twice the column number" high alpha.
If you replaced the "(y*2)" with "255" you would get an resulting image which starts full-yellow on the left and ends "full-white" on the right. But as we start with a "fully transparent" when in row 0 and end in "nearly full opaque" in row 100 (exactly it is 200/255 opaque).
It is "yellow" because this is what "g + b" result in.

Feel free to experiment with the values to understand it a bit more. Playing with sources is always something you should do.


bye
Ron


Endive(Posted 2015) [#19]
Derron: Thanks, I should be able to just remove all my init code and replace it with yours. I'll have to dissect mine to see what I'm doing wrong...


TomToad(Posted 2015) [#20]
Also know that using WritePixmap() to the screen might ignore the alpha channel on some systems. If you do something like

Image:TImage = LoadImage(Pixmap)
DrawImage Image,10,10

Then the alpha will work.
SuperStrict

Graphics 800,600
Local Pixmap:TPixmap = CreatePixmap(64,64,PF_RGBA8888) 'create the puixmap

Local alpha:Int 'for calculating the alpha
For Local x:Int = -32 To 31
	For Local y:Int = -32 To 31
		alpha = 255 - Sqr(x*x+y*y)*8 'calculate the alpha
		alpha = Max(alpha,0)
		WritePixel(pixmap,x+32,y+32,alpha Shl 24 + $FFFF00) 'Yellow pixel
	Next
Next

SetBlend ALPHABLEND
DrawPixmap pixmap,10,10 'draw the pixmap (alpha might not work)
Local Image:TImage = LoadImage(Pixmap) 'load the pixmap into an image
DrawImage Image,100,100 'draw the image (alpha renders ok)

Flip
WaitKey()



Endive(Posted 2015) [#21]
All right, I understand now what at least part of the problem was. Drawpixmap doesn't respond to ALPHABLEND.

Now, how do I convert my pixmap to an image without the intermediary step of saving and loading from disk, all while preserving transparency?

EDIT: TomToad explained.

This should all be sorted out now, or close. Thanks so much guys for elucidating.


dw817(Posted 2015) [#22]
Oh, I gotcha, Derron. I always do my rectangles where vertical is the first loop. I thought you were doing the same but it's opposite. Ok, I can see how to learn from this now.

TomToad, I am seeing that in BlitzMAX when you use drawpixmap it definitely doesn't take into account intermediary alpha, rotation, scaling, or even color for that matter.

Which would bring up an interesting point. I wonder if drawpixmap() or drawimage() is faster, or are they the same speed perhaps ?



One day to Christmas ...


Kryzon(Posted 2015) [#23]
If I'm not mistaken, looping vertical then horizontal inside is more "cache friendly", since the image buffer is stored contiguously in memory as all rows joined together.
The compiler may even vectorise -- process multiple pixels at once.

DrawPixmap is a convenience function. For production use you should rely on TImage instead, that internally uses textures for accelerated drawing. This means you should use DrawImage and the Set[...] functions (SetBlend, SetScale etc.).


Endive(Posted 2015) [#24]
If I'm not mistaken, looping vertical then horizontal inside is more "cache friendly", since the image is stored contiguously in memory as all rows joined together.
The compiler may even vectorise -- process multiple pixels at once.


Very astute. I will time this...


xlsior(Posted 2015) [#25]
Which would bring up an interesting point. I wonder if drawpixmap() or drawimage() is faster, or are they the same speed perhaps ?


Pixemaps live in your computer's main RAM, images live in video memory.

Any time you draw a pixmap, it has to transfer from RAM to videomemory first, and this will slow it down considerably over drawing images.


Endive(Posted 2015) [#26]
I was under the assumption that pixmaps were much faster. Guess I assumed wrong.


TomToad(Posted 2015) [#27]



dw817(Posted 2015) [#28]
Seems to run the same speed here, TomToad. Could be the FLIP() is what is slowing everything down. Maybe have it FLIP only once every 10 times or so to get the CPU usage higher.

But yes, drawing PIXMAPS does just that with no color, rotation, scaling, or alpha. Still, drawing PIXMAP absolutely ensures you are drawing just that with no dithering.


Derron(Posted 2015) [#29]
Flip is doing the texture transport to the gpu hence the long pprocessing time.
Flip is needed as it does the actual render.

Bye
Ron


Endive(Posted 2015) [#30]
Flip is doing the texture transport to the gpu hence the long pprocessing time.

By definition though it only needs to happen once per frame :)

Is there any way to do frame compositing on the GPU itself, thereby obviating the need for Flip?


Casaber(Posted 2015) [#31]
I get slower as suspected when I use PIXMAP, itīs visible when I replace FLIP with FLIP 0.

From what I understand FLIP doesnīt make any transfer but just swaps the backbufferpointer into become the frontbuffer.
The only things that slows FLIP down is the vertical blanking wait (and FLIP 0 would not be slowed down by anything).

I think itīs just PIXMAP, where you draw to main memory and have alot of needed transfering going on and it happens at the time the actual drawing commands was issued.
I donīt think drawing operations are badged up until a FLIP happens.

Thatīs my view on the hardware at least. (That everything draws onto the backbuffer at the time commands are actually issued
(at various speed depending on which side of the GPU the image is located) and, that FLIP does nothing beside a hardware pointerswapping)


Derron(Posted 2015) [#32]
Thatīs my view on the hardware at least.


Your view is limited (not to say "wrong").

Check flip on DX and on OGL ... and on multiple hardware.
You then will see, that sometimes "DrawImage" takes its time and flip is fast, and sometimes "DrawImage" is nearly instant but flip takes time.


bye
Ron


Endive(Posted 2015) [#33]
Now another question. What's the best and simplest way to draw sprites from a single large image to minimize writes to the card? Should I just use TImage frames?


dw817(Posted 2015) [#34]
If that question is for anyone, it depends, Endive ... Do you want to display same-size images as your sprites ? Then use of TIMAGE frames would be fine.

RPG Maker 95 used this method, tried and true, each element being 32x32 pixels or 64x128 pixels per 8-images per sprite:



Derron(Posted 2015) [#35]
Checkout the imagehelper-class I provided in post #2.

Use it to store your individual images (-> their pixmaps) in a freshly created bix pixmap.
This way (and with my functions) you are even in the chance to colorize grey areas (eg. team color flags).

I wont go much into detail about sprite atlas packing - as this was handled multiple times in the forum.

The following class enables you to create the regions of a sprite atlas:
https://github.com/GWRon/Dig/blob/master/base.gfx.spriteatlas.bmx

I wont give more help how to use it than the following:
- create a TSpriteAtlas
- use atlas.AddElement(w,h) for each sprite
- iterate over atlas.elements.Values() to fetch the information on where to store the sprites on the new spritesheet.


(that class uses "base.util.rectangle.bmx" - and this then "base.util.vector.bmx" - feel free to replace it with your own x,y,w,h-wrapper)



bye
Ron


Endive(Posted 2015) [#36]
Hmmmm. I think for this current game I'm working on I'm just going to use TImage frames. Colorization would be amazing but I don't need it, or varying sizes.

Your stuff is amazing but at this point it's overkill for what I need and this is probably the last game I'm going to write using sprites, I'm going to bite the bullet and learn OpenGL better.


Casaber(Posted 2015) [#37]
I doing what Dw817 does and use only 32x32 sprites, I find that DrawSubImageRect and even SetColor works so amazingly fast that you could build just about everything using them reliably.

I also really like to be able to put clothes and weapons separate in grays and color them realtime with SETCOLOR. It works out great. Great speed.

Instead of using different sizes of tiles and sprites I use one fixed and use "chained sprites" as Neogeo did to form any shape i need.
Itīs simple Itīs just a matter of meta-tiles really. Some tiles are treated like arrays (or other structure) that points to a bunch of
tiles to draw the complete shape in one go. And you could even put more relative x,y,mirror/rotation of each tile, and parameters for eg overall rotation with a center point. I also use this for layering tiles (I layer say 2 or 3 sprites maximum) This is mostly used for clever designs in maps to keep the tilecount down to a minimum and to layer colored things (because SETCOLOR are so terribly simplistic so ofte you want a few layers of sprites to form a coherent properly colorful item.

This is I guess an oldtimers trick, but itīs me and Itīs not a terrible waste when used properly. I do love drawing sprites in layers and be flexible within the game with those elements.
It really sounds more complicated than it is, Itīs just my way of playing lego when I build my games. I like that.

All in all - that little DrawSubImageRect are pure gold. You can do so much with it.


Derron(Posted 2015) [#38]
Merging elements in single sprites reduces draw calls ...
Imagine you draw: body, arms/legs, head, weapon, shield, helmet, chest ... then multiply by amount of units simultaneously on screen.

If you precalculate everything in a spritesheet, you loose flexibility of "randomness" in animation (move leg +- 0.5px, rotate head a bit more sometimes...) but gain more performance (fps).

You decide for the tradeoff..


bye
Ron


Casaber(Posted 2015) [#39]
You trade creativity for technicality constrains, yes and for this.. the tradeoff has been accounted for.

I use this calculated tradeoff as a template for my game. Iīts 80x50 32x32 tiles x 4 layers, and 2000 sprites for layering and everything else.

You could EASLY get 8 layers instead of 4 (so Iīm using 80 x 50 x 4 less 32x32 sprites less than I could). (I do this on 2010 equipment). I get steady 60 fps. And have ALOT things to play with. Thatīs alot more important than be constrained with technical precision. I used to be precision minded myself, not anymore. And GOD am I glad that is possible now. coding is fun once again.


Casaber(Posted 2015) [#40]
I also like that both Mac and PC has incredible identical limiits in what and how they are limited in power. This works perfectly on 2010 Mac and, 2012 PC (mid end). This isnīt a lucky shoot. This is where we is today. Well.. few years ago even.


Derron(Posted 2015) [#41]
Add particles to your 2000 sprites and you will sooner or later see an issue rising.

Do not forget potential targets like android/html5/iOS ... they would really benefit from having less draw calls.

Ah ... and if you intend to draw some text, this will add too (one glyph = one texture if you use SetImageFont() instead of a custom sprite atlas).


bye
Ron


Casaber(Posted 2015) [#42]
Particles are nasty yes and pixels aswell, those are borderline cases, still.

Text I guess it is slow but it should be a matter of highlevel implementation not lowlevel trickery as the above. If one knows the complex math of fonts you should be able to draw tiny polygons onto buffers lightningly fast. Itīs just a big questionmark how to reach there and it forces you to use libraries that might be slow in some cases. I personally want to try the non-bitmap font route next, and particles. But I know they are a class for themselves so Iīm saving them for later. I dont't want those kind of things stop my juices flowing.

I guess the particles are a very good point though.

The Android platform was a good point aswell. The sad thing are those machines often has equally powerful innards or close, but you never get to see it.
It's hickup world. Also itīs a huge difference in Android if you use ALPHA, COLOR or not. Android is a separate case definitly.


EDIT just a quick note about Android, my thoughts and experience

I'm able to get pretty much half the spec of the above technique, on an Android mobile (vs a desktop mac/pc), but i need to have bigger tiles, 64x64 I found works perfectly. Android seem very CALL sensitive it doesnīt want many draw commands.
It seem to me that you get exactly 4 fullscreen layers in total no more no less, I think beacuse the fillrate on all Androids are set to a minimum to be 4 layers. Google have some minimum standard to make their UI fluid I think.

I use that as a minimum on Android. So 4 fullscreen layers, and 64x64 tiles there, in whatever amount is needed to cover the screen (1920x1080 would take about 512 64x64).
And I scrap ALPHA and COLOR, Iīm not sure which ones that makes performance crappy but I think thatīs very specific to different models yet. So I stay away.

Thatīs what I get with my mobile (highend 2012 model Samsung with Lollipop). I got a 2014 model now, same range, pretty same spec (but AWFULY higher pixelresolution) but the power inside matches pretty much identical to the 2012 which has lower resolution. This actually made me sad bc that 2012 resolution are amazing, why not make new ones *4 powerful and keep the resolution instead of making them both x4 powerful and x4 higher resolution, which just makes them equally powerful (fillrate wise) and you cantīt really notice those extra pixels on the display anyway. Oh well. sorry I'm rambling.

So Android -4 fullscreenlayers of 64x64 tiles (and NO sprites bc I want to be sure itīs not glitchy more than the OS itself, so Iīm simply using 3 layers and 1 of the layers are instead sprites. in beutiful smooth 60fps (OS likes to chirp in now and then and creates a hickup though) hate it.


dw817(Posted 2015) [#43]
Casaber, I'm looking at the command drawsubimagerect(). I knew about this when I looked up the commands earlier in BlitzMAX.

It seems to have an error in it though. If you do this:
Graphics 640,480
SetColor 255,0,0
DrawRect 0,0,32,32
Global img:TImage=CreateImage(32,32)
GrabImage img,0,0
DrawSubImageRect img,64,0,32,32,0,0,8,6
Flip
WaitKey
End


Notice how at the end I said there was Source Width of 8 pixels and Source Height of 6 pixels ... and yet it still displays a full 32x32 pixel rectangle.

Why is this ?

And ... is there a way of doing a DrawSubImageRect where the output is in fact another TIMAGE or TPIXMAP ? That might solve the Grass Cutter program I wrote earlier for you in your question regarding Worms.


Casaber(Posted 2015) [#44]

Notice how at the end I said there was Source Width of 8 pixels and Source Height of 6 pixels ... and yet it still displays a full 32x32 pixel rectangle.



Thatīs one of the nice things with DrawSubImageRect, you have the option to select the
X,Y,Width,Height for the destination (how you want to draw it)
and after those 4 parameters you have the same for the source.
X,Y,Width, Height

DrawSubImageRect img,64,0,32,32,0,0,8,6 would mean cut out a sprite in img from (0,0,8,6) and it
would paste it to current buffer at (64,0,32,32)

So you stretch 8x6 into 32x32 there. I use this alot for scaling and squishing. (fitting x tiles onto the screen for instance)

For instance to draw that 8x6 in it is you would do this

Graphics 640,480
SetColor 255,0,0
DrawRect 0,0,32,32
Global img:TImage=CreateImage(32,32)
GrabImage img,0,0
DrawSubImageRect img,64,0,8,6,0,0,8,6
Flip
WaitKey
End



Casaber(Posted 2015) [#45]
yup there is a way to draw to another buffer that Iīm using in it right now. So sorry for the mess, itīs not for ppls eye right now, but dig into it if you want.
I could try to tidy things up somewhat.

I cannot load pics up right now but just feed it any 128x128.png with something init so you see the effect.

It will plot to the texture (which you could use as offscreen buffer in hardware aswell, which is nice) and then it splat the texture on the screen.

Thereīs also a old tilesprite test where I use 8x8 tile from that png to build a 256x256 sprite aswell.

[code]
HideMouse ; TImageBuffer.Init(1920,1080,32,60) 'Same as Graphics but set to GLDriver + glewinit
; SetBlend(MASKBLEND)

' tilemap
Global tilemap:Int[476*317]
For y = 0 To 316 ; For x = 0 To 475 ; tilemap[x + y * 476] = 32 If Rnd (10)>8 Then tilemap[x + y * 476] = Int(Rnd(127))
Next ; Next
For temp = 0 To 255 ; tilemap[x + y * 476] = temp ; Next

' load atlas
Global img = LoadImage("128x1282.png",1) ' 0 = antialiaising, 1 = raw pixels
Local IB:TImageBuffer = TImageBuffer.SetBuffer(Img)

s=2 ; y:Int = 0 ; x:Int = 0 ; char:Int = 0 ; wx:Int = 0 ; wy:Int = 0 ; xd=1

While Not MouseDown(2)

' -------------------------------------------
' draw to img (the texture atlas) instead of the backbuffer (here we use the atlas as source aswell, interesting stuff, but you could draw with whatever tools, like a normal screen)
IB.BindBuffer() ' ; IB.Cls(1.0,,,0.4)
For temp=0 To 100 ; SetColor Rnd(255),Rnd(255),Rnd(255) ; Plot Int(Rnd(127)),Int(Rnd(63+16)) ; Next ' ** draw colored dots to show we're alive **
SetColor 255,255,255 ; xx=8 ; DrawSubImageRect img,xx,128-0,128,-8, 0,5*8,128,8 ' also do a stunt and copy a line from itself, to itself to be sure that i can draw to itself, even using itself. Notice the (128-y) and negative height (-8) Itīs needed as there seem to be some Y mirroring going on with the texture. I havnīt checked it this something that must be so or if it is an artifcat how this code is done (canīt remember itīs from this forum somewhere the functions)
IB.UnBindBuffer()
SetViewport 0,0,1920,1080 ; Cls

' back to drawing to the normal backbuffer now !

' ------------------------------------------- (this is trash unneeded old test code and some sprite and splatting the texture onto the screen

wx=xxxx ; Wy=yyyy ; wx=wx-s*KeyDown(KEY_LEFT)+s*KeyDown(KEY_RIGHT) ; wy=wy-s*KeyDown(KEY_UP)+s*KeyDown(KEY_DOWN) ; wx=Max(0,Min(10000,wx)) ; wy=Max(0,Min(10000,wy))
yyyy=wy ; xxxx=wX

'display(wx,wy,0,0,1920,1080) '; display(wx*2,wy*2,0,0,1920,1080) ; display(wx/2,wy/2,0,0,1920,1080) ; display(wx*4,wy*4,0,0,1920,1080)
'SetViewport ofx,ofy,sx,sy ' ; Cls
DrawSubImageRect img, cntx - scrx + ofx, cnty - scry + ofy, tilewidth,tileheight, tilex*8,tiley*8,8,8
'DrawSubImageRect img, 0,0,8,8,32,32,8,8

' garbage from my old code and a moving big sprite build out of 32x32 tiles
xsprite=xsprite + xd '; ysprite = 200+Sin(temp2)*128 ; temp2 = temp2 + 2
If xsprite > ((1920 - (32*16))/4) Then xd = - xd ' how reverse sign
If xsprite < 0 Then xd=-xd

char=21 ; For tempy = 0 To 15 ; For tempx = 0 To 15
sx=xsprite-wx ; sy=ysprite-wy ; char = 65
DrawSubImageRect img, sx+tempx*32,sy+tempy*32,32,32, (char & 15)*8,(char Sar 4)*8,8,8 ; Next ; Next
mx=MouseX() ; my = MouseY() ; char = 30
DrawSubImageRect img, mx-16,my-16,32,32, (char & 15)*8,(char Sar 4)*8,8,8 ' draw this centered mx,my is hotspot
SetColor 255,255,255
xxx=(wx+mx) Sar 5 ; yyy=(wy+my) Sar 5 ; If KeyDown(KEY_SPACE) Or MouseDown(1) Then tilemap[xxx+yyy*476]=30
' -------------------------------------------

DrawImage img,0,0
Delay 1 ; Flip 1
Wend
End

Type TImageBuffer
Field Image:TImage
Field rb:Int[1]
Field fb:Int[1]
Field Imageframe:TGLImageframe
Field Frame:Int = 0
Field OrigX:Int
Field OrigY:Int
Field OrigW:Int
Field OrigH:Int

Function SetBuffer:TImageBuffer(Image:TImage,Frame:Int = 0 )
Local IB:TImageBuffer = New TImageBuffer
IB.Image = Image ; IB.Frame = Frame ; IB.GenerateFBO() ; IB.BindBuffer()
Return IB
End Function

Function Init(Width:Int,Height:Int,Bit:Int=0,Mode:Int=60)
SetGraphicsDriver(GLMax2DDriver()) ; Graphics Width , Height,bit,Mode ; glewInit()
End Function

Method GenerateFBO()
ImageFrame = TGLImageFrame


Casaber(Posted 2015) [#46]
yup there is a way to draw to another buffer that Iīm using in it right now. So sorry for the mess, itīs not for ppls eye right now, but dig into it if you want.
I could try to tidy things up somewhat.

I cannot load pics up right now but just feed it any 128x128.png with something init so you see the effect.

It will plot to the texture (which you could use as offscreen buffer in hardware aswell, which is nice) and then it splat the texture on the screen.

Thereīs also a old tilesprite test where I use 8x8 tile from that png to build a 256x256 sprite aswell.

HideMouse ; TImageBuffer.Init(1920,1080,32,60) 'Same as Graphics but set to GLDriver + glewinit
; SetBlend(MASKBLEND)

' tilemap 
Global tilemap:Int[476*317] 
For y = 0 To 316 ; For x = 0 To 475 ; tilemap[x + y * 476] = 32 If Rnd (10)>8 Then tilemap[x + y * 476] = Int(Rnd(127))
Next ; Next
For temp = 0 To 255 ; tilemap[x + y * 476] = temp ; Next

' load atlas
Global img = LoadImage("128x1282.png",1) ' 0 = antialiaising, 1 = raw pixels
Local IB:TImageBuffer = TImageBuffer.SetBuffer(Img) 

s=2 ; y:Int = 0 ; x:Int = 0 ; char:Int = 0 ; wx:Int = 0 ; wy:Int = 0 ; xd=1

While Not MouseDown(2)

' -------------------------------------------
' draw to img (the texture atlas) instead of the backbuffer (here we use the atlas as source aswell, interesting stuff, but you could draw with whatever tools, like a normal screen)
IB.BindBuffer() ' ; IB.Cls(1.0,,,0.4)

For temp=0 To 100 ; SetColor Rnd(255),Rnd(255),Rnd(255) ; Plot Int(Rnd(127)),Int(Rnd(63+16)) ; Next '  ** draw colored dots to show we're alive **
SetColor 255,255,255 ; xx=8 ; DrawSubImageRect img,xx,128-0,128,-8, 0,5*8,128,8 ' also do a stunt and copy a line from itself, to itself to be sure that i can draw to itself, even using itself. 
' Notice the (128-y) and negative height (-8) Itīs needed as there seem to be some Y mirroring going on with the texture. I havnīt checked it this something that must be so
'  or if it is an artifcat how this code is done (canīt remember itīs from this forum somewhere the functions)

IB.UnBindBuffer() 
SetViewport 0,0,1920,1080 ; Cls

' back to drawing to the normal backbuffer now !

' ------------------------------------------- (this is trash unneeded old test code and some sprite and splatting the texture onto the screen

wx=xxxx ; Wy=yyyy ; wx=wx-s*KeyDown(KEY_LEFT)+s*KeyDown(KEY_RIGHT) ; wy=wy-s*KeyDown(KEY_UP)+s*KeyDown(KEY_DOWN) ; wx=Max(0,Min(10000,wx)) ; wy=Max(0,Min(10000,wy))
yyyy=wy ; xxxx=wX

	'display(wx,wy,0,0,1920,1080) '; 	display(wx*2,wy*2,0,0,1920,1080) ; 	display(wx/2,wy/2,0,0,1920,1080) ;	display(wx*4,wy*4,0,0,1920,1080)
	'SetViewport ofx,ofy,sx,sy ' ; Cls
	DrawSubImageRect img, cntx - scrx + ofx, cnty - scry + ofy, tilewidth,tileheight, tilex*8,tiley*8,8,8 
	'DrawSubImageRect img, 0,0,8,8,32,32,8,8

' garbage from my old code	and a moving big sprite build out of 32x32 tiles
	xsprite=xsprite + xd ';  ysprite = 200+Sin(temp2)*128 ; temp2 = temp2 + 2
	If xsprite > ((1920 - (32*16))/4) Then xd = - xd ' how reverse sign
	If xsprite < 0 Then xd=-xd

	char=21 ; For tempy = 0 To 15 ; For tempx = 0 To 15
	sx=xsprite-wx ; sy=ysprite-wy ; char = 65
	DrawSubImageRect img, sx+tempx*32,sy+tempy*32,32,32, (char & 15)*8,(char Sar 4)*8,8,8 ; Next ; Next
	mx=MouseX() ; my = MouseY() ; char = 30
	DrawSubImageRect img, mx-16,my-16,32,32, (char & 15)*8,(char Sar 4)*8,8,8 ' draw this centered mx,my is hotspot
	SetColor 255,255,255
	xxx=(wx+mx) Sar 5 ; yyy=(wy+my) Sar 5 ; If KeyDown(KEY_SPACE) Or MouseDown(1) Then tilemap[xxx+yyy*476]=30
' -------------------------------------------

	DrawImage img,0,0
	Delay 1 ; Flip 1
Wend
End
Type TImageBuffer
	Field Image:TImage
	Field rb:Int[1]
	Field fb:Int[1]
	Field Imageframe:TGLImageframe
	Field Frame:Int = 0
	Field OrigX:Int
	Field OrigY:Int
	Field OrigW:Int
	Field OrigH:Int

	Function SetBuffer:TImageBuffer(Image:TImage,Frame:Int = 0 )
		Local IB:TImageBuffer = New TImageBuffer
		IB.Image = Image ; 	IB.Frame = Frame ; 	IB.GenerateFBO() ; 	IB.BindBuffer()
		Return IB
	End Function
	
	Function Init(Width:Int,Height:Int,Bit:Int=0,Mode:Int=60)
		SetGraphicsDriver(GLMax2DDriver()) ; Graphics Width , Height,bit,Mode ; glewInit()
	End Function
	
	Method GenerateFBO()
		ImageFrame = TGLImageFrame(Image.frame(Frame) )
		imageframe.v0 = imageframe.v1
		imageframe.v1 = 0.0
		Local W:Int = Image.width
		Local H:Int = Image.Height
		AdjustTexSize(W , H) 
		glGenFramebuffersEXT(1, fb )
	    glGenRenderbuffersEXT(1 , rb) 
	    glBindTexture(GL_TEXTURE_2D, Imageframe.name);
	    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT , fb[0]) ; 
	 	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,  Imageframe.name, 0);
	    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rb[0]);
	    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, W, H);
	    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT , GL_DEPTH_ATTACHMENT_EXT , GL_RENDERBUFFER_EXT , rb[0])
	    Local status:Int =  glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)
	   
	    Select status
	       Case GL_FRAMEBUFFER_COMPLETE_EXT 
	          Print "all right" + " : " + Status
	       Case GL_FRAMEBUFFER_UNSUPPORTED_EXT
	          Print "choose different formats"
	       Default
	          End 
	    EndSelect 
   
	End Method
	
	Method BindBuffer()
		GetViewport(OrigX,OrigY,OrigW,OrigH)
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT , fb[0])
		glMatrixMode GL_PROJECTION
		glLoadIdentity
		glOrtho 0,Image.Width,Image.Width,0,-1,1
		glMatrixMode GL_MODELVIEW 
		glViewport(0 , 0 , Image.Width , Image.Height)
		glScissor 0,0, Image.Width , Image.Height
	End Method
	
	Method UnBindBuffer()
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT , 0)
		glMatrixMode GL_PROJECTION
		glLoadIdentity
		glOrtho 0,OrigW ,Origh,0,-1,1
		glMatrixMode GL_MODELVIEW 
		glViewport(0 , 0 , OrigW, OrigH)
		glScissor 0,0, OrigW ,OrigH
	End Method
	
	Method Cls(r#=0.0,g#=0.0,b#=0.0,a#=1.0)
		glClearColor r,g,b,a
		glClear GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT
	End Method
	
	Method BufferWidth:Int()
		Return Image.Width
	End Method
	
	Method BufferHeight:Int()
		Return Image.Height
	End Method

End Type

Function AdjustTexSize( width:Int Var,height:Int Var )
	width=Pow2Size( width ) ; height=Pow2Size( height )
	Repeat
		Local t:Int
		glTexImage2D GL_PROXY_TEXTURE_2D,0,4,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,Null
		glGetTexLevelParameteriv GL_PROXY_TEXTURE_2D,0,GL_TEXTURE_WIDTH,Varptr t
		If t Return
		If width=1 And height=1 RuntimeError "Unable to calculate tex size"
		If width>1 width:/2
		If height>1 height:/2
	Forever
End Function

Function Pow2Size:Int( n:Int )
	Local t:Int=1
	While t<n  ;	t:*2 ;	Wend
	Return t
End Function



dw817(Posted 2015) [#47]
Ah, you're right ! I changed the code a bit to see this.
Graphics 640,480
SetBlend alphablend
SetColor 255,0,0
DrawRect 0,0,32,32
SetColor 0,0,0
DrawRect 1,1,30,30
SetColor 255,255,255
Global img:TImage=CreateImage(32,32)
GrabImage img,0,0
DrawSubImageRect img,64,0,32,32,0,0,8,6
Flip
WaitKey
End


With the hollow rectangle, you can see that it is indeed dithering it to the right scale with correct blur.

Is there a way to do a type of DrawSubImageRect where it writes back to the same or different pixmap or timage, however, Casaber ?

GrabImage so far is definitely showing signs of slowing down the more you use it - which is a shame as for a graphic editor I wrote years ago in BM uses quite a bit f that for image manipulation and alignment.


Casaber(Posted 2015) [#48]
Check the example above I do that there, after the colorfful plotting I paint to the atlas using the atlas. Be careful if you overlap src and dst rectangles or It will be the fun house effect.

I guess you could have a img and a img2 (or any numberof buffers) and ya.. paint between them. reeally fast copying effectivly.

Becuase this is hardware now !! a copy is the same as a GPU draw (a Timage). So it should take zero time. Could you use this to recode your code you think?


This line would copy img perfectly ontop of itself for instance, it could be another buffer equally well.

DrawSubImageRect img,0,128-0,128,-128, 0,0,128,128 ' perfect copy of itself onto itself when used in above context (does effectively nothing, pixelperfect clone onto itself)



Casaber(Posted 2015) [#49]
Could this be related to managing alpha aswell? I hope so.

It might change how you may load and paint on something and then save it with alpha intact in the hardware buffers? I might be wrong. I hope not though.


Bobysait(Posted 2015) [#50]
<edit> Woups ! wrong post ... sorry ^^


dw817(Posted 2015) [#51]
That's quite a bit of code you have up there, Casaber. Do you think you could make it more bite (byte ?) size. If I understand this correctly you are showing an example using DrawSubImageRect to draw on the main screen.

This still leaves the problem of grabimage() slowing things down. Is there a way to get around this ?

BTW, the command, TImageBuffer.Init(1920,1080,32,60), crashes royally on my computer. It is not capable of handling this resolution.


Casaber(Posted 2015) [#52]
Crashes? Maybe you have a 1280,800 resolution? You could use any resolution that your computer likes (you could also skip the 32,60 if you want windowed instead of fullscreen).

It shows more than DrawSubImageRect,m it shows how to get useful buffers for drawing. SETBUFFER, that kind of thing. And those two fits very well together I think.

You can copy and past at amazing speed between several images/buffers. And DrawSubImageRect is just a good example of how
you could use those two in your code to build great templates for your games. This kind of freedom sparks great ideas.


dw817(Posted 2015) [#53]
Alright. We'll bite. Changed the top graphics so it is not hardwired where it crashes:
TImageBuffer.Init(1920,1080)',32,60)

Created a dummy 128x1282 image file:
Global img = LoadImage("128x1282.png",1)

Attempt to BUILD AND RUN reveals:
Unhandled Exception: Attempt to index array element beyond array length
[OKAY]

On this line:
For temp = 0 To 255 ; tilemap[x + y * 476] = temp ; Next



Casaber(Posted 2015) [#54]
I didnīt know BlitzMAX was diferent in how it reacted on bad defined arrays, I have no error but I can imagine there is an error in there but I canīt see it now. Luckily that is just old trash code thatīs not needed for this, so just eliminate every lines that uses tilemap, it will work out great.


dw817(Posted 2015) [#55]
Let me try your program with a resolution that fits my screen. That may fix the problem, Casaber.

Bah, it still crashes. I'll try REMing the TILEMAP code as you suggested.

... .. . Hmm ... I'm REMing way too many lines. Yeah, now it doesn't do anything. Can you send me a .EXE of it so I can see how it looks on your end ?

Please don't use a resolution of 1280,800 though, instead 1024,768 and no hard screen change (which my computer can't do).

So the line would read:
TImageBuffer.Init(1024,768)',32,60)