gl_image.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #include "ui/gl/gl_image.h"
  8. #include <QtGui/QOpenGLFunctions>
  9. namespace Ui::GL {
  10. namespace details {
  11. void GenerateTextures(
  12. QOpenGLFunctions &f,
  13. gsl::span<GLuint> values,
  14. GLint filter,
  15. GLint clamp) {
  16. Expects(!values.empty());
  17. f.glGenTextures(values.size(), values.data());
  18. for (const auto texture : values) {
  19. f.glBindTexture(GL_TEXTURE_2D, texture);
  20. f.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp);
  21. f.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp);
  22. f.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
  23. f.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
  24. }
  25. }
  26. void DestroyTextures(QOpenGLFunctions *f, gsl::span<GLuint> values) {
  27. Expects(!values.empty());
  28. if (f) {
  29. f->glDeleteTextures(values.size(), values.data());
  30. }
  31. ranges::fill(values, 0);
  32. }
  33. void GenerateFramebuffers(QOpenGLFunctions &f, gsl::span<GLuint> values) {
  34. Expects(!values.empty());
  35. f.glGenFramebuffers(values.size(), values.data());
  36. }
  37. void DestroyFramebuffers(QOpenGLFunctions *f, gsl::span<GLuint> values) {
  38. Expects(!values.empty());
  39. if (f) {
  40. f->glDeleteTextures(values.size(), values.data());
  41. }
  42. ranges::fill(values, 0);
  43. }
  44. } // namespace details
  45. void Image::setImage(QImage image, QSize subimage) {
  46. Expects(subimage.width() <= image.width()
  47. && subimage.height() <= image.height());
  48. _image = std::move(image);
  49. _subimage = subimage.isValid() ? subimage : _image.size();
  50. }
  51. const QImage &Image::image() const {
  52. return _image;
  53. }
  54. QImage Image::takeImage() {
  55. return _image.isNull() ? base::take(_storage) : base::take(_image);
  56. }
  57. void Image::invalidate() {
  58. _storage = base::take(_image);
  59. _subimage = QSize();
  60. }
  61. void Image::bind(QOpenGLFunctions &f) {
  62. _textures.ensureCreated(f, GL_NEAREST);
  63. if (_subimage.isEmpty()) {
  64. _textureSize = _subimage;
  65. return;
  66. }
  67. const auto cacheKey = _image.cacheKey();
  68. const auto upload = (_cacheKey != cacheKey);
  69. if (upload) {
  70. _cacheKey = cacheKey;
  71. }
  72. _textures.bind(f, 0);
  73. if (upload) {
  74. f.glPixelStorei(GL_UNPACK_ROW_LENGTH, _image.bytesPerLine() / 4);
  75. if (_textureSize.width() < _subimage.width()
  76. || _textureSize.height() < _subimage.height()) {
  77. _textureSize = _subimage;
  78. f.glTexImage2D(
  79. GL_TEXTURE_2D,
  80. 0,
  81. kFormatRGBA,
  82. _subimage.width(),
  83. _subimage.height(),
  84. 0,
  85. kFormatRGBA,
  86. GL_UNSIGNED_BYTE,
  87. _image.constBits());
  88. } else {
  89. f.glTexSubImage2D(
  90. GL_TEXTURE_2D,
  91. 0,
  92. 0,
  93. 0,
  94. _subimage.width(),
  95. _subimage.height(),
  96. kFormatRGBA,
  97. GL_UNSIGNED_BYTE,
  98. _image.constBits());
  99. }
  100. f.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  101. }
  102. }
  103. void Image::destroy(QOpenGLFunctions *f) {
  104. invalidate();
  105. _textures.destroy(f);
  106. _cacheKey = 0;
  107. _textureSize = QSize();
  108. }
  109. TexturedRect Image::texturedRect(
  110. const QRect &geometry,
  111. const QRect &texture,
  112. const QRect &clip) {
  113. Expects(!_image.isNull());
  114. const auto visible = clip.isNull()
  115. ? geometry
  116. : clip.intersected(geometry);
  117. if (visible.isEmpty()) {
  118. return TexturedRect{
  119. .geometry = Rect(visible),
  120. .texture = Rect(0., 0., 0., 0.),
  121. };
  122. }
  123. const auto xFactor = texture.width() / geometry.width();
  124. const auto yFactor = texture.height() / geometry.height();
  125. const auto usedTexture = QRect(
  126. texture.x() + (visible.x() - geometry.x()) * xFactor,
  127. texture.y() + (visible.y() - geometry.y()) * yFactor,
  128. visible.width() * xFactor,
  129. visible.height() * yFactor);
  130. const auto dimensions = QSizeF((_textureSize.width() < _subimage.width()
  131. || _textureSize.height() < _subimage.height())
  132. ? _subimage
  133. : _textureSize);
  134. return {
  135. .geometry = Rect(visible),
  136. .texture = Rect(QRectF(
  137. usedTexture.x() / dimensions.width(),
  138. usedTexture.y() / dimensions.height(),
  139. usedTexture.width() / dimensions.width(),
  140. usedTexture.height() / dimensions.height())),
  141. };
  142. }
  143. } // namespace Ui::GL