gfxgfxFreeBASIC Games Directory Forumgfxgfx
gfx gfx
gfx
Welcome, Guest. Please login or register. May 25, 2013, 07:30:13 AM

Login with username, password and session length
11.5.2013 - Added a webpage for the latest FBGD competition.

13.3.2013 - Members registrations temporary disabled. For all membership requests, please email me: lachie13@yahoo.com

30.11.2012 - The ninth issue of BASIC Gaming is out! Read it here: http://games.freebasic.net/forum/index.php?topic=560.0

22.11.2012 - Be sure to check our currently running annual FBGD game making competition. This year's theme is SEASONS OF THE YEAR, 300 $ first place prize, and the competition runs till 18th of February. Link: http://games.freebasic.net/forum/index.php?topic=559.0
gfx
gfx
*
gfxgfx
gfxgfx gfxgfx
gfxgfx Home Help Search Login Register   gfxgfx
gfx gfx
gfx
Pages: [1] 2 3
Print
Author Topic: Efficient pixel drawing?  (Read 2440 times)
Brick Break
Forum Sage
*****
Gender: Male
Posts: 412



View Profile
« on: July 09, 2010, 08:06:13 PM »

Quote
while Pset and the opposite Point provide valid results, they are very slow. Much better performance can be achieved by using Poke after calculating the address yourself from values obtained from Imageinfo and Screeninfo, or even more usig inline ASM.



You guys have to help me. I don't know what I'm going to do.
Logged

Lachie Dazdarian
Double dipper
Administrator
Forum Sage
*****
Gender: Male
Posts: 1195


lachie13
View Profile WWW Email
« Reply #1 on: July 10, 2010, 11:22:18 AM »

Where did you get that information from? I think you are worrying too much with irrelevant (or outdated) advices. If you will use FB built-in GFX library then storing your gfx in memory and pasting it with PUT is more than fine. If you want to use hardware accelerated libraries like OpenGL or HGE then you don't care about these issues.
Logged

"Things like Basic and Free Basic provide much-needed therapy and a return to sanity and a correct appreciation of people. The arrogant folk really hate a word like 'Basic' - fine, and good riddance." ~ pragmatist
Brick Break
Forum Sage
*****
Gender: Male
Posts: 412



View Profile
« Reply #2 on: July 10, 2010, 03:46:38 PM »

I got it from the Wiki. I sure hope it isn't accurate.

Here's my problem: I'm trying to work out textured, software-rendered 3D. We're not talking raycasting here, full triangle texture mapping with texture filtering. To do that, I need an efficient way to draw to the screen, be it per line or per pixel. If I could just use the FB built-in functions, that would be great, but it sounds like calling PSET a few hundred times would slow it down.
Logged

Brick Break
Forum Sage
*****
Gender: Male
Posts: 412



View Profile
« Reply #3 on: July 10, 2010, 11:59:16 PM »

Oh, wonderful. I found something else:
Quote
The background screen updating eats a considerable amount of CPU performance.


 Cry
Logged

KristopherWindsor
Forum Sage
*****
Gender: Male
Posts: 363


The Thirsty Smiley


View Profile WWW Email
« Reply #4 on: July 14, 2010, 12:58:11 AM »

Pset is slow. If you try to use Pset on every pixel in the window, it will be way slower than using a single Put, but if you use point manipulation, you can manipulate every pixel almost as fast as Put. Here's some full-screen effects I made, with ASM from Mysoft:
Sub xfx_graphic_type.effect_grayscale ()
  #ifndef server_validator
 
  Static As Ulongint MAXALPHA = &hFF000000FF000000ull
  Static As Ulongint MAXCOMP =  &h000000FF000000FFull
 
  Dim As Uinteger c, pt, weight
  Dim As Uinteger Ptr dataptr
 
  dataptr = Screenptr()
  pt = screen.screen_sx * screen.screen_sy
  Asm
    mov edi,[dataptr]       'buffer ptr
    mov ecx,[pt]            'pixel counter
    Shr ecx,1
    movq mm6,[MAXCOMP]
    movq mm7,[MAXALPHA]
    _xgtem_next_pixelm2_:   'go next pixel
    movq mm0,[edi]           'load org pixel
    movq mm1,mm0             'add get blue
    pand mm1,mm6            '
    psrld mm0,8             '\
    movq mm2,mm0            'add green
    pand mm2,mm6            '
    paddd mm1,mm2           '/
    psrld mm1,1             'bg average
    psrld mm0,8             '\
    pand mm0,mm6            'add blue
    paddd mm1,mm0           '
    psrld mm1,1               'bg average (BW/METAL)
    movq mm0,mm1            ' \
    pslld mm1,8             ' |
    paddd mm0,mm1           ' |
    pslld mm1,8             ' |
    paddd mm0,mm1           ' |
    por mm0, mm7            ' /
    movq [edi],mm0          ' \
    add edi,8               ' |
    dec ecx                 ' / save pixel
    jnz _xgtem_next_pixelm2_
    emms
  End Asm
'  For i As Integer = 1 To pt
'    c = *dataptr
'    weight = ((c And &HFF) + ((c And &HFF00) Shr 8) + ((c And &HFF0000) Shr 16)) \ 3
'    *dataptr = &H010101 * weight
'    dataptr += 1
'  Next i
  #Endif
End Sub

Sub xfx_graphic_type.effect_inverse ()
  #ifndef server_validator
 
  Dim As Uinteger c, pt, weight
  Dim As Uinteger Ptr dataptr
 
  dataptr = Screenptr()
  pt = screen.screen_sx * screen.screen_sy
  For i As Integer = 1 To pt
    *dataptr Xor= &HFFFFFF
    dataptr += 1
  Next i
  #Endif
End Sub

Sub xfx_graphic_type.effect_metal ()
  #ifndef server_validator
 
  Static As Ulongint MAXALPHA = &hFF000000FF000000ull
  Static As Ulongint MAXCOMP =  &h000000FF000000FF
 
  Dim As Uinteger c, pt, weight
  Dim As Uinteger Ptr dataptr
 
  dataptr = Screenptr()
  pt = screen.screen_sx * screen.screen_sy
  Asm
    mov edi,[dataptr]       'buffer ptr
    mov ecx,[pt]            'pixel counter
    Shr ecx,1
    movq mm6,[MAXCOMP]
    movq mm7,[MAXALPHA]
    _xgtem_next_pixelm_:   'go next pixel
    movq mm0,[edi]           'load org pixel
    movq mm1,mm0             'add get blue
    pand mm1,mm6            '
    psrld mm0,8             '\
    movq mm2,mm0            'add green
    pand mm2,mm6            '
    paddd mm1,mm2           '/
    psrld mm1,1             'bg average
    psrld mm0,8             '\
    pand mm0,mm6            'add blue
    paddd mm1,mm0           '
    'psrld mm1,1               'bg average (BW/METAL)
    movq mm0,mm1            ' \
    pslld mm1,8             ' |
    paddd mm0,mm1           ' |
    pslld mm1,8             ' |
    paddd mm0,mm1           ' |
    por mm0, mm7            ' /
    movq [edi],mm0          ' \
    add edi,8               ' |
    dec ecx                 ' / save pixel
    jnz _xgtem_next_pixelm_
    emms
  End Asm
'  For i As Integer = 1 To pt
'    c = *dataptr
'    weight = ((c And &HFF) + ((c And &HFF00) Shr 8) + ((c And &HFF0000) Shr 16)) \ 3
'    *dataptr = &H020202 * weight
'    dataptr += 1
'  Next i
  #Endif
End Sub

'Function palettecolor (Byval c As Integer) As Uinteger
'  Const pmax = 16

'  Static As Uinteger pc(1 To pmax) = {&HFF000000, &HFF0000AA, &HFF00AA00, &HFF00AAAA, _
'    &HFFAA0000, &HFFAA00AA, &HFFAA5500, &HFFAAAAAA, &HFF555555, &HFF5555FF, _
'    &HFF55FF55, &HFF55FFFF, &HFFFF5555, &HFFFF55FF, &HFFFFFF55, &HFFFFFFFF}, pc_one
'  Static As Uinteger diff(1 To pmax)
'  Dim As Uinteger diff_closest = 1, diff_amount = 768

'  For i As Integer = 1 To pmax
'    pc_one = pc(i)
'    diff(i) = _
'      Abs(((pc_one Shr 16) And &HFF) - ((c Shr 16) And &HFF)) + _
'      Abs(((pc_one Shr 8) And &HFF) - ((c Shr 8) And &HFF)) + _
'      Abs((pc_one And &HFF) - (c And &HFF))
'  Next i

'  For i As Integer = 1 To pmax
'    If diff(i) < diff_amount Then
'      diff_amount = diff(i)
'      diff_closest = i
'    End If
'  Next i

'  Return pc(diff_closest)
'End Function

Sub xfx_graphic_type.effect_pixelation ()
  #ifndef server_validator
  Dim As Integer mx, my, p
  Dim As Uinteger c, cr, cg, cb, ix, iy, x, y
  Dim As Uinteger Ptr s = Screenptr, s2
 
  Screeninfo(mx, my,,, p)
  p Shr= 2
 
  For x = 0 To mx - 8 Step 8
    For y = 0 To my - 8 Step 8
      cr = 0
      cg = 0
      cb = 0
     
      s2 = s + y * p
      For iy = 0 To 7
        For ix = x To x + 7
          c = *(s2 + ix)
          cr += (c Shr 16) And &HFF
          cg += (c Shr 8) And &HFF
          cb += c And &HFF
        Next ix
        s2 += p
      Next iy
     
      cr Shr= 6
      cg Shr= 6
      cb Shr= 6
      c = Rgb(cr, cg, cb)
      'c = palettecolor(c)
     
      s2 = s + y * p
      For iy = 0 To 7
        For ix = x To x + 7
          *(s2 + ix) = c
        Next ix
        s2 += p
      Next iy
    Next y
  Next x
  #Endif
End Sub
Logged

Brick Break
Forum Sage
*****
Gender: Male
Posts: 412



View Profile
« Reply #5 on: July 14, 2010, 12:25:40 PM »

I don't want to use ASM, because it's not universal. The help guide mentioned "using Poke after calculating the address yourself from values obtained from Imageinfo and Screeninfo". How would I do that?
Logged

Brick Break
Forum Sage
*****
Gender: Male
Posts: 412



View Profile
« Reply #6 on: July 15, 2010, 10:00:38 AM »

Bump. I really need help with this. If anyone could give me an example using poke, that would be great.
Logged

Mitchell
Forum Howler
****
Gender: Male
Posts: 172


Rockin Geek


View Profile Email
« Reply #7 on: July 15, 2010, 08:01:58 PM »

Bump. I really need help with this. If anyone could give me an example using poke, that would be great.

Alright, I'll boot up FB and figure it out how to poke right. Do NOT use any ASM code to make a program.
Logged

Never underestimate the destructive powers of somebody doing something new without having any clue of how to do it. Tongue
Brick Break
Forum Sage
*****
Gender: Male
Posts: 412



View Profile
« Reply #8 on: July 15, 2010, 08:09:06 PM »

Bump. I really need help with this. If anyone could give me an example using poke, that would be great.

Alright, I'll boot up FB and figure it out how to poke right. Do NOT use any ASM code to make a program.
Thank you very much. I'll be waiting.
Logged

Mitchell
Forum Howler
****
Gender: Male
Posts: 172


Rockin Geek


View Profile Email
« Reply #9 on: July 15, 2010, 08:43:02 PM »

Alright, here it is (it compiles for me):

' Screen resolution parameters
const as integer screenWidth = 640
const as integer screenHeight = 480

screenres screenWidth, screenHeight, 32

' Draws a pixel by manipulating graphics buffer
declare sub drawPixel(x as integer, y as integer, c as uinteger)

' Coordinates for the top left corner of the x to be drawn
const as integer imageXOffset = 100
const as integer imageYOffset = 100

' Draw an x to the screen
for x as integer = 0 to 100
' y value of one arm of the x
dim as integer y1 = x

' y value of the other arm of the x
dim as integer y2 = 100 - x

/' Call the pixel subroutine so we can draw at this
coordinate '/
drawPixel(x + imageXOffset, y1 + imageYOffset, rgb(255, 255, 255))
drawPixel(x + imageXOffset, y2 + imageYOffset, rgb(255, 255, 255))
next x

sleep
end

'----------------- End of Execution ------------------------

/''
 ' Parameters:
 ' integer x: x coordinate of pixel
 ' integer y: y coordinate of pixel
 ' uinteger c: new color of pixel
 '/
sub drawPixel(x as integer, y as integer, c as uinteger)
/' Note: this is the quick and dirty way to get the address
of the pixel. I hard coded in 4 since I'm using
32 bit (32 bit = 4 bytes) screen. This is definitely
not the proper way to do it. '/
dim as ubyte ptr pPixel = screenPtr + 4*(x + screenWidth*y)

/' Cast the above to a uninteger ptr since we're working
with 32 bit color '/
dim as uinteger ptr puiPixel = cptr(uinteger ptr, pPixel)

' Draw to the pixel by setting it's value directly
*puiPixel = c
end sub

It's dirty, but it gets the job done. The code that does the 'poking' is the subroutine drawPixel. Ugly as hell pointers, and I don't know how much overhead it takes for each screenPtr() call (I probably should have called it once, then stored it to a variable somewhere), but it's pretty direct.
Logged

Never underestimate the destructive powers of somebody doing something new without having any clue of how to do it. Tongue
Brick Break
Forum Sage
*****
Gender: Male
Posts: 412



View Profile
« Reply #10 on: July 15, 2010, 11:26:28 PM »

Oh my god it worked instantly! I love you and I will love you forever. Smiley Smiley Smiley Smiley Smiley Smiley Smiley Smiley
Logged

Brick Break
Forum Sage
*****
Gender: Male
Posts: 412



View Profile
« Reply #11 on: July 15, 2010, 11:51:00 PM »

Oh, man, reading through your code a second time, that's really advanced stuff.

Would it be just as fast using the actual poke command? And what of this cptr? So many questions.

The entire drawPixel function's hard. I take it the asterisk denotes actually updating the memory location with a pointer? That is where poke would come in, right?

The color seems pretty straightforward. I'm glad it's that simple. However, how do you get the memory address of the pixel? Does dim slow the program any more than reassigning the variable? Do you not like your code because the "4" restricts it to 32-bit? Is it all per-byte operations then? What is a byte? Is a pixel a byte?

Probably my biggest confusion is with "screenPtr". Is that the screenptr() function? I'm so confused with all of this. Could you see if you could modify it to use the actual poke statement and explain the math operations? I'm sorry, it's just really hard for me to understand. In the mean time, I'll work on it, see what I can understand.

Thanks. Smiley
Logged

Brick Break
Forum Sage
*****
Gender: Male
Posts: 412



View Profile
« Reply #12 on: July 16, 2010, 12:20:33 AM »

Oh, and another thing. What about page flipping? Do you fill an array? Then how do you push the array onto the screen? I would think a for-next loop would be slow.
Logged

Mitchell
Forum Howler
****
Gender: Male
Posts: 172


Rockin Geek


View Profile Email
« Reply #13 on: July 16, 2010, 11:49:41 AM »

From what I know of poke, the only difference is that this line:
' Draw to the pixel by setting it's value directly
*puiPixel = c

becomes

' Draw to the pixel by setting it's value directly
poke(uinteger, puiPixel, c)

AFAIK, there's no performance difference, though I don't know if poke has extra overhead since it's a subroutine. Otherwise, under the hood, they are identical except poke does an extra cast each time its called, which I already did with making puiPixel.

(Note: I haven't tested poke to see if it works. I just looked at the manual).

And if you're worried about the performance hit from declaring the variables each time the subroutine is called, you can use:
dim static pPixel as ubyte ptr

That creates the variable only once. However, since it doesn't delete the variable, it keeps its old value if you call the function again. In this case, that's not a problem.

And as I said, it's rough and dirty code. I probably could have taken out a line somewhere in drawPixel() if I changed the way I handled casting.

I'll get to explaining how it all works in the next post.
Logged

Never underestimate the destructive powers of somebody doing something new without having any clue of how to do it. Tongue
Brick Break
Forum Sage
*****
Gender: Male
Posts: 412



View Profile
« Reply #14 on: July 16, 2010, 12:21:42 PM »

I'm having a hell of a time just trying to put screenptr in a variable.
Logged

Pages: [1] 2 3
Print
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines
Cerberus design by Bloc
Valid XHTML 1.0! Valid CSS!
gfx
gfxgfx gfxgfx