From c068f22329d5cc722622a2183bbb22eef2093df7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 11:16:07 +0200 Subject: initial import --- src/parsec/con_cani.cpp | 627 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 627 insertions(+) create mode 100644 src/parsec/con_cani.cpp (limited to 'src/parsec/con_cani.cpp') diff --git a/src/parsec/con_cani.cpp b/src/parsec/con_cani.cpp new file mode 100644 index 0000000..4e66fca --- /dev/null +++ b/src/parsec/con_cani.cpp @@ -0,0 +1,627 @@ +/* + * PARSEC - Color Animation Commands + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:34 $ + * + * Orginally written by: + * Copyright (c) Markus Hadwiger 1999 + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include +#include +#include +#include + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// mathematics header +#include "utl_math.h" + +// local module header +#include "con_cani.h" + +// proprietary module headers +#include "con_arg.h" +#include "con_aux.h" +#include "con_main.h" +#include "e_colani.h" + + + +// string constants ----------------------------------------------------------- +// +static char colanim_name_missing[] = "name of colanim must be specified."; +static char colanim_name_invalid[] = "name invalid."; +static char colanim_mode_invalid[] = "mode invalid."; +static char colanim_len0_invalid[] = "len invalid."; +static char colanim_len1_invalid[] = "len2 invalid."; +static char colanim_len1_missing[] = "len2 missing but src2 specified."; +static char colanim_tab1_missing[] = "src2 missing but len2 specified."; +static char colanim_comp0_invalid[] = "comp is invalid (src)."; +static char colanim_comp1_invalid[] = "comp is invalid (src2)."; +static char colanim_t0_invalid[] = "tequi is invalid (src)."; +static char colanim_t1_invalid[] = "tequi is invalid (src2)."; +static char colanim_tl0_invalid[] = "tlist is invalid (src)."; +static char colanim_tl1_invalid[] = "tlist is invalid (src2)."; +static char colanim_w0_invalid[] = "invalid wave spec (src)."; +static char colanim_w1_invalid[] = "invalid wave spec (src2)."; +static char colanim_min0_invalid[] = "invalid min value (src)."; +static char colanim_min1_invalid[] = "invalid min value (src2)."; +static char colanim_max0_invalid[] = "invalid max value (src)."; +static char colanim_max1_invalid[] = "invalid max value (src2)."; +static char colanim_mask0_invalid[] = "invalid channel mask (src)."; +static char colanim_mask1_invalid[] = "invalid channel mask (src2)."; +static char colanim_reg_failed[] = "colanim registration failed."; + + +// key tables for colanim registration via console command -------------------- +// +key_value_s colanim_key_value[] = { + + { "src", NULL, KEYVALFLAG_PARENTHESIZE | KEYVALFLAG_MANDATORY }, + { "len", NULL, KEYVALFLAG_NONE | KEYVALFLAG_MANDATORY }, + { "src2", NULL, KEYVALFLAG_PARENTHESIZE }, + { "len2", NULL, KEYVALFLAG_NONE }, + { "mode", NULL, KEYVALFLAG_NONE }, + + { NULL, NULL, KEYVALFLAG_NONE }, +}; + +enum { + + KEY_COLANI_SRC0, + KEY_COLANI_LEN0, + KEY_COLANI_SRC1, + KEY_COLANI_LEN1, + KEY_COLANI_MODE +}; + + +key_value_s colanim_tab_key_value[] = { + + { "tab", NULL, KEYVALFLAG_PARENTHESIZE | KEYVALFLAG_MANDATORY }, + { "comp", NULL, KEYVALFLAG_NONE }, + { "t", NULL, KEYVALFLAG_NONE }, + { "tl", NULL, KEYVALFLAG_PARENTHESIZE }, + { "mask", NULL, KEYVALFLAG_NONE }, + + { NULL, NULL, KEYVALFLAG_NONE }, +}; + +enum { + + KEY_COLANI_TAB_TAB, + KEY_COLANI_TAB_COMP, + KEY_COLANI_TAB_TEQUI, + KEY_COLANI_TAB_TLIST, + KEY_COLANI_TAB_MASK +}; + + +key_value_s colanim_wav_key_value[] = { + + { "wave", NULL, KEYVALFLAG_MANDATORY }, + { "t", NULL, KEYVALFLAG_NONE }, + { "max", NULL, KEYVALFLAG_NONE }, + { "min", NULL, KEYVALFLAG_NONE }, + { "mask", NULL, KEYVALFLAG_NONE }, + + { NULL, NULL, KEYVALFLAG_NONE }, +}; + +enum { + + KEY_COLANI_WAV_WAVE, + KEY_COLANI_WAV_TEQUI, + KEY_COLANI_WAV_MAX, + KEY_COLANI_WAV_MIN, + KEY_COLANI_WAV_MASK +}; + +static char colanim_wave_separator[] = "wave "; +static int colanim_wave_seplen = strlen( colanim_wave_separator ); + + +// waveform specs ------------------------------------------------------------- +// +static char colanim_wave_tri[] = "tri"; +static char colanim_wave_saw[] = "saw"; +static char colanim_wave_ramp[] = "ramp"; +static char colanim_wave_sine[] = "sine"; + + +// store color and timing info into colanim entry ----------------------------- +// +#define SET_COLTAB_ENTRY(p,v,t) { \ + coltab[ p ].color.R = ( mask & 0x01 ) ? (byte)(v) : 0x00; \ + coltab[ p ].color.G = ( mask & 0x02 ) ? (byte)(v) : 0x00; \ + coltab[ p ].color.B = ( mask & 0x04 ) ? (byte)(v) : 0x00; \ + coltab[ p ].color.A = ( mask & 0x08 ) ? (byte)(v) : 0x00; \ + coltab[ p ].deltatime = (t); \ +} + + +// check and parse color channel mask ----------------------------------------- +// +PRIVATE +int CheckChannelMask( char *maskstr, dword *mask ) +{ + ASSERT( mask != NULL ); + + if ( maskstr != NULL ) { + + *mask = 0x00; + + if ( maskstr[ 0 ] == 'r' ) { + *mask |= 0x01; + maskstr++; + } + if ( maskstr[ 0 ] == 'g' ) { + *mask |= 0x02; + maskstr++; + } + if ( maskstr[ 0 ] == 'b' ) { + *mask |= 0x04; + maskstr++; + } + if ( maskstr[ 0 ] == 'a' ) { + *mask |= 0x08; + maskstr++; + } + if ( ( maskstr[ 0 ] != ' ' ) && ( maskstr[ 0 ] != 0 ) ) { + return FALSE; + } + } + + return TRUE; +} + + +// check for waveform specs --------------------------------------------------- +// +PRIVATE +int CheckWaveSpec( char *tabstr, colfrm_s *coltab, size_t tabsize, int tid ) +{ + ASSERT( tabstr != NULL ); + ASSERT( coltab != NULL ); + ASSERT( ( tid == 0 ) || ( tid == 1 ) ); + + // scan out all values to colanim_wav keys + if ( !ScanKeyValuePairs( colanim_wav_key_value, tabstr ) ) { + return FALSE; + } + + // timing + int tequi = 200; + if ( colanim_wav_key_value[ KEY_COLANI_WAV_TEQUI ].value != NULL ) { + if ( ScanKeyValueInt( &colanim_wav_key_value[ KEY_COLANI_WAV_TEQUI ], &tequi ) < 0 ) { + CON_AddLine( tid ? colanim_t1_invalid : colanim_t0_invalid ); + return FALSE; + } + if ( tequi < 1 ) { + CON_AddLine( tid ? colanim_t1_invalid : colanim_t0_invalid ); + return FALSE; + } + } + + // lower bound + int minval = 0; + if ( colanim_wav_key_value[ KEY_COLANI_WAV_MIN ].value != NULL ) { + if ( ScanKeyValueInt( &colanim_wav_key_value[ KEY_COLANI_WAV_MIN ], &minval ) < 0 ) { + CON_AddLine( tid ? colanim_min1_invalid : colanim_min0_invalid ); + return FALSE; + } + if ( ( minval < 0 ) || ( minval > 255 ) ) { + CON_AddLine( tid ? colanim_min1_invalid : colanim_min0_invalid ); + return FALSE; + } + } + + // upper bound + int maxval = 255; + if ( colanim_wav_key_value[ KEY_COLANI_WAV_MAX ].value != NULL ) { + if ( ScanKeyValueInt( &colanim_wav_key_value[ KEY_COLANI_WAV_MAX ], &maxval ) < 0 ) { + CON_AddLine( tid ? colanim_max1_invalid : colanim_max0_invalid ); + return FALSE; + } + if ( ( maxval < minval ) || ( maxval > 255 ) ) { + CON_AddLine( tid ? colanim_max1_invalid : colanim_max0_invalid ); + return FALSE; + } + } + + // check for color channel mask + dword mask = 0x0f; + if ( !CheckChannelMask( colanim_wav_key_value[ KEY_COLANI_WAV_MASK ].value, &mask ) ) { + CON_AddLine( tid ? colanim_mask1_invalid : colanim_mask0_invalid ); + return FALSE; + } + + // generate specified waveform + char *wave = colanim_wav_key_value[ KEY_COLANI_WAV_WAVE ].value; + + if ( strcmp( wave, colanim_wave_tri ) == 0 ) { + + // triangle: "/\" + if ( tabsize < 2 ) { + SET_COLTAB_ENTRY( 0, minval, tequi ); + return TRUE; + } + unsigned int halft = tabsize / 2; + float step = (float)( maxval - minval ) / (float)halft; + float curval = (float)minval; + unsigned int tpos = 0; + for ( tpos = 0; tpos < halft; tpos++ ) { + SET_COLTAB_ENTRY( tpos, curval, tequi ); + curval += step; + } + for ( ; tpos < tabsize; tpos++ ) { + SET_COLTAB_ENTRY( tpos, curval, tequi ); + curval -= step; + } + + } else if ( strcmp( wave, colanim_wave_saw ) == 0 ) { + + // sawtooth: "|\" + if ( tabsize < 2 ) { + SET_COLTAB_ENTRY( 0, minval, tequi ); + return TRUE; + } + float step = (float)( maxval - minval ) / (float)( tabsize - 1 ); + float curval = (float)maxval; + for ( unsigned int tpos = 0; tpos < tabsize; tpos++ ) { + SET_COLTAB_ENTRY( tpos, curval, tequi ); + curval -= step; + } + + } else if ( strcmp( wave, colanim_wave_ramp ) == 0 ) { + + // ramp: "/|" + if ( tabsize < 2 ) { + SET_COLTAB_ENTRY( 0, minval, tequi ); + return TRUE; + } + float step = (float)( maxval - minval ) / (float)( tabsize - 1 ); + float curval = (float)minval; + for ( unsigned int tpos = 0; tpos < tabsize; tpos++ ) { + SET_COLTAB_ENTRY( tpos, curval, tequi ); + curval += step; + } + + } else if ( strcmp( wave, colanim_wave_sine ) == 0 ) { + + // sine + float step = (float)BAMS_DEG360 / (float)tabsize; + float base = (float)( maxval + minval ) / 2; + float ampl = (float)( maxval - minval ) / 2; + float curval = (float)BAMS_DEG0; + for ( unsigned int tpos = 0; tpos < tabsize; tpos++ ) { + sincosval_s sincos; + GetSinCos( (dword)curval, &sincos ); + float cursig = ampl * GEOMV_TO_FLOAT( sincos.sinval ); + SET_COLTAB_ENTRY( tpos, base + cursig, tequi ); + curval += step; + } + + } else { + + CON_AddLine( tid ? colanim_w1_invalid : colanim_w0_invalid ); + return FALSE; + } + + return TRUE; +} + + +// parse entire color table of 1, 3, or 4 components -------------------------- +// +PRIVATE +int ParseColorTable( char *tabstr, colfrm_s *coltab, int *intlist, size_t tabsize, int tid ) +{ + ASSERT( tabstr != NULL ); + ASSERT( coltab != NULL ); + ASSERT( intlist != NULL ); + ASSERT( ( tid == 0 ) || ( tid == 1 ) ); + + // check for wave spec instead of table + while ( *tabstr == ' ' ) + tabstr++; + if ( strncmp( tabstr, colanim_wave_separator, colanim_wave_seplen ) == 0 ) { + return CheckWaveSpec( tabstr, coltab, tabsize, tid ); + } + + // scan out all values to colanim_tab keys + if ( !ScanKeyValuePairs( colanim_tab_key_value, tabstr ) ) { + return FALSE; + } + + // number of color components + int comp = 1; + if ( ScanKeyValueInt( &colanim_tab_key_value[ KEY_COLANI_TAB_COMP ], &comp ) < 0 ) { + CON_AddLine( tid ? colanim_comp1_invalid : colanim_comp0_invalid ); + return FALSE; + } + if ( ( comp != 1 ) && ( comp != 3 ) && ( comp != 4 ) ) { + CON_AddLine( tid ? colanim_comp1_invalid : colanim_comp0_invalid ); + return FALSE; + } + + // check for color channel mask + dword mask = 0x0f; + if ( !CheckChannelMask( colanim_tab_key_value[ KEY_COLANI_TAB_MASK ].value, &mask ) ) { + CON_AddLine( tid ? colanim_mask1_invalid : colanim_mask0_invalid ); + return FALSE; + } + + // timing + int tequi = 200; + int tlist = FALSE; + if ( colanim_tab_key_value[ KEY_COLANI_TAB_TEQUI ].value != NULL ) { + + if ( ScanKeyValueInt( &colanim_tab_key_value[ KEY_COLANI_TAB_TEQUI ], &tequi ) < 0 ) { + CON_AddLine( tid ? colanim_t1_invalid : colanim_t0_invalid ); + return FALSE; + } + if ( tequi < 1 ) { + CON_AddLine( tid ? colanim_t1_invalid : colanim_t0_invalid ); + return FALSE; + } + + } else if ( colanim_tab_key_value[ KEY_COLANI_TAB_TLIST ].value != NULL ) { + + if ( ScanKeyValueIntList( &colanim_tab_key_value[ KEY_COLANI_TAB_TLIST ], + intlist, tabsize, tabsize ) == 0 ) { + CON_AddLine( tid ? colanim_tl1_invalid : colanim_tl0_invalid ); + return FALSE; + } + tlist = TRUE; + } + if ( tlist ) { + for ( unsigned int eid = 0; eid < tabsize; eid++ ) { + if ( intlist[ eid ] < 1 ) { + CON_AddLine( tid ? colanim_t1_invalid : colanim_t0_invalid ); + return FALSE; + } + coltab[ eid ].deltatime = intlist[ eid ]; + } + } else { + for ( unsigned int eid = 0; eid < tabsize; eid++ ) { + coltab[ eid ].deltatime = tequi; + } + } + + // color components + size_t complistlen = comp * tabsize; + if ( ScanKeyValueIntList( &colanim_tab_key_value[ KEY_COLANI_TAB_TAB ], + intlist, complistlen, complistlen ) == 0 ) { + CON_AddLine( tid ? colanim_tl1_invalid : colanim_tl0_invalid ); + return FALSE; + } + int *complist = intlist; + for ( unsigned int eid = 0; eid < tabsize; eid++, complist += comp ) { + + switch ( comp ) { + + case 1: + coltab[ eid ].color.R = ( mask & 0x01 ) ? complist[ 0 ] : 0x00; + coltab[ eid ].color.G = ( mask & 0x02 ) ? complist[ 0 ] : 0x00; + coltab[ eid ].color.B = ( mask & 0x04 ) ? complist[ 0 ] : 0x00; + coltab[ eid ].color.A = ( mask & 0x08 ) ? complist[ 0 ] : 0x00; + break; + + case 3: + coltab[ eid ].color.R = ( mask & 0x01 ) ? complist[ 0 ] : 0x00; + coltab[ eid ].color.G = ( mask & 0x02 ) ? complist[ 1 ] : 0x00; + coltab[ eid ].color.B = ( mask & 0x04 ) ? complist[ 2 ] : 0x00; + coltab[ eid ].color.A = ( mask & 0x08 ) ? 0xff : 0x00; + break; + + case 4: + coltab[ eid ].color.R = ( mask & 0x01 ) ? complist[ 0 ] : 0x00; + coltab[ eid ].color.G = ( mask & 0x02 ) ? complist[ 1 ] : 0x00; + coltab[ eid ].color.B = ( mask & 0x04 ) ? complist[ 2 ] : 0x00; + coltab[ eid ].color.A = ( mask & 0x08 ) ? complist[ 3 ] : 0x00; + break; + } + } + + return TRUE; +} + + +// possible colanim_s::col_flags modes (COLANIM_SOURCExx) --------------------- +// +static char colanim_mode_sourcenocomb[] = "nocombine"; +static char colanim_mode_sourceadd[] = "add"; +static char colanim_mode_sourcemul[] = "mul"; + + +// console command for registering new colanim ("colanim") -------------------- +// +int Cmd_DefColAnim( char *command ) +{ + //NOTE: + //CONCOM: + // colanim_command ::= 'colanim' [] [] + // name ::= "may be parenthesized to include whitespace" + // coltab0 ::= 'src' 'len' + // coltab1 ::= 'src2' 'len2' + // coltab_src ::= '(' | ')' + // coltab_len ::= + // mode_spec ::= 'mode' 'add' | 'mul' + // tab_spec ::= 'tab' [] [] [ | ] + // col_list ::= '(' + ')' + // comp ::= 'comp' '1' | '3' | '4' + // t_equi ::= 't' + // t_list ::= 'tl' '(' + ')' + // wave_spec ::= 'wave' [] [] [] [] + // wave_name ::= 'tri' | 'saw' | 'ramp' | 'sine' + // max ::= 'max' + // min ::= 'min' + // mask ::= 'mask' ['r'] ['g'] ['b'] ['a'] + + ASSERT( command != NULL ); + HANDLE_COMMAND_DOMAIN_SEP( command ); + + // this flag is used during internal data reloads + if ( AUX_ALLOW_ONLY_TEXTURE_LOADING ) { + return TRUE; + } + + // create pointer to list of parameters (first is always the name) + char *colanimname = strtok( command, " " ); + if ( colanimname == NULL ) { + CON_AddLine( colanim_name_missing ); + return TRUE; + } + + // allow name to be parenthesized to include whitespace + colanimname = GetParenthesizedName( colanimname ); + if ( colanimname == NULL ) { + CON_AddLine( colanim_name_invalid ); + return TRUE; + } + + // scan out all values to colanim keys + if ( !ScanKeyValuePairs( colanim_key_value, NULL ) ) + return TRUE; + + // fetch length of coltab0 + int len0; + if ( ScanKeyValueInt( &colanim_key_value[ KEY_COLANI_LEN0 ], &len0 ) < 0 ) { + CON_AddLine( colanim_len0_invalid ); + return TRUE; + } + if ( ( len0 < 1 ) || ( len0 > 256 ) ) { + CON_AddLine( colanim_len0_invalid ); + return TRUE; + } + + // fetch length of coltab1 + int len1 = 0; + if ( colanim_key_value[ KEY_COLANI_LEN1 ].value != NULL ) { + if ( ScanKeyValueInt( &colanim_key_value[ KEY_COLANI_LEN1 ], &len1 ) < 0 ) { + CON_AddLine( colanim_len1_invalid ); + return TRUE; + } + if ( ( len1 < 1 ) || ( len1 > 256 ) ) { + CON_AddLine( colanim_len1_invalid ); + return TRUE; + } + } + + // check whether both len1 and coltab1 specified or none at all + if ( colanim_key_value[ KEY_COLANI_SRC1 ].value != NULL ) { + if ( len1 < 1 ) { + CON_AddLine( colanim_len1_missing ); + return TRUE; + } + } else { + if ( len1 > 0 ) { + CON_AddLine( colanim_tab1_missing ); + return TRUE; + } + } + + // parse mode if supplied + dword mode = COLANIM_SOURCEADD; + if ( colanim_key_value[ KEY_COLANI_MODE ].value != NULL ) { + char *modestr = colanim_key_value[ KEY_COLANI_MODE ].value; + if ( strcmp( modestr, colanim_mode_sourceadd ) == 0 ) { + mode = COLANIM_SOURCEADD; + } else if ( strcmp( modestr, colanim_mode_sourcemul ) == 0 ) { + mode = COLANIM_SOURCEMUL; + } else if ( strcmp( modestr, colanim_mode_sourcenocomb ) == 0 ) { + mode = COLANIM_SOURCENOCOMBINE; + } else { + CON_AddLine( colanim_mode_invalid ); + return TRUE; + } + } + + // reserve table memory (both tables in one block) + size_t tabsize = ( len0 + len1 ); + char *tabmem = (char *) ALLOCMEM( tabsize * sizeof( colfrm_s ) ); + if ( tabmem == NULL ) + OUTOFMEM( 0 ); + colfrm_s *coltab0 = (colfrm_s *) tabmem; + colfrm_s *coltab1 = ( len1 > 0 ) ? &coltab0[ len0 ] : NULL; + + // need tempmem for color lists (maximum four components per color) + size_t tempsize = max( len0, len1 ) * 4; + char *tempmem = (char *) ALLOCMEM( tempsize * sizeof( int ) ); + if ( tempmem == NULL ) + OUTOFMEM( 0 ); + int *intlist = (int *) tempmem; + + // parse coltab0 + char *coltab0str = colanim_key_value[ KEY_COLANI_SRC0 ].value; + if ( !ParseColorTable( coltab0str, coltab0, intlist, len0, 0 ) ) { + FREEMEM( tempmem ); + FREEMEM( tabmem ); + return TRUE; + } + + // parse coltab1 if supplied + char *coltab1str = colanim_key_value[ KEY_COLANI_SRC1 ].value; + if ( coltab1str != NULL ) { + if ( !ParseColorTable( coltab1str, coltab1, intlist, len1, 1 ) ) { + FREEMEM( tempmem ); + FREEMEM( tabmem ); + return TRUE; + } + } + + // init registration info + colanim_s colanim; + colanim.col_table0 = coltab0; + colanim.col_table1 = coltab1; + colanim.col_end0 = ( len0 - 1 ); + colanim.col_end1 = ( len1 > 0 ) ? ( len1 - 1 ) : 0; + colanim.col_flags = mode; + + colanimreg_s colanimreg; + colanimreg.name = colanimname; + colanimreg.colanim = colanim; + + // do registration + if ( !RegisterColAnim( &colanimreg ) ) { + + CON_AddLine( colanim_reg_failed ); + FREEMEM( tempmem ); + FREEMEM( tabmem ); + return TRUE; + } + + // free temporary mem + FREEMEM( tempmem ); + + return TRUE; +} + + + -- cgit v1.2.3