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 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125
  1. /*!
  2. * \file src/Texture.cpp
  3. * \brief Texture registry
  4. *
  5. * \author Mongoose
  6. */
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <stdarg.h>
  11. #include "SDL_ttf.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. gl_font_t *gFontTest = 0x0;
  22. ////////////////////////////////////////////////////////////
  23. // Constructors
  24. ////////////////////////////////////////////////////////////
  25. Texture::Texture()
  26. {
  27. mTextureIds = NULL;
  28. mFlags = 0;
  29. mTextureId = -1;
  30. mTextureId2 = -1;
  31. mTextureCount = 0;
  32. mTextureLimit = 0;
  33. initSDL_TTF();
  34. textureDebug = -1;
  35. }
  36. Texture::~Texture()
  37. {
  38. if (gFontTest)
  39. {
  40. glDeleteLists(gFontTest->drawListBase, gFontTest->count);
  41. delete gFontTest;
  42. }
  43. reset();
  44. }
  45. ////////////////////////////////////////////////////////////
  46. // Public Accessors
  47. ////////////////////////////////////////////////////////////
  48. unsigned char *Texture::generateColorTexture(unsigned char rgba[4],
  49. unsigned int width,
  50. unsigned int height)
  51. {
  52. unsigned char *image;
  53. unsigned int i, size;
  54. image = new unsigned char[height*width*4];
  55. for (i = 0, size = width*height; i < size; ++i)
  56. {
  57. /* RBGA */
  58. image[i*4] = rgba[0];
  59. image[i*4+1] = rgba[1];
  60. image[i*4+2] = rgba[2];
  61. image[i*4+3] = rgba[3];
  62. }
  63. return image;
  64. }
  65. void glEnterMode2d(unsigned int width, unsigned int height)
  66. {
  67. glPushAttrib(GL_ENABLE_BIT);
  68. glDisable(GL_DEPTH_TEST);
  69. glDisable(GL_CULL_FACE);
  70. glEnable(GL_TEXTURE_2D);
  71. /* This allows alpha blending of 2D textures with the scene */
  72. glEnable(GL_BLEND);
  73. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  74. glViewport(0, 0, width, height);
  75. glMatrixMode(GL_PROJECTION);
  76. glPushMatrix();
  77. glLoadIdentity();
  78. glOrtho(0.0, (GLdouble)width, (GLdouble)height, 0.0, 0.0, 1.0);
  79. glMatrixMode(GL_MODELVIEW);
  80. glPushMatrix();
  81. glLoadIdentity();
  82. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  83. }
  84. void glExitMode2d()
  85. {
  86. glMatrixMode(GL_MODELVIEW);
  87. glPopMatrix();
  88. glMatrixMode(GL_PROJECTION);
  89. glPopMatrix();
  90. glPopAttrib();
  91. glMatrixMode(GL_MODELVIEW);
  92. }
  93. void bufferedPrintf(char *string, unsigned int len, char *s, ...)
  94. {
  95. va_list args;
  96. if (s && s[0])
  97. {
  98. va_start(args, s);
  99. vsnprintf(string, len-1, s, args);
  100. string[len-1] = 0;
  101. va_end(args);
  102. }
  103. }
  104. void glPrint2d(float x, float y, float scale, char *string)
  105. {
  106. gl_font_t *font = gFontTest;
  107. if (!font)
  108. {
  109. static int errors = 0;
  110. if (errors < 10)
  111. printf("ERROR: glPrint2d failed, %i\n", ++errors);
  112. return;
  113. }
  114. glPushMatrix();
  115. glBindTexture(GL_TEXTURE_2D, font->textureId);
  116. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  117. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  118. glTranslatef(x, y, 0);
  119. glScalef(scale, scale, 1);
  120. /*! \fixme
  121. * Add utf-8 dencoding of char* string
  122. *
  123. * Also this string must be preprocessed to have glyph offsets
  124. * instead of ASCII text in it and support counts over 256 */
  125. glListBase(font->drawListBase - font->utf8Offset);
  126. glCallLists(strlen(string), GL_BYTE, string);
  127. glPopMatrix();
  128. }
  129. void glPrint3d(float x, float y, float z,
  130. float pitch, float yaw, float roll,
  131. float scale,
  132. char *string)
  133. {
  134. gl_font_t *font = gFontTest;
  135. if (!font)
  136. {
  137. static int errors = 0;
  138. if (errors < 10)
  139. printf("ERROR: glPrint3d failed, %i\n", ++errors);
  140. return;
  141. }
  142. glPushMatrix();
  143. glBindTexture(GL_TEXTURE_2D, font->textureId);
  144. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  145. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  146. glTranslatef(x, y, z);
  147. glRotatef(roll, 1, 0, 0);
  148. glRotatef(yaw, 0, 1, 0);
  149. glRotatef(pitch, 0, 0, 1);
  150. glScalef(scale, scale, scale);
  151. /*! \fixme
  152. * Add utf-8 dencoding of char* string
  153. *
  154. * Also this string must be preprocessed to have glyph offsets
  155. * instead of ASCII text in it and support counts over 256 */
  156. glListBase(font->drawListBase - font->utf8Offset);
  157. glCallLists(strlen(string), GL_BYTE, string);
  158. glPopMatrix();
  159. }
  160. int Texture::showTextureDebug(int textureId) {
  161. if (textureId >= getTextureCount())
  162. return -1;
  163. textureDebug = textureId;
  164. textureDebugFrames = 100;
  165. return mTextureIds[textureId];
  166. }
  167. void Texture::debugTextureRender(int width, int height) {
  168. int xMin, xMax, yMin, yMax;
  169. xMin = yMin = 0;
  170. xMax = width;
  171. yMax = height;
  172. if ((textureDebug >= 0) && (textureDebugFrames > 0)) {
  173. glColor3f(1, 1, 1);
  174. bindTextureId(textureDebug);
  175. // Draw a textured quad
  176. glBegin(GL_QUADS);
  177. glTexCoord2f(0, 0); glVertex3f(xMin, yMin, 0);
  178. glTexCoord2f(0, 1); glVertex3f(xMin, yMax, 0);
  179. glTexCoord2f(1, 1); glVertex3f(xMax, yMax, 0);
  180. glTexCoord2f(1, 0); glVertex3f(xMax, yMin, 0);
  181. glEnd();
  182. textureDebugFrames--;
  183. }
  184. }
  185. int Texture::loadFontTTF(const char *filename,
  186. unsigned int utf8Offset, unsigned int count)
  187. {
  188. ttf_texture_t *texture;
  189. unsigned char rgb[3] = {0xff, 0xff, 0xff};
  190. if (!filename || !filename[0])
  191. {
  192. printf("fontTest> Passed bad filename\n");
  193. return -1;
  194. }
  195. texture = generateFontTexture(filename, 24, 256, rgb,
  196. //0x303f, 0x3093-0x303f, // hiragana
  197. //32, 126 - 32, // english
  198. utf8Offset, count,
  199. false);
  200. if (texture)
  201. {
  202. #ifdef DUMP_TTF_TGA
  203. tgaSaveFilename(texture->texture, 256, 256, 4, "ttf_font.tga");
  204. #endif
  205. gFontTest = generateFont(texture);
  206. /*! \fixme Until UTF8 decoder is working, we map from
  207. ASCII when rendering */
  208. gFontTest->utf8Offset = 32; // hack to use ASCII strings to test unicode
  209. delete [] texture->texture;
  210. delete [] texture->glyphs;
  211. delete texture;
  212. return gFontTest->textureId;
  213. }
  214. else
  215. {
  216. return -2;
  217. }
  218. }
  219. gl_font_t *Texture::generateFont(ttf_texture_t *texture)
  220. {
  221. const float spacing = 4.0;
  222. unsigned int i;
  223. float u, v, u2, v2;
  224. int h;
  225. gl_font_t *font;
  226. if (!texture)
  227. return NULL;
  228. printf("Generating gl font from texture...\n");
  229. font = new gl_font_t;
  230. font->utf8Offset = texture->utf8Offset;
  231. font->count = texture->count;
  232. font->textureId = loadBuffer(texture->texture,
  233. texture->width, texture->width, RGBA, 32);
  234. glColor3f(1.0, 1.0, 1.0);
  235. font->drawListBase = glGenLists(texture->count);
  236. glBindTexture(GL_TEXTURE_2D, font->textureId);
  237. for (i = 0; i < texture->count; i++)
  238. {
  239. /* Generate texture coordinates for this TTF glyph */
  240. u = (float)texture->glyphs[i].x / (float)texture->width;
  241. v = (float)texture->glyphs[i].y / (float)texture->width;
  242. u2 = (((float)texture->glyphs[i].x + (float)texture->glyphs[i].w) /
  243. (float)texture->width);
  244. v2 = (((float)texture->glyphs[i].y + (float)texture->glyphs[i].h) /
  245. (float)texture->width);
  246. #ifdef DEBUG_TTF_OFFSET
  247. if (i+texture->utf8Offset == 'y' || i+texture->utf8Offset == 'x')
  248. {
  249. printf("%c: %i %i %i\n",
  250. i+texture->utf8Offset,
  251. texture->fontDescent,
  252. texture->glyphs[i].miny, texture->glyphs[i].maxy);
  253. }
  254. #endif
  255. if (texture->glyphs[i].h < texture->fontHeight)
  256. {
  257. h = texture->fontHeight - texture->glyphs[i].h;
  258. }
  259. else
  260. {
  261. h = 0;
  262. }
  263. // After migrating to SDL2_TTF, some characters where rendered slightly
  264. // vertically offset. However, dumping the font texture as TGA did not show
  265. // this offset. It turns out, this fixes the issue...? O.o --xythobuz
  266. // h += -texture->fontHeight/2-(texture->fontDescent + texture->glyphs[i].miny);
  267. h -= texture->fontHeight/2 + texture->fontDescent;
  268. /* Make a list for this TTF glyph, one nonuniform Quad per glyph */
  269. glNewList(font->drawListBase + i, GL_COMPILE);
  270. glBegin(GL_QUADS);
  271. glTexCoord2f(u2, v); /* Top, right */
  272. glVertex3i(texture->glyphs[i].w, h, 0);
  273. glTexCoord2f(u, v); /* Top, left */
  274. glVertex3i(0, h, 0);
  275. glTexCoord2f(u, v2); /* Bottom, left */
  276. glVertex3i(0, h+texture->glyphs[i].h, 0);
  277. glTexCoord2f(u2, v2); /* Bottom, right */
  278. glVertex3i(texture->glyphs[i].w, h+texture->glyphs[i].h, 0);
  279. glEnd();
  280. /* Move To The Left Of The Character */
  281. glTranslated(texture->glyphs[i].w + spacing, 0, 0);
  282. glEndList();
  283. }
  284. return font;
  285. }
  286. ttf_texture_t *Texture::generateFontTexture(const char *filename, int pointSize,
  287. unsigned int textureWidth,
  288. unsigned char color[3],
  289. unsigned int utf8Offset,
  290. unsigned int count,
  291. char verbose)
  292. {
  293. unsigned int i;
  294. int xx = 0, yy = 0, hh = 0, k, h, w, offset;
  295. unsigned char b;
  296. unsigned char *image;
  297. SDL_Surface* glyph;
  298. SDL_Color sdlColor;
  299. TTF_Font *font;
  300. ttf_texture_t *texture;
  301. FILE *f;
  302. sdlColor.r = color[0];
  303. sdlColor.g = color[1];
  304. sdlColor.b = color[2];
  305. if (!(mFlags & fUseSDL_TTF))
  306. {
  307. printf("SDL_TTF couldn't be used... exiting\n");
  308. return NULL;
  309. }
  310. if (pointSize < 8)
  311. {
  312. pointSize = 8;
  313. }
  314. /* Work around for TTF_OpenFont for file not found segfault */
  315. f = fopen(filename, "rb");
  316. if (!f)
  317. {
  318. printf("generateFontTexture> Couldn't load '%s'\n", filename);
  319. perror(filename);
  320. return NULL;
  321. }
  322. fclose(f);
  323. // Open the font file at the requested point size
  324. font = TTF_OpenFont(filename, pointSize);
  325. if (font == NULL)
  326. {
  327. fprintf(stderr, "generateFontTexture> Couldn't load %d pt font from %s: %s\n",
  328. pointSize, filename, SDL_GetError());
  329. return NULL;
  330. }
  331. // TTF_STYLE_NORMAL, TTF_STYLE_BOLD, TTF_STYLE_ITALIC, TTF_STYLE_UNDERLINE
  332. int renderStyle = TTF_STYLE_NORMAL;
  333. TTF_SetFontStyle(font, renderStyle);
  334. TTF_SetFontHinting(font, TTF_HINTING_LIGHT);
  335. /* Allocate a new TTF font texture */
  336. printf("Creating font texture from '%s'...\n", filename);
  337. texture = new ttf_texture_t;
  338. texture->width = textureWidth;
  339. texture->utf8Offset = utf8Offset;
  340. texture->count = count;
  341. texture->glyphs = new ttf_glyph_t[count];
  342. texture->texture = new unsigned char[textureWidth*textureWidth*4];
  343. memset(texture->texture, 0, textureWidth*textureWidth*4);
  344. texture->fontHeight = TTF_FontHeight(font);
  345. texture->fontAscent = TTF_FontAscent(font);
  346. texture->fontDescent = TTF_FontDescent(font);
  347. texture->fontSpacing = TTF_FontLineSkip(font);
  348. for (i = 0; i < count; ++i)
  349. {
  350. glyph = TTF_RenderGlyph_Blended(font, (Uint16)(i + utf8Offset), sdlColor);
  351. if (glyph)
  352. {
  353. image = (unsigned char*)glyph->pixels;
  354. TTF_GlyphMetrics(font, (Uint16)(i + utf8Offset),
  355. &texture->glyphs[i].minx, &texture->glyphs[i].maxx,
  356. &texture->glyphs[i].miny, &texture->glyphs[i].maxy,
  357. &texture->glyphs[i].advance);
  358. texture->glyphs[i].w = glyph->w;
  359. texture->glyphs[i].h = glyph->h;
  360. if (xx + texture->glyphs[i].w > ((int)textureWidth - 1))
  361. {
  362. yy += hh;
  363. hh = 2;
  364. xx = 2;
  365. texture->glyphs[i].x = 0;
  366. texture->glyphs[i].y = yy;
  367. }
  368. else
  369. {
  370. (texture->glyphs[i].h > hh) ? hh = texture->glyphs[i].h: 0;
  371. texture->glyphs[i].x = xx;
  372. texture->glyphs[i].y = yy;
  373. }
  374. xx += glyph->w;
  375. if (verbose)
  376. {
  377. printf("0x%x : %ix%i @ %i, %i\n", i + utf8Offset,
  378. texture->glyphs[i].w, texture->glyphs[i].h,
  379. texture->glyphs[i].x, texture->glyphs[i].y);
  380. }
  381. /* Blit @ xx, yy - in pixels */
  382. for (k = 0; k < glyph->w*glyph->h; ++k)
  383. {
  384. w = texture->glyphs[i].x + k%glyph->w;
  385. h = texture->glyphs[i].y + k/glyph->w;
  386. offset = (w + h*textureWidth);
  387. if (verbose)
  388. {
  389. printf("Offset: %i; Pixel: %i,%i; Data: 0x%08x\n",
  390. offset, w, h, *((unsigned int *)(void *)&image[k*4]));
  391. }
  392. /* 32-bit ARGB to RGBA */
  393. b = image[k*4+3];
  394. texture->texture[offset*4] = image[k*4] = image[k*4+1];
  395. texture->texture[offset*4+1] = image[k*4+1] = image[k*4+2];
  396. texture->texture[offset*4+2] = image[k*4+2] = image[k*4+3];
  397. texture->texture[offset*4+3] = image[k*4+3] = b;
  398. }
  399. }
  400. }
  401. TTF_CloseFont(font);
  402. return texture;
  403. }
  404. ////////////////////////////////////////////////////////////
  405. // Public Mutators
  406. ////////////////////////////////////////////////////////////
  407. int Texture::loadColorTexture(unsigned char rgba[4],
  408. unsigned int width, unsigned int height)
  409. {
  410. unsigned char *image;
  411. int id;
  412. image = generateColorTexture(rgba, width, height);
  413. id = loadBuffer(image, width, height, RGBA, 32);
  414. delete [] image;
  415. return id;
  416. }
  417. void Texture::initSDL_TTF()
  418. {
  419. // Initialize the TTF library
  420. if (TTF_Init() < 0)
  421. {
  422. fprintf(stderr, "initSDL_TTF> TTF_Init() failed!\n");
  423. fprintf(stderr, "initSDL_TTF> Error is [%s].\n", SDL_GetError());
  424. }
  425. else
  426. {
  427. mFlags |= fUseSDL_TTF;
  428. printf("Started SDL_TTF subsystem!\n");
  429. atexit(TTF_Quit);
  430. }
  431. }
  432. void Texture::setFlag(TextureFlag flag)
  433. {
  434. mFlags |= flag;
  435. }
  436. void Texture::clearFlag(TextureFlag flag)
  437. {
  438. mFlags |= flag;
  439. mFlags ^= flag;
  440. }
  441. void Texture::reset()
  442. {
  443. if (mTextureIds)
  444. {
  445. glDeleteTextures(mTextureLimit, mTextureIds);
  446. delete [] mTextureIds;
  447. }
  448. mTextureIds = 0x0;
  449. mTextureCount = 0;
  450. mTextureLimit = 0;
  451. }
  452. void Texture::disableMultiTexture()
  453. {
  454. mFlags ^= fUseMultiTexture;
  455. mTextureId = -1;
  456. mTextureId2 = -1;
  457. glDisable(GL_TEXTURE_2D);
  458. glActiveTextureARB(GL_TEXTURE0_ARB);
  459. }
  460. void Texture::useMultiTexture(float aU, float aV, float bU, float bV)
  461. {
  462. if (!(mFlags & fUseMultiTexture))
  463. return;
  464. glMultiTexCoord2fARB(GL_TEXTURE0_ARB, aU, aV);
  465. glMultiTexCoord2fARB(GL_TEXTURE1_ARB, bU, bV);
  466. }
  467. void Texture::useMultiTexture(float u, float v)
  468. {
  469. if (!(mFlags & fUseMultiTexture))
  470. return;
  471. glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v);
  472. glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, v);
  473. }
  474. void Texture::bindMultiTexture(int texture0, int texture1)
  475. {
  476. if (//(int)a == mTextureId && (int)b == mTextureId2 ||
  477. !mTextureIds ||
  478. texture0 < 0 || texture0 > (int)mTextureCount ||
  479. texture1 < 0 || texture1 > (int)mTextureCount)
  480. {
  481. return;
  482. }
  483. mFlags |= fUseMultiTexture;
  484. mTextureId = texture0;
  485. mTextureId2 = texture1;
  486. glActiveTextureARB(GL_TEXTURE0_ARB);
  487. glEnable(GL_TEXTURE_2D);
  488. glBindTexture(GL_TEXTURE_2D, mTextureIds[texture0]);
  489. glActiveTextureARB(GL_TEXTURE1_ARB);
  490. glEnable(GL_TEXTURE_2D);
  491. glBindTexture(GL_TEXTURE_2D, mTextureIds[texture1]);
  492. }
  493. void Texture::setMaxTextureCount(unsigned int n)
  494. {
  495. mTextureLimit = n;
  496. mTextureIds = new unsigned int[n];
  497. glGenTextures(n, mTextureIds);
  498. }
  499. int Texture::getTextureCount()
  500. {
  501. return (mTextureCount-1);
  502. }
  503. int Texture::loadBuffer(unsigned char *image,
  504. unsigned int width, unsigned int height,
  505. ColorMode mode, unsigned int bpp)
  506. {
  507. int id;
  508. id = loadBufferSlot(image, width, height, mode, bpp, mTextureCount++);
  509. if (id < 0)
  510. {
  511. return id;
  512. }
  513. return ++id;
  514. }
  515. void convertARGB32bppToRGBA32bpp(unsigned char *image,
  516. unsigned int w, unsigned int h)
  517. {
  518. unsigned int i, size = w*h;
  519. unsigned char swap;
  520. for (i = 0; i < size; ++i)
  521. {
  522. /* 32-bit ARGB to RGBA */
  523. swap = image[i*4+3];
  524. image[i*4] = image[i*4+1];
  525. image[i*4+1] = image[i*4+2];
  526. image[i*4+2] = image[i*4+3];
  527. image[i*4+3] = swap;
  528. }
  529. }
  530. // http://mmmovania.blogspot.de/2011/01/opengl-30-and-above-deprecated-func-and.html
  531. // http://www.g-truc.net/post-0256.html
  532. GLint deprecated_gluBuild2DMipmaps(GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data) {
  533. glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE);
  534. glTexImage2D(target, 0, internalFormat, width, height, 0, format, type, data);
  535. return 0;
  536. }
  537. int Texture::loadBufferSlot(unsigned char *image,
  538. unsigned int width, unsigned int height,
  539. ColorMode mode, unsigned int bpp,
  540. unsigned int slot)
  541. {
  542. unsigned char bytes;
  543. unsigned int glcMode;
  544. if (!mTextureIds || slot >= mTextureLimit)
  545. {
  546. printf("Texture::Load> ERROR Not initialized or out of free slots\n");
  547. return -1000;
  548. }
  549. if (!width || !height || !image)
  550. {
  551. printf("Texture::Load> ERROR Assertion 'image is valid' failed\n");
  552. return -1;
  553. }
  554. switch (mode)
  555. {
  556. case GREYSCALE:
  557. if (bpp != 8)
  558. {
  559. printf("Texture::Load> ERROR Unsupported GREYSCALE, %i bpp\n", bpp);
  560. return -2;
  561. }
  562. bytes = 1;
  563. glcMode = GL_LUMINANCE;
  564. break;
  565. case RGB:
  566. if (bpp != 24)
  567. {
  568. printf("Texture::Load> ERROR Unsupported RGB, %i bpp\n", bpp);
  569. return -2;
  570. }
  571. bytes = 3;
  572. glcMode = GL_RGB;
  573. break;
  574. case ARGB:
  575. if (bpp == 32)
  576. {
  577. convertARGB32bppToRGBA32bpp(image, width, height);
  578. }
  579. else
  580. {
  581. printf("Texture::Load> ERROR Unsupported ARGB, %i bpp\n", bpp);
  582. return -2;
  583. }
  584. bytes = 4;
  585. glcMode = GL_RGBA;
  586. break;
  587. case RGBA:
  588. if (bpp != 32)
  589. {
  590. printf("Texture::Load> ERROR Unsupported RGBA, %i bpp\n", bpp);
  591. return -2;
  592. }
  593. bytes = 4;
  594. glcMode = GL_RGBA;
  595. break;
  596. }
  597. glClearColor(0.0, 0.0, 0.0, 0.0);
  598. glEnable(GL_DEPTH_TEST);
  599. glShadeModel(GL_SMOOTH);
  600. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  601. glBindTexture(GL_TEXTURE_2D, mTextureIds[slot]);
  602. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  603. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  604. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  605. if (mFlags & fUseMipmaps)
  606. {
  607. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  608. GL_NEAREST_MIPMAP_LINEAR);
  609. //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  610. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  611. GL_LINEAR_MIPMAP_LINEAR);
  612. //gluBuild2DMipmaps(GL_TEXTURE_2D, bytes, width, height, glcMode, GL_UNSIGNED_BYTE, image);
  613. // gluBuild2DMipmaps is deprecated. Replacement by xythobuz
  614. deprecated_gluBuild2DMipmaps(GL_TEXTURE_2D, bytes, width, height, glcMode, GL_UNSIGNED_BYTE, image);
  615. }
  616. else
  617. {
  618. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  619. glTexImage2D(GL_TEXTURE_2D, 0, glcMode, width, height, 0,
  620. glcMode, GL_UNSIGNED_BYTE, image);
  621. }
  622. //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  623. return slot;
  624. }
  625. void Texture::bindTextureId(unsigned int n)
  626. {
  627. if ((int)n == mTextureId || !mTextureIds || n > mTextureCount)
  628. {
  629. return;
  630. }
  631. mTextureId = n;
  632. glEnable(GL_TEXTURE_2D);
  633. //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  634. glBindTexture(GL_TEXTURE_2D, mTextureIds[n]);
  635. }
  636. void Texture::glScreenShot(char *base, unsigned int width, unsigned int height) {
  637. FILE *f;
  638. int sz = width * height;
  639. unsigned char *image = new unsigned char[sz * 3];
  640. char filename[1024];
  641. static int count = 0;
  642. bool done = false;
  643. if (!image || !width || !height) {
  644. if (image)
  645. delete [] image;
  646. printf("glScreenShot> ERROR: Couldn't allocate image!\n");
  647. return;
  648. }
  649. // Don't overwrite files
  650. while (!done)
  651. {
  652. snprintf(filename, 1024, "%s-%04i.tga", base, count++);
  653. f = fopen(filename, "rb");
  654. if (f)
  655. fclose(f);
  656. else
  657. done = true;
  658. }
  659. // Capture frame buffer
  660. glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, image);
  661. tgaSaveFilename(image, width, height, 0, "%s", filename);
  662. printf("Took screenshot '%s'.\n", filename);
  663. delete [] image;
  664. }
  665. int Texture::loadTGA(const char *filename)
  666. {
  667. FILE *f;
  668. unsigned char *image = NULL;
  669. unsigned char *image2 = NULL;
  670. unsigned int w, h;
  671. char type;
  672. int id = -1;
  673. f = fopen(filename, "rb");
  674. if (!f)
  675. {
  676. perror("Couldn't load file");
  677. }
  678. else if (!tgaCheck(f))
  679. {
  680. tgaLoad(f, &image, &w, &h, &type);
  681. type += 2;
  682. image2 = scaleBuffer(image, w, h, (type == 4) ? 4 : 3);
  683. if (image2)
  684. {
  685. image = image2;
  686. w = h = 256;
  687. }
  688. if (image)
  689. {
  690. id = loadBuffer(image, w, h,
  691. (type == 4) ? RGBA : RGB,
  692. (type == 4) ? 32 : 24);
  693. delete [] image;
  694. }
  695. fclose(f);
  696. }
  697. if (id == -1)
  698. {
  699. printf("Texture::loadTGA> ERROR: Failed to load '%s'\n", filename);
  700. }
  701. return id;
  702. }
  703. ////////////////////////////////////////////////////////////
  704. // Private Accessors
  705. ////////////////////////////////////////////////////////////
  706. int Texture::nextPower(int seed)
  707. {
  708. int i;
  709. for(i = 1; i < seed; i *= 2)
  710. ;
  711. return i;
  712. }
  713. /* This code based off on gluScaleImage() */
  714. unsigned char *Texture::scaleBuffer(unsigned char *image,
  715. int width, int height,
  716. int components)
  717. {
  718. int i, j, k;
  719. float* tempin;
  720. float* tempout;
  721. float sx, sy;
  722. // int components = 3;
  723. unsigned char *timage;
  724. int original_height = height;
  725. int original_width = width;
  726. if (!image || !width || !height)
  727. {
  728. return NULL;
  729. }
  730. height = nextPower(height);
  731. width = nextPower(width);
  732. if (height > 256)
  733. height = 256;
  734. if (width > 256)
  735. width = 256;
  736. // Check to see if scaling is needed
  737. if (height == original_height && width == original_width)
  738. return NULL;
  739. //printf("%i\n", components);
  740. timage = new unsigned char[height * width * components];
  741. tempin = new float[original_width * original_height * components * sizeof(float)];
  742. tempout = new float[width * height * components * sizeof(float)];
  743. if (!tempout || !tempin || !timage)
  744. {
  745. if (tempout)
  746. delete [] tempout;
  747. if (tempin)
  748. delete [] tempin;
  749. if (timage)
  750. delete [] timage;
  751. printf("Oh shit out of memory!\n");
  752. return NULL;
  753. }
  754. // Copy user data to float format.
  755. for (i = 0; i < original_height * original_width * components; ++i)
  756. {
  757. tempin[i] = (float)image[i];
  758. }
  759. // Determine which filter to use by checking ratios.
  760. if (width > 1)
  761. {
  762. sx = (float)(original_width - 1) / (float)(width - 1);
  763. }
  764. else
  765. {
  766. sx = (float)(original_width - 1);
  767. }
  768. if (height > 1)
  769. {
  770. sy = (float)(original_height - 1) / (float) (height - 1);
  771. }
  772. else
  773. {
  774. sy = (float)(original_height - 1);
  775. }
  776. if (sx < 1.0 && sy < 1.0)
  777. {
  778. /* Magnify both width and height: use weighted sample of 4 pixels */
  779. int i0, i1, j0, j1;
  780. float alpha, beta;
  781. float* src00;
  782. float* src01;
  783. float* src10;
  784. float* src11;
  785. float s1, s2;
  786. float* dst;
  787. for(i = 0; i < height; ++i)
  788. {
  789. i0 = (int)(i * sy);
  790. i1 = i0 + 1;
  791. if (i1 >= original_height)
  792. {
  793. i1 = original_height - 1;
  794. }
  795. alpha = i * sy - i0;
  796. for (j = 0; j < width; ++j)
  797. {
  798. j0 = (int) (j * sx);
  799. j1 = j0 + 1;
  800. if (j1 >= original_width)
  801. {
  802. j1 = original_width - 1;
  803. }
  804. beta = j * sx - j0;
  805. /* Compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
  806. src00 = tempin + (i0 * original_width + j0) * components;
  807. src01 = tempin + (i0 * original_width + j1) * components;
  808. src10 = tempin + (i1 * original_width + j0) * components;
  809. src11 = tempin + (i1 * original_width + j1) * components;
  810. dst = tempout + (i * width + j) * components;
  811. for (k = 0; k < components; ++k)
  812. {
  813. s1 = *src00++ * (1.0f - beta) + *src01++ * beta;
  814. s2 = *src10++ * (1.0f - beta) + *src11++ * beta;
  815. *dst++ = s1 * (1.0f - alpha) + s2 * alpha;
  816. }
  817. }
  818. }
  819. }
  820. else
  821. {
  822. /* Shrink width and/or height: use an unweighted box filter */
  823. int i0, i1;
  824. int j0, j1;
  825. int ii, jj;
  826. float sum;
  827. float* dst;
  828. for (i = 0; i < height; ++i)
  829. {
  830. i0 = (int) (i * sy);
  831. i1 = i0 + 1;
  832. if (i1 >= original_height)
  833. {
  834. i1 = original_height - 1;
  835. }
  836. for (j = 0; j < width; ++j)
  837. {
  838. j0 = (int) (j * sx);
  839. j1 = j0 + 1;
  840. if (j1 >= original_width)
  841. {
  842. j1 = original_width - 1;
  843. }
  844. dst = tempout + (i * width + j) * components;
  845. /* Compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
  846. for (k = 0; k < components; ++k)
  847. {
  848. sum = 0.0;
  849. for (ii = i0; ii <= i1; ++ii)
  850. {
  851. for (jj = j0; jj <= j1; ++jj)
  852. {
  853. sum += *(tempin + (ii * original_width + jj)
  854. * components + k);
  855. }
  856. }
  857. sum /= ( j1 - j0 + 1 ) * ( i1 - i0 + 1 );
  858. *dst++ = sum;
  859. }
  860. }
  861. }
  862. }
  863. // Copy to our results.
  864. for( i = 0; i < height * width * components; ++i)
  865. {
  866. timage[i] = (unsigned char)tempout[i];
  867. }
  868. // Delete our temp buffers.
  869. delete[] tempin;
  870. delete[] tempout;
  871. delete[] image;
  872. return timage;
  873. }
  874. ////////////////////////////////////////////////////////////
  875. // Private Mutators
  876. ////////////////////////////////////////////////////////////