1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 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.
23 
24 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.
25 
26 ===========================================================================
27 */
28 
29 #include "tools/edit_gui_common.h"
30 
31 
32 #include "qe3.h"
33 #include "Radiant.h"
34 #include "GLWidget.h"
35 #include "PropertyList.h"
36 #include "entitydlg.h"
37 #include "PreviewDlg.h"
38 #include "CurveDlg.h"
39 
40 #include "../../renderer/model_local.h"		// for idRenderModelPrt
41 
42 void	Select_Ungroup();
43 
44 // CEntityDlg dialog
45 
IMPLEMENT_DYNAMIC(CEntityDlg,CDialog)46 IMPLEMENT_DYNAMIC(CEntityDlg, CDialog)
47 CEntityDlg::CEntityDlg(CWnd* pParent /*=NULL*/)
48 	: CDialog(CEntityDlg::IDD, pParent)
49 {
50 	editEntity = NULL;
51 	multipleEntities = false;
52 	currentAnimation = NULL;
53 }
54 
~CEntityDlg()55 CEntityDlg::~CEntityDlg()
56 {
57 }
58 
DoDataExchange(CDataExchange * pDX)59 void CEntityDlg::DoDataExchange(CDataExchange* pDX)
60 {
61 	CDialog::DoDataExchange(pDX);
62 	DDX_Control(pDX, IDC_LIST_KEYVAL, listKeyVal);
63 	DDX_Control(pDX, IDC_COMBO_CLASS, comboClass);
64 	DDX_Control(pDX, IDC_EDIT_KEY, editKey);
65 	DDX_Control(pDX, IDC_EDIT_VAL, editVal);
66 	DDX_Control(pDX, IDC_STATIC_TITLE, staticTitle);
67 	DDX_Control(pDX, IDC_STATIC_KEY, staticKey);
68 	DDX_Control(pDX, IDC_STATIC_VAL, staticVal);
69 	DDX_Control(pDX, IDC_BUTTON_BROWSE, btnBrowse);
70 	DDX_Control(pDX, IDC_E_135, btn135);
71 	DDX_Control(pDX, IDC_E_90, btn90);
72 	DDX_Control(pDX, IDC_E_45, btn45);
73 	DDX_Control(pDX, IDC_E_180, btn180);
74 	DDX_Control(pDX, IDC_E_0, btn360);
75 	DDX_Control(pDX, IDC_E_225, btn225);
76 	DDX_Control(pDX, IDC_E_270, btn270);
77 	DDX_Control(pDX, IDC_E_315, btn315);
78 	DDX_Control(pDX, IDC_E_UP, btnUp);
79 	DDX_Control(pDX, IDC_E_DOWN, btnDown);
80 	DDX_Control(pDX, IDC_BUTTON_MODEL, btnModel);
81 	DDX_Control(pDX, IDC_BUTTON_SOUND, btnSound);
82 	DDX_Control(pDX, IDC_BUTTON_GUI, btnGui);
83 	DDX_Control(pDX, IDC_BUTTON_PARTICLE, btnParticle);
84 	DDX_Control(pDX, IDC_BUTTON_SKIN, btnSkin);
85 	DDX_Control(pDX, IDC_BUTTON_CURVE, btnCurve);
86 	DDX_Control(pDX, IDC_BUTTON_CREATE, btnCreate);
87 	DDX_Control(pDX, IDC_LIST_VARS, listVars);
88 	DDX_Control(pDX, IDC_ENTITY_ANIMATIONS , cbAnimations);
89 	DDX_Control(pDX, IDC_ANIMATION_SLIDER , slFrameSlider);
90 	DDX_Control(pDX, IDC_ENTITY_CURRENT_ANIM , staticFrame);
91 	DDX_Control(pDX, IDC_ENTITY_PLAY_ANIM , btnPlayAnim);
92 	DDX_Control(pDX, IDC_ENTITY_STOP_ANIM , btnStopAnim);
93 }
94 
95 
96 
OnInitDialog()97 BOOL CEntityDlg::OnInitDialog()
98 {
99 	CDialog::OnInitDialog();
100 	listKeyVal.SetUpdateInspectors(true);
101 	listKeyVal.SetDivider(100);
102 	listVars.SetDivider(100);
103 	staticFrame.SetWindowText ( "0" );
104 
105 	return TRUE;  // return TRUE unless you set the focus to a control
106 	// EXCEPTION: OCX Property Pages should return FALSE
107 }
108 
OnToolHitTest(CPoint point,TOOLINFO * pTI) const109 int CEntityDlg::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
110 {
111 	// TODO: Add your specialized code here and/or call the base class
112 
113 	return CDialog::OnToolHitTest(point, pTI);
114 }
115 
116 
AddClassNames()117 void CEntityDlg::AddClassNames() {
118 	comboClass.ResetContent();
119 	for (eclass_t *pec = eclass; pec; pec = pec->next) {
120 		comboClass.AddString(pec->name);
121 	}
122 
123 }
124 
BEGIN_MESSAGE_MAP(CEntityDlg,CDialog)125 BEGIN_MESSAGE_MAP(CEntityDlg, CDialog)
126 	ON_WM_SIZE()
127 	ON_CBN_SELCHANGE(IDC_COMBO_CLASS, OnCbnSelchangeComboClass)
128 	ON_LBN_SELCHANGE(IDC_LIST_KEYVAL, OnLbnSelchangeListkeyval)
129 	ON_BN_CLICKED(IDC_E_135, OnBnClickedE135)
130 	ON_BN_CLICKED(IDC_E_90, OnBnClickedE90)
131 	ON_BN_CLICKED(IDC_E_45, OnBnClickedE45)
132 	ON_BN_CLICKED(IDC_E_180, OnBnClickedE180)
133 	ON_BN_CLICKED(IDC_E_0, OnBnClickedE0)
134 	ON_BN_CLICKED(IDC_E_225, OnBnClickedE225)
135 	ON_BN_CLICKED(IDC_E_270, OnBnClickedE270)
136 	ON_BN_CLICKED(IDC_E_315, OnBnClickedE315)
137 	ON_BN_CLICKED(IDC_E_UP, OnBnClickedEUp)
138 	ON_BN_CLICKED(IDC_E_DOWN, OnBnClickedEDown)
139 	ON_BN_CLICKED(IDC_BUTTON_MODEL, OnBnClickedButtonModel)
140 	ON_BN_CLICKED(IDC_BUTTON_SOUND, OnBnClickedButtonSound)
141 	ON_BN_CLICKED(IDC_BUTTON_GUI, OnBnClickedButtonGui)
142 	ON_BN_CLICKED(IDC_BUTTON_BROWSE, OnBnClickedButtonBrowse)
143 	ON_CBN_DBLCLK(IDC_COMBO_CLASS, OnCbnDblclkComboClass)
144 	ON_BN_CLICKED(IDC_BUTTON_CREATE, OnBnClickedButtonCreate)
145 	ON_LBN_DBLCLK(IDC_LIST_KEYVAL, OnLbnDblclkListkeyval)
146 	ON_LBN_SELCHANGE(IDC_LIST_VARS, OnLbnSelchangeListVars)
147 	ON_LBN_DBLCLK(IDC_LIST_VARS, OnLbnDblclkListVars)
148 	ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_ANIMATION_SLIDER, OnNMReleasedcaptureSlider1)
149 	ON_BN_CLICKED(IDC_BUTTON_PARTICLE, OnBnClickedButtonParticle)
150 	ON_BN_CLICKED(IDC_BUTTON_SKIN, OnBnClickedButtonSkin)
151 	ON_BN_CLICKED(IDC_BUTTON_CURVE, OnBnClickedButtonCurve)
152 	ON_CBN_SELCHANGE(IDC_ENTITY_ANIMATIONS, OnCbnAnimationChange)
153 	ON_BN_CLICKED(IDC_ENTITY_PLAY_ANIM , OnBnClickedStartAnimation)
154 	ON_BN_CLICKED(IDC_ENTITY_STOP_ANIM , OnBnClickedStopAnimation)
155 	ON_WM_TIMER()
156 	ON_BN_CLICKED(IDOK, OnOK)
157 END_MESSAGE_MAP()
158 
159 void CEntityDlg::OnSize(UINT nType, int cx, int cy)
160 {
161 	if (staticTitle.GetSafeHwnd() == NULL) {
162 		return;
163 	}
164 	CDialog::OnSize(nType, cx, cy);
165 	CRect rect, crect, crect2;
166 	GetClientRect(rect);
167 	int bh = (float)rect.Height() * (rect.Height() - 210) / rect.Height() / 2;
168 	staticTitle.GetWindowRect(crect);
169 	staticTitle.SetWindowPos(NULL, 4, 4, rect.Width() -8, crect.Height(), SWP_SHOWWINDOW);
170 	int top = 4 + crect.Height() + 4;
171 	comboClass.GetWindowRect(crect);
172 	btnCreate.GetWindowRect(crect2);
173 	comboClass.SetWindowPos(NULL, 4, top, rect.Width() - 12 - crect2.Width(), crect.Height(), SWP_SHOWWINDOW);
174 	btnCreate.SetWindowPos(NULL, rect.Width() - crect2.Width() - 4, top, crect2.Width(), crect.Height(), SWP_SHOWWINDOW);
175 	top += crect.Height() + 4;
176 	listVars.SetWindowPos(NULL, 4, top, rect.Width() - 8, bh, SWP_SHOWWINDOW);
177 	top += bh + 4;
178 	listKeyVal.SetWindowPos(NULL, 4, top, rect.Width() - 8, bh, SWP_SHOWWINDOW);
179 	top += bh + 4;
180 	staticKey.GetWindowRect(crect);
181 	staticKey.SetWindowPos(NULL, 4, top + 2, crect.Width(), crect.Height(), SWP_SHOWWINDOW);
182 	int left = 4 + crect.Width() + 4;
183 	int pad = crect.Width();
184 	editKey.GetWindowRect(crect);
185 	editKey.SetWindowPos(NULL, left, top, rect.Width() - 12 - pad, crect.Height(), SWP_SHOWWINDOW);
186 	top += crect.Height() + 4;
187 	staticVal.GetWindowRect(crect);
188 	staticVal.SetWindowPos(NULL, 4, top + 2, crect.Width(), crect.Height(), SWP_SHOWWINDOW);
189 	editVal.GetWindowRect(crect);
190 	bh = crect.Height();
191 	editVal.SetWindowPos(NULL, left, top, rect.Width() - 16 - bh - pad, crect.Height(), SWP_SHOWWINDOW);
192 	btnBrowse.SetWindowPos(NULL, rect.right - 4 - bh, top, bh, bh, SWP_SHOWWINDOW);
193 	top += crect.Height() + 8;
194 	btnModel.GetWindowRect(crect);
195 	btnModel.SetWindowPos(NULL, rect.right - 4 - crect.Width(), top + 8, crect.Width(), crect.Height(), SWP_SHOWWINDOW);
196 	btnSound.SetWindowPos(NULL, rect.right - 4 - crect.Width(), top + 12 + crect.Height(), crect.Width(), crect.Height(), SWP_SHOWWINDOW);
197 	btnGui.SetWindowPos(NULL, rect.right - 4 - crect.Width(), top + 16 + crect.Height() * 2, crect.Width(), crect.Height(), SWP_SHOWWINDOW);
198 	btnParticle.SetWindowPos(NULL, rect.right - 8 - (crect.Width() * 2), top + 16 + crect.Height() * 2, crect.Width(), crect.Height(), SWP_SHOWWINDOW);
199 	btnSkin.SetWindowPos( NULL, rect.right - 8 - ( crect.Width() * 2 ), top + 12 + crect.Height(), crect.Width(), crect.Height(), SWP_SHOWWINDOW );
200 	btnCurve.SetWindowPos( NULL, rect.right - 8 - ( crect.Width() * 2 ), top + 8, crect.Width(), crect.Height(), SWP_SHOWWINDOW );
201 
202 	//*************************************
203 	//animation controls
204 	//*************************************
205 	int rightAnimAreaBorder = rect.right - 75 - crect.Width (); /*models, etc button width*/
206 
207 	btnStopAnim.GetWindowRect(crect);
208 	btnStopAnim.SetWindowPos(NULL,rightAnimAreaBorder - crect.Width (),
209 		top + 8  ,crect.Width(),crect.Height(),SWP_SHOWWINDOW);
210 
211 	left = rightAnimAreaBorder - crect.Width() - 4;
212 	btnPlayAnim.GetWindowRect(crect);
213 	btnPlayAnim.SetWindowPos(NULL,left-crect.Width () ,top + 8 , crect.Width(),crect.Height(),SWP_SHOWWINDOW);
214 
215 	left -= crect.Width() + 4;
216 	cbAnimations.GetWindowRect(crect);
217 	cbAnimations.SetWindowPos(NULL,left-crect.Width (),top + 8  ,crect.Width(),crect.Height(),SWP_SHOWWINDOW);
218 
219 	staticFrame.GetWindowRect(crect);
220 	staticFrame.SetWindowPos(NULL,rightAnimAreaBorder - crect.Width (),
221 		top + 34  ,crect.Width(),crect.Height(),SWP_SHOWWINDOW);
222 
223 	left = rightAnimAreaBorder - crect.Width () - 4;
224 
225 	slFrameSlider.GetWindowRect(crect);
226 	slFrameSlider.SetWindowPos(NULL,left - crect.Width (),
227 	top + 32  ,crect.Width(),crect.Height(),SWP_SHOWWINDOW);
228 
229 	//*************************************
230 	//*************************************
231 
232 	btn135.GetWindowRect(crect);
233 	bh = crect.Width();
234 	btn135.SetWindowPos(NULL, 4, top, bh, bh, SWP_SHOWWINDOW);
235 	btn90.SetWindowPos(NULL, 4 + 2 + bh, top, bh, bh, SWP_SHOWWINDOW);
236 	btn45.SetWindowPos(NULL, 4 + 2 + 2 + bh * 2, top, bh, bh, SWP_SHOWWINDOW);
237 	btnUp.SetWindowPos(NULL, 4 + 2 + 2 + 6 + bh * 3, top + bh / 2,bh,bh, SWP_SHOWWINDOW);
238 	btnDown.SetWindowPos(NULL, 4 + 2 + 2 + 6 + bh *3, top + bh / 2 + bh + 2,bh,bh, SWP_SHOWWINDOW);
239 	top += bh + 2;
240 	btn180.SetWindowPos(NULL, 4, top, bh, bh, SWP_SHOWWINDOW);
241 	btn360.SetWindowPos(NULL, 4 + 2 + 2 + bh * 2, top, bh, bh, SWP_SHOWWINDOW);
242 	top += bh + 2;
243 	btn225.SetWindowPos(NULL, 4, top, bh, bh, SWP_SHOWWINDOW);
244 	btn270.SetWindowPos(NULL, 4 + 2 + bh, top, bh, bh, SWP_SHOWWINDOW);
245 	btn315.SetWindowPos(NULL, 4 + 2 + 2 + bh * 2, top, bh, bh, SWP_SHOWWINDOW);
246 	Invalidate();
247 }
248 
OnCbnSelchangeComboClass()249 void CEntityDlg::OnCbnSelchangeComboClass()
250 {
251 	int index = comboClass.GetCurSel();
252 	if (index != LB_ERR) {
253 		CString str;
254 		comboClass.GetLBText(index, str);
255 		eclass_t *ent = Eclass_ForName (str, false);
256 		if (ent) {
257 			if (selected_brushes.next == &selected_brushes) {
258 				editEntity = world_entity;
259 				multipleEntities = false;
260 			} else {
261 				editEntity = selected_brushes.next->owner;
262 				for (brush_t *b = selected_brushes.next->next; b != &selected_brushes; b = b->next) {
263 					if (b->owner != editEntity) {
264 						multipleEntities = true;
265 						break;
266 					}
267 				}
268 			}
269 			listVars.ResetContent();
270 			CPropertyItem *pi = new CPropertyItem("Usage:", ent->desc.c_str(), PIT_VAR, "");
271 			listVars.AddPropItem(pi);
272 
273 			int c = ent->vars.Num();
274 			for (int i = 0; i < c; i++) {
275 				pi = new CPropertyItem(ent->vars[i].name.c_str(), ent->vars[i].desc.c_str(), PIT_VAR, "");
276 				pi->SetData(ent->vars[i].type);
277 				listVars.AddPropItem(pi);
278 			}
279 			listVars.Invalidate();
280 			SetKeyValPairs();
281 		}
282 	}
283 }
284 
TranslateString(const char * buf)285 const char *CEntityDlg::TranslateString(const char *buf) {
286 	static char buf2[32768];
287 	int			i, l;
288 	char		*out;
289 
290 	l = strlen(buf);
291 	out = buf2;
292 	for (i = 0; i < l; i++) {
293 		if (buf[i] == '\n') {
294 			*out++ = '\r';
295 			*out++ = '\n';
296 		}
297 		else {
298 			*out++ = buf[i];
299 		}
300 	}
301 
302 	*out++ = 0;
303 
304 	return buf2;
305 
306 }
307 
UpdateFromListBox()308 void CEntityDlg::UpdateFromListBox() {
309 	if (editEntity == NULL) {
310 		return;
311 	}
312 	int c = listKeyVal.GetCount();
313 	for (int i = 0 ; i < c; i++) {
314 		CPropertyItem* pItem = (CPropertyItem*)listKeyVal.GetItemDataPtr(i);
315 		if (pItem) {
316 			editEntity->epairs.Set(pItem->m_propName, pItem->m_curValue);
317 		}
318 	}
319 	SetKeyValPairs();
320 }
321 
SetKeyValPairs(bool updateAnims)322 void CEntityDlg::SetKeyValPairs( bool updateAnims ) {
323 	if (editEntity) {
324 		listKeyVal.ResetContent();
325 		int c = editEntity->epairs.GetNumKeyVals();
326 		for (int i = 0; i < c; i++) {
327 			const idKeyValue *kv = editEntity->epairs.GetKeyVal(i);
328 			CPropertyItem *pi = new CPropertyItem(kv->GetKey().c_str(), kv->GetValue().c_str(), PIT_EDIT, "");
329 			bool found = false;
330 			int vc = editEntity->eclass->vars.Num();
331 			for (int j = 0; j < vc; j++) {
332 				if (editEntity->eclass->vars[j].name.Icmp(kv->GetKey()) == 0) {
333 					switch (editEntity->eclass->vars[j].type) {
334 						case EVAR_STRING :
335 						case EVAR_INT :
336 						case EVAR_FLOAT :
337 							pi->m_nItemType = PIT_EDIT;
338 							break;
339 						case EVAR_BOOL :
340 							pi->m_nItemType = PIT_EDIT;
341 							//pi->m_cmbItems = "0|1";
342 							break;
343 						case EVAR_COLOR :
344 							pi->m_nItemType = PIT_COLOR;
345 							break;
346 						case EVAR_MATERIAL :
347 							pi->m_nItemType = PIT_MATERIAL;
348 							break;
349 						case EVAR_MODEL :
350 							pi->m_nItemType = PIT_MODEL;
351 							break;
352 						case EVAR_GUI :
353 							pi->m_nItemType = PIT_GUI;
354 							break;
355 						case EVAR_SOUND :
356 							pi->m_nItemType = PIT_SOUND;
357 							break;
358 					}
359 					found = true;
360 					break;
361 				}
362 			}
363 			if (!found) {
364 				if (kv->GetKey().Icmp("model") == 0) {
365 					pi->m_nItemType = PIT_MODEL;
366 				}
367 				if (kv->GetKey().Icmp("_color") == 0) {
368 					pi->m_nItemType = PIT_COLOR;
369 				}
370 				if (kv->GetKey().Icmp("gui") == 0) {
371 					pi->m_nItemType = PIT_GUI;
372 				}
373 				if (kv->GetKey().Icmp("gui2") == 0) {
374 					pi->m_nItemType = PIT_GUI;
375 				}
376 				if (kv->GetKey().Icmp("gui3") == 0) {
377 					pi->m_nItemType = PIT_GUI;
378 				}
379 				if (kv->GetKey().Icmp("s_shader") == 0) {
380 					pi->m_nItemType = PIT_SOUND;
381 				}
382 			}
383 			listKeyVal.AddPropItem(pi);
384 		}
385 
386 		if ( updateAnims ) {
387 			int i, num;
388 
389 			cbAnimations.ResetContent();
390 			num = gameEdit->ANIM_GetNumAnimsFromEntityDef( &editEntity->eclass->defArgs );
391 			for( i = 0; i < num; i++ ) {
392 				cbAnimations.AddString( gameEdit->ANIM_GetAnimNameFromEntityDef( &editEntity->eclass->defArgs, i ) );
393 			}
394 
395 			const idKeyValue* kv = editEntity->epairs.FindKey ( "anim" );
396 			if ( kv ) {
397 				int selIndex = cbAnimations.FindStringExact( 0 , kv->GetValue().c_str() );
398 				if ( selIndex != -1 ) {
399 					cbAnimations.SetCurSel( selIndex );
400 					OnCbnAnimationChange ();
401 				}
402 			}
403 		}
404 	}
405 }
406 
UpdateEntitySel(eclass_t * ent)407 void CEntityDlg::UpdateEntitySel(eclass_t *ent) {
408 	assert ( ent );
409 	assert ( ent->name );
410 	int index = comboClass.FindString(-1, ent->name);
411 	if (index != LB_ERR) {
412 		comboClass.SetCurSel(index);
413 		OnCbnSelchangeComboClass();
414 	}
415 }
416 
OnLbnSelchangeListkeyval()417 void CEntityDlg::OnLbnSelchangeListkeyval()
418 {
419 	int index = listKeyVal.GetCurSel();
420 	if (index != LB_ERR) {
421 		CString str;
422 		listKeyVal.GetText(index, str);
423 		int i;
424 		for (i = 0; str[i] != '\t' && str[i] != '\0'; i++) {
425 		}
426 
427 		idStr key = str.Left(i);
428 		while (str[i] == '\t' && str[i] != '\0') {
429 			i++;
430 		}
431 
432 		idStr val = str.Right(str.GetLength() - i);
433 
434 		editKey.SetWindowText(key);
435 		editVal.SetWindowText(val);
436 	}
437 }
438 
439 static int TabOrder[] = {
440 	IDC_COMBO_CLASS,
441 	IDC_BUTTON_CREATE,
442 	//IDC_EDIT_INFO,
443 	IDC_LIST_KEYVAL,
444 	IDC_EDIT_KEY,
445 	IDC_EDIT_VAL,
446 	IDC_BUTTON_BROWSE,
447 	IDC_E_135,
448 	IDC_E_90,
449 	IDC_E_45,
450 	IDC_E_180,
451 	IDC_E_0,
452 	IDC_E_225,
453 	IDC_E_270,
454 	IDC_E_315,
455 	IDC_E_UP,
456 	IDC_E_DOWN,
457 	IDC_BUTTON_MODEL,
458 	IDC_BUTTON_SOUND,
459 	IDC_BUTTON_GUI,
460 	IDC_ENTITY_ANIMATIONS
461 };
462 
463 int TabCount = sizeof(TabOrder) / sizeof(int);
464 
DelProp()465 void CEntityDlg::DelProp() {
466 	CString key;
467 
468 	if (editEntity == NULL) {
469 		return;
470 	}
471 
472 	editKey.GetWindowText(key);
473 	if (multipleEntities) {
474 		for (brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next) {
475 			DeleteKey(b->owner, key);
476 			Entity_UpdateCurveData( b->owner );
477 		}
478 	} else {
479 		DeleteKey(editEntity, key);
480 		Entity_UpdateCurveData( editEntity );
481 	}
482 
483 	// refresh the prop listbox
484 	SetKeyValPairs();
485 	Sys_UpdateWindows( W_ENTITY | W_XY | W_CAMERA );
486 }
487 
488 
PreTranslateMessage(MSG * pMsg)489 BOOL CEntityDlg::PreTranslateMessage(MSG* pMsg)
490 {
491 
492 	if (pMsg->hwnd == editVal.GetSafeHwnd()) {
493 		if (pMsg->message == WM_LBUTTONDOWN) {
494 			editVal.SetFocus();
495 			return TRUE;
496 		}
497 	}
498 
499 	if (pMsg->hwnd == editKey.GetSafeHwnd()) {
500 		if (pMsg->message == WM_LBUTTONDOWN) {
501 			editKey.SetFocus();
502 			return TRUE;
503 		}
504 	}
505 
506 	if (GetFocus() == &editVal || GetFocus() == &editKey) {
507 		if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN ) {
508 				AddProp();
509 				return TRUE;
510 		}
511 
512 	}
513 
514 	if (GetFocus() == listKeyVal.GetEditBox()) {
515 		if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN ) {
516 			listKeyVal.OnChangeEditBox();
517 			listKeyVal.OnSelchange();
518 			listKeyVal.OnKillfocusEditBox();
519 			AddProp();
520 			SetKeyValPairs();
521 			return TRUE;
522 		}
523 	}
524 
525 	if (GetFocus() == &listKeyVal) {
526 		if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_DELETE && editEntity) {
527 			DelProp();
528 			return TRUE;
529 		}
530 	}
531 
532 	if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) {
533 		if (pMsg->wParam == VK_ESCAPE) {
534 			g_pParentWnd->GetCamera()->SetFocus();
535 			Select_Deselect();
536 		}
537 		return TRUE;
538 	}
539 
540 	if ( pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN ) {
541 		// keeps ENTER from closing the dialog
542 		return TRUE;
543 	}
544 
545 	if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_TAB) {
546 		if (GetFocus()) {
547 			int id = GetFocus()->GetDlgCtrlID();
548 			for (int i = 0; i < TabCount; i++) {
549 				if (TabOrder[i] == id) {
550 					i++;
551 					if (i >= TabCount) {
552 						i = 0;
553 					}
554 					CWnd *next = GetDlgItem(TabOrder[i]);
555 					if (next) {
556 						next->SetFocus();
557 						if (TabOrder[i] == IDC_EDIT_VAL) {
558 							editVal.SetSel(0, -1);
559 						}
560 						return TRUE;
561 					}
562 				}
563 			}
564 		}
565 	}
566 
567 	if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RIGHT && pMsg->hwnd == slFrameSlider.GetSafeHwnd()) {
568 		int pos = slFrameSlider.GetPos() + 1;
569 		pos = (pos % slFrameSlider.GetRangeMax());
570 		slFrameSlider.SetPos ( pos );
571 		UpdateFromAnimationFrame ();
572 		return TRUE;
573 	}
574 
575 	if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_LEFT && pMsg->hwnd == slFrameSlider.GetSafeHwnd()) {
576 		int pos = slFrameSlider.GetPos() - 1;
577 
578 		if ( pos < 1 ) {
579 			pos = slFrameSlider.GetRangeMax();
580 		}
581 
582 		slFrameSlider.SetPos ( pos );
583 		UpdateFromAnimationFrame ();
584 		return TRUE;
585 	}
586 
587 	return CDialog::PreTranslateMessage(pMsg);
588 }
589 
590 
591 /*
592  =======================================================================================================================
593 	AddProp
594  =======================================================================================================================
595  */
AddProp()596 void CEntityDlg::AddProp() {
597 
598 	if (editEntity == NULL) {
599 		return;
600 	}
601 
602 	CString Key, Value;
603 	editKey.GetWindowText(Key);
604 	editVal.GetWindowText(Value);
605 
606 	bool isName = (stricmp(Key, "name") == 0);
607 	bool isModel = static_cast<bool>((stricmp(Key, "model") == 0 && Value.GetLength() > 0));
608 	bool isOrigin = ( idStr::Icmp( Key, "origin" ) == 0 );
609 
610 	if (multipleEntities) {
611 		brush_t *b;
612 		for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
613 			if (isName) {
614 				Entity_SetName(b->owner, Value);
615 			} else {
616 				if ( ! ( ( isModel || isOrigin ) && ( b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN ) ) ) {
617 					SetKeyValue(b->owner, Key, Value);
618 				}
619 			}
620 		}
621 	}
622 	else {
623 		if (isName) {
624 			Entity_SetName(editEntity, Value);
625 		} else {
626 			if ( ! ( ( isModel || isOrigin ) && ( editEntity->eclass->nShowFlags & ECLASS_WORLDSPAWN ) ) ) {
627 				SetKeyValue(editEntity, Key, Value);
628 			}
629 		}
630 
631 		if ( isModel && !( editEntity->eclass->nShowFlags & ECLASS_WORLDSPAWN ) ) {
632 			idBounds	bo;
633 			idVec3	mins, maxs;
634 
635 			selected_brushes.next->modelHandle = renderModelManager->FindModel( Value );
636 			if ( dynamic_cast<idRenderModelPrt*>( selected_brushes.next->modelHandle ) || dynamic_cast<idRenderModelLiquid*>( selected_brushes.next->modelHandle ) ) {
637 				bo.Zero();
638 				bo.ExpandSelf( 12.0f );
639 			} else {
640 				bo = selected_brushes.next->modelHandle->Bounds( NULL );
641 			}
642 
643 			VectorCopy(bo[0], mins);
644 			VectorCopy(bo[1], maxs);
645 			VectorAdd(mins, editEntity->origin, mins);
646 			VectorAdd(maxs, editEntity->origin, maxs);
647 			Brush_RebuildBrush(selected_brushes.next, mins, maxs, false);
648 			Brush_Build ( selected_brushes.next , false, false , false, true );
649 		}
650 	}
651 
652 	// refresh the prop listbox
653 	SetKeyValPairs();
654 	Sys_UpdateWindows(W_ALL);
655 
656 }
657 
AngleKey()658 const char *CEntityDlg::AngleKey() {
659 	if (editEntity == NULL) {
660 		return "";
661 	}
662 
663 	if (editEntity->eclass->nShowFlags & ECLASS_MOVER) {
664 		return "movedir";
665 	}
666 
667 	return "angle";
668 }
669 
670 
OnBnClickedE135()671 void CEntityDlg::OnBnClickedE135()
672 {
673 	if (editEntity == NULL) {
674 		return;
675 	}
676 	editKey.SetWindowText(AngleKey());
677 	editVal.SetWindowText("135");
678 	AddProp();
679 }
680 
OnBnClickedE90()681 void CEntityDlg::OnBnClickedE90()
682 {
683 	if (editEntity == NULL) {
684 		return;
685 	}
686 	editKey.SetWindowText(AngleKey());
687 	editVal.SetWindowText("90");
688 	AddProp();
689 }
690 
OnBnClickedE45()691 void CEntityDlg::OnBnClickedE45()
692 {
693 	if (editEntity == NULL) {
694 		return;
695 	}
696 	editKey.SetWindowText(AngleKey());
697 	editVal.SetWindowText("45");
698 	AddProp();
699 }
700 
OnBnClickedE180()701 void CEntityDlg::OnBnClickedE180()
702 {
703 	if (editEntity == NULL) {
704 		return;
705 	}
706 	editKey.SetWindowText(AngleKey());
707 	editVal.SetWindowText("180");
708 	AddProp();
709 }
710 
OnBnClickedE0()711 void CEntityDlg::OnBnClickedE0()
712 {
713 	if (editEntity == NULL) {
714 		return;
715 	}
716 	editKey.SetWindowText(AngleKey());
717 	editVal.SetWindowText("0");
718 	AddProp();
719 }
720 
OnBnClickedE225()721 void CEntityDlg::OnBnClickedE225()
722 {
723 	if (editEntity == NULL) {
724 		return;
725 	}
726 	editKey.SetWindowText(AngleKey());
727 	editVal.SetWindowText("225");
728 	AddProp();
729 }
730 
OnBnClickedE270()731 void CEntityDlg::OnBnClickedE270()
732 {
733 	if (editEntity == NULL) {
734 		return;
735 	}
736 	editKey.SetWindowText(AngleKey());
737 	editVal.SetWindowText("270");
738 	AddProp();
739 }
740 
OnBnClickedE315()741 void CEntityDlg::OnBnClickedE315()
742 {
743 	if (editEntity == NULL) {
744 		return;
745 	}
746 	editKey.SetWindowText(AngleKey());
747 	editVal.SetWindowText("315");
748 	AddProp();
749 }
750 
OnBnClickedEUp()751 void CEntityDlg::OnBnClickedEUp()
752 {
753 	if (editEntity == NULL) {
754 		return;
755 	}
756 	editKey.SetWindowText(AngleKey());
757 	editVal.SetWindowText("-1");
758 	AddProp();
759 }
760 
OnBnClickedEDown()761 void CEntityDlg::OnBnClickedEDown()
762 {
763 	if (editEntity == NULL) {
764 		return;
765 	}
766 	editKey.SetWindowText(AngleKey());
767 	editVal.SetWindowText("-2");
768 	AddProp();
769 }
770 
ShowModelChooser()771 CPreviewDlg *CEntityDlg::ShowModelChooser() {
772 	static CPreviewDlg modelDlg;
773 	modelDlg.SetMode(CPreviewDlg::MODELS);
774 	modelDlg.SetModal();
775 	if (modelDlg.GetSafeHwnd() == NULL) {
776 		modelDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW));
777 	}
778 	modelDlg.ShowWindow( SW_SHOW );
779 	modelDlg.BringWindowToTop();
780 	while (modelDlg.Waiting()) {
781 	}
782 	return &modelDlg;
783 }
784 
ShowParticleChooser()785 CPreviewDlg *CEntityDlg::ShowParticleChooser() {
786 	static CPreviewDlg modelDlg;
787 	modelDlg.SetMode(CPreviewDlg::PARTICLES);
788 	modelDlg.SetModal();
789 	if (modelDlg.GetSafeHwnd() == NULL) {
790 		modelDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW));
791 	}
792 	modelDlg.ShowWindow(SW_SHOW);
793 	modelDlg.BringWindowToTop();
794 	while (modelDlg.Waiting()) {
795 	}
796 	return &modelDlg;
797 }
798 
ShowSkinChooser(entity_t * ent)799 CPreviewDlg *CEntityDlg::ShowSkinChooser(entity_t *ent) {
800 	static CPreviewDlg modelDlg;
801 	modelDlg.SetMode(CPreviewDlg::SKINS);
802 	modelDlg.SetModal();
803 	if (modelDlg.GetSafeHwnd() == NULL) {
804 		modelDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW));
805 	}
806 	modelDlg.RebuildTree( ( ent ) ? ent->epairs.GetString( "model" ) : "" );
807 	modelDlg.ShowWindow(SW_SHOW);
808 	modelDlg.BringWindowToTop();
809 	while (modelDlg.Waiting()) {
810 	}
811 	return &modelDlg;
812 }
813 
ShowGuiChooser()814 CPreviewDlg *CEntityDlg::ShowGuiChooser() {
815 	static CPreviewDlg guiDlg;
816 	guiDlg.SetMode(CPreviewDlg::GUIS);
817 	guiDlg.SetModal();
818 	if (guiDlg.GetSafeHwnd() == NULL) {
819 		guiDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW));
820 	}
821 	guiDlg.ShowWindow(SW_SHOW);
822 	guiDlg.BringWindowToTop();
823 	while (guiDlg.Waiting()) {
824 	}
825 	return &guiDlg;
826 }
827 
ShowSoundChooser()828 CPreviewDlg *CEntityDlg::ShowSoundChooser() {
829 	static CPreviewDlg soundDlg;
830 	soundDlg.SetMode(CPreviewDlg::SOUNDS);
831 	soundDlg.SetModal();
832 	if (soundDlg.GetSafeHwnd() == NULL) {
833 		soundDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW));
834 	}
835 	soundDlg.ShowWindow(SW_SHOW);
836 	while (soundDlg.Waiting()) {
837 	}
838 	return &soundDlg;
839 }
840 
ShowMaterialChooser()841 CPreviewDlg *CEntityDlg::ShowMaterialChooser() {
842 	static CPreviewDlg matDlg;
843 	matDlg.SetMode(CPreviewDlg::MATERIALS);
844 	matDlg.SetModal();
845 	if (matDlg.GetSafeHwnd() == NULL) {
846 		matDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW));
847 	}
848 	matDlg.ShowWindow(SW_SHOW);
849 	matDlg.BringWindowToTop();
850 	while (matDlg.Waiting()) {
851 	}
852 	return &matDlg;
853 }
854 
AssignModel()855 void CEntityDlg::AssignModel ()
856 {
857 	OnBnClickedButtonModel();
858 }
OnBnClickedButtonModel()859 void CEntityDlg::OnBnClickedButtonModel() {
860 	CPreviewDlg *dlg = ShowModelChooser();
861 	if (dlg->returnCode == IDOK) {
862 		editKey.SetWindowText("model");
863 		editVal.SetWindowText(dlg->mediaName);
864 		AddProp();
865 	}
866 }
867 
OnBnClickedButtonSound()868 void CEntityDlg::OnBnClickedButtonSound() {
869 	CPreviewDlg *dlg = ShowSoundChooser();
870 	if (dlg->returnCode == IDOK) {
871 		editKey.SetWindowText("s_shader");
872 		editVal.SetWindowText(dlg->mediaName);
873 		AddProp();
874 	}
875 }
876 
OnBnClickedButtonGui()877 void CEntityDlg::OnBnClickedButtonGui() {
878 	CPreviewDlg *dlg = ShowGuiChooser();
879 	if (dlg->returnCode == IDOK) {
880 		editKey.SetWindowText("gui");
881 		editVal.SetWindowText(dlg->mediaName);
882 		AddProp();
883 	}
884 }
885 
OnBnClickedButtonParticle()886 void CEntityDlg::OnBnClickedButtonParticle() {
887 	CPreviewDlg *dlg = ShowParticleChooser();
888 	if (dlg->returnCode == IDOK) {
889 		editKey.SetWindowText("model");
890 		editVal.SetWindowText(dlg->mediaName);
891 		AddProp();
892 	}
893 }
894 
OnBnClickedButtonSkin()895 void CEntityDlg::OnBnClickedButtonSkin() {
896 	CPreviewDlg *dlg = ShowSkinChooser( editEntity );
897 	if (dlg->returnCode == IDOK) {
898 		editKey.SetWindowText("skin");
899 		editVal.SetWindowText(dlg->mediaName);
900 		AddProp();
901 	}
902 
903 }
904 
OnBnClickedButtonCurve()905 void CEntityDlg::OnBnClickedButtonCurve() {
906 	CCurveDlg dlg;
907 	if ( dlg.DoModal() == IDOK ) {
908 		if ( editEntity ) {
909 			idStr str = "curve_" + dlg.strCurveType;
910 			editKey.SetWindowText( str );
911 			idVec3 org = editEntity->origin;
912 			str = "3 ( ";
913 			str += org.ToString();
914 			org.x += 64;
915 			str += " ";
916 			str += org.ToString();
917 			org.y += 64;
918 			str += " ";
919 			str += org.ToString();
920 			str += " )";
921 			editVal.SetWindowText( str );
922 			AddProp();
923 			Entity_SetCurveData( editEntity );
924 		}
925 	}
926 }
927 
OnBnClickedButtonBrowse()928 void CEntityDlg::OnBnClickedButtonBrowse() {
929 	DelProp();
930 }
931 
OnCbnDblclkComboClass()932 void CEntityDlg::OnCbnDblclkComboClass()
933 {
934 	// TODO: Add your control notification handler code here
935 }
936 
937 //
938 // =======================================================================================================================
939 //    CreateEntity Creates a new entity based on the currently selected brush and entity type.
940 // =======================================================================================================================
941 //
CreateEntity()942 void CEntityDlg::CreateEntity() {
943 	entity_t	*petNew;
944 	bool		forceFixed = false;
945 
946 	// check to make sure we have a brush
947 	CXYWnd	*pWnd = g_pParentWnd->ActiveXY();
948 	if (pWnd) {
949 		CRect	rctZ;
950 		pWnd->GetClientRect(rctZ);
951 
952 		brush_t *pBrush;
953 		if (selected_brushes.next == &selected_brushes) {
954 			pBrush = CreateEntityBrush(g_nSmartX, rctZ.Height() - 1 - g_nSmartY, pWnd);
955 			forceFixed = true;
956 		}
957 	}
958 	else {
959 		if (selected_brushes.next == &selected_brushes) {
960 			MessageBox("You must have a selected brush to create an entity", "info", 0);
961 			return;
962 		}
963 	}
964 
965 	int index = comboClass.GetCurSel();
966 	if (index == LB_ERR) {
967 		MessageBox("You must have a selected class to create an entity", "info", 0);
968 		return;
969 	}
970 
971 	CString str;
972 	comboClass.GetLBText(index, str);
973 
974 	if (!stricmp(str, "worldspawn")) {
975 		MessageBox("Can't create an entity with worldspawn.", "info", 0);
976 		return;
977 	}
978 
979 	eclass_t *pecNew = Eclass_ForName (str, false);
980 
981 	// create it
982 	if ((GetAsyncKeyState(VK_CONTROL) & 0x8000)) {
983 		// MAJOR hack for xian
984 extern void Brush_CopyList(brush_t *pFrom, brush_t *pTo);
985 		brush_t temp_brushes;
986 		temp_brushes.next = &temp_brushes;
987 		Brush_CopyList(&selected_brushes, &temp_brushes);
988 		Select_Deselect();
989 		brush_t *pBrush = temp_brushes.next;
990 		while (pBrush != NULL && pBrush != &temp_brushes) {
991 			brush_t *pNext = pBrush->next;
992 			Brush_RemoveFromList(pBrush);
993 			Brush_AddToList(pBrush, &selected_brushes);
994 			pBrush = pNext;
995 			petNew = Entity_Create(pecNew, forceFixed);
996 			Select_Deselect();
997 		}
998 	} else if ((GetAsyncKeyState(VK_SHIFT) & 0x8000)) {
999 		Select_Ungroup();
1000 		petNew = Entity_Create(pecNew, forceFixed);
1001 	} else {
1002 		petNew = Entity_Create(pecNew, forceFixed);
1003 	}
1004 
1005 	if (petNew == NULL) {
1006 		MessageBox("Failed to create entity.", "info", 0);
1007 		return;
1008 	}
1009 
1010 	if (selected_brushes.next == &selected_brushes) {
1011 		editEntity = world_entity;
1012 	}
1013 	else {
1014 		editEntity = selected_brushes.next->owner;
1015 	}
1016 
1017 	SetKeyValPairs();
1018 	Select_Deselect();
1019 	Select_Brush(editEntity->brushes.onext);
1020 	Sys_UpdateWindows(W_ALL);
1021 }
1022 
OnBnClickedButtonCreate()1023 void CEntityDlg::OnBnClickedButtonCreate()
1024 {
1025 	CreateEntity();
1026 }
1027 
OnLbnDblclkListkeyval()1028 void CEntityDlg::OnLbnDblclkListkeyval()
1029 {
1030 	CString Key, Value;
1031 	idStr work;
1032 	editKey.GetWindowText( Key );
1033 	editVal.GetWindowText( Value );
1034 	if ( stricmp( Key, "script" ) == 0 ) {
1035 		Key = Value;
1036 		Value = "script/" + Key;
1037 		if ( fileSystem->ReadFile( Value, NULL, NULL ) == -1) {
1038 			sprintf( work, "// Script for %s\n// \n\nvoid main() {\n\n}\n\n", currentmap );
1039 			fileSystem->WriteFile( Value, work.c_str(), work.Length(), "fs_devpath" );
1040 		}
1041 		work = fileSystem->RelativePathToOSPath( Value );
1042 		WinExec( va( "notepad.exe %s", work.c_str() ), SW_SHOW );
1043 	}
1044 }
1045 
OnLbnSelchangeListVars()1046 void CEntityDlg::OnLbnSelchangeListVars() {
1047 
1048 }
1049 
OnLbnDblclkListVars()1050 void CEntityDlg::OnLbnDblclkListVars() {
1051 	if (editEntity == NULL) {
1052 		return;
1053 	}
1054 	int sel = listVars.GetCurSel();
1055 	CPropertyItem *pi = (CPropertyItem*)listVars.GetItemDataPtr(sel);
1056 	if (pi) {
1057 		if (editEntity->epairs.FindKey(pi->m_propName) == NULL) {
1058 			editKey.SetWindowText(pi->m_propName);
1059 			editVal.SetWindowText("");
1060 			editVal.SetFocus();
1061 		}
1062 	}
1063 }
1064 
1065 
UpdateKeyVal(const char * key,const char * val)1066 void CEntityDlg::UpdateKeyVal(const char *key, const char *val) {
1067 	if (editEntity) {
1068 		editEntity->epairs.Set(key, val);
1069 		SetKeyValPairs();
1070 		g_pParentWnd->GetCamera()->BuildEntityRenderState(editEntity, true);
1071 		Entity_UpdateSoundEmitter(editEntity);
1072 	}
1073 }
1074 
1075 
OnNMReleasedcaptureSlider1(NMHDR * pNMHDR,LRESULT * pResult)1076 void CEntityDlg::OnNMReleasedcaptureSlider1(NMHDR *pNMHDR, LRESULT *pResult)
1077 {
1078 	if ( !editEntity )
1079 	{
1080 		return;
1081 	}
1082 
1083 	UpdateFromAnimationFrame ();
1084 
1085 	*pResult = 0;
1086 }
1087 
UpdateFromAnimationFrame(bool updateKeyValueDisplay)1088 void CEntityDlg::UpdateFromAnimationFrame ( bool updateKeyValueDisplay )
1089 {
1090 	int frame = slFrameSlider.GetPos ();
1091 	editEntity->epairs.SetInt( "frame" , frame );
1092 	SetDlgItemText ( IDC_ENTITY_CURRENT_ANIM , va ( "%i" , frame));
1093 	if ( updateKeyValueDisplay ) {
1094 		SetKeyValPairs();
1095 	}
1096 
1097 	g_pParentWnd->GetCamera ()->BuildEntityRenderState (editEntity , true );
1098 	Sys_UpdateWindows ( W_ALL );
1099 
1100 }
1101 
OnCbnAnimationChange()1102 void CEntityDlg::OnCbnAnimationChange ()
1103 {
1104 	if ( !editEntity )
1105 	{
1106 		return;
1107 	}
1108 
1109 	int sel = cbAnimations.GetCurSel();
1110 	CString animName;
1111 	currentAnimation = NULL;
1112 	int currFrame = 0;
1113 
1114 	if ( sel != -1 ) {
1115 		cbAnimations.GetLBText( sel , animName );
1116 		if ( animName.GetLength() > 0 ) {
1117 			//preserve the existing frame number
1118 			currFrame = editEntity->epairs.GetInt ( "frame" , "1" );
1119 
1120 			editEntity->epairs.Set("anim" , animName.GetBuffer(0));
1121 			SetKeyValPairs(false/*don't update anims combo box :)*/ );
1122 
1123 			//update the slider
1124 			currentAnimation = gameEdit->ANIM_GetAnimFromEntityDef(editEntity->eclass->name , animName.GetBuffer(0));
1125 			currentAnimationFrame = 0;
1126 
1127 			if ( currentAnimation ) {
1128 				slFrameSlider.SetRange( 1 , gameEdit->ANIM_GetNumFrames( currentAnimation ), TRUE );
1129 				slFrameSlider.SetPos( currFrame );
1130 				currentAnimationFrame = currFrame;
1131 			}
1132 
1133 			Sys_UpdateWindows(W_ALL);
1134 		}
1135 	}
1136 }
1137 
OnBnClickedStartAnimation()1138 void CEntityDlg::OnBnClickedStartAnimation()
1139 {
1140 	if (!editEntity) {
1141 		return;
1142 	}
1143 	SetTimer ( 0 , 1000/24 , NULL );
1144 }
1145 
OnBnClickedStopAnimation()1146 void CEntityDlg::OnBnClickedStopAnimation()
1147 {
1148 	KillTimer ( 0 );
1149 }
1150 
OnTimer(UINT nIDEvent)1151 void CEntityDlg::OnTimer(UINT nIDEvent)
1152 {
1153 	if ( !editEntity ) {
1154 		OnBnClickedStopAnimation ();
1155 		return;
1156 	}
1157 
1158 	if ( currentAnimation ) {
1159 		currentAnimationFrame = ( (currentAnimationFrame++) % gameEdit->ANIM_GetNumFrames( currentAnimation ) );
1160 		editEntity->epairs.SetInt ( "frame" , currentAnimationFrame );
1161 		slFrameSlider.SetPos ( currentAnimationFrame );
1162 		UpdateFromAnimationFrame (false/*don't update key/value display*/);
1163 
1164 		Sys_UpdateWindows ( W_CAMERA | W_XY );
1165 	}
1166 }
1167 
AddCurvePoints()1168 void CEntityDlg::AddCurvePoints() {
1169 	if ( editEntity == NULL || editEntity->curve == NULL ) {
1170 		return;
1171 	}
1172 
1173 	// add one point 64 units from the direction of the two points int he curve
1174 	int c = editEntity->curve->GetNumValues();
1175 	idVec3 start;
1176 	idVec3 end;
1177 	if ( c > 1 ) {
1178 		start = editEntity->curve->GetValue( c - 2 );
1179 		end = editEntity->curve->GetValue( c - 1 );
1180 		idVec3 dir = end - start;
1181 		dir.Normalize();
1182 		start = end + 64 * dir;
1183 	} else  if ( c > 0 ) {
1184 		start = editEntity->curve->GetValue( 0 );
1185 		start.x += 64;
1186 		start.y += 64;
1187 	} else {
1188 		start = editEntity->origin;
1189 	}
1190 
1191 	editEntity->curve->AddValue( editEntity->curve->GetNumValues() * 100, start );
1192 
1193 	if ( g_qeglobals.d_select_mode == sel_editpoint ) {
1194 		g_qeglobals.d_select_mode = sel_brush;
1195 		EditCurvePoints();
1196 	}
1197 
1198 	Sys_UpdateWindows( W_CAMERA | W_XY );
1199 
1200 }
1201 
EditCurvePoints()1202 void CEntityDlg::EditCurvePoints() {
1203 
1204 	if ( editEntity == NULL || editEntity->curve == NULL ) {
1205 		return;
1206 	}
1207 
1208 	if ( g_qeglobals.d_select_mode == sel_editpoint ) {
1209 		g_qeglobals.d_select_mode = sel_brush;
1210 		return;
1211 	}
1212 
1213 	g_qeglobals.d_select_mode = sel_editpoint;
1214 
1215 	g_qeglobals.d_numpoints = 0;
1216 	g_qeglobals.d_num_move_points = 0;
1217 	int c = editEntity->curve->GetNumValues();
1218 	for ( int i = 0; i < c; i++ ) {
1219 		if ( g_qeglobals.d_numpoints < MAX_POINTS - 1 ) {
1220 			g_qeglobals.d_points[g_qeglobals.d_numpoints++] = editEntity->curve->GetValue( i );
1221 		}
1222 	}
1223 	Sys_UpdateWindows( W_XY | W_CAMERA );
1224 
1225 }
1226 
InsertCurvePoint()1227 void CEntityDlg::InsertCurvePoint() {
1228 	if ( editEntity == NULL || editEntity->curve == NULL ) {
1229 		return;
1230 	}
1231 
1232 	if ( g_qeglobals.d_select_mode != sel_editpoint ) {
1233 		return;
1234 	}
1235 
1236 	if ( g_qeglobals.d_num_move_points == 0 ) {
1237 		return;
1238 	}
1239 
1240 	for ( int i = 0; i < editEntity->curve->GetNumValues(); i++ ) {
1241 		if ( PointInMoveList( editEntity->curve->GetValueAddress( i ) ) >= 0 ) {
1242 			if ( i == editEntity->curve->GetNumValues() - 1 ) {
1243 				// just do an add
1244 				AddCurvePoints();
1245 			} else {
1246 				idCurve<idVec3> *newCurve = Entity_MakeCurve( editEntity );
1247 
1248 				if ( newCurve == NULL ) {
1249 					return;
1250 				}
1251 
1252 				for ( int j = 0; j < editEntity->curve->GetNumValues(); j++ ) {
1253 					if ( j == i ) {
1254 						idVec3 start;
1255 						idVec3 end;
1256 						if ( i > 0 ) {
1257 							start = editEntity->curve->GetValue( i - 1 );
1258 							end = editEntity->curve->GetValue( i );
1259 							start += end;
1260 							start *= 0.5f;
1261 						} else {
1262 							start = editEntity->curve->GetValue( 0 );
1263 							if ( editEntity->curve->GetNumValues() > 1 ) {
1264 								end = start;
1265 								start = editEntity->curve->GetValue ( 1 );
1266 								idVec3 dir = end - start;
1267 								dir.Normalize();
1268 								start = end + 64 * dir;
1269 							} else {
1270 								end = start;
1271 								end.x += 64;
1272 								end.y += 64;
1273 							}
1274 						}
1275 						newCurve->AddValue( newCurve->GetNumValues() * 100, start );
1276 					}
1277 					newCurve->AddValue( newCurve->GetNumValues() * 100, editEntity->curve->GetValue( j ) );
1278 				}
1279 				delete editEntity->curve;
1280 				editEntity->curve = newCurve;
1281 			}
1282 			g_qeglobals.d_num_move_points = 0;
1283 			break;
1284 		}
1285 	}
1286 	UpdateEntityCurve();
1287 
1288 	Sys_UpdateWindows( W_XY | W_CAMERA );
1289 
1290 }
1291 
DeleteCurvePoint()1292 void CEntityDlg::DeleteCurvePoint() {
1293 
1294 	if ( editEntity == NULL || editEntity->curve == NULL ) {
1295 		return;
1296 	}
1297 
1298 	if ( g_qeglobals.d_select_mode != sel_editpoint ) {
1299 		return;
1300 	}
1301 
1302 
1303 	if ( g_qeglobals.d_num_move_points == 0 ) {
1304 		return;
1305 	}
1306 
1307 	for ( int i = 0; i < editEntity->curve->GetNumValues(); i++ ) {
1308 		if ( PointInMoveList( editEntity->curve->GetValueAddress( i ) ) >= 0 ) {
1309 			editEntity->curve->RemoveIndex( i );
1310 			g_qeglobals.d_num_move_points = 0;
1311 			break;
1312 		}
1313 	}
1314 	UpdateEntityCurve();
1315 
1316 	Sys_UpdateWindows( W_XY | W_CAMERA );
1317 
1318 }
1319 
1320 
UpdateEntityCurve()1321 void CEntityDlg::UpdateEntityCurve() {
1322 
1323 	if ( editEntity == NULL ) {
1324 		return;
1325 	}
1326 
1327 	Entity_UpdateCurveData( editEntity );
1328 
1329 	if ( g_qeglobals.d_select_mode == sel_editpoint ) {
1330 		g_qeglobals.d_numpoints = 0;
1331 		int c = editEntity->curve->GetNumValues();
1332 		for ( int i = 0; i < c; i++ ) {
1333 			if ( g_qeglobals.d_numpoints < MAX_POINTS - 1 ) {
1334 				g_qeglobals.d_points[g_qeglobals.d_numpoints++] = editEntity->curve->GetValue( i );
1335 			}
1336 		}
1337 	}
1338 
1339 	Sys_UpdateWindows( W_ENTITY );
1340 }
1341 
1342 
SelectCurvePointByRay(const idVec3 & org,const idVec3 & dir,int buttons)1343 void CEntityDlg::SelectCurvePointByRay(const idVec3 &org, const idVec3 &dir, int buttons) {
1344 	int		i, besti;
1345 	float	d, bestd;
1346 	idVec3	temp;
1347 
1348 	if ( editEntity == NULL ) {
1349 		return;
1350 	}
1351 	// find the point closest to the ray
1352 	float scale = g_pParentWnd->ActiveXY()->Scale();
1353 	besti = -1;
1354 	bestd = 8 / scale / 2;
1355 	//bestd = 8;
1356 
1357 	for (i = 0; i < g_qeglobals.d_numpoints; i++) {
1358 		temp = g_qeglobals.d_points[i] - org;
1359 		d = temp * dir;
1360 		temp = org + d * dir;
1361 		temp = g_qeglobals.d_points[i] - temp;
1362 		d = temp.Length();
1363 		if ( d <= bestd ) {
1364 			bestd = d;
1365 			besti = i;
1366 		}
1367 	}
1368 
1369 	if (besti == -1) {
1370 		return;
1371 	}
1372 
1373 	g_qeglobals.d_num_move_points = 0;
1374 	assert ( besti < editEntity->curve->GetNumValues() );
1375 	g_qeglobals.d_move_points[ g_qeglobals.d_num_move_points++ ] = editEntity->curve->GetValueAddress( besti );
1376 }
1377