This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Tools/W3DView/AnimReportPage.cpp

216 lines
5.9 KiB
C++

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 3 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, see <http://www.gnu.org/licenses/>.
*/
// AnimReportPage.cpp : implementation file
//
#include "stdafx.h"
#include "w3dview.h"
#include "W3DViewDoc.h"
#include "AdvancedAnimSheet.h"
#include "AnimReportPage.h"
#include "HAnim.h"
#include "HTree.h"
#include "Utils.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAnimReportPage property page
IMPLEMENT_DYNCREATE(CAnimReportPage, CPropertyPage)
CAnimReportPage::CAnimReportPage(CAdvancedAnimSheet *sheet)
: CPropertyPage(CAnimReportPage::IDD),
m_Sheet(sheet)
{
//{{AFX_DATA_INIT(CAnimReportPage)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
CAnimReportPage::~CAnimReportPage()
{
}
void CAnimReportPage::DoDataExchange(CDataExchange* pDX)
{
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAnimReportPage)
DDX_Control(pDX, IDC_ANIM_REPORT, m_AnimReport);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAnimReportPage, CPropertyPage)
//{{AFX_MSG_MAP(CAnimReportPage)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAnimReportPage message handlers
BOOL CAnimReportPage::OnInitDialog()
{
CPropertyPage::OnInitDialog();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CAnimReportPage::FillListControl()
{
// Add the first column to the animation report. All bone names will
// go in this column.
m_AnimReport.InsertColumn(0, "Bone Name");
// Get the current render object and it's HTree. If it doesn't have
// an HTree, then it's not animating and we're not interested.
RenderObjClass *robj = ::GetCurrentDocument()->GetDisplayedObject();
if (robj == NULL)
return;
const HTreeClass *htree = robj->Get_HTree();
if (htree == NULL)
return;
// Get a sorted array of animations that affect the currently active object.
HAnimClass **anim = m_Sheet->GetAnims();
int anim_count = m_Sheet->GetAnimCount();
/*
** Create a column in the report view for each animation.
*/
int column_count; // number of columns in the report view (EXCLUDING the bone column)
bool indirect; // true if we have one column per animation selected in the mixing page
if (m_Sheet->m_SelectedAnims.Count() > 0)
{
column_count = m_Sheet->m_SelectedAnims.Count();
indirect = true;
}
else
{
column_count = anim_count;
indirect = false;
}
int i, j;
int anim_idx; // column index, essentially (anim_idx + 1 == column for that anim)
for (i = 0; i < column_count; i++)
{
// Add a new column with the name of this animation as the title.
anim_idx = indirect ? m_Sheet->m_SelectedAnims[i] : i;
if (m_AnimReport.InsertColumn(anim_idx+1, anim[anim_idx]->Get_Name(), LVCFMT_CENTER) == -1)
{
// Failed to add a new column to the list control.
ASSERT(false);
}
}
/*
** Add a row to the report for each bone in the object affected by
** an animation. It's entry (row/col) will contain the animation
** channels with valid animation data.
*/
for (i = 0; i < column_count; i++)
{
// Grab the anim pointer directly.
anim_idx = indirect ? m_Sheet->m_SelectedAnims[i] : i;
HAnimClass *pAnim = anim[anim_idx];
// Which bones does it affect, and how?
int num_bones = robj->Get_Num_Bones();
for (j = 1; j < num_bones; j++) // skip bone 0, which is always the root bone
{
// Add each bone to the report (regardless of animation status)
// if it isn't already there.
int idx = FindItem(htree->Get_Bone_Name(j));
if (idx == -1)
{
// Wasn't present, add a new item for this bone.
idx = m_AnimReport.InsertItem(m_AnimReport.GetItemCount(),
htree->Get_Bone_Name(j));
}
if (pAnim->Is_Node_Motion_Present(j))
{
// Add motion channel info to the appropriate column.
char channels[6]; // strlen("XYZQV")+1
ZeroMemory(channels, sizeof(channels));
MakeChannelStr(j, pAnim, channels);
m_AnimReport.SetItem(idx, i+1, LVIF_TEXT, channels, 0,0,0,0);
}
}
}
// Make the columns sized nicely.
m_AnimReport.SetColumnWidth(0, LVSCW_AUTOSIZE);
for (i = 0; i < column_count; i++)
m_AnimReport.SetColumnWidth(i+1, LVSCW_AUTOSIZE_USEHEADER);
// All done, the report view is set up.
}
int CAnimReportPage::FindItem (const char *item_name)
{
LVFINDINFO lvfi;
lvfi.flags = LVFI_STRING;
lvfi.psz = item_name;
return m_AnimReport.FindItem(&lvfi);
}
void CAnimReportPage::MakeChannelStr (int bone_idx, HAnimClass *hanim, char *channels)
{
if (hanim->Has_X_Translation(bone_idx))
strcat(channels, "X");
if (hanim->Has_Y_Translation(bone_idx))
strcat(channels, "Y");
if (hanim->Has_Z_Translation(bone_idx))
strcat(channels, "Z");
if (hanim->Has_Rotation(bone_idx))
strcat(channels, "Q");
if (hanim->Has_Visibility(bone_idx))
strcat(channels, "V");
}
BOOL CAnimReportPage::OnSetActive()
{
// Delete all info in the report view.
m_AnimReport.DeleteAllItems();
while (m_AnimReport.DeleteColumn(0));
// Fill the list control each time we're set active so that
// a change in selection on the mixing page will have an
// effect on this page.
FillListControl();
return CPropertyPage::OnSetActive();
}