Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (541)
Games in Android Showcase (133)
games submitted by our members
Games in WIP (603)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Libgdx overcoming color limitations?  (Read 2293 times)
0 Members and 1 Guest are viewing this topic.
Offline trollwarrior1
« Posted 2014-01-16 10:33:52 »

Soooo here I'm yet again asking questions about Libgdx..

When I was using LWJGL, you could pass in any floats as color parameters (r = 10f, g = 1f, b = 1f), and it would work. The image would be really bright red color.
But now that I'm using Libgdx, I'm setting color in SpriteBatch.setColor(r,g,b,a) method. Libgdx only supports 0-1 floats. Is there a way to overcome this? I would like to make certain sprites 2x brighter than they are. I hope there is a way to overcome this limitation..
Offline junkdog
« Reply #1 - Posted 2014-01-16 11:36:08 »

What's wrong with
1  
color.set(1f, .1f, .1f, 1f)


or, if you just want to make certain colors brighter:

1  
color.mul(2f, 1f, 1f, 1f)

artemis-odb: bugfixing and performance optimized fork of artemis ECS
Offline trollwarrior1
« Reply #2 - Posted 2014-01-16 11:50:20 »

This doesn't work, because color itself only accepts values 0-1. I can't make stuff brighter than the original texture. You can make stuff White and Yellow only using LWJGL.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline xsvenson
« Reply #3 - Posted 2014-01-16 12:01:41 »

The color, You add to SpriteBatch is a "tint" not an "abosolute" color. This means that the sprite and color are blended together.
LibGDX uses shaders and looking at the SpriteBatch shader, the colors are multiplied "gl_FragColor = v_color * texture2D(u_texture, v_texCoords);"

So what You can do. You can modify Your sprite (externally or at runtime) to make it brither (add more white). Or You could write Your own shader, that gives You more control over the colors.

Edit: Colors have 4 channels, 1 byte per channel. As a float, the channel values range from 0f (nothing) to 1f (everything). As such, 10f does not sense make any.

“The First Rule of Program Optimization: Don't do it. The Second Rule of Program Optimization (for experts only!): Don't do it yet.” - Michael A. Jackson
Offline trollwarrior1
« Reply #4 - Posted 2014-01-16 12:03:07 »

I just don't get it.
As Libgdx developer, why would you go through the pain of limiting colors only  to 0-1f ?
Is there any benefit in doing so?
Offline xsvenson
« Reply #5 - Posted 2014-01-16 12:05:39 »

Sorry, I edited my reply (touching the subject of colors) while You asked the last question.
10f does not have a meaning in color channel, since 1f is the max.

“The First Rule of Program Optimization: Don't do it. The Second Rule of Program Optimization (for experts only!): Don't do it yet.” - Michael A. Jackson
Offline gouessej
« Reply #6 - Posted 2014-01-16 13:20:28 »

I just don't get it.
As Libgdx developer, why would you go through the pain of limiting colors only  to 0-1f ?
Is there any benefit in doing so?
Floating-point values of OpenGL colors are clamped to the range [0, 1] and LibGDX has several backends based on OpenGL through LWJGL, Android GL and JogAmp (JOGL). The range of the "tint" color is larger. If you don't understand xsvenson's explanation and mine, maybe you should learn the basics before using LibGDX.

Offline davedes
« Reply #7 - Posted 2014-01-16 15:19:09 »

LibGDX packs the RGBA components into a single float, and sends it along the pipeline. This is much faster than sending four floats (R, G, B, A) to the vertex shader. Unfortunately, this means that OpenGL will "normalize" the value in the range 0.0 to 1.0.

One option is to add a uniform value for "brightness." See here. This is useful if you have a whole bunch of sprites that need the same brightness value. This should probably be fast enough for most use cases.

If you need better performance (e.g. per-sprite brightness), you should use a vertex attribute for brightness, instead of a uniform (so it can be batched). You basically have two options. Either you hack it, or you re-implement SpriteBatcher to have a proper brightness attribute.

To hack it, you could pass in a U texture coordinate larger than 1.0, and in the vertex shader, the brightness is taken from the integral part of the coordinate, and the actual U coordinate is the fractional
fract(..)
. Then you send both of those along to your fragment shader. This means no "texture repeat" wrapping (which is pretty rare in 2D games, anyways).

The "proper" solution is to have a brightness attribute in your sprite batcher; but this is more work. You'd have to implement the Batch interface, copy over most of SpriteBatch's code, and then add in the extra vertex attributes. Read more about working with mesh here.

And if you are just looking to change the brightness of the whole screen (rather than individual sprites), you should just use shaders and a post-processing step.

Cheers.

Offline theagentd

« JGO Bitwise Duke »


Medals: 366
Projects: 2
Exp: 8 years



« Reply #8 - Posted 2014-01-16 16:26:33 »

I just don't get it.
As Libgdx developer, why would you go through the pain of limiting colors only  to 0-1f ?
Is there any benefit in doing so?
Floating-point values of OpenGL colors are clamped to the range [0, 1] and LibGDX has several backends based on OpenGL through LWJGL, Android GL and JogAmp (JOGL). The range of the "tint" color is larger. If you don't understand xsvenson's explanation and mine, maybe you should learn the basics before using LibGDX.
I don't know much about LibGDX, but this is completely unrelated to OpenGL limitations.

When using fixed functionality, you can disable the clamping by calling:
1  
glClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE);


When using shaders, there's no such limitation. The normalized attribute of glVertexAttribPointer() has no effect on data already in floating point format.
Quote
For glVertexAttribPointer, if normalized is set to GL_TRUE, it indicates that values stored in an integer format are to be mapped to the range [-1,1] (for signed values) or [0,1] (for unsigned values) when they are accessed and converted to floating point.
Therefore, the only reason for values to be clamped to [0.0,1.0] would be if LibGDX either implements the clamping itself or if LibGDX converts the floats supplied to unsigned bytes (the last one is true according to Davedes).

It's obvious why TrollWarrior1 would call out on this when OpenGL doesn't have this problem with neither fixed functionality nor with shaders when using floats. I wouldn't call an implementation detail "the basics".


EDIT:
And if you are just looking to change the brightness of the whole screen (rather than individual sprites), you should just use shaders and a post-processing step.
I would not recommend that. Even "modest" brightness increases will reduce the effective bit depth a lot. To show this, I drew a gradient in Paint.NET, multiplied it by 0.25 and then by 4.0 to bring it back to its original form. That's the same as rendering a 0.25 sprite and then postprocessing it up to 1.0 by multiplying by 4.0.

We effectively killed 2 bits of information, so we get a 6-bit gradient with only 64 possible values instead of 256.

Myomyomyo.
Offline trollwarrior1
« Reply #9 - Posted 2014-01-16 19:55:40 »

Soo I came up with this method. You lose a little bit of colors, but the effect is the same as LWJGL above 1f color components.

In your vertex shader, multiply your fragColor by some kind of vec4 shade(?) :
1  
fragColor = a_color * vec4(2.,2.,2.,2.)


This will make everything very bright.
Now, when you send color components to Libgdx SpriteBatch, divide them by the floats you put in the vertex shader. So in this case divide all components you send to SpriteBatch by 2.
1  
spriteBatch.setColor(myColor.r / 2, myColor.g / 2, myColor.b / 2, myColor.a / 2);

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline theagentd

« JGO Bitwise Duke »


Medals: 366
Projects: 2
Exp: 8 years



« Reply #10 - Posted 2014-01-16 22:02:41 »

You're still losing a bit of precision since you're using an 8-bit precision color mapped to 512 values (0 - 2) instead of 256 values (0 - 1), but in contrast to the fullscreen pass version you only lose the precision of the actual a_color variable so I seriously doubt it'll have a visible impact.

Myomyomyo.
Offline Nate

« JGO Bitwise Duke »


Medals: 158
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #11 - Posted 2014-01-17 02:29:12 »

Fun fact, libgdx encodes an ABGR int color as a float but the high bits are masked with 0xfeffffff to avoid using floats in the NaN range (see Float#intBitsToFloat). This means packed color floats aren't completely opaque! The reason is that floats in the NaN range can't be converted back to int. If you know you won't convert a color float to an int, you can disable the mask using NumberUtils.intToFloatColorMask = false. Eg, Spine uses an FBO for image export, so if I do this to get proper colors.

Offline trollwarrior1
« Reply #12 - Posted 2014-01-17 05:30:30 »

You're still losing a bit of precision since you're using an 8-bit precision color mapped to 512 values (0 - 2) instead of 256 values (0 - 1), but in contrast to the fullscreen pass version you only lose the precision of the actual a_color variable so I seriously doubt it'll have a visible impact.

Ummm, you lose color precision in paper. In reality, all I do with colors is like 0.5f or 0.55f. There is like no visible difference Tongue
Offline theagentd

« JGO Bitwise Duke »


Medals: 366
Projects: 2
Exp: 8 years



« Reply #13 - Posted 2014-01-17 16:55:15 »

Ummm, you lose color precision in paper. In reality, all I do with colors is like 0.5f or 0.55f. There is like no visible difference Tongue
Yeah, that was my point. ^^ Just wanted to point out that there still was a loss in precision, but that it's much better than a fullscreen pass.

Myomyomyo.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 847
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #14 - Posted 2014-01-17 17:33:39 »

Fun fact, libgdx encodes an ABGR int color as a float but the high bits are masked with 0xfeffffff to avoid using floats in the NaN range (see Float#intBitsToFloat). This means packed color floats aren't completely opaque! The reason is that floats in the NaN range can't be converted back to int. If you know you won't convert a color float to an int, you can disable the mask using NumberUtils.intToFloatColorMask = false. Eg, Spine uses an FBO for image export, so if I do this to get proper colors.

I don't quite get it... Yes, there is a NaN problem, but this int (or 4-byte) -> float 'packing' is just another interpretation of bits (it would be a union in C). This means there is no conversion whatsoever, even when going from floats to ints, when using Float.floatToRawIntBits(float).

So... there is no need for this masking... right? As you might expect I didn't even test it because I'm rather... confident.

Ignore the java sourcecode of these methods (if any), the JVM completely ignores it and uses a union, which means it's basically a no-op. It tells the JIT that it can from now on interpret that register as another data-type.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline badlogicgames

« JGO Bitwise Duke »


Medals: 74
Projects: 2



« Reply #15 - Posted 2014-01-17 22:36:37 »

We pack the 32-bit int into a float. Not the other way around. Reason: vertices are stored in a float array, then copied to a direct buffer. Why not go with the direct buffer only? Cause Android is a turd, the direct buffer implementation is broken, and crossing the native/VM bridge for every int/float/byte costs to much compared to composing the data in primitive arrays then copying it to a direct buffer, then uploading it to the GPU. It's sad really.

edit: actually, those methods going from int to float do modify the value, they aren't NOPs.
edit2: what you said makes total sense, so i wrote a tiny little test http://ideone.com/UEy4vA it's been a very long time since we worked on this, and i can't remember why we had to mask things.

http://www.badlogicgames.com - musings on Android and Java game development
Offline Nate

« JGO Bitwise Duke »


Medals: 158
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #16 - Posted 2014-01-17 23:15:48 »

I don't quite get it... Yes, there is a NaN problem, but this int (or 4-byte) -> float 'packing' is just another interpretation of bits (it would be a union in C). This means there is no conversion whatsoever, even when going from floats to ints, when using Float.floatToRawIntBits(float).

1  
2  
3  
4  
5  
int intColor = 0xff800001;
float floatColor = Float.intBitsToFloat(intColor);
int intColor2 = Float.floatToRawIntBits(floatColor);
System.out.println(Integer.toHexString(intColor)); // ff800001
System.out.println(Integer.toHexString(intColor2)); // ffc00001

Offline badlogicgames

« JGO Bitwise Duke »


Medals: 74
Projects: 2



« Reply #17 - Posted 2014-01-17 23:19:29 »

Good, i thought i needed my crazy pills again... http://ideone.com/2mP7Tb

http://www.badlogicgames.com - musings on Android and Java game development
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 847
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #18 - Posted 2014-01-18 10:27:27 »

We stumbled on a serious JVM bug, then Smiley

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
      System.out.println("Java version: "+System. getProperty("java.version"));
      System.out.println("JVM name: "+System.getProperty("java.vm.name"));
      System.out.println("JVM version: "+System.getProperty("java.vm.version"));
      System.out.println();
     
      int i1 = 0xff800001;
      float f = Float.intBitsToFloat(i1);
      int i2 = Float.floatToRawIntBits(f);
      System.out.println(Integer.toHexString(i1));
      System.out.println(Integer.toHexString(i2));


(Eclipse)
1  
2  
3  
4  
5  
6  
Java version: 1.7.0_25
JVM name: Java HotSpot(TM) 64-Bit Server VM
JVM version: 23.25-b01

ff800001
ff800001



http://ideone.com/tSN70r
1  
2  
3  
4  
5  
6  
Java version: 1.7.0_25
JVM name: Java HotSpot(TM) Client VM
JVM version: 23.25-b01

ff800001
ffc00001

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline princec

« JGO Spiffy Duke »


Medals: 437
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #19 - Posted 2014-01-18 10:54:27 »

Oh dear. Still broken in client _51 just released the other day, too.

Cas Smiley

Offline badlogicgames

« JGO Bitwise Duke »


Medals: 74
Projects: 2



« Reply #20 - Posted 2014-01-18 13:23:48 »

There seems to be more going on. I remember writting a simple JNI method to replace intToFloat, but the JNI bridge seemed to have inserted some magic that checks for NaN and modifies the value.

Also, this behaviour is not limited to Oracle's VM. Dalvik exhibits the same behaviour, and that uses a modified Harmony class library. Can anyone try with Excelsior?

Who's gonna flip the bat sign switch?

http://www.badlogicgames.com - musings on Android and Java game development
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 847
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #21 - Posted 2014-01-18 13:28:58 »

It's too bad we can't do this on a register (like a C union is compiled to):

1  
2  
unsafe.putInt(register, val);
return unsafe.getFloat(register);


and that non-bulk Unsafe memory operation are not available on Android.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline Nate

« JGO Bitwise Duke »


Medals: 158
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #22 - Posted 2014-01-18 15:18:20 »

Don't think it's a bug, behavior is documented in intBitsToFloat javadocs:
http://docs.oracle.com/javase/7/docs/api/java/lang/Float.html#intBitsToFloat(int)

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Mr.CodeIt (24 views)
2014-12-23 03:34:11

rwatson462 (54 views)
2014-12-15 09:26:44

Mr.CodeIt (45 views)
2014-12-14 19:50:38

BurntPizza (85 views)
2014-12-09 22:41:13

BurntPizza (110 views)
2014-12-08 04:46:31

JscottyBieshaar (79 views)
2014-12-05 12:39:02

SHC (89 views)
2014-12-03 16:27:13

CopyableCougar4 (97 views)
2014-11-29 21:32:03

toopeicgaming1999 (155 views)
2014-11-26 15:22:04

toopeicgaming1999 (153 views)
2014-11-26 15:20:36
Resources for WIP games
by kpars
2014-12-18 10:26:14

Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!