I have started to make a 2d top view game. Wall, monsters, etc.
Now i created a function, that is casting light and shadows on the level.
My idea is to get all light sources to one texture (using blenging) and to have a "shadowmap" that will be blended onto the level.
My problem - when creating the shadows, i draw them directly to the level - and thats bad, cause i can't do 2 lightsources at once.
So the question - how should I change the drawing code to draw on some "memory-bitmap" as used in allegro and not directly on the video screen ? 
My code is from the tutorials, nothing special..
(the x1, ... x4 points are simple drawing rectangle shadows)
| 1 | glLoadIdentity();//reset matrix |
| 2 | glBindTexture(GL_TEXTURE_2D, gl_textures[texture]); |
| 3 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| 4 | glEnable(GL_BLEND); |
| 5 | |
| 6 | |
| 7 | glBegin(GL_QUADS); |
| 8 | glColor4ub(r, g, b, alpha); |
| 9 | |
| 10 | //Draw our four points, clockwise. |
| 11 | glTexCoord2f(0, 0); |
| 12 | glVertex3f(x1,y1, 0); |
| 13 | glTexCoord2f(1, 0); |
| 14 | glVertex3f(x2,y2, 0); |
| 15 | glTexCoord2f(1, 1); |
| 16 | glVertex3f(x3,y3, 0); |
| 17 | glTexCoord2f(0, 1); |
| 18 | glVertex3f(x4,y4, 0); |
| 19 | |
| 20 | glEnd(); |
| 21 | glLoadIdentity(); |
| 22 | } |
You need to render your lights and shadows on a texture using FBOs, and call 'glBlendEquationEXT(GL_MAX_EXT)', which would make your lights and shadows accumulate in a realistic way, e.g. red, green and blue lights will mix into white.
But even then, simply blending your shadowmap with the level won't do the job, because then, even the most dark spot won't be completely dark because it'll be a blend of black and whatever is underneath it.
Maybe you can use 'glBlendEquationEXT' with another parameter to fix that (what you need is to multiply the level pixel by the lightmap pixel), I don't remember how it's called, though.
I would suggest you to search the net for 'glBlendEquationEXT'.
[EDIT]
Silly me!
You can blend the lightmap with the rest of the level correctly with multitexturing and TEXTURE_ENV_MODE set to MODULATE.
And by the way, the simplest solution would be to precalculate your lightmaps instead of generating them in real time with all that render-to-texture burden, which isn't supported on old cards.
Oh, and here's an example of how to render stuff on a texture:
| 1 | #include <GL/glut.h> |
| 2 | #include <math.h> |
| 3 | #include <stdlib.h> |
| 4 | |
| 5 | #define SIZE 256 |
| 6 | |
| 7 | static unsigned char texture[3 * SIZE * SIZE]; |
| 8 | static unsigned int texture_id; |
| 9 | static int window_width = 500; |
| 10 | static int window_height = 500; |
| 11 | |
| 12 | |
| 13 | /* |
| 14 | ** Just a textured cube |
| 15 | */ |
| 16 | void Cube (void) |
| 17 | { |
| 18 | glBegin (GL_QUADS); |
| 19 | |
| 20 | glTexCoord2i (0, 0); glVertex3f (-1, -1, -1); |
| 21 | glTexCoord2i (0, 1); glVertex3f (-1, -1, 1); |
| 22 | glTexCoord2i (1, 1); glVertex3f (-1, 1, 1); |
| 23 | glTexCoord2i (1, 0); glVertex3f (-1, 1, -1); |
| 24 | |
| 25 | glTexCoord2i (0, 0); glVertex3f ( 1, -1, -1); |
| 26 | glTexCoord2i (0, 1); glVertex3f ( 1, -1, 1); |
| 27 | glTexCoord2i (1, 1); glVertex3f ( 1, 1, 1); |
| 28 | glTexCoord2i (1, 0); glVertex3f ( 1, 1, -1); |
| 29 | |
| 30 | glTexCoord2i (0, 0); glVertex3f (-1, -1, -1); |
| 31 | glTexCoord2i (0, 1); glVertex3f (-1, -1, 1); |
| 32 | glTexCoord2i (1, 1); glVertex3f ( 1, -1, 1); |
| 33 | glTexCoord2i (1, 0); glVertex3f ( 1, -1, -1); |
| 34 | |
| 35 | glTexCoord2i (0, 0); glVertex3f (-1, 1, -1); |
| 36 | glTexCoord2i (0, 1); glVertex3f (-1, 1, 1); |
| 37 | glTexCoord2i (1, 1); glVertex3f ( 1, 1, 1); |
| 38 | glTexCoord2i (1, 0); glVertex3f ( 1, 1, -1); |
| 39 | |
| 40 | glTexCoord2i (0, 0); glVertex3f (-1, -1, -1); |
| 41 | glTexCoord2i (0, 1); glVertex3f (-1, 1, -1); |
| 42 | glTexCoord2i (1, 1); glVertex3f ( 1, 1, -1); |
| 43 | glTexCoord2i (1, 0); glVertex3f ( 1, -1, -1); |
| 44 | |
| 45 | glTexCoord2i (0, 0); glVertex3f (-1, -1, 1); |
| 46 | glTexCoord2i (0, 1); glVertex3f (-1, 1, 1); |
| 47 | glTexCoord2i (1, 1); glVertex3f ( 1, 1, 1); |
| 48 | glTexCoord2i (1, 0); glVertex3f ( 1, -1, 1); |
| 49 | |
| 50 | glEnd (); |
| 51 | } |
| 52 | |
| 53 | /* |
| 54 | ** Function called to update rendering |
| 55 | */ |
| 56 | void DisplayFunc (void) |
| 57 | { |
| 58 | static float alpha = 20; |
| 59 | |
| 60 | glLoadIdentity(); |
| 61 | glTranslatef (0, 0, -10); |
| 62 | glRotatef (30, 1, 0, 0); |
| 63 | glRotatef (alpha, 0, 1, 0); |
| 64 | |
| 65 | /* Define a view-port adapted to the texture */ |
| 66 | glMatrixMode(GL_PROJECTION); |
| 67 | glLoadIdentity (); |
| 68 | gluPerspective (20, 1, 5, 15); |
| 69 | glViewport(0, 0, SIZE, SIZE); |
| 70 | glMatrixMode(GL_MODELVIEW); |
| 71 | |
| 72 | /* Render to buffer */ |
| 73 | glClearColor (1, 1, 1, 0); |
| 74 | glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| 75 | Cube (); |
| 76 | glFlush (); |
| 77 | |
| 78 | /* Copy buffer to texture */ |
| 79 | glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 5, 5, 0, 0, SIZE - 10, SIZE - 10); |
| 80 | |
| 81 | /* Render to screen */ |
| 82 | glMatrixMode(GL_PROJECTION); |
| 83 | glLoadIdentity (); |
| 84 | gluPerspective (20, window_width / (float) window_height, 5, 15); |
| 85 | glViewport(0, 0, window_width, window_height); |
| 86 | glMatrixMode(GL_MODELVIEW); |
| 87 | glClearColor (0, 0, 0, 0); |
| 88 | glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| 89 | Cube (); |
| 90 | |
| 91 | /* End */ |
| 92 | glFlush (); |
| 93 | glutSwapBuffers (); |
| 94 | |
| 95 | /* Update again and again */ |
| 96 | alpha = alpha + 0.1; |
| 97 | glutPostRedisplay(); |
| 98 | } |
| 99 | |
| 100 | /* |
| 101 | ** Function called when the window is created or resized |
| 102 | */ |
| 103 | void ReshapeFunc (int width, int height) |
| 104 | { |
| 105 | window_width = width; |
| 106 | window_height = height; |
| 107 | glutPostRedisplay(); |
| 108 | } |
| 109 | |
| 110 | /* |
| 111 | ** Function called when a key is hit |
| 112 | */ |
| 113 | void KeyboardFunc (unsigned char key, int x, int y) |
| 114 | { |
| 115 | int foo; |
| 116 | |
| 117 | foo = x + y; /* Has no effect: just to avoid a warning */ |
| 118 | if ('q' == key || 'Q' == key || 27 == key) |
| 119 | exit (0); |
| 120 | } |
| 121 | |
| 122 | |
| 123 | int main (int argc, char **argv) |
| 124 | { |
| 125 | /* Creation of the window */ |
| 126 | glutInit (&argc, argv); |
| 127 | glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); |
| 128 | glutInitWindowSize (500, 500); |
| 129 | glutCreateWindow ("Render to texture"); |
| 130 | |
| 131 | /* OpenGL settings */ |
| 132 | glEnable (GL_DEPTH_TEST); |
| 133 | |
| 134 | /* Texture setting */ |
| 135 | glEnable (GL_TEXTURE_2D); |
| 136 | glGenTextures (1, &texture_id); |
| 137 | glBindTexture (GL_TEXTURE_2D, texture_id); |
| 138 | glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, SIZE, SIZE, 0, GL_RGB, |
| 139 | GL_UNSIGNED_BYTE, texture); |
| 140 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 141 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 142 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); |
| 143 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); |
| 144 | |
| 145 | /* Declaration of the callbacks */ |
| 146 | glutDisplayFunc (&DisplayFunc); |
| 147 | glutReshapeFunc (&ReshapeFunc); |
| 148 | glutKeyboardFunc (&KeyboardFunc); |
| 149 | |
| 150 | /* Loop */ |
| 151 | glutMainLoop (); |
| 152 | |
| 153 | /* Never reached */ |
| 154 | return 0; |
| 155 | } |
Hope this helps!
Ok, don't know if its what you showed - I reprogrammed my program, that it draw the shadows, then copy it to a buffer texture, draw all my stuff and put the shadow texture on the level. Ok so far. All working fine.
BUT
my fps drops from 150 to 50 and when I use multiple sources (5 monsters that are casting shadows), the game is not playable - 4 fps.
My problem is, that I handle a lot of data
-------
- clear the video to zero
- copy video to shadows bitmap (I have an empty shadows)
for(each monster)
- clear video to light
- add shadows
- add previous shadow bitmap
end for
- clear video
- draw level stuff
- draw shadow bitmap
------------
in this way i have what I wanted - any object can cast light and the lights are ok when two monsters are close to each other, etc.
but erasing©ing over and over the shadow bitmap (using blending) is not usable ..
So is there a way to draw directly to a texture ?
Or have I missunderstand your example ?
(I'm really not skilled in open gl to read your code and be able to say what each of the commands are doing)
Sorry it took me so long to reply.
I was on a vacation.
Anyway, I don't really know what is the cause of your problem, but there are three options I can think of:
1. Your shadow method is slow, so it doesn't work well with many light sources and occluders
2. Your card is old, so render-to-texture is very slow
3. You misunderstood the example code and did something wrong
I won't be surprised if it's the third option, 'cause the example code is pretty bad.
I will try to clarify:
First you need to get a valid OpenGL ID for your framebuffer.
Put this where your program starts:
GLuint framebuffer; glGenFramebuffersEXT(1, &framebuffer);
Then, in the main loop, you render your shadows on the texture:
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, your_lightmap, 0); make_viewport_same_size_as_lightmap(); draw_some_shadows();
Note that in the shadow-drawing function, you need to do everything you would usually do when you draw to the screen. (Clear the color buffer ect.)
Then, you need to switch back to the ordinary screen and draw your scene with the lightmaps.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); make_viewport_the_way_it_was(); render_scene();
And one last thing, don't be surprised if your FPS is 150 with one lightsource and 50 with two.
FPS drops in a very non-linear way, so you can't really measure how good/bad the code you've added is, (unless your FPS drops to 4...
)
But beware that especially NVidia doesn't seem to like supporting framebuffer objects...
But beware that especially NVidia doesn't seem to like supporting framebuffer objects...
What gave you that impression? FBOs are fully supported on all GeForce FX, GeForce 6 and GeForce 7 series of GPUs.
I have a GeForce 5700 LE and they don't do me any trouble.
Mr.Big: thanx for the explanation - I really missunderstood your code 
I'll try it the way you wrote, hope this will help (and my large-texture-moving will not be necessary anymore;)
(BTW I have 5700 too
What gave you that impression? FBOs are fully supported on all GeForce FX, GeForce 6 and GeForce 7 series of GPUs.
I read it from an another thread here. Buf if they are, that's great!