PickFramebuffer.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import BoundingRectangle from '../Core/BoundingRectangle.js';
  2. import Color from '../Core/Color.js';
  3. import defaultValue from '../Core/defaultValue.js';
  4. import defined from '../Core/defined.js';
  5. import destroyObject from '../Core/destroyObject.js';
  6. import Framebuffer from '../Renderer/Framebuffer.js';
  7. import PassState from '../Renderer/PassState.js';
  8. import Renderbuffer from '../Renderer/Renderbuffer.js';
  9. import RenderbufferFormat from '../Renderer/RenderbufferFormat.js';
  10. import Texture from '../Renderer/Texture.js';
  11. /**
  12. * @private
  13. */
  14. function PickFramebuffer(context) {
  15. // Override per-command states
  16. var passState = new PassState(context);
  17. passState.blendingEnabled = false;
  18. passState.scissorTest = {
  19. enabled : true,
  20. rectangle : new BoundingRectangle()
  21. };
  22. passState.viewport = new BoundingRectangle();
  23. this._context = context;
  24. this._fb = undefined;
  25. this._passState = passState;
  26. this._width = 0;
  27. this._height = 0;
  28. }
  29. PickFramebuffer.prototype.begin = function(screenSpaceRectangle, viewport) {
  30. var context = this._context;
  31. var width = viewport.width;
  32. var height = viewport.height;
  33. BoundingRectangle.clone(screenSpaceRectangle, this._passState.scissorTest.rectangle);
  34. // Initially create or recreate renderbuffers and framebuffer used for picking
  35. if ((!defined(this._fb)) || (this._width !== width) || (this._height !== height)) {
  36. this._width = width;
  37. this._height = height;
  38. this._fb = this._fb && this._fb.destroy();
  39. this._fb = new Framebuffer({
  40. context : context,
  41. colorTextures : [new Texture({
  42. context : context,
  43. width : width,
  44. height : height
  45. })],
  46. depthStencilRenderbuffer : new Renderbuffer({
  47. context : context,
  48. width : width,
  49. height : height,
  50. format : RenderbufferFormat.DEPTH_STENCIL
  51. })
  52. });
  53. this._passState.framebuffer = this._fb;
  54. }
  55. this._passState.viewport.width = width;
  56. this._passState.viewport.height = height;
  57. return this._passState;
  58. };
  59. var colorScratch = new Color();
  60. PickFramebuffer.prototype.end = function(screenSpaceRectangle) {
  61. var width = defaultValue(screenSpaceRectangle.width, 1.0);
  62. var height = defaultValue(screenSpaceRectangle.height, 1.0);
  63. var context = this._context;
  64. var pixels = context.readPixels({
  65. x : screenSpaceRectangle.x,
  66. y : screenSpaceRectangle.y,
  67. width : width,
  68. height : height,
  69. framebuffer : this._fb
  70. });
  71. var max = Math.max(width, height);
  72. var length = max * max;
  73. var halfWidth = Math.floor(width * 0.5);
  74. var halfHeight = Math.floor(height * 0.5);
  75. var x = 0;
  76. var y = 0;
  77. var dx = 0;
  78. var dy = -1;
  79. // Spiral around the center pixel, this is a workaround until
  80. // we can access the depth buffer on all browsers.
  81. // The region does not have to square and the dimensions do not have to be odd, but
  82. // loop iterations would be wasted. Prefer square regions where the size is odd.
  83. for (var i = 0; i < length; ++i) {
  84. if (-halfWidth <= x && x <= halfWidth && -halfHeight <= y && y <= halfHeight) {
  85. var index = 4 * ((halfHeight - y) * width + x + halfWidth);
  86. colorScratch.red = Color.byteToFloat(pixels[index]);
  87. colorScratch.green = Color.byteToFloat(pixels[index + 1]);
  88. colorScratch.blue = Color.byteToFloat(pixels[index + 2]);
  89. colorScratch.alpha = Color.byteToFloat(pixels[index + 3]);
  90. var object = context.getObjectByPickColor(colorScratch);
  91. if (defined(object)) {
  92. return object;
  93. }
  94. }
  95. // if (top right || bottom left corners) || (top left corner) || (bottom right corner + (1, 0))
  96. // change spiral direction
  97. if (x === y || (x < 0 && -x === y) || (x > 0 && x === 1 - y)) {
  98. var temp = dx;
  99. dx = -dy;
  100. dy = temp;
  101. }
  102. x += dx;
  103. y += dy;
  104. }
  105. return undefined;
  106. };
  107. PickFramebuffer.prototype.isDestroyed = function() {
  108. return false;
  109. };
  110. PickFramebuffer.prototype.destroy = function() {
  111. this._fb = this._fb && this._fb.destroy();
  112. return destroyObject(this);
  113. };
  114. export default PickFramebuffer;