HeightField.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. #include "Base.h"
  2. #include "HeightField.h"
  3. #include "Image.h"
  4. #include "FileSystem.h"
  5. namespace gameplay
  6. {
  7. HeightField::HeightField(unsigned int columns, unsigned int rows)
  8. : _array(NULL), _cols(columns), _rows(rows)
  9. {
  10. _array = new float[columns * rows];
  11. }
  12. HeightField::~HeightField()
  13. {
  14. SAFE_DELETE_ARRAY(_array);
  15. }
  16. HeightField* HeightField::create(unsigned int columns, unsigned int rows)
  17. {
  18. return new HeightField(columns, rows);
  19. }
  20. /**
  21. * @script{ignore}
  22. */
  23. float normalizedHeightPacked(float r, float g, float b)
  24. {
  25. // This formula is intended for 24-bit packed heightmap images (that are generated
  26. // with gameplay-encoder. However, it is also compatible with normal grayscale
  27. // heightmap images, with an error of approximately 0.4%. This can be seen by
  28. // setting r=g=b=x and comparing the grayscale height expression to the packed
  29. // height expression: the error is 2^-8 + 2^-16 which is just under 0.4%.
  30. return (256.0f*r + g + 0.00390625f*b) / 65536.0f;
  31. }
  32. HeightField* HeightField::createFromImage(const char* path, float heightMin, float heightMax)
  33. {
  34. return create(path, 0, 0, heightMin, heightMax);
  35. }
  36. HeightField* HeightField::createFromRAW(const char* path, unsigned int width, unsigned int height, float heightMin, float heightMax)
  37. {
  38. return create(path, width, height, heightMin, heightMax);
  39. }
  40. HeightField* HeightField::create(const char* path, unsigned int width, unsigned int height, float heightMin, float heightMax)
  41. {
  42. GP_ASSERT(path);
  43. GP_ASSERT(heightMax >= heightMin);
  44. float heightScale = heightMax - heightMin;
  45. HeightField* heightfield = NULL;
  46. // Load height data from image
  47. std::string ext = FileSystem::getExtension(path);
  48. if (ext == ".PNG")
  49. {
  50. // Normal image
  51. Image* image = Image::create(path);
  52. if (!image)
  53. return NULL;
  54. unsigned int pixelSize = 0;
  55. switch (image->getFormat())
  56. {
  57. case Image::RGB:
  58. pixelSize = 3;
  59. break;
  60. case Image::RGBA:
  61. pixelSize = 4;
  62. break;
  63. default:
  64. SAFE_RELEASE(image);
  65. GP_WARN("Unsupported pixel format for heightfield image: %s.", path);
  66. return NULL;
  67. }
  68. // Calculate the heights for each pixel.
  69. heightfield = HeightField::create(image->getWidth(), image->getHeight());
  70. float* heights = heightfield->getArray();
  71. unsigned char* data = image->getData();
  72. int idx;
  73. for (int y = image->getHeight()-1, i = 0; y >= 0; --y)
  74. {
  75. for (unsigned int x = 0, w = image->getWidth(); x < w; ++x)
  76. {
  77. idx = (y*w + x) * pixelSize;
  78. heights[i++] = heightMin + normalizedHeightPacked(data[idx], data[idx + 1], data[idx + 2]) * heightScale;
  79. }
  80. }
  81. SAFE_RELEASE(image);
  82. }
  83. else if (ext == ".RAW" || ext == ".R16")
  84. {
  85. // RAW image (headerless)
  86. if (width < 2 || height < 2 || heightMax < 0)
  87. {
  88. GP_WARN("Invalid 'width', 'height' or 'heightMax' parameter for RAW heightfield image: %s.", path);
  89. return NULL;
  90. }
  91. // Load raw bytes
  92. int fileSize = 0;
  93. unsigned char* bytes = (unsigned char*)FileSystem::readAll(path, &fileSize);
  94. if (bytes == NULL)
  95. {
  96. GP_WARN("Falied to read bytes from RAW heightfield image: %s.", path);
  97. return NULL;
  98. }
  99. // Determine if the RAW file is 8-bit or 16-bit based on file size.
  100. int bits = (fileSize / (width * height)) * 8;
  101. if (bits != 8 && bits != 16)
  102. {
  103. GP_WARN("Invalid RAW file - must be 8-bit or 16-bit, but found neither: %s.", path);
  104. SAFE_DELETE_ARRAY(bytes);
  105. return NULL;
  106. }
  107. heightfield = HeightField::create(width, height);
  108. float* heights = heightfield->getArray();
  109. if (bits == 16)
  110. {
  111. // 16-bit (0-65535)
  112. int idx;
  113. for (unsigned int y = 0, i = 0; y < height; ++y)
  114. {
  115. for (unsigned int x = 0; x < width; ++x, ++i)
  116. {
  117. idx = (y * width + x) << 1;
  118. heights[i] = heightMin + ((bytes[idx] | (int)bytes[idx+1] << 8) / 65535.0f) * heightScale;
  119. }
  120. }
  121. }
  122. else
  123. {
  124. // 8-bit (0-255)
  125. for (unsigned int y = 0, i = 0; y < height; ++y)
  126. {
  127. for (unsigned int x = 0; x < width; ++x, ++i)
  128. {
  129. heights[i] = heightMin + (bytes[y * width + x] / 255.0f) * heightScale;
  130. }
  131. }
  132. }
  133. SAFE_DELETE_ARRAY(bytes);
  134. }
  135. else
  136. {
  137. GP_WARN("Unsupported heightfield image format: %s.", path);
  138. }
  139. return heightfield;
  140. }
  141. float* HeightField::getArray() const
  142. {
  143. return _array;
  144. }
  145. float HeightField::getHeight(float column, float row) const
  146. {
  147. // Clamp to heightfield boundaries
  148. column = column < 0 ? 0 : (column > (_cols-1) ? (_cols-1) : column);
  149. row = row < 0 ? 0 : (row > (_rows-1) ? (_rows-1) : row);
  150. unsigned int x1 = column;
  151. unsigned int y1 = row;
  152. unsigned int x2 = x1 + 1;
  153. unsigned int y2 = y1 + 1;
  154. float tmp;
  155. float xFactor = modf(column, &tmp);
  156. float yFactor = modf(row, &tmp);
  157. float xFactorI = 1.0f - xFactor;
  158. float yFactorI = 1.0f - yFactor;
  159. if (x2 >= _cols && y2 >= _rows)
  160. {
  161. return _array[x1 + y1 * _cols];
  162. }
  163. else if (x2 >= _cols)
  164. {
  165. return _array[x1 + y1 * _cols] * yFactorI + _array[x1 + y2 * _cols] * yFactor;
  166. }
  167. else if (y2 >= _rows)
  168. {
  169. return _array[x1 + y1 * _cols] * xFactorI + _array[x2 + y1 * _cols] * xFactor;
  170. }
  171. else
  172. {
  173. float a = xFactorI * yFactorI;
  174. float b = xFactorI * yFactor;
  175. float c = xFactor * yFactor;
  176. float d = xFactor * yFactorI;
  177. return _array[x1 + y1 * _cols] * a + _array[x1 + y2 * _cols] * b +
  178. _array[x2 + y2 * _cols] * c + _array[x2 + y1 * _cols] * d;
  179. }
  180. }
  181. unsigned int HeightField::getColumnCount() const
  182. {
  183. return _cols;
  184. }
  185. unsigned int HeightField::getRowCount() const
  186. {
  187. return _rows;
  188. }
  189. }