One thing that's helped me is a perl script which ripped all the fragments and placed them in a nice grid level so I could browse and do mockups. I'll give you that script below. I also needed a few geometric shapes which weren't anywhere in the original game, mods, or the free shapes posted by people like cyberdyne and micr0chip. For that I've figured out how to get Blender to export useful vertex and triangle list data. Blender is a free, open source modelling program available for all platforms. http://www.blender.org I'll tell you what little I know.
Let's start with Blender. I don't have a direct Blender --> .shp exporter, although that would be simple to do if you know Python since Blender has an embeded Python scripting engine. I was looking to see which existing export formats would have useful vertex and triangle lists, so I tried 'em all. In Blender 2.43 you can export a mesh to a SoftImage XSI file, and with a few simple text edits you can paste the data into an existing .shp file and be done. Very simple.
I don't know much about the magic of Blender, but I'll walk you through getting an icosohedron into a .shp file. Launch Blender and select Add > Mesh > IcoSphere and click the popup button down to 1 "Subdivision". You'll see a tiny mesh appear inside the starter cube. You could scale and edit the mesh. If you do, you will be in "Edit Mode". Before you can export the XSI format you must always remember to return to "Object Mode". There are sveral ways to do this -- a dropdown selector appears along the bottom edge of the viewport.
For kicks, let's scale the icosohedron. New meshes start out at unit size, so they'll be tiny in Darwinia. With the cursor in the viewport hit the "S" key and drag the mouse. The amount of scaling available depends on the relative positions of the mouse and selected object when you hit the "S" key. You can always undo mesh edits with the "U" key, but again, be sure the cursor is inside the viewport. Blender uses all the mouse buttons in context sensitive combinations. It's confusing at first. But since we spent all of 3 seconds creating this mesh, do as I did and choose File > New whenever you get into a bind. Read the Blender Quick Start Tutorial, it's good.
Once back in Object Mode, choose File > Export > SoftImage XSI and work the file dialog to put the file where you want it. We're done with Blender. Fire up your favorite text editor and load both the .xsi file and a .shp file. Your life will be easier if you start with a large .shp fragment. The one I like to use is the sphere out of micr0chip's engineer model (google "darwinia micr0chip" with a zero in the name.) It has >400 vertices and all the vertex mappings and colours are in numerical order. This means we can simply paste in our Blender data and tidy up. The .xsi verices are all in order, and the triangle lists use them in order.
So you're looking at the .xsi text file and the vertex coordinates are in a section that looks like this:
Code: Select all
SI_Mesh MSH-Sphere {
SI_Shape SHP-Sphere-ORG {
2,
"ORDERED",
12,
"POSITION",
0.000000,-0.000000,-9.902285,
7.165293,-5.205829,-4.428450,
-2.736843,-8.423280,-4.428450,
-8.856851,-0.000000,-4.428450,
-2.736843,8.423280,-4.428450,
7.165293,5.205829,-4.428450,
2.736843,-8.423280,4.428450,
-7.165293,-5.205829,4.428450,
-7.165293,5.205829,4.428450,
2.736843,8.423280,4.428450,
8.856851,-0.000000,4.428450,
0.000000,-0.000000,9.902285,
You can cut and paste the coordinate list into the Positions list in your .shp file and then type the "1:" "2:" etc. in front of each line. Or if your editor supports block selections you can clear the coords from the .shp file and then paste the coords into the rectangular area after the position numbers. The total number of Positions is the "12" just above the word "POSITION" in the .xsi file. The Vertices list takes the same count.
If you chose to start with cyberdyne's sphere fragment, then you can simply edit the Vertices list to the right length. The .xsi data is all used in-order. Otherwise you can use block select to make two copies of your position numbers and then add the colour index column by hand.
And finally for the triangle list, you' see the following section in the .xsi file:
Code: Select all
SI_TriangleList Sphere {
20,
"NORMAL",
"",
2,0,1,
1,0,5,
3,0,2,
4,0,3,
5,0,4,
1,5,10,
2,1,6,
3,2,7,
4,3,8,
5,4,9,
10,6,1,
6,7,2,
7,8,3,
8,9,4,
9,10,5,
6,10,11,
7,6,11,
8,7,11,
9,8,11,
10,9,11,
Just cut and paste into the Triangles section of your .shp and use the "20" count listed above the word "NORMAL". You only want the first block of triangle tuples. The second block (not shown here) is pretty useless.
[There's only two things left to do.] EDIT: Darwinia is perfectly happy with the trailing commas everywhere, and the comma delimited coordinate list, so there is nothing else to do. Just cut & paste! So skip this: [First you need to search and replace the commas in the coordinate data. Darwinia uses whitespace separators. Second you need to remove all the trailing commas from the triangle list. You can do this by hand, or if your editor supports regular expressions, you can do something like ",$" --> "" where the quotes are not to be typed in.]
If your shape file crashes Darwinia, check that you properly set all the counts at the beginning of the Positions:, Vertices: and Triangles: sections. I always forget to set the Vertices count because of the way I go about this.
Also note that the .xsi file will have a section called "Cube". This is the annoying little cube that appears in every new Blender scene. If you made a complex scene there would be one section for every Object you created. There is probably a way to merge objects in Blender so they produce a single triangle list when exported. I don't know how. I only wanted a few simple things.
You're done! As you can see the steps for taking an .xsi export file and producing a .shp file are pretty trivial. I'm sure a perl script could be hacked together in a few minutes. Or a python exporter for use from within Blender. If anyone gets ambitious, please share!
Here's the final icosahedron shape file:
Code: Select all
Fragment: Icosahedron
ParentName: sceneroot
up: 0.00 1.00 0.00
front: 0.00 0.00 1.00
pos: 0.00 20.00 0.00
Positions: 12
0: 0.000000 -0.000000 -9.902285
1: 7.165293 -5.205829 -4.428450
2: -2.736843 -8.423280 -4.428450
3: -8.856851 -0.000000 -4.428450
4: -2.736843 8.423280 -4.428450
5: 7.165293 5.205829 -4.428450
6: 2.736843 -8.423280 4.428450
7: -7.165293 -5.205829 4.428450
8: -7.165293 5.205829 4.428450
9: 2.736843 8.423280 4.428450
10: 8.856851 -0.000000 4.428450
11: 0.000000 -0.000000 9.902285
Normals: 0
Colours: 1
0: 128 128 128
Vertices: 12
0: 0 0
1: 1 0
2: 2 0
3: 3 0
4: 4 0
5: 5 0
6: 6 0
7: 7 0
8: 8 0
9: 9 0
10: 10 0
11: 11 0
Triangles: 20
2,0,1
1,0,5
3,0,2
4,0,3
5,0,4
1,5,10
2,1,6
3,2,7
4,3,8
5,4,9
10,6,1
6,7,2
7,8,3
8,9,4
9,10,5
6,10,11
7,6,11
8,7,11
9,8,11
10,9,11
EDIT: Blender and Darwinia apparently use different axis orientations. If you want the shape to appear in the same orientation as in Blender, replace the fragment header with the following:
Code: Select all
Fragment: Icosahedron
ParentName: sceneroot
up: 0.00 0.00 1.00
front: 0.00 1.00 0.00
pos: 0.00 20.00 0.00
OK, now for the perl script which extracts fragments from existing .shp files:
Code: Select all
#!/usr/bin/perl
@shpfiles = <*.shp>;
$i = 0;
open LISTFILE, ">", "shapelist.txt";
foreach $shpfile (@shpfiles) { if (not $shpfile =~ /zfrag/) {
open INFILE, "<", $shpfile;
{
local $/; #slurp mode
$shp = <INFILE>;
} #exit local slurp mode
close INFILE;
#for Windows machines, comment this line out!!
$shp =~ s/\r//g;
#for Windows machines, comment this line out!!
$shp .= "\nEOF\n"; # to catch last frag
@frags = $shp =~ /Fragment .*? (?=^\w)/xgmsi;
foreach $frag (@frags) {
$frag =~ /\s+ Positions (.*?) (?=^\s+ Normals)/xgmsi;
$coords = $1;
@xcoords = $coords =~ /\d+: \s+ (\-?\d+\.?\d*) \s+ \-?\d+\.?\d* \s+ \-?\d+\.?\d* /gx;
@ycoords = $coords =~ /\d+: \s+ \-?\d+\.?\d* \s+ (\-?\d+\.?\d*) \s+ \-?\d+\.?\d* /gx;
@zcoords = $coords =~ /\d+: \s+ \-?\d+\.?\d* \s+ \-?\d+\.?\d* \s+ (\-?\d+\.?\d*)/gx;
if ($#xcoords == -1 or $#ycoords == -1 or $#zcoords == -1 ) {
print "dropped frag from $shpfile : no coords\n";
next;
}
$min = 9999; $max = -9999;
foreach $c (@xcoords) {
$min = $c if $c < $min; $max = $c if $c > $max;
} $spanx = $max - $min;
$min = 9999; $max = -9999;
foreach $c (@ycoords) {
$min = $c if $c < $min; $max = $c if $c > $max;
} $spany = $max - $min; $miny = $min;
$min = 9999; $max = -9999;
foreach $c (@zcoords) {
$min = $c if $c < $min; $max = $c if $c > $max;
} $spanz = $max - $min;
#print "$spanx $spanz ($shpfile)\n";
$maxspan = $spanx < $spanz ? $spanz : $spanx;
$maxspan = $spany < $maxspan ? $maxspan : $spany;
if ($maxspan == 0) {
print "dropped frag from $shpfile : zero span\n";
next;
}
$scale = 100 / $maxspan;
if ($scale > 100) { $scale = 100; }
$cx = 0; $cy = 0; $cz = 0;
foreach $c (@xcoords) { $cx += $c }
foreach $c (@ycoords) { $cy += $c }
foreach $c (@zcoords) { $cz += $c }
$cx = -($cx / ($#xcoords + 1)) ;
$cz = -($cz / ($#zcoords + 1)) ;
$cy = -($cy / ($#ycoords + 1)) + (-$miny + 100) / $scale;
$cx = sprintf "%.3f", $cx;
$cy = sprintf "%.3f", $cy;
$cz = sprintf "%.3f", $cz;
$frag =~ s/ParentName: \s+ .*/ParentName: sceneroot/xm;
$frag =~ s/^\s+ up: .*/\t up: 0.00 1.00 0.00/xm;
$frag =~ s/^\s+ front: .*/\t front: 0.00 0.00 1.00/xm;
$frag =~ s/^\s+ pos: .*/\t pos: $cx $cy $cz /xm;
$fragshp = "zfrag$i.shp";
open OUTFILE, ">", $fragshp;
print OUTFILE $frag, "\n\n";
$x = 500 + 140 * ($i % 28);
$z = 500 + 140 * int($i / 28);
$scale = sprintf "%.3f", $scale;
print LISTFILE "\t StaticShape $i $x $z 1 0.00 0.00 0 $scale $fragshp \n";
$i++
}
}}
First off, I am not a professional programmer, or even a good one. This is just code that works for me. You're free to clean it up if you like. If it's broken, I'll try to help you get it working.
To use this, place it in a subdirectory with all your shape files. Please do me and yourself a favor: make a copy of all your shapes in a new subdirectory. Then run "perl shapelist.pl" there, with no arguments. It will scan all the .shp files in the current working directory and do two things. It will output one shape file for each fragment it finds. These will be called "zfrag000", etc. And it will output a file called "shapelist.txt" which contains StaticShape lines for your map file. Just cut and paste.
The program assumes your map will be 5000 x 5000. You don't need any land tiles since the fragments will be positioned to float in space. Each fragment is scaled to fit the nice grid, so tiny fragments will appear huge and huge fragments kinda small. There are a few fragments which appear way up in the air. I never figured out what was wrong with my spaghetti code. AND there are some homemade shapes that the program cannot parse. I think Trickfred's mushroom is one. These just get discarded from the fragments list.
***IF YOU ARE USING WINDOWS: you must comment out the line that says so near the beginning of the script file. (Place a # in front of it, just like the lines around it.) I'm using linux and the end-of-line conventions differ. If your zfrag000.shp files are all on one line in your text editor... you didn't comment out this line, and you need to.
That's it for now. Happy modding!