From 4b8c86b9a32c4928845f14ac361ad31be3e65705 Mon Sep 17 00:00:00 2001 From: Daniel Haehn Date: Fri, 28 Feb 2014 15:16:47 -0500 Subject: [PATCH 01/17] The labelmap textures seem to be damaged some how (1pixel difference in size when using fancy reslicing). --- io/interactor.js | 32 +++++----- io/parser.js | 15 +++-- objects/labelmap.js | 8 +++ objects/volume.js | 2 +- visualization/renderer3D.js | 88 ++++++++++++++++++++++++- visualization/shaders.js | 124 +++++++++++++++++++++++++++++++++++- 6 files changed, 245 insertions(+), 24 deletions(-) diff --git a/io/interactor.js b/io/interactor.js index 96c110a40..d0318092b 100644 --- a/io/interactor.js +++ b/io/interactor.js @@ -363,17 +363,17 @@ X.interactor.prototype.init = function() { this._element.oncontextmenu = null; } - if (this._config['KEYBOARD_ENABLED']) { + // if (this._config['KEYBOARD_ENABLED']) { - // the google closure way did not work, so let's do it this way.. - window.onkeydown = this.onKey_.bind(this); + // // the google closure way did not work, so let's do it this way.. + // window.onkeydown = this.onKey_.bind(this); - } else { + // } else { - // remove the keyboard observer - window.onkeydown = null; + // // remove the keyboard observer + // window.onkeydown = null; - } + // } // touch events if (this._config['TOUCH_ENABLED']) { @@ -561,13 +561,13 @@ X.interactor.prototype.onMouseMovementOutside_ = function(event) { // reset the click flags this._mouseInside = false; - if (this._config['KEYBOARD_ENABLED']) { + // if (this._config['KEYBOARD_ENABLED']) { - // if we observe the keyboard, remove the observer here - // this is necessary if there are more than one renderer in the document - window.onkeydown = null; + // // if we observe the keyboard, remove the observer here + // // this is necessary if there are more than one renderer in the document + // window.onkeydown = null; - } + // } this._leftButtonDown = false; this._middleButtonDown = false; @@ -940,13 +940,13 @@ X.interactor.prototype.onMouseMovementInside_ = function(event) { this._mouseInside = true; - if (this._config['KEYBOARD_ENABLED'] && window.onkeydown == null) { + // if (this._config['KEYBOARD_ENABLED'] && window.onkeydown == null) { - // we re-gained the focus, enable the keyboard observer again! - window.onkeydown = this.onKey_.bind(this); + // // we re-gained the focus, enable the keyboard observer again! + // window.onkeydown = this.onKey_.bind(this); - } + // } // prevent any other actions by the browser (f.e. scrolling, selection..) event.preventDefault(); diff --git a/io/parser.js b/io/parser.js index 3dbce8e22..39ca30e9f 100644 --- a/io/parser.js +++ b/io/parser.js @@ -811,7 +811,7 @@ X.parser.reslice2 = function(_sliceOrigin, _sliceXYSpacing, _sliceNormal, _color goog.vec.Mat4.multMat(_XYToRAS,_xyCenter, _RASCenter); var _wmin = Math.floor(_xyBBox[0]); - var _wmax = Math.ceil(_xyBBox[1]); + var _wmax = Math.ceil(_xyBBox[1]) + 1; // if the slice only has to intersections with the volume BBox // (can happens if the slice is right on the edge of the volume) @@ -824,7 +824,7 @@ X.parser.reslice2 = function(_sliceOrigin, _sliceXYSpacing, _sliceNormal, _color var _swidth = _wmax - _wmin; var _hmin = Math.floor(_xyBBox[2]); - var _hmax = Math.ceil(_xyBBox[3]); + var _hmax = Math.ceil(_xyBBox[3]) + 1; var _sheight = _hmax - _hmin; var _resX = _sliceXYSpacing[0]; @@ -910,8 +910,15 @@ X.parser.reslice2 = function(_sliceOrigin, _sliceXYSpacing, _sliceNormal, _color pixelValue_b = 255 * lookupValue[3]; pixelValue_a = 255 * lookupValue[4]; - } - else { + } else if(object._32bit) { + + // 32 bit textures + pixelValue_r = _IJKVolume[_k][_j][_i]; + pixelValue_g = _IJKVolume[_k][_j][_i+1]; + pixelValue_b = _IJKVolume[_k][_j][_i+2]; + pixelValue_a = _IJKVolume[_k][_j][_i+3]; + + } else { pixelValue_r = pixelValue_g = pixelValue_b = 255 * (pixval / object._max); pixelValue_a = 255; diff --git a/objects/labelmap.js b/objects/labelmap.js index c1cec8fe4..2bd58a487 100644 --- a/objects/labelmap.js +++ b/objects/labelmap.js @@ -75,6 +75,14 @@ X.labelmap = function(volume) { */ this._showOnlyColor = new Float32Array([-255, -255, -255, -255]); + this._32bit = false; + + this._32bit_show_list = null; + + this._gl_color_table = null; + + this._gl_merge_table = null; + }; // inherit from X.volume goog.inherits(X.labelmap, X.volume); diff --git a/objects/volume.js b/objects/volume.js index f05f6438d..4bb7370a3 100644 --- a/objects/volume.js +++ b/objects/volume.js @@ -460,7 +460,7 @@ X.volume.prototype.slicing_ = function() { //attach labelmap if(this.hasLabelMap){ - var _sliceLabel = X.parser.reslice2(_sliceOrigin, this._childrenInfo[xyz]._sliceXYSpacing, this._childrenInfo[xyz]._sliceNormal, this._childrenInfo[xyz]._color, this._BBox, this._labelmap._IJKVolume, this._labelmap, this._labelmap.hasLabelMap, this._labelmap._colortable._map); + var _sliceLabel = X.parser.reslice2(_sliceOrigin, this._childrenInfo[xyz]._sliceXYSpacing, this._childrenInfo[xyz]._sliceNormal, this._childrenInfo[xyz]._color, this._BBox, this._labelmap._IJKVolume, this._labelmap, this._labelmap.hasLabelMap, null); this._labelmap._children[xyz]._children[parseInt(currentIndex, 10)] = _sliceLabel; // add it to create the texture this._labelmap._children[xyz].modified(true); diff --git a/visualization/renderer3D.js b/visualization/renderer3D.js index 54f0a2adb..3d0641b03 100755 --- a/visualization/renderer3D.js +++ b/visualization/renderer3D.js @@ -567,7 +567,6 @@ X.renderer3D.prototype.update_ = function(object) { // different renderer) and does not need additional file loading but just the // gl texture setup if (goog.isDefAndNotNull(labelmap) && labelmap._dirty) { - // run the update_ function on the labelmap object without jumping out this.update_(labelmap); @@ -1444,6 +1443,60 @@ X.renderer3D.prototype.pick = function(x, y) { }; +X.renderer3D.prototype.updateFromDojo = function(colormap, colormaplength, mergetablekeys, mergetablevalues, mergetablelength) { + + var gl = this._context; + + + var merge_table_keys = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, merge_table_keys); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, mergetablelength, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, mergetablekeys); + + // clamp to edge + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + + gl.bindTexture(gl.TEXTURE_2D, null); + + var merge_table_values = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, merge_table_values); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, mergetablelength, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, mergetablevalues); + + // clamp to edge + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + + gl.bindTexture(gl.TEXTURE_2D, null); + + + // create colormap texture buffer + var colormap_texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, colormap_texture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, colormaplength, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, colormap); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + + gl.bindTexture(gl.TEXTURE_2D, null); + + + // + this._merge_table_keys = merge_table_keys; + this._merge_table_values = merge_table_values; + this._colormap_texture = colormap_texture; + this._colormap_length = colormaplength; + +}; + /** * @inheritDoc @@ -1585,6 +1638,13 @@ X.renderer3D.prototype.render_ = function(picking, invoked) { var uObjectTransform = uLocations.get(X.shaders.uniforms.OBJECTTRANSFORM); var uPointSize = uLocations.get(X.shaders.uniforms.POINTSIZE); + var uColorMapSampler = uLocations.get(X.shaders.uniforms.COLORMAPSAMPLER); + var uMaxColors = uLocations.get(X.shaders.uniforms.MAXCOLORS); + var uMergeTableKeySampler = uLocations.get(X.shaders.uniforms.MERGETABLEKEYSAMPLER); + var uMergeTableValueSampler = uLocations.get(X.shaders.uniforms.MERGETABLEVALUESAMPLER); + var uMergeTableLength = uLocations.get(X.shaders.uniforms.MERGETABLELENGTH); + var uUse32bit = uLocations.get(X.shaders.uniforms.USE32BIT); + // // loop through all objects and (re-)draw them @@ -1878,6 +1938,28 @@ X.renderer3D.prototype.render_ = function(picking, invoked) { // propagate the labelmap show only color this._context.uniform4fv(uLabelMapColor, labelmap._showOnlyColor); + if (labelmap._32bit) { + // 32 bit labelmap + this._context.uniform1i(uUse32bit, 1); + + var gl = this._context; + gl.activeTexture(gl.TEXTURE2); + gl.bindTexture(gl.TEXTURE_2D, this._colormap_texture); + gl.uniform1i(uColorMapSampler, 2); + + gl.uniform1f(uMaxColors, this._colormap_length); + + gl.activeTexture(gl.TEXTURE3); + gl.bindTexture(gl.TEXTURE_2D, this._merge_table_keys); + gl.uniform1i(uMergeTableKeySampler, 3); + + gl.activeTexture(gl.TEXTURE4); + gl.bindTexture(gl.TEXTURE_2D, this._merge_table_values); + gl.uniform1i(uMergeTableValueSampler, 4); + + gl.uniform1i(uMergeTableLength, this._merge_table_length); + } + } } @@ -2417,3 +2499,7 @@ goog.exportSymbol('X.renderer3D.prototype.resetViewAndRender', X.renderer3D.prototype.resetViewAndRender); goog.exportSymbol('X.renderer3D.prototype.pick', X.renderer3D.prototype.pick); goog.exportSymbol('X.renderer3D.prototype.pick3d', X.renderer3D.prototype.pick3d); + + +goog.exportSymbol('X.renderer3D.prototype.updateFromDojo', + X.renderer3D.prototype.updateFromDojo); \ No newline at end of file diff --git a/visualization/shaders.js b/visualization/shaders.js index bfc5d39af..67056d2f5 100644 --- a/visualization/shaders.js +++ b/visualization/shaders.js @@ -189,6 +189,15 @@ X.shaders = function() { t2 += 'uniform vec3 volumeScalarMaxColor;\n'; t2 += 'uniform float volumeWindowLow;\n'; t2 += 'uniform float volumeWindowHigh;\n'; + t2 += '\n'; + t2 += 'uniform bool uUse32bit;\n'; + t2 += 'uniform sampler2D uColorMapSampler;\n'; + t2 += 'uniform sampler2D uMergeTableKeySampler;\n'; + t2 += 'uniform sampler2D uMergeTableValueSampler;\n'; + t2 += 'uniform int uMergeTableLength;\n'; + t2 += 'uniform float uMaxColors;\n'; + t2 += '\n'; + t2 += 'const int MAX = 10000;\n'; t2 += '\n'; t2 += 'varying float fDiscardNow;\n'; t2 += 'varying vec4 fVertexPosition;\n'; @@ -197,6 +206,100 @@ X.shaders = function() { t2 += 'varying vec3 fVertexNormal;\n'; t2 += 'varying vec3 fTransformedVertexNormal;\n'; t2 += '\n'; + t2 += ' //\n'; + t2 += ' // 32 BIT <-> 8 BIT CONVERSIONS\n'; + t2 += ' //\n'; + t2 += ' // convert rgba to a 32 bit value\n'; + t2 += ' float unpack (vec4 value) {\n'; + t2 += ' // note: little endian\n'; + t2 += ' const vec4 bitShifts = vec4( (256.0 * 256.0 * 256.0),\n'; + t2 += ' (256.0 * 256.0),\n'; + t2 += ' 256.0,\n'; + t2 += ' 1);\n'; + t2 += ' return dot(value.abgr , bitShifts);\n'; + t2 += ' }\n'; + t2 += '\n'; + t2 += ' // convert 32 bit int to rgba\n'; + t2 += ' ivec4 pack (int value) {\n'; + t2 += '\n'; + t2 += ' ivec4 o = ivec4(0., 0., 0., 0.);\n'; + t2 += '\n'; + t2 += ' o.w = (value / (256*256*256));\n'; + t2 += ' o.z = ((value-o.w) / (256*256));\n'; + t2 += ' o.y = ((value-o.w-o.z) / (256));\n'; + t2 += ' o.x = (value-o.y*256-o.z*256*256-o.w*256*256*256);\n'; + t2 += '\n'; + t2 += ' return o;\n'; + t2 += '\n'; + t2 += ' }\n'; + t2 += '\n'; + t2 += ' //\n'; + t2 += ' // FLOAT COMPARE FUNCTIONS WITH DELTA\n'; + t2 += ' //\n'; + t2 += ' bool equals(float id1, float id2) {\n'; + t2 += ' return (abs(id1-id2) <= 0.1);\n'; + t2 += ' }\n'; + t2 += '\n'; + t2 += ' bool larger(float id1, float id2) {\n'; + t2 += '\n'; + t2 += ' if (equals(id1, id2)) return false;\n'; + t2 += '\n'; + t2 += ' return id1 > id2;\n'; + t2 += ' }\n'; + t2 += '\n'; + t2 += ' //\n'; + t2 += ' // ID LOOKUPS\n'; + t2 += ' //\n'; + t2 += ' float lookup_id_(float id) {\n'; + t2 += '\n'; + t2 += ' for (int m=0; m Date: Sat, 1 Mar 2014 16:00:41 -0500 Subject: [PATCH 02/17] Use faster, non-fancy reslicing. --- io/parser.js | 233 ++++++++++++++++++++++++++++++++++----- io/parserRAW.js | 6 +- visualization/shaders.js | 2 +- 3 files changed, 212 insertions(+), 29 deletions(-) diff --git a/io/parser.js b/io/parser.js index 39ca30e9f..aa4b729f2 100644 --- a/io/parser.js +++ b/io/parser.js @@ -502,6 +502,53 @@ X.parser.createIJKVolume = function(_data, _dims, _max){ return [_image, _imageN]; }; +X.parser.createIJKVolume32 = function(_data, _dims, _max){ + + // initiate variables + // allocate images + var _image = new Array(_dims[2]); + var _imageN = new Array(_dims[2]); + var _nb_pix_per_slice = _dims[1] * _dims[0]; + var _pix_value = 0; + var _i = 0; + var _j = 0; + var _k = 0; + var _data_pointer = 0; + + for (_k = 0; _k < _dims[2]; _k++) { + + // get current slice + var _current_k = _data.subarray(_k * (_nb_pix_per_slice), (_k + 1) + * _nb_pix_per_slice); + // initiate data pointer + _data_pointer = 0; + + // allocate images + _imageN[_k] = new Array(_dims[1]); + _image[_k] = new Array(_dims[1]); + + for (_j = 0; _j < _dims[1]; _j++) { + + // allocate images + _imageN[_k][_j] = new Array(_dims[0]);//_data.constructor(_dims[0]); + _image[_k][_j] = new Array(_dims[0]);//_data.constructor(_dims[0]); + for (_i = 0; _i < _dims[0]; _i++) { + + _pix_value1 = _current_k[_data_pointer++]; + _pix_value2 = _current_k[_data_pointer++]; + _pix_value3 = _current_k[_data_pointer++]; + _pix_value4 = _current_k[_data_pointer++]; + + // _imageN[_k][_j][_i] = 255 * (_pix_value / _max); + _image[_k][_j][_i] = [_pix_value1, _pix_value2, _pix_value3, _pix_value4]; + + } + } + } + + return [_image, _imageN]; +}; + /** * Compute intersection between line and a bounding box * @@ -811,7 +858,7 @@ X.parser.reslice2 = function(_sliceOrigin, _sliceXYSpacing, _sliceNormal, _color goog.vec.Mat4.multMat(_XYToRAS,_xyCenter, _RASCenter); var _wmin = Math.floor(_xyBBox[0]); - var _wmax = Math.ceil(_xyBBox[1]) + 1; + var _wmax = Math.ceil(_xyBBox[1]); // if the slice only has to intersections with the volume BBox // (can happens if the slice is right on the edge of the volume) @@ -824,17 +871,17 @@ X.parser.reslice2 = function(_sliceOrigin, _sliceXYSpacing, _sliceNormal, _color var _swidth = _wmax - _wmin; var _hmin = Math.floor(_xyBBox[2]); - var _hmax = Math.ceil(_xyBBox[3]) + 1; + var _hmax = Math.ceil(_xyBBox[3]); var _sheight = _hmax - _hmin; var _resX = _sliceXYSpacing[0]; var _resY = _sliceXYSpacing[1]; - var _epsilon = 0.0000001; + var _epsilon = 0.000;//0001; // How many pixels are we expecting the raw data - var _cswidth = Math.ceil(_swidth/_resX); - var _csheight = Math.ceil(_sheight/_resY); + var _cswidth = Math.ceil(_swidth/_resX)+1; + var _csheight = Math.ceil(_sheight/_resY)+1; var _csize = _cswidth*_csheight; var textureSize = 4 * _csize; @@ -913,10 +960,10 @@ X.parser.reslice2 = function(_sliceOrigin, _sliceXYSpacing, _sliceNormal, _color } else if(object._32bit) { // 32 bit textures - pixelValue_r = _IJKVolume[_k][_j][_i]; - pixelValue_g = _IJKVolume[_k][_j][_i+1]; - pixelValue_b = _IJKVolume[_k][_j][_i+2]; - pixelValue_a = _IJKVolume[_k][_j][_i+3]; + pixelValue_r = pixval[0]; + pixelValue_g = pixval[1]; + pixelValue_b = pixval[2]; + pixelValue_a = pixval[3]; } else { @@ -1125,7 +1172,7 @@ X.parser.prototype.updateSliceInfo = function(_index, _sliceOrigin, _sliceNormal * object The X.volume to fill. * @return {!Array} The volume data as a 3D Array. */ -X.parser.prototype.reslice = function(object) { +X.parser.prototype.reslice_old = function(object) { // ------------------------------------------ // CREATE IJK VOLUMES @@ -1133,13 +1180,16 @@ X.parser.prototype.reslice = function(object) { // Step 1: create 2 IJK volumes // 1 full res, 1 normalized [0-255] - - var _IJKVolumes = X.parser.createIJKVolume(object._data, object._dimensions, object._max); + // if (object._32bit) { + // var _IJKVolumes = X.parser.createIJKVolume32(object._data, object._dimensions, object._max); + // } else { + // var _IJKVolumes = X.parser.createIJKVolume(object._data, object._dimensions, object._max); + // real volume - object._IJKVolume = _IJKVolumes[0]; - // normalized volume - object._IJKVolumeN = _IJKVolumes[1]; - X.TIMER(this._classname + '.reslice'); + // object._IJKVolume = _IJKVolumes[0]; + // // normalized volume + // object._IJKVolumeN = _IJKVolumes[1]; + X.TIMER(this._classname + '.reslice_old'); // ------------------------------------------ // SETUP LABEL MAPS AND COLOR TABLES @@ -1203,16 +1253,16 @@ X.parser.prototype.reslice = function(object) { _sliceOrigin[1] = object._childrenInfo[0]._solutionsLine[0][0][1] + object._childrenInfo[0]._sliceDirection[1]*Math.floor(object._childrenInfo[0]._nb/2); _sliceOrigin[2] = object._childrenInfo[0]._solutionsLine[0][0][2] + object._childrenInfo[0]._sliceDirection[2]*Math.floor(object._childrenInfo[0]._nb/2); - var _slice = X.parser.reslice2(_sliceOrigin, object._childrenInfo[0]._sliceXYSpacing, object._childrenInfo[0]._sliceNormal, object._childrenInfo[0]._color, object._BBox, object._IJKVolume, object, object.hasLabelMap, object._colorTable); + //var _slice = X.parser.reslice2(_sliceOrigin, object._childrenInfo[0]._sliceXYSpacing, object._childrenInfo[0]._sliceNormal, object._childrenInfo[0]._color, object._BBox, object._IJKVolume, object, object.hasLabelMap, object._colorTable); if (object.hasLabelMap) { // if this object has a labelmap, // we have it loaded at this point (for sure) // ..so we can attach it as the second texture to this slice - _slice._labelmap = object._labelmap._children[0]._children[Math.floor(object._childrenInfo[0]._nb/2)]._texture; + //_slice._labelmap = object._labelmap._children[0]._children[Math.floor(object._childrenInfo[0]._nb/2)]._texture; } - object._children[0]._children[Math.floor(object._childrenInfo[0]._nb/2)] = _slice; + //object._children[0]._children[Math.floor(object._childrenInfo[0]._nb/2)] = _slice; object._indexX = Math.floor(object._childrenInfo[0]._nb/2); object._indexXold = Math.floor(object._childrenInfo[0]._nb/2); @@ -1250,16 +1300,16 @@ X.parser.prototype.reslice = function(object) { _sliceOrigin[1] = object._childrenInfo[1]._solutionsLine[0][0][1] + object._childrenInfo[1]._sliceDirection[1]*Math.floor(object._childrenInfo[1]._nb/2); _sliceOrigin[2] = object._childrenInfo[1]._solutionsLine[0][0][2] + object._childrenInfo[1]._sliceDirection[2]*Math.floor(object._childrenInfo[1]._nb/2); - _slice = X.parser.reslice2(_sliceOrigin, object._childrenInfo[1]._sliceXYSpacing, object._childrenInfo[1]._sliceNormal, object._childrenInfo[1]._color, object._BBox, object._IJKVolume, object, object.hasLabelMap, object._colorTable); + //_slice = X.parser.reslice2(_sliceOrigin, object._childrenInfo[1]._sliceXYSpacing, object._childrenInfo[1]._sliceNormal, object._childrenInfo[1]._color, object._BBox, object._IJKVolume, object, object.hasLabelMap, object._colorTable); if (object.hasLabelMap) { // if this object has a labelmap, // we have it loaded at this point (for sure) // ..so we can attach it as the second texture to this slice - _slice._labelmap = object._labelmap._children[1]._children[Math.floor(object._childrenInfo[1]._nb/2)]._texture; + //_slice._labelmap = object._labelmap._children[1]._children[Math.floor(object._childrenInfo[1]._nb/2)]._texture; } - object._children[1]._children[Math.floor(object._childrenInfo[1]._nb/2)] = _slice; + //object._children[1]._children[Math.floor(object._childrenInfo[1]._nb/2)] = _slice; object._indexY = Math.floor(object._childrenInfo[1]._nb/2); object._indexYold = Math.floor(object._childrenInfo[1]._nb/2); @@ -1296,22 +1346,151 @@ X.parser.prototype.reslice = function(object) { _sliceOrigin[1] = object._childrenInfo[2]._solutionsLine[0][0][1] + object._childrenInfo[2]._sliceDirection[1]*Math.floor(object._childrenInfo[2]._nb/2); _sliceOrigin[2] = object._childrenInfo[2]._solutionsLine[0][0][2] + object._childrenInfo[2]._sliceDirection[2]*Math.floor(object._childrenInfo[2]._nb/2); - _slice = X.parser.reslice2(_sliceOrigin, object._childrenInfo[2]._sliceXYSpacing, object._childrenInfo[2]._sliceNormal, object._childrenInfo[2]._color, object._BBox, object._IJKVolume, object, object.hasLabelMap, object._colorTable); + //_slice = X.parser.reslice2(_sliceOrigin, object._childrenInfo[2]._sliceXYSpacing, object._childrenInfo[2]._sliceNormal, object._childrenInfo[2]._color, object._BBox, object._IJKVolume, object, object.hasLabelMap, object._colorTable); if (object.hasLabelMap) { // if this object has a labelmap, // we have it loaded at this point (for sure) // ..so we can attach it as the second texture to this slice - _slice._labelmap = object._labelmap._children[2]._children[Math.floor(object._childrenInfo[2]._nb/2)]._texture; + //_slice._labelmap = object._labelmap._children[2]._children[Math.floor(object._childrenInfo[2]._nb/2)]._texture; } - object._children[2]._children[Math.floor(object._childrenInfo[2]._nb/2)] = _slice; + //object._children[2]._children[Math.floor(object._childrenInfo[2]._nb/2)] = _slice; object._indexZ = Math.floor(object._childrenInfo[2]._nb/2); object._indexZold = Math.floor(object._childrenInfo[2]._nb/2); - X.TIMERSTOP(this._classname + '.reslice'); + X.TIMERSTOP(this._classname + '.reslice_old'); - return object._IJKVolume; + //return object._IJKVolume; }; +X.parser.prototype.reslice = function(object) { + + X.TIMER(this._classname + '.reslice'); + + var data = object._data; + + var bytes_per_value = 1; + + var dim_x = object._dimensions[0]; + var dim_y = object._dimensions[1]; + var dim_z = object._dimensions[2]; + + var data_length = dim_x * dim_y * dim_z * bytes_per_value; + + var nb_pix_per_z = dim_x * dim_y * bytes_per_value; + + var slices_x = new Array(dim_x); + var slices_y = new Array(dim_y); + var slices_z = new Array(dim_z); + + // allocate slices x y z + for (var x=0; x Date: Sat, 1 Mar 2014 20:29:05 -0500 Subject: [PATCH 03/17] Still an error when parsing the labelmaps. --- io/parser.js | 71 ++++++++++++++++++++++++++++++++----------------- io/parserRAW.js | 9 +++++-- 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/io/parser.js b/io/parser.js index aa4b729f2..e4bdd0943 100644 --- a/io/parser.js +++ b/io/parser.js @@ -1371,12 +1371,16 @@ X.parser.prototype.reslice = function(object) { var data = object._data; - var bytes_per_value = 1; + var bytes_per_value = object._32bit ? 4 : 1; var dim_x = object._dimensions[0]; var dim_y = object._dimensions[1]; var dim_z = object._dimensions[2]; + var spacing_x = object._spacing[0]; + var spacing_y = object._spacing[1]; + var spacing_z = object._spacing[2]; + var data_length = dim_x * dim_y * dim_z * bytes_per_value; var nb_pix_per_z = dim_x * dim_y * bytes_per_value; @@ -1385,6 +1389,8 @@ X.parser.prototype.reslice = function(object) { var slices_y = new Array(dim_y); var slices_z = new Array(dim_z); + var labelmap = object._labelmap; + // allocate slices x y z for (var x=0; x Date: Sun, 2 Mar 2014 10:45:16 -0500 Subject: [PATCH 04/17] Take the bytecount into account properly. --- io/parser.js | 14 ++++++++++++-- lib/google-closure-library | 2 +- xtk-deps.js | 6 +++--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/io/parser.js b/io/parser.js index e4bdd0943..f953b9376 100644 --- a/io/parser.js +++ b/io/parser.js @@ -1383,7 +1383,7 @@ X.parser.prototype.reslice = function(object) { var data_length = dim_x * dim_y * dim_z * bytes_per_value; - var nb_pix_per_z = dim_x * dim_y * bytes_per_value; + var nb_pix_per_z = dim_x * dim_y; var slices_x = new Array(dim_x); var slices_y = new Array(dim_y); @@ -1399,7 +1399,7 @@ X.parser.prototype.reslice = function(object) { slices_y[y] = new Uint8Array(dim_x*dim_z*bytes_per_value); } for (var z=0; z Date: Sun, 2 Mar 2014 14:50:26 -0500 Subject: [PATCH 05/17] Attempt to change 32 bit labelmap textures to power-of-2 images to avoid interpolation. --- io/parser.js | 33 +++++++++++++++++++++------------ lib/google-closure-library | 2 +- visualization/renderer3D.js | 2 ++ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/io/parser.js b/io/parser.js index f953b9376..6af982e0f 100644 --- a/io/parser.js +++ b/io/parser.js @@ -1373,10 +1373,22 @@ X.parser.prototype.reslice = function(object) { var bytes_per_value = object._32bit ? 4 : 1; + var grayscale = (bytes_per_value == 1); + var dim_x = object._dimensions[0]; var dim_y = object._dimensions[1]; var dim_z = object._dimensions[2]; + var texture_dim_x = dim_x; + var texture_dim_y = dim_y; + var texture_dim_z = dim_z; + + if (!grayscale) { + var texture_dim_x = Math.pow(2,Math.ceil(Math.log(dim_x)/Math.log(2))); + var texture_dim_y = Math.pow(2,Math.ceil(Math.log(dim_y)/Math.log(2))); + var texture_dim_z = Math.pow(2,Math.ceil(Math.log(dim_z)/Math.log(2))); + } + var spacing_x = object._spacing[0]; var spacing_y = object._spacing[1]; var spacing_z = object._spacing[2]; @@ -1393,13 +1405,13 @@ X.parser.prototype.reslice = function(object) { // allocate slices x y z for (var x=0; x Date: Sun, 2 Mar 2014 18:05:17 -0500 Subject: [PATCH 06/17] Volume rendering of 32 bit overlays finally works. --- io/parser.js | 23 +++++++++++------------ objects/volume.js | 30 +++++++++++++++--------------- visualization/renderer3D.js | 9 +++++---- visualization/shaders.js | 10 +++++----- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/io/parser.js b/io/parser.js index 6af982e0f..d2e1bed0d 100644 --- a/io/parser.js +++ b/io/parser.js @@ -1383,11 +1383,11 @@ X.parser.prototype.reslice = function(object) { var texture_dim_y = dim_y; var texture_dim_z = dim_z; - if (!grayscale) { - var texture_dim_x = Math.pow(2,Math.ceil(Math.log(dim_x)/Math.log(2))); - var texture_dim_y = Math.pow(2,Math.ceil(Math.log(dim_y)/Math.log(2))); - var texture_dim_z = Math.pow(2,Math.ceil(Math.log(dim_z)/Math.log(2))); - } + // if (!grayscale) { + // var texture_dim_x = Math.pow(2,Math.ceil(Math.log(dim_x)/Math.log(2))); + // var texture_dim_y = Math.pow(2,Math.ceil(Math.log(dim_y)/Math.log(2))); + // var texture_dim_z = Math.pow(2,Math.ceil(Math.log(dim_z)/Math.log(2))); + // } var spacing_x = object._spacing[0]; var spacing_y = object._spacing[1]; @@ -1437,7 +1437,6 @@ X.parser.prototype.reslice = function(object) { px++; } - console.log(px, data_length); // parserRAW.parse: 946.685ms X.js:95 // parserRAW.reslice_old: 4.265ms X.js:95 @@ -1452,8 +1451,8 @@ X.parser.prototype.reslice = function(object) { var s = new X.slice(); var t = new X.texture(); - t._rawDataWidth = texture_dim_y * bytes_per_value; - t._rawDataHeight = texture_dim_z * bytes_per_value; + t._rawDataWidth = texture_dim_y; + t._rawDataHeight = texture_dim_z; t._rawData = slices_x[x]; t._grayscale = grayscale; s._texture = t; @@ -1480,8 +1479,8 @@ X.parser.prototype.reslice = function(object) { var s = new X.slice(); var t = new X.texture(); - t._rawDataWidth = texture_dim_x * bytes_per_value; - t._rawDataHeight = texture_dim_z * bytes_per_value; + t._rawDataWidth = texture_dim_x; + t._rawDataHeight = texture_dim_z; t._rawData = slices_y[y]; t._grayscale = grayscale; s._texture = t; @@ -1507,8 +1506,8 @@ X.parser.prototype.reslice = function(object) { var s = new X.slice(); var t = new X.texture(); - t._rawDataWidth = texture_dim_x * bytes_per_value; - t._rawDataHeight = texture_dim_y * bytes_per_value; + t._rawDataWidth = texture_dim_x; + t._rawDataHeight = texture_dim_y; t._rawData = slices_z[z]; t._grayscale = grayscale; s._texture = t; diff --git a/objects/volume.js b/objects/volume.js index 4bb7370a3..2c63a8e36 100644 --- a/objects/volume.js +++ b/objects/volume.js @@ -496,7 +496,7 @@ X.volume.prototype.slicing_ = function() { if(this._volumeRendering){ - _currentSlice._children[0]._visible = false; + // _currentSlice._children[0]._visible = false; if(xyz != this._volumeRenderingDirection){ _currentSlice['visible'] = false; @@ -1434,10 +1434,10 @@ X.volume.prototype.volumeRendering_ = function(direction) { this._volumeRenderingCache.push(direction); - this._computing = true; + // this._computing = true; - // call computing callback - this.onComputing_(direction); + // // call computing callback + // this.onComputing_(direction); } else { @@ -1540,7 +1540,7 @@ X.volume.prototype.volumeRendering_ = function(direction) { } - this.onComputingProgress_(0.25); + // this.onComputingProgress_(0.25); setTimeout(function() { @@ -1584,7 +1584,7 @@ X.volume.prototype.volumeRendering_ = function(direction) { } } - this.onComputingProgress_(0.50); + // this.onComputingProgress_(0.50); setTimeout(function() { @@ -1629,7 +1629,7 @@ X.volume.prototype.volumeRendering_ = function(direction) { } - this.onComputingProgress_(0.75); + // this.onComputingProgress_(0.75); setTimeout(function() { @@ -1674,29 +1674,29 @@ X.volume.prototype.volumeRendering_ = function(direction) { } - this.onComputingProgress_(1.0); + // this.onComputingProgress_(1.0); setTimeout(function() { - if (this._computing) { + // if (this._computing) { // add it to renderer! this._children[direction].modified(true); - } + // } // store the direction this._volumeRenderingDirection = direction; this._dirty = false; - if (this._computing) { - //call computing end callback - this.onComputingEnd_(direction); + // if (this._computing) { + // //call computing end callback + // this.onComputingEnd_(direction); - } + // } - this._computing = false; + // this._computing = false; }.bind(this), 10); diff --git a/visualization/renderer3D.js b/visualization/renderer3D.js index 4ee920a40..a8033276b 100755 --- a/visualization/renderer3D.js +++ b/visualization/renderer3D.js @@ -1914,11 +1914,13 @@ X.renderer3D.prototype.render_ = function(picking, invoked) { this._context.uniform1f(uObjectOpacity, parseFloat(volume._opacity)); - } else if (labelmap && labelmap._visible) { + } + + if (labelmap && labelmap._visible) { // only if we have an associated labelmap.. // grab the id of the labelmap - var labelmapTextureID = object._labelmap._id; + var labelmapTextureID = object._labelmap._texture._id; // we handle a second texture, actually the one for the labelmap this._context.uniform1i(uUseLabelMapTexture, true); @@ -1928,8 +1930,7 @@ X.renderer3D.prototype.render_ = function(picking, invoked) { // grab the texture from the internal hash map using the id as // the key - this._context.bindTexture(this._context.TEXTURE_2D, this._textures - .get(labelmapTextureID)); + this._context.bindTexture(this._context.TEXTURE_2D, this._textures.get(labelmapTextureID)); this._context.uniform1i(uTextureSampler2, 1); diff --git a/visualization/shaders.js b/visualization/shaders.js index 7a3322ba4..1a861be88 100644 --- a/visualization/shaders.js +++ b/visualization/shaders.js @@ -358,11 +358,11 @@ X.shaders = function() { t2 += ' if (volumeTexture) {\n'; t2 += ' float _volumeLowerThreshold = (volumeLowerThreshold / volumeScalarMax);\n'; t2 += ' float _volumeUpperThreshold = (volumeUpperThreshold / volumeScalarMax);\n'; - t2 += ' if (texture1.r < _volumeLowerThreshold ||\n'; - t2 += ' texture1.r > _volumeUpperThreshold ||\n'; - t2 += ' texture1.a == 0.0 ) {\n'; - t2 += ' discard;\n'; - t2 += ' };\n'; + // t2 += ' if (texture1.r < _volumeLowerThreshold ||\n'; + // t2 += ' texture1.r > _volumeUpperThreshold ||\n'; + // t2 += ' texture1.a == 0.0 ) {\n'; + // t2 += ' discard;\n'; + // t2 += ' };\n'; t2 += ' };\n'; t2 += ' gl_FragColor = textureSum;\n'; t2 += ' gl_FragColor.a = objectOpacity;\n'; From 449f85eb6be45ac87c859fb0384aa6db8e8a146a Mon Sep 17 00:00:00 2001 From: Daniel Haehn Date: Sun, 2 Mar 2014 19:07:42 -0500 Subject: [PATCH 07/17] Fix compilation (ignore the warnings for now) and also make sure the merge table length gets passed properly. --- io/parser.js | 47 ------------------------------------- objects/volume.js | 8 +++++-- visualization/renderer3D.js | 2 +- 3 files changed, 7 insertions(+), 50 deletions(-) diff --git a/io/parser.js b/io/parser.js index d2e1bed0d..fb336c838 100644 --- a/io/parser.js +++ b/io/parser.js @@ -502,53 +502,6 @@ X.parser.createIJKVolume = function(_data, _dims, _max){ return [_image, _imageN]; }; -X.parser.createIJKVolume32 = function(_data, _dims, _max){ - - // initiate variables - // allocate images - var _image = new Array(_dims[2]); - var _imageN = new Array(_dims[2]); - var _nb_pix_per_slice = _dims[1] * _dims[0]; - var _pix_value = 0; - var _i = 0; - var _j = 0; - var _k = 0; - var _data_pointer = 0; - - for (_k = 0; _k < _dims[2]; _k++) { - - // get current slice - var _current_k = _data.subarray(_k * (_nb_pix_per_slice), (_k + 1) - * _nb_pix_per_slice); - // initiate data pointer - _data_pointer = 0; - - // allocate images - _imageN[_k] = new Array(_dims[1]); - _image[_k] = new Array(_dims[1]); - - for (_j = 0; _j < _dims[1]; _j++) { - - // allocate images - _imageN[_k][_j] = new Array(_dims[0]);//_data.constructor(_dims[0]); - _image[_k][_j] = new Array(_dims[0]);//_data.constructor(_dims[0]); - for (_i = 0; _i < _dims[0]; _i++) { - - _pix_value1 = _current_k[_data_pointer++]; - _pix_value2 = _current_k[_data_pointer++]; - _pix_value3 = _current_k[_data_pointer++]; - _pix_value4 = _current_k[_data_pointer++]; - - // _imageN[_k][_j][_i] = 255 * (_pix_value / _max); - _image[_k][_j][_i] = [_pix_value1, _pix_value2, _pix_value3, _pix_value4]; - - } - } - } - - return [_image, _imageN]; -}; - /** * Compute intersection between line and a bounding box * diff --git a/objects/volume.js b/objects/volume.js index 2c63a8e36..50d98c771 100644 --- a/objects/volume.js +++ b/objects/volume.js @@ -264,6 +264,8 @@ X.volume = function(volume) { */ this._max = 0; + this._IJKVolume = null; + /** * The image pixels * @@ -1444,8 +1446,10 @@ X.volume.prototype.volumeRendering_ = function(direction) { // we do not need to reslice // hide old volume rendering slices - var _child = this._children[this._volumeRenderingDirection]; - _child['visible'] = false; + if (this._volumeRenderingDirection != -1) { + var _child = this._children[this._volumeRenderingDirection]; + _child['visible'] = false; + } // show new volume rendering slices, but don't show the borders _child = this._children[direction]; diff --git a/visualization/renderer3D.js b/visualization/renderer3D.js index a8033276b..9e04420e5 100755 --- a/visualization/renderer3D.js +++ b/visualization/renderer3D.js @@ -1444,7 +1444,6 @@ X.renderer3D.prototype.pick = function(x, y) { }; X.renderer3D.prototype.updateFromDojo = function(colormap, colormaplength, mergetablekeys, mergetablevalues, mergetablelength) { - var gl = this._context; @@ -1494,6 +1493,7 @@ X.renderer3D.prototype.updateFromDojo = function(colormap, colormaplength, merge this._merge_table_values = merge_table_values; this._colormap_texture = colormap_texture; this._colormap_length = colormaplength; + this._merge_table_length = mergetablelength; }; From 7de7c914ed19556360a62ae9b2cb98d694db75f6 Mon Sep 17 00:00:00 2001 From: Daniel Haehn Date: Sun, 2 Mar 2014 19:26:51 -0500 Subject: [PATCH 08/17] Add X.labelmap.use32bit flag. --- objects/labelmap.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/objects/labelmap.js b/objects/labelmap.js index 2bd58a487..3872dfe6f 100644 --- a/objects/labelmap.js +++ b/objects/labelmap.js @@ -105,6 +105,12 @@ X.labelmap.prototype.modified = function() { }; +X.labelmap.prototype.__defineSetter__('use32bit', function(flag) { + + this._32bit = flag; + +}); + /** * Show only the label with the given value or color (RGBA 0..1). If null is passed, From a88f7f65fe57d89f4ad5ba2156536dd797e1484a Mon Sep 17 00:00:00 2001 From: Daniel Haehn Date: Mon, 3 Mar 2014 00:24:52 -0500 Subject: [PATCH 09/17] Fix volume orientation and support a list of 3d labels to render. --- io/parser.js | 6 +++--- visualization/renderer3D.js | 29 ++++++++++++++++++++++++++++- visualization/shaders.js | 35 +++++++++++++++++++++++++++++------ 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/io/parser.js b/io/parser.js index fb336c838..c64ad884d 100644 --- a/io/parser.js +++ b/io/parser.js @@ -1412,7 +1412,7 @@ X.parser.prototype.reslice = function(object) { s._width = dim_y*spacing_y; s._height = dim_z*spacing_z; - s._center = [x*spacing_x, Math.floor(dim_y*spacing_y/2), Math.floor(dim_z*spacing_z/2)]; + s._center = [-Math.floor(dim_x*spacing_x/2) + x*spacing_x, 0, 0]; s._front = [1, 0, 0]; s._right = [0, 1, 0]; s._up = [0, 0, 1]; @@ -1440,7 +1440,7 @@ X.parser.prototype.reslice = function(object) { s._width = dim_x*spacing_x; s._height = dim_z*spacing_z; - s._center = [Math.floor(dim_x*spacing_x/2), y*spacing_y, Math.floor(dim_z*spacing_z/2)]; + s._center = [0, -Math.floor(dim_y*spacing_y/2) + y*spacing_y, 0]; s._front = [0, 1, 0]; s._right = [1, 0, 0]; s._up = [0, 0, 1]; @@ -1467,7 +1467,7 @@ X.parser.prototype.reslice = function(object) { s._width = dim_x*spacing_x; s._height = dim_y*spacing_y; - s._center = [Math.floor(dim_x*spacing_x/2), Math.floor(dim_y*spacing_y/2), z*spacing_z]; + s._center = [0, 0, -Math.floor(dim_z*spacing_z/2) + z*spacing_z]; s._front = [0, 0, 1]; s._right = [1, 0, 0]; s._up = [0, 1, 0]; diff --git a/visualization/renderer3D.js b/visualization/renderer3D.js index 9e04420e5..b61a970e2 100755 --- a/visualization/renderer3D.js +++ b/visualization/renderer3D.js @@ -1443,7 +1443,7 @@ X.renderer3D.prototype.pick = function(x, y) { }; -X.renderer3D.prototype.updateFromDojo = function(colormap, colormaplength, mergetablekeys, mergetablevalues, mergetablelength) { +X.renderer3D.prototype.updateFromDojo = function(colormap, colormaplength, mergetablekeys, mergetablevalues, mergetablelength, threeDlabels, threeDlabelslength, useThreeDlabels) { var gl = this._context; @@ -1487,6 +1487,18 @@ X.renderer3D.prototype.updateFromDojo = function(colormap, colormaplength, merge gl.bindTexture(gl.TEXTURE_2D, null); + var threeD_labels_texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, threeD_labels_texture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, threeDlabelslength, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, threeDlabels); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + + gl.bindTexture(gl.TEXTURE_2D, null); + // this._merge_table_keys = merge_table_keys; @@ -1494,6 +1506,9 @@ X.renderer3D.prototype.updateFromDojo = function(colormap, colormaplength, merge this._colormap_texture = colormap_texture; this._colormap_length = colormaplength; this._merge_table_length = mergetablelength; + this._threeD_labels_texture = threeD_labels_texture; + this._threeD_labels_length = threeDlabelslength; + this._use_threeD_labels = useThreeDlabels; }; @@ -1644,6 +1659,9 @@ X.renderer3D.prototype.render_ = function(picking, invoked) { var uMergeTableValueSampler = uLocations.get(X.shaders.uniforms.MERGETABLEVALUESAMPLER); var uMergeTableLength = uLocations.get(X.shaders.uniforms.MERGETABLELENGTH); var uUse32bit = uLocations.get(X.shaders.uniforms.USE32BIT); + var uThreeDLabels = uLocations.get(X.shaders.uniforms.THREEDLABELS); + var uThreeDLabelsLength = uLocations.get(X.shaders.uniforms.THREEDLABELSLENGTH); + var uUseThreeDLabels = uLocations.get(X.shaders.uniforms.USETHREEDLABELS); // // loop through all objects and (re-)draw them @@ -1961,6 +1979,15 @@ X.renderer3D.prototype.render_ = function(picking, invoked) { gl.uniform1i(uMergeTableValueSampler, 4); gl.uniform1i(uMergeTableLength, this._merge_table_length); + + gl.activeTexture(gl.TEXTURE5); + gl.bindTexture(gl.TEXTURE_2D, this._threeD_labels_texture); + gl.uniform1i(uThreeDLabels, 5); + + gl.uniform1i(uThreeDLabelsLength, this._threeD_labels_length); + + gl.uniform1i(uUseThreeDLabels, this._use_threeD_labels); + } } diff --git a/visualization/shaders.js b/visualization/shaders.js index 1a861be88..fb2538015 100644 --- a/visualization/shaders.js +++ b/visualization/shaders.js @@ -194,8 +194,11 @@ X.shaders = function() { t2 += 'uniform sampler2D uColorMapSampler;\n'; t2 += 'uniform sampler2D uMergeTableKeySampler;\n'; t2 += 'uniform sampler2D uMergeTableValueSampler;\n'; + t2 += 'uniform sampler2D uThreeDLabels;\n'; t2 += 'uniform int uMergeTableLength;\n'; t2 += 'uniform float uMaxColors;\n'; + t2 += 'uniform int uThreeDLabelsLength;\n'; + t2 += 'uniform bool uUseThreeDLabels;\n'; t2 += '\n'; t2 += 'const int MAX = 10000;\n'; t2 += '\n'; @@ -299,6 +302,25 @@ X.shaders = function() { t2 += '\n'; t2 += ' }\n'; t2 += '\n'; + t2 += 'bool is_3d_label(float id) {\n'; + t2 += ' for(int m=0; m Date: Mon, 3 Mar 2014 12:10:25 -0500 Subject: [PATCH 10/17] We don't need the setTimeouts to prevent flickering. --- objects/volume.js | 224 +++++++++++++++++++++++----------------------- 1 file changed, 112 insertions(+), 112 deletions(-) diff --git a/objects/volume.js b/objects/volume.js index 50d98c771..2a1d90078 100644 --- a/objects/volume.js +++ b/objects/volume.js @@ -1478,7 +1478,7 @@ X.volume.prototype.volumeRendering_ = function(direction) { // - setTimeout(function() { + // setTimeout(function() { // hide old volume rendering slices var _child = null; @@ -1503,184 +1503,184 @@ X.volume.prototype.volumeRendering_ = function(direction) { // var i; - for (i = 0; i < 1*quarters; i++) { + for (i = 0; i < _numberOfSlices; i++) { // RESLICE VOLUME IF NECESSARY! //loop through slice - if(!goog.isDefAndNotNull(_child._children[i])){ + // if(!goog.isDefAndNotNull(_child._children[i])){ - var _sliceOrigin = goog.vec.Vec3.createFloat32(); + // var _sliceOrigin = goog.vec.Vec3.createFloat32(); - _sliceOrigin[0] = this._childrenInfo[direction]._solutionsLine[0][0][0] + this._childrenInfo[direction]._sliceDirection[0]*i; - _sliceOrigin[1] = this._childrenInfo[direction]._solutionsLine[0][0][1] + this._childrenInfo[direction]._sliceDirection[1]*i; - _sliceOrigin[2] = this._childrenInfo[direction]._solutionsLine[0][0][2] + this._childrenInfo[direction]._sliceDirection[2]*i; + // _sliceOrigin[0] = this._childrenInfo[direction]._solutionsLine[0][0][0] + this._childrenInfo[direction]._sliceDirection[0]*i; + // _sliceOrigin[1] = this._childrenInfo[direction]._solutionsLine[0][0][1] + this._childrenInfo[direction]._sliceDirection[1]*i; + // _sliceOrigin[2] = this._childrenInfo[direction]._solutionsLine[0][0][2] + this._childrenInfo[direction]._sliceDirection[2]*i; - //attach labelmap - if(this.hasLabelMap){ - var _sliceLabel = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._labelmap._IJKVolume, this._labelmap, this._labelmap.hasLabelMap, this._labelmap._colortable._map); - this._labelmap._children[direction]._children[i] = _sliceLabel; - // add it to create the texture - this._labelmap._children[direction].modified(true); - } + // //attach labelmap + // if(this.hasLabelMap){ + // var _sliceLabel = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._labelmap._IJKVolume, this._labelmap, this._labelmap.hasLabelMap, this._labelmap._colortable._map); + // this._labelmap._children[direction]._children[i] = _sliceLabel; + // // add it to create the texture + // this._labelmap._children[direction].modified(true); + // } - var _slice = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._IJKVolume, this, true, null); - _slice._children[0]._visible = false; + // var _slice = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._IJKVolume, this, true, null); + // _slice._children[0]._visible = false; - if(this.hasLabelMap){ - _slice._labelmap = _slice._texture; - _slice._labelmap = this._labelmap._children[direction]._children[i]._texture; - } + // if(this.hasLabelMap){ + // _slice._labelmap = _slice._texture; + // _slice._labelmap = this._labelmap._children[direction]._children[i]._texture; + // } - _child._children[i] = _slice; + // _child._children[i] = _slice; - _child._children[i]._visible = true; + // _child._children[i]._visible = true; - } - else{ + // } + // else{ _child._children[i]._visible = true; - } + // } } // this.onComputingProgress_(0.25); - setTimeout(function() { + // setTimeout(function() { - for (; i < 2*quarters; i++) { + // for (; i < 2*quarters; i++) { // RESLICE VOLUME IF NECESSARY! //loop through slice - if(!goog.isDefAndNotNull(_child._children[i])){ + // if(!goog.isDefAndNotNull(_child._children[i])){ - var _sliceOrigin = goog.vec.Vec3.createFloat32(); + // var _sliceOrigin = goog.vec.Vec3.createFloat32(); - _sliceOrigin[0] = this._childrenInfo[direction]._solutionsLine[0][0][0] + this._childrenInfo[direction]._sliceDirection[0]*i; - _sliceOrigin[1] = this._childrenInfo[direction]._solutionsLine[0][0][1] + this._childrenInfo[direction]._sliceDirection[1]*i; - _sliceOrigin[2] = this._childrenInfo[direction]._solutionsLine[0][0][2] + this._childrenInfo[direction]._sliceDirection[2]*i; + // _sliceOrigin[0] = this._childrenInfo[direction]._solutionsLine[0][0][0] + this._childrenInfo[direction]._sliceDirection[0]*i; + // _sliceOrigin[1] = this._childrenInfo[direction]._solutionsLine[0][0][1] + this._childrenInfo[direction]._sliceDirection[1]*i; + // _sliceOrigin[2] = this._childrenInfo[direction]._solutionsLine[0][0][2] + this._childrenInfo[direction]._sliceDirection[2]*i; - //attach labelmap - if(this.hasLabelMap){ - var _sliceLabel = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._labelmap._IJKVolume, this._labelmap, this._labelmap.hasLabelMap, this._labelmap._colortable._map); - this._labelmap._children[direction]._children[i] = _sliceLabel; - // add it to create the texture - this._labelmap._children[direction].modified(true); - } + // //attach labelmap + // if(this.hasLabelMap){ + // var _sliceLabel = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._labelmap._IJKVolume, this._labelmap, this._labelmap.hasLabelMap, this._labelmap._colortable._map); + // this._labelmap._children[direction]._children[i] = _sliceLabel; + // // add it to create the texture + // this._labelmap._children[direction].modified(true); + // } - var _slice = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._IJKVolume, this, true, null); - _slice._children[0]._visible = false; + // var _slice = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._IJKVolume, this, true, null); + // _slice._children[0]._visible = false; - if(this.hasLabelMap){ - _slice._labelmap = _slice._texture; - _slice._labelmap = this._labelmap._children[direction]._children[i]._texture; - } + // if(this.hasLabelMap){ + // _slice._labelmap = _slice._texture; + // _slice._labelmap = this._labelmap._children[direction]._children[i]._texture; + // } - _child._children[i] = _slice; + // _child._children[i] = _slice; - _child._children[i]._visible = true; + // _child._children[i]._visible = true; - } - else{ + // } + // // else{ - _child._children[i]._visible = true; + // _child._children[i]._visible = true; - } - } + // // } + // } // this.onComputingProgress_(0.50); - setTimeout(function() { + // setTimeout(function() { - for (; i < 3*quarters; i++) { + // for (; i < 3*quarters; i++) { // RESLICE VOLUME IF NECESSARY! //loop through slice - if(!goog.isDefAndNotNull(_child._children[i])){ + // if(!goog.isDefAndNotNull(_child._children[i])){ - var _sliceOrigin = goog.vec.Vec3.createFloat32(); + // var _sliceOrigin = goog.vec.Vec3.createFloat32(); - _sliceOrigin[0] = this._childrenInfo[direction]._solutionsLine[0][0][0] + this._childrenInfo[direction]._sliceDirection[0]*i; - _sliceOrigin[1] = this._childrenInfo[direction]._solutionsLine[0][0][1] + this._childrenInfo[direction]._sliceDirection[1]*i; - _sliceOrigin[2] = this._childrenInfo[direction]._solutionsLine[0][0][2] + this._childrenInfo[direction]._sliceDirection[2]*i; + // _sliceOrigin[0] = this._childrenInfo[direction]._solutionsLine[0][0][0] + this._childrenInfo[direction]._sliceDirection[0]*i; + // _sliceOrigin[1] = this._childrenInfo[direction]._solutionsLine[0][0][1] + this._childrenInfo[direction]._sliceDirection[1]*i; + // _sliceOrigin[2] = this._childrenInfo[direction]._solutionsLine[0][0][2] + this._childrenInfo[direction]._sliceDirection[2]*i; - //attach labelmap - if(this.hasLabelMap){ - var _sliceLabel = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._labelmap._IJKVolume, this._labelmap, this._labelmap.hasLabelMap, this._labelmap._colortable._map); - this._labelmap._children[direction]._children[i] = _sliceLabel; - // add it to create the texture - this._labelmap._children[direction].modified(true); - } + // //attach labelmap + // if(this.hasLabelMap){ + // var _sliceLabel = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._labelmap._IJKVolume, this._labelmap, this._labelmap.hasLabelMap, this._labelmap._colortable._map); + // this._labelmap._children[direction]._children[i] = _sliceLabel; + // // add it to create the texture + // this._labelmap._children[direction].modified(true); + // } - var _slice = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._IJKVolume, this, true, null); - _slice._children[0]._visible = false; + // var _slice = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._IJKVolume, this, true, null); + // _slice._children[0]._visible = false; - if(this.hasLabelMap){ - _slice._labelmap = _slice._texture; - _slice._labelmap = this._labelmap._children[direction]._children[i]._texture; - } + // if(this.hasLabelMap){ + // _slice._labelmap = _slice._texture; + // _slice._labelmap = this._labelmap._children[direction]._children[i]._texture; + // } - _child._children[i] = _slice; + // _child._children[i] = _slice; - _child._children[i]._visible = true; + // _child._children[i]._visible = true; - } - else{ + // } + // else{ - _child._children[i]._visible = true; + // _child._children[i]._visible = true; - } + // // } - } + // } // this.onComputingProgress_(0.75); - setTimeout(function() { + // setTimeout(function() { - for (i=3*quarters; i < _numberOfSlices; i++) { + // for (i=3*quarters; i < _numberOfSlices; i++) { // RESLICE VOLUME IF NECESSARY! //loop through slice - if(!goog.isDefAndNotNull(_child._children[i])){ + // if(!goog.isDefAndNotNull(_child._children[i])){ - var _sliceOrigin = goog.vec.Vec3.createFloat32(); + // var _sliceOrigin = goog.vec.Vec3.createFloat32(); - _sliceOrigin[0] = this._childrenInfo[direction]._solutionsLine[0][0][0] + this._childrenInfo[direction]._sliceDirection[0]*i; - _sliceOrigin[1] = this._childrenInfo[direction]._solutionsLine[0][0][1] + this._childrenInfo[direction]._sliceDirection[1]*i; - _sliceOrigin[2] = this._childrenInfo[direction]._solutionsLine[0][0][2] + this._childrenInfo[direction]._sliceDirection[2]*i; + // _sliceOrigin[0] = this._childrenInfo[direction]._solutionsLine[0][0][0] + this._childrenInfo[direction]._sliceDirection[0]*i; + // _sliceOrigin[1] = this._childrenInfo[direction]._solutionsLine[0][0][1] + this._childrenInfo[direction]._sliceDirection[1]*i; + // _sliceOrigin[2] = this._childrenInfo[direction]._solutionsLine[0][0][2] + this._childrenInfo[direction]._sliceDirection[2]*i; - //attach labelmap - if(this.hasLabelMap){ - var _sliceLabel = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._labelmap._IJKVolume, this._labelmap, this._labelmap.hasLabelMap, this._labelmap._colortable._map); - this._labelmap._children[direction]._children[i] = _sliceLabel; - // add it to create the texture - this._labelmap._children[direction].modified(true); - } + // //attach labelmap + // if(this.hasLabelMap){ + // var _sliceLabel = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._labelmap._IJKVolume, this._labelmap, this._labelmap.hasLabelMap, this._labelmap._colortable._map); + // this._labelmap._children[direction]._children[i] = _sliceLabel; + // // add it to create the texture + // this._labelmap._children[direction].modified(true); + // } - var _slice = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._IJKVolume, this, true, null); - _slice._children[0]._visible = false; + // var _slice = X.parser.reslice2(_sliceOrigin, this._childrenInfo[direction]._sliceXYSpacing, this._childrenInfo[direction]._sliceNormal, this._childrenInfo[direction]._color, this._BBox, this._IJKVolume, this, true, null); + // _slice._children[0]._visible = false; - if(this.hasLabelMap){ - _slice._labelmap = _slice._texture; - _slice._labelmap = this._labelmap._children[direction]._children[i]._texture; - } + // if(this.hasLabelMap){ + // _slice._labelmap = _slice._texture; + // _slice._labelmap = this._labelmap._children[direction]._children[i]._texture; + // } - _child._children[i] = _slice; + // _child._children[i] = _slice; - _child._children[i]._visible = true; + // _child._children[i]._visible = true; - } - else{ + // } + // // else{ - _child._children[i]._visible = true; + // _child._children[i]._visible = true; - } + // // } - } + // } // this.onComputingProgress_(1.0); - setTimeout(function() { + // setTimeout(function() { // if (this._computing) { @@ -1702,15 +1702,15 @@ X.volume.prototype.volumeRendering_ = function(direction) { // this._computing = false; - }.bind(this), 10); + // }.bind(this), 10); - }.bind(this), 10); + // }.bind(this), 10); - }.bind(this), 10); + // }.bind(this), 10); - }.bind(this), 10); + // }.bind(this), 10); - }.bind(this), 10); + // }.bind(this), 10); }; From af6b312f2b0ea2511b7c30460d9408712606a20f Mon Sep 17 00:00:00 2001 From: Daniel Haehn Date: Mon, 3 Mar 2014 15:56:47 -0500 Subject: [PATCH 11/17] Try to incorporate texture thresholding when performing picking without success yet. --- visualization/shaders.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/visualization/shaders.js b/visualization/shaders.js index fb2538015..630fd846e 100644 --- a/visualization/shaders.js +++ b/visualization/shaders.js @@ -326,10 +326,7 @@ X.shaders = function() { t2 += ' if (fDiscardNow > 0.0) {\n'; t2 += ' discard;\n'; // really discard now t2 += ' }\n'; - // in picking mode, we don't want any extras but just the plain color - t2 += ' if (usePicking) {\n'; - t2 += ' gl_FragColor = vec4(fragmentColor, 1.0);\n'; - t2 += ' } else if (useTexture) {\n'; + t2 += ' if (useTexture) {\n'; t2 += ' vec4 texture1 = texture2D(textureSampler,fragmentTexturePos);\n'; t2 += ' vec4 textureSum = texture1;\n'; // perform window level @@ -384,8 +381,13 @@ X.shaders = function() { // t2 += ' discard;\n'; // t2 += ' };\n'; t2 += ' };\n'; - t2 += ' gl_FragColor = textureSum;\n'; - t2 += ' gl_FragColor.a = objectOpacity;\n'; + // in picking mode, we don't want any extras but just the plain color + t2 += ' if (usePicking) {\n'; + t2 += ' gl_FragColor = vec4(fragmentColor,1.);\n'; + t2 += ' } else {\n'; + t2 += ' gl_FragColor = textureSum;\n'; + t2 += ' gl_FragColor.a = objectOpacity;\n'; + t2 += ' }\n'; t2 += ' } else {\n'; // configure advanced lighting t2 += ' vec3 nNormal = normalize(fTransformedVertexNormal);\n'; @@ -408,10 +410,15 @@ X.shaders = function() { t2 += ' float ambient = 0.3;\n'; // .. and now setup the fragment color using these three values and the // opacity - t2 += ' gl_FragColor = vec4(fragmentColor * ambient +\n'; + // in picking mode, we don't want any extras but just the plain color + t2 += ' if (usePicking) {\n'; + t2 += ' gl_FragColor = vec4(fragmentColor,1.);\n'; + t2 += ' } else {\n'; + t2 += ' gl_FragColor = vec4(fragmentColor * ambient +\n'; t2 += ' fragmentColor * diffuse +\n'; t2 += ' vec3(0.2, 0.2, 0.2) * specular,\n'; t2 += ' objectOpacity);\n'; + t2 += ' }\n'; t2 += ' }\n'; t2 += '}\n'; this._fragmentshaderSource = t2; From bd0179ca0d22ce06f5ce9d21b004269b88620329 Mon Sep 17 00:00:00 2001 From: Daniel Haehn Date: Wed, 19 Mar 2014 15:11:01 -0400 Subject: [PATCH 12/17] Some more exports required to modify textures after segmentation adjustment. --- core/texture.js | 12 +++ objects/slice.js | 14 ++- visualization/renderer3D.js | 164 +++++++++++++++++++++++------------- 3 files changed, 132 insertions(+), 58 deletions(-) diff --git a/core/texture.js b/core/texture.js index 5f1100d34..7cf001803 100644 --- a/core/texture.js +++ b/core/texture.js @@ -104,6 +104,8 @@ X.texture = function() { * @protected */ this._grayscale = false; + + this._needs_update = false; // inject functionality inject(this, new X.loadable()); // this object is loadable from a file @@ -168,4 +170,14 @@ X.texture.prototype.__defineSetter__('grayscale', function(grayscale) { }); +X.texture.prototype.updateTexture = function(data) { + + this._rawData = data; + this._needs_update = true; + + this._dirty = true; + +}; + goog.exportSymbol('X.texture', X.texture); +goog.exportSymbol('X.texture.prototype.updateTexture', X.texture.prototype.updateTexture); diff --git a/objects/slice.js b/objects/slice.js index 40b447dc7..536eabf3b 100644 --- a/objects/slice.js +++ b/objects/slice.js @@ -120,7 +120,7 @@ X.slice = function(slice) { /** * The label map of this slice which is a second texture. * - * @type {?X.texture} + * @type {?X.slice} * @protected */ this._labelmap = null; @@ -202,6 +202,18 @@ X.slice.prototype.__defineSetter__('width', function(width) { }); +/** + * Get the label map of this slice. + * + * @return {X.slice} + */ +X.slice.prototype.__defineGetter__('labelmap', function() { + + return this._labelmap; + +}); + + /** * Setup this X.slice and create it. * diff --git a/visualization/renderer3D.js b/visualization/renderer3D.js index b61a970e2..f6d0bc906 100755 --- a/visualization/renderer3D.js +++ b/visualization/renderer3D.js @@ -750,83 +750,110 @@ X.renderer3D.prototype.update_ = function(object) { _flipY = true; } - this._context.pixelStorei(this._context.UNPACK_FLIP_Y_WEBGL, _flipY); + if (texture._needs_update) { - // setup the glTexture, at this point the image for the texture was - // already - // loaded thanks to X.loader - var glTexture = this._context.createTexture(); + var glTexture = this._textures.get(texture._id); + this._context.bindTexture(this._context.TEXTURE_2D, glTexture); - // connect the image and the glTexture - glTexture.image = texture._image; - - // - // activate the texture on the WebGL side - this._textures.set(texture._id, glTexture); - - this._context.bindTexture(this._context.TEXTURE_2D, glTexture); - if (texture._rawData) { var _texture_type = this._context.RGBA; - - if (texture._grayscale) { - - // one channel texture - _texture_type = this._context.LUMINANCE; - this._context.pixelStorei(this._context.UNPACK_ALIGNMENT, 1); - - } - // use rawData rather than loading an imagefile this._context.texImage2D(this._context.TEXTURE_2D, 0, _texture_type, texture._rawDataWidth, texture._rawDataHeight, 0, _texture_type, this._context.UNSIGNED_BYTE, texture._rawData); - } else { + texture._dirty = false; + texture._needs_update = false; - // use an imageFile for the texture - this._context.texImage2D(this._context.TEXTURE_2D, 0, - this._context.RGBA, this._context.RGBA, - this._context.UNSIGNED_BYTE, glTexture.image); + object._dirty = false; - } + this._locked = false; - this._context.texParameteri(this._context.TEXTURE_2D, - this._context.TEXTURE_WRAP_S, this._context.CLAMP_TO_EDGE); - this._context.texParameteri(this._context.TEXTURE_2D, - this._context.TEXTURE_WRAP_T, this._context.CLAMP_TO_EDGE); + // we don't need anything else + return; - // for labelmaps, we use NEAREST NEIGHBOR filtering - if (isLabelMap) { - this._context.texParameteri(this._context.TEXTURE_2D, - this._context.TEXTURE_MAG_FILTER, this._context.NEAREST); - this._context.texParameteri(this._context.TEXTURE_2D, - this._context.TEXTURE_MIN_FILTER, this._context.NEAREST); } else { + + this._context.pixelStorei(this._context.UNPACK_FLIP_Y_WEBGL, _flipY); + + // setup the glTexture, at this point the image for the texture was + // already + // loaded thanks to X.loader + var glTexture = this._context.createTexture(); + + // connect the image and the glTexture + glTexture.image = texture._image; + + // + // activate the texture on the WebGL side + this._textures.set(texture._id, glTexture); + + this._context.bindTexture(this._context.TEXTURE_2D, glTexture); + if (texture._rawData) { + + var _texture_type = this._context.RGBA; + + if (texture._grayscale) { + + // one channel texture + _texture_type = this._context.LUMINANCE; + this._context.pixelStorei(this._context.UNPACK_ALIGNMENT, 1); + + } + + // use rawData rather than loading an imagefile + this._context.texImage2D(this._context.TEXTURE_2D, 0, + _texture_type, texture._rawDataWidth, texture._rawDataHeight, + 0, _texture_type, this._context.UNSIGNED_BYTE, + texture._rawData); + + } else { + + // use an imageFile for the texture + this._context.texImage2D(this._context.TEXTURE_2D, 0, + this._context.RGBA, this._context.RGBA, + this._context.UNSIGNED_BYTE, glTexture.image); + + } + this._context.texParameteri(this._context.TEXTURE_2D, - this._context.TEXTURE_MAG_FILTER, this._context.LINEAR); + this._context.TEXTURE_WRAP_S, this._context.CLAMP_TO_EDGE); this._context.texParameteri(this._context.TEXTURE_2D, - this._context.TEXTURE_MIN_FILTER, this._context.LINEAR); - } + this._context.TEXTURE_WRAP_T, this._context.CLAMP_TO_EDGE); + + // for labelmaps, we use NEAREST NEIGHBOR filtering + if (isLabelMap) { + this._context.texParameteri(this._context.TEXTURE_2D, + this._context.TEXTURE_MAG_FILTER, this._context.NEAREST); + this._context.texParameteri(this._context.TEXTURE_2D, + this._context.TEXTURE_MIN_FILTER, this._context.NEAREST); + } else { + this._context.texParameteri(this._context.TEXTURE_2D, + this._context.TEXTURE_MAG_FILTER, this._context.LINEAR); + this._context.texParameteri(this._context.TEXTURE_2D, + this._context.TEXTURE_MIN_FILTER, this._context.LINEAR); + } - // release the texture binding to clear things - this._context.bindTexture(this._context.TEXTURE_2D, null); + // release the texture binding to clear things + this._context.bindTexture(this._context.TEXTURE_2D, null); - // create texture buffer - var glTexturePositionBuffer = this._context.createBuffer(); + // create texture buffer + var glTexturePositionBuffer = this._context.createBuffer(); - // bind and fill with colors defined above - this._context.bindBuffer(this._context.ARRAY_BUFFER, - glTexturePositionBuffer); - this._context.bufferData(this._context.ARRAY_BUFFER, new Float32Array( - textureCoordinateMap), this._context.STATIC_DRAW); + // bind and fill with colors defined above + this._context.bindBuffer(this._context.ARRAY_BUFFER, + glTexturePositionBuffer); + this._context.bufferData(this._context.ARRAY_BUFFER, new Float32Array( + textureCoordinateMap), this._context.STATIC_DRAW); - // create an X.buffer to store the texture-coordinate map - texturePositionBuffer = new X.buffer(glTexturePositionBuffer, - textureCoordinateMap.length, 2); + // create an X.buffer to store the texture-coordinate map + texturePositionBuffer = new X.buffer(glTexturePositionBuffer, + textureCoordinateMap.length, 2); - this._texturePositionBuffers.set(id, texturePositionBuffer); + this._texturePositionBuffers.set(id, texturePositionBuffer); + + } texture._dirty = false; @@ -2508,6 +2535,29 @@ X.renderer3D.prototype.pick3d = function(x, y, delta, epsilon, object) { }; + +/** + * Get the GL context. + */ +X.renderer3D.prototype.__defineGetter__('gl', function() { + + return this._context; + +}); + +X.renderer3D.prototype.__defineGetter__('textures', function() { + + return this._textures; + +}); + +X.renderer3D.prototype.getTexture = function(id) { + + return this._textures.get(id); + +}; + + // export symbols (required for advanced compilation) goog.exportSymbol('X.renderer3D', X.renderer3D); goog.exportSymbol('X.renderer3D.prototype.init', X.renderer3D.prototype.init); @@ -2529,7 +2579,7 @@ goog.exportSymbol('X.renderer3D.prototype.resetViewAndRender', X.renderer3D.prototype.resetViewAndRender); goog.exportSymbol('X.renderer3D.prototype.pick', X.renderer3D.prototype.pick); goog.exportSymbol('X.renderer3D.prototype.pick3d', X.renderer3D.prototype.pick3d); - +goog.exportSymbol('X.renderer3D.prototype.getTexture', X.renderer3D.prototype.getTexture); goog.exportSymbol('X.renderer3D.prototype.updateFromDojo', - X.renderer3D.prototype.updateFromDojo); \ No newline at end of file + X.renderer3D.prototype.updateFromDojo); From a30e208635ed44454589c2de17fcb85d6c77a707 Mon Sep 17 00:00:00 2001 From: Daniel Haehn Date: Sun, 23 Mar 2014 15:25:13 -0400 Subject: [PATCH 13/17] Add getter for the X.texture._rawData. --- core/texture.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/texture.js b/core/texture.js index 7cf001803..b42ec8553 100644 --- a/core/texture.js +++ b/core/texture.js @@ -115,6 +115,19 @@ X.texture = function() { goog.inherits(X.texture, X.base); +/** + * Get the raw data of this texture. + * + * @return {?Object} The raw data array (Uint8Array). + */ +X.texture.prototype.__defineGetter__('rawData', function() { + + return this._rawData; + +}); + + + /** * Set the raw data of this texture. * From 6ee2cbad53817d523bc676d92067469d723db68f Mon Sep 17 00:00:00 2001 From: haehn Date: Mon, 11 May 2015 16:54:21 -0400 Subject: [PATCH 14/17] Expose the X.renderer3D.onResize() function. --- visualization/renderer.js | 11 +++++++++++ visualization/renderer3D.js | 2 ++ 2 files changed, 13 insertions(+) diff --git a/visualization/renderer.js b/visualization/renderer.js index 459d830cf..ed352f064 100644 --- a/visualization/renderer.js +++ b/visualization/renderer.js @@ -401,6 +401,17 @@ X.renderer.prototype.onHover_ = function(event) { }; +/** + * Trigger viewport adjustment after resizing. + * + * @public + */ +X.renderer.prototype.onResize = function() { + + this.onResize_(); + +}; + /** * @protected diff --git a/visualization/renderer3D.js b/visualization/renderer3D.js index f6d0bc906..224f40c53 100755 --- a/visualization/renderer3D.js +++ b/visualization/renderer3D.js @@ -2571,6 +2571,8 @@ goog.exportSymbol('X.renderer3D.prototype.render', X.renderer3D.prototype.render); goog.exportSymbol('X.renderer3D.prototype.destroy', X.renderer3D.prototype.destroy); +goog.exportSymbol('X.renderer3D.prototype.onResize', + X.renderer3D.prototype.onResize); goog.exportSymbol('X.renderer3D.prototype.remove', X.renderer3D.prototype.remove); goog.exportSymbol('X.renderer3D.prototype.resetBoundingBox', From f90ffc77c740bd1301540bec9d1b059b07b92aa8 Mon Sep 17 00:00:00 2001 From: haehn Date: Tue, 12 May 2015 15:53:11 -0400 Subject: [PATCH 15/17] Add the X.volume.xySampleRate value to control the sampling in XY during reslicing. --- io/parser.js | 7 ++++++- objects/volume.js | 44 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/io/parser.js b/io/parser.js index c64ad884d..d70ba35be 100644 --- a/io/parser.js +++ b/io/parser.js @@ -1336,6 +1336,8 @@ X.parser.prototype.reslice = function(object) { var texture_dim_y = dim_y; var texture_dim_z = dim_z; + var x_y_sample_rate = object._x_y_sample_rate; + // if (!grayscale) { // var texture_dim_x = Math.pow(2,Math.ceil(Math.log(dim_x)/Math.log(2))); // var texture_dim_y = Math.pow(2,Math.ceil(Math.log(dim_y)/Math.log(2))); @@ -1425,6 +1427,7 @@ X.parser.prototype.reslice = function(object) { s._labelmap = object._labelmap._children[0]._children[x]; } + if (x % x_y_sample_rate == 0) object._children[0]._children[x] = s; } @@ -1453,7 +1456,9 @@ X.parser.prototype.reslice = function(object) { s._labelmap = object._labelmap._children[1]._children[y]; } - object._children[1]._children[y] = s; + if (y % x_y_sample_rate == 0) { + object._children[1]._children[y] = s; + } } for (var z=0; z Date: Sat, 4 Jul 2015 14:08:56 -0400 Subject: [PATCH 16/17] Add the X.volume.zSampleRate switch for reducing VR sampling in Z direction. --- io/parser.js | 16 +++++++++++++--- objects/volume.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/io/parser.js b/io/parser.js index d70ba35be..d7174311a 100644 --- a/io/parser.js +++ b/io/parser.js @@ -1313,6 +1313,12 @@ X.parser.prototype.reslice_old = function(object) { object._indexZ = Math.floor(object._childrenInfo[2]._nb/2); object._indexZold = Math.floor(object._childrenInfo[2]._nb/2); + + if (object._indexZ % 2 != 0) { + object._indexZ -= 1; + object._indexZold -= 1; + } + X.TIMERSTOP(this._classname + '.reslice_old'); //return object._IJKVolume; @@ -1337,6 +1343,7 @@ X.parser.prototype.reslice = function(object) { var texture_dim_z = dim_z; var x_y_sample_rate = object._x_y_sample_rate; + var z_sample_rate = object._z_sample_rate; // if (!grayscale) { // var texture_dim_x = Math.pow(2,Math.ceil(Math.log(dim_x)/Math.log(2))); @@ -1427,8 +1434,9 @@ X.parser.prototype.reslice = function(object) { s._labelmap = object._labelmap._children[0]._children[x]; } - if (x % x_y_sample_rate == 0) - object._children[0]._children[x] = s; + if (x % x_y_sample_rate == 0) { + object._children[0]._children[x] = s; + } } for (var y=0; y Date: Fri, 24 Jun 2016 12:56:48 -0400 Subject: [PATCH 17/17] Ignore label 0 for XTK. --- visualization/shaders.js | 1 + 1 file changed, 1 insertion(+) diff --git a/visualization/shaders.js b/visualization/shaders.js index 630fd846e..d320c440a 100644 --- a/visualization/shaders.js +++ b/visualization/shaders.js @@ -344,6 +344,7 @@ X.shaders = function() { t2 += ' vec4 texture2 = texture2D(textureSampler2,fragmentTexturePos);\n'; t2 += ' if (uUse32bit) {\n'; t2 += ' float id = lookup_id(unpack(texture2)*255.);\n'; + t2 += ' if (id == 0.) { discard;\n }'; t2 += ' float normalized_id = mod(id, uMaxColors);\n'; t2 += ' vec2 colormap_pos = vec2(normalized_id / (uMaxColors - 1.), 0.);\n'; t2 += ' vec4 color = texture2D(uColorMapSampler, colormap_pos);\n';