123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- if(NOT build_icons)
- # This entire subdirectory does nothing on platforms where we can't
- # build the icons in any case.
- return()
- endif()
- include(FindPerl)
- if(NOT PERL_EXECUTABLE)
- message(WARNING "Puzzle icons cannot be rebuilt (did not find Perl)")
- set(build_icons FALSE)
- return()
- endif()
- find_program(CONVERT convert)
- find_program(IDENTIFY identify)
- if(NOT CONVERT OR NOT IDENTIFY)
- message(WARNING "Puzzle icons cannot be rebuilt (did not find ImageMagick)")
- set(build_icons FALSE)
- return()
- endif()
- # For puzzles which have animated moves, it's nice to show the sample
- # image part way through the animation of a move. This setting will
- # cause a 'redo' action immediately after loading the save file,
- # causing the first undone move in the undo chain to be redone, and
- # then it will stop this far through the move animation to take the
- # screenshot.
- set(cube_redo 0.15)
- set(fifteen_redo 0.3)
- set(flip_redo 0.3)
- set(netslide_redo 0.3)
- set(sixteen_redo 0.3)
- set(twiddle_redo 0.3)
- # For many puzzles, we'd prefer that the icon zooms in on a couple of
- # squares of the playing area rather than trying to show the whole of
- # a game. These settings configure that. Each one indicates the
- # expected full size of the screenshot image, followed by the area we
- # want to crop to.
- #
- # (The expected full size is a safety precaution: if a puzzle changes
- # its default display size, then that won't match, and we'll get a
- # build error here rather than silently continuing to take the wrong
- # subrectangle of the resized puzzle display.)
- set(blackbox_crop 352x352 144x144+0+208)
- set(bridges_crop 264x264 107x107+157+157)
- set(dominosa_crop 304x272 152x152+152+0)
- set(fifteen_crop 240x240 120x120+0+120)
- set(filling_crop 256x256 133x133+14+78)
- set(flip_crop 288x288 145x145+120+72)
- set(galaxies_crop 288x288 165x165+0+0)
- set(guess_crop 263x420 178x178+75+17)
- set(inertia_crop 321x321 128x128+193+0)
- set(keen_crop 288x288 96x96+24+120)
- set(lightup_crop 256x256 112x112+144+0)
- set(loopy_crop 257x257 113x113+0+0)
- set(magnets_crop 264x232 96x96+36+100)
- set(mines_crop 240x240 110x110+130+130)
- set(mosaic_crop 288x288 97x97+142+78)
- set(net_crop 193x193 113x113+0+80)
- set(netslide_crop 289x289 144x144+0+0)
- set(palisade_crop 288x288 192x192+0+0)
- set(pattern_crop 384x384 223x223+0+0)
- set(pearl_crop 216x216 94x94+108+15)
- set(pegs_crop 263x263 147x147+116+0)
- set(range_crop 256x256 98x98+111+15)
- set(rect_crop 205x205 115x115+90+0)
- set(signpost_crop 240x240 98x98+23+23)
- set(singles_crop 224x224 98x98+15+15)
- set(sixteen_crop 288x288 144x144+144+144)
- set(slant_crop 321x321 160x160+160+160)
- set(solo_crop 481x481 145x145+24+24)
- set(tents_crop 320x320 165x165+142+0)
- set(towers_crop 300x300 102x102+151+6)
- set(tracks_crop 246x246 118x118+6+6)
- set(twiddle_crop 192x192 102x102+69+21)
- set(undead_crop 416x480 192x192+16+80)
- set(unequal_crop 208x208 104x104+104+104)
- set(untangle_crop 320x320 164x164+3+116)
- add_custom_target(icons)
- # All sizes of icon we make for any purpose.
- set(all_icon_sizes 128 96 88 64 48 44 32 24 16)
- # Sizes of icon we put into the Windows .ico files.
- set(win_icon_sizes 48 32 16)
- # Border thickness for each icon size.
- set(border_128 8)
- set(border_96 4)
- set(border_88 4)
- set(border_64 4)
- set(border_48 4)
- set(border_44 4)
- set(border_32 2)
- set(border_24 1)
- set(border_16 1)
- set(icon_srcdir ${CMAKE_SOURCE_DIR}/icons)
- set(icon_bindir ${CMAKE_BINARY_DIR}/icons)
- # We'll need to point $SGT_PUZZLES_DIR at an empty directory, to avoid
- # the icons reflecting the building user's display preferences.
- set(empty_config_dir ${CMAKE_BINARY_DIR}/icons/config)
- function(build_icon name)
- set(output_icon_files)
- # Compile the GTK puzzle binary without an icon, so that we can run
- # it to generate a screenshot to make the icon out of.
- add_executable(${NAME}-icon-maker ${NAME}.c
- ${CMAKE_SOURCE_DIR}/no-icon.c)
- target_link_libraries(${NAME}-icon-maker
- common ${platform_gui_libs} ${platform_libs})
- set_target_properties(${NAME}-icon-maker PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY ${icon_bindir})
- # Now run that binary to generate a screenshot of the puzzle in
- # play, which will be the base image we make everything else out
- # out.
- if(DEFINED ${name}_redo)
- set(redo_arg --redo ${${name}_redo})
- else()
- set(redo_arg)
- endif()
- add_custom_command(OUTPUT ${icon_bindir}/${name}-base.png
- COMMAND ${CMAKE_COMMAND} -E make_directory ${empty_config_dir}
- COMMAND ${CMAKE_COMMAND} -E env
- ASAN_OPTIONS=detect_leaks=0
- SGT_PUZZLES_DIR=${empty_config_dir}
- ${icon_bindir}/${name}-icon-maker
- ${redo_arg}
- --screenshot ${icon_bindir}/${name}-base.png
- --load ${icon_srcdir}/${name}.sav
- DEPENDS
- ${name}-icon-maker ${icon_srcdir}/${name}.sav)
- # Shrink it to a fixed-size square image for the web page,
- # trimming boring border parts of the original image in the
- # process. Done by square.pl.
- add_custom_command(OUTPUT ${icon_bindir}/${name}-web.png
- COMMAND ${PERL_EXECUTABLE} ${icon_srcdir}/square.pl
- ${CONVERT} 150 5
- ${icon_bindir}/${name}-base.png
- ${icon_bindir}/${name}-web.png
- DEPENDS
- ${icon_srcdir}/square.pl
- ${icon_bindir}/${name}-base.png)
- list(APPEND output_icon_files ${icon_bindir}/${name}-web.png)
- # Shrink differently to an oblong for the KaiStore marketing
- # banner. This is dimmed behind the name of the application, so put
- # it at a jaunty angle to avoid unfortunate interactions with the
- # text.
- add_custom_command(OUTPUT ${icon_bindir}/${name}-banner.jpg
- COMMAND ${CONVERT} ${icon_bindir}/${name}-base.png
- -crop 1:1+0+0 -rotate -10 +repage -shave 13% -resize 240 -crop x130+0+0
- ${icon_bindir}/${name}-banner.jpg
- DEPENDS ${icon_bindir}/${name}-base.png)
- list(APPEND output_icon_files ${icon_bindir}/${name}-banner.jpg)
- # Make the base image for all the icons, by cropping out the most
- # interesting part of the whole screenshot.
- add_custom_command(OUTPUT ${icon_bindir}/${name}-ibase.png
- COMMAND ${icon_srcdir}/crop.sh
- ${IDENTIFY} ${CONVERT}
- ${icon_bindir}/${name}-base.png
- ${icon_bindir}/${name}-ibase.png
- ${${name}_crop}
- DEPENDS
- ${icon_srcdir}/crop.sh
- ${icon_bindir}/${name}-base.png)
- # Coerce that base image down to colour depth of 4 bits, using the
- # fixed 16-colour Windows palette. We do this before shrinking the
- # image, because I've found that gives better results than just
- # doing it after.
- add_custom_command(OUTPUT ${icon_bindir}/${name}-ibase4.png
- COMMAND ${CONVERT}
- -colors 16
- +dither
- -set colorspace RGB
- -map ${icon_srcdir}/win16pal.xpm
- ${icon_bindir}/${name}-ibase.png
- ${icon_bindir}/${name}-ibase4.png
- DEPENDS
- ${icon_srcdir}/win16pal.xpm
- ${icon_bindir}/${name}-ibase.png)
- foreach(size ${all_icon_sizes})
- # Make a 24-bit icon image at each size, by shrinking the base
- # icon image.
- add_custom_command(OUTPUT ${icon_bindir}/${name}-${size}d24.png
- COMMAND ${PERL_EXECUTABLE} ${icon_srcdir}/square.pl
- ${CONVERT} ${size} ${border_${size}}
- ${icon_bindir}/${name}-ibase.png
- ${icon_bindir}/${name}-${size}d24.png
- DEPENDS
- ${icon_srcdir}/square.pl
- ${icon_bindir}/${name}-ibase.png)
- list(APPEND output_icon_files ${icon_bindir}/${name}-${size}d24.png)
- # And reduce the colour depth of that one to make an 8-bit
- # version.
- add_custom_command(OUTPUT ${icon_bindir}/${name}-${size}d8.png
- COMMAND ${CONVERT}
- -colors 256
- ${icon_bindir}/${name}-${size}d24.png
- ${icon_bindir}/${name}-${size}d8.png
- DEPENDS ${icon_bindir}/${name}-${size}d24.png)
- list(APPEND output_icon_files ${icon_bindir}/${name}-${size}d8.png)
- endforeach()
- foreach(size ${win_icon_sizes})
- # 4-bit icons are only needed for Windows. We make each one by
- # first shrinking the large 4-bit image we made above ...
- add_custom_command(OUTPUT ${icon_bindir}/${name}-${size}d4pre.png
- COMMAND ${PERL_EXECUTABLE} ${icon_srcdir}/square.pl
- ${CONVERT} ${size} ${border_${size}}
- ${icon_bindir}/${name}-ibase4.png
- ${icon_bindir}/${name}-${size}d4pre.png
- DEPENDS
- ${icon_srcdir}/square.pl
- ${icon_bindir}/${name}-ibase4.png)
- # ... and then re-coercing the output back to 16 colours, since
- # that shrink operation will have introduced intermediate colour
- # values again.
- add_custom_command(OUTPUT ${icon_bindir}/${name}-${size}d4.png
- COMMAND ${CONVERT}
- -colors 16
- +dither
- -set colorspace RGB
- -map ${icon_srcdir}/win16pal.xpm
- ${icon_bindir}/${name}-${size}d4pre.png
- ${icon_bindir}/${name}-${size}d4.png
- DEPENDS ${icon_bindir}/${name}-${size}d4pre.png)
- list(APPEND output_icon_files ${icon_bindir}/${name}-${size}d4.png)
- endforeach()
- # Make the Windows icon.
- set(icon_pl_args)
- set(icon_pl_deps)
- foreach(depth 24 8 4)
- list(APPEND icon_pl_args -${depth})
- foreach(size ${win_icon_sizes})
- list(APPEND icon_pl_args ${icon_bindir}/${name}-${size}d${depth}.png)
- list(APPEND icon_pl_deps ${icon_bindir}/${name}-${size}d${depth}.png)
- endforeach()
- endforeach()
- add_custom_command(OUTPUT ${icon_bindir}/${name}.ico
- COMMAND ${PERL_EXECUTABLE} ${icon_srcdir}/icon.pl
- --convert=${CONVERT}
- ${icon_pl_args} > ${icon_bindir}/${name}.ico
- DEPENDS
- ${icon_srcdir}/icon.pl
- ${icon_pl_deps})
- list(APPEND output_icon_files ${icon_bindir}/${name}.ico)
- # Make a C source file containing XPMs of all the 24-bit images.
- set(cicon_pl_infiles)
- foreach(size ${all_icon_sizes})
- list(APPEND cicon_pl_infiles ${icon_bindir}/${name}-${size}d24.png)
- endforeach()
- add_custom_command(OUTPUT ${icon_bindir}/${name}-icon.c
- COMMAND ${PERL_EXECUTABLE} ${icon_srcdir}/cicon.pl
- ${CONVERT} ${cicon_pl_infiles} > ${icon_bindir}/${name}-icon.c
- DEPENDS
- ${icon_srcdir}/cicon.pl
- ${cicon_pl_infiles})
- list(APPEND output_icon_files ${icon_bindir}/${name}-icon.c)
- # Make the KaiOS icons, which have rounded corners and shadows
- # https://developer.kaiostech.com/docs/design-guide/launcher-icon
- foreach(size 56 112)
- math(EXPR srciconsize "${size} * 44 / 56")
- math(EXPR borderwidth "(${size} - ${srciconsize}) / 2")
- math(EXPR cornerradius "${size} * 5 / 56")
- math(EXPR sizeminusone "${srciconsize} - 1")
- math(EXPR shadowspread "${size} * 4 / 56")
- math(EXPR shadowoffset "${size} * 2 / 56")
- add_custom_command(OUTPUT ${icon_bindir}/${name}-${size}kai.png
- COMMAND ${CONVERT}
- ${icon_bindir}/${name}-${srciconsize}d24.png
- -alpha Opaque
- "\\(" -size ${srciconsize}x${srciconsize} -depth 8 canvas:none
- -draw "roundRectangle 0,0,${sizeminusone},${sizeminusone},${cornerradius},${cornerradius}" "\\)"
- -compose dst-in -composite
- -compose over -bordercolor transparent -border ${borderwidth}
- "\\(" +clone -background black
- -shadow 30x${shadowspread}+0+${shadowoffset} "\\)"
- +swap -background none -flatten -crop '${size}x${size}+0+0!' -depth 8
- ${icon_bindir}/${name}-${size}kai.png
- DEPENDS ${icon_bindir}/${name}-${srciconsize}d24.png)
- list(APPEND output_icon_files ${icon_bindir}/${name}-${size}kai.png)
- endforeach()
- add_custom_target(${name}-icons DEPENDS ${output_icon_files})
- add_dependencies(icons ${name}-icons)
- endfunction()
|