Source code of Windows XP (NT5)
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.

1188 lines
32 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: texture.c
  3. *
  4. * Texture handling functions
  5. *
  6. * Copyright (c) 1994 Microsoft Corporation
  7. *
  8. \**************************************************************************/
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <math.h>
  13. #include <sys/types.h>
  14. #include <time.h>
  15. #include <windows.h>
  16. #include <scrnsave.h>
  17. #include <commdlg.h>
  18. #include <GL/gl.h>
  19. #include "tk.h"
  20. #include "scrnsave.h" // for hMainInstance
  21. #include "sscommon.h"
  22. #include "texture.h"
  23. static int ProcessTexture( TEXTURE *pTex );
  24. static int ProcessTkTexture( TK_RGBImageRec *image, TEXTURE *pTex );
  25. static int VerifyTextureFile( TEXFILE *pTexFile );
  26. static int GetTexFileType( TEXFILE *pTexFile );
  27. static TEX_STRINGS gts = {0};
  28. BOOL gbTextureObjects = FALSE;
  29. static BOOL gbPalettedTexture = FALSE;
  30. static PFNGLCOLORTABLEEXTPROC pfnColorTableEXT;
  31. static PFNGLCOLORSUBTABLEEXTPROC pfnColorSubTableEXT;
  32. static BOOL gbEnableErrorMsgs = FALSE;
  33. /******************************Public*Routine******************************\
  34. *
  35. * ss_LoadTextureResourceStrings
  36. *
  37. * Load various messages and strings that are used in processing textures,
  38. * into global TEX_STRINGS structure
  39. *
  40. \**************************************************************************/
  41. BOOL
  42. ss_LoadTextureResourceStrings()
  43. {
  44. LPTSTR pszStr;
  45. // title for choose texture File dialog
  46. LoadString(hMainInstance, IDS_TEXTUREDIALOGTITLE, gts.szTextureDialogTitle,
  47. GEN_STRING_SIZE);
  48. LoadString(hMainInstance, IDS_BMP, gts.szBmp, GEN_STRING_SIZE);
  49. LoadString(hMainInstance, IDS_DOTBMP, gts.szDotBmp, GEN_STRING_SIZE);
  50. // szTextureFilter requires a little more work. Need to assemble the file
  51. // name filter string, which is composed of two strings separated by a NULL
  52. // and terminated with a double NULL.
  53. LoadString(hMainInstance, IDS_TEXTUREFILTER, gts.szTextureFilter,
  54. GEN_STRING_SIZE);
  55. pszStr = &gts.szTextureFilter[lstrlen(gts.szTextureFilter)+1];
  56. LoadString(hMainInstance, IDS_STARDOTBMP, pszStr, GEN_STRING_SIZE);
  57. pszStr += lstrlen(pszStr);
  58. *pszStr++ = TEXT(';');
  59. LoadString(hMainInstance, IDS_STARDOTRGB, pszStr, GEN_STRING_SIZE);
  60. pszStr += lstrlen(pszStr);
  61. pszStr++;
  62. *pszStr = TEXT('\0');
  63. LoadString(hMainInstance, IDS_WARNING, gts.szWarningMsg, MAX_PATH);
  64. LoadString(hMainInstance, IDS_SELECT_ANOTHER_BITMAP,
  65. gts.szSelectAnotherBitmapMsg, MAX_PATH );
  66. LoadString(hMainInstance, IDS_BITMAP_INVALID,
  67. gts.szBitmapInvalidMsg, MAX_PATH );
  68. LoadString(hMainInstance, IDS_BITMAP_SIZE,
  69. gts.szBitmapSizeMsg, MAX_PATH );
  70. // assumed here that all above calls loaded properly (mf: fix later)
  71. return TRUE;
  72. }
  73. /******************************Public*Routine******************************\
  74. *
  75. *
  76. \**************************************************************************/
  77. void
  78. ss_DisableTextureErrorMsgs()
  79. {
  80. gbEnableErrorMsgs = FALSE;
  81. }
  82. /******************************Public*Routine******************************\
  83. *
  84. * ss_LoadBMPTextureFile
  85. *
  86. * Loads a BMP file and prepares it for GL usage
  87. *
  88. \**************************************************************************/
  89. int
  90. ss_LoadBMPTextureFile( LPCTSTR pszBmpfile, TEXTURE *pTex )
  91. {
  92. TK_RGBImageRec *image = (TK_RGBImageRec *) NULL;
  93. #ifdef UNICODE
  94. image = tkDIBImageLoadAW( (char *) pszBmpfile, TRUE );
  95. #else
  96. image = tkDIBImageLoadAW( (char *) pszBmpfile, FALSE );
  97. #endif
  98. if( !image ) {
  99. return 0;
  100. }
  101. return ProcessTkTexture( image, pTex );
  102. }
  103. /******************************Public*Routine******************************\
  104. *
  105. * ss_LoadTextureFile
  106. *
  107. * Loads a BMP file and prepares it for GL usage
  108. *
  109. \**************************************************************************/
  110. int
  111. ss_LoadTextureFile( TEXFILE *pTexFile, TEXTURE *pTex )
  112. {
  113. TK_RGBImageRec *image = (TK_RGBImageRec *) NULL;
  114. LPTSTR pszBmpfile = pTexFile->szPathName;
  115. int type;
  116. LPTSTR pszStr;
  117. // Verify file / set type
  118. if( !(type = VerifyTextureFile( pTexFile )) )
  119. return 0;
  120. if( type == TEX_BMP ) {
  121. #ifdef UNICODE
  122. image = tkDIBImageLoadAW( (char *) pszBmpfile, TRUE );
  123. #else
  124. image = tkDIBImageLoadAW( (char *) pszBmpfile, FALSE );
  125. #endif
  126. } else {
  127. #ifdef UNICODE
  128. image = tkRGBImageLoadAW( (char *) pszBmpfile, TRUE );
  129. #else
  130. image = tkRGBImageLoadAW( (char *) pszBmpfile, FALSE );
  131. #endif
  132. }
  133. if( !image ) {
  134. return 0;
  135. }
  136. return ProcessTkTexture( image, pTex );
  137. }
  138. /******************************Public*Routine******************************\
  139. *
  140. * ss_LoadTextureResource
  141. *
  142. * Loads a BMP or RGB texture resource and prepares it for GL usage
  143. *
  144. \**************************************************************************/
  145. int
  146. ss_LoadTextureResource( TEX_RES *pTexRes, TEXTURE *pTex )
  147. {
  148. HMODULE ghmodule;
  149. HRSRC hr;
  150. HGLOBAL hg;
  151. LPVOID pv;
  152. LPCTSTR lpType;
  153. BOOL fLoaded = FALSE;
  154. ghmodule = GetModuleHandle(NULL);
  155. switch(pTexRes->type)
  156. {
  157. case TEX_RGB:
  158. lpType = MAKEINTRESOURCE(RT_RGB);
  159. break;
  160. case TEX_BMP:
  161. lpType = MAKEINTRESOURCE(RT_MYBMP);
  162. break;
  163. case TEX_A8:
  164. lpType = MAKEINTRESOURCE(RT_A8);
  165. break;
  166. }
  167. hr = FindResource(ghmodule, MAKEINTRESOURCE(pTexRes->name), lpType);
  168. if (hr == NULL)
  169. {
  170. goto EH_NotFound;
  171. }
  172. hg = LoadResource(ghmodule, hr);
  173. if (hg == NULL)
  174. {
  175. goto EH_FreeResource;
  176. }
  177. pv = (PSZ)LockResource(hg);
  178. if (pv == NULL)
  179. {
  180. goto EH_FreeResource;
  181. }
  182. switch(pTexRes->type)
  183. {
  184. case TEX_RGB:
  185. fLoaded = ss_RGBImageLoad( pv, pTex );
  186. break;
  187. case TEX_BMP:
  188. fLoaded = ss_DIBImageLoad( pv, pTex );
  189. break;
  190. case TEX_A8:
  191. fLoaded = ss_A8ImageLoad( pv, pTex );
  192. break;
  193. }
  194. EH_FreeResource:
  195. FreeResource(hr);
  196. EH_NotFound:
  197. if( !fLoaded ) {
  198. return 0;
  199. }
  200. return ProcessTexture( pTex );
  201. }
  202. /******************************Public*Routine******************************\
  203. *
  204. * ValidateTextureSize
  205. *
  206. * - Scales the texture to powers of 2
  207. *
  208. \**************************************************************************/
  209. static BOOL
  210. ValidateTextureSize( TEXTURE *pTex )
  211. {
  212. double xPow2, yPow2;
  213. int ixPow2, iyPow2;
  214. int xSize2, ySize2;
  215. float fxFact, fyFact;
  216. GLint glMaxTexDim;
  217. if( (pTex->width <= 0) || (pTex->height <= 0) ) {
  218. SS_WARNING( "ValidateTextureSize : invalid texture dimensions\n" );
  219. return FALSE;
  220. }
  221. pTex->origAspectRatio = (float) pTex->height / (float) pTex->width;
  222. glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim);
  223. if( glMaxTexDim <= 0 )
  224. return FALSE;
  225. if( pTex->format != GL_COLOR_INDEX ) {
  226. // We limit the max dimension here for performance reasons
  227. glMaxTexDim = min(256, glMaxTexDim);
  228. if (pTex->width <= glMaxTexDim)
  229. xPow2 = log((double)pTex->width) / log((double)2.0);
  230. else
  231. xPow2 = log((double)glMaxTexDim) / log((double)2.0);
  232. if (pTex->height <= glMaxTexDim)
  233. yPow2 = log((double)pTex->height) / log((double)2.0);
  234. else
  235. yPow2 = log((double)glMaxTexDim) / log((double)2.0);
  236. ixPow2 = (int)xPow2;
  237. iyPow2 = (int)yPow2;
  238. // Always scale to higher nearest power
  239. if (xPow2 != (double)ixPow2)
  240. ixPow2++;
  241. if (yPow2 != (double)iyPow2)
  242. iyPow2++;
  243. xSize2 = 1 << ixPow2;
  244. ySize2 = 1 << iyPow2;
  245. if (xSize2 != pTex->width ||
  246. ySize2 != pTex->height)
  247. {
  248. BYTE *pData;
  249. pData = (BYTE *) malloc(xSize2 * ySize2 * pTex->components * sizeof(BYTE));
  250. if (!pData) {
  251. SS_WARNING( "ValidateTextureSize : can't alloc pData\n" );
  252. return FALSE;
  253. }
  254. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  255. if( gluScaleImage(pTex->format, pTex->width, pTex->height,
  256. GL_UNSIGNED_BYTE, pTex->data,
  257. xSize2, ySize2, GL_UNSIGNED_BYTE,
  258. pData) )
  259. {
  260. // glu failure
  261. SS_WARNING( "ValidateTextureSize : gluScaleImage failure\n" );
  262. free(pData);
  263. return FALSE;
  264. }
  265. // set the new width,height,data
  266. pTex->width = xSize2;
  267. pTex->height = ySize2;
  268. free(pTex->data);
  269. pTex->data = pData;
  270. }
  271. } else { // paletted texture case
  272. //mf
  273. // paletted texture: must be power of 2 - but might need to enforce
  274. // here if not done in a8 load. Also have to check against
  275. // GL_MAX_TEXTURE_SIZE. Could then clip it to power of 2 size
  276. }
  277. return TRUE;
  278. }
  279. /******************************Public*Routine******************************\
  280. *
  281. * SetDefaultTextureParams
  282. *
  283. \**************************************************************************/
  284. static void
  285. SetDefaultTextureParams()
  286. {
  287. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  288. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  289. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  290. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  291. }
  292. /******************************Public*Routine******************************\
  293. *
  294. * ProcessTexture
  295. *
  296. * - Verifies texture size
  297. * - Fills out TEXTURE structure with required data
  298. * - Creates a texture object if extension exists
  299. *
  300. \**************************************************************************/
  301. static int
  302. ProcessTexture( TEXTURE *pTex )
  303. {
  304. // Enforce proper texture size (power of 2, etc.)
  305. if( !ValidateTextureSize( pTex ) )
  306. return 0;
  307. // if texturing objects available, init the object
  308. if( gbTextureObjects ) {
  309. glGenTextures( 1, &pTex->texObj );
  310. glBindTexture( GL_TEXTURE_2D, pTex->texObj );
  311. // Default attributes for texObj
  312. SetDefaultTextureParams();
  313. glTexImage2D( GL_TEXTURE_2D, 0, pTex->components,
  314. pTex->width, pTex->height, 0, pTex->format,
  315. GL_UNSIGNED_BYTE, pTex->data );
  316. if (gbPalettedTexture && pTex->pal != NULL)
  317. {
  318. pfnColorTableEXT(GL_TEXTURE_2D, GL_RGBA, pTex->pal_size,
  319. GL_BGRA_EXT, GL_UNSIGNED_BYTE, pTex->pal);
  320. }
  321. } else
  322. pTex->texObj = 0;
  323. return 1;
  324. }
  325. /******************************Public*Routine******************************\
  326. *
  327. * ProcessTkTexture
  328. *
  329. * Simple wrapper for ProcessTexture which fills out a TEXTURE
  330. * from a TK_RGBImageRec
  331. *
  332. * Frees the ImageRec if ProcessTexture succeeds
  333. *
  334. \**************************************************************************/
  335. static int
  336. ProcessTkTexture( TK_RGBImageRec *image, TEXTURE *pTex )
  337. {
  338. pTex->width = image->sizeX;
  339. pTex->height = image->sizeY;
  340. pTex->format = GL_RGB;
  341. pTex->components = 3;
  342. pTex->data = image->data;
  343. pTex->pal_size = 0;
  344. pTex->pal = NULL;
  345. if( ProcessTexture( pTex ) )
  346. {
  347. free(image);
  348. return 1;
  349. }
  350. else
  351. {
  352. return 0;
  353. }
  354. }
  355. /******************************Public*Routine******************************\
  356. *
  357. * ss_SetTexture
  358. *
  359. \**************************************************************************/
  360. void
  361. ss_SetTexture( TEXTURE *pTex )
  362. {
  363. if( pTex == NULL )
  364. return;
  365. if( gbTextureObjects && pTex->texObj ) {
  366. glBindTexture( GL_TEXTURE_2D, pTex->texObj );
  367. return;
  368. }
  369. glTexImage2D( GL_TEXTURE_2D, 0, pTex->components,
  370. pTex->width, pTex->height, 0, pTex->format,
  371. GL_UNSIGNED_BYTE, pTex->data );
  372. if (gbPalettedTexture && pTex->pal != NULL)
  373. {
  374. pfnColorTableEXT(GL_TEXTURE_2D, GL_RGBA, pTex->pal_size,
  375. GL_BGRA_EXT, GL_UNSIGNED_BYTE, pTex->pal);
  376. }
  377. }
  378. /******************************Public*Routine******************************\
  379. *
  380. * ss_CopyTexture
  381. *
  382. * Make a copy of a texture.
  383. *
  384. \**************************************************************************/
  385. BOOL
  386. ss_CopyTexture( TEXTURE *pTexDst, TEXTURE *pTexSrc )
  387. {
  388. int size;
  389. if( (pTexDst == NULL) || (pTexSrc == NULL) )
  390. return FALSE;
  391. *pTexDst = *pTexSrc;
  392. if( gbTextureObjects && pTexSrc->texObj ) {
  393. glGenTextures( 1, &pTexDst->texObj );
  394. }
  395. // copy image data
  396. size = pTexSrc->width * pTexSrc->height;
  397. if( pTexSrc->components != GL_COLOR_INDEX8_EXT )
  398. size *= pTexSrc->components; // since data format always UNSIGNED_BYTE
  399. pTexDst->data = (unsigned char *) malloc( size );
  400. if( pTexDst->pal == NULL )
  401. return FALSE;
  402. memcpy( pTexDst->data, pTexSrc->data, size );
  403. // copy palette data
  404. if( gbPalettedTexture && pTexSrc->pal != NULL )
  405. {
  406. size = pTexSrc->pal_size*sizeof(RGBQUAD);
  407. pTexDst->pal = (RGBQUAD *) malloc(size);
  408. if( pTexDst->pal == NULL )
  409. {
  410. free(pTexDst->data);
  411. return FALSE;
  412. }
  413. memcpy( pTexDst->pal, pTexSrc->pal, size );
  414. }
  415. if( gbTextureObjects ) {
  416. glBindTexture( GL_TEXTURE_2D, pTexDst->texObj );
  417. // Default attributes for texObj
  418. SetDefaultTextureParams();
  419. glTexImage2D( GL_TEXTURE_2D, 0, pTexDst->components,
  420. pTexDst->width, pTexDst->height, 0, pTexDst->format,
  421. GL_UNSIGNED_BYTE, pTexDst->data );
  422. if( gbPalettedTexture && (pTexDst->pal != NULL) )
  423. {
  424. pfnColorTableEXT(GL_TEXTURE_2D, GL_RGBA, pTexDst->pal_size,
  425. GL_BGRA_EXT, GL_UNSIGNED_BYTE, pTexDst->pal);
  426. }
  427. }
  428. return TRUE;
  429. }
  430. /******************************Public*Routine******************************\
  431. *
  432. * ss_SetTexturePalette
  433. *
  434. * Set a texture's palette according to the supplied index. This index
  435. * indicates the start of the palette, which then wraps around if necessary.
  436. * Of course this only works on paletted textures.
  437. *
  438. \**************************************************************************/
  439. void
  440. ss_SetTexturePalette( TEXTURE *pTex, int index )
  441. {
  442. if( pTex == NULL )
  443. return;
  444. if( gbTextureObjects )
  445. ss_SetTexture( pTex );
  446. if( gbPalettedTexture && pTex->pal != NULL )
  447. {
  448. int start, count;
  449. start = index & (pTex->pal_size - 1);
  450. count = pTex->pal_size - start;
  451. pfnColorSubTableEXT(GL_TEXTURE_2D, 0, count, GL_BGRA_EXT,
  452. GL_UNSIGNED_BYTE, pTex->pal + start);
  453. if (start != 0)
  454. {
  455. pfnColorSubTableEXT(GL_TEXTURE_2D, count, start, GL_BGRA_EXT,
  456. GL_UNSIGNED_BYTE, pTex->pal);
  457. }
  458. }
  459. }
  460. /******************************Public*Routine******************************\
  461. *
  462. * SetTextureAlpha
  463. *
  464. * Set a constant alpha value for the texture
  465. * Again, don't overwrite any existing 0 alpha values, as explained in
  466. * ss_SetTextureTransparency
  467. *
  468. \**************************************************************************/
  469. static void
  470. SetTextureAlpha( TEXTURE *pTex, float fAlpha )
  471. {
  472. int i;
  473. unsigned char *pData = pTex->data;
  474. RGBA8 *pColor = (RGBA8 *) pTex->data;
  475. BYTE bAlpha = (BYTE) (fAlpha * 255.0f);
  476. if( pTex->components != 4 )
  477. return;
  478. for( i = 0; i < pTex->width*pTex->height; i ++, pColor++ ) {
  479. if( pColor->a != 0 )
  480. pColor->a = bAlpha;
  481. }
  482. }
  483. /******************************Public*Routine******************************\
  484. *
  485. * ConvertTextureToRGBA
  486. *
  487. * Convert RGB texture to RGBA
  488. *
  489. \**************************************************************************/
  490. static void
  491. ConvertTextureToRGBA( TEXTURE *pTex, float fAlpha )
  492. {
  493. unsigned char *pNewData;
  494. int count = pTex->width * pTex->height;
  495. unsigned char *src, *dst;
  496. BYTE bAlpha = (BYTE) (fAlpha * 255.0f);
  497. int i;
  498. pNewData = (unsigned char *) LocalAlloc(LMEM_FIXED, count * sizeof(RGBA8));
  499. if( !pNewData )
  500. return;
  501. src = pTex->data;
  502. dst = pNewData;
  503. // Note: the color ordering is ABGR, where R is lsb
  504. for( i = 0; i < count; i ++ ) {
  505. *((RGB8 *)dst) = *((RGB8 *)src);
  506. dst += sizeof(RGB8);
  507. src += sizeof(RGB8);
  508. *dst++ = bAlpha;
  509. }
  510. LocalFree( pTex->data );
  511. pTex->data = pNewData;
  512. pTex->components = 4;
  513. pTex->format = GL_RGBA;
  514. }
  515. /******************************Public*Routine******************************\
  516. *
  517. * ss_SetTextureTransparency
  518. *
  519. * Set transparency for a texture by adding or modifying the alpha data.
  520. * Transparency value must be between 0.0 (opaque) and 1.0 (fully transparent)
  521. * If the texture data previously had no alpha, add it in.
  522. * If bSet is TRUE, make this the current texture.
  523. *
  524. * Note: Currently fully transparent pixels (alpha=0) will not be altered, since
  525. * it is assumed these should be permanently transparent (could make this an
  526. * option? - bPreserveTransparentPixels )
  527. *
  528. \**************************************************************************/
  529. BOOL
  530. ss_SetTextureTransparency( TEXTURE *pTex, float fTransp, BOOL bSet )
  531. {
  532. int i;
  533. float fAlpha;
  534. if( pTex == NULL )
  535. return FALSE;
  536. SS_CLAMP_TO_RANGE2( fTransp, 0.0f, 1.0f );
  537. fAlpha = 1 - fTransp;
  538. if( pTex->format == GL_COLOR_INDEX )
  539. {
  540. // just need to modify the palette
  541. RGBQUAD *pPal = pTex->pal;
  542. BYTE bAlpha = (BYTE) (fAlpha * 255.0f);
  543. if( !pPal )
  544. return FALSE;
  545. for( i = 0; i < pTex->pal_size; i ++, pPal++ ) {
  546. if( pPal->rgbReserved != 0 )
  547. pPal->rgbReserved = bAlpha;
  548. }
  549. // need to send down the new palette for texture objects
  550. if( gbTextureObjects && gbPalettedTexture )
  551. {
  552. glBindTexture( GL_TEXTURE_2D, pTex->texObj );
  553. pfnColorTableEXT(GL_TEXTURE_2D, GL_RGBA, pTex->pal_size,
  554. GL_BGRA_EXT, GL_UNSIGNED_BYTE, pTex->pal);
  555. }
  556. }
  557. else {
  558. // Need to setup new texture data
  559. if( pTex->components != 4 ) {
  560. // Make room for alpha component
  561. //mf: ? change to bAlpha ?
  562. ConvertTextureToRGBA( pTex, fAlpha );
  563. } else {
  564. // Set alpha component
  565. SetTextureAlpha( pTex, fAlpha );
  566. }
  567. // Send down new data if texture objects
  568. if( gbTextureObjects )
  569. {
  570. glBindTexture( GL_TEXTURE_2D, pTex->texObj );
  571. glTexImage2D( GL_TEXTURE_2D, 0, pTex->components,
  572. pTex->width, pTex->height, 0, pTex->format,
  573. GL_UNSIGNED_BYTE, pTex->data );
  574. }
  575. }
  576. if( bSet )
  577. ss_SetTexture( pTex );
  578. return TRUE;
  579. }
  580. /******************************Public*Routine******************************\
  581. *
  582. * ss_DeleteTexture
  583. *
  584. \**************************************************************************/
  585. void
  586. ss_DeleteTexture( TEXTURE *pTex )
  587. {
  588. if( pTex == NULL )
  589. return;
  590. if( gbTextureObjects && pTex->texObj ) {
  591. glDeleteTextures( 1, &pTex->texObj );
  592. pTex->texObj = 0;
  593. }
  594. if (pTex->pal != NULL)
  595. {
  596. free(pTex->pal);
  597. }
  598. if( pTex->data )
  599. free( pTex->data );
  600. }
  601. /******************************Public*Routine******************************\
  602. *
  603. * ss_TextureObjectsEnabled
  604. *
  605. * Returns BOOL set by ss_QueryGLVersion (Texture Objects only supported on
  606. * GL v.1.1 or greater)
  607. *
  608. \**************************************************************************/
  609. BOOL
  610. ss_TextureObjectsEnabled( void )
  611. {
  612. return gbTextureObjects;
  613. }
  614. /******************************Public*Routine******************************\
  615. *
  616. * ss_PalettedTextureEnabled
  617. *
  618. * Returns result from ss_QueryPalettedTextureEXT
  619. *
  620. \**************************************************************************/
  621. BOOL
  622. ss_PalettedTextureEnabled( void )
  623. {
  624. return gbPalettedTexture;
  625. }
  626. /******************************Public*Routine******************************\
  627. *
  628. * ss_QueryPalettedTextureEXT
  629. *
  630. * Queries the OpenGL implementation to see if paletted texture is supported
  631. * Typically called once at app startup.
  632. *
  633. \**************************************************************************/
  634. BOOL
  635. ss_QueryPalettedTextureEXT( void )
  636. {
  637. PFNGLGETCOLORTABLEPARAMETERIVEXTPROC pfnGetColorTableParameterivEXT;
  638. int size;
  639. pfnColorTableEXT = (PFNGLCOLORTABLEEXTPROC)
  640. wglGetProcAddress("glColorTableEXT");
  641. if (pfnColorTableEXT == NULL)
  642. return FALSE;
  643. pfnColorSubTableEXT = (PFNGLCOLORSUBTABLEEXTPROC)
  644. wglGetProcAddress("glColorSubTableEXT");
  645. if (pfnColorSubTableEXT == NULL)
  646. return FALSE;
  647. // Check color table size
  648. pfnGetColorTableParameterivEXT = (PFNGLGETCOLORTABLEPARAMETERIVEXTPROC)
  649. wglGetProcAddress("glGetColorTableParameterivEXT");
  650. if (pfnGetColorTableParameterivEXT == NULL)
  651. return FALSE;
  652. // For now, the only paletted textures supported in this lib are TEX_A8,
  653. // with 256 color table entries. Make sure the device supports this.
  654. pfnColorTableEXT(GL_PROXY_TEXTURE_2D, GL_RGBA, 256,
  655. GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL );
  656. pfnGetColorTableParameterivEXT( GL_PROXY_TEXTURE_2D,
  657. GL_COLOR_TABLE_WIDTH_EXT, &size );
  658. if( size != 256 )
  659. // The device does not support a color table size of 256, so we don't
  660. // enable paletted textures in general.
  661. return FALSE;
  662. return gbPalettedTexture=TRUE;
  663. }
  664. /******************************Public*Routine******************************\
  665. *
  666. * ss_VerifyTextureFile
  667. *
  668. * Validates texture bmp or rgb file, by checking for valid pathname and
  669. * correct format.
  670. *
  671. * History
  672. * Apr. 28, 95 : [marcfo]
  673. * - Wrote it
  674. *
  675. * Jul. 25, 95 : [marcfo]
  676. * - Suppress warning dialog box in child preview mode, as it will
  677. * be continuously brought up.
  678. *
  679. * Dec. 12, 95 : [marcfo]
  680. * - Support .rgb files as well
  681. *
  682. * Dec. 14, 95 : [marcfo]
  683. * - Change to have it only check the file path
  684. *
  685. \**************************************************************************/
  686. BOOL
  687. ss_VerifyTextureFile( TEXFILE *ptf )
  688. {
  689. // Make sure the selected texture file is OK.
  690. ISIZE size;
  691. TCHAR szFileName[MAX_PATH];
  692. PTSTR pszString;
  693. TCHAR szString[MAX_PATH];
  694. lstrcpy(szFileName, ptf->szPathName);
  695. if ( SearchPath(NULL, szFileName, NULL, MAX_PATH,
  696. ptf->szPathName, &pszString)
  697. )
  698. {
  699. ptf->nOffset = (int)((ULONG_PTR)(pszString - ptf->szPathName));
  700. return TRUE;
  701. }
  702. else
  703. {
  704. lstrcpy(ptf->szPathName, szFileName); // restore
  705. if( !ss_fOnWin95() && gbEnableErrorMsgs )
  706. {
  707. wsprintf(szString, gts.szSelectAnotherBitmapMsg, ptf->szPathName);
  708. MessageBox(NULL, szString, gts.szWarningMsg, MB_OK);
  709. }
  710. return FALSE;
  711. }
  712. }
  713. /******************************Public*Routine******************************\
  714. *
  715. * ss_SelectTextureFile
  716. *
  717. * Use the common dialog GetOpenFileName to get the name of a bitmap file
  718. * for use as a texture. This function will not return until the user
  719. * either selects a valid bitmap or cancels. If a valid bitmap is selected
  720. * by the user, the global array szPathName will have the full path
  721. * to the bitmap file and the global value nOffset will have the
  722. * offset from the beginning of szPathName to the pathless file name.
  723. *
  724. * If the user cancels, szPathName and nOffset will remain
  725. * unchanged.
  726. *
  727. * History:
  728. * 10-May-1994 -by- Gilman Wong [gilmanw]
  729. * - Wrote it.
  730. * Apr. 28, 95 : [marcfo]
  731. * - Modified for common use
  732. * Dec. 12, 95 : [marcfo]
  733. * - Support .rgb files as well
  734. *
  735. \**************************************************************************/
  736. BOOL
  737. ss_SelectTextureFile( HWND hDlg, TEXFILE *ptf )
  738. {
  739. OPENFILENAME ofn;
  740. TCHAR dirName[MAX_PATH];
  741. TEXFILE newTexFile;
  742. LPTSTR pszFileName = newTexFile.szPathName;
  743. TCHAR origPathName[MAX_PATH];
  744. PTSTR pszString;
  745. BOOL bTryAgain, bFileSelected;
  746. //mf:
  747. gbEnableErrorMsgs = TRUE;
  748. // Make a copy of the original file path name, so we can tell if
  749. // it changed or not
  750. lstrcpy( origPathName, ptf->szPathName );
  751. // Make dialog look nice by parsing out the initial path and
  752. // file name from the full pathname. If this isn't done, then
  753. // dialog has a long ugly name in the file combo box and
  754. // directory will end up with the default current directory.
  755. if (ptf->nOffset) {
  756. // Separate the directory and file names.
  757. lstrcpy(dirName, ptf->szPathName);
  758. dirName[ptf->nOffset-1] = L'\0';
  759. lstrcpy(pszFileName, &ptf->szPathName[ptf->nOffset]);
  760. }
  761. else {
  762. // If nOffset is zero, then szPathName is not a full path.
  763. // Attempt to make it a full path by calling SearchPath.
  764. if ( SearchPath(NULL, ptf->szPathName, NULL, MAX_PATH,
  765. dirName, &pszString) )
  766. {
  767. // Successful. Go ahead a change szPathName to the full path
  768. // and compute the filename offset.
  769. lstrcpy(ptf->szPathName, dirName);
  770. ptf->nOffset = (int)((ULONG_PTR)(pszString - dirName));
  771. // Break the filename and directory paths apart.
  772. dirName[ptf->nOffset-1] = TEXT('\0');
  773. lstrcpy(pszFileName, pszString);
  774. }
  775. // Give up and use the Windows system directory.
  776. else
  777. {
  778. GetWindowsDirectory(dirName, MAX_PATH);
  779. lstrcpy(pszFileName, ptf->szPathName);
  780. }
  781. }
  782. ofn.lStructSize = sizeof(OPENFILENAME);
  783. ofn.hwndOwner = hDlg;
  784. ofn.hInstance = NULL;
  785. ofn.lpstrFilter = gts.szTextureFilter;
  786. ofn.lpstrCustomFilter = (LPTSTR) NULL;
  787. ofn.nMaxCustFilter = 0;
  788. ofn.nFilterIndex = 1;
  789. ofn.lpstrFile = pszFileName;
  790. ofn.nMaxFile = MAX_PATH;
  791. ofn.lpstrFileTitle = (LPTSTR) NULL;
  792. ofn.nMaxFileTitle = 0;
  793. ofn.lpstrInitialDir = dirName;
  794. ofn.lpstrTitle = gts.szTextureDialogTitle;
  795. ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
  796. ofn.nFileOffset = 0;
  797. ofn.nFileExtension = 0;
  798. ofn.lpstrDefExt = gts.szBmp;
  799. ofn.lCustData = 0;
  800. ofn.lpfnHook = (LPOFNHOOKPROC) NULL;
  801. ofn.lpTemplateName = (LPTSTR) NULL;
  802. do {
  803. // Invoke the common file dialog. If it succeeds, then validate
  804. // the bitmap file. If not valid, make user try again until either
  805. // they pick a good one or cancel the dialog.
  806. bTryAgain = FALSE;
  807. if ( bFileSelected = GetOpenFileName(&ofn) ) {
  808. ISIZE size;
  809. newTexFile.nOffset = ofn.nFileOffset;
  810. if( VerifyTextureFile( &newTexFile ) ) {
  811. // copy in new file and offset
  812. *ptf = newTexFile;
  813. }
  814. else {
  815. bTryAgain = TRUE;
  816. }
  817. }
  818. // If need to try again, recompute dir and file name so dialog
  819. // still looks nice.
  820. if (bTryAgain && ofn.nFileOffset) {
  821. lstrcpy(dirName, pszFileName);
  822. dirName[ofn.nFileOffset-1] = L'\0';
  823. lstrcpy(pszFileName, &pszFileName[ofn.nFileOffset]);
  824. }
  825. } while (bTryAgain);
  826. gbEnableErrorMsgs = FALSE;
  827. if( bFileSelected ) {
  828. if( lstrcmpi( origPathName, ptf->szPathName ) )
  829. // a different file was selected
  830. return TRUE;
  831. }
  832. return FALSE;
  833. }
  834. /******************************Public*Routine******************************\
  835. *
  836. * ss_GetDefaultBmpFile
  837. *
  838. * Determine a default bitmap file to use for texturing, if none
  839. * exists yet in the registry.
  840. *
  841. * Put default in BmpFile parameter. DotBmp parameter is the bitmap
  842. * extension (usually .bmp).
  843. *
  844. * We have to synthesise the name from the ProductType registry entry.
  845. * Currently, this can be WinNT, LanmanNT, or Server. If it is
  846. * WinNT, the bitmap is winnt.bmp. If it is LanmanNT or Server,
  847. * the bitmap is lanmannt.bmp.
  848. *
  849. * History
  850. * Apr. 28, 95 : [marcfo]
  851. * - Wrote it
  852. *
  853. * Jul. 27, 95 : [marcfo]
  854. * - Added support for win95
  855. *
  856. * Apr. 23, 96 : [marcfo]
  857. * - Return NULL string for win95
  858. *
  859. \**************************************************************************/
  860. void
  861. ss_GetDefaultBmpFile( LPTSTR pszBmpFile )
  862. {
  863. HKEY hkey;
  864. LONG cjDefaultBitmap = MAX_PATH;
  865. if( ss_fOnWin95() )
  866. // There is no 'nice' bmp file on standard win95 installations
  867. lstrcpy( pszBmpFile, TEXT("") );
  868. else {
  869. if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  870. (LPCTSTR) TEXT("System\\CurrentControlSet\\Control\\ProductOptions"),
  871. 0,
  872. KEY_QUERY_VALUE,
  873. &hkey) == ERROR_SUCCESS )
  874. {
  875. if ( RegQueryValueEx(hkey,
  876. TEXT("ProductType"),
  877. (LPDWORD) NULL,
  878. (LPDWORD) NULL,
  879. (LPBYTE) pszBmpFile,
  880. (LPDWORD) &cjDefaultBitmap) == ERROR_SUCCESS
  881. && (cjDefaultBitmap / sizeof(TCHAR) + 4) <= MAX_PATH )
  882. lstrcat( pszBmpFile, gts.szDotBmp );
  883. else
  884. lstrcpy( pszBmpFile, TEXT("winnt.bmp") );
  885. RegCloseKey(hkey);
  886. }
  887. else
  888. lstrcpy( pszBmpFile, TEXT("winnt.bmp") );
  889. // If its not winnt.bmp, then its lanmannt.bmp. (This would be a lot
  890. // cleaner both in the screen savers and for usersrv desktop bitmap
  891. // initialization if the desktop bitmap name were stored in the
  892. // registry).
  893. if ( lstrcmpi( pszBmpFile, TEXT("winnt.bmp") ) != 0 )
  894. lstrcpy( pszBmpFile, TEXT("lanmannt.bmp") );
  895. }
  896. }
  897. /******************************Public*Routine******************************\
  898. *
  899. * VerifyTextureFile
  900. *
  901. * Verify that a bitmap or rgb file is valid
  902. *
  903. * Returns:
  904. * File type (RGB or BMP) if valid file; otherwise, 0.
  905. *
  906. * History
  907. * Dec. 12, 95 : [marcfo]
  908. * - Creation
  909. *
  910. \**************************************************************************/
  911. static int
  912. VerifyTextureFile( TEXFILE *pTexFile )
  913. {
  914. int type;
  915. ISIZE size;
  916. BOOL bValid;
  917. TCHAR szString[2 * MAX_PATH]; // May contain a pathname
  918. // check for 0 offset and null strings
  919. if( (pTexFile->nOffset == 0) || (*pTexFile->szPathName == 0) )
  920. return 0;
  921. type = GetTexFileType( pTexFile );
  922. switch( type ) {
  923. case TEX_BMP:
  924. bValid = bVerifyDIB( pTexFile->szPathName, &size );
  925. break;
  926. case TEX_RGB:
  927. bValid = bVerifyRGB( pTexFile->szPathName, &size );
  928. break;
  929. case TEX_UNKNOWN:
  930. default:
  931. bValid = FALSE;
  932. }
  933. if( !bValid ) {
  934. if( gbEnableErrorMsgs ) {
  935. wsprintf(szString, gts.szSelectAnotherBitmapMsg, pTexFile->szPathName);
  936. MessageBox(NULL, szString, gts.szWarningMsg, MB_OK);
  937. }
  938. return 0;
  939. }
  940. // Check size ?
  941. if ( (size.width > TEX_WIDTH_MAX) ||
  942. (size.height > TEX_HEIGHT_MAX) )
  943. {
  944. if( gbEnableErrorMsgs )
  945. {
  946. wsprintf(szString, gts.szBitmapSizeMsg,
  947. TEX_WIDTH_MAX, TEX_HEIGHT_MAX);
  948. MessageBox(NULL, szString, gts.szWarningMsg, MB_OK);
  949. }
  950. return 0;
  951. }
  952. return type;
  953. }
  954. /******************************Public*Routine******************************\
  955. *
  956. * ss_InitAutoTexture
  957. *
  958. * Generate texture coordinates automatically.
  959. * If pTexRep is not NULL, use it to set the repetition of the generated
  960. * texture.
  961. *
  962. \**************************************************************************/
  963. void
  964. ss_InitAutoTexture( TEX_POINT2D *pTexRep )
  965. {
  966. GLfloat sgenparams[] = {1.0f, 0.0f, 0.0f, 0.0f};
  967. GLfloat tgenparams[] = {0.0f, 1.0f, 0.0f, 0.0f};
  968. glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
  969. if( pTexRep )
  970. sgenparams[0] = pTexRep->s;
  971. glTexGenfv(GL_S, GL_OBJECT_PLANE, sgenparams );
  972. glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
  973. if( pTexRep )
  974. tgenparams[0] = pTexRep->t;
  975. glTexGenfv(GL_T, GL_OBJECT_PLANE, tgenparams );
  976. glEnable(GL_TEXTURE_GEN_S);
  977. glEnable(GL_TEXTURE_GEN_T);
  978. glEnable( GL_TEXTURE_2D );
  979. }
  980. /******************************Public*Routine******************************\
  981. *
  982. * GetTexFileType
  983. *
  984. * Determine if a texture file is rgb or bmp, based on extension. This is
  985. * good enough, as the open texture dialog only shows files with these
  986. * extensions.
  987. *
  988. \**************************************************************************/
  989. static int
  990. GetTexFileType( TEXFILE *pTexFile )
  991. {
  992. LPTSTR pszStr;
  993. #ifdef UNICODE
  994. pszStr = wcsrchr( pTexFile->szPathName + pTexFile->nOffset,
  995. (USHORT) L'.' );
  996. #else
  997. pszStr = strrchr( pTexFile->szPathName + pTexFile->nOffset,
  998. (USHORT) L'.' );
  999. #endif
  1000. if( !pszStr || (lstrlen(++pszStr) == 0) )
  1001. return TEX_UNKNOWN;
  1002. if( !lstrcmpi( pszStr, TEXT("bmp") ) )
  1003. return TEX_BMP;
  1004. else if( !lstrcmpi( pszStr, TEXT("rgb") ) )
  1005. return TEX_RGB;
  1006. else
  1007. return TEX_UNKNOWN;
  1008. }