Open Source Tomb Raider Engine
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

Texture.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. /*!
  2. * \file src/Texture.cpp
  3. * \brief Texture registry
  4. *
  5. * \author Mongoose
  6. * \author xythobuz
  7. */
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <stdarg.h>
  12. #include "global.h"
  13. #include "utils/pcx.h"
  14. #include "utils/pixel.h"
  15. #include "utils/strings.h"
  16. #include "utils/tga.h"
  17. #include "Texture.h"
  18. Texture::Texture() {
  19. mTextureIds = NULL;
  20. mFlags = 0;
  21. mTextureId = -1;
  22. mTextureId2 = -1;
  23. mTextureCount = 0;
  24. mTextureLimit = 0;
  25. }
  26. Texture::~Texture() {
  27. reset();
  28. }
  29. unsigned char *Texture::generateColorTexture(unsigned char rgba[4],
  30. unsigned int width, unsigned int height) {
  31. unsigned char *image;
  32. unsigned int i, size;
  33. assert(rgba != NULL);
  34. assert(width > 0);
  35. assert(height > 0);
  36. image = new unsigned char[height*width*4];
  37. for (i = 0, size = width*height; i < size; ++i) {
  38. /* RBGA */
  39. image[i*4] = rgba[0];
  40. image[i*4+1] = rgba[1];
  41. image[i*4+2] = rgba[2];
  42. image[i*4+3] = rgba[3];
  43. }
  44. return image;
  45. }
  46. int Texture::loadColorTexture(unsigned char rgba[4],
  47. unsigned int width, unsigned int height) {
  48. unsigned char *image;
  49. int id;
  50. assert(rgba != NULL);
  51. assert(width > 0);
  52. assert(height > 0);
  53. image = generateColorTexture(rgba, width, height);
  54. id = loadBuffer(image, width, height, RGBA, 32);
  55. delete [] image;
  56. return id;
  57. }
  58. void Texture::setFlag(TextureFlag flag) {
  59. mFlags |= flag;
  60. }
  61. void Texture::clearFlag(TextureFlag flag) {
  62. mFlags &= ~flag;
  63. }
  64. void Texture::reset() {
  65. if (mTextureIds) {
  66. glDeleteTextures(mTextureLimit, mTextureIds);
  67. delete [] mTextureIds;
  68. }
  69. mTextureIds = NULL;
  70. mTextureCount = 0;
  71. mTextureLimit = 0;
  72. }
  73. void Texture::disableMultiTexture() {
  74. mFlags ^= fUseMultiTexture;
  75. mTextureId = -1;
  76. mTextureId2 = -1;
  77. glDisable(GL_TEXTURE_2D);
  78. glActiveTextureARB(GL_TEXTURE0_ARB);
  79. }
  80. void Texture::useMultiTexture(float aU, float aV, float bU, float bV) {
  81. if (!(mFlags & fUseMultiTexture))
  82. return;
  83. glMultiTexCoord2fARB(GL_TEXTURE0_ARB, aU, aV);
  84. glMultiTexCoord2fARB(GL_TEXTURE1_ARB, bU, bV);
  85. }
  86. void Texture::useMultiTexture(float u, float v) {
  87. if (!(mFlags & fUseMultiTexture))
  88. return;
  89. glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v);
  90. glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, v);
  91. }
  92. void Texture::bindMultiTexture(int texture0, int texture1) {
  93. assert(mTextureIds != NULL);
  94. assert(texture0 >= 0);
  95. assert((unsigned int)texture0 <= mTextureCount);
  96. assert(texture1 >= 0);
  97. assert((unsigned int)texture1 <= mTextureCount);
  98. mFlags |= fUseMultiTexture;
  99. mTextureId = texture0;
  100. mTextureId2 = texture1;
  101. glActiveTextureARB(GL_TEXTURE0_ARB);
  102. glEnable(GL_TEXTURE_2D);
  103. glBindTexture(GL_TEXTURE_2D, mTextureIds[texture0]);
  104. glActiveTextureARB(GL_TEXTURE1_ARB);
  105. glEnable(GL_TEXTURE_2D);
  106. glBindTexture(GL_TEXTURE_2D, mTextureIds[texture1]);
  107. }
  108. void Texture::setMaxTextureCount(unsigned int n) {
  109. assert(n > 0);
  110. mTextureLimit = n;
  111. mTextureIds = new unsigned int[n];
  112. glGenTextures(n, mTextureIds);
  113. }
  114. int Texture::getTextureCount() {
  115. return mTextureCount - 1;
  116. }
  117. int Texture::loadBuffer(unsigned char *image,
  118. unsigned int width, unsigned int height,
  119. ColorMode mode, unsigned int bpp) {
  120. int id;
  121. assert(image != NULL);
  122. assert(width > 0);
  123. assert(height > 0);
  124. assert((bpp == 8) || (bpp == 24) || (bpp == 32));
  125. id = loadBufferSlot(image, width, height, mode, bpp, mTextureCount++);
  126. if (id < 0)
  127. return id;
  128. return id;
  129. }
  130. int Texture::loadBufferSlot(unsigned char *image,
  131. unsigned int width, unsigned int height,
  132. ColorMode mode, unsigned int bpp,
  133. unsigned int slot) {
  134. unsigned char bytes;
  135. unsigned int glcMode;
  136. assert(mTextureIds != NULL);
  137. assert(slot < mTextureLimit);
  138. assert(image != NULL);
  139. assert(width > 0);
  140. assert(height > 0);
  141. assert((bpp == 8) || (bpp == 24) || (bpp == 32));
  142. switch (mode) {
  143. case GREYSCALE:
  144. if (bpp != 8) {
  145. printf("Texture::Load ERROR Unsupported GREYSCALE, %i bpp\n", bpp);
  146. return -1;
  147. }
  148. bytes = 1;
  149. glcMode = GL_LUMINANCE;
  150. break;
  151. case RGB:
  152. if (bpp != 24) {
  153. printf("Texture::Load ERROR Unsupported RGB, %i bpp\n", bpp);
  154. return -1;
  155. }
  156. bytes = 3;
  157. glcMode = GL_RGB;
  158. break;
  159. case ARGB:
  160. if (bpp == 32) {
  161. argb2rgba32(image, width, height);
  162. } else {
  163. printf("Texture::Load ERROR Unsupported ARGB, %i bpp\n", bpp);
  164. return -1;
  165. }
  166. bytes = 4;
  167. glcMode = GL_RGBA;
  168. break;
  169. case RGBA:
  170. if (bpp != 32) {
  171. printf("Texture::Load ERROR Unsupported RGBA, %i bpp\n", bpp);
  172. return -1;
  173. }
  174. bytes = 4;
  175. glcMode = GL_RGBA;
  176. break;
  177. case BGR:
  178. if (bpp != 24) {
  179. printf("Texture::Load ERROR Unsupported BGR, %i bpp\n", bpp);
  180. return -1;
  181. }
  182. bytes = 3;
  183. glcMode = GL_BGR_EXT;
  184. break;
  185. case BGRA:
  186. if (bpp != 32) {
  187. printf("Texture::Load ERROR Unsupported BGRA, %i bpp\n", bpp);
  188. return -1;
  189. }
  190. bytes = 4;
  191. glcMode = GL_BGRA_EXT;
  192. break;
  193. }
  194. glClearColor(0.0, 0.0, 0.0, 0.0);
  195. glEnable(GL_DEPTH_TEST);
  196. glShadeModel(GL_SMOOTH);
  197. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  198. glBindTexture(GL_TEXTURE_2D, mTextureIds[slot]);
  199. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  200. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  201. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  202. if (mFlags & fUseMipmaps) {
  203. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  204. GL_NEAREST_MIPMAP_LINEAR);
  205. //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  206. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  207. GL_LINEAR_MIPMAP_LINEAR);
  208. glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
  209. glTexImage2D(GL_TEXTURE_2D, 0, bytes, width, height, 0, glcMode, GL_UNSIGNED_BYTE, image);
  210. } else {
  211. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  212. glTexImage2D(GL_TEXTURE_2D, 0, glcMode, width, height, 0,
  213. glcMode, GL_UNSIGNED_BYTE, image);
  214. }
  215. //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  216. return slot;
  217. }
  218. void Texture::bindTextureId(unsigned int n) {
  219. assert(mTextureIds != NULL);
  220. assert(n <= mTextureCount);
  221. mTextureId = n;
  222. glEnable(GL_TEXTURE_2D);
  223. //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  224. glBindTexture(GL_TEXTURE_2D, mTextureIds[n]);
  225. }
  226. int Texture::loadPCX(const char *filename) {
  227. unsigned char *image;
  228. unsigned int w, h;
  229. int id = -1;
  230. int error = pcxLoad(filename, &image, &w, &h);
  231. if (error == 0) {
  232. id = loadBuffer(image, w, h, RGBA, 32);
  233. delete [] image;
  234. }
  235. return id;
  236. }
  237. int Texture::loadTGA(const char *filename) {
  238. FILE *f;
  239. unsigned char *image = NULL;
  240. unsigned char *image2 = NULL;
  241. unsigned int w, h;
  242. char type;
  243. int id = -1;
  244. assert(filename != NULL);
  245. assert(filename[0] != '\0');
  246. f = fopen(filename, "rb");
  247. if (!f) {
  248. perror("Couldn't load file");
  249. } else if (!tgaCheck(f)) {
  250. tgaLoad(f, &image, &w, &h, &type);
  251. type += 2;
  252. image2 = scaleBuffer(image, w, h, (type == 4) ? 4 : 3);
  253. if (image2) {
  254. image = image2;
  255. w = h = 256;
  256. }
  257. if (image) {
  258. id = loadBuffer(image, w, h,
  259. (type == 4) ? RGBA : RGB,
  260. (type == 4) ? 32 : 24);
  261. delete [] image;
  262. }
  263. fclose(f);
  264. }
  265. if (id == -1) {
  266. printf("Texture::loadTGA> ERROR: Failed to load '%s'\n", filename);
  267. }
  268. return id;
  269. }
  270. int Texture::nextPower(int seed) {
  271. int i = 1;
  272. for (; i < seed; i *= 2);
  273. return i;
  274. }
  275. /* This code based off on gluScaleImage() */
  276. unsigned char *Texture::scaleBuffer(unsigned char *image,
  277. int width, int height, int components) {
  278. int i, j, k;
  279. float* tempin;
  280. float* tempout;
  281. float sx, sy;
  282. //int components = 3;
  283. unsigned char *timage;
  284. int original_height = height;
  285. int original_width = width;
  286. assert(image != NULL);
  287. assert(width > 0);
  288. assert(height > 0);
  289. height = nextPower(height);
  290. width = nextPower(width);
  291. if (height > 256)
  292. height = 256;
  293. if (width > 256)
  294. width = 256;
  295. // Check to see if scaling is needed
  296. if (height == original_height && width == original_width)
  297. return NULL;
  298. //printf("%i\n", components);
  299. timage = new unsigned char[height * width * components];
  300. tempin = new float[original_width * original_height * components * sizeof(float)];
  301. tempout = new float[width * height * components * sizeof(float)];
  302. // Copy user data to float format.
  303. for (i = 0; i < original_height * original_width * components; ++i) {
  304. tempin[i] = (float)image[i];
  305. }
  306. // Determine which filter to use by checking ratios.
  307. if (width > 1) {
  308. sx = (float)(original_width - 1) / (float)(width - 1);
  309. } else {
  310. sx = (float)(original_width - 1);
  311. }
  312. if (height > 1) {
  313. sy = (float)(original_height - 1) / (float) (height - 1);
  314. } else {
  315. sy = (float)(original_height - 1);
  316. }
  317. if (sx < 1.0 && sy < 1.0) {
  318. /* Magnify both width and height: use weighted sample of 4 pixels */
  319. for (i = 0; i < height; ++i) {
  320. int i0 = (int)(i * sy);
  321. int i1 = i0 + 1;
  322. if (i1 >= original_height) {
  323. i1 = original_height - 1;
  324. }
  325. float alpha = i * sy - i0;
  326. for (j = 0; j < width; ++j) {
  327. int j0 = (int) (j * sx);
  328. int j1 = j0 + 1;
  329. if (j1 >= original_width) {
  330. j1 = original_width - 1;
  331. }
  332. float beta = j * sx - j0;
  333. /* Compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
  334. float *src00 = tempin + (i0 * original_width + j0) * components;
  335. float *src01 = tempin + (i0 * original_width + j1) * components;
  336. float *src10 = tempin + (i1 * original_width + j0) * components;
  337. float *src11 = tempin + (i1 * original_width + j1) * components;
  338. float *dst = tempout + (i * width + j) * components;
  339. for (k = 0; k < components; ++k) {
  340. float s1 = *src00++ * (1.0f - beta) + *src01++ * beta;
  341. float s2 = *src10++ * (1.0f - beta) + *src11++ * beta;
  342. *dst++ = s1 * (1.0f - alpha) + s2 * alpha;
  343. }
  344. }
  345. }
  346. } else {
  347. /* Shrink width and/or height: use an unweighted box filter */
  348. for (i = 0; i < height; ++i) {
  349. int i0 = (int) (i * sy);
  350. int i1 = i0 + 1;
  351. if (i1 >= original_height) {
  352. i1 = original_height - 1;
  353. }
  354. for (j = 0; j < width; ++j) {
  355. int j0 = (int) (j * sx);
  356. int j1 = j0 + 1;
  357. if (j1 >= original_width) {
  358. j1 = original_width - 1;
  359. }
  360. float *dst = tempout + (i * width + j) * components;
  361. /* Compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
  362. for (k = 0; k < components; ++k) {
  363. float sum = 0.0;
  364. for (int ii = i0; ii <= i1; ++ii) {
  365. for (int jj = j0; jj <= j1; ++jj) {
  366. sum += *(tempin + (ii * original_width + jj)
  367. * components + k);
  368. }
  369. }
  370. sum /= ( j1 - j0 + 1 ) * ( i1 - i0 + 1 );
  371. *dst++ = sum;
  372. }
  373. }
  374. }
  375. }
  376. // Copy to our results.
  377. for (i = 0; i < height * width * components; ++i) {
  378. timage[i] = (unsigned char)tempout[i];
  379. }
  380. // Delete our temp buffers.
  381. delete[] tempin;
  382. delete[] tempout;
  383. delete[] image;
  384. return timage;
  385. }