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