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

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