From 16e1d44cdb158c69e0d3bc5d89586eea43463fab Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Tue, 27 May 2003 14:12:10 +0000 Subject: [PATCH] Implemented gamma, brightness and contrast controls on win32 and linux using a simplified gamma ramp API --- src/java/org/lwjgl/Display.java | 74 +++++--- .../lwjgl/test/DisplayConfigurationTest.java | 44 +++++ src/native/common/org_lwjgl_Display.h | 14 +- src/native/linux/org_lwjgl_Display.cpp | 160 ++++++++++++++---- src/native/win32/org_lwjgl_Display.cpp | 118 +++---------- 5 files changed, 241 insertions(+), 169 deletions(-) create mode 100644 src/java/org/lwjgl/test/DisplayConfigurationTest.java diff --git a/src/java/org/lwjgl/Display.java b/src/java/org/lwjgl/Display.java index 4b0c93e8..ac613710 100644 --- a/src/java/org/lwjgl/Display.java +++ b/src/java/org/lwjgl/Display.java @@ -34,6 +34,9 @@ package org.lwjgl; import java.util.HashSet; import java.util.Arrays; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.ByteOrder; /** * $Id$ @@ -201,34 +204,51 @@ public final class Display { public static native int getPlatform(); /** - * Obtains the display's gamma ramp. The gamma ramp returned is an array of - * 16:16 fixed point values representing 0.0...1.0. The gamma ramp consists of three - * arrays, one for red, one for green, and one for blue. The array lengths must be 256. - * - * If gamma is not supported by the underlying hardware then false is returned. - * - * @param red An array of ints to store red gamma in. Must be 256 in length. - * @param green An array of ints to store green gamma in. Must be 256 in length. - * @param blue An array of ints to store blue gamma in. Must be 256 in length. - * @return true if it succeeds, false if it fails - */ - public static native boolean getGammaRamp(int[] red, int[] green, int[] blue); - - /** - * Sets the display's gamma ramp. The gamma ramp should be an array of ints - * in 16:16 fixed point format, arranged as for getGammaRamp(). - * The length of the arrays must be 256. - * - * If the underlying hardware does not support gamma then this command is a no-op. - * - * When resetDisplaMode is called, any gamma changes are automatically undone. + * Set the display configuration to the specified gamma, brightness and contrast. + * The configuration changes will be reset when resetDisplayMode is called. * - * @param red An array of ints to store red gamma in. Must be 256 in length. - * @param green An array of ints to store green gamma in. Must be 256 in length. - * @param blue An array of ints to store blue gamma in. Must be 256 in length. - * - * @return true if it succeeds, false if it fails + * @param gamma The gamma value + * @param brightness The brightness value between -1.0 and 1.0, inclusive + * @param contrast The contrast, larger than 0.0. + * @return true if the call succeeded, false otherwise */ - public static native boolean setGammaRamp(int[] red, int[] green, int[] blue); + public static boolean setDisplayConfiguration(float gamma, float brightness, float contrast) { + assert brightness >= -1.0f && brightness <= 1.0f; + assert contrast >= 0.0f; + int rampSize = getGammaRampLength(); + if (rampSize == 0) + return false; + FloatBuffer gammaRamp = ByteBuffer.allocateDirect(rampSize*4).order(ByteOrder.nativeOrder()).asFloatBuffer(); + for (int i = 0; i < rampSize; i++) { + float intensity = (float)i/(rampSize - 1); + // apply gamma + float rampEntry = (float)java.lang.Math.pow(intensity, gamma); + // apply brightness + rampEntry += brightness; + // apply contrast + rampEntry = (rampEntry - 0.5f)*contrast + 0.5f; + // Clamp entry to [0, 1] + if (rampEntry > 1.0f) + rampEntry = 1.0f; + else if (rampEntry < 0.0f) + rampEntry = 0.0f; + gammaRamp.put(i, rampEntry); + } + if (!setGammaRamp(Sys.getDirectBufferAddress(gammaRamp))) + return false; + return true; + } + /** + * Return the length of the gamma ramp arrays. Returns 0 if gamma settings are + * unsupported. + * + * @return the length of each gamma ramp array, or 0 if gamma settings are unsupported. + */ + private static native int getGammaRampLength(); + + /** + * Native method to set the gamma ramp. + */ + private static native boolean setGammaRamp(int gammaRampAddress); } diff --git a/src/java/org/lwjgl/test/DisplayConfigurationTest.java b/src/java/org/lwjgl/test/DisplayConfigurationTest.java new file mode 100644 index 00000000..e95cff55 --- /dev/null +++ b/src/java/org/lwjgl/test/DisplayConfigurationTest.java @@ -0,0 +1,44 @@ +/* + * Created on 18-03-2003 + * + * To change this generated comment go to + * Window>Preferences>Java>Code Generation>Code Template + */ +package org.lwjgl.test; + +import org.lwjgl.*; +import org.lwjgl.opengl.GL; + +/** + * @author Elias Naur + */ +public class DisplayConfigurationTest { + private static void changeConfig(float gamma, float brightness, float contrast) { + Display.setDisplayConfiguration(gamma, brightness, contrast); + System.out.println("Configuration changed, gamma = " + gamma + " brightness = " + brightness + " contrast = " + contrast); + try { + Thread.sleep(3000); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void main(String[] args) { + System.out.println("Testing normal setting"); + changeConfig(1.0f, 0f, 1f); + System.out.println("Testing gamma settings"); + changeConfig(5.0f, 0f, 1f); + changeConfig(0.5f, 0f, 1f); + System.out.println("Testing brightness settings"); + changeConfig(1.0f, -1.0f, 1f); + changeConfig(1.0f, -0.5f, 1f); + changeConfig(1.0f, 0.5f, 1f); + changeConfig(1.0f, 1.0f, 1f); + System.out.println("Testing contrast settings"); + changeConfig(1.0f, 0f, 0f); + changeConfig(1.0f, 0f, 0.5f); + changeConfig(1.0f, 0f, 10000.0f); + System.out.println("Test done - Resetting configuration"); + Display.resetDisplayMode(); + } +} diff --git a/src/native/common/org_lwjgl_Display.h b/src/native/common/org_lwjgl_Display.h index 3b9e5d1b..d2290406 100644 --- a/src/native/common/org_lwjgl_Display.h +++ b/src/native/common/org_lwjgl_Display.h @@ -18,7 +18,7 @@ extern "C" { #define org_lwjgl_Display_PLATFORM_GLX 1L #undef org_lwjgl_Display_PLATFORM_AGL #define org_lwjgl_Display_PLATFORM_AGL 2L -/* Inaccessible static: class_000240 */ +/* Inaccessible static: class_00024org_00024lwjgl_00024Display */ /* * Class: org_lwjgl_Display * Method: init @@ -61,19 +61,19 @@ JNIEXPORT jint JNICALL Java_org_lwjgl_Display_getPlatform /* * Class: org_lwjgl_Display - * Method: getGammaRamp - * Signature: ([I[I[I)Z + * Method: getGammaRampLength + * Signature: ()I */ -JNIEXPORT jboolean JNICALL Java_org_lwjgl_Display_getGammaRamp - (JNIEnv *, jclass, jintArray, jintArray, jintArray); +JNIEXPORT jint JNICALL Java_org_lwjgl_Display_getGammaRampLength + (JNIEnv *, jclass); /* * Class: org_lwjgl_Display * Method: setGammaRamp - * Signature: ([I[I[I)Z + * Signature: (I)Z */ JNIEXPORT jboolean JNICALL Java_org_lwjgl_Display_setGammaRamp - (JNIEnv *, jclass, jintArray, jintArray, jintArray); + (JNIEnv *, jclass, jint); #ifdef __cplusplus } diff --git a/src/native/linux/org_lwjgl_Display.cpp b/src/native/linux/org_lwjgl_Display.cpp index ae9a23eb..85cbcea9 100644 --- a/src/native/linux/org_lwjgl_Display.cpp +++ b/src/native/linux/org_lwjgl_Display.cpp @@ -48,44 +48,45 @@ #include #include #include +#include #include #include "org_lwjgl_Display.h" static int saved_width; static int saved_height; +static int gamma_ramp_length = 0; +static unsigned short *r_ramp; +static unsigned short *g_ramp; +static unsigned short *b_ramp; -static int getDisplayModes(Display *disp, int screen, int *num_modes, XF86VidModeModeInfo ***avail_modes) { - int event_base, error_base, xvid_ver, xvid_rev; +static bool getVidModeExtensionVersion(Display *disp, int screen, int *major, int *minor) { + int event_base, error_base; if (!XF86VidModeQueryExtension(disp, &event_base, &error_base)) { #ifdef _DEBUG printf("XF86VidMode extension not available\n"); -#endif - return 0; - } - XF86VidModeQueryVersion(disp, &xvid_ver, &xvid_rev); -#ifdef _DEBUG - printf("XF86VidMode extension version %i.%i\n", xvid_ver, xvid_rev); -#endif - XF86VidModeGetAllModeLines(disp, screen, num_modes, avail_modes); - return 1; -} - -static bool setMode(int width, int height, bool lock_mode) { - int num_modes, i; - XF86VidModeModeInfo **avail_modes; - int screen; - Display *disp = XOpenDisplay(NULL); - - if (disp == NULL) { -#ifdef _DEBUG - printf("Could not open X connection\n"); #endif return false; } - screen = DefaultScreen(disp); + XF86VidModeQueryVersion(disp, major, minor); +#ifdef _DEBUG + printf("XF86VidMode extension version %i.%i\n", major, minor); +#endif + return true; +} + +static bool getDisplayModes(Display *disp, int screen, int *num_modes, XF86VidModeModeInfo ***avail_modes) { + int minor_ver, major_ver; + if (!getVidModeExtensionVersion(disp, screen, &major_ver, &minor_ver)) + return false; + XF86VidModeGetAllModeLines(disp, screen, num_modes, avail_modes); + return true; +} + +static bool setMode(Display *disp, int screen, int width, int height, bool lock_mode) { + int num_modes, i; + XF86VidModeModeInfo **avail_modes; if (!getDisplayModes(disp, screen, &num_modes, &avail_modes)) { - XCloseDisplay(disp); #ifdef _DEBUG printf("Could not get display modes\n"); #endif @@ -107,15 +108,40 @@ static bool setMode(int width, int height, bool lock_mode) { if (lock_mode) XF86VidModeLockModeSwitch(disp, screen, 1); XFree(avail_modes); - XCloseDisplay(disp); return true; } } XFree(avail_modes); - XCloseDisplay(disp); return false; } +static void freeSavedGammaRamps() { + free(r_ramp); + free(g_ramp); + free(b_ramp); + r_ramp = NULL; + g_ramp = NULL; + b_ramp = NULL; + gamma_ramp_length = 0; +} + +static int getGammaRampLength(Display *disp, int screen) { + int minor_ver, major_ver, ramp_size; + if (!getVidModeExtensionVersion(disp, screen, &major_ver, &minor_ver) || major_ver < 2) { +#ifdef _DEBUG + printf("XF86VidMode extension version >= 2 not found\n"); +#endif + return 0; + } + if (XF86VidModeGetGammaRampSize(disp, screen, &ramp_size) == False) { +#ifdef _DEBUG + printf("XF86VidModeGetGammaRampSize call failed\n"); +#endif + return 0; + } + return ramp_size; +} + JNIEXPORT void JNICALL Java_org_lwjgl_Display_init (JNIEnv * env, jclass clazz) { @@ -149,6 +175,16 @@ JNIEXPORT void JNICALL Java_org_lwjgl_Display_init env->SetStaticObjectField(clazz, fid_initialMode, newMode); XFree(avail_modes); + + /* Fetch the current gamma ramp */ + gamma_ramp_length = getGammaRampLength(disp, screen); + if (gamma_ramp_length > 0) { + r_ramp = (unsigned short *)malloc(sizeof(unsigned short)*gamma_ramp_length); + g_ramp = (unsigned short *)malloc(sizeof(unsigned short)*gamma_ramp_length); + b_ramp = (unsigned short *)malloc(sizeof(unsigned short)*gamma_ramp_length); + if (!XF86VidModeGetGammaRamp(disp, screen, gamma_ramp_length, r_ramp, g_ramp, b_ramp)) + freeSavedGammaRamps(); + } XCloseDisplay(disp); } @@ -158,14 +194,40 @@ JNIEXPORT void JNICALL Java_org_lwjgl_Display_setDisplayMode(JNIEnv * env, jclas jfieldID fid_height = env->GetFieldID(cls_displayMode, "height", "I"); int width = env->GetIntField(mode, fid_width); int height = env->GetIntField(mode, fid_height); - if (setMode(width, height, true)) { + int screen; + Display *disp = XOpenDisplay(NULL); + + if (disp == NULL) { +#ifdef _DEBUG + printf("Could not open X connection\n"); +#endif + return; + } + screen = DefaultScreen(disp); + if (setMode(disp, screen, width, height, true)) { jfieldID fid_initialMode = env->GetStaticFieldID(clazz, "mode", "Lorg/lwjgl/DisplayMode;"); env->SetStaticObjectField(clazz, fid_initialMode, mode); } + XCloseDisplay(disp); } JNIEXPORT void JNICALL Java_org_lwjgl_Display_resetDisplayMode(JNIEnv * env, jclass clazz) { - setMode(saved_width, saved_height, false); + int screen; + Display *disp = XOpenDisplay(NULL); + + if (disp == NULL) { +#ifdef _DEBUG + printf("Could not open X connection\n"); +#endif + return; + } + screen = DefaultScreen(disp); + setMode(disp, screen, saved_width, saved_height, false); + if (gamma_ramp_length > 0) { + XF86VidModeSetGammaRamp(disp, screen, gamma_ramp_length, r_ramp, g_ramp, b_ramp); + freeSavedGammaRamps(); + } + XCloseDisplay(disp); } /* @@ -225,22 +287,48 @@ JNIEXPORT jint JNICALL Java_org_lwjgl_Display_getPlatform /* * Class: org_lwjgl_Display - * Method: getGammaRamp - * Signature: ()[I + * Method: getGammaRampLength + * Signature: ()I */ -JNIEXPORT jboolean JNICALL Java_org_lwjgl_Display_getGammaRamp - (JNIEnv * env, jclass clazz, jintArray red, jintArray green, jintArray blue) +JNIEXPORT jint JNICALL Java_org_lwjgl_Display_getGammaRampLength + (JNIEnv *env, jclass clazz) { - return false; + return gamma_ramp_length; } /* * Class: org_lwjgl_Display * Method: setGammaRamp - * Signature: ([I[I[I)V + * Signature: (I)Z */ JNIEXPORT jboolean JNICALL Java_org_lwjgl_Display_setGammaRamp - (JNIEnv * env, jclass clazz, jintArray red, jintArray green, jintArray blue) + (JNIEnv *env, jclass clazz, jint gamma_ramp_address) { - return false; + if (gamma_ramp_length == 0) + return JNI_FALSE; + Display * disp = XOpenDisplay(NULL); + if (disp == NULL) { +#ifdef _DEBUG + printf("Could not open X connection\n"); +#endif + return JNI_FALSE; + } + int screen = DefaultScreen(disp); + float *gamma_ramp = (float *)gamma_ramp_address; + unsigned short *ramp; + ramp = (unsigned short *)malloc(sizeof(unsigned short)*gamma_ramp_length); + for (int i = 0; i < gamma_ramp_length; i++) { + float scaled_gamma = gamma_ramp[i]*0xffff; + ramp[i] = (unsigned short)round(scaled_gamma); + } + if (XF86VidModeSetGammaRamp(disp, screen, gamma_ramp_length, ramp, ramp, ramp) == False) { +#ifdef _DEBUG + printf("Could not set gamma ramp\n"); +#endif + XCloseDisplay(disp); + return JNI_FALSE; + } + XCloseDisplay(disp); + return JNI_TRUE; } + diff --git a/src/native/win32/org_lwjgl_Display.cpp b/src/native/win32/org_lwjgl_Display.cpp index 6803ba22..08b95f42 100644 --- a/src/native/win32/org_lwjgl_Display.cpp +++ b/src/native/win32/org_lwjgl_Display.cpp @@ -272,7 +272,11 @@ JNIEXPORT void JNICALL Java_org_lwjgl_Display_resetDisplayMode // Return device gamma to normal HDC screenDC = GetDC(NULL); - SetDeviceGammaRamp(screenDC, originalGamma); + if (!SetDeviceGammaRamp(screenDC, originalGamma)) { +#ifdef _DEBUG + printf("Could not reset device gamma\n"); +#endif + } ReleaseDC(NULL, screenDC); if (modeSet) { @@ -287,112 +291,32 @@ JNIEXPORT void JNICALL Java_org_lwjgl_Display_resetDisplayMode /* * Class: org_lwjgl_Display - * Method: getGammaRamp - * Signature: ()[I + * Method: getGammaRampLength + * Signature: ()I */ -JNIEXPORT jboolean JNICALL Java_org_lwjgl_Display_getGammaRamp - (JNIEnv * env, jclass clazz, jintArray red, jintArray green, jintArray blue) +JNIEXPORT jint JNICALL Java_org_lwjgl_Display_getGammaRampLength + (JNIEnv *env, jclass clazz) { -#ifdef _DEBUG - if (red == NULL) { - throwRuntimeException(env, "Null red array."); - return JNI_FALSE; - } - if (green == NULL) { - throwRuntimeException(env, "Null green array."); - return JNI_FALSE; - } - if (blue == NULL) { - throwRuntimeException(env, "Null blue array."); - return JNI_FALSE; - } - if (env->GetArrayLength(red) != 256) { - throwRuntimeException(env, "Red array is not 256 long."); - return JNI_FALSE; - } - if (env->GetArrayLength(green) != 256) { - throwRuntimeException(env, "Green array is not 256 long."); - return JNI_FALSE; - } - if (env->GetArrayLength(blue) != 256) { - throwRuntimeException(env, "Blue array is not 256 long."); - return JNI_FALSE; - } -#endif - - jint * redPtr = env->GetIntArrayElements(red, NULL); - jint * greenPtr = env->GetIntArrayElements(green, NULL); - jint * bluePtr = env->GetIntArrayElements(blue, NULL); - - WORD currentGamma[768]; - HDC screenDC = GetDC(NULL); - if (GetDeviceGammaRamp(screenDC, currentGamma) == FALSE) { -#ifdef _DEBUG - printf("Failed to get device gamma\n"); -#endif - env->ReleaseIntArrayElements(red, redPtr, JNI_ABORT); - env->ReleaseIntArrayElements(green, greenPtr, JNI_ABORT); - env->ReleaseIntArrayElements(blue, bluePtr, JNI_ABORT); - ReleaseDC(NULL, screenDC); - return JNI_FALSE; - } - ReleaseDC(NULL, screenDC); - for (int i = 0; i < 256; i ++) { - redPtr[i] = (jint) currentGamma[i]; - greenPtr[i] = (jint) currentGamma[i + 256]; - bluePtr[i] = (jint) currentGamma[i + 512]; - } - env->ReleaseIntArrayElements(red, redPtr, 0); - env->ReleaseIntArrayElements(green, greenPtr, 0); - env->ReleaseIntArrayElements(blue, bluePtr, 0); - return JNI_TRUE; + return 256; } /* * Class: org_lwjgl_Display * Method: setGammaRamp - * Signature: ([I[I[I)V + * Signature: (I)Z */ JNIEXPORT jboolean JNICALL Java_org_lwjgl_Display_setGammaRamp - (JNIEnv * env, jclass clazz, jintArray red, jintArray green, jintArray blue) + (JNIEnv * env, jclass clazz, jint gammaRampAddress) { -#ifdef _DEBUG - if (red == NULL) { - throwRuntimeException(env, "Null red array."); - return JNI_FALSE; - } - if (green == NULL) { - throwRuntimeException(env, "Null green array."); - return JNI_FALSE; - } - if (blue == NULL) { - throwRuntimeException(env, "Null blue array."); - return JNI_FALSE; - } - if (env->GetArrayLength(red) != 256) { - throwRuntimeException(env, "Red array is not 256 long."); - return JNI_FALSE; - } - if (env->GetArrayLength(green) != 256) { - throwRuntimeException(env, "Green array is not 256 long."); - return JNI_FALSE; - } - if (env->GetArrayLength(blue) != 256) { - throwRuntimeException(env, "Blue array is not 256 long."); - return JNI_FALSE; - } -#endif - - jint * redPtr = env->GetIntArrayElements(red, NULL); - jint * greenPtr = env->GetIntArrayElements(green, NULL); - jint * bluePtr = env->GetIntArrayElements(blue, NULL); - - // Turn array of ints into array of RGB WORDs + float *gammaRamp = (float *)gammaRampAddress; + // Turn array of floats into array of RGB WORDs WORD newGamma[768]; for (int i = 0; i < 256; i ++) { - newGamma[i] = (WORD)(min(0x00010000, redPtr[i])); - newGamma[i + 256] = (WORD)(min(0x00010000, greenPtr[i])); - newGamma[i + 512] = (WORD)(min(0x00010000, bluePtr[i])); + float scaledRampEntry = gammaRamp[i]*0xffff; + WORD rampEntry = (WORD)scaledRampEntry; + newGamma[i] = rampEntry; + newGamma[i + 256] = rampEntry; + newGamma[i + 512] = rampEntry; } jboolean ret; HDC screenDC = GetDC(NULL); @@ -406,10 +330,6 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_Display_setGammaRamp } ReleaseDC(NULL, screenDC); - env->ReleaseIntArrayElements(red, redPtr, JNI_ABORT); - env->ReleaseIntArrayElements(green, greenPtr, JNI_ABORT); - env->ReleaseIntArrayElements(blue, bluePtr, JNI_ABORT); - return ret; }