1
0
forked from 0ad/0ad
0ad/source/sced/ScEdView.cpp
2004-05-29 21:45:04 +00:00

581 lines
14 KiB
C++
Executable File

// ScEdView.cpp : implementation of the CScEdView class
//
#include "stdafx.h"
#include "ScEd.h"
#include "ScEdDoc.h"
#include "ScEdView.h"
#include "ToolManager.h"
#include "EditorData.h"
#include "UserConfig.h"
#include "MainFrm.h"
#include "timer.h"
#include "ogl.h"
#include "res/vfs.h"
int g_ClickMode=0;
static unsigned int GetModifierKeyFlags()
{
unsigned int flags=0;
if (::GetAsyncKeyState(VK_MENU) & 0x8000) flags|=TOOL_MOUSEFLAG_ALTDOWN;
if (::GetAsyncKeyState(VK_SHIFT) & 0x8000) flags|=TOOL_MOUSEFLAG_SHIFTDOWN;
if (::GetAsyncKeyState(VK_CONTROL) & 0x8000) flags|=TOOL_MOUSEFLAG_CTRLDOWN;
return flags;
}
/////////////////////////////////////////////////////////////////////////////
// CScEdView
IMPLEMENT_DYNCREATE(CScEdView, CView)
BEGIN_MESSAGE_MAP(CScEdView, CView)
//{{AFX_MSG_MAP(CScEdView)
ON_WM_ERASEBKGND()
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_SIZE()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_RBUTTONDOWN()
ON_WM_RBUTTONUP()
ON_WM_MBUTTONDOWN()
ON_WM_MBUTTONUP()
ON_MESSAGE(WM_MOUSEWHEEL,OnMouseWheel)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CScEdView construction/destruction
CScEdView::CScEdView() : m_hGLRC(0), m_LastTickTime(-1.0f), m_LastFrameDuration(-1.0f)
{
}
CScEdView::~CScEdView()
{
}
BOOL CScEdView::PreCreateWindow(CREATESTRUCT& cs)
{
cs.lpszClass = ::AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC,
::LoadCursor(NULL, IDC_ARROW), NULL, NULL);
cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
return CView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CScEdView drawing
void CScEdView::OnDraw(CDC* pDC)
{
HWND hWnd = GetSafeHwnd();
HDC hDC = ::GetDC(hWnd);
wglMakeCurrent(hDC,m_hGLRC);
g_EditorData.OnDraw();
SwapBuffers(hDC);
}
/////////////////////////////////////////////////////////////////////////////
// CScEdView diagnostics
#ifdef _DEBUG
void CScEdView::AssertValid() const
{
CView::AssertValid();
}
void CScEdView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CScEdDoc* CScEdView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CScEdDoc)));
return (CScEdDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CScEdView message handlers
BOOL CScEdView::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
int CScEdView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// base initialisation first
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// get device context for this window
HDC dc=::GetDC(m_hWnd);
// try and setup a default pixel format
if (!SetupPixelFormat(dc)) {
return -1;
}
// create context, make it current
m_hGLRC=wglCreateContext(dc);
wglMakeCurrent(dc,m_hGLRC);
// initialise gl stuff (extensions, etc)
oglInit();
// check for minimum requirements
if(!oglExtAvail("GL_ARB_multitexture") || !oglExtAvail("GL_ARB_texture_env_combine")) {
const char* err="No graphics card support for multitexturing found; please visit the 0AD Forums for more information.";
::MessageBox(0,err,"Error",MB_OK);
exit(0);
}
// initialise VFS paths
char path[256];
::GetModuleFileName(0,path,256);
file_rel_chdir(path, "../data");
vfs_mount("", "mods/official", 0);
// create renderer related stuff
new CRenderer;
// start up the renderer
g_Renderer.Open(0,0,::GetDeviceCaps(dc,BITSPIXEL));
// initialise document data
if (!g_EditorData.Init()) return -1;
// store current mouse pos
::GetCursorPos(&m_LastMousePos);
return 0;
}
void CScEdView::OnDestroy()
{
// close down editor resources
g_EditorData.Terminate();
// destroy renderer related stuff
delete CRenderer::GetSingletonPtr();
// release rendering context
if (m_hGLRC) {
wglMakeCurrent(0,0);
wglDeleteContext(m_hGLRC);
m_hGLRC=0;
}
// base destruction
CView::OnDestroy();
}
void CScEdView::OnSize(UINT nType, int cx, int cy)
{
// give base class a shout ..
CView::OnSize(nType, cx, cy);
m_Width=cx;
m_Height=cy;
g_Renderer.Resize(m_Width,m_Height);
g_EditorData.OnCameraChanged();
}
bool CScEdView::SetupPixelFormat(HDC dc)
{
int bpp=::GetDeviceCaps(dc,BITSPIXEL);
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
bpp==16 ? 16 : 24, // 16/24 bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
bpp==16 ? 0 : 8, // 16/24 bit color depth
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
24, // 24-bit z-buffer
8, // 8-bit stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int format=::ChoosePixelFormat(dc,&pfd);
if (format==0) {
// ack - can't choose format; bail out
return false;
}
if(::SetPixelFormat(dc,format,&pfd) == false) {
// ugh - still can't get anything; bail out
return false;
}
// check we've got an accelerated format available
if (::DescribePixelFormat(dc,format,sizeof(pfd),&pfd)) {
if (pfd.dwFlags & PFD_GENERIC_FORMAT) {
const char* err="No hardware accelerated graphics support found; please visit the 0AD Forums for more information.";
::MessageBox(0,err,"Error",MB_OK);
exit(0);
}
}
return true;
}
static CPoint lastClientMousePos;
void CScEdView::OnMouseLeave(const CPoint& point)
{
}
void CScEdView::OnMouseEnter(const CPoint& point)
{
unsigned int flags=GetModifierKeyFlags();
// trigger left button up and right button up events as required
if (!(::GetAsyncKeyState(VK_LBUTTON) & 0x8000)) {
g_ToolMan.OnLButtonUp(flags,point.x,point.y);
}
if (!(::GetAsyncKeyState(VK_RBUTTON) & 0x8000)) {
g_ToolMan.OnRButtonUp(flags,point.x,point.y);
}
}
void CScEdView::OnMouseMove(UINT nFlags, CPoint point)
{
SetFocus();
if (nFlags & MK_MBUTTON) {
// middle mouse down .. forward move to the navicam and
// we're done
u32 flags=GetModifierKeyFlags();
g_NaviCam.OnMouseMove(flags,point.x,point.y);
return;
}
static bool mouseInView=false;
// get view rect
CRect rect;
GetClientRect(rect);
// inside?
if(rect.PtInRect(point)) {
// yes - previously inside?
if (!mouseInView) {
// nope - enable mouse capture
SetCapture();
// run any necessary mouse leave code
OnMouseEnter(point);
}
mouseInView=true;
// store mouse position
lastClientMousePos=point;
// now actually handle everything required for the actual move event
// assume we want to update tile selection on mouse move
bool updateSelection=true;
// check for left mouse down on minimap following click on minimap
if (nFlags & MK_LBUTTON) {
if (g_ClickMode==0) {
if (point.x>m_Width-200 && point.y>m_Height-200) {
AdjustCameraViaMinimapClick(point);
// minimap moved, so don't update selection
updateSelection=false;
}
}
}
if (updateSelection) {
unsigned int flags=GetModifierKeyFlags();
g_ToolMan.OnMouseMove(flags,point.x,point.y);
}
// store this position as last
m_LastMousePos=point;
} else {
// previously inside view?
if (mouseInView) {
// yes - run any necessary mouse leave code
OnMouseLeave(point);
// release capture
ReleaseCapture();
}
// note mouse no longer in view
mouseInView=false;
}
}
void CScEdView::OnScreenShot()
{
static int counter=1;
// generate filename, create directory if required
char buf[512];
sprintf(buf,"../screenshots");
mkdir(buf,0);
sprintf(buf,"%s/%08d.tga",buf,counter++);
// make context current
HWND hWnd = GetSafeHwnd();
HDC hDC = ::GetDC(hWnd);
wglMakeCurrent(hDC,m_hGLRC);
// call on editor to make screenshot
g_EditorData.OnScreenShot(buf);
}
void CScEdView::OnRButtonUp(UINT nFlags, CPoint point)
{
g_ClickMode=1;
unsigned int flags=GetModifierKeyFlags();
g_ToolMan.OnRButtonUp(flags,point.x,point.y);
}
void CScEdView::OnRButtonDown(UINT nFlags, CPoint point)
{
if (point.x>m_Width-200 && point.y>m_Height-200) {
} else {
g_ClickMode=1;
unsigned int flags=GetModifierKeyFlags();
g_ToolMan.OnRButtonDown(flags,point.x,point.y);
}
}
void CScEdView::OnLButtonUp(UINT nFlags, CPoint point)
{
g_ClickMode=1;
unsigned int flags=GetModifierKeyFlags();
g_ToolMan.OnLButtonUp(flags,point.x,point.y);
}
void CScEdView::OnLButtonDown(UINT nFlags, CPoint point)
{
if (point.x>m_Width-200 && point.y>m_Height-200) {
g_ClickMode=0;
AdjustCameraViaMinimapClick(point);
} else {
g_ClickMode=1;
unsigned int flags=GetModifierKeyFlags();
g_ToolMan.OnLButtonDown(flags,point.x,point.y);
}
}
void CScEdView::AdjustCameraViaMinimapClick(CPoint point)
{
// convert from screen space point back to world space point representating intersection of
// ray with terrain plane
CVector3D pos;
pos.X=float(CELL_SIZE*g_Terrain.GetVerticesPerSide())*float(point.x+200-m_Width)/200.0f;
pos.Y=-g_EditorData.m_TerrainPlane.m_Dist;
pos.Z=float(CELL_SIZE*g_Terrain.GetVerticesPerSide())*float(m_Height-point.y)/197.0f;
// calculate desired camera point from this
CVector3D startpos=g_NaviCam.GetCamera().m_Orientation.GetTranslation();
CVector3D rayDir=g_NaviCam.GetCamera().m_Orientation.GetIn();
float distToPlane=g_EditorData.m_TerrainPlane.DistanceToPlane(startpos);
float dot=rayDir.Dot(g_EditorData.m_TerrainPlane.m_Norm);
CVector3D endpos=pos+(rayDir*(distToPlane/dot));
// translate camera from old point to new
CVector3D trans=endpos-startpos;
g_NaviCam.GetCamera().m_Orientation.Translate(trans);
g_EditorData.OnCameraChanged();
}
bool CScEdView::AppHasFocus()
{
CWnd* wnd=AfxGetMainWnd();
if (!wnd) return false;
CWnd* focuswnd=GetFocus();
while (focuswnd) {
if (focuswnd==wnd) return true;
focuswnd=focuswnd->GetParent();
}
return false;
}
void CScEdView::IdleTimeProcess()
{
if (m_LastTickTime==-1) {
m_LastTickTime=get_time();
return;
}
// fake a mouse move from current position if either mouse button is down
unsigned int flags=0;
if ((::GetAsyncKeyState(VK_LBUTTON) & 0x8000) || (::GetAsyncKeyState(VK_RBUTTON) & 0x8000)) {
unsigned int flags=GetModifierKeyFlags();
g_ToolMan.OnMouseMove(flags,m_LastMousePos.x,m_LastMousePos.y);
}
double curtime=get_time();
double diff=curtime-m_LastTickTime;
if (m_LastFrameDuration>0) {
g_EditorData.UpdateWorld(float(m_LastFrameDuration));
// check app has focus
if (AppHasFocus()) {
POINT pt;
if (GetCursorPos(&pt)) {
// want to scroll?
int scrollspeed=g_UserCfg.GetOptionInt(CFG_SCROLLSPEED);
if (scrollspeed>0) {
RECT rect;
AfxGetMainWnd()->GetWindowRect(&rect);
// scale translation by distance from terrain
float h=g_NaviCam.GetCamera().m_Orientation.GetTranslation().Y;
float speed=h*0.1f;
// scale translation to account for fact that we might not be running at the same rate as the timer
speed*=float(diff);
// scale by user requested speed
speed*=scrollspeed;
bool changed=false;
if (pt.x<rect.left+16) {
CVector3D left=g_NaviCam.GetCamera().m_Orientation.GetLeft();
// strip vertical movement, to prevent moving into/away from terrain plane
left.Y=0;
left.Normalize();
g_NaviCam.GetCamera().m_Orientation.Translate(left*speed);
changed=true;
} else if (pt.x>rect.right-16) {
CVector3D left=g_NaviCam.GetCamera().m_Orientation.GetLeft();
// strip vertical movement, to prevent moving into/away from terrain plane
left.Y=0;
left.Normalize();
g_NaviCam.GetCamera().m_Orientation.Translate(left*(-speed));
changed=true;
}
if (pt.y>rect.bottom-16) {
CVector3D up=g_NaviCam.GetCamera().m_Orientation.GetUp();
// strip vertical movement, to prevent moving into/away from terrain plane
up.Y=0;
up.Normalize();
g_NaviCam.GetCamera().m_Orientation.Translate(up*(-speed));
changed=true;
} else if (pt.y<rect.top+16) {
CVector3D up=g_NaviCam.GetCamera().m_Orientation.GetUp();
// strip vertical movement, to prevent moving into/away from terrain plane
up.Y=0;
up.Normalize();
g_NaviCam.GetCamera().m_Orientation.Translate(up*speed);
changed=true;
}
if (changed) {
g_EditorData.OnCameraChanged();
}
}
}
}
}
// store frame time
m_LastFrameDuration=diff;
// store current time
m_LastTickTime=curtime;
// finally, redraw view
HWND hWnd = GetSafeHwnd();
HDC hDC = ::GetDC(hWnd);
wglMakeCurrent(hDC,m_hGLRC);
g_EditorData.OnDraw();
SwapBuffers(hDC);
}
LRESULT CScEdView::OnMouseWheel(WPARAM wParam,LPARAM lParam)
{
int xPos = LOWORD(lParam);
int yPos = HIWORD(lParam);
SHORT fwKeys = LOWORD(wParam);
SHORT zDelta = HIWORD(wParam);
g_NaviCam.OnMouseWheelScroll(0,xPos,yPos,float(zDelta)/120.0f);
return 0;
}
void CScEdView::OnMButtonDown(UINT nFlags, CPoint point)
{
g_NaviCam.OnMButtonDown(0,point.x,point.y);
}
void CScEdView::OnMButtonUp(UINT nFlags, CPoint point)
{
g_NaviCam.OnMButtonUp(0,point.x,point.y);
}
BOOL CScEdView::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) {
if (pMsg->message==WM_KEYDOWN) {
int key=(int) pMsg->wParam;
CMainFrame* mainfrm=(CMainFrame*)AfxGetApp()->m_pMainWnd;
switch (key) {
case VK_F1:
mainfrm->OnViewRenderStats();
break;
case VK_F9:
mainfrm->OnViewScreenshot();
break;
case 'Z':
if (GetAsyncKeyState(VK_CONTROL))
mainfrm->OnEditUndo();
break;
case 'Y':
if (GetAsyncKeyState(VK_CONTROL))
mainfrm->OnEditRedo();
break;
}
}
return 1;
} else {
return CView::PreTranslateMessage(pMsg);
}
}