aboutsummaryrefslogtreecommitdiff
path: root/src/parsec/con_shad.cpp
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2026-08-24 11:16:07 +0200
committerFelix Morgner <felix.morgner@gmail.com>2026-08-24 11:16:07 +0200
commitc068f22329d5cc722622a2183bbb22eef2093df7 (patch)
tree12d56c1aede67988a55e241364606bfbb4dba933 /src/parsec/con_shad.cpp
downloadopenparsec-c068f22329d5cc722622a2183bbb22eef2093df7.tar.xz
openparsec-c068f22329d5cc722622a2183bbb22eef2093df7.zip
initial importHEADmain
Diffstat (limited to 'src/parsec/con_shad.cpp')
-rw-r--r--src/parsec/con_shad.cpp583
1 files changed, 583 insertions, 0 deletions
diff --git a/src/parsec/con_shad.cpp b/src/parsec/con_shad.cpp
new file mode 100644
index 0000000..44f374f
--- /dev/null
+++ b/src/parsec/con_shad.cpp
@@ -0,0 +1,583 @@
+/*
+ * PARSEC - Shader Commands
+ *
+ * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:35 $
+ *
+ * Orginally written by:
+ * Copyright (c) Markus Hadwiger <msh@parsec.org> 1999-2000
+ *
+ * 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 <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// compilation flags/debug support
+#include "config.h"
+#include "debug.h"
+
+// general definitions
+#include "general.h"
+#include "objstruc.h"
+
+// global externals
+#include "globals.h"
+
+// local module header
+#include "con_shad.h"
+
+// proprietary module headers
+#include "con_arg.h"
+#include "con_aux.h"
+#include "con_main.h"
+#include "e_colani.h"
+#include "e_shader.h"
+#include "obj_clas.h"
+#include "part_api.h"
+
+
+
+// generic string paste area --------------------------------------------------
+//
+#define PASTE_STR_LEN 255
+static char paste_str[ PASTE_STR_LEN + 1 ];
+
+
+// string constants -----------------------------------------------------------
+//
+static char invalid_lod[] = "invalid lod specification.";
+static char face_id_invalid[] = "face id invalid.";
+static char shader_name_missing[] = "name of shader must be specified.";
+static char shader_name_invalid[] = "shader name invalid.";
+static char shader_spec_invalid[] = "shader spec missing or invalid.";
+static char iter_base_invalid[] = "iter_base spec invalid.";
+static char iter_compose_invalid[] = "iter_compose spec invalid.";
+static char texanim_invalid[] = "texanim name invalid.";
+static char colanim_invalid[] = "colanim name invalid.";
+static char colanim_flags_invalid[] = "colanim mode spec invalid.";
+static char colanim_flags_ignored[] = "ignoring colanim mode spec.";
+static char facecolor_invalid[] = "face color invalid.";
+static char shader_reg_failed[] = "shader registration failed.";
+static char base_object_empty[] = "base object is empty.";
+
+
+// flag map for shader spec ---------------------------------------------------
+//
+static flag_map_s shader_flag_map[] = {
+
+ { "iter_constrgb", iter_constrgb, 0 },
+ { "iter_constrgba", iter_constrgba, 0 },
+ { "iter_rgb", iter_rgb, 0 },
+ { "iter_rgba", iter_rgba, 0 },
+ { "iter_texonly", iter_texonly, 0 },
+ { "iter_texconsta", iter_texconsta, 0 },
+ { "iter_texconstrgb", iter_texconstrgb, 0 },
+ { "iter_texconstrgba", iter_texconstrgba, 0 },
+ { "iter_texa", iter_texa, 0 },
+ { "iter_texrgb", iter_texrgb, 0 },
+ { "iter_texrgba", iter_texrgba, 0 },
+ { "iter_constrgbtexa", iter_constrgbtexa, 0 },
+ { "iter_constrgbatexa", iter_constrgbatexa, 0 },
+ { "iter_rgbtexa", iter_rgbtexa, 0 },
+ { "iter_rgbatexa", iter_rgbatexa, 0 },
+ { "iter_texblendrgba", iter_texblendrgba, 0 },
+ { "iter_texspeca", iter_texspeca, 0 },
+ { "iter_texspecrgb", iter_texspecrgb, 0 },
+ { "iter_texconstaspecrgb", iter_texconstaspecrgb, 0 },
+ { "iter_texconstrgbspeca", iter_texconstrgbspeca, 0 },
+ { "iter_texaspecrgb", iter_texaspecrgb, 0 },
+ { "iter_texrgbspeca", iter_texrgbspeca, 0 },
+
+ { "iter_overwrite", iter_overwrite, 1 },
+ { "iter_alphablend", iter_alphablend, 1 },
+ { "iter_modulate", iter_modulate, 1 },
+ { "iter_specularadd", iter_specularadd, 1 },
+ { "iter_premulblend", iter_premulblend, 1 },
+ { "iter_additiveblend", iter_additiveblend, 1 },
+
+ { "flag_texipolate", FACE_SHADING_TEXIPOLATE<<16, 2 },
+ { "flag_nodepthcmp", FACE_SHADING_NODEPTHCMP<<16, 2 },
+ { "flag_nodepthwrite", FACE_SHADING_NODEPTHWRITE<<16, 2 },
+ { "flag_draw_sorted", FACE_SHADING_DRAW_SORTED<<16, 2 },
+ { "flag_draw_last", FACE_SHADING_DRAW_LAST<<16, 2 },
+ { "flag_nobackcull", FACE_SHADING_NOBACKCULLING<<16, 2 },
+ { "flag_back_first", FACE_SHADING_BACK_FIRST<<16, 2 },
+
+ { NULL, 0, 0 },
+};
+
+
+// temporary shader for returning a shader specified in immediate mode --------
+//
+static shader_s result_shader;
+
+
+// parse global object shading spec -------------------------------------------
+//
+shader_s *DetermineODTShader( key_value_s *shaderspec )
+{
+ ASSERT( shaderspec != NULL );
+
+ shader_s *shader = NULL;
+
+ if ( shaderspec->value != NULL ) {
+
+ // try to interpret argument as shader name
+ shader = FetchShaderByName( shaderspec->value, NULL );
+ if ( shader != NULL )
+ return shader;
+
+ // use anonymous (temp) shader
+ shader = &result_shader;
+ memset( shader, 0, sizeof( shader_s ) );
+
+ // parse list, set corresponding bits
+ dword dwshader = 0x00000000;
+ if ( ScanKeyValueFlagList( shaderspec, &dwshader, shader_flag_map ) == 0 ) {
+ return NULL;
+ }
+
+ // check shader for consistency
+ dword base = dwshader & iter_base_mask;
+ dword comp = dwshader & iter_compose_mask;
+
+ // iter_base may be invalid if multiple specs or'ed together
+ if ( base > iter_texrgbspeca ) {
+ CON_AddLine( iter_base_invalid );
+ shader = NULL;
+ }
+ // iter_compose may be invalid if multiple specs or'ed together
+ if ( comp > iter_premulblend ) {
+ CON_AddLine( iter_compose_invalid );
+ shader = NULL;
+ }
+
+ // set immediate mode fields
+ if ( shader != NULL ) {
+ shader->iter = dwshader & 0xffff;
+ shader->flags = dwshader >> 16;
+ }
+ }
+
+ return shader;
+}
+
+
+// get description for shader (iter/flags part only) --------------------------
+//
+char *GetShaderDescription( dword shaderid )
+{
+ ASSERT( shaderid < (dword)num_registered_shaders );
+
+ shader_s *shader = &registered_shaders[ shaderid ];
+
+ dword base = (dword)shader->iter & iter_base_mask;
+ dword comp = (dword)shader->iter & iter_compose_mask;
+ dword flags = (dword)shader->flags << 16;
+
+ flag_map_s *basemap = NULL;
+ flag_map_s *compmap = NULL;
+
+ // get iter and compose description
+ flag_map_s *map = NULL;
+ for ( map = shader_flag_map; map->name != NULL; map++ ) {
+
+ switch ( map->group ) {
+
+ case 0:
+ if ( base == map->value )
+ basemap = map;
+ break;
+
+ case 1:
+ if ( comp == map->value )
+ compmap = map;
+ break;
+ }
+ }
+
+ strcpy( paste_str, ( basemap != NULL ) ? basemap->name : "base_invalid" );
+ strcat( paste_str, " " );
+ strcat( paste_str, ( compmap != NULL ) ? compmap->name : "comp_invalid" );
+
+ // append flags
+ for ( map = shader_flag_map; map->name != NULL; map++ ) {
+ if ( ( map->group == 2 ) && ( flags & map->value ) ) {
+ strcat( paste_str, " " );
+ strcat( paste_str, map->name );
+ }
+ }
+
+ return paste_str;
+}
+
+
+// key table for defshader specification --------------------------------------
+//
+key_value_s defshader_key_value[] = {
+
+ { "shader", NULL, KEYVALFLAG_PARENTHESIZE },
+ { "color", NULL, KEYVALFLAG_PARENTHESIZE },
+ { "texanim", NULL, KEYVALFLAG_PARENTHESIZE },
+ { "colanim", NULL, KEYVALFLAG_PARENTHESIZE },
+ { "colmode", NULL, KEYVALFLAG_NONE },
+
+ { NULL, NULL, KEYVALFLAG_NONE },
+};
+
+enum {
+
+ KEY_DEFSHAD_SHADER,
+ KEY_DEFSHAD_COLOR,
+ KEY_DEFSHAD_TEXANIM,
+ KEY_DEFSHAD_COLANIM,
+ KEY_DEFSHAD_COLMODE
+};
+
+
+// possible FaceAnimState::ColFlags modes (FACE_ANIM_BASExx) ------------------
+//
+static char colanim_mode_baseignore[] = "nobase";
+static char colanim_mode_baseadd[] = "add";
+static char colanim_mode_basemul[] = "mul";
+
+
+// command "shader.def" -------------------------------------------------------
+//
+int Cmd_DefShader( char *command )
+{
+ //NOTE:
+ //CONCOM:
+ // defshader_command ::= 'shader.def' <shader-name> [<shader-spec>] [<color>] [<anims>]
+ // shader_name ::= "may be parenthesized to include whitespace"
+ // shader_spec ::= 'shader' <shader-iter> | <shader-name>
+ // shader_iter ::= '(' 'iter_xx'* 'flag_xx'* ')'
+ // shader_name ::= "valid name of shader"
+ // color ::= 'color' '(' <int> <int> <int> [<int>] ')'
+ // anims ::= [<texanim>] [<colanim> [<colanim-mode>]]
+ // texanim ::= 'texanim' "valid name of texanim"
+ // colanim ::= 'colanim' "valid name of colanim"
+ // colanim_mode ::= 'colmode' 'add' | 'mul' | 'nobase'
+
+ 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 *shadername = strtok( command, " " );
+ if ( shadername == NULL ) {
+ CON_AddLine( shader_name_missing );
+ return TRUE;
+ }
+
+ // allow name to be parenthesized to include whitespace
+ shadername = GetParenthesizedName( shadername );
+ if ( shadername == NULL ) {
+ CON_AddLine( shader_name_invalid );
+ return TRUE;
+ }
+
+ // scan out all values to keys
+ if ( !ScanKeyValuePairs( defshader_key_value, NULL ) )
+ return TRUE;
+
+ // parse shader spec
+ shader_s *shader = DetermineODTShader( &defshader_key_value[ KEY_DEFSHAD_SHADER ] );
+ if ( shader == NULL ) {
+ CON_AddLine( shader_spec_invalid );
+ return TRUE;
+ }
+
+ //NOTE:
+ // if ( shader->name != NULL ) here, the shader has not been
+ // specified in immediate mode, but with an already existing
+ // shader name. this can be used for duplicating shaders.
+
+ word iter = shader->iter;
+ word flags = shader->flags;
+
+ colrgba_s facecolor;
+ memset( &facecolor, 0, sizeof( colrgba_s ) );
+
+ // check for constant face color specification
+ if ( defshader_key_value[ KEY_DEFSHAD_COLOR ].value != NULL ) {
+
+ int colspec[ 4 ];
+ colspec[ 3 ] = 255;
+
+ int numcomps =
+ ScanKeyValueIntList( &defshader_key_value[ KEY_DEFSHAD_COLOR ], colspec, 3, 4 );
+ if ( numcomps < 3 ) {
+ CON_AddLine( facecolor_invalid );
+ return TRUE;
+ }
+
+ if ( ( (dword)colspec[ 0 ] > 255 ) || ( (dword)colspec[ 1 ] > 255 ) ||
+ ( (dword)colspec[ 2 ] > 255 ) || ( (dword)colspec[ 3 ] > 255 ) ) {
+ CON_AddLine( facecolor_invalid );
+ return TRUE;
+ }
+
+ facecolor.R = colspec[ 0 ];
+ facecolor.G = colspec[ 1 ];
+ facecolor.B = colspec[ 2 ];
+ facecolor.A = colspec[ 3 ];
+
+ // set flag to use face color
+ flags |= FACE_SHADING_FACECOLOR;
+ }
+
+ // acquire texanim if name specified
+ texanim_s *texanim = NULL;
+ if ( defshader_key_value[ KEY_DEFSHAD_TEXANIM ].value != NULL ) {
+
+ texanim = PRT_AcquireParticleDefinition(
+ defshader_key_value[ KEY_DEFSHAD_TEXANIM ].value, NULL );
+ if ( texanim == NULL ) {
+ CON_AddLine( texanim_invalid );
+ return TRUE;
+ }
+ }
+
+ // acquire colanim if name specified
+ colanim_s *colanim = NULL;
+ if ( defshader_key_value[ KEY_DEFSHAD_COLANIM ].value != NULL ) {
+
+ colanimreg_s *colanimreg = FetchColAnim(
+ defshader_key_value[ KEY_DEFSHAD_COLANIM ].value, NULL );
+ if ( colanimreg == NULL ) {
+ CON_AddLine( colanim_invalid );
+ return TRUE;
+ }
+ colanim = &colanimreg->colanim;
+
+ // set flag to use face color
+ flags |= FACE_SHADING_FACECOLOR;
+ }
+
+ // fetch colanim mode
+ dword colmode = FACE_ANIM_BASEIGNORE;
+ if ( defshader_key_value[ KEY_DEFSHAD_COLMODE ].value != NULL ) {
+
+ if ( colanim != NULL ) {
+ char *modespec = defshader_key_value[ KEY_DEFSHAD_COLMODE ].value;
+ if ( strcmp( modespec, colanim_mode_baseadd ) == 0 ) {
+ colmode = FACE_ANIM_BASEADD;
+ } else if ( strcmp( modespec, colanim_mode_basemul ) == 0 ) {
+ colmode = FACE_ANIM_BASEMUL;
+ } else if ( strcmp( modespec, colanim_mode_baseignore ) == 0 ) {
+ colmode = FACE_ANIM_BASEIGNORE;
+ } else {
+ CON_AddLine( colanim_flags_invalid );
+ return TRUE;
+ }
+ } else {
+ CON_AddLine( colanim_flags_ignored );
+ }
+ }
+
+ shader_s newshader;
+ newshader.iter = iter;
+ newshader.flags = flags;
+ newshader.name = shadername;
+ newshader.facecolor = facecolor;
+ newshader.texanim = texanim;
+ newshader.colanim = colanim;
+ newshader.colflags = colmode;
+
+ // register shader
+ if ( !RegisterShader( &newshader ) ) {
+ CON_AddLine( shader_reg_failed );
+ }
+
+ return TRUE;
+}
+
+
+// key table for setshader specification --------------------------------------
+//
+key_value_s setshader_key_value[] = {
+
+ { "class", NULL, KEYVALFLAG_PARENTHESIZE },
+ { "id", NULL, KEYVALFLAG_NONE },
+ { "shader", NULL, KEYVALFLAG_PARENTHESIZE },
+ { "texture", NULL, KEYVALFLAG_PARENTHESIZE },
+ { "faceid", NULL, KEYVALFLAG_PARENTHESIZE },
+ { "lod", NULL, KEYVALFLAG_NONE },
+
+ { NULL, NULL, KEYVALFLAG_NONE },
+};
+
+enum {
+
+ KEY_SETSHAD_CLASS,
+ KEY_SETSHAD_ID,
+ KEY_SETSHAD_SHADER,
+ KEY_SETSHAD_TEXTURE,
+ KEY_SETSHAD_FACEID,
+ KEY_SETSHAD_LOD
+};
+
+
+// command "shader.set" to overwrite specified (object,face)'s shader spec ----
+//
+int Cmd_SetShader( char *command )
+{
+ //NOTE:
+ //CONCOM:
+ // setshader_command ::= 'shader.set' <class-spec> <shader-spec> [<face-spec>]
+ // class_spec ::= <class-name> | <class-id> [<lod-spec>]
+ // class_name ::= 'class' <name>
+ // class_id ::= 'id' <int>
+ // lod_spec ::= 'lod' <int>
+ // shader_spec ::= 'shader' <shader-iter> | <shader-name>
+ // shader_iter ::= '(' 'iter_xx'* 'flag_xx'* ')'
+ // shader_name ::= "valid name of shader"
+ // face_spec ::= <tex-spec> | <face-id-spec>
+ // tex_spec ::= 'texture' <texture-name>
+ // face_id_spec ::= 'faceid' <face-id> | <face-id-list>
+ // face_id_list ::= '(' <face-id>+ ')'
+
+ ASSERT( command != NULL );
+ HANDLE_COMMAND_DOMAIN_SEP( command );
+
+ // this flag is used during internal data reloads
+ if ( AUX_ALLOW_ONLY_TEXTURE_LOADING ) {
+ return TRUE;
+ }
+
+ // scan out all values to keys
+ if ( !ScanKeyValuePairs( setshader_key_value, command ) )
+ return TRUE;
+
+ // get object class (either name or id)
+ dword objclass = ScanKeyValueObjClass( setshader_key_value, KEY_SETSHAD_CLASS, KEY_SETSHAD_ID );
+ if ( objclass == CLASS_ID_INVALID ) {
+ return TRUE;
+ }
+
+ GenObject *gobj = ObjClasses[ objclass ];
+
+ // guard against empty base objects
+ if ( gobj->NumFaces == 0 ) {
+ CON_AddLine( base_object_empty );
+ return TRUE;
+ }
+
+ // highest allowed face id
+ dword maxfaceid = gobj->NumFaces - 1;
+
+ // parse (optional) lod spec
+ int lod = 0;
+ if ( setshader_key_value[ KEY_SETSHAD_LOD ].value != NULL ) {
+ if ( ScanKeyValueInt( &setshader_key_value[ KEY_SETSHAD_LOD ], &lod ) < 0 ) {
+ CON_AddLine( invalid_lod );
+ return TRUE;
+ }
+ if ( lod != 0 ) {
+ if ( ( lod >= gobj->NumLodObjects ) ||
+ ( -lod >= gobj->NumLodObjects ) ) {
+ CON_AddLine( invalid_lod );
+ return TRUE;
+ }
+ // check will be made for
+ // each lod individually
+ maxfaceid = 100000;
+ }
+ }
+
+ // parse shader spec
+ shader_s *shader = DetermineODTShader( &setshader_key_value[ KEY_SETSHAD_SHADER ] );
+ if ( shader == NULL ) {
+ CON_AddLine( shader_spec_invalid );
+ return TRUE;
+ }
+
+ // set shader for single face or list of faces specified via id
+ char *faceidstr = setshader_key_value[ KEY_SETSHAD_FACEID ].value;
+ if ( faceidstr != NULL ) {
+
+ // try list first
+ while ( *faceidstr == ' ' )
+ faceidstr++;
+ while ( ( *faceidstr != 0 ) && ( *faceidstr != ' ' ) && ( *faceidstr != '-' ) )
+ faceidstr++;
+ while ( *faceidstr == ' ' )
+ faceidstr++;
+ if ( *faceidstr != 0 ) {
+
+ // read list of ids
+ int *faceids = (int *) ALLOCMEM( 512 * sizeof( int ) );
+ if ( faceids == NULL )
+ OUTOFMEM( 0 );
+ int cnt = ScanKeyValueIntListBounded(&setshader_key_value[ KEY_SETSHAD_FACEID ], faceids, 2, 512, 0, maxfaceid );
+ if ( cnt > 0 ) {
+ if (override_arg_faceids != NULL)
+ FREEMEM(override_arg_faceids);
+
+ override_arg_faceids = (dword *) faceids;
+ override_arg_count = cnt;
+ OverrideShaderLodFaces( objclass, shader, lod, OVERRIDE_ARG_IDLIST );
+ } else {
+ CON_AddLine( face_id_invalid );
+ FREEMEM(faceids);
+ }
+ return TRUE;
+ }
+
+ // read single id
+ int * faceid = (int *) ALLOCMEM(sizeof(int));
+ if ( ScanKeyValueInt( &setshader_key_value[ KEY_SETSHAD_FACEID ], faceid ) < 0 ) {
+ CON_AddLine( face_id_invalid );
+ FREEMEM(faceid);
+ return TRUE;
+ }
+ if ( ( *faceid < 0 ) || ( *faceid > (int)maxfaceid ) ) {
+ CON_AddLine( face_id_invalid );
+ FREEMEM(faceid);
+ return TRUE;
+ }
+
+ if (override_arg_faceids != NULL)
+ FREEMEM(override_arg_faceids);
+
+ override_arg_faceids = (dword *) faceid;
+ override_arg_count = 1;
+ OverrideShaderLodFaces( objclass, shader, lod, OVERRIDE_ARG_IDLIST );
+ return TRUE;
+ }
+
+ // set shader for set of faces specified via texture name
+ if ( setshader_key_value[ KEY_SETSHAD_TEXTURE ].value != NULL ) {
+ override_arg_texname = setshader_key_value[ KEY_SETSHAD_TEXTURE ].value;
+ OverrideShaderLodFaces( objclass, shader, lod, OVERRIDE_ARG_TEXTURE );
+ return TRUE;
+ }
+
+ // set shader for all faces of object
+ OverrideShaderLodFaces( objclass, shader, lod, OVERRIDE_ARG_GLOBAL );
+
+ return TRUE;
+}
+
+
+