source: trunk/src/opengl/glide/cvg/texus/write.c

Last change on this file was 6653, checked in by bird, 24 years ago

Added $Id:$ keyword.

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