ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/utils/cfutil.in
(Generate patch)

Comparing deliantra/server/utils/cfutil.in (file contents):
Revision 1.118 by root, Tue Jan 3 11:35:33 2012 UTC vs.
Revision 1.124 by root, Sun Nov 11 05:53:12 2012 UTC

1#!@PERL@ 1#!@PERL@
2 2
3# 3#
4# This file is part of Deliantra, the Roguelike Realtime MMORPG. 4# This file is part of Deliantra, the Roguelike Realtime MMORPG.
5# 5#
6# Copyright (©) 2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 6# Copyright (©) 2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
7# 7#
8# Deliantra is free software: you can redistribute it and/or modify it under 8# Deliantra is free software: you can redistribute it and/or modify it under
9# the terms of the Affero GNU General Public License as published by the 9# the terms of the Affero GNU General Public License as published by the
10# Free Software Foundation, either version 3 of the License, or (at your 10# Free Software Foundation, either version 3 of the License, or (at your
11# option) any later version. 11# option) any later version.
12# 12#
13# This program is distributed in the hope that it will be useful, 13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details. 16# GNU General Public License for more details.
17# 17#
18# You should have received a copy of the Affero GNU General Public License 18# You should have received a copy of the Affero GNU General Public License
19# and the GNU General Public License along with this program. If not, see 19# and the GNU General Public License along with this program. If not, see
20# <http://www.gnu.org/licenses/>. 20# <http://www.gnu.org/licenses/>.
21# 21#
22# The authors can be reached via e-mail to <support@deliantra.net> 22# The authors can be reached via e-mail to <support@deliantra.net>
23# 23#
24 24
25use common::sense; 25use common::sense;
26 26
221 our $c_arc = new Coro::Channel; 221 our $c_arc = new Coro::Channel;
222 our $c_any = new Coro::Channel; 222 our $c_any = new Coro::Channel;
223 223
224 our @c_png; 224 our @c_png;
225 225
226 # texture catalog size, in 64x64 tiles
227 sub TC_W() { 1024 / 64 }
228 sub TC_H() { 1024 / 64 }
229
230 our @TC = ([]); # texture catalogs
231
226 sub commit_png($$$$) { 232 sub commit_png($$$$$$) {
227 my ($stem, $name, $data, $T) = @_; 233 my ($stem, $name, $data, $T, $w, $h) = @_;
228 234
229 $FACEINFO{$name}{"stem"} = substr $stem, 1 + length $PATH; 235 $FACEINFO{$name}{stem} = substr $stem, 1 + length $PATH;
230 $FACEINFO{$name}{"data$T"} = $data; 236 $FACEINFO{$name}{"data$T"} = $data;
237 $FACEINFO{$name}{w} = $w;
238 $FACEINFO{$name}{h} = $h;
231 } 239 }
232 240
233 sub process_png { 241 sub process_png {
234 while (@c_png) { 242 while (@c_png) {
235 my ($path, $delete) = @{pop @c_png}; 243 my ($path, $delete) = @{pop @c_png};
347 $x * ($w - 8) + 4, 355 $x * ($w - 8) + 4,
348 $y * ($h - 8) + 4; 356 $y * ($h - 8) + 4;
349 } 357 }
350 } 358 }
351 359
352 system "convert -depth 8 $SRC rgba:-" 360 system "$CONVERT -depth 8 $SRC rgba:-"
353 . "| $exec_prefix/bin/cfhq2xa $w $h 0" 361 . "| $exec_prefix/bin/cfhq2xa $w $h 0"
354 . "| convert -depth 8 -size ".($w * 2)."x".($h * 2)." rgba:- $CROP $QUANTIZE -quality 00 png32:\Q$other\E~" 362 . "| $CONVERT -depth 8 -size ".($w * 2)."x".($h * 2)." rgba:- $CROP $QUANTIZE -quality 00 png32:\Q$other\E~"
355 and die "convert/cfhq2xa pipeline error: status $? ($!)"; 363 and die "convert/cfhq2xa pipeline error: status $? ($!)";
356 optipng "$other~"; 364 optipng "$other~";
357 rename "$other~", $other; 365 rename "$other~", $other;
358 }; 366 };
359 }; 367 };
365 if (0 > aio_stat "$stem.32x32.png") { 373 if (0 > aio_stat "$stem.32x32.png") {
366 my $other = "$stem.32x32.png~"; 374 my $other = "$stem.32x32.png~";
367 375
368 make_file $path, $other, sub { 376 make_file $path, $other, sub {
369 fork_exec { 377 fork_exec {
370 system "convert png:\Q$path\E -geometry 50% -filter lanczos $QUANTIZE -quality 00 png32:\Q$other\E~"; 378 system "$CONVERT png:\Q$path\E -geometry 50% -filter lanczos $QUANTIZE -quality 00 png32:\Q$other\E~";
371 optipng "$other~"; 379 optipng "$other~";
372 380
373 # reduce smoothfaces >10000 bytes 381 # reduce smoothfaces >10000 bytes
374 # obsolete, no longer required 382 # obsolete, no longer required
375 if (0 && $stem =~ /_S\./ && (-s "$other~") > 10000) { 383 if (0 && $stem =~ /_S\./ && (-s "$other~") > 10000) {
445 warn "ERROR: facename $type:$face contains unsupported derivation type.\n"; 453 warn "ERROR: facename $type:$face contains unsupported derivation type.\n";
446 } 454 }
447 455
448 aio_load $dpath, my $png; 456 aio_load $dpath, my $png;
449 IO::AIO::aio_unlink $dpath unless $CACHE; 457 IO::AIO::aio_unlink $dpath unless $CACHE;
450 commit_png "$dir/$type:$face", "$type:$face", $png, $T; 458 commit_png "$dir/$type:$face", "$type:$face", $png, $T, 1, 1;
451 } 459 }
452 460
453 # split all bigfaces, but avoid smoothfaces (*_S) 461 # split all bigfaces, but avoid smoothfaces (*_S)
454 if (($w > $T || $h > $T) && $face !~ /_S\./) { 462 if (($w > $T || $h > $T) && $face !~ /_S\./) {
455 # split 463 # split
500 508
501 if (0 > aio_load $file, $tile) { 509 if (0 > aio_load $file, $tile) {
502 die "$path: unable to read tile +$x+$y, aborting.\n"; 510 die "$path: unable to read tile +$x+$y, aborting.\n";
503 } 511 }
504 IO::AIO::aio_unlink $file unless $CACHE; 512 IO::AIO::aio_unlink $file unless $CACHE;
505 commit_png $stem, $x|$y ? "$face+$x+$y" : $face, $tile, $T; 513 commit_png $stem, $x|$y ? "$face+$x+$y" : $face, $tile, $T, 1, 1;
506 } 514 }
507 } else { 515 } else {
508 # use as-is (either small, use smooth) 516 # use as-is (either small, use smooth)
509 commit_png $stem, $face, $png, $T; 517 commit_png $stem, $face, $png, $T, $w / $T, $h / $T;
510 } 518 }
511 519
512 IO::AIO::aio_unlink $path if $delete; 520 IO::AIO::aio_unlink $path if $delete;
513 } 521 }
514 } 522 }
761 $meta = { 769 $meta = {
762 %{ $meta->{"" } || {} }, 770 %{ $meta->{"" } || {} },
763 %{ $meta->{$file} || {} }, 771 %{ $meta->{$file} || {} },
764 }; 772 };
765 773
766 if ($meta->{license} =~ s/^#//) { 774 if (exists $meta->{license} && $meta->{license} =~ s/^#//) { # exists == avoid autovivification
767 $meta->{license} = ({ 775 $meta->{license} = ({
768 "pd" => "Public Domain", 776 "pd" => "Public Domain",
769 "gpl" => "GNU General Public License, version 3.0 or any later", 777 "gpl" => "GNU General Public License, version 3.0 or any later",
770 "cc/by/2.0" => "Licensed under Creative Commons Attribution 2.0 http://creativecommons.org/licenses/by/2.0/", 778 "cc/by/2.0" => "Licensed under Creative Commons Attribution 2.0 http://creativecommons.org/licenses/by/2.0/",
771 "cc/by/2.1" => "Licensed under Creative Commons Attribution 2.1 http://creativecommons.org/licenses/by/2.1/", 779 "cc/by/2.1" => "Licensed under Creative Commons Attribution 2.1 http://creativecommons.org/licenses/by/2.1/",
782 $file =~ s/\.res$//; 790 $file =~ s/\.res$//;
783 $file =~ s/\.(ogg|wav|jpg|png)$//; 791 $file =~ s/\.(ogg|wav|jpg|png)$//;
784 792
785 if ($file =~ s/\.plt$//) { 793 if ($file =~ s/\.plt$//) {
786 $data = process_plt "$dir/$file", $data; 794 $data = process_plt "$dir/$file", $data;
787 } elsif (my $filter = $meta->{cfutil_filter}) { 795 } elsif (my $filter = delete $meta->{cfutil_filter}) {
788 if ($filter eq "yaml2json") { 796 if ($filter eq "yaml2json") {
789 $data = JSON::XS::encode_json YAML::XS::Load $data; 797 $data = JSON::XS::encode_json YAML::XS::Load $data;
790 } elsif ($filter eq "json2json") { 798 } elsif ($filter eq "json2json") {
791 $data = JSON::XS::encode_json JSON::XS->relaxed->utf8->decode ($data); 799 $data = JSON::XS::encode_json JSON::XS->relaxed->utf8->decode ($data);
792 } elsif ($filter eq "perl2json") { 800 } elsif ($filter eq "perl2json") {
797 } 805 }
798 } 806 }
799 807
800 substr $dir, 0, 1 + length $PATH, ""; 808 substr $dir, 0, 1 + length $PATH, "";
801 809
802 $RESOURCE{"$dir/$file"} = { 810 my %info = (
803 type => (exists $meta->{type} ? delete $meta->{type} : $type), 811 type => (exists $meta->{type} ? delete $meta->{type} : $type),
804 data => $data, 812 data => $data,
805 %$meta ? (meta => $meta) : (), 813 %$meta ? (meta => $meta) : (),
806 }; 814 );
815
816 $RESOURCE{"$dir/$file"} = \%info;
807 } 817 }
808 818
809 sub process_any { 819 sub process_any {
810 while (my ($func, @args) = @{ $c_any->get }) { 820 while (my ($func, @args) = @{ $c_any->get }) {
811 $func->(@args); 821 $func->(@args);
844 if ($file =~ /\.(jpg|png)$/) { 854 if ($file =~ /\.(jpg|png)$/) {
845 $c_any->put ([\&process_res, $path, $file, 0]) # FT_FACE 855 $c_any->put ([\&process_res, $path, $file, 0]) # FT_FACE
846 } elsif ($file =~ /\.(res)$/) { 856 } elsif ($file =~ /\.(res)$/) {
847 $c_any->put ([\&process_res, $path, $file, 6]) # FT_RSRC 857 $c_any->put ([\&process_res, $path, $file, 6]) # FT_RSRC
848 } else { 858 } else {
849 $c_any->put ([\&process_res, $path, $file, undef]); 859 $c_any->put ([\&process_res, $path, $file, 6]); # was type undef, but now meta files are mandatory, so any mentioned file surely has a purpose
850 } 860 }
851 861
852 } elsif ($file =~ /\.png$/) { 862 } elsif ($file =~ /\.png$/) {
853 $PNG{$file} = $path; 863 $PNG{$file} = $path;
854 864
1034 print $fh $TRS; 1044 print $fh $TRS;
1035 } 1045 }
1036 1046
1037 { 1047 {
1038 print "processing facedata...\n" if $VERBOSE; 1048 print "processing facedata...\n" if $VERBOSE;
1039 while (my ($k, $v) = each %FACEINFO) { 1049
1050 for my $k (sort keys %FACEINFO) {
1051 my $v = $FACEINFO{$k};
1052
1040 length $v->{data32} or warn "ERROR: face '$k' has no png32 - this will not work.\n"; 1053 length $v->{data32} or warn "ERROR: face '$k' has no png32 - this will not work.\n";
1041 length $v->{data64} or warn "ERROR: face '$k' has no png64 - this will not work.\n"; 1054 length $v->{data64} or warn "ERROR: face '$k' has no png64 - this will not work.\n";
1042 1055
1043 make_hash $k, $v->{data32}, $v->{hash32}; 1056 make_hash $k, $v->{data32}, $v->{hash32};
1044 make_hash $k, $v->{data64}, $v->{hash64}; 1057 make_hash $k, $v->{data64}, $v->{hash64};
1048 1061
1049 $v->{glyph} // warn "ERROR: face '$k' has no glyph - missing faceinfo entry?\n"; 1062 $v->{glyph} // warn "ERROR: face '$k' has no glyph - missing faceinfo entry?\n";
1050 $v->{visibility} // warn "ERROR: face '$k' has no visibility info - missing faceinfo entry?\n"; 1063 $v->{visibility} // warn "ERROR: face '$k' has no visibility info - missing faceinfo entry?\n";
1051 $v->{magicmap} // warn "ERROR: face '$k' has no foreground colour - missing faceinfo entry?\n"; 1064 $v->{magicmap} // warn "ERROR: face '$k' has no foreground colour - missing faceinfo entry?\n";
1052 1065
1066 if (0 && $v->{w} == 1 && $v->{h} == 1) { # texture catalogs
1067 my $id = @TC;
1068 my $n = @{ $TC[-1] };
1069 my $x = $n % TC_W;
1070 my $y = int $n / TC_W;
1071
1072 push @{ $TC[-1] }, [$v, $x, $y];
1073
1074 $v->{tc} = [$id, $x, $y];
1075
1076 push @TC, [] if $n == TC_W * TC_H - 1; # start new texture if full
1077 }
1078
1053 delete @$v{qw(arc stem derive)}; # not used by the server 1079 delete @$v{qw(w h arc stem derive)}; # not used by the server
1080 }
1081
1082if (0) { #d# texture catalogs
1083 print "creating texture catalogs...\n" if $VERBOSE;
1084
1085 for my $id (0 .. $#TC) {
1086 my $tc = $TC[$id];
1087
1088 my $cmd = "$CONVERT -depth 8 -size " . (TC_W * 64) . "x" . (TC_H * 64) . " xc:transparent";
1089 my $idx = "a";
1090
1091 for (@$tc) {
1092 my $path = "$TMPDIR/tc" . $idx++;
1093
1094 open my $fh, ">:perlio", $path
1095 or die "$path: $!";
1096 syswrite $fh, $_->[0]{data64};
1097
1098 my $x = $_->[1] * 64;
1099 my $y = $_->[2] * 64;
1100
1101 $cmd .= " png:\Q$path\E -geometry +$x+$y -composite";
1054 } 1102 }
1103
1104 system "$cmd png:\Q$TMPDIR/tc$id\E";
1105 optipng "$TMPDIR/tc$id";
1106 }
1107}
1055 1108
1056 print "processing resources...\n" if $VERBOSE; 1109 print "processing resources...\n" if $VERBOSE;
1057 my $enc = JSON::XS->new->utf8->canonical->relaxed; 1110 my $enc = JSON::XS->new->utf8->canonical->relaxed;
1058 while (my ($k, $v) = each %RESOURCE) { 1111 for my $k (sort keys %RESOURCE) {
1112 my $v = $RESOURCE{$k};
1059 1113
1060 if ($v->{meta} && $v->{meta}{datadir}) { 1114 if ($v->{meta} && $v->{meta}{datadir}) {
1061 delete $RESOURCE{$k}; 1115 delete $RESOURCE{$k};
1062 1116
1063 $k =~ s/^res\/// or die "$k: datadir files must be in res/"; 1117 $k =~ s/^res\/// or die "$k: datadir files must be in res/";
1082 1136
1083 make_hash $k, $v->{data}, $v->{hash}, 6; # 6 for the benefit of existing clients 1137 make_hash $k, $v->{data}, $v->{hash}, 6; # 6 for the benefit of existing clients
1084 } 1138 }
1085 } 1139 }
1086 1140
1141 printf "writing facedata...\n" if $VERBOSE;
1142
1143 {
1144 open my $fh, ">:perlio", "$DATADIR/facedata~"
1145 or die "$DATADIR/facedata~: $!";
1146
1147 print $fh "FACEDATA";
1148 my $fofs = 8;
1149
1150 my $put = sub {
1151 my $len = length $_[0];
1152 my $ofs = $fofs;
1153
1154 print $fh $_[0];
1155 $fofs += $len;
1156
1157 ($len, $ofs)
1158 };
1159
1160 for (values %FACEINFO) {
1161 ($_->{size32}, $_->{fofs32}) = $put->(delete $_->{data32});
1162 ($_->{size64}, $_->{fofs64}) = $put->(delete $_->{data64});
1163 }
1164
1165 for (values %RESOURCE) {
1166 ($_->{size}, $_->{fofs}) = $put->(delete $_->{data});
1167 }
1168
1169 close $fh;
1170 }
1171
1087 printf "writing facedata (%d faces, %d anims, %d resources)...\n", 1172 printf "writing faceinfo (%d faces, %d anims, %d resources)...\n",
1088 scalar keys %FACEINFO, 1173 scalar keys %FACEINFO,
1089 scalar keys %ANIMINFO, 1174 scalar keys %ANIMINFO,
1090 scalar keys %RESOURCE 1175 scalar keys %RESOURCE
1091 if $VERBOSE; 1176 if $VERBOSE;
1092 1177
1093 open my $fh, ">:perlio", "$DATADIR/facedata~" 1178 open my $fh, ">:perlio", "$DATADIR/faceinfo~"
1094 or die "$DATADIR/facedata~: $!"; 1179 or die "$DATADIR/faceinfo~: $!";
1095 1180
1096 print $fh nfreeze { 1181 print $fh nfreeze {
1097 version => 2, 1182 version => 2,
1098 faceinfo => \%FACEINFO, 1183 faceinfo => \%FACEINFO,
1099 animinfo => \%ANIMINFO, 1184 animinfo => \%ANIMINFO,
1101 }; 1186 };
1102 } 1187 }
1103 1188
1104 print "committing files...\n" if $VERBOSE; 1189 print "committing files...\n" if $VERBOSE;
1105 1190
1106 for (qw(archetypes facedata treasures), @COMMIT) { 1191 for (qw(archetypes faceinfo facedata treasures), @COMMIT) {
1107 chmod 0644, "$DATADIR/$_~"; 1192 chmod 0644, "$DATADIR/$_~";
1108 rename "$DATADIR/$_~", "$DATADIR/$_" 1193 rename "$DATADIR/$_~", "$DATADIR/$_"
1109 or die "$DATADIR/$_: $!"; 1194 or die "$DATADIR/$_: $!";
1110 } 1195 }
1111 1196

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines