From 8453b937f5516bc70a813794e9c78b6c43e63587 Mon Sep 17 00:00:00 2001
From: Rudolf Polzer <divverent@xonotic.org>
Date: Tue, 12 Feb 2013 10:15:31 +0100
Subject: [PATCH] load animblending info from txt file

---
 models/player/erebus.iqm_0.txt  |  4 ++
 qcsrc/client/autocvars.qh       |  2 -
 qcsrc/client/csqcmodel_hooks.qc | 10 ++---
 qcsrc/client/player_skeleton.qc | 77 +++++++++++++++++++--------------
 qcsrc/client/player_skeleton.qh |  5 +++
 qcsrc/common/util.qc            | 13 ++++++
 qcsrc/common/util.qh            |  3 ++
 7 files changed, 74 insertions(+), 40 deletions(-)

diff --git a/models/player/erebus.iqm_0.txt b/models/player/erebus.iqm_0.txt
index ac81e7e09..79fb0bc65 100644
--- a/models/player/erebus.iqm_0.txt
+++ b/models/player/erebus.iqm_0.txt
@@ -3,5 +3,9 @@ species human
 sex Male
 weight 105
 age 26
+bone_upperbody spine2
+bone_aim spine2
+bone_weapon bip01 r hand
+fixbone 1
 
 Heavyweight Xonotic Solider
diff --git a/qcsrc/client/autocvars.qh b/qcsrc/client/autocvars.qh
index 3cafa3961..cb4fa4f81 100644
--- a/qcsrc/client/autocvars.qh
+++ b/qcsrc/client/autocvars.qh
@@ -415,6 +415,4 @@ string autocvar__cl_playermodel;
 float autocvar_cl_precacheplayermodels;
 float autocvar_cl_deathglow;
 float autocvar_developer_csqcentities;
-float autocvar__animblend;
-float autocvar__animblend_fixbone;
 float autocvar_g_jetpack_attenuation;
diff --git a/qcsrc/client/csqcmodel_hooks.qc b/qcsrc/client/csqcmodel_hooks.qc
index 1d0c36ae9..3b4c95c16 100644
--- a/qcsrc/client/csqcmodel_hooks.qc
+++ b/qcsrc/client/csqcmodel_hooks.qc
@@ -398,11 +398,8 @@ void CSQCModel_AutoTagIndex_Apply(void)
 					}
 					else if(self.tag_entity.isplayermodel)
 					{
-						self.tag_index = gettagindex(self.tag_entity, "weapon");
-						if(!self.tag_index)
-							self.tag_index = gettagindex(self.tag_entity, "tag_weapon");
-						if(!self.tag_index)
-							self.tag_index = gettagindex(self.tag_entity, "bip01 r hand");
+						skeleton_loadinfo(self.tag_entity);
+						self.tag_index = self.tag_entity.bone_weapon;
 					}
 				}
 
@@ -611,7 +608,8 @@ void CSQCModel_Hook_PreDraw(float isplayer)
 		else
 		{
 			// we know that frame3 and frame4 fields, used by InterpolateAnimation, are left alone - but that is all we know!
-			float doblend = autocvar__animblend;
+			skeleton_loadinfo(self);
+			float doblend = (self.bone_upperbody >= 0);
 			float onground = 0;
 			if(self == csqcplayer)
 			{
diff --git a/qcsrc/client/player_skeleton.qc b/qcsrc/client/player_skeleton.qc
index 2834343d0..ca6190f45 100644
--- a/qcsrc/client/player_skeleton.qc
+++ b/qcsrc/client/player_skeleton.qc
@@ -1,19 +1,47 @@
-.float skeleton_modelindex;
+.float skeleton_info_modelindex;
+.float skeleton_info_skin;
 #define BONETYPE_LOWER 0
 #define BONETYPE_UPPER 1
 #define MAX_BONES 128
 .float skeleton_bonetype[MAX_BONES];
-.float skeleton_fixrotatebone;
-.float skeleton_bone;
-.float skeleton_aimbone;
 .float skeleton_numbones;
 
-void skeleton_identifybones(entity e)
+void skeleton_loadinfo(entity e)
+{
+	if(e.skeleton_info_modelindex == e.modelindex && e.skeleton_info_skin == e.skin)
+		return;
+	e.bone_upperbody = 0;
+	e.bone_weapon = gettagindex(e, "weapon");
+	if(!e.bone_weapon)
+		e.bone_weapon = gettagindex(e, "tag_weapon");
+	if(!e.bone_weapon)
+		e.bone_weapon = gettagindex(e, "bip01 r hand");
+	e.fixbone = 0;
+	if(get_model_parameters(e.model, e.skin))
+	{
+		if(get_model_parameters_bone_upperbody)
+			e.bone_upperbody = gettagindex(e, get_model_parameters_bone_upperbody);
+		if(get_model_parameters_bone_weapon)
+			e.bone_weapon = gettagindex(e, get_model_parameters_bone_weapon);
+		e.fixbone = get_model_parameters_fixbone;
+	}
+	else
+		dprint("No model parameters for ", e.model, "\n");
+	dprint(e.model, " uses ", ftos(e.bone_upperbody), " ", ftos(e.fixbone), "\n");
+	get_model_parameters(string_null, 0);
+	e.skeleton_info_modelindex = e.modelindex;
+	e.skeleton_info_skin = e.skin;
+	if(e.skeletonindex)
+	{
+		skel_delete(e.skeletonindex);
+		e.skeletonindex = 0;
+	}
+}
+
+void skeleton_markbones(entity e)
 {
 	float s = e.skeletonindex;
 	float n = (e.skeleton_numbones = skel_get_numbones(s));
-	e.skeleton_aimbone = 0;
-	e.skeleton_fixrotatebone = 0;
 	float i;
 	for(i = 1; i <= n; ++i)
 	{
@@ -21,29 +49,23 @@ void skeleton_identifybones(entity e)
 		float p = skel_get_boneparent(s, i);
 		if(p > 0)
 			t = e.(skeleton_bonetype[p-1]);
-		string nm = skel_get_bonename(s, i);
-		if(nm == "spine2")
-		{
-			e.skeleton_fixrotatebone = i;
+		if(i == e.bone_upperbody)
 			t = BONETYPE_UPPER;
-		}
-		if(nm == "upperarm_R")
-			e.skeleton_aimbone = i;
 		e.(skeleton_bonetype[i-1]) = t;
 	}
 }
 
 void skeleton_fixbone(entity e, vector ang)
 {
-	if(!e.skeleton_fixrotatebone)
+	if(!e.bone_upperbody)
 		return;
 	float s = e.skeletonindex;
 
-	skel_get_boneabs(s, e.skeleton_fixrotatebone);
+	skel_get_boneabs(s, e.bone_upperbody);
 	vector ang_cur = fixedvectoangles2(v_forward, v_up);
 	vector fix = AnglesTransform_LeftDivide(ang_cur, ang);
 	fixedmakevectors(fix);
-	skel_mul_bone(s, e.skeleton_fixrotatebone, '0 0 0');
+	skel_mul_bone(s, e.bone_upperbody, '0 0 0');
 }
 
 void free_skeleton_from_frames(entity e)
@@ -58,19 +80,10 @@ void free_skeleton_from_frames(entity e)
 void skeleton_from_frames(entity e)
 {
 	float m = e.modelindex;
-	if(m != e.skeleton_modelindex)
+	if(!e.skeletonindex)
 	{
-		if(e.skeletonindex)
-		{
-			skel_delete(e.skeletonindex);
-			e.skeletonindex = 0;
-		}
-		m = (e.skeleton_modelindex = e.modelindex);
-		if(m)
-		{
-			e.skeletonindex = skel_create(m);
-			skeleton_identifybones(e);
-		}
+		e.skeletonindex = skel_create(m);
+		skeleton_markbones(e);
 	}
 	float s = e.skeletonindex;
 	if(!s)
@@ -82,7 +95,7 @@ void skeleton_from_frames(entity e)
 	float savelerpfrac4 = e.lerpfrac4;
 
 	vector fixbone_oldangles = '0 0 0';
-	if(autocvar__animblend_fixbone)
+	if(e.fixbone)
 	{
 		// make all bones BONETYPE_UPPER
 		e.lerpfrac = 0;
@@ -91,7 +104,7 @@ void skeleton_from_frames(entity e)
 		// build skeleton
 		skel_build(s, e, m, 0, 1, n);
 		// get hip bone
-		skel_get_boneabs(s, e.skeleton_fixrotatebone);
+		skel_get_boneabs(s, e.bone_upperbody);
 		fixbone_oldangles = fixedvectoangles2(v_forward, v_up);
 	}
 
@@ -123,7 +136,7 @@ void skeleton_from_frames(entity e)
 	e.lerpfrac3 = savelerpfrac3;
 	e.lerpfrac4 = savelerpfrac4;
 
-	if(autocvar__animblend_fixbone)
+	if(e.fixbone)
 	{
 		// FIX IT
 		skeleton_fixbone(e, fixbone_oldangles);
diff --git a/qcsrc/client/player_skeleton.qh b/qcsrc/client/player_skeleton.qh
index 292cfca09..2cbb6187c 100644
--- a/qcsrc/client/player_skeleton.qh
+++ b/qcsrc/client/player_skeleton.qh
@@ -1,2 +1,7 @@
 void free_skeleton_from_frames(entity e);
 void skeleton_from_frames(entity e);
+void skeleton_loadinfo(entity e);
+
+.float bone_upperbody;
+.float bone_weapon;
+.float fixbone;
diff --git a/qcsrc/common/util.qc b/qcsrc/common/util.qc
index 404bd7e5a..bb2fcba0a 100644
--- a/qcsrc/common/util.qc
+++ b/qcsrc/common/util.qc
@@ -2011,9 +2011,16 @@ float get_model_parameters(string m, float sk)
 	get_model_parameters_weight = -1;
 	get_model_parameters_age = -1;
 	get_model_parameters_desc = string_null;
+	get_model_parameters_bone_upperbody = string_null;
+	get_model_parameters_bone_weapon = string_null;
+	get_model_parameters_fixbone = 0;
 
 	if not(m)
 		return 1;
+
+	if(substring(m, -9, 5) == "_lod1" || substring(m, -9, 5) == "_lod2")
+		m = strcat(substring(m, 0, -10), substring(m, -4, -1));
+
 	if(sk < 0)
 	{
 		if(substring(m, -4, -1) != ".txt")
@@ -2062,6 +2069,12 @@ float get_model_parameters(string m, float sk)
 			get_model_parameters_weight = stof(s);
 		if(c == "age")
 			get_model_parameters_age = stof(s);
+		if(c == "bone_upperbody")
+			get_model_parameters_bone_upperbody = s;
+		if(c == "bone_weapon")
+			get_model_parameters_bone_weapon = s;
+		if(c == "fixbone")
+			get_model_parameters_fixbone = stof(s);
 	}
 
 	while((s = fgets(fh)))
diff --git a/qcsrc/common/util.qh b/qcsrc/common/util.qh
index 4e553e4ba..8b1170b4e 100644
--- a/qcsrc/common/util.qh
+++ b/qcsrc/common/util.qh
@@ -250,6 +250,9 @@ float get_model_parameters_species;
 string get_model_parameters_sex;
 float get_model_parameters_weight;
 float get_model_parameters_age;
+string get_model_parameters_bone_upperbody;
+string get_model_parameters_bone_weapon;
+float get_model_parameters_fixbone;
 string get_model_parameters_desc;
 float get_model_parameters(string mod, float skn); // call with string_null to clear; skin -1 means mod is the filename of the txt file and is to be split
 
-- 
2.39.5