Viewport.js

  1. 'use strict';
  2. const WebGLContext = require('./WebGLContext');
  3. /**
  4. * Bind the viewport to the rendering context.
  5. *
  6. * @private
  7. *
  8. * @param {Viewport} viewport - The viewport object.
  9. * @param {number} x - The horizontal offset override.
  10. * @param {number} y - The vertical offset override.
  11. * @param {number} width - The width override.
  12. * @param {number} height - The height override.
  13. */
  14. function set(viewport, x, y, width, height) {
  15. const gl = viewport.gl;
  16. x = (x !== undefined) ? x : viewport.x;
  17. y = (y !== undefined) ? y : viewport.y;
  18. width = (width !== undefined) ? width : viewport.width;
  19. height = (height !== undefined) ? height : viewport.height;
  20. gl.viewport(x, y, width, height);
  21. }
  22. /**
  23. * A viewport class for managing WebGL viewports.
  24. */
  25. class Viewport {
  26. /**
  27. * Instantiates a Viewport object.
  28. *
  29. * @param {Object} spec - The viewport specification object.
  30. * @param {number} spec.width - The width of the viewport.
  31. * @param {number} spec.height - The height of the viewport.
  32. */
  33. constructor(spec = {}) {
  34. this.gl = WebGLContext.get();
  35. this.stack = [];
  36. // set size
  37. this.resize(
  38. spec.width || this.gl.canvas.width,
  39. spec.height || this.gl.canvas.height);
  40. }
  41. /**
  42. * Updates the viewports width and height. This resizes the underlying canvas element.
  43. *
  44. * @param {number} width - The width of the viewport.
  45. * @param {number} height - The height of the viewport.
  46. *
  47. * @returns {Viewport} The viewport object, for chaining.
  48. */
  49. resize(width = 0, height = 0) {
  50. if (typeof width !== 'number' || width <= 0) {
  51. throw `Provided \`width\` of \`${width}\` is invalid`;
  52. }
  53. if (typeof height !== 'number' || height <= 0) {
  54. throw `Provided \`height\` of \`${height}\` is invalid`;
  55. }
  56. this.width = width;
  57. this.height = height;
  58. this.gl.canvas.width = width;
  59. this.gl.canvas.height = height;
  60. return this;
  61. }
  62. /**
  63. * Sets the viewport dimensions and position. The underlying canvas element
  64. * is not affected.
  65. *
  66. * @param {number} x - The horizontal offset override.
  67. * @param {number} y - The vertical offset override.
  68. * @param {number} width - The width override.
  69. * @param {number} height - The height override.
  70. *
  71. * @returns {Viewport} - The viewport object, for chaining.
  72. */
  73. push(x = 0, y = 0, width = this.width, height = this.height) {
  74. if (typeof x !== 'number') {
  75. throw `Provided \`x\` of \`${x}\` is invalid`;
  76. }
  77. if (typeof y !== 'number') {
  78. throw `Provided \`y\` of \`${y}\` is invalid`;
  79. }
  80. if (typeof width !== 'number' || width <= 0) {
  81. throw `Provided \`width\` of \`${width}\` is invalid`;
  82. }
  83. if (typeof height !== 'number' || height <= 0) {
  84. throw `Provided \`height\` of \`${height}\` is invalid`;
  85. }
  86. // push onto stack
  87. this.stack.push({
  88. x: x,
  89. y: y,
  90. width: width,
  91. height: height
  92. });
  93. // set viewport
  94. set(this, x, y, width, height);
  95. return this;
  96. }
  97. /**
  98. * Pops current the viewport object and sets the viewport beneath it.
  99. *
  100. * @returns {Viewport} The viewport object, for chaining.
  101. */
  102. pop() {
  103. if (this.stack.length === 0) {
  104. throw 'Viewport stack is empty';
  105. }
  106. this.stack.pop();
  107. if (this.stack.length > 0) {
  108. const top = this.stack[this.stack.length - 1];
  109. set(this, top.x, top.y, top.width, top.height);
  110. } else {
  111. set(this);
  112. }
  113. return this;
  114. }
  115. }
  116. module.exports = Viewport;