#if !defined(AFX_CAMEDIT_H__4B4AF8E8_F26A_430F_A7F2_66CD8FAAA895__INCLUDED_)
#define AFX_CAMEDIT_H__4B4AF8E8_F26A_430F_A7F2_66CD8FAAA895__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CamEdit.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CCamEdit form view

#ifndef __AFXEXT_H__
#include <afxext.h>
#endif

#include "thingview.h"
#include "resource.h"

enum CAMSLIDER
{
	CS_POSVAR,
	CS_POSHVAR,
	CS_FOCVAR,
	CS_FOCHVAR,
	CS_TILT,
	CS_TILTVAR,
	CS_FOV,
	CS_FOVVAR,
	CS_XSHIFT,
	CS_YSHIFT,
	CS_FOCREL,
};

#define RADFAC 100
#define HFAC 100

struct CamFrame;

struct thecam
{
	v3 p,f;
	float shiftx,shifty;
	float fov;
	float tilt;
	int lastt;

	v3 fwd,across,up;

	thecam()
	{
		p=v3(50,10,30);
		f=v3(0,0,0);
		fov=camfov;
		tilt=0;
		lastt=0;
		shiftx=0;
		shifty=0;
	}

	void SetToFrame(CamFrame &fr);
	void GetFromFrame(CamFrame fr, bool wib=false);

	void DrawFull(SimpleBuffer &sb)
	{
		v3 tp,tf,up;
		sb.primtype=D3DPT_LINELIST;
		GetActualPos(tp,tf,up,shiftx,shifty);
		int vp0 = sb.AddVertex(tp,0xffff0000);
		int vf0 = sb.AddVertex(tf,0xffffffff);
		GetActualPos(tp,tf,up,-1,-1);
		int vf1 = sb.AddVertex(tf,0xffff0000);
		GetActualPos(tp,tf,up,1,-1);
		int vf2 = sb.AddVertex(tf,0xffff0000);
		GetActualPos(tp,tf,up,1,1);
		int vf3 = sb.AddVertex(tf,0xffff0000);
		GetActualPos(tp,tf,up,-1,1);
		int vf4 = sb.AddVertex(tf,0xffff0000);
		GetActualPos(tp,tf,up,0,0);
		int vf5 = sb.AddVertex(tf,0xffff0000);

		sb.AddLine(vp0,vf0); // main line
		sb.AddLine(vp0,vf5); // center line
		sb.AddLine(vf1,vf2); // border
		sb.AddLine(vf2,vf3); // border
		sb.AddLine(vf3,vf4); // border
		sb.AddLine(vf4,vf1); // border

		sb.AddLine(vf1,vp0); // border
		sb.AddLine(vf2,vp0); // border
		sb.AddLine(vf3,vp0); // border
		sb.AddLine(vf4,vp0); // border

		sb.Draw();
	}

	void GetActualPos(v3 &tp, v3 &tf, v3 &up, float shiftx, float shifty)
	{
		p-=f;
		fwd=Normalize(p);
		p+=f;
		// across = x up = y fwd = z
		across = Normalize(CrossProduct(v3(0,1,0),fwd));
		up=Normalize(CrossProduct(fwd,across));
		// spin the up by the tilt
		up=cos(tilt)*up+sin(tilt)*across;
		across=Normalize(CrossProduct(up,fwd));		
		// shift the focus
		float foclen = Length(p-f);
		float adj = tan(fov/2)*foclen;
		//tp=p+(across*shiftx+up*shifty)*adj;
		tp=p;
		tf=f+(across*shiftx+up*shifty)*adj;			
	}


	void Update();
	
};


struct CamPath;

struct CamFrame
{
	CamFrame *prev();
	CamPath *parent;
	int framenum;
	
	v3 GetPos(bool wibble);
	v3 GetFoc(bool wibble);
	float GetVal(CAMSLIDER s, bool wibble);


	

	void SetVal(CAMSLIDER s, float f)
	{
		f=bound(0,f,1);
		float of=GetVal(s,false);
		if (of==f) return;
		lock[s]=0;
		slider[s]=f;
	}

	void DrawCyl(SimpleBuffer &sb, v3 p, float h, float r, DWORD col)
	{
		int vi[25][3];
		for (int yy=-1;yy<2;yy++) for (int c1=0;c1<25;c1++)
		{
			float r2=r;
			if (c1==24) r2=0;
			vi[c1][yy+1]=sb.AddVertex(p+v3(cos(c1*PI*2/24.f)*r2,h*(yy),sin(c1*PI*2/24.f)*r2),col);
		}
		for (yy=0;yy<3;yy++)
		{
			for (int x=0;x<24;x++)
			{
				sb.AddLine(vi[(x+0)%24][yy],vi[(x+1)%24][yy]);
				sb.AddLine(vi[(x+0)%24][yy],vi[24][yy]);
			
				if (yy==2) sb.AddLine(vi[(x+0)%24][0],vi[(x+0)%24][2]);			
			}
			
		}
		sb.Draw();		
	}

	void DrawFull(SimpleBuffer &sb)
	{
		DrawCyl(sb,GetPos(false)+GetFoc(false),GetVal(CS_POSHVAR,false)*HFAC,0.1f+GetVal(CS_POSVAR,false)*RADFAC,0xffffff00);
		DrawCyl(sb,GetFoc(false),GetVal(CS_FOCHVAR,false)*HFAC,0.1f+GetVal(CS_FOCVAR,false)*RADFAC,0xffffff00);
	}


	CamFrame()
	{
		parent=NULL;
		framenum=0;
		pos=v3(5,1,0);
		foc=v3(0,0,0);
		lpos=lfoc=1;
		for (int c1=0;c1<11;c1++)
		{
			lock[c1]=1;
			slider[c1]=0;
		}
		slider[CS_XSHIFT]=0.5f;
		slider[CS_YSHIFT]=0.5f;
		slider[CS_FOV]=0.5f;
		slider[CS_TILT]=0.5f;
	}

		
	
	
	v3 pos,foc;
	union
	{
		struct
		{
			float posvar,poshvar,focvar,fochvar;
			float tilt,tiltvar,fov,fovvar,xshift,yshift;
			float focrel;
			int lposvar,lposhvar,lfocvar,lfochvar;
			int ltilt,ltiltvar,lfov,lfovvar,lxshift,lyshift;
			int lfocrel;			
		};
		struct
		{
			float slider[11];
			int lock[11];
		};		
	};
	int lpos,lfoc;
		
};

typedef std::vector<CamFrame> CamFrames;

struct CamPath
{
	int curframe; // must be first
	int previewmode;	
	float previewpos;
	int numframes;
	int unused[4];

	CamFrames frames;
	CamFrame interp;
	
	CamFrame Interp(float t, bool wib);

	float GetWibble(int idx, CamFrame *fram)
	{
		int t=fram-&*frames.begin();
		return Perlin::Noise2(t*0.5f + 0.25f, idx*7+0.5f);
	}

	CamPath()
	{
		previewmode=0;
		curframe=0;
		previewpos=0;
		frames.push_back(CamFrame());
		frames[0].parent=this;
	}

	void Draw(SimpleBuffer &sb)
	{
		sb.primtype=D3DPT_LINELIST;
		for (int f=0;f<frames.size()-1;f++)
		{
			int v0=sb.AddVertex(frames[f].GetFoc(false),0xff0000ff);
			int v1=sb.AddVertex(frames[f+1].GetFoc(false),0xff0000ff);
			int v2=sb.AddVertex(frames[f].GetPos(false)+frames[f].GetFoc(false),0xffff00ff);
			int v3=sb.AddVertex(frames[f+1].GetPos(false)+frames[f+1].GetFoc(false),0xffff00ff);
			sb.AddLine(v0,v1);
			sb.AddLine(v2,v3);

		}
		frames[curframe].DrawFull(sb);
		thecam mycam;
		mycam.GetFromFrame(frames[curframe]);
		mycam.DrawFull(sb);

		interp = Interp(previewpos,false);
		//interp.DrawFull(sb);
		mycam.GetFromFrame(interp);
		mycam.DrawFull(sb);
	}
};


class CCamEdit : public CFormView
{
protected:
	CCamEdit();           // protected constructor used by dynamic creation
	DECLARE_DYNCREATE(CCamEdit)

// Form Data
public:
	int curpath;
	CamPath paths[256];
	CamPath &path()
	{
		return paths[curpath&255];
	}
	CString fname;
	bool inupdate;
	CSliderCtrl	m_slider[10];
	CEdit	m_pos[3];
	CEdit	m_foc[3];
	CButton	m_lock[11];
	//{{AFX_DATA(CCamEdit)
	enum { IDD = IDD_CAMEDIT };	
	CButton	m_previewon;	
	CSliderCtrl	m_previewslider;
	CSliderCtrl	m_frameslider;
	CComboBox	m_foccombo;
	
	CButton	m_lockpos;
	CButton	m_lockfoc;

	int sliderchanged;
	
	//}}AFX_DATA

// Attributes
public:
	void SetFrame(int f);
	void SetPath(int p);

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CCamEdit)
	public:
	virtual void OnInitialUpdate();
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	virtual ~CCamEdit();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

	// Generated message map functions
	//{{AFX_MSG(CCamEdit)
	afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) ;
	afx_msg void OnCheck1();
	afx_msg void OnLoad();
	afx_msg void OnSave();
	afx_msg void OnPreview();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

extern CCamEdit *camedit;

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CAMEDIT_H__4B4AF8E8_F26A_430F_A7F2_66CD8FAAA895__INCLUDED_)
