PageRenderTime 54ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/source/soil/SOIL.c

http://phoenixgl.googlecode.com/
C | 2034 lines | 1653 code | 40 blank | 341 comment | 323 complexity | 516373e57a159fc8e40b880cfd6e3f32 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. Jonathan Dummer
  3. 2007-07-26-10.36
  4. Simple OpenGL Image Library
  5. Public Domain
  6. using Sean Barret's stb_image as a base
  7. Thanks to:
  8. * Sean Barret - for the awesome stb_image
  9. * Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts
  10. * everybody at gamedev.net
  11. */
  12. #define SOIL_CHECK_FOR_GL_ERRORS 0
  13. #ifdef WIN32
  14. #ifndef WIN32_LEAN_AND_MEAN
  15. #define WIN32_LEAN_AND_MEAN
  16. #endif //ifndef
  17. #include <windows.h>
  18. #include <wingdi.h>
  19. #include <GL/gl.h>
  20. #elif defined(__APPLE__) || defined(__APPLE_CC__)
  21. /* I can't test this Apple stuff! */
  22. #include <OpenGL/gl.h>
  23. #include <Carbon/Carbon.h>
  24. #define APIENTRY
  25. #else
  26. #include <GL/gl.h>
  27. #include <GL/glx.h>
  28. #endif
  29. #include "SOIL.h"
  30. #include "stb_image_aug.h"
  31. #include "image_helper.h"
  32. #include "image_DXT.h"
  33. #include <stdlib.h>
  34. #include <string.h>
  35. /* error reporting */
  36. char *result_string_pointer = "SOIL initialized";
  37. /* for loading cube maps */
  38. enum{
  39. SOIL_CAPABILITY_UNKNOWN = -1,
  40. SOIL_CAPABILITY_NONE = 0,
  41. SOIL_CAPABILITY_PRESENT = 1
  42. };
  43. static int has_cubemap_capability = SOIL_CAPABILITY_UNKNOWN;
  44. int query_cubemap_capability( void );
  45. #define SOIL_TEXTURE_WRAP_R 0x8072
  46. #define SOIL_CLAMP_TO_EDGE 0x812F
  47. #define SOIL_NORMAL_MAP 0x8511
  48. #define SOIL_REFLECTION_MAP 0x8512
  49. #define SOIL_TEXTURE_CUBE_MAP 0x8513
  50. #define SOIL_TEXTURE_BINDING_CUBE_MAP 0x8514
  51. #define SOIL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
  52. #define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
  53. #define SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
  54. #define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
  55. #define SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
  56. #define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
  57. #define SOIL_PROXY_TEXTURE_CUBE_MAP 0x851B
  58. #define SOIL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
  59. /* for non-power-of-two texture */
  60. static int has_NPOT_capability = SOIL_CAPABILITY_UNKNOWN;
  61. int query_NPOT_capability( void );
  62. /* for texture rectangles */
  63. static int has_tex_rectangle_capability = SOIL_CAPABILITY_UNKNOWN;
  64. int query_tex_rectangle_capability( void );
  65. #define SOIL_TEXTURE_RECTANGLE_ARB 0x84F5
  66. #define SOIL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
  67. /* for using DXT compression */
  68. static int has_DXT_capability = SOIL_CAPABILITY_UNKNOWN;
  69. int query_DXT_capability( void );
  70. #define SOIL_RGB_S3TC_DXT1 0x83F0
  71. #define SOIL_RGBA_S3TC_DXT1 0x83F1
  72. #define SOIL_RGBA_S3TC_DXT3 0x83F2
  73. #define SOIL_RGBA_S3TC_DXT5 0x83F3
  74. typedef void (APIENTRY * P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid * data);
  75. P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC soilGlCompressedTexImage2D = NULL;
  76. unsigned int SOIL_direct_load_DDS(
  77. const char *filename,
  78. unsigned int reuse_texture_ID,
  79. int flags,
  80. int loading_as_cubemap );
  81. unsigned int SOIL_direct_load_DDS_from_memory(
  82. const unsigned char *const buffer,
  83. int buffer_length,
  84. unsigned int reuse_texture_ID,
  85. int flags,
  86. int loading_as_cubemap );
  87. /* other functions */
  88. unsigned int
  89. SOIL_internal_create_OGL_texture
  90. (
  91. const unsigned char *const data,
  92. int width, int height, int channels,
  93. unsigned int reuse_texture_ID,
  94. unsigned int flags,
  95. unsigned int opengl_texture_type,
  96. unsigned int opengl_texture_target,
  97. unsigned int texture_check_size_enum
  98. );
  99. /* and the code magic begins here [8^) */
  100. unsigned int
  101. SOIL_load_OGL_texture
  102. (
  103. const char *filename,
  104. int force_channels,
  105. unsigned int reuse_texture_ID,
  106. unsigned int flags,
  107. int* w,
  108. int* h
  109. )
  110. {
  111. /* variables */
  112. unsigned char* img;
  113. int width, height, channels;
  114. unsigned int tex_id;
  115. /* does the user want direct uploading of the image as a DDS file? */
  116. if( flags & SOIL_FLAG_DDS_LOAD_DIRECT )
  117. {
  118. /* 1st try direct loading of the image as a DDS file
  119. note: direct uploading will only load what is in the
  120. DDS file, no MIPmaps will be generated, the image will
  121. not be flipped, etc. */
  122. tex_id = SOIL_direct_load_DDS( filename, reuse_texture_ID, flags, 0 );
  123. if( tex_id )
  124. {
  125. /* hey, it worked!! */
  126. return tex_id;
  127. }
  128. }
  129. /* try to load the image */
  130. img = SOIL_load_image( filename, &width, &height, &channels, force_channels );
  131. /* channels holds the original number of channels, which may have been forced */
  132. if( (force_channels >= 1) && (force_channels <= 4) )
  133. {
  134. channels = force_channels;
  135. }
  136. if( NULL == img )
  137. {
  138. /* image loading failed */
  139. result_string_pointer = stbi_failure_reason();
  140. return 0;
  141. }
  142. /* OK, make it a texture! */
  143. tex_id = SOIL_internal_create_OGL_texture(
  144. img, width, height, channels,
  145. reuse_texture_ID, flags,
  146. GL_TEXTURE_2D, GL_TEXTURE_2D,
  147. GL_MAX_TEXTURE_SIZE );
  148. /* and nuke the image data */
  149. SOIL_free_image_data( img );
  150. /* Set the width and height */
  151. (*w) = width;
  152. (*h) = height;
  153. /* and return the handle, such as it is */
  154. return tex_id;
  155. }
  156. unsigned int
  157. SOIL_load_OGL_HDR_texture
  158. (
  159. const char *filename,
  160. int fake_HDR_format,
  161. int rescale_to_max,
  162. unsigned int reuse_texture_ID,
  163. unsigned int flags
  164. )
  165. {
  166. /* variables */
  167. unsigned char* img;
  168. int width, height, channels;
  169. unsigned int tex_id;
  170. /* no direct uploading of the image as a DDS file */
  171. /* error check */
  172. if( (fake_HDR_format != SOIL_HDR_RGBE) &&
  173. (fake_HDR_format != SOIL_HDR_RGBdivA) &&
  174. (fake_HDR_format != SOIL_HDR_RGBdivA2) )
  175. {
  176. result_string_pointer = "Invalid fake HDR format specified";
  177. return 0;
  178. }
  179. /* try to load the image (only the HDR type) */
  180. img = stbi_hdr_load_rgbe( filename, &width, &height, &channels, 4 );
  181. /* channels holds the original number of channels, which may have been forced */
  182. if( NULL == img )
  183. {
  184. /* image loading failed */
  185. result_string_pointer = stbi_failure_reason();
  186. return 0;
  187. }
  188. /* the load worked, do I need to convert it? */
  189. if( fake_HDR_format == SOIL_HDR_RGBdivA )
  190. {
  191. RGBE_to_RGBdivA( img, width, height, rescale_to_max );
  192. } else if( fake_HDR_format == SOIL_HDR_RGBdivA2 )
  193. {
  194. RGBE_to_RGBdivA2( img, width, height, rescale_to_max );
  195. }
  196. /* OK, make it a texture! */
  197. tex_id = SOIL_internal_create_OGL_texture(
  198. img, width, height, channels,
  199. reuse_texture_ID, flags,
  200. GL_TEXTURE_2D, GL_TEXTURE_2D,
  201. GL_MAX_TEXTURE_SIZE );
  202. /* and nuke the image data */
  203. SOIL_free_image_data( img );
  204. /* and return the handle, such as it is */
  205. return tex_id;
  206. }
  207. unsigned int
  208. SOIL_load_OGL_texture_from_memory
  209. (
  210. const unsigned char *const buffer,
  211. int buffer_length,
  212. int force_channels,
  213. unsigned int reuse_texture_ID,
  214. unsigned int flags
  215. )
  216. {
  217. /* variables */
  218. unsigned char* img;
  219. int width, height, channels;
  220. unsigned int tex_id;
  221. /* does the user want direct uploading of the image as a DDS file? */
  222. if( flags & SOIL_FLAG_DDS_LOAD_DIRECT )
  223. {
  224. /* 1st try direct loading of the image as a DDS file
  225. note: direct uploading will only load what is in the
  226. DDS file, no MIPmaps will be generated, the image will
  227. not be flipped, etc. */
  228. tex_id = SOIL_direct_load_DDS_from_memory(
  229. buffer, buffer_length,
  230. reuse_texture_ID, flags, 0 );
  231. if( tex_id )
  232. {
  233. /* hey, it worked!! */
  234. return tex_id;
  235. }
  236. }
  237. /* try to load the image */
  238. img = SOIL_load_image_from_memory(
  239. buffer, buffer_length,
  240. &width, &height, &channels,
  241. force_channels );
  242. /* channels holds the original number of channels, which may have been forced */
  243. if( (force_channels >= 1) && (force_channels <= 4) )
  244. {
  245. channels = force_channels;
  246. }
  247. if( NULL == img )
  248. {
  249. /* image loading failed */
  250. result_string_pointer = stbi_failure_reason();
  251. return 0;
  252. }
  253. /* OK, make it a texture! */
  254. tex_id = SOIL_internal_create_OGL_texture(
  255. img, width, height, channels,
  256. reuse_texture_ID, flags,
  257. GL_TEXTURE_2D, GL_TEXTURE_2D,
  258. GL_MAX_TEXTURE_SIZE );
  259. /* and nuke the image data */
  260. SOIL_free_image_data( img );
  261. /* and return the handle, such as it is */
  262. return tex_id;
  263. }
  264. unsigned int
  265. SOIL_load_OGL_cubemap
  266. (
  267. const char *x_pos_file,
  268. const char *x_neg_file,
  269. const char *y_pos_file,
  270. const char *y_neg_file,
  271. const char *z_pos_file,
  272. const char *z_neg_file,
  273. int force_channels,
  274. unsigned int reuse_texture_ID,
  275. unsigned int flags
  276. )
  277. {
  278. /* variables */
  279. unsigned char* img;
  280. int width, height, channels;
  281. unsigned int tex_id;
  282. /* error checking */
  283. if( (x_pos_file == NULL) ||
  284. (x_neg_file == NULL) ||
  285. (y_pos_file == NULL) ||
  286. (y_neg_file == NULL) ||
  287. (z_pos_file == NULL) ||
  288. (z_neg_file == NULL) )
  289. {
  290. result_string_pointer = "Invalid cube map files list";
  291. return 0;
  292. }
  293. /* capability checking */
  294. if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
  295. {
  296. result_string_pointer = "No cube map capability present";
  297. return 0;
  298. }
  299. /* 1st face: try to load the image */
  300. img = SOIL_load_image( x_pos_file, &width, &height, &channels, force_channels );
  301. /* channels holds the original number of channels, which may have been forced */
  302. if( (force_channels >= 1) && (force_channels <= 4) )
  303. {
  304. channels = force_channels;
  305. }
  306. if( NULL == img )
  307. {
  308. /* image loading failed */
  309. result_string_pointer = stbi_failure_reason();
  310. return 0;
  311. }
  312. /* upload the texture, and create a texture ID if necessary */
  313. tex_id = SOIL_internal_create_OGL_texture(
  314. img, width, height, channels,
  315. reuse_texture_ID, flags,
  316. SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_X,
  317. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  318. /* and nuke the image data */
  319. SOIL_free_image_data( img );
  320. /* continue? */
  321. if( tex_id != 0 )
  322. {
  323. /* 1st face: try to load the image */
  324. img = SOIL_load_image( x_neg_file, &width, &height, &channels, force_channels );
  325. /* channels holds the original number of channels, which may have been forced */
  326. if( (force_channels >= 1) && (force_channels <= 4) )
  327. {
  328. channels = force_channels;
  329. }
  330. if( NULL == img )
  331. {
  332. /* image loading failed */
  333. result_string_pointer = stbi_failure_reason();
  334. return 0;
  335. }
  336. /* upload the texture, but reuse the assigned texture ID */
  337. tex_id = SOIL_internal_create_OGL_texture(
  338. img, width, height, channels,
  339. tex_id, flags,
  340. SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X,
  341. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  342. /* and nuke the image data */
  343. SOIL_free_image_data( img );
  344. }
  345. /* continue? */
  346. if( tex_id != 0 )
  347. {
  348. /* 1st face: try to load the image */
  349. img = SOIL_load_image( y_pos_file, &width, &height, &channels, force_channels );
  350. /* channels holds the original number of channels, which may have been forced */
  351. if( (force_channels >= 1) && (force_channels <= 4) )
  352. {
  353. channels = force_channels;
  354. }
  355. if( NULL == img )
  356. {
  357. /* image loading failed */
  358. result_string_pointer = stbi_failure_reason();
  359. return 0;
  360. }
  361. /* upload the texture, but reuse the assigned texture ID */
  362. tex_id = SOIL_internal_create_OGL_texture(
  363. img, width, height, channels,
  364. tex_id, flags,
  365. SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y,
  366. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  367. /* and nuke the image data */
  368. SOIL_free_image_data( img );
  369. }
  370. /* continue? */
  371. if( tex_id != 0 )
  372. {
  373. /* 1st face: try to load the image */
  374. img = SOIL_load_image( y_neg_file, &width, &height, &channels, force_channels );
  375. /* channels holds the original number of channels, which may have been forced */
  376. if( (force_channels >= 1) && (force_channels <= 4) )
  377. {
  378. channels = force_channels;
  379. }
  380. if( NULL == img )
  381. {
  382. /* image loading failed */
  383. result_string_pointer = stbi_failure_reason();
  384. return 0;
  385. }
  386. /* upload the texture, but reuse the assigned texture ID */
  387. tex_id = SOIL_internal_create_OGL_texture(
  388. img, width, height, channels,
  389. tex_id, flags,
  390. SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
  391. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  392. /* and nuke the image data */
  393. SOIL_free_image_data( img );
  394. }
  395. /* continue? */
  396. if( tex_id != 0 )
  397. {
  398. /* 1st face: try to load the image */
  399. img = SOIL_load_image( z_pos_file, &width, &height, &channels, force_channels );
  400. /* channels holds the original number of channels, which may have been forced */
  401. if( (force_channels >= 1) && (force_channels <= 4) )
  402. {
  403. channels = force_channels;
  404. }
  405. if( NULL == img )
  406. {
  407. /* image loading failed */
  408. result_string_pointer = stbi_failure_reason();
  409. return 0;
  410. }
  411. /* upload the texture, but reuse the assigned texture ID */
  412. tex_id = SOIL_internal_create_OGL_texture(
  413. img, width, height, channels,
  414. tex_id, flags,
  415. SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z,
  416. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  417. /* and nuke the image data */
  418. SOIL_free_image_data( img );
  419. }
  420. /* continue? */
  421. if( tex_id != 0 )
  422. {
  423. /* 1st face: try to load the image */
  424. img = SOIL_load_image( z_neg_file, &width, &height, &channels, force_channels );
  425. /* channels holds the original number of channels, which may have been forced */
  426. if( (force_channels >= 1) && (force_channels <= 4) )
  427. {
  428. channels = force_channels;
  429. }
  430. if( NULL == img )
  431. {
  432. /* image loading failed */
  433. result_string_pointer = stbi_failure_reason();
  434. return 0;
  435. }
  436. /* upload the texture, but reuse the assigned texture ID */
  437. tex_id = SOIL_internal_create_OGL_texture(
  438. img, width, height, channels,
  439. tex_id, flags,
  440. SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
  441. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  442. /* and nuke the image data */
  443. SOIL_free_image_data( img );
  444. }
  445. /* and return the handle, such as it is */
  446. return tex_id;
  447. }
  448. unsigned int
  449. SOIL_load_OGL_cubemap_from_memory
  450. (
  451. const unsigned char *const x_pos_buffer,
  452. int x_pos_buffer_length,
  453. const unsigned char *const x_neg_buffer,
  454. int x_neg_buffer_length,
  455. const unsigned char *const y_pos_buffer,
  456. int y_pos_buffer_length,
  457. const unsigned char *const y_neg_buffer,
  458. int y_neg_buffer_length,
  459. const unsigned char *const z_pos_buffer,
  460. int z_pos_buffer_length,
  461. const unsigned char *const z_neg_buffer,
  462. int z_neg_buffer_length,
  463. int force_channels,
  464. unsigned int reuse_texture_ID,
  465. unsigned int flags
  466. )
  467. {
  468. /* variables */
  469. unsigned char* img;
  470. int width, height, channels;
  471. unsigned int tex_id;
  472. /* error checking */
  473. if( (x_pos_buffer == NULL) ||
  474. (x_neg_buffer == NULL) ||
  475. (y_pos_buffer == NULL) ||
  476. (y_neg_buffer == NULL) ||
  477. (z_pos_buffer == NULL) ||
  478. (z_neg_buffer == NULL) )
  479. {
  480. result_string_pointer = "Invalid cube map buffers list";
  481. return 0;
  482. }
  483. /* capability checking */
  484. if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
  485. {
  486. result_string_pointer = "No cube map capability present";
  487. return 0;
  488. }
  489. /* 1st face: try to load the image */
  490. img = SOIL_load_image_from_memory(
  491. x_pos_buffer, x_pos_buffer_length,
  492. &width, &height, &channels, force_channels );
  493. /* channels holds the original number of channels, which may have been forced */
  494. if( (force_channels >= 1) && (force_channels <= 4) )
  495. {
  496. channels = force_channels;
  497. }
  498. if( NULL == img )
  499. {
  500. /* image loading failed */
  501. result_string_pointer = stbi_failure_reason();
  502. return 0;
  503. }
  504. /* upload the texture, and create a texture ID if necessary */
  505. tex_id = SOIL_internal_create_OGL_texture(
  506. img, width, height, channels,
  507. reuse_texture_ID, flags,
  508. SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_X,
  509. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  510. /* and nuke the image data */
  511. SOIL_free_image_data( img );
  512. /* continue? */
  513. if( tex_id != 0 )
  514. {
  515. /* 1st face: try to load the image */
  516. img = SOIL_load_image_from_memory(
  517. x_neg_buffer, x_neg_buffer_length,
  518. &width, &height, &channels, force_channels );
  519. /* channels holds the original number of channels, which may have been forced */
  520. if( (force_channels >= 1) && (force_channels <= 4) )
  521. {
  522. channels = force_channels;
  523. }
  524. if( NULL == img )
  525. {
  526. /* image loading failed */
  527. result_string_pointer = stbi_failure_reason();
  528. return 0;
  529. }
  530. /* upload the texture, but reuse the assigned texture ID */
  531. tex_id = SOIL_internal_create_OGL_texture(
  532. img, width, height, channels,
  533. tex_id, flags,
  534. SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X,
  535. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  536. /* and nuke the image data */
  537. SOIL_free_image_data( img );
  538. }
  539. /* continue? */
  540. if( tex_id != 0 )
  541. {
  542. /* 1st face: try to load the image */
  543. img = SOIL_load_image_from_memory(
  544. y_pos_buffer, y_pos_buffer_length,
  545. &width, &height, &channels, force_channels );
  546. /* channels holds the original number of channels, which may have been forced */
  547. if( (force_channels >= 1) && (force_channels <= 4) )
  548. {
  549. channels = force_channels;
  550. }
  551. if( NULL == img )
  552. {
  553. /* image loading failed */
  554. result_string_pointer = stbi_failure_reason();
  555. return 0;
  556. }
  557. /* upload the texture, but reuse the assigned texture ID */
  558. tex_id = SOIL_internal_create_OGL_texture(
  559. img, width, height, channels,
  560. tex_id, flags,
  561. SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y,
  562. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  563. /* and nuke the image data */
  564. SOIL_free_image_data( img );
  565. }
  566. /* continue? */
  567. if( tex_id != 0 )
  568. {
  569. /* 1st face: try to load the image */
  570. img = SOIL_load_image_from_memory(
  571. y_neg_buffer, y_neg_buffer_length,
  572. &width, &height, &channels, force_channels );
  573. /* channels holds the original number of channels, which may have been forced */
  574. if( (force_channels >= 1) && (force_channels <= 4) )
  575. {
  576. channels = force_channels;
  577. }
  578. if( NULL == img )
  579. {
  580. /* image loading failed */
  581. result_string_pointer = stbi_failure_reason();
  582. return 0;
  583. }
  584. /* upload the texture, but reuse the assigned texture ID */
  585. tex_id = SOIL_internal_create_OGL_texture(
  586. img, width, height, channels,
  587. tex_id, flags,
  588. SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
  589. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  590. /* and nuke the image data */
  591. SOIL_free_image_data( img );
  592. }
  593. /* continue? */
  594. if( tex_id != 0 )
  595. {
  596. /* 1st face: try to load the image */
  597. img = SOIL_load_image_from_memory(
  598. z_pos_buffer, z_pos_buffer_length,
  599. &width, &height, &channels, force_channels );
  600. /* channels holds the original number of channels, which may have been forced */
  601. if( (force_channels >= 1) && (force_channels <= 4) )
  602. {
  603. channels = force_channels;
  604. }
  605. if( NULL == img )
  606. {
  607. /* image loading failed */
  608. result_string_pointer = stbi_failure_reason();
  609. return 0;
  610. }
  611. /* upload the texture, but reuse the assigned texture ID */
  612. tex_id = SOIL_internal_create_OGL_texture(
  613. img, width, height, channels,
  614. tex_id, flags,
  615. SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z,
  616. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  617. /* and nuke the image data */
  618. SOIL_free_image_data( img );
  619. }
  620. /* continue? */
  621. if( tex_id != 0 )
  622. {
  623. /* 1st face: try to load the image */
  624. img = SOIL_load_image_from_memory(
  625. z_neg_buffer, z_neg_buffer_length,
  626. &width, &height, &channels, force_channels );
  627. /* channels holds the original number of channels, which may have been forced */
  628. if( (force_channels >= 1) && (force_channels <= 4) )
  629. {
  630. channels = force_channels;
  631. }
  632. if( NULL == img )
  633. {
  634. /* image loading failed */
  635. result_string_pointer = stbi_failure_reason();
  636. return 0;
  637. }
  638. /* upload the texture, but reuse the assigned texture ID */
  639. tex_id = SOIL_internal_create_OGL_texture(
  640. img, width, height, channels,
  641. tex_id, flags,
  642. SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
  643. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  644. /* and nuke the image data */
  645. SOIL_free_image_data( img );
  646. }
  647. /* and return the handle, such as it is */
  648. return tex_id;
  649. }
  650. unsigned int
  651. SOIL_load_OGL_single_cubemap
  652. (
  653. const char *filename,
  654. const char face_order[6],
  655. int force_channels,
  656. unsigned int reuse_texture_ID,
  657. unsigned int flags
  658. )
  659. {
  660. /* variables */
  661. unsigned char* img;
  662. int width, height, channels, i;
  663. unsigned int tex_id = 0;
  664. /* error checking */
  665. if( filename == NULL )
  666. {
  667. result_string_pointer = "Invalid single cube map file name";
  668. return 0;
  669. }
  670. /* does the user want direct uploading of the image as a DDS file? */
  671. if( flags & SOIL_FLAG_DDS_LOAD_DIRECT )
  672. {
  673. /* 1st try direct loading of the image as a DDS file
  674. note: direct uploading will only load what is in the
  675. DDS file, no MIPmaps will be generated, the image will
  676. not be flipped, etc. */
  677. tex_id = SOIL_direct_load_DDS( filename, reuse_texture_ID, flags, 1 );
  678. if( tex_id )
  679. {
  680. /* hey, it worked!! */
  681. return tex_id;
  682. }
  683. }
  684. /* face order checking */
  685. for( i = 0; i < 6; ++i )
  686. {
  687. if( (face_order[i] != 'N') &&
  688. (face_order[i] != 'S') &&
  689. (face_order[i] != 'W') &&
  690. (face_order[i] != 'E') &&
  691. (face_order[i] != 'U') &&
  692. (face_order[i] != 'D') )
  693. {
  694. result_string_pointer = "Invalid single cube map face order";
  695. return 0;
  696. };
  697. }
  698. /* capability checking */
  699. if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
  700. {
  701. result_string_pointer = "No cube map capability present";
  702. return 0;
  703. }
  704. /* 1st off, try to load the full image */
  705. img = SOIL_load_image( filename, &width, &height, &channels, force_channels );
  706. /* channels holds the original number of channels, which may have been forced */
  707. if( (force_channels >= 1) && (force_channels <= 4) )
  708. {
  709. channels = force_channels;
  710. }
  711. if( NULL == img )
  712. {
  713. /* image loading failed */
  714. result_string_pointer = stbi_failure_reason();
  715. return 0;
  716. }
  717. /* now, does this image have the right dimensions? */
  718. if( (width != 6*height) &&
  719. (6*width != height) )
  720. {
  721. SOIL_free_image_data( img );
  722. result_string_pointer = "Single cubemap image must have a 6:1 ratio";
  723. return 0;
  724. }
  725. /* try the image split and create */
  726. tex_id = SOIL_create_OGL_single_cubemap(
  727. img, width, height, channels,
  728. face_order, reuse_texture_ID, flags
  729. );
  730. /* nuke the temporary image data and return the texture handle */
  731. SOIL_free_image_data( img );
  732. return tex_id;
  733. }
  734. unsigned int
  735. SOIL_load_OGL_single_cubemap_from_memory
  736. (
  737. const unsigned char *const buffer,
  738. int buffer_length,
  739. const char face_order[6],
  740. int force_channels,
  741. unsigned int reuse_texture_ID,
  742. unsigned int flags
  743. )
  744. {
  745. /* variables */
  746. unsigned char* img;
  747. int width, height, channels, i;
  748. unsigned int tex_id = 0;
  749. /* error checking */
  750. if( buffer == NULL )
  751. {
  752. result_string_pointer = "Invalid single cube map buffer";
  753. return 0;
  754. }
  755. /* does the user want direct uploading of the image as a DDS file? */
  756. if( flags & SOIL_FLAG_DDS_LOAD_DIRECT )
  757. {
  758. /* 1st try direct loading of the image as a DDS file
  759. note: direct uploading will only load what is in the
  760. DDS file, no MIPmaps will be generated, the image will
  761. not be flipped, etc. */
  762. tex_id = SOIL_direct_load_DDS_from_memory(
  763. buffer, buffer_length,
  764. reuse_texture_ID, flags, 1 );
  765. if( tex_id )
  766. {
  767. /* hey, it worked!! */
  768. return tex_id;
  769. }
  770. }
  771. /* face order checking */
  772. for( i = 0; i < 6; ++i )
  773. {
  774. if( (face_order[i] != 'N') &&
  775. (face_order[i] != 'S') &&
  776. (face_order[i] != 'W') &&
  777. (face_order[i] != 'E') &&
  778. (face_order[i] != 'U') &&
  779. (face_order[i] != 'D') )
  780. {
  781. result_string_pointer = "Invalid single cube map face order";
  782. return 0;
  783. };
  784. }
  785. /* capability checking */
  786. if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
  787. {
  788. result_string_pointer = "No cube map capability present";
  789. return 0;
  790. }
  791. /* 1st off, try to load the full image */
  792. img = SOIL_load_image_from_memory(
  793. buffer, buffer_length,
  794. &width, &height, &channels,
  795. force_channels );
  796. /* channels holds the original number of channels, which may have been forced */
  797. if( (force_channels >= 1) && (force_channels <= 4) )
  798. {
  799. channels = force_channels;
  800. }
  801. if( NULL == img )
  802. {
  803. /* image loading failed */
  804. result_string_pointer = stbi_failure_reason();
  805. return 0;
  806. }
  807. /* now, does this image have the right dimensions? */
  808. if( (width != 6*height) &&
  809. (6*width != height) )
  810. {
  811. SOIL_free_image_data( img );
  812. result_string_pointer = "Single cubemap image must have a 6:1 ratio";
  813. return 0;
  814. }
  815. /* try the image split and create */
  816. tex_id = SOIL_create_OGL_single_cubemap(
  817. img, width, height, channels,
  818. face_order, reuse_texture_ID, flags
  819. );
  820. /* nuke the temporary image data and return the texture handle */
  821. SOIL_free_image_data( img );
  822. return tex_id;
  823. }
  824. unsigned int
  825. SOIL_create_OGL_single_cubemap
  826. (
  827. const unsigned char *const data,
  828. int width, int height, int channels,
  829. const char face_order[6],
  830. unsigned int reuse_texture_ID,
  831. unsigned int flags
  832. )
  833. {
  834. /* variables */
  835. unsigned char* sub_img;
  836. int dw, dh, sz, i;
  837. unsigned int tex_id;
  838. /* error checking */
  839. if( data == NULL )
  840. {
  841. result_string_pointer = "Invalid single cube map image data";
  842. return 0;
  843. }
  844. /* face order checking */
  845. for( i = 0; i < 6; ++i )
  846. {
  847. if( (face_order[i] != 'N') &&
  848. (face_order[i] != 'S') &&
  849. (face_order[i] != 'W') &&
  850. (face_order[i] != 'E') &&
  851. (face_order[i] != 'U') &&
  852. (face_order[i] != 'D') )
  853. {
  854. result_string_pointer = "Invalid single cube map face order";
  855. return 0;
  856. };
  857. }
  858. /* capability checking */
  859. if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
  860. {
  861. result_string_pointer = "No cube map capability present";
  862. return 0;
  863. }
  864. /* now, does this image have the right dimensions? */
  865. if( (width != 6*height) &&
  866. (6*width != height) )
  867. {
  868. result_string_pointer = "Single cubemap image must have a 6:1 ratio";
  869. return 0;
  870. }
  871. /* which way am I stepping? */
  872. if( width > height )
  873. {
  874. dw = height;
  875. dh = 0;
  876. } else
  877. {
  878. dw = 0;
  879. dh = width;
  880. }
  881. sz = dw+dh;
  882. sub_img = (unsigned char *)malloc( sz*sz*channels );
  883. /* do the splitting and uploading */
  884. tex_id = reuse_texture_ID;
  885. for( i = 0; i < 6; ++i )
  886. {
  887. int x, y, idx = 0;
  888. unsigned int cubemap_target = 0;
  889. /* copy in the sub-image */
  890. for( y = i*dh; y < i*dh+sz; ++y )
  891. {
  892. for( x = i*dw*channels; x < (i*dw+sz)*channels; ++x )
  893. {
  894. sub_img[idx++] = data[y*width*channels+x];
  895. }
  896. }
  897. /* what is my texture target?
  898. remember, this coordinate system is
  899. LHS if viewed from inside the cube! */
  900. switch( face_order[i] )
  901. {
  902. case 'N':
  903. cubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z;
  904. break;
  905. case 'S':
  906. cubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
  907. break;
  908. case 'W':
  909. cubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X;
  910. break;
  911. case 'E':
  912. cubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_X;
  913. break;
  914. case 'U':
  915. cubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y;
  916. break;
  917. case 'D':
  918. cubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
  919. break;
  920. }
  921. /* upload it as a texture */
  922. tex_id = SOIL_internal_create_OGL_texture(
  923. sub_img, sz, sz, channels,
  924. tex_id, flags,
  925. SOIL_TEXTURE_CUBE_MAP,
  926. cubemap_target,
  927. SOIL_MAX_CUBE_MAP_TEXTURE_SIZE );
  928. }
  929. /* and nuke the image and sub-image data */
  930. SOIL_free_image_data( sub_img );
  931. /* and return the handle, such as it is */
  932. return tex_id;
  933. }
  934. unsigned int
  935. SOIL_create_OGL_texture
  936. (
  937. const unsigned char *const data,
  938. int width, int height, int channels,
  939. unsigned int reuse_texture_ID,
  940. unsigned int flags
  941. )
  942. {
  943. /* wrapper function for 2D textures */
  944. return SOIL_internal_create_OGL_texture(
  945. data, width, height, channels,
  946. reuse_texture_ID, flags,
  947. GL_TEXTURE_2D, GL_TEXTURE_2D,
  948. GL_MAX_TEXTURE_SIZE );
  949. }
  950. #if SOIL_CHECK_FOR_GL_ERRORS
  951. void check_for_GL_errors( const char *calling_location )
  952. {
  953. /* check for errors */
  954. GLenum err_code = glGetError();
  955. while( GL_NO_ERROR != err_code )
  956. {
  957. printf( "OpenGL Error @ %s: %i", calling_location, err_code );
  958. err_code = glGetError();
  959. }
  960. }
  961. #else
  962. void check_for_GL_errors( const char *calling_location )
  963. {
  964. /* no check for errors */
  965. }
  966. #endif
  967. unsigned int
  968. SOIL_internal_create_OGL_texture
  969. (
  970. const unsigned char *const data,
  971. int width, int height, int channels,
  972. unsigned int reuse_texture_ID,
  973. unsigned int flags,
  974. unsigned int opengl_texture_type,
  975. unsigned int opengl_texture_target,
  976. unsigned int texture_check_size_enum
  977. )
  978. {
  979. /* variables */
  980. unsigned char* img;
  981. unsigned int tex_id;
  982. unsigned int internal_texture_format = 0, original_texture_format = 0;
  983. int DXT_mode = SOIL_CAPABILITY_UNKNOWN;
  984. int max_supported_size;
  985. /* If the user wants to use the texture rectangle I kill a few flags */
  986. if( flags & SOIL_FLAG_TEXTURE_RECTANGLE )
  987. {
  988. /* well, the user asked for it, can we do that? */
  989. if( query_tex_rectangle_capability() == SOIL_CAPABILITY_PRESENT )
  990. {
  991. /* only allow this if the user in _NOT_ trying to do a cubemap! */
  992. if( opengl_texture_type == GL_TEXTURE_2D )
  993. {
  994. /* clean out the flags that cannot be used with texture rectangles */
  995. flags &= ~(
  996. SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS |
  997. SOIL_FLAG_TEXTURE_REPEATS
  998. );
  999. /* and change my target */
  1000. opengl_texture_target = SOIL_TEXTURE_RECTANGLE_ARB;
  1001. opengl_texture_type = SOIL_TEXTURE_RECTANGLE_ARB;
  1002. } else
  1003. {
  1004. /* not allowed for any other uses (yes, I'm looking at you, cubemaps!) */
  1005. flags &= ~SOIL_FLAG_TEXTURE_RECTANGLE;
  1006. }
  1007. } else
  1008. {
  1009. /* can't do it, and that is a breakable offense (uv coords use pixels instead of [0,1]!) */
  1010. result_string_pointer = "Texture Rectangle extension unsupported";
  1011. return 0;
  1012. }
  1013. }
  1014. /* create a copy the image data */
  1015. img = (unsigned char*)malloc( width*height*channels );
  1016. memcpy( img, data, width*height*channels );
  1017. /* does the user want me to invert the image? */
  1018. if( flags & SOIL_FLAG_INVERT_Y )
  1019. {
  1020. int i, j;
  1021. for( j = 0; j*2 < height; ++j )
  1022. {
  1023. int index1 = j * width * channels;
  1024. int index2 = (height - 1 - j) * width * channels;
  1025. for( i = width * channels; i > 0; --i )
  1026. {
  1027. unsigned char temp = img[index1];
  1028. img[index1] = img[index2];
  1029. img[index2] = temp;
  1030. ++index1;
  1031. ++index2;
  1032. }
  1033. }
  1034. }
  1035. /* does the user want me to scale the colors into the NTSC safe RGB range? */
  1036. if( flags & SOIL_FLAG_NTSC_SAFE_RGB )
  1037. {
  1038. scale_image_RGB_to_NTSC_safe( img, width, height, channels );
  1039. }
  1040. /* does the user want me to convert from straight to pre-multiplied alpha?
  1041. (and do we even _have_ alpha?) */
  1042. if( flags & SOIL_FLAG_MULTIPLY_ALPHA )
  1043. {
  1044. int i;
  1045. switch( channels )
  1046. {
  1047. case 2:
  1048. for( i = 0; i < 2*width*height; i += 2 )
  1049. {
  1050. img[i] = (img[i] * img[i+1] + 128) >> 8;
  1051. }
  1052. break;
  1053. case 4:
  1054. for( i = 0; i < 4*width*height; i += 4 )
  1055. {
  1056. img[i+0] = (img[i+0] * img[i+3] + 128) >> 8;
  1057. img[i+1] = (img[i+1] * img[i+3] + 128) >> 8;
  1058. img[i+2] = (img[i+2] * img[i+3] + 128) >> 8;
  1059. }
  1060. break;
  1061. default:
  1062. /* no other number of channels contains alpha data */
  1063. break;
  1064. }
  1065. }
  1066. /* if the user can't support NPOT textures, make sure we force the POT option */
  1067. if( (query_NPOT_capability() == SOIL_CAPABILITY_NONE) &&
  1068. !(flags & SOIL_FLAG_TEXTURE_RECTANGLE) )
  1069. {
  1070. /* add in the POT flag */
  1071. flags |= SOIL_FLAG_POWER_OF_TWO;
  1072. }
  1073. /* how large of a texture can this OpenGL implementation handle? */
  1074. /* texture_check_size_enum will be GL_MAX_TEXTURE_SIZE or SOIL_MAX_CUBE_MAP_TEXTURE_SIZE */
  1075. glGetIntegerv( texture_check_size_enum, &max_supported_size );
  1076. /* do I need to make it a power of 2? */
  1077. if(
  1078. (flags & SOIL_FLAG_POWER_OF_TWO) || /* user asked for it */
  1079. (flags & SOIL_FLAG_MIPMAPS) || /* need it for the MIP-maps */
  1080. (width > max_supported_size) || /* it's too big, (make sure it's */
  1081. (height > max_supported_size) ) /* 2^n for later down-sampling) */
  1082. {
  1083. int new_width = 1;
  1084. int new_height = 1;
  1085. while( new_width < width )
  1086. {
  1087. new_width *= 2;
  1088. }
  1089. while( new_height < height )
  1090. {
  1091. new_height *= 2;
  1092. }
  1093. /* still? */
  1094. if( (new_width != width) || (new_height != height) )
  1095. {
  1096. /* yep, resize */
  1097. unsigned char *resampled = (unsigned char*)malloc( channels*new_width*new_height );
  1098. up_scale_image(
  1099. img, width, height, channels,
  1100. resampled, new_width, new_height );
  1101. /* OJO this is for debug only! */
  1102. /*
  1103. SOIL_save_image( "\\showme.bmp", SOIL_SAVE_TYPE_BMP,
  1104. new_width, new_height, channels,
  1105. resampled );
  1106. */
  1107. /* nuke the old guy, then point it at the new guy */
  1108. SOIL_free_image_data( img );
  1109. img = resampled;
  1110. width = new_width;
  1111. height = new_height;
  1112. }
  1113. }
  1114. /* now, if it is too large... */
  1115. if( (width > max_supported_size) || (height > max_supported_size) )
  1116. {
  1117. /* I've already made it a power of two, so simply use the MIPmapping
  1118. code to reduce its size to the allowable maximum. */
  1119. unsigned char *resampled;
  1120. int reduce_block_x = 1, reduce_block_y = 1;
  1121. int new_width, new_height;
  1122. if( width > max_supported_size )
  1123. {
  1124. reduce_block_x = width / max_supported_size;
  1125. }
  1126. if( height > max_supported_size )
  1127. {
  1128. reduce_block_y = height / max_supported_size;
  1129. }
  1130. new_width = width / reduce_block_x;
  1131. new_height = height / reduce_block_y;
  1132. resampled = (unsigned char*)malloc( channels*new_width*new_height );
  1133. /* perform the actual reduction */
  1134. mipmap_image( img, width, height, channels,
  1135. resampled, reduce_block_x, reduce_block_y );
  1136. /* nuke the old guy, then point it at the new guy */
  1137. SOIL_free_image_data( img );
  1138. img = resampled;
  1139. width = new_width;
  1140. height = new_height;
  1141. }
  1142. /* does the user want us to use YCoCg color space? */
  1143. if( flags & SOIL_FLAG_CoCg_Y )
  1144. {
  1145. /* this will only work with RGB and RGBA images */
  1146. convert_RGB_to_YCoCg( img, width, height, channels );
  1147. /*
  1148. save_image_as_DDS( "CoCg_Y.dds", width, height, channels, img );
  1149. */
  1150. }
  1151. /* create the OpenGL texture ID handle
  1152. (note: allowing a forced texture ID lets me reload a texture) */
  1153. tex_id = reuse_texture_ID;
  1154. if( tex_id == 0 )
  1155. {
  1156. glGenTextures( 1, &tex_id );
  1157. }
  1158. check_for_GL_errors( "glGenTextures" );
  1159. /* Note: sometimes glGenTextures fails (usually no OpenGL context) */
  1160. if( tex_id )
  1161. {
  1162. /* and what type am I using as the internal texture format? */
  1163. switch( channels )
  1164. {
  1165. case 1:
  1166. original_texture_format = GL_LUMINANCE;
  1167. break;
  1168. case 2:
  1169. original_texture_format = GL_LUMINANCE_ALPHA;
  1170. break;
  1171. case 3:
  1172. original_texture_format = GL_RGB;
  1173. break;
  1174. case 4:
  1175. original_texture_format = GL_RGBA;
  1176. break;
  1177. }
  1178. internal_texture_format = original_texture_format;
  1179. /* does the user want me to, and can I, save as DXT? */
  1180. if( flags & SOIL_FLAG_COMPRESS_TO_DXT )
  1181. {
  1182. DXT_mode = query_DXT_capability();
  1183. if( DXT_mode == SOIL_CAPABILITY_PRESENT )
  1184. {
  1185. /* I can use DXT, whether I compress it or OpenGL does */
  1186. if( (channels & 1) == 1 )
  1187. {
  1188. /* 1 or 3 channels = DXT1 */
  1189. internal_texture_format = SOIL_RGB_S3TC_DXT1;
  1190. } else
  1191. {
  1192. /* 2 or 4 channels = DXT5 */
  1193. internal_texture_format = SOIL_RGBA_S3TC_DXT5;
  1194. }
  1195. }
  1196. }
  1197. /* bind an OpenGL texture ID */
  1198. glBindTexture( opengl_texture_type, tex_id );
  1199. check_for_GL_errors( "glBindTexture" );
  1200. /* upload the main image */
  1201. if( DXT_mode == SOIL_CAPABILITY_PRESENT )
  1202. {
  1203. /* user wants me to do the DXT conversion! */
  1204. int DDS_size;
  1205. unsigned char *DDS_data = NULL;
  1206. if( (channels & 1) == 1 )
  1207. {
  1208. /* RGB, use DXT1 */
  1209. DDS_data = convert_image_to_DXT1( img, width, height, channels, &DDS_size );
  1210. } else
  1211. {
  1212. /* RGBA, use DXT5 */
  1213. DDS_data = convert_image_to_DXT5( img, width, height, channels, &DDS_size );
  1214. }
  1215. if( DDS_data )
  1216. {
  1217. soilGlCompressedTexImage2D(
  1218. opengl_texture_target, 0,
  1219. internal_texture_format, width, height, 0,
  1220. DDS_size, DDS_data );
  1221. check_for_GL_errors( "glCompressedTexImage2D" );
  1222. SOIL_free_image_data( DDS_data );
  1223. /* printf( "Internal DXT compressor\n" ); */
  1224. } else
  1225. {
  1226. /* my compression failed, try the OpenGL driver's version */
  1227. glTexImage2D(
  1228. opengl_texture_target, 0,
  1229. internal_texture_format, width, height, 0,
  1230. original_texture_format, GL_UNSIGNED_BYTE, img );
  1231. check_for_GL_errors( "glTexImage2D" );
  1232. /* printf( "OpenGL DXT compressor\n" ); */
  1233. }
  1234. } else
  1235. {
  1236. /* user want OpenGL to do all the work! */
  1237. glTexImage2D(
  1238. opengl_texture_target, 0,
  1239. internal_texture_format, width, height, 0,
  1240. original_texture_format, GL_UNSIGNED_BYTE, img );
  1241. check_for_GL_errors( "glTexImage2D" );
  1242. /*printf( "OpenGL DXT compressor\n" ); */
  1243. }
  1244. /* are any MIPmaps desired? */
  1245. if( flags & SOIL_FLAG_MIPMAPS )
  1246. {
  1247. int MIPlevel = 1;
  1248. int MIPwidth = (width+1) / 2;
  1249. int MIPheight = (height+1) / 2;
  1250. unsigned char *resampled = (unsigned char*)malloc( channels*MIPwidth*MIPheight );
  1251. while( ((1<<MIPlevel) <= width) || ((1<<MIPlevel) <= height) )
  1252. {
  1253. /* do this MIPmap level */
  1254. mipmap_image(
  1255. img, width, height, channels,
  1256. resampled,
  1257. (1 << MIPlevel), (1 << MIPlevel) );
  1258. /* upload the MIPmaps */
  1259. if( DXT_mode == SOIL_CAPABILITY_PRESENT )
  1260. {
  1261. /* user wants me to do the DXT conversion! */
  1262. int DDS_size;
  1263. unsigned char *DDS_data = NULL;
  1264. if( (channels & 1) == 1 )
  1265. {
  1266. /* RGB, use DXT1 */
  1267. DDS_data = convert_image_to_DXT1(
  1268. resampled, MIPwidth, MIPheight, channels, &DDS_size );
  1269. } else
  1270. {
  1271. /* RGBA, use DXT5 */
  1272. DDS_data = convert_image_to_DXT5(
  1273. resampled, MIPwidth, MIPheight, channels, &DDS_size );
  1274. }
  1275. if( DDS_data )
  1276. {
  1277. soilGlCompressedTexImage2D(
  1278. opengl_texture_target, MIPlevel,
  1279. internal_texture_format, MIPwidth, MIPheight, 0,
  1280. DDS_size, DDS_data );
  1281. check_for_GL_errors( "glCompressedTexImage2D" );
  1282. SOIL_free_image_data( DDS_data );
  1283. } else
  1284. {
  1285. /* my compression failed, try the OpenGL driver's version */
  1286. glTexImage2D(
  1287. opengl_texture_target, MIPlevel,
  1288. internal_texture_format, MIPwidth, MIPheight, 0,
  1289. original_texture_format, GL_UNSIGNED_BYTE, resampled );
  1290. check_for_GL_errors( "glTexImage2D" );
  1291. }
  1292. } else
  1293. {
  1294. /* user want OpenGL to do all the work! */
  1295. glTexImage2D(
  1296. opengl_texture_target, MIPlevel,
  1297. internal_texture_format, MIPwidth, MIPheight, 0,
  1298. original_texture_format, GL_UNSIGNED_BYTE, resampled );
  1299. check_for_GL_errors( "glTexImage2D" );
  1300. }
  1301. /* prep for the next level */
  1302. ++MIPlevel;
  1303. MIPwidth = (MIPwidth + 1) / 2;
  1304. MIPheight = (MIPheight + 1) / 2;
  1305. }
  1306. SOIL_free_image_data( resampled );
  1307. /* instruct OpenGL to use the MIPmaps */
  1308. glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  1309. glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
  1310. check_for_GL_errors( "GL_TEXTURE_MIN/MAG_FILTER" );
  1311. } else
  1312. {
  1313. /* instruct OpenGL _NOT_ to use the MIPmaps */
  1314. glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  1315. glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  1316. check_for_GL_errors( "GL_TEXTURE_MIN/MAG_FILTER" );
  1317. }
  1318. /* does the user want clamping, or wrapping? */
  1319. if( flags & SOIL_FLAG_TEXTURE_REPEATS )
  1320. {
  1321. glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT );
  1322. glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT );
  1323. if( opengl_texture_type == SOIL_TEXTURE_CUBE_MAP )
  1324. {
  1325. /* SOIL_TEXTURE_WRAP_R is invalid if cubemaps aren't supported */
  1326. glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT );
  1327. }
  1328. check_for_GL_errors( "GL_TEXTURE_WRAP_*" );
  1329. } else
  1330. {
  1331. /* unsigned int clamp_mode = SOIL_CLAMP_TO_EDGE; */
  1332. unsigned int clamp_mode = GL_CLAMP;
  1333. glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode );
  1334. glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode );
  1335. if( opengl_texture_type == SOIL_TEXTURE_CUBE_MAP )
  1336. {
  1337. /* SOIL_TEXTURE_WRAP_R is invalid if cubemaps aren't supported */
  1338. glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode );
  1339. }
  1340. check_for_GL_errors( "GL_TEXTURE_WRAP_*" );
  1341. }
  1342. /* done */
  1343. result_string_pointer = "Image loaded as an OpenGL texture";
  1344. } else
  1345. {
  1346. /* failed */
  1347. result_string_pointer = "Failed to generate an OpenGL texture name; missing OpenGL context?";
  1348. }
  1349. SOIL_free_image_data( img );
  1350. return tex_id;
  1351. }
  1352. int
  1353. SOIL_save_screenshot
  1354. (
  1355. const char *filename,
  1356. int image_type,
  1357. int x, int y,
  1358. int width, int height
  1359. )
  1360. {
  1361. unsigned char *pixel_data;
  1362. int i, j;
  1363. int save_result;
  1364. /* error checks */
  1365. if( (width < 1) || (height < 1) )
  1366. {
  1367. result_string_pointer = "Invalid screenshot dimensions";
  1368. return 0;
  1369. }
  1370. if( (x < 0) || (y < 0) )
  1371. {
  1372. result_string_pointer = "Invalid screenshot location";
  1373. return 0;
  1374. }
  1375. if( filename == NULL )
  1376. {
  1377. result_string_pointer = "Invalid screenshot filename";
  1378. return 0;
  1379. }
  1380. /* Get the data from OpenGL */
  1381. pixel_data = (unsigned char*)malloc( 3*width*height );
  1382. glReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixel_data);
  1383. /* invert the image */
  1384. for( j = 0; j*2 < height; ++j )
  1385. {
  1386. int index1 = j * width * 3;
  1387. int index2 = (height - 1 - j) * width * 3;
  1388. for( i = width * 3; i > 0; --i )
  1389. {
  1390. unsigned char temp = pixel_data[index1];
  1391. pixel_data[index1] = pixel_data[index2];
  1392. pixel_data[index2] = temp;
  1393. ++index1;
  1394. ++index2;
  1395. }
  1396. }
  1397. /* save the image */
  1398. save_result = SOIL_save_image( filename, image_type, width, height, 3, pixel_data);
  1399. /* And free the memory */
  1400. SOIL_free_image_data( pixel_data );
  1401. return save_result;
  1402. }
  1403. unsigned char*
  1404. SOIL_load_image
  1405. (
  1406. const char *filename,
  1407. int *width, int *height, int *channels,
  1408. int force_channels
  1409. )
  1410. {
  1411. unsigned char *result = stbi_load( filename,
  1412. width, height, channels, force_channels );
  1413. if( result == NULL )
  1414. {
  1415. result_string_pointer = stbi_failure_reason();
  1416. } else
  1417. {
  1418. result_string_pointer = "Image loaded";
  1419. }
  1420. return result;
  1421. }
  1422. unsigned char*
  1423. SOIL_load_image_from_memory
  1424. (
  1425. const unsigned char *const buffer,
  1426. int buffer_length,
  1427. int *width, int *height, int *channels,
  1428. int force_channels
  1429. )
  1430. {
  1431. unsigned char *result = stbi_load_from_memory(
  1432. buffer, buffer_length,
  1433. width, height, channels,
  1434. force_channels );
  1435. if( result == NULL )
  1436. {
  1437. result_string_pointer = stbi_failure_reason();
  1438. } else
  1439. {
  1440. result_string_pointer = "Image loaded from memory";
  1441. }
  1442. return result;
  1443. }
  1444. int
  1445. SOIL_save_image
  1446. (
  1447. const char *filename,
  1448. int image_type,
  1449. int width, int height, int channels,
  1450. const unsigned char *const data
  1451. )
  1452. {
  1453. int save_result;
  1454. /* error check */
  1455. if( (width < 1) || (height < 1) ||
  1456. (channels < 1) || (channels > 4) ||
  1457. (data == NULL) ||
  1458. (filename == NULL) )
  1459. {
  1460. return 0;
  1461. }
  1462. if( image_type == SOIL_SAVE_TYPE_BMP )
  1463. {
  1464. save_result = stbi_write_bmp( filename,
  1465. width, height, channels, (void*)data );
  1466. } else
  1467. if( image_type == SOIL_SAVE_TYPE_TGA )
  1468. {
  1469. save_result = stbi_write_tga( filename,
  1470. width, height, channels, (void*)data );
  1471. } else
  1472. if( image_type == SOIL_SAVE_TYPE_DDS )
  1473. {
  1474. save_result = save_image_as_DDS( filename,
  1475. width, height, channels, (const unsigned char *const)data );
  1476. } else
  1477. {
  1478. save_result = 0;
  1479. }
  1480. if( save_result == 0 )
  1481. {
  1482. result_string_pointer = "Saving the image failed";
  1483. } else
  1484. {
  1485. result_string_pointer = "Image saved";
  1486. }
  1487. return save_result;
  1488. }
  1489. void
  1490. SOIL_free_image_data
  1491. (
  1492. unsigned char *img_data
  1493. )
  1494. {
  1495. free( (void*)img_data );
  1496. }
  1497. const char*
  1498. SOIL_last_result
  1499. (
  1500. void
  1501. )
  1502. {
  1503. return result_string_pointer;
  1504. }
  1505. unsigned int SOIL_direct_load_DDS_from_memory(
  1506. const unsigned char *const buffer,
  1507. int buffer_length,
  1508. unsigned int reuse_texture_ID,
  1509. int flags,
  1510. int loading_as_cubemap )
  1511. {
  1512. /* variables */
  1513. DDS_header header;
  1514. unsigned int buffer_index = 0;
  1515. unsigned int tex_ID = 0;
  1516. /* file reading variables */
  1517. unsigned int S3TC_type = 0;
  1518. unsigned char *DDS_data;
  1519. unsigned int DDS_main_size;
  1520. unsigned int DDS_full_size;
  1521. unsigned int width, height;
  1522. int mipmaps, cubemap, uncompressed, block_size = 16;
  1523. unsigned int flag;
  1524. unsigned int cf_target, ogl_target_start, ogl_target_end;
  1525. unsigned int opengl_texture_type;
  1526. int i;
  1527. /* 1st off, does the filename even exist? */
  1528. if( NULL == buffer )
  1529. {
  1530. /* we can't do it! */
  1531. result_string_pointer = "NULL buffer";
  1532. return 0;
  1533. }
  1534. if( buffer_length < sizeof( DDS_header ) )
  1535. {
  1536. /* we can't do it! */
  1537. result_string_pointer = "DDS file was too small to contain the DDS header";
  1538. return 0;
  1539. }
  1540. /* try reading in the header */
  1541. memcpy ( (void*)(&header), (const void *)buffer, sizeof( DDS_header ) );
  1542. buffer_index = sizeof( DDS_header );
  1543. /* guilty until proven innocent */
  1544. result_string_pointer = "Failed to read a known DDS header";
  1545. /* validate the header (warning, "goto"'s ahead, shield your eyes!!) */
  1546. flag = ('D'<<0)|('D'<<8)|('S'<<16)|(' '<<24);
  1547. if( header.dwMagic != flag ) {goto quick_exit;}
  1548. if( header.dwSize != 124 ) {goto quick_exit;}
  1549. /* I need all of these */
  1550. flag = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  1551. if( (header.dwFlags & flag) != flag ) {goto quick_exit;}
  1552. /* According to the MSDN spec, the dwFlags should contain
  1553. DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if
  1554. uncompressed. Some DDS writers do not conform to the
  1555. spec, so I need to make my reader more tolerant */
  1556. /* I need one of these */
  1557. flag = DDPF_FOURCC | DDPF_RGB;
  1558. if( (header.sPixelFormat.dwFlags & flag) == 0 ) {goto quick_exit;}
  1559. if( header.sPixelFormat.dwSize != 32 ) {goto quick_exit;}
  1560. if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) {goto quick_exit;}
  1561. /* make sure it is a type we can upload */
  1562. if( (header.sPixelFormat.dwFlags & DDPF_FOURCC) &&
  1563. !(
  1564. (header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24))) ||
  1565. (header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('3'<<24))) ||
  1566. (header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('5'<<24)))
  1567. ) )
  1568. {
  1569. goto quick_exit;
  1570. }
  1571. /* OK, validated the header, let's load the image data */
  1572. result_string_pointer = "DDS header loaded and validated";
  1573. width = header.dwWidth;
  1574. height = header.dwHeight;
  1575. uncompressed = 1 - (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC;
  1576. cubemap = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP;
  1577. if( uncompressed )
  1578. {
  1579. S3TC_type = GL_RGB;
  1580. block_size = 3;
  1581. if( header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS )
  1582. {
  1583. S3TC_type = GL_RGBA;
  1584. block_size = 4;
  1585. }
  1586. DDS_main_size = width * height * block_size;
  1587. } else
  1588. {
  1589. /* can we even handle direct uploading to OpenGL DXT compressed images? */
  1590. if( query_DXT_capability() != SOIL_CAPABILITY_PRESENT )
  1591. {
  1592. /* we can't do it! */
  1593. result_string_pointer = "Direct upload of S3TC images not supported by the OpenGL driver";
  1594. return 0;
  1595. }
  1596. /* well, we know it is DXT1/3/5, because we checked above */
  1597. switch( (header.sPixelFormat.dwFourCC >> 24) - '0' )
  1598. {
  1599. case 1:
  1600. S3TC_type = SOIL_RGBA_S3TC_DXT1;
  1601. block_size = 8;
  1602. break;
  1603. case 3:
  1604. S3TC_type = SOIL_RGBA_S3TC_DXT3;
  1605. block_size = 16;
  1606. break;
  1607. case 5:
  1608. S3TC_type = SOIL_RGBA_S3TC_DXT5;
  1609. block_size = 16;
  1610. break;
  1611. }
  1612. DDS_main_size = ((width+3)>>2)*((height+3)>>2)*block_size;
  1613. }
  1614. if( cubemap )
  1615. {
  1616. /* does the user want a cubemap? */
  1617. if( !loading_as_cubemap )
  1618. {
  1619. /* we can't do it! */
  1620. result_string_pointer = "DDS image was a cubemap";
  1621. return 0;
  1622. }
  1623. /* can we even handle cubemaps with the OpenGL driver? */
  1624. if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
  1625. {
  1626. /* we can't do it! */
  1627. result_string_pointer = "Direct upload of cubemap images not supported by the OpenGL driver";
  1628. return 0;
  1629. }
  1630. ogl_target_start = SOIL_TEXTURE_CUBE_MAP_POSITIVE_X;
  1631. ogl_target_end = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
  1632. opengl_texture_type = SOIL_TEXTURE_CUBE_MAP;
  1633. } else
  1634. {
  1635. /* does the user want a non-cubemap? */
  1636. if( loading_as_cubemap )
  1637. {
  1638. /* we can't do it! */
  1639. result_string_pointer = "DDS image was not a cubemap";
  1640. return 0;
  1641. }
  1642. ogl_target_start = GL_TEXTURE_2D;
  1643. ogl_target_end = GL_TEXTURE_2D;
  1644. opengl_texture_type = GL_TEXTURE_2D;
  1645. }
  1646. if( (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1) )
  1647. {
  1648. int shift_offset;
  1649. mipmaps = header.dwMipMapCount - 1;
  1650. DDS_full_size = DDS_main_size;
  1651. if( uncompressed )
  1652. {
  1653. /* uncompressed DDS, simple MIPmap size calculation */
  1654. shift_offset = 0;
  1655. } else
  1656. {
  1657. /* compressed DDS, MIPmap size calculation is block based */
  1658. shift_offset = 2;
  1659. }
  1660. for( i = 1; i <= mipmaps; ++ i )
  1661. {
  1662. int w, h;
  1663. w = width >> (shift_offset + i);
  1664. h = height >> (shift_offset + i);
  1665. if( w < 1 )
  1666. {
  1667. w = 1;
  1668. }
  1669. if( h < 1 )
  1670. {
  1671. h = 1;
  1672. }
  1673. DDS_full_size += w*h*block_size;
  1674. }
  1675. } else
  1676. {
  1677. mipmaps = 0;
  1678. DDS_full_size = DDS_main_size;
  1679. }
  1680. DDS_data = (unsigned char*)malloc( DDS_full_size );
  1681. /* got the image data RAM, create or use an existing OpenGL texture handle */
  1682. tex_ID = reuse_texture_ID;
  1683. if( tex_ID == 0 )
  1684. {
  1685. glGenTextures( 1, &tex_ID );
  1686. }
  1687. /* bind an OpenGL texture ID */
  1688. glBindTexture( opengl_texture_type, tex_ID );
  1689. /* do this for each face of the cubemap! */
  1690. for( cf_target = ogl_target_start; c

Large files files are truncated, but you can click here to view the full file