Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
1190 lines
26 KiB
C++
1190 lines
26 KiB
C++
// CurveEditor.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "pixelwhippro.h"
|
|
#include "CurveEditor.h"
|
|
#include "EffectEditWin.h"
|
|
#include "TreeParamView.h"
|
|
#include "DataParamView.h"
|
|
#include "CurveSet.h"
|
|
#include <GosFx\GosFx.hpp>
|
|
|
|
extern CPixelWhipProApp theApp;
|
|
extern gosFX::Effect *CurrentEffect;
|
|
|
|
#define LINEDIVS 30
|
|
#define HANDLELEN 5
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CCurveEditor
|
|
|
|
//IMPLEMENT_DYNCREATE(CCurveEditor, CWnd)
|
|
|
|
CCurveEditor::CCurveEditor()
|
|
{
|
|
CurrentEditMode=MOVE;
|
|
EditHan=EditVar=false;
|
|
StartY=-100;
|
|
EndY=100;
|
|
NumCurves=0;
|
|
DCurve=VCurve=NULL;
|
|
CurrentCSet=NULL;
|
|
SelectedKey=-1;
|
|
}
|
|
|
|
CCurveEditor::~CCurveEditor()
|
|
{
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CCurveEditor, CWnd)
|
|
//{{AFX_MSG_MAP(CCurveEditor)
|
|
ON_WM_CLOSE()
|
|
ON_WM_PAINT()
|
|
ON_COMMAND(ID_EDIT_INSERTMODE, OnEditInsertmode)
|
|
ON_COMMAND(ID_EDIT_MOVEMODE, OnEditMovemode)
|
|
ON_COMMAND(ID_EDIT_PANMODE, OnEditPanmode)
|
|
ON_COMMAND(ID_EDIT_SCALEMODE, OnEditScalemode)
|
|
ON_COMMAND(ID_EDIT_ZOOMMODE, OnEditZoommode)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_INSERTMODE, OnUpdateEditInsertmode)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_MOVEMODE, OnUpdateEditMovemode)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_PANMODE, OnUpdateEditPanmode)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_SCALEMODE, OnUpdateEditScalemode)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_ZOOMMODE, OnUpdateEditZoommode)
|
|
ON_COMMAND(ID_EDIT_EDITVARAINCECURVE, OnEditEditvaraincecurve)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_EDITVARAINCECURVE, OnUpdateEditEditvaraincecurve)
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_COMMAND(ID_EDIT_DELETEVERTEX, OnEditDeletevertex)
|
|
ON_COMMAND(ID_VIEW_ZOOMTOCURVE, OnViewZoomtocurve)
|
|
ON_WM_CREATE()
|
|
ON_WM_KEYDOWN()
|
|
ON_WM_SIZE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CCurveEditor message handlers
|
|
|
|
void CCurveEditor::OnClose()
|
|
{
|
|
ShowWindow(SW_HIDE);
|
|
// CWnd::OnClose();
|
|
}
|
|
|
|
|
|
void CCurveEditor::Refresh()
|
|
{
|
|
SelectedKey=-1;
|
|
ReDraw();
|
|
}
|
|
|
|
|
|
void CCurveEditor::OnPaint()
|
|
{
|
|
|
|
CPaintDC dc(this); // device context for painting
|
|
|
|
ReDrawInternal();
|
|
}
|
|
|
|
void CCurveEditor::DrawHandles(CDC *dc,gosFX::Curve *curve)
|
|
{
|
|
CRect crct;
|
|
GetClientRect(&crct);
|
|
int hlen=crct.Width()<crct.Height()?crct.Width():crct.Height()/HANDLELEN;
|
|
CPoint lpt;
|
|
|
|
if(curve)
|
|
{
|
|
Check_Object(curve);
|
|
|
|
switch(curve->m_type)
|
|
{
|
|
|
|
case gosFX::Curve::e_SplineType:
|
|
{
|
|
gosFX::SplineCurve *SCurve=(gosFX::SplineCurve *)curve;
|
|
double ang;
|
|
float slp;
|
|
|
|
lpt.x=0;
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(0.0f,0.0f),crct.Height());
|
|
dc->MoveTo(lpt);
|
|
slp=SCurve->ComputeSlope(0.0f);
|
|
slp=(float)(CurveToClient(slp,crct.Height())-CurveToClient(0.0f,crct.Height()))/crct.Width();
|
|
ang=atan(slp);
|
|
|
|
lpt.x+=(int)((float)hlen*cos(ang));
|
|
lpt.y+=(int)((float)hlen*sin(ang));
|
|
H1Pos=lpt;
|
|
dc->LineTo(lpt);
|
|
dc->Ellipse(lpt.x-5,lpt.y-5,lpt.x+5,lpt.y+5);
|
|
|
|
lpt.x=crct.Width();
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(1.0f,0.0f),crct.Height());
|
|
dc->MoveTo(lpt);
|
|
|
|
slp=SCurve->ComputeSlope(1.0f);
|
|
slp=(float)(CurveToClient(slp,crct.Height())-CurveToClient(0.0f,crct.Height()))/crct.Width();
|
|
ang=atan(slp);
|
|
lpt.x-=(int)(hlen*cos(ang));
|
|
lpt.y-=(int)(hlen*sin(ang));
|
|
|
|
H2Pos=lpt;
|
|
dc->LineTo(lpt);
|
|
dc->Ellipse(lpt.x-5,lpt.y-5,lpt.x+5,lpt.y+5);
|
|
|
|
}
|
|
break;
|
|
|
|
case gosFX::Curve::e_ComplexType:
|
|
{
|
|
gosFX::ComplexCurve *SCurve=(gosFX::ComplexCurve *)curve;
|
|
Stuff::Scalar tme;
|
|
tme=(*SCurve)[SCurve->GetKeyCount()-1].m_time;
|
|
lpt.x=(int)(tme*crct.Width());
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(tme,0.0f),crct.Height());
|
|
dc->MoveTo(lpt);
|
|
|
|
lpt.x=crct.Width();
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(1.0f,0.0f),crct.Height());
|
|
H1Pos=lpt;
|
|
dc->LineTo(lpt);
|
|
dc->Ellipse(lpt.x-5,lpt.y-5,lpt.x+5,lpt.y+5);
|
|
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CCurveEditor::DrawCurve(CDC *dc,gosFX::Curve *curve,bool DrawKeys)
|
|
{
|
|
CRect crct;
|
|
GetClientRect(&crct);
|
|
|
|
Check_Object(curve);
|
|
|
|
switch(curve->m_type)
|
|
{
|
|
case gosFX::Curve::e_ConstantType:
|
|
{
|
|
CPoint lpt;
|
|
gosFX::ConstantCurve *SCurve=(gosFX::ConstantCurve *)curve;
|
|
|
|
lpt.x=0;
|
|
lpt.y=CurveToClient(SCurve->m_value,crct.Height());
|
|
if(DrawKeys)
|
|
{
|
|
dc->Rectangle(lpt.x-5,lpt.y-5,lpt.x+5,lpt.y+5);
|
|
}
|
|
|
|
dc->MoveTo(lpt);
|
|
lpt.x=crct.Width();
|
|
dc->LineTo(lpt);
|
|
|
|
}
|
|
break;
|
|
|
|
case gosFX::Curve::e_LinearType:
|
|
{
|
|
CPoint lpt;
|
|
gosFX::LinearCurve *SCurve=(gosFX::LinearCurve *)curve;
|
|
|
|
lpt.x=0;
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(0.0f,0.0f),crct.Height());
|
|
if(DrawKeys)
|
|
{
|
|
dc->Rectangle(lpt.x-5,lpt.y-5,lpt.x+5,lpt.y+5);
|
|
}
|
|
|
|
dc->MoveTo(lpt);
|
|
lpt.x=crct.Width();
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(1.0f,0.0f),crct.Height());
|
|
dc->LineTo(lpt);
|
|
|
|
}
|
|
break;
|
|
|
|
case gosFX::Curve::e_SplineType:
|
|
{
|
|
gosFX::SplineCurve *SCurve=(gosFX::SplineCurve *)curve;
|
|
|
|
CPoint lpt;
|
|
|
|
if(DrawKeys)
|
|
{
|
|
lpt.x=0;
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(0.0f,0.0f),crct.Height());
|
|
dc->Rectangle(lpt.x-5,lpt.y-5,lpt.x+5,lpt.y+5);
|
|
lpt.x=crct.Width();
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(1.0f,0.0f),crct.Height());
|
|
dc->Rectangle(lpt.x-5,lpt.y-5,lpt.x+5,lpt.y+5);
|
|
}
|
|
|
|
lpt.x=0;
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(0.0f,0.0f),crct.Height());
|
|
|
|
float finc,linelen=1.0f/LINEDIVS;
|
|
|
|
dc->MoveTo(lpt);
|
|
|
|
for(finc=linelen;finc<=1.0f;finc+=linelen)
|
|
{
|
|
lpt.x=(long)(finc*crct.Width());
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(finc,0.0f),crct.Height());
|
|
dc->LineTo(lpt);
|
|
}
|
|
lpt.x=crct.Width();
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(1.0f,0.0f),crct.Height());
|
|
dc->LineTo(lpt);
|
|
|
|
}
|
|
break;
|
|
|
|
case gosFX::Curve::e_ComplexType:
|
|
{
|
|
gosFX::ComplexCurve *SCurve=(gosFX::ComplexCurve *)curve;
|
|
int key;
|
|
float st,finc,linelen=1.0f/LINEDIVS,nextx=0.0f;
|
|
CPoint lpt,pt;
|
|
if(DrawKeys)
|
|
{
|
|
for(key=0;key<SCurve->GetKeyCount();key++)
|
|
{
|
|
st=(*SCurve)[key].m_time;
|
|
lpt.x=(long)(st*crct.Width());
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(st,0.0f),crct.Height());
|
|
dc->Rectangle(lpt.x-5,lpt.y-5,lpt.x+5,lpt.y+5);
|
|
}
|
|
}
|
|
lpt.x=0;
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(0.0,0.0f),crct.Height());
|
|
|
|
key=1;
|
|
for(finc=0.0f;finc<=1.0f;finc+=linelen)
|
|
{
|
|
if(key<SCurve->GetKeyCount())
|
|
{
|
|
st=(*SCurve)[key].m_time;
|
|
|
|
if(finc>st)
|
|
{
|
|
finc=st;
|
|
key++;
|
|
}
|
|
else
|
|
{
|
|
if(st-finc<linelen) {finc=st; key++;}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if((1.0f-finc)<=linelen)
|
|
finc=1.0f;
|
|
}
|
|
|
|
pt.x=(long)(finc*crct.Width());
|
|
pt.y=CurveToClient(SCurve->ComputeValue(finc,0.0f),crct.Height());
|
|
dc->MoveTo(lpt);
|
|
dc->LineTo(pt);
|
|
lpt=pt;
|
|
if(finc<1.0f && (finc+linelen)>1.0f) finc-=linelen; //cap end
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
void CCurveEditor::OnEditInsertmode() { CurrentEditMode=INSERT; }
|
|
void CCurveEditor::OnEditMovemode() { CurrentEditMode=MOVE; }
|
|
void CCurveEditor::OnEditPanmode() { CurrentEditMode=PAN; }
|
|
void CCurveEditor::OnEditScalemode() { CurrentEditMode=SCALE; }
|
|
void CCurveEditor::OnEditZoommode() { CurrentEditMode=ZOOM; }
|
|
|
|
void CCurveEditor::OnUpdateEditInsertmode(CCmdUI* pCmdUI)
|
|
{ pCmdUI->SetCheck(CurrentEditMode==INSERT?1:0); }
|
|
|
|
void CCurveEditor::OnUpdateEditMovemode(CCmdUI* pCmdUI)
|
|
{ pCmdUI->SetCheck(CurrentEditMode==MOVE?1:0); }
|
|
|
|
void CCurveEditor::OnUpdateEditPanmode(CCmdUI* pCmdUI)
|
|
{ pCmdUI->SetCheck(CurrentEditMode==PAN?1:0); }
|
|
|
|
void CCurveEditor::OnUpdateEditScalemode(CCmdUI* pCmdUI)
|
|
{ pCmdUI->SetCheck(CurrentEditMode==SCALE?1:0); }
|
|
|
|
void CCurveEditor::OnUpdateEditZoommode(CCmdUI* pCmdUI)
|
|
{ pCmdUI->SetCheck(CurrentEditMode==ZOOM?1:0); }
|
|
|
|
void CCurveEditor::OnEditEditvaraincecurve()
|
|
{
|
|
EditVar=!EditVar;
|
|
SelectedKey=-1;
|
|
ReDraw();
|
|
}
|
|
|
|
void CCurveEditor::OnUpdateEditEditvaraincecurve(CCmdUI* pCmdUI)
|
|
{ pCmdUI->SetCheck(EditVar?1:0); }
|
|
|
|
void CCurveEditor::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
switch(CurrentEditMode)
|
|
{
|
|
case INSERT:
|
|
break;
|
|
case MOVE:
|
|
ReleaseCapture();
|
|
break;
|
|
case PAN:
|
|
ReleaseCapture();
|
|
break;
|
|
case SCALE:
|
|
ReleaseCapture();
|
|
break;
|
|
case ZOOM:
|
|
ReleaseCapture();
|
|
break;
|
|
}
|
|
|
|
CWnd::OnLButtonUp(nFlags, point);
|
|
}
|
|
|
|
void CCurveEditor::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
if(nFlags&MK_LBUTTON)
|
|
{
|
|
CRect rct;
|
|
GetClientRect(&rct);
|
|
|
|
|
|
switch(CurrentEditMode)
|
|
{
|
|
case INSERT:
|
|
break;
|
|
case MOVE:
|
|
{
|
|
gosFX::Curve *Curve=EditVar?VCurve:DCurve;
|
|
|
|
if(Curve)
|
|
{
|
|
Check_Object(Curve);
|
|
|
|
Stuff::DynamicMemoryStream stream;
|
|
|
|
if(CurrentCSet)
|
|
CurrentCSet->PushState();
|
|
|
|
Stuff::Scalar newy;
|
|
|
|
newy=ClientToCurve(point.y,rct.Height());
|
|
switch(Curve->m_type)
|
|
{
|
|
case gosFX::Curve::e_ConstantType:
|
|
{
|
|
gosFX::ConstantCurve *SCurve=(gosFX::ConstantCurve *)Curve;
|
|
SCurve->SetCurve(newy);
|
|
}
|
|
break;
|
|
|
|
case gosFX::Curve::e_LinearType:
|
|
{
|
|
gosFX::LinearCurve *SCurve=(gosFX::LinearCurve *)Curve;
|
|
Stuff::Scalar v0,v1;
|
|
v0=SCurve->ComputeValue(0.0f,0.0f);
|
|
v1=SCurve->ComputeValue(1.0f,0.0f);
|
|
|
|
if(SelectedKey<0)
|
|
v0=newy;
|
|
else
|
|
v1=newy;
|
|
|
|
SCurve->SetCurve(v0,v1);
|
|
}
|
|
break;
|
|
|
|
case gosFX::Curve::e_SplineType:
|
|
{
|
|
gosFX::SplineCurve *SCurve=(gosFX::SplineCurve *)Curve;
|
|
Stuff::Scalar v0,v1,s0,s1;
|
|
v0=SCurve->ComputeValue(0.0f,0.0f);
|
|
v1=SCurve->ComputeValue(1.0f,0.0f);
|
|
s0=SCurve->ComputeSlope(0.0f);
|
|
s1=SCurve->ComputeSlope(1.0f);
|
|
|
|
if(EditHan)
|
|
{
|
|
float cx=(float)point.x/rct.Width();
|
|
if(cx<0.00000001f || fabs(cx-1.0f)<0.00000001f) return;
|
|
if(SelectedKey<0)
|
|
s0=(newy-SCurve->ComputeValue(0.0f,0.0f))/cx;
|
|
else
|
|
s1=-((newy-SCurve->ComputeValue(1.0f,0.0f))/(1.0f-cx));
|
|
}
|
|
else
|
|
{
|
|
if(SelectedKey<0)
|
|
v0=newy;
|
|
else
|
|
v1=newy;
|
|
}
|
|
SCurve->SetCurve(v0,s0,v1,s1);
|
|
}
|
|
break;
|
|
|
|
case gosFX::Curve::e_ComplexType:
|
|
if(SelectedKey>=0)
|
|
{
|
|
gosFX::ComplexCurve *SCurve=(gosFX::ComplexCurve *)Curve;
|
|
if(EditHan)
|
|
{
|
|
Stuff::Scalar val,tme,ntme;
|
|
tme=(*SCurve)[SCurve->GetKeyCount()-1].m_time;
|
|
val=(*SCurve)[SCurve->GetKeyCount()-1].m_value;
|
|
ntme=((float)point.x/rct.Width());
|
|
if(point.x<(tme*rct.Width()) || (ntme-tme)<0.000001f) return;
|
|
(*SCurve)[SCurve->GetKeyCount()-1].SetLinearKey(tme,val,newy,ntme-tme);
|
|
}
|
|
else
|
|
{
|
|
Stuff::Scalar tme,slp;
|
|
|
|
int MinX,MaxX;
|
|
if(SelectedKey==0)
|
|
MinX=0;
|
|
else
|
|
MinX=(int)ceil((*SCurve)[SelectedKey-1].m_time*rct.Width())+1;
|
|
|
|
if(SelectedKey==SCurve->GetKeyCount()-1)
|
|
MaxX=rct.Width();
|
|
else
|
|
MaxX=(int)floor((*SCurve)[SelectedKey+1].m_time*rct.Width())-1;
|
|
|
|
int xval=point.x;
|
|
xval=xval<MinX?MinX:xval;
|
|
xval=xval>MaxX?MaxX:xval;
|
|
// slp=(*SCurve)[SelectedKey].m_slope;
|
|
slp=SCurve->ComputeValue(1.0f,0.0f);
|
|
tme=(float)xval/rct.Width();
|
|
if(tme<1.0f)
|
|
{
|
|
(*SCurve)[SelectedKey].SetLinearKey(tme,newy,slp,1.0f-tme);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
} //end of cs type
|
|
FixCurve(Curve);
|
|
|
|
if(CurrentCSet)
|
|
CurrentCSet->VerifyAndPop();
|
|
|
|
theApp.ParamWin->DataPane->UpdateControls();
|
|
ReDraw();
|
|
|
|
}//end of If Curve
|
|
}
|
|
break;
|
|
case PAN:
|
|
{
|
|
float add;
|
|
add=((point.y-OldPoint.y)*(EndY-StartY))/rct.Height();
|
|
StartY+=add;
|
|
EndY+=add;
|
|
ReDraw();
|
|
}
|
|
break;
|
|
case SCALE:
|
|
{
|
|
|
|
gosFX::Curve *Curve=EditVar?VCurve:DCurve;
|
|
|
|
if(Curve)
|
|
{
|
|
Check_Object(Curve);
|
|
|
|
Stuff::DynamicMemoryStream stream;
|
|
if(CurrentCSet)
|
|
CurrentCSet->PushState();
|
|
|
|
float perchange;
|
|
perchange=(float)pow((EndY-StartY)/2,(float)(OldPoint.y-point.y)/rct.Height());
|
|
Curve->AxisScale(perchange,0.0f);
|
|
theApp.ParamWin->DataPane->UpdateControls();
|
|
ReDraw();
|
|
|
|
if(CurrentCSet)
|
|
CurrentCSet->VerifyAndPop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
case ZOOM:
|
|
{
|
|
float perchange,add;
|
|
perchange=(float)pow(4.0,(float)(point.y-OldPoint.y)/rct.Height());
|
|
add=(EndY-StartY)*(1.0f-perchange);
|
|
StartY+=add;
|
|
EndY-=add;
|
|
ReDraw();
|
|
}
|
|
break;
|
|
}
|
|
OldPoint=point;
|
|
}
|
|
CWnd::OnMouseMove(nFlags, point);
|
|
}
|
|
|
|
void CCurveEditor::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
OldPoint=point;
|
|
|
|
switch(CurrentEditMode)
|
|
{
|
|
case INSERT:
|
|
{
|
|
|
|
CRect crct;
|
|
GetClientRect(&crct);
|
|
Stuff::DynamicMemoryStream stream;
|
|
if(CurrentCSet)
|
|
CurrentCSet->PushState();
|
|
|
|
gosFX::Curve *Curve=EditVar?VCurve:DCurve;
|
|
|
|
if(Curve && Curve->m_type==gosFX::Curve::e_ComplexType)
|
|
{
|
|
Check_Object(Curve);
|
|
gosFX::ComplexCurve *SCurve=(gosFX::ComplexCurve *)Curve;
|
|
SelectedKey=SCurve->InsertKey((float)point.x/crct.Width());
|
|
}
|
|
|
|
if(CurrentCSet)
|
|
CurrentCSet->VerifyAndPop();
|
|
|
|
theApp.Modified=true;
|
|
|
|
ReDraw();
|
|
}
|
|
break;
|
|
case MOVE:
|
|
SetCapture();
|
|
SelectedKey=GetClosestKey(point);
|
|
ReDraw();
|
|
theApp.Modified=true;
|
|
|
|
break;
|
|
case PAN:
|
|
SetCapture();
|
|
break;
|
|
case SCALE:
|
|
SetCapture();
|
|
theApp.Modified=true;
|
|
break;
|
|
case ZOOM:
|
|
SetCapture();
|
|
break;
|
|
}
|
|
|
|
CWnd::OnLButtonDown(nFlags, point);
|
|
}
|
|
|
|
void CCurveEditor::UpdateCurveList(HTREEITEM itm)
|
|
{
|
|
|
|
if(itm==NULL) return;
|
|
|
|
if(itm!=TVI_ROOT)
|
|
{
|
|
|
|
CurveSet *CSet=(CurveSet *)theApp.ParamWin->TreePane->m_PTree.GetItemData(itm);
|
|
|
|
gosFX::Curve *curve;
|
|
|
|
if(CSet)
|
|
curve=CSet->Curve;
|
|
else
|
|
curve=NULL;
|
|
|
|
if(curve)
|
|
{
|
|
Check_Object(curve);
|
|
|
|
if(!DCurve && theApp.ParamWin->TreePane->m_PTree.GetSelectedItem()==itm)
|
|
{
|
|
CurrentCSet=CSet;
|
|
|
|
DCurve=curve->GetSubCurve(0);
|
|
VCurve=curve->GetSubCurve(1);
|
|
EditHan=false;
|
|
}
|
|
else
|
|
if(theApp.ParamWin->TreePane->m_PTree.GetCheck(itm))
|
|
{
|
|
Curves[NumCurves++]=curve->GetSubCurve(0);
|
|
Verify(NumCurves<MAXCURVES);
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
CurrentCSet=NULL;
|
|
NumCurves=0;
|
|
DCurve=VCurve=NULL;
|
|
EditHan=false;
|
|
}
|
|
|
|
//Draw Children
|
|
HTREEITEM nitm=theApp.ParamWin->TreePane->m_PTree.GetChildItem(itm);
|
|
|
|
while(nitm!=NULL)
|
|
{
|
|
UpdateCurveList(nitm);
|
|
nitm=theApp.ParamWin->TreePane->m_PTree.GetNextSiblingItem(nitm);
|
|
}
|
|
|
|
if(itm==TVI_ROOT) ReDraw();
|
|
|
|
}
|
|
|
|
int CCurveEditor::GetClosestKey(CPoint &pnt)
|
|
{
|
|
|
|
int i;
|
|
CRect crct;
|
|
GetClientRect(&crct);
|
|
int kx,ky;
|
|
|
|
int dist,lval=crct.Width()*crct.Width()+crct.Height()*crct.Height();
|
|
int lnum=0;
|
|
|
|
gosFX::Curve *Curve=EditVar?VCurve:DCurve;
|
|
if(!Curve) return -1;
|
|
Check_Object(Curve);
|
|
|
|
switch(Curve->m_type)
|
|
{
|
|
case gosFX::Curve::e_ConstantType:
|
|
{
|
|
gosFX::ConstantCurve *SCurve=(gosFX::ConstantCurve *)Curve;
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case gosFX::Curve::e_LinearType:
|
|
{
|
|
gosFX::LinearCurve *SCurve=(gosFX::LinearCurve *)Curve;
|
|
if(pnt.x<crct.Width()/2) return -1; else return 0;
|
|
}
|
|
break;
|
|
|
|
case gosFX::Curve::e_SplineType:
|
|
{
|
|
gosFX::SplineCurve *SCurve=(gosFX::SplineCurve *)Curve;
|
|
int tval,lval,tdist,dist;
|
|
|
|
|
|
lval=0;
|
|
tval=(int)(pnt.y-CurveToClient(SCurve->ComputeValue(0.0f,0.0f),crct.Height()));
|
|
dist=pnt.x*pnt.x+tval*tval;
|
|
|
|
tval=(int)(pnt.y-CurveToClient(SCurve->ComputeValue(1.0f,0.0f),crct.Height()));
|
|
tdist=(pnt.x-crct.Width())*(pnt.x-crct.Width())+tval*tval;
|
|
if(tdist<dist) {dist=tdist; lval=1;}
|
|
|
|
tdist=(pnt.x-H1Pos.x)*(pnt.x-H1Pos.x)+(pnt.y-H1Pos.y)*(pnt.y-H1Pos.y);
|
|
if(tdist<dist) {dist=tdist; lval=2;}
|
|
|
|
tdist=(pnt.x-H2Pos.x)*(pnt.x-H2Pos.x)+(pnt.y-H2Pos.y)*(pnt.y-H2Pos.y);
|
|
if(tdist<dist) {dist=tdist; lval=3;}
|
|
|
|
switch(lval)
|
|
{
|
|
case 0: //left key
|
|
EditHan=false;
|
|
return -1;
|
|
break;
|
|
case 1: //right key
|
|
EditHan=false;
|
|
return 0;
|
|
break;
|
|
case 2: //left handle
|
|
EditHan=true;
|
|
return -1;
|
|
break;
|
|
case 3: //right handle
|
|
EditHan=true;
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
break;
|
|
|
|
case gosFX::Curve::e_ComplexType:
|
|
{
|
|
gosFX::ComplexCurve *SCurve=(gosFX::ComplexCurve *)Curve;
|
|
|
|
kx=crct.Width();
|
|
ky=(int)CurveToClient(SCurve->ComputeValue(1.0f,0.0f),crct.Height());
|
|
lval=(pnt.x-kx)*(pnt.x-kx)+(pnt.y-ky)*(pnt.y-ky);
|
|
lnum=-1;
|
|
|
|
for(i=0;i<SCurve->GetKeyCount();i++)
|
|
{
|
|
kx=(int)((*SCurve)[i].m_time*crct.Width());
|
|
ky=(int)CurveToClient(SCurve->ComputeValue((*SCurve)[i].m_time,0.0f),crct.Height());
|
|
dist=(pnt.x-kx)*(pnt.x-kx)+(pnt.y-ky)*(pnt.y-ky);
|
|
if(dist<lval) {lval=dist; lnum=i; }
|
|
}
|
|
|
|
if(lnum<0)
|
|
{
|
|
EditHan=true;
|
|
return SCurve->GetKeyCount()-1;
|
|
}
|
|
else
|
|
{
|
|
EditHan=false;
|
|
return lnum;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void CCurveEditor::OnEditDeletevertex()
|
|
{
|
|
|
|
gosFX::Curve *Curve=EditVar?VCurve:DCurve;
|
|
if(!Curve || Curve->m_type!=gosFX::Curve::e_ComplexType) return;
|
|
|
|
gosFX::ComplexCurve *SCurve=(gosFX::ComplexCurve *)Curve;
|
|
if(SelectedKey>0)
|
|
{
|
|
|
|
float cfx,cfy;
|
|
cfx=(*SCurve)[SelectedKey].m_time;
|
|
cfy=SCurve->ComputeValue(cfx,0.0f);
|
|
SCurve->DeleteKey(SelectedKey);
|
|
CRect crct;
|
|
GetClientRect(&crct);
|
|
SelectedKey=GetClosestKey(CPoint((long)(cfx*crct.Width()),CurveToClient(cfy,crct.Height())));
|
|
FixCurve(Curve);
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
for(i=1;i<SCurve->GetKeyCount();i++) SCurve->DeleteKey(i);
|
|
FixCurve(Curve);
|
|
}
|
|
|
|
ReDraw();
|
|
}
|
|
|
|
|
|
void CCurveEditor::FixCurve(gosFX::Curve *Curve)
|
|
{
|
|
|
|
|
|
switch(Curve->m_type)
|
|
{
|
|
|
|
|
|
case gosFX::Curve::e_SplineType:
|
|
{
|
|
gosFX::SplineCurve *SCurve=(gosFX::SplineCurve *)Curve;
|
|
}
|
|
break;
|
|
|
|
case gosFX::Curve::e_ComplexType:
|
|
{
|
|
gosFX::ComplexCurve *SCurve=(gosFX::ComplexCurve *)Curve;
|
|
|
|
Stuff::Scalar cval,nval,ctme,ntme;
|
|
if(SCurve->GetKeyCount()==1)
|
|
{
|
|
cval=(*SCurve)[0].m_value;
|
|
nval=SCurve->ComputeValue(1.0f,0.0f);
|
|
(*SCurve)[0].SetLinearKey(0.0f,cval,nval,1.0f);
|
|
|
|
}
|
|
else
|
|
{
|
|
cval=(*SCurve)[0].m_value;
|
|
(*SCurve)[0].SetLinearKey(0.0f,cval,cval,0.01f);
|
|
}
|
|
|
|
// Connect the Keys
|
|
int key;
|
|
for(key=0;key<SCurve->GetKeyCount()-1;key++)
|
|
{
|
|
ctme=(*SCurve)[key].m_time;
|
|
ntme=(*SCurve)[key+1].m_time;
|
|
cval=(*SCurve)[key].m_value;
|
|
nval=(*SCurve)[key+1].m_value;
|
|
(*SCurve)[key].SetLinearKey(ctme,cval,nval,ntme-ctme);
|
|
}
|
|
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
void CCurveEditor::OnViewZoomtocurve()
|
|
{
|
|
|
|
gosFX::Curve *Curve=EditVar?VCurve:DCurve;
|
|
|
|
if(Curve==NULL)
|
|
{
|
|
StartY=-100.0f;
|
|
EndY=100.0f;
|
|
return;
|
|
}
|
|
|
|
Curve->ExpensiveComputeRange(&StartY,&EndY);
|
|
|
|
float aval;
|
|
aval=(float)fabs(StartY);
|
|
aval=(float)fabs(EndY)>aval?(float)fabs(EndY):aval;
|
|
aval+=aval*0.2f;
|
|
StartY=-aval;
|
|
EndY=aval;
|
|
/*
|
|
if(StartY==EndY)
|
|
{
|
|
StartY-=.5;
|
|
EndY+=.5;
|
|
}
|
|
else
|
|
{
|
|
EndY+=(EndY-StartY)*0.1f;
|
|
StartY-=(EndY-StartY)*0.1f;
|
|
}
|
|
*/
|
|
|
|
ReDraw();
|
|
}
|
|
|
|
void CCurveEditor::DrawTicks(CDC *dc)
|
|
{
|
|
float cury,nexty;
|
|
int Ccury,Cnexty;
|
|
CRect rct;
|
|
GetClientRect(&rct);
|
|
|
|
dc->SelectObject(&TickPen);
|
|
CString lab;
|
|
CRect textrect;
|
|
|
|
dc->SetTextColor(0xffffff);
|
|
dc->SetBkColor(0x000000);
|
|
|
|
if(StartY<0)
|
|
{
|
|
cury=-StartY;
|
|
cury=(float)pow(10,(int)log10(cury));
|
|
Ccury=CurveToClient(-cury,rct.Height());
|
|
|
|
|
|
nexty=cury*0.1f;
|
|
Cnexty=CurveToClient(-nexty,rct.Height());
|
|
|
|
while((Ccury-Cnexty)>3 && Ccury>0 && -cury<EndY)
|
|
{
|
|
dc->MoveTo(0,Ccury);
|
|
dc->LineTo(rct.Width(),Ccury);
|
|
|
|
lab.Format("%5.3f",-cury);
|
|
textrect.top=Ccury-10; textrect.left=0;
|
|
textrect.bottom=Ccury+10; textrect.right=100;
|
|
dc->DrawText(lab,&textrect,DT_LEFT );
|
|
|
|
cury=nexty;
|
|
Ccury=Cnexty;
|
|
nexty=cury*0.1f;
|
|
Cnexty=CurveToClient(-nexty,rct.Height());
|
|
}
|
|
|
|
|
|
}
|
|
|
|
if(EndY>0)
|
|
{
|
|
cury=EndY;
|
|
cury=(float)pow(10,(int)log10(cury));
|
|
Ccury=CurveToClient(cury,rct.Height());
|
|
|
|
|
|
nexty=cury*0.1f;
|
|
Cnexty=CurveToClient(nexty,rct.Height());
|
|
|
|
while((Cnexty-Ccury)>3 && Ccury<rct.Height() && cury>StartY)
|
|
{
|
|
dc->MoveTo(0,Ccury);
|
|
dc->LineTo(rct.Width(),Ccury);
|
|
|
|
lab.Format("%5.3f",cury);
|
|
textrect.top=Ccury-10; textrect.left=0;
|
|
textrect.bottom=Ccury+10; textrect.right=100;
|
|
dc->DrawText(lab,&textrect,DT_LEFT );
|
|
|
|
cury=nexty;
|
|
Ccury=Cnexty;
|
|
nexty=cury*0.1f;
|
|
Cnexty=CurveToClient(nexty,rct.Height());
|
|
}
|
|
|
|
|
|
}
|
|
|
|
dc->SelectObject(&ZeroPen);
|
|
dc->MoveTo(0,CurveToClient(0,rct.Height()));
|
|
dc->LineTo(rct.Width(),CurveToClient(0,rct.Height()));
|
|
|
|
}
|
|
|
|
BOOL CCurveEditor::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
|
|
{
|
|
// TODO: Add your specialized code here and/or call the base class
|
|
|
|
return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
|
|
}
|
|
|
|
int CCurveEditor::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
{
|
|
if (CWnd::OnCreate(lpCreateStruct) == -1)
|
|
return -1;
|
|
|
|
LOGBRUSH lb;
|
|
|
|
|
|
lb.lbColor=0x00C800;
|
|
lb.lbStyle=BS_SOLID;
|
|
InactivePen.CreatePen(PS_SOLID,1,&lb);
|
|
|
|
lb.lbColor=0x7f7f7f;
|
|
lb.lbStyle=BS_SOLID;
|
|
TickPen.CreatePen(PS_DASHDOT,1,&lb);
|
|
|
|
lb.lbColor=0x00ffff;
|
|
lb.lbStyle=BS_SOLID;
|
|
ZeroPen.CreatePen(PS_DOT,1,&lb);
|
|
|
|
EditablePen.CreatePen(PS_SOLID,1,0x0000ff);
|
|
VarPen.CreatePen(PS_SOLID,1,0xff0000);
|
|
SelVertPen.CreatePen(PS_SOLID,1,0x00ff00);
|
|
BlackPen.CreatePen(PS_SOLID,1,(COLORREF)0x000000);
|
|
HandlePen.CreatePen(PS_SOLID,1,(COLORREF)0xff00ff);
|
|
BGBrush.CreateSolidBrush(0xC8C8C8);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CCurveEditor::ReDrawInternal()
|
|
{
|
|
if(theApp.ParamWin)
|
|
{
|
|
CDC *dc,*pDC=GetDC();
|
|
|
|
theApp.AllowDraw=false;
|
|
CDC bbufDC;
|
|
|
|
bbufDC.CreateCompatibleDC(pDC);
|
|
bbufDC.SelectObject(BackBuffer);
|
|
|
|
CRect crct;
|
|
GetClientRect(&crct);
|
|
// dc->SelectObject(&BGBrush);
|
|
// dc->Rectangle(crct);
|
|
/*
|
|
static bool flip=false;
|
|
flip=!flip;
|
|
pDC->BitBlt(0,0,crct.Width(),crct.Height(),NULL,0,0,flip?BLACKNESS:WHITENESS);
|
|
*/
|
|
dc=&bbufDC;
|
|
// dc=pDC;
|
|
dc->BitBlt(0,0,crct.Width(),crct.Height(),NULL,0,0,BLACKNESS);
|
|
int i;
|
|
|
|
dc->SelectObject(GetStockObject(NULL_BRUSH));
|
|
|
|
DrawTicks(dc);
|
|
|
|
dc->SelectObject(&InactivePen);
|
|
for(i=0;i<NumCurves;i++)
|
|
DrawCurve(dc,Curves[i]);
|
|
|
|
if(EditVar)
|
|
|
|
{
|
|
if(DCurve)
|
|
{
|
|
dc->SelectObject(&EditablePen);
|
|
DrawCurve(dc,DCurve);
|
|
}
|
|
if(VCurve)
|
|
{
|
|
dc->SelectObject(&VarPen);
|
|
DrawCurve(dc,VCurve,true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(VCurve)
|
|
{
|
|
dc->SelectObject(&VarPen);
|
|
DrawCurve(dc,VCurve);
|
|
}
|
|
if(DCurve)
|
|
{
|
|
dc->SelectObject(&EditablePen);
|
|
DrawCurve(dc,DCurve,true);
|
|
}
|
|
}
|
|
|
|
gosFX::Curve *Curve=EditVar?VCurve:DCurve;
|
|
|
|
//DrawHandles
|
|
dc->SelectObject(&HandlePen);
|
|
DrawHandles(dc,Curve);
|
|
|
|
//OverDrawSelected Key
|
|
dc->SelectObject(&SelVertPen);
|
|
if(Curve)
|
|
{
|
|
Check_Object(Curve);
|
|
switch(Curve->m_type)
|
|
{
|
|
case gosFX::Curve::e_ComplexType:
|
|
{
|
|
gosFX::ComplexCurve *SCurve=(gosFX::ComplexCurve *)Curve;
|
|
if(SelectedKey>=SCurve->GetKeyCount())
|
|
SelectedKey=-1;
|
|
if(SelectedKey!=-1)
|
|
{
|
|
float st=(*SCurve)[SelectedKey].m_time;
|
|
CPoint lpt;
|
|
lpt.x=(long)(st*crct.Width());
|
|
lpt.y=CurveToClient(SCurve->ComputeValue(st,0.0f),crct.Height());
|
|
dc->Rectangle(lpt.x-5,lpt.y-5,lpt.x+5,lpt.y+5);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if(SelectedKey<0)
|
|
{
|
|
CPoint lpt;
|
|
lpt.x=0;
|
|
lpt.y=CurveToClient(Curve->ExpensiveCompute(0.0f),crct.Height());
|
|
dc->Rectangle(lpt.x-5,lpt.y-5,lpt.x+5,lpt.y+5);
|
|
}
|
|
else
|
|
{
|
|
CPoint lpt;
|
|
lpt.x=crct.Width();
|
|
lpt.y=CurveToClient(Curve->ExpensiveCompute(1.0f),crct.Height());
|
|
dc->Rectangle(lpt.x-5,lpt.y-5,lpt.x+5,lpt.y+5);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
theApp.AllowDraw=true;
|
|
pDC->BitBlt(crct.left,crct.top,crct.Width(),crct.Height(),&bbufDC,0,0,SRCCOPY);
|
|
ReleaseDC(pDC);
|
|
}
|
|
|
|
}
|
|
|
|
void CCurveEditor::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
// TODO: Add your message handler code here and/or call default
|
|
switch(nChar)
|
|
{
|
|
case 'E':
|
|
OnEditMovemode();
|
|
break ;
|
|
case 'A':
|
|
OnEditInsertmode();
|
|
break ;
|
|
case 'Z':
|
|
OnEditZoommode();
|
|
break ;
|
|
case ' ':
|
|
OnEditPanmode();
|
|
break ;
|
|
case 'S':
|
|
OnEditScalemode();
|
|
break ;
|
|
case 'V':
|
|
OnEditEditvaraincecurve();
|
|
break ;
|
|
case 'F':
|
|
OnViewZoomtocurve();
|
|
break ;
|
|
case 'D':
|
|
OnEditDeletevertex();
|
|
break ;
|
|
}
|
|
|
|
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
|
|
}
|
|
|
|
|
|
void CCurveEditor::BuildBackBuffer()
|
|
{
|
|
BackBuffer.DeleteObject();
|
|
CRect crect;
|
|
GetClientRect(&crect);
|
|
CDC *pDC=GetDC();
|
|
BackBuffer.CreateCompatibleBitmap(pDC,crect.Width(),crect.Height());
|
|
ReleaseDC(pDC);
|
|
}
|
|
|
|
void CCurveEditor::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CWnd::OnSize(nType, cx, cy);
|
|
BuildBackBuffer();
|
|
// TODO: Add your message handler code here
|
|
|
|
}
|