Changeset - r10248:82b5afcc36bb
[Not reviewed]
master
0 2 0
rubidium - 16 years ago 2008-10-17 17:14:09
rubidium@openttd.org
(svn r14479) -Add: initial (optional) support for handling bidirectional scripts and connecting Arabic characters.
2 files changed with 189 insertions and 14 deletions:
0 comments (0 inline, 0 general)
config.lib
Show inline comments
 

	
 
log() {
 
	if [ $1 = "1" ]; then echo "$2"; fi
 
	echo "$2" >> $config_log
 
}
 

	
 
set_default() {
 
	released_version=""
 

	
 
	ignore_extra_parameters="0"
 
	# We set all kinds of defaults for params. Later on the user can override
 
	# most of them; but if they don't, this default is used.
 
	build=""
 
	host=""
 
	cc_build=""
 
	cc_host=""
 
	cxx_build=""
 
	cxx_host=""
 
	windres=""
 
	strip=""
 
	lipo=""
 
	awk="awk"
 
	os="DETECT"
 
	endian="AUTO"
 
	cpu_type="DETECT"
 
	revision=""
 
	config_log="config.log"
 
	prefix_dir="/usr/local"
 
	binary_dir="games"
 
	data_dir="share/games/openttd"
 
	doc_dir="1"
 
	icon_dir="share/pixmaps"
 
	icon_theme_dir="1"
 
	personal_dir="1"
 
	shared_dir="1"
 
	install_dir="/"
 
	man_dir="1"
 
	menu_dir="1"
 
	menu_group="Game;"
 
	menu_name="OpenTTD"
 
	binary_name="openttd"
 
	enable_debug="0"
 
	enable_desync_debug="0"
 
	enable_profiling="0"
 
	enable_dedicated="0"
 
	enable_network="1"
 
	enable_static="1"
 
	enable_translator="0"
 
	enable_unicode="1"
 
	enable_assert="1"
 
	enable_strip="0"
 
	enable_universal="1"
 
	enable_osx_g5="0"
 
	enable_cocoa_quartz="1"
 
	enable_cocoa_quickdraw="1"
 
	with_osx_sysroot="1"
 
	with_application_bundle="1"
 
	with_menu_entry="1"
 
	with_sdl="1"
 
	with_cocoa="1"
 
	with_zlib="1"
 
	with_png="1"
 
	with_makedepend="1"
 
	with_direct_music="1"
 
	with_sort="1"
 
	with_iconv="1"
 
	with_midi=""
 
	with_midi_arg=""
 
	with_libtimidity="1"
 
	with_freetype="1"
 
	with_fontconfig="1"
 
	with_icu="1"
 
	with_psp_config="1"
 
	with_threads="1"
 
	with_distcc="1"
 
	with_ccache="1"
 

	
 
	save_params_array="
 
		build
 
		host
 
		cc_build
 
		cc_host
 
		cxx_build
 
		cxx_host
 
		windres
 
		strip
 
		lipo
 
		awk
 
		os
 
		endian
 
		cpu_type
 
		revision
 
		config_log
 
		prefix_dir
 
		binary_dir
 
		data_dir
 
		doc_dir
 
		icon_dir
 
		icon_theme_dir
 
		man_dir
 
		menu_dir
 
		personal_dir
 
		shared_dir
 
		install_dir
 
		menu_group
 
		menu_name
 
		binary_name
 
		enable_debug
 
		enable_desync_debug
 
		enable_profiling
 
		enable_dedicated
 
		enable_network
 
		enable_static
 
		enable_translator
 
		enable_unicode
 
		enable_assert
 
		enable_strip
 
		enable_universal
 
		enable_osx_g5
 
		enable_cocoa_quartz
 
		enable_cocoa_quickdraw
 
		with_osx_sysroot
 
		with_application_bundle
 
		with_sdl
 
		with_cocoa
 
		with_zlib
 
		with_png
 
		with_makedepend
 
		with_direct_music
 
		with_sort
 
		with_iconv
 
		with_midi
 
		with_midi_arg
 
		with_libtimidity
 
		with_freetype
 
		with_fontconfig
 
		with_icu
 
		with_psp_config
 
		with_threads
 
		with_distcc
 
		with_ccache
 
	CC CXX CFLAGS LDFLAGS"
 
}
 

	
 
detect_params() {
 
	# Walk over all params from the user and override any default settings if
 
	#  needed. This also handles any invalid option.
 
	for p in "$@"; do
 
		if [ -n "$prev_p" ]; then
 
			eval "$prev_p=\$p"
 
			prev_p=
 
			continue
 
		fi
 

	
 
		optarg=`expr "x$p" : 'x[^=]*=\(.*\)'`
 

	
 
		case "$p" in
 
			--help | -h)                  showhelp; exit 0;;
 

	
 
			--config-log)                 prev_p="config_log";;
 
			--config-log=*)               config_log="$optarg";;
 

	
 
			--build)                      prev_p="build";;
 
			--build=*)                    build="$optarg";;
 

	
 
			--host)                       prev_p="host";;
 
			--host=*)                     host="$optarg";;
 

	
 
			--os)                         prev_p="os";;
 
			--os=*)                       os="$optarg";;
 

	
 
			--cpu-type)                   prev_p="cpu_type";;
 
			--cpu-type=*)                 cpu_type="$optarg";;
 

	
 
			--revision=*)                 revision="$optarg";;
 

	
 
			--cc-build)                   prevp_p="cc_build";;
 
			--cc-build=*)                 cc_build="$optarg";;
 
			--cc-host)                    prevp_p="cc_host";;
 
			--cc-host=*)                  cc_host="$optarg";;
 
			--cxx-build)                  prevp_p="cxx_build";;
 
			--cxx-build=*)                cxx_build="$optarg";;
 
			--cxx-host)                   prevp_p="cxx_host";;
 
			--cxx-host=*)                 cxx_host="$optarg";;
 
			--windres)                    prevp_p="windres";;
 
			--windres=*)                  windres="$optarg";;
 
			--awk)                        prevp_p="awk";;
 
			--awk=*)                      awk="$optarg";;
 
			--strip)                      prevp_p="strip";;
 
			--strip=*)                    strip="$optarg";;
 
			--lipo)                       prevp_p="lipo";;
 
			--lipo=*)                     lipo="$optarg";;
 

	
 
			--endian)                     prev_p="endian";;
 
			--endian=*)                   endian="$optarg";;
 

	
 

	
 

	
 
			--prefix-dir)                 prevp_p="prefix-dir";;
 
			--prefix-dir=*)               prefix_dir="$optarg";;
 

	
 
			--binary-dir)                 prevp_p="binary-dir";;
 
			--binary-dir=*)               binary_dir="$optarg";;
 

	
 
			--data-dir)                   prevp_p="data-dir";;
 
			--data-dir=*)                 data_dir="$optarg";;
 

	
 
			--doc-dir)                    prevp_p="doc-dir";;
 
			--doc-dir=*)                  doc_dir="$optarg";;
 

	
 
			--icon-dir)                   prevp_p="icon-dir";;
 
			--icon-dir=*)                 icon_dir="$optarg";;
 

	
 
			--icon-theme-dir)             prevp_p="icon-theme-dir";;
 
			--icon-theme-dir=*)           icon_theme_dir="$optarg";;
 
			--without-icon-theme)         icon_theme_dir="";;
 

	
 
			--menu-dir)                   prevp_p="menu_dir";;
 
			--menu-dir=*)                 menu_dir="$optarg";;
 
			--without-menu-entry)         menu_dir="";;
 

	
 
			--menu-name)                  prevp_p="menu_name";;
 
			--menu-name=*)                menu_name="$optarg";;
 

	
 
			--binary-name)                prevp_p="binary_name";;
 
			--binary-name=*)              binary_name="$optarg";;
 

	
 
			--man-dir)                    prevp_p="man_dir";;
 
			--man-dir=*)                  man_dir="$optarg";;
 

	
 
			--personal-dir)               prevp_p="personal-dir";;
 
			--personal-dir=*)             personal_dir="$optarg";;
 
			--without-personal-dir)       personal_dir="";;
 

	
 
			--shared-dir)                 prevp_p="shared-dir";;
 
			--shared-dir=*)               shared_dir="$optarg";;
 
			--without-shared-dir)         shared_dir="";;
 

	
 
			--install-dir)                prevp_p="install-dir";;
 
			--install-dir=*)              install_dir="$optarg";;
 

	
 

	
 

	
 
			--menu-group)                 prevp_p="menu_group";;
 
			--menu-group=*)               menu_group="$optarg";;
 

	
 

	
 

	
 
			--enable-debug)               enable_debug="1";;
 
			--enable-debug=*)             enable_debug="$optarg";;
 
			--enable-desync-debug)        enable_desync_debug="1";;
 
			--enable-desync-debug=*)      enable_desync_debug="$optarg";;
 
			--enable-profiling)           enable_profiling="1";;
 
			--enable-profiling=*)         enable_profiling="$optarg";;
 
			--enable-dedicated)           enable_dedicated="1";;
 
			--enable-dedicated=*)         enable_dedicated="$optarg";;
 
			--enable-network=*)           enable_network="$optarg";;
 
			--disable-network)            enable_network="0";;
 
			--disable-static)             enable_static="0";;
 
			--enable-static)              enable_static="2";;
 
			--enable-static=*)            enable_static="$optarg";;
 
			--disable-translator)         enable_translator="0";;
 
			--enable-translator)          enable_translator="2";;
 
			--enable-translator=*)        enable_translator="$optarg";;
 
			--disable-assert)             enable_assert="0";;
 
			--enable-assert)              enable_assert="2";;
 
			--enable-assert=*)            enable_assert="$optarg";;
 
			--disable-strip)              enable_strip="0";;
 
			--enable-strip)               enable_strip="2";;
 
			--enable-strip=*)             enable_strip="$optarg";;
 
			--disable-universal)          enable_universal="0";;
 
			--enable-universal)           enable_universal="2";;
 
			--enable-universal=*)         enable_universal="$optarg";;
 
			--disable-osx-g5)             enable_osx_g5="0";;
 
			--enable-osx-g5)              enable_osx_g5="2";;
 
			--enable-osx-g5=*)            enable_osx_g5="$optarg";;
 
			--disable-unicode)            enable_unicode="0";;
 
			--enable-unicode)             enable_unicode="2";;
 
			--enable-unicode=*)           enable_unicode="$optarg";;
 

	
 
			--disable-cocoa-quartz)       enable_cocoa_quartz="0";;
 
			--enable-cocoa-quartz)        enable_cocoa_quartz="2";;
 
			--enable-cocoa-quartz=*)      enable_cocoa_quartz="$optarg";;
 
			--disable-cocoa-quickdraw)    enable_cocoa_quickdraw="0";;
 
			--enable-cocoa-quickdraw)     enable_cocoa_quickdraw="2";;
 
			--enable-cocoa-quickdraw=*)   enable_cocoa_quickdraw="$optarg";;
 

	
 
			--with-sdl)                   with_sdl="2";;
 
			--without-sdl)                with_sdl="0";;
 
			--with-sdl=*)                 with_sdl="$optarg";;
 

	
 
			--with-cocoa)                 with_cocoa="2";;
 
			--without-cocoa)              with_cocoa="0";;
 
			--with-cocoa=*)               with_cocoa="$optarg";;
 

	
 
			--with-zlib)                  with_zlib="2";;
 
			--without-zlib)               with_zlib="0";;
 
			--with-zlib=*)                with_zlib="$optarg";;
 

	
 
			--with-png)                   with_png="2";;
 
			--without-png)                with_png="0";;
 
			--with-png=*)                 with_png="$optarg";;
 
			--with-libpng)                with_png="2";;
 
			--without-libpng)             with_png="0";;
 
			--with-libpng=*)              with_png="$optarg";;
 

	
 
			--with-libtimidity)           with_libtimidity="2";;
 
			--without-libtimidity)        with_libtimidity="0";;
 
			--with-libtimidity=*)         with_libtimidity="$optarg";;
 

	
 
			--with-freetype)              with_freetype="2";;
 
			--without-freetype)           with_freetype="0";;
 
			--with-freetype=*)            with_freetype="$optarg";;
 
			--with-libfreetype)           with_freetype="2";;
 
			--without-libfreetype)        with_freetype="0";;
 
			--with-libfreetype=*)         with_freetype="$optarg";;
 

	
 
			--with-fontconfig)            with_fontconfig="2";;
 
			--without-fontconfig)         with_fontconfig="0";;
 
			--with-fontconfig=*)          with_fontconfig="$optarg";;
 
			--with-libfontconfig)         with_fontconfig="2";;
 
			--without-libfontconfig)      with_fontconfig="0";;
 
			--with-libfontconfig=*)       with_fontconfig="$optarg";;
 

	
 
			--with-icu)                   with_icu="2";;
 
			--without-icu)                with_icu="0";;
 
			--with-icu=*)                 with_icu="$optarg";;
 
			--with-libicu)                with_icu="2";;
 
			--without-libicu)             with_icu="0";;
 
			--with-libicu=*)              with_icu="$optarg";;
 

	
 
			--with-psp-config)            with_psp_config="2";;
 
			--without-psp-config)         with_psp_config="0";;
 
			--with-psp-config=*)          with_psp_config="$optarg";;
 

	
 
			--with-makedepend)            with_makedepend="2";;
 
			--without-makedepend)         with_makedepend="0";;
 
			--with-makedepend=*)          with_makedepend="$optarg";;
 

	
 
			--with-direct-music)          with_direct_music="2";;
 
			--without-direct-music)       with_direct_music="0";;
 
			--with-direct-music=*)        with_direct_music="$optarg";;
 

	
 
			--with-sort)                  with_sort="2";;
 
			--without-sort)               with_sort="0";;
 
			--with-sort=*)                with_sort="$optarg";;
 

	
 
			--with-iconv)                 with_iconv="2";;
 
			--without-iconv)              with_iconv="0";;
 
			--with-iconv=*)               with_iconv="$optarg";;
 

	
 
			--with-midi=*)                with_midi="$optarg";;
 
			--with-midi-arg=*)            with_midi_arg="$optarg";;
 

	
 
			--without-distcc)             with_distcc="0";;
 
			--with-distcc)                with_distcc="2";;
 
			--with-distcc=*)              with_distcc="$optarg";;
 

	
 
			--without-ccache)             with_ccache="0";;
 
			--with-ccache)                with_ccache="2";;
 
			--with-ccache=*)              with_ccache="$optarg";;
 

	
 
			--without-osx-sysroot)        with_osx_sysroot="0";;
 
			--with-osx-sysroot)           with_osx_sysroot="2";;
 
			--with-osx-sysroot=*)         with_osx_sysroot="$optarg";;
 

	
 
			--without-application-bundle) with_application_bundle="0";;
 
			--with-application-bundle)    with_application_bundle="1";;
 
			--with-application-bundle=*)  with_application_bundle="$optarg";;
 

	
 
			--without-threads)            with_threads="0";;
 
			--with-threads)               with_threads="1";;
 
			--with-threads=*)             with_threads="$optarg";;
 

	
 
			CC=* | --CC=*)                CC="$optarg";;
 
			CXX=* | --CXX=*)              CXX="$optarg";;
 
			CFLAGS=* | --CFLAGS=*)        CFLAGS="$optarg";;
 
			LDFLAGS=* | --LDFLAGS=*)      LDFLAGS="$optarg";;
 

	
 
			--ignore-extra-parameters)    ignore_extra_parameters="1";;
 

	
 
			--*)
 
				if [ "$ignore_extra_parameters" = "0" ]; then
 
					echo "Unknown option $p"
 
					exit 1
 
				else
 
					echo "Unknown option $p ignored"
 
				fi
 
				;;
 
		esac
 
	done
 

	
 
	if [ -n "$prev_p" ]; then
 
		echo "configure: error: missing argument to --$prev_p"
 
		exit 1
 
	fi
 

	
 
	# Clean the logfile
 
	echo "" > $config_log
 
}
 

	
 
save_params() {
 
	# Here we save all params, so we can later on do an exact redo of this
 
	#  configuration, without having the user to re-input stuff
 

	
 
	echo "Running configure with following options:" >> $config_log
 
	echo "" >> $config_log
 

	
 
	configure="$CONFIGURE_EXECUTABLE --ignore-extra-parameters"
 
	for p in $save_params_array; do
 
		eval "v=\"\$$p\""
 
		p=`echo "$p" | sed 's~_~-~g;s~\n~~g;s~ ~\\ ~g'`
 
		# Only save those params that aren't empty
 
		configure="$configure --$p=\"$v\""
 
	done
 

	
 
	echo "$configure" >> $config_log
 
	echo "$configure" > config.cache
 
	echo "" >> $config_log
 
}
 

	
 
check_params() {
 
	# Some params want to be in full uppercase, else they might not work as
 
	# expected.. fix that here
 

	
 
	endian=`echo $endian | tr '[a-z]' '[A-Z]'`
 
	os=`echo $os | tr '[a-z]' '[A-Z]'`
 
@@ -511,192 +520,193 @@ check_params() {
 
			log 1 "WARNING: use static at your own risk on this platform"
 

	
 
			sleep 5
 
		fi
 
	else
 
		log 1 "checking static... no"
 
	fi
 

	
 
	if [ "$enable_unicode" = "1" ]; then
 
		if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ]; then
 
			enable_unicode="2"
 
		else
 
			enable_unicode="0"
 
		fi
 
	fi
 

	
 
	if [ "$enable_unicode" != "0" ]; then
 
		log 1 "checking unicode... yes"
 
	else
 
		log 1 "checking unicode... no"
 
	fi
 

	
 
	# Show what we configured
 
	if [ "$enable_debug" = "0" ]; then
 
		log 1 "using debug level... no"
 
	elif [ "$enable_profiling" != "0" ]; then
 
		log 1 "using debug level... profiling (debug level $enable_debug)"
 
	else
 
		log 1 "using debug level... level $enable_debug"
 
	fi
 

	
 
	if [ "$enable_desync_debug" = "0" ]; then
 
		log 1 "using desync debug level... no"
 
	else
 
		log 1 "using desync debug level... level $enable_desync_debug"
 
		log 1 "WARNING: desync debug functions slow down the game considerably."
 
		log 1 "WARNING: use only when you are instructed to do so"
 
		log 1 "         or when you know what you are doing."
 

	
 
		sleep 5
 
	fi
 

	
 
	detect_sdl
 
	detect_cocoa
 

	
 
	if [ "$enable_dedicated" != "0" ]; then
 
		log 1 "checking GDI video driver... skipping"
 
		log 1 "checking dedicated... found"
 

	
 
		if [ "$enable_network" = "0" ]; then
 
			log 1 "WARNING: compiling a dedicated server without network is pointless"
 
			sleep 5
 
		fi
 
	else
 
		if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ]; then
 
			log 1 "checking GDI video driver... found"
 
		else
 
			log 1 "checking GDI video driver... not Windows, skipping"
 
		fi
 

	
 
		if [ -z "$sdl_config" ] && [ "$with_cocoa" = 0 ] && [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ] && [ "$os" != "WINCE" ]; then
 
			log 1 "WARNING: no video driver found, building dedicated only"
 
			enable_dedicated="1"
 
			sleep 1
 

	
 
			log 1 "checking dedicated... found"
 
		else
 
			log 1 "checking dedicated... not selected"
 
		fi
 
	fi
 

	
 
	if [ "$enable_network" != "0" ]; then
 
		log 1 "checking network... found"
 
	else
 
		log 1 "checking network... disabled"
 
	fi
 

	
 
	if [ "$enable_translator" != "0" ]; then
 
		log 1 "checking translator... debug"
 
		# -t shows TODO items, normally they are muted
 
		strgen_flags="-t"
 
	else
 
		log 1 "checking translator... no"
 
		strgen_flags=""
 
	fi
 

	
 
	if [ "$enable_assert" != "0" ]; then
 
		log 1 "checking assert... enabled"
 
	else
 
		log 1 "checking assert... disabled"
 
	fi
 

	
 
	detect_zlib
 
	detect_png
 
	detect_freetype
 
	detect_fontconfig
 
	detect_icu
 
	detect_pspconfig
 
	detect_libtimidity
 

	
 
	if [ "$with_direct_music" = "1" ] || [ "$with_direct_music" = "2" ]; then
 
		if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ]; then
 
			if [ "$with_direct_music" = "2" ]; then
 
				log 1 "configure: error: direct-music is only supported on Win32 targets"
 
				exit 1
 
			fi
 
			with_direct_music="0"
 

	
 
			log 1 "checking direct-music... not Windows, skipping"
 
		else
 
			check_direct_music
 
		fi
 
	fi
 

	
 
	detect_sort
 

	
 
	if [ "$os" = "OSX" ] && [ "$endian" = "AUTO" ]; then
 
		endian="PREPROCESSOR"
 
	fi
 

	
 
	log 1 "checking endianess... $endian"
 

	
 
	# Suppress language errors when there is a version defined, indicating a release
 
	#  It just isn't pretty if any release produces warnings in the languages.
 
	if [ -f "$ROOT_DIR/version" ]; then
 
		lang_suppress="yes"
 
		log 1 "suppress language errors... yes"
 
	else
 
		lang_suppress=""
 
		log 1 "suppress language errors... no"
 
	fi
 

	
 
	if [ "$enable_debug" = "0" ] && [ "$enable_profiling" = "0" ] && [ "$enable_strip" != "0" ]; then
 
		if [ "$os" = "MORPHOS" ]; then
 
			strip_arg="--strip-all --strip-unneeded --remove-section .comment"
 
		elif [ "$os" = "OSX" ]; then
 
			strip_arg=""
 
		elif [ "$os" = "OS2" ]; then
 
			strip_arg=""
 
			# OS2 uses strip via gcc, because it needs to be feed to emxbind
 
			LDFLAGS="$LDFLAGS -s"
 
		elif [ "$os" = "SUNOS" ]; then
 
			# The GNU strip does know -s, the non-GNU doesn't
 
			#  So try to detect it (in a bit of an ugly way)
 
			strip_arg="`$strip -s strip.test 2>/dev/null && echo \"-s\"`"
 
		else
 
			strip_arg="-s"
 
		fi
 

	
 
		log 1 "checking stripping... $strip $strip_arg"
 
	else
 
		strip=""
 
		log 1 "checking stripping... skipped"
 
	fi
 

	
 
	if [ "$with_distcc" = "0" ]; then
 
		log 1 "checking distcc... no"
 
	elif [ "$with_distcc" = "1" ]; then
 
		with_distcc="0"
 

	
 
		log 1 "checking distcc... no (only used when forced)"
 
	elif [ "$with_distcc" = "2" ]; then
 
		distcc="distcc"
 
	else
 
		distcc="$with_distcc"
 
	fi
 
	if [ "$with_distcc" != "0" ]; then
 
		res="`$distcc --version 2>/dev/null | head -n 1 | cut -b 1-6`"
 
		if [ "$res" != "distcc" ]; then
 
			distcc=""
 
			log 1 "checking distcc... no"
 
			if [ "$with_distcc" = "2" ]; then
 
				log 1 "configure: error: no distcc detected, but was forced to be used"
 
				exit 1
 
			fi
 
			if [ "$with_distcc" != "1" ]; then
 
				log 1 "configure: error: '$with_distcc' doesn't seem a distcc to me"
 
				exit 1
 
			fi
 
		fi
 

	
 
		log 1 "checking distcc... $distcc"
 
	fi
 

	
 
	if [ "$with_ccache" = "0" ]; then
 
		log 1 "checking ccache... no"
 
	elif [ "$with_ccache" = "1" ]; then
 
		with_ccache="0"
 

	
 
		log 1 "checking ccache... no (only used when forced)"
 
	elif [ "$with_ccache" = "2" ]; then
 
		ccache="ccache"
 
	else
 
@@ -1134,192 +1144,200 @@ make_cflags_and_ldflags() {
 
	if [ "$os" = "BEOS" ]; then
 
		LIBS="$LIBS -lmidi -lbe"
 
	fi
 

	
 
	# Most targets act like UNIX, just with some additions
 
	if [ "$os" = "BEOS" ] || [ "$os" = "OSX" ] || [ "$os" = "MORPHOS" ] || [ "$os" = "FREEBSD" ] || [ "$os" = "OPENBSD" ] || [ "$os" = "NETBSD" ] || [ "$os" = "HPUX" ] || [ "$os" = "SUNOS" ] || [ "$os" = "OS2" ]; then
 
		CFLAGS="$CFLAGS -DUNIX"
 
	fi
 
	# And others like Windows
 
	if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ]; then
 
		CFLAGS="$CFLAGS -DWIN"
 
	fi
 

	
 
	if [ -n "$sdl_config" ]; then
 
		CFLAGS="$CFLAGS -DWITH_SDL"
 
		CFLAGS="$CFLAGS `$sdl_config --cflags`"
 
		if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ] && [ "$os" != "WINCE" ]; then
 
			if [ "$enable_static" != "0" ]; then
 
				LIBS="$LIBS `$sdl_config --static-libs`"
 
			else
 
				LIBS="$LIBS `$sdl_config --libs`"
 
			fi
 
		fi
 
	fi
 

	
 
	if [ "$with_cocoa" != "0" ]; then
 
		CFLAGS="$CFLAGS -DWITH_COCOA"
 
		LIBS="$LIBS -F/System/Library/Frameworks -framework Cocoa -framework Carbon -framework AudioUnit"
 

	
 
		if [ "$enable_cocoa_quartz" != "0" ]; then
 
			CFLAGS="$CFLAGS -DENABLE_COCOA_QUARTZ"
 
		fi
 

	
 
		if [ "$enable_cocoa_quickdraw" != "0" ]; then
 
			CFLAGS="$CFLAGS -DENABLE_COCOA_QUICKDRAW"
 
		fi
 
	fi
 

	
 
	if [ "$with_zlib" != "0" ]; then
 
		if [ "$enable_static" != "0" ] && [ "$os" != "OSX" ]; then
 
			LIBS="$LIBS $zlib"
 
		else
 
			LIBS="$LIBS -lz"
 
		fi
 
		CFLAGS="$CFLAGS -DWITH_ZLIB"
 
	fi
 

	
 
	if [ -n "$png_config" ]; then
 
		CFLAGS="$CFLAGS -DWITH_PNG"
 
		CFLAGS="$CFLAGS `$png_config --cppflags --I_opts | tr '\n\r' '  '`"
 

	
 
		# The extra flags are unneeded for latest libpng-config, but some versions are so broken...
 
		if [ "$enable_static" != "0" ]; then
 
			if [ "$os" = "OSX" ]; then
 
				LIBS="$LIBS `$png_config --prefix`/lib/libpng.a"
 
			else
 
				LIBS="$LIBS `$png_config --static --ldflags | tr '\n\r' '  '`"
 
			fi
 
		else
 
			LIBS="$LIBS `$png_config --ldflags | tr '\n\r' '  '`"
 
		fi
 
	fi
 

	
 
	if [ -n "$fontconfig_config" ]; then
 
		CFLAGS="$CFLAGS -DWITH_FONTCONFIG"
 
		CFLAGS="$CFLAGS `$fontconfig_config --cflags | tr '\n\r' '  '`"
 

	
 
		if [ "$enable_static" != "0" ]; then
 
			if [ "$os" = "OSX" ]; then
 
				# fontconfig_config goes via pkg-config on all systems, which doesn't know --prefix
 
				# Also, despite the reason we link to the .a file ourself (because we can't use -static), we do need to ask pkg-config about possible other deps
 
				LIBS="$LIBS `$fontconfig_config --variable=prefix`/lib/libfontconfig.a `$fontconfig_config --libs --static | sed s~-lfontconfig~~`"
 
			else
 
				LIBS="$LIBS `$fontconfig_config --libs --static | tr '\n\r' '  '`"
 
			fi
 
		else
 
			LIBS="$LIBS `$fontconfig_config --libs | tr '\n\r' '  '`"
 
		fi
 
	fi
 

	
 
	if [ -n "$freetype_config" ]; then
 
		CFLAGS="$CFLAGS -DWITH_FREETYPE"
 
		CFLAGS="$CFLAGS `$freetype_config --cflags | tr '\n\r' '  '`"
 

	
 
		if [ "$enable_static" != "0" ]; then
 
			if [ "$os" = "OSX" ]; then
 
				LIBS="$LIBS `$freetype_config --prefix`/lib/libfreetype.a"
 
			else
 
				# Is it possible to do static with freetype, if so: how?
 
				LIBS="$LIBS `$freetype_config --libs | tr '\n\r' '  '`"
 
			fi
 
		else
 
			LIBS="$LIBS `$freetype_config --libs | tr '\n\r' '  '`"
 
		fi
 
	fi
 

	
 
	if [ -n "$icu_config" ]; then
 
		CFLAGS="$CFLAGS -DWITH_ICU"
 
		CFLAGS="$CFLAGS `$icu_config --cppflags | tr '\n\r' '  '`"
 

	
 
		LIBS="$LIBS `$icu_config --ldflags-libsonly | tr '\n\r' '  '`"
 
	fi
 

	
 

	
 
	if [ "$with_direct_music" != "0" ]; then
 
		CFLAGS="$CFLAGS -DWIN32_ENABLE_DIRECTMUSIC_SUPPORT"
 
		# GCC 4.0+ doesn't like the DirectX includes (gives tons of
 
		#  warnings on it we won't be able to fix). For now just
 
		#  suppress those warnings.
 
		if [ $cc_version -ge 40 ]; then
 
			CFLAGS="$CFLAGS -Wno-non-virtual-dtor"
 
		fi
 
	fi
 

	
 
	if [ -n "$libtimidity" ]; then
 
		if [ "$enable_static" != "0" ]; then
 
			LIBS="$LIBS $libtimidity"
 
		else
 
			LIBS="$LIBS -ltimidity"
 
		fi
 
		CFLAGS="$CFLAGS -DLIBTIMIDITY"
 
	fi
 

	
 
	if [ "$with_iconv" != "0" ]; then
 
		CFLAGS="$CFLAGS -DWITH_ICONV"
 
		LIBS="$LIBS -liconv"
 
		if [ "$with_iconv" != "2" ]; then
 
			CFLAGS="$CFLAGS -I$with_iconv/include"
 
			LIBS="$LIBS -L$with_iconv/lib"
 
		fi
 

	
 
		if [ "$have_broken_iconv" != "no" ]; then
 
			CFLAGS="$CFLAGS -DHAVE_BROKEN_ICONV"
 
		fi
 
	fi
 

	
 
	if [ -n "$with_midi" ]; then
 
		CFLAGS="$CFLAGS -DEXTERNAL_PLAYER=\\\\\"$with_midi\\\\\""
 
	fi
 
	if [ -n "$with_midi_arg" ]; then
 
		CFLAGS="$CFLAGS -DMIDI_ARG=\\\\\"$with_midi_arg\\\\\""
 
	fi
 

	
 
	if [ "$enable_dedicated" != "0" ]; then
 
		CFLAGS="$CFLAGS -DDEDICATED"
 
	fi
 

	
 
	if [ "$enable_unicode" != "0" ]; then
 
		CFLAGS="$CFLAGS -DUNICODE -D_UNICODE"
 
	fi
 

	
 
	if [ "$enable_network" != "0" ]; then
 
		CFLAGS="$CFLAGS -DENABLE_NETWORK"
 

	
 
		if [ "$os" = "BEOS" ]; then
 
			LDFLAGS="$LDFLAGS -lbind -lsocket"
 
		fi
 

	
 
		if [ "$os" = "SUNOS" ]; then
 
			LDFLAGS="$LDFLAGS -lnsl -lsocket"
 
		fi
 
	fi
 

	
 
	if [ "$enable_static" != "0" ]; then
 
		# OSX can't handle -static in LDFLAGS
 
		if [ "$os" != "OSX" ]; then
 
			LDFLAGS="$LDFLAGS -static"
 
		fi
 
	fi
 

	
 
	if [ "$enable_assert" = "0" ]; then
 
		CFLAGS="$CFLAGS -DNDEBUG"
 
	fi
 

	
 
	if [ "$enable_desync_debug" = "1" ]; then
 
		CFLAGS="$CFLAGS -DDEBUG_DUMP_COMMANDS"
 
	fi
 
	if [ "$enable_desync_debug" = "2" ]; then
 
		CFLAGS="$CFLAGS -DRANDOM_DEBUG"
 
	fi
 

	
 
	if [ "$enable_osx_g5" != "0" ]; then
 
		CFLAGS="$CFLAGS -mtune=970 -mcpu=970 -mpowerpc-gpopt"
 
	fi
 

	
 
	if [ -n "$personal_dir" ]; then
 
		CFLAGS="$CFLAGS -DWITH_PERSONAL_DIR -DPERSONAL_DIR=\\\\\"$personal_dir\\\\\""
 
	fi
 

	
 
	if [ -n "$shared_dir" ]; then
 
		CFLAGS="$CFLAGS -DWITH_SHARED_DIR -DSHARED_DIR=\\\\\"$shared_dir\\\\\""
 
	fi
 

	
 
	CFLAGS="$CFLAGS -DGLOBAL_DATA_DIR=\\\\\"$prefix_dir/$data_dir\\\\\""
 

	
 
	log 1 "using CFLAGS... $CFLAGS $CC_CFLAGS"
 
	log 1 "using LDFLAGS... $LIBS $LDFLAGS"
 

	
 
	# Makedepend doesn't like something like: -isysroot /OSX/blabla
 
	#  so convert it to: -isysroot -OSX/blabla. makedepend just ignores
 
@@ -1967,192 +1985,235 @@ detect_png() {
 
	log 1 "checking libpng... found"
 
}
 

	
 
detect_freetype() {
 
	# 0 means no, 1 is auto-detect, 2 is force
 
	if [ "$with_freetype" = "0" ]; then
 
		log 1 "checking libfreetype... disabled"
 

	
 
		freetype_config=""
 
		return 0
 
	fi
 

	
 
	if [ "$with_zlib" = "0" ] || [ "$zlib" = "" ]; then
 
		log 1 "configure: error: libfreetype depends on zlib, which couldn't be found / was disabled"
 
		log 1 "configure: error: please supply --with-zlib, with a valid zlib location"
 
		exit 1
 
	fi
 

	
 
	if [ "$with_freetype" = "1" ] || [ "$with_freetype" = "" ] || [ "$with_freetype" = "2" ]; then
 
		freetype_config="freetype-config"
 
	else
 
		freetype_config="$with_freetype"
 
	fi
 

	
 
	version=`$freetype_config --version 2>/dev/null`
 
	ret=$?
 
	log 2 "executing freetype_config --version"
 
	log 2 "  returned $version"
 
	log 2 "  exit code $ret"
 

	
 
	if [ -z "$version" ] || [ "$ret" != "0" ]; then
 
		log 1 "checking libfreetype... not found"
 

	
 
		# It was forced, so it should be found.
 
		if [ "$with_freetype" != "1" ]; then
 
			log 1 "configure: error: freetype-config couldn't be found"
 
			log 1 "configure: error: you supplied '$with_freetype', but it seems invalid"
 
			exit 1
 
		fi
 

	
 
		freetype_config=""
 
		return 0
 
	fi
 

	
 
	log 1 "checking libfreetype... found"
 
}
 

	
 
detect_fontconfig() {
 
	# 0 means no, 1 is auto-detect, 2 is force
 
	if [ "$with_fontconfig" = "0" ]; then
 
		log 1 "checking libfontconfig... disabled"
 

	
 
		fontconfig_config=""
 
		return 0
 
	fi
 

	
 
	if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ]; then
 
		log 1 "checking libfontconfig... WIN32, skipping"
 
		fontconfig_config=""
 
		return 0
 
	fi
 

	
 
	if [ "$with_fontconfig" = "1" ] || [ "$with_fontconfig" = "" ] || [ "$with_fontconfig" = "2" ]; then
 
		fontconfig_config="pkg-config fontconfig"
 
	else
 
		fontconfig_config="$with_fontconfig"
 
	fi
 

	
 
	version=`$fontconfig_config --modversion 2>/dev/null`
 
	ret=$?
 
	shortversion=`echo $version | cut -c 1,3`
 
	log 2 "executing $fontconfig_config --modversion"
 
	log 2 "  returned $version"
 
	log 2 "  exit code $ret"
 

	
 
	if [ -z "$version" ] || [ "$ret" != "0" ] || [ "$shortversion" -le "22" ]; then
 
		if [ -n "$shortversion" ] && [ "$shortversion" -le "22" ]; then
 
			log 1 "checking libfontconfig... needs at least version 2.3.0, fontconfig NOT enabled"
 
		else
 
			log 1 "checking libfontconfig... not found"
 
		fi
 

	
 
		# It was forced, so it should be found.
 
		if [ "$with_fontconfig" != "1" ]; then
 
			log 1 "configure: error: fontconfig-config couldn't be found"
 
			log 1 "configure: error: you supplied '$with_fontconfig', but it seems invalid"
 
			exit 1
 
		fi
 

	
 
		fontconfig_config=""
 
		return 0
 
	fi
 

	
 
	log 1 "checking libfontconfig... found"
 
}
 

	
 
detect_icu() {
 
	# 0 means no, 1 is auto-detect, 2 is force
 
	if [ "$with_icu" = "0" ]; then
 
		log 1 "checking libicu... disabled"
 

	
 
		icu_config=""
 
		return 0
 
	fi
 

	
 
	if [ "$with_icu" = "1" ] || [ "$with_icu" = "" ] || [ "$with_icu" = "2" ]; then
 
		icu_config="icu-config"
 
	else
 
		icu_config="$with_icu"
 
	fi
 

	
 
	version=`$icu_config --version 2>/dev/null`
 
	ret=$?
 
	shortversion=`echo $version | cut -c 1,3`
 
	log 2 "executing $icu_config --version"
 
	log 2 "  returned $version"
 
	log 2 "  exit code $ret"
 

	
 
	if [ -z "$version" ] || [ "$ret" != "0" ] || [ "$shortversion" -lt "20" ]; then
 
		if [ -n "$shortversion" ] && [ "$shortversion" -lt "20" ]; then
 
			log 1 "checking libicu... needs at least version 2.0.0, icu NOT enabled"
 
		else
 
			log 1 "checking libicu... not found"
 
		fi
 

	
 
		# It was forced, so it should be found.
 
		if [ "$with_icu" != "1" ]; then
 
			log 1 "configure: error: icu-config couldn't be found"
 
			log 1 "configure: error: you supplied '$with_icuconfig', but it seems invalid"
 
			exit 1
 
		fi
 

	
 
		icu_config=""
 
		return 0
 
	fi
 

	
 
	log 1 "checking libicu... found"
 
}
 

	
 
detect_pspconfig() {
 
	# 0 means no, 1 is auto-detect, 2 is force
 
	if [ "$with_psp_config" = "0" ]; then
 
		log 1 "checking psp-config... disabled"
 

	
 
		psp_config=""
 
		return 0
 
	fi
 

	
 
	if [ "$with_psp_config" = "1" ] && [ "$os" != "PSP" ]; then
 
		log 1 "checking psp-config... not PSP, skipping"
 

	
 
		psp_config="";
 
		return 0
 
	fi
 

	
 
	if [ "$os" != "PSP" ]; then
 
		log 1 "checking psp-config... not PSP"
 

	
 
		log 1 "configure: error: psp-config is only supported for PSP"
 
		exit 1
 
	fi
 

	
 
	if [ "$with_psp_config" = "1" ] || [ "$with_psp_config" = "" ] || [ "$with_psp_config" = "2" ]; then
 
		psp_config="psp-config"
 
	else
 
		psp_config="$with_psp_config"
 
	fi
 

	
 
	version=`$psp_config -p 2>/dev/null`
 
	ret=$?
 
	log 2 "executing $psp_config -p"
 
	log 2 "  returned $version"
 
	log 2 "  exit code $ret"
 

	
 
	if [ -z "$version" ] || [ "$ret" != "0" ]; then
 
		log 1 "checking psp-config... not found"
 
		log 1 "configure: error: psp-config couldn't be found"
 

	
 
		# It was forced, so it should be found.
 
		if [ "$with_psp_config" != "1" ]; then
 
			log 1 "configure: error: you supplied '$with_psp_config', but it seems invalid"
 
		fi
 
		exit 1
 
	fi
 

	
 
	log 1 "checking psp-config... found"
 
}
 

	
 
detect_iconv() {
 
	# 0 means no, 1 is auto-detect, 2 is force
 
	if [ "$with_iconv" = "0" ]; then
 
		log 1 "checking iconv... disabled"
 

	
 
		return 0
 
	fi
 

	
 
	if [ "$with_iconv" = "1" ] && [ "$os" != "OSX" ]; then
 
		log 1 "checking iconv... not OSX, skipping"
 
		with_iconv="0"
 

	
 
		return 0
 
	fi
 

	
 
	# Try to find iconv.h, seems to only thing to detect iconv with
 

	
 
	if [ "$with_iconv" = "1" ] || [ "$with_iconv" = "" ] || [ "$with_iconv" = "2" ]; then
 
		iconv=`ls -1 /usr/include 2>/dev/null | grep "iconv.h"`
 
		if [ -z "$iconv" ]; then
 
			iconv=`ls -1 /usr/local/include 2>/dev/null | grep "iconv.h"`
 
		fi
 
	else
 
		# Make sure it exists
 
		iconv=`ls $with_iconv/include/iconv.h 2>/dev/null`
 
	fi
 

	
 
	if [ -z "$iconv" ]; then
 
		log 1 "checking iconv... not found"
 
		if [ "$with_iconv" = "2" ]; then
 
			log 1 "configure: error: iconv couldn't be found"
 

	
 
			exit 1
 
		elif [ "$with_iconv" != "1" ]; then
 
			log 1 "configure: error: iconv couldn't be found"
 
			log 1 "configure: error: you supplied '$with_iconv', but I couldn't detect iconv in it"
 

	
 
			exit 1
 
		fi
 

	
 
		return 0
 
	fi
 

	
 
	if [ "$with_iconv" = "1" ]; then
 
		with_iconv="2"
 
	fi
 

	
src/gfx.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file gfx.cpp Handling of drawing text and other gfx related stuff. */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "gfx_func.h"
 
#include "spritecache.h"
 
#include "variables.h"
 
#include "fontcache.h"
 
#include "genworld.h"
 
#include "debug.h"
 
#include "zoom_func.h"
 
#include "texteff.hpp"
 
#include "blitter/factory.hpp"
 
#include "video/video_driver.hpp"
 
#include "strings_func.h"
 
#include "core/math_func.hpp"
 
#include "settings_type.h"
 
#include "core/alloc_func.hpp"
 
#include "core/sort_func.hpp"
 
#include "landscape_type.h"
 
#include "network/network_func.h"
 

	
 
#include "table/palettes.h"
 
#include "table/sprites.h"
 
#include "table/control_codes.h"
 

	
 
byte _dirkeys;        ///< 1 = left, 2 = up, 4 = right, 8 = down
 
bool _fullscreen;
 
CursorVars _cursor;
 
bool _ctrl_pressed;   ///< Is Ctrl pressed?
 
bool _shift_pressed;  ///< Is Shift pressed?
 
byte _fast_forward;
 
bool _left_button_down;     ///< Is left mouse button pressed?
 
bool _left_button_clicked;  ///< Is left mouse button clicked?
 
bool _right_button_down;    ///< Is right mouse button pressed?
 
bool _right_button_clicked; ///< Is right mouse button clicked?
 
DrawPixelInfo _screen;
 
bool _screen_disable_anim = false;   ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot)
 
bool _exit_game;
 
bool _networking;         ///< are we in networking mode?
 
byte _game_mode;
 
int8 _pause_game;
 
int _pal_first_dirty;
 
int _pal_count_dirty;
 

	
 
Colour _cur_palette[256];
 
byte _stringwidth_table[FS_END][224]; ///< Cache containing width of often used characters. @see GetCharacterWidth()
 
DrawPixelInfo *_cur_dpi;
 
byte _colour_gradient[COLOUR_END][8];
 

	
 
static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL);
 
static int ReallyDoDrawString(const char *string, int x, int y, uint16 real_colour, bool parse_string_also_when_clipped = false);
 

	
 
FontSize _cur_fontsize;
 
static FontSize _last_fontsize;
 
static uint8 _cursor_backup[64 * 64 * 4];
 

	
 
/**
 
 * The rect for repaint.
 
 *
 
 * This rectangle defines the area which should be repaint by the video driver.
 
 *
 
 * @ingroup dirty
 
 */
 
static Rect _invalid_rect;
 
static const byte *_color_remap_ptr;
 
static byte _string_colorremap[3];
 

	
 
enum {
 
	DIRTY_BLOCK_HEIGHT   = 8,
 
	DIRTY_BLOCK_WIDTH    = 64,
 
};
 
static uint _dirty_bytes_per_line = 0;
 
static byte *_dirty_blocks = NULL;
 

	
 
void GfxScroll(int left, int top, int width, int height, int xo, int yo)
 
{
 
	Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
 

	
 
	if (xo == 0 && yo == 0) return;
 

	
 
	if (_cursor.visible) UndrawMouseCursor();
 

	
 
#ifdef ENABLE_NETWORK
 
	NetworkUndrawChatMessage();
 
#endif /* ENABLE_NETWORK */
 

	
 
	blitter->ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo);
 
	/* This part of the screen is now dirty. */
 
	_video_driver->MakeDirty(left, top, width, height);
 
}
 

	
 

	
 
/**
 
 * Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
 
 *
 
 * @pre dpi->zoom == ZOOM_LVL_NORMAL, right >= left, bottom >= top
 
 * @param left Minimum X (inclusive)
 
 * @param top Minimum Y (inclusive)
 
 * @param right Maximum X (inclusive)
 
 * @param bottom Maximum Y (inclusive)
 
 * @param color A 8 bit palette index (FILLRECT_OPAQUE and FILLRECT_CHECKER) or a recolor spritenumber (FILLRECT_RECOLOR)
 
 * @param mode
 
 *         FILLRECT_OPAQUE:   Fill the rectangle with the specified color
 
 *         FILLRECT_CHECKER:  Like FILLRECT_OPAQUE, but only draw every second pixel (used to grey out things)
 
 *         FILLRECT_RECOLOR:  Apply a recolor sprite to every pixel in the rectangle currently on screen
 
 */
 
void GfxFillRect(int left, int top, int right, int bottom, int color, FillRectMode mode)
 
{
 
	Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
 
	const DrawPixelInfo *dpi = _cur_dpi;
 
	void *dst;
 
	const int otop = top;
 
	const int oleft = left;
 

	
 
	if (dpi->zoom != ZOOM_LVL_NORMAL) return;
 
	if (left > right || top > bottom) return;
 
	if (right < dpi->left || left >= dpi->left + dpi->width) return;
 
	if (bottom < dpi->top || top >= dpi->top + dpi->height) return;
 

	
 
	if ( (left -= dpi->left) < 0) left = 0;
 
	right = right - dpi->left + 1;
 
	if (right > dpi->width) right = dpi->width;
 
	right -= left;
 
	assert(right > 0);
 

	
 
	if ( (top -= dpi->top) < 0) top = 0;
 
	bottom = bottom - dpi->top + 1;
 
	if (bottom > dpi->height) bottom = dpi->height;
 
	bottom -= top;
 
	assert(bottom > 0);
 

	
 
	dst = blitter->MoveTo(dpi->dst_ptr, left, top);
 

	
 
	switch (mode) {
 
		default: // FILLRECT_OPAQUE
 
			blitter->DrawRect(dst, right, bottom, (uint8)color);
 
			break;
 

	
 
		case FILLRECT_RECOLOR:
 
			blitter->DrawColorMappingRect(dst, right, bottom, GB(color, 0, PALETTE_WIDTH));
 
			break;
 

	
 
		case FILLRECT_CHECKER: {
 
			byte bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1;
 
			do {
 
				for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8)color);
 
				dst = blitter->MoveTo(dst, 0, 1);
 
			} while (--bottom > 0);
 
			break;
 
		}
 
	}
 
}
 

	
 
void GfxDrawLine(int x, int y, int x2, int y2, int color)
 
{
 
	Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
 
	DrawPixelInfo *dpi = _cur_dpi;
 

	
 
	x -= dpi->left;
 
	x2 -= dpi->left;
 
	y -= dpi->top;
 
	y2 -= dpi->top;
 

	
 
	/* Check clipping */
 
	if (x < 0 && x2 < 0) return;
 
	if (y < 0 && y2 < 0) return;
 
	if (x > dpi->width  && x2 > dpi->width)  return;
 
	if (y > dpi->height && y2 > dpi->height) return;
 

	
 
	blitter->DrawLine(dpi->dst_ptr, x, y, x2, y2, dpi->width, dpi->height, color);
 
}
 

	
 
void GfxDrawLineUnscaled(int x, int y, int x2, int y2, int color)
 
{
 
	Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
 
	DrawPixelInfo *dpi = _cur_dpi;
 

	
 
	x -= dpi->left;
 
	x2 -= dpi->left;
 
	y -= dpi->top;
 
	y2 -= dpi->top;
 

	
 
	/* Check clipping */
 
	if (x < 0 && x2 < 0) return;
 
	if (y < 0 && y2 < 0) return;
 
	if (x > dpi->width  && x2 > dpi->width)  return;
 
	if (y > dpi->height && y2 > dpi->height) return;
 

	
 
	blitter->DrawLine(dpi->dst_ptr, UnScaleByZoom(x, dpi->zoom), UnScaleByZoom(y, dpi->zoom),
 
			UnScaleByZoom(x2, dpi->zoom), UnScaleByZoom(y2, dpi->zoom),
 
			UnScaleByZoom(dpi->width, dpi->zoom), UnScaleByZoom(dpi->height, dpi->zoom), color);
 
}
 

	
 
/**
 
 * Draws the projection of a parallelepiped.
 
 * This can be used to draw boxes in world coordinates.
 
 *
 
 * @param x   Screen X-coordinate of top front corner.
 
 * @param y   Screen Y-coordinate of top front corner.
 
 * @param dx1 Screen X-length of first edge.
 
 * @param dy1 Screen Y-length of first edge.
 
 * @param dx2 Screen X-length of second edge.
 
 * @param dy2 Screen Y-length of second edge.
 
 * @param dx3 Screen X-length of third edge.
 
 * @param dy3 Screen Y-length of third edge.
 
 */
 
void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3)
 
{
 
	/*           ....
 
	 *         ..    ....
 
	 *       ..          ....
 
	 *     ..                ^
 
	 *   <--__(dx1,dy1)    /(dx2,dy2)
 
	 *   :    --__       /   :
 
	 *   :        --__ /     :
 
	 *   :            *(x,y) :
 
	 *   :            |      :
 
	 *   :            |     ..
 
	 *    ....        |(dx3,dy3)
 
	 *        ....    | ..
 
	 *            ....V.
 
	 */
 

	
 
	static const byte color = 255;
 

	
 
	GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, color);
 
	GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, color);
 
	GfxDrawLineUnscaled(x, y, x + dx3, y + dy3, color);
 

	
 
	GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx2, y + dy1 + dy2, color);
 
	GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx3, y + dy1 + dy3, color);
 
	GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx1, y + dy2 + dy1, color);
 
	GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx3, y + dy2 + dy3, color);
 
	GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx1, y + dy3 + dy1, color);
 
	GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx2, y + dy3 + dy2, color);
 
}
 

	
 

	
 
#if !defined(WITH_ICU)
 
static void HandleBiDiAndArabicShapes(char *text, const char *lastof) {}
 
#else
 
#include "unicode/ubidi.h"
 
#include "unicode/ushape.h"
 

	
 
/**
 
 * Function to be able to handle right-to-left text and Arabic chars properly.
 
 *
 
 * First: right-to-left (RTL) is stored 'logically' in almost all applications
 
 *        and so do we. This means that their text is stored from right to the
 
 *        left in memory and any non-RTL text (like numbers or English) are
 
 *        then stored from left-to-right. When we want to actually draw the
 
 *        text we need to reverse the RTL text in memory, which is what
 
 *        happens in ubidi_writeReordered.
 
 * Second: Arabic characters "differ" based on their context. To draw the
 
 *        correct variant we pass it through u_shapeArabic. This function can
 
 *        add or remove some characters. This is the reason for the lastof
 
 *        so we know till where we can fill the output.
 
 *
 
 * Sadly enough these functions work with a custom character format, UChar,
 
 * which isn't the same size as WChar. Because of that we need to transform
 
 * our text first to UChars and then back to something we can use.
 
 *
 
 * To be able to truncate strings properly you must truncate before passing to
 
 * this function. This way the logical begin of the string remains and the end
 
 * gets chopped of instead of the other way around.
 
 *
 
 * The reshaping of Arabic characters might increase or decrease the width of
 
 * the characters/string. So it might still overflow after truncation, though
 
 * the chance is fairly slim as most characters get shorter instead of longer.
 
 * @param buffer the buffer to read from/to
 
 * @param lastof the end of the buffer
 
 */
 
static void HandleBiDiAndArabicShapes(char *buffer, const char *lastof)
 
{
 
	UChar input_output[DRAW_STRING_BUFFER];
 
	UChar intermediate[DRAW_STRING_BUFFER];
 

	
 
	char *t = buffer;
 
	size_t length = 0;
 
	while (*t != '\0' && length < lengthof(input_output)) {
 
		WChar tmp;
 
		t += Utf8Decode(&tmp, t);
 
		input_output[length++] = tmp;
 
	}
 
	input_output[length] = 0;
 

	
 
	UErrorCode err = U_ZERO_ERROR;
 
	UBiDi *para = ubidi_openSized(length, 0, &err);
 
	if (para == NULL) return;
 

	
 
	ubidi_setPara(para, input_output, length, UBIDI_DEFAULT_RTL, NULL, &err);
 
	ubidi_writeReordered(para, intermediate, length, 0, &err);
 
	length = u_shapeArabic(intermediate, length, input_output, lengthof(input_output), U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_LETTERS_SHAPE, &err);
 
	ubidi_close(para);
 

	
 
	if (U_FAILURE(err)) return;
 

	
 
	t = buffer;
 
	for (size_t i = 0; i < length && t < (lastof - 4); i++) {
 
		t += Utf8Encode(t, input_output[i]);
 
	}
 
	*t = '\0';
 
}
 
#endif /* WITH_ICU */
 

	
 

	
 
/** Truncate a given string to a maximum width if neccessary.
 
 * If the string is truncated, add three dots ('...') to show this.
 
 * @param *str string that is checked and possibly truncated
 
 * @param maxw maximum width in pixels of the string
 
 * @return new width of (truncated) string */
 
static int TruncateString(char *str, int maxw)
 
{
 
	int w = 0;
 
	FontSize size = _cur_fontsize;
 
	int ddd, ddd_w;
 

	
 
	WChar c;
 
	char *ddd_pos;
 

	
 
	ddd_w = ddd = GetCharacterWidth(size, '.') * 3;
 

	
 
	for (ddd_pos = str; (c = Utf8Consume((const char **)&str)) != '\0'; ) {
 
		if (IsPrintable(c)) {
 
			w += GetCharacterWidth(size, c);
 

	
 
			if (w >= maxw) {
 
				/* string got too big... insert dotdotdot, but make sure we do not
 
				 * print anything beyond the string termination character. */
 
				for (int i = 0; *ddd_pos != '\0' && i < 3; i++, ddd_pos++) *ddd_pos = '.';
 
				*ddd_pos = '\0';
 
				return ddd_w;
 
			}
 
		} else {
 
			if (c == SCC_SETX) {
 
				w = *str;
 
				str++;
 
			} else if (c == SCC_SETXY) {
 
				w = *str;
 
				str += 2;
 
			} else if (c == SCC_TINYFONT) {
 
				size = FS_SMALL;
 
				ddd = GetCharacterWidth(size, '.') * 3;
 
			} else if (c == SCC_BIGFONT) {
 
				size = FS_LARGE;
 
				ddd = GetCharacterWidth(size, '.') * 3;
 
			}
 
		}
 

	
 
		/* Remember the last position where three dots fit. */
 
		if (w + ddd < maxw) {
 
			ddd_w = w + ddd;
 
			ddd_pos = str;
 
		}
 
	}
 

	
 
	return w;
 
}
 

	
 
/**
 
 * Write string to output buffer, truncating it to specified maximal width in pixels if it is too long.
 
 *
 
 * @param src   String to truncate
 
 * @param dest  Start of character output buffer where truncated string is stored
 
 * @param maxw  Maximal allowed length of the string in pixels
 
 * @param last  Address of last character in output buffer
 
 *
 
 * @return Actual width of the (possibly) truncated string in pixels
 
 */
 
static inline int TruncateStringID(StringID src, char *dest, int maxw, const char* last)
 
{
 
	GetString(dest, src, last);
 
	return TruncateString(dest, maxw);
 
}
 

	
 
/**
 
 * Draw string starting at position (x,y).
 
 *
 
 * @param x      X position to start drawing
 
 * @param y      Y position to start drawing
 
 * @param str    String to draw
 
 * @param color  Color used for drawing the string, see DoDrawString() for details
 
 *
 
 * @return Horizontal coordinate after drawing the string
 
 */
 
int DrawString(int x, int y, StringID str, uint16 color)
 
{
 
	char buffer[DRAW_STRING_BUFFER];
 

	
 
	GetString(buffer, str, lastof(buffer));
 
	return DoDrawString(buffer, x, y, color);
 
	HandleBiDiAndArabicShapes(buffer, lastof(buffer));
 
	return ReallyDoDrawString(buffer, x, y, color);
 
}
 

	
 
/**
 
 * Draw string, possibly truncated to make it fit in its allocated space
 
 *
 
 * @param x      X position to start drawing
 
 * @param y      Y position to start drawing
 
 * @param str    String to draw
 
 * @param color  Color used for drawing the string, see DoDrawString() for details
 
 * @param maxw   Maximal width of the string
 
 *
 
 * @return Horizontal coordinate after drawing the (possibly truncated) string
 
 */
 
int DrawStringTruncated(int x, int y, StringID str, uint16 color, uint maxw)
 
{
 
	char buffer[DRAW_STRING_BUFFER];
 
	TruncateStringID(str, buffer, maxw, lastof(buffer));
 
	return DoDrawString(buffer, x, y, color);
 
	HandleBiDiAndArabicShapes(buffer, lastof(buffer));
 
	return ReallyDoDrawString(buffer, x, y, color);
 
}
 

	
 
/**
 
 * Draw string right-aligned.
 
 *
 
 * @param x      Right-most x position of the string
 
 * @param y      Y position of the string
 
 * @param str    String to draw
 
 * @param color  Color used for drawing the string, see DoDrawString() for details
 
 *
 
 * @return Width of drawn string in pixels
 
 */
 
int DrawStringRightAligned(int x, int y, StringID str, uint16 color)
 
{
 
	char buffer[DRAW_STRING_BUFFER];
 
	int w;
 

	
 
	GetString(buffer, str, lastof(buffer));
 
	HandleBiDiAndArabicShapes(buffer, lastof(buffer));
 

	
 
	w = GetStringBoundingBox(buffer).width;
 
	DoDrawString(buffer, x - w, y, color);
 
	ReallyDoDrawString(buffer, x - w, y, color);
 

	
 
	return w;
 
}
 

	
 
/**
 
 * Draw string right-aligned, possibly truncated to make it fit in its allocated space
 
 *
 
 * @param x      Right-most x position to start drawing
 
 * @param y      Y position to start drawing
 
 * @param str    String to draw
 
 * @param color  Color used for drawing the string, see DoDrawString() for details
 
 * @param maxw   Maximal width of the string
 
 */
 
void DrawStringRightAlignedTruncated(int x, int y, StringID str, uint16 color, uint maxw)
 
{
 
	char buffer[DRAW_STRING_BUFFER];
 

	
 
	TruncateStringID(str, buffer, maxw, lastof(buffer));
 
	DoDrawString(buffer, x - GetStringBoundingBox(buffer).width, y, color);
 
	HandleBiDiAndArabicShapes(buffer, lastof(buffer));
 
	ReallyDoDrawString(buffer, x - GetStringBoundingBox(buffer).width, y, color);
 
}
 

	
 
/**
 
 * Draw string right-aligned with a line underneath it.
 
 *
 
 * @param x      Right-most x position of the string
 
 * @param y      Y position of the string
 
 * @param str    String to draw
 
 * @param color  Color used for drawing the string, see DoDrawString() for details
 
 */
 
void DrawStringRightAlignedUnderline(int x, int y, StringID str, uint16 color)
 
{
 
	int w = DrawStringRightAligned(x, y, str, color);
 
	GfxFillRect(x - w, y + 10, x, y + 10, _string_colorremap[1]);
 
}
 

	
 
/**
 
 * Draw string centered.
 
 *
 
 * @param x      X position of center of the string
 
 * @param y      Y position of center of the string
 
 * @param str    String to draw
 
 * @param color  Color used for drawing the string, see DoDrawString() for details
 
 *
 
 * @return Width of the drawn string in pixels
 
 */
 
int DrawStringCentered(int x, int y, StringID str, uint16 color)
 
{
 
	char buffer[DRAW_STRING_BUFFER];
 
	int w;
 

	
 
	GetString(buffer, str, lastof(buffer));
 
	HandleBiDiAndArabicShapes(buffer, lastof(buffer));
 

	
 
	w = GetStringBoundingBox(buffer).width;
 
	DoDrawString(buffer, x - w / 2, y, color);
 
	ReallyDoDrawString(buffer, x - w / 2, y, color);
 

	
 
	return w;
 
}
 

	
 
/**
 
 * Draw string centered, possibly truncated to fit in the assigned space.
 
 *
 
 * @param xl     Left-most x position
 
 * @param xr     Right-most x position
 
 * @param y      Y position of the string
 
 * @param str    String to draw
 
 * @param color  Color used for drawing the string, see DoDrawString() for details
 
 *
 
 * @return Right-most coordinate of the (possibly truncated) drawn string
 
 */
 
int DrawStringCenteredTruncated(int xl, int xr, int y, StringID str, uint16 color)
 
{
 
	char buffer[DRAW_STRING_BUFFER];
 
	int w = TruncateStringID(str, buffer, xr - xl, lastof(buffer));
 
	return DoDrawString(buffer, (xl + xr - w) / 2, y, color);
 
	TruncateStringID(str, buffer, xr - xl, lastof(buffer));
 
	HandleBiDiAndArabicShapes(buffer, lastof(buffer));
 

	
 
	int w = GetStringBoundingBox(buffer).width;
 
	return ReallyDoDrawString(buffer, (xl + xr - w) / 2, y, color);
 
}
 

	
 
/**
 
 * Draw string centered.
 
 *
 
 * @param x      X position of center of the string
 
 * @param y      Y position of center of the string
 
 * @param str    String to draw
 
 * @param color  Color used for drawing the string, see DoDrawString() for details
 
 *
 
 * @return Width of the drawn string in pixels
 
 */
 
int DoDrawStringCentered(int x, int y, const char *str, uint16 color)
 
{
 
	int w = GetStringBoundingBox(str).width;
 
	DoDrawString(str, x - w / 2, y, color);
 
	char buffer[DRAW_STRING_BUFFER];
 
	strecpy(buffer, str, lastof(buffer));
 
	HandleBiDiAndArabicShapes(buffer, lastof(buffer));
 

	
 
	int w = GetStringBoundingBox(buffer).width;
 
	ReallyDoDrawString(buffer, x - w / 2, y, color);
 
	return w;
 
}
 

	
 
/**
 
 * Draw string centered, with additional line underneath it
 
 *
 
 * @param x      X position of center of the string
 
 * @param y      Y position of center of the string
 
 * @param str    String to draw
 
 * @param color  Color used for drawing the string, see DoDrawString() for details
 
 */
 
void DrawStringCenterUnderline(int x, int y, StringID str, uint16 color)
 
{
 
	int w = DrawStringCentered(x, y, str, color);
 
	GfxFillRect(x - (w >> 1), y + 10, x - (w >> 1) + w, y + 10, _string_colorremap[1]);
 
}
 

	
 
/**
 
 * Draw string centered possibly truncated, with additional line underneath it
 
 *
 
 * @param xl     Left x position of the string
 
 * @param xr     Right x position of the string
 
 * @param y      Y position of center of the string
 
 * @param str    String to draw
 
 * @param color  Color used for drawing the string, see DoDrawString() for details
 
 */
 
void DrawStringCenterUnderlineTruncated(int xl, int xr, int y, StringID str, uint16 color)
 
{
 
	int w = DrawStringCenteredTruncated(xl, xr, y, str, color);
 
	GfxFillRect((xl + xr - w) / 2, y + 10, (xl + xr + w) / 2, y + 10, _string_colorremap[1]);
 
}
 

	
 
/**
 
 * 'Correct' a string to a maximum length. Longer strings will be cut into
 
 * additional lines at whitespace characters if possible. The string parameter
 
 * is modified with terminating characters mid-string which are the
 
 * placeholders for the newlines.
 
 * The string WILL be truncated if there was no whitespace for the current
 
 * line's maximum width.
 
 *
 
 * @note To know if the terminating '\0' is the string end or just a
 
 * newline, the returned 'num' value should be consulted. The num'th '\0',
 
 * starting with index 0 is the real string end.
 
 *
 
 * @param str string to check and correct for length restrictions
 
 * @param maxw the maximum width the string can have on one line
 
 * @return return a 32bit wide number consisting of 2 packed values:
 
 *  0 - 15 the number of lines ADDED to the string
 
 * 16 - 31 the fontsize in which the length calculation was done at
 
 */
 
uint32 FormatStringLinebreaks(char *str, int maxw)
 
{
 
	FontSize size = _cur_fontsize;
 
	int num = 0;
 

	
 
	assert(maxw > 0);
 

	
 
	for (;;) {
 
		char *last_space = NULL;
 
		int w = 0;
 

	
 
		for (;;) {
 
			WChar c = Utf8Consume((const char **)&str);
 
			/* whitespace is where we will insert the line-break */
 
			if (IsWhitespace(c)) last_space = str;
 

	
 
			if (IsPrintable(c)) {
 
				w += GetCharacterWidth(size, c);
 
				/* string is longer than maximum width so we need to decide what to
 
				 * do. We can do two things:
 
				 * 1. If no whitespace was found at all up until now (on this line) then
 
				 *    we will truncate the string and bail out.
 
				 * 2. In all other cases force a linebreak at the last seen whitespace */
 
				if (w > maxw) {
 
					if (last_space == NULL) {
 
						*Utf8PrevChar(str) = '\0';
 
						return num + (size << 16);
 
					}
 
					str = last_space;
 
					break;
 
				}
 
			} else {
 
				switch (c) {
 
					case '\0': return num + (size << 16); break;
 
					case SCC_SETX:  str++; break;
 
					case SCC_SETXY: str += 2; break;
 
					case SCC_TINYFONT: size = FS_SMALL; break;
 
					case SCC_BIGFONT:  size = FS_LARGE; break;
 
					case '\n': goto end_of_inner_loop;
 
				}
 
			}
 
		}
 
end_of_inner_loop:
 
		/* String didn't fit on line (or a '\n' was encountered), so 'dummy' terminate
 
		 * and increase linecount. We use Utf8PrevChar() as also non 1 char long
 
		 * whitespace seperators are supported */
 
		num++;
 
		char *s = Utf8PrevChar(str);
 
		*s++ = '\0';
 

	
 
		/* In which case (see above) we will shift remainder to left and close the gap */
 
		if (str - s >= 1) {
 
			for (; str[-1] != '\0';) *s++ = *str++;
 
		}
 
	}
 
}
 

	
 

	
 
/** Calculates height of string (in pixels). Accepts multiline string with '\0' as separators.
 
 * @param src string to check
 
 * @param num number of extra lines (output of FormatStringLinebreaks())
 
 * @note assumes text won't be truncated. FormatStringLinebreaks() is a good way to ensure that.
 
 * @return height of pixels of string when it is drawn
 
 */
 
static int GetMultilineStringHeight(const char *src, int num)
 
{
 
	int maxy = 0;
 
	int y = 0;
 
	int fh = GetCharacterHeight(_cur_fontsize);
 

	
 
	for (;;) {
 
		WChar c = Utf8Consume(&src);
 

	
 
		switch (c) {
 
			case 0:            y += fh; if (--num < 0) return maxy; break;
 
			case '\n':         y += fh;                             break;
 
			case SCC_SETX:     src++;                               break;
 
			case SCC_SETXY:    src++; y = (int)*src++;              break;
 
			case SCC_TINYFONT: fh = GetCharacterHeight(FS_SMALL);   break;
 
			case SCC_BIGFONT:  fh = GetCharacterHeight(FS_LARGE);   break;
 
			default:           maxy = max<int>(maxy, y + fh);       break;
 
		}
 
	}
 
}
 

	
 

	
 
/** Calculates height of string (in pixels). The string is changed to a multiline string if needed.
 
 * @param str string to check
 
 * @param maxw maximum string width
 
 * @return height of pixels of string when it is drawn
 
 */
 
int GetStringHeight(StringID str, int maxw)
 
{
 
	char buffer[DRAW_STRING_BUFFER];
 

	
 
	GetString(buffer, str, lastof(buffer));
 

	
 
	uint32 tmp = FormatStringLinebreaks(buffer, maxw);
 

	
 
	return GetMultilineStringHeight(buffer, GB(tmp, 0, 16));
 
}
 

	
 

	
 
/** Draw a given string with the centre around the given (x,y) coordinates
 
 * @param x Centre the string around this pixel width
 
 * @param y Centre the string around this pixel height
 
 * @param str String to draw
 
 * @param maxw Maximum width the string can have before it is wrapped */
 
void DrawStringMultiCenter(int x, int y, StringID str, int maxw)
 
{
 
	char buffer[DRAW_STRING_BUFFER];
 
	uint32 tmp;
 
	int num, w, mt;
 
	int num, mt;
 
	const char *src;
 
	WChar c;
 

	
 
	GetString(buffer, str, lastof(buffer));
 

	
 
	tmp = FormatStringLinebreaks(buffer, maxw);
 
	num = GB(tmp, 0, 16);
 

	
 
	mt = GetCharacterHeight((FontSize)GB(tmp, 16, 16));
 

	
 
	y -= (mt >> 1) * num;
 

	
 
	src = buffer;
 

	
 
	for (;;) {
 
		w = GetStringBoundingBox(src).width;
 
		DoDrawString(src, x - (w >> 1), y, 0xFE, true);
 
		char buf2[DRAW_STRING_BUFFER];
 
		strecpy(buf2, src, lastof(buf2));
 
		HandleBiDiAndArabicShapes(buf2, lastof(buf2));
 
		int w = GetStringBoundingBox(buf2).width;
 
		ReallyDoDrawString(buf2, x - (w >> 1), y, 0xFE, true);
 
		_cur_fontsize = _last_fontsize;
 

	
 
		for (;;) {
 
			c = Utf8Consume(&src);
 
			if (c == 0) {
 
				y += mt;
 
				if (--num < 0) {
 
					_cur_fontsize = FS_NORMAL;
 
					return;
 
				}
 
				break;
 
			} else if (c == SCC_SETX) {
 
				src++;
 
			} else if (c == SCC_SETXY) {
 
				src += 2;
 
			}
 
		}
 
	}
 
}
 

	
 

	
 
uint DrawStringMultiLine(int x, int y, StringID str, int maxw, int maxh)
 
{
 
	char buffer[DRAW_STRING_BUFFER];
 
	uint32 tmp;
 
	int num, mt;
 
	uint total_height;
 
	const char *src;
 
	WChar c;
 

	
 
	GetString(buffer, str, lastof(buffer));
 

	
 
	tmp = FormatStringLinebreaks(buffer, maxw);
 
	num = GB(tmp, 0, 16);
 

	
 
	mt = GetCharacterHeight((FontSize)GB(tmp, 16, 16));
 
	total_height = (num + 1) * mt;
 

	
 
	if (maxh != -1 && (int)total_height > maxh) {
 
		/* Check there's room enough for at least one line. */
 
		if (maxh < mt) return 0;
 

	
 
		num = maxh / mt - 1;
 
		total_height = (num + 1) * mt;
 
	}
 

	
 
	src = buffer;
 

	
 
	for (;;) {
 
		DoDrawString(src, x, y, 0xFE, true);
 
		char buf2[DRAW_STRING_BUFFER];
 
		strecpy(buf2, src, lastof(buf2));
 
		HandleBiDiAndArabicShapes(buf2, lastof(buf2));
 
		ReallyDoDrawString(buf2, x, y, 0xFE, true);
 
		_cur_fontsize = _last_fontsize;
 

	
 
		for (;;) {
 
			c = Utf8Consume(&src);
 
			if (c == 0) {
 
				y += mt;
 
				if (--num < 0) {
 
					_cur_fontsize = FS_NORMAL;
 
					return total_height;
 
				}
 
				break;
 
			} else if (c == SCC_SETX) {
 
				src++;
 
			} else if (c == SCC_SETXY) {
 
				src += 2;
 
			}
 
		}
 
	}
 
}
 

	
 
/** Return the string dimension in pixels. The height and width are returned
 
 * in a single Dimension value. TINYFONT, BIGFONT modifiers are only
 
 * supported as the first character of the string. The returned dimensions
 
 * are therefore a rough estimation correct for all the current strings
 
 * but not every possible combination
 
 * @param str string to calculate pixel-width
 
 * @return string width and height in pixels */
 
Dimension GetStringBoundingBox(const char *str)
 
{
 
	FontSize size = _cur_fontsize;
 
	Dimension br;
 
	int max_width;
 
	WChar c;
 

	
 
	br.width = br.height = max_width = 0;
 
	for (;;) {
 
		c = Utf8Consume(&str);
 
		if (c == 0) break;
 
		if (IsPrintable(c)) {
 
			br.width += GetCharacterWidth(size, c);
 
		} else {
 
			switch (c) {
 
				case SCC_SETX: br.width += (byte)*str++; break;
 
				case SCC_SETXY:
 
					br.width += (byte)*str++;
 
					br.height += (byte)*str++;
 
					break;
 
				case SCC_TINYFONT: size = FS_SMALL; break;
 
				case SCC_BIGFONT:  size = FS_LARGE; break;
 
				case '\n':
 
					br.height += GetCharacterHeight(size);
 
					if (br.width > max_width) max_width = br.width;
 
					br.width = 0;
 
					break;
 
			}
 
		}
 
	}
 
	br.height += GetCharacterHeight(size);
 

	
 
	br.width  = max(br.width, max_width);
 
	return br;
 
}
 

	
 
/**
 
 * Draw single character horizontally centered around (x,y)
 
 * @param c           Character (glyph) to draw
 
 * @param x           X position to draw character
 
 * @param y           Y position to draw character
 
 * @param real_color  Colour to use, see DoDrawString() for details
 
 */
 
void DrawCharCentered(WChar c, int x, int y, uint16 real_color)
 
{
 
	FontSize size = FS_NORMAL;
 
	byte color = real_color & 0xFF;
 
	int w = GetCharacterWidth(size, c);
 

	
 
	_string_colorremap[1] = _string_colormap[_use_palette][color].text;
 
	_string_colorremap[2] = _string_colormap[_use_palette][color].shadow;
 
	_color_remap_ptr = _string_colorremap;
 

	
 
	GfxMainBlitter(GetGlyph(size, c), x - w / 2, y, BM_COLOUR_REMAP);
 
}
 

	
 
/** Draw a string at the given coordinates with the given colour.
 
 *  While drawing the string, parse it in case some formatting is specified,
 
 *  like new colour, new size or even positionning.
 
 * @param string              The string to draw
 
 * @param string              The string to draw. This is not yet bidi reordered.
 
 * @param x                   Offset from left side of the screen
 
 * @param y                   Offset from top side of the screen
 
 * @param real_colour         Colour of the string, see _string_colormap in
 
 *                            table/palettes.h or docs/ottd-colourtext-palette.png or the enum TextColour in gfx_type.h
 
 * @param parse_string_also_when_clipped
 
 *                            By default, always test the available space where to draw the string.
 
 *                            When in multipline drawing, it would already be done,
 
 *                            so no need to re-perform the same kind (more or less) of verifications.
 
 *                            It's not only an optimisation, it's also a way to ensures the string will be parsed
 
 *                            (as there are certain side effects on global variables, which are important for the next line)
 
 * @return                    the x-coordinates where the drawing has finished.
 
 *                            If nothing is drawn, the originally passed x-coordinate is returned
 
 */
 
int DoDrawString(const char *string, int x, int y, uint16 real_colour, bool parse_string_also_when_clipped)
 
{
 
	char buffer[DRAW_STRING_BUFFER];
 
	strecpy(buffer, string, lastof(buffer));
 
	HandleBiDiAndArabicShapes(buffer, lastof(buffer));
 

	
 
	return ReallyDoDrawString(buffer, x, y, real_colour, parse_string_also_when_clipped);
 
}
 

	
 
/** Draw a string at the given coordinates with the given colour.
 
 *  While drawing the string, parse it in case some formatting is specified,
 
 *  like new colour, new size or even positionning.
 
 * @param string              The string to draw. This is already bidi reordered.
 
 * @param x                   Offset from left side of the screen
 
 * @param y                   Offset from top side of the screen
 
 * @param real_colour         Colour of the string, see _string_colormap in
 
 *                            table/palettes.h or docs/ottd-colourtext-palette.png or the enum TextColour in gfx_type.h
 
 * @param parse_string_also_when_clipped
 
 *                            By default, always test the available space where to draw the string.
 
 *                            When in multipline drawing, it would already be done,
 
 *                            so no need to re-perform the same kind (more or less) of verifications.
 
 *                            It's not only an optimisation, it's also a way to ensures the string will be parsed
 
 *                            (as there are certain side effects on global variables, which are important for the next line)
 
 * @return                    the x-coordinates where the drawing has finished.
 
 *                            If nothing is drawn, the originally passed x-coordinate is returned
 
 */
 
static int ReallyDoDrawString(const char *string, int x, int y, uint16 real_colour, bool parse_string_also_when_clipped)
 
{
 
	DrawPixelInfo *dpi = _cur_dpi;
 
	FontSize size = _cur_fontsize;
 
	WChar c;
 
	int xo = x, yo = y;
 

	
 
	byte colour = real_colour & 0xFF;  // extract the 8 bits colour index that is required for the mapping
 
	byte previous_colour = colour;
 

	
 
	if (!parse_string_also_when_clipped) {
 
		/* in "mode multiline", the available space have been verified. Not in regular one.
 
		 * So if the string cannot be drawn, return the original start to say so.*/
 
		if (x >= dpi->left + dpi->width || y >= dpi->top + dpi->height) return x;
 

	
 
		if (colour != TC_INVALID) { // the invalid colour flag test should not  really occur.  But better be safe
 
switch_colour:;
 
			if (real_colour & IS_PALETTE_COLOR) {
 
				_string_colorremap[1] = colour;
 
				_string_colorremap[2] = (_use_palette == PAL_DOS) ? 1 : 215;
 
			} else {
 
				_string_colorremap[1] = _string_colormap[_use_palette][colour].text;
 
				_string_colorremap[2] = _string_colormap[_use_palette][colour].shadow;
 
			}
 
			_color_remap_ptr = _string_colorremap;
 
		}
 
	}
 

	
 
check_bounds:
 
	if (y + 19 <= dpi->top || dpi->top + dpi->height <= y) {
 
skip_char:;
 
		for (;;) {
 
			c = Utf8Consume(&string);
 
			if (!IsPrintable(c)) goto skip_cont;
 
		}
 
	}
 

	
 
	for (;;) {
 
		c = Utf8Consume(&string);
 
skip_cont:;
 
		if (c == 0) {
 
			_last_fontsize = size;
 
			return x;  // Nothing more to draw, get out. And here is the new x position
 
		}
 
		if (IsPrintable(c)) {
 
			if (x >= dpi->left + dpi->width) goto skip_char;
 
			if (x + 26 >= dpi->left) {
 
				GfxMainBlitter(GetGlyph(size, c), x, y, BM_COLOUR_REMAP);
 
			}
 
			x += GetCharacterWidth(size, c);
 
		} else if (c == '\n') { // newline = {}
 
			x = xo;  // We require a new line, so the x coordinate is reset
 
			y += GetCharacterHeight(size);
 
			goto check_bounds;
 
		} else if (c >= SCC_BLUE && c <= SCC_BLACK) { // change colour?
 
			previous_colour = colour;
 
			colour = (byte)(c - SCC_BLUE);
 
			goto switch_colour;
 
		} else if (c == SCC_PREVIOUS_COLOUR) { // revert to the previous colour
 
			Swap(colour, previous_colour);
 
			goto switch_colour;
 
		} else if (c == SCC_SETX) { // {SETX}
 
			x = xo + (byte)*string++;
 
		} else if (c == SCC_SETXY) {// {SETXY}
 
			x = xo + (byte)*string++;
 
			y = yo + (byte)*string++;
 
		} else if (c == SCC_TINYFONT) { // {TINYFONT}
 
			size = FS_SMALL;
 
		} else if (c == SCC_BIGFONT) { // {BIGFONT}
 
			size = FS_LARGE;
 
		} else {
 
			DEBUG(misc, 0, "[utf8] unknown string command character %d", c);
 
		}
 
	}
 
}
 

	
 
/**
 
 * Draw the string of the character buffer, starting at position (x,y) with a given maximal width.
 
 * String is truncated if it is too long.
 
 *
 
 * @param str  Character buffer containing the string
 
 * @param x    Left-most x coordinate to start drawing
 
 * @param y    Y coordinate to draw the string
 
 * @param color Colour to use, see DoDrawString() for details.
 
 * @param maxw  Maximal width in pixels that may be used for drawing
 
 *
 
 * @return Right-most x position after drawing the (possibly truncated) string
 
 */
 
int DoDrawStringTruncated(const char *str, int x, int y, uint16 color, uint maxw)
 
{
 
	char buffer[DRAW_STRING_BUFFER];
 
	ttd_strlcpy(buffer, str, sizeof(buffer));
 
	TruncateString(buffer, maxw);
 
	return DoDrawString(buffer, x, y, color);
 
}
 

	
 
/**
 
 * Draw a sprite.
0 comments (0 inline, 0 general)