size_t MFFileNative_Write(MFFile* fileHandle, const void *pBuffer, size_t bytes)
{
	MFCALLSTACK;

	// TODO: support 64bit properly!
	// if size_t is 64bit, and a large value is passed to 'bytes', this will fail...

	DWORD bytesWritten;

	if(fileHandle->createFlags & MFOF_Append)
	{
		// seek to end
		LARGE_INTEGER rel;
		rel.QuadPart = 0;
		SetFilePointerEx(fileHandle->pFilesysData, rel, NULL, FILE_END);

		WriteFile(fileHandle->pFilesysData, pBuffer, (DWORD)bytes, (LPDWORD)&bytesWritten, NULL);
		fileHandle->length += bytesWritten;

		// return to current position
		rel.QuadPart = fileHandle->offset;
		SetFilePointerEx(fileHandle->pFilesysData, rel, NULL, FILE_BEGIN);
	}
	else
	{
		WriteFile(fileHandle->pFilesysData, pBuffer, (DWORD)bytes, (LPDWORD)&bytesWritten, NULL);
		fileHandle->offset += bytesWritten;
		fileHandle->length = MFMax(fileHandle->offset, fileHandle->length);
	}

	return (size_t)bytesWritten;
}
Beispiel #2
0
bool MFCollision_RaySphereTest(const MFVector& rayPos, const MFVector& rayDir, const MFVector& spherePos, float radius, MFRayIntersectionResult *pResult)
{
	MFVector diff = rayPos - spherePos;

	// calcuate the coefficients
	float a = rayDir.MagSquared3();
	float b = (2.0f*rayDir).Dot3(diff);
	float c = diff.MagSquared3() - radius*radius;

	// calculate the stuff under the root sign, if it's negative no (real) solutions exist
	float d = b*b - 4.0f*a*c;
	if(d < 0.0f) // this means ray misses cylinder
		return false;

	float root = MFSqrt(d);
	float rcp2a = MFRcp(2.0f*a);
	float t1 = (-b - root)*rcp2a;
	float t2 = (-b + root)*rcp2a;

	if(t2 < 0.0f || t1 > 1.0f)
		return false;

	if(pResult)
	{
		pResult->time = MFMax(t1, 0.0f);
		pResult->surfaceNormal.Mad3(rayDir, pResult->time, diff);
		pResult->surfaceNormal.Normalise3();
	}

	return true;
}
Beispiel #3
0
bool MFCollision_RaySlabTest(const MFVector& rayPos, const MFVector& rayDir, const MFVector& plane, float slabHalfWidth, MFRayIntersectionResult *pResult)
{
	float a = plane.Dot3(rayDir);

	// if ray is parallel to plane
	if(a > -MFALMOST_ZERO && a < MFALMOST_ZERO)
	{
		// TODO: this is intentionally BROKEN
		// this is a near impossible case, and it adds a lot of junk to the function
/*
		if(MFAbs(rayPos.DotH(plane)) <= slabHalfWidth)
		{
			if(pResult)
			{
				pResult->time = 0.0f;
			}

			return true;
		}
*/
		return false;
	}

	// otherwise we can do the conventional test
	float inva = MFRcp(a);
	float t = -rayPos.DotH(plane);
	float t1 = (t + slabHalfWidth) * inva;
	float t2 = (t - slabHalfWidth) * inva;

	t = MFMin(t1, t2);
	t2 = MFMax(t1, t2);

	if(t > 1.0f || t2 < 0.0f)
		return false;

	if(pResult)
	{
		pResult->time = MFMax(t, 0.0f);
		pResult->surfaceNormal = a > 0.0f ? -plane : plane;
	}

	return true;
}
int MFFileNative_Write(MFFile* fileHandle, const void *pBuffer, int64 bytes)
{
	MFCALLSTACK;

	uint32 bytesWritten;
	WriteFile(fileHandle->pFilesysData, pBuffer, (DWORD)bytes, (LPDWORD)&bytesWritten, NULL);
	fileHandle->offset += bytesWritten;
	fileHandle->length = MFMax(fileHandle->offset, fileHandle->length);

	return bytesWritten;
}
int MFFileNative_Write(MFFile* fileHandle, const void *pBuffer, int64 bytes)
{
	MFCALLSTACK;

	int64 bytesWritten;
	bytesWritten = sceIoWrite((SceUID)fileHandle->pFilesysData, pBuffer, bytes);
	fileHandle->offset += bytesWritten;
	fileHandle->length = MFMax(fileHandle->offset, fileHandle->length);

	return bytesWritten;
}
Beispiel #6
0
void MFRenderer_EndFrame()
{
	MFRenderer_EndFramePlatformSpecific();

	// free scratch buffers
	MFVertex_EndFrame();

	// calculate the high water mark for the scratch memory
	size_t size = gScratchMemoryOffset < gScratchMemoryMark ? gScratchMemorySize - gScratchMemoryMark + gScratchMemoryOffset : gScratchMemoryOffset - gScratchMemoryMark;
	gScratchMemoryPeak = MFMax(gScratchMemoryPeak, size);

	// move the render memory marker to the current offset
	gScratchMemoryMark = gScratchMemoryOffset;
}
Beispiel #7
0
int MFFileNative_Write(MFFile* fileHandle, const void *pBuffer, int64 bytes)
{
	MFCALLSTACK;

	size_t bytesWritten = 0;

#if defined(_USE_CRT_FOR_NULL_DRIVERS)
	bytesWritten = fwrite(pBuffer, 1, (size_t)bytes, (FILE*)fileHandle->pFilesysData);
	fileHandle->offset += bytesWritten;
	fileHandle->length = MFMax(fileHandle->offset, fileHandle->length);
#endif

	return (int)bytesWritten;
}
int MFFileNative_Write(MFFile* fileHandle, const void *pBuffer, int64 bytes)
{
	MFCALLSTACK;

	int bytesWritten = 0;

	bytesWritten = write((size_t)fileHandle->pFilesysData, pBuffer, (unsigned int)bytes);
	if(bytesWritten < 0) // write() returns -1 on error
		bytesWritten = 0;

	fileHandle->offset += bytesWritten;
	fileHandle->length = MFMax(fileHandle->offset, fileHandle->length);

	return (int)bytesWritten;
}
Beispiel #9
0
void HKWidgetListbox::Update()
{
	if(!bDragging)
	{
		if(velocity != 0.f)
		{
			// apply scroll velocity
			velocity *= 1.f - MFSystem_GetTimeDelta()*10.f;
			if(velocity < 0.01f)
				velocity = 0.f;

			scrollOffset += velocity * MFSystem_GetTimeDelta();
		}

		if(scrollOffset > 0.f)
		{
			scrollOffset = MFMax(scrollOffset - MFMax(scrollOffset * 10.f * MFSystem_GetTimeDelta(), 1.f), 0.f);
		}
		else
		{
			float listSize = orientation == Horizontal ? size.x - (padding.x + padding.z) : size.y - (padding.y + padding.w);
			float overflow = MFMin(listSize - (contentSize + scrollOffset), -scrollOffset);
			if(overflow > 0.f)
			{
				scrollOffset = MFMin(scrollOffset + MFMax(overflow * 10.f * MFSystem_GetTimeDelta(), 1.f), scrollOffset + overflow);
			}
		}
	}

	scrollOffset = MFFloor(scrollOffset);
	if(scrollOffset != prevScrollOffset)
	{
		prevScrollOffset = scrollOffset;
		ArrangeChildren();
	}
}
Beispiel #10
0
MFString& MFString::Detach(size_t reserveBytes)
{
	if(pData && (pData->refCount > 1 || pData->allocated == 0))
	{
		MFStringData *pNew = MFStringData_Alloc();
		pNew->bytes = pData->bytes;
		pNew->pMemory = (char*)stringHeap.Alloc(MFMax(pNew->bytes + 1, reserveBytes), &pNew->allocated);
		MFString_Copy(pNew->pMemory, pData->pMemory);

		MFStringData_Release(pData);
		pData = pNew;
	}

	return *this;
}
void HKStringEntryLogic::ClearSelection()
{
	if(selectionStart == selectionEnd)
		return;

	int selMin = MFMin(selectionStart, selectionEnd);
	int selMax = MFMax(selectionStart, selectionEnd);

	buffer.ClearRange(selMin, selMax - selMin);

	cursorPos = selMin;
	selectionStart = selectionEnd = cursorPos;

	if(changeCallback)
		changeCallback(buffer.CStr());
}
Beispiel #12
0
void HKWidgetListbox::ArrangeChildren()
{
	// early out?
	int numChildren = GetNumChildren();
	if(numChildren == 0)
		return;

	MFVector pPos = orientation == Horizontal ? MakeVector(padding.x + scrollOffset, padding.y) : MakeVector(padding.x, padding.y + scrollOffset);
	MFVector pSize = MakeVector(size.x - (padding.x + padding.z), size.y - (padding.y + padding.w));

	contentSize = 0.f;

	for(int a=0; a<numChildren; ++a)
	{
		HKWidget *pWidget = GetChild(a);
		if(pWidget->GetVisible() == Gone)
			continue;

		const MFVector &cMargin = pWidget->GetLayoutMargin();
		const MFVector &cSize = pWidget->GetSize();

		MFVector tPos = pPos + MakeVector(cMargin.x, cMargin.y);
		MFVector tSize = MFMax(pSize - MakeVector(cMargin.x + cMargin.z, cMargin.y + cMargin.w), MFVector::zero);

		if(orientation == Horizontal)
		{
			float itemSize = cSize.x + cMargin.x + cMargin.z;
			contentSize += itemSize;
			pPos.x += itemSize;
			pWidget->SetPosition(tPos);
			pWidget->SetHeight(tSize.y);
		}
		else
		{
			float itemSize = cSize.y + cMargin.y + cMargin.w;
			contentSize += itemSize;
			pPos.y += itemSize;
			pWidget->SetPosition(tPos);
			pWidget->SetWidth(tSize.x);
		}
	}
}
Beispiel #13
0
MF_API MFCollisionItem* MFCollision_SweepSphereTest(const MFVector &sweepSpherePos, const MFVector &sweepSphereVelocity, float sweepSphereRadius, MFCollisionItem *pItem, MFSweepSphereResult *pResult)
{
	MFBoundingVolume rayVolume;

	MFVector radiusVector = MakeVector(sweepSphereRadius, sweepSphereRadius, sweepSphereRadius, 0.0f);
	MFVector sweepEnd = sweepSpherePos + sweepSphereVelocity;
	rayVolume.min = MFMin(sweepSpherePos, sweepEnd) - radiusVector;
	rayVolume.max = MFMax(sweepSpherePos, sweepEnd) + radiusVector;
	rayVolume.boundingSphere = MakeVector(sweepSpherePos + sweepSphereVelocity*0.5f, sweepSphereVelocity.Magnitude3()*0.5f + sweepSphereRadius);

	if(0)//!MFBoundingVolume_Test(rayVolume, pItem->pTemplate->boundingVolume))
	{
		return NULL;
	}

	switch(pItem->pTemplate->type)
	{
		case MFCT_Sphere:
		{
			MFCollisionSphere *pSphere = (MFCollisionSphere*)pItem->pTemplate->pCollisionTemplateData;
			if(!MFCollision_SweepSphereSphereTest(sweepSpherePos, sweepSphereVelocity, sweepSphereRadius, pItem->worldPos.GetTrans(), pSphere->radius, pResult))
				return NULL;
			break;
		}
		case MFCT_Mesh:
		{
			if(!MFCollision_SweepSphereMeshTest(sweepSpherePos, sweepSphereVelocity, sweepSphereRadius, pItem, pResult))
				return NULL;
			break;
		}
		case MFCT_Field:
		{
			pItem = MFCollision_SweepSphereFieldTest(sweepSpherePos, sweepSphereVelocity, sweepSphereRadius, pItem, pResult);
			break;
		}
		default:
			MFDebug_Assert(false, "Invalid target primitive");
	}

	return pItem;
}
Beispiel #14
0
MF_API MFCollisionItem* MFCollision_RayTest(const MFVector& rayPos, const MFVector& rayDir, MFCollisionItem *pItem, MFRayIntersectionResult *pResult)
{
	MFBoundingVolume rayVolume;

	MFVector rayEnd = rayPos+rayDir;
	rayVolume.min = MFMin(rayPos, rayEnd);
	rayVolume.max = MFMax(rayPos, rayEnd);
	rayVolume.boundingSphere = MakeVector(rayPos + rayDir*0.5f, rayDir.Magnitude3()*0.5f);

	if(!MFBoundingVolume_Test(rayVolume, pItem->pTemplate->boundingVolume))
	{
		return NULL;
	}

	switch(pItem->pTemplate->type)
	{
		case MFCT_Sphere:
		{
			MFCollisionSphere *pSphere = (MFCollisionSphere*)pItem->pTemplate->pCollisionTemplateData;
			if(!MFCollision_RaySphereTest(rayPos, rayDir, pItem->worldPos.GetTrans(), pSphere->radius, pResult))
				return NULL;
			break;
		}
		case MFCT_Mesh:
		{
			if(!MFCollision_RayMeshTest(rayPos, rayDir, pItem, pResult))
				return NULL;
			break;
		}
		case MFCT_Field:
		{
			pItem = MFCollision_RayFieldTest(rayPos, rayDir, pItem, pResult);
			break;
		}
		default:
			MFDebug_Assert(false, "Invalid target primitive");
	}

	return pItem;
}
int MFFileZipFile_Seek(MFFile* pFile, int64 bytes, MFFileSeek relativity)
{
	MFCALLSTACK;

	int64 newPos = 0;

	switch(relativity)
	{
		case MFSeek_Begin:
			newPos = MFMin(bytes, pFile->length);
			break;
		case MFSeek_End:
			newPos = MFMax((int64)0, pFile->length - bytes);
			break;
		case MFSeek_Current:
			newPos = MFClamp((int64)0, pFile->offset + bytes, pFile->length);
			break;
		default:
			MFDebug_Assert(false, "Invalid 'relativity' for file seeking.");
	}

	unzFile f = (unzFile)pFile->pFilesysData;

	unzCloseCurrentFile(f);
	unzOpenCurrentFile(f);

	pFile->offset = newPos;

	// read to the desired position.
	char buffer[256];

	while(newPos)
	{
		int64 bytes = newPos < 256 ? newPos : 256;
		unzReadCurrentFile(f, buffer, (uint32)bytes);
		newPos -= bytes;
	}

	return (int)pFile->offset;
}
Beispiel #16
0
MF_API void MFCollision_BuildField(MFCollisionItem *pField)
{
	MFCollisionField *pFieldData = (MFCollisionField*)pField->pTemplate;

	int numItems = pFieldData->itemList.GetLength();

	if(numItems <= 0)
	{
		MFDebug_Warn(4, "EmptyField can not be generated.");
		return;
	}

	// find the min and max range of the objects
	MFVector fieldMin = MakeVector(10e+30f), fieldMax = MakeVector(-10e+30f);

	MFCollisionItem **ppI = pFieldData->itemList.Begin();

	while(*ppI)
	{
		MFCollisionItem *pI = *ppI;
		MFCollisionTemplate *pT = pI->pTemplate;

		MFVector tMin = ApplyMatrixH(pT->boundingVolume.min, pI->worldPos);
		MFVector tMax = ApplyMatrixH(pT->boundingVolume.max, pI->worldPos);

		fieldMin = MFMin(fieldMin, tMin);
		fieldMax = MFMax(fieldMax, tMax);

		ppI++;
	}

	pFieldData->fieldMin = fieldMin;
	pFieldData->fieldMax = fieldMin;

	MFVector numCells;
	MFVector fieldRange = fieldMax - fieldMin;
	numCells.Rcp3(pFieldData->cellSize);
	numCells.Mul3(fieldRange, numCells);

	pFieldData->width = (int)MFCeil(numCells.x);
	pFieldData->height = (int)MFCeil(numCells.y);
	pFieldData->depth = (int)MFCeil(numCells.z);

	// this is TOTALLY broken!! .. if a big object lies in many cell's, it could easilly overflow the array.
	int totalCells = pFieldData->width * pFieldData->height * pFieldData->depth;
	int numPointers = totalCells * 2 + numItems * 16;

	MFCollisionItem **ppItems = (MFCollisionItem**)MFHeap_Alloc(sizeof(MFCollisionItem*) * numPointers);
	pFieldData->pppItems = (MFCollisionItem***)ppItems;
	ppItems += totalCells;

	for(int z=0; z<pFieldData->depth; z++)
	{
		for(int y=0; y<pFieldData->height; y++)
		{
			for(int x=0; x<pFieldData->width; x++)
			{
				pFieldData->pppItems[z*pFieldData->height*pFieldData->width + y*pFieldData->width + x] = ppItems;

				MFVector thisCell = fieldMin + pFieldData->cellSize * MakeVector((float)x, (float)y, (float)z);
				MFVector thisCellEnd = thisCell + pFieldData->cellSize;

				MFCollisionItem **ppI = pFieldData->itemList.Begin();

				while(*ppI)
				{
					MFCollisionItem *pI = *ppI;
					MFCollisionTemplate *pT = pI->pTemplate;

					// if this item fits in this cell, insert it into this cells list.
					MFVector tMin = ApplyMatrixH(pT->boundingVolume.min, pI->worldPos);
					MFVector tMax = ApplyMatrixH(pT->boundingVolume.max, pI->worldPos);

					// test of bounding boxes overlap
					if(MFCollision_TestAABB(tMin, tMax, thisCell, thisCellEnd))
					{
						*ppItems = pI;
						++ppItems;
					}

					ppI++;
				}

				*ppItems = NULL;
				++ppItems;
			}
		}
	}

	MFHeap_ValidateMemory(pFieldData->pppItems);
}
void HKWidgetLayoutFrame::ArrangeChildren()
{
	bool bFitWidth = bAutoWidth && GetHAlign() != Align_Fill; // fitFlags & FitContentHorizontal
	bool bFitHeight = bAutoHeight && GetVAlign() != VAlign_Fill; // fitFlags & FitContentVertical

	// early out?
	int numChildren = GetNumChildren();
	if(numChildren == 0)
	{
		if(bFitWidth || bFitHeight)
		{
			// resize the layout
			MFVector newSize = GetSize();
			if(bFitWidth)
				newSize.x = padding.x + padding.z;
			if(bFitHeight)
				newSize.y = padding.y + padding.w;
			Resize(newSize);
		}
		return;
	}

	if(bFitWidth || bFitHeight)
	{
		// fit to largest child in each dimension
		MFVector fit = MFVector::zero;
		for(int a=0; a<numChildren; ++a)
		{
			HKWidget *pWidget = GetChild(a);
			const MFVector &cSize = pWidget->GetSizeWithMargin();

			fit.x = MFMax(fit.x, cSize.x + padding.x + padding.z);
			fit.y = MFMax(fit.y, cSize.y + padding.y + padding.w);
		}

		// resize the layout
		MFVector newSize = GetSize();
		if(bFitWidth)
			newSize.x = fit.x;
		if(bFitHeight)
			newSize.y = fit.y;
		Resize(newSize);
	}

	MFVector cPos = MakeVector(padding.x, padding.y);
	MFVector cSize = MakeVector(size.x - (padding.x + padding.z), size.y - (padding.y + padding.w));

	for(int a=0; a<numChildren; ++a)
	{
		HKWidget *pWidget = GetChild(a);

		const MFVector &cMargin = pWidget->GetLayoutMargin();
		const MFVector &size = pWidget->GetSize();
		MFVector tPos = cPos + MakeVector(cMargin.x, cMargin.y);
		MFVector tSize = cSize - MakeVector(cMargin.x + cMargin.z, cMargin.y + cMargin.w);

		switch(pWidget->GetLayoutJustification())
		{
		case TopLeft:
			pWidget->SetPosition(tPos);
			break;
		case TopCenter:
			pWidget->SetPosition(tPos + MakeVector((tSize.x - size.x) * 0.5f, 0));
			break;
		case TopRight:
			pWidget->SetPosition(tPos + MakeVector(tSize.x - size.x, 0));
			break;
		case TopFill:
			pWidget->SetPosition(tPos);
			ResizeChild(pWidget, MakeVector(tSize.x, size.y));
			break;
		case CenterLeft:
			pWidget->SetPosition(tPos + MakeVector(0, (tSize.y - size.y) * 0.5f));
			break;
		case Center:
			pWidget->SetPosition(tPos + MakeVector((tSize.x - size.x) * 0.5f, (tSize.y - size.y) * 0.5f));
			break;
		case CenterRight:
			pWidget->SetPosition(tPos + MakeVector(tSize.x - size.x, (tSize.y - size.y) * 0.5f));
			break;
		case CenterFill:
			pWidget->SetPosition(tPos + MakeVector(0, (tSize.y - size.y) * 0.5f));
			ResizeChild(pWidget, MakeVector(tSize.x, size.y));
			break;
		case BottomLeft:
			pWidget->SetPosition(tPos + MakeVector(0, tSize.y - size.y));
			break;
		case BottomCenter:
			pWidget->SetPosition(tPos + MakeVector((tSize.x - size.x) * 0.5f, tSize.y - size.y));
			break;
		case BottomRight:
			pWidget->SetPosition(tPos + MakeVector(tSize.x - size.x, tSize.y - size.y));
			break;
		case BottomFill:
			pWidget->SetPosition(tPos + MakeVector(0, tSize.y - size.y));
			ResizeChild(pWidget, MakeVector(tSize.x, size.y));
			break;
		case FillLeft:
			pWidget->SetPosition(tPos);
			ResizeChild(pWidget, MakeVector(size.x, tSize.y));
			break;
		case FillCenter:
			pWidget->SetPosition(tPos + MakeVector((tSize.x - size.x) * 0.5f, 0));
			ResizeChild(pWidget, MakeVector(size.x, tSize.y));
			break;
		case FillRight:
			pWidget->SetPosition(tPos + MakeVector(tSize.x - size.x, 0));
			ResizeChild(pWidget, MakeVector(size.x, tSize.y));
			break;
		case Fill:
			pWidget->SetPosition(tPos);
			ResizeChild(pWidget, tSize);
			break;
		case None:
			// this widget has absolute coordinates..
		default:
			break;
		}
	}
}
Beispiel #18
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();
}
Beispiel #19
0
bool MFCollision_RayCylinderTest(const MFVector& rayPos, const MFVector& rayDir, const MFVector& cylinderPos, const MFVector& cylinderDir, float cylinderRadius, bool capped, MFRayIntersectionResult *pResult, float *pCylinderTime)
{
	MFVector local = rayPos - cylinderPos;

	float rayD = rayDir.Dot3(cylinderDir);
	float T0 = local.Dot3(cylinderDir);

	// bring T0 into 0.0-1.0 range
	float invMagSq = MFRcp(cylinderDir.MagSquared3());
	rayD *= invMagSq;
	T0 *= invMagSq;

	// calculate some intermediate vectors
	MFVector v1 = rayDir - rayD*cylinderDir;
	MFVector v2 = local - T0*cylinderDir;

	// calculate coeff in quadratic formula
	float a = v1.MagSquared3();
	float b = (2.0f*v1).Dot3(v2);
	float c = v2.MagSquared3() - cylinderRadius*cylinderRadius;

	// calculate the stuff under the root sign, if it's negative no (real) solutions exist
	float d = b*b - 4.0f*a*c;
	if(d < 0.0f) // this means ray misses cylinder
		return false;

	float root = MFSqrt(d);
	float rcp2a = MFRcp(2.0f*a);
	float t1 = (-b - root)*rcp2a;
	float t2 = (-b + root)*rcp2a;

	if(t1 > 1.0f || t2 < 0.0f)
		return false; // the cylinder is beyond the ray..

	if(capped || pCylinderTime || pResult)
	{
		float t = MFMax(t1, 0.0f);

		// get the t for the cylinders ray
		MFVector intersectedRay;
		intersectedRay.Mad3(rayDir, t, local);

		float ct = intersectedRay.Dot3(cylinderDir) * invMagSq;

		if(capped && (ct < 0.0f || ct > 1.0f))
		{
			// we need to test the caps

			// TODO: this is REALLY slow!! can be majorly improved!!

			// generate a plane for the cap
			MFVector point, plane;

			if(rayD > 0.0f)
			{
				// the near one
				point = cylinderPos;
				plane = MFCollision_MakePlaneFromPointAndNormal(point, -cylinderDir);
			}
			else
			{
				// the far one
				point = cylinderPos + cylinderDir;
				plane = MFCollision_MakePlaneFromPointAndNormal(point, cylinderDir);
			}

			// test the ray against the plane
			bool collide = MFCollision_RayPlaneTest(rayPos, rayDir, plane, pResult);

			if(collide)
			{
				// calculate the intersection point
				intersectedRay.Mad3(rayDir, pResult->time, rayPos);
				intersectedRay.Sub3(intersectedRay, point);

				// and see if its within the cylinders radius
				if(intersectedRay.MagSquared3() <= cylinderRadius * cylinderRadius)
				{
					return true;
				}
			}

			return false;
		}

		if(pResult)
		{
			pResult->time = t;
			pResult->surfaceNormal.Mad3(cylinderDir, -ct, intersectedRay);
			pResult->surfaceNormal.Normalise3();
		}

		if(pCylinderTime)
		{
			*pCylinderTime = ct;
		}
	}

	return true;
}
void HKStringEntryLogic::Update()
{
	bool shiftL = !!MFInput_Read(Key_LShift, IDD_Keyboard);
	bool shiftR = !!MFInput_Read(Key_RShift, IDD_Keyboard);
	bool ctrlL = !!MFInput_Read(Key_LControl, IDD_Keyboard);
	bool ctrlR = !!MFInput_Read(Key_RControl, IDD_Keyboard);

	int keyPressed = 0;

	bool shift = shiftL || shiftR;
	bool ctrl = ctrlL || ctrlR;

#if defined(MF_WINDOWS)
	if(ctrl && MFInput_WasPressed(Key_C, IDD_Keyboard) && selectionStart != selectionEnd)
	{
		BOOL opened = OpenClipboard(apphWnd);

		if(opened)
		{
			int selMin = MFMin(selectionStart, selectionEnd);
			int selMax = MFMax(selectionStart, selectionEnd);

			int numChars = selMax-selMin;

			HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, numChars + 1);
			char *pString = (char*)GlobalLock(hData);

			MFString_Copy(pString, GetRenderString().SubStr(selMin, numChars).CStr());

			GlobalUnlock(hData);

			EmptyClipboard();
			SetClipboardData(CF_TEXT, hData);

			CloseClipboard();
		}
	}
	else if(ctrl && MFInput_WasPressed(Key_X, IDD_Keyboard) && selectionStart != selectionEnd)
	{
		BOOL opened = OpenClipboard(apphWnd);

		if(opened)
		{
			int selMin = MFMin(selectionStart, selectionEnd);
			int selMax = MFMax(selectionStart, selectionEnd);

			int numChars = selMax-selMin;

			HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, numChars + 1);
			char *pString = (char*)GlobalLock(hData);

			MFString_Copy(pString, GetRenderString().SubStr(selMin, numChars).CStr());

			GlobalUnlock(hData);

			EmptyClipboard();
			SetClipboardData(CF_TEXT, hData);

			CloseClipboard();

			ClearSelection();
		}
	}
	else if(ctrl && MFInput_WasPressed(Key_V, IDD_Keyboard))
	{
		BOOL opened = OpenClipboard(apphWnd);

		if(opened)
		{
			int selMin = MFMin(selectionStart, selectionEnd);
			int selMax = MFMax(selectionStart, selectionEnd);

			int numChars = selMax-selMin;

			HANDLE hData = GetClipboardData(CF_TEXT);
			MFString paste((const char*)GlobalLock(hData), true);

			buffer.Replace(selMin, numChars, paste);

			GlobalUnlock(hData);

			cursorPos = selMin + paste.NumBytes();
			selectionStart = selectionEnd = cursorPos;

			GlobalUnlock(hData);

			CloseClipboard();

			if((numChars || cursorPos != selMin) && changeCallback)
				changeCallback(buffer.CStr());
		}
	}
	else
#endif
	{
		// check for new keypresses
		for(int a=0; a<255; a++)
		{
			if(MFInput_WasPressed(a, IDD_Keyboard))
			{
				keyPressed = a;
				holdKey = a;
				repeatDelay = gRepeatDelay;
				break;
			}
		}

		// handle repeat keys
		if(holdKey && MFInput_Read(holdKey, IDD_Keyboard))
		{
			repeatDelay -= MFSystem_TimeDelta();
			if(repeatDelay <= 0.f)
			{
				keyPressed = holdKey;
				repeatDelay += gRepeatRate;
			}
		}
		else
			holdKey = 0;

		// if there was a new key press
		if(keyPressed)
		{
			switch(keyPressed)
			{
				case Key_Backspace:
				case Key_Delete:
				{
					if(selectionStart != selectionEnd)
					{
						ClearSelection();
					}
					else
					{
						if(keyPressed == Key_Backspace && cursorPos > 0)
						{
							buffer.ClearRange(--cursorPos, 1);
							selectionStart = selectionEnd = cursorPos;

							if(changeCallback)
								changeCallback(buffer.CStr());
						}
						else if(keyPressed == Key_Delete && cursorPos < buffer.NumBytes())
						{
							buffer.ClearRange(cursorPos, 1);
							selectionStart = selectionEnd = cursorPos;

							if(changeCallback)
								changeCallback(buffer.CStr());
						}
					}
					break;
				}

				case Key_Left:
				case Key_Right:
				case Key_Home:
				case Key_End:
				{
					if(ctrl)
					{
						if(keyPressed == Key_Left)
						{
							while(cursorPos && MFIsWhite(buffer[cursorPos-1]))
								--cursorPos;
							if(MFIsAlphaNumeric(buffer[cursorPos-1]))
							{
								while(cursorPos && MFIsAlphaNumeric(buffer[cursorPos-1]))
									--cursorPos;
							}
							else if(cursorPos)
							{
								--cursorPos;
								while(cursorPos && buffer[cursorPos-1] == buffer[cursorPos])
									--cursorPos;
							}
						}
						else if(keyPressed == Key_Right)
						{
							while(cursorPos < buffer.NumBytes() && MFIsWhite(buffer[cursorPos]))
								++cursorPos;
							if(MFIsAlphaNumeric(buffer[cursorPos]))
							{
								while(cursorPos < buffer.NumBytes() && MFIsAlphaNumeric(buffer[cursorPos]))
									++cursorPos;
							}
							else if(cursorPos < buffer.NumBytes())
							{
								++cursorPos;
								while(cursorPos < buffer.NumBytes() && buffer[cursorPos] == buffer[cursorPos-1])
									++cursorPos;
							}
						}
						else if(keyPressed == Key_Home)
							cursorPos = 0;
						else if(keyPressed == Key_End)
							cursorPos = buffer.NumBytes();
					}
					else
					{
						if(keyPressed == Key_Left)
							cursorPos = (!shift && selectionStart != selectionEnd ? MFMin(selectionStart, selectionEnd) : MFMax(cursorPos-1, 0));
						else if(keyPressed == Key_Right)
							cursorPos = (!shift && selectionStart != selectionEnd ? MFMax(selectionStart, selectionEnd) : MFMin(cursorPos+1, buffer.NumBytes()));
						else if(keyPressed == Key_Home)
							cursorPos = 0;	// TODO: if multiline, go to start of line..
						else if(keyPressed == Key_End)
							cursorPos = buffer.NumBytes();	// TODO: if multiline, go to end of line...
					}

					if(shift)
						selectionEnd = cursorPos;
					else
						selectionStart = selectionEnd = cursorPos;

					break;
				}

				default:
				{
					bool caps = MFInput_GetKeyboardStatusState(KSS_CapsLock);
					int ascii = MFInput_KeyToAscii(keyPressed, shift, caps);

					if(ascii && (!maxLen || buffer.NumBytes() < maxLen-1))
					{
						// check character exclusions
						if(MFIsNewline(ascii) && type != ST_MultiLine)
							break;
						if(ascii == '\t' && type != ST_MultiLine)
							break;
						if(type == ST_Numeric && !MFIsNumeric(ascii))
							break;
						if(include)
						{
							if(include.FindChar(ascii) < 0)
								break;
						}
						if(exclude)
						{
							if(exclude.FindChar(ascii) >= 0)
								break;
						}

						int selMin = MFMin(selectionStart, selectionEnd);
						int selMax = MFMax(selectionStart, selectionEnd);
						int selRange = selMax - selMin;

						const uint16 wstr[] = { (uint16)ascii, 0 };
						char insert[5];
						MFString_CopyUTF16ToUTF8(insert, wstr);
						buffer.Replace(selMin, selRange, insert);
						cursorPos = selMin + 1;

						selectionStart = selectionEnd = cursorPos;

						if(changeCallback)
							changeCallback(buffer.CStr());
					}
					break;
				}
			}
		}
	}
}
Beispiel #21
0
const char *ParseSkinWeights(const char *pText, F3DSubObject &sub, int numPositions)
{
	SkipToken(pText, "{");

	const char *pName = GetString(pText, &pText);

	// get num weights
	int numWeights = GetInt(pText, &pText);

	if(numWeights > 0)
		MFDebug_Assert(numWeights == numPositions, "Number of weights's does not match the number of verts in the mesh.");

	int *pIndices = numWeights > 0 ? (int*)MFHeap_Alloc(sizeof(int) * numWeights) : NULL;
	GetIntArray(pText, pIndices, numWeights, &pText);

	float *pWeights = numWeights > 0 ? (float*)MFHeap_Alloc(sizeof(float) * numWeights) : NULL;
	GetFloatArray(pText, pWeights, numWeights, &pText);

	MFMatrix matrixOffset;
	GetFloatArray(pText, (float*)&matrixOffset, 16, &pText);
	SkipToken(pText, ";");

	SkipToken(pText, "}");

	if(numWeights > 0)
	{
		// now we want to do something with all this data...
		F3DSkeletonChunk *pSC = pModel->GetSkeletonChunk();

		int boneID = pSC->FindBone(pName);

		// if boneID == -1 we dont want to process this data
		if(boneID == -1)
			return pText;

		// check weights are sequential
		for(int a=0; a<numWeights; a++)
			MFDebug_Assert(a == pIndices[a], "Weight array is not sequential!");

		for(int a=0; a<sub.matSubobjects.size(); a++)
			++sub.matSubobjects[a].numBones;

		// map to faces
		for(int m=0; m<sub.matSubobjects.size(); m++)
		{
			int totalVerts = sub.matSubobjects[m].vertices.size();
			for(int a=0; a<totalVerts; a++)
			{
				F3DVertex &v = sub.matSubobjects[m].vertices[a];

				int i = v.position;
				const int numBones = sizeof(v.bone)/sizeof(v.bone[0]);

				if(pWeights[i] != 0.0f)
				{
					for(int b=0; b<numBones; b++)
					{
						if(v.bone[b] == -1)
						{
							v.weight[b] = pWeights[i];
							v.bone[b] = boneID;
							pSC->bones[boneID].bIsSkinned = true;
							sub.matSubobjects[m].maxWeights = MFMax(sub.matSubobjects[m].maxWeights, b+1);
							break;
						}
					}
				}
			}
		}
	}

	return pText;
}
Beispiel #22
0
void ParseOBJFile(const char *pFilePtr)
{
	const char *pToken = GetNextToken(pFilePtr);

	while(*pToken != 0)
	{
		if(!MFString_CaseCmp(pToken, "o"))
		{
			const char *pName = GetRestOfLine(pFilePtr);

			pModel->name = pName;
		}
		else if(!MFString_CaseCmp(pToken, "g"))
		{
			const char *pName = GetRestOfLine(pFilePtr);

			if(!vertsInGroup)
			{
				// we'll just rename the current subobject, since theres nothing in it..
				F3DSubObject &sub = pModel->GetMeshChunk()->subObjects[subObject];
				sub.name = pName;
			}
			else
			{
				// probably wanna copy vertex data in at this point..
				// and subtract the min from each of the components indices..
				CopyDataIntoSubobject(subObject);

				++subObject;

				matSub = 0;

				minVertIndex = -1;
				minUVIndex = -1;
				minNormIndex = -1;
				maxVertIndex = -1;
				maxUVIndex = -1;
				maxNormIndex = -1;

				vertsInGroup = false;
				vertsInMatSub = false;

				F3DSubObject &sub = pModel->GetMeshChunk()->subObjects[subObject];
				sub.name = pName;
			}
		}
		else if(!MFString_CaseCmp(pToken, "v"))
		{
			const char *pX = GetNextToken(pFilePtr);
			const char *pY = GetNextToken(pFilePtr);
			const char *pZ = GetNextToken(pFilePtr);
			pFilePtr = MFSeekNewline(pFilePtr);

			MFVector v;
			v.x = (float)atof(pX);
			v.y = (float)atof(pY);
			v.z = (float)atof(pZ);
			v.w = 1.0f;

			verts.push(v);
		}
		else if(!MFString_CaseCmp(pToken, "vt"))
		{
			const char *pU = GetNextToken(pFilePtr);
			const char *pV = GetNextToken(pFilePtr);
			pFilePtr = MFSeekNewline(pFilePtr);

			MFVector v;
			v.x = (float)atof(pU);
			v.y = (float)atof(pV);
			v.z = 0.0f;
			v.w = 1.0f;

			uvs.push(v);
		}
		else if(!MFString_CaseCmp(pToken, "vn"))
		{
			const char *pX = GetNextToken(pFilePtr);
			const char *pY = GetNextToken(pFilePtr);
			const char *pZ = GetNextToken(pFilePtr);
			pFilePtr = MFSeekNewline(pFilePtr);

			MFVector v;
			v.x = (float)atof(pX);
			v.y = (float)atof(pY);
			v.z = (float)atof(pZ);
			v.w = 1.0f;

			normals.push(v);
		}
		else if(!MFString_CaseCmp(pToken, "f"))
		{
			vertsInGroup = true;
			vertsInMatSub = true;

			F3DSubObject &sub = pModel->GetMeshChunk()->subObjects[subObject];

			const char *pRestOfLine = GetRestOfLine(pFilePtr);

			int firstVert = (int)sub.matSubobjects[matSub].vertices.size();

			pToken = GetNextToken(pRestOfLine);

			while(*pToken)
			{
				const char *pPos = GetNextIndex(pToken);
				const char *pUV = GetNextIndex(pToken);
				const char *pNorm = GetNextIndex(pToken);

				int posid = atoi(pPos);
				int texid = atoi(pUV);
				int normid = atoi(pNorm);

				if(posid < 0)
					posid = (int)verts.size() - posid;
				else
					posid = posid - 1;

				if(texid < 0)
					texid = (int)uvs.size() - texid;
				else
					texid = texid - 1;

				if(normid < 0)
					normid = (int)normals.size() - normid;
				else
					normid = normid - 1;

				minVertIndex = minVertIndex == -1 ? posid : MFMin(minVertIndex, posid);
				minUVIndex = minUVIndex == -1 ? texid : MFMin(minUVIndex, texid);
				minNormIndex = minNormIndex == -1 ? normid : MFMin(minNormIndex, normid);
				maxVertIndex = minVertIndex == -1 ? posid : MFMax(maxVertIndex, posid);
				maxUVIndex = maxUVIndex == -1 ? texid : MFMax(maxUVIndex, texid);
				maxNormIndex = maxNormIndex == -1 ? normid : MFMax(maxNormIndex, normid);

				int vi = (int)sub.matSubobjects[matSub].vertices.size();
				int f = vi - firstVert;

				F3DVertex &vert = sub.matSubobjects[matSub].vertices[firstVert + f];
				vert.position = posid;
				vert.uv[0] = texid;
				vert.normal = normid;

				// add a triangle if we are up to the third vert or beyond
				if(f >= 2)
				{
					F3DTriangle &tri = sub.matSubobjects[matSub].triangles.push();

					tri.v[0] = firstVert;
					tri.v[1] = vi-1;
					tri.v[2] = vi;
				}

				pToken = GetNextToken(pRestOfLine);
			}
		}
		else if(!MFString_CaseCmp(pToken, "usemtl"))
		{
			F3DSubObject &sub = pModel->GetMeshChunk()->subObjects[subObject];

			if(vertsInGroup && vertsInMatSub)
			{
				++matSub;
				vertsInMatSub = false;
			}

			const char *pName = GetRestOfLine(pFilePtr);

			sub.matSubobjects[matSub].materialIndex = GetMaterialID(pName);
		}
		else if(!MFString_CaseCmp(pToken, "mtllib"))
		{
			// load material info?
			//..
			
			pFilePtr = MFSeekNewline(pFilePtr);
		}
		else if(pToken[0] == '#')
		{
			pFilePtr = MFSeekNewline(pFilePtr);
		}
		else
		{
			MFDebug_Warn(2, MFStr("Unknown token encountered in obj file '%s'!", pToken));
			pFilePtr = MFSeekNewline(pFilePtr);
		}

		pToken = GetNextToken(pFilePtr);
	}

	// want to copy vertex data into the last subobject at this point...
	if(vertsInGroup)
	{
		CopyDataIntoSubobject(subObject);
	}
}
Beispiel #23
0
void MFInput_GetGamepadStateInternal(int id, MFGamepadState *pGamepadState)
{
    MFCALLSTACK;

	MFZeroMemory(pGamepadState, sizeof(MFGamepadState));

	LinuxGamepad *pPad = &gGamepads[id];
	const int *pButtonMap = pPad->pGamepadInfo->pButtonMap;

	// if this is a virtual device, find the source device
	while(pPad->bVirtualDevice)
		--pPad;

	if(pPad->joyFD)
	{
		// convert input to float data
		for(int a=0; a<GamepadType_Max; a++)
		{
			if(pButtonMap[a] == -1)
				continue;

			int axisID = MFGETAXIS(pButtonMap[a]);

			// if we are not reading the analog axis
			if(!(pButtonMap[a] & AID_Analog))
			{
				if(axisID >= 60)// && gPCJoysticks[id].bHasPOV)
				{
/*
					if(POVCentered)
					{
						// POV is centered
						pGamepadState->values[a] = 0.0f;
					}
					else
					{
						// read POV (or more appropriately titled, POS)
						if(axisID == 60)
							pGamepadState->values[Button_DUp] = ((pov >= 31500 && pov <= 36000) || (pov >= 0 && pov <= 4500)) ? 1.0f : 0.0f;
						else if(axisID == 61)
							pGamepadState->values[Button_DDown] = (pov >= 13500 && pov <= 22500) ? 1.0f : 0.0f;
						else if(axisID == 62)
							pGamepadState->values[Button_DLeft] = (pov >= 22500 && pov <= 31500) ? 1.0f : 0.0f;
						else if(axisID == 63)
							pGamepadState->values[Button_DRight] = (pov >= 4500 && pov <= 13500) ? 1.0f : 0.0f;
					}
*/
				}
				else
				{
					// read digital button
					pGamepadState->values[a] = pPad->button[pButtonMap[a] & AID_ButtonMask] ? 1.0f : 0.0f;
				}
			}
			else
			{
				// read an analog axis
//				pGamepadState->values[a] = MFMin(pad.axis[pad.axisMap[MFGETAXIS(pButtonMap[a])]] * (1.0f/32767.0f), 1.0f);
				pGamepadState->values[a] = MFMin(pPad->axis[axisID] * (1.0f/32767.0f), 1.0f);
			}

			// invert any buttons with the AID_Negative flag
			if(pButtonMap[a] & AID_Negative)
				pGamepadState->values[a] = -pGamepadState->values[a];
			// clamp any butons with the AID_Clamp flag to the positive range
			if(pButtonMap[a] & AID_Clamp)
				pGamepadState->values[a] = MFMax(0.0f, pGamepadState->values[a]);
			// use the full range for any buttons with the AID_Full flag
			if(pButtonMap[a] & AID_Full)
				pGamepadState->values[a] = (pGamepadState->values[a] + 1.0f) * 0.5f;
		}
	}
}
void HKWidgetLayoutLinear::ArrangeChildren()
{
	bool bFitWidth = bAutoWidth && GetHAlign() != Align_Fill; // fitFlags & FitContentHorizontal
	bool bFitHeight = bAutoHeight && GetVAlign() != VAlign_Fill; // fitFlags & FitContentVertical

	// early out?
	int numChildren = GetNumChildren();
	if(numChildren == 0)
	{
		if(bFitWidth || bFitHeight)
		{
			// resize the layout
			MFVector newSize = GetSize();
			if(bFitWidth)
				newSize.x = padding.x + padding.z;
			if(bFitHeight)
				newSize.y = padding.y + padding.w;
			Resize(newSize);
		}
		return;
	}

	// calculate weight and fit
	float totalWeight = 0.f;
	MFVector fit = MakeVector(padding.x + padding.z, padding.y + padding.w);
	for(int a=0; a<numChildren; ++a)
	{
		HKWidget *pWidget = GetChild(a);
		if(pWidget->GetVisible() == Gone)
			continue;

		const MFVector &cSize = pWidget->GetSizeWithMargin();

		if(orientation == Horizontal)
		{
			if(pWidget->GetHAlign() == Align_Fill) // fill horizontally
				totalWeight += pWidget->GetLayoutWeight();
			else
				fit.x += cSize.x;

			fit.y = MFMax(fit.y, cSize.y + padding.y + padding.w);
		}
		else
		{
			if(pWidget->GetVAlign() == VAlign_Fill) // fill vertically
				totalWeight += pWidget->GetLayoutWeight();
			else
				fit.y += cSize.y;

			fit.x = MFMax(fit.x, cSize.x + padding.x + padding.z);
		}
	}

	if(bFitWidth || bFitHeight)
	{
		// resize the layout
		MFVector newSize = size;
		if(bFitWidth)
			newSize.x = fit.x;
		if(bFitHeight)
			newSize.y = fit.y;
		Resize(newSize);
	}

	MFVector pPos = MakeVector(padding.x, padding.y);
	MFVector pSize = MakeVector(size.x - (padding.x + padding.z), size.y - (padding.y + padding.w));

	MFVector slack = MFMax(size - fit, MFVector::zero);

	for(int a=0; a<numChildren; ++a)
	{
		HKWidget *pWidget = GetChild(a);
		if(pWidget->GetVisible() == Gone)
			continue;

		const MFVector &cMargin = pWidget->GetLayoutMargin();
		const MFVector &cSize = pWidget->GetSize();

		MFVector tPos = pPos + MakeVector(cMargin.x, cMargin.y);
		MFVector tSize = MFMax(pSize - MakeVector(cMargin.x + cMargin.z, cMargin.y + cMargin.w), MFVector::zero);

		Align align = pWidget->GetHAlign();
		VAlign valign = pWidget->GetVAlign();

		MFVector newSize = cSize;

		if(orientation == Horizontal)
		{
			if(align == Align_Fill) // fill horizontally
			{
				// this widget fills available empty space in the parent container
				newSize.x = slack.x * (pWidget->GetLayoutWeight() / totalWeight);
				pPos.x += newSize.x;
				newSize.x = MFMax(0.f, newSize.x - cMargin.x - cMargin.z);
			}
			else
			{
				pPos.x += cSize.x + cMargin.x + cMargin.z;
			}

			switch(valign)
			{
			case VAlign_None:
			case VAlign_Top:
				pWidget->SetPosition(tPos);
				break;
			case VAlign_Center:
				pWidget->SetPosition(tPos + MakeVector(0, MFMax(tSize.y - cSize.y, 0.f) * 0.5f));
				break;
			case VAlign_Bottom:
				pWidget->SetPosition(tPos + MakeVector(0, MFMax(tSize.y - cSize.y, 0.f)));
				break;
			case VAlign_Fill:
				pWidget->SetPosition(tPos);
				newSize.y = tSize.y;
				break;
			default:
				MFUNREACHABLE;
			}
		}
		else
		{
			if(valign == VAlign_Fill) // fill vertically
			{
				// this widget fills available empty space in the parent container
				newSize.y = slack.y * (pWidget->GetLayoutWeight() / totalWeight);
				pPos.y += newSize.y;
				newSize.y = MFMax(0.f, newSize.y - cMargin.y - cMargin.w);
			}
			else
			{
				pPos.y += cSize.y + cMargin.y + cMargin.w;
			}

			switch(align)
			{
				case Align_None:
				case Align_Left:
					pWidget->SetPosition(tPos);
					break;
				case Align_Center:
					pWidget->SetPosition(tPos + MakeVector(MFMax(tSize.x - cSize.x, 0.f) * 0.5f, 0));
					break;
				case Align_Right:
					pWidget->SetPosition(tPos + MakeVector(MFMax(tSize.x - cSize.x, 0.f), 0));
					break;
				case Align_Fill:
					pWidget->SetPosition(tPos);
					newSize.x = tSize.x;
					break;
				default:
					MFUNREACHABLE;
			}
		}

		ResizeChild(pWidget, newSize);
	}
}
Beispiel #25
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
}
Beispiel #26
0
int F3DFile::ReadMD3(const char *pFilename)
{
	pModel = this;

	char *pBuffer = NULL;

	// open .pk3 file
	unzFile zipFile = unzOpen(pFilename);

	// iterate files in zip
	int zipFileIndex = unzGoToFirstFile(zipFile);

	while(zipFileIndex != UNZ_END_OF_LIST_OF_FILE)
	{
		MFDebug_Assert(zipFileIndex == UNZ_OK, "Error in .zip file.");

		char fileNameBuf[256];
		unz_file_info fileInfo;
		unzGetCurrentFileInfo(zipFile, &fileInfo, fileNameBuf, sizeof(fileNameBuf), NULL, 0, NULL, 0);
		MFString fileName = fileNameBuf;

		if(fileName.EndsWith(".md3"))
		{
			// read fle from zip
			pBuffer = (char*)malloc(fileInfo.uncompressed_size);

			unzOpenCurrentFile(zipFile);
			uint32 bytesRead = unzReadCurrentFile(zipFile, pBuffer, fileInfo.uncompressed_size);
			unzCloseCurrentFile(zipFile);

			MFDebug_Assert(bytesRead == fileInfo.uncompressed_size, "Incorrect number of bytes read..");

			// get subobject and model name..
			int slash = MFMax(fileName.FindCharReverse('/'), fileName.FindCharReverse('\\'));
			MFString subobjectName = fileName.SubStr(slash + 1);

			MFString modelName = fileName.SubStr(0, slash);
			slash = MFMax(modelName.FindCharReverse('/'), modelName.FindCharReverse('\\'));
			pModel->name = modelName.SubStr(slash + 1);

			// search for skin file
			MFString skinFilename = fileName;
			skinFilename.TruncateExtension();
			skinFilename += "_";
			skinFilename += pModel->name;
			skinFilename += ".skin";

			// attempt to read skin..
			char *pSkinFile = NULL;

			zipFileIndex = unzLocateFile(zipFile, skinFilename.CStr(), 0);

			if(zipFileIndex != UNZ_END_OF_LIST_OF_FILE)
			{
				// read skin file from zip
				unz_file_info skinInfo;
				char skinName[256];

				unzGetCurrentFileInfo(zipFile, &skinInfo, skinName, 256, NULL, 0, NULL, 0);

				pSkinFile = (char*)MFHeap_TAlloc(skinInfo.uncompressed_size + 1);
				pSkinFile[skinInfo.uncompressed_size] = 0;

				unzOpenCurrentFile(zipFile);
				uint32 skinBytesRead = unzReadCurrentFile(zipFile, pSkinFile, skinInfo.uncompressed_size);
				unzCloseCurrentFile(zipFile);

				MFDebug_Assert(skinBytesRead == skinInfo.uncompressed_size, "Incorrect number of bytes read..");
			}

			zipFileIndex = unzLocateFile(zipFile, fileName.CStr(), 0);

			// parse MD3
			ParseMD3File(pBuffer, fileInfo.uncompressed_size, subobjectName.CStr(), pSkinFile);

			// free file
			MFHeap_Free(pBuffer);
			pBuffer = NULL;
		}
/*
		else if(!MFString_CaseCmp(".skin", &fileName[Max(filenameLen - 5, 0)]))
		{
			int a, b;
			char skinName[256];

			// get subobject and model name
			for(a = filenameLen - 5; a >= 0; a--)
			{
				if(fileName[a] == '/' || fileName[a] == '\\')
					break;
			}

			char *pSkinName = &fileName[a+1];

			for(b = a-1; b >= 0; b--)
			{
				if(fileName[b] == '/' || fileName[b] == '\\')
					break;
			}

			MFString_Copy(skinName, &fileName[b+1]);
			skinName[a-b-1] = 0;

			pSkinName = strchr(pSkinName, '_');
			DBGASSERT(pSkinName, "Incorrectly named .skin file in .pk3");
			++pSkinName;

			// check that this is the default skin for this model
			if(!MFString_CaseCmpN(pSkinName, skinName, MFString_Length(skinName)))
			{
				// read material file from zip
				pBuffer = (char*)malloc(fileInfo.uncompressed_size);

				unzOpenCurrentFile(zipFile);
				uint32 bytesRead = unzReadCurrentFile(zipFile, pBuffer, fileInfo.uncompressed_size);
				unzCloseCurrentFile(zipFile);

				// parse .skin file

				free(pBuffer);
				pBuffer = NULL;
			}
			else
			{
				// we have an alternate skin.. do nothing..
			}
		}
*/

		zipFileIndex = unzGoToNextFile(zipFile);
	}

	// close .pk3 file
	unzClose(zipFile);

	return 0;
}
Beispiel #27
0
void UpdateEditor()
{
	static GHEvent *pHold[8] = { (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1, (GHEvent*)(size_t)-1 };

	bool ctrlState = MFInput_Read(Key_LControl, IDD_Keyboard) || MFInput_Read(Key_RControl, IDD_Keyboard);
	bool shiftState = MFInput_Read(Key_LShift, IDD_Keyboard) || MFInput_Read(Key_LShift, IDD_Keyboard);
	bool altState = MFInput_Read(Key_LAlt, IDD_Keyboard) || MFInput_Read(Key_RAlt, IDD_Keyboard);

	int res = gEditor.pSong->GetRes();

	if(TestControl(dBCtrl_Edit_Save, GHCT_Once))
	{
		gEditor.pSong->SaveChart();
		MFVoice *pVoice = MFSound_Play(gEditor.pSaveSound, MFPF_BeginPaused);
		MFSound_SetVolume(pVoice, gConfig.sound.fxLevel);
		MFSound_Pause(pVoice, false);

		if(gConfig.editor.saveAction[0])
			system(gConfig.editor.saveAction);
	}

	if(TestControl(dBCtrl_Edit_Event, GHCT_Once))
		PlaceEvent();
	else if(TestControl(dBCtrl_Edit_TrackEvent, GHCT_Once))
		PlaceTrackEvent();
	else if(TestControl(dBCtrl_Edit_Section, GHCT_Once))
		PlaceSection();
	else if(TestControl(dBCtrl_Edit_Quantise, GHCT_Once))
		gpStringBox->Show(MFTranslation_GetString(pStrings, MENU_SETQUANTISE), "", SetCustomQuantisation);
	else if(TestControl(dBCtrl_Edit_Mixer, GHCT_Once))
		((EditorScreen*)dBScreen::GetCurrent())->gMixer.Push();

	// check selection
	if(bSelecting && !TestControl(dBCtrl_Edit_RangeSelect, GHCT_Hold))
	{
		gEditor.selectEnd = gEditor.offset;
		bSelecting = false;
	}
	else if(!bSelecting && TestControl(dBCtrl_Edit_RangeSelect, GHCT_Hold))
	{
		gEditor.selectStart = gEditor.selectEnd = gEditor.offset;
		bSelecting = true;
	}

	if(TestControl(dBCtrl_Edit_Cut, GHCT_Once) || TestControl(dBCtrl_Edit_Copy, GHCT_Once))
	{
		if(gEditor.selectStart != gEditor.selectEnd)
		{
			gEditor.copyLen = gEditor.selectEnd - gEditor.selectStart;

			gEditor.selectEvents.Clear();

			GHEventManager &noteStream = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]];
			GHEvent *pEv = noteStream.GetNextEvent(gEditor.selectStart);

			while(pEv && pEv->tick < gEditor.selectEnd)
			{
				// copy the next pointer incase we cut the note.
				GHEvent *pNext = pEv->Next();

				// just cut/copy notes
				if(pEv->event == GHE_Note)
				{
					// copy to clipboard
					gEditor.selectEvents.AddEvent(pEv->event, pEv->tick - gEditor.selectStart, pEv->key, pEv->parameter);

					// if we cut
					if(TestControl(dBCtrl_Edit_Cut, GHCT_Once))
						pNext = noteStream.RemoveEvent(pEv);
				}

				pEv = pNext;
			}
		}
	}
	else if(TestControl(dBCtrl_Edit_Paste, GHCT_Once))
	{
		GHEvent *pEv = gEditor.selectEvents.First();

		if(pEv)
		{
			int curStream = gEditor.currentStream[gEditor.selectedStream];
			GHEventManager &noteStream = gEditor.pSong->notes[curStream];

			// delete notes in paste range
			GHEvent *pDel = noteStream.GetNextEvent(gEditor.offset);
			while(pDel && pDel->tick < gEditor.offset + gEditor.copyLen)
			{
				if(pDel->event == GHE_Note)
					pDel = noteStream.RemoveEvent(pDel);
				else
					pDel = pDel->Next();
			}

			// paste notes
			while(pEv)
			{
				noteStream.AddEvent(pEv->event, pEv->tick + gEditor.offset, pEv->key, pEv->parameter);
				pEv = pEv->Next();
			}

			gEditor.pSong->CalculateNoteTimes(curStream, gEditor.offset);
		}
	}

	if(TestControl(dBCtrl_Edit_Delete, GHCT_Once))
	{
		GHEventManager &notes = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]];
		if(gEditor.selectStart != gEditor.selectEnd)
		{
			// delete notes in selected range
			GHEvent *pDel = notes.GetNextEvent(gEditor.selectStart);
			while(pDel && pDel->tick < gEditor.selectEnd)
			{
				if(pDel->event == GHE_Note)
					pDel = notes.RemoveEvent(pDel);
				else
					pDel = pDel->Next();
			}
		}
		else
		{
			int numEvents = 0;
			uint32 eventTypes = 0;

			// find note events
			GHEvent *pEvent = notes.GetNextEvent(gEditor.offset);
			while(pEvent && pEvent->tick == gEditor.offset)
			{
				uint32 bit = 1 << pEvent->event;
				if(!(eventTypes & bit))
				{
					++numEvents;
					eventTypes |= bit;
				}
				pEvent = pEvent->Next();
			}

			// find sync events
			if(gEditor.offset > 0)
			{
				pEvent = gEditor.pSong->sync.GetNextEvent(gEditor.offset);
				while(pEvent && pEvent->tick == gEditor.offset)
				{
					uint32 bit = 1 << pEvent->event;
					if(!(eventTypes & bit))
					{
						++numEvents;
						eventTypes |= bit;
					}
					pEvent = pEvent->Next();
				}
			}

			// find global events
			pEvent = gEditor.pSong->events.GetNextEvent(gEditor.offset);
			while(pEvent && pEvent->tick == gEditor.offset)
			{
				uint32 bit = 1 << pEvent->event;
				if(!(eventTypes & bit))
				{
					++numEvents;
					eventTypes |= bit;
				}
				pEvent = pEvent->Next();
			}

			// if there are multiple event types to remove, show a list box
			if(numEvents > 1)
				gpListBox->Show(MFTranslation_GetString(pStrings, SELECT_EVENT_REMOVE), RemoveEventCallback, 200.0f, 100.0f);

			for(int a=0; a<GHE_Max; ++a)
			{
				if(eventTypes & (1 << a))
				{
					if(numEvents > 1)
						gpListBox->AddItem(MFTranslation_GetString(pStrings, EVENT_TYPE_UNKNOWN+a), (void*)(size_t)a);
					else
						RemoveEventCallback(false, 0, NULL, (void*)(size_t)a);
				}
			}
		}
	}

	// shift notes left or right
	int selStart, selEnd;

	if(gEditor.selectStart != gEditor.selectEnd)
	{
		selStart = gEditor.selectStart;
		selEnd = gEditor.selectEnd;
	}
	else
	{
		selStart = gEditor.offset;
		selEnd = gEditor.pSong->GetLastNoteTick();
	}

	if(TestControl(dBCtrl_Edit_ShiftForwards, GHCT_Delay))
	{
		int offset = 4*res / gEditor.quantisation;

		// TODO: gotta remove notes after the selection that will be overwritten as the selection shifts..

		if(altState)
		{
			// shift events, sync and other tracks too
			GHEvent *pEv = gEditor.pSong->sync.GetNextEvent(selStart);
			while(pEv && pEv->tick < selEnd)
			{
				if(pEv->tick != 0)
					pEv->tick += offset;
				pEv = pEv->Next();
			}

			pEv = gEditor.pSong->events.GetNextEvent(selStart);
			while(pEv && pEv->tick < selEnd)
			{
				pEv->tick += offset;
				pEv = pEv->Next();
			}

			for(int i=0; i<GHS_Max; ++i)
			{
				pEv = gEditor.pSong->notes[i].GetNextEvent(selStart);
				while(pEv && pEv->tick < selEnd)
				{
					pEv->tick += offset;
					pEv = pEv->Next();
				}
			}
		}
		else
		{
			GHEvent *pEv = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]].GetNextEvent(selStart);
			while(pEv && pEv->tick < selEnd)
			{
				pEv->tick += offset;
				pEv = pEv->Next();
			}
		}

		gEditor.selectStart += offset;
		gEditor.selectEnd += offset;
		gEditor.offset += offset;

		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[gEditor.selectedStream], gEditor.offset);
	}
	if(TestControl(dBCtrl_Edit_ShiftBackwards, GHCT_Delay))
	{
		int offset = MFMin(4*res / gEditor.quantisation, gEditor.selectStart);

		// TODO: gotta remove notes before the selection that will be overwritten as the selection shifts..

		if(altState)
		{
			// shift events, sync and other tracks too
			GHEvent *pEv = gEditor.pSong->sync.GetNextEvent(selStart);
			while(pEv && pEv->tick < selEnd)
			{
				if(pEv->tick != 0)
					pEv->tick -= offset;
				pEv = pEv->Next();
			}

			pEv = gEditor.pSong->events.GetNextEvent(selStart);
			while(pEv && pEv->tick < selEnd)
			{
				pEv->tick -= offset;
				pEv = pEv->Next();
			}

			for(int i=0; i<GHS_Max; ++i)
			{
				pEv = gEditor.pSong->notes[i].GetNextEvent(selStart);
				while(pEv && pEv->tick < selEnd)
				{
					pEv->tick -= offset;
					pEv = pEv->Next();
				}
			}
		}
		else
		{
			GHEvent *pEv = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]].GetNextEvent(selStart);
			while(pEv && pEv->tick < selEnd)
			{
				pEv->tick -= offset;
				pEv = pEv->Next();
			}
		}

		gEditor.selectStart -= offset;
		gEditor.selectEnd -= offset;
		gEditor.offset -= offset;

		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[gEditor.selectedStream], gEditor.offset);
	}
	if(TestControl(dBCtrl_Edit_ShiftLeft, GHCT_Once))
	{
		GHEvent *pEv = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]].GetNextEvent(selStart);

		while(pEv && pEv->tick < selEnd)
		{
			if(pEv->event == GHE_Note)
				pEv->key = MFMax(0, pEv->key - 1);

			pEv = pEv->Next();
		}
	}
	if(TestControl(dBCtrl_Edit_ShiftRight, GHCT_Once))
	{
		GHEvent *pEv = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]].GetNextEvent(selStart);

		while(pEv && pEv->tick < selEnd)
		{
			if(pEv->event == GHE_Note)
				pEv->key = MFMin(4, pEv->key + 1);

			pEv = pEv->Next();
		}
	}

	// change quantisation
	if(TestControl(dBCtrl_Edit_QuantiseDown, GHCT_Delay))
	{
		gEditor.quantiseStep = MFMax(0, gEditor.quantiseStep-1);
		gEditor.quantisation = gQuantiseSteps[gEditor.quantiseStep];
		OffsetToMeasureAndBeat(gEditor.offset, &gEditor.measure, &gEditor.beat);

		MFVoice *pVoice = MFSound_Play(gEditor.pChangeSound, MFPF_BeginPaused);
		MFSound_SetVolume(pVoice, gConfig.sound.fxLevel);
		MFSound_Pause(pVoice, false);
	}
	if(TestControl(dBCtrl_Edit_QuantiseUp, GHCT_Delay))
	{
		gEditor.quantiseStep = MFMin((int)(sizeof(gQuantiseSteps)/sizeof(gQuantiseSteps[0]))-1, gEditor.quantiseStep+1);
		gEditor.quantisation = gQuantiseSteps[gEditor.quantiseStep];
		OffsetToMeasureAndBeat(gEditor.offset, &gEditor.measure, &gEditor.beat);

		MFVoice *pVoice = MFSound_Play(gEditor.pChangeSound, MFPF_BeginPaused);
		MFSound_SetVolume(pVoice, gConfig.sound.fxLevel);
		MFSound_Pause(pVoice, false);
	}

	// move the track
	if(TestControl(dBCtrl_Edit_Forward, GHCT_Delay))
	{
		// forward one step
		++gEditor.beat;
		if(gEditor.beat == gEditor.quantisation)
		{
			++gEditor.measure;
			gEditor.beat = 0;
		}
	}
	if(TestControl(dBCtrl_Edit_Back, GHCT_Delay))
	{
		// back one step
		if(gEditor.measure || gEditor.beat)
		{
			--gEditor.beat;
			if(gEditor.beat < 0)
			{
				--gEditor.measure;
				gEditor.beat += gEditor.quantisation;
			}
		}
	}
	if(TestControl(dBCtrl_Edit_Start, GHCT_Once))
	{
		// go to start
		gEditor.measure = gEditor.beat = 0;
	}
	if(TestControl(dBCtrl_Edit_End, GHCT_Once))
	{
		// go to the last note...
		OffsetToMeasureAndBeat(gEditor.pSong->GetLastNoteTick(), &gEditor.measure, &gEditor.beat);
	}
	if(TestControl(dBCtrl_Edit_UpMeasure, GHCT_Delay))
	{
		// forward one measure
		// TODO: consider bar lengths while moving
		++gEditor.measure;
	}
	if(TestControl(dBCtrl_Edit_DownMeasure, GHCT_Delay))
	{
		// back one measure
		// TODO: consider bar lengths while moving
		if(gEditor.measure < 1)
			gEditor.measure = gEditor.beat = 0;
		else
			--gEditor.measure;
	}
	if(TestControl(dBCtrl_Edit_NextSection, GHCT_Delay))
	{
		GHEvent *pEv = gEditor.pSong->events.GetNextEvent(gEditor.offset);

		while(pEv)
		{
			if(pEv->tick >= gEditor.offset + gEditor.pSong->resolution*4 / gEditor.quantisation && !MFString_CompareN(pEv->GetString(), "section ", 8))
			{
				OffsetToMeasureAndBeat(pEv->tick, &gEditor.measure, &gEditor.beat);
				break;
			}

			pEv = pEv->Next();
		}

		if(!pEv)
			OffsetToMeasureAndBeat(gEditor.pSong->GetLastNoteTick(), &gEditor.measure, &gEditor.beat);
	}
	if(TestControl(dBCtrl_Edit_PrevSection, GHCT_Delay))
	{
		GHEvent *pMostRecent = NULL;
		GHEvent *pEv = gEditor.pSong->events.First();

		while(pEv && pEv->tick < gEditor.offset)
		{
			if(!MFString_CompareN(pEv->GetString(), "section ", 8))
				pMostRecent = pEv;

			pEv = pEv->Next();
		}

		if(pMostRecent)
			OffsetToMeasureAndBeat(pMostRecent->tick, &gEditor.measure, &gEditor.beat);
		else
			gEditor.measure = gEditor.beat = 0;
	}

	int newOffset = MeasureAndBeatToOffset(gEditor.measure, gEditor.beat);
	int shift = newOffset - gEditor.offset;
	shift = MFMax(gEditor.offset + shift, 0) - gEditor.offset;

	if(shift)
	{
		// update BPM if applicable
		int shiftStart, shiftEnd;

		if(shift > 0)
		{
			shiftStart = gEditor.offset;
			shiftEnd = gEditor.offset+shift + 1;
		}
		else
		{
			shiftStart = 0;
			shiftEnd = gEditor.offset+shift + 1;
		}

		gEditor.offset += shift;

		if(bSelecting)
			gEditor.selectEnd = gEditor.offset;

		GHEvent *pEv = gEditor.pSong->sync.GetNextEvent(shiftStart);

		while(pEv && pEv->tick < shiftEnd)
		{
			if(pEv->event == GHE_BPM || pEv->event == GHE_Anchor)
				gEditor.currentBPM = pEv->parameter;
			else if(pEv->event == GHE_TimeSignature)
			{
				gEditor.currentTimeSignature = pEv->parameter;
				gEditor.lastTimeSignature = pEv->tick;
			}

			pEv = pEv->Next();
		}

		gEditor.playingTime = gEditor.pSong->CalculateTimeOfTick(gEditor.offset);

		MFVoice *pVoice = MFSound_Play(gEditor.pStepSound, MFPF_BeginPaused);
		if(pVoice)
		{
			MFSound_SetVolume(pVoice, gConfig.sound.fxLevel);
			MFSound_Pause(pVoice, false);
		}
	}

	// increase/decrease BPM
	if(gEditor.currentBPM > 1000 && TestControl(dBCtrl_Edit_DecreaseBPM, GHCT_Delay))
	{
		// reduce BPM
		int inc = 1000;

		if(shiftState)
			inc /= 10;
		if(ctrlState)
			inc /= 100;
		if(altState)
			inc *= 10;

		GHEvent *pEv = gEditor.pSong->sync.FindEvent(GHE_BPM, gEditor.offset, 0);
		if(!pEv) pEv = gEditor.pSong->sync.FindEvent(GHE_Anchor, gEditor.offset, 0);

		if(!pEv)
			pEv = gEditor.pSong->sync.AddEvent(GHE_BPM, gEditor.offset, 0, MFMax(gEditor.currentBPM - inc, 1000));
		else
			pEv->parameter = MFMax(pEv->parameter - inc, 1000);

		gEditor.currentBPM = pEv->parameter;

		// remove this BPM marker if its the same as the previous one..
		if(pEv->event != GHE_Anchor)
		{
			GHEvent *pPrev = gEditor.pSong->sync.GetMostRecentEvent(GHE_BPM, gEditor.offset);
			if(pPrev && pPrev->parameter == pEv->parameter)
				gEditor.pSong->sync.RemoveEvent(pEv);
		}

		// recalculate the note times from this point on
		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[0], gEditor.offset);
		if(gEditor.currentStream[1] != -1)
			gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[1], gEditor.offset);
	}

	if(gEditor.currentBPM < 9999000 && TestControl(dBCtrl_Edit_IncreaseBPM, GHCT_Delay))
	{
		// increase BPM
		int inc = 1000;

		if(shiftState)
			inc /= 10;
		if(ctrlState)
			inc /= 100;
		if(altState)
			inc *= 10;

		GHEvent *pEv = gEditor.pSong->sync.FindEvent(GHE_BPM, gEditor.offset, 0);
		if(!pEv) pEv = gEditor.pSong->sync.FindEvent(GHE_Anchor, gEditor.offset, 0);

		if(!pEv)
			pEv = gEditor.pSong->sync.AddEvent(GHE_BPM, gEditor.offset, 0, MFMin(gEditor.currentBPM + inc, 9999000));
		else
			pEv->parameter = MFMin(pEv->parameter + inc, 9999000);

		gEditor.currentBPM = pEv->parameter;

		// remove this BPM marker if its the same as the previous one..
		if(pEv->event != GHE_Anchor)
		{
			GHEvent *pPrev = gEditor.pSong->sync.GetMostRecentEvent(GHE_BPM, gEditor.offset);
			if(pEv->event != GHE_Anchor && pPrev && pPrev->parameter == pEv->parameter)
				gEditor.pSong->sync.RemoveEvent(pEv);
		}

		// recalculate the note times from this point on
		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[0], gEditor.offset);
		if(gEditor.currentStream[1] != -1)
			gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[1], gEditor.offset);
	}

	// place anchor
	if(TestControl(dBCtrl_Edit_Anchor, GHCT_Once) && gEditor.offset > 0)
	{
		GHEvent *pEv = gEditor.pSong->sync.FindEvent(GHE_BPM, gEditor.offset, 0);

		if(pEv)
		{
			pEv->event = GHE_Anchor;
			pEv->time = gEditor.pSong->CalculateTimeOfTick(pEv->tick);
		}
		else
		{
			pEv = gEditor.pSong->sync.FindEvent(GHE_Anchor, gEditor.offset, 0);

			if(!pEv)
			{
				pEv = gEditor.pSong->sync.AddEvent(GHE_Anchor, gEditor.offset, 0, gEditor.currentBPM);
				pEv->time = gEditor.pSong->CalculateTimeOfTick(pEv->tick);
			}
			else
			{
				GHEvent *pLast = gEditor.pSong->sync.GetMostRecentSyncEvent(pEv->tick);

				if(pLast && pLast->parameter == pEv->parameter)
					gEditor.pSong->sync.RemoveEvent(pEv);
				else
					pEv->event = GHE_BPM;
			}
		}

		// recalculate the note times
		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[0], 0);
		if(gEditor.currentStream[1] != -1)
			gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[1], 0);
	}

	// change time signature
	if(TestControl(dBCtrl_Edit_DecreaseTS, GHCT_Delay) && gEditor.currentTimeSignature > 1)
	{
		int tsTime = gEditor.offset - ((gEditor.offset - gEditor.lastTimeSignature) % (res*gEditor.currentTimeSignature));

		GHEvent *pEv = gEditor.pSong->sync.FindEvent(GHE_TimeSignature, tsTime, 0);

		if(!pEv)
			pEv = gEditor.pSong->sync.AddEvent(GHE_TimeSignature, tsTime, 0, gEditor.currentTimeSignature - 1);
		else
			--pEv->parameter;

		gEditor.currentTimeSignature = pEv->parameter;
		gEditor.lastTimeSignature = tsTime;

		// remove this BPM marker if its the same as the previous one..
		GHEvent *pPrev = gEditor.pSong->sync.GetMostRecentEvent(GHE_TimeSignature, tsTime);
		if(pPrev && pPrev->parameter == pEv->parameter)
		{
			gEditor.lastTimeSignature = pPrev->tick;
			gEditor.pSong->sync.RemoveEvent(pEv);
		}

		// recalculate the note times from this point on
		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[0], tsTime);
		if(gEditor.currentStream[1] != -1)
			gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[1], tsTime);
	}
	else if(TestControl(dBCtrl_Edit_IncreaseTS, GHCT_Delay) && gEditor.currentTimeSignature < 99)
	{
		int tsTime = gEditor.offset - ((gEditor.offset - gEditor.lastTimeSignature) % (res*gEditor.currentTimeSignature));

		GHEvent *pEv = gEditor.pSong->sync.FindEvent(GHE_TimeSignature, tsTime, 0);

		if(!pEv)
			pEv = gEditor.pSong->sync.AddEvent(GHE_TimeSignature, tsTime, 0, gEditor.currentTimeSignature + 1);
		else
			++pEv->parameter;

		gEditor.currentTimeSignature = pEv->parameter;
		gEditor.lastTimeSignature = tsTime;

		// remove this BPM marker if its the same as the previous one..
		GHEvent *pPrev = gEditor.pSong->sync.GetMostRecentEvent(GHE_TimeSignature, tsTime);
		if(pPrev && pPrev->parameter == pEv->parameter)
		{
			gEditor.lastTimeSignature = pPrev->tick;
			gEditor.pSong->sync.RemoveEvent(pEv);
		}

		// recalculate the note times from this point on
		gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[0], tsTime);
		if(gEditor.currentStream[1] != -1)
			gEditor.pSong->CalculateNoteTimes(gEditor.currentStream[1], tsTime);
	}

	// add/remove notes
	GHEventManager &noteStream = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]];
	dBControlType keys_righty[] = { dBCtrl_Edit_Note0, dBCtrl_Edit_Note1, dBCtrl_Edit_Note2, dBCtrl_Edit_Note3, dBCtrl_Edit_Note4, dBCtrl_Edit_PS1, dBCtrl_Edit_PS2, dBCtrl_Edit_Note5 };
	dBControlType keys_lefty[] = { dBCtrl_Edit_Note4, dBCtrl_Edit_Note3, dBCtrl_Edit_Note2, dBCtrl_Edit_Note1, dBCtrl_Edit_Note0, dBCtrl_Edit_PS1, dBCtrl_Edit_PS2, dBCtrl_Edit_Note5 };
	dBControlType *keys = gConfig.controls.leftyFlip[0] ? keys_lefty : keys_righty;

	for(int a=0; a<8; a++)
	{
		GHEventType ev = a < 5 ? GHE_Note : GHE_Special;
		int key = a < 5 ? GHEK_Green + a : GHS_Player1 + (a - 5);

		if(TestControl(keys[a], GHCT_Hold))
		{
			if(pHold[a])
			{
				if(pHold[a] != (GHEvent*)(size_t)0xFFFFFFFF)
				{
					pHold[a]->parameter = MFMax(gEditor.offset - pHold[a]->tick, 0);
				}
			}
			else
			{
				GHEvent *pEv = noteStream.FindEvent(ev, gEditor.offset, key);

				if(pEv)
				{
					noteStream.RemoveEvent(pEv);
					pHold[a] = (GHEvent*)(size_t)0xFFFFFFFF;
					for(int i=0; i<8; ++i)
					{
						if(pHold[i] && pHold[i] != (GHEvent*)(size_t)0xFFFFFFFF)
						{
							if(pHold[i] > pEv)
								--pHold[i];
						}
					}
				}
				else
				{
					// check if we are intersecting a hold note
					pEv = noteStream.GetMostRecentEvent(GHE_Note, gEditor.offset);

					if(pEv && pEv->parameter > gEditor.offset - pEv->tick)
					{
						// the last note was a hold note, we'll cut it short...
						do
						{
							pEv->parameter = gEditor.offset - pEv->tick;
							pEv = pEv->Prev();
						}
						while(pEv && pEv->tick == pEv->Next()->tick);
					}

					pEv = noteStream.AddEvent(ev, gEditor.offset, key);
					pEv->time = gEditor.pSong->CalculateTimeOfTick(gEditor.offset);
					pHold[a] = pEv;
				}
			}
		}
		else
		{
			if(a<5)
			{
				// check if we have just released a hold note
				if(pHold[a] && pHold[a] != (GHEvent*)(size_t)0xFFFFFFFF && pHold[a]->parameter != 0)
				{
					// remove any other notes within the hold range
					GHEvent *pEv = gEditor.pSong->notes[gEditor.currentStream[gEditor.selectedStream]].GetNextEvent(pHold[a]->tick);

					while(pEv && pEv->tick < pHold[a]->tick+pHold[a]->parameter)
					{
						GHEvent *pNext = pEv->Next();

						if(pEv->event == GHE_Note)
						{
							// and make sure we dont remove chords
							if(pHold[a]->tick != pEv->tick || pHold[a]->parameter != pEv->parameter)
							{
								pNext = noteStream.RemoveEvent(pEv);
								for(int i=0; i<8; ++i)
								{
									if(pHold[i] && pHold[i] != (GHEvent*)(size_t)0xFFFFFFFF)
									{
										if(pHold[i] > pEv)
											--pHold[i];
									}
								}
							}
						}

						pEv = pNext;
					}
				}
			}
			else
			{
				// remove zero length special events...
				if(pHold[a] && pHold[a] != (GHEvent*)(size_t)0xFFFFFFFF && pHold[a]->parameter == 0)
				{
					noteStream.RemoveEvent(pHold[a]);
				}
			}

			pHold[a] = NULL;
		}
	}
}