Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Routines to cache merged textures.
  23.  *
  24.  */
  25.  
  26.  
  27. #include "gr.h"
  28. #include "dxxerror.h"
  29. #include "game.h"
  30. #include "textures.h"
  31. #include "rle.h"
  32. #include "timer.h"
  33. #include "piggy.h"
  34. #include "texmerge.h"
  35. #include "piggy.h"
  36.  
  37. #include "compiler-range_for.h"
  38. #include "partial_range.h"
  39.  
  40. #if DXX_USE_OGL
  41. #include "ogl_init.h"
  42. #endif
  43. #define MAX_NUM_CACHE_BITMAPS 10
  44.  
  45. //static grs_bitmap * cache_bitmaps[MAX_NUM_CACHE_BITMAPS];                    
  46.  
  47. namespace {
  48.  
  49. struct TEXTURE_CACHE {
  50.         grs_bitmap_ptr bitmap;
  51.         grs_bitmap * bottom_bmp;
  52.         grs_bitmap * top_bmp;
  53.         int             orient;
  54.         fix64           last_time_used;
  55. };
  56.  
  57. /* Helper classes merge_texture_0 through merge_texture_3 correspond to
  58.  * the four values of `orient` used by texmerge_get_cached_bitmap.
  59.  */
  60. struct merge_texture_0
  61. {
  62.         static size_t get_top_data_index(const unsigned wh, const unsigned y, const unsigned x)
  63.         {
  64.                 return wh * y + x;
  65.         }
  66. };
  67.  
  68. struct merge_texture_1
  69. {
  70.         static size_t get_top_data_index(const unsigned wh, const unsigned y, const unsigned x)
  71.         {
  72.                 return wh * x + ((wh - 1) - y);
  73.         }
  74. };
  75.  
  76. struct merge_texture_2
  77. {
  78.         static size_t get_top_data_index(const unsigned wh, const unsigned y, const unsigned x)
  79.         {
  80.                 return wh * ((wh - 1) - y) + ((wh - 1) - x);
  81.         }
  82. };
  83.  
  84. struct merge_texture_3
  85. {
  86.         static size_t get_top_data_index(const unsigned wh, const unsigned y, const unsigned x)
  87.         {
  88.                 return wh * ((wh - 1) - x) + y;
  89.         }
  90. };
  91.  
  92. /* For supertransparent colors, remap 254.
  93.  * For regular transparent colors, do nothing.
  94.  *
  95.  * In both cases, the caller remaps TRANSPARENCY_COLOR to the bottom
  96.  * bitmap.
  97.  */
  98. struct merge_transform_super_xparent
  99. {
  100.         static uint8_t transform_color(uint8_t c)
  101.         {
  102.                 return c == 254 ? TRANSPARENCY_COLOR : c;
  103.         }
  104. };
  105.  
  106. struct merge_transform_new
  107. {
  108.         static uint8_t transform_color(uint8_t c)
  109.         {
  110.                 return c;
  111.         }
  112. };
  113.  
  114. }
  115.  
  116. /* Run the transform for one texture merge case.  Different values of
  117.  * `orient` in texmerge_get_cached_bitmap lead to different types for
  118.  * `get_index`.
  119.  */
  120. template <typename texture_transform, typename get_index>
  121. static void merge_textures_case(const unsigned wh, const uint8_t *const top_data, const uint8_t *const bottom_data, uint8_t *dest_data)
  122. {
  123.         for (unsigned y = 0; y < wh; ++y)
  124.                 for (unsigned x = 0; x < wh; ++x)
  125.                 {
  126.                         const auto c = top_data[get_index::get_top_data_index(wh, y, x)];
  127.                         /* All merged textures support TRANSPARENCY_COLOR, so handle
  128.                          * it here.  Supertransparency is delegated down to
  129.                          * `texture_transform`, since not all textures want
  130.                          * supertransparency.
  131.                          */
  132.                         *dest_data++ = (c == TRANSPARENCY_COLOR)
  133.                                 ? bottom_data[wh * y + x]
  134.                                 : texture_transform::transform_color(c);
  135.                 }
  136. }
  137.  
  138. /* Dispatch a texture transformation based on the value of `orient`.
  139.  * The loops are duplicated in each case so that `orient` is not reread
  140.  * for each byte processed.
  141.  */
  142. template <typename texture_transform>
  143. static void merge_textures(unsigned orient, const grs_bitmap &expanded_bottom_bmp, const grs_bitmap &expanded_top_bmp, uint8_t *const dest_data)
  144. {
  145.         const auto &top_data = expanded_top_bmp.bm_data;
  146.         const auto &bottom_data = expanded_bottom_bmp.bm_data;
  147.         const auto wh = expanded_bottom_bmp.bm_w;
  148.         switch (orient)
  149.         {
  150.                 case 0:
  151.                         merge_textures_case<texture_transform, merge_texture_0>(wh, top_data, bottom_data, dest_data);
  152.                         break;
  153.                 case 1:
  154.                         merge_textures_case<texture_transform, merge_texture_1>(wh, top_data, bottom_data, dest_data);
  155.                         break;
  156.                 case 2:
  157.                         merge_textures_case<texture_transform, merge_texture_2>(wh, top_data, bottom_data, dest_data);
  158.                         break;
  159.                 case 3:
  160.                         merge_textures_case<texture_transform, merge_texture_3>(wh, top_data, bottom_data, dest_data);
  161.                         break;
  162.         }
  163. }
  164.  
  165. static std::array<TEXTURE_CACHE, MAX_NUM_CACHE_BITMAPS> Cache;
  166.  
  167. static int cache_hits = 0;
  168. static int cache_misses = 0;
  169.  
  170. //----------------------------------------------------------------------
  171.  
  172. int texmerge_init()
  173. {
  174.         range_for (auto &i, Cache)
  175.         {
  176.                 i.bitmap = NULL;
  177.                 i.last_time_used = -1;
  178.                 i.top_bmp = NULL;
  179.                 i.bottom_bmp = NULL;
  180.                 i.orient = -1;
  181.         }
  182.  
  183.         return 1;
  184. }
  185.  
  186. void texmerge_flush()
  187. {
  188.         range_for (auto &i, Cache)
  189.         {
  190.                 i.last_time_used = -1;
  191.                 i.top_bmp = NULL;
  192.                 i.bottom_bmp = NULL;
  193.                 i.orient = -1;
  194.         }
  195. }
  196.  
  197.  
  198. //-------------------------------------------------------------------------
  199. void texmerge_close()
  200. {
  201.         range_for (auto &i, Cache)
  202.         {
  203.                 i.bitmap.reset();
  204.         }
  205. }
  206.  
  207. //--unused-- int info_printed = 0;
  208.  
  209. grs_bitmap &texmerge_get_cached_bitmap(unsigned tmap_bottom, unsigned tmap_top)
  210. {
  211.         grs_bitmap *bitmap_top, *bitmap_bottom;
  212.         int orient;
  213.         int lowest_time_used;
  214.  
  215.         bitmap_top = &GameBitmaps[Textures[tmap_top&0x3FFF].index];
  216.         bitmap_bottom = &GameBitmaps[Textures[tmap_bottom].index];
  217.        
  218.         orient = ((tmap_top&0xC000)>>14) & 3;
  219.  
  220.         lowest_time_used = Cache[0].last_time_used;
  221.         auto least_recently_used = &Cache.front();
  222.         range_for (auto &i, Cache)
  223.         {
  224.                 if ( (i.last_time_used > -1) && (i.top_bmp==bitmap_top) && (i.bottom_bmp==bitmap_bottom) && (i.orient==orient ))        {
  225.                         cache_hits++;
  226.                         i.last_time_used = timer_query();
  227.                         return *i.bitmap.get();
  228.                 }      
  229.                 if ( i.last_time_used < lowest_time_used )      {
  230.                         lowest_time_used = i.last_time_used;
  231.                         least_recently_used = &i;
  232.                 }
  233.         }
  234.  
  235.         //---- Page out the LRU bitmap;
  236.         cache_misses++;
  237.  
  238.         // Make sure the bitmaps are paged in...
  239.  
  240.         PIGGY_PAGE_IN(Textures[tmap_top&0x3FFF]);
  241.         PIGGY_PAGE_IN(Textures[tmap_bottom]);
  242.         if (bitmap_bottom->bm_w != bitmap_bottom->bm_h || bitmap_top->bm_w != bitmap_top->bm_h)
  243.                 Error("Texture width != texture height!\nbottom tmap = %u; bottom bitmap = %u; bottom width = %u; bottom height = %u\ntop tmap = %u; top bitmap = %u; top width=%u; top height=%u", tmap_bottom, Textures[tmap_bottom].index, bitmap_bottom->bm_w, bitmap_bottom->bm_h, tmap_top, Textures[tmap_top & 0x3fff].index, bitmap_top->bm_w, bitmap_top->bm_h);
  244.         if (bitmap_bottom->bm_w != bitmap_top->bm_w || bitmap_bottom->bm_h != bitmap_top->bm_h)
  245.                 Error("Top and Bottom textures have different size!\nbottom tmap = %u; bottom bitmap = %u; bottom width = %u; bottom height = %u\ntop tmap = %u; top bitmap = %u; top width=%u; top height=%u", tmap_bottom, Textures[tmap_bottom].index, bitmap_bottom->bm_w, bitmap_bottom->bm_h, tmap_top, Textures[tmap_top & 0x3fff].index, bitmap_top->bm_w, bitmap_top->bm_h);
  246.  
  247.         least_recently_used->bitmap = gr_create_bitmap(bitmap_bottom->bm_w,  bitmap_bottom->bm_h);
  248. #if DXX_USE_OGL
  249.         ogl_freebmtexture(*least_recently_used->bitmap.get());
  250. #endif
  251.  
  252.         auto &expanded_top_bmp = *rle_expand_texture(*bitmap_top);
  253.         auto &expanded_bottom_bmp = *rle_expand_texture(*bitmap_bottom);
  254.         if (bitmap_top->get_flag_mask(BM_FLAG_SUPER_TRANSPARENT))
  255.         {
  256.                 merge_textures<merge_transform_super_xparent>(orient, expanded_bottom_bmp, expanded_top_bmp, least_recently_used->bitmap->get_bitmap_data());
  257.                 gr_set_bitmap_flags(*least_recently_used->bitmap.get(), BM_FLAG_TRANSPARENT);
  258. #if !DXX_USE_OGL
  259.                 least_recently_used->bitmap->avg_color = bitmap_top->avg_color;
  260. #endif
  261.         } else  {
  262.                 merge_textures<merge_transform_new>(orient, expanded_bottom_bmp, expanded_top_bmp, least_recently_used->bitmap->get_bitmap_data());
  263.                 least_recently_used->bitmap->set_flags(bitmap_bottom->get_flag_mask(~BM_FLAG_RLE));
  264. #if !DXX_USE_OGL
  265.                 least_recently_used->bitmap->avg_color = bitmap_bottom->avg_color;
  266. #endif
  267.         }
  268.  
  269.         least_recently_used->top_bmp = bitmap_top;
  270.         least_recently_used->bottom_bmp = bitmap_bottom;
  271.         least_recently_used->last_time_used = timer_query();
  272.         least_recently_used->orient = orient;
  273.         return *least_recently_used->bitmap.get();
  274. }
  275.