2016-03-27 11:49:47 +02:00
|
|
|
/*
|
|
|
|
===========================================================================
|
2023-11-06 17:58:58 +01:00
|
|
|
Copyright (C) 2023 the OpenMoHAA team
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
|
|
|
|
OpenMoHAA source code 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.
|
|
|
|
|
|
|
|
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
// bonetable.cpp : Bone table
|
|
|
|
|
|
|
|
#include "q_shared.h"
|
2023-06-17 01:24:20 +02:00
|
|
|
#include "tiki.h"
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
void ChannelNameTable::CopyChannel(ChannelName_t *dest, const ChannelName_t *source)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-11-06 17:58:58 +01:00
|
|
|
memcpy(dest, source, sizeof(ChannelName_t));
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
void ChannelNameTable::SetChannelName(ChannelName_t *channel, const char *newName)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2024-09-20 21:53:48 +02:00
|
|
|
Q_strncpyz(channel->name, newName, sizeof(channel->name));
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ChannelNameTable::ChannelNameTable()
|
|
|
|
{
|
2023-11-06 17:58:58 +01:00
|
|
|
memset(this, 0, sizeof(ChannelNameTable));
|
|
|
|
m_iNumChannels = 0;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ChannelNameTable::PrintContents()
|
|
|
|
{
|
2023-11-06 17:58:58 +01:00
|
|
|
str channelList;
|
|
|
|
int i;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
for (i = 0; i < m_iNumChannels; i++) {
|
|
|
|
if (!m_Channels[i].name[0]) {
|
|
|
|
continue;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
channelList += str("c") + m_Channels[i].channelNum + ":" + str(m_Channels[i].name) + "\n";
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
SKEL_Message("ChannelNameTable contents:\n%s", channelList.c_str());
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
bool ChannelNameTable::FindIndexFromName(const char *name, int *indexPtr)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-11-06 17:58:58 +01:00
|
|
|
int sortValue;
|
|
|
|
int lowerBound;
|
|
|
|
int upperBound;
|
|
|
|
int index;
|
|
|
|
|
|
|
|
lowerBound = 0;
|
|
|
|
upperBound = m_iNumChannels - 1;
|
|
|
|
while (lowerBound <= upperBound) {
|
|
|
|
index = (lowerBound + upperBound) / 2;
|
|
|
|
sortValue = stricmp(name, m_Channels[index].name);
|
|
|
|
if (!sortValue) {
|
|
|
|
if (indexPtr) {
|
|
|
|
*indexPtr = index;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (sortValue <= 0) {
|
|
|
|
upperBound = index - 1;
|
|
|
|
} else {
|
|
|
|
lowerBound = index + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (indexPtr) {
|
|
|
|
*indexPtr = lowerBound;
|
|
|
|
}
|
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
int ChannelNameTable::FindNameLookup(const char *name)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-11-06 17:58:58 +01:00
|
|
|
int index;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
if (FindIndexFromName(name, &index)) {
|
|
|
|
return m_Channels[index].channelNum;
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
const char *ChannelNameTable::FindName(int index)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-11-06 17:58:58 +01:00
|
|
|
return FindNameFromLookup(m_lookup[index]);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
void ChannelNameTable::SortIntoTable(int index)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-11-06 17:58:58 +01:00
|
|
|
int i;
|
|
|
|
ChannelName_t tempName;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
CopyChannel(&tempName, &m_Channels[m_iNumChannels]);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
for (i = m_iNumChannels - 1; i >= index; i--) {
|
|
|
|
m_lookup[m_Channels[i].channelNum] = i + 1;
|
|
|
|
CopyChannel(&m_Channels[i + 1], &m_Channels[i]);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
m_lookup[tempName.channelNum] = index;
|
|
|
|
CopyChannel(&m_Channels[index], &tempName);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
static const char *bogusNameTable[] = {
|
|
|
|
"Bip01 Spine pos",
|
|
|
|
"Bip01 Spine1 pos",
|
|
|
|
"Bip01 Spine2 pos",
|
|
|
|
"Bip01 Neck pos",
|
|
|
|
"Bip01 Head pos",
|
|
|
|
"helmet bone pos",
|
|
|
|
"helmet bone rot",
|
|
|
|
"Bip01 R Clavicle pos",
|
|
|
|
"Bip01 R UpperArm pos",
|
|
|
|
"Bip01 R Forearm pos",
|
|
|
|
"Bip01 R Hand pos",
|
|
|
|
"Bip01 R Finger0 pos",
|
|
|
|
"Bip01 R Finger01 pos",
|
|
|
|
"Bip01 R Finger02 pos",
|
|
|
|
"Bip01 R Finger1 pos",
|
|
|
|
"Bip01 R Finger11 pos",
|
|
|
|
"Bip01 R Finger12 pos",
|
|
|
|
"Bip01 R Finger2 pos",
|
|
|
|
"Bip01 R Finger21 pos",
|
|
|
|
"Bip01 R Finger22 pos",
|
|
|
|
"Bip01 R Finger3 pos",
|
|
|
|
"Bip01 R Finger31 pos",
|
|
|
|
"Bip01 R Finger32 pos",
|
|
|
|
"Bip01 R Finger4 pos",
|
|
|
|
"Bip01 R Finger41 pos",
|
|
|
|
"Bip01 R Finger42 pos",
|
|
|
|
"Bip01 L Clavicle pos",
|
|
|
|
"Bip01 L UpperArm pos",
|
|
|
|
"Bip01 L Forearm pos",
|
|
|
|
"Bip01 L Hand pos",
|
|
|
|
"Bip01 L Finger0 pos",
|
|
|
|
"Bip01 L Finger01 pos",
|
|
|
|
"Bip01 L Finger02 pos",
|
|
|
|
"Bip01 L Finger1 pos",
|
|
|
|
"Bip01 L Finger11 pos",
|
|
|
|
"Bip01 L Finger12 pos",
|
|
|
|
"Bip01 L Finger2 pos",
|
|
|
|
"Bip01 L Finger21 pos",
|
|
|
|
"Bip01 L Finger22 pos",
|
|
|
|
"Bip01 L Finger3 pos",
|
|
|
|
"Bip01 L Finger31 pos",
|
|
|
|
"Bip01 L Finger32 pos",
|
|
|
|
"Bip01 L Finger4 pos",
|
|
|
|
"Bip01 L Finger41 pos",
|
|
|
|
"Bip01 L Finger42 pos",
|
|
|
|
"Bip01 L Toe0 pos",
|
|
|
|
"Bip01 R Toe0 pos",
|
|
|
|
"buckle bone pos",
|
|
|
|
"buckle bone rot",
|
|
|
|
"belt attachments bone pos",
|
|
|
|
"belt attachments bone rot",
|
|
|
|
"backpack bone pos",
|
|
|
|
"backpack bone rot",
|
|
|
|
"helper Lelbow pos",
|
|
|
|
"helper Lelbow rot",
|
|
|
|
"helper Lshoulder pos",
|
|
|
|
"helper Lshoulder rot",
|
|
|
|
"helper Lshoulder01 pos",
|
|
|
|
"helper Lshoulder01 rot",
|
|
|
|
"helper Rshoulder pos",
|
|
|
|
"helper Rshoulder rot",
|
|
|
|
"helper Lshoulder02 pos",
|
|
|
|
"helper Lshoulder02 rot",
|
|
|
|
"helper Relbow pos",
|
|
|
|
"helper Relbow rot",
|
|
|
|
"helper Lankle pos",
|
|
|
|
"helper Lankle rot",
|
|
|
|
"helper Lknee pos",
|
|
|
|
"helper Lknee rot",
|
|
|
|
"helper Rankle pos",
|
|
|
|
"helper Rankle rot",
|
|
|
|
"helper Rknee pos",
|
|
|
|
"helper Rknee rot",
|
|
|
|
"helper Lhip pos",
|
|
|
|
"helper Lhip rot",
|
|
|
|
"helper Lhip01 pos",
|
|
|
|
"helper Lhip01 rot",
|
|
|
|
"helper Rhip pos",
|
|
|
|
"helper Rhip rot",
|
|
|
|
"helper Rhip01 pos",
|
|
|
|
"helper Rhip01 rot",
|
|
|
|
"target_left_hand pos",
|
|
|
|
"target_left_hand rot",
|
|
|
|
"target_right_hand pos",
|
|
|
|
"target_right_hand rot",
|
|
|
|
"JAW open-closed pos",
|
|
|
|
"JAW open-closed rot",
|
|
|
|
"BROW_worry$",
|
|
|
|
"EYES_down$",
|
|
|
|
"EYES_Excited_$",
|
|
|
|
"EYES_L_squint$",
|
|
|
|
"EYES_left$",
|
|
|
|
"EYES_right$",
|
|
|
|
"EYES_smile$",
|
|
|
|
"EYES_up_$",
|
|
|
|
"JAW_open-open$",
|
|
|
|
"MOUTH_L_smile_open$",
|
|
|
|
"VISEME_Eat$",
|
|
|
|
"right foot placeholder pos"
|
|
|
|
"right foot placeholder rot"
|
|
|
|
"left foot placeholder pos"
|
|
|
|
"left foot placeholder rot"};
|
|
|
|
|
|
|
|
bool IsBogusChannelName(const char *name)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-11-06 17:58:58 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(bogusNameTable) / sizeof(bogusNameTable[0]); i++) {
|
|
|
|
if (!Q_stricmp(name, bogusNameTable[i])) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strstr(name, "Bip0") && !strstr(name, "Bip01") && !strstr(name, "Footsteps")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-06-13 23:04:33 +02:00
|
|
|
channelType_t GetBoneChannelType(const char* name)
|
2024-06-04 23:48:29 +02:00
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (!name) {
|
2024-06-13 23:04:33 +02:00
|
|
|
return CHANNEL_NONE;
|
2024-06-04 23:48:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (IsBogusChannelName(name)) {
|
2024-06-13 23:04:33 +02:00
|
|
|
return CHANNEL_NONE;
|
2024-06-04 23:48:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen(name);
|
|
|
|
if (len < 4) {
|
2024-06-13 23:04:33 +02:00
|
|
|
return CHANNEL_VALUE;
|
2024-06-04 23:48:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(name + len - 4, " rot")) {
|
2024-06-13 23:04:33 +02:00
|
|
|
return CHANNEL_ROTATION;
|
2024-06-04 23:48:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(name + len - 4, " pos")) {
|
2024-06-13 23:04:33 +02:00
|
|
|
return CHANNEL_POSITION;
|
2024-06-04 23:48:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (len >= 6 && !strcmp(name + len - 6, " rotFK")) {
|
2024-06-13 23:04:33 +02:00
|
|
|
return CHANNEL_NONE;
|
2024-06-04 23:48:29 +02:00
|
|
|
}
|
|
|
|
|
2024-06-13 23:04:33 +02:00
|
|
|
return CHANNEL_VALUE;
|
2024-06-04 23:48:29 +02:00
|
|
|
}
|
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
int ChannelNameTable::RegisterChannel(const char *name)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-11-06 17:58:58 +01:00
|
|
|
int index;
|
|
|
|
|
|
|
|
if (IsBogusChannelName(name)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FindIndexFromName(name, &index)) {
|
|
|
|
return m_Channels[index].channelNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_iNumChannels >= MAX_SKELETOR_CHANNELS) {
|
|
|
|
Com_Printf("==========================================================================\n");
|
|
|
|
Com_Printf("Skeletor channel name table, contents (in order of addition):\n");
|
|
|
|
|
|
|
|
for (index = 0; index < MAX_SKELETOR_CHANNELS; index++) {
|
|
|
|
Com_Printf("%s\n", m_Channels[m_lookup[index]].name);
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_Printf("==========================================================================\n");
|
|
|
|
SKEL_Error("Channel name table already has %i channels, can't add any more.", MAX_SKELETOR_CHANNELS);
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
SetChannelName(&m_Channels[m_iNumChannels], name);
|
|
|
|
m_Channels[m_iNumChannels].channelNum = m_iNumChannels;
|
|
|
|
SortIntoTable(index);
|
|
|
|
return m_iNumChannels++;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-11-06 17:58:58 +01:00
|
|
|
const char *ChannelNameTable::FindNameFromLookup(int index)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2024-06-10 23:40:34 +02:00
|
|
|
if (index >= m_iNumChannels) {
|
2023-11-06 17:58:58 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
2024-06-10 23:40:34 +02:00
|
|
|
|
|
|
|
return m_Channels[index].name;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|