Subversion Repositories gelsvn

Rev

Rev 449 | Go to most recent revision | Details | Last modification | View Log | RSS feed

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