/* =========================================================================== IceTech GPL Source Code Copyright (C) 2026 Justin Marshall Modernized Entity Inspector UI pass by Justin / IceBridge workflow. =========================================================================== */ #include "precompiled.h" #pragma hdrstop #include "qe3.h" #include "Radiant.h" #include "GLWidget.h" #include "PropertyList.h" #include "entitydlg.h" #include "PreviewDlg.h" #include "CurveDlg.h" #include "../../renderer/model_local.h" // for idRenderModelPrt void Select_Ungroup(); // CEntityDlg dialog IMPLEMENT_DYNAMIC(CEntityDlg, CDialog) CEntityDlg::CEntityDlg(CWnd* pParent /*=NULL*/) : CDialog(CEntityDlg::IDD, pParent) { editEntity = NULL; multipleEntities = false; currentAnimation = NULL; currentAnimationFrame = 0; dict = NULL; themeInitialized = false; colorBackground = RGB(245, 246, 248); colorPanel = RGB(255, 255, 255); colorPanelAlt = RGB(248, 249, 251); colorBorder = RGB(210, 214, 220); colorText = RGB(32, 36, 42); colorTextMuted = RGB(92, 99, 112); colorAccent = RGB(0, 122, 204); colorEditBg = RGB(255, 255, 255); } CEntityDlg::~CEntityDlg() { DestroyModernTheme(); } void CEntityDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST_KEYVAL, listKeyVal); DDX_Control(pDX, IDC_COMBO_CLASS, comboClass); DDX_Control(pDX, IDC_EDIT_KEY, editKey); DDX_Control(pDX, IDC_EDIT_VAL, editVal); DDX_Control(pDX, IDC_STATIC_TITLE, staticTitle); DDX_Control(pDX, IDC_STATIC_KEY, staticKey); DDX_Control(pDX, IDC_STATIC_VAL, staticVal); DDX_Control(pDX, IDC_BUTTON_BROWSE, btnBrowse); DDX_Control(pDX, IDC_E_135, btn135); DDX_Control(pDX, IDC_E_90, btn90); DDX_Control(pDX, IDC_E_45, btn45); DDX_Control(pDX, IDC_E_180, btn180); DDX_Control(pDX, IDC_E_0, btn360); DDX_Control(pDX, IDC_E_225, btn225); DDX_Control(pDX, IDC_E_270, btn270); DDX_Control(pDX, IDC_E_315, btn315); DDX_Control(pDX, IDC_E_UP, btnUp); DDX_Control(pDX, IDC_E_DOWN, btnDown); DDX_Control(pDX, IDC_BUTTON_MODEL, btnModel); DDX_Control(pDX, IDC_BUTTON_SOUND, btnSound); DDX_Control(pDX, IDC_BUTTON_GUI, btnGui); DDX_Control(pDX, IDC_BUTTON_PARTICLE, btnParticle); DDX_Control(pDX, IDC_BUTTON_SKIN, btnSkin); DDX_Control(pDX, IDC_BUTTON_CURVE, btnCurve); DDX_Control(pDX, IDC_BUTTON_CREATE, btnCreate); DDX_Control(pDX, IDC_LIST_VARS, listVars); DDX_Control(pDX, IDC_ENTITY_ANIMATIONS, cbAnimations); DDX_Control(pDX, IDC_ANIMATION_SLIDER, slFrameSlider); DDX_Control(pDX, IDC_ENTITY_CURRENT_ANIM, staticFrame); DDX_Control(pDX, IDC_ENTITY_PLAY_ANIM, btnPlayAnim); DDX_Control(pDX, IDC_ENTITY_STOP_ANIM, btnStopAnim); } BEGIN_MESSAGE_MAP(CEntityDlg, CDialog) ON_WM_SIZE() ON_WM_CTLCOLOR() ON_WM_ERASEBKGND() ON_WM_PAINT() ON_CBN_SELCHANGE(IDC_COMBO_CLASS, OnCbnSelchangeComboClass) ON_LBN_SELCHANGE(IDC_LIST_KEYVAL, OnLbnSelchangeListkeyval) ON_BN_CLICKED(IDC_E_135, OnBnClickedE135) ON_BN_CLICKED(IDC_E_90, OnBnClickedE90) ON_BN_CLICKED(IDC_E_45, OnBnClickedE45) ON_BN_CLICKED(IDC_E_180, OnBnClickedE180) ON_BN_CLICKED(IDC_E_0, OnBnClickedE0) ON_BN_CLICKED(IDC_E_225, OnBnClickedE225) ON_BN_CLICKED(IDC_E_270, OnBnClickedE270) ON_BN_CLICKED(IDC_E_315, OnBnClickedE315) ON_BN_CLICKED(IDC_E_UP, OnBnClickedEUp) ON_BN_CLICKED(IDC_E_DOWN, OnBnClickedEDown) ON_BN_CLICKED(IDC_BUTTON_MODEL, OnBnClickedButtonModel) ON_BN_CLICKED(IDC_BUTTON_SOUND, OnBnClickedButtonSound) ON_BN_CLICKED(IDC_BUTTON_GUI, OnBnClickedButtonGui) ON_BN_CLICKED(IDC_BUTTON_BROWSE, OnBnClickedButtonBrowse) ON_CBN_DBLCLK(IDC_COMBO_CLASS, OnCbnDblclkComboClass) ON_BN_CLICKED(IDC_BUTTON_CREATE, OnBnClickedButtonCreate) ON_LBN_DBLCLK(IDC_LIST_KEYVAL, OnLbnDblclkListkeyval) ON_LBN_SELCHANGE(IDC_LIST_VARS, OnLbnSelchangeListVars) ON_LBN_DBLCLK(IDC_LIST_VARS, OnLbnDblclkListVars) ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_ANIMATION_SLIDER, OnNMReleasedcaptureSlider1) ON_BN_CLICKED(IDC_BUTTON_PARTICLE, OnBnClickedButtonParticle) ON_BN_CLICKED(IDC_BUTTON_SKIN, OnBnClickedButtonSkin) ON_BN_CLICKED(IDC_BUTTON_CURVE, OnBnClickedButtonCurve) ON_CBN_SELCHANGE(IDC_ENTITY_ANIMATIONS, OnCbnAnimationChange) ON_BN_CLICKED(IDC_ENTITY_PLAY_ANIM, OnBnClickedStartAnimation) ON_BN_CLICKED(IDC_ENTITY_STOP_ANIM, OnBnClickedStopAnimation) ON_WM_TIMER() ON_BN_CLICKED(IDOK, OnOK) END_MESSAGE_MAP() // -------------------------------------------------------------------------- // Modern theme helpers // -------------------------------------------------------------------------- void CEntityDlg::DestroyModernTheme() { if (fontTitle.GetSafeHandle()) { fontTitle.DeleteObject(); } if (fontSection.GetSafeHandle()) { fontSection.DeleteObject(); } if (fontNormal.GetSafeHandle()) { fontNormal.DeleteObject(); } if (fontMono.GetSafeHandle()) { fontMono.DeleteObject(); } if (brushBackground.GetSafeHandle()) { brushBackground.DeleteObject(); } if (brushPanel.GetSafeHandle()) { brushPanel.DeleteObject(); } if (brushPanelAlt.GetSafeHandle()) { brushPanelAlt.DeleteObject(); } if (brushEdit.GetSafeHandle()) { brushEdit.DeleteObject(); } if (brushStatic.GetSafeHandle()) { brushStatic.DeleteObject(); } themeInitialized = false; } void CEntityDlg::InitModernTheme() { if (themeInitialized) { return; } NONCLIENTMETRICS ncm; memset(&ncm, 0, sizeof(ncm)); ncm.cbSize = sizeof(ncm); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); LOGFONT lf = ncm.lfMessageFont; strcpy(lf.lfFaceName, "Segoe UI"); lf.lfHeight = -12; lf.lfWeight = FW_NORMAL; fontNormal.CreateFontIndirect(&lf); lf.lfHeight = -17; lf.lfWeight = FW_SEMIBOLD; fontTitle.CreateFontIndirect(&lf); lf.lfHeight = -12; lf.lfWeight = FW_SEMIBOLD; fontSection.CreateFontIndirect(&lf); strcpy(lf.lfFaceName, "Consolas"); lf.lfHeight = -12; lf.lfWeight = FW_NORMAL; fontMono.CreateFontIndirect(&lf); brushBackground.CreateSolidBrush(colorBackground); brushPanel.CreateSolidBrush(colorPanel); brushPanelAlt.CreateSolidBrush(colorPanelAlt); brushEdit.CreateSolidBrush(colorEditBg); brushStatic.CreateSolidBrush(colorPanel); themeInitialized = true; } void CEntityDlg::SetCtrlFont(CWnd& wnd, CFont* font) { if (wnd.GetSafeHwnd() && font && font->GetSafeHandle()) { wnd.SetFont(font, FALSE); } } void CEntityDlg::SetCtrlFont(int id, CFont* font) { CWnd* wnd = GetDlgItem(id); if (wnd && wnd->GetSafeHwnd() && font && font->GetSafeHandle()) { wnd->SetFont(font, FALSE); } } void CEntityDlg::ApplyModernTheme() { InitModernTheme(); SetCtrlFont(staticTitle, &fontTitle); SetCtrlFont(staticKey, &fontSection); SetCtrlFont(staticVal, &fontSection); SetCtrlFont(staticFrame, &fontNormal); SetCtrlFont(comboClass, &fontNormal); SetCtrlFont(cbAnimations, &fontNormal); SetCtrlFont(editKey, &fontMono); SetCtrlFont(editVal, &fontMono); SetCtrlFont(listKeyVal, &fontMono); SetCtrlFont(listVars, &fontNormal); SetCtrlFont(btnCreate, &fontSection); SetCtrlFont(btnBrowse, &fontSection); SetCtrlFont(btnModel, &fontNormal); SetCtrlFont(btnSound, &fontNormal); SetCtrlFont(btnGui, &fontNormal); SetCtrlFont(btnParticle, &fontNormal); SetCtrlFont(btnSkin, &fontNormal); SetCtrlFont(btnCurve, &fontNormal); SetCtrlFont(btn135, &fontNormal); SetCtrlFont(btn90, &fontNormal); SetCtrlFont(btn45, &fontNormal); SetCtrlFont(btn180, &fontNormal); SetCtrlFont(btn360, &fontNormal); SetCtrlFont(btn225, &fontNormal); SetCtrlFont(btn270, &fontNormal); SetCtrlFont(btn315, &fontNormal); SetCtrlFont(btnUp, &fontNormal); SetCtrlFont(btnDown, &fontNormal); SetCtrlFont(btnPlayAnim, &fontNormal); SetCtrlFont(btnStopAnim, &fontNormal); if (editKey.GetSafeHwnd()) { editKey.SetMargins(6, 6); } if (editVal.GetSafeHwnd()) { editVal.SetMargins(6, 6); } staticTitle.SetWindowText("Entity Inspector"); staticKey.SetWindowText("Key"); staticVal.SetWindowText("Value"); } void CEntityDlg::MoveCtrl(CWnd& wnd, int x, int y, int w, int h, UINT flags) { if (wnd.GetSafeHwnd()) { wnd.SetWindowPos(NULL, x, y, max(1, w), max(1, h), flags | SWP_NOZORDER); } } void CEntityDlg::MoveCtrl(int id, int x, int y, int w, int h, UINT flags) { CWnd* wnd = GetDlgItem(id); if (wnd && wnd->GetSafeHwnd()) { wnd->SetWindowPos(NULL, x, y, max(1, w), max(1, h), flags | SWP_NOZORDER); } } void CEntityDlg::DrawPanel(CDC& dc, const CRect& r, const char* title, bool accent) { CBrush* oldBrush = dc.SelectObject(&brushPanel); CPen borderPen(PS_SOLID, 1, accent ? colorAccent : colorBorder); CPen* oldPen = dc.SelectObject(&borderPen); dc.RoundRect(r.left, r.top, r.right, r.bottom, 8, 8); if (title && title[0]) { CRect titleRect = r; titleRect.left += 10; titleRect.top += 6; titleRect.bottom = titleRect.top + 18; CFont* oldFont = dc.SelectObject(&fontSection); dc.SetBkMode(TRANSPARENT); dc.SetTextColor(accent ? colorAccent : colorTextMuted); dc.DrawText(title, -1, &titleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); dc.SelectObject(oldFont); } dc.SelectObject(oldPen); dc.SelectObject(oldBrush); } void CEntityDlg::DrawModernBackground(CDC& dc) { CRect rect; GetClientRect(&rect); dc.FillSolidRect(&rect, colorBackground); const int pad = 8; CRect header(rect.left + pad, rect.top + pad, rect.right - pad, rect.top + 42); CRect classPanel(rect.left + pad, header.bottom + pad, rect.right - pad, header.bottom + 52 + pad); int contentTop = classPanel.bottom + pad; int contentBottom = rect.bottom - pad; int width = rect.Width(); if (width >= 560) { int leftW = (width - pad * 3) / 2; CRect vars(rect.left + pad, contentTop, rect.left + pad + leftW, contentTop + 220); CRect keyvals(vars.right + pad, contentTop, rect.right - pad, contentTop + 220); CRect editor(rect.left + pad, vars.bottom + pad, rect.right - pad, vars.bottom + 106); CRect tools(rect.left + pad, editor.bottom + pad, rect.right - pad, contentBottom); DrawPanel(dc, header, "", true); DrawPanel(dc, classPanel, "Class", false); DrawPanel(dc, vars, "Spawn Args / Help", false); DrawPanel(dc, keyvals, "Key / Value Pairs", true); DrawPanel(dc, editor, "Edit Property", false); DrawPanel(dc, tools, "Tools", false); } else { int h = max(120, (contentBottom - contentTop - pad * 3) / 4); CRect vars(rect.left + pad, contentTop, rect.right - pad, contentTop + h); CRect keyvals(rect.left + pad, vars.bottom + pad, rect.right - pad, vars.bottom + h); CRect editor(rect.left + pad, keyvals.bottom + pad, rect.right - pad, keyvals.bottom + 106); CRect tools(rect.left + pad, editor.bottom + pad, rect.right - pad, contentBottom); DrawPanel(dc, header, "", true); DrawPanel(dc, classPanel, "Class", false); DrawPanel(dc, vars, "Spawn Args / Help", false); DrawPanel(dc, keyvals, "Key / Value Pairs", true); DrawPanel(dc, editor, "Edit Property", false); DrawPanel(dc, tools, "Tools", false); } } BOOL CEntityDlg::OnEraseBkgnd(CDC* pDC) { if (pDC) { DrawModernBackground(*pDC); } return TRUE; } void CEntityDlg::OnPaint() { CPaintDC dc(this); DrawModernBackground(dc); } HBRUSH CEntityDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); if (!themeInitialized) { return hbr; } const int id = pWnd ? pWnd->GetDlgCtrlID() : 0; switch (nCtlColor) { case CTLCOLOR_STATIC: pDC->SetTextColor((id == IDC_STATIC_TITLE) ? colorText : colorTextMuted); pDC->SetBkMode(TRANSPARENT); return (HBRUSH)brushPanel.GetSafeHandle(); case CTLCOLOR_EDIT: pDC->SetTextColor(colorText); pDC->SetBkColor(colorEditBg); return (HBRUSH)brushEdit.GetSafeHandle(); case CTLCOLOR_LISTBOX: pDC->SetTextColor(colorText); pDC->SetBkColor(colorEditBg); return (HBRUSH)brushEdit.GetSafeHandle(); case CTLCOLOR_BTN: pDC->SetTextColor(colorText); pDC->SetBkColor(colorPanelAlt); return (HBRUSH)brushPanelAlt.GetSafeHandle(); case CTLCOLOR_DLG: return (HBRUSH)brushBackground.GetSafeHandle(); } return hbr; } // -------------------------------------------------------------------------- // Dialog init / layout // -------------------------------------------------------------------------- BOOL CEntityDlg::OnInitDialog() { CDialog::OnInitDialog(); InitModernTheme(); listKeyVal.SetUpdateInspectors(true); listKeyVal.SetDivider(120); listVars.SetDivider(120); staticFrame.SetWindowText("0"); ApplyModernTheme(); ModifyStyleEx(0, WS_EX_CONTROLPARENT); Invalidate(FALSE); return TRUE; } INT_PTR CEntityDlg::OnToolHitTest(CPoint point, TOOLINFO* pTI) const { return CDialog::OnToolHitTest(point, pTI); } void CEntityDlg::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); if (staticTitle.GetSafeHwnd() == NULL) { return; } const int pad = 8; const int inner = 10; const int headerH = 42; const int classH = 52; const int editorH = 106; const int minToolH = 124; CRect rect; GetClientRect(&rect); int w = max(1, rect.Width()); int h = max(1, rect.Height()); CRect header(rect.left + pad, rect.top + pad, rect.right - pad, rect.top + pad + headerH); MoveCtrl(staticTitle, header.left + 12, header.top + 8, header.Width() - 24, 24); CRect classPanel(rect.left + pad, header.bottom + pad, rect.right - pad, header.bottom + pad + classH); int classY = classPanel.top + 22; int createW = 82; MoveCtrl(comboClass, classPanel.left + inner, classY, classPanel.Width() - inner * 3 - createW, 22); MoveCtrl(btnCreate, classPanel.right - inner - createW, classY, createW, 22); int contentTop = classPanel.bottom + pad; int contentBottom = rect.bottom - pad; if (w >= 560) { int listH = max(120, min(260, (h - contentTop - editorH - minToolH - pad * 3))); int leftW = (w - pad * 3) / 2; CRect varsPanel(rect.left + pad, contentTop, rect.left + pad + leftW, contentTop + listH); CRect keyPanel(varsPanel.right + pad, contentTop, rect.right - pad, contentTop + listH); MoveCtrl(listVars, varsPanel.left + inner, varsPanel.top + 28, varsPanel.Width() - inner * 2, varsPanel.Height() - 38); MoveCtrl(listKeyVal, keyPanel.left + inner, keyPanel.top + 28, keyPanel.Width() - inner * 2, keyPanel.Height() - 38); CRect editPanel(rect.left + pad, varsPanel.bottom + pad, rect.right - pad, varsPanel.bottom + pad + editorH); int labelW = 52; int browseW = 28; int rowH = 22; int rowY = editPanel.top + 30; MoveCtrl(staticKey, editPanel.left + inner, rowY + 2, labelW, rowH); MoveCtrl(editKey, editPanel.left + inner + labelW + 6, rowY, editPanel.Width() - inner * 2 - labelW - 6, rowH); rowY += rowH + 10; MoveCtrl(staticVal, editPanel.left + inner, rowY + 2, labelW, rowH); MoveCtrl(editVal, editPanel.left + inner + labelW + 6, rowY, editPanel.Width() - inner * 2 - labelW - 6 - browseW - 6, rowH); MoveCtrl(btnBrowse, editPanel.right - inner - browseW, rowY, browseW, rowH); CRect toolsPanel(rect.left + pad, editPanel.bottom + pad, rect.right - pad, contentBottom); int toolY = toolsPanel.top + 28; int toolX = toolsPanel.left + inner; int b = 30; MoveCtrl(btn135, toolX, toolY, b, b); MoveCtrl(btn90, toolX + b + 4, toolY, b, b); MoveCtrl(btn45, toolX + (b + 4) * 2, toolY, b, b); MoveCtrl(btn180, toolX, toolY + b + 4, b, b); MoveCtrl(btn360, toolX + (b + 4) * 2, toolY + b + 4, b, b); MoveCtrl(btn225, toolX, toolY + (b + 4) * 2, b, b); MoveCtrl(btn270, toolX + b + 4, toolY + (b + 4) * 2, b, b); MoveCtrl(btn315, toolX + (b + 4) * 2, toolY + (b + 4) * 2, b, b); MoveCtrl(btnUp, toolX + (b + 4) * 3 + 8, toolY + 16, b + 8, b); MoveCtrl(btnDown, toolX + (b + 4) * 3 + 8, toolY + 16 + b + 6, b + 8, b); int mediaX = toolX + 190; int mediaW = 76; int mediaH = 24; MoveCtrl(btnModel, mediaX, toolY, mediaW, mediaH); MoveCtrl(btnSound, mediaX, toolY + mediaH + 6, mediaW, mediaH); MoveCtrl(btnGui, mediaX, toolY + (mediaH + 6) * 2, mediaW, mediaH); MoveCtrl(btnCurve, mediaX + mediaW + 8, toolY, mediaW, mediaH); MoveCtrl(btnSkin, mediaX + mediaW + 8, toolY + mediaH + 6, mediaW, mediaH); MoveCtrl(btnParticle, mediaX + mediaW + 8, toolY + (mediaH + 6) * 2, mediaW, mediaH); int animX = mediaX + (mediaW + 8) * 2 + 18; int animW = max(120, toolsPanel.right - animX - inner); MoveCtrl(cbAnimations, animX, toolY, animW, 24); MoveCtrl(btnPlayAnim, animX, toolY + 32, 54, 24); MoveCtrl(btnStopAnim, animX + 60, toolY + 32, 54, 24); MoveCtrl(slFrameSlider, animX, toolY + 66, max(80, animW - 44), 24); MoveCtrl(staticFrame, animX + animW - 38, toolY + 68, 36, 20); } else { int available = contentBottom - contentTop; int listH = max(82, (available - editorH - minToolH - pad * 3) / 2); CRect varsPanel(rect.left + pad, contentTop, rect.right - pad, contentTop + listH); CRect keyPanel(rect.left + pad, varsPanel.bottom + pad, rect.right - pad, varsPanel.bottom + pad + listH); MoveCtrl(listVars, varsPanel.left + inner, varsPanel.top + 28, varsPanel.Width() - inner * 2, varsPanel.Height() - 38); MoveCtrl(listKeyVal, keyPanel.left + inner, keyPanel.top + 28, keyPanel.Width() - inner * 2, keyPanel.Height() - 38); CRect editPanel(rect.left + pad, keyPanel.bottom + pad, rect.right - pad, keyPanel.bottom + pad + editorH); int labelW = 48; int browseW = 28; int rowH = 22; int rowY = editPanel.top + 30; MoveCtrl(staticKey, editPanel.left + inner, rowY + 2, labelW, rowH); MoveCtrl(editKey, editPanel.left + inner + labelW + 6, rowY, editPanel.Width() - inner * 2 - labelW - 6, rowH); rowY += rowH + 10; MoveCtrl(staticVal, editPanel.left + inner, rowY + 2, labelW, rowH); MoveCtrl(editVal, editPanel.left + inner + labelW + 6, rowY, editPanel.Width() - inner * 2 - labelW - 6 - browseW - 6, rowH); MoveCtrl(btnBrowse, editPanel.right - inner - browseW, rowY, browseW, rowH); CRect toolsPanel(rect.left + pad, editPanel.bottom + pad, rect.right - pad, contentBottom); int toolY = toolsPanel.top + 28; int toolX = toolsPanel.left + inner; int b = 26; MoveCtrl(btn135, toolX, toolY, b, b); MoveCtrl(btn90, toolX + b + 4, toolY, b, b); MoveCtrl(btn45, toolX + (b + 4) * 2, toolY, b, b); MoveCtrl(btn180, toolX, toolY + b + 4, b, b); MoveCtrl(btn360, toolX + (b + 4) * 2, toolY + b + 4, b, b); MoveCtrl(btn225, toolX, toolY + (b + 4) * 2, b, b); MoveCtrl(btn270, toolX + b + 4, toolY + (b + 4) * 2, b, b); MoveCtrl(btn315, toolX + (b + 4) * 2, toolY + (b + 4) * 2, b, b); MoveCtrl(btnUp, toolX + (b + 4) * 3 + 6, toolY + 12, b + 8, b); MoveCtrl(btnDown, toolX + (b + 4) * 3 + 6, toolY + 12 + b + 6, b + 8, b); int mediaX = toolX + 152; int mediaW = max(58, (toolsPanel.right - mediaX - inner - 8) / 2); int mediaH = 22; MoveCtrl(btnModel, mediaX, toolY, mediaW, mediaH); MoveCtrl(btnSound, mediaX, toolY + mediaH + 5, mediaW, mediaH); MoveCtrl(btnGui, mediaX, toolY + (mediaH + 5) * 2, mediaW, mediaH); MoveCtrl(btnCurve, mediaX + mediaW + 8, toolY, mediaW, mediaH); MoveCtrl(btnSkin, mediaX + mediaW + 8, toolY + mediaH + 5, mediaW, mediaH); MoveCtrl(btnParticle, mediaX + mediaW + 8, toolY + (mediaH + 5) * 2, mediaW, mediaH); int animY = toolY + 88; MoveCtrl(cbAnimations, toolX, animY, toolsPanel.Width() - inner * 2, 22); MoveCtrl(btnPlayAnim, toolX, animY + 28, 54, 22); MoveCtrl(btnStopAnim, toolX + 60, animY + 28, 54, 22); MoveCtrl(slFrameSlider, toolX + 120, animY + 28, toolsPanel.Width() - inner * 2 - 162, 22); MoveCtrl(staticFrame, toolsPanel.right - inner - 36, animY + 30, 36, 18); } Invalidate(FALSE); } // -------------------------------------------------------------------------- // Entity/class/keyval behavior // -------------------------------------------------------------------------- void CEntityDlg::AddClassNames() { comboClass.ResetContent(); for (eclass_t* pec = eclass; pec; pec = pec->next) { comboClass.AddString(pec->name); } } void CEntityDlg::OnCbnSelchangeComboClass() { int index = comboClass.GetCurSel(); if (index != LB_ERR) { CString str; comboClass.GetLBText(index, str); eclass_t* ent = Eclass_ForName(str, false); if (ent) { if (selected_brushes.next == &selected_brushes) { editEntity = world_entity; multipleEntities = false; } else { editEntity = selected_brushes.next->owner; multipleEntities = false; for (brush_t* b = selected_brushes.next->next; b != &selected_brushes; b = b->next) { if (b->owner != editEntity) { multipleEntities = true; break; } } } listVars.ResetContent(); CPropertyItem* pi = new CPropertyItem("Usage:", ent->desc.c_str(), PIT_VAR, ""); listVars.AddPropItem(pi); int c = ent->vars.Num(); for (int i = 0; i < c; i++) { pi = new CPropertyItem(ent->vars[i].name.c_str(), ent->vars[i].desc.c_str(), PIT_VAR, ""); pi->SetData(ent->vars[i].type); listVars.AddPropItem(pi); } listVars.Invalidate(); SetKeyValPairs(); } } } const char* CEntityDlg::TranslateString(const char* buf) { static char buf2[32768]; int l = strlen(buf); char* out = buf2; for (int i = 0; i < l; i++) { if (buf[i] == '\n') { *out++ = '\r'; *out++ = '\n'; } else { *out++ = buf[i]; } } *out++ = 0; return buf2; } void CEntityDlg::UpdateFromListBox() { if (editEntity == NULL) { return; } int c = listKeyVal.GetCount(); for (int i = 0; i < c; i++) { CPropertyItem* pItem = (CPropertyItem*)listKeyVal.GetItemDataPtr(i); if (pItem) { editEntity->epairs.Set(pItem->m_propName, pItem->m_curValue); } } SetKeyValPairs(); } void CEntityDlg::SetKeyValPairs(bool updateAnims) { if (editEntity) { listKeyVal.ResetContent(); int c = editEntity->epairs.GetNumKeyVals(); for (int i = 0; i < c; i++) { const idKeyValue* kv = editEntity->epairs.GetKeyVal(i); CPropertyItem* pi = new CPropertyItem(kv->GetKey().c_str(), kv->GetValue().c_str(), PIT_EDIT, ""); bool found = false; int vc = editEntity->eclass->vars.Num(); for (int j = 0; j < vc; j++) { if (editEntity->eclass->vars[j].name.Icmp(kv->GetKey()) == 0) { switch (editEntity->eclass->vars[j].type) { case EVAR_STRING: case EVAR_INT: case EVAR_FLOAT: pi->m_nItemType = PIT_EDIT; break; case EVAR_BOOL: pi->m_nItemType = PIT_EDIT; break; case EVAR_COLOR: pi->m_nItemType = PIT_COLOR; break; case EVAR_MATERIAL: pi->m_nItemType = PIT_MATERIAL; break; case EVAR_MODEL: pi->m_nItemType = PIT_MODEL; break; case EVAR_GUI: pi->m_nItemType = PIT_GUI; break; case EVAR_SOUND: pi->m_nItemType = PIT_SOUND; break; } found = true; break; } } if (!found) { if (kv->GetKey().Icmp("model") == 0) { pi->m_nItemType = PIT_MODEL; } if (kv->GetKey().Icmp("_color") == 0) { pi->m_nItemType = PIT_COLOR; } if (kv->GetKey().Icmp("gui") == 0) { pi->m_nItemType = PIT_GUI; } if (kv->GetKey().Icmp("gui2") == 0) { pi->m_nItemType = PIT_GUI; } if (kv->GetKey().Icmp("gui3") == 0) { pi->m_nItemType = PIT_GUI; } if (kv->GetKey().Icmp("s_shader") == 0) { pi->m_nItemType = PIT_SOUND; } } listKeyVal.AddPropItem(pi); } if (updateAnims) { int i, num; cbAnimations.ResetContent(); num = gameEdit->ANIM_GetNumAnimsFromEntityDef(&editEntity->eclass->defArgs); for (i = 0; i < num; i++) { cbAnimations.AddString(gameEdit->ANIM_GetAnimNameFromEntityDef(&editEntity->eclass->defArgs, i)); } const idKeyValue* kv = editEntity->epairs.FindKey("anim"); if (kv) { int selIndex = cbAnimations.FindStringExact(0, kv->GetValue().c_str()); if (selIndex != -1) { cbAnimations.SetCurSel(selIndex); OnCbnAnimationChange(); } } } } } void CEntityDlg::UpdateEntitySel(eclass_t* ent) { assert(ent); assert(ent->name); int index = comboClass.FindString(-1, ent->name); if (index != LB_ERR) { comboClass.SetCurSel(index); OnCbnSelchangeComboClass(); } } void CEntityDlg::OnLbnSelchangeListkeyval() { int index = listKeyVal.GetCurSel(); if (index != LB_ERR) { CString str; listKeyVal.GetText(index, str); int i; for (i = 0; str[i] != '\t' && str[i] != '\0'; i++) { } idStr key = str.Left(i); while (str[i] == '\t' && str[i] != '\0') { i++; } idStr val = str.Right(str.GetLength() - i); editKey.SetWindowText(key); editVal.SetWindowText(val); } } static int TabOrder[] = { IDC_COMBO_CLASS, IDC_BUTTON_CREATE, IDC_LIST_KEYVAL, IDC_EDIT_KEY, IDC_EDIT_VAL, IDC_BUTTON_BROWSE, IDC_E_135, IDC_E_90, IDC_E_45, IDC_E_180, IDC_E_0, IDC_E_225, IDC_E_270, IDC_E_315, IDC_E_UP, IDC_E_DOWN, IDC_BUTTON_MODEL, IDC_BUTTON_SOUND, IDC_BUTTON_GUI, IDC_ENTITY_ANIMATIONS }; int TabCount = sizeof(TabOrder) / sizeof(int); void CEntityDlg::DelProp() { CString key; if (editEntity == NULL) { return; } editKey.GetWindowText(key); if (multipleEntities) { for (brush_t* b = selected_brushes.next; b != &selected_brushes; b = b->next) { DeleteKey(b->owner, key); Entity_UpdateCurveData(b->owner); } } else { DeleteKey(editEntity, key); Entity_UpdateCurveData(editEntity); } SetKeyValPairs(); Sys_UpdateWindows(W_ENTITY | W_XY | W_CAMERA); } BOOL CEntityDlg::PreTranslateMessage(MSG* pMsg) { if (pMsg->hwnd == editVal.GetSafeHwnd()) { if (pMsg->message == WM_LBUTTONDOWN) { editVal.SetFocus(); return TRUE; } } if (pMsg->hwnd == editKey.GetSafeHwnd()) { if (pMsg->message == WM_LBUTTONDOWN) { editKey.SetFocus(); return TRUE; } } if (GetFocus() == &editVal || GetFocus() == &editKey) { if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { AddProp(); return TRUE; } } if (GetFocus() == listKeyVal.GetEditBox()) { if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { listKeyVal.OnChangeEditBox(); listKeyVal.OnSelchange(); listKeyVal.OnKillfocusEditBox(); AddProp(); SetKeyValPairs(); return TRUE; } } if (GetFocus() == &listKeyVal) { if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_DELETE && editEntity) { DelProp(); return TRUE; } } if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) { g_pParentWnd->GetCamera()->SetFocus(); Select_Deselect(); return TRUE; } if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { return TRUE; } if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_TAB) { if (GetFocus()) { int id = GetFocus()->GetDlgCtrlID(); for (int i = 0; i < TabCount; i++) { if (TabOrder[i] == id) { i++; if (i >= TabCount) { i = 0; } CWnd* next = GetDlgItem(TabOrder[i]); if (next) { next->SetFocus(); if (TabOrder[i] == IDC_EDIT_VAL) { editVal.SetSel(0, -1); } return TRUE; } } } } } if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RIGHT && pMsg->hwnd == slFrameSlider.GetSafeHwnd()) { int maxRange = slFrameSlider.GetRangeMax(); if (maxRange <= 0) { return TRUE; } int pos = slFrameSlider.GetPos() + 1; pos = (pos % maxRange); slFrameSlider.SetPos(pos); UpdateFromAnimationFrame(); return TRUE; } if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_LEFT && pMsg->hwnd == slFrameSlider.GetSafeHwnd()) { int maxRange = slFrameSlider.GetRangeMax(); if (maxRange <= 0) { return TRUE; } int pos = slFrameSlider.GetPos() - 1; if (pos < 1) { pos = maxRange; } slFrameSlider.SetPos(pos); UpdateFromAnimationFrame(); return TRUE; } return CDialog::PreTranslateMessage(pMsg); } void CEntityDlg::AddProp() { if (editEntity == NULL) { return; } CString Key, Value; editKey.GetWindowText(Key); editVal.GetWindowText(Value); bool isName = (stricmp(Key, "name") == 0); bool isModel = static_cast((stricmp(Key, "model") == 0 && Value.GetLength() > 0)); bool isOrigin = (idStr::Icmp(Key, "origin") == 0); if (multipleEntities) { for (brush_t* b = selected_brushes.next; b != &selected_brushes; b = b->next) { if (isName) { Entity_SetName(b->owner, Value); } else { if (!((isModel || isOrigin) && (b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN))) { SetKeyValue(b->owner, Key, Value); } } } } else { if (isName) { Entity_SetName(editEntity, Value); } else { if (!((isModel || isOrigin) && (editEntity->eclass->nShowFlags & ECLASS_WORLDSPAWN))) { SetKeyValue(editEntity, Key, Value); } } if (isModel && !(editEntity->eclass->nShowFlags & ECLASS_WORLDSPAWN)) { idBounds bo; idVec3 mins, maxs; selected_brushes.next->modelHandle = renderModelManager->FindModel(Value); if (dynamic_cast(selected_brushes.next->modelHandle) || dynamic_cast(selected_brushes.next->modelHandle)) { bo.Zero(); bo.ExpandSelf(12.0f); } else { bo = selected_brushes.next->modelHandle->Bounds(NULL); } VectorCopy(bo[0], mins); VectorCopy(bo[1], maxs); VectorAdd(mins, editEntity->origin, mins); VectorAdd(maxs, editEntity->origin, maxs); Brush_RebuildBrush(selected_brushes.next, mins, maxs, false); Brush_Build(selected_brushes.next, false, false, false, true); } } SetKeyValPairs(); Sys_UpdateWindows(W_ALL); } const char* CEntityDlg::AngleKey() { if (editEntity == NULL) { return ""; } if (editEntity->eclass->nShowFlags & ECLASS_MOVER) { return "movedir"; } return "angle"; } void CEntityDlg::OnBnClickedE135() { if (editEntity == NULL) { return; } editKey.SetWindowText(AngleKey()); editVal.SetWindowText("135"); AddProp(); } void CEntityDlg::OnBnClickedE90() { if (editEntity == NULL) { return; } editKey.SetWindowText(AngleKey()); editVal.SetWindowText("90"); AddProp(); } void CEntityDlg::OnBnClickedE45() { if (editEntity == NULL) { return; } editKey.SetWindowText(AngleKey()); editVal.SetWindowText("45"); AddProp(); } void CEntityDlg::OnBnClickedE180() { if (editEntity == NULL) { return; } editKey.SetWindowText(AngleKey()); editVal.SetWindowText("180"); AddProp(); } void CEntityDlg::OnBnClickedE0() { if (editEntity == NULL) { return; } editKey.SetWindowText(AngleKey()); editVal.SetWindowText("0"); AddProp(); } void CEntityDlg::OnBnClickedE225() { if (editEntity == NULL) { return; } editKey.SetWindowText(AngleKey()); editVal.SetWindowText("225"); AddProp(); } void CEntityDlg::OnBnClickedE270() { if (editEntity == NULL) { return; } editKey.SetWindowText(AngleKey()); editVal.SetWindowText("270"); AddProp(); } void CEntityDlg::OnBnClickedE315() { if (editEntity == NULL) { return; } editKey.SetWindowText(AngleKey()); editVal.SetWindowText("315"); AddProp(); } void CEntityDlg::OnBnClickedEUp() { if (editEntity == NULL) { return; } editKey.SetWindowText(AngleKey()); editVal.SetWindowText("-1"); AddProp(); } void CEntityDlg::OnBnClickedEDown() { if (editEntity == NULL) { return; } editKey.SetWindowText(AngleKey()); editVal.SetWindowText("-2"); AddProp(); } // -------------------------------------------------------------------------- // Choosers // -------------------------------------------------------------------------- CPreviewDlg* CEntityDlg::ShowModelChooser() { static CPreviewDlg modelDlg; modelDlg.SetMode(CPreviewDlg::MODELS); modelDlg.SetModal(); if (modelDlg.GetSafeHwnd() == NULL) { modelDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW)); } modelDlg.ShowWindow(SW_SHOW); modelDlg.BringWindowToTop(); while (modelDlg.Waiting()) { } return &modelDlg; } CPreviewDlg* CEntityDlg::ShowParticleChooser() { static CPreviewDlg modelDlg; modelDlg.SetMode(CPreviewDlg::PARTICLES); modelDlg.SetModal(); if (modelDlg.GetSafeHwnd() == NULL) { modelDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW)); } modelDlg.ShowWindow(SW_SHOW); modelDlg.BringWindowToTop(); while (modelDlg.Waiting()) { } return &modelDlg; } CPreviewDlg* CEntityDlg::ShowSkinChooser(entity_t* ent) { static CPreviewDlg modelDlg; modelDlg.SetMode(CPreviewDlg::SKINS); modelDlg.SetModal(); if (modelDlg.GetSafeHwnd() == NULL) { modelDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW)); } modelDlg.RebuildTree((ent) ? ent->epairs.GetString("model") : ""); modelDlg.ShowWindow(SW_SHOW); modelDlg.BringWindowToTop(); while (modelDlg.Waiting()) { } return &modelDlg; } CPreviewDlg* CEntityDlg::ShowGuiChooser() { static CPreviewDlg guiDlg; guiDlg.SetMode(CPreviewDlg::GUIS); guiDlg.SetModal(); if (guiDlg.GetSafeHwnd() == NULL) { guiDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW)); } guiDlg.ShowWindow(SW_SHOW); guiDlg.BringWindowToTop(); while (guiDlg.Waiting()) { } return &guiDlg; } CPreviewDlg* CEntityDlg::ShowSoundChooser() { static CPreviewDlg soundDlg; soundDlg.SetMode(CPreviewDlg::SOUNDS); soundDlg.SetModal(); if (soundDlg.GetSafeHwnd() == NULL) { soundDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW)); } soundDlg.ShowWindow(SW_SHOW); while (soundDlg.Waiting()) { } return &soundDlg; } CPreviewDlg* CEntityDlg::ShowMaterialChooser() { static CPreviewDlg matDlg; matDlg.SetMode(CPreviewDlg::MATERIALS); matDlg.SetModal(); if (matDlg.GetSafeHwnd() == NULL) { matDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW)); } matDlg.ShowWindow(SW_SHOW); matDlg.BringWindowToTop(); while (matDlg.Waiting()) { } return &matDlg; } void CEntityDlg::AssignModel() { OnBnClickedButtonModel(); } void CEntityDlg::OnBnClickedButtonModel() { CPreviewDlg* dlg = ShowModelChooser(); if (dlg->returnCode == IDOK) { editKey.SetWindowText("model"); editVal.SetWindowText(dlg->mediaName); AddProp(); } } void CEntityDlg::OnBnClickedButtonSound() { CPreviewDlg* dlg = ShowSoundChooser(); if (dlg->returnCode == IDOK) { editKey.SetWindowText("s_shader"); editVal.SetWindowText(dlg->mediaName); AddProp(); } } void CEntityDlg::OnBnClickedButtonGui() { CPreviewDlg* dlg = ShowGuiChooser(); if (dlg->returnCode == IDOK) { editKey.SetWindowText("gui"); editVal.SetWindowText(dlg->mediaName); AddProp(); } } void CEntityDlg::OnBnClickedButtonParticle() { CPreviewDlg* dlg = ShowParticleChooser(); if (dlg->returnCode == IDOK) { editKey.SetWindowText("model"); editVal.SetWindowText(dlg->mediaName); AddProp(); } } void CEntityDlg::OnBnClickedButtonSkin() { CPreviewDlg* dlg = ShowSkinChooser(editEntity); if (dlg->returnCode == IDOK) { editKey.SetWindowText("skin"); editVal.SetWindowText(dlg->mediaName); AddProp(); } } void CEntityDlg::OnBnClickedButtonCurve() { CCurveDlg dlg; if (dlg.DoModal() == IDOK) { if (editEntity) { idStr str = "curve_" + dlg.strCurveType; editKey.SetWindowText(str); idVec3 org = editEntity->origin; str = "3 ( "; str += org.ToString(); org.x += 64; str += " "; str += org.ToString(); org.y += 64; str += " "; str += org.ToString(); str += " )"; editVal.SetWindowText(str); AddProp(); Entity_SetCurveData(editEntity); } } } void CEntityDlg::OnBnClickedButtonBrowse() { DelProp(); } void CEntityDlg::OnCbnDblclkComboClass() { } // -------------------------------------------------------------------------- // Entity creation // -------------------------------------------------------------------------- void CEntityDlg::CreateEntity() { entity_t* petNew; bool forceFixed = false; CXYWnd* pWnd = g_pParentWnd->ActiveXY(); if (pWnd) { CRect rctZ; pWnd->GetClientRect(rctZ); if (selected_brushes.next == &selected_brushes) { CreateEntityBrush(g_nSmartX, rctZ.Height() - 1 - g_nSmartY, pWnd); forceFixed = true; } } else { if (selected_brushes.next == &selected_brushes) { MessageBox("You must have a selected brush to create an entity", "info", 0); return; } } int index = comboClass.GetCurSel(); if (index == LB_ERR) { MessageBox("You must have a selected class to create an entity", "info", 0); return; } CString str; comboClass.GetLBText(index, str); if (!stricmp(str, "worldspawn")) { MessageBox("Can't create an entity with worldspawn.", "info", 0); return; } eclass_t* pecNew = Eclass_ForName(str, false); if ((GetAsyncKeyState(VK_CONTROL) & 0x8000)) { extern void Brush_CopyList(brush_t * pFrom, brush_t * pTo); brush_t temp_brushes; temp_brushes.next = &temp_brushes; Brush_CopyList(&selected_brushes, &temp_brushes); Select_Deselect(); brush_t* pBrush = temp_brushes.next; while (pBrush != NULL && pBrush != &temp_brushes) { brush_t* pNext = pBrush->next; Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &selected_brushes); pBrush = pNext; petNew = Entity_Create(pecNew, forceFixed); Select_Deselect(); } } else if ((GetAsyncKeyState(VK_SHIFT) & 0x8000)) { Select_Ungroup(); petNew = Entity_Create(pecNew, forceFixed); } else { petNew = Entity_Create(pecNew, forceFixed); } if (petNew == NULL) { MessageBox("Failed to create entity.", "info", 0); return; } if (selected_brushes.next == &selected_brushes) { editEntity = world_entity; } else { editEntity = selected_brushes.next->owner; } SetKeyValPairs(); Select_Deselect(); Select_Brush(editEntity->brushes.onext); Sys_UpdateWindows(W_ALL); } void CEntityDlg::OnBnClickedButtonCreate() { CreateEntity(); } void CEntityDlg::OnLbnDblclkListkeyval() { CString Key, Value; idStr work; editKey.GetWindowText(Key); editVal.GetWindowText(Value); if (stricmp(Key, "script") == 0) { Key = Value; Value = "script/" + Key; if (fileSystem->ReadFile(Value, NULL, NULL) == -1) { sprintf(work, "// Script for %s\n// \n\nvoid main() {\n\n}\n\n", currentmap); fileSystem->WriteFile(Value, work.c_str(), work.Length(), "fs_devpath"); } work = fileSystem->RelativePathToOSPath(Value); WinExec(va("notepad.exe %s", work.c_str()), SW_SHOW); } } void CEntityDlg::OnLbnSelchangeListVars() { } void CEntityDlg::OnLbnDblclkListVars() { if (editEntity == NULL) { return; } int sel = listVars.GetCurSel(); if (sel == LB_ERR) { return; } CPropertyItem* pi = (CPropertyItem*)listVars.GetItemDataPtr(sel); if (pi) { if (editEntity->epairs.FindKey(pi->m_propName) == NULL) { editKey.SetWindowText(pi->m_propName); editVal.SetWindowText(""); editVal.SetFocus(); } } } void CEntityDlg::UpdateKeyVal(const char* key, const char* val) { if (editEntity) { editEntity->epairs.Set(key, val); SetKeyValPairs(); g_pParentWnd->GetCamera()->BuildEntityRenderState(editEntity, true); Entity_UpdateSoundEmitter(editEntity); } } // -------------------------------------------------------------------------- // Animation // -------------------------------------------------------------------------- void CEntityDlg::OnNMReleasedcaptureSlider1(NMHDR* pNMHDR, LRESULT* pResult) { if (!editEntity) { return; } UpdateFromAnimationFrame(); *pResult = 0; } void CEntityDlg::UpdateFromAnimationFrame(bool updateKeyValueDisplay) { if (!editEntity) { return; } int frame = slFrameSlider.GetPos(); editEntity->epairs.SetInt("frame", frame); SetDlgItemText(IDC_ENTITY_CURRENT_ANIM, va("%i", frame)); if (updateKeyValueDisplay) { SetKeyValPairs(); } g_pParentWnd->GetCamera()->BuildEntityRenderState(editEntity, true); Sys_UpdateWindows(W_ALL); } void CEntityDlg::OnCbnAnimationChange() { if (!editEntity) { return; } int sel = cbAnimations.GetCurSel(); CString animName; currentAnimation = NULL; int currFrame = 0; if (sel != -1) { cbAnimations.GetLBText(sel, animName); if (animName.GetLength() > 0) { currFrame = editEntity->epairs.GetInt("frame", "1"); editEntity->epairs.Set("anim", animName.GetBuffer(0)); SetKeyValPairs(false); currentAnimation = gameEdit->ANIM_GetAnimFromEntityDef(editEntity->eclass->name, animName.GetBuffer(0)); currentAnimationFrame = 0; if (currentAnimation) { slFrameSlider.SetRange(1, gameEdit->ANIM_GetNumFrames(currentAnimation), TRUE); slFrameSlider.SetPos(currFrame); currentAnimationFrame = currFrame; } Sys_UpdateWindows(W_ALL); } } } void CEntityDlg::OnBnClickedStartAnimation() { if (!editEntity) { return; } SetTimer(0, 1000 / 24, NULL); } void CEntityDlg::OnBnClickedStopAnimation() { KillTimer(0); } void CEntityDlg::OnTimer(UINT_PTR nIDEvent) { if (!editEntity) { OnBnClickedStopAnimation(); return; } if (currentAnimation) { int numFrames = gameEdit->ANIM_GetNumFrames(currentAnimation); if (numFrames <= 0) { return; } currentAnimationFrame = ((currentAnimationFrame++) % numFrames); editEntity->epairs.SetInt("frame", currentAnimationFrame); slFrameSlider.SetPos(currentAnimationFrame); UpdateFromAnimationFrame(false); Sys_UpdateWindows(W_CAMERA | W_XY); } } // -------------------------------------------------------------------------- // Curves // -------------------------------------------------------------------------- void CEntityDlg::AddCurvePoints() { if (editEntity == NULL || editEntity->curve == NULL) { return; } int c = editEntity->curve->GetNumValues(); idVec3 start; idVec3 end; if (c > 1) { start = editEntity->curve->GetValue(c - 2); end = editEntity->curve->GetValue(c - 1); idVec3 dir = end - start; dir.Normalize(); start = end + 64 * dir; } else if (c > 0) { start = editEntity->curve->GetValue(0); start.x += 64; start.y += 64; } else { start = editEntity->origin; } editEntity->curve->AddValue(editEntity->curve->GetNumValues() * 100, start); if (g_qeglobals.d_select_mode == sel_editpoint) { g_qeglobals.d_select_mode = sel_brush; EditCurvePoints(); } Sys_UpdateWindows(W_CAMERA | W_XY); } void CEntityDlg::EditCurvePoints() { if (editEntity == NULL || editEntity->curve == NULL) { return; } if (g_qeglobals.d_select_mode == sel_editpoint) { g_qeglobals.d_select_mode = sel_brush; return; } g_qeglobals.d_select_mode = sel_editpoint; g_qeglobals.d_numpoints = 0; g_qeglobals.d_num_move_points = 0; int c = editEntity->curve->GetNumValues(); for (int i = 0; i < c; i++) { if (g_qeglobals.d_numpoints < MAX_POINTS - 1) { g_qeglobals.d_points[g_qeglobals.d_numpoints++] = editEntity->curve->GetValue(i); } } Sys_UpdateWindows(W_XY | W_CAMERA); } void CEntityDlg::InsertCurvePoint() { if (editEntity == NULL || editEntity->curve == NULL) { return; } if (g_qeglobals.d_select_mode != sel_editpoint) { return; } if (g_qeglobals.d_num_move_points == 0) { return; } for (int i = 0; i < editEntity->curve->GetNumValues(); i++) { if (PointInMoveList(editEntity->curve->GetValueAddress(i)) >= 0) { if (i == editEntity->curve->GetNumValues() - 1) { AddCurvePoints(); } else { idCurve* newCurve = Entity_MakeCurve(editEntity); if (newCurve == NULL) { return; } for (int j = 0; j < editEntity->curve->GetNumValues(); j++) { if (j == i) { idVec3 start; idVec3 end; if (i > 0) { start = editEntity->curve->GetValue(i - 1); end = editEntity->curve->GetValue(i); start += end; start *= 0.5f; } else { start = editEntity->curve->GetValue(0); if (editEntity->curve->GetNumValues() > 1) { end = start; start = editEntity->curve->GetValue(1); idVec3 dir = end - start; dir.Normalize(); start = end + 64 * dir; } else { end = start; end.x += 64; end.y += 64; } } newCurve->AddValue(newCurve->GetNumValues() * 100, start); } newCurve->AddValue(newCurve->GetNumValues() * 100, editEntity->curve->GetValue(j)); } delete editEntity->curve; editEntity->curve = newCurve; } g_qeglobals.d_num_move_points = 0; break; } } UpdateEntityCurve(); Sys_UpdateWindows(W_XY | W_CAMERA); } void CEntityDlg::DeleteCurvePoint() { if (editEntity == NULL || editEntity->curve == NULL) { return; } if (g_qeglobals.d_select_mode != sel_editpoint) { return; } if (g_qeglobals.d_num_move_points == 0) { return; } for (int i = 0; i < editEntity->curve->GetNumValues(); i++) { if (PointInMoveList(editEntity->curve->GetValueAddress(i)) >= 0) { editEntity->curve->RemoveIndex(i); g_qeglobals.d_num_move_points = 0; break; } } UpdateEntityCurve(); Sys_UpdateWindows(W_XY | W_CAMERA); } void CEntityDlg::UpdateEntityCurve() { if (editEntity == NULL) { return; } Entity_UpdateCurveData(editEntity); if (g_qeglobals.d_select_mode == sel_editpoint) { g_qeglobals.d_numpoints = 0; int c = editEntity->curve->GetNumValues(); for (int i = 0; i < c; i++) { if (g_qeglobals.d_numpoints < MAX_POINTS - 1) { g_qeglobals.d_points[g_qeglobals.d_numpoints++] = editEntity->curve->GetValue(i); } } } Sys_UpdateWindows(W_ENTITY); } void CEntityDlg::SelectCurvePointByRay(const idVec3& org, const idVec3& dir, int buttons) { if (editEntity == NULL) { return; } int besti = -1; float scale = g_pParentWnd->ActiveXY()->Scale(); float bestd = 8 / scale / 2; for (int i = 0; i < g_qeglobals.d_numpoints; i++) { idVec3 temp = g_qeglobals.d_points[i] - org; float d = temp * dir; temp = org + d * dir; temp = g_qeglobals.d_points[i] - temp; d = temp.Length(); if (d <= bestd) { bestd = d; besti = i; } } if (besti == -1) { return; } g_qeglobals.d_num_move_points = 0; assert(besti < editEntity->curve->GetNumValues()); g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = editEntity->curve->GetValueAddress(besti); }