Dark Bit Factory & Gravity
PROGRAMMING => Other languages => Blitz => Topic started by: Pixel_Outlaw on November 10, 2009
-
I've liked the look of oscilliscopes for some time. I like that they have very sharp lines that seem to bleed light around the edges. I think Zawran's rendering framework would be perfect for the task.
My initial thought was:
1 first create one of his zImageBuffers at a smaller size than the screen resolution.
2 Draw lines to the buffer using a light blend mode so overlaps will be brighter spots
3 draw the zImagebuffer stretched to the screen resolution (causing smooth interpolationand the light bleeding effect would happen here.)
My problem is that I'm not how to implement additive blending mode for the way his engine handles primative shapes.
-
One way of doing it might be:
Make a buffer that you draw to, then when done drawing copy that buffer and do a box blur on it. Then draw the original buffer ontop of the new buffer using mask draw so that the crisp lines gets drawn ontop of the blured version. That could give you the bleeding light around the crisp lines.
Another way might be:
Using the code from the drawAdditiveMasked() method as inspiration to make a new line draw method that allows for additive drawing of pixels. And for each pixel in the line have it draw the fullbright in the center, and half bright to the left and right of it.
I was thinking about revisiting the framework, so I might be taking another look at updating it, and perhaps adding too it.
-
The blur can come from scaling with hardware but the increased intensity at intersections is really what sells the effect.
-
Try and add the following to the framework code:
' add to the color of a pixel in the image buffer
Method setPixelAdditive(x:Int,y:Int,r:Byte,g:Byte,b:Byte,a:Byte=255)
Local pixPtr:Byte Ptr = PixmapPixelPtr(Self.buffer)
If x > -1 And x < Self.width And y > -1 And y < Self.height Then
Local offset:Int = y*Self.pitch+x*Self.bcount
If r + pixPtr[offset] > 255 Then
pixPtr[offset] = 255
Else
pixPtr[offset] :+ r
End If
If g + pixPtr[offset+1] > 255 Then
pixPtr[offset+1] = 255
Else
pixPtr[offset+1] :+ g
End If
If b + pixPtr[offset+2] > 255 Then
pixPtr[offset+2] = 255
Else
pixPtr[offset+2] :+ b
End If
If Self.bcount = 4 Then
If a + pixPtr[offset+3] > 255 Then
pixPtr[offset+3] = 255
Else
pixPtr[offset+3] :+ a
End If
End If
End If
End Method
Then try something like this:
SuperStrict
Framework BRL.GLMax2D
Import BRL.Pixmap
Import BRL.PNGLoader
Import BRL.Random
Import BRL.Retro
SetGraphicsDriver GLMax2DDriver()
Include "E:\zSoftwareRenderFramework\zSoftwareRenderFramework_v05.bmx"
Graphics 640,480
Global timerUpd:Int = MilliSecs()
Global timerFrq:Int = 1000/30 ' 30 fps
Global screenBuffer:zImageBuffer = zImageBuffer.make(640,480)
While Not KeyHit(KEY_ESCAPE)
Cls
screenBuffer.drawToScreen()
Flip
While MilliSecs() < timerUpd+timerFrq
Wend
timerUpd = MilliSecs()
additiveLine(screenBuffer,Rnd(0,320),Rnd(0,240),Rnd(320,640),Rnd(240,480),32,64,32)
Wend
End
Function additiveLine(buf:zImageBuffer,x1:Float,y1:Float,x2:Float,y2:Float,r:Byte,g:Byte,b:Byte,a:Byte=255)
Local r2:Byte = r/2,g2:Byte = g/2,b2:Byte = b/2
Local steps:Float,xI:Float,i:Int
x2 :- x1
y2 :- y1
If Abs(x2) > Abs(y2) Then
steps = Abs(x2)
Else
steps = Abs(y2)
End If
xI = Float(x2 / steps)
y2 = Float(y2 / steps)
For x2 = 0 To steps
buf.setPixelAdditive(Int(x1)-1,Int(y1),r2,g2,b2,a)
buf.setPixelAdditive(Int(x1)+1,Int(y1),r2,g2,b2,a)
buf.setPixelAdditive(Int(x1),Int(y1),r,g,b,a)
buf.setPixelAdditive(Int(x1),Int(y1)-1,r2,g2,b2,a)
buf.setPixelAdditive(Int(x1),Int(y1)+2,r2,g2,b2,a)
x1 :+ xI
y1 :+ y2
Next
End Function
You will have to change the include path to where you have stored the software render framework file.
Is that somewhat like the effect you are after?
-
Honestly dude, I think your framework really adds something that they should have implemented all along. Why not have multiple screen buffers? Good job.
-
One of the things a lot of people have been posting about on the official blitzmax forum is why there isn't more features in the max2d module. One of the problems of adding features is that blitz research wants those features to run the exact same on all three platforms, and sometimes solutions are not that obvious so that a feature can just be added. But I do think that there is room for improvements for sure. And I am fairly certain that I could make a module which had more useful features and that would even be faster than the max2d that comes with the language. The main problem is that I wouldn't really be able to make it work the way most users would want, because whether or not I like it, most of them would want a directX solution for the window side of things, and I just don't know enough about directX to make something like that. I would know how to make everything work using opengl though. And I have previously made a replacement module, basically a sprite module which did more or less everything the max2d module did, but just faster because it was based on single texture rendering and batching of opengl calls. But that was a couple of years back and I have learned a lot more about opengl since, so I would probably be able to make it even more efficient now.
Having multiple screenbuffers are more pratical for retro looking stuff than current tech where everything is done with textures and shaders. But it still have its merits and I can understand why it is dissapointing that its not part of the standard features. The good thing for us is that blitzmax is such an open language to work with, that it is fairly easy to add these features ourselves.
I just had another look at the example code I posted earlier on, and I have done a quick sine wave thingy. You can switch to the lines by tapping on spacebar. I have provided a link to an exe as well if someone without blitzmax wanted to take a peek.
SuperStrict
Framework BRL.GLMax2D
Import BRL.Pixmap
Import BRL.PNGLoader
Import BRL.Random
Import BRL.Retro
SetGraphicsDriver GLMax2DDriver()
Include "E:\zSoftwareRenderFramework\zSoftwareRenderFramework_v05.bmx"
Graphics 640,480
Global timerUpd:Int = MilliSecs()
Global timerFrq:Int = 1000/30 ' 30 fps
Global cnt:Int = 0
Global mode:Int = 1
Global screenBuffer:zImageBuffer = zImageBuffer.make(640,480)
While Not KeyHit(KEY_ESCAPE)
Cls
screenBuffer.drawToScreen()
Flip
While MilliSecs() < timerUpd+timerFrq
Wend
timerUpd = MilliSecs()
Select mode
Case 0
additiveLine(screenBuffer,Rnd(0,320),Rnd(0,240),Rnd(320,640),Rnd(240,480),32,64,32)
Case 1
Local r:Int = Rnd(359)
Local v:Int = Rnd(120)
For Local i:Int = 0 To 639
additivePlot(screenBuffer,i,240+Sin(r)*v,32,64,32)
r :+ 1
Next
End Select
cnt :+ 1
If cnt > 19 Then
cnt = 0
screenBuffer.clear()
If mode = 1 Then
additiveLine(screenBuffer,0,240,639,240,32,64,32)
additiveLine(screenBuffer,320,0,320,479,32,64,32)
For Local i:Int = 0 To 640 Step 32
additiveLine(screenBuffer,i,220,i,260,32,64,32)
Next
End If
End If
If KeyHit(KEY_SPACE) Then mode = 1-mode
Wend
End
Function additivePlot(buf:zImageBuffer,x:Float,y:Float,r:Byte,g:Byte,b:Byte,a:Byte=255)
Local r2:Byte = r/2,g2:Byte = g/2,b2:Byte = b/2
buf.setPixelAdditive(x-1,y,r2,g2,b2,a)
buf.setPixelAdditive(x+1,y,r2,g2,b2,a)
buf.setPixelAdditive(x,y,r,g,b,a)
buf.setPixelAdditive(x,y-1,r2,g2,b2,a)
buf.setPixelAdditive(x,y+1,r2,g2,b2,a)
End Function
Function additiveLine(buf:zImageBuffer,x1:Float,y1:Float,x2:Float,y2:Float,r:Byte,g:Byte,b:Byte,a:Byte=255)
Local r2:Byte = r/2,g2:Byte = g/2,b2:Byte = b/2
Local steps:Float,xI:Float,i:Int
x2 :- x1
y2 :- y1
If Abs(x2) > Abs(y2) Then
steps = Abs(x2)
Else
steps = Abs(y2)
End If
xI = Float(x2 / steps)
y2 = Float(y2 / steps)
For x2 = 0 To steps
buf.setPixelAdditive(Int(x1)-1,Int(y1),r2,g2,b2,a)
buf.setPixelAdditive(Int(x1)+1,Int(y1),r2,g2,b2,a)
buf.setPixelAdditive(Int(x1),Int(y1),r,g,b,a)
buf.setPixelAdditive(Int(x1),Int(y1)-1,r2,g2,b2,a)
buf.setPixelAdditive(Int(x1),Int(y1)+1,r2,g2,b2,a)
x1 :+ xI
y1 :+ y2
Next
End Function
http://zac-interactive.dk/temp/srft.zip (http://zac-interactive.dk/temp/srft.zip)
-
That is really cool. Almost a demo effect in its own right. Have some karma.