Draw to Image?

Monkey Forums/Monkey Programming/Draw to Image?

nullterm(Posted 2014) [#1]
After a long hiatus from playing with BlitzMax/Plus, I've discovered Monkey and am loving it. Had a prototype on Win/Mac/iOS/Droid in no time, soon my OUYA too.

One question, is there a way to draw to an Image? Like the ability in OpenGL ES 2.0 to render to texture.

I'd like to do all the draw commands to a low res Image (say 320x320, 256x256, or even 32x32 or 64x64) to draw the scene, but then use that to DrawImage so all the sprite pixels are all lined up even on higher res displays like desktop or iPad. Or rotate/skew that image.

Looking at using Monkey for some hobby projects for stuff like jams with low res pixel art.


Steve Ancell(Posted 2014) [#2]
You may want to look at WritePixels for that, it's not a simple setbuffer/drawimage thing.


nullterm(Posted 2014) [#3]
Thanks.

Wonder if anyone has tried an alternative...
* draw to the upper left 64x64 pixels of the screen buffer
* grab pixels with ReadPixels
* put into Image with Image.WritePixels
* DrawImage back scaled at 10x or whatever scale

So I get the scaling low pixel effect, but still have the usual draw functions.

Just wondering if ReadPixels/WritePixels would have a performance hit?


Steve Ancell(Posted 2014) [#4]
I don't like to use ReadPixels in monkey, it seems to only copy pixels from the render screen rather than allowing to copy directly from a loaded image. I thought that it would have been possible to access pixel data as if it was an array seeing that images can be written from an array, but in this case we cannot have our cake and eat it. Being able to read pixels from an image buffer would make pixel-perfect collision so much easier.

If you're going to use WritePixels or ReadPixels you really should apply it to your needs in a pre-calculated fashion, I would expect a slowdown if done in realtime.


Steve Ancell(Posted 2014) [#5]
I also discovered that anything copied by ReadPixels has to be in view, nothing outside the viewable area seems to be copied.


Steve Ancell(Posted 2014) [#6]
I did have an idea of a workaround by using GrabImage to get bits of the image pixel by pixel, but then I'm quite sure you can't get pixel data in this way either.


Steve Ancell(Posted 2014) [#7]
Then again I think GrabImage could be used to do it from a different approach. Use GrabImage to get one pixel from an image buffer then draw that to the top of the viewable area, mask off that area, so the game player don't see it, then use ReadPixels to get that data into the array. Repeat the same method for the rest of the pixels.

P.S: You really don't want to use that method in realtime either.


skid(Posted 2014) [#8]
nullterm, the answer I suggest is no.

mojo is best suited to working with loaded imagery and it is best you consider generating media further up the toolchain.I typically keep blitzmax programs that generate images and sound in the project.data folder and run them when mods are needed.

If you do want to generate images simply set viewport to sprite size which can't be bigger than the display size draw your sprite montage to the display with a white background then do the same with a black background. This allows you to build a full32 bit argb image.

The trick to optimising writepixels I think is never use it with an image that is being drawn in current or next render frame, ie best to do during "Loading Level..." state.

I use this overly complicated function which uses some of these techniques to colorise a font bitmap that is typically bigger than the display. There may still be issues as it is not clear to me if pixels in monkey use pre-multiplied alpha format.


Steve Ancell(Posted 2014) [#9]
The same goes for manipulating pixels in Blitz. I agree with skid here, never manipulate pixels on the fly if speed is critical.


DruggedBunny(Posted 2014) [#10]
Would AutoFit with #MOJO_IMAGE_FILTERING_ENABLED=False do the trick?

Here's an example set up for GLFW, where I wanted to recreate the VFD display of a coffee machine at work (looks cool if you set up an alpha scanline filter image on top!):

http://www.hi-toro.com/monkey/vfd.zip

Notes: Set actual display size in main file (vfd.monkey) via #GLFW_WINDOW_WIDTH and #GLFW_WINDOW_HEIGHT, and the low-res virtual display size in imports/game.monkey -> OnCreate -> SetVirtualDisplay resx, resy

I'm sure with a bit of work it could be set up to force images to the nearest x/y pixel of the simulated display too, for completeness...


itto(Posted 2014) [#11]
@skid That's interesting, could you please elaborate on the white/black background trick? I suppose you then see the difference in color for each pixel comparing the two drawings against the original, but how do you calculate each pixel exactly?


skid(Posted 2014) [#12]
@itto, to get the alpha channel, i currently

1. draw the scene in black on white and map r->255-a
2. draw the scene in normal colour on black and map rgb->rgb

use two arrays to store the results so the pixel calculation and writing to image can be done in separate steps (when dealing with large quantities of anything its best to keep the loops tight and remove any calls to external modules like mojo)


Nobuyuki(Posted 2014) [#13]
if you're not afraid of limiting your target options to OpenGL supporting targets, try this: https://github.com/nobuyukinyuu/nDrawExts2


nullterm(Posted 2014) [#14]
That's interesting, thanks Nobu!

So when using mojo, you can also call GL functions directly to extend the core mojo.graphics?

Wondering if I can bend things around and use GLES2 draw to texture to achieve the desired effect.


ImmutableOctet(SKNG)(Posted 2014) [#15]
Didn't realize this thread was a thing.

@nullterm: Yes, you technically can. External code may be required, however. SKN3 made a module a while ago which allows you to use FBOs with Mojo's 'Image' class via its 'surface' field. The only problem is, you'll have to add a method to Mojo's 'Image' class to delegate this field.

Here's SKN3's module for this; 'skn3.imagebuffer'. That module still works for me. The shader functionality has some weird inconsistency problems when converting strings, but the FBO functionality works just fine. That module is only for the GLFW targets, however. It could probably be ported to other targets. In fact, the mainly problematic and/or target-specific code has to do with the shader functionality.

But if scaling, rotating, and overall virtual screen functionality is what you want, just use 'autofit' (Though, I'd recommend my refactored version). As far as device rotation goes, the resolution will simply change in Mojo when the orientation changes. It's as simple as that. From there, if you're using 'autofit', it'll handle the virtual display based on the settings you give it. There's also some more advanced stuff you can do with regard to resolution-based scaling, but that's a different topic.


nullterm(Posted 2015) [#16]
I sorted out one approach using GLES20 frame/renderbuffers. Works on both GLFW3 and HTML5, haven't tried anything else yet.



Basically I create a render to texture, then draw the screen to that buffer. Then finally draw that buffer (as a texture) to the default render/framebuffer.

This creates the render to texture...



Then to setup for drawing in the render texture...



Then when finished...



I tried using some mojo.graphics, but SetColor died trying to access "renderDevice" which I'm guessing is Null. Which is fine, I can achieve everything I wanted with GLES20 directly.


nullterm(Posted 2015) [#17]
That all said, somewhere in their something is restricting the buffer/texture dimensions to be min(w,h) x min(w,h). So even if I'm requesting 128x32, it still comes out as 32x32. Will investigate.


Taron(Posted 2015) [#18]
That FBO stuff is exactly what I'm looking into right now, too. Just as I got used to Framebuffer juggling with BlitzMax, Monkey X turns it on its head somehow. Sure, openGL ES is a big part of the challenge for me right now, too. Boy, oh, boy, it ain't easy to wrap my head around two new things at once...
However, I'm pretty impressed with monkey already. If I figure out how to deal with the FBOs, I'll certainly try to make a "Verve" (my little fluid dynamics based painter) version for WebGL with Monkey x! :o)

Thanks for getting this research started here! ;o)
As soon as I'll figure out more, I'll post it, too.


Taron(Posted 2015) [#19]
Another big trouble for me is that there ain't no 16bit (GL_RGBA16F) or 32 bit formats supported in monkey's GL implementation. I suppose they could get hacked into it, but that only inspires to consider writing directly in js instead. OpenGL ES 3.0 supports both formats, while 32 bit "cannot be filtered", sadly.
Yes, yes, this may go beyond what "games" ordinarily ask for, but why cut monkey short, if it can reach contemporary standards?!

Anyway...I'll keep investigating. I hope I can find enough to begin promoting this promising language with some fun monkey apps! 8)