/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code 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 Doom 3 Source Code. If not, see .
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "tools/edit_gui_common.h"
#include "qe3.h"
#include "Radiant.h"
#include "XYWnd.h"
#include "DialogInfo.h"
#include "splines.h"
#include "../../renderer/tr_local.h"
#include "../../renderer/model_local.h" // for idRenderModelLiquid
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
const char *g_pDimStrings[] = { "x:%.f", "y:%.f", "z:%.f" };
const char *g_pOrgStrings[] = { "(x:%.f y:%.f)", "(x:%.f z:%.f)", "(y:%.f z:%.f)" };
CString g_strDim;
CString g_strStatus;
bool g_bCrossHairs = false;
bool g_bScaleMode;
int g_nScaleHow;
bool g_bRotateMode;
bool g_bClipMode;
bool g_bRogueClipMode;
bool g_bSwitch;
CClipPoint g_Clip1;
CClipPoint g_Clip2;
CClipPoint g_Clip3;
CClipPoint *g_pMovingClip;
brush_t g_brFrontSplits;
brush_t g_brBackSplits;
brush_t g_brClipboard;
brush_t g_brUndo;
entity_t g_enClipboard;
idVec3 g_vRotateOrigin;
idVec3 g_vRotation;
bool g_bPathMode;
CClipPoint g_PathPoints[256];
CClipPoint *g_pMovingPath;
int g_nPathCount;
int g_nPathLimit;
bool g_bSmartGo;
bool g_bPointMode;
CClipPoint g_PointPoints[512];
CClipPoint *g_pMovingPoint;
int g_nPointCount;
int g_nPointLimit;
const int XY_LEFT = 0x01;
const int XY_RIGHT = 0x02;
const int XY_UP = 0x04;
const int XY_DOWN = 0x08;
PFNPathCallback *g_pPathFunc = NULL;
void Select_Ungroup();
/*
=======================================================================================================================
=======================================================================================================================
*/
void AcquirePath(int nCount, PFNPathCallback *pFunc) {
g_nPathCount = 0;
g_nPathLimit = nCount;
g_pPathFunc = pFunc;
g_bPathMode = true;
}
CPtrArray g_ptrMenus;
CMemFile g_Clipboard(4096);
CMemFile g_PatchClipboard(4096);
extern int pressx;
extern int pressy;
/*
=======================================================================================================================
=======================================================================================================================
*/
float fDiff(float f1, float f2) {
if (f1 > f2) {
return f1 - f2;
}
else {
return f2 - f1;
}
}
#define MAX_DRAG_POINTS 128
CPtrArray dragPoints;
static CDragPoint *activeDrag = NULL;
static bool activeDragging = false;
/*
=======================================================================================================================
=======================================================================================================================
*/
bool CDragPoint::PointWithin(idVec3 p, int nView) {
if (nView == -1) {
if (fDiff(p[0], vec[0]) <= 3 && fDiff(p[1], vec[1]) <= 3 && fDiff(p[2], vec[2]) <= 3) {
return true;
}
}
else {
int nDim1 = (nView == YZ) ? 1 : 0;
int nDim2 = (nView == XY) ? 1 : 2;
if (fDiff(p[nDim1], vec[nDim1]) <= 3 && fDiff(p[nDim2], vec[nDim2]) <= 3) {
return true;
}
}
return false;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
CDragPoint *PointRay(const idVec3 &org, const idVec3 &dir, float *dist) {
int i, besti;
float d, bestd;
idVec3 temp;
CDragPoint *drag = NULL;
CDragPoint *priority = NULL;
// find the point closest to the ray
float scale = g_pParentWnd->ActiveXY()->Scale();
besti = -1;
bestd = 12 / scale / 2;
int count = dragPoints.GetSize();
for (i = 0; i < count; i++) {
drag = reinterpret_cast < CDragPoint * > (dragPoints[i]);
temp = drag->vec - org;
d = temp * dir;
temp = org + d * dir;
temp = drag->vec - temp;
d = temp.Length();
if ( d < bestd ) {
bestd = d;
besti = i;
if (priority == NULL) {
priority = reinterpret_cast < CDragPoint * > (dragPoints[besti]);
if (!priority->priority) {
priority = NULL;
}
}
}
}
if (besti == -1) {
return NULL;
}
drag = reinterpret_cast < CDragPoint * > (dragPoints[besti]);
if (priority && !drag->priority) {
drag = priority;
}
return drag;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void ClearSelectablePoints(brush_t *b) {
if (b == NULL) {
dragPoints.RemoveAll();
}
else {
CPtrArray ptr;
ptr.Copy(dragPoints);
dragPoints.RemoveAll();
int count = ptr.GetSize();
for (int i = 0; i < count; i++) {
if (b == reinterpret_cast < CDragPoint * > ( ptr.GetAt(i))->pBrush ) {
continue;
}
else {
dragPoints.Add(ptr.GetAt(i));
}
}
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void AddSelectablePoint(brush_t *b, idVec3 v, int type, bool priority) {
dragPoints.Add(new CDragPoint(b, v, type, priority));
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void UpdateSelectablePoint(brush_t *b, idVec3 v, int type) {
int count = dragPoints.GetSize();
for (int i = 0; i < count; i++) {
CDragPoint *drag = reinterpret_cast < CDragPoint * > (dragPoints.GetAt(i));
if (b == drag->pBrush && type == drag->nType) {
VectorCopy(v, drag->vec);
return;
}
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void VectorToAngles(idVec3 vec, idVec3 angles) {
float forward;
float yaw, pitch;
if ((vec[0] == 0) && (vec[1] == 0)) {
yaw = 0;
if (vec[2] > 0) {
pitch = 90;
}
else {
pitch = 270;
}
}
else {
yaw = RAD2DEG( atan2(vec[1], vec[0]) );
if (yaw < 0) {
yaw += 360;
}
forward = (float)idMath::Sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
pitch = RAD2DEG( atan2(vec[2], forward) );
if (pitch < 0) {
pitch += 360;
}
}
angles[0] = pitch;
angles[1] = yaw;
angles[2] = 0;
}
/*
=======================================================================================================================
RotateLight target is relative to the light origin up and right are relative to the target up and right are
perpendicular and are on a plane through the target with the target vector as normal delta is the movement of the
target relative to the light
=======================================================================================================================
*/
void VectorSnapGrid(idVec3 &v) {
v.x = floor(v.x / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
v.y = floor(v.y / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
v.z = floor(v.z / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
static void RotateLight(idVec3 &target, idVec3 &up, idVec3 &right, const idVec3 &delta) {
idVec3 newtarget, cross, dst;
idVec3 normal;
double angle, dist, d, len;
idMat3 rot;
// calculate new target
newtarget = target + delta;
// get the up and right vector relative to the light origin
up += target;
right += target;
len = target.Length() * newtarget.Length();
if (len > 0.1) {
// calculate the rotation angle between the vectors
double dp = target * newtarget;
double dv = dp / len;
angle = RAD2DEG( idMath::ACos( dv ) );
// get a vector orthogonal to the rotation plane
cross = target.Cross( newtarget );
cross.Normalize();
if (cross[0] || cross[1] || cross[2]) {
// build the rotation matrix
rot = idRotation( vec3_origin, cross, angle ).ToMat3();
rot.ProjectVector(target, dst);
target = dst;
rot.ProjectVector( up, dst );
up = dst;
rot.ProjectVector( right, dst);
right = dst;
}
}
//
// project the up and right vectors onto a plane that goes through the target and
// has normal vector target.Normalize()
//
normal = target;
normal.Normalize();
dist = normal * target;
d = (normal * up) - dist;
up -= d * normal;
d = (normal * right) - dist;
right -= d * normal;
//
// FIXME: maybe calculate the right vector with a cross product between the target
// and up vector, just to make sure the up and right vectors are perpendicular
// get the up and right vectors relative to the target
//
up -= target;
right -= target;
// move the target in the (target - light_origin) direction
target = newtarget;
VectorSnapGrid(target);
VectorSnapGrid(up);
VectorSnapGrid(right);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
extern idVec3 Brush_TransformedPoint(brush_t *b, const idVec3 &in);
extern idMat3 Brush_RotationMatrix(brush_t *b);
bool UpdateActiveDragPoint(const idVec3 &move) {
if (activeDrag) {
idMat3 mat = Brush_RotationMatrix(activeDrag->pBrush);
idMat3 invmat = mat.Transpose();
idVec3 target, up, right, start, end;
CString str;
if (activeDrag->nType == LIGHT_TARGET) {
GetVectorForKey(activeDrag->pBrush->owner, "light_target", target);
GetVectorForKey(activeDrag->pBrush->owner, "light_up", up);
GetVectorForKey(activeDrag->pBrush->owner, "light_right", right);
target *= mat;
up *= mat;
right *= mat;
RotateLight(target, up, right, move);
target *= invmat;
up *= invmat;
right *= invmat;
SetKeyVec3(activeDrag->pBrush->owner, "light_target", target);
SetKeyVec3(activeDrag->pBrush->owner, "light_up", up);
SetKeyVec3(activeDrag->pBrush->owner, "light_right", right);
target += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush, target), LIGHT_TARGET);
up += target;
UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,up), LIGHT_UP);
right += target;
UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,right), LIGHT_RIGHT);
}
else if (activeDrag->nType == LIGHT_UP) {
GetVectorForKey(activeDrag->pBrush->owner, "light_up", up);
up *= mat;
up += move;
up *= invmat;
SetKeyVec3(activeDrag->pBrush->owner, "light_up", up);
GetVectorForKey(activeDrag->pBrush->owner, "light_target", target);
target += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
up += target;
UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,up), LIGHT_UP);
}
else if (activeDrag->nType == LIGHT_RIGHT) {
GetVectorForKey(activeDrag->pBrush->owner, "light_right", right);
right *= mat;
right += move;
right *= invmat;
SetKeyVec3(activeDrag->pBrush->owner, "light_right", right);
GetVectorForKey(activeDrag->pBrush->owner, "light_target", target);
target += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
right += target;
UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,right), LIGHT_RIGHT);
}
else if (activeDrag->nType == LIGHT_START) {
GetVectorForKey(activeDrag->pBrush->owner, "light_start", start);
start *= mat;
start += move;
start *= invmat;
SetKeyVec3(activeDrag->pBrush->owner, "light_start", start);
start += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,start), LIGHT_START);
}
else if (activeDrag->nType == LIGHT_END) {
GetVectorForKey(activeDrag->pBrush->owner, "light_end", end);
end *= mat;
end += move;
end *= invmat;
SetKeyVec3(activeDrag->pBrush->owner, "light_end", end);
end += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,end), LIGHT_END);
}
else if (activeDrag->nType == LIGHT_CENTER) {
GetVectorForKey(activeDrag->pBrush->owner, "light_center", end);
end *= mat;
end += move;
end *= invmat;
SetKeyVec3(activeDrag->pBrush->owner, "light_center", end);
end += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush, end), LIGHT_CENTER);
}
// FIXME: just build the frustrum values
Brush_Build(activeDrag->pBrush);
return true;
}
return false;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
bool SetDragPointCursor(idVec3 p, int nView) {
activeDrag = NULL;
int numDragPoints = dragPoints.GetSize();
for (int i = 0; i < numDragPoints; i++) {
if (reinterpret_cast < CDragPoint * > (dragPoints[i])->PointWithin(p, nView)) {
activeDrag = reinterpret_cast < CDragPoint * > (dragPoints[i]);
return true;
}
}
return false;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void SetActiveDrag(CDragPoint *p) {
activeDrag = p;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void ClearActiveDrag() {
activeDrag = NULL;
}
// CXYWnd
IMPLEMENT_DYNCREATE(CXYWnd, CWnd);
/*
=======================================================================================================================
=======================================================================================================================
*/
CXYWnd::CXYWnd() {
g_brClipboard.next = &g_brClipboard;
g_brUndo.next = &g_brUndo;
g_nScaleHow = 0;
g_bRotateMode = false;
g_bClipMode = false;
g_bRogueClipMode = false;
g_bSwitch = true;
g_pMovingClip = NULL;
g_pMovingPath = NULL;
g_brFrontSplits.next = &g_brFrontSplits;
g_brBackSplits.next = &g_brBackSplits;
m_bActive = false;
m_bRButtonDown = false;
m_nUpdateBits = W_XY;
g_bPathMode = false;
g_nPathCount = 0;
g_nPathLimit = 0;
m_nTimerID = -1;
m_nButtonstate = 0;
XY_Init();
}
/*
=======================================================================================================================
=======================================================================================================================
*/
CXYWnd::~CXYWnd() {
int nSize = g_ptrMenus.GetSize();
while (nSize > 0) {
CMenu *pMenu = reinterpret_cast < CMenu * > (g_ptrMenus.GetAt(nSize - 1));
ASSERT(pMenu);
pMenu->DestroyMenu();
delete pMenu;
nSize--;
}
g_ptrMenus.RemoveAll();
m_mnuDrop.DestroyMenu();
}
BEGIN_MESSAGE_MAP(CXYWnd, CWnd)
//{{AFX_MSG_MAP(CXYWnd)
ON_WM_CREATE()
ON_WM_LBUTTONDOWN()
ON_WM_MBUTTONDOWN()
ON_WM_RBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MBUTTONUP()
ON_WM_RBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_PAINT()
ON_WM_KEYDOWN()
ON_WM_SIZE()
ON_WM_DESTROY()
ON_COMMAND(ID_SELECT_MOUSEROTATE, OnSelectMouserotate)
ON_WM_TIMER()
ON_WM_KEYUP()
ON_WM_NCCALCSIZE()
ON_WM_KILLFOCUS()
ON_WM_SETFOCUS()
ON_WM_CLOSE()
ON_WM_ERASEBKGND()
ON_WM_MOUSEWHEEL()
ON_COMMAND(ID_DROP_NEWMODEL, OnDropNewmodel)
//}}AFX_MSG_MAP
ON_COMMAND_RANGE(ID_ENTITY_START, ID_ENTITY_END, OnEntityCreate)
END_MESSAGE_MAP()
// CXYWnd message handlers
LONG WINAPI XYWndProc(HWND, UINT, WPARAM, LPARAM);
/*
=======================================================================================================================
=======================================================================================================================
*/
BOOL CXYWnd::PreCreateWindow(CREATESTRUCT &cs) {
WNDCLASS wc;
HINSTANCE hInstance = AfxGetInstanceHandle();
if (::GetClassInfo(hInstance, XY_WINDOW_CLASS, &wc) == FALSE) {
// Register a new class
memset(&wc, 0, sizeof(wc));
wc.style = CS_NOCLOSE;
wc.lpszClassName = XY_WINDOW_CLASS;
wc.hCursor = NULL; // LoadCursor (NULL,IDC_ARROW);
wc.lpfnWndProc = ::DefWindowProc;
if (AfxRegisterClass(&wc) == FALSE) {
Error("CCamWnd RegisterClass: failed");
}
}
cs.lpszClass = XY_WINDOW_CLASS;
cs.lpszName = "VIEW";
if (cs.style != QE3_CHILDSTYLE) {
cs.style = QE3_SPLITTER_STYLE;
}
return CWnd::PreCreateWindow(cs);
}
HDC s_hdcXY;
HGLRC s_hglrcXY;
static unsigned s_stipple[32] = {
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
0xaaaaaaaa,
0x55555555,
};
/*
=======================================================================================================================
WXY_WndProc
=======================================================================================================================
*/
LONG WINAPI XYWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg)
{
case WM_DESTROY:
return 0;
case WM_NCCALCSIZE: // don't let windows copy pixels
DefWindowProc(hWnd, uMsg, wParam, lParam);
return WVR_REDRAW;
case WM_KILLFOCUS:
case WM_SETFOCUS:
SendMessage(hWnd, WM_NCACTIVATE, uMsg == WM_SETFOCUS, 0);
return 0;
case WM_CLOSE:
DestroyWindow(hWnd);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
static void WXY_InitPixelFormat(PIXELFORMATDESCRIPTOR *pPFD) {
memset(pPFD, 0, sizeof(*pPFD));
pPFD->nSize = sizeof(PIXELFORMATDESCRIPTOR);
pPFD->nVersion = 1;
pPFD->dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pPFD->iPixelType = PFD_TYPE_RGBA;
pPFD->cColorBits = 24;
pPFD->cDepthBits = 32;
pPFD->iLayerType = PFD_MAIN_PLANE;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void WXY_Print(void) {
DOCINFO di;
PRINTDLG pd;
/* initialize the PRINTDLG struct and execute it */
memset(&pd, 0, sizeof(pd));
pd.lStructSize = sizeof(pd);
pd.hwndOwner = g_pParentWnd->GetXYWnd()->GetSafeHwnd();
pd.Flags = PD_RETURNDC;
pd.hInstance = 0;
if (!PrintDlg(&pd) || !pd.hDC) {
g_pParentWnd->MessageBox("Could not PrintDlg()", "QE4 Print Error", MB_OK | MB_ICONERROR);
return;
}
/* StartDoc */
memset(&di, 0, sizeof(di));
di.cbSize = sizeof(di);
di.lpszDocName = "QE4";
if (StartDoc(pd.hDC, &di) <= 0) {
g_pParentWnd->MessageBox("Could not StartDoc()", "QE4 Print Error", MB_OK | MB_ICONERROR);
return;
}
/* StartPage */
if (StartPage(pd.hDC) <= 0) {
g_pParentWnd->MessageBox("Could not StartPage()", "QE4 Print Error", MB_OK | MB_ICONERROR);
return;
} { /* read pixels from the XY window */
int bmwidth = 320, bmheight = 320;
int pwidth, pheight;
RECT r;
GetWindowRect(g_pParentWnd->GetXYWnd()->GetSafeHwnd(), &r);
bmwidth = r.right - r.left;
bmheight = r.bottom - r.top;
pwidth = GetDeviceCaps(pd.hDC, PHYSICALWIDTH) - GetDeviceCaps(pd.hDC, PHYSICALOFFSETX);
pheight = GetDeviceCaps(pd.hDC, PHYSICALHEIGHT) - GetDeviceCaps(pd.hDC, PHYSICALOFFSETY);
StretchBlt(pd.hDC, 0, 0, pwidth, pheight, s_hdcXY, 0, 0, bmwidth, bmheight, SRCCOPY);
}
/* EndPage and EndDoc */
if (EndPage(pd.hDC) <= 0) {
g_pParentWnd->MessageBox("QE4 Print Error", "Could not EndPage()", MB_OK | MB_ICONERROR);
return;
}
if (EndDoc(pd.hDC) <= 0) {
g_pParentWnd->MessageBox("QE4 Print Error", "Could not EndDoc()", MB_OK | MB_ICONERROR);
return;
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
int CXYWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
if (CWnd::OnCreate(lpCreateStruct) == -1) {
return -1;
}
s_hdcXY = ::GetDC(GetSafeHwnd());
QEW_SetupPixelFormat(s_hdcXY, false);
qglPolygonStipple((unsigned char *)s_stipple);
qglLineStipple(3, 0xaaaa);
return 0;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
float ptSum(idVec3 pt) {
return pt[0] + pt[1] + pt[2];
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::DropClipPoint(UINT nFlags, CPoint point) {
CRect rctZ;
GetClientRect(rctZ);
if (g_pMovingClip) {
SetCapture();
SnapToPoint(point.x, rctZ.Height() - 1 - point.y, *g_pMovingClip);
}
else {
idVec3 *pPt = NULL;
if (g_Clip1.Set() == false) {
pPt = g_Clip1;
g_Clip1.Set(true);
g_Clip1.m_ptScreen = point;
}
else if (g_Clip2.Set() == false) {
pPt = g_Clip2;
g_Clip2.Set(true);
g_Clip2.m_ptScreen = point;
}
else if (g_Clip3.Set() == false) {
pPt = g_Clip3;
g_Clip3.Set(true);
g_Clip3.m_ptScreen = point;
}
else {
RetainClipMode(true);
pPt = g_Clip1;
g_Clip1.Set(true);
g_Clip1.m_ptScreen = point;
}
SnapToPoint(point.x, rctZ.Height() - 1 - point.y, *pPt);
// Put the off-viewaxis coordinate at the top or bottom of selected brushes
if ( GetAsyncKeyState(VK_CONTROL) & 0x8000 ) {
if ( selected_brushes.next != &selected_brushes ) {
idVec3 smins, smaxs;
Select_GetBounds( smins, smaxs );
if ( m_nViewType == XY ) {
if ( GetAsyncKeyState(VK_SHIFT) & 0x8000 ) {
pPt->z = smaxs.z;
} else {
pPt->z = smins.z;
}
} else if ( m_nViewType == YZ ) {
if ( GetAsyncKeyState(VK_SHIFT) & 0x8000 ) {
pPt->x = smaxs.x;
} else {
pPt->x = smins.x;
}
} else {
if ( GetAsyncKeyState(VK_SHIFT) & 0x8000 ) {
pPt->y = smaxs.y;
} else {
pPt->y = smins.y;
}
}
}
}
}
Sys_UpdateWindows(XY | W_CAMERA_IFON);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::DropPathPoint(UINT nFlags, CPoint point) {
CRect rctZ;
GetClientRect(rctZ);
if (g_pMovingPath) {
SetCapture();
SnapToPoint(point.x, rctZ.Height() - 1 - point.y, *g_pMovingPath);
}
else {
g_PathPoints[g_nPathCount].Set(true);
g_PathPoints[g_nPathCount].m_ptScreen = point;
SnapToPoint(point.x, rctZ.Height() - 1 - point.y, g_PathPoints[g_nPathCount]);
g_nPathCount++;
if (g_nPathCount == g_nPathLimit) {
if (g_pPathFunc) {
g_pPathFunc(true, g_nPathCount);
}
g_nPathCount = 0;
g_bPathMode = false;
g_pPathFunc = NULL;
}
}
Sys_UpdateWindows(XY | W_CAMERA_IFON);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::AddPointPoint(UINT nFlags, idVec3 *pVec) {
g_PointPoints[g_nPointCount].Set(true);
// g_PointPoints[g_nPointCount].m_ptScreen = point;
g_PointPoints[g_nPointCount].m_ptClip = *pVec;
g_PointPoints[g_nPointCount].SetPointPtr(pVec);
g_nPointCount++;
Sys_UpdateWindows(XY | W_CAMERA_IFON);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnLButtonDown(UINT nFlags, CPoint point) {
g_pParentWnd->SetActiveXY(this);
UndoCopy();
if (g_pParentWnd->GetNurbMode()) {
int i, num = g_pParentWnd->GetNurb()->GetNumValues();
idList temp;
for (i = 0; i < num; i++) {
temp.Append(g_pParentWnd->GetNurb()->GetValue(i));
}
CRect rctZ;
GetClientRect(rctZ);
idVec3 v3;
SnapToPoint(point.x, rctZ.Height() - 1 - point.y, v3);
temp.Append(idVec2(v3.x, v3.y));
num++;
g_pParentWnd->GetNurb()->Clear();
for (i = 0; i < num; i++) {
g_pParentWnd->GetNurb()->AddValue((1000 * i)/num, temp[i]);
}
}
if (ClipMode() && !RogueClipMode()) {
DropClipPoint(nFlags, point);
}
else if (PathMode()) {
DropPathPoint(nFlags, point);
}
else {
OriginalButtonDown(nFlags, point);
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnMButtonDown(UINT nFlags, CPoint point) {
OriginalButtonDown(nFlags, point);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
float Betwixt(float f1, float f2) {
if (f1 > f2) {
return f2 + ((f1 - f2) / 2);
}
else {
return f1 + ((f2 - f1) / 2);
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::ProduceSplits(brush_t **pFront, brush_t **pBack) {
*pFront = NULL;
*pBack = NULL;
if (ClipMode()) {
if (g_Clip1.Set() && g_Clip2.Set()) {
face_t face;
VectorCopy(g_Clip1.m_ptClip, face.planepts[0]);
VectorCopy(g_Clip2.m_ptClip, face.planepts[1]);
VectorCopy(g_Clip3.m_ptClip, face.planepts[2]);
if (selected_brushes.next && (selected_brushes.next->next == &selected_brushes)) {
if (g_Clip3.Set() == false) {
if (m_nViewType == XY) {
face.planepts[0][2] = selected_brushes.next->mins[2];
face.planepts[1][2] = selected_brushes.next->mins[2];
face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
face.planepts[2][2] = selected_brushes.next->maxs[2];
}
else if (m_nViewType == YZ) {
face.planepts[0][0] = selected_brushes.next->mins[0];
face.planepts[1][0] = selected_brushes.next->mins[0];
face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
face.planepts[2][0] = selected_brushes.next->maxs[0];
}
else {
face.planepts[0][1] = selected_brushes.next->mins[1];
face.planepts[1][1] = selected_brushes.next->mins[1];
face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
face.planepts[2][1] = selected_brushes.next->maxs[1];
}
}
Brush_SplitBrushByFace(selected_brushes.next, &face, pFront, pBack);
}
}
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CleanList(brush_t *pList) {
brush_t *pBrush = pList->next;
while (pBrush != NULL && pBrush != pList) {
brush_t *pNext = pBrush->next;
Brush_Free(pBrush);
pBrush = pNext;
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::ProduceSplitLists() {
if (AnyPatchesSelected()) {
Sys_Status("Deslecting patches for clip operation.\n");
brush_t *next;
for (brush_t * pb = selected_brushes.next; pb != &selected_brushes; pb = next) {
next = pb->next;
if (pb->pPatch) {
Brush_RemoveFromList(pb);
Brush_AddToList(pb, &active_brushes);
UpdatePatchInspector();
}
}
}
CleanList(&g_brFrontSplits);
CleanList(&g_brBackSplits);
g_brFrontSplits.next = &g_brFrontSplits;
g_brBackSplits.next = &g_brBackSplits;
brush_t *pBrush;
for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) {
brush_t *pFront = NULL;
brush_t *pBack = NULL;
if (ClipMode()) {
if (g_Clip1.Set() && g_Clip2.Set()) {
face_t face;
VectorCopy(g_Clip1.m_ptClip, face.planepts[0]);
VectorCopy(g_Clip2.m_ptClip, face.planepts[1]);
VectorCopy(g_Clip3.m_ptClip, face.planepts[2]);
if (g_Clip3.Set() == false) {
if (g_pParentWnd->ActiveXY()->GetViewType() == XY) {
face.planepts[0][2] = pBrush->mins[2];
face.planepts[1][2] = pBrush->mins[2];
face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
face.planepts[2][2] = pBrush->maxs[2];
}
else if (g_pParentWnd->ActiveXY()->GetViewType() == YZ) {
face.planepts[0][0] = pBrush->mins[0];
face.planepts[1][0] = pBrush->mins[0];
face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
face.planepts[2][0] = pBrush->maxs[0];
}
else {
face.planepts[0][1] = pBrush->mins[1];
face.planepts[1][1] = pBrush->mins[1];
face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
face.planepts[2][1] = pBrush->maxs[1];
}
}
Brush_SplitBrushByFace(pBrush, &face, &pFront, &pBack);
if (pBack) {
Brush_AddToList(pBack, &g_brBackSplits);
}
if (pFront) {
Brush_AddToList(pFront, &g_brFrontSplits);
}
}
}
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void Brush_CopyList(brush_t *pFrom, brush_t *pTo) {
brush_t *pBrush = pFrom->next;
while (pBrush != NULL && pBrush != pFrom) {
brush_t *pNext = pBrush->next;
Brush_RemoveFromList(pBrush);
Brush_AddToList(pBrush, pTo);
pBrush = pNext;
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnRButtonDown(UINT nFlags, CPoint point) {
g_pParentWnd->SetActiveXY(this);
m_ptDown = point;
m_bRButtonDown = true;
if (g_PrefsDlg.m_nMouseButtons == 3) { // 3 button mouse
if ((GetAsyncKeyState(VK_CONTROL) & 0x8000)) {
if (ClipMode()) { // already there?
DropClipPoint(nFlags, point);
}
else {
SetClipMode(true);
g_bRogueClipMode = true;
DropClipPoint(nFlags, point);
}
return;
}
}
OriginalButtonDown(nFlags, point);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnLButtonUp(UINT nFlags, CPoint point) {
if (ClipMode()) {
if (g_pMovingClip) {
ReleaseCapture();
g_pMovingClip = NULL;
}
}
OriginalButtonUp(nFlags, point);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnMButtonUp(UINT nFlags, CPoint point) {
OriginalButtonUp(nFlags, point);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnRButtonUp(UINT nFlags, CPoint point) {
m_bRButtonDown = false;
if (point == m_ptDown) { // mouse didn't move
bool bGo = true;
if ((GetAsyncKeyState(VK_MENU) & 0x8000)) {
bGo = false;
}
if ((GetAsyncKeyState(VK_CONTROL) & 0x8000)) {
bGo = false;
}
if ((GetAsyncKeyState(VK_SHIFT) & 0x8000)) {
bGo = false;
}
if (bGo) {
HandleDrop();
}
}
OriginalButtonUp(nFlags, point);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OriginalButtonDown(UINT nFlags, CPoint point) {
CRect rctZ;
GetClientRect(rctZ);
SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
if (g_pParentWnd->GetTopWindow() != this) {
BringWindowToTop();
}
SetFocus();
SetCapture();
XY_MouseDown(point.x, rctZ.Height() - 1 - point.y, nFlags);
m_nScrollFlags = nFlags;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OriginalButtonUp(UINT nFlags, CPoint point) {
CRect rctZ;
GetClientRect(rctZ);
XY_MouseUp(point.x, rctZ.Height() - 1 - point.y, nFlags);
if (!(nFlags & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON))) {
ReleaseCapture();
}
}
idVec3 tdp;
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnMouseMove(UINT nFlags, CPoint point) {
m_ptDown.x = 0;
m_ptDown.y = 0;
if
(
g_PrefsDlg.m_bChaseMouse == TRUE &&
(point.x < 0 || point.y < 0 || point.x > m_nWidth || point.y > m_nHeight) &&
GetCapture() == this
) {
float fAdjustment = (g_qeglobals.d_gridsize / 8 * 64) / m_fScale;
// m_ptDrag = point;
m_ptDragAdj.x = 0;
m_ptDragAdj.y = 0;
if (point.x < 0) {
m_ptDragAdj.x = -fAdjustment;
}
else if (point.x > m_nWidth) {
m_ptDragAdj.x = fAdjustment;
}
if (point.y < 0) {
m_ptDragAdj.y = -fAdjustment;
}
else if (point.y > m_nHeight) {
m_ptDragAdj.y = fAdjustment;
}
if (m_nTimerID == -1) {
m_nTimerID = SetTimer(100, 50, NULL);
m_ptDrag = point;
m_ptDragTotal = 0;
}
return;
}
// else if (m_nTimerID != -1)
if (m_nTimerID != -1) {
KillTimer(m_nTimerID);
pressx -= m_ptDragTotal.x;
pressy += m_ptDragTotal.y;
m_nTimerID = -1;
// return;
}
bool bCrossHair = false;
if (!m_bRButtonDown) {
tdp[0] = tdp[1] = tdp[2] = 0.0;
SnapToPoint(point.x, m_nHeight - 1 - point.y, tdp);
g_strStatus.Format("x:: %.1f y:: %.1f z:: %.1f", tdp[0], tdp[1], tdp[2]);
g_pParentWnd->SetStatusText(1, g_strStatus);
//
// i need to generalize the point code.. having 3 flavors pretty much sucks.. once
// the new curve stuff looks like it is going to stick i will rationalize this
// down to a single interface..
//
if (PointMode()) {
if (g_pMovingPoint && GetCapture() == this) {
bCrossHair = true;
SnapToPoint(point.x, m_nHeight - 1 - point.y, g_pMovingPoint->m_ptClip);
g_pMovingPoint->UpdatePointPtr();
Sys_UpdateWindows(XY | W_CAMERA_IFON);
}
else {
g_pMovingPoint = NULL;
int nDim1 = (m_nViewType == YZ) ? 1 : 0;
int nDim2 = (m_nViewType == XY) ? 1 : 2;
for (int n = 0; n < g_nPointCount; n++) {
if
(
fDiff(g_PointPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 &&
fDiff(g_PointPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3
) {
bCrossHair = true;
g_pMovingPoint = &g_PointPoints[n];
}
}
}
}
else if (ClipMode()) {
if (g_pMovingClip && GetCapture() == this) {
bCrossHair = true;
SnapToPoint(point.x, m_nHeight - 1 - point.y, g_pMovingClip->m_ptClip);
Sys_UpdateWindows(XY | W_CAMERA_IFON);
}
else {
g_pMovingClip = NULL;
int nDim1 = (m_nViewType == YZ) ? 1 : 0;
int nDim2 = (m_nViewType == XY) ? 1 : 2;
if (g_Clip1.Set()) {
if
(
fDiff(g_Clip1.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
fDiff(g_Clip1.m_ptClip[nDim2], tdp[nDim2]) < 3
) {
bCrossHair = true;
g_pMovingClip = &g_Clip1;
}
}
if (g_Clip2.Set()) {
if
(
fDiff(g_Clip2.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
fDiff(g_Clip2.m_ptClip[nDim2], tdp[nDim2]) < 3
) {
bCrossHair = true;
g_pMovingClip = &g_Clip2;
}
}
if (g_Clip3.Set()) {
if
(
fDiff(g_Clip3.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
fDiff(g_Clip3.m_ptClip[nDim2], tdp[nDim2]) < 3
) {
bCrossHair = true;
g_pMovingClip = &g_Clip3;
}
}
}
if (bCrossHair == false) {
XY_MouseMoved(point.x, m_nHeight - 1 - point.y, nFlags);
}
}
else if (PathMode()) {
if (g_pMovingPath && GetCapture() == this) {
bCrossHair = true;
SnapToPoint(point.x, m_nHeight - 1 - point.y, g_pMovingPath->m_ptClip);
Sys_UpdateWindows(XY | W_CAMERA_IFON);
}
else {
g_pMovingPath = NULL;
int nDim1 = (m_nViewType == YZ) ? 1 : 0;
int nDim2 = (m_nViewType == XY) ? 1 : 2;
for (int n = 0; n < g_nPathCount; n++) {
if
(
fDiff(g_PathPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 &&
fDiff(g_PathPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3
) {
bCrossHair = true;
g_pMovingPath = &g_PathPoints[n];
}
}
}
}
else {
bCrossHair = XY_MouseMoved(point.x, m_nHeight - 1 - point.y, nFlags);
}
}
else {
bCrossHair = XY_MouseMoved(point.x, m_nHeight - 1 - point.y, nFlags);
}
if (bCrossHair) {
SetCursor(::LoadCursor(NULL, IDC_CROSS));
}
else {
SetCursor(::LoadCursor(NULL, IDC_ARROW));
}
/// If precision crosshair is active, force redraw of the 2d view on mouse move
if( m_precisionCrosshairMode != PRECISION_CROSSHAIR_NONE )
{
/// Force 2d view redraw (so that the precision cursor moves with the mouse)
Sys_UpdateWindows( W_XY );
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::RetainClipMode(bool bMode) {
bool bSave = g_bRogueClipMode;
SetClipMode(bMode);
if (bMode == true) {
g_bRogueClipMode = bSave;
}
else {
g_bRogueClipMode = false;
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::SetClipMode(bool bMode) {
g_bClipMode = bMode;
g_bRogueClipMode = false;
if (bMode) {
g_Clip1.Reset();
g_Clip2.Reset();
g_Clip3.Reset();
CleanList(&g_brFrontSplits);
CleanList(&g_brBackSplits);
g_brFrontSplits.next = &g_brFrontSplits;
g_brBackSplits.next = &g_brBackSplits;
}
else {
if (g_pMovingClip) {
ReleaseCapture();
g_pMovingClip = NULL;
}
CleanList(&g_brFrontSplits);
CleanList(&g_brBackSplits);
g_brFrontSplits.next = &g_brFrontSplits;
g_brBackSplits.next = &g_brBackSplits;
Sys_UpdateWindows(XY | W_CAMERA_IFON);
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
bool CXYWnd::ClipMode() {
return g_bClipMode;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
bool CXYWnd::RogueClipMode() {
return g_bRogueClipMode;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
bool CXYWnd::PathMode() {
return g_bPathMode;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
bool CXYWnd::PointMode() {
return g_bPointMode;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::SetPointMode(bool b) {
g_bPointMode = b;
if (!b) {
g_nPointCount = 0;
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnPaint() {
CPaintDC dc(this); // device context for painting
bool bPaint = true;
if (!qwglMakeCurrent(dc.m_hDC, win32.hGLRC)) {
common->Printf("ERROR: wglMakeCurrent failed.. Error:%i\n", qglGetError());
common->Printf("Please restart Q3Radiant if the Map view is not working\n");
bPaint = false;
}
if (bPaint) {
QE_CheckOpenGLForErrors();
XY_Draw();
QE_CheckOpenGLForErrors();
if (m_nViewType != XY) {
qglPushMatrix();
if (m_nViewType == YZ) {
qglRotatef(-90, 0, 1, 0); // put Z going up
}
qglRotatef(-90, 1, 0, 0); // put Z going up
}
if ( g_bCrossHairs ) {
qglColor4f( 0.2f, 0.9f, 0.2f, 0.8f );
qglBegin(GL_LINES);
if (m_nViewType == XY) {
qglVertex2f(-16384, tdp[1]);
qglVertex2f(16384, tdp[1]);
qglVertex2f(tdp[0], -16384);
qglVertex2f(tdp[0], 16384);
}
else if (m_nViewType == YZ) {
qglVertex3f(tdp[0], -16384, tdp[2]);
qglVertex3f(tdp[0], 16384, tdp[2]);
qglVertex3f(tdp[0], tdp[1], -16384);
qglVertex3f(tdp[0], tdp[1], 16384);
}
else {
qglVertex3f(-16384, tdp[1], tdp[2]);
qglVertex3f(16384, tdp[1], tdp[2]);
qglVertex3f(tdp[0], tdp[1], -16384);
qglVertex3f(tdp[0], tdp[1], 16384);
}
qglEnd();
}
if (ClipMode()) {
qglPointSize(4);
qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER].ToFloatPtr());
qglBegin(GL_POINTS);
if (g_Clip1.Set()) {
qglVertex3fv(g_Clip1);
}
if (g_Clip2.Set()) {
qglVertex3fv(g_Clip2);
}
if (g_Clip3.Set()) {
qglVertex3fv(g_Clip3);
}
qglEnd();
qglPointSize(1);
CString strMsg;
if (g_Clip1.Set()) {
qglRasterPos3f(g_Clip1.m_ptClip[0] + 2, g_Clip1.m_ptClip[1] + 2, g_Clip1.m_ptClip[2] + 2);
strMsg = "1";
// strMsg.Format("1 (%f, %f, %f)", g_Clip1[0], g_Clip1[1], g_Clip1[2]);
qglCallLists(strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
}
if (g_Clip2.Set()) {
qglRasterPos3f(g_Clip2.m_ptClip[0] + 2, g_Clip2.m_ptClip[1] + 2, g_Clip2.m_ptClip[2] + 2);
strMsg = "2";
// strMsg.Format("2 (%f, %f, %f)", g_Clip2[0], g_Clip2[1], g_Clip2[2]);
qglCallLists(strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
}
if (g_Clip3.Set()) {
qglRasterPos3f(g_Clip3.m_ptClip[0] + 2, g_Clip3.m_ptClip[1] + 2, g_Clip3.m_ptClip[2] + 2);
strMsg = "3";
// strMsg.Format("3 (%f, %f, %f)", g_Clip3[0], g_Clip3[1], g_Clip3[2]);
qglCallLists(strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
}
if (g_Clip1.Set() && g_Clip2.Set() && selected_brushes.next != &selected_brushes) {
ProduceSplitLists();
brush_t *pBrush;
brush_t *pList = ((m_nViewType == XZ) ? !g_bSwitch : g_bSwitch) ? &g_brBackSplits : &g_brFrontSplits;
for (pBrush = pList->next; pBrush != NULL && pBrush != pList; pBrush = pBrush->next) {
qglColor3f(1, 1, 0);
face_t *face;
int order;
for (face = pBrush->brush_faces, order = 0; face; face = face->next, order++) {
idWinding *w = face->face_winding;
if (!w) {
continue;
}
// draw the polygon
qglBegin(GL_LINE_LOOP);
for (int i = 0; i < w->GetNumPoints(); i++) {
qglVertex3fv( (*w)[i].ToFloatPtr() );
}
qglEnd();
}
}
}
}
if (PathMode()) {
qglPointSize(4);
qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER].ToFloatPtr());
qglBegin(GL_POINTS);
int n;
for ( n = 0; n < g_nPathCount; n++) {
qglVertex3fv(g_PathPoints[n]);
}
qglEnd();
qglPointSize(1);
CString strMsg;
for (n = 0; n < g_nPathCount; n++) {
qglRasterPos3f
(
g_PathPoints[n].m_ptClip[0] + 2,
g_PathPoints[n].m_ptClip[1] + 2,
g_PathPoints[n].m_ptClip[2] + 2
);
strMsg.Format("%i", n + 1);
qglCallLists(strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
}
}
if (m_nViewType != XY) {
qglPopMatrix();
}
qwglSwapBuffers(dc.m_hDC);
TRACE("XY Paint\n");
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
g_pParentWnd->HandleKey(nChar, nRepCnt, nFlags);
}
//
// =======================================================================================================================
// FIXME: the brush_t *pBrush is never used. ( Entity_Create uses selected_brushes )
// =======================================================================================================================
//
void CreateEntityFromName(char *pName, brush_t *pBrush, bool forceFixed, idVec3 min, idVec3 max, idVec3 org) {
eclass_t *pecNew;
entity_t *petNew;
if (stricmp(pName, "worldspawn") == 0) {
g_pParentWnd->MessageBox("Can't create an entity with worldspawn.", "info", 0);
return;
}
pecNew = Eclass_ForName(pName, false);
if ((GetAsyncKeyState(VK_SHIFT) & 0x8000)) {
Select_Ungroup();
}
// create it
petNew = Entity_Create(pecNew, forceFixed);
if (petNew && idStr::Icmp(pName, "light") == 0 ) {
idVec3 rad = max - min;
rad *= 0.5;
if (rad.x != 0 && rad.y != 0 && rad.z != 0) {
SetKeyValue(petNew, "light_radius", va("%g %g %g", idMath::Fabs(rad.x), idMath::Fabs(rad.y), idMath::Fabs(rad.z)));
DeleteKey(petNew, "light");
}
}
if (petNew == NULL) {
if (!((selected_brushes.next == &selected_brushes) || (selected_brushes.next->next != &selected_brushes))) {
brush_t *b = selected_brushes.next;
if (b->owner != world_entity && ((b->owner->eclass->fixedsize && pecNew->fixedsize) || forceFixed)) {
idVec3 mins, maxs;
idVec3 origin;
for (int i = 0; i < 3; i++) {
origin[i] = b->mins[i] - pecNew->mins[i];
}
VectorAdd(pecNew->mins, origin, mins);
VectorAdd(pecNew->maxs, origin, maxs);
brush_t *nb = Brush_Create(mins, maxs, &pecNew->texdef);
Entity_LinkBrush(b->owner, nb);
nb->owner->eclass = pecNew;
SetKeyValue(nb->owner, "classname", pName);
Brush_Free(b);
Brush_Build(nb);
Brush_AddToList(nb, &active_brushes);
Select_Brush(nb);
return;
}
}
g_pParentWnd->MessageBox("Failed to create entity.", "info", 0);
return;
}
Select_Deselect();
//
// entity_t* pEntity = world_entity; if (selected_brushes.next !=
// &selected_brushes) pEntity = selected_brushes.next->owner;
//
Select_Brush(petNew->brushes.onext);
Brush_Build(petNew->brushes.onext);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
brush_t *CreateEntityBrush(int x, int y, CXYWnd *pWnd) {
idVec3 mins, maxs;
int i;
float temp;
brush_t *n;
pWnd->SnapToPoint(x, y, mins);
x += 32;
y += 32;
pWnd->SnapToPoint(x, y, maxs);
int nDim = (pWnd->GetViewType() == XY) ? 2 : (pWnd->GetViewType() == YZ) ? 0 : 1;
mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom[nDim] / g_qeglobals.d_gridsize));
maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top[nDim] / g_qeglobals.d_gridsize));
if (maxs[nDim] <= mins[nDim]) {
maxs[nDim] = mins[nDim] + g_qeglobals.d_gridsize;
}
for (i = 0; i < 3; i++) {
if (mins[i] == maxs[i]) {
maxs[i] += 16; // don't create a degenerate brush
}
if (mins[i] > maxs[i]) {
temp = mins[i];
mins[i] = maxs[i];
maxs[i] = temp;
}
}
n = Brush_Create(mins, maxs, &g_qeglobals.d_texturewin.texdef);
if (!n) {
return NULL;
}
Brush_AddToList(n, &selected_brushes);
Entity_LinkBrush(world_entity, n);
Brush_Build(n);
return n;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CreateRightClickEntity(CXYWnd *pWnd, int x, int y, char *pName) {
idVec3 min, max, org;
Select_GetBounds(min, max);
Select_GetMid(org);
CRect rctZ;
pWnd->GetClientRect(rctZ);
brush_t *pBrush;
if (selected_brushes.next == &selected_brushes) {
pBrush = CreateEntityBrush(x, rctZ.Height() - 1 - y, pWnd);
min.Zero();
max.Zero();
CreateEntityFromName(pName, pBrush, true, min, max, org);
}
else {
pBrush = selected_brushes.next;
CreateEntityFromName(pName, pBrush, false, min, max, org);
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
brush_t *CreateSmartBrush(idVec3 v) {
idVec3 mins, maxs;
int i;
brush_t *n;
for (i = 0; i < 3; i++) {
mins[i] = v[i] - 16;
maxs[i] = v[i] + 16;
}
n = Brush_Create(mins, maxs, &g_qeglobals.d_texturewin.texdef);
if (!n) {
return NULL;
}
Brush_AddToList(n, &selected_brushes);
// Entity_LinkBrush(world_entity, n);
Brush_Build(n);
return n;
}
CString g_strSmartEntity;
int g_nSmartX;
int g_nSmartY;
bool g_bSmartWaiting;
/*
=======================================================================================================================
=======================================================================================================================
*/
void _SmartPointDone(bool b, int n) {
g_bSmartWaiting = false;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CreateSmartEntity(CXYWnd *pWnd, int x, int y, const char *pName) {
g_nSmartX = x;
g_nSmartY = y;
g_strSmartEntity = pName;
if (g_strSmartEntity.Find("Smart_Train") >= 0) {
ShowInfoDialog("Select the path of the train by left clicking in XY, YZ and/or XZ views. You can move an already dropped point by grabbing and moving it. When you are finished, press ENTER to accept and create the entity and path(s), press ESC to abandon the creation");
g_bPathMode = true;
g_nPathLimit = 0;
g_nPathCount = 0;
g_bSmartGo = true;
}
else if (g_strSmartEntity.Find("Smart_Monster...") >= 0) {
g_bPathMode = true;
g_nPathLimit = 0;
g_nPathCount = 0;
}
else if (g_strSmartEntity.Find("Smart_Rotating") >= 0) {
g_bSmartWaiting = true;
ShowInfoDialog("Left click to specify the rotation origin");
AcquirePath(1, &_SmartPointDone);
while (g_bSmartWaiting) {
MSG msg;
if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
HideInfoDialog();
CPtrArray array;
g_bScreenUpdates = false;
CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_rotating");
array.Add(reinterpret_cast < void * > (selected_brushes.next));
Select_Deselect();
brush_t *pBrush = CreateSmartBrush(g_PathPoints[0]);
array.Add(pBrush);
Select_Deselect();
Select_Brush(reinterpret_cast < brush_t * > (array.GetAt(0)));
Select_Brush(reinterpret_cast < brush_t * > (array.GetAt(1)));
ConnectEntities();
g_bScreenUpdates = true;
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void FinishSmartCreation() {
CPtrArray array;
HideInfoDialog();
if (g_strSmartEntity.Find("Smart_Train") >= 0) {
g_bScreenUpdates = false;
CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_train");
array.Add(reinterpret_cast < void * > (selected_brushes.next));
int n;
for (n = 0; n < g_nPathCount; n++) {
Select_Deselect();
CreateRightClickEntity
(
g_pParentWnd->ActiveXY(),
g_PathPoints[n].m_ptScreen.x,
g_PathPoints[n].m_ptScreen.y,
"path_corner"
);
array.Add(reinterpret_cast < void * > (selected_brushes.next));
}
for (n = 0; n < g_nPathCount; n++) {
Select_Deselect();
Select_Brush(reinterpret_cast < brush_t * > (array.GetAt(n)));
Select_Brush(reinterpret_cast < brush_t * > (array.GetAt(n + 1)));
ConnectEntities();
}
g_bScreenUpdates = true;
}
g_nPathCount = 0;
g_bPathMode = false;
Sys_UpdateWindows(W_ALL);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::KillPathMode() {
g_bSmartGo = false;
g_bPathMode = false;
if (g_pPathFunc) {
g_pPathFunc(false, g_nPathCount);
}
g_nPathCount = 0;
g_pPathFunc = NULL;
Sys_UpdateWindows(W_ALL);
}
//
// =======================================================================================================================
// gets called for drop down menu messages TIP: it's not always about EntityCreate
// =======================================================================================================================
//
void CXYWnd::OnEntityCreate(unsigned int nID) {
if (m_mnuDrop.GetSafeHmenu()) {
CString strItem;
m_mnuDrop.GetMenuString(nID, strItem, MF_BYCOMMAND);
if (strItem.CompareNoCase("Add to...") == 0) {
//
// ++timo TODO: fill the menu with current groups? this one is for adding to
// existing groups only
//
common->Printf("TODO: Add to... in CXYWnd::OnEntityCreate\n");
}
else if (strItem.CompareNoCase("Remove") == 0) {
// remove selected brushes from their current group
brush_t *b;
for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
}
}
// ++timo FIXME: remove when all hooks are in
if
(
strItem.CompareNoCase("Add to...") == 0 ||
strItem.CompareNoCase("Remove") == 0 ||
strItem.CompareNoCase("Name...") == 0 ||
strItem.CompareNoCase("New group...") == 0
) {
common->Printf("TODO: hook drop down group menu\n");
return;
}
if (strItem.Find("Smart_") >= 0) {
CreateSmartEntity(this, m_ptDown.x, m_ptDown.y, strItem);
}
else {
CreateRightClickEntity(this, m_ptDown.x, m_ptDown.y, strItem.GetBuffer(0));
}
Sys_UpdateWindows(W_ALL);
// OnLButtonDown((MK_LBUTTON | MK_SHIFT), CPoint(m_ptDown.x+2, m_ptDown.y+2));
}
}
BOOL CXYWnd::OnCmdMsg( UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO *pHandlerInfo )
{
if ( CWnd::OnCmdMsg( nID, nCode, pExtra, pHandlerInfo ) ) {
return TRUE;
}
return AfxGetMainWnd()->OnCmdMsg( nID, nCode, pExtra, pHandlerInfo );
}
bool MergeMenu(CMenu * pMenuDestination, const CMenu * pMenuAdd, bool bTopLevel /*=false*/)
{
// get the number menu items in the menus
int iMenuAddItemCount = pMenuAdd->GetMenuItemCount();
int iMenuDestItemCount = pMenuDestination->GetMenuItemCount();
// if there are no items return
if (iMenuAddItemCount == 0)
return true;
// if we are not at top level and the destination menu is not empty
// -> we append a seperator
if (!bTopLevel && iMenuDestItemCount > 0)
pMenuDestination->AppendMenu(MF_SEPARATOR);
// iterate through the top level of
for(int iLoop = 0; iLoop < iMenuAddItemCount; iLoop++)
{
// get the menu string from the add menu
CString sMenuAddString;
pMenuAdd->GetMenuString(iLoop, sMenuAddString, MF_BYPOSITION);
// try to get the submenu of the current menu item
CMenu* pSubMenu = pMenuAdd->GetSubMenu(iLoop);
// check if we have a sub menu
if (!pSubMenu)
{
// normal menu item
// read the source and append at the destination
UINT nState = pMenuAdd->GetMenuState(iLoop, MF_BYPOSITION);
UINT nItemID = pMenuAdd->GetMenuItemID(iLoop);
if (pMenuDestination->AppendMenu(nState, nItemID, sMenuAddString))
{
// menu item added, don't forget to correct the item count
iMenuDestItemCount++;
}
else
{
TRACE("MergeMenu: AppendMenu failed!\n");
return false;
}
}
else
{
// create or insert a new popup menu item
// default insert pos is like ap
int iInsertPosDefault = -1;
// if we are at top level merge into existing popups rather than
// creating new ones
if(bTopLevel)
{
ASSERT(sMenuAddString != "&?" && sMenuAddString !=
"?");
CString csAdd(sMenuAddString);
csAdd.Remove('&'); // for comparison of menu items supress '&'
bool bAdded = false;
// try to find existing popup
for( int iLoop1 = 0; iLoop1 < iMenuDestItemCount; iLoop1++ )
{
// get the menu string from the destination menu
CString sDest;
pMenuDestination->GetMenuString(iLoop1, sDest, MF_BYPOSITION);
sDest.Remove('&'); // for a better compare (s.a.)
if (csAdd == sDest)
{
// we got a hit -> merge the two popups
// try to get the submenu of the desired destination menu item
CMenu* pSubMenuDest =
pMenuDestination->GetSubMenu(iLoop1);
if (pSubMenuDest)
{
// merge the popup recursivly and continue with outer for loop
if (!MergeMenu(pSubMenuDest, pSubMenu, false))
return false;
bAdded = true;
break;
}
}
// alternativ insert before or
if (iInsertPosDefault == -1 && (sDest == "Window"
|| sDest == "?" || sDest == "Help"))
{
iInsertPosDefault = iLoop1;
}
} // for (iLoop1)
if (bAdded)
{
// menu added, so go on with loop over pMenuAdd's top level
continue;
}
} // if (bTopLevel)
// if the top level search did not find a position append the menu
if( iInsertPosDefault == -1 )
{
iInsertPosDefault = pMenuDestination->GetMenuItemCount();
}
// create a new popup and insert before or
CMenu NewPopupMenu;
if (!NewPopupMenu.CreatePopupMenu())
{
TRACE("MergeMenu: CreatePopupMenu failed!\n");
return false;
}
// merge the new popup recursivly
if (!MergeMenu(&NewPopupMenu, pSubMenu, false))
return false;
// insert the new popup menu into the destination menu
HMENU hNewMenu = NewPopupMenu.GetSafeHmenu();
if (pMenuDestination->InsertMenu(iInsertPosDefault,
MF_BYPOSITION | MF_POPUP | MF_ENABLED,
(UINT_PTR)hNewMenu, sMenuAddString ))
{
// don't forget to correct the item count
iMenuDestItemCount++;
}
else
{
TRACE("MergeMenu: InsertMenu failed!\n");
return false;
}
// don't destroy the new menu
NewPopupMenu.Detach();
} // if (pSubMenu)
} // for (iLoop)
return true;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::HandleDrop() {
if (g_PrefsDlg.m_bRightClick == false) {
return;
}
if (!m_mnuDrop.GetSafeHmenu()) { // first time, load it up
m_mnuDrop.CreatePopupMenu();
CMenu *drop = new CMenu;
drop->LoadMenu( IDR_MENU_DROP );
MergeMenu( &m_mnuDrop, drop, false );
int nID = ID_ENTITY_START;
CMenu *pMakeEntityPop = &m_mnuDrop;
// Todo: Make this a config option maybe?
const int entitiesOnSubMenu = false;
if ( entitiesOnSubMenu ) {
pMakeEntityPop = new CMenu;
pMakeEntityPop->CreateMenu();
}
CMenu *pChild = NULL;
eclass_t *e;
CString strActive;
CString strLast;
CString strName;
for (e = eclass; e; e = e->next) {
strLast = strName;
strName = e->name;
int n_ = strName.Find("_");
if (n_ > 0) {
CString strLeft = strName.Left(n_);
CString strRight = strName.Right(strName.GetLength() - n_ - 1);
if (strLeft == strActive) { // this is a child
ASSERT(pChild);
pChild->AppendMenu(MF_STRING, nID++, strName);
}
else {
if (pChild) {
pMakeEntityPop->AppendMenu (
MF_POPUP,
reinterpret_cast (pChild->GetSafeHmenu()),
strActive
);
g_ptrMenus.Add(pChild);
// pChild->DestroyMenu(); delete pChild;
pChild = NULL;
}
strActive = strLeft;
pChild = new CMenu;
pChild->CreateMenu();
pChild->AppendMenu(MF_STRING, nID++, strName);
}
}
else {
if (pChild) {
pMakeEntityPop->AppendMenu (
MF_POPUP,
reinterpret_cast (pChild->GetSafeHmenu()),
strActive
);
g_ptrMenus.Add(pChild);
// pChild->DestroyMenu(); delete pChild;
pChild = NULL;
}
strActive = "";
pMakeEntityPop->AppendMenu(MF_STRING, nID++, strName);
}
}
if ( pMakeEntityPop != &m_mnuDrop ) {
m_mnuDrop.AppendMenu (
MF_POPUP,
reinterpret_cast (pMakeEntityPop->GetSafeHmenu()),
"Make Entity"
);
}
}
CPoint ptMouse;
GetCursorPos(&ptMouse);
m_mnuDrop.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, ptMouse.x, ptMouse.y, this);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::XY_Init() {
m_vOrigin[0] = 0;
m_vOrigin[1] = 20;
m_vOrigin[2] = 46;
m_fScale = 1;
m_precisionCrosshairMode = PRECISION_CROSSHAIR_NONE;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::SnapToPoint(int x, int y, idVec3 &point) {
if (g_PrefsDlg.m_bNoClamp) {
XY_ToPoint(x, y, point);
}
else {
XY_ToGridPoint(x, y, point);
}
// -- else -- XY_ToPoint(x, y, point); -- //XY_ToPoint(x, y, point);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::XY_ToPoint(int x, int y, idVec3 &point) {
float fx = x;
float fy = y;
float fw = m_nWidth;
float fh = m_nHeight;
if (m_nViewType == XY) {
point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale;
point[1] = m_vOrigin[1] + (fy - fh / 2) / m_fScale;
// point[2] = 0;
}
else if (m_nViewType == YZ) {
//
// //point[0] = 0; point[1] = m_vOrigin[0] + (fx - fw / 2) / m_fScale; point[2] =
// m_vOrigin[1] + (fy - fh / 2 ) / m_fScale;
//
point[1] = m_vOrigin[1] + (fx - fw / 2) / m_fScale;
point[2] = m_vOrigin[2] + (fy - fh / 2) / m_fScale;
}
else {
//
// point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale; /point[1] = 0; point[2] =
// m_vOrigin[1] + (fy - fh / 2) / m_fScale;
//
point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale;
// point[1] = 0;
point[2] = m_vOrigin[2] + (fy - fh / 2) / m_fScale;
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::XY_ToGridPoint(int x, int y, idVec3 &point) {
if (m_nViewType == XY) {
point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale;
point[1] = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale;
// point[2] = 0;
point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
}
else if (m_nViewType == YZ) {
//
// point[0] = 0; point[1] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale; point[2]
// = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale;
//
point[1] = m_vOrigin[1] + (x - m_nWidth / 2) / m_fScale;
point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale;
point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
}
else {
//
// point[1] = 0; point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale; point[2]
// = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale;
//
point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale;
point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale;
point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
idVec3 dragOrigin;
idVec3 dragDir;
idVec3 dragX;
idVec3 dragY;
void CXYWnd::XY_MouseDown(int x, int y, int buttons) {
idVec3 point,center;
idVec3 origin, dir, right, up;
m_nButtonstate = buttons;
m_nPressx = x;
m_nPressy = y;
VectorCopy(vec3_origin, m_vPressdelta);
point.Zero();
XY_ToPoint(x, y, point);
VectorCopy(point, origin);
dir.Zero();
if (m_nViewType == XY) {
origin[2] = HUGE_DISTANCE;
dir[2] = -1;
right[0] = 1 / m_fScale;
right[1] = 0;
right[2] = 0;
up[0] = 0;
up[1] = 1 / m_fScale;
up[2] = 0;
point[2] = g_pParentWnd->GetCamera()->Camera().origin[2];
}
else if (m_nViewType == YZ) {
origin[0] = HUGE_DISTANCE;
dir[0] = -1;
right[1] = 1 / m_fScale;
right[2] = 0;
right[0] = 0;
up[0] = 0;
up[2] = 1 / m_fScale;
up[1] = 0;
point[0] = g_pParentWnd->GetCamera()->Camera().origin[0];
}
else {
origin[1] = HUGE_DISTANCE;
dir[1] = -1;
right[0] = 1 / m_fScale;
right[2] = 0;
right[1] = 0;
up[0] = 0;
up[2] = 1 / m_fScale;
up[1] = 0;
point[1] = g_pParentWnd->GetCamera()->Camera().origin[1];
}
dragOrigin = m_vOrigin;
dragDir = dir;
dragX = right;
dragY = up;
m_bPress_selection = (selected_brushes.next != &selected_brushes);
GetCursorPos(&m_ptCursor);
// Sys_GetCursorPos (&m_ptCursor.x, &m_ptCursor.y);
if (buttons == MK_LBUTTON && activeDrag) {
activeDragging = true;
}
else {
activeDragging = false;
}
// lbutton = manipulate selection shift-LBUTTON = select
if
(
(buttons == MK_LBUTTON) ||
(buttons == (MK_LBUTTON | MK_SHIFT)) ||
(buttons == (MK_LBUTTON | MK_CONTROL)) ||
(buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT))
) {
if (g_qeglobals.d_select_mode == sel_addpoint) {
XY_ToGridPoint(x, y, point);
if (g_qeglobals.selectObject) {
g_qeglobals.selectObject->addPoint(point);
}
return;
}
Patch_SetView((m_nViewType == XY) ? W_XY : (m_nViewType == YZ) ? W_YZ : W_XZ);
Drag_Begin(x, y, buttons, right, up, origin, dir);
return;
}
int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
// control mbutton = move camera
if (m_nButtonstate == (MK_CONTROL | nMouseButton)) {
VectorCopyXY(point, g_pParentWnd->GetCamera()->Camera().origin);
Sys_UpdateWindows(W_CAMERA | W_XY_OVERLAY);
}
// mbutton = angle camera
if
(
(g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) ||
(g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT | MK_CONTROL | MK_RBUTTON))
) {
VectorSubtract(point, g_pParentWnd->GetCamera()->Camera().origin, point);
int n1 = (m_nViewType == XY) ? 1 : 2;
int n2 = (m_nViewType == YZ) ? 1 : 0;
int nAngle = (m_nViewType == XY) ? YAW : PITCH;
if (point[n1] || point[n2]) {
g_pParentWnd->GetCamera()->Camera().angles[nAngle] = RAD2DEG( atan2(point[n1], point[n2]) );
Sys_UpdateWindows(W_CAMERA_IFON | W_XY_OVERLAY);
}
}
// shift mbutton = move z checker
if (m_nButtonstate == (MK_SHIFT | nMouseButton)) {
if (RotateMode() || g_bPatchBendMode) {
SnapToPoint(x, y, point);
VectorCopyXY(point, g_vRotateOrigin);
if (g_bPatchBendMode) {
VectorCopy(point, g_vBendOrigin);
}
Sys_UpdateWindows(W_XY);
return;
}
else {
SnapToPoint(x, y, point);
if (m_nViewType == XY) {
z.origin[0] = point[0];
z.origin[1] = point[1];
}
else if (m_nViewType == YZ) {
z.origin[0] = point[1];
z.origin[1] = point[2];
}
else {
z.origin[0] = point[0];
z.origin[1] = point[2];
}
Sys_UpdateWindows(W_XY_OVERLAY | W_Z);
return;
}
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::XY_MouseUp(int x, int y, int buttons) {
activeDragging = false;
Drag_MouseUp(buttons);
if (!m_bPress_selection) {
Sys_UpdateWindows(W_ALL);
}
m_nButtonstate = 0;
while (::ShowCursor(TRUE) < 0)
;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
bool CXYWnd::DragDelta(int x, int y, idVec3 &move) {
idVec3 xvec, yvec, delta;
int i;
xvec[0] = 1 / m_fScale;
xvec[1] = xvec[2] = 0;
yvec[1] = 1 / m_fScale;
yvec[0] = yvec[2] = 0;
for (i = 0; i < 3; i++) {
delta[i] = xvec[i] * (x - m_nPressx) + yvec[i] * (y - m_nPressy);
if (!g_PrefsDlg.m_bNoClamp) {
delta[i] = floor(delta[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
}
}
VectorSubtract(delta, m_vPressdelta, move);
VectorCopy(delta, m_vPressdelta);
if (move[0] || move[1] || move[2]) {
return true;
}
return false;
}
/*
=======================================================================================================================
NewBrushDrag
=======================================================================================================================
*/
void CXYWnd::NewBrushDrag(int x, int y) {
idVec3 mins, maxs, junk;
int i;
float temp;
brush_t *n;
if ( radiant_entityMode.GetBool() ) {
return;
}
if (!DragDelta(x, y, junk)) {
return;
}
// delete the current selection
if (selected_brushes.next != &selected_brushes) {
Brush_Free(selected_brushes.next);
}
SnapToPoint(m_nPressx, m_nPressy, mins);
int nDim = (m_nViewType == XY) ? 2 : (m_nViewType == YZ) ? 0 : 1;
mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom[nDim] / g_qeglobals.d_gridsize));
SnapToPoint(x, y, maxs);
maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top[nDim] / g_qeglobals.d_gridsize));
if (maxs[nDim] <= mins[nDim]) {
maxs[nDim] = mins[nDim] + g_qeglobals.d_gridsize;
}
for (i = 0; i < 3; i++) {
if (mins[i] == maxs[i]) {
return; // don't create a degenerate brush
}
if (mins[i] > maxs[i]) {
temp = mins[i];
mins[i] = maxs[i];
maxs[i] = temp;
}
}
n = Brush_Create(mins, maxs, &g_qeglobals.d_texturewin.texdef);
if (!n) {
return;
}
idVec3 vSize;
VectorSubtract(maxs, mins, vSize);
g_strStatus.Format("Size X:: %.1f Y:: %.1f Z:: %.1f", vSize[0], vSize[1], vSize[2]);
g_pParentWnd->SetStatusText(2, g_strStatus);
Brush_AddToList(n, &selected_brushes);
Entity_LinkBrush(world_entity, n);
Brush_Build(n);
// Sys_UpdateWindows (W_ALL);
Sys_UpdateWindows(W_XY | W_CAMERA);
}
/*
=======================================================================================================================
XY_MouseMoved
=======================================================================================================================
*/
bool CXYWnd::XY_MouseMoved(int x, int y, int buttons) {
idVec3 point;
if (!m_nButtonstate) {
if (g_bCrossHairs) {
::ShowCursor(FALSE);
Sys_UpdateWindows(W_XY | W_XY_OVERLAY);
::ShowCursor(TRUE);
}
return false;
}
//
// lbutton without selection = drag new brush if (m_nButtonstate == MK_LBUTTON &&
// !m_bPress_selection && g_qeglobals.d_select_mode != sel_curvepoint &&
// g_qeglobals.d_select_mode != sel_splineedit)
//
if (m_nButtonstate == MK_LBUTTON && !m_bPress_selection && g_qeglobals.d_select_mode == sel_brush) {
NewBrushDrag(x, y);
return false;
}
// lbutton (possibly with control and or shift) with selection = drag selection
if (m_nButtonstate & MK_LBUTTON) {
Drag_MouseMoved(x, y, buttons);
Sys_UpdateWindows(W_XY_OVERLAY | W_CAMERA_IFON | W_Z);
return false;
}
int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
// control mbutton = move camera
if (m_nButtonstate == (MK_CONTROL | nMouseButton)) {
SnapToPoint(x, y, point);
VectorCopyXY(point, g_pParentWnd->GetCamera()->Camera().origin);
Sys_UpdateWindows(W_XY_OVERLAY | W_CAMERA);
return false;
}
// shift mbutton = move z checker
if (m_nButtonstate == (MK_SHIFT | nMouseButton)) {
if (RotateMode() || g_bPatchBendMode) {
SnapToPoint(x, y, point);
VectorCopyXY(point, g_vRotateOrigin);
if (g_bPatchBendMode) {
VectorCopy(point, g_vBendOrigin);
}
Sys_UpdateWindows(W_XY);
return false;
}
else {
SnapToPoint(x, y, point);
if (m_nViewType == XY) {
z.origin[0] = point[0];
z.origin[1] = point[1];
}
else if (m_nViewType == YZ) {
z.origin[0] = point[1];
z.origin[1] = point[2];
}
else {
z.origin[0] = point[0];
z.origin[1] = point[2];
}
}
Sys_UpdateWindows(W_XY_OVERLAY | W_Z);
return false;
}
// mbutton = angle camera
if
(
(g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) ||
(g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT | MK_CONTROL | MK_RBUTTON))
) {
SnapToPoint(x, y, point);
VectorSubtract(point, g_pParentWnd->GetCamera()->Camera().origin, point);
int n1 = (m_nViewType == XY) ? 1 : 2;
int n2 = (m_nViewType == YZ) ? 1 : 0;
int nAngle = (m_nViewType == XY) ? YAW : PITCH;
if (point[n1] || point[n2]) {
g_pParentWnd->GetCamera()->Camera().angles[nAngle] = RAD2DEG( atan2(point[n1], point[n2]) );
Sys_UpdateWindows(W_CAMERA_IFON | W_XY_OVERLAY);
}
return false;
}
// rbutton = drag xy origin
if (m_nButtonstate == MK_RBUTTON) {
Sys_GetCursorPos(&x, &y);
if (x != m_ptCursor.x || y != m_ptCursor.y) {
if ((GetAsyncKeyState(VK_MENU) & 0x8000)) {
int *px = &x;
long *px2 = &m_ptCursor.x;
if (fDiff(y, m_ptCursor.y) > fDiff(x, m_ptCursor.x)) {
px = &y;
px2 = &m_ptCursor.y;
}
if (*px > *px2) {
// zoom in
SetScale( Scale() * 1.1f );
if ( Scale() < 0.1f ) {
SetScale( 0.1f );
}
}
else if (*px < *px2) {
// zoom out
SetScale( Scale() * 0.9f );
if ( Scale() > 16.0f ) {
SetScale( 16.0f );
}
}
*px2 = *px;
Sys_UpdateWindows(W_XY | W_XY_OVERLAY);
}
else {
int nDim1 = (m_nViewType == YZ) ? 1 : 0;
int nDim2 = (m_nViewType == XY) ? 1 : 2;
m_vOrigin[nDim1] -= (x - m_ptCursor.x) / m_fScale;
m_vOrigin[nDim2] += (y - m_ptCursor.y) / m_fScale;
SetCursorPos(m_ptCursor.x, m_ptCursor.y);
::ShowCursor(FALSE);
// XY_Draw(); RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
Sys_UpdateWindows(W_XY | W_XY_OVERLAY);
// ::ShowCursor(TRUE);
}
}
return false;
}
return false;
}
/*
=======================================================================================================================
DRAWING £
XY_DrawGrid
=======================================================================================================================
*/
void CXYWnd::XY_DrawGrid() {
float x, y, xb, xe, yb, ye;
int w, h;
char text[32];
int startPos = max ( 64 , g_qeglobals.d_gridsize );
w = m_nWidth / 2 / m_fScale;
h = m_nHeight / 2 / m_fScale;
int nDim1 = (m_nViewType == YZ) ? 1 : 0;
int nDim2 = (m_nViewType == XY) ? 1 : 2;
// int nDim1 = 0; int nDim2 = 1;
xb = m_vOrigin[nDim1] - w;
if (xb < region_mins[nDim1]) {
xb = region_mins[nDim1];
}
xb = startPos * floor(xb / startPos);
xe = m_vOrigin[nDim1] + w;
if (xe > region_maxs[nDim1]) {
xe = region_maxs[nDim1];
}
xe = startPos * ceil(xe / startPos);
yb = m_vOrigin[nDim2] - h;
if (yb < region_mins[nDim2]) {
yb = region_mins[nDim2];
}
yb = startPos * floor(yb / startPos);
ye = m_vOrigin[nDim2] + h;
if (ye > region_maxs[nDim2]) {
ye = region_maxs[nDim2];
}
ye = startPos * ceil(ye / startPos);
// draw major blocks
qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR].ToFloatPtr());
int stepSize = 64 * 0.1 / m_fScale;
if (stepSize < 64) {
stepSize = max ( 64 , g_qeglobals.d_gridsize );
}
else {
int i;
for (i = 1; i < stepSize; i <<= 1) {
}
stepSize = i;
}
if (g_qeglobals.d_showgrid) {
qglBegin(GL_LINES);
for (x = xb; x <= xe; x += stepSize) {
qglVertex2f(x, yb);
qglVertex2f(x, ye);
}
for (y = yb; y <= ye; y += stepSize) {
qglVertex2f(xb, y);
qglVertex2f(xe, y);
}
qglEnd();
}
// draw minor blocks
if ( m_fScale > .1 &&
g_qeglobals.d_showgrid &&
g_qeglobals.d_gridsize * m_fScale >= 4 &&
!g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR].Compare( g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK] ) ) {
qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR].ToFloatPtr());
qglBegin(GL_LINES);
for (x = xb; x < xe; x += g_qeglobals.d_gridsize) {
if (!((int)x & (startPos - 1))) {
continue;
}
qglVertex2f(x, yb);
qglVertex2f(x, ye);
}
for (y = yb; y < ye; y += g_qeglobals.d_gridsize) {
if (!((int)y & (startPos - 1))) {
continue;
}
qglVertex2f(xb, y);
qglVertex2f(xe, y);
}
qglEnd();
}
// draw ZClip boundaries (if applicable)...
//
if (m_nViewType == XZ || m_nViewType == YZ)
{
if (g_pParentWnd->GetZWnd()->m_pZClip) // should always be the case at this point I think, but this is safer
{
if (g_pParentWnd->GetZWnd()->m_pZClip->IsEnabled())
{
qglColor3f(ZCLIP_COLOUR);
qglLineWidth(2);
qglBegin (GL_LINES);
qglVertex2f (xb, g_pParentWnd->GetZWnd()->m_pZClip->GetTop());
qglVertex2f (xe, g_pParentWnd->GetZWnd()->m_pZClip->GetTop());
qglVertex2f (xb, g_pParentWnd->GetZWnd()->m_pZClip->GetBottom());
qglVertex2f (xe, g_pParentWnd->GetZWnd()->m_pZClip->GetBottom());
qglEnd ();
qglLineWidth(1);
}
}
}
// draw coordinate text if needed
if (g_qeglobals.d_savedinfo.show_coordinates) {
// glColor4f(0, 0, 0, 0);
qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT].ToFloatPtr());
for (x = xb; x < xe; x += stepSize) {
qglRasterPos2f(x, m_vOrigin[nDim2] + h - 10 / m_fScale);
sprintf(text, "%i", (int)x);
qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
}
for (y = yb; y < ye; y += stepSize) {
qglRasterPos2f(m_vOrigin[nDim1] - w + 1, y);
sprintf(text, "%i", (int)y);
qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
}
if (Active()) {
qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME].ToFloatPtr());
}
qglRasterPos2f(m_vOrigin[nDim1] - w + 35 / m_fScale, m_vOrigin[nDim2] + h - 20 / m_fScale);
char cView[20];
if (m_nViewType == XY) {
strcpy(cView, "XY Top");
}
else if (m_nViewType == XZ) {
strcpy(cView, "XZ Front");
}
else {
strcpy(cView, "YZ Side");
}
qglCallLists(strlen(cView), GL_UNSIGNED_BYTE, cView);
}
/*
* if (true) { qglColor3f(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]);
* qglBegin (GL_LINES); qglVertex2f (x, yb); qglVertex2f (x, ye); qglEnd(); }
*/
}
/*
=======================================================================================================================
XY_DrawBlockGrid
=======================================================================================================================
*/
void CXYWnd::XY_DrawBlockGrid() {
float x, y, xb, xe, yb, ye;
int w, h;
char text[32];
w = m_nWidth / 2 / m_fScale;
h = m_nHeight / 2 / m_fScale;
int nDim1 = (m_nViewType == YZ) ? 1 : 0;
int nDim2 = (m_nViewType == XY) ? 1 : 2;
xb = m_vOrigin[nDim1] - w;
if (xb < region_mins[nDim1]) {
xb = region_mins[nDim1];
}
xb = 1024 * floor(xb / 1024);
xe = m_vOrigin[nDim1] + w;
if (xe > region_maxs[nDim1]) {
xe = region_maxs[nDim1];
}
xe = 1024 * ceil(xe / 1024);
yb = m_vOrigin[nDim2] - h;
if (yb < region_mins[nDim2]) {
yb = region_mins[nDim2];
}
yb = 1024 * floor(yb / 1024);
ye = m_vOrigin[nDim2] + h;
if (ye > region_maxs[nDim2]) {
ye = region_maxs[nDim2];
}
ye = 1024 * ceil(ye / 1024);
// draw major blocks
qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK].ToFloatPtr());
qglLineWidth(0.5);
qglBegin(GL_LINES);
for (x = xb; x <= xe; x += 1024) {
qglVertex2f(x, yb);
qglVertex2f(x, ye);
}
for (y = yb; y <= ye; y += 1024) {
qglVertex2f(xb, y);
qglVertex2f(xe, y);
}
qglEnd();
qglLineWidth(0.25);
// draw coordinate text if needed
for (x = xb; x < xe; x += 1024) {
for (y = yb; y < ye; y += 1024) {
qglRasterPos2f(x + 512, y + 512);
sprintf(text, "%i,%i", (int)floor(x / 1024), (int)floor(y / 1024));
qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
}
}
qglColor4f(0, 0, 0, 0);
}
void GLColoredBoxWithLabel(float x, float y, float size, idVec4 color, const char *text, idVec4 textColor, float xofs, float yofs, float lineSize) {
globalImages->BindNull();
qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
qglDisable(GL_CULL_FACE);
qglDisable(GL_BLEND);
qglColor4f(color[0], color[1], color[2], color[3]);
qglBegin(GL_QUADS);
qglVertex3f(x - size, y - size, 0);
qglVertex3f(x + size, y - size, 0);
qglVertex3f(x + size, y + size, 0);
qglVertex3f(x - size, y + size, 0);
qglEnd();
qglColor4f(textColor[0], textColor[1], textColor[2], textColor[3]);
qglLineWidth(lineSize);
qglRasterPos2f(x + xofs, y + yofs);
qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::DrawRotateIcon() {
float x, y;
if (m_nViewType == XY) {
x = g_vRotateOrigin[0];
y = g_vRotateOrigin[1];
}
else if (m_nViewType == YZ) {
x = g_vRotateOrigin[1];
y = g_vRotateOrigin[2];
}
else {
x = g_vRotateOrigin[0];
y = g_vRotateOrigin[2];
}
qglEnable(GL_BLEND);
globalImages->BindNull();
qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
qglDisable(GL_CULL_FACE);
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
qglColor4f( 0.8f, 0.1f, 0.9f, 0.25f );
qglBegin(GL_QUADS);
qglVertex3f(x - 4, y - 4, 0);
qglVertex3f(x + 4, y - 4, 0);
qglVertex3f(x + 4, y + 4, 0);
qglVertex3f(x - 4, y + 4, 0);
qglEnd();
qglDisable(GL_BLEND);
qglColor4f( 1.0f, 0.2f, 1.0f, 1.0f );
qglBegin(GL_POINTS);
qglVertex3f(x, y, 0);
qglEnd();
int w = m_nWidth / 2 / m_fScale;
int h = m_nHeight / 2 / m_fScale;
int nDim1 = (m_nViewType == YZ) ? 1 : 0;
int nDim2 = (m_nViewType == XY) ? 1 : 2;
x = m_vOrigin[nDim1] - w + 35 / m_fScale;
y = m_vOrigin[nDim2] + h - 40 / m_fScale;
const char *p = "Rotate Z Axis";
if (g_qeglobals.rotateAxis == 1) {
p = "Rotate Y Axis";
} else if (g_qeglobals.rotateAxis == 0) {
p = "Rotate X Axis";
}
idStr str = p;
if (g_qeglobals.flatRotation) {
str += g_qeglobals.flatRotation == 2 ? " Flat [center] " : " Flat [ rot origin ] ";
}
qglRasterPos2f(x, y);
qglCallLists(str.Length(), GL_UNSIGNED_BYTE, str.c_str());
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::DrawCameraIcon() {
float x, y, a;
if (m_nViewType == XY) {
x = g_pParentWnd->GetCamera()->Camera().origin[0];
y = g_pParentWnd->GetCamera()->Camera().origin[1];
a = g_pParentWnd->GetCamera()->Camera().angles[YAW] * idMath::M_DEG2RAD;
}
else if (m_nViewType == YZ) {
x = g_pParentWnd->GetCamera()->Camera().origin[1];
y = g_pParentWnd->GetCamera()->Camera().origin[2];
a = g_pParentWnd->GetCamera()->Camera().angles[PITCH] * idMath::M_DEG2RAD;
}
else {
x = g_pParentWnd->GetCamera()->Camera().origin[0];
y = g_pParentWnd->GetCamera()->Camera().origin[2];
a = g_pParentWnd->GetCamera()->Camera().angles[PITCH] * idMath::M_DEG2RAD;
}
float scale = 1.0/m_fScale; //jhefty - keep the camera icon proportionally the same size
qglColor3f(0.0, 0.0, 1.0);
qglBegin(GL_LINE_STRIP);
qglVertex3f(x - 16*scale, y, 0);
qglVertex3f(x, y + 8*scale, 0);
qglVertex3f(x + 16*scale, y, 0);
qglVertex3f(x, y - 8*scale, 0);
qglVertex3f(x - 16*scale, y, 0);
qglVertex3f(x + 16*scale, y, 0);
qglEnd();
qglBegin(GL_LINE_STRIP);
qglVertex3f(x + (48 * cos( a + idMath::PI * 0.25f )*scale), y + (48 * sin( a + idMath::PI * 0.25f )*scale), 0);
qglVertex3f(x, y, 0);
qglVertex3f(x + (48 * cos( a - idMath::PI * 0.25f )*scale), y + (48 * sin( a - idMath::PI * 0.25f )*scale), 0);
qglEnd();
#if 0
char text[128];
qglRasterPos2f(x + 64, y + 64);
sprintf(text, "%f", g_pParentWnd->GetCamera()->Camera().angles[YAW]);
qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
#endif
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::DrawZIcon(void) {
if (m_nViewType == XY) {
float x = z.origin[0];
float y = z.origin[1];
qglEnable(GL_BLEND);
globalImages->BindNull();
qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
qglDisable(GL_CULL_FACE);
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
qglColor4f(0.0, 0.0, 1.0, 0.25);
qglBegin(GL_QUADS);
qglVertex3f(x - 8, y - 8, 0);
qglVertex3f(x + 8, y - 8, 0);
qglVertex3f(x + 8, y + 8, 0);
qglVertex3f(x - 8, y + 8, 0);
qglEnd();
qglDisable(GL_BLEND);
qglColor4f(0.0, 0.0, 1.0, 1);
qglBegin(GL_LINE_LOOP);
qglVertex3f(x - 8, y - 8, 0);
qglVertex3f(x + 8, y - 8, 0);
qglVertex3f(x + 8, y + 8, 0);
qglVertex3f(x - 8, y + 8, 0);
qglEnd();
qglBegin(GL_LINE_STRIP);
qglVertex3f(x - 4, y + 4, 0);
qglVertex3f(x + 4, y + 4, 0);
qglVertex3f(x - 4, y - 4, 0);
qglVertex3f(x + 4, y - 4, 0);
qglEnd();
}
}
/*
=======================================================================================================================
FilterBrush
=======================================================================================================================
*/
bool FilterBrush(brush_t *pb) {
if (!pb->owner) {
return false; // during construction
}
if (pb->hiddenBrush) {
return true;
}
if ( pb->forceVisibile ) {
return false;
}
if (g_pParentWnd->GetZWnd()->m_pZClip) // ZClip class up and running? (and hence Z window built)
{
if (g_pParentWnd->GetZWnd()->m_pZClip->IsEnabled())
{
// ZClipping active...
//
if (pb->mins[2] > g_pParentWnd->GetZWnd()->m_pZClip->GetTop() // brush bottom edge is above clip top
||
pb->maxs[2] < g_pParentWnd->GetZWnd()->m_pZClip->GetBottom()// brush top edge is below clip bottom
)
{
return TRUE;
}
}
}
if (g_qeglobals.d_savedinfo.exclude & (EXCLUDE_CAULK | EXCLUDE_VISPORTALS)) {
//
// filter out the brush only if all faces are caulk if not don't hide the whole
// brush, proceed on a per-face basis (Cam_Draw) ++timo TODO: set this as a
// preference .. show caulk: hide any brush with caulk // don't draw caulk faces
//
face_t *f;
f = pb->brush_faces;
while (f) {
if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) {
if (!strstr(f->texdef.name, "caulk")) {
break;
}
} else {
if (strstr(f->texdef.name, "visportal")) {
return true;
}
}
f = f->next;
}
if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) {
if (!f) {
return true;
}
}
// ++timo FIXME: .. same deal here?
if (strstr(pb->brush_faces->texdef.name, "donotenter")) {
return true;
}
}
if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_HINT) {
if (strstr(pb->brush_faces->texdef.name, "hint")) {
return true;
}
}
if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) {
if (strstr(pb->brush_faces->texdef.name, "clip")) {
return true;
}
}
if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_TRIGGERS) {
if (strstr(pb->brush_faces->texdef.name, "trig")) {
return true;
}
}
if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_NODRAW) {
if (strstr(pb->brush_faces->texdef.name, "nodraw")) {
return true;
}
}
if (strstr(pb->brush_faces->texdef.name, "skip")) {
return true;
}
if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_DYNAMICS) {
if (pb->modelHandle > 0) {
idRenderModel *model = pb->modelHandle;
if ( dynamic_cast(model) ) {
return true;
}
}
}
if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CURVES) {
if (pb->pPatch) {
return true;
}
}
if (pb->owner == world_entity) {
if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD) {
return true;
}
return false;
}
else {
if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT ) {
return ( idStr::Cmpn( pb->owner->eclass->name, "func_static", 10 ) != 0 );
}
}
if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTS && pb->owner->eclass->nShowFlags & ECLASS_LIGHT ) {
return true;
}
if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_COMBATNODES && pb->owner->eclass->nShowFlags & ECLASS_COMBATNODE ) {
return true;
}
if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS && pb->owner->eclass->nShowFlags & ECLASS_PATH) {
return true;
}
if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_MODELS && ( pb->owner->eclass->entityModel != NULL || pb->modelHandle > 0 ) ) {
return true;
}
return false;
}
/*
=======================================================================================================================
PATH LINES £
DrawPathLines Draws connections between entities. Needs to consider all entities, not just ones on screen, because
the lines can be visible when neither end is. Called for both camera view and xy view.
=======================================================================================================================
*/
void DrawPathLines(void) {
int i, k;
idVec3 mid, mid1;
entity_t *se, *te;
brush_t *sb, *tb;
const char *psz;
idVec3 dir, s1, s2;
float len, f;
int arrows;
int num_entities;
const char *ent_target[MAX_MAP_ENTITIES];
entity_t *ent_entity[MAX_MAP_ENTITIES];
if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) {
return;
}
num_entities = 0;
for (te = entities.next; te != &entities && num_entities != MAX_MAP_ENTITIES; te = te->next) {
for (i = 0; i < 2048; i++) {
if (i == 0) {
ent_target[num_entities] = ValueForKey(te, "target");
} else {
ent_target[num_entities] = ValueForKey(te, va("target%i", i));
}
if (ent_target[num_entities][0]) {
ent_entity[num_entities] = te;
num_entities++;
} else if (i > 16) {
break;
}
}
}
for (se = entities.next; se != &entities; se = se->next) {
psz = ValueForKey(se, "name");
if (psz == NULL || psz[0] == '\0') {
continue;
}
sb = se->brushes.onext;
if (sb == &se->brushes) {
continue;
}
for (k = 0; k < num_entities; k++) {
if (strcmp(ent_target[k], psz)) {
continue;
}
te = ent_entity[k];
tb = te->brushes.onext;
if (tb == &te->brushes) {
continue;
}
mid = sb->owner->origin;
mid1 = tb->owner->origin;
VectorSubtract(mid1, mid, dir);
len = dir.Normalize();
s1[0] = -dir[1] * 8 + dir[0] * 8;
s2[0] = dir[1] * 8 + dir[0] * 8;
s1[1] = dir[0] * 8 + dir[1] * 8;
s2[1] = -dir[0] * 8 + dir[1] * 8;
qglColor3f(se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]);
qglBegin(GL_LINES);
qglVertex3fv(mid.ToFloatPtr());
qglVertex3fv(mid1.ToFloatPtr());
arrows = (int)(len / 256) + 1;
for (i = 0; i < arrows; i++) {
f = len * (i + 0.5) / arrows;
mid1 = mid + (f * dir);
qglVertex3fv(mid1.ToFloatPtr());
qglVertex3f(mid1[0] + s1[0], mid1[1] + s1[1], mid1[2]);
qglVertex3fv(mid1.ToFloatPtr());
qglVertex3f(mid1[0] + s2[0], mid1[1] + s2[1], mid1[2]);
}
qglEnd();
}
}
return;
}
//
// =======================================================================================================================
// can be greatly simplified but per usual i am in a hurry which is not an excuse, just a fact
// =======================================================================================================================
//
void CXYWnd::PaintSizeInfo(int nDim1, int nDim2, idVec3 vMinBounds, idVec3 vMaxBounds) {
idVec3 vSize;
VectorSubtract(vMaxBounds, vMinBounds, vSize);
qglColor3f
(
g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] * .65,
g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] * .65,
g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] * .65
);
if (m_nViewType == XY) {
qglBegin(GL_LINES);
qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f);
qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f);
qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2], 0.0f);
qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f);
qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f);
qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f);
qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2], 0.0f);
qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f);
qglEnd();
qglRasterPos3f(Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), vMinBounds[nDim2] - 20.0 / m_fScale, 0.0f);
g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]);
qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
qglRasterPos3f(vMaxBounds[nDim1] + 16.0 / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]), 0.0f);
g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]);
qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
qglRasterPos3f(vMinBounds[nDim1] + 4, vMaxBounds[nDim2] + 8 / m_fScale, 0.0f);
g_strDim.Format(g_pOrgStrings[0], vMinBounds[nDim1], vMaxBounds[nDim2]);
qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
}
else if (m_nViewType == XZ) {
qglBegin(GL_LINES);
qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 6.0f / m_fScale);
qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
qglVertex3f(vMaxBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
qglVertex3f(vMaxBounds[nDim1], 0, vMinBounds[nDim2] - 6.0f / m_fScale);
qglVertex3f(vMaxBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, 0, vMinBounds[nDim2]);
qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0, vMinBounds[nDim2]);
qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0, vMinBounds[nDim2]);
qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0, vMaxBounds[nDim2]);
qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, 0, vMaxBounds[nDim2]);
qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0, vMaxBounds[nDim2]);
qglEnd();
qglRasterPos3f(Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), 0, vMinBounds[nDim2] - 20.0 / m_fScale);
g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]);
qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
qglRasterPos3f(vMaxBounds[nDim1] + 16.0 / m_fScale, 0, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]));
g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]);
qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
qglRasterPos3f(vMinBounds[nDim1] + 4, 0, vMaxBounds[nDim2] + 8 / m_fScale);
g_strDim.Format(g_pOrgStrings[1], vMinBounds[nDim1], vMaxBounds[nDim2]);
qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
}
else {
qglBegin(GL_LINES);
qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale);
qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale);
qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
qglVertex3f(0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2]);
qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2]);
qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2]);
qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2]);
qglVertex3f(0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2]);
qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2]);
qglEnd();
qglRasterPos3f(0, Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), vMinBounds[nDim2] - 20.0 / m_fScale);
g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]);
qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
qglRasterPos3f(0, vMaxBounds[nDim1] + 16.0 / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]));
g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]);
qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
qglRasterPos3f(0, vMinBounds[nDim1] + 4.0, vMaxBounds[nDim2] + 8 / m_fScale);
g_strDim.Format(g_pOrgStrings[2], vMinBounds[nDim1], vMaxBounds[nDim2]);
qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
}
}
/* XY_Draw */
long g_lCount = 0;
long g_lTotal = 0;
extern void DrawBrushEntityName(brush_t *b);
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::XY_Draw() {
brush_t *brush;
float w, h;
entity_t *e;
idVec3 mins, maxs;
int drawn, culled;
int i;
if (!active_brushes.next) {
return; // not valid yet
}
// clear
m_bDirty = false;
GL_State( GLS_DEFAULT );
qglViewport(0, 0, m_nWidth, m_nHeight);
qglScissor(0, 0, m_nWidth, m_nHeight);
qglClearColor
(
g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0],
g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1],
g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2],
0
);
qglDisable(GL_DEPTH_TEST);
qglDisable(GL_CULL_FACE);
qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// set up viewpoint
qglMatrixMode(GL_PROJECTION);
qglLoadIdentity();
w = m_nWidth / 2 / m_fScale;
h = m_nHeight / 2 / m_fScale;
int nDim1 = (m_nViewType == YZ) ? 1 : 0;
int nDim2 = (m_nViewType == XY) ? 1 : 2;
mins[0] = m_vOrigin[nDim1] - w;
maxs[0] = m_vOrigin[nDim1] + w;
mins[1] = m_vOrigin[nDim2] - h;
maxs[1] = m_vOrigin[nDim2] + h;
idBounds viewBounds( mins, maxs );
viewBounds[0].z = -99999;
viewBounds[1].z = 99999;
qglOrtho(mins[0], maxs[0], mins[1], maxs[1], MIN_WORLD_COORD, MAX_WORLD_COORD);
// draw stuff
globalImages->BindNull();
// now draw the grid
qglLineWidth(0.25);
XY_DrawGrid();
qglLineWidth(0.5);
drawn = culled = 0;
if (m_nViewType != XY) {
qglPushMatrix();
if (m_nViewType == YZ) {
qglRotatef(-90, 0, 1, 0); // put Z going up
}
// else
qglRotatef(-90, 1, 0, 0); // put Z going up
}
e = world_entity;
for ( brush = active_brushes.next; brush != &active_brushes; brush = brush->next ) {
if ( brush->forceVisibile || ( brush->owner->eclass->nShowFlags & ( ECLASS_LIGHT | ECLASS_PROJECTEDLIGHT ) ) ) {
} else if ( brush->mins[nDim1] > maxs[0] || brush->mins[nDim2] > maxs[1] || brush->maxs[nDim1] < mins[0] || brush->maxs[nDim2] < mins[1] ) {
culled++;
continue; // off screen
}
if ( FilterBrush(brush) ) {
continue;
}
drawn++;
if (brush->owner != e && brush->owner) {
qglColor3fv(brush->owner->eclass->color.ToFloatPtr());
}
else {
qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES].ToFloatPtr());
}
Brush_DrawXY( brush, m_nViewType );
}
DrawPathLines();
// draw pointfile
if (g_qeglobals.d_pointfile_display_list) {
qglCallList(g_qeglobals.d_pointfile_display_list);
}
if (!(m_nViewType == XY)) {
qglPopMatrix();
}
// draw block grid
if (g_qeglobals.show_blocks) {
XY_DrawBlockGrid();
}
// now draw selected brushes
if (m_nViewType != XY) {
qglPushMatrix();
if (m_nViewType == YZ) {
qglRotatef(-90, 0, 1, 0); // put Z going up
}
// else
qglRotatef(-90, 1, 0, 0); // put Z going up
}
qglPushMatrix();
qglTranslatef
(
g_qeglobals.d_select_translate[0],
g_qeglobals.d_select_translate[1],
g_qeglobals.d_select_translate[2]
);
if (RotateMode()) {
qglColor3f( 0.8f, 0.1f, 0.9f );
}
else if (ScaleMode()) {
qglColor3f( 0.1f, 0.8f, 0.1f );
}
else {
qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr());
}
if (g_PrefsDlg.m_bNoStipple == FALSE) {
qglEnable(GL_LINE_STIPPLE);
qglLineStipple(3, 0xaaaa);
}
qglLineWidth(1);
idVec3 vMinBounds;
idVec3 vMaxBounds;
vMinBounds[0] = vMinBounds[1] = vMinBounds[2] = 999999.9f;
vMaxBounds[0] = vMaxBounds[1] = vMaxBounds[2] = -999999.9f;
int nSaveDrawn = drawn;
bool bFixedSize = false;
for (brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next) {
drawn++;
Brush_DrawXY(brush, m_nViewType, true);
if (!bFixedSize) {
if (brush->owner->eclass->fixedsize) {
bFixedSize = true;
}
if (g_PrefsDlg.m_bSizePaint) {
for (i = 0; i < 3; i++) {
if (brush->mins[i] < vMinBounds[i]) {
vMinBounds[i] = brush->mins[i];
}
if (brush->maxs[i] > vMaxBounds[i]) {
vMaxBounds[i] = brush->maxs[i];
}
}
}
}
}
if (g_PrefsDlg.m_bNoStipple == FALSE) {
qglDisable(GL_LINE_STIPPLE);
}
qglLineWidth(0.5);
if (!bFixedSize && !RotateMode() && !ScaleMode() && drawn - nSaveDrawn > 0 && g_PrefsDlg.m_bSizePaint) {
PaintSizeInfo(nDim1, nDim2, vMinBounds, vMaxBounds);
}
// edge / vertex flags
if (g_qeglobals.d_select_mode == sel_vertex) {
qglPointSize(4);
qglColor3f(0, 1, 0);
qglBegin(GL_POINTS);
for (i = 0; i < g_qeglobals.d_numpoints; i++) {
qglVertex3fv(g_qeglobals.d_points[i].ToFloatPtr());
}
qglEnd();
qglPointSize(1);
}
else if (g_qeglobals.d_select_mode == sel_edge) {
float *v1, *v2;
qglPointSize(4);
qglColor3f(0, 0, 1);
qglBegin(GL_POINTS);
for (i = 0; i < g_qeglobals.d_numedges; i++) {
v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1].ToFloatPtr();
v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2].ToFloatPtr();
qglVertex3f((v1[0] + v2[0]) * 0.5, (v1[1] + v2[1]) * 0.5, (v1[2] + v2[2]) * 0.5);
}
qglEnd();
qglPointSize(1);
}
g_splineList->draw (static_cast(g_qeglobals.d_select_mode == sel_editpoint || g_qeglobals.d_select_mode == sel_addpoint));
if (g_pParentWnd->GetNurbMode() && g_pParentWnd->GetNurb()->GetNumValues()) {
int maxage = g_pParentWnd->GetNurb()->GetNumValues();
int time = 0;
qglColor3f(0, 0, 1);
qglPointSize(1);
qglBegin(GL_POINTS);
g_pParentWnd->GetNurb()->SetOrder(3);
for (i = 0; i < 100; i++) {
idVec2 v = g_pParentWnd->GetNurb()->GetCurrentValue(time);
qglVertex3f(v.x, v.y, 0.0f);
time += 10;
}
qglEnd();
qglPointSize(4);
qglColor3f(0, 0, 1);
qglBegin(GL_POINTS);
for (i = 0; i < maxage; i++) {
idVec2 v = g_pParentWnd->GetNurb()->GetValue(i);
qglVertex3f(v.x, v.y, 0.0f);
}
qglEnd();
qglPointSize(1);
}
qglPopMatrix();
qglTranslatef
(
-g_qeglobals.d_select_translate[0],
-g_qeglobals.d_select_translate[1],
-g_qeglobals.d_select_translate[2]
);
if (!(m_nViewType == XY)) {
qglPopMatrix();
}
// area selection hack
if (g_qeglobals.d_select_mode == sel_area) {
qglEnable(GL_BLEND);
qglPolygonMode ( GL_FRONT_AND_BACK , GL_FILL );
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
qglColor4f(0.0, 0.0, 1.0, 0.25);
qglRectf
(
g_qeglobals.d_vAreaTL[nDim1],
g_qeglobals.d_vAreaTL[nDim2],
g_qeglobals.d_vAreaBR[nDim1],
g_qeglobals.d_vAreaBR[nDim2]
);
qglDisable(GL_BLEND);
qglPolygonMode ( GL_FRONT_AND_BACK , GL_LINE );
qglColor3f(1.0f, 1.0f, 1.0f);
qglRectf
(
g_qeglobals.d_vAreaTL[nDim1],
g_qeglobals.d_vAreaTL[nDim2],
g_qeglobals.d_vAreaBR[nDim1],
g_qeglobals.d_vAreaBR[nDim2]
);
}
// now draw camera point
DrawCameraIcon();
DrawZIcon();
if (RotateMode()) {
DrawRotateIcon();
}
/// Draw a "precision crosshair" if enabled
if( m_precisionCrosshairMode != PRECISION_CROSSHAIR_NONE )
DrawPrecisionCrosshair();
qglFlush();
// QE_CheckOpenGLForErrors();
}
/*
=======================================================================================================================
=======================================================================================================================
*/
idVec3 &CXYWnd::GetOrigin() {
return m_vOrigin;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::SetOrigin(idVec3 org) {
m_vOrigin[0] = org[0];
m_vOrigin[1] = org[1];
m_vOrigin[2] = org[2];
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnSize(UINT nType, int cx, int cy) {
CWnd::OnSize(nType, cx, cy);
CRect rect;
GetClientRect(rect);
m_nWidth = rect.Width();
m_nHeight = rect.Height();
InvalidateRect(NULL, false);
}
brush_t hold_brushes;
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::Clip() {
if (ClipMode()) {
hold_brushes.next = &hold_brushes;
ProduceSplitLists();
// brush_t* pList = (g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits;
brush_t *pList;
if (g_PrefsDlg.m_bSwitchClip) {
pList = ((m_nViewType == XZ) ? g_bSwitch : !g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits;
}
else {
pList = ((m_nViewType == XZ) ? !g_bSwitch : g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits;
}
if (pList->next != pList) {
Brush_CopyList(pList, &hold_brushes);
CleanList(&g_brFrontSplits);
CleanList(&g_brBackSplits);
Select_Delete();
Brush_CopyList(&hold_brushes, &selected_brushes);
if (RogueClipMode()) {
RetainClipMode(false);
}
else {
RetainClipMode(true);
}
Sys_UpdateWindows(W_ALL);
}
}
else if (PathMode()) {
FinishSmartCreation();
if (g_pPathFunc) {
g_pPathFunc(true, g_nPathCount);
}
g_pPathFunc = NULL;
g_nPathCount = 0;
g_bPathMode = false;
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::SplitClip() {
ProduceSplitLists();
if ((g_brFrontSplits.next != &g_brFrontSplits) && (g_brBackSplits.next != &g_brBackSplits)) {
Select_Delete();
Brush_CopyList(&g_brFrontSplits, &selected_brushes);
Brush_CopyList(&g_brBackSplits, &selected_brushes);
CleanList(&g_brFrontSplits);
CleanList(&g_brBackSplits);
if (RogueClipMode()) {
RetainClipMode(false);
}
else {
RetainClipMode(true);
}
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::FlipClip() {
g_bSwitch = !g_bSwitch;
Sys_UpdateWindows(XY | W_CAMERA_IFON);
}
//
// =======================================================================================================================
// makes sure the selected brush or camera is in view
// =======================================================================================================================
//
void CXYWnd::PositionView() {
int nDim1 = (m_nViewType == YZ) ? 1 : 0;
int nDim2 = (m_nViewType == XY) ? 1 : 2;
brush_t *b = selected_brushes.next;
if (b && b->next != b) {
m_vOrigin[nDim1] = b->mins[nDim1];
m_vOrigin[nDim2] = b->mins[nDim2];
}
else {
m_vOrigin[nDim1] = g_pParentWnd->GetCamera()->Camera().origin[nDim1];
m_vOrigin[nDim2] = g_pParentWnd->GetCamera()->Camera().origin[nDim2];
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::VectorCopyXY(const idVec3 &in, idVec3 &out) {
if (m_nViewType == XY) {
out[0] = in[0];
out[1] = in[1];
}
else if (m_nViewType == XZ) {
out[0] = in[0];
out[2] = in[2];
}
else {
out[1] = in[1];
out[2] = in[2];
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnDestroy() {
CWnd::OnDestroy();
// delete this;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::SetViewType(int n) {
m_nViewType = n;
char *p = "YZ Side";
if (m_nViewType == XY) {
p = "XY Top";
} else if (m_nViewType == XZ) {
p = "XZ Front";
}
SetWindowText(p);
};
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::Redraw(unsigned int nBits) {
m_nUpdateBits = nBits;
RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
m_nUpdateBits = W_XY;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
bool CXYWnd::RotateMode() {
return g_bRotateMode;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
bool CXYWnd::ScaleMode() {
return g_bScaleMode;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
extern bool Select_OnlyModelsSelected();
bool CXYWnd::SetRotateMode(bool bMode) {
if (bMode && selected_brushes.next != &selected_brushes) {
g_bRotateMode = true;
if (Select_OnlyModelsSelected()) {
Select_GetTrueMid(g_vRotateOrigin);
} else {
Select_GetMid(g_vRotateOrigin);
}
g_vRotation.Zero();
Select_InitializeRotation();
}
else {
if (bMode) {
Sys_Status("Need a brush selected to turn on Mouse Rotation mode\n");
}
g_bRotateMode = false;
Select_FinalizeRotation();
}
RedrawWindow();
return g_bRotateMode;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::SetScaleMode(bool bMode) {
g_bScaleMode = bMode;
RedrawWindow();
}
//
// =======================================================================================================================
// xy - z xz - y yz - x
// =======================================================================================================================
//
void CXYWnd::OnSelectMouserotate() {
// TODO: Add your command handler code here
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CleanCopyEntities() {
entity_t *pe = g_enClipboard.next;
while (pe != NULL && pe != &g_enClipboard) {
entity_t *next = pe->next;
pe->epairs.Clear();
Entity_Free(pe);
pe = next;
}
g_enClipboard.next = g_enClipboard.prev = &g_enClipboard;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
entity_t *Entity_CopyClone(entity_t *e) {
entity_t *n;
n = Entity_New();
n->brushes.onext = n->brushes.oprev = &n->brushes;
n->eclass = e->eclass;
n->rotation = e->rotation;
// add the entity to the entity list
n->next = g_enClipboard.next;
g_enClipboard.next = n;
n->next->prev = n;
n->prev = &g_enClipboard;
n->epairs = e->epairs;
return n;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
bool OnList(entity_t *pFind, CPtrArray *pList) {
int nSize = pList->GetSize();
while (nSize-- > 0) {
entity_t *pEntity = reinterpret_cast < entity_t * > (pList->GetAt(nSize));
if (pEntity == pFind) {
return true;
}
}
return false;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::Copy()
{
#if 1
CWaitCursor WaitCursor;
g_Clipboard.SetLength(0);
g_PatchClipboard.SetLength(0);
Map_SaveSelected(&g_Clipboard, &g_PatchClipboard);
bool bClipped = false;
UINT nClipboard = ::RegisterClipboardFormat("RadiantClippings");
if (nClipboard > 0) {
if (OpenClipboard()) {
::EmptyClipboard();
long lSize = g_Clipboard.GetLength();
HANDLE h = ::GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, lSize + sizeof (long));
if (h != NULL) {
unsigned char *cp = reinterpret_cast < unsigned char * > (::GlobalLock(h));
memcpy(cp, &lSize, sizeof (long));
cp += sizeof (long);
g_Clipboard.SeekToBegin();
g_Clipboard.Read(cp, lSize);
::GlobalUnlock(h);
::SetClipboardData(nClipboard, h);
::CloseClipboard();
bClipped = true;
}
}
}
if (!bClipped) {
common->Printf("Unable to register Windows clipboard formats, copy/paste between editors will not be possible");
}
/*
* CString strOut; ::GetTempPath(1024, strOut.GetBuffer(1024));
* strOut.ReleaseBuffer(); AddSlash(strOut); strOut += "RadiantClipboard.$$$";
* Map_SaveSelected(strOut.GetBuffer(0));
*/
#else
CPtrArray holdArray;
CleanList(&g_brClipboard);
CleanCopyEntities();
for (brush_t * pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) {
if (pBrush->owner == world_entity) {
brush_t *pClone = Brush_Clone(pBrush);
pClone->owner = NULL;
Brush_AddToList(pClone, &g_brClipboard);
}
else {
if (!OnList(pBrush->owner, &holdArray)) {
entity_t *e = pBrush->owner;
holdArray.Add(reinterpret_cast < void * > (e));
entity_t *pEClone = Entity_CopyClone(e);
for (brush_t * pEB = e->brushes.onext; pEB != &e->brushes; pEB = pEB->onext) {
brush_t *pClone = Brush_Clone(pEB);
// Brush_AddToList (pClone, &g_brClipboard);
Entity_LinkBrush(pEClone, pClone);
Brush_Build(pClone);
}
}
}
}
#endif
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::Undo() {
/*
* if (g_brUndo.next != &g_brUndo) { g_bScreenUpdates = false; Select_Delete();
* for (brush_t* pBrush = g_brUndo.next ; pBrush != NULL && pBrush != &g_brUndo ;
* pBrush=pBrush->next) { brush_t* pClone = Brush_Clone(pBrush); Brush_AddToList
* (pClone, &active_brushes); Entity_LinkBrush (pBrush->pUndoOwner, pClone);
* Brush_Build(pClone); Select_Brush(pClone); } CleanList(&g_brUndo);
* g_bScreenUpdates = true; Sys_UpdateWindows(W_ALL); } else common->Printf("Nothing
* to undo.../n");
*/
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::UndoClear() {
/* CleanList(&g_brUndo); */
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::UndoCopy() {
/*
* CleanList(&g_brUndo); for (brush_t* pBrush = selected_brushes.next ; pBrush !=
* NULL && pBrush != &selected_brushes ; pBrush=pBrush->next) { brush_t* pClone =
* Brush_Clone(pBrush); pClone->pUndoOwner = pBrush->owner; Brush_AddToList
* (pClone, &g_brUndo); }
*/
}
/*
=======================================================================================================================
=======================================================================================================================
*/
bool CXYWnd::UndoAvailable() {
return(g_brUndo.next != &g_brUndo);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::Paste()
{
#if 1
CWaitCursor WaitCursor;
UINT nClipboard = ::RegisterClipboardFormat("RadiantClippings");
if (nClipboard > 0 && OpenClipboard() && ::IsClipboardFormatAvailable(nClipboard)) {
HANDLE h = ::GetClipboardData(nClipboard);
if (h) {
g_Clipboard.SetLength(0);
unsigned char *cp = reinterpret_cast < unsigned char * > (::GlobalLock(h));
long lSize = 0;
memcpy(&lSize, cp, sizeof (long));
cp += sizeof (long);
g_Clipboard.Write(cp, lSize);
}
::GlobalUnlock(h);
::CloseClipboard();
}
if (g_Clipboard.GetLength() > 0) {
g_Clipboard.SeekToBegin();
int nLen = g_Clipboard.GetLength();
char *pBuffer = new char[nLen + 1];
memset(pBuffer, 0, nLen + 1);
g_Clipboard.Read(pBuffer, nLen);
pBuffer[nLen] = '\0';
Map_ImportBuffer(pBuffer, !(GetAsyncKeyState(VK_SHIFT) & 0x8000));
delete[] pBuffer;
}
#if 0
if (g_PatchClipboard.GetLength() > 0) {
g_PatchClipboard.SeekToBegin();
int nLen = g_PatchClipboard.GetLength();
char *pBuffer = new char[nLen + 1];
g_PatchClipboard.Read(pBuffer, nLen);
pBuffer[nLen] = '\0';
Patch_ReadBuffer(pBuffer, true);
delete[] pBuffer;
}
#endif
#else
if (g_brClipboard.next != &g_brClipboard || g_enClipboard.next != &g_enClipboard) {
Select_Deselect();
for (brush_t * pBrush = g_brClipboard.next; pBrush != NULL && pBrush != &g_brClipboard; pBrush = pBrush->next) {
brush_t *pClone = Brush_Clone(pBrush);
// pClone->owner = pBrush->owner;
if (pClone->owner == NULL) {
Entity_LinkBrush(world_entity, pClone);
}
Brush_AddToList(pClone, &selected_brushes);
Brush_Build(pClone);
}
for
(
entity_t * pEntity = g_enClipboard.next;
pEntity != NULL && pEntity != &g_enClipboard;
pEntity = pEntity->next
) {
entity_t *pEClone = Entity_Clone(pEntity);
for (brush_t * pEB = pEntity->brushes.onext; pEB != &pEntity->brushes; pEB = pEB->onext) {
brush_t *pClone = Brush_Clone(pEB);
Brush_AddToList(pClone, &selected_brushes);
Entity_LinkBrush(pEClone, pClone);
Brush_Build(pClone);
if (pClone->owner && pClone->owner != world_entity) {
g_Inspectors->UpdateEntitySel(pClone->owner->eclass);
}
}
}
Sys_UpdateWindows(W_ALL);
}
else {
common->Printf("Nothing to paste.../n");
}
#endif
}
/*
=======================================================================================================================
=======================================================================================================================
*/
idVec3 &CXYWnd::Rotation() {
return g_vRotation;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
idVec3 &CXYWnd::RotateOrigin() {
return g_vRotateOrigin;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnTimer(UINT_PTR nIDEvent) {
if (nIDEvent == 100) {
int nDim1 = (m_nViewType == YZ) ? 1 : 0;
int nDim2 = (m_nViewType == XY) ? 1 : 2;
m_vOrigin[nDim1] += m_ptDragAdj.x / m_fScale;
m_vOrigin[nDim2] -= m_ptDragAdj.y / m_fScale;
Sys_UpdateWindows(W_XY | W_CAMERA);
// int nH = (m_ptDrag.y == 0) ? -1 : m_ptDrag.y;
m_ptDrag += m_ptDragAdj;
m_ptDragTotal += m_ptDragAdj;
XY_MouseMoved(m_ptDrag.x, m_nHeight - 1 - m_ptDrag.y, m_nScrollFlags);
//
// m_vOrigin[nDim1] -= m_ptDrag.x / m_fScale; m_vOrigin[nDim1] -= m_ptDrag.x /
// m_fScale;
//
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) {
g_pParentWnd->HandleKey(nChar, nRepCnt, nFlags, false);
// CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR *lpncsp) {
CWnd::OnNcCalcSize(bCalcValidRects, lpncsp);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnKillFocus(CWnd *pNewWnd) {
CWnd::OnKillFocus(pNewWnd);
SendMessage(WM_NCACTIVATE, FALSE, 0);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnSetFocus(CWnd *pOldWnd) {
CWnd::OnSetFocus(pOldWnd);
SendMessage(WM_NCACTIVATE, TRUE, 0);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void CXYWnd::OnClose() {
CWnd::OnClose();
}
//
// =======================================================================================================================
// should be static as should be the rotate scale stuff
// =======================================================================================================================
//
bool CXYWnd::AreaSelectOK() {
return RotateMode() ? false : ScaleMode() ? false : true;
}
/*
=======================================================================================================================
=======================================================================================================================
*/
BOOL CXYWnd::OnEraseBkgnd(CDC *pDC) {
return TRUE;
// return CWnd::OnEraseBkgnd(pDC);
}
extern void AssignModel();
void CXYWnd::OnDropNewmodel()
{
CPoint point;
GetCursorPos(&point);
CreateRightClickEntity(this, m_ptDown.x, m_ptDown.y, "func_static");
g_Inspectors->SetMode(W_ENTITY);
g_Inspectors->AssignModel();
}
BOOL CXYWnd::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
if (zDelta > 0) {
g_pParentWnd->OnViewZoomin();
} else {
g_pParentWnd->OnViewZoomout();
}
return TRUE;
}
//---------------------------------------------------------------------------
// CyclePrecisionCrosshairMode
//
// Called when the user presses the "cycle precision cursor mode" key.
// Cycles the precision cursor among the following three modes:
// PRECISION_CURSOR_NONE
// PRECISION_CURSOR_SNAP
// PRECISION_CURSOR_FREE
//---------------------------------------------------------------------------
void CXYWnd::CyclePrecisionCrosshairMode( void )
{
common->Printf("TODO: Make DrawPrecisionCrosshair work..." );
/// Cycle to next mode, wrap if necessary
m_precisionCrosshairMode ++;
if( m_precisionCrosshairMode >= PRECISION_CROSSHAIR_MAX )
m_precisionCrosshairMode = PRECISION_CROSSHAIR_NONE;
Sys_UpdateWindows( W_XY );
}
//---------------------------------------------------------------------------
// DrawPrecisionCrosshair
//
// Draws a precision crosshair beneath the cursor in the 2d (XY) view,
// depending on one of the following values for m_precisionCrosshairMode:
//
// PRECISION_CROSSHAIR_NONE No crosshair is drawn. Do not force refresh of XY view.
// PRECISION_CROSSHAIR_SNAP Crosshair snaps to grid size. Force refresh of XY view.
// PRECISION_CROSSHAIR_FREE Crosshair does not snap to grid. Force refresh of XY view.
//---------------------------------------------------------------------------
void CXYWnd::DrawPrecisionCrosshair( void )
{
// FIXME: m_mouseX, m_mouseY, m_axisHoriz, m_axisVert, etc... are never set
#if 0
idVec3 mouse3dPos (0.0f, 0.0f, 0.0f);
float x, y;
idVec4 crossEndColor (1.0f, 0.0f, 1.0f, 1.0f); // the RGBA color of the precision crosshair at its ends
idVec4 crossMidColor; // the RGBA color of the precision crosshair at the crossing point
/// Transform the mouse coordinates into axis-correct map-coordinates
if( m_precisionCrosshairMode == PRECISION_CROSSHAIR_SNAP )
SnapToPoint( m_mouseX, m_mouseY, mouse3dPos );
else
XY_ToPoint( m_mouseX, m_mouseY, mouse3dPos );
x = mouse3dPos[ m_axisHoriz ];
y = mouse3dPos[ m_axisVert ];
/// Use the color specified by the user
crossEndColor[0] = g_qeglobals.d_savedinfo.colors[ COLOR_PRECISION_CROSSHAIR ][0];
crossEndColor[1] = g_qeglobals.d_savedinfo.colors[ COLOR_PRECISION_CROSSHAIR ][1];
crossEndColor[2] = g_qeglobals.d_savedinfo.colors[ COLOR_PRECISION_CROSSHAIR ][2];
crossEndColor[3] = 1.0f;
crossMidColor = crossEndColor;
if( m_precisionCrosshairMode == PRECISION_CROSSHAIR_FREE )
crossMidColor[ 3 ] = 0.0f; // intersection-color is 100% transparent (alpha = 0.0f)
/// Set up OpenGL states (for drawing smooth-shaded plain-colored lines)
qglEnable( GL_BLEND );
qglDisable( GL_TEXTURE_2D );
qglShadeModel( GL_SMOOTH );
qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
/// Draw a fullscreen-sized crosshair over the cursor
qglBegin( GL_LINES );
{
/// Draw the horizontal precision line (in two pieces)
qglColor4fv( crossEndColor.ToFloatPtr() );
qglVertex2f( m_mcLeft, y );
qglColor4fv( crossMidColor.ToFloatPtr() );
qglVertex2f( x, y );
qglColor4fv( crossMidColor.ToFloatPtr() );
qglVertex2f( x, y );
qglColor4fv( crossEndColor.ToFloatPtr() );
qglVertex2f( m_mcRight, y );
/// Draw the vertical precision line (in two pieces)
qglColor4fv( crossEndColor.ToFloatPtr() );
qglVertex2f( x, m_mcTop );
qglColor4fv( crossMidColor.ToFloatPtr() );
qglVertex2f( x, y );
qglColor4fv( crossMidColor.ToFloatPtr() );
qglVertex2f( x, y );
qglColor4fv( crossEndColor.ToFloatPtr() );
qglVertex2f( x, m_mcBottom );
}
qglEnd(); // GL_LINES
// Radiant was in opaque, flat-shaded mode by default; restore this to prevent possible slowdown
qglShadeModel( GL_FLAT );
qglDisable( GL_BLEND );
#endif
}