/* ** 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 . */ // SplineTestView.cpp : implementation of the CSplineTestView class // #include "stdafx.h" #include "SplineTest.h" #include "SplineTestDoc.h" #include "SplineTestView.h" #include "curve.h" #include "hermitespline.h" #include "catmullromspline.h" #include "cardinalspline.h" #include "tcbspline.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif const float MIN_X = -10.0f; const float MIN_Y = -10.0f; const float MIN_Z = -10.0f; const float MAX_X = 10.0f; const float MAX_Y = 10.0f; const float MAX_Z = 10.0f; ///////////////////////////////////////////////////////////////////////////// // CSplineTestView IMPLEMENT_DYNCREATE(CSplineTestView, CView) BEGIN_MESSAGE_MAP(CSplineTestView, CView) //{{AFX_MSG_MAP(CSplineTestView) ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_WM_RBUTTONUP() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CSplineTestView construction/destruction CSplineTestView::CSplineTestView() { DrawTangents = false; } CSplineTestView::~CSplineTestView() { } BOOL CSplineTestView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CView::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // CSplineTestView drawing void CSplineTestView::OnDraw(CDC* pDC) { CSplineTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); Curve3DClass * curve = pDoc->Get_Curve(); if (curve == NULL) return; Vector3 pt; int x,y; // draw coordinate axes CPen blackpen; blackpen.CreatePen(PS_DASH,1,RGB(0,0,0)); pDC->SelectObject(&blackpen); Map_Point(Vector3(0,10,0),&x,&y); pDC->MoveTo(x,y); Map_Point(Vector3(0,-10,0),&x,&y); pDC->LineTo(x,y); Map_Point(Vector3(10,0,0),&x,&y); pDC->MoveTo(x,y); Map_Point(Vector3(-10,0,0),&x,&y); pDC->LineTo(x,y); // draw the spline CPen greenpen; greenpen.CreatePen(PS_SOLID,2,RGB(0,255,0)); pDC->SelectObject(&greenpen); if (curve->Key_Count() >= 2) { float t0 = curve->Get_Start_Time(); float t1 = curve->Get_End_Time(); float dt = (t1 - t0) / 500.0f; curve->Evaluate(t0,&pt); Map_Point(pt,&x,&y); pDC->MoveTo(x,y); for (float t=t0; tEvaluate(t,&pt); Map_Point(pt,&x,&y); pDC->LineTo(x,y); } } // draw the control points for (int pi=0; piKey_Count(); pi++) { curve->Get_Key(pi,&pt,NULL); Map_Point(pt,&x,&y); pDC->FillSolidRect(x-2,y-2,4,4, RGB(255,0,0)); } // draw the tangents if ((DrawTangents) && (pDoc->Get_Curve_Type() > CSplineTestDoc::LINEAR)) { HermiteSpline3DClass * spline = (HermiteSpline3DClass *)curve; CPen blackpen; blackpen.CreatePen(PS_SOLID,1,RGB(0,0,0)); pDC->SelectObject(&blackpen); for (int pi=0; piKey_Count(); pi++) { int cx,cy; spline->Get_Key(pi,&pt,NULL); Map_Point(pt,&cx,&cy); Vector3 in,out; spline->Get_Tangents(pi,&in,&out); Map_Point(pt-in,&x,&y); pDC->MoveTo(cx,cy); pDC->LineTo(x,y); Map_Point(pt+out,&x,&y); pDC->MoveTo(cx,cy); pDC->LineTo(x,y); } } } void CSplineTestView::Map_Point(const Vector3 & point,int * set_x,int * set_y) { RECT rect; GetClientRect(&rect); float nx,ny; nx = (point.X - MIN_X) / (MAX_X - MIN_X); ny = (point.Y - MIN_Y) / (MAX_Y - MIN_Y); *set_x = (float)(rect.right - rect.left) * nx + rect.left; *set_y = (float)(rect.top - rect.bottom) * ny + rect.bottom; } void CSplineTestView::Un_Map_Point(int x,int y,Vector3 * set_point) { RECT rect; GetClientRect(&rect); float nx,ny; nx = (float)(x - rect.left) / (float)(rect.right - rect.left); ny = (float)(y - rect.bottom) / (float)(rect.top - rect.bottom); set_point->X = MIN_X + (MAX_X - MIN_X) * nx; set_point->Y = MIN_Y + (MAX_Y - MIN_Y) * ny; set_point->Z = 0.0f; *set_point = Clamp_Point(*set_point); } ///////////////////////////////////////////////////////////////////////////// // CSplineTestView diagnostics #ifdef _DEBUG void CSplineTestView::AssertValid() const { CView::AssertValid(); } void CSplineTestView::Dump(CDumpContext& dc) const { CView::Dump(dc); } CSplineTestDoc* CSplineTestView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSplineTestDoc))); return (CSplineTestDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CSplineTestView message handlers void CSplineTestView::OnLButtonDown(UINT nFlags, CPoint point) { CSplineTestDoc* pDoc = GetDocument(); if (pDoc) { // map the point Vector3 pt; Un_Map_Point(point.x,point.y,&pt); // try to go into drag mode bool gotone = pDoc->Grab_Point(pt); if (gotone) { ::SetCapture(m_hWnd); } } CView::OnLButtonDown(nFlags, point); } void CSplineTestView::OnLButtonUp(UINT nFlags, CPoint point) { // were we dragging something? if so release it // otherwise add a point to the curve CSplineTestDoc* pDoc = GetDocument(); if (pDoc != NULL) { if (pDoc->Is_Dragging()) { pDoc->Release_Point(); ::ReleaseCapture(); } else { Vector3 pt; Un_Map_Point(point.x,point.y,&pt); pDoc->Add_Point(pt); } } CView::OnLButtonUp(nFlags, point); } void CSplineTestView::OnMouseMove(UINT nFlags, CPoint point) { CSplineTestDoc* pDoc = GetDocument(); // are we dragging? // if so tell the doc where the point should go if (pDoc && pDoc->Is_Dragging()) { Vector3 pt; Un_Map_Point(point.x,point.y,&pt); pDoc->Drag_Point(pt); } CView::OnMouseMove(nFlags, point); } void CSplineTestView::OnRButtonUp(UINT nFlags, CPoint point) { Vector3 pt; Un_Map_Point(point.x,point.y,&pt); CSplineTestDoc* pDoc = GetDocument(); if (pDoc) { pDoc->Edit_Point(pt); } CView::OnRButtonUp(nFlags, point); } Vector3 CSplineTestView::Clamp_Point(const Vector3 & input) { Vector3 output = input; if (output.X < MIN_X) output.X = MIN_X; if (output.Y < MIN_Y) output.Y = MIN_Y; if (output.Z < MIN_Z) output.Z = MIN_Z; if (output.X > MAX_X) output.X = MAX_X; if (output.Y > MAX_Y) output.Y = MAX_Y; if (output.Z > MAX_Z) output.Z = MAX_Z; return output; } void CSplineTestView::Enable_Draw_Tangents(bool onoff) { DrawTangents = onoff; CSplineTestDoc* pDoc = GetDocument(); if (pDoc) { pDoc->UpdateAllViews(NULL); } } bool CSplineTestView::Is_Draw_Tangents_Enabled(void) { return DrawTangents; }