1 /* 2 Copyright (c) 2009 Peter "Corsix" Cawley 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy of 5 this software and associated documentation files (the "Software"), to deal in 6 the Software without restriction, including without limitation the rights to 7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 of the Software, and to permit persons to whom the Software is furnished to do 9 so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in all 12 copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 SOFTWARE. 21 */ 22 23 #ifndef CORSIX_TH_TH_GFX_H_ 24 #define CORSIX_TH_TH_GFX_H_ 25 #include <map> 26 #include <string> 27 #include <vector> 28 29 #include "th.h" 30 #include "th_gfx_sdl.h" 31 32 class lua_persist_reader; 33 class lua_persist_writer; 34 35 enum class scaled_items { none, sprite_sheets, bitmaps, all }; 36 37 void clip_rect_intersection(clip_rect& rcClip, const clip_rect& rcIntersect); 38 39 //! Bitflags for drawing operations 40 enum draw_flags : uint32_t { 41 /** Sprite drawing flags **/ 42 /* Where possible, designed to be the same values used by TH data files */ 43 44 //! Draw with the left becoming the right and vice versa 45 thdf_flip_horizontal = 1 << 0, 46 //! Draw with the top becoming the bottom and vice versa 47 thdf_flip_vertical = 1 << 1, 48 //! Draw with 50% transparency 49 thdf_alpha_50 = 1 << 2, 50 //! Draw with 75% transparency 51 thdf_alpha_75 = 1 << 3, 52 //! Draw using a remapped palette 53 thdf_alt_palette = 1 << 4, 54 55 /** How to draw alternative palette in 32bpp. */ 56 /* A 3 bit field (bits 5,6,7), currently 2 bits used. */ 57 58 //! Lowest bit of the field. 59 thdf_alt32_start = 5, 60 //! Mask for the 32bpp alternative drawing values. 61 thdf_alt32_mask = 0x7 << thdf_alt32_start, 62 63 //! Draw the sprite with the normal palette (fallback option). 64 thdf_alt32_plain = 0 << thdf_alt32_start, 65 //! Draw the sprite in grey scale. 66 thdf_alt32_grey_scale = 1 << thdf_alt32_start, 67 //! Draw the sprite with red and blue colours swapped. 68 thdf_alt32_blue_red_swap = 2 << thdf_alt32_start, 69 70 /** Object attached to tile flags **/ 71 /* (should be set prior to attaching to a tile) */ 72 73 //! Attach to the early sprite list (right-to-left pass) 74 thdf_early_list = 1 << 10, 75 //! Keep this sprite at the bottom of the attached list 76 thdf_list_bottom = 1 << 11, 77 //! Hit-test using bounding-box precision rather than pixel-perfect 78 thdf_bound_box_hit_test = 1 << 12, 79 //! Apply a cropping operation prior to drawing 80 thdf_crop = 1 << 13, 81 }; 82 83 /** Helper structure with parameters to create a #render_target. */ 84 struct render_target_creation_params { 85 int width; ///< Expected width of the render target. 86 int height; ///< Expected height of the render target. 87 int bpp; ///< Expected colour depth of the render target. 88 bool fullscreen; ///< Run full-screen. 89 bool present_immediate; ///< Whether to present immediately to the user 90 ///< (else wait for Vsync). 91 bool direct_zoom; ///< Scale each texture when copying if true, otherwise 92 ///< render to intermediate texture and scale. 93 }; 94 95 /*! 96 Base class for a linked list of drawable objects. 97 Note that "object" is used as a generic term, not in specific reference to 98 game objects (though they are the most common thing in drawing lists). 99 */ 100 // TODO: Replace this struct with something cleaner 101 struct drawable : public link_list { drawabledrawable102 drawable() : link_list() { drawing_layer = 0; } 103 104 //! Draw the object at a specific point on a render target 105 /*! 106 Can also "draw" the object to the speakers, i.e. play sounds. 107 */ 108 void (*draw_fn)(drawable* pSelf, render_target* pCanvas, int iDestX, 109 int iDestY); 110 111 //! Perform a hit test against the object 112 /*! 113 Should return true if when the object is drawn at (iDestX, iDestY) on a 114 canvas, the point (iTestX, iTestY) is within / on the object. 115 */ 116 bool (*hit_test_fn)(drawable* pSelf, int iDestX, int iDestY, int iTestX, 117 int iTestY); 118 119 //! Drawing flags (zero or more list flags from #draw_flags). 120 uint32_t flags; 121 122 /** Returns true if instance is a multiple frame animation. 123 Should be overloaded in derived class. 124 */ 125 bool (*is_multiple_frame_animation_fn)(drawable* pSelf); 126 get_drawing_layerdrawable127 int get_drawing_layer() { return drawing_layer; } set_drawing_layerdrawable128 void set_drawing_layer(int layer) { drawing_layer = layer; } 129 130 private: 131 int drawing_layer; 132 }; 133 134 /*! 135 Utility class for decoding Theme Hospital "chunked" graphics files. 136 Generally used internally by sprite_sheet. 137 */ 138 class chunk_renderer { 139 public: 140 //! Initialise a renderer for a specific size result 141 /*! 142 @param width Pixel width of the resulting image 143 @param height Pixel height of the resulting image 144 @param buffer If nullptr, then a new buffer is created to render the 145 image onto. Otherwise, should be an array at least width*height in size. 146 Ownership of this pointer is assumed by the class - call takeData() 147 to take ownership back again. 148 */ 149 chunk_renderer(int width, int height, uint8_t* buffer = nullptr); 150 151 ~chunk_renderer(); 152 153 // TODO: Should be function, not method of chunk_renderer 154 //! Convert a stream of chunks into a raw bitmap 155 /*! 156 @param pData Stream data. 157 @param iDataLen Length of \a pData. 158 @param bComplex true if pData is a stream of "complex" chunks, false if 159 pData is a stream of "simple" chunks. Passing the wrong value will 160 usually result in a very visible wrong result. 161 162 Use getData() or takeData() to obtain the resulting bitmap. 163 */ 164 void decode_chunks(const uint8_t* pData, int iDataLen, bool bComplex); 165 166 //! Get the result buffer, and take ownership of it 167 /*! 168 This transfers ownership of the buffer to the caller. After calling, 169 the class will not have any buffer, and thus cannot be used for 170 anything. 171 */ 172 uint8_t* take_data(); 173 174 //! Get the result buffer get_data()175 inline const uint8_t* get_data() const { return data; } 176 177 //! Perform a "copy" chunk (normally called by decodeChunks) 178 void chunk_copy(int npixels, const uint8_t* in_data); 179 180 //! Perform a "fill" chunk (normally called by decodeChunks) 181 void chunk_fill(int npixels, uint8_t value); 182 183 //! Perform a "fill to end of line" chunk (normally called by decodeChunks) 184 void chunk_fill_to_end_of_line(uint8_t value); 185 186 //! Perform a "fill to end of file" chunk (normally called by decodeChunks) 187 void chunk_finish(uint8_t value); 188 189 private: is_done()190 inline bool is_done() { return ptr == end; } 191 inline void fix_n_pixels(int& npixels) const; 192 inline void increment_position(int npixels); 193 194 uint8_t *data, *ptr, *end; 195 int x, y, width, height; 196 bool skip_eol; 197 }; 198 199 //! Layer information (see animation_manager::draw_frame) 200 struct layers { 201 uint8_t layer_contents[13]; 202 }; 203 204 class memory_reader; 205 206 /** Key value for finding an animation. */ 207 struct animation_key { 208 std::string name; ///< Name of the animations. 209 int tile_size; ///< Size of a tile. 210 }; 211 212 //! Less-than operator for map-sorting. 213 /*! 214 @param oK First key value. 215 @param oL Second key value. 216 @return Whether \a oK should be before \a oL. 217 */ 218 inline bool operator<(const animation_key& oK, const animation_key& oL) { 219 if (oK.tile_size != oL.tile_size) return oK.tile_size < oL.tile_size; 220 return oK.name < oL.name; 221 } 222 223 /** 224 * Start frames of an animation, in each view direction. 225 * A negative number indicates there is no animation in that direction. 226 */ 227 struct animation_start_frames { 228 long north; ///< Animation start frame for the 'north' view. 229 long east; ///< Animation start frame for the 'east' view. 230 long south; ///< Animation start frame for the 'south' view. 231 long west; ///< Animation start frame for the 'west' view. 232 }; 233 234 /** Map holding the custom animations. */ 235 typedef std::map<animation_key, animation_start_frames> named_animations_map; 236 237 /** Insertion data structure. */ 238 typedef std::pair<animation_key, animation_start_frames> named_animation_pair; 239 240 //! Theme Hospital sprite animation manager 241 /*! 242 An animation manager takes a sprite sheet and four animation information 243 files, and uses them to draw animation frames and provide information about 244 the animations. 245 */ 246 class animation_manager { 247 public: 248 animation_manager(); 249 ~animation_manager(); 250 251 void set_sprite_sheet(sprite_sheet* pSpriteSheet); 252 253 //! Load original animations. 254 /*! 255 set_sprite_sheet() must be called before calling this. 256 @param pStartData Animation first frame indices (e.g. VSTART-1.ANI) 257 @param iStartDataLength Length of \a pStartData. 258 @param pFrameData Frame details (e.g. VFRA-1.ANI) 259 @param iFrameDataLength Length of \a pFrameData 260 @param pListData Element indices list (e.g. VLIST-1.ANI) 261 @param iListDataLength Length of \a pListData 262 @param pElementData Element details (e.g. VELE-1.ANI) 263 @param iElementDataLength Length of \a pElementData 264 @return Loading was successful. 265 */ 266 bool load_from_th_file(const uint8_t* pStartData, size_t iStartDataLength, 267 const uint8_t* pFrameData, size_t iFrameDataLength, 268 const uint8_t* pListData, size_t iListDataLength, 269 const uint8_t* pElementData, 270 size_t iElementDataLength); 271 272 //! Set the video target. 273 /*! 274 @param pCanvas Video surface to use. 275 */ 276 void set_canvas(render_target* pCanvas); 277 278 //! Load free animations. 279 /*! 280 @param pData Start of the loaded data. 281 @param iDataLength Length of the loaded data. 282 @return Loading was successful. 283 */ 284 bool load_custom_animations(const uint8_t* pData, size_t iDataLength); 285 286 //! Get the total number of animations 287 size_t get_animation_count() const; 288 289 //! Get the total number of animation frames 290 size_t get_frame_count() const; 291 292 //! Get the index of the first frame of an animation 293 size_t get_first_frame(size_t iAnimation) const; 294 295 //! Get the index of the frame after a given frame 296 /*! 297 To draw an animation frame by frame, call get_first_frame() to get the 298 index of the first frame, and then keep on calling get_next_frame() 299 using the most recent return value from get_next_frame() or 300 get_first_frame(). 301 */ 302 size_t get_next_frame(size_t iFrame) const; 303 304 //! Set the palette remap data for an animation 305 /*! 306 This sets the palette remap data for every single sprite used by the 307 given animation. If the animation (or any of its sprites) are drawn 308 using the thdf_alt_palette flag, then palette indices will be mapped to 309 new palette indices by the 256 byte array pMap. This is typically used 310 to draw things in different colours or in greyscale. 311 */ 312 void set_animation_alt_palette_map(size_t iAnimation, const uint8_t* pMap, 313 uint32_t iAlt32); 314 315 //! Draw an animation frame 316 /*! 317 @param pCanvas The render target to draw onto. 318 @param iFrame The frame index to draw (should be in range [0, 319 getFrameCount() - 1]) 320 @param oLayers Information to decide what to draw on each layer. 321 An animation is comprised of up to thirteen layers, numbered 0 322 through 12. Some animations will have different options for what to 323 render on each layer. For example, patient animations generally 324 have the different options on layer 1 as different clothes, so if 325 layer 1 is set to the value 0, they may have their default clothes, 326 and if set to the value 2 or 4 or 6, they may have other clothes. 327 Play with the AnimView tool for a better understanding of layers, 328 though note that while it can draw more than one option on each 329 layer, this class can only draw a single option for each layer. 330 @param iX The screen position to use as the animation X origin. 331 @param iY The screen position to use as the animation Y origin. 332 @param iFlags Zero or more THDrawFlags flags. 333 */ 334 void draw_frame(render_target* pCanvas, size_t iFrame, 335 const ::layers& oLayers, int iX, int iY, 336 uint32_t iFlags) const; 337 338 void get_frame_extent(size_t iFrame, const ::layers& oLayers, int* pMinX, 339 int* pMaxX, int* pMinY, int* pMaxY, 340 uint32_t iFlags) const; 341 size_t get_frame_sound(size_t iFrame); 342 343 bool hit_test(size_t iFrame, const ::layers& oLayers, int iX, int iY, 344 uint32_t iFlags, int iTestX, int iTestY) const; 345 346 bool set_frame_marker(size_t iFrame, int iX, int iY); 347 bool set_frame_secondary_marker(size_t iFrame, int iX, int iY); 348 bool get_frame_marker(size_t iFrame, int* pX, int* pY); 349 bool get_frame_secondary_marker(size_t iFrame, int* pX, int* pY); 350 351 //! Retrieve a custom animation by name and tile size. 352 /*! 353 @param sName Name of the animation. 354 @param iTilesize Tile size of the animation. 355 @return A set starting frames for the queried animation. 356 */ 357 const animation_start_frames& get_named_animations(const std::string& sName, 358 int iTilesize) const; 359 360 private: 361 #if CORSIX_TH_USE_PACK_PRAGMAS 362 #pragma pack(push) 363 #pragma pack(1) 364 #endif 365 // Animation information structure reinterpreted from Theme Hospital data. 366 struct th_animation_properties { 367 uint16_t first_frame; 368 // It could be that frame is a uint32_t rather than a uint16_t, which 369 // would resolve the following unknown (which seems to always be zero). 370 uint16_t unknown; 371 } CORSIX_TH_PACKED_FLAGS; 372 373 // Frame information structure reinterpreted from Theme Hospital data. 374 struct th_frame_properties { 375 uint32_t list_index; 376 // These fields have something to do with width and height, but it's 377 // not clear quite exactly how. 378 uint8_t width; 379 uint8_t height; 380 // If non-zero, index into sound.dat filetable. 381 uint8_t sound; 382 // Combination of zero or more fame_flags values 383 uint8_t flags; 384 uint16_t next; 385 } CORSIX_TH_PACKED_FLAGS; 386 387 // Structure reinterpreted from Theme Hospital data. 388 struct th_element_properties { 389 uint16_t table_position; 390 uint8_t offx; 391 uint8_t offy; 392 // High nibble: The layer which the element belongs to [0, 12] 393 // Low nibble: Zero or more draw_flags 394 uint8_t flags; 395 // The layer option / layer id 396 uint8_t layerid; 397 } CORSIX_TH_PACKED_FLAGS; 398 #if CORSIX_TH_USE_PACK_PRAGMAS 399 #pragma pack(pop) 400 #endif 401 402 struct frame { 403 size_t list_index; ///< First entry in #element_list (pointing to an 404 ///< element) for this frame. 405 size_t next_frame; ///< Number of the next frame. 406 unsigned int sound; ///< Sound to play, if non-zero. 407 unsigned int flags; ///< Flags of the frame. Bit 0=start of animation. 408 409 // Bounding rectangle is with all layers / options enabled - used as a 410 // quick test prior to a full pixel perfect test. 411 int bounding_left; ///< Left edge of the bounding rectangle of this 412 ///< frame. 413 int bounding_right; ///< Right edge of the bounding rectangle of this 414 ///< frame. 415 int bounding_top; ///< Top edge of the bounding rectangle of this 416 ///< frame. 417 int bounding_bottom; ///< Bottom edge of the bounding rectangle of this 418 ///< frame. 419 420 // Markers are used to know where humanoids are on an frame. The 421 // positions are pixels offsets from the centre of the frame's base 422 // tile to the centre of the humanoid's feet. 423 int marker_x; ///< X position of the first center of a humanoids feet. 424 int marker_y; ///< Y position of the first center of a humanoids feet. 425 int secondary_marker_x; ///< X position of the second center of a 426 ///< humanoids feet. 427 int secondary_marker_y; ///< Y position of the second center of a 428 ///< humanoids feet. 429 }; 430 431 struct element { 432 size_t sprite; ///< Sprite number of the sprite sheet to display. 433 uint32_t flags; ///< Flags of the sprite. 434 ///< bit 0=flip vertically, bit 1=flip horizontally, 435 ///< bit 2=draw 50% alpha, bit 3=draw 75% alpha. 436 int x; ///< X offset of the sprite. 437 int y; ///< Y offset of the sprite. 438 uint8_t layer; ///< Layer class (0..12). 439 uint8_t layer_id; ///< Value of the layer class to match. 440 441 sprite_sheet* element_sprite_sheet; ///< Sprite sheet to use for this 442 ///< element. 443 }; 444 445 std::vector<size_t> first_frames; ///< First frame number of an animation. 446 std::vector<frame> frames; ///< The loaded frames. 447 std::vector<uint16_t> element_list; ///< List of elements for a frame. 448 std::vector<element> elements; ///< Sprite Elements. 449 std::vector<sprite_sheet*> 450 custom_sheets; ///< Sprite sheets with custom graphics. 451 named_animations_map named_animations; ///< Collected named animations. 452 453 sprite_sheet* sheet; ///< Sprite sheet to use. 454 render_target* canvas; ///< Video surface to use. 455 456 size_t animation_count; ///< Number of animations. 457 size_t frame_count; ///< Number of frames. 458 size_t element_list_count; ///< Number of list elements. 459 size_t element_count; ///< Number of sprite elements. 460 461 //! Compute the bounding box of the frame. 462 /*! 463 @param oFrame Frame to inspect/set. 464 */ 465 void set_bounding_box(frame& oFrame); 466 467 //! Load sprite elements from the input. 468 /*! 469 @param [inout] input Data to read. 470 @param pSpriteSheet Sprite sheet to use. 471 @param iNumElements Number of elements to read. 472 @param [inout] iLoadedElements Number of loaded elements so far. 473 @param iElementStart Offset of the first element. 474 @param iElementCount Number of elements to load. 475 @return Index of the first loaded element in #elements. Negative value 476 means failure. 477 */ 478 size_t load_elements(memory_reader& input, sprite_sheet* pSpriteSheet, 479 size_t iNumElements, size_t& iLoadedElements, 480 size_t iElementStart, size_t iElementCount); 481 482 //! Construct a list element for every element, and a 0xFFFF at the end. 483 /*! 484 @param iFirstElement Index of the first element in #elements. 485 @param iNumElements Number of elements to add. 486 @param [inout] iLoadedListElements Number of created list elements so 487 far. 488 @param iListStart Offset of the first created list element. 489 @param iListCount Expected number of list elements to create. 490 @return Index of the list elements, or a negative value to indicate 491 failure. 492 */ 493 size_t make_list_elements(size_t iFirstElement, size_t iNumElements, 494 size_t& iLoadedListElements, size_t iListStart, 495 size_t iListCount); 496 497 //! Fix the flags of the first frame, and set the next frame of the last 498 //! frame back to the first frame. 499 /*! 500 @param iFirst First frame of the animation, or 0xFFFFFFFFu. 501 @param iLength Number of frames in the animation. 502 */ 503 void fix_next_frame(uint32_t iFirst, size_t iLength); 504 }; 505 506 struct map_tile; 507 class animation_base : public drawable { 508 public: 509 animation_base(); 510 511 void remove_from_tile(); 512 void attach_to_tile(map_tile* pMapNode, int layer); 513 get_flags()514 uint32_t get_flags() const { return flags; } get_x()515 int get_x() const { return x_relative_to_tile; } get_y()516 int get_y() const { return y_relative_to_tile; } 517 set_flags(uint32_t iFlags)518 void set_flags(uint32_t iFlags) { flags = iFlags; } set_position(int iX,int iY)519 void set_position(int iX, int iY) { 520 x_relative_to_tile = iX, y_relative_to_tile = iY; 521 } 522 void set_layer(int iLayer, int iId); set_layers_from(const animation_base * pSrc)523 void set_layers_from(const animation_base* pSrc) { layers = pSrc->layers; } 524 525 // bool isMultipleFrameAnimation() { return false;} 526 protected: 527 //! X position on tile (not tile x-index) 528 int x_relative_to_tile; 529 //! Y position on tile (not tile y-index) 530 int y_relative_to_tile; 531 532 ::layers layers; 533 }; 534 535 struct xy_diff { 536 //! Amount to change x per tick 537 int dx; 538 //! Amount to change y per tick 539 int dy; 540 }; 541 542 class animation : public animation_base { 543 public: 544 animation(); 545 546 void set_parent(animation* pParent); 547 548 void tick(); 549 void draw(render_target* pCanvas, int iDestX, int iDestY); 550 bool hit_test(int iDestX, int iDestY, int iTestX, int iTestY); 551 void draw_morph(render_target* pCanvas, int iDestX, int iDestY); 552 bool hit_test_morph(int iDestX, int iDestY, int iTestX, int iTestY); 553 void draw_child(render_target* pCanvas, int iDestX, int iDestY); 554 bool hit_test_child(int iDestX, int iDestY, int iTestX, int iTestY); 555 get_previous()556 link_list* get_previous() { return prev; } get_animation()557 size_t get_animation() const { return animation_index; } 558 bool get_marker(int* pX, int* pY); 559 bool get_secondary_marker(int* pX, int* pY); get_frame()560 size_t get_frame() const { return frame_index; } get_crop_column()561 int get_crop_column() const { return crop_column; } 562 563 void set_animation(animation_manager* pManager, size_t iAnimation); 564 void set_morph_target(animation* pMorphTarget, int iDurationFactor = 1); 565 void set_frame(size_t iFrame); 566 set_speed(int iX,int iY)567 void set_speed(int iX, int iY) { speed.dx = iX, speed.dy = iY; } set_crop_column(int iColumn)568 void set_crop_column(int iColumn) { crop_column = iColumn; } 569 570 void persist(lua_persist_writer* pWriter) const; 571 void depersist(lua_persist_reader* pReader); 572 get_animation_manager()573 animation_manager* get_animation_manager() { return manager; } 574 575 private: 576 animation_manager* manager; 577 animation* morph_target; 578 size_t animation_index; ///< Animation number. 579 size_t frame_index; ///< Frame number. 580 union { 581 xy_diff speed; 582 //! Some animations are tied to the marker of another animation and 583 //! hence have a parent rather than a speed. 584 animation* parent; 585 }; 586 587 size_t sound_to_play; 588 int crop_column; 589 }; 590 591 class sprite_render_list : public animation_base { 592 public: 593 sprite_render_list(); 594 ~sprite_render_list(); 595 596 void tick(); 597 void draw(render_target* pCanvas, int iDestX, int iDestY); 598 bool hit_test(int iDestX, int iDestY, int iTestX, int iTestY); 599 set_sheet(sprite_sheet * pSheet)600 void set_sheet(sprite_sheet* pSheet) { sheet = pSheet; } set_speed(int iX,int iY)601 void set_speed(int iX, int iY) { dx_per_tick = iX, dy_per_tick = iY; } 602 void set_lifetime(int iLifetime); 603 void append_sprite(size_t iSprite, int iX, int iY); is_dead()604 bool is_dead() const { return lifetime == 0; } 605 606 void persist(lua_persist_writer* pWriter) const; 607 void depersist(lua_persist_reader* pReader); 608 609 private: 610 struct sprite { 611 size_t index; 612 int x; 613 int y; 614 }; 615 616 sprite_sheet* sheet; 617 sprite* sprites; 618 int sprite_count; 619 int buffer_size; 620 621 //! Amount to change x per tick 622 int dx_per_tick; 623 //! Amount to change y per tick 624 int dy_per_tick; 625 //! Number of ticks until reports as dead (-1 = never dies) 626 int lifetime; 627 }; 628 629 #endif // CORSIX_TH_TH_GFX_H_ 630