Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /*
  2. * encantar.js
  3. * GPU-accelerated Augmented Reality for the web
  4. * Copyright (C) 2022-2024 Alexandre Martins <alemartf(at)gmail.com>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published
  8. * by the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. *
  19. * resolution.ts
  20. * Resolution utilities
  21. */
  22. import Speedy from 'speedy-vision';
  23. import { SpeedySize } from 'speedy-vision/types/core/speedy-size';
  24. import { IllegalArgumentError } from './errors';
  25. type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
  26. type EvenDigit = '0' | '2' | '4' | '6' | '8';
  27. type PositiveDigit = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
  28. type OptionalDigit = Digit | '';
  29. type CustomResolution = `${PositiveDigit}${OptionalDigit}${Digit}${EvenDigit}p`;
  30. type ResolutionAlias = 'xs' | 'xs+' | 'sm' | 'sm+' | 'md' | 'md+' | 'lg' | 'lg+' | 'xl' | 'xl+' | 'xxl';
  31. /** Resolution type */
  32. export type Resolution = ResolutionAlias | CustomResolution;
  33. /** A regex that identifies custom resolutions */
  34. const CUSTOM_RESOLUTION_REGEX = /^[1-9][0-9]?[0-9][02468]p$/;
  35. /** Reference heights when in landscape mode, measured in pixels, for all aliases */
  36. const ALIAS_TO_HEIGHT: { readonly [R in ResolutionAlias]: number } = {
  37. 'xs' : 120,
  38. 'xs+': 144,
  39. 'sm' : 240,
  40. 'sm+': 288,
  41. 'md' : 320,
  42. 'md+': 360,
  43. 'lg' : 480,
  44. 'lg+': 600,
  45. 'xl' : 720,
  46. 'xl+': 900,
  47. 'xxl': 1080,
  48. };
  49. /**
  50. * Convert a resolution type to a (width, height) pair
  51. * @param resolution resolution type
  52. * @param aspectRatio desired width / height ratio
  53. * @returns size in pixels
  54. */
  55. export function computeResolution(resolution: Resolution, aspectRatio: number): SpeedySize
  56. {
  57. const referenceHeight = parseHeight(resolution);
  58. let width = 0, height = 0;
  59. if(Number.isNaN(referenceHeight))
  60. throw new IllegalArgumentError('Invalid resolution: ' + resolution);
  61. else if(aspectRatio <= 0)
  62. throw new IllegalArgumentError('Invalid aspect ratio: ' + aspectRatio);
  63. if(aspectRatio >= 1) {
  64. // landscape
  65. height = referenceHeight;
  66. width = Math.floor(height * aspectRatio);
  67. width += width % 2;
  68. }
  69. else {
  70. // portrait
  71. width = referenceHeight;
  72. height = Math.floor(width / aspectRatio);
  73. height += height % 2;
  74. }
  75. return Speedy.Size(width, height);
  76. }
  77. /**
  78. * Get the height in pixels of a resolution
  79. * @param resolution resolution type
  80. * @returns the height in pixels, or NaN on error
  81. */
  82. function parseHeight(resolution: Resolution): number
  83. {
  84. if(ALIAS_TO_HEIGHT.hasOwnProperty(resolution))
  85. return ALIAS_TO_HEIGHT[resolution as ResolutionAlias];
  86. if(CUSTOM_RESOLUTION_REGEX.test(resolution))
  87. return parseInt(resolution);
  88. return Number.NaN;
  89. }