Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

Texture.cpp 13KB

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