/* 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 #include #include #include #include #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= 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; iKnotDrawLine(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 &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; iVtxProjectCoordinate( 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]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; iVtxProjectCoordinate( 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 &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; iVtxProjectCoordinate( 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) || ((fDistancem_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; iPropertydec_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; iLayer0) { 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; iVtxm_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 &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( ; iVtxm_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 &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; iVtxUpdateAllViews(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 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 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_tmStartStatusLineInfomessage==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 pressed if( bCtrl && !bLMB && !bRMB && !bShift) { STATUS_LINE_MESASGE( L"Use LMBx2 to teleport primitive. Try: LMB,RMB,LMB+RMB,Shift"); } //-------- commands for primitive // primitive mode, pressed else if( bCtrl && !bLMB && !bRMB && bShift) { STATUS_LINE_MESASGE( L"Size and shear primitive. Try: LMB,RMB"); } // primitive mode, pressed else if( bCtrl && bLMB && !bRMB && bShift) { STATUS_LINE_MESASGE( L"Resize primitive"); } // primitive mode, pressed else if( bCtrl && !bLMB && bRMB && bShift) { STATUS_LINE_MESASGE( L"Shear primitive"); } // primitive mode, pressed else if( bCtrl && bLMB && !bRMB && !bShift) { STATUS_LINE_MESASGE( L"Move primitive in view plane"); } // primitive mode, pressed else if( bCtrl && !bLMB && bRMB && !bShift) { STATUS_LINE_MESASGE( L"Move primitive in floor plane"); } // primitive mode, pressed else if( bCtrl && bLMB && bRMB && !bShift) { STATUS_LINE_MESASGE( L"Rotate primitive in view plane"); } // 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 { //-------- commands for template (moving and rotating) // template mode, only pressed if( bCtrl && !bLMB && !bRMB && !bShift) { STATUS_LINE_MESASGE( L"Use LMB dbl. click to teleport template. Try: LMB,RMB,LMB+RMB"); } // template mode, pressed else if( bCtrl && bLMB && !bRMB && !bShift) { STATUS_LINE_MESASGE( L"Move template in view plane"); } // template mode, pressed else if( bCtrl && !bLMB && bRMB && !bShift) { STATUS_LINE_MESASGE( L"Move template in floor plane"); } // template mode, 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, pressed if( bEditingProperties && bCtrl && bShift ) { STATUS_LINE_MESASGE( L"Use LMB to change range or direction"); } // 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, pressed else if( !bCtrl && bShift) { STATUS_LINE_MESASGE( L"Use LMB to toggle selection of one entity . Try: Ctrl,Space"); } // entity mode, 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, pressed else if( bCtrl && bLMB && !bRMB && !bShift) { STATUS_LINE_MESASGE( L"Move entities in view plane"); } // entity mode, pressed else if( bCtrl && !bLMB && bRMB && !bShift) { STATUS_LINE_MESASGE( L"Move entities in floor plane"); } // entity mode, 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, 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, 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, pressed else if( bCtrl && bLMB && !bRMB && !bShift && !bAlt) { STATUS_LINE_MESASGE( L"Scroll polygon's mapping texture"); } // polygon mode, 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, 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, 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 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 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, '�', 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", "������������������������������"); 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", "������������������������������"); } } } } 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 = ""; INDEX iContentType = pbscSector->GetContentType(); CTString strContentType = pDoc->m_woWorld.wo_actContentTypes[iContentType].ct_strName; if( strContentType == "") strContentType = ""; INDEX iEnvironmentType = pbscSector->GetEnvironmentType(); CTString strEnvironmentType = pDoc->m_woWorld.wo_aetEnvironmentTypes[iEnvironmentType].et_strName; if( strEnvironmentType == "") strEnvironmentType = ""; INDEX iForceType = pbscSector->GetForceType(); CBrush3D *pbrBrush = pbscSector->bsc_pbmBrushMip->bm_pbrBrush; CTString strForceType = pbrBrush->br_penEntity->GetForceName( iForceType); if( strForceType == "") strForceType = ""; 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���������������\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; iPropertydec_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 = ""; 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 = ""; 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 = ""; } 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(); CBrush3D &brBrush = *penBrush->en_pbrBrush; if (penBrush==NULL) return; // 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 &dcPolygons) { dcPolygons.Clear(); FOREACHINDYNAMICCONTAINER( selPolygons, CBrushPolygon, itbpo) { dcPolygons.Add( itbpo); } } void CWorldEditorView::RestorePolygonSelection(CBrushPolygonSelection &selPolygons, CDynamicContainer &dcPolygons) { selPolygons.Clear(); FOREACHINDYNAMICCONTAINER( dcPolygons, CBrushPolygon, itbpo) { selPolygons.Select( *itbpo); } } void CWorldEditorView::DiscardShadows( CEntity *penEntity) { CWorldEditorDoc* pDoc = GetDocument(); CDynamicContainer 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 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 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; iPropertydec_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; ibpebpl_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; ibpebpl_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 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; im_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 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; im_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 &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; iPropertydec_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 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 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 dcEntities; // for all classes in hierarchy of this entity for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase) { // for all properties for(INDEX iProperty=0; iPropertydec_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 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; iPropertydec_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; iKneeGetEditingMode()) { 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; iKneebpo_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 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 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 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; iYm_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 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( tmCurrentDeltaGetHighPrecisionTimer();*/ } 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=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(iLastTickTickQuantum)/_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(; ibpebpl_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; ibpefMaxV) { 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 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::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 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 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 dcPolygons; CDynamicContainer 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 dcTileInfo; INDEX ctTilesPerRaw=0; ObtainLayerTileInfo( &dcTileInfo, ptlLayer->tl_ptdTexture, ctTilesPerRaw); INDEX ctTiles=dcTileInfo.Count(); for(INDEX iTile=0; iTiletl_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(); } }