From 6ce851fd71bf0fa456f62f3bf234fae98391bcd9 Mon Sep 17 00:00:00 2001 From: Rewryte <129854247+Rewryte@users.noreply.github.com> Date: Fri, 23 Jun 2023 22:21:52 +0800 Subject: [PATCH] 3D vision for isometric tilesets (#66383) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enable iso * reimplement height_3d * store zlevel_height in json * scaling fallback fog intensity * height_3d for fields and indicators * disable 3d memory for now memorized tile gets drawn on the wrong z-level * astyle * disable fog for legacy iso * Update compose.py * lint py * tweak ultica height measured from t_wall sprite * update fog calculations Co-Authored-By: Jianxiang Wang (王健翔) --------- Co-authored-by: Jianxiang Wang (王健翔) --- gfx/SmashButton_iso/tile_config.json | 2 +- gfx/Ultica_iso/tile_config.json | 2 +- src/cata_tiles.cpp | 71 +++++++++++++++++----------- src/cata_tiles.h | 7 +++ tools/gfx_tools/compose.py | 4 ++ 5 files changed, 57 insertions(+), 29 deletions(-) diff --git a/gfx/SmashButton_iso/tile_config.json b/gfx/SmashButton_iso/tile_config.json index b1b5a4353ee3d..98e134ea4d6fc 100644 --- a/gfx/SmashButton_iso/tile_config.json +++ b/gfx/SmashButton_iso/tile_config.json @@ -1,6 +1,6 @@ { "tile_info": [ - { "pixelscale": 2, "width": 16, "height": 20, "iso": true, "retract_dist_min": -1.0, "retract_dist_max": 1.0 } + { "pixelscale": 2, "width": 16, "height": 20, "zlevel_height": 10, "iso": true, "retract_dist_min": -1.0, "retract_dist_max": 1.0 } ], "tiles-new": [ { diff --git a/gfx/Ultica_iso/tile_config.json b/gfx/Ultica_iso/tile_config.json index 205d5ef74e220..380a89b7bbc4d 100644 --- a/gfx/Ultica_iso/tile_config.json +++ b/gfx/Ultica_iso/tile_config.json @@ -1,6 +1,6 @@ { "tile_info": [ - { "pixelscale": 1, "width": 48, "height": 24, "iso": true, "retract_dist_min": 2.5, "retract_dist_max": 6.0 } + { "pixelscale": 1, "width": 48, "height": 24, "zlevel_height": 96, "iso": true, "retract_dist_min": 2.5, "retract_dist_max": 6.0 } ], "tiles-new": [ { diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index 8bf40de8c16fe..a03f4b1e0195e 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -334,6 +334,11 @@ void cata_tiles::load_tileset( const std::string &tileset_id, const bool prechec tileset_ptr = cache.load_tileset( tileset_id, renderer, precheck, force, pump_events ); set_draw_scale( 16 ); + + // Precalculate fog transparency + // On isometric tilesets, fog intensity scales with zlevel_height in tile_config.json + fog_alpha = is_isometric() ? std::min( std::max( int( 255.0f - 255.0f * pow( 155.0f / 255.0f, + zlevel_height / 100.0f ) ), 40 ), 150 ) : 100; } void cata_tiles::reinit() @@ -598,6 +603,7 @@ void cata_tiles::set_draw_scale( int scale ) cata_assert( tileset_ptr ); tile_width = tileset_ptr->get_tile_width() * tileset_ptr->get_tile_pixelscale() * scale / 16; tile_height = tileset_ptr->get_tile_height() * tileset_ptr->get_tile_pixelscale() * scale / 16; + zlevel_height = tileset_ptr->get_zlevel_height(); tile_ratiox = ( static_cast( tile_width ) / static_cast( fontwidth ) ); tile_ratioy = ( static_cast( tile_height ) / static_cast( fontheight ) ); @@ -660,6 +666,7 @@ void tileset_cache::loader::load( const std::string &tileset_id, const bool prec for( const JsonObject curr_info : config.get_array( "tile_info" ) ) { ts.tile_height = curr_info.get_int( "height" ); ts.tile_width = curr_info.get_int( "width" ); + ts.zlevel_height = curr_info.get_int( "zlevel_height", 0 ); ts.tile_isometric = curr_info.get_bool( "iso", false ); ts.tile_pixelscale = curr_info.get_float( "pixelscale", 1.0f ); ts.prevent_occlusion_min_dist = curr_info.get_float( "retract_dist_min", -1.0f ); @@ -1360,7 +1367,7 @@ void cata_tiles::draw( const point &dest, const tripoint ¢er, int width, int std::map> draw_points; // Limit draw depth to vertical vision setting // Disable multi z-level display on isometric tilesets until height_3d issues resolved - const int max_draw_depth = is_isometric() ? 0 : fov_3d_z_range; + const int max_draw_depth = fov_3d_z_range; for( int row = min_row; row < max_row; row ++ ) { draw_points[row].reserve( max_col ); for( int col = min_col; col < max_col; col ++ ) { @@ -1611,7 +1618,6 @@ void cata_tiles::draw( const point &dest, const tripoint ¢er, int width, int } }; - //const int height_3d_mult = is_isometric() ? 10 : 0; if( max_draw_depth <= 0 ) { // Legacy draw mode for( int row = min_row; row < max_row; row ++ ) { @@ -1626,9 +1632,12 @@ void cata_tiles::draw( const point &dest, const tripoint ¢er, int width, int // Start drawing from the bottom-most z-level int cur_zlevel = -OVERMAP_DEPTH; do { - //int cur_height_3d = ( cur_zlevel - center.z ) * height_3d_mult; // For each row for( int row = min_row; row < max_row; row ++ ) { + // Set base height for each tile + for( tile_render_info &p : draw_points[row] ) { + p.height_3d = ( cur_zlevel - center.z ) * zlevel_height; + } // For each layer for( auto f : drawing_layers ) { // For each tile @@ -1640,8 +1649,19 @@ void cata_tiles::draw( const point &dest, const tripoint ¢er, int width, int } tripoint draw_loc = p.pos; draw_loc.z = cur_zlevel; - // Draw - ( this->*f )( draw_loc, p.ll, p.height_3d, p.invisible ); + if( f == &cata_tiles::draw_vpart_no_roof || f == &cata_tiles::draw_vpart_roof ) { + int temp_height_3d = p.height_3d; + // Reset height_3d to base when drawing vehicles + p.height_3d = ( cur_zlevel - center.z ) * zlevel_height; + // Draw + if( !( this->*f )( draw_loc, p.ll, p.height_3d, p.invisible ) ) { + // If no vpart drawn, revert height_3d changes + p.height_3d = temp_height_3d; + } + } else { + // Draw + ( this->*f )( draw_loc, p.ll, p.height_3d, p.invisible ); + } } } } @@ -2898,8 +2918,8 @@ bool cata_tiles::draw_terrain( const tripoint &p, const lit_level ll, int &heigh // first memorize the actual terrain const ter_id &t = here.ter( p ); const std::string &tname = t.id().str(); - // Non-isometric legacy mode does not draw fog sprites - if( !is_isometric() && fov_3d_z_range == 0 && tname == "t_open_air" ) { + // Legacy mode does not draw fog sprites + if( fov_3d_z_range == 0 && tname == "t_open_air" ) { return false; } if( t && !invisible[0] ) { @@ -2916,7 +2936,7 @@ bool cata_tiles::draw_terrain( const tripoint &p, const lit_level ll, int &heigh get_terrain_orientation( p, rotation, subtile, {}, invisible, rotate_group ); // do something to get other terrain orientation values } - if( here.check_seen_cache( p ) ) { + if( here.check_seen_cache( p ) && p.z == get_avatar().pos().z ) { get_avatar().memorize_terrain( here.getabs( p ), tname, subtile, rotation ); } // draw the actual terrain if there's no override @@ -2999,7 +3019,7 @@ bool cata_tiles::draw_furniture( const tripoint &p, const lit_level ll, int &hei const std::string &fname = f.id().str(); if( !( you.get_grab_type() == object_type::FURNITURE && p == you.pos() + you.grab_point ) - && here.check_seen_cache( p ) ) { + && here.check_seen_cache( p ) && p.z == get_avatar().pos().z ) { you.memorize_decoration( here.getabs( p ), fname, subtile, rotation ); } // draw the actual furniture if there's no override @@ -3086,7 +3106,7 @@ bool cata_tiles::draw_trap( const tripoint &p, const lit_level ll, int &height_3 int rotation = 0; get_tile_values( tr.loadid.to_i(), neighborhood, subtile, rotation, 0 ); const std::string trname = tr.loadid.id().str(); - if( here.check_seen_cache( p ) ) { + if( here.check_seen_cache( p ) && p.z == get_avatar().pos().z ) { you.memorize_decoration( here.getabs( p ), trname, subtile, rotation ); } // draw the actual trap if there's no override @@ -3144,7 +3164,7 @@ bool cata_tiles::draw_part_con( const tripoint &p, const lit_level ll, int &heig if( here.partial_con_at( tripoint_bub_ms( p ) ) != nullptr && !invisible[0] ) { avatar &you = get_avatar(); std::string const &trname = tr_unfinished_construction.str();; - if( here.check_seen_cache( p ) ) { + if( here.check_seen_cache( p ) && p.z == get_avatar().pos().z ) { you.memorize_decoration( here.getabs( p ), trname, 0, 0 ); } return draw_from_id_string( trname, TILE_CATEGORY::TRAP, empty_string, p, 0, @@ -3219,7 +3239,6 @@ bool cata_tiles::draw_field_or_item( const tripoint &p, const lit_level ll, int //get field intensity int intensity = fd_pr.second.get_field_intensity(); - int nullint = 0; bool has_drawn = false; @@ -3247,7 +3266,7 @@ bool cata_tiles::draw_field_or_item( const tripoint &p, const lit_level ll, int // if we have found info on the item go through and draw its stuff ret_draw_field = draw_from_id_string( sprite_to_draw, TILE_CATEGORY::FIELD, empty_string, p, - subtile, rotation, lit, nv, nullint, intensity, "", layer_var.offset ); + subtile, rotation, lit, nv, height_3d, intensity, "", layer_var.offset ); has_drawn = true; break; } @@ -3275,7 +3294,7 @@ bool cata_tiles::draw_field_or_item( const tripoint &p, const lit_level ll, int // if we have found info on the item go through and draw its stuff ret_draw_field = draw_from_id_string( sprite_to_draw, TILE_CATEGORY::FIELD, empty_string, p, - subtile, rotation, lit, nv, nullint, intensity, "", layer_var.offset ); + subtile, rotation, lit, nv, height_3d, intensity, "", layer_var.offset ); has_drawn = true; break; } @@ -3286,7 +3305,7 @@ bool cata_tiles::draw_field_or_item( const tripoint &p, const lit_level ll, int // draw the default sprite if( !has_drawn ) { ret_draw_field = draw_from_id_string( fld.id().str(), TILE_CATEGORY::FIELD, empty_string, - p, subtile, rotation, lit, nv, nullint, intensity ); + p, subtile, rotation, lit, nv, height_3d, intensity ); } } @@ -3317,9 +3336,8 @@ bool cata_tiles::draw_field_or_item( const tripoint &p, const lit_level ll, int //get field intensity int intensity = fld_overridden ? 0 : here.field_at( p ).displayed_intensity(); - int nullint = 0; ret_draw_field = draw_from_id_string( fld.id().str(), TILE_CATEGORY::FIELD, empty_string, - p, subtile, rotation, lit, nv, nullint, intensity ); + p, subtile, rotation, lit, nv, height_3d, intensity ); } } @@ -3520,14 +3538,15 @@ bool cata_tiles::draw_vpart( const tripoint &p, lit_level ll, int &height_3d, if( !veh.forward_velocity() && !veh.player_in_control( you ) && !( you.get_grab_type() == object_type::VEHICLE && veh.get_points().count( you.pos() + you.grab_point ) ) - && here.check_seen_cache( p ) ) { + && here.check_seen_cache( p ) && p.z == get_avatar().pos().z ) { you.memorize_decoration( here.getabs( p ), vd.get_tileset_id(), subtile, rotation ); } if( !overridden ) { - int height_3d_temp = 0; + int height_3d_temp = height_3d; const bool ret = draw_from_id_string( "vp_" + vd.id.str(), TILE_CATEGORY::VEHICLE_PART, empty_string, p, subtile, rotation, ll, nv_goggles_activated, height_3d_temp, 0, vd.variant.id ); + // Do not increment height_3d for non-roof vparts if( !roof ) { height_3d = height_3d_temp; } @@ -3549,7 +3568,7 @@ bool cata_tiles::draw_vpart( const tripoint &p, lit_level ll, int &height_3d, const std::string vpname = "vp_" + vp2.str(); // tile overrides are never memorized // tile overrides are always shown with full visibility - int height_3d_temp = 0; + int height_3d_temp = height_3d; const bool ret = draw_from_id_string( vpname, TILE_CATEGORY::VEHICLE_PART, empty_string, p, subtile, rotation, lit_level::LIT, false, height_3d_temp ); @@ -3566,7 +3585,7 @@ bool cata_tiles::draw_vpart( const tripoint &p, lit_level ll, int &height_3d, const memorized_tile &t = get_vpart_memory_at( p ); std::string_view tid = t.get_dec_id(); if( !tid.empty() ) { - int height_3d_temp = 0; + int height_3d_temp = height_3d; std::string_view tvar; const size_t variant_separator = tid.find( vehicles::variant_separator ); if( variant_separator != std::string::npos ) { @@ -3786,7 +3805,7 @@ bool cata_tiles::draw_zone_mark( const tripoint &p, lit_level ll, int &height_3d } bool cata_tiles::draw_zombie_revival_indicators( const tripoint &pos, const lit_level /*ll*/, - int &/*height_3d*/, const std::array &invisible ) + int &height_3d, const std::array &invisible ) { map &here = get_map(); if( tileset_ptr->find_tile_type( ZOMBIE_REVIVAL_INDICATOR ) && !invisible[0] && @@ -3795,7 +3814,7 @@ bool cata_tiles::draw_zombie_revival_indicators( const tripoint &pos, const lit_ for( item &i : here.i_at( pos ) ) { if( i.can_revive() ) { return draw_from_id_string( ZOMBIE_REVIVAL_INDICATOR, TILE_CATEGORY::NONE, - empty_string, pos, 0, 0, lit_level::LIT, false ); + empty_string, pos, 0, 0, lit_level::LIT, false, height_3d ); } } } @@ -3804,9 +3823,6 @@ bool cata_tiles::draw_zombie_revival_indicators( const tripoint &pos, const lit_ void cata_tiles::draw_zlevel_overlay( const tripoint &p, const lit_level ll, int &height_3d ) { - if( is_isometric() ) { - return; - } // Draws zlevel fog using geometry renderer // Slower than sprites so only use as fallback when sprite missing const point screen = player_to_screen( p.xy() ); @@ -3827,7 +3843,8 @@ void cata_tiles::draw_zlevel_overlay( const tripoint &p, const lit_level ll, int fog_color = curses_color_to_SDL( c_dark_gray ); } // Setting for fog transparency - fog_color.a = 100; + // On isometric tilesets, fog intensity scales with zlevel_height in tile_config.json + fog_color.a = fog_alpha; // Change blend mode for transparency to work // Disable after to avoid visual bugs diff --git a/src/cata_tiles.h b/src/cata_tiles.h index dccb287a98db4..453f70190b713 100644 --- a/src/cata_tiles.h +++ b/src/cata_tiles.h @@ -142,6 +142,7 @@ class tileset bool tile_isometric = false; int tile_width = 0; int tile_height = 0; + int zlevel_height = 0; float prevent_occlusion_min_dist = 0.0; float prevent_occlusion_max_dist = 0.0; @@ -186,6 +187,9 @@ class tileset int get_tile_height() const { return tile_height; } + int get_zlevel_height() const { + return zlevel_height; + } float get_tile_pixelscale() const { return tile_pixelscale; } @@ -694,6 +698,7 @@ class cata_tiles int tile_height = 0; int tile_width = 0; + int zlevel_height = 0; // The width and height of the area we can draw in, // measured in map coordinates, *not* in pixels. int screentile_width = 0; @@ -701,6 +706,8 @@ class cata_tiles float tile_ratiox = 0.0f; float tile_ratioy = 0.0f; + int fog_alpha = 0; + bool in_animation = false; bool do_draw_explosion = false; diff --git a/tools/gfx_tools/compose.py b/tools/gfx_tools/compose.py index 6a0840b27d3de..061faa78e8b15 100755 --- a/tools/gfx_tools/compose.py +++ b/tools/gfx_tools/compose.py @@ -259,6 +259,7 @@ def __init__( info_path = self.source_dir.joinpath('tile_info.json') self.sprite_width = 16 self.sprite_height = 16 + self.zlevel_height = 0 self.pixelscale = 1 self.iso = False self.retract_dist_min = -1.0 @@ -272,6 +273,8 @@ def __init__( self.info = json.load(file) self.sprite_width = self.info[0].get('width', self.sprite_width) self.sprite_height = self.info[0].get('height', self.sprite_height) + self.zlevel_height = self.info[0].get('zlevel_height', + self.zlevel_height) self.pixelscale = self.info[0].get('pixelscale', self.pixelscale) self.retract_dist_min = self.info[0].get('retract_dist_min', self.retract_dist_min) @@ -471,6 +474,7 @@ def create_tile_entries_for_unused( 'pixelscale': self.pixelscale, 'width': self.sprite_width, 'height': self.sprite_height, + 'zlevel_height': self.zlevel_height, 'iso': self.iso, 'retract_dist_min': self.retract_dist_min, 'retract_dist_max': self.retract_dist_max