Open Source Tomb Raider Engine
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

Texture.cpp 13KB

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