2016-03-12 01:20:51 +01:00
|
|
|
|
/* 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. */
|
2016-03-11 14:57:17 +01:00
|
|
|
|
|
|
|
|
|
// WorldEditorView.cpp : implementation of the CWorldEditorView class
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "WorldEditor.h"
|
|
|
|
|
#include <Engine/Base/Profiling.h>
|
|
|
|
|
#include <Engine/Base/Statistics.h>
|
|
|
|
|
#include <Engine/Templates/Stock_CTextureData.h>
|
|
|
|
|
#include <Engine/Terrain/TerrainEditing.h>
|
|
|
|
|
#include <Engine/Terrain/TerrainMisc.h>
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
#undef new
|
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
|
#undef THIS_FILE
|
|
|
|
|
static char THIS_FILE[] = __FILE__;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
CTimerValue _tvLastTerrainBrushingApplied;
|
|
|
|
|
static INDEX aiForCreationOfSizingVertices[14][6] =
|
|
|
|
|
{
|
|
|
|
|
{0,0,2,2,5,5},
|
|
|
|
|
{1,1,2,2,5,5},
|
|
|
|
|
{1,1,2,2,4,4},
|
|
|
|
|
{0,0,2,2,4,4},
|
|
|
|
|
{0,0,3,3,5,5},
|
|
|
|
|
{1,1,3,3,5,5},
|
|
|
|
|
{1,1,3,3,4,4},
|
|
|
|
|
{0,0,3,3,4,4},
|
|
|
|
|
{0,1,2,3,5,5},
|
|
|
|
|
{1,1,2,3,4,5},
|
|
|
|
|
{0,1,2,3,4,4},
|
|
|
|
|
{0,0,2,3,4,5},
|
|
|
|
|
{0,1,2,2,4,5},
|
|
|
|
|
{0,1,3,3,4,5},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static INDEX aiForAllowedSizing[14][6] =
|
|
|
|
|
{
|
|
|
|
|
{1,0,1,0,0,1},
|
|
|
|
|
{0,1,1,0,0,1},
|
|
|
|
|
{0,1,1,0,1,0},
|
|
|
|
|
{1,0,1,0,1,0},
|
|
|
|
|
{1,0,0,1,0,1},
|
|
|
|
|
{0,1,0,1,0,1},
|
|
|
|
|
{0,1,0,1,1,0},
|
|
|
|
|
{1,0,0,1,1,0},
|
|
|
|
|
{0,0,0,0,0,1},
|
|
|
|
|
{0,1,0,0,0,0},
|
|
|
|
|
{0,0,0,0,1,0},
|
|
|
|
|
{1,0,0,0,0,0},
|
|
|
|
|
{0,0,1,0,0,0},
|
|
|
|
|
{0,0,0,1,0,0},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// CWorldEditorView
|
|
|
|
|
|
|
|
|
|
IMPLEMENT_DYNCREATE(CWorldEditorView, CView)
|
|
|
|
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CWorldEditorView, CView)
|
|
|
|
|
//{{AFX_MSG_MAP(CWorldEditorView)
|
|
|
|
|
ON_WM_CREATE()
|
|
|
|
|
ON_WM_SIZE()
|
|
|
|
|
ON_WM_KILLFOCUS()
|
|
|
|
|
ON_WM_LBUTTONDOWN()
|
|
|
|
|
ON_WM_KEYDOWN()
|
|
|
|
|
ON_WM_KEYUP()
|
|
|
|
|
ON_WM_MOUSEMOVE()
|
|
|
|
|
ON_WM_RBUTTONDOWN()
|
|
|
|
|
ON_WM_LBUTTONUP()
|
|
|
|
|
ON_WM_RBUTTONUP()
|
|
|
|
|
ON_WM_DROPFILES()
|
|
|
|
|
ON_COMMAND(ID_ISOMETRIC_FRONT, OnIsometricFront)
|
|
|
|
|
ON_COMMAND(ID_ISOMETRIC_BACK, OnIsometricBack)
|
|
|
|
|
ON_COMMAND(ID_ISOMETRIC_BOTTOM, OnIsometricBottom)
|
|
|
|
|
ON_COMMAND(ID_ISOMETRIC_LEFT, OnIsometricLeft)
|
|
|
|
|
ON_COMMAND(ID_ISOMETRIC_RIGHT, OnIsometricRight)
|
|
|
|
|
ON_COMMAND(ID_ISOMETRIC_TOP, OnIsometricTop)
|
|
|
|
|
ON_COMMAND(ID_PERSPECTIVE, OnPerspective)
|
|
|
|
|
ON_COMMAND(ID_ZOOM_LESS, OnZoomLess)
|
|
|
|
|
ON_COMMAND(ID_ZOOM_MORE, OnZoomMore)
|
|
|
|
|
ON_COMMAND(ID_MOVE_DOWN, OnMoveDown)
|
|
|
|
|
ON_COMMAND(ID_MOVE_UP, OnMoveUp)
|
|
|
|
|
ON_WM_LBUTTONDBLCLK()
|
|
|
|
|
ON_COMMAND(ID_MEASUREMENT_TAPE, OnMeasurementTape)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_MEASUREMENT_TAPE, OnUpdateMeasurementTape)
|
|
|
|
|
ON_COMMAND(ID_CIRCLE_MODES, OnCircleModes)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_CIRCLE_MODES, OnUpdateCircleModes)
|
|
|
|
|
ON_COMMAND(ID_DESELECT_ALL, OnDeselectAll)
|
|
|
|
|
ON_COMMAND(ID_DELETE_ENTITIES, OnDeleteEntities)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_DELETE_ENTITIES, OnUpdateDeleteEntities)
|
|
|
|
|
ON_WM_SETCURSOR()
|
|
|
|
|
ON_COMMAND(ID_TAKE_SS, OnTakeSs)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_ENTITY_MODE, OnUpdateEntityMode)
|
|
|
|
|
ON_COMMAND(ID_SECTOR_MODE, OnSectorMode)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_SECTOR_MODE, OnUpdateSectorMode)
|
|
|
|
|
ON_COMMAND(ID_POLYGON_MODE, OnPolygonMode)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_POLYGON_MODE, OnUpdatePolygonMode)
|
|
|
|
|
ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
|
|
|
|
|
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
|
|
|
|
|
ON_COMMAND(ID_CLONE_CSG, OnCloneCSG)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_CLONE_CSG, OnUpdateCloneCsg)
|
|
|
|
|
ON_COMMAND(ID_MEASURE_ON, OnMeasureOn)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_MEASURE_ON, OnUpdateMeasureOn)
|
|
|
|
|
ON_COMMAND(ID_RESET_VIEWER, OnResetViewer)
|
|
|
|
|
ON_COMMAND(ID_COPY_TEXTURE, OnCopyTexture)
|
|
|
|
|
ON_COMMAND(ID_PASTE_TEXTURE, OnPasteTexture)
|
|
|
|
|
ON_COMMAND(ID_CENTER_ENTITY, OnCenterEntity)
|
|
|
|
|
ON_COMMAND(ID_FUNCTION, OnFunction)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_CENTER_ENTITY, OnUpdateCenterEntity)
|
|
|
|
|
ON_COMMAND(ID_DROP_MARKER, OnDropMarker)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_DROP_MARKER, OnUpdateDropMarker)
|
|
|
|
|
ON_COMMAND(ID_TEST_CONNECTIONS, OnTestConnections)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_TEST_CONNECTIONS, OnUpdateTestConnections)
|
|
|
|
|
ON_COMMAND(ID_ALIGN_VOLUME, OnAlignVolume)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_ALIGN_VOLUME, OnUpdateAlignVolume)
|
|
|
|
|
ON_COMMAND(ID_CURRENT_VIEW_PROPERTIES, OnCurrentViewProperties)
|
|
|
|
|
ON_COMMAND(ID_DELETE_MIP, OnDeleteMip)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_DELETE_MIP, OnUpdateDeleteMip)
|
|
|
|
|
ON_COMMAND(ID_PREVIOUS_MIP_BRUSH, OnPreviousMipBrush)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_PREVIOUS_MIP_BRUSH, OnUpdatePreviousMipBrush)
|
|
|
|
|
ON_COMMAND(ID_NEXT_MIP_BRUSH, OnNextMipBrush)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_NEXT_MIP_BRUSH, OnUpdateNextMipBrush)
|
|
|
|
|
ON_COMMAND(ID_CROSSROAD_FOR_C, OnCrossroadForC)
|
|
|
|
|
ON_COMMAND(ID_CHOOSE_COLOR, OnChooseColor)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_CHOOSE_COLOR, OnUpdateChooseColor)
|
|
|
|
|
ON_COMMAND(ID_MENU_COPY_MAPPING, OnMenuCopyMapping)
|
|
|
|
|
ON_COMMAND(ID_MENU_PASTE_MAPPING, OnMenuPasteMapping)
|
|
|
|
|
ON_COMMAND(ID_SET_AS_CSG_TARGET, OnSetAsCsgTarget)
|
|
|
|
|
ON_COMMAND(ID_KEY_PASTE, OnKeyPaste)
|
|
|
|
|
ON_WM_RBUTTONDBLCLK()
|
|
|
|
|
ON_COMMAND(ID_SELECT_BY_TEXTURE_ADJACENT, OnSelectByTextureAdjacent)
|
|
|
|
|
ON_COMMAND(ID_SELECT_BY_TEXTURE_IN_SECTOR, OnSelectByTextureInSector)
|
|
|
|
|
ON_COMMAND(ID_SELECT_BY_COLOR_IN_SECTOR, OnSelectByColorInSector)
|
|
|
|
|
ON_COMMAND(ID_CONUS_PRIMITIVE, OnConusPrimitive)
|
|
|
|
|
ON_COMMAND(ID_TORUS_PRIMITIVE, OnTorusPrimitive)
|
|
|
|
|
ON_COMMAND(ID_TERRAIN_PRIMITIVE, OnTerrainPrimitive)
|
|
|
|
|
ON_COMMAND(ID_SPHERE_PRIMITIVE, OnSpherePrimitive)
|
|
|
|
|
ON_COMMAND(ID_STAIRCASE_PRIMITIVE, OnStaircasePrimitive)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_CONUS_PRIMITIVE, OnUpdateConusPrimitive)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_SPHERE_PRIMITIVE, OnUpdateSpherePrimitive)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_TERRAIN_PRIMITIVE, OnUpdateTerrainPrimitive)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_TORUS_PRIMITIVE, OnUpdateTorusPrimitive)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_STAIRCASE_PRIMITIVE, OnUpdateStaircasePrimitive)
|
|
|
|
|
ON_COMMAND(ID_POPUP_CONUS, OnPopupConus)
|
|
|
|
|
ON_COMMAND(ID_POPUP_SPHERE, OnPopupSphere)
|
|
|
|
|
ON_COMMAND(ID_POPUP_STAIRS, OnPopupStairs)
|
|
|
|
|
ON_COMMAND(ID_POPUP_TERRAIN, OnPopupTerrain)
|
|
|
|
|
ON_COMMAND(ID_POPUP_TORUS, OnPopupTorus)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_MOVE_DOWN, OnUpdateMoveDown)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_MOVE_UP, OnUpdateMoveUp)
|
|
|
|
|
ON_COMMAND(ID_SELECT_LIGHTS, OnSelectLights)
|
|
|
|
|
ON_COMMAND(ID_DISCARD_SHADOWS, OnDiscardShadows)
|
|
|
|
|
ON_COMMAND(ID_COPY_SECTOR_AMBIENT, OnCopySectorAmbient)
|
|
|
|
|
ON_COMMAND(ID_PASTE_SECTOR_AMBIENT, OnPasteSectorAmbient)
|
|
|
|
|
ON_COMMAND(ID_SELECT_ALL_POLYGONS, OnSelectAllPolygons)
|
|
|
|
|
ON_COMMAND(ID_COPY_SECTORS, OnCopySectors)
|
|
|
|
|
ON_COMMAND(ID_DELETE_SECTORS, OnDeleteSectors)
|
|
|
|
|
ON_COMMAND(ID_PASTE_SECTORS, OnPasteSectors)
|
|
|
|
|
ON_COMMAND(ID_CENTER_BCG_VIEWER, OnCenterBcgViewer)
|
|
|
|
|
ON_COMMAND(ID_MENU_PASTE_AS_PROJECTED_MAPPING, OnMenuPasteAsProjectedMapping)
|
|
|
|
|
ON_COMMAND(ID_KEY_PASTE_AS_PROJECTED, OnKeyPasteAsProjected)
|
|
|
|
|
ON_COMMAND(ID_SELECT_ALL_ENTITIES, OnSelectAllEntitiesInSectors)
|
|
|
|
|
ON_COMMAND(ID_SELECT_ALL_SECTORS, OnSelectAllSectors)
|
|
|
|
|
ON_COMMAND(ID_LAST_PRIMITIVE, OnLastPrimitive)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_LAST_PRIMITIVE, OnUpdateLastPrimitive)
|
|
|
|
|
ON_COMMAND(ID_CLONE_TO_MORE_PRECISE_MIP, OnCloneToMorePreciseMip)
|
|
|
|
|
ON_COMMAND(ID_CLONE_TO_ROUGHER_MIP_LEVEL, OnCloneToRougherMipLevel)
|
|
|
|
|
ON_COMMAND(ID_CREATE_EMPTY_MORE_PRECISE_MIP, OnCreateEmptyMorePreciseMip)
|
|
|
|
|
ON_COMMAND(ID_CREATE_EMPTY_ROUGHER_MIP, OnCreateEmptyRougherMip)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_CLONE_TO_MORE_PRECISE_MIP, OnUpdateCloneToMorePreciseMip)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_CLONE_TO_ROUGHER_MIP_LEVEL, OnUpdateCloneToRougherMipLevel)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_CREATE_EMPTY_MORE_PRECISE_MIP, OnUpdateCreateEmptyMorePreciseMip)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_CREATE_EMPTY_ROUGHER_MIP, OnUpdateCreateEmptyRougherMip)
|
|
|
|
|
ON_COMMAND(ID_EDIT_PASTE_ALTERNATIVE, OnEditPasteAlternative)
|
|
|
|
|
ON_COMMAND(ID_SELECT_ALL_ENTITIES_IN_WORLD, OnSelectAllEntitiesInWorld)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE_ALTERNATIVE, OnUpdateEditPasteAlternative)
|
|
|
|
|
ON_COMMAND(ID_ENTITY_MODE, OnEntityMode)
|
|
|
|
|
ON_COMMAND(ID_FIND_TEXTURE, OnFindTexture)
|
|
|
|
|
ON_COMMAND(ID_SELECT_SECTORS_WITH_SAME_NAME, OnSelectSectorsWithSameName)
|
|
|
|
|
ON_COMMAND(ID_SELECT_SECTORS_ARROUND_ENTITY, OnSelectSectorsArroundEntity)
|
|
|
|
|
ON_COMMAND(ID_SELECT_SECTORS_ARROUND_ENTITY_ON_CONTEXT, OnSelectSectorsArroundEntityOnContext)
|
|
|
|
|
ON_COMMAND(ID_INSERT_VERTEX, OnInsertVertex)
|
|
|
|
|
ON_COMMAND(ID_DELETE_VERTEX, OnDeleteVertex)
|
|
|
|
|
ON_COMMAND(ID_SAVE_PICTURES_FOR_ENVIRONMENT, OnSavePicturesForEnvironment)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_SAVE_PICTURES_FOR_ENVIRONMENT, OnUpdateSavePicturesForEnvironment)
|
|
|
|
|
ON_WM_ERASEBKGND()
|
|
|
|
|
ON_COMMAND(ID_CSG_SELECT_SECTOR, OnCsgSelectSector)
|
|
|
|
|
ON_COMMAND(ID_MENU_ALIGN_MAPPING_U, OnMenuAlignMappingU)
|
|
|
|
|
ON_COMMAND(ID_MENU_ALIGN_MAPPING_V, OnMenuAlignMappingV)
|
|
|
|
|
ON_WM_DESTROY()
|
|
|
|
|
ON_COMMAND(ID_FALL_DOWN, OnFallDown)
|
|
|
|
|
ON_COMMAND(ID_PREVIOUS, OnPrevious)
|
|
|
|
|
ON_COMMAND(ID_NEXT, OnNext)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_PREVIOUS, OnUpdatePrevious)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_NEXT, OnUpdateNext)
|
|
|
|
|
ON_COMMAND(ID_REMOVE_UNUSED_TEXTURES, OnRemoveUnusedTextures)
|
|
|
|
|
ON_COMMAND(ID_ROTATE, OnRotate)
|
|
|
|
|
ON_COMMAND(ID_ROTATE_BACK, OnRotateBack)
|
|
|
|
|
ON_COMMAND(ID_SELECT_VISIBLE_SECTORS, OnSelectVisibleSectors)
|
|
|
|
|
ON_COMMAND(ID_EDIT_COPY_ALTERNATIVE, OnEditCopyAlternative)
|
|
|
|
|
ON_COMMAND(ID_ROTATE_LEFT, OnRotateLeft)
|
|
|
|
|
ON_COMMAND(ID_ROTATE_RIGHT, OnRotateRight)
|
|
|
|
|
ON_COMMAND(ID_ROTATE_UP, OnRotateUp)
|
|
|
|
|
ON_COMMAND(ID_ROTATE_DOWN, OnRotateDown)
|
|
|
|
|
ON_COMMAND(ID_SELECT_WHO_TARGETS, OnSelectWhoTargets)
|
|
|
|
|
ON_COMMAND(ID_SELECT_INVALIDTRIS, OnSelectInvalidTris)
|
|
|
|
|
ON_COMMAND(ID_TEST_CONNECTIONS_BACK, OnTestConnectionsBack)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_TEST_CONNECTIONS_BACK, OnUpdateTestConnectionsBack)
|
|
|
|
|
ON_WM_MOUSEWHEEL()
|
|
|
|
|
ON_COMMAND(ID_SELECT_SECTORS_OTHER_SIDE, OnSelectSectorsOtherSide)
|
|
|
|
|
ON_COMMAND(ID_SELECT_LINKS_TO_SECTOR, OnSelectLinksToSector)
|
|
|
|
|
ON_COMMAND(ID_REMAIN_SELECTEDBY_ORIENTATION, OnRemainSelectedByOrientation)
|
|
|
|
|
ON_COMMAND(ID_DESELECT_BY_ORIENTATION, OnDeselectByOrientation)
|
|
|
|
|
ON_COMMAND(ID_VERTEX_MODE, OnVertexMode)
|
|
|
|
|
ON_COMMAND(ID_REOPTIMIZE_BRUSHES, OnReoptimizeBrushes)
|
|
|
|
|
ON_COMMAND(ID_MERGE_VERTICES, OnMergeVertices)
|
|
|
|
|
ON_COMMAND(ID_EXPORT_DISPLACE_MAP, OnExportDisplaceMap)
|
|
|
|
|
ON_COMMAND(ID_CUT_MODE, OnCutMode)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_CUT_MODE, OnUpdateCutMode)
|
|
|
|
|
ON_COMMAND(ID_SELECT_ALL_TARGETS, OnSelectAllTargets)
|
|
|
|
|
ON_COMMAND(ID_SELECT_ALL_TARGETS_ON_CONTEXT, OnSelectAllTargetsOnContext)
|
|
|
|
|
ON_COMMAND(ID_SELECT_CLONES, OnSelectClones)
|
|
|
|
|
ON_COMMAND(ID_SELECT_CLONES_ON_CONTEXT, OnSelectClonesOnContext)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_SELECT_CLONES, OnUpdateSelectClones)
|
|
|
|
|
ON_COMMAND(ID_SELECT_ALL_VERTICES, OnSelectAllVertices)
|
|
|
|
|
ON_COMMAND(ID_SELECT_OF_SAME_CLASS, OnSelectOfSameClass)
|
|
|
|
|
ON_COMMAND(ID_SELECT_OF_SAME_CLASS_ON_CONTEXT, OnSelectOfSameClassOnContext)
|
|
|
|
|
ON_COMMAND(ID_ALTERNATIVE_MOVING_MODE, OnAlternativeMovingMode)
|
|
|
|
|
ON_COMMAND(ID_RE_TRIPLE, OnReTriple)
|
|
|
|
|
ON_COMMAND(ID_SELECT_WHO_TARGETS_ON_CONTEXT, OnSelectWhoTargetsOnContext)
|
|
|
|
|
ON_COMMAND(ID_CLEAR_ALL_TARGETS, OnClearAllTargets)
|
|
|
|
|
ON_COMMAND(ID_SELECT_CSG_TARGET, OnSelectCsgTarget)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_SELECT_CSG_TARGET, OnUpdateSelectCsgTarget)
|
|
|
|
|
ON_COMMAND(ID_REMAIN_SELECTEDBY_ORIENTATION_SINGLE, OnRemainSelectedbyOrientationSingle)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_RE_TRIPLE, OnUpdateReTriple)
|
|
|
|
|
ON_COMMAND(ID_TRIANGULARIZE_POLYGON, OnTriangularizePolygon)
|
|
|
|
|
ON_COMMAND(ID_ENTITY_CONTEXT_HELP, OnEntityContextHelp)
|
|
|
|
|
ON_COMMAND(ID_POPUP_AUTO_FIT_MAPPING, OnPopupAutoFitMapping)
|
|
|
|
|
ON_COMMAND(ID_TRIANGULARIZE_SELECTION, OnTriangularizeSelection)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_TRIANGULARIZE_SELECTION, OnUpdateTriangularizeSelection)
|
|
|
|
|
ON_COMMAND(ID_POPUP_AUTO_FIT_MAPPING_SMALL, OnPopupAutoFitMappingSmall)
|
|
|
|
|
ON_COMMAND(ID_POPUP_AUTO_FIT_MAPPING_BOTH, OnPopupAutoFitMappingBoth)
|
|
|
|
|
ON_COMMAND(ID_RESET_MAPPING_OFFSET, OnResetMappingOffset)
|
|
|
|
|
ON_COMMAND(ID_RESET_MAPPING_ROTATION, OnResetMappingRotation)
|
|
|
|
|
ON_COMMAND(ID_RESET_MAPPING_STRETCH, OnResetMappingStretch)
|
|
|
|
|
ON_COMMAND(ID_CROSSROAD_FOR_L, OnCrossroadForL)
|
|
|
|
|
ON_COMMAND(ID_SELECT_USING_TARGET_TREE, OnSelectUsingTargetTree)
|
|
|
|
|
ON_COMMAND(ID_TARGET_TREE, OnTargetTree)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_TARGET_TREE, OnUpdateTargetTree)
|
|
|
|
|
ON_COMMAND(ID_SWAP_LAYERS_12, OnSwapLayers12)
|
|
|
|
|
ON_COMMAND(ID_SWAP_LAYERS_23, OnSwapLayers23)
|
|
|
|
|
ON_COMMAND(ID_SELECT_DESCENDANTS, OnSelectDescendants)
|
|
|
|
|
ON_COMMAND(ID_CROSSROAD_FOR_CTRL_F, OnCrossroadForCtrlF)
|
|
|
|
|
ON_COMMAND(ID_ROTATE_TO_TARGET_CENTER, OnRotateToTargetCenter)
|
|
|
|
|
ON_COMMAND(ID_ROTATE_TO_TARGET_ORIGIN, OnRotateToTargetOrigin)
|
|
|
|
|
ON_COMMAND(ID_COPY_ORIENTATION, OnCopyOrientation)
|
|
|
|
|
ON_COMMAND(ID_COPY_PLACEMENT, OnCopyPlacement)
|
|
|
|
|
ON_COMMAND(ID_COPY_POSITION, OnCopyPosition)
|
|
|
|
|
ON_COMMAND(ID_PASTE_ORIENTATION, OnPasteOrientation)
|
|
|
|
|
ON_COMMAND(ID_PASTE_PLACEMENT, OnPastePlacement)
|
|
|
|
|
ON_COMMAND(ID_PASTE_POSITION, OnPastePosition)
|
|
|
|
|
ON_COMMAND(ID_ALIGN_B, OnAlignB)
|
|
|
|
|
ON_COMMAND(ID_ALIGN_H, OnAlignH)
|
|
|
|
|
ON_COMMAND(ID_ALIGN_P, OnAlignP)
|
|
|
|
|
ON_COMMAND(ID_ALIGN_X, OnAlignX)
|
|
|
|
|
ON_COMMAND(ID_ALIGN_Y, OnAlignY)
|
|
|
|
|
ON_COMMAND(ID_ALIGN_Z, OnAlignZ)
|
|
|
|
|
ON_COMMAND(ID_AUTOTEXTURIZE_MIPS, OnAutotexturizeMips)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_AUTOTEXTURIZE_MIPS, OnUpdateAutotexturizeMips)
|
|
|
|
|
ON_COMMAND(ID_RANDOM_OFFSET_U, OnRandomOffsetU)
|
|
|
|
|
ON_COMMAND(ID_RANDOM_OFFSET_V, OnRandomOffsetV)
|
|
|
|
|
ON_COMMAND(ID_STRETCH_RELATIVE_OFFSET, OnStretchRelativeOffset)
|
|
|
|
|
ON_COMMAND(ID_DESELECT_HIDDEN, OnDeselectHidden)
|
|
|
|
|
ON_COMMAND(ID_SELECT_HIDDEN, OnSelectHidden)
|
|
|
|
|
ON_COMMAND(ID_SECTORS_TO_BRUSH, OnSectorsToBrush)
|
|
|
|
|
ON_COMMAND(ID_POLYGONS_TO_BRUSH, OnPolygonsToBrush)
|
|
|
|
|
ON_COMMAND(ID_CLONE_POLYGONS, OnClonePolygons)
|
|
|
|
|
ON_COMMAND(ID_DELETE_POLYGONS, OnDeletePolygons)
|
|
|
|
|
ON_COMMAND(ID_KEY_U, OnKeyU)
|
|
|
|
|
ON_COMMAND(ID_KEY_D, OnKeyD)
|
|
|
|
|
ON_COMMAND(ID_FLIP_POLYGON, OnFlipPolygon)
|
|
|
|
|
ON_COMMAND(ID_TERRAIN_MODE, OnTerrainMode)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_TERRAIN_MODE, OnUpdateTerrainMode)
|
|
|
|
|
ON_COMMAND(ID_KEY_M, OnKeyM)
|
|
|
|
|
ON_COMMAND(ID_KEY_BACKSLASH, OnKeyBackslash)
|
|
|
|
|
ON_COMMAND(ID_SELECT_BRUSH, OnSelectBrush)
|
|
|
|
|
ON_COMMAND(ID_SELECT_TERRAIN, OnSelectTerrain)
|
|
|
|
|
ON_COMMAND(ID_ALTITUDE_EDIT_MODE, OnAltitudeEditMode)
|
|
|
|
|
ON_COMMAND(ID_LAYER_TEXTURE_EDIT_MODE, OnLayerTextureEditMode)
|
|
|
|
|
ON_COMMAND(ID_TBRUSH_ALTITUDE, OnTbrushAltitude)
|
|
|
|
|
ON_COMMAND(ID_TBRUSH_EQUILAZE, OnTbrushEquilaze)
|
|
|
|
|
ON_COMMAND(ID_TBRUSH_ERASE, OnTbrushErase)
|
|
|
|
|
ON_COMMAND(ID_TBRUSH_NOISE, OnTbrushNoise)
|
|
|
|
|
ON_COMMAND(ID_TBRUSH_SMOOTH, OnTbrushSmooth)
|
|
|
|
|
ON_COMMAND(ID_OPTIMIZE_TERRAIN, OnOptimizeTerrain)
|
|
|
|
|
ON_COMMAND(ID_RECALCULATE_TERRAIN_SHADOWS, OnRecalculateTerrainShadows)
|
|
|
|
|
ON_COMMAND(ID_VIEW_HEIGHTMAP, OnViewHeightmap)
|
|
|
|
|
ON_COMMAND(ID_IMPORT_HEIGHTMAP, OnImportHeightmap)
|
|
|
|
|
ON_COMMAND(ID_EXPORT_HEIGHTMAP, OnExportHeightmap)
|
|
|
|
|
ON_COMMAND(ID_IMPORT_HEIGHTMAP16, OnImportHeightmap16)
|
|
|
|
|
ON_COMMAND(ID_EXPORT_HEIGHTMAP16, OnExportHeightmap16)
|
|
|
|
|
ON_COMMAND(ID_SELECT_LAYER, OnSelectLayer)
|
|
|
|
|
ON_COMMAND(ID_PICK_LAYER, OnPickLayer)
|
|
|
|
|
ON_COMMAND(ID_KEY_O, OnKeyO)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_KEY_O, OnUpdateKeyO)
|
|
|
|
|
ON_COMMAND(ID_POSTERIZE, OnPosterize)
|
|
|
|
|
ON_COMMAND(ID_EQUILIZE, OnFlatten)
|
|
|
|
|
ON_COMMAND(ID_APPLY_FILTER, OnApplyFilter)
|
|
|
|
|
ON_COMMAND(ID_TE_SMOOTH, OnTeSmooth)
|
|
|
|
|
ON_COMMAND(ID_EDIT_TERRAIN_PREFS, OnEditTerrainPrefs)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_TERRAIN_PREFS, OnUpdateEditTerrainPrefs)
|
|
|
|
|
ON_COMMAND(ID_KEY_CTRL_SHIFT_E, OnKeyCtrlShiftE)
|
|
|
|
|
ON_COMMAND(ID_KEY_CTRL_SHIFT_G, OnKeyCtrlShiftG)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_KEY_CTRL_SHIFT_G, OnUpdateKeyCtrlShiftG)
|
|
|
|
|
ON_COMMAND(ID_TERRAIN_LAYER_OPTIONS, OnTerrainLayerOptions)
|
|
|
|
|
ON_UPDATE_COMMAND_UI(ID_TERRAIN_LAYER_OPTIONS, OnUpdateTerrainLayerOptions)
|
|
|
|
|
ON_COMMAND(ID_KEY_CTRL_SHIFT_K, OnKeyCtrlShiftK)
|
|
|
|
|
ON_COMMAND(ID_APPLY_CONTINOUS_NOISE, OnApplyContinousNoise)
|
|
|
|
|
ON_COMMAND(ID_APPLY_MINIMUM, OnApplyMinimum)
|
|
|
|
|
ON_COMMAND(ID_APPLY_MAXIMUM, OnApplyMaximum)
|
|
|
|
|
ON_COMMAND(ID_APPLY_FLATTEN, OnApplyFlatten)
|
|
|
|
|
ON_COMMAND(ID_APPLY_POSTERIZE, OnApplyPosterize)
|
|
|
|
|
ON_COMMAND(ID_OPTIMIZE_LAYERS, OnOptimizeLayers)
|
|
|
|
|
ON_COMMAND(ID_TBRUSH_CONTINOUS_NOISE, OnTbrushContinousNoise)
|
|
|
|
|
ON_COMMAND(ID_TBRUSH_FILTER, OnTbrushFilter)
|
|
|
|
|
ON_COMMAND(ID_TBRUSH_FLATTEN, OnTbrushFlatten)
|
|
|
|
|
ON_COMMAND(ID_TBRUSH_MAXIMUM, OnTbrushMaximum)
|
|
|
|
|
ON_COMMAND(ID_TBRUSH_MINIMUM, OnTbrushMinimum)
|
|
|
|
|
ON_COMMAND(ID_TBRUSH_POSTERIZE, OnTbrushPosterize)
|
|
|
|
|
ON_COMMAND(ID_TERRAIN_PROPERTIES, OnTerrainProperties)
|
|
|
|
|
//}}AFX_MSG_MAP
|
|
|
|
|
ON_COMMAND_RANGE(ID_BUFFER01, ID_BUFFER10, OnKeyBuffer)
|
|
|
|
|
ON_COMMAND_RANGE(ID_EDIT_BUFFER01, ID_EDIT_BUFFER10, OnKeyEditBuffer)
|
|
|
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// CWorldEditorView construction/destruction
|
|
|
|
|
|
|
|
|
|
CWorldEditorView::CWorldEditorView()
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_NONE;
|
|
|
|
|
m_iaLastInputAction=IA_NONE;
|
|
|
|
|
m_pbpoTranslationPlane = NULL;
|
|
|
|
|
|
|
|
|
|
m_vpViewPrefs = theApp.m_vpViewPrefs[ 0];
|
|
|
|
|
m_ptProjectionType = CSlaveViewer::PT_PERSPECTIVE;
|
|
|
|
|
|
|
|
|
|
m_pdpDrawPort = NULL;
|
|
|
|
|
m_pvpViewPort = NULL;
|
|
|
|
|
|
|
|
|
|
m_fGridInMeters = 10.0f;
|
|
|
|
|
|
|
|
|
|
m_pbpoRightClickedPolygon = NULL;
|
|
|
|
|
m_penEntityHitOnContext = NULL;
|
|
|
|
|
|
|
|
|
|
m_iDragVertice = -1;
|
|
|
|
|
m_iDragEdge = -1;
|
|
|
|
|
|
|
|
|
|
_pselbvxtSelectOnRender = NULL;
|
|
|
|
|
_pselenSelectOnRender = NULL;
|
|
|
|
|
m_bRequestVtxClickSelect = FALSE;
|
|
|
|
|
m_bRequestVtxLassoSelect = FALSE;
|
|
|
|
|
m_bRequestEntityLassoSelect = FALSE;
|
|
|
|
|
m_strTest="";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CWorldEditorView::~CWorldEditorView()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CWorldEditorView::PreCreateWindow(CREATESTRUCT& cs)
|
|
|
|
|
{
|
|
|
|
|
// TODO: Modify the Window class or styles here by modifying
|
|
|
|
|
// the CREATESTRUCT cs
|
|
|
|
|
|
|
|
|
|
return CView::PreCreateWindow(cs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void GetToolTipText(void *pView, char *pToolTipText)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorView *pWorldEditorView = (CWorldEditorView *) pView;
|
|
|
|
|
pWorldEditorView->GetToolTipText( pToolTipText);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// CWorldEditorView drawing
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::RenderBackdropTexture(CDrawPort *pDP,
|
|
|
|
|
FLOAT3D v0, FLOAT3D v1, FLOAT3D v2, FLOAT3D v3,
|
|
|
|
|
CTextureObject &to)
|
|
|
|
|
{
|
|
|
|
|
if( to.GetData() == NULL) return;
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
FLOAT3D v0p, v1p, v2p, v3p;
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer(GetChildFrame()->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid, pDP);
|
|
|
|
|
// create a projection for slave viewer
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
|
|
|
|
|
// project current base vertice and convert y coordinate from mathemathical representation
|
|
|
|
|
// into screen representation
|
|
|
|
|
prProjection->ProjectCoordinate( v0, v0p); v0p(2) = pDP->GetHeight() - v0p(2);
|
|
|
|
|
prProjection->ProjectCoordinate( v1, v1p); v1p(2) = pDP->GetHeight() - v1p(2);
|
|
|
|
|
prProjection->ProjectCoordinate( v2, v2p); v2p(2) = pDP->GetHeight() - v2p(2);
|
|
|
|
|
prProjection->ProjectCoordinate( v3, v3p); v3p(2) = pDP->GetHeight() - v3p(2);
|
|
|
|
|
|
|
|
|
|
FLOATaabbox3D box;
|
|
|
|
|
box |= v0p;
|
|
|
|
|
box |= v1p;
|
|
|
|
|
box |= v2p;
|
|
|
|
|
box |= v3p;
|
|
|
|
|
if( (box.Size()(1) > 2) && (box.Size()(2) > 2) )
|
|
|
|
|
{
|
|
|
|
|
// create rectangle for backdrop picture
|
|
|
|
|
PIXaabbox2D rectPict;
|
|
|
|
|
rectPict = PIXaabbox2D( PIX2D((SLONG)box.Min()(1), (SLONG)box.Min()(2)),
|
|
|
|
|
PIX2D((SLONG)box.Max()(1), (SLONG)box.Max()(2)) );
|
|
|
|
|
pDP->PutTexture( &to, rectPict);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL _bCursorMoved=FALSE;
|
|
|
|
|
void CWorldEditorView::RenderView( CDrawPort *pDP)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CChildFrame *pChild = GetChildFrame();
|
|
|
|
|
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
|
|
|
|
|
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
|
|
|
|
|
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
|
|
|
|
|
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
|
|
|
|
|
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer(GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pDP);
|
|
|
|
|
|
|
|
|
|
// copy view's world rendering preferences to global world rendering preferences
|
|
|
|
|
_wrpWorldRenderPrefs = m_vpViewPrefs.m_wrpWorldRenderPrefs;
|
|
|
|
|
_wrpWorldRenderPrefs.SetTextureLayerOn( theApp.m_bTexture1, 0);
|
|
|
|
|
_wrpWorldRenderPrefs.SetTextureLayerOn( theApp.m_bTexture2, 1);
|
|
|
|
|
_wrpWorldRenderPrefs.SetTextureLayerOn( theApp.m_bTexture3, 2);
|
|
|
|
|
// set shadow type from child frame
|
|
|
|
|
_wrpWorldRenderPrefs.SetShadowsType( GetChildFrame()->m_stShadowType);
|
|
|
|
|
// copy view's model rendering preferences to global model rendering preferences
|
|
|
|
|
_mrpModelRenderPrefs = m_vpViewPrefs.m_mrpModelRenderPrefs;
|
|
|
|
|
// copy auto mip modeling flag from child frame
|
|
|
|
|
_wrpWorldRenderPrefs.SetAutoMipBrushingOn( GetChildFrame()->m_bAutoMipBrushingOn);
|
|
|
|
|
// and manual mip factor
|
|
|
|
|
_wrpWorldRenderPrefs.SetManualMipBrushingFactor( GetChildFrame()->m_fManualMipBrushingFactor);
|
|
|
|
|
// view visibility tweaking
|
|
|
|
|
_wrpWorldRenderPrefs.SetVisTweaksOn(GetChildFrame()->m_bShowVisibilityTweaks);
|
|
|
|
|
_wrpWorldRenderPrefs.DisableVisTweaks(GetChildFrame()->m_bDisableVisibilityTweaks);
|
|
|
|
|
_pselbscVisTweaks=&pDoc->m_selSectorSelection;
|
|
|
|
|
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectedEntityModel( theApp.m_pEntityMarkerModelObject);
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectedPortalModel( theApp.m_pPortalMarkerModelObject);
|
|
|
|
|
_wrpWorldRenderPrefs.SetEmptyBrushModel( theApp.m_pEmptyBrushModelObject);
|
|
|
|
|
|
|
|
|
|
// if we are using automatic rendering range
|
|
|
|
|
if( m_vpViewPrefs.m_bAutoRenderingRange)
|
|
|
|
|
{
|
|
|
|
|
// set rendering range of 1.5 x viewer's target distance
|
|
|
|
|
FLOAT fTargetDistance = svViewer.GetTargetDistance();
|
|
|
|
|
// we have to take second layer distance in considiration also
|
|
|
|
|
FLOAT fMinimumRenderRange = fTargetDistance;
|
|
|
|
|
|
|
|
|
|
// if second layer's world exists
|
|
|
|
|
if( pDoc->m_pwoSecondLayer != NULL)
|
|
|
|
|
{
|
|
|
|
|
CPlacement3D plViewer = GetChildFrame()->m_mvViewer.GetViewerPlacement();
|
|
|
|
|
// calculate viewer-layer distance
|
|
|
|
|
FLOAT fViewerLayerDistance =
|
|
|
|
|
(plViewer.pl_PositionVector - pDoc->m_plSecondLayer.pl_PositionVector).Length();
|
|
|
|
|
// if current minimum rendering range is smaller than one that viewer-layer
|
|
|
|
|
// distance would request
|
|
|
|
|
if( fMinimumRenderRange < fViewerLayerDistance )
|
|
|
|
|
{
|
|
|
|
|
fMinimumRenderRange = fViewerLayerDistance;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// don't allow minimum rendering range to drop below 1.5 m
|
|
|
|
|
if( fMinimumRenderRange < 1.5f)
|
|
|
|
|
{
|
|
|
|
|
fMinimumRenderRange = 1.5f;
|
|
|
|
|
}
|
|
|
|
|
_wrpWorldRenderPrefs.SetMinimumRenderRange( fMinimumRenderRange * 1.5f);
|
|
|
|
|
}
|
|
|
|
|
// we are using fixed rendering range
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// set global rendering range from fixed one remembered in prefs
|
|
|
|
|
_wrpWorldRenderPrefs.SetMinimumRenderRange( m_vpViewPrefs.m_fRenderingRange);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set visibility of link lines
|
|
|
|
|
_wrpWorldRenderPrefs.SetShowTargetsOn(pChild->m_bShowTargets);
|
|
|
|
|
// set visibility of entity names
|
|
|
|
|
_wrpWorldRenderPrefs.SetShowEntityNamesOn(pChild->m_bShowEntityNames);
|
|
|
|
|
|
|
|
|
|
// find out if z buffer clearing should occure
|
|
|
|
|
BOOL bClearZBuffer = FALSE;
|
|
|
|
|
BOOL bClearScreen = TRUE;
|
|
|
|
|
|
|
|
|
|
// get world and model polygon fill flags
|
|
|
|
|
BOOL bModelPolygonFilling =
|
|
|
|
|
(_mrpModelRenderPrefs.GetRenderType() & RT_TEXTURE_MASK) != RT_NO_POLYGON_FILL;
|
|
|
|
|
// find out if any of isometric projection modes is currently on
|
|
|
|
|
BOOL bPerspectiveOn = m_ptProjectionType == CSlaveViewer::PT_PERSPECTIVE;
|
|
|
|
|
BOOL bPolygonFillOn = _wrpWorldRenderPrefs.GetPolygonsFillType() != CWorldRenderPrefs::FT_NONE;
|
|
|
|
|
|
|
|
|
|
// if something requires clearing of z-buffer
|
|
|
|
|
if( bPolygonFillOn ||
|
|
|
|
|
pDoc->m_bOrientationIcons ||
|
|
|
|
|
((!bCSGOn && bPerspectiveOn) && GetChildFrame()->m_bSceneRenderingTime) ||
|
|
|
|
|
m_vpViewPrefs.m_bMeasurementTape ||
|
|
|
|
|
theApp.m_bMeasureModeOn || theApp.m_bCutModeOn)
|
|
|
|
|
{
|
|
|
|
|
bClearZBuffer = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if we will render models using polygon fill, we must clear z-buffer
|
|
|
|
|
if( bModelPolygonFilling)
|
|
|
|
|
{
|
|
|
|
|
bClearZBuffer = TRUE;
|
|
|
|
|
}
|
|
|
|
|
// if rendering will fill whole screen along with z-buffer
|
|
|
|
|
if( bPolygonFillOn && bPerspectiveOn)
|
|
|
|
|
{
|
|
|
|
|
bClearZBuffer = FALSE;
|
|
|
|
|
bClearScreen = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COLOR colBcgFill=m_vpViewPrefs.m_PaperColor;
|
|
|
|
|
if(_wrpWorldRenderPrefs.IsBackgroundTextureOn())
|
|
|
|
|
{
|
|
|
|
|
bClearScreen = TRUE;
|
|
|
|
|
colBcgFill=pDoc->m_woWorld.wo_colBackground;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set selected entity model
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectedEntityModel( theApp.m_pEntityMarkerModelObject);
|
|
|
|
|
// set selected portal model
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectedPortalModel( theApp.m_pPortalMarkerModelObject);
|
|
|
|
|
// set empty brush model
|
|
|
|
|
_wrpWorldRenderPrefs.SetEmptyBrushModel( theApp.m_pEmptyBrushModelObject);
|
|
|
|
|
|
|
|
|
|
switch( pDoc->GetEditingMode())
|
|
|
|
|
{
|
|
|
|
|
case POLYGON_MODE:
|
|
|
|
|
{
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_POLYGONS);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SECTOR_MODE:
|
|
|
|
|
{
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_SECTORS);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ENTITY_MODE:
|
|
|
|
|
{
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_ENTITIES);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case VERTEX_MODE:
|
|
|
|
|
{
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_VERTICES);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TERRAIN_MODE:
|
|
|
|
|
{
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_NONE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CSG_MODE:
|
|
|
|
|
{
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_NONE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: { FatalError("Unknown editing mode."); break;};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if selection shouldn't be rendered and we are not in vertex mode (selection should always be rendered)
|
|
|
|
|
if( !GetChildFrame()->m_bSelectionVisible && (pDoc->GetEditingMode()!= VERTEX_MODE) )
|
|
|
|
|
{
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_NONE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create a projection for slave viewer
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
// set object placement
|
|
|
|
|
prProjection->ObjectPlacementL() = pDoc->m_plGrid;
|
|
|
|
|
if( !bPerspectiveOn && !_wrpWorldRenderPrefs.wrp_bApplyFarClipPlaneInIsometricProjection)
|
|
|
|
|
{
|
|
|
|
|
prProjection->FarClipDistanceL() = -1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
prProjection->FarClipDistanceL() = _wrpWorldRenderPrefs.wrp_fFarClipPlane;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// prepare the projection
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
|
|
|
|
|
// if screen clearance is required
|
|
|
|
|
if( bClearScreen)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
m_toBcgPicture.SetData_t(CTString(m_vpViewPrefs.m_achrBcgPicture));
|
|
|
|
|
}
|
|
|
|
|
// if failed
|
|
|
|
|
catch (char *strError)
|
|
|
|
|
{
|
|
|
|
|
(void) strError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( m_toBcgPicture.GetData() != NULL)
|
|
|
|
|
{
|
|
|
|
|
// fill background with bcg picture
|
|
|
|
|
PIXaabbox2D screenBox;
|
|
|
|
|
screenBox = PIXaabbox2D( PIX2D(0,0), PIX2D(pDP->GetWidth(), pDP->GetHeight()) );
|
|
|
|
|
pDP->PutTexture( &m_toBcgPicture, screenBox);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// clear background using current color form rendering preferences
|
|
|
|
|
pDP->Fill(colBcgFill | CT_OPAQUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( pDoc->m_woWorld.wo_strBackdropUp != "" && GetChildFrame()->m_bRenderViewPictures)
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D v0 = FLOAT3D(pDoc->m_woWorld.wo_fUpCX-pDoc->m_woWorld.wo_fUpW/2.0f, 0.0f,
|
|
|
|
|
pDoc->m_woWorld.wo_fUpCZ-pDoc->m_woWorld.wo_fUpL/2.0f);
|
|
|
|
|
FLOAT3D v1 = FLOAT3D(pDoc->m_woWorld.wo_fUpCX+pDoc->m_woWorld.wo_fUpW/2.0f, 0.0f,
|
|
|
|
|
pDoc->m_woWorld.wo_fUpCZ-pDoc->m_woWorld.wo_fUpL/2.0f);
|
|
|
|
|
FLOAT3D v2 = FLOAT3D(pDoc->m_woWorld.wo_fUpCX+pDoc->m_woWorld.wo_fUpW/2.0f, 0.0f,
|
|
|
|
|
pDoc->m_woWorld.wo_fUpCZ+pDoc->m_woWorld.wo_fUpL/2.0f);
|
|
|
|
|
FLOAT3D v3 = FLOAT3D(pDoc->m_woWorld.wo_fUpCX-pDoc->m_woWorld.wo_fUpW/2.0f, 0.0f,
|
|
|
|
|
pDoc->m_woWorld.wo_fUpCZ+pDoc->m_woWorld.wo_fUpL/2.0f);
|
|
|
|
|
RenderBackdropTexture( pDP, v0, v1, v2, v3, pDoc->m_toBackdropUp);
|
|
|
|
|
}
|
|
|
|
|
if( pDoc->m_woWorld.wo_strBackdropFt != "" && GetChildFrame()->m_bRenderViewPictures)
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D v0 = FLOAT3D(pDoc->m_woWorld.wo_fFtCX-pDoc->m_woWorld.wo_fFtW/2.0f,
|
|
|
|
|
pDoc->m_woWorld.wo_fFtCY-pDoc->m_woWorld.wo_fFtH/2.0f, 0.0f);
|
|
|
|
|
FLOAT3D v1 = FLOAT3D(pDoc->m_woWorld.wo_fFtCX+pDoc->m_woWorld.wo_fFtW/2.0f,
|
|
|
|
|
pDoc->m_woWorld.wo_fFtCY-pDoc->m_woWorld.wo_fFtH/2.0f, 0.0f);
|
|
|
|
|
FLOAT3D v2 = FLOAT3D(pDoc->m_woWorld.wo_fFtCX+pDoc->m_woWorld.wo_fFtW/2.0f,
|
|
|
|
|
pDoc->m_woWorld.wo_fFtCY+pDoc->m_woWorld.wo_fFtH/2.0f, 0.0f);
|
|
|
|
|
FLOAT3D v3 = FLOAT3D(pDoc->m_woWorld.wo_fFtCX-pDoc->m_woWorld.wo_fFtW/2.0f,
|
|
|
|
|
pDoc->m_woWorld.wo_fFtCY+pDoc->m_woWorld.wo_fFtH/2.0f, 0.0f);
|
|
|
|
|
RenderBackdropTexture( pDP, v0, v1, v2, v3, pDoc->m_toBackdropFt);
|
|
|
|
|
}
|
|
|
|
|
if( pDoc->m_woWorld.wo_strBackdropRt != "" && GetChildFrame()->m_bRenderViewPictures)
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D v0 = FLOAT3D(0.0f, pDoc->m_woWorld.wo_fRtCY-pDoc->m_woWorld.wo_fRtH/2.0f,
|
|
|
|
|
pDoc->m_woWorld.wo_fRtCZ-pDoc->m_woWorld.wo_fRtL/2.0f);
|
|
|
|
|
FLOAT3D v1 = FLOAT3D(0.0f, pDoc->m_woWorld.wo_fRtCY+pDoc->m_woWorld.wo_fRtH/2.0f,
|
|
|
|
|
pDoc->m_woWorld.wo_fRtCZ-pDoc->m_woWorld.wo_fRtL/2.0f);
|
|
|
|
|
FLOAT3D v2 = FLOAT3D(0.0f, pDoc->m_woWorld.wo_fRtCY+pDoc->m_woWorld.wo_fRtH/2.0f,
|
|
|
|
|
pDoc->m_woWorld.wo_fRtCZ+pDoc->m_woWorld.wo_fRtL/2.0f);
|
|
|
|
|
FLOAT3D v3 = FLOAT3D(0.0f, pDoc->m_woWorld.wo_fRtCY-pDoc->m_woWorld.wo_fRtH/2.0f,
|
|
|
|
|
pDoc->m_woWorld.wo_fRtCZ+pDoc->m_woWorld.wo_fRtL/2.0f);
|
|
|
|
|
RenderBackdropTexture( pDP, v0, v1, v2, v3, pDoc->m_toBackdropRt);
|
|
|
|
|
}
|
|
|
|
|
// if object should me rendered as backdrop
|
|
|
|
|
if( GetChildFrame()->m_bRenderViewPictures)
|
|
|
|
|
{
|
|
|
|
|
CObject3D &ob = pDoc->m_o3dBackdropObject;
|
|
|
|
|
FOREACHINDYNAMICARRAY(ob.ob_aoscSectors, CObjectSector, itosc)
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICARRAY(itosc->osc_aoedEdges, CObjectEdge, itoe)
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D vtx0 = DOUBLEtoFLOAT(*itoe->oed_Vertex0);
|
|
|
|
|
FLOAT3D vtx1 = DOUBLEtoFLOAT(*itoe->oed_Vertex1);
|
|
|
|
|
prProjection->PreClip( vtx0, vtx0);
|
|
|
|
|
prProjection->PreClip( vtx1, vtx1);
|
|
|
|
|
prProjection->ClipLine(vtx0, vtx1);
|
|
|
|
|
// apply perspective
|
|
|
|
|
FLOAT3D vtx0p, vtx1p;
|
|
|
|
|
prProjection->PostClip( vtx0, vtx0p);
|
|
|
|
|
prProjection->PostClip( vtx1, vtx1p);
|
|
|
|
|
// draw one line of bounding box
|
|
|
|
|
pDP->DrawLine( (PIX)vtx0p(1), (PIX)vtx0p(2), (PIX)vtx1p(1), (PIX)vtx1p(2),
|
|
|
|
|
C_dGRAY|CT_OPAQUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if z-buffer clearance is required
|
|
|
|
|
if( bClearZBuffer)
|
|
|
|
|
{
|
|
|
|
|
// erase z-buffer
|
|
|
|
|
pDP->FillZBuffer(ZBUF_BACK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FLOAT3D fGridOrigin;
|
|
|
|
|
// project grid origin
|
|
|
|
|
prProjection->ProjectCoordinate( FLOAT3D( 0.0f, 0.0f, 0.0f), fGridOrigin);
|
|
|
|
|
// convert y coordinate form mathematical form info screen space
|
|
|
|
|
fGridOrigin(2) = pDP->GetHeight() - fGridOrigin(2);
|
|
|
|
|
|
|
|
|
|
// calculate grid in pixels but there must be bigger than given minimal size
|
|
|
|
|
#define SMALLEST_ALLOWED_GRID_IN_PIXELS 30
|
|
|
|
|
// get zoom factor
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
// declare decadic grid in meters
|
|
|
|
|
FLOAT afDecadicGridInMeters[] = {0.25f,0.50f,1.0f,2.5f,5.0f,10.0f,25.0f,50.0f,100.0f,
|
|
|
|
|
250.0f,500.0f,1000.0f,10000.0f,100000.0f};
|
|
|
|
|
FLOAT afBinaryGridInMeters[] = {0.25f,0.50f,1.0f,2.0f,4.0f,8.0f,16.0f,32.0f,64.0f,128.0f,256.0f,
|
|
|
|
|
512.0f,1024.0f,2048.0f,4096.0f,8192.0f,16384.0f,32768.0f,65536.0f};
|
|
|
|
|
// select max grid value
|
|
|
|
|
if( theApp.m_bDecadicGrid)
|
|
|
|
|
{
|
|
|
|
|
m_fGridInMeters = afDecadicGridInMeters[ sizeof( afDecadicGridInMeters)/sizeof(FLOAT)-1];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_fGridInMeters = afBinaryGridInMeters[ sizeof( afBinaryGridInMeters)/sizeof(FLOAT)-1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ptr to curently active grid table
|
|
|
|
|
FLOAT *pafGridInMeters;
|
|
|
|
|
INDEX ctTableMembers;
|
|
|
|
|
// select active table
|
|
|
|
|
if( theApp.m_bDecadicGrid)
|
|
|
|
|
{
|
|
|
|
|
pafGridInMeters = afDecadicGridInMeters;
|
|
|
|
|
ctTableMembers = sizeof( afDecadicGridInMeters)/sizeof(FLOAT);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pafGridInMeters = afBinaryGridInMeters;
|
|
|
|
|
ctTableMembers = sizeof( afBinaryGridInMeters)/sizeof(FLOAT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for all members in precalculated grid in meters array
|
|
|
|
|
for( INDEX i=0; i<ctTableMembers; i++)
|
|
|
|
|
{
|
|
|
|
|
// calculate grid steep
|
|
|
|
|
m_fpixGridSteep = fZoom * pafGridInMeters[ i];
|
|
|
|
|
// is it bigger than smallest allowed grid size in pixels
|
|
|
|
|
if( m_fpixGridSteep >= SMALLEST_ALLOWED_GRID_IN_PIXELS)
|
|
|
|
|
{
|
|
|
|
|
m_fGridInMeters = pafGridInMeters[ i];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// we have calculated wanted grid in pixels, value is stored in pixGridSteep
|
|
|
|
|
// if grid on, draw it
|
|
|
|
|
if( GetChildFrame()->m_bGridOn && !bPerspectiveOn && !bPolygonFillOn)
|
|
|
|
|
{
|
|
|
|
|
// get grid's origin projected point
|
|
|
|
|
FLOAT fGridOriginX = fGridOrigin(1);
|
|
|
|
|
FLOAT fGridOriginY = fGridOrigin(2);
|
|
|
|
|
// calculate starting coordinates of left-up grid line
|
|
|
|
|
FLOAT fGridX = fGridOriginX - (m_fpixGridSteep * (int)(fGridOriginX / m_fpixGridSteep));
|
|
|
|
|
FLOAT fGridY = fGridOriginY - (m_fpixGridSteep * (int)(fGridOriginY / m_fpixGridSteep));
|
|
|
|
|
// remember these start grid values so they can be used for measurement
|
|
|
|
|
m_fGridX = fGridX;
|
|
|
|
|
m_fGridY = fGridY;
|
|
|
|
|
// style of grid line
|
|
|
|
|
ULONG ulLineStyle;
|
|
|
|
|
// loop all vertical grid lines
|
|
|
|
|
#define LINE_EPSILON 0.05f
|
|
|
|
|
FOREVER
|
|
|
|
|
{
|
|
|
|
|
// does this grid lines touch origin point
|
|
|
|
|
if( Abs(fGridX - fGridOriginX) < LINE_EPSILON )
|
|
|
|
|
{
|
|
|
|
|
// if so, draw full line
|
|
|
|
|
ulLineStyle = _FULL_;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// does not, draw point line
|
|
|
|
|
ulLineStyle = _POINT_;
|
|
|
|
|
}
|
|
|
|
|
// draw one vertical grid line
|
|
|
|
|
pDP->DrawLine( (int) fGridX, 0, (int) fGridX, pDP->GetHeight()-1,
|
|
|
|
|
m_vpViewPrefs.m_GridColor|CT_OPAQUE, ulLineStyle);
|
|
|
|
|
// move to next grid line
|
|
|
|
|
fGridX += m_fpixGridSteep;
|
|
|
|
|
// is coordinate passed draw port's width
|
|
|
|
|
if( fGridX > pDP->GetWidth())
|
|
|
|
|
{
|
|
|
|
|
// if so, vertical grid is drawn, stop endless loop
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// loop all horizontal grid lines
|
|
|
|
|
FOREVER
|
|
|
|
|
{
|
|
|
|
|
// does this grid lines touch origin point
|
|
|
|
|
if( Abs(fGridY - fGridOriginY) < LINE_EPSILON )
|
|
|
|
|
{
|
|
|
|
|
// if so, draw full line
|
|
|
|
|
ulLineStyle = _FULL_;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// does not, draw point line
|
|
|
|
|
ulLineStyle = _POINT_;
|
|
|
|
|
}
|
|
|
|
|
// draw one vertical grid line
|
|
|
|
|
pDP->DrawLine( 0, (int) fGridY, pDP->GetWidth()-1, (int) fGridY,
|
|
|
|
|
m_vpViewPrefs.m_GridColor|CT_OPAQUE, ulLineStyle);
|
|
|
|
|
// move to next grid line
|
|
|
|
|
fGridY += m_fpixGridSteep;
|
|
|
|
|
// is coordinate passed draw port's height
|
|
|
|
|
if( fGridY > pDP->GetHeight())
|
|
|
|
|
{
|
|
|
|
|
// if so, vertical grid is drawn, stop endless loop
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if we should draw measurement tape
|
|
|
|
|
if( m_vpViewPrefs.m_bMeasurementTape && !bPerspectiveOn)
|
|
|
|
|
{
|
|
|
|
|
// define tape in meters for decadic grid type
|
|
|
|
|
FLOAT afDecadicTapeInMeters[] =
|
|
|
|
|
{ 0.01f, 0.1f, 1.0f, 10.0f, 100.0f, 1000.0f, 10000.0f, 100000.0f};
|
|
|
|
|
CTString astrDecadicTapeInMeters[] =
|
|
|
|
|
{ "1 mm", "1 cm", "1 m", "10 m", "100 m", "1 km", "10 km", "100 km"};
|
|
|
|
|
// define tape in meters for binary grid type
|
|
|
|
|
FLOAT afBinaryTapeInMeters[] =
|
|
|
|
|
{ 1.0f/64, 1.0f/8, 1.0f, 8.0f, 64.0f, 256.0f, 1024.0f, 4096.0f, 16484.0f, 65536.0f};
|
|
|
|
|
CTString astrBinaryTapeInMeters[] =
|
|
|
|
|
{ "1/64 m", "1/8 m", "1 m", "8 m", "64 m", "256 m", "1024 m", "4096 m", "16384 m", "65536 m"};
|
|
|
|
|
|
|
|
|
|
CTString *pastrTapeInMetersTable;
|
|
|
|
|
FLOAT *pafTapeInMetersTable;
|
|
|
|
|
INDEX ctTableMembers;
|
|
|
|
|
|
|
|
|
|
// select active table
|
|
|
|
|
if( theApp.m_bDecadicGrid)
|
|
|
|
|
{
|
|
|
|
|
pafTapeInMetersTable = afDecadicTapeInMeters;
|
|
|
|
|
pastrTapeInMetersTable = astrDecadicTapeInMeters;
|
|
|
|
|
ctTableMembers = sizeof( afDecadicTapeInMeters)/sizeof(FLOAT);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pafTapeInMetersTable = afBinaryTapeInMeters;
|
|
|
|
|
pastrTapeInMetersTable = astrBinaryTapeInMeters;
|
|
|
|
|
ctTableMembers = sizeof( afBinaryTapeInMeters)/sizeof(FLOAT);
|
|
|
|
|
}
|
|
|
|
|
// here we will calculate our tape lenght in meters
|
|
|
|
|
FLOAT fTapeLenMeters;
|
|
|
|
|
// here we will calculate our tape lenght in pixels
|
|
|
|
|
PIX pixTapeLen;
|
|
|
|
|
// here we will place appropriate text saying tape's lenght in meters
|
|
|
|
|
CTString strTapeLen;
|
|
|
|
|
// for all possible dimensions of measurement tape
|
|
|
|
|
for( INDEX i=ctTableMembers-1; i>=0; i--)
|
|
|
|
|
{
|
|
|
|
|
// get tape len in meters
|
|
|
|
|
fTapeLenMeters = pafTapeInMetersTable[ i];
|
|
|
|
|
// get appropriate descriptive string
|
|
|
|
|
strTapeLen = pastrTapeInMetersTable[ i];
|
|
|
|
|
// calculate tape in pixels
|
|
|
|
|
pixTapeLen = (PIX)(fZoom * fTapeLenMeters);
|
|
|
|
|
// is it smaller than 75% of draw port's width
|
|
|
|
|
if( pixTapeLen <= pDP->GetWidth()*3/4)
|
|
|
|
|
{
|
|
|
|
|
// it is, we found our tape dimension
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// calculate tape position on screen
|
|
|
|
|
PIX x = (PIX) ( pDP->GetWidth() * 0.05f); // x starts at 5% of draw port's width
|
|
|
|
|
PIX y = (PIX) ( pDP->GetHeight()* 0.95f); // y starts at 95% of draw port's height
|
|
|
|
|
// draw tape's left end, little vertical line
|
|
|
|
|
pDP->DrawLine( x, y-2, x, y+2, C_BLACK|CT_OPAQUE);
|
|
|
|
|
// draw tape's main, horizontal little
|
|
|
|
|
pDP->DrawLine( x, y, x+pixTapeLen, y, C_BLACK|CT_OPAQUE);
|
|
|
|
|
// draw tape's right end, little vertical line
|
|
|
|
|
pDP->DrawLine( x+pixTapeLen, y-2, x+pixTapeLen, y+2, C_BLACK|CT_OPAQUE);
|
|
|
|
|
// type appropriate text, lenght in meters
|
|
|
|
|
pDP->SetFont( theApp.m_pfntSystem);
|
|
|
|
|
pDP->SetTextAspect( 1.0f);
|
|
|
|
|
pDP->SetTextScaling( 1.0f);
|
|
|
|
|
pDP->PutText( strTapeLen, x, y-16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we are not rendering scene over already rendered scene (used for CSG layer)
|
|
|
|
|
pDP->SetOverlappedRendering(FALSE);
|
|
|
|
|
|
|
|
|
|
// print grid size (or no grid)
|
|
|
|
|
char strPaneText[ 128];
|
|
|
|
|
sprintf( strPaneText, "Grid: %g m", m_fGridInMeters);
|
|
|
|
|
pMainFrame->m_wndStatusBar.SetPaneText( GRID_PANE, CString(strPaneText), TRUE);
|
|
|
|
|
|
|
|
|
|
// create renderer and render world
|
|
|
|
|
CEntity *penOnlySelected = NULL;
|
|
|
|
|
if( pDoc->m_selEntitySelection.Count() == 1)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selEntitySelection.Lock();
|
|
|
|
|
penOnlySelected = &pDoc->m_selEntitySelection[0];
|
|
|
|
|
pDoc->m_selEntitySelection.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// request vertex selecting from renderer
|
|
|
|
|
if( m_bRequestVtxClickSelect)
|
|
|
|
|
{
|
|
|
|
|
_bSelectAlternative = m_bOnSelectVertexShiftDown;
|
|
|
|
|
_pselbvxtSelectOnRender = &pDoc->m_selVertexSelection;
|
|
|
|
|
}
|
|
|
|
|
if( m_bRequestVtxLassoSelect)
|
|
|
|
|
{
|
|
|
|
|
_bSelectAlternative = m_bOnSelectVertexAltDown;
|
|
|
|
|
_pselbvxtSelectOnRender = &pDoc->m_selVertexSelection;
|
|
|
|
|
_pavpixSelectLasso = &m_avpixLaso;
|
|
|
|
|
}
|
|
|
|
|
if( m_bRequestEntityLassoSelect)
|
|
|
|
|
{
|
|
|
|
|
_bSelectAlternative = m_bOnSelectEntityAltDown;
|
|
|
|
|
_pselenSelectOnRender = &pDoc->m_selEntitySelection;
|
|
|
|
|
_pavpixSelectLasso = &m_avpixLaso;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(pDoc->GetEditingMode()==TERRAIN_MODE &&
|
|
|
|
|
theApp.m_penLastTerrainHit==GetTerrainEntity() &&
|
|
|
|
|
!_pInput->IsInputEnabled())
|
|
|
|
|
{
|
|
|
|
|
RenderAndApplyTerrainEditBrush(theApp.m_vLastTerrainHit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( GetChildFrame()->m_bViewFromEntity &&
|
|
|
|
|
(penOnlySelected != NULL) &&
|
|
|
|
|
!(penOnlySelected->GetFlags()&ENF_ANCHORED) &&
|
|
|
|
|
bPerspectiveOn )
|
|
|
|
|
{
|
|
|
|
|
// create a projection for slave viewer
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
prProjection->ViewerPlacementL() = penOnlySelected->GetPlacement();
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
|
|
|
|
|
::RenderView(pDoc->m_woWorld, *penOnlySelected, prProjection, *pDP);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// create renderer and render world
|
|
|
|
|
::RenderView(pDoc->m_woWorld, *(CEntity*) NULL, prProjection, *pDP);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// don't allow further laso select tests
|
|
|
|
|
if( m_bRequestVtxLassoSelect || m_bRequestEntityLassoSelect)
|
|
|
|
|
{
|
|
|
|
|
m_avpixLaso.Clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_pselbvxtSelectOnRender = NULL;
|
|
|
|
|
_pselenSelectOnRender = NULL;
|
|
|
|
|
m_bRequestVtxClickSelect = FALSE;
|
|
|
|
|
m_bRequestVtxLassoSelect = FALSE;
|
|
|
|
|
m_bRequestEntityLassoSelect = FALSE;
|
|
|
|
|
_pavpixSelectLasso = NULL;
|
|
|
|
|
|
|
|
|
|
INDEX ctLasoPts = m_avpixLaso.Count();
|
|
|
|
|
if(((m_iaInputAction == IA_SELECT_LASSO_BRUSH_VERTEX) ||
|
|
|
|
|
(m_iaInputAction == IA_SELECT_LASSO_ENTITY)) && (ctLasoPts>1) )
|
|
|
|
|
{
|
|
|
|
|
for( INDEX iKnot=0; iKnot<ctLasoPts-1; iKnot++)
|
|
|
|
|
{
|
|
|
|
|
PIX x0 = m_avpixLaso[iKnot](1);
|
|
|
|
|
PIX x1 = m_avpixLaso[iKnot+1](1);
|
|
|
|
|
PIX y0 = m_avpixLaso[iKnot](2);
|
|
|
|
|
PIX y1 = m_avpixLaso[iKnot+1](2);
|
|
|
|
|
pDP->DrawLine(x0, y0, x1, y1, m_vpViewPrefs.m_GridColor|CT_OPAQUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prProjection->DepthBufferNearL() = 0.0f;
|
|
|
|
|
prProjection->DepthBufferFarL() = 0.9f;
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
|
|
|
|
|
BeginModelRenderingView(prProjection, pDP);
|
|
|
|
|
|
|
|
|
|
// if we have entity mode active, at least one entity selected and edititng property of
|
|
|
|
|
// edit range type, and perspective is not on, render entities using rendering range model
|
|
|
|
|
CPropertyID *ppidProperty = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
|
|
|
|
|
if( (pDoc->GetEditingMode() == ENTITY_MODE) &&
|
|
|
|
|
(pDoc->m_selEntitySelection.Count() != 0) &&
|
|
|
|
|
(ppidProperty != NULL) &&
|
|
|
|
|
( (ppidProperty->pid_eptType == CEntityProperty::EPT_ANGLE3D) ||
|
|
|
|
|
(ppidProperty->pid_eptType == CEntityProperty::EPT_RANGE) ||
|
|
|
|
|
(ppidProperty->pid_eptType == CEntityProperty::EPT_FLOATAABBOX3D && !bPerspectiveOn)) )
|
|
|
|
|
{
|
|
|
|
|
// for all selected entities
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// obtain property ptr
|
|
|
|
|
CEntityProperty *penpProperty = iten->PropertyForName( ppidProperty->pid_strName);
|
|
|
|
|
// if this entity is just selected, it may not have range property but that was not
|
|
|
|
|
// noticed (it will be during first on idle), so skip it
|
|
|
|
|
if( penpProperty==NULL)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// if we are in perspective and entity property is marked not to be visible in perspective view
|
|
|
|
|
if( (penpProperty->ep_ulFlags & EPROPF_HIDEINPERSPECTIVE) && bPerspectiveOn)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// this model we will render
|
|
|
|
|
CModelObject *pModelObject;
|
|
|
|
|
// this render model structure will be rendered
|
|
|
|
|
CRenderModel rmRenderModel;
|
|
|
|
|
// if we are editing range property
|
|
|
|
|
if( ppidProperty->pid_eptType == CEntityProperty::EPT_RANGE)
|
|
|
|
|
{
|
|
|
|
|
// get editing range
|
|
|
|
|
FLOAT fRange = ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, FLOAT);
|
|
|
|
|
// set collision box's stretch factor
|
|
|
|
|
theApp.m_pRangeSphereModelObject->mo_Stretch = FLOAT3D( fRange, fRange, fRange);
|
|
|
|
|
// set texture rendering mode and phong shading
|
|
|
|
|
//_mrpModelRenderPrefs.SetRenderType( RT_TEXTURE|RT_SHADING_PHONG);
|
|
|
|
|
// copy range model's placement from entity
|
|
|
|
|
rmRenderModel.SetObjectPlacement(iten->GetPlacement());
|
|
|
|
|
// set range sphere model for rendering
|
|
|
|
|
pModelObject = theApp.m_pRangeSphereModelObject;
|
|
|
|
|
}
|
|
|
|
|
// if we are editing angle3D property
|
|
|
|
|
else if( ppidProperty->pid_eptType == CEntityProperty::EPT_ANGLE3D)
|
|
|
|
|
{
|
|
|
|
|
// get editting bounding box
|
|
|
|
|
ANGLE3D aAngle = ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, ANGLE3D);
|
|
|
|
|
rmRenderModel.SetObjectPlacement(
|
|
|
|
|
CPlacement3D(iten->GetPlacement().pl_PositionVector, aAngle));
|
|
|
|
|
// set angle3d vector's stretch factor
|
|
|
|
|
FLOATaabbox3D box;
|
|
|
|
|
iten->GetSize(box);
|
|
|
|
|
FLOAT fStretch = box.Size().Length();
|
|
|
|
|
theApp.m_pAngle3DModelObject->mo_Stretch = FLOAT3D( fStretch, fStretch, fStretch);
|
|
|
|
|
// set angle3d model for rendering
|
|
|
|
|
pModelObject = theApp.m_pAngle3DModelObject;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// get editting bounding box
|
|
|
|
|
FLOATaabbox3D bbox = ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, FLOATaabbox3D);
|
|
|
|
|
// reset orientation (axes alligned bounding box !!!)
|
|
|
|
|
rmRenderModel.SetObjectPlacement(
|
|
|
|
|
CPlacement3D(iten->GetPlacement().pl_PositionVector + bbox.Min(),
|
|
|
|
|
ANGLE3D( 0, 0, 0)));
|
|
|
|
|
// set collision box's stretch factor
|
|
|
|
|
theApp.m_pBoundingBoxModelObject->mo_Stretch = bbox.Size();
|
|
|
|
|
// render black wire frame allways
|
|
|
|
|
_mrpModelRenderPrefs.SetWire( TRUE);
|
|
|
|
|
_mrpModelRenderPrefs.SetInkColor( C_BLACK);
|
|
|
|
|
// set bounding box model for rendering
|
|
|
|
|
pModelObject = theApp.m_pBoundingBoxModelObject;
|
|
|
|
|
}
|
|
|
|
|
// set light placement
|
|
|
|
|
rmRenderModel.rm_vLightDirection = FLOAT3D(1.0f, -1.0f, 1.0f);
|
|
|
|
|
// set color of light
|
|
|
|
|
rmRenderModel.rm_colLight= C_WHITE;
|
|
|
|
|
rmRenderModel.rm_colAmbient = C_GRAY;
|
|
|
|
|
// render range sphere model
|
|
|
|
|
pModelObject->SetupModelRendering(rmRenderModel);
|
|
|
|
|
pModelObject->RenderModel(rmRenderModel);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if we should render volume box model
|
|
|
|
|
if( pDoc->m_bBrowseEntitiesMode)
|
|
|
|
|
{
|
|
|
|
|
// this model we will render
|
|
|
|
|
CModelObject *pModelObject;
|
|
|
|
|
// this render model structure will be rendered
|
|
|
|
|
CRenderModel rmRenderModel;
|
|
|
|
|
// create bbox from requested volume
|
|
|
|
|
FLOATaabbox3D bboxVolume( pDoc->m_vCreateBoxVertice0, pDoc->m_vCreateBoxVertice1);
|
|
|
|
|
// position it inside box
|
|
|
|
|
rmRenderModel.SetObjectPlacement(CPlacement3D(bboxVolume.Min(), ANGLE3D( 0, 0, 0)));
|
|
|
|
|
// set collision box's stretch factor
|
|
|
|
|
theApp.m_pBoundingBoxModelObject->mo_Stretch = bboxVolume.Size();
|
|
|
|
|
// render black wire frame allways
|
|
|
|
|
_mrpModelRenderPrefs.SetWire( TRUE);
|
|
|
|
|
_mrpModelRenderPrefs.SetHiddenLines( TRUE);
|
|
|
|
|
_mrpModelRenderPrefs.SetInkColor( C_BLACK);
|
|
|
|
|
// set bounding box model for rendering
|
|
|
|
|
pModelObject = theApp.m_pBoundingBoxModelObject;
|
|
|
|
|
// set light placement
|
|
|
|
|
rmRenderModel.rm_vLightDirection = FLOAT3D(1.0f, -1.0f, 1.0f);
|
|
|
|
|
// set color of light
|
|
|
|
|
rmRenderModel.rm_colLight= C_WHITE;
|
|
|
|
|
rmRenderModel.rm_colAmbient = C_GRAY;
|
|
|
|
|
// render bounding volume model
|
|
|
|
|
pModelObject->SetupModelRendering(rmRenderModel);
|
|
|
|
|
pModelObject->RenderModel(rmRenderModel);
|
|
|
|
|
}
|
|
|
|
|
EndModelRenderingView();
|
|
|
|
|
|
|
|
|
|
// if we should draw orientation icon, do it now because latter we may
|
|
|
|
|
// have problems due to automatic InitRenderer (in that case we would try
|
|
|
|
|
// to render icons on second layer's DrawPort, last locked, but it is allready
|
|
|
|
|
// destructed)
|
|
|
|
|
if( pDoc->m_bOrientationIcons)
|
|
|
|
|
{
|
|
|
|
|
#define XS 10
|
|
|
|
|
#define YS 16
|
|
|
|
|
#define DX 32
|
|
|
|
|
#define DY 32
|
|
|
|
|
|
|
|
|
|
PIXaabbox2D boxScreen(PIX2D(XS, YS), PIX2D(XS+DX, YS+DY));
|
|
|
|
|
|
|
|
|
|
// choose view's orientation icon index
|
|
|
|
|
INDEX iIcon = 0;
|
|
|
|
|
CTString strView="None";
|
|
|
|
|
CTString strU="?";
|
|
|
|
|
CTString strV="?";
|
|
|
|
|
switch( m_ptProjectionType)
|
|
|
|
|
{
|
|
|
|
|
case CSlaveViewer::PT_PERSPECTIVE: { iIcon = 0; strView="persp"; strU=""; strV=""; break;}
|
|
|
|
|
case CSlaveViewer::PT_ISOMETRIC_FRONT: { iIcon = 5; strView="front"; strU="x"; strV="y"; break;}
|
|
|
|
|
case CSlaveViewer::PT_ISOMETRIC_RIGHT: { iIcon = 3; strView="right"; strU="-z"; strV="y"; break;}
|
|
|
|
|
case CSlaveViewer::PT_ISOMETRIC_TOP: { iIcon = 1; strView="top"; strU="x"; strV="-z"; break;}
|
|
|
|
|
case CSlaveViewer::PT_ISOMETRIC_BACK: { iIcon = 6; strView="back"; strU="-x"; strV="y"; break;}
|
|
|
|
|
case CSlaveViewer::PT_ISOMETRIC_LEFT: { iIcon = 4; strView="left"; strU="z"; strV="y"; break;}
|
|
|
|
|
case CSlaveViewer::PT_ISOMETRIC_BOTTOM: { iIcon = 2; strView="bottom"; strU="x"; strV="z"; break;}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MEXaabbox2D boxTexture(MEX2D(iIcon*DX, 0), MEX2D((iIcon+1)*DX, DY));
|
|
|
|
|
|
|
|
|
|
// render icon
|
|
|
|
|
CTextureObject toIcon;
|
|
|
|
|
toIcon.SetData( theApp.m_pViewIconsTD);
|
|
|
|
|
pDP->PutTexture(&toIcon, boxScreen, boxTexture);
|
|
|
|
|
|
|
|
|
|
PIX2D pixCenter=PIX2D( pDP->GetWidth()*0.03f, pDP->GetHeight()*0.97f);
|
|
|
|
|
DrawAxis( pixCenter, 40, C_BLUE|CT_OPAQUE, C_RED|CT_OPAQUE, strU, strV);
|
|
|
|
|
|
|
|
|
|
pDP->SetFont( _pfdConsoleFont);
|
|
|
|
|
pDP->SetTextAspect( 1.0f);
|
|
|
|
|
pDP->SetTextScaling( 1.0f);
|
|
|
|
|
pDP->PutTextCXY( strView, XS+DX/2, YS/2, C_RED|CT_OPAQUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pDP->BlendScreen();
|
|
|
|
|
|
|
|
|
|
// if second layer's world exists
|
|
|
|
|
if( pDoc->m_pwoSecondLayer != NULL)
|
|
|
|
|
{
|
|
|
|
|
// prepare second layer's projection ...
|
|
|
|
|
// get viewer placement from first layer
|
|
|
|
|
CPlacement3D plVirtualViewer = prProjection->ViewerPlacementR();
|
|
|
|
|
// transform it to the system of the second layer
|
|
|
|
|
plVirtualViewer.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
// use it in projection for second layer
|
|
|
|
|
CAnyProjection3D prProjectionSecondLayer;
|
|
|
|
|
prProjectionSecondLayer = prProjection;
|
|
|
|
|
prProjectionSecondLayer->ViewerPlacementL() = plVirtualViewer;
|
|
|
|
|
prProjectionSecondLayer->Prepare();
|
|
|
|
|
|
|
|
|
|
// if we will not use any kind of polygon filling
|
|
|
|
|
if( !bPolygonFillOn)
|
|
|
|
|
{
|
|
|
|
|
// render scene directly into primary draw port
|
|
|
|
|
::RenderView( *pDoc->m_pwoSecondLayer, *(CEntity*) NULL,
|
|
|
|
|
prProjectionSecondLayer, *pDP);
|
|
|
|
|
}
|
|
|
|
|
// if filling, create drawport for second layer and create picture using CopyViaZBuffer
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// disable shadow rendering on world in second layer
|
|
|
|
|
_wrpWorldRenderPrefs.SetShadowsType( CWorldRenderPrefs::SHT_NONE);
|
|
|
|
|
|
|
|
|
|
// set that we will rendering scene over allready rendered scene
|
|
|
|
|
pDP->SetOverlappedRendering(TRUE);
|
|
|
|
|
// render second layer's scene over already rendered scene using filled z-buffer
|
|
|
|
|
::RenderView( *pDoc->m_pwoSecondLayer, *(CEntity*) NULL, prProjectionSecondLayer, *pDP);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if we are in triangularisation primitive mode
|
|
|
|
|
if( (pDoc->m_bPrimitiveMode) &&
|
|
|
|
|
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) )
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Lock();
|
|
|
|
|
CDynamicArray<CObjectVertex> &aVtx = theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors[0].osc_aovxVertices;
|
|
|
|
|
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Unlock();
|
|
|
|
|
|
|
|
|
|
aVtx.Lock();
|
|
|
|
|
// render all selected vertices as boxes
|
|
|
|
|
for( INDEX iVtx=0; iVtx<aVtx.Count(); iVtx++)
|
|
|
|
|
{
|
|
|
|
|
if( aVtx[ iVtx].ovx_ulFlags & OVXF_SELECTED)
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D vProjected;
|
|
|
|
|
// project vertice
|
|
|
|
|
prProjectionSecondLayer->ProjectCoordinate( DOUBLEtoFLOAT(aVtx[ iVtx]), vProjected);
|
|
|
|
|
// convert y coordinate from mathemathical representation into screen one
|
|
|
|
|
vProjected(2) = pDP->GetHeight() - vProjected(2);
|
|
|
|
|
pDP->Fill( (SLONG)vProjected(1)-3, (SLONG)vProjected(2)-3, 6, 6, C_BLACK|CT_OPAQUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
aVtx.Unlock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if cut mode on, this isn't perspective view, and cut line modification has been performed on this view
|
|
|
|
|
if( theApp.m_bCutModeOn && !bPerspectiveOn && ( pDoc->m_pCutLineView == this))
|
|
|
|
|
{
|
|
|
|
|
// render cut line
|
|
|
|
|
FLOAT3D v0 = pDoc->m_vCutLineStart;
|
|
|
|
|
FLOAT3D v1 = pDoc->m_vCutLineEnd;
|
|
|
|
|
FLOAT3D vp0;
|
|
|
|
|
FLOAT3D vp1;
|
|
|
|
|
// create a projection for current viewer
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
|
|
|
|
|
prProjection->ProjectCoordinate( v0, vp0);
|
|
|
|
|
prProjection->ProjectCoordinate( v1, vp1);
|
|
|
|
|
|
|
|
|
|
// convert y coordinates into view space
|
|
|
|
|
vp0(2) = pDP->GetHeight()-vp0(2);
|
|
|
|
|
vp1(2) = pDP->GetHeight()-vp1(2);
|
|
|
|
|
|
|
|
|
|
PIX x1 = (PIX)vp0(1);
|
|
|
|
|
PIX y1 = (PIX)vp0(2);
|
|
|
|
|
PIX x2 = (PIX)vp1(1);
|
|
|
|
|
PIX y2 = (PIX)vp1(2);
|
|
|
|
|
|
|
|
|
|
// spread cut line (using parametric line representation) to edges of the draw port
|
|
|
|
|
FLOAT dx = x2-x1;
|
|
|
|
|
FLOAT dy = y2-y1;
|
|
|
|
|
|
|
|
|
|
FLOAT fT[4];
|
|
|
|
|
fT[0] = (0-x1)/dx;
|
|
|
|
|
fT[1] = (pDP->GetWidth()-x1)/dx;
|
|
|
|
|
fT[2] = (0-y1)/dy;
|
|
|
|
|
fT[3] = (pDP->GetHeight()-y1)/dy;
|
|
|
|
|
|
|
|
|
|
// find smallest T greater than 0 and biggest T less than 0
|
|
|
|
|
FLOAT fMaxNegT = -9999999.0f;
|
|
|
|
|
FLOAT fMinPosT = 9999999.0f;
|
|
|
|
|
for( INDEX iT=0; iT<4; iT++)
|
|
|
|
|
{
|
|
|
|
|
if(fT[iT]>1)
|
|
|
|
|
{
|
|
|
|
|
if(fT[iT]<fMinPosT)
|
|
|
|
|
{
|
|
|
|
|
fMinPosT = fT[iT];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(fT[iT]<0)
|
|
|
|
|
{
|
|
|
|
|
if(fT[iT]>fMaxNegT)
|
|
|
|
|
{
|
|
|
|
|
fMaxNegT = fT[iT];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// calculate border coordinates for found two T values
|
|
|
|
|
PIX xb1 = (PIX) x1+dx*fMaxNegT;
|
|
|
|
|
PIX xb2 = (PIX) x1+dx*fMinPosT;
|
|
|
|
|
PIX yb1 = (PIX) y1+dy*fMaxNegT;
|
|
|
|
|
PIX yb2 = (PIX) y1+dy*fMinPosT;
|
|
|
|
|
|
|
|
|
|
// draw cut line
|
|
|
|
|
COLOR colCutBorderLine = C_RED|CT_OPAQUE;
|
|
|
|
|
pDP->DrawLine( xb1, yb1, xb2, yb2, colCutBorderLine, _TY124_);
|
|
|
|
|
|
|
|
|
|
// draw control point lines
|
|
|
|
|
COLOR colControl = C_BLACK|CT_OPAQUE;
|
|
|
|
|
pDP->DrawLine( x1-3, y1-3, x1+3, y1+3, colControl);
|
|
|
|
|
pDP->DrawLine( x1+3, y1-3, x1-3, y1+3, colControl);
|
|
|
|
|
pDP->DrawLine( x2-3, y2-3, x2+3, y2+3, colControl);
|
|
|
|
|
pDP->DrawLine( x2+3, y2-3, x2-3, y2+3, colControl);
|
|
|
|
|
}
|
|
|
|
|
// if measure mode on
|
|
|
|
|
if( m_iaInputAction == IA_MEASURING)
|
|
|
|
|
{
|
|
|
|
|
// calculate placement for mouse down
|
|
|
|
|
CPlacement3D plMouseDown;
|
|
|
|
|
// obtain information about where mouse pointed into the world in the moment of mouse down
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouseDown);
|
|
|
|
|
plMouseDown.pl_PositionVector = crRayHit.cr_vHit;
|
|
|
|
|
pDoc->SnapToGrid( plMouseDown, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
|
|
|
|
|
// calculate placement for current mouse position
|
|
|
|
|
CPlacement3D plCurrentMousePos;
|
|
|
|
|
// obtain information about where mouse points into the world right now
|
|
|
|
|
crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
plCurrentMousePos.pl_PositionVector = crRayHit.cr_vHit;
|
|
|
|
|
// snap to grid curent mouse placement
|
|
|
|
|
pDoc->SnapToGrid( plCurrentMousePos, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
|
|
|
|
|
// construct bbox containing both points
|
|
|
|
|
FLOATaabbox3D bbox( plMouseDown.pl_PositionVector);
|
|
|
|
|
bbox |= FLOATaabbox3D( plCurrentMousePos.pl_PositionVector);
|
|
|
|
|
|
|
|
|
|
FLOAT3D vCenter = plMouseDown.pl_PositionVector;
|
|
|
|
|
FLOAT3D vUp = plMouseDown.pl_PositionVector;
|
|
|
|
|
FLOAT3D vRight = plMouseDown.pl_PositionVector;
|
|
|
|
|
FLOAT3D vForward = plMouseDown.pl_PositionVector;
|
|
|
|
|
|
|
|
|
|
vUp(2) = plCurrentMousePos.pl_PositionVector(2);
|
|
|
|
|
vRight(1) = plCurrentMousePos.pl_PositionVector(1);
|
|
|
|
|
vForward(3) = plCurrentMousePos.pl_PositionVector(3);
|
|
|
|
|
|
|
|
|
|
// prepare font
|
|
|
|
|
pDP->SetFont( theApp.m_pfntSystem);
|
|
|
|
|
pDP->SetTextAspect( 1.0f);
|
|
|
|
|
pDP->SetTextScaling( 1.0f);
|
|
|
|
|
|
|
|
|
|
CTString strText;
|
|
|
|
|
strText.PrintF( "%g", bbox.Size()(1));
|
|
|
|
|
DrawArrowAndTypeText( *prProjection, vCenter, vRight, C_BLUE|CT_OPAQUE, strText);
|
|
|
|
|
strText.PrintF( "%g", bbox.Size()(2));
|
|
|
|
|
DrawArrowAndTypeText( *prProjection, vCenter, vUp, C_BLUE|CT_OPAQUE, strText);
|
|
|
|
|
strText.PrintF( "%g", bbox.Size()(3));
|
|
|
|
|
DrawArrowAndTypeText( *prProjection, vCenter, vForward, C_BLUE|CT_OPAQUE, strText);
|
|
|
|
|
|
|
|
|
|
// in orto projections, draw diagonal line
|
|
|
|
|
if( m_ptProjectionType != CSlaveViewer::PT_PERSPECTIVE)
|
|
|
|
|
{
|
|
|
|
|
//strText.PrintF( "%g", bbox.Size().Length());
|
|
|
|
|
DrawArrowAndTypeText( *prProjection,
|
|
|
|
|
plMouseDown.pl_PositionVector,
|
|
|
|
|
plCurrentMousePos.pl_PositionVector, C_lGRAY|CT_OPAQUE, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_strMeasuring.PrintF( "Distance: %g", bbox.Size().Length());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// test string
|
|
|
|
|
if( m_strTest!="")
|
|
|
|
|
{
|
|
|
|
|
pDP->SetFont( theApp.m_pfntSystem);
|
|
|
|
|
pDP->SetTextScaling( 1.0f);
|
|
|
|
|
pDP->SetTextAspect( 1.0f);
|
|
|
|
|
pDP->PutText( m_strTest, 32, 32);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static TIME tmSwapBuffers = 0;
|
|
|
|
|
extern BOOL _bInOnDraw = FALSE;
|
|
|
|
|
void CWorldEditorView::OnDraw(CDC* pDC)
|
|
|
|
|
{
|
|
|
|
|
// skip if already drawing
|
|
|
|
|
if( _bInOnDraw) return;
|
|
|
|
|
_bInOnDraw = TRUE;
|
|
|
|
|
|
|
|
|
|
// get some view variables
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
|
|
|
|
|
BOOL bPerspectiveOn = m_ptProjectionType == CSlaveViewer::PT_PERSPECTIVE;
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
CViewPort *pvpValidViewPort = GetViewPort();
|
|
|
|
|
|
|
|
|
|
// if there is a valid drawport, and the drawport can be locked
|
|
|
|
|
if( pdpValidDrawPort!=NULL && pdpValidDrawPort->Lock())
|
|
|
|
|
{
|
|
|
|
|
// variable to recive start time
|
|
|
|
|
CTimerValue tvStart = _pTimer->GetHighPrecisionTimer();
|
|
|
|
|
// render view
|
|
|
|
|
RenderView( pdpValidDrawPort);
|
|
|
|
|
// obtain stop time
|
|
|
|
|
CTimerValue tvStop = _pTimer->GetHighPrecisionTimer();
|
|
|
|
|
// number telling how many miliseconds passed
|
|
|
|
|
TIME tmDelta = (tvStop-tvStart).GetSeconds() +tmSwapBuffers;
|
|
|
|
|
|
|
|
|
|
// mark that view has been changed
|
|
|
|
|
m_chViewChanged.MarkChanged();
|
|
|
|
|
|
|
|
|
|
// if we can and should print any kind of frame rate descriptive message
|
|
|
|
|
if( !bCSGOn && bPerspectiveOn && GetChildFrame()->m_bSceneRenderingTime)
|
|
|
|
|
{
|
|
|
|
|
// prepare string about things that impact to currently rendered picture
|
|
|
|
|
CTString strFPS, strReport;
|
|
|
|
|
STAT_Report(strReport);
|
|
|
|
|
STAT_Reset();
|
|
|
|
|
// adjust and set font
|
|
|
|
|
pdpValidDrawPort->SetFont( _pfdConsoleFont);
|
|
|
|
|
pdpValidDrawPort->SetTextScaling( 1.0f);
|
|
|
|
|
// put filter
|
|
|
|
|
PIX pixDPHeight = pdpValidDrawPort->GetHeight();
|
|
|
|
|
pdpValidDrawPort->Fill( 0,0, 150,pixDPHeight, C_BLACK|128, C_BLACK|0, C_BLACK|192, C_BLACK|0);
|
|
|
|
|
// printout statistics
|
|
|
|
|
strFPS.PrintF( " %3.0f FPS (%2.0f ms)\n----------------\n", 1.0f/tmDelta, tmDelta*1000.0f);
|
|
|
|
|
pdpValidDrawPort->PutText( strFPS, 0, 5, C_lCYAN|CT_OPAQUE);
|
|
|
|
|
pdpValidDrawPort->PutText( strReport, 4, 30, C_GREEN|CT_OPAQUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// unlock the drawport
|
|
|
|
|
pdpValidDrawPort->Unlock();
|
|
|
|
|
|
|
|
|
|
// swap if there is a valid viewport
|
|
|
|
|
if( pvpValidViewPort!=NULL) {
|
|
|
|
|
tvStart = _pTimer->GetHighPrecisionTimer();
|
|
|
|
|
pvpValidViewPort->SwapBuffers();
|
|
|
|
|
tvStop = _pTimer->GetHighPrecisionTimer();
|
|
|
|
|
tmSwapBuffers = (tvStop-tvStart).GetSeconds();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// all done
|
|
|
|
|
_bInOnDraw = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// CWorldEditorView diagnostics
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
void CWorldEditorView::AssertValid() const
|
|
|
|
|
{
|
|
|
|
|
CView::AssertValid();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::Dump(CDumpContext& dc) const
|
|
|
|
|
{
|
|
|
|
|
CView::Dump(dc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* CWorldEditorView::GetDocument() // non-debug version is inline
|
|
|
|
|
{
|
|
|
|
|
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CWorldEditorDoc)));
|
|
|
|
|
return (CWorldEditorDoc*)m_pDocument;
|
|
|
|
|
}
|
|
|
|
|
#endif //_DEBUG
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// CWorldEditorView message handlers
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnInitialUpdate()
|
|
|
|
|
{
|
|
|
|
|
CView::OnInitialUpdate();
|
|
|
|
|
|
|
|
|
|
// allow file drop
|
|
|
|
|
DragAcceptFiles();
|
|
|
|
|
|
|
|
|
|
// at this time, m_hWnd is valid, so we do canvas initialization here
|
|
|
|
|
_pGfx->CreateWindowCanvas(m_hWnd, &m_pvpViewPort, &m_pdpDrawPort);
|
|
|
|
|
|
|
|
|
|
// get active view
|
|
|
|
|
CWorldEditorView *pWorldEditorView = theApp.GetActiveView();
|
|
|
|
|
|
|
|
|
|
if( (pWorldEditorView != NULL) && (pWorldEditorView != this)
|
|
|
|
|
&& (theApp.m_Preferences.ap_CopyExistingWindowPrefs) )
|
|
|
|
|
{
|
|
|
|
|
m_IsWinBcgTexture = pWorldEditorView->m_IsWinBcgTexture;
|
|
|
|
|
m_fnWinBcgTexture = pWorldEditorView->m_fnWinBcgTexture;
|
|
|
|
|
m_SelectionColor = pWorldEditorView->m_SelectionColor;
|
|
|
|
|
m_PaperColor = pWorldEditorView->m_PaperColor;
|
|
|
|
|
m_InkColor = pWorldEditorView->m_InkColor;
|
|
|
|
|
CChildFrame *pcfThis = GetChildFrame();
|
|
|
|
|
CChildFrame *pcfOld = pWorldEditorView->GetChildFrame();
|
|
|
|
|
if( pcfThis != pcfOld)
|
|
|
|
|
{
|
|
|
|
|
pcfThis->m_mvViewer = pcfOld->m_mvViewer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_IsWinBcgTexture = FALSE;
|
|
|
|
|
m_SelectionColor = theApp.m_Preferences.ap_DefaultSelectionColor;
|
|
|
|
|
m_PaperColor = theApp.m_Preferences.ap_DefaultPaperColor;
|
|
|
|
|
m_InkColor = theApp.m_Preferences.ap_DefaultInkColor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( theApp.m_Preferences.ap_SetDefaultColors)
|
|
|
|
|
{
|
|
|
|
|
m_SelectionColor = CLRF_CLR( theApp.m_Preferences.ap_DefaultSelectionColor);
|
|
|
|
|
m_PaperColor = CLRF_CLR( theApp.m_Preferences.ap_DefaultPaperColor);
|
|
|
|
|
m_InkColor = CLRF_CLR( theApp.m_Preferences.ap_DefaultInkColor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSize(UINT nType, int cx, int cy)
|
|
|
|
|
{
|
|
|
|
|
CView::OnSize(nType, cx, cy);
|
|
|
|
|
|
|
|
|
|
// if we are not in game mode and changing of display mode is not on
|
|
|
|
|
if( !theApp.m_bChangeDisplayModeInProgress)
|
|
|
|
|
{ // and window canvas is valid
|
|
|
|
|
if( m_pvpViewPort!=NULL)
|
|
|
|
|
{ // resize it
|
|
|
|
|
m_pvpViewPort->Resize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int CWorldEditorView::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
|
|
|
{
|
|
|
|
|
if (CView::OnCreate(lpCreateStruct) == -1)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
// register drop target
|
|
|
|
|
m_DropTarget.Register(this);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get the pointer to the main frame object of this application
|
|
|
|
|
*/
|
|
|
|
|
CMainFrame *CWorldEditorView::GetMainFrame()
|
|
|
|
|
{
|
|
|
|
|
// get the MDIChildFrame of this window
|
|
|
|
|
CChildFrame *pfrChild = (CChildFrame *)this->GetParentFrame();
|
|
|
|
|
ASSERT(pfrChild!=NULL);
|
|
|
|
|
// get the MDIFrameWnd
|
|
|
|
|
CMainFrame *pfrMain = (CMainFrame *)pfrChild->GetParentFrame();
|
|
|
|
|
ASSERT(pfrMain!=NULL);
|
|
|
|
|
|
|
|
|
|
return pfrMain;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKillFocus(CWnd* pNewWnd)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_NONE;
|
|
|
|
|
// discard laso selection
|
|
|
|
|
m_avpixLaso.Clear();
|
|
|
|
|
CView::OnKillFocus(pNewWnd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnActivateView(BOOL bActivate,
|
|
|
|
|
CView* pActivateView, CView* pDeactiveView)
|
|
|
|
|
{
|
|
|
|
|
// if new view's document is not same as last activated document and if document is
|
|
|
|
|
// beiing activated
|
|
|
|
|
if( (pActivateView != NULL) &&
|
|
|
|
|
(pActivateView->GetDocument() != theApp.GetLastActivatedDocument()) &&
|
|
|
|
|
(bActivate) &&
|
|
|
|
|
(pActivateView->GetDocument() != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// mark that we are in crossing fase of switching documents if anybody searches for
|
|
|
|
|
// document, he will get NULL
|
|
|
|
|
theApp.m_bDocumentChangeOn = TRUE;
|
|
|
|
|
// force OnIdle so info and combos will adjust to situation when doc = NULL
|
|
|
|
|
theApp.OnIdle( 0);
|
|
|
|
|
// finish crossing fase, continue "normal" behaviour
|
|
|
|
|
theApp.m_bDocumentChangeOn = FALSE;
|
|
|
|
|
}
|
|
|
|
|
// mark that new document will be activated
|
|
|
|
|
theApp.ActivateDocument(GetDocument());
|
|
|
|
|
|
|
|
|
|
CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL MyChooseColor( COLORREF &clrNewColor, CWnd &wndOwner)
|
|
|
|
|
{
|
|
|
|
|
COLORREF MyCustColors[ 16];
|
|
|
|
|
CHOOSECOLOR ccInit;
|
|
|
|
|
|
|
|
|
|
ASSERT( &wndOwner != NULL);
|
|
|
|
|
MyCustColors[ 0] = CLRF_CLR(C_BLACK);
|
|
|
|
|
MyCustColors[ 1] = CLRF_CLR(C_WHITE);
|
|
|
|
|
MyCustColors[ 2] = CLRF_CLR(C_dGRAY);
|
|
|
|
|
MyCustColors[ 3] = CLRF_CLR(C_GRAY);
|
|
|
|
|
MyCustColors[ 4] = CLRF_CLR(C_lGRAY);
|
|
|
|
|
MyCustColors[ 5] = CLRF_CLR(C_dRED);
|
|
|
|
|
MyCustColors[ 6] = CLRF_CLR(C_dGREEN);
|
|
|
|
|
MyCustColors[ 7] = CLRF_CLR(C_dBLUE);
|
|
|
|
|
MyCustColors[ 8] = CLRF_CLR(C_dCYAN);
|
|
|
|
|
MyCustColors[ 9] = CLRF_CLR(C_dMAGENTA);
|
|
|
|
|
MyCustColors[10] = CLRF_CLR(C_dYELLOW);
|
|
|
|
|
MyCustColors[11] = CLRF_CLR(C_dORANGE);
|
|
|
|
|
MyCustColors[12] = CLRF_CLR(C_dBROWN);
|
|
|
|
|
MyCustColors[13] = CLRF_CLR(C_dPINK);
|
|
|
|
|
MyCustColors[14] = CLRF_CLR(C_lORANGE);
|
|
|
|
|
MyCustColors[15] = CLRF_CLR(C_lBROWN);
|
|
|
|
|
|
|
|
|
|
memset(&ccInit, 0, sizeof(CHOOSECOLOR));
|
|
|
|
|
|
|
|
|
|
ccInit.lStructSize = sizeof(CHOOSECOLOR);
|
|
|
|
|
ccInit.Flags = CC_RGBINIT | CC_FULLOPEN;
|
|
|
|
|
ccInit.rgbResult = clrNewColor;
|
|
|
|
|
ccInit.lpCustColors = &MyCustColors[ 0];
|
|
|
|
|
ccInit.hwndOwner = wndOwner.m_hWnd;
|
|
|
|
|
|
|
|
|
|
if( !ChooseColor( &ccInit))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
clrNewColor = ccInit.rgbResult;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns eather perspective view's or manual mip factor
|
|
|
|
|
FLOAT CWorldEditorView::GetCurrentlyActiveMipFactor(void)
|
|
|
|
|
{
|
|
|
|
|
// get document
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
|
|
|
|
|
CEntity *penBrush = pMainFrame->m_CSGDesitnationCombo.GetSelectedBrushEntity();
|
|
|
|
|
// get draw port
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
if((GetChildFrame()->m_bAutoMipBrushingOn) &&
|
|
|
|
|
(penBrush != NULL) &&
|
|
|
|
|
(pdpValidDrawPort != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// get entity's brush
|
|
|
|
|
CBrush3D *pbrBrush = penBrush->GetBrush();
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, CSlaveViewer::PT_PERSPECTIVE,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
// create a projection for slave viewer
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
prProjection->ObjectPlacementL() = penBrush->GetPlacement();
|
|
|
|
|
// prepare the projection
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
// return mip factor for entity in perspective projection
|
|
|
|
|
return( -prProjection->pr_TranslationVector(3));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return (GetChildFrame()->m_fManualMipBrushingFactor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
|
|
|
{
|
|
|
|
|
// find window under mouse pointer
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->SetStatusLineModeInfoMessage();
|
|
|
|
|
|
|
|
|
|
POINT point;
|
|
|
|
|
GetCursorPos(&point);
|
|
|
|
|
HWND hwndUnderMouse = ::WindowFromPoint( point);
|
|
|
|
|
|
|
|
|
|
// if not this one (use parent because gfx-API child is over the window)
|
|
|
|
|
if (m_hWnd != ::GetParent(hwndUnderMouse)) {
|
|
|
|
|
// ignore the key
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CView::OnKeyDown( nChar, nRepCnt, nFlags);
|
|
|
|
|
BOOL bShift = (GetKeyState(VK_SHIFT) &0x8000) != 0;
|
|
|
|
|
BOOL bCtrl = (GetKeyState(VK_CONTROL)&0x8000) != 0;
|
|
|
|
|
BOOL bAlt = (GetKeyState(VK_MENU) &0x8000) != 0;
|
|
|
|
|
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
|
|
|
|
|
BOOL bLMB = (GetKeyState( VK_LBUTTON)&0x8000) != 0;
|
|
|
|
|
|
|
|
|
|
if(bLMB && !bAlt && (pDoc->GetEditingMode()==TERRAIN_MODE) && !bSpace)
|
|
|
|
|
{
|
|
|
|
|
if( bCtrl) m_iaInputAction=IA_TERRAIN_EDITING_CTRL_LMB;
|
|
|
|
|
else m_iaInputAction=IA_TERRAIN_EDITING_LMB;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// tool tips are on when you press I
|
|
|
|
|
if( (GetKeyState('I')&0x80) && !(bShift|bCtrl|bAlt)) {
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
// if info doesn't yet exist
|
|
|
|
|
if( pMainFrame->m_pwndToolTip == NULL)
|
|
|
|
|
{ // force it
|
|
|
|
|
theApp.m_cttToolTips.ManualOn( m_ptMouse.x, m_ptMouse.y, &::GetToolTipText, this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// call parent's key pressed function
|
|
|
|
|
GetChildFrame()->KeyPressed( nChar, nRepCnt, nFlags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->SetStatusLineModeInfoMessage();
|
|
|
|
|
|
|
|
|
|
// if we are in mip mode for setting, set new brush switch factor
|
|
|
|
|
if( m_iaInputAction == IA_MIP_SETTING)
|
|
|
|
|
{
|
|
|
|
|
SetMipBrushFactor();
|
|
|
|
|
}
|
|
|
|
|
BOOL bCtrl = (GetKeyState(VK_CONTROL)&0x8000) != 0;
|
|
|
|
|
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
|
|
|
|
|
BOOL bLMB = (GetKeyState( VK_LBUTTON)&0x8000) != 0;
|
|
|
|
|
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
|
|
|
|
|
|
|
|
|
|
if(bLMB && !bAlt && (pDoc->GetEditingMode()==TERRAIN_MODE) && !bSpace)
|
|
|
|
|
{
|
|
|
|
|
if( bCtrl) m_iaInputAction=IA_TERRAIN_EDITING_CTRL_LMB;
|
|
|
|
|
else m_iaInputAction=IA_TERRAIN_EDITING_LMB;
|
|
|
|
|
_tvLastTerrainBrushingApplied=_pTimer->GetHighPrecisionTimer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// shut down tool tips
|
|
|
|
|
theApp.m_cttToolTips.ManualOff();
|
|
|
|
|
|
|
|
|
|
CView::OnKeyUp(nChar, nRepCnt, nFlags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::SetMipBrushFactor(void)
|
|
|
|
|
{
|
|
|
|
|
// remember current time as time when last mip brushing option has been used
|
|
|
|
|
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
|
|
|
|
|
|
|
|
|
|
CChildFrame *pChild = GetChildFrame();
|
|
|
|
|
// set auto mip brushing mode on
|
|
|
|
|
pChild->m_bAutoMipBrushingOn = TRUE;
|
|
|
|
|
// get auto mip factor
|
|
|
|
|
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
|
|
|
|
|
pChild->m_bAutoMipBrushingOn = pChild->m_bLastAutoMipBrushingOn;
|
|
|
|
|
// set auto mip brushing mode as it was before mip setting started
|
|
|
|
|
ASSERT( m_pbmToSetMipSwitch != NULL);
|
|
|
|
|
// set new mip switch factor
|
|
|
|
|
m_pbmToSetMipSwitch->SetMipDistance( fCurrentMipFactor-0.01f);
|
|
|
|
|
// switch back to auto mip brushing mode
|
|
|
|
|
GetChildFrame()->m_bAutoMipBrushingOn = TRUE;
|
|
|
|
|
|
|
|
|
|
// get document
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// document has changed
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
m_iaInputAction = IA_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::StartMouseInput( CPoint point)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
|
|
|
|
|
|
|
|
|
|
pDoc->UpdateAllViews(NULL);
|
|
|
|
|
// reset offseted placement
|
|
|
|
|
m_plMouseOffset.pl_PositionVector = FLOAT3D(0.0f, 0.0f, 0.0f);
|
|
|
|
|
m_plMouseOffset.pl_OrientationAngle = ANGLE3D(0, 0, 0);
|
|
|
|
|
// if there is CSG operation active
|
|
|
|
|
if( bCSGOn)
|
|
|
|
|
{
|
|
|
|
|
// copy original layer's placement because we need to perform "continous moving"
|
|
|
|
|
m_plMouseMove = pDoc->m_plSecondLayer;
|
|
|
|
|
}
|
|
|
|
|
// otherwise if we are in entity mode and there is at least 1 entity selected
|
|
|
|
|
else if( pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
if(pDoc->m_selEntitySelection.Count()==0)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_aSelectedEntityPlacements.Clear();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FLOATaabbox3D box;
|
|
|
|
|
CPlacement3D plEntityCenter;
|
|
|
|
|
plEntityCenter = CPlacement3D( FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// accumulate positions
|
|
|
|
|
box |= iten->GetPlacement().pl_PositionVector;
|
|
|
|
|
//plEntityCenter.pl_OrientationAngle += iten->GetPlacement().pl_OrientationAngle;
|
|
|
|
|
}}
|
|
|
|
|
plEntityCenter.pl_PositionVector = box.Center();
|
|
|
|
|
plEntityCenter.pl_PositionVector(2) = box.Min()(2);
|
|
|
|
|
// calculate average rotation
|
|
|
|
|
//plEntityCenter.pl_OrientationAngle /= (ANGLE)pDoc->m_selEntitySelection.Count();
|
|
|
|
|
// remember
|
|
|
|
|
pDoc->m_aSelectedEntityPlacements.Clear();
|
|
|
|
|
pDoc->m_aSelectedEntityPlacements.New(pDoc->m_selEntitySelection.Count());
|
|
|
|
|
INDEX ienCurrent = 0;
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CPlacement3D plRelative = iten->GetPlacement();
|
|
|
|
|
plRelative.AbsoluteToRelativeSmooth(plEntityCenter);
|
|
|
|
|
pDoc->m_aSelectedEntityPlacements[ ienCurrent] = plRelative;
|
|
|
|
|
ienCurrent++;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// copy it's placement for continous moving
|
|
|
|
|
m_plMouseMove = plEntityCenter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == VERTEX_MODE)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_avStartDragVertices.Clear();
|
|
|
|
|
INDEX ctDragVertices = pDoc->m_selVertexSelection.Count();
|
|
|
|
|
if( ctDragVertices != 0)
|
|
|
|
|
{
|
|
|
|
|
// remember coordinates of vertices for dragging
|
|
|
|
|
pDoc->m_avStartDragVertices.New(ctDragVertices);
|
|
|
|
|
INDEX iVtx = 0;
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_avStartDragVertices[ iVtx] = FLOATtoDOUBLE( itbvx->bvx_vAbsolute);
|
|
|
|
|
iVtx++;
|
|
|
|
|
}}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// copy mouse point to both point for calculating relative (from last mouse position) and
|
|
|
|
|
// absolute (from mouse down position) distances
|
|
|
|
|
m_ptMouse = point;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::StopMouseInput(void)
|
|
|
|
|
{
|
|
|
|
|
// update all views when current view stopped modifying
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// obtain information about what was hitted with mouse
|
|
|
|
|
CCastRay CWorldEditorView::GetMouseHitInformation( CPoint point,
|
|
|
|
|
BOOL bHitPortals /* = FALSE */,
|
|
|
|
|
BOOL bHitModels /* = TRUE */,
|
|
|
|
|
BOOL bHitFields /* = FALSE */,
|
|
|
|
|
CEntity *penSourceEntity /* = NULL */,
|
|
|
|
|
BOOL bHitBrushes /* = TRUE */)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
// get draw port
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
// if it is not valid
|
|
|
|
|
if( pdpValidDrawPort == NULL)
|
|
|
|
|
{
|
|
|
|
|
// return dummy result
|
|
|
|
|
return CCastRay( NULL, CPlacement3D(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0)) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// obtain viewer placement
|
|
|
|
|
CPlacement3D plViewer = GetChildFrame()->m_mvViewer.GetViewerPlacement();
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
|
|
|
|
|
// now we will try to obtain where mouse poonts to in the base world
|
|
|
|
|
// create a projection for current viewer
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
// make the ray from viewer point through the mouse point, in current projection
|
|
|
|
|
CPlacement3D plRay;
|
|
|
|
|
prProjection->RayThroughPoint(FLOAT3D((float)point.x,
|
|
|
|
|
pdpValidDrawPort->GetHeight()-(float)point.y, 0.0f), plRay);
|
|
|
|
|
// construct cast ray for base world
|
|
|
|
|
CCastRay crBaseWorldCastResult( penSourceEntity, plRay);
|
|
|
|
|
// set portal "transparency" or "hitability" for hit beam
|
|
|
|
|
crBaseWorldCastResult.cr_bHitPortals = bHitPortals;
|
|
|
|
|
// set hitability for models
|
|
|
|
|
if( (m_vpViewPrefs.m_mrpModelRenderPrefs.GetRenderType() & RT_TEXTURE) && bHitModels)
|
|
|
|
|
{
|
|
|
|
|
crBaseWorldCastResult.cr_ttHitModels = CCastRay::TT_FULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
crBaseWorldCastResult.cr_ttHitModels = CCastRay::TT_NONE;
|
|
|
|
|
}
|
|
|
|
|
crBaseWorldCastResult.cr_bHitFields = bHitFields;
|
|
|
|
|
crBaseWorldCastResult.cr_bHitBrushes = bHitBrushes;
|
|
|
|
|
// cast ray, go for hit data
|
|
|
|
|
pDoc->m_woWorld.CastRay( crBaseWorldCastResult);
|
|
|
|
|
|
|
|
|
|
// if second layer's world exist
|
|
|
|
|
if( pDoc->m_pwoSecondLayer != NULL)
|
|
|
|
|
{
|
|
|
|
|
// prepare second layer's projection ...
|
|
|
|
|
// get viewer placement from first layer
|
|
|
|
|
CPlacement3D plVirtualViewer = prProjection->ViewerPlacementR();
|
|
|
|
|
// transform it to the system of the second layer
|
|
|
|
|
plVirtualViewer.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
// use it in projection for second layer
|
|
|
|
|
CAnyProjection3D prProjectionSecondLayer;
|
|
|
|
|
prProjectionSecondLayer = prProjection;
|
|
|
|
|
prProjectionSecondLayer->ViewerPlacementL() = plVirtualViewer;
|
|
|
|
|
prProjectionSecondLayer->Prepare();
|
|
|
|
|
// calculate valid ray for second layer
|
|
|
|
|
CPlacement3D plLayerRay;
|
|
|
|
|
prProjectionSecondLayer->RayThroughPoint(FLOAT3D((float)point.x,
|
|
|
|
|
pdpValidDrawPort->GetHeight()-(float)point.y, 0.0f), plLayerRay);
|
|
|
|
|
// construct cast ray for second layer's world
|
|
|
|
|
CCastRay crLayerWorldCastResult( penSourceEntity, plLayerRay);
|
|
|
|
|
// set portal "transparency" or "hitability" for hit beam
|
|
|
|
|
crLayerWorldCastResult.cr_bHitPortals = bHitPortals;
|
|
|
|
|
// set hitability for models
|
|
|
|
|
if( m_vpViewPrefs.m_mrpModelRenderPrefs.GetRenderType() & RT_TEXTURE)
|
|
|
|
|
{
|
|
|
|
|
crLayerWorldCastResult.cr_ttHitModels = CCastRay::TT_SIMPLE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
crLayerWorldCastResult.cr_ttHitModels = CCastRay::TT_NONE;
|
|
|
|
|
}
|
|
|
|
|
// cast ray, go for hit data
|
|
|
|
|
pDoc->m_pwoSecondLayer->CastRay( crLayerWorldCastResult);
|
|
|
|
|
// if any kind of entity on second layer was hitted
|
|
|
|
|
if( crLayerWorldCastResult.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
// calculate distance beetween viewer and hited point in layer's world
|
|
|
|
|
FLOAT fSecondLayerHitDistance =
|
|
|
|
|
(crLayerWorldCastResult.cr_vHit - plVirtualViewer.pl_PositionVector).Length();
|
|
|
|
|
// transform hited coordinate back to absolute space
|
|
|
|
|
CPlacement3D plHitPlacement = plLayerRay;
|
|
|
|
|
plHitPlacement.pl_PositionVector = crLayerWorldCastResult.cr_vHit;
|
|
|
|
|
plHitPlacement.RelativeToAbsolute( pDoc->m_plSecondLayer);
|
|
|
|
|
// and set it as hited point
|
|
|
|
|
crLayerWorldCastResult.cr_vHit = plHitPlacement.pl_PositionVector;
|
|
|
|
|
|
|
|
|
|
// if ray didn't hit anything on base world
|
|
|
|
|
if( crBaseWorldCastResult.cr_penHit == NULL)
|
|
|
|
|
{
|
|
|
|
|
// valid result is one received from second layer ray hit
|
|
|
|
|
return crLayerWorldCastResult;
|
|
|
|
|
}
|
|
|
|
|
// calculate distance beetween viewer and base world's hit point
|
|
|
|
|
FLOAT fBaseWorldHitDistance =
|
|
|
|
|
(crBaseWorldCastResult.cr_vHit - plViewer.pl_PositionVector).Length();
|
|
|
|
|
|
|
|
|
|
// if base world's hit point is closer than second layer's hit point
|
|
|
|
|
if( Abs(fBaseWorldHitDistance) < Abs(fSecondLayerHitDistance))
|
|
|
|
|
{
|
|
|
|
|
// base world's hit result is valid result
|
|
|
|
|
return crBaseWorldCastResult;
|
|
|
|
|
}
|
|
|
|
|
// otherwise
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// second layer's world hit result is valid result
|
|
|
|
|
return crLayerWorldCastResult;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( crBaseWorldCastResult.cr_penHit == NULL)
|
|
|
|
|
{
|
|
|
|
|
// placement equals ray placement
|
|
|
|
|
CPlacement3D plPlacementInFront = plRay;
|
|
|
|
|
// calculate position somewhere in front of viewer
|
|
|
|
|
plPlacementInFront.Translate_OwnSystem( FLOAT3D( 0.0f, 0.0f, -10.0f));
|
|
|
|
|
// copy result coordinate into cast object
|
|
|
|
|
crBaseWorldCastResult.cr_vHit = plPlacementInFront.pl_PositionVector;
|
|
|
|
|
}
|
|
|
|
|
return crBaseWorldCastResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FLOAT3D CWorldEditorView::GetMouseHitOnPlane( CPoint point, const FLOATplane3D &plPlane)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
// get draw port
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
// if it is not valid
|
|
|
|
|
if( pdpValidDrawPort == NULL)
|
|
|
|
|
{
|
|
|
|
|
// return dummy result
|
|
|
|
|
return FLOAT3D(0.0f,0.0f,0.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// obtain viewer placement
|
|
|
|
|
CPlacement3D plViewer = GetChildFrame()->m_mvViewer.GetViewerPlacement();
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
|
|
|
|
|
// now we will try to obtain where mouse poonts to in the base world
|
|
|
|
|
// create a projection for current viewer
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
// make the ray from viewer point through the mouse point, in current projection
|
|
|
|
|
CPlacement3D plRay;
|
|
|
|
|
prProjection->RayThroughPoint(FLOAT3D((float)point.x,
|
|
|
|
|
pdpValidDrawPort->GetHeight()-(float)point.y, 0.0f), plRay);
|
|
|
|
|
|
|
|
|
|
// get two points on the line
|
|
|
|
|
FLOAT3D v0 = plRay.pl_PositionVector;
|
|
|
|
|
FLOAT3D v1;
|
|
|
|
|
AnglesToDirectionVector(plRay.pl_OrientationAngle, v1);
|
|
|
|
|
v1*=100.0f; // to increase precision on large scales
|
|
|
|
|
v1+=v0;
|
|
|
|
|
|
|
|
|
|
// find intersection of line and plane
|
|
|
|
|
FLOAT f0 = plPlane.PointDistance(v0);
|
|
|
|
|
FLOAT f1 = plPlane.PointDistance(v1);
|
|
|
|
|
FLOAT fFraction = f0/(f0-f1);
|
|
|
|
|
return v0+(v1-v0)*fFraction;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::MarkClosestVtxAndEdgeOnPrimitiveBase(CPoint point)
|
|
|
|
|
{
|
|
|
|
|
// get draw port
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
// if it is not valid
|
|
|
|
|
if( pdpValidDrawPort == NULL) return;
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
// create a projection for current viewer
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
// prepare the projection
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
// make the ray from viewer point through the mouse point, in current projection
|
|
|
|
|
CPlacement3D plRay;
|
|
|
|
|
prProjection->RayThroughPoint(FLOAT3D((float)point.x,
|
|
|
|
|
pdpValidDrawPort->GetHeight()-(float)point.y, 0.0f), plRay);
|
|
|
|
|
// transform ray to the system of the second layer
|
|
|
|
|
plRay.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
m_vMouseDownSecondLayer = plRay.pl_PositionVector;
|
|
|
|
|
// prepare second layer's projection ...
|
|
|
|
|
// get viewer placement from first layer
|
|
|
|
|
CPlacement3D plVirtualViewer = prProjection->ViewerPlacementR();
|
|
|
|
|
// transform it to the system of the second layer
|
|
|
|
|
plVirtualViewer.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
// use it in projection for second layer
|
|
|
|
|
CAnyProjection3D prProjectionSecondLayer;
|
|
|
|
|
prProjectionSecondLayer = prProjection;
|
|
|
|
|
prProjectionSecondLayer->ViewerPlacementL() = plVirtualViewer;
|
|
|
|
|
prProjectionSecondLayer->Prepare();
|
|
|
|
|
// get number of vertices for base polygon
|
|
|
|
|
INDEX vtxCt = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive.Count();
|
|
|
|
|
// set distance of closest vertice to a hudge distance
|
|
|
|
|
FLOAT fMinVertexDistance = 999999.9f;
|
|
|
|
|
m_iDragVertice = -1;
|
|
|
|
|
FLOAT fMinEdgeDistance = 999999.9f;
|
|
|
|
|
m_iDragEdge = -1;
|
|
|
|
|
// now we will project base vertices onto screen and try
|
|
|
|
|
// to find closest vertice to mouse for moving vertices on the base
|
|
|
|
|
for( INDEX iVtx=0; iVtx<vtxCt; iVtx++)
|
|
|
|
|
{
|
|
|
|
|
INDEX iNext = (iVtx+1)%vtxCt;
|
|
|
|
|
FLOAT3D vProjectedVtx1, vProjectedVtx2;
|
|
|
|
|
// project vertices
|
|
|
|
|
prProjectionSecondLayer->ProjectCoordinate(
|
|
|
|
|
DOUBLEtoFLOAT(theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ iVtx]), vProjectedVtx1);
|
|
|
|
|
prProjectionSecondLayer->ProjectCoordinate(
|
|
|
|
|
DOUBLEtoFLOAT(theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ iNext]), vProjectedVtx2);
|
|
|
|
|
// convert y coordinate from mathemathical representation into screen one
|
|
|
|
|
vProjectedVtx1(2) = pdpValidDrawPort->GetHeight() - vProjectedVtx1(2);
|
|
|
|
|
vProjectedVtx2(2) = pdpValidDrawPort->GetHeight() - vProjectedVtx2(2);
|
|
|
|
|
vProjectedVtx1(3) = 0.0f;
|
|
|
|
|
vProjectedVtx2(3) = 0.0f;
|
|
|
|
|
// calculate distance to mouse
|
|
|
|
|
FLOAT fDVtx1 = ( FLOAT3D((FLOAT)point.x, (FLOAT)point.y, 0.0f) - vProjectedVtx1).Length();
|
|
|
|
|
FLOAT fDVtx2 = ( FLOAT3D((FLOAT)point.x, (FLOAT)point.y, 0.0f) - vProjectedVtx2).Length();
|
|
|
|
|
FLOAT fEdgeLen = ( vProjectedVtx1 - vProjectedVtx2).Length();
|
|
|
|
|
FLOAT s = (fDVtx1+fDVtx2+fEdgeLen)/2.0f;
|
|
|
|
|
FLOAT fArea = FLOAT(sqrt( FLOATtoDOUBLE( s*(s-fDVtx1)*(s-fDVtx2)*(s-fEdgeLen))));
|
|
|
|
|
FLOAT fDEdge = 2.0f*fArea/fEdgeLen;
|
|
|
|
|
// if distance of edge is smaller than last remembered and both edges are smaller than
|
|
|
|
|
// edges of triangle
|
|
|
|
|
if( (fDEdge < fMinEdgeDistance) && (fEdgeLen > fDVtx1) && (fEdgeLen > fDVtx2) )
|
|
|
|
|
{
|
|
|
|
|
fMinEdgeDistance = fDEdge;
|
|
|
|
|
m_iDragEdge = iVtx;
|
|
|
|
|
}
|
|
|
|
|
// if distance of first vertex is smaller than last remembered
|
|
|
|
|
if( fDVtx1 < fMinVertexDistance)
|
|
|
|
|
{
|
|
|
|
|
fMinVertexDistance = fDVtx1;
|
|
|
|
|
m_iDragVertice = iVtx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// when we found closest vertice, remember its current position
|
|
|
|
|
m_vStartDragVertice = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ m_iDragVertice];
|
|
|
|
|
if( m_iDragEdge != -1)
|
|
|
|
|
{
|
|
|
|
|
INDEX iEdgeEnd = (m_iDragEdge+1)%vtxCt;
|
|
|
|
|
m_vStartDragEdge =
|
|
|
|
|
(theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ m_iDragEdge]+
|
|
|
|
|
theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[ iEdgeEnd])/2.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::MarkClosestVtxOnPrimitive( BOOL bToggleSelection)
|
|
|
|
|
{
|
|
|
|
|
// get draw port
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
// if it is not valid
|
|
|
|
|
if( pdpValidDrawPort == NULL) return;
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
// create a projection for current viewer
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
// prepare the projection
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
|
|
|
|
|
// prepare second layer's projection ...
|
|
|
|
|
// get viewer placement from first layer
|
|
|
|
|
CPlacement3D plVirtualViewer = prProjection->ViewerPlacementR();
|
|
|
|
|
// transform it to the system of the second layer
|
|
|
|
|
plVirtualViewer.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
// use it in projection for second layer
|
|
|
|
|
CAnyProjection3D prProjectionSecondLayer;
|
|
|
|
|
prProjectionSecondLayer = prProjection;
|
|
|
|
|
prProjectionSecondLayer->ViewerPlacementL() = plVirtualViewer;
|
|
|
|
|
prProjectionSecondLayer->Prepare();
|
|
|
|
|
|
|
|
|
|
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Lock();
|
|
|
|
|
CDynamicArray<CObjectVertex> &aVtx = theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors[0].osc_aovxVertices;
|
|
|
|
|
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Unlock();
|
|
|
|
|
|
|
|
|
|
aVtx.Lock();
|
|
|
|
|
// set distance of closest vertice to a hudge distance
|
|
|
|
|
FLOAT fMinVertexDistance = 999999.9f;
|
|
|
|
|
FLOAT fMinVertexDistanceZ = 999999.9f;
|
|
|
|
|
INDEX iClosest = -1;
|
|
|
|
|
BOOL bHasSelection = FALSE;
|
|
|
|
|
// now we will project base vertices onto screen and try
|
|
|
|
|
// to find closest vertice to mouse for moving vertices on the base
|
|
|
|
|
for( INDEX iVtx=0; iVtx<aVtx.Count(); iVtx++)
|
|
|
|
|
{
|
|
|
|
|
if( (aVtx[ iVtx].ovx_ulFlags & OVXF_SELECTED) && !bHasSelection)
|
|
|
|
|
{
|
|
|
|
|
bHasSelection = TRUE;
|
|
|
|
|
m_vStartDragO3DVertice = aVtx[ iVtx];
|
|
|
|
|
}
|
|
|
|
|
aVtx[ iVtx].ovx_ulFlags &= ~OVXF_CLOSEST;
|
|
|
|
|
FLOAT3D vProjected;
|
|
|
|
|
// project current base vertice
|
|
|
|
|
prProjectionSecondLayer->ProjectCoordinate( DOUBLEtoFLOAT(aVtx[ iVtx]), vProjected);
|
|
|
|
|
// convert y coordinate from mathemathical representation into screen one
|
|
|
|
|
vProjected(2) = pdpValidDrawPort->GetHeight() - vProjected(2);
|
|
|
|
|
// calculate distance to mouse point
|
|
|
|
|
FLOAT fDX = (FLOAT)m_ptMouse.x-vProjected(1);
|
|
|
|
|
FLOAT fDY = (FLOAT)m_ptMouse.y-vProjected(2);
|
|
|
|
|
FLOAT fDistance = (FLOAT)sqrt(fDX*fDX+fDY*fDY);
|
|
|
|
|
FLOAT fDistanceZ = -vProjected(3);
|
|
|
|
|
// if this distance is smaller than last remembered
|
|
|
|
|
if( (fDistance < fMinVertexDistance-0.5) ||
|
|
|
|
|
((fDistance<fMinVertexDistance+0.5) && fDistanceZ<fMinVertexDistanceZ) )
|
|
|
|
|
{
|
|
|
|
|
// set this one as smallest
|
|
|
|
|
fMinVertexDistance = fDistance;
|
|
|
|
|
fMinVertexDistanceZ = fDistanceZ;
|
|
|
|
|
// remember its index
|
|
|
|
|
iClosest = iVtx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
aVtx[ iClosest].ovx_ulFlags |= OVXF_CLOSEST;
|
|
|
|
|
if( bToggleSelection)
|
|
|
|
|
{
|
|
|
|
|
aVtx[ iClosest].ovx_ulFlags ^= OVXF_SELECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !bHasSelection)
|
|
|
|
|
{
|
|
|
|
|
m_vStartDragO3DVertice = aVtx[ iClosest];
|
|
|
|
|
}
|
|
|
|
|
aVtx.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
POINT CWorldEditorView::Get2DCoordinateFrom3D( FLOAT3D vPoint)
|
|
|
|
|
{
|
|
|
|
|
CDrawPort *pDP = m_pdpDrawPort;
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid, pDP);
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
|
|
|
|
|
FLOAT3D vResult;
|
|
|
|
|
prProjection->ProjectCoordinate( vPoint, vResult);
|
|
|
|
|
POINT ptResult;
|
|
|
|
|
ptResult.x = (LONG) vResult(1);
|
|
|
|
|
ptResult.y = pDP->GetHeight()-(LONG) vResult(2);
|
|
|
|
|
return ptResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FLOAT3D CWorldEditorView::Get3DCoordinateFrom2D( POINT &pt)
|
|
|
|
|
{
|
|
|
|
|
CDrawPort *pDP = m_pdpDrawPort;
|
|
|
|
|
|
|
|
|
|
// convert coordinate
|
|
|
|
|
PIX pixX = pt.x;
|
|
|
|
|
PIX pixY = pt.y;
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid, pDP);
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
// make the ray from viewer point through the mouse point, in current projection
|
|
|
|
|
CPlacement3D plRay;
|
|
|
|
|
prProjection->RayThroughPoint(FLOAT3D((float)pixX, pDP->GetHeight()-(float)pixY, 0.0f), plRay);
|
|
|
|
|
|
|
|
|
|
// snap to grid entity's placement
|
|
|
|
|
pDoc->SnapToGrid( plRay, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
|
|
|
|
|
// get viewer's direction vector
|
|
|
|
|
FLOAT3D vDirection;
|
|
|
|
|
AnglesToDirectionVector( plRay.pl_OrientationAngle, vDirection);
|
|
|
|
|
FLOAT3D vResult;
|
|
|
|
|
vResult = plRay.pl_PositionVector + vDirection;
|
|
|
|
|
|
|
|
|
|
// snap result
|
|
|
|
|
SnapVector( vResult);
|
|
|
|
|
|
|
|
|
|
return vResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::SnapVector(FLOAT3D &vToSnap)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
if( pDoc->m_bAutoSnap)
|
|
|
|
|
{
|
|
|
|
|
Snap(vToSnap(1), m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
Snap(vToSnap(2), m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
Snap(vToSnap(3), m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Snap(vToSnap(1), SNAP_DOUBLE_CM);
|
|
|
|
|
Snap(vToSnap(2), SNAP_DOUBLE_CM);
|
|
|
|
|
Snap(vToSnap(3), SNAP_DOUBLE_CM);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::SnapVector(DOUBLE3D &vToSnap)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
FLOAT3D vTemp = DOUBLEtoFLOAT(vToSnap);
|
|
|
|
|
|
|
|
|
|
if( pDoc->m_bAutoSnap)
|
|
|
|
|
{
|
|
|
|
|
Snap(vTemp(1), m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
Snap(vTemp(2), m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
Snap(vTemp(3), m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Snap(vTemp(1), SNAP_DOUBLE_CM);
|
|
|
|
|
Snap(vTemp(2), SNAP_DOUBLE_CM);
|
|
|
|
|
Snap(vTemp(3), SNAP_DOUBLE_CM);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vToSnap = FLOATtoDOUBLE(vTemp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FLOAT GetDistance( POINT &pt1, POINT &pt2)
|
|
|
|
|
{
|
|
|
|
|
FLOAT2D vpt1, vpt2;
|
|
|
|
|
|
|
|
|
|
vpt1(1) = pt1.x;
|
|
|
|
|
vpt1(2) = pt1.y;
|
|
|
|
|
|
|
|
|
|
vpt2(1) = pt2.x;
|
|
|
|
|
vpt2(2) = pt2.y;
|
|
|
|
|
|
|
|
|
|
FLOAT2D vDistance = vpt1-vpt2;
|
|
|
|
|
return vDistance.Length();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::RenderAndApplyTerrainEditBrush(FLOAT3D vHit)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CTerrain *ptrTerrain=GetTerrain();
|
|
|
|
|
if( ptrTerrain!=NULL)
|
|
|
|
|
{
|
|
|
|
|
CTString strBrushFile;
|
|
|
|
|
INDEX iBrush=INDEX(theApp.m_fCurrentTerrainBrush);
|
|
|
|
|
strBrushFile.PrintF("Textures\\Editor\\TerrainBrush%02d.tex", iBrush);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
CTextureData *ptdBrush=_pTextureStock->Obtain_t(strBrushFile);
|
|
|
|
|
ptdBrush->Force(TEX_STATIC);
|
|
|
|
|
|
|
|
|
|
FLOAT fStrengthRatio=theApp.m_fTerrainBrushPressure/1024.0f;
|
|
|
|
|
FLOAT fUncompensatedStrength=(pow(1.0f+theApp.m_fTerrainBrushPressure/1024.0f*16.0f,2)-1.0f)/64.0f;
|
|
|
|
|
COLOR colSelection=C_WHITE|CT_OPAQUE;
|
|
|
|
|
ETerrainEdit teTool=TE_NONE;
|
|
|
|
|
SelectionFill sf;
|
|
|
|
|
// heightmap mode
|
|
|
|
|
if( theApp.m_iTerrainEditMode==TEM_HEIGHTMAP)
|
|
|
|
|
{
|
|
|
|
|
colSelection=C_ORANGE|CT_OPAQUE;
|
|
|
|
|
switch(INDEX(theApp.m_iTerrainBrushMode))
|
|
|
|
|
{
|
|
|
|
|
case TBM_PAINT : teTool=TE_BRUSH_ALTITUDE_PAINT ; break;
|
|
|
|
|
case TBM_SMOOTH : teTool=TE_BRUSH_ALTITUDE_SMOOTH ; break;
|
|
|
|
|
case TBM_FILTER : teTool=TE_BRUSH_ALTITUDE_FILTER ; break;
|
|
|
|
|
case TBM_MINIMUM : teTool=TE_BRUSH_ALTITUDE_MINIMUM ; break;
|
|
|
|
|
case TBM_MAXIMUM : teTool=TE_BRUSH_ALTITUDE_MAXIMUM ; break;
|
|
|
|
|
case TBM_FLATTEN : teTool=TE_BRUSH_ALTITUDE_FLATTEN ; break;
|
|
|
|
|
case TBM_POSTERIZE : teTool=TE_BRUSH_ALTITUDE_POSTERIZE; break;
|
|
|
|
|
case TBM_RND_NOISE : teTool=TE_BRUSH_ALTITUDE_RND_NOISE; break;
|
|
|
|
|
case TBM_CONTINOUS_NOISE: teTool=TE_BRUSH_ALTITUDE_CONTINOUS_NOISE; break;
|
|
|
|
|
case TBM_ERASE : teTool=TE_BRUSH_EDGE_ERASE ; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// texture layer mode
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
colSelection=C_GREEN|CT_OPAQUE;
|
|
|
|
|
teTool=TE_BRUSH_LAYER_PAINT;
|
|
|
|
|
|
|
|
|
|
CTerrainLayer *ptlLayer=GetLayer();
|
|
|
|
|
if(ptlLayer==NULL) return;
|
|
|
|
|
|
|
|
|
|
if( ptlLayer->tl_ltType==LT_TILE)
|
|
|
|
|
{
|
|
|
|
|
teTool=TE_TILE_PAINT;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch(INDEX(theApp.m_iTerrainBrushMode))
|
|
|
|
|
{
|
|
|
|
|
case TBM_PAINT : teTool=TE_BRUSH_LAYER_PAINT ; break;
|
|
|
|
|
case TBM_SMOOTH : teTool=TE_BRUSH_LAYER_SMOOTH ; break;
|
|
|
|
|
case TBM_FILTER : teTool=TE_BRUSH_LAYER_FILTER ; break;
|
|
|
|
|
case TBM_RND_NOISE : teTool=TE_BRUSH_LAYER_RND_NOISE; break;
|
|
|
|
|
case TBM_CONTINOUS_NOISE: teTool=TE_BRUSH_LAYER_CONTINOUS_NOISE; break;
|
|
|
|
|
case TBM_ERASE : teTool=TE_BRUSH_EDGE_ERASE ; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// no cursor if selection is hidden
|
|
|
|
|
if(!GetChildFrame()->m_bSelectionVisible) colSelection&=0xFFFFFF00;
|
|
|
|
|
|
|
|
|
|
if( m_iaInputAction==IA_TERRAIN_EDITING_LMB || m_iaInputAction==IA_TERRAIN_EDITING_CTRL_LMB)
|
|
|
|
|
{
|
|
|
|
|
// if we pressed mouse down (terrain edit start)
|
|
|
|
|
if(m_iaInputAction!=m_iaLastInputAction)
|
|
|
|
|
{
|
|
|
|
|
TerrainEditBegin();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CTimerValue tvNow=_pTimer->GetHighPrecisionTimer();
|
|
|
|
|
// get difference to time when last mip brushing option has been used
|
|
|
|
|
FLOAT fSecondsPassed=(tvNow-_tvLastTerrainBrushingApplied).GetSeconds();
|
|
|
|
|
_tvLastTerrainBrushingApplied=_pTimer->GetHighPrecisionTimer();
|
|
|
|
|
// apply time passed factor, so terrain editing wouldn't depend upon frame rate
|
|
|
|
|
fSecondsPassed=Clamp(fSecondsPassed,0.0f,1.0f);
|
|
|
|
|
FLOAT fCompensatedStrength=fUncompensatedStrength*fSecondsPassed/(1.0f/50.0f);
|
|
|
|
|
|
|
|
|
|
if( m_iaInputAction==IA_TERRAIN_EDITING_CTRL_LMB) fCompensatedStrength=-fCompensatedStrength;
|
|
|
|
|
// apply terrain editing
|
|
|
|
|
EditTerrain(ptdBrush, vHit, fCompensatedStrength, teTool);
|
|
|
|
|
}
|
|
|
|
|
// if we stopped editing
|
|
|
|
|
else if( m_iaLastInputAction==IA_TERRAIN_EDITING_LMB || m_iaLastInputAction==IA_TERRAIN_EDITING_CTRL_LMB)
|
|
|
|
|
{
|
|
|
|
|
TerrainEditEnd();
|
|
|
|
|
}
|
|
|
|
|
m_iaLastInputAction=m_iaInputAction;
|
|
|
|
|
|
|
|
|
|
// render terrain editing cursor
|
|
|
|
|
Rect rect;
|
|
|
|
|
Point pt=Calculate2dHitPoint(ptrTerrain, vHit);
|
|
|
|
|
rect.rc_iLeft=pt.pt_iX-ptdBrush->GetPixWidth()/2;
|
|
|
|
|
rect.rc_iRight=pt.pt_iX+(ptdBrush->GetPixWidth()-ptdBrush->GetPixWidth()/2);
|
|
|
|
|
rect.rc_iTop=pt.pt_iY-ptdBrush->GetPixHeight()/2;
|
|
|
|
|
rect.rc_iBottom=pt.pt_iY+(ptdBrush->GetPixHeight()-ptdBrush->GetPixHeight()/2);
|
|
|
|
|
|
|
|
|
|
if(GetChildFrame()->m_bSelectionVisible)
|
|
|
|
|
{
|
|
|
|
|
sf=(SelectionFill) theApp.m_Preferences.ap_iTerrainSelectionVisible;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sf=(SelectionFill) theApp.m_Preferences.ap_iTerrainSelectionHidden;
|
|
|
|
|
}
|
|
|
|
|
if(sf!=3)
|
|
|
|
|
{
|
|
|
|
|
ShowSelection(ptrTerrain, rect, ptdBrush, colSelection, 0.25f+fStrengthRatio*0.75f, sf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch( char *strError)
|
|
|
|
|
{
|
|
|
|
|
(void) strError;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnLButtonDown(UINT nFlags, CPoint point)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_NONE;
|
|
|
|
|
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
if( pdpValidDrawPort == NULL) return;
|
|
|
|
|
|
|
|
|
|
m_pbpoTranslationPlane = NULL;
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
|
|
|
|
|
// key statuses
|
|
|
|
|
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
|
|
|
|
|
BOOL bSpace = (GetKeyState( ' ') & 128) != 0;
|
|
|
|
|
BOOL bCtrl = nFlags & MK_CONTROL;
|
|
|
|
|
BOOL bShift = nFlags & MK_SHIFT;
|
|
|
|
|
BOOL bRMB = nFlags & MK_RBUTTON;
|
|
|
|
|
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
|
|
|
|
|
|
|
|
|
|
BOOL bHitModels = (pDoc->GetEditingMode() == ENTITY_MODE) || bSpace;
|
|
|
|
|
BOOL bHitFields = (pDoc->GetEditingMode() == ENTITY_MODE) || bSpace;
|
|
|
|
|
BOOL bHitBrushes = (pDoc->GetEditingMode() != TERRAIN_MODE) || bSpace;
|
|
|
|
|
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( point, FALSE, bHitModels, bHitFields, NULL, bHitBrushes);
|
|
|
|
|
m_vHitOnMouseDown = crRayHit.cr_vHit;
|
|
|
|
|
theApp.m_vLastTerrainHit=crRayHit.cr_vHit;
|
|
|
|
|
m_ptMouseDown = point;
|
|
|
|
|
m_VFPMouseDown = theApp.m_vfpCurrent;
|
|
|
|
|
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
|
|
|
|
|
// space+ctrl+lmb zoomes in 2x
|
|
|
|
|
if( bSpace && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
if( bRMB) return;
|
|
|
|
|
// set new target
|
|
|
|
|
GetChildFrame()->m_mvViewer.SetTargetPlacement( crRayHit.cr_vHit);
|
|
|
|
|
// move mouse to center of screen
|
|
|
|
|
CPoint ptCenter = CPoint( m_pdpDrawPort->GetWidth()/2, m_pdpDrawPort->GetHeight()/2);
|
|
|
|
|
ClientToScreen( &ptCenter);
|
|
|
|
|
SetCursorPos(ptCenter.x, ptCenter.y);
|
|
|
|
|
OnZoomMore();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
m_ptMouseDown = ptCenter;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// space+lmb is used for viewer and CSG layer movement in floor plane,+rmb rotates
|
|
|
|
|
else if( bSpace)
|
|
|
|
|
{
|
|
|
|
|
if( bRMB) m_iaInputAction = IA_ROTATING_VIEWER;
|
|
|
|
|
else m_iaInputAction = IA_MOVING_VIEWER_IN_FLOOR_PLANE;
|
|
|
|
|
StartMouseInput( point);
|
|
|
|
|
}
|
|
|
|
|
// in measure mode, only viewer moving is enabled
|
|
|
|
|
else if( theApp.m_bMeasureModeOn)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_MEASURING;
|
|
|
|
|
}
|
|
|
|
|
// in cut mode, only viewer moving is enabled
|
|
|
|
|
else if( theApp.m_bCutModeOn)
|
|
|
|
|
{
|
|
|
|
|
// project 3D control points
|
|
|
|
|
POINT ptStart = Get2DCoordinateFrom3D( pDoc->m_vCutLineStart);
|
|
|
|
|
POINT ptEnd = Get2DCoordinateFrom3D( pDoc->m_vCutLineEnd);
|
|
|
|
|
|
|
|
|
|
// calculate distances
|
|
|
|
|
FLOAT fDStart = GetDistance( ptStart, point);
|
|
|
|
|
FLOAT fDEnd = GetDistance( ptEnd, point);
|
|
|
|
|
FLOAT fAllowedDistance = 32.0f;
|
|
|
|
|
|
|
|
|
|
// if we clicked near coontrol point
|
|
|
|
|
if( fDStart < fAllowedDistance)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_MOVING_CUT_LINE_START;
|
|
|
|
|
pDoc->m_vControlLineDragStart = pDoc->m_vCutLineStart;
|
|
|
|
|
}
|
|
|
|
|
else if( fDEnd < fAllowedDistance)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_MOVING_CUT_LINE_END;
|
|
|
|
|
pDoc->m_vControlLineDragStart = pDoc->m_vCutLineEnd;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_CUT_MODE;
|
|
|
|
|
pDoc->m_pCutLineView = this;
|
|
|
|
|
pDoc->m_vCutLineStart = Get3DCoordinateFrom2D( point);
|
|
|
|
|
pDoc->m_vCutLineEnd = pDoc->m_vCutLineStart;
|
|
|
|
|
}
|
|
|
|
|
pDoc->UpdateAllViews( this);
|
|
|
|
|
}
|
|
|
|
|
// test for mouse operations used while primitive CSG is on
|
|
|
|
|
else if( bCSGOn)
|
|
|
|
|
{
|
|
|
|
|
if( bCtrl && bAlt)
|
|
|
|
|
{
|
|
|
|
|
SetAsCsgTarget(crRayHit.cr_penHit);
|
|
|
|
|
}
|
|
|
|
|
if( bCtrl && !bShift)
|
|
|
|
|
{
|
|
|
|
|
if( bRMB) m_iaInputAction = IA_ROTATING_SECOND_LAYER;
|
|
|
|
|
else m_iaInputAction = IA_MOVING_SECOND_LAYER_IN_FLOOR_PLANE;
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->m_bPrimitiveMode)
|
|
|
|
|
{
|
|
|
|
|
// in triangularisation primitive mode
|
|
|
|
|
if( theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE)
|
|
|
|
|
{
|
|
|
|
|
// select vertices on primitive
|
|
|
|
|
MarkClosestVtxOnPrimitive( bShift);
|
|
|
|
|
// and start dragging them
|
|
|
|
|
if( !bShift) m_iaInputAction = IA_DRAG_VERTEX_ON_PRIMITIVE;
|
|
|
|
|
}
|
|
|
|
|
// shift+lmb inserts vertex on primitive base
|
|
|
|
|
else if( !bCtrl && bShift)
|
|
|
|
|
{
|
|
|
|
|
// find and remember vertex on primitive base for draging
|
|
|
|
|
MarkClosestVtxAndEdgeOnPrimitiveBase( point);
|
|
|
|
|
if(m_iDragEdge != -1)
|
|
|
|
|
{
|
|
|
|
|
pDoc->InsertPrimitiveVertex( m_iDragEdge, m_vMouseDownSecondLayer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// lmb is used for dragging vertices on base of primitive
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// ctrl+shift+lmb stretches primitive
|
|
|
|
|
if( bCtrl && bShift) m_iaInputAction = IA_STRETCHING_PRIMITIVE;
|
|
|
|
|
else m_iaInputAction = IA_DRAG_VERTEX_ON_PRIMITIVE_BASE;
|
|
|
|
|
// ------ Find closest vertice on base of primitive and remember its position
|
|
|
|
|
// prepare second layer's projection ...
|
|
|
|
|
// get viewer placement from first layer
|
|
|
|
|
CPlacement3D plVirtualViewer = prProjection->ViewerPlacementR();
|
|
|
|
|
// transform it to the system of the second layer
|
|
|
|
|
plVirtualViewer.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
// use it in projection for second layer
|
|
|
|
|
CAnyProjection3D prProjectionSecondLayer;
|
|
|
|
|
prProjectionSecondLayer = prProjection;
|
|
|
|
|
prProjectionSecondLayer->ViewerPlacementL() = plVirtualViewer;
|
|
|
|
|
prProjectionSecondLayer->Prepare();
|
|
|
|
|
|
|
|
|
|
// find and remember vertex on primitive base for draging
|
|
|
|
|
MarkClosestVtxAndEdgeOnPrimitiveBase( point);
|
|
|
|
|
|
|
|
|
|
m_iSizeControlVertice = -1;
|
|
|
|
|
FLOAT fMinDistance = 9999999.9f;
|
|
|
|
|
// prepare array with vertices used as control points for sizing box arround primitive
|
|
|
|
|
FLOAT3D avtxSizeControlVertices[ 14];
|
|
|
|
|
|
|
|
|
|
// table of min x, max x, miny, ...
|
|
|
|
|
FLOAT afCoordinates[ 6];
|
|
|
|
|
afCoordinates[0] = theApp.m_vfpCurrent.vfp_fXMin;
|
|
|
|
|
afCoordinates[1] = theApp.m_vfpCurrent.vfp_fXMax;
|
|
|
|
|
afCoordinates[2] = theApp.m_vfpCurrent.vfp_fYMin;
|
|
|
|
|
afCoordinates[3] = theApp.m_vfpCurrent.vfp_fYMax;
|
|
|
|
|
afCoordinates[4] = theApp.m_vfpCurrent.vfp_fZMin;
|
|
|
|
|
afCoordinates[5] = theApp.m_vfpCurrent.vfp_fZMax;
|
|
|
|
|
// create control points using table with indices into afCoordinates table
|
|
|
|
|
for( INDEX iVtx=0;iVtx<14;iVtx++)
|
|
|
|
|
{
|
|
|
|
|
avtxSizeControlVertices[iVtx](1) =
|
|
|
|
|
(afCoordinates[aiForCreationOfSizingVertices[iVtx][0]]+
|
|
|
|
|
afCoordinates[aiForCreationOfSizingVertices[iVtx][1]])/2;
|
|
|
|
|
avtxSizeControlVertices[iVtx](2) =
|
|
|
|
|
(afCoordinates[aiForCreationOfSizingVertices[iVtx][2]]+
|
|
|
|
|
afCoordinates[aiForCreationOfSizingVertices[iVtx][3]])/2;
|
|
|
|
|
avtxSizeControlVertices[iVtx](3) =
|
|
|
|
|
(afCoordinates[aiForCreationOfSizingVertices[iVtx][4]]+
|
|
|
|
|
afCoordinates[aiForCreationOfSizingVertices[iVtx][5]])/2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// now we will project size control vertices and try to find closest one to mouse
|
|
|
|
|
for( INDEX iControlVtx=0; iControlVtx<14; iControlVtx++)
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D vProjectedCoordinate;
|
|
|
|
|
// project current control vertex
|
|
|
|
|
prProjectionSecondLayer->ProjectCoordinate(
|
|
|
|
|
avtxSizeControlVertices[iControlVtx], vProjectedCoordinate);
|
|
|
|
|
// convert y coordinate from mathemathical representation into screen one
|
|
|
|
|
vProjectedCoordinate(2) = pdpValidDrawPort->GetHeight() - vProjectedCoordinate(2);
|
|
|
|
|
FLOAT fDX = vProjectedCoordinate(1)-point.x;
|
|
|
|
|
FLOAT fDY = vProjectedCoordinate(2)-point.y;
|
|
|
|
|
// calculate distance to mouse point
|
|
|
|
|
FLOAT fDistance = fDX*fDX+fDY*fDY;
|
|
|
|
|
// if this distance is smaller than last remembered
|
|
|
|
|
if( fDistance < fMinDistance)
|
|
|
|
|
{
|
|
|
|
|
// set this one as smallest
|
|
|
|
|
fMinDistance = fDistance;
|
|
|
|
|
// and remember its indice as souch
|
|
|
|
|
m_iSizeControlVertice = iControlVtx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// reset relative placement (m_plMouseOffset)
|
|
|
|
|
StartMouseInput( point);
|
|
|
|
|
}
|
|
|
|
|
// if only Alt key is pressed, we are not in vertex nor entity mode, we want to save thumbnail
|
|
|
|
|
else if( bAlt && !bCtrl && !bShift && !bSpace &&
|
|
|
|
|
(pDoc->GetEditingMode() != VERTEX_MODE) &&
|
|
|
|
|
(pDoc->GetEditingMode() != ENTITY_MODE))
|
|
|
|
|
{
|
|
|
|
|
// if document is modified
|
|
|
|
|
if( pDoc->IsModified() )
|
|
|
|
|
{
|
|
|
|
|
// report error
|
|
|
|
|
AfxMessageBox(L"You must save your document before you can perform drag.");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CTFileName fnDocument = CTString(CStringA(pDoc->GetPathName()));
|
|
|
|
|
// save the thumbnail
|
|
|
|
|
pDoc->SaveThumbnail();
|
|
|
|
|
// try to
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// remove application path
|
|
|
|
|
fnDocument.RemoveApplicationPath_t();
|
|
|
|
|
// create drag and drop object
|
|
|
|
|
HGLOBAL hglobal = CreateHDrop( fnDocument);
|
|
|
|
|
m_DataSource.CacheGlobalData( CF_HDROP, hglobal);
|
|
|
|
|
m_DataSource.DoDragDrop( DROPEFFECT_COPY);
|
|
|
|
|
}
|
|
|
|
|
// if failed
|
|
|
|
|
catch (char *strError)
|
|
|
|
|
{
|
|
|
|
|
// report error
|
|
|
|
|
AfxMessageBox(CString(strError));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// else if we are in entity mode
|
|
|
|
|
else if( pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
// if ctrl pressed, we want to move or rotate entity selection
|
|
|
|
|
if( bCtrl && !bShift && !bAlt)
|
|
|
|
|
{
|
|
|
|
|
if( bRMB) m_iaInputAction = IA_ROTATING_ENTITY_SELECTION;
|
|
|
|
|
else m_iaInputAction = IA_MOVING_ENTITY_SELECTION_IN_FLOOR_PLANE;
|
|
|
|
|
StartMouseInput( point);
|
|
|
|
|
}
|
|
|
|
|
// if we are in browsing entities mode (or select by volume)
|
|
|
|
|
else if( (pDoc->m_bBrowseEntitiesMode) &&
|
|
|
|
|
(m_ptProjectionType != CSlaveViewer::PT_PERSPECTIVE) )
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_SIZING_SELECT_BY_VOLUME_BOX;
|
|
|
|
|
// ------ Find closest vertice of volume box
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
// create a projection for current viewer
|
|
|
|
|
CAnyProjection3D prProjection;
|
|
|
|
|
svViewer.MakeProjection(prProjection);
|
|
|
|
|
// prepare the projection
|
|
|
|
|
prProjection->Prepare();
|
|
|
|
|
// set distance of closest vertice to a hudge distance
|
|
|
|
|
FLOAT fMinVertexDistance = 999999.9f;
|
|
|
|
|
pDoc->m_iVolumeBoxDragVertice = 0;
|
|
|
|
|
// now we will project volume box's vertices onto screen and find closest one to mouse
|
|
|
|
|
for( INDEX iVtx=0; iVtx<8; iVtx++)
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D vProjectedCoordinate;
|
|
|
|
|
// project current base vertice
|
|
|
|
|
prProjection->ProjectCoordinate( pDoc->m_avVolumeBoxVertice[iVtx], vProjectedCoordinate);
|
|
|
|
|
// convert y coordinate from mathemathical representation into screen one
|
|
|
|
|
vProjectedCoordinate(2) = pdpValidDrawPort->GetHeight() - vProjectedCoordinate(2);
|
|
|
|
|
// reset on screen "z" coordinate
|
|
|
|
|
vProjectedCoordinate(3) = 0.0f;
|
|
|
|
|
// calculate distance to mouse point
|
|
|
|
|
FLOAT fDistance =
|
|
|
|
|
( FLOAT3D((FLOAT)point.x, (FLOAT)point.y, 0.0f) - vProjectedCoordinate ).Length();
|
|
|
|
|
// if this distance is smaller than last remembered
|
|
|
|
|
if( fDistance < fMinVertexDistance)
|
|
|
|
|
{
|
|
|
|
|
// set this one as smallest
|
|
|
|
|
fMinVertexDistance = fDistance;
|
|
|
|
|
// and remember its indice as souch
|
|
|
|
|
pDoc->m_iVolumeBoxDragVertice = iVtx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// when we found closest vertice, remember its current position
|
|
|
|
|
pDoc->m_vVolumeBoxStartDragVertice = pDoc->m_avVolumeBoxVertice[ pDoc->m_iVolumeBoxDragVertice];
|
|
|
|
|
// reset relative placement (m_plMouseOffset)
|
|
|
|
|
StartMouseInput( point);
|
|
|
|
|
}
|
|
|
|
|
// ctrl+shift+lmb is used to edit range and angle3d properties
|
|
|
|
|
else if( bCtrl && bShift)
|
|
|
|
|
{
|
|
|
|
|
if( pDoc->m_selEntitySelection.Count() != 0)
|
|
|
|
|
{
|
|
|
|
|
// get selected property
|
|
|
|
|
CPropertyID *ppid = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
|
|
|
|
|
// if property is of range or angle3d type
|
|
|
|
|
if( (ppid != NULL) && (ppid->pid_eptType == CEntityProperty::EPT_RANGE) )
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_CHANGING_RANGE_PROPERTY;
|
|
|
|
|
}
|
|
|
|
|
if( (ppid != NULL) && (ppid->pid_eptType == CEntityProperty::EPT_ANGLE3D) )
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_CHANGING_ANGLE3D_PROPERTY;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Alt+Ctrl+LMB requests that clicked entity becomes target to selected entity
|
|
|
|
|
else if( bAlt && bCtrl && (crRayHit.cr_penHit != NULL))
|
|
|
|
|
{
|
|
|
|
|
if( pDoc->m_selEntitySelection.Count() == 0)
|
|
|
|
|
{
|
|
|
|
|
SetAsCsgTarget(crRayHit.cr_penHit);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// get selected property
|
|
|
|
|
CPropertyID *ppid = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
|
|
|
|
|
if( (ppid == NULL) ||
|
|
|
|
|
!((ppid->pid_eptType == CEntityProperty::EPT_ENTITYPTR) ||
|
|
|
|
|
(ppid->pid_eptType == CEntityProperty::EPT_PARENT)) ) return;
|
|
|
|
|
|
|
|
|
|
BOOL bParentProperty = ppid->pid_eptType == CEntityProperty::EPT_PARENT;
|
|
|
|
|
// for each of the selected entities
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
if( bParentProperty)
|
|
|
|
|
{
|
|
|
|
|
iten->SetParent( crRayHit.cr_penHit);
|
|
|
|
|
}
|
|
|
|
|
else if (crRayHit.cr_penHit->IsTargetable())
|
|
|
|
|
{
|
|
|
|
|
// obtain entity class ptr
|
|
|
|
|
CDLLEntityClass *pdecDLLClass = iten->GetClass()->ec_pdecDLLClass;
|
|
|
|
|
// for all classes in hierarchy of this entity
|
|
|
|
|
for(;
|
|
|
|
|
pdecDLLClass!=NULL;
|
|
|
|
|
pdecDLLClass = pdecDLLClass->dec_pdecBase) {
|
|
|
|
|
// for all properties
|
|
|
|
|
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++) {
|
|
|
|
|
CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
|
|
|
|
|
if( (ppid->pid_strName == epProperty.ep_strName) &&
|
|
|
|
|
(ppid->pid_eptType == epProperty.ep_eptType) )
|
|
|
|
|
{
|
|
|
|
|
// discard old entity settings
|
|
|
|
|
iten->End();
|
|
|
|
|
// set clicked entity as one that selected entity points to
|
|
|
|
|
ENTITYPROPERTY( &*iten, epProperty.ep_slOffset, CEntityPointer) = crRayHit.cr_penHit;
|
|
|
|
|
// apply new entity settings
|
|
|
|
|
iten->Initialize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// update edit range control (by updating parent dialog)
|
|
|
|
|
pMainFrame->m_PropertyComboBar.UpdateData( FALSE);
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// we want to select entities
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_SELECTING_ENTITIES;
|
|
|
|
|
m_bOnSelectEntityShiftDown = bShift;
|
|
|
|
|
m_bOnSelectEntityAltDown = bAlt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// else if we are in sector mode
|
|
|
|
|
else if( pDoc->GetEditingMode() == SECTOR_MODE)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_SELECTING_SECTORS;
|
|
|
|
|
ToggleHittedSector( crRayHit);
|
|
|
|
|
}
|
|
|
|
|
// if we are in polygon mode
|
|
|
|
|
else if( pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
// Alt+Ctrl+LMB requests that clicked polygon sizes its texture
|
|
|
|
|
if( bAlt && bCtrl && !bShift)
|
|
|
|
|
{
|
|
|
|
|
MultiplyMappingOnPolygon( 0.5f);
|
|
|
|
|
}
|
|
|
|
|
else if( bAlt && bCtrl && bShift)
|
|
|
|
|
{
|
|
|
|
|
OnRemainSelectedByOrientation(FALSE);
|
|
|
|
|
}
|
|
|
|
|
if( bAlt && bShift)
|
|
|
|
|
{
|
|
|
|
|
OnRemainSelectedByOrientation(TRUE);
|
|
|
|
|
}
|
|
|
|
|
// if we hit polygon
|
|
|
|
|
else if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// if we want to change polygon mapping
|
|
|
|
|
if( bCtrl && !bShift)
|
|
|
|
|
{
|
|
|
|
|
if( bRMB) m_iaInputAction = IA_ROTATING_POLYGON_MAPPING;
|
|
|
|
|
else m_iaInputAction = IA_MOVING_POLYGON_MAPPING;
|
|
|
|
|
StartMouseInput( point);
|
|
|
|
|
// remember hitted point
|
|
|
|
|
m_f3dRotationOrigin = crRayHit.cr_vHit;
|
|
|
|
|
m_plMouseMove.pl_PositionVector = crRayHit.cr_vHit;
|
|
|
|
|
m_plMouseMove.pl_OrientationAngle = ANGLE3D( 0, 0, 0);
|
|
|
|
|
m_pbpoTranslationPlane = crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
m_plTranslationPlane = crRayHit.cr_pbpoBrushPolygon->bpo_pbplPlane->bpl_plAbsolute;
|
|
|
|
|
}
|
|
|
|
|
// select or deselect hitted polygon
|
|
|
|
|
else if( !bCtrl)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_SELECTING_POLYGONS;
|
|
|
|
|
ToggleHittedPolygon( crRayHit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if we are in vertex mode
|
|
|
|
|
else if( pDoc->GetEditingMode() == VERTEX_MODE)
|
|
|
|
|
{
|
|
|
|
|
// Ctrl+Alt is used to add vertex
|
|
|
|
|
if( bCtrl && bAlt)
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygon *pbpo = crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) && (pbpo != NULL) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
pDoc->m_selVertexSelection.Clear();
|
|
|
|
|
pbpo->bpo_pbscSector->TriangularizePolygon( pbpo);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
// cast ray again to hit newly created triangle
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( point, FALSE, bHitModels, bHitFields);
|
|
|
|
|
CBrushPolygon *pbpo = crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) && (pbpo != NULL) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selPolygonSelection.Select( *pbpo);
|
|
|
|
|
pbpo->bpo_pbscSector->InsertVertexIntoTriangle( pDoc->m_selPolygonSelection, crRayHit.cr_vHit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Ctrl is used for rotating or moving vertices
|
|
|
|
|
else if( bCtrl)
|
|
|
|
|
{
|
|
|
|
|
if( bShift)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_STRETCH_BRUSH_VERTEX;
|
|
|
|
|
}
|
|
|
|
|
else if( bRMB)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_ROTATE_BRUSH_VERTEX;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_DRAG_BRUSH_VERTEX_IN_FLOOR_PLANE;
|
|
|
|
|
}
|
|
|
|
|
// clear polygon selection because some of the old polygons could disappear
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
pDoc->m_woWorld.TriangularizeForVertices( pDoc->m_selVertexSelection);
|
|
|
|
|
StartMouseInput( point);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_avpixLaso.Clear();
|
|
|
|
|
m_iaInputAction = IA_SELECT_SINGLE_BRUSH_VERTEX;
|
|
|
|
|
_vpixSelectNearPoint(1) = point.x;
|
|
|
|
|
_vpixSelectNearPoint(2) = point.y;
|
|
|
|
|
m_bOnSelectVertexShiftDown = bShift;
|
|
|
|
|
m_bOnSelectVertexAltDown = bAlt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
if(crRayHit.cr_penHit!=NULL && crRayHit.cr_penHit==GetTerrainEntity())
|
|
|
|
|
{
|
|
|
|
|
_bCursorMoved=FALSE;
|
|
|
|
|
if( bAlt && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
OnPickLayer();
|
|
|
|
|
}
|
|
|
|
|
else if( !bAlt && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_TERRAIN_EDITING_CTRL_LMB;
|
|
|
|
|
_tvLastTerrainBrushingApplied=_pTimer->GetHighPrecisionTimer();
|
|
|
|
|
}
|
|
|
|
|
else if( !bAlt)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_TERRAIN_EDITING_LMB;
|
|
|
|
|
_tvLastTerrainBrushingApplied=_pTimer->GetHighPrecisionTimer();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// if terrain entity hit
|
|
|
|
|
if(crRayHit.cr_penHit!=NULL && crRayHit.cr_penHit->GetRenderType()==CEntity::RT_TERRAIN)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_ptrSelectedTerrain=crRayHit.cr_penHit->GetTerrain();
|
|
|
|
|
theApp.m_ctTerrainPage.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CView::OnLButtonDown(nFlags, point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SelectLayerCommand(INDEX iSelectedLayer)
|
|
|
|
|
{
|
|
|
|
|
SelectLayer(iSelectedLayer);
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
|
|
|
|
|
if(pDoc!=NULL)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::InvokeSelectLayerCombo(void)
|
|
|
|
|
{
|
|
|
|
|
CPoint pt=m_ptMouse;
|
|
|
|
|
CCastRay crRayHit=GetMouseHitInformation( pt);
|
|
|
|
|
if( (crRayHit.cr_penHit==NULL) || (crRayHit.cr_penHit->GetRenderType()!=CEntity::RT_TERRAIN) ) return;
|
|
|
|
|
|
|
|
|
|
CCustomComboWnd *pCombo=new CCustomComboWnd;
|
|
|
|
|
CTerrain *ptrTerrain=crRayHit.cr_penHit->GetTerrain();
|
|
|
|
|
if(ptrTerrain==NULL) return;
|
|
|
|
|
INDEX ctLayers=ptrTerrain->tr_atlLayers.Count();
|
|
|
|
|
for(INDEX iLayer=ctLayers-1; iLayer>=0; iLayer--)
|
|
|
|
|
{
|
|
|
|
|
CTString strLayerName;
|
|
|
|
|
UBYTE ubPower=GetValueFromMask(ptrTerrain, iLayer, crRayHit.cr_vHit);
|
|
|
|
|
strLayerName.PrintF("Layer %d (%d%%)", iLayer+1, INDEX(ubPower/255.0f*100.0f));
|
|
|
|
|
if(ubPower>0)
|
|
|
|
|
{
|
|
|
|
|
INDEX iAddedAs=pCombo->InsertItem( strLayerName);
|
|
|
|
|
pCombo->SetItemValue( iAddedAs, iLayer);
|
|
|
|
|
}
|
|
|
|
|
if(ubPower==255) break;
|
|
|
|
|
}
|
|
|
|
|
GetCursorPos( &pt);
|
|
|
|
|
pCombo->Initialize(NULL, SelectLayerCommand, pt.x-8, pt.y-8, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRButtonDown(UINT nFlags, CPoint point)
|
|
|
|
|
{
|
|
|
|
|
if( m_iaInputAction != IA_MIP_SETTING) m_iaInputAction = IA_NONE;
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
|
|
|
|
|
BOOL bShift = nFlags & MK_SHIFT;
|
|
|
|
|
BOOL bCtrl = nFlags & MK_CONTROL;
|
|
|
|
|
BOOL bLMB = nFlags & MK_LBUTTON;
|
|
|
|
|
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
|
|
|
|
|
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
|
|
|
|
|
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
|
|
|
|
|
BOOL bCaps = (GetKeyState( VK_CAPITAL)&0x0001) != 0;
|
|
|
|
|
|
|
|
|
|
BOOL bHitModels = (pDoc->GetEditingMode() == ENTITY_MODE) || bSpace;
|
|
|
|
|
BOOL bHitFields = (pDoc->GetEditingMode() == ENTITY_MODE) || bSpace;
|
|
|
|
|
|
|
|
|
|
StartMouseInput( point);
|
|
|
|
|
// remember point in the view
|
|
|
|
|
m_ptMouseDown = point;
|
|
|
|
|
// remember values for primitive
|
|
|
|
|
m_VFPMouseDown = theApp.m_vfpCurrent;
|
|
|
|
|
|
|
|
|
|
// if nothing of below is activated, call popup menu
|
|
|
|
|
if( !bShift && !bAlt && !bCtrl && !bSpace && !bLMB)
|
|
|
|
|
{
|
|
|
|
|
CallPopupMenu( point);
|
|
|
|
|
}
|
|
|
|
|
// space+ctrl+lmb zoomes out 2x
|
|
|
|
|
else if( bSpace && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
if( bLMB) return;
|
|
|
|
|
OnZoomLess();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if( bSpace && bLMB)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_ROTATING_VIEWER;
|
|
|
|
|
}
|
|
|
|
|
// we have viewer movement in view plane
|
|
|
|
|
else if( bSpace && !bShift)
|
|
|
|
|
{
|
|
|
|
|
if( bSpace) m_iaInputAction = IA_MOVING_VIEWER_IN_VIEW_PLANE;
|
|
|
|
|
StartMouseInput( point);
|
|
|
|
|
}
|
|
|
|
|
// second layer movements
|
|
|
|
|
else if( bCSGOn)
|
|
|
|
|
{
|
|
|
|
|
// if ctrl+rmb pressed, we want to move second layer in view plane
|
|
|
|
|
if( bCtrl && !bShift)
|
|
|
|
|
{
|
|
|
|
|
if( bLMB) m_iaInputAction = IA_ROTATING_SECOND_LAYER;
|
|
|
|
|
else m_iaInputAction = IA_MOVING_SECOND_LAYER_IN_VIEW_PLANE;
|
|
|
|
|
StartMouseInput( point);
|
|
|
|
|
}
|
|
|
|
|
// test for mouse operations used while primitive CSG is on
|
|
|
|
|
else if( pDoc->m_bPrimitiveMode)
|
|
|
|
|
{
|
|
|
|
|
// ctrl+shift+rmb sheares primitive
|
|
|
|
|
if( bCtrl && bShift)
|
|
|
|
|
{
|
|
|
|
|
if( m_ptProjectionType != CSlaveViewer::PT_PERSPECTIVE)
|
|
|
|
|
m_iaInputAction = IA_SHEARING_PRIMITIVE;
|
|
|
|
|
}
|
|
|
|
|
// shift+rmb in deletes vertex on base of primitive
|
|
|
|
|
else if( bShift && !bCtrl && !bLMB && !bSpace)
|
|
|
|
|
{
|
|
|
|
|
MarkClosestVtxAndEdgeOnPrimitiveBase( point);
|
|
|
|
|
if( m_iDragVertice != -1) pDoc->DeletePrimitiveVertex( m_iDragVertice);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
// measure and cut modes disable all functions
|
|
|
|
|
if( theApp.m_bMeasureModeOn || theApp.m_bCutModeOn)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
if( bAlt && bShift)
|
|
|
|
|
{
|
|
|
|
|
OnDeselectByOrientation();
|
|
|
|
|
}
|
|
|
|
|
// alt+ctrl+rmb sizes polygon's texture
|
|
|
|
|
else if( bAlt && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
MultiplyMappingOnPolygon( 2.0f);
|
|
|
|
|
}
|
|
|
|
|
else if( bCtrl && bLMB)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_ROTATING_POLYGON_MAPPING;
|
|
|
|
|
}
|
|
|
|
|
// shift turns on portal testing
|
|
|
|
|
else if( bShift && !bCtrl)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_SELECTING_POLYGONS;
|
|
|
|
|
// cast ray but ask if test for portal hits
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( point, TRUE, FALSE);
|
|
|
|
|
ToggleHittedPolygon( crRayHit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == SECTOR_MODE)
|
|
|
|
|
{
|
|
|
|
|
// shift turns on portal testing
|
|
|
|
|
if( bShift)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_SELECTING_SECTORS;
|
|
|
|
|
// cast ray but ask if test for portal hits
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( point, TRUE, FALSE);
|
|
|
|
|
ToggleHittedSector( crRayHit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CEntity *penBrush = pMainFrame->m_CSGDesitnationCombo.GetSelectedBrushEntity();
|
|
|
|
|
// if we should start mip setting mode
|
|
|
|
|
if( bShift && bCtrl && !bAlt && (penBrush != NULL) )
|
|
|
|
|
{
|
|
|
|
|
if( m_iaInputAction == IA_MIP_SETTING) return;
|
|
|
|
|
// get entity's brush
|
|
|
|
|
CBrush3D *pbrBrush = penBrush->GetBrush();
|
|
|
|
|
if( pbrBrush != NULL)
|
|
|
|
|
{
|
|
|
|
|
CChildFrame *pChild = GetChildFrame();
|
|
|
|
|
// set auto mip brushing mode as it was before mip setting started
|
|
|
|
|
pChild->m_bLastAutoMipBrushingOn = pChild->m_bAutoMipBrushingOn;
|
|
|
|
|
// get curently active mip factor
|
|
|
|
|
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
|
|
|
|
|
// get the mip brush for current factor
|
|
|
|
|
m_pbmToSetMipSwitch = pbrBrush->GetBrushMipByDistance(fCurrentMipFactor);
|
|
|
|
|
// if we are in automatic mip brushing mode
|
|
|
|
|
if( (GetChildFrame()->m_bAutoMipBrushingOn) && (m_pbmToSetMipSwitch != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// set manual mip factor so current mip brush would be visible
|
|
|
|
|
GetChildFrame()->m_fManualMipBrushingFactor = fCurrentMipFactor;
|
|
|
|
|
// set manual mip brushing mode
|
|
|
|
|
GetChildFrame()->m_bAutoMipBrushingOn = FALSE;
|
|
|
|
|
m_iaInputAction = IA_MIP_SETTING;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_NONE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_NONE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Alt+Ctrl+RMB sets clicked entity as target on first available free target ptr slot
|
|
|
|
|
else if( bAlt && bCtrl && !bShift && (pDoc->m_selEntitySelection.Count() != 0))
|
|
|
|
|
{
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( point, FALSE, bHitModels, bHitFields);
|
|
|
|
|
if(crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
// get first empty selected property
|
|
|
|
|
pMainFrame->m_PropertyComboBar.SetFirstValidEmptyTargetProperty( crRayHit.cr_penHit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if ctrl+rmb pressed, we want to move entity selection in view plane
|
|
|
|
|
else if( bCtrl && !bShift && !bAlt)
|
|
|
|
|
{
|
|
|
|
|
if( bLMB) m_iaInputAction = IA_ROTATING_ENTITY_SELECTION;
|
|
|
|
|
else m_iaInputAction = IA_MOVING_ENTITY_SELECTION_IN_VIEW_PLANE;
|
|
|
|
|
StartMouseInput( point);
|
|
|
|
|
}
|
|
|
|
|
else if( bShift && bSpace && !GetChildFrame()->m_bAutoMipBrushingOn)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_MANUAL_MIP_SWITCH_FACTOR_CHANGING;
|
|
|
|
|
}
|
|
|
|
|
else if( bShift && bAlt)
|
|
|
|
|
{
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( point, FALSE, bHitModels, bHitFields);
|
|
|
|
|
ShowLinkTree(crRayHit.cr_penHit, TRUE, bCaps);
|
|
|
|
|
}
|
|
|
|
|
else if( bShift)
|
|
|
|
|
{
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( point, FALSE, bHitModels, bHitFields);
|
|
|
|
|
ShowLinkTree(crRayHit.cr_penHit, FALSE, bCaps);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if we are in vertex mode
|
|
|
|
|
else if( pDoc->GetEditingMode() == VERTEX_MODE)
|
|
|
|
|
{
|
|
|
|
|
if( bCtrl)
|
|
|
|
|
{
|
|
|
|
|
if( bLMB)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_ROTATE_BRUSH_VERTEX;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_DRAG_BRUSH_VERTEX_IN_VIEW_PLANE;
|
|
|
|
|
}
|
|
|
|
|
// clear polygon selection because some of the old polygons could disappear
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
pDoc->m_woWorld.TriangularizeForVertices( pDoc->m_selVertexSelection);
|
|
|
|
|
StartMouseInput( point);
|
|
|
|
|
}
|
|
|
|
|
if( bShift)
|
|
|
|
|
{
|
|
|
|
|
if(pDoc->m_selVertexSelection.Count()==3)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_woWorld.CreatePolygon(pDoc->m_selVertexSelection);
|
|
|
|
|
pDoc->ClearSelections();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if we are in terrain mode
|
|
|
|
|
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
InvokeSelectLayerCombo();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CView::OnRButtonDown(nFlags, point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnLButtonUp(UINT nFlags, CPoint point)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
BOOL bShift = nFlags & MK_SHIFT;
|
|
|
|
|
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
|
|
|
|
|
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
|
|
|
|
|
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
|
|
|
|
|
StopMouseInput();
|
|
|
|
|
// if measure mode on
|
|
|
|
|
if( theApp.m_bMeasureModeOn)
|
|
|
|
|
{
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if we are in browse by volume mode and lmb released, refresh first selected volume
|
|
|
|
|
if( pDoc->m_bBrowseEntitiesMode && !bSpace && !bCtrl)
|
|
|
|
|
{
|
|
|
|
|
pDoc->SelectEntitiesByVolumeBox();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
if( m_iaInputAction == IA_SELECTING_ENTITIES)
|
|
|
|
|
{
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( point, FALSE, TRUE, TRUE);
|
|
|
|
|
// if we hit some entity
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
// if shift is not pressed
|
|
|
|
|
if( !bShift)
|
|
|
|
|
{
|
|
|
|
|
BOOL bWasSelected = crRayHit.cr_penHit->IsSelected( ENF_SELECTED);
|
|
|
|
|
// deselect all selected entities
|
|
|
|
|
INDEX ctSelectedBefore = pDoc->m_selEntitySelection.Count();
|
|
|
|
|
pDoc->m_selEntitySelection.Clear();
|
|
|
|
|
// if entity was not selected before
|
|
|
|
|
if( !((ctSelectedBefore == 1) && bWasSelected))
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *crRayHit.cr_penHit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// if entity is not yet selected
|
|
|
|
|
if( !crRayHit.cr_penHit->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *crRayHit.cr_penHit);
|
|
|
|
|
}
|
|
|
|
|
// otherwise deselect it
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selEntitySelection.Deselect( *crRayHit.cr_penHit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
|
|
|
|
|
// and refresh property combo manualy calling on idle
|
|
|
|
|
pMainFrame->m_PropertyComboBar.m_PropertyComboBox.OnIdle( 0);
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( this);
|
|
|
|
|
}
|
|
|
|
|
else if( m_iaInputAction == IA_SELECT_LASSO_ENTITY)
|
|
|
|
|
{
|
|
|
|
|
m_bRequestEntityLassoSelect = TRUE;
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( pDoc->GetEditingMode() == VERTEX_MODE)
|
|
|
|
|
{
|
|
|
|
|
if( m_iaInputAction == IA_SELECT_SINGLE_BRUSH_VERTEX)
|
|
|
|
|
{
|
|
|
|
|
m_bRequestVtxClickSelect = TRUE;
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
else if( m_iaInputAction == IA_SELECT_LASSO_BRUSH_VERTEX)
|
|
|
|
|
{
|
|
|
|
|
m_bRequestVtxLassoSelect = TRUE;
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
else if(
|
|
|
|
|
(m_iaInputAction == IA_DRAG_BRUSH_VERTEX_IN_FLOOR_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_DRAG_BRUSH_VERTEX_IN_VIEW_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_STRETCH_BRUSH_VERTEX) ||
|
|
|
|
|
(m_iaInputAction == IA_ROTATE_BRUSH_VERTEX) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_woWorld.UpdateSectorsAfterVertexChange( pDoc->m_selVertexSelection);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_iaInputAction = IA_NONE;
|
|
|
|
|
|
|
|
|
|
CView::OnLButtonUp(nFlags, point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRButtonUp(UINT nFlags, CPoint point)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( m_iaInputAction == IA_MIP_SETTING)
|
|
|
|
|
{
|
|
|
|
|
SetMipBrushFactor();
|
|
|
|
|
}
|
|
|
|
|
else if(
|
|
|
|
|
(m_iaInputAction == IA_DRAG_BRUSH_VERTEX_IN_FLOOR_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_DRAG_BRUSH_VERTEX_IN_VIEW_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_STRETCH_BRUSH_VERTEX) ||
|
|
|
|
|
(m_iaInputAction == IA_ROTATE_BRUSH_VERTEX) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_woWorld.UpdateSectorsAfterVertexChange( pDoc->m_selVertexSelection);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_iaInputAction = IA_NONE;
|
|
|
|
|
StopMouseInput();
|
|
|
|
|
CView::OnRButtonUp(nFlags, point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// select all descendents of selected entity
|
|
|
|
|
void SelectDescendents( CEntitySelection &selEntity, CEntity &enParent)
|
|
|
|
|
{
|
|
|
|
|
FOREACHINLIST( CEntity, en_lnInParent, enParent.en_lhChildren, itenChild)
|
|
|
|
|
{
|
|
|
|
|
SelectDescendents( selEntity, *itenChild);
|
|
|
|
|
}
|
|
|
|
|
if( !enParent.IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
selEntity.Select( enParent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnLButtonDblClk(UINT nFlags, CPoint point)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_NONE;
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
BOOL bSpace = (GetKeyState( ' ') & 128) != 0;
|
|
|
|
|
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
|
|
|
|
|
BOOL bCtrl = nFlags & MK_CONTROL;
|
|
|
|
|
BOOL bShift = nFlags & MK_SHIFT;
|
|
|
|
|
BOOL bRMB = (GetKeyState( VK_RBUTTON)&0x8000) != 0;
|
|
|
|
|
|
|
|
|
|
// space+ctrl+lmb zoomes in 2x
|
|
|
|
|
if( (bSpace) && (bCtrl))
|
|
|
|
|
{
|
|
|
|
|
if( bRMB) return;
|
|
|
|
|
// set new target
|
|
|
|
|
GetChildFrame()->m_mvViewer.SetTargetPlacement( m_vHitOnMouseDown);
|
|
|
|
|
// move mouse to center of screen
|
|
|
|
|
CPoint ptCenter = CPoint( m_pdpDrawPort->GetWidth()/2, m_pdpDrawPort->GetHeight()/2);
|
|
|
|
|
ClientToScreen( &ptCenter);
|
|
|
|
|
SetCursorPos(ptCenter.x, ptCenter.y);
|
|
|
|
|
OnZoomMore();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( point);
|
|
|
|
|
|
|
|
|
|
// space + doubble click center point that mouse points to
|
|
|
|
|
if( bSpace)
|
|
|
|
|
{
|
|
|
|
|
// set new target
|
|
|
|
|
GetChildFrame()->m_mvViewer.SetTargetPlacement( crRayHit.cr_vHit);
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
// if we are in measure or cut mode, no operation
|
|
|
|
|
else if( theApp.m_bMeasureModeOn || theApp.m_bCutModeOn)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
// if we are in sector mode, no operation
|
|
|
|
|
else if( pDoc->GetEditingMode() == SECTOR_MODE)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
// if we are in polygon mode, select similar polygons
|
|
|
|
|
else if( pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
// Alt+Ctrl+RMB requests that clicked polygon sizes its texture
|
|
|
|
|
if( bAlt && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
MultiplyMappingOnPolygon( 0.5f);
|
|
|
|
|
}
|
|
|
|
|
// if we hit some brush entity
|
|
|
|
|
else if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL))
|
|
|
|
|
{
|
|
|
|
|
// if shift is not pressed, delelect all polygons
|
|
|
|
|
if( !bShift && !bCtrl)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LMBx2 centers mapping on polygon
|
|
|
|
|
if( bCtrl && !bShift &&(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygon &bpo = *crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
CEntity *pen = bpo.bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
|
|
|
|
|
CMappingDefinition mdOriginal = bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
|
|
|
|
|
CMappingDefinition mdTranslated = mdOriginal;
|
|
|
|
|
CSimpleProjection3D pr;
|
|
|
|
|
pr.ObjectPlacementL() = _plOrigin;
|
|
|
|
|
pr.ViewerPlacementL() = pen->GetPlacement();
|
|
|
|
|
pr.Prepare();
|
|
|
|
|
FLOAT3D vRelative;
|
|
|
|
|
pr.ProjectCoordinate(crRayHit.cr_vHit, vRelative);
|
|
|
|
|
CMappingDefinition mdRelative = theApp.m_mdMapping;
|
|
|
|
|
mdTranslated.Center(bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative, vRelative);
|
|
|
|
|
FLOAT fUOffset = mdTranslated.md_fUOffset-mdOriginal.md_fUOffset;
|
|
|
|
|
FLOAT fVOffset = mdTranslated.md_fVOffset-mdOriginal.md_fVOffset;
|
|
|
|
|
if( !crRayHit.cr_pbpoBrushPolygon->IsSelected(BPOF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// add the offsets to its mapping
|
|
|
|
|
crRayHit.cr_pbpoBrushPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fUOffset+=fUOffset;
|
|
|
|
|
crRayHit.cr_pbpoBrushPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fVOffset+=fVOffset;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// for each selected polygon
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
// add the offsets to its mapping
|
|
|
|
|
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fUOffset+=fUOffset;
|
|
|
|
|
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fVOffset+=fVOffset;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
// Ctrl+Shift+LMBx2 slects similar by texture in sector
|
|
|
|
|
else if( bCtrl && bShift)
|
|
|
|
|
{
|
|
|
|
|
OnSelectByTextureInSector();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// select similar to hitted polygon
|
|
|
|
|
crRayHit.cr_pbpoBrushPolygon->SelectSimilarByColor( pDoc->m_selPolygonSelection);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == VERTEX_MODE)
|
|
|
|
|
{
|
|
|
|
|
// if we hit some polygon
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) && (crRayHit.cr_pbpoBrushPolygon != NULL))
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygon &bpo=*crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
// select vertices
|
|
|
|
|
FOREACHINSTATICARRAY(bpo.bpo_apbvxTriangleVertices, CBrushVertex *, itpbvx)
|
|
|
|
|
{
|
|
|
|
|
if( !(*itpbvx)->IsSelected(BVXF_SELECTED)) pDoc->m_selVertexSelection.Select( **itpbvx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if we are in entity mode
|
|
|
|
|
else if( pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
// if nothing pressed
|
|
|
|
|
if( !bCtrl && !bAlt && !bSpace)
|
|
|
|
|
{
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
SelectDescendents( pDoc->m_selEntitySelection, *crRayHit.cr_penHit);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CTRL + LMB teleports entities
|
|
|
|
|
if( (pDoc->m_selEntitySelection.Count() != 0) && (bCtrl) && (!bAlt) )
|
|
|
|
|
{
|
|
|
|
|
// lock selection's dynamic container
|
|
|
|
|
pDoc->m_selEntitySelection.Lock();
|
|
|
|
|
FLOATaabbox3D box;
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
box |= iten->GetPlacement().pl_PositionVector;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
FLOAT3D f3dCenter = box.Center();
|
|
|
|
|
f3dCenter(2) = box.Min()(2);
|
|
|
|
|
FLOAT3D f3dOffset = crRayHit.cr_vHit - f3dCenter;
|
|
|
|
|
CEntity *penBrush = NULL;
|
|
|
|
|
// for each of the selected entities
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
if (iten->en_RenderType == CEntity::RT_BRUSH) {
|
|
|
|
|
penBrush = &*iten;
|
|
|
|
|
}
|
|
|
|
|
// if movement of anchored entities is allowed or entity is not anchored
|
|
|
|
|
if( (((iten->GetFlags() & ENF_ANCHORED) == 0) ||
|
|
|
|
|
(GetChildFrame()->m_bAncoredMovingAllowed)) &&
|
|
|
|
|
((iten->GetParent()==NULL) || !(iten->GetParent()->IsSelected( ENF_SELECTED))) )
|
|
|
|
|
{
|
|
|
|
|
// get placement of current entity
|
|
|
|
|
CPlacement3D plEntityPlacement = iten->GetPlacement();
|
|
|
|
|
plEntityPlacement.pl_PositionVector += f3dOffset;
|
|
|
|
|
// snap to grid entity's placement
|
|
|
|
|
pDoc->SnapToGrid( plEntityPlacement, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
// set placement back to entity
|
|
|
|
|
iten->SetPlacement( plEntityPlacement);
|
|
|
|
|
// mark that document is changed
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
}
|
|
|
|
|
if( penBrush != NULL)
|
|
|
|
|
{
|
|
|
|
|
DiscardShadows( penBrush);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
// refresh position page
|
|
|
|
|
pDoc->RefreshCurrentInfoPage();
|
|
|
|
|
}
|
|
|
|
|
// if we are in csg mode, CTRL + LMB teleports second layer's world (primitive)
|
|
|
|
|
else if( (pDoc->GetEditingMode() == CSG_MODE) && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
// set new placement of second layer
|
|
|
|
|
pDoc->m_plSecondLayer.pl_PositionVector = crRayHit.cr_vHit;
|
|
|
|
|
// snap to grid whole second layer's placement
|
|
|
|
|
pDoc->SnapToGrid( pDoc->m_plSecondLayer, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
theApp.m_vfpCurrent.vfp_plPrimitive = pDoc->m_plSecondLayer;
|
|
|
|
|
// refresh all views
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
// refresh position page
|
|
|
|
|
pDoc->RefreshCurrentInfoPage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CView::OnLButtonDblClk(nFlags, point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::CallPopupMenu(CPoint point)
|
|
|
|
|
{
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
BOOL bHitFields = (pDoc->GetEditingMode() == ENTITY_MODE);
|
|
|
|
|
// obtain information about where mouse pointed into the world in the moment of mouse down
|
|
|
|
|
CCastRay crRayHitOnContext = GetMouseHitInformation( point, FALSE, TRUE, bHitFields);
|
|
|
|
|
|
|
|
|
|
// create popup menu
|
|
|
|
|
CMenu menu;
|
|
|
|
|
INDEX iMenuID;
|
|
|
|
|
// choose popup menu
|
|
|
|
|
switch( pDoc->GetEditingMode())
|
|
|
|
|
{
|
|
|
|
|
case POLYGON_MODE:{ iMenuID = IDR_POLYGON_POPUP; break; }
|
|
|
|
|
case SECTOR_MODE:{ iMenuID = IDR_SECTOR_POPUP;break; }
|
|
|
|
|
case VERTEX_MODE:{ iMenuID = IDR_VERTEX_POPUP;break; }
|
|
|
|
|
case ENTITY_MODE:{ iMenuID = IDR_ENTITY_POPUP;break; }
|
|
|
|
|
case TERRAIN_MODE:{ iMenuID = IDR_TERRAIN_POPUP;break; }
|
|
|
|
|
case CSG_MODE:
|
|
|
|
|
{
|
|
|
|
|
if( pDoc->m_bPrimitiveMode) iMenuID = IDR_CSG_PRIMITIVE_POPUP;
|
|
|
|
|
else iMenuID = IDR_CSG_TEMPLATE_POPUP;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: { FatalError("Unknown editing mode."); break;};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// load popup menu
|
|
|
|
|
if( menu.LoadMenu(iMenuID))
|
|
|
|
|
{
|
|
|
|
|
BOOL bEntityClicked = FALSE;
|
|
|
|
|
BOOL bBrushClicked = FALSE;
|
|
|
|
|
BOOL bSecondLayerHited = FALSE;
|
|
|
|
|
BOOL bPortalClicked = FALSE;
|
|
|
|
|
m_penEntityHitOnContext = NULL;
|
|
|
|
|
|
|
|
|
|
if( crRayHitOnContext.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
m_penEntityHitOnContext = crRayHitOnContext.cr_penHit;
|
|
|
|
|
bEntityClicked = TRUE;
|
|
|
|
|
// test if we hited second layer
|
|
|
|
|
if( crRayHitOnContext.cr_penHit->GetWorld() != &pDoc->m_woWorld)
|
|
|
|
|
{
|
|
|
|
|
bSecondLayerHited = TRUE;
|
|
|
|
|
}
|
|
|
|
|
m_plEntityHitOnContext = crRayHitOnContext.cr_penHit->GetPlacement();
|
|
|
|
|
m_plEntityHitOnContext.pl_PositionVector = crRayHitOnContext.cr_vHit;
|
|
|
|
|
|
|
|
|
|
CEntity::RenderType rt = crRayHitOnContext.cr_penHit->GetRenderType();
|
|
|
|
|
if( rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
|
|
|
|
|
{
|
|
|
|
|
bBrushClicked = TRUE;
|
|
|
|
|
}
|
|
|
|
|
m_pbpoRightClickedPolygon = crRayHitOnContext.cr_pbpoBrushPolygon;
|
|
|
|
|
if( m_pbpoRightClickedPolygon != NULL)
|
|
|
|
|
{
|
|
|
|
|
bPortalClicked = m_pbpoRightClickedPolygon->bpo_ulFlags & BPOF_PORTAL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// remember if we hited any entity with cntext menu
|
|
|
|
|
m_bEntityHitedOnContext = bEntityClicked;
|
|
|
|
|
CMenu* pPopup = menu.GetSubMenu(0);
|
|
|
|
|
|
|
|
|
|
pPopup->EnableMenuItem( ID_ENTITY_CONTEXT_HELP, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_SET_AS_CSG_TARGET, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
if(bBrushClicked && !bSecondLayerHited) pPopup->EnableMenuItem(ID_SET_AS_CSG_TARGET, MF_ENABLED);
|
|
|
|
|
|
|
|
|
|
// disable commands that can't be applied
|
|
|
|
|
switch( pDoc->GetEditingMode())
|
|
|
|
|
{
|
|
|
|
|
case POLYGON_MODE:
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_POLYGON_MODE, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
if( !bPortalClicked)
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_SELECT_SECTORS_OTHER_SIDE, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !bBrushClicked)
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_MENU_COPY_MAPPING, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_COPY_TEXTURE, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_SELECT_BY_TEXTURE_ADJACENT, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_SELECT_BY_TEXTURE_IN_SECTOR, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_SELECT_BY_COLOR_IN_SECTOR, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_FIND_TEXTURE, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_DESELECT_BY_ORIENTATION, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
if( pDoc->m_selPolygonSelection.Count() == 0)
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_FILTER_SELECTION, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_CHOOSE_COLOR, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_EXPORT_DISPLACE_MAP, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_RANDOM_OFFSET_U, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_RANDOM_OFFSET_V, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_POLYGONS_TO_BRUSH, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_CLONE_POLYGONS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_DELETE_POLYGONS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
if( !pDoc->m_woWorld.CanJoinPolygons( pDoc->m_selPolygonSelection))
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem( ID_CSG_JOIN_POLYGONS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
if( !pDoc->m_woWorld.CanJoinAllPossiblePolygons( pDoc->m_selPolygonSelection))
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem( ID_CSG_JOIN_ALL_POLYGONS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
BOOL bEnableRetripling = FALSE;
|
|
|
|
|
if( pDoc->m_selPolygonSelection.Count() != 0)
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygon *pbpo = pDoc->m_selPolygonSelection.GetFirstInSelection();
|
|
|
|
|
bEnableRetripling = pbpo->bpo_pbscSector->IsReTripleAvailable( pDoc->m_selPolygonSelection);
|
|
|
|
|
}
|
|
|
|
|
if( !bEnableRetripling)
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem( ID_RE_TRIPLE, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !pDoc->m_woWorld.CanJoinPolygons( pDoc->m_selPolygonSelection))
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem( ID_CSG_JOIN_POLYGONS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SECTOR_MODE:
|
|
|
|
|
{
|
|
|
|
|
if( !bBrushClicked)
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_SELECT_LINKS_TO_SECTOR, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_SELECT_SECTORS_WITH_SAME_NAME, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
if( pDoc->m_selSectorSelection.Count() == 0)
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_HIDE_SELECTED_SECTORS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_HIDE_UNSELECTED_SECTORS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_DELETE_SECTORS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_CHOOSE_COLOR, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_SECTORS_TO_BRUSH, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !pDoc->m_woWorld.CanCopySectors(pDoc->m_selSectorSelection))
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem( ID_COPY_SECTORS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem( ID_EDIT_COPY_ALTERNATIVE, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( pDoc->m_woWorld.CanJoinSectors(pDoc->m_selSectorSelection))
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem( ID_CSG_JOIN_SECTORS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TERRAIN_MODE:
|
|
|
|
|
{
|
|
|
|
|
CTerrain *ptrTerrain=GetTerrain();
|
|
|
|
|
if(ptrTerrain==NULL)
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem( ID_PICK_LAYER, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem( ID_SELECT_LAYER, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem( ID_CHANGE_TERRAIN_SIZE, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem( ID_CHANGE_HEIGHTMAP_SIZE, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem( ID_RECALCULATE_TERRAIN_SHADOWS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem( ID_OPTIMIZE_TERRAIN, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem( ID_IMPORT_HEIGHTMAP, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem( ID_IMPORT_HEIGHTMAP16, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem( ID_EXPORT_HEIGHTMAP, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem( ID_EXPORT_HEIGHTMAP16, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem( ID_VIEW_HEIGHTMAP, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
|
|
|
|
|
CTerrainLayer *ptlLayer=GetLayer();
|
|
|
|
|
if(ptlLayer==NULL)
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem( ID_LAYER_OPTIONS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ENTITY_MODE:
|
|
|
|
|
{
|
|
|
|
|
if( bEntityClicked)
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_ENTITY_CONTEXT_HELP, MF_ENABLED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL bDisableSelectTarget = FALSE;
|
|
|
|
|
if( pDoc->m_selEntitySelection.Count() == 1)
|
|
|
|
|
{
|
|
|
|
|
CPropertyID *ppidProperty = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
|
|
|
|
|
if( (ppidProperty == NULL) ||
|
|
|
|
|
!((ppidProperty->pid_eptType == CEntityProperty::EPT_PARENT) ||
|
|
|
|
|
(ppidProperty->pid_eptType == CEntityProperty::EPT_ENTITYPTR)))
|
|
|
|
|
{
|
|
|
|
|
bDisableSelectTarget = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bDisableSelectTarget = TRUE;
|
|
|
|
|
}
|
|
|
|
|
if( bDisableSelectTarget)
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_SELECT_TARGET, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pPopup->EnableMenuItem(ID_ENTITY_MODE, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
// see if should disable delete
|
|
|
|
|
if( !IsDeleteEntityEnabled())
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_DELETE_ENTITIES, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
// if clear all target is disabled
|
|
|
|
|
if( !m_bEntityHitedOnContext)
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_ROTATE_TO_TARGET_ORIGIN, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_ROTATE_TO_TARGET_CENTER, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_COPY_POSITION, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_COPY_ORIENTATION, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_COPY_PLACEMENT, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
|
|
|
|
|
pPopup->EnableMenuItem(ID_PASTE_POSITION, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
|
|
|
|
|
pPopup->EnableMenuItem(ID_CLEAR_ALL_TARGETS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
// if clone updating is disabled
|
|
|
|
|
if( !pDoc->IsCloneUpdatingAllowed())
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_UPDATE_CLONES, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
// if brush updating is disabled
|
|
|
|
|
if( !pDoc->IsBrushUpdatingAllowed())
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_UPDATE_BRUSHES, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
// if copy is not allowed
|
|
|
|
|
if( pDoc->m_selEntitySelection.Count() == 0)
|
|
|
|
|
{
|
|
|
|
|
pPopup->EnableMenuItem(ID_EDIT_COPY, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
pPopup->EnableMenuItem(ID_SELECT_DESCENDANTS, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
// if clipboard world does not exist
|
|
|
|
|
if( GetFileAttributesA( _fnmApplicationPath + "Temp\\ClipboardWorld.wld") == -1)
|
|
|
|
|
{
|
|
|
|
|
// disable pasting
|
|
|
|
|
pPopup->EnableMenuItem(ID_EDIT_PASTE, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
if( !IsSelectClonesOnContextEnabled())
|
|
|
|
|
{
|
|
|
|
|
// disable select clones
|
|
|
|
|
pPopup->EnableMenuItem(ID_SELECT_CLONES_ON_CONTEXT, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
if( !IsSelectOfSameClassOnContextEnabled())
|
|
|
|
|
{
|
|
|
|
|
// disable select clones
|
|
|
|
|
pPopup->EnableMenuItem(ID_SELECT_OF_SAME_CLASS_ON_CONTEXT, MF_DISABLED|MF_GRAYED);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// convert mouse coordinates into screen coordinates
|
|
|
|
|
ClientToScreen( &point);
|
|
|
|
|
|
|
|
|
|
// call popup menu
|
|
|
|
|
pPopup->TrackPopupMenu( TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
|
|
|
|
|
point.x, point.y, this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::SetEditingDataPaneInfo( BOOL bImidiateRepainting)
|
|
|
|
|
{
|
|
|
|
|
// obtain current time
|
|
|
|
|
FLOAT fTimeNow = _pTimer->GetRealTimeTick();
|
|
|
|
|
// get difference to time when last mip brushing option has been used
|
|
|
|
|
FLOAT fSecondsPassed = fTimeNow-_fLastMipBrushingOptionUsed;
|
|
|
|
|
// if we used any mip brushing option inside last 30 seconds
|
|
|
|
|
BOOL bUsingMipBrushing;
|
|
|
|
|
if( fSecondsPassed < 120) bUsingMipBrushing = TRUE;
|
|
|
|
|
else bUsingMipBrushing = FALSE;
|
|
|
|
|
|
|
|
|
|
// get draw port
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
// if it is not valid
|
|
|
|
|
if( pdpValidDrawPort == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !theApp.m_bShowStatusInfo)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
char strDataPaneText[ 128];
|
|
|
|
|
// obtain button statuses and interesting flags
|
|
|
|
|
BOOL bSpace = (GetKeyState( ' ') & 128) != 0;
|
|
|
|
|
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
BOOL bLMB = (GetKeyState( VK_LBUTTON)&0x8000) != 0;
|
|
|
|
|
BOOL bRMB = (GetKeyState( VK_RBUTTON)&0x8000) != 0;
|
|
|
|
|
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
|
|
|
|
|
BOOL bEntityMode = pDoc->GetEditingMode() == ENTITY_MODE;
|
|
|
|
|
BOOL bPolygonMode = pDoc->GetEditingMode() == POLYGON_MODE;
|
|
|
|
|
BOOL bTerrainMode = pDoc->GetEditingMode() == TERRAIN_MODE;
|
|
|
|
|
BOOL bVertexMode = pDoc->GetEditingMode() == VERTEX_MODE;
|
|
|
|
|
CEntity *penBrush = pMainFrame->m_CSGDesitnationCombo.GetSelectedBrushEntity();
|
|
|
|
|
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
|
|
|
|
|
//---------------- Now we will prepare status line' text describing editing data
|
|
|
|
|
|
|
|
|
|
if( theApp.m_bMeasureModeOn)
|
|
|
|
|
{
|
|
|
|
|
strcpy( strDataPaneText, m_strMeasuring);
|
|
|
|
|
}
|
|
|
|
|
else if( theApp.m_bCutModeOn)
|
|
|
|
|
{
|
|
|
|
|
sprintf( strDataPaneText, "Cut/Mirror mode");
|
|
|
|
|
}
|
|
|
|
|
else if( (penBrush != NULL) && bUsingMipBrushing)
|
|
|
|
|
{
|
|
|
|
|
CBrush3D *pbrBrush = penBrush->GetBrush();
|
|
|
|
|
ASSERT( pbrBrush != NULL);
|
|
|
|
|
// get currently active mip factor
|
|
|
|
|
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
|
|
|
|
|
// get mip brush
|
|
|
|
|
if( pbrBrush != NULL)
|
|
|
|
|
{
|
|
|
|
|
CBrushMip *pbmCurrentMip = pbrBrush->GetBrushMipByDistance( fCurrentMipFactor);
|
|
|
|
|
if( pbmCurrentMip != NULL)
|
|
|
|
|
{
|
|
|
|
|
// get mip switch factor for currently visible brush
|
|
|
|
|
FLOAT fCurrentMipSwitchFactor = pbmCurrentMip->GetMipDistance();
|
|
|
|
|
// so prepare string telling selected brush's mip switch factor
|
|
|
|
|
sprintf( strDataPaneText, "factor=%.2f, mip=%d/%d, switch=%.2f",
|
|
|
|
|
fCurrentMipFactor, pbmCurrentMip->GetMipIndex(),
|
|
|
|
|
pbrBrush->br_lhBrushMips.Count(), fCurrentMipSwitchFactor);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// so prepare string telling selected brush's mip switch factor
|
|
|
|
|
sprintf( strDataPaneText, "factor=%.2f, after last mip", fCurrentMipFactor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// brush wasn't valid, report error
|
|
|
|
|
sprintf( strDataPaneText, "entity has invalid brush");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if space pressed, we are interested in viewer placement
|
|
|
|
|
else if( bSpace)
|
|
|
|
|
{
|
|
|
|
|
// get viewer position and orientation data
|
|
|
|
|
CPlacement3D plViewer = GetChildFrame()->m_mvViewer.GetViewerPlacement();
|
|
|
|
|
// if both mouses are pressed, we want to rotate viewer
|
|
|
|
|
if( bLMB && bRMB)
|
|
|
|
|
{
|
|
|
|
|
// so prepare string telling viewer orientation
|
|
|
|
|
sprintf( strDataPaneText, "H=%g P=%g B=%g",
|
|
|
|
|
DegAngle( plViewer.pl_OrientationAngle(1)),
|
|
|
|
|
DegAngle( plViewer.pl_OrientationAngle(2)),
|
|
|
|
|
DegAngle( plViewer.pl_OrientationAngle(3)) );
|
|
|
|
|
}
|
|
|
|
|
// we are interested in viewer's current position
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// so prepare string telling viewer position
|
|
|
|
|
sprintf( strDataPaneText, "X=%g Y=%g Z=%g",
|
|
|
|
|
plViewer.pl_PositionVector(1),
|
|
|
|
|
plViewer.pl_PositionVector(2),
|
|
|
|
|
plViewer.pl_PositionVector(3) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( (bVertexMode) && ( pDoc->m_selVertexSelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
// so prepare string telling entity position
|
|
|
|
|
if (pDoc->m_selVertexSelection.Count()==1) {
|
|
|
|
|
const FLOAT3D &v = pDoc->m_selVertexSelection.GetFirst().bvx_vAbsolute;
|
|
|
|
|
sprintf( strDataPaneText, "%f,%f,%f", v(1), v(2), v(3));
|
|
|
|
|
} else {
|
|
|
|
|
sprintf( strDataPaneText, "Dragging %d vertices", pDoc->m_selVertexSelection.Count());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if we are in entity mode and there is selected entity
|
|
|
|
|
else if( (bEntityMode) && ( pDoc->m_selEntitySelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
// lock selection's dynamic container
|
|
|
|
|
pDoc->m_selEntitySelection.Lock();
|
|
|
|
|
// get first entity
|
|
|
|
|
CEntity *penEntityOne = pDoc->m_selEntitySelection.Pointer(0);
|
|
|
|
|
// unlock selection's dynamic container
|
|
|
|
|
pDoc->m_selEntitySelection.Unlock();
|
|
|
|
|
// get placement of first entity
|
|
|
|
|
CPlacement3D plEntityOnePlacement = penEntityOne->GetPlacement();
|
|
|
|
|
// if both mouses are pressed, we want to rotate entity so prepare text telling angles
|
|
|
|
|
if( bLMB && bRMB)
|
|
|
|
|
{
|
|
|
|
|
// so prepare string telling entity orientation
|
|
|
|
|
sprintf( strDataPaneText, "H=%g P=%g B=%g",
|
|
|
|
|
DegAngle( plEntityOnePlacement.pl_OrientationAngle(1)),
|
|
|
|
|
DegAngle( plEntityOnePlacement.pl_OrientationAngle(2)),
|
|
|
|
|
DegAngle( plEntityOnePlacement.pl_OrientationAngle(3)) );
|
|
|
|
|
}
|
|
|
|
|
// we are interested in entity one's current position
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// so prepare string telling entity position
|
|
|
|
|
sprintf( strDataPaneText, "X=%g Y=%g Z=%g",
|
|
|
|
|
plEntityOnePlacement.pl_PositionVector(1),
|
|
|
|
|
plEntityOnePlacement.pl_PositionVector(2),
|
|
|
|
|
plEntityOnePlacement.pl_PositionVector(3) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if we are in polygon mode and only one polygon is selected
|
|
|
|
|
else if( (bPolygonMode) && (pDoc->m_selPolygonSelection.Count() == 1) && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selPolygonSelection.Lock();
|
|
|
|
|
CBrushPolygon *pbpoBrushPolygon = pDoc->m_selPolygonSelection.Pointer(0);
|
|
|
|
|
pDoc->m_selPolygonSelection.Unlock();
|
|
|
|
|
|
|
|
|
|
CMappingDefinitionUI mdui;
|
|
|
|
|
pbpoBrushPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.ToUI( mdui);
|
|
|
|
|
// prepare text telling about mapping info
|
|
|
|
|
sprintf( strDataPaneText, "Tex %d: U=%.1f V=%.1f RU=%.1f RV=%.1f",
|
|
|
|
|
pDoc->m_iTexture+1, mdui.mdui_fUOffset, mdui.mdui_fVOffset,
|
|
|
|
|
mdui.mdui_aURotation, mdui.mdui_aVRotation);
|
|
|
|
|
}
|
|
|
|
|
else if( bTerrainMode)
|
|
|
|
|
{
|
|
|
|
|
// pane data text has bee obtained on render's ray cast
|
|
|
|
|
sprintf(strDataPaneText, "%s", m_strTerrainDataPaneText);
|
|
|
|
|
}
|
|
|
|
|
else if( bCSGOn)
|
|
|
|
|
{
|
|
|
|
|
// if primitive mode on and ctrl+shift+RMB pressed
|
|
|
|
|
if( pDoc->m_bPrimitiveMode && bCtrl && bShift && bRMB)
|
|
|
|
|
{
|
|
|
|
|
// prepare pane text telling primitive shear info
|
|
|
|
|
sprintf( strDataPaneText, "Shear X=%g Shear Z=%g",
|
|
|
|
|
theApp.m_vfpCurrent.vfp_fShearX, theApp.m_vfpCurrent.vfp_fShearZ);
|
|
|
|
|
}
|
|
|
|
|
// if primitive mode on and ctrl+shift+LMB pressed
|
|
|
|
|
else if( pDoc->m_bPrimitiveMode && bCtrl && bShift)
|
|
|
|
|
{
|
|
|
|
|
// prepare pane text telling primitive size info
|
|
|
|
|
sprintf( strDataPaneText, "W=%g H=%g L=%g",
|
|
|
|
|
theApp.m_vfpCurrent.vfp_fXMax-theApp.m_vfpCurrent.vfp_fXMin,
|
|
|
|
|
theApp.m_vfpCurrent.vfp_fYMax-theApp.m_vfpCurrent.vfp_fYMin,
|
|
|
|
|
theApp.m_vfpCurrent.vfp_fZMax-theApp.m_vfpCurrent.vfp_fZMin);
|
|
|
|
|
}
|
|
|
|
|
// else if ctrl and both mouses are pressed
|
|
|
|
|
else if( bCtrl && bLMB && bRMB)
|
|
|
|
|
{
|
|
|
|
|
// prepare text telling CSG layer orientation
|
|
|
|
|
sprintf( strDataPaneText, "H=%g P=%g B=%g",
|
|
|
|
|
DegAngle( pDoc->m_plSecondLayer.pl_OrientationAngle(1)),
|
|
|
|
|
DegAngle( pDoc->m_plSecondLayer.pl_OrientationAngle(2)),
|
|
|
|
|
DegAngle( pDoc->m_plSecondLayer.pl_OrientationAngle(3)) );
|
|
|
|
|
}
|
|
|
|
|
// else
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// prepare text telling CSG layer position
|
|
|
|
|
sprintf( strDataPaneText, "X=%g Y=%g Z=%g",
|
|
|
|
|
pDoc->m_plSecondLayer.pl_PositionVector(1),
|
|
|
|
|
pDoc->m_plSecondLayer.pl_PositionVector(2),
|
|
|
|
|
pDoc->m_plSecondLayer.pl_PositionVector(3) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// sprintf( strDataPaneText, "Idle time");
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if any kind of entity was hitted
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
// get hitted coordinate
|
|
|
|
|
FLOAT3D f3Coordinate = crRayHit.cr_vHit;
|
|
|
|
|
// snap it
|
|
|
|
|
SnapVector( f3Coordinate);
|
|
|
|
|
|
|
|
|
|
// prepare text describing hitted coordinate
|
|
|
|
|
sprintf( strDataPaneText, "X=%g Y=%g Z=%g", f3Coordinate(1), f3Coordinate(2), f3Coordinate(3));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// if the ray hits the empty space
|
|
|
|
|
sprintf( strDataPaneText, "Over nothing");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// put editing data info into status line
|
|
|
|
|
pMainFrame->m_wndStatusBar.SetPaneText( POSITION_PANE, CString(strDataPaneText), bImidiateRepainting);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define SCROLL_CHANGE 0.2f
|
|
|
|
|
#define ZOOM_CHANGE 0.05f
|
|
|
|
|
#define ANGLE_CHANGE 1.0f
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnMouseMove(UINT nFlags, CPoint point)
|
|
|
|
|
{
|
|
|
|
|
BOOL bLMB = (GetKeyState( VK_LBUTTON)&0x8000) != 0;
|
|
|
|
|
BOOL bRMB = (GetKeyState( VK_RBUTTON)&0x8000) != 0;
|
|
|
|
|
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
|
|
|
|
|
|
|
|
|
|
if(((m_iaInputAction == IA_SELECT_LASSO_ENTITY) ||
|
|
|
|
|
(m_iaInputAction == IA_SELECT_LASSO_BRUSH_VERTEX)) && !bLMB)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_NONE;
|
|
|
|
|
// discard laso selection
|
|
|
|
|
m_avpixLaso.Clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if neather mouse key is pressed, simulate that action is none
|
|
|
|
|
if( !bLMB && !bRMB) m_iaInputAction = IA_NONE;
|
|
|
|
|
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
CWorldEditorView *pWorldEditorView = theApp.GetActiveView();
|
|
|
|
|
if( pWorldEditorView == NULL) return;
|
|
|
|
|
|
|
|
|
|
HWND hwndUnderMouse = ::WindowFromPoint( point);
|
|
|
|
|
HWND hwndInfo = NULL;
|
|
|
|
|
if( pMainFrame->m_pInfoFrame != NULL)
|
|
|
|
|
{
|
|
|
|
|
hwndInfo = pMainFrame->m_pInfoFrame->m_hWnd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HWND hwndFocused = ::GetFocus();
|
|
|
|
|
//HWND hwndForeground = ::GetForegroundWindow();
|
|
|
|
|
//if( hwndForeground==pMainFrame->m_hWnd)
|
|
|
|
|
{
|
|
|
|
|
// if this is the first mouse move over new view and it is not over info window,
|
|
|
|
|
// set focus and loose all previous actions
|
|
|
|
|
if( (m_hWnd != hwndFocused) && ( hwndInfo != hwndUnderMouse) )
|
|
|
|
|
{
|
|
|
|
|
SetActiveWindow();
|
|
|
|
|
SetFocus();
|
|
|
|
|
GetChildFrame()->SetActiveView( this);
|
|
|
|
|
pMainFrame->MDIActivate(GetParentFrame());
|
|
|
|
|
|
|
|
|
|
// cancel any possible previous actions
|
|
|
|
|
m_iaInputAction = IA_NONE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
if( pdpValidDrawPort == NULL) return;
|
|
|
|
|
|
|
|
|
|
CView::OnMouseMove(nFlags, point);
|
|
|
|
|
CPoint ptScreen = point;
|
|
|
|
|
LONG lOffsetX = point.x - m_ptMouse.x;
|
|
|
|
|
LONG lOffsetY = point.y - m_ptMouse.y;
|
|
|
|
|
float fOriginOffsetX = (FLOAT) (point.x - m_ptMouseDown.x);
|
|
|
|
|
float fOriginOffsetY = (FLOAT) (point.y - m_ptMouseDown.y);
|
|
|
|
|
|
|
|
|
|
//_RPT2(_CRT_WARN, "%f %f\n", fOriginOffsetX, fOriginOffsetY);
|
|
|
|
|
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
BOOL bHitModels = (pDoc->GetEditingMode() != POLYGON_MODE) &&
|
|
|
|
|
(pDoc->GetEditingMode() != TERRAIN_MODE);
|
|
|
|
|
BOOL bHitFields = pDoc->GetEditingMode() == ENTITY_MODE;
|
|
|
|
|
BOOL bHitBrushes = pDoc->GetEditingMode() != TERRAIN_MODE;
|
|
|
|
|
|
|
|
|
|
// set dummy ray hit result
|
|
|
|
|
CCastRay crRayHit( NULL, CPlacement3D(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0)) );
|
|
|
|
|
BOOL bRayHitNeeded;
|
|
|
|
|
if( (m_iaInputAction == IA_MOVING_VIEWER_IN_FLOOR_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_MOVING_VIEWER_IN_VIEW_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_ROTATING_VIEWER) ||
|
|
|
|
|
(m_iaInputAction == IA_MOVING_SECOND_LAYER_IN_FLOOR_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_MOVING_SECOND_LAYER_IN_VIEW_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_ROTATING_SECOND_LAYER) ||
|
|
|
|
|
(m_iaInputAction == IA_MOVING_ENTITY_SELECTION_IN_FLOOR_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_MOVING_ENTITY_SELECTION_IN_VIEW_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_ROTATING_ENTITY_SELECTION) ||
|
|
|
|
|
(m_iaInputAction == IA_DRAG_BRUSH_VERTEX_IN_FLOOR_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_DRAG_BRUSH_VERTEX_IN_VIEW_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_SELECT_LASSO_ENTITY) ||
|
|
|
|
|
(m_iaInputAction == IA_SELECT_LASSO_BRUSH_VERTEX) ||
|
|
|
|
|
(m_iaInputAction == IA_STRETCH_BRUSH_VERTEX) ||
|
|
|
|
|
(m_iaInputAction == IA_ROTATE_BRUSH_VERTEX) ) {
|
|
|
|
|
bRayHitNeeded = FALSE;
|
|
|
|
|
} else {
|
|
|
|
|
bRayHitNeeded = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL bSelectPortals = FALSE;
|
|
|
|
|
// for right mouse button select portals
|
|
|
|
|
if( bRMB)
|
|
|
|
|
{
|
|
|
|
|
bSelectPortals = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( bRayHitNeeded)
|
|
|
|
|
{
|
|
|
|
|
crRayHit = GetMouseHitInformation( m_ptMouse, bSelectPortals, bHitModels, bHitFields, NULL, bHitBrushes);
|
|
|
|
|
if(abs(lOffsetX)>=1 || abs(lOffsetY)>=1)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_vLastTerrainHit=crRayHit.cr_vHit;
|
|
|
|
|
theApp.m_penLastTerrainHit=crRayHit.cr_penHit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_strTerrainDataPaneText="Terrain not hit";
|
|
|
|
|
if( pDoc->GetEditingMode() == TERRAIN_MODE && !_pInput->IsInputEnabled())
|
|
|
|
|
{
|
|
|
|
|
if( (crRayHit.cr_penHit!=NULL) && (crRayHit.cr_penHit->GetRenderType() == CEntity::RT_TERRAIN))
|
|
|
|
|
{
|
|
|
|
|
CTerrain *ptrTerrain=crRayHit.cr_penHit->GetTerrain();
|
|
|
|
|
INDEX iLayerBeneath=-1;
|
|
|
|
|
UBYTE ubLayerPower=0;
|
|
|
|
|
INDEX ctLayers=ptrTerrain->tr_atlLayers.Count();
|
|
|
|
|
for(INDEX iLayer=0; iLayer<ctLayers; iLayer++)
|
|
|
|
|
{
|
|
|
|
|
UBYTE ubPower=GetValueFromMask(ptrTerrain, iLayer, crRayHit.cr_vHit);
|
|
|
|
|
if(ubPower>0)
|
|
|
|
|
{
|
|
|
|
|
iLayerBeneath=iLayer;
|
|
|
|
|
ubLayerPower=ubPower;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(iLayerBeneath!=-1)
|
|
|
|
|
{
|
|
|
|
|
if(theApp.m_iTerrainEditMode==TEM_HEIGHTMAP)
|
|
|
|
|
{
|
|
|
|
|
if( bCtrl&&bAlt)
|
|
|
|
|
{
|
|
|
|
|
Point pt=Calculate2dHitPoint(ptrTerrain, crRayHit.cr_vHit);
|
|
|
|
|
INDEX iWidth=ptrTerrain->tr_pixHeightMapWidth;
|
|
|
|
|
UWORD uwAltitude=*(ptrTerrain->tr_auwHeightMap+iWidth*pt.pt_iY+pt.pt_iX);
|
|
|
|
|
FLOAT fAltitudeBeneath=FLOAT(uwAltitude)/65535*ptrTerrain->tr_vTerrainSize(2);
|
|
|
|
|
m_strTerrainDataPaneText.PrintF("Altitude: %g", fAltitudeBeneath);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FLOAT fReferenceAltitude=FLOAT(theApp.m_uwEditAltitude)/65535*ptrTerrain->tr_vTerrainSize(2);
|
|
|
|
|
m_strTerrainDataPaneText.PrintF("Reference altitude: %g", fReferenceAltitude);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_strTerrainDataPaneText.PrintF("Layer: %d (%d%%)", iLayerBeneath+1, INDEX(ubLayerPower/255.0f*100.0f));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_strTerrainDataPaneText.PrintF("No layers");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_strTerrainDataPaneText.PrintF("No terrain hit");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL bRefreshView = FALSE;// view refresh is not needed for now
|
|
|
|
|
BOOL bObjectMoved = FALSE;// nothing has moved for now
|
|
|
|
|
BOOL bRepaintImmediately = FALSE; // force immediate repainting
|
|
|
|
|
BOOL bRecreatePrimitive = FALSE;// there is no need for recreating primitive
|
|
|
|
|
|
|
|
|
|
// act acording to action started in OnLButtonDown() and OnRButtonDown()
|
|
|
|
|
switch( m_iaInputAction)
|
|
|
|
|
{
|
|
|
|
|
case IA_MIP_SETTING:
|
|
|
|
|
{
|
|
|
|
|
// remember current time as time when last mip brushing option has been used
|
|
|
|
|
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
|
|
|
|
|
if( lOffsetY > 0) lOffsetY = 0;
|
|
|
|
|
// translate viewer in floor plane
|
|
|
|
|
svViewer.Translate_OwnSystem( 0, 0, -lOffsetY);
|
|
|
|
|
// set new viewer position
|
|
|
|
|
GetChildFrame()->m_mvViewer = svViewer;
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_MANUAL_MIP_SWITCH_FACTOR_CHANGING:
|
|
|
|
|
{
|
|
|
|
|
if( GetChildFrame()->m_fManualMipBrushingFactor - lOffsetY/50.0f > 0.0f)
|
|
|
|
|
{
|
|
|
|
|
// remember current time as time when last mip brushing option has been used
|
|
|
|
|
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
|
|
|
|
|
GetChildFrame()->m_fManualMipBrushingFactor -= lOffsetY/50.0f;
|
|
|
|
|
}
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_ROTATING_VIEWER:
|
|
|
|
|
{
|
|
|
|
|
svViewer.Rotate_HPB( lOffsetX, lOffsetY, 0);
|
|
|
|
|
// set new viewer position
|
|
|
|
|
GetChildFrame()->m_mvViewer = svViewer;
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_MOVING_VIEWER_IN_FLOOR_PLANE:
|
|
|
|
|
{
|
|
|
|
|
// translate viewer in floor plane
|
|
|
|
|
svViewer.Translate_OwnSystem( lOffsetX, lOffsetY, 0);
|
|
|
|
|
// set new viewer position
|
|
|
|
|
GetChildFrame()->m_mvViewer = svViewer;
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_MOVING_VIEWER_IN_VIEW_PLANE:
|
|
|
|
|
{
|
|
|
|
|
// translate viewer in view plane
|
|
|
|
|
svViewer.Translate_OwnSystem( lOffsetX, 0, -lOffsetY);
|
|
|
|
|
// set new viewer position
|
|
|
|
|
GetChildFrame()->m_mvViewer = svViewer;
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_SHEARING_PRIMITIVE:
|
|
|
|
|
{
|
|
|
|
|
// get translation vector in view space
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
CPlacement3D plVector0(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
|
|
|
|
|
CPlacement3D plVector1(
|
|
|
|
|
FLOAT3D( fOriginOffsetX/fZoom, -fOriginOffsetY/fZoom, 0.0f),
|
|
|
|
|
ANGLE3D(0,0,0));
|
|
|
|
|
// project translation vector from view space to absolute space
|
|
|
|
|
CPlacement3D plViewer = svViewer.GetViewerPlacement();
|
|
|
|
|
plVector0.RelativeToAbsolute(plViewer);
|
|
|
|
|
plVector1.RelativeToAbsolute(plViewer);
|
|
|
|
|
// project translation vector from absolute space to second layer space
|
|
|
|
|
plVector0.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
plVector1.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
// extract translation vector from placements
|
|
|
|
|
FLOAT3D vSizeDelta = plVector1.pl_PositionVector-plVector0.pl_PositionVector;
|
|
|
|
|
|
|
|
|
|
// apply mouse movement
|
|
|
|
|
theApp.m_vfpCurrent.vfp_fShearX = m_VFPMouseDown.vfp_fShearX+vSizeDelta(1);
|
|
|
|
|
theApp.m_vfpCurrent.vfp_fShearZ = m_VFPMouseDown.vfp_fShearZ+vSizeDelta(3);
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fShearX, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fShearZ, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
bRecreatePrimitive = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_STRETCHING_PRIMITIVE:
|
|
|
|
|
{
|
|
|
|
|
// get translation vector in view space
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
CPlacement3D plVector0(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
|
|
|
|
|
CPlacement3D plVector1(
|
|
|
|
|
FLOAT3D( fOriginOffsetX/fZoom, -fOriginOffsetY/fZoom,0.0f),
|
|
|
|
|
ANGLE3D(0,0,0));
|
|
|
|
|
// project translation vector from view space to absolute space
|
|
|
|
|
CPlacement3D plViewer = svViewer.GetViewerPlacement();
|
|
|
|
|
plVector0.RelativeToAbsolute(plViewer);
|
|
|
|
|
plVector1.RelativeToAbsolute(plViewer);
|
|
|
|
|
// project translation vector from absolute space to second layer space
|
|
|
|
|
plVector0.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
plVector1.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
// extract translation vector from placements
|
|
|
|
|
FLOAT3D vSizeDelta = plVector1.pl_PositionVector-plVector0.pl_PositionVector;
|
|
|
|
|
|
|
|
|
|
// apply mouse movement
|
|
|
|
|
CValuesForPrimitive vfpTemp = theApp.m_vfpCurrent;
|
|
|
|
|
vfpTemp.vfp_fXMin = m_VFPMouseDown.vfp_fXMin+vSizeDelta(1)*aiForAllowedSizing[m_iSizeControlVertice][0];
|
|
|
|
|
vfpTemp.vfp_fXMax = m_VFPMouseDown.vfp_fXMax+vSizeDelta(1)*aiForAllowedSizing[m_iSizeControlVertice][1];
|
|
|
|
|
vfpTemp.vfp_fYMin = m_VFPMouseDown.vfp_fYMin+vSizeDelta(2)*aiForAllowedSizing[m_iSizeControlVertice][2];
|
|
|
|
|
vfpTemp.vfp_fYMax = m_VFPMouseDown.vfp_fYMax+vSizeDelta(2)*aiForAllowedSizing[m_iSizeControlVertice][3];
|
|
|
|
|
vfpTemp.vfp_fZMin = m_VFPMouseDown.vfp_fZMin+vSizeDelta(3)*aiForAllowedSizing[m_iSizeControlVertice][4];
|
|
|
|
|
vfpTemp.vfp_fZMax = m_VFPMouseDown.vfp_fZMax+vSizeDelta(3)*aiForAllowedSizing[m_iSizeControlVertice][5];
|
|
|
|
|
|
|
|
|
|
pDoc->SnapFloat( vfpTemp.vfp_fXMin, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
pDoc->SnapFloat( vfpTemp.vfp_fXMax, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
pDoc->SnapFloat( vfpTemp.vfp_fYMin, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
pDoc->SnapFloat( vfpTemp.vfp_fYMax, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
pDoc->SnapFloat( vfpTemp.vfp_fZMin, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
pDoc->SnapFloat( vfpTemp.vfp_fZMax, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
|
|
|
|
|
// if movement produced valid primitive
|
|
|
|
|
if( (vfpTemp.vfp_fXMax>vfpTemp.vfp_fXMin) &&
|
|
|
|
|
(vfpTemp.vfp_fYMax>vfpTemp.vfp_fYMin) &&
|
|
|
|
|
(vfpTemp.vfp_fZMax>vfpTemp.vfp_fZMin) )
|
|
|
|
|
{
|
|
|
|
|
theApp.m_vfpCurrent = vfpTemp;
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
bRecreatePrimitive = TRUE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_CHANGING_RANGE_PROPERTY:
|
|
|
|
|
case IA_CHANGING_ANGLE3D_PROPERTY:
|
|
|
|
|
{
|
|
|
|
|
CPropertyID *ppid = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
|
|
|
|
|
if( ppid == NULL) return;
|
|
|
|
|
//for all selected entities
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// obtain property ptr
|
|
|
|
|
CEntityProperty *penpProperty = iten->PropertyForName( ppid->pid_strName);
|
|
|
|
|
if( penpProperty == NULL) return;
|
|
|
|
|
// discard old entity settings
|
|
|
|
|
iten->End();
|
|
|
|
|
if( ppid->pid_eptType == CEntityProperty::EPT_RANGE)
|
|
|
|
|
{
|
|
|
|
|
// get editing range for current entity
|
|
|
|
|
FLOAT fRange = ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, FLOAT);
|
|
|
|
|
// add range offset received during L/R mouse move
|
|
|
|
|
fRange += svViewer.PixelsToMeters(lOffsetX);
|
|
|
|
|
// set new range
|
|
|
|
|
ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, FLOAT) = fRange;
|
|
|
|
|
// change dialog's range variable
|
|
|
|
|
pMainFrame->m_PropertyComboBar.m_fEditingFloat = fRange;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// get angle3d for current entity
|
|
|
|
|
ANGLE3D aAngle = ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, ANGLE3D);
|
|
|
|
|
// create dummy placement
|
|
|
|
|
CPlacement3D plDummyPlacement;
|
|
|
|
|
plDummyPlacement.pl_PositionVector = FLOAT3D( 0.0f, 0.0f, 0.0f);
|
|
|
|
|
plDummyPlacement.pl_OrientationAngle = aAngle;
|
|
|
|
|
// set new angles using trackball method
|
|
|
|
|
svViewer.RotatePlacement_TrackBall(plDummyPlacement, lOffsetX, lOffsetY, 0);
|
|
|
|
|
aAngle = plDummyPlacement.pl_OrientationAngle;
|
|
|
|
|
// set new angle
|
|
|
|
|
ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, ANGLE3D) = aAngle;
|
|
|
|
|
// change dialog's range variable
|
|
|
|
|
pMainFrame->m_PropertyComboBar.m_fEditingHeading = DegAngle(aAngle(1));
|
|
|
|
|
pMainFrame->m_PropertyComboBar.m_fEditingPitch = DegAngle(aAngle(2));
|
|
|
|
|
pMainFrame->m_PropertyComboBar.m_fEditingBanking = DegAngle(aAngle(3));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// apply new entity settings
|
|
|
|
|
iten->Initialize();
|
|
|
|
|
// update edit range control (by updating parent dialog)
|
|
|
|
|
pMainFrame->m_PropertyComboBar.UpdateData( FALSE);
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
}
|
|
|
|
|
// mark that document is changed
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_ROTATING_ENTITY_SELECTION:
|
|
|
|
|
case IA_ROTATING_SECOND_LAYER:
|
|
|
|
|
{
|
|
|
|
|
// use trackball method for rotation
|
|
|
|
|
svViewer.RotatePlacement_TrackBall(m_plMouseMove, -lOffsetX, -lOffsetY, 0);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
bObjectMoved = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_MOVING_ENTITY_SELECTION_IN_FLOOR_PLANE:
|
|
|
|
|
case IA_MOVING_SECOND_LAYER_IN_FLOOR_PLANE:
|
|
|
|
|
{
|
|
|
|
|
svViewer.TranslatePlacement_OwnSystem(m_plMouseMove, lOffsetX, lOffsetY, 0);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
bObjectMoved = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_MOVING_ENTITY_SELECTION_IN_VIEW_PLANE:
|
|
|
|
|
case IA_MOVING_SECOND_LAYER_IN_VIEW_PLANE:
|
|
|
|
|
{
|
|
|
|
|
svViewer.TranslatePlacement_OwnSystem(m_plMouseMove, lOffsetX, 0, lOffsetY);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
bObjectMoved = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_SIZING_SELECT_BY_VOLUME_BOX:
|
|
|
|
|
{
|
|
|
|
|
// get translation vector in view space
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
CPlacement3D plVector0(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
|
|
|
|
|
CPlacement3D plVector1(FLOAT3D(fOriginOffsetX/fZoom,-fOriginOffsetY/fZoom,0.0f),
|
|
|
|
|
ANGLE3D(0,0,0));
|
|
|
|
|
// project translation vector from view space to absolute space
|
|
|
|
|
CPlacement3D plViewer = svViewer.GetViewerPlacement();
|
|
|
|
|
plVector0.RelativeToAbsolute(plViewer);
|
|
|
|
|
plVector1.RelativeToAbsolute(plViewer);
|
|
|
|
|
// extract translation vector from placements
|
|
|
|
|
FLOAT3D vDelta = plVector1.pl_PositionVector-plVector0.pl_PositionVector;
|
|
|
|
|
// apply movement
|
|
|
|
|
FLOAT3D vNewVolumeBoxCorner = pDoc->m_vVolumeBoxStartDragVertice+vDelta;
|
|
|
|
|
pDoc->CorrectBox( pDoc->m_iVolumeBoxDragVertice, vNewVolumeBoxCorner);
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_DRAG_VERTEX_ON_PRIMITIVE_BASE:
|
|
|
|
|
{
|
|
|
|
|
if( m_iDragVertice == -1) break;
|
|
|
|
|
// ------ Move closest vertice on base of primitive
|
|
|
|
|
CPlacement3D plVector0(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
CPlacement3D plVector1(FLOAT3D(fOriginOffsetX/fZoom,-fOriginOffsetY/fZoom,0.0f),
|
|
|
|
|
ANGLE3D(0,0,0));
|
|
|
|
|
// project translation vector from view space to absolute space
|
|
|
|
|
CPlacement3D plViewer = svViewer.GetViewerPlacement();
|
|
|
|
|
plVector0.RelativeToAbsolute(plViewer);
|
|
|
|
|
plVector1.RelativeToAbsolute(plViewer);
|
|
|
|
|
// project translation vector from absolute space to second layer space
|
|
|
|
|
plVector0.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
plVector1.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
// extract translation vector from placements
|
|
|
|
|
DOUBLE3D vDelta = FLOATtoDOUBLE(plVector1.pl_PositionVector)-
|
|
|
|
|
FLOATtoDOUBLE(plVector0.pl_PositionVector);
|
|
|
|
|
|
|
|
|
|
DOUBLE3D &vDrag = theApp.m_vfpCurrent.vfp_avVerticesOnBaseOfPrimitive[m_iDragVertice];
|
|
|
|
|
// apply movement
|
|
|
|
|
vDrag = m_vStartDragVertice + vDelta;
|
|
|
|
|
// snap resulting vertex coordinate
|
|
|
|
|
SnapVector( vDrag);
|
|
|
|
|
|
|
|
|
|
// refresh primitive
|
|
|
|
|
pDoc->CreatePrimitive();
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_DRAG_VERTEX_ON_PRIMITIVE:
|
|
|
|
|
{
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
DragVerticesOnPrimitive(fOriginOffsetX/fZoom,-fOriginOffsetY/fZoom, 0.0f, FALSE);
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_SELECT_LASSO_BRUSH_VERTEX:
|
|
|
|
|
case IA_SELECT_LASSO_ENTITY:
|
|
|
|
|
{
|
|
|
|
|
INDEX ctLasoPts = m_avpixLaso.Count();
|
|
|
|
|
m_avpixLaso.Push(1);
|
|
|
|
|
m_avpixLaso[ctLasoPts](1) = point.x;
|
|
|
|
|
m_avpixLaso[ctLasoPts](2) = point.y;
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_SELECT_SINGLE_BRUSH_VERTEX:
|
|
|
|
|
{
|
|
|
|
|
// if mouse moved more than few pixels arround
|
|
|
|
|
if( (abs( lOffsetX) > 3) || (abs( lOffsetY) > 3) )
|
|
|
|
|
{
|
|
|
|
|
// if shift nor alt were pressed on mouse down
|
|
|
|
|
if( !m_bOnSelectVertexShiftDown && !m_bOnSelectVertexAltDown)
|
|
|
|
|
{
|
|
|
|
|
// clear vertex selection
|
|
|
|
|
pDoc->m_selVertexSelection.Clear();
|
|
|
|
|
}
|
|
|
|
|
// switch to laso select
|
|
|
|
|
m_iaInputAction = IA_SELECT_LASSO_BRUSH_VERTEX;
|
|
|
|
|
// add mouse down and current mouse positions to lasso buffer
|
|
|
|
|
m_avpixLaso.Push(2);
|
|
|
|
|
m_avpixLaso[0](1) = m_ptMouseDown.x;
|
|
|
|
|
m_avpixLaso[0](2) = m_ptMouseDown.y;
|
|
|
|
|
m_avpixLaso[1](1) = point.x;
|
|
|
|
|
m_avpixLaso[1](2) = point.y;
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_DRAG_BRUSH_VERTEX_IN_FLOOR_PLANE:
|
|
|
|
|
{
|
|
|
|
|
bRepaintImmediately = TRUE;
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
DragBrushVertex(fOriginOffsetX/fZoom,-fOriginOffsetY/fZoom, 0.0f);
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_DRAG_BRUSH_VERTEX_IN_VIEW_PLANE:
|
|
|
|
|
{
|
|
|
|
|
bRepaintImmediately = TRUE;
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
DragBrushVertex(fOriginOffsetX/fZoom, 0.0f, fOriginOffsetY/fZoom);
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_ROTATE_BRUSH_VERTEX:
|
|
|
|
|
{
|
|
|
|
|
bRepaintImmediately = TRUE;
|
|
|
|
|
// apply brush vertex rotation
|
|
|
|
|
RotateOrStretchBrushVertex(-fOriginOffsetX, -fOriginOffsetY, TRUE);
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
// calculate BBox of all vertices before rotating started
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_STRETCH_BRUSH_VERTEX:
|
|
|
|
|
{
|
|
|
|
|
bRepaintImmediately = TRUE;
|
|
|
|
|
// apply brush stretch
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
RotateOrStretchBrushVertex(fOriginOffsetX, fZoom, FALSE);
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
// calculate BBox of all vertices before rotating started
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_SELECTING_POLYGONS:
|
|
|
|
|
{
|
|
|
|
|
// if mouse is not over some polygon, break
|
|
|
|
|
if( (crRayHit.cr_penHit == NULL) ||
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon == NULL) ) break;
|
|
|
|
|
// if polygon under mouse is selected and first polygon that we hitted
|
|
|
|
|
// was deselected
|
|
|
|
|
if( crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED) && m_bWeDeselectedFirstPolygon)
|
|
|
|
|
{
|
|
|
|
|
// deselect polygon under mouse
|
|
|
|
|
pDoc->m_selPolygonSelection.Deselect( *crRayHit.cr_pbpoBrushPolygon);
|
|
|
|
|
}
|
|
|
|
|
// if polygon under mouse is not selected and first polygon that we hitted
|
|
|
|
|
// at the begining of selecting was selected
|
|
|
|
|
if( !crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED) && !m_bWeDeselectedFirstPolygon)
|
|
|
|
|
{
|
|
|
|
|
// select polygon under mouse
|
|
|
|
|
pDoc->m_selPolygonSelection.Select( *crRayHit.cr_pbpoBrushPolygon);
|
|
|
|
|
}
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
// and refresh property combo manualy calling on idle
|
|
|
|
|
pMainFrame->m_PropertyComboBar.m_PropertyComboBox.OnIdle( 0);
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_SELECTING_SECTORS:
|
|
|
|
|
{
|
|
|
|
|
// if mouse is not over some polygon, break
|
|
|
|
|
if( (crRayHit.cr_penHit == NULL) ||
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon == NULL) ) break;
|
|
|
|
|
// if sector under mouse is selected and first sector that we hitted
|
|
|
|
|
// at the begining of selecting was deselected
|
|
|
|
|
if( crRayHit.cr_pbscBrushSector->IsSelected( BSCF_SELECTED) && m_bWeDeselectedFirstSector)
|
|
|
|
|
{
|
|
|
|
|
// deselect sector under mouse
|
|
|
|
|
pDoc->m_selSectorSelection.Deselect( *crRayHit.cr_pbscBrushSector);
|
|
|
|
|
}
|
|
|
|
|
// if sector under mouse is not selected and first sector that we hitted
|
|
|
|
|
// at the begining of selecting was selected
|
|
|
|
|
if( !crRayHit.cr_pbscBrushSector->IsSelected( BSCF_SELECTED) && !m_bWeDeselectedFirstSector)
|
|
|
|
|
{
|
|
|
|
|
// select sector under mouse
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *crRayHit.cr_pbscBrushSector);
|
|
|
|
|
}
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
// and refresh property combo manualy calling on idle
|
|
|
|
|
pMainFrame->m_PropertyComboBar.m_PropertyComboBox.OnIdle( 0);
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_SELECTING_ENTITIES:
|
|
|
|
|
{
|
|
|
|
|
// if mouse moved more than few pixels arround
|
|
|
|
|
if( (abs( lOffsetX) > 3) || (abs( lOffsetY) > 3) )
|
|
|
|
|
{
|
|
|
|
|
// if shift nor alt were pressed on mouse down
|
|
|
|
|
if( !m_bOnSelectEntityShiftDown && !m_bOnSelectEntityAltDown)
|
|
|
|
|
{
|
|
|
|
|
// clear entity selection
|
|
|
|
|
pDoc->m_selEntitySelection.Clear();
|
|
|
|
|
}
|
|
|
|
|
// switch to laso select
|
|
|
|
|
m_iaInputAction = IA_SELECT_LASSO_ENTITY;
|
|
|
|
|
// add mouse down and current mouse positions to lasso buffer
|
|
|
|
|
m_avpixLaso.Push(2);
|
|
|
|
|
m_avpixLaso[0](1) = m_ptMouseDown.x;
|
|
|
|
|
m_avpixLaso[0](2) = m_ptMouseDown.y;
|
|
|
|
|
m_avpixLaso[1](1) = point.x;
|
|
|
|
|
m_avpixLaso[1](2) = point.y;
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_MEASURING:
|
|
|
|
|
{
|
|
|
|
|
// just refresh view
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_MOVING_CUT_LINE_START:
|
|
|
|
|
{
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
FLOAT3D vDelta = ProjectVectorToWorldSpace( fOriginOffsetX/fZoom, -fOriginOffsetY/fZoom, 0.0f);
|
|
|
|
|
// calculate and snap new position
|
|
|
|
|
pDoc->m_vCutLineStart = pDoc->m_vControlLineDragStart+vDelta;
|
|
|
|
|
SnapVector( pDoc->m_vCutLineStart);
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_MOVING_CUT_LINE_END:
|
|
|
|
|
{
|
|
|
|
|
// get 3D delta vector in world, from mouse down point to current mouse position
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
FLOAT3D vDelta = ProjectVectorToWorldSpace( fOriginOffsetX/fZoom, -fOriginOffsetY/fZoom, 0.0f);
|
|
|
|
|
// calculate and snap new position
|
|
|
|
|
pDoc->m_vCutLineEnd = pDoc->m_vControlLineDragStart+vDelta;
|
|
|
|
|
SnapVector( pDoc->m_vCutLineEnd);
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_CUT_MODE:
|
|
|
|
|
{
|
|
|
|
|
// calculate current cut line end
|
|
|
|
|
pDoc->m_vCutLineEnd = Get3DCoordinateFrom2D( point);
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_ROTATING_POLYGON_MAPPING:
|
|
|
|
|
{
|
|
|
|
|
if(crRayHit.cr_pbpoBrushPolygon==NULL) return;
|
|
|
|
|
svViewer.RotatePlacement_TrackBall(m_plMouseMove, lOffsetX, lOffsetY, 0);
|
|
|
|
|
// get rotation angle
|
|
|
|
|
ANGLE3D angMappingRotation = m_plMouseMove.pl_OrientationAngle;
|
|
|
|
|
|
|
|
|
|
CTString strDataPaneText;
|
|
|
|
|
strDataPaneText.PrintF("H=%g,P=%g,B=%g",
|
|
|
|
|
DegAngle( angMappingRotation(1)),
|
|
|
|
|
DegAngle( angMappingRotation(2)),
|
|
|
|
|
DegAngle( angMappingRotation(3)));
|
|
|
|
|
pMainFrame->m_wndStatusBar.SetPaneText( STATUS_LINE_PANE, CString(strDataPaneText), TRUE);
|
|
|
|
|
|
|
|
|
|
// for each selected polygon
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygon *pbpo = itbpo;
|
|
|
|
|
CEntity *pen = pbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
|
|
|
|
|
CSimpleProjection3D pr;
|
|
|
|
|
pr.ObjectPlacementL() = _plOrigin;
|
|
|
|
|
pr.ViewerPlacementL() = pen->GetPlacement();
|
|
|
|
|
pr.Prepare();
|
|
|
|
|
FLOATplane3D vRelative;
|
|
|
|
|
pr.ProjectCoordinate(m_vHitOnMouseDown, vRelative);
|
|
|
|
|
|
|
|
|
|
// rotate it
|
|
|
|
|
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.Rotate(
|
|
|
|
|
pbpo->bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative,
|
|
|
|
|
vRelative, angMappingRotation(1));
|
|
|
|
|
}
|
|
|
|
|
// mark that document is changed
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
// reset mouse placement
|
|
|
|
|
m_plMouseMove.pl_PositionVector = crRayHit.cr_vHit;
|
|
|
|
|
m_plMouseMove.pl_OrientationAngle = ANGLE3D( 0, 0, 0);
|
|
|
|
|
// refresh position page
|
|
|
|
|
pDoc->RefreshCurrentInfoPage();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IA_MOVING_POLYGON_MAPPING:
|
|
|
|
|
{
|
|
|
|
|
// find translation vector in 3d
|
|
|
|
|
crRayHit.cr_vHit = GetMouseHitOnPlane(point, m_plTranslationPlane);
|
|
|
|
|
FLOAT3D f3dMappingTranslation = crRayHit.cr_vHit-m_plMouseMove.pl_PositionVector;
|
|
|
|
|
// find how much that offsets hit polygon
|
|
|
|
|
if( m_pbpoTranslationPlane == NULL) return;
|
|
|
|
|
CBrushPolygon &bpo = *m_pbpoTranslationPlane;
|
|
|
|
|
CEntity *pen = bpo.bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
|
|
|
|
|
CSimpleProjection3D pr;
|
|
|
|
|
pr.ObjectPlacementL() = _plOrigin;
|
|
|
|
|
pr.ViewerPlacementL() = pen->GetPlacement();
|
|
|
|
|
pr.Prepare();
|
|
|
|
|
FLOATplane3D vRelative;
|
|
|
|
|
pr.ProjectDirection(f3dMappingTranslation, vRelative);
|
|
|
|
|
CMappingDefinition mdOriginal = bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
|
|
|
|
|
CMappingDefinition mdTranslated = mdOriginal;
|
|
|
|
|
|
|
|
|
|
mdTranslated.Translate(
|
|
|
|
|
bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative, vRelative);
|
|
|
|
|
FLOAT fUOffset = mdTranslated.md_fUOffset-mdOriginal.md_fUOffset;
|
|
|
|
|
FLOAT fVOffset = mdTranslated.md_fVOffset-mdOriginal.md_fVOffset;
|
|
|
|
|
// for each selected polygon
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
// add the offsets to its mapping
|
|
|
|
|
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fUOffset+=fUOffset;
|
|
|
|
|
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fVOffset+=fVOffset;
|
|
|
|
|
}
|
|
|
|
|
// mark that document is changed
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
bRefreshView = TRUE;
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
// reset mouse placement
|
|
|
|
|
m_plMouseMove.pl_PositionVector = crRayHit.cr_vHit;
|
|
|
|
|
m_plMouseMove.pl_OrientationAngle = ANGLE3D( 0, 0, 0);
|
|
|
|
|
// refresh position page
|
|
|
|
|
pDoc->RefreshCurrentInfoPage();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if recreating of primitive requested
|
|
|
|
|
if( bRecreatePrimitive)
|
|
|
|
|
{
|
|
|
|
|
pDoc->RefreshPrimitivePage();
|
|
|
|
|
pDoc->CreatePrimitive();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if something has moved
|
|
|
|
|
if( bObjectMoved)
|
|
|
|
|
{
|
|
|
|
|
if( (m_iaInputAction == IA_MOVING_SECOND_LAYER_IN_FLOOR_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_MOVING_SECOND_LAYER_IN_VIEW_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_ROTATING_SECOND_LAYER) )
|
|
|
|
|
{
|
|
|
|
|
// copy new placement to second layer
|
|
|
|
|
pDoc->m_plSecondLayer = m_plMouseMove;
|
|
|
|
|
pDoc->SnapToGrid( pDoc->m_plSecondLayer, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
theApp.m_vfpCurrent.vfp_plPrimitive = pDoc->m_plSecondLayer;
|
|
|
|
|
}
|
|
|
|
|
else if( (m_iaInputAction == IA_MOVING_ENTITY_SELECTION_IN_FLOOR_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_MOVING_ENTITY_SELECTION_IN_VIEW_PLANE) ||
|
|
|
|
|
(m_iaInputAction == IA_ROTATING_ENTITY_SELECTION) )
|
|
|
|
|
{
|
|
|
|
|
ASSERT( pDoc->m_aSelectedEntityPlacements.Count()==pDoc->m_selEntitySelection.Count());
|
|
|
|
|
if( pDoc->m_aSelectedEntityPlacements.Count()!=pDoc->m_selEntitySelection.Count()) return;
|
|
|
|
|
// if there is no anchored entity in selection or if moving of
|
|
|
|
|
// anchored entities is allowed
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
if( ((iten->GetFlags() & ENF_ANCHORED) != 0) &&
|
|
|
|
|
(!GetChildFrame()->m_bAncoredMovingAllowed) ) return;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
INDEX ienCurrent = 0;
|
|
|
|
|
CEntity *penBrush = NULL;
|
|
|
|
|
// for each of the selected entities
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
if (iten->en_RenderType == CEntity::RT_BRUSH) {
|
|
|
|
|
penBrush = &*iten;
|
|
|
|
|
}
|
|
|
|
|
if( (iten->GetParent()==NULL) || !(iten->GetParent()->IsSelected( ENF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
// set new entity placement
|
|
|
|
|
CPlacement3D plEntityPlacement = pDoc->m_aSelectedEntityPlacements[ienCurrent];
|
|
|
|
|
plEntityPlacement.RelativeToAbsoluteSmooth(m_plMouseMove);
|
|
|
|
|
pDoc->SnapToGrid( plEntityPlacement, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
iten->SetPlacement(plEntityPlacement);
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
}
|
|
|
|
|
ienCurrent++;
|
|
|
|
|
}}
|
|
|
|
|
if( penBrush != NULL)
|
|
|
|
|
{
|
|
|
|
|
DiscardShadows( penBrush);
|
|
|
|
|
}
|
|
|
|
|
if(m_iaInputAction == IA_ROTATING_ENTITY_SELECTION)
|
|
|
|
|
{
|
|
|
|
|
// check for terrain updating
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CLightSource *pls = iten->GetLightSource();
|
|
|
|
|
if (pls!=NULL)
|
|
|
|
|
{
|
|
|
|
|
// if light is directional
|
|
|
|
|
if(pls->ls_ulFlags &LSF_DIRECTIONAL)
|
|
|
|
|
{
|
|
|
|
|
CTerrain *ptrTerrain=GetTerrain();
|
|
|
|
|
if(ptrTerrain!=NULL) ptrTerrain->UpdateShadowMap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if rotating/moving viewer (bRefreshView) or moving CSG layer, entities or polygon's
|
|
|
|
|
// mapping (bObjectMoved) or editing primitive (bRecreatePrimitive)
|
|
|
|
|
if( bRefreshView || bObjectMoved || bRecreatePrimitive)
|
|
|
|
|
{
|
|
|
|
|
// see in preferences if all views should be updated
|
|
|
|
|
if( theApp.m_Preferences.ap_UpdateAllways || bRepaintImmediately ||
|
|
|
|
|
(bCtrl && bLMB && pDoc->GetEditingMode()==POLYGON_MODE) )
|
|
|
|
|
{
|
|
|
|
|
// force immediatly repainting
|
|
|
|
|
RedrawWindow( NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
|
|
|
|
|
// update other views
|
|
|
|
|
pDoc->UpdateAllViews( this);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// just invalidate
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// set text describing data that is edited
|
|
|
|
|
SetEditingDataPaneInfo( TRUE);
|
|
|
|
|
|
|
|
|
|
// remember current mouse position as last pressed
|
|
|
|
|
m_ptMouse = point;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Called by document at the end of CSG
|
|
|
|
|
*/
|
|
|
|
|
void CWorldEditorView::AtStopCSG(void)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Called by MFC from CWorldEditorDoc::UpdateAllViews().
|
|
|
|
|
*/
|
|
|
|
|
void CWorldEditorView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
|
|
|
|
|
{
|
|
|
|
|
// just invalidate the whole window area
|
|
|
|
|
Invalidate(FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDropFiles(HDROP hDropInfo)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
|
|
|
|
|
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
|
|
|
|
|
// You can't drag anything while CSG is on
|
|
|
|
|
if( bCSGOn)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get number of dropped files
|
|
|
|
|
INDEX iNoOfFiles = DragQueryFile( hDropInfo, 0xFFFFFFFF, NULL, 0);
|
|
|
|
|
|
|
|
|
|
// there can be only one file dropped
|
|
|
|
|
if( iNoOfFiles != 1)
|
|
|
|
|
{
|
|
|
|
|
AfxMessageBox( L"You can drop only one file at a time.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// buffer for dropped file name
|
|
|
|
|
char chrFile[ 256];
|
|
|
|
|
// place dropped file name into buffer
|
|
|
|
|
DragQueryFileA( hDropInfo, 0, chrFile, 256);
|
|
|
|
|
// create file name from buffer
|
|
|
|
|
CTFileName fnDropped = CTString(chrFile);
|
|
|
|
|
|
|
|
|
|
// don't allow document self-drop
|
|
|
|
|
/*if( CTFileName(pDoc->GetPathName()) == fnDropped)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
// object to hold coordinates
|
|
|
|
|
CPoint point;
|
|
|
|
|
// get dropped coordinates
|
|
|
|
|
DragQueryPoint( hDropInfo, &point);
|
|
|
|
|
|
|
|
|
|
// try to
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// remove application path
|
|
|
|
|
fnDropped.RemoveApplicationPath_t();
|
|
|
|
|
}
|
|
|
|
|
catch( char* err_str)
|
|
|
|
|
{
|
|
|
|
|
AfxMessageBox( CString(err_str));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CPlacement3D plDrop;
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( point);
|
|
|
|
|
// place the dropped object at hitted point
|
|
|
|
|
plDrop.pl_PositionVector = crRayHit.cr_vHit;
|
|
|
|
|
// reset angles
|
|
|
|
|
plDrop.pl_OrientationAngle = ANGLE3D(0,0,0);
|
|
|
|
|
|
|
|
|
|
// if the hit entity was a brush
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) ) {
|
|
|
|
|
// get the hit normal in absolute space
|
|
|
|
|
CSimpleProjection3D prBrushToAbsolute;
|
|
|
|
|
prBrushToAbsolute.ObjectPlacementL() = crRayHit.cr_penHit->GetPlacement();
|
|
|
|
|
prBrushToAbsolute.ViewerPlacementL() = CPlacement3D(
|
|
|
|
|
FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
|
|
|
|
|
prBrushToAbsolute.Prepare();
|
|
|
|
|
|
|
|
|
|
FLOAT3D vHitNormal;
|
|
|
|
|
prBrushToAbsolute.ProjectDirection(crRayHit.cr_pbpoBrushPolygon->bpo_pbplPlane->bpl_plAbsolute,
|
|
|
|
|
vHitNormal);
|
|
|
|
|
// if the normal is more horizontal
|
|
|
|
|
if (Abs(vHitNormal(2))<0.5f) {
|
|
|
|
|
// calculate angles to align -z axis towards the plane
|
|
|
|
|
DirectionVectorToAngles(-vHitNormal, plDrop.pl_OrientationAngle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->SnapToGrid( plDrop, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
|
|
|
|
|
// if the dragged object is an entity class
|
|
|
|
|
if (fnDropped.FileExt()==".ecl")
|
|
|
|
|
{
|
|
|
|
|
// create dragged entity
|
|
|
|
|
CPlacement3D plEntity;
|
|
|
|
|
CEntity *pen = NULL;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
extern BOOL _bInOnDraw;
|
|
|
|
|
_bInOnDraw = TRUE;
|
|
|
|
|
pen = pDoc->m_woWorld.CreateEntity_t(plDrop, fnDropped);
|
|
|
|
|
// prepare the entity
|
|
|
|
|
pen->Initialize();
|
|
|
|
|
_bInOnDraw = FALSE;
|
|
|
|
|
// the drop was successful
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
// mark that document changeable was changed
|
|
|
|
|
pDoc->m_chDocument.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
catch(char *err_str)
|
|
|
|
|
{
|
|
|
|
|
_bInOnDraw = FALSE;
|
|
|
|
|
AfxMessageBox(CString(err_str));
|
|
|
|
|
if (pen!=NULL) {
|
|
|
|
|
pen->Destroy();
|
|
|
|
|
}
|
|
|
|
|
// the drop was no successful
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// deselect all entities
|
|
|
|
|
pDoc->m_selEntitySelection.Clear();
|
|
|
|
|
// if succeseful, switch to entity mode and only-select dropped entity
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *pen);
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
// switch to entity mode
|
|
|
|
|
OnEntityMode();
|
|
|
|
|
// and refresh property combo manualy calling on idle
|
|
|
|
|
pMainFrame->m_PropertyComboBar.m_PropertyComboBox.OnIdle( 0);
|
|
|
|
|
if( (pen->GetRenderType() == CEntity::RT_BRUSH) ||
|
|
|
|
|
(pen->GetRenderType() == CEntity::RT_FIELDBRUSH) )
|
|
|
|
|
{
|
|
|
|
|
pMainFrame->m_CSGDesitnationCombo.OnIdle(0);
|
|
|
|
|
pMainFrame->m_CSGDesitnationCombo.SelectBrushEntity(pen);
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->m_chDocument.MarkChanged();
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( this);
|
|
|
|
|
}
|
|
|
|
|
// if the dragged object is a world
|
|
|
|
|
else if (fnDropped.FileExt()==".wld")
|
|
|
|
|
{
|
|
|
|
|
pDoc->StartTemplateCSG( plDrop, fnDropped, FALSE /*don't reset angles*/);
|
|
|
|
|
// the drop was successful
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (fnDropped.FileExt()==".tex")
|
|
|
|
|
{
|
|
|
|
|
// if we hit some entity and hitted entity is brush
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// try to apply dropped texture to current selection
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// if polygon that is hit with mouse is selected
|
|
|
|
|
if( crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// paste dropped texture over polygon selection
|
|
|
|
|
pDoc->PasteTextureOverSelection_t( fnDropped);
|
|
|
|
|
}
|
|
|
|
|
// otherwise
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// paste it only for drop-hitted polygon
|
|
|
|
|
crRayHit.cr_pbpoBrushPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.SetData_t( fnDropped);
|
|
|
|
|
// mark that document has been modified
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
// mark that selections have been changed to update entity intersection properties
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if failed
|
|
|
|
|
catch( char *err_str)
|
|
|
|
|
{
|
|
|
|
|
// report error
|
|
|
|
|
AfxMessageBox( CString(err_str));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// inform user that drop can be achived only over polygons
|
|
|
|
|
AfxMessageBox( L"You can drop textures only by hitting some polygon, but You hit some entity.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// the drop was not successful, report error
|
|
|
|
|
AfxMessageBox( L"You can drop only textures, classes and worlds.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get pointer to the child frame of this view.
|
|
|
|
|
*/
|
|
|
|
|
CChildFrame *CWorldEditorView::GetChildFrame(void)
|
|
|
|
|
{
|
|
|
|
|
return (CChildFrame *)GetParentFrame();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnIsometricFront()
|
|
|
|
|
{
|
|
|
|
|
m_ptProjectionType = CSlaveViewer::PT_ISOMETRIC_FRONT;
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnIsometricBack()
|
|
|
|
|
{
|
|
|
|
|
m_ptProjectionType = CSlaveViewer::PT_ISOMETRIC_BACK;
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnIsometricBottom()
|
|
|
|
|
{
|
|
|
|
|
m_ptProjectionType = CSlaveViewer::PT_ISOMETRIC_BOTTOM;
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnIsometricLeft()
|
|
|
|
|
{
|
|
|
|
|
m_ptProjectionType = CSlaveViewer::PT_ISOMETRIC_LEFT;
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnIsometricRight()
|
|
|
|
|
{
|
|
|
|
|
m_ptProjectionType = CSlaveViewer::PT_ISOMETRIC_RIGHT;
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnIsometricTop()
|
|
|
|
|
{
|
|
|
|
|
m_ptProjectionType = CSlaveViewer::PT_ISOMETRIC_TOP;
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPerspective()
|
|
|
|
|
{
|
|
|
|
|
m_ptProjectionType = CSlaveViewer::PT_PERSPECTIVE;
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnZoomLess()
|
|
|
|
|
{
|
|
|
|
|
// get draw port
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
// if it is not valid
|
|
|
|
|
if( pdpValidDrawPort == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer(GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
|
|
|
|
|
// scale target distance by 2 - zoom out x2
|
|
|
|
|
svViewer.ScaleTargetDistance( 2.0f);
|
|
|
|
|
|
|
|
|
|
// copy slave viewer back to master
|
|
|
|
|
GetChildFrame()->m_mvViewer = svViewer;
|
|
|
|
|
// redraw all viewes
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnZoomMore()
|
|
|
|
|
{
|
|
|
|
|
// get draw port
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
// if it is not valid
|
|
|
|
|
if( pdpValidDrawPort == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer(GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
|
|
|
|
|
// scale target distance by -1/2 - zoom in x2
|
|
|
|
|
svViewer.ScaleTargetDistance( -0.5f);
|
|
|
|
|
|
|
|
|
|
// copy slave viewer back to master
|
|
|
|
|
GetChildFrame()->m_mvViewer = svViewer;
|
|
|
|
|
// redraw all viewes
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::RotateOrStretchBrushVertex(FLOAT fDX, FLOAT fDY, BOOL bRotate)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// project translation vector from view space to absolute space
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
if( pdpValidDrawPort == NULL) return;
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
// both selection and coordinate arrays must be sinchronized
|
|
|
|
|
if( pDoc->m_avStartDragVertices.Count()!=pDoc->m_selVertexSelection.Count()) {
|
|
|
|
|
ASSERT(FALSE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -------- Calculate BBox of all selected brush vertices
|
|
|
|
|
FLOATaabbox3D boxVtx;
|
|
|
|
|
// for each vertex
|
|
|
|
|
{for( INDEX iVtx=0; iVtx<pDoc->m_avStartDragVertices.Count(); iVtx++)
|
|
|
|
|
{
|
|
|
|
|
// get new position
|
|
|
|
|
boxVtx |= DOUBLEtoFLOAT(pDoc->m_avStartDragVertices[ iVtx]);
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// create dummy placement
|
|
|
|
|
CPlacement3D plDummy;
|
|
|
|
|
plDummy.pl_PositionVector = boxVtx.Center();
|
|
|
|
|
DOUBLE3D vCenter = FLOATtoDOUBLE(plDummy.pl_PositionVector);
|
|
|
|
|
plDummy.pl_OrientationAngle = ANGLE3D(0.0f, 0.0f, 0.0f);
|
|
|
|
|
// use trackball method for rotation
|
|
|
|
|
if( bRotate)
|
|
|
|
|
{
|
|
|
|
|
svViewer.RotatePlacement_TrackBall( plDummy, -fDX, -fDY, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get rotation matrix
|
|
|
|
|
FLOATmatrix3D t3dRotation;
|
|
|
|
|
MakeRotationMatrixFast( t3dRotation, plDummy.pl_OrientationAngle);
|
|
|
|
|
|
|
|
|
|
DOUBLEmatrix3D t3ddRotation;
|
|
|
|
|
t3ddRotation = FLOATtoDOUBLE(t3dRotation);
|
|
|
|
|
|
|
|
|
|
FLOAT fFactor=1.0f;
|
|
|
|
|
if( !bRotate)
|
|
|
|
|
{
|
|
|
|
|
FLOAT fDiag=boxVtx.Size().Length();
|
|
|
|
|
// fDY is actually current view's zoom factor
|
|
|
|
|
fFactor=(fDiag+fDX/fDY)/fDiag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for each vertex
|
|
|
|
|
INDEX iVtx = 0;
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
|
|
|
|
|
{
|
|
|
|
|
DOUBLE3D vRelative = pDoc->m_avStartDragVertices[ iVtx]-vCenter;
|
|
|
|
|
|
|
|
|
|
// rotate vertex around bbox center to get new position
|
|
|
|
|
DOUBLE3D vNew = vRelative*fFactor*t3ddRotation;
|
|
|
|
|
|
|
|
|
|
// snap resulting vertex coordinate
|
|
|
|
|
SnapVector(vNew);
|
|
|
|
|
|
|
|
|
|
// set its new position
|
|
|
|
|
itbvx->SetAbsolutePosition(vNew+vCenter);
|
|
|
|
|
iVtx++;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// update sectors
|
|
|
|
|
pDoc->m_woWorld.UpdateSectorsDuringVertexChange( pDoc->m_selVertexSelection);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FLOAT3D CWorldEditorView::ProjectVectorToWorldSpace(FLOAT fDX,FLOAT fDY,FLOAT fDZ)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CPlacement3D plVector0(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
|
|
|
|
|
CPlacement3D plVector1(FLOAT3D(fDX,fDY,fDZ), ANGLE3D(0,0,0));
|
|
|
|
|
|
|
|
|
|
CDrawPort *pdp = GetDrawPort();
|
|
|
|
|
if( pdp == NULL)
|
|
|
|
|
{
|
|
|
|
|
ASSERTALWAYS("Invalid draw port found!");
|
|
|
|
|
return FLOAT3D( 0.0f, 0.0f, 0.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// project translation vector from view space to absolute space
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid, pdp);
|
|
|
|
|
CPlacement3D plViewer = svViewer.GetViewerPlacement();
|
|
|
|
|
plVector0.RelativeToAbsolute(plViewer);
|
|
|
|
|
plVector1.RelativeToAbsolute(plViewer);
|
|
|
|
|
|
|
|
|
|
// obtain translation vector from placements
|
|
|
|
|
FLOAT3D vDelta = (plVector1.pl_PositionVector-plVector0.pl_PositionVector);
|
|
|
|
|
return vDelta;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::DragBrushVertex(FLOAT fDX,FLOAT fDY,FLOAT fDZ)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
// obtain 3d translation vector
|
|
|
|
|
DOUBLE3D vDelta = FLOATtoDOUBLE( ProjectVectorToWorldSpace( fDX, fDY, fDZ));
|
|
|
|
|
|
|
|
|
|
// both selection and coordinate arrays must be sinchronized
|
|
|
|
|
if( pDoc->m_avStartDragVertices.Count()!=pDoc->m_selVertexSelection.Count()) {
|
|
|
|
|
ASSERT(FALSE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---- apply movement
|
|
|
|
|
|
|
|
|
|
// for each vertex
|
|
|
|
|
INDEX iVtx = 0;
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
|
|
|
|
|
{
|
|
|
|
|
// get new position
|
|
|
|
|
DOUBLE3D vNew = pDoc->m_avStartDragVertices[ iVtx] + vDelta;
|
|
|
|
|
SnapVector( vNew);
|
|
|
|
|
// set its new position
|
|
|
|
|
itbvx->SetAbsolutePosition(vNew);
|
|
|
|
|
iVtx++;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// update sectors
|
|
|
|
|
pDoc->m_woWorld.UpdateSectorsDuringVertexChange( pDoc->m_selVertexSelection);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::DragVerticesOnPrimitive(FLOAT fDX,FLOAT fDY,FLOAT fDZ, BOOL bAbsolute,
|
|
|
|
|
BOOL bSnap/*=TRUE*/)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CPlacement3D plVector0(FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
|
|
|
|
|
CPlacement3D plVector1(FLOAT3D(fDX,fDY,fDZ), ANGLE3D(0,0,0));
|
|
|
|
|
// project translation vector from view space to absolute space
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
if( pdpValidDrawPort == NULL) return;
|
|
|
|
|
CSlaveViewer svViewer( GetChildFrame()->m_mvViewer, m_ptProjectionType,
|
|
|
|
|
pDoc->m_plGrid, pdpValidDrawPort);
|
|
|
|
|
CPlacement3D plViewer = svViewer.GetViewerPlacement();
|
|
|
|
|
plVector0.RelativeToAbsolute(plViewer);
|
|
|
|
|
plVector1.RelativeToAbsolute(plViewer);
|
|
|
|
|
// project translation vector from absolute space to second layer space
|
|
|
|
|
plVector0.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
plVector1.AbsoluteToRelative(pDoc->m_plSecondLayer);
|
|
|
|
|
// extract translation vector from placements
|
|
|
|
|
DOUBLE3D vDelta = FLOATtoDOUBLE(plVector1.pl_PositionVector)-
|
|
|
|
|
FLOATtoDOUBLE(plVector0.pl_PositionVector);
|
|
|
|
|
|
|
|
|
|
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Lock();
|
|
|
|
|
CDynamicArray<CObjectVertex> &aVtx = theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors[0].osc_aovxVertices;
|
|
|
|
|
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Unlock();
|
|
|
|
|
|
|
|
|
|
aVtx.Lock();
|
|
|
|
|
DOUBLE3D vClosest;
|
|
|
|
|
DOUBLE3D vFirstInSelection;
|
|
|
|
|
BOOL bHasSelection = FALSE;
|
|
|
|
|
// see if any of the vertices is selected
|
|
|
|
|
INDEX iVtx=0;
|
|
|
|
|
for( ; iVtx<aVtx.Count(); iVtx++)
|
|
|
|
|
{
|
|
|
|
|
if( aVtx[ iVtx].ovx_ulFlags & OVXF_CLOSEST) vClosest = aVtx[ iVtx];
|
|
|
|
|
if( (aVtx[ iVtx].ovx_ulFlags & OVXF_SELECTED) && !bHasSelection)
|
|
|
|
|
{
|
|
|
|
|
vFirstInSelection = aVtx[ iVtx];
|
|
|
|
|
bHasSelection = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
DOUBLE3D vVectorForAdding;
|
|
|
|
|
// if given delta vector should be applied absolutly
|
|
|
|
|
if( bAbsolute)
|
|
|
|
|
{
|
|
|
|
|
vVectorForAdding = vDelta;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if( bHasSelection)
|
|
|
|
|
{
|
|
|
|
|
vVectorForAdding = m_vStartDragO3DVertice+vDelta-vFirstInSelection;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
vVectorForAdding = m_vStartDragO3DVertice+vDelta-vClosest;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// apply movement
|
|
|
|
|
for( iVtx=0; iVtx<aVtx.Count(); iVtx++)
|
|
|
|
|
{
|
|
|
|
|
if( ((aVtx[ iVtx].ovx_ulFlags & OVXF_CLOSEST) && !bHasSelection) ||
|
|
|
|
|
((aVtx[ iVtx].ovx_ulFlags & OVXF_SELECTED) && bHasSelection) )
|
|
|
|
|
{
|
|
|
|
|
aVtx[ iVtx] += vVectorForAdding;
|
|
|
|
|
|
|
|
|
|
if( pDoc->m_bAutoSnap && bSnap)
|
|
|
|
|
{
|
|
|
|
|
// snap resulting vertex coordinate
|
|
|
|
|
Snap(aVtx[iVtx](1), m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
Snap(aVtx[iVtx](2), m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
Snap(aVtx[iVtx](3), m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Snap(aVtx[iVtx](1), SNAP_DOUBLE_CM);
|
|
|
|
|
Snap(aVtx[iVtx](2), SNAP_DOUBLE_CM);
|
|
|
|
|
Snap(aVtx[iVtx](3), SNAP_DOUBLE_CM);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
aVtx.Unlock();
|
|
|
|
|
pDoc->ConvertObject3DToBrush(theApp.m_vfpCurrent.vfp_o3dPrimitive, TRUE);
|
|
|
|
|
// redraw all viewes
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnMoveUp()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( (pDoc->m_pwoSecondLayer != NULL) &&
|
|
|
|
|
(pDoc->m_bPrimitiveMode) &&
|
|
|
|
|
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) &&
|
|
|
|
|
((!theApp.m_vfpCurrent.vfp_bAutoCreateMipBrushes)||
|
|
|
|
|
(theApp.m_vfpCurrent.vfp_ptPrimitiveType != PT_TERRAIN)) )
|
|
|
|
|
{
|
|
|
|
|
MarkClosestVtxOnPrimitive( FALSE);
|
|
|
|
|
DragVerticesOnPrimitive( 0.0, 0.0, m_fGridInMeters/GRID_DISCRETE_VALUES, TRUE, FALSE);
|
|
|
|
|
}
|
|
|
|
|
// redraw all viewes
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnMoveDown()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( (pDoc->m_pwoSecondLayer != NULL) &&
|
|
|
|
|
(pDoc->m_bPrimitiveMode) &&
|
|
|
|
|
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) &&
|
|
|
|
|
((!theApp.m_vfpCurrent.vfp_bAutoCreateMipBrushes)||
|
|
|
|
|
(theApp.m_vfpCurrent.vfp_ptPrimitiveType != PT_TERRAIN)) )
|
|
|
|
|
{
|
|
|
|
|
MarkClosestVtxOnPrimitive( FALSE);
|
|
|
|
|
DragVerticesOnPrimitive( 0.0, 0.0, -m_fGridInMeters/GRID_DISCRETE_VALUES, TRUE, FALSE);
|
|
|
|
|
}
|
|
|
|
|
// redraw all viewes
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnMeasurementTape()
|
|
|
|
|
{
|
|
|
|
|
m_vpViewPrefs.m_bMeasurementTape = !m_vpViewPrefs.m_bMeasurementTape;
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateMeasurementTape(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
if( m_ptProjectionType == CSlaveViewer::PT_PERSPECTIVE)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( FALSE);
|
|
|
|
|
pCmdUI->SetCheck( FALSE);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( TRUE);
|
|
|
|
|
pCmdUI->SetCheck( m_vpViewPrefs.m_bMeasurementTape);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyBuffer(UINT nID)
|
|
|
|
|
{
|
|
|
|
|
// get difference of key "1", which means buffer index
|
|
|
|
|
INDEX iPreferencesBuffer = nID-ID_BUFFER01;
|
|
|
|
|
|
|
|
|
|
// copy selected preferences to view's rendering preferences
|
|
|
|
|
m_vpViewPrefs = theApp.m_vpViewPrefs[ iPreferencesBuffer];
|
|
|
|
|
// see the change
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyEditBuffer(UINT nID)
|
|
|
|
|
{
|
|
|
|
|
// get difference of key "1", which means buffer index
|
|
|
|
|
INDEX iPreferencesBuffer = nID-ID_EDIT_BUFFER01;
|
|
|
|
|
|
|
|
|
|
CDlgRenderingPreferences dlg( iPreferencesBuffer);
|
|
|
|
|
// if dialog ended with cancel or esc, dont switch to changed preferences
|
|
|
|
|
if( dlg.DoModal() != IDOK)
|
|
|
|
|
{
|
|
|
|
|
// don't set new preferences
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// copy selected preferences to view's rendering preferences
|
|
|
|
|
m_vpViewPrefs = theApp.m_vpViewPrefs[ iPreferencesBuffer];
|
|
|
|
|
// see the change
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCircleModes()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
|
|
|
|
|
switch( pDoc->GetEditingMode())
|
|
|
|
|
{
|
|
|
|
|
case ENTITY_MODE: { pDoc->SetEditingMode( SECTOR_MODE); break;};
|
|
|
|
|
case SECTOR_MODE: { pDoc->SetEditingMode( POLYGON_MODE); break;};
|
|
|
|
|
case POLYGON_MODE: { pDoc->SetEditingMode( VERTEX_MODE); break;};
|
|
|
|
|
case VERTEX_MODE: { pDoc->SetEditingMode( TERRAIN_MODE); break;};
|
|
|
|
|
case TERRAIN_MODE: { pDoc->SetEditingMode( ENTITY_MODE); break;};
|
|
|
|
|
default: { FatalError("Unknown editing mode."); break;};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateCircleModes(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
pCmdUI->Enable( pDoc->GetEditingMode() != CSG_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDeselectAll()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
pDoc->DeselectAll();
|
|
|
|
|
|
|
|
|
|
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
|
|
|
|
|
// if we are in triangularisation primitive mode
|
|
|
|
|
if( (theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) &&
|
|
|
|
|
(bCSGOn && pDoc->m_bPrimitiveMode) )
|
|
|
|
|
{
|
|
|
|
|
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Lock();
|
|
|
|
|
CDynamicArray<CObjectVertex> &aVtx = theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors[0].osc_aovxVertices;
|
|
|
|
|
theApp.m_vfpCurrent.vfp_o3dPrimitive.ob_aoscSectors.Unlock();
|
|
|
|
|
aVtx.Lock();
|
|
|
|
|
// reset selected flags for all vertices
|
|
|
|
|
for( INDEX iVtx=0; iVtx<aVtx.Count(); iVtx++)
|
|
|
|
|
{
|
|
|
|
|
aVtx[ iVtx].ovx_ulFlags &= ~OVXF_SELECTED;
|
|
|
|
|
}
|
|
|
|
|
aVtx.Unlock();
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews(NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void CWorldEditorView::RemoveFromLinkedChain(CEntity *pen)
|
|
|
|
|
{
|
|
|
|
|
CTFileName fnDropClass;
|
|
|
|
|
CTString strTargetProperty;
|
|
|
|
|
CEntityProperty *penpProperty;
|
|
|
|
|
|
|
|
|
|
CEntity &enOnly = *pen;
|
|
|
|
|
// obtain drop class and target property name
|
|
|
|
|
if( !enOnly.DropsMarker( fnDropClass, strTargetProperty)) return;
|
|
|
|
|
penpProperty = enOnly.PropertyForName( strTargetProperty);
|
|
|
|
|
CEntity *penHisTarget = ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer);
|
|
|
|
|
// or ptr is NULL
|
|
|
|
|
if( penHisTarget == NULL) return;
|
|
|
|
|
|
|
|
|
|
CEntity *penCurrent = pen;
|
|
|
|
|
INDEX iInfiniteLoopProtector = 0;
|
|
|
|
|
// loop forever
|
|
|
|
|
FOREVER
|
|
|
|
|
{
|
|
|
|
|
if( !penCurrent->DropsMarker( fnDropClass, strTargetProperty)) return;
|
|
|
|
|
penpProperty = penCurrent->PropertyForName( strTargetProperty);
|
|
|
|
|
CEntity *penNext = ENTITYPROPERTY( penCurrent, penpProperty->ep_slOffset, CEntityPointer);
|
|
|
|
|
if( penNext == NULL) return;
|
|
|
|
|
if( penNext == pen) break;
|
|
|
|
|
// jump to next in chain
|
|
|
|
|
penCurrent = penNext;
|
|
|
|
|
iInfiniteLoopProtector ++;
|
|
|
|
|
if( iInfiniteLoopProtector >= 256) return;
|
|
|
|
|
}
|
|
|
|
|
if( !penCurrent->DropsMarker( fnDropClass, strTargetProperty)) return;
|
|
|
|
|
penpProperty = penCurrent->PropertyForName( strTargetProperty);
|
|
|
|
|
ENTITYPROPERTY( penCurrent, penpProperty->ep_slOffset, CEntityPointer) = penHisTarget;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDeleteEntities()
|
|
|
|
|
{
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
if( pDoc->GetEditingMode() == CSG_MODE) return;
|
|
|
|
|
|
|
|
|
|
if( pDoc->GetEditingMode() == SECTOR_MODE)
|
|
|
|
|
{
|
|
|
|
|
if( pDoc->m_selSectorSelection.Count() != 0)
|
|
|
|
|
{
|
|
|
|
|
if( theApp.m_Preferences.ap_bSaveUndoForDelete)
|
|
|
|
|
{
|
|
|
|
|
pDoc->RememberUndo();
|
|
|
|
|
}
|
|
|
|
|
pDoc->ClearSelections( ST_SECTOR);
|
|
|
|
|
pDoc->m_woWorld.DeleteSectors( pDoc->m_selSectorSelection, TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// if any of selected entities is anchored, anchored operation flag must be allowed or deleting is disabled
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
if( (iten->GetFlags() & ENF_ANCHORED) && !GetChildFrame()->m_bAncoredMovingAllowed) return;
|
|
|
|
|
}}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( pDoc->m_selEntitySelection.Count() != 0)
|
|
|
|
|
{
|
|
|
|
|
if( theApp.m_Preferences.ap_bSaveUndoForDelete)
|
|
|
|
|
{
|
|
|
|
|
pDoc->RememberUndo();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// check for deleting terrain
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CEntity &en=*iten;
|
|
|
|
|
// if it is terrain
|
|
|
|
|
if(en.GetRenderType()==CEntity::RT_TERRAIN)
|
|
|
|
|
{
|
|
|
|
|
// if it is selected terrain
|
|
|
|
|
if(pDoc->m_ptrSelectedTerrain==en.GetTerrain())
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_ptrSelectedTerrain=NULL;
|
|
|
|
|
theApp.m_ctTerrainPage.MarkChanged();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// for each of the selected entities
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
if( pDoc->m_cenEntitiesSelectedByVolume.IsMember(iten))
|
|
|
|
|
pDoc->m_cenEntitiesSelectedByVolume.Remove(iten);
|
|
|
|
|
}}
|
|
|
|
|
// for each of the selected entities
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
RemoveFromLinkedChain(iten);
|
|
|
|
|
}}
|
|
|
|
|
// clear selections
|
|
|
|
|
pDoc->m_selVertexSelection.Clear();
|
|
|
|
|
pDoc->m_selSectorSelection.Clear();
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
// delete all selected entities
|
|
|
|
|
pDoc->m_woWorld.DestroyEntities( pDoc->m_selEntitySelection);
|
|
|
|
|
}
|
|
|
|
|
// mark that document was changed (for saving)
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
// mark that document changeable was changed to update CSG target combo box
|
|
|
|
|
pDoc->m_chDocument.MarkChanged();
|
|
|
|
|
// mark that selections have been changed to update entity intersection properties
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews(NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateDeleteEntities(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( IsDeleteEntityEnabled());
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == SECTOR_MODE)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( pDoc->m_woWorld.CanCopySectors( pDoc->m_selSectorSelection));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CWorldEditorView::IsDeleteEntityEnabled(void)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// enable button if we are in entity mode and there is at least 1 brush entity unselected
|
|
|
|
|
BOOL bEnable = FALSE;
|
|
|
|
|
if( (pDoc->GetEditingMode() == ENTITY_MODE) &&
|
|
|
|
|
(pDoc->m_selEntitySelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
// for all of the world's entities
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// if the entity is brush
|
|
|
|
|
if (iten->GetRenderType() == CEntity::RT_BRUSH)
|
|
|
|
|
{
|
|
|
|
|
// if this is brush entity and is not selected
|
|
|
|
|
if( !iten->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// enable delete entity button
|
|
|
|
|
bEnable = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return bEnable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::UpdateCursor(void)
|
|
|
|
|
{
|
|
|
|
|
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
|
|
|
|
|
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
CTerrainLayer *ptlLayer=GetLayer();
|
|
|
|
|
|
|
|
|
|
if( theApp.m_bMeasureModeOn)
|
|
|
|
|
{
|
|
|
|
|
SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS));
|
|
|
|
|
}
|
|
|
|
|
else if( theApp.m_bCutModeOn)
|
|
|
|
|
{
|
|
|
|
|
if( pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_MIRROR));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_CUT_LINE));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL && ptlLayer!=NULL)
|
|
|
|
|
{
|
|
|
|
|
if(bCtrl&&bAlt)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_PICK));
|
|
|
|
|
}
|
|
|
|
|
else if(theApp.m_iTerrainEditMode==TEM_LAYER && ptlLayer->tl_ltType==LT_TILE)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_TILE_PAINTING));
|
|
|
|
|
}
|
|
|
|
|
else if(theApp.m_iTerrainBrushMode==TBM_ERASE)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_ERASE));
|
|
|
|
|
}
|
|
|
|
|
else if(theApp.m_iTerrainBrushMode==TBM_SMOOTH)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_SMOOTH));
|
|
|
|
|
}
|
|
|
|
|
else if(theApp.m_iTerrainBrushMode==TBM_FILTER)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_FILTER));
|
|
|
|
|
}
|
|
|
|
|
else if(theApp.m_iTerrainBrushMode==TBM_MINIMUM)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_MIN));
|
|
|
|
|
}
|
|
|
|
|
else if(theApp.m_iTerrainBrushMode==TBM_MAXIMUM)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_MAX));
|
|
|
|
|
}
|
|
|
|
|
else if(theApp.m_iTerrainBrushMode==TBM_FLATTEN)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_FLATTEN));
|
|
|
|
|
}
|
|
|
|
|
else if(theApp.m_iTerrainBrushMode==TBM_POSTERIZE)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_POSTERIZE));
|
|
|
|
|
}
|
|
|
|
|
else if(theApp.m_iTerrainBrushMode==TBM_RND_NOISE)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_RND_NOISE));
|
|
|
|
|
}
|
|
|
|
|
else if(theApp.m_iTerrainBrushMode==TBM_CONTINOUS_NOISE)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_CONTINOUS_NOISE));
|
|
|
|
|
}
|
|
|
|
|
else if(theApp.m_iTerrainBrushMode==TBM_PAINT)
|
|
|
|
|
{
|
|
|
|
|
if(theApp.m_iTerrainEditMode==TEM_HEIGHTMAP)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_HEIGHTMAP));
|
|
|
|
|
}
|
|
|
|
|
else if(theApp.m_iTerrainEditMode==TEM_LAYER)
|
|
|
|
|
{
|
|
|
|
|
SetCursor( AfxGetApp()->LoadCursor(IDC_TE_LAYER_PAINT));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CWorldEditorView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTakeSs()
|
|
|
|
|
{
|
|
|
|
|
// get draw port
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
// if it is not valid
|
|
|
|
|
if( pdpValidDrawPort == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CImageInfo iiImageInfo;
|
|
|
|
|
/* First remember current screen-shot in memory. */
|
|
|
|
|
if( pdpValidDrawPort->Lock())
|
|
|
|
|
{
|
|
|
|
|
RenderView( pdpValidDrawPort);
|
|
|
|
|
pdpValidDrawPort->Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// grab screen creating image info
|
|
|
|
|
pdpValidDrawPort->GrabScreen( iiImageInfo, 1);
|
|
|
|
|
|
|
|
|
|
// ask for save screen shot name
|
|
|
|
|
CTFileName fnDocName = CTString( CStringA(GetDocument()->GetPathName()));
|
|
|
|
|
CTFileName fnScreenShoot = _EngineGUI.FileRequester(
|
|
|
|
|
"Choose file name for screen shoot", FILTER_TGA FILTER_ALL FILTER_END, KEY_NAME_SCREEN_SHOT_DIR,
|
|
|
|
|
"ScreenShots\\", fnDocName.FileName()+"xx"+".tga", NULL, FALSE);
|
|
|
|
|
if( fnScreenShoot == "") return;
|
|
|
|
|
|
|
|
|
|
// try to
|
|
|
|
|
try {
|
|
|
|
|
// save screen shot as TGA
|
|
|
|
|
iiImageInfo.SaveTGA_t( fnScreenShoot);
|
|
|
|
|
} // if failed
|
|
|
|
|
catch (char *strError) {
|
|
|
|
|
// report error
|
|
|
|
|
AfxMessageBox(CString(strError));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnEntityMode()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
pDoc->SetEditingMode( ENTITY_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateEntityMode(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
pCmdUI->Enable( pDoc->GetEditingMode() != CSG_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTerrainMode()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
pDoc->SetEditingMode( TERRAIN_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateTerrainMode(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
pCmdUI->Enable( pDoc->GetEditingMode() != CSG_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSectorMode()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
pDoc->SetEditingMode( SECTOR_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateSectorMode(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
pCmdUI->Enable( pDoc->GetEditingMode() != CSG_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPolygonMode()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
pDoc->SetEditingMode( POLYGON_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdatePolygonMode(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
pCmdUI->Enable( pDoc->GetEditingMode() != CSG_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnEditCopy()
|
|
|
|
|
{
|
|
|
|
|
EditCopy( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnVertexMode()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
pDoc->OnCsgCancel();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::EditCopy( BOOL bAlternative)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
BOOL bCopyWorld = FALSE;
|
|
|
|
|
// if we are in entity mode
|
|
|
|
|
if( pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
// if we have some entities selected
|
|
|
|
|
if( pDoc->m_selEntitySelection.Count() != 0)
|
|
|
|
|
{
|
|
|
|
|
if( bAlternative)
|
|
|
|
|
{
|
|
|
|
|
CDynamicContainer<CEntity> selClones;
|
|
|
|
|
CPlacement3D plPaste = GetMouseInWorldPlacement();
|
|
|
|
|
// for all selected entities
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CEntity *pClone = pDoc->m_woWorld.CopyEntityInWorld( *iten, plPaste);
|
|
|
|
|
selClones.Add( pClone);
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// clear old selection and select clones
|
|
|
|
|
pDoc->m_selEntitySelection.Clear();
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER( selClones, CEntity, itenClone)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *itenClone);
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// calculate bounding boxes of all selected entities
|
|
|
|
|
FLOATaabbox3D boxEntities;
|
|
|
|
|
// for all selected entities
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
FLOATaabbox3D boxCurrentEntity;
|
|
|
|
|
iten->GetSize( boxCurrentEntity);
|
|
|
|
|
boxCurrentEntity += iten->GetPlacement().pl_PositionVector;
|
|
|
|
|
boxEntities |= boxCurrentEntity;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// average for all vectors of entities
|
|
|
|
|
FLOAT3D vCenter = boxEntities.Center();
|
|
|
|
|
vCenter(2) = boxEntities.Min()(2);
|
|
|
|
|
CPlacement3D plCenter = CPlacement3D( -vCenter, ANGLE3D(0,0,0) );
|
|
|
|
|
|
|
|
|
|
FLOAT3D vSize = boxEntities.Size();
|
|
|
|
|
FLOAT fMaxEdge = Max( Max(vSize(1), vSize(2)), vSize(3));
|
|
|
|
|
FLOAT fSnapValue;
|
|
|
|
|
if( theApp.m_bDecadicGrid)
|
|
|
|
|
{
|
|
|
|
|
INDEX iLog = (INDEX) (Log2( fMaxEdge/GRID_DISCRETE_VALUES)/Log2(10.0f));
|
|
|
|
|
fSnapValue = FLOAT(pow(10.0f, iLog));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
INDEX iLog = (INDEX) Log2( fMaxEdge/GRID_DISCRETE_VALUES);
|
|
|
|
|
fSnapValue = FLOAT(pow(2.0f, iLog));
|
|
|
|
|
}
|
|
|
|
|
pDoc->SnapToGrid( plCenter, fSnapValue);
|
|
|
|
|
|
|
|
|
|
// create world to receive selected entities
|
|
|
|
|
CWorld woEntityClipboard;
|
|
|
|
|
woEntityClipboard.SetBackgroundColor( C_WHITE);
|
|
|
|
|
woEntityClipboard.SetDescription( "No description");
|
|
|
|
|
theApp.m_ctLastCopyType = CT_ENTITY;
|
|
|
|
|
|
|
|
|
|
// copy entities in selection
|
|
|
|
|
CEntitySelection senDummy;
|
|
|
|
|
woEntityClipboard.CopyEntities(pDoc->m_woWorld, pDoc->m_selEntitySelection,
|
|
|
|
|
senDummy, plCenter);
|
|
|
|
|
senDummy.Clear();
|
|
|
|
|
|
|
|
|
|
// try to
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// save entity clipboard world
|
|
|
|
|
woEntityClipboard.Save_t(CTString("Temp\\ClipboardEntityWorld.wld"));
|
|
|
|
|
}
|
|
|
|
|
catch( char *strError)
|
|
|
|
|
{
|
|
|
|
|
AfxMessageBox( CString(strError));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// we will copy whole world
|
|
|
|
|
bCopyWorld = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if we are in polygon mode
|
|
|
|
|
else if( pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
// obtain point in the world where mouse pointed last time it was moved
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse, FALSE, FALSE, FALSE);
|
|
|
|
|
// if mouse is over polygon
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// remember selected polygon's parameters to application
|
|
|
|
|
theApp.m_pbpoClipboardPolygon->CopyProperties( *crRayHit.cr_pbpoBrushPolygon);
|
|
|
|
|
if( bAlternative)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_ctLastCopyType = CT_POLYGON_PROPERTIES_ALTERNATIVE;
|
|
|
|
|
CopyMapping(crRayHit.cr_pbpoBrushPolygon);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
theApp.m_ctLastCopyType = CT_POLYGON_PROPERTIES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// we will copy whole world
|
|
|
|
|
bCopyWorld = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if we are in sector mode
|
|
|
|
|
else if( pDoc->GetEditingMode() == SECTOR_MODE)
|
|
|
|
|
{
|
|
|
|
|
// if there are no sectors selected
|
|
|
|
|
if( pDoc->m_selSectorSelection.Count() == 0)
|
|
|
|
|
{
|
|
|
|
|
// we will copy whole world
|
|
|
|
|
bCopyWorld = TRUE;
|
|
|
|
|
}
|
|
|
|
|
// copy selected sectors
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if( !pDoc->m_woWorld.CanCopySectors( pDoc->m_selSectorSelection))
|
|
|
|
|
{
|
|
|
|
|
WarningMessage( "Error: Can't copy selected sectors. "
|
|
|
|
|
"All sectors must be in same brush and same mip factor.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// create world to receive selected sectors
|
|
|
|
|
CWorld woClipboard;
|
|
|
|
|
woClipboard.SetBackgroundColor( C_WHITE);
|
|
|
|
|
woClipboard.SetDescription( "No description");
|
|
|
|
|
// now create world base entity
|
|
|
|
|
CEntity *penWorldBase;
|
|
|
|
|
CPlacement3D plWorld = CPlacement3D( FLOAT3D(0.0f,0.0f,0.0f), ANGLE3D(0,0,0));
|
|
|
|
|
// try to
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
penWorldBase = woClipboard.CreateEntity_t(plWorld, CTFILENAME("Classes\\WorldBase.ecl"));
|
|
|
|
|
}
|
|
|
|
|
// catch and
|
|
|
|
|
catch( char *err_str)
|
|
|
|
|
{
|
|
|
|
|
// report errors
|
|
|
|
|
WarningMessage( err_str);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// prepare the entity
|
|
|
|
|
penWorldBase->Initialize();
|
|
|
|
|
EFirstWorldBase eFirstWorldBase;
|
|
|
|
|
penWorldBase->SendEvent( eFirstWorldBase);
|
|
|
|
|
CEntity::HandleSentEvents();
|
|
|
|
|
pDoc->m_woWorld.CopySectors( pDoc->m_selSectorSelection, penWorldBase, !bAlternative);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// save world to clipboard
|
|
|
|
|
woClipboard.Save_t(CTString("Temp\\ClipboardSectorWorld.wld"));
|
|
|
|
|
}
|
|
|
|
|
catch( char *strError)
|
|
|
|
|
{
|
|
|
|
|
AfxMessageBox( CString(strError));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
theApp.m_ctLastCopyType = CT_SECTOR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if we should copy the whole world
|
|
|
|
|
if( bCopyWorld)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// save world into clipboard file
|
|
|
|
|
pDoc->m_woWorld.Save_t( (CTString)"Temp\\ClipboardWorld.wld");
|
|
|
|
|
}
|
|
|
|
|
catch( char *strError)
|
|
|
|
|
{
|
|
|
|
|
AfxMessageBox( CString(strError));
|
|
|
|
|
}
|
|
|
|
|
theApp.m_ctLastCopyType = CT_WORLD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// obtain point in the world where mouse pointed last time it was moved
|
|
|
|
|
CPlacement3D CWorldEditorView::GetMouseInWorldPlacement(void)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
|
|
|
|
|
// get hitted point
|
|
|
|
|
CPlacement3D plMouse;
|
|
|
|
|
// if any kind of entity was hitted with mouse
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
// hitted entity exist
|
|
|
|
|
plMouse.pl_PositionVector = crRayHit.cr_vHit;
|
|
|
|
|
}
|
|
|
|
|
// if none of entities (brushes) was hitted with mouse
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// set position in front of viewer, at the placement of viewing point (target)
|
|
|
|
|
plMouse = GetChildFrame()->m_mvViewer.GetTargetPlacement();
|
|
|
|
|
}
|
|
|
|
|
// reset angles
|
|
|
|
|
plMouse.pl_OrientationAngle = ANGLE3D(0,0,0);
|
|
|
|
|
// snap placement
|
|
|
|
|
pDoc->SnapToGrid( plMouse, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
return plMouse;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnEditPaste()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
|
|
|
|
|
// You can't paste anything while CSG is on
|
|
|
|
|
if( bCSGOn)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL bHitModels = FALSE;
|
|
|
|
|
if( theApp.m_ctLastCopyType == CT_ENTITY) bHitModels = TRUE;
|
|
|
|
|
|
|
|
|
|
CPlacement3D plPaste = GetMouseInWorldPlacement();
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse, FALSE, bHitModels, FALSE);
|
|
|
|
|
// if last copy operation was with entities
|
|
|
|
|
if( theApp.m_ctLastCopyType == CT_ENTITY)
|
|
|
|
|
{
|
|
|
|
|
// switch to entity mode
|
|
|
|
|
pDoc->SetEditingMode( ENTITY_MODE);
|
|
|
|
|
// create world to receive pasted entities
|
|
|
|
|
CWorld woEntityClipboard;
|
|
|
|
|
// try to
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// load clipboard entity World
|
|
|
|
|
woEntityClipboard.Load_t( (CTString)"Temp\\ClipboardEntityWorld.wld");
|
|
|
|
|
}
|
|
|
|
|
catch( char *err_str)
|
|
|
|
|
{
|
|
|
|
|
AfxMessageBox( CString(err_str));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// deselect all entities
|
|
|
|
|
pDoc->m_selEntitySelection.Clear();
|
|
|
|
|
|
|
|
|
|
// make container of entities to copy
|
|
|
|
|
CDynamicContainer<CEntity> cenToCopy;
|
|
|
|
|
cenToCopy = woEntityClipboard.wo_cenEntities;
|
|
|
|
|
// remove empty brushes from it
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(woEntityClipboard.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
if( iten->IsEmptyBrush() && (iten->GetFlags()&ENF_ZONING))
|
|
|
|
|
{
|
|
|
|
|
cenToCopy.Remove(iten);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
// copy entities in clipboard
|
|
|
|
|
pDoc->m_woWorld.CopyEntities(woEntityClipboard, cenToCopy,
|
|
|
|
|
pDoc->m_selEntitySelection, plPaste);
|
|
|
|
|
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
// if last copy operation was with polygon properties
|
|
|
|
|
else if( theApp.m_ctLastCopyType == CT_POLYGON_PROPERTIES)
|
|
|
|
|
{
|
|
|
|
|
// if mouse is over polygon
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
if( crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
// apply remembered polygon's parameters to selection
|
|
|
|
|
itbpo->CopyTextures( *theApp.m_pbpoClipboardPolygon);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// apply remembered polygon's parameters to polygon under mouse
|
|
|
|
|
crRayHit.cr_pbpoBrushPolygon->CopyTextures( *theApp.m_pbpoClipboardPolygon);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
// if last copy operation was with whole world
|
|
|
|
|
else if( theApp.m_ctLastCopyType == CT_WORLD)
|
|
|
|
|
{
|
|
|
|
|
// load world from clipboard file and start template CSG
|
|
|
|
|
pDoc->StartTemplateCSG( plPaste, (CTString)"Temp\\ClipboardWorld.wld");
|
|
|
|
|
}
|
|
|
|
|
// if last copy operation was with selected sectors
|
|
|
|
|
else if( theApp.m_ctLastCopyType == CT_SECTOR)
|
|
|
|
|
{
|
|
|
|
|
// load world from sectors clipboard file and start template CSG
|
|
|
|
|
pDoc->StartTemplateCSG( plPaste, (CTString)"Temp\\ClipboardSectorWorld.wld");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProcesWEDConsoleShortcuts( MSG *pMsg)
|
|
|
|
|
{
|
|
|
|
|
if( pMsg->message==WM_KEYDOWN)
|
|
|
|
|
{
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
if( !bShift && pMsg->wParam == VK_F2) _pShell->Execute( "include \"Scripts\\WorldEditorKeys\\F2.ini\"");
|
|
|
|
|
if( !bShift && pMsg->wParam == VK_F3) _pShell->Execute( "include \"Scripts\\WorldEditorKeys\\F3.ini\"");
|
|
|
|
|
if( !bShift && pMsg->wParam == VK_F4) _pShell->Execute( "include \"Scripts\\WorldEditorKeys\\F4.ini\"");
|
|
|
|
|
if( bShift && (pMsg->wParam == VK_F2)) _pShell->Execute( "include \"Scripts\\WorldEditorKeys\\Shift_F2.ini\"");
|
|
|
|
|
if( bShift && (pMsg->wParam == VK_F3)) _pShell->Execute( "include \"Scripts\\WorldEditorKeys\\Shift_F3.ini\"");
|
|
|
|
|
if( bShift && (pMsg->wParam == VK_F4)) _pShell->Execute( "include \"Scripts\\WorldEditorKeys\\Shift_F4.ini\"");
|
|
|
|
|
}
|
|
|
|
|
if( pMsg->message==WM_MBUTTONDOWN || pMsg->message==WM_MBUTTONDBLCLK )
|
|
|
|
|
{
|
|
|
|
|
_pShell->Execute( "include \"Scripts\\WorldEditorKeys\\MiddleMouse.ini\"");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CWorldEditorView::PreTranslateMessage(MSG* pMsg)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
// get csg and primitive flags
|
|
|
|
|
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
|
|
|
|
|
BOOL bPrimitive = pDoc->m_bPrimitiveMode;
|
|
|
|
|
// get editting mode flags
|
|
|
|
|
BOOL bEntityMode = pDoc->GetEditingMode() == ENTITY_MODE;
|
|
|
|
|
BOOL bSectorMode = pDoc->GetEditingMode() == SECTOR_MODE;
|
|
|
|
|
BOOL bPolygonMode = pDoc->GetEditingMode() == POLYGON_MODE;
|
|
|
|
|
BOOL bTerrainMode = pDoc->GetEditingMode() == TERRAIN_MODE;
|
|
|
|
|
// get key statuses
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
|
|
|
|
|
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
|
|
|
|
|
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
|
|
|
|
|
// get mouse button statuses
|
|
|
|
|
BOOL bLMB = (GetKeyState( VK_LBUTTON)&0x8000) != 0;
|
|
|
|
|
BOOL bRMB = (GetKeyState( VK_RBUTTON)&0x8000) != 0;
|
|
|
|
|
|
|
|
|
|
// process scripts that are invoked on shortcuts from within WED
|
|
|
|
|
ProcesWEDConsoleShortcuts( pMsg);
|
|
|
|
|
|
|
|
|
|
// Ctrl +'A':
|
|
|
|
|
// - entity -> select all in volume
|
|
|
|
|
// - sector -> select all entities
|
|
|
|
|
// - polygon -> select all polygons in sector(s)
|
|
|
|
|
|
|
|
|
|
// Alt+'A'
|
|
|
|
|
// - sector -> show all sectors
|
|
|
|
|
// - entity -> show all entities
|
|
|
|
|
// - polygon-> auto fit mapping
|
|
|
|
|
// - vertex-> auto fit mapping
|
|
|
|
|
|
|
|
|
|
// 'A':
|
|
|
|
|
// - select by volume -> allign volume
|
|
|
|
|
// - entity -> allign entity selection or world
|
|
|
|
|
// - primitive -> allign primitive to screen
|
|
|
|
|
// - sector -> allign visible sectors to screen
|
|
|
|
|
|
|
|
|
|
if( ((pMsg->message==WM_KEYDOWN) || (pMsg->message==WM_SYSKEYDOWN)) &&
|
|
|
|
|
((int)pMsg->wParam=='A') )
|
|
|
|
|
{
|
|
|
|
|
// setup mouse - ray hit information
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
m_penEntityHitOnContext = crRayHit.cr_penHit;
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) && (crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
m_pbpoRightClickedPolygon = crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( bCSGOn && !bShift)
|
|
|
|
|
{
|
|
|
|
|
if( bCtrl && bPrimitive)
|
|
|
|
|
{
|
|
|
|
|
OnAlignPrimitive();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FLOATaabbox3D boxSecondLayer;
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_pwoSecondLayer->wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
FLOATaabbox3D box;
|
|
|
|
|
iten->GetSize( box);
|
|
|
|
|
|
|
|
|
|
FLOAT fMinX = box.Min()(1);
|
|
|
|
|
FLOAT fMinY = box.Min()(2);
|
|
|
|
|
FLOAT fMinZ = box.Min()(3);
|
|
|
|
|
FLOAT fMaxX = box.Max()(1);
|
|
|
|
|
FLOAT fMaxY = box.Max()(2);
|
|
|
|
|
FLOAT fMaxZ = box.Max()(3);
|
|
|
|
|
FLOAT3D avCorners[8];
|
|
|
|
|
avCorners[0] = FLOAT3D(fMinX,fMinY,fMinZ);
|
|
|
|
|
avCorners[1] = FLOAT3D(fMaxX,fMinY,fMinZ);
|
|
|
|
|
avCorners[2] = FLOAT3D(fMaxX,fMinY,fMaxZ);
|
|
|
|
|
avCorners[3] = FLOAT3D(fMinX,fMinY,fMaxZ);
|
|
|
|
|
avCorners[4] = FLOAT3D(fMinX,fMaxY,fMinZ);
|
|
|
|
|
avCorners[5] = FLOAT3D(fMaxX,fMaxY,fMinZ);
|
|
|
|
|
avCorners[6] = FLOAT3D(fMaxX,fMaxY,fMaxZ);
|
|
|
|
|
avCorners[7] = FLOAT3D(fMinX,fMaxY,fMaxZ);
|
|
|
|
|
|
|
|
|
|
for( INDEX iVtx=0; iVtx<8; iVtx++)
|
|
|
|
|
{
|
|
|
|
|
CPlacement3D plToProject = CPlacement3D( avCorners[iVtx], ANGLE3D(0,0,0));
|
|
|
|
|
plToProject.RelativeToAbsolute( pDoc->m_plSecondLayer);
|
|
|
|
|
boxSecondLayer |= FLOATaabbox3D(plToProject.pl_PositionVector);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
AllignBox( boxSecondLayer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == ENTITY_MODE && !bShift)
|
|
|
|
|
{
|
|
|
|
|
if( bCtrl && bAlt)
|
|
|
|
|
{
|
|
|
|
|
OnSelectAllSectors();
|
|
|
|
|
}
|
|
|
|
|
else if( bCtrl)
|
|
|
|
|
{
|
|
|
|
|
pDoc->OnSelectAllInVolume();
|
|
|
|
|
}
|
|
|
|
|
else if( bAlt)
|
|
|
|
|
{
|
|
|
|
|
pDoc->OnShowAllEntities();
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->m_bBrowseEntitiesMode)
|
|
|
|
|
{
|
|
|
|
|
OnAlignVolume();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CenterSelected();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(pDoc->GetEditingMode() == SECTOR_MODE && !bShift)
|
|
|
|
|
{
|
|
|
|
|
if( bCtrl && bAlt)
|
|
|
|
|
{
|
|
|
|
|
OnSelectAllPolygons();
|
|
|
|
|
}
|
|
|
|
|
else if( bCtrl)
|
|
|
|
|
{
|
|
|
|
|
OnSelectAllEntitiesInSectors();
|
|
|
|
|
}
|
|
|
|
|
else if( bAlt)
|
|
|
|
|
{
|
|
|
|
|
pDoc->OnShowAllSectors();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CenterSelected();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
if( bCtrl && bAlt && !bShift)
|
|
|
|
|
{
|
|
|
|
|
OnSelectAllVertices();
|
|
|
|
|
}
|
|
|
|
|
else if( bCtrl && !bShift && !bAlt)
|
|
|
|
|
{
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) && (crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// select all polygons in hitted sector
|
|
|
|
|
CBrushSector *pbscSector = crRayHit.cr_pbpoBrushPolygon->bpo_pbscSector;
|
|
|
|
|
FOREACHINSTATICARRAY(pbscSector->bsc_abpoPolygons, CBrushPolygon, itpo)
|
|
|
|
|
{
|
|
|
|
|
if( !itpo->IsSelected(BPOF_SELECTED)) pDoc->m_selPolygonSelection.Select( *itpo);
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( bAlt && bShift && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
AutoFitMapping( crRayHit.cr_pbpoBrushPolygon, TRUE, TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( bAlt && bShift)
|
|
|
|
|
{
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
AutoFitMapping( crRayHit.cr_pbpoBrushPolygon, TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( bAlt)
|
|
|
|
|
{
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
AutoFitMapping( crRayHit.cr_pbpoBrushPolygon);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(!bCtrl&&!bShift&&!bAlt)
|
|
|
|
|
{
|
|
|
|
|
CenterSelected();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
if(!bCtrl&&!bShift&&!bAlt)
|
|
|
|
|
{
|
|
|
|
|
CenterSelected();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(pDoc->GetEditingMode() == VERTEX_MODE && !bShift)
|
|
|
|
|
{
|
|
|
|
|
if( bCtrl && bAlt)
|
|
|
|
|
{
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) && (crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// select all vertices on hitted polygon
|
|
|
|
|
FOREACHINSTATICARRAY(crRayHit.cr_pbpoBrushPolygon->bpo_apbvxTriangleVertices, CBrushVertex *, itpbvx)
|
|
|
|
|
{
|
|
|
|
|
if( !(*itpbvx)->IsSelected(BVXF_SELECTED)) pDoc->m_selVertexSelection.Select( **itpbvx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
else if( bCtrl||bAlt)
|
|
|
|
|
{
|
|
|
|
|
CDlgAllignVertices dlg;
|
|
|
|
|
dlg.DoModal();
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CenterSelected();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if return is pressed in primitive CSG mode
|
|
|
|
|
if( (pMsg->message==WM_KEYDOWN) && ((int)pMsg->wParam==VK_RETURN) && bCSGOn && bPrimitive)
|
|
|
|
|
{
|
|
|
|
|
pMainFrame->ShowInfoWindow();
|
|
|
|
|
CInfoSheet *pSheet = pMainFrame->m_pInfoFrame->m_pInfoSheet;
|
|
|
|
|
CWnd *pwndWidthEditCtrl = pSheet->m_PgPrimitive.GetDlgItem( IDC_WIDTH);
|
|
|
|
|
if( pwndWidthEditCtrl != NULL)
|
|
|
|
|
{
|
|
|
|
|
pSheet->SetActivePage( &pSheet->m_PgPrimitive);
|
|
|
|
|
pwndWidthEditCtrl->SetFocus();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FLOAT tmNow = _pTimer->GetHighPrecisionTimer().GetSeconds();
|
|
|
|
|
// if we caught key or button down message and not status line info pause requested
|
|
|
|
|
if( (theApp.m_tmStartStatusLineInfo<tmNow) &&
|
|
|
|
|
( (pMsg->message==WM_SYSKEYDOWN) ||
|
|
|
|
|
(pMsg->message==WM_KEYDOWN) ||
|
|
|
|
|
(pMsg->message==WM_KEYUP) ||
|
|
|
|
|
(pMsg->message==WM_LBUTTONDOWN) ||
|
|
|
|
|
(pMsg->message==WM_RBUTTONDOWN) ||
|
|
|
|
|
(pMsg->message==WM_LBUTTONUP) ||
|
|
|
|
|
(pMsg->message==WM_RBUTTONUP) ||
|
|
|
|
|
(pMsg->message==WM_MOUSEMOVE) ||
|
|
|
|
|
(pMsg->message==WM_CHANGE_EDITING_MODE) ||
|
|
|
|
|
(bShift || bAlt || bCtrl || bSpace || bLMB || bRMB)) )
|
|
|
|
|
{
|
|
|
|
|
// space without mouse buttons but ctrl pressed
|
|
|
|
|
if( bSpace && !bLMB && !bRMB && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"LMB zoomes in 2x, RMB zoomes out 2x");
|
|
|
|
|
}
|
|
|
|
|
// space without mouse buttons
|
|
|
|
|
else if( bSpace && !bLMB && !bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Rotate or move viewer. Try: LMB,RMB,LMB+RMB,Space+Ctrl");
|
|
|
|
|
}
|
|
|
|
|
// space with left mouse button
|
|
|
|
|
else if( bSpace && bLMB && !bRMB)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Move viewer in view plane");
|
|
|
|
|
}
|
|
|
|
|
// space with right mouse button
|
|
|
|
|
else if( bSpace && !bLMB && bRMB)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Move viewer in floor plane");
|
|
|
|
|
}
|
|
|
|
|
// space with both mouse buttons
|
|
|
|
|
else if( bSpace && bLMB && bRMB)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Rotate viewer");
|
|
|
|
|
}
|
|
|
|
|
// Alt pressed
|
|
|
|
|
else if( bAlt && !bCtrl && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"You can drag any view and drop it into browser");
|
|
|
|
|
}
|
|
|
|
|
// for measure mode
|
|
|
|
|
else if( theApp.m_bMeasureModeOn)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use LMB to measure distances");
|
|
|
|
|
}
|
|
|
|
|
// for cut mode
|
|
|
|
|
else if( theApp.m_bCutModeOn)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use LMB to move cut/mirror line, enter to apply");
|
|
|
|
|
}
|
|
|
|
|
// for CSG mode
|
|
|
|
|
else if( bCSGOn)
|
|
|
|
|
{
|
|
|
|
|
// for primitive mode
|
|
|
|
|
if( bPrimitive)
|
|
|
|
|
{
|
|
|
|
|
// primitive mode, only <Ctrl> pressed
|
|
|
|
|
if( bCtrl && !bLMB && !bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use LMBx2 to teleport primitive. Try: LMB,RMB,LMB+RMB,Shift");
|
|
|
|
|
}
|
|
|
|
|
//-------- <Ctrl+Shift> commands for primitive
|
|
|
|
|
// primitive mode, <Ctrl+Shift> pressed
|
|
|
|
|
else if( bCtrl && !bLMB && !bRMB && bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Size and shear primitive. Try: LMB,RMB");
|
|
|
|
|
}
|
|
|
|
|
// primitive mode, <Ctrl+Shift+LMB> pressed
|
|
|
|
|
else if( bCtrl && bLMB && !bRMB && bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Resize primitive");
|
|
|
|
|
}
|
|
|
|
|
// primitive mode, <Ctrl+Shift+RMB> pressed
|
|
|
|
|
else if( bCtrl && !bLMB && bRMB && bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Shear primitive");
|
|
|
|
|
}
|
|
|
|
|
// primitive mode, <Ctrl+LMB> pressed
|
|
|
|
|
else if( bCtrl && bLMB && !bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Move primitive in view plane");
|
|
|
|
|
}
|
|
|
|
|
// primitive mode, <Ctrl+RMB> pressed
|
|
|
|
|
else if( bCtrl && !bLMB && bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Move primitive in floor plane");
|
|
|
|
|
}
|
|
|
|
|
// primitive mode, <Ctrl+LMB+RMB> pressed
|
|
|
|
|
else if( bCtrl && bLMB && bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Rotate primitive in view plane");
|
|
|
|
|
}
|
|
|
|
|
// <Shift> pressed
|
|
|
|
|
else if( !bCtrl && !bLMB && !bRMB && bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"LMB inserts vertex, RMB deletes vertex. Try: Ctrl");
|
|
|
|
|
}
|
|
|
|
|
// primitive mode, nothing pressed
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Primitive mode. Try: Alt,Ctrl,Shift");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// for template mode
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//-------- <Ctrl> commands for template (moving and rotating)
|
|
|
|
|
// template mode, only <Ctrl> pressed
|
|
|
|
|
if( bCtrl && !bLMB && !bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use LMB dbl. click to teleport template. Try: LMB,RMB,LMB+RMB");
|
|
|
|
|
}
|
|
|
|
|
// template mode, <Ctrl+LMB> pressed
|
|
|
|
|
else if( bCtrl && bLMB && !bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Move template in view plane");
|
|
|
|
|
}
|
|
|
|
|
// template mode, <Ctrl+RMB> pressed
|
|
|
|
|
else if( bCtrl && !bLMB && bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Move template in floor plane");
|
|
|
|
|
}
|
|
|
|
|
// template mode, <Ctrl+LMB+RMB> pressed
|
|
|
|
|
else if( bCtrl && bLMB && bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Rotate template");
|
|
|
|
|
}
|
|
|
|
|
// template mode, nothing pressed
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Template primitive mode. Try: Ctrl");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// for entity mode
|
|
|
|
|
else if( bEntityMode)
|
|
|
|
|
{
|
|
|
|
|
// get property ID
|
|
|
|
|
CPropertyID *ppidProperty = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
|
|
|
|
|
// if we have at least one entity selected and edititng property of edit range type
|
|
|
|
|
// and Ctrl+Shift pressed
|
|
|
|
|
BOOL bEditingProperties = ( (pDoc->m_selEntitySelection.Count() != 0) &&
|
|
|
|
|
( (ppidProperty != NULL) &&
|
|
|
|
|
( (ppidProperty->pid_eptType == CEntityProperty::EPT_ANGLE3D) ||
|
|
|
|
|
(ppidProperty->pid_eptType == CEntityProperty::EPT_RANGE))) );
|
|
|
|
|
// entity mode, <Ctrl+Shift> pressed
|
|
|
|
|
if( bEditingProperties && bCtrl && bShift )
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use LMB to change range or direction");
|
|
|
|
|
}
|
|
|
|
|
// <Alt + Ctrl> pressed
|
|
|
|
|
else if( bAlt && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use LMB to set entity ptr. (Entity ptr property must be selected)");
|
|
|
|
|
}
|
|
|
|
|
else if( bCtrl && bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use RMB to set mip switch distance (in auto mode)");
|
|
|
|
|
}
|
|
|
|
|
else if( bSpace && bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use RMB to change virtual mip distance");
|
|
|
|
|
}
|
|
|
|
|
// entity mode, <Shift> pressed
|
|
|
|
|
else if( !bCtrl && bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use LMB to toggle selection of one entity . Try: Ctrl,Space");
|
|
|
|
|
}
|
|
|
|
|
// entity mode, <Ctrl> pressed
|
|
|
|
|
else if( bCtrl && !bLMB && !bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
if( bEditingProperties)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use LMBx2 click to teleport entity. Try: LMB,RMB,LMB+RMB,Shift");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use LMBx2 click to teleport entity. Try: Alt,LMB,RMB,LMB+RMB");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// entity mode, <Ctrl+LMB> pressed
|
|
|
|
|
else if( bCtrl && bLMB && !bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Move entities in view plane");
|
|
|
|
|
}
|
|
|
|
|
// entity mode, <Ctrl+RMB> pressed
|
|
|
|
|
else if( bCtrl && !bLMB && bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Move entities in floor plane");
|
|
|
|
|
}
|
|
|
|
|
// entity mode, <Ctrl+LMB+RMB> pressed
|
|
|
|
|
else if( bCtrl && bLMB && bRMB && !bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Rotate entities");
|
|
|
|
|
}
|
|
|
|
|
// entity mode, nothing pressed
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if( bEditingProperties)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use LMB to select entities. Try: Ctrl,Shift");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Use LMB to select entities. Try: Ctrl,Shift,Ctrl+Alt");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// for polygon mode
|
|
|
|
|
else if( bPolygonMode)
|
|
|
|
|
{
|
|
|
|
|
// polygon mode, <Ctrl> pressed
|
|
|
|
|
if( bCtrl && !bLMB && !bRMB && !bShift && !bAlt)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"LMBx2 centers texture. RMBx2 selects similar by texture. Try: LMB,LMB+RMB");
|
|
|
|
|
}
|
|
|
|
|
// polygon mode, <Shift> pressed
|
|
|
|
|
else if( !bCtrl && !bLMB && !bRMB && bShift && !bAlt)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Toggle polygon using LMB or RMB. Add simillar with LMB dbl. click");
|
|
|
|
|
}
|
|
|
|
|
// polygon mode, <Ctrl+LMB> pressed
|
|
|
|
|
else if( bCtrl && bLMB && !bRMB && !bShift && !bAlt)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Scroll polygon's mapping texture");
|
|
|
|
|
}
|
|
|
|
|
// polygon mode, <Ctrl+LMB+RMB> pressed
|
|
|
|
|
else if( bCtrl && bLMB && bRMB && !bShift && !bAlt)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Rotate polygon's mapping texture");
|
|
|
|
|
}
|
|
|
|
|
else if( bCtrl && bAlt)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Zoom in texture 2x using LMB, zoom out texture 2x using RMB");
|
|
|
|
|
}
|
|
|
|
|
// polygon mode, <Ctrl+Shift> pressed
|
|
|
|
|
else if( bCtrl && bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Select polygons similar by texture in sector with LMBx2, similar by color with RMBx2");
|
|
|
|
|
}
|
|
|
|
|
// polygon mode, nothing pressed
|
|
|
|
|
else if( !bCtrl && !bLMB && !bRMB && !bShift && !bAlt)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Select polygons using LMB or RMB, by color using LMBx2. Try: Alt,Ctrl,Shift,Ctrl+Alt");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// for sector mode
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// sector mode, <Shift> pressed
|
|
|
|
|
if( !bCtrl && !bLMB && !bRMB && bShift)
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Add to selection or deselect sector using LMB or LMB dbl. click");
|
|
|
|
|
}
|
|
|
|
|
// sector mode, nothing pressed
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
STATUS_LINE_MESASGE( L"Select or deselect sector using LMB or LMB dbl. click. Try: Alt,Shift");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for these events
|
|
|
|
|
if( (pMsg->message==WM_KEYDOWN) ||
|
|
|
|
|
(pMsg->message==WM_KEYUP) ||
|
|
|
|
|
(pMsg->message==WM_LBUTTONDOWN) ||
|
|
|
|
|
(pMsg->message==WM_RBUTTONDOWN) ||
|
|
|
|
|
(pMsg->message==WM_LBUTTONUP) ||
|
|
|
|
|
(pMsg->message==WM_RBUTTONUP) )
|
|
|
|
|
{
|
|
|
|
|
// set text describing data that is edited
|
|
|
|
|
SetEditingDataPaneInfo( TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CView::PreTranslateMessage(pMsg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyO()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode()==TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_SMOOTH;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
pDoc->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OnCloneCSG();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateKeyO(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode()==TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( TRUE);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OnUpdateCloneCsg(pCmdUI);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCloneCSG()
|
|
|
|
|
{
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CDlgProgress dlgProgressDialog( pMainFrame);
|
|
|
|
|
|
|
|
|
|
// disable CSG report
|
|
|
|
|
theApp.m_bCSGReportEnabled = FALSE;
|
|
|
|
|
// and clear its values
|
|
|
|
|
_pfWorldEditingProfile.Reset();
|
|
|
|
|
// remember automatic info flag
|
|
|
|
|
BOOL bAutomaticInfo = theApp.m_Preferences.ap_AutomaticInfo;
|
|
|
|
|
// get shift pressed flag
|
|
|
|
|
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
|
|
|
|
|
// we will have 1 clone (by default)
|
|
|
|
|
INDEX ctClones = 1;
|
|
|
|
|
// if shift is pressed, we want "array of clones" (numeric option)
|
|
|
|
|
if( bAlt)
|
|
|
|
|
{
|
|
|
|
|
CDlgAutoDeltaCSG dlgAutoDeltaCSG;
|
|
|
|
|
// if dialog wasn't succeseful
|
|
|
|
|
if( dlgAutoDeltaCSG.DoModal() != IDOK)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// temporary disable automatic info
|
|
|
|
|
theApp.m_Preferences.ap_AutomaticInfo = FALSE;
|
|
|
|
|
// get wanted count of clones
|
|
|
|
|
ctClones = dlgAutoDeltaCSG.m_ctNumberOfClones;
|
|
|
|
|
// write it to .ini file for the next time
|
|
|
|
|
theApp.WriteProfileInt(L"World editor", L"Number of CSG clones", ctClones);
|
|
|
|
|
}
|
|
|
|
|
// set wait cursor
|
|
|
|
|
CWaitCursor StartWaitCursor;
|
|
|
|
|
|
|
|
|
|
// if there is more than 1 clone in progress
|
|
|
|
|
if( ctClones > 1)
|
|
|
|
|
{
|
|
|
|
|
// create progress dialog
|
|
|
|
|
dlgProgressDialog.Create( IDD_PROGRESS_DIALOG);
|
|
|
|
|
dlgProgressDialog.SetWindowText(L"Repeat CSG");
|
|
|
|
|
// show progress window
|
|
|
|
|
dlgProgressDialog.ShowWindow( SW_SHOW);
|
|
|
|
|
// center window
|
|
|
|
|
dlgProgressDialog.CenterWindow();
|
|
|
|
|
// set progress range
|
|
|
|
|
dlgProgressDialog.m_ctrlProgres.SetRange( 0, (short) ctClones);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if primitive CSG was last used CSG operation
|
|
|
|
|
if( pDoc->m_bLastUsedPrimitiveMode)
|
|
|
|
|
{
|
|
|
|
|
// for all clones
|
|
|
|
|
for( INDEX iClone=0; iClone<ctClones; iClone++)
|
|
|
|
|
{
|
|
|
|
|
// if there is more than 1 clone in progress
|
|
|
|
|
if( ctClones > 1)
|
|
|
|
|
{
|
|
|
|
|
char achrProgressMessage[ 256];
|
|
|
|
|
sprintf( achrProgressMessage, "Cloning CSG operation ... (processing %d/%d)",
|
|
|
|
|
iClone+1, ctClones);
|
|
|
|
|
// set message and progress position
|
|
|
|
|
dlgProgressDialog.SetProgressMessageAndPosition( achrProgressMessage, iClone+1);
|
|
|
|
|
}
|
|
|
|
|
// create new placement from delta placement
|
|
|
|
|
CPlacement3D plNewPlacement = pDoc->m_plDeltaPlacement;
|
|
|
|
|
// convert it into absolute space of last used placement (delta applyed)
|
|
|
|
|
plNewPlacement.RelativeToAbsolute( pDoc->m_plLastPlacement);
|
|
|
|
|
// copy last used values for primitive as initial values for this new primitive
|
|
|
|
|
theApp.m_vfpPreLast = theApp.m_vfpLast;
|
|
|
|
|
theApp.m_vfpCurrent = theApp.m_vfpLast;
|
|
|
|
|
// apply width, sheer, stretch, ... delta
|
|
|
|
|
theApp.m_vfpCurrent += theApp.m_vfpDelta;
|
|
|
|
|
// after substraction we colud get some invalid values (like negative width!!!)
|
|
|
|
|
// so we have to correct them
|
|
|
|
|
theApp.m_vfpCurrent.CorrectInvalidValues();
|
|
|
|
|
// we will snap primitive placement
|
|
|
|
|
pDoc->SnapToGrid( plNewPlacement, SNAP_FLOAT_25);
|
|
|
|
|
|
|
|
|
|
// create primitive but don't reset orientation angles
|
|
|
|
|
pDoc->StartPrimitiveCSG( plNewPlacement, FALSE);
|
|
|
|
|
// for last clone enable undo remembering
|
|
|
|
|
if( iClone > 0)
|
|
|
|
|
{
|
|
|
|
|
// disable undo remembering
|
|
|
|
|
theApp.m_bRememberUndo = FALSE;
|
|
|
|
|
}
|
|
|
|
|
// if shift was helded while starting clone CSG
|
|
|
|
|
if( bAlt)
|
|
|
|
|
{
|
|
|
|
|
// apply same CSG operation as was used last time
|
|
|
|
|
pDoc->ApplyCSG( pDoc->m_csgtLastUsedCSGOperation);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if there is more than 1 clone in progress
|
|
|
|
|
if( ctClones > 1)
|
|
|
|
|
{
|
|
|
|
|
// destroy progress dialog
|
|
|
|
|
dlgProgressDialog.DestroyWindow();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// for templates
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// for all clones
|
|
|
|
|
for( INDEX iClone=0; iClone<ctClones; iClone++)
|
|
|
|
|
{
|
|
|
|
|
// if there is more than 1 clone in progress
|
|
|
|
|
if( ctClones > 1)
|
|
|
|
|
{
|
|
|
|
|
char achrProgressMessage[ 256];
|
|
|
|
|
sprintf( achrProgressMessage, "Repeating last operation... (processing %d/%d)",
|
|
|
|
|
iClone+1, ctClones);
|
|
|
|
|
// set message and progress position
|
|
|
|
|
dlgProgressDialog.SetProgressMessageAndPosition( achrProgressMessage, iClone+1);
|
|
|
|
|
}
|
|
|
|
|
// create new placement from delta placement
|
|
|
|
|
CPlacement3D plNewPlacement = pDoc->m_plDeltaPlacement;
|
|
|
|
|
// convert it into absolute space of last used placement (delta applyed)
|
|
|
|
|
plNewPlacement.RelativeToAbsolute( pDoc->m_plLastPlacement);
|
|
|
|
|
|
|
|
|
|
// we will snap template placement
|
|
|
|
|
pDoc->SnapToGrid( plNewPlacement, SNAP_FLOAT_25);
|
|
|
|
|
|
|
|
|
|
// for last clone enable undo remembering
|
|
|
|
|
if( iClone > 0)
|
|
|
|
|
{
|
|
|
|
|
// disable undo remembering
|
|
|
|
|
theApp.m_bRememberUndo = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// start template CSG but don't reset orientation angles
|
|
|
|
|
pDoc->StartTemplateCSG( plNewPlacement, pDoc->m_fnLastDroppedTemplate, FALSE);
|
|
|
|
|
|
|
|
|
|
// if shift was helded while starting clone CSG, we want to apply CSG
|
|
|
|
|
// if template was automaticly joined after droping, we are not in CSG_MODE any more
|
|
|
|
|
if( bAlt && (pDoc->GetEditingMode() == CSG_MODE) )
|
|
|
|
|
{
|
|
|
|
|
// apply same CSG operation as was used last time
|
|
|
|
|
pDoc->ApplyCSG( pDoc->m_csgtLastUsedCSGOperation);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if there is more than 1 clone in progress
|
|
|
|
|
if( ctClones > 1)
|
|
|
|
|
{
|
|
|
|
|
// destroy progress dialog
|
|
|
|
|
dlgProgressDialog.DestroyWindow();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// enable undo remembering
|
|
|
|
|
theApp.m_bRememberUndo = TRUE;
|
|
|
|
|
// restore automatic info flag
|
|
|
|
|
theApp.m_Preferences.ap_AutomaticInfo = bAutomaticInfo;
|
|
|
|
|
// enable CSG report
|
|
|
|
|
theApp.m_bCSGReportEnabled = TRUE;
|
|
|
|
|
// and report calculated CSG report values
|
|
|
|
|
_pfWorldEditingProfile.Report( theApp.m_strCSGAndShadowStatistics);
|
|
|
|
|
theApp.m_strCSGAndShadowStatistics.SaveVar(CTString("Temp\\Profile_CSGWizard.txt"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateCloneCsg(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// there can't be any kind of CSG going on if we want to clone last CSG operation
|
|
|
|
|
BOOL bCSGOn = pDoc->m_pwoSecondLayer != NULL;
|
|
|
|
|
// there must be at least one CSG operation done
|
|
|
|
|
BOOL bCanBeCloned = ( (pDoc->m_csgtLastUsedCSGOperation == CSG_ADD) ||
|
|
|
|
|
(pDoc->m_csgtLastUsedCSGOperation == CSG_ADD_REVERSE) ||
|
|
|
|
|
(pDoc->m_csgtLastUsedCSGOperation == CSG_REMOVE) ||
|
|
|
|
|
(pDoc->m_csgtLastUsedCSGOperation == CSG_REMOVE_REVERSE) ||
|
|
|
|
|
(pDoc->m_csgtLastUsedCSGOperation == CSG_SPLIT_SECTORS) ||
|
|
|
|
|
(pDoc->m_csgtLastUsedCSGOperation == CSG_SPLIT_POLYGONS) ||
|
|
|
|
|
(pDoc->m_csgtLastUsedCSGOperation == CSG_JOIN_LAYERS) );
|
|
|
|
|
// last and current primitive CSG operation must have same primitive types
|
|
|
|
|
pCmdUI->Enable( bCanBeCloned && !bCSGOn &&
|
|
|
|
|
(pDoc->m_csgtPreLastUsedCSGOperation==pDoc->m_csgtLastUsedCSGOperation) &&
|
|
|
|
|
(pDoc->m_bPreLastUsedPrimitiveMode==pDoc->m_bLastUsedPrimitiveMode) &&
|
|
|
|
|
(!pDoc->m_bLastUsedPrimitiveMode ||
|
|
|
|
|
(pDoc->m_bLastUsedPrimitiveMode &&
|
|
|
|
|
(theApp.m_vfpPreLast.vfp_ptPrimitiveType == theApp.m_vfpLast.vfp_ptPrimitiveType))) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPopupConus()
|
|
|
|
|
{
|
|
|
|
|
// start conus primitive
|
|
|
|
|
theApp.m_vfpCurrent = theApp.m_vfpConus;
|
|
|
|
|
CreatePrimitiveCalledFromPopup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPopupTorus()
|
|
|
|
|
{
|
|
|
|
|
// start conus primitive
|
|
|
|
|
theApp.m_vfpCurrent = theApp.m_vfpTorus;
|
|
|
|
|
CreatePrimitiveCalledFromPopup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPopupSphere()
|
|
|
|
|
{
|
|
|
|
|
// start conus primitive
|
|
|
|
|
theApp.m_vfpCurrent = theApp.m_vfpSphere;
|
|
|
|
|
CreatePrimitiveCalledFromPopup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPopupStairs()
|
|
|
|
|
{
|
|
|
|
|
// start conus primitive
|
|
|
|
|
theApp.m_vfpCurrent = theApp.m_vfpStaircases;
|
|
|
|
|
CreatePrimitiveCalledFromPopup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPopupTerrain()
|
|
|
|
|
{
|
|
|
|
|
// start conus primitive
|
|
|
|
|
theApp.m_vfpCurrent = theApp.m_vfpTerrain;
|
|
|
|
|
CreatePrimitiveCalledFromPopup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::CreatePrimitiveCalledFromPopup()
|
|
|
|
|
{
|
|
|
|
|
if( !m_bEntityHitedOnContext)
|
|
|
|
|
{
|
|
|
|
|
OnConusPrimitive();
|
|
|
|
|
}
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// create placement for primitive's position
|
|
|
|
|
CPlacement3D plDrop = m_plEntityHitOnContext;
|
|
|
|
|
|
|
|
|
|
// snap placement
|
|
|
|
|
pDoc->SnapToGrid( plDrop, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
// create primitive for the first time, don't reset angles
|
|
|
|
|
pDoc->StartPrimitiveCSG( plDrop, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnMeasureOn()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_bMeasureModeOn = !theApp.m_bMeasureModeOn;
|
|
|
|
|
theApp.m_bCutModeOn = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateMeasureOn(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->SetCheck( theApp.m_bMeasureModeOn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnResetViewer()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
// set new target
|
|
|
|
|
GetChildFrame()->m_mvViewer.SetTargetPlacement( FLOAT3D(0.0f, 0.0f, 0.0f));
|
|
|
|
|
_fFlyModeSpeedMultiplier=theApp.m_Preferences.ap_fDefaultFlyModeSpeed;
|
|
|
|
|
pMainFrame->ResetInfoWindowPos();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCenterBcgViewer()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// for all of the world's entities
|
|
|
|
|
CEntity *penBackgroundViewer = pDoc->m_woWorld.GetBackgroundViewer();
|
|
|
|
|
if( penBackgroundViewer != NULL)
|
|
|
|
|
{
|
|
|
|
|
// set new target
|
|
|
|
|
GetChildFrame()->m_mvViewer.SetTargetPlacement(
|
|
|
|
|
penBackgroundViewer->GetPlacement().pl_PositionVector);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCopyTexture()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
OnPickLayer();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
if( pDoc->GetEditingMode() == SECTOR_MODE)
|
|
|
|
|
{
|
|
|
|
|
CBrushSector *pbscSector = crRayHit.cr_pbpoBrushPolygon->bpo_pbscSector;
|
|
|
|
|
CopySectorAmbient( pbscSector);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// get polygon's texture
|
|
|
|
|
CTextureData *pTD = (CTextureData *)crRayHit.cr_pbpoBrushPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.GetData();
|
|
|
|
|
if( pTD != NULL)
|
|
|
|
|
{
|
|
|
|
|
// get name from serial object
|
|
|
|
|
CTFileName fnTextureName = pTD->GetName();
|
|
|
|
|
// set it as new active texture
|
|
|
|
|
theApp.SetNewActiveTexture( _fnmApplicationPath + fnTextureName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPasteTexture()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_RND_NOISE;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
pDoc->SetStatusLineModeInfoMessage();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL))
|
|
|
|
|
{
|
|
|
|
|
if( pDoc->GetEditingMode() == SECTOR_MODE)
|
|
|
|
|
{
|
|
|
|
|
CBrushSector *pbscSector = crRayHit.cr_pbpoBrushPolygon->bpo_pbscSector;
|
|
|
|
|
PasteSectorAmbient( pbscSector);
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
PasteTexture( crRayHit.cr_pbpoBrushPolygon);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectByTextureAdjacent()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// select similar by texture to hitted polygon
|
|
|
|
|
crRayHit.cr_pbpoBrushPolygon->SelectSimilarByTexture( pDoc->m_selPolygonSelection, pDoc->m_iTexture);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectByTextureInSector()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// select similar by texture to hitted polygon
|
|
|
|
|
crRayHit.cr_pbpoBrushPolygon->SelectByTextureInSector( pDoc->m_selPolygonSelection, pDoc->m_iTexture);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectByColorInSector()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// select similar by color to hitted polygon
|
|
|
|
|
crRayHit.cr_pbpoBrushPolygon->SelectByColorInSector( pDoc->m_selPolygonSelection);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnFunction()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->m_iMode == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_cenEntitiesSelectedByVolume.Clear();
|
|
|
|
|
// for each of the entities selected by volume
|
|
|
|
|
FOREACHINDYNAMICCONTAINER( pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// add entity into volume selection
|
|
|
|
|
if( !pDoc->m_cenEntitiesSelectedByVolume.IsMember(iten))
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_cenEntitiesSelectedByVolume.Add( iten);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// go out of browse by volume mode
|
|
|
|
|
if( pDoc->m_bBrowseEntitiesMode) pDoc->OnBrowseEntitiesMode();
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
// obtain main frame ptr
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
// and refresh property combo manualy calling on idle
|
|
|
|
|
pMainFrame->m_PropertyComboBar.m_PropertyComboBox.OnIdle( 0);
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->m_iMode == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
pDoc->OnFilterSelection();
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->m_iMode == VERTEX_MODE)
|
|
|
|
|
{
|
|
|
|
|
SnapSelectedVerticesToPlane();
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->m_iMode == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_FILTER;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
pDoc->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::SnapSelectedVerticesToPlane(void)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->RememberUndo();
|
|
|
|
|
pDoc->m_woWorld.TriangularizeForVertices( pDoc->m_selVertexSelection);
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygon *pbpo = crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
CEntity *pen = pbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
|
|
|
|
|
CSimpleProjection3D_DOUBLE pr;
|
|
|
|
|
pr.ObjectPlacementL() = pen->GetPlacement();
|
|
|
|
|
pr.ViewerPlacementL() = _plOrigin;
|
|
|
|
|
pr.Prepare();
|
|
|
|
|
DOUBLEplane3D plAbsPrecise;
|
|
|
|
|
pr.Project(pbpo->bpo_pbplPlane->bpl_pldPreciseRelative, plAbsPrecise);
|
|
|
|
|
|
|
|
|
|
// snap vertices to plane
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
|
|
|
|
|
{
|
|
|
|
|
CEntity *pen = itbvx->bvx_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
|
|
|
|
|
CSimpleProjection3D_DOUBLE pr;
|
|
|
|
|
pr.ObjectPlacementL() = pen->GetPlacement();
|
|
|
|
|
pr.ViewerPlacementL() = _plOrigin;
|
|
|
|
|
pr.Prepare();
|
|
|
|
|
DOUBLE3D vAbsPrecise;
|
|
|
|
|
pr.ProjectCoordinate(itbvx->bvx_vdPreciseRelative, vAbsPrecise);
|
|
|
|
|
DOUBLE3D vOnPlaneAbsPrecise=plAbsPrecise.ProjectPoint(vAbsPrecise);
|
|
|
|
|
itbvx->SetAbsolutePosition(vOnPlaneAbsPrecise);
|
|
|
|
|
}}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_woWorld.UpdateSectorsDuringVertexChange( pDoc->m_selVertexSelection);
|
|
|
|
|
pDoc->m_woWorld.UpdateSectorsAfterVertexChange( pDoc->m_selVertexSelection);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCrossroadForCtrlF()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if(pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
OnFindTexture();
|
|
|
|
|
}
|
|
|
|
|
else if(pDoc->GetEditingMode() == VERTEX_MODE)
|
|
|
|
|
{
|
|
|
|
|
CDlgFilterVertexSelection dlg;
|
|
|
|
|
dlg.DoModal();
|
|
|
|
|
}
|
|
|
|
|
else if(pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iFilter=(theApp.m_iFilter+1)%FLT_COUNT;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnFindTexture()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// get polygon's texture
|
|
|
|
|
CTextureData *pTD = (CTextureData *)crRayHit.cr_pbpoBrushPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.GetData();
|
|
|
|
|
if( pTD != NULL)
|
|
|
|
|
{
|
|
|
|
|
// get name from serial object
|
|
|
|
|
CTFileName fnTextureName = pTD->GetName();
|
|
|
|
|
// set it as new active texture
|
|
|
|
|
theApp.FindItemInBrowser( fnTextureName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCenterEntity()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
if(pDoc->GetEditingMode() == CSG_MODE)
|
|
|
|
|
{
|
|
|
|
|
GetChildFrame()->m_mvViewer.SetTargetPlacement( pDoc->m_plSecondLayer.pl_PositionVector);
|
|
|
|
|
}
|
|
|
|
|
if(pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
CTerrain *ptrTerrain=GetTerrain();
|
|
|
|
|
if(ptrTerrain!=NULL)
|
|
|
|
|
{
|
|
|
|
|
FLOATaabbox3D boxBoundingBox;
|
|
|
|
|
ptrTerrain->GetAllTerrainBBox(boxBoundingBox);
|
|
|
|
|
FLOAT3D vTerrainCenter=boxBoundingBox.Center();
|
|
|
|
|
GetChildFrame()->m_mvViewer.SetTargetPlacement( vTerrainCenter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if( pDoc->m_selEntitySelection.Count() == 0) return;
|
|
|
|
|
// reset position
|
|
|
|
|
FLOAT3D vEntityPlacementAverage = FLOAT3D( 0.0f, 0.0f, 0.0f);
|
|
|
|
|
//for all selected entities
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// get placement of current entity
|
|
|
|
|
CPlacement3D plEntityPlacement = iten->GetPlacement();
|
|
|
|
|
// add movement offset to placement
|
|
|
|
|
vEntityPlacementAverage += plEntityPlacement.pl_PositionVector;
|
|
|
|
|
}
|
|
|
|
|
// calculate average position
|
|
|
|
|
vEntityPlacementAverage /= (FLOAT) pDoc->m_selEntitySelection.Count();
|
|
|
|
|
// set centered entity position as new viewer's target
|
|
|
|
|
GetChildFrame()->m_mvViewer.SetTargetPlacement( vEntityPlacementAverage);
|
|
|
|
|
}
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateCenterEntity(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// if we are in entity mode and we have at least 1 entity selected
|
|
|
|
|
pCmdUI->Enable( (pDoc->GetEditingMode() == CSG_MODE) ||
|
|
|
|
|
((pDoc->GetEditingMode() == TERRAIN_MODE) &&
|
|
|
|
|
(GetTerrain()!=NULL)) ||
|
|
|
|
|
((pDoc->GetEditingMode() == ENTITY_MODE) &&
|
|
|
|
|
(pDoc->m_selEntitySelection.Count() != 0)) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDropMarker()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CTFileName fnDropClass;
|
|
|
|
|
CTString strTargetProperty;
|
|
|
|
|
|
|
|
|
|
if(pDoc->m_selEntitySelection.Count() == 1)
|
|
|
|
|
{
|
|
|
|
|
CEntity &enOnly = pDoc->m_selEntitySelection.GetFirst();
|
|
|
|
|
if(enOnly.DropsMarker( fnDropClass, strTargetProperty))
|
|
|
|
|
{
|
|
|
|
|
OnDropMarker(enOnly.GetPlacement());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDropMarker(CPlacement3D plMarker)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
CTFileName fnDropClass, fnDummy;
|
|
|
|
|
CTString strTargetProperty;
|
|
|
|
|
CEntityProperty *penpProperty;
|
|
|
|
|
|
|
|
|
|
CEntity &enOnly = pDoc->m_selEntitySelection.GetFirst();
|
|
|
|
|
// obtain drop class and target property name
|
|
|
|
|
if( !enOnly.DropsMarker( fnDropClass, strTargetProperty)) return;
|
|
|
|
|
penpProperty = enOnly.PropertyForName( strTargetProperty);
|
|
|
|
|
|
|
|
|
|
CEntity *penFirstInChain;
|
|
|
|
|
if (enOnly.IsMarker())
|
|
|
|
|
{
|
|
|
|
|
penFirstInChain = &enOnly;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
penFirstInChain = ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer);
|
|
|
|
|
}
|
|
|
|
|
CEntity *penSecondInChain = NULL;
|
|
|
|
|
// if first in chain exists, try getting his target
|
|
|
|
|
if( penFirstInChain != NULL)
|
|
|
|
|
{
|
|
|
|
|
if( !penFirstInChain->DropsMarker( fnDropClass, strTargetProperty)) return;
|
|
|
|
|
penpProperty = penFirstInChain->PropertyForName( strTargetProperty);
|
|
|
|
|
penSecondInChain = ENTITYPROPERTY( penFirstInChain, penpProperty->ep_slOffset, CEntityPointer);
|
|
|
|
|
}
|
|
|
|
|
// spawn entity
|
|
|
|
|
CEntity *penSpawned;
|
|
|
|
|
if( !enOnly.DropsMarker( fnDropClass, strTargetProperty)) return;
|
|
|
|
|
penpProperty = enOnly.PropertyForName( strTargetProperty);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// spawn one entity of class selected in browser
|
|
|
|
|
penSpawned = pDoc->m_woWorld.CreateEntity_t( plMarker, fnDropClass);
|
|
|
|
|
penSpawned->Initialize();
|
|
|
|
|
}
|
|
|
|
|
catch( char *strError)
|
|
|
|
|
{
|
|
|
|
|
AfxMessageBox( CString(strError));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// if first in chain entity exists, set spawned entity to be his target
|
|
|
|
|
if( penFirstInChain != NULL)
|
|
|
|
|
{
|
|
|
|
|
if( !penFirstInChain->DropsMarker( fnDropClass, strTargetProperty)) return;
|
|
|
|
|
penpProperty = penFirstInChain->PropertyForName( strTargetProperty);
|
|
|
|
|
ENTITYPROPERTY( penFirstInChain, penpProperty->ep_slOffset, CEntityPointer) = penSpawned;
|
|
|
|
|
}
|
|
|
|
|
if( !penSpawned->DropsMarker( fnDropClass, strTargetProperty)) return;
|
|
|
|
|
penpProperty = penSpawned->PropertyForName( strTargetProperty);
|
|
|
|
|
if( penSecondInChain != NULL)
|
|
|
|
|
{
|
|
|
|
|
ENTITYPROPERTY( penSpawned, penpProperty->ep_slOffset, CEntityPointer) = penSecondInChain;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ENTITYPROPERTY( penSpawned, penpProperty->ep_slOffset, CEntityPointer) = penFirstInChain;
|
|
|
|
|
}
|
|
|
|
|
// set our only selected entity to point to spawned entity
|
|
|
|
|
if( !enOnly.DropsMarker( fnDropClass, strTargetProperty)) return;
|
|
|
|
|
penpProperty = enOnly.PropertyForName( strTargetProperty);
|
|
|
|
|
ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer) = penSpawned;
|
|
|
|
|
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateDropMarker(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CTFileName fnDropClass;
|
|
|
|
|
CTString strTargetProperty;
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// if we are in entity mode, we have 1 entity selected and entity can drop marker
|
|
|
|
|
if( (pDoc->GetEditingMode() == ENTITY_MODE) &&
|
|
|
|
|
(pDoc->m_selEntitySelection.Count() == 1) &&
|
|
|
|
|
(pDoc->m_selEntitySelection.GetFirst().DropsMarker( fnDropClass, strTargetProperty)) )
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( TRUE);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTestConnections()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CEntityProperty *penpProperty;
|
|
|
|
|
|
|
|
|
|
CEntity &enOnly = pDoc->m_selEntitySelection.GetFirst();
|
|
|
|
|
CTString strTargetProperty;
|
|
|
|
|
|
|
|
|
|
// get target pointer for curently selected entity
|
|
|
|
|
enOnly.MovesByTargetedRoute( strTargetProperty);
|
|
|
|
|
penpProperty = enOnly.PropertyForName( strTargetProperty);
|
|
|
|
|
CEntity *penCurrent = ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer);
|
|
|
|
|
|
|
|
|
|
// if no target
|
|
|
|
|
if( penCurrent == NULL) {
|
|
|
|
|
// do nothing
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get target pointer for its target (get next)
|
|
|
|
|
penCurrent->MovesByTargetedRoute( strTargetProperty);
|
|
|
|
|
penpProperty = penCurrent->PropertyForName( strTargetProperty);
|
|
|
|
|
CEntity *penNext = ENTITYPROPERTY( penCurrent, penpProperty->ep_slOffset, CEntityPointer);
|
|
|
|
|
|
|
|
|
|
// if no target
|
|
|
|
|
if( penNext == NULL) {
|
|
|
|
|
// do nothing
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// teleport to next
|
|
|
|
|
enOnly.SetPlacement( penNext->GetPlacement());
|
|
|
|
|
|
|
|
|
|
if (enOnly.en_RenderType == CEntity::RT_BRUSH)
|
|
|
|
|
{
|
|
|
|
|
DiscardShadows( &enOnly);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set target pointer to next next
|
|
|
|
|
enOnly.MovesByTargetedRoute( strTargetProperty);
|
|
|
|
|
penpProperty = enOnly.PropertyForName( strTargetProperty);
|
|
|
|
|
ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer) = penNext;
|
|
|
|
|
|
|
|
|
|
// mark that document and selections are changed
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTestConnectionsBack()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CEntityProperty *penpProperty;
|
|
|
|
|
|
|
|
|
|
CEntity &enOnly = pDoc->m_selEntitySelection.GetFirst();
|
|
|
|
|
CTString strTargetProperty;
|
|
|
|
|
|
|
|
|
|
// get target pointer for curently selected entity
|
|
|
|
|
enOnly.MovesByTargetedRoute( strTargetProperty);
|
|
|
|
|
penpProperty = enOnly.PropertyForName( strTargetProperty);
|
|
|
|
|
CEntity *penCurrent = ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer);
|
|
|
|
|
|
|
|
|
|
// if no target
|
|
|
|
|
if( penCurrent == NULL) {
|
|
|
|
|
// do nothing
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// start from current
|
|
|
|
|
CEntity *penNext=penCurrent;
|
|
|
|
|
|
|
|
|
|
// repeat
|
|
|
|
|
FOREVER {
|
|
|
|
|
// get next target pointer
|
|
|
|
|
penNext->MovesByTargetedRoute( strTargetProperty);
|
|
|
|
|
penpProperty = penCurrent->PropertyForName( strTargetProperty);
|
|
|
|
|
CEntity *penNextNext = ENTITYPROPERTY( penNext, penpProperty->ep_slOffset, CEntityPointer);
|
|
|
|
|
// if no target
|
|
|
|
|
if( penNextNext == NULL) {
|
|
|
|
|
// do nothing
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// if the next one is same as where the entity started
|
|
|
|
|
if( penNextNext==penCurrent) {
|
|
|
|
|
// stop searching
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// go to that target
|
|
|
|
|
penNext = penNextNext;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// teleport to next
|
|
|
|
|
enOnly.SetPlacement( penNext->GetPlacement());
|
|
|
|
|
if (enOnly.en_RenderType == CEntity::RT_BRUSH)
|
|
|
|
|
{
|
|
|
|
|
DiscardShadows( &enOnly);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set target pointer to next next
|
|
|
|
|
enOnly.MovesByTargetedRoute( strTargetProperty);
|
|
|
|
|
penpProperty = enOnly.PropertyForName( strTargetProperty);
|
|
|
|
|
ENTITYPROPERTY( &enOnly, penpProperty->ep_slOffset, CEntityPointer) = penNext;
|
|
|
|
|
|
|
|
|
|
// mark that document and selections are changed
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateTestConnections(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
BOOL bModeAndCount = (pDoc->GetEditingMode() == ENTITY_MODE) &&
|
|
|
|
|
( pDoc->m_selEntitySelection.Count() == 1);
|
|
|
|
|
BOOL bEnableCommand = FALSE;
|
|
|
|
|
// if we have only one entity selected and we are in entity mode
|
|
|
|
|
if( bModeAndCount)
|
|
|
|
|
{
|
|
|
|
|
CEntity &enOnly = pDoc->m_selEntitySelection.GetFirst();
|
|
|
|
|
CTString strTargetProperty;
|
|
|
|
|
// if we can perform test path function on this entity
|
|
|
|
|
if( enOnly.MovesByTargetedRoute( strTargetProperty))
|
|
|
|
|
bEnableCommand = TRUE;
|
|
|
|
|
}
|
|
|
|
|
pCmdUI->Enable( bEnableCommand);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateTestConnectionsBack(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
// update same as it is forward
|
|
|
|
|
OnUpdateTestConnections( pCmdUI);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define PAPER (4.0f/5.0f)
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAlignVolume()
|
|
|
|
|
{
|
|
|
|
|
// get draw port
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
// if it is not valid
|
|
|
|
|
if( pdpValidDrawPort == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer(GetChildFrame()->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid,
|
|
|
|
|
pdpValidDrawPort);
|
|
|
|
|
// get zoom factor
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
PIX pixWidth = pdpValidDrawPort->GetWidth();
|
|
|
|
|
PIX pixHeight = pdpValidDrawPort->GetHeight();
|
|
|
|
|
FLOAT fWidth = pixWidth/fZoom;
|
|
|
|
|
FLOAT fHeight = pixHeight/fZoom;
|
|
|
|
|
// get point in space that user is looking
|
|
|
|
|
FLOAT3D vTargetPoint = GetChildFrame()->m_mvViewer.GetTargetPlacement().pl_PositionVector;
|
|
|
|
|
|
|
|
|
|
pDoc->m_vCreateBoxVertice0 = FLOAT3D(
|
|
|
|
|
vTargetPoint(1)-fWidth*PAPER/2,
|
|
|
|
|
vTargetPoint(2)-fHeight*PAPER/2,
|
|
|
|
|
vTargetPoint(3)-fHeight*PAPER/2);
|
|
|
|
|
pDoc->m_vCreateBoxVertice1 = FLOAT3D(
|
|
|
|
|
vTargetPoint(1)+fWidth*PAPER/2,
|
|
|
|
|
vTargetPoint(2)+fHeight*PAPER/2,
|
|
|
|
|
vTargetPoint(3)+fHeight*PAPER/2);
|
|
|
|
|
pDoc->SelectEntitiesByVolumeBox();
|
|
|
|
|
// try to select first entity in volume
|
|
|
|
|
pDoc->SelectGivenEntity( 0);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAlignPrimitive()
|
|
|
|
|
{
|
|
|
|
|
// get draw port
|
|
|
|
|
CDrawPort *pdpValidDrawPort = GetDrawPort();
|
|
|
|
|
// if it is not valid
|
|
|
|
|
if( pdpValidDrawPort == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer(GetChildFrame()->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid,
|
|
|
|
|
pdpValidDrawPort);
|
|
|
|
|
// get zoom factor
|
|
|
|
|
FLOAT fZoom = svViewer.GetZoomFactor();
|
|
|
|
|
PIX pixWidth = pdpValidDrawPort->GetWidth()*8/10;
|
|
|
|
|
PIX pixHeight = pdpValidDrawPort->GetHeight()*8/10;
|
|
|
|
|
FLOAT fWidth = pixWidth/fZoom;
|
|
|
|
|
FLOAT fHeight = pixHeight/fZoom;
|
|
|
|
|
// get point in space that user is looking
|
|
|
|
|
FLOAT3D vTargetPoint = GetChildFrame()->m_mvViewer.GetTargetPlacement().pl_PositionVector;
|
|
|
|
|
pDoc->m_plSecondLayer.pl_PositionVector = vTargetPoint;
|
|
|
|
|
|
|
|
|
|
fWidth = FLOAT( pow( 2.0f, floor(Log2(fWidth))));
|
|
|
|
|
fHeight = FLOAT( pow( 2.0f, floor(Log2(fHeight))));
|
|
|
|
|
|
|
|
|
|
theApp.m_vfpCurrent.vfp_fXMin = -fWidth/2.0f;
|
|
|
|
|
theApp.m_vfpCurrent.vfp_fXMax = fWidth/2.0f;
|
|
|
|
|
theApp.m_vfpCurrent.vfp_fYMin = -fHeight/2.0f;
|
|
|
|
|
theApp.m_vfpCurrent.vfp_fYMax = fHeight/2.0f;
|
|
|
|
|
theApp.m_vfpCurrent.vfp_fZMin = -fHeight/2.0f;
|
|
|
|
|
theApp.m_vfpCurrent.vfp_fZMax = fHeight/2.0f;
|
|
|
|
|
|
|
|
|
|
pDoc->SnapToGrid( pDoc->m_plSecondLayer, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
if( pDoc->m_bAutoSnap)
|
|
|
|
|
{
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fXMin, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fXMax, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fYMin, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fYMax, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fZMin, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fZMax, m_fGridInMeters/GRID_DISCRETE_VALUES);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fXMin, SNAP_FLOAT_CM);
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fXMax, SNAP_FLOAT_CM);
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fYMin, SNAP_FLOAT_CM);
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fYMax, SNAP_FLOAT_CM);
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fZMin, SNAP_FLOAT_CM);
|
|
|
|
|
pDoc->SnapFloat( theApp.m_vfpCurrent.vfp_fZMax, SNAP_FLOAT_CM);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pDoc->RefreshPrimitivePage();
|
|
|
|
|
pDoc->CreatePrimitive();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateAlignVolume(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pCmdUI->Enable( pDoc->m_bBrowseEntitiesMode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCurrentViewProperties()
|
|
|
|
|
{
|
|
|
|
|
// copy selected preferences from view rendering preferences to temporary buffer
|
|
|
|
|
theApp.m_vpViewPrefs[ VIEW_PREFERENCES_CT] = m_vpViewPrefs;
|
|
|
|
|
// call edit view preferences with temporary view preferences buffer (last one)
|
|
|
|
|
CDlgRenderingPreferences dlg( VIEW_PREFERENCES_CT);
|
|
|
|
|
// if dialog ended with cancel or esc, dont switch to changed preferences
|
|
|
|
|
if( dlg.DoModal() != IDOK)
|
|
|
|
|
{
|
|
|
|
|
// don't set new preferences
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// copy selected preferences to view's rendering preferences
|
|
|
|
|
m_vpViewPrefs = theApp.m_vpViewPrefs[ VIEW_PREFERENCES_CT];
|
|
|
|
|
// see the change
|
|
|
|
|
Invalidate( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnChooseColor()
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
// find toll bar's rectangle
|
|
|
|
|
RECT rectToolBar;
|
|
|
|
|
m_wndSelectionTools.GetWindowRect( &rectToolBar);
|
|
|
|
|
// Then we find tool button's index
|
|
|
|
|
INDEX iToolButton = m_wndSelectionTools.CommandToIndex( ID_CHOOSE_COLOR);
|
|
|
|
|
// Using given index, we obtain button's rectangle
|
|
|
|
|
RECT rectButton;
|
|
|
|
|
m_wndSelectionTools.GetItemRect( iToolButton, &rectButton);
|
|
|
|
|
// set screen coordinates of LU point of clicked tool button
|
|
|
|
|
CustomColorPicker( rectToolBar.left + rectButton.left, rectToolBar.top + rectButton.bottom);
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
POINT ptCursor;
|
|
|
|
|
GetCursorPos( &ptCursor);
|
|
|
|
|
if( ptCursor.y < 100)
|
|
|
|
|
{
|
|
|
|
|
pMainFrame->CustomColorPicker( ptCursor.x-50, ptCursor.y);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pMainFrame->CustomColorPicker( ptCursor.x-50, ptCursor.y-100);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateChooseColor(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
// don't enable initially
|
|
|
|
|
BOOL bEnable = FALSE;
|
|
|
|
|
// obtain document
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
// if sector mode is on and there is at least 1 selected sector
|
|
|
|
|
if( (pDoc->m_iMode == SECTOR_MODE) && (pDoc->m_selSectorSelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
bEnable = TRUE;
|
|
|
|
|
}
|
|
|
|
|
// if polygon mode is on and there is at least 1 selected polygon
|
|
|
|
|
if( (pDoc->m_iMode == POLYGON_MODE) && (pDoc->m_selPolygonSelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
bEnable = TRUE;
|
|
|
|
|
}
|
|
|
|
|
pCmdUI->Enable( bEnable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCrossroadForC()
|
|
|
|
|
{
|
|
|
|
|
PostMessage( WM_COMMAND, ID_CHOOSE_COLOR, 0);
|
|
|
|
|
PostMessage( WM_COMMAND, ID_CENTER_ENTITY, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::SetAsCsgTarget(CEntity *pen)
|
|
|
|
|
{
|
|
|
|
|
if( (pen != NULL) &&
|
|
|
|
|
( (pen->GetRenderType() == CEntity::RT_BRUSH) ||
|
|
|
|
|
(pen->GetRenderType() == CEntity::RT_FIELDBRUSH)) )
|
|
|
|
|
{
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
pMainFrame->m_CSGDesitnationCombo.SelectBrushEntity(pen);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSetAsCsgTarget()
|
|
|
|
|
{
|
|
|
|
|
SetAsCsgTarget(m_penEntityHitOnContext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCsgSelectSector()
|
|
|
|
|
{
|
|
|
|
|
if( (m_penEntityHitOnContext != NULL) &&
|
|
|
|
|
((m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) ||
|
|
|
|
|
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_FIELDBRUSH)) &&
|
|
|
|
|
(m_pbpoRightClickedPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
CBrushSector *pbscHitted = m_pbpoRightClickedPolygon->bpo_pbscSector;
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
pDoc->m_selSectorSelection.Clear();
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *pbscHitted);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT CWorldEditorView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
|
{
|
|
|
|
|
CChildFrame *pCF = GetChildFrame();
|
|
|
|
|
// if test game is active
|
|
|
|
|
if( _pInput->IsInputEnabled())
|
|
|
|
|
{ // repost some messages to thread
|
|
|
|
|
switch( message ) {
|
|
|
|
|
case WM_CANCELMODE:
|
|
|
|
|
case WM_KILLFOCUS:
|
|
|
|
|
case WM_ACTIVATEAPP:
|
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
|
::PostMessage(NULL, message, wParam, lParam);
|
|
|
|
|
break;
|
|
|
|
|
case WM_MOUSEACTIVATE:
|
|
|
|
|
if( pCF->m_bTestGameOn)
|
|
|
|
|
{
|
|
|
|
|
return MA_ACTIVATEANDEAT;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case WM_DESTROY:
|
|
|
|
|
PostQuitMessage(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CView::WindowProc(message, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRButtonDblClk(UINT nFlags, CPoint point)
|
|
|
|
|
{
|
|
|
|
|
m_iaInputAction = IA_NONE;
|
|
|
|
|
|
|
|
|
|
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
|
|
|
|
|
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
BOOL bLMB = nFlags & MK_LBUTTON;
|
|
|
|
|
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
|
|
|
|
|
|
|
|
|
|
// space+ctrl+rmb zoomes out 2x
|
|
|
|
|
if( (bSpace) && (bCtrl) )
|
|
|
|
|
{
|
|
|
|
|
if( bLMB) return;
|
|
|
|
|
OnZoomLess();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RMB dblclick and ctrl select by texture in sector
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
// Alt+Ctrl requests that clicked polygon sizes its texture
|
|
|
|
|
if( bAlt && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
MultiplyMappingOnPolygon( 2.0f);
|
|
|
|
|
}
|
|
|
|
|
else if( bCtrl && bShift && !bAlt)
|
|
|
|
|
{
|
|
|
|
|
OnSelectByColorInSector();
|
|
|
|
|
}
|
|
|
|
|
else if( bCtrl && !bAlt)
|
|
|
|
|
{
|
|
|
|
|
OnSelectByTextureAdjacent();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CView::OnRButtonDblClk(nFlags, point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnLastPrimitive()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
CTString strError;
|
|
|
|
|
BOOL bCutEnabled = IsCutEnabled( strError);
|
|
|
|
|
if( theApp.m_bCutModeOn)
|
|
|
|
|
{
|
|
|
|
|
if( !bCutEnabled)
|
|
|
|
|
{
|
|
|
|
|
// exit cut mode
|
|
|
|
|
theApp.m_bCutModeOn = FALSE;
|
|
|
|
|
WarningMessage( "%s", strError);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pDoc->ApplyCut();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// exit cut mode
|
|
|
|
|
theApp.m_bCutModeOn = FALSE;
|
|
|
|
|
pDoc->StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateLastPrimitive(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( GetDocument()->m_pwoSecondLayer == NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnConusPrimitive()
|
|
|
|
|
{
|
|
|
|
|
// copy last used values for conus primitive as initial values for new primitive
|
|
|
|
|
theApp.m_vfpCurrent = theApp.m_vfpConus;
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTorusPrimitive()
|
|
|
|
|
{
|
|
|
|
|
// copy last used values for torus primitive as initial values for new primitive
|
|
|
|
|
theApp.m_vfpCurrent = theApp.m_vfpTorus;
|
|
|
|
|
// create primitive for the first time
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnStaircasePrimitive()
|
|
|
|
|
{
|
|
|
|
|
// copy last used values for staircase primitive as initial values for new primitive
|
|
|
|
|
theApp.m_vfpCurrent = theApp.m_vfpStaircases;
|
|
|
|
|
// create primitive for the first time
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSpherePrimitive()
|
|
|
|
|
{
|
|
|
|
|
// copy last used values for sphere primitive as initial values for new primitive
|
|
|
|
|
theApp.m_vfpCurrent = theApp.m_vfpSphere;
|
|
|
|
|
// create primitive for the first time
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTerrainPrimitive()
|
|
|
|
|
{
|
|
|
|
|
// copy last used values for terrain primitive as initial values for new primitive
|
|
|
|
|
theApp.m_vfpCurrent = theApp.m_vfpTerrain;
|
|
|
|
|
// create primitive for the first time
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->StartPrimitiveCSG( theApp.m_vfpCurrent.vfp_plPrimitive, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateConusPrimitive(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( GetDocument()->m_pwoSecondLayer == NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateSpherePrimitive(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( GetDocument()->m_pwoSecondLayer == NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateTerrainPrimitive(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( GetDocument()->m_pwoSecondLayer == NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateTorusPrimitive(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( GetDocument()->m_pwoSecondLayer == NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateStaircasePrimitive(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( GetDocument()->m_pwoSecondLayer == NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateMoveDown(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pCmdUI->Enable( (pDoc->m_pwoSecondLayer != NULL) &&
|
|
|
|
|
(pDoc->m_bPrimitiveMode) &&
|
|
|
|
|
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateMoveUp(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pCmdUI->Enable( (pDoc->m_pwoSecondLayer != NULL) &&
|
|
|
|
|
(pDoc->m_bPrimitiveMode) &&
|
|
|
|
|
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectLights()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
CBrushPolygon *pbpoPolygon = crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit == NULL) ||
|
|
|
|
|
(pbpoPolygon == NULL) ||
|
|
|
|
|
(pbpoPolygon->IsSelected(BPOF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
CBrushShadowMap &bsm = itbpo->bpo_smShadowMap;
|
|
|
|
|
FOREACHINLIST(CBrushShadowLayer, bsl_lnInShadowMap, bsm.bsm_lhLayers, itbsl)
|
|
|
|
|
{
|
|
|
|
|
CLightSource *plsLight = itbsl->bsl_plsLightSource;
|
|
|
|
|
CEntity *penLight = plsLight->ls_penEntity;
|
|
|
|
|
if( !pDoc->m_selEntitySelection.IsSelected( *penLight))
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *penLight);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CBrushShadowMap &bsm = pbpoPolygon->bpo_smShadowMap;
|
|
|
|
|
FOREACHINLIST(CBrushShadowLayer, bsl_lnInShadowMap, bsm.bsm_lhLayers, itbsl)
|
|
|
|
|
{
|
|
|
|
|
CLightSource *plsLight = itbsl->bsl_plsLightSource;
|
|
|
|
|
CEntity *penLight = plsLight->ls_penEntity;
|
|
|
|
|
if( !pDoc->m_selEntitySelection.IsSelected( *penLight))
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *penLight);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetEditingMode( ENTITY_MODE);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDiscardShadows()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CEntity *penEntity = NULL;
|
|
|
|
|
CBrushSector *pbscSector = NULL;
|
|
|
|
|
CBrushPolygon *pbpoPolygon = NULL;
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
penEntity = crRayHit.cr_penHit;
|
|
|
|
|
pbscSector = crRayHit.cr_pbpoBrushPolygon->bpo_pbscSector;
|
|
|
|
|
pbpoPolygon = crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
DiscardShadows( penEntity);
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == SECTOR_MODE)
|
|
|
|
|
{
|
|
|
|
|
DiscardShadows( pbscSector);
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
DiscardShadows( pbpoPolygon);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCopySectorAmbient()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
CBrushSector *pbscHitted = NULL;
|
|
|
|
|
if( (m_penEntityHitOnContext != NULL) &&
|
|
|
|
|
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) &&
|
|
|
|
|
(m_pbpoRightClickedPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
CopySectorAmbient( m_pbpoRightClickedPolygon->bpo_pbscSector);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPasteSectorAmbient()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
CBrushSector *pbscHitted = NULL;
|
|
|
|
|
if( (m_penEntityHitOnContext != NULL) &&
|
|
|
|
|
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) &&
|
|
|
|
|
(m_pbpoRightClickedPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
PasteSectorAmbient( m_pbpoRightClickedPolygon->bpo_pbscSector);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectAllPolygons( void)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
CBrushSector *pbscHitted = NULL;
|
|
|
|
|
if( (m_penEntityHitOnContext != NULL) &&
|
|
|
|
|
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) &&
|
|
|
|
|
(m_pbpoRightClickedPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
pbscHitted = m_pbpoRightClickedPolygon->bpo_pbscSector;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( (pbscHitted == NULL) || pbscHitted->IsSelected( BSCF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
if( !itbpo->IsSelected(BPOF_SELECTED)) pDoc->m_selPolygonSelection.Select( *itbpo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FOREACHINSTATICARRAY(pbscHitted->bsc_abpoPolygons, CBrushPolygon, itpo)
|
|
|
|
|
{
|
|
|
|
|
if( !itpo->IsSelected(BPOF_SELECTED)) pDoc->m_selPolygonSelection.Select( *itpo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetEditingMode( POLYGON_MODE);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectAllVertices()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
CBrushPolygon *pbpoHitted = NULL;
|
|
|
|
|
if( (m_penEntityHitOnContext != NULL) &&
|
|
|
|
|
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) &&
|
|
|
|
|
(m_pbpoRightClickedPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
pbpoHitted = m_pbpoRightClickedPolygon;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( (pbpoHitted == NULL) || pbpoHitted->IsSelected( BPOF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
FOREACHINSTATICARRAY(itbpo->bpo_apbvxTriangleVertices, CBrushVertex *, itpbvx)
|
|
|
|
|
{
|
|
|
|
|
if( !(*itpbvx)->IsSelected(BVXF_SELECTED)) pDoc->m_selVertexSelection.Select( **itpbvx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FOREACHINSTATICARRAY(pbpoHitted->bpo_apbvxTriangleVertices, CBrushVertex *, itpbvx)
|
|
|
|
|
{
|
|
|
|
|
if( !(*itpbvx)->IsSelected(BVXF_SELECTED)) pDoc->m_selVertexSelection.Select( **itpbvx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetEditingMode( VERTEX_MODE);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCopySectors()
|
|
|
|
|
{
|
|
|
|
|
OnEditCopy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPasteSectors()
|
|
|
|
|
{
|
|
|
|
|
OnEditPaste();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDeleteSectors()
|
|
|
|
|
{
|
|
|
|
|
OnDeleteEntities();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::GetToolTipText( char *pToolTipText)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CPoint CursorPos;
|
|
|
|
|
::GetCursorPos(&CursorPos);
|
|
|
|
|
ScreenToClient(&CursorPos);
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
BOOL bHitModels = pDoc->GetEditingMode() != POLYGON_MODE;
|
|
|
|
|
BOOL bHitFields = pDoc->GetEditingMode() == ENTITY_MODE;
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse, FALSE, bHitModels, bHitFields);
|
|
|
|
|
CEntity *penEntity = crRayHit.cr_penHit;
|
|
|
|
|
CBrushPolygon *pbpoPolygon = crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
CBrushSector *pbscSector = NULL;
|
|
|
|
|
if( pbpoPolygon != NULL) pbscSector = crRayHit.cr_pbpoBrushPolygon->bpo_pbscSector;
|
|
|
|
|
char *pchrCursor = pToolTipText;
|
|
|
|
|
INDEX iLongestLineLetters = 1;
|
|
|
|
|
|
|
|
|
|
CDLLEntityClass *pdecDLLClass;
|
|
|
|
|
if( (pDoc->GetEditingMode() == ENTITY_MODE) && (penEntity != NULL))
|
|
|
|
|
{
|
|
|
|
|
// get description line for all properties with name
|
|
|
|
|
pdecDLLClass = penEntity->GetClass()->ec_pdecDLLClass;
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "Class: %-24.24s\n", pdecDLLClass->dec_strName);
|
|
|
|
|
INDEX ctLetters = strlen("Class: ")+strlen(pdecDLLClass->dec_strName);
|
|
|
|
|
memset(pchrCursor, '<EFBFBD>', ctLetters);
|
|
|
|
|
pchrCursor+=ctLetters;
|
|
|
|
|
*pchrCursor = '\n';
|
|
|
|
|
pchrCursor++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INDEX ctMips = 0;
|
|
|
|
|
INDEX iMipIndex = 0;
|
|
|
|
|
INDEX ctEntities = 0;
|
|
|
|
|
INDEX ctSectors = 0;
|
|
|
|
|
INDEX ctPolygons = 0;
|
|
|
|
|
INDEX ctEdges = 0;
|
|
|
|
|
INDEX ctVertices = 0;
|
|
|
|
|
INDEX ctPlanes = 0;
|
|
|
|
|
|
|
|
|
|
// see if info should apply to whole selection
|
|
|
|
|
BOOL bCountSelection = TRUE;
|
|
|
|
|
if( (pDoc->GetEditingMode() == ENTITY_MODE) &&
|
|
|
|
|
(penEntity != NULL) &&
|
|
|
|
|
(!penEntity->IsSelected( ENF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
bCountSelection = FALSE;
|
|
|
|
|
}
|
|
|
|
|
if( (pDoc->GetEditingMode() == POLYGON_MODE) &&
|
|
|
|
|
(pbpoPolygon != NULL) &&
|
|
|
|
|
(!pbpoPolygon->IsSelected( BPOF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
bCountSelection = FALSE;
|
|
|
|
|
}
|
|
|
|
|
if( (pDoc->GetEditingMode() == SECTOR_MODE) &&
|
|
|
|
|
(pbscSector != NULL) &&
|
|
|
|
|
(!pbscSector->IsSelected( BSCF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
bCountSelection = FALSE;
|
|
|
|
|
}
|
|
|
|
|
if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
CTerrain *ptrTerrain=GetTerrain();
|
|
|
|
|
if(ptrTerrain!=NULL)
|
|
|
|
|
{
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%-24s %g x %g x %g\n%-24s %d x %d\n%-24s %d x %d\n%-24s %d x %d\n%-24s %d\n%-24s %d\n%-24s %g\n",
|
|
|
|
|
"Terrain size", ptrTerrain->tr_vTerrainSize(1),ptrTerrain->tr_vTerrainSize(2),ptrTerrain->tr_vTerrainSize(3),
|
|
|
|
|
"Height map size", ptrTerrain->tr_pixHeightMapWidth, ptrTerrain->tr_pixHeightMapHeight,
|
|
|
|
|
"Shadow map size", ptrTerrain->GetShadowMapWidth(), ptrTerrain->GetShadowMapHeight(),
|
|
|
|
|
"Model shading map size", ptrTerrain->GetShadingMapWidth(), ptrTerrain->GetShadingMapHeight(),
|
|
|
|
|
"Layers", ptrTerrain->tr_atlLayers.Count(),
|
|
|
|
|
"Tiles", ptrTerrain->tr_ctTiles,
|
|
|
|
|
"LOD switch distance", ptrTerrain->tr_fDistFactor);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "Terrain not selected\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
if( (bCountSelection && iten->IsSelected( ENF_SELECTED)) ||
|
|
|
|
|
(!bCountSelection && (iten ==penEntity)) )
|
|
|
|
|
{
|
|
|
|
|
ctEntities ++;
|
|
|
|
|
CEntity::RenderType rt = iten->GetRenderType();
|
|
|
|
|
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
|
|
|
|
|
{
|
|
|
|
|
CBrush3D *pBrush3D = iten->GetBrush();
|
|
|
|
|
if(pBrush3D != NULL)
|
|
|
|
|
{
|
|
|
|
|
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
|
|
|
|
|
CBrush3D *pbrBrush = iten->GetBrush();
|
|
|
|
|
if( pbrBrush != NULL)
|
|
|
|
|
{
|
|
|
|
|
CBrushMip *pbmCurrentMip = pbrBrush->GetBrushMipByDistance( fCurrentMipFactor);
|
|
|
|
|
if( pbmCurrentMip != NULL)
|
|
|
|
|
{
|
|
|
|
|
ctSectors += pbmCurrentMip->bm_abscSectors.Count();
|
|
|
|
|
FOREACHINDYNAMICARRAY(pbmCurrentMip->bm_abscSectors, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
ctPolygons += itbsc->bsc_abpoPolygons.Count();
|
|
|
|
|
ctEdges += itbsc->bsc_abedEdges.Count();
|
|
|
|
|
ctVertices+= itbsc->bsc_abvxVertices.Count();
|
|
|
|
|
ctPlanes += itbsc->bsc_abplPlanes.Count();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d\n",
|
|
|
|
|
"No of entities:", ctEntities,
|
|
|
|
|
"No of sectors:", ctSectors,
|
|
|
|
|
"No of polygons:", ctPolygons,
|
|
|
|
|
"No of edges:", ctEdges,
|
|
|
|
|
"No of vertices:", ctVertices,
|
|
|
|
|
"No of planes:", ctPlanes);
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%s\n", "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
|
|
|
|
|
|
|
|
|
if( !bCountSelection)
|
|
|
|
|
{
|
|
|
|
|
CEntity::RenderType rt = penEntity->GetRenderType();
|
|
|
|
|
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
|
|
|
|
|
{
|
|
|
|
|
CBrush3D *pBrush3D = penEntity->GetBrush();
|
|
|
|
|
if(pBrush3D != NULL)
|
|
|
|
|
{
|
|
|
|
|
INDEX iMip = 0;
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, pBrush3D->br_lhBrushMips, itbm)
|
|
|
|
|
{
|
|
|
|
|
FLOAT fMipSwitchDistance = itbm->GetMipDistance();
|
|
|
|
|
CTString strTmp;
|
|
|
|
|
strTmp.PrintF("Mip %d is visible until ", iMip);
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%-24s %g m\n", strTmp, fMipSwitchDistance);
|
|
|
|
|
iMip++;
|
|
|
|
|
}
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%s\n", "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
if( bCountSelection)
|
|
|
|
|
{
|
|
|
|
|
INDEX ctEdges = 0;
|
|
|
|
|
ULONG ulShadowMemory = 0;
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
ctEdges += itbpo->bpo_abpePolygonEdges.Count();
|
|
|
|
|
ulShadowMemory += itbpo->bpo_smShadowMap.GetShadowSize();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "Selection has %d polygons with %d edges\n", pDoc->m_selPolygonSelection.Count(), ctEdges);
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "Shadows on selected polygons occupy %g kb\n", ulShadowMemory/1024.0f);
|
|
|
|
|
}
|
|
|
|
|
if( pbpoPolygon != NULL)
|
|
|
|
|
{
|
|
|
|
|
CTextureData *ptd;
|
|
|
|
|
#define SET_MAPPING_INFO(mp, tex_name)\
|
|
|
|
|
ptd = (CTextureData*) mp.bpt_toTexture.GetData();\
|
|
|
|
|
if( ptd == NULL) pchrCursor += sprintf(pchrCursor, "%-24s None\n", tex_name);\
|
|
|
|
|
else {\
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%-24s %.64s %s\n", tex_name, CTString(ptd->GetName()),\
|
|
|
|
|
ptd->GetDescription() );\
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%-24s %s %s\n", " ",\
|
|
|
|
|
"Scroll: \""+pDoc->m_woWorld.wo_attTextureTransformations[mp.s.bpt_ubScroll].tt_strName+"\"",\
|
|
|
|
|
"Blend: \""+pDoc->m_woWorld.wo_atbTextureBlendings[mp.s.bpt_ubBlend].tb_strName+"\"");}
|
|
|
|
|
|
|
|
|
|
CBrushPolygon &bpo = *crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
SET_MAPPING_INFO( bpo.bpo_abptTextures[0], "Texture 1");
|
|
|
|
|
SET_MAPPING_INFO( bpo.bpo_abptTextures[1], "Texture 2");
|
|
|
|
|
SET_MAPPING_INFO( bpo.bpo_abptTextures[2], "Texture 3");
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "Polygon under mouse has %d edges\n", bpo.bpo_abpePolygonEdges.Count());
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "Shadow on polygon under mouse occupies %g kb\n", bpo.bpo_smShadowMap.GetShadowSize()/1024.0f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( pDoc->GetEditingMode() == SECTOR_MODE)
|
|
|
|
|
{
|
|
|
|
|
if( bCountSelection)
|
|
|
|
|
{
|
|
|
|
|
ctSectors = pDoc->m_selSectorSelection.Count();
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
ctPolygons += itbsc->bsc_abpoPolygons.Count();
|
|
|
|
|
ctEdges += itbsc->bsc_abedEdges.Count();
|
|
|
|
|
ctVertices+= itbsc->bsc_abvxVertices.Count();
|
|
|
|
|
ctPlanes += itbsc->bsc_abplPlanes.Count();
|
|
|
|
|
}
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d\n%",
|
|
|
|
|
"No of sectors:", ctSectors,
|
|
|
|
|
"No of polygons:", ctPolygons,
|
|
|
|
|
"No of edges:", ctEdges,
|
|
|
|
|
"No of vertices:", ctVertices,
|
|
|
|
|
"No of planes:", ctPlanes);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ctPolygons = pbscSector->bsc_abpoPolygons.Count();
|
|
|
|
|
ctEdges = pbscSector->bsc_abedEdges.Count();
|
|
|
|
|
ctVertices = pbscSector->bsc_abvxVertices.Count();
|
|
|
|
|
ctPlanes = pbscSector->bsc_abplPlanes.Count();
|
|
|
|
|
|
|
|
|
|
UBYTE ubR, ubG, ubB;
|
|
|
|
|
UBYTE ubH, ubS, ubV;
|
|
|
|
|
ColorToRGB( pbscSector->bsc_colAmbient, ubR, ubG, ubB);
|
|
|
|
|
ColorToHSV( pbscSector->bsc_colAmbient, ubH, ubS, ubV);
|
|
|
|
|
CTString strSectorName = pbscSector->bsc_strName;
|
|
|
|
|
if( strSectorName == "") strSectorName = "<not defined>";
|
|
|
|
|
|
|
|
|
|
INDEX iContentType = pbscSector->GetContentType();
|
|
|
|
|
CTString strContentType = pDoc->m_woWorld.wo_actContentTypes[iContentType].ct_strName;
|
|
|
|
|
if( strContentType == "") strContentType = "<not defined>";
|
|
|
|
|
|
|
|
|
|
INDEX iEnvironmentType = pbscSector->GetEnvironmentType();
|
|
|
|
|
CTString strEnvironmentType = pDoc->m_woWorld.wo_aetEnvironmentTypes[iEnvironmentType].et_strName;
|
|
|
|
|
if( strEnvironmentType == "") strEnvironmentType = "<not defined>";
|
|
|
|
|
|
|
|
|
|
INDEX iForceType = pbscSector->GetForceType();
|
|
|
|
|
CBrush3D *pbrBrush = pbscSector->bsc_pbmBrushMip->bm_pbrBrush;
|
|
|
|
|
CTString strForceType = pbrBrush->br_penEntity->GetForceName( iForceType);
|
|
|
|
|
if( strForceType == "") strForceType = "<not defined>";
|
|
|
|
|
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%-24.24s %.64s\n%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d\n%-24s"
|
|
|
|
|
"(R=%d G=%d B=%d) (H=%d S=%d V=%d)\n%-24.24s %.64s\n%-24.24s %.64s\n%-24.24s %.64s\n",
|
|
|
|
|
"Name:", strSectorName,
|
|
|
|
|
"No of polygons:", ctPolygons,
|
|
|
|
|
"No of edges:", ctEdges,
|
|
|
|
|
"No of vertices:", ctVertices,
|
|
|
|
|
"No of planes:", ctPlanes,
|
|
|
|
|
"Ambient color:", ubR, ubG, ubB, ubH, ubS, ubV,
|
|
|
|
|
"Content type:", strContentType,
|
|
|
|
|
"Environment type:", strEnvironmentType,
|
|
|
|
|
"Force type:", strForceType);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( pDoc->GetEditingMode() == CSG_MODE)
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_pwoSecondLayer->wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CEntity::RenderType rt = iten->GetRenderType();
|
|
|
|
|
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
|
|
|
|
|
{
|
|
|
|
|
CBrush3D *pBrush3D = iten->GetBrush();
|
|
|
|
|
if( pBrush3D != NULL)
|
|
|
|
|
{
|
|
|
|
|
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
|
|
|
|
|
CBrush3D *pbrBrush = iten->GetBrush();
|
|
|
|
|
if( pbrBrush != NULL)
|
|
|
|
|
{
|
|
|
|
|
CBrushMip *pbmCurrentMip = pbrBrush->GetBrushMipByDistance( fCurrentMipFactor);
|
|
|
|
|
if( pbmCurrentMip != NULL)
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICARRAY(pbmCurrentMip->bm_abscSectors, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
ctPolygons += itbsc->bsc_abpoPolygons.Count();
|
|
|
|
|
ctEdges += itbsc->bsc_abedEdges.Count();
|
|
|
|
|
ctVertices+= itbsc->bsc_abvxVertices.Count();
|
|
|
|
|
ctPlanes += itbsc->bsc_abplPlanes.Count();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "Primitive info:\n<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\n%-24s %d\n%-24s %d\n%-24s %d\n%-24s %d",
|
|
|
|
|
"No of polygons:", ctPolygons,
|
|
|
|
|
"No of edges:", ctEdges,
|
|
|
|
|
"No of vertices:", ctVertices,
|
|
|
|
|
"No of planes:", ctPlanes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( (pDoc->GetEditingMode() == ENTITY_MODE) && (penEntity!=NULL) )
|
|
|
|
|
{
|
|
|
|
|
// add count of occupiing sectors and their names
|
|
|
|
|
INDEX ctIntersectingSectors = penEntity->en_rdSectors.Count();
|
|
|
|
|
INDEX ctWithName = 0;
|
|
|
|
|
{FOREACHSRCOFDST(penEntity->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
|
|
|
|
|
if( pbsc->bsc_strName != "") ctWithName++;
|
|
|
|
|
ENDFOR}
|
|
|
|
|
INDEX ctLetters = sprintf(pchrCursor, "In %d sectors (%d with name):\n", ctIntersectingSectors, ctWithName);
|
|
|
|
|
if( ctLetters > iLongestLineLetters) iLongestLineLetters = ctLetters;
|
|
|
|
|
pchrCursor += ctLetters;
|
|
|
|
|
{FOREACHSRCOFDST(penEntity->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
|
|
|
|
|
if( pbsc->bsc_strName != "")
|
|
|
|
|
{
|
|
|
|
|
INDEX ctLetters = sprintf(pchrCursor, "In: %-24.24s\n", pbsc->bsc_strName);
|
|
|
|
|
if( ctLetters > iLongestLineLetters) iLongestLineLetters = ctLetters;
|
|
|
|
|
pchrCursor += ctLetters;
|
|
|
|
|
}
|
|
|
|
|
ENDFOR}
|
|
|
|
|
|
|
|
|
|
for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
|
|
|
|
|
{
|
|
|
|
|
CTString strValue;
|
|
|
|
|
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
|
|
|
|
|
{
|
|
|
|
|
CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
|
|
|
|
|
if( epProperty.ep_strName == CTString("")) continue;
|
|
|
|
|
strValue = "!!! Unkown property type";
|
|
|
|
|
switch( epProperty.ep_eptType)
|
|
|
|
|
{
|
|
|
|
|
case CEntityProperty::EPT_FLAGS:
|
|
|
|
|
{
|
|
|
|
|
strValue = "Flag array property";
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_ENUM:
|
|
|
|
|
{
|
|
|
|
|
INDEX iCurrentEnum = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, INDEX);
|
|
|
|
|
CEntityPropertyEnumType *epEnum = epProperty.ep_pepetEnumType;
|
|
|
|
|
for( INDEX iEnum = 0; iEnum< epEnum->epet_ctValues; iEnum++)
|
|
|
|
|
{
|
|
|
|
|
INDEX iEnumID = epEnum->epet_aepevValues[ iEnum].epev_iValue;
|
|
|
|
|
if( iEnumID == iCurrentEnum)
|
|
|
|
|
strValue = (epEnum->epet_aepevValues[ iEnum].epev_strName);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_BOOL:
|
|
|
|
|
{
|
|
|
|
|
if( ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, BOOL))strValue = "TRUE";
|
|
|
|
|
else strValue = "FALSE";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_FLOAT:
|
|
|
|
|
{
|
|
|
|
|
strValue.PrintF( "%g", ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, FLOAT));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_RANGE:
|
|
|
|
|
{
|
|
|
|
|
strValue.PrintF( "%g m", ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, FLOAT));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_COLOR:
|
|
|
|
|
{
|
|
|
|
|
COLOR colColor = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, COLOR);
|
|
|
|
|
UBYTE ubR, ubG, ubB, ubA;
|
|
|
|
|
UBYTE ubH, ubS, ubV;
|
|
|
|
|
ubA=colColor&0xFF;
|
|
|
|
|
ColorToRGB( colColor, ubR, ubG, ubB);
|
|
|
|
|
ColorToHSV( colColor, ubH, ubS, ubV);
|
|
|
|
|
strValue.PrintF( "RGBA(%d,%d,%d,%d) HSV(%d,%d,%d)", ubR,ubG,ubB,ubA,ubH,ubS,ubV);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_STRING:
|
|
|
|
|
case CEntityProperty::EPT_STRINGTRANS:
|
|
|
|
|
case CEntityProperty::EPT_FILENAMENODEP:
|
|
|
|
|
{
|
|
|
|
|
strValue = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, CTString);
|
|
|
|
|
if( strValue == "") strValue = "<no value>";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_ENTITYPTR:
|
|
|
|
|
{
|
|
|
|
|
CEntity *pen=ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, CEntity *);
|
|
|
|
|
if( pen == NULL) strValue = "-> None";
|
|
|
|
|
else strValue = "-> "+pen->GetName();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_PARENT:
|
|
|
|
|
{
|
|
|
|
|
CEntity *pen=penEntity->GetParent();
|
|
|
|
|
if( pen == NULL) strValue = "-> None";
|
|
|
|
|
else strValue = "-> "+pen->GetName();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_FILENAME:
|
|
|
|
|
{
|
|
|
|
|
strValue = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, CTFileName);
|
|
|
|
|
if( strValue == "") strValue = "<no file>";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_INDEX:
|
|
|
|
|
case CEntityProperty::EPT_ANGLE:
|
|
|
|
|
{
|
|
|
|
|
strValue.PrintF( "%d", ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, INDEX) );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_ANIMATION:
|
|
|
|
|
{
|
|
|
|
|
CAnimData *pAD = penEntity->GetAnimData( epProperty.ep_slOffset);
|
|
|
|
|
if( pAD == NULL)
|
|
|
|
|
{
|
|
|
|
|
strValue = "<no animation>";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CAnimInfo aiInfo;
|
|
|
|
|
INDEX iAnimation = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, INDEX);
|
|
|
|
|
pAD->GetAnimInfo( iAnimation, aiInfo);
|
|
|
|
|
strValue = aiInfo.ai_AnimName;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_ILLUMINATIONTYPE:
|
|
|
|
|
{
|
|
|
|
|
INDEX iIllumination = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, INDEX);
|
|
|
|
|
strValue = pDoc->m_woWorld.wo_aitIlluminationTypes[iIllumination].it_strName;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_FLOATAABBOX3D:
|
|
|
|
|
{
|
|
|
|
|
FLOATaabbox3D bbox = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, FLOATaabbox3D);
|
|
|
|
|
FLOAT3D vMin = bbox.Min();
|
|
|
|
|
FLOAT3D vMax = bbox.Max();
|
|
|
|
|
strValue.PrintF( "Min(%g,%g,%g), Max(%g,%g,%g)",
|
|
|
|
|
vMin(1), vMin(2), vMin(3), vMax(1), vMax(2), vMax(3));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_FLOAT3D:
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D vVector = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, FLOAT3D);
|
|
|
|
|
strValue.PrintF( "%g,%g,%g", vVector(1), vVector(2), vVector(3));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CEntityProperty::EPT_ANGLE3D:
|
|
|
|
|
{
|
|
|
|
|
ANGLE3D aAngle = ENTITYPROPERTY( &*penEntity, epProperty.ep_slOffset, ANGLE3D);
|
|
|
|
|
strValue.PrintF( "%g,%g,%g", DegAngle(aAngle(1)), DegAngle(aAngle(2)), DegAngle(aAngle(3)));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
INDEX ctLetters = sprintf(pchrCursor, "%-24.24s %.64s \n", epProperty.ep_strName, strValue);
|
|
|
|
|
if( ctLetters > iLongestLineLetters) iLongestLineLetters = ctLetters;
|
|
|
|
|
pchrCursor += ctLetters;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( iLongestLineLetters>2)
|
|
|
|
|
{
|
|
|
|
|
iLongestLineLetters-=2;
|
|
|
|
|
memset(pchrCursor, '_', iLongestLineLetters);
|
|
|
|
|
pchrCursor+=iLongestLineLetters;
|
|
|
|
|
*pchrCursor = '\n';
|
|
|
|
|
pchrCursor++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( penEntity->GetParent() != NULL)
|
|
|
|
|
{
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "Parent: %s\n", penEntity->GetParent()->GetName());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "No parent\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CTString strSpawn = "";
|
|
|
|
|
ULONG ulSpawn = penEntity->GetSpawnFlags();
|
|
|
|
|
ULONG ulAllways = SPF_EASY|SPF_NORMAL|SPF_HARD|SPF_EXTREME|SPF_SINGLEPLAYER|SPF_COOPERATIVE|SPF_DEATHMATCH;
|
|
|
|
|
if( (ulSpawn & ulAllways) == ulAllways)
|
|
|
|
|
{
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%s", "Entity exists allways");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if( ulSpawn & SPF_EASY) strSpawn+="Easy,";
|
|
|
|
|
if( ulSpawn & SPF_NORMAL) strSpawn+="Normal,";
|
|
|
|
|
if( ulSpawn & SPF_HARD) strSpawn+="Hard,";
|
|
|
|
|
if( ulSpawn & SPF_EXTREME) strSpawn+="Extreme,";
|
|
|
|
|
if( ulSpawn & SPF_SINGLEPLAYER) strSpawn+="Single,";
|
|
|
|
|
if( ulSpawn & SPF_COOPERATIVE) strSpawn+="Cooperative,";
|
|
|
|
|
if( ulSpawn & SPF_DEATHMATCH) strSpawn+="Deathmatch,";
|
|
|
|
|
if( strSpawn != "")
|
|
|
|
|
{
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%s", strSpawn);
|
|
|
|
|
*(pchrCursor-1) = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%s", "Does not exist acording to spawn flags");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( pDoc->GetEditingMode() == VERTEX_MODE)
|
|
|
|
|
{
|
|
|
|
|
pchrCursor += sprintf(pchrCursor, "%d %s", pDoc->m_selVertexSelection.Count(), "vertices");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnMenuCopyMapping()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
ASSERT( m_pbpoRightClickedPolygon != NULL);
|
|
|
|
|
CopyMapping(m_pbpoRightClickedPolygon);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyPaste()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_PAINT;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
pDoc->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// paste mapping
|
|
|
|
|
PasteMapping( crRayHit.cr_pbpoBrushPolygon, FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyPasteAsProjected()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
// paste mapping
|
|
|
|
|
PasteMapping( crRayHit.cr_pbpoBrushPolygon, TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnMenuPasteMapping()
|
|
|
|
|
{
|
|
|
|
|
PasteMapping( m_pbpoRightClickedPolygon, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnMenuPasteAsProjectedMapping()
|
|
|
|
|
{
|
|
|
|
|
PasteMapping( m_pbpoRightClickedPolygon, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::CopyMapping(CBrushPolygon *pbpo)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
ASSERT(pbpo!=NULL);
|
|
|
|
|
CBrushPlane *pbpl = pbpo->bpo_pbplPlane;
|
|
|
|
|
CEntity *pen = pbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
|
|
|
|
|
ASSERT(pen!=NULL);
|
|
|
|
|
// get the mapping in absolute space
|
|
|
|
|
theApp.m_mdMapping = pbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
|
|
|
|
|
theApp.m_mdMapping.Transform(pbpl->bpl_plRelative, pen->GetPlacement(), _plOrigin);
|
|
|
|
|
theApp.m_plMapping = pbpl->bpl_plAbsolute;
|
|
|
|
|
|
|
|
|
|
theApp.m_mdMapping1 = pbpo->bpo_abptTextures[0].bpt_mdMapping;
|
|
|
|
|
theApp.m_mdMapping1.Transform(pbpl->bpl_plRelative, pen->GetPlacement(), _plOrigin);
|
|
|
|
|
theApp.m_plMapping1 = pbpl->bpl_plAbsolute;
|
|
|
|
|
theApp.m_mdMapping2 = pbpo->bpo_abptTextures[1].bpt_mdMapping;
|
|
|
|
|
theApp.m_mdMapping2.Transform(pbpl->bpl_plRelative, pen->GetPlacement(), _plOrigin);
|
|
|
|
|
theApp.m_plMapping2 = pbpl->bpl_plAbsolute;
|
|
|
|
|
theApp.m_mdMapping3 = pbpo->bpo_abptTextures[2].bpt_mdMapping;
|
|
|
|
|
theApp.m_mdMapping3.Transform(pbpl->bpl_plRelative, pen->GetPlacement(), _plOrigin);
|
|
|
|
|
theApp.m_plMapping3 = pbpl->bpl_plAbsolute;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::PasteMappingOnOnePolygon(CBrushPolygon *pbpo, BOOL bAsProjected)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
PasteOneLayerMapping(pDoc->m_iTexture, theApp.m_mdMapping, theApp.m_plMapping, pbpo, bAsProjected);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::PasteOneLayerMapping(INDEX iLayer, CMappingDefinition &md,
|
|
|
|
|
FLOATplane3D &pl, CBrushPolygon *pbpo, BOOL bAsProjected)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
// get the mapping in relative space of the brush polygon's entity
|
|
|
|
|
CEntity *pen = pbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
|
|
|
|
|
CSimpleProjection3D pr;
|
|
|
|
|
pr.ObjectPlacementL() = _plOrigin;
|
|
|
|
|
pr.ViewerPlacementL() = pen->GetPlacement();
|
|
|
|
|
pr.Prepare();
|
|
|
|
|
FLOATplane3D plRelative;
|
|
|
|
|
pr.Project(pl, plRelative);
|
|
|
|
|
CMappingDefinition mdRelative = md;
|
|
|
|
|
mdRelative.Transform(pl, _plOrigin, pen->GetPlacement());
|
|
|
|
|
|
|
|
|
|
// paste the mapping
|
|
|
|
|
if( bAsProjected)
|
|
|
|
|
{
|
|
|
|
|
pbpo->bpo_abptTextures[iLayer].bpt_mdMapping.ProjectMapping(
|
|
|
|
|
plRelative, mdRelative, pbpo->bpo_pbplPlane->bpl_plRelative);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pbpo->bpo_abptTextures[iLayer].bpt_mdMapping = mdRelative;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::PasteMapping(CBrushPolygon *pbpo, BOOL bAsProjected)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
// paste mapping over selection if clicked polygon is selected
|
|
|
|
|
if( (pbpo == NULL) || (pbpo->IsSelected( BPOF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
PasteMappingOnOnePolygon(itbpo, bAsProjected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PasteMappingOnOnePolygon(pbpo, bAsProjected);
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectAllEntitiesInSectors()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
CBrushSector *pbscHitted = NULL;
|
|
|
|
|
if( (m_penEntityHitOnContext != NULL) &&
|
|
|
|
|
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) &&
|
|
|
|
|
(m_pbpoRightClickedPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
pbscHitted = m_pbpoRightClickedPolygon->bpo_pbscSector;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if right clicked on nothing or selected sector
|
|
|
|
|
if( (pbscHitted == NULL) || pbscHitted->IsSelected( BSCF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
{FOREACHDSTOFSRC(itbsc->bsc_rsEntities, CEntity, en_rdSectors, pen)
|
|
|
|
|
if( !pen->IsSelected( ENF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *pen);
|
|
|
|
|
}
|
|
|
|
|
ENDFOR}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
{FOREACHDSTOFSRC(pbscHitted->bsc_rsEntities, CEntity, en_rdSectors, pen)
|
|
|
|
|
if( !pen->IsSelected( ENF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *pen);
|
|
|
|
|
}
|
|
|
|
|
ENDFOR}
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetEditingMode( ENTITY_MODE);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectAllSectors()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
if( m_penEntityHitOnContext == NULL)
|
|
|
|
|
{
|
|
|
|
|
// in all entities in world
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CEntity::RenderType rt = iten->GetRenderType();
|
|
|
|
|
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
|
|
|
|
|
{
|
|
|
|
|
// for each mip in its brush
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->GetBrush()->br_lhBrushMips, itbm)
|
|
|
|
|
{
|
|
|
|
|
// for all sectors in this mip
|
|
|
|
|
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
// if sector is not hidden and not selected
|
|
|
|
|
if( !(itbsc->bsc_ulFlags & BSCF_HIDDEN) && !itbsc->IsSelected( BSCF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *itbsc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// perform select sectors on whole entity selection
|
|
|
|
|
else if( m_penEntityHitOnContext->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CEntity::RenderType rt = iten->GetRenderType();
|
|
|
|
|
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
|
|
|
|
|
{
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->GetBrush()->br_lhBrushMips, itbm)
|
|
|
|
|
{
|
|
|
|
|
// for all sectors in this mip
|
|
|
|
|
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
// if sector is not hidden and not selected
|
|
|
|
|
if( !(itbsc->bsc_ulFlags & BSCF_HIDDEN) && !itbsc->IsSelected( BSCF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *itbsc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH)
|
|
|
|
|
{
|
|
|
|
|
// select all sectors in all mip levels
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, m_penEntityHitOnContext->GetBrush()->br_lhBrushMips, itbm)
|
|
|
|
|
{
|
|
|
|
|
// select all sectors in current mip
|
|
|
|
|
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
if( !(itbsc->bsc_ulFlags & BSCF_HIDDEN) && !itbsc->IsSelected( BSCF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *itbsc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetEditingMode( SECTOR_MODE);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::CenterSelected(void)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CPropertyID *ppidProperty = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
|
|
|
|
|
// bounding box of visible sectors
|
|
|
|
|
FLOATaabbox3D boxBoundingBox;
|
|
|
|
|
if( pDoc->GetEditingMode() == ENTITY_MODE && (pDoc->m_selEntitySelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D vPos = iten->GetPlacement().pl_PositionVector;
|
|
|
|
|
FLOATaabbox3D boxEntity;
|
|
|
|
|
|
|
|
|
|
if( (ppidProperty != NULL) && (ppidProperty->pid_eptType == CEntityProperty::EPT_RANGE))
|
|
|
|
|
{
|
|
|
|
|
// obtain property ptr
|
|
|
|
|
CEntityProperty *penpProperty = iten->PropertyForName( ppidProperty->pid_strName);
|
|
|
|
|
// get editing range
|
|
|
|
|
FLOAT fRange = ENTITYPROPERTY( &*iten, penpProperty->ep_slOffset, FLOAT);
|
|
|
|
|
boxEntity |= FLOATaabbox3D( FLOAT3D(0.0f, 0.0f ,0.0f), fRange);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
iten->GetSize( boxEntity);
|
|
|
|
|
}
|
|
|
|
|
boxEntity+=vPos;
|
|
|
|
|
boxBoundingBox |= boxEntity;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
CTerrain *ptrTerrain=GetTerrain();
|
|
|
|
|
if(ptrTerrain!=NULL)
|
|
|
|
|
{
|
|
|
|
|
ptrTerrain->GetAllTerrainBBox(boxBoundingBox);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == POLYGON_MODE && (pDoc->m_selPolygonSelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
boxBoundingBox |= itbpo->bpo_boxBoundingBox;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == SECTOR_MODE && (pDoc->m_selSectorSelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
boxBoundingBox |= itbsc->bsc_boxBoundingBox;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( (pDoc->GetEditingMode() == VERTEX_MODE) && (pDoc->m_selVertexSelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selVertexSelection, CBrushVertex, itbvtx)
|
|
|
|
|
{
|
|
|
|
|
FLOATaabbox3D boxVtxBox = FLOATaabbox3D( itbvtx->bvx_vAbsolute);
|
|
|
|
|
boxVtxBox.Expand( 20);
|
|
|
|
|
boxBoundingBox |= boxVtxBox;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CEntity::RenderType rt = iten->GetRenderType();
|
|
|
|
|
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
|
|
|
|
|
{
|
|
|
|
|
// for each mip in its brush
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->GetBrush()->br_lhBrushMips, itbm)
|
|
|
|
|
{
|
|
|
|
|
// for all sectors in this mip
|
|
|
|
|
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
// if sector is not hidden
|
|
|
|
|
if( !(itbsc->bsc_ulFlags & BSCF_HIDDEN))
|
|
|
|
|
{
|
|
|
|
|
boxBoundingBox |= itbsc->bsc_boxBoundingBox;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D vPos = iten->GetPlacement().pl_PositionVector;
|
|
|
|
|
FLOATaabbox3D boxEntity;
|
|
|
|
|
iten->GetSize( boxEntity);
|
|
|
|
|
boxEntity+=vPos;
|
|
|
|
|
boxBoundingBox |= boxEntity;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
AllignBox( boxBoundingBox);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::AllignBox( FLOATaabbox3D bbox)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
CChildFrame *pCF = GetChildFrame();
|
|
|
|
|
FLOAT3D vSize = bbox.Size();
|
|
|
|
|
if( vSize.Length() <= 1.0f)
|
|
|
|
|
vSize = FLOAT3D( 2.0f, 2.0f, 2.0f);
|
|
|
|
|
|
|
|
|
|
// width is alligned inside horizontal borders of draw port, height and lenght
|
|
|
|
|
// are alligned to height of draw port
|
|
|
|
|
FLOAT fDX = (FLOAT)m_pdpDrawPort->GetWidth()*9/10;
|
|
|
|
|
FLOAT fDY = (FLOAT)m_pdpDrawPort->GetHeight()*9/10;
|
|
|
|
|
|
|
|
|
|
FLOAT fWantedZoom = Min( Min( fDX/vSize(1), fDY/vSize(2)), fDY/vSize(3));
|
|
|
|
|
|
|
|
|
|
if( (fWantedZoom>1E-4) && (fWantedZoom<1E4) )
|
|
|
|
|
{
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer(pCF->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid,
|
|
|
|
|
m_pdpDrawPort);
|
|
|
|
|
pCF->m_mvViewer.mv_fTargetDistance = svViewer.GetDistanceForZoom(fWantedZoom);
|
|
|
|
|
pCF->m_mvViewer.SetTargetPlacement( bbox.Center());
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::AllignPolygon( CBrushPolygon *pbpo)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
CChildFrame *pCF = GetChildFrame();
|
|
|
|
|
|
|
|
|
|
FLOATaabbox3D bbox = pbpo->bpo_boxBoundingBox;
|
|
|
|
|
FLOAT3D vSize = bbox.Size();
|
|
|
|
|
if( vSize.Length() <= 1.0f)
|
|
|
|
|
vSize = FLOAT3D( 2.0f, 2.0f, 2.0f);
|
|
|
|
|
|
|
|
|
|
// width is alligned inside horizontal borders of draw port, height and lenght
|
|
|
|
|
// are alligned to height of draw port
|
|
|
|
|
FLOAT fDX = (FLOAT)m_pdpDrawPort->GetWidth()*9/10;
|
|
|
|
|
FLOAT fDY = (FLOAT)m_pdpDrawPort->GetHeight()*9/10;
|
|
|
|
|
|
|
|
|
|
FLOAT fWantedZoom = Min( Min( fDX/vSize(1), fDY/vSize(2)), fDY/vSize(3));
|
|
|
|
|
if( (fWantedZoom>1E-4) && (fWantedZoom<1E4) )
|
|
|
|
|
{
|
|
|
|
|
// create a slave viewer
|
|
|
|
|
CSlaveViewer svViewer(pCF->m_mvViewer, m_ptProjectionType, pDoc->m_plGrid, m_pdpDrawPort);
|
|
|
|
|
pCF->m_mvViewer.mv_fTargetDistance = svViewer.GetDistanceForZoom(fWantedZoom);
|
|
|
|
|
FLOAT3D vDirection = pbpo->bpo_pbplPlane->bpl_plAbsolute;
|
|
|
|
|
DirectionVectorToAngles( -vDirection, pCF->m_mvViewer.mv_plViewer.pl_OrientationAngle);
|
|
|
|
|
pCF->m_mvViewer.SetTargetPlacement( bbox.Center());
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCloneToMorePreciseMip()
|
|
|
|
|
{
|
|
|
|
|
OnAddMorePreciseMip(TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCreateEmptyMorePreciseMip()
|
|
|
|
|
{
|
|
|
|
|
OnAddMorePreciseMip(FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCloneToRougherMipLevel()
|
|
|
|
|
{
|
|
|
|
|
OnAddRougherMipLevel( TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCreateEmptyRougherMip()
|
|
|
|
|
{
|
|
|
|
|
OnAddRougherMipLevel( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAddMorePreciseMip(BOOL bClone)
|
|
|
|
|
{
|
|
|
|
|
// remember current time as time when last mip brushing option has been used
|
|
|
|
|
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->RememberUndo();
|
|
|
|
|
|
|
|
|
|
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
|
|
|
|
|
if (pbmCurrentMip==NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CBrushMip *pbmAdded = pbmCurrentMip->bm_pbrBrush->NewBrushMipBefore(pbmCurrentMip, bClone);
|
|
|
|
|
|
|
|
|
|
GetChildFrame()->m_fManualMipBrushingFactor = pbmAdded->GetMipDistance()-0.01f;
|
|
|
|
|
|
|
|
|
|
// document has changed
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
// set text describing data that is edited
|
|
|
|
|
SetEditingDataPaneInfo( TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAddRougherMipLevel(BOOL bClone)
|
|
|
|
|
{
|
|
|
|
|
// remember current time as time when last mip brushing option has been used
|
|
|
|
|
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->RememberUndo();
|
|
|
|
|
|
|
|
|
|
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
|
|
|
|
|
if (pbmCurrentMip==NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CBrushMip *pbmAdded = pbmCurrentMip->bm_pbrBrush->NewBrushMipAfter(pbmCurrentMip, bClone);
|
|
|
|
|
|
|
|
|
|
GetChildFrame()->m_fManualMipBrushingFactor = pbmAdded->GetMipDistance()-0.01f;
|
|
|
|
|
|
|
|
|
|
// document has changed
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
// set text describing data that is edited
|
|
|
|
|
SetEditingDataPaneInfo( TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get current brush mip of current csg target brush
|
|
|
|
|
CBrushMip *CWorldEditorView::GetCurrentBrushMip(void)
|
|
|
|
|
{
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CEntity *penBrush = pMainFrame->m_CSGDesitnationCombo.GetSelectedBrushEntity();
|
|
|
|
|
if (penBrush==NULL) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
// get entity's brush
|
|
|
|
|
CBrush3D *pbrBrush = penBrush->GetBrush();
|
|
|
|
|
if( pbrBrush == NULL) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
// get currently active mip factor
|
|
|
|
|
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
|
|
|
|
|
|
|
|
|
|
return pbrBrush->GetBrushMipByDistance(fCurrentMipFactor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDeleteMip()
|
|
|
|
|
{
|
|
|
|
|
// remember current time as time when last mip brushing option has been used
|
|
|
|
|
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
|
|
|
|
|
|
|
|
|
|
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
|
|
|
|
|
if (pbmCurrentMip==NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// delete currently visible mip brush
|
|
|
|
|
pbmCurrentMip->bm_pbrBrush->DeleteBrushMip(pbmCurrentMip);
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// document has changed
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
// set text describing data that is edited
|
|
|
|
|
SetEditingDataPaneInfo( TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPreviousMipBrush()
|
|
|
|
|
{
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CEntity *penBrush = pMainFrame->m_CSGDesitnationCombo.GetSelectedBrushEntity();
|
|
|
|
|
|
2016-03-23 18:42:20 +01:00
|
|
|
|
if (penBrush == NULL) return;
|
|
|
|
|
|
|
|
|
|
CBrush3D &brBrush = *penBrush->en_pbrBrush;
|
2016-03-11 14:57:17 +01:00
|
|
|
|
|
|
|
|
|
// remember current time as time when last mip brushing option has been used
|
|
|
|
|
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
|
|
|
|
|
|
|
|
|
|
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
|
|
|
|
|
CBrushMip *pbmPrevMip = NULL;
|
|
|
|
|
|
|
|
|
|
if (pbmCurrentMip==NULL)
|
|
|
|
|
{
|
|
|
|
|
pbmPrevMip = brBrush.GetLastMip();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pbmPrevMip = pbmCurrentMip->GetPrev();
|
|
|
|
|
}
|
|
|
|
|
if (pbmPrevMip==NULL) return;
|
|
|
|
|
|
|
|
|
|
// set manual mip factor to show previous mip brush
|
|
|
|
|
GetChildFrame()->m_fManualMipBrushingFactor = pbmPrevMip->GetMipDistance()-0.01f;
|
|
|
|
|
|
|
|
|
|
// update all views
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
// set text describing data that is edited
|
|
|
|
|
SetEditingDataPaneInfo( TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnNextMipBrush()
|
|
|
|
|
{
|
|
|
|
|
// remember current time as time when last mip brushing option has been used
|
|
|
|
|
_fLastMipBrushingOptionUsed = _pTimer->GetRealTimeTick();
|
|
|
|
|
|
|
|
|
|
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
|
|
|
|
|
if (pbmCurrentMip==NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBrushMip *pbmNextMip = pbmCurrentMip->GetNext();
|
|
|
|
|
if (pbmNextMip==NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set manual mip factor to show next mip brush
|
|
|
|
|
GetChildFrame()->m_fManualMipBrushingFactor = pbmNextMip->GetMipDistance()-0.01f;
|
|
|
|
|
|
|
|
|
|
// update all views
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
// set text describing data that is edited
|
|
|
|
|
SetEditingDataPaneInfo( TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateCloneToMorePreciseMip(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( GetCurrentBrushMip()!=NULL && !GetChildFrame()->m_bAutoMipBrushingOn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateCloneToRougherMipLevel(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( GetCurrentBrushMip()!=NULL && !GetChildFrame()->m_bAutoMipBrushingOn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateCreateEmptyMorePreciseMip(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( GetCurrentBrushMip()!=NULL && !GetChildFrame()->m_bAutoMipBrushingOn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateCreateEmptyRougherMip(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( GetCurrentBrushMip()!=NULL && !GetChildFrame()->m_bAutoMipBrushingOn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateDeleteMip(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CBrushMip *pbm = GetCurrentBrushMip();
|
|
|
|
|
pCmdUI->Enable(
|
|
|
|
|
pbm!=NULL &&
|
|
|
|
|
pbm->bm_pbrBrush->br_lhBrushMips.Count()>1 &&
|
|
|
|
|
!GetChildFrame()->m_bAutoMipBrushingOn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdatePreviousMipBrush(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CBrushMip *pbm = GetCurrentBrushMip();
|
|
|
|
|
pCmdUI->Enable(
|
|
|
|
|
( (pbm==NULL) ||
|
|
|
|
|
(pbm->GetPrev()!=NULL) ) &&
|
|
|
|
|
!GetChildFrame()->m_bAutoMipBrushingOn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateNextMipBrush(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CBrushMip *pbm = GetCurrentBrushMip();
|
|
|
|
|
pCmdUI->Enable(
|
|
|
|
|
pbm!=NULL &&
|
|
|
|
|
pbm->GetNext()!=NULL &&
|
|
|
|
|
!GetChildFrame()->m_bAutoMipBrushingOn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// paste polygon properties but don't paste mapping
|
|
|
|
|
void CWorldEditorView::OnEditPasteAlternative()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
|
|
|
|
|
if( theApp.m_ctLastCopyType == CT_POLYGON_PROPERTIES)
|
|
|
|
|
{
|
|
|
|
|
// if mouse is over polygon
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
if( crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
// apply all parameters from remembered
|
|
|
|
|
itbpo->CopyProperties( *theApp.m_pbpoClipboardPolygon);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// apply all parameters from remembered
|
|
|
|
|
crRayHit.cr_pbpoBrushPolygon->CopyProperties( *theApp.m_pbpoClipboardPolygon);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
if( theApp.m_ctLastCopyType == CT_POLYGON_PROPERTIES_ALTERNATIVE)
|
|
|
|
|
{
|
|
|
|
|
// if mouse is over polygon
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
if( crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
// apply all parameters from remembered
|
|
|
|
|
itbpo->CopyProperties( *theApp.m_pbpoClipboardPolygon);
|
|
|
|
|
PasteOneLayerMapping(0, theApp.m_mdMapping1, theApp.m_plMapping1, &*itbpo, TRUE);
|
|
|
|
|
PasteOneLayerMapping(1, theApp.m_mdMapping2, theApp.m_plMapping2, &*itbpo, TRUE);
|
|
|
|
|
PasteOneLayerMapping(2, theApp.m_mdMapping3, theApp.m_plMapping3, &*itbpo, TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// apply all parameters from remembered
|
|
|
|
|
crRayHit.cr_pbpoBrushPolygon->CopyProperties( *theApp.m_pbpoClipboardPolygon);
|
|
|
|
|
PasteOneLayerMapping(0, theApp.m_mdMapping1, theApp.m_plMapping1, crRayHit.cr_pbpoBrushPolygon, TRUE);
|
|
|
|
|
PasteOneLayerMapping(1, theApp.m_mdMapping2, theApp.m_plMapping2, crRayHit.cr_pbpoBrushPolygon, TRUE);
|
|
|
|
|
PasteOneLayerMapping(2, theApp.m_mdMapping3, theApp.m_plMapping3, crRayHit.cr_pbpoBrushPolygon, TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
else if (theApp.m_ctLastCopyType == CT_ENTITY)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CPlacement3D plPaste = GetMouseInWorldPlacement();
|
|
|
|
|
// load world from clipboard file and start template CSG
|
|
|
|
|
pDoc->StartTemplateCSG( plPaste, (CTString)"Temp\\ClipboardEntityWorld.wld");
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateEditPasteAlternative(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::ToggleHittedPolygon( CCastRay &crRayHit)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( (crRayHit.cr_penHit == NULL) ||
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon == NULL) )
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
// remember if first clicked polygon is to be deselected
|
|
|
|
|
m_bWeDeselectedFirstPolygon = crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED) != 0;
|
|
|
|
|
INDEX ctPolygonsSelectedBefore = pDoc->m_selPolygonSelection.Count();
|
|
|
|
|
// if shift is not pressed
|
|
|
|
|
if( !bShift)
|
|
|
|
|
{
|
|
|
|
|
if( ctPolygonsSelectedBefore>1)
|
|
|
|
|
{
|
|
|
|
|
m_bWeDeselectedFirstPolygon = FALSE;
|
|
|
|
|
}
|
|
|
|
|
// deselect all selected polygons
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
}
|
|
|
|
|
// if we have to deselect first polygon but we didn't deselect it with clear
|
|
|
|
|
if( (m_bWeDeselectedFirstPolygon) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon->IsSelected( BPOF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
// deselect clicked polygon
|
|
|
|
|
pDoc->m_selPolygonSelection.Deselect( *crRayHit.cr_pbpoBrushPolygon);
|
|
|
|
|
}
|
|
|
|
|
// if we must select first polygon
|
|
|
|
|
if( !m_bWeDeselectedFirstPolygon)
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selPolygonSelection.Select( *crRayHit.cr_pbpoBrushPolygon);
|
|
|
|
|
}
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::ToggleHittedSector( CCastRay &crRayHit)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// if any polygon hit toggle or add its sector
|
|
|
|
|
if( (crRayHit.cr_penHit == NULL) ||
|
|
|
|
|
(crRayHit.cr_pbscBrushSector == NULL) )
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
// remember if first clicked sector is to be deselected
|
|
|
|
|
m_bWeDeselectedFirstSector = crRayHit.cr_pbscBrushSector->IsSelected( BSCF_SELECTED) != 0;
|
|
|
|
|
INDEX ctSectorsSelectedBefore = pDoc->m_selSectorSelection.Count();
|
|
|
|
|
// if shift is not pressed
|
|
|
|
|
if( !bShift)
|
|
|
|
|
{
|
|
|
|
|
if( ctSectorsSelectedBefore>1)
|
|
|
|
|
{
|
|
|
|
|
m_bWeDeselectedFirstSector = FALSE;
|
|
|
|
|
}
|
|
|
|
|
// deselect all selected sectors
|
|
|
|
|
pDoc->m_selSectorSelection.Clear();
|
|
|
|
|
}
|
|
|
|
|
// if we have to deselect first sector but we didn't deselect it with clear
|
|
|
|
|
if( (m_bWeDeselectedFirstSector) &&
|
|
|
|
|
(crRayHit.cr_pbscBrushSector->IsSelected( BSCF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
// deselect clicked sector
|
|
|
|
|
pDoc->m_selSectorSelection.Deselect( *crRayHit.cr_pbscBrushSector);
|
|
|
|
|
}
|
|
|
|
|
// if we must select first sector
|
|
|
|
|
if( !m_bWeDeselectedFirstSector)
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *crRayHit.cr_pbscBrushSector);
|
|
|
|
|
}
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectAllEntitiesInWorld()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// deselect all entities
|
|
|
|
|
pDoc->m_selEntitySelection.Clear();
|
|
|
|
|
|
|
|
|
|
// add each entity in world
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CBrushSector *pbscSector = iten->GetFirstSector();
|
|
|
|
|
BOOL bSectorVisible = (pbscSector == NULL) ||
|
|
|
|
|
!(pbscSector->bsc_ulFlags & BSCF_HIDDEN);
|
|
|
|
|
// if it isn't classified in hidden sector and is not hidden itself
|
|
|
|
|
if( bSectorVisible && !(iten->en_ulFlags&ENF_HIDDEN))
|
|
|
|
|
{
|
|
|
|
|
// add it to selection
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *iten);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectSectorsWithSameName()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( m_pbpoRightClickedPolygon == NULL) return;
|
|
|
|
|
|
|
|
|
|
// select all sectors in world with same name
|
|
|
|
|
CBrushSector *pbscSrc = m_pbpoRightClickedPolygon->bpo_pbscSector;
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CEntity::RenderType rt = iten->GetRenderType();
|
|
|
|
|
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
|
|
|
|
|
{
|
|
|
|
|
// for each mip in its brush
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->GetBrush()->br_lhBrushMips, itbm)
|
|
|
|
|
{
|
|
|
|
|
// for all sectors in this mip
|
|
|
|
|
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
// if sector is not hidden and has same name, select it
|
|
|
|
|
if( !(itbsc->bsc_ulFlags & BSCF_HIDDEN) &&
|
|
|
|
|
(itbsc->bsc_strName==pbscSrc->bsc_strName) )
|
|
|
|
|
{
|
|
|
|
|
if( !itbsc->IsSelected( BSCF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *itbsc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
// update all views
|
|
|
|
|
pDoc->UpdateAllViews( this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectSectorsArroundEntity()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
// if none selected
|
|
|
|
|
if(pDoc->m_selEntitySelection.Count() == 0)
|
|
|
|
|
{
|
|
|
|
|
// perform on ray-hitted entity
|
|
|
|
|
BOOL bHitModels = pDoc->GetEditingMode() != POLYGON_MODE;
|
|
|
|
|
BOOL bHitFields = pDoc->GetEditingMode() == ENTITY_MODE;
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse, FALSE, bHitModels, bHitFields);
|
|
|
|
|
// if none of entities is hitted
|
|
|
|
|
if(crRayHit.cr_penHit == NULL) return;
|
|
|
|
|
{FOREACHSRCOFDST(crRayHit.cr_penHit->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
|
|
|
|
|
// if sector is not hidden and not selected
|
|
|
|
|
if( !(pbsc->bsc_ulFlags & BSCF_HIDDEN) && !pbsc->IsSelected( BSCF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *pbsc);
|
|
|
|
|
}
|
|
|
|
|
ENDFOR}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
{FOREACHSRCOFDST(iten->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
|
|
|
|
|
// if sector is not hidden and not selected
|
|
|
|
|
if( !(pbsc->bsc_ulFlags & BSCF_HIDDEN) && !pbsc->IsSelected( BSCF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *pbsc);
|
|
|
|
|
}
|
|
|
|
|
ENDFOR}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pDoc->SetEditingMode( SECTOR_MODE);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectSectorsArroundEntityOnContext()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
if( m_penEntityHitOnContext == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// perform select sectors on whole entity selection
|
|
|
|
|
if( m_penEntityHitOnContext->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
{FOREACHSRCOFDST(iten->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
|
|
|
|
|
// if sector is not hidden and not selected
|
|
|
|
|
if( !(pbsc->bsc_ulFlags & BSCF_HIDDEN) && !pbsc->IsSelected( BSCF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *pbsc);
|
|
|
|
|
}
|
|
|
|
|
ENDFOR}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
{FOREACHSRCOFDST(m_penEntityHitOnContext->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
|
|
|
|
|
// if sector is not hidden and not selected
|
|
|
|
|
if( !(pbsc->bsc_ulFlags & BSCF_HIDDEN) && !pbsc->IsSelected( BSCF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *pbsc);
|
|
|
|
|
}
|
|
|
|
|
ENDFOR}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pDoc->SetEditingMode( SECTOR_MODE);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::CopySectorAmbient( CBrushSector *pbscSector)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_colSectorAmbientClipboard = pbscSector->bsc_colAmbient;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::PasteSectorAmbient( CBrushSector *pbscSector)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( (pbscSector == NULL) || (pbscSector->IsSelected( BSCF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
itbsc->bsc_colAmbient = theApp.m_colSectorAmbientClipboard;
|
|
|
|
|
itbsc->UncacheLightMaps();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pbscSector->bsc_colAmbient = theApp.m_colSectorAmbientClipboard;
|
|
|
|
|
pbscSector->UncacheLightMaps();
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::PasteTexture( CBrushPolygon *pbpoPolygon)
|
|
|
|
|
{
|
|
|
|
|
if( theApp.m_ptdActiveTexture==NULL) return;
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CTFileName fnTextureName = theApp.m_ptdActiveTexture->GetName();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if( (pbpoPolygon == NULL) || (pbpoPolygon->IsSelected( BPOF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.SetData_t( fnTextureName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pbpoPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.SetData_t( fnTextureName);
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
}
|
|
|
|
|
catch( char *strError)
|
|
|
|
|
{
|
|
|
|
|
AfxMessageBox( CString(strError));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::StorePolygonSelection(CBrushPolygonSelection &selPolygons,
|
|
|
|
|
CDynamicContainer<CBrushPolygon> &dcPolygons)
|
|
|
|
|
{
|
|
|
|
|
dcPolygons.Clear();
|
|
|
|
|
FOREACHINDYNAMICCONTAINER( selPolygons, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
dcPolygons.Add( itbpo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::RestorePolygonSelection(CBrushPolygonSelection &selPolygons,
|
|
|
|
|
CDynamicContainer<CBrushPolygon> &dcPolygons)
|
|
|
|
|
{
|
|
|
|
|
selPolygons.Clear();
|
|
|
|
|
FOREACHINDYNAMICCONTAINER( dcPolygons, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
selPolygons.Select( *itbpo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::DiscardShadows( CEntity *penEntity)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
CDynamicContainer<CBrushPolygon> dcPolygons;
|
|
|
|
|
StorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
|
|
|
|
|
FLOATaabbox3D boxForDiscard;
|
|
|
|
|
if( (penEntity == NULL) || (penEntity->IsSelected( ENF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// if it is brush
|
|
|
|
|
if (iten->en_RenderType == CEntity::RT_BRUSH)
|
|
|
|
|
{
|
|
|
|
|
// for each mip in its brush
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm)
|
|
|
|
|
{
|
|
|
|
|
// for all sectors in this mip
|
|
|
|
|
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
// for all polygons in sector
|
|
|
|
|
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
boxForDiscard |= itbpo->bpo_boxBoundingBox;
|
|
|
|
|
itbpo->bpo_smShadowMap.DiscardAllLayers();
|
|
|
|
|
itbpo->InitializeShadowMap();
|
|
|
|
|
pDoc->m_selPolygonSelection.Select( *itbpo);
|
|
|
|
|
}
|
|
|
|
|
itbsc->UncacheLightMaps();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// if it is brush
|
|
|
|
|
if (penEntity->en_RenderType == CEntity::RT_BRUSH)
|
|
|
|
|
{
|
|
|
|
|
// for each mip in its brush
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, penEntity->en_pbrBrush->br_lhBrushMips, itbm)
|
|
|
|
|
{
|
|
|
|
|
// for all sectors in this mip
|
|
|
|
|
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
// for all polygons in sector
|
|
|
|
|
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
boxForDiscard |= itbpo->bpo_boxBoundingBox;
|
|
|
|
|
itbpo->bpo_smShadowMap.DiscardAllLayers();
|
|
|
|
|
itbpo->InitializeShadowMap();
|
|
|
|
|
pDoc->m_selPolygonSelection.Select( *itbpo);
|
|
|
|
|
}
|
|
|
|
|
itbsc->UncacheLightMaps();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_woWorld.FindShadowLayers( boxForDiscard, TRUE);
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
RestorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::DiscardShadows( CBrushSector *pbscSector)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
CDynamicContainer<CBrushPolygon> dcPolygons;
|
|
|
|
|
StorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
|
|
|
|
|
FLOATaabbox3D boxForDiscard;
|
|
|
|
|
if( (pbscSector == NULL) || (pbscSector->IsSelected( BSCF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
boxForDiscard |= itbpo->bpo_boxBoundingBox;
|
|
|
|
|
itbpo->bpo_smShadowMap.DiscardAllLayers();
|
|
|
|
|
itbpo->InitializeShadowMap();
|
|
|
|
|
pDoc->m_selPolygonSelection.Select( *itbpo);
|
|
|
|
|
}
|
|
|
|
|
itbsc->UncacheLightMaps();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FOREACHINSTATICARRAY(pbscSector->bsc_abpoPolygons, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
boxForDiscard |= itbpo->bpo_boxBoundingBox;
|
|
|
|
|
itbpo->bpo_smShadowMap.DiscardAllLayers();
|
|
|
|
|
itbpo->InitializeShadowMap();
|
|
|
|
|
pDoc->m_selPolygonSelection.Select( *itbpo);
|
|
|
|
|
}
|
|
|
|
|
pbscSector->UncacheLightMaps();
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_woWorld.FindShadowLayers( boxForDiscard, TRUE);
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
RestorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::DiscardShadows( CBrushPolygon *pbpoPolygon)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
CDynamicContainer<CBrushPolygon> dcPolygons;
|
|
|
|
|
StorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
|
|
|
|
|
|
|
|
|
|
FLOATaabbox3D boxForDiscard;
|
|
|
|
|
if( (pbpoPolygon == NULL) || (pbpoPolygon->IsSelected( BPOF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
// calculate bounding box for all polygons
|
|
|
|
|
boxForDiscard |= itbpo->bpo_boxBoundingBox;
|
|
|
|
|
itbpo->bpo_smShadowMap.DiscardAllLayers();
|
|
|
|
|
itbpo->InitializeShadowMap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pbpoPolygon->bpo_smShadowMap.DiscardAllLayers();
|
|
|
|
|
pbpoPolygon->InitializeShadowMap();
|
|
|
|
|
boxForDiscard |= pbpoPolygon->bpo_boxBoundingBox;
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
pDoc->m_selPolygonSelection.Select( *pbpoPolygon);
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_woWorld.FindShadowLayers( boxForDiscard, TRUE);
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
RestorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnInsertVertex()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
MarkClosestVtxAndEdgeOnPrimitiveBase( m_ptMouse);
|
|
|
|
|
if( m_iDragEdge != -1) pDoc->InsertPrimitiveVertex( m_iDragEdge, m_vMouseDownSecondLayer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDeleteVertex()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
MarkClosestVtxAndEdgeOnPrimitiveBase( m_ptMouse);
|
|
|
|
|
if( m_iDragVertice != -1) pDoc->DeletePrimitiveVertex( m_iDragVertice);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyBackslash()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
CPoint ptMouse;
|
|
|
|
|
GetCursorPos( &ptMouse);
|
|
|
|
|
if( theApp.m_iTerrainEditMode==TEM_LAYER)
|
|
|
|
|
{
|
|
|
|
|
CTerrainLayer *ptlLayer=GetLayer();
|
|
|
|
|
if(ptlLayer==NULL) return;
|
|
|
|
|
|
|
|
|
|
if( ptlLayer->tl_ltType==LT_TILE)
|
|
|
|
|
{
|
|
|
|
|
InvokeTerrainTilePalette(ptMouse.x, ptMouse.y);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InvokeTerrainBrushPalette( ptMouse.x-BRUSH_PALETTE_WIDTH/2, ptMouse.y+BRUSH_PALETTE_HEIGHT/2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
if( pDoc->m_selEntitySelection.Count() == 1)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selEntitySelection.Lock();
|
|
|
|
|
CEntity *penOnlySelected = &pDoc->m_selEntitySelection[0];
|
|
|
|
|
pDoc->m_selEntitySelection.Unlock();
|
|
|
|
|
|
|
|
|
|
CEntity *penToSelect = NULL;
|
|
|
|
|
CPropertyID *ppidProperty = pMainFrame->m_PropertyComboBar.GetSelectedProperty();
|
|
|
|
|
if( ppidProperty == NULL) return;
|
|
|
|
|
if( ppidProperty->pid_eptType == CEntityProperty::EPT_PARENT)
|
|
|
|
|
{
|
|
|
|
|
penToSelect = penOnlySelected->GetParent();
|
|
|
|
|
}
|
|
|
|
|
else if( ppidProperty->pid_eptType == CEntityProperty::EPT_ENTITYPTR)
|
|
|
|
|
{
|
|
|
|
|
// obtain entity class ptr
|
|
|
|
|
CDLLEntityClass *pdecDLLClass = penOnlySelected->GetClass()->ec_pdecDLLClass;
|
|
|
|
|
// for all classes in hierarchy of this entity
|
|
|
|
|
for(;
|
|
|
|
|
pdecDLLClass!=NULL;
|
|
|
|
|
pdecDLLClass = pdecDLLClass->dec_pdecBase) {
|
|
|
|
|
// for all properties
|
|
|
|
|
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++) {
|
|
|
|
|
CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
|
|
|
|
|
if( (ppidProperty->pid_strName == epProperty.ep_strName) &&
|
|
|
|
|
(ppidProperty->pid_eptType == epProperty.ep_eptType) )
|
|
|
|
|
{
|
|
|
|
|
// get target entity
|
|
|
|
|
penToSelect = ENTITYPROPERTY( &*penOnlySelected, epProperty.ep_slOffset, CEntityPointer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( penToSelect == NULL) return;
|
|
|
|
|
pDoc->m_selEntitySelection.Clear();
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *penToSelect);
|
|
|
|
|
pMainFrame->m_PropertyComboBar.UpdateData( FALSE);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSavePicturesForEnvironment()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->m_selEntitySelection.Lock();
|
|
|
|
|
CEntity *pen = &pDoc->m_selEntitySelection[0];
|
|
|
|
|
pDoc->m_selEntitySelection.Unlock();
|
|
|
|
|
|
|
|
|
|
CTFileName fnName = _EngineGUI.FileRequester( "Save pictures as ...",
|
|
|
|
|
FILTER_TGA FILTER_ALL FILTER_END,"Environment pictures directory", "Textures\\");
|
|
|
|
|
if( fnName == "") return;
|
|
|
|
|
CTFileName fnBase = fnName.NoExt();
|
|
|
|
|
|
|
|
|
|
CDrawPort *pdp;
|
|
|
|
|
CImageInfo II;
|
|
|
|
|
CTextureData TD;
|
|
|
|
|
CAnimData AD;
|
|
|
|
|
ULONG flags = NONE;
|
|
|
|
|
|
|
|
|
|
CChildFrame *pChild = GetChildFrame();
|
|
|
|
|
// create canvas to render picture
|
|
|
|
|
_pGfx->CreateWorkCanvas( 256, 256, &pdp);
|
|
|
|
|
if( pdp != NULL)
|
|
|
|
|
{
|
|
|
|
|
if( pdp->Lock())
|
|
|
|
|
{
|
|
|
|
|
CViewPrefs vpOld = m_vpViewPrefs;
|
|
|
|
|
// set rendering type for world
|
|
|
|
|
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetHiddenLinesOn( FALSE);
|
|
|
|
|
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetEditorModelsOn( FALSE);
|
|
|
|
|
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetFieldBrushesOn( FALSE);
|
|
|
|
|
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetBackgroundTextureOn( TRUE);
|
|
|
|
|
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetVerticesFillType( CWorldRenderPrefs::FT_NONE);
|
|
|
|
|
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetEdgesFillType( CWorldRenderPrefs::FT_NONE);
|
|
|
|
|
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetPolygonsFillType( CWorldRenderPrefs::FT_TEXTURE);
|
|
|
|
|
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetLensFlaresType( CWorldRenderPrefs::LFT_REFLECTIONS_AND_GLARE);
|
|
|
|
|
// for models
|
|
|
|
|
m_vpViewPrefs.m_mrpModelRenderPrefs.SetRenderType( RT_TEXTURE);
|
|
|
|
|
m_vpViewPrefs.m_mrpModelRenderPrefs.SetShadingType( RT_SHADING_PHONG);
|
|
|
|
|
m_vpViewPrefs.m_mrpModelRenderPrefs.SetShadowQuality( 0);
|
|
|
|
|
m_vpViewPrefs.m_mrpModelRenderPrefs.SetWire( FALSE);
|
|
|
|
|
m_vpViewPrefs.m_mrpModelRenderPrefs.SetHiddenLines( FALSE);
|
|
|
|
|
m_vpViewPrefs.m_mrpModelRenderPrefs.BBoxFrameShow( FALSE);
|
|
|
|
|
m_vpViewPrefs.m_mrpModelRenderPrefs.BBoxAllShow( FALSE);
|
|
|
|
|
|
|
|
|
|
// remember old viewer settings
|
|
|
|
|
CPlacement3D plOrgPlacement = pChild->m_mvViewer.mv_plViewer;
|
|
|
|
|
FLOAT fOldTargetDistance = pChild->m_mvViewer.mv_fTargetDistance;
|
|
|
|
|
enum CSlaveViewer::ProjectionType ptOld = m_ptProjectionType;
|
|
|
|
|
m_ptProjectionType = CSlaveViewer::PT_PERSPECTIVE;
|
|
|
|
|
// set new viewer settings
|
|
|
|
|
pChild->m_mvViewer.mv_plViewer = pen->GetPlacement();
|
|
|
|
|
pChild->m_mvViewer.mv_fTargetDistance = 10.0f;
|
|
|
|
|
|
|
|
|
|
#define GRAB_BCG( ext, angDelta) \
|
|
|
|
|
pChild->m_mvViewer.mv_plViewer = pen->GetPlacement();\
|
|
|
|
|
pChild->m_mvViewer.mv_plViewer.pl_OrientationAngle+=angDelta;\
|
|
|
|
|
RenderView( pdp);\
|
|
|
|
|
pdp->GrabScreen(II);\
|
|
|
|
|
try { II.SaveTGA_t( fnBase+ext); } \
|
|
|
|
|
catch (char *strError)\
|
|
|
|
|
{ AfxMessageBox(CString(strError)); }
|
|
|
|
|
|
|
|
|
|
GRAB_BCG( "N.tga", ANGLE3D( 0, 0, 0));
|
|
|
|
|
GRAB_BCG( "W.tga", ANGLE3D( 90.0f, 0, 0));
|
|
|
|
|
GRAB_BCG( "S.tga", ANGLE3D( 180.0f, 0, 0));
|
|
|
|
|
GRAB_BCG( "E.tga", ANGLE3D( -90.0f, 0, 0));
|
|
|
|
|
GRAB_BCG( "C.tga", ANGLE3D( 0, 90.0f, 0));
|
|
|
|
|
GRAB_BCG( "F.tga", ANGLE3D( 0, -90.0f, 0));
|
|
|
|
|
|
|
|
|
|
// restore original settings
|
|
|
|
|
m_ptProjectionType = ptOld;
|
|
|
|
|
pChild->m_mvViewer.mv_plViewer = plOrgPlacement;
|
|
|
|
|
pChild->m_mvViewer.mv_fTargetDistance = fOldTargetDistance;
|
|
|
|
|
m_vpViewPrefs = vpOld;
|
|
|
|
|
pdp->Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_pGfx->DestroyWorkCanvas( pdp);
|
|
|
|
|
pdp = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateSavePicturesForEnvironment(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pCmdUI->Enable( pDoc->m_selEntitySelection.Count() == 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CWorldEditorView::OnEraseBkgnd(CDC* pDC)
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnMenuAlignMappingU()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->m_selPolygonSelection.Count() == 0) return;
|
|
|
|
|
|
|
|
|
|
FLOAT fLastU = 0;
|
|
|
|
|
// for each selected polygon
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo) {
|
|
|
|
|
CBrushPolygon &bpo = *itbpo;
|
|
|
|
|
CMappingDefinition &md = bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
|
|
|
|
|
// find min and max u for the polygon
|
|
|
|
|
md.md_fUOffset = 0;
|
|
|
|
|
FLOAT fMinU = UpperLimit(0.0f);
|
|
|
|
|
FLOAT fMaxU = LowerLimit(0.0f);
|
|
|
|
|
for(INDEX ibpe=0; ibpe<bpo.bpo_abpePolygonEdges.Count(); ibpe++) {
|
|
|
|
|
CBrushPolygonEdge &bpe = bpo.bpo_abpePolygonEdges[ibpe];
|
|
|
|
|
FLOAT3D v0, v1;
|
|
|
|
|
MEX2D(vTex0);
|
|
|
|
|
bpe.GetVertexCoordinatesRelative(v0, v1);
|
|
|
|
|
md.GetTextureCoordinates(
|
|
|
|
|
bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative, v0, vTex0);
|
|
|
|
|
FLOAT fU = vTex0(1)/1024.0f;
|
|
|
|
|
fMinU = Min(fMinU, fU);
|
|
|
|
|
fMaxU = Max(fMaxU, fU);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// add the offsets to its mapping
|
|
|
|
|
md.md_fUOffset=fMinU-fLastU;
|
|
|
|
|
fLastU += fMaxU-fMinU;
|
|
|
|
|
}
|
|
|
|
|
CPrintF("Total length u: %fm\n", fLastU);
|
|
|
|
|
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyCtrlShiftK()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
ApplyRndNoiseOntoTerrain();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OnMenuAlignMappingV();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnMenuAlignMappingV()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->m_selPolygonSelection.Count() == 0) return;
|
|
|
|
|
|
|
|
|
|
FLOAT fLastV = 0;
|
|
|
|
|
// for each selected polygon
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo) {
|
|
|
|
|
CBrushPolygon &bpo = *itbpo;
|
|
|
|
|
CMappingDefinition &md = bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
|
|
|
|
|
// find min and max v for the polygon
|
|
|
|
|
md.md_fVOffset = 0;
|
|
|
|
|
FLOAT fMinV = UpperLimit(0.0f);
|
|
|
|
|
FLOAT fMaxV = LowerLimit(0.0f);
|
|
|
|
|
for(INDEX ibpe=0; ibpe<bpo.bpo_abpePolygonEdges.Count(); ibpe++) {
|
|
|
|
|
CBrushPolygonEdge &bpe = bpo.bpo_abpePolygonEdges[ibpe];
|
|
|
|
|
FLOAT3D v0, v1;
|
|
|
|
|
MEX2D(vTex0);
|
|
|
|
|
bpe.GetVertexCoordinatesRelative(v0, v1);
|
|
|
|
|
md.GetTextureCoordinates(
|
|
|
|
|
bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative, v0, vTex0);
|
|
|
|
|
FLOAT fV = vTex0(2)/1024.0f;
|
|
|
|
|
fMinV = Min(fMinV, fV);
|
|
|
|
|
fMaxV = Max(fMaxV, fV);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// add the offsets to its mapping
|
|
|
|
|
md.md_fVOffset=fMinV-fLastV;
|
|
|
|
|
fLastV += fMaxV-fMinV;
|
|
|
|
|
}
|
|
|
|
|
CPrintF("Total length v %fm\n", fLastV);
|
|
|
|
|
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDestroy()
|
|
|
|
|
{
|
|
|
|
|
// destroy canvas that is currently used
|
|
|
|
|
_pGfx->DestroyWindowCanvas( m_pvpViewPort);
|
|
|
|
|
m_pvpViewPort = NULL;
|
|
|
|
|
|
|
|
|
|
CView::OnDestroy();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnFallDown()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
iten->FallDownToFloor();
|
|
|
|
|
}
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdatePrevious(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
// for browsing trough properties
|
|
|
|
|
if( bShift && (pDoc->GetEditingMode() == ENTITY_MODE) && (pDoc->m_selEntitySelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( TRUE);
|
|
|
|
|
}
|
|
|
|
|
else if( (pDoc->GetEditingMode() == POLYGON_MODE) && (pDoc->m_selPolygonSelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( TRUE);
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( TRUE);
|
|
|
|
|
}
|
|
|
|
|
else if( (pDoc->m_bBrowseEntitiesMode) || (pDoc->m_cenEntitiesSelectedByVolume.Count()>0) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->OnUpdatePreviousSelectedEntity(pCmdUI);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OnUpdatePreviousMipBrush( pCmdUI);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateNext(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
// for browsing trough properties
|
|
|
|
|
if( bShift && (pDoc->GetEditingMode() == ENTITY_MODE) && (pDoc->m_selEntitySelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( TRUE);
|
|
|
|
|
}
|
|
|
|
|
else if( (pDoc->GetEditingMode() == POLYGON_MODE) && (pDoc->m_selPolygonSelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( TRUE);
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( TRUE);
|
|
|
|
|
}
|
|
|
|
|
else if( (pDoc->m_bBrowseEntitiesMode) || (pDoc->m_cenEntitiesSelectedByVolume.Count()>0) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->OnUpdateNextSelectedEntity(pCmdUI);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OnUpdateNextMipBrush( pCmdUI);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPrevious()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CPropertyComboBar &dlgProperty = pMainFrame->m_PropertyComboBar;
|
|
|
|
|
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
|
|
|
|
|
// in entity mode use shift to select previous property
|
|
|
|
|
if( (pDoc->GetEditingMode() == ENTITY_MODE) && bShift )
|
|
|
|
|
{
|
|
|
|
|
// shift only is used to select previous empty target property
|
|
|
|
|
if( !bCtrl)
|
|
|
|
|
{
|
|
|
|
|
dlgProperty.SelectPreviousEmptyTarget();
|
|
|
|
|
}
|
|
|
|
|
// ctrl+shift is used to select previous property
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dlgProperty.SelectPreviousProperty();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( (pDoc->GetEditingMode() == POLYGON_MODE) && (pDoc->m_selPolygonSelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
OnPreviousPolygon();
|
|
|
|
|
}
|
|
|
|
|
else if( (pDoc->m_bBrowseEntitiesMode) || (pDoc->m_cenEntitiesSelectedByVolume.Count()>0) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->OnPreviousSelectedEntity();
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
CTerrainLayer *ptlLayer=GetLayer();
|
|
|
|
|
if(theApp.m_iTerrainEditMode==TEM_LAYER && ptlLayer!=NULL && ptlLayer->tl_ltType==LT_TILE)
|
|
|
|
|
{
|
|
|
|
|
CDynamicContainer<CTileInfo> dcTileInfo;
|
|
|
|
|
INDEX ctTilesPerRaw=0;
|
|
|
|
|
ObtainLayerTileInfo( &dcTileInfo, ptlLayer->tl_ptdTexture, ctTilesPerRaw);
|
|
|
|
|
INDEX ctTiles=dcTileInfo.Count();
|
|
|
|
|
ptlLayer->tl_iSelectedTile= Clamp( ptlLayer->tl_iSelectedTile+INDEX(1), (INDEX)0, INDEX(ctTiles-1) );
|
|
|
|
|
// free allocated tile info structures
|
|
|
|
|
for(INDEX i=0; i<dcTileInfo.Count(); i++)
|
|
|
|
|
{
|
|
|
|
|
delete &dcTileInfo[i];
|
|
|
|
|
}
|
|
|
|
|
dcTileInfo.Clear();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
theApp.m_fCurrentTerrainBrush=ClampUp(theApp.m_fCurrentTerrainBrush+1.0f,FLOAT(CT_BRUSHES-1));
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OnPreviousMipBrush();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnNext()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CPropertyComboBar &dlgProperty = pMainFrame->m_PropertyComboBar;
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
BOOL bCtrl = (GetKeyState( VK_CONTROL)&0x8000) != 0;
|
|
|
|
|
// in entity mode use shift to select next property
|
|
|
|
|
if( (pDoc->GetEditingMode() == ENTITY_MODE) && bShift )
|
|
|
|
|
{
|
|
|
|
|
// shift only is used to select next empty target property
|
|
|
|
|
if( !bCtrl)
|
|
|
|
|
{
|
|
|
|
|
dlgProperty.SelectNextEmptyTarget();
|
|
|
|
|
}
|
|
|
|
|
// ctrl+shift is used to select next property
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dlgProperty.SelectNextProperty();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( (pDoc->GetEditingMode() == POLYGON_MODE) && (pDoc->m_selPolygonSelection.Count() != 0) )
|
|
|
|
|
{
|
|
|
|
|
OnNextPolygon();
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
CTerrainLayer *ptlLayer=GetLayer();
|
|
|
|
|
if(theApp.m_iTerrainEditMode==TEM_LAYER && ptlLayer!=NULL && ptlLayer->tl_ltType==LT_TILE)
|
|
|
|
|
{
|
|
|
|
|
CDynamicContainer<CTileInfo> dcTileInfo;
|
|
|
|
|
INDEX ctTilesPerRaw=0;
|
|
|
|
|
ObtainLayerTileInfo( &dcTileInfo, ptlLayer->tl_ptdTexture, ctTilesPerRaw);
|
|
|
|
|
INDEX ctTiles=dcTileInfo.Count();
|
|
|
|
|
ptlLayer->tl_iSelectedTile= Clamp( ptlLayer->tl_iSelectedTile-INDEX(1), (INDEX)0, INDEX(ctTiles-1) );
|
|
|
|
|
// free allocated tile info structures
|
|
|
|
|
for(INDEX i=0; i<dcTileInfo.Count(); i++)
|
|
|
|
|
{
|
|
|
|
|
delete &dcTileInfo[i];
|
|
|
|
|
}
|
|
|
|
|
dcTileInfo.Clear();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
theApp.m_fCurrentTerrainBrush=ClampDn(theApp.m_fCurrentTerrainBrush-1.0f,0.0f);
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( (pDoc->m_bBrowseEntitiesMode) || (pDoc->m_cenEntitiesSelectedByVolume.Count()>0) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->OnNextSelectedEntity();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OnNextMipBrush();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPreviousPolygon(void)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
pDoc->m_selPolygonSelection.Lock();
|
|
|
|
|
ASSERT( pDoc->m_selPolygonSelection.Count() != 0);
|
|
|
|
|
INDEX iSelectedPolygon=0;
|
|
|
|
|
|
|
|
|
|
if( !pDoc->m_selPolygonSelection.IsMember( pDoc->m_pbpoLastCentered))
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_pbpoLastCentered = &pDoc->m_selPolygonSelection[0];
|
|
|
|
|
iSelectedPolygon=0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
INDEX iCurrent = pDoc->m_selPolygonSelection.Index( pDoc->m_pbpoLastCentered);
|
|
|
|
|
INDEX iNext = (iCurrent+1) % pDoc->m_selPolygonSelection.Count();
|
|
|
|
|
pDoc->m_pbpoLastCentered = &pDoc->m_selPolygonSelection[iNext];
|
|
|
|
|
iSelectedPolygon=iNext;
|
|
|
|
|
}
|
|
|
|
|
AllignPolygon( pDoc->m_pbpoLastCentered);
|
|
|
|
|
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CTString strMessage;
|
|
|
|
|
strMessage.PrintF("Polygon %d/%d", iSelectedPolygon, pDoc->m_selPolygonSelection.Count());
|
|
|
|
|
pMainFrame->SetStatusBarMessage( strMessage, STATUS_LINE_PANE, 2);
|
|
|
|
|
|
|
|
|
|
pDoc->m_selPolygonSelection.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnNextPolygon(void)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
pDoc->m_selPolygonSelection.Lock();
|
|
|
|
|
ASSERT( pDoc->m_selPolygonSelection.Count() != 0);
|
|
|
|
|
INDEX iSelectedPolygon=0;
|
|
|
|
|
|
|
|
|
|
if( !pDoc->m_selPolygonSelection.IsMember( pDoc->m_pbpoLastCentered))
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_pbpoLastCentered = &pDoc->m_selPolygonSelection[0];
|
|
|
|
|
iSelectedPolygon=0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
INDEX iCurrent = pDoc->m_selPolygonSelection.Index( pDoc->m_pbpoLastCentered);
|
|
|
|
|
INDEX iPrev = (iCurrent+pDoc->m_selPolygonSelection.Count()-1) % pDoc->m_selPolygonSelection.Count();
|
|
|
|
|
pDoc->m_pbpoLastCentered = &pDoc->m_selPolygonSelection[iPrev];
|
|
|
|
|
iSelectedPolygon=iPrev;
|
|
|
|
|
}
|
|
|
|
|
AllignPolygon( pDoc->m_pbpoLastCentered);
|
|
|
|
|
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CTString strMessage;
|
|
|
|
|
strMessage.PrintF("Polygon %d/%d", iSelectedPolygon, pDoc->m_selPolygonSelection.Count());
|
|
|
|
|
pMainFrame->SetStatusBarMessage( strMessage, STATUS_LINE_PANE, 2);
|
|
|
|
|
|
|
|
|
|
pDoc->m_selPolygonSelection.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRemoveUnusedTextures()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// for each entity in the world
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten) {
|
|
|
|
|
// if it is brush entity
|
|
|
|
|
if (iten->en_RenderType == CEntity::RT_BRUSH) {
|
|
|
|
|
// for each mip in its brush
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) {
|
|
|
|
|
// for all sectors in this mip
|
|
|
|
|
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
|
|
|
|
|
// for all polygons in sector
|
|
|
|
|
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
// if it is non translucent portal same texture
|
|
|
|
|
if ( ((itbpo->bpo_ulFlags&BPOF_PORTAL) && !(itbpo->bpo_ulFlags&BPOF_TRANSLUCENT)) &&
|
|
|
|
|
(itbpo->bpo_bppProperties.bpp_uwPretenderDistance==0) )
|
|
|
|
|
{
|
|
|
|
|
itbpo->bpo_abptTextures[0].bpt_toTexture.SetData_t( CTString(""));
|
|
|
|
|
itbpo->bpo_abptTextures[1].bpt_toTexture.SetData_t( CTString(""));
|
|
|
|
|
itbpo->bpo_abptTextures[2].bpt_toTexture.SetData_t( CTString(""));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if failed
|
|
|
|
|
catch( char *err_str)
|
|
|
|
|
{
|
|
|
|
|
// report error
|
|
|
|
|
AfxMessageBox( CString(err_str));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRotate()
|
|
|
|
|
{
|
|
|
|
|
Rotate(90.0f, 0.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRotateBack()
|
|
|
|
|
{
|
|
|
|
|
Rotate(-90.0f, 0.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define ANGLE_KEY_DELTA 15.0f
|
|
|
|
|
void CWorldEditorView::OnRotateLeft()
|
|
|
|
|
{
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
Rotate(ANGLE_KEY_DELTA, 0.0f, bShift);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRotateRight()
|
|
|
|
|
{
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
Rotate(-ANGLE_KEY_DELTA, 0.0f, bShift);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRotateUp()
|
|
|
|
|
{
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
if( (pDoc->m_pwoSecondLayer != NULL) &&
|
|
|
|
|
(pDoc->m_bPrimitiveMode) &&
|
|
|
|
|
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) )
|
|
|
|
|
{
|
|
|
|
|
OnMoveUp();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Rotate(0.0f,-ANGLE_KEY_DELTA, bShift);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRotateDown()
|
|
|
|
|
{
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
if( (pDoc->m_pwoSecondLayer != NULL) &&
|
|
|
|
|
(pDoc->m_bPrimitiveMode) &&
|
|
|
|
|
(theApp.m_vfpCurrent.vfp_ttTriangularisationType != TT_NONE) )
|
|
|
|
|
{
|
|
|
|
|
OnMoveDown();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Rotate(0.0f,ANGLE_KEY_DELTA, bShift);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::Rotate( FLOAT fAngleLR, FLOAT fAngleUD, BOOL bSmooth/*=FALSE*/)
|
|
|
|
|
{
|
|
|
|
|
if( bSmooth && Abs(fAngleLR)!=90.0f)
|
|
|
|
|
{
|
|
|
|
|
fAngleLR/=10;
|
|
|
|
|
fAngleUD/=10;
|
|
|
|
|
}
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
ANGLE3D a3dForRotation = ANGLE3D(0.0f, 0.0f, 0.0f);
|
|
|
|
|
switch( m_ptProjectionType)
|
|
|
|
|
{
|
|
|
|
|
case CSlaveViewer::PT_ISOMETRIC_FRONT:
|
|
|
|
|
case CSlaveViewer::PT_ISOMETRIC_BACK:
|
|
|
|
|
{
|
|
|
|
|
a3dForRotation(3) = fAngleLR;
|
|
|
|
|
a3dForRotation(2) = fAngleUD;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CSlaveViewer::PT_ISOMETRIC_RIGHT:
|
|
|
|
|
case CSlaveViewer::PT_ISOMETRIC_LEFT:
|
|
|
|
|
{
|
|
|
|
|
a3dForRotation(2) = fAngleLR;
|
|
|
|
|
a3dForRotation(3) = -fAngleUD;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
a3dForRotation(1) = fAngleLR;
|
|
|
|
|
a3dForRotation(2) = fAngleUD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( (pDoc->GetEditingMode() == POLYGON_MODE))
|
|
|
|
|
{
|
|
|
|
|
if( Abs(fAngleLR)!=90.0f)
|
|
|
|
|
{
|
|
|
|
|
fAngleLR/=50;
|
|
|
|
|
fAngleUD/=50;
|
|
|
|
|
}
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if mouse is over polygon
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygon &bpo = *crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
FLOAT3D vCenter=bpo.bpo_boxBoundingBox.Center();
|
|
|
|
|
vCenter=bpo.bpo_pbplPlane->bpl_plAbsolute.ProjectPoint( vCenter);
|
|
|
|
|
|
|
|
|
|
CEntity *pen = bpo.bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
|
|
|
|
|
CSimpleProjection3D pr;
|
|
|
|
|
pr.ObjectPlacementL() = _plOrigin;
|
|
|
|
|
pr.ViewerPlacementL() = pen->GetPlacement();
|
|
|
|
|
pr.Prepare();
|
|
|
|
|
FLOATplane3D vRelative;
|
|
|
|
|
pr.ProjectCoordinate(vCenter, vRelative);
|
|
|
|
|
|
|
|
|
|
// rotate it
|
|
|
|
|
ANGLE3D angMappingRotation=ANGLE3D(0,0,0);
|
|
|
|
|
angMappingRotation(1)=fAngleLR;
|
|
|
|
|
bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.Rotate(
|
|
|
|
|
bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative,
|
|
|
|
|
vRelative, angMappingRotation(1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( (pDoc->GetEditingMode() == CSG_MODE))
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_plSecondLayer.pl_OrientationAngle += a3dForRotation;
|
|
|
|
|
}
|
|
|
|
|
else if( (pDoc->GetEditingMode() == ENTITY_MODE))
|
|
|
|
|
{
|
|
|
|
|
CEntity *penBrush = NULL;
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
if (iten->en_RenderType == CEntity::RT_BRUSH) {
|
|
|
|
|
penBrush = &*iten;
|
|
|
|
|
}
|
|
|
|
|
if( !(iten->GetFlags() & ENF_ANCHORED) ||
|
|
|
|
|
GetChildFrame()->m_bAncoredMovingAllowed)
|
|
|
|
|
{
|
|
|
|
|
CPlacement3D plEntity = iten->GetPlacement();
|
|
|
|
|
plEntity.pl_OrientationAngle += a3dForRotation;
|
|
|
|
|
iten->SetPlacement( plEntity);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// check for terrain updating
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CLightSource *pls = iten->GetLightSource();
|
|
|
|
|
if (pls!=NULL)
|
|
|
|
|
{
|
|
|
|
|
// if light is directional
|
|
|
|
|
if(pls->ls_ulFlags &LSF_DIRECTIONAL)
|
|
|
|
|
{
|
|
|
|
|
CTerrain *ptrTerrain=GetTerrain();
|
|
|
|
|
if(ptrTerrain!=NULL) ptrTerrain->UpdateShadowMap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
if( penBrush != NULL)
|
|
|
|
|
{
|
|
|
|
|
DiscardShadows( penBrush);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::MultiplyMappingOnPolygon( FLOAT fFactor)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if mouse is over polygon
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
CMappingDefinitionUI mdui;
|
|
|
|
|
CBrushPolygon *pbpo = crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
pbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.ToUI( mdui);
|
|
|
|
|
mdui.mdui_fUStretch *= fFactor;
|
|
|
|
|
mdui.mdui_fVStretch *= fFactor;
|
|
|
|
|
pbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.FromUI( mdui);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectVisibleSectors()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
pDoc->m_selSectorSelection.Clear();
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// don't select for hidden entities
|
|
|
|
|
if( !(iten->en_ulFlags & ENF_HIDDEN))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
CEntity::RenderType rt = iten->GetRenderType();
|
|
|
|
|
if (rt==CEntity::RT_BRUSH || rt==CEntity::RT_FIELDBRUSH)
|
|
|
|
|
{
|
|
|
|
|
CBrush3D *pBrush3D = iten->GetBrush();
|
|
|
|
|
if(pBrush3D != NULL)
|
|
|
|
|
{
|
|
|
|
|
FLOAT fCurrentMipFactor = GetCurrentlyActiveMipFactor();
|
|
|
|
|
CBrush3D *pbrBrush = iten->GetBrush();
|
|
|
|
|
if( pbrBrush != NULL)
|
|
|
|
|
{
|
|
|
|
|
CBrushMip *pbmCurrentMip = pbrBrush->GetBrushMipByDistance( fCurrentMipFactor);
|
|
|
|
|
if( pbmCurrentMip != NULL)
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICARRAY(pbmCurrentMip->bm_abscSectors, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
if( !(itbsc->bsc_ulFlags & BSCF_HIDDEN))
|
|
|
|
|
{
|
|
|
|
|
// add it to selection
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *itbsc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnEditCopyAlternative()
|
|
|
|
|
{
|
|
|
|
|
EditCopy( TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Draw a line for arrow drawing.
|
|
|
|
|
*/
|
|
|
|
|
static inline void DrawArrowLine(CDrawPort &dp, const FLOAT2D &vPoint0,
|
|
|
|
|
const FLOAT2D &vPoint1, COLOR color, ULONG ulLineType)
|
|
|
|
|
{
|
|
|
|
|
PIX x0 = (PIX)vPoint0(1);
|
|
|
|
|
PIX x1 = (PIX)vPoint1(1);
|
|
|
|
|
PIX y0 = (PIX)vPoint0(2);
|
|
|
|
|
PIX y1 = (PIX)vPoint1(2);
|
|
|
|
|
|
|
|
|
|
dp.DrawLine(x0, y0, x1, y1, color, ulLineType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Draw an arrow for debugging edge directions.
|
|
|
|
|
*/
|
|
|
|
|
static inline void DrawArrow(CDrawPort &dp, PIX i0, PIX j0, PIX i1, PIX j1, COLOR color,
|
|
|
|
|
ULONG ulLineType)
|
|
|
|
|
{
|
|
|
|
|
FLOAT2D vPoint0 = FLOAT2D((FLOAT)i0, (FLOAT)j0);
|
|
|
|
|
FLOAT2D vPoint1 = FLOAT2D((FLOAT)i1, (FLOAT)j1);
|
|
|
|
|
FLOAT2D vDelta = vPoint1-vPoint0;
|
|
|
|
|
FLOAT fDelta = vDelta.Length();
|
|
|
|
|
FLOAT2D vArrowLen, vArrowWidth;
|
|
|
|
|
if (fDelta>0.01) {
|
|
|
|
|
vArrowLen = vDelta/fDelta*FLOAT(10.0);
|
|
|
|
|
vArrowWidth = vDelta/fDelta*FLOAT(2.0);
|
|
|
|
|
} else {
|
|
|
|
|
vArrowWidth = vArrowLen = FLOAT2D(0.0f, 0.0f);
|
|
|
|
|
}
|
|
|
|
|
// FLOAT3D vArrowLen = vDelta/5.0f;
|
|
|
|
|
// FLOAT3D vArrowWidth = vDelta/30.0f;
|
|
|
|
|
Swap(vArrowWidth(1), vArrowWidth(2));
|
|
|
|
|
//vArrowWidth(2) *= -1.0f;
|
|
|
|
|
|
|
|
|
|
DrawArrowLine(dp, vPoint0, vPoint1, color, ulLineType);
|
|
|
|
|
DrawArrowLine(dp, vPoint1-vArrowLen+vArrowWidth, vPoint1, color, ulLineType);
|
|
|
|
|
DrawArrowLine(dp, vPoint1-vArrowLen-vArrowWidth, vPoint1, color, ulLineType);
|
|
|
|
|
//DrawArrowLine(dp, vPoint0+vArrowWidth, vPoint0-vArrowWidth, color, ulLineType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::DrawAxis(const PIX2D &pixC, PIX len, COLOR colAxisColor, COLOR colTextColor,
|
|
|
|
|
CTString strU, CTString strV)
|
|
|
|
|
{
|
|
|
|
|
if( strU=="" || strV=="") return;
|
|
|
|
|
// draw arrow-headed axis
|
|
|
|
|
DrawArrow( *m_pdpDrawPort, pixC(1), pixC(2), pixC(1)+len, pixC(2), colAxisColor, _FULL_);
|
|
|
|
|
DrawArrow( *m_pdpDrawPort, pixC(1), pixC(2), pixC(1), pixC(2)-len, colAxisColor, _FULL_);
|
|
|
|
|
// type axis text line
|
|
|
|
|
m_pdpDrawPort->SetFont( _pfdConsoleFont);
|
|
|
|
|
m_pdpDrawPort->SetTextAspect( 1.0f);
|
|
|
|
|
m_pdpDrawPort->SetTextScaling( 1.0f);
|
|
|
|
|
m_pdpDrawPort->PutTextCXY( strU, pixC(1)+len+8, pixC(2), colTextColor);
|
|
|
|
|
m_pdpDrawPort->PutTextCXY( strV, pixC(1), pixC(2)-len-8, colTextColor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::DrawArrowAndTypeText( CProjection3D &prProjection,
|
|
|
|
|
const FLOAT3D &v0, const FLOAT3D &v1, COLOR colColor, CTString strText)
|
|
|
|
|
{
|
|
|
|
|
// get transformed end vertices
|
|
|
|
|
FLOAT3D tv0, tv1;
|
|
|
|
|
prProjection.PreClip(v0, tv0);
|
|
|
|
|
prProjection.PreClip(v1, tv1);
|
|
|
|
|
|
|
|
|
|
// clip the edge line
|
|
|
|
|
FLOAT3D vClipped0 = tv0;
|
|
|
|
|
FLOAT3D vClipped1 = tv1;
|
|
|
|
|
ULONG ulClipFlags = prProjection.ClipLine(vClipped0, vClipped1);
|
|
|
|
|
// if the edge remains after clipping to front plane
|
|
|
|
|
if (ulClipFlags != LCF_EDGEREMOVED) {
|
|
|
|
|
// project the vertices
|
|
|
|
|
FLOAT3D v3d0, v3d1;
|
|
|
|
|
prProjection.PostClip(vClipped0, v3d0);
|
|
|
|
|
prProjection.PostClip(vClipped1, v3d1);
|
|
|
|
|
// make 2d vertices
|
|
|
|
|
FLOAT2D v2d0, v2d1;
|
|
|
|
|
v2d0(1) = v3d0(1); v2d0(2) = v3d0(2);
|
|
|
|
|
v2d1(1) = v3d1(1); v2d1(2) = v3d1(2);
|
|
|
|
|
|
|
|
|
|
if( (Abs(v2d1(1)-v2d0(1)) > 8) || (Abs(v2d1(2)-v2d0(2)) > 8) )
|
|
|
|
|
{
|
|
|
|
|
// draw arrow-headed line between vertices
|
|
|
|
|
DrawArrow( *m_pdpDrawPort, (PIX)v2d0(1), (PIX)v2d0(2),
|
|
|
|
|
(PIX)v2d1(1), (PIX)v2d1(2), colColor, _FULL_);
|
|
|
|
|
// type text over line
|
|
|
|
|
if( strText != "")
|
|
|
|
|
m_pdpDrawPort->PutTextCXY( strText, (v2d0(1)+v2d1(1))/2, (v2d0(2)+v2d1(2))/2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::SelectWhoTargets( CDynamicContainer<CEntity> &dcTargetedEntities)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
pDoc->m_selEntitySelection.Clear();
|
|
|
|
|
CEntityProperty *pepSelected = NULL;
|
|
|
|
|
// for each that can be targeted
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(dcTargetedEntities, CEntity, itenTargets)
|
|
|
|
|
{
|
|
|
|
|
// for each entity in world
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// obtain entity class ptr
|
|
|
|
|
CDLLEntityClass *pdecDLLClass = iten->GetClass()->ec_pdecDLLClass;
|
|
|
|
|
// for all classes in hierarchy of this entity
|
|
|
|
|
for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
|
|
|
|
|
{
|
|
|
|
|
// for all properties
|
|
|
|
|
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
|
|
|
|
|
{
|
|
|
|
|
CEntityProperty *pepProperty = &pdecDLLClass->dec_aepProperties[iProperty];
|
|
|
|
|
if( pepProperty->ep_eptType == CEntityProperty::EPT_ENTITYPTR)
|
|
|
|
|
{
|
|
|
|
|
// obtain property ptr
|
|
|
|
|
CEntity *penCurrentPtr = ENTITYPROPERTY( &*iten, pepProperty->ep_slOffset, CEntityPointer);
|
|
|
|
|
if( (penCurrentPtr == &*itenTargets) && !iten->IsSelected( ENF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
pepSelected = pepProperty;
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *iten);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
|
|
|
|
|
// if only one entity targets
|
|
|
|
|
if( pDoc->m_selEntitySelection.Count() == 1)
|
|
|
|
|
{
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
pMainFrame->m_PropertyComboBar.SelectProperty( pepSelected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectWhoTargetsOnContext()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
// to hold entities for selecting
|
|
|
|
|
CDynamicContainer<CEntity> dcEntities;
|
|
|
|
|
// if right-clicked on void or selected entity
|
|
|
|
|
if( (m_penEntityHitOnContext == NULL) ||
|
|
|
|
|
(m_penEntityHitOnContext->IsSelected( ENF_SELECTED)) )
|
|
|
|
|
{
|
|
|
|
|
// perform on whole selection
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
dcEntities.Add( iten);
|
|
|
|
|
}}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// perform only on right-clicked entity
|
|
|
|
|
dcEntities.Add( m_penEntityHitOnContext);
|
|
|
|
|
}
|
|
|
|
|
// select all entities that target ones from dynamic container
|
|
|
|
|
SelectWhoTargets( dcEntities);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectWhoTargets()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
// to hold entities for selecting
|
|
|
|
|
CDynamicContainer<CEntity> dcEntities;
|
|
|
|
|
// perform on whole selection
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
dcEntities.Add( iten);
|
|
|
|
|
}}
|
|
|
|
|
// select all entities that target ones from dynamic container
|
|
|
|
|
SelectWhoTargets( dcEntities);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectAllTargetsOnContext()
|
|
|
|
|
{
|
|
|
|
|
CEntity *pen = m_penEntityHitOnContext;
|
|
|
|
|
if( pen==NULL || pen->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
SelectAllTargetsOfSelectedEntities();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SelectAllTargetsOfEntity(pen);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectAllTargets()
|
|
|
|
|
{
|
|
|
|
|
SelectAllTargetsOfSelectedEntities();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::SelectAllTargetsOfEntity(CEntity *pen)
|
|
|
|
|
{
|
|
|
|
|
ASSERT( pen!= NULL);
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
// obtain entity class ptr
|
|
|
|
|
CDLLEntityClass *pdecDLLClass = pen->GetClass()->ec_pdecDLLClass;
|
|
|
|
|
|
|
|
|
|
// to hold entities for selecting
|
|
|
|
|
CDynamicContainer<CEntity> dcEntities;
|
|
|
|
|
|
|
|
|
|
// for all classes in hierarchy of this entity
|
|
|
|
|
for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
|
|
|
|
|
{
|
|
|
|
|
// for all properties
|
|
|
|
|
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
|
|
|
|
|
{
|
|
|
|
|
CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
|
|
|
|
|
if( epProperty.ep_eptType == CEntityProperty::EPT_ENTITYPTR &&
|
|
|
|
|
epProperty.ep_strName!=NULL &&
|
|
|
|
|
CTString(epProperty.ep_strName)!="")
|
|
|
|
|
{
|
|
|
|
|
// obtain property ptr
|
|
|
|
|
CEntity *penTarget = ENTITYPROPERTY( &*pen, epProperty.ep_slOffset, CEntityPointer);
|
|
|
|
|
if( penTarget != NULL)
|
|
|
|
|
{
|
|
|
|
|
// add it to container
|
|
|
|
|
dcEntities.Add( penTarget);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for all entities in dynamic container
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(dcEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// if not yet selected
|
|
|
|
|
if( !iten->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *iten);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::SelectAllTargetsOfSelectedEntities(void)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
// to hold entities for selecting
|
|
|
|
|
CDynamicContainer<CEntity> dcEntities;
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// obtain entity class ptr
|
|
|
|
|
CDLLEntityClass *pdecDLLClass = iten->GetClass()->ec_pdecDLLClass;
|
|
|
|
|
// for all classes in hierarchy of this entity
|
|
|
|
|
for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
|
|
|
|
|
{
|
|
|
|
|
// for all properties
|
|
|
|
|
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
|
|
|
|
|
{
|
|
|
|
|
CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
|
|
|
|
|
if(epProperty.ep_eptType==CEntityProperty::EPT_ENTITYPTR &&
|
|
|
|
|
epProperty.ep_strName!=NULL &&
|
|
|
|
|
CTString(epProperty.ep_strName)!="")
|
|
|
|
|
{
|
|
|
|
|
// obtain property ptr
|
|
|
|
|
CEntity *penTarget = ENTITYPROPERTY( &*iten, epProperty.ep_slOffset, CEntityPointer);
|
|
|
|
|
if( penTarget != NULL)
|
|
|
|
|
{
|
|
|
|
|
// add it to container
|
|
|
|
|
dcEntities.Add( penTarget);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// for all entities in dynamic container
|
|
|
|
|
FOREACHINDYNAMICCONTAINER( dcEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// if not yet selected
|
|
|
|
|
if( !iten->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *iten);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectInvalidTris()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
// for each entity in the world
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten) {
|
|
|
|
|
// if it is brush entity
|
|
|
|
|
if (iten->en_RenderType == CEntity::RT_BRUSH) {
|
|
|
|
|
// for each mip in its brush
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) {
|
|
|
|
|
// for all sectors in this mip
|
|
|
|
|
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
|
|
|
|
|
// for all polygons in sector
|
|
|
|
|
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo) {
|
|
|
|
|
// if it has invalid triangles
|
|
|
|
|
if ((itbpo->bpo_ulFlags&BPOF_INVALIDTRIANGLES)&&
|
|
|
|
|
!(itbpo->IsSelected(BPOF_SELECTED))) {
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selPolygonSelection.Select( *itbpo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CWorldEditorView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
|
|
|
|
|
{
|
|
|
|
|
INDEX iCount = zDelta/120;
|
|
|
|
|
|
|
|
|
|
BOOL bSpace = (GetKeyState( ' ') & 128) != 0;
|
|
|
|
|
BOOL bCtrl = nFlags & MK_CONTROL;
|
|
|
|
|
BOOL bAlt = (GetKeyState( VK_MENU)&0x8000) != 0;
|
|
|
|
|
BOOL bShift = (GetKeyState( VK_SHIFT)&0x8000) != 0;
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
ASSERT_VALID(pDoc);
|
|
|
|
|
|
|
|
|
|
// ctrl + mouse wheel toggle modes
|
|
|
|
|
/*
|
|
|
|
|
if( bCtrl && !bSpace && !bShift && !bAlt)
|
|
|
|
|
{
|
|
|
|
|
for( INDEX iKnee=0; iKnee<Abs(iCount); iKnee++)
|
|
|
|
|
{
|
|
|
|
|
if(iCount<0)
|
|
|
|
|
{
|
|
|
|
|
switch(pDoc->GetEditingMode())
|
|
|
|
|
{
|
|
|
|
|
case( ENTITY_MODE):
|
|
|
|
|
{
|
|
|
|
|
pDoc->SetEditingMode( SECTOR_MODE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case( SECTOR_MODE):
|
|
|
|
|
{
|
|
|
|
|
pDoc->SetEditingMode( POLYGON_MODE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case( POLYGON_MODE):
|
|
|
|
|
{
|
|
|
|
|
pDoc->SetEditingMode( VERTEX_MODE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case( VERTEX_MODE):
|
|
|
|
|
{
|
|
|
|
|
pDoc->SetEditingMode( TERRAIN_MODE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case( TERRAIN_MODE):
|
|
|
|
|
{
|
|
|
|
|
pDoc->SetEditingMode( ENTITY_MODE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch(pDoc->GetEditingMode())
|
|
|
|
|
{
|
|
|
|
|
case( ENTITY_MODE):
|
|
|
|
|
{
|
|
|
|
|
pDoc->SetEditingMode( TERRAIN_MODE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case( SECTOR_MODE):
|
|
|
|
|
{
|
|
|
|
|
pDoc->SetEditingMode( ENTITY_MODE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case( POLYGON_MODE):
|
|
|
|
|
{
|
|
|
|
|
pDoc->SetEditingMode( SECTOR_MODE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case( VERTEX_MODE):
|
|
|
|
|
{
|
|
|
|
|
pDoc->SetEditingMode( POLYGON_MODE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case( TERRAIN_MODE):
|
|
|
|
|
{
|
|
|
|
|
pDoc->SetEditingMode( VERTEX_MODE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
// space+ctrl+lmb zoomes in 2x
|
|
|
|
|
if( bSpace && bCtrl)
|
|
|
|
|
{
|
|
|
|
|
BOOL bHitModels = (pDoc->GetEditingMode() == ENTITY_MODE) || bSpace;
|
|
|
|
|
BOOL bHitFields = (pDoc->GetEditingMode() == ENTITY_MODE) || bSpace;
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse, FALSE, bHitModels, bHitFields);
|
|
|
|
|
// set new target
|
|
|
|
|
GetChildFrame()->m_mvViewer.SetTargetPlacement( crRayHit.cr_vHit);
|
|
|
|
|
// move mouse to center of screen
|
|
|
|
|
CPoint ptCenter = CPoint( m_pdpDrawPort->GetWidth()/2, m_pdpDrawPort->GetHeight()/2);
|
|
|
|
|
ClientToScreen( &ptCenter);
|
|
|
|
|
SetCursorPos(ptCenter.x, ptCenter.y);
|
|
|
|
|
OnZoomMore();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
m_ptMouseDown = ptCenter;
|
|
|
|
|
|
|
|
|
|
for( INDEX iKnee=0; iKnee<Abs(iCount); iKnee++)
|
|
|
|
|
{
|
|
|
|
|
if(iCount<0) OnZoomLess();
|
|
|
|
|
else OnZoomMore();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for( INDEX iKnee=0; iKnee<Abs(iCount); iKnee++)
|
|
|
|
|
{
|
|
|
|
|
if(iCount<0) PostMessage( WM_COMMAND, ID_PREVIOUS, 0);
|
|
|
|
|
else PostMessage( WM_COMMAND, ID_NEXT, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CView::OnMouseWheel(nFlags, zDelta, pt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectSectorsOtherSide()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon->bpo_ulFlags & BPOF_PORTAL))
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygon &bpo = *crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
// for all sectors behind portal
|
|
|
|
|
{FOREACHDSTOFSRC(bpo.bpo_rsOtherSideSectors, CBrushSector, bsc_rdOtherSidePortals, pbsc)
|
|
|
|
|
if( !pbsc->IsSelected( BSCF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selSectorSelection.Select( *pbsc);
|
|
|
|
|
}
|
|
|
|
|
ENDFOR}
|
|
|
|
|
|
|
|
|
|
pDoc->SetEditingMode( SECTOR_MODE);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectLinksToSector()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL))
|
|
|
|
|
{
|
|
|
|
|
CBrushSector &bsc = *crRayHit.cr_pbpoBrushPolygon->bpo_pbscSector;
|
|
|
|
|
|
|
|
|
|
// for all sectors behind portal
|
|
|
|
|
{FOREACHSRCOFDST(bsc.bsc_rdOtherSidePortals, CBrushPolygon, bpo_rsOtherSideSectors, pbpo)
|
|
|
|
|
if( !pbpo->IsSelected( BPOF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selPolygonSelection.Select( *pbpo);
|
|
|
|
|
}
|
|
|
|
|
ENDFOR}
|
|
|
|
|
|
|
|
|
|
pDoc->SetEditingMode( POLYGON_MODE);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRemainSelectedByOrientation()
|
|
|
|
|
{
|
|
|
|
|
OnRemainSelectedByOrientation(TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRemainSelectedbyOrientationSingle()
|
|
|
|
|
{
|
|
|
|
|
OnRemainSelectedByOrientation(FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRemainSelectedByOrientation(BOOL bBothSides)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
CBrushPolygon *pbpoPolygon = crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(pbpoPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D vReference = pbpoPolygon->bpo_pbplPlane->bpl_plAbsolute;
|
|
|
|
|
// copy polygon selection to container
|
|
|
|
|
CDynamicContainer<CBrushPolygon> dcTemp;
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
dcTemp.Add( itbpo);
|
|
|
|
|
}}
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER( dcTemp, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
FLOAT fCos;
|
|
|
|
|
if( bBothSides)
|
|
|
|
|
{
|
|
|
|
|
fCos = Abs(vReference % itbpo->bpo_pbplPlane->bpl_plAbsolute);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fCos = vReference % itbpo->bpo_pbplPlane->bpl_plAbsolute;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( fCos > CosFast(360.0f/8.0f))
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selPolygonSelection.Select( *itbpo);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDeselectByOrientation()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
CBrushPolygon *pbpoPolygon = crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(pbpoPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D vReference = pbpoPolygon->bpo_pbplPlane->bpl_plAbsolute;
|
|
|
|
|
// copy polygon selection to container
|
|
|
|
|
CDynamicContainer<CBrushPolygon> dcTemp;
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
dcTemp.Add( itbpo);
|
|
|
|
|
}}
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER( dcTemp, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
FLOAT fCos = Abs(vReference % itbpo->bpo_pbplPlane->bpl_plAbsolute);
|
|
|
|
|
if( fCos < CosFast(360.0f/8.0f))
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selPolygonSelection.Select( *itbpo);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnReoptimizeBrushes()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
CWaitCursor wc;
|
|
|
|
|
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->ClearSelections();
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
CEntity *penEntityHit = crRayHit.cr_penHit;
|
|
|
|
|
BOOL bSelected = crRayHit.cr_penHit->IsSelected( ENF_SELECTED);
|
|
|
|
|
|
|
|
|
|
if( bSelected && (pDoc->GetEditingMode() == ENTITY_MODE))
|
|
|
|
|
{
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
if (iten->en_RenderType == CEntity::RT_BRUSH)
|
|
|
|
|
{
|
|
|
|
|
CBrush3D *pbrBrush = iten->GetBrush();
|
|
|
|
|
// for each mip in the brush
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, pbrBrush->br_lhBrushMips, itbm)
|
|
|
|
|
{
|
|
|
|
|
// reoptimize it
|
|
|
|
|
itbm->Reoptimize();
|
|
|
|
|
}
|
|
|
|
|
DiscardShadows( &*iten);
|
|
|
|
|
if( iten->GetFlags() & ENF_ZONING)
|
|
|
|
|
{
|
|
|
|
|
pbrBrush->SwitchToZoning();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pbrBrush->SwitchToNonZoning();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (penEntityHit->en_RenderType == CEntity::RT_BRUSH)
|
|
|
|
|
{
|
|
|
|
|
CBrush3D *pbrBrush = penEntityHit->GetBrush();
|
|
|
|
|
// for each mip in the brush
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, pbrBrush->br_lhBrushMips, itbm)
|
|
|
|
|
{
|
|
|
|
|
// reoptimize it
|
|
|
|
|
itbm->Reoptimize();
|
|
|
|
|
}
|
|
|
|
|
DiscardShadows( penEntityHit);
|
|
|
|
|
if( penEntityHit->GetFlags() & ENF_ZONING)
|
|
|
|
|
{
|
|
|
|
|
pbrBrush->SwitchToZoning();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pbrBrush->SwitchToNonZoning();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// automaticly update portal links
|
|
|
|
|
pDoc->m_woWorld.RebuildLinks();
|
|
|
|
|
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
}
|
|
|
|
|
// ray-hit didn't hit any entity, reoptimize the whole world
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// for each entity in the world
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// if it is brush entity
|
|
|
|
|
if (iten->en_RenderType == CEntity::RT_BRUSH)
|
|
|
|
|
{
|
|
|
|
|
CBrush3D *pbrBrush = iten->GetBrush();
|
|
|
|
|
// for each mip in the brush
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, pbrBrush->br_lhBrushMips, itbm)
|
|
|
|
|
{
|
|
|
|
|
// reoptimize it
|
|
|
|
|
itbm->Reoptimize();
|
|
|
|
|
}
|
|
|
|
|
DiscardShadows( iten);
|
|
|
|
|
if( iten->GetFlags() & ENF_ZONING)
|
|
|
|
|
{
|
|
|
|
|
pbrBrush->SwitchToZoning();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pbrBrush->SwitchToNonZoning();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnMergeVertices()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pDoc->RememberUndo();
|
|
|
|
|
pDoc->ClearSelections( ST_VERTEX);
|
|
|
|
|
|
|
|
|
|
CDynamicContainer<CBrushVertex> cbvxAllreadyDone;
|
|
|
|
|
|
|
|
|
|
DOUBLE3D vMergeToVertex;
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
|
|
|
|
|
{
|
|
|
|
|
vMergeToVertex = FLOATtoDOUBLE(itbvx->bvx_vAbsolute);
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// deselect vertices that are on right spot, to avoid unnecessary triangularisation
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
|
|
|
|
|
{
|
|
|
|
|
if( FLOATtoDOUBLE(itbvx->bvx_vAbsolute) == vMergeToVertex)
|
|
|
|
|
{
|
|
|
|
|
cbvxAllreadyDone.Add(itbvx);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER( cbvxAllreadyDone, CBrushVertex, itbvx)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selVertexSelection.Deselect( *itbvx);
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// triangularize all influenced polygons
|
|
|
|
|
pDoc->m_woWorld.TriangularizeForVertices( pDoc->m_selVertexSelection);
|
|
|
|
|
|
|
|
|
|
// for each vertex
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER( pDoc->m_selVertexSelection, CBrushVertex, itbvx)
|
|
|
|
|
{
|
|
|
|
|
// set its new position
|
|
|
|
|
itbvx->SetAbsolutePosition( vMergeToVertex);
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// reselect vertices
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER( cbvxAllreadyDone, CBrushVertex, itbvx)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selVertexSelection.Select( *itbvx);
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// update sectors
|
|
|
|
|
pDoc->m_woWorld.UpdateSectorsDuringVertexChange( pDoc->m_selVertexSelection);
|
|
|
|
|
pDoc->m_woWorld.UpdateSectorsAfterVertexChange( pDoc->m_selVertexSelection);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnExportDisplaceMap()
|
|
|
|
|
{
|
|
|
|
|
CImageInfo ii;
|
|
|
|
|
|
|
|
|
|
CDlgDisplaceMapSize dlgDisplaceMapSize;
|
|
|
|
|
if( dlgDisplaceMapSize.DoModal() != IDOK)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// find bounding box of all selected polygons
|
|
|
|
|
FLOATaabbox3D boxSelection;
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
// calculate bounding box for all polygons
|
|
|
|
|
boxSelection |= itbpo->bpo_boxBoundingBox;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PIX pixWidth = dlgDisplaceMapSize.m_pixWidth;
|
|
|
|
|
PIX pixHeight = dlgDisplaceMapSize.m_pixHeight;
|
|
|
|
|
|
|
|
|
|
FLOAT fMinX = boxSelection.Min()(1);
|
|
|
|
|
FLOAT fMaxX = boxSelection.Max()(1);
|
|
|
|
|
FLOAT fMinY = boxSelection.Min()(2);
|
|
|
|
|
FLOAT fMaxY = boxSelection.Max()(2);
|
|
|
|
|
FLOAT fSizeY = boxSelection.Size()(2);
|
|
|
|
|
FLOAT fMinZ = boxSelection.Min()(3);
|
|
|
|
|
FLOAT fMaxZ = boxSelection.Max()(3);
|
|
|
|
|
FLOAT fDeltaX;
|
|
|
|
|
FLOAT fDeltaZ;
|
|
|
|
|
if (dlgDisplaceMapSize.m_bMidPixSample)
|
|
|
|
|
{
|
|
|
|
|
fDeltaX = (fMaxX-fMinX)/pixWidth;
|
|
|
|
|
fDeltaZ = (fMaxZ-fMinZ)/pixHeight;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fDeltaX = (fMaxX-fMinX-0.5f)/pixWidth;
|
|
|
|
|
fDeltaZ = (fMaxZ-fMinZ-0.5f)/pixHeight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CPrintF("Export displace map...\n");
|
|
|
|
|
CPrintF("Min: (%gf, %gf, %gf), Max: (%gf, %gf, %gf), Delta X=%g, Delta Z=%g\n",
|
|
|
|
|
fMinX, fMinY, fMinZ,
|
|
|
|
|
fMaxX, fMaxY, fMaxZ,
|
|
|
|
|
fDeltaX, fDeltaZ);
|
|
|
|
|
|
|
|
|
|
CTFileName fnDocName = CTString(CStringA(pDoc->GetPathName()));
|
|
|
|
|
CTFileName fnDirectory = fnDocName.FileDir();
|
|
|
|
|
CTFileName fnDefaultSelected = fnDocName.FileName()+CTString("DisplaceMap.tga");
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
fnDirectory.RemoveApplicationPath_t();
|
|
|
|
|
}
|
|
|
|
|
catch( char *str_err)
|
|
|
|
|
{
|
|
|
|
|
AfxMessageBox( CString(str_err));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// note: NULL given instead of profile string name, to avoid using last directory
|
|
|
|
|
CTFileName fnDisplaceMap =
|
|
|
|
|
_EngineGUI.FileRequester( "Select name to export displace map",
|
|
|
|
|
"Pictures (*.tga)\0*.tga\0" FILTER_END,
|
|
|
|
|
NULL, fnDirectory, fnDefaultSelected, NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
if( fnDisplaceMap == "") return;
|
|
|
|
|
|
|
|
|
|
ULONG ulSize = pixWidth*pixHeight*3;
|
|
|
|
|
UBYTE *pubPicture = (UBYTE *) AllocMemory( ulSize);
|
|
|
|
|
|
|
|
|
|
// initializes structure members and attaches pointer to image
|
|
|
|
|
ii.Attach( pubPicture, pixWidth, pixHeight, 24);
|
|
|
|
|
|
|
|
|
|
// for each line of pixels in height map
|
|
|
|
|
for( INDEX iY=0; iY<pixHeight; iY++)
|
|
|
|
|
{
|
|
|
|
|
// for each horizontal pixel in height map
|
|
|
|
|
for( INDEX iX=0; iX<pixWidth; iX++)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
FLOAT fX;
|
|
|
|
|
FLOAT fZ;
|
|
|
|
|
|
|
|
|
|
// calculate coordinate in world
|
|
|
|
|
if (dlgDisplaceMapSize.m_bMidPixSample)
|
|
|
|
|
{
|
|
|
|
|
fX = fMinX+fDeltaX*iX+fDeltaX/2;
|
|
|
|
|
fZ = fMinZ+fDeltaZ*iY+fDeltaZ/2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fX = fMinX+fDeltaX*iX+0.1;
|
|
|
|
|
fZ = fMinZ+fDeltaZ*iY+0.1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cast ray to recive height
|
|
|
|
|
CCastRay crRayHit = CCastRay( NULL, CPlacement3D(FLOAT3D(fX, fMaxY+1.0f, fZ), ANGLE3D(0,-90,0)) );
|
|
|
|
|
crRayHit.cr_bAllowOverHit = TRUE;
|
|
|
|
|
crRayHit.cr_bHitPortals = FALSE;
|
|
|
|
|
crRayHit.cr_ttHitModels = CCastRay::TT_NONE;
|
|
|
|
|
// cast ray, go for hit data
|
|
|
|
|
pDoc->m_woWorld.CastRay( crRayHit);
|
|
|
|
|
|
|
|
|
|
if (!dlgDisplaceMapSize.m_bHighResolution){
|
|
|
|
|
// set black pixel if nothing hit
|
|
|
|
|
UBYTE ubPixelColor = 0;
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
FLOAT fYHit = crRayHit.cr_vHit(2);
|
|
|
|
|
ubPixelColor = (UBYTE) ((fYHit-fMinY)/fSizeY*255.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UBYTE *pPixel=pubPicture+iY*pixWidth*3+iX*3;
|
|
|
|
|
*(pPixel+0) = ubPixelColor;
|
|
|
|
|
*(pPixel+1) = ubPixelColor;
|
|
|
|
|
*(pPixel+2) = ubPixelColor;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// set black pixel if nothing hit
|
|
|
|
|
unsigned short usPixelColor = 0;
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
FLOAT fYHit = crRayHit.cr_vHit(2);
|
|
|
|
|
usPixelColor = (unsigned short) ((fYHit-fMinY)/fSizeY*65535);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UBYTE *pPixel=pubPicture+iY*pixWidth*3+iX*3;
|
|
|
|
|
*(pPixel+0) = 0;
|
|
|
|
|
*(pPixel+1) = usPixelColor>>8;
|
|
|
|
|
*(pPixel+2) = usPixelColor&0xFF;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// try to
|
|
|
|
|
try {
|
|
|
|
|
// save displace map as TGA
|
|
|
|
|
ii.SaveTGA_t( fnDisplaceMap);
|
|
|
|
|
} // if failed
|
|
|
|
|
catch (char *strError) {
|
|
|
|
|
// report error
|
|
|
|
|
AfxMessageBox(CString(strError));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCutMode()
|
|
|
|
|
{
|
|
|
|
|
// if we should enter cut mode
|
|
|
|
|
if( !theApp.m_bCutModeOn)
|
|
|
|
|
{
|
|
|
|
|
CTString strError;
|
|
|
|
|
BOOL bCutEnabled = IsCutEnabled( strError);
|
|
|
|
|
if( !bCutEnabled)
|
|
|
|
|
{
|
|
|
|
|
// warn user
|
|
|
|
|
WarningMessage( "%s", strError);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
theApp.m_bCutModeOn = !theApp.m_bCutModeOn;
|
|
|
|
|
theApp.m_bMeasureModeOn = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateCutMode(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
// cut is enabled only in sector and polygon mode
|
|
|
|
|
if( (pDoc->GetEditingMode() == POLYGON_MODE) ||
|
|
|
|
|
(pDoc->GetEditingMode() == ENTITY_MODE) ||
|
|
|
|
|
(pDoc->GetEditingMode() == SECTOR_MODE) )
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( TRUE);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( FALSE);
|
|
|
|
|
}
|
|
|
|
|
pCmdUI->SetCheck( theApp.m_bCutModeOn);
|
|
|
|
|
//pDoc->UpdateAllViews( NULL); !!!!!!!!!!!!!!!!!!!!! unbelievable !!!!!!!!!!!!!!!!!
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CWorldEditorView::IsCutEnabled(CTString &strError)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
if( pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
// there must be at least one entity in selection
|
|
|
|
|
if( pDoc->m_selEntitySelection.Count() == 0)
|
|
|
|
|
{
|
|
|
|
|
strError = "You must select entity(s) that you want to mirror!";
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
// there must be at least one polygon in selection
|
|
|
|
|
if( pDoc->m_selPolygonSelection.Count() == 0)
|
|
|
|
|
{
|
|
|
|
|
strError = "You must select polygon(s) that you want to cut!";
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
// all polygons must be of the same brush
|
|
|
|
|
CBrush3D *pbrBrush = NULL;
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
// remember first polygon's brush
|
|
|
|
|
if( pbrBrush == NULL)
|
|
|
|
|
{
|
|
|
|
|
pbrBrush = itbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// if any of the other polygons are not from same brush
|
|
|
|
|
if( pbrBrush != itbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush)
|
|
|
|
|
{
|
|
|
|
|
// don't allow cut
|
|
|
|
|
strError = "All polygons must be from the same brush to be able to cut them!";
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(pDoc->GetEditingMode() == SECTOR_MODE)
|
|
|
|
|
{
|
|
|
|
|
// there must be at least one sector in selection
|
|
|
|
|
if( pDoc->m_selSectorSelection.Count() == 0)
|
|
|
|
|
{
|
|
|
|
|
strError = "You must select sector(s) that you want to cut!";
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
// all sectors must be of the same brush
|
|
|
|
|
CBrush3D *pbrBrush = NULL;
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
// remember first sector's brush
|
|
|
|
|
if( pbrBrush == NULL)
|
|
|
|
|
{
|
|
|
|
|
pbrBrush = itbsc->bsc_pbmBrushMip->bm_pbrBrush;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// if any of the other sectors are not from same brush
|
|
|
|
|
if( pbrBrush != itbsc->bsc_pbmBrushMip->bm_pbrBrush)
|
|
|
|
|
{
|
|
|
|
|
// don't allow cut
|
|
|
|
|
strError = "All sector must be from the same brush to be able to cut them!";
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateSelectClones(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// allow clone selecting only if we have only one entity selected
|
|
|
|
|
if( pDoc->m_selEntitySelection.Count() == 1)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( TRUE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pCmdUI->Enable( FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectClones()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CEntity *pen = pDoc->m_selEntitySelection.GetFirstInSelection();
|
|
|
|
|
|
|
|
|
|
// for each entity in the world
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// if has same name
|
|
|
|
|
if( pen->GetName() == iten->GetName() )
|
|
|
|
|
{
|
|
|
|
|
// if is not yet selected
|
|
|
|
|
if( !iten->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *iten);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CWorldEditorView::IsSelectClonesOnContextEnabled( void)
|
|
|
|
|
{
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectClonesOnContext()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
// get hitted entity
|
|
|
|
|
CEntity *pen = crRayHit.cr_penHit;
|
|
|
|
|
|
|
|
|
|
// for each entity in the world
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// if has same name
|
|
|
|
|
if( pen->GetName() == iten->GetName() )
|
|
|
|
|
{
|
|
|
|
|
// if is not yet selected
|
|
|
|
|
if( !iten->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *iten);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyCtrlShiftE()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if(pDoc->GetEditingMode()==TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
ApplyEqualizeOntoTerrain();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OnSelectOfSameClass();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectOfSameClass()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CEntity *pen = pDoc->m_selEntitySelection.GetFirstInSelection();
|
|
|
|
|
|
|
|
|
|
// to hold entities for selecting
|
|
|
|
|
CDynamicContainer<CEntity> dcEntities;
|
|
|
|
|
|
|
|
|
|
// for all selected entities
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
dcEntities.Add( &*iten);
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// for each non-hidden entity in the world
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CBrushSector *pbscSector = iten->GetFirstSector();
|
|
|
|
|
BOOL bSectorVisible = (pbscSector == NULL) ||
|
|
|
|
|
!(pbscSector->bsc_ulFlags & BSCF_HIDDEN);
|
|
|
|
|
// if it isn't classified in hidden sector and is not hidden itself
|
|
|
|
|
if( !bSectorVisible || (iten->en_ulFlags&ENF_HIDDEN) )
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// obtain this entity's class ptr
|
|
|
|
|
CEntityClass *pdecClass = iten->GetClass();
|
|
|
|
|
|
|
|
|
|
// test all classes
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(dcEntities, CEntity, itenClass)
|
|
|
|
|
{
|
|
|
|
|
CEntityClass *pdecClassTest = itenClass->GetClass();
|
|
|
|
|
// if of same class
|
|
|
|
|
if( pdecClassTest == pdecClass)
|
|
|
|
|
{
|
|
|
|
|
// if not yet selected
|
|
|
|
|
if( !iten->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *iten);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectOfSameClassOnContext()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
// get hitted entity
|
|
|
|
|
CEntity *pen = crRayHit.cr_penHit;
|
|
|
|
|
// obtain this entity's class ptr
|
|
|
|
|
CEntityClass *pdecClassTest = pen->GetClass();
|
|
|
|
|
|
|
|
|
|
// for each non-hidden entity in the world
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CBrushSector *pbscSector = iten->GetFirstSector();
|
|
|
|
|
BOOL bSectorVisible = (pbscSector == NULL) ||
|
|
|
|
|
!(pbscSector->bsc_ulFlags & BSCF_HIDDEN);
|
|
|
|
|
// if it isn't classified in hidden sector and is not hidden itself
|
|
|
|
|
if( !bSectorVisible || (iten->en_ulFlags&ENF_HIDDEN) )
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CEntityClass *pdecClass = iten->GetClass();
|
|
|
|
|
// if of same class
|
|
|
|
|
if( pdecClassTest == pdecClass)
|
|
|
|
|
{
|
|
|
|
|
// if not yet selected
|
|
|
|
|
if( !iten->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *iten);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CWorldEditorView::IsSelectOfSameClassOnContextEnabled( void)
|
|
|
|
|
{
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
if( crRayHit.cr_penHit != NULL)
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// limit current frame rate if neeeded
|
|
|
|
|
void LimitFrameRate(void)
|
|
|
|
|
{
|
|
|
|
|
// measure passed time for each loop
|
|
|
|
|
/*
|
|
|
|
|
static CTimerValue tvLast(-1.0f);
|
|
|
|
|
CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
|
|
|
|
|
TIME tmCurrentDelta = (tvNow-tvLast).GetSeconds();
|
|
|
|
|
|
|
|
|
|
// limit maximum frame rate
|
|
|
|
|
wed_iMaxFPSActive = ClampDn( (INDEX)wed_iMaxFPSActive, 1L);
|
|
|
|
|
TIME tmWantedDelta = 1.0f / wed_iMaxFPSActive;
|
|
|
|
|
if( tmCurrentDelta<tmWantedDelta) Sleep( (tmWantedDelta-tmCurrentDelta)*1000.0f);
|
|
|
|
|
|
|
|
|
|
// remember new time
|
|
|
|
|
tvLast = _pTimer->GetHighPrecisionTimer();*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::ApplyFreeModeControls( CPlacement3D &pl, ANGLE3D &aAbs, FLOAT &fSpeedMultiplier, BOOL bPrescan)
|
|
|
|
|
{
|
|
|
|
|
CChildFrame *pcf = GetChildFrame();
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
#define FB_SPEED 1.0f
|
|
|
|
|
#define LR_SPEED 1.0f
|
|
|
|
|
#define UD_SPEED 1.0f
|
|
|
|
|
#define ROT_SPEED 0.75f
|
|
|
|
|
|
|
|
|
|
FLOAT fFB = 0.0f; // forward/backward movement
|
|
|
|
|
FLOAT fLR = 0.0f; // left/right movement
|
|
|
|
|
FLOAT fUD = 0.0f; // up/down movement
|
|
|
|
|
FLOAT fRLR = 0.0f; // rotate left/right
|
|
|
|
|
FLOAT fRUD = 0.0f; // rotate up/down
|
|
|
|
|
|
|
|
|
|
_pInput->GetInput(bPrescan);
|
|
|
|
|
|
|
|
|
|
if (!bPrescan) {
|
|
|
|
|
// additional key indentifiers are not on
|
|
|
|
|
BOOL bShift = _pInput->GetButtonState( KID_LSHIFT) || _pInput->GetButtonState( KID_RSHIFT);
|
|
|
|
|
BOOL bAlt = _pInput->GetButtonState( KID_LALT) || _pInput->GetButtonState( KID_RALT);
|
|
|
|
|
BOOL bCtrl = _pInput->GetButtonState( KID_LCONTROL) || _pInput->GetButtonState( KID_RCONTROL);
|
|
|
|
|
|
|
|
|
|
// apply view configuration from first perspective view of child configuration
|
|
|
|
|
if(_pInput->GetButtonState( KID_NUM0)) pcf->ApplySettingsFromPerspectiveView( this, 0);
|
|
|
|
|
if(_pInput->GetButtonState( KID_NUM1)) pcf->ApplySettingsFromPerspectiveView( this, 1);
|
|
|
|
|
if(_pInput->GetButtonState( KID_NUM2)) pcf->ApplySettingsFromPerspectiveView( this, 2);
|
|
|
|
|
if(_pInput->GetButtonState( KID_NUM3)) pcf->ApplySettingsFromPerspectiveView( this, 3);
|
|
|
|
|
if(_pInput->GetButtonState( KID_NUM4)) pcf->ApplySettingsFromPerspectiveView( this, 4);
|
|
|
|
|
if(_pInput->GetButtonState( KID_NUM5)) pcf->ApplySettingsFromPerspectiveView( this, 5);
|
|
|
|
|
if(_pInput->GetButtonState( KID_NUM6)) pcf->ApplySettingsFromPerspectiveView( this, 6);
|
|
|
|
|
if(_pInput->GetButtonState( KID_NUM7)) pcf->ApplySettingsFromPerspectiveView( this, 7);
|
|
|
|
|
if(_pInput->GetButtonState( KID_NUM8)) pcf->ApplySettingsFromPerspectiveView( this, 8);
|
|
|
|
|
if(_pInput->GetButtonState( KID_NUM9)) pcf->ApplySettingsFromPerspectiveView( this, 9);
|
|
|
|
|
|
|
|
|
|
// apply view configuration from available buffers
|
|
|
|
|
if(_pInput->GetButtonState( KID_0)) OnKeyBuffer( ID_BUFFER10);
|
|
|
|
|
if(_pInput->GetButtonState( KID_1)) OnKeyBuffer( ID_BUFFER01);
|
|
|
|
|
if(_pInput->GetButtonState( KID_2)) OnKeyBuffer( ID_BUFFER02);
|
|
|
|
|
if(_pInput->GetButtonState( KID_3)) OnKeyBuffer( ID_BUFFER03);
|
|
|
|
|
if(_pInput->GetButtonState( KID_4)) OnKeyBuffer( ID_BUFFER04);
|
|
|
|
|
if(_pInput->GetButtonState( KID_5)) OnKeyBuffer( ID_BUFFER05);
|
|
|
|
|
if(_pInput->GetButtonState( KID_6)) OnKeyBuffer( ID_BUFFER06);
|
|
|
|
|
if(_pInput->GetButtonState( KID_7)) OnKeyBuffer( ID_BUFFER07);
|
|
|
|
|
if(_pInput->GetButtonState( KID_8)) OnKeyBuffer( ID_BUFFER08);
|
|
|
|
|
if(_pInput->GetButtonState( KID_9)) OnKeyBuffer( ID_BUFFER09);
|
|
|
|
|
|
|
|
|
|
// ---------- Simulate moving as in fly mode
|
|
|
|
|
// forward
|
|
|
|
|
if(
|
|
|
|
|
_pInput->GetButtonState( KID_W) ||
|
|
|
|
|
_pInput->GetButtonState( KID_MOUSE2) ||
|
|
|
|
|
_pInput->GetButtonState( KID_ARROWUP))
|
|
|
|
|
{
|
|
|
|
|
fFB = -FB_SPEED*fSpeedMultiplier;
|
|
|
|
|
}
|
|
|
|
|
// backward
|
|
|
|
|
if(
|
|
|
|
|
_pInput->GetButtonState( KID_S) ||
|
|
|
|
|
_pInput->GetButtonState( KID_MOUSE1) ||
|
|
|
|
|
_pInput->GetButtonState( KID_ARROWDOWN) )
|
|
|
|
|
{
|
|
|
|
|
fFB = +FB_SPEED*fSpeedMultiplier;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
if( _pInput->GetButtonState( KID_MOUSE1))
|
|
|
|
|
{
|
|
|
|
|
fLR = -_pInput->GetAxisRelative(1)/15.0f;
|
|
|
|
|
}*/
|
|
|
|
|
// strife left
|
|
|
|
|
if(
|
|
|
|
|
_pInput->GetButtonState( KID_Q) ||
|
|
|
|
|
_pInput->GetButtonState( KID_A) ||
|
|
|
|
|
_pInput->GetButtonState( KID_ARROWLEFT) )
|
|
|
|
|
{
|
|
|
|
|
fLR = -LR_SPEED*fSpeedMultiplier;
|
|
|
|
|
}
|
|
|
|
|
// strife right
|
|
|
|
|
if(
|
|
|
|
|
_pInput->GetButtonState( KID_E) ||
|
|
|
|
|
_pInput->GetButtonState( KID_D) ||
|
|
|
|
|
_pInput->GetButtonState( KID_ARROWRIGHT) )
|
|
|
|
|
{
|
|
|
|
|
fLR = +LR_SPEED*fSpeedMultiplier;
|
|
|
|
|
}
|
|
|
|
|
// up
|
|
|
|
|
if( (_pInput->GetButtonState( KID_R) && !bAlt) ||
|
|
|
|
|
_pInput->GetButtonState( KID_SPACE) )
|
|
|
|
|
{
|
|
|
|
|
fUD = +UD_SPEED*fSpeedMultiplier;
|
|
|
|
|
}
|
|
|
|
|
// down
|
|
|
|
|
if( _pInput->GetButtonState( KID_F))
|
|
|
|
|
{
|
|
|
|
|
fUD = -UD_SPEED*fSpeedMultiplier;
|
|
|
|
|
}
|
|
|
|
|
// drop marker here
|
|
|
|
|
if( _pInput->GetButtonState( KID_C))
|
|
|
|
|
{
|
|
|
|
|
CTFileName fnDropClass;
|
|
|
|
|
CTString strTargetProperty;
|
|
|
|
|
if(pDoc->m_selEntitySelection.Count() == 1)
|
|
|
|
|
{
|
|
|
|
|
CEntity &enOnly = pDoc->m_selEntitySelection.GetFirst();
|
|
|
|
|
if(enOnly.DropsMarker( fnDropClass, strTargetProperty))
|
|
|
|
|
{
|
|
|
|
|
OnDropMarker(pl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOL bLastTurboDown = FALSE;
|
|
|
|
|
static FLOAT fSpeedMultiplierBeforeTurbo = 1.0f;
|
|
|
|
|
if( _pInput->GetButtonState( KID_TAB))
|
|
|
|
|
{
|
|
|
|
|
if( !bLastTurboDown)
|
|
|
|
|
{
|
|
|
|
|
fSpeedMultiplierBeforeTurbo = fSpeedMultiplier;
|
|
|
|
|
}
|
|
|
|
|
bLastTurboDown = TRUE;
|
|
|
|
|
fSpeedMultiplier = Clamp( fSpeedMultiplier+0.5f, 1.0f, 20.0f);
|
|
|
|
|
}
|
|
|
|
|
else if( bLastTurboDown)
|
|
|
|
|
{
|
|
|
|
|
bLastTurboDown = FALSE;
|
|
|
|
|
fSpeedMultiplier = fSpeedMultiplierBeforeTurbo;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// get current rotation
|
|
|
|
|
fRLR = _pInput->GetAxisValue(1)*ROT_SPEED;
|
|
|
|
|
fRUD = -_pInput->GetAxisValue(2)*ROT_SPEED;
|
|
|
|
|
|
|
|
|
|
// apply translation
|
|
|
|
|
if (!bPrescan) {
|
|
|
|
|
pl.Translate_OwnSystem( FLOAT3D(fLR, fUD, fFB));
|
|
|
|
|
// apply rotation
|
|
|
|
|
pl.pl_OrientationAngle = aAbs;//.Rotate_HPB( ANGLE3D(-fRLR, -fRUD, 0));
|
|
|
|
|
}
|
|
|
|
|
aAbs+=ANGLE3D(-fRLR, -fRUD, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// placements and orientation used in free fly mode
|
|
|
|
|
static CPlacement3D _plNew;
|
|
|
|
|
static CPlacement3D _plOld;
|
|
|
|
|
static ANGLE3D _aAbs;
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::PumpWindowsMessagesInFreeMode(BOOL &bRunning, FLOAT &fSpeedMultiplier)
|
|
|
|
|
{
|
|
|
|
|
CChildFrame *pcf = GetChildFrame();
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
// additional key indentifiers are not on
|
|
|
|
|
BOOL bShift = _pInput->GetButtonState( KID_LSHIFT) || _pInput->GetButtonState( KID_RSHIFT);
|
|
|
|
|
BOOL bAlt = _pInput->GetButtonState( KID_LALT) || _pInput->GetButtonState( KID_RALT);
|
|
|
|
|
BOOL bCtrl = _pInput->GetButtonState( KID_LCONTROL) || _pInput->GetButtonState( KID_RCONTROL);
|
|
|
|
|
// while there are any messages in the message queue
|
|
|
|
|
MSG msg;
|
|
|
|
|
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
|
|
|
{
|
|
|
|
|
// process scripts that are invoked on shortcuts from within WED
|
|
|
|
|
ProcesWEDConsoleShortcuts( &msg);
|
|
|
|
|
|
|
|
|
|
if(msg.message==_uiMessengerMsg)
|
|
|
|
|
{
|
|
|
|
|
// if one application allready started
|
|
|
|
|
HWND hwndMessenger = ::FindWindow(NULL, L"Croteam Messenger");
|
|
|
|
|
if(hwndMessenger != NULL)
|
|
|
|
|
{
|
|
|
|
|
// force messenger to popup
|
|
|
|
|
::PostMessage( hwndMessenger, _uiMessengerForcePopup, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- Simulate some important commands of wed
|
|
|
|
|
if( msg.message==WM_KEYDOWN || msg.message==WM_SYSKEYDOWN)
|
|
|
|
|
{
|
|
|
|
|
// 'G' links on/off
|
|
|
|
|
if( msg.wParam=='G' && !bCtrl) pcf->OnRenderTargets();
|
|
|
|
|
// 'G' links on/off
|
|
|
|
|
if( msg.wParam=='G' && bCtrl) pcf->OnToggleEntityNames();
|
|
|
|
|
// 'H' shadow on off
|
|
|
|
|
if( msg.wParam=='H') pcf->OnViewShadowsOnoff();
|
|
|
|
|
// 'Num -' toggle frame rate
|
|
|
|
|
if( msg.wParam == VK_SUBTRACT) pcf->OnSceneRenderingTime();
|
|
|
|
|
// 'B' toggle auto mip leveling
|
|
|
|
|
if( msg.wParam=='B') pcf->OnAutoMipLeveling();
|
|
|
|
|
// 'Alt+R' toggle frame rate
|
|
|
|
|
if( msg.wParam=='R' && bAlt) pcf->OnSceneRenderingTime();
|
|
|
|
|
// 'Shift+Backspace' center background viewer
|
|
|
|
|
if( (msg.wParam == VK_BACK) && bShift)
|
|
|
|
|
{
|
|
|
|
|
OnCenterBcgViewer();
|
|
|
|
|
_plNew = pcf->m_mvViewer.mv_plViewer;
|
|
|
|
|
_plOld = _plNew;
|
|
|
|
|
_aAbs = _plNew.pl_OrientationAngle;
|
|
|
|
|
}
|
|
|
|
|
// 'Backspace' center to 0
|
|
|
|
|
else if( msg.wParam == VK_BACK)
|
|
|
|
|
{
|
|
|
|
|
OnResetViewer();
|
|
|
|
|
_plNew = pcf->m_mvViewer.mv_plViewer;
|
|
|
|
|
_plOld = _plNew;
|
|
|
|
|
_aAbs = _plNew.pl_OrientationAngle;
|
|
|
|
|
}
|
|
|
|
|
// 'F5, F6, F7, F8' type of projections
|
|
|
|
|
if( (msg.wParam == VK_F5) && bShift) OnIsometricBottom();
|
|
|
|
|
else if( msg.wParam == VK_F5) OnIsometricTop();
|
|
|
|
|
if( (msg.wParam == VK_F6) && bShift) OnIsometricLeft();
|
|
|
|
|
else if( msg.wParam == VK_F6) OnIsometricRight();
|
|
|
|
|
if( (msg.wParam == VK_F7) && bShift) OnIsometricBack();
|
|
|
|
|
else if( msg.wParam == VK_F7) OnIsometricFront();
|
|
|
|
|
if( (msg.wParam == VK_F8)) OnPerspective();
|
|
|
|
|
// 'Home', 'End', 'Page Up', 'Page Dn' 'Ctrl+' combinations for storing and restoring positions
|
|
|
|
|
if( (msg.wParam == VK_HOME) && bCtrl) pcf->OnStorePosition01();
|
|
|
|
|
else if( msg.wParam == VK_HOME)
|
|
|
|
|
{
|
|
|
|
|
pcf->OnRestorePosition01();
|
|
|
|
|
_plNew = pcf->m_mvViewer.mv_plViewer;
|
|
|
|
|
_plOld = _plNew;
|
|
|
|
|
_aAbs = _plNew.pl_OrientationAngle;
|
|
|
|
|
}
|
|
|
|
|
if( (msg.wParam == VK_END) && bCtrl) pcf->OnStorePosition02();
|
|
|
|
|
else if( msg.wParam == VK_END)
|
|
|
|
|
{
|
|
|
|
|
pcf->OnRestorePosition02();
|
|
|
|
|
_plNew = pcf->m_mvViewer.mv_plViewer;
|
|
|
|
|
_plOld = _plNew;
|
|
|
|
|
_aAbs = _plNew.pl_OrientationAngle;
|
|
|
|
|
}
|
|
|
|
|
if( (msg.wParam == VK_PRIOR) && bCtrl) pcf->OnStorePosition03();
|
|
|
|
|
else if( msg.wParam == VK_PRIOR)
|
|
|
|
|
{
|
|
|
|
|
pcf->OnRestorePosition03();
|
|
|
|
|
_plNew = pcf->m_mvViewer.mv_plViewer;
|
|
|
|
|
_plOld = _plNew;
|
|
|
|
|
_aAbs = _plNew.pl_OrientationAngle;
|
|
|
|
|
}
|
|
|
|
|
if( (msg.wParam == VK_NEXT) && bCtrl) pcf->OnStorePosition04();
|
|
|
|
|
else if( msg.wParam == VK_NEXT)
|
|
|
|
|
{
|
|
|
|
|
pcf->OnRestorePosition04();
|
|
|
|
|
_plNew = pcf->m_mvViewer.mv_plViewer;
|
|
|
|
|
_plOld = _plNew;
|
|
|
|
|
_aAbs = _plNew.pl_OrientationAngle;
|
|
|
|
|
}
|
|
|
|
|
// 'X', 'Alt+X', 'Alt+A' hide selected, unselected, show all
|
|
|
|
|
if( (msg.wParam == 'X') && bAlt) pDoc->OnHideUnselected();
|
|
|
|
|
else if( msg.wParam == 'X') pDoc->OnHideSelected();
|
|
|
|
|
if( (msg.wParam == 'A') && bAlt) pDoc->OnShowAll();
|
|
|
|
|
// 'Z' for toggle view selection
|
|
|
|
|
if( msg.wParam == 'Z') pcf->OnViewSelection();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// use mouse wheel to increase/decrease moving speed
|
|
|
|
|
if( msg.message==WM_MOUSEWHEEL)
|
|
|
|
|
{
|
|
|
|
|
short zDelta = (short) HIWORD(msg.wParam);
|
|
|
|
|
INDEX iCount = zDelta/120;
|
|
|
|
|
for( INDEX iKnee=0; iKnee<Abs(iCount); iKnee++)
|
|
|
|
|
{
|
|
|
|
|
if(iCount<0) fSpeedMultiplier/=2;
|
|
|
|
|
else fSpeedMultiplier*=2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if it is not a mouse message
|
|
|
|
|
if(!(msg.message>=WM_MOUSEFIRST&&msg.message<=WM_MOUSELAST))
|
|
|
|
|
{
|
|
|
|
|
// if not system key messages
|
|
|
|
|
if (!(msg.message==WM_KEYDOWN && msg.wParam==VK_F10
|
|
|
|
|
||msg.message==WM_SYSKEYDOWN))
|
|
|
|
|
{
|
|
|
|
|
// translate it
|
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
|
}
|
|
|
|
|
// if paint message
|
|
|
|
|
if (msg.message==WM_PAINT)
|
|
|
|
|
{
|
|
|
|
|
// dispatch it
|
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if should stop
|
|
|
|
|
if( (msg.message==WM_KEYDOWN && msg.wParam==VK_ESCAPE)
|
|
|
|
|
||(msg.message==WM_ACTIVATE)
|
|
|
|
|
||(msg.message==WM_CANCELMODE)
|
|
|
|
|
||(msg.message==WM_KILLFOCUS)
|
|
|
|
|
||(msg.message==WM_ACTIVATEAPP))
|
|
|
|
|
{
|
|
|
|
|
// stop running
|
|
|
|
|
bRunning = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAlternativeMovingMode()
|
|
|
|
|
{
|
|
|
|
|
INDEX iAllowMouseAcceleration = _pShell->GetINDEX("inp_bAllowMouseAcceleration");
|
|
|
|
|
INDEX iFilterMouse = _pShell->GetINDEX("inp_bFilterMouse");
|
|
|
|
|
|
|
|
|
|
_pShell->SetINDEX("inp_bAllowMouseAcceleration", 1);
|
|
|
|
|
_pShell->SetINDEX("inp_bFilterMouse", 1);
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CViewPrefs vpOrg = m_vpViewPrefs;
|
|
|
|
|
// obtain child frame ptr
|
|
|
|
|
CChildFrame *pcf = GetChildFrame();
|
|
|
|
|
_plNew = pcf->m_mvViewer.mv_plViewer;
|
|
|
|
|
_plOld = _plNew;
|
|
|
|
|
_aAbs = _plNew.pl_OrientationAngle;
|
|
|
|
|
|
|
|
|
|
BOOL bAutoMipBrushingBefore = pcf->m_bAutoMipBrushingOn;
|
|
|
|
|
BOOL bDisableVisibilityTweaksBefore = pcf->m_bDisableVisibilityTweaks;
|
|
|
|
|
|
|
|
|
|
// enable input
|
|
|
|
|
_pInput->EnableInput(m_pvpViewPort);
|
|
|
|
|
|
|
|
|
|
// initialy, game is running
|
|
|
|
|
BOOL bRunning = TRUE;
|
|
|
|
|
INDEX iLastTick = 0;
|
|
|
|
|
CTimerValue tvStart = _pTimer->GetHighPrecisionTimer();
|
|
|
|
|
|
|
|
|
|
// while it is still running
|
|
|
|
|
while( bRunning)
|
|
|
|
|
{
|
|
|
|
|
// process all windows messages
|
|
|
|
|
PumpWindowsMessagesInFreeMode( bRunning, _fFlyModeSpeedMultiplier);
|
|
|
|
|
|
|
|
|
|
CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
|
|
|
|
|
FLOAT fPassed = (tvNow-tvStart).GetSeconds();
|
|
|
|
|
INDEX iNowTick = INDEX(fPassed/_pTimer->TickQuantum);
|
|
|
|
|
// apply controls for frame rates below tick quantum
|
|
|
|
|
while(iLastTick<iNowTick-1)
|
|
|
|
|
{
|
|
|
|
|
_plOld = _plNew;
|
|
|
|
|
ApplyFreeModeControls( _plNew, _aAbs, _fFlyModeSpeedMultiplier, FALSE);
|
|
|
|
|
iLastTick++;
|
|
|
|
|
}
|
|
|
|
|
ApplyFreeModeControls( _plNew, _aAbs, _fFlyModeSpeedMultiplier, TRUE);
|
|
|
|
|
|
|
|
|
|
// set new viewer position
|
|
|
|
|
FLOAT fLerpFactor = (fPassed-iNowTick*_pTimer->TickQuantum)/_pTimer->TickQuantum;
|
|
|
|
|
ASSERT(fLerpFactor>0 && fLerpFactor<1.0f);
|
|
|
|
|
pcf->m_mvViewer.mv_plViewer.Lerp( _plOld, _plNew, Clamp(fLerpFactor, 0.0f, 1.0f));
|
|
|
|
|
pcf->m_mvViewer.mv_plViewer.pl_OrientationAngle = _aAbs;
|
|
|
|
|
|
|
|
|
|
// disable auto rendering range
|
|
|
|
|
m_vpViewPrefs.m_bAutoRenderingRange = FALSE;
|
|
|
|
|
m_vpViewPrefs.m_fRenderingRange = 2.0f;
|
|
|
|
|
pcf->m_bAutoMipBrushingOn = TRUE;
|
|
|
|
|
pcf->m_bDisableVisibilityTweaks=FALSE;
|
|
|
|
|
|
|
|
|
|
// render view again
|
|
|
|
|
CDC *pDC = GetDC();
|
|
|
|
|
OnDraw( pDC);
|
|
|
|
|
ReleaseDC( pDC);
|
|
|
|
|
// smooth frame rate
|
|
|
|
|
LimitFrameRate();
|
|
|
|
|
}
|
|
|
|
|
_pInput->DisableInput();
|
|
|
|
|
// restore rendering range settings from remembered stat view prefs
|
|
|
|
|
m_vpViewPrefs.m_bAutoRenderingRange = vpOrg.m_bAutoRenderingRange;
|
|
|
|
|
m_vpViewPrefs.m_wrpWorldRenderPrefs.SetMinimumRenderRange(vpOrg.m_wrpWorldRenderPrefs.GetMinimumRenderRange());
|
|
|
|
|
pcf->m_bAutoMipBrushingOn = bAutoMipBrushingBefore;
|
|
|
|
|
pcf->m_bDisableVisibilityTweaks=bDisableVisibilityTweaksBefore;
|
|
|
|
|
|
|
|
|
|
_pShell->SetINDEX("inp_bAllowMouseAcceleration", iAllowMouseAcceleration);
|
|
|
|
|
_pShell->SetINDEX("inp_bFilterMouse", iFilterMouse);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnReTriple()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CBrushPolygon *pbpo = pDoc->m_selPolygonSelection.GetFirstInSelection();
|
|
|
|
|
pbpo->bpo_pbscSector->ReTriple( pDoc->m_selPolygonSelection);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnClearAllTargets(void)
|
|
|
|
|
{
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
if( m_bEntityHitedOnContext && m_penEntityHitOnContext != NULL)
|
|
|
|
|
{
|
|
|
|
|
if( ::MessageBoxA( pMainFrame->m_hWnd, "Are you sure that you want to clear all targets?",
|
|
|
|
|
"Warning !", MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2|
|
|
|
|
|
MB_SYSTEMMODAL | MB_TOPMOST) != IDYES)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// clear all targets of right-clicked entity
|
|
|
|
|
pMainFrame->m_PropertyComboBar.ClearAllTargets( m_penEntityHitOnContext);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectCsgTarget()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
|
|
|
|
|
if (pbmCurrentMip!=NULL)
|
|
|
|
|
{
|
|
|
|
|
// obtain entity
|
|
|
|
|
CEntity *pen = pbmCurrentMip->bm_pbrBrush->br_penEntity;
|
|
|
|
|
if( !pen->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *pen);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateSelectCsgTarget(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CBrushMip *pbmCurrentMip = GetCurrentBrushMip();
|
|
|
|
|
pCmdUI->Enable(pbmCurrentMip!=NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateReTriple(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
BOOL bEnableRetripling = FALSE;
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->m_selPolygonSelection.Count() != 0)
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygon *pbpo = pDoc->m_selPolygonSelection.GetFirstInSelection();
|
|
|
|
|
bEnableRetripling = pbpo->bpo_pbscSector->IsReTripleAvailable( pDoc->m_selPolygonSelection);
|
|
|
|
|
}
|
|
|
|
|
pCmdUI->Enable(bEnableRetripling);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTriangularizePolygon()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc *pDoc = GetDocument();
|
|
|
|
|
CBrushPolygon *pbpoHitted = NULL;
|
|
|
|
|
if( (m_penEntityHitOnContext != NULL) &&
|
|
|
|
|
(m_penEntityHitOnContext->GetRenderType() == CEntity::RT_BRUSH) &&
|
|
|
|
|
(m_pbpoRightClickedPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
pbpoHitted = m_pbpoRightClickedPolygon;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( pbpoHitted != NULL)
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selVertexSelection.Clear();
|
|
|
|
|
if( pbpoHitted->IsSelected(BPOF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
OnTriangularizeSelection();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selVertexSelection.Clear();
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
pbpoHitted->bpo_pbscSector->TriangularizePolygon( pbpoHitted);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnEntityContextHelp()
|
|
|
|
|
{
|
|
|
|
|
if( m_penEntityHitOnContext != NULL)
|
|
|
|
|
{
|
|
|
|
|
theApp.DisplayHelp(m_penEntityHitOnContext->GetClass()->GetName(), HH_DISPLAY_TOPIC, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::AutoFitMapping(CBrushPolygon *pbpo, BOOL bInvert/*=FALSE*/, BOOL bFitBoth/*=FALSE*/)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pbpo==NULL) return;
|
|
|
|
|
|
|
|
|
|
if( pbpo->IsSelected(BPOF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// for each selected polygon
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
AutoFitMappingOnPolygon(*itbpo, bInvert, bFitBoth);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
AutoFitMappingOnPolygon(*pbpo, bInvert, bFitBoth);
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::AutoFitMappingOnPolygon(CBrushPolygon &bpo, BOOL bInvert/*=FALSE*/, BOOL bFitBoth/*=FALSE*/)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CMappingDefinition &md = bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
|
|
|
|
|
|
|
|
|
|
// reset u,v stretches
|
|
|
|
|
CMappingDefinitionUI mdui;
|
|
|
|
|
md.ToUI(mdui);
|
|
|
|
|
mdui.mdui_fUStretch = 1.0f;
|
|
|
|
|
mdui.mdui_fVStretch = 1.0f;
|
|
|
|
|
mdui.mdui_fUOffset = 0.0f;
|
|
|
|
|
mdui.mdui_fVOffset = 0.0f;
|
|
|
|
|
md.FromUI(mdui);
|
|
|
|
|
|
|
|
|
|
// find min and max u and v for the polygon
|
|
|
|
|
FLOAT fMinU = UpperLimit(0.0f);
|
|
|
|
|
FLOAT fMaxU = LowerLimit(0.0f);
|
|
|
|
|
FLOAT fMinV = UpperLimit(0.0f);
|
|
|
|
|
FLOAT fMaxV = LowerLimit(0.0f);
|
|
|
|
|
INDEX ibpe=0;
|
|
|
|
|
for(; ibpe<bpo.bpo_abpePolygonEdges.Count(); ibpe++)
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygonEdge &bpe = bpo.bpo_abpePolygonEdges[ibpe];
|
|
|
|
|
FLOAT3D v0, v1;
|
|
|
|
|
MEX2D(vTex0);
|
|
|
|
|
bpe.GetVertexCoordinatesRelative(v0, v1);
|
|
|
|
|
md.GetTextureCoordinates( bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative, v0, vTex0);
|
|
|
|
|
FLOAT fU = vTex0(1)/1024.0f;
|
|
|
|
|
FLOAT fV = vTex0(2)/1024.0f;
|
|
|
|
|
fMinU = Min(fMinU, fU);
|
|
|
|
|
fMaxU = Max(fMaxU, fU);
|
|
|
|
|
fMinV = Min(fMinV, fV);
|
|
|
|
|
fMaxV = Max(fMaxV, fV);
|
|
|
|
|
}
|
|
|
|
|
// calculate u,v fit stretches
|
|
|
|
|
FLOAT fFitStretchU = fMaxU-fMinU;
|
|
|
|
|
FLOAT fFitStretchV = fMaxV-fMinV;
|
|
|
|
|
// get fit stretch
|
|
|
|
|
FLOAT fFitStretch;
|
|
|
|
|
if( !bInvert)
|
|
|
|
|
{
|
|
|
|
|
fFitStretch = Min(fFitStretchV,fFitStretchU);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fFitStretch = Max(fFitStretchV,fFitStretchU);
|
|
|
|
|
}
|
|
|
|
|
// adjust stretch for texture size
|
|
|
|
|
CTextureData *ptd = (CTextureData *)bpo.bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.GetData();
|
|
|
|
|
if( ptd!=NULL)
|
|
|
|
|
{
|
|
|
|
|
MEX mexW=ptd->GetWidth();
|
|
|
|
|
MEX mexH=ptd->GetHeight();
|
|
|
|
|
// if fitting U
|
|
|
|
|
if( fFitStretch==fFitStretchU)
|
|
|
|
|
{
|
|
|
|
|
fFitStretch/=mexW/1024.0f;
|
|
|
|
|
}
|
|
|
|
|
// if fitting V
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fFitStretch/=mexH/1024.0f;
|
|
|
|
|
}
|
|
|
|
|
fFitStretchU/=mexW/1024.0f;
|
|
|
|
|
fFitStretchV/=mexH/1024.0f;
|
|
|
|
|
}
|
|
|
|
|
if( bFitBoth)
|
|
|
|
|
{
|
|
|
|
|
mdui.mdui_fUStretch=fFitStretchU;
|
|
|
|
|
mdui.mdui_fVStretch=fFitStretchV;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mdui.mdui_fUStretch=fFitStretch;
|
|
|
|
|
mdui.mdui_fVStretch=fFitStretch;
|
|
|
|
|
}
|
|
|
|
|
md.FromUI(mdui);
|
|
|
|
|
CMappingVectors &mv = bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_mvRelative;
|
|
|
|
|
|
|
|
|
|
// find vtx that has min u and v
|
|
|
|
|
fMinU = UpperLimit(0.0f);
|
|
|
|
|
fMaxV = LowerLimit(0.0f);
|
|
|
|
|
FLOAT3D vMinU, vMaxV;
|
|
|
|
|
for(ibpe=0; ibpe<bpo.bpo_abpePolygonEdges.Count(); ibpe++)
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygonEdge &bpe = bpo.bpo_abpePolygonEdges[ibpe];
|
|
|
|
|
FLOAT3D v0, v1, va0, va1;
|
|
|
|
|
MEX2D(vTex0);
|
|
|
|
|
bpe.GetVertexCoordinatesRelative(v0, v1);
|
|
|
|
|
bpe.GetVertexCoordinatesAbsolute(va0, va1);
|
|
|
|
|
md.GetTextureCoordinates( mv, v0, vTex0);
|
|
|
|
|
FLOAT fU = vTex0(1)/1024.0f;
|
|
|
|
|
FLOAT fV = vTex0(2)/1024.0f;
|
|
|
|
|
if( fU<fMinU)
|
|
|
|
|
{
|
|
|
|
|
vMinU=v0;
|
|
|
|
|
fMinU=fU;
|
|
|
|
|
}
|
|
|
|
|
if( fV>fMaxV)
|
|
|
|
|
{
|
|
|
|
|
vMaxV=v0;
|
|
|
|
|
fMaxV=fV;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// remember u offset
|
|
|
|
|
md.Center(mv, vMinU);
|
|
|
|
|
md.ToUI(mdui);
|
|
|
|
|
fMinU = mdui.mdui_fUOffset;
|
|
|
|
|
|
|
|
|
|
// remember v offset
|
|
|
|
|
md.Center(mv, vMaxV);
|
|
|
|
|
md.ToUI(mdui);
|
|
|
|
|
fMaxV = mdui.mdui_fVOffset;
|
|
|
|
|
|
|
|
|
|
// set offsets
|
|
|
|
|
mdui.mdui_fUOffset=fMinU;
|
|
|
|
|
mdui.mdui_fVOffset=fMaxV;
|
|
|
|
|
md.FromUI(mdui);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTriangularizeSelection()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CDynamicContainer<CBrushPolygon> dcPolygons;
|
|
|
|
|
// copy polygon selection
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
dcPolygons.Add(&*itbpo);
|
|
|
|
|
}
|
|
|
|
|
// clear selections
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
pDoc->m_selVertexSelection.Clear();
|
|
|
|
|
// apply triangularisation
|
|
|
|
|
pDoc->m_woWorld.TriangularizePolygons( dcPolygons);
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateTriangularizeSelection(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pCmdUI->Enable(pDoc->m_selPolygonSelection.Count()!=0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPopupAutoFitMapping()
|
|
|
|
|
{
|
|
|
|
|
if(m_pbpoRightClickedPolygon != NULL)
|
|
|
|
|
{
|
|
|
|
|
AutoFitMapping( m_pbpoRightClickedPolygon);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPopupAutoFitMappingSmall()
|
|
|
|
|
{
|
|
|
|
|
if(m_pbpoRightClickedPolygon != NULL)
|
|
|
|
|
{
|
|
|
|
|
AutoFitMapping( m_pbpoRightClickedPolygon, TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPopupAutoFitMappingBoth()
|
|
|
|
|
{
|
|
|
|
|
if(m_pbpoRightClickedPolygon != NULL)
|
|
|
|
|
{
|
|
|
|
|
AutoFitMapping( m_pbpoRightClickedPolygon, TRUE, TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::ApplyDefaultMapping(CBrushPolygon *pbpo, BOOL bRotation, BOOL bOffset, BOOL bStretch)
|
|
|
|
|
{
|
|
|
|
|
if(m_pbpoRightClickedPolygon == NULL) return;
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// if is selected
|
|
|
|
|
if( m_pbpoRightClickedPolygon->IsSelected(BPOF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygon &po=*itbpo;
|
|
|
|
|
CMappingDefinition &md=po.bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
|
|
|
|
|
CMappingDefinitionUI mdui;
|
|
|
|
|
md.ToUI(mdui);
|
|
|
|
|
if( bRotation)
|
|
|
|
|
{
|
|
|
|
|
mdui.mdui_aURotation=0.0f;
|
|
|
|
|
mdui.mdui_aVRotation=0.0f;
|
|
|
|
|
}
|
|
|
|
|
if( bStretch)
|
|
|
|
|
{
|
|
|
|
|
mdui.mdui_fUStretch = 1.0f;
|
|
|
|
|
mdui.mdui_fVStretch = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
if( bOffset)
|
|
|
|
|
{
|
|
|
|
|
mdui.mdui_fUOffset = 0.0f;
|
|
|
|
|
mdui.mdui_fVOffset = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
md.FromUI(mdui);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CMappingDefinition &md=m_pbpoRightClickedPolygon->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping;
|
|
|
|
|
CMappingDefinitionUI mdui;
|
|
|
|
|
md.ToUI(mdui);
|
|
|
|
|
if( bRotation)
|
|
|
|
|
{
|
|
|
|
|
mdui.mdui_aURotation=0.0f;
|
|
|
|
|
mdui.mdui_aVRotation=0.0f;
|
|
|
|
|
}
|
|
|
|
|
if( bStretch)
|
|
|
|
|
{
|
|
|
|
|
mdui.mdui_fUStretch = 1.0f;
|
|
|
|
|
mdui.mdui_fVStretch = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
if( bOffset)
|
|
|
|
|
{
|
|
|
|
|
mdui.mdui_fUOffset = 0.0f;
|
|
|
|
|
mdui.mdui_fVOffset = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
md.FromUI(mdui);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnResetMappingOffset()
|
|
|
|
|
{
|
|
|
|
|
ApplyDefaultMapping( m_pbpoRightClickedPolygon, FALSE, TRUE, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnResetMappingRotation()
|
|
|
|
|
{
|
|
|
|
|
ApplyDefaultMapping( m_pbpoRightClickedPolygon, TRUE, FALSE, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnResetMappingStretch()
|
|
|
|
|
{
|
|
|
|
|
ApplyDefaultMapping( m_pbpoRightClickedPolygon, FALSE, FALSE, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::ShowLinkTree(CEntity *pen, BOOL bWhoTargets/*=FALSE*/, BOOL bPropertyNames/*=FALSE*/)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CPoint ptScr=m_ptMouse;
|
|
|
|
|
ClientToScreen( &ptScr);
|
|
|
|
|
if( pen!=NULL || (pDoc->m_selEntitySelection.Count() != 0))
|
|
|
|
|
{
|
|
|
|
|
CDlgLinkTree dlg( pen, ptScr, bWhoTargets, bPropertyNames);
|
|
|
|
|
dlg.DoModal();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCrossroadForL()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
ShowLinkTree(NULL);
|
|
|
|
|
}
|
|
|
|
|
else if(pDoc->m_pwoSecondLayer != NULL)
|
|
|
|
|
{
|
|
|
|
|
pDoc->OnJoinLayers();
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainEditMode=TEM_LAYER;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectUsingTargetTree()
|
|
|
|
|
{
|
|
|
|
|
ShowLinkTree(m_penEntityHitOnContext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTargetTree()
|
|
|
|
|
{
|
|
|
|
|
ShowLinkTree(NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateTargetTree(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pCmdUI->Enable(pDoc->m_selEntitySelection.Count() != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SwapLayers( CBrushPolygon &bpo, INDEX il1, INDEX il2)
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygonTexture bptTemp;
|
|
|
|
|
bptTemp.CopyTextureProperties(bpo.bpo_abptTextures[il1], TRUE);
|
|
|
|
|
bpo.bpo_abptTextures[il1].CopyTextureProperties(bpo.bpo_abptTextures[il2], TRUE);
|
|
|
|
|
bpo.bpo_abptTextures[il2].CopyTextureProperties(bptTemp, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSwapLayers12()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
SwapLayers( *itbpo, 0, 1);
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSwapLayers23()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
SwapLayers( *itbpo, 1, 2);
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectDescendants()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
SelectDescendents( pDoc->m_selEntitySelection, *iten);
|
|
|
|
|
}
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRotateToTargetOrigin()
|
|
|
|
|
{
|
|
|
|
|
if(m_penEntityHitOnContext != NULL)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
const CPlacement3D &plDst=iten->GetPlacement();
|
|
|
|
|
const CPlacement3D &plSrc=m_penEntityHitOnContext->GetPlacement();
|
|
|
|
|
FLOAT3D vDir=plSrc.pl_PositionVector-plDst.pl_PositionVector;
|
|
|
|
|
vDir.Normalize();
|
|
|
|
|
ANGLE3D ang;
|
|
|
|
|
DirectionVectorToAngles(vDir, ang);
|
|
|
|
|
CPlacement3D plNew=plDst;
|
|
|
|
|
plNew.pl_OrientationAngle=ang;
|
|
|
|
|
iten->SetPlacement(plNew);
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRotateToTargetCenter()
|
|
|
|
|
{
|
|
|
|
|
if(m_penEntityHitOnContext != NULL)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
const CPlacement3D &plDst=iten->GetPlacement();
|
|
|
|
|
FLOATaabbox3D box;
|
|
|
|
|
m_penEntityHitOnContext->GetSize(box);
|
|
|
|
|
FLOAT3D vTarget=box.Center();
|
|
|
|
|
FLOAT3D vDir=vTarget-plDst.pl_PositionVector;
|
|
|
|
|
vDir.Normalize();
|
|
|
|
|
ANGLE3D ang;
|
|
|
|
|
DirectionVectorToAngles(vDir, ang);
|
|
|
|
|
CPlacement3D plNew=plDst;
|
|
|
|
|
plNew.pl_OrientationAngle=ang;
|
|
|
|
|
iten->SetPlacement(plNew);
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCopyPlacement()
|
|
|
|
|
{
|
|
|
|
|
if(m_penEntityHitOnContext==NULL) return;
|
|
|
|
|
theApp.m_plClipboard2=m_penEntityHitOnContext->GetPlacement();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCopyOrientation()
|
|
|
|
|
{
|
|
|
|
|
if(m_penEntityHitOnContext==NULL) return;
|
|
|
|
|
theApp.m_plClipboard1.pl_OrientationAngle=m_penEntityHitOnContext->GetPlacement().pl_OrientationAngle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnCopyPosition()
|
|
|
|
|
{
|
|
|
|
|
if(m_penEntityHitOnContext==NULL) return;
|
|
|
|
|
theApp.m_plClipboard1.pl_PositionVector=m_penEntityHitOnContext->GetPlacement().pl_PositionVector;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPastePlacement()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if(m_penEntityHitOnContext==NULL) return;
|
|
|
|
|
if( m_penEntityHitOnContext->IsSelected(ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
iten->SetPlacement(theApp.m_plClipboard2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_penEntityHitOnContext->SetPlacement(theApp.m_plClipboard2);
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPasteOrientation()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if(m_penEntityHitOnContext==NULL) return;
|
|
|
|
|
if( m_penEntityHitOnContext->IsSelected(ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CPlacement3D pl=iten->GetPlacement();
|
|
|
|
|
pl.pl_OrientationAngle=theApp.m_plClipboard1.pl_OrientationAngle;
|
|
|
|
|
iten->SetPlacement(pl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CPlacement3D pl=m_penEntityHitOnContext->GetPlacement();
|
|
|
|
|
pl.pl_OrientationAngle=theApp.m_plClipboard1.pl_OrientationAngle;
|
|
|
|
|
m_penEntityHitOnContext->SetPlacement(pl);
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPastePosition()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if(m_penEntityHitOnContext==NULL) return;
|
|
|
|
|
if( m_penEntityHitOnContext->IsSelected(ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CPlacement3D pl=iten->GetPlacement();
|
|
|
|
|
pl.pl_PositionVector=theApp.m_plClipboard1.pl_PositionVector;
|
|
|
|
|
iten->SetPlacement(pl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CPlacement3D pl=m_penEntityHitOnContext->GetPlacement();
|
|
|
|
|
pl.pl_PositionVector=theApp.m_plClipboard1.pl_PositionVector;
|
|
|
|
|
m_penEntityHitOnContext->SetPlacement(pl);
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::Align(BOOL bX,BOOL bY,BOOL bZ,BOOL bH,BOOL bP,BOOL bB)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
INDEX ctSelected=pDoc->m_woWorld.wo_cenEntities.Count();
|
|
|
|
|
CEntity *penLast=NULL;
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
penLast=&*iten;
|
|
|
|
|
}}
|
|
|
|
|
CPlacement3D penSrc=penLast->GetPlacement();
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CPlacement3D pl=iten->GetPlacement();
|
|
|
|
|
if( bX) {pl.pl_PositionVector(1)=penSrc.pl_PositionVector(1);};
|
|
|
|
|
if( bY) {pl.pl_PositionVector(2)=penSrc.pl_PositionVector(2);};
|
|
|
|
|
if( bZ) {pl.pl_PositionVector(3)=penSrc.pl_PositionVector(3);};
|
|
|
|
|
if( bH) {pl.pl_OrientationAngle(1)=penSrc.pl_OrientationAngle(1);};
|
|
|
|
|
if( bP) {pl.pl_OrientationAngle(2)=penSrc.pl_OrientationAngle(2);};
|
|
|
|
|
if( bB) {pl.pl_OrientationAngle(3)=penSrc.pl_OrientationAngle(3);};
|
|
|
|
|
iten->SetPlacement(pl);
|
|
|
|
|
}}
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAlignB()
|
|
|
|
|
{
|
|
|
|
|
Align(FALSE,FALSE,FALSE,FALSE,FALSE,TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAlignH()
|
|
|
|
|
{
|
|
|
|
|
Align(FALSE,FALSE,FALSE,TRUE,FALSE,FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAlignP()
|
|
|
|
|
{
|
|
|
|
|
Align(FALSE,FALSE,FALSE,FALSE,TRUE,FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAlignX()
|
|
|
|
|
{
|
|
|
|
|
Align(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAlignY()
|
|
|
|
|
{
|
|
|
|
|
Align(FALSE,TRUE,FALSE,FALSE,FALSE,FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAlignZ()
|
|
|
|
|
{
|
|
|
|
|
Align(FALSE,FALSE,TRUE,FALSE,FALSE,FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct CameraProjectionInfo {
|
|
|
|
|
FLOAT cpi_fOffsetRatioX;
|
|
|
|
|
FLOAT cpi_fOffsetRatioY;
|
|
|
|
|
FLOAT cpi_fOffsetRatioZ;
|
|
|
|
|
ANGLE cpi_angH;
|
|
|
|
|
ANGLE cpi_angP;
|
|
|
|
|
ANGLE cpi_angB;
|
|
|
|
|
double cpi_rMinI;
|
|
|
|
|
double cpi_rMinJ;
|
|
|
|
|
double cpi_rSizeI;
|
|
|
|
|
double cpi_rSizeJ;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
CameraProjectionInfo *_pacpi=NULL;
|
|
|
|
|
INDEX _ctProjections=0;
|
|
|
|
|
CameraProjectionInfo acpiF[] =
|
|
|
|
|
{
|
|
|
|
|
{ 0, 0, 1, 0, 0, 0, 0, 0, 1, 1}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
CameraProjectionInfo acpi2x2[] =
|
|
|
|
|
{
|
|
|
|
|
{ 0, 0, 1, 0, 0, 0, 0, 0, 0.5, 0.5},
|
|
|
|
|
{ 1, 0, 0, 90, 0, 0, 0.5, 0, 0.5, 0.5},
|
|
|
|
|
{ 0, 0, -1, 180, 0, 0, 0, 0.5, 0.5, 0.5},
|
|
|
|
|
{-1, 0, 0, 270, 0, 0, 0.5, 0.5, 0.5, 0.5}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
CameraProjectionInfo acpi3x2[] =
|
|
|
|
|
{
|
|
|
|
|
{ 0, 0, 1, 0, 0, 0, 0, 0, 0.3, 0.3},
|
|
|
|
|
{ 1, 0, 0, 90, 0, 0, 0.3, 0, 0.3, 0.3},
|
|
|
|
|
{ 0, 0, -1, 180, 0, 0, 0.6, 0, 0.3, 0.3},
|
|
|
|
|
{-1, 0, 0, 270, 0, 0, 0, 0.3, 0.3, 0.3},
|
|
|
|
|
{ 0, 1, 0, 0,-90, 0, 0.3, 0.3, 0.3, 0.3},
|
|
|
|
|
{ 0,-1, 0, 0, 90, 0, 0.6, 0.3, 0.3, 0.3},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// setup viewing parameters for saving pretender textures
|
|
|
|
|
void SetupView(INDEX iFrame, CDrawPort *pdp, CAnyProjection3D &apr, FLOATaabbox3D box)
|
|
|
|
|
{
|
|
|
|
|
// init projection parameters
|
|
|
|
|
CIsometricProjection3D prIsometricProjection;
|
|
|
|
|
prIsometricProjection.ScreenBBoxL() = FLOATaabbox2D(
|
|
|
|
|
FLOAT2D(0.0f, 0.0f),
|
|
|
|
|
FLOAT2D((FLOAT)pdp->GetWidth(), (FLOAT)pdp->GetHeight())
|
|
|
|
|
);
|
|
|
|
|
prIsometricProjection.NearClipDistanceL() = 0.0f;
|
|
|
|
|
// determine far clip plane
|
|
|
|
|
FLOAT3D vSize=box.Size();
|
|
|
|
|
FLOAT3D vHSize=vSize/2.0f;
|
|
|
|
|
FLOAT3D vRatio=FLOAT3D(
|
|
|
|
|
_pacpi[iFrame].cpi_fOffsetRatioX,
|
|
|
|
|
_pacpi[iFrame].cpi_fOffsetRatioY,
|
|
|
|
|
_pacpi[iFrame].cpi_fOffsetRatioZ);
|
|
|
|
|
ANGLE3D ang=ANGLE3D(
|
|
|
|
|
_pacpi[iFrame].cpi_angH,
|
|
|
|
|
_pacpi[iFrame].cpi_angP,
|
|
|
|
|
_pacpi[iFrame].cpi_angB);
|
|
|
|
|
FLOAT fFCD=Max(
|
|
|
|
|
Abs(vRatio(1))*vSize(1), Max(
|
|
|
|
|
Abs(vRatio(2))*vSize(2),
|
|
|
|
|
Abs(vRatio(3))*vSize(3)));
|
|
|
|
|
prIsometricProjection.FarClipDistanceL() = fFCD;
|
|
|
|
|
prIsometricProjection.AspectRatioL() = 1.0f;
|
|
|
|
|
// set up viewer position
|
|
|
|
|
apr = prIsometricProjection;
|
|
|
|
|
FLOAT3D vPos=FLOAT3D(
|
|
|
|
|
vRatio(1)*vHSize(1),
|
|
|
|
|
vRatio(2)*vHSize(2),
|
|
|
|
|
vRatio(3)*vHSize(3))+box.Center();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FLOAT fMaxSize;
|
|
|
|
|
if( vRatio(1)!=0)
|
|
|
|
|
{
|
|
|
|
|
fMaxSize=Max(vSize(2),vSize(3));
|
|
|
|
|
}
|
|
|
|
|
else if( vRatio(2)!=0)
|
|
|
|
|
{
|
|
|
|
|
fMaxSize=Max(vSize(1),vSize(3));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fMaxSize=Max(vSize(1),vSize(2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prIsometricProjection.ZoomFactorL()=pdp->GetWidth()/fMaxSize;
|
|
|
|
|
|
|
|
|
|
CPlacement3D plViewer=CPlacement3D(vPos, ang);
|
|
|
|
|
//plViewer.RelativeToAbsolute(plEntity);
|
|
|
|
|
apr=prIsometricProjection;
|
|
|
|
|
apr->ViewerPlacementL() = plViewer;
|
|
|
|
|
apr->ObjectPlacementL() = CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0));
|
|
|
|
|
apr->Prepare();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CWorldEditorView::SaveAutoTexture(FLOATaabbox3D boxBrush, CTFileName &fnTex)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CDlgAutTexturize dlg;
|
|
|
|
|
if( dlg.DoModal()!=IDOK) return FALSE;
|
|
|
|
|
|
|
|
|
|
// call file requester for pretender texture name
|
|
|
|
|
CTFileName fnPretenderTexture = _EngineGUI.FileRequester( "Pretender texture name",
|
|
|
|
|
FILTER_TGA FILTER_END, "Auto save texture", "", "", NULL, TRUE);
|
|
|
|
|
if( fnPretenderTexture == "") return FALSE;
|
|
|
|
|
|
|
|
|
|
switch( dlg.m_iPretenderStyle)
|
|
|
|
|
{
|
|
|
|
|
case 0: _pacpi=acpiF; _ctProjections=1; break;
|
|
|
|
|
case 1: _pacpi=acpi2x2; _ctProjections=4; break;
|
|
|
|
|
case 2: _pacpi=acpi3x2; _ctProjections=6; break;
|
|
|
|
|
default: _pacpi=acpi3x2; _ctProjections=6; break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CDrawPort *pdp;
|
|
|
|
|
CImageInfo II;
|
|
|
|
|
CTextureData TD;
|
|
|
|
|
CAnimData AD;
|
|
|
|
|
ULONG flags = NONE;
|
|
|
|
|
|
|
|
|
|
CChildFrame *pChild = GetChildFrame();
|
|
|
|
|
// create canvas to render picture
|
|
|
|
|
_pGfx->CreateWorkCanvas( dlg.m_pixWidth, dlg.m_pixHeight, &pdp);
|
|
|
|
|
if( pdp != NULL)
|
|
|
|
|
{
|
|
|
|
|
FLOAT3D vSize=boxBrush.Size();
|
|
|
|
|
for(INDEX iFrame=0; iFrame<_ctProjections; iFrame++)
|
|
|
|
|
{
|
|
|
|
|
CameraProjectionInfo &cpi=_pacpi[iFrame];
|
|
|
|
|
CDrawPort dpClone( pdp, cpi.cpi_rMinI, cpi.cpi_rMinJ, cpi.cpi_rSizeI, cpi.cpi_rSizeJ);
|
|
|
|
|
// clone draw port
|
|
|
|
|
if( dpClone.Lock())
|
|
|
|
|
{
|
|
|
|
|
dpClone.FillZBuffer(ZBUF_BACK);
|
|
|
|
|
CAnyProjection3D apr;
|
|
|
|
|
SetupView(iFrame, &dpClone, apr, boxBrush);
|
|
|
|
|
|
|
|
|
|
// store rendering preferences
|
|
|
|
|
BOOL bWasBcgOn = _wrpWorldRenderPrefs.IsBackgroundTextureOn();
|
|
|
|
|
CWorldRenderPrefs::SelectionType stBefore=_wrpWorldRenderPrefs.GetSelectionType();
|
|
|
|
|
_wrpWorldRenderPrefs.SetBackgroundTextureOn( FALSE);
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectionType( CWorldRenderPrefs::ST_NONE);
|
|
|
|
|
COLOR colOld=pDoc->m_woWorld.GetBackgroundColor();
|
|
|
|
|
pDoc->m_woWorld.SetBackgroundColor(dlg.m_colBcg.GetColor());
|
|
|
|
|
// render view
|
|
|
|
|
::RenderView(pDoc->m_woWorld, *(CEntity*)NULL, apr, dpClone);
|
|
|
|
|
// restore rendering preferences
|
|
|
|
|
pDoc->m_woWorld.SetBackgroundColor(colOld);
|
|
|
|
|
_wrpWorldRenderPrefs.SetSelectionType(stBefore);
|
|
|
|
|
_wrpWorldRenderPrefs.SetBackgroundTextureOn( bWasBcgOn);
|
|
|
|
|
}
|
|
|
|
|
dpClone.Unlock();
|
|
|
|
|
}
|
|
|
|
|
pdp->GrabScreen( II, 2);
|
|
|
|
|
if( dlg.m_bExpandEdges)
|
|
|
|
|
{
|
|
|
|
|
II.ExpandEdges();
|
|
|
|
|
}
|
|
|
|
|
// try to
|
|
|
|
|
try {
|
|
|
|
|
// save screen shot as TGA
|
|
|
|
|
II.SaveTGA_t( fnPretenderTexture);
|
|
|
|
|
fnTex=fnPretenderTexture.NoExt()+".tex";
|
|
|
|
|
// create temporary texture
|
|
|
|
|
CreateTexture_t( fnPretenderTexture, fnTex,
|
|
|
|
|
dlg.m_pixWidth, MAX_MEX_LOG2+1, FALSE);
|
|
|
|
|
_EngineGUI.CreateTexture( fnTex);
|
|
|
|
|
} // if failed
|
|
|
|
|
catch (char *strError) {
|
|
|
|
|
// report error
|
|
|
|
|
AfxMessageBox(CString(strError));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INDEX _aiMinMax[] =
|
|
|
|
|
{
|
|
|
|
|
0,0,1,
|
|
|
|
|
1,0,1,
|
|
|
|
|
1,0,0,
|
|
|
|
|
0,0,0,
|
|
|
|
|
0,1,1,
|
|
|
|
|
1,1,1,
|
|
|
|
|
1,1,0,
|
|
|
|
|
0,1,0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
INDEX _aiPlaneVtx[] =
|
|
|
|
|
{
|
|
|
|
|
4,0,1,5,
|
|
|
|
|
5,1,2,6,
|
|
|
|
|
6,2,3,7,
|
|
|
|
|
7,3,0,4,
|
|
|
|
|
7,4,5,6,
|
|
|
|
|
0,3,2,1,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FLOAT3D _avBoxVtx[8];
|
|
|
|
|
|
|
|
|
|
struct BoxPlaneParams {
|
|
|
|
|
FLOATplane3D bpp_plPlane;
|
|
|
|
|
CMappingVectors bpp_mvDefault;
|
|
|
|
|
CMappingVectors bpp_mvVectors;
|
|
|
|
|
CMappingDefinition bpp_mdMappingDefinition;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BoxPlaneParams _abpp[6];
|
|
|
|
|
|
|
|
|
|
BOOL CWorldEditorView::SetAutoTextureBoxParams(FLOATaabbox3D boxBrush, CTFileName &fnTex)
|
|
|
|
|
{
|
|
|
|
|
CTextureData *pTD=NULL;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
pTD=_pTextureStock->Obtain_t( fnTex);
|
|
|
|
|
}
|
|
|
|
|
catch (char *strError)
|
|
|
|
|
{
|
|
|
|
|
WarningMessage(strError);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create box vertices
|
|
|
|
|
FLOAT3D vMin=boxBrush.Min();
|
|
|
|
|
FLOAT3D vMax=boxBrush.Max();
|
|
|
|
|
FLOAT3D vSize=boxBrush.Size();
|
|
|
|
|
for( INDEX iVtx=0; iVtx<8; iVtx++)
|
|
|
|
|
{
|
|
|
|
|
FLOAT fX=_aiMinMax[iVtx*3+0]*vSize(1)+vMin(1);
|
|
|
|
|
FLOAT fY=_aiMinMax[iVtx*3+1]*vSize(2)+vMin(2);
|
|
|
|
|
FLOAT fZ=_aiMinMax[iVtx*3+2]*vSize(3)+vMin(3);
|
|
|
|
|
_avBoxVtx[iVtx]=FLOAT3D(fX,fY,fZ);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create box planes
|
|
|
|
|
for( INDEX iPlane=0; iPlane<_ctProjections; iPlane++)
|
|
|
|
|
{
|
|
|
|
|
CameraProjectionInfo &cpi=_pacpi[iPlane];
|
|
|
|
|
// create plane
|
|
|
|
|
BoxPlaneParams &bpp=_abpp[iPlane];
|
|
|
|
|
FLOAT3D &vVtx0=_avBoxVtx[_aiPlaneVtx[iPlane*4+0]];
|
|
|
|
|
FLOAT3D &vVtx1=_avBoxVtx[_aiPlaneVtx[iPlane*4+1]];
|
|
|
|
|
FLOAT3D &vVtx2=_avBoxVtx[_aiPlaneVtx[iPlane*4+2]];
|
|
|
|
|
FLOAT3D &vVtx3=_avBoxVtx[_aiPlaneVtx[iPlane*4+3]];
|
|
|
|
|
bpp.bpp_plPlane=FLOATplane3D(vVtx0, vVtx1, vVtx2);
|
|
|
|
|
// create mapping vectors
|
|
|
|
|
bpp.bpp_mvDefault.FromPlane(bpp.bpp_plPlane);
|
|
|
|
|
bpp.bpp_mvVectors.mv_vO=(vVtx0+vVtx2)/2.0f;
|
|
|
|
|
FLOAT3D vDeltaU=vVtx3-vVtx0;
|
|
|
|
|
FLOAT3D vDeltaV=vVtx1-vVtx0;
|
|
|
|
|
FLOAT fStretch = Max(vDeltaU.Length(), vDeltaV.Length())/(pTD->GetWidth()/1024.0f*cpi.cpi_rSizeI);
|
|
|
|
|
bpp.bpp_mvVectors.mv_vU=vDeltaU.Normalize()*fStretch;
|
|
|
|
|
bpp.bpp_mvVectors.mv_vV=vDeltaV.Normalize()*fStretch;
|
|
|
|
|
bpp.bpp_mdMappingDefinition.FromMappingVectors(bpp.bpp_mvDefault, bpp.bpp_mvVectors);
|
|
|
|
|
MEX mexOffsetU = pTD->GetWidth() *(cpi.cpi_rMinI+cpi.cpi_rSizeI/2);
|
|
|
|
|
MEX mexOffsetV = pTD->GetHeight()*(cpi.cpi_rMinJ+cpi.cpi_rSizeJ/2);
|
|
|
|
|
bpp.bpp_mdMappingDefinition.md_fUOffset-=mexOffsetU/1024.0f;
|
|
|
|
|
bpp.bpp_mdMappingDefinition.md_fVOffset-=mexOffsetV/1024.0f;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::AutoApplyTextureOntoPolygon(CBrushPolygon &bpo, FLOATaabbox3D boxBrush, CTFileName &fnTex)
|
|
|
|
|
{
|
|
|
|
|
// get box polygon that has smallest scalar product with our polygon
|
|
|
|
|
FLOAT fMaxScalar=-1e6f;
|
|
|
|
|
INDEX iMaxPlane=0;
|
|
|
|
|
FLOATplane3D &plPlaneAbs=bpo.bpo_pbplPlane->bpl_plAbsolute;
|
|
|
|
|
FLOATplane3D &plPlaneRel=bpo.bpo_pbplPlane->bpl_plRelative;
|
|
|
|
|
for(INDEX iPlane=0; iPlane<6; iPlane++)
|
|
|
|
|
{
|
|
|
|
|
BoxPlaneParams &bpp=_abpp[iPlane];
|
|
|
|
|
FLOAT fScalar=plPlaneAbs%bpp.bpp_plPlane;
|
|
|
|
|
if( fScalar>fMaxScalar)
|
|
|
|
|
{
|
|
|
|
|
iMaxPlane=iPlane;
|
|
|
|
|
fMaxScalar=fScalar;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BoxPlaneParams &bpp=_abpp[iMaxPlane];
|
|
|
|
|
CBrushPolygonTexture &bbpt0=bpo.bpo_abptTextures[0];
|
|
|
|
|
CBrushPolygonTexture &bbpt1=bpo.bpo_abptTextures[1];
|
|
|
|
|
CBrushPolygonTexture &bbpt2=bpo.bpo_abptTextures[2];
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
bbpt0.CopyTextureProperties(CBrushPolygonTexture(),TRUE);
|
|
|
|
|
bbpt0.bpt_toTexture.SetData_t(fnTex);
|
|
|
|
|
bbpt1.bpt_toTexture.SetData(NULL);
|
|
|
|
|
bbpt2.bpt_toTexture.SetData(NULL);
|
|
|
|
|
|
|
|
|
|
// get the mapping in relative space of the brush polygon's entity
|
|
|
|
|
CEntity *pen = bpo.bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush->br_penEntity;
|
|
|
|
|
CSimpleProjection3D pr;
|
|
|
|
|
pr.ObjectPlacementL() = _plOrigin;
|
|
|
|
|
pr.ViewerPlacementL() = pen->GetPlacement();
|
|
|
|
|
pr.Prepare();
|
|
|
|
|
FLOATplane3D plRelative;
|
|
|
|
|
pr.Project(bpp.bpp_plPlane, plRelative);
|
|
|
|
|
CMappingDefinition mdRelative = bpp.bpp_mdMappingDefinition;
|
|
|
|
|
mdRelative.Transform(bpp.bpp_plPlane, _plOrigin, pen->GetPlacement());
|
|
|
|
|
|
|
|
|
|
bbpt0.bpt_mdMapping.ProjectMapping(plRelative, mdRelative, plPlaneRel);
|
|
|
|
|
|
|
|
|
|
bpo.bpo_ulFlags |= BPOF_FULLBRIGHT;
|
|
|
|
|
bpo.bpo_smShadowMap.Uncache();
|
|
|
|
|
bpo.DiscardShadows();
|
|
|
|
|
}
|
|
|
|
|
catch (char *strError)
|
|
|
|
|
{
|
|
|
|
|
WarningMessage(strError);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::AutoApplyTexture(FLOATaabbox3D boxBrush, CTFileName &fnTex)
|
|
|
|
|
{
|
|
|
|
|
if( !SetAutoTextureBoxParams(boxBrush, fnTex)) return;
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// textureize mip levels
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CEntity *pen=&*iten;
|
|
|
|
|
if( pen->GetRenderType() == CEntity::RT_BRUSH)
|
|
|
|
|
{
|
|
|
|
|
CBrush3D *pbrBrush=pen->GetBrush();
|
|
|
|
|
// for each mip in the brush
|
|
|
|
|
BOOL bFirstMip=TRUE;
|
|
|
|
|
FOREACHINLIST(CBrushMip, bm_lnInBrush, pbrBrush->br_lhBrushMips, itbm)
|
|
|
|
|
{
|
|
|
|
|
if( bFirstMip)
|
|
|
|
|
{
|
|
|
|
|
bFirstMip=FALSE;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// for all sectors in this mip
|
|
|
|
|
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
|
|
|
|
|
// for each polygon in sector
|
|
|
|
|
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo) {
|
|
|
|
|
CBrushPolygon &bpo = *itbpo;
|
|
|
|
|
AutoApplyTextureOntoPolygon(bpo, boxBrush, fnTex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAutotexturizeMips()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
FLOATaabbox3D boxBrush;
|
|
|
|
|
// for each entity in the world
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
CEntity *pen=&*iten;
|
|
|
|
|
if( pen->GetRenderType() == CEntity::RT_BRUSH)
|
|
|
|
|
{
|
|
|
|
|
CBrush3D *pbrBrush=pen->GetBrush();
|
|
|
|
|
CBrushMip *pbrMip=pbrBrush->GetFirstMip();
|
|
|
|
|
boxBrush|=pbrMip->bm_boxBoundingBox;
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
CTFileName fnTex;
|
|
|
|
|
BOOL bSuccess=SaveAutoTexture( boxBrush, fnTex);
|
|
|
|
|
if( !bSuccess) return;
|
|
|
|
|
|
|
|
|
|
AutoApplyTexture( boxBrush, fnTex);
|
|
|
|
|
|
|
|
|
|
// mark that selections have been changed
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
pDoc->SetModifiedFlag();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateAutotexturizeMips(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pCmdUI->Enable(pDoc->m_selEntitySelection.Count()!=0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRandomOffsetU()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// for each selected polygon
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
CTextureData *pTD = (CTextureData *) itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.GetData();
|
|
|
|
|
if( pTD != NULL)
|
|
|
|
|
{
|
|
|
|
|
// add rnd offsets to mapping
|
|
|
|
|
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fUOffset+=((FLOAT)rand())/RAND_MAX*pTD->GetWidth();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRandomOffsetV()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// for each selected polygon
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
CTextureData *pTD = (CTextureData *) itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.GetData();
|
|
|
|
|
if( pTD != NULL)
|
|
|
|
|
{
|
|
|
|
|
// add rnd offsets to mapping
|
|
|
|
|
itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_mdMapping.md_fVOffset+=((FLOAT)rand())/RAND_MAX*pTD->GetHeight();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnStretchRelativeOffset()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if(m_penEntityHitOnContext==NULL) return;
|
|
|
|
|
CDlgStretchChildOffset dlg;
|
|
|
|
|
if( dlg.DoModal()!=IDOK) return;
|
|
|
|
|
if( m_penEntityHitOnContext->IsSelected(ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
if( iten->GetParent()!=NULL)
|
|
|
|
|
{
|
|
|
|
|
CPlacement3D pl=iten->GetPlacement();
|
|
|
|
|
CPlacement3D plParent=iten->GetParent()->GetPlacement();
|
|
|
|
|
pl.AbsoluteToRelative(plParent);
|
|
|
|
|
FLOAT3D vRelPos=pl.pl_PositionVector;
|
|
|
|
|
vRelPos*=dlg.m_fStretchValue;
|
|
|
|
|
// set stretched offset
|
|
|
|
|
pl.pl_PositionVector=vRelPos;
|
|
|
|
|
pl.RelativeToAbsolute(plParent);
|
|
|
|
|
iten->SetPlacement(pl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if( m_penEntityHitOnContext->GetParent()!=NULL)
|
|
|
|
|
{
|
|
|
|
|
CPlacement3D pl=m_penEntityHitOnContext->GetPlacement();
|
|
|
|
|
CPlacement3D plParent=m_penEntityHitOnContext->GetParent()->GetPlacement();
|
|
|
|
|
pl.AbsoluteToRelative(plParent);
|
|
|
|
|
FLOAT3D vRelPos=pl.pl_PositionVector;
|
|
|
|
|
vRelPos*=dlg.m_fStretchValue;
|
|
|
|
|
// set stretched offset
|
|
|
|
|
pl.pl_PositionVector=vRelPos;
|
|
|
|
|
pl.RelativeToAbsolute(plParent);
|
|
|
|
|
m_penEntityHitOnContext->SetPlacement(pl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDeselectHidden()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// for all of the world's entities
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// if the entity is hidden and selected
|
|
|
|
|
if (iten->en_ulFlags&ENF_HIDDEN && iten->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// deselect it
|
|
|
|
|
pDoc->m_selEntitySelection.Deselect( *iten);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectHidden()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
// for all of the world's entities
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
|
|
|
|
|
{
|
|
|
|
|
// if the entity is hidden and selected
|
|
|
|
|
if (iten->en_ulFlags&ENF_HIDDEN && !iten->IsSelected( ENF_SELECTED))
|
|
|
|
|
{
|
|
|
|
|
// select it
|
|
|
|
|
pDoc->m_selEntitySelection.Select( *iten);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSectorsToBrush()
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygonSelection selPolygons;
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if(pDoc->m_selSectorSelection.Count()==0) return;
|
|
|
|
|
|
|
|
|
|
pDoc->RememberUndo();
|
|
|
|
|
pDoc->ClearSelections(ST_SECTOR);
|
|
|
|
|
// make polygon selection
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(pDoc->m_selSectorSelection, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
selPolygons.Select( *itbpo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PolygonsToBrush(selPolygons, FALSE, TRUE);
|
|
|
|
|
selPolygons.CDynamicContainer<CBrushPolygon>::Clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::PolygonsToBrush(CBrushPolygonSelection &selPolygons, BOOL bDeleteSectors, BOOL bZoning)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
|
|
|
|
|
FLOATaabbox3D boxPolygons;
|
|
|
|
|
// get bbox of selected polygons
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(selPolygons, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
boxPolygons |= itbpo->bpo_boxBoundingBox;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CPlacement3D plCenterDown=CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0));
|
|
|
|
|
plCenterDown.pl_PositionVector=FLOAT3D(boxPolygons.Center()(1),boxPolygons.Min()(2),boxPolygons.Center()(3));
|
|
|
|
|
|
|
|
|
|
CEntity *penwb=theApp.CreateWorldBaseEntity(pDoc->m_woWorld, bZoning, plCenterDown);
|
|
|
|
|
if( penwb==NULL) return;
|
|
|
|
|
|
|
|
|
|
pDoc->m_woWorld.CopyPolygonsToBrush(selPolygons, penwb);
|
|
|
|
|
if(bDeleteSectors)
|
|
|
|
|
{
|
|
|
|
|
// delete old sectors
|
|
|
|
|
pDoc->m_woWorld.DeleteSectors( pDoc->m_selSectorSelection, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pDoc->ClearSelections();
|
|
|
|
|
pDoc->m_chSelections.MarkChanged();
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPolygonsToBrush()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->m_selPolygonSelection.Count()==0) return;
|
|
|
|
|
pDoc->RememberUndo();
|
|
|
|
|
|
|
|
|
|
CDynamicContainer<CBrushPolygon> dcPolygons;
|
|
|
|
|
StorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
|
|
|
|
|
|
|
|
|
|
PolygonsToBrush(pDoc->m_selPolygonSelection, FALSE, FALSE);
|
|
|
|
|
pDoc->m_woWorld.DeletePolygons(dcPolygons);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnClonePolygons()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->m_selPolygonSelection.Count()==0) return;
|
|
|
|
|
pDoc->RememberUndo();
|
|
|
|
|
PolygonsToBrush(pDoc->m_selPolygonSelection, FALSE, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnDeletePolygons()
|
|
|
|
|
{
|
|
|
|
|
CDynamicContainer<CBrushPolygon> dcPolygons;
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->m_selPolygonSelection.Count()==0) return;
|
|
|
|
|
pDoc->RememberUndo();
|
|
|
|
|
|
|
|
|
|
StorePolygonSelection( pDoc->m_selPolygonSelection, dcPolygons);
|
|
|
|
|
pDoc->ClearSelections();
|
|
|
|
|
|
|
|
|
|
pDoc->m_woWorld.DeletePolygons(dcPolygons);
|
|
|
|
|
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyU()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
OnKeyPasteAsProjected();
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainEditMode=TEM_HEIGHTMAP;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyD()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode() == ENTITY_MODE)
|
|
|
|
|
{
|
|
|
|
|
OnDropMarker();
|
|
|
|
|
}
|
|
|
|
|
if( (pDoc->GetEditingMode() == POLYGON_MODE) ||
|
|
|
|
|
(pDoc->GetEditingMode() == VERTEX_MODE) )
|
|
|
|
|
{
|
|
|
|
|
OnFlipPolygon();
|
|
|
|
|
}
|
|
|
|
|
if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_ERASE;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
pDoc->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnFlipPolygon()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
BOOL bSelection=TRUE;
|
|
|
|
|
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse, FALSE, FALSE, FALSE);
|
|
|
|
|
CBrushPolygon *pbpoHit=crRayHit.cr_pbpoBrushPolygon;
|
|
|
|
|
|
|
|
|
|
if( (pbpoHit!=NULL) && !pbpoHit->IsSelected( BPOF_SELECTED) )
|
|
|
|
|
{
|
|
|
|
|
bSelection=FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CDynamicContainer<CBrushPolygon> dcPolygons;
|
|
|
|
|
CDynamicContainer<CBrushSector> dcSectors;
|
|
|
|
|
if( bSelection)
|
|
|
|
|
{
|
|
|
|
|
FOREACHINDYNAMICCONTAINER( pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
dcPolygons.Add( itbpo);
|
|
|
|
|
if( !dcSectors.IsMember(itbpo->bpo_pbscSector))
|
|
|
|
|
{
|
|
|
|
|
dcSectors.Add(itbpo->bpo_pbscSector);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_selPolygonSelection.Clear();
|
|
|
|
|
dcPolygons.Add( pbpoHit);
|
|
|
|
|
dcSectors.Add(pbpoHit->bpo_pbscSector);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pDoc->ClearSelections();
|
|
|
|
|
FOREACHINDYNAMICCONTAINER(dcPolygons, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygon &bpo = *itbpo;
|
|
|
|
|
pDoc->m_woWorld.FlipPolygon(bpo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FOREACHINDYNAMICCONTAINER( dcSectors, CBrushSector, itbsc)
|
|
|
|
|
{
|
|
|
|
|
itbsc->UpdateSector();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{FOREACHINDYNAMICCONTAINER(dcPolygons, CBrushPolygon, itbpo)
|
|
|
|
|
{
|
|
|
|
|
CBrushPolygon &bpo = *itbpo;
|
|
|
|
|
INDEX iTriVtx=bpo.bpo_aiTriangleElements.Count();
|
|
|
|
|
INDEX tmpa=0;
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
pDoc->SetModifiedFlag( TRUE);
|
|
|
|
|
pDoc->UpdateAllViews( NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyM()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode() == POLYGON_MODE)
|
|
|
|
|
{
|
|
|
|
|
// obtain information about where mouse points into the world
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
// if we hit brush entity
|
|
|
|
|
if( (crRayHit.cr_penHit != NULL) &&
|
|
|
|
|
(crRayHit.cr_pbpoBrushPolygon != NULL) )
|
|
|
|
|
{
|
|
|
|
|
CopyMapping(crRayHit.cr_pbpoBrushPolygon);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == VERTEX_MODE)
|
|
|
|
|
{
|
|
|
|
|
OnMergeVertices();
|
|
|
|
|
}
|
|
|
|
|
else if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_MINIMUM;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
pDoc->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectBrush()
|
|
|
|
|
{
|
|
|
|
|
CPoint ptMouse;
|
|
|
|
|
GetCursorPos( &ptMouse);
|
|
|
|
|
InvokeTerrainBrushPalette( ptMouse.x-BRUSH_PALETTE_WIDTH/2, ptMouse.y+BRUSH_PALETTE_HEIGHT/2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectTerrain()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CCastRay crRayHit = GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
if( (crRayHit.cr_penHit!=NULL) && (crRayHit.cr_penHit->GetRenderType() == CEntity::RT_TERRAIN) &&
|
|
|
|
|
(crRayHit.cr_penHit!=GetTerrainEntity()) )
|
|
|
|
|
{
|
|
|
|
|
pDoc->m_ptrSelectedTerrain=crRayHit.cr_penHit->GetTerrain();
|
|
|
|
|
theApp.m_ctTerrainPage.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnAltitudeEditMode()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainEditMode=TEM_HEIGHTMAP;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnLayerTextureEditMode()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainEditMode=TEM_LAYER;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnOptimizeTerrain()
|
|
|
|
|
{
|
|
|
|
|
OptimizeLayers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnRecalculateTerrainShadows()
|
|
|
|
|
{
|
|
|
|
|
CTerrain *ptrTerrain=GetTerrain();
|
|
|
|
|
if( ptrTerrain==NULL) return;
|
|
|
|
|
ptrTerrain->UpdateShadowMap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnViewHeightmap()
|
|
|
|
|
{
|
|
|
|
|
POINT pt;
|
|
|
|
|
GetCursorPos(&pt);
|
|
|
|
|
pt.x-=32;
|
|
|
|
|
pt.y+=32;
|
|
|
|
|
DisplayHeightMapWindow(pt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnImportHeightmap()
|
|
|
|
|
{
|
|
|
|
|
ApplyImportExport(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnImportHeightmap16()
|
|
|
|
|
{
|
|
|
|
|
ApplyImportExport(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnExportHeightmap()
|
|
|
|
|
{
|
|
|
|
|
ApplyImportExport(2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnExportHeightmap16()
|
|
|
|
|
{
|
|
|
|
|
ApplyImportExport(3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnSelectLayer()
|
|
|
|
|
{
|
|
|
|
|
InvokeSelectLayerCombo();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPickLayer()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
CCastRay crRayHit=GetMouseHitInformation( m_ptMouse);
|
|
|
|
|
if( (crRayHit.cr_penHit!=NULL) && (crRayHit.cr_penHit->GetRenderType() == CEntity::RT_TERRAIN))
|
|
|
|
|
{
|
|
|
|
|
CTerrain *ptrTerrain=crRayHit.cr_penHit->GetTerrain();
|
|
|
|
|
Point pt=Calculate2dHitPoint(ptrTerrain, crRayHit.cr_vHit);
|
|
|
|
|
|
|
|
|
|
// in altitude mode
|
|
|
|
|
if(theApp.m_iTerrainEditMode==TEM_HEIGHTMAP)
|
|
|
|
|
{
|
|
|
|
|
// pick altitude
|
|
|
|
|
INDEX iWidth=ptrTerrain->tr_pixHeightMapWidth;
|
|
|
|
|
UWORD *puw=ptrTerrain->tr_auwHeightMap+iWidth*pt.pt_iY+pt.pt_iX;
|
|
|
|
|
theApp.m_uwEditAltitude=*puw;
|
|
|
|
|
}
|
|
|
|
|
// in layer mode
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// pick layer
|
|
|
|
|
INDEX ctLayers=ptrTerrain->tr_atlLayers.Count();
|
|
|
|
|
for(INDEX iLayer=ctLayers-1; iLayer>=0; iLayer--)
|
|
|
|
|
{
|
|
|
|
|
UBYTE ubPower=GetValueFromMask(ptrTerrain, iLayer, crRayHit.cr_vHit);
|
|
|
|
|
if(ubPower>0)
|
|
|
|
|
{
|
|
|
|
|
SelectLayer(iLayer);
|
|
|
|
|
CTerrainLayer *ptlLayer=&ptrTerrain->tr_atlLayers[iLayer];
|
|
|
|
|
if(ptlLayer->tl_ltType==LT_TILE)
|
|
|
|
|
{
|
|
|
|
|
CDynamicContainer<CTileInfo> dcTileInfo;
|
|
|
|
|
INDEX ctTilesPerRaw=0;
|
|
|
|
|
ObtainLayerTileInfo( &dcTileInfo, ptlLayer->tl_ptdTexture, ctTilesPerRaw);
|
|
|
|
|
INDEX ctTiles=dcTileInfo.Count();
|
|
|
|
|
for(INDEX iTile=0; iTile<ctTiles; iTile++)
|
|
|
|
|
{
|
|
|
|
|
CTileInfo &ti=dcTileInfo[iTile];
|
|
|
|
|
if( ((ubPower&TL_TILE_INDEX)==(ti.ti_iy*ptlLayer->tl_ctTilesInRow+ti.ti_ix) ) &&
|
|
|
|
|
(ubPower&TL_VISIBLE) &&
|
|
|
|
|
(!(ubPower&TL_FLIPX) == !ti.ti_bFlipX) &&
|
|
|
|
|
(!(ubPower&TL_FLIPY) == !ti.ti_bFlipY) &&
|
|
|
|
|
(!(ubPower&TL_SWAPXY) == !ti.ti_bSwapXY) )
|
|
|
|
|
{
|
|
|
|
|
ptlLayer->tl_iSelectedTile=iTile;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnIdle(void)
|
|
|
|
|
{
|
|
|
|
|
POINT point;
|
|
|
|
|
GetCursorPos(&point);
|
|
|
|
|
HWND hwndUnderMouse = ::WindowFromPoint(point);
|
|
|
|
|
if( ::GetParent(hwndUnderMouse)==m_hWnd)
|
|
|
|
|
{
|
|
|
|
|
UpdateCursor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode()==TERRAIN_MODE && m_iaInputAction==IA_NONE)
|
|
|
|
|
{
|
|
|
|
|
UpdateLayerDistribution();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnPosterize()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_POSTERIZE;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnFlatten()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode() == TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_FLATTEN;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnApplyFilter()
|
|
|
|
|
{
|
|
|
|
|
ApplyFilterOntoTerrain();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTeSmooth()
|
|
|
|
|
{
|
|
|
|
|
ApplySmoothOntoTerrain();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnEditTerrainPrefs()
|
|
|
|
|
{
|
|
|
|
|
CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
|
|
|
|
|
CDlgTEOperationSettings dlg(pMainFrame);
|
|
|
|
|
dlg.DoModal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateEditTerrainPrefs(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pCmdUI->Enable( pDoc->GetEditingMode()==TERRAIN_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnKeyCtrlShiftG()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if(pDoc->GetEditingMode()==TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
RandomizeWhiteNoise();
|
|
|
|
|
ApplyGenerateTerrain();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
GetChildFrame()->OnGridOnOff();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateKeyCtrlShiftG(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if(pDoc->GetEditingMode()==TERRAIN_MODE)
|
|
|
|
|
{
|
|
|
|
|
pCmdUI->Enable( TRUE);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
GetChildFrame()->OnUpdateGridOnOff(pCmdUI);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTerrainLayerOptions()
|
|
|
|
|
{
|
|
|
|
|
CTerrainLayer *ptlLayer=GetLayer();
|
|
|
|
|
if(ptlLayer==NULL) return;
|
|
|
|
|
|
|
|
|
|
CDlgEditTerrainLayer dlg;
|
|
|
|
|
if( dlg.DoModal()==IDOK)
|
|
|
|
|
{
|
|
|
|
|
INDEX iLayer=GetLayerIndex();
|
|
|
|
|
GenerateLayerDistribution(iLayer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnUpdateTerrainLayerOptions(CCmdUI* pCmdUI)
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
pCmdUI->Enable( pDoc->GetEditingMode()==TERRAIN_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnApplyContinousNoise()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
|
|
|
|
|
{
|
|
|
|
|
ApplyContinousNoiseOntoTerrain();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnApplyMinimum()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
|
|
|
|
|
{
|
|
|
|
|
ApplyMinimumOntoTerrain();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnApplyMaximum()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
|
|
|
|
|
{
|
|
|
|
|
ApplyMaximumOntoTerrain();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnApplyFlatten()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
|
|
|
|
|
{
|
|
|
|
|
ApplyFlattenOntoTerrain();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnApplyPosterize()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
|
|
|
|
|
{
|
|
|
|
|
ApplyPosterizeOntoTerrain();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnOptimizeLayers()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
|
|
|
|
|
{
|
|
|
|
|
OptimizeLayers();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTbrushAltitude()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_PAINT;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTbrushSmooth()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_SMOOTH;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTbrushEquilaze()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_FLATTEN;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTbrushErase()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_ERASE;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTbrushNoise()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_RND_NOISE;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTbrushContinousNoise()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_CONTINOUS_NOISE;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTbrushFilter()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_FILTER;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTbrushFlatten()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_FLATTEN;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTbrushMaximum()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_MAXIMUM;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTbrushMinimum()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_MINIMUM;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTbrushPosterize()
|
|
|
|
|
{
|
|
|
|
|
theApp.m_iTerrainBrushMode=TBM_POSTERIZE;
|
|
|
|
|
theApp.m_ctTerrainPageCanvas.MarkChanged();
|
|
|
|
|
GetDocument()->SetStatusLineModeInfoMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CWorldEditorView::OnTerrainProperties()
|
|
|
|
|
{
|
|
|
|
|
CWorldEditorDoc* pDoc = GetDocument();
|
|
|
|
|
if( pDoc->GetEditingMode()==TERRAIN_MODE && GetTerrain()!=NULL)
|
|
|
|
|
{
|
|
|
|
|
CDlgTerrainProperties dlg;
|
|
|
|
|
dlg.DoModal();
|
|
|
|
|
}
|
|
|
|
|
}
|