
Lesson 10 Source Files
Resource Files
This lesson adds in a robust light handler. lights.txt defines the light sources and map.lights.txt defines where those lights are positioned in the map. There are 7 values that define each light:
character,r,g,b,colored,global
Character is the single character that is used in the map file to indicate where the light is positioned. r,g and b are the color values from 0-255. colored is either 0 or 1. If a light is not colored then the color values are ignored. Otherwise the color value is applied to the pixel which is being lit up. If a light is global then walls are ignored when calculating the lighting of a pixel. When a light is not global the walls cast shadows. Although non-global lighting is allowed it is highly expensive and will cause a huge drop in the framerate.
light_handler.java does all the heavy lifting with the lighting effects. You can trade off shadow accuracy with rendering speed if you want.
1 2 3 4 5 6 7 8 | dx = (sx-tx)/(dist*16.0); dy = (sy-ty)/(dist*16.0); for(j=0;j<dist*16.0;j++) { if(map.wall_tile_s((int)tx, (int)ty)>-1) { visible=false; j=dist;} tx+=dx; ty+=dy; } |

dist is the map location. If you multiply by 1 the render speed is the fastest but the light appears to wrap around walls a bit. If you multiply by 64 (which converts it to pixel location) then you get pixel level accuracy. However you’re now doing 64 times as many checks for the light hitting a wall which really slows things down. 16 gives a decent accuracy and allows for a reasonable framerate with 1 non-global light source. Your results will vary based on the system you’re running.
Notice that we’re tracing the light from the light source to the pixel we’re rendering. This allows us to use less accurate tracing to improve speed. If we went the other way we may start off inside the wall we’re checking for illumination. There’s probably ways to fix that but going from the light to the destination I think makes more sense anyway. If we hit a wall before we get the the destination we set visible to false and the light source is ignored. And that’s how shadows are created. You may notice that it looks very similar to the raycasting code that renders the level. It’s the same concept except that instead of shooting a ray from the camera we shoot it from a light.
Global lighting is very fast since the most expensive calculation is a squareroot. On modern processors the squareroot is calculated by the CPU which is very fast. Back when Wolfenstein 3D came out the sqrt function was the bane of game programming because it was not a native instruction on the CPU. Carmack came up with a C function to do the calculation very fast but that is still much slower than a modern CPU.
And that concludes our real time software rendering tutorials using Java.