Strange readpixels behaviour on android

Monkey Targets Forums/Android/Strange readpixels behaviour on android

Sub_Zero(Posted 2013) [#1]
Hi I'm using v75d and readpixels seems to not be returning the right color values.

Try to run this code, what is wrong here?

Import mojo

Class Game Extends App

    Field counter:Int
    
    Method OnCreate()
        SetUpdateRate 60
        Seed = Millisecs()
    End

    Method OnUpdate()
    End

    Method OnRender()
        Cls(255,255,255)
        Local r:Int = Rnd(0,255)
        Local g:Int = Rnd(0,255)
        Local b:Int = Rnd(0,255)
        
        SetColor(r,g,b)
        DrawLine 2,2,40,2
        
        If counter < 1
	        Print "Before: " + r + " " + g + " " + b
	        
	        Local pdata:Int[] = New Int[40 * 2]
	        ReadPixels pdata,2,1,10,1
	        For Local pixel:Int = Eachin pdata
	        	Print "After: " + IntToR(pixel) + " " + IntToG(pixel) + " " + IntToB(pixel)
	        Next
        Endif
        counter += 1
        Return 0
    End Method
    
    Function IntToA:Int( color:Int )
		Return (color Shr 24) & $FF
	End

	Function IntToR:Int( color:Int )
		Return (color Shr 16) & $FF
	End

	Function IntToG:Int( color:Int )
		Return (color Shr 8) & $FF
	End

	Function IntToB:Int( color:Int )
		Return color & $FF
	End
    
End Class

Function Main()
	New Game()
End Function


Output example:
I/[Monkey](14590): Before: 82 128 129
I/[Monkey](14590): After: 82 125 123
I/[Monkey](14590): After: 82 130 132
I/[Monkey](14590): After: 82 125 123
I/[Monkey](14590): After: 82 130 132



ElectricBoogaloo(Posted 2013) [#2]
Different Android devices do it in different ways. Sorry to say, but you can't trust ReadPixels in the slightest. I had previously assumed that, even with a terrible display, dividing everything by 8 would at least give me a nice working set of numbers, but not even that works.
Alphas are stripped away, odd dithering takes place, it's all a shambles.

FWIW, it also happens on Windows. Make a GLFW exe, and set your desktop to 16bit, and you'll see similar issues.
But, again, it's hard to compensate for, because every time it happens, each system seems to "fix" the image in a slightly different way.

Bottom line : Android Fragmentation sucks. Avoid ReadPixels.


Sub_Zero(Posted 2013) [#3]
This is what I ended up with using, which works for me in my situation:

where boxr, boxg and boxb are the r,g,b values of what to expect at the pixel position

and

pixelr, pixelg and pixelb are the r,g,b actual values read by readpixels

If boxr - pixelr < 15 And boxr - pixelr > -15 And boxg - pixelg < 15 And boxg - pixelg > -15 And boxb - pixelb < 15 And boxb - pixelb > -15



ElectricBoogaloo(Posted 2013) [#4]
For future reference...
If Abs(boxr-pixelr)<15
Does both less and greater.. Saves you needing two for everything..

But, no, not even that can be trusted, due to the annoying dithering that some devices do.
Even solid coloured blocks come out as obscure patterns of dots.
I did a LOT of testing with this!!


Gerry Quinn(Posted 2013) [#5]
If you really need this stuff to work on every device out there, even with dithering etc., you could always import your graphics in their own format and process them as arrays in standard RAM using your own basic drawing and blitting functions for any image pre-processing you need to do. Then use CreateImage and WritePixels to generate images for general purposes.


Sub_Zero(Posted 2013) [#6]
Update: I ended up editing mojo, and added a function that turns dithering off.
Dithering on android can be disabled with the following java command:

GLES11.glDisable(GLES11.GL_DITHER);



ElectricBoogaloo(Posted 2013) [#7]
As much as I want to say "OMG! awesome!!!" I wouldn't want to rely on that. If I've learned anything from Android dev, it's this...
Never EVER assume that what you think should happen on one Android device, is what will actually happen on another...

Android Fragmentation is a terrible thing.


Sub_Zero(Posted 2013) [#8]
You're right, also even with dithering disabled, fragmentation causes some invisible artifacts on screen.

Seems ios is better ;)