windows-nt/Source/XPSP1/NT/multimedia/directx/dinput/pid/pidparam.c
2020-09-26 16:20:57 +08:00

944 lines
27 KiB
C

/*****************************************************************************
*
* PidParam.c
*
* Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
*
* Abstract:
*
* Download PID parameter block(s) .
*
*****************************************************************************/
#include "pidpr.h"
#define sqfl ( sqflParam )
//struct to keep in relevant data for g_Custom
typedef struct PIDCUSTOM
{
DWORD DataOffset;
DWORD cSamples;
DWORD dwSamplePeriod;
} PIDCUSTOM, *PPIDCUSTOM;
#pragma BEGIN_CONST_DATA
static PIDUSAGE c_rgUsgEnvelope[] =
{
MAKE_PIDUSAGE(ATTACK_LEVEL, FIELD_OFFSET(DIENVELOPE,dwAttackLevel) ),
MAKE_PIDUSAGE(ATTACK_TIME, FIELD_OFFSET(DIENVELOPE,dwAttackTime) ),
MAKE_PIDUSAGE(FADE_LEVEL, FIELD_OFFSET(DIENVELOPE,dwFadeLevel) ),
MAKE_PIDUSAGE(FADE_TIME, FIELD_OFFSET(DIENVELOPE,dwFadeTime) ),
};
PIDREPORT g_Envelope =
{
HidP_Output,
HID_USAGE_PAGE_PID,
HID_USAGE_PID_SET_ENVELOPE_REPORT,
cbX(DIENVELOPE),
cA(c_rgUsgEnvelope),
c_rgUsgEnvelope
};
static PIDUSAGE c_rgUsgCondition[] =
{
MAKE_PIDUSAGE(CP_OFFSET, FIELD_OFFSET(DICONDITION, lOffset) ),
MAKE_PIDUSAGE(POSITIVE_COEFFICIENT, FIELD_OFFSET(DICONDITION, lPositiveCoefficient)),
MAKE_PIDUSAGE(NEGATIVE_COEFFICIENT, FIELD_OFFSET(DICONDITION, lNegativeCoefficient)),
MAKE_PIDUSAGE(POSITIVE_SATURATION, FIELD_OFFSET(DICONDITION, dwPositiveSaturation)),
MAKE_PIDUSAGE(NEGATIVE_SATURATION, FIELD_OFFSET(DICONDITION, dwNegativeSaturation)),
MAKE_PIDUSAGE(DEAD_BAND, FIELD_OFFSET(DICONDITION, lDeadBand)),
};
PIDREPORT g_Condition =
{
HidP_Output,
HID_USAGE_PAGE_PID,
HID_USAGE_PID_SET_CONDITION_REPORT,
cbX(DICONDITION),
cA(c_rgUsgCondition),
c_rgUsgCondition
};
static PIDUSAGE c_rgUsgPeriodic[] =
{
MAKE_PIDUSAGE(OFFSET, FIELD_OFFSET(DIPERIODIC,lOffset)),
MAKE_PIDUSAGE(MAGNITUDE, FIELD_OFFSET(DIPERIODIC,dwMagnitude)),
MAKE_PIDUSAGE(PHASE, FIELD_OFFSET(DIPERIODIC,dwPhase)),
MAKE_PIDUSAGE(PERIOD, FIELD_OFFSET(DIPERIODIC,dwPeriod)),
};
PIDREPORT g_Periodic =
{
HidP_Output,
HID_USAGE_PAGE_PID,
HID_USAGE_PID_SET_PERIODIC_REPORT,
cbX(DIPERIODIC),
cA(c_rgUsgPeriodic),
c_rgUsgPeriodic
};
static PIDUSAGE c_rgUsgConstant[] =
{
MAKE_PIDUSAGE(MAGNITUDE, FIELD_OFFSET(DICONSTANTFORCE, lMagnitude)),
};
PIDREPORT g_Constant =
{
HidP_Output,
HID_USAGE_PAGE_PID,
HID_USAGE_PID_SET_CONSTANT_FORCE_REPORT,
cbX(DICONSTANTFORCE),
cA(c_rgUsgConstant),
c_rgUsgConstant
};
static PIDUSAGE c_rgUsgRamp[] =
{
MAKE_PIDUSAGE(RAMP_START, FIELD_OFFSET(DIRAMPFORCE, lStart)),
MAKE_PIDUSAGE(RAMP_END, FIELD_OFFSET(DIRAMPFORCE, lEnd)),
};
PIDREPORT g_Ramp =
{
HidP_Output,
HID_USAGE_PAGE_PID,
HID_USAGE_PID_SET_RAMP_FORCE_REPORT,
cbX(DIRAMPFORCE),
cA(c_rgUsgRamp),
c_rgUsgRamp
};
static PIDUSAGE c_rgUsgCustom[]=
{
MAKE_PIDUSAGE(CUSTOM_FORCE_DATA_OFFSET, FIELD_OFFSET(PIDCUSTOM, DataOffset)),
MAKE_PIDUSAGE(SAMPLE_COUNT, FIELD_OFFSET(PIDCUSTOM, cSamples)),
MAKE_PIDUSAGE(SAMPLE_PERIOD, FIELD_OFFSET(PIDCUSTOM, dwSamplePeriod)),
};
PIDREPORT g_Custom =
{
HidP_Output,
HID_USAGE_PAGE_PID,
HID_USAGE_PID_SET_CUSTOM_FORCE_REPORT,
cbX(PIDCUSTOM),
cA(c_rgUsgCustom),
c_rgUsgCustom,
};
static PIDUSAGE c_rgUsgCustomData[]=
{
MAKE_PIDUSAGE(CUSTOM_FORCE_DATA_OFFSET, 0x0),
MAKE_HIDUSAGE(GENERIC, HID_USAGE_GENERIC_BYTE_COUNT, 0x0),
MAKE_PIDUSAGE(CUSTOM_FORCE_DATA, 0x0 ),
};
PIDREPORT g_CustomData =
{
HidP_Output,
HID_USAGE_PAGE_PID,
HID_USAGE_PID_CUSTOM_FORCE_DATA_REPORT,
cbX(DWORD),
cA(c_rgUsgCustomData),
c_rgUsgCustomData,
};
static PIDUSAGE c_rgUsgDirectionAxes[]=
{
MAKE_HIDUSAGE(GENERIC, HID_USAGE_GENERIC_X, 0*cbX(ULONG)),
MAKE_HIDUSAGE(GENERIC, HID_USAGE_GENERIC_Y, 1*cbX(ULONG)),
MAKE_HIDUSAGE(GENERIC, HID_USAGE_GENERIC_Z, 2*cbX(ULONG)),
};
PIDREPORT g_CustomSample =
{
HidP_Output,
HID_USAGE_PAGE_PID,
HID_USAGE_PID_DOWNLOAD_FORCE_SAMPLE ,
cbX(DWORD),
cA(c_rgUsgDirectionAxes),
c_rgUsgDirectionAxes,
};
static PIDUSAGE c_rgUsgParameterOffset[] =
{
MAKE_PIDUSAGE(PARAMETER_BLOCK_OFFSET, 0x0 ),
};
static PIDREPORT g_ParameterOffset =
{
HidP_Output,
HID_USAGE_PAGE_PID,
0x0,
cbX(DWORD),
cA(c_rgUsgParameterOffset),
c_rgUsgParameterOffset
};
#pragma END_CONST_DATA
//global variable to keep in relevant data for g_Custom
PIDCUSTOM g_PidCustom;
STDMETHODIMP
PID_GetParameterOffset
(
IDirectInputEffectDriver *ped,
DWORD dwEffectIndex,
UINT uParameter,
DWORD dwSz,
PLONG plValue
)
{
CPidDrv *this = (CPidDrv *)ped;
HRESULT hres = S_OK;
USHORT uOffset = (USHORT)-1;
PEFFECTSTATE pEffectState = PeffectStateFromBlockIndex(this,dwEffectIndex);
PPIDMEM pMem = &pEffectState->PidMem[uParameter];
EnterProcI( PID_GetParameterOffset, (_"xxxxx", ped, dwEffectIndex, uParameter, dwSz, plValue));
AssertF(uParameter < this->cMaxParameters);
*plValue = 0x0;
hres = PID_ValidateEffectIndex(ped, dwEffectIndex);
if(SUCCEEDED(hres))
{
// We have already allocated memory,
// Just return the last size
if( PIDMEM_SIZE(pMem) != 0x0 )
{
uOffset = PIDMEM_OFFSET(pMem);
} else if( dwSz == 0x0 )
{
// Logitech device wants parameter blocks to
// set to -1 if they do not exist
uOffset = (USHORT)-1;
} else
{
// New Allocation
PPIDMEM pTmp, pNext;
UINT nAlloc;
USHORT uSz;
PUNITSTATE pUnitState = (PUNITSTATE)(g_pshmem + this->iUnitStateOffset);
hres = DIERR_OUTOFMEMORY;
// Align memory request
uSz = (USHORT)((dwSz / this->ReportPool.uPoolAlign + 1) * (this->ReportPool.uPoolAlign));
AssertF(uSz >= (USHORT)this->ReportPool.uPoolAlign);
//To be doubly sure.
uSz = max( uSz, (USHORT)this->ReportPool.uPoolAlign);
WaitForSingleObject(g_hmtxShared, INFINITE);
for(nAlloc = 0x0, pTmp = &(pUnitState->Guard[0]), pNext = (PPIDMEM)((PUCHAR)pUnitState + pTmp->iNext);
nAlloc < pUnitState->nAlloc && pTmp != &(pUnitState->Guard[1]);
nAlloc++, pTmp = pNext, pNext = (PPIDMEM)((PUCHAR)pUnitState + pTmp->iNext))
{
SquirtSqflPtszV(sqfl | sqflVerbose,
TEXT("%d %x(%x), Next:%x (%x) "),
nAlloc, pTmp, pTmp->uOfSz, pNext, pNext->uOfSz );
AssertF(pNext != NULL );
// If pNext == pUnitState, it means that the offset is 0.
// The offset of 0 is invalid.
AssertF((PUCHAR)pNext != (PUCHAR)pUnitState);
// Is there space in the cracks
if( GET_NEXTOFFSET(pTmp) + uSz < PIDMEM_OFFSET(pNext) )
{
pMem->iNext = (PUCHAR)pNext - (PUCHAR)pUnitState;
pTmp->iNext = (PUCHAR)pMem - (PUCHAR)pUnitState;
uOffset = GET_NEXTOFFSET(pTmp) ;
pMem->uOfSz = PIDMEM_OFSZ(uOffset, uSz);
pUnitState->nAlloc++;
pUnitState->cbAlloc += uSz;
hres = S_OK;
SquirtSqflPtszV(sqfl | sqflVerbose,
TEXT("%d %p (%x), Next: %p (%x) "),
nAlloc, pMem, pMem->uOfSz, pNext, pNext->uOfSz );
break;
}
}
ReleaseMutex(g_hmtxShared);
}
}
if( SUCCEEDED(hres) )
{
*plValue = (ULONG)uOffset;
} else
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s:FAIL Could not allocate %d bytes, UsedMem:%d, Allocs%d"),
s_tszProc, dwSz, ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->cbAlloc, ((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->nAlloc );
}
ExitOleProc();
return hres;
}
HRESULT
PID_SendParameterBlock
(
IDirectInputEffectDriver *ped,
DWORD dwEffectIndex,
DWORD dwMemSz,
PUINT puParameter,
PPIDREPORT pPidReport,
PVOID pvData,
UINT cbData,
BOOL bBlocking,
UINT totalBlocks
)
{
CPidDrv *this = (CPidDrv *)ped;
HRESULT hres=S_OK;
PUCHAR pReport;
UINT cbReport;
EnterProcI( PID_SendParameterBlock, (_"xxxxx", ped, dwEffectIndex, dwMemSz, pPidReport, pvData, cbData));
AssertF(pPidReport->HidP_Type == HidP_Output);
cbReport = this->cbReport[pPidReport->HidP_Type];
pReport = this->pReport[pPidReport->HidP_Type];
if( *puParameter >= this->cMaxParameters )
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s:FAIL Only support %d parameter blocks per effect "),
s_tszProc, *puParameter );
hres = E_NOTIMPL;
}
if( SUCCEEDED(hres) )
{
USHORT LinkCollection;
ZeroBuf(pReport, cbReport);
PID_GetLinkCollectionIndex(ped, pPidReport->UsagePage, pPidReport->Collection, 0x0, &LinkCollection);
hres = PID_PackValue
(
ped,
pPidReport,
LinkCollection,
pvData,
cbData,
pReport,
cbReport
);
// For device managed memory, we need to send the
// effect index
if( SUCCEEDED(hres) )
{
if( this->uDeviceManaged & PID_DEVICEMANAGED )
{
// Must be a valid effect ID
AssertF(dwEffectIndex != 0x0 );
/*hres =*/
PID_PackValue
(
ped,
&g_BlockIndex,
LinkCollection,
&dwEffectIndex,
cbX(dwEffectIndex),
pReport,
cbReport
);
// Send down the paramter block index
/*hres =*/PID_PackValue
(
ped,
&g_ParameterOffset,
LinkCollection,
puParameter,
cbX(*puParameter),
pReport,
cbReport
);
} else
{
LONG lValue;
hres = PID_GetParameterOffset(ped, dwEffectIndex, *puParameter, dwMemSz, &lValue);
if( SUCCEEDED(hres) )
{
hres = PID_PackValue
(
ped,
&g_ParameterOffset,
LinkCollection,
&lValue,
cbX(lValue),
pReport,
cbReport
);
}
}
}
if( SUCCEEDED(hres) )
{
hres = PID_SendReport(ped, pReport, cbReport, pPidReport->HidP_Type, bBlocking, *puParameter, totalBlocks);
}
if(SUCCEEDED(hres))
{
(*puParameter)++;
}
}
ExitOleProc();
return hres;
}
/*****************************************************************************
*
* PID_DownloadCustomForceData
*
* Download custom force sample data to the device.
*
*****************************************************************************/
STDMETHODIMP
PID_DownloadCustomForceData
(
IDirectInputEffectDriver *ped,
DWORD dwEffectIndex,
PUINT puParameter,
LPCDICUSTOMFORCE pCustom,
LPCDIEFFECT peff
)
{
CPidDrv *this = (CPidDrv *)ped;
HRESULT hres = S_OK;
PCHAR pData = NULL;
PCHAR pBuff = NULL;
USHORT cbData;
USHORT nBytes;
USHORT bitsX;
USHORT bitsY;
USHORT bitsZ;
LPLONG pSample;
EnterProcI( PID_DownloadCustomForceData, (_"xxx", ped, dwEffectIndex, pCustom, puParameter ));
//zero out g_PidCustom
g_PidCustom.cSamples = g_PidCustom.DataOffset = g_PidCustom.dwSamplePeriod = 0;
//get bytes per sample and allocate the buffer
bitsX = this->customCaps[0].BitSize;
bitsY = this->customCaps[1].BitSize;
bitsZ = this->customCaps[2].BitSize;
//byte count must be multiple of 8!
if ((bitsX%8 != 0) || (bitsY%8 != 0) || (bitsZ%8 != 0))
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s:FAIL Download Force Sample report fields that are not multiples of 8 are not supported!\n"),
s_tszProc );
hres = E_NOTIMPL;
}
//report count shouldn't be bigger than 1!
AssertF(this->customCaps[0].ReportCount <= 1);
AssertF(this->customCaps[1].ReportCount <= 1);
AssertF(this->customCaps[2].ReportCount <= 1);
if (SUCCEEDED(hres))
{
nBytes = (bitsX + bitsY + bitsZ)/8;
cbData = (USHORT) (pCustom->cSamples * nBytes);
hres = AllocCbPpv(cbData, &pBuff);
if( pBuff != NULL)
{
//determine which effect axis corresponds to which report axis
LONG Offset[3] = {-1, -1, -1};
int nAxis = 0;
int nChannel = 0;
int nSample = 0;
for (nChannel = 0; nChannel < (int)pCustom->cChannels, nChannel < (int)peff->cAxes; nChannel ++)
{
for (nAxis = 0; nAxis < 3; nAxis ++)
{
if (DIGETUSAGE(peff->rgdwAxes[nChannel]) == DIGETUSAGE(g_CustomSample.rgPidUsage[nAxis].dwUsage))
{
Offset[nAxis] = nChannel;
}
}
}
ZeroBuf(pBuff, cbData);
pData = pBuff;
pSample = pCustom->rglForceData;
//scale all the samples
//loop through samples
for (nSample = 0; nSample < (int)pCustom->cSamples; nSample ++)
{
//loop through report axis
for (nAxis = 0; nAxis < 3; nAxis++)
{
LONG lSampleValue = 0;
//check if this axis is used
if (Offset[nAxis] == -1)
{
pData += this->customCaps[nAxis].BitSize/8;
continue;
}
lSampleValue = *(pSample + Offset[nAxis]);
switch (this->customCaps[nAxis].BitSize)
{
case 8:
//8-bit reports
{
(*((BYTE*)pData)) = (BYTE)(this->customCaps[nAxis].LogicalMin + ((lSampleValue + DI_FFNOMINALMAX) * (this->customCaps[nAxis].LogicalMax - this->customCaps[nAxis].LogicalMin))/(2*DI_FFNOMINALMAX));
pData++;
break;
}
case 16:
//16-bit reports
{
(*((SHORT*)pData)) = (SHORT)(this->customCaps[nAxis].LogicalMin + ((lSampleValue + DI_FFNOMINALMAX) * (this->customCaps[nAxis].LogicalMax - this->customCaps[nAxis].LogicalMin))/(2*DI_FFNOMINALMAX));
pData++;
break;
}
case 32:
//assume 32-bit reports as default
{
(*((LONG*)pData)) = (LONG)(this->customCaps[nAxis].LogicalMin + ((lSampleValue + DI_FFNOMINALMAX) * (this->customCaps[nAxis].LogicalMax - this->customCaps[nAxis].LogicalMin))/(2*DI_FFNOMINALMAX));
pData++;
break;
}
default:
{
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s:FAIL Download Force Sample report fields that are not 8, 16 or 32 are not supported\n"),
s_tszProc );
hres = E_NOTIMPL;
}
}
}
pSample += pCustom->cChannels;
}
}
if(SUCCEEDED(hres))
{
PCHAR pReport;
UINT cbReport;
HIDP_REPORT_TYPE HidP_Type = HidP_Output;
USAGE UsagePage = HID_USAGE_PAGE_PID;
USAGE UsageData = HID_USAGE_PID_CUSTOM_FORCE_DATA;
USAGE UsageOffset = HID_USAGE_PID_CUSTOM_FORCE_DATA_OFFSET;
USHORT LinkCollection = 0x0;
cbReport = this->cbReport[g_CustomData.HidP_Type];
pReport = this->pReport[g_CustomData.HidP_Type];
if ((this->customDataCaps.ReportCount > 0) && (this->customDataCaps.BitSize >=8))
{
USHORT nOffset = 0;
LONG lOffset = 0;
USHORT nIncrement = (this->customDataCaps.ReportCount * this->customDataCaps.BitSize)/8;
// For memory managed device allocate enough memory
// holding the custom force samples
if( ! (this->uDeviceManaged & PID_DEVICEMANAGED ))
{
hres = PID_GetParameterOffset(ped, dwEffectIndex, *puParameter, this->SzPool.uSzCustom, &lOffset);
}
pData = pBuff;
if (SUCCEEDED(hres))
{
//send data in a loop
for (nOffset = 0; nOffset < cbData; nOffset += nIncrement)
{
//create a new buffer and copy data into it
PCHAR pIncrement = NULL;
hres = AllocCbPpv(nIncrement, &pIncrement);
if (pIncrement != NULL)
{
ZeroBuf(pIncrement, nIncrement);
memcpy(pIncrement, pData, min((cbData - nOffset), nIncrement));
ZeroBuf(pReport, cbReport);
//set the byte count
hres = HidP_SetScaledUsageValue
(
HidP_Type,
HID_USAGE_PAGE_GENERIC,
LinkCollection,
HID_USAGE_GENERIC_BYTE_COUNT,
(LONG)nIncrement,
this->ppd,
pReport,
cbReport
);
//set the offset
hres = HidP_SetScaledUsageValue
(
HidP_Type,
UsagePage,
0x0,
//LinkCollection,
UsageOffset,
(LONG) (nOffset + lOffset),
this->ppd,
pReport,
cbReport
);
//set the data
hres = HidP_SetUsageValueArray
(
HidP_Type, // IN HIDP_REPORT_TYPE ReportType,
UsagePage, // IN USAGE UsagePage,
0x0, // IN USHORT LinkCollection, // Optional
UsageData,
pIncrement, // IN PCHAR UsageValue,
nIncrement, // IN USHORT UsageValueByteLength,
this->ppd, // IN PHIDP_PREPARSED_DATA PreparsedData,
pReport, // OUT PCHAR Report,
cbReport // IN ULONG ReportLength
);
//set the effect index
PID_PackValue
(
ped,
&g_BlockIndex,
LinkCollection,
&dwEffectIndex,
cbX(dwEffectIndex),
pReport,
cbReport
);
//send the report
hres = PID_SendReport(ped, pReport, cbReport, HidP_Type, TRUE, 0, 1);
pData += nIncrement;
FreePpv(&pIncrement);
}
}
//put data into g_PidCustom
g_PidCustom.DataOffset = (DWORD)lOffset;
g_PidCustom.cSamples = pCustom->cSamples;
//ISSUE-2001/03/29-timgill May need to do real scaling.
g_PidCustom.dwSamplePeriod = pCustom->dwSamplePeriod/1000; //in milliseconds
//and increment puParameter
(*puParameter)++;
}
}
else
{
//do nothing
}
FreePpv(&pBuff);
}
}
ExitOleProc();
return hres;
}
STDMETHODIMP
PID_DoParameterBlocks
(
IDirectInputEffectDriver *ped,
DWORD dwId,
DWORD dwEffectId,
DWORD dwEffectIndex,
LPCDIEFFECT peff,
DWORD dwFlags,
PUINT puParameter,
BOOL bBlocking,
UINT totalBlocks
)
{
CPidDrv *this = (CPidDrv *)ped;
HRESULT hres = S_OK;
EnterProcI( PID_DoParameterBlocks, (_"xxxxxxx", ped, dwId, dwEffectId, dwEffectIndex, peff, dwFlags, puParameter ));
if( SUCCEEDED(hres)
&& (dwFlags & DIEP_TYPESPECIFICPARAMS) )
{
AssertF(peff->lpvTypeSpecificParams != NULL);
AssertF(peff->cbTypeSpecificParams != 0x0 );
switch(dwEffectId)
{
case PIDMAKEUSAGEDWORD(ET_CONSTANT) :
{
DICONSTANTFORCE DiParam;
AssertF(peff->cbTypeSpecificParams <= cbX(DiParam) );
memcpy(&DiParam, peff->lpvTypeSpecificParams, cbX(DiParam));
// Constant Force:
// Scale the magnitude.
DiParam.lMagnitude = Clamp(-DI_FFNOMINALMAX, DiParam.lMagnitude, DI_FFNOMINALMAX);
PID_ApplyScalingFactors(ped, &g_Constant, &this->DiSConstScale, cbX(this->DiSConstScale), &this->DiSConstOffset, cbX(this->DiSConstOffset), &DiParam, cbX(DiParam) );
hres = PID_SendParameterBlock
(
ped,
dwEffectIndex,
this->SzPool.uSzConstant,
puParameter,
&g_Constant,
&DiParam,
cbX(DiParam),
bBlocking,
totalBlocks
);
break;
}
case PIDMAKEUSAGEDWORD(ET_RAMP):
{
// Ramp Force
DIRAMPFORCE DiParam;
AssertF(peff->cbTypeSpecificParams <= cbX(DiParam) );
memcpy(&DiParam, peff->lpvTypeSpecificParams, cbX(DiParam));
//Scale the magnitude
DiParam.lStart = Clamp(-DI_FFNOMINALMAX, DiParam.lStart, DI_FFNOMINALMAX);
DiParam.lEnd = Clamp(-DI_FFNOMINALMAX, DiParam.lEnd, DI_FFNOMINALMAX);
PID_ApplyScalingFactors(ped, &g_Ramp, &this->DiSRampScale, cbX(this->DiSRampScale), &this->DiSRampOffset, cbX(this->DiSRampOffset), &DiParam, cbX(DiParam) );
hres = PID_SendParameterBlock
(
ped,
dwEffectIndex,
this->SzPool.uSzRamp,
puParameter,
&g_Ramp,
&DiParam,
cbX(DiParam),
bBlocking,
totalBlocks
);
break;
}
case PIDMAKEUSAGEDWORD(ET_SQUARE):
case PIDMAKEUSAGEDWORD(ET_SINE):
case PIDMAKEUSAGEDWORD(ET_TRIANGLE):
case PIDMAKEUSAGEDWORD(ET_SAWTOOTH_UP):
case PIDMAKEUSAGEDWORD(ET_SAWTOOTH_DOWN):
{
DIPERIODIC DiParam;
AssertF(peff->cbTypeSpecificParams <= cbX(DiParam) );
memcpy(&DiParam, peff->lpvTypeSpecificParams, cbX(DiParam));
//Scale the parameters
DiParam.dwMagnitude = Clip( DiParam.dwMagnitude, DI_FFNOMINALMAX);
DiParam.lOffset = Clamp(-DI_FFNOMINALMAX, DiParam.lOffset, DI_FFNOMINALMAX);
//Wrap the phase around
DiParam.dwPhase %= (360*DI_DEGREES);
PID_ApplyScalingFactors(ped, &g_Periodic, &this->DiSPeriodicScale, cbX(this->DiSPeriodicScale), &this->DiSPeriodicOffset, cbX(this->DiSPeriodicOffset), &DiParam, cbX(DiParam) );
hres = PID_SendParameterBlock
(
ped,
dwEffectIndex,
this->SzPool.uSzPeriodic,
puParameter,
&g_Periodic,
&DiParam,
cbX(DiParam),
bBlocking,
totalBlocks
);
break;
}
case PIDMAKEUSAGEDWORD(ET_SPRING):
case PIDMAKEUSAGEDWORD(ET_DAMPER):
case PIDMAKEUSAGEDWORD(ET_INERTIA):
case PIDMAKEUSAGEDWORD(ET_FRICTION):
{
LPDICONDITION lpCondition;
DWORD nStruct;
DWORD cStruct = (peff->cbTypeSpecificParams)/sizeof(DICONDITION);
AssertF(cStruct <= peff->cAxes);
for(nStruct = 0x0, lpCondition = (LPDICONDITION)peff->lpvTypeSpecificParams;
nStruct < cStruct && SUCCEEDED(hres);
nStruct++, lpCondition++ )
{
DICONDITION DiCondition;
DiCondition = *lpCondition;
//Scale the values
DiCondition.lOffset = Clamp(-DI_FFNOMINALMAX, DiCondition.lOffset, DI_FFNOMINALMAX);
DiCondition.lPositiveCoefficient = Clamp(-DI_FFNOMINALMAX, DiCondition.lPositiveCoefficient, DI_FFNOMINALMAX);
DiCondition.lNegativeCoefficient = Clamp(-DI_FFNOMINALMAX, DiCondition.lNegativeCoefficient, DI_FFNOMINALMAX);
DiCondition.dwPositiveSaturation = Clip( DiCondition.dwPositiveSaturation, DI_FFNOMINALMAX);
DiCondition.dwNegativeSaturation = Clip( DiCondition.dwNegativeSaturation, DI_FFNOMINALMAX);
DiCondition.lDeadBand = Clamp(0, DiCondition.lDeadBand, DI_FFNOMINALMAX);
PID_ApplyScalingFactors(ped, &g_Condition, &this->DiSCondScale, cbX(this->DiSCondScale), &this->DiSCondOffset, cbX(this->DiSCondOffset), &DiCondition, cbX(DiCondition) );
hres = PID_SendParameterBlock
(
ped,
dwEffectIndex,
this->SzPool.uSzCondition,
puParameter,
&g_Condition,
&DiCondition,
sizeof(DiCondition),
bBlocking,
totalBlocks
);
}
//Conditions can't have envelopes!
//So if there's a flag indicating an envelope, take it out.
dwFlags &= ~(DIEP_ENVELOPE);
break;
}
case PIDMAKEUSAGEDWORD(ET_CUSTOM):
{
// Custom Force
DICUSTOMFORCE DiParam;
AssertF(peff->cbTypeSpecificParams <= cbX(DiParam) );
memcpy(&DiParam, peff->lpvTypeSpecificParams, cbX(DiParam));
// Download Custom Force -- always a blocking call
hres = PID_DownloadCustomForceData(ped, dwEffectIndex, puParameter, &DiParam, peff);
if( SUCCEEDED(hres) )
{
// Set custom Effect parameter block header -- always a blocking call
hres = PID_SendParameterBlock
(
ped,
dwEffectIndex,
this->SzPool.uSzCustom,
puParameter,
&g_Custom,
&g_PidCustom,
cbX(DiParam),
TRUE,
totalBlocks
);
}
break;
}
default:
hres = DIERR_PID_USAGENOTFOUND;
SquirtSqflPtszV(sqfl | sqflError,
TEXT("%s:FAIL Unknown parameter block for dwEffectId(0x%x)"),
s_tszProc, dwEffectId );
break;
}
}
if( SUCCEEDED(hres)
&& (dwFlags & DIEP_ENVELOPE)
&& peff->lpEnvelope != NULL )
{
DIENVELOPE DiEnv;
DiEnv = *peff->lpEnvelope;
//Scale the values
DiEnv.dwAttackLevel = Clip(DiEnv.dwAttackLevel, DI_FFNOMINALMAX);
DiEnv.dwFadeLevel = Clip(DiEnv.dwFadeLevel, DI_FFNOMINALMAX);
PID_ApplyScalingFactors(ped, &g_Envelope, &this->DiSEnvScale, cbX(this->DiSEnvScale), &this->DiSEnvOffset, cbX(this->DiSEnvOffset), &DiEnv, DiEnv.dwSize );
hres = PID_SendParameterBlock
(
ped,
dwEffectIndex,
this->SzPool.uSzEnvelope,
puParameter,
&g_Envelope,
&DiEnv,
DiEnv.dwSize,
bBlocking,
totalBlocks
);
}
ExitOleProc();
return hres;
}