!XT (BREAK-16) (Sandbox) Remove double-newlines at the end of files.
[CRYENGINE.git] / Code / Sandbox / Plugins / MFCToolsPlugin / Controls / PreviewModelCtrl.cpp
blob78088ab56e4fa3389a665dc9a56314aa3cda14de
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
5 #include "IEditorMaterial.h"
6 #include "PreviewModelCtrl.h"
8 #include <Cry3DEngine/I3DEngine.h>
9 #include <CryEntitySystem/IEntitySystem.h>
10 #include <CryAnimation/ICryAnimation.h>
11 #include <CryRenderer/IRenderAuxGeom.h>
12 #include <CryParticleSystem/IParticles.h>
14 #include "IIconManager.h"
15 #include "ViewportInteraction.h"
16 #include <Preferences/ViewportPreferences.h>
17 #include "RenderLock.h"
19 CPreviewModelCtrl::CPreviewModelCtrl()
21 m_bShowObject = true;
22 m_pRenderer = 0;
23 m_pObj = 0;
24 m_pCharacter = 0;
25 m_pEntity = 0;
26 m_nTimer = 0;
27 m_pEmitter = 0;
28 m_size(0, 0, 0);
30 m_bRotate = false;
31 m_rotateAngle = 0;
33 m_backgroundTextureId = 0;
35 m_pRenderer = GetIEditor()->GetRenderer();
36 m_pAnimationSystem = GetIEditor()->GetSystem()->GetIAnimationSystem();
38 m_fov = 60;
39 m_camera.SetFrustum(800, 600, DEG2RAD(m_fov), 0.02f, 10000.0f);
41 m_bInRotateMode = false;
42 m_bInMoveMode = false;
44 SRenderLight l;
46 float L = 1.0f;
47 l.m_Flags |= DLF_SUN | DLF_DIRECTIONAL;
48 l.SetLightColor(ColorF(L, L, L, 1));
49 l.SetPosition(Vec3(100, 100, 100));
50 l.SetRadius(10000);
51 m_lights.push_back(l);
53 m_bUseBacklight = false;
54 m_renderContextCreated = false;
55 m_bHaveAnythingToRender = false;
56 m_bGrid = true;
57 m_bAxis = true;
58 m_bUpdate = false;
59 m_bShowNormals = false;
60 m_bShowPhysics = false;
61 m_bShowRenderInfo = false;
63 m_cameraAngles.Set(0, 0, 0);
65 m_clearColor.set(0.5f, 0.5f, 0.5f, 1.0f);
66 m_ambientColor.set(1.0f, 1.0f, 1.0f, 1.0f);
67 m_ambientMultiplier = 0.5f;
69 m_cameraChangeCallback = NULL;
70 m_bPrecacheMaterial = false;
71 m_bDrawWireFrame = false;
73 m_tileX = 0.0f;
74 m_tileY = 0.0f;
75 m_tileSizeX = 1.0f;
76 m_tileSizeY = 1.0f;
78 m_aabb = AABB(2);
79 FitToScreen();
81 GetIEditor()->RegisterNotifyListener(this);
82 m_physHelpers0 = gEnv->pPhysicalWorld->GetPhysVars()->iDrawHelpers;
85 CPreviewModelCtrl::~CPreviewModelCtrl()
87 ReleaseObject();
88 GetIEditor()->UnregisterNotifyListener(this);
89 gEnv->pPhysicalWorld->GetPhysVars()->iDrawHelpers = m_physHelpers0;
92 BEGIN_MESSAGE_MAP(CPreviewModelCtrl, CWnd)
93 //{{AFX_MSG_MAP(CPreviewModelCtrl)
94 ON_WM_CREATE()
95 ON_WM_PAINT()
96 ON_WM_ERASEBKGND()
97 ON_WM_TIMER()
98 ON_WM_DESTROY()
99 ON_WM_LBUTTONDOWN()
100 ON_WM_LBUTTONUP()
101 ON_WM_MBUTTONDOWN()
102 ON_WM_MBUTTONUP()
103 ON_WM_MOUSEMOVE()
104 ON_WM_RBUTTONDOWN()
105 ON_WM_RBUTTONUP()
106 ON_WM_MOUSEWHEEL()
107 ON_WM_SIZE()
108 //}}AFX_MSG_MAP
109 END_MESSAGE_MAP()
111 BOOL CPreviewModelCtrl::Create(CWnd* pWndParent, const CRect& rc, DWORD dwStyle, UINT nID)
113 BOOL bReturn = CreateEx(NULL, AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
114 AfxGetApp()->LoadStandardCursor(IDC_ARROW), NULL, NULL), NULL, dwStyle,
115 rc, pWndParent, nID, NULL);
117 return bReturn;
120 int CPreviewModelCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
122 if (CWnd::OnCreate(lpCreateStruct) == -1)
123 return -1;
125 return 0;
128 bool CPreviewModelCtrl::CreateRenderContext()
130 // Create context.
131 if (m_pRenderer && !m_renderContextCreated)
133 CRect rc;
134 GetClientRect(rc);
135 IRenderer::SDisplayContextDescription desc;
137 desc.handle = m_hWnd;
138 desc.type = IRenderer::eViewportType_Secondary;
139 desc.clearColor = m_clearColor;
140 desc.renderFlags = FRT_CLEAR_COLOR | FRT_CLEAR_DEPTH | FRT_TEMPORARY_DEPTH;
141 desc.superSamplingFactor.x = 1;
142 desc.superSamplingFactor.y = 1;
143 desc.screenResolution.x = rc.Width();
144 desc.screenResolution.y = rc.Height();
146 m_displayContextKey = m_pRenderer->CreateSwapChainBackedContext(desc);
147 m_renderContextCreated = true;
149 return true;
152 return false;
155 void CPreviewModelCtrl::DestroyRenderContext()
157 // Destroy render context.
158 if (m_pRenderer && m_renderContextCreated)
160 // Do not delete primary context.
161 if (m_displayContextKey != reinterpret_cast<HWND>(m_pRenderer->GetHWND()))
162 m_pRenderer->DeleteContext(m_displayContextKey);
164 m_renderContextCreated = false;
168 SDisplayContext CPreviewModelCtrl::InitDisplayContext(const SDisplayContextKey& displayContextKey)
170 CRY_PROFILE_FUNCTION(PROFILE_EDITOR);
172 SDisplayContext dctx;
173 dctx.SetDisplayContext(displayContextKey, IRenderer::eViewportType_Secondary);
174 // dctx.SetView(m_pViewportAdapter.get());
175 dctx.SetCamera(&m_camera);
176 dctx.renderer = m_pRenderer;
177 dctx.engine = nullptr;
178 dctx.box.min = Vec3(-100000, -100000, -100000);
179 dctx.box.max = Vec3(100000, 100000, 100000);
180 dctx.flags = 0;
182 return dctx;
185 void CPreviewModelCtrl::PreSubclassWindow()
187 CWnd::PreSubclassWindow();
190 void CPreviewModelCtrl::ReleaseObject()
192 m_pObj = NULL;
193 SAFE_RELEASE(m_pCharacter);
194 if (m_pEmitter)
196 m_pEmitter->Activate(false);
197 m_pEmitter->Release();
198 m_pEmitter = 0;
200 m_pEntity = 0;
201 m_bHaveAnythingToRender = false;
204 void CPreviewModelCtrl::LoadFile(const char* modelFile, bool changeCamera)
206 m_bHaveAnythingToRender = false;
207 if (!m_hWnd)
208 return;
209 if (!m_pRenderer)
210 return;
212 ReleaseObject();
214 if (!modelFile || !*modelFile)
216 if (m_nTimer != 0)
217 KillTimer(m_nTimer);
218 m_nTimer = 0;
219 Invalidate();
220 return;
223 m_loadedFile = modelFile;
225 CString strFileExt = PathUtil::GetExt(modelFile);
226 uint32 isSKEL = stricmp(strFileExt, CRY_SKEL_FILE_EXT) == 0;
227 uint32 isSKIN = stricmp(strFileExt, CRY_SKIN_FILE_EXT) == 0;
228 uint32 isCDF = stricmp(strFileExt, CRY_CHARACTER_DEFINITION_FILE_EXT) == 0;
229 uint32 isCGA = stricmp(strFileExt, CRY_ANIM_GEOMETRY_FILE_EXT) == 0;
230 uint32 isCGF = stricmp(strFileExt, CRY_GEOMETRY_FILE_EXT) == 0;
232 if (isCGA)
234 // Load CGA animated object.
235 m_pCharacter = m_pAnimationSystem->CreateInstance(modelFile);
236 if (!m_pCharacter)
238 CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_WARNING, "Loading of geometry object %s failed.", modelFile);
239 if (m_nTimer != 0)
240 KillTimer(m_nTimer);
241 m_nTimer = 0;
242 Invalidate();
243 return;
245 m_pCharacter->AddRef();
246 m_aabb = m_pCharacter->GetAABB();
249 if (isSKEL || isSKIN || isCDF)
251 // Load character.
252 m_pCharacter = m_pAnimationSystem->CreateInstance(modelFile, CA_PreviewMode | CA_CharEditModel);
253 if (!m_pCharacter)
255 CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_WARNING, "Loading of character %s failed.", modelFile);
256 if (m_nTimer != 0)
257 KillTimer(m_nTimer);
258 m_nTimer = 0;
259 Invalidate();
260 return;
262 m_pCharacter->AddRef();
263 m_aabb = m_pCharacter->GetAABB();
266 if (isCGF)
268 // Load object.
269 m_pObj = GetIEditor()->Get3DEngine()->LoadStatObj(modelFile, NULL, NULL, false);
270 if (!m_pObj)
272 CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_WARNING, "Loading of geometry object %s failed.", (const char*)modelFile);
273 if (m_nTimer != 0)
274 KillTimer(m_nTimer);
275 m_nTimer = 0;
276 Invalidate();
277 return;
279 m_aabb.min = m_pObj->GetBoxMin();
280 m_aabb.max = m_pObj->GetBoxMax();
282 else
284 if (m_nTimer != 0)
285 KillTimer(m_nTimer);
286 m_nTimer = 0;
287 Invalidate();
288 return;
291 m_bHaveAnythingToRender = true;
293 if (changeCamera)
294 FitToScreen();
296 Invalidate();
299 void CPreviewModelCtrl::LoadParticleEffect(IParticleEffect* pEffect)
301 m_bHaveAnythingToRender = false;
302 if (!m_hWnd)
303 return;
304 if (!m_pRenderer)
305 return;
307 ReleaseObject();
309 if (!pEffect)
310 return;
312 RECT rc;
313 GetClientRect(&rc);
314 if (rc.bottom - rc.top < 2 || rc.right - rc.left < 2)
315 return;
317 Matrix34 tm;
318 tm.SetIdentity();
319 tm.SetRotationXYZ(Ang3(DEG2RAD(90.0f), 0, 0));
321 m_bHaveAnythingToRender = true;
322 SpawnParams sp;
323 sp.bNowhere = true;
324 m_pEmitter = pEffect->Spawn(tm, sp);
325 if (m_pEmitter)
327 m_pEmitter->AddRef();
328 m_pEmitter->Update();
329 m_aabb = m_pEmitter->GetBBox();
330 if (m_aabb.IsReset())
331 m_aabb = AABB(1);
332 FitToScreen();
335 Invalidate();
338 void CPreviewModelCtrl::SetEntity(IRenderNode* entity)
340 m_bHaveAnythingToRender = false;
341 if (m_pEntity != entity)
343 m_pEntity = entity;
344 if (m_pEntity)
346 m_bHaveAnythingToRender = true;
347 m_aabb = m_pEntity->GetBBox();
349 Invalidate();
353 void CPreviewModelCtrl::SetObject(IStatObj* pObject)
355 if (m_pObj != pObject)
357 m_bHaveAnythingToRender = false;
358 m_pObj = pObject;
359 if (m_pObj)
361 m_bHaveAnythingToRender = true;
362 m_aabb = m_pObj->GetAABB();
364 Invalidate();
368 void CPreviewModelCtrl::SetCameraRadius(float fRadius)
370 m_cameraRadius = fRadius;
372 Matrix34 m = m_camera.GetMatrix();
373 Vec3 dir = m.TransformVector(Vec3(0, 1, 0));
374 Matrix34 tm = Matrix33::CreateRotationVDir(dir, 0);
375 tm.SetTranslation(m_cameraTarget - dir * m_cameraRadius);
376 m_camera.SetMatrix(tm);
377 if (m_cameraChangeCallback)
378 m_cameraChangeCallback(m_pCameraChangeUserData, this);
381 void CPreviewModelCtrl::SetCameraLookAt(float fRadiusScale, const Vec3& fromDir)
383 m_cameraTarget = m_aabb.GetCenter();
384 m_cameraRadius = m_aabb.GetRadius() * fRadiusScale;
386 Vec3 dir = fromDir.GetNormalized();
387 Matrix34 tm = Matrix33::CreateRotationVDir(dir, 0);
388 tm.SetTranslation(m_cameraTarget - dir * m_cameraRadius);
389 m_camera.SetMatrix(tm);
390 if (m_cameraChangeCallback)
391 m_cameraChangeCallback(m_pCameraChangeUserData, this);
394 CCamera& CPreviewModelCtrl::GetCamera()
396 return m_camera;
399 void CPreviewModelCtrl::UseBackLight(bool bEnable)
401 if (bEnable)
403 m_lights.resize(1);
404 SRenderLight l;
405 l.m_Flags |= DLF_POINT;
406 l.SetPosition(Vec3(-100, 100, -100));
407 float L = 0.5f;
408 l.SetLightColor(ColorF(L, L, L, 1));
409 l.SetRadius(1000);
410 m_lights.push_back(l);
412 else
414 m_lights.resize(1);
416 m_bUseBacklight = bEnable;
419 void CPreviewModelCtrl::OnPaint()
421 CPaintDC dc(this);
422 bool res = Render();
423 if (!res)
425 RECT rect;
426 // Get the rect of the client window
427 GetClientRect(&rect);
428 // Create the brush
429 CBrush cFillBrush;
430 cFillBrush.CreateSolidBrush(RGB(128, 128, 128));
431 // Fill the entire client area
432 dc.FillRect(&rect, &cFillBrush);
436 BOOL CPreviewModelCtrl::OnEraseBkgnd(CDC* pDC)
438 if (m_bHaveAnythingToRender)
439 return TRUE;
441 return CWnd::OnEraseBkgnd(pDC);
444 void CPreviewModelCtrl::SetCamera(CCamera& cam)
446 m_camera.SetPosition(cam.GetPosition());
448 CRect rc;
449 GetClientRect(rc);
450 int w = rc.Width() * m_tileSizeX;
451 int h = rc.Height() * m_tileSizeY;
452 m_camera.SetFrustum(w, h, DEG2RAD(m_fov), m_camera.GetNearPlane(), m_camera.GetFarPlane());
454 if (m_cameraChangeCallback)
455 m_cameraChangeCallback(m_pCameraChangeUserData, this);
458 void CPreviewModelCtrl::SetOrbitAngles(const Ang3& ang)
460 assert(0);
463 bool CPreviewModelCtrl::Render()
465 bool result = false;
467 // lock while we are rendering to prevent any recursive rendering across the application
468 if (CScopedRenderLock lock = CScopedRenderLock())
470 if (!m_renderContextCreated)
472 if (!CreateRenderContext())
473 return false;
476 // Configures Aux to draw to the current display-context
477 SDisplayContext context = InitDisplayContext(m_displayContextKey);
479 m_pRenderer->BeginFrame(m_displayContextKey);
481 result = RenderInternal(context);
483 m_pRenderer->EndFrame();
486 return result;
489 bool CPreviewModelCtrl::RenderInternal(SDisplayContext& context)
491 CRect rc;
492 GetClientRect(rc);
494 int width = rc.right - rc.left;
495 int height = rc.bottom - rc.top;
496 if (height < 2 || width < 2)
497 return false;
499 SetCamera(m_camera);
501 DrawBackground();
502 if (m_bGrid || m_bAxis)
503 DrawGrid();
505 // save some cvars
506 int showNormals = gEnv->pConsole->GetCVar("r_ShowNormals")->GetIVal();
507 int showPhysics = gEnv->pConsole->GetCVar("p_draw_helpers")->GetIVal();
508 int showInfo = gEnv->pConsole->GetCVar("r_displayInfo")->GetIVal();
510 gEnv->pConsole->GetCVar("r_ShowNormals")->Set((int)m_bShowNormals);
511 gEnv->pConsole->GetCVar("p_draw_helpers")->Set((int)m_bShowPhysics);
512 gEnv->pConsole->GetCVar("r_displayInfo")->Set((int)m_bShowRenderInfo);
514 // Render object.
515 SRenderingPassInfo passInfo = SRenderingPassInfo::CreateGeneralPassRenderingInfo(m_camera, SRenderingPassInfo::DEFAULT_FLAGS, true, context.GetDisplayContextKey());
516 passInfo.GetIRenderView()->SetShaderRenderingFlags(SHDF_NOASYNC | SHDF_ALLOWHDR | SHDF_SECONDARY_VIEWPORT);
517 m_pRenderer->EF_StartEf(passInfo);
520 CScopedWireFrameMode scopedWireFrame(m_pRenderer, m_bDrawWireFrame ? R_WIREFRAME_MODE : R_SOLID_MODE);
522 // Add lights.
523 for (size_t i = 0; i < m_lights.size(); i++)
525 m_pRenderer->EF_ADDDlight(&m_lights[i], passInfo);
528 if (m_pCurrentMaterial)
529 m_pCurrentMaterial->DisableHighlight();
531 _smart_ptr<IMaterial> pMaterial;
532 if (m_pCurrentMaterial)
533 pMaterial = m_pCurrentMaterial->GetMatInfo();
535 if (m_bPrecacheMaterial)
537 IMaterial* pCurMat = pMaterial;
538 if (!pCurMat)
540 if (m_pObj)
541 pCurMat = m_pObj->GetMaterial();
542 else if (m_pEntity)
543 pCurMat = m_pEntity->GetMaterial();
544 else if (m_pCharacter)
545 pCurMat = m_pCharacter->GetIMaterial();
546 else if (m_pEmitter)
547 pCurMat = m_pEmitter->GetMaterial();
549 if (pCurMat)
551 pCurMat->PrecacheMaterial(0.0f, NULL, true, true);
556 // activate shader item
557 IMaterial* pCurMat = pMaterial;
558 if (!pCurMat)
560 if (m_pObj)
561 pCurMat = m_pObj->GetMaterial();
562 else if (m_pEntity)
563 pCurMat = m_pEntity->GetMaterial();
564 else if (m_pCharacter)
565 pCurMat = m_pCharacter->GetIMaterial();
566 else if (m_pEmitter)
567 pCurMat = m_pEmitter->GetMaterial();
569 /*if (pCurMat)
571 pCurMat->ActivateAllShaderItem();
575 if (m_bShowObject)
576 RenderObject(pMaterial, passInfo);
578 m_pRenderer->EF_EndEf3D(-1, -1, passInfo);
580 if (true)
581 RenderEffect(pMaterial, passInfo);
584 m_pRenderer->RenderDebug(false);
586 gEnv->pConsole->GetCVar("r_ShowNormals")->Set(showNormals);
587 gEnv->pConsole->GetCVar("p_draw_helpers")->Set(showPhysics);
588 gEnv->pConsole->GetCVar("r_displayInfo")->Set(showInfo);
590 return true;
593 void CPreviewModelCtrl::RenderObject(IMaterial* pMaterial, const SRenderingPassInfo& passInfo)
595 SRendParams rp;
596 rp.dwFObjFlags = 0;
597 rp.AmbientColor = m_ambientColor * m_ambientMultiplier;
598 rp.dwFObjFlags |= FOB_TRANS_MASK /*| FOB_GLOBAL_ILLUMINATION*/ | FOB_NO_FOG /*| FOB_ZPREPASS*/;
599 rp.pMaterial = pMaterial;
601 Matrix34 tm;
602 tm.SetIdentity();
603 rp.pMatrix = &tm;
605 if (m_bRotate)
607 tm.SetRotationXYZ(Ang3(0, 0, m_rotateAngle));
608 m_rotateAngle += 0.1f;
611 if (m_pObj)
612 m_pObj->Render(rp, passInfo);
614 if (m_pEntity)
615 m_pEntity->Render(rp, passInfo);
617 if (m_pCharacter)
618 m_pCharacter->Render(rp, passInfo);
620 if (m_pEmitter)
622 m_pEmitter->Update();
623 m_pEmitter->Render(rp, passInfo);
627 void CPreviewModelCtrl::RenderEffect(IMaterial* pMaterial, const SRenderingPassInfo& passInfo)
631 void CPreviewModelCtrl::DrawGrid()
633 // Draw grid.
634 float step = 0.1f;
635 float XR = 5;
636 float YR = 5;
638 IRenderAuxGeom* pRag = m_pRenderer->GetIRenderAuxGeom();
639 SAuxGeomRenderFlags nRendFlags = pRag->GetRenderFlags();
641 pRag->SetRenderFlags(e_Def3DPublicRenderflags);
642 SAuxGeomRenderFlags nNewFlags = pRag->GetRenderFlags();
643 nNewFlags.SetAlphaBlendMode(e_AlphaBlended);
644 pRag->SetRenderFlags(nNewFlags);
646 int nGridAlpha = 40;
647 if (m_bGrid)
649 // Draw grid.
650 for (float x = -XR; x < XR; x += step)
652 if (fabs(x) > 0.01)
653 pRag->DrawLine(Vec3(x, -YR, 0), ColorB(150, 150, 150, nGridAlpha), Vec3(x, YR, 0), ColorB(150, 150, 150, nGridAlpha));
655 for (float y = -YR; y < YR; y += step)
657 if (fabs(y) > 0.01)
658 pRag->DrawLine(Vec3(-XR, y, 0), ColorB(150, 150, 150, nGridAlpha), Vec3(XR, y, 0), ColorB(150, 150, 150, nGridAlpha));
663 nGridAlpha = 60;
664 if (m_bAxis)
666 // Draw axis.
667 pRag->DrawLine(Vec3(0, 0, 0), ColorB(255, 0, 0, nGridAlpha), Vec3(XR, 0, 0), ColorB(255, 0, 0, nGridAlpha));
668 pRag->DrawLine(Vec3(0, 0, 0), ColorB(0, 255, 0, nGridAlpha), Vec3(0, YR, 0), ColorB(0, 255, 0, nGridAlpha));
669 pRag->DrawLine(Vec3(0, 0, 0), ColorB(0, 0, 255, nGridAlpha), Vec3(0, 0, YR), ColorB(0, 0, 255, nGridAlpha));
671 pRag->SetRenderFlags(nRendFlags);
674 void CPreviewModelCtrl::UpdateAnimation()
676 if (m_pCharacter)
678 GetISystem()->GetIAnimationSystem()->Update(false);
679 m_pCharacter->GetISkeletonPose()->SetForceSkeletonUpdate(0);
681 const CCamera& camera = GetCamera();
682 float fDistance = (camera.GetPosition()).GetLength();
683 float fZoomFactor = 0.001f + 0.999f * (RAD2DEG(camera.GetFov()) / 60.f);
685 SAnimationProcessParams params;
686 params.locationAnimation = QuatTS(IDENTITY);
687 params.bOnRender = 0;
688 params.zoomAdjustedDistanceFromCamera = fDistance * fZoomFactor;
689 m_pCharacter->StartAnimationProcessing(params);
690 m_pCharacter->FinishAnimationComputations();
692 m_aabb = m_pCharacter->GetAABB();
696 void CPreviewModelCtrl::OnTimer(UINT_PTR nIDEvent)
698 if (IsWindowVisible())
700 if (m_bHaveAnythingToRender)
701 Invalidate();
704 CWnd::OnTimer(nIDEvent);
707 void CPreviewModelCtrl::SetCameraTM(const Matrix34& cameraTM)
709 m_camera.SetMatrix(cameraTM);
710 if (m_cameraChangeCallback)
711 m_cameraChangeCallback(m_pCameraChangeUserData, this);
714 void CPreviewModelCtrl::GetCameraTM(Matrix34& cameraTM)
716 cameraTM = m_camera.GetMatrix();
719 void CPreviewModelCtrl::OnDestroy()
721 ReleaseObject();
722 DestroyRenderContext();
724 CWnd::OnDestroy();
726 if (m_nTimer)
727 KillTimer(m_nTimer);
730 void CPreviewModelCtrl::OnLButtonDown(UINT nFlags, CPoint point)
732 m_bInRotateMode = true;
733 m_mousePosition = point;
734 SetFocus();
735 if (!m_bInMoveMode)
736 SetCapture();
737 Invalidate();
740 void CPreviewModelCtrl::OnLButtonUp(UINT nFlags, CPoint point)
742 m_bInRotateMode = false;
743 if (!m_bInMoveMode)
744 ReleaseCapture();
745 Invalidate();
748 void CPreviewModelCtrl::OnMButtonDown(UINT nFlags, CPoint point)
750 m_bInRotateMode = true;
751 m_bInMoveMode = true;
752 m_mousePosition = point;
753 SetCapture();
754 Invalidate();
757 void CPreviewModelCtrl::OnMButtonUp(UINT nFlags, CPoint point)
759 m_bInRotateMode = false;
760 m_bInMoveMode = false;
761 ReleaseCapture();
762 Invalidate();
765 void CPreviewModelCtrl::OnMouseMove(UINT nFlags, CPoint point)
767 // TODO: Add your message handler code here and/or call default
768 CWnd::OnMouseMove(nFlags, point);
770 if (point == m_mousePosition)
771 return;
773 if (m_bInMoveMode)
775 // Zoom.
776 Matrix34 m = m_camera.GetMatrix();
777 Vec3 xdir(0, 0, 0);
778 Vec3 zdir = m.GetColumn1().GetNormalized();
780 float step = 0.002f;
781 float dx = (point.x - m_mousePosition.x);
782 float dy = (point.y - m_mousePosition.y);
783 m_camera.SetPosition(m_camera.GetPosition() + step * xdir * dx + step * zdir * dy);
784 SetCamera(m_camera);
786 CPoint pnt = m_mousePosition;
787 ClientToScreen(&pnt);
788 SetCursorPos(pnt.x, pnt.y);
789 Invalidate();
791 else if (m_bInRotateMode)
793 Vec3 pos = m_camera.GetMatrix().GetTranslation();
794 m_cameraRadius = Vec3(m_camera.GetMatrix().GetTranslation() - m_cameraTarget).GetLength();
795 // Look
796 Ang3 angles(-point.y + m_mousePosition.y, 0, -point.x + m_mousePosition.x);
797 angles = angles * 0.002f;
799 Matrix34 camtm = m_camera.GetMatrix();
800 Matrix33 Rz = Matrix33::CreateRotationXYZ(Ang3(0, 0, angles.z)); // Rotate around vertical axis.
801 Matrix33 Rx = Matrix33::CreateRotationAA(angles.x, camtm.GetColumn0()); // Rotate with angle around x axis in camera space.
803 Vec3 dir = camtm.TransformVector(Vec3(0, 1, 0));
804 Vec3 newdir = (Rx * Rz).TransformVector(dir).GetNormalized();
805 camtm = Matrix34(Matrix33::CreateRotationVDir(newdir, 0), m_cameraTarget - newdir * m_cameraRadius);
806 m_camera.SetMatrix(camtm);
807 if (m_cameraChangeCallback)
808 m_cameraChangeCallback(m_pCameraChangeUserData, this);
810 CPoint pnt = m_mousePosition;
811 ClientToScreen(&pnt);
812 SetCursorPos(pnt.x, pnt.y);
813 Invalidate();
815 else if (m_bInMoveMode)
817 // Slide.
818 float speedScale = 0.001f;
819 Matrix34 m = m_camera.GetMatrix();
820 Vec3 xdir = m.GetColumn0().GetNormalized();
821 Vec3 zdir = m.GetColumn2().GetNormalized();
823 Vec3 pos = m_cameraTarget;
824 pos += 0.1f * xdir * (point.x - m_mousePosition.x) * speedScale + 0.1f * zdir * (m_mousePosition.y - point.y) * speedScale;
825 m_cameraTarget = pos;
827 Vec3 dir = m.TransformVector(Vec3(0, 1, 0));
828 m.SetTranslation(m_cameraTarget - dir * m_cameraRadius);
829 m_camera.SetMatrix(m);
830 if (m_cameraChangeCallback)
831 m_cameraChangeCallback(m_pCameraChangeUserData, this);
833 m_mousePosition = point;
834 CPoint pnt = m_mousePosition;
835 ClientToScreen(&pnt);
836 SetCursorPos(pnt.x, pnt.y);
837 Invalidate();
841 void CPreviewModelCtrl::OnRButtonDown(UINT nFlags, CPoint point)
843 m_bInMoveMode = true;
844 m_mousePosition = point;
845 if (!m_bInRotateMode)
846 SetCapture();
847 Invalidate();
850 void CPreviewModelCtrl::OnRButtonUp(UINT nFlags, CPoint point)
852 m_bInMoveMode = false;
853 m_mousePosition = point;
854 if (!m_bInRotateMode)
855 ReleaseCapture();
856 Invalidate();
859 BOOL CPreviewModelCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint point)
861 // TODO: Add your message handler code here and/or call default
862 Matrix34 m = m_camera.GetMatrix();
863 Vec3 zdir = m.GetColumn1().GetNormalized();
865 //m_camera.SetPosition( m_camera.GetPos() + ydir*(m_mousePos.y-point.y),xdir*(m_mousePos.x-point.x) );
866 m_camera.SetPosition(m_camera.GetPosition() + 0.002f * zdir * (zDelta));
867 SetCamera(m_camera);
868 Invalidate();
870 return TRUE;
873 void CPreviewModelCtrl::OnSize(UINT nType, int cx, int cy)
875 CWnd::OnSize(nType, cx, cy);
876 RedrawWindow();
878 //m_pRenderer->ResizeContext(GetSafeHwnd(),cx,cy);
881 void CPreviewModelCtrl::EnableUpdate(bool bUpdate)
883 m_bUpdate = bUpdate;
886 void CPreviewModelCtrl::Update(bool bForceUpdate)
888 ProcessKeys();
890 if (m_bUpdate && m_bHaveAnythingToRender || bForceUpdate)
892 if (IsWindowVisible())
893 Render();
897 void CPreviewModelCtrl::SetRotation(bool bEnable)
899 m_bRotate = bEnable;
902 void CPreviewModelCtrl::SetMaterial(IEditorMaterial* pMaterial)
904 if (pMaterial)
906 if ((pMaterial->GetFlags() & MTL_FLAG_NOPREVIEW))
908 m_pCurrentMaterial = 0;
909 Invalidate();
910 return;
913 m_pCurrentMaterial = pMaterial;
914 Invalidate();
917 IEditorMaterial* CPreviewModelCtrl::GetMaterial()
919 return m_pCurrentMaterial;
922 void CPreviewModelCtrl::OnEditorNotifyEvent(EEditorNotifyEvent event)
924 switch (event)
926 case eNotify_OnIdleUpdate:
927 Update();
928 break;
929 case eNotify_OnClearLevelContents:
930 ReleaseObject();
931 break;
935 void CPreviewModelCtrl::GetImageOffscreen(CImageEx& image, const CSize& customSize)
937 m_pRenderer->EnableSwapBuffers(false);
938 Render();
939 m_pRenderer->EnableSwapBuffers(true);
941 CRect rc;
942 int width;
943 int height;
945 GetClientRect(rc);
947 if (customSize.cx == 0 && customSize.cy == 0)
949 width = rc.Width();
950 height = rc.Height();
952 else
954 width = customSize.cx;
955 height = customSize.cy;
958 image.Allocate(width, height);
959 m_pRenderer->ReadFrameBuffer(image.GetData(), width, height);
961 // At this point the image is upside-down, so we need to flip it.
962 unsigned int* data = image.GetData();
963 for (int row = 0; row < (height - 1) / 2; ++row)
965 for (int col = 0; col < width; ++col)
967 unsigned int pixelUp = data[row * width + col];
968 unsigned int pixelDn = data[(height - row - 1) * width + col];
970 data[row * width + col] = pixelDn;
971 data[(height - row - 1) * width + col] = pixelUp;
976 void CPreviewModelCtrl::GetImage(CImageEx& image)
978 Render();
980 CRect rc;
981 GetClientRect(rc);
982 int width = rc.Width();
983 int height = rc.Height();
984 image.Allocate(width, height);
986 CBitmap bmp;
987 CDC dcMemory;
988 CDC* pDC = GetDC();
989 dcMemory.CreateCompatibleDC(pDC);
991 bmp.CreateCompatibleBitmap(pDC, width, height);
993 CBitmap* pOldBitmap = dcMemory.SelectObject(&bmp);
994 dcMemory.BitBlt(0, 0, width, height, pDC, 0, 0, SRCCOPY);
996 BITMAP bmpInfo;
997 bmp.GetBitmap(&bmpInfo);
998 bmp.GetBitmapBits(width * height * (bmpInfo.bmBitsPixel / 8), image.GetData());
999 int bpp = bmpInfo.bmBitsPixel / 8;
1001 dcMemory.SelectObject(pOldBitmap);
1003 ReleaseDC(pDC);
1006 void CPreviewModelCtrl::SetClearColor(const ColorF& color)
1008 m_clearColor = color;
1011 static int GetFaceCountRecursively(IStatObj* p)
1013 if (!p)
1015 return 0;
1017 int n = 0;
1018 if (p->GetRenderMesh())
1020 n += p->GetRenderMesh()->GetIndicesCount() / 3;
1022 for (int i = 0; i < p->GetSubObjectCount(); ++i)
1024 IStatObj::SSubObject* const pS = p->GetSubObject(i);
1025 if (pS)
1027 n += GetFaceCountRecursively(pS->pStatObj);
1030 return n;
1033 static int GetVertexCountRecursively(IStatObj* p)
1035 if (!p)
1037 return 0;
1039 int n = 0;
1040 if (p->GetRenderMesh())
1042 n += p->GetRenderMesh()->GetVerticesCount();
1044 for (int i = 0; i < p->GetSubObjectCount(); ++i)
1046 IStatObj::SSubObject* const pS = p->GetSubObject(i);
1047 if (pS)
1049 n += GetVertexCountRecursively(pS->pStatObj);
1052 return n;
1055 static int GetMaxLodRecursively(IStatObj* p)
1057 if (!p)
1059 return 0;
1061 int n = 0;
1062 for (int i = 1; i < 10; i++)
1064 if (p->GetLodObject(i))
1066 n = i;
1069 for (int i = 0; i < p->GetSubObjectCount(); ++i)
1071 IStatObj::SSubObject* const pS = p->GetSubObject(i);
1072 if (pS)
1074 const int n2 = GetMaxLodRecursively(pS->pStatObj);
1075 n = (n < n2) ? n2 : n;
1078 return n;
1081 namespace
1083 struct MaterialId
1085 const void* ptr;
1086 int id;
1088 MaterialId(const void* a_ptr, int a_id)
1089 : ptr(a_ptr)
1090 , id(a_id)
1094 bool operator<(const MaterialId& a) const
1096 return ptr < a.ptr || id < a.id;
1101 static void CollectMaterialsRecursively(std::set<MaterialId>& mats, IStatObj* p)
1103 if (!p)
1105 return;
1107 if (p->GetRenderMesh())
1109 TRenderChunkArray& ch = p->GetRenderMesh()->GetChunks();
1110 for (size_t i = 0; i < ch.size(); ++i)
1112 mats.insert(MaterialId(p->GetMaterial(), ch[i].m_nMatID));
1115 for (int i = 0; i < p->GetSubObjectCount(); ++i)
1117 IStatObj::SSubObject* const pS = p->GetSubObject(i);
1118 if (pS)
1120 CollectMaterialsRecursively(mats, pS->pStatObj);
1125 int CPreviewModelCtrl::GetFaceCount()
1127 if (m_pObj)
1129 return GetFaceCountRecursively(m_pObj);
1131 else if (m_pCharacter)
1135 return 0;
1138 int CPreviewModelCtrl::GetVertexCount()
1140 if (m_pObj)
1142 return GetVertexCountRecursively(m_pObj);
1144 else if (m_pCharacter)
1148 return 0;
1151 int CPreviewModelCtrl::GetMaxLod()
1153 if (m_pObj)
1155 return GetMaxLodRecursively(m_pObj);
1157 else if (m_pCharacter)
1159 return 1; //BaseModels have only 1 LOD
1161 return 0;
1164 int CPreviewModelCtrl::GetMtlCount()
1166 if (m_pObj)
1168 std::set<MaterialId> mats;
1169 CollectMaterialsRecursively(mats, m_pObj);
1170 return (int)mats.size();
1172 return 0;
1175 void CPreviewModelCtrl::FitToScreen()
1177 SetCameraLookAt(2.0f, Vec3(1, 1, -0.5));
1180 bool CPreviewModelCtrl::CheckVirtualKey(int virtualKey)
1182 GetAsyncKeyState(virtualKey);
1183 if (GetAsyncKeyState(virtualKey) & (1 << 15))
1184 return true;
1185 return false;
1188 void CPreviewModelCtrl::ProcessKeys()
1190 if (GetFocus() != this)
1191 return;
1193 int moveSpeed = 1;
1195 Matrix34 m = m_camera.GetMatrix();
1197 Vec3 ydir = m.GetColumn2().GetNormalized();
1198 Vec3 xdir = m.GetColumn0().GetNormalized();
1200 Vec3 pos = m.GetTranslation();
1202 float speedScale = 60.0f * GetIEditor()->GetSystem()->GetITimer()->GetFrameTime();
1203 if (speedScale > 20) speedScale = 20;
1205 speedScale *= 0.04f;
1207 if (CheckVirtualKey(VK_SHIFT))
1209 speedScale *= gViewportMovementPreferences.camFastMoveSpeed;
1212 if (ViewportInteraction::CheckPolledKey(ViewportInteraction::eKey_Forward))
1214 // move forward
1215 m_camera.SetPosition(pos + speedScale * moveSpeed * ydir);
1216 SetCamera(m_camera);
1219 if (ViewportInteraction::CheckPolledKey(ViewportInteraction::eKey_Backward))
1221 // move backward
1222 m_camera.SetPosition(pos - speedScale * moveSpeed * ydir);
1223 SetCamera(m_camera);
1227 BOOL CPreviewModelCtrl::PreTranslateMessage(MSG* pMsg)
1229 if (WM_KEYDOWN == pMsg->message || WM_KEYUP == pMsg->message)
1230 return TRUE;
1232 return CWnd::PreTranslateMessage(pMsg);
1235 void CPreviewModelCtrl::SetBackgroundTexture(const CString& textureFilename)
1237 m_backgroundTextureId = GetIEditor()->GetIconManager()->GetIconTexture(textureFilename);
1240 void CPreviewModelCtrl::DrawBackground()
1242 if (!m_backgroundTextureId)
1243 return;
1245 SVF_P3F_C4B_T2F tempVertices[6];
1246 SVF_P3F_C4B_T2F* pVertex = tempVertices;
1248 const float xpos = 0.0f;
1249 const float ypos = 0.0f;
1250 const float z = 0.0f;
1251 const uint32 color = 0xFFFFFFFF;
1252 const float w = 1.0f;
1253 const float h = 1.0f;
1254 const float s[4] = { 0.0f, 1.0f, 1.0f, 0.0f };
1255 const float t[4] = { 1.0f, 1.0f, 0.0f, 0.0f };
1257 pVertex->xyz.x = xpos;
1258 pVertex->xyz.y = ypos;
1259 pVertex->xyz.z = z;
1260 pVertex->st = Vec2(s[0], t[0]);
1261 pVertex->color.dcolor = color;
1263 ++pVertex;
1265 pVertex->xyz.x = xpos + w;
1266 pVertex->xyz.y = ypos;
1267 pVertex->xyz.z = z;
1268 pVertex->st = Vec2(s[1], t[1]);
1269 pVertex->color.dcolor = color;
1271 ++pVertex;
1273 pVertex->xyz.x = xpos;
1274 pVertex->xyz.y = ypos + h;
1275 pVertex->xyz.z = z;
1276 pVertex->st = Vec2(s[3], t[3]);
1277 pVertex->color.dcolor = color;
1279 ++pVertex;
1281 pVertex->xyz.x = xpos;
1282 pVertex->xyz.y = ypos + h;
1283 pVertex->xyz.z = z;
1284 pVertex->st = Vec2(s[3], t[3]);
1285 pVertex->color.dcolor = color;
1287 ++pVertex;
1289 pVertex->xyz.x = xpos + w;
1290 pVertex->xyz.y = ypos;
1291 pVertex->xyz.z = z;
1292 pVertex->st = Vec2(s[1], t[1]);
1293 pVertex->color.dcolor = color;
1295 ++pVertex;
1297 pVertex->xyz.x = xpos + w;
1298 pVertex->xyz.y = ypos + h;
1299 pVertex->xyz.z = z;
1300 pVertex->st = Vec2(s[2], t[2]);
1301 pVertex->color.dcolor = color;
1303 SAuxGeomRenderFlags renderFlags;
1304 renderFlags.SetMode2D3DFlag(e_Mode2D);
1305 renderFlags.SetAlphaBlendMode(e_AlphaNone);
1306 renderFlags.SetDrawInFrontMode(e_DrawInFrontOff);
1307 renderFlags.SetFillMode(e_FillModeSolid);
1308 renderFlags.SetCullMode(e_CullModeNone);
1309 renderFlags.SetDepthWriteFlag(e_DepthWriteOff);
1310 renderFlags.SetDepthTestFlag(e_DepthTestOff);
1312 IRenderAuxGeom* aux = gEnv->pRenderer->GetIRenderAuxGeom();
1313 const SAuxGeomRenderFlags prevRenderFlags = aux->GetRenderFlags();
1314 aux->SetRenderFlags(renderFlags);
1315 aux->SetTexture(m_backgroundTextureId);
1317 aux->DrawBuffer(tempVertices, 6, true);
1319 aux->SetTexture(-1);
1320 aux->SetRenderFlags(prevRenderFlags);