Subversion Repositories gelsvn

Rev

Rev 373 | Rev 555 | Go to most recent revision | Details | Compare with Previous | 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*
449 jrf 1445
	SOIL_load_HDR_image
1446
	(
1447
		const char *filename,
1448
		int *width, int *height, int *channels,
1449
		int force_channels
1450
	)
1451
{
1452
	unsigned char *result = stbi_hdr_load_rgbe( filename,
1453
			width, height, channels, force_channels );
1454
	if( result == NULL )
1455
	{
1456
		result_string_pointer = stbi_failure_reason();
1457
	} else
1458
	{
1459
		result_string_pointer = "Image loaded";
1460
	}
1461
	return result;
1462
}
1463
 
1464
unsigned char*
369 jab 1465
	SOIL_load_image_from_memory
1466
	(
1467
		const unsigned char *const buffer,
1468
		int buffer_length,
1469
		int *width, int *height, int *channels,
1470
		int force_channels
1471
	)
1472
{
1473
	unsigned char *result = stbi_load_from_memory(
1474
				buffer, buffer_length,
1475
				width, height, channels,
1476
				force_channels );
1477
	if( result == NULL )
1478
	{
1479
		result_string_pointer = stbi_failure_reason();
1480
	} else
1481
	{
1482
		result_string_pointer = "Image loaded from memory";
1483
	}
1484
	return result;
1485
}
1486
 
1487
int
1488
	SOIL_save_image
1489
	(
1490
		const char *filename,
1491
		int image_type,
1492
		int width, int height, int channels,
1493
		const unsigned char *const data
1494
	)
1495
{
1496
	int save_result;
1497
 
1498
	/*	error check	*/
1499
	if( (width < 1) || (height < 1) ||
1500
		(channels < 1) || (channels > 4) ||
1501
		(data == NULL) ||
1502
		(filename == NULL) )
1503
	{
1504
		return 0;
1505
	}
1506
	if( image_type == SOIL_SAVE_TYPE_BMP )
1507
	{
1508
		save_result = stbi_write_bmp( filename,
1509
				width, height, channels, (void*)data );
1510
	} else
1511
	if( image_type == SOIL_SAVE_TYPE_TGA )
1512
	{
1513
		save_result = stbi_write_tga( filename,
1514
				width, height, channels, (void*)data );
1515
	} else
1516
	if( image_type == SOIL_SAVE_TYPE_DDS )
1517
	{
1518
		save_result = save_image_as_DDS( filename,
1519
				width, height, channels, (const unsigned char *const)data );
1520
	} else
1521
	{
1522
		save_result = 0;
1523
	}
1524
	if( save_result == 0 )
1525
	{
1526
		result_string_pointer = "Saving the image failed";
1527
	} else
1528
	{
1529
		result_string_pointer = "Image saved";
1530
	}
1531
	return save_result;
1532
}
1533
 
1534
void
1535
	SOIL_free_image_data
1536
	(
1537
		unsigned char *img_data
1538
	)
1539
{
1540
	free( (void*)img_data );
1541
}
1542
 
1543
const char*
1544
	SOIL_last_result
1545
	(
1546
		void
1547
	)
1548
{
1549
	return result_string_pointer;
1550
}
1551
 
1552
unsigned int SOIL_direct_load_DDS_from_memory(
1553
		const unsigned char *const buffer,
1554
		int buffer_length,
1555
		unsigned int reuse_texture_ID,
1556
		int flags,
1557
		int loading_as_cubemap )
1558
{
1559
	/*	variables	*/
1560
	DDS_header header;
1561
	unsigned int buffer_index = 0;
1562
	unsigned int tex_ID = 0;
1563
	/*	file reading variables	*/
1564
	unsigned int S3TC_type = 0;
1565
	unsigned char *DDS_data;
1566
	unsigned int DDS_main_size;
1567
	unsigned int DDS_full_size;
1568
	unsigned int width, height;
1569
	int mipmaps, cubemap, uncompressed, block_size = 16;
1570
	unsigned int flag;
1571
	unsigned int cf_target, ogl_target_start, ogl_target_end;
1572
	unsigned int opengl_texture_type;
1573
	int i;
1574
	/*	1st off, does the filename even exist?	*/
1575
	if( NULL == buffer )
1576
	{
1577
		/*	we can't do it!	*/
1578
		result_string_pointer = "NULL buffer";
1579
		return 0;
1580
	}
1581
	if( buffer_length < sizeof( DDS_header ) )
1582
	{
1583
		/*	we can't do it!	*/
1584
		result_string_pointer = "DDS file was too small to contain the DDS header";
1585
		return 0;
1586
	}
1587
	/*	try reading in the header	*/
1588
	memcpy ( (void*)(&header), (const void *)buffer, sizeof( DDS_header ) );
1589
	buffer_index = sizeof( DDS_header );
1590
	/*	guilty until proven innocent	*/
1591
	result_string_pointer = "Failed to read a known DDS header";
1592
	/*	validate the header (warning, "goto"'s ahead, shield your eyes!!)	*/
1593
	flag = ('D'<<0)|('D'<<8)|('S'<<16)|(' '<<24);
1594
	if( header.dwMagic != flag ) {goto quick_exit;}
1595
	if( header.dwSize != 124 ) {goto quick_exit;}
1596
	/*	I need all of these	*/
1597
	flag = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1598
	if( (header.dwFlags & flag) != flag ) {goto quick_exit;}
1599
	/*	According to the MSDN spec, the dwFlags should contain
1600
		DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if
1601
		uncompressed.  Some DDS writers do not conform to the
1602
		spec, so I need to make my reader more tolerant	*/
1603
	/*	I need one of these	*/
1604
	flag = DDPF_FOURCC | DDPF_RGB;
1605
	if( (header.sPixelFormat.dwFlags & flag) == 0 ) {goto quick_exit;}
1606
	if( header.sPixelFormat.dwSize != 32 ) {goto quick_exit;}
1607
	if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) {goto quick_exit;}
1608
	/*	make sure it is a type we can upload	*/
1609
	if( (header.sPixelFormat.dwFlags & DDPF_FOURCC) &&
1610
		!(
1611
		(header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24))) ||
1612
		(header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('3'<<24))) ||
1613
		(header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('5'<<24)))
1614
		) )
1615
	{
1616
		goto quick_exit;
1617
	}
1618
	/*	OK, validated the header, let's load the image data	*/
1619
	result_string_pointer = "DDS header loaded and validated";
1620
	width = header.dwWidth;
1621
	height = header.dwHeight;
1622
	uncompressed = 1 - (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC;
1623
	cubemap = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP;
1624
	if( uncompressed )
1625
	{
1626
		S3TC_type = GL_RGB;
1627
		block_size = 3;
1628
		if( header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS )
1629
		{
1630
			S3TC_type = GL_RGBA;
1631
			block_size = 4;
1632
		}
1633
		DDS_main_size = width * height * block_size;
1634
	} else
1635
	{
1636
		/*	can we even handle direct uploading to OpenGL DXT compressed images?	*/
1637
		if( query_DXT_capability() != SOIL_CAPABILITY_PRESENT )
1638
		{
1639
			/*	we can't do it!	*/
1640
			result_string_pointer = "Direct upload of S3TC images not supported by the OpenGL driver";
1641
			return 0;
1642
		}
1643
		/*	well, we know it is DXT1/3/5, because we checked above	*/
1644
		switch( (header.sPixelFormat.dwFourCC >> 24) - '0' )
1645
		{
1646
		case 1:
1647
			S3TC_type = SOIL_RGBA_S3TC_DXT1;
1648
			block_size = 8;
1649
			break;
1650
		case 3:
1651
			S3TC_type = SOIL_RGBA_S3TC_DXT3;
1652
			block_size = 16;
1653
			break;
1654
		case 5:
1655
			S3TC_type = SOIL_RGBA_S3TC_DXT5;
1656
			block_size = 16;
1657
			break;
1658
		}
1659
		DDS_main_size = ((width+3)>>2)*((height+3)>>2)*block_size;
1660
	}
1661
	if( cubemap )
1662
	{
1663
		/* does the user want a cubemap?	*/
1664
		if( !loading_as_cubemap )
1665
		{
1666
			/*	we can't do it!	*/
1667
			result_string_pointer = "DDS image was a cubemap";
1668
			return 0;
1669
		}
1670
		/*	can we even handle cubemaps with the OpenGL driver?	*/
1671
		if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )
1672
		{
1673
			/*	we can't do it!	*/
1674
			result_string_pointer = "Direct upload of cubemap images not supported by the OpenGL driver";
1675
			return 0;
1676
		}
1677
		ogl_target_start = SOIL_TEXTURE_CUBE_MAP_POSITIVE_X;
1678
		ogl_target_end =   SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1679
		opengl_texture_type = SOIL_TEXTURE_CUBE_MAP;
1680
	} else
1681
	{
1682
		/* does the user want a non-cubemap?	*/
1683
		if( loading_as_cubemap )
1684
		{
1685
			/*	we can't do it!	*/
1686
			result_string_pointer = "DDS image was not a cubemap";
1687
			return 0;
1688
		}
1689
		ogl_target_start = GL_TEXTURE_2D;
1690
		ogl_target_end =   GL_TEXTURE_2D;
1691
		opengl_texture_type = GL_TEXTURE_2D;
1692
	}
1693
	if( (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1) )
1694
	{
1695
		int shift_offset;
1696
		mipmaps = header.dwMipMapCount - 1;
1697
		DDS_full_size = DDS_main_size;
1698
		if( uncompressed )
1699
		{
1700
			/*	uncompressed DDS, simple MIPmap size calculation	*/
1701
			shift_offset = 0;
1702
		} else
1703
		{
1704
			/*	compressed DDS, MIPmap size calculation is block based	*/
1705
			shift_offset = 2;
1706
		}
1707
		for( i = 1; i <= mipmaps; ++ i )
1708
		{
1709
			int w, h;
1710
			w = width >> (shift_offset + i);
1711
			h = height >> (shift_offset + i);
1712
			if( w < 1 )
1713
			{
1714
				w = 1;
1715
			}
1716
			if( h < 1 )
1717
			{
1718
				h = 1;
1719
			}
1720
			DDS_full_size += w*h*block_size;
1721
		}
1722
	} else
1723
	{
1724
		mipmaps = 0;
1725
		DDS_full_size = DDS_main_size;
1726
	}
1727
	DDS_data = (unsigned char*)malloc( DDS_full_size );
1728
	/*	got the image data RAM, create or use an existing OpenGL texture handle	*/
1729
	tex_ID = reuse_texture_ID;
1730
	if( tex_ID == 0 )
1731
	{
1732
		glGenTextures( 1, &tex_ID );
1733
	}
1734
	/*  bind an OpenGL texture ID	*/
1735
	glBindTexture( opengl_texture_type, tex_ID );
1736
	/*	do this for each face of the cubemap!	*/
1737
	for( cf_target = ogl_target_start; cf_target <= ogl_target_end; ++cf_target )
1738
	{
373 jrf 1739
		if( buffer_index + DDS_full_size <= (unsigned int)buffer_length )
369 jab 1740
		{
1741
			unsigned int byte_offset = DDS_main_size;
1742
			memcpy( (void*)DDS_data, (const void*)(&buffer[buffer_index]), DDS_full_size );
1743
			buffer_index += DDS_full_size;
1744
			/*	upload the main chunk	*/
1745
			if( uncompressed )
1746
			{
1747
				/*	and remember, DXT uncompressed uses BGR(A),
1748
					so swap to RGB(A) for ALL MIPmap levels	*/
373 jrf 1749
				for( i = 0; i < (int)DDS_full_size; i += block_size )
369 jab 1750
				{
1751
					unsigned char temp = DDS_data[i];
1752
					DDS_data[i] = DDS_data[i+2];
1753
					DDS_data[i+2] = temp;
1754
				}
1755
				glTexImage2D(
1756
					cf_target, 0,
1757
					S3TC_type, width, height, 0,
1758
					S3TC_type, GL_UNSIGNED_BYTE, DDS_data );
1759
			} else
1760
			{
1761
				soilGlCompressedTexImage2D(
1762
					cf_target, 0,
1763
					S3TC_type, width, height, 0,
1764
					DDS_main_size, DDS_data );
1765
			}
1766
			/*	upload the mipmaps, if we have them	*/
1767
			for( i = 1; i <= mipmaps; ++i )
1768
			{
1769
				int w, h, mip_size;
1770
				w = width >> i;
1771
				h = height >> i;
1772
				if( w < 1 )
1773
				{
1774
					w = 1;
1775
				}
1776
				if( h < 1 )
1777
				{
1778
					h = 1;
1779
				}
1780
				/*	upload this mipmap	*/
1781
				if( uncompressed )
1782
				{
1783
					mip_size = w*h*block_size;
1784
					glTexImage2D(
1785
						cf_target, i,
1786
						S3TC_type, w, h, 0,
1787
						S3TC_type, GL_UNSIGNED_BYTE, &DDS_data[byte_offset] );
1788
				} else
1789
				{
1790
					mip_size = ((w+3)/4)*((h+3)/4)*block_size;
1791
					soilGlCompressedTexImage2D(
1792
						cf_target, i,
1793
						S3TC_type, w, h, 0,
1794
						mip_size, &DDS_data[byte_offset] );
1795
				}
1796
				/*	and move to the next mipmap	*/
1797
				byte_offset += mip_size;
1798
			}
1799
			/*	it worked!	*/
1800
			result_string_pointer = "DDS file loaded";
1801
		} else
1802
		{
1803
			glDeleteTextures( 1, & tex_ID );
1804
			tex_ID = 0;
1805
			cf_target = ogl_target_end + 1;
1806
			result_string_pointer = "DDS file was too small for expected image data";
1807
		}
1808
	}/* end reading each face */
1809
	SOIL_free_image_data( DDS_data );
1810
	if( tex_ID )
1811
	{
1812
		/*	did I have MIPmaps?	*/
1813
		if( mipmaps > 0 )
1814
		{
1815
			/*	instruct OpenGL to use the MIPmaps	*/
1816
			glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1817
			glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
1818
		} else
1819
		{
1820
			/*	instruct OpenGL _NOT_ to use the MIPmaps	*/
1821
			glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1822
			glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1823
		}
1824
		/*	does the user want clamping, or wrapping?	*/
1825
		if( flags & SOIL_FLAG_TEXTURE_REPEATS )
1826
		{
1827
			glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT );
1828
			glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT );
1829
			glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT );
1830
		} else
1831
		{
1832
			/*	unsigned int clamp_mode = SOIL_CLAMP_TO_EDGE;	*/
1833
			unsigned int clamp_mode = GL_CLAMP;
1834
			glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode );
1835
			glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode );
1836
			glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode );
1837
		}
1838
	}
1839
 
1840
quick_exit:
1841
	/*	report success or failure	*/
1842
	return tex_ID;
1843
}
1844
 
1845
unsigned int SOIL_direct_load_DDS(
1846
		const char *filename,
1847
		unsigned int reuse_texture_ID,
1848
		int flags,
1849
		int loading_as_cubemap )
1850
{
1851
	FILE *f;
1852
	unsigned char *buffer;
1853
	size_t buffer_length, bytes_read;
1854
	unsigned int tex_ID = 0;
1855
	/*	error checks	*/
1856
	if( NULL == filename )
1857
	{
1858
		result_string_pointer = "NULL filename";
1859
		return 0;
1860
	}
1861
	f = fopen( filename, "rb" );
1862
	if( NULL == f )
1863
	{
1864
		/*	the file doesn't seem to exist (or be open-able)	*/
1865
		result_string_pointer = "Can not find DDS file";
1866
		return 0;
1867
	}
1868
	fseek( f, 0, SEEK_END );
1869
	buffer_length = ftell( f );
1870
	fseek( f, 0, SEEK_SET );
1871
	buffer = (unsigned char *) malloc( buffer_length );
1872
	if( NULL == buffer )
1873
	{
1874
		result_string_pointer = "malloc failed";
1875
		fclose( f );
1876
		return 0;
1877
	}
1878
	bytes_read = fread( (void*)buffer, 1, buffer_length, f );
1879
	fclose( f );
1880
	if( bytes_read < buffer_length )
1881
	{
1882
		/*	huh?	*/
1883
		buffer_length = bytes_read;
1884
	}
1885
	/*	now try to do the loading	*/
1886
	tex_ID = SOIL_direct_load_DDS_from_memory(
1887
		(const unsigned char *const)buffer, buffer_length,
1888
		reuse_texture_ID, flags, loading_as_cubemap );
1889
	SOIL_free_image_data( buffer );
1890
	return tex_ID;
1891
}
1892
 
1893
int query_NPOT_capability( void )
1894
{
1895
	/*	check for the capability	*/
1896
	if( has_NPOT_capability == SOIL_CAPABILITY_UNKNOWN )
1897
	{
1898
		/*	we haven't yet checked for the capability, do so	*/
1899
		if(
1900
			(NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
1901
				"GL_ARB_texture_non_power_of_two" ) )
1902
			)
1903
		{
1904
			/*	not there, flag the failure	*/
1905
			has_NPOT_capability = SOIL_CAPABILITY_NONE;
1906
		} else
1907
		{
1908
			/*	it's there!	*/
1909
			has_NPOT_capability = SOIL_CAPABILITY_PRESENT;
1910
		}
1911
	}
1912
	/*	let the user know if we can do non-power-of-two textures or not	*/
1913
	return has_NPOT_capability;
1914
}
1915
 
1916
int query_tex_rectangle_capability( void )
1917
{
1918
	/*	check for the capability	*/
1919
	if( has_tex_rectangle_capability == SOIL_CAPABILITY_UNKNOWN )
1920
	{
1921
		/*	we haven't yet checked for the capability, do so	*/
1922
		if(
1923
			(NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
1924
				"GL_ARB_texture_rectangle" ) )
1925
		&&
1926
			(NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
1927
				"GL_EXT_texture_rectangle" ) )
1928
		&&
1929
			(NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
1930
				"GL_NV_texture_rectangle" ) )
1931
			)
1932
		{
1933
			/*	not there, flag the failure	*/
1934
			has_tex_rectangle_capability = SOIL_CAPABILITY_NONE;
1935
		} else
1936
		{
1937
			/*	it's there!	*/
1938
			has_tex_rectangle_capability = SOIL_CAPABILITY_PRESENT;
1939
		}
1940
	}
1941
	/*	let the user know if we can do texture rectangles or not	*/
1942
	return has_tex_rectangle_capability;
1943
}
1944
 
1945
int query_cubemap_capability( void )
1946
{
1947
	/*	check for the capability	*/
1948
	if( has_cubemap_capability == SOIL_CAPABILITY_UNKNOWN )
1949
	{
1950
		/*	we haven't yet checked for the capability, do so	*/
1951
		if(
1952
			(NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
1953
				"GL_ARB_texture_cube_map" ) )
1954
		&&
1955
			(NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ),
1956
				"GL_EXT_texture_cube_map" ) )
1957
			)
1958
		{
1959
			/*	not there, flag the failure	*/
1960
			has_cubemap_capability = SOIL_CAPABILITY_NONE;
1961
		} else
1962
		{
1963
			/*	it's there!	*/
1964
			has_cubemap_capability = SOIL_CAPABILITY_PRESENT;
1965
		}
1966
	}
1967
	/*	let the user know if we can do cubemaps or not	*/
1968
	return has_cubemap_capability;
1969
}
1970
 
1971
int query_DXT_capability( void )
1972
{
1973
	/*	check for the capability	*/
1974
	if( has_DXT_capability == SOIL_CAPABILITY_UNKNOWN )
1975
	{
1976
		/*	we haven't yet checked for the capability, do so	*/
1977
		if( NULL == strstr(
1978
				(char const*)glGetString( GL_EXTENSIONS ),
1979
				"GL_EXT_texture_compression_s3tc" ) )
1980
		{
1981
			/*	not there, flag the failure	*/
1982
			has_DXT_capability = SOIL_CAPABILITY_NONE;
1983
		} else
1984
		{
1985
			/*	and find the address of the extension function	*/
1986
			P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC ext_addr = NULL;
1987
			#ifdef WIN32
1988
				ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)
1989
						wglGetProcAddress
1990
						(
1991
							"glCompressedTexImage2DARB"
1992
						);
1993
			#elif defined(__APPLE__) || defined(__APPLE_CC__)
1994
				/*	I can't test this Apple stuff!	*/
1995
				CFBundleRef bundle;
1996
				CFURLRef bundleURL =
1997
					CFURLCreateWithFileSystemPath(
1998
						kCFAllocatorDefault,
1999
						CFSTR("/System/Library/Frameworks/OpenGL.framework"),
2000
						kCFURLPOSIXPathStyle,
2001
						true );
2002
				CFStringRef extensionName =
2003
					CFStringCreateWithCString(
2004
						kCFAllocatorDefault,
2005
						"glCompressedTexImage2DARB",
2006
						kCFStringEncodingASCII );
2007
				bundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
2008
				assert( bundle != NULL );
2009
				ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)
2010
						CFBundleGetFunctionPointerForName
2011
						(
2012
							bundle, extensionName
2013
						);
2014
				CFRelease( bundleURL );
2015
				CFRelease( extensionName );
2016
				CFRelease( bundle );
2017
			#else
2018
				ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)
2019
						glXGetProcAddressARB
2020
						(
2021
							(const GLubyte *)"glCompressedTexImage2DARB"
2022
						);
2023
			#endif
2024
			/*	Flag it so no checks needed later	*/
2025
			if( NULL == ext_addr )
2026
			{
2027
				/*	hmm, not good!!  This should not happen, but does on my
2028
					laptop's VIA chipset.  The GL_EXT_texture_compression_s3tc
2029
					spec requires that ARB_texture_compression be present too.
2030
					this means I can upload and have the OpenGL drive do the
2031
					conversion, but I can't use my own routines or load DDS files
2032
					from disk and upload them directly [8^(	*/
2033
				has_DXT_capability = SOIL_CAPABILITY_NONE;
2034
			} else
2035
			{
2036
				/*	all's well!	*/
2037
				soilGlCompressedTexImage2D = ext_addr;
2038
				has_DXT_capability = SOIL_CAPABILITY_PRESENT;
2039
			}
2040
		}
2041
	}
2042
	/*	let the user know if we can do DXT or not	*/
2043
	return has_DXT_capability;
2044
}