I put this here not like Spam, I don't have nothing with the developer but I think can be interesting for all the people, basically the 90% of our games are doing in 2D.
http://store.steampowered.com/app/316830/
This soft it's something similar to do in 3D objects with bump or better said with noemal maps, but the good point it's in 2D, I think Erico put sometime ago a tutorial for do the same.
For now I see a bit expensive but the interesting of Steam they always do offers in the products, perhaps in 2 weeks or X months this soft cost only a few Euros... it's important take a look I just bought for 10E an 3D editor very very good and it's have an standard price about 40E.
***Ian if you have to take off the post do without problems don't worry, but I think it's an excellent tool for all the people do 2D GFX in the forum, at least for know this technology it's in the market.
I'm not the only one that removes posts you know! :P Besides I will only remove a post if it's inappropriate and or abusive - this is neither. I don't believe in censorship for the sake of it.
I've seen this before and think it's a nice tool. My artwork isn't worth bothering with fancy lighting, but it's a good tool :)
Ok Ian :P don't worry , I comment because one time I put something and this was erased... I don't know the reason don't appear naked girls boys =D =D
QuoteI comment because one time I put something and this was erased...
Are you sure it was erased? And are you sure that I erased it? If I remove something I always leave a message, giving the reason.
This happens a lot of time ago... don't worry Ian perhpas I put something incorrect in those post... Don't worry don't have the minimum importance you know I have a lot of aprecciate to you... :good: :good:
could that thread got removed after the server crash?
Yes not sure what it happens, but there is nothing wrong with this software (nor tested it).
PS. As you see, im can also accidently split a thread in a wrong way (its should have splitted with the follow posts, but its diddent do that).
this is just applying a height map to a sprite.
The hard part is the calculation of the lightning of each pixel based on lightsources and the Heightmap.
You could also add a "shadermap".
Nice idea, Maybe I could write something like this in GLBasic.
Edit:
Dynamic Light Map creation for a 320 x 240 pixels finished. Supports 10 Lights ( and a real ambient light :D ) . ;)
Now I will calculate the light value on a sprite by using the LightMap:
I will start easy and just calculate the light Values given by the virtual 3D x and z angles of a heightmap pixel.
Then I will create the light affected sprite from this data.
Tried adding a sprite and a heightmap for the sprite.
I didn´t came to the point, where I get to play around with the Heightmap, because I can´t read the heights out
of the Heightmap ( in the function drawlitsprite ).
Here is my attempt so far:
CONSTANT LightsMax = 10
CONSTANT SpriteMax = 100
TYPE vRGB
r% ; g% ; b%
ENDTYPE
TYPE light
color AS vRGB
range% // range of light ( Radius! )
kind% // kind of light ( other light reduction kinds till the end of the light range
exist%
x%
y%
ENDTYPE
TYPE sprite
srcTex$
srcH$
srcS$
iD%
x% ; y%
ENDTYPE
GLOBAL LightMap[] AS vRGB
GLOBAL Ambient AS vRGB
GLOBAL Lights[] AS light
main()
FUNCTION newSprite AS sprite: any AS sprite , iDG , sT$ , sH$ , sS$ , x , y
any.srcTex$ = sT$ ; any.srcH$ = sH$ ; any.srcS$ = sS$ ; any.iD = iDG ; any.x = x ; any.y = y
ENDFUNCTION
FUNCTION main:
LOCAL width% , height% , white AS vRGB , blue AS vRGB , red AS vRGB , ball AS sprite
LOCAL mX% , mY% , b1% , b2%
width = 320 ; height = 240
Ambient.r = 40 ; Ambient.g = 40 ; Ambient.b = 40
white.r = 255 ; white.g = 255 ; white.b = 255
blue.r = 120 ; blue.g = 120 ; blue.b = 255
red.r = 60 ; red.g = 255 ; red.b = 60
newSprite( ball , 100 , "bBall.bmp" , "bBallH.bmp" , "bBallS.bmp" , 160 , 120 )
SETCURRENTDIR("Media/Sprites") // go to media files
DIM LightMap[width][height] ; DIM Lights[LightsMax]
Lights[0].exist = TRUE ; Lights[0].x = 160 ; Lights[0].y = 120 ; Lights[0].range = 250 ; Lights[0].color = red
// Lights[1].exist = TRUE ; Lights[1].x = 160 ; Lights[1].y = 120 ; Lights[1].range = 50 ; Lights[1].color = blue
// Lights[2].exist = TRUE ; Lights[2].x = 60 ; Lights[2].y = 60 ; Lights[2].range = 50 ; Lights[2].color = white
WHILE NOT KEY( 30 )
MOUSESTATE mX , mY , b1 , b2
Lights[0].x = mX ; Lights[0].y = mY
// updateLightMap( width , height , Ambient )
X_MAKE2D
// drawLightMap( width , height )
drawLitSprite( ball )
SHOWSCREEN
WEND
ENDFUNCTION
FUNCTION drawLitSprite: spr AS sprite
LOCAL w% , h% , w2% , h2% , tMap%[] , hMap%[] , x% , y%
LOCAL hLD# , hRD# , hLU# , hRU# , hU# , hD# , hL# , hR# , anX# , anZ#
LOCAL lAllow% , rAllow% , dAllow% , uAllow% , dist# , clr AS vRGB , ok%
ok = LOADSPRITEMEM( spr.srcTex$ , w2 , h2 , hMap[] )
IF NOT ok THEN RETURN FALSE
ok = LOADSPRITEMEM( spr.srcTex$ , w , h , tMap[] )
IF NOT ok THEN RETURN FALSE
IF w2 <> w OR h2 <> h THEN RETURN FALSE // hMap has to be the same size as the texture size for this to work...
clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
FOR i = 0 TO BOUNDS( hMap[] , 0 ) - 1 // let the magic begin...
x = MOD( i , w ) ; y = i / w ;
hLD = bAND(ASR( hMap[ i ],24), 0xff)
IF bAND(ASR( hMap[ i ],24), 0xff) <> 0x00 // not pink "alpha" color...
hLD = ( bAND( hMap[ i ], 0x00ff00) / 255.0 ) * 100.0
hRD = ( bAND( hMap[ cB( ( x + 1 ) , 0 , ( w - 1 ) ) + ( y * w ) ] , 0xff ) / 255.0 ) * 100.0 // in debug I always get zero for those heights, also when I try to look at the value of hMap[ i ] I allways get the same value...
hLU = ( bAND( hMap[ x + ( cB( ( y + 1 ) , 0 , ( h - 1 ) ) * w ) ] , 0xff ) / 255.0 ) * 100.0
hRU = ( bAND( hMap[ cB( ( x + 1 ) , 0 , ( w - 1 ) ) + ( cB( ( y + 1 ) , 0 , ( h - 1 ) ) * w ) ] , 0xff ) / 255.0 ) * 100.0
hU = hLU + ( hRU - hLU ) / 2.0 ; hD = hLD + ( hRD - hLD ) / 2.0 ; hL = hLD + ( hLU - hLD ) / 2.0 ; hR = hRD + ( hRU - hRD ) / 2.0 // mean values
anZ = ATAN( ( hD - hU ) , 10.0 ) ; anX = ATAN( ( hL - hR ) , 10.0 ) // getting angles of steepness in right and up direction
lAllow = FALSE ; rAllow = FALSE ; dAllow = FALSE ; uAllow = FALSE
IF anX <= 0 THEN lAllow = TRUE ; IF anX >= 0 THEN rAllow = TRUE // light affecting this angle at all ?
IF anZ <= 0 THEN dAllow = TRUE ; IF anZ >= 0 THEN uAllow = TRUE // light affecting this angle at all ?
FOR i2 = 0 TO LightsMax - 1
IF Lights[i2].exist
IF ( Lights[i2].x > spr.x + x AND rAllow ) OR ( Lights[i2].x < spr.x + x AND lAllow ) OR ( Lights[i2].y > spr.y + y AND uAllow ) OR ( Lights[i2].y < spr.y + y AND dAllow ) // light affecting this angle at all ?
dist = SQR( POW( ( ( spr.x + x ) - Lights[i2].x ) , 2 ) + POW( ( ( spr.y + y ) - Lights[i2].y ) , 2 ) )
dist = Lights[i2].range - dist
IF dist > 0
dist = dist / ( Lights[i2].range / 2.0 )
dist = cBR( dist , 0 , 0.5 )
clr.r = clr.r + ( Lights[i2].color.r - clr.r ) *dist ; clr.g = clr.g + ( Lights[i2].color.g - clr.g ) * dist ; clr.b = clr.b + ( Lights[i2].color.b - clr.b ) * dist
ENDIF
ENDIF
ENDIF
NEXT
ENDIF
IF bAND(ASR(tMap[ i ],24), 0xff) <> 0x00
clr.r = clr.r - ( bAND( tMap[ i ], 0xff ) - clr.r ) / 2.0
clr.g = clr.g - ( bAND( ASR( tMap[ i ] , 8 ) , 0xff ) - clr.g ) / 2.0
clr.b = clr.b - ( bAND( ASR( tMap[ i ] , 16 ) , 0xff ) - clr.b ) / 2.0
SETPIXEL spr.x + x , spr.y + y , RGB( clr.r , clr.g , clr.b )
ENDIF
clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
NEXT
DIM hMap[0] ; DIM tMap[0]
ENDFUNCTION
FUNCTION cB: value , minimum , maximum // in bounds checker
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value
ENDFUNCTION
FUNCTION cBR#: value# , minimum# , maximum# // in bounds checker for floats
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value#
ENDFUNCTION
I know in some post , (a lot of time ago) someone put a lot of info how done this FX, I thik someone try to do it, but without succes.. :rant:
I am almost at success.
This is almost the Effect I want to achieve.
You can clearly see while testing, that light is only calculated correctly in 4 different directions, that is due
to the height difference calculation.
Because i have not yet implemented real terrain ground height getting for the correct ground height at floating point values, which
will make it a lot smoother.
// --------------------------------- //
// Project: 2DLight
// Start: Friday, January 02, 2015
// IDE Version: 12.312
CONSTANT LightsMax = 10
CONSTANT SpriteMax = 100
GLOBAL LightAngle#
TYPE vRGB
r% ; g% ; b%
ENDTYPE
TYPE light
color AS vRGB
range% // range of light ( Radius! )
kind% // kind of light ( other light reduction kinds till the end of the light range
exist%
x%
y%
ENDTYPE
TYPE sprite
srcTex$
srcH$
srcS$
iD%
x% ; y%
ENDTYPE
TYPE vec3D
x#
y#
z#
dX#
dY#
dZ#
ENDTYPE
GLOBAL LightMap[] AS vRGB
GLOBAL Ambient AS vRGB
GLOBAL Lights[] AS light
main()
FUNCTION dotP: vector1 AS vec3D , vector2 AS vec3D
RETURN vector1.dX * vector2.dX + vector1.dY * vector2.dY + vector1.dZ * vector2.dZ
ENDFUNCTION
FUNCTION magnitude: v AS vec3D
RETURN SQR( v.dX * v.dX + v.dY * v.dY + v.dZ * v.dZ )
ENDFUNCTION
FUNCTION newSprite AS sprite: s AS sprite , iDG , sT$ , sH$ , sS$ , x , y
s.srcTex$ = sT$ ; s.srcH$ = sH$ ; s.srcS$ = sS$ ; s.iD = iDG ; s.x = x ; s.y = y
ENDFUNCTION
FUNCTION newVector3D AS vec3D: v AS vec3D , x% , y% , z% , dX% , dY% , dZ%
v.x = x ; v.y = y ; v.z = z ; v.dX = dX ; v.dY = dY ; v.dZ = dZ
ENDFUNCTION
FUNCTION getAngleBetweenVec3D: v1 AS vec3D , v2 AS vec3D
RETURN dotP( v1 , v2 ) / ( magnitude( v1 ) * magnitude( v2 ) )
ENDFUNCTION
FUNCTION main:
LOCAL width% , height% , white AS vRGB , blue AS vRGB , red AS vRGB , ball AS sprite
LOCAL mX% , mY% , b1% , b2%
width = 320 ; height = 240
Ambient.r = 0 ; Ambient.g = 0 ; Ambient.b = 0
white.r = 255 ; white.g = 255 ; white.b = 255
blue.r = 120 ; blue.g = 120 ; blue.b = 255
red.r = 60 ; red.g = 255 ; red.b = 60
newSprite( ball , 100 , "bBall.bmp" , "bBallH.bmp" , "bBallS.bmp" , 160 , 120 )
SETCURRENTDIR("Media/Sprites") // go to media files
DIM LightMap[width][height] ; DIM Lights[LightsMax]
Lights[0].exist = TRUE ; Lights[0].x = 160 ; Lights[0].y = 120 ; Lights[0].range = 250 ; Lights[0].color = white
Lights[1].exist = TRUE ; Lights[1].x = 160 ; Lights[1].y = 120 ; Lights[1].range = 50 ; Lights[1].color = blue
Lights[2].exist = TRUE ; Lights[2].x = 60 ; Lights[2].y = 60 ; Lights[2].range = 50 ; Lights[2].color = white
WHILE NOT KEY( 30 )
MOUSESTATE mX , mY , b1 , b2
Lights[0].x = mX ; Lights[0].y = mY
updateLightMap( width , height , Ambient )
X_MAKE2D
drawLightMap( width , height )
drawLightSprite( ball )
PRINT LightAngle , 200 , 200
SHOWSCREEN
WEND
ENDFUNCTION
FUNCTION drawLightSprite: spr AS sprite
LOCAL w% , h% , w1% , h1% , w2% , h2% , tMap%[] , hMap%[] , x% , y% , value% , turn% , anIX# , anIZ# , hDif#
LOCAL hLD% , hRD% , hLU% , hRU% , ok% , anX# , anZ# , lDX# , lDY# , noEffect% , noXEffect% , noYEffect%
LOCAL hL# , hR# , hU# , hD#
LOCAL dist# , clr AS vRGB , v1 AS vec3D , v2 AS vec3D , vL AS vec3D
ok = LOADSPRITEMEM( spr.srcTex$ , w1 , h1 , tMap[] )
IF NOT ok THEN RETURN FALSE
ok = LOADSPRITEMEM( spr.srcH$ , w2 , h2 , hMap[] )
IF NOT ok THEN RETURN FALSE
IF w2 <> w1 OR h2 <> h1 THEN RETURN FALSE // hMap has to be the same size as the texture size for this to work...
w = w1 ; h = h1 ; clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
LightAngle = ATAN( ( ( h / 2 ) + spr.y - Lights[0].y ) , ( ( w / 2.0 ) + spr.x - Lights[0].x ) )
FOR i = 0 TO BOUNDS( hMap[] , 0 ) - 1
x = MOD( i , w ) ; y = i / w ; value = hMap[ i ]
IF bAND(ASR(value,24), 0xff) <> 0x00 // not pink "alpha" color...
hLD = value
hRD = hMap[ cB( ( x + 1 ) , 0 , ( w - 1 ) ) + ( y * w ) ]
hLU = hMap[ x + ( cB( ( y + 1 ) , 0 , ( h - 1 ) ) * w ) ]
hRU = hMap[ cB( ( x + 1 ) , 0 , ( w - 1 ) ) + ( cB( ( y + 1 ) , 0 , ( h - 1 ) ) * w ) ]
IF hRD = 0xFFFF0080 THEN hRD = value ; IF hLU = 0xFFFF0080 THEN hLU = value ; IF hRU = 0xFFFF0080 THEN hRU = value // not pink "alpha" color...
hLD = bAND( hLD , 0xff ) ; hRD = bAND( hRD , 0xff ) ; hLU = bAND( hLU , 0xff ) ; hRU = bAND( hRU , 0xff )
hL = hLD + ( hLU - hLD ) / 2.0 ; hR = hRD + ( hRU - hRD ) / 2.0
hU = hLU + ( hRU - hLU ) / 2.0 ; hD = hLD + ( hRD - hLD ) / 2.0
FOR i2 = 0 TO LightsMax - 1
IF Lights[i2].exist
lDX = Lights[i2].x - ( spr.x + ( w / 2.0 ) ) ; lDY = Lights[i2].y - ( spr.y + ( h / 2.0 ) )
IF lDX = 0 AND lDY > 0 ; hDif = hD - hU ; ENDIF
IF lDX = 0 AND lDY < 0 ; hDif = hU - hD ; ENDIF
IF lDX > 0 AND lDY = 0 ; hDif = hL - hR ; ENDIF
IF lDX < 0 AND lDY = 0 ; hDif = hR - hL ; ENDIF
IF lDX > 0 AND lDY > 0 ; hDif = hLD - hRU ; ENDIF
IF lDX < 0 AND lDY > 0 ; hDif = hRD - hLU ; ENDIF
IF lDX > 0 AND lDY < 0 ; hDif = hLU - hRD ; ENDIF
IF lDX < 0 AND lDY < 0 ; hDif = hRU - hLD ; ENDIF
newVector3D( v1 , spr.x + x , hLD , spr.y + y , lDX , hDif , lDY )
newVector3D( vL , Lights[i2].x , 300 , Lights[i2].y , Lights[i2].x - ( spr.x + x ) , -300 , Lights[i2].y - ( spr.y + y ) )
anIX = getAngleBetweenVec3D( v1 , vL )
noEffect = FALSE ; noXEffect = FALSE ; noYEffect = FALSE
dist = SQR( POW( ( ( spr.x + x ) - Lights[i2].x ) , 2 ) + POW( ( ( spr.y + y ) - Lights[i2].y ) , 2 ) )
dist = Lights[i2].range - dist
IF anIX < 0 THEN anIX = 0
anIX = 1.0 - anIX
IF dist > 0
dist = dist / Lights[i2].range
dist = ( dist ) * anIX
dist = cBR( dist , 0 , 1.0 )
clr.r = clr.r + ( Lights[i2].color.r - clr.r ) *dist ; clr.g = clr.g + ( Lights[i2].color.g - clr.g ) * dist ; clr.b = clr.b + ( Lights[i2].color.b - clr.b ) * dist
ENDIF
ENDIF
NEXT
ENDIF
value = tMap[ i ]
IF bAND(ASR(value,24), 0xff) <> 0x00
clr.r = bAND( value, 0xff ) + ( clr.r - bAND( value, 0xff ) ) / 2.0
clr.g = bAND( ASR( value , 8 ) , 0xff ) + ( clr.g - bAND( ASR( value , 8 ) , 0xff ) ) / 2.0
clr.b = bAND( ASR( value , 16 ) , 0xff ) + ( clr.b - bAND( ASR( value , 16 ) , 0xff ) ) / 2.0
SETPIXEL spr.x + x , spr.y + y , RGB( clr.r , clr.g , clr.b )
ENDIF
clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
NEXT
ENDFUNCTION
FUNCTION cB: value , minimum , maximum
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value
ENDFUNCTION
FUNCTION cBR: value , minimum , maximum
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value
ENDFUNCTION
FUNCTION updateLightMap: width% , height% , ambient AS vRGB
LOCAL lXL% , lXR% , lYU% , lYD% , dist# , scaleL#
FOR i = 0 TO width - 1
FOR i2 = 0 TO height - 1
LightMap[i][i2].r = ambient.r
LightMap[i][i2].g = ambient.g
LightMap[i][i2].b = ambient.b // Fill Lightmap with ambient light...
NEXT
NEXT
FOR i = 0 TO LightsMax - 1
IF Lights[i].exist
// IF Lights[i].x < 0 THEN Lights[i].x = 0 ; IF Lights[i].x > width - 1 THEN Lights[i].x = width - 1
// IF Lights[i].y < 0 THEN Lights[i].y = 0 ; IF Lights[i].y > height - 1 THEN Lights[i].y = height - 1
lXL = Lights[i].x - Lights[i].range ; lXR = Lights[i].x + Lights[i].range
IF lXL < 0 THEN lXL = 0 ; IF lXR > width - 1 THEN lXR = width - 1
lYD = Lights[i].y - Lights[i].range ; lYU = Lights[i].y + Lights[i].range
IF lYD < 0 THEN lYD = 0 ; IF lYU > height - 1 THEN lYU = height - 1
FOR i2 = lXL TO lXR
FOR i3 = lYD TO lYU
dist = SQR( POW( ( i2 - Lights[i].x ) , 2 ) + POW( ( i3 - Lights[i].y ) , 2 ) )
IF dist < Lights[i].range
scaleL = ( Lights[i].range - dist ) / Lights[i].range
LightMap[i2][i3].r = LightMap[i2][i3].r + ( Lights[i].color.r - LightMap[i2][i3].r ) * scaleL
LightMap[i2][i3].g = LightMap[i2][i3].g + ( Lights[i].color.g - LightMap[i2][i3].g ) * scaleL
LightMap[i2][i3].b = LightMap[i2][i3].b + ( Lights[i].color.b - LightMap[i2][i3].b ) * scaleL
ENDIF
NEXT
NEXT
ENDIF
NEXT
ENDFUNCTION
FUNCTION drawLightMap: width% , height% // for testing purpose, draw the lightmap only
FOR i = 0 TO width - 1
FOR i2 = 0 TO height - 1
SETPIXEL i , i2 , RGB( LightMap[i][i2].r , LightMap[i][i2].g , LightMap[i][i2].b )
NEXT
NEXT
ENDFUNCTION
Sprites are in the attachment
almost finished!
Just need to optimize it a bit ( calculate the normal map only once )
// --------------------------------- //
// Project: 2DLight
// Start: Friday, January 02, 2015
// IDE Version: 12.312
CONSTANT LightsMax = 10
CONSTANT SpriteMax = 100
TYPE vRGB
r% ; g% ; b%
ENDTYPE
TYPE light
color AS vRGB
range% // range of light ( Radius! )
kind% // kind of light ( other light reduction kinds till the end of the light range
exist%
x%
y%
ENDTYPE
TYPE sprite
srcTex$
srcH$
srcS$
iD%
x% ; y%
ENDTYPE
TYPE vec3D
dX#
dY#
dZ#
ENDTYPE
GLOBAL LightMap[] AS vRGB
GLOBAL Ambient AS vRGB
GLOBAL Lights[] AS light
main()
FUNCTION dotP: vector1 AS vec3D , vector2 AS vec3D
RETURN vector1.dX * vector2.dX + vector1.dY * vector2.dY + vector1.dZ * vector2.dZ
ENDFUNCTION
FUNCTION crossP AS vec3D: v1 AS vec3D , v2 AS vec3D , n AS vec3D
n.dX = ( v1.dY * v2.dZ ) - ( v1.dZ * v2.dY )
n.dY = ( v1.dZ * v2.dX ) - ( v1.dX * v2.dZ )
n.dZ = ( v1.dX * v2.dY ) - ( v1.dY * v2.dX )
ENDFUNCTION
FUNCTION magnitude: v AS vec3D
RETURN SQR( v.dX * v.dX + v.dY * v.dY + v.dZ * v.dZ )
ENDFUNCTION
FUNCTION newSprite AS sprite: s AS sprite , iDG , sT$ , sH$ , sS$ , x , y
s.srcTex$ = sT$ ; s.srcH$ = sH$ ; s.srcS$ = sS$ ; s.iD = iDG ; s.x = x ; s.y = y
ENDFUNCTION
FUNCTION newVector3D AS vec3D: v AS vec3D , dX% , dY% , dZ%
v.dX = dX ; v.dY = dY ; v.dZ = dZ
ENDFUNCTION
FUNCTION getAngleBetweenVec3D: v1 AS vec3D , v2 AS vec3D
RETURN dotP( v1 , v2 ) / ( magnitude( v1 ) * magnitude( v2 ) )
ENDFUNCTION
FUNCTION new2DLight AS light: nr% , x% , y% , range% , kind% , r% , g% , b%
Lights[nr].exist = TRUE ; Lights[nr].x = x ; Lights[nr].y = y ; Lights[nr].range = range
Lights[nr].color.r = r ; Lights[nr].color.g = g ; Lights[nr].color.b = b ; Lights[nr].kind = kind
ENDFUNCTION
FUNCTION main:
LOCAL width% , height% , ball AS sprite , ball2 AS sprite
LOCAL mX% , mY% , b1% , b2%
width = 320 ; height = 240 // size of LightMap ( Just for testing )
Ambient.r = 0 ; Ambient.g = 0 ; Ambient.b = 0
DIM LightMap[width][height] ; DIM Lights[LightsMax]
SETCURRENTDIR("Media/Sprites") // go to media files
newSprite( ball , 100 , "bBall.bmp" , "bBallH.bmp" , "bBallS.bmp" , 160 , 120 )
newSprite( ball2 , 101 , "bBall.bmp" , "bBallH2.bmp" , "bBallS.bmp" , 320 , 240 )
new2DLight( 0 , 0 , 0 , 800 , 0 , 255 , 220 , 220 )
WHILE NOT KEY( 30 )
MOUSESTATE mX , mY , b1 , b2
Lights[0].x = mX ; Lights[0].y = mY
IF b2 = TRUE ; Lights[0].kind = 1 ; ELSE ; Lights[0].kind = 0 ; ENDIF
updateLightMap( width , height , Ambient )
X_MAKE2D
drawLightMap( width , height )
drawLightSprite( ball ) ; drawLightSprite( ball2 )
SHOWSCREEN
WEND
ENDFUNCTION
FUNCTION drawLightSprite: spr AS sprite
LOCAL w1% , h1% , w2% , h2% , tMap%[] , hMap%[] , x% , y% , value% , anIN#
LOCAL hLD% , hRD% , hLU% , hRU% , ok%
LOCAL dist# , clr AS vRGB , v1 AS vec3D , v2 AS vec3D , vL AS vec3D
ok = LOADSPRITEMEM( spr.srcTex$ , w1 , h1 , tMap[] )
IF NOT ok THEN RETURN FALSE
ok = LOADSPRITEMEM( spr.srcH$ , w2 , h2 , hMap[] )
IF NOT ok THEN RETURN FALSE
IF w2 <> w1 OR h2 <> h1 THEN RETURN FALSE // hMap has to be the same size as the texture size for this to work...
clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
FOR i = 0 TO BOUNDS( hMap[] , 0 ) - 1
x = MOD( i , w1 ) ; y = i / w1 ; value = hMap[ i ]
IF bAND(ASR(value,24), 0xff) <> 0x00 // not pink "alpha" color...
hLD = value
hRD = hMap[ cB( ( x + 1 ) , 0 , ( w1 - 1 ) ) + ( y * w1 ) ]
hLU = hMap[ x + ( cB( ( y + 1 ) , 0 , ( h1 - 1 ) ) * w1 ) ]
hRU = hMap[ cB( ( x + 1 ) , 0 , ( w1 - 1 ) ) + ( cB( ( y + 1 ) , 0 , ( h1 - 1 ) ) * w1 ) ]
// check for pink "alpha" on the points around...
IF bAND(ASR(hRD,24), 0xff) = 0x00 ; hRD = 0 ; ELSE ; hRD = bAND( hRD , 0xff ) ; ENDIF
IF bAND(ASR(hLU,24), 0xff) = 0x00 ; hLU = 0 ; ELSE ; hLU = bAND( hLU , 0xff ) ; ENDIF
IF bAND(ASR(hRU,24), 0xff) = 0x00 ; hRU = 0 ; ELSE ; hRU = bAND( hRU , 0xff ) ; ENDIF
hLD = bAND( hLD , 0xff )
FOR i2 = 0 TO LightsMax - 1 // Go through all Lights and get an interpolated Light value based on Normals
IF Lights[i2].exist
dist = SQR( POW( ( ( spr.x + x ) - Lights[i2].x ) , 2 ) + POW( ( ( spr.y + y ) - Lights[i2].y ) , 2 ) )
dist = Lights[i2].range - dist
IF dist > 0
getnormalVector(hLU , hRU , hLD , hRD , v1 ) // Calculate the normal vector
newVector3D( vL , ( Lights[i2].x - ( spr.x + x ) ) , -Lights[i2].range / 2.0 , ( Lights[i2].y - ( spr.y + y ) ) ) // generate the Light Vector
anIN = getAngleBetweenVec3D( v1 , vL ) ; anIN = 1.0 + anIN ; IF anIN > 1.0 THEN anIN = 1.0
dist = dist / Lights[i2].range ; dist = ( dist ) * anIN
clr.r = clr.r + ( Lights[i2].color.r - clr.r ) *dist ; clr.g = clr.g + ( Lights[i2].color.g - clr.g ) * dist ; clr.b = clr.b + ( Lights[i2].color.b - clr.b ) * dist
ENDIF
ENDIF
NEXT
ENDIF
value = tMap[ i ] // Draw the Pixel by drawing the mean value of the texture pixel and Light Pixel
IF bAND(ASR(value,24), 0xff) <> 0x00
clr.r = bAND( value, 0xff ) + ( clr.r - bAND( value, 0xff ) ) / 2.0
clr.g = bAND( ASR( value , 8 ) , 0xff ) + ( clr.g - bAND( ASR( value , 8 ) , 0xff ) ) / 2.0
clr.b = bAND( ASR( value , 16 ) , 0xff ) + ( clr.b - bAND( ASR( value , 16 ) , 0xff ) ) / 2.0
SETPIXEL spr.x + x , spr.y + y , RGB( clr.r , clr.g , clr.b )
ENDIF
clr.r = Ambient.r ; clr.g = Ambient.g ; clr.b = Ambient.b
NEXT
ENDFUNCTION
FUNCTION getnormalVector AS vec3D: hLU% , hRU% , hLD% , hRD% , n AS vec3D
LOCAL P1 AS vec3D , P2 AS vec3D , P3 AS vec3D , n1 AS vec3D , n2 AS vec3D , c1 AS vec3D , c2 AS vec3D , c3 AS vec3D
IF ABS( ( hLU - hRD ) ) > ABS( ( hRU - hLD ) )// turn triangles...
P1.dX = 0 ; P1.dY = hLD ; P1.dZ = 0 ; P2.dX = 0 ; P2.dY = hLU ; P2.dZ = 1 ; P3.dX = 1 ; P3.dY = hRD ; P3.dZ = 0
crossP( P1 , P2 , c1 ) ; crossP( P2 , P3 , c2 ) ; crossP( P3 , P1 , c3 )
n1.dX = c1.dX + c2.dX + c3.dX
n1.dY = c1.dY + c2.dY + c3.dY
n1.dZ = c1.dZ + c2.dZ + c3.dZ
P1.dX = 1 ; P1.dY = hRU ; P1.dZ = 1 ; P2.dX = 1 ; P2.dY = hRD ; P2.dZ = 0 ; P3.dX = 0 ; P3.dY = hLU ; P3.dZ = 1
crossP( P1 , P2 , c1 ) ; crossP( P2 , P3 , c2 ) ; crossP( P3 , P1 , c3 )
n2.dX = c1.dX + c2.dX + c3.dX
n2.dY = c1.dY + c2.dY + c3.dY
n2.dZ = c1.dZ + c2.dZ + c3.dZ
n.dX = n1.dX + ( n2.dX - n1.dX ) / 2.0
n.dY = n1.dY + ( n2.dY - n1.dY ) / 2.0
n.dZ = n1.dZ + ( n2.dZ - n1.dZ ) / 2.0
ELSE
P1.dX = 0 ; P1.dY = hLU ; P1.dZ = 1 ; P2.dX = 1 ; P2.dY = hRU ; P2.dZ = 1 ; P3.dX = 0 ; P3.dY = hLD ; P3.dZ = 0
crossP( P1 , P2 , c1 ) ; crossP( P2 , P3 , c2 ) ; crossP( P3 , P1 , c3 )
n1.dX = c1.dX + c2.dX + c3.dX
n1.dY = c1.dY + c2.dY + c3.dY
n1.dZ = c1.dZ + c2.dZ + c3.dZ
P1.dX = 1 ; P1.dY = hRD ; P1.dZ = 0 ; P2.dX = 0 ; P2.dY = hLD ; P2.dZ = 0 ; P3.dX = 1 ; P3.dY = hRU ; P3.dZ = 1
crossP( P1 , P2 , c1 ) ; crossP( P2 , P3 , c2 ) ; crossP( P3 , P1 , c3 )
n2.dX = c1.dX + c2.dX + c3.dX
n2.dY = c1.dY + c2.dY + c3.dY
n2.dZ = c1.dZ + c2.dZ + c3.dZ
n.dX = n1.dX + ( n2.dX - n1.dX ) / 2.0
n.dY = n1.dY + ( n2.dY - n1.dY ) / 2.0
n.dZ = n1.dZ + ( n2.dZ - n1.dZ ) / 2.0
ENDIF
ENDFUNCTION
FUNCTION cB: value , minimum , maximum
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value
ENDFUNCTION
FUNCTION cBR AS float: value# , minimum# , maximum#
IF minimum > maximum THEN SWAP minimum , maximum
IF value < minimum THEN RETURN minimum
IF value > maximum THEN RETURN maximum
RETURN value
ENDFUNCTION
FUNCTION updateLightMap: width% , height% , ambient AS vRGB
LOCAL lXL% , lXR% , lYU% , lYD% , dist# , scaleL#
FOR i = 0 TO width - 1
FOR i2 = 0 TO height - 1
LightMap[i][i2].r = ambient.r
LightMap[i][i2].g = ambient.g
LightMap[i][i2].b = ambient.b // Fill Lightmap with ambient light...
NEXT
NEXT
FOR i = 0 TO LightsMax - 1
IF Lights[i].exist
lXL = Lights[i].x - Lights[i].range ; lXR = Lights[i].x + Lights[i].range
IF lXL < 0 THEN lXL = 0 ; IF lXR > width - 1 THEN lXR = width - 1
lYD = Lights[i].y - Lights[i].range ; lYU = Lights[i].y + Lights[i].range
IF lYD < 0 THEN lYD = 0 ; IF lYU > height - 1 THEN lYU = height - 1
FOR i2 = lXL TO lXR
FOR i3 = lYD TO lYU
dist = SQR( POW( ( i2 - Lights[i].x ) , 2 ) + POW( ( i3 - Lights[i].y ) , 2 ) )
IF dist < Lights[i].range
scaleL = ( Lights[i].range - dist ) / Lights[i].range
LightMap[i2][i3].r = LightMap[i2][i3].r + ( Lights[i].color.r - LightMap[i2][i3].r ) * scaleL
LightMap[i2][i3].g = LightMap[i2][i3].g + ( Lights[i].color.g - LightMap[i2][i3].g ) * scaleL
LightMap[i2][i3].b = LightMap[i2][i3].b + ( Lights[i].color.b - LightMap[i2][i3].b ) * scaleL
ENDIF
NEXT
NEXT
ENDIF
NEXT
ENDFUNCTION
FUNCTION drawLightMap: width% , height% // for testing purpose, draw the lightmap only
FOR i = 0 TO width - 1
FOR i2 = 0 TO height - 1
SETPIXEL i , i2 , RGB( LightMap[i][i2].r , LightMap[i][i2].g , LightMap[i][i2].b )
NEXT
NEXT
ENDFUNCTION
Media files in the attachment