Page 1 of 2

Per-pixel plasma / copperbars

Posted: Thu Mar 03, 2011 10:53 pm
by NÖÖB
Branching off my previous topic http://love2d.org/forums/viewtopic.php?f=4&t=2547 about per pixel manipulation speed; after taking into consideration that framebuffers won't work on all computers, I looked into the newImageData function to use that as a sort of buffer.
It's not fast, but at least it seems faster than love.graphics.point.

Please excuse the code, I've only learned the bare minimum of love to create this, if that..

MAIN.LUA

Code: Select all

initScreen = love.graphics.setMode( 800, 600, false, true, 0 )

pixBuf		= love.image.newImageData( 512, 256 ) -- initialize PO2 buffer
pix		= love.graphics.newImage( pixBuf )

pixUpdate	= 0;	pixOffsetX	= 0;	pixOffsetY	= 0
f1		= 0;	f2		= 0;	f3		= 0
av		= 0;	av2		= 0;	av3		= 0
l1		= 0;	l2		= 0;	b1		= 0
pm		= 3.14 / 180

-- ---------------------------------------------------------------------
function love.update( dt )
	pixUpdate = pixUpdate + 1
	if pixUpdate > 1 then -- limit render FPS
		plasma()
		pixUpdate = 0
	end
	love.timer.sleep( 1 )
end

-- ---------------------------------------------------------------------
function love.draw()
	love.graphics.draw( pix, pixOffsetX, pixOffsetY, 0, 2, 2, 0, 0 )
	love.graphics.print("FPS: " .. love.timer.getFPS(), 1, 1 )
end

-- ---------------------------------------------------------------------
function preparePix()
	collectgarbage('collect')
	pixBuf = love.image.newImageData( 512, 256 )
end

-- ---------------------------------------------------------------------
function updatePix( pOX, pOY )
	pixOffsetX = pOX; pixOffsetY = pOY
	pix = love.graphics.newImage( pixBuf )
	pix:setFilter( "nearest", "nearest" )
end

-- ---------------------------------------------------------------------
function plasma()
	preparePix()
	f1 = f1 + 1
	f2 = f2 - 7
	f3 = f3 + 3
	for l1 = 0, 180 do -- plasma size 320 x 180 ( rendered 640 x 360 )
		av = 50 * math.sin(( l1 + f1 ) * pm )
		av2 = 60 + av * math.cos(( f2 + l1 ) * pm )
		av3 = 100 + 10 * math.sin(( f1 + l1 ) / 10 )
		b1 = 100 + 70 * ( math.cos( av2 + l1 )) / 8
		for l2 = 0, 320 do
			r = 140 + av2 * math.sin(( l2 + av2 + l1 ) / av3 )
			pixBuf:setPixel(l2, l1, r, av2, b1, 255 )
		end
	end
	updatePix( 80, 120 )
end
[edit] the plasma code is heavily based on a freebasic plasma a guy name Shockwave @ dbfinteractive.com wrote [/edit]

Re: Per-pixel plasma / copperbars

Posted: Thu Mar 03, 2011 11:30 pm
by RPG
Slow as hell:(

Re: Per-pixel plasma / copperbars

Posted: Thu Mar 03, 2011 11:38 pm
by NÖÖB
Well, yeah..
What FPS were you getting? I get 20FPS on my Acer AS3810t

Re: Per-pixel plasma / copperbars

Posted: Thu Mar 03, 2011 11:41 pm
by EmmanuelOga
AFAICT in your example you only need to initialize the pixBuf once, no need to create it again and again.

Code: Select all

 pixBuf = love.image.newImageData( 512, 256 )
Calling that only once won't give you any noticeable speed up though.

IMHO löve is not very well suited for this kind of old school effect because, as your examples show, its ability to push raw pixels is limited. Not sure if that's because of being opengl based or because doing getpixel/putpixel stuff in lua is inherently slow. It is much faster to draw a thousand triangles that it is to draw a thousand pixels. The modern way of doing that kind of stuff is using shaders, and I'm not sure when (If?) love will support shaders (someone did implement shaders for löve in a fork, but I haven't heard anything about löve authors going to merge that fork).

On a different note, to me, the main utility of framebuffers is not that they are faster (http://pastie.org/1630601), but that fbs allow you to draw the stuff you would normally draw to the screen to a surface, which you then can further manipulate. They are cool for overlay effects (fade outs, crops, etc...). But they are not necessarily faster.

On a last note, is it really common that video cards do not support framebuffers? I thought that was a really old feature of video cards. In my laptop I have a crappy Intel Mobile 4 video card and framebuffers work just fine.

Re: Per-pixel plasma / copperbars

Posted: Thu Mar 03, 2011 11:55 pm
by NÖÖB
Thanks for the heads up on the pixBuf!
I just read on another thread that framebuffers may not work on some computers.. I dunno - I tried your version of the program, and the framebuffer works here on an intel GMA4500 integrated card, although it ran a bit slower than mine; 7FPS vs 20FPS

Re: Per-pixel plasma / copperbars

Posted: Thu Mar 03, 2011 11:59 pm
by TechnoCat
EmmanuelOga wrote:AFAICT in your example you only need to initialize the pixBuf once, no need to create it again and again.

Code: Select all

 pixBuf = love.image.newImageData( 512, 256 )
Calling that only once won't give you any noticeable speed up though.
I actually got bumped from 36fps to 38fps when I made it reuse the ImageData object.

Re: Per-pixel plasma / copperbars

Posted: Fri Mar 04, 2011 12:00 am
by EmmanuelOga
NÖÖB wrote:Thanks for the heads up on the pixBuf!
I just read on another thread that framebuffers may not work on some computers.. I dunno - I tried your version of the program, and the framebuffer works here on an intel GMA4500 integrated card, although it ran a bit slower than mine; 7FPS vs 20FPS
That may be because I changed the frame limiting code. Try using the same love.update function from your example. In the best case, I'm getting around the same fps for both versions (between 27-32).

Re: Per-pixel plasma / copperbars

Posted: Fri Mar 04, 2011 12:06 am
by TechnoCat
I bumped it up to 60fps from 36fps just by putting "local" in places.

Code: Select all

function love.load()
  pixBuf = love.image.newImageData( 512, 256 ) -- initialize PO2 buffer
  pix = love.graphics.newImage( pixBuf )

  pixUpdate = 0
  pixOffsetX = 0
  pixOffsetY = 0
  f1 = 0
  f2 = 0
  f3 = 0
  av = 0
  av2 = 0
  av3 = 0
  l1 = 0
  l2 = 0
  b1 = 0
  pm = 3.14 / 180

  preparePix()
end

-- ---------------------------------------------------------------------
function love.update( dt )
   pixUpdate = pixUpdate + 1
   if pixUpdate > 1 then -- limit render FPS
      plasma()
      pixUpdate = 0
   end
   love.timer.sleep( 1 )
end

-- ---------------------------------------------------------------------
function love.draw()
   love.graphics.draw( pix, pixOffsetX, pixOffsetY, 0, 2, 2, 0, 0 )
   love.graphics.print("FPS: " .. love.timer.getFPS(), 1, 1 )
end

-- ---------------------------------------------------------------------
function preparePix()
   collectgarbage('collect')
   pixBuf = love.image.newImageData( 512, 256 )
end

-- ---------------------------------------------------------------------
function updatePix( pOX, pOY )
   pixOffsetX = pOX; pixOffsetY = pOY
   pix = love.graphics.newImage( pixBuf )
   pix:setFilter( "nearest", "nearest" )
end

-- ---------------------------------------------------------------------
function plasma()
  f1 = f1 + 1
  f2 = f2 - 7
  f3 = f3 + 3
  local sin = math.sin
  local cos = math.cos
  for l1 = 0, 180 do -- plasma size 320 x 180 ( rendered 640 x 360 )
    local av = 50 * sin(( l1 + f1 ) * pm )
    local av2 = 60 + av * cos(( f2 + l1 ) * pm )
    local av3 = 100 + 10 * sin(( f1 + l1 ) / 10 )
    local b1 = 100 + 70 * ( cos( av2 + l1 )) / 8
    for l2 = 0, 320 do
       local r = 140 + av2 * sin(( l2 + av2 + l1 ) / av3 )
       pixBuf:setPixel(l2, l1, r, av2, b1, 255 )
    end
  end
  updatePix( 80, 120 )
end

Re: Per-pixel plasma / copperbars

Posted: Fri Mar 04, 2011 12:08 am
by NÖÖB
EmmanuelOga wrote:That may be because I changed the frame limiting code. Try using the same love.update function from your example. In the best case, I'm getting around the same fps for both versions (between 27-32).
Yeah, that did it; getting 14FPS on your version now :)

@Technocat: woah! :awesome: You need the preparePix call in the plasma function, though.. if not, your ram gets eaten

Re: Per-pixel plasma / copperbars

Posted: Fri Mar 04, 2011 12:14 am
by RPG
20-25 fps on nvidia GF6200. May be much better.