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 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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. unsigned char* generateColorTexture(glm::vec4 rgba, unsigned int width,
  10. unsigned int height, unsigned int bpp) {
  11. orAssert(width > 0);
  12. orAssert(height > 0);
  13. orAssert((bpp == 24) || (bpp == 32));
  14. unsigned char* image = new unsigned char[height * width * (bpp / 8)];
  15. for (unsigned int i = 0; i < (width * height); i++) {
  16. image[i * (bpp / 8)] = (unsigned char)(rgba.r * 255);
  17. image[(i * (bpp / 8)) + 1] = (unsigned char)(rgba.g * 255);
  18. image[(i * (bpp / 8)) + 2] = (unsigned char)(rgba.b * 255);
  19. if (bpp == 32) {
  20. image[(i * (bpp / 8)) + 3] = (unsigned char)(rgba.a * 255);
  21. }
  22. }
  23. return image;
  24. }
  25. void argb2rgba32(unsigned char* image, unsigned int w, unsigned int h) {
  26. orAssert(image != nullptr);
  27. orAssert(w > 0);
  28. orAssert(h > 0);
  29. for (unsigned int i = 0; i < (w * h); ++i) {
  30. // 32-bit ARGB to RGBA
  31. unsigned char swap = image[i * 4];
  32. image[i * 4] = image[(i * 4) + 1];
  33. image[(i * 4) + 1] = image[(i * 4) + 2];
  34. image[(i * 4) + 2] = image[(i * 4) + 3];
  35. image[(i * 4) + 3] = swap;
  36. }
  37. }
  38. unsigned char* argb16to32(unsigned char* image, unsigned int w, unsigned int h) {
  39. orAssert(image != nullptr);
  40. orAssert(w > 0);
  41. orAssert(h > 0);
  42. unsigned char* img = new unsigned char[w * h * 4];
  43. for (unsigned int i = 0; i < (w * h); ++i) {
  44. // arrr.rrgg gggb.bbbb shift to 5bit
  45. img[i * 4] = (image[(i * 2) + 1] & 0x80) ? 0xFF : 0; // A
  46. img[(i * 4) + 1] = (image[(i * 2) + 1] & 0x7C) >> 2; // R
  47. img[(i * 4) + 2] = (image[(i * 2) + 1] & 0x03) << 3;
  48. img[(i * 4) + 2] |= (image[i * 2] & 0xE0) >> 5; // G
  49. img[(i * 4) + 3] = image[i * 2] & 0x1F; // B
  50. img[(i * 4) + 1] <<= 3; // R
  51. img[(i * 4) + 2] <<= 3; // G
  52. img[(i * 4) + 3] <<= 3; // B
  53. }
  54. return img;
  55. }
  56. unsigned char* grayscale2rgba(unsigned char* image, unsigned int w, unsigned int h) {
  57. orAssert(image != nullptr);
  58. orAssert(w > 0);
  59. orAssert(h > 0);
  60. unsigned char* img = new unsigned char[w * h * 4];
  61. for (unsigned int i = 0; i < (w * h); i++) {
  62. img[i * 4] = image[i];
  63. img[(i * 4) + 1] = image[i];
  64. img[(i * 4) + 2] = image[i];
  65. img[(i * 4) + 3] = (image[i] == 0) ? 0 : 255;
  66. }
  67. return img;
  68. }
  69. #define NEXT_POWER(x) do { \
  70. unsigned int i; \
  71. for (i = 1; i < (x); i *= 2); \
  72. (x) = i; \
  73. } while (false);
  74. // This code based off on gluScaleImage()
  75. unsigned char* scaleBuffer(unsigned char* image, unsigned int* w, unsigned int* h,
  76. unsigned int bpp) {
  77. unsigned int width = *w;
  78. unsigned int height = *h;
  79. orAssert(image != nullptr);
  80. orAssert(width > 0);
  81. orAssert(height > 0);
  82. orAssert((bpp % 8) == 0);
  83. unsigned int components = bpp / 8;
  84. unsigned int original_height = height;
  85. unsigned int original_width = width;
  86. NEXT_POWER(height);
  87. NEXT_POWER(width);
  88. // Check to see if scaling is needed
  89. if (height == original_height && width == original_width)
  90. return nullptr;
  91. *w = width;
  92. *h = height;
  93. unsigned char* timage = new unsigned char[height * width * components];
  94. float* tempin = new float[original_width * original_height * components];
  95. float* tempout = new float[width * height * components];
  96. // Copy user data to float format.
  97. for (unsigned int i = 0; i < original_height * original_width * components; ++i) {
  98. tempin[i] = (float)image[i];
  99. }
  100. // Determine which filter to use by checking ratios.
  101. float sx;
  102. if (width > 1) {
  103. sx = (float)(original_width - 1) / (float)(width - 1);
  104. } else {
  105. sx = (float)(original_width - 1);
  106. }
  107. float sy;
  108. if (height > 1) {
  109. sy = (float)(original_height - 1) / (float)(height - 1);
  110. } else {
  111. sy = (float)(original_height - 1);
  112. }
  113. if (sx < 1.0 && sy < 1.0) { // Magnify both width and height: use weighted sample of 4 pixels
  114. for (unsigned int i = 0; i < height; ++i) {
  115. unsigned int i0 = (unsigned int)(i * sy);
  116. unsigned int i1 = i0 + 1;
  117. if (i1 >= original_height) {
  118. i1 = original_height - 1;
  119. }
  120. float alpha = i * sy - i0;
  121. for (unsigned int j = 0; j < width; ++j) {
  122. unsigned int j0 = (unsigned int)(j * sx);
  123. unsigned int j1 = j0 + 1;
  124. if (j1 >= original_width) {
  125. j1 = original_width - 1;
  126. }
  127. float beta = j * sx - j0;
  128. // Compute weighted average of pixels in rect (i0,j0)-(i1,j1)
  129. float* src00 = tempin + (i0 * original_width + j0) * components;
  130. float* src01 = tempin + (i0 * original_width + j1) * components;
  131. float* src10 = tempin + (i1 * original_width + j0) * components;
  132. float* src11 = tempin + (i1 * original_width + j1) * components;
  133. float* dst = tempout + (i * width + j) * components;
  134. for (unsigned int k = 0; k < components; ++k) {
  135. float s1 = *src00++ * (1.0f - beta) + *src01++ * beta;
  136. float s2 = *src10++ * (1.0f - beta) + *src11++ * beta;
  137. *dst++ = s1 * (1.0f - alpha) + s2 * alpha;
  138. }
  139. }
  140. }
  141. } else { // Shrink width and/or height: use an unweighted box filter
  142. for (unsigned int i = 0; i < height; ++i) {
  143. unsigned int i0 = (unsigned int)(i * sy);
  144. unsigned int i1 = i0 + 1;
  145. if (i1 >= original_height) {
  146. i1 = original_height - 1;
  147. }
  148. for (unsigned int j = 0; j < width; ++j) {
  149. unsigned int j0 = (unsigned int)(j * sx);
  150. unsigned int j1 = j0 + 1;
  151. if (j1 >= original_width) {
  152. j1 = original_width - 1;
  153. }
  154. float* dst = tempout + (i * width + j) * components;
  155. // Compute average of pixels in the rectangle (i0,j0)-(i1,j1)
  156. for (unsigned int k = 0; k < components; ++k) {
  157. float sum = 0.0;
  158. for (unsigned int ii = i0; ii <= i1; ++ii) {
  159. for (unsigned int jj = j0; jj <= j1; ++jj) {
  160. sum += *(tempin + (ii * original_width + jj)
  161. * components + k);
  162. }
  163. }
  164. sum /= (j1 - j0 + 1) * (i1 - i0 + 1);
  165. *dst++ = sum;
  166. }
  167. }
  168. }
  169. }
  170. // Copy to our results.
  171. for (unsigned int i = 0; i < height * width * components; ++i) {
  172. timage[i] = (unsigned char)tempout[i];
  173. }
  174. // Delete our temp buffers.
  175. delete [] tempin;
  176. delete [] tempout;
  177. return timage;
  178. }