Skip to content

Add proper icons for screen scrolling speed #6957

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
Draft
Binary file modified files/data/resurrection.h2d
Binary file not shown.
47 changes: 40 additions & 7 deletions src/engine/image_tool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@
#include <cassert>
#include <cstdint>
#include <cstring>
#include <functional>
#include <memory>
#include <ostream>
#include <string_view>
#include <vector>

#include <SDL_error.h>
#include <SDL_stdinc.h>
#include <SDL_version.h>

#if SDL_VERSION_ATLEAST( 2, 0, 0 )
Expand Down Expand Up @@ -166,15 +169,48 @@ namespace fheroes2

bool Load( const std::string & path, Image & image )
{
std::unique_ptr<SDL_Surface, std::function<void( SDL_Surface * )>> surface( nullptr, SDL_FreeSurface );

{
std::unique_ptr<SDL_Surface, std::function<void( SDL_Surface * )>> loadedSurface( nullptr, SDL_FreeSurface );

#if defined( ENABLE_PNG )
SDL_Surface * surface = IMG_Load( path.c_str() );
loadedSurface.reset( IMG_Load( path.c_str() ) );
#else
SDL_Surface * surface = SDL_LoadBMP( path.c_str() );
loadedSurface.reset( SDL_LoadBMP( path.c_str() ) );
#endif
if ( !loadedSurface ) {
return false;
}

#if SDL_VERSION_ATLEAST( 2, 0, 0 )
// SDL_PIXELFORMAT_BGRA32 and other RGBA color variants are only supported starting with SDL 2.0.5
#if !SDL_VERSION_ATLEAST( 2, 0, 5 )
#error Minimal supported SDL version is 2.0.5.
#endif

// Image loading functions can theoretically return SDL_Surface in any supported color format, so we will convert it to a specific format for subsequent
// processing
const std::unique_ptr<SDL_PixelFormat, std::function<void( SDL_PixelFormat * )>> pixelFormat( SDL_AllocFormat( SDL_PIXELFORMAT_BGRA32 ), SDL_FreeFormat );
if ( !pixelFormat ) {
return false;
}

surface.reset( SDL_ConvertSurface( loadedSurface.get(), pixelFormat.get(), 0 ) );
if ( !surface ) {
return false;
}

assert( SDL_MUSTLOCK( surface.get() ) == SDL_FALSE && surface->format->BytesPerPixel == 4 );
#else
// With SDL1, we just use the loaded SDL_Surface as is and hope for the best
surface = std::move( loadedSurface );
#endif
if ( surface == nullptr ) {
return false;
}

assert( surface && SDL_MUSTLOCK( surface.get() ) == SDL_FALSE );

// TODO: with SDL2 we can use specific color format of SDL_Surface, therefore, most of this code will not be needed
if ( surface->format->BytesPerPixel == 1 ) {
const SDL_Palette * palette = surface->format->palette;
assert( palette != nullptr );
Expand Down Expand Up @@ -282,12 +318,9 @@ namespace fheroes2
}
}
else {
SDL_FreeSurface( surface );
return false;
}

SDL_FreeSurface( surface );

return true;
}

Expand Down
9 changes: 9 additions & 0 deletions src/fheroes2/agg/agg_image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3369,6 +3369,15 @@ namespace fheroes2
h2d::readImage( "graphics_icon.image", _icnVsSprite[id][1] );
break;
}
case ICN::SCREEN_SCROLL_ICON: {
_icnVsSprite[id].resize( 4 );

h2d::readImage( "scroll_icon_0.image", _icnVsSprite[id][0] );
h2d::readImage( "scroll_icon_1.image", _icnVsSprite[id][1] );
h2d::readImage( "scroll_icon_2.image", _icnVsSprite[id][2] );
h2d::readImage( "scroll_icon_3.image", _icnVsSprite[id][3] );
break;
}
default:
break;
}
Expand Down
1 change: 1 addition & 0 deletions src/fheroes2/agg/icn.h
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,7 @@ namespace ICN
BUTTON_MAPSIZE_ALL,

GAME_OPTION_ICON,
SCREEN_SCROLL_ICON,

// IMPORTANT! Put any new entry just above this one.
LASTICN
Expand Down
17 changes: 6 additions & 11 deletions src/fheroes2/dialog/dialog_system_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,34 +123,29 @@ namespace

// Scrolling speed.
const int scrollSpeed = conf.ScrollSpeed();
int32_t scrollSpeedIconIcn = ICN::UNKNOWN;
const int32_t scrollSpeedIconIcn = ICN::SCREEN_SCROLL_ICON;
uint32_t scrollSpeedIconId = 0;
std::string scrollSpeedName;

if ( scrollSpeed == SCROLL_SPEED_NONE ) {
scrollSpeedName = _( "Off" );
scrollSpeedIconIcn = ICN::SPANEL;
scrollSpeedIconId = 9;
scrollSpeedIconId = 0;
}
else if ( scrollSpeed == SCROLL_SPEED_SLOW ) {
scrollSpeedName = _( "Slow" );
scrollSpeedIconIcn = ICN::CSPANEL;
scrollSpeedIconId = 0;
scrollSpeedIconId = 1;
}
else if ( scrollSpeed == SCROLL_SPEED_NORMAL ) {
scrollSpeedName = _( "Normal" );
scrollSpeedIconIcn = ICN::CSPANEL;
scrollSpeedIconId = 0;
scrollSpeedIconId = 1;
}
else if ( scrollSpeed == SCROLL_SPEED_FAST ) {
scrollSpeedName = _( "Fast" );
scrollSpeedIconIcn = ICN::CSPANEL;
scrollSpeedIconId = 1;
scrollSpeedIconId = 2;
}
else if ( scrollSpeed == SCROLL_SPEED_VERY_FAST ) {
scrollSpeedName = _( "Very Fast" );
scrollSpeedIconIcn = ICN::CSPANEL;
scrollSpeedIconId = 2;
scrollSpeedIconId = 3;
}

assert( scrollSpeedIconIcn != ICN::UNKNOWN );
Expand Down
119 changes: 90 additions & 29 deletions src/tools/h2dmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,22 @@

#include "h2d_file.h"
#include "image.h"
#include "image_palette.h"
#include "image_tool.h"
#include "serialize.h"
#include "system.h"
#include "tools.h"

namespace
{
constexpr size_t validPaletteSize = 768;
constexpr uint8_t imageBackground = 142;

bool isH2DImageItem( const std::string_view name )
{
return std::filesystem::path( name ).extension() == ".image";
}

bool isImageFile( const std::string_view fileName )
{
const std::string extension = StringLower( std::filesystem::path( fileName ).extension().string() );
Expand All @@ -55,18 +65,40 @@ namespace
std::string baseName = System::GetBasename( argv[0] );

std::cerr << baseName << " manages the contents of the specified H2D file(s)." << std::endl
<< "Syntax: " << baseName << " extract dst_dir input_file.h2d ..." << std::endl
<< " " << baseName << " combine target_file.h2d input_file ..." << std::endl;
<< "Syntax: " << baseName << " extract dst_dir palette_file.pal input_file.h2d ..." << std::endl
<< " " << baseName << " combine target_file.h2d palette_file.pal input_file ..." << std::endl;
}

bool loadPalette( const char * paletteFileName )
{
StreamFile paletteStream;
if ( !paletteStream.open( paletteFileName, "rb" ) ) {
std::cerr << "Cannot open file " << paletteFileName << std::endl;
return false;
}

const std::vector<uint8_t> palette = paletteStream.getRaw();
if ( palette.size() != validPaletteSize ) {
std::cerr << "Invalid palette size of " << palette.size() << " instead of " << validPaletteSize << std::endl;
return false;
}

fheroes2::setGamePalette( palette );
return true;
}

int extractH2D( const int argc, char ** argv )
{
assert( argc >= 4 );
assert( argc >= 5 );

const char * dstDir = argv[2];

if ( !loadPalette( argv[3] ) ) {
return EXIT_FAILURE;
}

std::vector<std::string> inputFileNames;
for ( int i = 3; i < argc; ++i ) {
for ( int i = 4; i < argc; ++i ) {
if ( System::isShellLevelGlobbingSupported() ) {
inputFileNames.emplace_back( argv[i] );
}
Expand Down Expand Up @@ -98,28 +130,53 @@ namespace
}

for ( const std::string & name : reader.getAllFileNames() ) {
static_assert( std::is_same_v<uint8_t, unsigned char>, "uint8_t is not the same as char, check the logic below" );

const std::vector<uint8_t> buf = reader.getFile( name );

const std::filesystem::path outputFilePath = prefixPath / std::filesystem::path( name );

std::ofstream outputStream( outputFilePath, std::ios_base::binary | std::ios_base::trunc );
if ( !outputStream ) {
std::cerr << "Cannot open file " << outputFilePath << std::endl;
return EXIT_FAILURE;
}

const auto streamSize = fheroes2::checkedCast<std::streamsize>( buf.size() );
if ( !streamSize ) {
std::cerr << inputFileName << ": item " << name << " is too large" << std::endl;
return EXIT_FAILURE;
// Image items need special processing
if ( isH2DImageItem( name ) ) {
fheroes2::Sprite image;

if ( !fheroes2::readImageFromH2D( reader, name, image ) ) {
std::cerr << inputFileName << ": item " << name << " contains an invalid image" << std::endl;
return EXIT_FAILURE;
}

std::string outputFileName = ( prefixPath / std::filesystem::path( name ).stem() ).string();

if ( fheroes2::isPNGFormatSupported() ) {
outputFileName += ".png";
}
else {
outputFileName += ".bmp";
}

if ( !fheroes2::Save( image, outputFileName, imageBackground ) ) {
std::cerr << inputFileName << ": error saving image " << name << std::endl;
return EXIT_FAILURE;
}
}

outputStream.write( reinterpret_cast<const char *>( buf.data() ), streamSize.value() );
if ( !outputStream ) {
std::cerr << "Error writing to file " << outputFilePath << std::endl;
return EXIT_FAILURE;
else {
static_assert( std::is_same_v<uint8_t, unsigned char>, "uint8_t is not the same as char, check the logic below" );

const std::vector<uint8_t> buf = reader.getFile( name );

const std::filesystem::path outputFilePath = prefixPath / std::filesystem::path( name );

std::ofstream outputStream( outputFilePath, std::ios_base::binary | std::ios_base::trunc );
if ( !outputStream ) {
std::cerr << "Cannot open file " << outputFilePath << std::endl;
return EXIT_FAILURE;
}

const auto streamSize = fheroes2::checkedCast<std::streamsize>( buf.size() );
if ( !streamSize ) {
std::cerr << inputFileName << ": item " << name << " is too large" << std::endl;
return EXIT_FAILURE;
}

outputStream.write( reinterpret_cast<const char *>( buf.data() ), streamSize.value() );
if ( !outputStream ) {
std::cerr << "Error writing to file " << outputFilePath << std::endl;
return EXIT_FAILURE;
}
}

++itemsExtracted;
Expand All @@ -133,12 +190,16 @@ namespace

int combineH2D( const int argc, char ** argv )
{
assert( argc >= 4 );
assert( argc >= 5 );

const char * h2dFileName = argv[2];

if ( !loadPalette( argv[3] ) ) {
return EXIT_FAILURE;
}

std::vector<std::string> inputFileNames;
for ( int i = 3; i < argc; ++i ) {
for ( int i = 4; i < argc; ++i ) {
if ( System::isShellLevelGlobbingSupported() ) {
inputFileNames.emplace_back( argv[i] );
}
Expand Down Expand Up @@ -257,11 +318,11 @@ namespace

int main( int argc, char ** argv )
{
if ( argc >= 4 && strcmp( argv[1], "extract" ) == 0 ) {
if ( argc >= 5 && strcmp( argv[1], "extract" ) == 0 ) {
return extractH2D( argc, argv );
}

if ( argc >= 4 && strcmp( argv[1], "combine" ) == 0 ) {
if ( argc >= 5 && strcmp( argv[1], "combine" ) == 0 ) {
return combineH2D( argc, argv );
}

Expand Down
17 changes: 10 additions & 7 deletions src/tools/pal2img.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ int main( int argc, char ** argv )
}

const char * paletteFileName = argv[1];
const char * outputImage = argv[2];
const char * outputFileName = argv[2];

{
StreamFile paletteStream;
Expand All @@ -65,25 +65,28 @@ int main( int argc, char ** argv )
fheroes2::setGamePalette( palette );
}

fheroes2::Image output( 256, 256 );
output.reset();
fheroes2::Image image( 256, 256 );
image.reset();
// We do not need to care about the transform layer.
output._disableTransformLayer();
image._disableTransformLayer();

// These color indexes are from PAL::GetCyclingPalette() method.
const std::set<uint8_t> cyclingColors{ 214, 215, 216, 217, 218, 219, 220, 221, 231, 232, 233, 234, 235, 238, 239, 240, 241 };

for ( uint8_t y = 0; y < 16; ++y ) {
for ( uint8_t x = 0; x < 16; ++x ) {
fheroes2::Fill( output, x * 16, y * 16, 16, 16, x + y * 16 );
fheroes2::Fill( image, x * 16, y * 16, 16, 16, x + y * 16 );

if ( cyclingColors.count( x + y * 16 ) > 0 ) {
fheroes2::Fill( output, x * 16, y * 16, 4, 4, 0 );
fheroes2::Fill( image, x * 16, y * 16, 4, 4, 0 );
}
}
}

fheroes2::Save( output, outputImage );
if ( !fheroes2::Save( image, outputFileName ) ) {
std::cerr << "Error writing to file " << outputFileName << std::endl;
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}