--- old/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java 2015-03-25 17:43:14.000000000 +0300 +++ new/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java 2015-03-25 17:43:14.000000000 +0300 @@ -371,7 +371,7 @@ super.initializeDesktopProperties(); Map fontHints = new HashMap<>(); fontHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - fontHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + fontHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); desktopProperties.put(SunToolkit.DESKTOPFONTHINTS, fontHints); desktopProperties.put("awt.mouse.numButtons", BUTTONS); --- old/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.m 2015-03-25 17:43:15.000000000 +0300 +++ new/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.m 2015-03-25 17:43:15.000000000 +0300 @@ -311,21 +311,26 @@ jlong *glyphInfos = (*env)->GetPrimitiveArrayCritical(env, glyphInfoLongArray, NULL); - if (glyphInfos != NULL) { - jint *rawGlyphCodes = - (*env)->GetPrimitiveArrayCritical(env, glyphCodes, NULL); - if (rawGlyphCodes != NULL) { + jint *rawGlyphCodes = + (*env)->GetPrimitiveArrayCritical(env, glyphCodes, NULL); + @try { + if (rawGlyphCodes != NULL && glyphInfos != NULL) { CGGlyphImages_GetGlyphImagePtrs(glyphInfos, awtStrike, - rawGlyphCodes, len); - + rawGlyphCodes, len); + } + } + @finally { + if (rawGlyphCodes != NULL) { (*env)->ReleasePrimitiveArrayCritical(env, glyphCodes, - rawGlyphCodes, JNI_ABORT); + rawGlyphCodes, JNI_ABORT); + } + if (glyphInfos != NULL) { + // Do not use JNI_COMMIT, as that will not free the buffer copy + // when +ProtectJavaHeap is on. + (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoLongArray, + glyphInfos, 0); } - // Do not use JNI_COMMIT, as that will not free the buffer copy - // when +ProtectJavaHeap is on. - (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoLongArray, - glyphInfos, 0); } JNF_COCOA_EXIT(env); --- old/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m 2015-03-25 17:43:16.000000000 +0300 +++ new/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m 2015-03-25 17:43:15.000000000 +0300 @@ -48,14 +48,28 @@ * If the necessary canvas is too large, the shared one will not be used and a * temporary one will be provided. */ +typedef enum { + BLACK_ON_WHITE_STAGE, + WHITE_ON_BLACK_STAGE +} CGGI_GlyphRenderingStage; + @interface CGGI_GlyphCanvas : NSObject { @public CGContextRef context; vImage_Buffer *image; + CGGI_GlyphRenderingStage stage; } @end; @implementation CGGI_GlyphCanvas +- (id) init { + if (self = [super init]) { + context = NULL; + image = NULL; + stage = BLACK_ON_WHITE_STAGE; + } + return self; +} @end @@ -199,15 +213,9 @@ static inline void CGGI_CopyARGBPixelToRGBPixel(const UInt32 p, UInt8 *dst) { -#if __LITTLE_ENDIAN__ - *(dst + 2) = 0xFF - (p >> 24 & 0xFF); - *(dst + 1) = 0xFF - (p >> 16 & 0xFF); - *(dst) = 0xFF - (p >> 8 & 0xFF); -#else - *(dst) = 0xFF - (p >> 16 & 0xFF); - *(dst + 1) = 0xFF - (p >> 8 & 0xFF); - *(dst + 2) = 0xFF - (p & 0xFF); -#endif + *(dst + 0) = 0xFF - (p >> 16 & 0xFF); // red + *(dst + 1) = 0xFF - (p >> 8 & 0xFF); // green + *(dst + 2) = 0xFF - (p & 0xFF); // blue } static void @@ -222,20 +230,41 @@ size_t height = info->height; size_t y; - for (y = 0; y < height; y++) { - size_t destRow = y * destRowWidth * 3; - size_t srcRow = y * srcRowWidth; - - size_t x; - for (x = 0; x < destRowWidth; x++) { - // size_t x3 = x * 3; - // UInt32 p = src[srcRow + x]; - // dest[destRow + x3] = 0xFF - (p >> 16 & 0xFF); - // dest[destRow + x3 + 1] = 0xFF - (p >> 8 & 0xFF); - // dest[destRow + x3 + 2] = 0xFF - (p & 0xFF); - CGGI_CopyARGBPixelToRGBPixel(src[srcRow + x], - dest + destRow + x * 3); - } + switch (canvas->stage) { + case BLACK_ON_WHITE_STAGE: + // fill empty glyph image with black-on-white glyph + for (y = 0; y < height; y++) { + size_t destRow = y * destRowWidth * 3; + size_t srcRow = y * srcRowWidth; + + size_t x; + for (x = 0; x < destRowWidth; x++) { + CGGI_CopyARGBPixelToRGBPixel(src[srcRow + x], + dest + destRow + x * 3); + } + } + break; + case WHITE_ON_BLACK_STAGE: + // merge black-on-white glyph (which is already in the glyph image) + // with white-on-black glyph + for (y = 0; y < height; y++) { + size_t destRow = y * destRowWidth * 3; + size_t srcRow = y * srcRowWidth; + + size_t x; + for (x = 0; x < destRowWidth; x++) { + UInt8* pDst = dest + destRow + x * 3; + UInt32 srcPixel = src[srcRow + x]; + + UInt16 r = *(pDst + 0) + (0xff & (srcPixel >> 16)); + *(pDst + 0) = (UInt8)(r >> 1); + UInt16 g = *(pDst + 1) + (0xff & (srcPixel >> 8)); + *(pDst + 1) = (UInt8)(g >> 1); + UInt16 b = *(pDst + 2) + (0xff & (srcPixel )); + *(pDst + 2) = (UInt8)(b >> 1); + } + } + break; } } @@ -260,13 +289,14 @@ //} static inline UInt8 -CGGI_ConvertPixelToGreyBit(UInt32 p) +CGGI_ConvertWBPixelToByteGray(UInt32 p) { + return ((p >> 16 & 0xFF) + (p >> 8 & 0xFF) + (p & 0xFF)) / 3; +} + +static inline UInt8 +CGGI_ConvertBWPixelToByteGray(UInt32 p) { -#ifdef __LITTLE_ENDIAN__ - return 0xFF - ((p >> 24 & 0xFF) + (p >> 16 & 0xFF) + (p >> 8 & 0xFF)) / 3; -#else - return 0xFF - ((p >> 16 & 0xFF) + (p >> 8 & 0xFF) + (p & 0xFF)) / 3; -#endif + return 0xFF - CGGI_ConvertWBPixelToByteGray(p); } static void @@ -281,15 +311,34 @@ size_t height = info->height; size_t y; - for (y = 0; y < height; y++) { - size_t destRow = y * destRowWidth; - size_t srcRow = y * srcRowWidth; - - size_t x; - for (x = 0; x < destRowWidth; x++) { - UInt32 p = src[srcRow + x]; - dest[destRow + x] = CGGI_ConvertPixelToGreyBit(p); - } + switch (canvas->stage) { + case BLACK_ON_WHITE_STAGE: + // fill empty glyph image with black-on-white glyph + for (y = 0; y < height; y++) { + size_t destRow = y * destRowWidth; + size_t srcRow = y * srcRowWidth; + size_t x; + for (x = 0; x < destRowWidth; x++) { + UInt32 p = src[srcRow + x]; + dest[destRow + x] = CGGI_ConvertBWPixelToByteGray(p); + } + } + break; + case WHITE_ON_BLACK_STAGE: + // merge black-on-white glyph (which is already in the glyph image) + // with white-on-black glyph + for (y = 0; y < height; y++) { + size_t destRow = y * destRowWidth; + size_t srcRow = y * srcRowWidth; + + size_t x; + for (x = 0; x < destRowWidth; x++) { + UInt32 p = src[srcRow + x]; + UInt16 gray = dest[destRow + x] + CGGI_ConvertWBPixelToByteGray(p); + dest[destRow + x] = (UInt8)(gray >> 1); + } + } + break; } } @@ -316,13 +365,11 @@ { CGGI_RenderingMode mode; mode.cgFontMode = strike->fStyle; + NSException *e = nil; switch (strike->fAAStyle) { - case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_OFF: case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON: - case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP: - default: mode.glyphDescriptor = &grey; break; case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB: @@ -331,6 +378,14 @@ case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_VBGR: mode.glyphDescriptor = &rgb; break; + case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP: + case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT: + default: + e = [NSException + exceptionWithName:@"IllegalArgumentException" + reason:@"Invalid hint value" + userInfo:nil]; + @throw e; } return mode; @@ -345,7 +400,8 @@ */ static inline void CGGI_InitCanvas(CGGI_GlyphCanvas *canvas, - const vImagePixelCount width, const vImagePixelCount height) + const vImagePixelCount width, const vImagePixelCount height, + const CGGI_RenderingMode* mode) { // our canvas is *always* 4-byte ARGB size_t bytesPerRow = width * sizeof(UInt32); @@ -356,19 +412,28 @@ canvas->image->height = height; canvas->image->rowBytes = bytesPerRow; - canvas->image->data = (void *)calloc(byteCount, sizeof(UInt32)); + canvas->image->data = (void *)calloc(byteCount, sizeof(UInt8)); if (canvas->image->data == NULL) { [[NSException exceptionWithName:NSMallocException reason:@"Failed to allocate memory for the buffer which backs the CGContext for glyph strikes." userInfo:nil] raise]; } + canvas->stage = BLACK_ON_WHITE_STAGE; + + uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst; + if (mode->glyphDescriptor == &rgb) { + bmpInfo |= kCGBitmapByteOrder32Host; + } + CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); canvas->context = CGBitmapContextCreate(canvas->image->data, width, height, 8, bytesPerRow, colorSpace, - kCGImageAlphaPremultipliedFirst); + bmpInfo); + // set foreground color CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f); + CGContextSetFontSize(canvas->context, 1); CGContextSaveGState(canvas->context); @@ -404,7 +469,9 @@ * Quick and easy inline to check if this canvas is big enough. */ static inline void -CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width, const vImagePixelCount height, const JRSFontRenderingStyle style) +CGGI_SizeCanvas(CGGI_GlyphCanvas *canvas, const vImagePixelCount width, + const vImagePixelCount height, + const CGGI_RenderingMode* mode) { if (canvas->image != NULL && width < canvas->image->width && @@ -418,8 +485,9 @@ CGGI_FreeCanvas(canvas); CGGI_InitCanvas(canvas, width * CGGI_GLYPH_CANVAS_SLACK, - height * CGGI_GLYPH_CANVAS_SLACK); - JRSFontSetRenderingStyleOnContext(canvas->context, style); + height * CGGI_GLYPH_CANVAS_SLACK, + mode); + JRSFontSetRenderingStyleOnContext(canvas->context, mode->cgFontMode); } /* @@ -439,11 +507,24 @@ // clean the canvas #ifdef CGGI_DEBUG Pixel_8888 opaqueWhite = { 0xE0, 0xE0, 0xE0, 0xE0 }; + Pixel_8888 opaqueBlack = { 0x10, 0x10, 0x10, 0xF0 }; #else Pixel_8888 opaqueWhite = { 0xFF, 0xFF, 0xFF, 0xFF }; + Pixel_8888 opaqueBlack = { 0x00, 0x00, 0x00, 0xFF }; #endif - vImageBufferFill_ARGB8888(&canvasRectToClear, opaqueWhite, kvImageNoFlags); + // clear canvas background and set foreground color + switch(canvas->stage) { + case BLACK_ON_WHITE_STAGE: + vImageBufferFill_ARGB8888(&canvasRectToClear, opaqueWhite, kvImageNoFlags); + CGContextSetRGBFillColor(canvas->context, 0.0f, 0.0f, 0.0f, 1.0f); + break; + case WHITE_ON_BLACK_STAGE: + vImageBufferFill_ARGB8888(&canvasRectToClear, opaqueBlack, kvImageNoFlags); + CGContextSetRGBFillColor(canvas->context, 1.0f, 1.0f, 1.0f, 1.0f); + break; + } + CGContextSaveGState(canvas->context); } @@ -577,7 +658,7 @@ GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, mode); // fix the context size, just in case the substituted character is unexpectedly large - CGGI_SizeCanvas(canvas, info->width, info->height, mode->cgFontMode); + CGGI_SizeCanvas(canvas, info->width, info->height, mode); // align the transform for the real CoreText strike CGContextSetTextMatrix(canvas->context, strike->fAltTx); @@ -653,8 +734,11 @@ #endif } -static NSString *threadLocalCanvasKey = - @"Java CoreGraphics Text Renderer Cached Canvas"; +static NSString *threadLocalAACanvasKey = + @"Java CoreGraphics Text Renderer Cached Canvas for AA"; + +static NSString *threadLocalLCDCanvasKey = + @"Java CoreGraphics Text Renderer Cached Canvas for LCD"; /* * This is the maximum length and height times the above slack squared @@ -678,7 +762,14 @@ CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_MAX*CGGI_GLYPH_CANVAS_SLACK*CGGI_GLYPH_CANVAS_SLACK) { CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init]; - CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight); + CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight, mode); + // create black-on-white glyph image + CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike, + mode, glyphInfos, uniChars, + glyphs, len); + + // merge glyph image with white-on-black glyph + tmpCanvas->stage = WHITE_ON_BLACK_STAGE; CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike, mode, glyphInfos, uniChars, glyphs, len); @@ -687,18 +778,29 @@ [tmpCanvas release]; return; } - NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary]; - CGGI_GlyphCanvas *canvas = [threadDict objectForKey:threadLocalCanvasKey]; + + NSString* theKey = (mode->glyphDescriptor == &rgb) ? + threadLocalLCDCanvasKey : threadLocalAACanvasKey; + + CGGI_GlyphCanvas *canvas = [threadDict objectForKey:theKey]; if (canvas == nil) { canvas = [[CGGI_GlyphCanvas alloc] init]; - [threadDict setObject:canvas forKey:threadLocalCanvasKey]; + [threadDict setObject:canvas forKey:theKey]; } - CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode->cgFontMode); + CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode); + // create black-on-white glyph image + canvas->stage = BLACK_ON_WHITE_STAGE; CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode, glyphInfos, uniChars, glyphs, len); + + // merge glyph image with white-on-black glyph + canvas->stage = WHITE_ON_BLACK_STAGE; + CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode, + glyphInfos, uniChars, glyphs, len); + } /* --- old/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java 2015-03-25 17:43:16.000000000 +0300 +++ new/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java 2015-03-25 17:43:16.000000000 +0300 @@ -25,10 +25,7 @@ package sun.java2d.opengl; -import java.awt.AlphaComposite; -import java.awt.GraphicsEnvironment; -import java.awt.Rectangle; -import java.awt.Transparency; +import java.awt.*; import java.awt.image.ColorModel; import java.awt.image.Raster; import sun.awt.SunHints; @@ -400,9 +397,8 @@ /** * For now, we can only render LCD text if: * - the fragment shader extension is available, and - * - blending is disabled, and - * - the source color is opaque - * - and the destination is opaque + * - the source color is opaque, and + * - blending is SrcOverNoEa or disabled * * Eventually, we could enhance the native OGL text rendering code * and remove the above restrictions, but that would require significantly @@ -411,9 +407,19 @@ public boolean canRenderLCDText(SunGraphics2D sg2d) { return graphicsConfig.isCapPresent(CAPS_EXT_LCD_SHADER) && - sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && + sg2d.surfaceData.getTransparency() == Transparency.OPAQUE && sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR && - sg2d.surfaceData.getTransparency() == Transparency.OPAQUE; + (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY || + (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA && canHandleComposite(sg2d.composite))); + } + + private boolean canHandleComposite(Composite c) { + if (c instanceof AlphaComposite) { + AlphaComposite ac = (AlphaComposite)c; + + return ac.getRule() == AlphaComposite.SRC_OVER && ac.getAlpha() >= 1f; + } + return false; } public void validatePipe(SunGraphics2D sg2d) { --- old/src/java.desktop/share/native/common/java2d/opengl/OGLTextRenderer.c 2015-03-25 17:43:17.000000000 +0300 +++ new/src/java.desktop/share/native/common/java2d/opengl/OGLTextRenderer.c 2015-03-25 17:43:17.000000000 +0300 @@ -299,8 +299,8 @@ "uniform vec3 src_adj;" "uniform sampler2D glyph_tex;" "uniform sampler2D dst_tex;" - "uniform sampler3D invgamma_tex;" - "uniform sampler3D gamma_tex;" + "uniform vec3 gamma;" + "uniform vec3 invgamma;" "" "void main(void)" "{" @@ -313,11 +313,11 @@ // load the RGB value from the corresponding destination pixel " vec3 dst_clr = vec3(texture2D(dst_tex, gl_TexCoord[1].st));" // gamma adjust the dest color using the invgamma LUT - " vec3 dst_adj = vec3(texture3D(invgamma_tex, dst_clr.stp));" + " vec3 dst_adj = pow(dst_clr.rgb, invgamma);" // linearly interpolate the three color values " vec3 result = mix(dst_adj, src_adj, glyph_clr);" // gamma re-adjust the resulting color (alpha is always set to 1.0) - " gl_FragColor = vec4(vec3(texture3D(gamma_tex, result.stp)), 1.0);" + " gl_FragColor = vec4(pow(result.rgb, gamma), 1.0);" "}"; /** @@ -348,11 +348,7 @@ j2d_glUniform1iARB(loc, 0); // texture unit 0 loc = j2d_glGetUniformLocationARB(lcdTextProgram, "dst_tex"); j2d_glUniform1iARB(loc, 1); // texture unit 1 - loc = j2d_glGetUniformLocationARB(lcdTextProgram, "invgamma_tex"); - j2d_glUniform1iARB(loc, 2); // texture unit 2 - loc = j2d_glGetUniformLocationARB(lcdTextProgram, "gamma_tex"); - j2d_glUniform1iARB(loc, 3); // texture unit 3 - + // "unuse" the program object; it will be re-bound later as needed j2d_glUseProgramObjectARB(0); @@ -360,56 +356,10 @@ } /** - * Initializes a 3D texture object for use as a three-dimensional gamma - * lookup table. Note that the wrap mode is initialized to GL_LINEAR so - * that the table will interpolate adjacent values when the index falls - * somewhere in between. - */ -static GLuint -OGLTR_InitGammaLutTexture() -{ - GLuint lutTextureID; - - j2d_glGenTextures(1, &lutTextureID); - j2d_glBindTexture(GL_TEXTURE_3D, lutTextureID); - j2d_glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - j2d_glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - j2d_glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - j2d_glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - j2d_glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - return lutTextureID; -} - -/** - * Updates the lookup table in the given texture object with the float - * values in the given system memory buffer. Note that we could use - * glTexSubImage3D() when updating the texture after its first - * initialization, but since we're updating the entire table (with - * power-of-two dimensions) and this is a relatively rare event, we'll - * just stick with glTexImage3D(). - */ -static void -OGLTR_UpdateGammaLutTexture(GLuint texID, GLfloat *lut, jint size) -{ - j2d_glBindTexture(GL_TEXTURE_3D, texID); - j2d_glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB8, - size, size, size, 0, GL_RGB, GL_FLOAT, lut); -} - -/** - * (Re)Initializes the gamma lookup table textures. + * (Re)Initializes the gamma related uniforms. * * The given contrast value is an int in the range [100, 250] which we will - * then scale to fit in the range [1.0, 2.5]. We create two LUTs, one - * that essentially calculates pow(x, gamma) and the other calculates - * pow(x, 1/gamma). These values are replicated in all three dimensions, so - * given a single 3D texture coordinate (typically this will be a triplet - * in the form (r,g,b)), the 3D texture lookup will return an RGB triplet: - * - * (pow(r,g), pow(y,g), pow(z,g) - * - * where g is either gamma or 1/gamma, depending on the table. + * then scale to fit in the range [1.0, 2.5]. */ static jboolean OGLTR_UpdateLCDTextContrast(jint contrast) @@ -417,51 +367,16 @@ double gamma = ((double)contrast) / 100.0; double ig = gamma; double g = 1.0 / ig; - GLfloat lut[LUT_EDGE][LUT_EDGE][LUT_EDGE][3]; - GLfloat invlut[LUT_EDGE][LUT_EDGE][LUT_EDGE][3]; - int min = 0; - int max = LUT_EDGE - 1; - int x, y, z; + GLint loc; J2dTraceLn1(J2D_TRACE_INFO, "OGLTR_UpdateLCDTextContrast: contrast=%d", contrast); + + loc = j2d_glGetUniformLocationARB(lcdTextProgram, "gamma"); + j2d_glUniform3fARB(loc, g, g, g); - for (z = min; z <= max; z++) { - double zval = ((double)z) / max; - GLfloat gz = (GLfloat)pow(zval, g); - GLfloat igz = (GLfloat)pow(zval, ig); - - for (y = min; y <= max; y++) { - double yval = ((double)y) / max; - GLfloat gy = (GLfloat)pow(yval, g); - GLfloat igy = (GLfloat)pow(yval, ig); - - for (x = min; x <= max; x++) { - double xval = ((double)x) / max; - GLfloat gx = (GLfloat)pow(xval, g); - GLfloat igx = (GLfloat)pow(xval, ig); - - lut[z][y][x][0] = gx; - lut[z][y][x][1] = gy; - lut[z][y][x][2] = gz; - - invlut[z][y][x][0] = igx; - invlut[z][y][x][1] = igy; - invlut[z][y][x][2] = igz; - } - } - } - - if (gammaLutTextureID == 0) { - gammaLutTextureID = OGLTR_InitGammaLutTexture(); - } - OGLTR_UpdateGammaLutTexture(gammaLutTextureID, (GLfloat *)lut, LUT_EDGE); - - if (invGammaLutTextureID == 0) { - invGammaLutTextureID = OGLTR_InitGammaLutTexture(); - } - OGLTR_UpdateGammaLutTexture(invGammaLutTextureID, - (GLfloat *)invlut, LUT_EDGE); + loc = j2d_glGetUniformLocationARB(lcdTextProgram, "invgamma"); + j2d_glUniform3fARB(loc, ig, ig, ig); return JNI_TRUE; } @@ -478,7 +393,7 @@ static jboolean OGLTR_UpdateLCDTextColor(jint contrast) { - double gamma = ((double)contrast) / 100.0; + double invgamma = ((double)contrast) / 100; GLfloat radj, gadj, badj; GLfloat clr[4]; GLint loc; @@ -499,9 +414,9 @@ j2d_glGetFloatv(GL_CURRENT_COLOR, clr); // gamma adjust the primary color - radj = (GLfloat)pow(clr[0], gamma); - gadj = (GLfloat)pow(clr[1], gamma); - badj = (GLfloat)pow(clr[2], gamma); + radj = (GLfloat)pow(clr[0], invgamma); + gadj = (GLfloat)pow(clr[1], invgamma); + badj = (GLfloat)pow(clr[2], invgamma); // update the "src_adj" parameter of the shader program with this value loc = j2d_glGetUniformLocationARB(lcdTextProgram, "src_adj");