Example #1
0
void ApplicationState::addDrawableObject(DrawableObject& drawable)
{
  drawableObjects.push_back(&drawable);

  if (drawable.isClickable())
    addClickableObject(drawable, drawable.getLayer());
}
/*****************************************************************************\
	Compute the distance metrics for each entry in the display list 
	given the new view point.  Entries below the bottom Z value given will
	be removed from the list and placed into the "lowList" chain.  Entries
	which are too high will go into the "highList" chain.

    this version ONLY calculates the distance for the objects in it's list
\*****************************************************************************/
void ObjectDisplayList::UpdateMetrics(const Tpoint *pos)
{
	register float	x = pos->x;
	register float	y = pos->y;
//	register float	z = pos->z;

	DrawableObject	*p;

	// Quit now if we don't have at least one list entry
	if ( !head ) return;

	// Run through the whole list and compute the sorting metrics for each entry
	p = head;
	//while ( p )
	while ( p && !F4IsBadReadPtr(p, sizeof(DrawableObject))) // JB 010318 CTD
	{
		// Update the distance metric (not less than 0)
		p->distance = max( (float)fabs(x - p->position.x), (float)fabs(y - p->position.y) );
		ShiAssert(!_isnan(p->distance));
		if(_isnan(p->distance))
		{
			p->distance = 0.0f;
		}
		else if (p->distance > p->Radius())
		{
			p->distance = p->distance - p->Radius();
		}
		else
		{
			p->distance = 0.0f;
		}
		p=p->next;
	}
}
Example #3
0
DrawableObject* ApplicationState::getObjectClicked(Vector2d& mousePosition, int layer)
{
  DrawableObject * closestObject = clickableObjects[layer].findClosest(mousePosition);

  if (closestObject != NULL && closestObject->isClicked(mousePosition))
    return closestObject;
  return NULL;
}
Example #4
0
  const char *render_scene(std::vector<DrawableObject*> &actors)
  {
    if (first_frame) {
      EntryCB cb = Callbacks.begin();
      while (cb != Callbacks.end()) {
	if (cb->first != "idle") {
	  std::cout<<cb->first<<": "<<cb->second->get_message()<<std::endl;
	}
	++cb;
      }
      first_frame = false;
    }

    character_input = ' ';
    CurrentWindow = this;

    glClearColor(Color[0], Color[1], Color[2], 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    GLfloat light_ambient [] = { 0.4, 0.4, 0.4, 1.0 };
    GLfloat light_diffuse [] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat light_position[] = { 0.0, 0.0, 1.0, 0.0 };

    glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    glTranslated(Position[0], Position[1], Position[2]);
    glRotated(Orientation[0], 1, 0, 0);
    glRotated(Orientation[1], 0, 1, 0);
    glScaled(Scale[0], Scale[1], Scale[2]);

    for (std::vector<DrawableObject*>::iterator a=actors.begin();
         a!=actors.end(); ++a) {
      DrawableObject *actor = *a;
      actor->draw();
    }

    glFlush();
    glfwSwapBuffers();

    if (glfwGetKey(GLFW_KEY_ESC) || !glfwGetWindowParam(GLFW_OPENED)) {
      glfwCloseWindow();
      return "terminate";
    }

    CurrentWindow->exec_callback("idle");
    return "continue";
  }
Example #5
0
QDomNode DataBackend::createObjectNode(QString name, DrawableObject n, QDomDocument * d)
{
	QDomElement out=d->createElement("fizzix_object");
	out.setAttribute("name",name);
	std::vector<std::string> v=n.getSetProperties();
	for(unsigned int i=0; i<v.size(); i++)
		out.appendChild(createConstantNode(QString::fromStdString(v.at(i)),n[v.at(i)],d));
	return out;
}
bool Turret::canFollowTarget(DrawableObject & target, bool TargetInvisible)
{
	float distance = (float)sqrt(pow(target.getPosition().x - _position.x,2) +
			pow(target.getPosition().y - _position.y, 2));
	Angle direction = (float)atan2(_position.y - target.getPosition().y,
			_position.x - target.getPosition().x) / _pi * 180 ;

	if(distance < _lockDistance && (direction.getAngle() - DrawableObject::_direction.getAngle() < 5
			&& direction.getAngle() - DrawableObject::_direction.getAngle() > -5)
			&& (direction > _range.x && direction < _range.y)
			&& !TargetInvisible)
	{
		DrawableObject::_direction = direction;
		return true;
	}
	else
		return false;
}
Example #7
0
void MainWindow::drawSingleObject(cairo_t *cr, DrawableObject object) {
    vector<Coordinate> coords = object.coords();

    cairo_move_to(cr, coords[0]._x, coords[0]._y);
    cairo_line_to(cr, coords.front()._x, coords.front()._y);

    for (uint i = 1; i < coords.size(); i++) {
        cairo_line_to(cr, coords[i]._x, coords[i]._y);
    }

    if (coords.size() == 1)
        cairo_line_to(cr, coords[0]._x + 1, coords[0]._y + 1);
    else if (object.type() == polygon)
        cairo_line_to(cr, coords.front()._x, coords.front()._y);

//	if(object.filled())
//		cairo_fill(cr);

    cairo_stroke(cr);
}
int SceneLoader::LoadFile(const char* filename)
{
	Assimp::Importer importer;

	const aiScene *scene = importer.ReadFile(filename, 0);
	scene = importer.ApplyPostProcessing(aiProcess_CalcTangentSpace | aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_JoinIdenticalVertices);
	if (!scene)
	{
		std::stringstream oss;
		oss << "ERROR - File: " << filename << " not found." << std::endl;
		std::string debugMsg(oss.str());
		OutputDebugStringA(debugMsg.c_str());
		return false;
	}
	DrawableObject *newObject = new DrawableObject();
	std::vector<Vertex> vertexList;
	std::vector<UINT> indexList;
	std::stringstream oss;
	for (unsigned int i = 0; i < scene->mRootNode->mNumChildren; ++i)
	{
		bool successfulLoad = true;
		aiNode* currentNode = scene->mRootNode->mChildren[i];
		BuildShaders(d3dDevice, *newObject, mShaderManager);
		for (unsigned int j = 0; j < currentNode->mNumMeshes; ++j)
		{
			ProcessMesh(d3dDevice, *scene->mMeshes[currentNode->mMeshes[j]], *newObject, vertexList, indexList, scene->mMeshes[currentNode->mMeshes[j]]->mMaterialIndex - 1);
			//LoadMaterials(d3dDevice, scene->mMeshes[currentNode->mMeshes[j]]->mMaterialIndex, *newObject, scene);
			oss << "MatIndex = " << scene->mMeshes[currentNode->mMeshes[j]]->mMaterialIndex << "\n";
		}
	}
	std::string debugMsg(oss.str());
	OutputDebugStringA(debugMsg.c_str());
	for (unsigned int i = 0; i < scene->mNumMaterials; ++i)
	{
		LoadMaterials(d3dDevice, i, *newObject, scene);
	}
	newObject->GetMeshData()->Initialize(d3dDevice, vertexList, indexList);
	mDrawableObjects.push_back(newObject);

	return mDrawableObjects.size() - 1;
}
Example #9
0
DrawableObject* ApplicationState::getObjectClicked()
{
  DrawableObject *  closestObject = NULL;
  DrawableObject *  clickedObject = NULL;
  int highestLayer = 0;
  for (auto it = clickableObjects.begin(); it != clickableObjects.end(); it++)
  {
    closestObject = it->second.findClosest(mousePosition);

    if (closestObject != NULL && closestObject->isClicked(mousePosition))
    {
      // remember the QuadTrees are indexed on their layers
      if (it->first > highestLayer)
      {
        clickedObject = closestObject;
        highestLayer = it->first;
      }
    }
  }
  return clickedObject;
}
void BuildShaders(ID3D11Device* d3dDevice, DrawableObject &inObject, ShaderManager* inShaderManager)
{
	ID3D11Buffer *newVSConstantBuffer, *newPSConstantBuffer;

	D3D11_INPUT_ELEMENT_DESC vertex1Desc[] = {
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "BINORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};

	inObject.SetVertexShader(inShaderManager->AddVertexShader("phongVSShadowMap.cso", vertex1Desc, 5));
	inObject.SetPixelShader(inShaderManager->AddPixelShader("phongPSShadowMap.cso"));

	//declare VS constant buffer description
	D3D11_BUFFER_DESC perObjectConstantBufferDesc;
	perObjectConstantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	perObjectConstantBufferDesc.ByteWidth = sizeof(perObjectCBVSStruct);
	perObjectConstantBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
	perObjectConstantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	perObjectConstantBufferDesc.MiscFlags = 0;
	perObjectConstantBufferDesc.StructureByteStride = 0;
	d3dDevice->CreateBuffer(&perObjectConstantBufferDesc, NULL, &newVSConstantBuffer);


	//declare PS constant buffer description
	perObjectConstantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	perObjectConstantBufferDesc.ByteWidth = sizeof(perObjectCBPSStruct);
	perObjectConstantBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
	perObjectConstantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	perObjectConstantBufferDesc.MiscFlags = 0;
	perObjectConstantBufferDesc.StructureByteStride = 0;

	d3dDevice->CreateBuffer(&perObjectConstantBufferDesc, NULL, &newPSConstantBuffer);

	inObject.SetVSConstantBuffer(newVSConstantBuffer);
	inObject.SetPSConstantBuffer(newPSConstantBuffer);
}
bool SceneLoader::ProcessMesh(ID3D11Device *ind3dDevice, aiMesh &inMesh , DrawableObject &inObject, std::vector<Vertex> &inVertexList, std::vector<UINT> &inIndexList, unsigned int inMaterialIndex)
{

	int inPrevIndexListSize = inIndexList.size();
	int inPrevVertexListSize = inVertexList.size();

	LoadVertices(inMesh, inVertexList, mSceneBoundingSphere);
	LoadIndices(inMesh, inIndexList);

	inObject.AddPart(inPrevVertexListSize, inPrevIndexListSize, inIndexList.size() - inPrevIndexListSize, inMaterialIndex);

	return true;
}
Example #12
0
void GLDrawPane::drawObject(const DrawableObject & obj)
{
	const vector<triangle*> & mesh = obj.getVertices();
	const vec3 & color = obj["SYSTEM_color"].vector/256.0;
	const vec3 & pos = obj.getPos();
	const vec3 npos(0,0,0);
	const Quaternion & q = obj.getQuaternion();
	if(isnan(pos.x)||isnan(pos.y)||isnan(pos.z))
		{drawObject(mesh, color, npos, q, obj.getProperty(HIDDEN), obj.getProperty(SMOOTH));}
	else
		{drawObject(mesh, color, pos, q, obj.getProperty(HIDDEN), obj.getProperty(SMOOTH));}
}
Example #13
0
int DrawableObject::_get_shader_(lua_State *L)
{
  DrawableObject *self = checkarg<DrawableObject>(L, 1);
  self->retrieve(self->shader);
  return 1;
}
Example #14
0
void  ApplicationState::addClickableObject(DrawableObject& clickable, int z)
{
  if (!clickable.isClickable())
    return;
  clickableObjects[z].insert(clickable);
}
Example #15
0
void DrawStack3D::updatePositions() {

	tilt*=0.95;

	int len = stack.length();

	float cosTilt = cos(tilt);
	float sinTilt = sin(tilt);

	for(int i = 0; i < len; i++) {
		DrawableObject* e = stack.getElement(i);

		vec3 charPos = e->getPosition();

		float dy = charPos.y-camera.y;
		float dx = charPos.x-camera.x;
		float dz = charPos.z-camera.z;

		float charAngle = atan2f(dy, dx);

		float dAngle = mod(angle, 2.0f*PI) - mod(charAngle, 2.0f*PI);

		//Clamp dAngle between -PI and PI
		if(dAngle > PI) {
			dAngle -= PI*2.0f;
		}

		if(dAngle < -PI) {
			dAngle += PI*2.0f;
		}

		float distance = length(vec3(dx, dy, dz));

		//Used for weapon 'raycasts'.
		e->setPlayerAngle2(charAngle);
		e->setPlayerAngle(dAngle);
		e->setPlayerDistance(distance);
		//

		float absDAngle = abs(dAngle);

		distance = length(vec3(dx, dy, dz));

		if(distance > DETAIL_OBJECT_DESTROY_DISTANCE && e->entityType == 1) {
			//Destroy detail object.
			e->destroy = true;
		}

		if(distance > 500.0f || dAngle > PI/2 || dAngle < -PI/2) {
			e->setVisibility(false);
		} else {
			e->setVisibility(true);

			//Fake some field of view perspective stuff.
			float dX = dAngle*FIELD_OF_VIEW_WIDTH*(0.9f+0.1f*abs(sin(dAngle)));

			float dZ = 400.0f*(dz)/distance;

			float scale = 1.0f/distance;


			if(distance < PI) {
				dZ += cos(distance/2.0f)*150.0f;
			}



			//Tilt offsets:
			float oX = -sinTilt*dZ+cosTilt*dX;
			float oY = sinTilt*dX+cosTilt*dZ;


			e->setImageParameters(vec2(640+oX, 360+oY), scale, tilt);
			e->priority = scale;
		}
	}
}
void LoadMaterials(ID3D11Device* d3dDevice, int inIndex, DrawableObject &inObject, const aiScene *inScene)
{
	aiString texPath, normTexPath;
	aiReturn hasTex = inScene->mMaterials[inIndex]->GetTexture(aiTextureType_DIFFUSE, 0, &texPath);
	if (hasTex == AI_SUCCESS)
	{
		wchar_t texPathW[150];

		//std::string texPathString = "dabrovic-sponza/01_STUB.dds";

		MultiByteToWideChar(CP_ACP, 0, texPath.C_Str(), -1, texPathW, 150);

		ID3D11Resource *texture, *textureNorm;
		ID3D11ShaderResourceView *newDiffuseShaderResourceView, *newNormalMapShaderResourceView;
		HRESULT hr = CreateDDSTextureFromFile(d3dDevice, texPathW, &texture, &newDiffuseShaderResourceView);
		if (FAILED(hr))
		{
			CreateDDSTextureFromFile(d3dDevice, L"texture_missing.dds", &texture, &newDiffuseShaderResourceView);
			std::stringstream oss;
			oss << "ERROR - Texture: " << texPathW << " not found." << std::endl;
			std::string debugMsg(oss.str());
			OutputDebugStringA(debugMsg.c_str());
		}
		std::string normTexPath = std::string(texPath.C_Str());
		normTexPath.resize(normTexPath.length() - 4); // remove the .dds
		normTexPath += "_normal.dds";

		//normTexPath = "dabrovic-sponza/01_STUB_normal.dds";

		MultiByteToWideChar(CP_ACP, 0, normTexPath.c_str(), -1, texPathW, 150);

		hr = CreateDDSTextureFromFile(d3dDevice, texPathW, &textureNorm, &newNormalMapShaderResourceView);
		if (FAILED(hr))
		{
			std::stringstream oss;
			oss << "ERROR - Normal Texture: " << texPathW << " not found." << std::endl;
			std::string debugMsg(oss.str());
			OutputDebugStringA(debugMsg.c_str());
			CreateDDSTextureFromFile(d3dDevice, L"texture_missing_normal.dds", &textureNorm, &newNormalMapShaderResourceView);
		}

		D3D11_SAMPLER_DESC textureSamplerDesc;
		ZeroMemory(&textureSamplerDesc, sizeof(textureSamplerDesc));
		textureSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
		textureSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
		textureSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
		textureSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
		textureSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
		textureSamplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

		ID3D11SamplerState *newSamplerState;
		d3dDevice->CreateSamplerState(&textureSamplerDesc, &newSamplerState);

		ZeroMemory(&textureSamplerDesc, sizeof(textureSamplerDesc));
		textureSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
		textureSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
		textureSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
		textureSamplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
		textureSamplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
		ZeroMemory(textureSamplerDesc.BorderColor, 4);

		ID3D11SamplerState *newShadowSamplerState;
		d3dDevice->CreateSamplerState(&textureSamplerDesc, &newShadowSamplerState);

		D3D11_TEXTURE2D_DESC textureDesc;
		reinterpret_cast<ID3D11Texture2D*>(texture)->GetDesc(&textureDesc);
		texture->Release();
		reinterpret_cast<ID3D11Texture2D*>(textureNorm)->GetDesc(&textureDesc);
		textureNorm->Release();

		inObject.AddTexture(newDiffuseShaderResourceView, newNormalMapShaderResourceView);
		inObject.SetTextureSamplerState(newSamplerState);
		inObject.SetShadowSamplerState(newShadowSamplerState);
	}
	hasTex = inScene->mMaterials[inIndex]->GetTexture(aiTextureType_NORMALS, 0, &texPath);
	if (hasTex == AI_SUCCESS)
	{
		wchar_t texPathW[100];
		MultiByteToWideChar(CP_ACP, 0, texPath.C_Str(), -1, texPathW, 100);

		ID3D11Resource *texture0;
		ID3D11ShaderResourceView *newShaderResourceView;
		HRESULT hr = CreateDDSTextureFromFile(d3dDevice, texPathW, &texture0, &newShaderResourceView);
		if (FAILED(hr))
		{
			CreateDDSTextureFromFile(d3dDevice, L"texture_missing.dds", &texture0, &newShaderResourceView);
		}
		D3D11_SAMPLER_DESC textureSamplerDesc;
		ZeroMemory(&textureSamplerDesc, sizeof(textureSamplerDesc));
		textureSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
		textureSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
		textureSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
		textureSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
		textureSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
		textureSamplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

		ID3D11SamplerState *newSamplerState;
		d3dDevice->CreateSamplerState(&textureSamplerDesc, &newSamplerState);

		D3D11_TEXTURE2D_DESC textureDesc;
		reinterpret_cast<ID3D11Texture2D*>(texture0)->GetDesc(&textureDesc);
		texture0->Release();

		//inObject.SetDiffuseResourceView(newShaderResourceView);
		inObject.SetTextureSamplerState(newSamplerState);
	}
	aiColor3D ambientColor, diffuseColor, specularColor;
	float shininess;
	inScene->mMaterials[inIndex]->Get(AI_MATKEY_COLOR_AMBIENT, ambientColor);
	inScene->mMaterials[inIndex]->Get(AI_MATKEY_COLOR_DIFFUSE, diffuseColor);
	inScene->mMaterials[inIndex]->Get(AI_MATKEY_COLOR_SPECULAR, specularColor);
	inScene->mMaterials[inIndex]->Get(AI_MATKEY_SHININESS, shininess);

	inObject.SetMaterial(ambientColor, diffuseColor, specularColor, shininess);
}
Example #17
0
int DrawableObject::_set_shader_(lua_State *L)
{
  DrawableObject *self = checkarg<DrawableObject>(L, 1);
  self->shader = self->replace(self->shader, 2);
  return 0;
}
Example #18
0
/*****************************************************************************\
	Compute the distance metrics for each entry in the display list 
	given the new view point.  Entries below the bottom Z value given will
	be removed from the list and placed into the "lowList" chain.  Entries
	which are too high will go into the "highList" chain.
\*****************************************************************************/
void ObjectDisplayList::UpdateMetrics( long listNo, const Tpoint *pos, TransportStr *transList )
{
	register float	x = pos->x;
	register float	y = pos->y;
//	register float	z = pos->z;

	DrawableObject	*p;
	DrawableObject	*q;

	long			i;

	// Quit now if we don't have at least one list entry
	if ( !head ) return;

	
#ifdef _SANITY_CHECK_
	if ( head )
	{
		DrawableObject *_cur_;
		long count=0;

		// Sanity checks
		if (head->parentList != this)
			return;
		if(head->prev)
		{

			head->prev=NULL;
		}
		_cur_=head;
		while(_cur_ && count < 10000)
		{
			if (_cur_->parentList != this)
				return;
			_cur_=_cur_->next;
			count++;
		}
		if(_cur_)
		{
			head->prev=NULL; // painless breakpoint
		}
	}
#endif

	// Run through the whole list and compute the sorting metrics for each entry
	q = head;
	while ( q ) {

		p=q;
		q=q->next;

		// Update the distance metric (not less than 0)
		p->distance = max( (float)fabs(x - p->position.x), (float)fabs(y - p->position.y) );
		ShiAssert(!_isnan(p->distance));
		if(_isnan(p->distance))
		{
			p->distance = 0.0f;
		}
		else if (p->distance > p->Radius())
		{
			p->distance = p->distance - p->Radius();
		}
		else
		{
			p->distance = 0.0f;
		}

		if (transList)
		{
			if (p->position.z >= transList->bottom[listNo] && listNo)
			{
				i=listNo-1;
				while(i > 0 && p->position.z >= transList->bottom[i])
					i--;
				// remove object from objectList
				RemoveObject(p);
				// head insert object into transport list
				p->next=transList->list[i];
				transList->list[i]=p;
			}
			else if(p->position.z < transList->top[listNo] && listNo < (_NUM_OBJECT_LISTS_-1))
			{
				i=listNo+1;
				while(i < (_NUM_OBJECT_LISTS_-1) && p->position.z < transList->top[i])
					i++;
				// remove object from objectList
				RemoveObject(p);
				// head insert object into transport list
				p->next=transList->list[i];
				transList->list[i]=p;
			}
		}
	}

#ifdef _SANITY_CHECK_
	if ( head )
	{
		DrawableObject *_cur_;
		long count=0;

		// Sanity checks
		if(head->prev)
		{
			head->prev=NULL;
		}
		_cur_=head;
		while(_cur_ && count < 10000)
		{
			_cur_=_cur_->next;
			count++;
		}
		if(_cur_)
		{
			head->prev=NULL; // painless breakpoint
		}
	}
#endif

	// Now call anyone who has registered for a callback
	for (UpdateCallBack	*nextCall = updateCBlist; nextCall; nextCall = nextCall->next) {
		nextCall->fn( nextCall->self, listNo, pos, transList );
	}
}