423 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			423 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | ||
| **	Command & Conquer Red Alert(tm)
 | ||
| **	Copyright 2025 Electronic Arts Inc.
 | ||
| **
 | ||
| **	This program is free software: you can redistribute it and/or modify
 | ||
| **	it under the terms of the GNU General Public License as published by
 | ||
| **	the Free Software Foundation, either version 3 of the License, or
 | ||
| **	(at your option) any later version.
 | ||
| **
 | ||
| **	This program is distributed in the hope that it will be useful,
 | ||
| **	but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||
| **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||
| **	GNU General Public License for more details.
 | ||
| **
 | ||
| **	You should have received a copy of the GNU General Public License
 | ||
| **	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||
| */
 | ||
| 
 | ||
| /* $Header: g:/library/wwlib32/file/rcs/writelbm.cpp 1.1 1994/04/20 14:38:57 scott_bowen Exp $ */
 | ||
| /***************************************************************************
 | ||
|  **   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
 | ||
|  ***************************************************************************
 | ||
|  *                                                                         *
 | ||
|  *                 Project Name : Write LBM File                           *
 | ||
|  *                                                                         *
 | ||
|  *                    File Name : writelbm.c                               *
 | ||
|  *                                                                         *
 | ||
|  *                   Programmer : Scott Bowen                              *
 | ||
|  *                                                                         *
 | ||
|  *                   Start Date :  November 18, 1991                       *
 | ||
|  *                                                                         *
 | ||
|  *                  Last Update : November 19, 1991   [SB]                 *
 | ||
|  *                                                                         *
 | ||
|  *-------------------------------------------------------------------------*
 | ||
|  * Functions:                                                              *
 | ||
|  *   Get_Line -- convert one plane of one row to a packed plane            *
 | ||
|  *   Write_BMHD -- writes out the bit map header (LocalHeader)             *
 | ||
|  *   Write_Body -- writes out compressed data in an LBM file               *
 | ||
|  *   Write_CMAP -- Writes out CMAP (palette) information                   *
 | ||
|  *   Write_LBM_File -- Writes out a file in LBM format                     *
 | ||
|  *   Write_Row -- compresses and writes a row plane to .lbm file           *
 | ||
|  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | ||
| 
 | ||
| 
 | ||
| // At the end of this file there is an IFF definition for a .LBM file.
 | ||
| 
 | ||
| #include <wwstd.h>
 | ||
| #include "iff.h"
 | ||
| #include "file.h"
 | ||
| #include <stdio.h>
 | ||
| #include <string.h>
 | ||
| 
 | ||
| 
 | ||
| 	// A BitMapHeader is stored in a BMHD chunk.  This structure MUST be an even size
 | ||
| typedef struct {
 | ||
|     UWORD w, h;							// raster width & height in pixels 
 | ||
|     UWORD x, y;							// position for this image
 | ||
|     UBYTE planes;							// # source bitplanes 
 | ||
|     UBYTE masking;						// masking technique 
 | ||
|     UBYTE compression;					// compression algoithm
 | ||
|     UBYTE pad1;							// UNUSED.  For consistency, put 0 here.
 | ||
|     UWORD transcolor;					// transparent "color number"
 | ||
|     UBYTE xaspect, yaspect;			// aspect ratio, a rational number x/y
 | ||
|     UWORD pagewidth, pageheight;		// source "page" size in pixels
 | ||
| } BitMapHeaderType;
 | ||
| 
 | ||
| 
 | ||
| // All values in LocalHeader are always the same except planes.  This is set in Write_BMHD
 | ||
| // the WORD values must be in low-high order for compatibility.
 | ||
| 
 | ||
| PRIVATE BitMapHeaderType LocalHeader = {
 | ||
| 	0x4001, 0xc800, 0, 0, 0, 0,		// width, height, x, y, planes, mask
 | ||
| 	1,   0, 0xFF00, 5, 6, 				// compress, pad1, transcolor, xasptect, yaspect
 | ||
| 	0x4001,	0xC800 };					// pagewidth, pageheight
 | ||
| 
 | ||
| 	
 | ||
| 	// Used to verify that the write of the header was valid
 | ||
| #define BM_HEADER_SIZE		(((sizeof(BitMapHeaderType) + 1) & 0xFFFE) + 8L)
 | ||
| 
 | ||
| 
 | ||
| /*=========================================================================*/
 | ||
| /* The following PRIVATE functions are in this file:                       */
 | ||
| /*=========================================================================*/
 | ||
| 
 | ||
| PRIVATE LONG Write_BMHD(WORD lbmhandle, WORD bitplanes);
 | ||
| PRIVATE LONG Write_CMAP(WORD lbmhandle, UBYTE * palette, WORD bitplanes);
 | ||
| PRIVATE LONG Write_BODY(WORD lbmhandle, BufferClass& buff, WORD bitplanes);
 | ||
| PRIVATE LONG Write_Row(WORD lbmhandle, UBYTE *buffer);
 | ||
| 
 | ||
| 
 | ||
| /*= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
 | ||
| 
 | ||
| /***************************************************************************
 | ||
|  * WRITE_LBM_FILE -- Writes out a file in LBM format                       *
 | ||
|  *                                                                         *
 | ||
|  * INPUT:  WORD lbmhandle -- lbm file handle already opened by caller      *
 | ||
|  *         BufferClass buff -- buff where MCGA picture is                     *
 | ||
|  *         WORD bitplane -- number of bitplanes to convert to              *
 | ||
|  *         BYTE *palette -- pointer to palette for buff                    *
 | ||
|  *                                                                         *
 | ||
|  * OUTPUT: Returns BOOL -- successfull or not                              *
 | ||
|  *                                                                         *
 | ||
|  * WARNINGS:                                                               *
 | ||
|  *                                                                         *
 | ||
|  * HISTORY:                                                                *
 | ||
|  *   11/18/1991  SB : Created.                                             *
 | ||
|  *=========================================================================*/
 | ||
| 
 | ||
| PUBLIC BOOL Write_LBM_File(WORD lbmhandle, BufferClass& buff, WORD bitplanes, UBYTE *palette)
 | ||
| {
 | ||
| 	LONG filesize;
 | ||
| 
 | ||
| 
 | ||
| 	Seek_File(lbmhandle, 0L, SEEK_SET);						// goto beginning of file 
 | ||
| 																
 | ||
| 	Write_File(lbmhandle, "FORM????ILBM", 12L);			// First 12 bytes of all .lbm files 
 | ||
| 																		// size is unkown so write ????
 | ||
| 	filesize = 12L; 												// 4 bytes for "ILBM" 
 | ||
| 
 | ||
| 	filesize += Write_BMHD(lbmhandle, bitplanes);		// write out BMHD (fixed size)
 | ||
| 	filesize += Write_CMAP(lbmhandle, palette, bitplanes);	// write out CMAP 
 | ||
| 
 | ||
| 		// Write out the body, or compressed picture image.  This size will depend
 | ||
| 		// on the compression, but the value passed back is what the compressor
 | ||
| 		// assumed was written to file
 | ||
| 
 | ||
| 	filesize += Write_BODY(lbmhandle, buff, bitplanes);
 | ||
| 
 | ||
| 		// Verify that we were able to write out the file without running out of space
 | ||
| 	if (Seek_File(lbmhandle, 0L, SEEK_END) != filesize) {
 | ||
| 		return(FALSE);
 | ||
| 	}
 | ||
| 
 | ||
| 	Seek_File(lbmhandle, 4L, SEEK_SET);						// goto beginning of file 
 | ||
| 	filesize = Reverse_LONG(filesize - 8L);				// - 8 because of "FORM" + WORD (size)
 | ||
| 	Write_File(lbmhandle, (BYTE *) &filesize, 4L);		// patch in filesize 
 | ||
| 
 | ||
| 	return(TRUE);
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /***************************************************************************
 | ||
|  * WRITE_BMHD -- writes out the bit map header (LocalHeader)               *
 | ||
|  *                                                                         *
 | ||
|  * INPUT:  WORD lbmhandle -- file handle for lbm file                      *
 | ||
|  *         WORD pitplanes -- number of bitplanes to write out              *
 | ||
|  *                                                                         *
 | ||
|  * OUTPUT: LONG number of bytes hopefully written out to .LBM file         *
 | ||
|  *                                                                         *
 | ||
|  * WARNINGS:                                                               *
 | ||
|  *                                                                         *
 | ||
|  * HISTORY:                                                                *
 | ||
|  *   11/19/1991  SB : Created.                                             *
 | ||
|  *=========================================================================*/
 | ||
| PRIVATE LONG Write_BMHD(WORD lbmhandle, WORD bitplanes)
 | ||
| {
 | ||
| 	LONG size;
 | ||
| 	
 | ||
| 	Write_File(lbmhandle, "BMHD", 4L);					// write out chunk title 
 | ||
| 	size = Reverse_LONG(sizeof(LocalHeader));			// write out size of LocalHeader chunk
 | ||
| 	Write_File(lbmhandle, (BYTE *) &size, 4L);
 | ||
| 
 | ||
| 	LocalHeader.planes	= bitplanes;					// only nonconstant value in LocalHeader
 | ||
| 
 | ||
| 		// Make sure size is even. Return 8 = "BMHD" + size of the bitmap header structure
 | ||
| 
 | ||
| 	return(Write_File(lbmhandle, (BYTE *) &LocalHeader,
 | ||
| 	                 (sizeof(LocalHeader) + 1) & 0xFFFE) + 8L);
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /***************************************************************************
 | ||
|  * WRITE_CMAP -- Writes out CMAP (palette) information                     *
 | ||
|  *                                                                         *
 | ||
|  *                                                                         *
 | ||
|  * INPUT:  WORD lbmhandle -- file handle of lbm file                       *
 | ||
|  *         BYTE * palette -- pointer to paletter information       			*
 | ||
|  *         WORD bitplanes -- used to figure out size of palette            *
 | ||
|  *                                                                         *
 | ||
|  * OUTPUT: LONG number of bytes that should have been written out to .LBM. *
 | ||
|  *                                                                         *
 | ||
|  * WARNINGS:                                                               *
 | ||
|  *                                                                         *
 | ||
|  * HISTORY:                                                                *
 | ||
|  *   11/19/1991  SB : Created.                                             *
 | ||
|  *=========================================================================*/
 | ||
| 
 | ||
| PRIVATE LONG Write_CMAP(WORD lbmhandle, UBYTE * palette, WORD bitplanes)
 | ||
| {
 | ||
| 	WORD color, r, g, b, colors;
 | ||
| 	LONG size;
 | ||
| 	UBYTE *pal_ptr;
 | ||
| 	BYTE rgb[3];
 | ||
| 
 | ||
| 
 | ||
| 	Write_File(lbmhandle, "CMAP", 4L);						// write out palette info
 | ||
| 	colors = 1 << bitplanes;									// colors = 2 to the bitplanes
 | ||
| 	size = Reverse_LONG(colors * 3L);						// size = colors * 3 guns
 | ||
| 
 | ||
|  	Write_File(lbmhandle, (BYTE *) &size, 4L);
 | ||
| 
 | ||
| 	for (pal_ptr = palette, color = 0; color < colors; color++) { // for each color
 | ||
| 
 | ||
| 		if ((r = *pal_ptr++) != 0) {			// DPaint changes allows 0 - 100 for gun values		
 | ||
| 			r = (r << 2) | 0x03;					// this must be converted to 0 - 256 for LBM
 | ||
| 		}												// so LBM_val = (DP_val * 4) | 3 if DP_val != 0
 | ||
| 		if ((g = *pal_ptr++) != 0) {			
 | ||
| 			g = (g << 2) | 0x03;
 | ||
| 		}
 | ||
| 		if ((b = *pal_ptr++) != 0) {
 | ||
| 			b = (b << 2) | 0x03;
 | ||
| 		}
 | ||
| 		rgb[0] = r;									// assign gun values to an array to write out
 | ||
| 		rgb[1] = g;
 | ||
| 		rgb[2] = b;
 | ||
| 		
 | ||
| 		Write_File(lbmhandle, rgb, 3L);
 | ||
| 	}
 | ||
| 														// size = colors * 3
 | ||
| 	return(((colors << 1) + colors) + 8L);	// total size of CMAP 8 = "CMAP" + WORD (size)
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /***************************************************************************
 | ||
|  * WRITE_BODY -- writes out compressed data in an LBM file                 *
 | ||
|  *                                                                         *
 | ||
|  * INPUT: WORD lbmhandle -- file handle of lbm file                        *
 | ||
|  *                                                                         *
 | ||
|  * OUTPUT: LONG - number of byte written                                   *
 | ||
|  *  	                                                                     *
 | ||
|  * WARNINGS:                                                               *
 | ||
|  *                                                                         *
 | ||
|  * HISTORY:                                                                *
 | ||
|  *   11/19/1991  SB : Created.                                             *
 | ||
|  *=========================================================================*/
 | ||
| 
 | ||
| PRIVATE LONG Write_BODY(WORD lbmhandle, BufferClass& buff, WORD bitplanes)
 | ||
| {
 | ||
| 	LONG bodysize = 0;
 | ||
| 	LONG actualsize;
 | ||
| 	LONG size;
 | ||
| 	WORD planebit;
 | ||
| 	WORD line, plane;
 | ||
| 	UBYTE buffer[40];
 | ||
| 	UBYTE *buffptr;
 | ||
| 
 | ||
| 	Write_File(lbmhandle, "BODY????", 8L);		// BODY chunk ID, ???? reserved for chuncksize 
 | ||
| 
 | ||
| 	buffptr = (UBYTE *) buff.Get_Buffer();						// point to beginning of buff
 | ||
| 
 | ||
| 	for (line = 0; line < 200; line++) {
 | ||
| 		planebit = 1;											// start with bit 1 set 
 | ||
| 
 | ||
| 		for (plane = 0; plane < bitplanes; plane++) {
 | ||
| 			Pack_2_Plane(buffer, buffptr, planebit);	// convert to planar
 | ||
| 			bodysize += Write_Row(lbmhandle, buffer); // write to to the BODY in the LBM
 | ||
| 
 | ||
| 			planebit <<= 1;									// set next bit
 | ||
| 		}
 | ||
| 
 | ||
| 		buffptr += 320;										// row size is 320
 | ||
| 	}
 | ||
| 
 | ||
| 	actualsize = bodysize + (bodysize&0x01);
 | ||
| 
 | ||
| 	if (actualsize != bodysize) {
 | ||
| 		Write_File(lbmhandle, buffer, 1);		// Padd the block.
 | ||
| 	}
 | ||
| 
 | ||
| 	Seek_File(lbmhandle, -(actualsize + 4L), SEEK_CUR);		// Patch in chunksize
 | ||
| 	size = Reverse_LONG(bodysize);
 | ||
| 	Write_File(lbmhandle, (BYTE *) &size ,4L);			
 | ||
| 
 | ||
| 	return(actualsize + 8L);		// total size of BODY,  "BODY????" = 8 bytes
 | ||
| }
 | ||
| 
 | ||
| /***************************************************************************
 | ||
|  * WRITE_ROW -- compresses and writes a row plane to .lbm file             *
 | ||
|  *                                                                         *
 | ||
|  * INPUT:  WORD lbmhandle -- lbm file handle                               *
 | ||
|  *         UBYTE *buffer -- pointer to buffer to be written out            *
 | ||
|  *                                                                         *
 | ||
|  * OUTPUT: LONG size of chunk that should have been written out            *
 | ||
|  *                                                                         *
 | ||
|  * WARNINGS:                                                               *
 | ||
|  *                                                                         *
 | ||
|  * HISTORY:                                                                *
 | ||
|  *   11/19/1991  SB : Created.                                             *
 | ||
|  *=========================================================================*/
 | ||
| // this algorithm was taken from WILBM.c written by EA that was in the
 | ||
| // 1985 yearbook.  This is the compression method that DP.EXE uses.
 | ||
| // Change only if DP.EXE changes.
 | ||
| 
 | ||
| PRIVATE LONG Write_Row(WORD lbmhandle, UBYTE *buffer)
 | ||
| {
 | ||
| 	WORD i;
 | ||
| 	WORD chunksize = 0;
 | ||
| 	WORD dataLength = 40;	  					// 320 rows / 8 ( 1 plane per row)
 | ||
| 	UBYTE repCode, current, curr_plus_2;
 | ||
| 	UBYTE *buffptr;
 | ||
| 
 | ||
| 	while (dataLength) {
 | ||
| 
 | ||
|   		// If at least 2 more bytes and they are equal, then replicate 
 | ||
| 
 | ||
| 		if ((dataLength >= 2) && (buffer[0] == buffer[1])) {
 | ||
| 			buffptr = buffer;
 | ||
| 			for (i = 0; (i <= 128) &&  (i < (dataLength - 1)); i++) {
 | ||
| 				if (*buffptr != buffptr[1]) {
 | ||
| 					break;
 | ||
| 				}
 | ||
| 				buffptr++;
 | ||
| 			}
 | ||
| 			i++;
 | ||
| 			repCode = -i + 1;
 | ||
| 			Write_File(lbmhandle, &repCode, 1L);			// Write count as -count+1
 | ||
| 			Write_File(lbmhandle, buffer,   1L);			// Write byte to replicate
 | ||
| 			buffer += i;
 | ||
| 			dataLength -= i;
 | ||
| 			chunksize  += 2;
 | ||
| 
 | ||
| 		}
 | ||
| 		else { // Copy literally till 3 byte run or two 2 byte runs found 
 | ||
| 
 | ||
| 			for (i = 0; (i <= 128) && (i < dataLength); i++) {
 | ||
| 				current     = buffer[i];
 | ||
| 				curr_plus_2 = buffer[i + 2];
 | ||
| 
 | ||
| 				if (i == dataLength - 1)
 | ||
| 					continue;
 | ||
| 				if (current != buffer[i + 1])
 | ||
| 					continue;
 | ||
| 				if (i == dataLength - 2)
 | ||
| 					continue;
 | ||
| 				if (current == curr_plus_2)
 | ||
| 					break;
 | ||
| 				if (i == dataLength - 3)
 | ||
| 					continue;
 | ||
| 				if (curr_plus_2 == buffer[i + 3])
 | ||
| 					 break;
 | ||
| 			}
 | ||
| 			repCode = i - 1;
 | ||
| 			Write_File(lbmhandle, &repCode, 1L);			// Write count as count-1 
 | ||
| 			Write_File(lbmhandle, buffer, (LONG) i);		// Write 'count' bytes
 | ||
| 			buffer += i;
 | ||
| 			dataLength -= i;
 | ||
| 			chunksize += i + 1;
 | ||
| 		}
 | ||
| 	}  // end while
 | ||
| 
 | ||
| 	return(chunksize);
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| #if(FALSE)
 | ||
| 
 | ||
| This is a definition of a DPII .LBM file.
 | ||
| Below this definition are differences in DPIIe .LMB files.
 | ||
| 
 | ||
| Created by : Scott K. Bowen Nov 18, 1991
 | ||
| 	
 | ||
| Start with .LBM to read definition :
 | ||
| 
 | ||
| .LBM		-> "FORM" + FILESIZE + "ILMB" + CHUNKS
 | ||
| 
 | ||
| BITPLANES	-> (word) // number of bit planes used
 | ||
| BLUE			-> (byte) // blue color gun value
 | ||
| BMHD 			-> "BMHD" + CHUNKSIZE + CONTEXT
 | ||
| BODY			->
 | ||
| 
 | ||
| CHUNKS		-> BMHD | BODY | CMAP | DPPV | CRNG | ????
 | ||
| CHUNKSIZE	-> (long) // size of chunk not including header or size.
 | ||
| CMAP			-> "CMAP" + CHUNKSIZE + PALETTE_INFO
 | ||
| COMPRESS_METHOD -> (byte) // compression method used
 | ||
| CONTEXT		-> WIDTH + HEIGHT + POSX + POSY + #_BITPLANES + MASKING +
 | ||
| 				   COMPRESS_METHOD + PAD + TRANS_COL + XASPECT + YASPECT +
 | ||
| 					PAGEWIDTH + PAGEHEIGHT
 | ||
| CRNG			-> // we do not use
 | ||
| 
 | ||
| DPPV			-> // we do not use
 | ||
| 
 | ||
| FILESIZE		-> (long)   //size of file minus (sizeof(FORM) + sizeof(FILESIZE)
 | ||
| 
 | ||
| GREEN			-> (byte) // green color gun value
 | ||
| 
 | ||
| HEIGHT		-> (word) // of picture
 | ||
| 
 | ||
| MASKING		-> (byte) // masking type ?
 | ||
| 
 | ||
| NUM_COLORS	-> //number of colors used depending on format
 | ||
| 
 | ||
| PAGE_WIDTH	-> (word) // width of page
 | ||
| PAGE_HEIGHT	-> (word) // height of page
 | ||
| PALETTE_INFO-> (RED+GREEN+BLUE) @ NUM_COLORS
 | ||
| PAD 			-> (byte) // not used.  used as a padding
 | ||
| POSX 			-> (word) // staring position
 | ||
| POSY			-> (word) // staring position
 | ||
| 
 | ||
| RED			-> (byte) // red color gun value
 | ||
| 
 | ||
| TRANS_COL	-> (word) // transparrent color
 | ||
| 
 | ||
| WIDTH			-> (word) // of picture 
 | ||
| 
 | ||
| XASPECT		-> (byte) // x aspect ratio
 | ||
| 
 | ||
| YASPECT		-> (byte) // y aspect ratio
 | ||
| 
 | ||
| ????			-> // other possibilities
 | ||
| 
 | ||
| 
 | ||
| Differences in DPII enhance version
 | ||
| 
 | ||
| .LBM 		-> "FORM" + FILESIZE + "PBM " + CHUNKS
 | ||
| DPPV		-> DPPS		// uses dpps instead of dppv
 | ||
| CHUNKS		-> + TINY	// add these to old definition
 | ||
|  
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| #endif
 | ||
| 
 | 
