Texture brightness for a 2D sprite

UPDATE: The code below is good. The code I was actually using in my project had texenvi statements being called inside the glBegin which AFAIK isn’t allowed. I blame this on the feature not working, because now everything works fine.

Hello,

A buddy and I are working on a 2D side-scroller. I’m currently experimenting with making the sprites for our enemy entities “Flash” white when hit with a bullet. I’ve done extensive searching and encountered a lot of information on making a texture brighter using the COMBINE and ADD functionality in GL tex env. So far all I have achieved is making the sprites darken. The color range seems to “Cap” at 1.0f, although the posts and tutorials that suggested “ADD” seem to suggest that the range is higher. Here’s our initialization for the GL object, which occurs once at the start of the game:

gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluOrtho2D(0.0, 1440, 0.0, 900);

//set up the viewports
gl.glViewport(0, 0, 1440,900 );

//set up some options
gl.glClearColor(1, 1, 1, 0);
gl.glDisable(gl.GL_DEPTH_TEST);
gl.glEnable(gl.GL_TEXTURE_2D);
gl.glBlendFunc(gl.GL_SRC_ALPHA,gl.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnable(gl.GL_BLEND);

And here is the code that is responsible for texturing and drawing the entities:


if (flashLength > 0)
{ 
     float brightness = 1.5f;
     gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE,GL.GL_COMBINE);            //Need to be in this mode
     
     gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_COLOR, GL.GL_SRC2_RGB);       //Use 0-2 scale???
     gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_RGB_SCALE, GL.GL_OPERAND2_RGB);              //Use 0-2 scale???
     
     gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_COMBINE_RGB, GL.GL_ADD);                           //Add mode needed
     gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_COMBINE_ALPHA,  GL.GL_REPLACE);               //Don't use add mode for alpha
     
     gl.glColor4f(brightness - 1.0f, brightness - 1.0f, brightness - 1.0f, 1.0f);             //Add brightness to RGB, keep alpha the same
     
     gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_SRC0_RGB,         GL.GL_TEXTURE);                 //Set source 1
     gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_SRC1_RGB,         GL.GL_PRIMARY_COLOR);     //Set source 2
     gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_SRC0_ALPHA,       GL.GL_TEXTURE);               //Get texture's alpha
     
      flashLength--;                                                                      //Decrement Flash Length
}
else
{
     //If no flash, modulate and draw the default 
     gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE,GL.GL_MODULATE);
     gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}

//Draw the quad
gl.glBegin(GL.GL_QUADS);                             
  //set the texture coordinates for the next vertex
  gl.glTexCoord2d(0.0, 1.0);
  gl.glVertex2f(x - width/2, y - height/2); //bottom left
  gl.glTexCoord2d(1.0, 1.0);
  gl.glVertex2f(x + width/2,y - height/2);  //bottom right
  gl.glTexCoord2d(1.0, 0.0);
  gl.glVertex2f(x + width/2,y + height/2);  //top right
  gl.glTexCoord2d(0.0, 0.0);
  gl.glVertex2f(x - width/2,y + height/2);  //top left
gl.glEnd();

flashLength is assigned by a collision event in our physics engine and is the duration that the new color settings (white flash) will be applied. Using modulate I can achieve a red tint, but I’m capped in brightness by the texture brightness.

There’s a lot going on there, and I suspect that there’s something wrong with the graphics object not having its settings reset between drawing. We’re completely new to this and have no idea about:

  1. Whether the GL_TEXTURE_ENV adjustments need to be made inside the glBegin
  2. How the ADD setting actually works and if this code is executing that functionality correctly
  3. Any pre-defined environment variables we have forgotten to set in our initialization that make this functionality possible
  4. A whole host of other things, but we’re getting there.

Any help or at least a nudge in the right direction would be appreciated. We’re trying to adjust the brightness of a texture.

EDIT: Should probably clarify that we are using JOGL but were using LWJGL, not sure what was lost in the conversion.

[quote]Using modulate I can achieve a red tint, but I’m capped in brightness by the texture brightness.
[/quote]
I have actually the same problem, although using Slick. I’m not much of a low level OpenGl programmer, so not sure I will even fix it.

Render the sprite on top of the previous one, with:

glBlendFunc(GL_SRC_ALPHA, GL_ONE)

It will use additive blending, so obviously black remain black, but it will result in a pretty nice effect.

So I would literally use the glBegin , vertex code, glEnd twice for each sprite that needs to be flashed? Does this mean scrapping the ADD mode logic all together? Is this the only parameter that would differ?

ie. set the blend func to:
glBlendFunc(GL_SRC_ALPHA, GL_ONE); when I want to render the second “brightness” image
gl.glBlendFunc(gl.GL_SRC_ALPHA,gl.GL_ONE_MINUS_SRC_ALPHA); for everything else

well it does work, but its kinda subtle
doing it many more times helps (drawing it like 100 times more per frame), but obviously thats not how you would do it

any way to intensify the result ?

If I want to really red-out the sprite… now is only a little more redish

like I said each to you draw it it gets better and brighter, but I already use max red

What are you actually executing? Does it have to do with what Riven posted?

I’m trying to draw attention to my original post here, I don’t want anyone helping to get confused. If I get a solution to my problem it will probably work for yours too.

draw Normal sprite
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
draw sprite with red filter

using white, like Rejechted wants, works much better
but I want to completey red-out a sprite when being hit, and then is fades (well maybe not completely, but more than this)

When rendering the image a second time, why not try using glColor4f(1.0f, 0.0f, 0.0f, 1.0f)? Won’t this “Red it out”?

well it adds red
and each consecutive time you draw this again it adds more (actually, if you do it 10 times, thats it, not getting more red)

but you know not enough

I’m sure this has to do with the fact that you cannot lighten an image really…

Actually when I used Java2D I got this working. (Although Java2D is slow of course)

scratchG2d = flashImg.createGraphics();
scratchG2d.setComposite(AlphaComposite.Src);
scratchG2d.setColor(new Color(255,0,0,flashedFrames));
scratchG2d.fillRect(0,0,getAtmVisual().getImageFrame().getWidth(),getAtmVisual().getImageFrame().getHeight());
scratchG2d.setComposite(AlphaComposite.DstAtop);
scratchG2d.drawImage(getAtmVisual().getImageFrame(),0,0,null);
scratchG2d.dispose();
scratchG2d = null;

then you render the original and then “flashImg” over it and there you have it
since flashimg is a red silhouette which fades into transparency

EDIT: “getAtmVisual().getImageFrame()” is obsiously just the original sprite

So if I render my flashimg with the new blend equation, using:

glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

Yes, it’s white, with an alpha of 1.0f, but won’t that also “not be enough” if yours isn’t either? The only difference in that color call is the presence of green and blue.

well obviously I have not enough understanding of how it actually works but, doing it with white 3 times, pretty much makes it all white, not so with red

What glColor function are using and what parameters. Copy paste

How much red you get entirely depends on how much red you had in your original sprite, so it’s not a good way to go if you want to do a redout. It does make a nice flashing effect, though, just not if you want it tinted to a particular color.

You could create a second sprite, which has the same shape, but is all white, and then set the color to red and render it on top of the original - that would give you consistent results. Rendering it once would be enough, since all of its color channels are maxed out. This is simple to do, but requires loading more images, or generating them with your texture loading code.

As an alternative, you could use the destination alpha channel to keep track of the shape of the sprite, and then blend a white quad on top of it while discarding the pixels that are transparent in the sprite.

The rough steps to do that are:

  • Make sure to request 8 bits of destination alpha when creating the Display

When rendering:

  • set glColorMask(false,false,false,true) - this makes rendering only affect the alpha
  • set glColor 0,0,0,0, glBlendFunc to GL_ONE, GL_ZERO and render a quad large enough to cover the area your sprite will be in - this will set destination alpha in the area to 0
  • set glColorMask(true,true,true,true)
  • set glColor to 1,1,1,1
  • Render the original sprite normally - this will render the sprite on the screen, and also render its alpha value
  • set glColor to 1,0,0,1
  • set glBlendFunc to GL_DST_ALPHA, GL_ONE - this will render only in areas where your original sprite wasn’t transparent
  • render a quad, same size as you used to clear the destination alpha - it should add on top of the sprite

You could also use the stencil buffer for this (make sure to request 8 bits of stencil when creating the Display). It’s a similar idea - you draw the shape to the stencil buffer, then use it to discard pixels in subsequent drawing calls. I think that’s a bit tougher to wrap your head around, though, if it’s your first time looking at it.

No insights as to the original stuff that I tried with the brightness variable and end mode? I’m still a bit wonky as to why there are so many ways to do something which seems so simple.

I actually got what I wanted, but not sure it would help as I am using primarily Slick and only rarely direct opengl calls, so… just nevermind me I got it now

Can anyone explain how my code and the code in the brightness function here:

http://developer.apple.com/library/ios/#samplecode/GLImageProcessing/Listings/Imaging_c.html#//apple_ref/doc/uid/DTS40009053-Imaging_c-DontLinkElementID_9

are different, and what’s preventing mine from working?

It’s not the solution to your question, but why not just draw the same image with/without like 50% alpha? It looks fine.

Draw the same image on top of the existing one? I’m afraid to hog resources. I’m aware that this works, though. If you were to draw the same image again with 100% alpha, would you have full white?

No, you wouldn’t.

Think of it in terms of individual pixels.

Say a given pixel is 0,100,200,255 in the image. Drawing it twice (with glBlendFunc GL_SRC_ALPHA, GL_ONE) will double each value - so it’ll be 0,200,255,255.

Now, most colors tend to have non-zero values in each color channel, so it’ll look overall brighter, and will turn white in some places - i.e., where doubling the rgb values gives 255 across the board.

is that the equivalent of increasing saturation?