mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-08-15 14:43:32 -07:00
Add primitive .3do (TA/Spring) model conversion tool.
This was SVN commit r8007.
This commit is contained in:
parent
9fa5af5fbf
commit
fed57d7bee
3 changed files with 870 additions and 0 deletions
270
source/tools/springimport/SpringPalette.pm
Normal file
270
source/tools/springimport/SpringPalette.pm
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
package SpringPalette;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my @palette = (
|
||||
"000000",
|
||||
"800000",
|
||||
"008000",
|
||||
"808000",
|
||||
"000080",
|
||||
"800080",
|
||||
"008080",
|
||||
"808080",
|
||||
"C0DCC0",
|
||||
"5454FC",
|
||||
"000000",
|
||||
"000000",
|
||||
"000000",
|
||||
"000000",
|
||||
"000000",
|
||||
"000000",
|
||||
"FFEBF3",
|
||||
"EBC7D3",
|
||||
"D7A3B3",
|
||||
"C38797",
|
||||
"AF6F7F",
|
||||
"9B5B63",
|
||||
"8B474F",
|
||||
"7B3B47",
|
||||
"6F333B",
|
||||
"632B33",
|
||||
"57232B",
|
||||
"4B1B27",
|
||||
"3B171F",
|
||||
"2F0F17",
|
||||
"230B0F",
|
||||
"17070B",
|
||||
"73FFDF",
|
||||
"57E7BF",
|
||||
"43CF9F",
|
||||
"2FB783",
|
||||
"1F9F67",
|
||||
"138B4F",
|
||||
"0F773F",
|
||||
"0B6B37",
|
||||
"075F2F",
|
||||
"07532B",
|
||||
"004727",
|
||||
"003F23",
|
||||
"00331B",
|
||||
"002717",
|
||||
"001B0F",
|
||||
"00130B",
|
||||
"E3EFFF",
|
||||
"C7DFE7",
|
||||
"AFCFCB",
|
||||
"93B7A7",
|
||||
"7F9F83",
|
||||
"6B8767",
|
||||
"5F6F53",
|
||||
"5F6347",
|
||||
"5B573B",
|
||||
"534333",
|
||||
"473B2B",
|
||||
"3B3323",
|
||||
"2F2B1B",
|
||||
"231F13",
|
||||
"17130F",
|
||||
"0B0B07",
|
||||
"FBFBD7",
|
||||
"DFDFB7",
|
||||
"C3C39B",
|
||||
"ABAB83",
|
||||
"93936F",
|
||||
"777757",
|
||||
"636343",
|
||||
"535333",
|
||||
"434323",
|
||||
"333317",
|
||||
"23230F",
|
||||
"1B1B07",
|
||||
"171707",
|
||||
"131300",
|
||||
"0F0F00",
|
||||
"0B0B00",
|
||||
"FBFBFB",
|
||||
"EBEBEB",
|
||||
"DBDBDB",
|
||||
"CBCBCB",
|
||||
"BBBBBB",
|
||||
"ABABAB",
|
||||
"9B9B9B",
|
||||
"8B8B8B",
|
||||
"7B7B7B",
|
||||
"6B6B6B",
|
||||
"5B5B5B",
|
||||
"4B4B4B",
|
||||
"3B3B3B",
|
||||
"2B2B2B",
|
||||
"1F1F1F",
|
||||
"0F0F0F",
|
||||
"EBF3FF",
|
||||
"CBE3FF",
|
||||
"AFCFFF",
|
||||
"97B3FF",
|
||||
"7B97FF",
|
||||
"677FFF",
|
||||
"536BEF",
|
||||
"3F5BE3",
|
||||
"334BD7",
|
||||
"233BCB",
|
||||
"172FAF",
|
||||
"0F2797",
|
||||
"071F7B",
|
||||
"071763",
|
||||
"000F47",
|
||||
"000B2F",
|
||||
"E3F7FF",
|
||||
"BFDBE7",
|
||||
"9FBFCF",
|
||||
"83A7B7",
|
||||
"6B8FA3",
|
||||
"53778B",
|
||||
"3F5F73",
|
||||
"2F4B5F",
|
||||
"273F57",
|
||||
"23374F",
|
||||
"1F2F47",
|
||||
"1B273F",
|
||||
"171F37",
|
||||
"131B2F",
|
||||
"0F1327",
|
||||
"0B0F1F",
|
||||
"D7EFFF",
|
||||
"BBE3EF",
|
||||
"9BCBDF",
|
||||
"83B7CF",
|
||||
"6BA3C3",
|
||||
"538FB3",
|
||||
"3F7BA3",
|
||||
"2F6B97",
|
||||
"235B87",
|
||||
"1B4B77",
|
||||
"133F67",
|
||||
"0B3357",
|
||||
"072747",
|
||||
"001B37",
|
||||
"001327",
|
||||
"000B1B",
|
||||
"FFE7FF",
|
||||
"E7C7EB",
|
||||
"D3ABD7",
|
||||
"BB93C3",
|
||||
"A77BB3",
|
||||
"8F639F",
|
||||
"774B8F",
|
||||
"633B7F",
|
||||
"4F2B6F",
|
||||
"431F63",
|
||||
"371757",
|
||||
"2B0F47",
|
||||
"1F073B",
|
||||
"13002B",
|
||||
"0B001F",
|
||||
"070013",
|
||||
"D7FFA7",
|
||||
"ABE77F",
|
||||
"83D35B",
|
||||
"67BF3F",
|
||||
"4BAB2B",
|
||||
"43972B",
|
||||
"378727",
|
||||
"2F771B",
|
||||
"2B6713",
|
||||
"235B0F",
|
||||
"1F4F0B",
|
||||
"1B4307",
|
||||
"173300",
|
||||
"0F2700",
|
||||
"0B1B00",
|
||||
"070F00",
|
||||
"FFE39F",
|
||||
"E3C773",
|
||||
"CBAF53",
|
||||
"B3973F",
|
||||
"9B832F",
|
||||
"836F23",
|
||||
"6B5B17",
|
||||
"53470F",
|
||||
"4B3B0B",
|
||||
"433307",
|
||||
"3B2B07",
|
||||
"372300",
|
||||
"2F1B00",
|
||||
"271300",
|
||||
"1F0F00",
|
||||
"1B0B00",
|
||||
"FFFFA3",
|
||||
"FBF383",
|
||||
"F7E367",
|
||||
"F3D34F",
|
||||
"EFBB33",
|
||||
"EFA71B",
|
||||
"EB8F13",
|
||||
"E77B0F",
|
||||
"DF4F07",
|
||||
"D72300",
|
||||
"BF1F00",
|
||||
"A71B00",
|
||||
"931700",
|
||||
"7B1300",
|
||||
"631300",
|
||||
"4F0F00",
|
||||
"FFFF00",
|
||||
"FFBF00",
|
||||
"FF8300",
|
||||
"FF4700",
|
||||
"D32B00",
|
||||
"AB1700",
|
||||
"7F0700",
|
||||
"570000",
|
||||
"DFCBFF",
|
||||
"BB9FDF",
|
||||
"9B77BF",
|
||||
"7F579F",
|
||||
"673B7F",
|
||||
"4B235F",
|
||||
"33133F",
|
||||
"1B071F",
|
||||
"D3DBFF",
|
||||
"879FF7",
|
||||
"436FEF",
|
||||
"1747E7",
|
||||
"0B2BBB",
|
||||
"07178F",
|
||||
"000763",
|
||||
"000037",
|
||||
"7BFF77",
|
||||
"53DF4F",
|
||||
"33BF2B",
|
||||
"1B9F13",
|
||||
"1B7F0B",
|
||||
"175F07",
|
||||
"133F00",
|
||||
"0B1F00",
|
||||
"000000",
|
||||
"000000",
|
||||
"000000",
|
||||
"000000",
|
||||
"000000",
|
||||
"000000",
|
||||
"FFFBF0",
|
||||
"A0A0A4",
|
||||
"808080",
|
||||
"FF0000",
|
||||
"00FF00",
|
||||
"FFFF00",
|
||||
"0000FF",
|
||||
"FF00FF",
|
||||
"00FFFF",
|
||||
"FFFFFF"
|
||||
);
|
||||
|
||||
sub get_image
|
||||
{
|
||||
my ($idx) = @_;
|
||||
return "xc:#" . $palette[$idx] . "[4x4]";
|
||||
}
|
||||
|
||||
1;
|
||||
93
source/tools/springimport/TextureAtlas.pm
Normal file
93
source/tools/springimport/TextureAtlas.pm
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
package TextureAtlas;
|
||||
|
||||
# Incredibly rubbish texture packer
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Image::Magick;
|
||||
|
||||
sub new
|
||||
{
|
||||
my ($class, $width) = @_;
|
||||
my $self = {
|
||||
width => $width,
|
||||
x => 0,
|
||||
y => 0,
|
||||
rowheight => 0,
|
||||
images => {},
|
||||
};
|
||||
bless $self, $class;
|
||||
}
|
||||
|
||||
sub add
|
||||
{
|
||||
my ($self, $filename) = @_;
|
||||
return if $self->{images}{$filename};
|
||||
|
||||
my $img = new Image::Magick;
|
||||
$img->ReadImage($filename);
|
||||
my $w = $img->Get("width");
|
||||
my $h = $img->Get("height");
|
||||
|
||||
if ($filename =~ /\.tga$/i) {
|
||||
for my $y (0..$h-1) {
|
||||
for my $x (0..$w-1) {
|
||||
my @p = $img->GetPixel(x => $x, y => $y, channel => "RGBA");
|
||||
if ($p[0] == $p[2] and $p[1] == 0) {
|
||||
my $a = $p[0] * 1.5;
|
||||
$a = 0.95 if $a > 0.95; # prevent premul ugliness
|
||||
my $c = $a;
|
||||
$img->SetPixel(x => $x, y => $y, color => [$c,$c,$c,$a], channel => "RGBA");
|
||||
} else {
|
||||
$img->SetPixel(x => $x, y => $y, color => [$p[0],$p[1],$p[2],0], channel => "RGBA");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
die if $w > $self->{width};
|
||||
if ($self->{x} + $w > $self->{width}) {
|
||||
$self->{x} = 0;
|
||||
$self->{y} += $self->{rowheight};
|
||||
$self->{rowheight} = 0;
|
||||
}
|
||||
|
||||
$self->{images}{$filename} = { img => $img, w => $w, h => $h, x => $self->{x}, y => $self->{y} };
|
||||
|
||||
$self->{rowheight} = $h if $h > $self->{rowheight};
|
||||
$self->{x} += $w;
|
||||
}
|
||||
|
||||
sub finish
|
||||
{
|
||||
my ($self, $filename) = @_;
|
||||
|
||||
my $h = $self->{y} + $self->{rowheight};
|
||||
my $hlog = log($h)/log(2);
|
||||
$hlog = int($hlog+1) if $hlog != int($hlog);
|
||||
$h = 2**$hlog;
|
||||
$self->{height} = $h;
|
||||
|
||||
my $image = new Image::Magick;
|
||||
$image->Set(size => $self->{width}."x".$h, depth => 8);
|
||||
$image->ReadImage("xc:transparent");
|
||||
for my $t (values %{ $self->{images} }) {
|
||||
$image->Composite(image => $t->{img}, x => $t->{x}, y => $t->{y});
|
||||
}
|
||||
$image->Write($filename);
|
||||
}
|
||||
|
||||
sub get_texcoords
|
||||
{
|
||||
my ($self, $filename) = @_;
|
||||
my $t = $self->{images}{$filename} or die;
|
||||
return (
|
||||
$t->{x} / $self->{width},
|
||||
1 - ($t->{y} / $self->{height}),
|
||||
($t->{x} + $t->{w}) / $self->{width},
|
||||
1 - (($t->{y} + $t->{h}) / $self->{height}),
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
507
source/tools/springimport/convert.pl
Normal file
507
source/tools/springimport/convert.pl
Normal file
|
|
@ -0,0 +1,507 @@
|
|||
# Copyright (c) 2010 Wildfire Games
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
# This is a fairly hacky converter from the .3do format used by Spring
|
||||
# to the Collada + actor XML format used by 0 A.D.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Data::Dumper;
|
||||
|
||||
use TextureAtlas;
|
||||
use SpringPalette;
|
||||
|
||||
use constant SCALE => 3.0 / 1048576;
|
||||
|
||||
my $ROOT = "../../../binaries/data/mods/public";
|
||||
my $SOURCE = "../../../../../misc/spring/BA712";
|
||||
|
||||
sub parse_3do
|
||||
{
|
||||
my ($fh) = @_;
|
||||
|
||||
my $b;
|
||||
|
||||
read $fh, $b, 13*4 or die;
|
||||
my ($sig, $num_verts, $num_prims, $sel_prim, $x, $y, $z,
|
||||
$off_name, undef, $off_verts, $off_prims, $off_sib, $off_child) =
|
||||
unpack 'l*', $b;
|
||||
|
||||
die unless $sig == 1;
|
||||
|
||||
seek $fh, $off_name, 0;
|
||||
my $name = '';
|
||||
while (1) {
|
||||
read $fh, my $c, 1 or die;
|
||||
last if $c eq "\0";
|
||||
$name .= $c;
|
||||
}
|
||||
|
||||
seek $fh, $off_verts, 0;
|
||||
read $fh, $b, 12*$num_verts or die;
|
||||
my @verts = unpack 'l*', $b;
|
||||
|
||||
my @prims;
|
||||
for my $p (0..$num_prims-1) {
|
||||
seek $fh, $off_prims + 32*$p, 0;
|
||||
read $fh, $b, 32 or die;
|
||||
my ($palette, $num_idxs, undef, $off_idxs, $off_tex) = unpack 'l*', $b;
|
||||
|
||||
seek $fh, $off_idxs, 0;
|
||||
read $fh, $b, 2*$num_idxs or die;
|
||||
my @idxs = unpack 's*', $b;
|
||||
|
||||
my $texture;
|
||||
if ($off_tex) {
|
||||
$texture = '';
|
||||
seek $fh, $off_tex, 0;
|
||||
while (1) {
|
||||
read $fh, my $c, 1 or die;
|
||||
last if $c eq "\0";
|
||||
$texture .= $c;
|
||||
}
|
||||
}
|
||||
|
||||
push @prims, {
|
||||
palette => $palette,
|
||||
idxs => \@idxs,
|
||||
texture => $texture,
|
||||
};
|
||||
}
|
||||
|
||||
my $ret = {
|
||||
name => $name,
|
||||
verts => \@verts,
|
||||
prims => \@prims,
|
||||
offset => [$x, $y, $z],
|
||||
};
|
||||
|
||||
if ($off_child) {
|
||||
seek $fh, $off_child, 0;
|
||||
$ret->{children} = [ parse_3do($fh) ];
|
||||
}
|
||||
|
||||
if ($off_sib) {
|
||||
seek $fh, $off_sib, 0;
|
||||
return ($ret, parse_3do($fh));
|
||||
} else {
|
||||
return ($ret);
|
||||
}
|
||||
}
|
||||
|
||||
sub write_geometries
|
||||
{
|
||||
my ($obj, $atlas, $name, $fh) = @_;
|
||||
|
||||
my $num_verts = @{ $obj->{verts} } / 3;
|
||||
my $num_prims = @{ $obj->{prims} };
|
||||
|
||||
my @vertex_normals;
|
||||
for (0..$num_verts-1) {
|
||||
push @vertex_normals, [0,0,0];
|
||||
}
|
||||
|
||||
my @prim_normals;
|
||||
for my $prim (@{ $obj->{prims} }) {
|
||||
my @v0 = ($obj->{verts}[$prim->{idxs}[0]*3], $obj->{verts}[$prim->{idxs}[0]*3+1], $obj->{verts}[$prim->{idxs}[0]*3+2]);
|
||||
my @v1 = ($obj->{verts}[$prim->{idxs}[1]*3], $obj->{verts}[$prim->{idxs}[1]*3+1], $obj->{verts}[$prim->{idxs}[1]*3+2]);
|
||||
my @v2 = ($obj->{verts}[$prim->{idxs}[2]*3], $obj->{verts}[$prim->{idxs}[2]*3+1], $obj->{verts}[$prim->{idxs}[2]*3+2]);
|
||||
my @d10 = ($v1[0] - $v0[0], $v1[1] - $v0[1], $v1[2] - $v0[2]);
|
||||
my @d20 = ($v2[0] - $v0[0], $v2[1] - $v0[1], $v2[2] - $v0[2]);
|
||||
my @x = ($d10[1]*$d20[2] - $d10[2]*$d20[1], $d10[2]*$d20[0] - $d10[0]*$d20[2], $d10[0]*$d20[1] - $d10[1]*$d20[0]);
|
||||
my $d = sqrt($x[0]*$x[0] + $x[1]*$x[1] + $x[2]*$x[2]);
|
||||
my @n = $d ? ($x[0]/$d, $x[1]/$d, $x[2]/$d) : (0,1,0);
|
||||
push @prim_normals, \@n;
|
||||
for my $v (@{ $prim->{idxs} }) {
|
||||
$vertex_normals[$v][0] += $n[0];
|
||||
$vertex_normals[$v][1] += $n[1];
|
||||
$vertex_normals[$v][2] += $n[2];
|
||||
}
|
||||
}
|
||||
|
||||
for (0..$num_verts-1) {
|
||||
my @n = @{ $vertex_normals[$_] };
|
||||
my $d = sqrt($n[0]*$n[0] + $n[1]*$n[1] + $n[2]*$n[2]);
|
||||
$vertex_normals[$_] = $d ? [$n[0]/$d, $n[1]/$d, $n[2]/$d] : [0,0,0];
|
||||
}
|
||||
|
||||
print $fh <<EOF;
|
||||
<library_geometries>
|
||||
<geometry id="$name">
|
||||
<mesh>
|
||||
<source id="$name-Position">
|
||||
<float_array id="$name-Position-array" count="@{[ $num_verts*3 ]}">
|
||||
EOF
|
||||
|
||||
for my $n (0..$num_verts-1) {
|
||||
printf $fh "%.6f %.6f %.6f\n", $obj->{verts}[$n*3]*SCALE, $obj->{verts}[$n*3+1]*SCALE, $obj->{verts}[$n*3+2]*SCALE;
|
||||
}
|
||||
|
||||
print $fh <<EOF;
|
||||
</float_array>
|
||||
<technique_common>
|
||||
<accessor source="#$name-Position-array" count="$num_verts" stride="3">
|
||||
<param name="X" type="float"/>
|
||||
<param name="Y" type="float"/>
|
||||
<param name="Z" type="float"/>
|
||||
</accessor>
|
||||
</technique_common>
|
||||
</source>
|
||||
<source id="$name-Normal0">
|
||||
<float_array id="$name-Normal0-array" count="@{[ $num_verts*3 ]}">
|
||||
EOF
|
||||
|
||||
for my $n (0..$num_verts-1) {
|
||||
printf $fh "%.6f %.6f %.6f\n", @{$vertex_normals[$n]};
|
||||
}
|
||||
|
||||
my @uvs;
|
||||
for my $prim (@{ $obj->{prims} }) {
|
||||
my ($u0,$v0, $u1,$v1) = $atlas->get_texcoords(texture_filename($prim));
|
||||
if (@{ $prim->{idxs} } == 3) {
|
||||
push @uvs, $u0,$v0, $u0,$v1, $u1,$v1;
|
||||
} elsif (@{ $prim->{idxs} } == 4) {
|
||||
push @uvs, $u0,$v0, $u0,$v1, $u1,$v1, $u1,$v0;
|
||||
} else {
|
||||
push @uvs, ($u1,$v0) x @{ $prim->{idxs} };
|
||||
}
|
||||
}
|
||||
my $num_uvs = @uvs/2;
|
||||
|
||||
print $fh <<EOF;
|
||||
</float_array>
|
||||
<technique_common>
|
||||
<accessor source="#$name-Normal0-array" count="$num_verts" stride="3">
|
||||
<param name="X" type="float"/>
|
||||
<param name="Y" type="float"/>
|
||||
<param name="Z" type="float"/>
|
||||
</accessor>
|
||||
</technique_common>
|
||||
</source>
|
||||
<source id="$name-UV0">
|
||||
<float_array id="$name-UV0-array" count="@{[ $num_uvs*2 ]}">
|
||||
@uvs
|
||||
</float_array>
|
||||
<technique_common>
|
||||
<accessor source="#$name-UV0-array" count="$num_uvs" stride="2">
|
||||
<param name="S" type="float"/>
|
||||
<param name="T" type="float"/>
|
||||
</accessor>
|
||||
</technique_common>
|
||||
</source>
|
||||
<vertices id="$name-Vertex">
|
||||
<input semantic="POSITION" source="#$name-Position"/>
|
||||
</vertices>
|
||||
<polygons count="$num_prims">
|
||||
<input semantic="VERTEX" offset="0" source="#$name-Vertex"/>
|
||||
<input semantic="NORMAL" offset="1" source="#$name-Normal0"/>
|
||||
<input semantic="TEXCOORD" offset="2" set="0" source="#$name-UV0"/>
|
||||
EOF
|
||||
|
||||
my $i = 0;
|
||||
my $j = 0;
|
||||
for my $prim (@{ $obj->{prims} }) {
|
||||
print $fh "<p>";
|
||||
for (@{ $prim->{idxs} }) {
|
||||
print $fh "$_ $_ $j ";
|
||||
++$j;
|
||||
}
|
||||
++$i;
|
||||
print $fh "</p>\n";
|
||||
}
|
||||
|
||||
print $fh <<EOF;
|
||||
</polygons>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</library_geometries>
|
||||
EOF
|
||||
}
|
||||
|
||||
sub write_mesh
|
||||
{
|
||||
my ($obj, $atlas, $name, $fh) = @_;
|
||||
|
||||
print $fh <<EOF;
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.0">
|
||||
<asset>
|
||||
<unit meter="0.025400"/>
|
||||
<up_axis>Y_UP</up_axis>
|
||||
</asset>
|
||||
EOF
|
||||
|
||||
write_geometries($obj, $atlas, $name, $fh);
|
||||
|
||||
print $fh <<EOF;
|
||||
<library_visual_scenes>
|
||||
<visual_scene id="RootNode" name="RootNode">
|
||||
<node name="$name\_node">
|
||||
<instance_geometry url="#$name"/>
|
||||
</node>
|
||||
</visual_scene>
|
||||
</library_visual_scenes>
|
||||
<scene>
|
||||
<instance_visual_scene url="#RootNode"/>
|
||||
</scene>
|
||||
</COLLADA>
|
||||
EOF
|
||||
}
|
||||
|
||||
sub write_joint
|
||||
{
|
||||
my ($joint, $fh, $indent) = @_;
|
||||
|
||||
print $fh qq[$indent<node id="prop-$joint->{name}" name="prop-$joint->{name}" type="JOINT">\n];
|
||||
print $fh qq[$indent <translate>] . (sprintf "%.6f %.6f %.6f", map $_*SCALE, $joint->{offset}[0], $joint->{offset}[1], -$joint->{offset}[2]) . qq[</translate>\n];
|
||||
for my $c (@{ $joint->{children} }) {
|
||||
write_joint($c, $fh, "$indent ");
|
||||
}
|
||||
print $fh qq[$indent</node>\n];
|
||||
}
|
||||
|
||||
sub write_skeleton
|
||||
{
|
||||
my ($skeleton, $rootobj, $atlas, $name, $fh) = @_;
|
||||
|
||||
print $fh <<EOF;
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.0">
|
||||
<asset>
|
||||
<unit meter="0.025400"/>
|
||||
<up_axis>Y_UP</up_axis>
|
||||
</asset>
|
||||
EOF
|
||||
|
||||
write_geometries($rootobj, $atlas, $name, $fh);
|
||||
|
||||
print $fh <<EOF;
|
||||
<library_visual_scenes>
|
||||
<visual_scene id="RootNode">
|
||||
<node type="NODE" name="$name\_node">
|
||||
<rotate>0 1.0 0 180</rotate>
|
||||
<instance_geometry url="#$name"/>
|
||||
EOF
|
||||
|
||||
write_joint($_, $fh, " ") for @$skeleton;
|
||||
|
||||
print $fh <<EOF;
|
||||
</node>
|
||||
</visual_scene>
|
||||
</library_visual_scenes>
|
||||
<scene>
|
||||
<instance_visual_scene url="#RootNode"/>
|
||||
</scene>
|
||||
</COLLADA>
|
||||
EOF
|
||||
}
|
||||
|
||||
sub extract_joint_names
|
||||
{
|
||||
my ($joint) = @_;
|
||||
return ($joint->{name}, map { extract_joint_names($_) } @{ $joint->{children} });
|
||||
}
|
||||
|
||||
sub texture_filename
|
||||
{
|
||||
my ($prim) = @_;
|
||||
if ($prim->{texture}) {
|
||||
my $base = "$prim->{texture}";
|
||||
my @files = ("${base}.tga", "${base}00.tga", "${base}00.bmp", "${base}00.BMP");
|
||||
push @files, map { lc $_ } @files;
|
||||
@files = grep { -e "$SOURCE/unittextures/tatex/$_" } @files;
|
||||
die "can't find $prim->{texture}" unless @files;
|
||||
return "$SOURCE/unittextures/tatex/$files[0]";
|
||||
} else {
|
||||
return SpringPalette::get_image($prim->{palette});
|
||||
}
|
||||
}
|
||||
|
||||
sub write_skeleton_actor
|
||||
{
|
||||
my ($skeleton, $name, $fh) = @_;
|
||||
print $fh <<EOF;
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
|
||||
<castshadow/>
|
||||
|
||||
<group>
|
||||
<variant frequency="100" name="Base">
|
||||
<mesh>spring/$name.dae</mesh>
|
||||
<texture>spring/$name.tga</texture>
|
||||
<props>
|
||||
<prop actor="props/units/weapons/spear_gold.xml" attachpoint="projectile"/>
|
||||
EOF
|
||||
|
||||
my @joints = map { extract_joint_names($_) } @$skeleton;
|
||||
for my $n (@joints[1..$#joints]) {
|
||||
print $fh qq[ <prop actor="spring/$name-$n.xml" attachpoint="$n"/>\n];
|
||||
}
|
||||
|
||||
print $fh <<EOF;
|
||||
</props>
|
||||
</variant>
|
||||
</group>
|
||||
|
||||
<material>player_trans.xml</material>
|
||||
|
||||
</actor>
|
||||
EOF
|
||||
}
|
||||
|
||||
sub write_mesh_actor
|
||||
{
|
||||
my ($mesh, $prefix, $name, $fh) = @_;
|
||||
#warn Dumper $mesh;
|
||||
print $fh <<EOF;
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<actor version="1">
|
||||
|
||||
<castshadow/>
|
||||
|
||||
<group>
|
||||
<variant frequency="100" name="Base">
|
||||
<mesh>spring/$name.dae</mesh>
|
||||
<texture>spring/$prefix.tga</texture>
|
||||
</variant>
|
||||
</group>
|
||||
|
||||
<material>player_trans.xml</material>
|
||||
|
||||
</actor>
|
||||
EOF
|
||||
}
|
||||
|
||||
sub write_entity
|
||||
{
|
||||
my ($prefix, $fh) = @_;
|
||||
print $fh <<EOF;
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_unit_infantry_ranged">
|
||||
<Identity>
|
||||
<Civ>hele</Civ>
|
||||
<SpecificName>$prefix</SpecificName>
|
||||
</Identity>
|
||||
<Promotion>
|
||||
<Entity>???</Entity>
|
||||
</Promotion>
|
||||
<UnitMotion>
|
||||
<WalkSpeed>9.0</WalkSpeed>
|
||||
</UnitMotion>
|
||||
<VisualActor>
|
||||
<Actor>spring/$prefix.xml</Actor>
|
||||
</VisualActor>
|
||||
EOF
|
||||
|
||||
if ($prefix =~ /^(armaas|armbats|corcrus)$/) {
|
||||
print $fh <<EOF;
|
||||
<Position>
|
||||
<Floating>true</Floating>
|
||||
</Position>
|
||||
EOF
|
||||
}
|
||||
|
||||
print $fh <<EOF;
|
||||
</Entity>
|
||||
EOF
|
||||
}
|
||||
|
||||
sub extract_textures
|
||||
{
|
||||
my ($obj, $atlas) = @_;
|
||||
|
||||
my @meshes;
|
||||
my @prims = grep { @{ $_->{idxs} } >= 3 } @{ $obj->{prims} };
|
||||
|
||||
for (@prims) {
|
||||
$atlas->add(texture_filename($_));
|
||||
}
|
||||
|
||||
extract_textures($_, $atlas) for @{ $obj->{children} };
|
||||
}
|
||||
|
||||
sub extract_meshes
|
||||
{
|
||||
my ($obj) = @_;
|
||||
|
||||
my @prims = grep { @{ $_->{idxs} } >= 3 } @{ $obj->{prims} };
|
||||
|
||||
my @meshes;
|
||||
push @meshes, { name => $obj->{name}, verts => $obj->{verts}, prims => \@prims };
|
||||
push @meshes, map { extract_meshes($_) } @{ $obj->{children} };
|
||||
return @meshes;
|
||||
}
|
||||
|
||||
sub extract_skeleton
|
||||
{
|
||||
my ($obj) = @_;
|
||||
return { name => $obj->{name}, offset => $obj->{offset}, children => [ map { extract_skeleton($_) } @{ $obj->{children} } ] };
|
||||
}
|
||||
|
||||
sub write_model
|
||||
{
|
||||
my ($prefix, $model) = @_;
|
||||
|
||||
my $atlas = new TextureAtlas(256);
|
||||
extract_textures($model, $atlas);
|
||||
$atlas->finish("$ROOT/art/textures/skins/spring/$prefix.tga");
|
||||
|
||||
my @meshes = extract_meshes($model);
|
||||
#print Dumper \@meshes;
|
||||
|
||||
#exit;
|
||||
|
||||
my @skeleton = extract_skeleton($model);
|
||||
#print Dumper \@skeleton;
|
||||
|
||||
{
|
||||
open my $fhm, '>', "$ROOT/art/meshes/spring/$prefix.dae" or die $!;
|
||||
write_skeleton(\@skeleton, $meshes[0], $atlas, $prefix, $fhm);
|
||||
|
||||
open my $fha, '>', "$ROOT/art/actors/spring/$prefix.xml" or die $!;
|
||||
write_skeleton_actor(\@skeleton, $prefix, $fha);
|
||||
}
|
||||
|
||||
for my $mesh (@meshes[1..$#meshes]) {
|
||||
my $name = $prefix.'-'.$mesh->{name};
|
||||
open my $fhm, '>', "$ROOT/art/meshes/spring/$name.dae" or die $!;
|
||||
write_mesh($mesh, $atlas, $name, $fhm);
|
||||
|
||||
open my $fha, '>', "$ROOT/art/actors/spring/$name.xml" or die $!;
|
||||
write_mesh_actor($mesh, $prefix, $name, $fha);
|
||||
}
|
||||
|
||||
{
|
||||
open my $fhe, '>', "$ROOT/simulation/templates/spring/$prefix.xml" or die $!;
|
||||
write_entity($prefix, $fhe);
|
||||
}
|
||||
}
|
||||
|
||||
#for my $n (qw(armpw armcom KrogTaar armlab corak corlab)) {
|
||||
for my $n (map { (/.*\/(.*)\.3do/)[0] } grep /\/(cor|arm)[a-z]+\./, <$SOURCE/Objects3d/*.3do>) {
|
||||
print "$n\n";
|
||||
open my $t, "$SOURCE/Objects3d/$n.3do" or die "$n: $!";
|
||||
binmode $t;
|
||||
my $model = parse_3do($t);
|
||||
#print Dumper $model;
|
||||
write_model($n, $model);
|
||||
}
|
||||
Loading…
Reference in a new issue