Subversion Repositories gelsvn

Rev

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