2D Dynamic Lighting Tutorial

Anything related in any way to game development as a whole is welcome here. Tell us about your game, grace us with your project, show us your new YouTube video, etc.

Moderator: PC Supremacists

2D Dynamic Lighting Tutorial

Postby TheAustech on Sat Oct 09, 2010 5:34 am

How to Implement Dynamic Lighting in Your 2D Project
A Thorough Tutorial
By: Austin Shindlecker (Austech)

Sections (in order)
Recommended Knowlege
Recommended Sites
What we'll cover and how
What makes a light dynamic
SFML Objects You Should be Aware of
Coding The Lights and Blocks
Making The Engine



Recommended Knowledge Needed:

Some understanding of the Trigonomic Functions (cos, sin, tan)
Pythagorean Theorem
Well enough experience in the language you plan on using (duh)
----------------------------------------------
Reccomended Sites if you don't want to read this thread:
http://www.gamedev.net/reference/progra ... oftshadow/
----------------------------------------------
What We'll Cover and how
The code you will see is made in C++ and using the SFML library, but I'm pretty sure that you will be able to get the basic idea of what to do\

This tutorial will only be discussing what is called "hard shadows". The shadows do not blend or fade. But they are dynamic
-----------------------------------------------

What makes a light dynamic
So what makes a light dyamic? First off dynamic, when compared to static, is something that changes. While static is something that doesn't. For those who are still confused here's an example. In my game, Zombie Outrage 2, the lighting system I made has a boolean for whether or not a light is dynamic.

Static Light:
Image

Dynamic Light:
Image


Notice how with dynamic the light stops when it hits the zombies or player, creating a field of darkness behind them. Yet with the static it goes through. With dynamic the light changes.
------------------------------------------------

SFML Objects You Should be Aware of
As I said, I'm going to be using SFML (Simple, Fast, Multimedia Library), and I will be using some objects.

sf::Vector2f - Vector holding 2 floats (x,y)
The structure looks something like:
Code: Select all
struct Vector2f
{
float x, y;
};

Though Vector2f in reality is a derived class from sf::Vector, using floats in the template, this is pretty much how the structure would look like.

sf::FloatRect - Rectangle object holding 4 floats. (Left, Top, Width, Height).
The structure looks something like:

Code: Select all
struct FloatRect
{
float Left, Top, Width, Height;
};

Like the Vector2f, FloatRect in reality is just a derved of sf::Rect, using floats in the template. But this is how the structure would look like.

sf::Color - Object holding values for Red, Green, Blue, and Alpha. This is used only for rendering, nothing based on the actual lighting system
The structure looks something like:
Code: Select all
struct Color
{
int r, g, b, a;
};

I beleive that it's UINT instead of int. But I'm not 100%. But you should get the general idea.
-------------------------------------------

Coding the Lights and Blocks
So now that the intro is done and some things are explained. Let's get into the code!

We will be making 3 classes:

Light - Info for lighting (color, radius, position, spread)
Block - Areas where the light can't go through (rect, allowblock)
LightEngine - This is the class that does what is needed with the Lights and Blocks.


Let's get the first 2 classes out of the way since they are the easiest. Since it would be a pain to write a tutorial will .cpp and .hpp, I'm going to just right all the bodies in the .hpp file

Code: Select all
//Light.hpp
#pragma once //don't allow this header to be included more than once
#include <SFML/Graphics/Color.hpp>
#include <SFML/System/Vector2.hpp>

class Light
{
public:
   Light()
   {
      color = sf::Color(255, 255, 255);
      radius = 0;
      angleSpread = 0;
      position = sf::Vector2f(0,0);
      angle = 0;
      dynamic = true;
   }
   /*If you prefer, you can do the constructor like so:
   
   Light()
   : color(255, 255, 255), radius(0), angleSpread(0), position(0,0), angle(0), dynamic(true)
   {
   }
   */

   sf::Vector2f position; //position of the light
   sf::Color color; //light color
   float radius; //how far the light will shine to
   float angleSpread; //spread of the light, creating an arc
   float angle; //where the light's pointing at
   bool dynamic; //can this change?
};


Code: Select all
//Block.hpp
#pragma once//don't allow this header to be included more than once
#include <SFML/Graphics/Rect.hpp>

class Block
{
public:
   Block()
   {
      allowBlock = true;
      fRect = sf::FloatRect(0,0,0,0);
   }
   /* Like the light class, you can do this in an initializer list, whatever works for you
   
   Block()
   : fRect(0,0,0,0), allowBlock(false)
   {
   }
   */

   sf::FloatRect fRect; //Area that will be blocking light
   bool allowBlock; //Sometimes we want to keep a block, but don't want it to actually block until a certain point
};


These are pretty easy and straight forward. I added comments in places to make it even more understandable. Unfortunately, this is the easy part. Now we are going to make the engine. Again there will be comments.
-----------------------------------------
Making the engine

The engine will be taking these 2 objects we made, and actually do things with them.

The light engine should have some sort of container for holding multiple lights and blocks. I'll be using std::vector.
The light engine should have a private Light() function to do things with a light.
The light engine should have some sort of step function to light each light in a vector.
A useful function to get the distance of two points
A function to check if a light hits a block
Maybe some useful functions to make long equations return an answer neater than typing it call out.

My class looks like this:

Code: Select all
//LightEngine.hpp

#pragma once//don't allow this header to be included more than once
#include "Light.hpp"
#include "Block.hpp"
#include <vector>
#include <SFML/Graphics/RenderTarget.hpp> //Place to draw on
#include <SFML/Graphics/Shape.hpp> //SFML programmable Shapes

class LightEngine
{
public:   
   void Step(sf::RenderTarget &rt);

   std::vector <Light> Lights; //Container for Lights
   
   std::vector <Block> Blocks; //Container for Blocks
private:
   
   void ShineLight(Light &lig, sf::RenderTarget &rt);
      
   static const float Distance(const sf::Vector2f &p1, const sf::Vector2f &p2);
   static const sf::Vector2f GetCenter(const sf::FloatRect &fr); //Get the center of a rectangle
   
   
   struct FindDistance //if a light's radius manages to intersect multiple blocks, we need to find the sortest distance to shorten the light
   {
      FindDistance();
      float shortest;
      bool LightHitsBlock(Light &l, Block &b, const float cur_ang, float &reflength);
      bool start; //to get the first distance to refer off of
   };

   FindDistance findDis;
};


Step - Only function exposed publicly. Calls "ShinLight" for each light in the container
struct FindDistance Structure containing info for calculating how much the light ray should be shortened.
FindDistance::LightHitsBlock - One of the main functions in LightEngine. Checks if a light hit's the block. This changes the findDis info.
ShineLight - Another main functions for ray casting a light
Distance - Static functionto find the distance between 2 points. This doesn't HAVE to be in the LighEngine class. It can be anywhere. I will use it for cleaner code and it's easier than typing the calculations over and over.
GetCenter - Get Center of a Rectangle


Now that you have a basic understanding of what each function and structure does. Let's get into the bodies of the structures. Like before, we'll do the easiest to hardest.

Code: Select all

LightEngine::FindDistance::FindDistance()
{
   start = false;
   shortest = 0;
}

const sf::Vector2f LightEngine::GetCenter(const sf::FloatRect &fr)
{
   return sf::Vector2f(fr.Left + (fr.Width / 2), fr.Top + (fr.Height / 2));
}

const float LightEngine::Distance(const sf::Vector2f &p1, const sf::Vector2f &p2)
{
   //We need to look at this as a triangle

   /*
            /|p1.y
           / |
          /  |
         /   |
        /    |
       /     |b
      /      |
     /       |
    /        |
   /         |
   -----------
        a     p2.y
p1.x           p2.x

   */

   float a = p2.x - p1.x;  //width length
   float b = p2.y - p1.y; //height length
   float c = sqrt((a * a) + (b * b)); //Pythagorean Theorem. (c² = a² + b²). c = squareroot(a² + b²)

   return c;
}


These really should be self explainable with the comments.

Step Function:

Code: Select all
void LightEngine::Step(sf::RenderTarget &rt)
{
   for(unsigned i = 0; i < Lights.size(); i++)
   {
      ShineLight(Lights[i], rt); //Shine all lights
   }
}


Now we have 2 functions left, ShineLight and LightHitsBlock. These both aren't really too hard. Let's start with the ShineLight function:

Code: Select all
void LightEngine::ShineLight(Light &l, sf::RenderTarget &rt)
{
   /*
   remember back in the Light class, we had something called 'angleSpread' ?
   that's to create a tunnel, or arc shaped light. Like this:
          /)
        /  )
      /    )
    /      )
   <       )
    \      )
      \    )
        \  )
         \)

   Obviously it'll look better than an ascii drawing
   */

   float current_angle = l.angle - (l.angleSpread / 2); //This will rotate the angle back far enough to get a desired arc

   /*
   Lights Angle (if it was at 0):
   
   -------------

   Current_Angle:
       /
      /
   /
   (slanted)

   */

   float dyn_len = l.radius; //dynamic length of the light. This will be changed in the function LightHitsBlock()

   float addto = 1.f / l.radius;
   for(current_angle; current_angle < l.angle + (l.angleSpread / 2); current_angle += addto * (180.f/3.14f)) //we need to add to the current angle, until it reaches the end of the arc. we divide 1.f by radius for a more solid shape. Otherwize you could see lines seperating
   {
      dyn_len = l.radius; //Reset the length
      findDis.start = true; //Start of finding a light, we need to reset
      findDis.shortest = 0; //Reset the shortest.

      
      
      if(l.dynamic) //can this change?
      {
         for(unsigned i = 0; i < Blocks.size(); i++)
         {
            findDis.LightHitsBlock(l, Blocks[i], current_angle, dyn_len);
         }
      }
      
      
      float radians = current_angle * (3.14f / 180); //Convert to radians for trig functions
      
      sf::Vector2f end = l.position;
      end.x += cos(radians) * dyn_len;
      end.y += sin(radians) * dyn_len;
      rt.Draw(sf::Shape(sf::Shape::Line(l.position,  end, 1, l.color)));
   }
}


We use another float, current_angle, because it's based off of the light's angle. At the very beginning we subtract half of the angle spread. This rotates that current_angle back. We use a for loop and increase the current_angle until it reaches the lights angle PLUS half the angle spread.

current_angle is the direction of where the light ray will go. One light can equal many light rays. Hundreds of them.

Since this function is using the LightHitsBlock function, we're going to go to that and come back.


Code: Select all
bool LightEngine::FindDistance::LightHitsBlock(Light &l, Block &b, float cur_ang, float &refleng)
{
   if(b.allowBlock) //can this even block?
   {
      float distance = Distance(l.position, GetCenter(b.fRect));
   
      if(l.radius >= distance) //check if it's radius is even long enough to hit a block
      {
         float radians = cur_ang * (3.14f / 180); //convert cur_ang to radians for trig functions
         sf::Vector2f pointpos = l.position;

         pointpos.x += cos(radians) * distance;
         pointpos.y += sin(radians) * distance;
         //By doing this, we check if the angle is in the direciton of the block.

         if(b.fRect.Contains(pointpos)) //If it was, than the point would be intersecting the rectangle of the block
         {
            if(start || distance < shortest) //If this is the first block, or it has a shorter distance
            {
               start = false; //definately not the start so other blocks can't automatically set the distance
               shortest = distance; //shortest is set to this
               refleng = distance; //This is where the dynamic comes in, it changes the length of the reference towhere it's going to stop after it hits the distance from the point to the block
            }
            return true;
         }
      }
   }
   return false;
}


The comments should explain a lot of this. This function is basically doing this:
Check if the Block can block light from passing through
Check if the light's radius can reach to the block
Check if the light's angle direction is in the direction of the block
if it is, then check if the block is the closest to the light
if it is, then change the ray's length to it's distance.




Now back to the ShineLight function:
Code: Select all
void LightEngine::ShineLight(Light &l, sf::RenderTarget &rt)
{
   /*
   remember back in the Light class, we had something called 'angleSpread' ?
   that's to create a tunnel, or arc shaped light. Like this:
          /)
        /  )
      /    )
    /      )
   <       )
    \      )
      \    )
        \  )
         \)

   Obviously it'll look better than an ascii drawing
   */

   float current_angle = l.angle - (l.angleSpread / 2); //This will rotate the angle back far enough to get a desired arc

   /*
   Lights Angle (if it was at 0):
   
   -------------

   Current_Angle:
       /
      /
   /
   (slanted)

   */

   float dyn_len = l.radius; //dynamic length of the light. This will be changed in the function LightHitsBlock()

   float addto = 1.f / l.radius;
   for(current_angle; current_angle < l.angle + (l.angleSpread / 2); current_angle += addto * (180.f/3.14f)) //we need to add to the current angle, until it reaches the end of the arc. we divide 1.f by radius for a more solid shape. Otherwize you could see lines seperating
   {
      dyn_len = l.radius; //Reset the length
      findDis.start = true; //Start of finding a light, we need to reset
      findDis.shortest = 0; //Reset the shortest.

      
      
      if(l.dynamic) //can this change?
      {
         for(unsigned i = 0; i < Blocks.size(); i++)
         {
            findDis.LightHitsBlock(l, Blocks[i], current_angle, dyn_len);
         }
      }
      
      
      float radians = current_angle * (3.14f / 180); //Convert to radians for trig functions
      
      sf::Vector2f end = l.position;
      end.x += cos(radians) * dyn_len;
      end.y += sin(radians) * dyn_len;
      rt.Draw(sf::Shape(sf::Shape::Line(l.position,  end, 1, l.color)));
   }
}


Notice how we loop through all blocks and call the same function. This is because it's changing variables and checking variables from the findDis object. As you can see before we loop through the blocks, we reset the values.

We pass dyn_len to the LighHitsBlock function as a reference, so the function can change the value of it based off the smallest distance.

After all that, we can finally draw it. We create a line from the lights original position, to the end which is the lights position plus the cos and sin of the dyn_len.




Now we can test it, I set up this simple example to do so:

Code: Select all
#include <SFML/Graphics.hpp>
#include <iostream>
#include "LightEngine.hpp"

int main()
{
   sf::RenderWindow win(sf::VideoMode(800, 600), "Light Tutorial");
   sf::Event event;

   LightEngine le;

   Light light;
   light.radius = 600;
   light.angleSpread = 100;
   light.position = sf::Vector2f(100,150);
   le.Lights.push_back(light);

   Block block;
   block.fRect = sf::FloatRect(0,0,50,50);
   le.Blocks.push_back(block);

   
   while(win.IsOpened())
   {
      while(win.GetEvent(event))
      {
         if(event.Type == sf::Event::Closed) win.Close();
      }
      std::cout<<1 / win.GetFrameTime()<<"\n"; //output the framerate
      win.Clear();
      le.Blocks[0].fRect.Left = win.GetInput().GetMouseX();
      le.Blocks[0].fRect.Top = win.GetInput().GetMouseY();
      win.Draw(sf::Shape::Rectangle(le.Blocks[0].fRect, sf::Color(255,0,0)));
      le.Step(win);
      win.Display();
   }
}


I added a light, and a block to the light engine. In the while loop I step the engine, and I also draw the rectangle of the first block I added to the container. I also output the framerate in the console. All in all, the program should look something like this:

Image

Testing multiple blocks:
Image

Little more
Image
====================================================================

I really hope this helps some people out. I knew that some people wanted to know how my game did it and a way for SFML. Sorry if this wasn't clear enough or easy to read. This is my second tutorial at the moment.


Thanks again. :)
Last edited by TheAustech on Sun Oct 10, 2010 9:14 am, edited 1 time in total.
User avatar
TheAustech
Chaos Rift Cool Newbie
Chaos Rift Cool Newbie
 
Posts: 98
Joined: Fri Sep 03, 2010 5:38 pm
Location: Maryland

Re: 2D Dynamic Lighting Tutorial

Postby dandymcgee on Sat Oct 09, 2010 12:40 pm

Holy shit man. This is one of the best contributions I've seen on these forums in a long time. You've done a mighty fine job writing it up.
Falco Girgis wrote:It is imperative that I can broadcast my narcissistic commit strings to the Twitter! Tweet Tweet, bitches! :twisted:
User avatar
dandymcgee
ES Beta Backer
ES Beta Backer
 
Posts: 4911
Joined: Tue Apr 29, 2008 4:24 pm
Location: New Hampshire

Re: 2D Dynamic Lighting Tutorial

Postby PaperDuckyFTW on Sat Oct 09, 2010 2:34 pm

WOW

I was think it would be cool to include lighting into my current/future games and I thought the only way I could was with OpenGL. THANKYOU SO MUCH!! Now I can actually find a use for learning pythagorus's theorum and trigonometry. The next time someone says "When will we ever need to know this?" Ill turn to them and say "For example: To add dynamic lighting to your game." They will have no clue what I'm talking about meh, I can feel cool inside.

Thankyou very much bud, I cant think of a better/easier to understand way you could have written it.
Last edited by PaperDuckyFTW on Sat Oct 09, 2010 9:39 pm, edited 1 time in total.
PaperDuckyFTW
Chaos Rift Cool Newbie
Chaos Rift Cool Newbie
 
Posts: 76
Joined: Sat Apr 03, 2010 6:08 am

Re: 2D Dynamic Lighting Tutorial

Postby Ginto8 on Sat Oct 09, 2010 3:27 pm

PaperDuckyFTW wrote::worship: :bow: :worship: :bow: :worship: :bow: :worship: :bow: :worship: :bow: :worship: :bow:
WOW

I was think it would be cool to include lighting into my current/future games and I thought the only way I could was with OpenGL. THANKYOU SO MUCH!! Now I can actually find a use for learning pythagorus's theorum and trigonometry. The next time someone says 'why are we learning this? When will we ever need to know this?" Ill turn to them and say "For example: To add dynamic lighting to your game." They will have no clue what I'm talking about meh, I can feel cool inside.

Thankyou very much bud, I cant think of a better/easier to understand way you could have written it.

pythagorean theorem + trig are used a shitload in graphics programming especially, though game programming in general is definitely where it is prominent.
Quit procrastinating and make something awesome.
Ducky wrote:Give a man some wood, he'll be warm for the night. Put him on fire and he'll be warm for the rest of his life.
User avatar
Ginto8
ES Beta Backer
ES Beta Backer
 
Posts: 1101
Joined: Tue Jan 06, 2009 6:12 pm

Re: 2D Dynamic Lighting Tutorial

Postby eatcomics on Sat Oct 09, 2010 4:15 pm

Great job austech! Showing once again, that you are probably the coolest person on these forums xD
Image
User avatar
eatcomics
ES Beta Backer
ES Beta Backer
 
Posts: 2664
Joined: Sat Mar 08, 2008 9:52 pm
Location: Illinois

Re: 2D Dynamic Lighting Tutorial

Postby GroundUpEngine on Sat Oct 09, 2010 6:16 pm

dandymcgee wrote:Holy shit man. This is one of the best contributions I've seen on these forums in a long time. You've done a mighty fine job writing it up.


+1
User avatar
GroundUpEngine
Chaos Rift Devotee
Chaos Rift Devotee
 
Posts: 869
Joined: Sun Nov 08, 2009 4:01 pm
Location: UK

Re: 2D Dynamic Lighting Tutorial

Postby Falco Girgis on Sat Oct 09, 2010 6:57 pm

Fuckin A, man. Stickied.
"So what happens if the Elysian Shadows Kickstarter fails?"
Image
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
 
Posts: 10693
Joined: Thu May 20, 2004 3:04 pm
Location: Studio Vorbis, AL

Re: 2D Dynamic Lighting Tutorial

Postby PaperDuckyFTW on Sat Oct 09, 2010 9:38 pm

pythagorean theorem + trig are used a shitload in graphics programming especially, though game programming in general is definitely where it is prominent.


Ive used trig back when playing with game maker's 3D support but 2d lighting is much, much cooler.
PaperDuckyFTW
Chaos Rift Cool Newbie
Chaos Rift Cool Newbie
 
Posts: 76
Joined: Sat Apr 03, 2010 6:08 am

Re: 2D Dynamic Lighting Tutorial

Postby EdBoon on Sat Oct 09, 2010 10:50 pm

That's some great stuff, even cooler to see whats behind the scenes in your project! Thanks for posting.
Undead Empire -> http://bit.ly/dYdu3z
Gamerscore Tracker -> http://bit.ly/vI4T4X
Undead Empire: Hellfire -> http://bit.ly/1AgC4ZY
facebook.com/BigRookGames twitter.com/BigRookGames
youtube.com/user/bigrookdigital
User avatar
EdBoon
Chaos Rift Junior
Chaos Rift Junior
 
Posts: 267
Joined: Fri May 28, 2010 11:44 pm
Location: Atlanta, GA

Re: 2D Dynamic Lighting Tutorial

Postby pubby8 on Mon Feb 07, 2011 2:01 pm

It is very nice of you to write such an example, however I wanted to point out that there are numerous flaws in your method and that this code should not be used in game.

You should spend some time and optimize it.
pubby8
Jealous Self-Righteous Prick
Jealous Self-Righteous Prick
 
Posts: 58
Joined: Mon Feb 07, 2011 2:22 am

Re: 2D Dynamic Lighting Tutorial

Postby k1net1k on Mon Feb 07, 2011 2:37 pm

i dont even know sfml/c++ or any of that stuff the cool kids use, but this is an excellent tutorial
User avatar
k1net1k
Chaos Rift Maniac
Chaos Rift Maniac
 
Posts: 594
Joined: Sun Nov 07, 2010 4:58 pm

Re: 2D Dynamic Lighting Tutorial

Postby dandymcgee on Mon Feb 07, 2011 9:14 pm

pubby8 wrote:It is very nice of you to write such an example, however I wanted to point out that there are numerous flaws in your method and that this code should not be used in game.

You should spend some time and optimize it.

I'm sure he's quite aware of this. Perhaps pointing a few of them out and suggesting alternatives would be helpful?
Falco Girgis wrote:It is imperative that I can broadcast my narcissistic commit strings to the Twitter! Tweet Tweet, bitches! :twisted:
User avatar
dandymcgee
ES Beta Backer
ES Beta Backer
 
Posts: 4911
Joined: Tue Apr 29, 2008 4:24 pm
Location: New Hampshire

Re: 2D Dynamic Lighting Tutorial

Postby pubby8 on Mon Feb 07, 2011 9:41 pm

dandymcgee wrote:
pubby8 wrote:It is very nice of you to write such an example, however I wanted to point out that there are numerous flaws in your method and that this code should not be used in game.

You should spend some time and optimize it.

I'm sure he's quite aware of this. Perhaps pointing a few of them out and suggesting alternatives would be helpful?


Well there are many methods/algorithms, and I am sure that somewhere there is one much better than what I am going to say. They are also highly dependant on the implementation.

General improvements: (I won't go into details)
*Sort data into a quadtree
*Rewrite rasterization to work on triangles instead of lines (I do not know sfml so I do not know if this is feasable)
*Branching ray tests
*Work on polygons instead of pixels

Some specifics:
One general thing you should avoid is stuff like this:
Code: Select all
         pointpos.x += cos(radians) * distance;
         pointpos.y += sin(radians) * distance;

You should be storing the trig into a variable and adding the variable. Most compilers will optimize this sort of thing automatically, but it is still good idea incase compiler misses it.

Also, when doing any sort of collision tests (lines with circles for instance) you should always check square bounding boxes before anything more complex.
pubby8
Jealous Self-Righteous Prick
Jealous Self-Righteous Prick
 
Posts: 58
Joined: Mon Feb 07, 2011 2:22 am

Re: 2D Dynamic Lighting Tutorial

Postby Firzen on Tue Feb 08, 2011 5:30 pm

pubby8 wrote:It is very nice of you to write such an example, however I wanted to point out that there are numerous flaws in your method and that this code should not be used in game.

You should spend some time and optimize it.


Dude, seriously. What the heck.

The last time I checked tutorials were ment to illustrate the basic idea of how things work. Optimization most of the time just obfuscates what the code does.
You do not teach kids in primary school about monoids before teaching them how to add numbers although strictly speaking that would be more accurate.

You seem to be missing the point of a tutorial.

Sure, he could have this working much easier and faster by taking just the edges and creating triangles away from the lightsource and darkening them.

But one last time, that is not the point. The point is: "How do I get light and shadows to work in 2d" and not "How do I optimize my light code crazily in order to achieve the best performance whatsoever, possibly also jamming some asm code in to approximate sin and cos a bit quicker and confuse the people that want to understand what I am doing a bit more"

Have a nice day
Firzen
Chaos Rift Newbie
Chaos Rift Newbie
 
Posts: 23
Joined: Mon Jul 20, 2009 8:13 pm

Re: 2D Dynamic Lighting Tutorial

Postby pubby8 on Tue Feb 08, 2011 11:41 pm

The tutorial is well-written, the method works, and works nicely - however I think people should realize that the code they are given should not be used as a "drop-in" replacement to the openGL version, as they will end up being frustrated if they are left to optimize it theirself due to laggy performance.

I think it would benefit everyone to discuss some general optimizations that can be made - 2d lighting is a very good area to learn about such things.
pubby8
Jealous Self-Righteous Prick
Jealous Self-Righteous Prick
 
Posts: 58
Joined: Mon Feb 07, 2011 2:22 am

Next

Return to Game Development

Who is online

Users browsing this forum: No registered users and 3 guests

cron