TASK.CPP 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. /*
  2. ** Command & Conquer Red Alert(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /****************************************************************************
  19. *
  20. * C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
  21. *
  22. *----------------------------------------------------------------------------
  23. *
  24. * PROJECT
  25. * VQA player library. (32-Bit protected mode)
  26. *
  27. * FILE
  28. * task.c
  29. *
  30. * DESCRIPTION
  31. * Loading and drawing delegation
  32. *
  33. * PROGRAMMER
  34. * Bill Randolph
  35. * Denzil E. Long, Jr.
  36. *
  37. * DATE
  38. * July 25, 1995
  39. *
  40. *----------------------------------------------------------------------------
  41. *
  42. * PUBLIC
  43. * VQA_Alloc - Allocate a VQAHandle to use.
  44. * VQA_Free - Free a VQAHandle.
  45. * VQA_Init - Initialize the VQAHandle IO.
  46. * VQA_Play - Play the VQA movie.
  47. * VQA_GetInfo - Get VQA movie information.
  48. * VQA_GetStats - Get VQA movie statistics.
  49. * VQA_Version - Get VQA library version number.
  50. * VQA_IDString - Get the VQA player library's ID string.
  51. *
  52. * PRIVATE
  53. * VQA_IO_Task - Loader task for multitasking.
  54. * VQA_Rendering_Task - Drawer task for multitasking.
  55. * User_Update - Page flip routine called by the task interrupt.
  56. *
  57. ****************************************************************************/
  58. #include <stdio.h>
  59. #include <malloc.h>
  60. #include <dos.h>
  61. #include <mem.h>
  62. #include <conio.h>
  63. #include <sys\timeb.h>
  64. #include <vqm32\all.h>
  65. #include "vqaplayp.h"
  66. /*---------------------------------------------------------------------------
  67. * PRIVATE DECLARATIONS
  68. *-------------------------------------------------------------------------*/
  69. /* Externals */
  70. #ifdef __cplusplus
  71. extern "C" {
  72. #endif
  73. extern int cdecl Check_Key(void);
  74. extern int cdecl Get_Key(void);
  75. #ifdef __cplusplus
  76. }
  77. #endif
  78. /****************************************************************************
  79. *
  80. * NAME
  81. * VQA_Alloc - Allocate a VQAHandle to use.
  82. *
  83. * SYNOPSIS
  84. * VQAHandle = VQA_Alloc()
  85. *
  86. * VQAHandle *VQA_Alloc(void);
  87. *
  88. * FUNCTION
  89. * Obtain a VQAHandle. This handle is used by most VQA library functions,
  90. * and contains the current position in the file. This is the only legal
  91. * way to obtain a VQAHandle.
  92. *
  93. * INPUTS
  94. * NONE
  95. *
  96. * RESULT
  97. * VQA - Handle of a VQA.
  98. *
  99. ****************************************************************************/
  100. VQAHandle *VQA_Alloc(void)
  101. {
  102. VQAHandleP *vqa;
  103. if ((vqa = (VQAHandleP *)malloc(sizeof(VQAHandleP))) != NULL) {
  104. memset(vqa, 0, sizeof(VQAHandleP));
  105. }
  106. return ((VQAHandle *)vqa);
  107. }
  108. /****************************************************************************
  109. *
  110. * NAME
  111. * VQA_Free - Free a VQAHandle.
  112. *
  113. * SYNOPSIS
  114. * VQA_Free(VQA)
  115. *
  116. * void VQA_Free(VQAHandle *);
  117. *
  118. * FUNCTION
  119. * Dispose of a VQAHandle. This is the only legal way to dispose of a
  120. * VQAHandle.
  121. *
  122. * INPUTS
  123. * VQA - Pointer to VQAHandle to dispose of.
  124. *
  125. * RESULT
  126. * NONE
  127. *
  128. ****************************************************************************/
  129. void VQA_Free(VQAHandle *vqa)
  130. {
  131. if (vqa) free(vqa);
  132. }
  133. /****************************************************************************
  134. *
  135. * NAME
  136. * VQA_Init - Initialize the VQAHandle IO handler.
  137. *
  138. * SYNOPSIS
  139. * VQA_Init(VQA, IOHandler)
  140. *
  141. * void VQA_Init(VQAHandle *, IOHandler *);
  142. *
  143. * FUNCTION
  144. * Initialize the specified VQAHandle IO with the client provided custom
  145. * IO handler.
  146. *
  147. * INPUTS
  148. * VQA - Pointer to VQAHandle to initialize.
  149. * IOHandler - Pointer to custom file I/O handler function.
  150. *
  151. * RESULT
  152. * NONE
  153. *
  154. ****************************************************************************/
  155. void VQA_Init(VQAHandle *vqa, long(*iohandler)(VQAHandle *vqa, long action,
  156. void *buffer, long nbytes))
  157. {
  158. ((VQAHandleP *)vqa)->IOHandler = iohandler;
  159. }
  160. /****************************************************************************
  161. *
  162. * NAME
  163. * VQA_Play - Play the VQA movie.
  164. *
  165. * SYNOPSIS
  166. * Error = VQA_Play(VQA, Mode)
  167. *
  168. * long VQA_Play(VQAHandle *, long);
  169. *
  170. * FUNCTION
  171. * Playback the movie associated with the specified VQAHandle.
  172. *
  173. * INPUTS
  174. * VQA - Pointer to handle of movie to play.
  175. * Mode - Playback mode.
  176. * VQAMODE_RUN - Run the movie until completion.
  177. * VQAMODE_WALK - Walk the movie frame by frame.
  178. * VQAMODE_PAUSE - Pause the movie.
  179. * VQAMODE_STOP - Stop the movie (Shutdown).
  180. *
  181. * RESULT
  182. * Error - 0 if successful, or error code.
  183. *
  184. ****************************************************************************/
  185. long VQA_Play(VQAHandle *vqa, long mode)
  186. {
  187. VQAData *vqabuf;
  188. VQAConfig *config;
  189. VQADrawer *drawer;
  190. long rc;
  191. long i;
  192. long key;
  193. /* Dereference commonly used data members for quick access. */
  194. vqabuf = ((VQAHandleP *)vqa)->VQABuf;
  195. drawer = &vqabuf->Drawer;
  196. config = &((VQAHandleP *)vqa)->Config;
  197. /* One time player priming. */
  198. if (!(vqabuf->Flags & VQADATF_PRIMED)) {
  199. /* Init the Drawer's configuration */
  200. VQA_Configure_Drawer((VQAHandleP *)vqa);
  201. /* If audio enabled & loaded, start playing */
  202. #if(VQAAUDIO_ON)
  203. if ((config->OptionFlags & VQAOPTF_AUDIO) && vqabuf->Audio.IsLoaded[0]) {
  204. VQA_StartAudio((VQAHandleP *)vqa);
  205. }
  206. #endif
  207. /* Initialize the timer */
  208. i = ((vqabuf->Drawer.CurFrame->FrameNum * VQA_TIMETICKS)
  209. / config->DrawRate);
  210. VQA_SetTimer((VQAHandleP *)vqa, i, config->TimerMethod);
  211. vqabuf->StartTime = VQA_GetTime((VQAHandleP *)vqa);
  212. /* Set up the Mono screen */
  213. #if(VQAMONO_ON)
  214. if (config->OptionFlags & VQAOPTF_MONO) {
  215. VQA_InitMono((VQAHandleP *)vqa);
  216. }
  217. #endif
  218. /* Priming is complete. */
  219. vqabuf->Flags |= VQADATF_PRIMED;
  220. }
  221. /* Main Player Loop */
  222. switch (mode) {
  223. case VQAMODE_PAUSE:
  224. if ((vqabuf->Flags & VQADATF_PAUSED) == 0) {
  225. vqabuf->Flags |= VQADATF_PAUSED;
  226. vqabuf->EndTime = VQA_GetTime((VQAHandleP *)vqa);
  227. /* Stop the audio while the movie is paused. */
  228. #if(VQAAUDIO_ON)
  229. if (vqabuf->Audio.Flags & VQAAUDF_ISPLAYING) {
  230. VQA_StopAudio((VQAHandleP *)vqa);
  231. }
  232. #endif
  233. }
  234. rc = VQAERR_PAUSED;
  235. break;
  236. case VQAMODE_RUN:
  237. case VQAMODE_WALK:
  238. default:
  239. /* Start up the movie if is it currently paused. */
  240. if (vqabuf->Flags & VQADATF_PAUSED) {
  241. vqabuf->Flags &= ~VQADATF_PAUSED;
  242. /* Start the audio if it was previously on. */
  243. #if(VQAAUDIO_ON)
  244. if (config->OptionFlags & VQAOPTF_AUDIO) {
  245. VQA_StartAudio((VQAHandleP *)vqa);
  246. }
  247. #endif
  248. VQA_SetTimer((VQAHandleP *)vqa, vqabuf->EndTime, config->TimerMethod);
  249. }
  250. /* Load, Draw, Load, Draw, Load, Draw ... */
  251. while ((vqabuf->Flags & (VQADATF_DDONE|VQADATF_LDONE))
  252. != (VQADATF_DDONE|VQADATF_LDONE)) {
  253. /* Load a frame */
  254. if (!(vqabuf->Flags & VQADATF_LDONE)) {
  255. if ((rc = VQA_LoadFrame(vqa)) == 0) {
  256. vqabuf->LoadedFrames++;
  257. }
  258. else if ((rc != VQAERR_NOBUFFER) && (rc != VQAERR_SLEEPING)) {
  259. vqabuf->Flags |= VQADATF_LDONE;
  260. rc = 0;
  261. }
  262. }
  263. /* Draw a frame */
  264. if ((config->DrawFlags & VQACFGF_NODRAW) == 0) {
  265. if ((rc = (*(vqabuf->Draw_Frame))(vqa)) == 0) {
  266. vqabuf->DrawnFrames++;
  267. if (User_Update(vqa)) {
  268. vqabuf->Flags |= (VQADATF_DDONE|VQADATF_LDONE);
  269. }
  270. }
  271. else if ((vqabuf->Flags & VQADATF_LDONE)
  272. && (rc == VQAERR_NOBUFFER)) {
  273. vqabuf->Flags |= VQADATF_DDONE;
  274. }
  275. } else {
  276. vqabuf->Flags |= VQADATF_DDONE;
  277. drawer->CurFrame->Flags = 0L;
  278. drawer->CurFrame = drawer->CurFrame->Next;
  279. }
  280. /* Update Mono output */
  281. #if(VQAMONO_ON)
  282. if (config->OptionFlags & VQAOPTF_MONO) {
  283. VQA_UpdateMono((VQAHandleP *)vqa);
  284. }
  285. #endif
  286. if (mode == VQAMODE_WALK) {
  287. break;
  288. }
  289. #if(VQASTANDALONE)
  290. else {
  291. /* Do single-stepping check. */
  292. if (config->OptionFlags & VQAOPTF_STEP) {
  293. while ((key = Check_Key()) == 0);
  294. Get_Key();
  295. /* Escape key still quits. */
  296. if (key == 27) {
  297. break;
  298. }
  299. }
  300. /* Check for ESC */
  301. if ((key = Check_Key()) != 0) {
  302. mode = VQAMODE_STOP;
  303. break;
  304. }
  305. }
  306. #endif
  307. }
  308. break;
  309. }
  310. /* If the movie is finished or we are requested to stop then shutdown. */
  311. if (((vqabuf->Flags & (VQADATF_DDONE|VQADATF_LDONE))
  312. == (VQADATF_DDONE|VQADATF_LDONE)) || (mode == VQAMODE_STOP)) {
  313. /* Record the end time; must be done before stopping audio, since we're
  314. * getting the elapsed time from the audio DMA position.
  315. */
  316. vqabuf->EndTime = VQA_GetTime((VQAHandleP *)vqa);
  317. /* Stop audio, if it's playing. */
  318. #if(VQAAUDIO_ON)
  319. if (vqabuf->Audio.Flags & VQAAUDF_ISPLAYING) {
  320. VQA_StopAudio((VQAHandleP *)vqa);
  321. }
  322. #endif
  323. /* Movie is finished. */
  324. rc = VQAERR_EOF;
  325. }
  326. return (rc);
  327. }
  328. /****************************************************************************
  329. *
  330. * NAME
  331. * VQA_GetInfo - Get VQA movie information.
  332. *
  333. * SYNOPSIS
  334. * VQA_GetInfo(VQA, Info)
  335. *
  336. * void VQA_GetInfo(VQAHandle *, VQAInfo *);
  337. *
  338. * FUNCTION
  339. * Retrieve information about the opened movie.
  340. *
  341. * INPUTS
  342. * VQA - Pointer to VQAHandle of opened movie.
  343. * Info - Pointer to VQAInfo structure to fill.
  344. *
  345. * RESULT
  346. * NONE
  347. *
  348. ****************************************************************************/
  349. void VQA_GetInfo(VQAHandle *vqa, VQAInfo *info)
  350. {
  351. VQAHeader *header;
  352. /* Dereference header structure. */
  353. header = &((VQAHandleP *)vqa)->Header;
  354. info->NumFrames = header->Frames;
  355. info->ImageHeight = header->ImageHeight;
  356. info->ImageWidth = header->ImageWidth;
  357. info->ImageBuf = ((VQAHandleP *)vqa)->VQABuf->Drawer.ImageBuf;
  358. }
  359. /****************************************************************************
  360. *
  361. * NAME
  362. * VQA_GetStats - Get VQA movie statistics.
  363. *
  364. * SYNOPSIS
  365. * VQA_GetStats(VQA, Stats)
  366. *
  367. * void VQA_GetStats(VQAHandle *, VQAStatistics *);
  368. *
  369. * FUNCTION
  370. * Retrieve the statistics for the VQA movie.
  371. *
  372. * INPUTS
  373. * VQA - Handle of VQA movie to get statistics for.
  374. * Stats - Pointer to VQAStatistics to fill.
  375. *
  376. * RESULT
  377. * NONE
  378. *
  379. ****************************************************************************/
  380. void VQA_GetStats(VQAHandle *vqa, VQAStatistics *stats)
  381. {
  382. VQAData *vqabuf;
  383. /* Dereference VQAData structure from VQAHandle */
  384. vqabuf = ((VQAHandleP *)vqa)->VQABuf;
  385. stats->MemUsed = vqabuf->MemUsed;
  386. stats->StartTime = vqabuf->StartTime;
  387. stats->EndTime = vqabuf->EndTime;
  388. stats->FramesLoaded = vqabuf->LoadedFrames;
  389. stats->FramesDrawn = vqabuf->DrawnFrames;
  390. stats->FramesSkipped = vqabuf->Drawer.NumSkipped;
  391. stats->MaxFrameSize = vqabuf->Loader.MaxFrameSize;
  392. #if(VQAAUDIO_ON)
  393. stats->SamplesPlayed = vqabuf->Audio.SamplesPlayed;
  394. #else
  395. stats->SamplesPlayed = 0;
  396. #endif
  397. }
  398. /****************************************************************************
  399. *
  400. * NAME
  401. * VQA_Version - Get VQA library version number.
  402. *
  403. * SYNOPSIS
  404. * Version = VQA_Version()
  405. *
  406. * char *VQA_Version(void);
  407. *
  408. * FUNCTION
  409. * Return the version of the VQA player library.
  410. *
  411. * INPUTS
  412. * NONE
  413. *
  414. * RESULT
  415. * Version - Pointer to version number string.
  416. *
  417. ****************************************************************************/
  418. char *VQA_Version(void)
  419. {
  420. return(VQA_VERSION);
  421. }
  422. /****************************************************************************
  423. *
  424. * NAME
  425. * VQA_IDString - Get the VQA player library's ID string.
  426. *
  427. * SYNOPSIS
  428. * IDString = VQA_IDString()
  429. *
  430. * char *VQA_IDString(void);
  431. *
  432. * FUNCTION
  433. * Return the ID string of this VQA player library.
  434. *
  435. * INPUTS
  436. * NONE
  437. *
  438. * RESULT
  439. * IDString - Pointer to ID string.
  440. *
  441. ****************************************************************************/
  442. char *VQA_IDString(void)
  443. {
  444. return (VQA_IDSTRING);
  445. }
  446. /****************************************************************************
  447. *
  448. * NAME
  449. * User_Update - Page flip routine called by the task interrupt.
  450. *
  451. * SYNOPSIS
  452. * User_Update(VQA)
  453. *
  454. * long User_Update(VQAHandle *);
  455. *
  456. * FUNCTION
  457. *
  458. * INPUTS
  459. * VQA - Handle of VQA movie.
  460. *
  461. * RESULT
  462. * NONE
  463. *
  464. ****************************************************************************/
  465. long User_Update(VQAHandle *vqa)
  466. {
  467. VQAData *vqabuf;
  468. long rc = 0;
  469. /* Dereference data members for quicker access. */
  470. vqabuf = ((VQAHandleP *)vqa)->VQABuf;
  471. if (vqabuf->Flags & VQADATF_UPDATE) {
  472. /* Invoke the page flip routine */
  473. rc = (*(vqabuf->Page_Flip))(vqa);
  474. /* Update data for mono output */
  475. vqabuf->Flipper.LastFrameNum = vqabuf->Flipper.CurFrame->FrameNum;
  476. /* Mark the frame as loadable */
  477. vqabuf->Flipper.CurFrame->Flags = 0L;
  478. vqabuf->Flags &= (~VQADATF_UPDATE);
  479. }
  480. return (rc);
  481. }