Esempio n. 1
0
void PerformanceDialog::addSwapBuffers()
{
    double startTime = (mSwapStart-mSwapVSync)*KScaleX;
    double duration= (mSwapEnd-mSwapStart)*KScaleX;
    mSwapValues->addValue(duration);

    addBar(startTime,duration, mSwapRow +0.5, QColor(255,255,180), QColor(255,255,120),QColor(255,255,0));

    if (mCurrentRow!=mSwapRow) {
        startTime = 0;
        duration = (mSwapEnd-mLastVSync)*KScaleX;
        addBar(startTime,duration, mCurrentRow +0.5, QColor(255,255,120), QColor(255,255,120),QColor(255,255,0));
    }
}
Esempio n. 2
0
void PerformanceDialog::addRender()
{
    double startTime = (mRenderStart-mRenderVSync)*KScaleX;
    double duration= (mRenderEnd-mRenderStart)*KScaleX;
    mRenderValues->addValue(duration);

    addBar(startTime,duration, mRenderRow +0.5, QColor(0,180,255), QColor(0,120,255),QColor(0,0,255));

    if (mCurrentRow!=mRenderRow) {
        startTime = 0;
        duration = (mRenderEnd-mLastVSync)*KScaleX;
        addBar(startTime,duration, mCurrentRow +0.5, QColor(0,120,255), QColor(0,120,255),QColor(0,0,255));
    }
}
Esempio n. 3
0
void PerformanceDialog::addUpdate()
{
    double startTime = (mUpdateStart-mUpdateVSync)*KScaleX;
    double duration= (mUpdateEnd-mUpdateStart)*KScaleX;
    mUpdateValues->addValue(duration);

    addBar(startTime,duration, mUpdateRow, QColor(180,255,0), QColor(120,255,0),QColor(0,255,0));

    if (mCurrentRow!=mUpdateRow) {
        startTime = 0;
        duration = (mUpdateEnd-mLastVSync)*KScaleX;
        addBar(startTime,duration, mCurrentRow +0.5, QColor(120,255,0), QColor(120,255,0),QColor(0,255,0));
    }
}
Esempio n. 4
0
void LLTextureView::draw()
{
	if (!mFreezeView)
	{
// 		LLViewerObject *objectp;
// 		S32 te;

		for_each(mTextureBars.begin(), mTextureBars.end(), DeletePointer());
		mTextureBars.clear();
	
		delete mGLTexMemBar;
		mGLTexMemBar = 0;
	
		typedef std::multiset<decode_pair_t, compare_decode_pair > display_list_t;
		display_list_t display_image_list;
	
		if (mPrintList)
		{
			llinfos << "ID\tMEM\tBOOST\tPRI\tWIDTH\tHEIGHT\tDISCARD" << llendl;
		}
	
		for (LLViewerImageList::image_priority_list_t::iterator iter = gImageList.mImageList.begin();
			 iter != gImageList.mImageList.end(); )
		{
			LLPointer<LLViewerImage> imagep = *iter++;

			S32 cur_discard = imagep->getDiscardLevel();
			S32 desired_discard = imagep->mDesiredDiscardLevel;
			
			if (mPrintList)
			{
				llinfos << imagep->getID()
						<< "\t" <<  imagep->mTextureMemory
						<< "\t" << imagep->getBoostLevel()
						<< "\t" << imagep->getDecodePriority()
						<< "\t" << imagep->getWidth()
						<< "\t" << imagep->getHeight()
						<< "\t" << cur_discard
						<< llendl;
			}
		
#if 0
			if (imagep->getDontDiscard())
			{
				continue;
			}

			if (imagep->isMissingAsset())
			{
				continue;
			}
#endif

#define HIGH_PRIORITY 100000000.f
			F32 pri;
			if (mOrderFetch)
			{
				pri = ((F32)imagep->mFetchPriority)/256.f;
			}
			else
			{
				pri = imagep->getDecodePriority();
			}
			
			if (sDebugImages.find(imagep) != sDebugImages.end())
			{
				pri += 4*HIGH_PRIORITY;
			}

			if (!mOrderFetch)
			{
#if 1
			if (pri < HIGH_PRIORITY && LLSelectMgr::getInstance())
			{
				struct f : public LLSelectedTEFunctor
				{
					LLViewerImage* mImage;
					f(LLViewerImage* image) : mImage(image) {}
					virtual bool apply(LLViewerObject* object, S32 te)
					{
						return (mImage == object->getTEImage(te));
					}
				} func(imagep);
				const bool firstonly = true;
				bool match = LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, firstonly);
				if (match)
				{
					pri += 3*HIGH_PRIORITY;
				}
			}
#endif
#if 1
			if (pri < HIGH_PRIORITY && (cur_discard< 0 || desired_discard < cur_discard))
			{
				LLViewerObject *objectp = gHoverView->getLastHoverObject();
				if (objectp)
				{
					S32 tex_count = objectp->getNumTEs();
					for (S32 i = 0; i < tex_count; i++)
					{
						if (imagep == objectp->getTEImage(i))
						{
							pri += 2*HIGH_PRIORITY;
							break;
						}
					}
				}
			}
#endif
#if 1
			if (pri > 0.f && pri < HIGH_PRIORITY)
			{
				if (imagep->mLastPacketTimer.getElapsedTimeF32() < 1.f ||
					imagep->mFetchDeltaTime < 0.25f)
				{
					pri += 1*HIGH_PRIORITY;
				}
			}
#endif
			}
			
	 		if (pri > 0.0f)
			{
				display_image_list.insert(std::make_pair(pri, imagep));
			}
		}
		
		if (mPrintList)
		{
			mPrintList = FALSE;
		}
		
		static S32 max_count = 50;
		S32 count = 0;
		for (display_list_t::iterator iter = display_image_list.begin();
			 iter != display_image_list.end(); iter++)
		{
			LLViewerImage* imagep = iter->second;
			S32 hilite = 0;
			F32 pri = iter->first;
			if (pri >= 1 * HIGH_PRIORITY)
			{
				hilite = (S32)((pri+1) / HIGH_PRIORITY) - 1;
			}
			if ((hilite || count < max_count-10) && (count < max_count))
			{
				if (addBar(imagep, hilite))
				{
					count++;
				}
			}
		}

		if (mOrderFetch)
			sortChildren(LLTextureBar::sort_fetch());
		else
			sortChildren(LLTextureBar::sort());

		mGLTexMemBar = new LLGLTexMemBar("gl texmem bar", this);
		addChild(mGLTexMemBar);
	
		reshape(getRect().getWidth(), getRect().getHeight(), TRUE);

		/*
		  count = gImageList.getNumImages();
		  std::string info_string;
		  info_string = llformat("Global Info:\nTexture Count: %d", count);
		  mInfoTextp->setText(info_string);
		*/


		for (child_list_const_iter_t child_iter = getChildList()->begin();
			 child_iter != getChildList()->end(); ++child_iter)
		{
			LLView *viewp = *child_iter;
			if (viewp->getRect().mBottom < 0)
			{
				viewp->setVisible(FALSE);
			}
		}
	}
	
	LLContainerView::draw();

}
Esempio n. 5
0
void renderI2of5(OROPage * page, const QRectF &r, const QString & _str, ORBarcodeData * bc)
{
  QString str = _str;
  qreal narrow_bar = bc->narrowBarWidth;
  qreal bar_width_mult = 2.5; // the wide bar width multiple of the narrow bar
  qreal wide_bar = narrow_bar * bar_width_mult;

  if(str.length() % 2)
  {
    str = "0" + str; // padding zero if number of characters is not even
  }

  // this is our mandatory minimum quiet zone
  qreal quiet_zone = narrow_bar * 10;
  if(quiet_zone < 0.1)
    quiet_zone = 0.1;

  // what kind of area do we have to work with
  qreal draw_width = r.width();

  // how long is the value we need to encode?
  int val_length = str.length();

  // L = (C(2N+3)+6+N)X
  // L length of barcode (excluding quite zone
  // C the number of characters in the value excluding the start/stop
  // N the bar width multiple for wide bars
  // X the width of a bar (pixels in our case)
  qreal L;
  qreal C = val_length;
  qreal N = bar_width_mult;
  qreal X = narrow_bar;

  L = (C * (2.0*N + 3.0) + 6.0 + N) * X;

  // now we have the actual width the barcode will be so can determine the actual
  // size of the quiet zone (we assume we center the barcode in the given area)
  // At the moment the way the code is written is we will always start at the minimum
  // required quiet zone if we don't have enough space.... I guess we'll just have over-run
  // to the right
  //
  // calculate the starting position based on the alignment option
  if(bc->align == 1) // center
  {
    qreal nqz = (draw_width - L) / 2.0;
    if(nqz > quiet_zone)
      quiet_zone = nqz;
  }
  else if(bc->align > 1) // right
    quiet_zone = draw_width - (L + quiet_zone);
  //else if(align < 1) {} // left : do nothing

  QPointF pos(r.left() + quiet_zone, r.top());

  // start character
  pos = addBar(page, r, pos, bc, narrow_bar);
  pos = addSpace(page, r, pos, bc, narrow_bar);
  pos = addBar(page, r, pos, bc, narrow_bar);
  pos = addSpace(page, r, pos, bc, narrow_bar);

  for(int i = 0; i < str.length()-1; i+=2)
  {
    for(int iElt = 0; _i2of5charmap [0][iElt] != '\0'; iElt++)
    {
      for(int offset=0; offset<=1; offset++)
      {
        QChar c = str.at(i+offset);
        if(!c.isDigit()) {
          break; // invalid character
        }
        int iChar = c.digitValue();
        qreal width = _i2of5charmap[iChar][iElt] == 'W' ? wide_bar : narrow_bar;
        pos = addElement(page, r, pos, bc, width, offset==1);
      }
    }
  }

  // stop character
  pos = addBar(page, r, pos, bc, wide_bar);
  pos = addSpace(page, r, pos, bc, narrow_bar);
  pos = addBar(page, r, pos, bc, narrow_bar);


  return;
}
void LLTextureView::draw()
{
    if (!mFreezeView)
    {
// 		LLViewerObject *objectp;
// 		S32 te;

        for_each(mTextureBars.begin(), mTextureBars.end(), KillView());
        mTextureBars.clear();

        if (mGLTexMemBar)
        {
            removeChild(mGLTexMemBar);
            mGLTexMemBar->die();
            mGLTexMemBar = 0;
        }

        if (mAvatarTexBar)
        {
            removeChild(mAvatarTexBar);
            mAvatarTexBar->die();
            mAvatarTexBar = 0;
        }

        typedef std::multiset<decode_pair_t, compare_decode_pair > display_list_t;
        display_list_t display_image_list;

        if (mPrintList)
        {
            llinfos << "ID\tMEM\tBOOST\tPRI\tWIDTH\tHEIGHT\tDISCARD" << llendl;
        }

        for (LLViewerTextureList::image_priority_list_t::iterator iter = gTextureList.mImageList.begin();
                iter != gTextureList.mImageList.end(); )
        {
            LLPointer<LLViewerFetchedTexture> imagep = *iter++;
            if(!imagep->hasFetcher())
            {
                continue ;
            }

            S32 cur_discard = imagep->getDiscardLevel();
            S32 desired_discard = imagep->mDesiredDiscardLevel;

            if (mPrintList)
            {
                S32 tex_mem = imagep->hasGLTexture() ? imagep->getTextureMemory() : 0 ;
                llinfos << imagep->getID()
                        << "\t" << tex_mem
                        << "\t" << imagep->getBoostLevel()
                        << "\t" << imagep->getDecodePriority()
                        << "\t" << imagep->getWidth()
                        << "\t" << imagep->getHeight()
                        << "\t" << cur_discard
                        << llendl;
            }

            if (imagep->getID() == LLAppViewer::getTextureFetch()->mDebugID)
            {
                static S32 debug_count = 0;
                ++debug_count; // for breakpoints
            }

            F32 pri;
            if (mOrderFetch)
            {
                pri = ((F32)imagep->mFetchPriority)/256.f;
            }
            else
            {
                pri = imagep->getDecodePriority();
            }
            pri = llclamp(pri, 0.0f, HIGH_PRIORITY-1.f);

            if (sDebugImages.find(imagep) != sDebugImages.end())
            {
                pri += 4*HIGH_PRIORITY;
            }

            if (!mOrderFetch)
            {
                if (pri < HIGH_PRIORITY && LLSelectMgr::getInstance())
                {
                    struct f : public LLSelectedTEFunctor
                    {
                        LLViewerFetchedTexture* mImage;
                        f(LLViewerFetchedTexture* image) : mImage(image) {}
                        virtual bool apply(LLViewerObject* object, S32 te)
                        {
                            return (mImage == object->getTEImage(te));
                        }
                    } func(imagep);
                    const bool firstonly = true;
                    bool match = LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, firstonly);
                    if (match)
                    {
                        pri += 3*HIGH_PRIORITY;
                    }
                }

                if (pri < HIGH_PRIORITY && (cur_discard< 0 || desired_discard < cur_discard))
                {
                    LLSelectNode* hover_node = LLSelectMgr::instance().getHoverNode();
                    if (hover_node)
                    {
                        LLViewerObject *objectp = hover_node->getObject();
                        if (objectp)
                        {
                            S32 tex_count = objectp->getNumTEs();
                            for (S32 i = 0; i < tex_count; i++)
                            {
                                if (imagep == objectp->getTEImage(i))
                                {
                                    pri += 2*HIGH_PRIORITY;
                                    break;
                                }
                            }
                        }
                    }
                }

                if (pri > 0.f && pri < HIGH_PRIORITY)
                {
                    if (imagep->mLastPacketTimer.getElapsedTimeF32() < 1.f ||
                            imagep->mFetchDeltaTime < 0.25f)
                    {
                        pri += 1*HIGH_PRIORITY;
                    }
                }
            }

            if (pri > 0.0f)
            {
                display_image_list.insert(std::make_pair(pri, imagep));
            }
        }

        if (mPrintList)
        {
            mPrintList = FALSE;
        }

        static S32 max_count = 50;
        S32 count = 0;
        mNumTextureBars = 0 ;
        for (display_list_t::iterator iter = display_image_list.begin();
                iter != display_image_list.end(); iter++)
        {
            LLViewerFetchedTexture* imagep = iter->second;
            S32 hilite = 0;
            F32 pri = iter->first;
            if (pri >= 1 * HIGH_PRIORITY)
            {
                hilite = (S32)((pri+1) / HIGH_PRIORITY) - 1;
            }
            if ((hilite || count < max_count-10) && (count < max_count))
            {
                if (addBar(imagep, hilite))
                {
                    count++;
                }
            }
        }

        if (mOrderFetch)
            sortChildren(LLTextureBar::sort_fetch());
        else
            sortChildren(LLTextureBar::sort());

        LLGLTexMemBar::Params tmbp;
        LLRect tmbr;
        tmbp.name("gl texmem bar");
        tmbp.rect(tmbr);
        tmbp.follows.flags = FOLLOWS_LEFT|FOLLOWS_TOP;
        tmbp.texture_view(this);
        mGLTexMemBar = LLUICtrlFactory::create<LLGLTexMemBar>(tmbp);
        addChild(mGLTexMemBar);
        sendChildToFront(mGLTexMemBar);

        LLAvatarTexBar::Params atbp;
        LLRect atbr;
        atbp.name("gl avatartex bar");
        atbp.texture_view(this);
        atbp.rect(atbr);
        mAvatarTexBar = LLUICtrlFactory::create<LLAvatarTexBar>(atbp);
        addChild(mAvatarTexBar);
        sendChildToFront(mAvatarTexBar);

        reshape(getRect().getWidth(), getRect().getHeight(), TRUE);

        LLUI::popMatrix();
        LLUI::pushMatrix();
        LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom);

        for (child_list_const_iter_t child_iter = getChildList()->begin();
                child_iter != getChildList()->end(); ++child_iter)
        {
            LLView *viewp = *child_iter;
            if (viewp->getRect().mBottom < 0)
            {
                viewp->setVisible(FALSE);
            }
        }
    }

    LLContainerView::draw();

}
void HelloWorld::update(float dt){
	if(m_istatus!=GAMEOVER){
		int lastgroud=-1;
		for (int i=0; i<m_pGroundVec.size(); i++)
		{
			m_pGroundVec[i]->setPositionX(m_pGroundVec[i]->getPositionX() - MOVESPEED/mfax);
			CCRect rcGroundBounding = m_pGroundVec[i]->boundingBox(); 
			if (rcGroundBounding.getMaxX()<=0)
			{
				lastgroud=i;			
			}
		}
		//float groundsize = m_pGround[i]->getContentSize().width*1.0;
		//m_pGround[i]->setPositionX(groundsize/2. + (GGROUNDNUM-1)*groundsize);
		if(lastgroud>-1){
			float moveposx=m_pGroundVec[m_ilastground]->boundingBox().getMaxX();
			moveposx+=m_pGroundVec[lastgroud]->getContentSize().width/2.;
			m_pGroundVec[lastgroud]->setPositionX(moveposx);
			m_ilastground=lastgroud;
			//CCLOG("win x:%f,Ground x:%f,mfac:%f,index=%d ",this->mScreenSize.width,
			//	moveposx,mfac,m_ilastground);
		}

	}
	if(m_istatus==GETREADY || m_istatus==GOSTART ){
		return;
	}
	//最后一个柱子离屏幕右边大于固定距离时放出来
	if(m_pDownBarVec.size()>0 && (mScreenSize.width-m_pDownBarVec.back()->getPositionX())
	>(mScreenSize.width*0.4))
	{
		addBar(0);
	}
	//重力响应
	mWorld->Step(dt, 8, 3); // 8和3为官方推荐数据
	myangle+=1.0f;
	if(myangle>=25)
	{
		iFlyKeep++;
		myangle=25;
	}
	if (myangle<25)
	{
		iFlyKeep=0;
		mBird->setRotation(myangle);
	}
	CCLOG("bird iFlyKeep:%d,angle:%0.2f,myangle:%d",iFlyKeep,mBird->getRotation(),myangle);
	if(iFlyKeep>30)
	{
		//if (mBird->getRotation() < 10.f/mfac && mBird->getRotation() > -85.f)
		//{
		//	mBird->setRotation(mBird->getRotation()-10.f);
		//}

		if(mBird->getRotation()-10.f<-90.f){
			mBird->setRotation(-90.f);
		}
		else{
			mBird->setRotation(mBird->getRotation()-6.f);
		}
		//if(mBird->getRotation() > -91)
		//mBird->setRotation(mBird->getRotation()-2.5f);
	}


	//CCLOG("bird angle:%0.2f,myangle:%0.2f ",mBird->getRotation(),myangle);
	if(myflag==1)
	{
		mBird->setRotation(-90);
		return;
	}
	//禁止小鸟越过屏幕高度
	if(mBird->getPositionY()>mScreenSize.height)
	{
		mBird->setPositionY(mScreenSize.height);
	}
	/*for (int i=0; i<gbackgroundNum; i++)
	{
	m_pBackGround[i]->setPositionX(m_pBackGround[i]->getPositionX() - 1); 
	CCRect rcBounding = m_pBackGround[i]->boundingBox(); 
	if (rcBounding.getMaxX() <= 0)    // 如果完全消失在屏幕上,就移动精灵1到精灵3的后面  
	{  
	int backgroundsize = m_pBackGround[i]->getContentSize().width;
	m_pBackGround[i]->setPositionX(backgroundsize/2 + (ggroundNum-1)*backgroundsize);  
	}  

	}
	*/

	//CCLOG("rcBounding1 MinX:%d MinY:%d MaxX:%d MaxY:%d", rcBounding1.getMinX()
	//, rcBounding1.getMinY(), rcBounding1.getMaxX(), rcBounding1.getMaxY());

	//给小鸟计分
	if(m_pDownBarVec.size()>0 && m_pDownBarVec.front()->boundingBox().getMaxX() <= this->mBird->boundingBox().getMaxX())
	{
		ShowNumberNode * snn = (ShowNumberNode *)this->getChildByTag(0);
		snn->f_ShowNumber(++testnum);
//		EFFECT_PLAY(true,MUSIC_POINT);
		m_pDownBarVec.pop_front();
	}

	CCSprite *s;
	std::vector<b2Body *>toDestroy;
	map<CCSprite *,int>::iterator itbar;
	for(b2Body *b = mWorld->GetBodyList(); b != NULL; b = b->GetNext()){
		s = (CCSprite *)b->GetUserData();
		if(s != NULL && s->getTag()==SPRITE_TAG_BAR){

			//CCLOG("bird x:%f guan x:%f ", mBird->getPositionX(),s->getPositionX());

			s->setPositionX(s->getPositionX() - MOVESPEED/mfax);
			if(s->getPositionX() < -20/mfac){
				s->setVisible(false);
				toDestroy.push_back(b);
				//s->removeFromParent();					
				//mWorld->DestroyBody(b);
				//b = mWorld->GetBodyList();
			}
		}
	}


	std::vector<b2Body*>::iterator pos2;
	for (pos2 = toDestroy.begin();pos2!=toDestroy.end();++pos2)
	{
		b2Body* body = *pos2;
		if(body->GetUserData()!=NULL)
		{
			CCSprite* sprite = (CCSprite*)body->GetUserData();
			this->removeChild(sprite,true);
		}

		mWorld->DestroyBody(body);
		body = NULL;

	}

}
Esempio n. 8
0
static cpSpace *
init(void)
{
	space = cpSpaceNew();
	cpSpaceSetIterations(space, 10);
	cpSpaceSetGravity(space, cpv(0, -100));
	cpSpaceSetSleepTimeThreshold(space, 0.5f);
	
	cpBody *staticBody = cpSpaceGetStaticBody(space);
	cpShape *shape;
	
	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,240), cpv(320,240), 0.0f));
	cpShapeSetElasticity(shape, 1.0f);
	cpShapeSetFriction(shape, 1.0f);
	cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
	
	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,120), cpv(320,120), 0.0f));
	cpShapeSetElasticity(shape, 1.0f);
	cpShapeSetFriction(shape, 1.0f);
	cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
	
	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,0), cpv(320,0), 0.0f));
	cpShapeSetElasticity(shape, 1.0f);
	cpShapeSetFriction(shape, 1.0f);
	cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
	
	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-120), cpv(320,-120), 0.0f));
	cpShapeSetElasticity(shape, 1.0f);
	cpShapeSetFriction(shape, 1.0f);
	cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
	
	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f));
	cpShapeSetElasticity(shape, 1.0f);
	cpShapeSetFriction(shape, 1.0f);
	cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
	
	
	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f));
	cpShapeSetElasticity(shape, 1.0f);
	cpShapeSetFriction(shape, 1.0f);
	cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
	
	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-160,-240), cpv(-160,240), 0.0f));
	cpShapeSetElasticity(shape, 1.0f);
	cpShapeSetFriction(shape, 1.0f);
	cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
	
	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(0,-240), cpv(0,240), 0.0f));
	cpShapeSetElasticity(shape, 1.0f);
	cpShapeSetFriction(shape, 1.0f);
	cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
	
	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(160,-240), cpv(160,240), 0.0f));
	cpShapeSetElasticity(shape, 1.0f);
	cpShapeSetFriction(shape, 1.0f);
	cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
	
	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f));
	cpShapeSetElasticity(shape, 1.0f);
	cpShapeSetFriction(shape, 1.0f);
	cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
	
	cpVect boxOffset;
	cpBody *body1, *body2;
	
	cpVect posA = cpv( 50, 60);
	cpVect posB = cpv(110, 60);
	
	#define POS_A cpvadd(boxOffset, posA)
	#define POS_B cpvadd(boxOffset, posB)
	
	// Pin Joints - Link shapes with a solid bar or pin.
	// Keeps the anchor points the same distance apart from when the joint was created.
	boxOffset = cpv(-320, -240);
	body1 = addBall(posA, boxOffset);
	body2 = addBall(posB, boxOffset);
	cpSpaceAddConstraint(space, cpPinJointNew(body1, body2, cpv(15,0), cpv(-15,0)));
	
	// Slide Joints - Like pin joints but with a min/max distance.
	// Can be used for a cheap approximation of a rope.
	boxOffset = cpv(-160, -240);
	body1 = addBall(posA, boxOffset);
	body2 = addBall(posB, boxOffset);
	cpSpaceAddConstraint(space, cpSlideJointNew(body1, body2, cpv(15,0), cpv(-15,0), 20.0f, 40.0f));
	
	// Pivot Joints - Holds the two anchor points together. Like a swivel.
	boxOffset = cpv(0, -240);
	body1 = addBall(posA, boxOffset);
	body2 = addBall(posB, boxOffset);
	cpSpaceAddConstraint(space, cpPivotJointNew(body1, body2, cpvadd(boxOffset, cpv(80,60))));
	// cpPivotJointNew() takes it's anchor parameter in world coordinates. The anchors are calculated from that
	// cpPivotJointNew2() lets you specify the two anchor points explicitly
	
	// Groove Joints - Like a pivot joint, but one of the anchors is a line segment that the pivot can slide in
	boxOffset = cpv(160, -240);
	body1 = addBall(posA, boxOffset);
	body2 = addBall(posB, boxOffset);
	cpSpaceAddConstraint(space, cpGrooveJointNew(body1, body2, cpv(30,30), cpv(30,-30), cpv(-30,0)));
	
	// Damped Springs
	boxOffset = cpv(-320, -120);
	body1 = addBall(posA, boxOffset);
	body2 = addBall(posB, boxOffset);
	cpSpaceAddConstraint(space, cpDampedSpringNew(body1, body2, cpv(15,0), cpv(-15,0), 20.0f, 5.0f, 0.3f));
	
	// Damped Rotary Springs
	boxOffset = cpv(-160, -120);
	body1 = addBar(posA, boxOffset);
	body2 = addBar(posB, boxOffset);
	// Add some pin joints to hold the circles in place.
	cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, POS_A));
	cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, POS_B));
	cpSpaceAddConstraint(space, cpDampedRotarySpringNew(body1, body2, 0.0f, 3000.0f, 60.0f));
	
	// Rotary Limit Joint
	boxOffset = cpv(0, -120);
	body1 = addLever(posA, boxOffset);
	body2 = addLever(posB, boxOffset);
	// Add some pin joints to hold the circles in place.
	cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, POS_A));
	cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, POS_B));
	// Hold their rotation within 90 degrees of each other.
	cpSpaceAddConstraint(space, cpRotaryLimitJointNew(body1, body2, -M_PI_2, M_PI_2));
	
	// Ratchet Joint - A rotary ratchet, like a socket wrench
	boxOffset = cpv(160, -120);
	body1 = addLever(posA, boxOffset);
	body2 = addLever(posB, boxOffset);
	// Add some pin joints to hold the circles in place.
	cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, POS_A));
	cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, POS_B));
	// Ratchet every 90 degrees
	cpSpaceAddConstraint(space, cpRatchetJointNew(body1, body2, 0.0f, M_PI_2));
	
	// Gear Joint - Maintain a specific angular velocity ratio
	boxOffset = cpv(-320, 0);
	body1 = addBar(posA, boxOffset);
	body2 = addBar(posB, boxOffset);
	// Add some pin joints to hold the circles in place.
	cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, POS_A));
	cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, POS_B));
	// Force one to sping 2x as fast as the other
	cpSpaceAddConstraint(space, cpGearJointNew(body1, body2, 0.0f, 2.0f));
	
	// Simple Motor - Maintain a specific angular relative velocity
	boxOffset = cpv(-160, 0);
	body1 = addBar(posA, boxOffset);
	body2 = addBar(posB, boxOffset);
	// Add some pin joints to hold the circles in place.
	cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, POS_A));
	cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, POS_B));
	// Make them spin at 1/2 revolution per second in relation to each other.
	cpSpaceAddConstraint(space, cpSimpleMotorNew(body1, body2, M_PI));
	
	// Make a car with some nice soft suspension
	boxOffset = cpv(0, 0);
	cpBody *wheel1 = addWheel(posA, boxOffset);
	cpBody *wheel2 = addWheel(posB, boxOffset);
	cpBody *chassis = addChassis(cpv(80, 100), boxOffset);
	
	cpSpaceAddConstraint(space, cpGrooveJointNew(chassis, wheel1, cpv(-30, -10), cpv(-30, -40), cpvzero));
	cpSpaceAddConstraint(space, cpGrooveJointNew(chassis, wheel2, cpv( 30, -10), cpv( 30, -40), cpvzero));
	
	cpSpaceAddConstraint(space, cpDampedSpringNew(chassis, wheel1, cpv(-30, 0), cpvzero, 50.0f, 20.0f, 10.0f));
	cpSpaceAddConstraint(space, cpDampedSpringNew(chassis, wheel2, cpv( 30, 0), cpvzero, 50.0f, 20.0f, 10.0f));
	
	return space;
}