HeightField.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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. // Validate input parameters
  45. size_t pathLength = strlen(path);
  46. if (pathLength <= 4)
  47. {
  48. GP_WARN("Unrecognized file extension for heightfield image: %s.", path);
  49. return NULL;
  50. }
  51. float heightScale = heightMax - heightMin;
  52. HeightField* heightfield = NULL;
  53. // Load height data from image
  54. const char* ext = path + (pathLength - 4);
  55. if (ext[0] == '.' && toupper(ext[1]) == 'P' && toupper(ext[2]) == 'N' && toupper(ext[3]) == 'G')
  56. {
  57. // Normal image
  58. Image* image = Image::create(path);
  59. if (!image)
  60. return NULL;
  61. unsigned int pixelSize = 0;
  62. switch (image->getFormat())
  63. {
  64. case Image::RGB:
  65. pixelSize = 3;
  66. break;
  67. case Image::RGBA:
  68. pixelSize = 4;
  69. break;
  70. default:
  71. SAFE_RELEASE(image);
  72. GP_WARN("Unsupported pixel format for heightfield image: %s.", path);
  73. return NULL;
  74. }
  75. // Calculate the heights for each pixel.
  76. heightfield = HeightField::create(image->getWidth(), image->getHeight());
  77. float* heights = heightfield->getArray();
  78. unsigned char* data = image->getData();
  79. int idx;
  80. for (int y = image->getHeight()-1, i = 0; y >= 0; --y)
  81. {
  82. for (unsigned int x = 0, w = image->getWidth(); x < w; ++x)
  83. {
  84. idx = (y*w + x) * pixelSize;
  85. heights[i++] = heightMin + normalizedHeightPacked(data[idx], data[idx + 1], data[idx + 2]) * heightScale;
  86. }
  87. }
  88. SAFE_RELEASE(image);
  89. }
  90. else if (ext[0] == '.' && toupper(ext[1]) == 'R' && toupper(ext[2]) == 'A' && toupper(ext[3]) == 'W')
  91. {
  92. // RAW image (headerless)
  93. if (width < 2 || height < 2 || heightMax < 0)
  94. {
  95. GP_WARN("Invalid 'width', 'height' or 'heightMax' parameter for RAW heightfield image: %s.", path);
  96. return NULL;
  97. }
  98. // Load raw bytes
  99. int fileSize = 0;
  100. unsigned char* bytes = (unsigned char*)FileSystem::readAll(path, &fileSize);
  101. if (bytes == NULL)
  102. {
  103. GP_WARN("Falied to read bytes from RAW heightfield image: %s.", path);
  104. return NULL;
  105. }
  106. // Determine if the RAW file is 8-bit or 16-bit based on file size.
  107. int bits = (fileSize / (width * height)) * 8;
  108. if (bits != 8 && bits != 16)
  109. {
  110. GP_WARN("Invalid RAW file - must be 8-bit or 16-bit, but found neither: %s.", path);
  111. SAFE_DELETE_ARRAY(bytes);
  112. return NULL;
  113. }
  114. heightfield = HeightField::create(width, height);
  115. float* heights = heightfield->getArray();
  116. if (bits == 16)
  117. {
  118. // 16-bit (0-65535)
  119. int idx;
  120. for (unsigned int y = 0, i = 0; y < height; ++y)
  121. {
  122. for (unsigned int x = 0; x < width; ++x, ++i)
  123. {
  124. idx = (y * width + x) << 1;
  125. heights[i] = heightMin + ((bytes[idx] | (int)bytes[idx+1] << 8) / 65535.0f) * heightScale;
  126. }
  127. }
  128. }
  129. else
  130. {
  131. // 8-bit (0-255)
  132. for (unsigned int y = 0, i = 0; y < height; ++y)
  133. {
  134. for (unsigned int x = 0; x < width; ++x, ++i)
  135. {
  136. heights[i] = heightMin + (bytes[y * width + x] / 255.0f) * heightScale;
  137. }
  138. }
  139. }
  140. SAFE_DELETE_ARRAY(bytes);
  141. }
  142. else
  143. {
  144. GP_WARN("Unsupported heightfield image format: %s.", path);
  145. }
  146. return heightfield;
  147. }
  148. float* HeightField::getArray() const
  149. {
  150. return _array;
  151. }
  152. float HeightField::getHeight(float column, float row) const
  153. {
  154. // Clamp to heightfield boundaries
  155. column = column < 0 ? 0 : (column > (_cols-1) ? (_cols-1) : column);
  156. row = row < 0 ? 0 : (row > (_rows-1) ? (_rows-1) : row);
  157. unsigned int x1 = column;
  158. unsigned int y1 = row;
  159. unsigned int x2 = x1 + 1;
  160. unsigned int y2 = y1 + 1;
  161. float tmp;
  162. float xFactor = modf(column, &tmp);
  163. float yFactor = modf(row, &tmp);
  164. float xFactorI = 1.0f - xFactor;
  165. float yFactorI = 1.0f - yFactor;
  166. if (x2 >= _cols && y2 >= _rows)
  167. {
  168. return _array[x1 + y1 * _cols];
  169. }
  170. else if (x2 >= _cols)
  171. {
  172. return _array[x1 + y1 * _cols] * yFactorI + _array[x1 + y2 * _cols] * yFactor;
  173. }
  174. else if (y2 >= _rows)
  175. {
  176. return _array[x1 + y1 * _cols] * xFactorI + _array[x2 + y1 * _cols] * xFactor;
  177. }
  178. else
  179. {
  180. float a = xFactorI * yFactorI;
  181. float b = xFactorI * yFactor;
  182. float c = xFactor * yFactor;
  183. float d = xFactor * yFactorI;
  184. return _array[x1 + y1 * _cols] * a + _array[x1 + y2 * _cols] * b +
  185. _array[x2 + y2 * _cols] * c + _array[x2 + y1 * _cols] * d;
  186. }
  187. }
  188. unsigned int HeightField::getColumnCount() const
  189. {
  190. return _cols;
  191. }
  192. unsigned int HeightField::getRowCount() const
  193. {
  194. return _rows;
  195. }
  196. }