From 3369fbec2d001644dc719e7fe17d102171e0743a Mon Sep 17 00:00:00 2001 From: Max Schenkelberg Date: Mon, 4 Nov 2013 17:52:38 -0600 Subject: [PATCH] Issue #2492 Implemented support for colormapping in different units than the data comes in as. Other changes include NPE fix in RecordTileSetRenderable, glsl cleanup to use structs for code sharing, a topo display fix, and moved viirs colormaps to common Amend: Fixed precision issue with float comparison, made factory better synchronized. Change-Id: Ie72d8d26ca5dc5ee1a0b5c14ca726edbee3bc1a2 Former-commit-id: ae724ecce3d4c65f8845f3278f9b5eeb5b04908a --- .../core/tile/RecordTileSetRenderable.java | 39 +- .../uf/viz/npp/viirs/rsc/VIIRSResource.java | 7 +- .../localization/glsl/truecolor.glsl | 139 +++-- .../GLTrueColorImagingExtension.java | 65 ++- .../truecolor/gl/image/GLTrueColorImage.java | 16 + .../localization/glsl/colormap.glsl | 26 +- .../localization/glsl/colormapRaster.glsl | 68 +-- .../localization/glsl/include/colorUtil.glsl | 34 -- .../localization/glsl/include/coloring.glsl | 23 + .../localization/glsl/include/indexing.glsl | 104 ---- .../localization/glsl/include/mapping.glsl | 299 ++++++++++ .../localization/glsl/raster.glsl | 8 +- .../localization/glsl/singleColor.glsl | 8 +- .../AbstractGLColorMapDataFormat.java | 2 +- .../core/gl/dataformat/GLColorMapData.java | 8 + .../imaging/GLColormappedImageExtension.java | 186 ++++-- .../gl/ext/imaging/GLDataMappingFactory.java | 343 ++++++++++++ .../imaging/GLDefaultImagingExtension.java | 11 +- .../imaging/GLSingleColorImageExtension.java | 11 +- .../viz/core/gl/glsl/GLSLStructFactory.java | 133 +++++ .../viz/core/gl/glsl/GLShaderProgram.java | 2 +- .../gl/images/AbstractGLColormappedImage.java | 25 + .../core/gl/images/GLBufferCMTextureData.java | 138 +++++ .../viz/core/gl/images/GLCMTextureData.java | 64 ++- .../gl/images/GLRetrievableCMTextureData.java | 50 +- .../viz/core/gl/internal/GLTarget.java | 52 +- .../raytheon/viz/core/topo/TopoResource.java | 16 +- .../uf/common/colormap/image/Colormapper.java | 431 +++++++++----- .../colormap/prefs/ColorMapParameters.java | 529 +++++++++--------- .../NPP/VIIRS/CA (Low Light Vis).cmap | 0 .../colormaps/NPP/VIIRS/IR BrightTemps.cmap | 0 .../base}/colormaps/NPP/VIIRS/IR Default.cmap | 0 .../colormaps/NPP/VIIRS/ZA (Vis Default).cmap | 0 .../uf/common/localization/FileLocker.java | 2 +- .../base/styleRules/topoImageryStyleRules.xml | 2 +- 35 files changed, 1934 insertions(+), 907 deletions(-) delete mode 100644 cave/com.raytheon.viz.core.gl/localization/glsl/include/colorUtil.glsl create mode 100644 cave/com.raytheon.viz.core.gl/localization/glsl/include/coloring.glsl delete mode 100644 cave/com.raytheon.viz.core.gl/localization/glsl/include/indexing.glsl create mode 100644 cave/com.raytheon.viz.core.gl/localization/glsl/include/mapping.glsl create mode 100644 cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLDataMappingFactory.java create mode 100644 cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/glsl/GLSLStructFactory.java create mode 100644 cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/GLBufferCMTextureData.java rename {cave/com.raytheon.uf.viz.npp.viirs/localization => edexOsgi/com.raytheon.uf.common.dataplugin.npp.viirs/utility/common_static/base}/colormaps/NPP/VIIRS/CA (Low Light Vis).cmap (100%) rename {cave/com.raytheon.uf.viz.npp.viirs/localization => edexOsgi/com.raytheon.uf.common.dataplugin.npp.viirs/utility/common_static/base}/colormaps/NPP/VIIRS/IR BrightTemps.cmap (100%) rename {cave/com.raytheon.uf.viz.npp.viirs/localization => edexOsgi/com.raytheon.uf.common.dataplugin.npp.viirs/utility/common_static/base}/colormaps/NPP/VIIRS/IR Default.cmap (100%) rename {cave/com.raytheon.uf.viz.npp.viirs/localization => edexOsgi/com.raytheon.uf.common.dataplugin.npp.viirs/utility/common_static/base}/colormaps/NPP/VIIRS/ZA (Vis Default).cmap (100%) diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/tile/RecordTileSetRenderable.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/tile/RecordTileSetRenderable.java index 498d757e7b..fe64f6f7a1 100644 --- a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/tile/RecordTileSetRenderable.java +++ b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/tile/RecordTileSetRenderable.java @@ -195,25 +195,28 @@ public class RecordTileSetRenderable extends TileSetRenderable { // All the images need staging, do bulk request ColorMapData data = retrieveRecordData(bigTile); - Rectangle bigTileRect = bigTile.getRectangle(); - for (int i = 0; i < numTiles; i += 1) { - Tile tile = subTiles.get(i); - DrawableImage image = images.get(i); - if (image != null) { - if (image.getImage().getStatus() == Status.UNLOADED) { - Rectangle tileRect = tile.getRectangle(); - ColorMapData subData = new ColorMapData( - BufferSlicer.slice(data.getBuffer(), - tileRect, bigTileRect), new int[] { - tileRect.width, tileRect.height }, - data.getDataType(), data.getDataUnit()); + if (data != null) { + Rectangle bigTileRect = bigTile.getRectangle(); + for (int i = 0; i < numTiles; i += 1) { + Tile tile = subTiles.get(i); + DrawableImage image = images.get(i); + if (image != null) { + if (image.getImage().getStatus() == Status.UNLOADED) { + Rectangle tileRect = tile.getRectangle(); + ColorMapData subData = new ColorMapData( + BufferSlicer.slice(data.getBuffer(), + tileRect, bigTileRect), + new int[] { tileRect.width, + tileRect.height }, + data.getDataType(), data.getDataUnit()); - callbacks.get(i).setRetrievedData(subData); - try { - image.getImage().stage(); - } catch (VizException e) { - statusHandler.handle(Priority.PROBLEM, - e.getLocalizedMessage(), e); + callbacks.get(i).setRetrievedData(subData); + try { + image.getImage().stage(); + } catch (VizException e) { + statusHandler.handle(Priority.PROBLEM, + e.getLocalizedMessage(), e); + } } } } diff --git a/cave/com.raytheon.uf.viz.npp.viirs/src/com/raytheon/uf/viz/npp/viirs/rsc/VIIRSResource.java b/cave/com.raytheon.uf.viz.npp.viirs/src/com/raytheon/uf/viz/npp/viirs/rsc/VIIRSResource.java index 4c6f94d877..ee578cde12 100644 --- a/cave/com.raytheon.uf.viz.npp.viirs/src/com/raytheon/uf/viz/npp/viirs/rsc/VIIRSResource.java +++ b/cave/com.raytheon.uf.viz.npp.viirs/src/com/raytheon/uf/viz/npp/viirs/rsc/VIIRSResource.java @@ -424,6 +424,7 @@ public class VIIRSResource extends } colorMapParameters.setDataUnit(dataUnit); + colorMapParameters.setColorMapUnit(dataUnit); colorMapParameters.setDisplayUnit(displayUnit); colorMapParameters.setColorMapMin(colorMapParameters.getDataMin()); @@ -433,12 +434,14 @@ public class VIIRSResource extends if (scale != null) { UnitConverter displayToData = colorMapParameters .getDisplayToDataConverter(); + UnitConverter displayToColorMap = colorMapParameters + .getDisplayToColorMapConverter(); if (scale.getMinValue() != null) { - colorMapParameters.setColorMapMin((float) displayToData + colorMapParameters.setColorMapMin((float) displayToColorMap .convert(scale.getMinValue())); } if (scale.getMaxValue() != null) { - colorMapParameters.setColorMapMax((float) displayToData + colorMapParameters.setColorMapMax((float) displayToColorMap .convert(scale.getMaxValue())); } if (scale.getMinValue2() != null) { diff --git a/cave/com.raytheon.uf.viz.truecolor.gl/localization/glsl/truecolor.glsl b/cave/com.raytheon.uf.viz.truecolor.gl/localization/glsl/truecolor.glsl index fc494e358b..390013fbd1 100644 --- a/cave/com.raytheon.uf.viz.truecolor.gl/localization/glsl/truecolor.glsl +++ b/cave/com.raytheon.uf.viz.truecolor.gl/localization/glsl/truecolor.glsl @@ -1,90 +1,89 @@ -#include -#include +#include // Multiplier used to store bit mask safely between 0-1 const float maskMultiplier = 8.0; +const int RED_BAND = 0; +const int GREEN_BAND = 1; +const int BLUE_BAND = 2; -uniform sampler2D rawTex; -uniform float naturalMin; -uniform float naturalMax; -uniform float cmapMin; -uniform float cmapMax; -uniform int isFloat; - -uniform int band; +uniform DataTexture rawData; +uniform DataMapping dataMapping; +uniform ColorMapping colorMapping; uniform sampler2D trueColorTexture; -uniform int height; -uniform int width; +uniform float height; +uniform float width; -uniform float noDataValue; -uniform float alphaStep; +uniform int band; uniform int expectedMask; int toBitMask(float alpha) { return int((alpha * maskMultiplier) + 0.5); } -float getIndex(sampler2D rawTex, float cmapMin, float cmapMax, float naturalMin, float naturalMax, int isFloat) { - vec4 textureValue = texture2D(rawTex, gl_TexCoord[0].st); - float naturalVal = textureValue.r; - if ( isFloat == 0 ) { - naturalVal = ((naturalVal * (naturalMax - naturalMin)) + naturalMin); - } - - float index = -1.0; - if (naturalVal != noDataValue && naturalVal == naturalVal) { - index = findIndex(naturalVal, cmapMin, cmapMax); - } - return index; +float fromBitMask(int bitMask) { + return bitMask / maskMultiplier; } -void main(void) -{ - if ( band == -1 ) { - vec4 imageVal = texture2D(rawTex,gl_TexCoord[0].st); - float r = imageVal.r; - float g = imageVal.g; - float b = imageVal.b; - float a = imageVal.a; - - // Round because of 8-bit floating point precision - int bitMask = toBitMask(a); - if (expectedMask > 0 && bitMask == expectedMask ) { - a = 1.0; - } else { - a = 0.0; - } - - gl_FragColor = vec4(r,g,b,a); +vec4 getFinalColor() { + vec4 imageVal = texture2D(trueColorTexture, gl_TexCoord[0].st); + float r = imageVal.r; + float g = imageVal.g; + float b = imageVal.b; + float a = imageVal.a; + + // Round because of 8-bit floating point precision + int bitMask = toBitMask(a); + if (expectedMask > 0 && bitMask == expectedMask) { + a = 1.0; } else { - vec2 xy = gl_FragCoord.xy; - vec4 imageVal = texture2D(rawTex,gl_TexCoord[0].st); - vec4 curVal = texture2D(trueColorTexture, vec2((xy.x / float(width)), (xy.y / float(height)))); + a = 0.0; + } + + return vec4(r, g, b, a); +} + +vec4 applyColorBand(int colorband) { + vec2 xy = gl_FragCoord.xy; + vec4 curVal = texture2D(trueColorTexture, + vec2((xy.x / width), (xy.y / height))); + + // Lookup raw data value + float dataValue = getDataValue(rawData, gl_TexCoord[0].st); + + float r = curVal.r; + float g = curVal.g; + float b = curVal.b; + float a = curVal.a; + + if (dataValue != rawData.noDataValue && dataValue == dataValue) { + // Convert dataValue to cmapValue + float cmapValue = dataToColorMapValue(dataValue, dataMapping); + float index = getColorMappingIndex(cmapValue, colorMapping); - float r = curVal.r; - float g = curVal.g; - float b = curVal.b; - float a = curVal.a; - - float index = getIndex(rawTex, cmapMin, cmapMax, naturalMin, naturalMax, isFloat); - if ( index != -1.0 ) { - int currentMask = toBitMask(a); - int bitValue = (1 << band); - if ( band == 0 && index > r ) { - r = index; - } else if ( band == 1 && index > g ) { - g = index; - } else if ( band == 2 && index > b ) { - b = index; - } - - if ( (currentMask & bitValue) == 0 ) { - // alpha does not contain this bit yet! - a = (currentMask | bitValue) / maskMultiplier; - } + int currentMask = toBitMask(a); + int bitValue = (1 << band); + if (colorband == RED_BAND && index > r) { + r = index; + } else if (colorband == GREEN_BAND && index > g) { + g = index; + } else if (colorband == BLUE_BAND && index > b) { + b = index; } - - gl_FragColor = vec4(r,g,b,a); + + if ((currentMask & bitValue) == 0) { + // alpha does not contain this bit yet! + a = fromBitMask(currentMask | bitValue); + } + } + + return vec4(r, g, b, a); +} + +void main(void) { + if (band == -1) { + gl_FragColor = getFinalColor(); + } else { + gl_FragColor = applyColorBand(band); } } \ No newline at end of file diff --git a/cave/com.raytheon.uf.viz.truecolor.gl/src/com/raytheon/uf/viz/truecolor/gl/extension/GLTrueColorImagingExtension.java b/cave/com.raytheon.uf.viz.truecolor.gl/src/com/raytheon/uf/viz/truecolor/gl/extension/GLTrueColorImagingExtension.java index 08e246b0f6..a2dfb6b56f 100644 --- a/cave/com.raytheon.uf.viz.truecolor.gl/src/com/raytheon/uf/viz/truecolor/gl/extension/GLTrueColorImagingExtension.java +++ b/cave/com.raytheon.uf.viz.truecolor.gl/src/com/raytheon/uf/viz/truecolor/gl/extension/GLTrueColorImagingExtension.java @@ -35,10 +35,13 @@ import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.truecolor.extension.ITrueColorImagingExtension; import com.raytheon.uf.viz.truecolor.gl.image.GLTrueColorImage; import com.raytheon.viz.core.gl.ext.GLOffscreenRenderingExtension; +import com.raytheon.viz.core.gl.ext.imaging.GLColormappedImageExtension; +import com.raytheon.viz.core.gl.ext.imaging.GLDataMappingFactory.GLDataMapping; import com.raytheon.viz.core.gl.glsl.AbstractGLSLImagingExtension; +import com.raytheon.viz.core.gl.glsl.GLSLStructFactory; import com.raytheon.viz.core.gl.glsl.GLShaderProgram; +import com.raytheon.viz.core.gl.images.AbstractGLColormappedImage; import com.raytheon.viz.core.gl.images.AbstractGLImage; -import com.raytheon.viz.core.gl.images.GLColormappedImage; /** * GL implementation of the {@link ITrueColorImagingExtension} @@ -64,9 +67,6 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension private Channel renderingChannel; - /** The current rendering bit mask, specifies what bands we rendered */ - private int currentMask = 0; - private Map parameters = new IdentityHashMap(); /* @@ -111,7 +111,6 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension GLTrueColorImage trueColorImage = (GLTrueColorImage) image; if (trueColorImage.isRepaint()) { // Reset current bit mask - currentMask = 0; parameters.clear(); writeToImage = trueColorImage; GLOffscreenRenderingExtension extension = target @@ -125,9 +124,6 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension DrawableImage[] imagesToDraw = trueColorImage .getImages(channel); if (imagesToDraw != null && imagesToDraw.length > 0) { - // Mark the channel bit in the current bit mask - currentMask |= (1 << channel.ordinal()); - // Make sure images are staged before we mosaic them ImagingSupport.prepareImages(target, imagesToDraw); @@ -160,12 +156,17 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension imageCoverage)); return null; } - } else { + } else if (image instanceof AbstractGLColormappedImage) { GL gl = target.getGl(); + + GLColormappedImageExtension.setupDataMapping(gl, + (AbstractGLColormappedImage) image, GL.GL_TEXTURE2, + GL.GL_TEXTURE3); // bind on GL_TEXTURE1 as 0 is channel image writeToImage.bind(gl, GL.GL_TEXTURE1); return image; } + return null; } /* @@ -190,6 +191,13 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension // Unbind the writeToImage from GL_TEXTURE1 gl.glActiveTexture(GL.GL_TEXTURE1); gl.glBindTexture(writeToImage.getTextureStorageType(), 0); + + // Unbind the data mapped textures + gl.glActiveTexture(GL.GL_TEXTURE2); + gl.glBindTexture(GL.GL_TEXTURE_1D, 0); + + gl.glActiveTexture(GL.GL_TEXTURE3); + gl.glBindTexture(GL.GL_TEXTURE_1D, 0); } } @@ -206,36 +214,41 @@ public class GLTrueColorImagingExtension extends AbstractGLSLImagingExtension public void loadShaderData(GLShaderProgram program, IImage image, PaintProperties paintProps) throws VizException { if (image instanceof GLTrueColorImage) { + GLTrueColorImage glImage = (GLTrueColorImage) image; program.setUniform("band", -1); - program.setUniform("rawTex", 0); - program.setUniform("expectedMask", currentMask); + program.setUniform("trueColorTexture", 0); + program.setUniform("expectedMask", glImage.getColorMask()); } else { - if (image instanceof GLColormappedImage == false) { + if (image instanceof AbstractGLColormappedImage == false) { throw new VizException( "Can only render colormapped images in true color"); } - GLColormappedImage cmapImage = (GLColormappedImage) image; + AbstractGLColormappedImage cmapImage = (AbstractGLColormappedImage) image; ColorMapParameters colorMapParameters = cmapImage .getColorMapParameters(); - parameters.put(colorMapParameters, null); - int textureType = cmapImage.getTextureType(); - // Set the band image data - program.setUniform("rawTex", 0); - program.setUniform("naturalMin", colorMapParameters.getDataMin()); - program.setUniform("naturalMax", colorMapParameters.getDataMax()); - program.setUniform("cmapMin", colorMapParameters.getColorMapMin()); - program.setUniform("cmapMax", colorMapParameters.getColorMapMax()); - program.setUniform("isFloat", textureType == GL.GL_FLOAT - || textureType == GL.GL_HALF_FLOAT_ARB ? 1 : 0); - program.setUniform("noDataValue", + parameters.put(colorMapParameters, null); + + GLSLStructFactory.createDataTexture(program, "rawData", 0, + cmapImage.getDataFormat(), colorMapParameters.getNoDataValue()); + int numMappingValues = 0; + GLDataMapping mapping = cmapImage.getDataMapping(); + if (mapping != null && mapping.isValid()) { + numMappingValues = mapping.getNumMappingValues(); + } + GLSLStructFactory.createDataMapping(program, "dataMapping", 2, 3, + numMappingValues); + + GLSLStructFactory.createColorMapping(program, "colorMapping", -1, + -1, colorMapParameters); + // Set the composite image data program.setUniform("trueColorTexture", 1); - program.setUniform("width", writeToImage.getWidth()); - program.setUniform("height", writeToImage.getHeight()); + program.setUniform("width", (float) writeToImage.getWidth()); + program.setUniform("height", (float) writeToImage.getHeight()); // Set the band we are rendering to program.setUniform("band", renderingChannel.ordinal()); diff --git a/cave/com.raytheon.uf.viz.truecolor.gl/src/com/raytheon/uf/viz/truecolor/gl/image/GLTrueColorImage.java b/cave/com.raytheon.uf.viz.truecolor.gl/src/com/raytheon/uf/viz/truecolor/gl/image/GLTrueColorImage.java index 90adf35fdd..27a35e7c8f 100644 --- a/cave/com.raytheon.uf.viz.truecolor.gl/src/com/raytheon/uf/viz/truecolor/gl/image/GLTrueColorImage.java +++ b/cave/com.raytheon.uf.viz.truecolor.gl/src/com/raytheon/uf/viz/truecolor/gl/image/GLTrueColorImage.java @@ -97,6 +97,22 @@ public class GLTrueColorImage extends GLDelegateImage implements this.imageExtent = imageExtent; } + /** + * Returns a bitmask of the expected RGB components to render + * + * @return + */ + public int getColorMask() { + int colorMask = 0; + for (Channel channel : Channel.values()) { + DrawableImage[] images = getImages(channel); + if (images != null && images.length > 0) { + colorMask |= (1 << channel.ordinal()); + } + } + return colorMask; + } + /** * @return the imageExtent */ diff --git a/cave/com.raytheon.viz.core.gl/localization/glsl/colormap.glsl b/cave/com.raytheon.viz.core.gl/localization/glsl/colormap.glsl index 677106250b..0eb7dbeeca 100644 --- a/cave/com.raytheon.viz.core.gl/localization/glsl/colormap.glsl +++ b/cave/com.raytheon.viz.core.gl/localization/glsl/colormap.glsl @@ -1,24 +1,21 @@ // Simple shader program for applying alpha,brightness, and contrast to the // colormap in the same way they are applied to data +#include +#include -#include -#include - -uniform float brightness; -uniform float contrast; -uniform float alphaVal; +uniform ColorMapping colorMapping; +uniform ColorModifiers modifiers; uniform float bkgrndRed; uniform float bkgrndGreen; uniform float bkgrndBlue; -uniform sampler1D colorMap; -uniform sampler2D alphaMask; - -uniform int applyMask; -uniform float logFactor; - void main(void){ + sampler1D colorMap = colorMapping.colorMap; + float logFactor = colorMapping.logFactor; + int applyMask = colorMapping.applyMask; + sampler1D alphaMask = colorMapping.alphaMask; + // Lookup color in colorMap for index float index = gl_TexCoord[0].s; if ( logFactor > 0.0 ) { @@ -29,10 +26,11 @@ void main(void){ // Apply alpha mask if set float alpha = color.a; if ( applyMask == 1 ) { - if ( texture2D(alphaMask , vec2(index,index) ).r != 0.0 ) { + if ( texture1D(alphaMask , index ).r != 0.0 ) { color = vec4(bkgrndRed, bkgrndGreen, bkgrndBlue, alpha); } } + if(alpha < 1.0){ // blend the color with background color, the colorbar should not be transparent alpha = 1.0; @@ -42,5 +40,5 @@ void main(void){ alpha); } - gl_FragColor = applyContrastAlphaBrightness(color, alphaVal, brightness, contrast); + gl_FragColor = applyColorModifiers(color, modifiers); } \ No newline at end of file diff --git a/cave/com.raytheon.viz.core.gl/localization/glsl/colormapRaster.glsl b/cave/com.raytheon.viz.core.gl/localization/glsl/colormapRaster.glsl index 611851ddf7..3be30b1856 100644 --- a/cave/com.raytheon.viz.core.gl/localization/glsl/colormapRaster.glsl +++ b/cave/com.raytheon.viz.core.gl/localization/glsl/colormapRaster.glsl @@ -1,56 +1,24 @@ -#include -#include +#include +#include -uniform float alpha; -uniform float brightness; -uniform float contrast; -uniform int applyMask; -uniform float naturalMin; -uniform float naturalMax; -uniform float cmapMin; -uniform float cmapMax; -uniform sampler1D colorMap; -uniform sampler2D alphaMask; -uniform sampler2D rawTex; -uniform float colorMapSz; -uniform int isFloat; -uniform int logarithmic; -uniform int mirror; -uniform float logFactor; +uniform DataTexture rawData; +uniform DataMapping dataMapping; +uniform ColorMapping colorMapping; +uniform ColorModifiers modifiers; void main(void) { - vec4 textureColor = texture2D(rawTex, gl_TexCoord[0].st); - float index = 0.0; - float rawValue = textureColor.r; - if ( isFloat == 1 ) { - if ( logarithmic == 1 ) { - index = findFloatIndexLog(rawValue, cmapMin, cmapMax, mirror); - } else { - index = findFloatIndex(rawValue, cmapMin, cmapMax); - } - - // Special float handling, -1.0 is NaN - if (index == -1.0){ - gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); - return; - } - } else { - float naturalValue = ((rawValue * (naturalMax - naturalMin)) + naturalMin); - index = findIndex(naturalValue, cmapMin, cmapMax); - } - - // Lookup color in colorMap for index - if ( logFactor > 0.0 ) { - index = getLogFactorIndex(index, logFactor); - } - textureColor = texture1D(colorMap, index).rgba; - - // Apply alpha mask - if ( applyMask == 1 ) { - if ( texture2D(alphaMask , vec2(index,index) ).r != 0.0 ) { - textureColor = vec4(textureColor.rgb, 0.0); - } + float dataValue = getDataValue(rawData, gl_TexCoord[0].st); + + // No data check/special NaN check + if (dataValue == rawData.noDataValue || dataValue != dataValue) { + gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); + return; } - gl_FragColor = applyContrastAlphaBrightness(textureColor, alpha, brightness, contrast); + // Convert dataValue to cmapValue + float cmapValue = dataToColorMapValue(dataValue, dataMapping); + // Get color for colormapping, given value + vec4 textureColor = getColorByValue(cmapValue, colorMapping); + // Apply the color modifiers into gl_FragColor + gl_FragColor = applyColorModifiers(textureColor, modifiers); } \ No newline at end of file diff --git a/cave/com.raytheon.viz.core.gl/localization/glsl/include/colorUtil.glsl b/cave/com.raytheon.viz.core.gl/localization/glsl/include/colorUtil.glsl deleted file mode 100644 index a448be537d..0000000000 --- a/cave/com.raytheon.viz.core.gl/localization/glsl/include/colorUtil.glsl +++ /dev/null @@ -1,34 +0,0 @@ - -vec3 AvgLuminance = vec3(0.5, 0.5, 0.5); - -/** - * This function applies the specified alpha, brightness, and contrast values - * to the color passed in - */ -vec4 applyContrastAlphaBrightness(vec4 color, float alpha, float brightness, float contrast){ - vec3 textureColor3 = vec3(color); - vec3 adjustedColor = mix(AvgLuminance, textureColor3, contrast); - float curAlpha = min(color.a, alpha); - return vec4(adjustedColor.r * brightness, adjustedColor.g * brightness, adjustedColor.b * brightness, curAlpha); -} - -/** - * This function calculates a new index to use based on the logFactor - */ -float getLogFactorIndex(float index, float logFactor) { - if (logFactor > 0.0){ - float minLog = log(logFactor); - float maxLog = log(logFactor + 1.0); - - float lg = log(logFactor + index); - - index = (lg - minLog) / (maxLog - minLog); - if (index < 0.0){ - index = 0.0; - } - else if (index > 1.0){ - index = 1.0; - } - } - return index; -} \ No newline at end of file diff --git a/cave/com.raytheon.viz.core.gl/localization/glsl/include/coloring.glsl b/cave/com.raytheon.viz.core.gl/localization/glsl/include/coloring.glsl new file mode 100644 index 0000000000..1bad90a781 --- /dev/null +++ b/cave/com.raytheon.viz.core.gl/localization/glsl/include/coloring.glsl @@ -0,0 +1,23 @@ + +struct ColorModifiers { + float alpha; + float brightness; + float contrast; +}; + +vec3 AvgLuminance = vec3(0.5, 0.5, 0.5); + +/** + * This function applies the specified ColorModifier values to the + * color passed in + */ +vec4 applyColorModifiers(vec4 color, ColorModifiers modifiers){ + float alpha = modifiers.alpha; + float brightness = modifiers.brightness; + float contrast = modifiers.contrast; + + vec3 textureColor3 = vec3(color); + vec3 adjustedColor = mix(AvgLuminance, textureColor3, contrast); + float curAlpha = min(color.a, alpha); + return vec4(adjustedColor.r * brightness, adjustedColor.g * brightness, adjustedColor.b * brightness, curAlpha); +} diff --git a/cave/com.raytheon.viz.core.gl/localization/glsl/include/indexing.glsl b/cave/com.raytheon.viz.core.gl/localization/glsl/include/indexing.glsl deleted file mode 100644 index c1fdfeae96..0000000000 --- a/cave/com.raytheon.viz.core.gl/localization/glsl/include/indexing.glsl +++ /dev/null @@ -1,104 +0,0 @@ - -float HALF_FLOAT_NaN = 65504.0; - -/** - * This function takes an index number and caps it to the range 0-1 - */ -float capIndex(float index) { - if ( index < 0.0 ) { - index = 0.0; - } else if ( index > 1.0 ) { - index = 1.0; - } - return index; -} - -/** - * This function linearly finds the index for the rawValue into cmapMin/cmapMax. - * 65504.0 is treated as NaN for half floats and -1 is returned as special case - */ -float findFloatIndex(float rawValue, float cmapMin, float cmapMax) { - if ( rawValue == HALF_FLOAT_NaN || rawValue != rawValue) { - return -1.0; - } - float index = ((rawValue - cmapMin) / abs(cmapMax-cmapMin)); - return capIndex(index); -} - -/** - * This function logarithmically finds the index for the rawValue into cmapMin/cmapMax. - * 65504.0 is treated as NaN for half floats and -1 is returned as special case - */ -float findFloatIndexLog(float rawValue, float cmapMin, float cmapMax, int mirror) { - if ( rawValue == HALF_FLOAT_NaN ) { - return -1.0; - } - - float index = 0.0; - // is this strictly negative, strictly positive or neg to pos scaling? - if ( cmapMin >= 0.0 && cmapMax >= 0.0 && mirror!=1) { - if(rawValue < cmapMin){ - index = 0.0; - }else{ - // simple calculation - index = ((log(rawValue) - log(cmapMin)) / abs(log(cmapMax)-log(cmapMin))); - } - } else if (cmapMin <= 0.0 && cmapMax <= 0.0 && mirror!=1) { - index = ((log(rawValue) - log(cmapMax)) / abs(log(cmapMin)-log(cmapMax))); - } else { - // special case, neg to pos: - float colorMapMin = cmapMin; - float colorMapMax = cmapMax; - float zeroVal = max(colorMapMax, abs(colorMapMin)) * 0.0001; - if (mirror==1 && (colorMapMin > 0.0 || colorMapMax < 0.0)) { - if (colorMapMax < 0.0) { - colorMapMax = -cmapMax; - rawValue = -rawValue; - zeroVal = -colorMapMin; - } else { - zeroVal = cmapMin; - } - colorMapMin = -cmapMax; - } - float leftZero = 0.0; - float rightZero = 0.0; - float absLogZeroVal = abs(log(zeroVal)); - - rightZero = absLogZeroVal + log(colorMapMax); - - float cmapMax2 = abs(colorMapMin); - - leftZero = absLogZeroVal + log(cmapMax2); - - float zeroIndex = leftZero / (leftZero + rightZero); - - // figure out index for texture val - float absTextureColor = abs(rawValue); - if (absTextureColor <= zeroVal) { - index = zeroIndex; - } else if (rawValue > 0.0) { - // positive texture color value, find index from 0 to - // cmapMax: - float logTexColor = absLogZeroVal + log(rawValue); - - float texIndex = logTexColor / rightZero; - index = (zeroIndex + ((1.0 - zeroIndex) * texIndex)); - } else { - // negative texture color value, find index from 0 to - // cmapMax: - float logTexColor = absLogZeroVal + log(absTextureColor); - - float texIndex = logTexColor / leftZero; - index = (zeroIndex - (zeroIndex * texIndex)); - } - } - return capIndex(index); -} - -/** - * Given a raw data value linearly determine the index(0-1) into cmapMin/cmapMax - */ -float findIndex(float rawValue, float cmapMin, float cmapMax) { - float index = ((rawValue - cmapMin) / abs(cmapMax-cmapMin)); - return capIndex(index); -} diff --git a/cave/com.raytheon.viz.core.gl/localization/glsl/include/mapping.glsl b/cave/com.raytheon.viz.core.gl/localization/glsl/include/mapping.glsl new file mode 100644 index 0000000000..8ded421d66 --- /dev/null +++ b/cave/com.raytheon.viz.core.gl/localization/glsl/include/mapping.glsl @@ -0,0 +1,299 @@ +/** + * Mapping glsl library for use by other glsl programs. Defines + * commonly used structures and functions for data and color mapping + */ + +/** + * Fields for the raw texture mapping is applied to. isScaled + * implied data will range 0-1 and need scaling to get raw value + * where scaleMin maps to 0 and scaleMax maps to 1. + */ +struct DataTexture { + sampler2D rawTex; + float noDataValue; + int isScaled; + float scaleMin; + float scaleMax; +}; + +/** + * Fields used for converting from image data values to + * colormapping data values. Done to avoid conversions in + * application code. dmv[i] -> cmv[i]. Linear interpolation + * is done where non-exact matches are found. Mappings should + * be uploaded as floats so no scaling is needed + */ +struct DataMapping { + sampler1D dataMappingValues; + sampler1D colorMappingValues; + int numMappingValues; +}; + +struct ColorMapping { + /** Fields for color map and size. colorMap contains colors to + * use for mapping. cmapMin/Max is range colormap is applied over */ + sampler1D colorMap; + float cmapMin; + float cmapMax; + + /** Field for alpha masking the colors. alphaMask is a texture the + * same size as colorMap and contains 0s and 1s, 1 indicating alpha + * should be set to completely transparent */ + int applyMask; + sampler1D alphaMask; + + /** Fields for logarithmic and mirrored indexing into the colorMap */ + int isMirrored; + float logFactor; + int isLogarithmic; +}; + +/** + * Returns the data value for the DataTexture at location. + */ +float getDataValue(DataTexture texture, vec2 location) { + vec4 textureValue = texture2D(texture.rawTex, location); + float dataValue = textureValue.r; + + if (texture.isScaled == 1) { + // Convert to non-scaled value + dataValue = ((dataValue * (texture.scaleMax - texture.scaleMin)) + + texture.scaleMin); + } + return dataValue; +} + +/** + * Looks up a value in a mapping texture given an index [0-numMappingValues). + */ +float lookupMappingValue(sampler1D mappingTex, int index, + int numMappingValues) { + return texture1D(mappingTex, float(index) / float(numMappingValues - 1)).r; +} + +/** + * Converts a data value into a colorMap value given the DataMapping + */ +float dataToColorMapValue(float dataValue, DataMapping mapping) { + int numMappingValues = mapping.numMappingValues; + if (numMappingValues == 0) { + // Short circuit if no mapping is needed + return dataValue; + } + + // Convert to colormap value + int lowIndex = 0; + int highIndex = numMappingValues - 1; + + float lowValue = lookupMappingValue(mapping.dataMappingValues, lowIndex, + numMappingValues); + float highValue = lookupMappingValue(mapping.dataMappingValues, highIndex, + numMappingValues); + int reversed = 0; + if (lowValue > highValue) { + reversed = 1; + float tmp = lowValue; + lowValue = highValue; + highValue = tmp; + } + + int done = 0; + // While there is at least one index to check + while (done == 0) { + int nextIndex = lowIndex + ((highIndex - lowIndex) / 2); + if (nextIndex > lowIndex && nextIndex < highIndex) { + // Look up next value and determine if it is a high or low + float nextValue = lookupMappingValue(mapping.dataMappingValues, nextIndex, + numMappingValues); + if (nextValue < dataValue) { + if (reversed == 0) { + lowIndex = nextIndex; + } else { + highIndex = nextIndex; + } + lowValue = nextValue; + } else { + if (reversed == 0) { + highIndex = nextIndex; + } else { + lowIndex = nextIndex; + } + highValue = nextValue; + } + } else { + done = 1; + } + } + + // Percentage dataValue is linearly between low and high value + float factor = (dataValue - lowValue) / (highValue - lowValue); + if (reversed == 1) { + // Reverse factor for high->low indexing + factor = 1.0 - factor; + } + + float lowCmapValue = lookupMappingValue(mapping.colorMappingValues, lowIndex, + numMappingValues); + float highCmapValue = lookupMappingValue(mapping.colorMappingValues, highIndex, + numMappingValues); + + return lowCmapValue + (highCmapValue - lowCmapValue) * factor; +} + +/** + * This function takes an index number and caps it to the range 0-1 + */ +float capIndex(float index) { + if (index < 0.0) { + index = 0.0; + } else if (index > 1.0) { + index = 1.0; + } + return index; +} + +/** + * Given a colorMap value linearly determine the index (capped at 0-1) + * into cmapMin/cmapMax + */ +float getLinearIndex(float cmapValue, float cmapMin, float cmapMax) { + float index = (cmapValue - cmapMin) / (cmapMax - cmapMin); + return capIndex(index); +} + +/** + * This function logarithmically finds the index for the cmapValue into + * cmapMin/cmapMax (capped at 0-1). + */ +float getLogIndex(float cmapValue, float cmapMin, float cmapMax, int mirror) { + float index = 0.0; + // is this strictly negative, strictly positive or neg to pos scaling? + if (cmapMin >= 0.0 && cmapMax >= 0.0 && mirror != 1) { + if (cmapValue < cmapMin) { + index = 0.0; + } else { + // simple calculation + index = ((log(cmapValue) - log(cmapMin)) + / abs(log(cmapMax) - log(cmapMin))); + } + } else if (cmapMin <= 0.0 && cmapMax <= 0.0 && mirror != 1) { + index = ((log(cmapValue) - log(cmapMax)) + / abs(log(cmapMin) - log(cmapMax))); + } else { + // special case, neg to pos: + float colorMapMin = cmapMin; + float colorMapMax = cmapMax; + float zeroVal = max(colorMapMax, abs(colorMapMin)) * 0.0001; + if (mirror == 1 && (colorMapMin > 0.0 || colorMapMax < 0.0)) { + if (colorMapMax < 0.0) { + colorMapMax = -cmapMax; + cmapValue = -cmapValue; + zeroVal = -colorMapMin; + } else { + zeroVal = cmapMin; + } + colorMapMin = -cmapMax; + } + float leftZero = 0.0; + float rightZero = 0.0; + float absLogZeroVal = abs(log(zeroVal)); + + rightZero = absLogZeroVal + log(colorMapMax); + + float cmapMax2 = abs(colorMapMin); + + leftZero = absLogZeroVal + log(cmapMax2); + + float zeroIndex = leftZero / (leftZero + rightZero); + + // figure out index for texture val + float absTextureColor = abs(cmapValue); + if (absTextureColor <= zeroVal) { + index = zeroIndex; + } else if (cmapValue > 0.0) { + // positive texture color value, find index from 0 to + // cmapMax: + float logTexColor = absLogZeroVal + log(cmapValue); + + float texIndex = logTexColor / rightZero; + index = (zeroIndex + ((1.0 - zeroIndex) * texIndex)); + } else { + // negative texture color value, find index from 0 to + // cmapMax: + float logTexColor = absLogZeroVal + log(absTextureColor); + + float texIndex = logTexColor / leftZero; + index = (zeroIndex - (zeroIndex * texIndex)); + } + } + return capIndex(index); +} + +/** + * This function calculates a new index to use based on the logFactor + * and passed in index + */ +float getLogFactorIndex(float index, float logFactor) { + if (logFactor > 0.0) { + float minLog = log(logFactor); + float maxLog = log(logFactor + 1.0); + + float lg = log(logFactor + index); + + index = (lg - minLog) / (maxLog - minLog); + if (index < 0.0) { + index = 0.0; + } else if (index > 1.0) { + index = 1.0; + } + } + return index; +} + +/** + * Returns an index for the cmapValue based on the ColorMapping + */ +float getColorMappingIndex(float cmapValue, ColorMapping colorMapping) { + int logarithmic = colorMapping.isLogarithmic; + int mirror = colorMapping.isMirrored; + float logFactor = colorMapping.logFactor; + float cmapMin = colorMapping.cmapMin; + float cmapMax = colorMapping.cmapMax; + + float index; + if (logarithmic == 1) { + index = getLogIndex(cmapValue, cmapMin, cmapMax, mirror); + } else { + index = getLinearIndex(cmapValue, cmapMin, cmapMax); + } + + // Apply logFactor if set + if (logFactor > 0.0) { + index = getLogFactorIndex(index, logFactor); + } + return index; +} + +/** + * Returns a color for the index based on the ColorMapping + */ +vec4 getColorByIndex(float index, ColorMapping colorMapping) { + // Lookup color in colorMap for index + vec4 textureColor = texture1D(colorMapping.colorMap, index).rgba; + + // Apply alpha mask + if (colorMapping.applyMask == 1) { + if (texture1D(colorMapping.alphaMask, index).r != 0.0) { + textureColor = vec4(textureColor.rgb, 0.0); + } + } + return textureColor; +} + +/** + * Returns a color for the cmapValue based on the ColorMapping + */ +vec4 getColorByValue(float cmapValue, ColorMapping colorMapping) { + return getColorByIndex(getColorMappingIndex(cmapValue, colorMapping), + colorMapping); +} \ No newline at end of file diff --git a/cave/com.raytheon.viz.core.gl/localization/glsl/raster.glsl b/cave/com.raytheon.viz.core.gl/localization/glsl/raster.glsl index a682fb1742..33237e532e 100644 --- a/cave/com.raytheon.viz.core.gl/localization/glsl/raster.glsl +++ b/cave/com.raytheon.viz.core.gl/localization/glsl/raster.glsl @@ -1,11 +1,9 @@ -#include +#include -uniform float brightness; -uniform float contrast; -uniform float alpha; uniform sampler2D rawTex; +uniform ColorModifiers modifiers; void main(void) { vec4 textureColor = texture2D(rawTex, gl_TexCoord[0].st); - gl_FragColor = applyContrastAlphaBrightness(textureColor, alpha, brightness, contrast); + gl_FragColor = applyColorModifiers(textureColor, modifiers); } \ No newline at end of file diff --git a/cave/com.raytheon.viz.core.gl/localization/glsl/singleColor.glsl b/cave/com.raytheon.viz.core.gl/localization/glsl/singleColor.glsl index c1b999b79a..0b4f5267dc 100644 --- a/cave/com.raytheon.viz.core.gl/localization/glsl/singleColor.glsl +++ b/cave/com.raytheon.viz.core.gl/localization/glsl/singleColor.glsl @@ -1,13 +1,11 @@ -#include +#include -uniform float brightness; -uniform float contrast; -uniform float alpha; uniform sampler2D rawTex; uniform vec3 color; +uniform ColorModifiers modifiers; void main(void) { vec4 textureColor = texture2D(rawTex, gl_TexCoord[0].st); textureColor.rgb = color; - gl_FragColor = applyContrastAlphaBrightness(textureColor, alpha, brightness, contrast); + gl_FragColor = applyColorModifiers(textureColor, modifiers); } \ No newline at end of file diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/dataformat/AbstractGLColorMapDataFormat.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/dataformat/AbstractGLColorMapDataFormat.java index 4480a8fab5..09beda646f 100644 --- a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/dataformat/AbstractGLColorMapDataFormat.java +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/dataformat/AbstractGLColorMapDataFormat.java @@ -217,7 +217,7 @@ public abstract class AbstractGLColorMapDataFormat { protected Buffer handleBufferSizing(GLColorMapData data, Buffer buffer, int[] dimensions) { int sliceWidth = dimensions[0] * getValuesPerPixel(); - int sliceHeight = dimensions[1]; + int sliceHeight = dimensions.length > 1 ? dimensions[1] : 1; int paddedSliceWidth = getAlignedWidth(sliceWidth); int totalDataSize = buffer.capacity(); diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/dataformat/GLColorMapData.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/dataformat/GLColorMapData.java index 06cbf805eb..2bd116a36b 100644 --- a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/dataformat/GLColorMapData.java +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/dataformat/GLColorMapData.java @@ -54,6 +54,10 @@ public class GLColorMapData { this.dimensions = dimensions; } + public AbstractGLColorMapDataFormat getDataFormat() { + return dataFormat; + } + public int getTextureFormat() { return dataFormat.getTextureFormat(); } @@ -93,6 +97,10 @@ public class GLColorMapData { return dimensions[index]; } + public int getNumDimensions() { + return dimensions.length; + } + public int[] getDimensions() { return dimensions; } diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLColormappedImageExtension.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLColormappedImageExtension.java index 98d1b9ab54..4afc4d21ea 100644 --- a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLColormappedImageExtension.java +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLColormappedImageExtension.java @@ -21,9 +21,11 @@ package com.raytheon.viz.core.gl.ext.imaging; import java.nio.ByteBuffer; +import javax.measure.unit.Unit; import javax.media.opengl.GL; import com.raytheon.uf.common.colormap.image.ColorMapData; +import com.raytheon.uf.common.colormap.image.ColorMapData.ColorMapDataType; import com.raytheon.uf.common.colormap.prefs.ColorMapParameters; import com.raytheon.uf.viz.core.PixelCoverage; import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback; @@ -32,10 +34,15 @@ import com.raytheon.uf.viz.core.drawables.IImage; import com.raytheon.uf.viz.core.drawables.PaintProperties; import com.raytheon.uf.viz.core.drawables.ext.colormap.IColormappedImageExtension; import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.viz.core.gl.dataformat.GLByteDataFormat; +import com.raytheon.viz.core.gl.ext.imaging.GLDataMappingFactory.GLDataMapping; import com.raytheon.viz.core.gl.glsl.AbstractGLSLImagingExtension; +import com.raytheon.viz.core.gl.glsl.GLSLStructFactory; import com.raytheon.viz.core.gl.glsl.GLShaderProgram; import com.raytheon.viz.core.gl.images.AbstractGLColormappedImage; import com.raytheon.viz.core.gl.images.AbstractGLImage; +import com.raytheon.viz.core.gl.images.GLBufferCMTextureData; +import com.raytheon.viz.core.gl.images.GLCMTextureData; import com.raytheon.viz.core.gl.images.GLColormappedImage; import com.raytheon.viz.core.gl.objects.GLTextureObject; @@ -53,7 +60,8 @@ import com.raytheon.viz.core.gl.objects.GLTextureObject; * Feb 14, 2013 1616 bsteffen Add option for interpolation of colormap * parameters, disable colormap interpolation * by default. - * Oct 16, 2013 2333 mschenke Cleaned up load shader method, used isScaled + * Oct 16, 2013 2333 mschenke Cleaned up load shader method, used isScaled. + * Added support for colormapping in non-data unit. * * * @@ -65,7 +73,7 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension implements IColormappedImageExtension { private static class GLColormappedImageExtensionData { - public GLColormappedImage alphaMaskTexture; + public GLCMTextureData alphaMask; } /* @@ -108,31 +116,10 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension return null; } - if (usedColorMapParameters.isUseMask()) { - final byte[] mask = usedColorMapParameters.getAlphaMask(); - data.alphaMaskTexture = initializeRaster( - new IColorMapDataRetrievalCallback() { - @Override - public ColorMapData getColorMapData() - throws VizException { - return new ColorMapData(ByteBuffer.wrap(mask), - new int[] { mask.length, 1 }); - } - }, usedColorMapParameters); - data.alphaMaskTexture.stage(); - data.alphaMaskTexture.target(target); - } - // Get and stage colormap texture GLTextureObject cmapTexture = target .getColorMapTexture(usedColorMapParameters); - if (data.alphaMaskTexture != null) { - gl.glActiveTexture(GL.GL_TEXTURE2); - gl.glBindTexture(data.alphaMaskTexture.getTextureStorageType(), - data.alphaMaskTexture.getTextureid()); - } - gl.glActiveTexture(GL.GL_TEXTURE1); cmapTexture.bind(gl, GL.GL_TEXTURE_1D); @@ -147,10 +134,97 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension gl.glTexParameteri(GL.GL_TEXTURE_1D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); } + + if (usedColorMapParameters.isUseMask()) { + data.alphaMask = setupAlphaMasking(gl, GL.GL_TEXTURE2, + usedColorMapParameters.getAlphaMask()); + } + + setupDataMapping(gl, glImage, GL.GL_TEXTURE3, GL.GL_TEXTURE4); } return data; } + /** + * Sets up a {@link GLCMTextureData} for an alpha mask for use in image + * rendering + * + * @param gl + * @param maskTexBinding + * @param mask + * @return The GLCMTextureData the alpha mask is bound to or null if the + * texture failed to initialize + * @throws VizException + */ + public static GLCMTextureData setupAlphaMasking(GL gl, int maskTexBinding, + byte[] mask) throws VizException { + GLBufferCMTextureData maskData = new GLBufferCMTextureData( + new ColorMapData(ByteBuffer.wrap(mask), + new int[] { mask.length }, ColorMapDataType.BYTE), + new GLByteDataFormat()); + gl.glActiveTexture(maskTexBinding); + if (maskData.loadTexture(gl)) { + gl.glBindTexture(maskData.getTextureStorageType(), + maskData.getTexId()); + } else { + maskData.dispose(); + maskData = null; + } + return maskData; + } + + /** + * Sets up a {@link GLDataMapping} for use in image rendering + * + * @param gl + * @param glImage + * @param dataMappedTexBinding + * @param colorMappedTexBinding + * @throws VizException + */ + public static void setupDataMapping(GL gl, + AbstractGLColormappedImage glImage, int dataMappedTexBinding, + int colorMappedTexBinding) throws VizException { + ColorMapParameters colorMapParameters = glImage.getColorMapParameters(); + // Get GLDataMapping and generate if datamapping is not set. If + // datamapping is not set, the data has already been mapped to + // colorMapUnits and we need not do anything + GLDataMapping dataMapping = glImage.getDataMapping(); + if (dataMapping == null && colorMapParameters.getDataMapping() == null) { + Unit colorMapUnit = colorMapParameters.getColorMapUnit(); + Unit dataUnit = colorMapParameters.getDataUnit(); + int colorMapSize = colorMapParameters.getColorMap().getSize(); + float colorMapMin = colorMapParameters.getColorMapMin(); + float colorMapMax = colorMapParameters.getColorMapMax(); + dataMapping = GLDataMappingFactory.constructGLDataMapping(gl, + dataUnit, colorMapUnit, colorMapMin, colorMapMax, + colorMapSize); + glImage.setDataMapping(dataMapping); + } + + if (dataMapping != null && dataMapping.isValid()) { + GLCMTextureData glDataMapping = dataMapping.getDataMapping(); + gl.glActiveTexture(dataMappedTexBinding); + if (glDataMapping.isLoaded() == false) { + glDataMapping.loadTexture(gl); + } + if (glDataMapping.isLoaded()) { + gl.glBindTexture(glDataMapping.getTextureStorageType(), + glDataMapping.getTexId()); + } + + GLCMTextureData glColorMapping = dataMapping.getColorMapping(); + gl.glActiveTexture(colorMappedTexBinding); + if (glColorMapping.isLoaded() == false) { + glColorMapping.loadTexture(gl); + } + if (glColorMapping.isLoaded()) { + gl.glBindTexture(glColorMapping.getTextureStorageType(), + glColorMapping.getTexId()); + } + } + } + /* * (non-Javadoc) * @@ -164,16 +238,22 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension AbstractGLImage image, Object data) throws VizException { GLColormappedImageExtensionData imageData = (GLColormappedImageExtensionData) data; GL gl = target.getGl(); - if (imageData.alphaMaskTexture != null) { - gl.glActiveTexture(GL.GL_TEXTURE2); - gl.glBindTexture( - imageData.alphaMaskTexture.getTextureStorageType(), 0); - - imageData.alphaMaskTexture.dispose(); - } gl.glActiveTexture(GL.GL_TEXTURE1); gl.glBindTexture(GL.GL_TEXTURE_1D, 0); + + if (imageData.alphaMask != null) { + gl.glActiveTexture(GL.GL_TEXTURE2); + gl.glBindTexture(imageData.alphaMask.getTextureStorageType(), 0); + + imageData.alphaMask.dispose(); + } + + gl.glActiveTexture(GL.GL_TEXTURE3); + gl.glBindTexture(GL.GL_TEXTURE_1D, 0); + + gl.glActiveTexture(GL.GL_TEXTURE4); + gl.glBindTexture(GL.GL_TEXTURE_1D, 0); } /* @@ -210,40 +290,22 @@ public class GLColormappedImageExtension extends AbstractGLSLImagingExtension ColorMapParameters colorMapParameters = image.getColorMapParameters(); - program.setUniform("colorMapSz", colorMapParameters.getColorMap() - .getSize()); - boolean isScaled = image.isImageFormatScaled(); - double dataMin = colorMapParameters.getDataMin(); - double dataMax = colorMapParameters.getDataMax(); - if (isScaled) { - // get format from image and get data min/max from it - dataMin = image.getDataMin(); - dataMax = image.getDataMax(); + GLSLStructFactory.createDataTexture(program, "rawData", 0, + image.getDataFormat(), colorMapParameters.getNoDataValue()); + + int numMappingValues = 0; + GLDataMapping mapping = image.getDataMapping(); + if (mapping != null && mapping.isValid()) { + numMappingValues = mapping.getNumMappingValues(); } + GLSLStructFactory.createDataMapping(program, "dataMapping", 3, 4, + numMappingValues); - double cmapMin = colorMapParameters.getColorMapMin(); - double cmapMax = colorMapParameters.getColorMapMax(); + GLSLStructFactory.createColorMapping(program, "colorMapping", 1, 2, + colorMapParameters); - program.setUniform("isFloat", !isScaled); - program.setUniform("logarithmic", - colorMapParameters.isLogarithmic() ? 1 : 0); - program.setUniform("logFactor", colorMapParameters.getLogFactor()); - program.setUniform("mirror", colorMapParameters.isMirror() ? 1 : 0); - - program.setUniform("applyMask", colorMapParameters.isUseMask() ? 1 : 0); - - program.setUniform("naturalMin", dataMin); - program.setUniform("naturalMax", dataMax); - program.setUniform("cmapMin", cmapMin); - program.setUniform("cmapMax", cmapMax); - - program.setUniform("alphaMask", 2); - program.setUniform("colorMap", 1); - program.setUniform("rawText", 0); - - program.setUniform("brightness", image.getBrightness()); - program.setUniform("contrast", image.getContrast()); - program.setUniform("alpha", paintProps.getAlpha()); + GLSLStructFactory.createColorModifiers(program, "modifiers", + paintProps.getAlpha(), image.getBrightness(), + image.getContrast()); } - } diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLDataMappingFactory.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLDataMappingFactory.java new file mode 100644 index 0000000000..9fdbad5dd3 --- /dev/null +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLDataMappingFactory.java @@ -0,0 +1,343 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.viz.core.gl.ext.imaging; + +import java.nio.FloatBuffer; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import javax.measure.converter.UnitConverter; +import javax.measure.unit.Unit; +import javax.media.opengl.GL; + +import com.raytheon.uf.common.colormap.image.ColorMapData; +import com.raytheon.viz.core.gl.dataformat.GLBufferColorMapData; +import com.raytheon.viz.core.gl.dataformat.GLFloatDataFormat; +import com.raytheon.viz.core.gl.images.GLBufferCMTextureData; +import com.raytheon.viz.core.gl.images.GLCMTextureData; + +/** + * Factory class for creation {@link GLDataMapping} objects that can convert + * between units + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 24, 2013 2492       mschenke    Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ + +public class GLDataMappingFactory { + + /** + * Key for {@link GLDataMappingFactory#mappingCache}. Stores fields needed + * to generate unique mappings + * + * @author mschenke + */ + private static class GLDataMappingKey { + + private final Unit dataUnit; + + private final Unit colorMapUnit; + + private final float colorMapMin; + + private final float colorMapMax; + + private final int colorMapSize; + + public GLDataMappingKey(Unit dataUnit, Unit colorMapUnit, + float colorMapMin, float colorMapMax, int colorMapSize) { + this.dataUnit = dataUnit; + this.colorMapUnit = colorMapUnit; + this.colorMapMin = colorMapMin; + this.colorMapMax = colorMapMax; + this.colorMapSize = colorMapSize; + } + + public Unit getDataUnit() { + return dataUnit; + } + + public Unit getColorMapUnit() { + return colorMapUnit; + } + + public float getColorMapMin() { + return colorMapMin; + } + + public float getColorMapMax() { + return colorMapMax; + } + + public int getColorMapSize() { + return colorMapSize; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Float.floatToIntBits(colorMapMax); + result = prime * result + Float.floatToIntBits(colorMapMin); + result = prime * result + colorMapSize; + result = prime * result + + ((colorMapUnit == null) ? 0 : colorMapUnit.hashCode()); + result = prime * result + + ((dataUnit == null) ? 0 : dataUnit.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + GLDataMappingKey other = (GLDataMappingKey) obj; + if (Float.floatToIntBits(colorMapMax) != Float + .floatToIntBits(other.colorMapMax)) + return false; + if (Float.floatToIntBits(colorMapMin) != Float + .floatToIntBits(other.colorMapMin)) + return false; + if (colorMapSize != other.colorMapSize) + return false; + if (colorMapUnit == null) { + if (other.colorMapUnit != null) + return false; + } else if (!colorMapUnit.equals(other.colorMapUnit)) + return false; + if (dataUnit == null) { + if (other.dataUnit != null) + return false; + } else if (!dataUnit.equals(other.dataUnit)) + return false; + return true; + } + + } + + /** + * GL data mapping object, represents a mapping between units for use in GL + * + * @author mschenke + */ + public static class GLDataMapping { + + private final GLDataMappingKey key; + + private GLCMTextureData colorMapping; + + private GLCMTextureData dataMapping; + + private int numMappingValues; + + private int refCount = 1; + + private boolean initialized = false; + + public GLDataMapping(GLDataMappingKey key) { + this.key = key; + } + + public GLCMTextureData getColorMapping() { + return colorMapping; + } + + public GLCMTextureData getDataMapping() { + return dataMapping; + } + + public int getNumMappingValues() { + return numMappingValues; + } + + public boolean isValid() { + return numMappingValues > 0 && colorMapping != null + && dataMapping != null; + } + + public void dispose() { + synchronized (mappingCache) { + refCount -= 1; + if (refCount <= 0) { + mappingCache.remove(key); + if (colorMapping != null) { + colorMapping.dispose(); + } + if (dataMapping != null) { + dataMapping.dispose(); + } + refCount = 0; + } + } + } + + private void use() { + if (refCount == 0) { + throw new IllegalStateException( + "GLDataMapping has already been disposed"); + } + refCount += 1; + } + + private synchronized void initialize(GL gl) { + if (initialized) { + return; + } + Unit dataUnit = key.getDataUnit(); + Unit colorMapUnit = key.getColorMapUnit(); + int colorMapSize = key.getColorMapSize(); + double colorMapMin = key.getColorMapMin(); + double colorMapMax = key.getColorMapMax(); + int numMappings = 0; + if (dataUnit != null && colorMapUnit != null + && dataUnit.equals(colorMapUnit) == false + && dataUnit.isCompatible(colorMapUnit)) { + // Worst case scenario, one mapping per color + double[] colorMapping = new double[colorMapSize]; + Arrays.fill(colorMapping, Float.NaN); + double[] dataMapping = new double[colorMapping.length]; + Arrays.fill(dataMapping, Float.NaN); + + UnitConverter colorMapToData = colorMapUnit + .getConverterTo(dataUnit); + double dataMin = colorMapToData.convert(colorMapMin); + double dataMax = colorMapToData.convert(colorMapMax); + colorMapping[0] = colorMapMin; + colorMapping[colorMapping.length - 1] = colorMapMax; + dataMapping[0] = dataMin; + dataMapping[dataMapping.length - 1] = dataMax; + + numMappings = 2; + if (colorMapToData.isLinear() == false) { + // Populate the dataMapping/colorMapping arrays + double increment = (colorMapMax - colorMapMin) + / (colorMapping.length - 1); + for (int i = 1; i < colorMapping.length - 1; ++i) { + colorMapping[i] = colorMapMin + (i * increment); + dataMapping[i] = colorMapToData + .convert(colorMapping[i]); + } + + // Search for linearness in the dataMappings. + int currEndIndex = 1; + double currEndValue = dataMapping[currEndIndex]; + float currDelta = (float) (currEndValue - dataMapping[0]); + for (int i = 2; i < dataMapping.length; ++i) { + double nextValue = dataMapping[i]; + float nextDelta = (float) ((nextValue - currEndValue) / (i - currEndIndex)); + if (nextDelta == currDelta) { + // Remove linear entries + dataMapping[currEndIndex] = colorMapping[currEndIndex] = Double.NaN; + currEndValue = nextValue; + currEndIndex = i; + } else { + // Non-linear entry found, add mapping + numMappings += 1; + currEndIndex = i; + currEndValue = nextValue; + currDelta = nextDelta; + } + } + } + + // Condense the mapping arrays removing nans + float[] condensedColorMapping = new float[numMappings]; + float[] condensedDataMapping = new float[numMappings]; + + int index = 0; + for (int i = 0; i < colorMapSize && index < numMappings; ++i) { + double colorMapVal = colorMapping[i]; + double dataMapVal = dataMapping[i]; + if (Double.isNaN(colorMapVal) == false + && Double.isNaN(dataMapVal) == false) { + condensedColorMapping[index] = (float) colorMapVal; + condensedDataMapping[index] = (float) dataMapVal; + index += 1; + } + } + + if (index == numMappings) { + this.numMappingValues = numMappings; + this.colorMapping = new GLBufferCMTextureData( + new GLBufferColorMapData(new ColorMapData( + FloatBuffer.wrap(condensedColorMapping), + new int[] { numMappings }), + new GLFloatDataFormat())); + this.dataMapping = new GLBufferCMTextureData( + new GLBufferColorMapData(new ColorMapData( + FloatBuffer.wrap(condensedDataMapping), + new int[] { numMappings }), + new GLFloatDataFormat())); + } + } + initialized = true; + } + } + + private static Map mappingCache = new HashMap(); + + /** + * Creates a {@link GLDataMapping} object given the dataUnit, colorMapUnit, + * color map min/max, and size of the colormap. Object must be disposed of + * when no longer used + * + * @param gl + * @param dataUnit + * @param colorMapUnit + * @param colorMapMin + * @param colorMapMax + * @param colorMapSize + * @return + */ + public static GLDataMapping constructGLDataMapping(GL gl, Unit dataUnit, + Unit colorMapUnit, float colorMapMin, float colorMapMax, + int colorMapSize) { + GLDataMapping mapping; + synchronized (mappingCache) { + GLDataMappingKey key = new GLDataMappingKey(dataUnit, colorMapUnit, + colorMapMin, colorMapMax, colorMapSize); + mapping = mappingCache.get(key); + if (mapping == null) { + mapping = new GLDataMapping(key); + mappingCache.put(key, mapping); + } else { + mapping.use(); + } + } + mapping.initialize(gl); + return mapping; + } + +} diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLDefaultImagingExtension.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLDefaultImagingExtension.java index f86080d9ba..5f81878958 100644 --- a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLDefaultImagingExtension.java +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLDefaultImagingExtension.java @@ -22,6 +22,7 @@ package com.raytheon.viz.core.gl.ext.imaging; import com.raytheon.uf.viz.core.drawables.IImage; import com.raytheon.uf.viz.core.drawables.PaintProperties; import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.viz.core.gl.glsl.GLSLStructFactory; import com.raytheon.viz.core.gl.glsl.GLShaderProgram; import com.raytheon.viz.core.gl.images.AbstractGLImage; @@ -34,7 +35,9 @@ import com.raytheon.viz.core.gl.images.AbstractGLImage; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Dec 16, 2011 mschenke Initial creation + * Dec 16, 2011 mschenke Initial creation + * Nov 4, 2013 2492 mschenke Switched to use GLSLStructFactory for + * common shader structure use * * * @@ -76,10 +79,10 @@ public class GLDefaultImagingExtension extends AbstractGLImagingExtension { } image = (AbstractGLImage) iimage; - program.setUniform("alpha", paintProps.getAlpha()); - program.setUniform("brightness", image.getBrightness()); - program.setUniform("contrast", image.getContrast()); program.setUniform("rawTex", 0); + GLSLStructFactory.createColorModifiers(program, "modifiers", + paintProps.getAlpha(), image.getBrightness(), + image.getContrast()); } } diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLSingleColorImageExtension.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLSingleColorImageExtension.java index 0425cc1554..c7994e4664 100644 --- a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLSingleColorImageExtension.java +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/ext/imaging/GLSingleColorImageExtension.java @@ -27,6 +27,7 @@ import com.raytheon.uf.viz.core.drawables.PaintProperties; import com.raytheon.uf.viz.core.drawables.ext.ISingleColorImageExtension; import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.viz.core.gl.glsl.AbstractGLSLImagingExtension; +import com.raytheon.viz.core.gl.glsl.GLSLStructFactory; import com.raytheon.viz.core.gl.glsl.GLShaderProgram; import com.raytheon.viz.core.gl.images.GLSingleColorImage; @@ -40,7 +41,9 @@ import com.raytheon.viz.core.gl.images.GLSingleColorImage; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Dec 15, 2011 mschenke Initial creation + * Dec 15, 2011 mschenke Initial creation + * Nov 4, 2013 2492 mschenke Switched to use GLSLStructFactory for + * common shader structure use * * * @@ -97,11 +100,11 @@ public class GLSingleColorImageExtension extends AbstractGLSLImagingExtension image = (GLSingleColorImage) iimage; - program.setUniform("brightness", image.getBrightness()); - program.setUniform("contrast", image.getContrast()); - program.setUniform("alpha", paintProps.getAlpha()); program.setUniform("color", image.getColor()); program.setUniform("rawTex", 0); + GLSLStructFactory.createColorModifiers(program, "modifiers", + paintProps.getAlpha(), image.getBrightness(), + image.getContrast()); } } diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/glsl/GLSLStructFactory.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/glsl/GLSLStructFactory.java new file mode 100644 index 0000000000..e8fd320933 --- /dev/null +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/glsl/GLSLStructFactory.java @@ -0,0 +1,133 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.viz.core.gl.glsl; + +import com.raytheon.uf.common.colormap.prefs.ColorMapParameters; +import com.raytheon.viz.core.gl.dataformat.AbstractGLColorMapDataFormat; + +/** + * Factory for creating GLSL struct mappings + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 31, 2013 2492       mschenke     Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ + +public class GLSLStructFactory { + + private static final String FIELD_SEPERATOR = "."; + + /** + * Creates a DataTexture structure in the program with the given name + * + * @param program + * @param name + * @param texBinding + * @param dataFormat + * @param noDataValue + */ + public static void createDataTexture(GLShaderProgram program, String name, + int texBinding, AbstractGLColorMapDataFormat dataFormat, + double noDataValue) { + setFieldUniform(program, name, "rawTex", texBinding); + setFieldUniform(program, name, "noDataValue", noDataValue); + setFieldUniform(program, name, "isScaled", dataFormat.isScaled()); + if (dataFormat.isScaled()) { + setFieldUniform(program, name, "scaleMin", + dataFormat.getDataFormatMin()); + setFieldUniform(program, name, "scaleMax", + dataFormat.getDataFormatMax()); + } + } + + /** + * Creates a DataMapping structure in the program with the given name + * + * @param program + * @param name + * @param dataMappingTexBinding + * @param colorMappingTexBinding + * @param numMappingValues + */ + public static void createDataMapping(GLShaderProgram program, String name, + int dataMappingTexBinding, int colorMappingTexBinding, + int numMappingValues) { + setFieldUniform(program, name, "dataMappingValues", + dataMappingTexBinding); + setFieldUniform(program, name, "colorMappingValues", + colorMappingTexBinding); + setFieldUniform(program, name, "numMappingValues", numMappingValues); + } + + /** + * Creates a ColorMapping structure in the program with the given name + * + * @param program + * @param name + * @param colorMapTexBinding + * @param alphaMaskTexBinding + * @param parameters + */ + public static void createColorMapping(GLShaderProgram program, String name, + int colorMapTexBinding, int alphaMaskTexBinding, + ColorMapParameters parameters) { + setFieldUniform(program, name, "colorMap", colorMapTexBinding); + setFieldUniform(program, name, "cmapMin", parameters.getColorMapMin()); + setFieldUniform(program, name, "cmapMax", parameters.getColorMapMax()); + + setFieldUniform(program, name, "applyMask", parameters.isUseMask()); + setFieldUniform(program, name, "alphaMask", alphaMaskTexBinding); + + setFieldUniform(program, name, "isMirrored", parameters.isMirror()); + setFieldUniform(program, name, "isLogarithmic", + parameters.isLogarithmic()); + setFieldUniform(program, name, "logFactor", parameters.getLogFactor()); + } + + /** + * Creates a ColorModifiers structure in the program with the given name + * + * @param program + * @param name + * @param alpha + * @param brightness + * @param contrast + */ + public static void createColorModifiers(GLShaderProgram program, + String name, float alpha, float brightness, float contrast) { + setFieldUniform(program, name, "alpha", alpha); + setFieldUniform(program, name, "brightness", brightness); + setFieldUniform(program, name, "contrast", contrast); + } + + private static void setFieldUniform(GLShaderProgram program, + String structName, String fieldName, Object fieldValue) { + program.setUniform(structName + FIELD_SEPERATOR + fieldName, fieldValue); + } +} diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/glsl/GLShaderProgram.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/glsl/GLShaderProgram.java index a7e72634a3..ad41e267ff 100644 --- a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/glsl/GLShaderProgram.java +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/glsl/GLShaderProgram.java @@ -155,7 +155,6 @@ public class GLShaderProgram { gl.glUseProgram(0); state = State.INITIALIZED; } - loadedUniforms.clear(); } /** @@ -358,6 +357,7 @@ public class GLShaderProgram { glslContext = -1; } state = State.INVALID; + loadedUniforms.clear(); } } diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/AbstractGLColormappedImage.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/AbstractGLColormappedImage.java index fcbba6b048..8f093e27f2 100644 --- a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/AbstractGLColormappedImage.java +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/AbstractGLColormappedImage.java @@ -26,6 +26,8 @@ import com.raytheon.uf.common.colormap.prefs.ColorMapParameters; import com.raytheon.uf.viz.core.drawables.IColormappedImage; import com.raytheon.uf.viz.core.drawables.ext.IImagingExtension; import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.viz.core.gl.dataformat.AbstractGLColorMapDataFormat; +import com.raytheon.viz.core.gl.ext.imaging.GLDataMappingFactory.GLDataMapping; import com.sun.opengl.util.texture.TextureCoords; /** @@ -52,6 +54,8 @@ public abstract class AbstractGLColormappedImage extends AbstractGLImage protected GLCMTextureData data; + private GLDataMapping dataMapping; + public AbstractGLColormappedImage(GLCMTextureData data, ColorMapParameters params, Class extensionClass) { @@ -143,6 +147,15 @@ public abstract class AbstractGLColormappedImage extends AbstractGLImage return data.getTexId(); } + /** + * Returns the GL format of the texture data + * + * @return + */ + public AbstractGLColorMapDataFormat getDataFormat() { + return data.getDataFormat(); + } + /** * the absolute minimum value of a pixel in this image. {@link Double#NaN} * if no absolute minimum exists @@ -233,6 +246,18 @@ public abstract class AbstractGLColormappedImage extends AbstractGLImage data.dispose(); data = null; } + if (dataMapping != null) { + dataMapping.dispose(); + dataMapping = null; + } + } + + public void setDataMapping(GLDataMapping dataMapping) { + this.dataMapping = dataMapping; + } + + public GLDataMapping getDataMapping() { + return dataMapping; } /* diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/GLBufferCMTextureData.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/GLBufferCMTextureData.java new file mode 100644 index 0000000000..3a08ca740e --- /dev/null +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/GLBufferCMTextureData.java @@ -0,0 +1,138 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.viz.core.gl.images; + +import java.nio.Buffer; + +import javax.measure.unit.Unit; +import javax.media.opengl.GL; + +import com.raytheon.uf.common.colormap.image.ColorMapData; +import com.raytheon.viz.core.gl.dataformat.AbstractGLColorMapDataFormat; +import com.raytheon.viz.core.gl.dataformat.GLBufferColorMapData; + +/** + * {@link GLCMTextureData} backed by a {@link Buffer}. The initial functions in + * here were moved here from {@link GLRetrievableCMTextureData} + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Oct 23, 2013 2492       mschenke    Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ + +public class GLBufferCMTextureData extends GLCMTextureData { + + public GLBufferCMTextureData(ColorMapData data, + AbstractGLColorMapDataFormat format) { + this(new GLBufferColorMapData(data, format)); + } + + public GLBufferCMTextureData(GLBufferColorMapData data) { + super(data); + } + + @Override + protected GLBufferColorMapData getDataObject() { + return (GLBufferColorMapData) super.getDataObject(); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.viz.core.gl.images.GLCMTextureData#isStaged() + */ + @Override + public boolean isStaged() { + GLBufferColorMapData data = getDataObject(); + // Override since we have our required data + return data != null && data.getData() != null; + } + + @Override + public void dispose() { + super.dispose(); + if (isStaged()) { + data = null; + } + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.viz.core.gl.images.GLCMTextureData#uploadTexture2D(javax + * .media.opengl.GL, int, int, int) + */ + @Override + protected void createTexture2D(GL gl, int type, int w, int h) { + gl.glTexImage2D(type, 0, getTextureInternalFormat(), w, h, 0, + getTextureFormat(), getTextureType(), getDataObject().getData() + .rewind()); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.viz.core.gl.images.GLCMTextureData#uploadTexture1D(javax + * .media.opengl.GL, int, int) + */ + @Override + protected void createTexture1D(GL gl, int type, int w) { + gl.glTexImage1D(type, 0, getTextureInternalFormat(), w, 0, + getTextureFormat(), getTextureType(), getDataObject().getData() + .rewind()); + } + + /** + * Returns the data value at the given coordinates. TODO: Add support for 1D + * texture sampling, change x,y to int[] index? + * + * @param x + * @param y + * @return + */ + public double getValue(int x, int y) { + double value = Double.NaN; + if (isStaged()) { + value = getDataObject().getValue(x, y).doubleValue(); + } + return value; + } + + /** + * Returns the {@link Unit} associated with the data + * + * @return the dataUnit + */ + public Unit getDataUnit() { + GLBufferColorMapData data = getDataObject(); + return data != null ? data.getDataUnit() : null; + } +} diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/GLCMTextureData.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/GLCMTextureData.java index d9df2d3bff..ce1aa27dd7 100644 --- a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/GLCMTextureData.java +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/GLCMTextureData.java @@ -23,6 +23,7 @@ import javax.media.opengl.GL; import com.raytheon.uf.common.colormap.image.ColorMapData.ColorMapDataType; import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.viz.core.gl.dataformat.AbstractGLColorMapDataFormat; import com.raytheon.viz.core.gl.dataformat.GLColorMapData; import com.raytheon.viz.core.gl.objects.GLTextureObject; @@ -40,6 +41,7 @@ import com.raytheon.viz.core.gl.objects.GLTextureObject; * format for offscreen textures. * Oct 16, 2013 2333 mschenke Moved retrievable/Buffer parts out and * into separate class. + * Oct 23, 2013 2492 mschenke Added support for 1D textures * * * @@ -116,6 +118,9 @@ public class GLCMTextureData { return false; } int type = getTextureStorageType(); + if (type == GL.GL_NONE) { + throw new VizException("Unsupported dimension size for texture"); + } tex = new GLTextureObject(this); tex.bind(gl, type); @@ -125,7 +130,8 @@ public class GLCMTextureData { gl.glTexParameteri(type, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); gl.glTexParameteri(type, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); - if (isDataFormatScaled() && isDataFormatSigned()) { + boolean changeScaleAndBias = isDataFormatScaled() && isDataFormatSigned(); + if (changeScaleAndBias) { // GL maps signed data into the range -1 to 1, but gl trims // this to a valid range of 0 to 1, essentially removing // negative values. Adding a scale and bias remaps this from @@ -135,20 +141,23 @@ public class GLCMTextureData { gl.glPixelTransferf(GL.GL_RED_BIAS, 0.5f); } - int w = getDimensionSize(0); - int h = getDimensionSize(1); + if (type == GL.GL_TEXTURE_1D) { + createTexture1D(gl, type, getDimensionSize(0)); + } else if (type == GL.GL_TEXTURE_2D) { + createTexture2D(gl, type, getDimensionSize(0), getDimensionSize(1)); + } - createTexture2D(gl, type, w, h); - - gl.glPixelTransferf(GL.GL_RED_SCALE, 1.0f); - gl.glPixelTransferf(GL.GL_RED_BIAS, 0.0f); + if (changeScaleAndBias) { + gl.glPixelTransferf(GL.GL_RED_SCALE, 1.0f); + gl.glPixelTransferf(GL.GL_RED_BIAS, 0.0f); + } return true; } /** - * Creates a 2D texture for type, with width/height w/h. Texture object must - * be bound for this call to work using + * Creates a 2D texture for type, with width/height, w/h. Texture object + * must be bound for this call to work using * {@link GLTextureObject#bind(GL, int)} * * @param gl @@ -163,6 +172,22 @@ public class GLCMTextureData { getTextureFormat(), getTextureType(), null); } + /** + * Creates a 1D texture for type, with width, w. Texture object must be + * bound for this call to work using {@link GLTextureObject#bind(GL, int)} + * + * @param gl + * @param type + * @param w + * @param h + */ + protected void createTexture1D(GL gl, int type, int w) { + // Allocate our space on the graphics card, no buffer to upload so it + // will be filled with default values initially (0s) + gl.glTexImage1D(type, 0, getTextureInternalFormat(), w, 0, + getTextureFormat(), getTextureType(), null); + } + /** * Checks if texture data is staged. If false, a call to * {@link #stageTexture()} is needed before texture can be loaded @@ -184,6 +209,15 @@ public class GLCMTextureData { return tex != null && tex.isValid(); } + /** + * Returns the GL format of the texture data + * + * @return + */ + public AbstractGLColorMapDataFormat getDataFormat() { + return data.getDataFormat(); + } + /** * Returns the size of the dimension index passed in (0=width,1=height) * @@ -272,12 +306,20 @@ public class GLCMTextureData { } /** - * The texture storage type of the data (TEXTURE_2D) + * The texture storage type of the data. Will return {@link GL#GL_NONE} if + * unsupported dimension is detected * * @return */ public int getTextureStorageType() { - return GL.GL_TEXTURE_2D; + switch (data.getNumDimensions()) { + case 1: + return GL.GL_TEXTURE_1D; + case 2: + return GL.GL_TEXTURE_2D; + default: + return GL.GL_NONE; + } } /** diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/GLRetrievableCMTextureData.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/GLRetrievableCMTextureData.java index a77cd86450..1d9458945e 100644 --- a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/GLRetrievableCMTextureData.java +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/images/GLRetrievableCMTextureData.java @@ -38,8 +38,9 @@ import com.raytheon.viz.core.gl.internal.cache.ImageCache; import com.raytheon.viz.core.gl.internal.cache.ImageCache.CacheType; /** - * Object that represents a colormapped texture that can be unloaded and - * reloaded from main/graphics memory using a retrieval callback + * {@link GLCMTextureData} that's backed by a {@link Buffer} that represents a + * colormapped texture that is cacheable and can be unloaded and reloaded from + * main/graphics memory using a retrieval callback * *
  * 
@@ -47,7 +48,8 @@ import com.raytheon.viz.core.gl.internal.cache.ImageCache.CacheType;
  * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Jun 24, 2013            mschenke     Initial creation
+ * Jun 24, 2013            mschenke    Initial creation
+ * Oct 23, 2013 2492       mschenke    Extracted Buffer backing into super class   
  * 
  * 
* @@ -55,7 +57,7 @@ import com.raytheon.viz.core.gl.internal.cache.ImageCache.CacheType; * @version 1.0 */ -public class GLRetrievableCMTextureData extends GLCMTextureData implements +public class GLRetrievableCMTextureData extends GLBufferCMTextureData implements IImageCacheable { private static Map texMap = new HashMap(); @@ -95,11 +97,6 @@ public class GLRetrievableCMTextureData extends GLCMTextureData implements this.callback = callback; } - @Override - protected GLBufferColorMapData getDataObject() { - return (GLBufferColorMapData) super.getDataObject(); - } - /* * (non-Javadoc) * @@ -224,18 +221,6 @@ public class GLRetrievableCMTextureData extends GLCMTextureData implements return 0; } - /* - * (non-Javadoc) - * - * @see com.raytheon.viz.core.gl.images.GLCMTextureData#isStaged() - */ - @Override - public boolean isStaged() { - GLBufferColorMapData data = getDataObject(); - // Override since we have our required data - return data != null && data.getData() != null; - } - public double getValue(int x, int y) { GLBufferColorMapData data = getDataObject(); double value = Double.NaN; @@ -265,27 +250,4 @@ public class GLRetrievableCMTextureData extends GLCMTextureData implements return value; } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.viz.core.gl.images.GLCMTextureData#uploadTexture2D(javax - * .media.opengl.GL, int, int, int) - */ - @Override - protected void createTexture2D(GL gl, int type, int w, int h) { - gl.glTexImage2D(type, 0, getTextureInternalFormat(), w, h, 0, - getTextureFormat(), getTextureType(), getDataObject().getData() - .rewind()); - } - - /** - * Returns the {@link Unit} associated with the data - * - * @return the dataUnit - */ - public Unit getDataUnit() { - GLBufferColorMapData data = getDataObject(); - return data != null ? data.getDataUnit() : null; - } } diff --git a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/internal/GLTarget.java b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/internal/GLTarget.java index b9b03e7f5e..553f339c9c 100644 --- a/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/internal/GLTarget.java +++ b/cave/com.raytheon.viz.core.gl/src/com/raytheon/viz/core/gl/internal/GLTarget.java @@ -53,6 +53,7 @@ import org.geotools.coverage.grid.GeneralGridGeometry; import com.raytheon.uf.common.colormap.ColorMap; import com.raytheon.uf.common.colormap.IColorMap; import com.raytheon.uf.common.colormap.image.ColorMapData; +import com.raytheon.uf.common.colormap.image.ColorMapData.ColorMapDataType; import com.raytheon.uf.common.colormap.prefs.ColorMapParameters; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; @@ -67,7 +68,6 @@ import com.raytheon.uf.viz.core.DrawableString; import com.raytheon.uf.viz.core.IExtent; import com.raytheon.uf.viz.core.IGraphicsTarget; import com.raytheon.uf.viz.core.IView; -import com.raytheon.uf.viz.core.data.IColorMapDataRetrievalCallback; import com.raytheon.uf.viz.core.data.IRenderedImageCallback; import com.raytheon.uf.viz.core.drawables.IDescriptor; import com.raytheon.uf.viz.core.drawables.IFont; @@ -86,11 +86,12 @@ import com.raytheon.viz.core.gl.GLDisposalManager; import com.raytheon.viz.core.gl.GLStats; import com.raytheon.viz.core.gl.IGLFont; import com.raytheon.viz.core.gl.IGLTarget; -import com.raytheon.viz.core.gl.ext.imaging.GLColormappedImageExtension; +import com.raytheon.viz.core.gl.dataformat.GLByteDataFormat; import com.raytheon.viz.core.gl.ext.imaging.GLDefaultImagingExtension; import com.raytheon.viz.core.gl.glsl.GLSLFactory; +import com.raytheon.viz.core.gl.glsl.GLSLStructFactory; import com.raytheon.viz.core.gl.glsl.GLShaderProgram; -import com.raytheon.viz.core.gl.images.GLColormappedImage; +import com.raytheon.viz.core.gl.images.GLBufferCMTextureData; import com.raytheon.viz.core.gl.images.GLImage; import com.raytheon.viz.core.gl.objects.GLTextureObject; import com.sun.opengl.util.Screenshot; @@ -128,6 +129,7 @@ import com.sun.opengl.util.j2d.TextRenderer; * strings are always readable despite extent * May 28, 2013 1638 mschenke Made sure {@link TextStyle#BLANKED} text is drawing correct size * box around text + * Nov 4, 2013 2492 mschenke Switched colormap drawing to use 1D texture object for alpha mask * * * @@ -517,28 +519,19 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget { GLTextureObject i = getColorMapTexture(colorMapParams); - GLColormappedImage alphaMaskTexture = null; + GLBufferCMTextureData alphaMaskTexture = null; if (colorMapParams.isUseMask() && capabilities.cardSupportsShaders) { - final byte[] mask = colorMapParams.getAlphaMask(); - alphaMaskTexture = getExtension( - GLColormappedImageExtension.class).initializeRaster( - new IColorMapDataRetrievalCallback() { - @Override - public ColorMapData getColorMapData() - throws VizException { - return new ColorMapData(ByteBuffer.wrap(mask), - new int[] { mask.length, 1 }); - } - - }, colorMapParams); - alphaMaskTexture.stage(); - alphaMaskTexture.target(this); - } - - if (alphaMaskTexture != null) { + byte[] mask = colorMapParams.getAlphaMask(); + alphaMaskTexture = new GLBufferCMTextureData(new ColorMapData( + ByteBuffer.wrap(mask), new int[] { mask.length }, + ColorMapDataType.BYTE), new GLByteDataFormat()); gl.glActiveTexture(GL.GL_TEXTURE1); - gl.glBindTexture(alphaMaskTexture.getTextureStorageType(), - alphaMaskTexture.getTextureid()); + if (alphaMaskTexture.loadTexture(gl)) { + gl.glBindTexture(alphaMaskTexture.getTextureStorageType(), + alphaMaskTexture.getTexId()); + } else { + alphaMaskTexture.dispose(); + } } gl.glPolygonMode(GL.GL_BACK, GL.GL_FILL); @@ -573,14 +566,11 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget { "colormap"); if (program != null) { program.startShader(); - program.setUniform("alphaVal", blendAlpha); - program.setUniform("brightness", brightness); - program.setUniform("contrast", contrast); - program.setUniform("colorMap", 0); - program.setUniform("logFactor", logFactor); - program.setUniform("alphaMask", 1); - program.setUniform("applyMask", - colorMapParams.isUseMask() ? 1 : 0); + + GLSLStructFactory.createColorMapping(program, + "colorMapping", 0, 1, colorMapParams); + GLSLStructFactory.createColorModifiers(program, + "modifiers", blendAlpha, brightness, contrast); program.setUniform("bkgrndRed", backgroundColor.red / 255.0f); program.setUniform("bkgrndGreen", diff --git a/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/topo/TopoResource.java b/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/topo/TopoResource.java index 14940fd703..da86576148 100644 --- a/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/topo/TopoResource.java +++ b/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/topo/TopoResource.java @@ -25,7 +25,6 @@ import java.text.DecimalFormat; import java.util.Arrays; import javax.measure.converter.UnitConverter; -import javax.measure.unit.NonSI; import javax.measure.unit.SI; import javax.measure.unit.Unit; import javax.measure.unit.UnitFormat; @@ -40,10 +39,10 @@ import com.raytheon.uf.common.datastorage.IDataStore; import com.raytheon.uf.common.geospatial.ReferencedCoordinate; import com.raytheon.uf.common.style.LabelingPreferences; import com.raytheon.uf.common.style.ParamLevelMatchCriteria; +import com.raytheon.uf.common.style.StyleException; import com.raytheon.uf.common.style.StyleManager; import com.raytheon.uf.common.style.StyleManager.StyleType; import com.raytheon.uf.common.style.StyleRule; -import com.raytheon.uf.common.style.StyleException; import com.raytheon.uf.common.style.image.DataScale; import com.raytheon.uf.common.style.image.ImagePreferences; import com.raytheon.uf.common.style.image.SamplePreferences; @@ -148,7 +147,8 @@ public class TopoResource extends // Set data unit, specify in resource data? Look up in data record? params.setDataUnit(SI.METER); - params.setDisplayUnit(NonSI.FOOT); + params.setDisplayUnit(SI.METER); + params.setColorMapUnit(SI.METER); params.setColorMapMin(-19); params.setColorMapMax(5000); params.setDataMin(Short.MIN_VALUE); @@ -169,15 +169,17 @@ public class TopoResource extends DataScale scale = prefs.getDataScale(); if (scale != null) { + UnitConverter displayToColorMap = params + .getDisplayToColorMapConverter(); Double minVal = scale.getMinValue(); Double maxVal = scale.getMaxValue(); if (minVal != null) { - params.setColorMapMin((float) params - .getDisplayToDataConverter().convert(minVal)); + params.setColorMapMin((float) displayToColorMap + .convert(minVal)); } if (maxVal != null) { - params.setColorMapMax((float) params - .getDisplayToDataConverter().convert(maxVal)); + params.setColorMapMax((float) displayToColorMap + .convert(maxVal)); } } diff --git a/edexOsgi/com.raytheon.uf.common.colormap/src/com/raytheon/uf/common/colormap/image/Colormapper.java b/edexOsgi/com.raytheon.uf.common.colormap/src/com/raytheon/uf/common/colormap/image/Colormapper.java index b4e434000e..d225d7317a 100644 --- a/edexOsgi/com.raytheon.uf.common.colormap/src/com/raytheon/uf/common/colormap/image/Colormapper.java +++ b/edexOsgi/com.raytheon.uf.common.colormap/src/com/raytheon/uf/common/colormap/image/Colormapper.java @@ -35,21 +35,27 @@ import java.nio.IntBuffer; import java.nio.ShortBuffer; import java.util.List; +import javax.measure.converter.UnitConverter; +import javax.measure.unit.Unit; + import com.raytheon.uf.common.colormap.Color; import com.raytheon.uf.common.colormap.IColorMap; import com.raytheon.uf.common.colormap.image.ColorMapData.ColorMapDataType; import com.raytheon.uf.common.colormap.prefs.ColorMapParameters; /** - * Colormapper class + * Colormapper class, written to mimic colormapRaster.glsl in java. Any changes + * to files mapping.glsl or colormapRaster.glsl will probably need to be + * reflected here * *
  * 
  * SOFTWARE HISTORY
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Aug 13, 2010            mschenke     Initial creation
+ * Aug 13, 2010            mschenke    Initial creation
  * Feb 15, 2013 1638       mschenke    Moved IndexColorModel creation to common.colormap utility
+ * Nov  4, 2013 2492       mschenke    Rewritten to model glsl equivalent
  * 
  * 
* @@ -77,39 +83,42 @@ public class Colormapper { int width = cmapData.getDimensions()[0]; int height = cmapData.getDimensions()[1]; Buffer buf = cmapData.getBuffer(); - ColorMapDataType dataType = cmapData.getDataType(); - - // Parameters ported from raster.glsl - boolean log = parameters.isLogarithmic(); - double logFactor = parameters.getLogFactor(); - boolean mirror = parameters.isMirror(); - double cmapMin = parameters.getColorMapMin(); - double cmapMax = parameters.getColorMapMax(); - int colorMapSz = parameters.getColorMap().getSize(); - - double diff = Math.abs(cmapMax - cmapMin); - int dataSize = buf.capacity(); - byte[] cmapedData = new byte[buf.capacity()]; + ColorMapDataType dataType = cmapData.getDataType(); + double noDataValue = parameters.getNoDataValue(); + Unit dataUnit = cmapData.getDataUnit(); + if (dataUnit == null) { + dataUnit = parameters.getDataUnit(); + } + Unit colorMapUnit = parameters.getColorMapUnit(); + UnitConverter converter = null; + if (dataUnit != null && colorMapUnit != null + && parameters.getDataMapping() == null + && dataUnit.equals(colorMapUnit) == false + && dataUnit.isCompatible(colorMapUnit) == true) { + converter = dataUnit.getConverterTo(colorMapUnit); + } + int numColors = parameters.getColorMap().getSize(); + byte[] indexArray = new byte[dataSize]; + for (int i = 0; i < dataSize; ++i) { - double value = getValue(buf, i, dataType); - double index = 0.0f; - if (log) { - index = findIndexLog(value, logFactor, cmapMin, cmapMax, mirror); - } else { - index = ((value - cmapMin) / diff); + double dataValue = getDataValue(buf, i, dataType); + if (Double.isNaN(dataValue) || dataValue == noDataValue) { + // Skip, need equivalent of setting alpha to 0 + continue; } - if (index < 0.0) { - index = 0.0; - } else if (index > 1.0) { - index = 1.0; + double cmapValue = dataValue; + if (converter != null) { + cmapValue = converter.convert(dataValue); } - cmapedData[i] = findColorIndex(index, logFactor, colorMapSz); + + double index = getColorMappingIndex(cmapValue, parameters); + indexArray[i] = (byte) (capIndex(index) * (numColors - 1)); } IndexColorModel cm = buildColorModel(parameters.getColorMap()); - DataBufferByte byteArray = new DataBufferByte(cmapedData, width + DataBufferByte byteArray = new DataBufferByte(indexArray, width * height); MultiPixelPackedSampleModel sample = new MultiPixelPackedSampleModel( @@ -123,114 +132,6 @@ public class Colormapper { return bi; } - private static double getValue(Buffer buffer, int idx, - ColorMapDataType dataType) { - switch (dataType) { - case BYTE: { - return ((ByteBuffer) buffer).get(idx) & 0xFF; - } - case SIGNED_BYTE: { - return ((ByteBuffer) buffer).get(idx); - } - case SHORT: { - return ((ShortBuffer) buffer).get(idx); - } - case UNSIGNED_SHORT: { - return ((ShortBuffer) buffer).get(idx) & 0xFFFF; - } - case INT: { - return ((IntBuffer) buffer).get(idx); - } - case FLOAT: { - return ((FloatBuffer) buffer).get(idx); - } - } - return 0.0; - } - - private static double findIndexLog(double value, double logFactor, - double cmapMin, double cmapMax, boolean mirror) { - double index = 0.0; - // is this strictly negative, strictly positive or neg to pos scaling? - if (cmapMin >= 0.0 && cmapMax >= 0.0 && mirror == false) { - if (value < cmapMin) { - index = 0.0; - } else { - // simple calculation - index = ((Math.log(value) - Math.log(cmapMin)) / Math.abs(Math - .log(cmapMax) - Math.log(cmapMin))); - } - } else if (cmapMin <= 0.0 && cmapMax <= 0.0 && mirror == false) { - index = ((Math.log(value) - Math.log(cmapMax)) / Math.abs(Math - .log(cmapMin) - Math.log(cmapMax))); - } else { - // special case, neg to pos: - double colorMapMin = cmapMin; - double colorMapMax = cmapMax; - double zeroVal = Math.max(colorMapMax, Math.abs(colorMapMin)) * 0.0001; - if (mirror && (colorMapMin > 0.0 || colorMapMax < 0.0)) { - if (colorMapMax < 0.0) { - colorMapMax = -cmapMax; - value = -value; - zeroVal = -colorMapMin; - } else { - zeroVal = cmapMin; - } - colorMapMin = -cmapMax; - } - double leftZero = 0.0; - double rightZero = 0.0; - double absLogZeroVal = Math.abs(Math.log(zeroVal)); - - rightZero = absLogZeroVal + Math.log(colorMapMax); - - double cmapMax2 = Math.abs(colorMapMin); - - leftZero = absLogZeroVal + Math.log(cmapMax2); - - double zeroIndex = leftZero / (leftZero + rightZero); - - // figure out index for texture val - double absTextureColor = Math.abs(value); - if (absTextureColor <= zeroVal) { - index = zeroIndex; - } else if (value > 0.0) { - // positive texture color value, find index from 0 to - // cmapMax: - double logTexColor = absLogZeroVal + Math.log(value); - - double texIndex = logTexColor / rightZero; - index = (zeroIndex + ((1.0 - zeroIndex) * texIndex)); - } else { - // negative texture color value, find index from 0 to - // cmapMax: - double logTexColor = absLogZeroVal + Math.log(absTextureColor); - - double texIndex = logTexColor / leftZero; - index = (zeroIndex - (zeroIndex * texIndex)); - } - } - return index; - } - - private static byte findColorIndex(double index, double logFactor, - int colorMapSz) { - if (logFactor > 0.0) { - double minLog = Math.log(logFactor); - double maxLog = Math.log(logFactor + 1.0); - - double lg = Math.log(logFactor + index); - - index = (lg - minLog) / (maxLog - minLog); - if (index < 0.0) { - index = 0.0; - } else if (index > 1.0) { - index = 1.0; - } - } - return (byte) (index * (colorMapSz - 1)); - } - /** * Builds a color model from a color map * @@ -256,4 +157,264 @@ public class Colormapper { return new IndexColorModel(COLOR_MODEL_NUMBER_BITS, size, red, green, blue, alpha); } + + /** + * Sets an index value into the indexArray for use in a Raster with + * IndexColorModel set + * + * @param dataArray + * @param idx + * @param idxValue + */ + public static void setIndexValue(Object dataArray, int idx, int idxValue) { + if (dataArray instanceof byte[]) { + ((byte[]) dataArray)[idx] = (byte) idxValue; + } else if (dataArray instanceof short[]) { + ((short[]) dataArray)[idx] = (short) idxValue; + } else if (dataArray instanceof int[]) { + ((int[]) dataArray)[idx] = idxValue; + } else { + throw new IllegalArgumentException("Unsupported dataArray type: " + + (dataArray != null ? dataArray.getClass() : null)); + } + } + + /** + * Returns the double representation of the data value for the Buffer at the + * given index + * + * @param buffer + * @param idx + * @param dataType + * @return + */ + public static double getDataValue(Buffer buffer, int idx, + ColorMapDataType dataType) { + switch (dataType) { + case BYTE: { + return ((ByteBuffer) buffer).get(idx) & 0xFF; + } + case SIGNED_BYTE: { + return ((ByteBuffer) buffer).get(idx); + } + case SHORT: { + return ((ShortBuffer) buffer).get(idx); + } + case UNSIGNED_SHORT: { + return ((ShortBuffer) buffer).get(idx) & 0xFFFF; + } + case INT: { + return ((IntBuffer) buffer).get(idx); + } + case FLOAT: { + return ((FloatBuffer) buffer).get(idx); + } + } + return 0.0; + } + + /** + * This function takes an index value and caps it to the range 0-1 + */ + public static double capIndex(double index) { + if (index < 0.0) { + index = 0.0; + } else if (index > 1.0) { + index = 1.0; + } + return index; + } + + /** + * Given a colorMap value linearly determine the index into cmapMin/cmapMax + * + * @param cmapValue + * @param cmapMin + * @param cmapMax + * @return + */ + public static double getLinearIndex(double cmapValue, double cmapMin, + double cmapMax) { + return (cmapValue - cmapMin) / (cmapMax - cmapMin); + } + + /** + * This function logarithmically finds the index for the cmapValue into + * cmapMin/cmapMax. + * + * @param cmapValue + * @param cmapMin + * @param cmapMax + * @param mirror + * @return + */ + public static double getLogIndex(double cmapValue, double cmapMin, + double cmapMax, boolean mirror) { + double index = 0.0; + // is this strictly negative, strictly positive or neg to pos scaling? + if (cmapMin >= 0.0 && cmapMax >= 0.0 && !mirror) { + if (cmapValue < cmapMin) { + index = 0.0; + } else { + // simple calculation + index = ((Math.log(cmapValue) - Math.log(cmapMin)) / Math + .abs(Math.log(cmapMax) - Math.log(cmapMin))); + } + } else if (cmapMin <= 0.0 && cmapMax <= 0.0 && !mirror) { + index = ((Math.log(cmapValue) - Math.log(cmapMax)) / Math.abs(Math + .log(cmapMin) - Math.log(cmapMax))); + } else { + // special case, neg to pos: + double colorMapMin = cmapMin; + double colorMapMax = cmapMax; + double zeroVal = Math.max(colorMapMax, Math.abs(colorMapMin)) * 0.0001; + if (mirror && (colorMapMin > 0.0 || colorMapMax < 0.0)) { + if (colorMapMax < 0.0) { + colorMapMax = -cmapMax; + cmapValue = -cmapValue; + zeroVal = -colorMapMin; + } else { + zeroVal = cmapMin; + } + colorMapMin = -cmapMax; + } + double leftZero = 0.0; + double rightZero = 0.0; + double absLogZeroVal = Math.abs(Math.log(zeroVal)); + + rightZero = absLogZeroVal + Math.log(colorMapMax); + + double cmapMax2 = Math.abs(colorMapMin); + + leftZero = absLogZeroVal + Math.log(cmapMax2); + + double zeroIndex = leftZero / (leftZero + rightZero); + + // figure out index for texture val + double absTextureColor = Math.abs(cmapValue); + if (absTextureColor <= zeroVal) { + index = zeroIndex; + } else if (cmapValue > 0.0) { + // positive texture color value, find index from 0 to + // cmapMax: + double logTexColor = absLogZeroVal + Math.log(cmapValue); + + double texIndex = logTexColor / rightZero; + index = (zeroIndex + ((1.0 - zeroIndex) * texIndex)); + } else { + // negative texture color value, find index from 0 to + // cmapMax: + double logTexColor = absLogZeroVal + Math.log(absTextureColor); + + double texIndex = logTexColor / leftZero; + index = (zeroIndex - (zeroIndex * texIndex)); + } + } + return index; + } + + /** + * This function calculates a new index to use based on the logFactor and + * passed in index + * + * @param index + * @param logFactor + * @return + */ + public static double getLogFactorIndex(double index, double logFactor) { + if (logFactor > 0.0) { + double minLog = Math.log(logFactor); + double maxLog = Math.log(logFactor + 1.0); + + double lg = Math.log(logFactor + index); + + index = (lg - minLog) / (maxLog - minLog); + if (index < 0.0) { + index = 0.0; + } else if (index > 1.0) { + index = 1.0; + } + } + return index; + } + + /** + * Returns an index for the cmapValue based on the + * {@link ColorMapParameters} + * + * @param cmapValue + * @param colorMapping + * @return + */ + public static double getColorMappingIndex(double cmapValue, + ColorMapParameters colorMapParameters) { + double logFactor = colorMapParameters.getLogFactor(); + double cmapMin = colorMapParameters.getColorMapMin(); + double cmapMax = colorMapParameters.getColorMapMax(); + + double index; + if (colorMapParameters.isLogarithmic()) { + index = getLogIndex(cmapValue, cmapMin, cmapMax, + colorMapParameters.isMirror()); + } else { + index = getLinearIndex(cmapValue, cmapMin, cmapMax); + } + + // Apply logFactor if set + if (logFactor > 0.0) { + index = getLogFactorIndex(index, logFactor); + } + return index; + } + + /** + * Gets the {@link Color} from the color map in the parameters at the index + * (capped 0-1) passed in + * + * @param index + * @param colorMapParameters + * @return + */ + public static Color getColorByIndex(double index, + ColorMapParameters colorMapParameters) { + index = capIndex(index); + IColorMap colorMap = colorMapParameters.getColorMap(); + if (colorMapParameters.isInterpolate()) { + index = 0.5f; + index = (index * (colorMap.getSize() - 1)); + int lowIndex = (int) Math.floor(index); + int highIndex = (int) Math.ceil(index); + double lowWeight = highIndex - index; + double highWeight = 1.0f - lowWeight; + Color low = colorMap.getColors().get(lowIndex); + Color high = colorMap.getColors().get(highIndex); + float r = (float) (lowWeight * low.getRed() + highWeight + * high.getRed()); + float g = (float) (lowWeight * low.getGreen() + highWeight + * high.getGreen()); + float b = (float) (lowWeight * low.getBlue() + highWeight + * high.getBlue()); + float a = (float) (lowWeight * low.getAlpha() + highWeight + * high.getAlpha()); + return new Color(r, g, b, a); + } else { + return colorMap.getColors().get( + (int) (index * (colorMap.getSize() - 1))); + } + } + + /** + * Returns a {@link Color} for the cmapValue based on the + * {@link ColorMapParameters} + * + * @param cmapValue + * @param colorMapParameters + * @return + */ + public static Color getColorByValue(double cmapValue, + ColorMapParameters colorMapParameters) { + return getColorByIndex( + getColorMappingIndex(cmapValue, colorMapParameters), + colorMapParameters); + } } diff --git a/edexOsgi/com.raytheon.uf.common.colormap/src/com/raytheon/uf/common/colormap/prefs/ColorMapParameters.java b/edexOsgi/com.raytheon.uf.common.colormap/src/com/raytheon/uf/common/colormap/prefs/ColorMapParameters.java index 4793b2703b..b20d9a1518 100644 --- a/edexOsgi/com.raytheon.uf.common.colormap/src/com/raytheon/uf/common/colormap/prefs/ColorMapParameters.java +++ b/edexOsgi/com.raytheon.uf.common.colormap/src/com/raytheon/uf/common/colormap/prefs/ColorMapParameters.java @@ -22,7 +22,9 @@ package com.raytheon.uf.common.colormap.prefs; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; import javax.measure.converter.UnitConverter; @@ -35,8 +37,8 @@ import javax.xml.bind.annotation.XmlElement; import com.raytheon.uf.common.colormap.AbstractColorMap; import com.raytheon.uf.common.colormap.Color; import com.raytheon.uf.common.colormap.IColorMap; +import com.raytheon.uf.common.colormap.image.Colormapper; import com.raytheon.uf.common.colormap.prefs.DataMappingPreferences.DataMappingEntry; -import com.raytheon.uf.common.serialization.ISerializableObject; /** * Colormap Parameters @@ -56,14 +58,15 @@ import com.raytheon.uf.common.serialization.ISerializableObject; * Jun 14, 2013 DR 16070 jgerth Utilize data mapping * Aug 2, 2013 2211 mschenke Backed out 16070 changes, made * dataUnit/imageUnit properly commutative. - * + * Nov 4, 2013 2492 mschenke Cleaned up variable naming to make purpose + * clear (image->colormap) * * * @author chammack * @version 1 */ @XmlAccessorType(XmlAccessType.NONE) -public class ColorMapParameters implements Cloneable, ISerializableObject { +public class ColorMapParameters { @XmlAccessorType(XmlAccessType.NONE) public static class PersistedParameters { @@ -123,13 +126,13 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { protected Set listeners = new HashSet(); - /** Units of the colormap parameters (min/max) */ + /** Units colormapping should be displayed in */ protected Unit displayUnit; - /** Units of the image pixel values */ - protected Unit imageUnit; + /** Units colormapping will occur in */ + protected Unit colorMapUnit; - /** Units of the data values */ + /** Units of the data values to colormap */ protected Unit dataUnit; /** The maximum value used to apply the colormap */ @@ -158,23 +161,23 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { @XmlAttribute protected String colorMapName; - /** The converter that converts data values to display values * */ + /** The converter that converts data values to {@link #displayUnit} * */ protected UnitConverter dataToDisplayConverter; - /** The converter that converts display values to data values * */ + /** The converter that converts display values to {@link #dataUnit} * */ protected UnitConverter displayToDataConverter; - /** The converter that converts data values to image pixels */ - protected UnitConverter dataToImageConverter; + /** The converter that converts data values to {@link #colorMapUnit} */ + protected UnitConverter dataToColorMapConverter; - /** The converter that converts image pixels to data values */ - protected UnitConverter imageToDataConverter; + /** The converter that converts color map unit values to {@link #dataUnit} */ + protected UnitConverter colorMapToDataConverter; - /** The converter that converts image pixels to display values */ - protected UnitConverter imageToDisplayConverter; + /** The converter that converts color map unit values to {@link #displayUnit} */ + protected UnitConverter colorMapToDisplayConverter; - /** The converter that converts display values to image pixels */ - protected UnitConverter displayToImageConverter; + /** The converter that converts display values to {@link #colorMapUnit} */ + protected UnitConverter displayToColorMapConverter; protected DataMappingPreferences dataMapping; @@ -201,7 +204,7 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { /** Specify whether the colormap should be interpolated */ protected boolean interpolate = false; - public static class LabelEntry { + public static class LabelEntry implements Comparable { private float location; private String text; @@ -258,8 +261,25 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { return true; } + /* + * (non-Javadoc) + * + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(LabelEntry o) { + return Double.compare(getLocation(), o.getLocation()); + } + } + /** + * Creates a {@link UnitConverter} converting the from unit to the to unit. + * + * @param from + * @param to + * @return The unit converter or null of units are not compatible + */ private UnitConverter constructConverter(Unit from, Unit to) { UnitConverter converter = null; @@ -270,22 +290,34 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { return converter; } - private void addLabel(float dispValue, String s) { - float index = getIndexByValue(dispValue); + /** + * Adds a label for a {@link #displayUnit} value + * + * @param colorMapValue + * @param s + */ + private void addDisplayValueLabel(float dispValue, String s) { + float colorMapValue = dispValue; + UnitConverter displayToColorMap = getDisplayToColorMapConverter(); + if (displayToColorMap != null) { + colorMapValue = (float) displayToColorMap.convert(dispValue); + } + addColorMapValueLabel(colorMapValue, s); + } + + /** + * Adds a label for a {@link #colorMapUnit} value + * + * @param colorMapValue + * @param s + */ + private void addColorMapValueLabel(float colorMapValue, String s) { + double index = Colormapper.getColorMappingIndex(colorMapValue, this); if (index > 1.0 || index < 0.0) { return; } - labels.add(new LabelEntry(s, index)); - } - - private void addLabel(int pixelValue, String s) { - float location = (float) pixelValue / 255; - if (location > 1.0 || location < 0.0) { - return; - } - - labels.add(new LabelEntry(s, location)); + labels.add(new LabelEntry(s, (float) index)); } private void computeLabels() { @@ -298,7 +330,7 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { if (colorMapRange != 0.0) { for (float label : colorBarIntervals) { String s = format.format(label); - addLabel(label, s); + addDisplayValueLabel(label, s); } } } else if (dataMapping != null) { @@ -309,14 +341,15 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { if (s == null) { s = format.format(dispValue); } - addLabel(dispValue, s); + addDisplayValueLabel(dispValue, s); } else if (entry.getPixelValue() != null && !"NO DATA".equals(s)) { - double pixelValue = entry.getPixelValue(); - addLabel((int) pixelValue, s); + float pixelValue = entry.getPixelValue().floatValue(); + addColorMapValueLabel(pixelValue, s); } } } + Collections.sort(labels); recomputeLabels = false; } @@ -357,22 +390,26 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { } /** - * @return the unit + * Returns the display unit + * + * @return The unit colormapping should be displayed in */ public Unit getDisplayUnit() { return displayUnit; } /** + * Sets the display units + * * @param unit - * the unit to set + * The unit colormapping should be displayed in */ public void setDisplayUnit(Unit unit) { this.displayUnit = unit; recomputeLabels = true; - displayToImageConverter = null; - imageToDisplayConverter = null; + displayToColorMapConverter = null; + colorMapToDisplayConverter = null; displayToDataConverter = null; dataToDisplayConverter = null; @@ -380,25 +417,32 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { } /** - * @return the colorMapMax + * Returns the maximum range value the colormapping occurs over + * + * @return the maximum range value in {@link #colorMapUnit} */ public float getColorMapMax() { return colorMapMax; } /** + * Sets the maximum range value the colormapping occurs over + * * @param colorMapMax - * the colorMapMax to set + * the maximum range value in {@link #colorMapUnit} */ public void setColorMapMax(float colorMapMax) { setColorMapMax(colorMapMax, false); } /** + * Sets the maximum range value the colormapping occurs over + * * @param colorMapMax - * the colorMapMax to set + * the maximum range value in {@link #colorMapUnit} * @param persist - * specifies whether to persist this value when saved + * true indicates colorMapMax should be persisted through + * serialization */ public void setColorMapMax(float colorMapMax, boolean persist) { this.colorMapMax = colorMapMax; @@ -410,25 +454,32 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { } /** - * @return the colorMapMin + * Returns the minimum range value the colormapping occurs over + * + * @return the minimum range value in {@link #colorMapUnit} */ public float getColorMapMin() { return colorMapMin; } /** + * Sets the minimum range value the colormapping occurs over + * * @param colorMapMin - * the colorMapMin to set + * the minimum range value in {@link #colorMapUnit} */ public void setColorMapMin(float colorMapMin) { setColorMapMin(colorMapMin, false); } /** + * Sets the minimum range value the colormapping occurs over + * * @param colorMapMin - * the colorMapMin to set + * the minimum range value in {@link #colorMapUnit} * @param persist - * specifies whether to persist this value when saved + * true indicates colorMapMin should be persisted through + * serialization */ public void setColorMapMin(float colorMapMin, boolean persist) { this.colorMapMin = colorMapMin; @@ -510,6 +561,8 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { } /** + * Returns the unit data values to be colormapped are in + * * @return the dataUnit */ public Unit getDataUnit() { @@ -517,18 +570,20 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { } /** + * Sets the unit data values to be colormapped are in + * * @param dataUnit * the dataUnit to set */ public void setDataUnit(Unit dataUnit) { this.dataUnit = dataUnit; - if (dataUnit != null && imageUnit == null) { - setImageUnit(dataUnit); + if (dataUnit != null && colorMapUnit == null) { + setColorMapUnit(dataUnit); } - dataToImageConverter = null; - imageToDataConverter = null; + dataToColorMapConverter = null; + colorMapToDataConverter = null; dataToDisplayConverter = null; displayToDataConverter = null; @@ -537,6 +592,9 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { } /** + * Returns the {@link UnitConverter} from {@link #dataUnit} to + * {@link #displayUnit} + * * @return the dataToDisplayConverter */ public UnitConverter getDataToDisplayConverter() { @@ -550,6 +608,9 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { } /** + * Returns the {@link UnitConverter} from {@link #displayUnit} to + * {@link #dataUnit} + * * @return the displayToDataConverter */ public UnitConverter getDisplayToDataConverter() { @@ -562,7 +623,7 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { return displayToDataConverter; } - public java.util.List getLabels() { + public List getLabels() { if (recomputeLabels) { computeLabels(); notifyListener(); @@ -570,10 +631,22 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { return labels; } + /** + * Returns true if the colormapping is logarithmically scaled from + * {@link #colorMapMin} to {@link #colorMapMax} + * + * @return + */ public boolean isLogarithmic() { return logarithmic; } + /** + * Set to true if the colormapping should logarithmically scaled from + * {@link #colorMapMin} to {@link #colorMapMax} + * + * @param logarithmic + */ public void setLogarithmic(boolean logarithmic) { recomputeLabels = recomputeLabels | this.logarithmic != logarithmic; this.logarithmic = logarithmic; @@ -581,83 +654,162 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { } /** - * @return the dataToImageConverter + * @deprecated Use {@link #getDataToColorMapConverter()} instead + * + * @return the dataToColorMapConverter */ + @Deprecated public UnitConverter getDataToImageConverter() { - if (dataToImageConverter == null) { - dataToImageConverter = constructConverter(dataUnit, imageUnit); - if (dataToImageConverter != null) { - notifyListener(); - } - } - return dataToImageConverter; + return getDataToColorMapConverter(); } /** - * @return the imageToDisplayConverter + * Returns a {@link UnitConverter} converting {@link #dataUnit} values to + * the {@link #colorMapUnit} if compatible or null otherwise + * + * @return */ + public UnitConverter getDataToColorMapConverter() { + if (dataToColorMapConverter == null) { + dataToColorMapConverter = constructConverter(dataUnit, colorMapUnit); + if (dataToColorMapConverter != null) { + notifyListener(); + } + } + return dataToColorMapConverter; + } + + /** + * @deprecated Use {@link #getColorMapToDisplayConverter()} instead + * + * @return the colorMapToDisplayConverter + */ + @Deprecated public UnitConverter getImageToDisplayConverter() { - if (imageToDisplayConverter == null) { - imageToDisplayConverter = constructConverter(imageUnit, displayUnit); - if (imageToDisplayConverter != null) { + return getColorMapToDisplayConverter(); + } + + /** + * Returns a {@link UnitConverter} converting {@link #colorMapUnit} values + * to the {@link #displayUnit} if compatible or null otherwise + * + * @return + */ + public UnitConverter getColorMapToDisplayConverter() { + if (colorMapToDisplayConverter == null) { + colorMapToDisplayConverter = constructConverter(colorMapUnit, + displayUnit); + if (colorMapToDisplayConverter != null) { notifyListener(); } } - return imageToDisplayConverter; + return colorMapToDisplayConverter; } /** - * @return the imageUnit + * @deprecated Use {@link #getColorMapUnit()} instead + * + * @return the colorMapUnit */ + @Deprecated public Unit getImageUnit() { - return imageUnit; + return getColorMapUnit(); } /** - * @param imageUnit - * the imageUnit to set + * Returns the unit colormapping will occur in + * + * @return */ - public void setImageUnit(Unit imageUnit) { - this.imageUnit = imageUnit; + public Unit getColorMapUnit() { + return colorMapUnit; + } - if (imageUnit != null && dataUnit == null) { - setDataUnit(imageUnit); + /** + * @deprecated Use {@link #setColorMapUnit(Unit)} instead + * + * @param imageUnit + * the colorMapUnit to set + */ + @Deprecated + public void setImageUnit(Unit imageUnit) { + setColorMapUnit(imageUnit); + } + + /** + * Sets the unit colormapping will occur in. {@link #colorMapMin} and + * {@link #colorMapMax} are expected to be in this unit + * + * @param colorMapUnit + */ + public void setColorMapUnit(Unit colorMapUnit) { + this.colorMapUnit = colorMapUnit; + + if (colorMapUnit != null && dataUnit == null) { + setDataUnit(colorMapUnit); } recomputeLabels = true; - imageToDataConverter = null; - dataToImageConverter = null; + colorMapToDataConverter = null; + dataToColorMapConverter = null; - imageToDisplayConverter = null; - displayToImageConverter = null; + colorMapToDisplayConverter = null; + displayToColorMapConverter = null; notifyListener(); } /** - * @return the imageToDataConverter + * @deprecated Use {@link #getColorMapToDataConverter()} instead + * + * @return the colorMapToDataConverter */ + @Deprecated public UnitConverter getImageToDataConverter() { - if (imageToDataConverter == null) { - imageToDataConverter = constructConverter(imageUnit, dataUnit); - if (imageToDataConverter != null) { - notifyListener(); - } - } - return imageToDataConverter; + return getColorMapToDataConverter(); } /** - * @return the displayToImageConverter + * Returns a {@link UnitConverter} converting {@link #colorMapUnit} values + * to the {@link #dataUnit} if compatible or null otherwise + * + * @return */ - public UnitConverter getDisplayToImageConverter() { - if (displayToImageConverter == null) { - displayToImageConverter = constructConverter(displayUnit, imageUnit); - if (displayToImageConverter != null) { + public UnitConverter getColorMapToDataConverter() { + if (colorMapToDataConverter == null) { + colorMapToDataConverter = constructConverter(colorMapUnit, dataUnit); + if (colorMapToDataConverter != null) { notifyListener(); } } - return displayToImageConverter; + return colorMapToDataConverter; + } + + /** + * @deprecated Use {@link #getDisplayToColorMapConverter()} instead + * + * @return the displayToColorMapConverter + */ + @Deprecated + public UnitConverter getDisplayToImageConverter() { + return getDisplayToColorMapConverter(); + } + + /** + * Returns a {@link UnitConverter} converting {@link #displayUnit} values to + * the {@link #colorMapUnit} if compatible or null otherwise + * + * @return + */ + public UnitConverter getDisplayToColorMapConverter() { + if (displayToColorMapConverter == null) { + displayToColorMapConverter = constructConverter(displayUnit, + colorMapUnit); + if (displayToColorMapConverter != null) { + notifyListener(); + } + } + return displayToColorMapConverter; } /** @@ -668,7 +820,7 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { this.dataMapping = dataMapping; recomputeLabels = true; if (dataMapping != null && displayUnit != null) { - setImageUnit(dataMapping.getImageUnit(displayUnit)); + setColorMapUnit(dataMapping.getImageUnit(displayUnit)); } notifyListener(); } @@ -707,12 +859,12 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { cmp.dataMax = dataMax; cmp.dataMin = dataMin; cmp.dataToDisplayConverter = dataToDisplayConverter; - cmp.dataToImageConverter = dataToImageConverter; + cmp.dataToColorMapConverter = dataToColorMapConverter; cmp.dataUnit = dataUnit; cmp.formatString = formatString; - cmp.imageToDataConverter = imageToDataConverter; - cmp.imageToDisplayConverter = imageToDisplayConverter; - cmp.imageUnit = imageUnit; + cmp.colorMapToDataConverter = colorMapToDataConverter; + cmp.colorMapToDisplayConverter = colorMapToDisplayConverter; + cmp.colorMapUnit = colorMapUnit; cmp.labels = labels; cmp.recomputeLabels = recomputeLabels; cmp.persisted = persisted.clone(); @@ -779,196 +931,19 @@ public class ColorMapParameters implements Cloneable, ISerializableObject { return mirror; } - public static void main(String[] args) { - float[] testValues = { -3.622782E-10f, -1.6778468E-8f, -3.3110254E-8f, - -3.7973948E-8f, -2.7633986E-8f, -9.904648E-9f, -7.5229956E-10f, - 7.5189455E-10f, 1.20609505E-8f, 2.9364383E-8f, 2.7346168E-8f, - 1.3699442E-10f, -2.9937E-8f, -3.6884128E-8f, -1.6217847E-8f, - 1.1931893E-8f, 2.252287E-8f, 1.3290519E-8f, -2.4843547E-9f, - -1.0386745E-8f, -6.1300884E-9f, 3.266153E-9f, 1.078073E-8f, - 1.2696603E-8f, 4.315502E-9f, -7.2422215E-9f, -1.2054819E-8f, - -9.100724E-9f, -2.2520505E-9f, 4.031535E-9f, 6.908326E-9f, - 4.5536255E-9f, 5.3565863E-10f, -6.767242E-11f, 1.7508048E-9f, - 1.2594312E-9f, -3.5915362E-9f, -6.42762E-9f, -6.295979E-9f, - -3.857202E-9f, -2.2052171E-9f, 6.51567E-10f, 3.1020404E-9f, - 3.2179108E-9f, 2.080211E-9f, 2.5326197E-10f, -2.181367E-9f, - -3.2126295E-9f, -2.2162419E-9f, -5.682299E-10f, 7.367537E-11f, - 1.7393351E-9f, 3.2000091E-9f, 2.82146E-9f, 1.9214115E-9f, - 1.2637547E-9f, 1.1449517E-9f, 9.570286E-10f, 2.4719807E-10f, - 7.4189294E-11f, -1.9902982E-10f, -1.6482227E-9f, -2.645924E-9f, - -1.4331059E-9f, -2.6336155E-10f, -1.5215194E-9f, - -1.5059594E-9f, 2.014035E-10f, 3.565288E-10f, -1.5582429E-9f, - -1.3200975E-9f, 1.2632209E-10f, 1.0882992E-9f, 1.5682087E-9f, - 4.24027E-9f, 3.1678654E-10f, -3.9073598E-9f, -3.4730894E-9f, - -9.989449E-10f, -4.0364423E-9f, -6.3506116E-9f, -2.8335263E-9f, - -3.1253768E-9f, -1.1271912E-9f, -3.0793168E-10f, 2.2091975E-9f, - 4.9031823E-9f, 1.0454194E-8f, 1.6462849E-8f, 1.339688E-8f, - 6.4451755E-9f, 3.820775E-9f, 1.7874671E-9f, -4.5423043E-9f, - -4.7599173E-9f, -3.718451E-9f, 2.086526E-10f, 4.4792867E-9f, - -5.1967337E-9f, -1.0332604E-8f }; - - ColorMapParameters colorMapParameters = new ColorMapParameters(); - float min = -2.6945168e-7f; - float max = 2.1146788e-7f; - colorMapParameters.setColorMapMin(-2.6945168e-7f); - colorMapParameters.setColorMapMax(2.1146788e-7f); - colorMapParameters.setLogarithmic(true); - DecimalFormat format = new DecimalFormat("0.###"); - int i = 0; - for (float dispValue : testValues) { - String s = format.format(dispValue); - colorMapParameters.addLabel(dispValue, s); - if (dispValue > max) { - System.out.println(colorMapParameters.labels.get(i).location - + "to high"); - } else if (dispValue < min) { - System.out.println(colorMapParameters.labels.get(i).location - + "to low"); - } else { - System.out.println(colorMapParameters.labels.get(i).location); - } - i++; - } - } - - private float getIndexByValue(float dispValue) { - UnitConverter displayToImage = getDisplayToImageConverter(); - float colorMapRange; - if (logarithmic) { - // float colorMapMin = this.colorMapMin * 1.25f; - // float colorMapMax = this.colorMapMax * 1.25f; - if (displayToImage != null) { - dispValue = (float) displayToImage.convert(dispValue); - } - float index = 0.0f; - // is this strictly negative, strictly positive or neg to pos - // scaling? - if (colorMapMin >= 0.0 && colorMapMax >= 0.0 && !isMirror()) { - // simple calculation - index = ((float) Math.log(dispValue) - (float) Math - .log(colorMapMin)) - / (float) Math.abs((float) Math.log(colorMapMax) - - (float) Math.log(colorMapMin)); - } else if (colorMapMin <= 0.0 && colorMapMax <= 0.0 && !isMirror()) { - index = ((float) (Math.log(dispValue) - (float) Math - .log(colorMapMax)) / (float) Math.abs((float) Math - .log(colorMapMin) - (float) Math.log(colorMapMax))); - } else { - // special case, neg to pos: - float cmapMin = colorMapMin; - float cmapMax = colorMapMax; - float zeroVal = (float) Math.max(cmapMax, - (float) Math.abs(cmapMin)) * 0.0001f; - ; - - if (isMirror() && (cmapMin > 0 || cmapMax < 0)) { - if (cmapMax < 0) { - cmapMax = -cmapMax; - dispValue = -dispValue; - zeroVal = -cmapMin; - } else { - zeroVal = cmapMin; - } - cmapMin = -cmapMax; - - } - float leftZero = 0; - float rightZero = 0; - float absLogZeroVal = (float) Math.abs((float) Math - .log(zeroVal)); - - rightZero = absLogZeroVal + (float) Math.log(cmapMax); - - float cmapMax2 = -1 * cmapMin; - - leftZero = absLogZeroVal + (float) Math.log(cmapMax2); - - float zeroIndex = leftZero / (leftZero + rightZero); - - // figure out index for texture val - float absTextureColor = (float) Math.abs(dispValue); - if (dispValue == 0) { - index = zeroIndex; - } else if (absTextureColor <= zeroVal) { - index = (float) zeroIndex; - } else if (dispValue > 0.0) { - // positive texture color value, find index from 0 to - // cmapMax: - float logTexColor = absLogZeroVal - + (float) Math.log(dispValue); - - float texIndex = logTexColor / rightZero; - index = (float) (zeroIndex + ((1.0 - zeroIndex) * texIndex)); - } else { - // negative texture color value, find index from 0 to - // cmapMax: - float logTexColor = absLogZeroVal - + (float) Math.log(absTextureColor); - - float texIndex = logTexColor / leftZero; - index = (zeroIndex - (zeroIndex * texIndex)); - } - } - - return index; - } else { - colorMapRange = colorMapMax - colorMapMin; - - if (colorMapRange != 0.0) { - double pixelValue; - if (displayToImage != null) { - pixelValue = displayToImage.convert(dispValue); - } else { - pixelValue = dispValue; - } - float location; - if (logarithmic) { - location = (float) ((Math.log(pixelValue) - Math - .log(colorMapMin)) / colorMapRange); - } else { - - location = ((float) pixelValue - colorMapMin) - / colorMapRange; - } - return location; - } else { - return 0.0f; - } - } - } - /** * Get the Color object of the value * * @param value + * value to get Color for in {@link #displayUnit} * @return */ public Color getColorByValue(float value) { - float index = getIndexByValue(value); - if (index < 0.0f) { - index = 0.0f; - } else if (index > 1.0f) { - index = 1.0f; - } - if (isInterpolate()) { - index = 0.5f; - index = (index * (colorMap.getSize() - 1)); - int lowIndex = (int) Math.floor(index); - int highIndex = (int) Math.ceil(index); - float lowWeight = highIndex - index; - float highWeight = 1.0f - lowWeight; - Color low = colorMap.getColors().get(lowIndex); - Color high = colorMap.getColors().get(highIndex); - float r = lowWeight * low.getRed() + highWeight * high.getRed(); - float g = lowWeight * low.getGreen() + highWeight * high.getGreen(); - float b = lowWeight * low.getBlue() + highWeight * high.getBlue(); - float a = lowWeight * low.getAlpha() + highWeight * high.getAlpha(); - return new Color(r, g, b, a); - } else { - return colorMap.getColors().get( - (int) (index * (colorMap.getSize() - 1))); - + UnitConverter displayToColorMap = getDisplayToColorMapConverter(); + if (displayToColorMap != null) { + value = (float) displayToColorMap.convert(value); } + return Colormapper.getColorByValue(value, this); } /** diff --git a/cave/com.raytheon.uf.viz.npp.viirs/localization/colormaps/NPP/VIIRS/CA (Low Light Vis).cmap b/edexOsgi/com.raytheon.uf.common.dataplugin.npp.viirs/utility/common_static/base/colormaps/NPP/VIIRS/CA (Low Light Vis).cmap similarity index 100% rename from cave/com.raytheon.uf.viz.npp.viirs/localization/colormaps/NPP/VIIRS/CA (Low Light Vis).cmap rename to edexOsgi/com.raytheon.uf.common.dataplugin.npp.viirs/utility/common_static/base/colormaps/NPP/VIIRS/CA (Low Light Vis).cmap diff --git a/cave/com.raytheon.uf.viz.npp.viirs/localization/colormaps/NPP/VIIRS/IR BrightTemps.cmap b/edexOsgi/com.raytheon.uf.common.dataplugin.npp.viirs/utility/common_static/base/colormaps/NPP/VIIRS/IR BrightTemps.cmap similarity index 100% rename from cave/com.raytheon.uf.viz.npp.viirs/localization/colormaps/NPP/VIIRS/IR BrightTemps.cmap rename to edexOsgi/com.raytheon.uf.common.dataplugin.npp.viirs/utility/common_static/base/colormaps/NPP/VIIRS/IR BrightTemps.cmap diff --git a/cave/com.raytheon.uf.viz.npp.viirs/localization/colormaps/NPP/VIIRS/IR Default.cmap b/edexOsgi/com.raytheon.uf.common.dataplugin.npp.viirs/utility/common_static/base/colormaps/NPP/VIIRS/IR Default.cmap similarity index 100% rename from cave/com.raytheon.uf.viz.npp.viirs/localization/colormaps/NPP/VIIRS/IR Default.cmap rename to edexOsgi/com.raytheon.uf.common.dataplugin.npp.viirs/utility/common_static/base/colormaps/NPP/VIIRS/IR Default.cmap diff --git a/cave/com.raytheon.uf.viz.npp.viirs/localization/colormaps/NPP/VIIRS/ZA (Vis Default).cmap b/edexOsgi/com.raytheon.uf.common.dataplugin.npp.viirs/utility/common_static/base/colormaps/NPP/VIIRS/ZA (Vis Default).cmap similarity index 100% rename from cave/com.raytheon.uf.viz.npp.viirs/localization/colormaps/NPP/VIIRS/ZA (Vis Default).cmap rename to edexOsgi/com.raytheon.uf.common.dataplugin.npp.viirs/utility/common_static/base/colormaps/NPP/VIIRS/ZA (Vis Default).cmap diff --git a/edexOsgi/com.raytheon.uf.common.localization/src/com/raytheon/uf/common/localization/FileLocker.java b/edexOsgi/com.raytheon.uf.common.localization/src/com/raytheon/uf/common/localization/FileLocker.java index f9b7194e6c..51563c383e 100644 --- a/edexOsgi/com.raytheon.uf.common.localization/src/com/raytheon/uf/common/localization/FileLocker.java +++ b/edexOsgi/com.raytheon.uf.common.localization/src/com/raytheon/uf/common/localization/FileLocker.java @@ -378,7 +378,7 @@ public class FileLocker { // locking, can't do any locking if (parentDir.canWrite() == false) { UFStatus.getHandler() - .handle(Priority.PROBLEM, + .handle(Priority.DEBUG, "Cannot write to directory: " + parentDir.getAbsolutePath()); return false; diff --git a/edexOsgi/com.raytheon.uf.common.topo/utility/common_static/base/styleRules/topoImageryStyleRules.xml b/edexOsgi/com.raytheon.uf.common.topo/utility/common_static/base/styleRules/topoImageryStyleRules.xml index 05507c29fb..bb6cd39900 100644 --- a/edexOsgi/com.raytheon.uf.common.topo/utility/common_static/base/styleRules/topoImageryStyleRules.xml +++ b/edexOsgi/com.raytheon.uf.common.topo/utility/common_static/base/styleRules/topoImageryStyleRules.xml @@ -27,7 +27,7 @@ kft - -0.0062 + -0.062 16.404 topo