SOIL.c 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042
  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. #define WIN32_LEAN_AND_MEAN
  15. #include <windows.h>
  16. #include <wingdi.h>
  17. #if 0
  18. #include <GL/gl.h>
  19. #endif
  20. #elif defined(__APPLE__) || defined(__APPLE_CC__)
  21. /* I can't test this Apple stuff! */
  22. #if 0
  23. #include <OpenGL/gl.h>
  24. #endif
  25. #include <Carbon/Carbon.h>
  26. #define APIENTRY
  27. #else
  28. #if 0
  29. #include <GL/gl.h>
  30. #include <GL/glx.h>
  31. #endif
  32. #endif
  33. #include "SOIL.h"
  34. #include "stb_image_aug.h"
  35. #include "image_helper.h"
  36. #include "image_DXT.h"
  37. #include <stdlib.h>
  38. #include <string.h>
  39. /* error reporting */
  40. const char *result_string_pointer = "SOIL initialized";
  41. /* for loading cube maps */
  42. enum{
  43. SOIL_CAPABILITY_UNKNOWN = -1,
  44. SOIL_CAPABILITY_NONE = 0,
  45. SOIL_CAPABILITY_PRESENT = 1
  46. };
  47. /* static int has_cubemap_capability = SOIL_CAPABILITY_UNKNOWN; */
  48. int query_cubemap_capability( void );
  49. #define SOIL_TEXTURE_WRAP_R 0x8072
  50. #define SOIL_CLAMP_TO_EDGE 0x812F
  51. #define SOIL_NORMAL_MAP 0x8511
  52. #define SOIL_REFLECTION_MAP 0x8512
  53. #define SOIL_TEXTURE_CUBE_MAP 0x8513
  54. #define SOIL_TEXTURE_BINDING_CUBE_MAP 0x8514
  55. #define SOIL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
  56. #define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
  57. #define SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
  58. #define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
  59. #define SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
  60. #define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
  61. #define SOIL_PROXY_TEXTURE_CUBE_MAP 0x851B
  62. #define SOIL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
  63. /* for non-power-of-two texture */
  64. /* static int has_NPOT_capability = SOIL_CAPABILITY_UNKNOWN; */
  65. int query_NPOT_capability( void );
  66. /* for texture rectangles */
  67. /* static int has_tex_rectangle_capability = SOIL_CAPABILITY_UNKNOWN; */
  68. int query_tex_rectangle_capability( void );
  69. #define SOIL_TEXTURE_RECTANGLE_ARB 0x84F5
  70. #define SOIL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
  71. /* for using DXT compression */
  72. /* static int has_DXT_capability = SOIL_CAPABILITY_UNKNOWN; */
  73. int query_DXT_capability( void );
  74. #define SOIL_RGB_S3TC_DXT1 0x83F0
  75. #define SOIL_RGBA_S3TC_DXT1 0x83F1
  76. #define SOIL_RGBA_S3TC_DXT3 0x83F2
  77. #define SOIL_RGBA_S3TC_DXT5 0x83F3
  78. #if 0
  79. typedef void (APIENTRY * P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid * data);
  80. P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC soilGlCompressedTexImage2D = NULL;
  81. unsigned int SOIL_direct_load_DDS(
  82. const char *filename,
  83. unsigned int reuse_texture_ID,
  84. int flags,
  85. int loading_as_cubemap );
  86. unsigned int SOIL_direct_load_DDS_from_memory(
  87. const unsigned char *const buffer,
  88. int buffer_length,
  89. unsigned int reuse_texture_ID,
  90. int flags,
  91. int loading_as_cubemap );
  92. /* other functions */
  93. unsigned int
  94. SOIL_internal_create_OGL_texture
  95. (
  96. const unsigned char *const data,
  97. int width, int height, int channels,
  98. unsigned int reuse_texture_ID,
  99. unsigned int flags,
  100. unsigned int opengl_texture_type,
  101. unsigned int opengl_texture_target,
  102. unsigned int texture_check_size_enum
  103. );
  104. /* and the code magic begins here [8^) */
  105. unsigned int
  106. SOIL_load_OGL_texture
  107. (
  108. const char *filename,
  109. int force_channels,
  110. unsigned int reuse_texture_ID,
  111. unsigned int flags
  112. )
  113. {
  114. /* variables */
  115. unsigned char* img;
  116. int width, height, channels;
  117. unsigned int tex_id;
  118. /* does the user want direct uploading of the image as a DDS file? */
  119. if( flags & SOIL_FLAG_DDS_LOAD_DIRECT )
  120. {
  121. /* 1st try direct loading of the image as a DDS file
  122. note: direct uploading will only load what is in the
  123. DDS file, no MIPmaps will be generated, the image will
  124. not be flipped, etc. */
  125. tex_id = SOIL_direct_load_DDS( filename, reuse_texture_ID, flags, 0 );
  126. if( tex_id )
  127. {
  128. /* hey, it worked!! */
  129. return tex_id;
  130. }
  131. }
  132. /* try to load the image */
  133. img = SOIL_load_image( filename, &width, &height, &channels, force_channels );
  134. /* channels holds the original number of channels, which may have been forced */
  135. if( (force_channels >= 1) && (force_channels <= 4) )
  136. {
  137. channels = force_channels;
  138. }
  139. if( NULL == img )
  140. {
  141. /* image loading failed */
  142. result_string_pointer = stbi_failure_reason();
  143. return 0;
  144. }
  145. /* OK, make it a texture! */
  146. tex_id = SOIL_internal_create_OGL_texture(
  147. img, width, height, channels,
  148. reuse_texture_ID, flags,
  149. GL_TEXTURE_2D, GL_TEXTURE_2D,
  150. GL_MAX_TEXTURE_SIZE );
  151. /* and nuke the image data */
  152. SOIL_free_image_data( img );
  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 = GL_REPORT_ERROR();
  955. while( GL_NO_ERROR != err_code )
  956. {
  957. printf( "OpenGL Error @ %s: %i", calling_location, err_code );
  958. err_code = GL_REPORT_ERROR();
  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. #endif
  1404. unsigned char *
  1405. SOIL_load_image
  1406. (
  1407. const char *filename,
  1408. int *width, int *height, int *channels,
  1409. int force_channels
  1410. )
  1411. {
  1412. stbi_uc *result = stbi_load( filename,
  1413. width, height, channels, force_channels );
  1414. if( result == NULL )
  1415. {
  1416. result_string_pointer = stbi_failure_reason();
  1417. } else
  1418. {
  1419. result_string_pointer = "Image loaded";
  1420. }
  1421. return result;
  1422. }
  1423. unsigned char *
  1424. SOIL_load_image_from_memory
  1425. (
  1426. const unsigned char *const buffer,
  1427. int buffer_length,
  1428. int *width, int *height, int *channels,
  1429. int force_channels
  1430. )
  1431. {
  1432. stbi_uc *result = stbi_load_from_memory(
  1433. buffer, buffer_length,
  1434. width, height, channels,
  1435. force_channels );
  1436. if( result == NULL )
  1437. {
  1438. result_string_pointer = stbi_failure_reason();
  1439. } else
  1440. {
  1441. result_string_pointer = "Image loaded from memory";
  1442. }
  1443. return result;
  1444. }
  1445. int
  1446. SOIL_save_image
  1447. (
  1448. const char *filename,
  1449. int image_type,
  1450. int width, int height, int channels,
  1451. const unsigned char *const data
  1452. )
  1453. {
  1454. int save_result;
  1455. /* error check */
  1456. if( (width < 1) || (height < 1) ||
  1457. (channels < 1) || (channels > 4) ||
  1458. (data == NULL) ||
  1459. (filename == NULL) )
  1460. {
  1461. return 0;
  1462. }
  1463. if( image_type == SOIL_SAVE_TYPE_BMP )
  1464. {
  1465. save_result = stbi_write_bmp( filename,
  1466. width, height, channels, (void*)data );
  1467. } else
  1468. if( image_type == SOIL_SAVE_TYPE_TGA )
  1469. {
  1470. save_result = stbi_write_tga( filename,
  1471. width, height, channels, (void*)data );
  1472. } else
  1473. if( image_type == SOIL_SAVE_TYPE_DDS )
  1474. {
  1475. save_result = save_image_as_DDS( filename,
  1476. width, height, channels, (const unsigned char *const)data );
  1477. } else
  1478. {
  1479. save_result = 0;
  1480. }
  1481. if( save_result == 0 )
  1482. {
  1483. result_string_pointer = "Saving the image failed";
  1484. } else
  1485. {
  1486. result_string_pointer = "Image saved";
  1487. }
  1488. return save_result;
  1489. }
  1490. void
  1491. SOIL_free_image_data
  1492. (
  1493. unsigned char *img_data
  1494. )
  1495. {
  1496. free( (void*)img_data );
  1497. }
  1498. const char*
  1499. SOIL_last_result
  1500. (
  1501. void
  1502. )
  1503. {
  1504. return result_string_pointer;
  1505. }
  1506. #if 0
  1507. unsigned int SOIL_direct_load_DDS_from_memory(
  1508. const unsigned char *const buffer,
  1509. int buffer_length,
  1510. unsigned int reuse_texture_ID,
  1511. int flags,
  1512. int loading_as_cubemap )
  1513. {
  1514. /* variables */
  1515. DDS_header header;
  1516. unsigned int buffer_index = 0;
  1517. unsigned int tex_ID = 0;
  1518. /* file reading variables */
  1519. unsigned int S3TC_type = 0;
  1520. unsigned char *DDS_data;
  1521. unsigned int DDS_main_size;
  1522. unsigned int DDS_full_size;
  1523. unsigned int width, height;
  1524. int mipmaps, cubemap, uncompressed, block_size = 16;
  1525. unsigned int flag;
  1526. unsigned int cf_target, ogl_target_start, ogl_target_end;
  1527. unsigned int opengl_texture_type;
  1528. int i;
  1529. /* 1st off, does the filename even exist? */
  1530. if( NULL == buffer )
  1531. {
  1532. /* we can't do it! */
  1533. result_string_pointer = "NULL buffer";
  1534. return 0;
  1535. }
  1536. if( buffer_length < sizeof( DDS_header ) )
  1537. {
  1538. /* we can't do it! */
  1539. result_string_pointer = "DDS file was too small to contain the DDS header";
  1540. return 0;
  1541. }
  1542. /* try reading in the header */
  1543. memcpy ( (void*)(&header), (const void *)buffer, sizeof( DDS_header ) );
  1544. buffer_index = sizeof( DDS_header );
  1545. /* guilty until proven innocent */
  1546. result_string_pointer = "Failed to read a known DDS header";
  1547. /* validate the header (warning, "goto"'s ahead, shield your eyes!!) */
  1548. flag = ('D'<<0)|('D'<<8)|('S'<<16)|(' '<<24);
  1549. if( header.dwMagic != flag ) {goto quick_exit;}
  1550. if( header.dwSize != 124 ) {goto quick_exit;}
  1551. /* I need all of these */
  1552. flag = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  1553. if( (header.dwFlags & flag) != flag ) {goto quick_exit;}
  1554. /* According to the MSDN spec, the dwFlags should contain
  1555. DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if
  1556. uncompressed. Some DDS writers do not conform to the
  1557. spec, so I need to make my reader more tolerant */
  1558. /* I need one of these */
  1559. flag = DDPF_FOURCC | DDPF_RGB;
  1560. if( (header.sPixelFormat.dwFlags & flag) == 0 ) {goto quick_exit;}
  1561. if( header.sPixelFormat.dwSize != 32 ) {goto quick_exit;}
  1562. if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) {goto quick_exit;}
  1563. /* make sure it is a type we can upload */
  1564. if( (header.sPixelFormat.dwFlags & DDPF_FOURCC) &&
  1565. !(
  1566. (header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24))) ||
  1567. (header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('3'<<24))) ||
  1568. (header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('5'<<24)))
  1569. ) )
  1570. {
  1571. goto quick_exit;
  1572. }
  1573. /* OK, validated the header, let's load the image data */
  1574. result_string_pointer = "DDS header loaded and validated";
  1575. width = header.dwWidth;
  1576. height = header.dwHeight;
  1577. uncompressed = 1 - (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC;
  1578. cubemap = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP;
  1579. if( uncompressed )
  1580. {
  1581. S3TC_type = GL_RGB;
  1582. block_size = 3;
  1583. if( header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS )
  1584. {
  1585. S3TC_type = GL_RGBA;
  1586. block_size = 4;
  1587. }
  1588. DDS_main_size = width * height * block_size;
  1589. } else
  1590. {
  1591. /* can we even handle direct uploading to OpenGL DXT compressed images? */
  1592. if( query_DXT_capability() != SOIL_CAPABILITY_PRESENT )
  1593. {
  1594. /* we can't do it! */
  1595. result_string_pointer = "Direct upload of S3TC images not supported by the OpenGL driver";
  1596. return 0;
  1597. }
  1598. /* well, we know it is DXT1/3/5, because we checked above */
  1599. switch( (header.sPixelFormat.dwFourCC >> 24) - '0' )
  1600. {
  1601. case 1:
  1602. S3TC_type = SOIL_RGBA_S3TC_DXT1;
  1603. block_size = 8;
  1604. break;
  1605. case 3:
  1606. S3TC_type = SOIL_RGBA_S3TC_DXT3;
  1607. block_size = 16;
  1608. break;
  1609. case 5:
  1610. S3TC_type = SOIL_RGBA_S3TC_DXT5;
  1611. block_size = 16;
  1612. break;
  1613. }
  1614. DDS_main_size = ((width+3)>>2)*((height+3)>>2)*block_size;
  1615. }
  1616. if( cubemap )
  1617. {
  1618. /* does the user want a cubemap? */
  1619. if( !loading_as_cubemap )
  1620. {
  1621. /* we can't do it! */
  1622. result_string_pointer = "DDS image was a cubemap";
  1623. return 0;
  1624. }
  1625. /* can we even handle cubemaps with the OpenGL driver? */
  1626. if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
  1627. {
  1628. /* we can't do it! */
  1629. result_string_pointer = "Direct upload of cubemap images not supported by the OpenGL driver";
  1630. return 0;
  1631. }
  1632. ogl_target_start = SOIL_TEXTURE_CUBE_MAP_POSITIVE_X;
  1633. ogl_target_end = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
  1634. opengl_texture_type = SOIL_TEXTURE_CUBE_MAP;
  1635. } else
  1636. {
  1637. /* does the user want a non-cubemap? */
  1638. if( loading_as_cubemap )
  1639. {
  1640. /* we can't do it! */
  1641. result_string_pointer = "DDS image was not a cubemap";
  1642. return 0;
  1643. }
  1644. ogl_target_start = GL_TEXTURE_2D;
  1645. ogl_target_end = GL_TEXTURE_2D;
  1646. opengl_texture_type = GL_TEXTURE_2D;
  1647. }
  1648. if( (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1) )
  1649. {
  1650. int shift_offset;
  1651. mipmaps = header.dwMipMapCount - 1;
  1652. DDS_full_size = DDS_main_size;
  1653. if( uncompressed )
  1654. {
  1655. /* uncompressed DDS, simple MIPmap size calculation */
  1656. shift_offset = 0;
  1657. } else
  1658. {
  1659. /* compressed DDS, MIPmap size calculation is block based */
  1660. shift_offset = 2;
  1661. }
  1662. for( i = 1; i <= mipmaps; ++ i )
  1663. {
  1664. int w, h;
  1665. w = width >> (shift_offset + i);
  1666. h = height >> (shift_offset + i);
  1667. if( w < 1 )
  1668. {
  1669. w = 1;
  1670. }
  1671. if( h < 1 )
  1672. {
  1673. h = 1;
  1674. }
  1675. DDS_full_size += w*h*block_size;
  1676. }
  1677. } else
  1678. {
  1679. mipmaps = 0;
  1680. DDS_full_size = DDS_main_size;
  1681. }
  1682. DDS_data = (unsigned char*)malloc( DDS_full_size );
  1683. /* got the image data RAM, create or use an existing OpenGL texture handle */
  1684. tex_ID = reuse_texture_ID;
  1685. if( tex_ID == 0 )
  1686. {
  1687. glGenTextures( 1, &tex_ID );
  1688. }
  1689. /* bind an OpenGL texture ID */
  1690. glBindTexture( opengl_texture_type, tex_ID );
  1691. /* do this for each face of the cubemap! */
  1692. for( cf_target = ogl_target_start; cf_target <= ogl_target_end; ++cf_target )
  1693. {
  1694. if( buffer_index + DDS_full_size <= buffer_length )
  1695. {
  1696. unsigned int byte_offset = DDS_main_size;
  1697. memcpy( (void*)DDS_data, (const void*)(&buffer[buffer_index]), DDS_full_size );
  1698. buffer_index += DDS_full_size;
  1699. /* upload the main chunk */
  1700. if( uncompressed )
  1701. {
  1702. /* and remember, DXT uncompressed uses BGR(A),
  1703. so swap to RGB(A) for ALL MIPmap levels */
  1704. for( i = 0; i < DDS_full_size; i += block_size )
  1705. {
  1706. unsigned char temp = DDS_data[i];
  1707. DDS_data[i] = DDS_data[i+2];
  1708. DDS_data[i+2] = temp;
  1709. }
  1710. glTexImage2D(
  1711. cf_target, 0,
  1712. S3TC_type, width, height, 0,
  1713. S3TC_type, GL_UNSIGNED_BYTE, DDS_data );
  1714. } else
  1715. {
  1716. soilGlCompressedTexImage2D(
  1717. cf_target, 0,
  1718. S3TC_type, width, height, 0,
  1719. DDS_main_size, DDS_data );
  1720. }
  1721. /* upload the mipmaps, if we have them */
  1722. for( i = 1; i <= mipmaps; ++i )
  1723. {
  1724. int w, h, mip_size;
  1725. w = width >> i;
  1726. h = height >> i;
  1727. if( w < 1 )
  1728. {
  1729. w = 1;
  1730. }
  1731. if( h < 1 )
  1732. {
  1733. h = 1;
  1734. }
  1735. /* upload this mipmap */
  1736. if( uncompressed )
  1737. {
  1738. mip_size = w*h*block_size;
  1739. glTexImage2D(
  1740. cf_target, i,
  1741. S3TC_type, w, h, 0,
  1742. S3TC_type, GL_UNSIGNED_BYTE, &DDS_data[byte_offset] );
  1743. } else
  1744. {
  1745. mip_size = ((w+3)/4)*((h+3)/4)*block_size;
  1746. soilGlCompressedTexImage2D(
  1747. cf_target, i,
  1748. S3TC_type, w, h, 0,
  1749. mip_size, &DDS_data[byte_offset] );
  1750. }
  1751. /* and move to the next mipmap */
  1752. byte_offset += mip_size;
  1753. }
  1754. /* it worked! */
  1755. result_string_pointer = "DDS file loaded";
  1756. } else
  1757. {
  1758. glDeleteTextures( 1, & tex_ID );
  1759. tex_ID = 0;
  1760. cf_target = ogl_target_end + 1;
  1761. result_string_pointer = "DDS file was too small for expected image data";
  1762. }
  1763. }/* end reading each face */
  1764. SOIL_free_image_data( DDS_data );
  1765. if( tex_ID )
  1766. {
  1767. /* did I have MIPmaps? */
  1768. if( mipmaps > 0 )
  1769. {
  1770. /* instruct OpenGL to use the MIPmaps */
  1771. glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  1772. glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
  1773. } else
  1774. {
  1775. /* instruct OpenGL _NOT_ to use the MIPmaps */
  1776. glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  1777. glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  1778. }
  1779. /* does the user want clamping, or wrapping? */
  1780. if( flags & SOIL_FLAG_TEXTURE_REPEATS )
  1781. {
  1782. glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT );
  1783. glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT );
  1784. glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT );
  1785. } else
  1786. {
  1787. /* unsigned int clamp_mode = SOIL_CLAMP_TO_EDGE; */
  1788. unsigned int clamp_mode = GL_CLAMP;
  1789. glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode );
  1790. glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode );
  1791. glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode );
  1792. }
  1793. }
  1794. quick_exit:
  1795. /* report success or failure */
  1796. return tex_ID;
  1797. }
  1798. unsigned int SOIL_direct_load_DDS(
  1799. const char *filename,
  1800. unsigned int reuse_texture_ID,
  1801. int flags,
  1802. int loading_as_cubemap )
  1803. {
  1804. FILE *f;
  1805. unsigned char *buffer;
  1806. size_t buffer_length, bytes_read;
  1807. unsigned int tex_ID = 0;
  1808. /* error checks */
  1809. if( NULL == filename )
  1810. {
  1811. result_string_pointer = "NULL filename";
  1812. return 0;
  1813. }
  1814. f = fopen( filename, "rb" );
  1815. if( NULL == f )
  1816. {
  1817. /* the file doesn't seem to exist (or be open-able) */
  1818. result_string_pointer = "Can not find DDS file";
  1819. return 0;
  1820. }
  1821. fseek( f, 0, SEEK_END );
  1822. buffer_length = ftell( f );
  1823. fseek( f, 0, SEEK_SET );
  1824. buffer = (unsigned char *) malloc( buffer_length );
  1825. if( NULL == buffer )
  1826. {
  1827. result_string_pointer = "malloc failed";
  1828. fclose( f );
  1829. return 0;
  1830. }
  1831. bytes_read = fread( (void*)buffer, 1, buffer_length, f );
  1832. fclose( f );
  1833. if( bytes_read < buffer_length )
  1834. {
  1835. /* huh? */
  1836. buffer_length = bytes_read;
  1837. }
  1838. /* now try to do the loading */
  1839. tex_ID = SOIL_direct_load_DDS_from_memory(
  1840. (const unsigned char *const)buffer, buffer_length,
  1841. reuse_texture_ID, flags, loading_as_cubemap );
  1842. SOIL_free_image_data( buffer );
  1843. return tex_ID;
  1844. }
  1845. int query_NPOT_capability( void )
  1846. {
  1847. /* check for the capability */
  1848. if( has_NPOT_capability == SOIL_CAPABILITY_UNKNOWN )
  1849. {
  1850. /* we haven't yet checked for the capability, do so */
  1851. if(
  1852. (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
  1853. "GL_ARB_texture_non_power_of_two" ) )
  1854. )
  1855. {
  1856. /* not there, flag the failure */
  1857. has_NPOT_capability = SOIL_CAPABILITY_NONE;
  1858. } else
  1859. {
  1860. /* it's there! */
  1861. has_NPOT_capability = SOIL_CAPABILITY_PRESENT;
  1862. }
  1863. }
  1864. /* let the user know if we can do non-power-of-two textures or not */
  1865. return has_NPOT_capability;
  1866. }
  1867. int query_tex_rectangle_capability( void )
  1868. {
  1869. /* check for the capability */
  1870. if( has_tex_rectangle_capability == SOIL_CAPABILITY_UNKNOWN )
  1871. {
  1872. /* we haven't yet checked for the capability, do so */
  1873. if(
  1874. (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
  1875. "GL_ARB_texture_rectangle" ) )
  1876. &&
  1877. (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
  1878. "GL_EXT_texture_rectangle" ) )
  1879. &&
  1880. (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
  1881. "GL_NV_texture_rectangle" ) )
  1882. )
  1883. {
  1884. /* not there, flag the failure */
  1885. has_tex_rectangle_capability = SOIL_CAPABILITY_NONE;
  1886. } else
  1887. {
  1888. /* it's there! */
  1889. has_tex_rectangle_capability = SOIL_CAPABILITY_PRESENT;
  1890. }
  1891. }
  1892. /* let the user know if we can do texture rectangles or not */
  1893. return has_tex_rectangle_capability;
  1894. }
  1895. int query_cubemap_capability( void )
  1896. {
  1897. /* check for the capability */
  1898. if( has_cubemap_capability == SOIL_CAPABILITY_UNKNOWN )
  1899. {
  1900. /* we haven't yet checked for the capability, do so */
  1901. if(
  1902. (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
  1903. "GL_ARB_texture_cube_map" ) )
  1904. &&
  1905. (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
  1906. "GL_EXT_texture_cube_map" ) )
  1907. )
  1908. {
  1909. /* not there, flag the failure */
  1910. has_cubemap_capability = SOIL_CAPABILITY_NONE;
  1911. } else
  1912. {
  1913. /* it's there! */
  1914. has_cubemap_capability = SOIL_CAPABILITY_PRESENT;
  1915. }
  1916. }
  1917. /* let the user know if we can do cubemaps or not */
  1918. return has_cubemap_capability;
  1919. }
  1920. int query_DXT_capability( void )
  1921. {
  1922. /* check for the capability */
  1923. if( has_DXT_capability == SOIL_CAPABILITY_UNKNOWN )
  1924. {
  1925. /* we haven't yet checked for the capability, do so */
  1926. if( NULL == strstr(
  1927. (char const*)glGetString( GL_EXTENSIONS ),
  1928. "GL_EXT_texture_compression_s3tc" ) )
  1929. {
  1930. /* not there, flag the failure */
  1931. has_DXT_capability = SOIL_CAPABILITY_NONE;
  1932. } else
  1933. {
  1934. /* and find the address of the extension function */
  1935. P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC ext_addr = NULL;
  1936. #ifdef WIN32
  1937. ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)
  1938. wglGetProcAddress
  1939. (
  1940. "glCompressedTexImage2DARB"
  1941. );
  1942. #elif defined(__APPLE__) || defined(__APPLE_CC__)
  1943. /* I can't test this Apple stuff! */
  1944. CFBundleRef bundle;
  1945. CFURLRef bundleURL =
  1946. CFURLCreateWithFileSystemPath(
  1947. kCFAllocatorDefault,
  1948. CFSTR("/System/Library/Frameworks/OpenGL.framework"),
  1949. kCFURLPOSIXPathStyle,
  1950. true );
  1951. CFStringRef extensionName =
  1952. CFStringCreateWithCString(
  1953. kCFAllocatorDefault,
  1954. "glCompressedTexImage2DARB",
  1955. kCFStringEncodingASCII );
  1956. bundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
  1957. assert( bundle != NULL );
  1958. ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)
  1959. CFBundleGetFunctionPointerForName
  1960. (
  1961. bundle, extensionName
  1962. );
  1963. CFRelease( bundleURL );
  1964. CFRelease( extensionName );
  1965. CFRelease( bundle );
  1966. #else
  1967. ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)
  1968. glXGetProcAddressARB
  1969. (
  1970. (const GLubyte *)"glCompressedTexImage2DARB"
  1971. );
  1972. #endif
  1973. /* Flag it so no checks needed later */
  1974. if( NULL == ext_addr )
  1975. {
  1976. /* hmm, not good!! This should not happen, but does on my
  1977. laptop's VIA chipset. The GL_EXT_texture_compression_s3tc
  1978. spec requires that ARB_texture_compression be present too.
  1979. this means I can upload and have the OpenGL drive do the
  1980. conversion, but I can't use my own routines or load DDS files
  1981. from disk and upload them directly [8^( */
  1982. has_DXT_capability = SOIL_CAPABILITY_NONE;
  1983. } else
  1984. {
  1985. /* all's well! */
  1986. soilGlCompressedTexImage2D = ext_addr;
  1987. has_DXT_capability = SOIL_CAPABILITY_PRESENT;
  1988. }
  1989. }
  1990. }
  1991. /* let the user know if we can do DXT or not */
  1992. return has_DXT_capability;
  1993. }
  1994. #endif