WSA.CPP 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  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. /* $Header: g:/library/source/rcs/./wsa.c 1.16 1994/05/20 15:35:27 joe_bostic Exp $ */
  19. /***************************************************************************
  20. ** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
  21. ***************************************************************************
  22. * *
  23. * Project Name : Library Animation System *
  24. * *
  25. * File Name : WSA.C *
  26. * *
  27. * Programmer : Michael Legg *
  28. * *
  29. * Start Date : November 20, 1991 *
  30. * *
  31. *-------------------------------------------------------------------------*
  32. * There are many different ways that the user can use the WSA library *
  33. * module. The options are as follows : *
  34. * *
  35. * System Allocation vs User Buffer - The user may request that the *
  36. * system allocate the needed buffer from the heap or the user may *
  37. * pass his own buffer in for the animator to use. *
  38. * *
  39. * Resident vs File based - If there is enough RAM, the user may put the *
  40. * entire animation into RAM for fastest animations. If there is *
  41. * not enouph RAM, the system will automatically make it so each *
  42. * frame will be read off disk when needed. *
  43. * *
  44. * Direct to Page vs Use of a user buffer -- Noramally Direct to page *
  45. * is the best method both in speed and in RAM need to hold anim. *
  46. * One may want to use the write to user buffer method if they *
  47. * are using the animation in a non sequencial order. *
  48. * *
  49. *-------------------------------------------------------------------------*
  50. * Functions: *
  51. * Animate_Frame -- Displays a frame of a given animation *
  52. * Get_Animation_Frame_Count -- Return Number of frames in an animation. *
  53. * Get_Animation_X -- Gets the x from an animation *
  54. * Get_Animation_Y -- Gets the y from an animation *
  55. * Get_Animation_Width -- Gets the width from an animation *
  56. * Get_Animation_Height -- The height of the animation we are processing *
  57. * Apply_Delta -- Copies frame into delta buffer, then applies to target *
  58. * Close_Animation -- Close the animation, freeing the space if necessary*
  59. * Get_File_Frame_Offset -- Get offset of a delta frame from animate file*
  60. * Get_Resident_Frame_Offset -- Gets frame offset of animate file in RAM *
  61. * Open_Animation -- Opens an animation file and reads into buffer *
  62. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  63. #include <wwstd.h>
  64. #include "wsa.h"
  65. #include <wwmem.h>
  66. #include <file.h>
  67. #include <misc.h>
  68. #include <iff.h>
  69. #include <mem.h>
  70. #include <string.h>
  71. //
  72. // WSA animation header allocation type.
  73. // If we need more then 8 flags for the flags variable, we can combine
  74. // USER_ALLOCATED with SYS_ALLOCATED and combine FILE with RESIDENT.
  75. //
  76. #define WSA_USER_ALLOCATED 0x01
  77. #define WSA_SYS_ALLOCATED 0x02
  78. #define WSA_FILE 0x04
  79. #define WSA_RESIDENT 0x08
  80. #define WSA_TARGET_IN_BUFFER 0x10
  81. #define WSA_LINEAR_ONLY 0x20
  82. #define WSA_FRAME_0_ON_PAGE 0x40
  83. #define WSA_AMIGA_ANIMATION 0x80
  84. #define WSA_PALETTE_PRESENT 0x100
  85. #define WSA_FRAME_0_IS_DELTA 0x200
  86. // These are used to call Apply_XOR_Delta_To_Page_Or_Viewport() to setup flags parameter. If
  87. // These change, make sure and change their values in lp_asm.asm.
  88. #define DO_XOR 0x0
  89. #define DO_COPY 0x01
  90. #define TO_VIEWPORT 0x0
  91. #define TO_PAGE 0x02
  92. typedef struct {
  93. UWORD current_frame;
  94. UWORD total_frames;
  95. UWORD pixel_x;
  96. UWORD pixel_y;
  97. UWORD pixel_width;
  98. UWORD pixel_height;
  99. UWORD largest_frame_size;
  100. BYTE *delta_buffer;
  101. BYTE *file_buffer;
  102. BYTE file_name[ 13 ];
  103. WORD flags;
  104. // New fields that animate does not know about below this point. SEE EXTRA_BYTES_ANIMATE_NOT_KNOW_ABOUT
  105. WORD file_handle;
  106. ULONG anim_mem_size;
  107. } SysAnimHeaderType;
  108. // NOTE:"THIS IS A BAD THING. SINCE sizeof(SysAnimHeaderType) CHANGED, THE ANIMATE.EXE
  109. // UTILITY DID NOT KNOW I UPDATED IT, IT ADDS IT TO largest_frame_size BEFORE SAVING
  110. // IT TO THE FILE. THIS MEANS I HAVE TO ADD THESE BYTES ON NOW FOR IT TO WORK.
  111. #define EXTRA_BYTES_ANIMATE_NOT_KNOW_ABOUT (sizeof(WORD) + sizeof(ULONG))
  112. //
  113. // Header structure for the file.
  114. // NOTE: The 'total_frames' field is used to differentiate between Amiga and IBM
  115. // animations. Amiga animations have the HIGH bit set.
  116. //
  117. typedef struct {
  118. UWORD total_frames;
  119. UWORD pixel_x;
  120. UWORD pixel_y;
  121. UWORD pixel_width;
  122. UWORD pixel_height;
  123. UWORD largest_frame_size;
  124. WORD flags;
  125. ULONG frame0_offset;
  126. ULONG frame0_end;
  127. /* ULONG data_seek_offset, UWORD frame_size ... */
  128. } WSA_FileHeaderType;
  129. #define WSA_FILE_HEADER_SIZE ( sizeof(WSA_FileHeaderType) - (2 * sizeof(ULONG)) )
  130. /*=========================================================================*/
  131. /* The following PRIVATE functions are in this file: */
  132. /*=========================================================================*/
  133. PRIVATE ULONG Get_Resident_Frame_Offset( BYTE *file_buffer, WORD frame );
  134. PRIVATE ULONG Get_File_Frame_Offset( WORD file_handle, WORD frame, WORD palette_adjust);
  135. PRIVATE BOOL Apply_Delta(SysAnimHeaderType *sys_header, WORD curr_frame, BYTE *dest_ptr, WORD dest_w);
  136. /*= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
  137. /***************************************************************************
  138. * OPEN_ANIMATION -- Opens an animation file and reads into buffer *
  139. * *
  140. * INPUT: BYTE *file_name of animation sequence file. *
  141. * BYTE *user_buffer pointer if one exists (NULL ok) *
  142. * ULONG user_buffer_size if known (NULL ok) *
  143. * WSAOpenType user_flags - flags on how to open. *
  144. * UBYTE *palette - pointer to palette space for return (NULL ok) *
  145. * *
  146. * OUTPUT: VOID *pointer to animation data. Must be used for all *
  147. * other WSA calls. *
  148. * *
  149. * WARNINGS: May return NULL, please check. *
  150. * *
  151. * HISTORY: *
  152. * 11/26/1991 SB : Created. *
  153. *=========================================================================*/
  154. VOID * cdecl Open_Animation(BYTE const *file_name, BYTE *user_buffer, LONG user_buffer_size, WSAOpenType user_flags, UBYTE *palette)
  155. {
  156. WORD fh, anim_flags;
  157. WORD palette_adjust;
  158. UWORD offsets_size;
  159. UWORD frame0_size;
  160. LONG target_buffer_size, delta_buffer_size, file_buffer_size;
  161. LONG max_buffer_size, min_buffer_size;
  162. BYTE *sys_anim_header_buffer;
  163. BYTE *target_buffer;
  164. BYTE *delta_buffer, *delta_back;
  165. SysAnimHeaderType *sys_header;
  166. WSA_FileHeaderType file_header;
  167. /*======================================================================*/
  168. /* Open the file to get the header information */
  169. /*======================================================================*/
  170. anim_flags = 0;
  171. fh = Open_File(file_name, READ);
  172. Read_File(fh, (BYTE *) &file_header, sizeof(WSA_FileHeaderType));
  173. /*======================================================================*/
  174. /* If the file has an attached palette then if we have a valid palette */
  175. /* pointer we need to read it in. */
  176. /*======================================================================*/
  177. if (file_header.flags & 1) {
  178. anim_flags |= WSA_PALETTE_PRESENT;
  179. palette_adjust = 768;
  180. if (palette != NULL) {
  181. Seek_File(fh, sizeof(ULONG) * (file_header.total_frames), SEEK_CUR);
  182. Read_File(fh, palette, 768L);
  183. }
  184. } else {
  185. palette_adjust = 0;
  186. }
  187. // Check for flag from ANIMATE indicating that this animation was
  188. // created from a .LBM and a .ANM. These means that the first
  189. // frame is a XOR Delta from a picture, not black.
  190. if (file_header.flags & 2) {
  191. anim_flags |= WSA_FRAME_0_IS_DELTA;
  192. }
  193. // Get the total file size minus the size of the first frame and the size
  194. // of the file header. These will not be read in to save even more space.
  195. file_buffer_size = Seek_File(fh, 0L, SEEK_END);
  196. if (file_header.frame0_offset) {
  197. LONG tlong;
  198. tlong = file_header.frame0_end - file_header.frame0_offset;
  199. frame0_size = (UWORD) tlong;
  200. }
  201. else {
  202. anim_flags |= WSA_FRAME_0_ON_PAGE;
  203. frame0_size = 0;
  204. }
  205. file_buffer_size -= palette_adjust + frame0_size + WSA_FILE_HEADER_SIZE;
  206. // We need to determine the buffer sizes required for the animation. At a
  207. // minimum, we need a target buffer for the uncompressed frame and a delta
  208. // buffer for the delta data. We may be able to make the file resident,
  209. // so we will determine the file size.
  210. //
  211. // If the target buffer is in the user buffer
  212. // Then figure its size
  213. // and set the allocation flag
  214. // Else size is zero.
  215. //
  216. if (user_flags & WSA_OPEN_DIRECT) {
  217. target_buffer_size = 0L;
  218. }
  219. else {
  220. anim_flags |= WSA_TARGET_IN_BUFFER;
  221. target_buffer_size = (ULONG) file_header.pixel_width * file_header.pixel_height;
  222. }
  223. // NOTE:"THIS IS A BAD THING. SINCE sizeof(SysAnimHeaderType) CHANGED, THE ANIMATE.EXE
  224. // UTILITY DID NOT KNOW I UPDATED IT, IT ADDS IT TO largest_frame_size BEFORE SAVING
  225. // IT TO THE FILE. THIS MEANS I HAVE TO ADD THESE BYTES ON NOW FOR IT TO WORK.
  226. delta_buffer_size = (ULONG) file_header.largest_frame_size + EXTRA_BYTES_ANIMATE_NOT_KNOW_ABOUT;
  227. min_buffer_size = target_buffer_size + delta_buffer_size;
  228. max_buffer_size = min_buffer_size + file_buffer_size;
  229. // check to see if buffer size is big enough for at least min required
  230. if (user_buffer && (user_buffer_size < min_buffer_size)) {
  231. Close_File(fh);
  232. return(NULL);
  233. }
  234. // A buffer was not passed in, so do allocations
  235. if (user_buffer == NULL) {
  236. // If the user wants it from the disk, then let us give it to him,
  237. // otherwise, try to give a max allocation he can have.
  238. if (user_flags & WSA_OPEN_FROM_DISK) {
  239. user_buffer_size = min_buffer_size;
  240. }
  241. // else no buffer size, then try max configuration.
  242. else if (!user_buffer_size) {
  243. user_buffer_size = max_buffer_size;
  244. }
  245. // else if buffer specified is less then max needed, give min.
  246. else if (user_buffer_size < max_buffer_size) {
  247. user_buffer_size = min_buffer_size;
  248. }
  249. // otherwise we only want to alloc what we need.
  250. else {
  251. user_buffer_size = max_buffer_size;
  252. }
  253. // Check to see if enough RAM available for buffer_size.
  254. if (user_buffer_size > Ram_Free(MEM_NORMAL)) {
  255. // If not enough room for even the min, return no buffer.
  256. if (min_buffer_size > Ram_Free(MEM_NORMAL)) {
  257. Close_File(fh);
  258. return(NULL);
  259. }
  260. // Else make buffer size the min and allocate it.
  261. user_buffer_size = min_buffer_size;
  262. }
  263. // allocate buffer needed
  264. user_buffer = (BYTE *) Alloc(user_buffer_size, MEM_CLEAR);
  265. anim_flags |= WSA_SYS_ALLOCATED;
  266. }
  267. else {
  268. // Check to see if the user_buffer_size should be min or max.
  269. if ((user_flags & WSA_OPEN_FROM_DISK) || (user_buffer_size < max_buffer_size)) {
  270. user_buffer_size = min_buffer_size;
  271. }
  272. else {
  273. user_buffer_size = max_buffer_size;
  274. }
  275. anim_flags |= WSA_USER_ALLOCATED;
  276. }
  277. // Set the pointers to the RAM buffers
  278. sys_anim_header_buffer = user_buffer;
  279. target_buffer = (BYTE *) Add_Long_To_Pointer(sys_anim_header_buffer, sizeof(SysAnimHeaderType));
  280. delta_buffer = (BYTE *) Add_Long_To_Pointer(target_buffer, target_buffer_size);
  281. // Clear target buffer if it is in the user buffer.
  282. if (target_buffer_size) {
  283. memset( target_buffer, 0, (UWORD) target_buffer_size );
  284. }
  285. // Poke data into the system animation header (start of user_buffer)
  286. // current_frame is set to total_frames so that Animate_Frame() knows that
  287. // it needs to clear the target buffer.
  288. sys_header = ( SysAnimHeaderType * ) sys_anim_header_buffer;
  289. sys_header -> current_frame =
  290. sys_header -> total_frames = file_header.total_frames;
  291. sys_header -> pixel_x = file_header.pixel_x;
  292. sys_header -> pixel_y = file_header.pixel_y;
  293. sys_header -> pixel_width = file_header.pixel_width;
  294. sys_header -> pixel_height = file_header.pixel_height;
  295. sys_header -> anim_mem_size = user_buffer_size;
  296. sys_header -> delta_buffer = delta_buffer;
  297. sys_header -> largest_frame_size =
  298. (UWORD) delta_buffer_size - sizeof(SysAnimHeaderType);
  299. strcpy(sys_header->file_name, file_name);
  300. // Figure how much room the frame offsets take up in the file.
  301. // Add 2 - one for the wrap around and one for the final end offset.
  302. offsets_size = (file_header.total_frames + 2) << 2;
  303. // Can the user_buffer_size handle the maximum case buffer?
  304. if ( user_buffer_size == max_buffer_size) {
  305. //
  306. // set the file buffer pointer,
  307. // Skip over the header information.
  308. // Read in the offsets.
  309. // Skip over the first frame.
  310. // Read in remaining frames.
  311. //
  312. sys_header->file_buffer = (BYTE *)Add_Long_To_Pointer(delta_buffer,sys_header->largest_frame_size);
  313. Seek_File( fh, WSA_FILE_HEADER_SIZE, SEEK_SET);
  314. Read_File( fh, sys_header->file_buffer, offsets_size);
  315. Seek_File( fh, frame0_size + palette_adjust, SEEK_CUR);
  316. Read_File( fh, sys_header->file_buffer + offsets_size,
  317. file_buffer_size - offsets_size);
  318. //
  319. // Find out if there is an ending value for the last frame.
  320. // If there is not, then this animation will not be able to
  321. // loop back to the beginning.
  322. //
  323. if (Get_Resident_Frame_Offset( sys_header->file_buffer, sys_header->total_frames + 1))
  324. anim_flags |= WSA_RESIDENT;
  325. else
  326. anim_flags |= WSA_LINEAR_ONLY | WSA_RESIDENT;
  327. }
  328. else { // buffer cannot handle max_size of buffer
  329. if(Get_File_Frame_Offset( fh, sys_header->total_frames + 1, palette_adjust))
  330. anim_flags |= WSA_FILE;
  331. else
  332. anim_flags |= WSA_LINEAR_ONLY | WSA_FILE;
  333. ////
  334. sys_header->file_buffer = NULL;
  335. }
  336. // Figure where to back load frame 0 into the delta buffer.
  337. delta_back = (BYTE *)Add_Long_To_Pointer(delta_buffer,
  338. sys_header->largest_frame_size - frame0_size);
  339. // Read the first frame into the delta buffer and uncompress it.
  340. // Then close it.
  341. Seek_File( fh, WSA_FILE_HEADER_SIZE + offsets_size + palette_adjust, SEEK_SET);
  342. Read_File( fh, delta_back, frame0_size);
  343. // We do not use the file handle when it is in RAM.
  344. if (anim_flags & WSA_RESIDENT) {
  345. sys_header -> file_handle = (WORD) -1;
  346. Close_File(fh);
  347. }
  348. else {
  349. sys_header -> file_handle = fh;
  350. }
  351. LCW_Uncompress(delta_back, delta_buffer, sys_header->largest_frame_size);
  352. // Finally set the flags,
  353. sys_header->flags = anim_flags;
  354. // return valid handle
  355. return( user_buffer );
  356. }
  357. /***************************************************************************
  358. * CLOSE_ANIMATION -- Close the animation, freeing the space if necessary. *
  359. * *
  360. * INPUT: VOID *handle to the animation data buffer *
  361. * *
  362. * OUTPUT: none *
  363. * *
  364. * WARNINGS: handle MUST have been returned by Open_Animation *
  365. * *
  366. * HISTORY: *
  367. * 11/23/1991 ML : Created. *
  368. *=========================================================================*/
  369. VOID cdecl Close_Animation( VOID *handle )
  370. {
  371. SysAnimHeaderType *sys_header;
  372. // Assign our local system header pointer to the beginning of the handle space
  373. sys_header = (SysAnimHeaderType *) handle;
  374. // Close the WSA file in it was disk based.
  375. if (sys_header->flags & WSA_FILE) {
  376. Close_File(sys_header->file_handle);
  377. }
  378. // Check to see if the buffer was allocated OR the programmer provided the buffer
  379. if (handle && sys_header->flags & WSA_SYS_ALLOCATED) {
  380. Free(handle);
  381. }
  382. }
  383. /***************************************************************************
  384. * ANIMATE_FRAME -- Displays a frame of a given animation *
  385. * *
  386. * INPUT: VOID *handle to the animation. *
  387. * WORD frame_number wanted to be displayed *
  388. * WORD x_pixel position of left side of animation on page *
  389. * WORD y_pixel position of top of animation on page *
  390. * *
  391. * OUTPUT: BOOL if successfull or not. *
  392. * *
  393. * WARNINGS: *
  394. * *
  395. * HISTORY: *
  396. * 11/27/1991 SB : Created. *
  397. *=========================================================================*/
  398. #pragma argsused
  399. BOOL cdecl Animate_Frame(VOID *handle, VideoViewPortClass& view,
  400. WORD frame_number, WORD x_pixel, WORD y_pixel,
  401. WSAType flags_and_prio, VOID *magic_cols, VOID *magic)
  402. {
  403. SysAnimHeaderType *sys_header; // fix up the VOID pointer past in.
  404. WORD curr_frame; // current frame we are on.
  405. WORD total_frames; // number of frames in anim.
  406. WORD distance; // distance to desired frame.
  407. WORD search_dir; // direcion to search for desired frame.
  408. WORD search_frames; // How many frames to search.
  409. WORD loop; // Just a loop varible.
  410. BYTE *frame_buffer; // our destination.
  411. BOOL direct_to_dest; // are we going directly to the destination?
  412. WORD dest_width; // the width of the destination buffer or page.
  413. // Assign local pointer to the beginning of the buffer where the system information
  414. // resides
  415. sys_header = (SysAnimHeaderType *)handle;
  416. // Get the total number of frames
  417. total_frames = sys_header->total_frames;
  418. // Are the animation handle and the frame number valid?
  419. if (!handle || (total_frames <= frame_number)) {
  420. return FALSE;
  421. }
  422. // Decide if we are going to a page or a viewport (part of a buffer).
  423. dest_width = view.Get_Width() + view.Get_XAdd();
  424. //
  425. // adjust x_pixel and y_pixel by system pixel_x and pixel_y respectively.
  426. //
  427. x_pixel += (WORD)sys_header->pixel_x;
  428. y_pixel += (WORD)sys_header->pixel_y;
  429. //
  430. // Check to see if we are using a buffer inside of the animation buffer or if
  431. // it is being drawn directly to the destination page or buffer.
  432. //
  433. if (sys_header->flags & WSA_TARGET_IN_BUFFER) {
  434. // Get a pointer to the frame in animation buffer.
  435. frame_buffer = (BYTE *)Add_Long_To_Pointer(sys_header, sizeof(SysAnimHeaderType));
  436. direct_to_dest = FALSE;
  437. }
  438. else {
  439. frame_buffer = (BYTE *)view.Get_Offset();
  440. frame_buffer += (y_pixel * dest_width) + x_pixel;
  441. direct_to_dest = TRUE;
  442. }
  443. //
  444. // If current_frame is equal to tatal_frames, then no animations have taken place
  445. // so must uncompress frame 0 in delta buffer to the frame_buffer/page if it
  446. // exists.
  447. //
  448. if (sys_header->current_frame == total_frames) {
  449. // Call apply delta telling it wether to copy or to xor depending on if the
  450. // target is a page or a buffer.
  451. if (!(sys_header->flags & WSA_FRAME_0_ON_PAGE)) {
  452. if (direct_to_dest) {
  453. // The last parameter says weather to copy or to XOR. If the
  454. // first frame is a DELTA, then it must be XOR'd. A TRUE is
  455. // copy while FALSE is XOR.
  456. Apply_XOR_Delta_To_Page_Or_Viewport(frame_buffer, sys_header->delta_buffer,
  457. sys_header->pixel_width, dest_width, //dest_width - sys_header->pixel_width,
  458. (sys_header->flags & WSA_FRAME_0_IS_DELTA)? DO_XOR : DO_COPY);
  459. }
  460. else {
  461. Apply_XOR_Delta(frame_buffer, sys_header->delta_buffer);
  462. }
  463. }
  464. sys_header->current_frame = 0;
  465. }
  466. //
  467. // Get the current frame
  468. // If no looping aloud, are the trying to do it anyways?
  469. //
  470. curr_frame = sys_header->current_frame;
  471. #if (FALSE)
  472. // This is commented out since we will let them loop even though they should
  473. // not - it will be slower.
  474. if ( (sys_header->flags & WSA_LINEAR_ONLY) && (frame_number < cur_frame) ) {
  475. return FALSE;
  476. }
  477. #endif
  478. // Get absoulte distance from our current frame to the target frame
  479. distance = ABS(curr_frame - frame_number);
  480. // Assume we are searching right
  481. search_dir = 1;
  482. // Calculate the number of frames to search if we go right and wrap
  483. if (frame_number > curr_frame) {
  484. search_frames = total_frames - frame_number + curr_frame;
  485. // Is going right faster than going backwards?
  486. // Or are they trying to loop when the should not?
  487. if ((search_frames < distance) && !(sys_header->flags & WSA_LINEAR_ONLY)) {
  488. search_dir = -1; // No, so go left
  489. }
  490. else {
  491. search_frames = distance;
  492. }
  493. }
  494. else {
  495. search_frames = total_frames - curr_frame + frame_number;
  496. // Is going right faster than going backwards?
  497. // Or are they trying to loop when the should not?
  498. if ((search_frames >= distance) || (sys_header->flags & WSA_LINEAR_ONLY)) {
  499. search_dir = -1; // No, so go left
  500. search_frames = distance;
  501. }
  502. }
  503. // Take care of the case when we are searching right (possibly right)
  504. if (search_dir > 0) {
  505. for (loop = 0; loop < search_frames; loop++) {
  506. // Move the logical frame number ordinally right
  507. curr_frame += search_dir;
  508. Apply_Delta(sys_header, curr_frame, frame_buffer, dest_width);
  509. // Adjust the current frame number, taking into consideration that we could
  510. // have wrapped
  511. if (curr_frame == total_frames) {
  512. curr_frame = 0;
  513. }
  514. }
  515. }
  516. else {
  517. for (loop = 0; loop < search_frames; loop++) {
  518. // If we are going backwards and we are on frame 0, the delta to get
  519. // to the last frame is the n + 1 delta (wrap delta)
  520. if (curr_frame == 0) {
  521. curr_frame = total_frames;
  522. }
  523. Apply_Delta(sys_header, curr_frame, frame_buffer, dest_width);
  524. curr_frame += search_dir;
  525. }
  526. }
  527. sys_header->current_frame = frame_number;
  528. // If we did this all in a hidden buffer, then copy it to the desired page or viewport.
  529. if (sys_header->flags & WSA_TARGET_IN_BUFFER) {
  530. #if TRUE
  531. Buffer_To_Page(x_pixel, y_pixel, sys_header->pixel_width, sys_header->pixel_height, frame_buffer, view);
  532. #else
  533. WORD flags = ((UWORD)flags_and_prio & 0xFF00u) >> 12u;
  534. WORD pri = flags_and_prio & 0x00FF;
  535. Buffer_Bitblit_To_LogicPage(x_pixel, y_pixel, sys_header->pixel_width,
  536. sys_header->pixel_height, 0, flags, frame_buffer, pri,
  537. magic_cols, magic);
  538. #endif
  539. }
  540. return TRUE;
  541. }
  542. /***************************************************************************
  543. * ANIMATE_FRAME -- Displays a frame of a given animation *
  544. * *
  545. * INPUT: VOID *handle to the animation. *
  546. * WORD frame_number wanted to be displayed *
  547. * WORD x_pixel position of left side of animation on page *
  548. * WORD y_pixel position of top of animation on page *
  549. * *
  550. * OUTPUT: BOOL if successfull or not. *
  551. * *
  552. * WARNINGS: *
  553. * *
  554. * HISTORY: *
  555. * 11/27/1991 SB : Created. *
  556. *=========================================================================*/
  557. #pragma argsused
  558. BOOL cdecl Animate_Frame(VOID *handle, GraphicViewPortClass& view,
  559. WORD frame_number, WORD x_pixel, WORD y_pixel,
  560. WSAType flags_and_prio, VOID *magic_cols, VOID *magic)
  561. {
  562. SysAnimHeaderType *sys_header; // fix up the VOID pointer past in.
  563. WORD curr_frame; // current frame we are on.
  564. WORD total_frames; // number of frames in anim.
  565. WORD distance; // distance to desired frame.
  566. WORD search_dir; // direcion to search for desired frame.
  567. WORD search_frames; // How many frames to search.
  568. WORD loop; // Just a loop varible.
  569. BYTE *frame_buffer; // our destination.
  570. BOOL direct_to_dest; // are we going directly to the destination?
  571. WORD dest_width; // the width of the destination buffer or page.
  572. // Assign local pointer to the beginning of the buffer where the system information
  573. // resides
  574. sys_header = (SysAnimHeaderType *)handle;
  575. // Get the total number of frames
  576. total_frames = sys_header->total_frames;
  577. // Are the animation handle and the frame number valid?
  578. if (!handle || (total_frames <= frame_number)) {
  579. return FALSE;
  580. }
  581. // Decide if we are going to a page or a viewport (part of a buffer).
  582. dest_width = view.Get_Width() + view.Get_XAdd();
  583. //
  584. // adjust x_pixel and y_pixel by system pixel_x and pixel_y respectively.
  585. //
  586. x_pixel += (WORD)sys_header->pixel_x;
  587. y_pixel += (WORD)sys_header->pixel_y;
  588. //
  589. // Check to see if we are using a buffer inside of the animation buffer or if
  590. // it is being drawn directly to the destination page or buffer.
  591. //
  592. if (sys_header->flags & WSA_TARGET_IN_BUFFER) {
  593. // Get a pointer to the frame in animation buffer.
  594. frame_buffer = (BYTE *)Add_Long_To_Pointer(sys_header, sizeof(SysAnimHeaderType));
  595. direct_to_dest = FALSE;
  596. }
  597. else {
  598. frame_buffer = (BYTE *)view.Get_Offset();
  599. frame_buffer += (y_pixel * dest_width) + x_pixel;
  600. direct_to_dest = TRUE;
  601. }
  602. //
  603. // If current_frame is equal to tatal_frames, then no animations have taken place
  604. // so must uncompress frame 0 in delta buffer to the frame_buffer/page if it
  605. // exists.
  606. //
  607. if (sys_header->current_frame == total_frames) {
  608. // Call apply delta telling it wether to copy or to xor depending on if the
  609. // target is a page or a buffer.
  610. if (!(sys_header->flags & WSA_FRAME_0_ON_PAGE)) {
  611. if (direct_to_dest) {
  612. // The last parameter says weather to copy or to XOR. If the
  613. // first frame is a DELTA, then it must be XOR'd. A TRUE is
  614. // copy while FALSE is XOR.
  615. Apply_XOR_Delta_To_Page_Or_Viewport(frame_buffer, sys_header->delta_buffer,
  616. sys_header->pixel_width, dest_width, //dest_width - sys_header->pixel_width,
  617. (sys_header->flags & WSA_FRAME_0_IS_DELTA)? DO_XOR : DO_COPY);
  618. }
  619. else {
  620. Apply_XOR_Delta(frame_buffer, sys_header->delta_buffer);
  621. }
  622. }
  623. sys_header->current_frame = 0;
  624. }
  625. //
  626. // Get the current frame
  627. // If no looping aloud, are the trying to do it anyways?
  628. //
  629. curr_frame = sys_header->current_frame;
  630. #if (FALSE)
  631. // This is commented out since we will let them loop even though they should
  632. // not - it will be slower.
  633. if ( (sys_header->flags & WSA_LINEAR_ONLY) && (frame_number < cur_frame) ) {
  634. return FALSE;
  635. }
  636. #endif
  637. // Get absoulte distance from our current frame to the target frame
  638. distance = ABS(curr_frame - frame_number);
  639. // Assume we are searching right
  640. search_dir = 1;
  641. // Calculate the number of frames to search if we go right and wrap
  642. if (frame_number > curr_frame) {
  643. search_frames = total_frames - frame_number + curr_frame;
  644. // Is going right faster than going backwards?
  645. // Or are they trying to loop when the should not?
  646. if ((search_frames < distance) && !(sys_header->flags & WSA_LINEAR_ONLY)) {
  647. search_dir = -1; // No, so go left
  648. }
  649. else {
  650. search_frames = distance;
  651. }
  652. }
  653. else {
  654. search_frames = total_frames - curr_frame + frame_number;
  655. // Is going right faster than going backwards?
  656. // Or are they trying to loop when the should not?
  657. if ((search_frames >= distance) || (sys_header->flags & WSA_LINEAR_ONLY)) {
  658. search_dir = -1; // No, so go left
  659. search_frames = distance;
  660. }
  661. }
  662. // Take care of the case when we are searching right (possibly right)
  663. if (search_dir > 0) {
  664. for (loop = 0; loop < search_frames; loop++) {
  665. // Move the logical frame number ordinally right
  666. curr_frame += search_dir;
  667. Apply_Delta(sys_header, curr_frame, frame_buffer, dest_width);
  668. // Adjust the current frame number, taking into consideration that we could
  669. // have wrapped
  670. if (curr_frame == total_frames) {
  671. curr_frame = 0;
  672. }
  673. }
  674. }
  675. else {
  676. for (loop = 0; loop < search_frames; loop++) {
  677. // If we are going backwards and we are on frame 0, the delta to get
  678. // to the last frame is the n + 1 delta (wrap delta)
  679. if (curr_frame == 0) {
  680. curr_frame = total_frames;
  681. }
  682. Apply_Delta(sys_header, curr_frame, frame_buffer, dest_width);
  683. curr_frame += search_dir;
  684. }
  685. }
  686. sys_header->current_frame = frame_number;
  687. // If we did this all in a hidden buffer, then copy it to the desired page or viewport.
  688. if (sys_header->flags & WSA_TARGET_IN_BUFFER) {
  689. #if TRUE
  690. Buffer_To_Page(x_pixel, y_pixel, sys_header->pixel_width, sys_header->pixel_height, frame_buffer, view);
  691. #else
  692. WORD flags = ((UWORD)flags_and_prio & 0xFF00u) >> 12u;
  693. WORD pri = flags_and_prio & 0x00FF;
  694. Buffer_Bitblit_To_LogicPage(x_pixel, y_pixel, sys_header->pixel_width,
  695. sys_header->pixel_height, 0, flags, frame_buffer, pri,
  696. magic_cols, magic);
  697. #endif
  698. }
  699. return TRUE;
  700. }
  701. /***************************************************************************
  702. * ANIMATE_FRAME_COUNT -- Return Number of frames in an animation. *
  703. * *
  704. * INPUT: VOID *handle to the animation. *
  705. * *
  706. * OUTPUT: WORD number of frames in animation. *
  707. * *
  708. * WARNINGS: *
  709. * *
  710. * HISTORY: *
  711. * 12/05/1991 SB : Created. *
  712. *=========================================================================*/
  713. WORD cdecl Get_Animation_Frame_Count(VOID *handle)
  714. {
  715. SysAnimHeaderType *sys_header;
  716. if (!handle) {
  717. return FALSE;
  718. }
  719. sys_header = (SysAnimHeaderType *) handle;
  720. return((WORD)sys_header->total_frames);
  721. }
  722. /***************************************************************************
  723. * GET_ANIM_X -- Gets the x from an animation *
  724. * *
  725. * *
  726. * INPUT: VOID * to the animation that we are processing *
  727. * *
  728. * OUTPUT: WORD the x of the animation we are processing *
  729. * *
  730. * WARNINGS: *
  731. * *
  732. * HISTORY: *
  733. * 07/03/1992 DRD : Created. *
  734. *=========================================================================*/
  735. WORD cdecl Get_Animation_X(VOID const *handle)
  736. {
  737. SysAnimHeaderType const *sys_header;
  738. if (!handle) {
  739. return FALSE;
  740. }
  741. sys_header = (SysAnimHeaderType *) handle;
  742. return(sys_header->pixel_x);
  743. }
  744. /***************************************************************************
  745. * GET_ANIM_Y -- Gets the y from an animation *
  746. * *
  747. * *
  748. * INPUT: VOID * to the animation that we are processing *
  749. * *
  750. * OUTPUT: WORD the y of the animation we are processing *
  751. * *
  752. * WARNINGS: *
  753. * *
  754. * HISTORY: *
  755. * 10/14/1992 PWG : Created. *
  756. *=========================================================================*/
  757. WORD cdecl Get_Animation_Y(VOID const *handle)
  758. {
  759. SysAnimHeaderType const *sys_header;
  760. if (!handle) {
  761. return FALSE;
  762. }
  763. sys_header = (SysAnimHeaderType *) handle;
  764. return(sys_header->pixel_y);
  765. }
  766. /***************************************************************************
  767. * GET_ANIM_WIDTH -- Gets the width from an animation *
  768. * *
  769. * *
  770. * INPUT: VOID * to the animation that we are processing *
  771. * *
  772. * OUTPUT: WORD the width of the animation we are processing *
  773. * *
  774. * WARNINGS: *
  775. * *
  776. * HISTORY: *
  777. * 10/14/1992 PWG : Created. *
  778. *=========================================================================*/
  779. WORD cdecl Get_Animation_Width(VOID const *handle)
  780. {
  781. SysAnimHeaderType const *sys_header;
  782. if (!handle) {
  783. return FALSE;
  784. }
  785. sys_header = (SysAnimHeaderType *) handle;
  786. return(sys_header->pixel_width);
  787. }
  788. /***************************************************************************
  789. * GET_ANIM_HEIGHT -- The height of the animation we are processing *
  790. * *
  791. * INPUT: VOID * to the animation that we are processing *
  792. * *
  793. * OUTPUT: WORD the height of the animation we are processing *
  794. * *
  795. * HISTORY: *
  796. * 10/14/1992 PWG : Created. *
  797. *=========================================================================*/
  798. WORD cdecl Get_Animation_Height(VOID const *handle)
  799. {
  800. SysAnimHeaderType const *sys_header;
  801. if (!handle) {
  802. return FALSE;
  803. }
  804. sys_header = (SysAnimHeaderType *) handle;
  805. return(sys_header->pixel_height);
  806. }
  807. /***************************************************************************
  808. * GET_ANIM_PALETTE -- Returns true if the anim had an attached palette *
  809. * *
  810. * INPUT: VOID * to the animation that we are processing *
  811. * *
  812. * OUTPUT: WORD True if the animation has a set palette. False if the *
  813. * animation does not. *
  814. * *
  815. * HISTORY: *
  816. * 10/14/1992 PWG : Created. *
  817. *=========================================================================*/
  818. WORD cdecl Get_Animation_Palette(VOID const *handle)
  819. {
  820. SysAnimHeaderType const *sys_header;
  821. if (!handle) {
  822. return FALSE;
  823. }
  824. sys_header = (SysAnimHeaderType *) handle;
  825. return(sys_header->flags & WSA_PALETTE_PRESENT);
  826. }
  827. /***************************************************************************
  828. * GET_ANIMATION_SIZE -- Return the amount of memory the animation is using*
  829. * *
  830. * *
  831. * INPUT: VOID * to the animation that we are processing *
  832. * *
  833. * OUTPUT: ULONG number of byte used by animation. *
  834. * *
  835. * WARNINGS: *
  836. * *
  837. * HISTORY: *
  838. * 05/23/1994 SKB : Created. *
  839. *=========================================================================*/
  840. ULONG cdecl Get_Animation_Size(VOID const *handle)
  841. {
  842. SysAnimHeaderType const *sys_header;
  843. if (!handle) {
  844. return FALSE;
  845. }
  846. sys_header = (SysAnimHeaderType *) handle;
  847. return(sys_header->anim_mem_size);
  848. }
  849. /* :::::::::::::::::::::::::::: PRIVATE FUNCTIONS :::::::::::::::::::::::::::::: */
  850. /***************************************************************************
  851. * GET_RESIDENT_FRAME_OFFSET -- Gets frame offset of animate file in RAM *
  852. * *
  853. * INPUT: BYTE *file_buffer in RAM of animation file. *
  854. * WORD frame number that we need the offset of. *
  855. * *
  856. * OUTPUT: WORD offset of frame requested. *
  857. * *
  858. * WARNINGS: *
  859. * *
  860. * HISTORY: *
  861. * 11/26/1991 SB : Created. *
  862. *=========================================================================*/
  863. PRIVATE ULONG Get_Resident_Frame_Offset( BYTE *file_buffer, WORD frame )
  864. {
  865. ULONG frame0_size;
  866. ULONG *lptr;
  867. // If there is a frame 0, the calculate its size.
  868. lptr = (ULONG *) file_buffer;
  869. if (*lptr) {
  870. frame0_size = lptr[1] - *lptr;
  871. } else {
  872. frame0_size = 0;
  873. }
  874. // Return the offset into RAM for the frame.
  875. lptr += frame;
  876. if (*lptr)
  877. return (*lptr - (frame0_size + WSA_FILE_HEADER_SIZE));
  878. else
  879. return (0L);
  880. }
  881. /***************************************************************************
  882. * GET_FILE_FRAME_OFFSET -- Get offset of a delta frame from animate file. *
  883. * *
  884. * INPUT: WORD file_handle of animation file. *
  885. * WORD frame number that we need the offset of. *
  886. * *
  887. * OUTPUT: WORD offset of frame requested. *
  888. * *
  889. * WARNINGS: *
  890. * *
  891. * HISTORY: *
  892. * 11/26/1991 SB : Created. *
  893. *=========================================================================*/
  894. PRIVATE ULONG Get_File_Frame_Offset( WORD file_handle, WORD frame, WORD palette_adjust)
  895. {
  896. ULONG offset;
  897. Seek_File(file_handle, (frame << 2) + WSA_FILE_HEADER_SIZE, SEEK_SET);
  898. if (Read_File(file_handle, (BYTE *) &offset, sizeof(ULONG)) != sizeof(ULONG)) {
  899. offset = 0L;
  900. }
  901. offset += palette_adjust;
  902. return( offset );
  903. }
  904. /***************************************************************************
  905. * APPLY_DELTA -- Copies frame into delta buffer, then applies to target *
  906. * *
  907. * INPUT: SysAnimHeaderType *sys_header - pointer to animation buffer.*
  908. * WORD curr_frame - frame to put into target buffer. *
  909. * *
  910. * OUTPUT: BOOL - Return wether or not it worked. *
  911. * *
  912. * WARNINGS: *
  913. * *
  914. * HISTORY: *
  915. * 11/26/1991 SB : Created. *
  916. *=========================================================================*/
  917. PRIVATE BOOL Apply_Delta(SysAnimHeaderType *sys_header, WORD curr_frame, BYTE *dest_ptr, WORD dest_w)
  918. {
  919. BYTE *data_ptr, *delta_back;
  920. WORD file_handle, palette_adjust;
  921. ULONG frame_data_size, frame_offset;
  922. palette_adjust = ((sys_header->flags & WSA_PALETTE_PRESENT) ? 768 : 0);
  923. delta_back = sys_header->delta_buffer;
  924. if (sys_header->flags & WSA_RESIDENT) {
  925. // Get offset of the given frame in the resident file
  926. // Get the size of the frame <- (frame+1 offset) - (offset)
  927. // Point at the delta data
  928. // figure offset to load data into end of delta buffer
  929. // copy it into buffer
  930. frame_offset = Get_Resident_Frame_Offset(sys_header->file_buffer, curr_frame);
  931. frame_data_size = Get_Resident_Frame_Offset(sys_header->file_buffer, curr_frame + 1) - frame_offset;
  932. data_ptr = (BYTE *)Add_Long_To_Pointer(sys_header->file_buffer, frame_offset);
  933. delta_back = (BYTE *)Add_Long_To_Pointer(delta_back,
  934. sys_header->largest_frame_size - frame_data_size);
  935. Mem_Copy( data_ptr, delta_back, frame_data_size );
  936. } else if (sys_header -> flags & WSA_FILE) {
  937. // Open up file because not file not in RAM.
  938. // Get offset of the given frame in the file on disk
  939. // Get the size of the frame <- (frame+1 offset) - (offset)
  940. // Return if Get_.._offset() failed. -- need error handling????
  941. // Seek to delta data.
  942. // figure offset to load data into end of delta buffer
  943. // Read it into buffer -- Return if correct amount not read.-- errors??
  944. file_handle = sys_header->file_handle;
  945. Seek_File(file_handle, 0L, SEEK_SET);
  946. frame_offset = Get_File_Frame_Offset(file_handle, curr_frame, palette_adjust);
  947. frame_data_size = Get_File_Frame_Offset(file_handle, curr_frame + 1, palette_adjust) - frame_offset;
  948. if (!frame_offset || !frame_data_size) {
  949. return(FALSE);
  950. }
  951. Seek_File(file_handle, frame_offset, SEEK_SET);
  952. delta_back = (BYTE *)Add_Long_To_Pointer(delta_back, sys_header->largest_frame_size - frame_data_size);
  953. if (Read_File(file_handle, delta_back, frame_data_size) != frame_data_size) {
  954. return(FALSE);
  955. }
  956. }
  957. // Uncompress data at end of delta buffer to the beginning of delta buffer.
  958. // Find start of target buffer.
  959. // Apply the XOR delta.
  960. LCW_Uncompress(delta_back, sys_header->delta_buffer, sys_header->largest_frame_size);
  961. if (sys_header->flags & WSA_TARGET_IN_BUFFER) {
  962. Apply_XOR_Delta(dest_ptr, sys_header->delta_buffer);
  963. }
  964. else {
  965. Apply_XOR_Delta_To_Page_Or_Viewport(dest_ptr, sys_header->delta_buffer,
  966. sys_header->pixel_width, dest_w, DO_XOR);
  967. }
  968. return(TRUE);
  969. }