Simple per pixel lighting system

BlitzMax Forums/BlitzMax Programming/Simple per pixel lighting system

altitudems(Posted 2005) [#1]
I thought I would post the source to the lighting system I've been working on. I'm sure it could be improved upon.
Basicly how it work is this:

* Create an image which is 1/32 the size of the screen
* Set blend to LightBlend
* Draw all your lights on it(could be images, shapes, whatever)
* Grab the lights image
* Cls
* Draw all your other stuff
* Set blend to ShadeBlend
* Draw the scaled up version of the lights image

Here is the system:


And here is an example:
Strict

SetGraphicsDriver GLMax2DDriver()
Graphics 640, 480,0

Import "light.bmx"

AmbientLight = [200,200,200]
TLight.InitBuffer
TLight.DefaultImage = LoadImage("light.png")
MidHandleImage TLight.DefaultImage

Local Light1:TLight = TLight.Create(MouseX(),MouseY(),[255,255,255],1,4,4)

While Not KeyHit (KEY_ESCAPE)

	Light1.X = MouseX()
	Light1.Y = MouseY()

	TLight.UpdateBuffer

	Cls

	'Render your other stuff here
		
	TLight.RenderBuffer

	Flip
	FlushMem
Wend

Screenshot:



TartanTangerine (was Indiepath)(Posted 2005) [#2]
heh, clever.


altitudems(Posted 2005) [#3]
Thanks. Like I said it is very simple. I only wish GrabImage wasn't so slow. But that will be the case until GPU hardware changes.


TartanTangerine (was Indiepath)(Posted 2005) [#4]
Yeah, render to texture would be nice to have.


fredborg(Posted 2005) [#5]
You can use the AccumBuffer instead of grabbing images, I did that for a project, and it worked very well.

(AccumBuffer is only present in OpenGL as far as I know)


tonyg(Posted 2005) [#6]
Very nice.
Is the bufferscale to maintain a decent fps?
It seems quite possible to add a changestatus and deletelight function to turn off or permanently destroy a light.
How would defining a light as static or dynamic help framerate. If there are no dynamic lights and the screen hasn't scrolled then you wouldn't have to call updatebuffer.
Lots of possibilities as well as using the lightbuffer to add shadows.


altitudems(Posted 2005) [#7]
@fredborg
I will look into the AccumBuffer buffer some more. It does sound like it would be much faster. But then we would have to resort to using opengl outside of max2d and eliminating any use of DX. I'm not sure if that is the best. But I think I will create a version which uses the accumilation buffer anyway.

@tonyg
Yes, I scale the buffer to achieve better framerates, but also to use less video ram. GrabImage/Pixmap is extremly slow.
Light states are very easily added, I just forgot to do so for this upload. I did a test where the image buffer was only updated when a light actualy moved. While the buffer stayed the same the frame rate was near 1000fps when a light moved it dropped very quickly to ~200fps.


Robert Cummings(Posted 2005) [#8]
Given it's 3D I would have looked into ver colours first before this.

And beyond that, looked into modulate2X as you would only need to draw the lights on top then as sprites.

for instance, there is nothing stopping you in both DX and opengl, from overlaying a nice subdivided mesh and changing the vert cols. This way, although there is upload to the card, it is minimal and possibly faster.


xlsior(Posted 2005) [#9]
All I get when I run the code above is a blank screen in a single shade of color?

Anything special about the light.png file?


tonyg(Posted 2005) [#10]
Try using the light.png from
"C:\Program
file\BlitzMax\samples\birdie\misc\lightImage\media\light.png"
and changing the X/Y scale to 1.
It also shows better if you load a background image or use another image with tileimage.


xlsior(Posted 2005) [#11]
Got it to work now -- nice!

also looks good if you chance the ambient light variable to something like [125,125,255], to give a blueish hue to the 'dark' parts, and have more of a night-time look to it.


tonyg(Posted 2005) [#12]
Simple turnon, turnoff, switchstatus and destroy...
Strict
Global LightList:TList = New TList
Global AmbientLight:Int[3]

Type TLight
	Global BufferScale:Int = 8
	Global BufferImage:TImage = Null
	Global DefaultImage:TImage = Null
	
	Field Image:TImage
	Field X:Float
	Field Y:Float
	Field Color:Int[3]
	Field ScaleX:Float
	Field ScaleY:Float
	Field Alpha:Float
	Field status:Int
	
	Function Create:TLight (_X:Float, _Y:Float, _Color:Int[],_Alpha:Float = 1.0,_ScaleX:Float = 1.0,_ScaleY:Float = 1,_Image:TImage = Null,_status=1)
		Local Light:TLight = New TLight
		Light.X = _X
		Light.Y = _Y
		Light.Color = _Color
		Light.ScaleX = _ScaleX
		Light.ScaleY = _ScaleY
		Light.Alpha = _Alpha
		Light.Image = _Image
		Light.status = _status
		If Not Light.Image
			If Not DefaultImage
				Return Null
			Else
				Light.Image = DefaultImage
			End If
		End If
		LightList.AddLast(Light)
		Return Light
	End Function
	
	Function InitBuffer()
		 BufferImage = CreateImage(GraphicsWidth()/BufferScale, GraphicsHeight()/BufferScale)
		 SetImageHandle BufferImage, 0,0
	End Function
	
	Function UpdateBuffer()
		SetClsColor AmbientLight[0],AmbientLight[1],AmbientLight[2]
		Cls
		Local _Blend:Int = GetBlend()
		SetBlend LightBlend
		For Local Light:TLight = EachIn LightList
		  If light.status=1
			SetAlpha Light.Alpha
			SetColor Light.Color[0],Light.Color[1],Light.Color[2]
			SetScale Light.ScaleX/BufferScale, Light.ScaleY/BufferScale
			DrawImage Light.Image,Light.X/BufferScale, Light.Y/BufferScale
	      EndIf
		Next
		GrabImage(TLight.BufferImage,0,0)
		SetBlend _Blend
		SetColor 255,255,255
		SetScale 1,1
	End Function
	
	Function RenderBuffer()
		Local _Blend:Int = GetBlend()
		Local _SX:Float,_SY:Float
		GetScale _SX, _SY
		SetBlend shadeBlend
		SetScale TLight.BufferScale,TLight.BufferScale
		DrawImage TLight.BufferImage,0,0
		SetBlend _Blend
		SetScale _SX,_SY
	End Function
	
	Function lighton(Light:TLight)
		light.status=1
    End Function   

	Function lightoff(Light:TLight)
		light.status=-1
    End Function 
   
	Function switchstatus(Light:TLight)
		light.status=-light.status
    End Function    

   Function destroylight(Light:TLight)
      ListRemove lightlist,Light
   End Function
 
End Type



altitudems(Posted 2005) [#13]
Thanks tonyg.

@Fish
Per vertex is cool and all, but much harder to impliment. I like to take things easy :). Maybe some day I will make a per vert system.


Jeroen(Posted 2005) [#14]
altidumens, nice screenshot, love the artwork


SillyPutty(Posted 2005) [#15]
awsome, looks like you can use it for the "fog of war" effect too.


tonyg(Posted 2005) [#16]
Altitudems, what plans have you got to develop this?


altitudems(Posted 2005) [#17]
@Jeroen
The artwork is not mine its from Zelda 3: A link to the past
But I'll take the credit, sure :)

@tonyg
My plan is to get a good amount of source code and graphics ready for a community project. The project should a tile-based game engine. My hope is that beginners will be able to learn how to program games from it. It will sort of be a framework to create games off of. Here are some things I had in mind:

* Console System - Will provide debugging and other
functionality. Variables can be viewed and changed,
commands can be issued, etc.

* Vector Math - Library with easy helper functions
(Finding angles, etc)

* Entity System - Each game object will be
an entity at the core

* Entity Collision - Box vs. Box(possible rotation support),
Ellipse vs. Ellipse, Ellipse vs. Box, Poly vs. Poly
All routines will detect overlap and will work with high
speed objects. Each test will also return the smallest
vector required to separate objects making collision
response a lot easier

* Basic Collision Response - An object's response type will
determine what will happen when a collision occurs.
Objects should also support bounce and friction.

* Sprite System - Easier (animated) image handling.
Some added special effects.

* Model System - This will handle each game characters
animations. For each state the character can have an
animation played. Each model can be saved to disk. So
creating a character animation set can be done easily with
a separate tool.

* Camera System - This will allow for multiple viewports in
the game. Each camera will be able to follow a game
object, zoom in and out, move(scroll), shake, etc.

* Tile Object - These can be animated, or static.

* Tile Map System - This will display all the map
information, and will provide coordinate conversion
routines. Each map can have multiple floors with a various
amount of detail/overlay layers. Each floor will have a
Collision map attached to it. Things like bridges will be
easily achieved.

* Player object - Will handle each player. Players will be
updated via Finite State Machine AI, which will be
triggered by Input from the user. Controls will be easily
defined and changed on the fly.

* Game characters - Will handle each character. They will
also be updated via Finite State Machine AI loaded from
external files. Each character will have different
attributes applied to it, that will affect its decisions.
When enabled to do so characters will be able to
communicate with each other, group together, etc.

* Particle System - This will allow for various special
effects in game.

* Lighting System - Per pixel lighting for creating
atmosphere in game. Image based for flexibility.
Ambient light can be set.

* Weather/Day-Night - This system will allow for additional
special effects like rain, clouds, fog, night, day, etc.
It will use the other special effect systems to achieve
this.

* In addition a Game Object will control the flow of the
game and its different levels and objectives.

Thats the plan anyway. I hope to most of it implemented before any project is started. If there is a solid base code a community project will be much more successful.


klepto2(Posted 2005) [#18]
@Altitudems, maybe you can take a look at my Console Mod. It already provides WatchFunctions for Variables and also it supports direct passing Functions to specified Commands.


ImaginaryHuman(Posted 2005) [#19]
It sounds like a pretty nice tile engine.


altitudems(Posted 2005) [#20]
@Klepto
Your console mod is great, I have looked at it. But the console mod I have works just as well and fits more tightly into the system.


klepto2(Posted 2005) [#21]
No problem. Was just an idea to help you saveing a bit of time.


tonyg(Posted 2005) [#22]
It does sound great.
If you do your own map-editor couldn't you also add a pathfinding function?