Example #1
0
float MenuItemColour::ListDraw(bool selected, const MFVector &_pos, float maxWidth)
{
	MFVector pos = _pos;

	MFFont_DrawText(MFFont_GetDebugFont(), pos+MakeVector(0.0f, MENU_FONT_HEIGHT*0.25f, 0.0f), MENU_FONT_HEIGHT, selected ? MakeVector(1,1,0,1) : MFVector::one, MFStr("%s: 0x%08X", name, pData->ToPackedColour()));

	pos += MakeVector(maxWidth - 55.0f, 2.0f, 0.0f);

	MFPrimitive(PT_TriStrip|PT_Untextured);

	MFBegin(4);
	MFSetColourV(MFVector::white);
	MFSetPositionV(pos);
	MFSetPositionV(pos + MakeVector(45.0f, 0.0f, 0.0f));
	MFSetPositionV(pos + MakeVector(0.0f, MENU_FONT_HEIGHT*1.5f-4.0f, 0.0f));
	MFSetPositionV(pos + MakeVector(45.0f, MENU_FONT_HEIGHT*1.5f-4.0f, 0.0f));
	MFEnd();

	pos += MakeVector(2.0f, 2.0f, 0.0f);

	MFBegin(4);
	MFSetColourV(*pData);
	MFSetPositionV(pos);
	MFSetPositionV(pos + MakeVector(41.0f, 0.0f, 0.0f));
	MFSetPositionV(pos + MakeVector(0.0f, MENU_FONT_HEIGHT*1.5f-8.0f, 0.0f));
	MFSetPositionV(pos + MakeVector(41.0f, MENU_FONT_HEIGHT*1.5f-8.0f, 0.0f));
	MFEnd();

	return MENU_FONT_HEIGHT*1.5f;
}
void MFParticleSystem_DrawRotating(MFParticleSystem *pParticleSystem, const MFMatrix &ltv)
{
	int numParticles = pParticleSystem->particles.GetLength();
	if(!numParticles)
		return;

	float fadeStart = pParticleSystem->params.life - pParticleSystem->params.fadeDelay;

	MFMaterial_SetMaterial(pParticleSystem->pMaterial);

	MFPrimitive(PT_TriList, 0);
	MFBegin(numParticles * 6);

	MFParticle **ppI = pParticleSystem->particles.Begin();

	while(*ppI)
	{
		MFParticle *pParticle = *ppI;

		float dt = MFSystem_TimeDelta();

		pParticle->rot += pParticleSystem->params.rotationRate * dt;
		pParticle->size += pParticleSystem->params.scaleRate * dt;
		pParticle->velocity += pParticleSystem->params.force * dt;
		pParticle->pos += pParticle->velocity * dt;

		float t = pParticle->size * 0.5f;
		float rad = MFSqrt(t*t*2);
		float xoff = MFCos(-pParticle->rot + 0.7853981f)*rad;
		float yoff = MFSin(-pParticle->rot + 0.7853981f)*rad;
		float alpha = MFMin(pParticle->life / fadeStart, 1.0f);

		MFVector pos = ApplyMatrixH(pParticle->pos, ltv);

		MFSetColourV(MakeVector(pParticle->colour, pParticle->colour.w * alpha));
		MFSetTexCoord1(1, 0);
		MFSetPosition(pos.x + xoff, pos.y + yoff, pos.z);
		MFSetTexCoord1(0, 1);
		MFSetPosition(pos.x - xoff, pos.y - yoff, pos.z);
		MFSetTexCoord1(0, 0);
		MFSetPosition(pos.x - yoff, pos.y + xoff, pos.z);
		MFSetTexCoord1(1, 0);
		MFSetPosition(pos.x + xoff, pos.y + yoff, pos.z);
		MFSetTexCoord1(1, 1);
		MFSetPosition(pos.x + yoff, pos.y - xoff, pos.z);
		MFSetTexCoord1(0, 1);
		MFSetPosition(pos.x - xoff, pos.y - yoff, pos.z);

		pParticle->life -= dt;
		if(pParticle->life < 0.0f)
			pParticleSystem->particles.Destroy(ppI);

		ppI++;
	}

	MFEnd();
}
Example #3
0
void DrawRing(float x, float z, float size, bool dark = false)
{
	MFPrimitive(PT_TriStrip, 0);
	MFBegin(4);
	MFSetColourV(MFVector::white * (dark ? 0.6f : 1.0f));
	MFSetTexCoord1(0.0f, 0.0f);
	MFSetPosition(x, z, size*0.5f);
	MFSetTexCoord1(1.0f, 0.0f);
	MFSetPosition(x + size, z, size*0.5f);
	MFSetTexCoord1(0.0f, 1.0f);
	MFSetPosition(x, z, -size*0.5f);
	MFSetTexCoord1(1.0f, 1.0f);
	MFSetPosition(x + size, z, -size*0.5f);
	MFEnd();
}
Example #4
0
void MFCollision_DrawItem(MFCollisionItem *pItem)
{
	// maybe reject it if its not in range..

	MFVector colour = (pItem->flags & MFCIF_Disabled) ? MakeVector(1,0,0,1) : ((pItem->flags & MFCIF_Dynamic) ? MakeVector(0,0,1,1) : MakeVector(0,1,0,1));

	MFMaterial_SetMaterial(MFMaterial_GetStockMaterial(MFMat_White));

	switch(pItem->pTemplate->type)
	{
		case MFCT_Sphere:
		{
			MFCollisionSphere *pSphere = (MFCollisionSphere*)pItem->pTemplate->pCollisionTemplateData;

			MFPrimitive_DrawSphere(MFVector::zero, pSphere->radius, 8, 7, colour, pItem->worldPos, true);
			break;
		}
		case MFCT_Mesh:
		{
			MFCollisionMesh *pMesh = (MFCollisionMesh*)pItem->pTemplate->pCollisionTemplateData;
			int a;

			// draw each triangle
			MFPrimitive(PT_TriList);
			MFSetMatrix(pItem->worldPos);
			MFBegin(pMesh->numTris * 3);
			MFSetColour(1.0f, 1.0f, 1.0f, 0.5f);

			for(a=0; a<pMesh->numTris; a++)
			{
				if(pMesh->pTriangles[a].flags)
					MFSetColour(1.0f, 0.0f, 0.0f, 0.5f);

				MFSetPositionV(pMesh->pTriangles[a].verts[0]);
				MFSetPositionV(pMesh->pTriangles[a].verts[1]);
				MFSetPositionV(pMesh->pTriangles[a].verts[2]);

				if(pMesh->pTriangles[a].flags)
				{
					MFSetColour(1.0f, 1.0f, 1.0f, 0.5f);
					pMesh->pTriangles[a].flags = 0;
				}
			}

			MFEnd();

			// draw each triangle outline
			MFPrimitive(PT_LineList);
			MFSetMatrix(pItem->worldPos);
			MFBegin(pMesh->numTris * 12);
			MFSetColourV(colour);

			for(a=0; a<pMesh->numTris; a++)
			{
				MFSetPositionV(pMesh->pTriangles[a].verts[0]);
				MFSetPositionV(pMesh->pTriangles[a].verts[1]);
				MFSetPositionV(pMesh->pTriangles[a].verts[1]);
				MFSetPositionV(pMesh->pTriangles[a].verts[2]);
				MFSetPositionV(pMesh->pTriangles[a].verts[2]);
				MFSetPositionV(pMesh->pTriangles[a].verts[0]);

				MFVector e1, e2, e3;

				e1 = (pMesh->pTriangles[a].verts[0] + pMesh->pTriangles[a].verts[1]) * 0.5f;
				e2 = (pMesh->pTriangles[a].verts[1] + pMesh->pTriangles[a].verts[2]) * 0.5f;
				e3 = (pMesh->pTriangles[a].verts[2] + pMesh->pTriangles[a].verts[0]) * 0.5f;

				MFSetPositionV(e1);
				MFSetPositionV(e1 + pMesh->pTriangles[a].edgePlanes[0] * 2.0f);
				MFSetPositionV(e2);
				MFSetPositionV(e2 + pMesh->pTriangles[a].edgePlanes[1] * 2.0f);
				MFSetPositionV(e3);
				MFSetPositionV(e3 + pMesh->pTriangles[a].edgePlanes[2] * 2.0f);

//				MFVector c = (pMesh->pTriangles[a].verts[0] + pMesh->pTriangles[a].verts[1] + pMesh->pTriangles[a].verts[2]) * (1.0f / 3.0f);

//				MFSetPosition(c);
//				MFSetPosition(c + pMesh->pTriangles[a].plane*3.0f);
			}

			MFEnd();
			break;
		}
		case MFCT_Field:
			break;
		default:
			break;
	}
}
Example #5
0
void Menu::Draw()
{
	MFVector dimensions = MakeVector(0.0f, 0.0f, 0.0f);
	MFVector currentPos;
	float requestedWidth = menuDimensions.x-40.0f;
	float selStart, selEnd;
	int a;

	// get menu size
	for(a=0; a<numChildren; a++)
	{
		MFVector dim = pChildren[a]->GetDimensions(requestedWidth);

		if(selection==a)
		{
			selStart = dimensions.y;
			selEnd = selStart + dim.y;

			if(selStart < -yOffset)
			{
				targetOffset = -selStart;
			}

			if(selEnd > menuDimensions.y - 75.0f - yOffset)
			{
				targetOffset = -(selEnd-(menuDimensions.y-75.0f));
			}
		}

		dimensions.y += dim.y;
		dimensions.x = MFMax(dimensions.x, dim.x);
	}

	if(targetOffset != yOffset)
	{
		yOffset -= MFAbs(yOffset-targetOffset) < 0.1f ? yOffset-targetOffset : (yOffset-targetOffset)*0.1f;
	}

	currentPos = MakeVector(menuPosition.x+20.0f, menuPosition.y+50.0f + yOffset, 0.0f);

	MFPrimitive(PT_TriStrip|PT_Untextured);

	MFBegin(4);
	MFSetColourV(colour*0.4f);
	MFSetPosition(menuPosition.x, menuPosition.y, 0);
	MFSetColourV(colour*0.8f);
	MFSetPosition(menuPosition.x+menuDimensions.x, menuPosition.y, 0);
	MFSetColourV(colour*0.6f);
	MFSetPosition(menuPosition.x, menuPosition.y+menuDimensions.y, 0);
	MFSetColourV(colour);
	MFSetPosition(menuPosition.x+menuDimensions.x, menuPosition.y+menuDimensions.y, 0);
	MFEnd();

	MFFont_DrawText2(MFFont_GetDebugFont(), menuPosition.x+10.0f, menuPosition.y+5.0f, MENU_FONT_HEIGHT*1.5f, MakeVector(1,0.6875f,0.5f,1), name);

	MFMaterial_SetMaterial(MFMaterial_GetStockMaterial(MFMat_SysLogoSmall));
	float logoMargin = 5.0f;
	float iconSize = 35.0f;

	MFPrimitive(PT_TriStrip);
	MFBegin(4);
	MFSetColourV(MFVector::white);
	MFSetTexCoord1(0,0);
	MFSetPosition((menuPosition.x+menuDimensions.x) - logoMargin*2 - iconSize, menuPosition.y + logoMargin, 0);
	MFSetTexCoord1(1,0);
	MFSetPosition((menuPosition.x+menuDimensions.x) - logoMargin*2, menuPosition.y + logoMargin, 0);
	MFSetTexCoord1(0,1);
	MFSetPosition((menuPosition.x+menuDimensions.x) - logoMargin*2 - iconSize, menuPosition.y + logoMargin + iconSize, 0);
	MFSetTexCoord1(1,1);
	MFSetPosition((menuPosition.x+menuDimensions.x) - logoMargin*2, menuPosition.y + logoMargin + iconSize, 0);
	MFEnd();

#if MF_RENDERER == MF_DRIVER_D3D9 || MF_RENDERER == MF_DRIVER_XBOX
	pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
	pd3dDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
	pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);
#endif

	MFPrimitive(PT_TriStrip|PT_Untextured);
	MFBegin(4);
	MFSetColour(0.f, 0.f, 0.f, 0.65f);
	MFSetPosition(menuPosition.x+15, menuPosition.y+45, 0);
	MFSetPosition(menuPosition.x+menuDimensions.x-15, menuPosition.y+45, 0);
	MFSetPosition(menuPosition.x+15, menuPosition.y+menuDimensions.y-15, 0);
	MFSetPosition(menuPosition.x+menuDimensions.x-15, menuPosition.y+menuDimensions.y-15, 0);
	MFEnd();

#if MF_RENDERER == MF_DRIVER_D3D9 || MF_RENDERER == MF_DRIVER_XBOX
	pd3dDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_LESS);
	pd3dDevice->SetRenderState(D3DRS_STENCILREF, 0);
#endif

	for(a=0; a<numChildren; a++)
	{
		if(currentPos.y > menuPosition.y + menuDimensions.y - 15.0f) break;

		if(selection==a)
		{
			float height = pChildren[a]->GetDimensions(requestedWidth).y;

			if(currentPos.y + height < menuPosition.y + 45.0f)
			{
				currentPos.y += height;
				continue;
			}

			MFPrimitive(PT_TriStrip|PT_Untextured);

			MFBegin(4);
			MFSetColour(0.f, 0.f, .5f, .75f);
			MFSetPosition(menuPosition.x+15, currentPos.y, 0);
			MFSetColour(0.f, 0.f, .8f, .75f);
			MFSetPosition(menuPosition.x+menuDimensions.x-15, currentPos.y, 0);
			MFSetColour(0.f, 0.f, .56f, .75f);
			MFSetPosition(menuPosition.x+15, currentPos.y + height, 0);
			MFSetColour(0.f, 0.f, .1f, .75f);
			MFSetPosition(menuPosition.x+menuDimensions.x-15, currentPos.y + height, 0);
			MFEnd();
		}

		currentPos.y += pChildren[a]->ListDraw(selection==a, currentPos, requestedWidth);
	}

#if MF_RENDERER == MF_DRIVER_D3D9 || MF_RENDERER == MF_DRIVER_XBOX
	pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
#endif
}
Example #6
0
void dBFrame::Draw()
{
	if(!pMat)
	{
		MFPrimitive_DrawUntexturedQuad(rect.x-10, rect.y-10, rect.width+20, rect.height+20, colours[0]);
	}
	else
	{
		// draw background
		float x, y, xRemaining, yRemaining;

		// calculate number of tiles (including edges)
		int h = (int)MFCeil(rect.width / borderWidth);
		int w = (int)MFCeil(rect.height / borderWidth);
		int numTiles = (h + 2) * (w + 2);

		// begin immediate renderer
		MFMaterial_SetMaterial(pMat);
		MFPrimitive(PT_QuadList);
		MFBegin(numTiles*2);

		MFSetColourV(colours[0]);

		// render tiled background
		yRemaining = rect.height;
		for(y = 0.0f; y < rect.height; y += borderWidth)
		{
			xRemaining = rect.width;
			for(x = 0.0f; x < rect.width; x += borderWidth)
			{
				float xuv = xRemaining < borderWidth ? 0.25f * (xRemaining / borderWidth) : 0.25f;
				float yuv = yRemaining < borderWidth ? 0.25f * (yRemaining / borderWidth) : 0.25f;

				MFSetTexCoord1(0.25f, 0.25f);
				MFSetPosition(rect.x + x, rect.y + y, 0);
				MFSetTexCoord1(0.25f + xuv, 0.25f + yuv);		
				MFSetPosition(rect.x + x + MFMin(borderWidth, xRemaining), rect.y + y + MFMin(borderWidth, yRemaining), 0);

				xRemaining -= borderWidth;
			}

			yRemaining -= borderWidth;
		}

		// draw frame
		// draw corners
		MFSetTexCoord1(0.0f, 0.0f);
		MFSetPosition(rect.x - borderWidth, rect.y - borderWidth, 0.0f);
		MFSetTexCoord1(0.25f, 0.25f);		
		MFSetPosition(rect.x, rect.y, 0.0f);
		MFSetTexCoord1(0.5f, 0.0f);
		MFSetPosition(rect.x + rect.width, rect.y - borderWidth, 0.0f);
		MFSetTexCoord1(0.75f, 0.25f);		
		MFSetPosition(rect.x + rect.width + borderWidth, rect.y, 0.0f);
		MFSetTexCoord1(0.0f, 0.50f);
		MFSetPosition(rect.x - borderWidth, rect.y + rect.height, 0.0f);
		MFSetTexCoord1(0.25f, 0.75f);		
		MFSetPosition(rect.x, rect.y + rect.height + borderWidth, 0.0f);
		MFSetTexCoord1(0.5f, 0.5f);
		MFSetPosition(rect.x + rect.width, rect.y + rect.height, 0.0f);
		MFSetTexCoord1(0.75f, 0.75f);		
		MFSetPosition(rect.x + rect.width + borderWidth, rect.y + rect.height + borderWidth, 0.0f);

		// draw vertical edges
		yRemaining = rect.height;
		for(y = 0.0f; y < rect.height; y += borderWidth)
		{
			float yuv = yRemaining < borderWidth ? 0.25f * (yRemaining / borderWidth) : 0.25f;

			MFSetTexCoord1(0.0f, 0.25f);
			MFSetPosition(rect.x - borderWidth, rect.y + y, 0.0f);
			MFSetTexCoord1(0.25f, 0.25f + yuv);		
			MFSetPosition(rect.x, rect.y + y + MFMin(borderWidth, yRemaining), 0.0f);

			MFSetTexCoord1(0.5f, 0.25f);
			MFSetPosition(rect.x + rect.width, rect.y + y, 0.0f);
			MFSetTexCoord1(0.75f, 0.25f + yuv);		
			MFSetPosition(rect.x + rect.width + borderWidth, rect.y + y + MFMin(borderWidth, yRemaining), 0.0f);

			yRemaining -= borderWidth;
		}

		// draw horizontal edges
		xRemaining = rect.width;
		for(x = 0.0f; x < rect.width; x += borderWidth)
		{
			float xuv = xRemaining < borderWidth ? 0.25f * (xRemaining / borderWidth) : 0.25f;

			MFSetTexCoord1(0.25f, 0.0f);
			MFSetPosition(rect.x + x, rect.y - borderWidth, 0.0f);
			MFSetTexCoord1(0.25f + xuv, 0.25f);		
			MFSetPosition(rect.x + x + MFMin(borderWidth, xRemaining), rect.y, 0.0f);

			MFSetTexCoord1(0.25f, 0.5f);
			MFSetPosition(rect.x + x, rect.y + rect.height, 0.0f);
			MFSetTexCoord1(0.25f + xuv, 0.75f);		
			MFSetPosition(rect.x + x + MFMin(borderWidth, xRemaining), rect.y + rect.height + borderWidth, 0.0f);

			xRemaining -= borderWidth;
		}

		MFEnd();
	}
}
MF_API void MFParticleSystem_Draw(MFParticleSystem *pParticleSystem)
{
	int numParticles = pParticleSystem->particles.GetLength();
	if(numParticles == 0)
		return;

	// render particles
	MFView_Push();

	MFMatrix ltv = MFView_GetWorldToViewMatrix();
	MFView_SetCameraMatrix(MFMatrix::identity);

	// update and draw each particle
	if(pParticleSystem->params.rotationRate != 0.0f)
	{
		MFParticleSystem_DrawRotating(pParticleSystem, ltv);
		MFView_Pop();
		return;
	}

	float fadeStart = pParticleSystem->params.life - pParticleSystem->params.fadeDelay;

	MFMaterial_SetMaterial(pParticleSystem->pMaterial);

	MFPrimitive(PT_QuadList, 0);
	MFBegin(numParticles * 2);

	MFParticle **ppI = pParticleSystem->particles.Begin();

	while(*ppI)
	{
		MFParticle *pParticle = *ppI;

		float dt = MFSystem_TimeDelta();

		pParticle->size += pParticleSystem->params.scaleRate * dt;
		pParticle->velocity += pParticleSystem->params.force * dt;
		pParticle->pos += pParticle->velocity * dt;

		float halfSize = pParticle->size * 0.5f;
		float alpha = MFMin(pParticle->life / fadeStart, 1.0f);

		MFVector pos = ApplyMatrixH(pParticle->pos, ltv);

		MFSetColourV(MakeVector(pParticle->colour, pParticle->colour.w * alpha));
		MFSetTexCoord1(0, 0);
		MFSetPosition(pos.x - halfSize, pos.y + halfSize, pos.z);
		MFSetTexCoord1(1, 1);
		MFSetPosition(pos.x + halfSize, pos.y - halfSize, pos.z);

		pParticle->life -= dt;
		if(pParticle->life < 0.0f)
			pParticleSystem->particles.Destroy(ppI);

		ppI++;
	}

	MFEnd();

	MFView_Pop();
}
Example #8
0
void Fretboard::Draw(float time, dBChart *pSong, int track)
{
	MFCALLSTACKc;

	MFView_Push();

	MFRect rect;
	MFView_GetViewport(&rect);

	float aspect = rect.width / rect.height;
	aspect = MFClamp(0.82f, aspect, 2.0f);
	MFView_SetAspectRatio(aspect);

	if(viewPoint == 0)
	{
		// incoming
		MFView_ConfigureProjection(MFDEGREES(65.0f)/aspect, 1.0f, 100.0f);

		// Setup the Camera in 3D space.
		MFMatrix cameraMatrix;
		MFVector start = MakeVector( 0, 8, 3 );
		MFVector dir = MakeVector( 0, 5, -8 );
		dir = (dir-start) * (1.0f/1.777777777f);
		cameraMatrix.LookAt(start + dir*aspect, MakeVector(0.0f, 0.0f, 5.0f));
		MFView_SetCameraMatrix(cameraMatrix);
	}
	else if(viewPoint == 1)
	{
		// overhead
		MFView_ConfigureProjection(MFDEGREES(45.0f), 1.0f, 100.0f);
/*
		float aspect = MFDisplay_GetNativeAspectRatio();
		MFView_SetAspectRatio(aspect);

		MFRect projRect;
		projRect.y = 15;
		projRect.height = -30;
		projRect.x = -projRect.y * aspect;
		projRect.width = -projRect.height * aspect;
		MFView_SetOrtho(&projRect);
*/

		// Setup the Camera in 3D space.
		MFMatrix cameraMatrix;
		cameraMatrix.LookAt(MakeVector(0, 30, 10), MakeVector(0, 0, 10), MakeVector(0, 0, 1));
		MFView_SetCameraMatrix(cameraMatrix);
	}
	else if(viewPoint == 2)
	{
		// overhead
		MFView_ConfigureProjection(MFDEGREES(45.0f), 1.0f, 100.0f);
/*
		float aspect = MFDisplay_GetNativeAspectRatio();
		MFView_SetAspectRatio(aspect);

		MFRect projRect;
		projRect.y = 15;
		projRect.height = -30;
		projRect.x = -projRect.y * aspect;
		projRect.width = -projRect.height * aspect;
		MFView_SetOrtho(&projRect);
*/

		// Setup the Camera in 3D space.
		MFMatrix cameraMatrix;
		cameraMatrix.LookAt(MakeVector(0, 20, 13), MakeVector(0, 0, 13), MakeVector(-1, 0, 0));
		MFView_SetCameraMatrix(cameraMatrix);
	}

	MFView_SetProjection();

	MFMaterial *pFB = pSong->pFretboard ? pSong->pFretboard : pFretboard;
	MFMaterial_SetMaterial(pFB);
	MFPrimitive(PT_TriStrip, 0);

	int start = -4;
	int end = 60;
	int fadeStart = end - 10;

	float fretboardRepeat = 15.0f;
	float fretboardWidth = 7.0f;

	float columnWidth = fretboardWidth / 5.0f;
	float ringBorder = 0.1f;

	// draw the fretboard...
	MFBegin(((end-start) / 4) * 2 + 2);
	MFSetColourV(MFVector::white);

	float halfFB = fretboardWidth*0.5f;

	float offset = time*scrollSpeed;
	float topTime = time + end/scrollSpeed;
	float bottomTime = time + start/scrollSpeed;

	int a;
	float textureOffset = fmodf(offset, fretboardRepeat);
	for(a=start; a<end; a+=4)
	{
		float z = (float)a;
		MFSetTexCoord1(1.0f, 1.0f - (z+textureOffset) / fretboardRepeat);
		MFSetPosition(halfFB, 0.0f, z);
		MFSetTexCoord1(0.0f, 1.0f - (z+textureOffset) / fretboardRepeat);
		MFSetPosition(-halfFB, 0.0f, z);
	}

	float z = (float)a;
	MFSetTexCoord1(1.0f, 1.0f - (z+textureOffset) / fretboardRepeat);
	MFSetPosition(halfFB, 0.0f, z);
	MFSetTexCoord1(0.0f, 1.0f - (z+textureOffset) / fretboardRepeat);
	MFSetPosition(-halfFB, 0.0f, z);

	MFEnd();

	// draw the selection region
	MFMaterial_SetMaterial(pFrets);
	MFPrimitive(PT_TriStrip, 0);

	if(gEditor.selectStart != gEditor.selectEnd)
	{
		float selectStartTime = GETSECONDS(pSong->CalculateTimeOfTick(gEditor.selectStart));
		float selectEndTime = GETSECONDS(pSong->CalculateTimeOfTick(gEditor.selectEnd));

		if(selectStartTime < topTime && selectEndTime > bottomTime)
		{
			selectStartTime = (MFMax(bottomTime, selectStartTime) - time) * scrollSpeed;
			selectEndTime = (MFMin(topTime, selectEndTime) - time) * scrollSpeed;

			MFBegin(4);
			MFSetColour(1.0f, 0.0f, 0.0f, 0.5f);
			MFSetPosition(-halfFB, 0.0f, selectEndTime);
			MFSetPosition(halfFB, 0.0f, selectEndTime);
			MFSetPosition(-halfFB, 0.0f, selectStartTime);
			MFSetPosition(halfFB, 0.0f, selectStartTime);
			MFEnd();
		}
	}

	// draw the fretboard edges and bar lines
	const float barWidth = 0.2f;

	MFMaterial_SetMaterial(pBar);
	MFPrimitive(PT_TriStrip, 0);

	MFBegin(4);
	MFSetColour(0.0f, 0.0f, 0.0f, 0.8f);
	MFSetTexCoord1(0,0);
	MFSetPosition(-halfFB, 0.0f, barWidth);
	MFSetTexCoord1(1,0);
	MFSetPosition(halfFB, 0.0f, barWidth);
	MFSetTexCoord1(0,1);
	MFSetPosition(-halfFB, 0.0f, -barWidth);
	MFSetTexCoord1(1,1);
	MFSetPosition(halfFB, 0.0f, -barWidth);
	MFEnd();

	MFMaterial_SetMaterial(pEdge);
	MFPrimitive(PT_TriStrip, 0);
	MFBegin(34);

	MFSetColour(0.0f, 0.0f, 0.0f, 0.3f);
	for(int col=1; col<5; col++)
	{
		if(col > 1)
			MFSetPosition(-halfFB + columnWidth*(float)col - 0.02f, 0.0f, (float)end);

		MFSetTexCoord1(0,0);
		MFSetPosition(-halfFB + columnWidth*(float)col - 0.02f, 0.0f, (float)end);
		MFSetTexCoord1(1,0);
		MFSetPosition(-halfFB + columnWidth*(float)col + 0.02f, 0.0f, (float)end);
		MFSetTexCoord1(0,1);
		MFSetPosition(-halfFB + columnWidth*(float)col - 0.02f, 0.0f, (float)start);
		MFSetTexCoord1(1,1);
		MFSetPosition(-halfFB + columnWidth*(float)col + 0.02f, 0.0f, (float)start);

		MFSetPosition(-halfFB + columnWidth*(float)col + 0.02f, 0.0f, (float)start);
	}
	MFSetColourV(MFVector::white);
	MFSetPosition(-halfFB - 0.1f, 0.0f, (float)end);

	MFSetTexCoord1(0,0);
	MFSetPosition(-halfFB - 0.1f, 0.0f, (float)end);
	MFSetTexCoord1(1,0);
	MFSetPosition(-halfFB + 0.1f, 0.0f, (float)end);
	MFSetTexCoord1(0,1);
	MFSetPosition(-halfFB - 0.1f, 0.0f, (float)start);
	MFSetTexCoord1(1,1);
	MFSetPosition(-halfFB + 0.1f, 0.0f, (float)start);

	MFSetPosition(-halfFB + 0.1f, 0.0f, (float)start);
	MFSetPosition(halfFB - 0.1f, 0.0f, (float)end);

	MFSetTexCoord1(0,0);
	MFSetPosition(halfFB - 0.1f, 0.0f, (float)end);
	MFSetTexCoord1(1,0);
	MFSetPosition(halfFB + 0.1f, 0.0f, (float)end);
	MFSetTexCoord1(0,1);
	MFSetPosition(halfFB - 0.1f, 0.0f, (float)start);
	MFSetTexCoord1(1,1);
	MFSetPosition(halfFB + 0.1f, 0.0f, (float)start);

	MFEnd();

	// draw the frets....
	MFMaterial_SetMaterial(pBar);
	MFPrimitive(PT_TriStrip, 0);

	int bottomTick = pSong->CalculateTickAtTime((int64)(bottomTime*1000000.0f));
	int res = pSong->GetRes();
	int ticks = bHalfFrets ? res/2 : res;
	int fretBeat = bottomTick + ticks - 1;
	fretBeat -= fretBeat % ticks;
	float fretTime = GETSECONDS(pSong->CalculateTimeOfTick(fretBeat));

	while(fretTime < topTime)
	{
		bool halfBeat = (fretBeat % res) != 0;
		bool bar = false;

		if(!halfBeat)
		{
			GHEvent *pLastTS = pSong->sync.GetMostRecentEvent(GHE_TimeSignature, fretBeat);

			if(pLastTS)
				bar = ((fretBeat - pLastTS->tick) % (pLastTS->parameter*res)) == 0;
			else if(fretBeat == 0)
				bar = true;
		}

		float bw = bar ? barWidth : barWidth*0.5f;
		MFBegin(4);

		float position = (fretTime - time) * scrollSpeed;

		if(!halfBeat)
			MFSetColourV(MFVector::white);
		else
			MFSetColourV(MakeVector(1,1,1,0.3f));
		MFSetTexCoord1(0,0);
		MFSetPosition(-halfFB, 0.0f, position + bw);
		MFSetTexCoord1(1,0);
		MFSetPosition(halfFB, 0.0f, position + bw);
		MFSetTexCoord1(0,1);
		MFSetPosition(-halfFB, 0.0f, position + -bw);
		MFSetTexCoord1(1,1);
		MFSetPosition(halfFB, 0.0f, position + -bw);

		MFEnd();

		fretBeat += ticks;
		fretTime = GETSECONDS(pSong->CalculateTimeOfTick(fretBeat));
	}

	// draw the notes...
	GHEventManager &noteStream = pSong->notes[track];
	GHEvent *pEv = noteStream.First();

	int64 topTimeus = (int64)(topTime*1000000.0f);
	while(pEv && pEv->time < topTimeus)
	{
		if((pEv->event == GHE_Note || pEv->event == GHE_Special) && pEv->tick + pEv->parameter >= bottomTick)
		{
			float evTime = GETSECONDS(pEv->time);

			// TODO: we need to calculate the end of the hold...
			float noteEnd = evTime;
			if(pEv->parameter)
				noteEnd = GETSECONDS(pSong->CalculateTimeOfTick(pEv->tick + pEv->parameter));

			if(pEv->event == GHE_Note && pEv->played != 1)
			{
				// draw a note
				int key = pEv->key;
				bool tap = false;

				// check if there is a previous note, and it is in range
				if(pEv->Prev() && pEv->Prev()->tick < pEv->tick && pEv->Prev()->tick > pEv->tick - (res/2) && pEv->Prev()->key != pEv->key
					&& (!pEv->Next() || !(pEv->Next()->tick == pEv->tick))
					&& !pEv->Prev()->parameter && !(pEv->Prev()->Prev() && pEv->Prev()->Prev()->tick == pEv->Prev()->tick))
				{
					tap = true;
				}

				int noteX = gConfig.controls.leftyFlip[0] ? 4-key : key;

				float position = (GETSECONDS(pEv->time) - time)*scrollSpeed;
				float xoffset = -halfFB + columnWidth*0.5f + (float)noteX*columnWidth;

				if(pEv->parameter)
				{
					MFMaterial_SetMaterial(pFrets);

					float whammyTop = (noteEnd - time)*scrollSpeed;

					MFPrimitive(PT_TriStrip, 0);

					// TODO: we could consider not drawing this part of the hold line.. seems reasonable that it terminates at the line...
					if(gEditor.state == GHPS_Stopped)
					{
						if(position < 0.0f)
						{
							MFBegin(4);
							MFSetColourV(gColours[key]);
							MFSetPosition(xoffset - 0.2f, 0.0f, MFMin(whammyTop, 0.0f));
							MFSetPosition(xoffset + 0.2f, 0.0f, MFMin(whammyTop, 0.0f));
							MFSetPosition(xoffset - 0.2f, 0.0f, position);
							MFSetPosition(xoffset + 0.2f, 0.0f, position);
							MFEnd();
						}
					}

					if(whammyTop > 0.0f)
					{
						// this half could have waves cruising down it if we wanted to support the whammy...
						MFBegin(4);
						MFSetColourV(gColours[key]);
						MFSetPosition(xoffset - 0.2f, 0.0f, MFMin(whammyTop, (float)end));
						MFSetPosition(xoffset + 0.2f, 0.0f, MFMin(whammyTop, (float)end));
						MFSetPosition(xoffset - 0.2f, 0.0f, MFMax(position, 0.0f));
						MFSetPosition(xoffset + 0.2f, 0.0f, MFMax(position, 0.0f));
						MFEnd();
					}
				}

				if(evTime >= bottomTime)
				{
					MFMatrix mat;
					mat.SetScale(MakeVector(0.5f/20, 0.5f/20, 0.5f/20));
					mat.Translate(MakeVector(xoffset, 0.03f, position));
					MFModel_SetWorldMatrix(pButton, mat);

					MFStateBlock *pSB = MFStateBlock_CreateTemporary(64);
					MFStateBlock_SetVector(pSB, MFSCV_DiffuseColour, pEv->played == -1 ? MakeVector(0.3f, 0.3f, 0.3f, 1.0f) : MFVector::white);
//					MFStateBlock_SetVector(pSB, MFSCV_DiffuseColour, position < 0.0f ? MakeVector(0.3f, 0.3f, 0.3f, 1.0f) : MFVector::white);

//					MFRenderer_SetRenderStateOverride(MFRS_MaterialOverride, (uint32&)(tap ? pButtonMat[key] : pButtonRing[key]));
					MFRenderer_AddModel(pButton, pSB, MFView_GetViewState());

					// render the note time
					if(bRenderNoteTimes)
					{
						MFView_Push();
						MFView_SetOrtho(&rect);

						MFVector pos;
						MFView_TransformPoint3DTo2D(MakeVector(xoffset, 0.0f, position), &pos);
						pos.x += 16.0f;
						pos.y -= 26.0f;

						int minutes = (int)(pEv->time / 60000000);
						int seconds = (int)((pEv->time % 60000000) / 1000000);
						int milliseconds = (int)((pEv->time % 1000000) / 1000);
						MFFont_DrawTextf(pText, pos, 20.0f, MFVector::yellow, "%s: %d:%02d.%d\nTick: %g", MFTranslation_GetString(pStrings, TRACK_TIME), minutes, seconds, milliseconds, (float)pEv->tick/res);

						MFView_Pop();
					}
				}
			}

			if(pEv->event == GHE_Special)
			{
//				static MFVector specialColours[3] = { MakeVector(1,0,0,1), MakeVector(1,1,0,1), MakeVector(0,0,1,1) };
//				static float specialX[3] = { halfFB + 0.2f, halfFB + 1, -halfFB - 1 };
//				static float specialWidth[3] = { 0.8f, 0.8f, 0.8f };
				static MFVector specialColours[3] = { MakeVector(1,0,0,0.5f), MakeVector(1,1,0,0.5f), MakeVector(0,0,1,0.5f) };
				static float specialX[3] = { -halfFB, halfFB - 0.8f, -halfFB };
				static float specialWidth[3] = { 0.8f, 0.8f, fretboardWidth };

				float bottom = (evTime - time)*scrollSpeed;
				float top = (noteEnd - time)*scrollSpeed;

				int key = pEv->key;

				MFMaterial_SetMaterial(pFrets);

				MFPrimitive(PT_TriStrip, 0);
				MFBegin(4);
				MFSetColourV(specialColours[key]);
				MFSetPosition(specialX[key], 0.0f, MFMin(top, (float)end));
				MFSetPosition(specialX[key]+specialWidth[key], 0.0f, MFMin(top, (float)end));
				MFSetPosition(specialX[key], 0.0f, MFMax(bottom, (float)start));
				MFSetPosition(specialX[key]+specialWidth[key], 0.0f, MFMax(bottom, (float)start));
				MFEnd();
			}
		}

		pEv = pEv->Next();
	}

//	MFRenderer_SetRenderStateOverride(MFRS_MaterialOverride, NULL);

	// draw circles at the bottom..
	MFMaterial_SetMaterial(pRing);
	for(int a=0; a<5; a++)
	{
		DrawRing(-halfFB + (float)a*columnWidth + columnWidth*ringBorder, 0.0f, columnWidth*(1.0f-ringBorder*2));
	}

	for(int a=0; a<5; a++)
	{
		dBControlType keys_righty[] = { dBCtrl_Edit_Note0, dBCtrl_Edit_Note1, dBCtrl_Edit_Note2, dBCtrl_Edit_Note3, dBCtrl_Edit_Note4 };
		dBControlType keys_lefty[] = { dBCtrl_Edit_Note4, dBCtrl_Edit_Note3, dBCtrl_Edit_Note2, dBCtrl_Edit_Note1, dBCtrl_Edit_Note0 };
		dBControlType *keys = gConfig.controls.leftyFlip[0] ? keys_lefty : keys_righty;

		int ringPos = gConfig.controls.leftyFlip[0] ? 4-a : a;

		MFMaterial_SetMaterial(pColourRing[a]);
		DrawRing(-halfFB + (float)ringPos*columnWidth, 0.0f, columnWidth, !TestControl(keys[a], GHCT_Hold));
	}

	// render trigger particles
	MFParticleSystem_Draw(pParticles);

	// render text and stuff
	MFView_SetOrtho(&rect);

	pEv = pSong->sync.GetNextEvent(bottomTick);

	while(pEv && pEv->time < topTimeus)
	{
		float evTime = GETSECONDS(pEv->time);

		if(evTime > bottomTime)
		{
			if(pEv->event == GHE_BPM)
			{
				float position = (evTime - time) * scrollSpeed;

				MFVector pos;
				MFView_TransformPoint3DTo2D(MakeVector(halfFB + 0.2f, 0.0f, position), &pos);
				pos.y -= 12.0f;
				MFFont_DrawTextf(pText, pos, 24.0f, MakeVector(0,0.5f,0,1), "%s: %g", MFTranslation_GetString(pStrings, TRACK_BPM), (float)pEv->parameter * 0.001f);
			}
			if(pEv->event == GHE_Anchor)
			{
				int minutes = (int)(pEv->time / 60000000);
				int seconds = (int)((pEv->time%60000000)/1000000);
				int milliseconds = (int)((pEv->time%1000000)/1000);

				float position = (evTime - time) * scrollSpeed;

				MFVector pos;
				MFView_TransformPoint3DTo2D(MakeVector(halfFB + 0.2f, 0.0f, position), &pos);
				pos.y -= 12.0f;
				MFFont_DrawTextf(pText, pos, 24.0f, MakeVector(0,0.5f,0,1), "A: %02d:%02d.%03d\n   %s: %g", minutes, seconds, milliseconds, MFTranslation_GetString(pStrings, TRACK_BPM), (float)pEv->parameter * 0.001f);
			}
			else if(pEv->event == GHE_TimeSignature)
			{
				float position = (evTime - time) * scrollSpeed;

				MFVector pos;
				MFView_TransformPoint3DTo2D(MakeVector(-halfFB - 0.2f, 0.0f, position), &pos);
				const char *pString = MFStr("TS: %d/4", pEv->parameter);
				pos.x -= MFFont_GetStringWidth(pText, pString, 24.0f);
				pos.y -= 12.0f;
				MFFont_DrawTextf(pText, pos, 24.0f, MFVector::yellow, pString);
			}
		}

		pEv = pEv->Next();
	}

	// render events
	pEv = pSong->events.GetNextEvent(bottomTick);

	int lastChecked = -1;
	float yEventOffset = -12.0f;
	while(pEv && pEv->time < topTimeus)
	{
		float evTime = GETSECONDS(pEv->time);

		if(evTime > bottomTime)
		{
			if(pEv->event == GHE_Event)
			{
				if(lastChecked != pEv->tick)
				{
					yEventOffset = -12.0f;
					lastChecked = pEv->tick;

					if(pSong->sync.FindEvent(GHE_TimeSignature, pEv->tick, 0))
					{
						yEventOffset -= 24.0f;
					}
				}

				float position = (evTime - time) * scrollSpeed;

				MFVector pos;
				MFView_TransformPoint3DTo2D(MakeVector(-halfFB - 0.2f, 0.0f, position), &pos);

				if(!MFString_CompareN(pEv->GetString(), "section ", 8))
				{
					// draw a line across?

					pos.x -= MFFont_GetStringWidth(pText, &pEv->GetString()[8], 24.0f);
					pos.y += yEventOffset;
					MFFont_DrawTextf(pText, pos, 24.0f, MFVector::blue, &pEv->GetString()[8]);
				}
				else
				{
					pos.x -= MFFont_GetStringWidth(pText, pEv->GetString(), 24.0f);
					pos.y += yEventOffset;
					MFFont_DrawTextf(pText, pos, 24.0f, MFVector::white, pEv->GetString());
				}

				yEventOffset -= 24.0f;
			}
		}

		pEv = pEv->Next();
	}

	// render track events
	pEv = pSong->notes[track].GetNextEvent(bottomTick);

	lastChecked = -1;
	yEventOffset = -12.0f;
	while(pEv && pEv->time < topTimeus)
	{
		float evTime = GETSECONDS(pEv->time);

		if(evTime > bottomTime)
		{
			if(pEv->event == GHE_Event)
			{
				if(lastChecked != pEv->tick)
				{
					yEventOffset = -12.0f;
					lastChecked = pEv->tick;

					if(pSong->sync.FindEvent(GHE_TimeSignature, pEv->tick, 0))
					{
						yEventOffset -= 24.0f;
					}

					GHEvent *pOther = pSong->events.FindEvent(GHE_Event, pEv->tick, 0);
					while(pOther && pOther->tick == pEv->tick)
					{
						yEventOffset -= 24.0f;
						pOther = pOther->Next();
					}
				}

				float position = (evTime - time) * scrollSpeed;

				MFVector pos;
				MFView_TransformPoint3DTo2D(MakeVector(-halfFB - 0.2f, 0.0f, position), &pos);

				pos.x -= MFFont_GetStringWidth(pText, pEv->GetString(), 24.0f);
				pos.y += yEventOffset;
				MFFont_DrawTextf(pText, pos, 24.0f, MakeVector(0.6f, 0.8f, 1.0f, 1.0f), pEv->GetString());

				yEventOffset -= 24.0f;
			}
		}

		pEv = pEv->Next();
	}

	MFView_Pop();
}