Open Source Tomb Raider Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pixel.cpp 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*!
  2. * \file src/utils/pixel.cpp
  3. * \brief Pixel buffer utilities
  4. *
  5. * \author xythobuz
  6. */
  7. #include "global.h"
  8. #include "utils/pixel.h"
  9. void bgr2rgb24(unsigned char *image, unsigned int w, unsigned int h) {
  10. assert(image != nullptr);
  11. assert(w > 0);
  12. assert(h > 0);
  13. for (unsigned int i = 0; i < (w * h); ++i) {
  14. /* 24-bit BGR to RGB */
  15. unsigned char swap = image[(i * 3) + 2];
  16. image[(i * 3) + 2] = image[(i * 3)];
  17. image[(i * 3)] = swap;
  18. }
  19. }
  20. void bgra2rgba32(unsigned char *image, unsigned int w, unsigned int h) {
  21. assert(image != nullptr);
  22. assert(w > 0);
  23. assert(h > 0);
  24. for (unsigned int i = 0; i < (w * h); ++i) {
  25. /* 32-bit BGRA to RGBA */
  26. unsigned char swap = image[(i * 4) + 2];
  27. image[(i * 4) + 2] = image[(i * 4)];
  28. image[(i * 4)] = swap;
  29. }
  30. }
  31. void argb2rgba32(unsigned char *image, unsigned int w, unsigned int h) {
  32. assert(image != nullptr);
  33. assert(w > 0);
  34. assert(h > 0);
  35. for (unsigned int i = 0; i < (w * h); ++i) {
  36. /* 32-bit ARGB to RGBA */
  37. unsigned char swap = image[(i * 4) + 3];
  38. image[(i * 4)] = image[(i * 4) + 1];
  39. image[(i * 4) + 1] = image[(i * 4) + 2];
  40. image[(i * 4) + 2] = image[(i * 4) + 3];
  41. image[(i * 4) + 3] = swap;
  42. }
  43. }
  44. #define NEXT_POWER(x) do { \
  45. int i; \
  46. for (i = 1; i < (x); i *= 2); \
  47. x = i; \
  48. } while (false);
  49. // This code based off on gluScaleImage()
  50. unsigned char *scaleBuffer(unsigned char *image, int width, int height, int components) {
  51. assert(image != NULL);
  52. assert(width > 0);
  53. assert(height > 0);
  54. assert((components == 3) || (components == 4));
  55. int original_height = height;
  56. int original_width = width;
  57. NEXT_POWER(height);
  58. NEXT_POWER(width);
  59. if (height > 256)
  60. height = 256;
  61. if (width > 256)
  62. width = 256;
  63. // Check to see if scaling is needed
  64. if (height == original_height && width == original_width)
  65. return NULL;
  66. unsigned char *timage = new unsigned char[height * width * components];
  67. float *tempin = new float[original_width * original_height * components];
  68. float *tempout = new float[width * height * components];
  69. // Copy user data to float format.
  70. for (int i = 0; i < original_height * original_width * components; ++i) {
  71. tempin[i] = (float)image[i];
  72. }
  73. // Determine which filter to use by checking ratios.
  74. float sx;
  75. if (width > 1) {
  76. sx = (float)(original_width - 1) / (float)(width - 1);
  77. } else {
  78. sx = (float)(original_width - 1);
  79. }
  80. float sy;
  81. if (height > 1) {
  82. sy = (float)(original_height - 1) / (float) (height - 1);
  83. } else {
  84. sy = (float)(original_height - 1);
  85. }
  86. if (sx < 1.0 && sy < 1.0) { // Magnify both width and height: use weighted sample of 4 pixels
  87. for (int i = 0; i < height; ++i) {
  88. int i0 = (int)(i * sy);
  89. int i1 = i0 + 1;
  90. if (i1 >= original_height) {
  91. i1 = original_height - 1;
  92. }
  93. float alpha = i * sy - i0;
  94. for (int j = 0; j < width; ++j) {
  95. int j0 = (int) (j * sx);
  96. int j1 = j0 + 1;
  97. if (j1 >= original_width) {
  98. j1 = original_width - 1;
  99. }
  100. float beta = j * sx - j0;
  101. // Compute weighted average of pixels in rect (i0,j0)-(i1,j1)
  102. float *src00 = tempin + (i0 * original_width + j0) * components;
  103. float *src01 = tempin + (i0 * original_width + j1) * components;
  104. float *src10 = tempin + (i1 * original_width + j0) * components;
  105. float *src11 = tempin + (i1 * original_width + j1) * components;
  106. float *dst = tempout + (i * width + j) * components;
  107. for (int k = 0; k < components; ++k) {
  108. float s1 = *src00++ * (1.0f - beta) + *src01++ * beta;
  109. float s2 = *src10++ * (1.0f - beta) + *src11++ * beta;
  110. *dst++ = s1 * (1.0f - alpha) + s2 * alpha;
  111. }
  112. }
  113. }
  114. } else { // Shrink width and/or height: use an unweighted box filter
  115. for (int i = 0; i < height; ++i) {
  116. int i0 = (int) (i * sy);
  117. int i1 = i0 + 1;
  118. if (i1 >= original_height) {
  119. i1 = original_height - 1;
  120. }
  121. for (int j = 0; j < width; ++j) {
  122. int j0 = (int) (j * sx);
  123. int j1 = j0 + 1;
  124. if (j1 >= original_width) {
  125. j1 = original_width - 1;
  126. }
  127. float *dst = tempout + (i * width + j) * components;
  128. // Compute average of pixels in the rectangle (i0,j0)-(i1,j1)
  129. for (int k = 0; k < components; ++k) {
  130. float sum = 0.0;
  131. for (int ii = i0; ii <= i1; ++ii) {
  132. for (int jj = j0; jj <= j1; ++jj) {
  133. sum += *(tempin + (ii * original_width + jj)
  134. * components + k);
  135. }
  136. }
  137. sum /= (j1 - j0 + 1) * (i1 - i0 + 1);
  138. *dst++ = sum;
  139. }
  140. }
  141. }
  142. }
  143. // Copy to our results.
  144. for (int i = 0; i < height * width * components; ++i) {
  145. timage[i] = (unsigned char)tempout[i];
  146. }
  147. // Delete our temp buffers.
  148. delete [] tempin;
  149. delete [] tempout;
  150. return timage;
  151. }