Initial commit of Command & Conquer Red Alert source code.

This commit is contained in:
LFeenanEA
2025-02-27 16:15:05 +00:00
parent b685cea758
commit 5e733d5dcc
2082 changed files with 797727 additions and 0 deletions

58
VQ/VQM32/ALL.H Normal file
View File

@@ -0,0 +1,58 @@
/*
** 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/>.
*/
#ifndef VQMALL_H
#define VQMALL_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* all.h
*
* DESCRIPTION
* All VQMisc32 library definitions. (32-Bit protected mode)
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* July 5, 1995
*
****************************************************************************/
#include <vqm32\iff.h>
#include <vqm32\mono.h>
#include <vqm32\portio.h>
#include <vqm32\profile.h>
#include <vqm32\targa.h>
#include <vqm32\compress.h>
#include <vqm32\video.h>
#include <vqm32\palette.h>
#include <vqm32\vesavid.h>
#include <vqm32\vesablit.h>
#include <vqm32\graphics.h>
#include <vqm32\mixfile.h>
#include <vqm32\crc.h>
#include <vqm32\huffman.h>
#include <vqm32\mem.h>
#endif /* VQMALL_H */

375
VQ/VQM32/AUDUNZAP.ASM Normal file
View File

@@ -0,0 +1,375 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* audunzap.asm
;*
;* DESCRIPTION
;* Audio uncompress (32-Bit protected mode)
;*
;* PROGRAMMER
;* Joe L. Bostic
;* Denzil E. Long, Jr.
;*
;* DATE
;* February 9, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* AudioUnzap - Uncompress zapped audio sample.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
CODESEG
CODE_2BIT EQU 0
CODE_4BIT EQU 1
CODE_RAW EQU 2
CODE_SILENCE EQU 3
MAGICNUMBER EQU 00000DEAFh
MAGICNUMBER2 EQU 0BABEBABEh
_2bitdecode DB -2,-1,0,1
_4bitdecode DB -9,-8,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,8
;****************************************************************************
;*
;* NAME
;* AudioUnzap - Uncompress zapped audio sample.
;*
;* SYNOPSIS
;* Size = AudioUnzap(Source, Dest, Size)
;*
;* long AudioUnzap(void *, void *, long);
;*
;* FUNCTION
;* Decompress the zapped audio sample data into a buffer.
;*
;* INPUTS
;* Source - Pointer to encoded audio data.
;* Dest - Pointer to buffer to decompress into.
;* Size - Maximum size of dest buffer.
;*
;* RESULT
;* Size - Number of uncompressed bytes.
;*
;****************************************************************************
GLOBAL C AudioUnzap:NEAR
PROC AudioUnzap C NEAR USES ebx ecx edx esi edi
ARG source:DWORD
ARG dest:DWORD
ARG count:DWORD
LOCAL previous:BYTE
LOCAL incount:DWORD
mov [incount],0 ;Bytes read from source
; Source, Dest and count must be valid.
; cmp [source],0
; je ??fini
; cmp [dest],0
; je ??fini
; cmp [count],0
; je ??fini
mov esi,[source] ;Pointer to source data.
mov edi,[dest] ;Pointer to destination data.
mov ecx,[count] ;Number of bytes to fill dest buffer.
mov dl,080h ;Previous sample (starting value).
cld
??mainloop:
cmp ecx,0 ;If dest full then exit
jle ??fini
xor eax,eax
mov al,[esi] ;Get code byte
inc [incount]
inc esi
shl eax,2 ;AH contains code.
shr al,2 ;AL contains sub-code data.
cmp ah,CODE_RAW ;Raw sequence?
jne short ??try4bit
; The code contains either a 5 bit delta or a count of
; raw samples to dump out.
test al,00100000b
je short ??justraw
; The lower 5 bits are actually a signed delta.
; Sign extend the delta and add it to the stream.
shl al,3
sar al,3
add dl,al
mov [edi],dl
dec ecx
inc edi
jmp ??mainloop
; The lower 5 bits hold a count of the number of raw
; samples that follow this code. Dump these samples to
; the output buffer.
??justraw:
mov ebx,ecx
xor ah,ah
inc al
mov ecx,eax
shr ecx,1
rep movsw
adc ecx,ecx
rep movsb
mov ecx,ebx
add [incount],eax
sub ecx,eax
dec edi
mov dl,[edi] ;Set "previous" value.
inc edi
jmp ??mainloop
; Check to see if this is a 4 bit delta code sequence.
??try4bit:
inc al ;Following codes use AL+1
cmp ah,CODE_4BIT
jne short ??try2bit
; A sequence of 4bit deltas follow. AL equals the
; number of nibble packed delta bytes to process.
??bit4loop:
mov ah,[esi] ;Fetch nibble packed delta codes
mov bl,ah
inc [incount]
inc esi
; Add first delta to 'previous' sample already in DL.
and ebx,00001111b
add dl,[_4bitdecode+ebx]
pushf
cmp [_4bitdecode+ebx],0
jl short ??neg1
popf
jnc short ??ok1
mov dl,0FFh
jmp short ??ok1
??neg1:
popf
jc short ??ok1
xor dl,dl
??ok1:
mov dh,dl ;DH now holds new 'previous' sample.
mov bl,ah
shr bl,4
add dh,[_4bitdecode+ebx]
pushf
cmp [_4bitdecode+ebx],0
jl short ??neg2
popf
jnc short ??ok2
mov dh,0FFh
jmp short ??ok2
??neg2:
popf
jc short ??ok2
xor dh,dh
??ok2:
mov [edi],dx ;Output the two sample bytes
sub ecx,2
add edi,2
; Put the correct 'previous' sample in DL where it belongs.
mov dl,dh
; If there are more deltas to process then loop back.
dec al
jnz short ??bit4loop
jmp ??mainloop
; Check to see if 2 bit deltas need to be processed.
??try2bit:
cmp ah,CODE_2BIT
jne ??zerodelta
; A sequence of 2bit deltas follow. AL equals the number of
; packed delta bytes to process.
??bit2loop:
mov ah,[esi] ;Fetch packed delat codes
inc [incount]
inc esi
; Add first delta to 'previous' sample already in DL.
mov bl,ah
and ebx,000011b
add dl,[_2bitdecode+ebx]
pushf
cmp [_2bitdecode+ebx],0
jl short ??neg3
popf
jnc short ??ok3
mov dl,0FFh
jmp short ??ok3
??neg3:
popf
jc short ??ok3
xor dl,dl
??ok3:
mov dh,dl
ror edx,8
mov bl,ah
shr ebx,2
and bl,00000011b
add dl,[_2bitdecode+ebx]
pushf
cmp [_2bitdecode+ebx],0
jl short ??neg4
popf
jnc short ??ok4
mov dl,0FFh
jmp short ??ok4
??neg4:
popf
jc short ??ok4
xor dl,dl
??ok4:
mov dh,dl
ror edx,8
mov bl,ah
shr ebx,4
and bl,00000011b
add dl,[_2bitdecode+ebx]
pushf
cmp [_2bitdecode+ebx],0
jl short ??neg5
popf
jnc short ??ok5
mov dl,0FFh
jmp short ??ok5
??neg5:
popf
jc short ??ok5
xor dl,dl
??ok5:
mov dh,dl
ror edx,8
mov bl,ah
shr ebx,6
and bl,00000011b
add dl,[_2bitdecode+ebx]
pushf
cmp [_2bitdecode+ebx],0
jl short ??neg6
popf
jnc short ??ok6
mov dl,0FFh
jmp short ??ok6
??neg6:
popf
jc short ??ok6
xor dl,dl
??ok6:
ror edx,8
mov [edi],edx ;Output two sample bytes
sub ecx,4
add edi,4
; Put the correct 'previous' sample in DL where it belongs.
rol edx,8
; If there are more deltas to process then loop back.
dec al
jnz ??bit2loop
jmp ??mainloop
; There is a run of zero deltas. Zero deltas merely duplicate
; the 'previous' sample the requested number of times.
??zerodelta:
xor ebx,ebx
mov bl,al
mov al,dl
sub ecx,ebx
xchg ecx,ebx
rep stosb
mov ecx,ebx
jmp ??mainloop
??fini:
mov eax,[incount]
ret
ENDP AudioUnzap
END

398
VQ/VQM32/AUDZAP.CPP Normal file
View File

@@ -0,0 +1,398 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* Audzap.c
*
* DESCRIPTION
* Lossy audio compression. (32-Bit protected mode)
*
* PROGRAMMER
* Joe L. Bostic
*
* DATE
* January 26, 1995
*
*----------------------------------------------------------------------------
*
* PUBLIC
* AudioZap - Compress audio sample data.
*
****************************************************************************/
#include <stdio.h>
#include <mem.h>
#include "compress.h"
/*---------------------------------------------------------------------------
* PRIVATE DECLARATIONS
*-------------------------------------------------------------------------*/
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
#define MAX(a,b) (((a)>(b)) ? (a) : (b))
typedef enum {
CODE_2BIT, /* Bit packed 2 bit delta. */
CODE_4BIT, /* Nibble packed 4 bit delta. */
CODE_RAW, /* Raw sample. */
CODE_SILENCE /* Run of silence. */
} SCodeType;
char _2bitencode[5] = {
0,1,2,3
};
long _2bitdecode[4] = {
-2,-1,0,1
};
char _4bitencode[19] = {
0,1,2,2,3,4,5,6,7,(8),
8,9,10,11,12,13,13,14,15
};
long _4bitdecode[16] = {
-9,-8,-6,-5,-4,-3,-2,
-1,0,1,2,3,4,5,6,8
};
/****************************************************************************
*
* NAME
* AudioZap - Compress audio sample data.
*
* SYNOPSIS
* Size = AudioZap(Source, Dest, Size)
*
* long AudioZap(void *, void *, long);
*
* FUNCTION
* NOTE - If the compressed size is equal to or greater than the original
* size then the data could not be compressed and the uncompressed data
* should be written.
*
* INPUTS
* Source - Pointer to buffer containing audio sample data.
* Dest - Pointer to buffer to put encoded data.
* Size - Number of bytes to compress.
*
* RESULT
* Size - Size in bytes of encoded data.
*
****************************************************************************/
long AudioZap(void *source, void *dest, long size)
{
unsigned char *s = (unsigned char *)source;
unsigned char *d = (unsigned char *)dest;
long delta;
unsigned long previous = 0x80;
long outcount = 0;
unsigned char *s4;
unsigned long p4;
long max4;
unsigned char *lastraw = 0;
long osize = size;
unsigned long i;
unsigned long dd;
/* Reduce very small amplitudes to silence. Usually a rather large
* portion of a sample is hovering around the silence value. This is
* due, in part, to the artifacting of the sample process. These low
* amplitudes are not audible.
*/
max4 = size;
s = (unsigned char *)source;
while (size > 0 && outcount < osize) {
/* First check for runs of zero deltas. If a run of at least
* any can be found, then output it.
*/
s4 = s;
max4 = MIN(63 + 1, size);
for (i = 0; i < max4; i++) {
if (previous != *s4++)
break;
}
/* When there is a code transition, terminate any run of raw
* samples.
*/
if (i > 2) {
lastraw = 0;
*d++ = ((i - 1)|(CODE_SILENCE << 6));
outcount++;
s += i;
size -= i;
continue;
}
/* If there are fewer than 4 samples remaining, then using delta
* compression is inefficient. Just drop into the raw routine
*/
if (size > 4) {
s4 = s;
p4 = previous;
/* Find out the number of lossless 2 bit deltas available. These
* deltas are always present in quads. The compressed code is
* the delta quad count followed by the deltas in bit packed bytes.
*/
max4 = MIN(64L * 4L + 4L + 4L, size);
for (i = 0; i < max4; i++) {
delta = (((int)*s4++) - p4);
if ((delta < -2) || (delta > 1)) {
break;
}
p4 += _2bitdecode[_2bitencode[delta + 2]];
if (((signed)p4) < 0) {
p4 = 0;
}
if (((signed)p4) > 255) {
p4 = 255;
}
}
i >>= 2; // Delta 2 always occur in quads -- force this.
/* If there is the minimum benificial number of delta 2s available,
* then compress them.
*/
if (i) {
/* When there is a code transition, terminate any run of raw
* samples.
*/
lastraw = 0;
/* Output the delta 4 pair count. This is the number of pairs
* minus the 'free' two pairs already assumed to be there.
*/
i = MIN(i, (63 + 1));
*d++ = ((i - 1)|(CODE_2BIT << 6));
outcount++;
for (dd = 0; dd < i; dd++) {
int delta1, delta2, delta3, delta4;
delta1 = _2bitencode[((((int)*s++) - previous) + 2)];
previous += _2bitdecode[delta1];
if (((signed)previous) < 0) {
previous = 0;
}
if (((signed)previous) > 255) {
previous = 255;
}
size--;
delta2 = _2bitencode[((((int)*s++) - previous) + 2)];
previous += _2bitdecode[delta2];
if (((signed)previous) < 0) {
previous = 0;
}
if (((signed)previous) > 255) {
previous = 255;
}
size--;
delta3 = _2bitencode[((((int)*s++) - previous) + 2)];
previous += _2bitdecode[delta3];
if (((signed)previous) < 0) {
previous = 0;
}
if (((signed)previous) > 255) {
previous = 255;
}
size--;
delta4 = _2bitencode[((((int)*s++) - previous) + 2)];
previous += _2bitdecode[delta4];
if (((signed)previous) < 0) {
previous = 0;
}
if (((signed)previous) > 255) {
previous = 255;
}
size--;
*d++ = ((delta4 << 6)|(delta3 << 4)|(delta2 << 2)|delta1);
outcount++;
}
continue;
} else {
s4 = s;
p4 = previous;
/* Find out the number of lossless 4 bit deltas follow. These
* deltas are always present in pairs. The compressed code is
* the delta pair count followed by the deltas in nibble packed
* bytes.
*/
max4 = MIN(64L * 2L + 4L + 4L, size);
for (i = 0; i < max4; i++) {
delta = (((int)*s4++) - p4);
if (delta < -9 || delta >= 9) {
break;
}
p4 += _4bitdecode[_4bitencode[(delta + 9)]];
if (((signed)p4) < 0) {
p4 = 0;
}
if (((signed)p4) > 255) {
p4 = 255;
}
}
i >>= 1; // Delta 4 always occur in pairs -- force this.
/* If there is the minimum benificial number of delta 4s available,
* then compress them.
*/
if (i) {
/* When there is a code transition, terminate any run of raw
* samples.
*/
lastraw = 0;
/* Output the delta 4 pair count. This is the number of pairs
* minus the 'free' two pairs already assumed to be there.
*/
i = MIN(i, (63 + 1));
*d++ = ((i - 1)|(CODE_4BIT << 6));
outcount++;
for (dd = 0; dd < i; dd++) {
int delta1, delta2;
delta1 = _4bitencode[((((int)*s++) - previous) + 9)];
previous += _4bitdecode[delta1];
if (((signed)previous) < 0) {
previous = 0;
}
if (((signed)previous) > 255) {
previous = 255;
}
size--;
delta2 = _4bitencode[((((int)*s++) - previous) + 9)];
previous += _4bitdecode[delta2];
if (((signed)previous) < 0) {
previous = 0;
}
if (((signed)previous) > 255) {
previous = 255;
}
size--;
*d++ = ((delta2 << 4)|(delta1 & 0x0F));
outcount++;
}
continue;
}
}
}
/* Raw output since deltas were unsuccessful. If this is a run
* of raw output, then merely tack it onto the run rather than
* create a new code sequence.
*/
if (lastraw) {
*lastraw = ((*lastraw) + 1);
/* There is only so much a run code can accomodate. If the limit
* has been reached, then terminate this code. A new one will be
* created if necessary.
*/
if ((*lastraw & 0x1F) == 0x1F) {
lastraw = 0;
}
} else {
/* If there is no current raw dump of samples, then check to see if
* this sample can fit into a 5 bit delta. If it can, then store
* it as such as a parasite to the "raw" code. This will save a byte
* for any stray 5 bit deltas that happen along. It is expected that
* this is more frequent than 6 or more bit deltas that would necessitate
* the use of the RAW code.
*/
delta = (((int)*s) - previous);
if ((delta >= -16) && (delta <= 15)) {
lastraw = 0;
*d++ = ((CODE_RAW << 6)|0x20|(delta & 0x1F));
outcount++;
previous = *s++;
size--;
continue;
} else {
lastraw = d;
*d++ = (CODE_RAW << 6);
outcount++;
}
}
*d++ = previous = *s++;
size--;
outcount++;
}
/* Check to see if the compression process actually resulted in smaller
* data size. In some cases, the 'compressed' data is actually larger. In
* this case, just output the raw frame. If the compressed and actual frame
* size match, then it is presumed that no compression occurs.
*/
if (outcount >= osize) {
memcpy(dest, source, (size_t)osize);
outcount = osize;
}
return(outcount);
}

9
VQ/VQM32/BCC32.CFG Normal file
View File

@@ -0,0 +1,9 @@
-c
-3
-d
-H=c:\projects\vqm32\obj\headers.sym
-wpro
-weas
-wpre
-IC:\PROJECTS\INCLUDE;C:\DEV\BC4\INCLUDE;C:\DEV\TNT\INCLUDE
-DPHARLAP_TNT=1

458
VQ/VQM32/CAPTOKEN.CPP Normal file
View File

@@ -0,0 +1,458 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* captoken.c
*
* DESCRIPTION
* Tokenize a caption script for playback processing.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* July 26, 1995
*
****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include "captoken.h"
/*---------------------------------------------------------------------------
* PRIVATE DECLARATIONS
*-------------------------------------------------------------------------*/
#define STRING_LENGTH 256
#define PADSIZE(size) (((size)+1)&(~1))
typedef enum {
TOKEN_NULL = 0,
TOKEN_BGCOL,
TOKEN_FGCOL,
TOKEN_XPOS,
TOKEN_YPOS,
TOKEN_ABS,
TOKEN_LEFT,
TOKEN_RIGHT,
TOKEN_CENTER,
TOKEN_FLASH,
TOKEN_CPF,
TOKEN_END
} TokenTag;
typedef struct _Token {
char *name;
long tag;
} Token;
/* Script tokens:
* BG/BGCOL - Background pen color (EX: BG=<color name>)
* FG/FGCOL - Foreground pen color (EX: FG=<color name>)
* X/XPOS - X pixel position of text (EX: X=<pixel cord>)
* Y/YPOS - Y pixel position of text (EX: Y=<pixel cord>)
* ABS/ABSOLUTE - Absolute justification
* LEFT - Left side justification
* RIGHT - Right side justification
* CENTER - Center justification
* FLASH - Enable flashing of text
* CPF - Print rate in characters per frame (EX: CPF=<rate>)
* END - Terminate compilation of caption script
*/
Token tokens[] = {
"BG", TOKEN_BGCOL,
"BGCOL", TOKEN_BGCOL,
"FG", TOKEN_FGCOL,
"FGCOL", TOKEN_FGCOL,
"X", TOKEN_XPOS,
"XPOS", TOKEN_XPOS,
"Y", TOKEN_YPOS,
"YPOS", TOKEN_YPOS,
"ABS", TOKEN_ABS,
"ABSOLUTE", TOKEN_ABS,
"LEFT", TOKEN_LEFT,
"RIGHT", TOKEN_RIGHT,
"CENTER", TOKEN_CENTER,
"FLASH", TOKEN_FLASH,
"CPF", TOKEN_CPF,
"END", TOKEN_END,
NULL, TOKEN_NULL,
};
Token colors[] = {
"BLACK", 0,
"WHITE", 251,
"RED", 252,
"GREEN", 253,
"SHADOW", 254,
"CYCLE", 255,
NULL, -1,
};
/* Prototypes. */
static long GetColorNum(char *name);
static long IsNumeric(char *string);
static void FormatString(char *string);
/****************************************************************************
*
* NAME
* BuildCaptions - Compile a caption script.
*
* SYNOPSIS
* Size = BuildCaptions(Name, Buffer)
*
* long BuildCaptions(char *, char *);
*
* FUNCTION
* Generate a compiled caption script for use in VQA playback.
*
* INPUTS
* Name - Name of caption script file to compile.
* Buffer - Buffer to put compiled captions into.
*
* RESULT
* Size - Size of compiled captions (in bytes).
*
****************************************************************************/
long BuildCaptions(char *name, char *buffer)
{
FILE *fp;
char *ptr;
char *ptr1;
long size = 0;
long error;
long i;
long tag;
CaptionText caption;
char string[STRING_LENGTH];
/* Initialize the caption parameters. */
memset(&caption, 0, sizeof(CaptionText));
/* Open the captions script file. */
fp = fopen(name, "r");
if (fp != NULL) {
error = 0;
while (!error) {
if (fgets(string, STRING_LENGTH, fp) == NULL) {
if (errno == 0) {
error = 1;
}
break;
}
/* Replace the newline with a NULL terminator. */
string[strlen(string) - 1] = 0;
/* Ignore comment lines. */
if (string[0] == ';') continue;
ptr = strtok(string, "=");
if (ptr != NULL) {
/* Check for a comma */
ptr1 = strchr(ptr, ',');
if (ptr1 != NULL) {
*ptr1++ = 0;
}
/* Is this a frame number. */
if (IsNumeric(ptr) && IsNumeric(ptr1)) {
i = atoi(ptr);
/* Frames must be defined in ascending order. */
if ((unsigned short)i >= caption.OnFrame) {
caption.OnFrame = i;
caption.OffFrame = atoi(ptr1);
caption.Size = sizeof(CaptionText);
/* Get caption text. */
ptr = strtok(NULL, "");
if (ptr != NULL) {
FormatString(ptr);
i = strlen(ptr) + 1;
caption.Size += PADSIZE(i);
size += caption.Size;
/* Copy the caption structure. */
memcpy(buffer, &caption, sizeof(CaptionText));
buffer += sizeof(CaptionText);
/* Copy the caption text. */
memcpy(buffer, ptr, i);
buffer += i;
/* WORD align */
if (PADSIZE(i) > i) {
*buffer++ = 0;
}
}
} else {
error = 1;
break;
}
} else {
/* Search for matching token. */
tag = TOKEN_NULL;
i = 0;
while (tokens[i].name != NULL) {
if (strcmpi(tokens[i].name, ptr) == 0) {
tag = tokens[i].tag;
break;
}
i++;
}
/* Get the data element. */
ptr = strtok(NULL, "");
switch (tag) {
case TOKEN_BGCOL:
caption.BgPen = (char)GetColorNum(ptr);
break;
case TOKEN_FGCOL:
caption.FgPen = (char)GetColorNum(ptr);
break;
case TOKEN_XPOS:
caption.Xpos = (unsigned short)atoi(ptr);
break;
case TOKEN_YPOS:
caption.Ypos = (unsigned short)atoi(ptr);
break;
case TOKEN_ABS:
caption.Flags &= ~CTF_JUSTIFY;
caption.Flags |= CTF_ABS;
break;
case TOKEN_LEFT:
caption.Flags &= ~CTF_JUSTIFY;
caption.Flags |= CTF_LEFT;
break;
case TOKEN_RIGHT:
caption.Flags &= ~CTF_JUSTIFY;
caption.Flags |= CTF_RIGHT;
break;
case TOKEN_CENTER:
caption.Flags &= ~CTF_JUSTIFY;
caption.Flags |= CTF_CENTER;
break;
case TOKEN_FLASH:
if (strcmpi(ptr, "OFF") == 0) {
caption.Flags &= ~CTF_FLASH;
} else {
caption.Flags |= CTF_FLASH;
}
break;
case TOKEN_CPF:
caption.CPF = (char)atoi(ptr);
break;
/* Termination captions */
case TOKEN_END:
caption.Size = sizeof(CaptionText);
caption.OnFrame = (unsigned short)-1;
memcpy(buffer, &caption, sizeof(CaptionText));
buffer += sizeof(CaptionText);
break;
default:
break;
}
}
}
}
/* Close the script file. */
fclose(fp);
}
return (size);
}
/****************************************************************************
*
* NAME
* GetColorNum - Get the color number from the color name.
*
* SYNOPSIS
* Color = GetColorNum(Name)
*
* long GetColorNum(char *);
*
* FUNCTION
* Look the color number that corresponds to the color name.
*
* INPUTS
* Name - Name of color.
*
* RESULT
* Color - Color number.
*
****************************************************************************/
static long GetColorNum(char *name)
{
long color = -1;
long i;
i = 0;
/* Scan for a matching name and return the corresponding color number. */
while (colors[i].name != NULL) {
if (strcmpi(colors[i].name, name) == 0) {
color = colors[i].tag;
}
i++;
}
return (color);
}
/****************************************************************************
*
* NAME
* IsNumeric - Check if a string is numeric.
*
* SYNOPSIS
* Condition = IsNumeric(String)
*
* long IsNumeric(char *);
*
* FUNCTION
* Interogate the string to see if it represents a numeric value. Each
* byte of the string must be between 0x30 and 0x39 inclusively.
*
* INPUTS
* String - String to check.
*
* RESULT
* Condition - 1 if numeric, 0 if not.
*
****************************************************************************/
static long IsNumeric(char *string)
{
long flag = 1;
/* Ignore any proceeding sign designation. */
if ((*string == '-') || (*string == '+')) {
string++;
}
/* Check to see if every byte in the string is a digit. */
while (flag && (*string != 0)) {
if (!isdigit(*string++)) {
flag = 0;
}
}
return (flag);
}
/****************************************************************************
*
* NAME
* FormatString - Parse any format codes in the string.
*
* SYNOPSIS
* FormatString(String)
*
* void FormatString(char *);
*
* FUNCTION
* Format a string with any embedded format commands contained in the
* input string.
*
* Supported format commands:
* /n - Insert carriage return. (0x0D)
* /r - Insert carriage return. (0x0D)
* // - Literal backslash.
*
* INPUTS
* String - Pointer to string to format.
*
* RESULT
* NONE
*
****************************************************************************/
static void FormatString(char *string)
{
char *ptr;
/* NULL strings are invalid. */
if (string != NULL) {
ptr = string;
/* Scan the string for embedded format commands. */
while ((ptr = strchr(ptr, '/')) != NULL) {
switch (*(ptr + 1)) {
/* Carriage return. */
case 'n':
case 'r':
*ptr = 0x0D;
break;
/* Literal backslash. */
case '/':
break;
default:
break;
}
/* Remove the unwanted character. */
strcpy((ptr + 1), (ptr + 2));
}
}
}

80
VQ/VQM32/CAPTOKEN.H Normal file
View File

@@ -0,0 +1,80 @@
/*
** 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/>.
*/
#ifndef VQMCAPTOKEN_H
#define VQMCAPTOKEN_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* captoken.h
*
* DESCRIPTION
* Text caption script definitions.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* July 26, 1995
*
****************************************************************************/
/* CaptionText: This structure describes a line of text to be displayed
* with the video/audio.
*
* Size - Size of caption in bytes.
* OnFrame - Frame number to display caption.
* OffFrame - Frame number to clear caption.
* Flags - Display modifiers.
* CPF - Characters to draw per frame.
* Xpos - X pixel position to display caption.
* Ypos - Y pixel position to display caption.
* BgPen - Background pen to use.
* FgPen - Foreground pen to use.
* Text - Text string to display. (WORD aligned)
*/
typedef struct _CaptionText {
unsigned short Size;
unsigned short OnFrame;
unsigned short OffFrame;
unsigned char Flags;
char CPF;
unsigned short Xpos;
unsigned short Ypos;
char BgPen;
char FgPen;
char Text[];
} CaptionText;
/* CaptionText flag definitions. */
#define CTF_JUSTIFY (3<<0) /* Justification field. */
#define CTF_ABS (0<<0) /* Use absolute X,Y positions. */
#define CTF_CENTER (1<<0) /* Justify on Center */
#define CTF_LEFT (2<<0) /* Justify on left */
#define CTF_RIGHT (3<<0) /* Justify on right */
#define CTF_FLASH (1<<4) /* Flash text. */
/* Function prototypes. */
long BuildCaptions(char *name, char *buffer);
#endif /* VQMCAPTOKEN_H */

76
VQ/VQM32/CHRWIDTH.CPP Normal file
View File

@@ -0,0 +1,76 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*---------------------------------------------------------------------------
*
* FILE
* chrwidth.c
*
* DESCRIPTION
* Character pixel width.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* June 9, 1995
*
*---------------------------------------------------------------------------
*
* PUBLIC
* Char_Pixel_Width - Get the pixel width of a character.
*
****************************************************************************/
#include "font.h"
/****************************************************************************
*
* NAME
* Char_Pixel_Width - Get the pixel width of a character.
*
* SYNOPSIS
* Width = Char_Pixel_Width(Character)
*
* long Char_Pixel_Width(char);
*
* FUNCTION
* Gets the pixel width of the specified character.
*
* INPUTS
* Character - Character to get the width for.
*
* RESULT
* Width - Width in pixels.
*
****************************************************************************/
#ifdef __WATCOMC__
long cdecl __saveregs Char_Pixel_Width(char chr)
#else
#pragma saveregs
long cdecl Char_Pixel_Width(char chr)
#endif
{
return (*(FontWidthBlockPtr + chr) + FontXSpacing);
}

59
VQ/VQM32/COMPRESS.H Normal file
View File

@@ -0,0 +1,59 @@
/*
** 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/>.
*/
#ifndef VQMCOMP_H
#define VQMCOMP_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* compress.h
*
* DESCRIPTION
* Compression definitions. (32-Bit protected mode)
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* January 26, 1995
*
****************************************************************************/
/* Prototypes */
#ifdef __cplusplus
extern "C" {
#endif
unsigned long cdecl LCW_Compress(char const *source, char *dest,
unsigned long length);
unsigned long cdecl LCW_Uncompress(char const *source, char *dest,
unsigned long length);
long AudioZap(void *source, void *dest, long size);
long cdecl AudioUnzap(void *source, void *dest, long);
#ifdef __cplusplus
}
#endif
#endif /* VQMCOMP_H */

133
VQ/VQM32/CRC.ASM Normal file
View File

@@ -0,0 +1,133 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* crc.asm
;*
;* DESCRIPTION
;* CRC checksum calculation.
;*
;* PROGRAMMER
;* Joe L. Bostic
;*
;* DATE
;* January 26, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* Calculate_CRC - Calculate CRC checksum.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
CODESEG
;****************************************************************************
;*
;* NAME
;* Calculate_CRC - Calculate CRC checksum.
;*
;* SYNOPSIS
;* CRC = Calculate_CRC(Buffer, Length)
;*
;* long Calculate_CRC(void *, long);
;*
;* FUNCTION
;* Compute a CRC checksum for a block of memory.
;*
;* INPUTS
;* Buffer - Pointer to buffer to calculate CRC for.
;* Length - Length of buffer.
;*
;* RESULT
;* CRC - CRC value.
;*
;****************************************************************************
GLOBAL C Calculate_CRC:NEAR
PROC Calculate_CRC C NEAR USES esi ebx ecx edx
ARG buffer:NEAR PTR
ARG length:DWORD
mov esi,[buffer]
cld
; Clear CRC to default (NULL) value.
xor ebx,ebx
mov ecx,[length] ;Get length of data block
or ecx,ecx
jz short ??fini
; Prepare the length counters.
mov edx,ecx
and dl,011b
shr ecx,2
; Perform the bulk of the CRC scanning.
or ecx,ecx
jz short ??remainder
??accumloop:
lodsd
rol ebx,1
add ebx,eax
loop ??accumloop
; Handle the remainder bytes.
??remainder:
or dl,dl
jz short ??fini
mov ecx,edx
xor eax,eax
push ecx
??nextbyte:
lodsb
ror eax,8
loop ??nextbyte
pop ecx
neg ecx
add ecx,4
shl ecx,3
ror eax,cl
;??nextbyte:
; shl eax,8
; lodsb
; loop ??nextbyte
rol ebx,1
add ebx,eax
??fini:
mov eax,ebx
ret
ENDP Calculate_CRC
END

51
VQ/VQM32/CRC.H Normal file
View File

@@ -0,0 +1,51 @@
/*
** 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/>.
*/
#ifndef VQMCRC_H
#define VQMCRC_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* CRC.h
*
* DESCRIPTION
* CRC calculation definitions.
*
* PROGRAMMER
* Joe L. Bostic
*
* DATE
* January 26, 1995
*
****************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
long cdecl Calculate_CRC(void const *buffer, long length);
#ifdef __cplusplus
}
#endif
#endif /* VQMCRC_H */

395
VQ/VQM32/DRAWCHAR.ASM Normal file
View File

@@ -0,0 +1,395 @@
;
; 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: U:\vq\projects\vqm32\drawchar.asv 1.1 08 May 1995 10:48:32 DENZIL_LONG $
;***************************************************************************
;** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
;***************************************************************************
;* *
;* Project Name : Westwood Library *
;* *
;* File Name : DRAWCHAR.ASM *
;* *
;* Programmer : Joe L. Bostic *
;* *
;* Start Date : August 20, 1993 *
;* *
;* Last Update : August 20, 1993 [JLB] *
;* *
;*-------------------------------------------------------------------------*
;* Functions: *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
CODESEG
XPIXEL_MAX EQU 320
YPIXEL_MAX EQU 200
FONTINFOBLOCK EQU 4
FONTOFFSETBLOCK EQU 6
FONTWIDTHBLOCK EQU 8
FONTDATABLOCK EQU 10
FONTHEIGHTBLOCK EQU 12
FONTINFOMAXHEIGHT EQU 4
FONTINFOMAXWIDTH EQU 5
EXTRN FontPtr:NEAR PTR
;***********************************************************
; DRAW_CHAR
;
; VOID Draw_Char(BYTE fontchar, WORD x_pixel, WORD y_pixel);
;
; Draws a character to the screen only if given coordinates that will allow
; the entire character to be drawn on the screen else will exit.
;
; NOTE: This is a routine called by Text_Print.
;
;*
GLOBAL C Draw_Char:NEAR
PROC Draw_Char C NEAR USES eax ebx ecx edx esi edi
ARG fontchar:DWORD
ARG x_pixel:DWORD
ARG y_pixel:DWORD
LOCAL infoblock:DWORD
LOCAL offsetblock:DWORD
LOCAL widthblock:DWORD
LOCAL heightblock:DWORD
LOCAL fwidth:DWORD
LOCAL nextline:DWORD
LOCAL startv:BYTE
LOCAL dheight:BYTE
LOCAL wheight:BYTE
mov esi,[FontPtr]
; Set up some working local variables.
xor eax,eax
mov ax,[esi+FONTINFOBLOCK] ; get offset to info block
mov [infoblock],eax ; save offset to info block
mov ax,[esi+FONTOFFSETBLOCK] ; get offset to offset block
mov [offsetblock],eax ; save offset to offset block
mov ax,[esi+FONTWIDTHBLOCK] ; get offset to width block
mov [widthblock],eax ; save offset to width block
mov ax,[esi+FONTHEIGHTBLOCK] ; get offset to height block
mov [heightblock],eax ; save offset to height block
; Fetch character data offset -- if NULL then undefined character.
mov ebx,[fontchar]
and ebx,0FFh
shl ebx,1 ; make word index
add ebx,[offsetblock] ; add offset to offset block
xor ecx,ecx
mov cx,[esi+ebx] ; load offset to font data
or ecx,ecx
jz ??exit ; is this character a null? if so exit
; If the character is off the left/right edge of the screen then abort.
mov edx,[x_pixel]
cmp edx,XPIXEL_MAX
jae ??exit
; If the character is off the top/bottom edge of the screen then abort.
mov ebx,[fontchar] ; get char
and ebx,0FFh
add ebx,[widthblock] ; add offset to width block
xor eax,eax
mov al,[esi+ebx] ; get width for character
mov [fwidth],eax ; save char width
add eax,edx ; ax = char len + x
cmp eax,XPIXEL_MAX
ja ??exit
mov edi,edx ; save xpos in di
mov edx,[y_pixel]
cmp edx,YPIXEL_MAX
jae ??exit
mov ebx,[infoblock] ; get offset to offset block
xor eax,eax
; get font max height from info block
mov al,[esi+ebx+FONTINFOMAXHEIGHT]
mov [wheight],al ; save max height of character
add eax,edx ; add height to y pos
cmp eax,YPIXEL_MAX ; will it go off the bottom
ja ??exit
??vdraw:
mov ebx,[fontchar] ; get char
and ebx,0FFh
shl ebx,1 ; make 2 byte index
add ebx,[heightblock] ; add offset to height block
mov ah,[esi+ebx] ; get start vertical for character
mov [startv],ah ; save start vertical for later
mov al,[esi+ebx+1] ; get data height for character
mov [dheight],al ; save data height for later
add ah,al ; add background and data
sub [wheight],ah ; remaining background height
add esi,ecx ; add font offset to font data
push edx
mov eax,XPIXEL_MAX
mul edx
add edi,eax
pop edx
mov eax,XPIXEL_MAX
sub eax,[fwidth]
mov [nextline],eax ; ?? to add to index for the nextline
add edi,0A0000h
mov ebx,OFFSET ColorXlat ; setup up bx for xlat commands
xor ecx,ecx
mov cl,[startv] ; number of scan lines that are
; background color
or ecx,ecx ; if starting vertical is zero
je short ??skiplead ; skip drawing top background lines
mov al,0
xlat [ebx] ; get background color
or al,al ; check for none zero color
jne short ??lheight ; update background color
push edx
mov eax,XPIXEL_MAX
mul ecx
add edi,eax
pop edx
mov ebx,OFFSET ColorXlat ; restore bx for xlat commands
jmp SHORT ??skiplead
??lheight:
mov edx,[fwidth] ; width of char
??lwidth:
stosb ; write out line of pixels for width
dec edx
jne ??lwidth
??lnext:
add edi,[nextline] ; goto next line at the start of char
loop ??lheight ; any more lines
??skiplead:
mov cl,[dheight] ; number of scan lines that are data
or ecx,ecx ; is there any data to be drawn
je short ??exit
??vheight:
mov edx,[fwidth] ; width of char
??vwidth:
lodsb ; get byte value from font data
mov ah,al ; save hinibble
and al,00FH ; get lonibble
xlat [ebx] ; get new color
or al,al
je short ??chklowidth ; skip color zero
mov [edi],al ; write out pixel of lonibble
??chklowidth:
inc edi
dec edx
je short ??vnext ; check if done with width of char
mov al,ah ; get byte value
and al,0F0H ; get hinibble
xlat [ebx] ; get new color
or al,al
je short ??chkhiwidth ; skip color zero
mov [edi],al ; write out pixel of hinibble
??chkhiwidth:
inc edi
dec edx
jne ??vwidth ; check if done with width of char
??vnext:
add edi,[nextline] ; next line at start of char
loop ??vheight ; any more lines
??trail:
mov cl,[wheight] ; remaining height of background color
or ecx,ecx ; if trailing height is zero
jle short ??exit ; skip drawing bottom background lines
mov al,0
xlat [ebx] ; get background color
or al,al ; check for color zero
je short ??exit ; skip drawing
??theight:
mov edx,[fwidth] ; width of char
??twidth:
stosb ; write out line of pixels for width
dec edx
jne ??twidth
??tnext:
add edi,[nextline] ; next line at start of char
loop ??theight ; any more lines
??exit:
ret
ENDP Draw_Char
;***********************************************************
;***********************************************************
; SET_FONT_PALETTE_RANGE
;
; VOID Set_Font_Palette_Range(VOID *palette, WORD start, WORD end);
;
; This routine changes the local Draw_Char color translation table
; with the color numbers in palette.
;
; Bounds Checking: forces start and end to a range of 0-15
;*
GLOBAL C Set_Font_Palette_Range:NEAR
PROC Set_Font_Palette_Range C NEAR USES eax ebx ecx edi esi
ARG palette:NEAR PTR
ARG start:DWORD
ARG endval:DWORD
cld
mov esi,[palette]
mov ebx,[start]
and ebx,0FH ; value 0-15
mov ecx,[endval]
and ecx,0FH ; value 0-15
cmp ecx,ebx ; if end < start then exit
jl short ??exit
sub ecx,ebx ; number of colors = end - start + 1
inc ecx
mov edi,OFFSET ColorXlat ; get start of xlat table
add edi,ebx ; add starting offset
shl ebx,4 ; multiply start offset by 16
add ebx,OFFSET ColorXlat ; add start of xlat table
; updates 0-15 for lonibble xlat
; updates 0,16,32,...,240 for hinibble xlat
??setpal:
lodsb ; get color number
stosb ; save color number for lonibble xlat
mov [ebx],al ; save color number for hinibble xlat
add ebx,010H ; add 16 to index for hinibble offset
loop ??setpal
??exit:
ret
ENDP Set_Font_Palette_Range
;***********************************************************
;***********************************************************
; DRAW_CHAR_SETUP
;
; VOID Draw_Char_Setup(VOID);
;
; This routine sets up code segment variables for Draw_Char.
;
; NOTE: This is a routine called by Set_Font.
;
;*
GLOBAL C Draw_Char_Setup:NEAR
PROC Draw_Char_Setup C NEAR
ret
ENDP Draw_Char_Setup
DATASEG
ColorXlat DB 000H,001H,002H,003H,004H,005H,006H,007H
DB 008H,009H,00AH,00BH,00CH,00DH,00EH,00FH
DB 001H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 002H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 003H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 004H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 005H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 006H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 007H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 008H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 009H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 00AH,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 00BH,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 00CH,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 00DH,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 00EH,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H
DB 00FH
;***********************************************************
END

216
VQ/VQM32/FILLRECT.ASM Normal file
View File

@@ -0,0 +1,216 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* fillrect.asm
;*
;* DESCRIPTION
;* Rectangle rendering.
;*
;* PROGRAMMER
;* Joe L. Bostic
;*
;* DATE
;* Febuary 8, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* Fill_Rect - Draw a filled rectangle.
;* Eor_Region - Hilights or unhilights a region by EOR it.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
CODESEG
;****************************************************************************
;*
;* NAME
;* Eor_Region - Hilights or unhilights a region by EOR it.
;*
;* SYNOPSIS
;* Eor_Region(X1, Y1, X2, Y2, Color)
;*
;* void Eor_Region(long, long, long, long, long);
;*
;* FUNCTION
;*
;* INPUTS
;* X1 - Starting X position.
;* Y1 - Starting Y position.
;* X2 - Ending X position.
;* Y2 - Ending Y position.
;* Color - Color to EOR.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Eor_Region:NEAR
PROC Eor_Region C NEAR USES eax ebx ecx edx edi
ARG x1_pixel:DWORD
ARG y1_pixel:DWORD
ARG x2_pixel:DWORD
ARG y2_pixel:DWORD
ARG color:DWORD
LOCAL eorit:DWORD
mov [eorit],1
jmp short Fill_Rect_Entry
ENDP Eor_Region
;****************************************************************************
;*
;* NAME
;* Fill_Rect - Draw a filled rectangle.
;*
;* SYNOPSIS
;* Fill_Rect(X1, Y1, X2, Y2, Color)
;*
;* void Fill_Rect(long, long, long, long, long);
;*
;* FUNCTION
;* Fill a rectangle area with a specified color.
;*
;* INPUTS
;* X1 - Starting X position.
;* Y1 - Starting Y position.
;* X2 - Ending X position.
;* Y2 - Ending Y position.
;* Color - Color to draw rectangle
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Fill_Rect:NEAR
PROC Fill_Rect C NEAR USES eax ebx ecx edx edi
ARG x1_pixel:DWORD
ARG y1_pixel:DWORD
ARG x2_pixel:DWORD
ARG y2_pixel:DWORD
ARG color:DWORD
LOCAL eorit:DWORD
mov [eorit],0
Fill_Rect_Entry:
cld ; always go forward
mov edi,0A0000h
; Verify bounds of x1_pixel.
mov eax,[x1_pixel]
cmp eax,320 ;XPIXEL_MAX
jae short ??exit
; Verify bounds of x2_pixel.
mov ebx,[x2_pixel]
cmp ebx,320 ;XPIXEL_MAX
jae short ??exit
; Backward rectangles are legal -- adjust for it.
cmp eax,ebx
jbe short ??okx
xchg eax,ebx
??okx:
; Verify bounds of y1_pixel.
mov ecx,[y1_pixel]
cmp ecx,200 ;YPIXEL_MAX
jae short ??exit
; Verify bounds of y2_pixel.
mov edx,[y2_pixel]
cmp edx,200 ;YPIXEL_MAX
jae short ??exit
; Backward rectangles are legal -- adjust for it.
cmp ecx,edx
jbe short ??oky
xchg ecx,edx
??oky:
; Set DX for height and BX for width.
sub edx,ecx
inc edx
sub ebx,eax
inc ebx
; Adjust DI to match offset into page of upper left corner.
push edx
push eax
mov eax,320 ;XPIXEL_MAX
mul ecx
add edi,eax ; Add in Y offset.
pop edx
add edi,edx ; Add in X offset.
pop edx
; Fill the region with the specified color.
mov eax,320 ;XPIXEL_MAX
sub eax,ebx
xchg eax,[color]
mov ah,al
cmp [eorit],0
je short ??loop
;------ EOR rectangle filling.
??loop2:
mov ecx,ebx ; Length of row
??loop2in:
lodsb
xor al,ah
stosb
loop ??loop2in
add edi,[color] ; Modulo add for next line prep.
dec edx
jg short ??loop2
jmp short ??exit
;------ Conventional rectangle filling.
??loop:
mov ecx,ebx ; Length of row
shr ecx,1
rep stosw
adc ecx,0
rep stosb
add edi,[color] ; Modulo add for next line prep.
dec edx
jg short ??loop
??exit:
ret
ENDP Fill_Rect
END

222
VQ/VQM32/FONT.CPP Normal file
View File

@@ -0,0 +1,222 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*---------------------------------------------------------------------------
*
* FILE
* font.c
*
* DESCRIPTION
* Font manipulation.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* March 9, 1995
*
*---------------------------------------------------------------------------
*
* PUBLIC
* Load_Font - Open a font for use.
* Set_Font - Set the default system font.
* String_Pixel_Width - Get the pixel width of a string.
*
****************************************************************************/
#include <stdlib.h>
#include <fcntl.h>
#include <io.h>
#include <string.h>
#include <malloc.h>
#include "font.h"
/*---------------------------------------------------------------------------
* PRIVATE DECLARATIONS
*-------------------------------------------------------------------------*/
/* min and max macros */
#ifdef __cplusplus
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#endif
void const *FontPtr = NULL;
char FontHeight = 8;
char FontWidth = 8;
int FontXSpacing = 0;
int FontYSpacing = 0;
char *FontWidthBlockPtr = NULL;
/****************************************************************************
*
* NAME
* Load_Font - Open a font for use.
*
* SYNOPSIS
* Font = Load_Font(Name)
*
* char *Load_Font(char *);
*
* FUNCTION
* Open a graphics font for use by Text_Print(). Use free() to dispose
* of the font.
*
* INPUTS
* Name - Name of font file to open.
*
* RESULT
* Font - Pointer to font, NULL if error.
*
****************************************************************************/
void *cdecl Load_Font(char const *name)
{
Font *font = NULL;
long fh;
short size;
short valid;
/* Open the font. */
if ((fh = open(name, (O_RDONLY|O_BINARY))) != -1) {
/* Get the size of the font. */
if (read(fh, &size, 2) == 2) {
/* Allocate memory to contain the font. */
if ((font = (Font *)malloc((unsigned long)size)) != NULL) {
valid = 0;
/* Read in the body of the font. */
if (read(fh, &font->CompMethod, (unsigned long)(size - 2))
== (unsigned long)(size - 2)) {
/* Verify the validity of the font. */
if ((font->CompMethod == 0) && (font->NumBlks == 5)) {
font->Size = size;
valid = 1;
}
}
/* Free the font if it is not valid. */
if (valid == 0) {
free(font);
font = NULL;
}
}
}
/* Close the font. */
close(fh);
}
return ((char *)font);
}
/****************************************************************************
*
* NAME
* Set_Font - Set the default system font.
*
* SYNOPSIS
* OldFont = Set_Font(Font)
*
* char *Set_Font(char *);
*
* FUNCTION
* Sets up the specified font as the default font used by the system.
*
* INPUTS
* Font - Pointer to Font to set as default. (NULL returns current font)
*
* RESULT
* OldFont - Previous font.
*
****************************************************************************/
void *cdecl Set_Font(void const *font)
{
void const *oldfont;
FontInfo *fi;
oldfont = FontPtr;
if (font != NULL) {
FontWidthBlockPtr = ((char *)font + ((Font *)font)->WidthBlk);
fi = (FontInfo *)((char *)font + ((Font *)font)->InfoBlk);
FontHeight = fi->MaxHeight;
FontWidth = fi->MaxWidth;
FontPtr = font;
}
return ((void *)oldfont);
}
/****************************************************************************
*
* NAME
* String_Pixel_Width - Get the pixel width of a string.
*
* SYNOPSIS
* Width = String_Pixel_Width(String)
*
* long String_Pixel_Width(char *);
*
* FUNCTION
* Calculates the pixel width of a string of characters.
*
* INPUTS
* String - Pointer to string to calculate width for.
*
* RESULT
* Width - Width of string in pixels.
*
****************************************************************************/
unsigned short String_Pixel_Width(char const *string)
{
long width = 0;
long largest = 0;
while (*string != NULL) {
if (*string == '\r') {
string++;
largest = max(largest, width);
width = 0;
} else {
width += Char_Pixel_Width(*string++);
}
}
largest = max(largest, width);
return (largest);
}

105
VQ/VQM32/FONT.H Normal file
View File

@@ -0,0 +1,105 @@
/*
** 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/>.
*/
#ifndef VQMFONT_H
#define VQMFONT_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*---------------------------------------------------------------------------
*
* FILE
* font.h
*
* DESCRIPTION
* Font definitions.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* March 9, 1995
*
****************************************************************************/
/* Font: A Westwood style font.
*
* Size - Size of font.
* CompMethod - Compression method of font. (0 = none)
* NumBlks - Number of data blocks.
* InfoBlk - Offset to font information block.
* OffsetBlk - Offset to character offset block.
* WidthBlk - Offset to character width block.
* DataBlk - Offset to character data block.
* HeightBlk - Offset to character height block.
*/
typedef struct _Font {
unsigned short Size;
unsigned char CompMethod;
unsigned char NumBlks;
unsigned short InfoBlk;
unsigned short OffsetBlk;
unsigned short WidthBlk;
unsigned short DataBlk;
unsigned short HeightBlk;
} Font;
typedef struct _FontInfo {
long huh;
unsigned char MaxHeight;
unsigned char MaxWidth;
} FontInfo;
#ifdef __cplusplus
extern "C" {
#endif
extern void const *FontPtr;
extern int FontXSpacing;
extern int FontYSpacing;
#ifdef __cplusplus
}
#endif
extern char FontWidth;
extern char FontHeight;
extern char *FontWidthBlockPtr;
/* Function prototypes. */
void *cdecl Load_Font(char const *name);
void *cdecl Set_Font(void const *font);
unsigned short cdecl String_Pixel_Width(char const *string);
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __WATCOMC__
long cdecl __saveregs Char_Pixel_Width(char chr);
#else
long cdecl Char_Pixel_Width(char chr);
#endif
#ifdef __cplusplus
}
#endif
#endif /* VQMFONT_H */

55
VQ/VQM32/GRAPHICS.H Normal file
View File

@@ -0,0 +1,55 @@
/*
** 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/>.
*/
#ifndef VQMGRAPHICS_H
#define VQMGRAPHICS_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* graphics.h
*
* DESCRIPTION
* Graphic rendering and manipulation definitions.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* April 27, 1995
*
****************************************************************************/
/* Prototypes */
#ifdef __cplusplus
extern "C" {
#endif
void cdecl Eor_Region(long sx, long sy, long dx, long dy, long color);
void cdecl Fill_Rect(long x1, long y1, long x2, long y2, long color);
#ifdef __cplusplus
}
#endif
#endif /* VQMGRAPHICS_H */

708
VQ/VQM32/HUFFCMP.CPP Normal file
View File

@@ -0,0 +1,708 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* huffcmp.h
*
* DESCRIPTION
* Huffman order 0 compressor.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* May 19, 1995
*
*----------------------------------------------------------------------------
*
* PUBLIC
* HuffCompress - Compress data using huffman order 0 compression.
* HuffCount - Count the frequency of occurence of every byte.
* HuffScaleCounts - Scale down the frequency counts.
* RLEHuffCounts - Run Length Encode the Huffman counts.
* ConvertToCodes - Convert the Huffman tree into a table of codes.
* HuffEncode - Huffman encode the data.
*
****************************************************************************/
#include <mem.h>
#include "huffman.h"
/****************************************************************************
*
* NAME
* HuffCompress - Compress data using huffman order 0 compression.
*
* SYNOPSIS
* Size = HuffCompress(Data, Buffer, Size, Temp)
*
* long HuffCompress(unsigned char *, unsigned char *, long, char *);
*
* FUNCTION
* This function performs an order 0 Huffman encoding of the input data.
* The algorithm used is fairly straightforward. First a count is made of
* all the bytes in the input data, then the counts are scaled down to
* a single byte representation in the node array. After the counts are
* scaled, a Huffman decoding tree is built from the node array. Then
* a code array is built by traversing the tree for each symbol. Finally,
* the input data is compressed.
*
* INPUTS
* Data - Pointer to data to compress.
* Buffer - Pointer to compressed data.
* Size - Length of data to compress.
* Temp - Pointer to temporary working buffer. (Must be >= 5120 bytes!)
*
* RESULT
* Size - Compressed size.
*
****************************************************************************/
long cdecl HuffCompress(unsigned char *data, unsigned char *buffer,
long length, char *temp)
{
#if(1)
TreeNode *nodes;
HuffCode *codes;
long size;
long root;
/* Initialize variables */
nodes = (TreeNode *)temp;
temp += (514 * sizeof(TreeNode));
codes = (HuffCode *)temp;
/* Analyze the frequency of the data. */
HuffCount(data, nodes, length, 1);
HuffScaleCounts(nodes);
/* Save the counts for the decompression. */
size = RLEHuffCounts(nodes, buffer);
buffer += size;
/* Build the Huffman decode tree and generate codes for encoding. */
root = BuildHuffTree(nodes);
ConvertToCodes(nodes, codes, 0, 0, root);
/* Encode the data. */
size += HuffEncode(data, buffer, codes, length);
return (size);
#else
TreeNode *nodes;
HuffCode *codes;
unsigned long *counts;
unsigned long max_count;
long i;
long size;
long first;
long last;
long next;
unsigned long symbol;
unsigned long mask;
/* Initialize variables. */
nodes = (TreeNode *)temp;
temp += (514 * sizeof(TreeNode));
counts = (unsigned long *)temp;
codes = (HuffCode *)temp;
/* Zero the initial counts. */
memset(temp, 0, 256 * sizeof(unsigned long));
size = 0;
/*-------------------------------------------------------------------------
* Calculate the distribution of the data then scale down the counts so
* they fit in an 8 bit value. This is done in order to limit the size of
* the codes to 16 bits.
*-----------------------------------------------------------------------*/
i = 0;
while (i < length) {
counts[((unsigned char *)data)[i]]++;
i++;
}
/* Scale down the counts. */
max_count = 0;
/* Find the maximum count. */
for (i = 0; i < 256; i++) {
if (counts[i] > max_count) {
max_count = counts[i];
}
}
if (max_count == 0) {
counts[0] = 1;
max_count = 1;
}
max_count /= 255;
max_count++;
/* Scale down the counts. */
for (i = 0; i < 256; i++) {
nodes[i].count = (unsigned long)(counts[i] / max_count);
/* Make sure that a node with a non-zero count does not get scaled
* down to zero.
*/
if ((nodes[i].count == 0) && (counts[i] != 0)) {
nodes[i].count = 1;
}
}
nodes[HUFF_EOS].count = 1;
/*-------------------------------------------------------------------------
* OUTPUT THE COUNTS
*
* In order to save space, we store runs of counts in the following format:
*
* Start, Stop, Counts..., Start, Stop, Counts..., ..., 0
*
* The list is terminated by storing a start value of zero (0).
*
* In order to efficiently use this format, we do not want to stop a run
* because of just one or two zero counts. So we include zero counts of
* less than three (3) in the run.
*-----------------------------------------------------------------------*/
/* Find the first occurance of a non-zero count. */
first = 0;
while ((first < 255) && (nodes[first].count == 0)) {
first++;
}
/* Each time I hit the start of the loop, I assume that first is the
* number for a run of non-zero values. The rest of the loop is
* concerned with finding the value for last, which is the end of the
* run, and the value of next, which is the start of the next run.
* At the end of the loop, I assign next to first, so it starts in on
* the next run.
*/
for (; first < 256; first = next) {
last = first + 1;
for (;;) {
/* Find the end of the run of non-zeros. */
for (; last < 256; last++) {
if (nodes[last].count == 0) {
break;
}
}
last--;
/* Check the beginning of the next run of non-zero counts. */
for (next = last + 1; next < 256; next++) {
if (nodes[next].count != 0) {
break;
}
}
/* Quit the run if we have reached the end. */
if (next > 255) {
break;
}
/* Quit the run if there is more than three non-zero counts. */
if ((next - last) > 3) {
break;
}
last = next;
};
/* Output Start and Stop. */
*buffer++ = first;
*buffer++ = last;
/* Output the run of counts. */
for (i = first; i <= last; i++) {
*buffer++ = (char)nodes[i].count;
}
size += (((last - first) + 1) + 2);
}
/* Output terminator. */
*buffer++ = 0;
size++;
/*-------------------------------------------------------------------------
* Build the Huffman tree. All active nodes are scanned in order to locate
* the two nodes with the minimum weights. These two weights are added
* together and assigned to a new node. The new node makes the two minimum
* nodes into its 0 child and 1 child. The two minimum nodes are then
* marked as inactive. This process repeats until their is only one node
* left, which is the root node.
*-----------------------------------------------------------------------*/
/* Node 513 is used to arbitratilly provide a node with a guaranteed
* maximum value.
*/
nodes[513].count = 0xFFFF;
for (next = (HUFF_EOS + 1); ; next++) {
first = 513;
last = 513;
for (i = 0; i < next; i++) {
/* We are only concerned with non-zero count nodes. */
if (nodes[i].count != 0) {
if (nodes[i].count < nodes[first].count) {
last = first;
first = i;
} else if (nodes[i].count < nodes[last].count) {
last = i;
}
}
}
if (last == 513) {
break;
}
nodes[next].count = (nodes[first].count + nodes[last].count);
nodes[first].count = 0;
nodes[last].count = 0;
nodes[next].child0 = (first << 3);
nodes[next].child1 = (last << 3);
}
next--;
/*-------------------------------------------------------------------------
* Convert the Huffman tree into an encoding table then encode the data.
*-----------------------------------------------------------------------*/
ConvertToCodes(nodes, codes, 0, 0, (next << 3));
/* Encode the data. */
*buffer = 0;
next = 0x80;
i = 0;
do {
if (i < length) {
symbol = ((unsigned char *)data)[i];
} else {
symbol = HUFF_EOS;
}
mask = 1L << (codes[symbol].bits - 1);
while (mask != 0) {
/* Set a bit in the output stream for each bit in the code. */
if (mask & codes[symbol].code) {
*buffer |= next;
}
/* Next bit position. */
next >>= 1;
/* Advance to the next byte in the output stream when the current
* byte is full.
*/
if (next == 0) {
buffer++;
*buffer = 0;
next = 0x80;
size++;
}
/* Next bit in the code. */
mask >>= 1;
}
i++;
} while (symbol != HUFF_EOS);
if (next != 0x80) {
size++;
}
return (size);
#endif
}
/****************************************************************************
*
* NAME
* HuffCount - Count the frequency of occurence of every byte.
*
* SYNOPSIS
* HuffCount(Data, Nodes, Length, Zero)
*
* void HuffCounts(unsigned char *, TreeNode *, long, long);
*
* FUNCTION
* This function counts the frequency of occurence of every byte in the
* input data. The nodes must be initialized to zero prior to calling this
* function for the first time, otherwise the counts will be flawed.
*
* INPUTS
* Data - Pointer to data to analyze.
* TreeNode - Pointer to array of nodes.
* Length - Length of data to analyze.
* Zero - Zero any previous counts flag. (TRUE = zero counts)
*
* RESULT
* Size - Amount of buffer used to hold counts.
*
****************************************************************************/
void cdecl HuffCount(unsigned char *data, TreeNode *nodes, long length,
long zero)
{
long i;
/* Zero any previous counts. */
if (zero) {
for (i = 0; i < 256; i++) {
nodes[i].count = 0;
}
}
/* Calculate the distribution of the data. */
i = 0;
while (i < length) {
nodes[((unsigned char *)data)[i]].count++;
i++;
}
}
/****************************************************************************
*
* NAME
* HuffScaleCounts - Scale down the frequency counts.
*
* SYNOPSIS
* HuffScaleCounts(Nodes)
*
* void HuffScaleCounts(TreeNode *);
*
* FUNCTION
* In order to limit the size of the Huffman codes to 16 bits, we must
* scale down the counts so they can be represented by a BYTE size value.
*
* INPUTS
* Nodes - Pointer to nodes to scale counts for.
*
* RESULT
* NONE
*
****************************************************************************/
void cdecl HuffScaleCounts(TreeNode *nodes)
{
unsigned long max_count;
unsigned long unscaled;
long i;
long first;
long last;
long next;
/* Scale down the counts so they fit in an 8 bit value. This is done in
* order to limit the size of the codes to 16 bits.
*/
max_count = 0;
/* Find the maximum count. */
for (i = 0; i < 256; i++) {
if (nodes[i].count > max_count) {
max_count = nodes[i].count;
}
}
if (max_count == 0) {
nodes[0].count = 1;
max_count = 1;
}
max_count /= 255;
max_count++;
/* Scale down the counts. */
for (i = 0; i < 256; i++) {
unscaled = nodes[i].count;
nodes[i].count /= max_count;
/* Make sure that a node with a non-zero count does not get scaled
* down to zero.
*/
if ((nodes[i].count == 0) && (unscaled != 0)) {
nodes[i].count = 1;
}
}
nodes[HUFF_EOS].count = 1;
}
/****************************************************************************
*
* NAME
* RLEHuffCounts - Run Length Encode the Huffman counts.
*
* SYNOPSIS
* Size = RLEHuffCounts(Nodes, Buffer)
*
* long RLEHuffCounts(TreeNode *, unsigned char *);
*
* FUNCTION
* In order for the decoder to build the same model, we have to transmit
* the symbol counts to it. To save space we do not save all 256 symbols
* unconditionally, instead we run length encode the counts. The format
* used to store the counts is as follows:
*
* Start, Stop, Counts[n], Start, Stop, Counts[n], .... 0
*
* Note: The sequence is terminated by a start value of 0. Also at least
* 1 run of counts has to be stored, even if the first start value is 0.
*
* INPUTS
* Nodes - Pointer to initialized nodes.
* Buffer - Pointer to buffer to store RLE'd counts.
*
* RESULT
* Size - Size of the RLE'd counts.
*
****************************************************************************/
long cdecl RLEHuffCounts(TreeNode *nodes, unsigned char *buffer)
{
long i;
long first;
long last;
long next;
long size = 0;
/* Find the first occurance of a non-zero count. */
first = 0;
while ((first < 255) && (nodes[first].count == 0)) {
first++;
}
/* Each time I hit the start of the loop, I assume that first is the
* number for a run of non-zero values. The rest of the loop is
* concerned with finding the value for last, which is the end of the
* run, and the value of next, which is the start of the next run.
* At the end of the loop, I assign next to first, so it starts in on
* the next run.
*/
for (; first < 256; first = next) {
last = first + 1;
for (;;) {
/* Find the end of the run of non-zeros. */
for (; last < 256; last++) {
if (nodes[last].count == 0) {
break;
}
}
last--;
/* Check the beginning of the next run of non-zero counts. */
for (next = last + 1; next < 256; next++) {
if (nodes[next].count != 0) {
break;
}
}
/* Quit the run if we have reached the end. */
if (next > 255) {
break;
}
/* Quit the run if there is more than three non-zero counts. */
if ((next - last) > 3) {
break;
}
last = next;
};
/* Output Start and Stop. */
*buffer++ = first;
*buffer++ = last;
/* Output the run of counts. */
for (i = first; i <= last; i++) {
*buffer++ = (unsigned char)nodes[i].count;
}
size += (((last - first) + 1) + 2);
}
/* Output terminator. */
*buffer = 0;
size++;
return (size);
}
/****************************************************************************
*
* NAME
* ConvertToCodes - Convert the Huffman tree into a table of codes.
*
* SYNOPSIS
* ConvertToCodes(Nodes, Codes, Code, Bits, Node)
*
* void ConvertToCodes(TreeNode *, HuffCode *, unsigned short, short,
* short);
*
* FUNCTION
* Since the Huffman tree is built as a decoding tree, there is no simple
* way to get the encoding values for each symbol. This routine
* recursively walks through the tree, adding the child bits to each code
* until it gets to a leaf. When it gets to a leaf, it stores the code
* value.
*
* INPUTS
* Nodes - Pointer to the Huffman tree.
* Codes - Pointer to the table of codes to generate.
* Code - Code being built (initialize with 0).
* Bits - Number of bits the code is comprised of (initialize with 0).
* Node - Number of the current node.
*
* RESULT
* NONE
*
****************************************************************************/
void cdecl ConvertToCodes(TreeNode *nodes, HuffCode *codes,
unsigned short code, short bits, short node)
{
node >>= 3;
if (node <= HUFF_EOS) {
codes[node].code = code;
codes[node].bits = bits;
return;
}
code <<= 1;
bits++;
ConvertToCodes(nodes, codes, code, bits, nodes[node].child0);
ConvertToCodes(nodes, codes, code|1, bits, nodes[node].child1);
}
/****************************************************************************
*
* NAME
* HuffEncode - Huffman encode the data.
*
* SYNOPSIS
* Size = HuffEncode(Data, Buffer, Codes, Length);
*
* long HuffEncode(unsigned char *, unsigned char *, HuffCodes *, long);
*
* FUNCTION
* Encoding of the data is simple. Each byte of data is taken as the index
* of the codes array, the corresponding code is then put in the output.
*
* INPUTS
* Data - Pointer to data to encode.
* Buffer - Pointer to buffer to hold encoded data.
* Codes - Pointer to array of Huffman codes.
* Length - Length of data buffer to encode.
*
* RESULT
* Size - Size of encoded data.
*
****************************************************************************/
long cdecl HuffEncode(unsigned char *data, unsigned char *buffer,
HuffCode *codes, long length)
{
long i;
long size;
long next;
unsigned long mask;
unsigned long symbol;
/* Initialize */
*buffer = 0;
next = 0x80;
i = 0;
do {
if (i < length) {
symbol = ((unsigned char *)data)[i];
} else {
symbol = HUFF_EOS;
}
mask = 1L << (codes[symbol].bits - 1);
while (mask != 0) {
/* Set a bit in the output stream for each bit in the code. */
if (mask & codes[symbol].code) {
*buffer |= next;
}
/* Next bit position. */
next >>= 1;
/* Advance to the next byte in the output stream when the current
* byte is full.
*/
if (next == 0) {
buffer++;
*buffer = 0;
next = 0x80;
size++;
}
/* Next bit in the code. */
mask >>= 1;
}
i++;
} while (symbol != HUFF_EOS);
if (next != 0x80) {
size++;
}
return (size);
}

391
VQ/VQM32/HUFFDCMP.ASM Normal file
View File

@@ -0,0 +1,391 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* huffdcmp.asm
;*
;* DESCRIPTION
;* Huffman order 0 decompressor.
;*
;* PROGRAMMER
;* Denzil E. Long, Jr.
;*
;* DATE
;* May 22, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* HuffDecompress - Decompress Huffman order 0 encoded data.
;* BuildHuffTree - Build the Huffman decode tree.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
STRUC TreeNode
count DD ? ;Weight of the node
child0 DW ? ;Child node 0
child1 DW ? ;Child node 1
ENDS TreeNode
HUFF_EOS EQU 256
CODESEG
;****************************************************************************
;*
;* NAME
;* HuffDecompress - Decompress Huffman order 0 encoded data.
;*
;* SYNOPSIS
;* Size = HuffDecompress(Data, Buffer, Length, Temp)
;*
;* long = HuffDecompress(unsigned char *, unsigned char *, long, char *);
;*
;* FUNCTION
;* Expand data that has been compressed with order 0 Huffman coding.
;* The model (counts) are extracted from the data and a decode tree is
;* built. The data is expanded by reading a bit and traversing the tree
;* until a leaf node is encountered.
;*
;* INPUTS
;* Data - Pointer to Huffman encoded data.
;* Buffer - Pointer to decompress buffer.
;* Length - Maximum decompress length.
;* Temp - Pointer to temporary working buffer. (Must be >= 5120 bytes!)
;*
;* RESULT
;* Size - Size of decompressed data.
;*
;****************************************************************************
GLOBAL C HuffDecompress:NEAR
PROC HuffDecompress C NEAR USES esi edi ebx ecx edx
ARG data:NEAR PTR
ARG buffer:NEAR PTR
ARG length:DWORD
ARG temp:NEAR PTR
LOCAL next:DWORD
;*---------------------------------------------------------------------------
;* Read in the set of counts
;*---------------------------------------------------------------------------
mov esi,[data] ;Compressed data
mov ebx,[temp] ;Nodes array
mov ax,[esi] ;Get first and last count
xor edx,edx ;i = 0
xor ecx,ecx
add esi,2
??getcounts:
cmp al,dl ;Reached start of run?
jne ??zerocount
;* Copy the run of counts to the nodes
sub ah,al ;Run length = Stop - Start
xor ecx,ecx
mov cl,ah
xor eax,eax
inc ecx ;Run length + 1
??copycounts:
mov al,[esi] ;Get count
inc edx ;i++
mov [ebx],eax ;Write count to node
inc esi
add ebx,8 ;Next node
dec ecx
jnz ??copycounts
mov ax,[esi] ;Get next start
inc esi
cmp al,0 ;Terminator?
je short ??nextcount
inc esi
jmp short ??nextcount
;* Fill empty nodes with 0
??zerocount:
mov [DWORD PTR ebx],ecx
inc edx ;i++
add ebx,8 ;Next node
??nextcount:
cmp edx,256
jl short ??getcounts
mov [WORD PTR ebx],1
mov [data],esi
;*---------------------------------------------------------------------------
;* Build the Huffman tree. All active nodes are scanned in order
;* to locate the two nodes with the minimum weights. These two
;* weights are added together and assigned a new node. The new
;* node makes the two minimum nodes into its 0 child and 1 child.
;* The two minimum nodes are then marked as inactive. This process
;* repeats until their is only one node left, which is the root.
;*---------------------------------------------------------------------------
mov eax,[temp] ;Nodes array
mov esi,eax
add eax,(513 * 8) ;Node[513] = guaranteed maximum
mov [DWORD PTR eax],-1
mov [next],((HUFF_EOS + 1) * 8)
??sortnext:
mov edx,(513 * 8) ;first = 513
mov edi,edx ;last = 513
xor ecx,ecx ;i = 0
mov ebx,esi ;nodes[i]
??sortnodes:
cmp [WORD PTR ebx],0 ;Only check non-zero nodes
jz ??nextnode
;* nodes[i].count < nodes[first].count
mov eax,[DWORD PTR esi + edx]
cmp eax,[DWORD PTR ebx]
jbe ??checklast
mov edi,edx ;last = first
mov edx,ecx ;first = i
jmp short ??nextnode
;* nodes[i].count < nodes[last].count
??checklast:
mov eax,[DWORD PTR esi + edi]
cmp eax,[DWORD PTR ebx]
jbe ??nextnode
mov edi,ecx ;last = i
??nextnode:
add ecx,8 ;i++
add ebx,8 ;nodes[i]
cmp ecx,[next]
jne short ??sortnodes
;* Tree done when last = 513
cmp edi,(513 * 8)
je short ??decode
mov ebx,[next]
add ebx,esi
mov [WORD PTR ebx+4],dx ;nodes[next].child0 = first
mov [WORD PTR ebx+6],di ;nodes[next].child1 = last
add edx,esi
mov eax,[DWORD PTR edx] ;nodes[first].count
add edi,esi
mov [DWORD PTR ebx],eax
mov ecx,[DWORD PTR edi] ;nodes[last].count
xor eax,eax
add [DWORD PTR ebx],ecx
mov [DWORD PTR edx],eax ;nodes[first].count = 0
mov [DWORD PTR edi],eax ;nodes[lats].count = 0
add [next],8
jmp ??sortnext
;*---------------------------------------------------------------------------
;* Expand the compressed data. As each new symbol is decoded, the
;* tree is traversed, starting at the root node, reading a bit in,
;* and taking either the child0 or child1 path. Eventually, the
;* tree winds down to a leaf node, and the corresponding symbol is
;* output. If the symbol is the HUFF_EOS symbol the process
;* terminates.
;*---------------------------------------------------------------------------
??decode:
sub [next],8 ;rootnode - 1
xor ecx,ecx
mov esi,[data] ;Input data buffer
mov al,080h ;mask = 0x80
mov edi,[buffer] ;Output buffer
mov ah,[esi] ;Data byte
mov ebx,[temp]
inc esi
??decodeloop:
mov edx,[next] ;node = root
??walktree:
mov ecx,4
add ecx,edx
test al,ah
jz short ??getnode
add ecx,2
??getnode:
mov dx,[WORD PTR ebx + ecx] ;nodes[node].child
shr al,1
jnz short ??checkleaf
mov ah,[esi] ;Get next data byte
mov al,080h ;Reset mask
inc esi
??checkleaf:
cmp edx,(HUFF_EOS * 8)
jg short ??walktree
je short ??done
shr edx,3
mov [edi],dl
inc edi
jmp short ??decodeloop
??done:
mov eax,edi
sub eax,[buffer]
ret
ENDP HuffDecompress
;****************************************************************************
;*
;* NAME
;* BuildHuffTree - Build the Huffman decode tree.
;*
;* SYNOPSIS
;* Root = BuildHuffTree(Nodes)
;*
;* long BuildHuffTree(TreeNode *);
;*
;* FUNCTION
;* Build the Huffman tree. All active nodes are scanned in order to
;* locate the two nodes with the minimum weights. These two weights are
;* added together and assigned a new node. The new node makes the two
;* minimum nodes into its 0 child and 1 child. The two minimum nodes are
;* then marked as inactive. This process repeats until their is only one
;* node left, which is the root.
;*
;* INPUTS
;* Nodes - Pointer to array of nodes.
;*
;* RESULT
;* Root - Number of root node.
;*
;****************************************************************************
GLOBAL C BuildHuffTree:NEAR
PROC BuildHuffTree C NEAR USES esi edi ebx ecx edx
ARG temp:NEAR PTR
LOCAL next:DWORD
mov eax,[temp] ;Nodes array
mov esi,eax
add eax,(513 * 8) ;Node[513] = guaranteed maximum
mov [DWORD PTR eax],-1
mov [next],((HUFF_EOS + 1) * 8)
??sortnext:
mov edx,(513 * 8) ;first = 513
mov edi,edx ;last = 513
xor ecx,ecx ;i = 0
mov ebx,esi ;nodes[i]
??sortnodes:
cmp [WORD PTR ebx],0 ;Only check non-zero nodes
jz ??nextnode
;* nodes[i].count < nodes[first].count
mov eax,[DWORD PTR esi + edx]
cmp eax,[DWORD PTR ebx]
jbe ??checklast
mov edi,edx ;last = first
mov edx,ecx ;first = i
jmp short ??nextnode
;* nodes[i].count < nodes[last].count
??checklast:
mov eax,[DWORD PTR esi + edi]
cmp eax,[DWORD PTR ebx]
jbe ??nextnode
mov edi,ecx ;last = i
??nextnode:
add ecx,8 ;i++
add ebx,8
cmp ecx,[next]
jne short ??sortnodes
;* Tree done when last = 513
cmp edi,(513 * 8)
je short ??done
mov ebx,[next]
add ebx,esi ;nodes[next]
mov [WORD PTR ebx+4],dx ;nodes[next].child0 = first
mov [WORD PTR ebx+6],di ;nodes[next].child1 = last
add edx,esi
mov eax,[DWORD PTR edx] ;nodes[first].count
add edi,esi
mov [DWORD PTR ebx],eax
mov ecx,[DWORD PTR edi] ;nodes[last].count
xor eax,eax
add [DWORD PTR ebx],ecx
mov [DWORD PTR edx],eax ;nodes[first].count = 0
mov [DWORD PTR edi],eax ;nodes[lats].count = 0
add [next],8
jmp ??sortnext
??done:
mov eax,[next]
sub eax,8
ret
ENDP BuildHuffTree
END

99
VQ/VQM32/HUFFMAN.H Normal file
View File

@@ -0,0 +1,99 @@
/*
** 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/>.
*/
#ifndef HUFFMAN_H
#define HUFFMAN_H
/****************************************************************************
*
* C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* huffman.h
*
* DESCRIPTION
* Huffman order 0 compress/decompress definitions.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* May 19, 1995
*
****************************************************************************/
/* TreeNode: Huffman decoding tree node.
*
* count - Weight of the node in the tree.
* child0 - Child node 0
* child1 - Child node 1
*/
typedef struct _TreeNode {
unsigned long count;
unsigned short child0;
unsigned short child1;
} TreeNode;
/* HuffCode: This structure is used for storing the code for each symbol
* during encoding. A table of codes for each symbol is built
* from the Huffman tree.
*
* code - Code used to represent a symbol.
* bits - Length of code in bits.
*/
typedef struct _HuffCode {
unsigned short code;
short bits;
} HuffCode;
#define HUFF_EOS 256 /* End of stream symbol */
/* Prototypes */
#ifdef __cplusplus
extern "C" {
#endif
long cdecl HuffCompress(unsigned char *data, unsigned char *buffer,
long length, char *work);
long cdecl HuffDecompress(unsigned char *data, unsigned char *buffer,
long length, char *work);
void cdecl HuffCount(unsigned char *data, TreeNode *nodes, long length,
long zero);
void cdecl HuffScaleCounts(TreeNode *nodes);
long cdecl RLEHuffCounts(TreeNode *nodes, unsigned char *buffer);
long cdecl BuildHuffTree(TreeNode *nodes);
void cdecl ConvertToCodes(TreeNode *nodes, HuffCode *codes,
unsigned short code, short bits, short node);
long cdecl HuffEncode(unsigned char *data, unsigned char *buffer,
HuffCode *codes, long length);
#ifdef __cplusplus
}
#endif
#endif /* HUFFMAN_H */

699
VQ/VQM32/IFF.CPP Normal file
View File

@@ -0,0 +1,699 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* iff.c
*
* DESCRIPTION
* IFF manager. (32-Bit protected mode)
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* January 26, 1995
*
*----------------------------------------------------------------------------
*
* PUBLIC
* OpenIFF - Open an IFF for reading or writting.
* CloseIFF - Close an IFF.
* ReadForm - Read the IFF FORM, size and type of the file.
* WriteForm - Write IFF form ID, size and type fields.
* ReadChunkHeader - Read the IFF chunk identification header.
* WriteChunkHeader - Write an IFF chunk identification header.
* WriteChunk - Write an IFF chunk with data from a buffer.
* WriteChunkBytes - Write data from a buffer to the IFF stream.
* SkipChunkBytes - Skip bytes in a chunk.
* FindChunk - Scan for a specific chunk name.
* IDtoStr - Convert a longword identifier to a NULL-terminated
* string.
* CurrentFilePos - Get the current file position.
*
****************************************************************************/
#include <stdio.h>
#include <malloc.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <mem.h>
#include "iff.h"
/****************************************************************************
*
* NAME
* OpenIFF - Open an IFF for reading or writting.
*
* SYNOPSIS
* IFFHandle = OpenIFF(Name, Mode)
*
* IFFHandle *OpenIFF(char *, long);
*
* FUNCTION
* Opens an IFF for a new read or write. The direction of the I/O is
* given by the value of Mode, which can be either IFF_READ or IFF_WRITE.
*
* INPUTS
* Name - Pointer to name of file to open.
* Mode - IFF_READ or IFF_WRITE.
*
* RESULT
* IFFHandle - Pointer to IFFHandle structure or NULL if error.
*
****************************************************************************/
IFFHandle *OpenIFF(char *name, long mode)
{
IFFHandle *iff;
/* Allocate IFFHandle structure. */
if ((iff = (IFFHandle *)malloc(sizeof(IFFHandle))) != NULL) {
/* Initialize handle.*/
memset(iff, 0, sizeof(IFFHandle));
iff->flags = mode;
switch (mode) {
case IFFF_READ:
iff->fh = open(name, O_RDONLY|O_BINARY);
break;
case IFFF_WRITE:
iff->fh = open(name, (O_CREAT|O_TRUNC|O_WRONLY|O_BINARY),
(S_IREAD|S_IWRITE));
printf("\r");
break;
case (IFFF_READ|IFFF_WRITE):
iff->fh = open(name, (O_RDWR|O_BINARY), (S_IREAD|S_IWRITE));
break;
default:
iff->fh = -1;
break;
}
/* If something went wrong we must free up any resources
* that we have opened.
*/
if (iff->fh == -1) {
free(iff);
iff = NULL;
}
}
return (iff);
}
/****************************************************************************
*
* NAME
* CloseIFF - Close an IFF.
*
* SYNOPSIS
* CloseIFF(IFFHandle)
*
* void CloseIFF(IFFHandle *);
*
* FUNCTION
* Completes an IFF read or write operation.
*
* INPUTS
* IFFHandle - Pointer to IFFHandle structure.
*
* RESULT
* NONE
*
****************************************************************************/
void CloseIFF(IFFHandle *iff)
{
long length;
/* Write the length of the FORM */
if ((iff->flags & IFFF_WRITE) && ((iff->form.size == 0)
|| (iff->scan > iff->form.size))) {
lseek(iff->fh, 4, SEEK_SET);
length = REVERSE_LONG(iff->scan);
write(iff->fh, &length, 4);
}
close(iff->fh);
free(iff);
}
/****************************************************************************
*
* NAME
* ReadForm - Read the IFF FORM, size and type of the file.
*
* SYNOPSIS
* Error = ReadForm(IFFHandle, FormHeader)
*
* long ReadForm(IFFHandle *, FormHeader *);
*
* FUNCTION
* Read in the IFF form, size, type information. If the FormHeader
* structure pointer is NULL then the FORM will be read into the
* IFFHandles form structure.
*
* INPUTS
* IFFHandle - Pointer to IFFHandle structure.
* FormHeader - Pointer to FormHeader structure.
*
* RESULT
* Error - 0 if successful or IFFERR_??? error code.
*
****************************************************************************/
long ReadForm(IFFHandle *iff, FormHeader *form)
{
FormHeader *ptr;
long error;
/* Read the FORM into the IFFHandle or the provided FormHeader. */
if (form == NULL) {
ptr = &iff->form;
} else {
ptr = form;
}
/* Read in IFF FORM from the file stream.. */
if ((error = read(iff->fh, ptr, 12)) == 12) {
ptr->size = REVERSE_LONG(ptr->size);
iff->scan = 4;
error = 0;
} else {
if (error == -1)
error = IFFERR_READ;
else if (error == 0)
error = IFFERR_EOF;
}
return (error);
}
/****************************************************************************
*
* NAME
* WriteForm - Write IFF form ID, size and type fields.
*
* SYNOPSIS
* Error = WriteForm(IFFHandle)
*
* long WriteForm(IFFHandle, FormHeader *);
*
* FUNCTION
* Write out the IFF form, size, type information. If the size field
* is zero then the IFF form size will be calculated and written by
* the CloseIFF() function. If the FormHeader structure pointer is NULL
* the the form from the IFFHandle will be written.
*
* INPUTS
* IFFHandle - Pointer to IFFHandle structure.
* FormHeader - Pointer to FormHeader structure.
*
* RESULT
* Error - 0 if successful or IFFERR_??? error code.
*
****************************************************************************/
long WriteForm(IFFHandle *iff, FormHeader *form)
{
FormHeader *ptr;
long error = 0;
/* Use the FORM from the IFFHandle or the provided FormHeader. */
if (form == NULL) {
ptr = &iff->form;
} else {
ptr = form;
}
/* Write the IFF form to the file stream. */
if (iff->flags & IFFF_WRITE) {
ptr->size = REVERSE_LONG(ptr->size);
if (write(iff->fh, ptr, 12) == 12) {
iff->scan = 4;
} else {
error = IFFERR_WRITE;
}
} else {
error = IFFERR_WRITE;
}
return (error);
}
/****************************************************************************
*
* NAME
* ReadChunkHeader - Read the IFF chunk identification header.
*
* SYNOPSIS
* Error = ReadChunkHeader(IFFHandle)
*
* long ReadChunkHeader(IFFHandle *);
*
* FUNCTION
* Read the IFF identification header from the files data stream.
*
* INPUTS
* IFFHandle - Pointer to IFFHandle structure.
*
* RESULT
* Error - 0 if successful or IFFERR_??? error code.
*
****************************************************************************/
long ReadChunkHeader(IFFHandle *iff)
{
long error = 0;
/* Skip any part of the previous chunk that hasn't been processed. */
if ((iff->cn.size != 0) && (iff->cn.scan < PADSIZE(iff->cn.size))) {
error = lseek(iff->fh, (PADSIZE(iff->cn.size) - iff->cn.scan), SEEK_CUR);
if (error == -1) {
error = IFFERR_READ;
} else {
error = 0;
}
}
/* Read in the next chunk header context. */
if (!error) {
if ((error = read(iff->fh, &iff->cn, 8)) == 8) {
error = 0;
iff->scan += 8;
iff->cn.size = REVERSE_LONG(iff->cn.size);
iff->cn.scan = 0;
} else {
if (error == -1) {
error = IFFERR_READ;
} else if (error == 0) {
error = IFFERR_EOF;
}
}
}
return (error);
}
/****************************************************************************
*
* NAME
* WriteChunkHeader - Write an IFF chunk identification header.
*
* SYNOPSIS
* Error = WriteChunkHeader(IFFHandle, ID, Size)
*
* long WriteChunkHeader(IFFHandle *, long, long);
*
* FUNCTION
* Write an IFF identification header to the files data stream.
*
* INPUTS
* IFFHandle - Pointer to IFFHandle structure.
* ID - ID code of chunk.
* Size - Size of chunk in bytes (WORD aligned).
*
* RESULT
* Error - 0 if successful or IFFERR_??? error code.
*
****************************************************************************/
long WriteChunkHeader(IFFHandle *iff, long id, long size)
{
long error = 0;
/* Make sure it is okay to write. */
if (iff->flags & IFFF_WRITE) {
iff->cn.id = id;
iff->cn.size = REVERSE_LONG(size);
iff->cn.scan = 0;
if (write(iff->fh, &iff->cn, 8) == 8) {
iff->scan += 8;
} else {
error = IFFERR_WRITE;
}
}
return (error);
}
/****************************************************************************
*
* NAME
* WriteChunk - Write an IFF chunk with data from a buffer.
*
* SYNOPSIS
* Actual = WriteChunk(IFFHandle, ID, Buffer, Size)
*
* long WriteChunk(IFFHandle *, long, char *, long);
*
* FUNCTION
* Write a IFF chunk at the current file position.
*
* INPUTS
* IFFHandle - Pointer to IFFHandle structure.
* ID - ID code of chunk.
* Buffer - Pointer to buffer area with bytes to be written.
* Size - Number of bytes to write.
*
* RESULT
* Actual - (positive) Bytes written or (negative) IFFERR_??? error code.
*
****************************************************************************/
long WriteChunk(IFFHandle *iff, long id, char *buffer, long size)
{
Context cn;
long actual;
/* Make sure we can write to this file. */
if (iff->flags & IFFF_WRITE) {
cn.id = id;
cn.size = REVERSE_LONG(size);
/* Write chunk header. */
if (write(iff->fh, &cn, 8) == 8) {
iff->scan += 8;
iff->cn.scan += 8;
/* Write chunk data. */
actual = write(iff->fh, buffer, size);
if (actual == size) {
iff->scan += actual;
iff->cn.scan += actual;
/* Write chunk padding if necessary. */
if (PADSIZE(size) > size) {
id = 0;
if (write(iff->fh, &id, 1) == 1) {
iff->scan++;
iff->cn.scan++;
} else {
actual = IFFERR_WRITE;
}
}
} else {
actual = IFFERR_WRITE;
}
} else {
actual = IFFERR_WRITE;
}
} else {
actual = IFFERR_WRITE;
}
return (actual);
}
/****************************************************************************
*
* NAME
* WriteChunkBytes - Write data from a buffer to the IFF stream.
*
* SYNOPSIS
* Actual = WriteChunkBytes(IFFHandle, Buffer, Size)
*
* long WriteChunk(IFFHandle *, char *, long);
*
* FUNCTION
* Write a IFF chunk at the current file position.
*
* INPUTS
* IFFHandle - Pointer to IFFHandle structure.
* Buffer - Pointer to buffer area with bytes to be written.
* Size - Number of bytes to write.
*
* RESULT
* Actual - (positive) Bytes written or (negative) IFFERR_??? error code.
*
****************************************************************************/
long WriteChunkBytes(IFFHandle *iff, char *buffer, long size)
{
long actual;
/* Make sure we can write to this file. */
if (iff->flags & IFFF_WRITE) {
/* Write data. */
if ((actual = (unsigned short)write(iff->fh, buffer, size)) == size) {
iff->scan += actual;
iff->cn.scan += actual;
} else {
actual = IFFERR_WRITE;
}
} else {
actual = IFFERR_WRITE;
}
return (actual);
}
/****************************************************************************
*
* NAME
* ReadChunkBytes - Read data from a chunk into a buffer.
*
* SYNOPSIS
* Actual = ReadChunkBytes(IFFHandle, Buffer, Length)
*
* long ReadChunkBytes(IFFHandle *, char *, long);
*
* FUNCTION
* Read in 'Length' number of bytes from the current chunk context.
* If the specified length exceeds the number of bytes remaining in the
* chunk ReadChunkBytes() will read in only the number of remaining
* bytes. ReadChunkBytes() will never read beyond the scope of the
* current chunk.
*
* INPUTS
* IFFHandle - Pointer to IFFHandle structure.
* Buffer - Pointer to buffer to read data into.
* Length - Number of bytes to read.
*
* RESULT
* Actual - (positive) Bytes written or (negative) IFFERR_??? error code.
*
****************************************************************************/
long ReadChunkBytes(IFFHandle *iff, char *buffer, long size)
{
long actual;
/* If the actual bytes remaining in the current chunk is less than
* the requested bytes to read then adjust the read request size
* to only read in the bytes that remain in the chunk.
*/
actual = (iff->cn.size - iff->cn.scan);
if (size > actual) {
size = actual;
}
/* Read in the requested number of bytes. */
if ((actual = read(iff->fh, buffer, size)) != size) {
actual = IFFERR_READ;
} else {
iff->scan += actual;
iff->cn.scan += actual;
}
return (actual);
}
/****************************************************************************
*
* NAME
* SkipChunkBytes - Skip bytes in a chunk.
*
* SYNOPSIS
* Error = SkipChunkBytes(IFFHandle, Skip)
*
* long SkipChunkBytes(IFFHandle *, long);
*
* FUNCTION
* Skip the specified number of bytes of the chunk.
*
* INPUTS
* IFFHandle - Pointer to IFFHandle structure.
* Skip - Number of bytes to skip.
*
* RESULT
* Error - 0 if successful or FAIL_??? error code.
*
****************************************************************************/
long SkipChunkBytes(IFFHandle *iff, long skip)
{
long error = 0;
if (lseek(iff->fh, skip, SEEK_CUR) == -1) {
error = IFFERR_READ;
} else {
iff->scan += skip;
iff->cn.scan += skip;
}
return (error);
}
/****************************************************************************
*
* NAME
* FindChunk - Scan for a specific chunk name.
*
* SYNOPSIS
* Error = FindChunk(IFFHandle, ID)
*
* long FindChunk(IFFHandle *, long);
*
* FUNCTION
* Scan from the current file position for the next occurance of the
* specified chunk ID. When a match is found the function will return
* with the matching chunk as the current context.
*
* INPUTS
* IFFHandle - Pointer to IFFHandle structure.
* ID - ID code of chunk.
*
* RESULT
* Error - 0 if successful or FAIL_??? error code.
*
****************************************************************************/
long FindChunk(IFFHandle *iff, long id)
{
long found = 0;
long error = 0;
/* Invalid handle check. */
if (iff != NULL) {
/* Scan until we have a match or an error. */
while ((found == 0) && !(error = ReadChunkHeader(iff))) {
/* If we found a match the terminate scan, otherwise skip this
* chunk and process the next.
*/
if (iff->cn.id == id) {
found = 1;
} else {
error = SkipChunkBytes(iff, PADSIZE(iff->cn.size));
}
}
}
return (error);
}
/****************************************************************************
*
* NAME
* IDtoStr - Convert a longword identifier to a NULL-terminated string.
*
* SYNOPSIS
* String = IDtoStr(ID, Buffer)
*
* char *IDtoStr(long, char *);
*
* FUNCTION
* Writes the ASCII equivalent of the given longword ID into buffer as a
* NULL-terminated string.
*
* INPUTS
* ID - Longword ID.
* Buffer - Character buffer to accept string (at least 5 characters).
*
* RESULT
* String - The value of "Buffer".
*
****************************************************************************/
char *IDtoStr(long id, char *buf)
{
memcpy(buf, &id, 4);
*(buf + 4) = 0;
return (buf);
}
/****************************************************************************
*
* NAME
* CurrentFilePos - Get the current file position.
*
* SYNOPSIS
* Position = CurrentFilePos(IFFHandle)
*
* long CurrentFilePos(IFFHandle *);
*
* FUNCTION
* This function returns the offset in bytes of the current file position
* from the beginning of the IFF.
*
* INPUTS
* IFFHandle - Pointer to IFFHandle structure.
*
* RESULT
* Position - Offset in bytes from the beginning of the file to the
* current position.
*
****************************************************************************/
long CurrentFilePos(IFFHandle *iff)
{
long offset;
if ((offset = lseek(iff->fh, 0, SEEK_CUR)) == -1) {
offset = IFFERR_READ;
}
return (offset);
}

141
VQ/VQM32/IFF.H Normal file
View File

@@ -0,0 +1,141 @@
/*
** 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/>.
*/
#ifndef VQMIFF_H
#define VQMIFF_H
/****************************************************************************
*
* C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* iff.h
*
* DESCRIPTION
* IFF (Interchange File Format) manager definitions.
* (32-Bit protected mode)
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* January 26, 1995
*
****************************************************************************/
/* FormHeader - Structure associated with IFF forms.
*
* id - IFF form id (IE: "FORM")
* size - Length of IFF in bytes
* type - Form type (IE: "ILBM")
*/
typedef struct _FormHeader {
long id;
long size;
long type;
} FormHeader;
/* Context - Structure associated with chunks.
*
* id - Chunk identifier.
* size - Size of chunk in bytes.
* scan - Bytes read/written.
*/
typedef struct _Context {
long id;
long size;
long scan;
} Context;
/* IFFHandle - Structure associated with an active IFF read\write session.
*
* fh - DOS filehandle
* flags - Internal flags used by IFF routines.
* form - IFF form information.
* scan - Bytes read/written
* cn - Context of current chunk.
*/
typedef struct _IFFHandle {
long fh;
long flags;
FormHeader form;
long scan;
Context cn;
} IFFHandle;
/* bit masks for "flags" field. */
#define IFFB_READ 0
#define IFFB_WRITE 1
#define IFFF_READ (1<<IFFB_READ)
#define IFFF_WRITE (1<<IFFB_WRITE)
/* IFF return codes. Most functions return either zero for success or
* one of these codes. The exceptions are the read/write functions which,
* return positive values for number of bytes read or written, or a negative
* error code.
*
* IFFERR_EOF - End of file.
* IFFERR_READ - Read error.
* IFFERR_WRITE - Write error.
* IFFERR_NOMEM - Unable to allocate memory.
*/
#define IFFERR_EOF -1
#define IFFERR_READ -2
#define IFFERR_WRITE -3
#define IFFERR_NOMEM -4
/* Macros to make things easier. */
#define REVERSE_LONG(id) (unsigned long)((((unsigned long)(id)>>24) \
&0x000000FFL)|(((unsigned long)(id)>>8) \
&0x0000FF00L)|(((unsigned long)(id)<<8) \
&0x00FF0000L)|(((unsigned long)(id)<<24)&0xFF000000L))
#define REVERSE_WORD(id) ((unsigned short)((((unsigned short)(id)<<8) \
&0x00FF00)|(((unsigned short)(id)>>8)&0x0FF)))
#define PADSIZE(size) (((size)+1)&(~1))
#ifndef MAKE_ID
#define MAKE_ID(a,b,c,d) ((long)((long)(d)<<24)|((long)(c)<<16)| \
((long)(b)<<8)|(long)(a))
#endif
/* Universal IFF identifiers */
#define ID_FORM MAKE_ID('F','O','R','M')
#define ID_LIST MAKE_ID('L','I','S','T')
#define ID_PROP MAKE_ID('P','R','O','P')
#define ID_NULL MAKE_ID(' ',' ',' ',' ')
/* Prototypes */
IFFHandle *OpenIFF(char *, long);
void CloseIFF(IFFHandle *);
long ReadForm(IFFHandle *, FormHeader *);
long WriteForm(IFFHandle *, FormHeader *);
long ReadChunkHeader(IFFHandle *);
long WriteChunkHeader(IFFHandle *, long, long);
long WriteChunk(IFFHandle *, long, char *, long);
long WriteChunkBytes(IFFHandle *, char *, long);
long ReadChunkBytes(IFFHandle *, char *, long);
long SkipChunkBytes(IFFHandle *, long);
long FindChunk(IFFHandle *, long);
char *IDtoStr(long, char *);
long CurrentFilePos(IFFHandle *);
#endif /* VQMIFF_H */

266
VQ/VQM32/LCWCOMP.ASM Normal file
View File

@@ -0,0 +1,266 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* lcwcomp.asm
;*
;* DESCRIPTION
;* LCW compression code. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Louis Castle
;* Denzil E. Long, Jr.
;*
;* DATE
;* January 26, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* LCW_Compress - LCW compress a buffer of memory.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
CODESEG
;****************************************************************************
;*
;* NAME
;* LCW_Compress - LCW compress a buffer of memory.
;*
;* SYNOPSIS
;* Size = LCW_Compress(Source, Dest, Length)
;*
;* long LCW_Compress(void *, void *, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Source - Pointer to data to compress.
;* Dest - Pointer to buffer to put compressed data.
;* Length - Length in bytes of data to compress.
;*
;* RESULT
;* Size - Size in bytes of compresed data.
;*
;****************************************************************************
GLOBAL C LCW_Compress:NEAR
PROC LCW_Compress C NEAR USES ebx ecx edx esi edi
ARG source:DWORD
ARG dest:DWORD
ARG datasize:DWORD
LOCAL inlen:DWORD
LOCAL a1stdest:DWORD
LOCAL a1stsrc:DWORD
LOCAL lenoff:DWORD
LOCAL ndest:DWORD
LOCAL count:DWORD
LOCAL matchoff:DWORD
LOCAL end_of_data:DWORD
mov esi,[source]
mov edi,[dest]
mov edx,[datasize]
cld ;Forward direction
mov ebx,esi
add ebx,edx
mov [end_of_data],ebx ;Save end of source address
mov [inlen],1 ;Set the in-length flag
mov [a1stdest],edi ;Save original dest
mov [a1stsrc],esi ;Save original source
mov [lenoff],edi ;Save offset length
mov al,081h ;First byte is always a len
stosb ;Write out a len of 1
lodsb ;Get the byte
stosb ;Save it
??loop:
mov [ndest],edi ;Save offset of compressed data
mov edi,[a1stsrc] ;Get address of first byte
mov [count],1 ;Set the count of run to 0
??searchloop:
sub eax,eax
mov al,[esi] ;Get the current byte of data
cmp al,[esi + 64]
jne short ??notrunlength
mov ebx,edi
mov edi,esi
mov ecx,[end_of_data]
sub ecx,edi
repe scasb
dec edi
mov ecx,edi
sub ecx,esi
cmp ecx,65
jb short ??notlongenough
mov [inlen],0 ;Clear the in-length flag
mov esi,edi
mov edi,[ndest]
mov ah,al
mov al,0FEh
stosb
xchg ecx,eax
stosw
mov al,ch
stosb
mov [ndest],edi ;Save offset of compressed data
mov edi,ebx
jmp ??searchloop
??notlongenough:
mov edi,ebx
??notrunlength:
??oploop:
mov ecx,esi ;Address of the last byte +1
sub ecx,edi ;Total number of bytes left
jz short ??searchdone
repne scasb ;Look for a match
jne short ??searchdone ;If we don't find one we're done
mov ebx,[count]
mov ah,[esi+ebx-1]
cmp ah,[edi+ebx-2]
jne ??oploop
mov edx,esi ;Save address for the next search
mov ebx,edi ;Save address for the length calc
dec edi ;Back up one for compare
mov ecx,[end_of_data] ;Get the end of data
sub ecx,esi ;Sub current source for max len
repe cmpsb ;See how many bytes match
jne short ??notend
inc edi
??notend:
mov esi,edx
mov eax,edi ;Get the dest
sub eax,ebx ;Sub the start for total bytes that match
mov edi,ebx ;Restore dest
cmp eax,[count] ;See if its better than before
jb ??searchloop ;If not keep looking
mov [count],eax ;If so keep the count
dec ebx ;Back it up for the actual match offset
mov [matchoff],ebx ;Save the offset for later
jmp ??searchloop ;Loop until we searched it all
??searchdone:
mov ecx,[count] ;Get the count of the longest run
mov edi,[ndest] ;Get the paragraph of our compressed data
cmp ecx,2 ;See if its not enough run to matter
jbe short ??lenin ;If its 0,1, or 2 its too small
cmp ecx,10 ;If not, see if it would fit in a short
ja short ??medrun ;If not, see if its a medium run
mov eax,esi ;If its short get the current address
sub eax,[matchoff] ;Sub the offset of the match
cmp eax,0FFFh ;If its less than 12 bits its a short
ja short ??medrun ;If its not, its a medium
??shortrun:
mov bl,cl ;Get the length (3-10)
sub bl,3 ;Sub 3 for a 3 bit number 0-7
shl bl,4
add ah,bl
xchg ah,al
jmp short ??srunnxt ;Do the run fixup code
??medrun:
cmp ecx,64 ;See if its a short run
ja short ??longrun ;If not, oh well at least its long
sub cl,3 ;Back down 3 to keep it in 6 bits
or cl,0C0h ;The highest bits are always on
mov al,cl ;Put it in al for the stosb
stosb ;Store it
jmp short ??medrunnxt ;Do the run fixup code
??lenin:
cmp [inlen],0 ;Is it doing a length?
jnz short ??len ;If so, skip code
??lenin1:
mov [lenoff],edi ;Save the length code offset
mov al,80h ;Set the length to 0
stosb ;Save it
??len:
mov ebx,[lenoff] ;Get the offset of the length code
cmp [BYTE PTR ebx],0BFh ;See if its maxed out
je ??lenin1 ;If so put out a new len code
??stolen:
inc [BYTE PTR ebx] ;Inc the count code
lodsb ;Get the byte
stosb ;Store it
mov [inlen],1 ;We are now in a length so save it
jmp short ??nxt ;Do the next code
??longrun:
mov al,0FFh ;Its a long so set a code of FF
stosb ;Store it
mov eax,[count] ;Send out the count
stosw ;Store it
??medrunnxt:
mov eax,[matchoff] ;Get the offset
sub eax,[a1stsrc] ;Make it relative tot he start of data
??srunnxt:
stosw ;Store it
add esi,[count] ;Add in the length of the run to the source
mov [inlen],0 ;Set the in leght flag to false
??nxt:
cmp esi,[end_of_data] ;See if we did the whole pic
jae short ??out ;If so, cool! were done
jmp ??loop
??out:
mov eax,080h ;Remember to send an end of data code
stosb ;Store it
mov eax,edi ;Get the last compressed address
sub eax,[a1stdest] ;Sub the first for the compressed size
ret
ENDP LCW_Compress
END

221
VQ/VQM32/LCWUNCMP.ASM Normal file
View File

@@ -0,0 +1,221 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* lcwuncmp.asm
;*
;* DESCRIPTION
;* LCW uncompress routine. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Chris Yates
;* Denzil E. Long, Jr.
;*
;* DATE
;* January 26, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* LCW_Uncompress - Uncompress LCW encoded data.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
CODESEG
;****************************************************************************
;*
;* NAME
;* LCW_Uncompress - Uncompress LCW encoded data.
;*
;* SYNOPSIS
;* Size = LCW_Uncompress(Source, Dest, Length)
;*
;* LONG LCW_Uncompress(void *, void *, long);
;*
;* FUNCTION
;* Uncompress data to the following codes in the format b = byte,
;* w = word, n = byte code pulled from compressed data.
;*
;* Bit field of n Command Description
;* ------------------------------------------------------------------
;* n=0xxxyyyy,yyyyyyyy short run back y bytes and run x+3
;* n=10xxxxxx,n1,n2,..,nx+1 med length copy the next x+1 bytes
;* n=11xxxxxx,w1 med run run x+3 bytes from offset w1
;* n=11111111,w1,w2 long copy copy w1 bytes from offset w2
;* n=11111110,w1,b1 long run run byte b1 for w1 bytes
;* n=10000000 end end of data reached
;*
;* INPUTS
;* Source - Pointer to LCW encoded data.
;* Dest - Pointer to buffer to uncompress into.
;* Length -
;*
;* RESULT
;* Size - Size of uncompressed data in bytes.
;*
;****************************************************************************
GLOBAL C LCW_Uncompress:NEAR
PROC LCW_Uncompress C NEAR USES ebx ecx edx esi edi
ARG source:DWORD
ARG dest:DWORD
ARG length:DWORD
LOCAL a1stdest:DWORD
LOCAL maxlen:DWORD
LOCAL lastbyte:DWORD
LOCAL lastcom:DWORD
LOCAL lastcom1:DWORD
mov esi,[source] ;ESI - Source address
mov edi,[dest] ;EDI - Destination address
mov edx,[length] ;EDX - Maximum length
mov [a1stdest],edi ;Save dest address
add edx,edi ;Last address (Dest + length)
mov [lastbyte],edx
cld ;Forward direction
mov ebx,esi ;Save source address
??loop:
; Exit if no bytes are remaining.
mov eax,[lastbyte]
sub eax,edi
jz short ??out
mov [maxlen],eax ;Save for string commands
mov esi,ebx ;Restore source address
lodsb
or al,al ;See if its a short run
js short ??notshort
mov ah,al ;Put rel offset high nibble in ah
and ah,0Fh ; Only 4 bits count
sub ecx,ecx
mov ch,al ;Put count nibble in ch
shr ch,4
mov cl,ch
xor ch,ch
add ecx,3 ;Get actual run length
cmp ecx,[maxlen] ;Is it too big to fit?
jbe short ??rsok ;If not, its ok
mov ecx,[maxlen] ;If so, max it out so it dosen't overrun
??rsok:
lodsb ;Get rel offset low byte
mov ebx,esi ;Save the source address
mov esi,edi ;Get the current dest
sub esi,eax ;Get relative offset
rep movsb
jmp ??loop
??notshort:
test al,40h ;Is it a length?
jne short ??notlength ;If not it could be med or long run
; If end code then exit.
cmp al,80h
je short ??out
mov cl,al ;Put the byte in count register
and ecx,3Fh ;Mask off the extra bits
cmp ecx,[maxlen] ;Is it too big to fit?
jbe short ??lenok ;If not, its ok
mov ecx,[maxlen] ;If so, max it out so it dosen't overrun
??lenok:
rep movsb
mov ebx,esi ;Save the source offset
jmp ??loop
??out:
mov eax,edi
sub eax,[a1stdest]
jmp short ??exit
??notlength:
mov cl,al ;Get the entire code
and ecx,3Fh ;Mask off all but the size -3
add ecx,3 ;Add 3 for byte count
cmp al,0FEh
jne short ??notrunlength
sub eax,eax
lodsw
mov ecx,eax
sub eax,eax
lodsb
mov ebx,esi ;Save the source offset
cmp ecx,[maxlen] ;Is it too big to fit?
jbe short ??runlenok ;If not, its ok
mov ecx,[maxlen] ;If so, max it out so it dosen't overrun
??runlenok:
rep stosb
jmp ??loop
??notrunlength:
cmp al,0FFh ;Is it a long run?
jne short ??notlong ;If not use the code as the size
sub eax,eax
lodsw ;If so, get the size
mov ecx,eax ;Put int the count byte
??notlong:
lodsw ;Get the rel index
mov ebx,esi ;Save the source offset
add eax,[a1stdest] ;Add in the first index
mov esi,eax ;Use this as a source
cmp ecx,[maxlen] ;Is it too big to fit?
jbe short ??runok ;If not, its ok
mov ecx,[maxlen] ;If so, max it out so it dosen't overrun
??runok:
rep movsb
jmp ??loop
??exit:
mov eax,edi
mov ebx,[dest]
sub eax,ebx ;Calculate bytes uncompressed.
ret
ENDP LCW_Uncompress
END

183
VQ/VQM32/MAKEFILE Normal file
View File

@@ -0,0 +1,183 @@
#
# 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/>.
#
#****************************************************************************
#
# C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
#
#----------------------------------------------------------------------------
#
# PROJECT
# VQMisc 32-bit library. (Watcom/4GW)
#
# FILE
# makefile
#
# DESCRIPTION
# Makefile for generating VQMisc32 library.
#
# PROGRAMMER
# Denzil E. Long, Jr.
#
# DATE
# Feburary 10, 1995
#
# ENVIROMENT
# PRJ - Projects path.
# PRJVCS - Version control archive path.
# WATCOM - Watcom C installation path.
#
#****************************************************************************
.OPTIMIZE
.ERASE
#----------------------------------------------------------------------------
# VERIFY ENVIROMENT
#----------------------------------------------------------------------------
!ifndef %PRJ || %PRJVCS || %WATCOM
!error Environment not configured.
!endif
#----------------------------------------------------------------------------
# PROJECTS DEPENDENT MACROS
#----------------------------------------------------------------------------
PRJNAME = vqm32wp
PRJDIR = $(%PRJ)\VQM32
OBJECTS = &
iff.obj &
profile.obj &
audzap.obj &
audunzap.obj &
targa.obj &
vertag.obj &
sortpal.obj &
palette.obj &
mono.obj &
lcwuncmp.obj &
lcwcomp.obj &
testvb.obj &
vb.obj &
mcgabuf.obj &
video.obj &
xmode.obj &
xmodepg.obj &
vesabuf.obj &
vesablit.obj &
vesavid.obj &
soscodec.obj &
drawchar.obj &
textprnt.obj &
font.obj &
chrwidth.obj &
mixfile.obj &
crc.obj &
fillrect.obj &
captoken.obj &
huffcmp.obj &
huffdcmp.obj &
mem.obj &
#----------------------------------------------------------------------------
# PATH MACROS
#----------------------------------------------------------------------------
!ifdef %LIB
LIBPATH = $(%PRJ)\LIB;$(%LIB)
!else
LIBPATH = $(%PRJ)\LIB;$(%WATCOM)\LIB386
!endif
!ifdef %INCLUDE
INCLUDEPATH = $(%PRJ)\INCLUDE;$(%INCLUDE)
!else
INCLUDEPATH = $(%PRJ)\INCLUDE;$(%WATCOM)\H
!endif
path_c = .\
path_cpp = .\
path_h = .\
path_asm = .\
path_i = .\
path_obj = .\O
path_lib = $(%PRJ)\LIB
path_exe = .\
#----------------------------------------------------------------------------
# IMPLICIT RULE EXTENSIONS AND PATHS
#----------------------------------------------------------------------------
.EXTENSIONS :
.EXTENSIONS : .exe .lib .obj .c .cpp .asm .h .i
.c : $(path_c)
.cpp : $(path_cpp)
.h : $(path_h)
.asm : $(path_asm)
.i : $(path_i)
.obj : $(path_obj)
.lib : $(path_lib)
.exe : $(path_exe)
#----------------------------------------------------------------------------
# TOOLS, COMMANDS AND CONFIGURATIONS
#----------------------------------------------------------------------------
CC_CMD = wcc386
CCP_CMD = wpp386
ASM_CMD = tasm32
LINK_CMD = wlink
LIB_CMD = wlib
CC_OPTS = -i$(INCLUDEPATH) -j -zp1 -5s -mf -oaeilrt -s -zq
ASM_OPTS = /t /m /w+ /jJUMPS /ml /p /z /dPHARLAP_TNT=0
LIB_OPTS = /b /c /q
LINK_CFG = $(PRJNAME).lnk
#----------------------------------------------------------------------------
# DEFAULT TARGET
#----------------------------------------------------------------------------
all : $(PRJNAME).lib .SYMBOLIC
$(PRJNAME).lib : $(OBJECTS) .SYMBOLIC
#----------------------------------------------------------------------------
# IMPLICIT RULES
#----------------------------------------------------------------------------
.c.obj :
$(CC_CMD) $(CC_OPTS) -fo=$(PATH_OBJ)\$^. $<
$(LIB_CMD) $(LIB_OPTS) $(path_lib)\$(PRJNAME).lib -+$(path_obj)\$]&
.cpp.obj :
$(CCP_CMD) $(CC_OPTS) -fo=$(PATH_OBJ)\$^. $<
$(LIB_CMD) $(LIB_OPTS) $(path_lib)\$(PRJNAME).lib -+$(path_obj)\$]&
.asm.obj:
$(ASM_CMD) $(ASM_OPTS) $<,$(path_obj)\$^.
$(LIB_CMD) $(LIB_OPTS) $(path_lib)\$(PRJNAME).lib -+$(path_obj)\$]&
update: .SYMBOLIC
@echo Updating VQMisc32 header files!
@copy *.h $(%PRJ)\INCLUDE\VQM32 >NUL
@copy *.i $(%PRJ)\INCLUDE\VQM32 >NUL

174
VQ/VQM32/MAKEFILE.BAK Normal file
View File

@@ -0,0 +1,174 @@
#
# 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/>.
#
#****************************************************************************
#
# C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
#
#----------------------------------------------------------------------------
#
# PROJECT
# VQMisc 32-bit library. (Watcom/4GW)
#
# FILE
# makefile
#
# DESCRIPTION
# Makefile for generating VQMisc32 library.
#
# PROGRAMMER
# Denzil E. Long, Jr.
#
# DATE
# Feburary 10, 1995
#
# ENVIROMENT
# PRJ - Projects path.
# PRJVCS - Version control archive path.
# WATCOM - Watcom C installation path.
#
#****************************************************************************
.OPTIMIZE
.ERASE
#----------------------------------------------------------------------------
# VERIFY ENVIROMENT
#----------------------------------------------------------------------------
PRJ=.
!ifndef PRJ || %WATCOM
!error Environment not configured.
!endif
#----------------------------------------------------------------------------
# PROJECTS DEPENDENT MACROS
#----------------------------------------------------------------------------
PRJNAME = VQM32W
PRJDIR = $(PRJ)\VQM32
OBJECTS = &
iff.obj &
profile.obj &
audzap.obj &
audunzap.obj &
targa.obj &
vertag.obj &
sortpal.obj &
palette.obj &
lcwuncmp.obj &
lcwcomp.obj &
testvb.obj &
vb.obj &
mcgabuf.obj &
video.obj &
xmode.obj &
xmodepg.obj &
vesabuf.obj &
vesablit.obj &
vesavid.obj &
soscodec.obj
# mono.obj &
#----------------------------------------------------------------------------
# PATH MACROS
#----------------------------------------------------------------------------
!ifdef %LIB
LIBPATH = $(PRJ)\LIB;$(%LIB)
!else
LIBPATH = $(PRJ)\LIB;$(%WATCOM)\LIB386
!endif
!ifdef %INCLUDE
INCLUDEPATH = $(PRJ)\INCLUDE;$(%INCLUDE)
!else
INCLUDEPATH = $(PRJ)\INCLUDE;$(%WATCOM)\H
!endif
path_c = .\
path_cpp = .\
path_h = .\
path_asm = .\
path_i = .\
path_obj = .\O
path_lib = $(PRJ)\LIB
path_exe = .\
#----------------------------------------------------------------------------
# IMPLICIT RULE EXTENSIONS AND PATHS
#----------------------------------------------------------------------------
.EXTENSIONS :
.EXTENSIONS : .exe .lib .obj .c .cpp .asm .h .i
.c : $(path_c)
.cpp : $(path_cpp)
.h : $(path_h)
.asm : $(path_asm)
.i : $(path_i)
.obj : $(path_obj)
.lib : $(path_lib)
.exe : $(path_exe)
#----------------------------------------------------------------------------
# TOOLS, COMMANDS AND CONFIGURATIONS
#----------------------------------------------------------------------------
CC_CMD = wcc386
CCP_CMD = wpp386
ASM_CMD = tasm32
LINK_CMD = wlink
LIB_CMD = wlib
CC_OPTS = -i$(INCLUDEPATH) -j -zp1 -5s -mf -oaeilrt -s -zq
ASM_OPTS = /t /m /w+ /jJUMPS /ml /p /z /dPHARLAP_TNT=0
LIB_OPTS = /b /c /q
LINK_CFG = $(PRJNAME).lnk
#----------------------------------------------------------------------------
# DEFAULT TARGET
#----------------------------------------------------------------------------
all : $(PRJNAME).lib .SYMBOLIC
$(PRJNAME).lib : $(OBJECTS) .SYMBOLIC
#----------------------------------------------------------------------------
# IMPLICIT RULES
#----------------------------------------------------------------------------
.c.obj :
$(CC_CMD) $(CC_OPTS) -fo=$(PATH_OBJ)\$^. $<
$(LIB_CMD) $(LIB_OPTS) $(path_lib)\$(PRJNAME).lib -+$(path_obj)\$]&
.cpp.obj :
$(CCP_CMD) $(CC_OPTS) -fo=$(PATH_OBJ)\$^. $<
$(LIB_CMD) $(LIB_OPTS) $(path_lib)\$(PRJNAME).lib -+$(path_obj)\$]&
.asm.obj:
$(ASM_CMD) $(ASM_OPTS) $<,$(path_obj)\$^.
$(LIB_CMD) $(LIB_OPTS) $(path_lib)\$(PRJNAME).lib -+$(path_obj)\$]&
update: .SYMBOLIC
@echo Updating VQMisc32 header files!
@copy *.h $(PRJ)\INCLUDE\VQM32 >NUL
@copy *.i $(PRJ)\INCLUDE\VQM32 >NUL

234
VQ/VQM32/MAKEFILE.BOR Normal file
View File

@@ -0,0 +1,234 @@
#
# 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/>.
#
#****************************************************************************
#
# C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
#
#----------------------------------------------------------------------------
#
# PROJECT
# VQMisc32 library. (Borland/TNT)
#
# FILE
# makefile
#
# DESCRIPTION
# Makefile for generating VQMisc32 library.
#
# PROGRAMMER
# Denzil E. Long, Jr.
#
# DATE
# Febuary 7, 1995
#
# ENVIROMENT
# PRJ - Projects path.
# PRJVCS - Version control archive path.
# BCDIR - Borland C installation path.
# TNTDIR - Pharlap/TNT installation path.
#
#****************************************************************************
.AUTODEPEND
#----------------------------------------------------------------------------
# VERIFY ENVIROMENT
#----------------------------------------------------------------------------
!if !$d(PRJ) || !$d(PRJVCS) || !$d(BCDIR) || !$d(TNTDIR)
!error Environment not configured.
!endif
#----------------------------------------------------------------------------
# PROJECT DEPENDENT MACROS
#----------------------------------------------------------------------------
PRJNAME = VQM32BP
PRJDIR = $(PRJ)\VQM32
OBJECTS = \
iff.obj \
profile.obj \
audzap.obj \
audunzap.obj \
targa.obj \
vertag.obj \
sortpal.obj \
palette.obj \
mono.obj \
lcwuncmp.obj \
lcwcomp.obj \
testvb.obj \
vb.obj \
mcgabuf.obj \
video.obj \
xmode.obj \
xmodepg.obj \
vesabuf.obj \
vesablit.obj \
vesavid.obj \
soscodec.obj \
drawchar.obj \
textprnt.obj \
font.obj \
chrwidth.obj \
mixfile.obj \
crc.obj \
fillrect.obj \
captoken.obj \
huffcmp.obj \
huffdcmp.obj \
mem.obj \
portio.obj \
#----------------------------------------------------------------------------
# PATH MACROS
#----------------------------------------------------------------------------
!if $d(LIB)
LIBPATH = $(PRJ)\LIB;$(LIB)
!else
LIBPATH = $(PRJ)\LIB;$(TNTDIR)\LIB;$(BCDIR)\LIB
!endif
!if $d(INCLUDE)
INCLUDEPATH = $(PRJ)\INCLUDE;$(INCLUDE)
!else
INCLUDEPATH = $(PRJ)\INCLUDE;$(TNTDIR)\INCLUDE;$(BCDIR)\INCLUDE
!endif
.path.asm = $(PRJDIR)
.path.c = $(PRJDIR)
.path.cpp = $(PRJDIR)
.path.h = $(PRJDIR)
.path.exe = $(PRJDIR)
.path.obj = $(PRJDIR)\OBJ
.path.sym = $(PRJDIR)\OBJ
.path.lib = $(PRJ)\LIB
#----------------------------------------------------------------------------
# TOOLS, COMMANDS AND CONFIGURATIONS
#----------------------------------------------------------------------------
CC_CMD = bcc32
ASM_CMD = tasm32
LINK_CMD = tlink32
LIB_CMD = tlib
CC_CFG = bcc32.cfg
ASM_CFG = tasm32.cfg
LINK_CFG = tlink32.cfg
LIB_CFG = tlib.cfg
CFG_FILES = $(CC_CFG) $(ASM_CFG) $(LINK_CFG) $(LIB_CFG)
#----------------------------------------------------------------------------
# DEFAULT TARGET
#----------------------------------------------------------------------------
all: $(PRJNAME).lib
#----------------------------------------------------------------------------
# IMPLICIT RULES
#----------------------------------------------------------------------------
.c.obj:
$(CC_CMD) -P- -n$(.path.obj) {$< }
.cpp.obj:
$(CC_CMD) -P -n$(.path.obj) {$< }
.asm.obj:
$(ASM_CMD) @$(ASM_CFG) $<,$(.path.obj)\$&
#----------------------------------------------------------------------------
# BUILD THE LIBRARY
#----------------------------------------------------------------------------
$(PRJNAME).lib: $(OBJECTS)
- @del $(.path.lib)\$(PRJNAME).lib >&NUL
$(LIB_CMD) $(.path.lib)\$(PRJNAME).lib @$(LIB_CFG) @&&|
-+$(**: = -+)
|
- @copy *.h $(PRJ)\INCLUDE\VQM32 >&NUL
- @copy *.i $(PRJ)\INCLUDE\VQM32 >&NUL
#----------------------------------------------------------------------------
# ALL OBJECTS DEPEND ON THE CONFIGURATION FILES
#----------------------------------------------------------------------------
$(OBJECTS): $(CFG_FILES)
#----------------------------------------------------------------------------
# COMPILER CONFIGURATION
#----------------------------------------------------------------------------
$(CC_CFG): makefile
copy &&|
-c
-3
-d
-H=$(.path.sym)\headers.sym
-wpro
-weas
-wpre
-I$(INCLUDEPATH)
-DPHARLAP_TNT=1
#-v
| $(CC_CFG)
#----------------------------------------------------------------------------
# ASSEMBLER CONFIGURATION
#----------------------------------------------------------------------------
$(ASM_CFG): makefile
copy &&|
/t
/m
/w+
/jJUMPS
/ml
/p
/z
/i$(PRJ)\INCLUDE
/zi
/dPHARLAP_TNT=1
| $(ASM_CFG)
#----------------------------------------------------------------------------
# LINKER CONFIGURATION
#----------------------------------------------------------------------------
$(LINK_CFG): makefile
copy &&|
/c
/m
/Gm
-L$(LIBPATH)
-v
| $(LINK_CFG)
#----------------------------------------------------------------------------
# LIBRARIAN CONFIGURATION
#----------------------------------------------------------------------------
$(LIB_CFG): makefile
copy &&|
/C /E
| $(LIB_CFG)

183
VQ/VQM32/MAKEFILE.WAT Normal file
View File

@@ -0,0 +1,183 @@
#
# 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/>.
#
#****************************************************************************
#
# C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
#
#----------------------------------------------------------------------------
#
# PROJECT
# VQMisc 32-bit library. (Watcom/4GW)
#
# FILE
# makefile
#
# DESCRIPTION
# Makefile for generating VQMisc32 library.
#
# PROGRAMMER
# Denzil E. Long, Jr.
#
# DATE
# Feburary 10, 1995
#
# ENVIROMENT
# PRJ - Projects path.
# PRJVCS - Version control archive path.
# WATCOM - Watcom C installation path.
#
#****************************************************************************
.OPTIMIZE
.ERASE
#----------------------------------------------------------------------------
# VERIFY ENVIROMENT
#----------------------------------------------------------------------------
!ifndef %PRJ || %PRJVCS || %WATCOM
!error Environment not configured.
!endif
#----------------------------------------------------------------------------
# PROJECTS DEPENDENT MACROS
#----------------------------------------------------------------------------
PRJNAME = vqm32wp
PRJDIR = $(%PRJ)\VQM32
OBJECTS = &
iff.obj &
profile.obj &
audzap.obj &
audunzap.obj &
targa.obj &
vertag.obj &
sortpal.obj &
palette.obj &
mono.obj &
lcwuncmp.obj &
lcwcomp.obj &
testvb.obj &
vb.obj &
mcgabuf.obj &
video.obj &
xmode.obj &
xmodepg.obj &
vesabuf.obj &
vesablit.obj &
vesavid.obj &
soscodec.obj &
drawchar.obj &
textprnt.obj &
font.obj &
chrwidth.obj &
mixfile.obj &
crc.obj &
fillrect.obj &
captoken.obj &
huffcmp.obj &
huffdcmp.obj &
mem.obj &
#----------------------------------------------------------------------------
# PATH MACROS
#----------------------------------------------------------------------------
!ifdef %LIB
LIBPATH = $(%PRJ)\LIB;$(%LIB)
!else
LIBPATH = $(%PRJ)\LIB;$(%WATCOM)\LIB386
!endif
!ifdef %INCLUDE
INCLUDEPATH = $(%PRJ)\INCLUDE;$(%INCLUDE)
!else
INCLUDEPATH = $(%PRJ)\INCLUDE;$(%WATCOM)\H
!endif
path_c = .\
path_cpp = .\
path_h = .\
path_asm = .\
path_i = .\
path_obj = .\O
path_lib = $(%PRJ)\LIB
path_exe = .\
#----------------------------------------------------------------------------
# IMPLICIT RULE EXTENSIONS AND PATHS
#----------------------------------------------------------------------------
.EXTENSIONS :
.EXTENSIONS : .exe .lib .obj .c .cpp .asm .h .i
.c : $(path_c)
.cpp : $(path_cpp)
.h : $(path_h)
.asm : $(path_asm)
.i : $(path_i)
.obj : $(path_obj)
.lib : $(path_lib)
.exe : $(path_exe)
#----------------------------------------------------------------------------
# TOOLS, COMMANDS AND CONFIGURATIONS
#----------------------------------------------------------------------------
CC_CMD = wcc386
CCP_CMD = wpp386
ASM_CMD = tasm32
LINK_CMD = wlink
LIB_CMD = wlib
CC_OPTS = -i$(INCLUDEPATH) -j -zp1 -5s -mf -oaeilrt -s -zq
ASM_OPTS = /t /m /w+ /jJUMPS /ml /p /z /dPHARLAP_TNT=0
LIB_OPTS = /b /c /q
LINK_CFG = $(PRJNAME).lnk
#----------------------------------------------------------------------------
# DEFAULT TARGET
#----------------------------------------------------------------------------
all : $(PRJNAME).lib .SYMBOLIC
$(PRJNAME).lib : $(OBJECTS) .SYMBOLIC
#----------------------------------------------------------------------------
# IMPLICIT RULES
#----------------------------------------------------------------------------
.c.obj :
$(CC_CMD) $(CC_OPTS) -fo=$(PATH_OBJ)\$^. $<
$(LIB_CMD) $(LIB_OPTS) $(path_lib)\$(PRJNAME).lib -+$(path_obj)\$]&
.cpp.obj :
$(CCP_CMD) $(CC_OPTS) -fo=$(PATH_OBJ)\$^. $<
$(LIB_CMD) $(LIB_OPTS) $(path_lib)\$(PRJNAME).lib -+$(path_obj)\$]&
.asm.obj:
$(ASM_CMD) $(ASM_OPTS) $<,$(path_obj)\$^.
$(LIB_CMD) $(LIB_OPTS) $(path_lib)\$(PRJNAME).lib -+$(path_obj)\$]&
update: .SYMBOLIC
@echo Updating VQMisc32 header files!
@copy *.h $(%PRJ)\INCLUDE\VQM32 >NUL
@copy *.i $(%PRJ)\INCLUDE\VQM32 >NUL

196
VQ/VQM32/MCGABUF.ASM Normal file
View File

@@ -0,0 +1,196 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* mcgabuf.asm
;*
;* DESCRIPTION
;* MCGA display routines. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Bill Randolph
;* Denzil E. Long, Jr.
;*
;* DATE
;* Febuary 3, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* ClearVRAM - Clear all VRAM.
;* MCGA_BufferCopy - Copy 320x200 buffer to MCGA VRAM
;* MCGA_Blit - Bit blit a block to the MCGA screen.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
INCLUDE "vga.i"
CODESEG
;****************************************************************************
;*
;* NAME
;* ClearVRAM - Clear all VRAM.
;*
;* SYNOPSIS
;* ClearVRAM()
;*
;* void ClearVRAM(void);
;*
;* FUNCTION
;*
;* INPUTS
;* NONE
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C ClearVRAM:NEAR
PROC ClearVRAM C NEAR USES eax ecx edi es
IF PHARLAP_TNT
mov eax,01Ch ;Set ES selector to video memory
mov es,ax
mov edi,0
ELSE
mov edi,0A0000h
ENDIF
SET_PLANE 0Fh ;Enable all planes for writing
cld
mov ecx,16000 ;Clear 320x200
xor eax,eax
rep stosd
ret
ENDP ClearVRAM
;****************************************************************************
;*
;* NAME
;* MCGA_BufferCopy - Copy 320x200 buffer to MCGA VRAM
;*
;* SYNOPSIS
;* MCGA_BufferCopy(Buffer, Dummy)
;*
;* void MCGA_BufferCopy(char *, char *);
;*
;* FUNCTION
;*
;* INPUTS
;* Buffer - Pointer to buffer to transfer.
;* Dummy - Prototype placeholder.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C MCGA_BufferCopy:NEAR
PROC MCGA_BufferCopy C NEAR USES ecx esi edi es
ARG buffer:NEAR PTR
ARG dummy:NEAR PTR
IF PHARLAP_TNT
mov eax,01Ch
mov es,ax
mov edi,0
ELSE
mov edi,0A0000h
ENDIF
mov esi, [buffer]
mov ecx,16000
rep movsd ;Transfer the data
ret
ENDP MCGA_BufferCopy
;****************************************************************************
;*
;* NAME
;* MCGA_Blit - Bit blit a block to the MCGA screen.
;*
;* SYNOPSIS
;* MCGA_Blit(Buffer, Screen, Width, Height)
;*
;* void MCGA_Blit(char *, char *, long, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Buffer - Pointer to buffer to copy.
;* Screen - Screen address to copy buffer to.
;* Width - Width of block.
;* Height - Height of block.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C MCGA_Blit:NEAR
PROC MCGA_Blit C NEAR USES ecx edx esi edi
ARG buffer:NEAR PTR
ARG screen:NEAR PTR
ARG imgwidth:DWORD
ARG imgheight:DWORD
IF PHARLAP_TNT
push es
mov eax,1Ch ;Set ES selector to VRAM
mov es,ax
ENDIF
mov esi,[buffer]
mov edi,[screen]
mov edx,320
sub edx,[imgwidth] ;Compute modulo
??Do_row:
mov ecx,[imgwidth]
rep movsb
add edi,edx
dec [imgheight]
jnz ??Do_row
IF PHARLAP_TNT
pop es
ENDIF
ret
ENDP MCGA_Blit
END

134
VQ/VQM32/MEM.CPP Normal file
View File

@@ -0,0 +1,134 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*---------------------------------------------------------------------------
*
* FILE
* mem.c
*
* DESCRIPTION
* Memory management.
*
* PROGRAMMER
* Phil Gorrow
* Denzil E. Long, Jr.
*
* DATE
* July 5, 1995
*
*---------------------------------------------------------------------------
*
* PUBLIC
* DPMI_Lock - Lock a memory page.
* DPMI_Unlock - Unlock a locked memory page.
*
****************************************************************************/
#ifdef __WATCOMC__
#include <dos.h>
#include <mem.h>
#include <vqm32\mem.h>
/****************************************************************************
*
* NAME
* DPMI_Lock - Lock a memory page.
*
* SYNOPSIS
* DPMI_Lock(Address, Size)
*
* void DPMI_Lock(void *, long);
*
* FUNCTION
*
* INPUTS
* Address - Starting linear address of memory to lock.
* Size - Size of region to lock in bytes.
*
* RESULT
* NONE
*
****************************************************************************/
void DPMI_Lock(void const *ptr, long const size)
{
union REGS regs;
struct SREGS sregs;
memset(&regs, 0, sizeof(REGS));
segread(&sregs);
/* Lock the memory page.
*
* AX = 0x600
* BX:CX = Starting linear address of memory to lock.
* SI:DI = Size of region to lock in bytes.
*/
regs.x.eax = DPMI_LOCK;
regs.x.ebx = ((long)ptr & 0xFFFF0000) >> 16;
regs.x.ecx = ((long)ptr & 0x0000FFFF);
regs.x.esi = ((long)size & 0xFFFF0000) >> 16;
regs.x.edi = ((long)size & 0x0000FFFF);
int386x(DPMI_INT, &regs, &regs, &sregs);
}
/****************************************************************************
*
* NAME
* DPMI_Unlock - Unlock a locked memory page.
*
* SYNOPSIS
* DPMI_Unlock(Address, Size)
*
* void DPMI_Unlock(void *, long);
*
* FUNCTION
*
* INPUTS
* Address - Starting linear address of memory to unlock.
* Size - Size of region to unlock in bytes.
*
* RESULT
* NONE
*
****************************************************************************/
void DPMI_Unlock(void const *ptr, long const size)
{
union REGS regs;
struct SREGS sregs;
/* Unlock memory page. */
memset(&regs, 0 ,sizeof(REGS));
segread(&sregs);
regs.x.eax = DPMI_UNLOCK;
regs.x.ebx = ((long)ptr & 0xFFFF0000) >> 16;
regs.x.ecx = ((long)ptr & 0x0000FFFF);
regs.x.esi = ((long)size & 0xFFFF0000) >> 16;
regs.x.edi = ((long)size & 0x0000FFFF);
int386x(DPMI_INT, &regs, &regs, &sregs);
}
#endif /* __WATCOMC__ */

56
VQ/VQM32/MEM.H Normal file
View File

@@ -0,0 +1,56 @@
/*
** 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/>.
*/
#ifndef VQAMEM_H
#define VQAMEM_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*---------------------------------------------------------------------------
*
* FILE
* mem.h
*
* DESCRIPTION
* Memory management definitions.
*
* PROGRAMMER
* Phil Gorrow
* Denzil E. Long, Jr.
*
* DATE
* July 5, 1995
*
****************************************************************************/
/* Definitions */
#define DPMI_INT 0x0031
#define DPMI_LOCK 0x0600
#define DPMI_UNLOCK 0x0601
/* Prototypes */
#ifdef __WATCOMC__
void DPMI_Lock(void const *ptr, long const size);
void DPMI_Unlock(void const *ptr, long const size);
#else
#define DPMI_Lock(a,b)
#define DPMI_Unlock(a,b)
#endif
#endif /* VQAMEM_H */

250
VQ/VQM32/MIXFILE.CPP Normal file
View File

@@ -0,0 +1,250 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* mixfile.c
*
* DESCRIPTION
* A mix file is basically a group of files concatinated together
* proceeded by a header describing where in the file each individual
* entry is located. These routines are provided to simplify the access
* to these file entries.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* January 26, 1995
*
*----------------------------------------------------------------------------
*
* MixFile format:
*
* HEADER
* (2 bytes) Count - The number of entries in this file.
* (4 bytes) Size - Size of the mix file in bytes.
*
* SUBBLOCKS (There are "Count" number of these.)
* (4 bytes) CRC - Entry descriptor (CRC of filename).
* (4 bytes) Offset - Offset in bytes from beginning of the DATA chunk.
* (4 bytes) Size - Size of entry.
*
* DATA
* Entry data.
*
*----------------------------------------------------------------------------
*
* PUBLIC
* OpenMix - Open mix file for access.
* CloseMix - Close a mix file.
* OpenMixEntry - Open a mix file entry.
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <io.h>
#include <mem.h>
#include <string.h>
#include "mixfile.h"
#include "crc.h"
/*---------------------------------------------------------------------------
* PRIVATE DECLARATIONS
*-------------------------------------------------------------------------*/
int compfunc(void const *ptr1, void const *ptr2);
/****************************************************************************
*
* NAME
* OpenMix - Open mix file for access.
*
* SYNOPSIS
* MixHandle = OpenMix(Name)
*
* MixHandle *OpenMix(char *);
*
* FUNCTION
* Open a mix file for access.
*
* INPUTS
* Name - Pointer to name of mix file to open.
*
* RESULT
* MixHandle - Pointer to handle for mix file.
*
****************************************************************************/
MIXHandle *OpenMix(char *name)
{
MIXHeader mfhdr;
MIXHandle *mix = NULL;
long fh;
long sbsize;
long size;
/* Open mix file and read in header. */
if ((fh = open(name, (O_RDONLY|O_BINARY))) != -1) {
if (read(fh, &mfhdr, sizeof(MIXHeader)) == sizeof(MIXHeader)) {
/* Allocate handle based on the number of SubBlocks. */
sbsize = (mfhdr.Count * sizeof(MIXSubBlock));
size = sbsize + sizeof(MIXHandle);
if ((mix = (MIXHandle *)malloc(size)) != NULL) {
memset(mix, 0, size);
mix->Name = name;
mix->Size = mfhdr.Size;
mix->Count = mfhdr.Count;
/* Read in the SubBlock entries. */
if (read(fh, &mix->Entries[0], sbsize) != sbsize) {
free(mix);
mix = NULL;
}
}
}
close(fh);
}
return (mix);
}
/****************************************************************************
*
* NAME
* CloseMix - Close a mix file.
*
* SYNOPSIS
* CloseMix(MixHandle)
*
* void CloseMix(MixHandle *);
*
* FUNCTION
* Close a mix file by freeing its handle.
*
* INPUTS
* MixHandle - Pointer to MixHandle returned by OpenMix().
*
* RESULT
* NONE
*
****************************************************************************/
void CloseMix(MIXHandle *mix)
{
free(mix);
}
/****************************************************************************
*
* NAME
* OpenMixEntry - Open a mix file entry.
*
* SYNOPSIS
* FH = OpenMixEntry(MixHandle, EntryName)
*
* short OpenMixEntry(MIXHandle *, char *);
*
* FUNCTION
* Opens an entry from the specified mix file handle. Use close() to close
* the file when done.
*
* INPUTS
* MixHandle - Pointer to MIXHandle containing entry to open.
* EntryName - Pointer to name of mix file entry to open.
*
* RESULT
* FH - DOS filehandle, -1 if unable to open.
*
****************************************************************************/
long OpenMixEntry(MIXHandle *mix, char *name)
{
MIXSubBlock key;
MIXSubBlock *block;
long fh;
/* Search for the specified file in the mix file. */
key.CRC = Calculate_CRC(name, strlen(name));
block = (MIXSubBlock *)bsearch(&key, &mix->Entries[0], mix->Count,
sizeof(MIXSubBlock), compfunc);
/* If the block exists for the requested filename. */
if (block != NULL) {
/* Initialize the key for file access. */
key.Offset = block->Offset;
key.Offset += (mix->Count * sizeof(MIXSubBlock)) + sizeof(MIXHeader);
/* Open the mix file. */
if ((fh = open(mix->Name, (O_RDONLY|O_BINARY))) != -1) {
/* Seek to the start of the file. */
if (lseek(fh, key.Offset, SEEK_SET) == -1) {
close(fh);
fh = -1;
}
}
}
return (fh);
}
/****************************************************************************
*
* NAME
* compfunc - Compare function for bsearch().
*
* SYNOPSIS
* Result = compfunc(Entry1, Entry2);
*
* int compfunc(void const *, void const *);
*
* FUNCTION
*
* INPUTS
* Entry1 - Pointer to first entry to compare.
* Entry2 - Pointer to second entry to compare.
*
* RESULT
* Result -
*
****************************************************************************/
int compfunc(void const *ptr1, void const *ptr2)
{
if (((MIXSubBlock *)ptr1)->CRC < ((MIXSubBlock *)ptr2)->CRC) return -1;
if (((MIXSubBlock *)ptr1)->CRC > ((MIXSubBlock *)ptr2)->CRC) return 1;
return(0);
}

105
VQ/VQM32/MIXFILE.H Normal file
View File

@@ -0,0 +1,105 @@
/*
** 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/>.
*/
#ifndef VQMMIXFILE_H
#define VQMMIXFILE_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* mixfile.h
*
* DESCRIPTION
* A mix file is basically a group of files concatinated together
* proceeded by a header describing where in the file each individual
* entry is located. These definitions are provided to simplify the access
* to these file entries.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* January 26, 1995
*
****************************************************************************/
/* Disable structure alignment.*/
#ifdef __WATCOMC__
#pragma pack(1);
#endif
/*---------------------------------------------------------------------------
* STRUCTURE DEFINITIONS
*-------------------------------------------------------------------------*/
/* MIXHeader: Mix file data header.
*
* Count - Number of entries contained in this mix file.
* Size - Size of Mix file.
*/
typedef struct _MIXHeader {
short Count;
long Size;
} MIXHeader;
/* MIXSubBlock: Mix file entry descriptor.
*
* CRC - Unique entry identifier.
* Offset - Offset from beginning of data segment to entry.
* Size - Size of entry.
*/
typedef struct _MIXSubBlock {
long CRC;
long Offset;
long Size;
} MIXSubBlock;
/* MIXHandle: Mix file handle.
*
* Name - Pointer to the name of the mix file this handle is for.
* Size - Size of entire mix file.
* FH - DOS file handle of opened entry.
* Count - Number of files contained in this mix.
* Entries - Array of 'Count' MIXSubBlock structure entries.
*/
typedef struct _MIXHandle {
char *Name;
long Size;
long FH;
long Count;
MIXSubBlock Entries[];
} MIXHandle;
/*---------------------------------------------------------------------------
* PROTOTYPES
*-------------------------------------------------------------------------*/
MIXHandle *OpenMix(char *name);
void CloseMix(MIXHandle *mix);
long OpenMixEntry(MIXHandle *mix, char *name);
/* Restore original alignment */
#ifdef __WATCOMC__
#pragma pack();
#endif
#endif /* VQMMIXFILE_H */

871
VQ/VQM32/MONO.ASM Normal file
View File

@@ -0,0 +1,871 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* mono.asm
;*
;* DESCRIPTION
;* Mono screen print and output routines. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Denzil E. Long, Jr.
;*
;* DATE
;* Febuary 8, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* Mono_Enable - Enable mono output.
;* Mono_Disable - Disable mono output.
;* Mono_X - Get mono cursors X position.
;* Mono_Y - Get mono cursors Y position.
;* Mono_Set_Cursor - Set the mono cursor to specified coordinates.
;* Mono_Clear_Screen - Clear the mono screen.
;* Mono_Scroll - Scroll the mono screen up.
;* Mono_Put_Char - Ouput a character to the mono screen.
;* Mono_Draw_Rect - Draw a box on the mono screen.
;* Mono_Text_Print - Print a string to the mono screen at a specified
;* position.
;* Mono_Print - Print a string to the mono screen.
;* Mono_View_Page - View a mono page.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
DATASEG
MonoEnabled DD 1
MonoX DD 0
MonoY DD 0
MonoOff DD 0
CharData DB 0DAh,0C4h,0BFh,0B3h,0D9h,0C4h,0C0h,0B3h ; Single line
DB 0D5h,0CDh,0B8h,0B3h,0BEh,0CDh,0D4h,0B3h ; Double horz.
DB 0D6h,0C4h,0B7h,0BAh,0BDh,0C4h,0D3h,0BAh ; Double vert.
DB 0C9h,0CDh,0BBh,0BAh,0BCh,0CDh,0C8h,0BAh ; Double line.
; x,y,dist
BoxData DB 1,0,0 ; Upper left corner.
DB 1,0,1 ; Top edge.
DB 0,1,0 ; Upper right corner.
DB 0,1,2 ; Right edge.
DB -1,0,0 ; Bottom right corner.
DB -1,0,1 ; Bottom edge.
DB 0,-1,0 ; Bottom left corner.
DB 0,-1,2 ; Left edge.
DB 0,0,-1 ; End of list.
PageMap DD 0,1,2,3,4,5,6,7
CODESEG
;****************************************************************************
;*
;* NAME
;* Mono_Enable - Enable mono output.
;*
;* SYNOPSIS
;* Mono_Enable()
;*
;* void Mono_Enable(void);
;*
;* FUNCTION
;* Turn on the MonoEnabled flag.
;*
;* INPUTS
;* NONE
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Mono_Enable:NEAR
PROC Mono_Enable C NEAR
mov [MonoEnabled],1
ret
ENDP Mono_Enable
;****************************************************************************
;*
;* NAME
;* Mono_Disable - Disable mono output.
;*
;* SYNOPSIS
;* Mono_Disable()
;*
;* void Mono_Disable(void);
;*
;* FUNCTION
;* Turn off the MonoEnabled flag.
;*
;* INPUTS
;* NONE
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Mono_Disable:NEAR
PROC Mono_Disable C NEAR
mov [MonoEnabled],0
ret
ENDP Mono_Disable
;****************************************************************************
;*
;* NAME
;* Mono_X - Get mono cursors X position.
;*
;* SYNOPSIS
;* X = Mono_X()
;*
;* long Mono_X(void);
;*
;* FUNCTION
;* Return the X position of the mono screen cursor.
;*
;* INPUTS
;* NONE
;*
;* RESULT
;* X - X coordinate position.
;*
;****************************************************************************
GLOBAL C Mono_X:NEAR
PROC Mono_X C NEAR
mov eax,[MonoX]
ret
ENDP Mono_X
;****************************************************************************
;*
;* NAME
;* Mono_Y - Get mono cursors Y position.
;*
;* SYNOPSIS
;* Y = Mono_Y()
;*
;* long Mono_Y(void);
;*
;* FUNCTION
;* Return the Y position of the mono screen cursor.
;*
;* INPUTS
;* NONE
;*
;* RESULT
;* Y - Y coordinate position.
;*
;****************************************************************************
GLOBAL C Mono_Y:NEAR
PROC Mono_Y C NEAR
mov eax,[MonoY]
ret
ENDP Mono_Y
;****************************************************************************
;*
;* NAME
;* Mono_Set_Cursor - Set the mono cursor to specified coordinates.
;*
;* SYNOPSIS
;* Mono_Set_Cursor(X, Y)
;*
;* void Mono_Set_Cursor(long, long);
;*
;* FUNCTION
;*
;* INPUTS
;* X - X coordinate position.
;* Y - Y coordinate position.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Mono_Set_Cursor:NEAR
PROC Mono_Set_Cursor C NEAR USES eax ebx edx
ARG xpos:DWORD
ARG ypos:DWORD
cmp [MonoEnabled],0
je short ??fini
mov eax,[ypos]
mov ah,80
imul ah
add eax,[xpos]
mov ebx,eax
; Update cursor position.
mov dx,03B4h
mov al,0Eh ;High byte register set.
out dx,al
inc dx
mov al,bh
out dx,al ;Set high byte.
dec dx
mov al,0Fh ;Low byte register set.
out dx,al
inc dx
mov al,bl
out dx,al ;Set low byte.
; Update the globals.
add ebx,ebx
mov [MonoOff],ebx
mov eax,[xpos]
mov [MonoX],eax
mov eax,[ypos]
mov [MonoY],eax
??fini:
ret
ENDP Mono_Set_Cursor
;****************************************************************************
;*
;* NAME
;* Mono_Clear_Screen - Clear the mono screen.
;*
;* SYNOPSIS
;* Mono_Clear_Screen()
;*
;* void Mono_Clear_Screen(void);
;*
;* FUNCTION
;* Clear the mono screen and set the mono cursor to the upperleft corner
;* of the screen.
;*
;* INPUTS
;* NONE
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Mono_Clear_Screen:NEAR
PROC Mono_Clear_Screen C NEAR USES es eax ecx edi
; Exit if mono disabled
cmp [MonoEnabled],0
je short ??fini
; Clear the mono screen
IF PHARLAP_TNT
mov ax,034h
mov es,ax ;Set ES selector to first MB
ENDIF
mov edi,0B0000h ;EDI = Mono screen address
xor eax,eax ;Set char & attributes to 0
mov ecx,8000h/4 ;Number of longwords to clear
rep stosd ;Clear the mono screen.
call Mono_Set_Cursor C,eax,eax
??fini:
ret
ENDP Mono_Clear_Screen
;****************************************************************************
;*
;* NAME
;* Mono_Scroll - Scroll the mono screen up.
;*
;* SYNOPSIS
;* Mono_Scroll(Lines)
;*
;* void Mono_Scroll(long);
;*
;* FUNCTION
;* Move the contents of the mono screen up the specified number of lines
;* while clearing out the bottom lines.
;*
;* INPUTS
;* Lines - Number of lines to scroll the screen up.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Mono_Scroll:NEAR
PROC Mono_Scroll C NEAR USES es eax ebx ecx esi edi
ARG lines:DWORD
; Exit if mono disabled
cmp [MonoEnabled],0
je short ??fini
; Exit if lines to scroll is 0.
mov eax,[lines]
or eax,eax
je short ??fini
; Move the screen data up the specified lines
mov ebx,eax
??looper:
IF PHARLAP_TNT
mov ax,034h
mov es,ax ;Set ES selector to first MB
ENDIF
push ds ;Save DS selector
mov ds,ax ;Set DS selector to first MB
mov ecx,((80*24)/2) ;Number of DWORDs to move
mov esi,0B00A0h
mov edi,0B0000h
rep movsd
pop ds ;Restore DS selector
dec [MonoY]
sub [MonoOff],(80*2)
xor eax,eax
mov ecx,(80/2)
rep stosd
dec ebx
jne ??looper
??fini:
ret
ENDP Mono_Scroll
;****************************************************************************
;*
;* NAME
;* Mono_Put_Char - Ouput a character to the mono screen.
;*
;* SYNOPSIS
;* Mono_Put_Char(Character, Attributes)
;*
;* void Mono_Put_Char(long, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Character - ASCII character to output.
;* Attributes - Display attributes
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Mono_Put_Char:NEAR
PROC Mono_Put_Char C NEAR USES es eax edi
ARG character:DWORD
ARG attrib:DWORD
; Exit if mono disabled
cmp [MonoEnabled],0
je short ??fini
; Output character to the mono screen
cld
IF PHARLAP_TNT
mov ax,034h
mov es,ax ;Set ES selector to first MB
ENDIF
mov edi,0B0000h ;EDI = mono screen
add edi,[MonoOff] ;Add cursor offset
mov eax,[character]
mov ah,[BYTE PTR attrib]
stosw
; Update cursor position.
inc [MonoX] ; X position moves.
call Mono_Set_Cursor C,[MonoX],[MonoY]
??fini:
ret
ENDP Mono_Put_Char
;****************************************************************************
;*
;* NAME
;* Mono_Draw_Rect - Draw a box on the mono screen.
;*
;* SYNOPSIS
;* Mono_Draw_Rect(X, Y, Width, Height, Attributes, Thickness)
;*
;* void Mono_Draw_Rect();
;*
;* FUNCTION
;* Draw a rectangle text box on the mono screen.
;*
;* INPUTS
;* X - X coordinate position of upperleft corner.
;* Y - Y coordinate position of upperleft corner.
;* Width - Desired width.
;* Height - Desired height.
;* Attributes - Display attributes.
;* Thickness - Line thickness.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Mono_Draw_Rect:NEAR
PROC Mono_Draw_Rect C NEAR
ARG xpos:DWORD
ARG ypos:DWORD
ARG width:DWORD
ARG height:DWORD
ARG attrib:DWORD
ARG thick:DWORD
; Exit if mono disabled
pushad
cmp [MonoEnabled],0
je ??fini
; Select the character table for the desired line thickness
mov edi,OFFSET CharData
mov cl,3
mov eax,[thick]
and eax,011b
shl eax,cl
add edi,eax
; Prep width and height.
cmp [width],2
jb ??fini
cmp [height],2
jb ??fini
sub [width],2
sub [height],2
; Set cursor position to upperleft corner of box
push [MonoY]
push [MonoX] ;Save current cursor position
call Mono_Set_Cursor C,[xpos],[ypos]
; Draw the rectangle
mov esi,OFFSET BoxData
; Determine the number of characters to output
??drawloop:
mov ecx,[width]
cmp [BYTE PTR esi+2],1
je short ??gotlen
mov ecx,[height]
cmp [BYTE PTR esi+2],2
je short ??gotlen
mov ecx,1
??gotlen:
jecxz ??donerun
??runloop:
xor eax,eax
mov al,[BYTE PTR edi]
call Mono_Put_Char C,eax,[attrib] ;Output the character.
mov al,[BYTE PTR esi+1]
cbw
cwde
add eax,[MonoY]
push eax
mov al,[BYTE PTR esi]
cbw
cwde
add eax,[MonoX]
dec eax ; Undo cursor advance.
push eax
call Mono_Set_Cursor ; Properly advance cursor.
add sp,8
loop ??runloop
; Advance to next control entry.
??donerun:
add esi,3
inc edi
cmp [BYTE PTR esi+2],-1
jne ??drawloop
; Restore cursor to original position.
call Mono_Set_Cursor
add sp,8
??fini:
popad
ret
ENDP Mono_Draw_Rect
;****************************************************************************
;*
;* NAME
;* Mono_Text_Print - Print a string to the mono screen at a specified
;* position.
;*
;* SYNOPSIS
;* Mono_Text_Print(String, X, Y, Attributes, Update)
;*
;* void Mono_Text_Print(char *, long, long, long, long);
;*
;* FUNCTION
;* Print a NULL terminated string to the mono screen at the specified
;* cooridinates and attributes.
;*
;* INPUTS
;* String - Pointer to NULL terminated string.
;* X - X coordinate position.
;* Y - Y coordinate position.
;* Attributes - Display attributes
;* Update - Update cursor position flag.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C _Mono_Text_Print:NEAR
PROC _Mono_Text_Print C NEAR USES eax esi
ARG text:NEAR PTR
ARG xpos:DWORD
ARG ypos:DWORD
ARG attrib:DWORD
ARG update:DWORD
; Save the current cursor position.
push [MonoY]
push [MonoX]
cmp [text],0 ;Exit if the string is NULL
je short ??fini
call Mono_Set_Cursor C,[xpos],[ypos]
; Print string to the mono screen
mov esi,[text] ;Text pointer
??charloop:
mov eax,[esi]
inc esi
or al,al ;Stop on a NULL
je short ??fini
cmp al,13 ;Special processing for '\r'
je short ??cr
; Output character to mono screen
??normal:
xor ah,ah
call Mono_Put_Char C,eax,[attrib]
; Perform adjustments if wrapping past right margin.
cmp [MonoX],80
jb short ??nowrap
inc [ypos]
call Mono_Set_Cursor C,0,[ypos]
jmp short ??nowrap
; Move to start of next line.
??cr:
inc [ypos]
call Mono_Set_Cursor C,[xpos],[ypos]
; Scroll the monochrome screen if necessary.
??nowrap:
cmp [MonoY],25
jb short ??noscroll
call Mono_Scroll C,1
dec [ypos]
??noscroll:
jmp short ??charloop
??fini:
cmp [update],0
jne short ??noupdate
call Mono_Set_Cursor
??noupdate:
pop eax
pop eax
ret
ENDP _Mono_Text_Print
;****************************************************************************
;*
;* NAME
;* Mono_Text_Print - Print a string to the mono screen. (ASM call)
;*
;* SYNOPSIS
;* Mono_Text_Print(String, X, Y, Attributes)
;*
;* void Mono_Text_Print(char *, long, long, long);
;*
;* FUNCTION
;* Print a NULL terminated string to the mono screen at the specified
;* cooridinates and attributes.
;*
;* INPUTS
;* String - Pointer to NULL terminated string.
;* X - X coordinate position.
;* Y - Y coordinate position.
;* Attributes - Display attributes
;*
;* RESULT
;* NONE
;*
;* SEE ALSO
;* _Mono_Text_Print
;*
;****************************************************************************
GLOBAL C Mono_Text_Print:NEAR
PROC Mono_Text_Print C NEAR USES
ARG text:NEAR PTR
ARG xpos:DWORD
ARG ypos:DWORD
ARG attrib:DWORD
; Exit if mono disabled
cmp [MonoEnabled],0
je short ??fini
call _Mono_Text_Print C,[text],[xpos],[ypos],[attrib],0
??fini:
ret
ENDP Mono_Text_Print
;****************************************************************************
;*
;* NAME
;* Mono_Print - Print a string to the mono screen.
;*
;* SYNOPSIS
;* Mono_Print(String)
;*
;* void Mono_Print(char *);
;*
;* FUNCTION
;* Print a string to the mono screen at the current cursor position and
;* update the cursor position.
;*
;* INPUTS
;* String - Pointer to NULL terminated string.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Mono_Print:NEAR
PROC Mono_Print C NEAR
ARG text:NEAR PTR
; Exit if mono disabled
cmp [MonoEnabled],0
je short ??fini
call _Mono_Text_Print C,[text],[MonoX],[MonoY],2,1
??fini:
ret
ENDP Mono_Print
;****************************************************************************
;*
;* NAME
;* Mono_View_Page - View a mono page.
;*
;* SYNOPSIS
;* Oldpage = Mono_View_Page(Page)
;*
;* long Mono_View_Page(long);
;*
;* FUNCTION
;* Displays the specified page in displayable mono memory.
;*
;* INPUTS
;* Page - Page to view.
;*
;* RESULT
;* Oldpage - Previous page.
;*
;****************************************************************************
GLOBAL C Mono_View_Page:NEAR
PROC Mono_View_Page C NEAR USES ds es eax ebx ecx edi esi
ARG page:DWORD
LOCAL oldpage:DWORD
; Prepare the original page number for return to caller.
cld
mov ebx,[PageMap]
mov [oldpage],ebx
; Exit of mono disabled
cmp [MonoEnabled],0
je short ??fini
; If the desired page is already displayed, then don't do anything.
mov eax,[page]
cmp eax,ebx
je short ??fini
; Verify that page specified is legal.
cmp eax,7
ja short ??fini
; Find where the logical page to display is actually located.
mov ecx,8
push ds
pop es
lea edi,[PageMap]
repne scasw
neg ecx
add ecx,7 ; CX = where desired page is located.
; Swap the page ID bytes in the PageMap array.
sub edi,4
mov ebx,[PageMap]
mov eax,[edi]
mov [edi],ebx
mov [PageMap],eax
shl ecx,8
add ecx,eax
mov esi,ecx
IF PHARLAP_TNT
mov ax,034h
mov ds,ax
ENDIF
mov edi,0B0000h
; Exchange the two pages.
mov ecx,1000H/4
??looper:
mov edx,[edi]
mov ebx,[esi]
mov [edi],ebx
mov [esi],edx
add esi,4
add edi,4
loop ??looper
; Return with the original page number.
??fini:
mov eax,[oldpage]
ret
ENDP Mono_View_Page
END

66
VQ/VQM32/MONO.H Normal file
View File

@@ -0,0 +1,66 @@
/*
** 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/>.
*/
#ifndef VQMMONO_H
#define VQMMONO_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* mono.h
*
* DESCRIPTION
* Mono screen definitions. (32-Bit protected mode)
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* Feburary 8, 1995
*
****************************************************************************/
/* Prototypes */
#ifdef __cplusplus
extern "C" {
#endif
void cdecl Mono_Enable(void);
void cdecl Mono_Disable(void);
void cdecl Mono_Set_Cursor(long x, long y);
void cdecl Mono_Clear_Screen(void);
void cdecl Mono_Scroll(long lines);
void cdecl Mono_Put_Char(long character, long attrib);
void cdecl Mono_Draw_Rect(long x, long y, long w, long h, long attrib,
long thick);
void cdecl Mono_Text_Print(void const *text, long x, long y, long attrib);
void cdecl Mono_Print(void const *text);
short cdecl Mono_View_Page(long page);
short cdecl Mono_X(void);
short cdecl Mono_Y(void);
#ifdef __cplusplus
}
#endif
#endif /* VQMMONO_H */

319
VQ/VQM32/PALETTE.ASM Normal file
View File

@@ -0,0 +1,319 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* palette.asm
;*
;* DESCRIPTION
;* Hardware level palette routines. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Bill Randolph
;* Denzil E. Long, Jr.
;*
;* DATE
;* January 26, 1995
;*
;*---------------------------------------------------------------------------
;*
;* To write palette colors:
;* - Out color # to 3c8h
;* - Out RGB values to 3c9h (data must be written in three's; PEL address
;* register auto-increments after 3 reads or writes)
;*
;* A time interval of about 240 ns is required between successive reads/
;* writes; on very fast machines, this means that the system may not be
;* able to handle a rapid-fire of RGB values. So, a "safe" routine is
;* provided that has wait states between each out.
;*
;* Reference: Progammers Guide to the EGA & VGA Cards, Ferraro, 2nd ed.
;* (Chapter 8.)
;*
;* Note that, if you set the palette in active scan, the screen will
;* flash; to prevent this, wait for vertical retrace (Vertical Blank
;* Interval), or turn the display off by using the Screen Off field in
;* the Clocking Mode register (Hmmmm....).
;*
;* To read palette colors:
;* - Out color # to 3c7h
;* - In RGB values from 3c9h (data must be read in three's; PEL address
;* register auto-increments after 3 reads or writes)
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* SetPalette - Set the palette without waiting to Vblank.
;* ReadPalette - Read the palette from the display adapter.
;* SetDAC - Set a single palette color in the DAC.
;* TranslatePalette - Translate 24-bit color to 15-bit color.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
INCLUDE "vga.i"
CODESEG
;****************************************************************************
;*
;* NAME
;* SetPalette - Set the palette without waiting to Vblank.
;*
;* SYNOPSIS
;* SetPalette(Palette, Numbytes, SlowFlag)
;*
;* void SetPalette(char *, long, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Palette - Pointer to the palette to set.
;* NumBytes - Number of bytes of palette to transfer (multiple of 3).
;* SlowFlag - Slow palette set flag.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C SetPalette:NEAR
PROC SetPalette C NEAR USES eax ecx edx esi ds
ARG palette:NEAR PTR
ARG numbytes:DWORD
ARG slowpal:DWORD
pushf
cld
cmp [slowpal],0 ;Do slow palette?
jne ??safe_palette_routine
;----------------------------------------------------------------------------
; Fast palette set
;----------------------------------------------------------------------------
mov esi,[palette]
mov edx,PEL_WRITE_ADDR
xor al,al
out dx,al ;Select color to write too.
inc al ;Step to the next color for next loop
inc edx ;DX = PEL_DATA
mov ecx,[numbytes] ;Max # colors to set
rep outsb ;Write 256 * RGB out to the palette
popf
ret
;----------------------------------------------------------------------------
; Safe palette set
;----------------------------------------------------------------------------
??safe_palette_routine:
mov esi,[palette]
mov ecx,[numbytes]
mov edx,PEL_WRITE_ADDR
sub eax,eax
out dx,al
mov edx,PEL_DATA
??Write_loop:
lodsb
out dx,al ;Red
jmp $+02 ;Delay (flush instruction cache)
lodsb
out dx,al ;Green
jmp $+02 ;Delay (flush instruction cache)
lodsb
out dx,al ;Blue
jmp $+02 ;Delay (flush instruction cache)
sub cx,3
ja ??Write_loop
popf
ret
ENDP SetPalette
;****************************************************************************
;*
;* NAME
;* ReadPalette - Read the palette from the display adapter.
;*
;* SYNOPSIS
;* ReadPalette(Palette)
;*
;* void SetPalette(char *);
;*
;* FUNCTION
;*
;* INPUTS
;* Palette - Pointer buffer to copy palette into.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C ReadPalette:NEAR
PROC ReadPalette C NEAR USES ecx edx edi es
ARG palette:NEAR PTR
mov edi,[palette]
mov ecx,256
mov edx,PEL_READ_ADDR
sub eax,eax
out dx,al
mov edx,PEL_DATA
??Read_loop:
in al,dx ;Red
stosb ;Save the byte
jmp $+02 ;Delay (flush instruction cache)
in al,dx ;Green
stosb ;Save the byte
jmp $+02 ;Delay (flush instruction cache)
in al,dx ;Blue
stosb ;Save the byte
jmp $+02 ;Delay (flush instruction cache)
dec ecx
jnz ??Read_loop
ret
ENDP ReadPalette
;****************************************************************************
;*
;* NAME
;* SetDAC - Set a single palette color in the DAC.
;*
;* SYNOPSIS
;* SetDAC(ColorNum, Red, Green, Blue)
;*
;* void SetPalette(long, char, char);
;*
;* FUNCTION
;*
;* INPUTS
;* ColorNum - Position number in palette of color to set.
;* Red - Red gun value.
;* Green - Green gun value.
;* Blue - Blue gun value.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C SetDAC:NEAR
PROC SetDAC C NEAR USES edx
ARG color_num:DWORD
ARG red:BYTE
ARG green:BYTE
ARG blue:BYTE
mov edx,PEL_WRITE_ADDR
mov eax,[color_num]
out dx,al ;Set color position
inc edx
jmp $+02 ;Delay (flush instruction cache)
mov al,[red]
out dx,al ;Set red gun
jmp $+02 ;Delay (flush instruction cache)
mov al,[green]
out dx,al ;Set green gun
jmp $+02 ;Delay (flush instruction cache)
mov al,[blue]
out dx,al ;Set blue gun
ret
ENDP SetDAC
;****************************************************************************
;*
;* NAME
;* TranslatePalette - Translate 24-bit color to 15-bit color.
;*
;* SYNOPSIS
;* TranslatePalette(Pal24, Pal15, NumBytes)
;*
;* void TranslatePalette(char *, char *, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Pal24 - Pointer to 24-bit palette. (Input)
;* Pal15 - Pointer to 15-bit palette. (Output)
;* NumBytes - Number of bytes to translate. (divisible by 3)
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C TranslatePalette:NEAR
PROC TranslatePalette C NEAR USES ecx edx edi esi
ARG pal24:NEAR PTR
ARG pal15:NEAR PTR
ARG numbytes:DWORD
mov esi,[pal24]
mov edi,[pal15]
mov ecx,[numbytes]
??TranslatePalette:
mov ah,[BYTE PTR esi] ;AH = red
mov al,[BYTE PTR esi+1] ;AL = green
mov dl,[BYTE PTR esi+2] ;DL = blue
shr ah,1 ;Red = lower 5 bits of AH
shl al,2 ;Green = upper 6 bits of AL
shr dl,1 ;Blue = lower 5 bits of DL
shl eax,2 ;Make room for blue
and al,0E0h ;Trim off bottom bit of green
or al,dl ;Load in blue bits
mov [WORD PTR edi],ax ;Store the value
add esi,3 ;Increment to next RGB values
add edi,2 ;Increment to next palette word
sub ecx,3
ja ??TranslatePalette
ret
ENDP TranslatePalette
END

59
VQ/VQM32/PALETTE.H Normal file
View File

@@ -0,0 +1,59 @@
/*
** 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/>.
*/
#ifndef VQMPALETTE_H
#define VQMPALETTE_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* Palette.h (32-Bit protected mode)
*
* DESCRIPTION
* Palette definitions.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* Febuary 3, 1995
*
****************************************************************************/
/* Prototypes */
#ifdef __cplusplus
extern "C" {
#endif
void cdecl SetPalette(unsigned char *palette,long numbytes,unsigned long slowpal);
void cdecl ReadPalette(void *palette);
void cdecl SetDAC(long color, long red, long green, long blue);
void cdecl TranslatePalette(void *pal24, void *pal15, long numbytes);
#ifdef __cplusplus
}
#endif
void SortPalette(unsigned char *pal, long numcolors);
#endif /* VQMPALETTE_H */

116
VQ/VQM32/PORTIO.ASM Normal file
View File

@@ -0,0 +1,116 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* portio.asm
;*
;* DESCRIPTION
;* I/O Port access. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Denzil E. Long, Jr.
;*
;* DATE
;* January 26, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* inp - Read a byte from a hardware port.
;* outp - Write a byte to a hardware port.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
CODESEG
;****************************************************************************
;*
;* NAME
;* inp - Read a byte from a hardware port.
;*
;* SYNOPSIS
;* Data = inp(PortID)
;*
;* short inp(unsinged short);
;*
;* FUNCTION
;*
;* INPUTS
;* PortID - Address if hardware port.
;*
;* RESULT
;* Data - Data read from port.
;*
;****************************************************************************
GLOBAL C inp:NEAR
PROC inp C NEAR USES edx
ARG port:WORD
mov dx,[port]
xor eax,eax
in al,dx
ret
ENDP inp
;****************************************************************************
;*
;* NAME
;* outp - Write a byte to a hardware port.
;*
;* SYNOPSIS
;* outp(PortID, Value)
;*
;* void outp(unsinged short, short);
;*
;* FUNCTION
;*
;* INPUTS
;* PortID - Address if hardware port.
;* Value - Value to write.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C outp:NEAR
PROC outp C NEAR USES edx
ARG port:WORD
ARG value:WORD
mov dx,[port]
mov ax,[value]
out dx,al
ret
ENDP outp
END

57
VQ/VQM32/PORTIO.H Normal file
View File

@@ -0,0 +1,57 @@
/*
** 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/>.
*/
#ifndef VQMPORTIO_H
#define VQMPORTIO_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* Portio.h (32-Bit protected mode)
*
* DESCRIPTION
* Hardware port I/O
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* Febuary 3, 1995
*
****************************************************************************/
#ifdef __BORLANDC__
#ifdef __cplusplus
extern "C" {
#endif
short cdecl inp(unsigned short portid);
void cdecl outp(unsigned short portid, short value);
#ifdef __cplusplus
}
#endif
#endif /* __BORLANDC__ */
#endif /* VQMPORTIO_H */

431
VQ/VQM32/PROFILE.CPP Normal file
View File

@@ -0,0 +1,431 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* profile.c
*
* DESCRIPTION
* INI file processing. (32-Bit protected mode)
*
* PROGRAMMER
* Bill Randolph
* Denzil E. Long, Jr.
*
* DATE
* January 26, 1995
*
*----------------------------------------------------------------------------
*
* PUBLIC
* Get_Frame_Pathname - Get pathname for a given frame and file type.
* GetINIInt - Get an integer value from an INI file.
* GetINIString - Get a string from the INI file.
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "profile.h"
/*---------------------------------------------------------------------------
* PRIVATE DECLARATIONS
*-------------------------------------------------------------------------*/
#ifndef max
#define max(a,b) (((a)>(b))?(a):(b))
#endif
#ifndef min
#define min(a,b) (((a)<(b))?(a):(b))
#endif
#define isspace(c) ((c==' ')||(c=='\t')||(c=='\n')||(c=='\r')?1:0)
static char *strtrim(char *string);
static long FileGets(FILE *fp, char *buf, long buflen);
/****************************************************************************
*
* NAME
* Get_Frame_Pathname - Get pathname for a given frame and file type.
*
* SYNOPSIS
* Error = Get_Frame_Pathname(IniFile, Frame, Extension, Buffer)
*
* long Get_Frame_Pathname(char *, long, char *, char *);
*
* FUNCTION
*
* INPUTS
* IniFile - Pointer to INI filename.
* Frame - Number of frame to get filename for.
* Extension - File extension type.
* Buffer - Pointer to buffer to put pathname into.
*
* RESULT
* Error - 0 if successful, or -1 if error.
*
***************************************************************************/
long Get_Frame_Pathname(char *inifile, long anim_frame, char *ext,
char *outbuf)
{
char rootdir[_MAX_PATH]; // Root directory from INI file
char extdir[_MAX_PATH]; // this extension's directory
char entry_name[40]; // INI entry name
char inibuf[80]; // string returned from INI file
char *prefix; // 4-char prefix for this scene
char *startstr; // starting frame #, string
char *endstr; // ending frame #, string
char *palstr; // palette filename string
long startnum; // scene's starting frame #
long endnum; // scene's ending frame #
long total_frames; // accumulated frame total
long scene_frames; // # frames in a given scene
long scene_num; // scene #
long file_frame; // file's frame #
long rc;
/* Get directory for this file type */
GetINIString("Path", "Root", "", rootdir, 80, inifile);
if (rootdir[strlen (rootdir) - 1] != '\\') {
strcat(rootdir,"\\");
}
GetINIString("Path", ext, "", extdir, 80, inifile);
if (extdir[strlen (extdir) - 1] != '\\') {
strcat(extdir,"\\");
}
/* VQG is a special case:
*
* The VQG files are named based upon the 1st 4 characters of the 'Name'
* entry in the INI file, and their numbers match the actual animation
* frame numbers, not the scene frame numbers.
*/
if (!stricmp(ext, "VQG")) {
GetINIString("Common", "Name", "", inibuf, 80, inifile);
if (strlen(inibuf) > 4) {
inibuf[4] = 0;
}
sprintf(outbuf,"%s%s%s%04d.%s",rootdir,extdir,inibuf,anim_frame,ext);
return (0);
}
/*-------------------------------------------------------------------------
* Loop through scenes until the desired frame # is found
*-----------------------------------------------------------------------*/
total_frames = 0;
scene_num = 1;
while (1) {
/* Get this scene's entry */
sprintf(entry_name, "Scene%d", scene_num);
rc = GetINIString("Scenes",entry_name,"",inibuf,80,inifile);
if (rc == 0) {
return (-1);
}
/* Parse the INI entry */
prefix = strtok(inibuf, ",");
startstr = strtok(NULL, ",");
endstr = strtok(NULL, ",");
palstr = strtok(NULL, ",");
if ((prefix == NULL) || (startstr == NULL) || (endstr == NULL)) {
return (-1);
}
startnum = atoi(startstr);
endnum = atoi(endstr);
scene_frames = ((endnum - startnum) + 1);
/* requested frame is found */
if (anim_frame < (total_frames + scene_frames)) {
/* Palette is a special case */
if (!stricmp(ext, "PAL")) {
if (palstr == NULL) {
return (-1);
} else {
sprintf(outbuf, "%s%s%s.PAL", rootdir, extdir, palstr);
return (0);
}
} else {
file_frame = ((anim_frame - total_frames) + startnum);
sprintf(outbuf,"%s%s%s%04d.%s",rootdir,extdir,prefix,file_frame,ext);
return (0);
}
}
/* Frame not found; go to next scene */
total_frames += scene_frames;
scene_num++;
}
}
/****************************************************************************
*
* NAME
* GetINIInt - Get an integer value from an INI file.
*
* SYNOPSIS
* Value = GetINIInt(Section, Entry, Default, ININame)
*
* long GetINIInt(char *, char *, long, char *);
*
* FUNCTION
* Retrieve an integer value from the INI file at the specified 'Section'
* and 'Entry' fields. If no value is defined then return the passed in
* 'Default' value.
*
* INPUTS
* Section - Pointer to section name.
* Entry - Pointer to entry name.
* Default - Default value.
* ININame - Pointer to INI filename.
*
* RESULT
* Value - Integer value from INI file or 'Default'.
*
****************************************************************************/
long GetINIInt(char const *section, char const *entry, long deflt,
char *fname)
{
char buffer[20];
sprintf(buffer, "%d", deflt);
GetINIString(section, entry, buffer, buffer, sizeof(buffer),
fname);
return (atoi(buffer));
}
/****************************************************************************
*
* NAME
* GetINIString - Get a string from the INI file.
*
* SYNOPSIS
* Length = GetINIString(Section, Entry, Default, Buffer,
* Length, ININame)
*
* long GetINIString(char *, char *, char *, char *, long,
* char *);
*
* FUNCTION
*
* INPUTS
* Section - Pointer to section name.
* Entry - Pointer to entry name.
* Default - Pointer to default string.
* Buffer - Pointer to buffer to copy string into.
* Length - Maximum length of string.
* ININame - Pointer to INI filename.
*
* RESULT
* Length - Length of string copied into the buffer.
*
****************************************************************************/
long GetINIString(char const *section, char const *entry,
char const *def, char *retbuffer, long retlen, char *fname)
{
FILE *fp;
long retval;
char txt[80];
char secname[40];
long len;
char *workptr;
/* Copy default value in case entry isn't found */
strncpy(retbuffer, def, (retlen - 1));
retbuffer[retlen - 1] = 0;
retval = min(strlen(def), (unsigned)retlen);
/* Open the file */
if ((fp = fopen(fname, "rt")) == NULL) {
return (retval);
}
/* Generate section name for search */
sprintf(secname, "[%s]", section);
len = strlen(secname);
/* Scan file for section name */
while (1) {
/* Read line; return if end-of-file */
if (FileGets(fp,txt,80)!=0) {
fclose(fp);
return (retval);
}
/* Skip comments */
if (txt[0] == ';') continue;
/* Parse a section name */
if (txt[0] == '[') {
if (!memicmp(secname, txt, len)) break;
}
}
/* Scan file for desired entry */
len = strlen(entry);
while (1) {
/* Read line; return if end-of-file */
if (FileGets(fp, txt, 80) != 0) {
fclose(fp);
return (retval);
}
/* Skip comments */
if (txt[0] == ';') continue;
/* Return if start of next section reached */
if (txt[0] == '[') {
fclose(fp);
return (retval);
}
/* Entry found; parse it */
if (!memicmp(entry, txt, len) && (isspace(txt[len])
|| txt[len] == '=')) {
fclose(fp);
/* Find '=' character */
workptr = strchr(txt, '=');
/* Return if not found */
if (workptr == NULL) return (retval);
/* Skip past '=' */
workptr++;
/* Skip white space */
while (isspace(*workptr) && strlen(workptr) > 0) {
workptr++;
}
/* Return if no string left */
if ((*workptr) == 0) return (retval);
strtrim(workptr);
strcpy(retbuffer,workptr);
return (strlen(workptr));
}
}
}
/****************************************************************************
*
* NAME
* strtrim - Trim off trailing spaces from a string.
*
* SYNOPSIS
* String = strtrim(String)
*
* char *strtrim(char *);
*
* FUNCTION
*
* INPUTS
* String - Pointer to string to trim.
*
* RESULT
* String - Pointer to trimmed string.
*
****************************************************************************/
static char *strtrim(char *string)
{
long i;
/* Return if NULL ptr or zero-length string */
if ((string == NULL) || (strlen(string) == 0)) {
return (string);
}
/* Find 1st non-white-space character from the right */
i = (strlen(string) - 1);
while ((i > 0) && isspace(string[i])) {
i--;
}
/* Set end of string */
i++;
string[i] = 0;
return (string);
}
/****************************************************************************
*
* NAME
* FileGets - A better fgets.
*
* SYNOPSIS
* Error = FileGets(FilePtr, Buffer, Length)
*
* long FileGets(FILE *, char *, long);
*
* FUNCTION
*
* INPUTS
* FilePtr - File pointer.
* Buffer - Pointer to buffer to fill.
* Length - Maximum length of buffer.
*
* RESULT
* Error = 0 if successfull, or -1 if error.
*
****************************************************************************/
static long FileGets(FILE *fp, char *buf, long buflen)
{
if (fgets(buf, buflen, fp)) {
buf[(strlen(buf) - 1)] = 0;
return (0);
} else {
return (-1);
}
}

52
VQ/VQM32/PROFILE.H Normal file
View File

@@ -0,0 +1,52 @@
/*
** 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/>.
*/
#ifndef VQMPROFILE_H
#define VQMPROFILE_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* Profile.h (32-Bit protected mode)
*
* DESCRIPTION
* INI file profiling definitions.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* January 26, 1995
*
****************************************************************************/
/* Prototypes */
long GetINIInt(char const *section, char const *entry,
long deflt, char *fname);
long GetINIString(char const *section, char const *entry,
char const *def, char *retbuffer, long retlen, char *fname);
long Get_Frame_Pathname(char *inifile,long anim_frame,char *ext,
char *outbuf);
#endif /* VQMPROFILE_H */

82
VQ/VQM32/REALMODE.H Normal file
View File

@@ -0,0 +1,82 @@
/*
** 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/>.
*/
#ifndef VQMREALMODE_H
#define VQMREALMODE_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* realmode.h
*
* DESCRIPTION
* Real-mode interfacing definitions and equates. Many of the definitions
* and descriptions in this file were taken from other sources and
* compiled here for use in MISC32 library.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* Febuary 6, 1995
*
****************************************************************************/
/* REALPTR: Real-mode pointer (segment:offset16).
*
* The REALPTR data type is used in protected mode to hold real-mode
* pointers. The type is an unsigned long value, were the upper 16 bits
* are the segment number and the lower 16 bit are an offset. This type
* and the associated macros are identical to that of the PHARLAP "pltypes.h"
* definitions for easy of conversion to WATCOM/4GW.
*/
typedef unsigned long REALPTR;
#define RP_OFF(rp) ((unsigned short)(((unsigned long)(rp)) & 0xFFFF))
#define RP_SEG(rp) ((unsigned short)(((unsigned long)(rp)) >> 16))
#define RP_SET(rp, off, seg) (rp = ((unsigned long)(seg) << 16) + (off))
#define RP_INCR(rp, incr) (rp += ((unsigned long)(incr)) & 0xFFFF)
#define MK_PTR(off, seg) (void *)((((unsigned long)seg&0xFFFF)<<4)+off)
/* RMInfo: Real-mode interrupt call structure.
*
* Information that needs to be passed down to the real-mode interrupt is
* transfered using this structure. The address to this protected-mode
* structure (allocated by user) is passed into DPMI function 0x300. DOS/4GW
* will then use this information to set up the real-mode registers, switch
* to real-mode and then execute the interrupt in real-mode.
*/
typedef struct _RMInfo {
long edi;
long esi;
long ebp;
long reservedbysystem;
long ebx;
long edx;
long ecx;
long eax;
short flags;
short es,ds,fs,gs,ip,cs,sp,ss;
} RMInfo;
#endif /* VQMREALMODE_H */

315
VQ/VQM32/SORTPAL.CPP Normal file
View File

@@ -0,0 +1,315 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* sortpal.c
*
* DESCRIPTION
* Palette sorting routines. (32-Bit protected mode)
*
* PROGRAMMER
* Denzil E. Long, Jr.
* Bill Randolph
*
* DATE
* January 26, 1995
*
*----------------------------------------------------------------------------
*
* PUBLIC
* SortPalette - Sort a palette.
* Comp_Luminance - Compare the luminace of two 24-bit palette entries.
* Comp_HSV - Compare the HSV of two 24-bit palette entries.
* RGB_To_HSV - Convert RGB color to HSV color.
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "palette.h"
/*---------------------------------------------------------------------------
* PRIVATE DECLARATIONS
*-------------------------------------------------------------------------*/
/* HSV color model */
#define DIVIDE_WITH_ROUND(n,d) (unsigned short)(((n)/(d))+ \
(unsigned short)(((n)%(d)) >= (((d)+1)>>1)))
#define HSV_BASE 255
#define HUE_WEIGHT 10L
#define SATURATION_WEIGHT 100L
#define VALUE_WEIGHT 1000L
/* Prototypes */
static int Comp_Luminance(const void *elem1, const void *elem2);
static int Comp_HSV(const void *elem1, const void *elem2);
static void RGB_To_HSV(unsigned short r, unsigned short g, unsigned short b,
unsigned short *h, unsigned short *s, unsigned short *v);
/****************************************************************************
*
* NAME
* SortPalette - Sort a palette.
*
* SYNOPSIS
* SortPalette(Palette, NumColors)
*
* void SortPalette(unsigned char *, long);
*
* FUNCTION
* Sort the palette colors.
*
* INPUTS
* Palette - Pointer to palette to sort.
* NumColors - Number of colors in the palette.
*
* RESULT
* NONE
*
****************************************************************************/
void SortPalette(unsigned char *pal, long numcolors)
{
qsort(pal, numcolors, 3, Comp_Luminance);
pal[0] = 0;
pal[1] = 0;
pal[2] = 0;
}
/****************************************************************************
*
* NAME
* Comp_Luminance - Compare the luminace of two 24-bit palette entries.
*
* SYNOPSIS
* Result = Comp_Luminance(Color1, Color2)
*
* long Comp_Luminance(void *, void *);
*
* FUNCTION
* Compare the luminace of the two colors and determine which color is
* brighter than the other.
*
* The computation used is:
* Luminance = (red * .299) + (green * .587) + (blue * .114)
*
* INPUTS
* Color1 - Pointer to palette entry.
* Color2 - Pointer to palette entry.
*
* RESULT
* Result - 0 = same, 1 = Color1 > Color2, -1 = Color1 < Color2
*
****************************************************************************/
static int Comp_Luminance(const void *elem1, const void *elem2)
{
unsigned char *pal;
long r,g,b;
long total1,total2;
/* Compute luminance for color1 */
pal = (unsigned char *)elem1;
r = ((long)pal[0]);
g = ((long)pal[1]);
b = ((long)pal[2]);
total1 = ((r * 19595L) + (g * 38470L) + (b * 7471L));
/* Compute luminance for color2 */
pal = (unsigned char *)elem2;
r = ((long)pal[0]);
g = ((long)pal[1]);
b = ((long)pal[2]);
total2 = ((r * 19595L) + (g * 38470L) + (b * 7471L));
if (total1 < total2) {
return (-1);
} else if (total1 > total2) {
return (1);
} else {
return (0);
}
}
/****************************************************************************
*
* NAME
* Comp_HSV - Compare the HSV of two 24-bit palette entries.
*
* SYNOPSIS
* Result = Comp_HSV(Color1, Color2)
*
* long Comp_HSV(void *, void *);
*
* FUNCTION
* Compare the HSV color values of two colors and determine the
* relationship between the colors in the color space.
*
* INPUTS
* Color1 - Pointer to 1st palette entry.
* Color2 - Pointer to 2nd palette entry.
*
* RESULT
* Result - 0 = same, 1 = Color1 > Color2, -1 = Color1 < Color2
*
****************************************************************************/
static int Comp_HSV(const void *elem1, const void *elem2)
{
unsigned char *pal;
unsigned char r,g,b;
unsigned short h,s,v;
unsigned long key1,key2;
long retval;
/* Convert 1st element to HSV */
pal = (unsigned char *)elem1;
r = pal[0];
g = pal[1];
b = pal[2];
RGB_To_HSV((unsigned short)r,(unsigned short)g,(unsigned short)b,&h,&s,&v);
key1 = ((h * HUE_WEIGHT) + (s * SATURATION_WEIGHT) + (v * VALUE_WEIGHT));
/* Convert 2nd element to HSV */
pal = (unsigned char *)elem2;
r = pal[0];
g = pal[1];
b = pal[2];
RGB_To_HSV((unsigned short)r,(unsigned short)g,(unsigned short)b,&h,&s,&v);
key2 = ((h * HUE_WEIGHT) + (s * SATURATION_WEIGHT) + (v * VALUE_WEIGHT));
if (key1 != key2) {
retval = ((key1 < key2) ? -1 : 1);
} else {
retval = 0;
}
return (retval);
}
/***************************************************************************
*
* NAME
* RGB_To_HSV - Convert RGB color to HSV color.
*
* SYNOPSIS
* RGB_To_HSV(R, G, B, H, S, V)
*
* void RGB_To_HSV(unsigned short, unsigned short, unsigned short,
* unsigned short *, unsigned short *, unsigned short *);
*
* FUNCTION
* Convert the RBG color to a HSV color. Assumes 8 bits per gun of R, G
* and B data. Also the HSV is based on a 255 degree scale rather than
* the more accurate 360 degree scale.
*
* INPUTS
* R - Red gun value.
* G - Green gun value.
* B - Blue gun value.
* H - Pointer to H value. (H will be set upon return of this function)
* S - Pointer to S value. (S will be set upon return of this function)
* V - Pointer to V value. (V will be set upon return of this function)
*
* RESULT
* NONE
*
***************************************************************************/
static void RGB_To_HSV(unsigned short r, unsigned short g, unsigned short b,
unsigned short *h, unsigned short *s, unsigned short *v)
{
unsigned short m;
unsigned short r1;
unsigned short g1;
unsigned short b1;
unsigned short tmp;
/* Set hue to default. */
*h = 0;
/* Set v = Max(r,g,b) to find dominant primary color. */
*v = ((r > g) ? r : g);
if (b > *v) {
*v = b;
}
/* Set m = min(r,g,b) to find amount of white. */
m = ((r < g) ? r : g);
if (b < m) {
m = b;
}
/* Determine the normalized saturation. */
if (*v != 0) {
*s = DIVIDE_WITH_ROUND((*v - m) * HSV_BASE, *v);
} else {
*s = 0;
}
if (*s != 0) {
tmp = *v - m;
r1 = DIVIDE_WITH_ROUND((*v - r) * HSV_BASE, tmp);
g1 = DIVIDE_WITH_ROUND((*v - g) * HSV_BASE, tmp);
b1 = DIVIDE_WITH_ROUND((*v - b) * HSV_BASE, tmp);
/* Find effect of second most predominant color.
* In which section of the hexagon of colors does the color lie?
*/
if ((*v) == r) {
if (m == g) {
*h = 5 * HSV_BASE + b1;
} else {
*h = 1 * HSV_BASE - g1;
}
} else {
if ((*v) == g) {
if (m == b) {
*h = 1 * HSV_BASE + r1;
} else {
*h = 3 * HSV_BASE - b1;
}
} else {
if (m == r) {
*h = 3 * HSV_BASE + g1;
} else {
*h = 5 * HSV_BASE - r1;
}
}
}
/* Divide by six and round. */
*h = DIVIDE_WITH_ROUND(*h, 6);
}
}

1271
VQ/VQM32/SOSCODEC.ASM Normal file

File diff suppressed because it is too large Load Diff

90
VQ/VQM32/SOSCOMP.H Normal file
View File

@@ -0,0 +1,90 @@
/*
** 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/>.
*/
/****************************************************************************
*
* File : soscomp.h
* Date Created : 6/1/94
* Description :
*
* Programmer(s) : Nick Skrepetos
* Last Modification : 10/1/94 - 11:37:9 AM
* Additional Notes : Modified by Denzil E. Long, Jr.
*
*****************************************************************************
* Copyright (c) 1994, HMI, Inc. All Rights Reserved *
****************************************************************************/
#ifndef _SOS_COMPRESS
#define _SOS_COMPRESS
/* compression types */
enum {
_ADPCM_TYPE_1,
};
/* define compression structure */
typedef struct _tagCOMPRESS_INFO {
char *lpSource;
char *lpDest;
unsigned long dwCompSize;
unsigned long dwUnCompSize;
short wBitSize;
short wChannels;
unsigned long dwSampleIndex;
long dwPredicted;
long dwDifference;
short wCodeBuf;
short wCode;
short wStep;
short wIndex;
unsigned long dwSampleIndex2; //added BP for channel 2
long dwPredicted2; //added BP for channel 2
long dwDifference2; //added BP for channel 2
short wCodeBuf2; //added BP for channel 2
short wCode2; //added BP for channel 2
short wStep2; //added BP for channel 2
short wIndex2; //added BP for channel 2
} _SOS_COMPRESS_INFO;
/* compressed file type header */
typedef struct _tagCOMPRESS_HEADER {
unsigned long dwType; // type of compression
unsigned long dwCompressedSize; // compressed file size
unsigned long dwUnCompressedSize; // uncompressed file size
unsigned long dwSourceBitSize; // original bit size
char szName[16]; // file type, for error checking
} _SOS_COMPRESS_HEADER;
/* Prototypes */
#ifdef __cplusplus
extern "C" {
#endif
void cdecl sosCODECInitStream(_SOS_COMPRESS_INFO *);
unsigned long cdecl sosCODECCompressData(_SOS_COMPRESS_INFO *,unsigned long);
unsigned long cdecl sosCODECDecompressData(_SOS_COMPRESS_INFO *,unsigned long);
#ifdef __cplusplus
}
#endif
#endif

699
VQ/VQM32/TARGA.CPP Normal file
View File

@@ -0,0 +1,699 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* targa.c
*
* DESCRIPTION
* Targa Image File reader. (32-Bit protected mode)
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* January 26, 1995
*
*----------------------------------------------------------------------------
*
* PUBLIC
* OpenTarga - Open Targa image file.
* CloseTarga - Close Targa image file.
* LoadTarga - Load Targa image file.
* XFlipTarga - X flip the image.
* YFlipTarga - Y flip the image.
*
* PRIVATE
* DecodeImageData - Decompress Targa image data.
*
****************************************************************************/
#include <stdio.h>
#include <malloc.h>
#include <mem.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include "targa.h"
/* Private data declerations. */
static long DecodeImageData(TGAHandle *, char *);
static void InvertImageData(TGAHeader *, char *);
/****************************************************************************
*
* NAME
* OpenTarga - Open Targa image file.
*
* SYNOPSIS
* TGAHandle = OpenTarga(Name, Mode)
*
* TGAHandle *OpenTarga(char *, unsigned short);
*
* FUNCTION
* Open a Targa image file and read in its header. The file stream will
* positioned after the ID field (if there is one).
*
* INPUTS
* Name - Pointer to name of Targa file.
* Mode - Access mode.
*
* RESULT
* TGAHandle - Pointer to initialized TGAHandle or NULL if error.
*
****************************************************************************/
TGAHandle *OpenTarga(char *name, unsigned short mode)
{
TGAHandle *tga;
long size;
long error = 0;
/* Allocate TGAHandle */
if ((tga = (TGAHandle *)malloc(sizeof(TGAHandle))) != NULL) {
/* Initialize TGAHandle structure. */
memset((void *)tga, 0, sizeof(TGAHandle));
tga->mode = mode;
switch (mode) {
/* Open targa file for read. */
case TGA_READMODE:
if ((tga->fh = open(name, (O_RDONLY|O_BINARY))) != -1) {
/* Read in header. */
size = read(tga->fh, &tga->header, sizeof(TGAHeader));
if (size != sizeof(TGAHeader)) {
error = 1;
}
/* Skip the ID field */
if (!error && (tga->header.IDLength != 0)) {
if (lseek(tga->fh, tga->header.IDLength, SEEK_CUR) == -1) {
error = 1;
}
}
} else {
error = 1;
}
break;
/* Open targa file for write. */
case TGA_WRITEMODE:
if ((tga->fh = open(name, (O_CREAT|O_TRUNC|O_WRONLY|O_BINARY),
(S_IREAD|S_IWRITE))) == -1) {
error = 1;
} else {
printf("\r");
}
break;
/* Open targa file for read/write.*/
case TGA_RDWRMODE:
if ((tga->fh = open(name, (O_RDWR|O_BINARY),
(S_IREAD|S_IWRITE))) != -1) {
/* Read in header. */
size = read(tga->fh, &tga->header, sizeof(TGAHeader));
if (size != sizeof(TGAHeader)) {
error = 1;
}
/* Skip the ID field */
if (!error && (tga->header.IDLength != 0)) {
if (lseek(tga->fh, tga->header.IDLength, SEEK_CUR) == -1) {
error = 1;
}
}
} else {
error = 1;
}
break;
}
/* Close on any error! */
if (error) {
CloseTarga(tga);
tga = NULL;
}
}
return (tga);
}
/****************************************************************************
*
* NAME
* CloseTarga - Close Targa image file.
*
* SYNOPSIS
* CloseTarga(TGAHandle)
*
* void CloseTarga(TGAHandle *);
*
* FUNCTION
* Close the Targa image file and free its handle.
*
* INPUTS
* TGAHandle - Pointer to TGAHandle returned by OpenTarga().
*
* RESULT
* NONE
*
****************************************************************************/
void CloseTarga(TGAHandle *tga)
{
/* Ensure valid handle. */
if (tga) {
/* Close the file if it is open. */
if (tga->fh != -1) close(tga->fh);
/* Free TGAHandle */
free(tga);
}
}
/****************************************************************************
*
* NAME
* LoadTarga - Load Targa Image File.
*
* SYNOPSIS
* Error = LoadTarga(Name, Palette, ImageBuffer)
*
* long LoadTarga(char *, char *, char *);
*
* FUNCTION
* Open and load the Targa into the specified buffers. If either buffer
* pointer is NULL then that field will not be processed.
*
* INPUTS
* Name - Name of Targa image file to load.
* Palette - Pointer to buffer to load the palette into.
* ImageBuffer - Pointer to buffer to load the image data into.
*
* RESULT
* Error - 0 if successful, or TGAERR_??? error code.
*
****************************************************************************/
long LoadTarga(char *name, char *palette, char *image)
{
TGAHandle *tga;
long size;
long depth;
long i,n;
char c;
long error = 0;
/* Open the Targa */
if ((tga = OpenTarga(name, TGA_READMODE)) != NULL) {
/* Process ColorMap (palette) */
if (tga->header.ColorMapType == 1) {
depth = (tga->header.CMapDepth >> 3);
size = (tga->header.CMapLength * depth);
/* Load the palette from the TGA if a palette buffer is provided
* otherwise we will skip it.
*/
if ((palette != NULL) && (tga->header.CMapLength > 0)) {
/* Adjust palette to the starting color entry. */
palette += (tga->header.CMapStart * depth);
/* Read in the palette. */
if (read(tga->fh, palette, size) == size) {
/* Swap the byte ordering of the palette entries. */
for (i = 0; i < tga->header.CMapLength; i++) {
#if(0)
for (n = 0; n < depth; n++) {
c = *(palette + n);
*(palette + n) = *(palette + ((depth - 1) - n));
*(palette + ((depth - 1) - n)) = c;
}
#else
c = *palette;
*palette = *(palette + (depth - 1));
*(palette + (depth - 1)) = c;
#endif
/* Next entry */
palette += depth;
}
} else {
error = TGAERR_READ;
}
} else {
if (lseek(tga->fh, size, SEEK_CUR) == -1) {
error = TGAERR_READ;
}
}
}
/* Load the image data from the TGA if an image buffer is provided
* otherwise we are done.
*/
if (!error && (image != NULL)) {
depth = (tga->header.PixelDepth >> 3);
size = ((tga->header.Width * tga->header.Height) * depth);
switch (tga->header.ImageType) {
case TGA_CMAPPED:
if (read(tga->fh, image, size) != size) {
error = TGAERR_READ;
}
break;
case TGA_TRUECOLOR:
if (read(tga->fh, image, size) == size) {
InvertImageData(&tga->header, image);
} else {
error = TGAERR_READ;
}
break;
case TGA_CMAPPED_ENCODED:
error = DecodeImageData(tga, image);
break;
case TGA_TRUECOLOR_ENCODED:
if ((error = DecodeImageData(tga, image)) == NULL) {
InvertImageData(&tga->header, image);
}
break;
default:
error = TGAERR_NOTSUPPORTED;
break;
}
/* Arrange the image so that the origin position (coordinate 0,0)
* is the upperleft hand corner of the image.
*/
if (!error) {
if (tga->header.ImageDescriptor & TGAF_XORIGIN) {
XFlipTarga(&tga->header, image);
}
if ((tga->header.ImageDescriptor & TGAF_YORIGIN) == 0) {
YFlipTarga(&tga->header, image);
}
}
}
/* Close the Targa */
CloseTarga(tga);
} else {
error = TGAERR_OPEN;
}
return (error);
}
/****************************************************************************
*
* NAME
* SaveTarga - Save a Targa Image File.
*
* SYNOPSIS
* Error = SaveTarga(Name, TGAHeader, Palette, ImageBuffer)
*
* long SaveTarga(char *, TGAHeader *, char *, char *);
*
* FUNCTION
*
* INPUTS
* Name - Pointer to name of file to save.
* TGAHeader - Pointer to initialized targa header structure.
* Palette - Pointer to palette.
* ImageBuffer - Pointer to raw image data.
*
* RESULT
* Error - 0 if successful, or TGAERR_??? error code.
*
****************************************************************************/
long SaveTarga(char *name, TGAHeader *tgahd, char *palette, char *image)
{
TGAHandle *tga;
long size;
long depth;
char *temppal;
char *ptr;
long i,n;
char c;
long error = 0;
/* Open the Targa for write. */
if ((tga = OpenTarga(name, TGA_WRITEMODE)) != NULL) {
/* Write the header. */
if (write(tga->fh, tgahd, sizeof(TGAHeader)) != sizeof(TGAHeader)) {
error = TGAERR_WRITE;
}
/* Write the palette. */
if (!error && (palette != NULL) && (tgahd->CMapLength > 0)) {
/* Adjust palette to the starting color entry. */
depth = (tgahd->CMapDepth >> 3);
palette += (tgahd->CMapStart * depth);
size = (tgahd->CMapLength * depth);
/* Allocate temporary buffer for palette manipulation. */
if ((temppal = (char *)malloc(size)) != NULL) {
memcpy(temppal, palette, size);
ptr = temppal;
/* Swap the byte ordering of the palette entries. */
for (i = 0; i < tga->header.CMapLength; i++) {
for (n = 0; n < (depth >> 1); n++) {
c = *(ptr + n);
*(ptr + n) = *(ptr + (depth - n));
*(ptr + (depth - n)) = c;
}
/* Next entry */
palette += depth;
}
/* Write the palette. */
if (write(tga->fh, temppal, size) != size) {
error = TGAERR_WRITE;
}
/* Free temporary palette buffer. */
free(temppal);
} else {
error = TGAERR_NOMEM;
}
}
/* Invert truecolor data. */
if (tgahd->ImageType == TGA_TRUECOLOR) {
InvertImageData(tgahd, image);
}
/* Write the image. */
if (!error && (image != NULL)) {
depth = (tgahd->PixelDepth >> 3);
size = (((tgahd->Width * tgahd->Height)) * depth);
if (write(tga->fh, image, size) != size) {
error = TGAERR_WRITE;
}
}
/* Close targa file. */
CloseTarga(tga);
} else {
error = TGAERR_OPEN;
}
return (error);
}
/****************************************************************************
*
* NAME
* XFlipTarga - X flip the image.
*
* SYNOPSIS
* XFlipTarga(TGAHeader, Image)
*
* void XFlipTarga(TGAHeader *, char *);
*
* FUNCTION
* Flip the image in memory on its X axis. (left to right)
*
* INPUTS
* TGAHeader - Pointer to initialized TGAHeader structure.
* Image - Pointer to image buffer.
*
* RESULT
* NONE
*
****************************************************************************/
void XFlipTarga(TGAHeader *tga, char *image)
{
char *ptr,*ptr1;
long x,y,d;
char v,v1;
char depth;
/* Pixel depth in bytes. */
depth = (tga->PixelDepth >> 3);
for (y = 0; y < tga->Height; y++) {
ptr = (image + ((tga->Width * depth) * y));
ptr1 = (ptr + ((tga->Width * depth) - depth));
for (x = 0; x < (tga->Width / 2); x++) {
for (d = 0; d < depth; d++) {
v = *(ptr + d);
v1 = *(ptr1 + d);
*(ptr + d) = v1;
*(ptr1 + d) = v;
}
ptr += depth;
ptr1 -= depth;
}
}
}
/****************************************************************************
*
* NAME
* YFlipTarga - Y flip the image.
*
* SYNOPSIS
* YFlipTarga(TGAHeader, Image)
*
* void YFlipTarga(TGAHeader *, char *);
*
* FUNCTION
* Flip the image in memory on its Y axis. (top to bottom)
*
* INPUTS
* TGAHeader - Pointer to initialized TGAHeader structure.
* Image - Pointer to image buffer.
*
* RESULT
* NONE
*
****************************************************************************/
void YFlipTarga(TGAHeader *tga, char *image)
{
char *ptr,*ptr1;
long x,y;
char v,v1;
char depth;
/* Pixel depth in bytes. */
depth = (tga->PixelDepth >> 3);
for (y = 0; y < (tga->Height >> 1); y++) {
/* Compute address of lines to exchange. */
ptr = (image + ((tga->Width * y) * depth));
ptr1 = (image + ((tga->Width * (tga->Height - 1)) * depth));
ptr1 -= ((tga->Width * y) * depth);
/* Exchange all the pixels on this scan line. */
for (x = 0; x < (tga->Width * depth); x++) {
v = *ptr;
v1 = *ptr1;
*ptr = v1;
*ptr1 = v;
ptr++;
ptr1++;
}
}
}
/****************************************************************************
*
* NAME
* DecodeImageData - Decompress Targa image data.
*
* SYNOPSIS
* Error = DecodeImageData(TGAHandle, ImageBuffer)
*
* long DecodeImageData(TGAHandle *, char *);
*
* FUNCTION
* Decode the RLE compressed image data into the specified buffer from
* the file I/O stream.
*
* INPUTS
* TGAHandle - Pointer to TGAHandle returned by OpenTarga().
* ImageBuffer - Pointer to buffer to decompress image into.
*
* RESULT
* Error - 0 if successful, or TGAERR_??? error code.
*
****************************************************************************/
static long DecodeImageData(TGAHandle *tga, char *image)
{
char *packet;
unsigned char count;
unsigned char depth;
unsigned long pixel_count;
unsigned long size;
unsigned long c,i;
long error = 0;
/* Compute pixel depth in bytes. */
depth = (tga->header.PixelDepth >> 3);
/* Total number of pixels compressed in this image. */
pixel_count = (tga->header.Width * tga->header.Height);
/* Allocate packet buffer to hold maximum encoded data run. */
if ((packet = (char *)malloc(128 * depth)) != NULL) {
while ((pixel_count > 0) && !error) {
/* Read count. */
if (read(tga->fh, &count, 1) == 1) {
/* If bit 8 of the count is set then we have a run of pixels,
* otherwise the data is raw pixels.
*/
if (count & 0x80) {
count &= 0x7F;
count++;
/* Read in run pixel. */
if (read(tga->fh, packet, depth) == depth) {
/* Repeat the pixel for the run count in the image buffer. */
for (c = 0; c < count; c++) {
for (i = 0; i < depth; i++) {
*image++ = *(packet + i);
}
}
} else {
error = TGAERR_READ;
}
} else {
count++;
size = (count * depth);
/* Read in raw pixels. */
if (read(tga->fh, packet, size) == size) {
/* Copy the raw pixel data into the image buffer. */
memcpy(image, packet, size);
image += size;
} else {
error = TGAERR_READ;
}
}
/* Adjust the pixel count. */
pixel_count -= count;
} else {
error = TGAERR_READ;
}
}
/* Free packet buffer. */
free(packet);
} else {
error = TGAERR_NOMEM;
}
return (error);
}
/****************************************************************************
*
* NAME
* InvertImageData - Invert TrueColor image data.
*
* SYNOPSIS
* InvertImageData(TGAHeader, ImageData)
*
* void InvertImageData(TGAHeader *, char *);
*
* FUNCTION
*
* INPUTS
* TGAHeader - Pointer to initialized TGAHeader structure.
* ImageData - Pointer to TrueColor image data.
*
* RESULT
* NONE
*
****************************************************************************/
static void InvertImageData(TGAHeader *tga, char *image)
{
long depth;
long pixel_count;
long i;
char c;
/* Compute the pixel depth in bytes. */
depth = (tga->PixelDepth >> 3);
/* Total number of pixels in this image. */
pixel_count = (tga->Width * tga->Height);
/* 16-bit pixel layout is different that 24-bit and 32-bit. */
if (depth > 2) {
while (pixel_count > 0) {
for (i = 0; i < (depth / 2); i++) {
c = *(image + i);
*(image + i) = *(image + ((depth - 1) - i));
*(image + ((depth - 1) - i)) = c;
}
/* Next pixel */
pixel_count--;
image += depth;
}
} else {
}
}

130
VQ/VQM32/TARGA.H Normal file
View File

@@ -0,0 +1,130 @@
/*
** 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/>.
*/
#ifndef VQMTARGA_H
#define VQMTARGA_H
/****************************************************************************
*
* C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* Targa.h (32-Bit protected mode)
*
* DESCRIPTION
* Targa Image File definitions.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* January 26, 1995
*
****************************************************************************/
/*---------------------------------------------------------------------------
* Targa Header definitions
*-------------------------------------------------------------------------*/
/* TGAHeader - Targa Image File header.
*
* IDLength - Size of Image ID field
* ColorMapType - Color map type.
* ImageType - Image type code.
* CMapStart - Color map origin.
* CMapLength - Color map length.
* CMapDepth - Depth of color map entries.
* XOffset - X origin of image.
* YOffset - Y origin of image.
* Width - Width of image.
* Height - Height of image.
* PixelDepth - Image pixel size
* ImageDescriptor - Image descriptor byte.
*/
typedef struct _TGAHeader {
char IDLength;
char ColorMapType;
char ImageType;
short CMapStart;
short CMapLength;
char CMapDepth;
short XOffset;
short YOffset;
short Width;
short Height;
char PixelDepth;
char ImageDescriptor;
} TGAHeader;
/* ImageType definiton */
#define TGA_NOIMAGE 0 /* No image data included in file */
#define TGA_CMAPPED 1 /* Color-mapped image data */
#define TGA_TRUECOLOR 2 /* Truecolor image data */
#define TGA_MONO 3 /* Monochrome image data */
#define TGA_CMAPPED_ENCODED 9 /* Color-mapped image data (Encoded) */
#define TGA_TRUECOLOR_ENCODED 10 /* Truecolor image data (Encoded) */
#define TGA_MONO_ENCODED 11 /* Monochrome image data (Encoded) */
/* ImageDescriptor definition */
#define TGAF_ATTRIB_BITS (0x0F<<0) /* Number of attribute bits per pixel */
#define TGAF_XORIGIN (1<<4)
#define TGAF_YORIGIN (1<<5)
/*---------------------------------------------------------------------------
* Targa Handle definitions
*-------------------------------------------------------------------------*/
/* TGAHandle - Targa Image File handle.
*
* fh - File handle returned by open().
* mode - Access mode.
* header - TGAHeader structure.
*/
typedef struct _TGAHandle {
short fh;
unsigned short mode;
TGAHeader header;
} TGAHandle;
/* Access modes. */
#define TGA_READMODE 0
#define TGA_WRITEMODE 1
#define TGA_RDWRMODE 2
/* Error codes */
#define TGAERR_OPEN -1
#define TGAERR_READ -2
#define TGAERR_WRITE -3
#define TGAERR_SYNTAX -4
#define TGAERR_NOMEM -5
#define TGAERR_NOTSUPPORTED -6
/*---------------------------------------------------------------------------
* Function prototypes
*-------------------------------------------------------------------------*/
TGAHandle *OpenTarga(char *, unsigned short);
void CloseTarga(TGAHandle *);
long LoadTarga(char *, char *, char *);
long SaveTarga(char *, TGAHeader *, char *, char *);
void XFlipTarga(TGAHeader *, char *);
void YFlipTarga(TGAHeader *, char *);
#endif /* VQMTARGA_H */

10
VQ/VQM32/TASM32.CFG Normal file
View File

@@ -0,0 +1,10 @@
/t
/m
/w+
/jJUMPS
/ml
/p
/z
/iC:\PROJECTS\INCLUDE
/zi
/dPHARLAP_TNT=1

104
VQ/VQM32/TESTVB.CPP Normal file
View File

@@ -0,0 +1,104 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* testvb.c
*
* DESCRIPTION
* Video mode setting. (32-Bit protected mode)
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* Febuary 3, 1995
*
*----------------------------------------------------------------------------
*
* PUBLIC
* TestVBIBit - Test the polarity of the vertical blank bit.
*
****************************************************************************/
#include <sys\timeb.h>
#ifdef __BORLANDC__
#include "portio.h"
#else
#include <conio.h>
#endif
/****************************************************************************
*
* NAME
* TestVBIBit - Test the polarity of the vertical blank bit.
*
* SYNOPSIS
* Polarity = TestVBIBit()
*
* long TestVBIBit(void);
*
* FUNCTION
*
* INPUTS
* NONE
*
* RESULT
* Polarity - Polarity of the vertical blank bit.
*
****************************************************************************/
long TestVBIBit(void)
{
static struct timeb mytime;
long curtime;
long endtime;
unsigned long high = 0;
unsigned long low = 0;
/* Set the check time for .25 (1/4) of a second. */
ftime(&mytime);
curtime = ((mytime.time * 1000) + mytime.millitm);
endtime = (curtime + (1000 / 4));
/* Sample the vertical blank bit for the specified period of time.
* The state in which it is in the least is the vertical blank state,
* the state in which it is in the most is the active scan state.
*/
while (endtime >= curtime) {
ftime(&mytime);
curtime = ((mytime.time * 1000) + mytime.millitm);
if (inp(0x3DA) & 0x08) {
high++;
} else {
low++;
}
}
return (high > low);
}

56
VQ/VQM32/TEXT.H Normal file
View File

@@ -0,0 +1,56 @@
/*
** 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/>.
*/
#ifndef VQMTEXT_H
#define VQMTEXT_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* text.h
*
* DESCRIPTION
* Text printing definitions. (32-Bit protected mode)
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* March 13, 1995
*
****************************************************************************/
/* Prototypes */
#ifdef __cplusplus
extern "C" {
#endif
long cdecl Text_Print(char *string, long x, long y, long fcol, long bcol);
void cdecl Draw_Char(long character, long x, long y);
void cdecl Set_Font_Palette_Range(void *palette, long start, long end);
#ifdef __cplusplus
}
#endif
#endif /* VQMTEXT_H */

178
VQ/VQM32/TEXTPRNT.ASM Normal file
View File

@@ -0,0 +1,178 @@
;
; 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: J:\vq\projects\vqm32\textprnt.asv 1.5 27 Jul 1995 13:57:04 DENZIL_LONG $
;***************************************************************************
;** 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 : LIBRARY *
;* *
;* File Name : TEXTPRNT.ASM *
;* *
;* Programmer : David R. Dettmer *
;* *
;* Start Date : January 28, 1992 *
;* *
;* Last Update : February 3, 1992 [DRD] *
;* *
;*-------------------------------------------------------------------------*
;* Functions: *
;* *
; VOID Text_Print(BYTE *string, WORD x_pixel, WORD y_pixel, *
; WORD fcolor, WORD bcolor); *
;* *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
CODESEG
XPIXEL_MAX EQU 320
YPIXEL_MAX EQU 200
FONTINFOBLOCK EQU 4
FONTOFFSETBLOCK EQU 6
FONTWIDTHBLOCK EQU 8
FONTDATABLOCK EQU 10
FONTHEIGHTBLOCK EQU 12
FONTINFOMAXHEIGHT EQU 4
FONTINFOMAXWIDTH EQU 5
EXTRN C Char_Pixel_Width:NEAR
EXTRN C Draw_Char:NEAR
EXTRN C Set_Font_Palette_Range:NEAR
EXTRN FontPtr:NEAR PTR
EXTRN FontYSpacing:DWORD
;----------------------------------------------------------------------------
; TEXT_PRINT
;
; VOID Text_Print(BYTE *string, WORD x_pixel, WORD y_pixel,
; WORD fcolor, WORD bcolor);
;
; Print the given string to the LogicPage.
;
; Bounds Checking:
;
; if x_pixel < 0, then x_pixel = 0
; if x_pixel >= XPIXEL_MAX, then exit
; if y_pixel < 0, then y_pixel = 0
; if y_pixel >= YPIXEL_MAX, then exit
;*
GLOBAL C Text_Print:NEAR
PROC Text_Print C NEAR USES ebx ecx edx edi esi
ARG string:NEAR PTR
ARG x_pixel:DWORD
ARG y_pixel:DWORD
ARG fcol:DWORD
ARG bcol:DWORD
LOCAL fwidth:DWORD ;Pixel width of font.
LOCAL fgbg:DWORD ;Two bytes of background & foreground colors.
LOCAL lines:DWORD ;Number of lines
LOCAL fontheight:DWORD
; Make sure there is a font available. If not, then bail.
xor eax,eax
mov [lines],eax
mov eax,[FontPtr]
or eax,eax
je ??exit
movzx ebx,[WORD PTR eax+FONTINFOBLOCK]
add ebx,eax
movzx eax,[BYTE PTR ebx+FONTINFOMAXHEIGHT]
mov [fontheight],eax
mov esi,[string]
mov ebx,[x_pixel] ; x pixel
cmp ebx,XPIXEL_MAX ; check max x pos
jae short ??exit
mov ecx,[y_pixel] ; y pixel
cmp ecx,YPIXEL_MAX ; check max y pos
jge short ??exit
mov al,[BYTE PTR bcol]
mov ah,[BYTE PTR fcol]
mov [fgbg],eax
lea eax,[fgbg]
call Set_Font_Palette_Range C,eax,0,1
; start of loop to print string
xor edx,edx
inc [lines]
??loop:
mov dl,[esi]
inc esi
cmp edx,0 ; end of string
je short ??exit
cmp edx,13 ; cmp to a '\r'
jne short ??chkxy
; Advance the screen to the left edge and down one line. Check
; to see if the coordinate would still be visible. If not, then
; bail.
??onelinedown:
mov ebx,[x_pixel] ; get original x position
add ecx,[fontheight]
add ecx,[FontYSpacing]
cmp ecx,YPIXEL_MAX ; check y pos
jae short ??exit
inc [lines]
jmp ??loop
??chkxy:
call Char_Pixel_Width C,edx
; Check to see if this character would spill past the right edge
; of the screen. If it would then drop down a line.
mov [fwidth],eax ; save width of char for later
add eax,ebx
cmp eax,XPIXEL_MAX ; check x pos
ja short ??onelinedown
call Draw_Char C,edx,ebx,ecx
add ebx,[fwidth] ; add font width
jmp ??loop
; Exit routine and unlock string if it was in EMS.
??exit:
mov eax,[lines]
ret
ENDP Text_Print
;----------------------------------------------------------------------------
END

1
VQ/VQM32/TLIB.CFG Normal file
View File

@@ -0,0 +1 @@
/C /E

5
VQ/VQM32/TLINK32.CFG Normal file
View File

@@ -0,0 +1,5 @@
/c
/m
/Gm
-LC:\PROJECTS\LIB;C:\DEV\BC4\LIB
-v

137
VQ/VQM32/VB.ASM Normal file
View File

@@ -0,0 +1,137 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* vb.asm
;*
;* DESCRIPTION
;* Vertical blank routines. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Denzil E. Long, Jr.
;*
;* DATE
;* January 26, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* WaitNoVB - Wait for active scan.
;* WaitVB - Wait for vertical blank.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
INCLUDE "video.i"
CODESEG
;****************************************************************************
;*
;* NAME
;* WaitNoVB - Wait for active scan.
;*
;* SYNOPSIS
;* WaitNoVB()
;*
;* void WaitNoVB(void);
;*
;* FUNCTION
;* Sit and wait for the active scan of the display.
;*
;* INPUTS
;* NONE
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C WaitNoVB:NEAR
PROC WaitNoVB C NEAR USES edx
ARG vbibit:DWORD
mov eax,[vbibit]
and al,1
shl al,3
mov ah,al
; loop while VBL bit != VQ_VertBlank
??no_scan_yet:
mov edx,03DAH
in al,dx
and al,8
xor al,ah
jnz short ??no_scan_yet
ret
ENDP WaitNoVB
;****************************************************************************
;*
;* NAME
;* WaitVB - Wait for vertical blank.
;*
;* SYNOPSIS
;* WaitVB()
;*
;* void WaitVB(void);
;*
;* FUNCTION
;* Sit and wait for the vertical blank of the display.
;*
;* INPUTS
;* NONE
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C WaitVB:NEAR
PROC WaitVB C NEAR USES
ARG vbibit:DWORD
mov eax,[vbibit]
and al,1
shl al,3
mov ah,al
; Loop while VBL bit = VQ_VertBlank
??no_vbl_yet:
mov edx,03DAH
in al,dx
and al,8
xor al,ah
jz short ??no_vbl_yet
ret
ENDP WaitVB
END

49
VQ/VQM32/VERTAG.CPP Normal file
View File

@@ -0,0 +1,49 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* PROJECT
* VQMisc32 library.
*
* FILE
* vertag.c (32-Bit protected mode)
*
* DESCRIPTION
* Embedded version string. This string is prefixed with a tag ("$VER$")
* which can be search for to find this string.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* Febuary 8, 1995
*
****************************************************************************/
#ifdef __WATCOMC__
#define DEVNAME "Watcom/4GW"
#else
#define DEVNAME "Borland/TNT"
#endif
char VerTag[] = {"$VER$VQM32 2.12 "DEVNAME" ("__DATE__" "__TIME__")"};

135
VQ/VQM32/VESABLIT.CPP Normal file
View File

@@ -0,0 +1,135 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* vesablit.c
*
* DESCRIPTION
* VESA bitblit routines. (32-Bit protected mode)
*
* PROGRAMMER
* Bill Randolph
* Denzil E. Long, Jr.
*
* DATE
* January 26, 1995
*
*----------------------------------------------------------------------------
*
* PUBLIC
* VESA_Blit_640x480 - Blit to 640x480 256 color VESA mode.
*
****************************************************************************/
#include <stdio.h>
#include <mem.h>
#include <dos.h>
#include "video.h"
#include "vesavid.h"
#include "vesablit.h"
/****************************************************************************
*
* NAME
* VESA_Blit_640x480 - Blit to 640x480 256 color VESA mode.
*
* SYNOPSIS
* VESA_Blit_640x480(DisplayInfo, Buffer, X, Y, Width, Height)
*
* void VESA_Blit_640x480(DisplayInfo *, char *, long, long, long, long);
*
* FUNCTION
*
* INPUTS
* DisplayInfo - Pointer to display information structure.
* Buffer - Pointer to buffer to blit to VRAM.
* X - Destination X coordinate of blit (upper left).
* Y - Destination Y coordinate of blit (upper left).
* Width - Width of blit.
* Height - Height of blit.
*
* RESULT
* NONE
*
****************************************************************************/
void VESA_Blit_640x480(DisplayInfo *disp,unsigned char *buf,long x1,long y1,
long width,long height)
{
VESAModeInfo *vminfo;
long bank;
long last_bank;
long bank_offset;
long scrn_offset;
long grains_per_win;
long part1;
long part2;
long i;
/* Initialize values */
vminfo = (VESAModeInfo *)disp->Extended;
scrn_offset = ((disp->XRes * y1) + x1);
grains_per_win = ((long)vminfo->WinSize / (long)vminfo->WinGranularity);
bank_offset = scrn_offset % 65536L;
last_bank = -1;
for (i = 0; i < height; i++) {
/* Compute which bank this scanline is in */
bank = (scrn_offset / 65536L);
/* Set a new bank */
if (bank != last_bank) {
SetVESAWindow(bank);
last_bank = bank;
bank_offset = (scrn_offset % 65536L);
}
/* Copy a full scanline */
if ((bank_offset + width) < 65536L) {
Copy_Row((char *)buf, (char *)bank_offset, width);
buf += width;
scrn_offset += disp->XRes;
bank_offset += disp->XRes;
}
/* Copy two partial scanlines */
else {
part1 = (65536L - bank_offset);
part2 = (width - part1);
Copy_Row((char *)buf, (char *)bank_offset, part1);
buf += part1;
bank += grains_per_win;
last_bank += grains_per_win;
SetVESAWindow(bank);
Copy_Row((char *)buf, (char *)0, part2);
buf += part2;
scrn_offset += disp->XRes;
bank_offset = (scrn_offset % 65536L);
}
}
}

71
VQ/VQM32/VESABLIT.H Normal file
View File

@@ -0,0 +1,71 @@
/*
** 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/>.
*/
#ifndef VQMVESABLIT_H
#define VQMVESABLIT_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* VESABlit.h (32-Bit protected mode)
*
* DESCRIPTION
* VESA bitblit routines.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* Febuary 3, 1995
*
****************************************************************************/
#include <vqm32\video.h>
/*---------------------------------------------------------------------------
* FUNCTION PROTOTYPES
*-------------------------------------------------------------------------*/
void VESA_Blit_640x480(DisplayInfo *disp,unsigned char *buf,long x1,
long y1,long width,long height);
#ifdef __cplusplus
extern "C" {
#endif
void cdecl Blit_VESA640x480(DisplayInfo *disp,unsigned char *buf,long x1,
long y1,long width,long height);
void cdecl Buf_320x200_To_VESA_320x200(unsigned char *buffer, long grain);
void cdecl Buf_320x200_To_VESA_640x400(unsigned char *buffer, long grain);
void cdecl Buf_320x200_To_VESA_32K(unsigned char *buffer,
unsigned char *palette, long grain);
void cdecl Copy_Row(char *, char *, long);
void cdecl Copy_Word_Row(char *source, char *dest, char *palette,
long numbytes);
#ifdef __cplusplus
}
#endif
#endif /* VQMVESABLIT_H */

722
VQ/VQM32/VESABUF.ASM Normal file
View File

@@ -0,0 +1,722 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* vesabuf.asm
;*
;* DESCRIPTION
;* VESA buffered blit routines. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Bill Randolph
;* Denzil E. Long, Jr.
;*
;* DATE
;* Febuary 3, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* Buf_320x200_To_VESA_320x200 - Buffer copy, unscaled
;* Buf_320x200_To_VESA_640x400 - Scales and copies 320x200 to 640x400
;* Buf_320x200_To_VESA_32K - Copies 320x200 buffer to VESA 32K
;* colors
;* Copy_Row - Copy a row of pixels to VRAM.
;* Copy_Word_Row - Copy a row of 15-bit pixels to VRAM
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
INCLUDE "video.i"
CODESEG
;---------------------------------------------------------------------------
; DRAW_BLOCK_ROWS: draws 'numrows' rows of 2x2 blocks
; Set ES:DI to current screen location
; Set DS:SI to current source location
; Uses: ax, cx, dx
;---------------------------------------------------------------------------
MACRO DRAW_BLOCK_ROWS numrows
LOCAL ??Start_row
LOCAL ??Not_finished_a_line
LOCAL ??Done
mov edx,numrows
??Start_row:
mov ecx,320
??Not_finished_a_line:
mov al,[BYTE PTR esi]
mov ah,al
inc esi
IF PHARLAP_TNT
mov [WORD PTR es:edi],ax
mov [WORD PTR es:edi+640],ax
ELSE
mov [WORD PTR edi],ax
mov [WORD PTR edi+640],ax
ENDIF
add edi,2
dec ecx
jnz ??Not_finished_a_line
add edi,640
dec edx
jz ??Done
jmp ??Start_row
??Done:
ENDM
;---------------------------------------------------------------------------
; DRAW_BLOCK_ROW: draws one row of 'numblks' 2x2 blocks
; Set ES:DI to current screen location
; Set DS:SI to current source location
; Uses: ax, cx
;---------------------------------------------------------------------------
MACRO DRAW_BLOCK_ROW numblks
LOCAL ??Not_done
mov ecx,numblks
??Not_done:
mov al,[BYTE PTR esi]
mov ah,al
inc esi
IF PHARLAP_TNT
mov [WORD PTR es:edi],ax
mov [WORD PTR es:edi+640],ax
ELSE
mov [WORD PTR edi],ax
mov [WORD PTR edi+640],ax
ENDIF
add edi,2
dec ecx
jnz ??Not_done
ENDM
;---------------------------------------------------------------------------
; DRAW_PIXEL_ROW: draws 'numblks' 2x1 blocks
; Set ES:DI to current screen location
; Set DS:SI to current source location
; Uses: ax, cx
;---------------------------------------------------------------------------
MACRO DRAW_PIXEL_ROW numblks
LOCAL ??Not_done
mov ecx,numblks
??Not_done:
mov al,[BYTE PTR esi]
mov ah,al
inc esi
IF PHARLAP_TNT
mov [WORD PTR es:edi],ax
ELSE
mov [WORD PTR edi],ax
ENDIF
add edi,2
dec ecx
jnz ??Not_done
ENDM
;****************************************************************************
;*
;* NAME
;* Blit_VESA640x480 - Blit to 640x480 256 color VESA mode.
;*
;* SYNOPSIS
;* Blit_VESA640x480(DisplayInfo, Buffer, X, Y, Width, Height)
;*
;* void Blit_VESA640x480(DisplayInfo *, char *, long, long, long, long);
;*
;* FUNCTION
;*
;* INPUTS
;* DisplayInfo - Pointer to display information structure.
;* Buffer - Pointer to buffer to blit to VRAM.
;* X - Destination X coordinate of blit (upper left).
;* Y - Destination Y coordinate of blit (upper left).
;* Width - Width of blit.
;* Height - Height of blit.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
; GLOBAL C Blit_VESA640x480:NEAR
; PROC Blit_VESA640x480 C NEAR USES
;
; ARG disp:NEAR PTR DisplayInfo
; ARG buffer:NEAR PTR
; ARG x:DWORD
; ARG y:DWORD
; ARG width:DWORD
; ARG height:DWORD
;
; LOCAL grain:DWORD
; LOCAL scrn_offset:DWORD
; LOCAL bank_offset:DWORD
; LOCAL bank:DWORD
; LOCAL xres:DWORD
;
;;----------------------------------------------------------------------------
;; INITIALIZE
;;----------------------------------------------------------------------------
;
; pushad
;
;; Calculate granularity units per window
;
; mov esi,[disp]
; xor eax,eax
; mov edi,[(DisplayInfo esi).Extended]
; xor ebx,ebx
; mov ax,[(VESAModeInfo edi).WinSize]
; xor edx,edx
; mov bx,[(VESAModeInfo edi).WinGranularity]
; idiv ebx
; mov [grain],eax
;
;; Calculate screen offset
;
; mov eax,[(DisplayInfo esi).XRes]
; mov [xres],eax
; imul [y]
; add eax,[x]
; mov [scrn_offset],eax
;
;; Calculate bank offset
;
; mov ebx,65536
; idiv ebx
; mov [bank_offset],edx
; mov [bank],eax
;
; popad
; ret
;
; ENDP Blit_VESA640x480
;****************************************************************************
;*
;* NAME
;* Buf_320x200_To_VESA_320x200 - Buffer copy, unscaled
;*
;* SYNOPSIS
;* Buf_320x200_To_VESA_320x200(Buffer, GrainPerWin)
;*
;* void Buf_320x200_To_VESA_320x200(char *, long);
;*
;* FUNCTION
;* To center the buffer on the screen, it's upper-left corner goes at
;* (160,140). This means the buffer spans VESA banks 1,2 & 3, so it must
;* be copied in 3 parts:
;*
;* Bank 1: starting offset 24224, 65 lines
;* Bank 2: starting offset 288, 102 lines
;* Bank 3: starting offset 32, 33 lines
;*
;* INPUTS
;* Buffer - Pointer to buffer to transfer to VRAM
;* GrainPerWin - Granularity units per 64k window.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Buf_320x200_To_VESA_320x200:NEAR
PROC Buf_320x200_To_VESA_320x200 C NEAR USES ebx ecx edx esi edi
ARG buffer:NEAR PTR
ARG grains_per_win:DWORD
LOCAL grain_num:DWORD
;----------------------------------------------------------------------------
; Initialize
;----------------------------------------------------------------------------
IF PHARLAP_TNT
push es
mov eax,01Ch ;Set ES selector to VRAM
mov es,ax
ENDIF
mov eax,[grains_per_win]
mov esi,[buffer]
mov [grain_num],eax
;----------------------------------------------------------------------------
; Copy Bank 1
;----------------------------------------------------------------------------
SET_WINDOW [grain_num]
mov edi,24224 ;Starting screen address
mov edx,65 ;Lines to copy
??SetBank1:
mov ecx,80 ;DWORDS to copy
rep movsd ;Move the pixels
add edi,320 ;Wrap to start of next line
dec edx ;Decrement our line counter
jnz ??SetBank1 ;Draw more lines
;----------------------------------------------------------------------------
; Copy Bank 2
;----------------------------------------------------------------------------
mov eax,[grains_per_win]
add [grain_num],eax
SET_WINDOW [grain_num]
mov edi,288 ;Starting screen address
mov edx,102 ;Lines to copy
??SetBank2:
mov ecx,80 ;DWORDS to copy
rep movsd ;Move the pixels
add edi,320 ;Wrap to start of next line
dec edx ;Decrement our line counter
jnz ??SetBank2 ;Draw more lines
;----------------------------------------------------------------------------
; Copy Bank 3
;----------------------------------------------------------------------------
mov eax,[grains_per_win]
add [grain_num],eax
SET_WINDOW [grain_num]
mov edi,32 ;Starting screen address
mov edx,33 ;Lines to copy
??SetBank3:
mov ecx,80 ;DWORDS to copy
rep movsd ;Move the pixels
add edi,320 ;Wrap to start of next line
dec edx ;Decrement our line counter
jnz ??SetBank3 ;Draw more lines
IF PHARLAP_TNT
pop es
ENDIF
ret
ENDP Buf_320x200_To_VESA_320x200
;****************************************************************************
;*
;* NAME
;* Buf_320x200_To_VESA_640x400 - Scales and copies 320x200 to 640x400
;*
;* SYNOPSIS
;* Buf_320x200_To_VESA_640x400(Buffer, GrainPerWin)
;*
;* void Buf_320x200_To_VESA_640x400(char *, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Buffer - Pointer to buffer to transfer to VRAM
;* GrainPerWin - Granularity units per 64k window.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Buf_320x200_To_VESA_640x400:NEAR
PROC Buf_320x200_To_VESA_640x400 C NEAR USES ebx ecx edx esi edi
ARG buffer:NEAR PTR
ARG grains_per_win:DWORD
LOCAL grain_num:DWORD
;----------------------------------------------------------------------------
; Initialize
;----------------------------------------------------------------------------
IF PHARLAP_TNT
push es
mov eax,01Ch ;Set ES selector to VRAM
mov es,ax
ENDIF
mov esi,[buffer]
mov [grain_num],0
;----------------------------------------------------------------------------
; Copy Bank 0
; - Skip down 40 scanlines (to center the image)
; - Draw 62 scanlines (31 rows of blocks)
; - Draw top half of 128 blocks
;----------------------------------------------------------------------------
SET_WINDOW [grain_num]
mov edi,25600 ;Starting screen address
DRAW_BLOCK_ROWS 62/2 ;Draw 31 rows of blocks
DRAW_PIXEL_ROW 256/2 ;Draw top half of next 128 blocks
;----------------------------------------------------------------------------
; Copy Bank 1
; - Draw bottom half of previous 128 blocks
; - Finish the scan line with full blocks
; - Draw 100 scanlines of blocks
; - last line: top half of 256 blocks
;----------------------------------------------------------------------------
mov eax,[grains_per_win]
add [grain_num],eax
SET_WINDOW [grain_num]
sub esi,256/2 ;Draw bottom half of prev 128 blks
mov edi,384
DRAW_PIXEL_ROW 256/2
mov edi,0
DRAW_BLOCK_ROW 384/2 ;Fill rest of this block row
add edi,640
DRAW_BLOCK_ROWS 100/2 ;Draw the block rows
DRAW_PIXEL_ROW 512/2 ;Draw top half of next 512 blocks
;----------------------------------------------------------------------------
; Copy Bank 2
; - Draw bottom half of previous 256 blocks
; - Finish the scan line with full blocks
; - Draw 101 scanlines of blocks
; - last line: 64 full blocks plus top half of 256 blocks
;----------------------------------------------------------------------------
mov eax,[grains_per_win]
add [grain_num],eax
SET_WINDOW [grain_num]
sub esi,512/2 ;Draw bottom half of prev 256 blks
mov edi,128
DRAW_PIXEL_ROW 512/2
mov edi,0
DRAW_BLOCK_ROW 128/2 ;Fill rest of this block row
add edi,640
DRAW_BLOCK_ROWS 101/2 ;Draw the block rows
DRAW_BLOCK_ROW 128/2 ;Draw next 64 blocks
DRAW_PIXEL_ROW 512/2 ;Top half of 256 blocks
;----------------------------------------------------------------------------
; Copy Bank 3
; - Draw bottom half of previous 256 blocks
; - Finish the scan line with full blocks
; - Draw 101 scanlines of blocks
; - last line: 192 full blocks, top half of 128 blocks
;----------------------------------------------------------------------------
mov eax,[grains_per_win]
add [grain_num],eax
SET_WINDOW [grain_num]
sub esi,512/2 ;Draw bottom half of prev 256 blks
mov edi,0
DRAW_PIXEL_ROW 512/2
DRAW_BLOCK_ROWS 101/2 ;Draw the block rows
DRAW_BLOCK_ROW 384/2 ;Last row of full blocks
DRAW_PIXEL_ROW 256/2 ;Top half of 128 blocks
;----------------------------------------------------------------------------
; Copy Bank 4
; - Draw bottom half of previous 128 blocks
; - Draw 30 scanlines of blocks
;----------------------------------------------------------------------------
mov eax,[grains_per_win]
add [grain_num],eax
SET_WINDOW [grain_num]
sub esi,256/2 ;Draw bottom half of prev 256 blks
mov edi,0
DRAW_PIXEL_ROW 256/2
DRAW_BLOCK_ROWS 30/2 ;Draw the block rows
IF PHARLAP_TNT
pop es
ENDIF
ret
ENDP Buf_320x200_To_VESA_640x400
;****************************************************************************
;*
;* NAME
;* Buf_320x200_To_VESA_32K - Copies 320x200 buffer to VESA 32K colors
;*
;* SYNOPSIS
;* Buf_320x200_To_VESA_32K(Buffer, Palette, GrainPerWin)
;*
;* void Buf_320x200_To_VESA_32K(char *, char *, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Buffer - Pointer to buffer to transfer to VRAM
;* Palette - Pointer to 15-bit palette to use.
;* GrainPerWin - Granularity units per 64k window.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Buf_320x200_To_VESA_32K:NEAR
PROC Buf_320x200_To_VESA_32K C NEAR USES ebx ecx edx esi edi
ARG buffer:NEAR PTR
ARG palette:NEAR PTR
ARG grains_per_win:DWORD
;----------------------------------------------------------------------------
; Initialize
;----------------------------------------------------------------------------
IF PHARLAP_TNT
push es
mov eax,01Ch ;Set ES selector to VRAM
mov es,ax
ENDIF
mov esi,[buffer]
;----------------------------------------------------------------------------
; Copy Bank 0
;----------------------------------------------------------------------------
SET_WINDOW 0
mov edi,0 ;Start at Bank 0, offset 0
mov ecx,32768 ;# words we'll be setting
; Get the pixel's offset into the palette
??Buf0Loop:
xor eax,eax
mov ebx,[palette]
mov al,[BYTE PTR esi]
add ebx,eax
inc esi
add ebx,eax
; store the 15-bit palette value
mov ax,[WORD PTR ebx]
IF PHARLAP_TNT
mov [WORD PTR es:edi],ax
ELSE
mov [WORD PTR edi],ax
ENDIF
add edi,2
dec ecx
jnz ??Buf0Loop
;----------------------------------------------------------------------------
; Copy Bank 1
;----------------------------------------------------------------------------
SET_WINDOW [grains_per_win]
mov edi,0 ;Start at Bank 1, offset 0
mov ecx,31232 ;# words we'll be setting
; Get the pixel's offset into the palette
??Buf1Loop:
xor eax,eax
mov ebx,[palette]
mov al,[BYTE PTR esi]
add ebx,eax
inc esi
add ebx,eax
; Store the 15-bit palette value
mov ax,[WORD PTR ebx]
IF PHARLAP_TNT
mov [WORD PTR es:edi],ax
ELSE
mov [WORD PTR edi],ax
ENDIF
add edi,2
dec ecx
jnz ??Buf1Loop
IF PHARLAP_TNT
pop es
ENDIF
ret
ENDP Buf_320x200_To_VESA_32K
;****************************************************************************
;*
;* NAME
;* Copy_Row - Copy a row of pixels to VRAM.
;*
;* SYNOPSIS
;* Copy_Row(Source, Dest, Length)
;*
;* void Copy_Row(char *, char *, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Source - Pointer to data to copy to VRAM
;* Dest - Destination VRAM address.
;* Length - Number of bytes to copy.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Copy_Row:NEAR
PROC Copy_Row C NEAR USES ecx esi edi
ARG source:NEAR PTR
ARG dest:NEAR PTR
ARG numbytes:DWORD
IF PHARLAP_TNT
push es
mov eax,01Ch
mov es,ax
ENDIF
cld
mov esi,[source]
mov edi,[dest]
mov ecx,[numbytes]
rep movsb
IF PHARLAP_TNT
pop es
ENDIF
ret
ENDP Copy_Row
;****************************************************************************
;*
;* NAME
;* Copy_Word_Row - Copy a row of 15-bit pixels to VRAM
;*
;* SYNOPSIS
;* Copy_Word_Row(Source, Dest, Palette, Length)
;*
;* void Copy_Word_Row(char *, char *, char *, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Source - Pointer to data to transfer.
;* Dest - Destination screen address.
;* Palette - 15bit palette to use.
;* Length - Bytes to transfer.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Copy_Word_Row:NEAR
PROC Copy_Word_Row C NEAR USES ebx ecx esi edi
ARG source:NEAR PTR
ARG dest:NEAR PTR
ARG palette:NEAR PTR
ARG numbytes:DWORD
IF PHARLAP_TNT
push es
mov eax,01Ch
mov es,ax
ENDIF
mov esi,[source]
mov edi,[dest]
mov ecx,[numbytes]
??loop:
mov ebx,[palette]
xor eax,eax
mov al,[esi] ;Get pixel value
shl eax,1 ;Adjust for word entry
add ebx,eax ;Compute color address
mov ax,[ebx] ;Get color
IF PHARLAP_TNT
mov [es:edi],ax ;Set 16bit pixel
ELSE
mov [edi],ax ;Set 16bit pixel
ENDIF
inc esi ;Next source pixel
add edi,2 ;Next dest pixel
dec ecx ;Decrement pixel count
jnz ??loop
IF PHARLAP_TNT
pop es
ENDIF
ret
ENDP Copy_Word_Row
END

457
VQ/VQM32/VESAVID.CPP Normal file
View File

@@ -0,0 +1,457 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* vesavid.c
*
* DESCRIPTION
* VESA video manager. (32-Bit protected mode)
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* January 26, 1995
*
*----------------------------------------------------------------------------
*
* PUBLIC
* InitVESA - Initialize the VESA video manager.
* UninitVESA - Uninitialize the VESA video manager.
* SetVESAMode - Set the display to the specified VESA video mode.
* ReadVESAModeInfo - Read the VESA mode information from the video card.
* SetVESAWindow - Set VESA window A's start address.
*
****************************************************************************/
#include <stdio.h>
#include <mem.h>
#include <dos.h>
#ifndef __WATCOMC__
#include <pldos32.h>
#include <pharlap.h>
#else
#include "realmode.h"
#endif
#include "vesavid.h"
/*---------------------------------------------------------------------------
* PRIVATE DECLARATIONS
*-------------------------------------------------------------------------*/
#ifdef __WATCOMC__
static short _VInfoSel = NULL;
static short _VInfoSeg = NULL;
static short _ModeInfoSel = NULL;
static short _ModeInfoSeg = NULL;
#else /* __WATCOMC__ */
/* _regs - Registers used for calling software interrupts.
* _rpVInfo - Real pointer to VInfo structure in conventional memory.
* _rpModeInfo - Real pointer to ModeInfo structure in conventional memory.
* _VInfo - Protected mode copy of VInfo structure.
* _ModeInfo - Protected mode copy of ModeInfo structure.
*/
static SWI_REGS _regs;
static REALPTR _rpVInfo = NULL;
static REALPTR _rpModeInfo = NULL;
static VESAInfo _VInfo;
static VESAModeInfo _ModeInfo;
#endif /* __WATCOMC__ */
/****************************************************************************
*
* NAME
* InitVESA - Initialize the VESA video manager.
*
* SYNOPSIS
* Error = InitVESA()
*
* long InitVESA(void);
*
* FUNCTION
* Initialize the VESA video system. Get the VESA information from the
* VESA video bios.
*
* INPUTS
* NONE
*
* RESULT
* Error - 0 if successful, or -1 error/VESA not supported.
*
****************************************************************************/
long InitVESA(void)
{
#ifdef __WATCOMC__
union REGS r;
struct SREGS sr;
RMInfo rmi;
long error = -1;
/* Allocate real-mode memory for VESA structure. */
r.x.eax = 0x0100;
r.x.ebx = (sizeof(VESAInfo) + 15) >> 4;
int386(0x31, &r, &r);
if (r.x.cflag == 0) {
_VInfoSel = r.w.dx;
_VInfoSeg = r.w.ax;
/* Allocate real-mode memory for VESAModeInfo structure. */
r.x.eax = 0x0100;
r.x.ebx = (sizeof(VESAModeInfo) + 15) >> 4;
int386(0x31, &r, &r);
if (r.x.cflag == 0) {
_ModeInfoSel = r.w.dx;
_ModeInfoSeg = r.w.ax;
/* Clear VESAInfo structure. */
memset(MK_PTR(0, _VInfoSeg), 0, sizeof(VESAInfo));
/* Get VESA information. */
memset(&rmi, 0, sizeof(RMInfo));
rmi.eax = 0x4F00;
rmi.edi = 0;
rmi.es = _VInfoSeg;
segread(&sr);
r.w.ax = 0x0300;
r.h.bl = 0x10;
r.h.bh = 0;
r.w.cx = 0;
sr.es = FP_SEG(&rmi);
r.x.edi = FP_OFF(&rmi);
int386x(0x31, &r, &r, &sr);
if ((r.x.cflag == 0) && (rmi.eax == 0x004F)) {
error = 0;
}
}
}
if (error != 0) {
UninitVESA();
}
return (error);
#else /* __WATCOMC__ */
unsigned short rseg;
long paras;
long error = -1;
/* Calculate size of VESAInfo structure in paragraphs */
paras = (sizeof(VESAInfo) + 15) >> 4;
/* Allocate real-mode memory for VESA structure. */
if (_dx_real_alloc(paras, (unsigned short *)&rseg,
(unsigned short *)&paras) == 0) {
RP_SET(_rpVInfo, 0, rseg);
/* Calculate size of VESAModeInfo structure in paragraphs */
paras = (sizeof(VESAModeInfo) + 15) >> 4;
/* Allocate real-mode memory for VESAModeInfo structure. */
if (_dx_real_alloc(paras, (unsigned short *)&rseg,
(unsigned short *)&paras) == 0) {
RP_SET(_rpModeInfo, 0, rseg);
/* Clear the input buffer */
FillRealMem(_rpVInfo, 0, sizeof(VESAInfo));
/* Set up function call */
_regs.eax = 0x4F00;
_regs.edi = RP_OFF(_rpVInfo);
_regs.es = RP_SEG(_rpVInfo);
_dx_real_int(0x10, &_regs);
if (_regs.eax == 0x004F) {
ReadRealMem(&_VInfo, _rpVInfo, sizeof(VESAInfo));
error = 0;
}
}
}
if (error != 0) {
UninitVESA();
}
return (error);
#endif /* __WATCOMC__ */
}
/****************************************************************************
*
* NAME
* UninitVESA - Uninitialize the VESA video manager.
*
* SYNOPSIS
* UninitVESA()
*
* void UninitVESA(void);
*
* FUNCTION
*
* INPUTS
* NONE
*
* RESULT
* NONE
*
****************************************************************************/
void UninitVESA(void)
{
#ifdef __WATCOMC__
union REGS r;
/* Free VESAInfo structure */
if (_VInfoSeg != NULL) {
r.x.eax = 0x0101;
r.x.edx = _VInfoSel;
int386(0x31, &r, &r);
_VInfoSeg = NULL;
_VInfoSel = NULL;
}
/* Free VESAModeInfo structure */
if (_ModeInfoSeg != NULL) {
r.x.eax = 0x0101;
r.x.edx = _VInfoSel;
int386(0x31, &r, &r);
_ModeInfoSeg = NULL;
_ModeInfoSel = NULL;
}
#else /* __WATCOMC__ */
/* Free VESAInfo structure */
if (_rpVInfo != NULL) {
_dx_real_free(RP_SEG(_rpVInfo));
_rpVInfo = NULL;
}
/* Free VESAModeInfo structure */
if (_rpModeInfo != NULL) {
_dx_real_free(RP_SEG(_rpModeInfo));
_rpModeInfo = NULL;
}
#endif /* __WATCOMC__ */
}
/****************************************************************************
*
* NAME
* SetVESAMode - Set the display adapter to the given VESA video mode.
*
* SYNOPSIS
* VESAModeInfo = SetVESAMode(Mode)
*
* VESAModeInfo *SetVESAMode(long);
*
* FUNCTION
* Set the display adapter to the specified VESA video mode.
*
* INPUTS
* Mode - VESA video mode to set the display to.
*
* RESULT
* VESAModeInfo - Pointer to VESA mode information structure or NULL if
* error.
*
****************************************************************************/
VESAModeInfo *SetVESAMode(long mode)
{
VESAModeInfo *vminfo;
/* Get mode info */
if ((vminfo = ReadVESAModeInfo(mode)) != NULL) {
/* If the mode is supported, set it. */
if ((vminfo->Attributes & 0x01) != 0) {
#ifdef __WATCOMC__
{
union REGS r;
r.x.eax = 0x4F02;
r.x.ebx = mode;
int386(0x10, &r, &r);
if (r.x.eax != 0x004F)
vminfo = NULL;
}
#else /* __WATCOMC__ */
/* Set up function call */
_regs.eax = 0x4F02;
_regs.ebx = mode;
_dx_real_int(0x10, &_regs);
if (_regs.eax != 0x004F) {
vminfo = NULL;
}
#endif /* __WATCOMC__ */
}
}
return (vminfo);
}
/****************************************************************************
*
* NAME
* ReadVESAModeInfo - Read the VESA mode information from the video card.
*
* SYNOPSIS
* VESAModeInfo = ReadVESAModeInfo(Mode)
*
* VESAModeInfo *ReadVESAModeInfo(long);
*
* FUNCTION
* Read information about the specified mode from the VESA video BIOS.
*
* INPUTS
* Mode - Mode ID to get information about.
*
* RESULT
* VESAModeInfo - Pointer to VESA mode information structure or NULL if
* error.
*
****************************************************************************/
VESAModeInfo *ReadVESAModeInfo(long mode)
{
VESAModeInfo *vminfo = NULL;
#ifdef __WATCOMC__
union REGS r;
struct SREGS sr;
RMInfo rmi;
/* Make sure we have real-mode memory. */
if (_ModeInfoSeg != NULL) {
memset(MK_PTR(0, _ModeInfoSeg), 0, sizeof(VESAModeInfo));
/* Get mode information. */
memset(&rmi, 0, sizeof(RMInfo));
rmi.eax = 0x4F01;
rmi.ecx = mode;
rmi.edi = 0;
rmi.es = _ModeInfoSeg;
segread(&sr);
r.w.ax = 0x0300;
r.w.bx = 0x0010;
r.w.cx = 0;
sr.es = FP_SEG(&rmi);
r.x.edi = FP_OFF(&rmi);
int386x(0x31, &r, &r, &sr);
if ((r.x.cflag == 0) && (rmi.eax == 0x004F)) {
vminfo = (VESAModeInfo *)MK_PTR(0, _ModeInfoSeg);
}
}
#else /* __WATCOMC__ */
/* Make sure we have real-mode memory. */
if (_rpModeInfo != NULL) {
/* Clear the input buffer */
FillRealMem(_rpModeInfo, 0, sizeof(VESAModeInfo));
/* Set up function call */
_regs.eax = 0x4F01;
_regs.ecx = mode;
_regs.edi = RP_OFF(_rpModeInfo);
_regs.es = RP_SEG(_rpModeInfo);
_dx_real_int(0x10, &_regs);
if (_regs.eax == 0x004F) {
ReadRealMem(&_ModeInfo, _rpModeInfo, sizeof(VESAModeInfo));
vminfo = &_ModeInfo;
}
}
#endif /* __WATCOMC__ */
return (vminfo);
}
/****************************************************************************
*
* NAME
* SetVESAWindow - Set VESA window A's start address.
*
* SYNOPSIS
* Error = SetVESAWindow(GrainNum)
*
* long SetVESAWindow(long);
*
* FUNCTION
* This function invokes the Window Function, whose address is provided
* in the VESAModeInfo structure. The 'GrainNum' must be in granularity
* units as specified in the ModeInfo structure.
*
* INPUTS
* GrainNum - Granularity number to set window to.
*
* RESULT
* NONE
*
****************************************************************************/
void SetVESAWindow(long grain)
{
#ifdef __WATCOMC__
#else /* __WATCOMC__ */
RMC_BLK regp;
regp.eax = 0x4F05;
regp.ebx = 0x00;
regp.edx = grain;
_dx_call_real(_ModeInfo.WinFunc, &regp, 0);
#endif /* __WATCOMC__ */
}

182
VQ/VQM32/VESAVID.H Normal file
View File

@@ -0,0 +1,182 @@
/*
** 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/>.
*/
#ifndef VQMVESAVID_H
#define VQMVESAVID_H
/****************************************************************************
*
* C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* VESAVid.h (32-Bit protected mode)
*
* DESCRIPTION
* VESA video manager definitions.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* Febuary 3, 1995
*
****************************************************************************/
#ifndef __WATCOMC__
#include <pharlap.h>
#else
#include "realmode.h"
#endif
/*---------------------------------------------------------------------------
* VESA Video Modes
*-------------------------------------------------------------------------*/
#define VESA_640X400_256 0x100
#define VESA_640X480_256 0x101
#define VESA_800X600_16 0x102
#define VESA_800X600_256 0x103
#define VESA_1024X768_16 0x104
#define VESA_1024X768_256 0x105
#define VESA_1280X400_16 0x106
#define VESA_1280X400_256 0x107
#define VESA_TEXT_80X60 0x108
#define VESA_TEXT_132X25 0x109
#define VESA_TEXT_132X60 0x10C
#define VESA_320X200_32K_1 0x10D
#define VESA_320X200_32K_2 0x10E
#define VESA_640X480_32K 0x110
#define VESA_640X480_65K 0x111
#define VESA_640X480_16M 0x112
#define VESA_800X600_32K 0x113
#define VESA_800X600_65K 0x114
#define VESA_1024X768_32K 0x116
#define VESA_1024X768_65K 0x117
#define VESA_MIN VESA_640X400_256
#define VESA_MAX VESA_1024X768_65K
/*---------------------------------------------------------------------------
* Structure definitions
*-------------------------------------------------------------------------*/
/* VESAInfo - General information about this VESA implementation.
* (Filled in by VESA BIOS Function 0)
*
* Signature - Will always be 'VESA'
* Version - Version #
* OEMString - OEM ID string
* Capabilities - Not defined by VESA yet
* AvailModes - List of available modes; terminated with -1 (0xffff)
* TotalMemory - ???
* Reserved - Pads structure to 256 bytes total
*/
typedef struct _VESAInfo {
char Signature[4];
unsigned short Version;
REALPTR OEMString;
unsigned long Capabilities;
REALPTR AvailModes;
unsigned short TotalMemory;
unsigned char Reserved[236];
} VESAInfo;
/* VESAModeInfo - Information about this VESA mode.
* (Filled in by VESA BIOS Function 1)
*
* Attributes - bit 0: 1 = mode is supported
* bit 1: 1 = optional info available
* bit 2: 1 = std BIOS output functions valid in this mode
* bit 3: 0 = monochrome, 1 = color
* bit 4: 0 = text mode, 1 = graphics
* WinA_Attributes - bit 0 = window exists, bit 1=readable, bit 2= writable
* WinB_Attributes - bit 0 = window exists, bit 1=readable, bit 2= writable
* WinGranularity - smallest address boundary window can be placed upon;
* size is in KB (ie 64, 32, 4)
* WinSize - size of windows in KB (ie 64, 32)
* WinA_Segment - location of Window A in CPU space (usually 0xa000)
* WinB_Segment - location of Window B in CPU space (usually 0xb000)
* WinFunc - address of window-setting function (This is provided
* as an alternative to Int 10 for speed.)
* BytesPerScanline - # bytes per scan line
*
* Optional info (available if bit 1 of Attributes is set):
*
* XRes - X-resolution
* YRes - Y-resolution
* XCharSize - Horizontal size of char cell
* YCharSize - Vertical size of char cell
* NumPlanes - # of memory planes (???)
* BitsPerPixel - # bites per pixel
* NumBanks - # of banks (ie planes)
* MemoryModel - 00h = Text mode
* 01h = CGA mode
* 02h = Hercules
* 03h = 4 plane planar mode
* 04h = packed pixel mode (1 byte/pixel)
* 05h = non-chain 4, 256-color mode
* 06-0Fh =
* 10-FFh = OEM-specific
* BankSize - Bank size in KB
*/
typedef struct _VESAModeInfo {
unsigned short Attributes;
unsigned char WinA_Attributes;
unsigned char WinB_Attributes;
unsigned short WinGranularity;
unsigned short WinSize;
unsigned short WinA_Segment;
unsigned short WinB_Segment;
REALPTR WinFunc;
unsigned short BytesPerScanline;
unsigned short XRes;
unsigned short YRes;
unsigned char XCharSize;
unsigned char YCharSize;
unsigned char NumPlanes;
unsigned char BitsPerPixel;
unsigned char NumBanks;
unsigned char MemoryModel;
unsigned char BankSize;
unsigned char NumInputPages;
unsigned char Reserved;
unsigned char RedMaskSize;
unsigned char RedFieldPosition;
unsigned char GreenMaskSize;
unsigned char GreenFieldPosition;
unsigned char BlueMaskSize;
unsigned char BlueFieldPosition;
unsigned char RsvdMaskSize;
unsigned char RsvdFieldPosition;
unsigned char DirectColorModeInfo;
unsigned char pad[216];
} VESAModeInfo;
/*---------------------------------------------------------------------------
* Function prototypes
*-------------------------------------------------------------------------*/
long InitVESA(void);
void UninitVESA(void);
VESAModeInfo *SetVESAMode(long mode);
VESAModeInfo *ReadVESAModeInfo(long mode);
void SetVESAWindow(long grain_num);
#endif /* VQMVESAVID_H */

203
VQ/VQM32/VESAVID.I Normal file
View File

@@ -0,0 +1,203 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*----------------------------------------------------------------------------
;*
;* FILE
;* vesavid.i
;*
;* DESCRIPTION
;* VESA video manager definitions. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Denzil E. Long, Jr.
;*
;* DATE
;* January 26, 1995
;*
;****************************************************************************
;----------------------------------------------------------------------------
; VESA video modes
;----------------------------------------------------------------------------
VESA_640X400_256 EQU 0x100
VESA_640X480_256 EQU 0x101
VESA_800X600_16 EQU 0x102
VESA_800X600_256 EQU 0x103
VESA_1024X768_16 EQU 0x104
VESA_1024X768_256 EQU 0x105
VESA_1280X400_16 EQU 0x106
VESA_1280X400_256 EQU 0x107
VESA_TEXT_80X60 EQU 0x108
VESA_TEXT_132X25 EQU 0x109
VESA_TEXT_132X60 EQU 0x10C
VESA_320X200_32K_1 EQU 0x10D
VESA_320X200_32K_2 EQU 0x10E
VESA_640X480_32K EQU 0x110
VESA_640X480_65K EQU 0x111
VESA_640X480_16M EQU 0x112
VESA_800X600_32K EQU 0x113
VESA_800X600_65K EQU 0x114
VESA_1024X768_32K EQU 0x116
VESA_1024X768_65K EQU 0x117
VESA_MIN EQU VESA_640X400_256
VESA_MAX EQU VESA_1024X768_65K
;----------------------------------------------------------------------------
; Structure definitions
;----------------------------------------------------------------------------
; VESAInfo - General information about this VESA implementation.
; (Filled in by VESA BIOS Function 0)
;
; Signature - Will always be 'VESA'
; Ver - Version #
; OEMString - OEM ID string
; Capabilities - Not defined by VESA yet
; AvailModes - List of available modes; terminated with -1 (0xffff)
; TotalMemory - ???
; Reserved - Pads structure to 256 bytes total
STRUC VESAInfo
Signature DD ?
Ver DW ?
OEMString DD ?
Capabilities DD ?
AvailModes DD ?
TotalMemory DW ?
Reserved DB 236 DUP (?)
ENDS VESAInfo
; VESAModeInfo - Information about this VESA mode.
; (Filled in by VESA BIOS Function 1)
;
; Attributes - bit 0: 1 = mode is supported
; bit 1: 1 = optional info available
; bit 2: 1 = std BIOS output functions valid in this mode
; bit 3: 0 = monochrome, 1 = color
; bit 4: 0 = text mode, 1 = graphics
; WinA_Attributes - bit 0 = window exists, bit 1=readable, bit 2= writable
; WinB_Attributes - bit 0 = window exists, bit 1=readable, bit 2= writable
; WinGranularity - smallest address boundary window can be placed upon;
; size is in KB (ie 64, 32, 4)
; WinSize - size of windows in KB (ie 64, 32)
; WinA_Segment - location of Window A in CPU space (usually 0xa000)
; WinB_Segment - location of Window B in CPU space (usually 0xb000)
; WinFunc - address of window-setting function (This is provided
; as an alternative to Int 10 for speed.)
; BytesPerScanline - # bytes per scan line
;
; Optional info (available if bit 1 of Attributes is set):
;
; XRes - X-resolution
; YRes - Y-resolution
; XCharSize - Horizontal size of char cell
; YCharSize - Vertical size of char cell
; NumPlanes - # of memory planes (???)
; BitsPerPixel - # bites per pixel
; NumBanks - # of banks (ie planes)
; MemoryModel - 00h = Text mode
; 01h = CGA mode
; 02h = Hercules
; 03h = 4 plane planar mode
; 04h = packed pixel mode (1 byte/pixel)
; 05h = non-chain 4, 256-color mode
; 06-0Fh =
; 10-FFh = OEM-specific
; BankSize - Bank size in KB
STRUC VESAModeInfo
Attributes DW ?
WinA_Attributes DB ?
WinB_Attributes DB ?
WinGranularity DW ?
WinSize DW ?
WinA_Segment DW ?
WinB_Segment DW ?
WinFunc DD ?
BytesPerScanline DW ?
XRes DW ?
YRes DW ?
XCharSize DB ?
YCharSize DB ?
NumPlanes DB ?
BitsPerPixel DB ?
NumBanks DB ?
MemoryModel DB ?
BankSize DB ?
NumInputPages DB ?
Reserved DB ?
RedMaskSize DB ?
RedFieldPosition DB ?
GreenMaskSize DB ?
GreenFieldPosition DB ?
BlueMaskSize DB ?
BlueFieldPosition DB ?
RsvdMaskSize DB ?
RsvdFieldPosition DB ?
DirectColorModeInfo DB ?
pad DB 216 DUP (?)
ENDS VESAModeInfo
;----------------------------------------------------------------------------
; Function definitions
;----------------------------------------------------------------------------
GLOBAL C InitVESA:PROC
GLOBAL C UninitVESA:PROC
GLOBAL C SetVESAMode:PROC
GLOBAL C ReadVESAModeInfo:PROC
GLOBAL C SetVESAWindow:PROC
;----------------------------------------------------------------------------
;
; NAME
; SET_WINDOW - Sets window A to the specified bank.
;
; SYNOPSIS
; SET_WINDOW GrainNum
;
; FUNCTION
; This routine uses the C Set_Window function rather than going through
; the BIOS, for two reasons: (1) Speed, and (2) On the Cirrus Logic 54xx
; VESA cards, BIOS calls make noise while playing digital audio.
;
; INPUTS
; GrainNum - Granularity number.
;
; RESULT
; NONE
;
;----------------------------------------------------------------------------
MACRO SET_WINDOW grain_num
push esi
push edi
push es
call SetVESAWindow C,grain_num
pop es
pop edi
pop esi
ENDM

217
VQ/VQM32/VGA.I Normal file
View File

@@ -0,0 +1,217 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* vga.i
;*
;* DESCRIPTION
;* VGA hardware definitions. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Denzil E. Long, Jr.
;*
;* DATE
;* January 26, 1995
;*
;****************************************************************************
;----------------------------------------------------------------------------
; VGA Registers
;----------------------------------------------------------------------------
R_SEQUENCER EQU 03C4h ;Sequencer Controller Index reg
SEQ_RESET EQU 00h ;Reset
SEQ_MAP_MASK EQU 02h ;Index in Sequencer of Map Mask reg
SEQ_MEMORY_MODE EQU 04h ;Memory Mode
R_GRAPHICS_CONTROLLER EQU 03CEh ;Graphics Controller Index reg
GC_READ_MAP EQU 04h ;Index in GController of Read Map reg
GC_MODE EQU 05h ;Read/Write Modes
GC_MISC EQU 06h ;Read/Write Modes
GC_BITMASK EQU 08h ;Index in GController of BitMask reg
R_CRT_CONTROLLER EQU 03D4h ;CRT Controller Index reg
CRT_VERT_TOTAL EQU 06h ;Vertical total
CRT_OVERFLOW EQU 07h ;Overflow
CRT_MAX_SCANLINE EQU 09h ;Max scan line
CRT_STARTADDR_HIGH EQU 0Ch ;Bitmap start address high byte
CRT_STARTADDR_LOW EQU 0Dh ;Bitmap start address low byte
CRT_VERTRET_START EQU 010h ;Vertical retrace pulse start
CRT_VERTRET_END EQU 011h ;Vertical retrace pulse end
CRT_VERTDISP_END EQU 012h ;Vertical display end
CRT_UNDERLINE EQU 014h ;Underline location
CRT_START_VB EQU 015h ;Start vertical blank
CRT_END_VB EQU 016h ;End vertical blank
CRT_MODE_CONTROL EQU 017h ;Mode control
R_MISC_OUTPUT EQU 03C2h ;Miscellaneous Output reg
;----------------------------------------------------------------------------
; Palette Registers
;----------------------------------------------------------------------------
PEL_READ_ADDR EQU 03C7h
PEL_WRITE_ADDR EQU 03C8h
PEL_DATA EQU 03C9h
;----------------------------------------------------------------------------
; XMode planes, for the Map Mask register
;----------------------------------------------------------------------------
XPLANE_1 EQU 1
XPLANE_2 EQU 2
XPLANE_3 EQU 4
XPLANE_4 EQU 8
;----------------------------------------------------------------------------
;
; NAME
; SET_PLANE - Set an XMode plane.
;
; SYNOPSIS
; SET_PLANE plane
;
; INPUTS
; plane - Number of Xmode plane to set.
;
; USES
; eax, edx
;
;----------------------------------------------------------------------------
MACRO SET_PLANE plane
mov edx,R_SEQUENCER
mov eax,SEQ_MAP_MASK
out dx,al
inc edx
mov eax,plane
out dx,al
ENDM
;----------------------------------------------------------------------------
;
; NAME
; SET_BITMASK - Set the BitMask register.
;
; SYNOPSIS
; SET_BITMASK mask
;
; INPUTS
; mask - Bitmask to use.
;
; USES
; eax, edx
;
;----------------------------------------------------------------------------
MACRO SET_BITMASK mask
mov edx,R_GRAPHICS_CONTROLLER
mov eax,GC_BITMASK
out dx,al
inc edx
mov eax,mask
out dx,al
ENDM
;----------------------------------------------------------------------------
;
; NAME
; SET_WRITEMODE - Set the VGA writemode.
;
; SYNOPSIS
; SET_WRITEMODE mode
;
; INPUTS
; mode - Write mode.
;
; USES
; eax, edx
;
;----------------------------------------------------------------------------
MACRO SET_WRITEMODE mode
mov edx,R_GRAPHICS_CONTROLLER
mov eax,GC_MODE
out dx,al
inc edx
in al,dx ;Read the register
and al,0FCh ;Turn off 2 lower bits
or al,mode ;Set write mode
out dx,al
ENDM
;----------------------------------------------------------------------------
;
; NAME
; OUTPORT - Output data to a VGA register.
;
; SYNOPSIS
; OUTPORT port,register,data
;
; INPUTS
; port - Port address.
; register - Register to write to.
; data - Data to write.
;
; USES
; eax, edx
;
;----------------------------------------------------------------------------
MACRO OUTPORT port,register,data
mov edx,port
mov al,register
out dx,al
inc edx
mov al,data
out dx,al
ENDM
;----------------------------------------------------------------------------
;
; NAME
; INPORT - Input data from a VGA register.
;
; SYNOPSIS
; data = INPORT port,register
;
; INPUTS
; port - Port address.
; register - Register to read from.
;
; RESULT
; data - Value read from port in AL.
;
; USES
; eax, edx
;
;----------------------------------------------------------------------------
MACRO INPORT port,register
mov edx,port
mov al,register
out dx,al
inc edx
in al,dx
ENDM

282
VQ/VQM32/VIDEO.CPP Normal file
View File

@@ -0,0 +1,282 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* video.c
*
* DESCRIPTION
* Video mode setting. (32-Bit protected mode)
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* Febuary 3, 1995
*
*----------------------------------------------------------------------------
*
* PUBLIC
* SetVideoMode - Set the video mode.
* GetDisplayInfo - Get the display info for the current video mode.
* GetVBIBit - Get the vertical blank bit polarity.
*
****************************************************************************/
#include <stdlib.h>
#include <dos.h>
#include <conio.h>
#ifndef __WATCOMC__
#include <pharlap.h>
#include <pldos32.h>
#else
#include "realmode.h"
#endif
#include "video.h"
/*---------------------------------------------------------------------------
* PRIVATE DECLARATIONS
*-------------------------------------------------------------------------*/
static DisplayInfo _Display = {-1,0,0,0,NULL};
/****************************************************************************
*
* NAME
* SetVideoMode - Set the display to the specified video mode.
*
* SYNOPSIS
* DisplayInfo = SetVideoMode(Mode)
*
* DisplayInfo *SetVideoMode(long);
*
* FUNCTION
* Set the video display adapter to the desired video mode.
*
* INPUTS
* Mode - Desired video mode.
*
* RESULT
* DisplayInfo - Pointer to DisplayInfo structure, otherwise 0 for error.
*
****************************************************************************/
DisplayInfo *SetVideoMode(long mode)
{
#ifdef __WATCOMC__
union REGS regs;
struct SREGS sregs;
#else
union _REGS regs;
#endif
DisplayInfo *di = NULL;
VESAModeInfo *vminfo;
long error;
/* Initialize the video manager on the first invocation of
* SetVideoMode()
*/
if (_Display.Mode == -1) {
_Display.VBIbit = TestVBIBit();
}
/* Clear the VRAM before enabling the mode so that there is
* not any garbage on the screen.
*/
ClearVRAM();
/* If the requested mode is the same as the current mode then
* we do not need to do anything.
*/
if (mode != _Display.Mode) {
/* Uninitialize VESA if the previous mode was a VESA mode and the new
* mode is not.
*/
if (((_Display.Mode >= VESA_MIN) && (_Display.Mode <= VESA_MAX))
&& ((mode < VESA_MIN) && (mode > VESA_MAX))) {
UninitVESA();
}
/* Set display to an XMode. */
if ((mode >= XMODE_MIN) && (mode <= XMODE_MAX)) {
SetXMode(mode);
ClearXMode();
SetupXPaging();
ShowXPage(0);
_Display.Mode = mode;
_Display.Extended = NULL;
di = &_Display;
/* Set display resolution information */
switch (mode) {
case XMODE_320X200:
_Display.XRes = 320;
_Display.YRes = 200;
break;
case XMODE_320X240:
_Display.XRes = 320;
_Display.YRes = 240;
break;
case XMODE_320X400:
_Display.XRes = 320;
_Display.YRes = 400;
break;
case XMODE_320X480:
_Display.XRes = 320;
_Display.YRes = 480;
break;
case XMODE_360X400:
_Display.XRes = 360;
_Display.YRes = 400;
break;
case XMODE_360X480:
_Display.XRes = 360;
_Display.YRes = 480;
break;
}
}
else if ((mode >= VESA_MIN) && (mode <= VESA_MAX)) {
/* Initialize the VESA manager if the current mode is not a VESA
* mode.
*/
if ((_Display.Mode < VESA_MIN) || (_Display.Mode > VESA_MAX)) {
error = InitVESA();
}
if (!error) {
/* Set the display to MCGA before going into VESA. This needs to be
* done to ensure that the video ram selector is initialized. This
* fixes a bug in some VESA BIOS'.
*/
#ifndef __WATCOMC__
regs.x.ax = mode;
_int86(0x10, &regs, &regs);
#else
segread(&sregs);
regs.x.eax = mode;
int386x(0x10, &regs, &regs, &sregs);
#endif
if ((vminfo = SetVESAMode(mode)) != NULL) {
_Display.Mode = mode;
_Display.XRes = (long)vminfo->XRes;
_Display.YRes = (long)vminfo->YRes;
_Display.Extended = vminfo;
di = &_Display;
}
}
}
else {
#ifndef __WATCOMC__
regs.x.ax = mode;
_int86(0x10, &regs, &regs);
#else
segread(&sregs);
regs.x.eax = mode;
int386x(0x10, &regs, &regs, &sregs);
#endif
_Display.Mode = mode;
_Display.XRes = 320;
_Display.YRes = 200;
_Display.Extended = NULL;
di = &_Display;
}
} else {
di = &_Display;
}
return (di);
}
/****************************************************************************
*
* NAME
* GetDisplayInfo - Get the display info for the current video mode.
*
* SYNOPSIS
* DisplayInfo = GetDisplayInfo()
*
* DisplayInfo *GetDisplayInfo(void);
*
* FUNCTION
* Return a pointer to the current display information structure.
*
* INPUTS
* NONE
*
* RESULT
* DisplayInfo - Pointer to initialized display info or NULL if not valid.
*
****************************************************************************/
DisplayInfo *GetDisplayInfo(void)
{
if (_Display.Mode != 0) {
return (&_Display);
} else {
return (NULL);
}
}
/****************************************************************************
*
* NAME
* GetVBIBit - Get the vertical blank bit polarity.
*
* SYNOPSIS
* VBIBit = GetVBIBit()
*
* long GetVBIBit(void);
*
* FUNCTION
* Return the polarity of the vertical blank bit.
*
* INPUTS
* NONE
*
* RESULT
* VBIBit - Vertical blank bit polarity.
*
****************************************************************************/
long GetVBIBit(void)
{
return (_Display.VBIbit);
}

115
VQ/VQM32/VIDEO.H Normal file
View File

@@ -0,0 +1,115 @@
/*
** 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/>.
*/
#ifndef VQMVIDEO_H
#define VQMVIDEO_H
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* Video.h (32-Bit protected mode)
*
* DESCRIPTION
* Video manager definitions.
*
* PROGRAMMER
* Denzil E. Long, Jr.
*
* DATE
* Febuary 3, 1995
*
****************************************************************************/
#include <vqm32\vesavid.h>
/*---------------------------------------------------------------------------
* VGA video modes
*-------------------------------------------------------------------------*/
#define TEXT 0x02
#define MCGA 0x13
#define XMODE_320X200 0x50
#define XMODE_320X240 0x51
#define XMODE_320X400 0x52
#define XMODE_320X480 0x53
#define XMODE_360X400 0x54
#define XMODE_360X480 0x55
#define XMODE_MIN 0x50
#define XMODE_MAX 0x55
/*---------------------------------------------------------------------------
* Structure definitions
*-------------------------------------------------------------------------*/
/* DisplayInfo - Information about the current display.
*
* Mode - Mode identification.
* XRes - X resolution of mode.
* YRes - Y resolution of mode.
* VBIbit - Polarity of vertical blank bit.
* Extended - Pointer to mode specific data structure.
*/
typedef struct _DisplayInfo {
long Mode;
long XRes;
long YRes;
long VBIbit;
void *Extended;
} DisplayInfo;
/*---------------------------------------------------------------------------
* Function prototypes
*-------------------------------------------------------------------------*/
DisplayInfo *SetVideoMode(long mode);
DisplayInfo *GetDisplayInfo(void);
long TestVBIBit(void);
long GetVBIBit(void);
void SetupXPaging(void);
void FlipXPage(void);
unsigned char *GetXHidPage(void);
unsigned char *GetXSeenPage(void);
void DisplayXPage(long page);
#ifdef __cplusplus
extern "C" {
#endif
void cdecl WaitNoVB(short vbibit);
void cdecl WaitVB(short vbibit);
void cdecl ClearVRAM(void);
long cdecl SetXMode(long mode);
void cdecl ClearXMode(void);
void cdecl ShowXPage(unsigned long StartOffset);
void cdecl Xmode_BufferCopy_320x200(void *buff, void *screen);
void cdecl Xmode_Blit(void *buffer, void *screen, long imgwidth, long imgheight);
void cdecl MCGA_BufferCopy(unsigned char *buffer, unsigned char *dummy);
void cdecl MCGA_Blit(unsigned char *buffer, unsigned char *screen,
long imgwidth, long imgheight);
#ifdef __cplusplus
}
#endif
#endif /* VQMVIDEO_H */

80
VQ/VQM32/VIDEO.I Normal file
View File

@@ -0,0 +1,80 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*----------------------------------------------------------------------------
;*
;* FILE
;* video.i
;*
;* DESCRIPTION
;* Video manager definitions. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Denzil E. Long, Jr.
;*
;* DATE
;* January 26, 1995
;*
;****************************************************************************
INCLUDE "vesavid.i"
;----------------------------------------------------------------------------
; Video Modes
;----------------------------------------------------------------------------
TEXT EQU 002h
MCGA EQU 013h
XMODE_320X200 EQU 050h
XMODE_320X240 EQU 051h
XMODE_320X400 EQU 052h
XMODE_320X480 EQU 053h
XMODE_360X400 EQU 054h
XMODE_360X480 EQU 055h
;----------------------------------------------------------------------------
; Structure definitions
;----------------------------------------------------------------------------
; DisplayInfo - Information about the current display.
;
; Mode - Mode identification
; XRes - X resolution
; YRes - Y resolution
; VBIbit - Polarity of vertical blank bit.
; Extended - Pointer to mode specified data structure.
STRUC DisplayInfo
Mode DD ?
XRes DD ?
YRes DD ?
VBIbit DD ?
Extended DD ?
ENDS DisplayInfo
;----------------------------------------------------------------------------
; Function definitions
;----------------------------------------------------------------------------
GLOBAL C GetDisplayInfo:NEAR
GLOBAL C GetVBIBit:NEAR

748
VQ/VQM32/XMODE.ASM Normal file
View File

@@ -0,0 +1,748 @@
;
; 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/>.
;
;****************************************************************************
;*
;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* xmode.asm
;*
;* DESCRIPTION
;* Xmode graphics display routines. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Bill Randolph
;* Denzil E. Long, Jr.
;*
;* DATE
;* Febuary 3, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* SetXMode - Set the specified Xmode video mode.
;* ClearXMode - Clear the XMode VRAM.
;* ShowXPage - Set a specific page for XMode display.
;* Xmode_BufferCopy_320x200 - Copy 320x200 buffer to Xmode VRAM.
;* Xmode_Blit - Bit blit a block to the XMode display.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
INCLUDE "vga.i"
INCLUDE "video.i"
CODESEG
;****************************************************************************
;*
;* NAME
;* SetXMode - Set the specified Xmode video mode.
;*
;* SYNOPSIS
;* Error = SetXMode(Mode)
;*
;* long SetXMode(long);
;*
;* FUNCTION
;* This routines set the current display adapter to the specified Xmode.
;* Portions of this routine were take from Dr. Dobb's, written in C, and
;* portions were taken from Dominic's 320x200 code.
;*
;* INPUTS
;* Mode - Xmode mode to set display to.
;*
;* RESULT
;* Error - 0 if successful, or -1 if error.
;*
;****************************************************************************
GLOBAL C SetXMode:NEAR
PROC SetXMode C NEAR USES edx
ARG mode:DWORD
??Set320x200:
cmp [mode],XMODE_320X200 ;320x200?
jne ??Set320x240
IF 0
mov eax,MCGA
int 10h
; Memory Mode:
; bit3 (chain) = 0 (planes are accessed via Map Mask)
; bit2 (odd/even) = 1 (use sequential addressing mode)
INPORT R_SEQUENCER,SEQ_MEMORY_MODE
and al,not 08h ;Turn off chain 4
or al,04h ;Turn off odd/even
out dx,al
INPORT R_GRAPHICS_CONTROLLER,GC_MODE
and al,not 10h ;Turn off odd/even
out dx,al
INPORT R_GRAPHICS_CONTROLLER,GC_MISC
and al,not 02h ;Turn off chain
out dx,al
OUTPORT R_SEQUENCER,SEQ_MAP_MASK,0Fh
INPORT R_CRT_CONTROLLER, CRT_MAX_SCANLINE
and al,not 1fh ;Clear low 5 bits
or al,1 ;Mode = 0 => 400 lines
out dx,al ;Mode =1 => 200
INPORT R_CRT_CONTROLLER,CRT_UNDERLINE
and al,not 40h ;Turn off doubleword
out dx,al
INPORT R_CRT_CONTROLLER,CRT_MODE_CONTROL
or al,40h ;Turn on byte mode bit,
out dx,al ; so mem scanned linearly
ENDIF
; The following section of code is from Roger Stevens' XMode
; example code; it's the same as 320x400, except the value sent
; to CRT_MAX_SCANLINE is 41, not 40.
mov eax,MCGA
int 10h
OUTPORT R_SEQUENCER,SEQ_MEMORY_MODE,06h
INPORT R_CRT_CONTROLLER,CRT_VERTRET_END
and al,07Fh
out dx,al
OUTPORT R_CRT_CONTROLLER,CRT_MAX_SCANLINE,41h
OUTPORT R_CRT_CONTROLLER,CRT_UNDERLINE,00h
OUTPORT R_CRT_CONTROLLER,CRT_MODE_CONTROL,0E3h
mov eax,0
jmp ??Done
??Set320x240:
cmp [mode],XMODE_320X240 ;320x240?
jne ??Set320x400
; Start by setting MCGA to let the BIOS program the registers;
; then, reprogram the registers that need it.
mov eax,MCGA
int 10h
; Memory Mode:
; bit3 (chain) = 0 (planes are accessed via Map Mask)
; bit2 (odd/even) = 1 (use sequential addressing mode)
; bit1 (extended mem) = 1 (>64K video RAM)
; bit0 (alpha/graph) = 0 (graphics mode)
OUTPORT R_SEQUENCER,SEQ_MEMORY_MODE,06h
; Issue a Sequencer Reset
OUTPORT R_SEQUENCER,SEQ_RESET,01h
; Misc Output: (set to 1100 0011)
; Bit 7: VSync polarity (1=negative)
; Bit 6: HSync polarity (1=negative)
; Bit 5: page bit for odd/even (0=low 64K)
; Bit 4: Video drivers (0=enable)
; Bit 3,2: clock select (0=25-MHz clock)
; Bit 1: VRAM access (1 = enable CPU to access)
; Bit 0: I/O Address (1=color emulation)
mov edx,R_MISC_OUTPUT
mov al,0C3h
out dx,al
; Clear Sequencer Reset
OUTPORT R_SEQUENCER,SEQ_RESET,03h
; Read Vertical Retrace End, and with 07f to clear high bit
; (clearing bit 7 enables writing to registers 0-7)
INPORT R_CRT_CONTROLLER,CRT_VERTRET_END
and al,07Fh
out dx,al
; Program the CRT Controller to display 480 scanlines, but to
; double each scanline so only 240 are displayed:
OUTPORT R_CRT_CONTROLLER,CRT_UNDERLINE,00h
OUTPORT R_CRT_CONTROLLER,CRT_MODE_CONTROL,0E3h
OUTPORT R_CRT_CONTROLLER,CRT_VERT_TOTAL,0Dh
OUTPORT R_CRT_CONTROLLER,CRT_OVERFLOW,03Eh
OUTPORT R_CRT_CONTROLLER,CRT_VERTRET_START,0EAh
OUTPORT R_CRT_CONTROLLER,CRT_VERTRET_END,0ACh
OUTPORT R_CRT_CONTROLLER,CRT_VERTDISP_END,0DFh
OUTPORT R_CRT_CONTROLLER,CRT_START_VB,0E7h
OUTPORT R_CRT_CONTROLLER,CRT_END_VB,06h
OUTPORT R_CRT_CONTROLLER,CRT_MAX_SCANLINE,041h
xor eax,eax
jmp ??Done
??Set320x400:
cmp [mode],XMODE_320X400 ;320x400
jne ??Set320x480
mov eax,MCGA
int 10h
OUTPORT R_SEQUENCER,04h,06h
INPORT R_CRT_CONTROLLER,011h
and al,07Fh
out dx,al
OUTPORT R_CRT_CONTROLLER,09h,40h
OUTPORT R_CRT_CONTROLLER,014h,00h
OUTPORT R_CRT_CONTROLLER,017h,0E3h
xor eax,eax
jmp ??Done
??Set320x480:
cmp [mode],XMODE_320X480 ;320x480?
jne ??Set360x400
mov eax,MCGA
int 10h
mov edx,R_SEQUENCER
mov eax,0604h
out dx,ax
mov eax,0100h
out dx,ax
mov edx,R_MISC_OUTPUT
mov al,0C3h
out dx,al
mov edx,R_SEQUENCER
mov eax,0300h
out dx,ax
mov edx,R_CRT_CONTROLLER
mov al,011h
out dx,al
mov edx,03D5h
in al,dx
and al,07Fh
out dx,al
mov edx,R_CRT_CONTROLLER
mov eax,04009h
out dx,ax
mov eax,00014h
out dx,ax
mov eax,0E317h
out dx,ax
mov eax,00D06h
out dx,ax
mov eax,03E07h
out dx,ax
mov eax,0EA10h
out dx,ax
mov eax,0AC11h
out dx,ax
mov eax,0DF12h
out dx,ax
mov eax,0E715h
out dx,ax
mov eax,00616h
out dx,ax
mov eax,04009h
out dx,ax
xor eax,eax
jmp ??Done
??Set360x400:
cmp [mode],XMODE_360X400 ;360x400
jne ??Set360x480
mov eax,MCGA
int 10h
mov edx,R_SEQUENCER
mov eax,0604h
out dx,ax
mov eax,0100h
out dx,ax
mov edx,R_MISC_OUTPUT
mov al,067h
out dx,al
mov edx,R_SEQUENCER
mov eax,0300h
out dx,ax
mov edx,R_CRT_CONTROLLER
mov al,011h
out dx,al
mov edx,03D5h
in al,dx
and al,07Fh
out dx,al
mov edx,R_CRT_CONTROLLER
mov eax,06B00h
out dx,ax
mov eax,05901h
out dx,ax
mov eax,05A02h
out dx,ax
mov eax,08E03h
out dx,ax
mov eax,05E04h
out dx,ax
mov eax,08A05h
out dx,ax
mov eax,04009
out dx,ax
mov eax,00014h
out dx,ax
mov eax,0E317h
out dx,ax
mov eax,02D13h
out dx,ax
xor eax,eax
jmp ??Done
??Set360x480:
cmp [mode],XMODE_360X480 ;360x480?
jne ??Unknown_mode
mov eax,MCGA
int 10h
mov edx,R_SEQUENCER
mov eax,0604h
out dx,ax
mov eax,0100h
out dx,ax
mov edx,R_MISC_OUTPUT
mov al,0E7h
out dx,al
mov edx,R_SEQUENCER
mov eax,0300h
out dx,ax
mov edx,R_CRT_CONTROLLER
mov al,011h
out dx,al
mov edx,03D5h
in al,dx
and al,07Fh
out dx,al
mov edx,R_CRT_CONTROLLER
mov eax,06B00h
out dx,ax
mov eax,05901h
out dx,ax
mov eax,05A02h
out dx,ax
mov eax,08E03h
out dx,ax
mov eax,05E04h
out dx,ax
mov eax,08A05h
out dx,ax
mov eax,04009h
out dx,ax
mov eax,00014h
out dx,ax
mov eax,0E317h
out dx,ax
mov eax,00D06h
out dx,ax
mov eax,03E07h
out dx,ax
mov eax,0EA10h
out dx,ax
mov eax,0AC11h
out dx,ax
mov eax,0DF12h
out dx,ax
mov eax,0E715h
out dx,ax
mov eax,00616h
out dx,ax
mov eax,02D13h
out dx,ax
xor eax,eax
jmp ??Done
??Unknown_mode:
mov eax,0FFFFFFFFh ;Unknown mode
??Done:
ret
ENDP SetXMode
;****************************************************************************
;*
;* NAME
;* ClearXMode - Clear the XMode VRAM.
;*
;* SYNOPSIS
;* ClearXMode()
;*
;* void ClearXMode(void);
;*
;* FUNCTION
;*
;* INPUTS
;* NONE
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C ClearXMode:NEAR
PROC ClearXMode C NEAR USES eax ecx edi es
IF PHARLAP_TNT
mov eax,01Ch
mov es,ax ;Set ES selector to VRAM
mov edi,0
ELSE
mov edi,0A0000h
ENDIF
SET_PLANE 0Fh
mov ecx,((320*240*2)/4/4)
xor eax,eax
rep stosd
ret
ENDP ClearXMode
;****************************************************************************
;*
;* NAME
;* ShowXPage - Set a specific page for XMode display.
;*
;* SYNOPSIS
;* ShowXPage(Offset)
;*
;* void ShowXPage();
;*
;* FUNCTION
;* Show the page at the specified offset in the bitmap. Page-flip takes
;* effect on the next active scan cycle.
;*
;* INPUTS
;* Offset - Offset to set page to.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C ShowXPage:NEAR
PROC ShowXPage C NEAR USES eax ebx ecx edx
ARG StartOffset:DWORD
mov edx,R_CRT_CONTROLLER
mov bl,CRT_STARTADDR_LOW
mov bh,[byte ptr StartOffset]
mov cl,CRT_STARTADDR_HIGH
mov ch,[byte ptr StartOffset+1]
mov eax,ebx
out dx,ax
mov eax,ecx
out dx,ax
ret
ENDP ShowXPage
;****************************************************************************
;*
;* NAME
;* Xmode_BufferCopy_320x200 - Copy 320x200 buffer to Xmode VRAM.
;*
;* SYNOPSIS
;* Xmode_BufferCopy_320x200(Buffer, Screen)
;*
;* void Xmode_BufferCopy_320x200(char *, char *);
;*
;* FUNCTION
;* BitBlt copy to VRAM.
;*
;* INPUTS
;* Buffer - Pointer to buffer to copy to XMode VRAM.
;* Screen - XMode VRAM screen address to copy buffer to.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Xmode_BufferCopy_320x200:NEAR
PROC Xmode_BufferCopy_320x200 C NEAR USES eax ecx edx edi esi es
ARG buffer:NEAR PTR
ARG screen:NEAR PTR
LOCAL save_esi:DWORD
LOCAL save_edi:DWORD
;----------------------------------------------------------------------------
; Initialize
;----------------------------------------------------------------------------
IF PHARLAP_TNT
mov eax,01Ch ;Set ES selector to VRAM.
mov es,ax
ENDIF
mov esi,[buffer] ;Set pointers
mov edi,[screen]
mov [save_esi],esi
mov [save_edi],edi
;----------------------------------------------------------------------------
; Copy plane 1
;----------------------------------------------------------------------------
SET_PLANE XPLANE_1
mov ecx,4000
x_loop_1:
mov al,[esi + 8] ;Get pixel
mov ah,[esi + 12] ;Get pixel
ror eax,16
mov al,[esi] ;Get pixel
mov ah,[esi + 4] ;Get pixel
mov [es:edi],eax ;Write plane 1 pixels to VRAM
add esi,16 ;Next source pixel position
add edi,4 ;Next VRAM position
dec ecx
jnz short x_loop_1
;----------------------------------------------------------------------------
; Copy plane 2
;----------------------------------------------------------------------------
mov esi,[save_esi] ;Restore pointers
mov edi,[save_edi]
inc esi ;Adjust source pointer to plane 2
SET_PLANE XPLANE_2
mov ecx,4000
x_loop_2:
mov al,[esi + 8] ;Get pixel
mov ah,[esi + 12] ;Get pixel
ror eax,16
mov al,[esi] ;Get pixel
mov ah,[esi + 4] ;Get pixel
mov [es:edi],eax ;Write plane 2 pixels to VRAM
add esi,16 ;Next source pixel position
add edi,4 ;Next VRAM position
dec ecx
jnz short x_loop_2
;----------------------------------------------------------------------------
; Copy plane 3
;----------------------------------------------------------------------------
mov esi,[save_esi] ;Restore pointers
mov edi,[save_edi]
add esi,2 ;Adjust source pointer to plane 3
SET_PLANE XPLANE_3
mov ecx,4000
x_loop_3:
mov al,[esi + 8] ;Get pixel
mov ah,[esi + 12] ;Get pixel
ror eax,16
mov al,[esi] ;Get pixel
mov ah,[esi + 4] ;Get pixel
mov [es:edi],eax ;Write plane 3 pixels to VRAM
add esi,16 ;Next source pixel position
add edi,4 ;Next VRAM position
dec ecx
jnz short x_loop_3
;----------------------------------------------------------------------------
; Copy plane 4
;----------------------------------------------------------------------------
mov esi,[save_esi] ;Restore pointers
mov edi,[save_edi]
add esi,3 ;Adjust source pointer to plane 4
SET_PLANE XPLANE_4
mov ecx,4000
x_loop_4:
mov al,[esi + 8] ;Get pixel
mov ah,[esi + 12] ;Get pixel
ror eax,16
mov al,[esi] ;Get pixel
mov ah,[esi + 4] ;Get pixel
mov [es:edi],eax ;Write plane 4 pixels to VRAM
add esi,16 ;Next source pixel position
add edi,4 ;Next screen position
dec ecx
jnz short x_loop_4
ret
ENDP Xmode_BufferCopy_320x200
;****************************************************************************
;*
;* NAME
;* Xmode_Blit - Bit blit a block to the XMode display.
;*
;* SYNOPSIS
;* XMode_Blit(Buffer, Screen, Width, Height)
;*
;* void XMode_Blit(char *, char *, long, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Buffer - Pointer buffer to blit to screen.
;* Screen - Screen address to blit buffer to.
;* Width - Width of buffer.
;* Height - Height of buffer.
;*
;* RESULT
;* NONE
;*
;* WARNINGS
;* Assumes the screen to be 320 pixels wide and the source buffer width
;* to be divisible by 16.
;*
;****************************************************************************
GLOBAL C Xmode_Blit:NEAR
PROC Xmode_Blit C NEAR USES ecx edx esi edi es
ARG buffer:NEAR PTR
ARG screen:NEAR PTR
ARG imgwidth:DWORD
ARG imgheight:DWORD
LOCAL rowcount:DWORD
LOCAL xplane:DWORD
LOCAL edi_startval:DWORD
LOCAL esi_startval:DWORD
LOCAL xadd:DWORD
;----------------------------------------------------------------------------
; Initialize
;----------------------------------------------------------------------------
IF PHARLAP_TNT
mov eax,01Ch ;Set ES selector to VRAM
mov es,ax
ENDIF
mov esi,[buffer]
mov edi,[screen]
mov [esi_startval],esi
mov [edi_startval],edi
mov edx,320 ;Compute modulo
sub edx,[imgwidth]
shr edx,2
mov [xadd],edx
;----------------------------------------------------------------------------
; Transfer the data on plane at a time.
;----------------------------------------------------------------------------
mov [xplane],1
??Do_plane:
SET_PLANE [xplane] ;Set plane to transfer to
mov eax,[imgheight]
mov [rowcount],eax
mov edx,[xadd]
??Do_row:
mov ecx,[imgwidth] ;Length of row to copy in DWORDS
shr ecx,4
; Transfer a row of pixels
??Not_done:
mov al,[esi + 8] ;Get pixel
mov ah,[esi + 12] ;Get pixel
ror eax,16
mov al,[esi] ;Get pixel
mov ah,[esi + 4] ;Get pixel
mov [es:edi],eax ;Write pixels to VRAM plane
add esi,16 ;Next source position
add edi,4 ;Next VRAM position
dec ecx
jnz ??Not_done
add edi,edx ;Next VRAM row
dec [rowcount] ;Decrement the row count
jnz ??Do_row
; Go to next X-Plane
inc [esi_startval]
mov eax,[esi_startval]
mov esi,eax
mov eax,[edi_startval]
mov edi,eax
shl [xplane],1
cmp [xplane],16
jnz ??Do_plane
ret
ENDP Xmode_Blit
END

201
VQ/VQM32/XMODEPG.CPP Normal file
View File

@@ -0,0 +1,201 @@
/*
** 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/>.
*/
/****************************************************************************
*
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
*
*----------------------------------------------------------------------------
*
* FILE
* xmodepg.c
*
* DESCRIPTION
* Xmode page access. (32-Bit protected mode)
*
* PROGRAMMER
* Bill Randolph
* Denzil E. Long, Jr.
*
* DATE
* January 26, 1995
*
*----------------------------------------------------------------------------
*
* PUBLIC
* SetupXPaging - Setup Xmode paging variables.
* FlipXPage - Page flip to next Xmode page.
* ShowXPage - Show the specified Xmode page.
* GetXHidPage - Get the address of the current Xmode HidPage.
* GetXSeenPage - Get the address of the current Xmode SeenPage.
*
****************************************************************************/
#include <dos.h>
#include "video.h"
/*---------------------------------------------------------------------------
* PRIVATE DECLARATIONS
*-------------------------------------------------------------------------*/
#define PAGE0_START_OFFSET 0
#define PAGE1_START_OFFSET ((320 * 240) / 4)
/* PageFlip page values. */
static unsigned long PageStartOffsets[2] = {
PAGE0_START_OFFSET,
PAGE1_START_OFFSET
};
static long DisplayedPage;
static long NonDisplayedPage;
/****************************************************************************
*
* NAME
* SetupXPaging - Setup Xmode paging variables.
*
* SYNOPSIS
* SetupXPaging()
*
* void SetupXPaging(void);
*
* FUNCTION
*
* INPUTS
* NONE
*
* RESULT
* NONE
*
****************************************************************************/
void SetupXPaging(void)
{
DisplayedPage = 1;
NonDisplayedPage = DisplayedPage ^ 1;
}
/****************************************************************************
*
* NAME
* FlipXPage - Page flip to next Xmode page.
*
* SYNOPSIS
* FlipXPage()
*
* void FlipXPage(void);
*
* FUNCTION
*
* INPUTS
* NONE
*
* RESULT
* NONE
*
****************************************************************************/
void FlipXPage(void)
{
ShowXPage(PageStartOffsets[NonDisplayedPage]);
DisplayedPage = NonDisplayedPage;
NonDisplayedPage = DisplayedPage ^ 1;
}
/****************************************************************************
*
* NAME
* ShowXPage - Show the specified Xmode page.
*
* SYNOPSIS
* ShowXPage(page)
*
* void ShowXPage(long);
*
* FUNCTION
*
* INPUTS
* Page - Xmode page number to show.
*
* RESULT
* NONE
*
****************************************************************************/
void DisplayXPage(long page)
{
ShowXPage(PageStartOffsets[page & 1]);
DisplayedPage = page;
NonDisplayedPage = DisplayedPage ^ 1;
}
/****************************************************************************
*
* NAME
* GetXHidPage - Get the address of the current Xmode HidPage.
*
* SYNOPSIS
* HidPage = GetXHidPage()
*
* unsigned char *GetXHidPage(void);
*
* FUNCTION
*
* INPUTS
* NONE
*
* RESULT
* HidPage - Address of Xmode HidPage.
*
****************************************************************************/
unsigned char *GetXHidPage(void)
{
return((unsigned char *)PageStartOffsets[NonDisplayedPage]);
}
/****************************************************************************
*
* NAME
* GetXSeenPage - Get the address of the current Xmode SeenPage.
*
* SYNOPSIS
* SeenPage = GetXSeenPage()
*
* unsigned char *GetXSeenPage(void);
*
* FUNCTION
*
* INPUTS
* NONE
*
* RESULT
* SeePage - Address of the Xmode SeenPage.
*
****************************************************************************/
unsigned char *GetXSeenPage(void)
{
return ((unsigned char *)PageStartOffsets[DisplayedPage]);
}