Anonymous Login
2018-12-16 10:25 UTC

View Issue Details Jump to Notes ]
IDProjectCategoryView StatusLast Update
0000931OpenClonkObjectspublic2017-10-25 05:52
ReporterPyrit 
Assigned ToZapper 
PrioritylowSeverityminorReproducibilityalways
StatusassignedResolutionopen 
PlatformPCOSWindows 7OS Version64 bit
Product Version 
Target Version9.0Fixed in Version 
Summary0000931: Buildings shake when being built
DescriptionWhen a building builds itself up, it jiggles up and down.
Steps To ReproduceBuild something
Additional InformationThis occured to me in CR, too.
It may have something to do with the position of the building not being displayed right. Maybe the enngine has difficulties to position half completed buildings right, since they don't have their full size?
TagsNo tags attached.
Attached Files
  • patch file icon c4shape-use-c4real.patch (25,659 bytes) 2015-10-29 20:47 -
     src/game/C4Game.cpp             |  5 +--
     src/gamescript/C4FindObject.cpp |  9 ++---
     src/lib/C4Real.h                |  8 ++--
     src/lib/C4Rect.cpp              | 20 ++++++----
     src/lib/C4Rect.h                | 60 +++++++++++++++++-------------
     src/object/C4DefGraphics.cpp    |  2 +-
     src/object/C4Movement.cpp       |  2 +-
     src/object/C4Object.cpp         | 12 +++---
     src/object/C4Object.h           | 10 ++---
     src/object/C4ObjectCom.cpp      |  4 +-
     src/object/C4Shape.cpp          | 82 +++++++++++++++++++++--------------------
     src/object/C4Shape.h            | 18 +++++----
     12 files changed, 125 insertions(+), 107 deletions(-)
    
    diff --git a/src/game/C4Game.cpp b/src/game/C4Game.cpp
    index 951d270..fa7829c 100644
    --- a/src/game/C4Game.cpp
    +++ b/src/game/C4Game.cpp
    @@ -1119,15 +1119,14 @@ C4Object* C4Game::CreateObjectConstruction(C4PropList * PropList,
     
     C4Object* C4Game::OverlapObject(int32_t tx, int32_t ty, int32_t wdt, int32_t hgt, int32_t Plane)
     {
    -	C4Rect rect1,rect2;
    -	rect1.x=tx; rect1.y=ty; rect1.Wdt=wdt; rect1.Hgt=hgt;
    +	C4Rect rect1(tx, ty, wdt, hgt);
     	C4LArea Area(&::Objects.Sectors, tx, ty, wdt, hgt); C4LSector *pSector;
     	for (C4ObjectList *pObjs = Area.FirstObjectShapes(&pSector); pSector; pObjs = Area.NextObjectShapes(pObjs, &pSector))
     		for (C4Object *cObj : *pObjs)
     			if (cObj->Status && !cObj->Contained)
     				if (cObj->GetPlane() == Plane)
     				{
    -					rect2=cObj->Shape; rect2.x+=cObj->GetX(); rect2.y+=cObj->GetY();
    +					C4Rect rect2 = cObj->Shape.GetRect(); rect2.x += cObj->GetX(); rect2.y += cObj->GetY();
     					if (rect1.Overlap(rect2)) return cObj;
     				}
     	return NULL;
    diff --git a/src/gamescript/C4FindObject.cpp b/src/gamescript/C4FindObject.cpp
    index 346fbbe..994c310 100644
    --- a/src/gamescript/C4FindObject.cpp
    +++ b/src/gamescript/C4FindObject.cpp
    @@ -648,19 +648,18 @@ bool C4FindObjectInRect::IsImpossible()
     
     bool C4FindObjectAtPoint::Check(C4Object *pObj)
     {
    -	return pObj->Shape.Contains(bounds.x - pObj->GetX(), bounds.y - pObj->GetY());
    +	return pObj->Shape.Contains(static_cast<C4Real>(bounds.x - pObj->GetX()), static_cast<C4Real>(bounds.y - pObj->GetY()));
     }
     
     bool C4FindObjectAtRect::Check(C4Object *pObj)
     {
    -	C4Rect rcShapeBounds = pObj->Shape;
    -	rcShapeBounds.x += pObj->GetX(); rcShapeBounds.y += pObj->GetY();
    -	return !!rcShapeBounds.Overlap(bounds);
    +	C4Rect position(fixtoi(pObj->Shape.x) + pObj->GetX(), fixtoi(pObj->Shape.y) + pObj->GetY(), fixtoi(pObj->Shape.Wdt), fixtoi(pObj->Shape.Hgt));
    +	return !!position.Overlap(bounds);
     }
     
     bool C4FindObjectOnLine::Check(C4Object *pObj)
     {
    -	return pObj->Shape.IntersectsLine(x - pObj->GetX(), y - pObj->GetY(), x2 - pObj->GetX(), y2 - pObj->GetY());
    +	return pObj->Shape.IntersectsLine(static_cast<C4Real>(x - pObj->GetX()), static_cast<C4Real>(y - pObj->GetY()), static_cast<C4Real>(x2 - pObj->GetX()), static_cast<C4Real>(y2 - pObj->GetY()));
     }
     
     bool C4FindObjectDistance::Check(C4Object *pObj)
    diff --git a/src/lib/C4Real.h b/src/lib/C4Real.h
    index 8f6ac55..f199a8f 100644
    --- a/src/lib/C4Real.h
    +++ b/src/lib/C4Real.h
    @@ -77,9 +77,7 @@ public:
     	inline C4Fixed () { }
     	inline C4Fixed (const C4Fixed &rCpy): val(rCpy.val) { }
     
    -	// Conversion must be done by the conversion routines itofix, fixtoi, ftofix and fixtof
    -	// in order to be backward compatible, so everything is private.
    -private:
    +	// Conversion constructors to allow standard casting.
     	explicit inline C4Fixed(int32_t iVal)
     			: val (iVal * FIXED_FPF)
     	{ }
    @@ -93,6 +91,7 @@ private:
     			: val(static_cast<int32_t>(fVal * float(FIXED_FPF)))
     	{ }
     
    +private:
     	// round to int
     	int32_t to_int() const
     	{
    @@ -103,6 +102,9 @@ private:
     		r >>= 1;
     		return r;
     	}
    +
    +	//operator int() const { return this->to_int(); }
    +
     	int32_t to_int(int32_t prec) const
     	{
     		int64_t r = val;
    diff --git a/src/lib/C4Rect.cpp b/src/lib/C4Rect.cpp
    index c65fbdf..f19784b 100644
    --- a/src/lib/C4Rect.cpp
    +++ b/src/lib/C4Rect.cpp
    @@ -23,12 +23,16 @@
     #include "StdCompiler.h"
     #include "StdAdaptors.h"
     
    -void C4Rect::Default()
    +// Declare required instantiation of template in order to be able to define the template functions in the cpp file.
    +template class C4AbstractRect<C4Real>;
    +template class C4AbstractRect<int32_t>;
    +
    +template <typename T> void C4AbstractRect<T>::Default()
     {
     	x=y=Wdt=Hgt=0;
     }
     
    -void C4Rect::CompileFunc(StdCompiler *pComp)
    +template <typename T> void C4AbstractRect<T>::CompileFunc(StdCompiler *pComp)
     {
     	pComp->Value(mkDefaultAdapt(x, 0)); pComp->Separator();
     	pComp->Value(mkDefaultAdapt(y, 0)); pComp->Separator();
    @@ -83,12 +87,12 @@ void C4TargetRect::CompileFunc(StdCompiler *pComp)
     	pComp->Value(mkDefaultAdapt(ty,0));
     }
     
    -void C4Rect::Set(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt)
    +template <typename T> void C4AbstractRect<T>::Set(T iX, T iY, T iWdt, T iHgt)
     {
     	x=iX; y=iY; Wdt=iWdt; Hgt=iHgt;
     }
     
    -bool C4Rect::Overlap(C4Rect &rTarget)
    +template <typename T> bool C4AbstractRect<T>::Overlap(C4AbstractRect<T> &rTarget)
     {
     	if (x+Wdt<=rTarget.x) return false;
     	if (x>=rTarget.x+rTarget.Wdt) return false;
    @@ -97,7 +101,7 @@ bool C4Rect::Overlap(C4Rect &rTarget)
     	return true;
     }
     
    -void C4Rect::Intersect(const C4Rect &r2)
    +template <typename T> void C4AbstractRect<T>::Intersect(const C4AbstractRect<T> &r2)
     {
     	// Narrow bounds
     	if (r2.x > x)
    @@ -119,7 +123,7 @@ void C4Rect::Intersect(const C4Rect &r2)
     	if (Hgt < 0) Hgt = 0;
     }
     
    -bool C4Rect::IntersectsLine(int32_t iX, int32_t iY, int32_t iX2, int32_t iY2)
    +template <typename T> bool C4AbstractRect<T>::IntersectsLine(T iX, T iY, T iX2, T iY2)
     {
     	// Easy cases first
     	if (Contains(iX, iY)) return true;
    @@ -131,7 +135,7 @@ bool C4Rect::IntersectsLine(int32_t iX, int32_t iY, int32_t iX2, int32_t iY2)
     	// check some special cases
     	if (iX == iX2 || iY == iY2) return true;
     	// Check intersection left/right
    -	int32_t iXI, iYI;
    +	T iXI, iYI;
     	iXI = (iX < x ? x : x+Wdt);
     	iYI = iY + (iY2 - iY) * (iXI - iX) / (iX2 - iX);
     	if (iYI >= y && iYI < y+Hgt) return true;
    @@ -141,7 +145,7 @@ bool C4Rect::IntersectsLine(int32_t iX, int32_t iY, int32_t iX2, int32_t iY2)
     	return iXI >= x && iXI < x+Wdt;
     }
     
    -void C4Rect::Add(const C4Rect &r2)
    +template <typename T> void C4AbstractRect<T>::Add(const C4AbstractRect<T> &r2)
     {
     	// Null? Don't do anything
     	if (!r2.Wdt || !r2.Hgt) return;
    diff --git a/src/lib/C4Rect.h b/src/lib/C4Rect.h
    index 0738fa8..9a527b8 100644
    --- a/src/lib/C4Rect.h
    +++ b/src/lib/C4Rect.h
    @@ -26,55 +26,63 @@
     
     struct FLOAT_RECT { float left,right,top,bottom; };
     
    -class C4Rect
    +
    +
    +template <typename T> class C4AbstractRect
     {
     public:
    -	int32_t x,y,Wdt,Hgt;
    +	T x,y,Wdt,Hgt;
     public:
    -	void Set(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt);
    +	void Set(T iX, T iY, T iWdt, T iHgt);
     	void Default();
    -	bool Overlap(C4Rect &rTarget);
    -	void Intersect(const C4Rect &r2);
    -	void Add(const C4Rect &r2);
    -	bool operator ==(const C4Rect &r2) const { return !((x-r2.x) | (y-r2.y) | (Wdt-r2.Wdt) | (Hgt-r2.Hgt)); }
    -	bool operator !=(const C4Rect &r2) const { return 0 != ((x-r2.x) | (y-r2.y) | (Wdt-r2.Wdt) | (Hgt-r2.Hgt)); }
    +	bool Overlap(C4AbstractRect<T> &rTarget);
    +	void Intersect(const C4AbstractRect<T> &r2);
    +	void Add(const C4AbstractRect<T> &r2);
    +	bool operator ==(const C4AbstractRect<T> &r2) const { return !((x - r2.x) | (y - r2.y) | (Wdt - r2.Wdt) | (Hgt - r2.Hgt)); }
    +	bool operator !=(const C4AbstractRect<T> &r2) const { return 0 != ((x - r2.x) | (y - r2.y) | (Wdt - r2.Wdt) | (Hgt - r2.Hgt)); }
     
    -	bool Contains(int32_t iX, int32_t iY) const
    +	bool Contains(T iX, T iY) const
     	{ return iX>=x && iX<x+Wdt && iY>=y && iY<y+Hgt; }
    -	bool Contains(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt) const
    +	bool Contains(T iX, T iY, T iWdt, T iHgt) const
     	{ return iX>=x && iX+iWdt<x+Wdt && iY>=y && iY+iHgt<y+Hgt; }
    -	bool Contains(const C4Rect &rect) const
    +	bool Contains(const C4AbstractRect<T> &rect) const
     	{ return Contains(rect.x, rect.y, rect.Wdt, rect.Hgt); }
    -	bool IntersectsLine(int32_t iX, int32_t iY, int32_t iX2, int32_t iY2);
    +	bool IntersectsLine(T iX, T iY, T iX2, T iY2);
     
     	void Normalize()
     	{ if (Wdt < 0) { x+=Wdt+1; Wdt=-Wdt; } if (Hgt < 0) { y+=Hgt+1; Hgt=-Hgt; } }
     
    -	void Enlarge(int32_t iByX, int32_t iByY)
    +	void Enlarge(T iByX, T iByY)
     	{ x -= iByX; y -= iByY; Wdt += 2*iByX; Hgt += 2*iByY; }
    -	void Enlarge(int32_t iBy)
    +	void Enlarge(T iBy)
     	{ Enlarge(iBy, iBy); }
     
    -	int32_t GetMiddleX() const { return x+Wdt/2; }
    -	int32_t GetMiddleY() const { return y + Hgt / 2; }
    -	int32_t GetBottom() const { return y + Hgt; }
    -	int32_t GetTop() const { return y; }
    -	int32_t GetLeft() const { return x; }
    -	int32_t GetRight() const { return x + Wdt; }
    +	T GetMiddleX() const { return x+Wdt/2; }
    +	T GetMiddleY() const { return y + Hgt / 2; }
    +	T GetBottom() const { return y + Hgt; }
    +	T GetTop() const { return y; }
    +	T GetLeft() const { return x; }
    +	T GetRight() const { return x + Wdt; }
     
    -	C4Rect(int32_t tx, int32_t ty, int32_t twdt, int32_t thgt) // ctor
    +	C4AbstractRect(T tx, T ty, T twdt, T thgt) // ctor
     	{ x=tx; y=ty; Wdt=twdt; Hgt=thgt; }
    -	C4Rect() { } // default ctor; doesn't initialize
    -	C4Rect(const FLOAT_RECT &rcfOuter) // set to surround floating point rectangle
    +	C4AbstractRect() { } // default ctor; doesn't initialize
    +	C4AbstractRect(const FLOAT_RECT &rcfOuter) // set to surround floating point rectangle
     	{
    -		x=static_cast<int32_t>(rcfOuter.left); y=static_cast<int32_t>(rcfOuter.top);
    -		Wdt=static_cast<int32_t>(ceilf(rcfOuter.right)-floorf(rcfOuter.left));
    -		Hgt=static_cast<int32_t>(ceilf(rcfOuter.bottom)-floorf(rcfOuter.top));
    +		x=static_cast<T>(rcfOuter.left); y=static_cast<T>(rcfOuter.top);
    +		Wdt=static_cast<T>(ceilf(rcfOuter.right)-floorf(rcfOuter.left));
    +		Hgt=static_cast<T>(ceilf(rcfOuter.bottom)-floorf(rcfOuter.top));
     	}
     
     	void CompileFunc(StdCompiler *pComp);
     };
     
    +class C4Rect : public C4AbstractRect<int32_t>
    +{
    +public:
    +	using C4AbstractRect<int32_t>::C4AbstractRect;
    +};
    +
     class C4TargetRect: public C4Rect
     {
     public:
    diff --git a/src/object/C4DefGraphics.cpp b/src/object/C4DefGraphics.cpp
    index 001628c..859b3db 100644
    --- a/src/object/C4DefGraphics.cpp
    +++ b/src/object/C4DefGraphics.cpp
    @@ -1005,7 +1005,7 @@ void C4GraphicsOverlay::Draw(C4TargetFacet &cgo, C4Object *pForObj, int32_t iByP
     			if (C4ValueToMatrix(value, &matrix))
     				pDraw->SetMeshTransform(&matrix);
     
    -			pDraw->RenderMesh(*pMeshInstance, cgo.Surface, offX - pDef->Shape.Wdt/2.0, offY - pDef->Shape.Hgt/2.0, pDef->Shape.Wdt, pDef->Shape.Hgt, pForObj->Color, &trf);
    +			pDraw->RenderMesh(*pMeshInstance, cgo.Surface, offX - pDef->Shape.Wdt / static_cast<C4Real>(2.0f), offY - pDef->Shape.Hgt / static_cast<C4Real>(2.0f), pDef->Shape.Wdt, pDef->Shape.Hgt, pForObj->Color, &trf);
     			pDraw->SetMeshTransform(NULL);
     		}
     	}
    diff --git a/src/object/C4Movement.cpp b/src/object/C4Movement.cpp
    index b7a102f..e04a091 100644
    --- a/src/object/C4Movement.cpp
    +++ b/src/object/C4Movement.cpp
    @@ -442,7 +442,7 @@ void C4Object::DoMovement()
     		if (!InLiquid) // Enter liquid
     		{
     			if (OCF & OCF_HitSpeed2) if (Mass>3)
    -					Splash(GetX(),GetY()+1,Min(Shape.Wdt*Shape.Hgt/10,20),this);
    +					Splash(GetX(),GetY()+1,Min(fixtoi(Shape.Wdt*Shape.Hgt)/10,20),this);
     			fNoAttach=false;
     			InLiquid=1;
     		}
    diff --git a/src/object/C4Object.cpp b/src/object/C4Object.cpp
    index 04105f7..ea816fb 100644
    --- a/src/object/C4Object.cpp
    +++ b/src/object/C4Object.cpp
    @@ -3745,7 +3745,7 @@ void C4Object::ExecAction()
     		// Set target controller
     		Action.Target->Controller=Controller;
     		// ObjectAction got hold check
    -		iPushDistance = Max(Shape.Wdt/2-8,0);
    +		iPushDistance = Max(fixtoi(Shape.Wdt)/2 - 8, 0);
     		iPushRange = iPushDistance + 10;
     		int32_t sax,say,sawdt,sahgt;
     		Action.Target->GetArea(sax,say,sawdt,sahgt);
    @@ -3820,7 +3820,7 @@ void C4Object::ExecAction()
     		}
     
     		// Pulling range
    -		iPushDistance = Max(Shape.Wdt/2-8,0);
    +		iPushDistance = Max(fixtoi(Shape.Wdt)/2 - 8, 0);
     		iPushRange = iPushDistance + 20;
     		Action.Target->GetArea(sax,say,sawdt,sahgt);
     		// Object lost
    @@ -3998,7 +3998,7 @@ void C4Object::ExecAction()
     				iConnectX1 += lineAttach->GetItem(0).getInt();
     				iConnectY1 += lineAttach->GetItem(1).getInt();
     			}
    -			if ((iConnectX1!=Shape.VtxX[0]) || (iConnectY1!=Shape.VtxY[0]))
    +			if ((iConnectX1!=fixtoi(Shape.VtxX[0])) || (iConnectY1!=fixtoi(Shape.VtxY[0])))
     			{
     				// Regular wrapping line
     				if (Def->LineIntersect == 0)
    @@ -4006,7 +4006,7 @@ void C4Object::ExecAction()
     											Shape.VtxX[0],Shape.VtxY[0])) fBroke=true;
     				// No-intersection line
     				if (Def->LineIntersect == 1)
    -					{ Shape.VtxX[0]=iConnectX1; Shape.VtxY[0]=iConnectY1; }
    +					{ Shape.VtxX[0]=C4Real(iConnectX1); Shape.VtxY[0]=C4Real(iConnectY1); }
     			}
     
     			// Movement by Target2
    @@ -4021,7 +4021,7 @@ void C4Object::ExecAction()
     				iConnectX2 += lineAttach->GetItem(0).getInt();
     				iConnectY2 += lineAttach->GetItem(1).getInt();
     			}
    -			if ((iConnectX2!=Shape.VtxX[Shape.VtxNum-1]) || (iConnectY2!=Shape.VtxY[Shape.VtxNum-1]))
    +			if ((iConnectX2!=fixtoi(Shape.VtxX[Shape.VtxNum-1])) || (iConnectY2!=fixtoi(Shape.VtxY[Shape.VtxNum-1])))
     			{
     				// Regular wrapping line
     				if (Def->LineIntersect == 0)
    @@ -4764,7 +4764,7 @@ void C4Object::UpdateInLiquid()
     		if (!InLiquid) // Enter liquid
     		{
     			if (OCF & OCF_HitSpeed2) if (Mass>3)
    -					Splash(GetX(),GetY()+1,Min(Shape.Wdt*Shape.Hgt/10,20),this);
    +					Splash(GetX(),GetY()+1,Min(fixtoi(Shape.Wdt*Shape.Hgt)/10,20),this);
     			InLiquid=1;
     		}
     	}
    diff --git a/src/object/C4Object.h b/src/object/C4Object.h
    index 2a4b72c..e988d1b 100644
    --- a/src/object/C4Object.h
    +++ b/src/object/C4Object.h
    @@ -303,11 +303,11 @@ public:
     	C4Object* CreateContents(C4PropList *);
     	bool CreateContentsByList(C4IDList &idlist);
     	BYTE GetArea(int32_t &aX, int32_t &aY, int32_t &aWdt, int32_t &aHgt) const;
    -	inline int32_t addtop() const { return Max<int32_t>(18-Shape.Hgt,0); } // Minimum top action size for build check
    -	inline int32_t Left() const { return GetX()+Shape.x; } // left border of shape
    -	inline int32_t Top() const { return GetY()+Shape.y-addtop(); } // top border of shape (+build-top)
    -	inline int32_t Width() const { return Shape.Wdt; } // width of shape
    -	inline int32_t Height() const { return Shape.Hgt+addtop(); } // height of shape (+build-top)
    +	inline int32_t addtop() const { return Max<int32_t>(18- fixtoi(Shape.Hgt),0); } // Minimum top action size for build check
    +	inline int32_t Left() const { return GetX()+ fixtoi(Shape.x); } // left border of shape
    +	inline int32_t Top() const { return GetY()+ fixtoi(Shape.y)-addtop(); } // top border of shape (+build-top)
    +	inline int32_t Width() const { return fixtoi(Shape.Wdt); } // width of shape
    +	inline int32_t Height() const { return fixtoi(Shape.Hgt)+addtop(); } // height of shape (+build-top)
     	inline int32_t GetX() const { return fixtoi(fix_x); }
     	inline int32_t GetY() const { return fixtoi(fix_y); }
     	inline int32_t GetR() const { return fixtoi(fix_r); }
    diff --git a/src/object/C4ObjectCom.cpp b/src/object/C4ObjectCom.cpp
    index 315b801..c244b9e 100644
    --- a/src/object/C4ObjectCom.cpp
    +++ b/src/object/C4ObjectCom.cpp
    @@ -386,8 +386,8 @@ bool ObjectComDrop(C4Object *cObj, C4Object *pThing)
     		if (ComDirLike(cObj->Action.ComDir, COMD_Right)) { tdir=+1; right = 1;  if (cObj->xdir > C4REAL10(-15) && !isHanglingOrSwimming) --iOutposReduction; }
     	}
     	// Exit object
    -	pThing->Exit(cObj->GetX() + (cObj->Shape.x + cObj->Shape.Wdt * right) * !!tdir * iOutposReduction,
    -	             cObj->GetY()+cObj->Shape.y+cObj->Shape.Hgt-(pThing->Shape.y+pThing->Shape.Hgt),0,pthrow*tdir,Fix0,Fix0);
    +	pThing->Exit(cObj->GetX() + fixtoi(cObj->Shape.x + cObj->Shape.Wdt * right) * !!tdir * iOutposReduction,
    +		cObj->GetY() + fixtoi(cObj->Shape.y + cObj->Shape.Hgt - (pThing->Shape.y + pThing->Shape.Hgt)), 0, pthrow*tdir, Fix0, Fix0);
     	// Update OCF
     	cObj->SetOCF();
     	// Ungrab
    diff --git a/src/object/C4Shape.cpp b/src/object/C4Shape.cpp
    index f92e240..0bd81ca 100644
    --- a/src/object/C4Shape.cpp
    +++ b/src/object/C4Shape.cpp
    @@ -56,9 +56,9 @@ void C4Shape::Rotate(C4Real Angle, bool bUpdateVertices)
     	int32_t i = 0;
     	if (Config.General.DebugRec)
     	{
    -		rc.x=x; rc.y=y; rc.wdt=Wdt; rc.hgt=Hgt; rc.r=Angle;
    +		rc.x= fixtoi(x); rc.y= fixtoi(y); rc.wdt= fixtoi(Wdt); rc.hgt= fixtoi(Hgt); rc.r= fixtoi(Angle);
     		for (; i<4; ++i)
    -			{ rc.VtxX[i]=VtxX[i]; rc.VtxY[i]=VtxY[i]; }
    +			{ rc.VtxX[i]= fixtoi(VtxX[i]); rc.VtxY[i]= fixtoi(VtxY[i]); }
     		AddDbgRec(RCT_RotVtx1, &rc, sizeof(rc));
     	}
     	int32_t cnt,nvtx,nvty,nwdt,nhgt;
    @@ -121,9 +121,9 @@ void C4Shape::Rotate(C4Real Angle, bool bUpdateVertices)
     	Hgt = nhgt;
     	if (Config.General.DebugRec)
     	{
    -		rc.x=x; rc.y=y; rc.wdt=Wdt; rc.hgt=Hgt;
    +		rc.x= fixtoi(x); rc.y= fixtoi(y); rc.wdt= fixtoi(Wdt); rc.hgt= fixtoi(Hgt);
     		for (i=0; i<4; ++i)
    -			{ rc.VtxX[i]=VtxX[i]; rc.VtxY[i]=VtxY[i]; }
    +			{ rc.VtxX[i]= fixtoi(VtxX[i]); rc.VtxY[i]= fixtoi(VtxY[i]); }
     		AddDbgRec(RCT_RotVtx2, &rc, sizeof(rc));
     	}
     }
    @@ -135,6 +135,9 @@ void C4Shape::Stretch(int32_t iCon, bool bUpdateVertices)
     	y=y*iCon/FullCon;
     	Wdt=Wdt*iCon/FullCon;
     	Hgt=Hgt*iCon/FullCon;
    +	int32_t xo = x;
    +	int32_t xoxo = fixtoi(x);
    +	int32_t xoxoxo = fixtoi(x, 10000);
     	FireTop=FireTop*iCon/FullCon;
     	if (bUpdateVertices)
     		for (cnt=0; cnt<VtxNum; cnt++)
    @@ -162,28 +165,28 @@ void C4Shape::GetVertexOutline(C4Rect &rRect)
     	for (cnt=0; cnt<VtxNum; cnt++)
     	{
     		// Extend left
    -		if (VtxX[cnt]<rRect.x)
    +		if (fixtoi(VtxX[cnt])<rRect.x)
     		{
    -			rRect.Wdt+=rRect.x-VtxX[cnt];
    -			rRect.x=VtxX[cnt];
    +			rRect.Wdt+=rRect.x- fixtoi(VtxX[cnt]);
    +			rRect.x= fixtoi(VtxX[cnt]);
     		}
     		// Extend right
    -		else if (VtxX[cnt]>rRect.x+rRect.Wdt)
    -			{ rRect.Wdt=VtxX[cnt]-rRect.x; }
    +		else if (fixtoi(VtxX[cnt])>rRect.x+rRect.Wdt)
    +			{ rRect.Wdt= fixtoi(VtxX[cnt])-rRect.x; }
     
     		// Extend up
     		if (VtxY[cnt]<rRect.y)
     		{
    -			rRect.Hgt+=rRect.y-VtxY[cnt];
    -			rRect.y=VtxY[cnt];
    +			rRect.Hgt+=rRect.y- fixtoi(VtxY[cnt]);
    +			rRect.y= fixtoi(VtxY[cnt]);
     		}
     		// Extend down
     		else if (VtxY[cnt]>rRect.y+rRect.Hgt)
    -			{ rRect.Hgt=VtxY[cnt]-rRect.y; }
    +			{ rRect.Hgt= fixtoi(VtxY[cnt])-rRect.y; }
     	}
     
    -	rRect.Hgt+=rRect.y-y;
    -	rRect.y=y;
    +	rRect.Hgt += rRect.y - fixtoi(y);
    +	rRect.y = fixtoi(y);
     
     }
     
    @@ -223,7 +226,7 @@ bool C4Shape::Attach(int32_t &cx, int32_t &cy, BYTE cnat_pos)
     			if (VtxCNAT[i] & cnat_pos)
     			{
     				// get new vertex pos
    -				int32_t ax = testx + VtxX[i], ay = testy + VtxY[i];
    +				int32_t ax = testx + fixtoi(VtxX[i]), ay = testy + fixtoi(VtxY[i]);
     				if (CheckTouchableMaterial(ax, ay, i))
     				{
     					found = false;
    @@ -274,7 +277,7 @@ bool C4Shape::LineConnect(int32_t tx, int32_t ty, int32_t cvtx, int32_t ld, int3
     
     	// Check new path
     	int32_t ix,iy;
    -	if (PathFree(tx,ty,VtxX[cvtx+ld],VtxY[cvtx+ld],&ix,&iy))
    +	if (PathFree(tx,ty, fixtoi(VtxX[cvtx+ld]), fixtoi(VtxY[cvtx+ld]),&ix,&iy))
     	{
     		// Okay, set vertex
     		VtxX[cvtx]=tx; VtxY[cvtx]=ty;
    @@ -290,7 +293,7 @@ bool C4Shape::LineConnect(int32_t tx, int32_t ty, int32_t cvtx, int32_t ld, int3
     			for (cix = ix - irange / 2; cix <= ix + irange; cix += irange)
     				for (ciy = iy - irange / 2; ciy <= iy + irange; ciy += irange)
     				{
    -					if (PathFree(cix,ciy,tx,ty) && PathFree(cix,ciy,VtxX[cvtx+ld],VtxY[cvtx+ld]))
    +					if (PathFree(cix,ciy,tx,ty) && PathFree(cix,ciy, fixtoi(VtxX[cvtx+ld]), fixtoi(VtxY[cvtx+ld])))
     					{
     						found = true;
     						goto out;
    @@ -303,8 +306,8 @@ out:
     			// allow going through vehicle in this case to allow lines through castles and elevator shafts
     			cix = oldx;
     			ciy = oldy;
    -			if (!PathFreeIgnoreVehicle(cix,ciy,tx,ty) || !PathFreeIgnoreVehicle(cix,ciy,VtxX[cvtx+ld],VtxY[cvtx+ld]))
    -				if (!PathFreeIgnoreVehicle(cix,ciy,tx,ty) || !PathFreeIgnoreVehicle(cix,ciy,VtxX[cvtx+ld],VtxY[cvtx+ld]))
    +			if (!PathFreeIgnoreVehicle(cix,ciy,tx,ty) || !PathFreeIgnoreVehicle(cix,ciy,fixtoi(VtxX[cvtx+ld]), fixtoi(VtxY[cvtx+ld])))
    +				if (!PathFreeIgnoreVehicle(cix,ciy,tx,ty) || !PathFreeIgnoreVehicle(cix,ciy, fixtoi(VtxX[cvtx+ld]), fixtoi(VtxY[cvtx+ld])))
     					return false; // Found no bend vertex
     		}
     		// Insert bend vertex
    @@ -353,7 +356,7 @@ bool C4Shape::CheckContact(int32_t cx, int32_t cy)
     
     	for (int32_t cvtx=0; cvtx<VtxNum; cvtx++)
     		if (!(VtxCNAT[cvtx] & CNAT_NoCollision))
    -			if (CheckTouchableMaterial(cx+VtxX[cvtx],cy+VtxY[cvtx], cvtx))
    +			if (CheckTouchableMaterial(cx+fixtoi(VtxX[cvtx]),cy+fixtoi(VtxY[cvtx]), cvtx))
     				return true;
     
     
    @@ -378,8 +381,8 @@ bool C4Shape::ContactCheck(int32_t cx, int32_t cy, uint32_t *border_hack_contact
     
     		{
     			VtxContactCNAT[cvtx]=CNAT_None;
    -			int32_t x = cx+VtxX[cvtx];
    -			int32_t y = cy+VtxY[cvtx];
    +			int32_t x = cx+fixtoi(VtxX[cvtx]);
    +			int32_t y = cy+fixtoi(VtxY[cvtx]);
     			VtxContactMat[cvtx]=GBackMat(x,y);
     
     			if (CheckTouchableMaterial(x, y, cvtx, collide_halfvehic? 1:0))
    @@ -417,30 +420,30 @@ bool C4Shape::CheckScaleToWalk(int x, int y)
     		if (VtxCNAT[i] & CNAT_Bottom)
     		{
     			// no ground under the feet?
    -			if (CheckTouchableMaterial(x + VtxX[i], y + VtxY[i] + 1, i))
    +			if (CheckTouchableMaterial(x + fixtoi(VtxX[i]), y + fixtoi(VtxY[i]) + 1, i))
     				return false;
     		}
     		else
     		{
     			// can climb with hands?
    -			if (CheckTouchableMaterial(x + VtxX[i] - 1, y + VtxY[i], i))
    +			if (CheckTouchableMaterial(x + fixtoi(VtxX[i]) - 1, y + fixtoi(VtxY[i]), i))
     				return false;
    -			if (CheckTouchableMaterial(x + VtxX[i] + 1, y + VtxY[i], i))
    +			if (CheckTouchableMaterial(x + fixtoi(VtxX[i]) + 1, y + fixtoi(VtxY[i]), i))
     				return false;
     		}
     	}
     	return true;
     }
     
    -int32_t C4Shape::GetVertexX(int32_t iVertex)
    +C4Real C4Shape::GetVertexX(int32_t iVertex)
     {
    -	if (!Inside<int32_t>(iVertex,0,VtxNum-1)) return 0;
    +	if (!Inside<int32_t>(iVertex,0,VtxNum-1)) return C4Real(0);
     	return VtxX[iVertex];
     }
     
    -int32_t C4Shape::GetVertexY(int32_t iVertex)
    +C4Real C4Shape::GetVertexY(int32_t iVertex)
     {
    -	if (!Inside<int32_t>(iVertex,0,VtxNum-1)) return 0;
    +	if (!Inside<int32_t>(iVertex,0,VtxNum-1)) return C4Real(0);
     	return VtxY[iVertex];
     }
     
    @@ -461,13 +464,18 @@ void C4Shape::CopyFrom(C4Shape rFrom, bool bCpyVertices, bool fCopyVerticesFromS
     		memcpy(VtxContactMat, rVtxFrom.VtxContactMat+iCopyPos, VtxNum*sizeof(*VtxContactMat));
     		// continue: copies other members
     	}
    -	*((C4Rect *) this) = rFrom;
    +	*((C4AbstractRect<C4Real> *) this) = rFrom;
     	AttachMat=rFrom.AttachMat;
     	ContactCNAT=rFrom.ContactCNAT;
     	ContactCount=rFrom.ContactCount;
     	FireTop=rFrom.FireTop;
     }
     
    +C4Rect C4Shape::GetRect()
    +{
    +	return C4Rect(fixtoi(x), fixtoi(y), fixtoi(Wdt), fixtoi(Hgt));
    +}
    +
     int32_t C4Shape::GetBottomVertex()
     {
     	// return bottom-most vertex
    @@ -479,16 +487,12 @@ int32_t C4Shape::GetBottomVertex()
     	return iMax;
     }
     
    -int C4Shape::GetBottom()
    +C4Real C4Shape::GetBottom()
     {
    -	int b = INT_MIN;
    -	for (int32_t i = 0; i < VtxNum; i++)
    -		if (~VtxCNAT[i] & CNAT_NoCollision)
    -			if (VtxY[i] > b)
    -				b = VtxY[i];
    -	if (b == INT_MIN)
    +	int32_t bottomVertex = GetBottomVertex();
    +	if (bottomVertex == -1)
     		return y + Hgt;
    -	return b;
    +	return VtxY[bottomVertex];
     }
     
     C4DensityProvider DefaultDensityProvider;
    @@ -504,7 +508,7 @@ int32_t C4Shape::GetVertexContact(int32_t iVtx, DWORD dwCheckMask, int32_t tx, i
     	// default check mask
     	if (!dwCheckMask) dwCheckMask = VtxCNAT[iVtx];
     	// check vertex positions (vtx num not range-checked!)
    -	tx += VtxX[iVtx]; ty += VtxY[iVtx];
    +	tx += fixtoi(VtxX[iVtx]); ty += fixtoi(VtxY[iVtx]);
     	int32_t iContact = 0;
     	// check all directions for solid mat
     	if (~VtxCNAT[iVtx] & CNAT_NoCollision)
    diff --git a/src/object/C4Shape.h b/src/object/C4Shape.h
    index d89a4e7..5cfe1b6 100644
    --- a/src/object/C4Shape.h
    +++ b/src/object/C4Shape.h
    @@ -36,7 +36,7 @@ public:
     
     extern C4DensityProvider DefaultDensityProvider;
     
    -class C4Shape: public C4Rect
    +class C4Shape : public C4AbstractRect<C4Real>
     {
     public:
     	C4Shape();
    @@ -44,8 +44,8 @@ public:
     	// remember to adjust C4Shape::CopyFrom and CreateOwnOriginalCopy when adding members here!
     	int32_t FireTop;
     	int32_t VtxNum;
    -	int32_t VtxX[C4D_MaxVertex];
    -	int32_t VtxY[C4D_MaxVertex];
    +	C4Real VtxX[C4D_MaxVertex];
    +	C4Real VtxY[C4D_MaxVertex];
     	int32_t VtxCNAT[C4D_MaxVertex];
     	int32_t VtxFriction[C4D_MaxVertex];
     	int32_t ContactDensity;
    @@ -62,10 +62,10 @@ public:
     	void Stretch(int32_t iCon, bool bUpdateVertices);
     	void Jolt(int32_t iCon, bool bUpdateVertices);
     	void GetVertexOutline(C4Rect &rRect);
    -	int32_t GetVertexY(int32_t iVertex);
    -	int32_t GetVertexX(int32_t iVertex);
    -	int32_t GetX() const { return x; }
    -	int32_t GetY() const { return y; }
    +	C4Real GetVertexY(int32_t iVertex);
    +	C4Real GetVertexX(int32_t iVertex);
    +	C4Real GetX() const { return x; }
    +	C4Real GetY() const { return y; }
     	bool AddVertex(int32_t iX, int32_t iY);
     	bool CheckContact(int32_t cx, int32_t cy);
     	bool ContactCheck(int32_t cx, int32_t cy, uint32_t *border_hack_contacts=0, bool collide_halfvehic=false);
    @@ -74,8 +74,10 @@ public:
     	bool InsertVertex(int32_t iPos, int32_t tx, int32_t ty);
     	bool RemoveVertex(int32_t iPos);
     	void CopyFrom(C4Shape rFrom, bool bCpyVertices, bool fCopyVerticesFromSelf);
    +	// Returns the C4Rect with rounded coordinates for this shape.
    +	C4Rect GetRect();
     	int32_t GetBottomVertex();
    -	int GetBottom(); // return lowest vertex Y
    +	C4Real GetBottom(); // return lowest vertex Y
     	int32_t GetVertexContact(int32_t iVtx, DWORD dwCheckMask, int32_t tx, int32_t ty, const C4DensityProvider &rDensityProvider = DefaultDensityProvider); // get CNAT-mask for given vertex - does not check range for iVtx!
     	bool CheckScaleToWalk(int x, int y);
     	void CreateOwnOriginalCopy(C4Shape &rFrom); // create copy of all vertex members in back area of own buffers
    
    patch file icon c4shape-use-c4real.patch (25,659 bytes) 2015-10-29 20:47 +

-Relationships
+Relationships

-Notes

~0003902

Clonkonaut (developer)

There are probably some position errors / rounding things when the shape of an object grows that lead to be graphics being drawn one pixel afar.
I am not sure this is worth the effort to fix. It's a very minor visual thing.

Set the priority to low.

~0004061

Zapper (developer)

I actually spent some time on this today. The reason is that DoCon adjusts for the bottom-most vertex. But the vertices are not in C4Real coordinates like the object position but in int32_t.

That means that the position does get rounded and thus jumps up and down.

I tried making C4Shape use C4Real for the vertices & shape (which worked). But the values that are loaded from the DefCore are still integers. I might finish that some day when I want to dive into how mkNamingAdapt works, meh.

There might still be some issues then (e.g. with loading old savegames?). No idea.
I'll just attach the work-in-progress patch here so it doesn't get lost. The todo is that the C4Reals in C4Shape actually just contain the raw integers that are read from the DefCore. No idea why, I'd expect that those integers are passed into C4Real::C4Real(int) and then properly converted. But maybe the StdCompiler does some extremely weird stuff or just cannot read C4Real or something from the DefCore format. Idk.

~0004062

Sven2 (developer)

Last edited: 2015-10-29 22:36

View 6 revisions

C4Real aka FIXED is saved as the "raw" (i.e. *65536) integer. That's just how the corresponding CompileFunc works. Of course you can easily work around that by making a mkParAdapt allowing you to load and/or save them in a different format for definitions. For objects they should stay in the current format because if they're saved rounded to int, there will be sync losses e.g. on runtime join.

Concerning the "shaking", I don't think it would be solved by making vertices C4Real. There would still be shaking because they have to be rounded when they're doing the landscape check (either that or DoCon will silently push the bottom vertex into a stuck state).

Anyway, there might be a much simpler solution: Just adjust the object position smoothly such that the bottom vertex is always at the same position. That shouldn't be too hard to calculate at least for un-rotated objects.

~0004063

Sven2 (developer)

Last edited: 2015-10-29 23:33

View 2 revisions

Ah, unfortunately the simple solution does not work because gravity will always kill the smoothly pushed sub-pixel position (the same effect can be observed for vertically moving SolidMasks e.g. on the blimp).

So Zapper's proposed solution (plus sub-pixel movement of the object during construction) seems to be the only way. But when changing something so deeply in the movement code, I fear there may be a lot of possible, unexpected consequences.

~0004066

Zapper (developer)

I believe we should postpone that to 8.0.

There is probably not much missing from my patch above, but due to the possibility of new bugs we should do it for a fresh release!

~0004067

Sven2 (developer)

Agreed. Pushed to 8.0.

~0005799

Clonkonaut (developer)

Reminder sent to: Zapper

What about your patch?

~0005800

Zapper (developer)

The same as just before the release of 7.0:
The patch might introduce new bugs, so we should wait until after the release to apply it - and this time really do it, that's why I assigned it to me :)
+Notes

-Issue History
Date Modified Username Field Change
2013-03-01 20:08 Pyrit New Issue
2015-10-12 18:53 Clonkonaut Priority normal => low
2015-10-12 18:56 Clonkonaut Note Added: 0003902
2015-10-12 18:56 Clonkonaut Status new => acknowledged
2015-10-16 00:32 Sven2 Target Version => 7.0
2015-10-29 20:46 Zapper Note Added: 0004061
2015-10-29 20:47 Zapper File Added: c4shape-use-c4real.patch
2015-10-29 22:29 Sven2 Note Added: 0004062
2015-10-29 22:32 Sven2 Note Edited: 0004062 View Revisions
2015-10-29 22:32 Sven2 Note Edited: 0004062 View Revisions
2015-10-29 22:32 Sven2 Note Edited: 0004062 View Revisions
2015-10-29 22:33 Sven2 Note Edited: 0004062 View Revisions
2015-10-29 22:36 Sven2 Note Edited: 0004062 View Revisions
2015-10-29 23:32 Sven2 Note Added: 0004063
2015-10-29 23:33 Sven2 Note Edited: 0004063 View Revisions
2015-10-30 19:56 Zapper Note Added: 0004066
2015-10-30 21:16 Sven2 Note Added: 0004067
2015-10-30 21:16 Sven2 Target Version 7.0 => 8.0
2017-08-20 11:35 Zapper Assigned To => Zapper
2017-08-20 11:35 Zapper Status acknowledged => assigned
2017-08-20 11:35 Zapper Target Version 8.0 => 9.0
2017-10-24 22:04 Clonkonaut Note Added: 0005799
2017-10-25 05:52 Zapper Note Added: 0005800
+Issue History