Drawing on an array

BlitzMax Forums/BlitzMax Programming/Drawing on an array

SpaceAce(Posted 2010) [#1]
I'd like to "draw" onto an int array, storing ARGB information in each cell. The drawing will consist of ovals, squares, irregular polygons made up of lines that may intersect one another. Does anyone know of existing code that can assist with this? I haven't found anything in the archives.

Assuming no such code exists, does anyone know of a good resource for learning how to find all the points that fall inside of an arbitrary oval, polygon, rotated square or rectangle, etc? Will I have to check each cell against the polygon each time, or is there a better way to find all the points that fall inside the polygon?


Naughty Alien(Posted 2010) [#2]
..maybe store additional flag describing each primitive 'area', so just set those flags for specific point based on current primitive location..


SpaceAce(Posted 2010) [#3]
Oh, I should have explained that I want to be able to do cell-by-cell comparisons between arrays. So, I need to actually store each pixel's state, not just coordinates for primitives. Come to think of it, I guess I also need to properly calculate a pixel's color value, taking into account alpha and overlapping shapes. No matter how many programs I write, I seem to be in over my head with every single new project I start.

Edit: Oh, I think I misunderstood you. Yes, I could do that, but I need to explore the math behind plotting which points to color. For instance, which pixels fall inside an 80-pixel by 22-pixel oval rotated 40 degrees and located at x, y.


_JIM(Posted 2010) [#4]
Well, the easy way would be to draw to the backbuffer and do grabpixmap.
The pixmap data is actually ints containing RGBA data (if you create it as PF_RGBA).


SpaceAce(Posted 2010) [#5]
Yeah, but the entire reason for the arrays is to avoid grabbing image data off the buffer.


_JIM(Posted 2010) [#6]
If it's for speed reasons, doing the transformations in software (CPU) could result in probably a slower code than just doing a grab.

In any case,

For scaling/rotations you must look up rotation/transformation matrices. You can get a faster code if you implement a 2D one. I posted a class somewhere in a thread around here a while ago. I'll try to find it later.

For circles: if (dist(px,py,cx,cy) < r) plot px,py
px,py - current point
cx,cy - circle center
r - circle radius

For ovals I can't think of a formula right now, but "point inside oval" on google might help.

For arbitrary polygons you have to write some kind of software rasterizer in order to mimic the behavior of the GPU.

Good luck.


TomToad(Posted 2010) [#7]
Treat the array as a set of pixels. Plotting the x,y would just involve writing the appropriate ARGB values to each index. Look up various polygon algorithms and just substitute any "WritePixel x,y,color" type calls with PixelArray[x,y] = color type assignments.
For example, an axis-aligned box function would look something like this

Function Box(PixelArray[,],x:int,y:int,Width:int,Height:int,Color:int)
    Local PixelArrayWidth:int = PixelArray.Dimensions()[0]
    Local PixelArrayHeight:int = PixelArray.Dimensions()[1]
    For Local PixelX:int = x Until x+Width
        For Local PixelY:int = Y Until Y+Height
            If PixelX < 0 Or PixelY < 0 Or PixelX >= PixelArrayWidth Or PixelY >= PixelArrayHeight Then Continue
            PixelArray[PixelX,PixelY] = Color
        Next
    Next
End Function


Color would, of course, be a packed int like in a pixmap.


ImaginaryHuman(Posted 2010) [#8]
See my code archive entries for drawing filled/unfilled ovals/circles using integer math..... they are drawn one row at a time so you can easily adapt it to draw into an array (or a pixmap, which is the same thing really).

Look for a scanline fill algorithm to do filled polygons.

You'll have a bit more of a struggle implementing rotation, if you plan to do that.


SpaceAce(Posted 2010) [#9]
Thanks for the suggestions. I feel like a knucklehead about the circle, because the answer is so obvious. Instead of checking every cell, I'll just get an upper-left and lower-right bound based on the circle's position and size, and check those cells. That really should have jumped out at me, since I am already doing exactly that when deciding which pixels of the pixmap are "dirty" and need updating.

I do want to implement rotation, and I was worried that might be problematic. I will look into scanline implementations for the arbitrary polygons.

If anyone else has links or information, I'm still interested!


Jesse(Posted 2010) [#10]
why do you want to create an array when you can use a pixmap? A pixmap contains a memory buffer that can be used like an array.

Skidracer was working on a module that can be used for such thing but I don't know how far het got with it.

[edit]
http://www.blitzmax.com/Community/posts.php?topic=87889#997264


SpaceAce(Posted 2010) [#11]
Jesse,
I am working on something that performs drawing operations every loop, and then must do a pixel-by-pixel comparison against another image. It is _not_ necessary for the on-screen representation to be updated every single frame. So, instead of having to draw, flip, capture to pixmap, and compare every single frame, I am looking to store the image data in an array.

Thanks for the link, I will have a look.


Jesse(Posted 2010) [#12]

I am working on something that performs drawing operations every loop, and then must do a pixel-by-pixel comparison against another image.



yes, you can do that to a pixmap by grabbing it of the the image. I'll give you an example


SuperStrict
Graphics 640,480
SetBlend solidblend 
Local image1:TImage = CreateImage(25,25,1)
Local pixmap1:TPixmap = LockImage(image1)
pixmap1.ClearPixels(0)
Local Img1Px:Int Ptr = Int Ptr(pixmap1.pixels)
Local red:Byte = $FF
Local green:Byte = $00
Local blue:Byte = $00
Local alpha:Byte = $FF
Local x:Int = 3
Local y:Int = 4
Local x1:Int = 20
Local y1:Int = 20
Local pos1:Int = (4*image1.width*y)+x
Local pos2:Int = image1.width*y1+x1
' this four instructions put the color in the first byte of the pixmap (3,4) see x & y
pixmap1.pixels[pos1+0] = alpha
pixmap1.pixels[pos1+1] = red
pixmap1.pixels[pos1+2] = green
pixmap1.pixels[pos1+3] = blue

'this one put the complete color in the secont byte of the pixmap (20,20) see x1 & y1
?LittleEndian 'pc's use this 
   img1px[pos2] = (alpha Shl 24) | (blue Shl 16) | (green Shl 8) | red 'this writes the whole 4 Bytes all at onece
?BigEndian 'ppc mac use this
   img1px[pos2] = (red Shl 24) | (green Shl 16) | (blue Shl 8) | alpha 'this writes the whole 4 Bytes all at onece
?
'draw the image with the modified pixels
UnlockImage(image1)
SetClsColor 20,20,20
Cls()
SetScale  16,16
DrawImage image1,100,100
Flip()
WaitKey()

you can treat them just like arrays compare and write as well as read them.
just be careful, in release mode there are no boundaries so if you write outside the pixmap it will more than likely crash the program and might even crash your computer.

[edited]
modified for Little Endian/ Bgi Endian computers.