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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212
  1. /* -*- Mode: C++; tab-width: 3; indent-tabs-mode: t; c-basic-offset: 3 -*- */
  2. /*==========================================================================
  3. *
  4. * Project : Freyja, OpenRaider
  5. * Author : Terry 'Mongoose' Hendrix II
  6. * Website : http://www.westga.edu/~stu7440
  7. * Email : stu7440@westga.edu
  8. * Object : Texture
  9. * Comments: This is the Texture class.
  10. *
  11. * See file COPYING for license details.
  12. *
  13. *
  14. *-- History ----------------------------------------------------------
  15. *
  16. * 2003.06.30,
  17. * Mongoose - API update, SDL_TTF support moved here, misc features
  18. * SDL_TTF support based on Sam Lantinga's public domain
  19. * SDL_TTF demo functions and algorithms
  20. *
  21. * 2001.05.29:
  22. * Mongoose - Removed legacy code and done clean up
  23. *
  24. * 2001.02.19:
  25. * Mongoose - Moved from GooseEgg to mtk
  26. *
  27. * 2000.04.29:
  28. * Mongoose - Created from old PPM/PCX codebases I have done before
  29. ==========================================================================*/
  30. #include <string.h>
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include <stdarg.h>
  34. #ifdef DEBUG_MEMORY
  35. #include <memory_test.h>
  36. #endif
  37. #include <SDL2/SDL_ttf.h>
  38. #ifdef __APPLE__
  39. #include <OpenGL/gl.h>
  40. #include <OpenGL/glu.h>
  41. #else
  42. #include <GL/gl.h>
  43. #include <GL/glu.h>
  44. #endif
  45. #include <TGA.h>
  46. #include <Texture.h>
  47. //Texture *gTextureManager = 0x0;
  48. gl_font_t *gFontTest = 0x0;
  49. ////////////////////////////////////////////////////////////
  50. // Constructors
  51. ////////////////////////////////////////////////////////////
  52. Texture::Texture()
  53. {
  54. mTextureIds = NULL;
  55. mFlags = 0;
  56. mTextureId = -1;
  57. mTextureId2 = -1;
  58. mTextureCount = 0;
  59. mTextureLimit = 0;
  60. //gTextureManager = this;
  61. initSDL_TTF();
  62. }
  63. Texture::~Texture()
  64. {
  65. if (gFontTest)
  66. {
  67. glDeleteLists(gFontTest->drawListBase, gFontTest->count);
  68. delete gFontTest;
  69. }
  70. reset();
  71. }
  72. ////////////////////////////////////////////////////////////
  73. // Public Accessors
  74. ////////////////////////////////////////////////////////////
  75. unsigned char *Texture::generateColorTexture(unsigned char rgba[4],
  76. unsigned int width,
  77. unsigned int height)
  78. {
  79. unsigned char *image;
  80. unsigned int i, size;
  81. image = new unsigned char[height*width*4];
  82. for (i = 0, size = width*height; i < size; ++i)
  83. {
  84. /* RBGA */
  85. image[i*4] = rgba[0];
  86. image[i*4+1] = rgba[1];
  87. image[i*4+2] = rgba[2];
  88. image[i*4+3] = rgba[3];
  89. }
  90. return image;
  91. }
  92. void glEnterMode2d(unsigned int width, unsigned int height)
  93. {
  94. glPushAttrib(GL_ENABLE_BIT);
  95. glDisable(GL_DEPTH_TEST);
  96. glDisable(GL_CULL_FACE);
  97. glEnable(GL_TEXTURE_2D);
  98. /* This allows alpha blending of 2D textures with the scene */
  99. glEnable(GL_BLEND);
  100. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  101. glViewport(0, 0, width, height);
  102. glMatrixMode(GL_PROJECTION);
  103. glPushMatrix();
  104. glLoadIdentity();
  105. glOrtho(0.0, (GLdouble)width, (GLdouble)height, 0.0, 0.0, 1.0);
  106. glMatrixMode(GL_MODELVIEW);
  107. glPushMatrix();
  108. glLoadIdentity();
  109. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  110. }
  111. void glExitMode2d()
  112. {
  113. glMatrixMode(GL_MODELVIEW);
  114. glPopMatrix();
  115. glMatrixMode(GL_PROJECTION);
  116. glPopMatrix();
  117. glPopAttrib();
  118. glMatrixMode(GL_MODELVIEW);
  119. }
  120. void bufferedPrintf(char *string, unsigned int len, char *s, ...)
  121. {
  122. va_list args;
  123. if (s && s[0])
  124. {
  125. va_start(args, s);
  126. vsnprintf(string, len-1, s, args);
  127. string[len-1] = 0;
  128. va_end(args);
  129. }
  130. }
  131. void glPrint2d(float x, float y, float scale, char *string)
  132. {
  133. gl_font_t *font = gFontTest;
  134. if (!font)
  135. {
  136. static int errors = 0;
  137. if (errors < 10)
  138. printf("ERROR: glPrint2d failed, %i\n", ++errors);
  139. return;
  140. }
  141. glPushMatrix();
  142. glBindTexture(GL_TEXTURE_2D, font->textureId);
  143. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  144. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  145. glTranslatef(x, y, 0);
  146. glScalef(scale, scale, 1);
  147. /*! \fixme
  148. * Add utf-8 dencoding of char* string
  149. *
  150. * Also this string must be preprocessed to have glyph offsets
  151. * instead of ASCII text in it and support counts over 256 */
  152. glListBase(font->drawListBase - font->utf8Offset);
  153. glCallLists(strlen(string), GL_BYTE, string);
  154. glPopMatrix();
  155. }
  156. void glPrint3d(float x, float y, float z,
  157. float pitch, float yaw, float roll,
  158. float scale,
  159. char *string)
  160. {
  161. gl_font_t *font = gFontTest;
  162. if (!font)
  163. {
  164. static int errors = 0;
  165. if (errors < 10)
  166. printf("ERROR: glPrint3d failed, %i\n", ++errors);
  167. return;
  168. }
  169. glPushMatrix();
  170. glBindTexture(GL_TEXTURE_2D, font->textureId);
  171. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  172. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  173. glTranslatef(x, y, z);
  174. glRotatef(roll, 1, 0, 0);
  175. glRotatef(yaw, 0, 1, 0);
  176. glRotatef(pitch, 0, 0, 1);
  177. glScalef(scale, scale, scale);
  178. /*! \fixme
  179. * Add utf-8 dencoding of char* string
  180. *
  181. * Also this string must be preprocessed to have glyph offsets
  182. * instead of ASCII text in it and support counts over 256 */
  183. glListBase(font->drawListBase - font->utf8Offset);
  184. glCallLists(strlen(string), GL_BYTE, string);
  185. glPopMatrix();
  186. }
  187. int Texture::loadFontTTF(const char *filename,
  188. unsigned int utf8Offset, unsigned int count)
  189. {
  190. ttf_texture_t *texture;
  191. unsigned char rgb[3] = {0xff, 0xff, 0xff};
  192. if (!filename || !filename[0])
  193. {
  194. printf("fontTest> Passed bad filename\n");
  195. return -1;
  196. }
  197. texture = generateFontTexture(filename, 24, 256, rgb,
  198. //0x303f, 0x3093-0x303f, // hiragana
  199. //32, 126 - 32, // english
  200. utf8Offset, count,
  201. false);
  202. if (texture)
  203. {
  204. #ifdef DUMP_TTF_TGA
  205. FILE *f = fopen("ttf_font.tga", "wb");
  206. if (f)
  207. {
  208. tga_save(f, texture->texture, 256, 256, 4);
  209. fclose(f);
  210. }
  211. else
  212. {
  213. perror("ttf_font.tga");
  214. }
  215. #endif
  216. gFontTest = generateFont(texture);
  217. /*! \fixme Until UTF8 decoder is working, we map from
  218. ASCII when rendering */
  219. gFontTest->utf8Offset = 32; // hack to use ASCII strings to test unicode
  220. delete [] texture->texture;
  221. delete [] texture->glyphs;
  222. delete texture;
  223. return gFontTest->textureId;
  224. }
  225. else
  226. {
  227. return -2;
  228. }
  229. }
  230. gl_font_t *Texture::generateFont(ttf_texture_t *texture)
  231. {
  232. const float spacing = 4.0;
  233. unsigned int i;
  234. float u, v, u2, v2;
  235. int h;
  236. gl_font_t *font;
  237. if (!texture)
  238. return NULL;
  239. printf("Generating gl font from texture...\n");
  240. font = new gl_font_t;
  241. font->utf8Offset = texture->utf8Offset;
  242. font->count = texture->count;
  243. font->textureId = loadBuffer(texture->texture,
  244. texture->width, texture->width, RGBA, 32);
  245. glColor3f(1.0, 1.0, 1.0);
  246. font->drawListBase = glGenLists(texture->count);
  247. glBindTexture(GL_TEXTURE_2D, font->textureId);
  248. for (i = 0; i < texture->count; i++)
  249. {
  250. /* Generate texture coordinates for this TTF glyph */
  251. u = (float)texture->glyphs[i].x / (float)texture->width;
  252. v = (float)texture->glyphs[i].y / (float)texture->width;
  253. u2 = (((float)texture->glyphs[i].x + (float)texture->glyphs[i].w) /
  254. (float)texture->width);
  255. v2 = (((float)texture->glyphs[i].y + (float)texture->glyphs[i].h) /
  256. (float)texture->width);
  257. #ifdef DEBUG_TTF_OFFSET
  258. if (i+texture->utf8Offset == 'y' || i+texture->utf8Offset == 'x')
  259. {
  260. printf("%c: %i %i %i\n",
  261. i+texture->utf8Offset,
  262. texture->fontDescent,
  263. texture->glyphs[i].miny, texture->glyphs[i].maxy);
  264. }
  265. #endif
  266. if (texture->glyphs[i].h < texture->fontHeight)
  267. {
  268. h = texture->fontHeight - texture->glyphs[i].h;
  269. }
  270. else
  271. {
  272. h = 0;
  273. }
  274. h += -texture->fontHeight/2-(texture->fontDescent + texture->glyphs[i].miny);
  275. /* Make a list for this TTF glyph, one nonuniform Quad per glyph */
  276. glNewList(font->drawListBase + i, GL_COMPILE);
  277. glBegin(GL_QUADS);
  278. glTexCoord2f(u2, v); /* Top, right */
  279. glVertex3i(texture->glyphs[i].w, h, 0);
  280. glTexCoord2f(u, v); /* Top, left */
  281. glVertex3i(0, h, 0);
  282. glTexCoord2f(u, v2); /* Bottom, left */
  283. glVertex3i(0, h+texture->glyphs[i].h, 0);
  284. glTexCoord2f(u2, v2); /* Bottom, right */
  285. glVertex3i(texture->glyphs[i].w, h+texture->glyphs[i].h, 0);
  286. glEnd();
  287. /* Move To The Left Of The Character */
  288. glTranslated(texture->glyphs[i].w + spacing, 0, 0);
  289. glEndList();
  290. }
  291. return font;
  292. }
  293. ttf_texture_t *Texture::generateFontTexture(const char *filename, int pointSize,
  294. unsigned int textureWidth,
  295. unsigned char color[3],
  296. unsigned int utf8Offset,
  297. unsigned int count,
  298. char verbose)
  299. {
  300. unsigned int i;
  301. int xx = 0, yy = 0, hh = 0, k, h, w, offset;
  302. unsigned char b;
  303. unsigned char *image;
  304. SDL_Surface* glyph;
  305. SDL_Color sdlColor;
  306. TTF_Font *font;
  307. ttf_texture_t *texture;
  308. FILE *f;
  309. sdlColor.r = color[0];
  310. sdlColor.g = color[1];
  311. sdlColor.b = color[2];
  312. if (!(mFlags & fUseSDL_TTF))
  313. {
  314. printf("SDL_TTF couldn't be used... exiting\n");
  315. return NULL;
  316. }
  317. if (pointSize < 8)
  318. {
  319. pointSize = 8;
  320. }
  321. /* Work around for TTF_OpenFont for file not found segfault */
  322. f = fopen(filename, "rb");
  323. if (!f)
  324. {
  325. printf("generateFontTexture> Couldn't load '%s'\n", filename);
  326. perror(filename);
  327. return NULL;
  328. }
  329. fclose(f);
  330. // Open the font file at the requested point size
  331. font = TTF_OpenFont(filename, pointSize);
  332. if (font == NULL)
  333. {
  334. fprintf(stderr, "generateFontTexture> Couldn't load %d pt font from %s: %s\n",
  335. pointSize, filename, SDL_GetError());
  336. return NULL;
  337. }
  338. // TTF_STYLE_NORMAL, TTF_STYLE_BOLD, TTF_STYLE_ITALIC, TTF_STYLE_UNDERLINE
  339. int renderStyle = TTF_STYLE_NORMAL;
  340. TTF_SetFontStyle(font, renderStyle);
  341. /* Allocate a new TTF font texture */
  342. printf("Creating font texture from '%s'...\n", filename);
  343. texture = new ttf_texture_t;
  344. texture->width = textureWidth;
  345. texture->utf8Offset = utf8Offset;
  346. texture->count = count;
  347. texture->glyphs = new ttf_glyph_t[count];
  348. texture->texture = new unsigned char[textureWidth*textureWidth*4];
  349. memset(texture->texture, 0, textureWidth*textureWidth*4);
  350. texture->fontHeight = TTF_FontHeight(font);
  351. texture->fontAscent = TTF_FontAscent(font);
  352. texture->fontDescent = TTF_FontDescent(font);
  353. texture->fontSpacing = TTF_FontLineSkip(font);
  354. for (i = 0; i < count; ++i)
  355. {
  356. glyph = TTF_RenderGlyph_Blended(font, (Uint16)(i + utf8Offset), sdlColor);
  357. if (glyph)
  358. {
  359. image = (unsigned char*)glyph->pixels;
  360. TTF_GlyphMetrics(font, (Uint16)(i + utf8Offset),
  361. &texture->glyphs[i].minx, &texture->glyphs[i].maxx,
  362. &texture->glyphs[i].miny, &texture->glyphs[i].maxy,
  363. &texture->glyphs[i].advance);
  364. texture->glyphs[i].w = glyph->w;
  365. texture->glyphs[i].h = glyph->h;
  366. if (xx + texture->glyphs[i].w > ((int)textureWidth - 1))
  367. {
  368. yy += hh;
  369. hh = 2;
  370. xx = 2;
  371. texture->glyphs[i].x = 0;
  372. texture->glyphs[i].y = yy;
  373. }
  374. else
  375. {
  376. (texture->glyphs[i].h > hh) ? hh = texture->glyphs[i].h: 0;
  377. texture->glyphs[i].x = xx;
  378. texture->glyphs[i].y = yy;
  379. }
  380. xx += glyph->w;
  381. if (verbose)
  382. {
  383. printf("0x%x : %ix%i @ %i, %i\n", i + utf8Offset,
  384. texture->glyphs[i].w, texture->glyphs[i].h,
  385. texture->glyphs[i].x, texture->glyphs[i].y);
  386. }
  387. /* Blit @ xx, yy - in pixels */
  388. for (k = 0; k < glyph->w*glyph->h; ++k)
  389. {
  390. w = texture->glyphs[i].x + k%glyph->w;
  391. h = texture->glyphs[i].y + k/glyph->w;
  392. offset = (w + h*textureWidth);
  393. if (verbose)
  394. {
  395. printf("Offset: %i; Pixel: %i,%i; Data: 0x%08x\n",
  396. offset, w, h, *((unsigned int *)(void *)&image[k*4]));
  397. }
  398. /* 32-bit ARGB to RGBA */
  399. b = image[k*4+3];
  400. texture->texture[offset*4] = image[k*4] = image[k*4+1];
  401. texture->texture[offset*4+1] = image[k*4+1] = image[k*4+2];
  402. texture->texture[offset*4+2] = image[k*4+2] = image[k*4+3];
  403. texture->texture[offset*4+3] = image[k*4+3] = b;
  404. }
  405. }
  406. }
  407. TTF_CloseFont(font);
  408. return texture;
  409. }
  410. ////////////////////////////////////////////////////////////
  411. // Public Mutators
  412. ////////////////////////////////////////////////////////////
  413. int Texture::loadColorTexture(unsigned char rgba[4],
  414. unsigned int width, unsigned int height)
  415. {
  416. unsigned char *image;
  417. int id;
  418. image = generateColorTexture(rgba, width, height);
  419. id = loadBuffer(image, width, height, RGBA, 32);
  420. delete [] image;
  421. return id;
  422. }
  423. void Texture::initSDL_TTF()
  424. {
  425. // Initialize the TTF library
  426. if (TTF_Init() < 0)
  427. {
  428. fprintf(stderr, "initSDL_TTF> TTF_Init() failed!\n");
  429. fprintf(stderr, "initSDL_TTF> Error is [%s].\n", SDL_GetError());
  430. }
  431. else
  432. {
  433. mFlags |= fUseSDL_TTF;
  434. printf("Started SDL_TTF subsystem!\n");
  435. atexit(TTF_Quit);
  436. }
  437. }
  438. void Texture::setFlag(TextureFlag flag)
  439. {
  440. mFlags |= flag;
  441. }
  442. void Texture::clearFlag(TextureFlag flag)
  443. {
  444. mFlags |= flag;
  445. mFlags ^= flag;
  446. }
  447. void Texture::reset()
  448. {
  449. if (mTextureIds)
  450. {
  451. glDeleteTextures(mTextureLimit, mTextureIds);
  452. delete [] mTextureIds;
  453. }
  454. mTextureIds = 0x0;
  455. mTextureCount = 0;
  456. mTextureLimit = 0;
  457. }
  458. void Texture::disableMultiTexture()
  459. {
  460. mFlags ^= fUseMultiTexture;
  461. mTextureId = -1;
  462. mTextureId2 = -1;
  463. glDisable(GL_TEXTURE_2D);
  464. glActiveTextureARB(GL_TEXTURE0_ARB);
  465. }
  466. void Texture::useMultiTexture(float aU, float aV, float bU, float bV)
  467. {
  468. if (!(mFlags & fUseMultiTexture))
  469. return;
  470. glMultiTexCoord2fARB(GL_TEXTURE0_ARB, aU, aV);
  471. glMultiTexCoord2fARB(GL_TEXTURE1_ARB, bU, bV);
  472. }
  473. void Texture::useMultiTexture(float u, float v)
  474. {
  475. if (!(mFlags & fUseMultiTexture))
  476. return;
  477. glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v);
  478. glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, v);
  479. }
  480. void Texture::bindMultiTexture(int texture0, int texture1)
  481. {
  482. if (//(int)a == mTextureId && (int)b == mTextureId2 ||
  483. !mTextureIds ||
  484. texture0 < 0 || texture0 > (int)mTextureCount ||
  485. texture1 < 0 || texture1 > (int)mTextureCount)
  486. {
  487. return;
  488. }
  489. mFlags |= fUseMultiTexture;
  490. mTextureId = texture0;
  491. mTextureId2 = texture1;
  492. glActiveTextureARB(GL_TEXTURE0_ARB);
  493. glEnable(GL_TEXTURE_2D);
  494. glBindTexture(GL_TEXTURE_2D, mTextureIds[texture0]);
  495. glActiveTextureARB(GL_TEXTURE1_ARB);
  496. glEnable(GL_TEXTURE_2D);
  497. glBindTexture(GL_TEXTURE_2D, mTextureIds[texture1]);
  498. }
  499. void Texture::setMaxTextureCount(unsigned int n)
  500. {
  501. mTextureLimit = n;
  502. mTextureIds = new unsigned int[n];
  503. glGenTextures(n, mTextureIds);
  504. }
  505. int Texture::getTextureCount()
  506. {
  507. return (mTextureCount-1);
  508. }
  509. int Texture::loadBuffer(unsigned char *image,
  510. unsigned int width, unsigned int height,
  511. ColorMode mode, unsigned int bpp)
  512. {
  513. int id;
  514. id = loadBufferSlot(image, width, height, mode, bpp, mTextureCount++);
  515. if (id < 0)
  516. {
  517. return id;
  518. }
  519. return ++id;
  520. }
  521. void convertARGB32bppToRGBA32bpp(unsigned char *image,
  522. unsigned int w, unsigned int h)
  523. {
  524. unsigned int i, size = w*h;
  525. unsigned char swap;
  526. for (i = 0; i < size; ++i)
  527. {
  528. /* 32-bit ARGB to RGBA */
  529. swap = image[i*4+3];
  530. image[i*4] = image[i*4+1];
  531. image[i*4+1] = image[i*4+2];
  532. image[i*4+2] = image[i*4+3];
  533. image[i*4+3] = swap;
  534. }
  535. }
  536. GLint deprecated_gluBuild2DMipmaps(GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
  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. // http://mmmovania.blogspot.de/2011/01/opengl-30-and-above-deprecated-func-and.html
  626. // http://www.g-truc.net/post-0256.html
  627. GLint deprecated_gluBuild2DMipmaps(GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data) {
  628. glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE);
  629. glTexImage2D(target, 0, internalFormat, width, height, 0, format, type, data);
  630. return 0;
  631. }
  632. void Texture::bindTextureId(unsigned int n)
  633. {
  634. if ((int)n == mTextureId || !mTextureIds || n > mTextureCount)
  635. {
  636. return;
  637. }
  638. mTextureId = n;
  639. glEnable(GL_TEXTURE_2D);
  640. //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  641. glBindTexture(GL_TEXTURE_2D, mTextureIds[n]);
  642. }
  643. void Texture::glScreenShot(char *base, unsigned int width, unsigned int height)
  644. {
  645. FILE *f;
  646. int sz = width*height;
  647. unsigned char *image = new unsigned char[sz*3];
  648. unsigned char *swap_row = new unsigned char[width*3];
  649. char filename[1024];
  650. static int count = 0;
  651. bool done = false;
  652. int i, j, size;
  653. unsigned char comment_lenght;
  654. unsigned char colormap_type;
  655. unsigned char image_type;
  656. unsigned short colormap_index;
  657. unsigned short colormap_lenght;
  658. unsigned char colormap_bbp;
  659. unsigned short origin_x;
  660. unsigned short origin_y;
  661. unsigned short swidth;
  662. unsigned short sheight;
  663. char comment[32] = "Mongoose TGA 0.0.1\0";
  664. unsigned char tmp, bpp, desc_flags;
  665. if (!image || !width || !height)
  666. {
  667. if (image)
  668. {
  669. delete [] image;
  670. }
  671. delete [] swap_row;
  672. printf("glScreenShot> ERROR: Couldn't allocate image!\n");
  673. return;
  674. }
  675. // Don't overwrite files
  676. while (!done)
  677. {
  678. snprintf(filename, 1024, "%s-%04i.tga", base, count++);
  679. f = fopen(filename, "rb");
  680. if (f)
  681. fclose(f);
  682. else
  683. done = true;
  684. }
  685. f = fopen(filename, "wb");
  686. if (!f)
  687. {
  688. printf("glScreenShot> ERROR: Couldn't write screenshot.\n");
  689. perror("glScreenShot> ERROR: ");
  690. delete [] image;
  691. delete [] swap_row;
  692. return;
  693. }
  694. // Capture frame buffer
  695. glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
  696. // Flip vertical
  697. for (i = 0, j = (int)height-1; i < (int)height/2; ++i, --j)
  698. {
  699. memcpy(swap_row, &image[i*width*3], width*3);
  700. memcpy(&image[i*width*3], &image[j*width*3], width*3);
  701. memcpy(&image[j*width*3], swap_row, width*3);
  702. }
  703. delete [] swap_row;
  704. comment_lenght = (unsigned char)strlen(comment);
  705. colormap_type = 0;
  706. image_type = 2;
  707. colormap_index = 0;
  708. colormap_lenght = 0;
  709. colormap_bbp = 0;
  710. origin_x = origin_y = 0;
  711. swidth = (unsigned short)width;
  712. sheight = (unsigned short)height;
  713. bpp = 24;
  714. desc_flags = 32;
  715. // Write TGA header
  716. fwrite(&comment_lenght, 1, 1, f);
  717. fwrite(&colormap_type, 1, 1, f);
  718. fwrite(&image_type, 1, 1, f);
  719. fwrite(&colormap_index, 2, 1, f);
  720. fwrite(&colormap_lenght, 2, 1, f);
  721. fwrite(&colormap_bbp, 1, 1, f);
  722. fwrite(&origin_x, 2, 1, f);
  723. fwrite(&origin_y, 2, 1, f);
  724. fwrite(&swidth, 2, 1, f);
  725. fwrite(&sheight, 2, 1, f);
  726. fwrite(&bpp, 1, 1, f);
  727. fwrite(&desc_flags, 1, 1, f);
  728. // Write comment
  729. fwrite(&comment, 1, comment_lenght, f);
  730. size = width * height * 3;
  731. for (i = 0; i < size; i += 3)
  732. {
  733. tmp = image[i];
  734. image[i] = image[i + 2];
  735. image[i + 2] = tmp;
  736. }
  737. // Write image data
  738. if (fwrite(image, size, 1, f) < 1)
  739. {
  740. perror("glScreenShot> Disk write failed.\n");
  741. fclose(f);
  742. delete [] image;
  743. return;
  744. }
  745. fclose(f);
  746. delete [] image;
  747. printf("Took screenshot '%s'.\n", filename);
  748. }
  749. int Texture::loadTGA(const char *filename)
  750. {
  751. FILE *f;
  752. unsigned char *image = NULL;
  753. unsigned char *image2 = NULL;
  754. unsigned int w, h;
  755. char type;
  756. int id = -1;
  757. f = fopen(filename, "rb");
  758. if (!f)
  759. {
  760. perror("Couldn't load file");
  761. }
  762. else if (!tga_check(f))
  763. {
  764. tga_load(f, &image, &w, &h, &type);
  765. type += 2;
  766. image2 = scaleBuffer(image, w, h, (type == 4) ? 4 : 3);
  767. if (image2)
  768. {
  769. image = image2;
  770. w = h = 256;
  771. }
  772. if (image)
  773. {
  774. id = loadBuffer(image, w, h,
  775. (type == 4) ? RGBA : RGB,
  776. (type == 4) ? 32 : 24);
  777. delete [] image;
  778. }
  779. fclose(f);
  780. }
  781. if (id == -1)
  782. {
  783. printf("Texture::loadTGA> ERROR: Failed to load '%s'\n", filename);
  784. }
  785. return id;
  786. }
  787. ////////////////////////////////////////////////////////////
  788. // Private Accessors
  789. ////////////////////////////////////////////////////////////
  790. int Texture::nextPower(int seed)
  791. {
  792. int i;
  793. for(i = 1; i < seed; i *= 2)
  794. ;
  795. return i;
  796. }
  797. /* This code based off on gluScaleImage() */
  798. unsigned char *Texture::scaleBuffer(unsigned char *image,
  799. int width, int height,
  800. int components)
  801. {
  802. int i, j, k;
  803. float* tempin;
  804. float* tempout;
  805. float sx, sy;
  806. // int components = 3;
  807. unsigned char *timage;
  808. int original_height = height;
  809. int original_width = width;
  810. if (!image || !width || !height)
  811. {
  812. return NULL;
  813. }
  814. height = nextPower(height);
  815. width = nextPower(width);
  816. if (height > 256)
  817. height = 256;
  818. if (width > 256)
  819. width = 256;
  820. // Check to see if scaling is needed
  821. if (height == original_height && width == original_width)
  822. return NULL;
  823. //printf("%i\n", components);
  824. timage = new unsigned char[height * width * components];
  825. tempin = new float[original_width * original_height * components * sizeof(float)];
  826. tempout = new float[width * height * components * sizeof(float)];
  827. if (!tempout || !tempin || !timage)
  828. {
  829. if (tempout)
  830. delete [] tempout;
  831. if (tempin)
  832. delete [] tempin;
  833. if (timage)
  834. delete [] timage;
  835. printf("Oh shit out of memory!\n");
  836. return NULL;
  837. }
  838. // Copy user data to float format.
  839. for (i = 0; i < original_height * original_width * components; ++i)
  840. {
  841. tempin[i] = (float)image[i];
  842. }
  843. // Determine which filter to use by checking ratios.
  844. if (width > 1)
  845. {
  846. sx = (float)(original_width - 1) / (float)(width - 1);
  847. }
  848. else
  849. {
  850. sx = (float)(original_width - 1);
  851. }
  852. if (height > 1)
  853. {
  854. sy = (float)(original_height - 1) / (float) (height - 1);
  855. }
  856. else
  857. {
  858. sy = (float)(original_height - 1);
  859. }
  860. if (sx < 1.0 && sy < 1.0)
  861. {
  862. /* Magnify both width and height: use weighted sample of 4 pixels */
  863. int i0, i1, j0, j1;
  864. float alpha, beta;
  865. float* src00;
  866. float* src01;
  867. float* src10;
  868. float* src11;
  869. float s1, s2;
  870. float* dst;
  871. for(i = 0; i < height; ++i)
  872. {
  873. i0 = (int)(i * sy);
  874. i1 = i0 + 1;
  875. if (i1 >= original_height)
  876. {
  877. i1 = original_height - 1;
  878. }
  879. alpha = i * sy - i0;
  880. for (j = 0; j < width; ++j)
  881. {
  882. j0 = (int) (j * sx);
  883. j1 = j0 + 1;
  884. if (j1 >= original_width)
  885. {
  886. j1 = original_width - 1;
  887. }
  888. beta = j * sx - j0;
  889. /* Compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
  890. src00 = tempin + (i0 * original_width + j0) * components;
  891. src01 = tempin + (i0 * original_width + j1) * components;
  892. src10 = tempin + (i1 * original_width + j0) * components;
  893. src11 = tempin + (i1 * original_width + j1) * components;
  894. dst = tempout + (i * width + j) * components;
  895. for (k = 0; k < components; ++k)
  896. {
  897. s1 = *src00++ * (1.0f - beta) + *src01++ * beta;
  898. s2 = *src10++ * (1.0f - beta) + *src11++ * beta;
  899. *dst++ = s1 * (1.0f - alpha) + s2 * alpha;
  900. }
  901. }
  902. }
  903. }
  904. else
  905. {
  906. /* Shrink width and/or height: use an unweighted box filter */
  907. int i0, i1;
  908. int j0, j1;
  909. int ii, jj;
  910. float sum;
  911. float* dst;
  912. for (i = 0; i < height; ++i)
  913. {
  914. i0 = (int) (i * sy);
  915. i1 = i0 + 1;
  916. if (i1 >= original_height)
  917. {
  918. i1 = original_height - 1;
  919. }
  920. for (j = 0; j < width; ++j)
  921. {
  922. j0 = (int) (j * sx);
  923. j1 = j0 + 1;
  924. if (j1 >= original_width)
  925. {
  926. j1 = original_width - 1;
  927. }
  928. dst = tempout + (i * width + j) * components;
  929. /* Compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
  930. for (k = 0; k < components; ++k)
  931. {
  932. sum = 0.0;
  933. for (ii = i0; ii <= i1; ++ii)
  934. {
  935. for (jj = j0; jj <= j1; ++jj)
  936. {
  937. sum += *(tempin + (ii * original_width + jj)
  938. * components + k);
  939. }
  940. }
  941. sum /= ( j1 - j0 + 1 ) * ( i1 - i0 + 1 );
  942. *dst++ = sum;
  943. }
  944. }
  945. }
  946. }
  947. // Copy to our results.
  948. for( i = 0; i < height * width * components; ++i)
  949. {
  950. timage[i] = (unsigned char)tempout[i];
  951. }
  952. // Delete our temp buffers.
  953. delete[] tempin;
  954. delete[] tempout;
  955. delete[] image;
  956. return timage;
  957. }
  958. ////////////////////////////////////////////////////////////
  959. // Private Mutators
  960. ////////////////////////////////////////////////////////////