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; }
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; }
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; }
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; }
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; }
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(); } }
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()); }
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); } } }
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; }
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; }
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; } } }
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 ¬eStream = 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(); }
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; } } } } }
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; }
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); } }
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); } }
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 }
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; }
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 ¬eStream = 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 ¬eStream = 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 ¬es = 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 ¬eStream = 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; } } }