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

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