Serious-Engine/Sources/WorldEditor/WorldEditorView.cpp
2016-03-23 20:42:20 +03:00

13725 lines
442 KiB
C++
Raw Blame History

/* Copyright (c) 2002-2012 Croteam Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as published by
the Free Software Foundation
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
// WorldEditorView.cpp : implementation of the CWorldEditorView class
//
#include "stdafx.h"
#include "WorldEditor.h"
#include <Engine/Base/Profiling.h>
#include <Engine/Base/Statistics.h>
#include <Engine/Templates/Stock_CTextureData.h>
#include <Engine/Terrain/TerrainEditing.h>
#include <Engine/Terrain/TerrainMisc.h>
#ifdef _DEBUG
#undef new
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CTimerValue _tvLastTerrainBrushingApplied;
static INDEX aiForCreationOfSizingVertices[14][6] =
{
{0,0,2,2,5,5},
{1,1,2,2,5,5},
{1,1,2,2,4,4},
{0,0,2,2,4,4},
{0,0,3,3,5,5},
{1,1,3,3,5,5},
{1,1,3,3,4,4},
{0,0,3,3,4,4},
{0,1,2,3,5,5},
{1,1,2,3,4,5},
{0,1,2,3,4,4},
{0,0,2,3,4,5},
{0,1,2,2,4,5},
{0,1,3,3,4,5},
};
static INDEX aiForAllowedSizing[14][6] =
{
{1,0,1,0,0,1},
{0,1,1,0,0,1},
{0,1,1,0,1,0},
{1,0,1,0,1,0},
{1,0,0,1,0,1},
{0,1,0,1,0,1},
{0,1,0,1,1,0},
{1,0,0,1,1,0},
{0,0,0,0,0,1},
{0,1,0,0,0,0},
{0,0,0,0,1,0},
{1,0,0,0,0,0},
{0,0,1,0,0,0},
{0,0,0,1,0,0},
};
/////////////////////////////////////////////////////////////////////////////
// CWorldEditorView
IMPLEMENT_DYNCREATE(CWorldEditorView, CView)
BEGIN_MESSAGE_MAP(CWorldEditorView, CView)
//{{AFX_MSG_MAP(CWorldEditorView)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_KILLFOCUS()
ON_WM_LBUTTONDOWN()
ON_WM_KEYDOWN()
ON_WM_KEYUP()
ON_WM_MOUSEMOVE()
ON_WM_RBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_RBUTTONUP()
ON_WM_DROPFILES()
ON_COMMAND(ID_ISOMETRIC_FRONT, OnIsometricFront)
ON_COMMAND(ID_ISOMETRIC_BACK, OnIsometricBack)
ON_COMMAND(ID_ISOMETRIC_BOTTOM, OnIsometricBottom)
ON_COMMAND(ID_ISOMETRIC_LEFT, OnIsometricLeft)
ON_COMMAND(ID_ISOMETRIC_RIGHT, OnIsometricRight)
ON_COMMAND(ID_ISOMETRIC_TOP, OnIsometricTop)
ON_COMMAND(ID_PERSPECTIVE, OnPerspective)
ON_COMMAND(ID_ZOOM_LESS, OnZoomLess)
ON_COMMAND(ID_ZOOM_MORE, OnZoomMore)
ON_COMMAND(ID_MOVE_DOWN, OnMoveDown)
ON_COMMAND(ID_MOVE_UP, OnMoveUp)
ON_WM_LBUTTONDBLCLK()
ON_COMMAND(ID_MEASUREMENT_TAPE, OnMeasurementTape)
ON_UPDATE_COMMAND_UI(ID_MEASUREMENT_TAPE, OnUpdateMeasurementTape)
ON_COMMAND(ID_CIRCLE_MODES, OnCircleModes)
ON_UPDATE_COMMAND_UI(ID_CIRCLE_MODES, OnUpdateCircleModes)
ON_COMMAND(ID_DESELECT_ALL, OnDeselectAll)
ON_COMMAND(ID_DELETE_ENTITIES, OnDeleteEntities)
ON_UPDATE_COMMAND_UI(ID_DELETE_ENTITIES, OnUpdateDeleteEntities)
ON_WM_SETCURSOR()
ON_COMMAND(ID_TAKE_SS, OnTakeSs)
ON_UPDATE_COMMAND_UI(ID_ENTITY_MODE, OnUpdateEntityMode)
ON_COMMAND(ID_SECTOR_MODE, OnSectorMode)
ON_UPDATE_COMMAND_UI(ID_SECTOR_MODE, OnUpdateSectorMode)
ON_COMMAND(ID_POLYGON_MODE, OnPolygonMode)
ON_UPDATE_COMMAND_UI(ID_POLYGON_MODE, OnUpdatePolygonMode)
ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
ON_COMMAND(ID_CLONE_CSG, OnCloneCSG)
ON_UPDATE_COMMAND_UI(ID_CLONE_CSG, OnUpdateCloneCsg)
ON_COMMAND(ID_MEASURE_ON, OnMeasureOn)
ON_UPDATE_COMMAND_UI(ID_MEASURE_ON, OnUpdateMeasureOn)
ON_COMMAND(ID_RESET_VIEWER, OnResetViewer)
ON_COMMAND(ID_COPY_TEXTURE, OnCopyTexture)
ON_COMMAND(ID_PASTE_TEXTURE, OnPasteTexture)
ON_COMMAND(ID_CENTER_ENTITY, OnCenterEntity)
ON_COMMAND(ID_FUNCTION, OnFunction)
ON_UPDATE_COMMAND_UI(ID_CENTER_ENTITY, OnUpdateCenterEntity)
ON_COMMAND(ID_DROP_MARKER, OnDropMarker)
ON_UPDATE_COMMAND_UI(ID_DROP_MARKER, OnUpdateDropMarker)
ON_COMMAND(ID_TEST_CONNECTIONS, OnTestConnections)
ON_UPDATE_COMMAND_UI(ID_TEST_CONNECTIONS, OnUpdateTestConnections)
ON_COMMAND(ID_ALIGN_VOLUME, OnAlignVolume)
ON_UPDATE_COMMAND_UI(ID_ALIGN_VOLUME, OnUpdateAlignVolume)
ON_COMMAND(ID_CURRENT_VIEW_PROPERTIES, OnCurrentViewProperties)
ON_COMMAND(ID_DELETE_MIP, OnDeleteMip)
ON_UPDATE_COMMAND_UI(ID_DELETE_MIP, OnUpdateDeleteMip)
ON_COMMAND(ID_PREVIOUS_MIP_BRUSH, OnPreviousMipBrush)
ON_UPDATE_COMMAND_UI(ID_PREVIOUS_MIP_BRUSH, OnUpdatePreviousMipBrush)
ON_COMMAND(ID_NEXT_MIP_BRUSH, OnNextMipBrush)
ON_UPDATE_COMMAND_UI(ID_NEXT_MIP_BRUSH, OnUpdateNextMipBrush)
ON_COMMAND(ID_CROSSROAD_FOR_C, OnCrossroadForC)
ON_COMMAND(ID_CHOOSE_COLOR, OnChooseColor)
ON_UPDATE_COMMAND_UI(ID_CHOOSE_COLOR, OnUpdateChooseColor)
ON_COMMAND(ID_MENU_COPY_MAPPING, OnMenuCopyMapping)
ON_COMMAND(ID_MENU_PASTE_MAPPING, OnMenuPasteMapping)
ON_COMMAND(ID_SET_AS_CSG_TARGET, OnSetAsCsgTarget)
ON_COMMAND(ID_KEY_PASTE, OnKeyPaste)
ON_WM_RBUTTONDBLCLK()
ON_COMMAND(ID_SELECT_BY_TEXTURE_ADJACENT, OnSelectByTextureAdjacent)
ON_COMMAND(ID_SELECT_BY_TEXTURE_IN_SECTOR, OnSelectByTextureInSector)
ON_COMMAND(ID_SELECT_BY_COLOR_IN_SECTOR, OnSelectByColorInSector)
ON_COMMAND(ID_CONUS_PRIMITIVE, OnConusPrimitive)
ON_COMMAND(ID_TORUS_PRIMITIVE, OnTorusPrimitive)
ON_COMMAND(ID_TERRAIN_PRIMITIVE, OnTerrainPrimitive)
ON_COMMAND(ID_SPHERE_PRIMITIVE, OnSpherePrimitive)
ON_COMMAND(ID_STAIRCASE_PRIMITIVE, OnStaircasePrimitive)
ON_UPDATE_COMMAND_UI(ID_CONUS_PRIMITIVE, OnUpdateConusPrimitive)
ON_UPDATE_COMMAND_UI(ID_SPHERE_PRIMITIVE, OnUpdateSpherePrimitive)
ON_UPDATE_COMMAND_UI(ID_TERRAIN_PRIMITIVE, OnUpdateTerrainPrimitive)
ON_UPDATE_COMMAND_UI(ID_TORUS_PRIMITIVE, OnUpdateTorusPrimitive)
ON_UPDATE_COMMAND_UI(ID_STAIRCASE_PRIMITIVE, OnUpdateStaircasePrimitive)
ON_COMMAND(ID_POPUP_CONUS, OnPopupConus)
ON_COMMAND(ID_POPUP_SPHERE, OnPopupSphere)
ON_COMMAND(ID_POPUP_STAIRS, OnPopupStairs)
ON_COMMAND(ID_POPUP_TERRAIN, OnPopupTerrain)
ON_COMMAND(ID_POPUP_TORUS, OnPopupTorus)
ON_UPDATE_COMMAND_UI(ID_MOVE_DOWN, OnUpdateMoveDown)
ON_UPDATE_COMMAND_UI(ID_MOVE_UP, OnUpdateMoveUp)
ON_COMMAND(ID_SELECT_LIGHTS, OnSelectLights)
ON_COMMAND(ID_DISCARD_SHADOWS, OnDiscardShadows)
ON_COMMAND(ID_COPY_SECTOR_AMBIENT, OnCopySectorAmbient)
ON_COMMAND(ID_PASTE_SECTOR_AMBIENT, OnPasteSectorAmbient)
ON_COMMAND(ID_SELECT_ALL_POLYGONS, OnSelectAllPolygons)
ON_COMMAND(ID_COPY_SECTORS, OnCopySectors)
ON_COMMAND(ID_DELETE_SECTORS, OnDeleteSectors)
ON_COMMAND(ID_PASTE_SECTORS, OnPasteSectors)
ON_COMMAND(ID_CENTER_BCG_VIEWER, OnCenterBcgViewer)
ON_COMMAND(ID_MENU_PASTE_AS_PROJECTED_MAPPING, OnMenuPasteAsProjectedMapping)
ON_COMMAND(ID_KEY_PASTE_AS_PROJECTED, OnKeyPasteAsProjected)
ON_COMMAND(ID_SELECT_ALL_ENTITIES, OnSelectAllEntitiesInSectors)
ON_COMMAND(ID_SELECT_ALL_SECTORS, OnSelectAllSectors)
ON_COMMAND(ID_LAST_PRIMITIVE, OnLastPrimitive)
ON_UPDATE_COMMAND_UI(ID_LAST_PRIMITIVE, OnUpdateLastPrimitive)
ON_COMMAND(ID_CLONE_TO_MORE_PRECISE_MIP, OnCloneToMorePreciseMip)
ON_COMMAND(ID_CLONE_TO_ROUGHER_MIP_LEVEL, OnCloneToRougherMipLevel)
ON_COMMAND(ID_CREATE_EMPTY_MORE_PRECISE_MIP, OnCreateEmptyMorePreciseMip)
ON_COMMAND(ID_CREATE_EMPTY_ROUGHER_MIP, OnCreateEmptyRougherMip)
ON_UPDATE_COMMAND_UI(ID_CLONE_TO_MORE_PRECISE_MIP, OnUpdateCloneToMorePreciseMip)
ON_UPDATE_COMMAND_UI(ID_CLONE_TO_ROUGHER_MIP_LEVEL, OnUpdateCloneToRougherMipLevel)
ON_UPDATE_COMMAND_UI(ID_CREATE_EMPTY_MORE_PRECISE_MIP, OnUpdateCreateEmptyMorePreciseMip)
ON_UPDATE_COMMAND_UI(ID_CREATE_EMPTY_ROUGHER_MIP, OnUpdateCreateEmptyRougherMip)
ON_COMMAND(ID_EDIT_PASTE_ALTERNATIVE, OnEditPasteAlternative)
ON_COMMAND(ID_SELECT_ALL_ENTITIES_IN_WORLD, OnSelectAllEntitiesInWorld)
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE_ALTERNATIVE, OnUpdateEditPasteAlternative)
ON_COMMAND(ID_ENTITY_MODE, OnEntityMode)
ON_COMMAND(ID_FIND_TEXTURE, OnFindTexture)
ON_COMMAND(ID_SELECT_SECTORS_WITH_SAME_NAME, OnSelectSectorsWithSameName)
ON_COMMAND(ID_SELECT_SECTORS_ARROUND_ENTITY, OnSelectSectorsArroundEntity)
ON_COMMAND(ID_SELECT_SECTORS_ARROUND_ENTITY_ON_CONTEXT, OnSelectSectorsArroundEntityOnContext)
ON_COMMAND(ID_INSERT_VERTEX, OnInsertVertex)
ON_COMMAND(ID_DELETE_VERTEX, OnDeleteVertex)
ON_COMMAND(ID_SAVE_PICTURES_FOR_ENVIRONMENT, OnSavePicturesForEnvironment)
ON_UPDATE_COMMAND_UI(ID_SAVE_PICTURES_FOR_ENVIRONMENT, OnUpdateSavePicturesForEnvironment)
ON_WM_ERASEBKGND()
ON_COMMAND(ID_CSG_SELECT_SECTOR, OnCsgSelectSector)
ON_COMMAND(ID_MENU_ALIGN_MAPPING_U, OnMenuAlignMappingU)
ON_COMMAND(ID_MENU_ALIGN_MAPPING_V, OnMenuAlignMappingV)
ON_WM_DESTROY()
ON_COMMAND(ID_FALL_DOWN, OnFallDown)
ON_COMMAND(ID_PREVIOUS, OnPrevious)
ON_COMMAND(ID_NEXT, OnNext)
ON_UPDATE_COMMAND_UI(ID_PREVIOUS, OnUpdatePrevious)
ON_UPDATE_COMMAND_UI(ID_NEXT, OnUpdateNext)
ON_COMMAND(ID_REMOVE_UNUSED_TEXTURES, OnRemoveUnusedTextures)
ON_COMMAND(ID_ROTATE, OnRotate)
ON_COMMAND(ID_ROTATE_BACK, OnRotateBack)
ON_COMMAND(ID_SELECT_VISIBLE_SECTORS, OnSelectVisibleSectors)
ON_COMMAND(ID_EDIT_COPY_ALTERNATIVE, OnEditCopyAlternative)
ON_COMMAND(ID_ROTATE_LEFT, OnRotateLeft)
ON_COMMAND(ID_ROTATE_RIGHT, OnRotateRight)
ON_COMMAND(ID_ROTATE_UP, OnRotateUp)
ON_COMMAND(ID_ROTATE_DOWN, OnRotateDown)
ON_COMMAND(ID_SELECT_WHO_TARGETS, OnSelectWhoTargets)
ON_COMMAND(ID_SELECT_INVALIDTRIS, OnSelectInvalidTris)
ON_COMMAND(ID_TEST_CONNECTIONS_BACK, OnTestConnectionsBack)
ON_UPDATE_COMMAND_UI(ID_TEST_CONNECTIONS_BACK, OnUpdateTestConnectionsBack)
ON_WM_MOUSEWHEEL()
ON_COMMAND(ID_SELECT_SECTORS_OTHER_SIDE, OnSelectSectorsOtherSide)
ON_COMMAND(ID_SELECT_LINKS_TO_SECTOR, OnSelectLinksToSector)
ON_COMMAND(ID_REMAIN_SELECTEDBY_ORIENTATION, OnRemainSelectedByOrientation)
ON_COMMAND(ID_DESELECT_BY_ORIENTATION, OnDeselectByOrientation)
ON_COMMAND(ID_VERTEX_MODE, OnVertexMode)
ON_COMMAND(ID_REOPTIMIZE_BRUSHES, OnReoptimizeBrushes)
ON_COMMAND(ID_MERGE_VERTICES, OnMergeVertices)
ON_COMMAND(ID_EXPORT_DISPLACE_MAP, OnExportDisplaceMap)
ON_COMMAND(ID_CUT_MODE, OnCutMode)
ON_UPDATE_COMMAND_UI(ID_CUT_MODE, OnUpdateCutMode)
ON_COMMAND(ID_SELECT_ALL_TARGETS, OnSelectAllTargets)
ON_COMMAND(ID_SELECT_ALL_TARGETS_ON_CONTEXT, OnSelectAllTargetsOnContext)
ON_COMMAND(ID_SELECT_CLONES, OnSelectClones)
ON_COMMAND(ID_SELECT_CLONES_ON_CONTEXT, OnSelectClonesOnContext)
ON_UPDATE_COMMAND_UI(ID_SELECT_CLONES, OnUpdateSelectClones)
ON_COMMAND(ID_SELECT_ALL_VERTICES, OnSelectAllVertices)
ON_COMMAND(ID_SELECT_OF_SAME_CLASS, OnSelectOfSameClass)
ON_COMMAND(ID_SELECT_OF_SAME_CLASS_ON_CONTEXT, OnSelectOfSameClassOnContext)
ON_COMMAND(ID_ALTERNATIVE_MOVING_MODE, OnAlternativeMovingMode)
ON_COMMAND(ID_RE_TRIPLE, OnReTriple)
ON_COMMAND(ID_SELECT_WHO_TARGETS_ON_CONTEXT, OnSelectWhoTargetsOnContext)
ON_COMMAND(ID_CLEAR_ALL_TARGETS, OnClearAllTargets)
ON_COMMAND(ID_SELECT_CSG_TARGET, OnSelectCsgTarget)
ON_UPDATE_COMMAND_UI(ID_SELECT_CSG_TARGET, OnUpdateSelectCsgTarget)
ON_COMMAND(ID_REMAIN_SELECTEDBY_ORIENTATION_SINGLE, OnRemainSelectedbyOrientationSingle)
ON_UPDATE_COMMAND_UI(ID_RE_TRIPLE, OnUpdateReTriple)
ON_COMMAND(ID_TRIANGULARIZE_POLYGON, OnTriangularizePolygon)
ON_COMMAND(ID_ENTITY_CONTEXT_HELP, OnEntityContextHelp)
ON_COMMAND(ID_POPUP_AUTO_FIT_MAPPING, OnPopupAutoFitMapping)
ON_COMMAND(ID_TRIANGULARIZE_SELECTION, OnTriangularizeSelection)
ON_UPDATE_COMMAND_UI(ID_TRIANGULARIZE_SELECTION, OnUpdateTriangularizeSelection)
ON_COMMAND(ID_POPUP_AUTO_FIT_MAPPING_SMALL, OnPopupAutoFitMappingSmall)
ON_COMMAND(ID_POPUP_AUTO_FIT_MAPPING_BOTH, OnPopupAutoFitMappingBoth)
ON_COMMAND(ID_RESET_MAPPING_OFFSET, OnResetMappingOffset)
ON_COMMAND(ID_RESET_MAPPING_ROTATION, OnResetMappingRotation)
ON_COMMAND(ID_RESET_MAPPING_STRETCH, OnResetMappingStretch)
ON_COMMAND(ID_CROSSROAD_FOR_L, OnCrossroadForL)
ON_COMMAND(ID_SELECT_USING_TARGET_TREE, OnSelectUsingTargetTree)
ON_COMMAND(ID_TARGET_TREE, OnTargetTree)
ON_UPDATE_COMMAND_UI(ID_TARGET_TREE, OnUpdateTargetTree)
ON_COMMAND(ID_SWAP_LAYERS_12, OnSwapLayers12)
ON_COMMAND(ID_SWAP_LAYERS_23, OnSwapLayers23)
ON_COMMAND(ID_SELECT_DESCENDANTS, OnSelectDescendants)
ON_COMMAND(ID_CROSSROAD_FOR_CTRL_F, OnCrossroadForCtrlF)
ON_COMMAND(ID_ROTATE_TO_TARGET_CENTER, OnRotateToTargetCenter)
ON_COMMAND(ID_ROTATE_TO_TARGET_ORIGIN, OnRotateToTargetOrigin)
ON_COMMAND(ID_COPY_ORIENTATION, OnCopyOrientation)
ON_COMMAND(ID_COPY_PLACEMENT, OnCopyPlacement)
ON_COMMAND(ID_COPY_POSITION, OnCopyPosition)
ON_COMMAND(ID_PASTE_ORIENTATION, OnPasteOrientation)
ON_COMMAND(ID_PASTE_PLACEMENT, OnPastePlacement)
ON_COMMAND(ID_PASTE_POSITION, OnPastePosition)
ON_COMMAND(ID_ALIGN_B, OnAlignB)
ON_COMMAND(ID_ALIGN_H, OnAlignH)
ON_COMMAND(ID_ALIGN_P, OnAlignP)
ON_COMMAND(ID_ALIGN_X, OnAlignX)
ON_COMMAND(ID_ALIGN_Y, OnAlignY)
ON_COMMAND(ID_ALIGN_Z, OnAlignZ)
ON_COMMAND(ID_AUTOTEXTURIZE_MIPS, OnAutotexturizeMips)
ON_UPDATE_COMMAND_UI(ID_AUTOTEXTURIZE_MIPS, OnUpdateAutotexturizeMips)
ON_COMMAND(ID_RANDOM_OFFSET_U, OnRandomOffsetU)
ON_COMMAND(ID_RANDOM_OFFSET_V, OnRandomOffsetV)
ON_COMMAND(ID_STRETCH_RELATIVE_OFFSET, OnStretchRelativeOffset)
ON_COMMAND(ID_DESELECT_HIDDEN, OnDeselectHidden)
ON_COMMAND(ID_SELECT_HIDDEN, OnSelectHidden)
ON_COMMAND(ID_SECTORS_TO_BRUSH, OnSectorsToBrush)
ON_COMMAND(ID_POLYGONS_TO_BRUSH, OnPolygonsToBrush)
ON_COMMAND(ID_CLONE_POLYGONS, OnClonePolygons)
ON_COMMAND(ID_DELETE_POLYGONS, OnDeletePolygons)
ON_COMMAND(ID_KEY_U, OnKeyU)
ON_COMMAND(ID_KEY_D, OnKeyD)
ON_COMMAND(ID_FLIP_POLYGON, OnFlipPolygon)
ON_COMMAND(ID_TERRAIN_MODE, OnTerrainMode)
ON_UPDATE_COMMAND_UI(ID_TERRAIN_MODE, OnUpdateTerrainMode)
ON_COMMAND(ID_KEY_M, OnKeyM)
ON_COMMAND(ID_KEY_BACKSLASH, OnKeyBackslash)
ON_COMMAND(ID_SELECT_BRUSH, OnSelectBrush)
ON_COMMAND(ID_SELECT_TERRAIN, OnSelectTerrain)
ON_COMMAND(ID_ALTITUDE_EDIT_MODE, OnAltitudeEditMode)
ON_COMMAND(ID_LAYER_TEXTURE_EDIT_MODE, OnLayerTextureEditMode)
ON_COMMAND(ID_TBRUSH_ALTITUDE, OnTbrushAltitude)
ON_COMMAND(ID_TBRUSH_EQUILAZE, OnTbrushEquilaze)
ON_COMMAND(ID_TBRUSH_ERASE, OnTbrushErase)
ON_COMMAND(ID_TBRUSH_NOISE, OnTbrushNoise)
ON_COMMAND(ID_TBRUSH_SMOOTH, OnTbrushSmooth)
ON_COMMAND(ID_OPTIMIZE_TERRAIN, OnOptimizeTerrain)
ON_COMMAND(ID_RECALCULATE_TERRAIN_SHADOWS, OnRecalculateTerrainShadows)
ON_COMMAND(ID_VIEW_HEIGHTMAP, OnViewHeightmap)
ON_COMMAND(ID_IMPORT_HEIGHTMAP, OnImportHeightmap)
ON_COMMAND(ID_EXPORT_HEIGHTMAP, OnExportHeightmap)
ON_COMMAND(ID_IMPORT_HEIGHTMAP16, OnImportHeightmap16)
ON_COMMAND(ID_EXPORT_HEIGHTMAP16, OnExportHeightmap16)
ON_COMMAND(ID_SELECT_LAYER, OnSelectLayer)
ON_COMMAND(ID_PICK_LAYER, OnPickLayer)
ON_COMMAND(ID_KEY_O, OnKeyO)
ON_UPDATE_COMMAND_UI(ID_KEY_O, OnUpdateKeyO)
ON_COMMAND(ID_POSTERIZE, OnPosterize)
ON_COMMAND(ID_EQUILIZE, OnFlatten)
ON_COMMAND(ID_APPLY_FILTER, OnApplyFilter)
ON_COMMAND(ID_TE_SMOOTH, OnTeSmooth)
ON_COMMAND(ID_EDIT_TERRAIN_PREFS, OnEditTerrainPrefs)
ON_UPDATE_COMMAND_UI(ID_EDIT_TERRAIN_PREFS, OnUpdateEditTerrainPrefs)
ON_COMMAND(ID_KEY_CTRL_SHIFT_E, OnKeyCtrlShiftE)
ON_COMMAND(ID_KEY_CTRL_SHIFT_G, OnKeyCtrlShiftG)
ON_UPDATE_COMMAND_UI(ID_KEY_CTRL_SHIFT_G, OnUpdateKeyCtrlShiftG)
ON_COMMAND(ID_TERRAIN_LAYER_OPTIONS, OnTerrainLayerOptions)
ON_UPDATE_COMMAND_UI(ID_TERRAIN_LAYER_OPTIONS, OnUpdateTerrainLayerOptions)
ON_COMMAND(ID_KEY_CTRL_SHIFT_K, OnKeyCtrlShiftK)
ON_COMMAND(ID_APPLY_CONTINOUS_NOISE, OnApplyContinousNoise)
ON_COMMAND(ID_APPLY_MINIMUM, OnApplyMinimum)
ON_COMMAND(ID_APPLY_MAXIMUM, OnApplyMaximum)
ON_COMMAND(ID_APPLY_FLATTEN, OnApplyFlatten)
ON_COMMAND(ID_APPLY_POSTERIZE, OnApplyPosterize)
ON_COMMAND(ID_OPTIMIZE_LAYERS, OnOptimizeLayers)
ON_COMMAND(ID_TBRUSH_CONTINOUS_NOISE, OnTbrushContinousNoise)
ON_COMMAND(ID_TBRUSH_FILTER, OnTbrushFilter)
ON_COMMAND(ID_TBRUSH_FLATTEN, OnTbrushFlatten)
ON_COMMAND(ID_TBRUSH_MAXIMUM, OnTbrushMaximum)
ON_COMMAND(ID_TBRUSH_MINIMUM, OnTbrushMinimum)
ON_COMMAND(ID_TBRUSH_POSTERIZE, OnTbrushPosterize)
ON_COMMAND(ID_TERRAIN_PROPERTIES, OnTerrainProperties)
//}}AFX_MSG_MAP
ON_COMMAND_RANGE(ID_BUFFER01, ID_BUFFER10, OnKeyBuffer)
ON_COMMAND_RANGE(ID_EDIT_BUFFER01, ID_EDIT_BUFFER10, OnKeyEditBuffer)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CWorldEditorView construction/destruction
CWorldEditorView::CWorldEditorView()
{
m_iaInputAction = IA_NONE;
m_iaLastInputAction=IA_NONE;
m_pbpoTranslationPlane = NULL;
m_vpViewPrefs = theApp.m_vpViewPrefs[ 0];
m_ptProjectionType = CSlaveViewer::PT_PERSPECTIVE;
m_pdpDrawPort = NULL;
m_pvpViewPort = NULL;
m_fGridInMeters = 10.0f;
m_pbpoRightClickedPolygon = NULL;
m_penEntityHitOnContext = NULL;
m_iDragVertice = -1;
m_iDragEdge = -1;
_pselbvxtSelectOnRender = NULL;
_pselenSelectOnRender = NULL;
m_bRequestVtxClickSelect = FALSE;
m_bRequestVtxLassoSelect = FALSE;
m_bRequestEntityLassoSelect = FALSE;
m_strTest="";
}
CWorldEditorView::~CWorldEditorView()
{
}
BOOL CWorldEditorView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
static void GetToolTipText(void *pView, char *pToolTipText)
{
CWorldEditorView *pWorldEditorView = (CWorldEditorView *) pView;
pWorldEditorView->GetToolTipText( pToolTipText);
}
/////////////////////////////////////////////////////////////////////////////
// CWorldEditorView drawing
void CWorldEditorView::RenderBackdropTexture(CDrawPort *pDP,
FLOAT3D v0, FLOAT3D v1, FLOAT3D v2, FLOAT3D v3,
CTextureObject &to)
{
if( to.GetData() == NULL) return;
CWorldEditorDoc* pDoc = GetDocument();
FLOAT3D v0p, v1p, v2p, v3p;
// create a slave viewer
CSlaveViewer svViewer(GetChildFrame()->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid, pDP);
// create a projection for slave viewer
CAnyProjection3D prProjection;
svViewer.MakeProjection(prProjection);
prProjection->Prepare();
// project current base vertice and convert y coordinate from mathemathical representation
// into screen representation
prProjection->ProjectCoordinate( v0, v0p); v0p(2) = pDP->GetHeight() - v0p(2);
prProjection->ProjectCoordinate( v1, v1p); v1p(2) = pDP->GetHeight() - v1p(2);
prProjection->ProjectCoordinate( v2, v2p); v2p(2) = pDP->GetHeight() - v2p(2);
prProjection->ProjectCoordinate( v3, v3p); v3p(2) = pDP->GetHeight() - v3p(2);
FLOATaabbox3D box;
box |= v0p;
box |= v1p;
box |= v2p;
box |= v3p;
if( (box.Size()(1) > 2) && (box.Size()(2) > 2) )
{
// create rectangle for backdrop picture
PIXaabbox2D rectPict;
rectPict = PIXaabbox2D( PIX2D((SLONG)box.Min()(1), (SLONG)box.Min()(2)),
PIX2D((SLONG)box.Max()(1), (SLONG)box.Max()(2)) );
pDP->PutTexture( &to, rectPict);
}
}
BOOL _bCursorMoved=FALSE;
void CWorldEditorView::RenderView( CDrawPort *pDP)
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CChildFrame *pChild = GetChildFrame();
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
// create a slave viewer
CSlaveViewer svViewer(GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pDP);
// copy view's world rendering preferences to global world rendering preferences
_wrpWorldRenderPrefs = m_vpViewPrefs.m_wrpWorldRenderPrefs;
_wrpWorldRenderPrefs.SetTextureLayerOn( theApp.m_bTexture1, 0);
_wrpWorldRenderPrefs.SetTextureLayerOn( theApp.m_bTexture2, 1);
_wrpWorldRenderPrefs.SetTextureLayerOn( theApp.m_bTexture3, 2);
// set shadow type from child frame
_wrpWorldRenderPrefs.SetShadowsType( GetChildFrame()->m_stShadowType);
// copy view's model rendering preferences to global model rendering preferences
_mrpModelRenderPrefs = m_vpViewPrefs.m_mrpModelRenderPrefs;
// copy auto mip modeling flag from child frame
_wrpWorldRenderPrefs.SetAutoMipBrushingOn( GetChildFrame()->m_bAutoMipBrushingOn);
// and manual mip factor
_wrpWorldRenderPrefs.SetManualMipBrushingFactor( GetChildFrame()->m_fManualMipBrushingFactor);
// view visibility tweaking
_wrpWorldRenderPrefs.SetVisTweaksOn(GetChildFrame()->m_bShowVisibilityTweaks);
_wrpWorldRenderPrefs.DisableVisTweaks(GetChildFrame()->m_bDisableVisibilityTweaks);
_pselbscVisTweaks=&pDoc->m_selSectorSelection;
_wrpWorldRenderPrefs.SetSelectedEntityModel( theApp.m_pEntityMarkerModelObject);
_wrpWorldRenderPrefs.SetSelectedPortalModel( theApp.m_pPortalMarkerModelObject);
_wrpWorldRenderPrefs.SetEmptyBrushModel( theApp.m_pEmptyBrushModelObject);
// if we are using automatic rendering range
if( m_vpViewPrefs.m_bAutoRenderingRange)
{
// set rendering range of 1.5 x viewer's target distance
FLOAT fTargetDistance = svViewer.GetTargetDistance();
// we have to take second layer distance in considiration also
FLOAT fMinimumRenderRange = fTargetDistance;
// if second layer's world exists
if( pDoc->m_pwoSecondLayer != NULL)
{
CPlacement3D plViewer = GetChildFrame()->m_mvViewer.GetViewerPlacement();
// calculate viewer-layer distance
FLOAT fViewerLayerDistance =
(plViewer.pl_PositionVector - pDoc->m_plSecondLayer.pl_PositionVector).Length();
// if current minimum rendering range is smaller than one that viewer-layer
// distance would request
if( fMinimumRenderRange < fViewerLayerDistance )
{
fMinimumRenderRange = fViewerLayerDistance;
}
}
// don't allow minimum rendering range to drop below 1.5 m
if( fMinimumRenderRange < 1.5f)
{
fMinimumRenderRange = 1.5f;
}
_wrpWorldRenderPrefs.SetMinimumRenderRange( fMinimumRenderRange * 1.5f);
}
// we are using fixed rendering range
else
{
// set global rendering range from fixed one remembered in prefs
_wrpWorldRenderPrefs.SetMinimumRenderRange( m_vpViewPrefs.m_fRenderingRange);
}
// set visibility of link lines
_wrpWorldRenderPrefs.SetShowTargetsOn(pChild->m_bShowTargets);
// set visibility of entity names
_wrpWorldRenderPrefs.SetShowEntityNamesOn(pChild->m_bShowEntityNames);
// find out if z buffer clearing should occure
BOOL bClearZBuffer = FALSE;
BOOL bClearScreen = TRUE;
// get world and model polygon fill flags
BOOL bModelPolygonFilling =
(_mrpModelRenderPrefs.GetRenderType() & RT_TEXTURE_MASK) != RT_NO_POLYGON_FILL;
// find out if any of isometric projection modes is currently on
BOOL bPerspectiveOn = m_ptProjectionType == CSlaveViewer::PT_PERSPECTIVE;
BOOL bPolygonFillOn = _wrpWorldRenderPrefs.GetPolygonsFillType() != CWorldRenderPrefs::FT_NONE;
// if something requires clearing of z-buffer
if( bPolygonFillOn ||
pDoc->m_bOrientationIcons ||
((!bCSGOn && bPerspectiveOn) && GetChildFrame()->m_bSceneRenderingTime) ||
m_vpViewPrefs.m_bMeasurementTape ||
theApp.m_bMeasureModeOn || theApp.m_bCutModeOn)
{
bClearZBuffer = TRUE;
}
// if we will render models using polygon fill, we must clear z-buffer
if( bModelPolygonFilling)
{
bClearZBuffer = TRUE;
}
// if rendering will fill whole screen along with z-buffer
if( bPolygonFillOn && bPerspectiveOn)
{
bClearZBuffer = FALSE;
bClearScreen = FALSE;
}
COLOR colBcgFill=m_vpViewPrefs.m_PaperColor;
if(_wrpWorldRenderPrefs.IsBackgroundTextureOn())
{
bClearScreen = TRUE;
colBcgFill=pDoc->m_woWorld.wo_colBackground;
}
// set selected entity model
_wrpWorldRenderPrefs.SetSelectedEntityModel( theApp.m_pEntityMarkerModelObject);
// set selected portal model
_wrpWorldRenderPrefs.SetSelectedPortalModel( theApp.m_pPortalMarkerModelObject);
// set empty brush model
_wrpWorldRenderPrefs.SetEmptyBrushModel( theApp.m_pEmptyBrushModelObject);
switch( pDoc->GetEditingMode())
{
case POLYGON_MODE:
{
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_POLYGONS);
break;
}
case SECTOR_MODE:
{
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_SECTORS);
break;
}
case ENTITY_MODE:
{
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_ENTITIES);
break;
}
case VERTEX_MODE:
{
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_VERTICES);
break;
}
case TERRAIN_MODE:
{
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_NONE);
break;
}
case CSG_MODE:
{
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_NONE);
break;
}
default: { FatalError("Unknown editing mode."); break;};
}
// if selection shouldn't be rendered and we are not in vertex mode (selection should always be rendered)
if( !GetChildFrame()->m_bSelectionVisible && (pDoc->GetEditingMode()!= VERTEX_MODE) )
{
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_NONE);
}
// create a projection for slave viewer
CAnyProjection3D prProjection;
svViewer.MakeProjection(prProjection);
// set object placement
prProjection->ObjectPlacementL() = pDoc->m_plGrid;
if( !bPerspectiveOn && !_wrpWorldRenderPrefs.wrp_bApplyFarClipPlaneInIsometricProjection)
{
prProjection->FarClipDistanceL() = -1;
}
else
{
prProjection->FarClipDistanceL() = _wrpWorldRenderPrefs.wrp_fFarClipPlane;
}
// prepare the projection
prProjection->Prepare();
// if screen clearance is required
if( bClearScreen)
{
try
{
m_toBcgPicture.SetData_t(CTString(m_vpViewPrefs.m_achrBcgPicture));
}
// if failed
catch (char *strError)
{
(void) strError;
}
if( m_toBcgPicture.GetData() != NULL)
{
// fill background with bcg picture
PIXaabbox2D screenBox;
screenBox = PIXaabbox2D( PIX2D(0,0), PIX2D(pDP->GetWidth(), pDP->GetHeight()) );
pDP->PutTexture( &m_toBcgPicture, screenBox);
}
else
{
// clear background using current color form rendering preferences
pDP->Fill(colBcgFill | CT_OPAQUE);
}
if( pDoc->m_woWorld.wo_strBackdropUp != "" && GetChildFrame()->m_bRenderViewPictures)
{
FLOAT3D v0 = FLOAT3D(pDoc->m_woWorld.wo_fUpCX-pDoc->m_woWorld.wo_fUpW/2.0f, 0.0f,
pDoc->m_woWorld.wo_fUpCZ-pDoc->m_woWorld.wo_fUpL/2.0f);
FLOAT3D v1 = FLOAT3D(pDoc->m_woWorld.wo_fUpCX+pDoc->m_woWorld.wo_fUpW/2.0f, 0.0f,
pDoc->m_woWorld.wo_fUpCZ-pDoc->m_woWorld.wo_fUpL/2.0f);
FLOAT3D v2 = FLOAT3D(pDoc->m_woWorld.wo_fUpCX+pDoc->m_woWorld.wo_fUpW/2.0f, 0.0f,
pDoc->m_woWorld.wo_fUpCZ+pDoc->m_woWorld.wo_fUpL/2.0f);
FLOAT3D v3 = FLOAT3D(pDoc->m_woWorld.wo_fUpCX-pDoc->m_woWorld.wo_fUpW/2.0f, 0.0f,
pDoc->m_woWorld.wo_fUpCZ+pDoc->m_woWorld.wo_fUpL/2.0f);
RenderBackdropTexture( pDP, v0, v1, v2, v3, pDoc->m_toBackdropUp);
}
if( pDoc->m_woWorld.wo_strBackdropFt != "" && GetChildFrame()->m_bRenderViewPictures)
{
FLOAT3D v0 = FLOAT3D(pDoc->m_woWorld.wo_fFtCX-pDoc->m_woWorld.wo_fFtW/2.0f,
pDoc->m_woWorld.wo_fFtCY-pDoc->m_woWorld.wo_fFtH/2.0f, 0.0f);
FLOAT3D v1 = FLOAT3D(pDoc->m_woWorld.wo_fFtCX+pDoc->m_woWorld.wo_fFtW/2.0f,
pDoc->m_woWorld.wo_fFtCY-pDoc->m_woWorld.wo_fFtH/2.0f, 0.0f);
FLOAT3D v2 = FLOAT3D(pDoc->m_woWorld.wo_fFtCX+pDoc->m_woWorld.wo_fFtW/2.0f,
pDoc->m_woWorld.wo_fFtCY+pDoc->m_woWorld.wo_fFtH/2.0f, 0.0f);
FLOAT3D v3 = FLOAT3D(pDoc->m_woWorld.wo_fFtCX-pDoc->m_woWorld.wo_fFtW/2.0f,
pDoc->m_woWorld.wo_fFtCY+pDoc->m_woWorld.wo_fFtH/2.0f, 0.0f);
RenderBackdropTexture( pDP, v0, v1, v2, v3, pDoc->m_toBackdropFt);
}
if( pDoc->m_woWorld.wo_strBackdropRt != "" && GetChildFrame()->m_bRenderViewPictures)
{
FLOAT3D v0 = FLOAT3D(0.0f, pDoc->m_woWorld.wo_fRtCY-pDoc->m_woWorld.wo_fRtH/2.0f,
pDoc->m_woWorld.wo_fRtCZ-pDoc->m_woWorld.wo_fRtL/2.0f);
FLOAT3D v1 = FLOAT3D(0.0f, pDoc->m_woWorld.wo_fRtCY+pDoc->m_woWorld.wo_fRtH/2.0f,
pDoc->m_woWorld.wo_fRtCZ-pDoc->m_woWorld.wo_fRtL/2.0f);
FLOAT3D v2 = FLOAT3D(0.0f, pDoc->m_woWorld.wo_fRtCY+pDoc->m_woWorld.wo_fRtH/2.0f,
pDoc->m_woWorld.wo_fRtCZ+pDoc->m_woWorld.wo_fRtL/2.0f);
FLOAT3D v3 = FLOAT3D(0.0f, pDoc->m_woWorld.wo_fRtCY-pDoc->m_woWorld.wo_fRtH/2.0f,
pDoc->m_woWorld.wo_fRtCZ+pDoc->m_woWorld.wo_fRtL/2.0f);
RenderBackdropTexture( pDP, v0, v1, v2, v3, pDoc->m_toBackdropRt);
}
// if object should me rendered as backdrop
if( GetChildFrame()->m_bRenderViewPictures)
{
CObject3D &ob = pDoc->m_o3dBackdropObject;
FOREACHINDYNAMICARRAY(ob.ob_aoscSectors, CObjectSector, itosc)
{
FOREACHINDYNAMICARRAY(itosc->osc_aoedEdges, CObjectEdge, itoe)
{
FLOAT3D vtx0 = DOUBLEtoFLOAT(*itoe->oed_Vertex0);
FLOAT3D vtx1 = DOUBLEtoFLOAT(*itoe->oed_Vertex1);
prProjection->PreClip( vtx0, vtx0);
prProjection->PreClip( vtx1, vtx1);
prProjection->ClipLine(vtx0, vtx1);
// apply perspective
FLOAT3D vtx0p, vtx1p;
prProjection->PostClip( vtx0, vtx0p);
prProjection->PostClip( vtx1, vtx1p);
// draw one line of bounding box
pDP->DrawLine( (PIX)vtx0p(1), (PIX)vtx0p(2), (PIX)vtx1p(1), (PIX)vtx1p(2),
C_dGRAY|CT_OPAQUE);
}
}
}
}
// if z-buffer clearance is required
if( bClearZBuffer)
{
// erase z-buffer
pDP->FillZBuffer(ZBUF_BACK);
}
FLOAT3D fGridOrigin;
// project grid origin
prProjection->ProjectCoordinate( FLOAT3D( 0.0f, 0.0f, 0.0f), fGridOrigin);
// convert y coordinate form mathematical form info screen space
fGridOrigin(2) = pDP->GetHeight() - fGridOrigin(2);
// calculate grid in pixels but there must be bigger than given minimal size
#define SMALLEST_ALLOWED_GRID_IN_PIXELS 30
// get zoom factor
FLOAT fZoom = svViewer.GetZoomFactor();
// declare decadic grid in meters
FLOAT afDecadicGridInMeters[] = {0.25f,0.50f,1.0f,2.5f,5.0f,10.0f,25.0f,50.0f,100.0f,
250.0f,500.0f,1000.0f,10000.0f,100000.0f};
FLOAT afBinaryGridInMeters[] = {0.25f,0.50f,1.0f,2.0f,4.0f,8.0f,16.0f,32.0f,64.0f,128.0f,256.0f,
512.0f,1024.0f,2048.0f,4096.0f,8192.0f,16384.0f,32768.0f,65536.0f};
// select max grid value
if( theApp.m_bDecadicGrid)
{
m_fGridInMeters = afDecadicGridInMeters[ sizeof( afDecadicGridInMeters)/sizeof(FLOAT)-1];
}
else
{
m_fGridInMeters = afBinaryGridInMeters[ sizeof( afBinaryGridInMeters)/sizeof(FLOAT)-1];
}
// ptr to curently active grid table
FLOAT *pafGridInMeters;
INDEX ctTableMembers;
// select active table
if( theApp.m_bDecadicGrid)
{
pafGridInMeters = afDecadicGridInMeters;
ctTableMembers = sizeof( afDecadicGridInMeters)/sizeof(FLOAT);
}
else
{
pafGridInMeters = afBinaryGridInMeters;
ctTableMembers = sizeof( afBinaryGridInMeters)/sizeof(FLOAT);
}
// for all members in precalculated grid in meters array
for( INDEX i=0; i<ctTableMembers; i++)
{
// calculate grid steep
m_fpixGridSteep = fZoom * pafGridInMeters[ i];
// is it bigger than smallest allowed grid size in pixels
if( m_fpixGridSteep >= SMALLEST_ALLOWED_GRID_IN_PIXELS)
{
m_fGridInMeters = pafGridInMeters[ i];
break;
}
}
// we have calculated wanted grid in pixels, value is stored in pixGridSteep
// if grid on, draw it
if( GetChildFrame()->m_bGridOn && !bPerspectiveOn && !bPolygonFillOn)
{
// get grid's origin projected point
FLOAT fGridOriginX = fGridOrigin(1);
FLOAT fGridOriginY = fGridOrigin(2);
// calculate starting coordinates of left-up grid line
FLOAT fGridX = fGridOriginX - (m_fpixGridSteep * (int)(fGridOriginX / m_fpixGridSteep));
FLOAT fGridY = fGridOriginY - (m_fpixGridSteep * (int)(fGridOriginY / m_fpixGridSteep));
// remember these start grid values so they can be used for measurement
m_fGridX = fGridX;
m_fGridY = fGridY;
// style of grid line
ULONG ulLineStyle;
// loop all vertical grid lines
#define LINE_EPSILON 0.05f
FOREVER
{
// does this grid lines touch origin point
if( Abs(fGridX - fGridOriginX) < LINE_EPSILON )
{
// if so, draw full line
ulLineStyle = _FULL_;
}
else
{
// does not, draw point line
ulLineStyle = _POINT_;
}
// draw one vertical grid line
pDP->DrawLine( (int) fGridX, 0, (int) fGridX, pDP->GetHeight()-1,
m_vpViewPrefs.m_GridColor|CT_OPAQUE, ulLineStyle);
// move to next grid line
fGridX += m_fpixGridSteep;
// is coordinate passed draw port's width
if( fGridX > pDP->GetWidth())
{
// if so, vertical grid is drawn, stop endless loop
break;
}
}
// loop all horizontal grid lines
FOREVER
{
// does this grid lines touch origin point
if( Abs(fGridY - fGridOriginY) < LINE_EPSILON )
{
// if so, draw full line
ulLineStyle = _FULL_;
}
else
{
// does not, draw point line
ulLineStyle = _POINT_;
}
// draw one vertical grid line
pDP->DrawLine( 0, (int) fGridY, pDP->GetWidth()-1, (int) fGridY,
m_vpViewPrefs.m_GridColor|CT_OPAQUE, ulLineStyle);
// move to next grid line
fGridY += m_fpixGridSteep;
// is coordinate passed draw port's height
if( fGridY > pDP->GetHeight())
{
// if so, vertical grid is drawn, stop endless loop
break;
}
}
}
// if we should draw measurement tape
if( m_vpViewPrefs.m_bMeasurementTape && !bPerspectiveOn)
{
// define tape in meters for decadic grid type
FLOAT afDecadicTapeInMeters[] =
{ 0.01f, 0.1f, 1.0f, 10.0f, 100.0f, 1000.0f, 10000.0f, 100000.0f};
CTString astrDecadicTapeInMeters[] =
{ "1 mm", "1 cm", "1 m", "10 m", "100 m", "1 km", "10 km", "100 km"};
// define tape in meters for binary grid type
FLOAT afBinaryTapeInMeters[] =
{ 1.0f/64, 1.0f/8, 1.0f, 8.0f, 64.0f, 256.0f, 1024.0f, 4096.0f, 16484.0f, 65536.0f};
CTString astrBinaryTapeInMeters[] =
{ "1/64 m", "1/8 m", "1 m", "8 m", "64 m", "256 m", "1024 m", "4096 m", "16384 m", "65536 m"};
CTString *pastrTapeInMetersTable;
FLOAT *pafTapeInMetersTable;
INDEX ctTableMembers;
// select active table
if( theApp.m_bDecadicGrid)
{
pafTapeInMetersTable = afDecadicTapeInMeters;
pastrTapeInMetersTable = astrDecadicTapeInMeters;
ctTableMembers = sizeof( afDecadicTapeInMeters)/sizeof(FLOAT);
}
else
{
pafTapeInMetersTable = afBinaryTapeInMeters;
pastrTapeInMetersTable = astrBinaryTapeInMeters;
ctTableMembers = sizeof( afBinaryTapeInMeters)/sizeof(FLOAT);
}
// here we will calculate our tape lenght in meters
FLOAT fTapeLenMeters;
// here we will calculate our tape lenght in pixels
PIX pixTapeLen;
// here we will place appropriate text saying tape's lenght in meters
CTString strTapeLen;
// for all possible dimensions of measurement tape
for( INDEX i=ctTableMembers-1; i>=0; i--)
{
// get tape len in meters
fTapeLenMeters = pafTapeInMetersTable[ i];
// get appropriate descriptive string
strTapeLen = pastrTapeInMetersTable[ i];
// calculate tape in pixels
pixTapeLen = (PIX)(fZoom * fTapeLenMeters);
// is it smaller than 75% of draw port's width
if( pixTapeLen <= pDP->GetWidth()*3/4)
{
// it is, we found our tape dimension
break;
}
}
// calculate tape position on screen
PIX x = (PIX) ( pDP->GetWidth() * 0.05f); // x starts at 5% of draw port's width
PIX y = (PIX) ( pDP->GetHeight()* 0.95f); // y starts at 95% of draw port's height
// draw tape's left end, little vertical line
pDP->DrawLine( x, y-2, x, y+2, C_BLACK|CT_OPAQUE);
// draw tape's main, horizontal little
pDP->DrawLine( x, y, x+pixTapeLen, y, C_BLACK|CT_OPAQUE);
// draw tape's right end, little vertical line
pDP->DrawLine( x+pixTapeLen, y-2, x+pixTapeLen, y+2, C_BLACK|CT_OPAQUE);
// type appropriate text, lenght in meters
pDP->SetFont( theApp.m_pfntSystem);
pDP->SetTextAspect( 1.0f);
pDP->SetTextScaling( 1.0f);
pDP->PutText( strTapeLen, x, y-16);
}
// we are not rendering scene over already rendered scene (used for CSG layer)
pDP->SetOverlappedRendering(FALSE);
// print grid size (or no grid)
char strPaneText[ 128];
sprintf( strPaneText, "Grid: %g m", m_fGridInMeters);
pMainFrame->m_wndStatusBar.SetPaneText( GRID_PANE, CString(strPaneText), TRUE);
// create renderer and render world
CEntity *penOnlySelected = NULL;
if( pDoc->m_selEntitySelection.Count() == 1)
{
pDoc->m_selEntitySelection.Lock();
penOnlySelected = &pDoc->m_selEntitySelection[0];
pDoc->m_selEntitySelection.Unlock();
}
// request vertex selecting from renderer
if( m_bRequestVtxClickSelect)
{
_bSelectAlternative = m_bOnSelectVertexShiftDown;
_pselbvxtSelectOnRender = &pDoc->m_selVertexSelection;
}
if( m_bRequestVtxLassoSelect)
{
_bSelectAlternative = m_bOnSelectVertexAltDown;
_pselbvxtSelectOnRender = &pDoc->m_selVertexSelection;
_pavpixSelectLasso = &m_avpixLaso;
}
if( m_bRequestEntityLassoSelect)
{
_bSelectAlternative = m_bOnSelectEntityAltDown;
_pselenSelectOnRender = &pDoc->m_selEntitySelection;
_pavpixSelectLasso = &m_avpixLaso;
}
if(pDoc->GetEditingMode()==TERRAIN_MODE &&
theApp.m_penLastTerrainHit==GetTerrainEntity() &&
!_pInput->IsInputEnabled())
{
RenderAndApplyTerrainEditBrush(theApp.m_vLastTerrainHit);
}
if( GetChildFrame()->m_bViewFromEntity &&
(penOnlySelected != NULL) &&
!(penOnlySelected->GetFlags()&ENF_ANCHORED) &&
bPerspectiveOn )
{
// create a projection for slave viewer
CAnyProjection3D prProjection;
svViewer.MakeProjection(prProjection);
prProjection->ViewerPlacementL() = penOnlySelected->GetPlacement();
prProjection->Prepare();
::RenderView(pDoc->m_woWorld, *penOnlySelected, prProjection, *pDP);
}
else
{
// create renderer and render world
::RenderView(pDoc->m_woWorld, *(CEntity*) NULL, prProjection, *pDP);
}
// don't allow further laso select tests
if( m_bRequestVtxLassoSelect || m_bRequestEntityLassoSelect)
{
m_avpixLaso.Clear();
}
_pselbvxtSelectOnRender = NULL;
_pselenSelectOnRender = NULL;
m_bRequestVtxClickSelect = FALSE;
m_bRequestVtxLassoSelect = FALSE;
m_bRequestEntityLassoSelect = FALSE;
_pavpixSelectLasso = NULL;
INDEX ctLasoPts = m_avpixLaso.Count();
if(((m_iaInputAction == IA_SELECT_LASSO_BRUSH_VERTEX) ||
(m_iaInputAction == IA_SELECT_LASSO_ENTITY)) && (ctLasoPts>1) )
{
for( INDEX iKnot=0; iKnot<ctLasoPts-1; iKnot++)
{
PIX x0 = m_avpixLaso[iKnot](1);
PIX x1 = m_avpixLaso[iKnot+1](1);
PIX y0 = m_avpixLaso[iKnot](2);
PIX y1 = m_avpixLaso[iKnot+1](2);
pDP->DrawLine(x0, y0, x1, y1, m_vpViewPrefs.m_GridColor|CT_OPAQUE);
}
}
prProjection->DepthBufferNearL() = 0.0f;
prProjection->DepthBufferFarL() = 0.9f;
prProjection->Prepare();
BeginModelRenderingView(prProjection, pDP);
// if we have entity mode active, at least one entity selected and edititng property of
// edit range type, and perspective is not on, render entities using rendering range model
CPropertyID *ppidProperty = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
if( (pDoc->GetEditingMode() == ENTITY_MODE) &&
(pDoc->m_selEntitySelection.Count() != 0) &&
(ppidProperty != NULL) &&
( (ppidProperty->pid_eptType == CEntityProperty::EPT_ANGLE3D) ||
(ppidProperty->pid_eptType == CEntityProperty::EPT_RANGE) ||
(ppidProperty->pid_eptType == CEntityProperty::EPT_FLOATAABBOX3D && !bPerspectiveOn)) )
{
// for all selected entities
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
// obtain property ptr
CEntityProperty *penpProperty = iten->PropertyForName( ppidProperty->pid_strName);
// if this entity is just selected, it may not have range property but that was not
// noticed (it will be during first on idle), so skip it
if( penpProperty==NULL)
{
continue;
}
// if we are in perspective and entity property is marked not to be visible in perspective view
if( (penpProperty->ep_ulFlags & EPROPF_HIDEINPERSPECTIVE) && bPerspectiveOn)
{
continue;
}
// this model we will render
CModelObject *pModelObject;
// this render model structure will be rendered
CRenderModel rmRenderModel;
// if we are editing range property
if( ppidProperty->pid_eptType == CEntityProperty::EPT_RANGE)
{
// get editing range
FLOAT fRange = ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, FLOAT);
// set collision box's stretch factor
theApp.m_pRangeSphereModelObject->mo_Stretch = FLOAT3D( fRange, fRange, fRange);
// set texture rendering mode and phong shading
//_mrpModelRenderPrefs.SetRenderType( RT_TEXTURE|RT_SHADING_PHONG);
// copy range model's placement from entity
rmRenderModel.SetObjectPlacement(iten->GetPlacement());
// set range sphere model for rendering
pModelObject = theApp.m_pRangeSphereModelObject;
}
// if we are editing angle3D property
else if( ppidProperty->pid_eptType == CEntityProperty::EPT_ANGLE3D)
{
// get editting bounding box
ANGLE3D aAngle = ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, ANGLE3D);
rmRenderModel.SetObjectPlacement(
CPlacement3D(iten->GetPlacement().pl_PositionVector, aAngle));
// set angle3d vector's stretch factor
FLOATaabbox3D box;
iten->GetSize(box);
FLOAT fStretch = box.Size().Length();
theApp.m_pAngle3DModelObject->mo_Stretch = FLOAT3D( fStretch, fStretch, fStretch);
// set angle3d model for rendering
pModelObject = theApp.m_pAngle3DModelObject;
}
else
{
// get editting bounding box
FLOATaabbox3D bbox = ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, FLOATaabbox3D);
// reset orientation (axes alligned bounding box !!!)
rmRenderModel.SetObjectPlacement(
CPlacement3D(iten->GetPlacement().pl_PositionVector + bbox.Min(),
ANGLE3D( 0, 0, 0)));
// set collision box's stretch factor
theApp.m_pBoundingBoxModelObject->mo_Stretch = bbox.Size();
// render black wire frame allways
_mrpModelRenderPrefs.SetWire( TRUE);
_mrpModelRenderPrefs.SetInkColor( C_BLACK);
// set bounding box model for rendering
pModelObject = theApp.m_pBoundingBoxModelObject;
}
// set light placement
rmRenderModel.rm_vLightDirection = FLOAT3D(1.0f, -1.0f, 1.0f);
// set color of light
rmRenderModel.rm_colLight= C_WHITE;
rmRenderModel.rm_colAmbient = C_GRAY;
// render range sphere model
pModelObject->SetupModelRendering(rmRenderModel);
pModelObject->RenderModel(rmRenderModel);
}
}
// if we should render volume box model
if( pDoc->m_bBrowseEntitiesMode)
{
// this model we will render
CModelObject *pModelObject;
// this render model structure will be rendered
CRenderModel rmRenderModel;
// create bbox from requested volume
FLOATaabbox3D bboxVolume( pDoc->m_vCreateBoxVertice0, pDoc->m_vCreateBoxVertice1);
// position it inside box
rmRenderModel.SetObjectPlacement(CPlacement3D(bboxVolume.Min(), ANGLE3D( 0, 0, 0)));
// set collision box's stretch factor
theApp.m_pBoundingBoxModelObject->mo_Stretch = bboxVolume.Size();
// render black wire frame allways
_mrpModelRenderPrefs.SetWire( TRUE);
_mrpModelRenderPrefs.SetHiddenLines( TRUE);
_mrpModelRenderPrefs.SetInkColor( C_BLACK);
// set bounding box model for rendering
pModelObject = theApp.m_pBoundingBoxModelObject;
// set light placement
rmRenderModel.rm_vLightDirection = FLOAT3D(1.0f, -1.0f, 1.0f);
// set color of light
rmRenderModel.rm_colLight= C_WHITE;
rmRenderModel.rm_colAmbient = C_GRAY;
// render bounding volume model
pModelObject->SetupModelRendering(rmRenderModel);
pModelObject->RenderModel(rmRenderModel);
}
EndModelRenderingView();
// if we should draw orientation icon, do it now because latter we may
// have problems due to automatic InitRenderer (in that case we would try
// to render icons on second layer's DrawPort, last locked, but it is allready
// destructed)
if( pDoc->m_bOrientationIcons)
{
#define XS 10
#define YS 16
#define DX 32
#define DY 32
PIXaabbox2D boxScreen(PIX2D(XS, YS), PIX2D(XS+DX, YS+DY));
// choose view's orientation icon index
INDEX iIcon = 0;
CTString strView="None";
CTString strU="?";
CTString strV="?";
switch( m_ptProjectionType)
{
case CSlaveViewer::PT_PERSPECTIVE: { iIcon = 0; strView="persp"; strU=""; strV=""; break;}
case CSlaveViewer::PT_ISOMETRIC_FRONT: { iIcon = 5; strView="front"; strU="x"; strV="y"; break;}
case CSlaveViewer::PT_ISOMETRIC_RIGHT: { iIcon = 3; strView="right"; strU="-z"; strV="y"; break;}
case CSlaveViewer::PT_ISOMETRIC_TOP: { iIcon = 1; strView="top"; strU="x"; strV="-z"; break;}
case CSlaveViewer::PT_ISOMETRIC_BACK: { iIcon = 6; strView="back"; strU="-x"; strV="y"; break;}
case CSlaveViewer::PT_ISOMETRIC_LEFT: { iIcon = 4; strView="left"; strU="z"; strV="y"; break;}
case CSlaveViewer::PT_ISOMETRIC_BOTTOM: { iIcon = 2; strView="bottom"; strU="x"; strV="z"; break;}
}
MEXaabbox2D boxTexture(MEX2D(iIcon*DX, 0), MEX2D((iIcon+1)*DX, DY));
// render icon
CTextureObject toIcon;
toIcon.SetData( theApp.m_pViewIconsTD);
pDP->PutTexture(&toIcon, boxScreen, boxTexture);
PIX2D pixCenter=PIX2D( pDP->GetWidth()*0.03f, pDP->GetHeight()*0.97f);
DrawAxis( pixCenter, 40, C_BLUE|CT_OPAQUE, C_RED|CT_OPAQUE, strU, strV);
pDP->SetFont( _pfdConsoleFont);
pDP->SetTextAspect( 1.0f);
pDP->SetTextScaling( 1.0f);
pDP->PutTextCXY( strView, XS+DX/2, YS/2, C_RED|CT_OPAQUE);
}
pDP->BlendScreen();
// if second layer's world exists
if( pDoc->m_pwoSecondLayer != NULL)
{
// prepare second layer's projection ...
// get viewer placement from first layer
CPlacement3D plVirtualViewer = prProjection->ViewerPlacementR();
// transform it to the system of the second layer
plVirtualViewer.AbsoluteToRelative(pDoc->m_plSecondLayer);
// use it in projection for second layer
CAnyProjection3D prProjectionSecondLayer;
prProjectionSecondLayer = prProjection;
prProjectionSecondLayer->ViewerPlacementL() = plVirtualViewer;
prProjectionSecondLayer->Prepare();
// if we will not use any kind of polygon filling
if( !bPolygonFillOn)
{
// render scene directly into primary draw port
::RenderView( *pDoc->m_pwoSecondLayer, *(CEntity*) NULL,
prProjectionSecondLayer, *pDP);
}
// if filling, create drawport for second layer and create picture using CopyViaZBuffer
else
{
// disable shadow rendering on world in second layer
_wrpWorldRenderPrefs.SetShadowsType( CWorldRenderPrefs::SHT_NONE);
// set that we will rendering scene over allready rendered scene
pDP->SetOverlappedRendering(TRUE);
// render second layer's scene over already rendered scene using filled z-buffer
::RenderView( *pDoc->m_pwoSecondLayer, *(CEntity*) NULL, prProjectionSecondLayer, *pDP);
}
// if we are in triangularisation primitive mode
if( (pDoc->m_bPrimitiveMode) &&
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) )
{
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Lock();
CDynamicArray<CObjectVertex> &aVtx = theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors[0].osc_aovxVertices;
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Unlock();
aVtx.Lock();
// render all selected vertices as boxes
for( INDEX iVtx=0; iVtx<aVtx.Count(); iVtx++)
{
if( aVtx[ iVtx].ovx_ulFlags & OVXF_SELECTED)
{
FLOAT3D vProjected;
// project vertice
prProjectionSecondLayer->ProjectCoordinate( DOUBLEtoFLOAT(aVtx[ iVtx]), vProjected);
// convert y coordinate from mathemathical representation into screen one
vProjected(2) = pDP->GetHeight() - vProjected(2);
pDP->Fill( (SLONG)vProjected(1)-3, (SLONG)vProjected(2)-3, 6, 6, C_BLACK|CT_OPAQUE);
}
}
aVtx.Unlock();
}
}
// if cut mode on, this isn't perspective view, and cut line modification has been performed on this view
if( theApp.m_bCutModeOn && !bPerspectiveOn && ( pDoc->m_pCutLineView == this))
{
// render cut line
FLOAT3D v0 = pDoc->m_vCutLineStart;
FLOAT3D v1 = pDoc->m_vCutLineEnd;
FLOAT3D vp0;
FLOAT3D vp1;
// create a projection for current viewer
CAnyProjection3D prProjection;
svViewer.MakeProjection(prProjection);
prProjection->Prepare();
prProjection->ProjectCoordinate( v0, vp0);
prProjection->ProjectCoordinate( v1, vp1);
// convert y coordinates into view space
vp0(2) = pDP->GetHeight()-vp0(2);
vp1(2) = pDP->GetHeight()-vp1(2);
PIX x1 = (PIX)vp0(1);
PIX y1 = (PIX)vp0(2);
PIX x2 = (PIX)vp1(1);
PIX y2 = (PIX)vp1(2);
// spread cut line (using parametric line representation) to edges of the draw port
FLOAT dx = x2-x1;
FLOAT dy = y2-y1;
FLOAT fT[4];
fT[0] = (0-x1)/dx;
fT[1] = (pDP->GetWidth()-x1)/dx;
fT[2] = (0-y1)/dy;
fT[3] = (pDP->GetHeight()-y1)/dy;
// find smallest T greater than 0 and biggest T less than 0
FLOAT fMaxNegT = -9999999.0f;
FLOAT fMinPosT = 9999999.0f;
for( INDEX iT=0; iT<4; iT++)
{
if(fT[iT]>1)
{
if(fT[iT]<fMinPosT)
{
fMinPosT = fT[iT];
}
}
else if(fT[iT]<0)
{
if(fT[iT]>fMaxNegT)
{
fMaxNegT = fT[iT];
}
}
}
// calculate border coordinates for found two T values
PIX xb1 = (PIX) x1+dx*fMaxNegT;
PIX xb2 = (PIX) x1+dx*fMinPosT;
PIX yb1 = (PIX) y1+dy*fMaxNegT;
PIX yb2 = (PIX) y1+dy*fMinPosT;
// draw cut line
COLOR colCutBorderLine = C_RED|CT_OPAQUE;
pDP->DrawLine( xb1, yb1, xb2, yb2, colCutBorderLine, _TY124_);
// draw control point lines
COLOR colControl = C_BLACK|CT_OPAQUE;
pDP->DrawLine( x1-3, y1-3, x1+3, y1+3, colControl);
pDP->DrawLine( x1+3, y1-3, x1-3, y1+3, colControl);
pDP->DrawLine( x2-3, y2-3, x2+3, y2+3, colControl);
pDP->DrawLine( x2+3, y2-3, x2-3, y2+3, colControl);
}
// if measure mode on
if( m_iaInputAction == IA_MEASURING)
{
// calculate placement for mouse down
CPlacement3D plMouseDown;
// obtain information about where mouse pointed into the world in the moment of mouse down
CCastRay crRayHit = GetMouseHitInformation( m_ptMouseDown);
plMouseDown.pl_PositionVector = crRayHit.cr_vHit;
pDoc->SnapToGrid( plMouseDown, m_fGridInMeters/GRID_DISCRETE_VALUES);
// calculate placement for current mouse position
CPlacement3D plCurrentMousePos;
// obtain information about where mouse points into the world right now
crRayHit = GetMouseHitInformation( m_ptMouse);
plCurrentMousePos.pl_PositionVector = crRayHit.cr_vHit;
// snap to grid curent mouse placement
pDoc->SnapToGrid( plCurrentMousePos, m_fGridInMeters/GRID_DISCRETE_VALUES);
// construct bbox containing both points
FLOATaabbox3D bbox( plMouseDown.pl_PositionVector);
bbox |= FLOATaabbox3D( plCurrentMousePos.pl_PositionVector);
FLOAT3D vCenter = plMouseDown.pl_PositionVector;
FLOAT3D vUp = plMouseDown.pl_PositionVector;
FLOAT3D vRight = plMouseDown.pl_PositionVector;
FLOAT3D vForward = plMouseDown.pl_PositionVector;
vUp(2) = plCurrentMousePos.pl_PositionVector(2);
vRight(1) = plCurrentMousePos.pl_PositionVector(1);
vForward(3) = plCurrentMousePos.pl_PositionVector(3);
// prepare font
pDP->SetFont( theApp.m_pfntSystem);
pDP->SetTextAspect( 1.0f);
pDP->SetTextScaling( 1.0f);
CTString strText;
strText.PrintF( "%g", bbox.Size()(1));
DrawArrowAndTypeText( *prProjection, vCenter, vRight, C_BLUE|CT_OPAQUE, strText);
strText.PrintF( "%g", bbox.Size()(2));
DrawArrowAndTypeText( *prProjection, vCenter, vUp, C_BLUE|CT_OPAQUE, strText);
strText.PrintF( "%g", bbox.Size()(3));
DrawArrowAndTypeText( *prProjection, vCenter, vForward, C_BLUE|CT_OPAQUE, strText);
// in orto projections, draw diagonal line
if( m_ptProjectionType != CSlaveViewer::PT_PERSPECTIVE)
{
//strText.PrintF( "%g", bbox.Size().Length());
DrawArrowAndTypeText( *prProjection,
plMouseDown.pl_PositionVector,
plCurrentMousePos.pl_PositionVector, C_lGRAY|CT_OPAQUE, "");
}
m_strMeasuring.PrintF( "Distance: %g", bbox.Size().Length());
}
// test string
if( m_strTest!="")
{
pDP->SetFont( theApp.m_pfntSystem);
pDP->SetTextScaling( 1.0f);
pDP->SetTextAspect( 1.0f);
pDP->PutText( m_strTest, 32, 32);
}
}
static TIME tmSwapBuffers = 0;
extern BOOL _bInOnDraw = FALSE;
void CWorldEditorView::OnDraw(CDC* pDC)
{
// skip if already drawing
if( _bInOnDraw) return;
_bInOnDraw = TRUE;
// get some view variables
CWorldEditorDoc* pDoc = GetDocument();
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
BOOL bPerspectiveOn = m_ptProjectionType == CSlaveViewer::PT_PERSPECTIVE;
CDrawPort *pdpValidDrawPort = GetDrawPort();
CViewPort *pvpValidViewPort = GetViewPort();
// if there is a valid drawport, and the drawport can be locked
if( pdpValidDrawPort!=NULL && pdpValidDrawPort->Lock())
{
// variable to recive start time
CTimerValue tvStart = _pTimer->GetHighPrecisionTimer();
// render view
RenderView( pdpValidDrawPort);
// obtain stop time
CTimerValue tvStop = _pTimer->GetHighPrecisionTimer();
// number telling how many miliseconds passed
TIME tmDelta = (tvStop-tvStart).GetSeconds() +tmSwapBuffers;
// mark that view has been changed
m_chViewChanged.MarkChanged();
// if we can and should print any kind of frame rate descriptive message
if( !bCSGOn && bPerspectiveOn && GetChildFrame()->m_bSceneRenderingTime)
{
// prepare string about things that impact to currently rendered picture
CTString strFPS, strReport;
STAT_Report(strReport);
STAT_Reset();
// adjust and set font
pdpValidDrawPort->SetFont( _pfdConsoleFont);
pdpValidDrawPort->SetTextScaling( 1.0f);
// put filter
PIX pixDPHeight = pdpValidDrawPort->GetHeight();
pdpValidDrawPort->Fill( 0,0, 150,pixDPHeight, C_BLACK|128, C_BLACK|0, C_BLACK|192, C_BLACK|0);
// printout statistics
strFPS.PrintF( " %3.0f FPS (%2.0f ms)\n----------------\n", 1.0f/tmDelta, tmDelta*1000.0f);
pdpValidDrawPort->PutText( strFPS, 0, 5, C_lCYAN|CT_OPAQUE);
pdpValidDrawPort->PutText( strReport, 4, 30, C_GREEN|CT_OPAQUE);
}
// unlock the drawport
pdpValidDrawPort->Unlock();
// swap if there is a valid viewport
if( pvpValidViewPort!=NULL) {
tvStart = _pTimer->GetHighPrecisionTimer();
pvpValidViewPort->SwapBuffers();
tvStop = _pTimer->GetHighPrecisionTimer();
tmSwapBuffers = (tvStop-tvStart).GetSeconds();
}
}
// all done
_bInOnDraw = FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CWorldEditorView diagnostics
#ifdef _DEBUG
void CWorldEditorView::AssertValid() const
{
CView::AssertValid();
}
void CWorldEditorView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CWorldEditorDoc* CWorldEditorView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CWorldEditorDoc)));
return (CWorldEditorDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CWorldEditorView message handlers
void CWorldEditorView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// allow file drop
DragAcceptFiles();
// at this time, m_hWnd is valid, so we do canvas initialization here
_pGfx->CreateWindowCanvas(m_hWnd, &m_pvpViewPort, &m_pdpDrawPort);
// get active view
CWorldEditorView *pWorldEditorView = theApp.GetActiveView();
if( (pWorldEditorView != NULL) && (pWorldEditorView != this)
&& (theApp.m_Preferences.ap_CopyExistingWindowPrefs) )
{
m_IsWinBcgTexture = pWorldEditorView->m_IsWinBcgTexture;
m_fnWinBcgTexture = pWorldEditorView->m_fnWinBcgTexture;
m_SelectionColor = pWorldEditorView->m_SelectionColor;
m_PaperColor = pWorldEditorView->m_PaperColor;
m_InkColor = pWorldEditorView->m_InkColor;
CChildFrame *pcfThis = GetChildFrame();
CChildFrame *pcfOld = pWorldEditorView->GetChildFrame();
if( pcfThis != pcfOld)
{
pcfThis->m_mvViewer = pcfOld->m_mvViewer;
}
}
else
{
m_IsWinBcgTexture = FALSE;
m_SelectionColor = theApp.m_Preferences.ap_DefaultSelectionColor;
m_PaperColor = theApp.m_Preferences.ap_DefaultPaperColor;
m_InkColor = theApp.m_Preferences.ap_DefaultInkColor;
}
if( theApp.m_Preferences.ap_SetDefaultColors)
{
m_SelectionColor = CLRF_CLR( theApp.m_Preferences.ap_DefaultSelectionColor);
m_PaperColor = CLRF_CLR( theApp.m_Preferences.ap_DefaultPaperColor);
m_InkColor = CLRF_CLR( theApp.m_Preferences.ap_DefaultInkColor);
}
}
void CWorldEditorView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// if we are not in game mode and changing of display mode is not on
if( !theApp.m_bChangeDisplayModeInProgress)
{ // and window canvas is valid
if( m_pvpViewPort!=NULL)
{ // resize it
m_pvpViewPort->Resize();
}
}
}
int CWorldEditorView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// register drop target
m_DropTarget.Register(this);
return 0;
}
/*
* Get the pointer to the main frame object of this application
*/
CMainFrame *CWorldEditorView::GetMainFrame()
{
// get the MDIChildFrame of this window
CChildFrame *pfrChild = (CChildFrame *)this->GetParentFrame();
ASSERT(pfrChild!=NULL);
// get the MDIFrameWnd
CMainFrame *pfrMain = (CMainFrame *)pfrChild->GetParentFrame();
ASSERT(pfrMain!=NULL);
return pfrMain;
}
void CWorldEditorView::OnKillFocus(CWnd* pNewWnd)
{
m_iaInputAction = IA_NONE;
// discard laso selection
m_avpixLaso.Clear();
CView::OnKillFocus(pNewWnd);
}
void CWorldEditorView::OnActivateView(BOOL bActivate,
CView* pActivateView, CView* pDeactiveView)
{
// if new view's document is not same as last activated document and if document is
// beiing activated
if( (pActivateView != NULL) &&
(pActivateView->GetDocument() != theApp.GetLastActivatedDocument()) &&
(bActivate) &&
(pActivateView->GetDocument() != NULL) )
{
// mark that we are in crossing fase of switching documents if anybody searches for
// document, he will get NULL
theApp.m_bDocumentChangeOn = TRUE;
// force OnIdle so info and combos will adjust to situation when doc = NULL
theApp.OnIdle( 0);
// finish crossing fase, continue "normal" behaviour
theApp.m_bDocumentChangeOn = FALSE;
}
// mark that new document will be activated
theApp.ActivateDocument(GetDocument());
CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
}
BOOL MyChooseColor( COLORREF &clrNewColor, CWnd &wndOwner)
{
COLORREF MyCustColors[ 16];
CHOOSECOLOR ccInit;
ASSERT( &wndOwner != NULL);
MyCustColors[ 0] = CLRF_CLR(C_BLACK);
MyCustColors[ 1] = CLRF_CLR(C_WHITE);
MyCustColors[ 2] = CLRF_CLR(C_dGRAY);
MyCustColors[ 3] = CLRF_CLR(C_GRAY);
MyCustColors[ 4] = CLRF_CLR(C_lGRAY);
MyCustColors[ 5] = CLRF_CLR(C_dRED);
MyCustColors[ 6] = CLRF_CLR(C_dGREEN);
MyCustColors[ 7] = CLRF_CLR(C_dBLUE);
MyCustColors[ 8] = CLRF_CLR(C_dCYAN);
MyCustColors[ 9] = CLRF_CLR(C_dMAGENTA);
MyCustColors[10] = CLRF_CLR(C_dYELLOW);
MyCustColors[11] = CLRF_CLR(C_dORANGE);
MyCustColors[12] = CLRF_CLR(C_dBROWN);
MyCustColors[13] = CLRF_CLR(C_dPINK);
MyCustColors[14] = CLRF_CLR(C_lORANGE);
MyCustColors[15] = CLRF_CLR(C_lBROWN);
memset(&ccInit, 0, sizeof(CHOOSECOLOR));
ccInit.lStructSize = sizeof(CHOOSECOLOR);
ccInit.Flags = CC_RGBINIT | CC_FULLOPEN;
ccInit.rgbResult = clrNewColor;
ccInit.lpCustColors = &MyCustColors[ 0];
ccInit.hwndOwner = wndOwner.m_hWnd;
if( !ChooseColor( &ccInit))
return FALSE;
clrNewColor = ccInit.rgbResult;
return TRUE;
}
// Returns eather perspective view's or manual mip factor
FLOAT CWorldEditorView::GetCurrentlyActiveMipFactor(void)
{
// get document
CWorldEditorDoc* pDoc = GetDocument();
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CEntity *penBrush = pMainFrame->m_CSGDesitnationCombo.GetSelectedBrushEntity();
// get draw port
CDrawPort *pdpValidDrawPort = GetDrawPort();
if((GetChildFrame()->m_bAutoMipBrushingOn) &&
(penBrush != NULL) &&
(pdpValidDrawPort != NULL) )
{
// get entity's brush
CBrush3D *pbrBrush = penBrush->GetBrush();
// create a slave viewer
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, CSlaveViewer::PT_PERSPECTIVE,
pDoc->m_plGrid, pdpValidDrawPort);
// create a projection for slave viewer
CAnyProjection3D prProjection;
svViewer.MakeProjection(prProjection);
prProjection->ObjectPlacementL() = penBrush->GetPlacement();
// prepare the projection
prProjection->Prepare();
// return mip factor for entity in perspective projection
return( -prProjection->pr_TranslationVector(3));
}
else
{
return (GetChildFrame()->m_fManualMipBrushingFactor);
}
}
void CWorldEditorView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// find window under mouse pointer
CWorldEditorDoc* pDoc = GetDocument();
pDoc->SetStatusLineModeInfoMessage();
POINT point;
GetCursorPos(&point);
HWND hwndUnderMouse = ::WindowFromPoint( point);
// if not this one (use parent because gfx-API child is over the window)
if (m_hWnd != ::GetParent(hwndUnderMouse)) {
// ignore the key
return;
}
CView::OnKeyDown( nChar, nRepCnt, nFlags);
BOOL bShift = (GetKeyState(VK_SHIFT) &0x8000) != 0;
BOOL bCtrl = (GetKeyState(VK_CONTROL)&0x8000) != 0;
BOOL bAlt = (GetKeyState(VK_MENU) &0x8000) != 0;
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
BOOL bLMB = (GetKeyState( VK_LBUTTON)&0x8000) != 0;
if(bLMB && !bAlt && (pDoc->GetEditingMode()==TERRAIN_MODE) && !bSpace)
{
if( bCtrl) m_iaInputAction=IA_TERRAIN_EDITING_CTRL_LMB;
else m_iaInputAction=IA_TERRAIN_EDITING_LMB;
}
// tool tips are on when you press I
if( (GetKeyState('I')&0x80) && !(bShift|bCtrl|bAlt)) {
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
// if info doesn't yet exist
if( pMainFrame->m_pwndToolTip == NULL)
{ // force it
theApp.m_cttToolTips.ManualOn( m_ptMouse.x, m_ptMouse.y, &::GetToolTipText, this);
}
}
// call parent's key pressed function
GetChildFrame()->KeyPressed( nChar, nRepCnt, nFlags);
}
void CWorldEditorView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CWorldEditorDoc* pDoc = GetDocument();
pDoc->SetStatusLineModeInfoMessage();
// if we are in mip mode for setting, set new brush switch factor
if( m_iaInputAction == IA_MIP_SETTING)
{
SetMipBrushFactor();
}
BOOL bCtrl = (GetKeyState(VK_CONTROL)&0x8000) != 0;
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
BOOL bLMB = (GetKeyState( VK_LBUTTON)&0x8000) != 0;
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
if(bLMB && !bAlt && (pDoc->GetEditingMode()==TERRAIN_MODE) && !bSpace)
{
if( bCtrl) m_iaInputAction=IA_TERRAIN_EDITING_CTRL_LMB;
else m_iaInputAction=IA_TERRAIN_EDITING_LMB;
_tvLastTerrainBrushingApplied=_pTimer->GetHighPrecisionTimer();
}
// shut down tool tips
theApp.m_cttToolTips.ManualOff();
CView::OnKeyUp(nChar, nRepCnt, nFlags);
}
void CWorldEditorView::SetMipBrushFactor(void)
{
// remember current time as time when last mip brushing option has been used
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
CChildFrame *pChild = GetChildFrame();
// set auto mip brushing mode on
pChild->m_bAutoMipBrushingOn = TRUE;
// get auto mip factor
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
pChild->m_bAutoMipBrushingOn = pChild->m_bLastAutoMipBrushingOn;
// set auto mip brushing mode as it was before mip setting started
ASSERT( m_pbmToSetMipSwitch != NULL);
// set new mip switch factor
m_pbmToSetMipSwitch->SetMipDistance( fCurrentMipFactor-0.01f);
// switch back to auto mip brushing mode
GetChildFrame()->m_bAutoMipBrushingOn = TRUE;
// get document
CWorldEditorDoc* pDoc = GetDocument();
// document has changed
pDoc->SetModifiedFlag();
// update all views
pDoc->UpdateAllViews( NULL);
m_iaInputAction = IA_NONE;
}
void CWorldEditorView::StartMouseInput( CPoint point)
{
CWorldEditorDoc* pDoc = GetDocument();
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
pDoc->UpdateAllViews(NULL);
// reset offseted placement
m_plMouseOffset.pl_PositionVector = FLOAT3D(0.0f, 0.0f, 0.0f);
m_plMouseOffset.pl_OrientationAngle = ANGLE3D(0, 0, 0);
// if there is CSG operation active
if( bCSGOn)
{
// copy original layer's placement because we need to perform "continous moving"
m_plMouseMove = pDoc->m_plSecondLayer;
}
// otherwise if we are in entity mode and there is at least 1 entity selected
else if( pDoc->GetEditingMode() == ENTITY_MODE)
{
if(pDoc->m_selEntitySelection.Count()==0)
{
pDoc->m_aSelectedEntityPlacements.Clear();
}
else
{
FLOATaabbox3D box;
CPlacement3D plEntityCenter;
plEntityCenter = CPlacement3D( FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
// accumulate positions
box |= iten->GetPlacement().pl_PositionVector;
//plEntityCenter.pl_OrientationAngle += iten->GetPlacement().pl_OrientationAngle;
}}
plEntityCenter.pl_PositionVector = box.Center();
plEntityCenter.pl_PositionVector(2) = box.Min()(2);
// calculate average rotation
//plEntityCenter.pl_OrientationAngle /= (ANGLE)pDoc->m_selEntitySelection.Count();
// remember
pDoc->m_aSelectedEntityPlacements.Clear();
pDoc->m_aSelectedEntityPlacements.New(pDoc->m_selEntitySelection.Count());
INDEX ienCurrent = 0;
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
CPlacement3D plRelative = iten->GetPlacement();
plRelative.AbsoluteToRelativeSmooth(plEntityCenter);
pDoc->m_aSelectedEntityPlacements[ ienCurrent] = plRelative;
ienCurrent++;
}}
// copy it's placement for continous moving
m_plMouseMove = plEntityCenter;
}
}
else if( pDoc->GetEditingMode() == VERTEX_MODE)
{
pDoc->m_avStartDragVertices.Clear();
INDEX ctDragVertices = pDoc->m_selVertexSelection.Count();
if( ctDragVertices != 0)
{
// remember coordinates of vertices for dragging
pDoc->m_avStartDragVertices.New(ctDragVertices);
INDEX iVtx = 0;
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
{
pDoc->m_avStartDragVertices[ iVtx] = FLOATtoDOUBLE( itbvx->bvx_vAbsolute);
iVtx++;
}}
}
}
// copy mouse point to both point for calculating relative (from last mouse position) and
// absolute (from mouse down position) distances
m_ptMouse = point;
}
void CWorldEditorView::StopMouseInput(void)
{
// update all views when current view stopped modifying
CWorldEditorDoc* pDoc = GetDocument();
pDoc->UpdateAllViews( NULL);
}
// obtain information about what was hitted with mouse
CCastRay CWorldEditorView::GetMouseHitInformation( CPoint point,
BOOL bHitPortals /* = FALSE */,
BOOL bHitModels /* = TRUE */,
BOOL bHitFields /* = FALSE */,
CEntity *penSourceEntity /* = NULL */,
BOOL bHitBrushes /* = TRUE */)
{
CWorldEditorDoc* pDoc = GetDocument();
// get draw port
CDrawPort *pdpValidDrawPort = GetDrawPort();
// if it is not valid
if( pdpValidDrawPort == NULL)
{
// return dummy result
return CCastRay( NULL, CPlacement3D(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0)) );
}
// obtain viewer placement
CPlacement3D plViewer = GetChildFrame()->m_mvViewer.GetViewerPlacement();
// create a slave viewer
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pdpValidDrawPort);
// now we will try to obtain where mouse poonts to in the base world
// create a projection for current viewer
CAnyProjection3D prProjection;
svViewer.MakeProjection(prProjection);
prProjection->Prepare();
// make the ray from viewer point through the mouse point, in current projection
CPlacement3D plRay;
prProjection->RayThroughPoint(FLOAT3D((float)point.x,
pdpValidDrawPort->GetHeight()-(float)point.y, 0.0f), plRay);
// construct cast ray for base world
CCastRay crBaseWorldCastResult( penSourceEntity, plRay);
// set portal "transparency" or "hitability" for hit beam
crBaseWorldCastResult.cr_bHitPortals = bHitPortals;
// set hitability for models
if( (m_vpViewPrefs.m_mrpModelRenderPrefs.GetRenderType() & RT_TEXTURE) && bHitModels)
{
crBaseWorldCastResult.cr_ttHitModels = CCastRay::TT_FULL;
}
else
{
crBaseWorldCastResult.cr_ttHitModels = CCastRay::TT_NONE;
}
crBaseWorldCastResult.cr_bHitFields = bHitFields;
crBaseWorldCastResult.cr_bHitBrushes = bHitBrushes;
// cast ray, go for hit data
pDoc->m_woWorld.CastRay( crBaseWorldCastResult);
// if second layer's world exist
if( pDoc->m_pwoSecondLayer != NULL)
{
// prepare second layer's projection ...
// get viewer placement from first layer
CPlacement3D plVirtualViewer = prProjection->ViewerPlacementR();
// transform it to the system of the second layer
plVirtualViewer.AbsoluteToRelative(pDoc->m_plSecondLayer);
// use it in projection for second layer
CAnyProjection3D prProjectionSecondLayer;
prProjectionSecondLayer = prProjection;
prProjectionSecondLayer->ViewerPlacementL() = plVirtualViewer;
prProjectionSecondLayer->Prepare();
// calculate valid ray for second layer
CPlacement3D plLayerRay;
prProjectionSecondLayer->RayThroughPoint(FLOAT3D((float)point.x,
pdpValidDrawPort->GetHeight()-(float)point.y, 0.0f), plLayerRay);
// construct cast ray for second layer's world
CCastRay crLayerWorldCastResult( penSourceEntity, plLayerRay);
// set portal "transparency" or "hitability" for hit beam
crLayerWorldCastResult.cr_bHitPortals = bHitPortals;
// set hitability for models
if( m_vpViewPrefs.m_mrpModelRenderPrefs.GetRenderType() & RT_TEXTURE)
{
crLayerWorldCastResult.cr_ttHitModels = CCastRay::TT_SIMPLE;
}
else
{
crLayerWorldCastResult.cr_ttHitModels = CCastRay::TT_NONE;
}
// cast ray, go for hit data
pDoc->m_pwoSecondLayer->CastRay( crLayerWorldCastResult);
// if any kind of entity on second layer was hitted
if( crLayerWorldCastResult.cr_penHit != NULL)
{
// calculate distance beetween viewer and hited point in layer's world
FLOAT fSecondLayerHitDistance =
(crLayerWorldCastResult.cr_vHit - plVirtualViewer.pl_PositionVector).Length();
// transform hited coordinate back to absolute space
CPlacement3D plHitPlacement = plLayerRay;
plHitPlacement.pl_PositionVector = crLayerWorldCastResult.cr_vHit;
plHitPlacement.RelativeToAbsolute( pDoc->m_plSecondLayer);
// and set it as hited point
crLayerWorldCastResult.cr_vHit = plHitPlacement.pl_PositionVector;
// if ray didn't hit anything on base world
if( crBaseWorldCastResult.cr_penHit == NULL)
{
// valid result is one received from second layer ray hit
return crLayerWorldCastResult;
}
// calculate distance beetween viewer and base world's hit point
FLOAT fBaseWorldHitDistance =
(crBaseWorldCastResult.cr_vHit - plViewer.pl_PositionVector).Length();
// if base world's hit point is closer than second layer's hit point
if( Abs(fBaseWorldHitDistance) < Abs(fSecondLayerHitDistance))
{
// base world's hit result is valid result
return crBaseWorldCastResult;
}
// otherwise
else
{
// second layer's world hit result is valid result
return crLayerWorldCastResult;
}
}
}
if( crBaseWorldCastResult.cr_penHit == NULL)
{
// placement equals ray placement
CPlacement3D plPlacementInFront = plRay;
// calculate position somewhere in front of viewer
plPlacementInFront.Translate_OwnSystem( FLOAT3D( 0.0f, 0.0f, -10.0f));
// copy result coordinate into cast object
crBaseWorldCastResult.cr_vHit = plPlacementInFront.pl_PositionVector;
}
return crBaseWorldCastResult;
}
FLOAT3D CWorldEditorView::GetMouseHitOnPlane( CPoint point, const FLOATplane3D &plPlane)
{
CWorldEditorDoc* pDoc = GetDocument();
// get draw port
CDrawPort *pdpValidDrawPort = GetDrawPort();
// if it is not valid
if( pdpValidDrawPort == NULL)
{
// return dummy result
return FLOAT3D(0.0f,0.0f,0.0f);
}
// obtain viewer placement
CPlacement3D plViewer = GetChildFrame()->m_mvViewer.GetViewerPlacement();
// create a slave viewer
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pdpValidDrawPort);
// now we will try to obtain where mouse poonts to in the base world
// create a projection for current viewer
CAnyProjection3D prProjection;
svViewer.MakeProjection(prProjection);
prProjection->Prepare();
// make the ray from viewer point through the mouse point, in current projection
CPlacement3D plRay;
prProjection->RayThroughPoint(FLOAT3D((float)point.x,
pdpValidDrawPort->GetHeight()-(float)point.y, 0.0f), plRay);
// get two points on the line
FLOAT3D v0 = plRay.pl_PositionVector;
FLOAT3D v1;
AnglesToDirectionVector(plRay.pl_OrientationAngle, v1);
v1*=100.0f; // to increase precision on large scales
v1+=v0;
// find intersection of line and plane
FLOAT f0 = plPlane.PointDistance(v0);
FLOAT f1 = plPlane.PointDistance(v1);
FLOAT fFraction = f0/(f0-f1);
return v0+(v1-v0)*fFraction;
}
void CWorldEditorView::MarkClosestVtxAndEdgeOnPrimitiveBase(CPoint point)
{
// get draw port
CDrawPort *pdpValidDrawPort = GetDrawPort();
// if it is not valid
if( pdpValidDrawPort == NULL) return;
CWorldEditorDoc* pDoc = GetDocument();
// create a slave viewer
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pdpValidDrawPort);
// create a projection for current viewer
CAnyProjection3D prProjection;
svViewer.MakeProjection(prProjection);
// prepare the projection
prProjection->Prepare();
// make the ray from viewer point through the mouse point, in current projection
CPlacement3D plRay;
prProjection->RayThroughPoint(FLOAT3D((float)point.x,
pdpValidDrawPort->GetHeight()-(float)point.y, 0.0f), plRay);
// transform ray to the system of the second layer
plRay.AbsoluteToRelative(pDoc->m_plSecondLayer);
m_vMouseDownSecondLayer = plRay.pl_PositionVector;
// prepare second layer's projection ...
// get viewer placement from first layer
CPlacement3D plVirtualViewer = prProjection->ViewerPlacementR();
// transform it to the system of the second layer
plVirtualViewer.AbsoluteToRelative(pDoc->m_plSecondLayer);
// use it in projection for second layer
CAnyProjection3D prProjectionSecondLayer;
prProjectionSecondLayer = prProjection;
prProjectionSecondLayer->ViewerPlacementL() = plVirtualViewer;
prProjectionSecondLayer->Prepare();
// get number of vertices for base polygon
INDEX vtxCt = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive.Count();
// set distance of closest vertice to a hudge distance
FLOAT fMinVertexDistance = 999999.9f;
m_iDragVertice = -1;
FLOAT fMinEdgeDistance = 999999.9f;
m_iDragEdge = -1;
// now we will project base vertices onto screen and try
// to find closest vertice to mouse for moving vertices on the base
for( INDEX iVtx=0; iVtx<vtxCt; iVtx++)
{
INDEX iNext = (iVtx+1)%vtxCt;
FLOAT3D vProjectedVtx1, vProjectedVtx2;
// project vertices
prProjectionSecondLayer->ProjectCoordinate(
DOUBLEtoFLOAT(theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ iVtx]), vProjectedVtx1);
prProjectionSecondLayer->ProjectCoordinate(
DOUBLEtoFLOAT(theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ iNext]), vProjectedVtx2);
// convert y coordinate from mathemathical representation into screen one
vProjectedVtx1(2) = pdpValidDrawPort->GetHeight() - vProjectedVtx1(2);
vProjectedVtx2(2) = pdpValidDrawPort->GetHeight() - vProjectedVtx2(2);
vProjectedVtx1(3) = 0.0f;
vProjectedVtx2(3) = 0.0f;
// calculate distance to mouse
FLOAT fDVtx1 = ( FLOAT3D((FLOAT)point.x, (FLOAT)point.y, 0.0f) - vProjectedVtx1).Length();
FLOAT fDVtx2 = ( FLOAT3D((FLOAT)point.x, (FLOAT)point.y, 0.0f) - vProjectedVtx2).Length();
FLOAT fEdgeLen = ( vProjectedVtx1 - vProjectedVtx2).Length();
FLOAT s = (fDVtx1+fDVtx2+fEdgeLen)/2.0f;
FLOAT fArea = FLOAT(sqrt( FLOATtoDOUBLE( s*(s-fDVtx1)*(s-fDVtx2)*(s-fEdgeLen))));
FLOAT fDEdge = 2.0f*fArea/fEdgeLen;
// if distance of edge is smaller than last remembered and both edges are smaller than
// edges of triangle
if( (fDEdge < fMinEdgeDistance) && (fEdgeLen > fDVtx1) && (fEdgeLen > fDVtx2) )
{
fMinEdgeDistance = fDEdge;
m_iDragEdge = iVtx;
}
// if distance of first vertex is smaller than last remembered
if( fDVtx1 < fMinVertexDistance)
{
fMinVertexDistance = fDVtx1;
m_iDragVertice = iVtx;
}
}
// when we found closest vertice, remember its current position
m_vStartDragVertice = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ m_iDragVertice];
if( m_iDragEdge != -1)
{
INDEX iEdgeEnd = (m_iDragEdge+1)%vtxCt;
m_vStartDragEdge =
(theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ m_iDragEdge]+
theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ iEdgeEnd])/2.0f;
}
}
void CWorldEditorView::MarkClosestVtxOnPrimitive( BOOL bToggleSelection)
{
// get draw port
CDrawPort *pdpValidDrawPort = GetDrawPort();
// if it is not valid
if( pdpValidDrawPort == NULL) return;
CWorldEditorDoc* pDoc = GetDocument();
// create a slave viewer
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pdpValidDrawPort);
// create a projection for current viewer
CAnyProjection3D prProjection;
svViewer.MakeProjection(prProjection);
// prepare the projection
prProjection->Prepare();
// prepare second layer's projection ...
// get viewer placement from first layer
CPlacement3D plVirtualViewer = prProjection->ViewerPlacementR();
// transform it to the system of the second layer
plVirtualViewer.AbsoluteToRelative(pDoc->m_plSecondLayer);
// use it in projection for second layer
CAnyProjection3D prProjectionSecondLayer;
prProjectionSecondLayer = prProjection;
prProjectionSecondLayer->ViewerPlacementL() = plVirtualViewer;
prProjectionSecondLayer->Prepare();
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Lock();
CDynamicArray<CObjectVertex> &aVtx = theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors[0].osc_aovxVertices;
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Unlock();
aVtx.Lock();
// set distance of closest vertice to a hudge distance
FLOAT fMinVertexDistance = 999999.9f;
FLOAT fMinVertexDistanceZ = 999999.9f;
INDEX iClosest = -1;
BOOL bHasSelection = FALSE;
// now we will project base vertices onto screen and try
// to find closest vertice to mouse for moving vertices on the base
for( INDEX iVtx=0; iVtx<aVtx.Count(); iVtx++)
{
if( (aVtx[ iVtx].ovx_ulFlags & OVXF_SELECTED) && !bHasSelection)
{
bHasSelection = TRUE;
m_vStartDragO3DVertice = aVtx[ iVtx];
}
aVtx[ iVtx].ovx_ulFlags &= ~OVXF_CLOSEST;
FLOAT3D vProjected;
// project current base vertice
prProjectionSecondLayer->ProjectCoordinate( DOUBLEtoFLOAT(aVtx[ iVtx]), vProjected);
// convert y coordinate from mathemathical representation into screen one
vProjected(2) = pdpValidDrawPort->GetHeight() - vProjected(2);
// calculate distance to mouse point
FLOAT fDX = (FLOAT)m_ptMouse.x-vProjected(1);
FLOAT fDY = (FLOAT)m_ptMouse.y-vProjected(2);
FLOAT fDistance = (FLOAT)sqrt(fDX*fDX+fDY*fDY);
FLOAT fDistanceZ = -vProjected(3);
// if this distance is smaller than last remembered
if( (fDistance < fMinVertexDistance-0.5) ||
((fDistance<fMinVertexDistance+0.5) && fDistanceZ<fMinVertexDistanceZ) )
{
// set this one as smallest
fMinVertexDistance = fDistance;
fMinVertexDistanceZ = fDistanceZ;
// remember its index
iClosest = iVtx;
}
}
aVtx[ iClosest].ovx_ulFlags |= OVXF_CLOSEST;
if( bToggleSelection)
{
aVtx[ iClosest].ovx_ulFlags ^= OVXF_SELECTED;
}
if( !bHasSelection)
{
m_vStartDragO3DVertice = aVtx[ iClosest];
}
aVtx.Unlock();
}
POINT CWorldEditorView::Get2DCoordinateFrom3D( FLOAT3D vPoint)
{
CDrawPort *pDP = m_pdpDrawPort;
CWorldEditorDoc* pDoc = GetDocument();
CAnyProjection3D prProjection;
// create a slave viewer
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid, pDP);
svViewer.MakeProjection(prProjection);
prProjection->Prepare();
FLOAT3D vResult;
prProjection->ProjectCoordinate( vPoint, vResult);
POINT ptResult;
ptResult.x = (LONG) vResult(1);
ptResult.y = pDP->GetHeight()-(LONG) vResult(2);
return ptResult;
}
FLOAT3D CWorldEditorView::Get3DCoordinateFrom2D( POINT &pt)
{
CDrawPort *pDP = m_pdpDrawPort;
// convert coordinate
PIX pixX = pt.x;
PIX pixY = pt.y;
CWorldEditorDoc* pDoc = GetDocument();
CAnyProjection3D prProjection;
// create a slave viewer
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid, pDP);
svViewer.MakeProjection(prProjection);
prProjection->Prepare();
// make the ray from viewer point through the mouse point, in current projection
CPlacement3D plRay;
prProjection->RayThroughPoint(FLOAT3D((float)pixX, pDP->GetHeight()-(float)pixY, 0.0f), plRay);
// snap to grid entity's placement
pDoc->SnapToGrid( plRay, m_fGridInMeters/GRID_DISCRETE_VALUES);
// get viewer's direction vector
FLOAT3D vDirection;
AnglesToDirectionVector( plRay.pl_OrientationAngle, vDirection);
FLOAT3D vResult;
vResult = plRay.pl_PositionVector + vDirection;
// snap result
SnapVector( vResult);
return vResult;
}
void CWorldEditorView::SnapVector(FLOAT3D &vToSnap)
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->m_bAutoSnap)
{
Snap(vToSnap(1), m_fGridInMeters/GRID_DISCRETE_VALUES);
Snap(vToSnap(2), m_fGridInMeters/GRID_DISCRETE_VALUES);
Snap(vToSnap(3), m_fGridInMeters/GRID_DISCRETE_VALUES);
}
else
{
Snap(vToSnap(1), SNAP_DOUBLE_CM);
Snap(vToSnap(2), SNAP_DOUBLE_CM);
Snap(vToSnap(3), SNAP_DOUBLE_CM);
}
}
void CWorldEditorView::SnapVector(DOUBLE3D &vToSnap)
{
CWorldEditorDoc* pDoc = GetDocument();
FLOAT3D vTemp = DOUBLEtoFLOAT(vToSnap);
if( pDoc->m_bAutoSnap)
{
Snap(vTemp(1), m_fGridInMeters/GRID_DISCRETE_VALUES);
Snap(vTemp(2), m_fGridInMeters/GRID_DISCRETE_VALUES);
Snap(vTemp(3), m_fGridInMeters/GRID_DISCRETE_VALUES);
}
else
{
Snap(vTemp(1), SNAP_DOUBLE_CM);
Snap(vTemp(2), SNAP_DOUBLE_CM);
Snap(vTemp(3), SNAP_DOUBLE_CM);
}
vToSnap = FLOATtoDOUBLE(vTemp);
}
FLOAT GetDistance( POINT &pt1, POINT &pt2)
{
FLOAT2D vpt1, vpt2;
vpt1(1) = pt1.x;
vpt1(2) = pt1.y;
vpt2(1) = pt2.x;
vpt2(2) = pt2.y;
FLOAT2D vDistance = vpt1-vpt2;
return vDistance.Length();
}
void CWorldEditorView::RenderAndApplyTerrainEditBrush(FLOAT3D vHit)
{
CWorldEditorDoc* pDoc = GetDocument();
CTerrain *ptrTerrain=GetTerrain();
if( ptrTerrain!=NULL)
{
CTString strBrushFile;
INDEX iBrush=INDEX(theApp.m_fCurrentTerrainBrush);
strBrushFile.PrintF("Textures\\Editor\\TerrainBrush%02d.tex", iBrush);
try
{
CTextureData *ptdBrush=_pTextureStock->Obtain_t(strBrushFile);
ptdBrush->Force(TEX_STATIC);
FLOAT fStrengthRatio=theApp.m_fTerrainBrushPressure/1024.0f;
FLOAT fUncompensatedStrength=(pow(1.0f+theApp.m_fTerrainBrushPressure/1024.0f*16.0f,2)-1.0f)/64.0f;
COLOR colSelection=C_WHITE|CT_OPAQUE;
ETerrainEdit teTool=TE_NONE;
SelectionFill sf;
// heightmap mode
if( theApp.m_iTerrainEditMode==TEM_HEIGHTMAP)
{
colSelection=C_ORANGE|CT_OPAQUE;
switch(INDEX(theApp.m_iTerrainBrushMode))
{
case TBM_PAINT : teTool=TE_BRUSH_ALTITUDE_PAINT ; break;
case TBM_SMOOTH : teTool=TE_BRUSH_ALTITUDE_SMOOTH ; break;
case TBM_FILTER : teTool=TE_BRUSH_ALTITUDE_FILTER ; break;
case TBM_MINIMUM : teTool=TE_BRUSH_ALTITUDE_MINIMUM ; break;
case TBM_MAXIMUM : teTool=TE_BRUSH_ALTITUDE_MAXIMUM ; break;
case TBM_FLATTEN : teTool=TE_BRUSH_ALTITUDE_FLATTEN ; break;
case TBM_POSTERIZE : teTool=TE_BRUSH_ALTITUDE_POSTERIZE; break;
case TBM_RND_NOISE : teTool=TE_BRUSH_ALTITUDE_RND_NOISE; break;
case TBM_CONTINOUS_NOISE: teTool=TE_BRUSH_ALTITUDE_CONTINOUS_NOISE; break;
case TBM_ERASE : teTool=TE_BRUSH_EDGE_ERASE ; break;
}
}
// texture layer mode
else
{
colSelection=C_GREEN|CT_OPAQUE;
teTool=TE_BRUSH_LAYER_PAINT;
CTerrainLayer *ptlLayer=GetLayer();
if(ptlLayer==NULL) return;
if( ptlLayer->tl_ltType==LT_TILE)
{
teTool=TE_TILE_PAINT;
}
else
{
switch(INDEX(theApp.m_iTerrainBrushMode))
{
case TBM_PAINT : teTool=TE_BRUSH_LAYER_PAINT ; break;
case TBM_SMOOTH : teTool=TE_BRUSH_LAYER_SMOOTH ; break;
case TBM_FILTER : teTool=TE_BRUSH_LAYER_FILTER ; break;
case TBM_RND_NOISE : teTool=TE_BRUSH_LAYER_RND_NOISE; break;
case TBM_CONTINOUS_NOISE: teTool=TE_BRUSH_LAYER_CONTINOUS_NOISE; break;
case TBM_ERASE : teTool=TE_BRUSH_EDGE_ERASE ; break;
}
}
}
// no cursor if selection is hidden
if(!GetChildFrame()->m_bSelectionVisible) colSelection&=0xFFFFFF00;
if( m_iaInputAction==IA_TERRAIN_EDITING_LMB || m_iaInputAction==IA_TERRAIN_EDITING_CTRL_LMB)
{
// if we pressed mouse down (terrain edit start)
if(m_iaInputAction!=m_iaLastInputAction)
{
TerrainEditBegin();
}
CTimerValue tvNow=_pTimer->GetHighPrecisionTimer();
// get difference to time when last mip brushing option has been used
FLOAT fSecondsPassed=(tvNow-_tvLastTerrainBrushingApplied).GetSeconds();
_tvLastTerrainBrushingApplied=_pTimer->GetHighPrecisionTimer();
// apply time passed factor, so terrain editing wouldn't depend upon frame rate
fSecondsPassed=Clamp(fSecondsPassed,0.0f,1.0f);
FLOAT fCompensatedStrength=fUncompensatedStrength*fSecondsPassed/(1.0f/50.0f);
if( m_iaInputAction==IA_TERRAIN_EDITING_CTRL_LMB) fCompensatedStrength=-fCompensatedStrength;
// apply terrain editing
EditTerrain(ptdBrush, vHit, fCompensatedStrength, teTool);
}
// if we stopped editing
else if( m_iaLastInputAction==IA_TERRAIN_EDITING_LMB || m_iaLastInputAction==IA_TERRAIN_EDITING_CTRL_LMB)
{
TerrainEditEnd();
}
m_iaLastInputAction=m_iaInputAction;
// render terrain editing cursor
Rect rect;
Point pt=Calculate2dHitPoint(ptrTerrain, vHit);
rect.rc_iLeft=pt.pt_iX-ptdBrush->GetPixWidth()/2;
rect.rc_iRight=pt.pt_iX+(ptdBrush->GetPixWidth()-ptdBrush->GetPixWidth()/2);
rect.rc_iTop=pt.pt_iY-ptdBrush->GetPixHeight()/2;
rect.rc_iBottom=pt.pt_iY+(ptdBrush->GetPixHeight()-ptdBrush->GetPixHeight()/2);
if(GetChildFrame()->m_bSelectionVisible)
{
sf=(SelectionFill) theApp.m_Preferences.ap_iTerrainSelectionVisible;
}
else
{
sf=(SelectionFill) theApp.m_Preferences.ap_iTerrainSelectionHidden;
}
if(sf!=3)
{
ShowSelection(ptrTerrain, rect, ptdBrush, colSelection, 0.25f+fStrengthRatio*0.75f, sf);
}
}
catch( char *strError)
{
(void) strError;
}
}
}
void CWorldEditorView::OnLButtonDown(UINT nFlags, CPoint point)
{
m_iaInputAction = IA_NONE;
CDrawPort *pdpValidDrawPort = GetDrawPort();
if( pdpValidDrawPort == NULL) return;
m_pbpoTranslationPlane = NULL;
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// key statuses
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
BOOL bSpace = (GetKeyState( ' ') & 128) != 0;
BOOL bCtrl = nFlags & MK_CONTROL;
BOOL bShift = nFlags & MK_SHIFT;
BOOL bRMB = nFlags & MK_RBUTTON;
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
BOOL bHitModels = (pDoc->GetEditingMode() == ENTITY_MODE) || bSpace;
BOOL bHitFields = (pDoc->GetEditingMode() == ENTITY_MODE) || bSpace;
BOOL bHitBrushes = (pDoc->GetEditingMode() != TERRAIN_MODE) || bSpace;
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( point, FALSE, bHitModels, bHitFields, NULL, bHitBrushes);
m_vHitOnMouseDown = crRayHit.cr_vHit;
theApp.m_vLastTerrainHit=crRayHit.cr_vHit;
m_ptMouseDown = point;
m_VFPMouseDown = theApp.m_vfpCurrent;
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pdpValidDrawPort);
CAnyProjection3D prProjection;
svViewer.MakeProjection(prProjection);
prProjection->Prepare();
// space+ctrl+lmb zoomes in 2x
if( bSpace && bCtrl)
{
if( bRMB) return;
// set new target
GetChildFrame()->m_mvViewer.SetTargetPlacement( crRayHit.cr_vHit);
// move mouse to center of screen
CPoint ptCenter = CPoint( m_pdpDrawPort->GetWidth()/2, m_pdpDrawPort->GetHeight()/2);
ClientToScreen( &ptCenter);
SetCursorPos(ptCenter.x, ptCenter.y);
OnZoomMore();
pDoc->UpdateAllViews( NULL);
m_ptMouseDown = ptCenter;
return;
}
// space+lmb is used for viewer and CSG layer movement in floor plane,+rmb rotates
else if( bSpace)
{
if( bRMB) m_iaInputAction = IA_ROTATING_VIEWER;
else m_iaInputAction = IA_MOVING_VIEWER_IN_FLOOR_PLANE;
StartMouseInput( point);
}
// in measure mode, only viewer moving is enabled
else if( theApp.m_bMeasureModeOn)
{
m_iaInputAction = IA_MEASURING;
}
// in cut mode, only viewer moving is enabled
else if( theApp.m_bCutModeOn)
{
// project 3D control points
POINT ptStart = Get2DCoordinateFrom3D( pDoc->m_vCutLineStart);
POINT ptEnd = Get2DCoordinateFrom3D( pDoc->m_vCutLineEnd);
// calculate distances
FLOAT fDStart = GetDistance( ptStart, point);
FLOAT fDEnd = GetDistance( ptEnd, point);
FLOAT fAllowedDistance = 32.0f;
// if we clicked near coontrol point
if( fDStart < fAllowedDistance)
{
m_iaInputAction = IA_MOVING_CUT_LINE_START;
pDoc->m_vControlLineDragStart = pDoc->m_vCutLineStart;
}
else if( fDEnd < fAllowedDistance)
{
m_iaInputAction = IA_MOVING_CUT_LINE_END;
pDoc->m_vControlLineDragStart = pDoc->m_vCutLineEnd;
}
else
{
m_iaInputAction = IA_CUT_MODE;
pDoc->m_pCutLineView = this;
pDoc->m_vCutLineStart = Get3DCoordinateFrom2D( point);
pDoc->m_vCutLineEnd = pDoc->m_vCutLineStart;
}
pDoc->UpdateAllViews( this);
}
// test for mouse operations used while primitive CSG is on
else if( bCSGOn)
{
if( bCtrl && bAlt)
{
SetAsCsgTarget(crRayHit.cr_penHit);
}
if( bCtrl && !bShift)
{
if( bRMB) m_iaInputAction = IA_ROTATING_SECOND_LAYER;
else m_iaInputAction = IA_MOVING_SECOND_LAYER_IN_FLOOR_PLANE;
}
else if( pDoc->m_bPrimitiveMode)
{
// in triangularisation primitive mode
if( theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE)
{
// select vertices on primitive
MarkClosestVtxOnPrimitive( bShift);
// and start dragging them
if( !bShift) m_iaInputAction = IA_DRAG_VERTEX_ON_PRIMITIVE;
}
// shift+lmb inserts vertex on primitive base
else if( !bCtrl && bShift)
{
// find and remember vertex on primitive base for draging
MarkClosestVtxAndEdgeOnPrimitiveBase( point);
if(m_iDragEdge != -1)
{
pDoc->InsertPrimitiveVertex( m_iDragEdge, m_vMouseDownSecondLayer);
}
}
// lmb is used for dragging vertices on base of primitive
else
{
// ctrl+shift+lmb stretches primitive
if( bCtrl && bShift) m_iaInputAction = IA_STRETCHING_PRIMITIVE;
else m_iaInputAction = IA_DRAG_VERTEX_ON_PRIMITIVE_BASE;
// ------ Find closest vertice on base of primitive and remember its position
// prepare second layer's projection ...
// get viewer placement from first layer
CPlacement3D plVirtualViewer = prProjection->ViewerPlacementR();
// transform it to the system of the second layer
plVirtualViewer.AbsoluteToRelative(pDoc->m_plSecondLayer);
// use it in projection for second layer
CAnyProjection3D prProjectionSecondLayer;
prProjectionSecondLayer = prProjection;
prProjectionSecondLayer->ViewerPlacementL() = plVirtualViewer;
prProjectionSecondLayer->Prepare();
// find and remember vertex on primitive base for draging
MarkClosestVtxAndEdgeOnPrimitiveBase( point);
m_iSizeControlVertice = -1;
FLOAT fMinDistance = 9999999.9f;
// prepare array with vertices used as control points for sizing box arround primitive
FLOAT3D avtxSizeControlVertices[ 14];
// table of min x, max x, miny, ...
FLOAT afCoordinates[ 6];
afCoordinates[0] = theApp.m_vfpCurrent.vfp_fXMin;
afCoordinates[1] = theApp.m_vfpCurrent.vfp_fXMax;
afCoordinates[2] = theApp.m_vfpCurrent.vfp_fYMin;
afCoordinates[3] = theApp.m_vfpCurrent.vfp_fYMax;
afCoordinates[4] = theApp.m_vfpCurrent.vfp_fZMin;
afCoordinates[5] = theApp.m_vfpCurrent.vfp_fZMax;
// create control points using table with indices into afCoordinates table
for( INDEX iVtx=0;iVtx<14;iVtx++)
{
avtxSizeControlVertices[iVtx](1) =
(afCoordinates[aiForCreationOfSizingVertices[iVtx][0]]+
afCoordinates[aiForCreationOfSizingVertices[iVtx][1]])/2;
avtxSizeControlVertices[iVtx](2) =
(afCoordinates[aiForCreationOfSizingVertices[iVtx][2]]+
afCoordinates[aiForCreationOfSizingVertices[iVtx][3]])/2;
avtxSizeControlVertices[iVtx](3) =
(afCoordinates[aiForCreationOfSizingVertices[iVtx][4]]+
afCoordinates[aiForCreationOfSizingVertices[iVtx][5]])/2;
}
// now we will project size control vertices and try to find closest one to mouse
for( INDEX iControlVtx=0; iControlVtx<14; iControlVtx++)
{
FLOAT3D vProjectedCoordinate;
// project current control vertex
prProjectionSecondLayer->ProjectCoordinate(
avtxSizeControlVertices[iControlVtx], vProjectedCoordinate);
// convert y coordinate from mathemathical representation into screen one
vProjectedCoordinate(2) = pdpValidDrawPort->GetHeight() - vProjectedCoordinate(2);
FLOAT fDX = vProjectedCoordinate(1)-point.x;
FLOAT fDY = vProjectedCoordinate(2)-point.y;
// calculate distance to mouse point
FLOAT fDistance = fDX*fDX+fDY*fDY;
// if this distance is smaller than last remembered
if( fDistance < fMinDistance)
{
// set this one as smallest
fMinDistance = fDistance;
// and remember its indice as souch
m_iSizeControlVertice = iControlVtx;
}
}
}
}
// reset relative placement (m_plMouseOffset)
StartMouseInput( point);
}
// if only Alt key is pressed, we are not in vertex nor entity mode, we want to save thumbnail
else if( bAlt && !bCtrl && !bShift && !bSpace &&
(pDoc->GetEditingMode() != VERTEX_MODE) &&
(pDoc->GetEditingMode() != ENTITY_MODE))
{
// if document is modified
if( pDoc->IsModified() )
{
// report error
AfxMessageBox(L"You must save your document before you can perform drag.");
}
else
{
CTFileName fnDocument = CTString(CStringA(pDoc->GetPathName()));
// save the thumbnail
pDoc->SaveThumbnail();
// try to
try
{
// remove application path
fnDocument.RemoveApplicationPath_t();
// create drag and drop object
HGLOBAL hglobal = CreateHDrop( fnDocument);
m_DataSource.CacheGlobalData( CF_HDROP, hglobal);
m_DataSource.DoDragDrop( DROPEFFECT_COPY);
}
// if failed
catch (char *strError)
{
// report error
AfxMessageBox(CString(strError));
}
}
}
// else if we are in entity mode
else if( pDoc->GetEditingMode() == ENTITY_MODE)
{
// if ctrl pressed, we want to move or rotate entity selection
if( bCtrl && !bShift && !bAlt)
{
if( bRMB) m_iaInputAction = IA_ROTATING_ENTITY_SELECTION;
else m_iaInputAction = IA_MOVING_ENTITY_SELECTION_IN_FLOOR_PLANE;
StartMouseInput( point);
}
// if we are in browsing entities mode (or select by volume)
else if( (pDoc->m_bBrowseEntitiesMode) &&
(m_ptProjectionType != CSlaveViewer::PT_PERSPECTIVE) )
{
m_iaInputAction = IA_SIZING_SELECT_BY_VOLUME_BOX;
// ------ Find closest vertice of volume box
// create a slave viewer
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pdpValidDrawPort);
// create a projection for current viewer
CAnyProjection3D prProjection;
svViewer.MakeProjection(prProjection);
// prepare the projection
prProjection->Prepare();
// set distance of closest vertice to a hudge distance
FLOAT fMinVertexDistance = 999999.9f;
pDoc->m_iVolumeBoxDragVertice = 0;
// now we will project volume box's vertices onto screen and find closest one to mouse
for( INDEX iVtx=0; iVtx<8; iVtx++)
{
FLOAT3D vProjectedCoordinate;
// project current base vertice
prProjection->ProjectCoordinate( pDoc->m_avVolumeBoxVertice[iVtx], vProjectedCoordinate);
// convert y coordinate from mathemathical representation into screen one
vProjectedCoordinate(2) = pdpValidDrawPort->GetHeight() - vProjectedCoordinate(2);
// reset on screen "z" coordinate
vProjectedCoordinate(3) = 0.0f;
// calculate distance to mouse point
FLOAT fDistance =
( FLOAT3D((FLOAT)point.x, (FLOAT)point.y, 0.0f) - vProjectedCoordinate ).Length();
// if this distance is smaller than last remembered
if( fDistance < fMinVertexDistance)
{
// set this one as smallest
fMinVertexDistance = fDistance;
// and remember its indice as souch
pDoc->m_iVolumeBoxDragVertice = iVtx;
}
}
// when we found closest vertice, remember its current position
pDoc->m_vVolumeBoxStartDragVertice = pDoc->m_avVolumeBoxVertice[ pDoc->m_iVolumeBoxDragVertice];
// reset relative placement (m_plMouseOffset)
StartMouseInput( point);
}
// ctrl+shift+lmb is used to edit range and angle3d properties
else if( bCtrl && bShift)
{
if( pDoc->m_selEntitySelection.Count() != 0)
{
// get selected property
CPropertyID *ppid = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
// if property is of range or angle3d type
if( (ppid != NULL) && (ppid->pid_eptType == CEntityProperty::EPT_RANGE) )
{
m_iaInputAction = IA_CHANGING_RANGE_PROPERTY;
}
if( (ppid != NULL) && (ppid->pid_eptType == CEntityProperty::EPT_ANGLE3D) )
{
m_iaInputAction = IA_CHANGING_ANGLE3D_PROPERTY;
}
}
}
// Alt+Ctrl+LMB requests that clicked entity becomes target to selected entity
else if( bAlt && bCtrl && (crRayHit.cr_penHit != NULL))
{
if( pDoc->m_selEntitySelection.Count() == 0)
{
SetAsCsgTarget(crRayHit.cr_penHit);
}
else
{
// get selected property
CPropertyID *ppid = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
if( (ppid == NULL) ||
!((ppid->pid_eptType == CEntityProperty::EPT_ENTITYPTR) ||
(ppid->pid_eptType == CEntityProperty::EPT_PARENT)) ) return;
BOOL bParentProperty = ppid->pid_eptType == CEntityProperty::EPT_PARENT;
// for each of the selected entities
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
if( bParentProperty)
{
iten->SetParent( crRayHit.cr_penHit);
}
else if (crRayHit.cr_penHit->IsTargetable())
{
// obtain entity class ptr
CDLLEntityClass *pdecDLLClass = iten->GetClass()->ec_pdecDLLClass;
// for all classes in hierarchy of this entity
for(;
pdecDLLClass!=NULL;
pdecDLLClass = pdecDLLClass->dec_pdecBase) {
// for all properties
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++) {
CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
if( (ppid->pid_strName == epProperty.ep_strName) &&
(ppid->pid_eptType == epProperty.ep_eptType) )
{
// discard old entity settings
iten->End();
// set clicked entity as one that selected entity points to
ENTITYPROPERTY( &*iten, epProperty.ep_slOffset, CEntityPointer) = crRayHit.cr_penHit;
// apply new entity settings
iten->Initialize();
}
}
}
}
}
// update edit range control (by updating parent dialog)
pMainFrame->m_PropertyComboBar.UpdateData( FALSE);
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
}
}
// we want to select entities
else
{
m_iaInputAction = IA_SELECTING_ENTITIES;
m_bOnSelectEntityShiftDown = bShift;
m_bOnSelectEntityAltDown = bAlt;
}
}
// else if we are in sector mode
else if( pDoc->GetEditingMode() == SECTOR_MODE)
{
m_iaInputAction = IA_SELECTING_SECTORS;
ToggleHittedSector( crRayHit);
}
// if we are in polygon mode
else if( pDoc->GetEditingMode() == POLYGON_MODE)
{
// Alt+Ctrl+LMB requests that clicked polygon sizes its texture
if( bAlt && bCtrl && !bShift)
{
MultiplyMappingOnPolygon( 0.5f);
}
else if( bAlt && bCtrl && bShift)
{
OnRemainSelectedByOrientation(FALSE);
}
if( bAlt && bShift)
{
OnRemainSelectedByOrientation(TRUE);
}
// if we hit polygon
else if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
// if we want to change polygon mapping
if( bCtrl && !bShift)
{
if( bRMB) m_iaInputAction = IA_ROTATING_POLYGON_MAPPING;
else m_iaInputAction = IA_MOVING_POLYGON_MAPPING;
StartMouseInput( point);
// remember hitted point
m_f3dRotationOrigin = crRayHit.cr_vHit;
m_plMouseMove.pl_PositionVector = crRayHit.cr_vHit;
m_plMouseMove.pl_OrientationAngle = ANGLE3D( 0, 0, 0);
m_pbpoTranslationPlane = crRayHit.cr_pbpoBrushPolygon;
m_plTranslationPlane = crRayHit.cr_pbpoBrushPolygon->bpo_pbplPlane->bpl_plAbsolute;
}
// select or deselect hitted polygon
else if( !bCtrl)
{
m_iaInputAction = IA_SELECTING_POLYGONS;
ToggleHittedPolygon( crRayHit);
}
}
}
// if we are in vertex mode
else if( pDoc->GetEditingMode() == VERTEX_MODE)
{
// Ctrl+Alt is used to add vertex
if( bCtrl && bAlt)
{
CBrushPolygon *pbpo = crRayHit.cr_pbpoBrushPolygon;
if( (crRayHit.cr_penHit != NULL) && (pbpo != NULL) )
{
pDoc->m_selPolygonSelection.Clear();
pDoc->m_selVertexSelection.Clear();
pbpo->bpo_pbscSector->TriangularizePolygon( pbpo);
pDoc->m_chSelections.MarkChanged();
// cast ray again to hit newly created triangle
CCastRay crRayHit = GetMouseHitInformation( point, FALSE, bHitModels, bHitFields);
CBrushPolygon *pbpo = crRayHit.cr_pbpoBrushPolygon;
if( (crRayHit.cr_penHit != NULL) && (pbpo != NULL) )
{
pDoc->m_selPolygonSelection.Select( *pbpo);
pbpo->bpo_pbscSector->InsertVertexIntoTriangle( pDoc->m_selPolygonSelection, crRayHit.cr_vHit);
}
}
}
// Ctrl is used for rotating or moving vertices
else if( bCtrl)
{
if( bShift)
{
m_iaInputAction = IA_STRETCH_BRUSH_VERTEX;
}
else if( bRMB)
{
m_iaInputAction = IA_ROTATE_BRUSH_VERTEX;
}
else
{
m_iaInputAction = IA_DRAG_BRUSH_VERTEX_IN_FLOOR_PLANE;
}
// clear polygon selection because some of the old polygons could disappear
pDoc->m_selPolygonSelection.Clear();
pDoc->m_woWorld.TriangularizeForVertices( pDoc->m_selVertexSelection);
StartMouseInput( point);
}
else
{
m_avpixLaso.Clear();
m_iaInputAction = IA_SELECT_SINGLE_BRUSH_VERTEX;
_vpixSelectNearPoint(1) = point.x;
_vpixSelectNearPoint(2) = point.y;
m_bOnSelectVertexShiftDown = bShift;
m_bOnSelectVertexAltDown = bAlt;
}
}
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
if(crRayHit.cr_penHit!=NULL && crRayHit.cr_penHit==GetTerrainEntity())
{
_bCursorMoved=FALSE;
if( bAlt && bCtrl)
{
OnPickLayer();
}
else if( !bAlt && bCtrl)
{
m_iaInputAction = IA_TERRAIN_EDITING_CTRL_LMB;
_tvLastTerrainBrushingApplied=_pTimer->GetHighPrecisionTimer();
}
else if( !bAlt)
{
m_iaInputAction = IA_TERRAIN_EDITING_LMB;
_tvLastTerrainBrushingApplied=_pTimer->GetHighPrecisionTimer();
}
}
else
{
// if terrain entity hit
if(crRayHit.cr_penHit!=NULL && crRayHit.cr_penHit->GetRenderType()==CEntity::RT_TERRAIN)
{
pDoc->m_ptrSelectedTerrain=crRayHit.cr_penHit->GetTerrain();
theApp.m_ctTerrainPage.MarkChanged();
}
}
}
CView::OnLButtonDown(nFlags, point);
}
void SelectLayerCommand(INDEX iSelectedLayer)
{
SelectLayer(iSelectedLayer);
theApp.m_ctTerrainPageCanvas.MarkChanged();
CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
if(pDoc!=NULL)
{
pDoc->m_chSelections.MarkChanged();
}
}
void CWorldEditorView::InvokeSelectLayerCombo(void)
{
CPoint pt=m_ptMouse;
CCastRay crRayHit=GetMouseHitInformation( pt);
if( (crRayHit.cr_penHit==NULL) || (crRayHit.cr_penHit->GetRenderType()!=CEntity::RT_TERRAIN) ) return;
CCustomComboWnd *pCombo=new CCustomComboWnd;
CTerrain *ptrTerrain=crRayHit.cr_penHit->GetTerrain();
if(ptrTerrain==NULL) return;
INDEX ctLayers=ptrTerrain->tr_atlLayers.Count();
for(INDEX iLayer=ctLayers-1; iLayer>=0; iLayer--)
{
CTString strLayerName;
UBYTE ubPower=GetValueFromMask(ptrTerrain, iLayer, crRayHit.cr_vHit);
strLayerName.PrintF("Layer %d (%d%%)", iLayer+1, INDEX(ubPower/255.0f*100.0f));
if(ubPower>0)
{
INDEX iAddedAs=pCombo->InsertItem( strLayerName);
pCombo->SetItemValue( iAddedAs, iLayer);
}
if(ubPower==255) break;
}
GetCursorPos( &pt);
pCombo->Initialize(NULL, SelectLayerCommand, pt.x-8, pt.y-8, TRUE);
}
void CWorldEditorView::OnRButtonDown(UINT nFlags, CPoint point)
{
if( m_iaInputAction != IA_MIP_SETTING) m_iaInputAction = IA_NONE;
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
BOOL bShift = nFlags & MK_SHIFT;
BOOL bCtrl = nFlags & MK_CONTROL;
BOOL bLMB = nFlags & MK_LBUTTON;
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
BOOL bCaps = (GetKeyState( VK_CAPITAL)&0x0001) != 0;
BOOL bHitModels = (pDoc->GetEditingMode() == ENTITY_MODE) || bSpace;
BOOL bHitFields = (pDoc->GetEditingMode() == ENTITY_MODE) || bSpace;
StartMouseInput( point);
// remember point in the view
m_ptMouseDown = point;
// remember values for primitive
m_VFPMouseDown = theApp.m_vfpCurrent;
// if nothing of below is activated, call popup menu
if( !bShift && !bAlt && !bCtrl && !bSpace && !bLMB)
{
CallPopupMenu( point);
}
// space+ctrl+lmb zoomes out 2x
else if( bSpace && bCtrl)
{
if( bLMB) return;
OnZoomLess();
return;
}
else if( bSpace && bLMB)
{
m_iaInputAction = IA_ROTATING_VIEWER;
}
// we have viewer movement in view plane
else if( bSpace && !bShift)
{
if( bSpace) m_iaInputAction = IA_MOVING_VIEWER_IN_VIEW_PLANE;
StartMouseInput( point);
}
// second layer movements
else if( bCSGOn)
{
// if ctrl+rmb pressed, we want to move second layer in view plane
if( bCtrl && !bShift)
{
if( bLMB) m_iaInputAction = IA_ROTATING_SECOND_LAYER;
else m_iaInputAction = IA_MOVING_SECOND_LAYER_IN_VIEW_PLANE;
StartMouseInput( point);
}
// test for mouse operations used while primitive CSG is on
else if( pDoc->m_bPrimitiveMode)
{
// ctrl+shift+rmb sheares primitive
if( bCtrl && bShift)
{
if( m_ptProjectionType != CSlaveViewer::PT_PERSPECTIVE)
m_iaInputAction = IA_SHEARING_PRIMITIVE;
}
// shift+rmb in deletes vertex on base of primitive
else if( bShift && !bCtrl && !bLMB && !bSpace)
{
MarkClosestVtxAndEdgeOnPrimitiveBase( point);
if( m_iDragVertice != -1) pDoc->DeletePrimitiveVertex( m_iDragVertice);
}
}
}
else if( pDoc->GetEditingMode() == POLYGON_MODE)
{
// measure and cut modes disable all functions
if( theApp.m_bMeasureModeOn || theApp.m_bCutModeOn)
{
}
if( bAlt && bShift)
{
OnDeselectByOrientation();
}
// alt+ctrl+rmb sizes polygon's texture
else if( bAlt && bCtrl)
{
MultiplyMappingOnPolygon( 2.0f);
}
else if( bCtrl && bLMB)
{
m_iaInputAction = IA_ROTATING_POLYGON_MAPPING;
}
// shift turns on portal testing
else if( bShift && !bCtrl)
{
m_iaInputAction = IA_SELECTING_POLYGONS;
// cast ray but ask if test for portal hits
CCastRay crRayHit = GetMouseHitInformation( point, TRUE, FALSE);
ToggleHittedPolygon( crRayHit);
}
}
else if( pDoc->GetEditingMode() == SECTOR_MODE)
{
// shift turns on portal testing
if( bShift)
{
m_iaInputAction = IA_SELECTING_SECTORS;
// cast ray but ask if test for portal hits
CCastRay crRayHit = GetMouseHitInformation( point, TRUE, FALSE);
ToggleHittedSector( crRayHit);
}
}
else if(pDoc->GetEditingMode() == ENTITY_MODE)
{
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CEntity *penBrush = pMainFrame->m_CSGDesitnationCombo.GetSelectedBrushEntity();
// if we should start mip setting mode
if( bShift && bCtrl && !bAlt && (penBrush != NULL) )
{
if( m_iaInputAction == IA_MIP_SETTING) return;
// get entity's brush
CBrush3D *pbrBrush = penBrush->GetBrush();
if( pbrBrush != NULL)
{
CChildFrame *pChild = GetChildFrame();
// set auto mip brushing mode as it was before mip setting started
pChild->m_bLastAutoMipBrushingOn = pChild->m_bAutoMipBrushingOn;
// get curently active mip factor
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
// get the mip brush for current factor
m_pbmToSetMipSwitch = pbrBrush->GetBrushMipByDistance(fCurrentMipFactor);
// if we are in automatic mip brushing mode
if( (GetChildFrame()->m_bAutoMipBrushingOn) && (m_pbmToSetMipSwitch != NULL) )
{
// set manual mip factor so current mip brush would be visible
GetChildFrame()->m_fManualMipBrushingFactor = fCurrentMipFactor;
// set manual mip brushing mode
GetChildFrame()->m_bAutoMipBrushingOn = FALSE;
m_iaInputAction = IA_MIP_SETTING;
}
else
{
m_iaInputAction = IA_NONE;
}
}
else
{
m_iaInputAction = IA_NONE;
}
}
// Alt+Ctrl+RMB sets clicked entity as target on first available free target ptr slot
else if( bAlt && bCtrl && !bShift && (pDoc->m_selEntitySelection.Count() != 0))
{
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( point, FALSE, bHitModels, bHitFields);
if(crRayHit.cr_penHit != NULL)
{
// get first empty selected property
pMainFrame->m_PropertyComboBar.SetFirstValidEmptyTargetProperty( crRayHit.cr_penHit);
}
}
// if ctrl+rmb pressed, we want to move entity selection in view plane
else if( bCtrl && !bShift && !bAlt)
{
if( bLMB) m_iaInputAction = IA_ROTATING_ENTITY_SELECTION;
else m_iaInputAction = IA_MOVING_ENTITY_SELECTION_IN_VIEW_PLANE;
StartMouseInput( point);
}
else if( bShift && bSpace && !GetChildFrame()->m_bAutoMipBrushingOn)
{
m_iaInputAction = IA_MANUAL_MIP_SWITCH_FACTOR_CHANGING;
}
else if( bShift && bAlt)
{
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( point, FALSE, bHitModels, bHitFields);
ShowLinkTree(crRayHit.cr_penHit, TRUE, bCaps);
}
else if( bShift)
{
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( point, FALSE, bHitModels, bHitFields);
ShowLinkTree(crRayHit.cr_penHit, FALSE, bCaps);
}
}
// if we are in vertex mode
else if( pDoc->GetEditingMode() == VERTEX_MODE)
{
if( bCtrl)
{
if( bLMB)
{
m_iaInputAction = IA_ROTATE_BRUSH_VERTEX;
}
else
{
m_iaInputAction = IA_DRAG_BRUSH_VERTEX_IN_VIEW_PLANE;
}
// clear polygon selection because some of the old polygons could disappear
pDoc->m_selPolygonSelection.Clear();
pDoc->m_woWorld.TriangularizeForVertices( pDoc->m_selVertexSelection);
StartMouseInput( point);
}
if( bShift)
{
if(pDoc->m_selVertexSelection.Count()==3)
{
pDoc->m_woWorld.CreatePolygon(pDoc->m_selVertexSelection);
pDoc->ClearSelections();
}
}
}
// if we are in terrain mode
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
InvokeSelectLayerCombo();
}
CView::OnRButtonDown(nFlags, point);
}
void CWorldEditorView::OnLButtonUp(UINT nFlags, CPoint point)
{
CWorldEditorDoc* pDoc = GetDocument();
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
BOOL bShift = nFlags & MK_SHIFT;
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
StopMouseInput();
// if measure mode on
if( theApp.m_bMeasureModeOn)
{
Invalidate( FALSE);
}
// if we are in browse by volume mode and lmb released, refresh first selected volume
if( pDoc->m_bBrowseEntitiesMode && !bSpace && !bCtrl)
{
pDoc->SelectEntitiesByVolumeBox();
}
if( pDoc->GetEditingMode() == ENTITY_MODE)
{
if( m_iaInputAction == IA_SELECTING_ENTITIES)
{
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( point, FALSE, TRUE, TRUE);
// if we hit some entity
if( crRayHit.cr_penHit != NULL)
{
// if shift is not pressed
if( !bShift)
{
BOOL bWasSelected = crRayHit.cr_penHit->IsSelected( ENF_SELECTED);
// deselect all selected entities
INDEX ctSelectedBefore = pDoc->m_selEntitySelection.Count();
pDoc->m_selEntitySelection.Clear();
// if entity was not selected before
if( !((ctSelectedBefore == 1) && bWasSelected))
{
// select it
pDoc->m_selEntitySelection.Select( *crRayHit.cr_penHit);
}
}
else
{
// if entity is not yet selected
if( !crRayHit.cr_penHit->IsSelected( ENF_SELECTED))
{
// select it
pDoc->m_selEntitySelection.Select( *crRayHit.cr_penHit);
}
// otherwise deselect it
else
{
pDoc->m_selEntitySelection.Deselect( *crRayHit.cr_penHit);
}
}
}
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
// and refresh property combo manualy calling on idle
pMainFrame->m_PropertyComboBar.m_PropertyComboBox.OnIdle( 0);
// update all views
pDoc->UpdateAllViews( this);
}
else if( m_iaInputAction == IA_SELECT_LASSO_ENTITY)
{
m_bRequestEntityLassoSelect = TRUE;
pDoc->m_chSelections.MarkChanged();
Invalidate( FALSE);
}
}
if( pDoc->GetEditingMode() == VERTEX_MODE)
{
if( m_iaInputAction == IA_SELECT_SINGLE_BRUSH_VERTEX)
{
m_bRequestVtxClickSelect = TRUE;
pDoc->m_chSelections.MarkChanged();
Invalidate( FALSE);
}
else if( m_iaInputAction == IA_SELECT_LASSO_BRUSH_VERTEX)
{
m_bRequestVtxLassoSelect = TRUE;
pDoc->m_chSelections.MarkChanged();
Invalidate( FALSE);
}
else if(
(m_iaInputAction == IA_DRAG_BRUSH_VERTEX_IN_FLOOR_PLANE) ||
(m_iaInputAction == IA_DRAG_BRUSH_VERTEX_IN_VIEW_PLANE) ||
(m_iaInputAction == IA_STRETCH_BRUSH_VERTEX) ||
(m_iaInputAction == IA_ROTATE_BRUSH_VERTEX) )
{
pDoc->m_woWorld.UpdateSectorsAfterVertexChange( pDoc->m_selVertexSelection);
}
}
m_iaInputAction = IA_NONE;
CView::OnLButtonUp(nFlags, point);
}
void CWorldEditorView::OnRButtonUp(UINT nFlags, CPoint point)
{
CWorldEditorDoc* pDoc = GetDocument();
if( m_iaInputAction == IA_MIP_SETTING)
{
SetMipBrushFactor();
}
else if(
(m_iaInputAction == IA_DRAG_BRUSH_VERTEX_IN_FLOOR_PLANE) ||
(m_iaInputAction == IA_DRAG_BRUSH_VERTEX_IN_VIEW_PLANE) ||
(m_iaInputAction == IA_STRETCH_BRUSH_VERTEX) ||
(m_iaInputAction == IA_ROTATE_BRUSH_VERTEX) )
{
pDoc->m_woWorld.UpdateSectorsAfterVertexChange( pDoc->m_selVertexSelection);
}
m_iaInputAction = IA_NONE;
StopMouseInput();
CView::OnRButtonUp(nFlags, point);
}
// select all descendents of selected entity
void SelectDescendents( CEntitySelection &selEntity, CEntity &enParent)
{
FOREACHINLIST( CEntity, en_lnInParent, enParent.en_lhChildren, itenChild)
{
SelectDescendents( selEntity, *itenChild);
}
if( !enParent.IsSelected( ENF_SELECTED))
{
selEntity.Select( enParent);
}
}
void CWorldEditorView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
m_iaInputAction = IA_NONE;
CWorldEditorDoc* pDoc = GetDocument();
BOOL bSpace = (GetKeyState( ' ') & 128) != 0;
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
BOOL bCtrl = nFlags & MK_CONTROL;
BOOL bShift = nFlags & MK_SHIFT;
BOOL bRMB = (GetKeyState( VK_RBUTTON)&0x8000) != 0;
// space+ctrl+lmb zoomes in 2x
if( (bSpace) && (bCtrl))
{
if( bRMB) return;
// set new target
GetChildFrame()->m_mvViewer.SetTargetPlacement( m_vHitOnMouseDown);
// move mouse to center of screen
CPoint ptCenter = CPoint( m_pdpDrawPort->GetWidth()/2, m_pdpDrawPort->GetHeight()/2);
ClientToScreen( &ptCenter);
SetCursorPos(ptCenter.x, ptCenter.y);
OnZoomMore();
pDoc->UpdateAllViews( NULL);
return;
}
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( point);
// space + doubble click center point that mouse points to
if( bSpace)
{
// set new target
GetChildFrame()->m_mvViewer.SetTargetPlacement( crRayHit.cr_vHit);
// update all views
pDoc->UpdateAllViews( NULL);
}
// if we are in measure or cut mode, no operation
else if( theApp.m_bMeasureModeOn || theApp.m_bCutModeOn)
{
}
// if we are in sector mode, no operation
else if( pDoc->GetEditingMode() == SECTOR_MODE)
{
}
// if we are in polygon mode, select similar polygons
else if( pDoc->GetEditingMode() == POLYGON_MODE)
{
// Alt+Ctrl+RMB requests that clicked polygon sizes its texture
if( bAlt && bCtrl)
{
MultiplyMappingOnPolygon( 0.5f);
}
// if we hit some brush entity
else if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL))
{
// if shift is not pressed, delelect all polygons
if( !bShift && !bCtrl)
{
pDoc->m_selPolygonSelection.Clear();
}
// LMBx2 centers mapping on polygon
if( bCtrl && !bShift &&(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
CBrushPolygon &bpo = *crRayHit.cr_pbpoBrushPolygon;
CEntity *pen = bpo.bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
CMappingDefinition mdOriginal = bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
CMappingDefinition mdTranslated = mdOriginal;
CSimpleProjection3D pr;
pr.ObjectPlacementL() = _plOrigin;
pr.ViewerPlacementL() = pen->GetPlacement();
pr.Prepare();
FLOAT3D vRelative;
pr.ProjectCoordinate(crRayHit.cr_vHit, vRelative);
CMappingDefinition mdRelative = theApp.m_mdMapping;
mdTranslated.Center(bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative, vRelative);
FLOAT fUOffset = mdTranslated.md_fUOffset-mdOriginal.md_fUOffset;
FLOAT fVOffset = mdTranslated.md_fVOffset-mdOriginal.md_fVOffset;
if( !crRayHit.cr_pbpoBrushPolygon->IsSelected(BPOF_SELECTED))
{
// add the offsets to its mapping
crRayHit.cr_pbpoBrushPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fUOffset+=fUOffset;
crRayHit.cr_pbpoBrushPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fVOffset+=fVOffset;
}
else
{
// for each selected polygon
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
// add the offsets to its mapping
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fUOffset+=fUOffset;
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fVOffset+=fVOffset;
}
}
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
// Ctrl+Shift+LMBx2 slects similar by texture in sector
else if( bCtrl && bShift)
{
OnSelectByTextureInSector();
}
else
{
// select similar to hitted polygon
crRayHit.cr_pbpoBrushPolygon->SelectSimilarByColor( pDoc->m_selPolygonSelection);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
}
}
else if( pDoc->GetEditingMode() == VERTEX_MODE)
{
// if we hit some polygon
if( (crRayHit.cr_penHit != NULL) && (crRayHit.cr_pbpoBrushPolygon != NULL))
{
CBrushPolygon &bpo=*crRayHit.cr_pbpoBrushPolygon;
// select vertices
FOREACHINSTATICARRAY(bpo.bpo_apbvxTriangleVertices, CBrushVertex *, itpbvx)
{
if( !(*itpbvx)->IsSelected(BVXF_SELECTED)) pDoc->m_selVertexSelection.Select( **itpbvx);
}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
}
// if we are in entity mode
else if( pDoc->GetEditingMode() == ENTITY_MODE)
{
// if nothing pressed
if( !bCtrl && !bAlt && !bSpace)
{
if( crRayHit.cr_penHit != NULL)
{
SelectDescendents( pDoc->m_selEntitySelection, *crRayHit.cr_penHit);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
}
// CTRL + LMB teleports entities
if( (pDoc->m_selEntitySelection.Count() != 0) && (bCtrl) && (!bAlt) )
{
// lock selection's dynamic container
pDoc->m_selEntitySelection.Lock();
FLOATaabbox3D box;
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
box |= iten->GetPlacement().pl_PositionVector;
}}
FLOAT3D f3dCenter = box.Center();
f3dCenter(2) = box.Min()(2);
FLOAT3D f3dOffset = crRayHit.cr_vHit - f3dCenter;
CEntity *penBrush = NULL;
// for each of the selected entities
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
if (iten->en_RenderType == CEntity::RT_BRUSH) {
penBrush = &*iten;
}
// if movement of anchored entities is allowed or entity is not anchored
if( (((iten->GetFlags() & ENF_ANCHORED) == 0) ||
(GetChildFrame()->m_bAncoredMovingAllowed)) &&
((iten->GetParent()==NULL) || !(iten->GetParent()->IsSelected( ENF_SELECTED))) )
{
// get placement of current entity
CPlacement3D plEntityPlacement = iten->GetPlacement();
plEntityPlacement.pl_PositionVector += f3dOffset;
// snap to grid entity's placement
pDoc->SnapToGrid( plEntityPlacement, m_fGridInMeters/GRID_DISCRETE_VALUES);
// set placement back to entity
iten->SetPlacement( plEntityPlacement);
// mark that document is changed
pDoc->SetModifiedFlag();
}
if( penBrush != NULL)
{
DiscardShadows( penBrush);
}
}
}
pDoc->UpdateAllViews( NULL);
// refresh position page
pDoc->RefreshCurrentInfoPage();
}
// if we are in csg mode, CTRL + LMB teleports second layer's world (primitive)
else if( (pDoc->GetEditingMode() == CSG_MODE) && bCtrl)
{
// set new placement of second layer
pDoc->m_plSecondLayer.pl_PositionVector = crRayHit.cr_vHit;
// snap to grid whole second layer's placement
pDoc->SnapToGrid( pDoc->m_plSecondLayer, m_fGridInMeters/GRID_DISCRETE_VALUES);
theApp.m_vfpCurrent.vfp_plPrimitive = pDoc->m_plSecondLayer;
// refresh all views
pDoc->UpdateAllViews( NULL);
// refresh position page
pDoc->RefreshCurrentInfoPage();
}
CView::OnLButtonDblClk(nFlags, point);
}
void CWorldEditorView::CallPopupMenu(CPoint point)
{
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
BOOL bHitFields = (pDoc->GetEditingMode() == ENTITY_MODE);
// obtain information about where mouse pointed into the world in the moment of mouse down
CCastRay crRayHitOnContext = GetMouseHitInformation( point, FALSE, TRUE, bHitFields);
// create popup menu
CMenu menu;
INDEX iMenuID;
// choose popup menu
switch( pDoc->GetEditingMode())
{
case POLYGON_MODE:{ iMenuID = IDR_POLYGON_POPUP; break; }
case SECTOR_MODE:{ iMenuID = IDR_SECTOR_POPUP;break; }
case VERTEX_MODE:{ iMenuID = IDR_VERTEX_POPUP;break; }
case ENTITY_MODE:{ iMenuID = IDR_ENTITY_POPUP;break; }
case TERRAIN_MODE:{ iMenuID = IDR_TERRAIN_POPUP;break; }
case CSG_MODE:
{
if( pDoc->m_bPrimitiveMode) iMenuID = IDR_CSG_PRIMITIVE_POPUP;
else iMenuID = IDR_CSG_TEMPLATE_POPUP;
break;
}
default: { FatalError("Unknown editing mode."); break;};
}
// load popup menu
if( menu.LoadMenu(iMenuID))
{
BOOL bEntityClicked = FALSE;
BOOL bBrushClicked = FALSE;
BOOL bSecondLayerHited = FALSE;
BOOL bPortalClicked = FALSE;
m_penEntityHitOnContext = NULL;
if( crRayHitOnContext.cr_penHit != NULL)
{
m_penEntityHitOnContext = crRayHitOnContext.cr_penHit;
bEntityClicked = TRUE;
// test if we hited second layer
if( crRayHitOnContext.cr_penHit->GetWorld() != &pDoc->m_woWorld)
{
bSecondLayerHited = TRUE;
}
m_plEntityHitOnContext = crRayHitOnContext.cr_penHit->GetPlacement();
m_plEntityHitOnContext.pl_PositionVector = crRayHitOnContext.cr_vHit;
CEntity::RenderType rt = crRayHitOnContext.cr_penHit->GetRenderType();
if( rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
{
bBrushClicked = TRUE;
}
m_pbpoRightClickedPolygon = crRayHitOnContext.cr_pbpoBrushPolygon;
if( m_pbpoRightClickedPolygon != NULL)
{
bPortalClicked = m_pbpoRightClickedPolygon->bpo_ulFlags & BPOF_PORTAL;
}
}
// remember if we hited any entity with cntext menu
m_bEntityHitedOnContext = bEntityClicked;
CMenu* pPopup = menu.GetSubMenu(0);
pPopup->EnableMenuItem( ID_ENTITY_CONTEXT_HELP, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_SET_AS_CSG_TARGET, MF_DISABLED|MF_GRAYED);
if(bBrushClicked && !bSecondLayerHited) pPopup->EnableMenuItem(ID_SET_AS_CSG_TARGET, MF_ENABLED);
// disable commands that can't be applied
switch( pDoc->GetEditingMode())
{
case POLYGON_MODE:
{
pPopup->EnableMenuItem(ID_POLYGON_MODE, MF_DISABLED|MF_GRAYED);
if( !bPortalClicked)
{
pPopup->EnableMenuItem(ID_SELECT_SECTORS_OTHER_SIDE, MF_DISABLED|MF_GRAYED);
}
if( !bBrushClicked)
{
pPopup->EnableMenuItem(ID_MENU_COPY_MAPPING, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_COPY_TEXTURE, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_SELECT_BY_TEXTURE_ADJACENT, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_SELECT_BY_TEXTURE_IN_SECTOR, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_SELECT_BY_COLOR_IN_SECTOR, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_FIND_TEXTURE, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_DESELECT_BY_ORIENTATION, MF_DISABLED|MF_GRAYED);
}
if( pDoc->m_selPolygonSelection.Count() == 0)
{
pPopup->EnableMenuItem(ID_FILTER_SELECTION, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_CHOOSE_COLOR, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_EXPORT_DISPLACE_MAP, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_RANDOM_OFFSET_U, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_RANDOM_OFFSET_V, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_POLYGONS_TO_BRUSH, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_CLONE_POLYGONS, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_DELETE_POLYGONS, MF_DISABLED|MF_GRAYED);
}
if( !pDoc->m_woWorld.CanJoinPolygons( pDoc->m_selPolygonSelection))
{
pPopup->EnableMenuItem( ID_CSG_JOIN_POLYGONS, MF_DISABLED|MF_GRAYED);
}
if( !pDoc->m_woWorld.CanJoinAllPossiblePolygons( pDoc->m_selPolygonSelection))
{
pPopup->EnableMenuItem( ID_CSG_JOIN_ALL_POLYGONS, MF_DISABLED|MF_GRAYED);
}
BOOL bEnableRetripling = FALSE;
if( pDoc->m_selPolygonSelection.Count() != 0)
{
CBrushPolygon *pbpo = pDoc->m_selPolygonSelection.GetFirstInSelection();
bEnableRetripling = pbpo->bpo_pbscSector->IsReTripleAvailable( pDoc->m_selPolygonSelection);
}
if( !bEnableRetripling)
{
pPopup->EnableMenuItem( ID_RE_TRIPLE, MF_DISABLED|MF_GRAYED);
}
if( !pDoc->m_woWorld.CanJoinPolygons( pDoc->m_selPolygonSelection))
{
pPopup->EnableMenuItem( ID_CSG_JOIN_POLYGONS, MF_DISABLED|MF_GRAYED);
}
break;
}
case SECTOR_MODE:
{
if( !bBrushClicked)
{
pPopup->EnableMenuItem(ID_SELECT_LINKS_TO_SECTOR, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_SELECT_SECTORS_WITH_SAME_NAME, MF_DISABLED|MF_GRAYED);
}
if( pDoc->m_selSectorSelection.Count() == 0)
{
pPopup->EnableMenuItem(ID_HIDE_SELECTED_SECTORS, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_HIDE_UNSELECTED_SECTORS, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_DELETE_SECTORS, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_CHOOSE_COLOR, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_SECTORS_TO_BRUSH, MF_DISABLED|MF_GRAYED);
}
if( !pDoc->m_woWorld.CanCopySectors(pDoc->m_selSectorSelection))
{
pPopup->EnableMenuItem( ID_COPY_SECTORS, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem( ID_EDIT_COPY_ALTERNATIVE, MF_DISABLED|MF_GRAYED);
}
if( pDoc->m_woWorld.CanJoinSectors(pDoc->m_selSectorSelection))
{
pPopup->EnableMenuItem( ID_CSG_JOIN_SECTORS, MF_DISABLED|MF_GRAYED);
}
break;
}
case TERRAIN_MODE:
{
CTerrain *ptrTerrain=GetTerrain();
if(ptrTerrain==NULL)
{
pPopup->EnableMenuItem( ID_PICK_LAYER, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem( ID_SELECT_LAYER, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem( ID_CHANGE_TERRAIN_SIZE, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem( ID_CHANGE_HEIGHTMAP_SIZE, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem( ID_RECALCULATE_TERRAIN_SHADOWS, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem( ID_OPTIMIZE_TERRAIN, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem( ID_IMPORT_HEIGHTMAP, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem( ID_IMPORT_HEIGHTMAP16, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem( ID_EXPORT_HEIGHTMAP, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem( ID_EXPORT_HEIGHTMAP16, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem( ID_VIEW_HEIGHTMAP, MF_DISABLED|MF_GRAYED);
CTerrainLayer *ptlLayer=GetLayer();
if(ptlLayer==NULL)
{
pPopup->EnableMenuItem( ID_LAYER_OPTIONS, MF_DISABLED|MF_GRAYED);
}
}
break;
}
case ENTITY_MODE:
{
if( bEntityClicked)
{
pPopup->EnableMenuItem(ID_ENTITY_CONTEXT_HELP, MF_ENABLED);
}
BOOL bDisableSelectTarget = FALSE;
if( pDoc->m_selEntitySelection.Count() == 1)
{
CPropertyID *ppidProperty = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
if( (ppidProperty == NULL) ||
!((ppidProperty->pid_eptType == CEntityProperty::EPT_PARENT) ||
(ppidProperty->pid_eptType == CEntityProperty::EPT_ENTITYPTR)))
{
bDisableSelectTarget = TRUE;
}
}
else
{
bDisableSelectTarget = TRUE;
}
if( bDisableSelectTarget)
{
pPopup->EnableMenuItem(ID_SELECT_TARGET, MF_DISABLED|MF_GRAYED);
}
pPopup->EnableMenuItem(ID_ENTITY_MODE, MF_DISABLED|MF_GRAYED);
// see if should disable delete
if( !IsDeleteEntityEnabled())
{
pPopup->EnableMenuItem(ID_DELETE_ENTITIES, MF_DISABLED|MF_GRAYED);
}
// if clear all target is disabled
if( !m_bEntityHitedOnContext)
{
pPopup->EnableMenuItem(ID_ROTATE_TO_TARGET_ORIGIN, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_ROTATE_TO_TARGET_CENTER, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_COPY_POSITION, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_COPY_ORIENTATION, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_COPY_PLACEMENT, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_PASTE_POSITION, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_CLEAR_ALL_TARGETS, MF_DISABLED|MF_GRAYED);
}
// if clone updating is disabled
if( !pDoc->IsCloneUpdatingAllowed())
{
pPopup->EnableMenuItem(ID_UPDATE_CLONES, MF_DISABLED|MF_GRAYED);
}
// if brush updating is disabled
if( !pDoc->IsBrushUpdatingAllowed())
{
pPopup->EnableMenuItem(ID_UPDATE_BRUSHES, MF_DISABLED|MF_GRAYED);
}
// if copy is not allowed
if( pDoc->m_selEntitySelection.Count() == 0)
{
pPopup->EnableMenuItem(ID_EDIT_COPY, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_SELECT_DESCENDANTS, MF_DISABLED|MF_GRAYED);
}
// if clipboard world does not exist
if( GetFileAttributesA( _fnmApplicationPath + "Temp\\ClipboardWorld.wld") == -1)
{
// disable pasting
pPopup->EnableMenuItem(ID_EDIT_PASTE, MF_DISABLED|MF_GRAYED);
}
if( !IsSelectClonesOnContextEnabled())
{
// disable select clones
pPopup->EnableMenuItem(ID_SELECT_CLONES_ON_CONTEXT, MF_DISABLED|MF_GRAYED);
}
if( !IsSelectOfSameClassOnContextEnabled())
{
// disable select clones
pPopup->EnableMenuItem(ID_SELECT_OF_SAME_CLASS_ON_CONTEXT, MF_DISABLED|MF_GRAYED);
}
break;
}
}
// convert mouse coordinates into screen coordinates
ClientToScreen( &point);
// call popup menu
pPopup->TrackPopupMenu( TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
point.x, point.y, this);
}
}
void CWorldEditorView::SetEditingDataPaneInfo( BOOL bImidiateRepainting)
{
// obtain current time
FLOAT fTimeNow = _pTimer->GetRealTimeTick();
// get difference to time when last mip brushing option has been used
FLOAT fSecondsPassed = fTimeNow-_fLastMipBrushingOptionUsed;
// if we used any mip brushing option inside last 30 seconds
BOOL bUsingMipBrushing;
if( fSecondsPassed < 120) bUsingMipBrushing = TRUE;
else bUsingMipBrushing = FALSE;
// get draw port
CDrawPort *pdpValidDrawPort = GetDrawPort();
// if it is not valid
if( pdpValidDrawPort == NULL)
{
return;
}
if( !theApp.m_bShowStatusInfo)
{
return;
}
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CWorldEditorDoc* pDoc = GetDocument();
char strDataPaneText[ 128];
// obtain button statuses and interesting flags
BOOL bSpace = (GetKeyState( ' ') & 128) != 0;
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
BOOL bLMB = (GetKeyState( VK_LBUTTON)&0x8000) != 0;
BOOL bRMB = (GetKeyState( VK_RBUTTON)&0x8000) != 0;
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
BOOL bEntityMode = pDoc->GetEditingMode() == ENTITY_MODE;
BOOL bPolygonMode = pDoc->GetEditingMode() == POLYGON_MODE;
BOOL bTerrainMode = pDoc->GetEditingMode() == TERRAIN_MODE;
BOOL bVertexMode = pDoc->GetEditingMode() == VERTEX_MODE;
CEntity *penBrush = pMainFrame->m_CSGDesitnationCombo.GetSelectedBrushEntity();
// create a slave viewer
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pdpValidDrawPort);
//---------------- Now we will prepare status line' text describing editing data
if( theApp.m_bMeasureModeOn)
{
strcpy( strDataPaneText, m_strMeasuring);
}
else if( theApp.m_bCutModeOn)
{
sprintf( strDataPaneText, "Cut/Mirror mode");
}
else if( (penBrush != NULL) && bUsingMipBrushing)
{
CBrush3D *pbrBrush = penBrush->GetBrush();
ASSERT( pbrBrush != NULL);
// get currently active mip factor
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
// get mip brush
if( pbrBrush != NULL)
{
CBrushMip *pbmCurrentMip = pbrBrush->GetBrushMipByDistance( fCurrentMipFactor);
if( pbmCurrentMip != NULL)
{
// get mip switch factor for currently visible brush
FLOAT fCurrentMipSwitchFactor = pbmCurrentMip->GetMipDistance();
// so prepare string telling selected brush's mip switch factor
sprintf( strDataPaneText, "factor=%.2f, mip=%d/%d, switch=%.2f",
fCurrentMipFactor, pbmCurrentMip->GetMipIndex(),
pbrBrush->br_lhBrushMips.Count(), fCurrentMipSwitchFactor);
}
else
{
// so prepare string telling selected brush's mip switch factor
sprintf( strDataPaneText, "factor=%.2f, after last mip", fCurrentMipFactor);
}
}
else
{
// brush wasn't valid, report error
sprintf( strDataPaneText, "entity has invalid brush");
}
}
// if space pressed, we are interested in viewer placement
else if( bSpace)
{
// get viewer position and orientation data
CPlacement3D plViewer = GetChildFrame()->m_mvViewer.GetViewerPlacement();
// if both mouses are pressed, we want to rotate viewer
if( bLMB && bRMB)
{
// so prepare string telling viewer orientation
sprintf( strDataPaneText, "H=%g P=%g B=%g",
DegAngle( plViewer.pl_OrientationAngle(1)),
DegAngle( plViewer.pl_OrientationAngle(2)),
DegAngle( plViewer.pl_OrientationAngle(3)) );
}
// we are interested in viewer's current position
else
{
// so prepare string telling viewer position
sprintf( strDataPaneText, "X=%g Y=%g Z=%g",
plViewer.pl_PositionVector(1),
plViewer.pl_PositionVector(2),
plViewer.pl_PositionVector(3) );
}
}
else if( (bVertexMode) && ( pDoc->m_selVertexSelection.Count() != 0) )
{
// so prepare string telling entity position
if (pDoc->m_selVertexSelection.Count()==1) {
const FLOAT3D &v = pDoc->m_selVertexSelection.GetFirst().bvx_vAbsolute;
sprintf( strDataPaneText, "%f,%f,%f", v(1), v(2), v(3));
} else {
sprintf( strDataPaneText, "Dragging %d vertices", pDoc->m_selVertexSelection.Count());
}
}
// if we are in entity mode and there is selected entity
else if( (bEntityMode) && ( pDoc->m_selEntitySelection.Count() != 0) )
{
// lock selection's dynamic container
pDoc->m_selEntitySelection.Lock();
// get first entity
CEntity *penEntityOne = pDoc->m_selEntitySelection.Pointer(0);
// unlock selection's dynamic container
pDoc->m_selEntitySelection.Unlock();
// get placement of first entity
CPlacement3D plEntityOnePlacement = penEntityOne->GetPlacement();
// if both mouses are pressed, we want to rotate entity so prepare text telling angles
if( bLMB && bRMB)
{
// so prepare string telling entity orientation
sprintf( strDataPaneText, "H=%g P=%g B=%g",
DegAngle( plEntityOnePlacement.pl_OrientationAngle(1)),
DegAngle( plEntityOnePlacement.pl_OrientationAngle(2)),
DegAngle( plEntityOnePlacement.pl_OrientationAngle(3)) );
}
// we are interested in entity one's current position
else
{
// so prepare string telling entity position
sprintf( strDataPaneText, "X=%g Y=%g Z=%g",
plEntityOnePlacement.pl_PositionVector(1),
plEntityOnePlacement.pl_PositionVector(2),
plEntityOnePlacement.pl_PositionVector(3) );
}
}
// if we are in polygon mode and only one polygon is selected
else if( (bPolygonMode) && (pDoc->m_selPolygonSelection.Count() == 1) && bCtrl)
{
pDoc->m_selPolygonSelection.Lock();
CBrushPolygon *pbpoBrushPolygon = pDoc->m_selPolygonSelection.Pointer(0);
pDoc->m_selPolygonSelection.Unlock();
CMappingDefinitionUI mdui;
pbpoBrushPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.ToUI( mdui);
// prepare text telling about mapping info
sprintf( strDataPaneText, "Tex %d: U=%.1f V=%.1f RU=%.1f RV=%.1f",
pDoc->m_iTexture+1, mdui.mdui_fUOffset, mdui.mdui_fVOffset,
mdui.mdui_aURotation, mdui.mdui_aVRotation);
}
else if( bTerrainMode)
{
// pane data text has bee obtained on render's ray cast
sprintf(strDataPaneText, "%s", m_strTerrainDataPaneText);
}
else if( bCSGOn)
{
// if primitive mode on and ctrl+shift+RMB pressed
if( pDoc->m_bPrimitiveMode && bCtrl && bShift && bRMB)
{
// prepare pane text telling primitive shear info
sprintf( strDataPaneText, "Shear X=%g Shear Z=%g",
theApp.m_vfpCurrent.vfp_fShearX, theApp.m_vfpCurrent.vfp_fShearZ);
}
// if primitive mode on and ctrl+shift+LMB pressed
else if( pDoc->m_bPrimitiveMode && bCtrl && bShift)
{
// prepare pane text telling primitive size info
sprintf( strDataPaneText, "W=%g H=%g L=%g",
theApp.m_vfpCurrent.vfp_fXMax-theApp.m_vfpCurrent.vfp_fXMin,
theApp.m_vfpCurrent.vfp_fYMax-theApp.m_vfpCurrent.vfp_fYMin,
theApp.m_vfpCurrent.vfp_fZMax-theApp.m_vfpCurrent.vfp_fZMin);
}
// else if ctrl and both mouses are pressed
else if( bCtrl && bLMB && bRMB)
{
// prepare text telling CSG layer orientation
sprintf( strDataPaneText, "H=%g P=%g B=%g",
DegAngle( pDoc->m_plSecondLayer.pl_OrientationAngle(1)),
DegAngle( pDoc->m_plSecondLayer.pl_OrientationAngle(2)),
DegAngle( pDoc->m_plSecondLayer.pl_OrientationAngle(3)) );
}
// else
else
{
// prepare text telling CSG layer position
sprintf( strDataPaneText, "X=%g Y=%g Z=%g",
pDoc->m_plSecondLayer.pl_PositionVector(1),
pDoc->m_plSecondLayer.pl_PositionVector(2),
pDoc->m_plSecondLayer.pl_PositionVector(3) );
}
}
else
{
// sprintf( strDataPaneText, "Idle time");
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if any kind of entity was hitted
if( crRayHit.cr_penHit != NULL)
{
// get hitted coordinate
FLOAT3D f3Coordinate = crRayHit.cr_vHit;
// snap it
SnapVector( f3Coordinate);
// prepare text describing hitted coordinate
sprintf( strDataPaneText, "X=%g Y=%g Z=%g", f3Coordinate(1), f3Coordinate(2), f3Coordinate(3));
}
else
{
// if the ray hits the empty space
sprintf( strDataPaneText, "Over nothing");
}
}
// put editing data info into status line
pMainFrame->m_wndStatusBar.SetPaneText( POSITION_PANE, CString(strDataPaneText), bImidiateRepainting);
}
#define SCROLL_CHANGE 0.2f
#define ZOOM_CHANGE 0.05f
#define ANGLE_CHANGE 1.0f
void CWorldEditorView::OnMouseMove(UINT nFlags, CPoint point)
{
BOOL bLMB = (GetKeyState( VK_LBUTTON)&0x8000) != 0;
BOOL bRMB = (GetKeyState( VK_RBUTTON)&0x8000) != 0;
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
if(((m_iaInputAction == IA_SELECT_LASSO_ENTITY) ||
(m_iaInputAction == IA_SELECT_LASSO_BRUSH_VERTEX)) && !bLMB)
{
m_iaInputAction = IA_NONE;
// discard laso selection
m_avpixLaso.Clear();
}
// if neather mouse key is pressed, simulate that action is none
if( !bLMB && !bRMB) m_iaInputAction = IA_NONE;
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CWorldEditorDoc* pDoc = GetDocument();
CWorldEditorView *pWorldEditorView = theApp.GetActiveView();
if( pWorldEditorView == NULL) return;
HWND hwndUnderMouse = ::WindowFromPoint( point);
HWND hwndInfo = NULL;
if( pMainFrame->m_pInfoFrame != NULL)
{
hwndInfo = pMainFrame->m_pInfoFrame->m_hWnd;
}
HWND hwndFocused = ::GetFocus();
//HWND hwndForeground = ::GetForegroundWindow();
//if( hwndForeground==pMainFrame->m_hWnd)
{
// if this is the first mouse move over new view and it is not over info window,
// set focus and loose all previous actions
if( (m_hWnd != hwndFocused) && ( hwndInfo != hwndUnderMouse) )
{
SetActiveWindow();
SetFocus();
GetChildFrame()->SetActiveView( this);
pMainFrame->MDIActivate(GetParentFrame());
// cancel any possible previous actions
m_iaInputAction = IA_NONE;
}
}
CDrawPort *pdpValidDrawPort = GetDrawPort();
if( pdpValidDrawPort == NULL) return;
CView::OnMouseMove(nFlags, point);
CPoint ptScreen = point;
LONG lOffsetX = point.x - m_ptMouse.x;
LONG lOffsetY = point.y - m_ptMouse.y;
float fOriginOffsetX = (FLOAT) (point.x - m_ptMouseDown.x);
float fOriginOffsetY = (FLOAT) (point.y - m_ptMouseDown.y);
//_RPT2(_CRT_WARN, "%f %f\n", fOriginOffsetX, fOriginOffsetY);
// create a slave viewer
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pdpValidDrawPort);
BOOL bHitModels = (pDoc->GetEditingMode() != POLYGON_MODE) &&
(pDoc->GetEditingMode() != TERRAIN_MODE);
BOOL bHitFields = pDoc->GetEditingMode() == ENTITY_MODE;
BOOL bHitBrushes = pDoc->GetEditingMode() != TERRAIN_MODE;
// set dummy ray hit result
CCastRay crRayHit( NULL, CPlacement3D(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0)) );
BOOL bRayHitNeeded;
if( (m_iaInputAction == IA_MOVING_VIEWER_IN_FLOOR_PLANE) ||
(m_iaInputAction == IA_MOVING_VIEWER_IN_VIEW_PLANE) ||
(m_iaInputAction == IA_ROTATING_VIEWER) ||
(m_iaInputAction == IA_MOVING_SECOND_LAYER_IN_FLOOR_PLANE) ||
(m_iaInputAction == IA_MOVING_SECOND_LAYER_IN_VIEW_PLANE) ||
(m_iaInputAction == IA_ROTATING_SECOND_LAYER) ||
(m_iaInputAction == IA_MOVING_ENTITY_SELECTION_IN_FLOOR_PLANE) ||
(m_iaInputAction == IA_MOVING_ENTITY_SELECTION_IN_VIEW_PLANE) ||
(m_iaInputAction == IA_ROTATING_ENTITY_SELECTION) ||
(m_iaInputAction == IA_DRAG_BRUSH_VERTEX_IN_FLOOR_PLANE) ||
(m_iaInputAction == IA_DRAG_BRUSH_VERTEX_IN_VIEW_PLANE) ||
(m_iaInputAction == IA_SELECT_LASSO_ENTITY) ||
(m_iaInputAction == IA_SELECT_LASSO_BRUSH_VERTEX) ||
(m_iaInputAction == IA_STRETCH_BRUSH_VERTEX) ||
(m_iaInputAction == IA_ROTATE_BRUSH_VERTEX) ) {
bRayHitNeeded = FALSE;
} else {
bRayHitNeeded = TRUE;
}
BOOL bSelectPortals = FALSE;
// for right mouse button select portals
if( bRMB)
{
bSelectPortals = TRUE;
}
if( bRayHitNeeded)
{
crRayHit = GetMouseHitInformation( m_ptMouse, bSelectPortals, bHitModels, bHitFields, NULL, bHitBrushes);
if(abs(lOffsetX)>=1 || abs(lOffsetY)>=1)
{
theApp.m_vLastTerrainHit=crRayHit.cr_vHit;
theApp.m_penLastTerrainHit=crRayHit.cr_penHit;
}
m_strTerrainDataPaneText="Terrain not hit";
if( pDoc->GetEditingMode() == TERRAIN_MODE && !_pInput->IsInputEnabled())
{
if( (crRayHit.cr_penHit!=NULL) && (crRayHit.cr_penHit->GetRenderType() == CEntity::RT_TERRAIN))
{
CTerrain *ptrTerrain=crRayHit.cr_penHit->GetTerrain();
INDEX iLayerBeneath=-1;
UBYTE ubLayerPower=0;
INDEX ctLayers=ptrTerrain->tr_atlLayers.Count();
for(INDEX iLayer=0; iLayer<ctLayers; iLayer++)
{
UBYTE ubPower=GetValueFromMask(ptrTerrain, iLayer, crRayHit.cr_vHit);
if(ubPower>0)
{
iLayerBeneath=iLayer;
ubLayerPower=ubPower;
}
}
if(iLayerBeneath!=-1)
{
if(theApp.m_iTerrainEditMode==TEM_HEIGHTMAP)
{
if( bCtrl&&bAlt)
{
Point pt=Calculate2dHitPoint(ptrTerrain, crRayHit.cr_vHit);
INDEX iWidth=ptrTerrain->tr_pixHeightMapWidth;
UWORD uwAltitude=*(ptrTerrain->tr_auwHeightMap+iWidth*pt.pt_iY+pt.pt_iX);
FLOAT fAltitudeBeneath=FLOAT(uwAltitude)/65535*ptrTerrain->tr_vTerrainSize(2);
m_strTerrainDataPaneText.PrintF("Altitude: %g", fAltitudeBeneath);
}
else
{
FLOAT fReferenceAltitude=FLOAT(theApp.m_uwEditAltitude)/65535*ptrTerrain->tr_vTerrainSize(2);
m_strTerrainDataPaneText.PrintF("Reference altitude: %g", fReferenceAltitude);
}
}
else
{
m_strTerrainDataPaneText.PrintF("Layer: %d (%d%%)", iLayerBeneath+1, INDEX(ubLayerPower/255.0f*100.0f));
}
}
else
{
m_strTerrainDataPaneText.PrintF("No layers");
}
}
else
{
m_strTerrainDataPaneText.PrintF("No terrain hit");
}
}
}
BOOL bRefreshView = FALSE;// view refresh is not needed for now
BOOL bObjectMoved = FALSE;// nothing has moved for now
BOOL bRepaintImmediately = FALSE; // force immediate repainting
BOOL bRecreatePrimitive = FALSE;// there is no need for recreating primitive
// act acording to action started in OnLButtonDown() and OnRButtonDown()
switch( m_iaInputAction)
{
case IA_MIP_SETTING:
{
// remember current time as time when last mip brushing option has been used
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
if( lOffsetY > 0) lOffsetY = 0;
// translate viewer in floor plane
svViewer.Translate_OwnSystem( 0, 0, -lOffsetY);
// set new viewer position
GetChildFrame()->m_mvViewer = svViewer;
bRefreshView = TRUE;
break;
}
case IA_MANUAL_MIP_SWITCH_FACTOR_CHANGING:
{
if( GetChildFrame()->m_fManualMipBrushingFactor - lOffsetY/50.0f > 0.0f)
{
// remember current time as time when last mip brushing option has been used
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
GetChildFrame()->m_fManualMipBrushingFactor -= lOffsetY/50.0f;
}
bRefreshView = TRUE;
break;
}
case IA_ROTATING_VIEWER:
{
svViewer.Rotate_HPB( lOffsetX, lOffsetY, 0);
// set new viewer position
GetChildFrame()->m_mvViewer = svViewer;
bRefreshView = TRUE;
break;
}
case IA_MOVING_VIEWER_IN_FLOOR_PLANE:
{
// translate viewer in floor plane
svViewer.Translate_OwnSystem( lOffsetX, lOffsetY, 0);
// set new viewer position
GetChildFrame()->m_mvViewer = svViewer;
bRefreshView = TRUE;
break;
}
case IA_MOVING_VIEWER_IN_VIEW_PLANE:
{
// translate viewer in view plane
svViewer.Translate_OwnSystem( lOffsetX, 0, -lOffsetY);
// set new viewer position
GetChildFrame()->m_mvViewer = svViewer;
bRefreshView = TRUE;
break;
}
case IA_SHEARING_PRIMITIVE:
{
// get translation vector in view space
FLOAT fZoom = svViewer.GetZoomFactor();
CPlacement3D plVector0(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
CPlacement3D plVector1(
FLOAT3D( fOriginOffsetX/fZoom, -fOriginOffsetY/fZoom, 0.0f),
ANGLE3D(0,0,0));
// project translation vector from view space to absolute space
CPlacement3D plViewer = svViewer.GetViewerPlacement();
plVector0.RelativeToAbsolute(plViewer);
plVector1.RelativeToAbsolute(plViewer);
// project translation vector from absolute space to second layer space
plVector0.AbsoluteToRelative(pDoc->m_plSecondLayer);
plVector1.AbsoluteToRelative(pDoc->m_plSecondLayer);
// extract translation vector from placements
FLOAT3D vSizeDelta = plVector1.pl_PositionVector-plVector0.pl_PositionVector;
// apply mouse movement
theApp.m_vfpCurrent.vfp_fShearX = m_VFPMouseDown.vfp_fShearX+vSizeDelta(1);
theApp.m_vfpCurrent.vfp_fShearZ = m_VFPMouseDown.vfp_fShearZ+vSizeDelta(3);
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fShearX, m_fGridInMeters/GRID_DISCRETE_VALUES);
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fShearZ, m_fGridInMeters/GRID_DISCRETE_VALUES);
bRefreshView = TRUE;
bRecreatePrimitive = TRUE;
break;
}
case IA_STRETCHING_PRIMITIVE:
{
// get translation vector in view space
FLOAT fZoom = svViewer.GetZoomFactor();
CPlacement3D plVector0(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
CPlacement3D plVector1(
FLOAT3D( fOriginOffsetX/fZoom, -fOriginOffsetY/fZoom,0.0f),
ANGLE3D(0,0,0));
// project translation vector from view space to absolute space
CPlacement3D plViewer = svViewer.GetViewerPlacement();
plVector0.RelativeToAbsolute(plViewer);
plVector1.RelativeToAbsolute(plViewer);
// project translation vector from absolute space to second layer space
plVector0.AbsoluteToRelative(pDoc->m_plSecondLayer);
plVector1.AbsoluteToRelative(pDoc->m_plSecondLayer);
// extract translation vector from placements
FLOAT3D vSizeDelta = plVector1.pl_PositionVector-plVector0.pl_PositionVector;
// apply mouse movement
CValuesForPrimitive vfpTemp = theApp.m_vfpCurrent;
vfpTemp.vfp_fXMin = m_VFPMouseDown.vfp_fXMin+vSizeDelta(1)*aiForAllowedSizing[m_iSizeControlVertice][0];
vfpTemp.vfp_fXMax = m_VFPMouseDown.vfp_fXMax+vSizeDelta(1)*aiForAllowedSizing[m_iSizeControlVertice][1];
vfpTemp.vfp_fYMin = m_VFPMouseDown.vfp_fYMin+vSizeDelta(2)*aiForAllowedSizing[m_iSizeControlVertice][2];
vfpTemp.vfp_fYMax = m_VFPMouseDown.vfp_fYMax+vSizeDelta(2)*aiForAllowedSizing[m_iSizeControlVertice][3];
vfpTemp.vfp_fZMin = m_VFPMouseDown.vfp_fZMin+vSizeDelta(3)*aiForAllowedSizing[m_iSizeControlVertice][4];
vfpTemp.vfp_fZMax = m_VFPMouseDown.vfp_fZMax+vSizeDelta(3)*aiForAllowedSizing[m_iSizeControlVertice][5];
pDoc->SnapFloat( vfpTemp.vfp_fXMin, m_fGridInMeters/GRID_DISCRETE_VALUES);
pDoc->SnapFloat( vfpTemp.vfp_fXMax, m_fGridInMeters/GRID_DISCRETE_VALUES);
pDoc->SnapFloat( vfpTemp.vfp_fYMin, m_fGridInMeters/GRID_DISCRETE_VALUES);
pDoc->SnapFloat( vfpTemp.vfp_fYMax, m_fGridInMeters/GRID_DISCRETE_VALUES);
pDoc->SnapFloat( vfpTemp.vfp_fZMin, m_fGridInMeters/GRID_DISCRETE_VALUES);
pDoc->SnapFloat( vfpTemp.vfp_fZMax, m_fGridInMeters/GRID_DISCRETE_VALUES);
// if movement produced valid primitive
if( (vfpTemp.vfp_fXMax>vfpTemp.vfp_fXMin) &&
(vfpTemp.vfp_fYMax>vfpTemp.vfp_fYMin) &&
(vfpTemp.vfp_fZMax>vfpTemp.vfp_fZMin) )
{
theApp.m_vfpCurrent = vfpTemp;
bRefreshView = TRUE;
bRecreatePrimitive = TRUE;
}
break;
}
case IA_CHANGING_RANGE_PROPERTY:
case IA_CHANGING_ANGLE3D_PROPERTY:
{
CPropertyID *ppid = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
if( ppid == NULL) return;
//for all selected entities
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
// obtain property ptr
CEntityProperty *penpProperty = iten->PropertyForName( ppid->pid_strName);
if( penpProperty == NULL) return;
// discard old entity settings
iten->End();
if( ppid->pid_eptType == CEntityProperty::EPT_RANGE)
{
// get editing range for current entity
FLOAT fRange = ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, FLOAT);
// add range offset received during L/R mouse move
fRange += svViewer.PixelsToMeters(lOffsetX);
// set new range
ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, FLOAT) = fRange;
// change dialog's range variable
pMainFrame->m_PropertyComboBar.m_fEditingFloat = fRange;
}
else
{
// get angle3d for current entity
ANGLE3D aAngle = ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, ANGLE3D);
// create dummy placement
CPlacement3D plDummyPlacement;
plDummyPlacement.pl_PositionVector = FLOAT3D( 0.0f, 0.0f, 0.0f);
plDummyPlacement.pl_OrientationAngle = aAngle;
// set new angles using trackball method
svViewer.RotatePlacement_TrackBall(plDummyPlacement, lOffsetX, lOffsetY, 0);
aAngle = plDummyPlacement.pl_OrientationAngle;
// set new angle
ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, ANGLE3D) = aAngle;
// change dialog's range variable
pMainFrame->m_PropertyComboBar.m_fEditingHeading = DegAngle(aAngle(1));
pMainFrame->m_PropertyComboBar.m_fEditingPitch = DegAngle(aAngle(2));
pMainFrame->m_PropertyComboBar.m_fEditingBanking = DegAngle(aAngle(3));
}
// apply new entity settings
iten->Initialize();
// update edit range control (by updating parent dialog)
pMainFrame->m_PropertyComboBar.UpdateData( FALSE);
bRefreshView = TRUE;
}
// mark that document is changed
pDoc->SetModifiedFlag( TRUE);
break;
}
case IA_ROTATING_ENTITY_SELECTION:
case IA_ROTATING_SECOND_LAYER:
{
// use trackball method for rotation
svViewer.RotatePlacement_TrackBall(m_plMouseMove, -lOffsetX, -lOffsetY, 0);
pDoc->m_chSelections.MarkChanged();
bObjectMoved = TRUE;
break;
}
case IA_MOVING_ENTITY_SELECTION_IN_FLOOR_PLANE:
case IA_MOVING_SECOND_LAYER_IN_FLOOR_PLANE:
{
svViewer.TranslatePlacement_OwnSystem(m_plMouseMove, lOffsetX, lOffsetY, 0);
pDoc->m_chSelections.MarkChanged();
bObjectMoved = TRUE;
break;
}
case IA_MOVING_ENTITY_SELECTION_IN_VIEW_PLANE:
case IA_MOVING_SECOND_LAYER_IN_VIEW_PLANE:
{
svViewer.TranslatePlacement_OwnSystem(m_plMouseMove, lOffsetX, 0, lOffsetY);
pDoc->m_chSelections.MarkChanged();
bObjectMoved = TRUE;
break;
}
case IA_SIZING_SELECT_BY_VOLUME_BOX:
{
// get translation vector in view space
FLOAT fZoom = svViewer.GetZoomFactor();
CPlacement3D plVector0(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
CPlacement3D plVector1(FLOAT3D(fOriginOffsetX/fZoom,-fOriginOffsetY/fZoom,0.0f),
ANGLE3D(0,0,0));
// project translation vector from view space to absolute space
CPlacement3D plViewer = svViewer.GetViewerPlacement();
plVector0.RelativeToAbsolute(plViewer);
plVector1.RelativeToAbsolute(plViewer);
// extract translation vector from placements
FLOAT3D vDelta = plVector1.pl_PositionVector-plVector0.pl_PositionVector;
// apply movement
FLOAT3D vNewVolumeBoxCorner = pDoc->m_vVolumeBoxStartDragVertice+vDelta;
pDoc->CorrectBox( pDoc->m_iVolumeBoxDragVertice, vNewVolumeBoxCorner);
bRefreshView = TRUE;
break;
}
case IA_DRAG_VERTEX_ON_PRIMITIVE_BASE:
{
if( m_iDragVertice == -1) break;
// ------ Move closest vertice on base of primitive
CPlacement3D plVector0(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
FLOAT fZoom = svViewer.GetZoomFactor();
CPlacement3D plVector1(FLOAT3D(fOriginOffsetX/fZoom,-fOriginOffsetY/fZoom,0.0f),
ANGLE3D(0,0,0));
// project translation vector from view space to absolute space
CPlacement3D plViewer = svViewer.GetViewerPlacement();
plVector0.RelativeToAbsolute(plViewer);
plVector1.RelativeToAbsolute(plViewer);
// project translation vector from absolute space to second layer space
plVector0.AbsoluteToRelative(pDoc->m_plSecondLayer);
plVector1.AbsoluteToRelative(pDoc->m_plSecondLayer);
// extract translation vector from placements
DOUBLE3D vDelta = FLOATtoDOUBLE(plVector1.pl_PositionVector)-
FLOATtoDOUBLE(plVector0.pl_PositionVector);
DOUBLE3D &vDrag = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[m_iDragVertice];
// apply movement
vDrag = m_vStartDragVertice + vDelta;
// snap resulting vertex coordinate
SnapVector( vDrag);
// refresh primitive
pDoc->CreatePrimitive();
bRefreshView = TRUE;
break;
}
case IA_DRAG_VERTEX_ON_PRIMITIVE:
{
FLOAT fZoom = svViewer.GetZoomFactor();
DragVerticesOnPrimitive(fOriginOffsetX/fZoom,-fOriginOffsetY/fZoom, 0.0f, FALSE);
bRefreshView = TRUE;
break;
}
case IA_SELECT_LASSO_BRUSH_VERTEX:
case IA_SELECT_LASSO_ENTITY:
{
INDEX ctLasoPts = m_avpixLaso.Count();
m_avpixLaso.Push(1);
m_avpixLaso[ctLasoPts](1) = point.x;
m_avpixLaso[ctLasoPts](2) = point.y;
Invalidate( FALSE);
break;
}
case IA_SELECT_SINGLE_BRUSH_VERTEX:
{
// if mouse moved more than few pixels arround
if( (abs( lOffsetX) > 3) || (abs( lOffsetY) > 3) )
{
// if shift nor alt were pressed on mouse down
if( !m_bOnSelectVertexShiftDown && !m_bOnSelectVertexAltDown)
{
// clear vertex selection
pDoc->m_selVertexSelection.Clear();
}
// switch to laso select
m_iaInputAction = IA_SELECT_LASSO_BRUSH_VERTEX;
// add mouse down and current mouse positions to lasso buffer
m_avpixLaso.Push(2);
m_avpixLaso[0](1) = m_ptMouseDown.x;
m_avpixLaso[0](2) = m_ptMouseDown.y;
m_avpixLaso[1](1) = point.x;
m_avpixLaso[1](2) = point.y;
pDoc->m_chSelections.MarkChanged();
Invalidate( FALSE);
}
break;
}
case IA_DRAG_BRUSH_VERTEX_IN_FLOOR_PLANE:
{
bRepaintImmediately = TRUE;
FLOAT fZoom = svViewer.GetZoomFactor();
DragBrushVertex(fOriginOffsetX/fZoom,-fOriginOffsetY/fZoom, 0.0f);
pDoc->SetModifiedFlag( TRUE);
bRefreshView = TRUE;
break;
}
case IA_DRAG_BRUSH_VERTEX_IN_VIEW_PLANE:
{
bRepaintImmediately = TRUE;
FLOAT fZoom = svViewer.GetZoomFactor();
DragBrushVertex(fOriginOffsetX/fZoom, 0.0f, fOriginOffsetY/fZoom);
pDoc->SetModifiedFlag( TRUE);
bRefreshView = TRUE;
break;
}
case IA_ROTATE_BRUSH_VERTEX:
{
bRepaintImmediately = TRUE;
// apply brush vertex rotation
RotateOrStretchBrushVertex(-fOriginOffsetX, -fOriginOffsetY, TRUE);
pDoc->SetModifiedFlag( TRUE);
// calculate BBox of all vertices before rotating started
bRefreshView = TRUE;
break;
}
case IA_STRETCH_BRUSH_VERTEX:
{
bRepaintImmediately = TRUE;
// apply brush stretch
FLOAT fZoom = svViewer.GetZoomFactor();
RotateOrStretchBrushVertex(fOriginOffsetX, fZoom, FALSE);
pDoc->SetModifiedFlag( TRUE);
// calculate BBox of all vertices before rotating started
bRefreshView = TRUE;
break;
}
case IA_SELECTING_POLYGONS:
{
// if mouse is not over some polygon, break
if( (crRayHit.cr_penHit == NULL) ||
(crRayHit.cr_pbpoBrushPolygon == NULL) ) break;
// if polygon under mouse is selected and first polygon that we hitted
// was deselected
if( crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED) && m_bWeDeselectedFirstPolygon)
{
// deselect polygon under mouse
pDoc->m_selPolygonSelection.Deselect( *crRayHit.cr_pbpoBrushPolygon);
}
// if polygon under mouse is not selected and first polygon that we hitted
// at the begining of selecting was selected
if( !crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED) && !m_bWeDeselectedFirstPolygon)
{
// select polygon under mouse
pDoc->m_selPolygonSelection.Select( *crRayHit.cr_pbpoBrushPolygon);
}
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
// and refresh property combo manualy calling on idle
pMainFrame->m_PropertyComboBar.m_PropertyComboBox.OnIdle( 0);
bRefreshView = TRUE;
break;
}
case IA_SELECTING_SECTORS:
{
// if mouse is not over some polygon, break
if( (crRayHit.cr_penHit == NULL) ||
(crRayHit.cr_pbpoBrushPolygon == NULL) ) break;
// if sector under mouse is selected and first sector that we hitted
// at the begining of selecting was deselected
if( crRayHit.cr_pbscBrushSector->IsSelected( BSCF_SELECTED) && m_bWeDeselectedFirstSector)
{
// deselect sector under mouse
pDoc->m_selSectorSelection.Deselect( *crRayHit.cr_pbscBrushSector);
}
// if sector under mouse is not selected and first sector that we hitted
// at the begining of selecting was selected
if( !crRayHit.cr_pbscBrushSector->IsSelected( BSCF_SELECTED) && !m_bWeDeselectedFirstSector)
{
// select sector under mouse
pDoc->m_selSectorSelection.Select( *crRayHit.cr_pbscBrushSector);
}
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
// and refresh property combo manualy calling on idle
pMainFrame->m_PropertyComboBar.m_PropertyComboBox.OnIdle( 0);
bRefreshView = TRUE;
break;
}
case IA_SELECTING_ENTITIES:
{
// if mouse moved more than few pixels arround
if( (abs( lOffsetX) > 3) || (abs( lOffsetY) > 3) )
{
// if shift nor alt were pressed on mouse down
if( !m_bOnSelectEntityShiftDown && !m_bOnSelectEntityAltDown)
{
// clear entity selection
pDoc->m_selEntitySelection.Clear();
}
// switch to laso select
m_iaInputAction = IA_SELECT_LASSO_ENTITY;
// add mouse down and current mouse positions to lasso buffer
m_avpixLaso.Push(2);
m_avpixLaso[0](1) = m_ptMouseDown.x;
m_avpixLaso[0](2) = m_ptMouseDown.y;
m_avpixLaso[1](1) = point.x;
m_avpixLaso[1](2) = point.y;
Invalidate( FALSE);
}
break;
}
case IA_MEASURING:
{
// just refresh view
bRefreshView = TRUE;
break;
}
case IA_MOVING_CUT_LINE_START:
{
FLOAT fZoom = svViewer.GetZoomFactor();
FLOAT3D vDelta = ProjectVectorToWorldSpace( fOriginOffsetX/fZoom, -fOriginOffsetY/fZoom, 0.0f);
// calculate and snap new position
pDoc->m_vCutLineStart = pDoc->m_vControlLineDragStart+vDelta;
SnapVector( pDoc->m_vCutLineStart);
bRefreshView = TRUE;
break;
}
case IA_MOVING_CUT_LINE_END:
{
// get 3D delta vector in world, from mouse down point to current mouse position
FLOAT fZoom = svViewer.GetZoomFactor();
FLOAT3D vDelta = ProjectVectorToWorldSpace( fOriginOffsetX/fZoom, -fOriginOffsetY/fZoom, 0.0f);
// calculate and snap new position
pDoc->m_vCutLineEnd = pDoc->m_vControlLineDragStart+vDelta;
SnapVector( pDoc->m_vCutLineEnd);
bRefreshView = TRUE;
break;
}
case IA_CUT_MODE:
{
// calculate current cut line end
pDoc->m_vCutLineEnd = Get3DCoordinateFrom2D( point);
bRefreshView = TRUE;
break;
}
case IA_ROTATING_POLYGON_MAPPING:
{
if(crRayHit.cr_pbpoBrushPolygon==NULL) return;
svViewer.RotatePlacement_TrackBall(m_plMouseMove, lOffsetX, lOffsetY, 0);
// get rotation angle
ANGLE3D angMappingRotation = m_plMouseMove.pl_OrientationAngle;
CTString strDataPaneText;
strDataPaneText.PrintF("H=%g,P=%g,B=%g",
DegAngle( angMappingRotation(1)),
DegAngle( angMappingRotation(2)),
DegAngle( angMappingRotation(3)));
pMainFrame->m_wndStatusBar.SetPaneText( STATUS_LINE_PANE, CString(strDataPaneText), TRUE);
// for each selected polygon
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
CBrushPolygon *pbpo = itbpo;
CEntity *pen = pbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
CSimpleProjection3D pr;
pr.ObjectPlacementL() = _plOrigin;
pr.ViewerPlacementL() = pen->GetPlacement();
pr.Prepare();
FLOATplane3D vRelative;
pr.ProjectCoordinate(m_vHitOnMouseDown, vRelative);
// rotate it
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.Rotate(
pbpo->bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative,
vRelative, angMappingRotation(1));
}
// mark that document is changed
pDoc->SetModifiedFlag();
bRefreshView = TRUE;
pDoc->UpdateAllViews( NULL);
// reset mouse placement
m_plMouseMove.pl_PositionVector = crRayHit.cr_vHit;
m_plMouseMove.pl_OrientationAngle = ANGLE3D( 0, 0, 0);
// refresh position page
pDoc->RefreshCurrentInfoPage();
break;
}
case IA_MOVING_POLYGON_MAPPING:
{
// find translation vector in 3d
crRayHit.cr_vHit = GetMouseHitOnPlane(point, m_plTranslationPlane);
FLOAT3D f3dMappingTranslation = crRayHit.cr_vHit-m_plMouseMove.pl_PositionVector;
// find how much that offsets hit polygon
if( m_pbpoTranslationPlane == NULL) return;
CBrushPolygon &bpo = *m_pbpoTranslationPlane;
CEntity *pen = bpo.bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
CSimpleProjection3D pr;
pr.ObjectPlacementL() = _plOrigin;
pr.ViewerPlacementL() = pen->GetPlacement();
pr.Prepare();
FLOATplane3D vRelative;
pr.ProjectDirection(f3dMappingTranslation, vRelative);
CMappingDefinition mdOriginal = bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
CMappingDefinition mdTranslated = mdOriginal;
mdTranslated.Translate(
bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative, vRelative);
FLOAT fUOffset = mdTranslated.md_fUOffset-mdOriginal.md_fUOffset;
FLOAT fVOffset = mdTranslated.md_fVOffset-mdOriginal.md_fVOffset;
// for each selected polygon
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
// add the offsets to its mapping
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fUOffset+=fUOffset;
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fVOffset+=fVOffset;
}
// mark that document is changed
pDoc->SetModifiedFlag();
bRefreshView = TRUE;
pDoc->UpdateAllViews( NULL);
// reset mouse placement
m_plMouseMove.pl_PositionVector = crRayHit.cr_vHit;
m_plMouseMove.pl_OrientationAngle = ANGLE3D( 0, 0, 0);
// refresh position page
pDoc->RefreshCurrentInfoPage();
break;
}
}
// if recreating of primitive requested
if( bRecreatePrimitive)
{
pDoc->RefreshPrimitivePage();
pDoc->CreatePrimitive();
}
// if something has moved
if( bObjectMoved)
{
if( (m_iaInputAction == IA_MOVING_SECOND_LAYER_IN_FLOOR_PLANE) ||
(m_iaInputAction == IA_MOVING_SECOND_LAYER_IN_VIEW_PLANE) ||
(m_iaInputAction == IA_ROTATING_SECOND_LAYER) )
{
// copy new placement to second layer
pDoc->m_plSecondLayer = m_plMouseMove;
pDoc->SnapToGrid( pDoc->m_plSecondLayer, m_fGridInMeters/GRID_DISCRETE_VALUES);
theApp.m_vfpCurrent.vfp_plPrimitive = pDoc->m_plSecondLayer;
}
else if( (m_iaInputAction == IA_MOVING_ENTITY_SELECTION_IN_FLOOR_PLANE) ||
(m_iaInputAction == IA_MOVING_ENTITY_SELECTION_IN_VIEW_PLANE) ||
(m_iaInputAction == IA_ROTATING_ENTITY_SELECTION) )
{
ASSERT( pDoc->m_aSelectedEntityPlacements.Count()==pDoc->m_selEntitySelection.Count());
if( pDoc->m_aSelectedEntityPlacements.Count()!=pDoc->m_selEntitySelection.Count()) return;
// if there is no anchored entity in selection or if moving of
// anchored entities is allowed
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
if( ((iten->GetFlags() & ENF_ANCHORED) != 0) &&
(!GetChildFrame()->m_bAncoredMovingAllowed) ) return;
}}
INDEX ienCurrent = 0;
CEntity *penBrush = NULL;
// for each of the selected entities
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
if (iten->en_RenderType == CEntity::RT_BRUSH) {
penBrush = &*iten;
}
if( (iten->GetParent()==NULL) || !(iten->GetParent()->IsSelected( ENF_SELECTED)) )
{
// set new entity placement
CPlacement3D plEntityPlacement = pDoc->m_aSelectedEntityPlacements[ienCurrent];
plEntityPlacement.RelativeToAbsoluteSmooth(m_plMouseMove);
pDoc->SnapToGrid( plEntityPlacement, m_fGridInMeters/GRID_DISCRETE_VALUES);
iten->SetPlacement(plEntityPlacement);
pDoc->SetModifiedFlag();
}
ienCurrent++;
}}
if( penBrush != NULL)
{
DiscardShadows( penBrush);
}
if(m_iaInputAction == IA_ROTATING_ENTITY_SELECTION)
{
// check for terrain updating
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
CLightSource *pls = iten->GetLightSource();
if (pls!=NULL)
{
// if light is directional
if(pls->ls_ulFlags &LSF_DIRECTIONAL)
{
CTerrain *ptrTerrain=GetTerrain();
if(ptrTerrain!=NULL) ptrTerrain->UpdateShadowMap();
}
}
}}
}
}
}
// if rotating/moving viewer (bRefreshView) or moving CSG layer, entities or polygon's
// mapping (bObjectMoved) or editing primitive (bRecreatePrimitive)
if( bRefreshView || bObjectMoved || bRecreatePrimitive)
{
// see in preferences if all views should be updated
if( theApp.m_Preferences.ap_UpdateAllways || bRepaintImmediately ||
(bCtrl && bLMB && pDoc->GetEditingMode()==POLYGON_MODE) )
{
// force immediatly repainting
RedrawWindow( NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
// update other views
pDoc->UpdateAllViews( this);
}
else
{
// just invalidate
Invalidate( FALSE);
}
}
// set text describing data that is edited
SetEditingDataPaneInfo( TRUE);
// remember current mouse position as last pressed
m_ptMouse = point;
}
/*
* Called by document at the end of CSG
*/
void CWorldEditorView::AtStopCSG(void)
{
}
/*
* Called by MFC from CWorldEditorDoc::UpdateAllViews().
*/
void CWorldEditorView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
// just invalidate the whole window area
Invalidate(FALSE);
}
void CWorldEditorView::OnDropFiles(HDROP hDropInfo)
{
CWorldEditorDoc* pDoc = GetDocument();
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
// You can't drag anything while CSG is on
if( bCSGOn)
{
return;
}
// get number of dropped files
INDEX iNoOfFiles = DragQueryFile( hDropInfo, 0xFFFFFFFF, NULL, 0);
// there can be only one file dropped
if( iNoOfFiles != 1)
{
AfxMessageBox( L"You can drop only one file at a time.");
return;
}
// buffer for dropped file name
char chrFile[ 256];
// place dropped file name into buffer
DragQueryFileA( hDropInfo, 0, chrFile, 256);
// create file name from buffer
CTFileName fnDropped = CTString(chrFile);
// don't allow document self-drop
/*if( CTFileName(pDoc->GetPathName()) == fnDropped)
{
return;
}*/
// object to hold coordinates
CPoint point;
// get dropped coordinates
DragQueryPoint( hDropInfo, &point);
// try to
try
{
// remove application path
fnDropped.RemoveApplicationPath_t();
}
catch( char* err_str)
{
AfxMessageBox( CString(err_str));
return;
}
CPlacement3D plDrop;
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( point);
// place the dropped object at hitted point
plDrop.pl_PositionVector = crRayHit.cr_vHit;
// reset angles
plDrop.pl_OrientationAngle = ANGLE3D(0,0,0);
// if the hit entity was a brush
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) ) {
// get the hit normal in absolute space
CSimpleProjection3D prBrushToAbsolute;
prBrushToAbsolute.ObjectPlacementL() = crRayHit.cr_penHit->GetPlacement();
prBrushToAbsolute.ViewerPlacementL() = CPlacement3D(
FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
prBrushToAbsolute.Prepare();
FLOAT3D vHitNormal;
prBrushToAbsolute.ProjectDirection(crRayHit.cr_pbpoBrushPolygon->bpo_pbplPlane->bpl_plAbsolute,
vHitNormal);
// if the normal is more horizontal
if (Abs(vHitNormal(2))<0.5f) {
// calculate angles to align -z axis towards the plane
DirectionVectorToAngles(-vHitNormal, plDrop.pl_OrientationAngle);
}
}
pDoc->SnapToGrid( plDrop, m_fGridInMeters/GRID_DISCRETE_VALUES);
// if the dragged object is an entity class
if (fnDropped.FileExt()==".ecl")
{
// create dragged entity
CPlacement3D plEntity;
CEntity *pen = NULL;
try
{
extern BOOL _bInOnDraw;
_bInOnDraw = TRUE;
pen = pDoc->m_woWorld.CreateEntity_t(plDrop, fnDropped);
// prepare the entity
pen->Initialize();
_bInOnDraw = FALSE;
// the drop was successful
pDoc->SetModifiedFlag();
// mark that document changeable was changed
pDoc->m_chDocument.MarkChanged();
}
catch(char *err_str)
{
_bInOnDraw = FALSE;
AfxMessageBox(CString(err_str));
if (pen!=NULL) {
pen->Destroy();
}
// the drop was no successful
return;
}
// deselect all entities
pDoc->m_selEntitySelection.Clear();
// if succeseful, switch to entity mode and only-select dropped entity
pDoc->m_selEntitySelection.Select( *pen);
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
// switch to entity mode
OnEntityMode();
// and refresh property combo manualy calling on idle
pMainFrame->m_PropertyComboBar.m_PropertyComboBox.OnIdle( 0);
if( (pen->GetRenderType() == CEntity::RT_BRUSH) ||
(pen->GetRenderType() == CEntity::RT_FIELDBRUSH) )
{
pMainFrame->m_CSGDesitnationCombo.OnIdle(0);
pMainFrame->m_CSGDesitnationCombo.SelectBrushEntity(pen);
}
pDoc->SetModifiedFlag( TRUE);
pDoc->m_chDocument.MarkChanged();
// update all views
pDoc->UpdateAllViews( this);
}
// if the dragged object is a world
else if (fnDropped.FileExt()==".wld")
{
pDoc->StartTemplateCSG( plDrop, fnDropped, FALSE /*don't reset angles*/);
// the drop was successful
return;
}
else if (fnDropped.FileExt()==".tex")
{
// if we hit some entity and hitted entity is brush
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
// try to apply dropped texture to current selection
try
{
// if polygon that is hit with mouse is selected
if( crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED))
{
// paste dropped texture over polygon selection
pDoc->PasteTextureOverSelection_t( fnDropped);
}
// otherwise
else
{
// paste it only for drop-hitted polygon
crRayHit.cr_pbpoBrushPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.SetData_t( fnDropped);
// mark that document has been modified
pDoc->SetModifiedFlag( TRUE);
// mark that selections have been changed to update entity intersection properties
pDoc->m_chSelections.MarkChanged();
// update all views
pDoc->UpdateAllViews( NULL);
}
}
// if failed
catch( char *err_str)
{
// report error
AfxMessageBox( CString(err_str));
return;
}
}
else
{
// inform user that drop can be achived only over polygons
AfxMessageBox( L"You can drop textures only by hitting some polygon, but You hit some entity.");
return;
}
}
else
{
// the drop was not successful, report error
AfxMessageBox( L"You can drop only textures, classes and worlds.");
return;
}
}
/*
* Get pointer to the child frame of this view.
*/
CChildFrame *CWorldEditorView::GetChildFrame(void)
{
return (CChildFrame *)GetParentFrame();
}
void CWorldEditorView::OnIsometricFront()
{
m_ptProjectionType = CSlaveViewer::PT_ISOMETRIC_FRONT;
Invalidate( FALSE);
}
void CWorldEditorView::OnIsometricBack()
{
m_ptProjectionType = CSlaveViewer::PT_ISOMETRIC_BACK;
Invalidate( FALSE);
}
void CWorldEditorView::OnIsometricBottom()
{
m_ptProjectionType = CSlaveViewer::PT_ISOMETRIC_BOTTOM;
Invalidate( FALSE);
}
void CWorldEditorView::OnIsometricLeft()
{
m_ptProjectionType = CSlaveViewer::PT_ISOMETRIC_LEFT;
Invalidate( FALSE);
}
void CWorldEditorView::OnIsometricRight()
{
m_ptProjectionType = CSlaveViewer::PT_ISOMETRIC_RIGHT;
Invalidate( FALSE);
}
void CWorldEditorView::OnIsometricTop()
{
m_ptProjectionType = CSlaveViewer::PT_ISOMETRIC_TOP;
Invalidate( FALSE);
}
void CWorldEditorView::OnPerspective()
{
m_ptProjectionType = CSlaveViewer::PT_PERSPECTIVE;
Invalidate( FALSE);
}
void CWorldEditorView::OnZoomLess()
{
// get draw port
CDrawPort *pdpValidDrawPort = GetDrawPort();
// if it is not valid
if( pdpValidDrawPort == NULL)
{
return;
}
CWorldEditorDoc* pDoc = GetDocument();
// create a slave viewer
CSlaveViewer svViewer(GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pdpValidDrawPort);
// scale target distance by 2 - zoom out x2
svViewer.ScaleTargetDistance( 2.0f);
// copy slave viewer back to master
GetChildFrame()->m_mvViewer = svViewer;
// redraw all viewes
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnZoomMore()
{
// get draw port
CDrawPort *pdpValidDrawPort = GetDrawPort();
// if it is not valid
if( pdpValidDrawPort == NULL)
{
return;
}
CWorldEditorDoc* pDoc = GetDocument();
// create a slave viewer
CSlaveViewer svViewer(GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pdpValidDrawPort);
// scale target distance by -1/2 - zoom in x2
svViewer.ScaleTargetDistance( -0.5f);
// copy slave viewer back to master
GetChildFrame()->m_mvViewer = svViewer;
// redraw all viewes
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::RotateOrStretchBrushVertex(FLOAT fDX, FLOAT fDY, BOOL bRotate)
{
CWorldEditorDoc* pDoc = GetDocument();
// project translation vector from view space to absolute space
CDrawPort *pdpValidDrawPort = GetDrawPort();
if( pdpValidDrawPort == NULL) return;
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pdpValidDrawPort);
// both selection and coordinate arrays must be sinchronized
if( pDoc->m_avStartDragVertices.Count()!=pDoc->m_selVertexSelection.Count()) {
ASSERT(FALSE);
return;
}
// -------- Calculate BBox of all selected brush vertices
FLOATaabbox3D boxVtx;
// for each vertex
{for( INDEX iVtx=0; iVtx<pDoc->m_avStartDragVertices.Count(); iVtx++)
{
// get new position
boxVtx |= DOUBLEtoFLOAT(pDoc->m_avStartDragVertices[ iVtx]);
}}
// create dummy placement
CPlacement3D plDummy;
plDummy.pl_PositionVector = boxVtx.Center();
DOUBLE3D vCenter = FLOATtoDOUBLE(plDummy.pl_PositionVector);
plDummy.pl_OrientationAngle = ANGLE3D(0.0f, 0.0f, 0.0f);
// use trackball method for rotation
if( bRotate)
{
svViewer.RotatePlacement_TrackBall( plDummy, -fDX, -fDY, 0);
}
// get rotation matrix
FLOATmatrix3D t3dRotation;
MakeRotationMatrixFast( t3dRotation, plDummy.pl_OrientationAngle);
DOUBLEmatrix3D t3ddRotation;
t3ddRotation = FLOATtoDOUBLE(t3dRotation);
FLOAT fFactor=1.0f;
if( !bRotate)
{
FLOAT fDiag=boxVtx.Size().Length();
// fDY is actually current view's zoom factor
fFactor=(fDiag+fDX/fDY)/fDiag;
}
// for each vertex
INDEX iVtx = 0;
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
{
DOUBLE3D vRelative = pDoc->m_avStartDragVertices[ iVtx]-vCenter;
// rotate vertex around bbox center to get new position
DOUBLE3D vNew = vRelative*fFactor*t3ddRotation;
// snap resulting vertex coordinate
SnapVector(vNew);
// set its new position
itbvx->SetAbsolutePosition(vNew+vCenter);
iVtx++;
}}
// update sectors
pDoc->m_woWorld.UpdateSectorsDuringVertexChange( pDoc->m_selVertexSelection);
}
FLOAT3D CWorldEditorView::ProjectVectorToWorldSpace(FLOAT fDX,FLOAT fDY,FLOAT fDZ)
{
CWorldEditorDoc* pDoc = GetDocument();
CPlacement3D plVector0(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
CPlacement3D plVector1(FLOAT3D(fDX,fDY,fDZ), ANGLE3D(0,0,0));
CDrawPort *pdp = GetDrawPort();
if( pdp == NULL)
{
ASSERTALWAYS("Invalid draw port found!");
return FLOAT3D( 0.0f, 0.0f, 0.0f);
}
// project translation vector from view space to absolute space
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid, pdp);
CPlacement3D plViewer = svViewer.GetViewerPlacement();
plVector0.RelativeToAbsolute(plViewer);
plVector1.RelativeToAbsolute(plViewer);
// obtain translation vector from placements
FLOAT3D vDelta = (plVector1.pl_PositionVector-plVector0.pl_PositionVector);
return vDelta;
}
void CWorldEditorView::DragBrushVertex(FLOAT fDX,FLOAT fDY,FLOAT fDZ)
{
CWorldEditorDoc* pDoc = GetDocument();
// obtain 3d translation vector
DOUBLE3D vDelta = FLOATtoDOUBLE( ProjectVectorToWorldSpace( fDX, fDY, fDZ));
// both selection and coordinate arrays must be sinchronized
if( pDoc->m_avStartDragVertices.Count()!=pDoc->m_selVertexSelection.Count()) {
ASSERT(FALSE);
return;
}
// ---- apply movement
// for each vertex
INDEX iVtx = 0;
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
{
// get new position
DOUBLE3D vNew = pDoc->m_avStartDragVertices[ iVtx] + vDelta;
SnapVector( vNew);
// set its new position
itbvx->SetAbsolutePosition(vNew);
iVtx++;
}}
// update sectors
pDoc->m_woWorld.UpdateSectorsDuringVertexChange( pDoc->m_selVertexSelection);
}
void CWorldEditorView::DragVerticesOnPrimitive(FLOAT fDX,FLOAT fDY,FLOAT fDZ, BOOL bAbsolute,
BOOL bSnap/*=TRUE*/)
{
CWorldEditorDoc* pDoc = GetDocument();
CPlacement3D plVector0(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
CPlacement3D plVector1(FLOAT3D(fDX,fDY,fDZ), ANGLE3D(0,0,0));
// project translation vector from view space to absolute space
CDrawPort *pdpValidDrawPort = GetDrawPort();
if( pdpValidDrawPort == NULL) return;
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
pDoc->m_plGrid, pdpValidDrawPort);
CPlacement3D plViewer = svViewer.GetViewerPlacement();
plVector0.RelativeToAbsolute(plViewer);
plVector1.RelativeToAbsolute(plViewer);
// project translation vector from absolute space to second layer space
plVector0.AbsoluteToRelative(pDoc->m_plSecondLayer);
plVector1.AbsoluteToRelative(pDoc->m_plSecondLayer);
// extract translation vector from placements
DOUBLE3D vDelta = FLOATtoDOUBLE(plVector1.pl_PositionVector)-
FLOATtoDOUBLE(plVector0.pl_PositionVector);
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Lock();
CDynamicArray<CObjectVertex> &aVtx = theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors[0].osc_aovxVertices;
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Unlock();
aVtx.Lock();
DOUBLE3D vClosest;
DOUBLE3D vFirstInSelection;
BOOL bHasSelection = FALSE;
// see if any of the vertices is selected
INDEX iVtx=0;
for( ; iVtx<aVtx.Count(); iVtx++)
{
if( aVtx[ iVtx].ovx_ulFlags & OVXF_CLOSEST) vClosest = aVtx[ iVtx];
if( (aVtx[ iVtx].ovx_ulFlags & OVXF_SELECTED) && !bHasSelection)
{
vFirstInSelection = aVtx[ iVtx];
bHasSelection = TRUE;
}
}
DOUBLE3D vVectorForAdding;
// if given delta vector should be applied absolutly
if( bAbsolute)
{
vVectorForAdding = vDelta;
}
else
{
if( bHasSelection)
{
vVectorForAdding = m_vStartDragO3DVertice+vDelta-vFirstInSelection;
}
else
{
vVectorForAdding = m_vStartDragO3DVertice+vDelta-vClosest;
}
}
// apply movement
for( iVtx=0; iVtx<aVtx.Count(); iVtx++)
{
if( ((aVtx[ iVtx].ovx_ulFlags & OVXF_CLOSEST) && !bHasSelection) ||
((aVtx[ iVtx].ovx_ulFlags & OVXF_SELECTED) && bHasSelection) )
{
aVtx[ iVtx] += vVectorForAdding;
if( pDoc->m_bAutoSnap && bSnap)
{
// snap resulting vertex coordinate
Snap(aVtx[iVtx](1), m_fGridInMeters/GRID_DISCRETE_VALUES);
Snap(aVtx[iVtx](2), m_fGridInMeters/GRID_DISCRETE_VALUES);
Snap(aVtx[iVtx](3), m_fGridInMeters/GRID_DISCRETE_VALUES);
}
else
{
Snap(aVtx[iVtx](1), SNAP_DOUBLE_CM);
Snap(aVtx[iVtx](2), SNAP_DOUBLE_CM);
Snap(aVtx[iVtx](3), SNAP_DOUBLE_CM);
}
}
}
aVtx.Unlock();
pDoc->ConvertObject3DToBrush(theApp.m_vfpCurrent.vfp_o3dPrimitive, TRUE);
// redraw all viewes
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnMoveUp()
{
CWorldEditorDoc* pDoc = GetDocument();
if( (pDoc->m_pwoSecondLayer != NULL) &&
(pDoc->m_bPrimitiveMode) &&
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) &&
((!theApp.m_vfpCurrent.vfp_bAutoCreateMipBrushes)||
(theApp.m_vfpCurrent.vfp_ptPrimitiveType != PT_TERRAIN)) )
{
MarkClosestVtxOnPrimitive( FALSE);
DragVerticesOnPrimitive( 0.0, 0.0, m_fGridInMeters/GRID_DISCRETE_VALUES, TRUE, FALSE);
}
// redraw all viewes
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnMoveDown()
{
CWorldEditorDoc* pDoc = GetDocument();
if( (pDoc->m_pwoSecondLayer != NULL) &&
(pDoc->m_bPrimitiveMode) &&
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) &&
((!theApp.m_vfpCurrent.vfp_bAutoCreateMipBrushes)||
(theApp.m_vfpCurrent.vfp_ptPrimitiveType != PT_TERRAIN)) )
{
MarkClosestVtxOnPrimitive( FALSE);
DragVerticesOnPrimitive( 0.0, 0.0, -m_fGridInMeters/GRID_DISCRETE_VALUES, TRUE, FALSE);
}
// redraw all viewes
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnMeasurementTape()
{
m_vpViewPrefs.m_bMeasurementTape = !m_vpViewPrefs.m_bMeasurementTape;
Invalidate( FALSE);
}
void CWorldEditorView::OnUpdateMeasurementTape(CCmdUI* pCmdUI)
{
if( m_ptProjectionType == CSlaveViewer::PT_PERSPECTIVE)
{
pCmdUI->Enable( FALSE);
pCmdUI->SetCheck( FALSE);
}
else
{
pCmdUI->Enable( TRUE);
pCmdUI->SetCheck( m_vpViewPrefs.m_bMeasurementTape);
}
}
void CWorldEditorView::OnKeyBuffer(UINT nID)
{
// get difference of key "1", which means buffer index
INDEX iPreferencesBuffer = nID-ID_BUFFER01;
// copy selected preferences to view's rendering preferences
m_vpViewPrefs = theApp.m_vpViewPrefs[ iPreferencesBuffer];
// see the change
Invalidate( FALSE);
}
void CWorldEditorView::OnKeyEditBuffer(UINT nID)
{
// get difference of key "1", which means buffer index
INDEX iPreferencesBuffer = nID-ID_EDIT_BUFFER01;
CDlgRenderingPreferences dlg( iPreferencesBuffer);
// if dialog ended with cancel or esc, dont switch to changed preferences
if( dlg.DoModal() != IDOK)
{
// don't set new preferences
return;
}
// copy selected preferences to view's rendering preferences
m_vpViewPrefs = theApp.m_vpViewPrefs[ iPreferencesBuffer];
// see the change
Invalidate( FALSE);
}
void CWorldEditorView::OnCircleModes()
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
switch( pDoc->GetEditingMode())
{
case ENTITY_MODE: { pDoc->SetEditingMode( SECTOR_MODE); break;};
case SECTOR_MODE: { pDoc->SetEditingMode( POLYGON_MODE); break;};
case POLYGON_MODE: { pDoc->SetEditingMode( VERTEX_MODE); break;};
case VERTEX_MODE: { pDoc->SetEditingMode( TERRAIN_MODE); break;};
case TERRAIN_MODE: { pDoc->SetEditingMode( ENTITY_MODE); break;};
default: { FatalError("Unknown editing mode."); break;};
}
}
void CWorldEditorView::OnUpdateCircleModes(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pCmdUI->Enable( pDoc->GetEditingMode() != CSG_MODE);
}
void CWorldEditorView::OnDeselectAll()
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->DeselectAll();
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
// if we are in triangularisation primitive mode
if( (theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) &&
(bCSGOn && pDoc->m_bPrimitiveMode) )
{
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Lock();
CDynamicArray<CObjectVertex> &aVtx = theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors[0].osc_aovxVertices;
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Unlock();
aVtx.Lock();
// reset selected flags for all vertices
for( INDEX iVtx=0; iVtx<aVtx.Count(); iVtx++)
{
aVtx[ iVtx].ovx_ulFlags &= ~OVXF_SELECTED;
}
aVtx.Unlock();
// update all views
pDoc->UpdateAllViews(NULL);
}
}
void CWorldEditorView::RemoveFromLinkedChain(CEntity *pen)
{
CTFileName fnDropClass;
CTString strTargetProperty;
CEntityProperty *penpProperty;
CEntity &enOnly = *pen;
// obtain drop class and target property name
if( !enOnly.DropsMarker( fnDropClass, strTargetProperty)) return;
penpProperty = enOnly.PropertyForName( strTargetProperty);
CEntity *penHisTarget = ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer);
// or ptr is NULL
if( penHisTarget == NULL) return;
CEntity *penCurrent = pen;
INDEX iInfiniteLoopProtector = 0;
// loop forever
FOREVER
{
if( !penCurrent->DropsMarker( fnDropClass, strTargetProperty)) return;
penpProperty = penCurrent->PropertyForName( strTargetProperty);
CEntity *penNext = ENTITYPROPERTY( penCurrent, penpProperty->ep_slOffset, CEntityPointer);
if( penNext == NULL) return;
if( penNext == pen) break;
// jump to next in chain
penCurrent = penNext;
iInfiniteLoopProtector ++;
if( iInfiniteLoopProtector >= 256) return;
}
if( !penCurrent->DropsMarker( fnDropClass, strTargetProperty)) return;
penpProperty = penCurrent->PropertyForName( strTargetProperty);
ENTITYPROPERTY( penCurrent, penpProperty->ep_slOffset, CEntityPointer) = penHisTarget;
}
void CWorldEditorView::OnDeleteEntities()
{
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == CSG_MODE) return;
if( pDoc->GetEditingMode() == SECTOR_MODE)
{
if( pDoc->m_selSectorSelection.Count() != 0)
{
if( theApp.m_Preferences.ap_bSaveUndoForDelete)
{
pDoc->RememberUndo();
}
pDoc->ClearSelections( ST_SECTOR);
pDoc->m_woWorld.DeleteSectors( pDoc->m_selSectorSelection, TRUE);
}
}
else
{
// if any of selected entities is anchored, anchored operation flag must be allowed or deleting is disabled
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
if( (iten->GetFlags() & ENF_ANCHORED) && !GetChildFrame()->m_bAncoredMovingAllowed) return;
}}
}
if( pDoc->m_selEntitySelection.Count() != 0)
{
if( theApp.m_Preferences.ap_bSaveUndoForDelete)
{
pDoc->RememberUndo();
}
}
// check for deleting terrain
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
CEntity &en=*iten;
// if it is terrain
if(en.GetRenderType()==CEntity::RT_TERRAIN)
{
// if it is selected terrain
if(pDoc->m_ptrSelectedTerrain==en.GetTerrain())
{
pDoc->m_ptrSelectedTerrain=NULL;
theApp.m_ctTerrainPage.MarkChanged();
break;
}
}
}}
// for each of the selected entities
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
if( pDoc->m_cenEntitiesSelectedByVolume.IsMember(iten))
pDoc->m_cenEntitiesSelectedByVolume.Remove(iten);
}}
// for each of the selected entities
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
RemoveFromLinkedChain(iten);
}}
// clear selections
pDoc->m_selVertexSelection.Clear();
pDoc->m_selSectorSelection.Clear();
pDoc->m_selPolygonSelection.Clear();
// delete all selected entities
pDoc->m_woWorld.DestroyEntities( pDoc->m_selEntitySelection);
}
// mark that document was changed (for saving)
pDoc->SetModifiedFlag();
// mark that document changeable was changed to update CSG target combo box
pDoc->m_chDocument.MarkChanged();
// mark that selections have been changed to update entity intersection properties
pDoc->m_chSelections.MarkChanged();
// update all views
pDoc->UpdateAllViews(NULL);
}
void CWorldEditorView::OnUpdateDeleteEntities(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == ENTITY_MODE)
{
pCmdUI->Enable( IsDeleteEntityEnabled());
}
else if( pDoc->GetEditingMode() == SECTOR_MODE)
{
pCmdUI->Enable( pDoc->m_woWorld.CanCopySectors( pDoc->m_selSectorSelection));
}
else
{
pCmdUI->Enable( FALSE);
}
}
BOOL CWorldEditorView::IsDeleteEntityEnabled(void)
{
CWorldEditorDoc* pDoc = GetDocument();
// enable button if we are in entity mode and there is at least 1 brush entity unselected
BOOL bEnable = FALSE;
if( (pDoc->GetEditingMode() == ENTITY_MODE) &&
(pDoc->m_selEntitySelection.Count() != 0) )
{
// for all of the world's entities
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
// if the entity is brush
if (iten->GetRenderType() == CEntity::RT_BRUSH)
{
// if this is brush entity and is not selected
if( !iten->IsSelected( ENF_SELECTED))
{
// enable delete entity button
bEnable = TRUE;
break;
}
}
}
}
return bEnable;
}
void CWorldEditorView::UpdateCursor(void)
{
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
CWorldEditorDoc* pDoc = GetDocument();
CTerrainLayer *ptlLayer=GetLayer();
if( theApp.m_bMeasureModeOn)
{
SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS));
}
else if( theApp.m_bCutModeOn)
{
if( pDoc->GetEditingMode() == ENTITY_MODE)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_MIRROR));
}
else
{
SetCursor( AfxGetApp()->LoadCursor(IDC_CUT_LINE));
}
}
else if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL && ptlLayer!=NULL)
{
if(bCtrl&&bAlt)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_PICK));
}
else if(theApp.m_iTerrainEditMode==TEM_LAYER && ptlLayer->tl_ltType==LT_TILE)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_TILE_PAINTING));
}
else if(theApp.m_iTerrainBrushMode==TBM_ERASE)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_ERASE));
}
else if(theApp.m_iTerrainBrushMode==TBM_SMOOTH)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_SMOOTH));
}
else if(theApp.m_iTerrainBrushMode==TBM_FILTER)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_FILTER));
}
else if(theApp.m_iTerrainBrushMode==TBM_MINIMUM)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_MIN));
}
else if(theApp.m_iTerrainBrushMode==TBM_MAXIMUM)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_MAX));
}
else if(theApp.m_iTerrainBrushMode==TBM_FLATTEN)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_FLATTEN));
}
else if(theApp.m_iTerrainBrushMode==TBM_POSTERIZE)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_POSTERIZE));
}
else if(theApp.m_iTerrainBrushMode==TBM_RND_NOISE)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_RND_NOISE));
}
else if(theApp.m_iTerrainBrushMode==TBM_CONTINOUS_NOISE)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_CONTINOUS_NOISE));
}
else if(theApp.m_iTerrainBrushMode==TBM_PAINT)
{
if(theApp.m_iTerrainEditMode==TEM_HEIGHTMAP)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_HEIGHTMAP));
}
else if(theApp.m_iTerrainEditMode==TEM_LAYER)
{
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_LAYER_PAINT));
}
}
}
else
{
SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
}
}
BOOL CWorldEditorView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
return TRUE;
}
void CWorldEditorView::OnTakeSs()
{
// get draw port
CDrawPort *pdpValidDrawPort = GetDrawPort();
// if it is not valid
if( pdpValidDrawPort == NULL)
{
return;
}
CImageInfo iiImageInfo;
/* First remember current screen-shot in memory. */
if( pdpValidDrawPort->Lock())
{
RenderView( pdpValidDrawPort);
pdpValidDrawPort->Unlock();
}
// grab screen creating image info
pdpValidDrawPort->GrabScreen( iiImageInfo, 1);
// ask for save screen shot name
CTFileName fnDocName = CTString( CStringA(GetDocument()->GetPathName()));
CTFileName fnScreenShoot = _EngineGUI.FileRequester(
"Choose file name for screen shoot", FILTER_TGA FILTER_ALL FILTER_END, KEY_NAME_SCREEN_SHOT_DIR,
"ScreenShots\\", fnDocName.FileName()+"xx"+".tga", NULL, FALSE);
if( fnScreenShoot == "") return;
// try to
try {
// save screen shot as TGA
iiImageInfo.SaveTGA_t( fnScreenShoot);
} // if failed
catch (char *strError) {
// report error
AfxMessageBox(CString(strError));
}
}
void CWorldEditorView::OnEntityMode()
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->SetEditingMode( ENTITY_MODE);
}
void CWorldEditorView::OnUpdateEntityMode(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pCmdUI->Enable( pDoc->GetEditingMode() != CSG_MODE);
}
void CWorldEditorView::OnTerrainMode()
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->SetEditingMode( TERRAIN_MODE);
}
void CWorldEditorView::OnUpdateTerrainMode(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pCmdUI->Enable( pDoc->GetEditingMode() != CSG_MODE);
}
void CWorldEditorView::OnSectorMode()
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->SetEditingMode( SECTOR_MODE);
}
void CWorldEditorView::OnUpdateSectorMode(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pCmdUI->Enable( pDoc->GetEditingMode() != CSG_MODE);
}
void CWorldEditorView::OnPolygonMode()
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->SetEditingMode( POLYGON_MODE);
}
void CWorldEditorView::OnUpdatePolygonMode(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pCmdUI->Enable( pDoc->GetEditingMode() != CSG_MODE);
}
void CWorldEditorView::OnEditCopy()
{
EditCopy( FALSE);
}
void CWorldEditorView::OnVertexMode()
{
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->OnCsgCancel();
}
void CWorldEditorView::EditCopy( BOOL bAlternative)
{
CWorldEditorDoc* pDoc = GetDocument();
BOOL bCopyWorld = FALSE;
// if we are in entity mode
if( pDoc->GetEditingMode() == ENTITY_MODE)
{
// if we have some entities selected
if( pDoc->m_selEntitySelection.Count() != 0)
{
if( bAlternative)
{
CDynamicContainer<CEntity> selClones;
CPlacement3D plPaste = GetMouseInWorldPlacement();
// for all selected entities
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
CEntity *pClone = pDoc->m_woWorld.CopyEntityInWorld( *iten, plPaste);
selClones.Add( pClone);
}}
// clear old selection and select clones
pDoc->m_selEntitySelection.Clear();
{FOREACHINDYNAMICCONTAINER( selClones, CEntity, itenClone)
{
pDoc->m_selEntitySelection.Select( *itenClone);
}}
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag();
pDoc->UpdateAllViews( NULL);
}
else
{
// calculate bounding boxes of all selected entities
FLOATaabbox3D boxEntities;
// for all selected entities
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
FLOATaabbox3D boxCurrentEntity;
iten->GetSize( boxCurrentEntity);
boxCurrentEntity += iten->GetPlacement().pl_PositionVector;
boxEntities |= boxCurrentEntity;
}}
// average for all vectors of entities
FLOAT3D vCenter = boxEntities.Center();
vCenter(2) = boxEntities.Min()(2);
CPlacement3D plCenter = CPlacement3D( -vCenter, ANGLE3D(0,0,0) );
FLOAT3D vSize = boxEntities.Size();
FLOAT fMaxEdge = Max( Max(vSize(1), vSize(2)), vSize(3));
FLOAT fSnapValue;
if( theApp.m_bDecadicGrid)
{
INDEX iLog = (INDEX) (Log2( fMaxEdge/GRID_DISCRETE_VALUES)/Log2(10.0f));
fSnapValue = FLOAT(pow(10.0f, iLog));
}
else
{
INDEX iLog = (INDEX) Log2( fMaxEdge/GRID_DISCRETE_VALUES);
fSnapValue = FLOAT(pow(2.0f, iLog));
}
pDoc->SnapToGrid( plCenter, fSnapValue);
// create world to receive selected entities
CWorld woEntityClipboard;
woEntityClipboard.SetBackgroundColor( C_WHITE);
woEntityClipboard.SetDescription( "No description");
theApp.m_ctLastCopyType = CT_ENTITY;
// copy entities in selection
CEntitySelection senDummy;
woEntityClipboard.CopyEntities(pDoc->m_woWorld, pDoc->m_selEntitySelection,
senDummy, plCenter);
senDummy.Clear();
// try to
try
{
// save entity clipboard world
woEntityClipboard.Save_t(CTString("Temp\\ClipboardEntityWorld.wld"));
}
catch( char *strError)
{
AfxMessageBox( CString(strError));
return;
}
}
}
else
{
// we will copy whole world
bCopyWorld = TRUE;
}
}
// if we are in polygon mode
else if( pDoc->GetEditingMode() == POLYGON_MODE)
{
// obtain point in the world where mouse pointed last time it was moved
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse, FALSE, FALSE, FALSE);
// if mouse is over polygon
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
// remember selected polygon's parameters to application
theApp.m_pbpoClipboardPolygon->CopyProperties( *crRayHit.cr_pbpoBrushPolygon);
if( bAlternative)
{
theApp.m_ctLastCopyType = CT_POLYGON_PROPERTIES_ALTERNATIVE;
CopyMapping(crRayHit.cr_pbpoBrushPolygon);
}
else
{
theApp.m_ctLastCopyType = CT_POLYGON_PROPERTIES;
}
}
else
{
// we will copy whole world
bCopyWorld = TRUE;
}
}
// if we are in sector mode
else if( pDoc->GetEditingMode() == SECTOR_MODE)
{
// if there are no sectors selected
if( pDoc->m_selSectorSelection.Count() == 0)
{
// we will copy whole world
bCopyWorld = TRUE;
}
// copy selected sectors
else
{
if( !pDoc->m_woWorld.CanCopySectors( pDoc->m_selSectorSelection))
{
WarningMessage( "Error: Can't copy selected sectors. "
"All sectors must be in same brush and same mip factor.");
return;
}
// create world to receive selected sectors
CWorld woClipboard;
woClipboard.SetBackgroundColor( C_WHITE);
woClipboard.SetDescription( "No description");
// now create world base entity
CEntity *penWorldBase;
CPlacement3D plWorld = CPlacement3D( FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
// try to
try
{
penWorldBase = woClipboard.CreateEntity_t(plWorld, CTFILENAME("Classes\\WorldBase.ecl"));
}
// catch and
catch( char *err_str)
{
// report errors
WarningMessage( err_str);
return;
}
// prepare the entity
penWorldBase->Initialize();
EFirstWorldBase eFirstWorldBase;
penWorldBase->SendEvent( eFirstWorldBase);
CEntity::HandleSentEvents();
pDoc->m_woWorld.CopySectors( pDoc->m_selSectorSelection, penWorldBase, !bAlternative);
try
{
// save world to clipboard
woClipboard.Save_t(CTString("Temp\\ClipboardSectorWorld.wld"));
}
catch( char *strError)
{
AfxMessageBox( CString(strError));
return;
}
theApp.m_ctLastCopyType = CT_SECTOR;
}
}
// if we should copy the whole world
if( bCopyWorld)
{
try
{
// save world into clipboard file
pDoc->m_woWorld.Save_t( (CTString)"Temp\\ClipboardWorld.wld");
}
catch( char *strError)
{
AfxMessageBox( CString(strError));
}
theApp.m_ctLastCopyType = CT_WORLD;
}
}
// obtain point in the world where mouse pointed last time it was moved
CPlacement3D CWorldEditorView::GetMouseInWorldPlacement(void)
{
CWorldEditorDoc* pDoc = GetDocument();
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// get hitted point
CPlacement3D plMouse;
// if any kind of entity was hitted with mouse
if( crRayHit.cr_penHit != NULL)
{
// hitted entity exist
plMouse.pl_PositionVector = crRayHit.cr_vHit;
}
// if none of entities (brushes) was hitted with mouse
else
{
// set position in front of viewer, at the placement of viewing point (target)
plMouse = GetChildFrame()->m_mvViewer.GetTargetPlacement();
}
// reset angles
plMouse.pl_OrientationAngle = ANGLE3D(0,0,0);
// snap placement
pDoc->SnapToGrid( plMouse, m_fGridInMeters/GRID_DISCRETE_VALUES);
return plMouse;
}
void CWorldEditorView::OnEditPaste()
{
CWorldEditorDoc* pDoc = GetDocument();
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
// You can't paste anything while CSG is on
if( bCSGOn)
{
return;
}
BOOL bHitModels = FALSE;
if( theApp.m_ctLastCopyType == CT_ENTITY) bHitModels = TRUE;
CPlacement3D plPaste = GetMouseInWorldPlacement();
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse, FALSE, bHitModels, FALSE);
// if last copy operation was with entities
if( theApp.m_ctLastCopyType == CT_ENTITY)
{
// switch to entity mode
pDoc->SetEditingMode( ENTITY_MODE);
// create world to receive pasted entities
CWorld woEntityClipboard;
// try to
try
{
// load clipboard entity World
woEntityClipboard.Load_t( (CTString)"Temp\\ClipboardEntityWorld.wld");
}
catch( char *err_str)
{
AfxMessageBox( CString(err_str));
return;
}
// deselect all entities
pDoc->m_selEntitySelection.Clear();
// make container of entities to copy
CDynamicContainer<CEntity> cenToCopy;
cenToCopy = woEntityClipboard.wo_cenEntities;
// remove empty brushes from it
{FOREACHINDYNAMICCONTAINER(woEntityClipboard.wo_cenEntities, CEntity, iten)
{
if( iten->IsEmptyBrush() && (iten->GetFlags()&ENF_ZONING))
{
cenToCopy.Remove(iten);
}
}}
// copy entities in clipboard
pDoc->m_woWorld.CopyEntities(woEntityClipboard, cenToCopy,
pDoc->m_selEntitySelection, plPaste);
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag();
pDoc->UpdateAllViews( NULL);
}
// if last copy operation was with polygon properties
else if( theApp.m_ctLastCopyType == CT_POLYGON_PROPERTIES)
{
// if mouse is over polygon
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
if( crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED))
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
// apply remembered polygon's parameters to selection
itbpo->CopyTextures( *theApp.m_pbpoClipboardPolygon);
}
}
else
{
// apply remembered polygon's parameters to polygon under mouse
crRayHit.cr_pbpoBrushPolygon->CopyTextures( *theApp.m_pbpoClipboardPolygon);
}
}
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag();
pDoc->UpdateAllViews( NULL);
}
// if last copy operation was with whole world
else if( theApp.m_ctLastCopyType == CT_WORLD)
{
// load world from clipboard file and start template CSG
pDoc->StartTemplateCSG( plPaste, (CTString)"Temp\\ClipboardWorld.wld");
}
// if last copy operation was with selected sectors
else if( theApp.m_ctLastCopyType == CT_SECTOR)
{
// load world from sectors clipboard file and start template CSG
pDoc->StartTemplateCSG( plPaste, (CTString)"Temp\\ClipboardSectorWorld.wld");
}
}
void ProcesWEDConsoleShortcuts( MSG *pMsg)
{
if( pMsg->message==WM_KEYDOWN)
{
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
if( !bShift && pMsg->wParam == VK_F2) _pShell->Execute( "include \"Scripts\\WorldEditorKeys\\F2.ini\"");
if( !bShift && pMsg->wParam == VK_F3) _pShell->Execute( "include \"Scripts\\WorldEditorKeys\\F3.ini\"");
if( !bShift && pMsg->wParam == VK_F4) _pShell->Execute( "include \"Scripts\\WorldEditorKeys\\F4.ini\"");
if( bShift && (pMsg->wParam == VK_F2)) _pShell->Execute( "include \"Scripts\\WorldEditorKeys\\Shift_F2.ini\"");
if( bShift && (pMsg->wParam == VK_F3)) _pShell->Execute( "include \"Scripts\\WorldEditorKeys\\Shift_F3.ini\"");
if( bShift && (pMsg->wParam == VK_F4)) _pShell->Execute( "include \"Scripts\\WorldEditorKeys\\Shift_F4.ini\"");
}
if( pMsg->message==WM_MBUTTONDOWN || pMsg->message==WM_MBUTTONDBLCLK )
{
_pShell->Execute( "include \"Scripts\\WorldEditorKeys\\MiddleMouse.ini\"");
}
}
BOOL CWorldEditorView::PreTranslateMessage(MSG* pMsg)
{
CWorldEditorDoc* pDoc = GetDocument();
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
// get csg and primitive flags
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
BOOL bPrimitive = pDoc->m_bPrimitiveMode;
// get editting mode flags
BOOL bEntityMode = pDoc->GetEditingMode() == ENTITY_MODE;
BOOL bSectorMode = pDoc->GetEditingMode() == SECTOR_MODE;
BOOL bPolygonMode = pDoc->GetEditingMode() == POLYGON_MODE;
BOOL bTerrainMode = pDoc->GetEditingMode() == TERRAIN_MODE;
// get key statuses
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
// get mouse button statuses
BOOL bLMB = (GetKeyState( VK_LBUTTON)&0x8000) != 0;
BOOL bRMB = (GetKeyState( VK_RBUTTON)&0x8000) != 0;
// process scripts that are invoked on shortcuts from within WED
ProcesWEDConsoleShortcuts( pMsg);
// Ctrl +'A':
// - entity -> select all in volume
// - sector -> select all entities
// - polygon -> select all polygons in sector(s)
// Alt+'A'
// - sector -> show all sectors
// - entity -> show all entities
// - polygon-> auto fit mapping
// - vertex-> auto fit mapping
// 'A':
// - select by volume -> allign volume
// - entity -> allign entity selection or world
// - primitive -> allign primitive to screen
// - sector -> allign visible sectors to screen
if( ((pMsg->message==WM_KEYDOWN) || (pMsg->message==WM_SYSKEYDOWN)) &&
((int)pMsg->wParam=='A') )
{
// setup mouse - ray hit information
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
m_penEntityHitOnContext = crRayHit.cr_penHit;
if( (crRayHit.cr_penHit != NULL) && (crRayHit.cr_pbpoBrushPolygon != NULL) )
{
m_pbpoRightClickedPolygon = crRayHit.cr_pbpoBrushPolygon;
}
if( bCSGOn && !bShift)
{
if( bCtrl && bPrimitive)
{
OnAlignPrimitive();
}
else
{
FLOATaabbox3D boxSecondLayer;
FOREACHINDYNAMICCONTAINER(pDoc->m_pwoSecondLayer->wo_cenEntities, CEntity, iten)
{
FLOATaabbox3D box;
iten->GetSize( box);
FLOAT fMinX = box.Min()(1);
FLOAT fMinY = box.Min()(2);
FLOAT fMinZ = box.Min()(3);
FLOAT fMaxX = box.Max()(1);
FLOAT fMaxY = box.Max()(2);
FLOAT fMaxZ = box.Max()(3);
FLOAT3D avCorners[8];
avCorners[0] = FLOAT3D(fMinX,fMinY,fMinZ);
avCorners[1] = FLOAT3D(fMaxX,fMinY,fMinZ);
avCorners[2] = FLOAT3D(fMaxX,fMinY,fMaxZ);
avCorners[3] = FLOAT3D(fMinX,fMinY,fMaxZ);
avCorners[4] = FLOAT3D(fMinX,fMaxY,fMinZ);
avCorners[5] = FLOAT3D(fMaxX,fMaxY,fMinZ);
avCorners[6] = FLOAT3D(fMaxX,fMaxY,fMaxZ);
avCorners[7] = FLOAT3D(fMinX,fMaxY,fMaxZ);
for( INDEX iVtx=0; iVtx<8; iVtx++)
{
CPlacement3D plToProject = CPlacement3D( avCorners[iVtx], ANGLE3D(0,0,0));
plToProject.RelativeToAbsolute( pDoc->m_plSecondLayer);
boxSecondLayer |= FLOATaabbox3D(plToProject.pl_PositionVector);
}
}
AllignBox( boxSecondLayer);
}
}
else if( pDoc->GetEditingMode() == ENTITY_MODE && !bShift)
{
if( bCtrl && bAlt)
{
OnSelectAllSectors();
}
else if( bCtrl)
{
pDoc->OnSelectAllInVolume();
}
else if( bAlt)
{
pDoc->OnShowAllEntities();
}
else if( pDoc->m_bBrowseEntitiesMode)
{
OnAlignVolume();
}
else
{
CenterSelected();
}
}
else if(pDoc->GetEditingMode() == SECTOR_MODE && !bShift)
{
if( bCtrl && bAlt)
{
OnSelectAllPolygons();
}
else if( bCtrl)
{
OnSelectAllEntitiesInSectors();
}
else if( bAlt)
{
pDoc->OnShowAllSectors();
}
else
{
CenterSelected();
}
}
else if( pDoc->GetEditingMode() == POLYGON_MODE)
{
if( bCtrl && bAlt && !bShift)
{
OnSelectAllVertices();
}
else if( bCtrl && !bShift && !bAlt)
{
if( (crRayHit.cr_penHit != NULL) && (crRayHit.cr_pbpoBrushPolygon != NULL) )
{
// select all polygons in hitted sector
CBrushSector *pbscSector = crRayHit.cr_pbpoBrushPolygon->bpo_pbscSector;
FOREACHINSTATICARRAY(pbscSector->bsc_abpoPolygons, CBrushPolygon, itpo)
{
if( !itpo->IsSelected(BPOF_SELECTED)) pDoc->m_selPolygonSelection.Select( *itpo);
}
pDoc->m_chSelections.MarkChanged();
}
}
else if( bAlt && bShift && bCtrl)
{
if( crRayHit.cr_penHit != NULL)
{
AutoFitMapping( crRayHit.cr_pbpoBrushPolygon, TRUE, TRUE);
}
}
else if( bAlt && bShift)
{
if( crRayHit.cr_penHit != NULL)
{
AutoFitMapping( crRayHit.cr_pbpoBrushPolygon, TRUE);
}
}
else if( bAlt)
{
if( crRayHit.cr_penHit != NULL)
{
AutoFitMapping( crRayHit.cr_pbpoBrushPolygon);
}
}
else if(!bCtrl&&!bShift&&!bAlt)
{
CenterSelected();
}
}
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
if(!bCtrl&&!bShift&&!bAlt)
{
CenterSelected();
}
}
else if(pDoc->GetEditingMode() == VERTEX_MODE && !bShift)
{
if( bCtrl && bAlt)
{
if( (crRayHit.cr_penHit != NULL) && (crRayHit.cr_pbpoBrushPolygon != NULL) )
{
// select all vertices on hitted polygon
FOREACHINSTATICARRAY(crRayHit.cr_pbpoBrushPolygon->bpo_apbvxTriangleVertices, CBrushVertex *, itpbvx)
{
if( !(*itpbvx)->IsSelected(BVXF_SELECTED)) pDoc->m_selVertexSelection.Select( **itpbvx);
}
}
pDoc->m_chSelections.MarkChanged();
}
else if( bCtrl||bAlt)
{
CDlgAllignVertices dlg;
dlg.DoModal();
return TRUE;
}
else
{
CenterSelected();
}
}
}
// if return is pressed in primitive CSG mode
if( (pMsg->message==WM_KEYDOWN) && ((int)pMsg->wParam==VK_RETURN) && bCSGOn && bPrimitive)
{
pMainFrame->ShowInfoWindow();
CInfoSheet *pSheet = pMainFrame->m_pInfoFrame->m_pInfoSheet;
CWnd *pwndWidthEditCtrl = pSheet->m_PgPrimitive.GetDlgItem( IDC_WIDTH);
if( pwndWidthEditCtrl != NULL)
{
pSheet->SetActivePage( &pSheet->m_PgPrimitive);
pwndWidthEditCtrl->SetFocus();
}
}
FLOAT tmNow = _pTimer->GetHighPrecisionTimer().GetSeconds();
// if we caught key or button down message and not status line info pause requested
if( (theApp.m_tmStartStatusLineInfo<tmNow) &&
( (pMsg->message==WM_SYSKEYDOWN) ||
(pMsg->message==WM_KEYDOWN) ||
(pMsg->message==WM_KEYUP) ||
(pMsg->message==WM_LBUTTONDOWN) ||
(pMsg->message==WM_RBUTTONDOWN) ||
(pMsg->message==WM_LBUTTONUP) ||
(pMsg->message==WM_RBUTTONUP) ||
(pMsg->message==WM_MOUSEMOVE) ||
(pMsg->message==WM_CHANGE_EDITING_MODE) ||
(bShift || bAlt || bCtrl || bSpace || bLMB || bRMB)) )
{
// space without mouse buttons but ctrl pressed
if( bSpace && !bLMB && !bRMB && bCtrl)
{
STATUS_LINE_MESASGE( L"LMB zoomes in 2x, RMB zoomes out 2x");
}
// space without mouse buttons
else if( bSpace && !bLMB && !bRMB && !bShift)
{
STATUS_LINE_MESASGE( L"Rotate or move viewer. Try: LMB,RMB,LMB+RMB,Space+Ctrl");
}
// space with left mouse button
else if( bSpace && bLMB && !bRMB)
{
STATUS_LINE_MESASGE( L"Move viewer in view plane");
}
// space with right mouse button
else if( bSpace && !bLMB && bRMB)
{
STATUS_LINE_MESASGE( L"Move viewer in floor plane");
}
// space with both mouse buttons
else if( bSpace && bLMB && bRMB)
{
STATUS_LINE_MESASGE( L"Rotate viewer");
}
// Alt pressed
else if( bAlt && !bCtrl && !bShift)
{
STATUS_LINE_MESASGE( L"You can drag any view and drop it into browser");
}
// for measure mode
else if( theApp.m_bMeasureModeOn)
{
STATUS_LINE_MESASGE( L"Use LMB to measure distances");
}
// for cut mode
else if( theApp.m_bCutModeOn)
{
STATUS_LINE_MESASGE( L"Use LMB to move cut/mirror line, enter to apply");
}
// for CSG mode
else if( bCSGOn)
{
// for primitive mode
if( bPrimitive)
{
// primitive mode, only <Ctrl> pressed
if( bCtrl && !bLMB && !bRMB && !bShift)
{
STATUS_LINE_MESASGE( L"Use LMBx2 to teleport primitive. Try: LMB,RMB,LMB+RMB,Shift");
}
//-------- <Ctrl+Shift> commands for primitive
// primitive mode, <Ctrl+Shift> pressed
else if( bCtrl && !bLMB && !bRMB && bShift)
{
STATUS_LINE_MESASGE( L"Size and shear primitive. Try: LMB,RMB");
}
// primitive mode, <Ctrl+Shift+LMB> pressed
else if( bCtrl && bLMB && !bRMB && bShift)
{
STATUS_LINE_MESASGE( L"Resize primitive");
}
// primitive mode, <Ctrl+Shift+RMB> pressed
else if( bCtrl && !bLMB && bRMB && bShift)
{
STATUS_LINE_MESASGE( L"Shear primitive");
}
// primitive mode, <Ctrl+LMB> pressed
else if( bCtrl && bLMB && !bRMB && !bShift)
{
STATUS_LINE_MESASGE( L"Move primitive in view plane");
}
// primitive mode, <Ctrl+RMB> pressed
else if( bCtrl && !bLMB && bRMB && !bShift)
{
STATUS_LINE_MESASGE( L"Move primitive in floor plane");
}
// primitive mode, <Ctrl+LMB+RMB> pressed
else if( bCtrl && bLMB && bRMB && !bShift)
{
STATUS_LINE_MESASGE( L"Rotate primitive in view plane");
}
// <Shift> pressed
else if( !bCtrl && !bLMB && !bRMB && bShift)
{
STATUS_LINE_MESASGE( L"LMB inserts vertex, RMB deletes vertex. Try: Ctrl");
}
// primitive mode, nothing pressed
else
{
STATUS_LINE_MESASGE( L"Primitive mode. Try: Alt,Ctrl,Shift");
}
}
// for template mode
else
{
//-------- <Ctrl> commands for template (moving and rotating)
// template mode, only <Ctrl> pressed
if( bCtrl && !bLMB && !bRMB && !bShift)
{
STATUS_LINE_MESASGE( L"Use LMB dbl. click to teleport template. Try: LMB,RMB,LMB+RMB");
}
// template mode, <Ctrl+LMB> pressed
else if( bCtrl && bLMB && !bRMB && !bShift)
{
STATUS_LINE_MESASGE( L"Move template in view plane");
}
// template mode, <Ctrl+RMB> pressed
else if( bCtrl && !bLMB && bRMB && !bShift)
{
STATUS_LINE_MESASGE( L"Move template in floor plane");
}
// template mode, <Ctrl+LMB+RMB> pressed
else if( bCtrl && bLMB && bRMB && !bShift)
{
STATUS_LINE_MESASGE( L"Rotate template");
}
// template mode, nothing pressed
else
{
STATUS_LINE_MESASGE( L"Template primitive mode. Try: Ctrl");
}
}
}
// for entity mode
else if( bEntityMode)
{
// get property ID
CPropertyID *ppidProperty = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
// if we have at least one entity selected and edititng property of edit range type
// and Ctrl+Shift pressed
BOOL bEditingProperties = ( (pDoc->m_selEntitySelection.Count() != 0) &&
( (ppidProperty != NULL) &&
( (ppidProperty->pid_eptType == CEntityProperty::EPT_ANGLE3D) ||
(ppidProperty->pid_eptType == CEntityProperty::EPT_RANGE))) );
// entity mode, <Ctrl+Shift> pressed
if( bEditingProperties && bCtrl && bShift )
{
STATUS_LINE_MESASGE( L"Use LMB to change range or direction");
}
// <Alt + Ctrl> pressed
else if( bAlt && bCtrl)
{
STATUS_LINE_MESASGE( L"Use LMB to set entity ptr. (Entity ptr property must be selected)");
}
else if( bCtrl && bShift)
{
STATUS_LINE_MESASGE( L"Use RMB to set mip switch distance (in auto mode)");
}
else if( bSpace && bShift)
{
STATUS_LINE_MESASGE( L"Use RMB to change virtual mip distance");
}
// entity mode, <Shift> pressed
else if( !bCtrl && bShift)
{
STATUS_LINE_MESASGE( L"Use LMB to toggle selection of one entity . Try: Ctrl,Space");
}
// entity mode, <Ctrl> pressed
else if( bCtrl && !bLMB && !bRMB && !bShift)
{
if( bEditingProperties)
{
STATUS_LINE_MESASGE( L"Use LMBx2 click to teleport entity. Try: LMB,RMB,LMB+RMB,Shift");
}
else
{
STATUS_LINE_MESASGE( L"Use LMBx2 click to teleport entity. Try: Alt,LMB,RMB,LMB+RMB");
}
}
// entity mode, <Ctrl+LMB> pressed
else if( bCtrl && bLMB && !bRMB && !bShift)
{
STATUS_LINE_MESASGE( L"Move entities in view plane");
}
// entity mode, <Ctrl+RMB> pressed
else if( bCtrl && !bLMB && bRMB && !bShift)
{
STATUS_LINE_MESASGE( L"Move entities in floor plane");
}
// entity mode, <Ctrl+LMB+RMB> pressed
else if( bCtrl && bLMB && bRMB && !bShift)
{
STATUS_LINE_MESASGE( L"Rotate entities");
}
// entity mode, nothing pressed
else
{
if( bEditingProperties)
{
STATUS_LINE_MESASGE( L"Use LMB to select entities. Try: Ctrl,Shift");
}
else
{
STATUS_LINE_MESASGE( L"Use LMB to select entities. Try: Ctrl,Shift,Ctrl+Alt");
}
}
}
// for polygon mode
else if( bPolygonMode)
{
// polygon mode, <Ctrl> pressed
if( bCtrl && !bLMB && !bRMB && !bShift && !bAlt)
{
STATUS_LINE_MESASGE( L"LMBx2 centers texture. RMBx2 selects similar by texture. Try: LMB,LMB+RMB");
}
// polygon mode, <Shift> pressed
else if( !bCtrl && !bLMB && !bRMB && bShift && !bAlt)
{
STATUS_LINE_MESASGE( L"Toggle polygon using LMB or RMB. Add simillar with LMB dbl. click");
}
// polygon mode, <Ctrl+LMB> pressed
else if( bCtrl && bLMB && !bRMB && !bShift && !bAlt)
{
STATUS_LINE_MESASGE( L"Scroll polygon's mapping texture");
}
// polygon mode, <Ctrl+LMB+RMB> pressed
else if( bCtrl && bLMB && bRMB && !bShift && !bAlt)
{
STATUS_LINE_MESASGE( L"Rotate polygon's mapping texture");
}
else if( bCtrl && bAlt)
{
STATUS_LINE_MESASGE( L"Zoom in texture 2x using LMB, zoom out texture 2x using RMB");
}
// polygon mode, <Ctrl+Shift> pressed
else if( bCtrl && bShift)
{
STATUS_LINE_MESASGE( L"Select polygons similar by texture in sector with LMBx2, similar by color with RMBx2");
}
// polygon mode, nothing pressed
else if( !bCtrl && !bLMB && !bRMB && !bShift && !bAlt)
{
STATUS_LINE_MESASGE( L"Select polygons using LMB or RMB, by color using LMBx2. Try: Alt,Ctrl,Shift,Ctrl+Alt");
}
}
// for sector mode
else
{
// sector mode, <Shift> pressed
if( !bCtrl && !bLMB && !bRMB && bShift)
{
STATUS_LINE_MESASGE( L"Add to selection or deselect sector using LMB or LMB dbl. click");
}
// sector mode, nothing pressed
else
{
STATUS_LINE_MESASGE( L"Select or deselect sector using LMB or LMB dbl. click. Try: Alt,Shift");
}
}
// for these events
if( (pMsg->message==WM_KEYDOWN) ||
(pMsg->message==WM_KEYUP) ||
(pMsg->message==WM_LBUTTONDOWN) ||
(pMsg->message==WM_RBUTTONDOWN) ||
(pMsg->message==WM_LBUTTONUP) ||
(pMsg->message==WM_RBUTTONUP) )
{
// set text describing data that is edited
SetEditingDataPaneInfo( TRUE);
}
}
return CView::PreTranslateMessage(pMsg);
}
void CWorldEditorView::OnKeyO()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode()==TERRAIN_MODE)
{
theApp.m_iTerrainBrushMode=TBM_SMOOTH;
theApp.m_ctTerrainPageCanvas.MarkChanged();
pDoc->SetStatusLineModeInfoMessage();
}
else
{
OnCloneCSG();
}
}
void CWorldEditorView::OnUpdateKeyO(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode()==TERRAIN_MODE)
{
pCmdUI->Enable( TRUE);
}
else
{
OnUpdateCloneCsg(pCmdUI);
}
}
void CWorldEditorView::OnCloneCSG()
{
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CWorldEditorDoc* pDoc = GetDocument();
CDlgProgress dlgProgressDialog( pMainFrame);
// disable CSG report
theApp.m_bCSGReportEnabled = FALSE;
// and clear its values
_pfWorldEditingProfile.Reset();
// remember automatic info flag
BOOL bAutomaticInfo = theApp.m_Preferences.ap_AutomaticInfo;
// get shift pressed flag
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
// we will have 1 clone (by default)
INDEX ctClones = 1;
// if shift is pressed, we want "array of clones" (numeric option)
if( bAlt)
{
CDlgAutoDeltaCSG dlgAutoDeltaCSG;
// if dialog wasn't succeseful
if( dlgAutoDeltaCSG.DoModal() != IDOK)
{
return;
}
// temporary disable automatic info
theApp.m_Preferences.ap_AutomaticInfo = FALSE;
// get wanted count of clones
ctClones = dlgAutoDeltaCSG.m_ctNumberOfClones;
// write it to .ini file for the next time
theApp.WriteProfileInt(L"World editor", L"Number of CSG clones", ctClones);
}
// set wait cursor
CWaitCursor StartWaitCursor;
// if there is more than 1 clone in progress
if( ctClones > 1)
{
// create progress dialog
dlgProgressDialog.Create( IDD_PROGRESS_DIALOG);
dlgProgressDialog.SetWindowText(L"Repeat CSG");
// show progress window
dlgProgressDialog.ShowWindow( SW_SHOW);
// center window
dlgProgressDialog.CenterWindow();
// set progress range
dlgProgressDialog.m_ctrlProgres.SetRange( 0, (short) ctClones);
}
// if primitive CSG was last used CSG operation
if( pDoc->m_bLastUsedPrimitiveMode)
{
// for all clones
for( INDEX iClone=0; iClone<ctClones; iClone++)
{
// if there is more than 1 clone in progress
if( ctClones > 1)
{
char achrProgressMessage[ 256];
sprintf( achrProgressMessage, "Cloning CSG operation ... (processing %d/%d)",
iClone+1, ctClones);
// set message and progress position
dlgProgressDialog.SetProgressMessageAndPosition( achrProgressMessage, iClone+1);
}
// create new placement from delta placement
CPlacement3D plNewPlacement = pDoc->m_plDeltaPlacement;
// convert it into absolute space of last used placement (delta applyed)
plNewPlacement.RelativeToAbsolute( pDoc->m_plLastPlacement);
// copy last used values for primitive as initial values for this new primitive
theApp.m_vfpPreLast = theApp.m_vfpLast;
theApp.m_vfpCurrent = theApp.m_vfpLast;
// apply width, sheer, stretch, ... delta
theApp.m_vfpCurrent += theApp.m_vfpDelta;
// after substraction we colud get some invalid values (like negative width!!!)
// so we have to correct them
theApp.m_vfpCurrent.CorrectInvalidValues();
// we will snap primitive placement
pDoc->SnapToGrid( plNewPlacement, SNAP_FLOAT_25);
// create primitive but don't reset orientation angles
pDoc->StartPrimitiveCSG( plNewPlacement, FALSE);
// for last clone enable undo remembering
if( iClone > 0)
{
// disable undo remembering
theApp.m_bRememberUndo = FALSE;
}
// if shift was helded while starting clone CSG
if( bAlt)
{
// apply same CSG operation as was used last time
pDoc->ApplyCSG( pDoc->m_csgtLastUsedCSGOperation);
}
}
// if there is more than 1 clone in progress
if( ctClones > 1)
{
// destroy progress dialog
dlgProgressDialog.DestroyWindow();
}
}
// for templates
else
{
// for all clones
for( INDEX iClone=0; iClone<ctClones; iClone++)
{
// if there is more than 1 clone in progress
if( ctClones > 1)
{
char achrProgressMessage[ 256];
sprintf( achrProgressMessage, "Repeating last operation... (processing %d/%d)",
iClone+1, ctClones);
// set message and progress position
dlgProgressDialog.SetProgressMessageAndPosition( achrProgressMessage, iClone+1);
}
// create new placement from delta placement
CPlacement3D plNewPlacement = pDoc->m_plDeltaPlacement;
// convert it into absolute space of last used placement (delta applyed)
plNewPlacement.RelativeToAbsolute( pDoc->m_plLastPlacement);
// we will snap template placement
pDoc->SnapToGrid( plNewPlacement, SNAP_FLOAT_25);
// for last clone enable undo remembering
if( iClone > 0)
{
// disable undo remembering
theApp.m_bRememberUndo = FALSE;
}
// start template CSG but don't reset orientation angles
pDoc->StartTemplateCSG( plNewPlacement, pDoc->m_fnLastDroppedTemplate, FALSE);
// if shift was helded while starting clone CSG, we want to apply CSG
// if template was automaticly joined after droping, we are not in CSG_MODE any more
if( bAlt && (pDoc->GetEditingMode() == CSG_MODE) )
{
// apply same CSG operation as was used last time
pDoc->ApplyCSG( pDoc->m_csgtLastUsedCSGOperation);
}
}
// if there is more than 1 clone in progress
if( ctClones > 1)
{
// destroy progress dialog
dlgProgressDialog.DestroyWindow();
}
}
// enable undo remembering
theApp.m_bRememberUndo = TRUE;
// restore automatic info flag
theApp.m_Preferences.ap_AutomaticInfo = bAutomaticInfo;
// enable CSG report
theApp.m_bCSGReportEnabled = TRUE;
// and report calculated CSG report values
_pfWorldEditingProfile.Report( theApp.m_strCSGAndShadowStatistics);
theApp.m_strCSGAndShadowStatistics.SaveVar(CTString("Temp\\Profile_CSGWizard.txt"));
}
void CWorldEditorView::OnUpdateCloneCsg(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
// there can't be any kind of CSG going on if we want to clone last CSG operation
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
// there must be at least one CSG operation done
BOOL bCanBeCloned = ( (pDoc->m_csgtLastUsedCSGOperation == CSG_ADD) ||
(pDoc->m_csgtLastUsedCSGOperation == CSG_ADD_REVERSE) ||
(pDoc->m_csgtLastUsedCSGOperation == CSG_REMOVE) ||
(pDoc->m_csgtLastUsedCSGOperation == CSG_REMOVE_REVERSE) ||
(pDoc->m_csgtLastUsedCSGOperation == CSG_SPLIT_SECTORS) ||
(pDoc->m_csgtLastUsedCSGOperation == CSG_SPLIT_POLYGONS) ||
(pDoc->m_csgtLastUsedCSGOperation == CSG_JOIN_LAYERS) );
// last and current primitive CSG operation must have same primitive types
pCmdUI->Enable( bCanBeCloned && !bCSGOn &&
(pDoc->m_csgtPreLastUsedCSGOperation==pDoc->m_csgtLastUsedCSGOperation) &&
(pDoc->m_bPreLastUsedPrimitiveMode==pDoc->m_bLastUsedPrimitiveMode) &&
(!pDoc->m_bLastUsedPrimitiveMode ||
(pDoc->m_bLastUsedPrimitiveMode &&
(theApp.m_vfpPreLast.vfp_ptPrimitiveType == theApp.m_vfpLast.vfp_ptPrimitiveType))) );
}
void CWorldEditorView::OnPopupConus()
{
// start conus primitive
theApp.m_vfpCurrent = theApp.m_vfpConus;
CreatePrimitiveCalledFromPopup();
}
void CWorldEditorView::OnPopupTorus()
{
// start conus primitive
theApp.m_vfpCurrent = theApp.m_vfpTorus;
CreatePrimitiveCalledFromPopup();
}
void CWorldEditorView::OnPopupSphere()
{
// start conus primitive
theApp.m_vfpCurrent = theApp.m_vfpSphere;
CreatePrimitiveCalledFromPopup();
}
void CWorldEditorView::OnPopupStairs()
{
// start conus primitive
theApp.m_vfpCurrent = theApp.m_vfpStaircases;
CreatePrimitiveCalledFromPopup();
}
void CWorldEditorView::OnPopupTerrain()
{
// start conus primitive
theApp.m_vfpCurrent = theApp.m_vfpTerrain;
CreatePrimitiveCalledFromPopup();
}
void CWorldEditorView::CreatePrimitiveCalledFromPopup()
{
if( !m_bEntityHitedOnContext)
{
OnConusPrimitive();
}
CWorldEditorDoc* pDoc = GetDocument();
// create placement for primitive's position
CPlacement3D plDrop = m_plEntityHitOnContext;
// snap placement
pDoc->SnapToGrid( plDrop, m_fGridInMeters/GRID_DISCRETE_VALUES);
// create primitive for the first time, don't reset angles
pDoc->StartPrimitiveCSG( plDrop, FALSE);
}
void CWorldEditorView::OnMeasureOn()
{
theApp.m_bMeasureModeOn = !theApp.m_bMeasureModeOn;
theApp.m_bCutModeOn = FALSE;
}
void CWorldEditorView::OnUpdateMeasureOn(CCmdUI* pCmdUI)
{
pCmdUI->SetCheck( theApp.m_bMeasureModeOn);
}
void CWorldEditorView::OnResetViewer()
{
CWorldEditorDoc* pDoc = GetDocument();
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
// set new target
GetChildFrame()->m_mvViewer.SetTargetPlacement( FLOAT3D(0.0f, 0.0f, 0.0f));
_fFlyModeSpeedMultiplier=theApp.m_Preferences.ap_fDefaultFlyModeSpeed;
pMainFrame->ResetInfoWindowPos();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnCenterBcgViewer()
{
CWorldEditorDoc* pDoc = GetDocument();
// for all of the world's entities
CEntity *penBackgroundViewer = pDoc->m_woWorld.GetBackgroundViewer();
if( penBackgroundViewer != NULL)
{
// set new target
GetChildFrame()->m_mvViewer.SetTargetPlacement(
penBackgroundViewer->GetPlacement().pl_PositionVector);
pDoc->UpdateAllViews( NULL);
}
}
void CWorldEditorView::OnCopyTexture()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
OnPickLayer();
return;
}
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
if( pDoc->GetEditingMode() == SECTOR_MODE)
{
CBrushSector *pbscSector = crRayHit.cr_pbpoBrushPolygon->bpo_pbscSector;
CopySectorAmbient( pbscSector);
}
else
{
// get polygon's texture
CTextureData *pTD = (CTextureData *)crRayHit.cr_pbpoBrushPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.GetData();
if( pTD != NULL)
{
// get name from serial object
CTFileName fnTextureName = pTD->GetName();
// set it as new active texture
theApp.SetNewActiveTexture( _fnmApplicationPath + fnTextureName);
}
}
}
}
void CWorldEditorView::OnPasteTexture()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
theApp.m_iTerrainBrushMode=TBM_RND_NOISE;
theApp.m_ctTerrainPageCanvas.MarkChanged();
pDoc->SetStatusLineModeInfoMessage();
return;
}
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL))
{
if( pDoc->GetEditingMode() == SECTOR_MODE)
{
CBrushSector *pbscSector = crRayHit.cr_pbpoBrushPolygon->bpo_pbscSector;
PasteSectorAmbient( pbscSector);
}
else if( pDoc->GetEditingMode() == POLYGON_MODE)
{
PasteTexture( crRayHit.cr_pbpoBrushPolygon);
}
}
}
void CWorldEditorView::OnSelectByTextureAdjacent()
{
CWorldEditorDoc* pDoc = GetDocument();
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
// select similar by texture to hitted polygon
crRayHit.cr_pbpoBrushPolygon->SelectSimilarByTexture( pDoc->m_selPolygonSelection, pDoc->m_iTexture);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
}
void CWorldEditorView::OnSelectByTextureInSector()
{
CWorldEditorDoc* pDoc = GetDocument();
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
// select similar by texture to hitted polygon
crRayHit.cr_pbpoBrushPolygon->SelectByTextureInSector( pDoc->m_selPolygonSelection, pDoc->m_iTexture);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
}
void CWorldEditorView::OnSelectByColorInSector()
{
CWorldEditorDoc* pDoc = GetDocument();
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
// select similar by color to hitted polygon
crRayHit.cr_pbpoBrushPolygon->SelectByColorInSector( pDoc->m_selPolygonSelection);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
}
void CWorldEditorView::OnFunction()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->m_iMode == ENTITY_MODE)
{
pDoc->m_cenEntitiesSelectedByVolume.Clear();
// for each of the entities selected by volume
FOREACHINDYNAMICCONTAINER( pDoc->m_selEntitySelection, CEntity, iten)
{
// add entity into volume selection
if( !pDoc->m_cenEntitiesSelectedByVolume.IsMember(iten))
{
pDoc->m_cenEntitiesSelectedByVolume.Add( iten);
}
}
// go out of browse by volume mode
if( pDoc->m_bBrowseEntitiesMode) pDoc->OnBrowseEntitiesMode();
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
// obtain main frame ptr
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
// and refresh property combo manualy calling on idle
pMainFrame->m_PropertyComboBar.m_PropertyComboBox.OnIdle( 0);
// update all views
pDoc->UpdateAllViews( NULL);
}
else if( pDoc->m_iMode == POLYGON_MODE)
{
pDoc->OnFilterSelection();
}
else if( pDoc->m_iMode == VERTEX_MODE)
{
SnapSelectedVerticesToPlane();
}
else if( pDoc->m_iMode == TERRAIN_MODE)
{
theApp.m_iTerrainBrushMode=TBM_FILTER;
theApp.m_ctTerrainPageCanvas.MarkChanged();
pDoc->SetStatusLineModeInfoMessage();
}
}
void CWorldEditorView::SnapSelectedVerticesToPlane(void)
{
CWorldEditorDoc* pDoc = GetDocument();
pDoc->RememberUndo();
pDoc->m_woWorld.TriangularizeForVertices( pDoc->m_selVertexSelection);
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
CBrushPolygon *pbpo = crRayHit.cr_pbpoBrushPolygon;
CEntity *pen = pbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
CSimpleProjection3D_DOUBLE pr;
pr.ObjectPlacementL() = pen->GetPlacement();
pr.ViewerPlacementL() = _plOrigin;
pr.Prepare();
DOUBLEplane3D plAbsPrecise;
pr.Project(pbpo->bpo_pbplPlane->bpl_pldPreciseRelative, plAbsPrecise);
// snap vertices to plane
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
{
CEntity *pen = itbvx->bvx_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
CSimpleProjection3D_DOUBLE pr;
pr.ObjectPlacementL() = pen->GetPlacement();
pr.ViewerPlacementL() = _plOrigin;
pr.Prepare();
DOUBLE3D vAbsPrecise;
pr.ProjectCoordinate(itbvx->bvx_vdPreciseRelative, vAbsPrecise);
DOUBLE3D vOnPlaneAbsPrecise=plAbsPrecise.ProjectPoint(vAbsPrecise);
itbvx->SetAbsolutePosition(vOnPlaneAbsPrecise);
}}
}
pDoc->m_woWorld.UpdateSectorsDuringVertexChange( pDoc->m_selVertexSelection);
pDoc->m_woWorld.UpdateSectorsAfterVertexChange( pDoc->m_selVertexSelection);
pDoc->UpdateAllViews( NULL);
pDoc->SetModifiedFlag();
}
void CWorldEditorView::OnCrossroadForCtrlF()
{
CWorldEditorDoc* pDoc = GetDocument();
if(pDoc->GetEditingMode() == POLYGON_MODE)
{
OnFindTexture();
}
else if(pDoc->GetEditingMode() == VERTEX_MODE)
{
CDlgFilterVertexSelection dlg;
dlg.DoModal();
}
else if(pDoc->GetEditingMode() == TERRAIN_MODE)
{
theApp.m_iFilter=(theApp.m_iFilter+1)%FLT_COUNT;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
}
void CWorldEditorView::OnFindTexture()
{
CWorldEditorDoc* pDoc = GetDocument();
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
// get polygon's texture
CTextureData *pTD = (CTextureData *)crRayHit.cr_pbpoBrushPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.GetData();
if( pTD != NULL)
{
// get name from serial object
CTFileName fnTextureName = pTD->GetName();
// set it as new active texture
theApp.FindItemInBrowser( fnTextureName);
}
}
}
void CWorldEditorView::OnCenterEntity()
{
CWorldEditorDoc* pDoc = GetDocument();
if(pDoc->GetEditingMode() == CSG_MODE)
{
GetChildFrame()->m_mvViewer.SetTargetPlacement( pDoc->m_plSecondLayer.pl_PositionVector);
}
if(pDoc->GetEditingMode() == TERRAIN_MODE)
{
CTerrain *ptrTerrain=GetTerrain();
if(ptrTerrain!=NULL)
{
FLOATaabbox3D boxBoundingBox;
ptrTerrain->GetAllTerrainBBox(boxBoundingBox);
FLOAT3D vTerrainCenter=boxBoundingBox.Center();
GetChildFrame()->m_mvViewer.SetTargetPlacement( vTerrainCenter);
}
}
else
{
if( pDoc->m_selEntitySelection.Count() == 0) return;
// reset position
FLOAT3D vEntityPlacementAverage = FLOAT3D( 0.0f, 0.0f, 0.0f);
//for all selected entities
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
// get placement of current entity
CPlacement3D plEntityPlacement = iten->GetPlacement();
// add movement offset to placement
vEntityPlacementAverage += plEntityPlacement.pl_PositionVector;
}
// calculate average position
vEntityPlacementAverage /= (FLOAT) pDoc->m_selEntitySelection.Count();
// set centered entity position as new viewer's target
GetChildFrame()->m_mvViewer.SetTargetPlacement( vEntityPlacementAverage);
}
// update all views
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnUpdateCenterEntity(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
// if we are in entity mode and we have at least 1 entity selected
pCmdUI->Enable( (pDoc->GetEditingMode() == CSG_MODE) ||
((pDoc->GetEditingMode() == TERRAIN_MODE) &&
(GetTerrain()!=NULL)) ||
((pDoc->GetEditingMode() == ENTITY_MODE) &&
(pDoc->m_selEntitySelection.Count() != 0)) );
}
void CWorldEditorView::OnDropMarker()
{
CWorldEditorDoc* pDoc = GetDocument();
CTFileName fnDropClass;
CTString strTargetProperty;
if(pDoc->m_selEntitySelection.Count() == 1)
{
CEntity &enOnly = pDoc->m_selEntitySelection.GetFirst();
if(enOnly.DropsMarker( fnDropClass, strTargetProperty))
{
OnDropMarker(enOnly.GetPlacement());
}
}
}
void CWorldEditorView::OnDropMarker(CPlacement3D plMarker)
{
CWorldEditorDoc* pDoc = GetDocument();
CTFileName fnDropClass, fnDummy;
CTString strTargetProperty;
CEntityProperty *penpProperty;
CEntity &enOnly = pDoc->m_selEntitySelection.GetFirst();
// obtain drop class and target property name
if( !enOnly.DropsMarker( fnDropClass, strTargetProperty)) return;
penpProperty = enOnly.PropertyForName( strTargetProperty);
CEntity *penFirstInChain;
if (enOnly.IsMarker())
{
penFirstInChain = &enOnly;
}
else
{
penFirstInChain = ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer);
}
CEntity *penSecondInChain = NULL;
// if first in chain exists, try getting his target
if( penFirstInChain != NULL)
{
if( !penFirstInChain->DropsMarker( fnDropClass, strTargetProperty)) return;
penpProperty = penFirstInChain->PropertyForName( strTargetProperty);
penSecondInChain = ENTITYPROPERTY( penFirstInChain, penpProperty->ep_slOffset, CEntityPointer);
}
// spawn entity
CEntity *penSpawned;
if( !enOnly.DropsMarker( fnDropClass, strTargetProperty)) return;
penpProperty = enOnly.PropertyForName( strTargetProperty);
try
{
// spawn one entity of class selected in browser
penSpawned = pDoc->m_woWorld.CreateEntity_t( plMarker, fnDropClass);
penSpawned->Initialize();
}
catch( char *strError)
{
AfxMessageBox( CString(strError));
return;
}
// if first in chain entity exists, set spawned entity to be his target
if( penFirstInChain != NULL)
{
if( !penFirstInChain->DropsMarker( fnDropClass, strTargetProperty)) return;
penpProperty = penFirstInChain->PropertyForName( strTargetProperty);
ENTITYPROPERTY( penFirstInChain, penpProperty->ep_slOffset, CEntityPointer) = penSpawned;
}
if( !penSpawned->DropsMarker( fnDropClass, strTargetProperty)) return;
penpProperty = penSpawned->PropertyForName( strTargetProperty);
if( penSecondInChain != NULL)
{
ENTITYPROPERTY( penSpawned, penpProperty->ep_slOffset, CEntityPointer) = penSecondInChain;
}
else
{
ENTITYPROPERTY( penSpawned, penpProperty->ep_slOffset, CEntityPointer) = penFirstInChain;
}
// set our only selected entity to point to spawned entity
if( !enOnly.DropsMarker( fnDropClass, strTargetProperty)) return;
penpProperty = enOnly.PropertyForName( strTargetProperty);
ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer) = penSpawned;
pDoc->SetModifiedFlag();
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnUpdateDropMarker(CCmdUI* pCmdUI)
{
CTFileName fnDropClass;
CTString strTargetProperty;
CWorldEditorDoc* pDoc = GetDocument();
// if we are in entity mode, we have 1 entity selected and entity can drop marker
if( (pDoc->GetEditingMode() == ENTITY_MODE) &&
(pDoc->m_selEntitySelection.Count() == 1) &&
(pDoc->m_selEntitySelection.GetFirst().DropsMarker( fnDropClass, strTargetProperty)) )
{
pCmdUI->Enable( TRUE);
}
else
{
pCmdUI->Enable( FALSE);
}
}
void CWorldEditorView::OnTestConnections()
{
CWorldEditorDoc* pDoc = GetDocument();
CEntityProperty *penpProperty;
CEntity &enOnly = pDoc->m_selEntitySelection.GetFirst();
CTString strTargetProperty;
// get target pointer for curently selected entity
enOnly.MovesByTargetedRoute( strTargetProperty);
penpProperty = enOnly.PropertyForName( strTargetProperty);
CEntity *penCurrent = ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer);
// if no target
if( penCurrent == NULL) {
// do nothing
return;
}
// get target pointer for its target (get next)
penCurrent->MovesByTargetedRoute( strTargetProperty);
penpProperty = penCurrent->PropertyForName( strTargetProperty);
CEntity *penNext = ENTITYPROPERTY( penCurrent, penpProperty->ep_slOffset, CEntityPointer);
// if no target
if( penNext == NULL) {
// do nothing
return;
}
// teleport to next
enOnly.SetPlacement( penNext->GetPlacement());
if (enOnly.en_RenderType == CEntity::RT_BRUSH)
{
DiscardShadows( &enOnly);
}
// set target pointer to next next
enOnly.MovesByTargetedRoute( strTargetProperty);
penpProperty = enOnly.PropertyForName( strTargetProperty);
ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer) = penNext;
// mark that document and selections are changed
pDoc->SetModifiedFlag();
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnTestConnectionsBack()
{
CWorldEditorDoc* pDoc = GetDocument();
CEntityProperty *penpProperty;
CEntity &enOnly = pDoc->m_selEntitySelection.GetFirst();
CTString strTargetProperty;
// get target pointer for curently selected entity
enOnly.MovesByTargetedRoute( strTargetProperty);
penpProperty = enOnly.PropertyForName( strTargetProperty);
CEntity *penCurrent = ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer);
// if no target
if( penCurrent == NULL) {
// do nothing
return;
}
// start from current
CEntity *penNext=penCurrent;
// repeat
FOREVER {
// get next target pointer
penNext->MovesByTargetedRoute( strTargetProperty);
penpProperty = penCurrent->PropertyForName( strTargetProperty);
CEntity *penNextNext = ENTITYPROPERTY( penNext, penpProperty->ep_slOffset, CEntityPointer);
// if no target
if( penNextNext == NULL) {
// do nothing
return;
}
// if the next one is same as where the entity started
if( penNextNext==penCurrent) {
// stop searching
break;
}
// go to that target
penNext = penNextNext;
}
// teleport to next
enOnly.SetPlacement( penNext->GetPlacement());
if (enOnly.en_RenderType == CEntity::RT_BRUSH)
{
DiscardShadows( &enOnly);
}
// set target pointer to next next
enOnly.MovesByTargetedRoute( strTargetProperty);
penpProperty = enOnly.PropertyForName( strTargetProperty);
ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer) = penNext;
// mark that document and selections are changed
pDoc->SetModifiedFlag();
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnUpdateTestConnections(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
BOOL bModeAndCount = (pDoc->GetEditingMode() == ENTITY_MODE) &&
( pDoc->m_selEntitySelection.Count() == 1);
BOOL bEnableCommand = FALSE;
// if we have only one entity selected and we are in entity mode
if( bModeAndCount)
{
CEntity &enOnly = pDoc->m_selEntitySelection.GetFirst();
CTString strTargetProperty;
// if we can perform test path function on this entity
if( enOnly.MovesByTargetedRoute( strTargetProperty))
bEnableCommand = TRUE;
}
pCmdUI->Enable( bEnableCommand);
}
void CWorldEditorView::OnUpdateTestConnectionsBack(CCmdUI* pCmdUI)
{
// update same as it is forward
OnUpdateTestConnections( pCmdUI);
}
#define PAPER (4.0f/5.0f)
void CWorldEditorView::OnAlignVolume()
{
// get draw port
CDrawPort *pdpValidDrawPort = GetDrawPort();
// if it is not valid
if( pdpValidDrawPort == NULL)
{
return;
}
CWorldEditorDoc* pDoc = GetDocument();
// create a slave viewer
CSlaveViewer svViewer(GetChildFrame()->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid,
pdpValidDrawPort);
// get zoom factor
FLOAT fZoom = svViewer.GetZoomFactor();
PIX pixWidth = pdpValidDrawPort->GetWidth();
PIX pixHeight = pdpValidDrawPort->GetHeight();
FLOAT fWidth = pixWidth/fZoom;
FLOAT fHeight = pixHeight/fZoom;
// get point in space that user is looking
FLOAT3D vTargetPoint = GetChildFrame()->m_mvViewer.GetTargetPlacement().pl_PositionVector;
pDoc->m_vCreateBoxVertice0 = FLOAT3D(
vTargetPoint(1)-fWidth*PAPER/2,
vTargetPoint(2)-fHeight*PAPER/2,
vTargetPoint(3)-fHeight*PAPER/2);
pDoc->m_vCreateBoxVertice1 = FLOAT3D(
vTargetPoint(1)+fWidth*PAPER/2,
vTargetPoint(2)+fHeight*PAPER/2,
vTargetPoint(3)+fHeight*PAPER/2);
pDoc->SelectEntitiesByVolumeBox();
// try to select first entity in volume
pDoc->SelectGivenEntity( 0);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnAlignPrimitive()
{
// get draw port
CDrawPort *pdpValidDrawPort = GetDrawPort();
// if it is not valid
if( pdpValidDrawPort == NULL)
{
return;
}
CWorldEditorDoc* pDoc = GetDocument();
// create a slave viewer
CSlaveViewer svViewer(GetChildFrame()->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid,
pdpValidDrawPort);
// get zoom factor
FLOAT fZoom = svViewer.GetZoomFactor();
PIX pixWidth = pdpValidDrawPort->GetWidth()*8/10;
PIX pixHeight = pdpValidDrawPort->GetHeight()*8/10;
FLOAT fWidth = pixWidth/fZoom;
FLOAT fHeight = pixHeight/fZoom;
// get point in space that user is looking
FLOAT3D vTargetPoint = GetChildFrame()->m_mvViewer.GetTargetPlacement().pl_PositionVector;
pDoc->m_plSecondLayer.pl_PositionVector = vTargetPoint;
fWidth = FLOAT( pow( 2.0f, floor(Log2(fWidth))));
fHeight = FLOAT( pow( 2.0f, floor(Log2(fHeight))));
theApp.m_vfpCurrent.vfp_fXMin = -fWidth/2.0f;
theApp.m_vfpCurrent.vfp_fXMax = fWidth/2.0f;
theApp.m_vfpCurrent.vfp_fYMin = -fHeight/2.0f;
theApp.m_vfpCurrent.vfp_fYMax = fHeight/2.0f;
theApp.m_vfpCurrent.vfp_fZMin = -fHeight/2.0f;
theApp.m_vfpCurrent.vfp_fZMax = fHeight/2.0f;
pDoc->SnapToGrid( pDoc->m_plSecondLayer, m_fGridInMeters/GRID_DISCRETE_VALUES);
if( pDoc->m_bAutoSnap)
{
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fXMin, m_fGridInMeters/GRID_DISCRETE_VALUES);
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fXMax, m_fGridInMeters/GRID_DISCRETE_VALUES);
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fYMin, m_fGridInMeters/GRID_DISCRETE_VALUES);
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fYMax, m_fGridInMeters/GRID_DISCRETE_VALUES);
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fZMin, m_fGridInMeters/GRID_DISCRETE_VALUES);
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fZMax, m_fGridInMeters/GRID_DISCRETE_VALUES);
}
else
{
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fXMin, SNAP_FLOAT_CM);
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fXMax, SNAP_FLOAT_CM);
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fYMin, SNAP_FLOAT_CM);
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fYMax, SNAP_FLOAT_CM);
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fZMin, SNAP_FLOAT_CM);
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fZMax, SNAP_FLOAT_CM);
}
pDoc->RefreshPrimitivePage();
pDoc->CreatePrimitive();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnUpdateAlignVolume(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
pCmdUI->Enable( pDoc->m_bBrowseEntitiesMode);
}
void CWorldEditorView::OnCurrentViewProperties()
{
// copy selected preferences from view rendering preferences to temporary buffer
theApp.m_vpViewPrefs[ VIEW_PREFERENCES_CT] = m_vpViewPrefs;
// call edit view preferences with temporary view preferences buffer (last one)
CDlgRenderingPreferences dlg( VIEW_PREFERENCES_CT);
// if dialog ended with cancel or esc, dont switch to changed preferences
if( dlg.DoModal() != IDOK)
{
// don't set new preferences
return;
}
// copy selected preferences to view's rendering preferences
m_vpViewPrefs = theApp.m_vpViewPrefs[ VIEW_PREFERENCES_CT];
// see the change
Invalidate( FALSE);
}
void CWorldEditorView::OnChooseColor()
{
/*
// find toll bar's rectangle
RECT rectToolBar;
m_wndSelectionTools.GetWindowRect( &rectToolBar);
// Then we find tool button's index
INDEX iToolButton = m_wndSelectionTools.CommandToIndex( ID_CHOOSE_COLOR);
// Using given index, we obtain button's rectangle
RECT rectButton;
m_wndSelectionTools.GetItemRect( iToolButton, &rectButton);
// set screen coordinates of LU point of clicked tool button
CustomColorPicker( rectToolBar.left + rectButton.left, rectToolBar.top + rectButton.bottom);
*/
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
POINT ptCursor;
GetCursorPos( &ptCursor);
if( ptCursor.y < 100)
{
pMainFrame->CustomColorPicker( ptCursor.x-50, ptCursor.y);
}
else
{
pMainFrame->CustomColorPicker( ptCursor.x-50, ptCursor.y-100);
}
}
void CWorldEditorView::OnUpdateChooseColor(CCmdUI* pCmdUI)
{
// don't enable initially
BOOL bEnable = FALSE;
// obtain document
CWorldEditorDoc *pDoc = GetDocument();
// if sector mode is on and there is at least 1 selected sector
if( (pDoc->m_iMode == SECTOR_MODE) && (pDoc->m_selSectorSelection.Count() != 0) )
{
bEnable = TRUE;
}
// if polygon mode is on and there is at least 1 selected polygon
if( (pDoc->m_iMode == POLYGON_MODE) && (pDoc->m_selPolygonSelection.Count() != 0) )
{
bEnable = TRUE;
}
pCmdUI->Enable( bEnable);
}
void CWorldEditorView::OnCrossroadForC()
{
PostMessage( WM_COMMAND, ID_CHOOSE_COLOR, 0);
PostMessage( WM_COMMAND, ID_CENTER_ENTITY, 0);
}
void CWorldEditorView::SetAsCsgTarget(CEntity *pen)
{
if( (pen != NULL) &&
( (pen->GetRenderType() == CEntity::RT_BRUSH) ||
(pen->GetRenderType() == CEntity::RT_FIELDBRUSH)) )
{
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
pMainFrame->m_CSGDesitnationCombo.SelectBrushEntity(pen);
}
}
void CWorldEditorView::OnSetAsCsgTarget()
{
SetAsCsgTarget(m_penEntityHitOnContext);
}
void CWorldEditorView::OnCsgSelectSector()
{
if( (m_penEntityHitOnContext != NULL) &&
((m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) ||
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_FIELDBRUSH)) &&
(m_pbpoRightClickedPolygon != NULL) )
{
CBrushSector *pbscHitted = m_pbpoRightClickedPolygon->bpo_pbscSector;
CWorldEditorDoc *pDoc = GetDocument();
pDoc->m_selSectorSelection.Clear();
pDoc->m_selSectorSelection.Select( *pbscHitted);
}
}
LRESULT CWorldEditorView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
CChildFrame *pCF = GetChildFrame();
// if test game is active
if( _pInput->IsInputEnabled())
{ // repost some messages to thread
switch( message ) {
case WM_CANCELMODE:
case WM_KILLFOCUS:
case WM_ACTIVATEAPP:
case WM_LBUTTONUP:
::PostMessage(NULL, message, wParam, lParam);
break;
case WM_MOUSEACTIVATE:
if( pCF->m_bTestGameOn)
{
return MA_ACTIVATEANDEAT;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
}
return CView::WindowProc(message, wParam, lParam);
}
void CWorldEditorView::OnRButtonDblClk(UINT nFlags, CPoint point)
{
m_iaInputAction = IA_NONE;
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
BOOL bLMB = nFlags & MK_LBUTTON;
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
// space+ctrl+rmb zoomes out 2x
if( (bSpace) && (bCtrl) )
{
if( bLMB) return;
OnZoomLess();
return;
}
// RMB dblclick and ctrl select by texture in sector
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == POLYGON_MODE)
{
// Alt+Ctrl requests that clicked polygon sizes its texture
if( bAlt && bCtrl)
{
MultiplyMappingOnPolygon( 2.0f);
}
else if( bCtrl && bShift && !bAlt)
{
OnSelectByColorInSector();
}
else if( bCtrl && !bAlt)
{
OnSelectByTextureAdjacent();
}
}
CView::OnRButtonDblClk(nFlags, point);
}
void CWorldEditorView::OnLastPrimitive()
{
CWorldEditorDoc* pDoc = GetDocument();
CTString strError;
BOOL bCutEnabled = IsCutEnabled( strError);
if( theApp.m_bCutModeOn)
{
if( !bCutEnabled)
{
// exit cut mode
theApp.m_bCutModeOn = FALSE;
WarningMessage( "%s", strError);
return;
}
pDoc->ApplyCut();
}
else
{
// exit cut mode
theApp.m_bCutModeOn = FALSE;
pDoc->StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
}
}
void CWorldEditorView::OnUpdateLastPrimitive(CCmdUI* pCmdUI)
{
pCmdUI->Enable( GetDocument()->m_pwoSecondLayer == NULL);
}
void CWorldEditorView::OnConusPrimitive()
{
// copy last used values for conus primitive as initial values for new primitive
theApp.m_vfpCurrent = theApp.m_vfpConus;
CWorldEditorDoc* pDoc = GetDocument();
pDoc->StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
}
void CWorldEditorView::OnTorusPrimitive()
{
// copy last used values for torus primitive as initial values for new primitive
theApp.m_vfpCurrent = theApp.m_vfpTorus;
// create primitive for the first time
CWorldEditorDoc* pDoc = GetDocument();
pDoc->StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
}
void CWorldEditorView::OnStaircasePrimitive()
{
// copy last used values for staircase primitive as initial values for new primitive
theApp.m_vfpCurrent = theApp.m_vfpStaircases;
// create primitive for the first time
CWorldEditorDoc* pDoc = GetDocument();
pDoc->StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
}
void CWorldEditorView::OnSpherePrimitive()
{
// copy last used values for sphere primitive as initial values for new primitive
theApp.m_vfpCurrent = theApp.m_vfpSphere;
// create primitive for the first time
CWorldEditorDoc* pDoc = GetDocument();
pDoc->StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
}
void CWorldEditorView::OnTerrainPrimitive()
{
// copy last used values for terrain primitive as initial values for new primitive
theApp.m_vfpCurrent = theApp.m_vfpTerrain;
// create primitive for the first time
CWorldEditorDoc* pDoc = GetDocument();
pDoc->StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
}
void CWorldEditorView::OnUpdateConusPrimitive(CCmdUI* pCmdUI)
{
pCmdUI->Enable( GetDocument()->m_pwoSecondLayer == NULL);
}
void CWorldEditorView::OnUpdateSpherePrimitive(CCmdUI* pCmdUI)
{
pCmdUI->Enable( GetDocument()->m_pwoSecondLayer == NULL);
}
void CWorldEditorView::OnUpdateTerrainPrimitive(CCmdUI* pCmdUI)
{
pCmdUI->Enable( GetDocument()->m_pwoSecondLayer == NULL);
}
void CWorldEditorView::OnUpdateTorusPrimitive(CCmdUI* pCmdUI)
{
pCmdUI->Enable( GetDocument()->m_pwoSecondLayer == NULL);
}
void CWorldEditorView::OnUpdateStaircasePrimitive(CCmdUI* pCmdUI)
{
pCmdUI->Enable( GetDocument()->m_pwoSecondLayer == NULL);
}
void CWorldEditorView::OnUpdateMoveDown(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
pCmdUI->Enable( (pDoc->m_pwoSecondLayer != NULL) &&
(pDoc->m_bPrimitiveMode) &&
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) );
}
void CWorldEditorView::OnUpdateMoveUp(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
pCmdUI->Enable( (pDoc->m_pwoSecondLayer != NULL) &&
(pDoc->m_bPrimitiveMode) &&
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) );
}
void CWorldEditorView::OnSelectLights()
{
CWorldEditorDoc* pDoc = GetDocument();
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
CBrushPolygon *pbpoPolygon = crRayHit.cr_pbpoBrushPolygon;
// if we hit brush entity
if( (crRayHit.cr_penHit == NULL) ||
(pbpoPolygon == NULL) ||
(pbpoPolygon->IsSelected(BPOF_SELECTED)) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
CBrushShadowMap &bsm = itbpo->bpo_smShadowMap;
FOREACHINLIST(CBrushShadowLayer, bsl_lnInShadowMap, bsm.bsm_lhLayers, itbsl)
{
CLightSource *plsLight = itbsl->bsl_plsLightSource;
CEntity *penLight = plsLight->ls_penEntity;
if( !pDoc->m_selEntitySelection.IsSelected( *penLight))
{
pDoc->m_selEntitySelection.Select( *penLight);
}
}
}
}
else
{
CBrushShadowMap &bsm = pbpoPolygon->bpo_smShadowMap;
FOREACHINLIST(CBrushShadowLayer, bsl_lnInShadowMap, bsm.bsm_lhLayers, itbsl)
{
CLightSource *plsLight = itbsl->bsl_plsLightSource;
CEntity *penLight = plsLight->ls_penEntity;
if( !pDoc->m_selEntitySelection.IsSelected( *penLight))
{
pDoc->m_selEntitySelection.Select( *penLight);
}
}
}
pDoc->SetEditingMode( ENTITY_MODE);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnDiscardShadows()
{
CWorldEditorDoc* pDoc = GetDocument();
CEntity *penEntity = NULL;
CBrushSector *pbscSector = NULL;
CBrushPolygon *pbpoPolygon = NULL;
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
penEntity = crRayHit.cr_penHit;
pbscSector = crRayHit.cr_pbpoBrushPolygon->bpo_pbscSector;
pbpoPolygon = crRayHit.cr_pbpoBrushPolygon;
}
if( pDoc->GetEditingMode() == ENTITY_MODE)
{
DiscardShadows( penEntity);
}
else if( pDoc->GetEditingMode() == SECTOR_MODE)
{
DiscardShadows( pbscSector);
}
else if( pDoc->GetEditingMode() == POLYGON_MODE)
{
DiscardShadows( pbpoPolygon);
}
}
void CWorldEditorView::OnCopySectorAmbient()
{
CWorldEditorDoc *pDoc = GetDocument();
CBrushSector *pbscHitted = NULL;
if( (m_penEntityHitOnContext != NULL) &&
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) &&
(m_pbpoRightClickedPolygon != NULL) )
{
CopySectorAmbient( m_pbpoRightClickedPolygon->bpo_pbscSector);
}
}
void CWorldEditorView::OnPasteSectorAmbient()
{
CWorldEditorDoc *pDoc = GetDocument();
CBrushSector *pbscHitted = NULL;
if( (m_penEntityHitOnContext != NULL) &&
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) &&
(m_pbpoRightClickedPolygon != NULL) )
{
PasteSectorAmbient( m_pbpoRightClickedPolygon->bpo_pbscSector);
}
}
void CWorldEditorView::OnSelectAllPolygons( void)
{
CWorldEditorDoc *pDoc = GetDocument();
CBrushSector *pbscHitted = NULL;
if( (m_penEntityHitOnContext != NULL) &&
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) &&
(m_pbpoRightClickedPolygon != NULL) )
{
pbscHitted = m_pbpoRightClickedPolygon->bpo_pbscSector;
}
if( (pbscHitted == NULL) || pbscHitted->IsSelected( BSCF_SELECTED) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
{
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
{
if( !itbpo->IsSelected(BPOF_SELECTED)) pDoc->m_selPolygonSelection.Select( *itbpo);
}
}
}
else
{
FOREACHINSTATICARRAY(pbscHitted->bsc_abpoPolygons, CBrushPolygon, itpo)
{
if( !itpo->IsSelected(BPOF_SELECTED)) pDoc->m_selPolygonSelection.Select( *itpo);
}
}
pDoc->SetEditingMode( POLYGON_MODE);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnSelectAllVertices()
{
CWorldEditorDoc *pDoc = GetDocument();
CBrushPolygon *pbpoHitted = NULL;
if( (m_penEntityHitOnContext != NULL) &&
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) &&
(m_pbpoRightClickedPolygon != NULL) )
{
pbpoHitted = m_pbpoRightClickedPolygon;
}
if( (pbpoHitted == NULL) || pbpoHitted->IsSelected( BPOF_SELECTED) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
FOREACHINSTATICARRAY(itbpo->bpo_apbvxTriangleVertices, CBrushVertex *, itpbvx)
{
if( !(*itpbvx)->IsSelected(BVXF_SELECTED)) pDoc->m_selVertexSelection.Select( **itpbvx);
}
}
}
else
{
FOREACHINSTATICARRAY(pbpoHitted->bpo_apbvxTriangleVertices, CBrushVertex *, itpbvx)
{
if( !(*itpbvx)->IsSelected(BVXF_SELECTED)) pDoc->m_selVertexSelection.Select( **itpbvx);
}
}
pDoc->SetEditingMode( VERTEX_MODE);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnCopySectors()
{
OnEditCopy();
}
void CWorldEditorView::OnPasteSectors()
{
OnEditPaste();
}
void CWorldEditorView::OnDeleteSectors()
{
OnDeleteEntities();
}
void CWorldEditorView::GetToolTipText( char *pToolTipText)
{
CWorldEditorDoc* pDoc = GetDocument();
CPoint CursorPos;
::GetCursorPos(&CursorPos);
ScreenToClient(&CursorPos);
// obtain information about where mouse points into the world
BOOL bHitModels = pDoc->GetEditingMode() != POLYGON_MODE;
BOOL bHitFields = pDoc->GetEditingMode() == ENTITY_MODE;
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse, FALSE, bHitModels, bHitFields);
CEntity *penEntity = crRayHit.cr_penHit;
CBrushPolygon *pbpoPolygon = crRayHit.cr_pbpoBrushPolygon;
CBrushSector *pbscSector = NULL;
if( pbpoPolygon != NULL) pbscSector = crRayHit.cr_pbpoBrushPolygon->bpo_pbscSector;
char *pchrCursor = pToolTipText;
INDEX iLongestLineLetters = 1;
CDLLEntityClass *pdecDLLClass;
if( (pDoc->GetEditingMode() == ENTITY_MODE) && (penEntity != NULL))
{
// get description line for all properties with name
pdecDLLClass = penEntity->GetClass()->ec_pdecDLLClass;
pchrCursor += sprintf(pchrCursor, "Class: %-24.24s\n", pdecDLLClass->dec_strName);
INDEX ctLetters = strlen("Class: ")+strlen(pdecDLLClass->dec_strName);
memset(pchrCursor, '<EFBFBD>', ctLetters);
pchrCursor+=ctLetters;
*pchrCursor = '\n';
pchrCursor++;
}
INDEX ctMips = 0;
INDEX iMipIndex = 0;
INDEX ctEntities = 0;
INDEX ctSectors = 0;
INDEX ctPolygons = 0;
INDEX ctEdges = 0;
INDEX ctVertices = 0;
INDEX ctPlanes = 0;
// see if info should apply to whole selection
BOOL bCountSelection = TRUE;
if( (pDoc->GetEditingMode() == ENTITY_MODE) &&
(penEntity != NULL) &&
(!penEntity->IsSelected( ENF_SELECTED)) )
{
bCountSelection = FALSE;
}
if( (pDoc->GetEditingMode() == POLYGON_MODE) &&
(pbpoPolygon != NULL) &&
(!pbpoPolygon->IsSelected( BPOF_SELECTED)) )
{
bCountSelection = FALSE;
}
if( (pDoc->GetEditingMode() == SECTOR_MODE) &&
(pbscSector != NULL) &&
(!pbscSector->IsSelected( BSCF_SELECTED)) )
{
bCountSelection = FALSE;
}
if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
CTerrain *ptrTerrain=GetTerrain();
if(ptrTerrain!=NULL)
{
pchrCursor += sprintf(pchrCursor, "%-24s %g x %g x %g\n%-24s %d x %d\n%-24s %d x %d\n%-24s %d x %d\n%-24s %d\n%-24s %d\n%-24s %g\n",
"Terrain size", ptrTerrain->tr_vTerrainSize(1),ptrTerrain->tr_vTerrainSize(2),ptrTerrain->tr_vTerrainSize(3),
"Height map size", ptrTerrain->tr_pixHeightMapWidth, ptrTerrain->tr_pixHeightMapHeight,
"Shadow map size", ptrTerrain->GetShadowMapWidth(), ptrTerrain->GetShadowMapHeight(),
"Model shading map size", ptrTerrain->GetShadingMapWidth(), ptrTerrain->GetShadingMapHeight(),
"Layers", ptrTerrain->tr_atlLayers.Count(),
"Tiles", ptrTerrain->tr_ctTiles,
"LOD switch distance", ptrTerrain->tr_fDistFactor);
}
else
{
pchrCursor += sprintf(pchrCursor, "Terrain not selected\n");
}
}
if( pDoc->GetEditingMode() == ENTITY_MODE)
{
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
if( (bCountSelection && iten->IsSelected( ENF_SELECTED)) ||
(!bCountSelection && (iten ==penEntity)) )
{
ctEntities ++;
CEntity::RenderType rt = iten->GetRenderType();
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
{
CBrush3D *pBrush3D = iten->GetBrush();
if(pBrush3D != NULL)
{
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
CBrush3D *pbrBrush = iten->GetBrush();
if( pbrBrush != NULL)
{
CBrushMip *pbmCurrentMip = pbrBrush->GetBrushMipByDistance( fCurrentMipFactor);
if( pbmCurrentMip != NULL)
{
ctSectors += pbmCurrentMip->bm_abscSectors.Count();
FOREACHINDYNAMICARRAY(pbmCurrentMip->bm_abscSectors, CBrushSector, itbsc)
{
ctPolygons += itbsc->bsc_abpoPolygons.Count();
ctEdges += itbsc->bsc_abedEdges.Count();
ctVertices+= itbsc->bsc_abvxVertices.Count();
ctPlanes += itbsc->bsc_abplPlanes.Count();
}
}
}
}
}
}
}
pchrCursor += sprintf(pchrCursor, "%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d\n",
"No of entities:", ctEntities,
"No of sectors:", ctSectors,
"No of polygons:", ctPolygons,
"No of edges:", ctEdges,
"No of vertices:", ctVertices,
"No of planes:", ctPlanes);
pchrCursor += sprintf(pchrCursor, "%s\n", "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
if( !bCountSelection)
{
CEntity::RenderType rt = penEntity->GetRenderType();
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
{
CBrush3D *pBrush3D = penEntity->GetBrush();
if(pBrush3D != NULL)
{
INDEX iMip = 0;
FOREACHINLIST(CBrushMip, bm_lnInBrush, pBrush3D->br_lhBrushMips, itbm)
{
FLOAT fMipSwitchDistance = itbm->GetMipDistance();
CTString strTmp;
strTmp.PrintF("Mip %d is visible until ", iMip);
pchrCursor += sprintf(pchrCursor, "%-24s %g m\n", strTmp, fMipSwitchDistance);
iMip++;
}
pchrCursor += sprintf(pchrCursor, "%s\n", "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
}
}
}
}
if( pDoc->GetEditingMode() == POLYGON_MODE)
{
if( bCountSelection)
{
INDEX ctEdges = 0;
ULONG ulShadowMemory = 0;
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
ctEdges += itbpo->bpo_abpePolygonEdges.Count();
ulShadowMemory += itbpo->bpo_smShadowMap.GetShadowSize();
}
pchrCursor += sprintf(pchrCursor, "Selection has %d polygons with %d edges\n", pDoc->m_selPolygonSelection.Count(), ctEdges);
pchrCursor += sprintf(pchrCursor, "Shadows on selected polygons occupy %g kb\n", ulShadowMemory/1024.0f);
}
if( pbpoPolygon != NULL)
{
CTextureData *ptd;
#define SET_MAPPING_INFO(mp, tex_name)\
ptd = (CTextureData*) mp.bpt_toTexture.GetData();\
if( ptd == NULL) pchrCursor += sprintf(pchrCursor, "%-24s None\n", tex_name);\
else {\
pchrCursor += sprintf(pchrCursor, "%-24s %.64s %s\n", tex_name, CTString(ptd->GetName()),\
ptd->GetDescription() );\
pchrCursor += sprintf(pchrCursor, "%-24s %s %s\n", " ",\
"Scroll: \""+pDoc->m_woWorld.wo_attTextureTransformations[mp.s.bpt_ubScroll].tt_strName+"\"",\
"Blend: \""+pDoc->m_woWorld.wo_atbTextureBlendings[mp.s.bpt_ubBlend].tb_strName+"\"");}
CBrushPolygon &bpo = *crRayHit.cr_pbpoBrushPolygon;
SET_MAPPING_INFO( bpo.bpo_abptTextures[0], "Texture 1");
SET_MAPPING_INFO( bpo.bpo_abptTextures[1], "Texture 2");
SET_MAPPING_INFO( bpo.bpo_abptTextures[2], "Texture 3");
pchrCursor += sprintf(pchrCursor, "Polygon under mouse has %d edges\n", bpo.bpo_abpePolygonEdges.Count());
pchrCursor += sprintf(pchrCursor, "Shadow on polygon under mouse occupies %g kb\n", bpo.bpo_smShadowMap.GetShadowSize()/1024.0f);
}
}
if( pDoc->GetEditingMode() == SECTOR_MODE)
{
if( bCountSelection)
{
ctSectors = pDoc->m_selSectorSelection.Count();
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
{
ctPolygons += itbsc->bsc_abpoPolygons.Count();
ctEdges += itbsc->bsc_abedEdges.Count();
ctVertices+= itbsc->bsc_abvxVertices.Count();
ctPlanes += itbsc->bsc_abplPlanes.Count();
}
pchrCursor += sprintf(pchrCursor, "%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d\n%",
"No of sectors:", ctSectors,
"No of polygons:", ctPolygons,
"No of edges:", ctEdges,
"No of vertices:", ctVertices,
"No of planes:", ctPlanes);
}
else
{
ctPolygons = pbscSector->bsc_abpoPolygons.Count();
ctEdges = pbscSector->bsc_abedEdges.Count();
ctVertices = pbscSector->bsc_abvxVertices.Count();
ctPlanes = pbscSector->bsc_abplPlanes.Count();
UBYTE ubR, ubG, ubB;
UBYTE ubH, ubS, ubV;
ColorToRGB( pbscSector->bsc_colAmbient, ubR, ubG, ubB);
ColorToHSV( pbscSector->bsc_colAmbient, ubH, ubS, ubV);
CTString strSectorName = pbscSector->bsc_strName;
if( strSectorName == "") strSectorName = "<not defined>";
INDEX iContentType = pbscSector->GetContentType();
CTString strContentType = pDoc->m_woWorld.wo_actContentTypes[iContentType].ct_strName;
if( strContentType == "") strContentType = "<not defined>";
INDEX iEnvironmentType = pbscSector->GetEnvironmentType();
CTString strEnvironmentType = pDoc->m_woWorld.wo_aetEnvironmentTypes[iEnvironmentType].et_strName;
if( strEnvironmentType == "") strEnvironmentType = "<not defined>";
INDEX iForceType = pbscSector->GetForceType();
CBrush3D *pbrBrush = pbscSector->bsc_pbmBrushMip->bm_pbrBrush;
CTString strForceType = pbrBrush->br_penEntity->GetForceName( iForceType);
if( strForceType == "") strForceType = "<not defined>";
pchrCursor += sprintf(pchrCursor, "%-24.24s %.64s\n%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d\n%-24s"
"(R=%d G=%d B=%d) (H=%d S=%d V=%d)\n%-24.24s %.64s\n%-24.24s %.64s\n%-24.24s %.64s\n",
"Name:", strSectorName,
"No of polygons:", ctPolygons,
"No of edges:", ctEdges,
"No of vertices:", ctVertices,
"No of planes:", ctPlanes,
"Ambient color:", ubR, ubG, ubB, ubH, ubS, ubV,
"Content type:", strContentType,
"Environment type:", strEnvironmentType,
"Force type:", strForceType);
}
}
if( pDoc->GetEditingMode() == CSG_MODE)
{
FOREACHINDYNAMICCONTAINER(pDoc->m_pwoSecondLayer->wo_cenEntities, CEntity, iten)
{
CEntity::RenderType rt = iten->GetRenderType();
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
{
CBrush3D *pBrush3D = iten->GetBrush();
if( pBrush3D != NULL)
{
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
CBrush3D *pbrBrush = iten->GetBrush();
if( pbrBrush != NULL)
{
CBrushMip *pbmCurrentMip = pbrBrush->GetBrushMipByDistance( fCurrentMipFactor);
if( pbmCurrentMip != NULL)
{
FOREACHINDYNAMICARRAY(pbmCurrentMip->bm_abscSectors, CBrushSector, itbsc)
{
ctPolygons += itbsc->bsc_abpoPolygons.Count();
ctEdges += itbsc->bsc_abedEdges.Count();
ctVertices+= itbsc->bsc_abvxVertices.Count();
ctPlanes += itbsc->bsc_abplPlanes.Count();
}
}
}
}
}
}
pchrCursor += sprintf(pchrCursor, "Primitive info:\n<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\n%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d",
"No of polygons:", ctPolygons,
"No of edges:", ctEdges,
"No of vertices:", ctVertices,
"No of planes:", ctPlanes);
}
if( (pDoc->GetEditingMode() == ENTITY_MODE) && (penEntity!=NULL) )
{
// add count of occupiing sectors and their names
INDEX ctIntersectingSectors = penEntity->en_rdSectors.Count();
INDEX ctWithName = 0;
{FOREACHSRCOFDST(penEntity->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
if( pbsc->bsc_strName != "") ctWithName++;
ENDFOR}
INDEX ctLetters = sprintf(pchrCursor, "In %d sectors (%d with name):\n", ctIntersectingSectors, ctWithName);
if( ctLetters > iLongestLineLetters) iLongestLineLetters = ctLetters;
pchrCursor += ctLetters;
{FOREACHSRCOFDST(penEntity->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
if( pbsc->bsc_strName != "")
{
INDEX ctLetters = sprintf(pchrCursor, "In: %-24.24s\n", pbsc->bsc_strName);
if( ctLetters > iLongestLineLetters) iLongestLineLetters = ctLetters;
pchrCursor += ctLetters;
}
ENDFOR}
for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
{
CTString strValue;
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
{
CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
if( epProperty.ep_strName == CTString("")) continue;
strValue = "!!! Unkown property type";
switch( epProperty.ep_eptType)
{
case CEntityProperty::EPT_FLAGS:
{
strValue = "Flag array property";
}
case CEntityProperty::EPT_ENUM:
{
INDEX iCurrentEnum = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, INDEX);
CEntityPropertyEnumType *epEnum = epProperty.ep_pepetEnumType;
for( INDEX iEnum = 0; iEnum< epEnum->epet_ctValues; iEnum++)
{
INDEX iEnumID = epEnum->epet_aepevValues[ iEnum].epev_iValue;
if( iEnumID == iCurrentEnum)
strValue = (epEnum->epet_aepevValues[ iEnum].epev_strName);
}
break;
}
case CEntityProperty::EPT_BOOL:
{
if( ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, BOOL))strValue = "TRUE";
else strValue = "FALSE";
break;
}
case CEntityProperty::EPT_FLOAT:
{
strValue.PrintF( "%g", ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, FLOAT));
break;
}
case CEntityProperty::EPT_RANGE:
{
strValue.PrintF( "%g m", ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, FLOAT));
break;
}
case CEntityProperty::EPT_COLOR:
{
COLOR colColor = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, COLOR);
UBYTE ubR, ubG, ubB, ubA;
UBYTE ubH, ubS, ubV;
ubA=colColor&0xFF;
ColorToRGB( colColor, ubR, ubG, ubB);
ColorToHSV( colColor, ubH, ubS, ubV);
strValue.PrintF( "RGBA(%d,%d,%d,%d) HSV(%d,%d,%d)", ubR,ubG,ubB,ubA,ubH,ubS,ubV);
break;
}
case CEntityProperty::EPT_STRING:
case CEntityProperty::EPT_STRINGTRANS:
case CEntityProperty::EPT_FILENAMENODEP:
{
strValue = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, CTString);
if( strValue == "") strValue = "<no value>";
break;
}
case CEntityProperty::EPT_ENTITYPTR:
{
CEntity *pen=ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, CEntity *);
if( pen == NULL) strValue = "-> None";
else strValue = "-> "+pen->GetName();
break;
}
case CEntityProperty::EPT_PARENT:
{
CEntity *pen=penEntity->GetParent();
if( pen == NULL) strValue = "-> None";
else strValue = "-> "+pen->GetName();
break;
}
case CEntityProperty::EPT_FILENAME:
{
strValue = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, CTFileName);
if( strValue == "") strValue = "<no file>";
break;
}
case CEntityProperty::EPT_INDEX:
case CEntityProperty::EPT_ANGLE:
{
strValue.PrintF( "%d", ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, INDEX) );
break;
}
case CEntityProperty::EPT_ANIMATION:
{
CAnimData *pAD = penEntity->GetAnimData( epProperty.ep_slOffset);
if( pAD == NULL)
{
strValue = "<no animation>";
}
else
{
CAnimInfo aiInfo;
INDEX iAnimation = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, INDEX);
pAD->GetAnimInfo( iAnimation, aiInfo);
strValue = aiInfo.ai_AnimName;
}
break;
}
case CEntityProperty::EPT_ILLUMINATIONTYPE:
{
INDEX iIllumination = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, INDEX);
strValue = pDoc->m_woWorld.wo_aitIlluminationTypes[iIllumination].it_strName;
break;
}
case CEntityProperty::EPT_FLOATAABBOX3D:
{
FLOATaabbox3D bbox = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, FLOATaabbox3D);
FLOAT3D vMin = bbox.Min();
FLOAT3D vMax = bbox.Max();
strValue.PrintF( "Min(%g,%g,%g), Max(%g,%g,%g)",
vMin(1), vMin(2), vMin(3), vMax(1), vMax(2), vMax(3));
break;
}
case CEntityProperty::EPT_FLOAT3D:
{
FLOAT3D vVector = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, FLOAT3D);
strValue.PrintF( "%g,%g,%g", vVector(1), vVector(2), vVector(3));
break;
}
case CEntityProperty::EPT_ANGLE3D:
{
ANGLE3D aAngle = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, ANGLE3D);
strValue.PrintF( "%g,%g,%g", DegAngle(aAngle(1)), DegAngle(aAngle(2)), DegAngle(aAngle(3)));
break;
}
}
INDEX ctLetters = sprintf(pchrCursor, "%-24.24s %.64s \n", epProperty.ep_strName, strValue);
if( ctLetters > iLongestLineLetters) iLongestLineLetters = ctLetters;
pchrCursor += ctLetters;
}
}
if( iLongestLineLetters>2)
{
iLongestLineLetters-=2;
memset(pchrCursor, '_', iLongestLineLetters);
pchrCursor+=iLongestLineLetters;
*pchrCursor = '\n';
pchrCursor++;
}
if( penEntity->GetParent() != NULL)
{
pchrCursor += sprintf(pchrCursor, "Parent: %s\n", penEntity->GetParent()->GetName());
}
else
{
pchrCursor += sprintf(pchrCursor, "No parent\n");
}
CTString strSpawn = "";
ULONG ulSpawn = penEntity->GetSpawnFlags();
ULONG ulAllways = SPF_EASY|SPF_NORMAL|SPF_HARD|SPF_EXTREME|SPF_SINGLEPLAYER|SPF_COOPERATIVE|SPF_DEATHMATCH;
if( (ulSpawn & ulAllways) == ulAllways)
{
pchrCursor += sprintf(pchrCursor, "%s", "Entity exists allways");
}
else
{
if( ulSpawn & SPF_EASY) strSpawn+="Easy,";
if( ulSpawn & SPF_NORMAL) strSpawn+="Normal,";
if( ulSpawn & SPF_HARD) strSpawn+="Hard,";
if( ulSpawn & SPF_EXTREME) strSpawn+="Extreme,";
if( ulSpawn & SPF_SINGLEPLAYER) strSpawn+="Single,";
if( ulSpawn & SPF_COOPERATIVE) strSpawn+="Cooperative,";
if( ulSpawn & SPF_DEATHMATCH) strSpawn+="Deathmatch,";
if( strSpawn != "")
{
pchrCursor += sprintf(pchrCursor, "%s", strSpawn);
*(pchrCursor-1) = 0;
}
else
{
pchrCursor += sprintf(pchrCursor, "%s", "Does not exist acording to spawn flags");
}
}
}
if( pDoc->GetEditingMode() == VERTEX_MODE)
{
pchrCursor += sprintf(pchrCursor, "%d %s", pDoc->m_selVertexSelection.Count(), "vertices");
}
}
void CWorldEditorView::OnMenuCopyMapping()
{
CWorldEditorDoc *pDoc = GetDocument();
ASSERT( m_pbpoRightClickedPolygon != NULL);
CopyMapping(m_pbpoRightClickedPolygon);
}
void CWorldEditorView::OnKeyPaste()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
theApp.m_iTerrainBrushMode=TBM_PAINT;
theApp.m_ctTerrainPageCanvas.MarkChanged();
pDoc->SetStatusLineModeInfoMessage();
}
else
{
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
// paste mapping
PasteMapping( crRayHit.cr_pbpoBrushPolygon, FALSE);
}
}
}
void CWorldEditorView::OnKeyPasteAsProjected()
{
CWorldEditorDoc* pDoc = GetDocument();
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
// paste mapping
PasteMapping( crRayHit.cr_pbpoBrushPolygon, TRUE);
}
}
void CWorldEditorView::OnMenuPasteMapping()
{
PasteMapping( m_pbpoRightClickedPolygon, FALSE);
}
void CWorldEditorView::OnMenuPasteAsProjectedMapping()
{
PasteMapping( m_pbpoRightClickedPolygon, TRUE);
}
void CWorldEditorView::CopyMapping(CBrushPolygon *pbpo)
{
CWorldEditorDoc *pDoc = GetDocument();
ASSERT(pbpo!=NULL);
CBrushPlane *pbpl = pbpo->bpo_pbplPlane;
CEntity *pen = pbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
ASSERT(pen!=NULL);
// get the mapping in absolute space
theApp.m_mdMapping = pbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
theApp.m_mdMapping.Transform(pbpl->bpl_plRelative, pen->GetPlacement(), _plOrigin);
theApp.m_plMapping = pbpl->bpl_plAbsolute;
theApp.m_mdMapping1 = pbpo->bpo_abptTextures[0].bpt_mdMapping;
theApp.m_mdMapping1.Transform(pbpl->bpl_plRelative, pen->GetPlacement(), _plOrigin);
theApp.m_plMapping1 = pbpl->bpl_plAbsolute;
theApp.m_mdMapping2 = pbpo->bpo_abptTextures[1].bpt_mdMapping;
theApp.m_mdMapping2.Transform(pbpl->bpl_plRelative, pen->GetPlacement(), _plOrigin);
theApp.m_plMapping2 = pbpl->bpl_plAbsolute;
theApp.m_mdMapping3 = pbpo->bpo_abptTextures[2].bpt_mdMapping;
theApp.m_mdMapping3.Transform(pbpl->bpl_plRelative, pen->GetPlacement(), _plOrigin);
theApp.m_plMapping3 = pbpl->bpl_plAbsolute;
}
void CWorldEditorView::PasteMappingOnOnePolygon(CBrushPolygon *pbpo, BOOL bAsProjected)
{
CWorldEditorDoc *pDoc = GetDocument();
PasteOneLayerMapping(pDoc->m_iTexture, theApp.m_mdMapping, theApp.m_plMapping, pbpo, bAsProjected);
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::PasteOneLayerMapping(INDEX iLayer, CMappingDefinition &md,
FLOATplane3D &pl, CBrushPolygon *pbpo, BOOL bAsProjected)
{
CWorldEditorDoc *pDoc = GetDocument();
// get the mapping in relative space of the brush polygon's entity
CEntity *pen = pbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
CSimpleProjection3D pr;
pr.ObjectPlacementL() = _plOrigin;
pr.ViewerPlacementL() = pen->GetPlacement();
pr.Prepare();
FLOATplane3D plRelative;
pr.Project(pl, plRelative);
CMappingDefinition mdRelative = md;
mdRelative.Transform(pl, _plOrigin, pen->GetPlacement());
// paste the mapping
if( bAsProjected)
{
pbpo->bpo_abptTextures[iLayer].bpt_mdMapping.ProjectMapping(
plRelative, mdRelative, pbpo->bpo_pbplPlane->bpl_plRelative);
}
else
{
pbpo->bpo_abptTextures[iLayer].bpt_mdMapping = mdRelative;
}
}
void CWorldEditorView::PasteMapping(CBrushPolygon *pbpo, BOOL bAsProjected)
{
CWorldEditorDoc *pDoc = GetDocument();
// paste mapping over selection if clicked polygon is selected
if( (pbpo == NULL) || (pbpo->IsSelected( BPOF_SELECTED)) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
PasteMappingOnOnePolygon(itbpo, bAsProjected);
}
}
else
{
PasteMappingOnOnePolygon(pbpo, bAsProjected);
}
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnSelectAllEntitiesInSectors()
{
CWorldEditorDoc *pDoc = GetDocument();
CBrushSector *pbscHitted = NULL;
if( (m_penEntityHitOnContext != NULL) &&
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) &&
(m_pbpoRightClickedPolygon != NULL) )
{
pbscHitted = m_pbpoRightClickedPolygon->bpo_pbscSector;
}
// if right clicked on nothing or selected sector
if( (pbscHitted == NULL) || pbscHitted->IsSelected( BSCF_SELECTED) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
{
{FOREACHDSTOFSRC(itbsc->bsc_rsEntities, CEntity, en_rdSectors, pen)
if( !pen->IsSelected( ENF_SELECTED) )
{
pDoc->m_selEntitySelection.Select( *pen);
}
ENDFOR}
}
}
else
{
{FOREACHDSTOFSRC(pbscHitted->bsc_rsEntities, CEntity, en_rdSectors, pen)
if( !pen->IsSelected( ENF_SELECTED) )
{
pDoc->m_selEntitySelection.Select( *pen);
}
ENDFOR}
}
pDoc->SetEditingMode( ENTITY_MODE);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnSelectAllSectors()
{
CWorldEditorDoc *pDoc = GetDocument();
if( m_penEntityHitOnContext == NULL)
{
// in all entities in world
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
CEntity::RenderType rt = iten->GetRenderType();
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
{
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->GetBrush()->br_lhBrushMips, itbm)
{
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
{
// if sector is not hidden and not selected
if( !(itbsc->bsc_ulFlags & BSCF_HIDDEN) && !itbsc->IsSelected( BSCF_SELECTED) )
{
// select it
pDoc->m_selSectorSelection.Select( *itbsc);
}
}
}
}
}
}
// perform select sectors on whole entity selection
else if( m_penEntityHitOnContext->IsSelected( ENF_SELECTED))
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
CEntity::RenderType rt = iten->GetRenderType();
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
{
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->GetBrush()->br_lhBrushMips, itbm)
{
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
{
// if sector is not hidden and not selected
if( !(itbsc->bsc_ulFlags & BSCF_HIDDEN) && !itbsc->IsSelected( BSCF_SELECTED) )
{
// select it
pDoc->m_selSectorSelection.Select( *itbsc);
}
}
}
}
}
}
else if (m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH)
{
// select all sectors in all mip levels
FOREACHINLIST(CBrushMip, bm_lnInBrush, m_penEntityHitOnContext->GetBrush()->br_lhBrushMips, itbm)
{
// select all sectors in current mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
{
if( !(itbsc->bsc_ulFlags & BSCF_HIDDEN) && !itbsc->IsSelected( BSCF_SELECTED) )
{
pDoc->m_selSectorSelection.Select( *itbsc);
}
}
}
}
pDoc->SetEditingMode( SECTOR_MODE);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::CenterSelected(void)
{
CWorldEditorDoc *pDoc = GetDocument();
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CPropertyID *ppidProperty = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
// bounding box of visible sectors
FLOATaabbox3D boxBoundingBox;
if( pDoc->GetEditingMode() == ENTITY_MODE && (pDoc->m_selEntitySelection.Count() != 0) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
FLOAT3D vPos = iten->GetPlacement().pl_PositionVector;
FLOATaabbox3D boxEntity;
if( (ppidProperty != NULL) && (ppidProperty->pid_eptType == CEntityProperty::EPT_RANGE))
{
// obtain property ptr
CEntityProperty *penpProperty = iten->PropertyForName( ppidProperty->pid_strName);
// get editing range
FLOAT fRange = ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, FLOAT);
boxEntity |= FLOATaabbox3D( FLOAT3D(0.0f, 0.0f ,0.0f), fRange);
}
else
{
iten->GetSize( boxEntity);
}
boxEntity+=vPos;
boxBoundingBox |= boxEntity;
}
}
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
CTerrain *ptrTerrain=GetTerrain();
if(ptrTerrain!=NULL)
{
ptrTerrain->GetAllTerrainBBox(boxBoundingBox);
}
}
else if( pDoc->GetEditingMode() == POLYGON_MODE && (pDoc->m_selPolygonSelection.Count() != 0) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
boxBoundingBox |= itbpo->bpo_boxBoundingBox;
}
}
else if( pDoc->GetEditingMode() == SECTOR_MODE && (pDoc->m_selSectorSelection.Count() != 0) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
{
boxBoundingBox |= itbsc->bsc_boxBoundingBox;
}
}
else if( (pDoc->GetEditingMode() == VERTEX_MODE) && (pDoc->m_selVertexSelection.Count() != 0) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selVertexSelection, CBrushVertex, itbvtx)
{
FLOATaabbox3D boxVtxBox = FLOATaabbox3D( itbvtx->bvx_vAbsolute);
boxVtxBox.Expand( 20);
boxBoundingBox |= boxVtxBox;
}
}
else
{
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
CEntity::RenderType rt = iten->GetRenderType();
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
{
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->GetBrush()->br_lhBrushMips, itbm)
{
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
{
// if sector is not hidden
if( !(itbsc->bsc_ulFlags & BSCF_HIDDEN))
{
boxBoundingBox |= itbsc->bsc_boxBoundingBox;
}
}
}
}
else
{
FLOAT3D vPos = iten->GetPlacement().pl_PositionVector;
FLOATaabbox3D boxEntity;
iten->GetSize( boxEntity);
boxEntity+=vPos;
boxBoundingBox |= boxEntity;
}
}
}
AllignBox( boxBoundingBox);
}
void CWorldEditorView::AllignBox( FLOATaabbox3D bbox)
{
CWorldEditorDoc *pDoc = GetDocument();
CChildFrame *pCF = GetChildFrame();
FLOAT3D vSize = bbox.Size();
if( vSize.Length() <= 1.0f)
vSize = FLOAT3D( 2.0f, 2.0f, 2.0f);
// width is alligned inside horizontal borders of draw port, height and lenght
// are alligned to height of draw port
FLOAT fDX = (FLOAT)m_pdpDrawPort->GetWidth()*9/10;
FLOAT fDY = (FLOAT)m_pdpDrawPort->GetHeight()*9/10;
FLOAT fWantedZoom = Min( Min( fDX/vSize(1), fDY/vSize(2)), fDY/vSize(3));
if( (fWantedZoom>1E-4) && (fWantedZoom<1E4) )
{
// create a slave viewer
CSlaveViewer svViewer(pCF->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid,
m_pdpDrawPort);
pCF->m_mvViewer.mv_fTargetDistance = svViewer.GetDistanceForZoom(fWantedZoom);
pCF->m_mvViewer.SetTargetPlacement( bbox.Center());
}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::AllignPolygon( CBrushPolygon *pbpo)
{
CWorldEditorDoc *pDoc = GetDocument();
CChildFrame *pCF = GetChildFrame();
FLOATaabbox3D bbox = pbpo->bpo_boxBoundingBox;
FLOAT3D vSize = bbox.Size();
if( vSize.Length() <= 1.0f)
vSize = FLOAT3D( 2.0f, 2.0f, 2.0f);
// width is alligned inside horizontal borders of draw port, height and lenght
// are alligned to height of draw port
FLOAT fDX = (FLOAT)m_pdpDrawPort->GetWidth()*9/10;
FLOAT fDY = (FLOAT)m_pdpDrawPort->GetHeight()*9/10;
FLOAT fWantedZoom = Min( Min( fDX/vSize(1), fDY/vSize(2)), fDY/vSize(3));
if( (fWantedZoom>1E-4) && (fWantedZoom<1E4) )
{
// create a slave viewer
CSlaveViewer svViewer(pCF->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid, m_pdpDrawPort);
pCF->m_mvViewer.mv_fTargetDistance = svViewer.GetDistanceForZoom(fWantedZoom);
FLOAT3D vDirection = pbpo->bpo_pbplPlane->bpl_plAbsolute;
DirectionVectorToAngles( -vDirection, pCF->m_mvViewer.mv_plViewer.pl_OrientationAngle);
pCF->m_mvViewer.SetTargetPlacement( bbox.Center());
}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnCloneToMorePreciseMip()
{
OnAddMorePreciseMip(TRUE);
}
void CWorldEditorView::OnCreateEmptyMorePreciseMip()
{
OnAddMorePreciseMip(FALSE);
}
void CWorldEditorView::OnCloneToRougherMipLevel()
{
OnAddRougherMipLevel( TRUE);
}
void CWorldEditorView::OnCreateEmptyRougherMip()
{
OnAddRougherMipLevel( FALSE);
}
void CWorldEditorView::OnAddMorePreciseMip(BOOL bClone)
{
// remember current time as time when last mip brushing option has been used
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
CWorldEditorDoc* pDoc = GetDocument();
pDoc->RememberUndo();
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
if (pbmCurrentMip==NULL) {
return;
}
CBrushMip *pbmAdded = pbmCurrentMip->bm_pbrBrush->NewBrushMipBefore(pbmCurrentMip, bClone);
GetChildFrame()->m_fManualMipBrushingFactor = pbmAdded->GetMipDistance()-0.01f;
// document has changed
pDoc->SetModifiedFlag();
// update all views
pDoc->UpdateAllViews( NULL);
// set text describing data that is edited
SetEditingDataPaneInfo( TRUE);
}
void CWorldEditorView::OnAddRougherMipLevel(BOOL bClone)
{
// remember current time as time when last mip brushing option has been used
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
CWorldEditorDoc* pDoc = GetDocument();
pDoc->RememberUndo();
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
if (pbmCurrentMip==NULL) {
return;
}
CBrushMip *pbmAdded = pbmCurrentMip->bm_pbrBrush->NewBrushMipAfter(pbmCurrentMip, bClone);
GetChildFrame()->m_fManualMipBrushingFactor = pbmAdded->GetMipDistance()-0.01f;
// document has changed
pDoc->SetModifiedFlag();
// update all views
pDoc->UpdateAllViews( NULL);
// set text describing data that is edited
SetEditingDataPaneInfo( TRUE);
}
// get current brush mip of current csg target brush
CBrushMip *CWorldEditorView::GetCurrentBrushMip(void)
{
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CEntity *penBrush = pMainFrame->m_CSGDesitnationCombo.GetSelectedBrushEntity();
if (penBrush==NULL) {
return NULL;
}
// get entity's brush
CBrush3D *pbrBrush = penBrush->GetBrush();
if( pbrBrush == NULL) {
return NULL;
}
// get currently active mip factor
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
return pbrBrush->GetBrushMipByDistance(fCurrentMipFactor);
}
void CWorldEditorView::OnDeleteMip()
{
// remember current time as time when last mip brushing option has been used
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
if (pbmCurrentMip==NULL) {
return;
}
// delete currently visible mip brush
pbmCurrentMip->bm_pbrBrush->DeleteBrushMip(pbmCurrentMip);
CWorldEditorDoc* pDoc = GetDocument();
// document has changed
pDoc->SetModifiedFlag();
// update all views
pDoc->UpdateAllViews( NULL);
// set text describing data that is edited
SetEditingDataPaneInfo( TRUE);
}
void CWorldEditorView::OnPreviousMipBrush()
{
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CEntity *penBrush = pMainFrame->m_CSGDesitnationCombo.GetSelectedBrushEntity();
if (penBrush == NULL) return;
CBrush3D &brBrush = *penBrush->en_pbrBrush;
// remember current time as time when last mip brushing option has been used
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
CBrushMip *pbmPrevMip = NULL;
if (pbmCurrentMip==NULL)
{
pbmPrevMip = brBrush.GetLastMip();
}
else
{
pbmPrevMip = pbmCurrentMip->GetPrev();
}
if (pbmPrevMip==NULL) return;
// set manual mip factor to show previous mip brush
GetChildFrame()->m_fManualMipBrushingFactor = pbmPrevMip->GetMipDistance()-0.01f;
// update all views
CWorldEditorDoc* pDoc = GetDocument();
pDoc->UpdateAllViews( NULL);
// set text describing data that is edited
SetEditingDataPaneInfo( TRUE);
}
void CWorldEditorView::OnNextMipBrush()
{
// remember current time as time when last mip brushing option has been used
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
if (pbmCurrentMip==NULL) {
return;
}
CBrushMip *pbmNextMip = pbmCurrentMip->GetNext();
if (pbmNextMip==NULL) {
return;
}
// set manual mip factor to show next mip brush
GetChildFrame()->m_fManualMipBrushingFactor = pbmNextMip->GetMipDistance()-0.01f;
// update all views
CWorldEditorDoc* pDoc = GetDocument();
pDoc->UpdateAllViews( NULL);
// set text describing data that is edited
SetEditingDataPaneInfo( TRUE);
}
void CWorldEditorView::OnUpdateCloneToMorePreciseMip(CCmdUI* pCmdUI)
{
pCmdUI->Enable( GetCurrentBrushMip()!=NULL && !GetChildFrame()->m_bAutoMipBrushingOn);
}
void CWorldEditorView::OnUpdateCloneToRougherMipLevel(CCmdUI* pCmdUI)
{
pCmdUI->Enable( GetCurrentBrushMip()!=NULL && !GetChildFrame()->m_bAutoMipBrushingOn);
}
void CWorldEditorView::OnUpdateCreateEmptyMorePreciseMip(CCmdUI* pCmdUI)
{
pCmdUI->Enable( GetCurrentBrushMip()!=NULL && !GetChildFrame()->m_bAutoMipBrushingOn);
}
void CWorldEditorView::OnUpdateCreateEmptyRougherMip(CCmdUI* pCmdUI)
{
pCmdUI->Enable( GetCurrentBrushMip()!=NULL && !GetChildFrame()->m_bAutoMipBrushingOn);
}
void CWorldEditorView::OnUpdateDeleteMip(CCmdUI* pCmdUI)
{
CBrushMip *pbm = GetCurrentBrushMip();
pCmdUI->Enable(
pbm!=NULL &&
pbm->bm_pbrBrush->br_lhBrushMips.Count()>1 &&
!GetChildFrame()->m_bAutoMipBrushingOn);
}
void CWorldEditorView::OnUpdatePreviousMipBrush(CCmdUI* pCmdUI)
{
CBrushMip *pbm = GetCurrentBrushMip();
pCmdUI->Enable(
( (pbm==NULL) ||
(pbm->GetPrev()!=NULL) ) &&
!GetChildFrame()->m_bAutoMipBrushingOn);
}
void CWorldEditorView::OnUpdateNextMipBrush(CCmdUI* pCmdUI)
{
CBrushMip *pbm = GetCurrentBrushMip();
pCmdUI->Enable(
pbm!=NULL &&
pbm->GetNext()!=NULL &&
!GetChildFrame()->m_bAutoMipBrushingOn);
}
// paste polygon properties but don't paste mapping
void CWorldEditorView::OnEditPasteAlternative()
{
CWorldEditorDoc* pDoc = GetDocument();
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
if( theApp.m_ctLastCopyType == CT_POLYGON_PROPERTIES)
{
// if mouse is over polygon
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
if( crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED))
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
// apply all parameters from remembered
itbpo->CopyProperties( *theApp.m_pbpoClipboardPolygon);
}
}
else
{
// apply all parameters from remembered
crRayHit.cr_pbpoBrushPolygon->CopyProperties( *theApp.m_pbpoClipboardPolygon);
}
}
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag();
pDoc->UpdateAllViews( NULL);
}
if( theApp.m_ctLastCopyType == CT_POLYGON_PROPERTIES_ALTERNATIVE)
{
// if mouse is over polygon
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
if( crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED))
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
// apply all parameters from remembered
itbpo->CopyProperties( *theApp.m_pbpoClipboardPolygon);
PasteOneLayerMapping(0, theApp.m_mdMapping1, theApp.m_plMapping1, &*itbpo, TRUE);
PasteOneLayerMapping(1, theApp.m_mdMapping2, theApp.m_plMapping2, &*itbpo, TRUE);
PasteOneLayerMapping(2, theApp.m_mdMapping3, theApp.m_plMapping3, &*itbpo, TRUE);
}
}
else
{
// apply all parameters from remembered
crRayHit.cr_pbpoBrushPolygon->CopyProperties( *theApp.m_pbpoClipboardPolygon);
PasteOneLayerMapping(0, theApp.m_mdMapping1, theApp.m_plMapping1, crRayHit.cr_pbpoBrushPolygon, TRUE);
PasteOneLayerMapping(1, theApp.m_mdMapping2, theApp.m_plMapping2, crRayHit.cr_pbpoBrushPolygon, TRUE);
PasteOneLayerMapping(2, theApp.m_mdMapping3, theApp.m_plMapping3, crRayHit.cr_pbpoBrushPolygon, TRUE);
}
}
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag();
pDoc->UpdateAllViews( NULL);
}
else if (theApp.m_ctLastCopyType == CT_ENTITY)
{
CWorldEditorDoc* pDoc = GetDocument();
CPlacement3D plPaste = GetMouseInWorldPlacement();
// load world from clipboard file and start template CSG
pDoc->StartTemplateCSG( plPaste, (CTString)"Temp\\ClipboardEntityWorld.wld");
// update all views
pDoc->UpdateAllViews( NULL);
}
}
void CWorldEditorView::OnUpdateEditPasteAlternative(CCmdUI* pCmdUI)
{
}
void CWorldEditorView::ToggleHittedPolygon( CCastRay &crRayHit)
{
CWorldEditorDoc* pDoc = GetDocument();
if( (crRayHit.cr_penHit == NULL) ||
(crRayHit.cr_pbpoBrushPolygon == NULL) )
{
return;
}
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
// remember if first clicked polygon is to be deselected
m_bWeDeselectedFirstPolygon = crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED) != 0;
INDEX ctPolygonsSelectedBefore = pDoc->m_selPolygonSelection.Count();
// if shift is not pressed
if( !bShift)
{
if( ctPolygonsSelectedBefore>1)
{
m_bWeDeselectedFirstPolygon = FALSE;
}
// deselect all selected polygons
pDoc->m_selPolygonSelection.Clear();
}
// if we have to deselect first polygon but we didn't deselect it with clear
if( (m_bWeDeselectedFirstPolygon) &&
(crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED)) )
{
// deselect clicked polygon
pDoc->m_selPolygonSelection.Deselect( *crRayHit.cr_pbpoBrushPolygon);
}
// if we must select first polygon
if( !m_bWeDeselectedFirstPolygon)
{
// select it
pDoc->m_selPolygonSelection.Select( *crRayHit.cr_pbpoBrushPolygon);
}
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
// update all views
pDoc->UpdateAllViews( this);
}
void CWorldEditorView::ToggleHittedSector( CCastRay &crRayHit)
{
CWorldEditorDoc* pDoc = GetDocument();
// if any polygon hit toggle or add its sector
if( (crRayHit.cr_penHit == NULL) ||
(crRayHit.cr_pbscBrushSector == NULL) )
{
return;
}
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
// remember if first clicked sector is to be deselected
m_bWeDeselectedFirstSector = crRayHit.cr_pbscBrushSector->IsSelected( BSCF_SELECTED) != 0;
INDEX ctSectorsSelectedBefore = pDoc->m_selSectorSelection.Count();
// if shift is not pressed
if( !bShift)
{
if( ctSectorsSelectedBefore>1)
{
m_bWeDeselectedFirstSector = FALSE;
}
// deselect all selected sectors
pDoc->m_selSectorSelection.Clear();
}
// if we have to deselect first sector but we didn't deselect it with clear
if( (m_bWeDeselectedFirstSector) &&
(crRayHit.cr_pbscBrushSector->IsSelected( BSCF_SELECTED)) )
{
// deselect clicked sector
pDoc->m_selSectorSelection.Deselect( *crRayHit.cr_pbscBrushSector);
}
// if we must select first sector
if( !m_bWeDeselectedFirstSector)
{
// select it
pDoc->m_selSectorSelection.Select( *crRayHit.cr_pbscBrushSector);
}
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
// update all views
pDoc->UpdateAllViews( this);
}
void CWorldEditorView::OnSelectAllEntitiesInWorld()
{
CWorldEditorDoc* pDoc = GetDocument();
// deselect all entities
pDoc->m_selEntitySelection.Clear();
// add each entity in world
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
CBrushSector *pbscSector = iten->GetFirstSector();
BOOL bSectorVisible = (pbscSector == NULL) ||
!(pbscSector->bsc_ulFlags & BSCF_HIDDEN);
// if it isn't classified in hidden sector and is not hidden itself
if( bSectorVisible && !(iten->en_ulFlags&ENF_HIDDEN))
{
// add it to selection
pDoc->m_selEntitySelection.Select( *iten);
}
}
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
// update all views
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnSelectSectorsWithSameName()
{
CWorldEditorDoc* pDoc = GetDocument();
if( m_pbpoRightClickedPolygon == NULL) return;
// select all sectors in world with same name
CBrushSector *pbscSrc = m_pbpoRightClickedPolygon->bpo_pbscSector;
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
CEntity::RenderType rt = iten->GetRenderType();
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
{
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->GetBrush()->br_lhBrushMips, itbm)
{
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
{
// if sector is not hidden and has same name, select it
if( !(itbsc->bsc_ulFlags & BSCF_HIDDEN) &&
(itbsc->bsc_strName==pbscSrc->bsc_strName) )
{
if( !itbsc->IsSelected( BSCF_SELECTED))
{
pDoc->m_selSectorSelection.Select( *itbsc);
}
}
}
}
}
}
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
// update all views
pDoc->UpdateAllViews( this);
}
void CWorldEditorView::OnSelectSectorsArroundEntity()
{
CWorldEditorDoc *pDoc = GetDocument();
// if none selected
if(pDoc->m_selEntitySelection.Count() == 0)
{
// perform on ray-hitted entity
BOOL bHitModels = pDoc->GetEditingMode() != POLYGON_MODE;
BOOL bHitFields = pDoc->GetEditingMode() == ENTITY_MODE;
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse, FALSE, bHitModels, bHitFields);
// if none of entities is hitted
if(crRayHit.cr_penHit == NULL) return;
{FOREACHSRCOFDST(crRayHit.cr_penHit->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
// if sector is not hidden and not selected
if( !(pbsc->bsc_ulFlags & BSCF_HIDDEN) && !pbsc->IsSelected( BSCF_SELECTED) )
{
// select it
pDoc->m_selSectorSelection.Select( *pbsc);
}
ENDFOR}
}
else
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
{FOREACHSRCOFDST(iten->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
// if sector is not hidden and not selected
if( !(pbsc->bsc_ulFlags & BSCF_HIDDEN) && !pbsc->IsSelected( BSCF_SELECTED) )
{
// select it
pDoc->m_selSectorSelection.Select( *pbsc);
}
ENDFOR}
}
}
pDoc->SetEditingMode( SECTOR_MODE);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnSelectSectorsArroundEntityOnContext()
{
CWorldEditorDoc *pDoc = GetDocument();
if( m_penEntityHitOnContext == NULL)
{
return;
}
// perform select sectors on whole entity selection
if( m_penEntityHitOnContext->IsSelected( ENF_SELECTED))
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
{FOREACHSRCOFDST(iten->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
// if sector is not hidden and not selected
if( !(pbsc->bsc_ulFlags & BSCF_HIDDEN) && !pbsc->IsSelected( BSCF_SELECTED) )
{
// select it
pDoc->m_selSectorSelection.Select( *pbsc);
}
ENDFOR}
}
}
else
{
{FOREACHSRCOFDST(m_penEntityHitOnContext->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
// if sector is not hidden and not selected
if( !(pbsc->bsc_ulFlags & BSCF_HIDDEN) && !pbsc->IsSelected( BSCF_SELECTED) )
{
// select it
pDoc->m_selSectorSelection.Select( *pbsc);
}
ENDFOR}
}
pDoc->SetEditingMode( SECTOR_MODE);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::CopySectorAmbient( CBrushSector *pbscSector)
{
theApp.m_colSectorAmbientClipboard = pbscSector->bsc_colAmbient;
}
void CWorldEditorView::PasteSectorAmbient( CBrushSector *pbscSector)
{
CWorldEditorDoc* pDoc = GetDocument();
if( (pbscSector == NULL) || (pbscSector->IsSelected( BSCF_SELECTED)) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
{
itbsc->bsc_colAmbient = theApp.m_colSectorAmbientClipboard;
itbsc->UncacheLightMaps();
}
}
else
{
pbscSector->bsc_colAmbient = theApp.m_colSectorAmbientClipboard;
pbscSector->UncacheLightMaps();
}
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::PasteTexture( CBrushPolygon *pbpoPolygon)
{
if( theApp.m_ptdActiveTexture==NULL) return;
CWorldEditorDoc* pDoc = GetDocument();
CTFileName fnTextureName = theApp.m_ptdActiveTexture->GetName();
try
{
if( (pbpoPolygon == NULL) || (pbpoPolygon->IsSelected( BPOF_SELECTED)) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.SetData_t( fnTextureName);
}
}
else
{
pbpoPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.SetData_t( fnTextureName);
}
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag( TRUE);
}
catch( char *strError)
{
AfxMessageBox( CString(strError));
return;
}
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::StorePolygonSelection(CBrushPolygonSelection &selPolygons,
CDynamicContainer<CBrushPolygon> &dcPolygons)
{
dcPolygons.Clear();
FOREACHINDYNAMICCONTAINER( selPolygons, CBrushPolygon, itbpo)
{
dcPolygons.Add( itbpo);
}
}
void CWorldEditorView::RestorePolygonSelection(CBrushPolygonSelection &selPolygons,
CDynamicContainer<CBrushPolygon> &dcPolygons)
{
selPolygons.Clear();
FOREACHINDYNAMICCONTAINER( dcPolygons, CBrushPolygon, itbpo)
{
selPolygons.Select( *itbpo);
}
}
void CWorldEditorView::DiscardShadows( CEntity *penEntity)
{
CWorldEditorDoc* pDoc = GetDocument();
CDynamicContainer<CBrushPolygon> dcPolygons;
StorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
pDoc->m_selPolygonSelection.Clear();
FLOATaabbox3D boxForDiscard;
if( (penEntity == NULL) || (penEntity->IsSelected( ENF_SELECTED)) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
// if it is brush
if (iten->en_RenderType == CEntity::RT_BRUSH)
{
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm)
{
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
{
// for all polygons in sector
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
{
boxForDiscard |= itbpo->bpo_boxBoundingBox;
itbpo->bpo_smShadowMap.DiscardAllLayers();
itbpo->InitializeShadowMap();
pDoc->m_selPolygonSelection.Select( *itbpo);
}
itbsc->UncacheLightMaps();
}
}
}
}
}
else
{
// if it is brush
if (penEntity->en_RenderType == CEntity::RT_BRUSH)
{
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, penEntity->en_pbrBrush->br_lhBrushMips, itbm)
{
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
{
// for all polygons in sector
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
{
boxForDiscard |= itbpo->bpo_boxBoundingBox;
itbpo->bpo_smShadowMap.DiscardAllLayers();
itbpo->InitializeShadowMap();
pDoc->m_selPolygonSelection.Select( *itbpo);
}
itbsc->UncacheLightMaps();
}
}
}
}
pDoc->m_woWorld.FindShadowLayers( boxForDiscard, TRUE);
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
RestorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
}
void CWorldEditorView::DiscardShadows( CBrushSector *pbscSector)
{
CWorldEditorDoc* pDoc = GetDocument();
CDynamicContainer<CBrushPolygon> dcPolygons;
StorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
pDoc->m_selPolygonSelection.Clear();
FLOATaabbox3D boxForDiscard;
if( (pbscSector == NULL) || (pbscSector->IsSelected( BSCF_SELECTED)) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
{
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
{
boxForDiscard |= itbpo->bpo_boxBoundingBox;
itbpo->bpo_smShadowMap.DiscardAllLayers();
itbpo->InitializeShadowMap();
pDoc->m_selPolygonSelection.Select( *itbpo);
}
itbsc->UncacheLightMaps();
}
}
else
{
FOREACHINSTATICARRAY(pbscSector->bsc_abpoPolygons, CBrushPolygon, itbpo)
{
boxForDiscard |= itbpo->bpo_boxBoundingBox;
itbpo->bpo_smShadowMap.DiscardAllLayers();
itbpo->InitializeShadowMap();
pDoc->m_selPolygonSelection.Select( *itbpo);
}
pbscSector->UncacheLightMaps();
}
pDoc->m_woWorld.FindShadowLayers( boxForDiscard, TRUE);
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
RestorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
}
void CWorldEditorView::DiscardShadows( CBrushPolygon *pbpoPolygon)
{
CWorldEditorDoc* pDoc = GetDocument();
CDynamicContainer<CBrushPolygon> dcPolygons;
StorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
FLOATaabbox3D boxForDiscard;
if( (pbpoPolygon == NULL) || (pbpoPolygon->IsSelected( BPOF_SELECTED)) )
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
// calculate bounding box for all polygons
boxForDiscard |= itbpo->bpo_boxBoundingBox;
itbpo->bpo_smShadowMap.DiscardAllLayers();
itbpo->InitializeShadowMap();
}
}
else
{
pbpoPolygon->bpo_smShadowMap.DiscardAllLayers();
pbpoPolygon->InitializeShadowMap();
boxForDiscard |= pbpoPolygon->bpo_boxBoundingBox;
pDoc->m_selPolygonSelection.Clear();
pDoc->m_selPolygonSelection.Select( *pbpoPolygon);
}
pDoc->m_woWorld.FindShadowLayers( boxForDiscard, TRUE);
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
RestorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
}
void CWorldEditorView::OnInsertVertex()
{
CWorldEditorDoc* pDoc = GetDocument();
MarkClosestVtxAndEdgeOnPrimitiveBase( m_ptMouse);
if( m_iDragEdge != -1) pDoc->InsertPrimitiveVertex( m_iDragEdge, m_vMouseDownSecondLayer);
}
void CWorldEditorView::OnDeleteVertex()
{
CWorldEditorDoc* pDoc = GetDocument();
MarkClosestVtxAndEdgeOnPrimitiveBase( m_ptMouse);
if( m_iDragVertice != -1) pDoc->DeletePrimitiveVertex( m_iDragVertice);
}
void CWorldEditorView::OnKeyBackslash()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
CPoint ptMouse;
GetCursorPos( &ptMouse);
if( theApp.m_iTerrainEditMode==TEM_LAYER)
{
CTerrainLayer *ptlLayer=GetLayer();
if(ptlLayer==NULL) return;
if( ptlLayer->tl_ltType==LT_TILE)
{
InvokeTerrainTilePalette(ptMouse.x, ptMouse.y);
return;
}
}
InvokeTerrainBrushPalette( ptMouse.x-BRUSH_PALETTE_WIDTH/2, ptMouse.y+BRUSH_PALETTE_HEIGHT/2);
}
else
{
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
if( pDoc->m_selEntitySelection.Count() == 1)
{
pDoc->m_selEntitySelection.Lock();
CEntity *penOnlySelected = &pDoc->m_selEntitySelection[0];
pDoc->m_selEntitySelection.Unlock();
CEntity *penToSelect = NULL;
CPropertyID *ppidProperty = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
if( ppidProperty == NULL) return;
if( ppidProperty->pid_eptType == CEntityProperty::EPT_PARENT)
{
penToSelect = penOnlySelected->GetParent();
}
else if( ppidProperty->pid_eptType == CEntityProperty::EPT_ENTITYPTR)
{
// obtain entity class ptr
CDLLEntityClass *pdecDLLClass = penOnlySelected->GetClass()->ec_pdecDLLClass;
// for all classes in hierarchy of this entity
for(;
pdecDLLClass!=NULL;
pdecDLLClass = pdecDLLClass->dec_pdecBase) {
// for all properties
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++) {
CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
if( (ppidProperty->pid_strName == epProperty.ep_strName) &&
(ppidProperty->pid_eptType == epProperty.ep_eptType) )
{
// get target entity
penToSelect = ENTITYPROPERTY( &*penOnlySelected, epProperty.ep_slOffset, CEntityPointer);
}
}
}
}
if( penToSelect == NULL) return;
pDoc->m_selEntitySelection.Clear();
pDoc->m_selEntitySelection.Select( *penToSelect);
pMainFrame->m_PropertyComboBar.UpdateData( FALSE);
pDoc->m_chSelections.MarkChanged();
}
}
}
void CWorldEditorView::OnSavePicturesForEnvironment()
{
CWorldEditorDoc* pDoc = GetDocument();
pDoc->m_selEntitySelection.Lock();
CEntity *pen = &pDoc->m_selEntitySelection[0];
pDoc->m_selEntitySelection.Unlock();
CTFileName fnName = _EngineGUI.FileRequester( "Save pictures as ...",
FILTER_TGA FILTER_ALL FILTER_END,"Environment pictures directory", "Textures\\");
if( fnName == "") return;
CTFileName fnBase = fnName.NoExt();
CDrawPort *pdp;
CImageInfo II;
CTextureData TD;
CAnimData AD;
ULONG flags = NONE;
CChildFrame *pChild = GetChildFrame();
// create canvas to render picture
_pGfx->CreateWorkCanvas( 256, 256, &pdp);
if( pdp != NULL)
{
if( pdp->Lock())
{
CViewPrefs vpOld = m_vpViewPrefs;
// set rendering type for world
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetHiddenLinesOn( FALSE);
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetEditorModelsOn( FALSE);
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetFieldBrushesOn( FALSE);
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetBackgroundTextureOn( TRUE);
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetVerticesFillType( CWorldRenderPrefs::FT_NONE);
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetEdgesFillType( CWorldRenderPrefs::FT_NONE);
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetPolygonsFillType( CWorldRenderPrefs::FT_TEXTURE);
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetLensFlaresType( CWorldRenderPrefs::LFT_REFLECTIONS_AND_GLARE);
// for models
m_vpViewPrefs.m_mrpModelRenderPrefs.SetRenderType( RT_TEXTURE);
m_vpViewPrefs.m_mrpModelRenderPrefs.SetShadingType( RT_SHADING_PHONG);
m_vpViewPrefs.m_mrpModelRenderPrefs.SetShadowQuality( 0);
m_vpViewPrefs.m_mrpModelRenderPrefs.SetWire( FALSE);
m_vpViewPrefs.m_mrpModelRenderPrefs.SetHiddenLines( FALSE);
m_vpViewPrefs.m_mrpModelRenderPrefs.BBoxFrameShow( FALSE);
m_vpViewPrefs.m_mrpModelRenderPrefs.BBoxAllShow( FALSE);
// remember old viewer settings
CPlacement3D plOrgPlacement = pChild->m_mvViewer.mv_plViewer;
FLOAT fOldTargetDistance = pChild->m_mvViewer.mv_fTargetDistance;
enum CSlaveViewer::ProjectionType ptOld = m_ptProjectionType;
m_ptProjectionType = CSlaveViewer::PT_PERSPECTIVE;
// set new viewer settings
pChild->m_mvViewer.mv_plViewer = pen->GetPlacement();
pChild->m_mvViewer.mv_fTargetDistance = 10.0f;
#define GRAB_BCG( ext, angDelta) \
pChild->m_mvViewer.mv_plViewer = pen->GetPlacement();\
pChild->m_mvViewer.mv_plViewer.pl_OrientationAngle+=angDelta;\
RenderView( pdp);\
pdp->GrabScreen(II);\
try { II.SaveTGA_t( fnBase+ext); } \
catch (char *strError)\
{ AfxMessageBox(CString(strError)); }
GRAB_BCG( "N.tga", ANGLE3D( 0, 0, 0));
GRAB_BCG( "W.tga", ANGLE3D( 90.0f, 0, 0));
GRAB_BCG( "S.tga", ANGLE3D( 180.0f, 0, 0));
GRAB_BCG( "E.tga", ANGLE3D( -90.0f, 0, 0));
GRAB_BCG( "C.tga", ANGLE3D( 0, 90.0f, 0));
GRAB_BCG( "F.tga", ANGLE3D( 0, -90.0f, 0));
// restore original settings
m_ptProjectionType = ptOld;
pChild->m_mvViewer.mv_plViewer = plOrgPlacement;
pChild->m_mvViewer.mv_fTargetDistance = fOldTargetDistance;
m_vpViewPrefs = vpOld;
pdp->Unlock();
}
_pGfx->DestroyWorkCanvas( pdp);
pdp = NULL;
}
}
void CWorldEditorView::OnUpdateSavePicturesForEnvironment(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
pCmdUI->Enable( pDoc->m_selEntitySelection.Count() == 1);
}
BOOL CWorldEditorView::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
void CWorldEditorView::OnMenuAlignMappingU()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->m_selPolygonSelection.Count() == 0) return;
FLOAT fLastU = 0;
// for each selected polygon
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo) {
CBrushPolygon &bpo = *itbpo;
CMappingDefinition &md = bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
// find min and max u for the polygon
md.md_fUOffset = 0;
FLOAT fMinU = UpperLimit(0.0f);
FLOAT fMaxU = LowerLimit(0.0f);
for(INDEX ibpe=0; ibpe<bpo.bpo_abpePolygonEdges.Count(); ibpe++) {
CBrushPolygonEdge &bpe = bpo.bpo_abpePolygonEdges[ibpe];
FLOAT3D v0, v1;
MEX2D(vTex0);
bpe.GetVertexCoordinatesRelative(v0, v1);
md.GetTextureCoordinates(
bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative, v0, vTex0);
FLOAT fU = vTex0(1)/1024.0f;
fMinU = Min(fMinU, fU);
fMaxU = Max(fMaxU, fU);
}
// add the offsets to its mapping
md.md_fUOffset=fMinU-fLastU;
fLastU += fMaxU-fMinU;
}
CPrintF("Total length u: %fm\n", fLastU);
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnKeyCtrlShiftK()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
ApplyRndNoiseOntoTerrain();
}
else
{
OnMenuAlignMappingV();
}
}
void CWorldEditorView::OnMenuAlignMappingV()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->m_selPolygonSelection.Count() == 0) return;
FLOAT fLastV = 0;
// for each selected polygon
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo) {
CBrushPolygon &bpo = *itbpo;
CMappingDefinition &md = bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
// find min and max v for the polygon
md.md_fVOffset = 0;
FLOAT fMinV = UpperLimit(0.0f);
FLOAT fMaxV = LowerLimit(0.0f);
for(INDEX ibpe=0; ibpe<bpo.bpo_abpePolygonEdges.Count(); ibpe++) {
CBrushPolygonEdge &bpe = bpo.bpo_abpePolygonEdges[ibpe];
FLOAT3D v0, v1;
MEX2D(vTex0);
bpe.GetVertexCoordinatesRelative(v0, v1);
md.GetTextureCoordinates(
bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative, v0, vTex0);
FLOAT fV = vTex0(2)/1024.0f;
fMinV = Min(fMinV, fV);
fMaxV = Max(fMaxV, fV);
}
// add the offsets to its mapping
md.md_fVOffset=fMinV-fLastV;
fLastV += fMaxV-fMinV;
}
CPrintF("Total length v %fm\n", fLastV);
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnDestroy()
{
// destroy canvas that is currently used
_pGfx->DestroyWindowCanvas( m_pvpViewPort);
m_pvpViewPort = NULL;
CView::OnDestroy();
}
void CWorldEditorView::OnFallDown()
{
CWorldEditorDoc *pDoc = GetDocument();
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
iten->FallDownToFloor();
}
pDoc->UpdateAllViews( NULL);
pDoc->SetModifiedFlag( TRUE);
}
void CWorldEditorView::OnUpdatePrevious(CCmdUI* pCmdUI)
{
CWorldEditorDoc *pDoc = GetDocument();
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
// for browsing trough properties
if( bShift && (pDoc->GetEditingMode() == ENTITY_MODE) && (pDoc->m_selEntitySelection.Count() != 0) )
{
pCmdUI->Enable( TRUE);
}
else if( (pDoc->GetEditingMode() == POLYGON_MODE) && (pDoc->m_selPolygonSelection.Count() != 0) )
{
pCmdUI->Enable( TRUE);
}
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
pCmdUI->Enable( TRUE);
}
else if( (pDoc->m_bBrowseEntitiesMode) || (pDoc->m_cenEntitiesSelectedByVolume.Count()>0) )
{
pDoc->OnUpdatePreviousSelectedEntity(pCmdUI);
}
else
{
OnUpdatePreviousMipBrush( pCmdUI);
}
}
void CWorldEditorView::OnUpdateNext(CCmdUI* pCmdUI)
{
CWorldEditorDoc *pDoc = GetDocument();
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
// for browsing trough properties
if( bShift && (pDoc->GetEditingMode() == ENTITY_MODE) && (pDoc->m_selEntitySelection.Count() != 0) )
{
pCmdUI->Enable( TRUE);
}
else if( (pDoc->GetEditingMode() == POLYGON_MODE) && (pDoc->m_selPolygonSelection.Count() != 0) )
{
pCmdUI->Enable( TRUE);
}
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
pCmdUI->Enable( TRUE);
}
else if( (pDoc->m_bBrowseEntitiesMode) || (pDoc->m_cenEntitiesSelectedByVolume.Count()>0) )
{
pDoc->OnUpdateNextSelectedEntity(pCmdUI);
}
else
{
OnUpdateNextMipBrush( pCmdUI);
}
}
void CWorldEditorView::OnPrevious()
{
CWorldEditorDoc *pDoc = GetDocument();
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CPropertyComboBar &dlgProperty = pMainFrame->m_PropertyComboBar;
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
// in entity mode use shift to select previous property
if( (pDoc->GetEditingMode() == ENTITY_MODE) && bShift )
{
// shift only is used to select previous empty target property
if( !bCtrl)
{
dlgProperty.SelectPreviousEmptyTarget();
}
// ctrl+shift is used to select previous property
else
{
dlgProperty.SelectPreviousProperty();
}
}
else if( (pDoc->GetEditingMode() == POLYGON_MODE) && (pDoc->m_selPolygonSelection.Count() != 0) )
{
OnPreviousPolygon();
}
else if( (pDoc->m_bBrowseEntitiesMode) || (pDoc->m_cenEntitiesSelectedByVolume.Count()>0) )
{
pDoc->OnPreviousSelectedEntity();
}
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
CTerrainLayer *ptlLayer=GetLayer();
if(theApp.m_iTerrainEditMode==TEM_LAYER && ptlLayer!=NULL && ptlLayer->tl_ltType==LT_TILE)
{
CDynamicContainer<CTileInfo> dcTileInfo;
INDEX ctTilesPerRaw=0;
ObtainLayerTileInfo( &dcTileInfo, ptlLayer->tl_ptdTexture, ctTilesPerRaw);
INDEX ctTiles=dcTileInfo.Count();
ptlLayer->tl_iSelectedTile= Clamp( ptlLayer->tl_iSelectedTile+INDEX(1), (INDEX)0, INDEX(ctTiles-1) );
// free allocated tile info structures
for(INDEX i=0; i<dcTileInfo.Count(); i++)
{
delete &dcTileInfo[i];
}
dcTileInfo.Clear();
}
else
{
theApp.m_fCurrentTerrainBrush=ClampUp(theApp.m_fCurrentTerrainBrush+1.0f,FLOAT(CT_BRUSHES-1));
theApp.m_ctTerrainPageCanvas.MarkChanged();
}
}
else
{
OnPreviousMipBrush();
}
}
void CWorldEditorView::OnNext()
{
CWorldEditorDoc *pDoc = GetDocument();
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CPropertyComboBar &dlgProperty = pMainFrame->m_PropertyComboBar;
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
// in entity mode use shift to select next property
if( (pDoc->GetEditingMode() == ENTITY_MODE) && bShift )
{
// shift only is used to select next empty target property
if( !bCtrl)
{
dlgProperty.SelectNextEmptyTarget();
}
// ctrl+shift is used to select next property
else
{
dlgProperty.SelectNextProperty();
}
}
else if( (pDoc->GetEditingMode() == POLYGON_MODE) && (pDoc->m_selPolygonSelection.Count() != 0) )
{
OnNextPolygon();
}
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
CTerrainLayer *ptlLayer=GetLayer();
if(theApp.m_iTerrainEditMode==TEM_LAYER && ptlLayer!=NULL && ptlLayer->tl_ltType==LT_TILE)
{
CDynamicContainer<CTileInfo> dcTileInfo;
INDEX ctTilesPerRaw=0;
ObtainLayerTileInfo( &dcTileInfo, ptlLayer->tl_ptdTexture, ctTilesPerRaw);
INDEX ctTiles=dcTileInfo.Count();
ptlLayer->tl_iSelectedTile= Clamp( ptlLayer->tl_iSelectedTile-INDEX(1), (INDEX)0, INDEX(ctTiles-1) );
// free allocated tile info structures
for(INDEX i=0; i<dcTileInfo.Count(); i++)
{
delete &dcTileInfo[i];
}
dcTileInfo.Clear();
}
else
{
theApp.m_fCurrentTerrainBrush=ClampDn(theApp.m_fCurrentTerrainBrush-1.0f,0.0f);
theApp.m_ctTerrainPageCanvas.MarkChanged();
}
}
else if( (pDoc->m_bBrowseEntitiesMode) || (pDoc->m_cenEntitiesSelectedByVolume.Count()>0) )
{
pDoc->OnNextSelectedEntity();
}
else
{
OnNextMipBrush();
}
}
void CWorldEditorView::OnPreviousPolygon(void)
{
CWorldEditorDoc *pDoc = GetDocument();
pDoc->m_selPolygonSelection.Lock();
ASSERT( pDoc->m_selPolygonSelection.Count() != 0);
INDEX iSelectedPolygon=0;
if( !pDoc->m_selPolygonSelection.IsMember( pDoc->m_pbpoLastCentered))
{
pDoc->m_pbpoLastCentered = &pDoc->m_selPolygonSelection[0];
iSelectedPolygon=0;
}
else
{
INDEX iCurrent = pDoc->m_selPolygonSelection.Index( pDoc->m_pbpoLastCentered);
INDEX iNext = (iCurrent+1) % pDoc->m_selPolygonSelection.Count();
pDoc->m_pbpoLastCentered = &pDoc->m_selPolygonSelection[iNext];
iSelectedPolygon=iNext;
}
AllignPolygon( pDoc->m_pbpoLastCentered);
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CTString strMessage;
strMessage.PrintF("Polygon %d/%d", iSelectedPolygon, pDoc->m_selPolygonSelection.Count());
pMainFrame->SetStatusBarMessage( strMessage, STATUS_LINE_PANE, 2);
pDoc->m_selPolygonSelection.Unlock();
}
void CWorldEditorView::OnNextPolygon(void)
{
CWorldEditorDoc *pDoc = GetDocument();
pDoc->m_selPolygonSelection.Lock();
ASSERT( pDoc->m_selPolygonSelection.Count() != 0);
INDEX iSelectedPolygon=0;
if( !pDoc->m_selPolygonSelection.IsMember( pDoc->m_pbpoLastCentered))
{
pDoc->m_pbpoLastCentered = &pDoc->m_selPolygonSelection[0];
iSelectedPolygon=0;
}
else
{
INDEX iCurrent = pDoc->m_selPolygonSelection.Index( pDoc->m_pbpoLastCentered);
INDEX iPrev = (iCurrent+pDoc->m_selPolygonSelection.Count()-1) % pDoc->m_selPolygonSelection.Count();
pDoc->m_pbpoLastCentered = &pDoc->m_selPolygonSelection[iPrev];
iSelectedPolygon=iPrev;
}
AllignPolygon( pDoc->m_pbpoLastCentered);
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CTString strMessage;
strMessage.PrintF("Polygon %d/%d", iSelectedPolygon, pDoc->m_selPolygonSelection.Count());
pMainFrame->SetStatusBarMessage( strMessage, STATUS_LINE_PANE, 2);
pDoc->m_selPolygonSelection.Unlock();
}
void CWorldEditorView::OnRemoveUnusedTextures()
{
CWorldEditorDoc *pDoc = GetDocument();
try
{
// for each entity in the world
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten) {
// if it is brush entity
if (iten->en_RenderType == CEntity::RT_BRUSH) {
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) {
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
// for all polygons in sector
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
{
// if it is non translucent portal same texture
if ( ((itbpo->bpo_ulFlags&BPOF_PORTAL) && !(itbpo->bpo_ulFlags&BPOF_TRANSLUCENT)) &&
(itbpo->bpo_bppProperties.bpp_uwPretenderDistance==0) )
{
itbpo->bpo_abptTextures[0].bpt_toTexture.SetData_t( CTString(""));
itbpo->bpo_abptTextures[1].bpt_toTexture.SetData_t( CTString(""));
itbpo->bpo_abptTextures[2].bpt_toTexture.SetData_t( CTString(""));
}
}
}
}
}
}
}
// if failed
catch( char *err_str)
{
// report error
AfxMessageBox( CString(err_str));
return;
}
}
void CWorldEditorView::OnRotate()
{
Rotate(90.0f, 0.0f);
}
void CWorldEditorView::OnRotateBack()
{
Rotate(-90.0f, 0.0f);
}
#define ANGLE_KEY_DELTA 15.0f
void CWorldEditorView::OnRotateLeft()
{
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
Rotate(ANGLE_KEY_DELTA, 0.0f, bShift);
}
void CWorldEditorView::OnRotateRight()
{
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
Rotate(-ANGLE_KEY_DELTA, 0.0f, bShift);
}
void CWorldEditorView::OnRotateUp()
{
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
CWorldEditorDoc *pDoc = GetDocument();
if( (pDoc->m_pwoSecondLayer != NULL) &&
(pDoc->m_bPrimitiveMode) &&
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) )
{
OnMoveUp();
}
else
{
Rotate(0.0f,-ANGLE_KEY_DELTA, bShift);
}
}
void CWorldEditorView::OnRotateDown()
{
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
CWorldEditorDoc *pDoc = GetDocument();
if( (pDoc->m_pwoSecondLayer != NULL) &&
(pDoc->m_bPrimitiveMode) &&
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) )
{
OnMoveDown();
}
else
{
Rotate(0.0f,ANGLE_KEY_DELTA, bShift);
}
}
void CWorldEditorView::Rotate( FLOAT fAngleLR, FLOAT fAngleUD, BOOL bSmooth/*=FALSE*/)
{
if( bSmooth && Abs(fAngleLR)!=90.0f)
{
fAngleLR/=10;
fAngleUD/=10;
}
CWorldEditorDoc *pDoc = GetDocument();
ANGLE3D a3dForRotation = ANGLE3D(0.0f, 0.0f, 0.0f);
switch( m_ptProjectionType)
{
case CSlaveViewer::PT_ISOMETRIC_FRONT:
case CSlaveViewer::PT_ISOMETRIC_BACK:
{
a3dForRotation(3) = fAngleLR;
a3dForRotation(2) = fAngleUD;
break;
}
case CSlaveViewer::PT_ISOMETRIC_RIGHT:
case CSlaveViewer::PT_ISOMETRIC_LEFT:
{
a3dForRotation(2) = fAngleLR;
a3dForRotation(3) = -fAngleUD;
break;
}
default:
{
a3dForRotation(1) = fAngleLR;
a3dForRotation(2) = fAngleUD;
}
}
if( (pDoc->GetEditingMode() == POLYGON_MODE))
{
if( Abs(fAngleLR)!=90.0f)
{
fAngleLR/=50;
fAngleUD/=50;
}
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if mouse is over polygon
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
CBrushPolygon &bpo = *crRayHit.cr_pbpoBrushPolygon;
FLOAT3D vCenter=bpo.bpo_boxBoundingBox.Center();
vCenter=bpo.bpo_pbplPlane->bpl_plAbsolute.ProjectPoint( vCenter);
CEntity *pen = bpo.bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
CSimpleProjection3D pr;
pr.ObjectPlacementL() = _plOrigin;
pr.ViewerPlacementL() = pen->GetPlacement();
pr.Prepare();
FLOATplane3D vRelative;
pr.ProjectCoordinate(vCenter, vRelative);
// rotate it
ANGLE3D angMappingRotation=ANGLE3D(0,0,0);
angMappingRotation(1)=fAngleLR;
bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.Rotate(
bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative,
vRelative, angMappingRotation(1));
}
}
else if( (pDoc->GetEditingMode() == CSG_MODE))
{
pDoc->m_plSecondLayer.pl_OrientationAngle += a3dForRotation;
}
else if( (pDoc->GetEditingMode() == ENTITY_MODE))
{
CEntity *penBrush = NULL;
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
if (iten->en_RenderType == CEntity::RT_BRUSH) {
penBrush = &*iten;
}
if( !(iten->GetFlags() & ENF_ANCHORED) ||
GetChildFrame()->m_bAncoredMovingAllowed)
{
CPlacement3D plEntity = iten->GetPlacement();
plEntity.pl_OrientationAngle += a3dForRotation;
iten->SetPlacement( plEntity);
}
}}
// check for terrain updating
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
CLightSource *pls = iten->GetLightSource();
if (pls!=NULL)
{
// if light is directional
if(pls->ls_ulFlags &LSF_DIRECTIONAL)
{
CTerrain *ptrTerrain=GetTerrain();
if(ptrTerrain!=NULL) ptrTerrain->UpdateShadowMap();
}
}
}}
if( penBrush != NULL)
{
DiscardShadows( penBrush);
}
}
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::MultiplyMappingOnPolygon( FLOAT fFactor)
{
CWorldEditorDoc *pDoc = GetDocument();
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if mouse is over polygon
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
CMappingDefinitionUI mdui;
CBrushPolygon *pbpo = crRayHit.cr_pbpoBrushPolygon;
pbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.ToUI( mdui);
mdui.mdui_fUStretch *= fFactor;
mdui.mdui_fVStretch *= fFactor;
pbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.FromUI( mdui);
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
}
void CWorldEditorView::OnSelectVisibleSectors()
{
CWorldEditorDoc *pDoc = GetDocument();
pDoc->m_selSectorSelection.Clear();
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
// don't select for hidden entities
if( !(iten->en_ulFlags & ENF_HIDDEN))
{
continue;
}
CEntity::RenderType rt = iten->GetRenderType();
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
{
CBrush3D *pBrush3D = iten->GetBrush();
if(pBrush3D != NULL)
{
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
CBrush3D *pbrBrush = iten->GetBrush();
if( pbrBrush != NULL)
{
CBrushMip *pbmCurrentMip = pbrBrush->GetBrushMipByDistance( fCurrentMipFactor);
if( pbmCurrentMip != NULL)
{
FOREACHINDYNAMICARRAY(pbmCurrentMip->bm_abscSectors, CBrushSector, itbsc)
{
if( !(itbsc->bsc_ulFlags & BSCF_HIDDEN))
{
// add it to selection
pDoc->m_selSectorSelection.Select( *itbsc);
}
}
}
}
}
}
}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnEditCopyAlternative()
{
EditCopy( TRUE);
}
/*
* Draw a line for arrow drawing.
*/
static inline void DrawArrowLine(CDrawPort &dp, const FLOAT2D &vPoint0,
const FLOAT2D &vPoint1, COLOR color, ULONG ulLineType)
{
PIX x0 = (PIX)vPoint0(1);
PIX x1 = (PIX)vPoint1(1);
PIX y0 = (PIX)vPoint0(2);
PIX y1 = (PIX)vPoint1(2);
dp.DrawLine(x0, y0, x1, y1, color, ulLineType);
}
/*
* Draw an arrow for debugging edge directions.
*/
static inline void DrawArrow(CDrawPort &dp, PIX i0, PIX j0, PIX i1, PIX j1, COLOR color,
ULONG ulLineType)
{
FLOAT2D vPoint0 = FLOAT2D((FLOAT)i0, (FLOAT)j0);
FLOAT2D vPoint1 = FLOAT2D((FLOAT)i1, (FLOAT)j1);
FLOAT2D vDelta = vPoint1-vPoint0;
FLOAT fDelta = vDelta.Length();
FLOAT2D vArrowLen, vArrowWidth;
if (fDelta>0.01) {
vArrowLen = vDelta/fDelta*FLOAT(10.0);
vArrowWidth = vDelta/fDelta*FLOAT(2.0);
} else {
vArrowWidth = vArrowLen = FLOAT2D(0.0f, 0.0f);
}
// FLOAT3D vArrowLen = vDelta/5.0f;
// FLOAT3D vArrowWidth = vDelta/30.0f;
Swap(vArrowWidth(1), vArrowWidth(2));
//vArrowWidth(2) *= -1.0f;
DrawArrowLine(dp, vPoint0, vPoint1, color, ulLineType);
DrawArrowLine(dp, vPoint1-vArrowLen+vArrowWidth, vPoint1, color, ulLineType);
DrawArrowLine(dp, vPoint1-vArrowLen-vArrowWidth, vPoint1, color, ulLineType);
//DrawArrowLine(dp, vPoint0+vArrowWidth, vPoint0-vArrowWidth, color, ulLineType);
}
void CWorldEditorView::DrawAxis(const PIX2D &pixC, PIX len, COLOR colAxisColor, COLOR colTextColor,
CTString strU, CTString strV)
{
if( strU=="" || strV=="") return;
// draw arrow-headed axis
DrawArrow( *m_pdpDrawPort, pixC(1), pixC(2), pixC(1)+len, pixC(2), colAxisColor, _FULL_);
DrawArrow( *m_pdpDrawPort, pixC(1), pixC(2), pixC(1), pixC(2)-len, colAxisColor, _FULL_);
// type axis text line
m_pdpDrawPort->SetFont( _pfdConsoleFont);
m_pdpDrawPort->SetTextAspect( 1.0f);
m_pdpDrawPort->SetTextScaling( 1.0f);
m_pdpDrawPort->PutTextCXY( strU, pixC(1)+len+8, pixC(2), colTextColor);
m_pdpDrawPort->PutTextCXY( strV, pixC(1), pixC(2)-len-8, colTextColor);
}
void CWorldEditorView::DrawArrowAndTypeText( CProjection3D &prProjection,
const FLOAT3D &v0, const FLOAT3D &v1, COLOR colColor, CTString strText)
{
// get transformed end vertices
FLOAT3D tv0, tv1;
prProjection.PreClip(v0, tv0);
prProjection.PreClip(v1, tv1);
// clip the edge line
FLOAT3D vClipped0 = tv0;
FLOAT3D vClipped1 = tv1;
ULONG ulClipFlags = prProjection.ClipLine(vClipped0, vClipped1);
// if the edge remains after clipping to front plane
if (ulClipFlags != LCF_EDGEREMOVED) {
// project the vertices
FLOAT3D v3d0, v3d1;
prProjection.PostClip(vClipped0, v3d0);
prProjection.PostClip(vClipped1, v3d1);
// make 2d vertices
FLOAT2D v2d0, v2d1;
v2d0(1) = v3d0(1); v2d0(2) = v3d0(2);
v2d1(1) = v3d1(1); v2d1(2) = v3d1(2);
if( (Abs(v2d1(1)-v2d0(1)) > 8) || (Abs(v2d1(2)-v2d0(2)) > 8) )
{
// draw arrow-headed line between vertices
DrawArrow( *m_pdpDrawPort, (PIX)v2d0(1), (PIX)v2d0(2),
(PIX)v2d1(1), (PIX)v2d1(2), colColor, _FULL_);
// type text over line
if( strText != "")
m_pdpDrawPort->PutTextCXY( strText, (v2d0(1)+v2d1(1))/2, (v2d0(2)+v2d1(2))/2);
}
}
}
void CWorldEditorView::SelectWhoTargets( CDynamicContainer<CEntity> &dcTargetedEntities)
{
CWorldEditorDoc *pDoc = GetDocument();
pDoc->m_selEntitySelection.Clear();
CEntityProperty *pepSelected = NULL;
// for each that can be targeted
FOREACHINDYNAMICCONTAINER(dcTargetedEntities, CEntity, itenTargets)
{
// for each entity in world
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
// obtain entity class ptr
CDLLEntityClass *pdecDLLClass = iten->GetClass()->ec_pdecDLLClass;
// for all classes in hierarchy of this entity
for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
{
// for all properties
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
{
CEntityProperty *pepProperty = &pdecDLLClass->dec_aepProperties[iProperty];
if( pepProperty->ep_eptType == CEntityProperty::EPT_ENTITYPTR)
{
// obtain property ptr
CEntity *penCurrentPtr = ENTITYPROPERTY( &*iten, pepProperty->ep_slOffset, CEntityPointer);
if( (penCurrentPtr == &*itenTargets) && !iten->IsSelected( ENF_SELECTED) )
{
pepSelected = pepProperty;
pDoc->m_selEntitySelection.Select( *iten);
}
}
}
}
}
}
pDoc->m_chSelections.MarkChanged();
// if only one entity targets
if( pDoc->m_selEntitySelection.Count() == 1)
{
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
pMainFrame->m_PropertyComboBar.SelectProperty( pepSelected);
}
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnSelectWhoTargetsOnContext()
{
CWorldEditorDoc *pDoc = GetDocument();
// to hold entities for selecting
CDynamicContainer<CEntity> dcEntities;
// if right-clicked on void or selected entity
if( (m_penEntityHitOnContext == NULL) ||
(m_penEntityHitOnContext->IsSelected( ENF_SELECTED)) )
{
// perform on whole selection
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
dcEntities.Add( iten);
}}
}
else
{
// perform only on right-clicked entity
dcEntities.Add( m_penEntityHitOnContext);
}
// select all entities that target ones from dynamic container
SelectWhoTargets( dcEntities);
}
void CWorldEditorView::OnSelectWhoTargets()
{
CWorldEditorDoc *pDoc = GetDocument();
// to hold entities for selecting
CDynamicContainer<CEntity> dcEntities;
// perform on whole selection
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
dcEntities.Add( iten);
}}
// select all entities that target ones from dynamic container
SelectWhoTargets( dcEntities);
}
void CWorldEditorView::OnSelectAllTargetsOnContext()
{
CEntity *pen = m_penEntityHitOnContext;
if( pen==NULL || pen->IsSelected( ENF_SELECTED))
{
SelectAllTargetsOfSelectedEntities();
return;
}
else
{
SelectAllTargetsOfEntity(pen);
}
}
void CWorldEditorView::OnSelectAllTargets()
{
SelectAllTargetsOfSelectedEntities();
}
void CWorldEditorView::SelectAllTargetsOfEntity(CEntity *pen)
{
ASSERT( pen!= NULL);
CWorldEditorDoc *pDoc = GetDocument();
// obtain entity class ptr
CDLLEntityClass *pdecDLLClass = pen->GetClass()->ec_pdecDLLClass;
// to hold entities for selecting
CDynamicContainer<CEntity> dcEntities;
// for all classes in hierarchy of this entity
for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
{
// for all properties
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
{
CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
if( epProperty.ep_eptType == CEntityProperty::EPT_ENTITYPTR &&
epProperty.ep_strName!=NULL &&
CTString(epProperty.ep_strName)!="")
{
// obtain property ptr
CEntity *penTarget = ENTITYPROPERTY( &*pen, epProperty.ep_slOffset, CEntityPointer);
if( penTarget != NULL)
{
// add it to container
dcEntities.Add( penTarget);
}
}
}
}
// for all entities in dynamic container
FOREACHINDYNAMICCONTAINER(dcEntities, CEntity, iten)
{
// if not yet selected
if( !iten->IsSelected( ENF_SELECTED))
{
// select it
pDoc->m_selEntitySelection.Select( *iten);
}
}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::SelectAllTargetsOfSelectedEntities(void)
{
CWorldEditorDoc *pDoc = GetDocument();
// to hold entities for selecting
CDynamicContainer<CEntity> dcEntities;
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
// obtain entity class ptr
CDLLEntityClass *pdecDLLClass = iten->GetClass()->ec_pdecDLLClass;
// for all classes in hierarchy of this entity
for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
{
// for all properties
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
{
CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
if(epProperty.ep_eptType==CEntityProperty::EPT_ENTITYPTR &&
epProperty.ep_strName!=NULL &&
CTString(epProperty.ep_strName)!="")
{
// obtain property ptr
CEntity *penTarget = ENTITYPROPERTY( &*iten, epProperty.ep_slOffset, CEntityPointer);
if( penTarget != NULL)
{
// add it to container
dcEntities.Add( penTarget);
}
}
}
}
}}
// for all entities in dynamic container
FOREACHINDYNAMICCONTAINER( dcEntities, CEntity, iten)
{
// if not yet selected
if( !iten->IsSelected( ENF_SELECTED))
{
// select it
pDoc->m_selEntitySelection.Select( *iten);
}
}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
return;
}
void CWorldEditorView::OnSelectInvalidTris()
{
CWorldEditorDoc *pDoc = GetDocument();
// for each entity in the world
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten) {
// if it is brush entity
if (iten->en_RenderType == CEntity::RT_BRUSH) {
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) {
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
// for all polygons in sector
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo) {
// if it has invalid triangles
if ((itbpo->bpo_ulFlags&BPOF_INVALIDTRIANGLES)&&
!(itbpo->IsSelected(BPOF_SELECTED))) {
// select it
pDoc->m_selPolygonSelection.Select( *itbpo);
}
}
}
}
}
}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
BOOL CWorldEditorView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
INDEX iCount = zDelta/120;
BOOL bSpace = (GetKeyState( ' ') & 128) != 0;
BOOL bCtrl = nFlags & MK_CONTROL;
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
CWorldEditorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// ctrl + mouse wheel toggle modes
/*
if( bCtrl && !bSpace && !bShift && !bAlt)
{
for( INDEX iKnee=0; iKnee<Abs(iCount); iKnee++)
{
if(iCount<0)
{
switch(pDoc->GetEditingMode())
{
case( ENTITY_MODE):
{
pDoc->SetEditingMode( SECTOR_MODE);
break;
}
case( SECTOR_MODE):
{
pDoc->SetEditingMode( POLYGON_MODE);
break;
}
case( POLYGON_MODE):
{
pDoc->SetEditingMode( VERTEX_MODE);
break;
}
case( VERTEX_MODE):
{
pDoc->SetEditingMode( TERRAIN_MODE);
break;
}
case( TERRAIN_MODE):
{
pDoc->SetEditingMode( ENTITY_MODE);
break;
}
}
}
else
{
switch(pDoc->GetEditingMode())
{
case( ENTITY_MODE):
{
pDoc->SetEditingMode( TERRAIN_MODE);
break;
}
case( SECTOR_MODE):
{
pDoc->SetEditingMode( ENTITY_MODE);
break;
}
case( POLYGON_MODE):
{
pDoc->SetEditingMode( SECTOR_MODE);
break;
}
case( VERTEX_MODE):
{
pDoc->SetEditingMode( POLYGON_MODE);
break;
}
case( TERRAIN_MODE):
{
pDoc->SetEditingMode( VERTEX_MODE);
break;
}
}
}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
}
*/
// space+ctrl+lmb zoomes in 2x
if( bSpace && bCtrl)
{
BOOL bHitModels = (pDoc->GetEditingMode() == ENTITY_MODE) || bSpace;
BOOL bHitFields = (pDoc->GetEditingMode() == ENTITY_MODE) || bSpace;
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse, FALSE, bHitModels, bHitFields);
// set new target
GetChildFrame()->m_mvViewer.SetTargetPlacement( crRayHit.cr_vHit);
// move mouse to center of screen
CPoint ptCenter = CPoint( m_pdpDrawPort->GetWidth()/2, m_pdpDrawPort->GetHeight()/2);
ClientToScreen( &ptCenter);
SetCursorPos(ptCenter.x, ptCenter.y);
OnZoomMore();
pDoc->UpdateAllViews( NULL);
m_ptMouseDown = ptCenter;
for( INDEX iKnee=0; iKnee<Abs(iCount); iKnee++)
{
if(iCount<0) OnZoomLess();
else OnZoomMore();
}
}
else
{
for( INDEX iKnee=0; iKnee<Abs(iCount); iKnee++)
{
if(iCount<0) PostMessage( WM_COMMAND, ID_PREVIOUS, 0);
else PostMessage( WM_COMMAND, ID_NEXT, 0);
}
}
return CView::OnMouseWheel(nFlags, zDelta, pt);
}
void CWorldEditorView::OnSelectSectorsOtherSide()
{
CWorldEditorDoc* pDoc = GetDocument();
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) &&
(crRayHit.cr_pbpoBrushPolygon->bpo_ulFlags & BPOF_PORTAL))
{
CBrushPolygon &bpo = *crRayHit.cr_pbpoBrushPolygon;
// for all sectors behind portal
{FOREACHDSTOFSRC(bpo.bpo_rsOtherSideSectors, CBrushSector, bsc_rdOtherSidePortals, pbsc)
if( !pbsc->IsSelected( BSCF_SELECTED))
{
pDoc->m_selSectorSelection.Select( *pbsc);
}
ENDFOR}
pDoc->SetEditingMode( SECTOR_MODE);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
}
void CWorldEditorView::OnSelectLinksToSector()
{
CWorldEditorDoc* pDoc = GetDocument();
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL))
{
CBrushSector &bsc = *crRayHit.cr_pbpoBrushPolygon->bpo_pbscSector;
// for all sectors behind portal
{FOREACHSRCOFDST(bsc.bsc_rdOtherSidePortals, CBrushPolygon, bpo_rsOtherSideSectors, pbpo)
if( !pbpo->IsSelected( BPOF_SELECTED))
{
pDoc->m_selPolygonSelection.Select( *pbpo);
}
ENDFOR}
pDoc->SetEditingMode( POLYGON_MODE);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
}
void CWorldEditorView::OnRemainSelectedByOrientation()
{
OnRemainSelectedByOrientation(TRUE);
}
void CWorldEditorView::OnRemainSelectedbyOrientationSingle()
{
OnRemainSelectedByOrientation(FALSE);
}
void CWorldEditorView::OnRemainSelectedByOrientation(BOOL bBothSides)
{
CWorldEditorDoc* pDoc = GetDocument();
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
CBrushPolygon *pbpoPolygon = crRayHit.cr_pbpoBrushPolygon;
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(pbpoPolygon != NULL) )
{
FLOAT3D vReference = pbpoPolygon->bpo_pbplPlane->bpl_plAbsolute;
// copy polygon selection to container
CDynamicContainer<CBrushPolygon> dcTemp;
{FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
dcTemp.Add( itbpo);
}}
pDoc->m_selPolygonSelection.Clear();
{FOREACHINDYNAMICCONTAINER( dcTemp, CBrushPolygon, itbpo)
{
FLOAT fCos;
if( bBothSides)
{
fCos = Abs(vReference % itbpo->bpo_pbplPlane->bpl_plAbsolute);
}
else
{
fCos = vReference % itbpo->bpo_pbplPlane->bpl_plAbsolute;
}
if( fCos > CosFast(360.0f/8.0f))
{
pDoc->m_selPolygonSelection.Select( *itbpo);
}
}}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
}
void CWorldEditorView::OnDeselectByOrientation()
{
CWorldEditorDoc* pDoc = GetDocument();
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
CBrushPolygon *pbpoPolygon = crRayHit.cr_pbpoBrushPolygon;
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(pbpoPolygon != NULL) )
{
FLOAT3D vReference = pbpoPolygon->bpo_pbplPlane->bpl_plAbsolute;
// copy polygon selection to container
CDynamicContainer<CBrushPolygon> dcTemp;
{FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
dcTemp.Add( itbpo);
}}
pDoc->m_selPolygonSelection.Clear();
{FOREACHINDYNAMICCONTAINER( dcTemp, CBrushPolygon, itbpo)
{
FLOAT fCos = Abs(vReference % itbpo->bpo_pbplPlane->bpl_plAbsolute);
if( fCos < CosFast(360.0f/8.0f))
{
pDoc->m_selPolygonSelection.Select( *itbpo);
}
}}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
}
void CWorldEditorView::OnReoptimizeBrushes()
{
CWorldEditorDoc* pDoc = GetDocument();
CWaitCursor wc;
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
pDoc->ClearSelections();
pDoc->m_chSelections.MarkChanged();
CEntity *penEntityHit = crRayHit.cr_penHit;
BOOL bSelected = crRayHit.cr_penHit->IsSelected( ENF_SELECTED);
if( bSelected && (pDoc->GetEditingMode() == ENTITY_MODE))
{
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
if (iten->en_RenderType == CEntity::RT_BRUSH)
{
CBrush3D *pbrBrush = iten->GetBrush();
// for each mip in the brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, pbrBrush->br_lhBrushMips, itbm)
{
// reoptimize it
itbm->Reoptimize();
}
DiscardShadows( &*iten);
if( iten->GetFlags() & ENF_ZONING)
{
pbrBrush->SwitchToZoning();
}
else
{
pbrBrush->SwitchToNonZoning();
}
}
}}
}
else
{
if (penEntityHit->en_RenderType == CEntity::RT_BRUSH)
{
CBrush3D *pbrBrush = penEntityHit->GetBrush();
// for each mip in the brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, pbrBrush->br_lhBrushMips, itbm)
{
// reoptimize it
itbm->Reoptimize();
}
DiscardShadows( penEntityHit);
if( penEntityHit->GetFlags() & ENF_ZONING)
{
pbrBrush->SwitchToZoning();
}
else
{
pbrBrush->SwitchToNonZoning();
}
}
}
// automaticly update portal links
pDoc->m_woWorld.RebuildLinks();
pDoc->UpdateAllViews( NULL);
pDoc->SetModifiedFlag();
}
// ray-hit didn't hit any entity, reoptimize the whole world
else
{
// for each entity in the world
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
// if it is brush entity
if (iten->en_RenderType == CEntity::RT_BRUSH)
{
CBrush3D *pbrBrush = iten->GetBrush();
// for each mip in the brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, pbrBrush->br_lhBrushMips, itbm)
{
// reoptimize it
itbm->Reoptimize();
}
DiscardShadows( iten);
if( iten->GetFlags() & ENF_ZONING)
{
pbrBrush->SwitchToZoning();
}
else
{
pbrBrush->SwitchToNonZoning();
}
}
}
}
}
void CWorldEditorView::OnMergeVertices()
{
CWorldEditorDoc* pDoc = GetDocument();
pDoc->RememberUndo();
pDoc->ClearSelections( ST_VERTEX);
CDynamicContainer<CBrushVertex> cbvxAllreadyDone;
DOUBLE3D vMergeToVertex;
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
{
vMergeToVertex = FLOATtoDOUBLE(itbvx->bvx_vAbsolute);
}}
// deselect vertices that are on right spot, to avoid unnecessary triangularisation
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
{
if( FLOATtoDOUBLE(itbvx->bvx_vAbsolute) == vMergeToVertex)
{
cbvxAllreadyDone.Add(itbvx);
}
}}
{FOREACHINDYNAMICCONTAINER( cbvxAllreadyDone, CBrushVertex, itbvx)
{
pDoc->m_selVertexSelection.Deselect( *itbvx);
}}
// triangularize all influenced polygons
pDoc->m_woWorld.TriangularizeForVertices( pDoc->m_selVertexSelection);
// for each vertex
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
{
// set its new position
itbvx->SetAbsolutePosition( vMergeToVertex);
}}
// reselect vertices
{FOREACHINDYNAMICCONTAINER( cbvxAllreadyDone, CBrushVertex, itbvx)
{
pDoc->m_selVertexSelection.Select( *itbvx);
}}
// update sectors
pDoc->m_woWorld.UpdateSectorsDuringVertexChange( pDoc->m_selVertexSelection);
pDoc->m_woWorld.UpdateSectorsAfterVertexChange( pDoc->m_selVertexSelection);
pDoc->UpdateAllViews( NULL);
pDoc->SetModifiedFlag();
}
void CWorldEditorView::OnExportDisplaceMap()
{
CImageInfo ii;
CDlgDisplaceMapSize dlgDisplaceMapSize;
if( dlgDisplaceMapSize.DoModal() != IDOK)
{
return;
}
CWorldEditorDoc* pDoc = GetDocument();
// find bounding box of all selected polygons
FLOATaabbox3D boxSelection;
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
// calculate bounding box for all polygons
boxSelection |= itbpo->bpo_boxBoundingBox;
}
PIX pixWidth = dlgDisplaceMapSize.m_pixWidth;
PIX pixHeight = dlgDisplaceMapSize.m_pixHeight;
FLOAT fMinX = boxSelection.Min()(1);
FLOAT fMaxX = boxSelection.Max()(1);
FLOAT fMinY = boxSelection.Min()(2);
FLOAT fMaxY = boxSelection.Max()(2);
FLOAT fSizeY = boxSelection.Size()(2);
FLOAT fMinZ = boxSelection.Min()(3);
FLOAT fMaxZ = boxSelection.Max()(3);
FLOAT fDeltaX;
FLOAT fDeltaZ;
if (dlgDisplaceMapSize.m_bMidPixSample)
{
fDeltaX = (fMaxX-fMinX)/pixWidth;
fDeltaZ = (fMaxZ-fMinZ)/pixHeight;
}
else
{
fDeltaX = (fMaxX-fMinX-0.5f)/pixWidth;
fDeltaZ = (fMaxZ-fMinZ-0.5f)/pixHeight;
}
CPrintF("Export displace map...\n");
CPrintF("Min: (%gf, %gf, %gf), Max: (%gf, %gf, %gf), Delta X=%g, Delta Z=%g\n",
fMinX, fMinY, fMinZ,
fMaxX, fMaxY, fMaxZ,
fDeltaX, fDeltaZ);
CTFileName fnDocName = CTString(CStringA(pDoc->GetPathName()));
CTFileName fnDirectory = fnDocName.FileDir();
CTFileName fnDefaultSelected = fnDocName.FileName()+CTString("DisplaceMap.tga");
try
{
fnDirectory.RemoveApplicationPath_t();
}
catch( char *str_err)
{
AfxMessageBox( CString(str_err));
return;
}
// note: NULL given instead of profile string name, to avoid using last directory
CTFileName fnDisplaceMap =
_EngineGUI.FileRequester( "Select name to export displace map",
"Pictures (*.tga)\0*.tga\0" FILTER_END,
NULL, fnDirectory, fnDefaultSelected, NULL, FALSE);
if( fnDisplaceMap == "") return;
ULONG ulSize = pixWidth*pixHeight*3;
UBYTE *pubPicture = (UBYTE *) AllocMemory( ulSize);
// initializes structure members and attaches pointer to image
ii.Attach( pubPicture, pixWidth, pixHeight, 24);
// for each line of pixels in height map
for( INDEX iY=0; iY<pixHeight; iY++)
{
// for each horizontal pixel in height map
for( INDEX iX=0; iX<pixWidth; iX++)
{
FLOAT fX;
FLOAT fZ;
// calculate coordinate in world
if (dlgDisplaceMapSize.m_bMidPixSample)
{
fX = fMinX+fDeltaX*iX+fDeltaX/2;
fZ = fMinZ+fDeltaZ*iY+fDeltaZ/2;
}
else
{
fX = fMinX+fDeltaX*iX+0.1;
fZ = fMinZ+fDeltaZ*iY+0.1;
}
// cast ray to recive height
CCastRay crRayHit = CCastRay( NULL, CPlacement3D(FLOAT3D(fX, fMaxY+1.0f, fZ), ANGLE3D(0,-90,0)) );
crRayHit.cr_bAllowOverHit = TRUE;
crRayHit.cr_bHitPortals = FALSE;
crRayHit.cr_ttHitModels = CCastRay::TT_NONE;
// cast ray, go for hit data
pDoc->m_woWorld.CastRay( crRayHit);
if (!dlgDisplaceMapSize.m_bHighResolution){
// set black pixel if nothing hit
UBYTE ubPixelColor = 0;
if( crRayHit.cr_penHit != NULL)
{
FLOAT fYHit = crRayHit.cr_vHit(2);
ubPixelColor = (UBYTE) ((fYHit-fMinY)/fSizeY*255.0f);
}
UBYTE *pPixel=pubPicture+iY*pixWidth*3+iX*3;
*(pPixel+0) = ubPixelColor;
*(pPixel+1) = ubPixelColor;
*(pPixel+2) = ubPixelColor;
}
else
{
// set black pixel if nothing hit
unsigned short usPixelColor = 0;
if( crRayHit.cr_penHit != NULL)
{
FLOAT fYHit = crRayHit.cr_vHit(2);
usPixelColor = (unsigned short) ((fYHit-fMinY)/fSizeY*65535);
}
UBYTE *pPixel=pubPicture+iY*pixWidth*3+iX*3;
*(pPixel+0) = 0;
*(pPixel+1) = usPixelColor>>8;
*(pPixel+2) = usPixelColor&0xFF;
}
}
}
// try to
try {
// save displace map as TGA
ii.SaveTGA_t( fnDisplaceMap);
} // if failed
catch (char *strError) {
// report error
AfxMessageBox(CString(strError));
}
}
void CWorldEditorView::OnCutMode()
{
// if we should enter cut mode
if( !theApp.m_bCutModeOn)
{
CTString strError;
BOOL bCutEnabled = IsCutEnabled( strError);
if( !bCutEnabled)
{
// warn user
WarningMessage( "%s", strError);
return;
}
}
theApp.m_bCutModeOn = !theApp.m_bCutModeOn;
theApp.m_bMeasureModeOn = FALSE;
}
void CWorldEditorView::OnUpdateCutMode(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
// cut is enabled only in sector and polygon mode
if( (pDoc->GetEditingMode() == POLYGON_MODE) ||
(pDoc->GetEditingMode() == ENTITY_MODE) ||
(pDoc->GetEditingMode() == SECTOR_MODE) )
{
pCmdUI->Enable( TRUE);
}
else
{
pCmdUI->Enable( FALSE);
}
pCmdUI->SetCheck( theApp.m_bCutModeOn);
//pDoc->UpdateAllViews( NULL); !!!!!!!!!!!!!!!!!!!!! unbelievable !!!!!!!!!!!!!!!!!
}
BOOL CWorldEditorView::IsCutEnabled(CTString &strError)
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == ENTITY_MODE)
{
// there must be at least one entity in selection
if( pDoc->m_selEntitySelection.Count() == 0)
{
strError = "You must select entity(s) that you want to mirror!";
return FALSE;
}
}
else if( pDoc->GetEditingMode() == POLYGON_MODE)
{
// there must be at least one polygon in selection
if( pDoc->m_selPolygonSelection.Count() == 0)
{
strError = "You must select polygon(s) that you want to cut!";
return FALSE;
}
// all polygons must be of the same brush
CBrush3D *pbrBrush = NULL;
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
// remember first polygon's brush
if( pbrBrush == NULL)
{
pbrBrush = itbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush;
}
else
{
// if any of the other polygons are not from same brush
if( pbrBrush != itbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush)
{
// don't allow cut
strError = "All polygons must be from the same brush to be able to cut them!";
return FALSE;
}
}
}
}
else if(pDoc->GetEditingMode() == SECTOR_MODE)
{
// there must be at least one sector in selection
if( pDoc->m_selSectorSelection.Count() == 0)
{
strError = "You must select sector(s) that you want to cut!";
return FALSE;
}
// all sectors must be of the same brush
CBrush3D *pbrBrush = NULL;
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
{
// remember first sector's brush
if( pbrBrush == NULL)
{
pbrBrush = itbsc->bsc_pbmBrushMip->bm_pbrBrush;
}
else
{
// if any of the other sectors are not from same brush
if( pbrBrush != itbsc->bsc_pbmBrushMip->bm_pbrBrush)
{
// don't allow cut
strError = "All sector must be from the same brush to be able to cut them!";
return FALSE;
}
}
}
}
return TRUE;
}
void CWorldEditorView::OnUpdateSelectClones(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
// allow clone selecting only if we have only one entity selected
if( pDoc->m_selEntitySelection.Count() == 1)
{
pCmdUI->Enable( TRUE);
return;
}
pCmdUI->Enable( FALSE);
}
void CWorldEditorView::OnSelectClones()
{
CWorldEditorDoc* pDoc = GetDocument();
CEntity *pen = pDoc->m_selEntitySelection.GetFirstInSelection();
// for each entity in the world
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
// if has same name
if( pen->GetName() == iten->GetName() )
{
// if is not yet selected
if( !iten->IsSelected( ENF_SELECTED))
{
// select it
pDoc->m_selEntitySelection.Select( *iten);
}
}
}
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
BOOL CWorldEditorView::IsSelectClonesOnContextEnabled( void)
{
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
if( crRayHit.cr_penHit != NULL)
{
return TRUE;
}
return FALSE;
}
void CWorldEditorView::OnSelectClonesOnContext()
{
CWorldEditorDoc* pDoc = GetDocument();
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
if( crRayHit.cr_penHit != NULL)
{
// get hitted entity
CEntity *pen = crRayHit.cr_penHit;
// for each entity in the world
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
// if has same name
if( pen->GetName() == iten->GetName() )
{
// if is not yet selected
if( !iten->IsSelected( ENF_SELECTED))
{
// select it
pDoc->m_selEntitySelection.Select( *iten);
}
}
}
}
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnKeyCtrlShiftE()
{
CWorldEditorDoc* pDoc = GetDocument();
if(pDoc->GetEditingMode()==TERRAIN_MODE)
{
ApplyEqualizeOntoTerrain();
}
else
{
OnSelectOfSameClass();
}
}
void CWorldEditorView::OnSelectOfSameClass()
{
CWorldEditorDoc* pDoc = GetDocument();
CEntity *pen = pDoc->m_selEntitySelection.GetFirstInSelection();
// to hold entities for selecting
CDynamicContainer<CEntity> dcEntities;
// for all selected entities
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
dcEntities.Add( &*iten);
}}
// for each non-hidden entity in the world
{FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
CBrushSector *pbscSector = iten->GetFirstSector();
BOOL bSectorVisible = (pbscSector == NULL) ||
!(pbscSector->bsc_ulFlags & BSCF_HIDDEN);
// if it isn't classified in hidden sector and is not hidden itself
if( !bSectorVisible || (iten->en_ulFlags&ENF_HIDDEN) )
{
continue;
}
// obtain this entity's class ptr
CEntityClass *pdecClass = iten->GetClass();
// test all classes
{FOREACHINDYNAMICCONTAINER(dcEntities, CEntity, itenClass)
{
CEntityClass *pdecClassTest = itenClass->GetClass();
// if of same class
if( pdecClassTest == pdecClass)
{
// if not yet selected
if( !iten->IsSelected( ENF_SELECTED))
{
// select it
pDoc->m_selEntitySelection.Select( *iten);
}
}
}}
}}
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnSelectOfSameClassOnContext()
{
CWorldEditorDoc* pDoc = GetDocument();
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
if( crRayHit.cr_penHit != NULL)
{
// get hitted entity
CEntity *pen = crRayHit.cr_penHit;
// obtain this entity's class ptr
CEntityClass *pdecClassTest = pen->GetClass();
// for each non-hidden entity in the world
{FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
CBrushSector *pbscSector = iten->GetFirstSector();
BOOL bSectorVisible = (pbscSector == NULL) ||
!(pbscSector->bsc_ulFlags & BSCF_HIDDEN);
// if it isn't classified in hidden sector and is not hidden itself
if( !bSectorVisible || (iten->en_ulFlags&ENF_HIDDEN) )
{
continue;
}
CEntityClass *pdecClass = iten->GetClass();
// if of same class
if( pdecClassTest == pdecClass)
{
// if not yet selected
if( !iten->IsSelected( ENF_SELECTED))
{
// select it
pDoc->m_selEntitySelection.Select( *iten);
}
}
}}
}
// mark that selections have been changed
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
BOOL CWorldEditorView::IsSelectOfSameClassOnContextEnabled( void)
{
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
if( crRayHit.cr_penHit != NULL)
{
return TRUE;
}
return FALSE;
}
// limit current frame rate if neeeded
void LimitFrameRate(void)
{
// measure passed time for each loop
/*
static CTimerValue tvLast(-1.0f);
CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
TIME tmCurrentDelta = (tvNow-tvLast).GetSeconds();
// limit maximum frame rate
wed_iMaxFPSActive = ClampDn( (INDEX)wed_iMaxFPSActive, 1L);
TIME tmWantedDelta = 1.0f / wed_iMaxFPSActive;
if( tmCurrentDelta<tmWantedDelta) Sleep( (tmWantedDelta-tmCurrentDelta)*1000.0f);
// remember new time
tvLast = _pTimer->GetHighPrecisionTimer();*/
}
void CWorldEditorView::ApplyFreeModeControls( CPlacement3D &pl, ANGLE3D &aAbs, FLOAT &fSpeedMultiplier, BOOL bPrescan)
{
CChildFrame *pcf = GetChildFrame();
CWorldEditorDoc* pDoc = GetDocument();
#define FB_SPEED 1.0f
#define LR_SPEED 1.0f
#define UD_SPEED 1.0f
#define ROT_SPEED 0.75f
FLOAT fFB = 0.0f; // forward/backward movement
FLOAT fLR = 0.0f; // left/right movement
FLOAT fUD = 0.0f; // up/down movement
FLOAT fRLR = 0.0f; // rotate left/right
FLOAT fRUD = 0.0f; // rotate up/down
_pInput->GetInput(bPrescan);
if (!bPrescan) {
// additional key indentifiers are not on
BOOL bShift = _pInput->GetButtonState( KID_LSHIFT) || _pInput->GetButtonState( KID_RSHIFT);
BOOL bAlt = _pInput->GetButtonState( KID_LALT) || _pInput->GetButtonState( KID_RALT);
BOOL bCtrl = _pInput->GetButtonState( KID_LCONTROL) || _pInput->GetButtonState( KID_RCONTROL);
// apply view configuration from first perspective view of child configuration
if(_pInput->GetButtonState( KID_NUM0)) pcf->ApplySettingsFromPerspectiveView( this, 0);
if(_pInput->GetButtonState( KID_NUM1)) pcf->ApplySettingsFromPerspectiveView( this, 1);
if(_pInput->GetButtonState( KID_NUM2)) pcf->ApplySettingsFromPerspectiveView( this, 2);
if(_pInput->GetButtonState( KID_NUM3)) pcf->ApplySettingsFromPerspectiveView( this, 3);
if(_pInput->GetButtonState( KID_NUM4)) pcf->ApplySettingsFromPerspectiveView( this, 4);
if(_pInput->GetButtonState( KID_NUM5)) pcf->ApplySettingsFromPerspectiveView( this, 5);
if(_pInput->GetButtonState( KID_NUM6)) pcf->ApplySettingsFromPerspectiveView( this, 6);
if(_pInput->GetButtonState( KID_NUM7)) pcf->ApplySettingsFromPerspectiveView( this, 7);
if(_pInput->GetButtonState( KID_NUM8)) pcf->ApplySettingsFromPerspectiveView( this, 8);
if(_pInput->GetButtonState( KID_NUM9)) pcf->ApplySettingsFromPerspectiveView( this, 9);
// apply view configuration from available buffers
if(_pInput->GetButtonState( KID_0)) OnKeyBuffer( ID_BUFFER10);
if(_pInput->GetButtonState( KID_1)) OnKeyBuffer( ID_BUFFER01);
if(_pInput->GetButtonState( KID_2)) OnKeyBuffer( ID_BUFFER02);
if(_pInput->GetButtonState( KID_3)) OnKeyBuffer( ID_BUFFER03);
if(_pInput->GetButtonState( KID_4)) OnKeyBuffer( ID_BUFFER04);
if(_pInput->GetButtonState( KID_5)) OnKeyBuffer( ID_BUFFER05);
if(_pInput->GetButtonState( KID_6)) OnKeyBuffer( ID_BUFFER06);
if(_pInput->GetButtonState( KID_7)) OnKeyBuffer( ID_BUFFER07);
if(_pInput->GetButtonState( KID_8)) OnKeyBuffer( ID_BUFFER08);
if(_pInput->GetButtonState( KID_9)) OnKeyBuffer( ID_BUFFER09);
// ---------- Simulate moving as in fly mode
// forward
if(
_pInput->GetButtonState( KID_W) ||
_pInput->GetButtonState( KID_MOUSE2) ||
_pInput->GetButtonState( KID_ARROWUP))
{
fFB = -FB_SPEED*fSpeedMultiplier;
}
// backward
if(
_pInput->GetButtonState( KID_S) ||
_pInput->GetButtonState( KID_MOUSE1) ||
_pInput->GetButtonState( KID_ARROWDOWN) )
{
fFB = +FB_SPEED*fSpeedMultiplier;
}
/*
if( _pInput->GetButtonState( KID_MOUSE1))
{
fLR = -_pInput->GetAxisRelative(1)/15.0f;
}*/
// strife left
if(
_pInput->GetButtonState( KID_Q) ||
_pInput->GetButtonState( KID_A) ||
_pInput->GetButtonState( KID_ARROWLEFT) )
{
fLR = -LR_SPEED*fSpeedMultiplier;
}
// strife right
if(
_pInput->GetButtonState( KID_E) ||
_pInput->GetButtonState( KID_D) ||
_pInput->GetButtonState( KID_ARROWRIGHT) )
{
fLR = +LR_SPEED*fSpeedMultiplier;
}
// up
if( (_pInput->GetButtonState( KID_R) && !bAlt) ||
_pInput->GetButtonState( KID_SPACE) )
{
fUD = +UD_SPEED*fSpeedMultiplier;
}
// down
if( _pInput->GetButtonState( KID_F))
{
fUD = -UD_SPEED*fSpeedMultiplier;
}
// drop marker here
if( _pInput->GetButtonState( KID_C))
{
CTFileName fnDropClass;
CTString strTargetProperty;
if(pDoc->m_selEntitySelection.Count() == 1)
{
CEntity &enOnly = pDoc->m_selEntitySelection.GetFirst();
if(enOnly.DropsMarker( fnDropClass, strTargetProperty))
{
OnDropMarker(pl);
}
}
}
static BOOL bLastTurboDown = FALSE;
static FLOAT fSpeedMultiplierBeforeTurbo = 1.0f;
if( _pInput->GetButtonState( KID_TAB))
{
if( !bLastTurboDown)
{
fSpeedMultiplierBeforeTurbo = fSpeedMultiplier;
}
bLastTurboDown = TRUE;
fSpeedMultiplier = Clamp( fSpeedMultiplier+0.5f, 1.0f, 20.0f);
}
else if( bLastTurboDown)
{
bLastTurboDown = FALSE;
fSpeedMultiplier = fSpeedMultiplierBeforeTurbo;
}
}
// get current rotation
fRLR = _pInput->GetAxisValue(1)*ROT_SPEED;
fRUD = -_pInput->GetAxisValue(2)*ROT_SPEED;
// apply translation
if (!bPrescan) {
pl.Translate_OwnSystem( FLOAT3D(fLR, fUD, fFB));
// apply rotation
pl.pl_OrientationAngle = aAbs;//.Rotate_HPB( ANGLE3D(-fRLR, -fRUD, 0));
}
aAbs+=ANGLE3D(-fRLR, -fRUD, 0);
}
// placements and orientation used in free fly mode
static CPlacement3D _plNew;
static CPlacement3D _plOld;
static ANGLE3D _aAbs;
void CWorldEditorView::PumpWindowsMessagesInFreeMode(BOOL &bRunning, FLOAT &fSpeedMultiplier)
{
CChildFrame *pcf = GetChildFrame();
CWorldEditorDoc* pDoc = GetDocument();
// additional key indentifiers are not on
BOOL bShift = _pInput->GetButtonState( KID_LSHIFT) || _pInput->GetButtonState( KID_RSHIFT);
BOOL bAlt = _pInput->GetButtonState( KID_LALT) || _pInput->GetButtonState( KID_RALT);
BOOL bCtrl = _pInput->GetButtonState( KID_LCONTROL) || _pInput->GetButtonState( KID_RCONTROL);
// while there are any messages in the message queue
MSG msg;
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// process scripts that are invoked on shortcuts from within WED
ProcesWEDConsoleShortcuts( &msg);
if(msg.message==_uiMessengerMsg)
{
// if one application allready started
HWND hwndMessenger = ::FindWindow(NULL, L"Croteam Messenger");
if(hwndMessenger != NULL)
{
// force messenger to popup
::PostMessage( hwndMessenger, _uiMessengerForcePopup, 0, 0);
}
}
// ---------- Simulate some important commands of wed
if( msg.message==WM_KEYDOWN || msg.message==WM_SYSKEYDOWN)
{
// 'G' links on/off
if( msg.wParam=='G' && !bCtrl) pcf->OnRenderTargets();
// 'G' links on/off
if( msg.wParam=='G' && bCtrl) pcf->OnToggleEntityNames();
// 'H' shadow on off
if( msg.wParam=='H') pcf->OnViewShadowsOnoff();
// 'Num -' toggle frame rate
if( msg.wParam == VK_SUBTRACT) pcf->OnSceneRenderingTime();
// 'B' toggle auto mip leveling
if( msg.wParam=='B') pcf->OnAutoMipLeveling();
// 'Alt+R' toggle frame rate
if( msg.wParam=='R' && bAlt) pcf->OnSceneRenderingTime();
// 'Shift+Backspace' center background viewer
if( (msg.wParam == VK_BACK) && bShift)
{
OnCenterBcgViewer();
_plNew = pcf->m_mvViewer.mv_plViewer;
_plOld = _plNew;
_aAbs = _plNew.pl_OrientationAngle;
}
// 'Backspace' center to 0
else if( msg.wParam == VK_BACK)
{
OnResetViewer();
_plNew = pcf->m_mvViewer.mv_plViewer;
_plOld = _plNew;
_aAbs = _plNew.pl_OrientationAngle;
}
// 'F5, F6, F7, F8' type of projections
if( (msg.wParam == VK_F5) && bShift) OnIsometricBottom();
else if( msg.wParam == VK_F5) OnIsometricTop();
if( (msg.wParam == VK_F6) && bShift) OnIsometricLeft();
else if( msg.wParam == VK_F6) OnIsometricRight();
if( (msg.wParam == VK_F7) && bShift) OnIsometricBack();
else if( msg.wParam == VK_F7) OnIsometricFront();
if( (msg.wParam == VK_F8)) OnPerspective();
// 'Home', 'End', 'Page Up', 'Page Dn' 'Ctrl+' combinations for storing and restoring positions
if( (msg.wParam == VK_HOME) && bCtrl) pcf->OnStorePosition01();
else if( msg.wParam == VK_HOME)
{
pcf->OnRestorePosition01();
_plNew = pcf->m_mvViewer.mv_plViewer;
_plOld = _plNew;
_aAbs = _plNew.pl_OrientationAngle;
}
if( (msg.wParam == VK_END) && bCtrl) pcf->OnStorePosition02();
else if( msg.wParam == VK_END)
{
pcf->OnRestorePosition02();
_plNew = pcf->m_mvViewer.mv_plViewer;
_plOld = _plNew;
_aAbs = _plNew.pl_OrientationAngle;
}
if( (msg.wParam == VK_PRIOR) && bCtrl) pcf->OnStorePosition03();
else if( msg.wParam == VK_PRIOR)
{
pcf->OnRestorePosition03();
_plNew = pcf->m_mvViewer.mv_plViewer;
_plOld = _plNew;
_aAbs = _plNew.pl_OrientationAngle;
}
if( (msg.wParam == VK_NEXT) && bCtrl) pcf->OnStorePosition04();
else if( msg.wParam == VK_NEXT)
{
pcf->OnRestorePosition04();
_plNew = pcf->m_mvViewer.mv_plViewer;
_plOld = _plNew;
_aAbs = _plNew.pl_OrientationAngle;
}
// 'X', 'Alt+X', 'Alt+A' hide selected, unselected, show all
if( (msg.wParam == 'X') && bAlt) pDoc->OnHideUnselected();
else if( msg.wParam == 'X') pDoc->OnHideSelected();
if( (msg.wParam == 'A') && bAlt) pDoc->OnShowAll();
// 'Z' for toggle view selection
if( msg.wParam == 'Z') pcf->OnViewSelection();
}
// use mouse wheel to increase/decrease moving speed
if( msg.message==WM_MOUSEWHEEL)
{
short zDelta = (short) HIWORD(msg.wParam);
INDEX iCount = zDelta/120;
for( INDEX iKnee=0; iKnee<Abs(iCount); iKnee++)
{
if(iCount<0) fSpeedMultiplier/=2;
else fSpeedMultiplier*=2;
}
}
// if it is not a mouse message
if(!(msg.message>=WM_MOUSEFIRST&&msg.message<=WM_MOUSELAST))
{
// if not system key messages
if (!(msg.message==WM_KEYDOWN && msg.wParam==VK_F10
||msg.message==WM_SYSKEYDOWN))
{
// translate it
TranslateMessage(&msg);
}
// if paint message
if (msg.message==WM_PAINT)
{
// dispatch it
DispatchMessage(&msg);
}
}
// if should stop
if( (msg.message==WM_KEYDOWN && msg.wParam==VK_ESCAPE)
||(msg.message==WM_ACTIVATE)
||(msg.message==WM_CANCELMODE)
||(msg.message==WM_KILLFOCUS)
||(msg.message==WM_ACTIVATEAPP))
{
// stop running
bRunning = FALSE;
break;
}
}
}
void CWorldEditorView::OnAlternativeMovingMode()
{
INDEX iAllowMouseAcceleration = _pShell->GetINDEX("inp_bAllowMouseAcceleration");
INDEX iFilterMouse = _pShell->GetINDEX("inp_bFilterMouse");
_pShell->SetINDEX("inp_bAllowMouseAcceleration", 1);
_pShell->SetINDEX("inp_bFilterMouse", 1);
CWorldEditorDoc* pDoc = GetDocument();
CViewPrefs vpOrg = m_vpViewPrefs;
// obtain child frame ptr
CChildFrame *pcf = GetChildFrame();
_plNew = pcf->m_mvViewer.mv_plViewer;
_plOld = _plNew;
_aAbs = _plNew.pl_OrientationAngle;
BOOL bAutoMipBrushingBefore = pcf->m_bAutoMipBrushingOn;
BOOL bDisableVisibilityTweaksBefore = pcf->m_bDisableVisibilityTweaks;
// enable input
_pInput->EnableInput(m_pvpViewPort);
// initialy, game is running
BOOL bRunning = TRUE;
INDEX iLastTick = 0;
CTimerValue tvStart = _pTimer->GetHighPrecisionTimer();
// while it is still running
while( bRunning)
{
// process all windows messages
PumpWindowsMessagesInFreeMode( bRunning, _fFlyModeSpeedMultiplier);
CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
FLOAT fPassed = (tvNow-tvStart).GetSeconds();
INDEX iNowTick = INDEX(fPassed/_pTimer->TickQuantum);
// apply controls for frame rates below tick quantum
while(iLastTick<iNowTick-1)
{
_plOld = _plNew;
ApplyFreeModeControls( _plNew, _aAbs, _fFlyModeSpeedMultiplier, FALSE);
iLastTick++;
}
ApplyFreeModeControls( _plNew, _aAbs, _fFlyModeSpeedMultiplier, TRUE);
// set new viewer position
FLOAT fLerpFactor = (fPassed-iNowTick*_pTimer->TickQuantum)/_pTimer->TickQuantum;
ASSERT(fLerpFactor>0 && fLerpFactor<1.0f);
pcf->m_mvViewer.mv_plViewer.Lerp( _plOld, _plNew, Clamp(fLerpFactor, 0.0f, 1.0f));
pcf->m_mvViewer.mv_plViewer.pl_OrientationAngle = _aAbs;
// disable auto rendering range
m_vpViewPrefs.m_bAutoRenderingRange = FALSE;
m_vpViewPrefs.m_fRenderingRange = 2.0f;
pcf->m_bAutoMipBrushingOn = TRUE;
pcf->m_bDisableVisibilityTweaks=FALSE;
// render view again
CDC *pDC = GetDC();
OnDraw( pDC);
ReleaseDC( pDC);
// smooth frame rate
LimitFrameRate();
}
_pInput->DisableInput();
// restore rendering range settings from remembered stat view prefs
m_vpViewPrefs.m_bAutoRenderingRange = vpOrg.m_bAutoRenderingRange;
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetMinimumRenderRange(vpOrg.m_wrpWorldRenderPrefs.GetMinimumRenderRange());
pcf->m_bAutoMipBrushingOn = bAutoMipBrushingBefore;
pcf->m_bDisableVisibilityTweaks=bDisableVisibilityTweaksBefore;
_pShell->SetINDEX("inp_bAllowMouseAcceleration", iAllowMouseAcceleration);
_pShell->SetINDEX("inp_bFilterMouse", iFilterMouse);
}
void CWorldEditorView::OnReTriple()
{
CWorldEditorDoc* pDoc = GetDocument();
CBrushPolygon *pbpo = pDoc->m_selPolygonSelection.GetFirstInSelection();
pbpo->bpo_pbscSector->ReTriple( pDoc->m_selPolygonSelection);
}
void CWorldEditorView::OnClearAllTargets(void)
{
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CWorldEditorDoc* pDoc = GetDocument();
if( m_bEntityHitedOnContext && m_penEntityHitOnContext != NULL)
{
if( ::MessageBoxA( pMainFrame->m_hWnd, "Are you sure that you want to clear all targets?",
"Warning !", MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2|
MB_SYSTEMMODAL | MB_TOPMOST) != IDYES)
{
return;
}
// clear all targets of right-clicked entity
pMainFrame->m_PropertyComboBar.ClearAllTargets( m_penEntityHitOnContext);
pDoc->UpdateAllViews( NULL);
pDoc->SetModifiedFlag();
}
}
void CWorldEditorView::OnSelectCsgTarget()
{
CWorldEditorDoc* pDoc = GetDocument();
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
if (pbmCurrentMip!=NULL)
{
// obtain entity
CEntity *pen = pbmCurrentMip->bm_pbrBrush->br_penEntity;
if( !pen->IsSelected( ENF_SELECTED))
{
pDoc->m_selEntitySelection.Select( *pen);
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
}
}
void CWorldEditorView::OnUpdateSelectCsgTarget(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
pCmdUI->Enable(pbmCurrentMip!=NULL);
}
void CWorldEditorView::OnUpdateReTriple(CCmdUI* pCmdUI)
{
BOOL bEnableRetripling = FALSE;
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->m_selPolygonSelection.Count() != 0)
{
CBrushPolygon *pbpo = pDoc->m_selPolygonSelection.GetFirstInSelection();
bEnableRetripling = pbpo->bpo_pbscSector->IsReTripleAvailable( pDoc->m_selPolygonSelection);
}
pCmdUI->Enable(bEnableRetripling);
}
void CWorldEditorView::OnTriangularizePolygon()
{
CWorldEditorDoc *pDoc = GetDocument();
CBrushPolygon *pbpoHitted = NULL;
if( (m_penEntityHitOnContext != NULL) &&
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) &&
(m_pbpoRightClickedPolygon != NULL) )
{
pbpoHitted = m_pbpoRightClickedPolygon;
}
if( pbpoHitted != NULL)
{
pDoc->m_selVertexSelection.Clear();
if( pbpoHitted->IsSelected(BPOF_SELECTED))
{
OnTriangularizeSelection();
return;
}
else
{
pDoc->m_selVertexSelection.Clear();
pDoc->m_selPolygonSelection.Clear();
pbpoHitted->bpo_pbscSector->TriangularizePolygon( pbpoHitted);
}
}
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnEntityContextHelp()
{
if( m_penEntityHitOnContext != NULL)
{
theApp.DisplayHelp(m_penEntityHitOnContext->GetClass()->GetName(), HH_DISPLAY_TOPIC, NULL);
}
}
void CWorldEditorView::AutoFitMapping(CBrushPolygon *pbpo, BOOL bInvert/*=FALSE*/, BOOL bFitBoth/*=FALSE*/)
{
CWorldEditorDoc* pDoc = GetDocument();
if( pbpo==NULL) return;
if( pbpo->IsSelected(BPOF_SELECTED))
{
// for each selected polygon
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
AutoFitMappingOnPolygon(*itbpo, bInvert, bFitBoth);
}
}
else
{
AutoFitMappingOnPolygon(*pbpo, bInvert, bFitBoth);
}
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::AutoFitMappingOnPolygon(CBrushPolygon &bpo, BOOL bInvert/*=FALSE*/, BOOL bFitBoth/*=FALSE*/)
{
CWorldEditorDoc* pDoc = GetDocument();
CMappingDefinition &md = bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
// reset u,v stretches
CMappingDefinitionUI mdui;
md.ToUI(mdui);
mdui.mdui_fUStretch = 1.0f;
mdui.mdui_fVStretch = 1.0f;
mdui.mdui_fUOffset = 0.0f;
mdui.mdui_fVOffset = 0.0f;
md.FromUI(mdui);
// find min and max u and v for the polygon
FLOAT fMinU = UpperLimit(0.0f);
FLOAT fMaxU = LowerLimit(0.0f);
FLOAT fMinV = UpperLimit(0.0f);
FLOAT fMaxV = LowerLimit(0.0f);
INDEX ibpe=0;
for(; ibpe<bpo.bpo_abpePolygonEdges.Count(); ibpe++)
{
CBrushPolygonEdge &bpe = bpo.bpo_abpePolygonEdges[ibpe];
FLOAT3D v0, v1;
MEX2D(vTex0);
bpe.GetVertexCoordinatesRelative(v0, v1);
md.GetTextureCoordinates( bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative, v0, vTex0);
FLOAT fU = vTex0(1)/1024.0f;
FLOAT fV = vTex0(2)/1024.0f;
fMinU = Min(fMinU, fU);
fMaxU = Max(fMaxU, fU);
fMinV = Min(fMinV, fV);
fMaxV = Max(fMaxV, fV);
}
// calculate u,v fit stretches
FLOAT fFitStretchU = fMaxU-fMinU;
FLOAT fFitStretchV = fMaxV-fMinV;
// get fit stretch
FLOAT fFitStretch;
if( !bInvert)
{
fFitStretch = Min(fFitStretchV,fFitStretchU);
}
else
{
fFitStretch = Max(fFitStretchV,fFitStretchU);
}
// adjust stretch for texture size
CTextureData *ptd = (CTextureData *)bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.GetData();
if( ptd!=NULL)
{
MEX mexW=ptd->GetWidth();
MEX mexH=ptd->GetHeight();
// if fitting U
if( fFitStretch==fFitStretchU)
{
fFitStretch/=mexW/1024.0f;
}
// if fitting V
else
{
fFitStretch/=mexH/1024.0f;
}
fFitStretchU/=mexW/1024.0f;
fFitStretchV/=mexH/1024.0f;
}
if( bFitBoth)
{
mdui.mdui_fUStretch=fFitStretchU;
mdui.mdui_fVStretch=fFitStretchV;
}
else
{
mdui.mdui_fUStretch=fFitStretch;
mdui.mdui_fVStretch=fFitStretch;
}
md.FromUI(mdui);
CMappingVectors &mv = bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative;
// find vtx that has min u and v
fMinU = UpperLimit(0.0f);
fMaxV = LowerLimit(0.0f);
FLOAT3D vMinU, vMaxV;
for(ibpe=0; ibpe<bpo.bpo_abpePolygonEdges.Count(); ibpe++)
{
CBrushPolygonEdge &bpe = bpo.bpo_abpePolygonEdges[ibpe];
FLOAT3D v0, v1, va0, va1;
MEX2D(vTex0);
bpe.GetVertexCoordinatesRelative(v0, v1);
bpe.GetVertexCoordinatesAbsolute(va0, va1);
md.GetTextureCoordinates( mv, v0, vTex0);
FLOAT fU = vTex0(1)/1024.0f;
FLOAT fV = vTex0(2)/1024.0f;
if( fU<fMinU)
{
vMinU=v0;
fMinU=fU;
}
if( fV>fMaxV)
{
vMaxV=v0;
fMaxV=fV;
}
}
// remember u offset
md.Center(mv, vMinU);
md.ToUI(mdui);
fMinU = mdui.mdui_fUOffset;
// remember v offset
md.Center(mv, vMaxV);
md.ToUI(mdui);
fMaxV = mdui.mdui_fVOffset;
// set offsets
mdui.mdui_fUOffset=fMinU;
mdui.mdui_fVOffset=fMaxV;
md.FromUI(mdui);
}
void CWorldEditorView::OnTriangularizeSelection()
{
CWorldEditorDoc* pDoc = GetDocument();
CDynamicContainer<CBrushPolygon> dcPolygons;
// copy polygon selection
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
dcPolygons.Add(&*itbpo);
}
// clear selections
pDoc->m_selPolygonSelection.Clear();
pDoc->m_selVertexSelection.Clear();
// apply triangularisation
pDoc->m_woWorld.TriangularizePolygons( dcPolygons);
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnUpdateTriangularizeSelection(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
pCmdUI->Enable(pDoc->m_selPolygonSelection.Count()!=0);
}
void CWorldEditorView::OnPopupAutoFitMapping()
{
if(m_pbpoRightClickedPolygon != NULL)
{
AutoFitMapping( m_pbpoRightClickedPolygon);
}
}
void CWorldEditorView::OnPopupAutoFitMappingSmall()
{
if(m_pbpoRightClickedPolygon != NULL)
{
AutoFitMapping( m_pbpoRightClickedPolygon, TRUE);
}
}
void CWorldEditorView::OnPopupAutoFitMappingBoth()
{
if(m_pbpoRightClickedPolygon != NULL)
{
AutoFitMapping( m_pbpoRightClickedPolygon, TRUE, TRUE);
}
}
void CWorldEditorView::ApplyDefaultMapping(CBrushPolygon *pbpo, BOOL bRotation, BOOL bOffset, BOOL bStretch)
{
if(m_pbpoRightClickedPolygon == NULL) return;
CWorldEditorDoc* pDoc = GetDocument();
// if is selected
if( m_pbpoRightClickedPolygon->IsSelected(BPOF_SELECTED))
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
CBrushPolygon &po=*itbpo;
CMappingDefinition &md=po.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
CMappingDefinitionUI mdui;
md.ToUI(mdui);
if( bRotation)
{
mdui.mdui_aURotation=0.0f;
mdui.mdui_aVRotation=0.0f;
}
if( bStretch)
{
mdui.mdui_fUStretch = 1.0f;
mdui.mdui_fVStretch = 1.0f;
}
if( bOffset)
{
mdui.mdui_fUOffset = 0.0f;
mdui.mdui_fVOffset = 0.0f;
}
md.FromUI(mdui);
}
}
else
{
CMappingDefinition &md=m_pbpoRightClickedPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
CMappingDefinitionUI mdui;
md.ToUI(mdui);
if( bRotation)
{
mdui.mdui_aURotation=0.0f;
mdui.mdui_aVRotation=0.0f;
}
if( bStretch)
{
mdui.mdui_fUStretch = 1.0f;
mdui.mdui_fVStretch = 1.0f;
}
if( bOffset)
{
mdui.mdui_fUOffset = 0.0f;
mdui.mdui_fVOffset = 0.0f;
}
md.FromUI(mdui);
}
}
void CWorldEditorView::OnResetMappingOffset()
{
ApplyDefaultMapping( m_pbpoRightClickedPolygon, FALSE, TRUE, FALSE);
}
void CWorldEditorView::OnResetMappingRotation()
{
ApplyDefaultMapping( m_pbpoRightClickedPolygon, TRUE, FALSE, FALSE);
}
void CWorldEditorView::OnResetMappingStretch()
{
ApplyDefaultMapping( m_pbpoRightClickedPolygon, FALSE, FALSE, TRUE);
}
void CWorldEditorView::ShowLinkTree(CEntity *pen, BOOL bWhoTargets/*=FALSE*/, BOOL bPropertyNames/*=FALSE*/)
{
CWorldEditorDoc* pDoc = GetDocument();
CPoint ptScr=m_ptMouse;
ClientToScreen( &ptScr);
if( pen!=NULL || (pDoc->m_selEntitySelection.Count() != 0))
{
CDlgLinkTree dlg( pen, ptScr, bWhoTargets, bPropertyNames);
dlg.DoModal();
}
}
void CWorldEditorView::OnCrossroadForL()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == ENTITY_MODE)
{
ShowLinkTree(NULL);
}
else if(pDoc->m_pwoSecondLayer != NULL)
{
pDoc->OnJoinLayers();
}
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
theApp.m_iTerrainEditMode=TEM_LAYER;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
}
void CWorldEditorView::OnSelectUsingTargetTree()
{
ShowLinkTree(m_penEntityHitOnContext);
}
void CWorldEditorView::OnTargetTree()
{
ShowLinkTree(NULL);
}
void CWorldEditorView::OnUpdateTargetTree(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
pCmdUI->Enable(pDoc->m_selEntitySelection.Count() != 0);
}
void SwapLayers( CBrushPolygon &bpo, INDEX il1, INDEX il2)
{
CBrushPolygonTexture bptTemp;
bptTemp.CopyTextureProperties(bpo.bpo_abptTextures[il1], TRUE);
bpo.bpo_abptTextures[il1].CopyTextureProperties(bpo.bpo_abptTextures[il2], TRUE);
bpo.bpo_abptTextures[il2].CopyTextureProperties(bptTemp, TRUE);
}
void CWorldEditorView::OnSwapLayers12()
{
CWorldEditorDoc* pDoc = GetDocument();
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
SwapLayers( *itbpo, 0, 1);
}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnSwapLayers23()
{
CWorldEditorDoc* pDoc = GetDocument();
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
SwapLayers( *itbpo, 1, 2);
}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnSelectDescendants()
{
CWorldEditorDoc* pDoc = GetDocument();
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
SelectDescendents( pDoc->m_selEntitySelection, *iten);
}
pDoc->m_chSelections.MarkChanged();
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnRotateToTargetOrigin()
{
if(m_penEntityHitOnContext != NULL)
{
CWorldEditorDoc* pDoc = GetDocument();
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
const CPlacement3D &plDst=iten->GetPlacement();
const CPlacement3D &plSrc=m_penEntityHitOnContext->GetPlacement();
FLOAT3D vDir=plSrc.pl_PositionVector-plDst.pl_PositionVector;
vDir.Normalize();
ANGLE3D ang;
DirectionVectorToAngles(vDir, ang);
CPlacement3D plNew=plDst;
plNew.pl_OrientationAngle=ang;
iten->SetPlacement(plNew);
}
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
}
void CWorldEditorView::OnRotateToTargetCenter()
{
if(m_penEntityHitOnContext != NULL)
{
CWorldEditorDoc* pDoc = GetDocument();
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
const CPlacement3D &plDst=iten->GetPlacement();
FLOATaabbox3D box;
m_penEntityHitOnContext->GetSize(box);
FLOAT3D vTarget=box.Center();
FLOAT3D vDir=vTarget-plDst.pl_PositionVector;
vDir.Normalize();
ANGLE3D ang;
DirectionVectorToAngles(vDir, ang);
CPlacement3D plNew=plDst;
plNew.pl_OrientationAngle=ang;
iten->SetPlacement(plNew);
}
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
}
void CWorldEditorView::OnCopyPlacement()
{
if(m_penEntityHitOnContext==NULL) return;
theApp.m_plClipboard2=m_penEntityHitOnContext->GetPlacement();
}
void CWorldEditorView::OnCopyOrientation()
{
if(m_penEntityHitOnContext==NULL) return;
theApp.m_plClipboard1.pl_OrientationAngle=m_penEntityHitOnContext->GetPlacement().pl_OrientationAngle;
}
void CWorldEditorView::OnCopyPosition()
{
if(m_penEntityHitOnContext==NULL) return;
theApp.m_plClipboard1.pl_PositionVector=m_penEntityHitOnContext->GetPlacement().pl_PositionVector;
}
void CWorldEditorView::OnPastePlacement()
{
CWorldEditorDoc* pDoc = GetDocument();
if(m_penEntityHitOnContext==NULL) return;
if( m_penEntityHitOnContext->IsSelected(ENF_SELECTED))
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
iten->SetPlacement(theApp.m_plClipboard2);
}
}
else
{
m_penEntityHitOnContext->SetPlacement(theApp.m_plClipboard2);
}
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnPasteOrientation()
{
CWorldEditorDoc* pDoc = GetDocument();
if(m_penEntityHitOnContext==NULL) return;
if( m_penEntityHitOnContext->IsSelected(ENF_SELECTED))
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
CPlacement3D pl=iten->GetPlacement();
pl.pl_OrientationAngle=theApp.m_plClipboard1.pl_OrientationAngle;
iten->SetPlacement(pl);
}
}
else
{
CPlacement3D pl=m_penEntityHitOnContext->GetPlacement();
pl.pl_OrientationAngle=theApp.m_plClipboard1.pl_OrientationAngle;
m_penEntityHitOnContext->SetPlacement(pl);
}
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnPastePosition()
{
CWorldEditorDoc* pDoc = GetDocument();
if(m_penEntityHitOnContext==NULL) return;
if( m_penEntityHitOnContext->IsSelected(ENF_SELECTED))
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
CPlacement3D pl=iten->GetPlacement();
pl.pl_PositionVector=theApp.m_plClipboard1.pl_PositionVector;
iten->SetPlacement(pl);
}
}
else
{
CPlacement3D pl=m_penEntityHitOnContext->GetPlacement();
pl.pl_PositionVector=theApp.m_plClipboard1.pl_PositionVector;
m_penEntityHitOnContext->SetPlacement(pl);
}
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::Align(BOOL bX,BOOL bY,BOOL bZ,BOOL bH,BOOL bP,BOOL bB)
{
CWorldEditorDoc* pDoc = GetDocument();
INDEX ctSelected=pDoc->m_woWorld.wo_cenEntities.Count();
CEntity *penLast=NULL;
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
penLast=&*iten;
}}
CPlacement3D penSrc=penLast->GetPlacement();
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
CPlacement3D pl=iten->GetPlacement();
if( bX) {pl.pl_PositionVector(1)=penSrc.pl_PositionVector(1);};
if( bY) {pl.pl_PositionVector(2)=penSrc.pl_PositionVector(2);};
if( bZ) {pl.pl_PositionVector(3)=penSrc.pl_PositionVector(3);};
if( bH) {pl.pl_OrientationAngle(1)=penSrc.pl_OrientationAngle(1);};
if( bP) {pl.pl_OrientationAngle(2)=penSrc.pl_OrientationAngle(2);};
if( bB) {pl.pl_OrientationAngle(3)=penSrc.pl_OrientationAngle(3);};
iten->SetPlacement(pl);
}}
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnAlignB()
{
Align(FALSE,FALSE,FALSE,FALSE,FALSE,TRUE);
}
void CWorldEditorView::OnAlignH()
{
Align(FALSE,FALSE,FALSE,TRUE,FALSE,FALSE);
}
void CWorldEditorView::OnAlignP()
{
Align(FALSE,FALSE,FALSE,FALSE,TRUE,FALSE);
}
void CWorldEditorView::OnAlignX()
{
Align(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE);
}
void CWorldEditorView::OnAlignY()
{
Align(FALSE,TRUE,FALSE,FALSE,FALSE,FALSE);
}
void CWorldEditorView::OnAlignZ()
{
Align(FALSE,FALSE,TRUE,FALSE,FALSE,FALSE);
}
struct CameraProjectionInfo {
FLOAT cpi_fOffsetRatioX;
FLOAT cpi_fOffsetRatioY;
FLOAT cpi_fOffsetRatioZ;
ANGLE cpi_angH;
ANGLE cpi_angP;
ANGLE cpi_angB;
double cpi_rMinI;
double cpi_rMinJ;
double cpi_rSizeI;
double cpi_rSizeJ;
};
CameraProjectionInfo *_pacpi=NULL;
INDEX _ctProjections=0;
CameraProjectionInfo acpiF[] =
{
{ 0, 0, 1, 0, 0, 0, 0, 0, 1, 1}
};
CameraProjectionInfo acpi2x2[] =
{
{ 0, 0, 1, 0, 0, 0, 0, 0, 0.5, 0.5},
{ 1, 0, 0, 90, 0, 0, 0.5, 0, 0.5, 0.5},
{ 0, 0, -1, 180, 0, 0, 0, 0.5, 0.5, 0.5},
{-1, 0, 0, 270, 0, 0, 0.5, 0.5, 0.5, 0.5}
};
CameraProjectionInfo acpi3x2[] =
{
{ 0, 0, 1, 0, 0, 0, 0, 0, 0.3, 0.3},
{ 1, 0, 0, 90, 0, 0, 0.3, 0, 0.3, 0.3},
{ 0, 0, -1, 180, 0, 0, 0.6, 0, 0.3, 0.3},
{-1, 0, 0, 270, 0, 0, 0, 0.3, 0.3, 0.3},
{ 0, 1, 0, 0,-90, 0, 0.3, 0.3, 0.3, 0.3},
{ 0,-1, 0, 0, 90, 0, 0.6, 0.3, 0.3, 0.3},
};
// setup viewing parameters for saving pretender textures
void SetupView(INDEX iFrame, CDrawPort *pdp, CAnyProjection3D &apr, FLOATaabbox3D box)
{
// init projection parameters
CIsometricProjection3D prIsometricProjection;
prIsometricProjection.ScreenBBoxL() = FLOATaabbox2D(
FLOAT2D(0.0f, 0.0f),
FLOAT2D((FLOAT)pdp->GetWidth(), (FLOAT)pdp->GetHeight())
);
prIsometricProjection.NearClipDistanceL() = 0.0f;
// determine far clip plane
FLOAT3D vSize=box.Size();
FLOAT3D vHSize=vSize/2.0f;
FLOAT3D vRatio=FLOAT3D(
_pacpi[iFrame].cpi_fOffsetRatioX,
_pacpi[iFrame].cpi_fOffsetRatioY,
_pacpi[iFrame].cpi_fOffsetRatioZ);
ANGLE3D ang=ANGLE3D(
_pacpi[iFrame].cpi_angH,
_pacpi[iFrame].cpi_angP,
_pacpi[iFrame].cpi_angB);
FLOAT fFCD=Max(
Abs(vRatio(1))*vSize(1), Max(
Abs(vRatio(2))*vSize(2),
Abs(vRatio(3))*vSize(3)));
prIsometricProjection.FarClipDistanceL() = fFCD;
prIsometricProjection.AspectRatioL() = 1.0f;
// set up viewer position
apr = prIsometricProjection;
FLOAT3D vPos=FLOAT3D(
vRatio(1)*vHSize(1),
vRatio(2)*vHSize(2),
vRatio(3)*vHSize(3))+box.Center();
FLOAT fMaxSize;
if( vRatio(1)!=0)
{
fMaxSize=Max(vSize(2),vSize(3));
}
else if( vRatio(2)!=0)
{
fMaxSize=Max(vSize(1),vSize(3));
}
else
{
fMaxSize=Max(vSize(1),vSize(2));
}
prIsometricProjection.ZoomFactorL()=pdp->GetWidth()/fMaxSize;
CPlacement3D plViewer=CPlacement3D(vPos, ang);
//plViewer.RelativeToAbsolute(plEntity);
apr=prIsometricProjection;
apr->ViewerPlacementL() = plViewer;
apr->ObjectPlacementL() = CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0));
apr->Prepare();
}
BOOL CWorldEditorView::SaveAutoTexture(FLOATaabbox3D boxBrush, CTFileName &fnTex)
{
CWorldEditorDoc* pDoc = GetDocument();
CDlgAutTexturize dlg;
if( dlg.DoModal()!=IDOK) return FALSE;
// call file requester for pretender texture name
CTFileName fnPretenderTexture = _EngineGUI.FileRequester( "Pretender texture name",
FILTER_TGA FILTER_END, "Auto save texture", "", "", NULL, TRUE);
if( fnPretenderTexture == "") return FALSE;
switch( dlg.m_iPretenderStyle)
{
case 0: _pacpi=acpiF; _ctProjections=1; break;
case 1: _pacpi=acpi2x2; _ctProjections=4; break;
case 2: _pacpi=acpi3x2; _ctProjections=6; break;
default: _pacpi=acpi3x2; _ctProjections=6; break;
}
CDrawPort *pdp;
CImageInfo II;
CTextureData TD;
CAnimData AD;
ULONG flags = NONE;
CChildFrame *pChild = GetChildFrame();
// create canvas to render picture
_pGfx->CreateWorkCanvas( dlg.m_pixWidth, dlg.m_pixHeight, &pdp);
if( pdp != NULL)
{
FLOAT3D vSize=boxBrush.Size();
for(INDEX iFrame=0; iFrame<_ctProjections; iFrame++)
{
CameraProjectionInfo &cpi=_pacpi[iFrame];
CDrawPort dpClone( pdp, cpi.cpi_rMinI, cpi.cpi_rMinJ, cpi.cpi_rSizeI, cpi.cpi_rSizeJ);
// clone draw port
if( dpClone.Lock())
{
dpClone.FillZBuffer(ZBUF_BACK);
CAnyProjection3D apr;
SetupView(iFrame, &dpClone, apr, boxBrush);
// store rendering preferences
BOOL bWasBcgOn = _wrpWorldRenderPrefs.IsBackgroundTextureOn();
CWorldRenderPrefs::SelectionType stBefore=_wrpWorldRenderPrefs.GetSelectionType();
_wrpWorldRenderPrefs.SetBackgroundTextureOn( FALSE);
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_NONE);
COLOR colOld=pDoc->m_woWorld.GetBackgroundColor();
pDoc->m_woWorld.SetBackgroundColor(dlg.m_colBcg.GetColor());
// render view
::RenderView(pDoc->m_woWorld, *(CEntity*)NULL, apr, dpClone);
// restore rendering preferences
pDoc->m_woWorld.SetBackgroundColor(colOld);
_wrpWorldRenderPrefs.SetSelectionType(stBefore);
_wrpWorldRenderPrefs.SetBackgroundTextureOn( bWasBcgOn);
}
dpClone.Unlock();
}
pdp->GrabScreen( II, 2);
if( dlg.m_bExpandEdges)
{
II.ExpandEdges();
}
// try to
try {
// save screen shot as TGA
II.SaveTGA_t( fnPretenderTexture);
fnTex=fnPretenderTexture.NoExt()+".tex";
// create temporary texture
CreateTexture_t( fnPretenderTexture, fnTex,
dlg.m_pixWidth, MAX_MEX_LOG2+1, FALSE);
_EngineGUI.CreateTexture( fnTex);
} // if failed
catch (char *strError) {
// report error
AfxMessageBox(CString(strError));
}
}
return TRUE;
}
INDEX _aiMinMax[] =
{
0,0,1,
1,0,1,
1,0,0,
0,0,0,
0,1,1,
1,1,1,
1,1,0,
0,1,0
};
INDEX _aiPlaneVtx[] =
{
4,0,1,5,
5,1,2,6,
6,2,3,7,
7,3,0,4,
7,4,5,6,
0,3,2,1,
};
FLOAT3D _avBoxVtx[8];
struct BoxPlaneParams {
FLOATplane3D bpp_plPlane;
CMappingVectors bpp_mvDefault;
CMappingVectors bpp_mvVectors;
CMappingDefinition bpp_mdMappingDefinition;
};
BoxPlaneParams _abpp[6];
BOOL CWorldEditorView::SetAutoTextureBoxParams(FLOATaabbox3D boxBrush, CTFileName &fnTex)
{
CTextureData *pTD=NULL;
try
{
pTD=_pTextureStock->Obtain_t( fnTex);
}
catch (char *strError)
{
WarningMessage(strError);
return FALSE;
}
// create box vertices
FLOAT3D vMin=boxBrush.Min();
FLOAT3D vMax=boxBrush.Max();
FLOAT3D vSize=boxBrush.Size();
for( INDEX iVtx=0; iVtx<8; iVtx++)
{
FLOAT fX=_aiMinMax[iVtx*3+0]*vSize(1)+vMin(1);
FLOAT fY=_aiMinMax[iVtx*3+1]*vSize(2)+vMin(2);
FLOAT fZ=_aiMinMax[iVtx*3+2]*vSize(3)+vMin(3);
_avBoxVtx[iVtx]=FLOAT3D(fX,fY,fZ);
}
// create box planes
for( INDEX iPlane=0; iPlane<_ctProjections; iPlane++)
{
CameraProjectionInfo &cpi=_pacpi[iPlane];
// create plane
BoxPlaneParams &bpp=_abpp[iPlane];
FLOAT3D &vVtx0=_avBoxVtx[_aiPlaneVtx[iPlane*4+0]];
FLOAT3D &vVtx1=_avBoxVtx[_aiPlaneVtx[iPlane*4+1]];
FLOAT3D &vVtx2=_avBoxVtx[_aiPlaneVtx[iPlane*4+2]];
FLOAT3D &vVtx3=_avBoxVtx[_aiPlaneVtx[iPlane*4+3]];
bpp.bpp_plPlane=FLOATplane3D(vVtx0, vVtx1, vVtx2);
// create mapping vectors
bpp.bpp_mvDefault.FromPlane(bpp.bpp_plPlane);
bpp.bpp_mvVectors.mv_vO=(vVtx0+vVtx2)/2.0f;
FLOAT3D vDeltaU=vVtx3-vVtx0;
FLOAT3D vDeltaV=vVtx1-vVtx0;
FLOAT fStretch = Max(vDeltaU.Length(), vDeltaV.Length())/(pTD->GetWidth()/1024.0f*cpi.cpi_rSizeI);
bpp.bpp_mvVectors.mv_vU=vDeltaU.Normalize()*fStretch;
bpp.bpp_mvVectors.mv_vV=vDeltaV.Normalize()*fStretch;
bpp.bpp_mdMappingDefinition.FromMappingVectors(bpp.bpp_mvDefault, bpp.bpp_mvVectors);
MEX mexOffsetU = pTD->GetWidth() *(cpi.cpi_rMinI+cpi.cpi_rSizeI/2);
MEX mexOffsetV = pTD->GetHeight()*(cpi.cpi_rMinJ+cpi.cpi_rSizeJ/2);
bpp.bpp_mdMappingDefinition.md_fUOffset-=mexOffsetU/1024.0f;
bpp.bpp_mdMappingDefinition.md_fVOffset-=mexOffsetV/1024.0f;
}
return TRUE;
}
void CWorldEditorView::AutoApplyTextureOntoPolygon(CBrushPolygon &bpo, FLOATaabbox3D boxBrush, CTFileName &fnTex)
{
// get box polygon that has smallest scalar product with our polygon
FLOAT fMaxScalar=-1e6f;
INDEX iMaxPlane=0;
FLOATplane3D &plPlaneAbs=bpo.bpo_pbplPlane->bpl_plAbsolute;
FLOATplane3D &plPlaneRel=bpo.bpo_pbplPlane->bpl_plRelative;
for(INDEX iPlane=0; iPlane<6; iPlane++)
{
BoxPlaneParams &bpp=_abpp[iPlane];
FLOAT fScalar=plPlaneAbs%bpp.bpp_plPlane;
if( fScalar>fMaxScalar)
{
iMaxPlane=iPlane;
fMaxScalar=fScalar;
}
}
BoxPlaneParams &bpp=_abpp[iMaxPlane];
CBrushPolygonTexture &bbpt0=bpo.bpo_abptTextures[0];
CBrushPolygonTexture &bbpt1=bpo.bpo_abptTextures[1];
CBrushPolygonTexture &bbpt2=bpo.bpo_abptTextures[2];
try
{
bbpt0.CopyTextureProperties(CBrushPolygonTexture(),TRUE);
bbpt0.bpt_toTexture.SetData_t(fnTex);
bbpt1.bpt_toTexture.SetData(NULL);
bbpt2.bpt_toTexture.SetData(NULL);
// get the mapping in relative space of the brush polygon's entity
CEntity *pen = bpo.bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
CSimpleProjection3D pr;
pr.ObjectPlacementL() = _plOrigin;
pr.ViewerPlacementL() = pen->GetPlacement();
pr.Prepare();
FLOATplane3D plRelative;
pr.Project(bpp.bpp_plPlane, plRelative);
CMappingDefinition mdRelative = bpp.bpp_mdMappingDefinition;
mdRelative.Transform(bpp.bpp_plPlane, _plOrigin, pen->GetPlacement());
bbpt0.bpt_mdMapping.ProjectMapping(plRelative, mdRelative, plPlaneRel);
bpo.bpo_ulFlags |= BPOF_FULLBRIGHT;
bpo.bpo_smShadowMap.Uncache();
bpo.DiscardShadows();
}
catch (char *strError)
{
WarningMessage(strError);
}
}
void CWorldEditorView::AutoApplyTexture(FLOATaabbox3D boxBrush, CTFileName &fnTex)
{
if( !SetAutoTextureBoxParams(boxBrush, fnTex)) return;
CWorldEditorDoc* pDoc = GetDocument();
// textureize mip levels
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
CEntity *pen=&*iten;
if( pen->GetRenderType() == CEntity::RT_BRUSH)
{
CBrush3D *pbrBrush=pen->GetBrush();
// for each mip in the brush
BOOL bFirstMip=TRUE;
FOREACHINLIST(CBrushMip, bm_lnInBrush, pbrBrush->br_lhBrushMips, itbm)
{
if( bFirstMip)
{
bFirstMip=FALSE;
continue;
}
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
// for each polygon in sector
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo) {
CBrushPolygon &bpo = *itbpo;
AutoApplyTextureOntoPolygon(bpo, boxBrush, fnTex);
}
}
}
}
}
}
void CWorldEditorView::OnAutotexturizeMips()
{
CWorldEditorDoc* pDoc = GetDocument();
FLOATaabbox3D boxBrush;
// for each entity in the world
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
CEntity *pen=&*iten;
if( pen->GetRenderType() == CEntity::RT_BRUSH)
{
CBrush3D *pbrBrush=pen->GetBrush();
CBrushMip *pbrMip=pbrBrush->GetFirstMip();
boxBrush|=pbrMip->bm_boxBoundingBox;
}
}}
CTFileName fnTex;
BOOL bSuccess=SaveAutoTexture( boxBrush, fnTex);
if( !bSuccess) return;
AutoApplyTexture( boxBrush, fnTex);
// mark that selections have been changed
pDoc->UpdateAllViews( NULL);
pDoc->SetModifiedFlag();
}
void CWorldEditorView::OnUpdateAutotexturizeMips(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
pCmdUI->Enable(pDoc->m_selEntitySelection.Count()!=0);
}
void CWorldEditorView::OnRandomOffsetU()
{
CWorldEditorDoc* pDoc = GetDocument();
// for each selected polygon
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
CTextureData *pTD = (CTextureData *) itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.GetData();
if( pTD != NULL)
{
// add rnd offsets to mapping
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fUOffset+=((FLOAT)rand())/RAND_MAX*pTD->GetWidth();
}
}
}
void CWorldEditorView::OnRandomOffsetV()
{
CWorldEditorDoc* pDoc = GetDocument();
// for each selected polygon
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
CTextureData *pTD = (CTextureData *) itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.GetData();
if( pTD != NULL)
{
// add rnd offsets to mapping
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fVOffset+=((FLOAT)rand())/RAND_MAX*pTD->GetHeight();
}
}
}
void CWorldEditorView::OnStretchRelativeOffset()
{
CWorldEditorDoc* pDoc = GetDocument();
if(m_penEntityHitOnContext==NULL) return;
CDlgStretchChildOffset dlg;
if( dlg.DoModal()!=IDOK) return;
if( m_penEntityHitOnContext->IsSelected(ENF_SELECTED))
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
if( iten->GetParent()!=NULL)
{
CPlacement3D pl=iten->GetPlacement();
CPlacement3D plParent=iten->GetParent()->GetPlacement();
pl.AbsoluteToRelative(plParent);
FLOAT3D vRelPos=pl.pl_PositionVector;
vRelPos*=dlg.m_fStretchValue;
// set stretched offset
pl.pl_PositionVector=vRelPos;
pl.RelativeToAbsolute(plParent);
iten->SetPlacement(pl);
}
}
}
else
{
if( m_penEntityHitOnContext->GetParent()!=NULL)
{
CPlacement3D pl=m_penEntityHitOnContext->GetPlacement();
CPlacement3D plParent=m_penEntityHitOnContext->GetParent()->GetPlacement();
pl.AbsoluteToRelative(plParent);
FLOAT3D vRelPos=pl.pl_PositionVector;
vRelPos*=dlg.m_fStretchValue;
// set stretched offset
pl.pl_PositionVector=vRelPos;
pl.RelativeToAbsolute(plParent);
m_penEntityHitOnContext->SetPlacement(pl);
}
}
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnDeselectHidden()
{
CWorldEditorDoc* pDoc = GetDocument();
// for all of the world's entities
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
// if the entity is hidden and selected
if (iten->en_ulFlags&ENF_HIDDEN && iten->IsSelected( ENF_SELECTED))
{
// deselect it
pDoc->m_selEntitySelection.Deselect( *iten);
}
}
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnSelectHidden()
{
CWorldEditorDoc* pDoc = GetDocument();
// for all of the world's entities
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
// if the entity is hidden and selected
if (iten->en_ulFlags&ENF_HIDDEN && !iten->IsSelected( ENF_SELECTED))
{
// select it
pDoc->m_selEntitySelection.Select( *iten);
}
}
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnSectorsToBrush()
{
CBrushPolygonSelection selPolygons;
CWorldEditorDoc* pDoc = GetDocument();
if(pDoc->m_selSectorSelection.Count()==0) return;
pDoc->RememberUndo();
pDoc->ClearSelections(ST_SECTOR);
// make polygon selection
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
{
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
{
selPolygons.Select( *itbpo);
}
}
PolygonsToBrush(selPolygons, FALSE, TRUE);
selPolygons.CDynamicContainer<CBrushPolygon>::Clear();
}
void CWorldEditorView::PolygonsToBrush(CBrushPolygonSelection &selPolygons, BOOL bDeleteSectors, BOOL bZoning)
{
CWorldEditorDoc* pDoc = GetDocument();
FLOATaabbox3D boxPolygons;
// get bbox of selected polygons
FOREACHINDYNAMICCONTAINER(selPolygons, CBrushPolygon, itbpo)
{
boxPolygons |= itbpo->bpo_boxBoundingBox;
}
CPlacement3D plCenterDown=CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0));
plCenterDown.pl_PositionVector=FLOAT3D(boxPolygons.Center()(1),boxPolygons.Min()(2),boxPolygons.Center()(3));
CEntity *penwb=theApp.CreateWorldBaseEntity(pDoc->m_woWorld, bZoning, plCenterDown);
if( penwb==NULL) return;
pDoc->m_woWorld.CopyPolygonsToBrush(selPolygons, penwb);
if(bDeleteSectors)
{
// delete old sectors
pDoc->m_woWorld.DeleteSectors( pDoc->m_selSectorSelection, FALSE);
}
pDoc->ClearSelections();
pDoc->m_chSelections.MarkChanged();
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnPolygonsToBrush()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->m_selPolygonSelection.Count()==0) return;
pDoc->RememberUndo();
CDynamicContainer<CBrushPolygon> dcPolygons;
StorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
PolygonsToBrush(pDoc->m_selPolygonSelection, FALSE, FALSE);
pDoc->m_woWorld.DeletePolygons(dcPolygons);
}
void CWorldEditorView::OnClonePolygons()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->m_selPolygonSelection.Count()==0) return;
pDoc->RememberUndo();
PolygonsToBrush(pDoc->m_selPolygonSelection, FALSE, FALSE);
}
void CWorldEditorView::OnDeletePolygons()
{
CDynamicContainer<CBrushPolygon> dcPolygons;
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->m_selPolygonSelection.Count()==0) return;
pDoc->RememberUndo();
StorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
pDoc->ClearSelections();
pDoc->m_woWorld.DeletePolygons(dcPolygons);
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnKeyU()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == POLYGON_MODE)
{
OnKeyPasteAsProjected();
}
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
theApp.m_iTerrainEditMode=TEM_HEIGHTMAP;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
}
void CWorldEditorView::OnKeyD()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == ENTITY_MODE)
{
OnDropMarker();
}
if( (pDoc->GetEditingMode() == POLYGON_MODE) ||
(pDoc->GetEditingMode() == VERTEX_MODE) )
{
OnFlipPolygon();
}
if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
theApp.m_iTerrainBrushMode=TBM_ERASE;
theApp.m_ctTerrainPageCanvas.MarkChanged();
pDoc->SetStatusLineModeInfoMessage();
}
}
void CWorldEditorView::OnFlipPolygon()
{
CWorldEditorDoc* pDoc = GetDocument();
BOOL bSelection=TRUE;
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse, FALSE, FALSE, FALSE);
CBrushPolygon *pbpoHit=crRayHit.cr_pbpoBrushPolygon;
if( (pbpoHit!=NULL) && !pbpoHit->IsSelected( BPOF_SELECTED) )
{
bSelection=FALSE;
}
CDynamicContainer<CBrushPolygon> dcPolygons;
CDynamicContainer<CBrushSector> dcSectors;
if( bSelection)
{
FOREACHINDYNAMICCONTAINER( pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
dcPolygons.Add( itbpo);
if( !dcSectors.IsMember(itbpo->bpo_pbscSector))
{
dcSectors.Add(itbpo->bpo_pbscSector);
}
}
}
else
{
pDoc->m_selPolygonSelection.Clear();
dcPolygons.Add( pbpoHit);
dcSectors.Add(pbpoHit->bpo_pbscSector);
}
pDoc->ClearSelections();
FOREACHINDYNAMICCONTAINER(dcPolygons, CBrushPolygon, itbpo)
{
CBrushPolygon &bpo = *itbpo;
pDoc->m_woWorld.FlipPolygon(bpo);
}
FOREACHINDYNAMICCONTAINER( dcSectors, CBrushSector, itbsc)
{
itbsc->UpdateSector();
}
{FOREACHINDYNAMICCONTAINER(dcPolygons, CBrushPolygon, itbpo)
{
CBrushPolygon &bpo = *itbpo;
INDEX iTriVtx=bpo.bpo_aiTriangleElements.Count();
INDEX tmpa=0;
}}
pDoc->SetModifiedFlag( TRUE);
pDoc->UpdateAllViews( NULL);
}
void CWorldEditorView::OnKeyM()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == POLYGON_MODE)
{
// obtain information about where mouse points into the world
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
// if we hit brush entity
if( (crRayHit.cr_penHit != NULL) &&
(crRayHit.cr_pbpoBrushPolygon != NULL) )
{
CopyMapping(crRayHit.cr_pbpoBrushPolygon);
}
}
else if( pDoc->GetEditingMode() == VERTEX_MODE)
{
OnMergeVertices();
}
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
theApp.m_iTerrainBrushMode=TBM_MINIMUM;
theApp.m_ctTerrainPageCanvas.MarkChanged();
pDoc->SetStatusLineModeInfoMessage();
}
}
void CWorldEditorView::OnSelectBrush()
{
CPoint ptMouse;
GetCursorPos( &ptMouse);
InvokeTerrainBrushPalette( ptMouse.x-BRUSH_PALETTE_WIDTH/2, ptMouse.y+BRUSH_PALETTE_HEIGHT/2);
}
void CWorldEditorView::OnSelectTerrain()
{
CWorldEditorDoc* pDoc = GetDocument();
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
if( (crRayHit.cr_penHit!=NULL) && (crRayHit.cr_penHit->GetRenderType() == CEntity::RT_TERRAIN) &&
(crRayHit.cr_penHit!=GetTerrainEntity()) )
{
pDoc->m_ptrSelectedTerrain=crRayHit.cr_penHit->GetTerrain();
theApp.m_ctTerrainPage.MarkChanged();
}
}
void CWorldEditorView::OnAltitudeEditMode()
{
theApp.m_iTerrainEditMode=TEM_HEIGHTMAP;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnLayerTextureEditMode()
{
theApp.m_iTerrainEditMode=TEM_LAYER;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnOptimizeTerrain()
{
OptimizeLayers();
}
void CWorldEditorView::OnRecalculateTerrainShadows()
{
CTerrain *ptrTerrain=GetTerrain();
if( ptrTerrain==NULL) return;
ptrTerrain->UpdateShadowMap();
}
void CWorldEditorView::OnViewHeightmap()
{
POINT pt;
GetCursorPos(&pt);
pt.x-=32;
pt.y+=32;
DisplayHeightMapWindow(pt);
}
void CWorldEditorView::OnImportHeightmap()
{
ApplyImportExport(0);
}
void CWorldEditorView::OnImportHeightmap16()
{
ApplyImportExport(1);
}
void CWorldEditorView::OnExportHeightmap()
{
ApplyImportExport(2);
}
void CWorldEditorView::OnExportHeightmap16()
{
ApplyImportExport(3);
}
void CWorldEditorView::OnSelectLayer()
{
InvokeSelectLayerCombo();
}
void CWorldEditorView::OnPickLayer()
{
CWorldEditorDoc* pDoc = GetDocument();
CCastRay crRayHit=GetMouseHitInformation( m_ptMouse);
if( (crRayHit.cr_penHit!=NULL) && (crRayHit.cr_penHit->GetRenderType() == CEntity::RT_TERRAIN))
{
CTerrain *ptrTerrain=crRayHit.cr_penHit->GetTerrain();
Point pt=Calculate2dHitPoint(ptrTerrain, crRayHit.cr_vHit);
// in altitude mode
if(theApp.m_iTerrainEditMode==TEM_HEIGHTMAP)
{
// pick altitude
INDEX iWidth=ptrTerrain->tr_pixHeightMapWidth;
UWORD *puw=ptrTerrain->tr_auwHeightMap+iWidth*pt.pt_iY+pt.pt_iX;
theApp.m_uwEditAltitude=*puw;
}
// in layer mode
else
{
// pick layer
INDEX ctLayers=ptrTerrain->tr_atlLayers.Count();
for(INDEX iLayer=ctLayers-1; iLayer>=0; iLayer--)
{
UBYTE ubPower=GetValueFromMask(ptrTerrain, iLayer, crRayHit.cr_vHit);
if(ubPower>0)
{
SelectLayer(iLayer);
CTerrainLayer *ptlLayer=&ptrTerrain->tr_atlLayers[iLayer];
if(ptlLayer->tl_ltType==LT_TILE)
{
CDynamicContainer<CTileInfo> dcTileInfo;
INDEX ctTilesPerRaw=0;
ObtainLayerTileInfo( &dcTileInfo, ptlLayer->tl_ptdTexture, ctTilesPerRaw);
INDEX ctTiles=dcTileInfo.Count();
for(INDEX iTile=0; iTile<ctTiles; iTile++)
{
CTileInfo &ti=dcTileInfo[iTile];
if( ((ubPower&TL_TILE_INDEX)==(ti.ti_iy*ptlLayer->tl_ctTilesInRow+ti.ti_ix) ) &&
(ubPower&TL_VISIBLE) &&
(!(ubPower&TL_FLIPX) == !ti.ti_bFlipX) &&
(!(ubPower&TL_FLIPY) == !ti.ti_bFlipY) &&
(!(ubPower&TL_SWAPXY) == !ti.ti_bSwapXY) )
{
ptlLayer->tl_iSelectedTile=iTile;
break;
}
}
}
else
{
theApp.m_ctTerrainPageCanvas.MarkChanged();
}
break;
}
}
}
}
}
void CWorldEditorView::OnIdle(void)
{
POINT point;
GetCursorPos(&point);
HWND hwndUnderMouse = ::WindowFromPoint(point);
if( ::GetParent(hwndUnderMouse)==m_hWnd)
{
UpdateCursor();
}
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode()==TERRAIN_MODE && m_iaInputAction==IA_NONE)
{
UpdateLayerDistribution();
}
}
void CWorldEditorView::OnPosterize()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
theApp.m_iTerrainBrushMode=TBM_POSTERIZE;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
}
void CWorldEditorView::OnFlatten()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode() == TERRAIN_MODE)
{
theApp.m_iTerrainBrushMode=TBM_FLATTEN;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
}
void CWorldEditorView::OnApplyFilter()
{
ApplyFilterOntoTerrain();
}
void CWorldEditorView::OnTeSmooth()
{
ApplySmoothOntoTerrain();
}
void CWorldEditorView::OnEditTerrainPrefs()
{
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CDlgTEOperationSettings dlg(pMainFrame);
dlg.DoModal();
}
void CWorldEditorView::OnUpdateEditTerrainPrefs(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
pCmdUI->Enable( pDoc->GetEditingMode()==TERRAIN_MODE);
}
void CWorldEditorView::OnKeyCtrlShiftG()
{
CWorldEditorDoc* pDoc = GetDocument();
if(pDoc->GetEditingMode()==TERRAIN_MODE)
{
RandomizeWhiteNoise();
ApplyGenerateTerrain();
}
else
{
GetChildFrame()->OnGridOnOff();
}
}
void CWorldEditorView::OnUpdateKeyCtrlShiftG(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
if(pDoc->GetEditingMode()==TERRAIN_MODE)
{
pCmdUI->Enable( TRUE);
}
else
{
GetChildFrame()->OnUpdateGridOnOff(pCmdUI);
}
}
void CWorldEditorView::OnTerrainLayerOptions()
{
CTerrainLayer *ptlLayer=GetLayer();
if(ptlLayer==NULL) return;
CDlgEditTerrainLayer dlg;
if( dlg.DoModal()==IDOK)
{
INDEX iLayer=GetLayerIndex();
GenerateLayerDistribution(iLayer);
}
}
void CWorldEditorView::OnUpdateTerrainLayerOptions(CCmdUI* pCmdUI)
{
CWorldEditorDoc* pDoc = GetDocument();
pCmdUI->Enable( pDoc->GetEditingMode()==TERRAIN_MODE);
}
void CWorldEditorView::OnApplyContinousNoise()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
{
ApplyContinousNoiseOntoTerrain();
}
}
void CWorldEditorView::OnApplyMinimum()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
{
ApplyMinimumOntoTerrain();
}
}
void CWorldEditorView::OnApplyMaximum()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
{
ApplyMaximumOntoTerrain();
}
}
void CWorldEditorView::OnApplyFlatten()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
{
ApplyFlattenOntoTerrain();
}
}
void CWorldEditorView::OnApplyPosterize()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
{
ApplyPosterizeOntoTerrain();
}
}
void CWorldEditorView::OnOptimizeLayers()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
{
OptimizeLayers();
}
}
void CWorldEditorView::OnTbrushAltitude()
{
theApp.m_iTerrainBrushMode=TBM_PAINT;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnTbrushSmooth()
{
theApp.m_iTerrainBrushMode=TBM_SMOOTH;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnTbrushEquilaze()
{
theApp.m_iTerrainBrushMode=TBM_FLATTEN;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnTbrushErase()
{
theApp.m_iTerrainBrushMode=TBM_ERASE;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnTbrushNoise()
{
theApp.m_iTerrainBrushMode=TBM_RND_NOISE;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnTbrushContinousNoise()
{
theApp.m_iTerrainBrushMode=TBM_CONTINOUS_NOISE;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnTbrushFilter()
{
theApp.m_iTerrainBrushMode=TBM_FILTER;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnTbrushFlatten()
{
theApp.m_iTerrainBrushMode=TBM_FLATTEN;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnTbrushMaximum()
{
theApp.m_iTerrainBrushMode=TBM_MAXIMUM;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnTbrushMinimum()
{
theApp.m_iTerrainBrushMode=TBM_MINIMUM;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnTbrushPosterize()
{
theApp.m_iTerrainBrushMode=TBM_POSTERIZE;
theApp.m_ctTerrainPageCanvas.MarkChanged();
GetDocument()->SetStatusLineModeInfoMessage();
}
void CWorldEditorView::OnTerrainProperties()
{
CWorldEditorDoc* pDoc = GetDocument();
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
{
CDlgTerrainProperties dlg;
dlg.DoModal();
}
}