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

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