1 | /*
|
---|
2 | ** THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
|
---|
3 | ** PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
|
---|
4 | ** TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
|
---|
5 | ** INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE
|
---|
6 | ** DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com).
|
---|
7 | ** THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
|
---|
8 | ** EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
|
---|
9 | ** FULL TEXT OF THE NON-WARRANTY PROVISIONS.
|
---|
10 | **
|
---|
11 | ** USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
|
---|
12 | ** RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
|
---|
13 | ** TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
|
---|
14 | ** AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
|
---|
15 | ** SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
|
---|
16 | ** THE UNITED STATES.
|
---|
17 | **
|
---|
18 | ** COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
|
---|
19 | */
|
---|
20 |
|
---|
21 | #include <stdio.h>
|
---|
22 | #include <stdlib.h>
|
---|
23 | #include <string.h>
|
---|
24 | #include <math.h>
|
---|
25 |
|
---|
26 | #include "texusint.h"
|
---|
27 |
|
---|
28 | /*
|
---|
29 | * The only two file formats we can write are: 3df and tga.
|
---|
30 | */
|
---|
31 | static char *Version = "1.1";
|
---|
32 | static char* aspect_names[] = { "8 1", "4 1", "2 1", "1 1",
|
---|
33 | "1 2", "1 4", "1 8" };
|
---|
34 |
|
---|
35 | /*************************************** tga files ****************************/
|
---|
36 | /*
|
---|
37 | * Write a tga file from an ARGB8888 mipmap.
|
---|
38 | */
|
---|
39 | static FxBool
|
---|
40 | txWriteTGA( FILE *stream, TxMip *txMip)
|
---|
41 | {
|
---|
42 |
|
---|
43 | struct {
|
---|
44 | FxU8 IDLength;
|
---|
45 | FxU8 ColorMapType;
|
---|
46 | FxU8 ImgType;
|
---|
47 | FxU8 CMapStartLo;
|
---|
48 | FxU8 CMapStartHi;
|
---|
49 | FxU8 CMapLengthLo;
|
---|
50 | FxU8 CMapLengthHi;
|
---|
51 | FxU8 CMapDepth;
|
---|
52 | FxU8 XOffSetLo;
|
---|
53 | FxU8 XOffSetHi;
|
---|
54 | FxU8 YOffSetLo;
|
---|
55 | FxU8 YOffSetHi;
|
---|
56 | FxU8 WidthLo;
|
---|
57 | FxU8 WidthHi;
|
---|
58 | FxU8 HeightLo;
|
---|
59 | FxU8 HeightHi;
|
---|
60 | FxU8 PixelDepth;
|
---|
61 | FxU8 ImageDescriptor;
|
---|
62 | } tgaHeader;
|
---|
63 |
|
---|
64 | FxU8 *data, *p;
|
---|
65 | FxU32 *data32;
|
---|
66 | int outW, outH, w, h, i;
|
---|
67 |
|
---|
68 | if (txMip->format != GR_TEXFMT_ARGB_8888) {
|
---|
69 | txPanic("TGA Image: Write: input format must be ARGB8888.");
|
---|
70 | }
|
---|
71 | if ( stream == NULL ) {
|
---|
72 | txPanic("Bad file handle");
|
---|
73 | return FXFALSE;
|
---|
74 | }
|
---|
75 |
|
---|
76 | outW = txMip->width;
|
---|
77 | outH = txMip->height;
|
---|
78 | if (txMip->depth > 1) outW += outW/2;
|
---|
79 |
|
---|
80 | tgaHeader.IDLength = 0;
|
---|
81 | tgaHeader.ColorMapType = 0;
|
---|
82 | tgaHeader.ImgType = 0x2;
|
---|
83 | tgaHeader.CMapStartLo = 0;
|
---|
84 | tgaHeader.CMapStartHi = 0;
|
---|
85 | tgaHeader.CMapLengthLo = 0;
|
---|
86 | tgaHeader.CMapLengthHi = 0;
|
---|
87 | tgaHeader.CMapDepth = 0;
|
---|
88 | tgaHeader.XOffSetLo = 0;
|
---|
89 | tgaHeader.XOffSetHi = 0;
|
---|
90 | tgaHeader.YOffSetLo = 0;
|
---|
91 | tgaHeader.YOffSetHi = 0;
|
---|
92 | tgaHeader.WidthHi = (FxU8)((outW >> 8) & 0xFF);
|
---|
93 | tgaHeader.WidthLo = (FxU8) (outW & 0xFF);
|
---|
94 | tgaHeader.HeightHi = (FxU8)((outH >> 8) & 0xFF);
|
---|
95 | tgaHeader.HeightLo = (FxU8) (outH & 0xFF);
|
---|
96 | tgaHeader.PixelDepth = 32;
|
---|
97 | tgaHeader.ImageDescriptor = 0x20; // image always right side up.
|
---|
98 |
|
---|
99 |
|
---|
100 | if ( fwrite( &tgaHeader, 1, 18, stream ) != 18 ) {
|
---|
101 | txPanic("TGA Header stream write error");
|
---|
102 | return FXFALSE;
|
---|
103 | }
|
---|
104 |
|
---|
105 | /*
|
---|
106 | * Allocate memory to hold all mipmaps, and copy the mipmaps.
|
---|
107 | */
|
---|
108 | p = data = txMalloc(outW * outH * 4);
|
---|
109 | memset(data, 0, outW * outH * 4);
|
---|
110 |
|
---|
111 | /* Copy level 0 into malloc'd area */
|
---|
112 | txRectCopy( data, outW * 4, txMip->data[0], txMip->width * 4,
|
---|
113 | txMip->width * 4, txMip->height);
|
---|
114 |
|
---|
115 | p += (txMip->width * 4);
|
---|
116 |
|
---|
117 | /* Copy the rest of the levels to the right of level 0 */
|
---|
118 | w = txMip->width;
|
---|
119 | h = txMip->height;
|
---|
120 | for (i=1; i< txMip->depth; i++) {
|
---|
121 | // printf("Copying: level = %d\n", i);
|
---|
122 | if (w > 1) w >>= 1;
|
---|
123 | if (h > 1) h >>= 1;
|
---|
124 | txRectCopy(p, outW * 4, txMip->data[i], w * 4, w * 4, h);
|
---|
125 | p += ( h * outW * 4);
|
---|
126 | }
|
---|
127 |
|
---|
128 | /* Write out the data */
|
---|
129 | data32 = (FxU32 *) data;
|
---|
130 | for (i=outW*outH; i; i--) {
|
---|
131 | putc(((*data32 ) & 0xff) , stream);
|
---|
132 | putc(((*data32 >> 8) & 0xff) , stream);
|
---|
133 | putc(((*data32 >> 16) & 0xff) , stream);
|
---|
134 | putc(((*data32 >> 24) & 0xff) , stream);
|
---|
135 | data32++;
|
---|
136 | }
|
---|
137 | return FXTRUE;
|
---|
138 | }
|
---|
139 |
|
---|
140 |
|
---|
141 | /*************************************** 3df files ****************************/
|
---|
142 | /* Write word, msb first */
|
---|
143 |
|
---|
144 | static FxBool
|
---|
145 | _txWrite16 (FILE *stream, FxU16 data)
|
---|
146 | {
|
---|
147 | FxU8 byte[2];
|
---|
148 |
|
---|
149 | byte[0] = (FxU8) ((data >> 8) & 0xFF);
|
---|
150 | byte[1] = (FxU8) ((data ) & 0xFF);
|
---|
151 |
|
---|
152 | return (fwrite (byte, 2, 1, stream) != 1) ? FXFALSE : FXTRUE;
|
---|
153 | }
|
---|
154 |
|
---|
155 | /* Write long word, msb first */
|
---|
156 |
|
---|
157 | static FxBool
|
---|
158 | _txWrite32 (FILE *stream, FxU32 data)
|
---|
159 | {
|
---|
160 | FxU8 byte[4];
|
---|
161 |
|
---|
162 | byte[0] = (FxU8) ((data >> 24) & 0xFF);
|
---|
163 | byte[1] = (FxU8) ((data >> 16) & 0xFF);
|
---|
164 | byte[2] = (FxU8) ((data >> 8) & 0xFF);
|
---|
165 | byte[3] = (FxU8) ((data ) & 0xFF);
|
---|
166 |
|
---|
167 | return (fwrite (byte, 4, 1, stream) != 1) ? FXFALSE : FXTRUE;
|
---|
168 | }
|
---|
169 |
|
---|
170 | /* Write NCC table */
|
---|
171 | static FxBool
|
---|
172 | _txWrite3dfNCCTable (FILE *stream, FxU32 *yab)
|
---|
173 | {
|
---|
174 | int i;
|
---|
175 |
|
---|
176 | for (i = 0; i < 16; i++)
|
---|
177 | if (!_txWrite16 (stream, (FxU16) (yab[i] & 0x00ff))) return FXFALSE;
|
---|
178 |
|
---|
179 | for (i = 0; i < 12; i++)
|
---|
180 | if (!_txWrite16 (stream, (FxU16) (yab[16+i] & 0xffff))) return FXFALSE;
|
---|
181 |
|
---|
182 | for (i = 0; i < 12; i++)
|
---|
183 | if (!_txWrite16 (stream, (FxU16) (yab[28+i] & 0xffff))) return FXFALSE;
|
---|
184 |
|
---|
185 | return FXTRUE;
|
---|
186 | }
|
---|
187 |
|
---|
188 | static FxBool
|
---|
189 | _txWrite3dfPalTable (FILE *stream, FxU32 *pal)
|
---|
190 | {
|
---|
191 | int i;
|
---|
192 |
|
---|
193 | for (i=0; i<256; i++) {
|
---|
194 | if (!_txWrite32 (stream, pal[i])) return FXFALSE;
|
---|
195 | }
|
---|
196 | return FXTRUE;
|
---|
197 | }
|
---|
198 |
|
---|
199 | static FxBool
|
---|
200 | txWrite3df (FILE *stream, TxMip *txMip)
|
---|
201 | {
|
---|
202 | FxU32 i;
|
---|
203 | FxU32 n_pixels;
|
---|
204 | int small_lod, large_lod, aspect;
|
---|
205 |
|
---|
206 | /* Write out the header */
|
---|
207 | large_lod = (txMip->width > txMip->height) ? txMip->width : txMip->height;
|
---|
208 | small_lod = large_lod >> (txMip->depth - 1);
|
---|
209 | aspect = txAspectRatio(txMip->width, txMip->height);
|
---|
210 |
|
---|
211 | // printf("Format = %d\n", txMip->format);
|
---|
212 | // printf("Format = %s\n", Format_Name[txMip->format]);
|
---|
213 |
|
---|
214 | // printf("Writing header...\n");
|
---|
215 | if (EOF == fprintf (stream,
|
---|
216 | "3df v%s\n%s\nlod range: %d %d\naspect ratio: %s\n",
|
---|
217 | Version,
|
---|
218 | Format_Name[txMip->format],
|
---|
219 | small_lod,
|
---|
220 | large_lod,
|
---|
221 | aspect_names[aspect])) return FXFALSE;
|
---|
222 |
|
---|
223 | /* write out ncc table if necessary */
|
---|
224 | // printf("Writing NCC...\n");
|
---|
225 | if ((txMip->format == GR_TEXFMT_YIQ_422) ||
|
---|
226 | (txMip->format == GR_TEXFMT_AYIQ_8422)) {
|
---|
227 | if (!_txWrite3dfNCCTable (stream, txMip->pal)) return FXFALSE;
|
---|
228 | }
|
---|
229 |
|
---|
230 | else if ((txMip->format == GR_TEXFMT_P_8) ||
|
---|
231 | (txMip->format == GR_TEXFMT_AP_88)) {
|
---|
232 | if (!_txWrite3dfPalTable (stream, txMip->pal)) return FXFALSE;
|
---|
233 | }
|
---|
234 |
|
---|
235 |
|
---|
236 | /* write out mipmap image data */
|
---|
237 | // printf("Writing mipmaps (%d bytes)...\n", txMip->size);
|
---|
238 | if (txMip->format < GR_TEXFMT_16BIT) {
|
---|
239 | n_pixels = txMip->size;
|
---|
240 | if (n_pixels != fwrite (txMip->data[0], 1, n_pixels, stream)) {
|
---|
241 | printf("Bad Bad Bad!\n");
|
---|
242 | return FXFALSE;
|
---|
243 | }
|
---|
244 | }
|
---|
245 | else if (txMip->format < GR_TEXFMT_32BIT) {
|
---|
246 | FxU16* data = (FxU16 *) txMip->data[0];
|
---|
247 | n_pixels = txMip->size >> 1;
|
---|
248 |
|
---|
249 | for (i = 0; i < n_pixels; i ++)
|
---|
250 | if (FXFALSE == _txWrite16 (stream, *data++)) return FXFALSE;
|
---|
251 | }
|
---|
252 | else {
|
---|
253 | FxU32* data = (FxU32*) txMip->data[0];
|
---|
254 | n_pixels = txMip->size >> 2;
|
---|
255 |
|
---|
256 | for (i = 0; i < n_pixels; i ++)
|
---|
257 | if (FXFALSE == _txWrite32 (stream, *data++)) return FXFALSE;
|
---|
258 | }
|
---|
259 | return FXTRUE;
|
---|
260 | }
|
---|
261 |
|
---|
262 | void
|
---|
263 | txMipWrite(TxMip *txMip, char *file, char *ext, int split)
|
---|
264 | {
|
---|
265 | int tgaformat;
|
---|
266 | FILE *stream;
|
---|
267 | char filename[128];
|
---|
268 | int i, w, h;
|
---|
269 | TxMip splitImg;
|
---|
270 |
|
---|
271 | if ((txMip->width & (txMip->width - 1)) ||
|
---|
272 | (txMip->height & (txMip->height - 1))) {
|
---|
273 | txPanic("txMipWrite: size not power of 2!");
|
---|
274 | }
|
---|
275 |
|
---|
276 | if (strcmp(ext, ".tga") && strcmp(ext, ".3df")) {
|
---|
277 | txPanic("txMipWrite: Bad output format");
|
---|
278 | }
|
---|
279 |
|
---|
280 | tgaformat = (strcmp(ext, ".tga") == 0);
|
---|
281 | if (tgaformat && (txMip->format != GR_TEXFMT_ARGB_8888)) {
|
---|
282 | txPanic("txMipWrite: TGA format must be ARGB_8888");
|
---|
283 | }
|
---|
284 |
|
---|
285 | /* If not split, write out a single file */
|
---|
286 | if (!split) {
|
---|
287 | strcpy(filename, file);
|
---|
288 | strcat(filename, ext);
|
---|
289 | if( txVerbose )
|
---|
290 | {
|
---|
291 | printf("Writing file \"%s\" (format: %s)\n",
|
---|
292 | filename, Format_Name[txMip->format]);
|
---|
293 | }
|
---|
294 | stream = fopen(filename, "wb");
|
---|
295 | if (stream == NULL) {
|
---|
296 | txPanic("Unable to open output file.");
|
---|
297 | }
|
---|
298 | if (tgaformat) {
|
---|
299 | if (!txWriteTGA( stream, txMip)) {
|
---|
300 | txPanic("txMipWrite: Write failed.");
|
---|
301 | }
|
---|
302 | } else {
|
---|
303 | if (!txWrite3df( stream, txMip)) {
|
---|
304 | txPanic("txMipWrite: Write failed.");
|
---|
305 | }
|
---|
306 | }
|
---|
307 | fclose(stream);
|
---|
308 | return;
|
---|
309 | }
|
---|
310 |
|
---|
311 | /* Otherwise, we need to write out separate output files */
|
---|
312 | w = txMip->width;
|
---|
313 | h = txMip->height;
|
---|
314 |
|
---|
315 | for (i=0; i<txMip->depth; i++) {
|
---|
316 | char suffix[2];
|
---|
317 |
|
---|
318 | splitImg = *txMip; // Copy everything first, including palette.
|
---|
319 |
|
---|
320 | // Then change stuff.
|
---|
321 | splitImg.format = txMip->format;
|
---|
322 | splitImg.width = w;
|
---|
323 | splitImg.height = h;
|
---|
324 | splitImg.size = w * h * GR_TEXFMT_SIZE( txMip->format );
|
---|
325 | splitImg.depth = 1;
|
---|
326 | splitImg.data[0] = txMip->data[i];
|
---|
327 |
|
---|
328 | // manufacture a new name.
|
---|
329 | suffix[0] = '0' + i;
|
---|
330 | suffix[1] = 0;
|
---|
331 | strcpy(filename, file);
|
---|
332 | strcat(filename, suffix);
|
---|
333 | strcat(filename, ext);
|
---|
334 | stream = fopen(filename, "wb");
|
---|
335 | if (stream == NULL) {
|
---|
336 | txPanic("Unable to open output file.");
|
---|
337 | }
|
---|
338 | if (tgaformat) {
|
---|
339 | if (!txWriteTGA( stream, &splitImg)) {
|
---|
340 | txPanic("txMipWrite: Write failed.");
|
---|
341 | }
|
---|
342 | } else {
|
---|
343 | if (!txWrite3df( stream, &splitImg)) {
|
---|
344 | txPanic("txMipWrite: Write failed.");
|
---|
345 | }
|
---|
346 | }
|
---|
347 | fclose(stream);
|
---|
348 | if (w > 1) w >>= 1;
|
---|
349 | if (h > 1) h >>= 1;
|
---|
350 | }
|
---|
351 | }
|
---|
352 |
|
---|
353 | FxBool txWrite( Gu3dfInfo *info, FILE *fp, FxU32 flags )
|
---|
354 | {
|
---|
355 | TxMip mip;
|
---|
356 |
|
---|
357 | mip.format = info->header.format;
|
---|
358 | mip.width = info->header.width;
|
---|
359 | mip.height = info->header.height;
|
---|
360 | #ifdef GLIDE3
|
---|
361 | mip.depth = info->header.large_lod - info->header.small_lod + 1;
|
---|
362 | #else
|
---|
363 | mip.depth = info->header.small_lod - info->header.large_lod + 1;
|
---|
364 | #endif
|
---|
365 | mip.size = info->mem_required;
|
---|
366 | mip.data[0] = info->data;
|
---|
367 | if( mip.format == GR_TEXFMT_P_8 || mip.format == GR_TEXFMT_AP_88 )
|
---|
368 | {
|
---|
369 | memcpy( mip.pal, info->table.palette.data, sizeof( FxU32 ) * 256 );
|
---|
370 | }
|
---|
371 | if( mip.format == GR_TEXFMT_YIQ_422 || mip.format == GR_TEXFMT_AYIQ_8422 )
|
---|
372 | {
|
---|
373 | txNccToPal( mip.pal, &info->table.nccTable);
|
---|
374 | }
|
---|
375 | switch( flags & TX_WRITE_MASK )
|
---|
376 | {
|
---|
377 | case TX_WRITE_3DF:
|
---|
378 | if( !txWrite3df( fp, &mip ) )
|
---|
379 | return FXFALSE;
|
---|
380 | break;
|
---|
381 | case TX_WRITE_TGA:
|
---|
382 | if( mip.format == GR_TEXFMT_YIQ_422 ||
|
---|
383 | mip.format == GR_TEXFMT_AYIQ_8422 )
|
---|
384 | {
|
---|
385 | txPanic( "Don't know how to write NCC textures\n" );
|
---|
386 | }
|
---|
387 | if( !txWriteTGA( fp, &mip ) )
|
---|
388 | return FXFALSE;
|
---|
389 | break;
|
---|
390 | default:
|
---|
391 | txPanic( "Unknown texture write format" );
|
---|
392 | break;
|
---|
393 | }
|
---|
394 | return FXTRUE;
|
---|
395 | }
|
---|