function simpleImg() { // prefer manually converted PNG files (as the imagecreatefromblp-script has issues with some formats) // see: https://github.com/Kanma/BLPConverter $loadImageFile = function ($path) { $result = null; if (in_array(mb_substr($path, -4, 4), ['.png', '.blp', '.BLP', '.PNG'])) { $path = mb_substr($path, 0, mb_strlen($path) - 4); } $file = $path . '.png'; if (CLISetup::fileExists($file)) { CLISetup::log('manually converted png file present for ' . $path . '.', CLISetup::LOG_INFO); $result = imagecreatefrompng($file); } if (!$result) { $file = $path . '.blp'; if (CLISetup::fileExists($file)) { $result = imagecreatefromblp($file); } } return $result; }; if (isset(FileGen::$cliOpts['help'])) { echo "\n"; echo "available options for subScript 'simpleImg':\n"; echo " --icons (generates square icons that are used for basicly everything)\n"; echo " --glyphs (decorative tidbit displayed on Infobox for Glyph Spells)\n"; echo " --pagetexts (imagery contained in PageTexts on readable GameObjects or Items)\n"; echo " --loadingscreens (loading screens (not used, skipped by default))\n"; return true; } $locStr = null; $groups = []; $dbcPath = CLISetup::$srcDir . '%sDBFilesClient/'; $imgPath = CLISetup::$srcDir . '%sInterface/'; $destDir = 'static/images/wow/'; $success = true; $iconDirs = array(['icons/large/', 'jpg', 0, 56, 4], ['icons/medium/', 'jpg', 0, 36, 4], ['icons/small/', 'jpg', 0, 18, 4], ['icons/tiny/', 'gif', 0, 15, 4]); $calendarDirs = array(['icons/large/', 'jpg', 90, 56, 4], ['icons/medium/', 'jpg', 90, 36, 4], ['icons/small/', 'jpg', 90, 18, 4], ['icons/tiny/', 'gif', 90, 15, 4]); $loadScreenDirs = array(['loadingscreens/large/', 'jpg', 0, 1024, 0], ['loadingscreens/medium/', 'jpg', 0, 488, 0], ['loadingscreens/original/', 'png', 0, 0, 0], ['loadingscreens/small/', 'jpg', 0, 244, 0]); $paths = array(0 => ['Icons/', $iconDirs, '/*.[bB][lL][pP]', true, 0], 1 => ['Spellbook/', [['Interface/Spellbook/', 'png', 0, 0, 0]], '/UI-Glyph-Rune*.blp', true, 0], 2 => ['PaperDoll/', array_slice($iconDirs, 0, 3), '/UI-{Backpack,PaperDoll}-*.blp', true, 0], 3 => ['GLUES/CHARACTERCREATE/UI-CharacterCreate-Races.blp', $iconDirs, '', true, 64], 4 => ['GLUES/CHARACTERCREATE/UI-CharacterCreate-CLASSES.blp', $iconDirs, '', true, 64], 5 => ['GLUES/CHARACTERCREATE/UI-CharacterCreate-Factions.blp', $iconDirs, '', true, 64], 7 => ['FlavorImages/', [['Interface/FlavorImages/', 'png', 0, 0, 0]], '/*.[bB][lL][pP]', false, 0], 8 => ['Pictures/', [['Interface/Pictures/', 'png', 0, 0, 0]], '/*.[bB][lL][pP]', false, 0], 9 => ['PvPRankBadges/', [['Interface/PvPRankBadges/', 'png', 0, 0, 0]], '/*.[bB][lL][pP]', false, 0], 10 => ['Calendar/Holidays/', $calendarDirs, '/*{rt,a,y,h,s}.[bB][lL][pP]', true, 0], 11 => ['GLUES/LOADINGSCREENS/', $loadScreenDirs, '/[lL][oO]*.[bB][lL][pP]', false, 0]); // textures are composed of 64x64 icons // numeric indexed arrays mimick the position on the texture $cuNames = array(2 => array('ui-paperdoll-slot-chest' => 'inventoryslot_chest', 'ui-backpack-emptyslot' => 'inventoryslot_empty', 'ui-paperdoll-slot-feet' => 'inventoryslot_feet', 'ui-paperdoll-slot-finger' => 'inventoryslot_finger', 'ui-paperdoll-slot-hands' => 'inventoryslot_hands', 'ui-paperdoll-slot-head' => 'inventoryslot_head', 'ui-paperdoll-slot-legs' => 'inventoryslot_legs', 'ui-paperdoll-slot-mainhand' => 'inventoryslot_mainhand', 'ui-paperdoll-slot-neck' => 'inventoryslot_neck', 'ui-paperdoll-slot-secondaryhand' => 'inventoryslot_offhand', 'ui-paperdoll-slot-ranged' => 'inventoryslot_ranged', 'ui-paperdoll-slot-relic' => 'inventoryslot_relic', 'ui-paperdoll-slot-shirt' => 'inventoryslot_shirt', 'ui-paperdoll-slot-shoulder' => 'inventoryslot_shoulder', 'ui-paperdoll-slot-tabard' => 'inventoryslot_tabard', 'ui-paperdoll-slot-trinket' => 'inventoryslot_trinket', 'ui-paperdoll-slot-waist' => 'inventoryslot_waist', 'ui-paperdoll-slot-wrists' => 'inventoryslot_wrists'), 3 => array(['race_human_male', 'race_dwarf_male', 'race_gnome_male', 'race_nightelf_male', 'race_draenei_male'], ['race_tauren_male', 'race_scourge_male', 'race_troll_male', 'race_orc_male', 'race_bloodelf_male'], ['race_human_female', 'race_dwarf_female', 'race_gnome_female', 'race_nightelf_female', 'race_draenei_female'], ['race_tauren_female', 'race_scourge_female', 'race_troll_female', 'race_orc_female', 'race_bloodelf_female']), 4 => array(['class_warrior', 'class_mage', 'class_rogue', 'class_druid'], ['class_hunter', 'class_shaman', 'class_priest', 'class_warlock'], ['class_paladin', 'class_deathknight']), 5 => array(['faction_alliance', 'faction_horde']), 6 => array([], [null, 'quest_start', 'quest_end', 'quest_start_daily', 'quest_end_daily']), 10 => array('calendar_winterveilstart' => 'calendar_winterveilstart', 'calendar_noblegardenstart' => 'calendar_noblegardenstart', 'calendar_childrensweekstart' => 'calendar_childrensweekstart', 'calendar_fishingextravaganza' => 'calendar_fishingextravaganzastart', 'calendar_harvestfestivalstart' => 'calendar_harvestfestivalstart', 'calendar_hallowsendstart' => 'calendar_hallowsendstart', 'calendar_lunarfestivalstart' => 'calendar_lunarfestivalstart', 'calendar_loveintheairstart' => 'calendar_loveintheairstart', 'calendar_midsummerstart' => 'calendar_midsummerstart', 'calendar_brewfeststart' => 'calendar_brewfeststart', 'calendar_darkmoonfaireelwynnstart' => 'calendar_darkmoonfaireelwynnstart', 'calendar_darkmoonfairemulgorestart' => 'calendar_darkmoonfairemulgorestart', 'calendar_darkmoonfaireterokkarstart' => 'calendar_darkmoonfaireterokkarstart', 'calendar_piratesday' => 'calendar_piratesdaystart', 'calendar_wotlklaunch' => 'calendar_wotlklaunchstart', 'calendar_dayofthedeadstart' => 'calendar_dayofthedeadstart', 'calendar_fireworks' => 'calendar_fireworksstart')); $writeImage = function ($name, $ext, $src, $srcDims, $destDims, $done) { $ok = false; $dest = imagecreatetruecolor($destDims['w'], $destDims['h']); imagesavealpha($dest, true); if ($ext == 'png') { imagealphablending($dest, false); } imagecopyresampled($dest, $src, $destDims['x'], $destDims['x'], $srcDims['x'], $srcDims['y'], $destDims['w'], $destDims['h'], $srcDims['w'], $srcDims['h']); switch ($ext) { case 'jpg': $ok = imagejpeg($dest, $name . '.' . $ext, 85); break; case 'gif': $ok = imagegif($dest, $name . '.' . $ext); break; case 'png': $ok = imagepng($dest, $name . '.' . $ext); break; default: CLISetup::log($done . ' - unsupported file fromat: ' . $ext, CLISetup::LOG_WARN); } imagedestroy($dest); if ($ok) { chmod($name . '.' . $ext, Util::FILE_ACCESS); CLISetup::log($done . ' - image ' . $name . '.' . $ext . ' written', CLISetup::LOG_OK); } else { CLISetup::log($done . ' - could not create image ' . $name . '.' . $ext, CLISetup::LOG_ERROR); } return $ok; }; $checkSourceDirs = function ($sub, &$missing = []) use($imgPath, $dbcPath, $paths) { $hasMissing = false; foreach (array_column($paths, 0) as $subDir) { $p = sprintf($imgPath, $sub) . $subDir; if (!CLISetup::fileExists($p)) { $hasMissing = true; $missing[] = $p; } } $p = sprintf($dbcPath, $sub); if (!CLISetup::fileExists($p)) { $hasMissing = true; $missing[] = $p; } return !$hasMissing; }; if (isset(FileGen::$cliOpts['icons'])) { array_push($groups, 0, 2, 3, 4, 5, 10); } if (isset(FileGen::$cliOpts['glyphs'])) { $groups[] = 1; } if (isset(FileGen::$cliOpts['pagetexts'])) { array_push($groups, 7, 8, 9); } if (isset(FileGen::$cliOpts['loadingscreens'])) { $groups[] = 11; } // filter by pasaed options if (!$groups) { // by default do not generate loadingscreens unset($paths[11]); } else { foreach (array_keys($paths) as $k) { if (!in_array($k, $groups)) { unset($paths[$k]); } } } foreach (CLISetup::$expectedPaths as $xp => $__) { if ($xp) { // if in subDir add trailing slash $xp .= '/'; } if ($checkSourceDirs($xp, $missing)) { $locStr = $xp; break; } } // if no subdir had sufficient data, diaf if ($locStr === null) { CLISetup::log('one or more required directories are missing:', CLISetup::LOG_ERROR); foreach ($missing as $m) { CLISetup::log(' - ' . $m, CLISetup::LOG_ERROR); } return; } // init directories foreach (array_column($paths, 1) as $subDirs) { foreach ($subDirs as $sd) { if (!CLISetup::writeDir($destDir . $sd[0])) { $success = false; } } } // ok, departure from std::procedure here // scan ItemDisplayInfo.dbc and SpellIcon.dbc for expected images and save them to an array // load all icon paths into another array and xor these two // excess entries for the directory are fine, excess entries for the dbc's are not $dbcEntries = []; if (isset($paths[0]) || isset($paths[1])) { if (isset($paths[0]) && !isset($paths[1])) { $siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon WHERE iconPath NOT LIKE "%glyph-rune%"'); } else { if (!isset($paths[0]) && isset($paths[1])) { $siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon WHERE iconPath LIKE "%glyph-rune%"'); } else { $siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon'); } } foreach ($siRows as $icon) { $dbcEntries[] = strtolower(sprintf('setup/mpqdata/%s', $locStr) . strtr($icon, ['\\' => '/']) . '.blp'); } } if (isset($paths[0])) { $itemIcons = DB::Aowow()->selectCol('SELECT inventoryIcon1 FROM dbc_itemdisplayinfo WHERE inventoryIcon1 <> ""'); foreach ($itemIcons as $icon) { $dbcEntries[] = strtolower(sprintf($imgPath, $locStr) . 'Icons/' . $icon . '.blp'); } $eventIcons = DB::Aowow()->selectCol('SELECT textureString FROM dbc_holidays WHERE textureString <> ""'); foreach ($eventIcons as $icon) { $dbcEntries[] = strtolower(sprintf($imgPath, $locStr) . 'Calendar/Holidays/' . $icon . 'Start.blp'); } } // case-insensitive array_unique *vomits silently into a corner* $dbcEntries = array_intersect_key($dbcEntries, array_unique($dbcEntries)); $allPaths = []; foreach ($paths as $i => $p) { $path = sprintf($imgPath, $locStr) . $p[0]; if (!CLISetup::fileExists($path)) { continue; } $files = glob($path . $p[2], GLOB_BRACE); $allPaths = array_merge($allPaths, $files); CLISetup::log('processing ' . count($files) . ' files in ' . $path . '...'); $j = 0; foreach ($files as $f) { ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time) $src = null; $img = explode('.', array_pop(explode('/', $f))); array_pop($img); // there are a hand full of images with multiple file endings or random dots in the name $img = implode('.', $img); // file not from dbc -> name from array or skip file if (!empty($cuNames[$i])) { if (!empty($cuNames[$i][strtolower($img)])) { $img = $cuNames[$i][strtolower($img)]; } else { if (!$p[4]) { $j += count($p[1]); CLISetup::log('skipping extraneous file ' . $img . ' (+' . count($p[1]) . ')'); continue; } } } $nFiles = count($p[1]) * ($p[4] ? array_sum(array_map('count', $cuNames[$i])) : count($files)); foreach ($p[1] as $info) { if ($p[4]) { foreach ($cuNames[$i] as $y => $row) { foreach ($row as $x => $name) { $j++; $img = $p[3] ? strtolower($name) : $name; $done = ' - ' . str_pad($j . '/' . $nFiles, 12) . str_pad('(' . number_format($j * 100 / $nFiles, 2) . '%)', 9); if (!isset(FileGen::$cliOpts['force']) && file_exists($destDir . $info[0] . $img . '.' . $info[1])) { CLISetup::log($done . ' - file ' . $info[0] . $img . '.' . $info[1] . ' was already processed'); continue; } if (!$src) { $src = $loadImageFile($f); } if (!$src) { // error should be created by imagecreatefromblp continue; } $from = array('x' => $info[4] + $p[4] * $x, 'y' => $info[4] + $p[4] * $y, 'w' => $p[4] - $info[4] * 2, 'h' => $p[4] - $info[4] * 2); $to = array('x' => 0, 'y' => 0, 'w' => $info[3], 'h' => $info[3]); if (!$writeImage($destDir . $info[0] . $img, $info[1], $src, $from, $to, $done)) { $success = false; } } } // custom handle for combined icon 'quest_startend' /* not used due to alphaChannel issues if ($p[4] == 32) { $dest = imagecreatetruecolor(19, 16); imagesavealpha($dest, true); imagealphablending($dest, true); // excalmationmark, questionmark imagecopyresampled($dest, $src, 0, 1, 32 + 5, 32 + 2, 8, 15, 18, 30); imagecopyresampled($dest, $src, 5, 0, 64 + 1, 32 + 1, 10, 16, 18, 28); if (imagegif($dest, $destDir.$info[0].'quest_startend.gif')) CLISetup::log(' extra - image '.$destDir.$info[0].'quest_startend.gif written', CLISetup::LOG_OK); else { CLISetup::log(' extra - could not create image '.$destDir.$info[0].'quest_startend.gif', CLISetup::LOG_ERROR); $success = false; } imagedestroy($dest); } */ } else { // icon -> lowercase if ($p[3]) { $img = strtolower($img); } $j++; $done = ' - ' . str_pad($j . '/' . $nFiles, 12) . str_pad('(' . number_format($j * 100 / $nFiles, 2) . '%)', 9); if (!isset(FileGen::$cliOpts['force']) && file_exists($destDir . $info[0] . $img . '.' . $info[1])) { CLISetup::log($done . ' - file ' . $info[0] . $img . '.' . $info[1] . ' was already processed'); continue; } if (!$src) { $src = $loadImageFile($f); } if (!$src) { // error should be created by imagecreatefromblp continue; } $from = array('x' => $info[4], 'y' => $info[4], 'w' => ($info[2] ?: imagesx($src)) - $info[4] * 2, 'h' => ($info[2] ?: imagesy($src)) - $info[4] * 2); $to = array('x' => 0, 'y' => 0, 'w' => $info[3] ?: imagesx($src), 'h' => $info[3] ?: imagesy($src)); if (!$writeImage($destDir . $info[0] . $img, $info[1], $src, $from, $to, $done)) { $success = false; } } } unset($src); } } // reset execTime ini_set('max_execution_time', FileGen::$defaultExecTime); if ($missing = array_diff(array_map('strtolower', $dbcEntries), array_map('strtolower', $allPaths))) { asort($missing); CLISetup::log('the following ' . count($missing) . ' images where referenced by DBC but not in the mpqData directory. They may need to be converted by hand later on.', CLISetup::LOG_WARN); foreach ($missing as $m) { CLISetup::log(' - ' . $m); } } return $success; }
continue; } for ($i = 0; $i < 12; $i++) { $img = imagecreatefromblp($prefix . ($i + 1) . ".blp"); imagecopyresampled($map, $img, 256 * ($i % 4), 256 * intval($i / 4), 0, 0, 256, 256, imagesx($img), imagesy($img)); imagedestroy($img); } echo "."; if (isset($wmo[$zid])) { foreach ($wmo[$zid] as $row) { $i = 1; $y = 0; while ($y < $row["height"]) { $x = 0; while ($x < $row["width"]) { $img = imagecreatefromblp($worldmapdir . $mapname . "/" . $row["name"] . $i . ".blp"); imagecopy($mapfg, $img, $row["left"] + $x, $row["top"] + $y, 0, 0, imagesx($img), imagesy($img)); imagedestroy($img); $x += 256; $i++; } $y += 256; } } echo "."; if (isset($outtmpdir)) { $tmp = imagecreate(1000, 1000); $cbg = imagecolorallocate($tmp, 255, 255, 255); $cfg = imagecolorallocate($tmp, 0, 0, 0); for ($y = 0; $y < 1000; $y++) { for ($x = 0; $x < 1000; $x++) {
function complexImg() { if (isset(FileGen::$cliOpts['help'])) { echo "\n"; echo "available options for subScript 'complexImg':\n"; // modeMask echo "--talentbgs (backgrounds for talent calculator)\n"; // 0x01 echo "--maps (generates worldmaps)\n"; // 0x02 echo "--spawn-maps (creates alphaMasks of each zone to check spawns against)\n"; // 0x04 echo "--artwork (optional: imagery from /glues/credits (not used, skipped by default))\n"; // 0x08 echo "--area-maps (optional: renders maps with highlighted subZones for each area)\n"; // 0x10 return true; } $mapWidth = 1002; $mapHeight = 668; $threshold = 95; // alpha threshold to define subZones: set it too low and you have unspawnable areas inside a zone; set it too high and the border regions overlap $runTime = ini_get('max_execution_time'); $locStr = null; $dbcPath = CLISetup::$srcDir . '%sDBFilesClient/'; $imgPath = CLISetup::$srcDir . '%sInterface/'; $destDir = 'static/images/wow/'; $success = true; $paths = ['WorldMap/', 'TalentFrame/', 'Glues/Credits/']; $modeMask = 0x7; // talentBGs, regular maps, spawn-related alphaMaps $createAlphaImage = function ($w, $h) { $img = imagecreatetruecolor($w, $h); imagesavealpha($img, true); imagealphablending($img, false); $bgColor = imagecolorallocatealpha($img, 0, 0, 0, 127); imagefilledrectangle($img, 0, 0, imagesx($img) - 1, imagesy($img) - 1, $bgColor); imagecolortransparent($img, $bgColor); imagealphablending($img, true); imagecolordeallocate($img, $bgColor); return $img; }; // prefer manually converted PNG files (as the imagecreatefromblp-script has issues with some formats) // alpha channel issues observed with locale deDE Hilsbrad and Elwynn - maps // see: https://github.com/Kanma/BLPConverter $loadImageFile = function ($path) { $result = null; $file = $path . '.png'; if (CLISetup::fileExists($file)) { CLISetup::log('manually converted png file present for ' . $path . '.', CLISetup::LOG_WARN); $result = imagecreatefrompng($file); } if (!$result) { $file = $path . '.blp'; if (CLISetup::fileExists($file)) { $result = imagecreatefromblp($file); } } return $result; }; $assembleImage = function ($baseName, $order, $w, $h) use($loadImageFile) { $dest = imagecreatetruecolor($w, $h); imagesavealpha($dest, true); imagealphablending($dest, false); $_h = $h; foreach ($order as $y => $row) { $_w = $w; foreach ($row as $x => $suffix) { $src = $loadImageFile($baseName . $suffix); if (!$src) { CLISetup::log(' - complexImg: tile ' . $baseName . $suffix . '.blp missing.', CLISetup::LOG_ERROR); unset($dest); return null; } imagecopyresampled($dest, $src, 256 * $x, 256 * $y, 0, 0, min($_w, 256), min($_h, 256), min($_w, 256), min($_h, 256)); $_w -= 256; unset($src); } $_h -= 256; } return $dest; }; $writeImage = function ($name, $ext, $src, $w, $h, $done) { $ok = false; $dest = imagecreatetruecolor($w, $h); imagesavealpha($dest, true); imagealphablending($dest, false); imagecopyresampled($dest, $src, 0, 0, 0, 0, $w, $h, imagesx($src), imagesy($src)); switch ($ext) { case 'jpg': $ok = imagejpeg($dest, $name . '.' . $ext, 85); break; case 'png': $ok = imagepng($dest, $name . '.' . $ext); break; default: CLISetup::log($done . ' - unsupported file fromat: ' . $ext, CLISetup::LOG_WARN); } imagedestroy($dest); if ($ok) { chmod($name . '.' . $ext, CLISetup::FILE_ACCESS); CLISetup::log($done . ' - image ' . $name . '.' . $ext . ' written', CLISetup::LOG_OK); } else { CLISetup::log($done . ' - could not create image ' . $name . '.' . $ext, CLISetup::LOG_ERROR); } return $ok; }; $createSpawnMap = function ($img, $zoneId) use($mapHeight, $mapWidth, $threshold) { CLISetup::log(' - creating spawn map'); $tmp = imagecreate(1000, 1000); $cbg = imagecolorallocate($tmp, 255, 255, 255); $cfg = imagecolorallocate($tmp, 0, 0, 0); for ($y = 0; $y < 1000; $y++) { for ($x = 0; $x < 1000; $x++) { $a = imagecolorat($img, $x * $mapWidth / 1000, $y * $mapHeight / 1000) >> 24; imagesetpixel($tmp, $x, $y, $a < $threshold ? $cfg : $cbg); } } imagepng($tmp, 'setup/generated/alphaMaps/' . $zoneId . '.png'); imagecolordeallocate($tmp, $cbg); imagecolordeallocate($tmp, $cfg); imagedestroy($tmp); }; $checkSourceDirs = function ($sub, &$missing = []) use($imgPath, $dbcPath, $paths, &$modeMask) { $hasMissing = false; foreach ($paths as $idx => $subDir) { if ($idx == 0 && !($modeMask & 0x16)) { // map related continue; } else { if ($idx == 1 && !($modeMask & 0x1)) { // talentBGs continue; } else { if ($idx == 2 && !($modeMask & 0x8)) { // artwork continue; } } } $p = sprintf($imgPath, $sub) . $subDir; if (!CLISetup::fileExists($p)) { $hasMissing = true; $missing[] = $p; } } if ($modeMask & 0x17) { $p = sprintf($dbcPath, $sub); if (!CLISetup::fileExists($p)) { $hasMissing = true; $missing[] = $p; } } return !$hasMissing; }; // do not change order of params! if ($_ = FileGen::hasOpt('talentbgs', 'maps', 'spawn-maps', 'artwork', 'area-maps')) { $modeMask = $_; } foreach (CLISetup::$expectedPaths as $xp => $__) { if ($xp) { // if in subDir add trailing slash $xp .= '/'; } if ($checkSourceDirs($xp, $missing)) { $locStr = $xp; break; } } // if no subdir had sufficient data, diaf if ($locStr === null) { CLISetup::log('one or more required directories are missing:', CLISetup::LOG_ERROR); foreach ($missing as $m) { CLISetup::log(' - ' . $m, CLISetup::LOG_ERROR); } return; } /**************/ /* TalentTabs */ /**************/ if ($modeMask & 0x1) { if (CLISetup::writeDir($destDir . 'hunterpettalents/') && CLISetup::writeDir($destDir . 'talents/backgrounds/')) { // [classMask, creatureFamilyMask, tabNr, textureStr] $tTabs = DB::Aowow()->select('SELECT tt.creatureFamilyMask, tt.textureFile, tt.tabNumber, cc.fileString FROM dbc_talenttab tt LEFT JOIN dbc_chrclasses cc ON cc.Id = (LOG(2, tt.classMask) + 1)'); $order = array(['-TopLeft', '-TopRight'], ['-BottomLeft', '-BottomRight']); if ($tTabs) { $sum = 0; $total = count($tTabs); CLISetup::log('Processing ' . $total . ' files from TalentFrame/ ...'); foreach ($tTabs as $tt) { ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time) $sum++; $done = ' - ' . str_pad($sum . '/' . $total, 8) . str_pad('(' . number_format($sum * 100 / $total, 2) . '%)', 9); if ($tt['creatureFamilyMask']) { $size = [244, 364]; $name = $destDir . 'hunterpettalents/bg_' . (log($tt['creatureFamilyMask'], 2) + 1); } else { $size = [204, 554]; $name = $destDir . 'talents/backgrounds/' . strtolower($tt['fileString']) . '_' . ($tt['tabNumber'] + 1); } if (!isset(FileGen::$cliOpts['force']) && file_exists($name . '.jpg')) { CLISetup::log($done . ' - file ' . $name . '.jpg was already processed'); continue; } $im = $assembleImage(sprintf($imgPath, $locStr) . 'TalentFrame/' . $tt['textureFile'], $order, 256 + 44, 256 + 75); if (!$im) { CLISetup::log(' - could not assemble file ' . $tt['textureFile'], CLISetup::LOG_ERROR); continue; } if (!$writeImage($name, 'jpg', $im, $size[0], $size[1], $done)) { $success = false; } } } else { $success = false; } ini_set('max_execution_time', $runTime); } else { $success = false; } } /************/ /* Worldmap */ /************/ if ($modeMask & 0x16) { $mapDirs = array(['maps/%snormal/', 'jpg', 488, 325], ['maps/%soriginal/', 'jpg', 0, 0], ['maps/%ssmall/', 'jpg', 224, 163], ['maps/%szoom/', 'jpg', 772, 515]); // as the js expects them $baseLevelFix = array(4264 => 1, 4265 => 1, 4415 => 1, 4416 => 1, 4493 => 0, 4500 => 1, 4603 => 1, 4723 => 1, 4809 => 1, 4813 => 1, 4820 => 1, 717 => 1, 3713 => 1, 2437 => 1, 3716 => 1, 3847 => 1, 718 => 1, 3717 => 1, 3714 => 1, 3562 => 1, 722 => 1, 491 => 1, 3792 => 1, 3789 => 1, 1477 => 1, 3959 => 0, 3845 => 1, 2717 => 1, 3923 => 1, 3607 => 1, 3836 => 1, 2159 => 1, 4075 => 0); $wmo = DB::Aowow()->select('SELECT *, worldMapAreaId AS ARRAY_KEY, Id AS ARRAY_KEY2 FROM dbc_worldmapoverlay WHERE textureString <> ""'); $wma = DB::Aowow()->select('SELECT * FROM dbc_worldmaparea'); if (!$wma || !$wmo) { $success = false; CLISetup::log(' - could not read required dbc files: WorldMapArea.dbc [' . count($wma) . ' entries]; WorldMapOverlay.dbc [' . count($wmo) . ' entries]', CLISetup::LOG_ERROR); return; } // fixups... foreach ($wma as &$a) { if ($a['areaId']) { continue; } switch ($a['Id']) { case 13: $a['areaId'] = -6; break; // Kalimdor // Kalimdor case 14: $a['areaId'] = -3; break; // Eastern Kingdoms // Eastern Kingdoms case 466: $a['areaId'] = -2; break; // Outland // Outland case 485: $a['areaId'] = -5; break; // Northrend } } array_unshift($wma, ['Id' => -1, 'areaId' => -1, 'nameINT' => 'World'], ['Id' => -4, 'areaId' => -4, 'nameINT' => 'Cosmic']); $sumMaps = count(CLISetup::$localeIds) * count($wma); CLISetup::log('Processing ' . $sumMaps . ' files from WorldMap/ ...'); foreach (CLISetup::$localeIds as $progressLoc => $l) { // create destination directories $dirError = false; foreach ($mapDirs as $md) { if (!CLISetup::writeDir($destDir . sprintf($md[0], strtolower(Util::$localeStrings[$l]) . '/'))) { $dirError = true; } } if ($modeMask & 0x4) { if (!CLISetup::writeDir('setup/generated/alphaMaps')) { $dirError = true; } } if ($dirError) { $success = false; CLISetup::log(' - complexImg: could not create map directories for locale ' . $l . '. skipping...', CLISetup::LOG_ERROR); continue; } // source for mapFiles $mapSrcDir = null; $locDirs = array_filter(CLISetup::$expectedPaths, function ($var) use($l) { return !$var || $var == $l; }); foreach ($locDirs as $mapLoc => $__) { if ($mapLoc) { // and trailing slash again $mapLoc .= '/'; } $p = sprintf($imgPath, $mapLoc) . $paths[0]; if (CLISetup::fileExists($p)) { CLISetup::log(' - using files from ' . ($mapLoc ?: '/') . ' for locale ' . Util::$localeStrings[$l], CLISetup::LOG_WARN); $mapSrcDir = $p . '/'; break; } } if ($mapSrcDir === null) { $success = false; CLISetup::log(' - no suitable localized map files found for locale ' . $l, CLISetup::LOG_ERROR); continue; } foreach ($wma as $progressArea => $areaEntry) { $curMap = $progressArea + count($wma) * $progressLoc; $progress = ' - ' . str_pad($curMap . '/' . $sumMaps, 10) . str_pad('(' . number_format($curMap * 100 / $sumMaps, 2) . '%)', 9); $wmaId = $areaEntry['Id']; $zoneId = $areaEntry['areaId']; $textureStr = $areaEntry['nameINT']; $path = $mapSrcDir . $textureStr; if (!CLISetup::fileExists($path)) { $success = false; CLISetup::log('worldmap file ' . $path . ' missing for selected locale ' . Util::$localeStrings[$l], CLISetup::LOG_ERROR); continue; } $fmt = array([1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]); CLISetup::log($textureStr . " [" . $zoneId . "]"); $overlay = $createAlphaImage($mapWidth, $mapHeight); // zone has overlays (is in open world; is not multiLeveled) if (isset($wmo[$wmaId])) { CLISetup::log(' - area has ' . count($wmo[$wmaId]) . ' overlays'); foreach ($wmo[$wmaId] as &$row) { $i = 1; $y = 0; while ($y < $row['h']) { $x = 0; while ($x < $row['w']) { $img = $loadImageFile($path . '/' . $row['textureString'] . $i); if (!$img) { CLISetup::log(' - complexImg: tile ' . $path . '/' . $row['textureString'] . $i . '.blp missing.', CLISetup::LOG_ERROR); break 2; } imagecopy($overlay, $img, $row['x'] + $x, $row['y'] + $y, 0, 0, imagesx($img), imagesy($img)); // prepare subzone image if ($modeMask & 0x10) { if (!isset($row['maskimage'])) { $row['maskimage'] = $createAlphaImage($row['w'], $row['h']); $row['maskcolor'] = imagecolorallocatealpha($row['maskimage'], 255, 64, 192, 64); } for ($my = 0; $my < imagesy($img); $my++) { for ($mx = 0; $mx < imagesx($img); $mx++) { if (imagecolorat($img, $mx, $my) >> 24 < $threshold) { imagesetpixel($row['maskimage'], $x + $mx, $y + $my, $row['maskcolor']); } } } } imagedestroy($img); $x += 256; $i++; } $y += 256; } } // create spawn-maps if wanted if ($modeMask & 0x4) { $createSpawnMap($overlay, $zoneId); } } // check, if the current zone is multiLeveled // if there are also files present without layer-suffix assume them as layer: 0 $multiLeveled = false; $multiLevel = 0; do { if (!CLISetup::filesInPath('/' . $textureStr . '\\/' . $textureStr . ($multiLevel + 1) . '_\\d\\.blp/i', true)) { break; } $multiLevel++; $multiLeveled = true; } while ($multiLevel < 18); // Karazhan has 17 frickin floors // check if we can create base map anyway $file = $path . '/' . $textureStr . '1.blp'; $hasBaseMap = CLISetup::fileExists($file); CLISetup::log(' - area has ' . ($multiLeveled ? $multiLevel . ' levels' : 'only base level')); $map = null; for ($i = 0; $i <= $multiLevel; $i++) { ini_set('max_execution_time', 120); // max 120sec per image $file = $path . '/' . $textureStr; if (!$i && !$hasBaseMap) { continue; } // if $multiLeveled also suffix -0 to baseMap if it exists if ($i && $multiLeveled) { $file .= $i . '_'; } $doSkip = 0x0; $outFile = []; foreach ($mapDirs as $idx => $info) { $outFile[$idx] = $destDir . sprintf($info[0], strtolower(Util::$localeStrings[$l]) . '/') . $zoneId; $floor = $i; if ($zoneId == 4100) { // ToCStratholme: map order fix $floor += 1; } if ($multiLeveled && !(isset($baseLevelFix[$zoneId]) && $i == $baseLevelFix[$zoneId])) { $outFile[$idx] .= '-' . $floor; } if (!isset(FileGen::$cliOpts['force']) && file_exists($outFile[$idx] . '.' . $info[1])) { CLISetup::log($progress . ' - file ' . $outFile[$idx] . '.' . $info[1] . ' was already processed'); $doSkip |= 1 << $idx; } } if ($doSkip == 0xf) { continue; } $map = $assembleImage($file, $fmt, $mapWidth, $mapHeight); if (!$map) { $success = false; CLISetup::log(' - could not create image resource for map ' . $zoneId . ($multiLevel ? ' level ' . $i : '')); continue; } if (!$multiLeveled) { imagecopymerge($map, $overlay, 0, 0, 0, 0, imagesx($overlay), imagesy($overlay), 100); imagedestroy($overlay); } // create map if ($modeMask & 0x2) { foreach ($mapDirs as $idx => $info) { if ($doSkip & 1 << $idx) { continue; } if (!$writeImage($outFile[$idx], $info[1], $map, $info[2] ?: $mapWidth, $info[3] ?: $mapHeight, $progress)) { $success = false; } } } } // also create subzone-maps if ($map && isset($wmo[$wmaId]) && $modeMask & 0x10) { foreach ($wmo[$wmaId] as &$row) { $doSkip = 0x0; $outFile = []; foreach ($mapDirs as $idx => $info) { $outFile[$idx] = $destDir . sprintf($info[0], strtolower(Util::$localeStrings[$l]) . '/') . $row['areaTableId']; if (!isset(FileGen::$cliOpts['force']) && file_exists($outFile[$idx] . '.' . $info[1])) { CLISetup::log($progress . ' - file ' . $outFile[$idx] . '.' . $info[1] . ' was already processed'); $doSkip |= 1 << $idx; } } if ($doSkip == 0xf) { continue; } $subZone = imagecreatetruecolor($mapWidth, $mapHeight); imagecopy($subZone, $map, 0, 0, 0, 0, imagesx($map), imagesy($map)); imagecopy($subZone, $row['maskimage'], $row['x'], $row['y'], 0, 0, imagesx($row['maskimage']), imagesy($row['maskimage'])); foreach ($mapDirs as $idx => $info) { if ($doSkip & 1 << $idx) { continue; } if (!$writeImage($outFile[$idx], $info[1], $subZone, $info[2] ?: $mapWidth, $info[3] ?: $mapHeight, $progress)) { $success = false; } } imagedestroy($subZone); } } if ($map) { imagedestroy($map); } } } } /***********/ /* Credits */ /***********/ if ($modeMask & 0x8) { if (CLISetup::writeDir($destDir . 'Interface/Glues/Credits/')) { // tile ordering $order = array(1 => array([1]), 2 => array([1], [2]), 4 => array([1, 2], [3, 4]), 6 => array([1, 2, 3], [4, 5, 6]), 8 => array([1, 2, 3, 4], [5, 6, 7, 8])); $imgGroups = []; $srcPath = sprintf($imgPath, $locStr) . 'Glues/Credits/'; $files = CLISetup::filesInPath($srcPath); foreach ($files as $f) { if (preg_match('/([^\\/]+)(\\d).blp/i', $f, $m)) { if ($m[1] && $m[2]) { if (!isset($imgGroups[$m[1]])) { $imgGroups[$m[1]] = $m[2]; } else { if ($imgGroups[$m[1]] < $m[2]) { $imgGroups[$m[1]] = $m[2]; } } } } } // errör-korrekt $imgGroups['Desolace'] = 4; $imgGroups['BloodElf_Female'] = 6; $total = count($imgGroups); $sum = 0; CLISetup::log('Processing ' . $total . ' files from Glues/Credits/...'); foreach ($imgGroups as $file => $fmt) { ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time) $sum++; $done = ' - ' . str_pad($sum . '/' . $total, 8) . str_pad('(' . number_format($sum * 100 / $total, 2) . '%)', 9); $name = $destDir . 'Interface/Glues/Credits/' . $file; if (!isset(FileGen::$cliOpts['force']) && file_exists($name . '.png')) { CLISetup::log($done . ' - file ' . $name . '.png was already processed'); continue; } if (!isset($order[$fmt])) { CLISetup::log(' - pattern for file ' . $name . ' not set. skipping', CLISetup::LOG_WARN); continue; } $im = $assembleImage($srcPath . $file, $order[$fmt], count($order[$fmt][0]) * 256, count($order[$fmt]) * 256); if (!$im) { CLISetup::log(' - could not assemble file ' . $name, CLISetup::LOG_ERROR); continue; } if (!$writeImage($name, 'png', $im, count($order[$fmt][0]) * 256, count($order[$fmt]) * 256, $done)) { $success = false; } } ini_set('max_execution_time', $runTime); } else { $success = false; } } return $success; }
function process($dbcfile, $dbcfmt) { global $mpqdir, $largedir, $mediumdir, $smalldir, $tinydir; status("Reading icons list from {$dbcfile}..."); $dbc = dbc2array_($dbcfile, $dbcfmt); $count = count($dbc); status($count . " icons found\n"); $current = 0; $status = array(); $lastfile = array(); foreach ($dbc as $row) { $srcfilename = strtolower(str_replace("\\", "/", $row[1])); if (strpos($srcfilename, "/") === FALSE) { $srcfilename = "interface/icons/" . $srcfilename; } $src = $mpqdir . $srcfilename . ".blp"; $stat_src = @stat($src); if ($row[1] == "") { echo " "; } else { if ($stat_src == NULL || $stat_src['size'] == 0) { $msg = "Not found"; $status[$msg] = isset($status[$msg]) ? $status[$msg] + 1 : 1; $lastfile[$msg][] = $src; echo "-"; } else { $dstfilename = strtolower(substr(strrchr($srcfilename, "/"), 1)); $stat_dst = @stat($largedir . $dstfilename . ".jpg"); if ($stat_dst != NULL && $stat_dst['mtime'] >= $stat_src['mtime']) { $msg = "Already up-to-date"; $status[$msg] = isset($status[$msg]) ? $status[$msg] + 1 : 1; //$lastfile[$msg][] = $src; $lastfile[$msg][0] = "..."; $lastfile[$msg][1] = $src; echo "."; } else { $img = imagecreatefromblp($src); resave($largedir . $dstfilename . ".jpg", $img, 56, 56); resave($mediumdir . $dstfilename . ".jpg", $img, 36, 36); resave($smalldir . $dstfilename . ".jpg", $img, 18, 18); resave($tinydir . $dstfilename . ".gif", $img, 15, 15); echo "+"; } } } $current++; if ($current % 60 == 0) { status(" " . $current . "/" . $count . " (" . round(100 * $current / $count) . "%)\n"); } } if ($current % 60 != 0) { status(" " . $current . "/" . $count . " (100%)\n"); } echo "Done\n"; if (count($status) > 0) { echo "Status:\n"; foreach ($status as $s => $row) { echo " " . $s . ": " . $row . "\n"; // foreach ($lastfile[$s] as $file) // echo " $file\n"; } } }