From 1da0bd681bb645a14514fbf9595c4ba21c15f2d2 Mon Sep 17 00:00:00 2001 From: jmbau <30726620+jmbau@users.noreply.github.com> Date: Mon, 9 Oct 2023 10:37:18 +0200 Subject: [PATCH] Humans enhancement (#46) * Improves humans. - Add a 'Gender' parameter in /data/humans.ini - Body shape now depends of weight and gender (very basic Body Mass Index use) - Up to 4 assistants instead of 1 per victim - Victim and assistant(s) can now be any of defined human, and not only blue/red and green guys - Documentation updated * Whitespace and encoding cleanups --------- Co-authored-by: Hector Sanjuan --- data/human.ini | 235 +++++++++-- docs/sar2ParmsBook/sar2ParmsDescription.js | 8 +- src/config.h | 1 + src/human.c | 65 +-- src/human.h | 9 +- src/humanio.c | 71 +++- src/obj.h | 52 ++- src/objio.c | 4 +- src/sardraw.c | 2 +- src/sardrawhuman.c | 459 +++++++++++++++------ src/sarfio.h | 2 + src/sarfioopen.c | 60 ++- src/sarfiosave.c | 10 + src/simop.c | 8 +- src/simutils.c | 11 +- 15 files changed, 740 insertions(+), 257 deletions(-) diff --git a/data/human.ini b/data/human.ini index 407e522..085af53 100644 --- a/data/human.ini +++ b/data/human.ini @@ -13,57 +13,202 @@ # All color values have arguments in the order of rgba. # # Height specifies the height of the human from toe to head in meters. +# Human drawing "size" is relative to height and mass. Note that drawing +# is -of course- approximative, and sometimes it needs to "cheat" +# on one parameter to obtain better drawing (example: baby_1 mass). +# If not set, default gender is male. If gender is female, breasts +# are drawn on human torso. # +# File version number. +Version = 1 1 + # First entry is always the default, it may be used whenever nothing # in particular is requested. PresetAdd = default - Height = 1.9 - Mass = 54.0 - ColorPaletteSelect = Standard - ColorFace = 0.847 0.615 0.447 1.00 - ColorHair = 0.30 0.24 0.19 1.00 - ColorTorso = 0.95 0.22 0.18 1.00 - ColorHips = 0.20 0.20 0.20 1.00 - ColorLegs = 0.80 0.78 0.75 1.00 - ColorFeet = 0.30 0.30 0.30 1.00 - ColorArms = 0.20 0.20 1.00 1.00 - ColorHands = 0.847 0.615 0.447 1.00 + Height = 1.9 + Mass = 90.0 + Gender = Male + ColorPaletteSelect = Standard + ColorFace = 0.847 0.615 0.447 1.0 + ColorHair = 0.300 0.240 0.190 1.0 + ColorTorso = 0.950 0.220 0.180 1.0 + ColorHips = 0.200 0.200 0.200 1.0 + ColorLegs = 0.800 0.780 0.750 1.0 + ColorFeet = 0.300 0.300 0.300 1.0 + ColorArms = 0.200 0.200 1.000 1.0 + ColorHands = 0.847 0.615 0.447 1.0 -# Diver (used for drawing at end of hoist rope). +# Diver (only for drawing at end of hoist rope). PresetAdd = diver - Height = 1.9 - Mass = 54.0 - ColorPaletteSelect = Standard - ColorFace = 0.847 0.615 0.447 1.00 - ColorHair = 0.10 0.20 0.60 1.00 - ColorTorso = 0.10 0.20 0.60 1.00 - ColorHips = 0.10 0.20 0.60 1.00 - ColorLegs = 0.10 0.20 0.60 1.00 - ColorFeet = 0.10 0.20 0.60 1.00 - ColorArms = 0.10 0.20 0.60 1.00 - ColorHands = 0.847 0.615 0.447 1.00 +# Hard-coded data: +# Height = 1.9 +# Mass = 90.0 +# Gender = Male + ColorPaletteSelect = Standard + ColorFace = 0.847 0.615 0.447 1.0 + ColorHair = 0.100 0.200 0.600 1.0 + ColorTorso = 0.100 0.200 0.600 1.0 + ColorHips = 0.100 0.200 0.600 1.0 + ColorLegs = 0.100 0.200 0.600 1.0 + ColorFeet = 0.100 0.200 0.600 1.0 + ColorArms = 0.100 0.200 0.600 1.0 + ColorHands = 0.847 0.615 0.447 1.0 -# Victim intended to be on a streatcher with one assisting human. +# For backward compatibility : victim intended to be on a stretcher with +# one assisting human. Note that only color can be be modified and will be +# applied to all (1 to 4) assisting humans. PresetAdd = victim_streatcher_assisted - Height = 1.9 - Mass = 54.0 - AssistingHumans = 1 - ColorPaletteSelect = Standard - ColorFace = 0.847 0.615 0.447 1.00 - ColorHair = 0.30 0.24 0.19 1.00 - ColorTorso = 0.95 0.22 0.18 1.00 - ColorHips = 0.20 0.20 0.20 1.00 - ColorLegs = 0.80 0.78 0.75 1.00 - ColorFeet = 0.30 0.30 0.30 1.00 - ColorArms = 0.20 0.20 1.00 1.00 - ColorHands = 0.847 0.615 0.447 1.00 - ColorPaletteSelect = AssistingHuman - ColorFace = 0.847 0.615 0.447 1.00 - ColorHair = 0.30 0.24 0.19 1.00 - ColorTorso = 0.21 0.95 0.20 1.00 - ColorHips = 0.70 0.70 0.70 1.00 - ColorLegs = 0.70 0.70 0.70 1.00 - ColorFeet = 0.30 0.30 0.30 1.00 - ColorArms = 0.21 0.95 0.20 1.00 - ColorHands = 0.94 0.92 0.9 1.00 + Height = 1.9 + Mass = 90.0 + AssistingHumans = 1 + ColorPaletteSelect = Standard + ColorFace = 0.847 0.615 0.447 1.0 + ColorHair = 0.300 0.240 0.190 1.0 + ColorTorso = 0.950 0.220 0.180 1.0 + ColorHips = 0.200 0.200 0.200 1.0 + ColorLegs = 0.800 0.780 0.750 1.0 + ColorFeet = 0.300 0.300 0.300 1.0 + ColorArms = 0.200 0.200 1.000 1.0 + ColorHands = 0.847 0.615 0.447 1.0 + ColorPaletteSelect = AssistingHuman + ColorFace = 0.847 0.615 0.447 1.0 + ColorHair = 0.300 0.240 0.190 1.0 + ColorTorso = 0.210 0.950 0.200 1.0 + ColorHips = 0.700 0.700 0.700 1.0 + ColorLegs = 0.700 0.700 0.700 1.0 + ColorFeet = 0.300 0.300 0.300 1.0 + ColorArms = 0.210 0.950 0.200 1.0 + ColorHands = 0.940 0.920 0.900 1.0 + +# Default assisting human. +PresetAdd = assistant_1 + Height = 1.9 + Mass = 90.0 + Gender = Male + ColorPaletteSelect = Standard + ColorFace = 0.847 0.615 0.447 1.0 + ColorHair = 0.300 0.240 0.190 1.0 + ColorTorso = 0.210 0.950 0.200 1.0 + ColorHips = 0.700 0.700 0.700 1.0 + ColorLegs = 0.700 0.700 0.700 1.0 + ColorFeet = 0.300 0.300 0.300 1.0 + ColorArms = 0.210 0.950 0.200 1.0 + ColorHands = 0.940 0.920 0.900 1.0 + +# An old black man, with hairs +PresetAdd = man_1 + Height = 1.75 + Mass = 80.0 + Gender = Male + ColorPaletteSelect = Standard + ColorFace = 0.304 0.206 0.206 1.0 + ColorHair = 0.900 0.900 0.900 1.0 + ColorTorso = 0.900 0.900 0.900 1.0 + ColorHips = 0.950 0.220 0.180 1.0 + ColorLegs = 0.950 0.220 0.180 1.0 + ColorFeet = 0.100 0.100 0.100 1.0 + ColorArms = 0.900 0.900 0.900 1.0 + ColorHands = 0.304 0.206 0.206 1.0 + +# An old white man, without hairs (ColorHair alpha value set to 0.0) +PresetAdd = man_2 + Height = 1.90 + Mass = 90.0 + Gender = Male + ColorPaletteSelect = Standard + ColorFace = 0.847 0.615 0.447 1.0 + ColorHair = 0.900 0.900 0.900 0.0 + ColorTorso = 0.576 0.174 0.724 1.0 + ColorHips = 0.194 0.369 0.723 1.0 + ColorLegs = 0.194 0.369 0.723 1.0 + ColorFeet = 0.315 0.157 0.157 1.0 + ColorArms = 0.576 0.174 0.724 1.0 + ColorHands = 0.847 0.615 0.447 1.0 + +# A 10 years old white girl +# Note that if gender had been defined and set to Female, girl would have breast. +PresetAdd = girl_1 + Height = 1.33 + Mass = 28.0 + ColorPaletteSelect = Standard + ColorFace = 0.847 0.615 0.447 1.0 + ColorHair = 0.932 0.938 0.548 1.0 + ColorTorso = 0.900 0.900 0.900 1.0 + ColorHips = 0.951 0.670 0.969 1.0 + ColorLegs = 0.847 0.615 0.447 1.0 + ColorFeet = 0.951 0.670 0.969 1.0 + ColorArms = 0.847 0.615 0.447 1.0 + ColorHands = 0.847 0.615 0.447 1.0 + +# A 10 years old black boy +PresetAdd = boy_1 + Height = 1.33 + Mass = 28.0 + ColorPaletteSelect = Standard + ColorFace = 0.304 0.206 0.206 1.0 + ColorHair = 0.123 0.123 0.123 1.0 + ColorTorso = 1.000 0.554 0.000 1.0 + ColorHips = 0.194 0.369 0.723 1.0 + ColorLegs = 0.194 0.369 0.723 1.0 + ColorFeet = 0.900 0.900 0.900 1.0 + ColorArms = 1.000 0.554 0.000 1.0 + ColorHands = 0.304 0.206 0.206 1.0 + +# A black woman +PresetAdd = woman_1 + Height = 1.70 + Mass = 60.0 + Gender = Female + ColorPaletteSelect = Standard + ColorFace = 0.304 0.206 0.206 1.0 + ColorHair = 0.123 0.123 0.123 1.0 + ColorTorso = 0.900 0.900 0.900 1.0 + ColorHips = 0.900 0.900 0.900 1.0 + ColorLegs = 0.900 0.900 0.900 1.0 + ColorFeet = 0.950 0.220 0.180 1.0 + ColorArms = 0.304 0.206 0.206 1.0 + ColorHands = 0.304 0.206 0.206 1.0 + +# A white woman +PresetAdd = woman_2 + Height = 1.65 + Mass = 56.0 + Gender = Female + ColorPaletteSelect = Standard + ColorFace = 0.847 0.615 0.447 1.0 + ColorHair = 0.919 0.292 0.191 1.0 + ColorTorso = 0.335 0.198 0.210 1.0 + ColorHips = 0.335 0.198 0.210 1.0 + ColorLegs = 0.847 0.615 0.447 1.0 + ColorFeet = 0.335 0.198 0.210 1.0 + ColorArms = 0.847 0.615 0.447 1.0 + ColorHands = 0.847 0.615 0.447 1.0 + +# A white baby +PresetAdd = baby_1 + Height = 0.50 + Mass = 7.0 + ColorPaletteSelect = Standard + ColorFace = 0.980 0.820 0.733 1.0 + ColorHair = 0.304 0.206 0.206 1.0 + ColorTorso = 0.460 0.773 0.796 1.0 + ColorHips = 0.460 0.773 0.796 1.0 + ColorLegs = 0.460 0.773 0.796 1.0 + ColorFeet = 0.980 0.820 0.733 1.0 + ColorArms = 0.460 0.773 0.796 1.0 + ColorHands = 0.980 0.820 0.733 1.0 + +# A fat boy with a turquoise cap and yellow gloves +PresetAdd = Boy_2 + Height = 1.20 + Mass = 60.0 + ColorPaletteSelect = Standard + ColorFace = 0.992 0.859 0.706 1.0 + ColorHair = 0.294 0.710 0.749 1.0 + ColorTorso = 0.843 0.125 0.250 1.0 + ColorHips = 0.843 0.125 0.250 1.0 + ColorLegs = 0.470 0.278 0.227 1.0 + ColorFeet = 0.192 0.188 0.208 1.0 + ColorArms = 0.843 0.125 0.250 1.0 + ColorHands = 0.969 0.882 0.039 1.0 diff --git a/docs/sar2ParmsBook/sar2ParmsDescription.js b/docs/sar2ParmsBook/sar2ParmsDescription.js index 8a68f73..8645459 100644 --- a/docs/sar2ParmsBook/sar2ParmsDescription.js +++ b/docs/sar2ParmsBook/sar2ParmsDescription.js @@ -789,8 +789,8 @@ __Creates a human.\ __ARGUMENTS\ __type_name
\ __default default human. May be used whenever nothing in particular is requested.\ -__victim_streatcher_assisted male victim intended to be on a stretcher with 1 assisting human. Warning: this type name is deprecated.\ -__.........(other type name)......... Warning: SaR II > 2.5.0 only! See data/human.ini file for other preset human types.\ +__.......(other type name)....... See data/human.ini file for other allowed preseted names.\ +__victim_streatcher_assisted Warning: this type name is deprecated. Victim intended to be on a stretcher with 1 assisting human.\ __flags
\ __need_rescue this human needs to be rescued (player has to take him aboard).\ __sit_up human is drawn sitting 'like on a chair', feet on the floor.\ @@ -801,7 +801,7 @@ __alert human is alert (is awake) and moves his arms to draw attention.\ __aware human is aware (knows of surroundings).\ __in_water human swims (moves his arms to float).\ __on_stretcher if this flag is specified, a stretcher is drawn below the human.\ -__assisted  n  type_name(s) Warning: SaR II > 2.5.0 only! human is assisted (surrounded) by 'n' (1 to 4) humans. Number 'n' must be followed by 'n' human type names.\ +__assisted  n  type_name(s) Warning: SaR II > 2.6.0 only! human is assisted (surrounded) by 'n' (1 to 4) humans. Number 'n' must be followed by 'n' human type names.\ __CONTEXT\ __mis scn\ __EXAMPLE\ @@ -811,7 +811,7 @@ __# Human position.\ __# If human 'z' position is greater than the ground / water / object which is under him, human will 'fall' until he comes into contact.\ __translate 30000.0 41020.0 0.0\ __...\ -__# Warning: SaR II > 2.5.0 only! Human lying on a strecher, with 2 assisting humans.\ +__# Warning: SaR II > 2.6.0 only! Human lying on a strecher, with 2 assisting humans.\ __create_human boy_1 need_rescue lying on_stretcher assisted 2 assistant_1 woman_1\ __translate 20000.0 41020.0 0.0\ __...\ diff --git a/src/config.h b/src/config.h index e6420d0..3f16ad9 100644 --- a/src/config.h +++ b/src/config.h @@ -653,6 +653,7 @@ to the fullest extent of the law." */ #define SAR_HUMAN_PRESET_NAME_STANDARD "standard" #define SAR_HUMAN_PRESET_NAME_DIVER "diver" +#define SAR_HUMAN_PRESET_NAME_ASSISTING_HUMAN "assistant_1" /* diff --git a/src/human.c b/src/human.c index 47bd32a..058c150 100644 --- a/src/human.c +++ b/src/human.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include "../include/string.h" @@ -36,7 +36,7 @@ sar_human_data_struct *SARHumanPresetsInit(void *core_ptr); void SARHumanPresetsShutdown(sar_human_data_struct *hd); void SARHumanEntryDelete( - sar_human_data_struct *hd, sar_human_data_entry_struct *entry + sar_human_data_struct *hd, sar_human_data_entry_struct *entry ); int SARHumanCreate( @@ -44,12 +44,14 @@ int SARHumanCreate( sar_scene_struct *scene, sar_object_struct ***object, int *total_objects, sar_obj_flags_t human_flags, + int assisting_humans, + const char *assisting_human_preset_name[SAR_ASSISTING_HUMANS_MAX], const char *name ); void SARHumanSetObjectPreset( - sar_human_data_struct *hd, - sar_object_struct *obj_ptr, - const char *name + sar_human_data_struct *hd, + sar_object_struct *obj_ptr, + const char *name ); @@ -75,7 +77,7 @@ void SARHumanSetObjectPreset( * Can return NULL on failed match or error. */ sar_human_data_entry_struct *SARHumanMatchEntryByName( - sar_human_data_struct *hd, const char *name + sar_human_data_struct *hd, const char *name ) { int i; @@ -152,7 +154,7 @@ void SARHumanPresetsShutdown(sar_human_data_struct *hd) * resources. */ void SARHumanEntryDelete( - sar_human_data_struct *hd, sar_human_data_entry_struct *entry + sar_human_data_struct *hd, sar_human_data_entry_struct *entry ) { if(entry == NULL) @@ -174,10 +176,12 @@ void SARHumanEntryDelete( */ int SARHumanCreate( sar_human_data_struct *hd, - sar_scene_struct *scene, - sar_object_struct ***object, int *total_objects, + sar_scene_struct *scene, + sar_object_struct ***object, int *total_objects, sar_obj_flags_t human_flags, - const char *name + int assisting_humans, + const char *assisting_human_preset_name[SAR_ASSISTING_HUMANS_MAX], + const char *name ) { int obj_num; @@ -237,7 +241,14 @@ int SARHumanCreate( human->intercepting_object_distance3d = 0.0; /* Number of assisting humans */ - human->assisting_humans = 0; + human->assisting_humans = assisting_humans; + + /* Assisting humans preset(s) */ + if (human->assisting_humans) + { + for(int i = 0; i < human->assisting_humans; i++) + human->assisting_human_preset_name[i] = assisting_human_preset_name[i]; + } /* Model human object values to preset values from the human * data presets. @@ -259,9 +270,9 @@ int SARHumanCreate( * then no operation will be performed. */ void SARHumanSetObjectPreset( - sar_human_data_struct *hd, - sar_object_struct *obj_ptr, - const char *name + sar_human_data_struct *hd, + sar_object_struct *obj_ptr, + const char *name ) { sar_object_human_struct *human; @@ -295,15 +306,23 @@ void SARHumanSetObjectPreset( /* Weight in kg */ human->mass = entry->mass; - /* Number of assisting humans */ - human->assisting_humans = entry->assisting_humans; - - /* Color palette for assisting humans */ - memcpy( - &human->assisting_human_color[0], - &entry->assisting_human_color[0], - SAR_HUMAN_COLORS_MAX * sizeof(sar_color_struct) - ); + /* Gender */ + if(entry->preset_entry_flags & SAR_HUMAN_FLAG_GENDER_FEMALE) + human->flags |= SAR_HUMAN_FLAG_GENDER_FEMALE; + + /* Number of assisting humans. Do not overwrite if assisting_humans + * number has been defined earlier by a create_human parameter. + */ + if(human->assisting_humans == 0) + human->assisting_humans = entry->assisting_humans; + + /* Color palette for assisting humans */ + memcpy( + &human->assisting_human_color[0], + &entry->assisting_human_color[0], + SAR_HUMAN_COLORS_MAX * sizeof(sar_color_struct) + ); + /* Add support for other things that need to be coppied here */ diff --git a/src/human.h b/src/human.h index 9578653..258648d 100644 --- a/src/human.h +++ b/src/human.h @@ -15,7 +15,7 @@ ***********************************************************************/ /* - Human Preset Data + Human Preset Data */ #ifndef HUMAN_H @@ -24,7 +24,6 @@ #include #include "obj.h" /* For SAR_HUMAN_COLOR_* definations */ - /* * Human Presets Data Entry: */ @@ -38,12 +37,14 @@ typedef struct { /* Height in meters */ float height; + /* For gender SAR_HUMAN_FLAG_GENDER_FEMALE (see obj.h). */ + sar_obj_flags_t preset_entry_flags; + /* Color palette */ sar_color_struct color[SAR_HUMAN_COLORS_MAX]; /* Number of assisting humans (0 for none) */ int assisting_humans; - /* Assisting human color palette */ sar_color_struct assisting_human_color[SAR_HUMAN_COLORS_MAX]; @@ -81,6 +82,8 @@ extern int SARHumanCreate( sar_scene_struct *scene, sar_object_struct ***object, int *total_objects, sar_obj_flags_t human_flags, + int assisting_humans, + const char *assisting_human_preset_name[SAR_ASSISTING_HUMANS_MAX], const char *name ); extern void SARHumanSetObjectPreset( diff --git a/src/humanio.c b/src/humanio.c index 705ffec..74b5a26 100644 --- a/src/humanio.c +++ b/src/humanio.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include "../include/fio.h" @@ -55,6 +55,7 @@ int SARHumanLoadFromFile(sar_human_data_struct *hd, const char *filename); int SARHumanLoadFromFile(sar_human_data_struct *hd, const char *filename) { int i; + int version_major, version_minor; FILE *fp; char *buf = NULL; struct stat stat_buf; @@ -78,16 +79,16 @@ int SARHumanLoadFromFile(sar_human_data_struct *hd, const char *filename) /* Check if the file exists and get its stats */ if(stat(filename, &stat_buf)) { - char *s = STRDUP(strerror(errno)); - if(s == NULL) - s = STRDUP("no such file"); - *s = toupper(*s); - fprintf( - stderr, - "%s: %s.\n", - filename, s - ); - free(s); + char *s = STRDUP(strerror(errno)); + if(s == NULL) + s = STRDUP("no such file"); + *s = toupper(*s); + fprintf( + stderr, + "%s: %s.\n", + filename, s + ); + free(s); return(-1); } #ifdef S_ISDIR @@ -122,6 +123,13 @@ int SARHumanLoadFromFile(sar_human_data_struct *hd, const char *filename) (_p_)->a = (float)value[3]; \ } } + /* Set version default values. + * Historically first human.ini file had no version number: + * this version will be named "1.0". + */ + version_major = 1; + version_minor = 0; + do { buf = FSeekNextParm( @@ -135,18 +143,17 @@ int SARHumanLoadFromFile(sar_human_data_struct *hd, const char *filename) /* Begin handling parameter */ - /* Version */ + /* File version */ if(!strcasecmp(buf, "Version")) { FGetValuesF(fp, value, 2); - - /* Ignore */ + version_major = (int)value[0]; + version_minor = (int)value[1]; } /* PresetAdd */ else if(!strcasecmp(buf, "PresetAdd")) { char *s = FGetString(fp); - /* Reset context pointers */ hdp_ptr = NULL; palette_ptr = NULL; @@ -168,9 +175,11 @@ int SARHumanLoadFromFile(sar_human_data_struct *hd, const char *filename) ); hdp_ptr->name = STRDUP(s); + /* Set gender to default value (male) for current preset. */ + hdp_ptr->preset_entry_flags &= ~SAR_HUMAN_FLAG_GENDER_FEMALE; + free(s); } - /* Height */ else if(!strcasecmp(buf, "Height")) { @@ -184,19 +193,43 @@ int SARHumanLoadFromFile(sar_human_data_struct *hd, const char *filename) else if(!strcasecmp(buf, "Mass")) { FGetValuesF(fp, value, 1); + + /* Mass for a 1.90m tall human was set to 54kg in original + * "Version 1.0" human.ini file. It was certainly an error, so + * let's overwrite it to 90kg. + */ + if(version_major == 1 && version_minor == 0) + value[0] = 90; + if(hdp_ptr != NULL) { hdp_ptr->mass = (float)MAX(value[0], 0.0); /* kg */ } } + /* Gender */ + else if(!strcasecmp(buf, "Gender")) + { + /* Male is default gender. + * If Female, breasts will be drawn on torso. + */ + + char *s = FGetString(fp); + if( (s != NULL) && (hdp_ptr != NULL) ) + { + if( !strcasecmp(s, "Female") || !strcasecmp(s, "female") ) + hdp_ptr->preset_entry_flags |= SAR_HUMAN_FLAG_GENDER_FEMALE; + else + /* default */ + hdp_ptr->preset_entry_flags &= ~SAR_HUMAN_FLAG_GENDER_FEMALE; + } + free(s); + } /* AssistingHumans */ else if(!strcasecmp(buf, "AssistingHumans")) { FGetValuesF(fp, value, 1); if(hdp_ptr != NULL) - { - hdp_ptr->assisting_humans = MAX((int)value[0], 0); - } + hdp_ptr->assisting_humans = CLIP((int)value[0], 0, SAR_ASSISTING_HUMANS_MAX); } diff --git a/src/obj.h b/src/obj.h index ba75e80..edb466e 100644 --- a/src/obj.h +++ b/src/obj.h @@ -160,7 +160,7 @@ typedef struct { /* * Position/Velocity: * - * Each member must be of type float and their order is + * Each member must be of type float and their order is * important. * * When used as position the units are in meters, when used as @@ -268,7 +268,7 @@ typedef enum { SAR_CRASH_TYPE_OBSTRUCTION, SAR_CRASH_TYPE_GROUND, SAR_CRASH_TYPE_MOUNTAIN, /* To be more specific than - * just ground */ + * just ground */ SAR_CRASH_TYPE_BUILDING, SAR_CRASH_TYPE_AIRCRAFT, /* Not used */ SAR_CRASH_TYPE_FIRE @@ -483,7 +483,7 @@ typedef struct { pos_cen, pos_max; - /* Direction, dir_min and dir_max are deltas relative to + /* Direction, dir_min and dir_max are deltas relative to * dir_cen * * Note that some part types interprite these values differently @@ -890,7 +890,7 @@ typedef struct { sar_engine_state engine_state; time_t next_engine_on; /* Time till engine starts up (in ms) */ - /* Throttle control position. In aircraft flight model this is + /* Throttle control position. In aircraft flight model this is * the actual throttle control position, in helicopter flight * model this is the speed at which the rotors are spinning. * Range is from 0.0 to 1.0 @@ -1135,7 +1135,7 @@ typedef struct { */ float radius_rate; - /* If this is true then when a smoke unit has reached its + /* If this is true then when a smoke unit has reached its * maximum size its visiblity will be reset to 0.0 (thus marking * it as "available for use") */ @@ -1220,12 +1220,12 @@ typedef struct { #define SAR_OBJECT_EXPLOSION(p) ((sar_object_explosion_struct *)(p)) -/* +/* * Fire: */ typedef struct { - /* Cylendrical size of fire in meters, this is also used to + /* Cylendrical size of fire in meters, this is also used to * calculate the fire billboard * * Center is at the base of the fire @@ -1234,13 +1234,13 @@ typedef struct { height; time_t frame_inc_int, /* Frame increment interval, in ms */ - next_frame_inc; /* Time to increment next frame, in ms */ + next_frame_inc; /* Time to increment next frame, in ms */ int cur_frame, /* Current frame */ frame_repeats; /* Number of times animation has cycled */ /* Number of frame repeats, 0 or less to repeat forever (or * when life span has exceeded) - */ + */ int total_frame_repeats; /* Texture number on scene */ @@ -1269,7 +1269,7 @@ typedef struct { sar_chemical_type chemical_type; - int owner; /* Object that created this spray or -1 + int owner; /* Object that created this spray or -1 * for none */ /* Texture number on the scene */ @@ -1461,6 +1461,7 @@ typedef struct { /* * Human/Actor: */ +#define SAR_ASSISTING_HUMANS_MAX 4 typedef enum { SAR_HUMAN_FLAG_NEED_RESCUE = (1 << 1), SAR_HUMAN_FLAG_SIT = (1 << 2), /* Base at tush */ @@ -1471,7 +1472,7 @@ typedef enum { SAR_HUMAN_FLAG_ALERT = (1 << 6), /* Is awake */ SAR_HUMAN_FLAG_AWARE = (1 << 7), /* Knows of surroundings */ SAR_HUMAN_FLAG_IN_WATER = (1 << 8), - SAR_HUMAN_FLAG_ON_STREATCHER = (1 << 9), + SAR_HUMAN_FLAG_ON_STRETCHER = (1 << 9), SAR_HUMAN_FLAG_RUN = (1 << 10), /* Animate as running */ SAR_HUMAN_FLAG_RUN_TOWARDS = (1 << 11), /* Intends to run towards * (does not imply currently @@ -1483,8 +1484,10 @@ typedef enum { SAR_HUMAN_FLAG_GRIPPED = (1 << 14), /* Someone/something is * holding this (ie in * rescue basket */ - SAR_HUMAN_FLAG_DIVER_CATCHER = (1 << 15) + SAR_HUMAN_FLAG_DIVER_CATCHER = (1 << 15), + SAR_HUMAN_FLAG_GENDER_FEMALE = (1 << 16) } sar_human_flags; + typedef struct { sar_human_flags flags; @@ -1511,8 +1514,8 @@ typedef struct { * -1 No intercepting * -2 Intercept player * - * Works when flags SAR_HUMAN_FLAG_RUN_TOWARDS xor - * SAR_HUMAN_FLAG_RUN_AWAY is set and intercepting_object is + * Works when flags SAR_HUMAN_FLAG_RUN_TOWARDS xor + * SAR_HUMAN_FLAG_RUN_AWAY is set and intercepting_object is * valid and not the human object itself. */ int intercepting_object; @@ -1529,8 +1532,15 @@ typedef struct { * humans. */ int assisting_humans; + + /* Assisting human(s) preset name. When human has assisting humans(s), + * preset name of each one assisting human is stored here. + */ + const char *assisting_human_preset_name[SAR_ASSISTING_HUMANS_MAX]; + sar_color_struct assisting_human_color[SAR_HUMAN_COLORS_MAX]; + /* Messages */ char *mesg_enter; /* Entering into aircraft or vehicle */ @@ -1634,7 +1644,7 @@ typedef struct { /* Time stamp of when this object was created in milliseconds - * and in systime seconds (respectivly). The value in milliseconds + * and in systime seconds (respectivly). The value in milliseconds * may not be accurate when timmers are reset */ time_t birth_time_ms, @@ -1736,7 +1746,7 @@ typedef struct { */ typedef struct { - /* Note, cloud layer moves with camera in modulous + /* Note, cloud layer moves with camera in modulous * of the tiled width and height on the XY plane */ @@ -1932,7 +1942,7 @@ typedef struct { * rotate any vertex relative to the camera's rotation, each * a 3 * 3 matrix. * Member camera_rotmatrix_count indicates the actual number - * of matrixes set, which is equal or less than + * of matrixes set, which is equal or less than * SAR_CAMERA_ROTMATRIX_MAX */ #define SAR_CAMERA_ROTMATRIX_MAX 5 @@ -2031,13 +2041,13 @@ typedef struct { time_t camera_ref_title_display_until; /* Flight dynamics model realm structure, used by the SFM - * library as global reference while simulating all flight + * library as global reference while simulating all flight * dynamics models */ SFMRealmStruct *realm; - - /* Welcome message - to be displayed at being of game */ - char *welcome_message; + + /* Welcome message - to be displayed at being of game */ + char *welcome_message; } sar_scene_struct; #define SAR_SCENE(p) ((sar_scene_struct *)(p)) diff --git a/src/objio.c b/src/objio.c index 3edc4cc..a3cb161 100644 --- a/src/objio.c +++ b/src/objio.c @@ -1608,6 +1608,8 @@ int SARObjLoadHuman( core_ptr->human_data, scene, &core_ptr->object, &core_ptr->total_objects, p_new_human->flags, + p_new_human->assisting_humans, + p_new_human->assisting_human_preset_name, p_new_human->type_name ); @@ -1696,7 +1698,7 @@ int SARObjLoadSmoke( case 2: /* Dark */ tex_name = SAR_STD_TEXNAME_SMOKE_DARK; break; - case 3: /* Orange */ + case 3: /* Orange */ tex_name = SAR_STD_TEXNAME_SMOKE_ORANGE; break; } diff --git a/src/sardraw.c b/src/sardraw.c index 44b5ca4..62ba7a4 100644 --- a/src/sardraw.c +++ b/src/sardraw.c @@ -1962,7 +1962,7 @@ static void SARDrawHoistDeployment( SARDrawHumanIterate( dc, 1.9f, /* Height in meters */ - 54.0f, /* Mass in kg */ + 90.0f, /* Mass in kg */ SAR_HUMAN_FLAG_ALERT | SAR_HUMAN_FLAG_AWARE | SAR_HUMAN_FLAG_GRIPPED | SAR_HUMAN_FLAG_DIVER_CATCHER, hoist->diver_color, diff --git a/src/sardrawhuman.c b/src/sardrawhuman.c index 150f68c..877d836 100644 --- a/src/sardrawhuman.c +++ b/src/sardrawhuman.c @@ -79,18 +79,37 @@ void SARDrawHumanIterate( float left_knee_to_calv_angle, right_knee_to_calv_angle; float thigh_len = 0.3f; - float calv_len = 0.4f; + float calf_len = 0.4f; + float foot_height = 0.08f; + float foot_length; float torso_len = 0.8f; float bisep_len = 0.3f; float trisep_len = 0.4f; float base_to_torso = 0.0f; /* Ground to bottom of torso * (calculated later). */ - float streatcher_height = 0.8f; /* Ground to bed of streatcher. */ + float stretcher_height = 0.8f; /* Ground to bed of stretcher. */ const sar_color_struct *c; Boolean draw_shadow_std = False; + /* Body segments length depends of human total height */ + float height_coef = height / 1.9f; // SarII standard human height is 1.9m + thigh_len *= height_coef; + calf_len *= height_coef; + foot_height *= height_coef; + foot_length = 1.90f * 0.13f * height_coef; + torso_len *= height_coef; + bisep_len *= height_coef; + trisep_len *= height_coef; + + /* Body width and thick depends of human mass: let's consider + * that standard is 1.9m / 90kg => BMI is ~25. + */ + float bmi = mass / (height * height); + float width_coef = (bmi * 0.66f) / 25; + float thick_coef = (bmi * 1.2f) / 25; + /* Macro to set the color pointed to by c. The color must be specifying * a color on the human's body, because dc->flir will be checked and if * it is True then the color will be brightened. @@ -108,7 +127,7 @@ void SARDrawHumanIterate( StateGLDisable(state, GL_LIGHTING); StateGLDisable(state, GL_TEXTURE_2D); V3DTextureSelect(NULL); - StateGLShadeModel(state, opt->gl_shade_model); + StateGLShadeModel(state, GL_SMOOTH); /* Calculate angles of body parts. Note that all zero radians * indicates human is standing upright with hands to side. @@ -127,9 +146,9 @@ void SARDrawHumanIterate( left_knee_to_calv_angle = (float)(0.0 * PI); right_knee_to_calv_angle = (float)(0.0 * PI); - base_to_torso = thigh_len + calv_len; + base_to_torso = thigh_len + calf_len + foot_height * height_coef; - if(flags & SAR_HUMAN_FLAG_ON_STREATCHER) + if(flags & SAR_HUMAN_FLAG_ON_STRETCHER) { /* Some translating will be done later. */ } @@ -178,11 +197,11 @@ void SARDrawHumanIterate( left_trisep_angle = (float)(1.75 * PI); right_trisep_angle = (float)(1.75 * PI); left_hip_to_thigh_angle = (float)(1.5 * PI); - right_hip_to_thigh_angle = (float)(1.5 * PI); + right_hip_to_thigh_angle = (float)(1.5 * PI); left_knee_to_calv_angle = (float)(0.5 * PI); right_knee_to_calv_angle = (float)(0.5 * PI); - - base_to_torso = calv_len; + + base_to_torso = calf_len + foot_height * height_coef; } else if(flags & SAR_HUMAN_FLAG_DIVER_CATCHER) { @@ -192,11 +211,11 @@ void SARDrawHumanIterate( right_shoulder_angle = (float)(1.9 * PI); left_bisep_angle = (float)(1.8 * PI); right_bisep_angle = (float)(1.8 * PI); - left_trisep_angle = (float)(1.8 * PI); + left_trisep_angle = (float)(1.8 * PI); right_trisep_angle = (float)(1.8 * PI); left_hip_to_thigh_angle = (float)(1.9 * PI); right_hip_to_thigh_angle = (float)(1.9 * PI); - left_knee_to_calv_angle = (float)(0.2 * PI); + left_knee_to_calv_angle = (float)(0.2 * PI); right_knee_to_calv_angle = (float)(0.2 * PI); /* If gripped it implies on end of rescue hoist rope. */ @@ -205,7 +224,7 @@ void SARDrawHumanIterate( else if(flags & SAR_HUMAN_FLAG_IN_WATER) base_to_torso = torso_len * -0.92f; else - base_to_torso = thigh_len + calv_len; + base_to_torso = thigh_len + calf_len + foot_height * height_coef; } /* Run should be checked last since lying and setting have * precidence. @@ -251,7 +270,7 @@ void SARDrawHumanIterate( left_knee_to_calv_angle = (float)(0.2 * PI); right_knee_to_calv_angle = (float)(0.2 * PI); - base_to_torso = thigh_len + calv_len; + base_to_torso = thigh_len + calf_len + foot_height * height_coef; draw_shadow_std = True; } @@ -273,7 +292,7 @@ void SARDrawHumanIterate( left_bisep_angle = (float)(1.5 * PI); right_bisep_angle = (float)(1.5 * PI); left_trisep_angle = (float)(0.0 * PI); - right_trisep_angle = (float)(0.0 * PI); + right_trisep_angle = (float)(0.0 * PI); left_hip_to_thigh_angle = (float)(0.0 * PI); right_hip_to_thigh_angle = (float)(0.0 * PI); left_knee_to_calv_angle = (float)(0.0 * PI); @@ -315,7 +334,7 @@ void SARDrawHumanIterate( left_knee_to_calv_angle = (float)(0.0 * PI); right_knee_to_calv_angle = (float)(0.0 * PI); - base_to_torso = thigh_len + calv_len; + base_to_torso = thigh_len + calf_len + foot_height * height_coef; } else { @@ -332,7 +351,7 @@ void SARDrawHumanIterate( left_knee_to_calv_angle = (float)(0.0 * PI); right_knee_to_calv_angle = (float)(0.0 * PI); - base_to_torso = thigh_len + calv_len; + base_to_torso = thigh_len + calf_len + foot_height * height_coef; } draw_shadow_std = True; } @@ -345,7 +364,7 @@ void SARDrawHumanIterate( /* Draw shadow? */ if(draw_shadow_std) { - float theta, r = 0.5f; + float theta, r = 0.07f + height / 4.4f; StateGLBoolean lighting = state->lighting; StateGLBoolean depth_mask_flag = state->depth_mask_flag; GLenum shade_model_mode = state->shade_model_mode; @@ -387,15 +406,15 @@ void SARDrawHumanIterate( StateGLShadeModel(state, shade_model_mode); } - /* Draw streatcher? */ - if(flags & SAR_HUMAN_FLAG_ON_STREATCHER) + /* Draw stretcher? */ + if(flags & SAR_HUMAN_FLAG_ON_STRETCHER) { float x = 0.35f, y = 1.05f; - float h = streatcher_height - 0.1f, hl = 0.1f; + float h = stretcher_height - 0.1f, hl = 0.1f; glColor4f(0.8f, 0.8f, 0.8f, 1.0f); - /* Bed of streatcher. */ + /* Bed of stretcher. */ glBegin(GL_QUADS); { glNormal3f(0.0f, 1.0f, 0.0f); @@ -426,7 +445,7 @@ void SARDrawHumanIterate( glEnd(); /* Right grids. */ - glBegin(GL_LINE_LOOP); + glBegin(GL_LINE_LOOP); { glNormal3f(1.0, 0.0, 0.0); glVertex3f(x, hl, -y); @@ -439,7 +458,7 @@ void SARDrawHumanIterate( glColor4f(0.1f, 0.1f, 0.1f, 1.0f); - /* Simple square wheels. */ + /* Simple square wheels, outside / inside. */ glBegin(GL_QUADS); { glNormal3f(-1.0f, 0.0f, 0.0f); @@ -447,16 +466,28 @@ void SARDrawHumanIterate( glVertex3f(-x, 0.0f, -(y - 0.1f)); glVertex3f(-x, hl, -(y - 0.1f)); glVertex3f(-x, hl, -y); + + glNormal3f(1.0f, 0.0f, 0.0f); + glVertex3f(-x, 0.0f, -y); + glVertex3f(-x, hl, -y); + glVertex3f(-x, hl, -(y - 0.1f)); + glVertex3f(-x, 0.0f, -(y - 0.1f)); } glEnd(); - glBegin(GL_QUADS); + glBegin(GL_QUADS); { glNormal3f(-1.0f, 0.0f, 0.0f); glVertex3f(-x, hl, y); glVertex3f(-x, hl, (y - 0.1f)); - glVertex3f(-x, 0.0f, (y - 0.1f)); + glVertex3f(-x, 0.0f, (y - 0.1f)); glVertex3f(-x, 0.0f, y); + + glNormal3f(1.0f, 0.0f, 0.0f); + glVertex3f(-x, hl, y); + glVertex3f(-x, 0.0f, y); + glVertex3f(-x, 0.0f, (y - 0.1f)); + glVertex3f(-x, hl, (y - 0.1f)); } glEnd(); @@ -467,6 +498,12 @@ void SARDrawHumanIterate( glVertex3f(x, hl, -y); glVertex3f(x, hl, -(y - 0.1f)); glVertex3f(x, 0.0f, -(y - 0.1f)); + + glNormal3f(-1.0f, 0.0f, 0.0f); + glVertex3f(x, 0.0f, -y); + glVertex3f(x, 0.0f, -(y - 0.1f)); + glVertex3f(x, hl, -(y - 0.1f)); + glVertex3f(x, hl, -y); } glEnd(); @@ -477,6 +514,12 @@ void SARDrawHumanIterate( glVertex3f(x, hl, (y - 0.1f)); glVertex3f(x, hl, y); glVertex3f(x, 0.0f, y); + + glNormal3f(-1.0f, 0.0f, 0.0f); + glVertex3f(x, 0.0f, (y - 0.1f)); + glVertex3f(x, 0.0f, y); + glVertex3f(x, hl, y); + glVertex3f(x, hl, (y - 0.1f)); } glEnd(); } @@ -486,14 +529,14 @@ void SARDrawHumanIterate( /* Torso. */ glPushMatrix(); { - /* Check if on streatcher, if so translate up. */ - if(flags & SAR_HUMAN_FLAG_ON_STREATCHER) + /* Check if on stretcher, if so translate up. */ + if(flags & SAR_HUMAN_FLAG_ON_STRETCHER) { /* Push on extra matrix and move up (matrix poped later). */ glPushMatrix(); glTranslatef( 0.0f, - streatcher_height, + stretcher_height, -(base_to_torso + 0.2f) ); } @@ -513,31 +556,144 @@ void SARDrawHumanIterate( SET_BODY_COLOR glBegin(GL_QUADS); { - SARDrawBoxBaseNS( - 0.45f * torso_len, - 0.25f * torso_len, + SARDrawBoxBaseNS( + 0.45f * torso_len * width_coef, + 0.25f * torso_len * thick_coef, 0.10f * torso_len, True ); } glEnd(); - - glTranslatef(0.0f, 0.10f * torso_len, 0.0f); - - /* Upper torso. */ - c = &palette[SAR_HUMAN_COLOR_TORSO]; - SET_BODY_COLOR - glBegin(GL_QUADS); + if( !(flags & SAR_HUMAN_FLAG_GENDER_FEMALE) ) { - SARDrawBoxBaseNS( - 0.45f * torso_len, - 0.25f * torso_len, - 0.90f * torso_len, - False - ); + /* Male upper torso (default torso). */ + glTranslatef(0.0f, 0.10f * torso_len, 0.0f); + + c = &palette[SAR_HUMAN_COLOR_TORSO]; + SET_BODY_COLOR + glBegin(GL_QUADS); + { + SARDrawBoxBaseNS( + 0.45f * torso_len * width_coef, + 0.25f * torso_len * thick_coef, + 0.90f * torso_len, + False + ); + } + glEnd(); + } + else + { + /* Female upper torso. */ + glTranslatef(0.0f, 0.10f * torso_len, 0.0f); + + float half_thick = (0.25f * torso_len * thick_coef) / 2.0f; + float half_width = 0.45f * torso_len * width_coef / 2.0f; + float torso_z0 = 0.0f; + float torso_z4 = 0.90f * torso_len; + float torso_z1 = torso_z4 - 0.25f * height_coef; + float torso_z2 = torso_z4 - 0.19f * height_coef; + float torso_y2 = -half_thick - 0.08f * thick_coef; + float torso_z3 = torso_z4 - 0.10f * height_coef; + + c = &palette[SAR_HUMAN_COLOR_TORSO]; + SET_BODY_COLOR + glBegin(GL_TRIANGLES); + glNormal3f(0.518700, 0.173200, -0.837200); + glVertex3f(-half_width, torso_z3,-half_thick); + glNormal3f(0.754400, -0.069900, -0.652600); + glVertex3f(-half_width, torso_z2, torso_y2); + glNormal3f(0.503600, -0.157200, -0.849500); + glVertex3f(-half_width, torso_z1,-half_thick); + glEnd(); + glBegin(GL_POLYGON); + glNormal3f(0.444300, 0.011200, -0.895800); + glVertex3f(-half_width, -torso_z0,-half_thick); + glNormal3f(-0.372500, 0.082900, -0.924300); + glVertex3f(-half_width, torso_z0, half_thick); + glNormal3f(-0.322800, 0.427900, -0.844200); + glVertex3f(-half_width, torso_z4, half_thick); + glNormal3f(0.381800, 0.424900, -0.820800); + glVertex3f(-half_width, torso_z4,-half_thick); + glNormal3f(0.513300, 0.187400, -0.837500); + glVertex3f(-half_width, torso_z3,-half_thick); + glNormal3f(0.497900, -0.169600, -0.850500); + glVertex3f(-half_width, torso_z1,-half_thick); + glEnd(); + glBegin(GL_TRIANGLES); + glNormal3f(0.754400, -0.069900, 0.652600); + glVertex3f(half_width, torso_z2, torso_y2); + glNormal3f(0.518700, 0.173200, 0.837200); + glVertex3f(half_width, torso_z3,-half_thick); + glNormal3f(0.503600, -0.157200, 0.849500); + glVertex3f(half_width, torso_z1,-half_thick); + glEnd(); + glBegin(GL_POLYGON); + glNormal3f(0.513300, 0.187300, 0.837500); + glVertex3f(half_width, torso_z3,-half_thick); + glNormal3f(0.381800, 0.424900, 0.820800); + glVertex3f(half_width, torso_z4,-half_thick); + glNormal3f(-0.322700, 0.427900, 0.844200); + glVertex3f(half_width, torso_z4, half_thick); + glNormal3f(-0.372500, 0.082900, 0.924300); + glVertex3f(half_width, torso_z0, half_thick); + glNormal3f(0.444300, 0.011200, 0.895800); + glVertex3f(half_width, -torso_z0,-half_thick); + glNormal3f(0.497900, -0.169600, 0.850500); + glVertex3f(half_width, torso_z1,-half_thick); + glEnd(); + glBegin(GL_QUADS); + glNormal3f(-0.334300, 0.736800, -0.587600); + glVertex3f(-half_width, torso_z4, half_thick); + glNormal3f(-0.334300, 0.736800, 0.587600); + glVertex3f(half_width, torso_z4, half_thick); + glNormal3f(0.391200, 0.731400, 0.558500); + glVertex3f(half_width, torso_z4,-half_thick); + glNormal3f(0.391200, 0.731400, -0.558500); + glVertex3f(-half_width, torso_z4,-half_thick); + glNormal3f(0.697400, 0.439900, -0.565900); + glVertex3f(-half_width, torso_z4,-half_thick); + glNormal3f(0.697400, 0.439900, 0.565900); + glVertex3f(half_width, torso_z4,-half_thick); + glNormal3f(0.800600, 0.188700, 0.568800); + glVertex3f(half_width, torso_z3,-half_thick); + glNormal3f(0.800600, 0.188800, -0.568700); + glVertex3f(-half_width, torso_z3,-half_thick); + glNormal3f(0.737800, 0.360800, -0.570500); + glVertex3f(-half_width, torso_z3,-half_thick); + glNormal3f(0.737800, 0.360800, 0.570500); + glVertex3f(half_width, torso_z3,-half_thick); + glNormal3f(0.937200, 0.101800, 0.333500); + glVertex3f(half_width, torso_z2, torso_y2); + glNormal3f(0.937200, 0.101800, -0.333500); + glVertex3f(-half_width, torso_z2, torso_y2); + glNormal3f(0.901200, -0.275700, -0.334300); + glVertex3f(-half_width, torso_z2, torso_y2); + glNormal3f(0.901200, -0.275700, 0.334300); + glVertex3f(half_width, torso_z2, torso_y2); + glNormal3f(0.696600, -0.396100, 0.598200); + glVertex3f(half_width, torso_z1,-half_thick); + glNormal3f(0.696600, -0.396100, -0.598200); + glVertex3f(-half_width, torso_z1,-half_thick); + glNormal3f(0.791000, -0.173400, -0.586700); + glVertex3f(-half_width, torso_z1,-half_thick); + glNormal3f(0.791000, -0.173400, 0.586700); + glVertex3f(half_width, torso_z1,-half_thick); + glNormal3f(0.753300, 0.011400, 0.657600); + glVertex3f(half_width, -torso_z0,-half_thick); + glNormal3f(0.753300, 0.011400, -0.657600); + glVertex3f(-half_width, -torso_z0,-half_thick); + glNormal3f(-0.699600, 0.086600, -0.709300); + glVertex3f(-half_width, torso_z0, half_thick); + glNormal3f(-0.699600, 0.086600, 0.709300); + glVertex3f(half_width, torso_z0, half_thick); + glNormal3f(-0.652000, 0.454400, 0.606900); + glVertex3f(half_width, torso_z4, half_thick); + glNormal3f(-0.652000, 0.454400, -0.606900); + glVertex3f(-half_width, torso_z4, half_thick); + glEnd(); } - glEnd(); } glPopMatrix(); /* Back to base of torso. */ @@ -550,7 +706,7 @@ void SARDrawHumanIterate( (GLfloat)-SFMRadiansToDegrees(left_hip_to_thigh_angle), 1.0f, 0.0f, 0.0f ); - glTranslatef(-0.16f * torso_len, 0.0f, 0.0f); + glTranslatef(-0.16f * torso_len * width_coef, 0.0f, 0.0f); c = &palette[SAR_HUMAN_COLOR_LEGS]; SET_BODY_COLOR @@ -558,8 +714,8 @@ void SARDrawHumanIterate( glBegin(GL_QUADS); { SARDrawBoxBaseNS( - 0.5f * thigh_len, - 0.5f * thigh_len, + 0.5f * thigh_len * width_coef, + 0.5f * thigh_len * thick_coef, -thigh_len, True ); @@ -578,16 +734,16 @@ void SARDrawHumanIterate( glBegin(GL_QUADS); { SARDrawBoxBaseNS( - 0.3f * calv_len, - 0.3f * calv_len, - -calv_len, + 0.3f * calf_len * width_coef, + 0.3f * calf_len * thick_coef, + -calf_len, True ); } glEnd(); /* Feet. */ - glTranslatef(0.0f, -calv_len, -0.05f); + glTranslatef(0.0f, -calf_len, -0.05f); c = &palette[SAR_HUMAN_COLOR_FEET]; SET_BODY_COLOR @@ -595,9 +751,9 @@ void SARDrawHumanIterate( glBegin(GL_QUADS); { SARDrawBoxBaseNS( - 0.1f, - 0.2f, - -0.1f, + 0.1f * width_coef, + foot_length, + -foot_height * height_coef, True ); } @@ -614,7 +770,7 @@ void SARDrawHumanIterate( (GLfloat)-SFMRadiansToDegrees(right_hip_to_thigh_angle), 1.0f, 0.0f, 0.0f ); - glTranslatef(0.16f * torso_len, 0.0f, 0.0f); + glTranslatef(0.16f * torso_len * width_coef, 0.0f, 0.0f); c = &palette[SAR_HUMAN_COLOR_LEGS]; SET_BODY_COLOR @@ -622,14 +778,14 @@ void SARDrawHumanIterate( glBegin(GL_QUADS); { SARDrawBoxBaseNS( - 0.5f * thigh_len, - 0.5f * thigh_len, + 0.5f * thigh_len * width_coef, + 0.5f * thigh_len * thick_coef, -thigh_len, True - ); + ); } - glEnd(); - + glEnd(); + /* Calv. */ glTranslatef(0.0f, -thigh_len, 0.0f); glRotatef( @@ -642,16 +798,16 @@ void SARDrawHumanIterate( glBegin(GL_QUADS); { SARDrawBoxBaseNS( - 0.3f * calv_len, - 0.3f * calv_len, - -calv_len, + 0.3f * calf_len * width_coef, + 0.3f * calf_len * thick_coef, + -calf_len, True ); } glEnd(); /* Feet. */ - glTranslatef(0.0f, -calv_len, -0.05f); + glTranslatef(0.0f, -calf_len, -0.05f); c = &palette[SAR_HUMAN_COLOR_FEET]; SET_BODY_COLOR @@ -659,9 +815,9 @@ void SARDrawHumanIterate( glBegin(GL_QUADS); { SARDrawBoxBaseNS( - 0.1f, - 0.2f, - -0.1f, + 0.1f * width_coef, + foot_length, + -foot_height * height_coef, True ); } @@ -678,7 +834,7 @@ void SARDrawHumanIterate( { /* Bisep and shoulder. */ glTranslatef( - (-0.225f * torso_len) + (-0.25f * bisep_len), + (-0.225f * torso_len + -0.25f * bisep_len) * width_coef, 0.0f, 0.0f ); @@ -697,8 +853,8 @@ void SARDrawHumanIterate( glBegin(GL_QUADS); { SARDrawBoxBaseNS( - 0.5f * bisep_len, - 0.5f * bisep_len, + 0.5f * bisep_len * width_coef, + 0.5f * bisep_len * thick_coef, -bisep_len, True ); @@ -715,8 +871,8 @@ void SARDrawHumanIterate( glBegin(GL_QUADS); { SARDrawBoxBaseNS( - 0.28f * trisep_len, - 0.28f * trisep_len, + 0.28f * trisep_len * width_coef, + 0.28f * trisep_len * thick_coef, -trisep_len, True ); @@ -732,7 +888,7 @@ void SARDrawHumanIterate( glBegin(GL_QUADS); { - SARDrawBoxBaseNS(0.2f, 0.1f, -0.2f, True); + SARDrawBoxBaseNS((0.28f * trisep_len + 0.06f) * width_coef, 0.06f * thick_coef, -0.50f * trisep_len, True); } glEnd(); } @@ -744,7 +900,7 @@ void SARDrawHumanIterate( { /* Bisep. */ glTranslatef( - (0.225f * torso_len) + (0.25f * bisep_len), + (0.225f * torso_len + 0.25f * bisep_len) * width_coef, 0.0f, 0.0f ); @@ -763,8 +919,8 @@ void SARDrawHumanIterate( glBegin(GL_QUADS); { SARDrawBoxBaseNS( - 0.5f * bisep_len, - 0.5f * bisep_len, + 0.5f * bisep_len * width_coef, + 0.5f * bisep_len * thick_coef, -bisep_len, True ); @@ -781,8 +937,8 @@ void SARDrawHumanIterate( glBegin(GL_QUADS); { SARDrawBoxBaseNS( - 0.28f * trisep_len, - 0.28f * trisep_len, + 0.28f * trisep_len * width_coef, + 0.28f * trisep_len * thick_coef, -trisep_len, True ); @@ -798,7 +954,7 @@ void SARDrawHumanIterate( glBegin(GL_QUADS); { - SARDrawBoxBaseNS(0.2f, 0.1f, -0.2f, True); + SARDrawBoxBaseNS((0.28f * trisep_len + 0.06f) * width_coef, 0.06f * thick_coef, -0.50f * trisep_len, True); } glEnd(); } @@ -806,51 +962,79 @@ void SARDrawHumanIterate( /* Back to shoulders. */ - /* Head. */ - glTranslatef(0.0f, 0.05f * torso_len, 0.0f); - - c = &palette[SAR_HUMAN_COLOR_FACE]; - SET_BODY_COLOR + /* Head and hair. */ + float head_height = 0.22f * height_coef; + head_height = (head_height >= 0.13) ? (head_height) : (0.13f); + float hairs_height = 0.1f * height_coef; + /* Do not apply whole thick coefficient to head */ + float head_thick = 0.18f * (thick_coef / 1.5f); - glBegin(GL_QUADS); + /* Check if hair color is transparent. If true, human is bald (has no head hair). */ + if ((&palette[SAR_HUMAN_COLOR_HAIR])->a == 0.0f) { - SARDrawBoxBaseNS(0.18f, 0.18f, 0.25f, False); - } - glEnd(); + head_height += hairs_height / 3.0f; - - /* Hair. */ - glPushMatrix(); - { - glTranslatef(0.0f, 0.25f, 0.0f); - - c = &palette[SAR_HUMAN_COLOR_HAIR]; + /* Head */ + c = &palette[SAR_HUMAN_COLOR_FACE]; SET_BODY_COLOR + glTranslatef(0.0f, 0.05f * torso_len * height_coef, 0.0f); glBegin(GL_QUADS); { - SARDrawBoxBaseNS(0.18f, 0.18f, 0.1f, False); + SARDrawBoxBaseNS(0.18f * width_coef, head_thick, head_height, True); } glEnd(); + + /* Dont' draw hair. */ } - glPopMatrix(); - /* Back of head hair. */ - glPushMatrix(); + else { - glTranslatef(0.0f, 0.05f, -(-0.09f - 0.03f)); + /* Head */ + c = &palette[SAR_HUMAN_COLOR_FACE]; + SET_BODY_COLOR + + glTranslatef(0.0f, 0.05f * torso_len * height_coef, 0.0f); glBegin(GL_QUADS); { - SARDrawBoxBaseNS(0.18f, 0.06f, 0.25f, True); + SARDrawBoxBaseNS(0.18f * width_coef, head_thick, head_height, True); } glEnd(); + + /* Hair. */ + glPushMatrix(); + { + /* Move to head top */ + glTranslatef(0.0f, head_height, 0.0f); + + c = &palette[SAR_HUMAN_COLOR_HAIR]; + SET_BODY_COLOR + + glBegin(GL_QUADS); + { + SARDrawBoxBaseNS(0.18f * width_coef, head_thick, hairs_height, False); + } + glEnd(); + } + glPopMatrix(); + + /* Back of head hair. */ + glPushMatrix(); + { + glTranslatef(0.0f, 0.05f * height_coef, (head_thick / 2.0f) + 0.05f / 2.0f); + glBegin(GL_QUADS); + { + SARDrawBoxBaseNS(0.18f * width_coef, 0.05f, head_height, True); + } + glEnd(); + } + glPopMatrix(); } - glPopMatrix(); - /* Check if on streatcher, if so we need to pop one matrix - * level that was added for translation up on to streatcher. + /* Check if on stretcher, if so we need to pop one matrix + * level that was added for translation up on to stretcher. */ - if(flags & SAR_HUMAN_FLAG_ON_STREATCHER) + if(flags & SAR_HUMAN_FLAG_ON_STRETCHER) { glPopMatrix(); } @@ -967,26 +1151,35 @@ void SARDrawHuman( { int i; sar_obj_flags_t flags; - float s = 0.8f; /* Left/right spacing. */ + float slr = 0.8f; /* Left/right spacing. */ + float sfr; /* Front/rear spacing, from stretcher center. */ + const sar_human_data_entry_struct *assisting_human; - /* Draw all assisting human objects, left and right. */ + if(human->assisting_humans <= 2) + /* Shitf a bit behind stretcher center. */ + sfr = 0.2f; + else + /* Shift to stretcher rear end. */ + sfr = 0.9f; + + /* Draw one to four assisting human objects */ for(i = 0; i < human->assisting_humans; i++) { glPushMatrix(); { - /* Translate to the side and a bit behind. */ - glTranslatef(s, 0.0f, 0.2f); + /* Translate to assistant position. */ + glTranslatef(slr, 0.0f, sfr); /* Set up `filtered' human flags that will be * passed to the human draw itteration function. - * This is so that we don't pass all the flags, + * This is so that we don't pass all the flags, * because in some situations the human may be - * lying on a streatcher and the assisting humans + * lying on a stretcher and the assisting humans * need to be running. */ flags = 0; if(human->flags & SAR_HUMAN_FLAG_ALERT) - flags |= SAR_HUMAN_FLAG_ALERT; + flags |= SAR_HUMAN_FLAG_ALERT; if(human->flags & SAR_HUMAN_FLAG_AWARE) flags |= SAR_HUMAN_FLAG_AWARE; if(human->flags & SAR_HUMAN_FLAG_IN_WATER) @@ -996,22 +1189,40 @@ void SARDrawHuman( if(human->flags & SAR_HUMAN_FLAG_PUSHING) flags |= SAR_HUMAN_FLAG_PUSHING; - /* Draw our human object as an assisting human, - * using the filtered human flags and the - * assisting_human_color color palette - */ - SARDrawHumanIterate( - dc, - human->height, human->mass, - flags, human->assisting_human_color, - human->water_ripple_tex_num, - human->anim_pos + assisting_human = SARHumanMatchEntryByName( + dc->core_ptr->human_data, human->assisting_human_preset_name[i] ); + /* Human preset name not found? */ + if(assisting_human == NULL) + /* Use default assisting human preset. */ + assisting_human = SARHumanMatchEntryByName( + dc->core_ptr->human_data, SAR_HUMAN_PRESET_NAME_ASSISTING_HUMAN + ); + + if(assisting_human != NULL) + { + /* Propagate assisting human gender to flags. */ + if(assisting_human->preset_entry_flags & SAR_HUMAN_FLAG_GENDER_FEMALE) + flags |= SAR_HUMAN_FLAG_GENDER_FEMALE; + + /* Draw assisting human. */ + SARDrawHumanIterate( + dc, + assisting_human->height, assisting_human->mass, + flags, assisting_human->color, + human->water_ripple_tex_num, + human->anim_pos + ); + } } glPopMatrix(); - /* Shift spacing to other side. */ - s *= -1.0; + /* Shift left/right spacing to other side. */ + slr *= -1.0; + + /* When second assistant has been drawn, shift to stretcher front end. */ + if(i == 1) + sfr *= -1.0; } } } diff --git a/src/sarfio.h b/src/sarfio.h index fd0dc52..104d319 100644 --- a/src/sarfio.h +++ b/src/sarfio.h @@ -432,6 +432,8 @@ typedef struct { int type; char *type_name; sar_obj_flags_t flags; /* Any of SAR_HUMAN_FLAG_* */ + int assisting_humans; /* Assisting humans number. */ + char *assisting_human_preset_name[SAR_ASSISTING_HUMANS_MAX]; /* Assisting human(s) preset name. */ } sar_parm_new_human_struct; diff --git a/src/sarfioopen.c b/src/sarfioopen.c index 740c0f0..3071f55 100644 --- a/src/sarfioopen.c +++ b/src/sarfioopen.c @@ -32,6 +32,7 @@ #include "sarfio.h" #include "config.h" #include "sfm.h" +#include "human.h" static const char *NEXT_ARG(const char *s); static void CHOP_STR_BLANK(char *s); @@ -1127,7 +1128,8 @@ static int SARParmLoadFromFileIterate( * * * - * + * + * */ /* First argument is type name */ @@ -1172,11 +1174,59 @@ static int SARParmLoadFromFileIterate( strcasepfx(cstrptr, "inwater") ) pv->flags |= SAR_HUMAN_FLAG_IN_WATER; - /* On streatcher? */ - else if(strcasepfx(cstrptr, "on_streatcher") || - strcasepfx(cstrptr, "onstreatcher") + /* On stretcher? */ + else if(strcasepfx(cstrptr, "on_stretcher") || + strcasepfx(cstrptr, "onstretcher") || + strcasepfx(cstrptr, "on_streatcher")|| + strcasepfx(cstrptr, "onstreatcher") ) - pv->flags |= SAR_HUMAN_FLAG_ON_STREATCHER; + pv->flags |= SAR_HUMAN_FLAG_ON_STRETCHER; + /* Assisted? */ + else if(strcasepfx(cstrptr, "assisted") || + strcasepfx(cstrptr, "assistants") || + strcasepfx(cstrptr, "assistant") + ) + { + cstrptr = NEXT_ARG(cstrptr); + if((cstrptr != NULL) ? (*cstrptr != '\0') : 0) + { + if(isdigit(cstrptr[0])) + /* Assisting_humans number found. */ + { + pv->assisting_humans = ( ATOI(cstrptr) <= SAR_ASSISTING_HUMANS_MAX ? + ATOI(cstrptr) : SAR_ASSISTING_HUMANS_MAX); + + if(pv->assisting_humans < 0) + pv->assisting_humans = 0; + + /* Save name of assisting human(s) preset(s) */ + for(int j = 0; j < pv->assisting_humans; j++) + { + cstrptr = NEXT_ARG(cstrptr); + if((cstrptr != NULL) ? (*cstrptr != '\0') : 0) + { + pv->assisting_human_preset_name[j] = STRDUP(cstrptr); + CHOP_STR_BLANK(pv->assisting_human_preset_name[j]); + } + else + pv->assisting_human_preset_name[j] = STRDUP(SAR_HUMAN_PRESET_NAME_ASSISTING_HUMAN); + } + } + else + /* Assisting_humans number not found. */ + { + pv->assisting_humans = 0; + /* Allow to re-read current parameter at next loop. */ + cstrptr--; + } + } + if(pv->assisting_humans == 0) + fprintf( + stderr, +"%s: %i: Warning: Assisting humans number missing or null.\n", + filename, *lines_read + ); + } else fprintf( stderr, diff --git a/src/sarfiosave.c b/src/sarfiosave.c index 3f6bcf5..d2054b9 100644 --- a/src/sarfiosave.c +++ b/src/sarfiosave.c @@ -632,6 +632,16 @@ static int SARParmSaveToFileAnyIterate( fprintf(fp, " aware"); if(pv->flags & SAR_HUMAN_FLAG_IN_WATER) fprintf(fp, " in_water"); + if(pv->flags & SAR_HUMAN_FLAG_ON_STRETCHER) + fprintf(fp, " on_stretcher"); + if(pv->assisting_humans > 0) + { + /* Assisting humans number */ + fprintf(fp, " assisted %d", pv->assisting_humans); + /* Assisting humans preset name(s) */ + for(int i = 0; i < pv->assisting_humans; i++) + fprintf(fp, " %s", pv->assisting_human_preset_name[i]); + } fputc('\n', fp); parms_saved++; #undef PARM_TYPE diff --git a/src/simop.c b/src/simop.c index aed37b4..e43ba5d 100644 --- a/src/simop.c +++ b/src/simop.c @@ -921,7 +921,7 @@ void SARSimSetAircraftCrashed( /* Not in water (need to work on this) */ human->flags &= ~SAR_HUMAN_FLAG_IN_WATER; - human->flags &= ~SAR_HUMAN_FLAG_ON_STREATCHER; + human->flags &= ~SAR_HUMAN_FLAG_ON_STRETCHER; } break; @@ -3409,7 +3409,7 @@ void SARSimApplyGCTL(sar_core_struct *core_ptr, sar_object_struct *obj_ptr) } /* Is door fully opened ? */ - if (door_ptr->flags & SAR_OBJ_PART_FLAG_DOOR_OPENED) + if(door_ptr->flags & SAR_OBJ_PART_FLAG_DOOR_OPENED) { /* Was rope previously in? */ if(hoist->rope_cur < hoist->contact_z_max) @@ -3420,8 +3420,8 @@ void SARSimApplyGCTL(sar_core_struct *core_ptr, sar_object_struct *obj_ptr) sar_position_struct *hoist_pos = &hoist->pos, *hoist_offset = &hoist->offset; double tx = hoist_offset->x, - ty = hoist_offset->y, - tz = hoist_offset->z; + ty = hoist_offset->y, + tz = hoist_offset->z; /* Move to initial position at hoist center */ SFMOrthoRotate2D( diff --git a/src/simutils.c b/src/simutils.c index 1e4bc07..f2f694e 100644 --- a/src/simutils.c +++ b/src/simutils.c @@ -2561,7 +2561,7 @@ int SARSimDoPickUpHuman( obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_LYING; /* Leave SAR_HUMAN_FLAG_ALERT and SAR_HUMAN_FLAG_AWARE as is */ obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_IN_WATER; - obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_ON_STREATCHER; + obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_ON_STRETCHER; obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_RUN; obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_RUN_TOWARDS; obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_RUN_AWAY; @@ -2578,7 +2578,7 @@ int SARSimDoPickUpHuman( obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_LYING; /* Leave SAR_HUMAN_FLAG_ALERT and SAR_HUMAN_FLAG_AWARE as is */ obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_IN_WATER; - obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_ON_STREATCHER; + obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_ON_STRETCHER; obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_RUN; obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_RUN_TOWARDS; obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_RUN_AWAY; @@ -2595,7 +2595,7 @@ int SARSimDoPickUpHuman( obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_LYING; /* Leave SAR_HUMAN_FLAG_ALERT and SAR_HUMAN_FLAG_AWARE as is */ obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_IN_WATER; - obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_ON_STREATCHER; + obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_ON_STRETCHER; obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_RUN; obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_RUN_TOWARDS; obj_human_ptr->flags &= ~SAR_HUMAN_FLAG_RUN_AWAY; @@ -2854,16 +2854,13 @@ int SARSimBoardObject( break; } - - /* Begin moving source object into target object */ - /* Increment passengers count */ *passengers = MAX(*passengers, 0) + 1; /* Increment passengers mass if possible */ if(passengers_mass != NULL) *passengers_mass = MAX(*passengers_mass, 0.0f) + src_mass; - + /* If a mission is active then call the mission passengers enter * notify callback */