Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1048 lines
29 KiB

  1. /****************************************************************************
  2. MODULE: FFD_SWFF.CPP
  3. Tab settings: 5 9
  4. Copyright 1995, 1996, Microsoft Corporation, All Rights Reserved.
  5. PURPOSE: FFD (SWForce HAL) API
  6. FUNCTIONS: Function prototypes for Force Feedback Joystick interface
  7. between the SWForce and the device
  8. FFD_GetDeviceState
  9. FFD_PutRawForce
  10. FFD_DownloadEffect
  11. FFD_DestroyEffect
  12. VFX functions:
  13. Download_VFX
  14. CreateEffectFromFile
  15. CreateEffectFromBuffer
  16. These functionality are not necessarily supported by all Force Feedback
  17. devices. For example, if a device does not support built-in synthesis
  18. capability, then the entry point DownloadEffect, will return an error
  19. code ERROR_NO_SUPPORT.
  20. COMMENTS:
  21. This module of functions are encapsulated in SW_WHEEL.dll the DirectInput
  22. DDI driver
  23. Author(s): Name:
  24. ---------- ----------------
  25. MEA Manolito E. Adan
  26. Revision History:
  27. -----------------
  28. Version Date Author Comments
  29. 1.0 21-Mar-97 MEA original from SWForce code
  30. 21-Mar-99 waltw Removed unreferenced FFD_xxx functions
  31. ****************************************************************************/
  32. #include <windows.h>
  33. #include <mmsystem.h>
  34. #include <assert.h>
  35. #include "midi.hpp"
  36. #include "hau_midi.hpp"
  37. #include "math.h"
  38. #include "FFD_SWFF.hpp"
  39. #include "midi_obj.hpp"
  40. #include "DPack.h"
  41. #include "DTrans.h"
  42. #include "FFDevice.h"
  43. #include "CritSec.h"
  44. static ACKNACK g_AckNack;
  45. // Force Output range values
  46. #define MAX_AMP 2047
  47. #define MIN_AMP -2048
  48. #define FORCE_RANGE ((MAX_AMP - MIN_AMP)/2)
  49. extern TCHAR szDeviceName[MAX_SIZE_SNAME];
  50. extern CJoltMidi *g_pJoltMidi;
  51. #ifdef _DEBUG
  52. extern char g_cMsg[160];
  53. #endif
  54. static HRESULT AngleToXY(
  55. IN LONG lDirectionAngle2D,
  56. IN LONG lValueData,
  57. IN ULONG ulAxisMask,
  58. IN OUT PLONG pX,
  59. IN OUT PLONG pY);
  60. // ----------------------------------------------------------------------------
  61. // Function: FFD_Download
  62. //
  63. // Purpose: Downloads the specified Effect object UD/BE/SE to the FF device.
  64. // Parameters:
  65. // IN OUT PDNHANDLE pDnloadD - Ptr to DNHANDLE to store EffectID
  66. // IN PEFFECT pEffect - Ptr Common attributes for Effects
  67. // IN PENVELOPE pEnvelope - Ptr to an ENVELOPE
  68. // IN PVOID pTypeParam - Ptr to a Type specific parameter
  69. // IN ULONG ulAction - Type of action desired
  70. //
  71. // Returns:
  72. // SUCCESS - if successful
  73. // SFERR_FFDEVICE_MEMORY - no more download RAM available
  74. // SFERR_INVALID_PARAM - Invalid parameters
  75. // SFERR_NO_SUPPORT - if function is unsupported.
  76. // Algorithm:
  77. //
  78. // Comments:
  79. //
  80. // ulAction: Type of action desired after downloading
  81. // PLAY_STORE - stores in Device only
  82. // || the following options:
  83. // PLAY_STORE - stores in Device only
  84. // || the following options:
  85. // PLAY_SOLO - stop other forces playing, make this the only one.
  86. // PLAY_SUPERIMPOSE- mix with currently playing device
  87. // PLAY_LOOP - Loops for Count times, where count value is in
  88. // HIWORD
  89. // PLAY_FOREVER - Play forever until told to stop: PLAY_LOOP with 0
  90. // value in HIWORD
  91. // ----------------------------------------------------------------------------
  92. HRESULT WINAPI FFD_DownloadEffect(
  93. IN OUT PDNHANDLE pDnloadID,
  94. IN PEFFECT pEffect,
  95. IN PENVELOPE pEnvelope,
  96. IN PVOID pTypeParam,
  97. IN ULONG ulAction)
  98. {
  99. #ifdef _DEBUG
  100. g_CriticalSection.Enter();
  101. wsprintf(g_cMsg, "Enter: FFD_DownloadEffect. DnloadID= %ld, Type=%ld, SubType=%ld\r\n",
  102. *pDnloadID,
  103. pEffect->m_Type, pEffect->m_SubType);
  104. _RPT0(_CRT_WARN, g_cMsg);
  105. g_CriticalSection.Leave();
  106. #endif
  107. return SFERR_DRIVER_ERROR;
  108. #if 0
  109. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  110. //REVIEW: Still need to do boundary Assertions, structure size check etc...
  111. assert(pDnloadID && pEffect);
  112. if (!pDnloadID || !pEffect) return (SFERR_INVALID_PARAM);
  113. // If the Effect type is not a BE_DELAY or EF_ROM_EFFECT,
  114. // make sure there is a pTypeParam
  115. if ((BE_DELAY != pEffect->m_SubType) && (EF_ROM_EFFECT != pEffect->m_Type))
  116. {
  117. assert(pTypeParam);
  118. if (NULL == pTypeParam) return (SFERR_INVALID_PARAM);
  119. }
  120. // Don't support PLAY_LOOP for this version
  121. if ((ulAction & PLAY_LOOP) || (ulAction & 0xffff0000))
  122. return (SFERR_NO_SUPPORT);
  123. // REVIEW: TO increase performance, we should do a parameter mod check
  124. // For now, we'll assume all parameters are changed, for dwFlags
  125. // otherwise, we should check for:
  126. //#define DIEP_ALLPARAMS 0x000000FF - All fields valid
  127. //#define DIEP_AXES 0x00000020 - cAxes and rgdwAxes
  128. //#define DIEP_DIRECTION 0x00000040 - cAxes and rglDirection
  129. //#define DIEP_DURATION 0x00000001 - dwDuration
  130. //#define DIEP_ENVELOPE 0x00000080 - lpEnvelope
  131. //#define DIEP_GAIN 0x00000004 - dwGain
  132. //#define DIEP_NODOWNLOAD 0x80000000 - suppress auto - download
  133. //#define DIEP_SAMPLEPERIOD 0x00000002 - dwSamplePeriod
  134. //#define DIEP_TRIGGERBUTTON 0x00000008 - dwTriggerButton
  135. //#define DIEP_TRIGGERREPEATINTERVAL 0x00000010 - dwTriggerRepeatInterval
  136. //#define DIEP_TYPESPECIFICPARAMS 0x00000100 - cbTypeSpecificParams
  137. // and lpTypeSpecificParams
  138. // Figure out the Common members
  139. BYTE bAxisMask = (BYTE) pEffect->m_AxisMask;
  140. ULONG ulDuration = pEffect->m_Duration;
  141. if (PLAY_FOREVER == (ulAction & PLAY_FOREVER)) ulDuration = 0;
  142. // map button 10 to button 9
  143. if(pEffect->m_ButtonPlayMask == 0x0200)
  144. pEffect->m_ButtonPlayMask = 0x0100;
  145. else if(pEffect->m_ButtonPlayMask == 0x0100)
  146. return SFERR_NO_SUPPORT;
  147. DWORD dwFlags = DIEP_ALLPARAMS;
  148. SE_PARAM seParam = { sizeof(SE_PARAM)};
  149. PBE_SPRING_PARAM pBE_xxx1D;
  150. PBE_SPRING_2D_PARAM pBE_xxx2D;
  151. BE_XXX BE_xxx;
  152. PBE_WALL_PARAM pBE_Wall;
  153. // Decode the type of Download to use
  154. HRESULT hRet = SFERR_INVALID_PARAM;
  155. ULONG ulSubType = pEffect->m_SubType;
  156. switch (pEffect->m_Type)
  157. {
  158. case EF_BEHAVIOR:
  159. switch (ulSubType)
  160. {
  161. case BE_SPRING: // 1D Spring
  162. case BE_DAMPER: // 1D Damper
  163. case BE_INERTIA: // 1D Inertia
  164. case BE_FRICTION: // 1D Friction
  165. pBE_xxx1D = (PBE_SPRING_PARAM) pTypeParam;
  166. if (X_AXIS == bAxisMask)
  167. {
  168. BE_xxx.m_XConstant = pBE_xxx1D->m_Kconstant;
  169. BE_xxx.m_YConstant = 0;
  170. if (ulSubType != BE_FRICTION)
  171. BE_xxx.m_Param3 = pBE_xxx1D->m_AxisCenter;
  172. BE_xxx.m_Param4= 0;
  173. }
  174. else
  175. {
  176. if (Y_AXIS != bAxisMask)
  177. break;
  178. else
  179. {
  180. BE_xxx.m_YConstant = pBE_xxx1D->m_Kconstant;
  181. BE_xxx.m_XConstant = 0;
  182. if (ulSubType != BE_FRICTION)
  183. BE_xxx.m_Param4 = pBE_xxx1D->m_AxisCenter;
  184. BE_xxx.m_Param3= 0;
  185. }
  186. }
  187. hRet = CMD_Download_BE_XXX(pEffect, NULL, &BE_xxx, (PDNHANDLE) pDnloadID, dwFlags);
  188. break;
  189. case BE_SPRING_2D: // 2D Spring
  190. case BE_DAMPER_2D: // 2D Damperfs
  191. case BE_INERTIA_2D: // 2D Inertia
  192. case BE_FRICTION_2D: // 2D Friction
  193. // Validate AxisMask is for 2D
  194. if ( (X_AXIS|Y_AXIS) != bAxisMask)
  195. break;
  196. pBE_xxx2D = (PBE_SPRING_2D_PARAM) pTypeParam;
  197. BE_xxx.m_XConstant = pBE_xxx2D->m_XKconstant;
  198. if (ulSubType != BE_FRICTION_2D)
  199. {
  200. BE_xxx.m_YConstant = pBE_xxx2D->m_YKconstant;
  201. BE_xxx.m_Param3 = pBE_xxx2D->m_XAxisCenter;
  202. BE_xxx.m_Param4 = pBE_xxx2D->m_YAxisCenter;
  203. }
  204. else
  205. {
  206. BE_xxx.m_YConstant = pBE_xxx2D->m_XAxisCenter;
  207. BE_xxx.m_Param3 = 0;
  208. BE_xxx.m_Param4 = 0;
  209. }
  210. hRet = CMD_Download_BE_XXX(pEffect, NULL, &BE_xxx, (PDNHANDLE) pDnloadID, dwFlags);
  211. break;
  212. case BE_WALL:
  213. pBE_Wall = (PBE_WALL_PARAM) pTypeParam;
  214. if ( (pBE_Wall->m_WallAngle == 0)
  215. || (pBE_Wall->m_WallAngle == 90)
  216. || (pBE_Wall->m_WallAngle == 180)
  217. || (pBE_Wall->m_WallAngle == 270) )
  218. {
  219. BE_xxx.m_XConstant = pBE_Wall->m_WallType;
  220. BE_xxx.m_YConstant = pBE_Wall->m_WallConstant;
  221. BE_xxx.m_Param3 = pBE_Wall->m_WallAngle;
  222. BE_xxx.m_Param4 = pBE_Wall->m_WallDistance;
  223. hRet = CMD_Download_BE_XXX(pEffect, NULL, &BE_xxx, (PDNHANDLE) pDnloadID, dwFlags);
  224. }
  225. else
  226. hRet = SFERR_NO_SUPPORT;
  227. break;
  228. case BE_DELAY:
  229. if (0 == ulDuration) return (SFERR_INVALID_PARAM);
  230. // hRet = CMD_Download_NOP_DELAY(ulDuration, pEffect, (PDNHANDLE) pDnloadID);
  231. break;
  232. default:
  233. hRet = SFERR_NO_SUPPORT;
  234. break;
  235. }
  236. break;
  237. case EF_USER_DEFINED:
  238. break;
  239. case EF_ROM_EFFECT:
  240. // Setup the default parameters for the Effect
  241. if (SUCCESS != g_pJoltMidi->SetupROM_Fx(pEffect))
  242. {
  243. hRet = SFERR_INVALID_OBJECT;
  244. break;
  245. }
  246. // Map the SE_PARAM
  247. // set the frequency
  248. seParam.m_Freq = 0; // unused by ROM Effect
  249. seParam.m_SampleRate = pEffect->m_ForceOutputRate;
  250. seParam.m_MinAmp = -100;
  251. seParam.m_MaxAmp = 100;
  252. break;
  253. case EF_SYNTHESIZED:
  254. if (0 == ((PSE_PARAM)pTypeParam)->m_SampleRate)
  255. ((PSE_PARAM)pTypeParam)->m_SampleRate = DEFAULT_JOLT_FORCE_RATE;
  256. if (0 == pEffect->m_ForceOutputRate)
  257. pEffect->m_ForceOutputRate = DEFAULT_JOLT_FORCE_RATE;
  258. break;
  259. default:
  260. hRet = SFERR_INVALID_PARAM;
  261. }
  262. #ifdef _DEBUG
  263. g_CriticalSection.Enter();
  264. wsprintf(g_cMsg, "Exit: FFD_DownloadEffect. DnloadID = %lx, hRet=%lx\r\n",
  265. *pDnloadID, hRet);
  266. _RPT0(_CRT_WARN, g_cMsg);
  267. g_CriticalSection.Leave();
  268. #endif
  269. return (hRet);
  270. #endif //0
  271. }
  272. // *** ---------------------------------------------------------------------***
  273. // Function: FFD_DestroyEffect
  274. // Purpose: Destroys the Effect from download RAM storage area.
  275. // Parameters:
  276. // IN EFHANDLE EffectID // an Effect ID
  277. //
  278. // Returns: SUCCESS if successful command sent, else
  279. // SFERR_INVALID_ID
  280. // SFERR_NO_SUPPORT
  281. //
  282. // Algorithm:
  283. //
  284. // Comments:
  285. // The Device's Effect ID and memory is returned to free pool.
  286. //
  287. // *** ---------------------------------------------------------------------***
  288. HRESULT WINAPI FFD_DestroyEffect(
  289. IN DNHANDLE DnloadID)
  290. {
  291. #ifdef _DEBUG
  292. g_CriticalSection.Enter();
  293. wsprintf(g_cMsg, "Enter: FFD_DestroyEffect. DnloadID:%ld\r\n",
  294. DnloadID);
  295. _RPT0(_CRT_WARN, g_cMsg);
  296. g_CriticalSection.Leave();
  297. #endif
  298. ASSUME_NOT_NULL(g_pDataPackager);
  299. ASSUME_NOT_NULL(g_pDataTransmitter);
  300. if ((g_pDataPackager == NULL) || (g_pDataTransmitter == NULL)) {
  301. return SFERR_DRIVER_ERROR;
  302. }
  303. // Create a command/data packet - send it of to the stick
  304. HRESULT hr = g_pDataPackager->DestroyEffect(DnloadID);
  305. if (hr != SUCCESS) {
  306. return hr;
  307. }
  308. hr = g_pDataTransmitter->Transmit(g_AckNack); // Send it off
  309. return hr;
  310. }
  311. // *** ---------------------------------------------------------------------***
  312. // Function: FFD_VFXProcessEffect
  313. // Purpose: Commands FF device to process downloaded Effects
  314. //
  315. // Parameters:
  316. // IN OUT PDNHANDLE pDnloadID // Storage for new Download ID
  317. // IN int nNumEffects // Number of Effect IDs in the array
  318. // IN ULONG ulProcessMode // Processing mode
  319. // IN PDNHANDLE pPListArray// Pointer to an array of Effect IDs
  320. //
  321. // Returns: SUCCESS - if successful, else
  322. // SFERR_INVALID_PARAM
  323. // SFERR_NO_SUPPORT
  324. //
  325. // Algorithm:
  326. //
  327. // Comments:
  328. // The following processing is available:
  329. // CONCATENATE: Enew = E1 followed by E2
  330. // SUPERIMPOSE: Enew = E1 (t1) + E2 (t1) + E1 (t2)
  331. // + E2 (t2) + . . . E1 (tn) + E2 (tn)
  332. //
  333. // ulProcessMode:
  334. // Processing mode:
  335. // CONCATENATE - CONCATENATE
  336. // SUPERIMPOSE - Mix or overlay
  337. //
  338. // pEFHandle:
  339. // The array of Effect IDs must be one more than the actual number
  340. // of Effect IDs to use. The first entry pEFHandle[0] will be
  341. // used to store the new Effect ID created for the CONCATENATE
  342. // and SUPERIMPOSE process choice.
  343. //
  344. // *** ---------------------------------------------------------------------***
  345. HRESULT WINAPI FFD_VFXProcessEffect(
  346. IN ULONG ulButtonPlayMask,
  347. IN OUT PDNHANDLE pDnloadID,
  348. IN int nNumEffects,
  349. IN ULONG ulProcessMode,
  350. IN PDNHANDLE pPListArray)
  351. {
  352. #ifdef _DEBUG
  353. g_CriticalSection.Enter();
  354. wsprintf(g_cMsg, "FFD_ProcessEffect, DnloadID=%ld\r\n",
  355. *pDnloadID);
  356. _RPT0(_CRT_WARN, g_cMsg);
  357. g_CriticalSection.Leave();
  358. #endif
  359. if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
  360. assert(pDnloadID && pPListArray);
  361. if ((NULL == pDnloadID) || (NULL == pPListArray)) return (SFERR_INVALID_PARAM);
  362. assert(nNumEffects > 0 && nNumEffects <= MAX_PLIST_EFFECT_SIZE);
  363. if ((nNumEffects > MAX_PLIST_EFFECT_SIZE) || (nNumEffects <= 0))
  364. return (SFERR_INVALID_PARAM);
  365. // map button 10 to button 9
  366. if(ulButtonPlayMask == 0x0200)
  367. ulButtonPlayMask = 0x0100;
  368. else if(ulButtonPlayMask == 0x0100)
  369. return SFERR_NO_SUPPORT;
  370. return S_OK;
  371. }
  372. // *** ---------------------------------------------------------------------***
  373. // Function: AngleToXY
  374. // Purpose: Computes XY from Angle
  375. // Parameters:
  376. // IN LONG lDirectionAngle2D - Angle in Degrees
  377. // IN LONG lForceValue - Resultant Force
  378. // IN ULONG ulAxisMask - Axis to Affect
  379. // IN OUT PLONG pX - X-Axis store
  380. // IN OUT PLONG pY - Y-Axis store
  381. // Returns: pX, pY with valid angle components
  382. //
  383. // *** ---------------------------------------------------------------------***
  384. HRESULT AngleToXY(
  385. IN LONG lDirectionAngle2D,
  386. IN LONG lValueData,
  387. IN ULONG ulAxisMask,
  388. IN OUT PLONG pX,
  389. IN OUT PLONG pY)
  390. {
  391. // If single Axis only, then use the force on that axis.
  392. // If X and Y-axis, then use 2D angle
  393. // If X, Y, and Z-axis, then use 3D angle
  394. // If axis is other than X,Y,Z then no support
  395. double Radian;
  396. switch (ulAxisMask)
  397. {
  398. case (X_AXIS|Y_AXIS): // use 2D
  399. Radian = xDegrees2Radians(lDirectionAngle2D % 360);
  400. #ifdef ORIENTATION_MODE1
  401. *pX = - (long) (lValueData * cos(Radian));
  402. *pY = (long) (lValueData * sin(Radian));
  403. #else
  404. *pX = - (long) (lValueData * sin(Radian));
  405. *pY = (long) (lValueData * cos(Radian));
  406. #endif
  407. break;
  408. case X_AXIS:
  409. *pX = lValueData;
  410. *pY = 0;
  411. break;
  412. case Y_AXIS:
  413. *pX = 0;
  414. *pY = lValueData;
  415. break;
  416. case (X_AXIS|Y_AXIS|Z_AXIS): // use 3D
  417. default:
  418. return (SFERR_NO_SUPPORT);
  419. break;
  420. }
  421. return SUCCESS;
  422. }
  423. //
  424. // --- VFX SUPPORT FUNCTIONS
  425. //
  426. // *** ---------------------------------------------------------------------***
  427. // Function: CreateEffectFromBuffer
  428. // Purpose: Creates an Effect from a buffer
  429. // Parameters: PSWFORCE pISWForce - Ptr to a SWForce
  430. // PPSWEFFECT ppISWEffect - Ptr to a SWEffect
  431. // PVOID pBuffer - Ptr to a buffer block
  432. // DWORD dwByteCount - Bytes in block
  433. // LPGUID lpGUID - Joystick GUID
  434. //
  435. //
  436. // Returns: SUCCESS - if successful, else
  437. // error code
  438. //
  439. // Algorithm:
  440. //
  441. // Comments:
  442. //
  443. // *** ---------------------------------------------------------------------***
  444. HRESULT CreateEffectFromBuffer(
  445. IN PVOID pBuffer,
  446. IN DWORD dwByteCount,
  447. IN ULONG ulAction,
  448. IN OUT PDNHANDLE pDnloadID,
  449. IN DWORD dwFlags)
  450. {
  451. #ifdef _DEBUG
  452. _RPT0(_CRT_WARN, "CImpIVFX::CreateEffectFromBuffer\n");
  453. #endif
  454. // parameter checking
  455. if ( !(pBuffer && pDnloadID) )
  456. return SFERR_INVALID_PARAM;
  457. // variables used in this function
  458. #define ID_TABLE_SIZE 50
  459. MMRESULT mmresult;
  460. DWORD dwMaxID = 0; // maximum id of effects entered into the following table
  461. DNHANDLE rgdwDnloadIDTable[ID_TABLE_SIZE];
  462. DNHANDLE dwCurrentDnloadID = 0;
  463. int nNextID = 0;
  464. HRESULT hResult = SUCCESS;
  465. DWORD dwBytesRead;
  466. DWORD dwBytesToRead;
  467. BYTE* pParam = NULL;
  468. BOOL bDone = FALSE;
  469. BOOL bSubEffects = FALSE;
  470. DWORD dwID;
  471. DWORD c; // cleanup counter variable
  472. // debugging variables (to make sure we destroy all but one
  473. // created effect on success, and that we destory every
  474. // created effect on failure)...
  475. #ifdef _DEBUG
  476. int nEffectsCreated = 0;
  477. int nEffectsDestroyed = 0;
  478. BOOL bFunctionSuccessful = FALSE;
  479. #endif //_DEBUG
  480. // clear effect table (we check it during cleanup... anything
  481. // that isn't NULL gets destroyed.)
  482. memset(rgdwDnloadIDTable,NULL,sizeof(rgdwDnloadIDTable));
  483. // open a RIFF memory file using the buffer
  484. MMIOINFO mmioinfo;
  485. mmioinfo.dwFlags = 0;
  486. mmioinfo.fccIOProc = FOURCC_MEM;
  487. mmioinfo.pIOProc = NULL;
  488. mmioinfo.wErrorRet = 0;
  489. mmioinfo.htask = NULL;
  490. mmioinfo.cchBuffer = dwByteCount;
  491. mmioinfo.pchBuffer = (char*)pBuffer;
  492. mmioinfo.pchNext = 0;
  493. mmioinfo.pchEndRead = 0;
  494. mmioinfo.lBufOffset = 0;
  495. mmioinfo.adwInfo[0] = 0;
  496. mmioinfo.adwInfo[1] = 0;
  497. mmioinfo.adwInfo[2] = 0;
  498. mmioinfo.dwReserved1 = 0;
  499. mmioinfo.dwReserved2 = 0;
  500. mmioinfo.hmmio = NULL;
  501. HMMIO hmmio;
  502. hmmio = mmioOpen(NULL, &mmioinfo, MMIO_READWRITE);
  503. if(hmmio == NULL)
  504. {
  505. hResult = MMIOErrorToSFERRor(mmioinfo.wErrorRet);
  506. goto cleanup;
  507. }
  508. // descend into FORC RIFF
  509. MMCKINFO mmckinfoForceEffectRIFF;
  510. mmckinfoForceEffectRIFF.fccType = FCC_FORCE_EFFECT_RIFF;
  511. mmresult = mmioDescend(hmmio, &mmckinfoForceEffectRIFF, NULL, MMIO_FINDRIFF);
  512. if(mmresult != MMSYSERR_NOERROR)
  513. {
  514. hResult = MMIOErrorToSFERRor(mmresult);
  515. goto cleanup;
  516. }
  517. //! handle loading of GUID chunk when its implemented/testable
  518. // descend into trak list
  519. MMCKINFO mmckinfoTrackLIST;
  520. mmckinfoTrackLIST.fccType = FCC_TRACK_LIST;
  521. mmresult = mmioDescend(hmmio, &mmckinfoTrackLIST, &mmckinfoForceEffectRIFF,
  522. MMIO_FINDLIST);
  523. if(mmresult != MMSYSERR_NOERROR)
  524. {
  525. hResult = MMIOErrorToSFERRor(mmresult);
  526. goto cleanup;
  527. }
  528. // descend into the first efct list (there has to be at least one effect)
  529. MMCKINFO mmckinfoEffectLIST;
  530. mmckinfoEffectLIST.fccType = FCC_EFFECT_LIST;
  531. mmresult = mmioDescend(hmmio, &mmckinfoEffectLIST, &mmckinfoTrackLIST,
  532. MMIO_FINDLIST);
  533. if(mmresult != MMSYSERR_NOERROR)
  534. {
  535. hResult = MMIOErrorToSFERRor(mmresult);
  536. goto cleanup;
  537. }
  538. bDone = FALSE;
  539. do
  540. {
  541. // descend into id chunk
  542. MMCKINFO mmckinfoIDCHUNK;
  543. mmckinfoIDCHUNK.ckid = FCC_ID_CHUNK;
  544. mmresult = mmioDescend(hmmio, &mmckinfoIDCHUNK, &mmckinfoEffectLIST,
  545. MMIO_FINDCHUNK);
  546. if(mmresult != MMSYSERR_NOERROR)
  547. {
  548. hResult = MMIOErrorToSFERRor(mmresult);
  549. goto cleanup;
  550. }
  551. // read the id
  552. //DWORD dwID; moved to being function global so we can use it near the end
  553. dwBytesToRead = sizeof(DWORD);
  554. dwBytesRead = mmioRead(hmmio, (char*)&dwID, dwBytesToRead);
  555. if(dwBytesRead != dwBytesToRead)
  556. {
  557. if(dwBytesRead == 0)
  558. hResult = VFX_ERR_FILE_END_OF_FILE;
  559. else
  560. hResult = MMIOErrorToSFERRor(MMIOERR_CANNOTREAD);
  561. goto cleanup;
  562. }
  563. if(dwID >= ID_TABLE_SIZE)
  564. {
  565. hResult = VFX_ERR_FILE_BAD_FORMAT;
  566. goto cleanup;
  567. }
  568. // ascend from id chunk
  569. mmresult = mmioAscend(hmmio, &mmckinfoIDCHUNK, 0);
  570. if(mmresult != MMSYSERR_NOERROR)
  571. {
  572. hResult = MMIOErrorToSFERRor(mmresult);
  573. goto cleanup;
  574. }
  575. // descend into data chunk
  576. MMCKINFO mmckinfoDataCHUNK;
  577. mmckinfoDataCHUNK.ckid = FCC_DATA_CHUNK;
  578. mmresult = mmioDescend(hmmio, &mmckinfoDataCHUNK, &mmckinfoEffectLIST,
  579. MMIO_FINDCHUNK);
  580. if(mmresult != MMSYSERR_NOERROR)
  581. {
  582. hResult = MMIOErrorToSFERRor(mmresult);
  583. goto cleanup;
  584. }
  585. // read the effect structure
  586. EFFECT effect;
  587. dwBytesToRead = sizeof(EFFECT);
  588. dwBytesRead = mmioRead(hmmio, (char*)&effect, dwBytesToRead);
  589. if(dwBytesRead != dwBytesToRead)
  590. {
  591. if(dwBytesRead == 0)
  592. hResult = VFX_ERR_FILE_END_OF_FILE;
  593. else
  594. hResult = MMIOErrorToSFERRor(MMIOERR_CANNOTREAD);
  595. goto cleanup;
  596. }
  597. // get the envelope structure
  598. ENVELOPE envelope;
  599. dwBytesToRead = sizeof(ENVELOPE);
  600. dwBytesRead = mmioRead(hmmio, (char*)&envelope, dwBytesToRead);
  601. if(dwBytesRead != dwBytesToRead)
  602. {
  603. if(dwBytesRead == 0)
  604. hResult = VFX_ERR_FILE_END_OF_FILE;
  605. else
  606. hResult = MMIOErrorToSFERRor(MMIOERR_CANNOTREAD);
  607. goto cleanup;
  608. }
  609. // calculate the size of and allocate a param structure
  610. if(pParam != NULL)
  611. {
  612. delete [] pParam;
  613. pParam = NULL;
  614. }
  615. // find cur pos w/o changing it
  616. DWORD dwCurrentFilePos = mmioSeek(hmmio, 0, SEEK_CUR);
  617. if(dwCurrentFilePos == -1)
  618. {
  619. hResult = MMIOErrorToSFERRor(MMIOERR_CANNOTSEEK);
  620. goto cleanup;
  621. }
  622. DWORD dwEndOfChunk = mmckinfoDataCHUNK.dwDataOffset
  623. + mmckinfoDataCHUNK.cksize;
  624. dwBytesToRead = dwEndOfChunk - dwCurrentFilePos;
  625. pParam = new BYTE[dwBytesToRead];
  626. if(pParam == NULL)
  627. {
  628. hResult = VFX_ERR_FILE_OUT_OF_MEMORY;
  629. goto cleanup;
  630. }
  631. // get the param structure
  632. dwBytesRead = mmioRead(hmmio, (char*)pParam, dwBytesToRead);
  633. if(dwBytesRead != dwBytesToRead)
  634. {
  635. if(dwBytesRead == 0)
  636. hResult = VFX_ERR_FILE_END_OF_FILE;
  637. else
  638. hResult = MMIOErrorToSFERRor(MMIOERR_CANNOTREAD);
  639. goto cleanup;
  640. }
  641. // ascend the data chunk
  642. mmresult = mmioAscend(hmmio, &mmckinfoDataCHUNK, 0);
  643. if(mmresult != MMSYSERR_NOERROR)
  644. {
  645. hResult = MMIOErrorToSFERRor(mmresult);
  646. goto cleanup;
  647. }
  648. // ascend from the efct list
  649. mmresult = mmioAscend(hmmio, &mmckinfoEffectLIST, 0);
  650. if(mmresult != MMSYSERR_NOERROR)
  651. {
  652. hResult = MMIOErrorToSFERRor(mmresult);
  653. goto cleanup;
  654. }
  655. // reset subeffects flag
  656. bSubEffects = FALSE;
  657. // special fix-ups for user-defined
  658. if(effect.m_Type == EF_USER_DEFINED &&
  659. (effect.m_SubType == PL_CONCATENATE
  660. || effect.m_SubType == PL_SUPERIMPOSE
  661. || effect.m_SubType == UD_WAVEFORM))
  662. {
  663. if(effect.m_SubType == UD_WAVEFORM)
  664. {
  665. // fix the pointer to the force data in the UD_PARAM
  666. BYTE* pForceData = pParam + sizeof(UD_PARAM); // - sizeof(LONG*);
  667. UD_PARAM* pUDParam = (UD_PARAM*)pParam;
  668. pUDParam->m_pForceData = (LONG*)pForceData;
  669. // do a sanity check
  670. if(pUDParam->m_NumVectors > MAX_UD_PARAM_FORCE_DATA_COUNT)
  671. {
  672. hResult = VFX_ERR_FILE_BAD_FORMAT;
  673. goto cleanup;
  674. }
  675. }
  676. else if(effect.m_SubType == PL_CONCATENATE
  677. || effect.m_SubType == PL_SUPERIMPOSE)
  678. {
  679. // fix the pointer to the PSWEFFECT list in the PL_PARAM
  680. BYTE* pProcessList = pParam + sizeof(PL_PARAM);
  681. PL_PARAM* pPLParam = (PL_PARAM*)pParam;
  682. pPLParam->m_pProcessList = (PPSWEFFECT)pProcessList;
  683. // do a sanity check
  684. if(pPLParam->m_NumEffects > MAX_PL_PARAM_NUM_EFFECTS)
  685. {
  686. hResult = VFX_ERR_FILE_BAD_FORMAT;
  687. goto cleanup;
  688. }
  689. // make sure all entries in this process list are valid
  690. ULONG i;
  691. for (i = 0; i < pPLParam->m_NumEffects; i++)
  692. {
  693. UINT nThisID = (UINT)pPLParam->m_pProcessList[i];
  694. if(nThisID >= ID_TABLE_SIZE)
  695. {
  696. hResult = VFX_ERR_FILE_BAD_FORMAT;
  697. goto cleanup;
  698. }
  699. DNHANDLE dwThisDnloadID=rgdwDnloadIDTable[nThisID];
  700. if(dwThisDnloadID == 0)
  701. {
  702. hResult = VFX_ERR_FILE_BAD_FORMAT;
  703. goto cleanup;
  704. }
  705. }
  706. // use the ID table to insert the download ID's
  707. for(i=0; i<pPLParam->m_NumEffects; i++)
  708. {
  709. UINT nThisID = (UINT)pPLParam->m_pProcessList[i];
  710. DNHANDLE dwThisDnloadID=rgdwDnloadIDTable[nThisID];
  711. pPLParam->m_pProcessList[i] = (IDirectInputEffect*)dwThisDnloadID;
  712. // since this effect has been used in a process list,
  713. // and it will be destroyed after being used in CreateEffect,
  714. // null it's entry in the table so it doesn't get erroneously
  715. // redestroyed during cleanup of an error.
  716. rgdwDnloadIDTable[nThisID] = NULL;
  717. }
  718. // we have a process list with sub effects, so set the flag
  719. bSubEffects = TRUE;
  720. }
  721. else
  722. {
  723. // there are no other UD sub-types
  724. hResult = VFX_ERR_FILE_BAD_FORMAT;
  725. goto cleanup;
  726. }
  727. }
  728. // download the effect
  729. // create the effect
  730. //hResult = pISWForce->CreateEffect(&pISWEffect, &effect,
  731. // &envelope, pParam);
  732. if(effect.m_SubType != PL_CONCATENATE && effect.m_SubType != PL_SUPERIMPOSE)
  733. {
  734. EFFECT SmallEffect;
  735. SmallEffect.m_Bytes = sizeof(EFFECT);
  736. SmallEffect.m_Type = effect.m_Type;
  737. SmallEffect.m_SubType = effect.m_SubType;
  738. SmallEffect.m_AxisMask = effect.m_AxisMask;
  739. SmallEffect.m_DirectionAngle2D = effect.m_DirectionAngle2D;
  740. SmallEffect.m_DirectionAngle3D = effect.m_DirectionAngle3D;
  741. SmallEffect.m_Duration = effect.m_Duration;
  742. SmallEffect.m_ForceOutputRate = effect.m_ForceOutputRate;
  743. SmallEffect.m_Gain = effect.m_Gain;
  744. SmallEffect.m_ButtonPlayMask = effect.m_ButtonPlayMask;
  745. *pDnloadID = 0;
  746. hResult = FFD_DownloadEffect(pDnloadID, &SmallEffect, &envelope, pParam, ulAction);
  747. }
  748. else
  749. {
  750. ULONG ulButtonPlayMask = effect.m_ButtonPlayMask;
  751. int nNumEffects = ((PL_PARAM*)pParam)->m_NumEffects;
  752. ULONG ulProcessMode = effect.m_SubType;
  753. PDNHANDLE pPListArray = new DNHANDLE[ID_TABLE_SIZE];
  754. for(int i=0; i<nNumEffects; i++)
  755. pPListArray[i] = (DNHANDLE)(((PL_PARAM*)pParam)->m_pProcessList[i]);
  756. *pDnloadID = 0;
  757. hResult = FFD_VFXProcessEffect(ulButtonPlayMask, pDnloadID, nNumEffects,
  758. ulProcessMode,pPListArray);
  759. }
  760. // moved check for success below...
  761. #ifdef _DEBUG
  762. if (!FAILED(hResult))
  763. nEffectsCreated++;
  764. #endif //_DEBUG
  765. // if there were sub effects we need to destroy them, making
  766. // their ref counts become 1, so the entire effect can be destroyed
  767. // by destroying the root effect.
  768. #if 0
  769. if (bSubEffects)
  770. {
  771. PL_PARAM* pPLParam = (PL_PARAM*)pParam;
  772. for (ULONG i = 0; i < pPLParam->m_NumEffects; i++)
  773. {
  774. ASSERT(pPLParam->m_pProcessList[i] != NULL);
  775. pISWForce->DestroyEffect(pPLParam->m_pProcessList[i]);
  776. #ifdef _DEBUG
  777. nEffectsDestroyed++;
  778. #endif //_DEBUG
  779. }
  780. }
  781. #endif
  782. // now check for success of CreateEffect, because regardless of
  783. // whether or not it succeeded, we -must- have destroyed the subeffects
  784. // before continuing, or cleanup will not work properly...
  785. if (SUCCESS != hResult)
  786. {
  787. goto cleanup;
  788. }
  789. // put the id/DnloadID pair into the map
  790. rgdwDnloadIDTable[dwID] = *pDnloadID; //pISWEffect;
  791. // keep track of the highest ID in the effect table
  792. if (dwID > dwMaxID)
  793. dwMaxID = dwID;
  794. // try to descend the next efct
  795. mmresult = mmioDescend(hmmio, &mmckinfoEffectLIST, &mmckinfoTrackLIST,
  796. MMIO_FINDLIST);
  797. if(mmresult == MMIOERR_CHUNKNOTFOUND)
  798. {
  799. // we are at the end of the list
  800. bDone = TRUE;
  801. }
  802. else if(mmresult != MMSYSERR_NOERROR)
  803. {
  804. hResult = MMIOErrorToSFERRor(mmresult);
  805. goto cleanup;
  806. }
  807. }
  808. while(!bDone);
  809. // ascend from trak list
  810. mmresult = mmioAscend(hmmio, &mmckinfoTrackLIST, 0);
  811. if(mmresult != MMSYSERR_NOERROR)
  812. {
  813. hResult = MMIOErrorToSFERRor(mmresult);
  814. goto cleanup;
  815. }
  816. // ascend from FORCE RIFF
  817. mmresult = mmioAscend(hmmio, &mmckinfoForceEffectRIFF, 0);
  818. if(mmresult != MMSYSERR_NOERROR)
  819. {
  820. hResult = MMIOErrorToSFERRor(mmresult);
  821. goto cleanup;
  822. }
  823. // get the return value
  824. //*pDnloadID = dwCurrentDnloadID;
  825. // clear the final effect's entry in the table so we don't destroy it during cleanup
  826. rgdwDnloadIDTable[dwID] = 0;
  827. // at this point the entire table should be NULL... make sure of it
  828. for (c = 0; c <= dwMaxID; c++)
  829. ;
  830. #ifdef _DEBUG
  831. bFunctionSuccessful = TRUE;
  832. #endif //_DEBUG
  833. cleanup:
  834. // destroy everything in the effect table that isn't NULL
  835. for (c = 0; c <= dwMaxID; c++)
  836. if (NULL != rgdwDnloadIDTable[c])
  837. {
  838. FFD_DestroyEffect(rgdwDnloadIDTable[c]);
  839. rgdwDnloadIDTable[c] = 0;
  840. #ifdef _DEBUG
  841. nEffectsDestroyed++;
  842. #endif //_DEBUG
  843. }
  844. #ifdef _DEBUG
  845. // make sure we destroy all but one created effect on success,
  846. // and that we destory -every- created effect on failure.
  847. if (bFunctionSuccessful)
  848. {
  849. ;//ASSERT(nEffectsCreated - 1 == nEffectsDestroyed);
  850. }
  851. else
  852. {
  853. ;//ASSERT(nEffectsCreated == nEffectsDestroyed);
  854. }
  855. #endif //_DEBUG
  856. // close the memory RIFF file
  857. if(hmmio != NULL)
  858. {
  859. mmresult = mmioClose(hmmio, 0);
  860. if(mmresult != MMSYSERR_NOERROR)
  861. {
  862. hResult = MMIOErrorToSFERRor(mmresult);
  863. }
  864. }
  865. // de-allocate any allocated memory
  866. if(pParam != NULL)
  867. delete [] pParam;
  868. // return the error code, which is SUCCESS, unless there was an error
  869. return hResult;
  870. }
  871. HRESULT MMIOErrorToSFERRor(MMRESULT mmresult)
  872. {
  873. HRESULT hResult;
  874. switch(mmresult)
  875. {
  876. case MMIOERR_FILENOTFOUND:
  877. hResult = VFX_ERR_FILE_NOT_FOUND;
  878. break;
  879. case MMIOERR_OUTOFMEMORY:
  880. hResult = VFX_ERR_FILE_OUT_OF_MEMORY;
  881. break;
  882. case MMIOERR_CANNOTOPEN:
  883. hResult = VFX_ERR_FILE_CANNOT_OPEN;
  884. break;
  885. case MMIOERR_CANNOTCLOSE:
  886. hResult = VFX_ERR_FILE_CANNOT_CLOSE;
  887. break;
  888. case MMIOERR_CANNOTREAD:
  889. hResult = VFX_ERR_FILE_CANNOT_READ;
  890. break;
  891. case MMIOERR_CANNOTWRITE:
  892. hResult = VFX_ERR_FILE_CANNOT_WRITE;
  893. break;
  894. case MMIOERR_CANNOTSEEK:
  895. hResult = VFX_ERR_FILE_CANNOT_SEEK;
  896. break;
  897. case MMIOERR_CANNOTEXPAND:
  898. hResult = VFX_ERR_FILE_UNKNOWN_ERROR;
  899. break;
  900. case MMIOERR_CHUNKNOTFOUND:
  901. hResult = VFX_ERR_FILE_BAD_FORMAT;
  902. break;
  903. case MMIOERR_UNBUFFERED:
  904. hResult = VFX_ERR_FILE_UNKNOWN_ERROR;
  905. break;
  906. case MMIOERR_PATHNOTFOUND:
  907. hResult = VFX_ERR_FILE_NOT_FOUND;
  908. break;
  909. case MMIOERR_ACCESSDENIED:
  910. hResult = VFX_ERR_FILE_ACCESS_DENIED;
  911. break;
  912. case MMIOERR_SHARINGVIOLATION:
  913. hResult = VFX_ERR_FILE_SHARING_VIOLATION;
  914. break;
  915. case MMIOERR_NETWORKERROR:
  916. hResult = VFX_ERR_FILE_NETWORK_ERROR;
  917. break;
  918. case MMIOERR_TOOMANYOPENFILES:
  919. hResult = VFX_ERR_FILE_TOO_MANY_OPEN_FILES;
  920. break;
  921. case MMIOERR_INVALIDFILE:
  922. hResult = VFX_ERR_FILE_INVALID;
  923. break;
  924. default:
  925. hResult = VFX_ERR_FILE_UNKNOWN_ERROR;
  926. break;
  927. }
  928. return hResult;
  929. }