1 //-----------------------------------------------------------------------------
2 //
3 // ImageLib Sources
4 // Copyright (C) 2000-2009 by Denton Woods
5 // Last modified: 01/19/2009
6 //
7 // Filename: src-IL/src/il_nvidia.cpp
8 //
9 // Description: Implements access to the nVidia Texture Tools library.
10 //
11 //-----------------------------------------------------------------------------
12 
13 
14 #include "il_internal.h"
15 #include "il_dds.h"
16 #include "il_manip.h"
17 #include <limits.h>
18 
19 
20 #ifdef IL_USE_DXTC_NVIDIA
21 #include <nvtt/nvtt.h>
22 
23 using namespace nvtt;
24 
25 #if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
26 	#if defined(_MSC_VER) || defined(__BORLANDC__)
27 		#ifndef _DEBUG
28 			#pragma comment(lib, "nvcore.lib")
29 			#pragma comment(lib, "nvtt.lib")
30 		#else
31 			#pragma comment(lib, "nvcore-d.lib")
32 			#pragma comment(lib, "nvtt-d.lib")
33 		#endif
34 	#endif
35 #endif
36 
37 
38 struct ilOutputHandlerMem : public nvtt::OutputHandler
39 {
ilOutputHandlerMemilOutputHandlerMem40 	ilOutputHandlerMem(ILuint Width, ILuint Height, ILenum DxtType)
41 	{
42 		Width = Width + (4 - (Width % 4)) % 4;    // Operates on 4x4 blocks,
43 		Height = Height + (4 - (Height % 4)) % 4; //  so gives extra room.
44 
45 		switch (DxtType)
46 		{
47 			case IL_DXT1:
48 			case IL_DXT1A:
49 				Size = Width * Height / 2;
50 				break;
51 			case IL_DXT3:
52 			case IL_DXT5:
53 				Size = Width * Height;
54 				break;
55 
56 			default:  // NVTT does not accept DXT2 or DXT4.
57 				// Should error somehow...
58 				break;
59 		}
60 		NewData = (ILubyte*)ialloc(Size);
61 		if (NewData == NULL)
62 			return;
63 		Temp = NewData;
64 	}
65 
beginImageilOutputHandlerMem66 	virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
67 	{
68 		// ignore.
69 	}
writeDatailOutputHandlerMem70 	virtual bool writeData(const void *data, int size)
71 	{
72 		memcpy(Temp, data, size);
73 		Temp += size;
74 		return true;
75 	}
76 
77 	ILubyte	*NewData, *Temp;
78 	ILuint	Size;
79 };
80 
81 
82 //! Compresses data to a DXT format using nVidia's Texture Tools library.
83 //  The data must be in unsigned byte RGBA format.  The alpha channel will be ignored if DxtType is IL_DXT1.
84 //  DxtSize is used to return the size in bytes of the DXTC data returned.
ilNVidiaCompressDXT(ILubyte * Data,ILuint Width,ILuint Height,ILuint Depth,ILenum DxtFormat,ILuint * DxtSize)85 ILAPI ILubyte* ILAPIENTRY ilNVidiaCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat, ILuint *DxtSize)
86 {
87 	if (Data == NULL) {  // We cannot operate on a null pointer.
88 		ilSetError(IL_INVALID_PARAM);
89 		return NULL;
90 	}
91 
92 	// The nVidia Texture Tools library does not support volume textures yet.
93 	if (Depth != 1) {
94 		ilSetError(IL_INVALID_PARAM);
95 		return NULL;
96 	}
97 
98 	InputOptions inputOptions;
99 	inputOptions.setTextureLayout(TextureType_2D, Width, Height);
100 	inputOptions.setMipmapData(Data, Width, Height);
101 	inputOptions.setMipmapGeneration(false, -1);  //@TODO: Use this in certain cases.
102 
103 	OutputOptions outputOptions;
104 	ilOutputHandlerMem outputHandler(Width, Height, DxtFormat);
105 	outputOptions.setOutputHeader(false);
106 	outputOptions.setOutputHandler(&outputHandler);
107 
108 	if (outputHandler.NewData == NULL)
109 		return NULL;
110 
111 	CompressionOptions compressionOptions;
112 	switch (DxtFormat)
113 	{
114 		case IL_DXT1:
115 			compressionOptions.setFormat(Format_DXT1);
116 			break;
117 		case IL_DXT1A:
118 			compressionOptions.setFormat(Format_DXT1a);
119 			break;
120 		case IL_DXT3:
121 			compressionOptions.setFormat(Format_DXT1);
122 			break;
123 		case IL_DXT5:
124 			compressionOptions.setFormat(Format_DXT5);
125 			break;
126 		default:  // Does not support DXT2 or DXT4.
127 			ilSetError(IL_INVALID_PARAM);
128 			break;
129 	}
130 
131 	Compressor compressor;
132 	compressor.process(inputOptions, compressionOptions, outputOptions);
133 
134 	*DxtSize = outputHandler.Size;
135 	return outputHandler.NewData;
136 }
137 
138 
139 
140 //
141 //
142 // The following is just a repeat of above, but it works generically on file streams or lumps.
143 //  @TODO: Merge these two together.
144 //
145 //
146 
147 
148 struct ilOutputHandlerFile : public nvtt::OutputHandler
149 {
ilOutputHandlerFileilOutputHandlerFile150 	ilOutputHandlerFile(ILuint Width, ILuint Height, ILenum DxtType)
151 	{
152 		return;
153 	}
154 
beginImageilOutputHandlerFile155 	virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
156 	{
157 		// ignore.
158 	}
writeDatailOutputHandlerFile159 	virtual bool writeData(const void *data, int size)
160 	{
161 		if (iwrite(data, 1, size) == size)
162 			return true;
163 		return false;
164 	}
165 
166 };
167 
168 
169 //! Compresses data to a DXT format using nVidia's Texture Tools library.
170 //  This version is supposed to be completely internal to DevIL.
171 //  The data must be in unsigned byte RGBA format.  The alpha channel will be ignored if DxtType is IL_DXT1.
ilNVidiaCompressDXTFile(ILubyte * Data,ILuint Width,ILuint Height,ILuint Depth,ILenum DxtFormat)172 ILuint ilNVidiaCompressDXTFile(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat)
173 {
174 	ILuint FilePos = itellw();
175 
176 	// The nVidia Texture Tools library does not support volume textures yet.
177 	if (Depth != 1) {
178 		ilSetError(IL_INVALID_PARAM);
179 		return 0;
180 	}
181 
182 	InputOptions inputOptions;
183 	inputOptions.setTextureLayout(TextureType_2D, Width, Height);
184 	inputOptions.setMipmapData(Data, Width, Height);
185 	inputOptions.setMipmapGeneration(false, -1);  //@TODO: Use this in certain cases.
186 
187 	OutputOptions outputOptions;
188 	ilOutputHandlerFile outputHandler(Width, Height, DxtFormat);
189 	outputOptions.setOutputHeader(false);
190 	outputOptions.setOutputHandler(&outputHandler);
191 
192 	CompressionOptions compressionOptions;
193 	switch (DxtFormat)
194 	{
195 		case IL_DXT1:
196 			compressionOptions.setFormat(Format_DXT1);
197 			break;
198 		case IL_DXT1A:
199 			compressionOptions.setFormat(Format_DXT1a);
200 			break;
201 		case IL_DXT3:
202 			compressionOptions.setFormat(Format_DXT1);
203 			break;
204 		case IL_DXT5:
205 			compressionOptions.setFormat(Format_DXT5);
206 			break;
207 		default:  // Does not support DXT2 or DXT4.
208 			ilSetError(IL_INVALID_PARAM);
209 			break;
210 	}
211 
212 	Compressor compressor;
213 	compressor.process(inputOptions, compressionOptions, outputOptions);
214 
215 	return itellw() - FilePos;  // Return the number of characters written.
216 }
217 
218 #else
219 // Let's have this so that the function is always created and exported, even if it does nothing.
ilNVidiaCompressDXT(ILubyte * Data,ILuint Width,ILuint Height,ILuint Depth,ILenum DxtFormat,ILuint * DxtSize)220 ILAPI ILubyte* ILAPIENTRY ilNVidiaCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DxtFormat, ILuint *DxtSize)
221 {
222 	//@TODO: Do we need to set an error message?
223 	return NULL;
224 }
225 
226 #endif//IL_NO_DXTC_NVIDIA
227