1 #include "pch.h"
2 #include "../ogre/common/Def_Str.h"
3 #include "../vdrift/dbl.h"
4 #include "Road.h"
5 
6 #include <OgreCamera.h>
7 #include <OgreTerrain.h>
8 #include <OgreSceneNode.h>
9 using namespace Ogre;
10 
11 
12 //  choose, selection
13 //--------------------------------------------------------------------------------------
ChoosePoint()14 void SplineEdit::ChoosePoint()
15 {
16 	iChosen = iSelPoint;
17 }
CopyNewPoint()18 void SplineEdit::CopyNewPoint()
19 {
20 	if (iChosen == -1)  return;
21 	newP = mP[iChosen];
22 }
23 
24 //  next
PrevPoint()25 void SplineEdit::PrevPoint()
26 {
27 	if (getNumPoints() != 0)
28 		iChosen = (iChosen-1 + getNumPoints()) % getNumPoints();
29 }
NextPoint()30 void SplineEdit::NextPoint()
31 {
32 	if (getNumPoints() != 0)
33 		iChosen = (iChosen+1) % getNumPoints();
34 }
35 
FirstPoint()36 void SplineEdit::FirstPoint()
37 {
38 	if (getNumPoints() != 0)
39 		iChosen = 0;
40 }
LastPoint()41 void SplineEdit::LastPoint()
42 {
43 	if (getNumPoints() != 0)
44 		iChosen = getNumPoints()-1;
45 }
46 
47 
48 //  mark need to rebuild geometry
Rebuild(bool full)49 void SplineEdit::Rebuild(bool full)
50 {
51 	rebuild = true;
52 	if (full)
53 		iDirtyId = -1;
54 	else
55 		iDirtyId = iChosen;
56 }
57 
58 
59 //  add/rem  select
SelAddPoint()60 void SplineEdit::SelAddPoint()
61 {
62 	int id = -1;
63 	if (iChosen   != -1)  id = iChosen;  else
64 	if (iSelPoint != -1)  id = iSelPoint;
65 	if (id != -1)
66 	{
67 		if (vSel.find(id) == vSel.end())
68 			vSel.insert(id);
69 		else
70 			vSel.erase(id);
71 	}
72 }
SelClear()73 void SplineEdit::SelClear()
74 {
75 	vSel.clear();
76 }
SelAll()77 void SplineEdit::SelAll()
78 {
79 	vSel.clear();
80 	for (size_t i=0; i < mP.size(); ++i)
81 		vSel.insert(i);
82 }
GetSelCnt()83 int SplineEdit::GetSelCnt()
84 {
85 	return vSel.size();
86 }
87 
88 
89 
90 //  Move point
91 ///-------------------------------------------------------------------------------------
Move1(int id,Vector3 relPos)92 void SplineEdit::Move1(int id, Vector3 relPos)
93 {
94 	Vector3 pos = getPos(id) + relPos;
95 	if (mP[id].onTer)
96 		pos.y = getTerH(pos) + g_Height;
97 	setPos(id, pos);
98 	vMarks[id].setPos(pos);  // upd marker
99 }
100 
Move(Vector3 relPos)101 void SplineEdit::Move(Vector3 relPos)
102 {
103 	if (!vSel.empty())  // move sel
104 	{	for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
105 			Move1(*it, relPos);
106 		bSelChng = true;
107 		return;
108 	}
109 	if (iChosen == -1)  {  // move one
110 		newP.pos.y += relPos.y;  return;  }
111 	else
112 	{	Move1(iChosen, relPos);
113 		Rebuild();	}
114 }
115 
116 //  Scale1 (for tools)
Scale1(int id,Real posMul,Real hMul)117 void SplineEdit::Scale1(int id, Real posMul, Real hMul)
118 {
119 	Vector3 pos = getPos(id);
120 	if (posMul != 0.f)
121 	{	pos.x *= posMul;  pos.z *= posMul;  }
122 	if (hMul != 0.f)
123 		pos.y *= hMul;
124 
125 	if (mP[id].onTer)
126 		pos.y = getTerH(pos) + g_Height;
127 	setPos(id, pos);
128 	vMarks[id].setPos(pos);  // upd marker
129 }
130 
131 
132 //  Update Points onTer
UpdPointsH()133 void SplineEdit::UpdPointsH()
134 {
135 	for (int id=0; id < getNumPoints(); ++id)
136 	{
137 		Vector3 pos = getPos(id);
138 		if (mP[id].onTer)
139 		{	pos.y = getTerH(pos) + g_Height;
140 			setPos(id, pos);
141 		}
142 		vMarks[id].setPos(pos);  // upd marker
143 	}
144 }
145 
getTerH(const Vector3 & p)146 Real SplineEdit::getTerH(const Vector3& p)
147 {
148 	return mTerrain ? mTerrain->getHeightAtWorldPosition(p.x, 0.f, p.z) : 0.f;
149 }
150 
151 
152 
153 ///  Edit Selected
154 ///-------------------------------------------------------------------------------------
155 
getPos0()156 Vector3 SplineEdit::getPos0()
157 {
158 	Vector3 pos0(0,0,0);
159 	if (iChosen == -1)  // geom center
160 	{
161 		for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
162 			pos0 += getPos(*it);
163 		pos0 /= Real(vSel.size());
164 	}
165 	else  // or chosen point
166 		pos0 = getPos(iChosen);
167 
168 	return pos0;
169 }
170 
171 //  Scale selected
ScaleSel(Real posMul)172 void SplineEdit::ScaleSel(Real posMul)
173 {
174 	Vector3 pos0(0,0,0);  // = getPos0() ?
175 	if (iChosen != -1)  // 0 or chosen point
176 		pos0 = getPos(iChosen);
177 
178 	for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
179 	{	int id = *it;
180 		Vector3 pos = (getPos(id) - pos0) * (1.f + posMul) + pos0;
181 		if (mP[id].onTer)
182 			pos.y = getTerH(pos) + g_Height;
183 		setPos(id, pos);
184 		vMarks[id].setPos(pos);  // upd marker
185 	}
186 }
187 
188 //  Rotate selected
RotateSel(Real relA,Vector3 axis,int addYawRoll)189 void SplineEdit::RotateSel(Real relA, Vector3 axis, int addYawRoll)
190 {
191 	if (vSel.empty())  return;
192 	Vector3 pos0 = getPos0();
193 
194 	Quaternion q;  q.FromAngleAxis(Degree(relA), axis);
195 	Matrix3 m;  q.ToRotationMatrix(m);
196 
197 	//  rotate 2d yaw around center
198 	for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
199 	{
200 		Vector3 pos = getPos(*it) - pos0;
201 		Vector3 npos = pos * m + pos0;
202 
203 		pos = npos;
204 		if (mP[*it].onTer)
205 			pos.y = getTerH(pos) + g_Height;
206 		setPos(*it, pos);
207 
208 		if (addYawRoll==1)  // todo: get from axis?
209 			mP[*it].mYaw -= relA;  // rot point yaw
210 		else if (addYawRoll==2)
211 			// todo: * mul by cos of yaw ?..
212 			mP[*it].mRoll -= relA;  // rot point roll
213 
214 		vMarks[*it].setPos(pos);
215 		//Move1(*it, npos);
216 	}
217 	bSelChng = true;
218 }
219 
220 //  Mirror selected
MirrorSel(bool alt)221 void SplineEdit::MirrorSel(bool alt)
222 {
223 	if (vSel.empty())  return;
224 
225 	std::vector<SplinePoint> mRev;
226 	for (std::set<int>::const_reverse_iterator it = vSel.rbegin(); it != vSel.rend(); ++it)
227 		mRev.push_back(mP[*it]);
228 
229 	int i = 0;
230 	for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it, ++i)
231 	{
232 		SplinePoint& p = mP[*it];
233 		p = mRev[i];
234 		p.mRoll = -p.mRoll;
235 		if (p.aType == AT_Manual)
236 		{	p.mYaw = p.mYaw+180.f;
237 			if (p.mYaw > 360.f)  p.mYaw -= 360.f;
238 		}
239 	}
240 	recalcTangents();
241 	Rebuild(true);
242 }
243 
244 
245 //  Edit  modify, controls +-
246 //--------------------------------------------------------------------------------------
247 
AddWidth(Real relW)248 void SplineEdit::AddWidth(Real relW)    ///  Width
249 {
250 	if (!vSel.empty()) {  // sel
251 		for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
252 			mP[*it].width += relW;
253 		bSelChng = true;	return;	}
254 
255 	if (iChosen == -1)  {	// one
256 		newP.width += relW;  return;  }
257 
258 	mP[iChosen].width  += relW;
259 
260 	Rebuild();
261 }
262 
AddYaw(Real relA,Real snapA,bool alt)263 void SplineEdit::AddYaw(Real relA, Real snapA, bool alt)    ///  Yaw
264 {
265 	if (!vSel.empty()) {  // rotate sel
266 		RotateSel(snapA==0.f ? relA : (relA > 0.f ? snapA : -snapA),
267 			// todo: get Z from camera
268 			alt ? Vector3::UNIT_Z : Vector3::UNIT_Y, alt ? 2 : 1);  return;  }
269 
270 	if (iChosen == -1)  {	newP.mYaw += relA;  return;  }
271 
272 	if (snapA == 0.f)	mP[iChosen].mYaw  += relA;
273 	else
274 	{	Real a = mP[iChosen].mYaw;  int i = a / snapA + (relA > 0.f ? 1 :-1);  mP[iChosen].mYaw = i * snapA;  }
275 
276 	Rebuild();
277 }
278 
AddRoll(Real relA,Real snapA,bool alt)279 void SplineEdit::AddRoll(Real relA, Real snapA, bool alt)   ///  Roll
280 {
281 	if (!vSel.empty()) {  // scale sel
282 		ScaleSel(relA * 0.02f);
283 		bSelChng = true;	return;  }
284 
285 	if (iChosen == -1)  {	newP.mRoll += relA;  return;  }
286 
287 	if (snapA == 0.f)	mP[iChosen].mRoll  += relA;
288 	else
289 	{	Real a = mP[iChosen].mRoll;  int i = a / snapA + (relA > 0.f ? 1 :-1);  mP[iChosen].mRoll = i * snapA;  }
290 
291 	Rebuild();
292 }
293 
AddPipe(Real relP)294 void SplineEdit::AddPipe(Real relP)    ///  Pipe
295 {
296 	if (!vSel.empty()) {  // sel
297 		for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
298 			mP[*it].pipe = std::max(0.f, std::min(1.f, mP[*it].pipe + relP));
299 		bSelChng = true;	return;  }
300 
301 	if (iChosen == -1)  {  // one
302 			newP.pipe = std::max(0.f, std::min(1.f, newP.pipe + relP));  return;  }
303 	mP[iChosen].pipe  = std::max(0.f, std::min(1.f, mP[iChosen].pipe + relP));
304 
305 	Rebuild();
306 }
307 
308 
309 //  toggle
310 
ToggleOnTerrain()311 void SplineEdit::ToggleOnTerrain()   ///  On Ter
312 {
313 	if (!vSel.empty()) {  // sel
314 		for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
315 			mP[*it].onTer = !mP[*it].onTer;
316 		bSelChng = true;	return;  }
317 
318 	if (iChosen == -1)  {  // one
319 			newP.onTer = !newP.onTer;  return;  }
320 	mP[iChosen].onTer  = !mP[iChosen].onTer;
321 
322 	if (mP[iChosen].onTer)
323 		Move(Vector3::ZERO);
324 }
325 
ToggleColumn()326 void SplineEdit::ToggleColumn()      ///  Column
327 {
328 	if (!vSel.empty()) {  // sel
329 		for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
330 			mP[*it].cols = 1-mP[*it].cols;
331 		bSelChng = true;	return;  }
332 
333 	if (iChosen == -1)  {  // one
334 			newP.cols = 1-newP.cols;  return;  }
335 
336 	mP[iChosen].cols  = 1-mP[iChosen].cols;
337 	Move(Vector3::ZERO);
338 }
339 
ToggleOnPipe(bool old)340 void SplineEdit::ToggleOnPipe(bool old)  ///  On Pipe  (old for stats only,  new also flips normal)
341 {
342 	#define onp(o)  old ? (o ? 0 : 1) : (o ? 0 : 2)
343 
344 	if (!vSel.empty()) {  // sel
345 		for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
346 			mP[*it].onPipe = onp(mP[*it].onPipe);
347 		bSelChng = true;	return;  }
348 
349 	if (iChosen == -1)  {  // one
350 			newP.onPipe = onp(newP.onPipe);  return;  }
351 
352 	mP[iChosen].onPipe  = onp(mP[iChosen].onPipe);
353 	Move(Vector3::ZERO);
354 }
355 
ToggleNotReal()356 void SplineEdit::ToggleNotReal()  ///  Not Real  (not drivable road)
357 {
358 	if (!vSel.empty()) {  // sel
359 		for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
360 			mP[*it].notReal = !mP[*it].notReal;
361 		return;  }
362 
363 	if (iChosen == -1)  {  // one
364 			newP.notReal = !newP.notReal;  return;  }
365 
366 	mP[iChosen].notReal = !mP[iChosen].notReal;
367 }
368 
ChgLoopType(int rel)369 void SplineEdit::ChgLoopType(int rel)   ///  Loop type,  (camera change on chk, pacenotes)
370 {
371 	if (!vSel.empty()) {  // sel
372 		for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
373 			mP[*it].loop = (LoopTypes+ mP[*it].loop + rel)%LoopTypes;
374 		return;  }
375 
376 	if (iChosen == -1)  {  // one
377 			newP.loop = (LoopTypes+ newP.loop + rel)%LoopTypes;  return;  }
378 
379 	mP[iChosen].loop  = (LoopTypes+ mP[iChosen].loop + rel)%LoopTypes;
380 }
381 
382 
ChgMtrId(int rel)383 void SplineEdit::ChgMtrId(int rel)   ///  Mtr Id
384 {
385 	if (!vSel.empty()) {  // sel
386 		for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
387 			mP[*it].idMtr = std::max(-1, std::min(MTRs-1, mP[*it].idMtr + rel));
388 		bSelChng = true;	return;  }
389 
390 	if (iChosen == -1)  {  // one
391 			newP.idMtr = std::max(-1, std::min(MTRs-1, newP.idMtr + rel));  return;  }
392 	mP[iChosen].idMtr  = std::max(-1, std::min(MTRs-1, mP[iChosen].idMtr + rel));
393 
394 	Move(Vector3::ZERO);
395 }
396 
ChgAngType(int rel)397 void SplineEdit::ChgAngType(int rel)   ///  Ang Type
398 {
399 	if (!vSel.empty()) {  // sel
400 		for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
401 			mP[*it].aType = (AngType)std::max(0, std::min(AT_ALL-1, mP[*it].aType + rel));
402 		bSelChng = true;	return;  }
403 
404 	if (iChosen == -1)  {  // one
405 			newP.aType = (AngType)std::max(0, std::min(AT_ALL-1, newP.aType + rel));  return;  }
406 	mP[iChosen].aType  = (AngType)std::max(0, std::min(AT_ALL-1, mP[iChosen].aType + rel));
407 
408 	Move(Vector3::ZERO);
409 }
410 
AngZero()411 void SplineEdit::AngZero()   ///  Angles set 0
412 {
413 	if (!vSel.empty()) {  // sel
414 		for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
415 		{	mP[*it].mYaw = 0;  mP[*it].mRoll = 0;	}
416 		bSelChng = true;	return;  }
417 
418 	if (iChosen == -1)  {  // one
419 			newP.mYaw = 0;  newP.mRoll = 0;  return;  }
420 	mP[iChosen].mYaw = 0;  mP[iChosen].mRoll = 0;
421 
422 	Move(Vector3::ZERO);
423 }
424 
425 
426 //---------------------------------------------------------------------------------------------------------------
427 
428 //  util
isPipe(int seg)429 bool SplineRoad::isPipe(int seg)
430 {
431 	int seg1 = (seg+1) % getNumPoints();
432 	return mP[seg].pipe > 0.f || mP[seg1].pipe > 0.f;
433 }
434 
435 //  info text only
getMtrStr(int seg)436 const String& SplineRoad::getMtrStr(int seg)
437 {
438 	static String sHid = "Hidden";
439 	if (seg < 0)  // new
440 	{
441 		int i = newP.idMtr;
442 		if (i==-1)  return sHid;
443 		return newP.pipe == 0.f ? sMtrRoad[i] : sMtrPipe[i];
444 	}
445 	int i = mP[seg].idMtr;
446 	if (i==-1)  return sHid;
447 	return !isPipe(seg) ? sMtrRoad[i] : sMtrPipe[i];
448 }
449 
SetMtrPipe(int i,String sMtr)450 void SplineRoad::SetMtrPipe(int i, String sMtr)
451 {
452 	sMtrPipe[i] = sMtr;  // check if glass in mtr name
453 	bMtrPipeGlass[i] = strstr(sMtr.c_str(), "lass") != 0;
454 }
455 
456 
457 ///  Add point
458 ///-------------------------------------------------------------------------------------
Insert(eIns ins)459 void SplineRoad::Insert(eIns ins)
460 {
461 	RoadSeg rs;  SplinePoint pt = newP;  // new
462 	pt.chk1st = false;  // clear 1st chk
463 
464 	if (pt.onTer)
465 		pt.pos.y = getTerH(pt.pos) + g_Height;
466 
467 	if (ins	== INS_Begin)
468 		iChosen = -1;
469 
470 	if (ins == INS_End)  // end
471 	{
472 		mP.push_back(pt);  //recalcTangents();
473 		vSegs.push_back(rs);
474 		iChosen = getNumPoints()-1;  //sel last
475 	}
476 	else if (iChosen == -1)  // begin  or none sel
477 	{
478 		mP.push_front(pt);
479 		vSegs.push_front(rs);  //recalcTangents();
480 	}
481 	else  // middle
482 	{
483 		mP.insert(mP.begin()+iChosen+1, pt);
484 		vSegs.insert(vSegs.begin()+iChosen+1, rs);
485 		if (ins == INS_Cur)  // INS_CurPre
486 			++iChosen;
487 	}
488 	recalcTangents();
489 
490 	AddMarker(pt.pos);
491 	if (ins	!= INS_End)
492 		UpdAllMarkers();/**/
493 	Rebuild(/*true*/);
494 }
495 
496 ///  Delete point
497 ///-------------------------------------------------------------------------------------
Delete()498 void SplineRoad::Delete()
499 {
500 	if (iChosen == -1)  return;
501 	bool last = (iChosen == getNumPoints()-1);
502 
503 	// remove from sel all ?.
504 	vSel.erase(getNumPoints()-1);
505 
506 	DestroySeg(iChosen);
507 	DelLastMarker();/**/
508 	lastNdChosen = 0;
509 
510 	if (last)	mP.pop_back();
511 	else		mP.erase(mP.begin() + iChosen);
512 	if (last)	vSegs.pop_back();
513 	else		vSegs.erase(vSegs.begin() + iChosen);
514 
515 	if (iChosen >= getNumPoints())
516 		iChosen = getNumPoints()-1;
517 	//iChosen = -1;  // cancel sel-
518 
519 	recalcTangents();
520 	UpdAllMarkers();
521 	Rebuild(/*true*/);
522 }
523 
524 
525 ///  selection copy, paste, delete
526 //--------------------------------------------------------------------------------------
527 
528 std::deque<SplinePoint> SplineBase::mPc;  // copy points
529 
CopySel()530 bool SplineRoad::CopySel()
531 {
532 	if (vSel.empty())  return false;
533 
534 	mPc.clear();
535 	for (std::set<int>::const_iterator it = vSel.begin(); it != vSel.end(); ++it)
536 		mPc.push_back(mP[*it]);
537 	return true;
538 }
539 
Paste(bool reverse)540 void SplineRoad::Paste(bool reverse)
541 {
542 	if (!bHitTer || iChosen==-1 || mPc.size()==0)  return;
543 
544 	Vector3 c(0,0,0);  // center of sel points
545 	for (int i=0; i < mPc.size(); ++i)
546 		c += mPc[i].pos;
547 	c *= 1.f / Real(mPc.size());
548 	c.y = 0.f;  //c xz only
549 
550 	vSel.clear();
551 	for (int i=0; i < mPc.size(); ++i)
552 	{
553 		newP = mPc[i];  // [!reverse ? i : mPc.size()-1-i];
554 		newP.pos += posHit - c;  // move center to hit pos
555 		Insert(INS_Cur/*INS_CurPre*/);
556 		vSel.insert(iChosen);  // select just inserted
557 	}
558 	if (reverse)  // rot 180
559 		RotateSel(180, Vector3::UNIT_Y, 1);
560 	Rebuild(true);
561 }
562 
DelSel()563 void SplineRoad::DelSel()
564 {
565 	if (vSel.empty())  return;
566 	for (std::set<int>::reverse_iterator it = vSel.rbegin(); it != vSel.rend(); ++it)
567 	{
568 		iChosen = *it;
569 		//Delete();
570 		bool last = (iChosen == getNumPoints()-1);
571 
572 		DestroySeg(iChosen);
573 		DelLastMarker();/**/
574 		lastNdChosen = 0;
575 
576 		if (last)	mP.pop_back();
577 		else		mP.erase(mP.begin() + iChosen);
578 		if (last)	vSegs.pop_back();
579 		else		vSegs.erase(vSegs.begin() + iChosen);
580 	}
581 	if (iChosen >= getNumPoints())
582 		iChosen = getNumPoints()-1;
583 	vSel.clear();
584 
585 	recalcTangents();
586 	UpdAllMarkers();
587 	Rebuild(true);
588 }
589 
590 
591 ///  Pick marker
592 //---------------------------------------------------------------------------------------------------------------
Pick(Camera * mCamera,Real mx,Real my,bool bRay,bool bAddH,bool bHide)593 void SplineRoad::Pick(Camera* mCamera, Real mx, Real my,  bool bRay, bool bAddH, bool bHide)
594 {
595 	iSelPoint = -1;
596 	//if (vMarkNodes.size() != getNumPoints())
597 	//	return;  // assert
598 
599 	Ray ray = mCamera->getCameraToViewportRay(mx,my);  // 0..1
600 	const Vector3& pos = mCamera->getDerivedPosition(), dir = ray.getDirection();
601 	const Plane& pl = mCamera->getFrustumPlane(FRUSTUM_PLANE_NEAR);
602 	Real plDist = FLT_MAX;
603 	const Real sphR = 2.4f;  //par
604 
605 	for (int i=0; i < (int)getNumPoints(); ++i)
606 	{
607 		// ray to sphere dist
608 		const Vector3& posSph = getPos(i);
609 		const Vector3 ps = pos - posSph;
610 		Vector3 crs = ps.crossProduct(dir);
611 		Real dist = crs.length() / dir.length();
612 		// dist to camera
613 		Real plD = pl.getDistance(posSph);
614 
615 		if (dist < sphR &&
616 			plD > 0 && plD < plDist)
617 		{
618 			plDist = plD;
619 			iSelPoint = i;
620 		}
621 	}
622 
623 	SelectMarker(bHide);
624 
625 	//  hide/show all markers
626 	int iHide = bHide ? 1 : 0;
627 	if (iHide != iOldHide)
628 	{	iOldHide = iHide;
629 		for (size_t i=0; i < vMarks.size(); ++i)
630 			vMarks[i].setVis(!bHide);
631 	}
632 
633 	//  ray terrain hit pos
634 	if (bRay && ndHit && mTerrain)
635 	{
636 		std::pair<bool, Vector3> p = mTerrain->rayIntersects(ray);
637 		bHitTer = p.first;  //ndHit->setVisible(bHitTer);
638 		posHit = p.second;
639 
640 		if (bHitTer)
641 		{
642 			Vector3 pos = posHit;
643 			//if (iChosen == -1)  // for new
644 			if (!newP.onTer && bAddH)
645 				pos.y = newP.pos.y;
646 			ndHit->setPosition(pos);
647 		}
648 	}
649 }
650