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.

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. }