- added glexemel to svn and CMake builds
- updated the G3D import script to properly bring in animations into Blender!
This commit is contained in:
parent
a8f982ad2b
commit
ada4140d84
|
@ -130,9 +130,15 @@ ENDIF()
|
|||
|
||||
ADD_SUBDIRECTORY( source/shared_lib )
|
||||
ADD_SUBDIRECTORY( source/glest_game )
|
||||
ADD_SUBDIRECTORY( source/glest_map_editor )
|
||||
ADD_SUBDIRECTORY( source/g3d_viewer )
|
||||
ADD_SUBDIRECTORY( source/configurator )
|
||||
#if(wxWidgets_FOUND)
|
||||
ADD_SUBDIRECTORY( source/glest_map_editor )
|
||||
ADD_SUBDIRECTORY( source/g3d_viewer )
|
||||
ADD_SUBDIRECTORY( source/configurator )
|
||||
#else()
|
||||
# MESSAGE(STATUS "WARNING... the following game tools will NOT be built since we cannot find wxWidgets on this machine")
|
||||
# MESSAGE(STATUS "map editor, g3d viewer, configurator")
|
||||
#endif()
|
||||
ADD_SUBDIRECTORY( source/tools/glexemel )
|
||||
|
||||
IF(APPLE)
|
||||
include(mk/macosx/CMakeLists.txt)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# glexemel
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/source/tools/glexemel)
|
||||
add_executable(g2xml g2xml.c g3dv4.h)
|
||||
|
||||
find_package(LibXml2)
|
||||
IF(LIBXML2_FOUND)
|
||||
include_directories(${LIBXML2_INCLUDE_DIR})
|
||||
add_executable(xml2g xml2g.c g3dv4.h)
|
||||
target_link_libraries(xml2g ${LIBXML2_LIBRARIES})
|
||||
ELSE()
|
||||
MESSAGE(STATUS "WARNING... xml2g will NOT be built since we cannot find libXml2 on this machine")
|
||||
ENDIF()
|
|
@ -0,0 +1,340 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,11 @@
|
|||
Sorry - no autotools support (yet!).
|
||||
|
||||
You will need:
|
||||
1) GNU Make (or an equivalent).
|
||||
2) An ANSI C compiler (eg: gcc).
|
||||
3) libxml2 (http://xmlsoft.org) - the XML parser for GNOME.
|
||||
|
||||
Just copy Makefile.linux to Makefile:
|
||||
$ cp Makefile.linux Makefile
|
||||
Then edit Makefile to suit your needs (it's *very* simple).
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# You need to edit this Makefile for your specific platform
|
||||
|
||||
# CC is the name of your C compiler
|
||||
CC=gcc
|
||||
# CFLAGS are the flags that you want to pass to the C compiler
|
||||
CFLAGS=-Wall -ansi -pedantic
|
||||
# IDIRS specify the include directories to use
|
||||
IDIRS=-I/usr/include/libxml2
|
||||
# LIBS specify the libraries (libxml2)
|
||||
LIBS=-lxml2
|
||||
# INSTALLDIR specifies the directory to which the binaries should be installed
|
||||
INSTALLDIR=/usr/local/bin
|
||||
# CP specifies the copy command for the system
|
||||
CP=cp
|
||||
|
||||
all: g2xml xml2g
|
||||
|
||||
g2xml:
|
||||
${CC} ${CFLAGS} ${IDIRS} g2xml.c -o g2xml ${LIBS}
|
||||
|
||||
xml2g:
|
||||
${CC} ${CFLAGS} ${IDIRS} xml2g.c -o xml2g ${LIBS}
|
||||
|
||||
install:
|
||||
${CP} g2xml ${INSTALLDIR}/.
|
||||
${CP} xml2g ${INSTALLDIR}/.
|
||||
${CP} g3d.dtd ${INSTALLDIR}/.
|
||||
|
||||
clean:
|
||||
rm -f g2xml xml2g
|
|
@ -0,0 +1,13 @@
|
|||
=== GLEXEMEL ===
|
||||
An XML format for the G3D file format used by the game Glest:
|
||||
http://www.glest.org
|
||||
|
||||
This XML format allows for exporters to create XML file descriptions that
|
||||
can then be converted to binary.
|
||||
|
||||
Note: This package is not yet part of Glest, although it is offered for
|
||||
inclusion should the developers wish.
|
||||
|
||||
Copyright (C) Jonathan Merritt 2005.
|
||||
This package may be distributed under the terms of the GNU General Public
|
||||
License (see the file COPYING for more details).
|
|
@ -0,0 +1,362 @@
|
|||
/**
|
||||
* File: g2xml.c
|
||||
* Written: Jonathan Merritt <jmerritt@warpax.com>
|
||||
*
|
||||
* Description:
|
||||
* Converts G3D format files into an XML representation.
|
||||
*
|
||||
* Copyright (C) Jonathan Merritt 2005.
|
||||
* This file may be distributed under the terms of the GNU General Public
|
||||
* License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "g3dv4.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Forward function declarations.
|
||||
*/
|
||||
int g3d2xml(FILE *infile, FILE *outfile);
|
||||
void usage(char *execname);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param argc: Number of arguments passed to the program.
|
||||
* @param argv: Array of string arguments.
|
||||
*
|
||||
* @returns: EXIT_SUCCESS or EXIT_FAILURE depending upon success or failure
|
||||
* of the conversion to XML.
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *infilename, *outfilename;
|
||||
FILE *infile, *outfile;
|
||||
int successFlag;
|
||||
|
||||
/* parse command line arguments */
|
||||
if (argc != 3)
|
||||
{
|
||||
usage(argv[0]);
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
infilename = argv[1];
|
||||
outfilename = argv[2];
|
||||
}
|
||||
|
||||
/* attempt to open the input and output files */
|
||||
infile = fopen(infilename, "rb");
|
||||
if (infile == NULL)
|
||||
{
|
||||
printf("Could not open file \"%s\" for binary reading.\n",
|
||||
infilename);
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
outfile = fopen(outfilename, "w");
|
||||
if (outfile == NULL)
|
||||
{
|
||||
printf("Could not open file \"%s\" for writing.\n",
|
||||
outfilename);
|
||||
fclose(infile);
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* perform the XML conversion */
|
||||
successFlag = g3d2xml(infile, outfile);
|
||||
|
||||
/* close the two files */
|
||||
fclose(infile);
|
||||
fclose(outfile);
|
||||
|
||||
/* return a success or failure flag */
|
||||
if (successFlag)
|
||||
return (EXIT_SUCCESS);
|
||||
else
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Prints a "Usage:" string for the program.
|
||||
*
|
||||
* @param execname: Executable name of the program.
|
||||
*/
|
||||
void usage(char *execname)
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf(" %s infile.g3d outfile.xml\n", execname);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Performs the conversion from the G3D file format to XML.
|
||||
*
|
||||
* @param infile: G3D binary file, opened as "rb", for input.
|
||||
* @param outfile: Text file, opened as "w", for XML output.
|
||||
*
|
||||
* @returns: TRUE if conversion to XML was successful, and FALSE otherwise.
|
||||
*/
|
||||
int g3d2xml(FILE *infile, FILE *outfile)
|
||||
{
|
||||
struct FileHeader fileHeader;
|
||||
struct ModelHeader modelHeader;
|
||||
struct MeshHeader meshHeader;
|
||||
size_t nBytes;
|
||||
uint8 textureName[NAMESIZE];
|
||||
float32 *fdata;
|
||||
uint32 *idata;
|
||||
int ii, jj, kk;
|
||||
|
||||
/* read in the FileHeader */
|
||||
nBytes = sizeof(struct FileHeader);
|
||||
if (fread(&fileHeader, nBytes, 1, infile) != 1)
|
||||
{
|
||||
printf("Could not read file header!\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (strncmp((char*)fileHeader.id, "G3D", 3) != 0)
|
||||
{
|
||||
printf("Expected \"G3D\" id was not found!\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (fileHeader.version != 4)
|
||||
{
|
||||
printf("Version 4 expected, but version %d found!\n",
|
||||
fileHeader.version);
|
||||
return FALSE;
|
||||
}
|
||||
fprintf(outfile, "<?xml version=\"1.0\" encoding=\"ASCII\" ?>\n");
|
||||
fprintf(outfile, "<!DOCTYPE G3D SYSTEM \"g3d.dtd\">\n");
|
||||
fprintf(outfile, "<!--\n");
|
||||
fprintf(outfile, "\tThis file is an XML encoding of a G3D binary\n");
|
||||
fprintf(outfile, "\tfile. The XML format is by Jonathan Merritt\n");
|
||||
fprintf(outfile, "\t(not yet accepted as part of Glest!).\n");
|
||||
fprintf(outfile, "-->\n");
|
||||
fprintf(outfile, "<G3D version=\"%d\">\n", fileHeader.version);
|
||||
|
||||
/* read in the ModelHeader */
|
||||
nBytes = sizeof(struct ModelHeader);
|
||||
if (fread(&modelHeader, nBytes, 1, infile) != 1)
|
||||
{
|
||||
printf("Could not read model header!\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (modelHeader.type != mtMorphMesh)
|
||||
{
|
||||
printf("Unrecognized mesh type!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* read in the meshes */
|
||||
for (ii = 0; ii < modelHeader.meshCount; ii++)
|
||||
{
|
||||
/* read in the MeshHeader */
|
||||
nBytes = sizeof(struct MeshHeader);
|
||||
if (fread(&meshHeader, nBytes, 1, infile) != 1)
|
||||
{
|
||||
printf("Could not read mesh header!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* write out XML mesh header */
|
||||
fprintf(outfile, "\t<Mesh name=\"%s\" ", meshHeader.name);
|
||||
fprintf(outfile, "frameCount=\"%d\" ", meshHeader.frameCount);
|
||||
fprintf(outfile, "vertexCount=\"%d\" ",
|
||||
meshHeader.vertexCount);
|
||||
fprintf(outfile, "indexCount=\"%d\" ", meshHeader.indexCount);
|
||||
fprintf(outfile, "specularPower=\"%f\" ",
|
||||
meshHeader.specularPower);
|
||||
fprintf(outfile, "opacity=\"%f\" ", meshHeader.opacity);
|
||||
if (meshHeader.properties & (0x1 << mpfTwoSided))
|
||||
fprintf(outfile, "twoSided=\"true\" ");
|
||||
else
|
||||
fprintf(outfile, "twoSided=\"false\" ");
|
||||
if (meshHeader.properties & (0x1 << mpfCustomColor))
|
||||
fprintf(outfile, "customColor=\"true\" ");
|
||||
else
|
||||
fprintf(outfile, "customColor=\"false\" ");
|
||||
if (meshHeader.textures)
|
||||
fprintf(outfile, "diffuseTexture=\"true\"");
|
||||
else
|
||||
fprintf(outfile, "diffuseTexture=\"false\"");
|
||||
fprintf(outfile, ">\n");
|
||||
|
||||
/* write out diffuse and specular colors */
|
||||
fprintf(outfile, "\t\t<Diffuse>\n");
|
||||
fprintf(outfile, "\t\t\t<Color r=\"%f\" g=\"%f\" b=\"%f\"/>\n",
|
||||
meshHeader.diffuseColor[0],
|
||||
meshHeader.diffuseColor[1],
|
||||
meshHeader.diffuseColor[2]);
|
||||
fprintf(outfile, "\t\t</Diffuse>\n");
|
||||
fprintf(outfile, "\t\t<Specular>\n");
|
||||
fprintf(outfile, "\t\t\t<Color r=\"%f\" g=\"%f\" b=\"%f\"/>\n",
|
||||
meshHeader.specularColor[0],
|
||||
meshHeader.specularColor[1],
|
||||
meshHeader.specularColor[2]);
|
||||
fprintf(outfile, "\t\t</Specular>\n");
|
||||
|
||||
/* read / write the texture name if present */
|
||||
if (meshHeader.textures)
|
||||
{
|
||||
nBytes = sizeof(textureName);
|
||||
if (fread(&textureName, nBytes, 1, infile) != 1)
|
||||
{
|
||||
printf("Could not read texture name!\n");
|
||||
return FALSE;
|
||||
}
|
||||
fprintf(outfile, "\t\t<Texture name=\"%s\"/>\n",
|
||||
textureName);
|
||||
}
|
||||
|
||||
/* read / write each set of vertex data */
|
||||
for (jj=0; jj < meshHeader.frameCount; jj++)
|
||||
{
|
||||
nBytes = sizeof(float32)*meshHeader.vertexCount*3;
|
||||
fdata = malloc(nBytes);
|
||||
if (fdata == NULL)
|
||||
{
|
||||
printf("Could not allocate buffer!\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (fread(fdata, nBytes, 1, infile) != 1)
|
||||
{
|
||||
printf("Could not read vertex data!\n");
|
||||
free(fdata);
|
||||
return FALSE;
|
||||
}
|
||||
fprintf(outfile, "\t\t<Vertices frame=\"%d\">\n",
|
||||
jj);
|
||||
for (kk=0; kk < meshHeader.vertexCount; kk++)
|
||||
{
|
||||
fprintf(outfile, "\t\t\t<Vertex ");
|
||||
/*fprintf(outfile, "i=\"%d\" ",
|
||||
kk);*/
|
||||
fprintf(outfile, "x=\"%f\" ",
|
||||
fdata[3*kk]);
|
||||
fprintf(outfile, "y=\"%f\" ",
|
||||
fdata[3*kk+1]);
|
||||
fprintf(outfile, "z=\"%f\"/>\n",
|
||||
fdata[3*kk+2]);
|
||||
}
|
||||
fprintf(outfile, "\t\t</Vertices>\n");
|
||||
free(fdata);
|
||||
}
|
||||
|
||||
/* read / write each set of normal data */
|
||||
for (jj=0; jj < meshHeader.frameCount; jj++)
|
||||
{
|
||||
nBytes = sizeof(float32)*meshHeader.vertexCount*3;
|
||||
fdata = malloc(nBytes);
|
||||
if (fdata == NULL)
|
||||
{
|
||||
printf("Could not allocate buffer!\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (fread(fdata, nBytes, 1, infile) != 1)
|
||||
{
|
||||
printf("Could not read normal data!\n");
|
||||
free(fdata);
|
||||
return FALSE;
|
||||
}
|
||||
fprintf(outfile, "\t\t<Normals frame=\"%d\">\n",
|
||||
jj);
|
||||
for (kk=0; kk < meshHeader.vertexCount; kk++)
|
||||
{
|
||||
fprintf(outfile, "\t\t\t<Normal ");
|
||||
/*fprintf(outfile, "i=\"%d\" ",
|
||||
kk);*/
|
||||
fprintf(outfile, "x=\"%f\" ",
|
||||
fdata[3*kk]);
|
||||
fprintf(outfile, "y=\"%f\" ",
|
||||
fdata[3*kk+1]);
|
||||
fprintf(outfile, "z=\"%f\"/>\n",
|
||||
fdata[3*kk+2]);
|
||||
}
|
||||
fprintf(outfile, "\t\t</Normals>\n");
|
||||
free(fdata);
|
||||
}
|
||||
|
||||
/* read / write texture coordinates */
|
||||
if (meshHeader.textures)
|
||||
{
|
||||
nBytes = sizeof(float32)*meshHeader.vertexCount*2;
|
||||
fdata = malloc(nBytes);
|
||||
if (fdata == NULL)
|
||||
{
|
||||
printf("Could not allocate buffer!\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (fread(fdata, nBytes, 1, infile) != 1)
|
||||
{
|
||||
printf("Could not read texture coords!\n");
|
||||
free(fdata);
|
||||
return FALSE;
|
||||
}
|
||||
fprintf(outfile, "\t\t<TexCoords>\n");
|
||||
for (kk=0; kk < meshHeader.vertexCount; kk++)
|
||||
{
|
||||
fprintf(outfile, "\t\t\t<ST ");
|
||||
/*fprintf(outfile, "i=\"%d\" ",
|
||||
kk);*/
|
||||
fprintf(outfile, "s=\"%f\" ",
|
||||
fdata[2*kk]);
|
||||
fprintf(outfile, "t=\"%f\"/>\n",
|
||||
fdata[2*kk+1]);
|
||||
}
|
||||
fprintf(outfile, "\t\t</TexCoords>\n");
|
||||
free(fdata);
|
||||
}
|
||||
|
||||
/* read / write face indices */
|
||||
nBytes = sizeof(uint32)*meshHeader.indexCount;
|
||||
idata = malloc(nBytes);
|
||||
if (idata == NULL)
|
||||
{
|
||||
printf("Could not allocate buffer!\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (fread(idata, nBytes, 1, infile) != 1)
|
||||
{
|
||||
printf("Could not read indexes!\n");
|
||||
free(idata);
|
||||
return FALSE;
|
||||
}
|
||||
fprintf(outfile, "\t\t<Indices>\n");
|
||||
for (kk=0; kk < meshHeader.indexCount; kk++)
|
||||
{
|
||||
fprintf(outfile, "\t\t\t<Ix i=\"%d\"/>\n",
|
||||
idata[kk]);
|
||||
}
|
||||
fprintf(outfile, "\t\t</Indices>\n");
|
||||
free(idata);
|
||||
|
||||
fprintf(outfile, "\t</Mesh>\n");
|
||||
}
|
||||
|
||||
fprintf(outfile, "</G3D>\n");
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="ASCII" ?>
|
||||
|
||||
<!--
|
||||
A DTD for describing an XML representation of G3D version 4 files.
|
||||
|
||||
Created by Jonathan Merritt <jmerritt@warpax.com>
|
||||
Copyright (C) Jonathan Merritt 2005.
|
||||
|
||||
This DTD may be distributed under the terms of the GNU General Public
|
||||
License.
|
||||
-->
|
||||
|
||||
<!ELEMENT G3D (Mesh+)>
|
||||
<!ATTLIST G3D version CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT Mesh
|
||||
(Diffuse,Specular,Texture?,Vertices+,Normals+,TexCoords?,Indices)>
|
||||
<!ATTLIST Mesh name CDATA #REQUIRED>
|
||||
<!ATTLIST Mesh frameCount CDATA #REQUIRED>
|
||||
<!ATTLIST Mesh vertexCount CDATA #REQUIRED>
|
||||
<!ATTLIST Mesh indexCount CDATA #REQUIRED>
|
||||
<!ATTLIST Mesh specularPower CDATA #REQUIRED>
|
||||
<!ATTLIST Mesh opacity CDATA #REQUIRED>
|
||||
<!ATTLIST Mesh twoSided (true|false) #REQUIRED>
|
||||
<!ATTLIST Mesh customColor (true|false) #REQUIRED>
|
||||
<!ATTLIST Mesh diffuseTexture (true|false) #REQUIRED>
|
||||
|
||||
<!ELEMENT Diffuse (Color)>
|
||||
|
||||
<!ELEMENT Specular (Color)>
|
||||
|
||||
<!ELEMENT Color EMPTY>
|
||||
<!ATTLIST Color r CDATA #REQUIRED>
|
||||
<!ATTLIST Color g CDATA #REQUIRED>
|
||||
<!ATTLIST Color b CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT Texture EMPTY>
|
||||
<!ATTLIST Texture name CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT Vertices (Vertex+)>
|
||||
<!ATTLIST Vertices frame CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT Vertex EMPTY>
|
||||
<!ATTLIST Vertex x CDATA #REQUIRED>
|
||||
<!ATTLIST Vertex y CDATA #REQUIRED>
|
||||
<!ATTLIST Vertex z CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT Normals (Normal+)>
|
||||
<!ATTLIST Normals frame CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT Normal EMPTY>
|
||||
<!ATTLIST Normal x CDATA #REQUIRED>
|
||||
<!ATTLIST Normal y CDATA #REQUIRED>
|
||||
<!ATTLIST Normal z CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT TexCoords (ST+)>
|
||||
|
||||
<!ELEMENT ST EMPTY>
|
||||
<!ATTLIST ST s CDATA #REQUIRED>
|
||||
<!ATTLIST ST t CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT Indices (Ix+)>
|
||||
|
||||
<!ELEMENT Ix EMPTY>
|
||||
<!ATTLIST Ix i CDATA #REQUIRED>
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
|
@ -0,0 +1,507 @@
|
|||
#!BPY
|
||||
"""
|
||||
Name: 'G3D Fileformat Im/Exporter'
|
||||
Blender: 237
|
||||
Group: 'Wizards'
|
||||
Tooltip: 'Imports and Exports the Glest fileformat V3/V4 (.g3d)'
|
||||
"""
|
||||
###########################################################################
|
||||
# Glest Model / Texture / UV / Animation Importer and Exporter
|
||||
# for the Game Glest that u can find http://www.glest.org
|
||||
# copyright 2005 By Andreas Becker (seltsamuel@yahoo.de)
|
||||
#
|
||||
# Updated Jan 2011 by Mark Vejvoda (SoftCoder) to properly import animations
|
||||
# from G3D into Blender
|
||||
#
|
||||
# Started Date: 07 June 2005 Put Public 20 June 2005
|
||||
# Ver: 0.01 Beta Exporter ripped off because work in Progress
|
||||
# Distributed under the GNU PUBLIC LICENSE for www.megaglest.org and glest.org
|
||||
###########################################################################
|
||||
#NOTE:
|
||||
# Copy this Script AND g3d_logo.png into .Blender\scripts
|
||||
# directory then start inside blender Scripts window
|
||||
# "Update Menus" after that this Script here is accesible
|
||||
# as 'Wizards' G3d Fileformat Im/Exporter
|
||||
#ToDo:
|
||||
#Exporter Bughunt he will be rejoined next release
|
||||
#Maybe Integrate UV Painter to Generate UVMaps from Blender Material and procedural Textures
|
||||
#will be nice to paint wireframe too, so that one can easyly load into Paintprogram and see where to paint
|
||||
#(Already possible through Blender functions so at the end of the list :-) )
|
||||
###########################################################################
|
||||
"""
|
||||
Here an explanation of the V4 Format found at www.glest.org
|
||||
================================
|
||||
1. DATA TYPES
|
||||
================================
|
||||
G3D files use the following data types:
|
||||
uint8: 8 bit unsigned integer
|
||||
uint16: 16 bit unsigned integer
|
||||
uint32: 32 bit unsigned integer
|
||||
float32: 32 bit floating point
|
||||
================================
|
||||
2. OVERALL STRUCTURE
|
||||
================================
|
||||
- File header
|
||||
- Model header
|
||||
- Mesh header
|
||||
- Texture names
|
||||
- Mesh data
|
||||
================================
|
||||
2. FILE HEADER
|
||||
================================
|
||||
Code:
|
||||
struct FileHeader{
|
||||
uint8 id[3];
|
||||
uint8 version;
|
||||
};
|
||||
This header is shared among all the versions of G3D, it identifies this file as a G3D model and provides information of the version.
|
||||
id: must be "G3D"
|
||||
version: must be 4, in binary (not '4')
|
||||
================================
|
||||
3. MODEL HEADER
|
||||
================================
|
||||
Code:
|
||||
struct ModelHeader{
|
||||
uint16 meshCount;
|
||||
uint8 type;
|
||||
};
|
||||
meshCount: number of meshes in this model
|
||||
type: must be 0
|
||||
================================
|
||||
4. MESH HEADER
|
||||
================================
|
||||
There is a mesh header for each mesh, there must be "meshCount" headers in a file but they are not consecutive, texture names and mesh data are stored in between.
|
||||
Code:
|
||||
struct MeshHeader{
|
||||
uint8 name[64];
|
||||
uint32 frameCount;
|
||||
uint32 vertexCount;
|
||||
uint32 indexCount;
|
||||
float32 diffuseColor[3];
|
||||
float32 specularColor[3];
|
||||
float32 specularPower;
|
||||
float32 opacity;
|
||||
uint32 properties;
|
||||
uint32 textures;
|
||||
};
|
||||
name: name of the mesh
|
||||
frameCount: number of keyframes in this mesh
|
||||
vertexCount: number of vertices in each frame
|
||||
indexCount: number of indices in this mesh (the number of triangles is indexCount/3)
|
||||
diffuseColor: RGB diffuse color
|
||||
specularColor: RGB specular color (currently unused)
|
||||
specularPower: specular power (currently unused)
|
||||
properties: property flags
|
||||
Code:
|
||||
enum MeshPropertyFlag{
|
||||
mpfTwoSided= 1,
|
||||
mpfCustomColor= 2,
|
||||
};
|
||||
mpfTwoSided: meshes in this mesh are rendered by both sides, if this flag is not present only "counter clockwise" faces are rendered
|
||||
mpfCustomColor: alpha in this model is replaced by a custom color, usually the player color
|
||||
textures: texture flags, only 0x1 is currently used, indicating that there is a diffuse texture in this mesh.
|
||||
================================
|
||||
4. TEXTURE NAMES
|
||||
================================
|
||||
A list of uint8[64] texture name values. One for each texture in the mesh. If there are no textures in the mesh no texture names are present. In practice since Glest only uses 1 texture for each mesh the number of texture names should be 0 or 1.
|
||||
================================
|
||||
5. MESH DATA
|
||||
================================
|
||||
After each mesh header and texture names the mesh data is placed.
|
||||
vertices: frameCount * vertexCount * 3, float32 values representing the x, y, z vertex coords for all frames
|
||||
normals: frameCount * vertexCount * 3, float32 values representing the x, y, z normal coords for all frames
|
||||
texture coords: vertexCount * 2, float32 values representing the s, t tex coords for all frames (only present if the mesh has 1 texture at least)
|
||||
indices: indexCount, uint32 values representing the indices
|
||||
"""
|
||||
###########################################################################
|
||||
# Importing Structures needed (must later verify if i need them really all)
|
||||
###########################################################################
|
||||
import Blender
|
||||
from Blender import NMesh, Object, Scene
|
||||
from Blender.BGL import *
|
||||
from Blender.Draw import *
|
||||
from Blender.Window import *
|
||||
from Blender.Image import *
|
||||
import sys, struct, string, types
|
||||
from types import *
|
||||
import os
|
||||
from os import path
|
||||
from os.path import dirname
|
||||
###########################################################################
|
||||
# Variables that are better Global to handle
|
||||
###########################################################################
|
||||
imported = [] #List of all imported Objects
|
||||
toexport = [] #List of Objects to export (actually only meshes)
|
||||
sceneID = None #Points to the active Blender Scene
|
||||
|
||||
###########################################################################
|
||||
# Declaring Structures of G3D Format
|
||||
###########################################################################
|
||||
class G3DHeader: #Read first 4 Bytes of file should be G3D + Versionnumber
|
||||
binary_format = "<3cB"
|
||||
def __init__(self, fileID):
|
||||
temp = fileID.read(struct.calcsize(self.binary_format))
|
||||
data = struct.unpack(self.binary_format,temp)
|
||||
self.id = "".join(data[0:3])
|
||||
self.version = data[3]
|
||||
|
||||
class G3DModelHeaderv3: #Read Modelheader in V3 there is only the number of Meshes in file
|
||||
binary_format = "<I"
|
||||
def __init__(self, fileID):
|
||||
temp = fileID.read(struct.calcsize(self.binary_format))
|
||||
data = struct.unpack(self.binary_format,temp)
|
||||
self.meshcount = data[0]
|
||||
|
||||
class G3DModelHeaderv4: #Read Modelheader: Number of Meshes and Meshtype (must be 0)
|
||||
binary_format = "<HB"
|
||||
def __init__(self, fileID):
|
||||
temp = fileID.read(struct.calcsize(self.binary_format))
|
||||
data = struct.unpack(self.binary_format,temp)
|
||||
self.meshcount = data[0]
|
||||
self.mtype = data[1]
|
||||
|
||||
class G3DMeshHeaderv3: #Read Meshheader
|
||||
binary_format = "<7I64c"
|
||||
def __init__(self,fileID):
|
||||
temp = fileID.read(struct.calcsize(self.binary_format))
|
||||
data = struct.unpack(self.binary_format,temp)
|
||||
self.framecount = data[0] #Framecount = Number of Animationsteps
|
||||
self.normalframecount= data[1] #Number of Normal Frames actualli equal to Framecount
|
||||
self.texturecoordframecount= data[2]#Number of Frames of Texturecoordinates seems everytime to be 1
|
||||
self.colorframecount= data[3] #Number of Frames of Colors seems everytime to be 1
|
||||
self.vertexcount= data[4] #Number of Vertices in each Frame
|
||||
self.indexcount= data[5] #Number of Indices in Mesh (Triangles = Indexcount/3)
|
||||
self.properties= data[6] #Property flags
|
||||
if self.properties & 1: #PropertyBit is Mesh Textured ?
|
||||
self.hastexture = False
|
||||
self.texturefilename = None
|
||||
else:
|
||||
self.texturefilename = "".join([x for x in data[7:-1] if x in string.printable])
|
||||
self.hastexture = True
|
||||
if self.properties & 2: #PropertyBit is Mesh TwoSided ?
|
||||
self.istwosided = True
|
||||
else:
|
||||
self.istwosided = False
|
||||
if self.properties & 4: #PropertyBit is Mesh Alpha Channel custom Color in Game ?
|
||||
self.customalpha = True
|
||||
else:
|
||||
self.customalpha = False
|
||||
|
||||
class G3DMeshHeaderv4: #Read Meshheader
|
||||
binary_format = "<64c3I8f2I"
|
||||
texname_format = "<64c"
|
||||
def __init__(self,fileID):
|
||||
temp = fileID.read(struct.calcsize(self.binary_format))
|
||||
data = struct.unpack(self.binary_format,temp)
|
||||
self.meshname = "".join([x for x in data[0:64] if x in string.printable]) #Name of Mesh every Char is a String on his own
|
||||
self.framecount = data[64] #Framecount = Number of Animationsteps
|
||||
self.vertexcount = data[65] #Number of Vertices in each Frame
|
||||
self.indexcount = data[66] #Number of Indices in Mesh (Triangles = Indexcount/3)
|
||||
self.diffusecolor = data[67:70] #RGB diffuse color
|
||||
self.specularcolor = data[70:73] #RGB specular color (unused)
|
||||
self.specularpower = data[73] #Specular power (unused)
|
||||
self.opacity = data[74] #Opacity
|
||||
self.properties= data[75] #Property flags
|
||||
self.textures = data[76] #Texture flag
|
||||
if self.properties & 1: #PropertyBit is Mesh TwoSided ?
|
||||
self.istwosided = True
|
||||
else:
|
||||
self.istwosided = False
|
||||
if self.properties & 2: #PropertyBit is Mesh Alpha Channel custom Color in Game ?
|
||||
self.customalpha = True
|
||||
else:
|
||||
self.customalpha = False
|
||||
if self.textures & 1: #PropertyBit is Mesh Textured ?
|
||||
temp = fileID.read(struct.calcsize(self.texname_format))
|
||||
data = struct.unpack(self.texname_format,temp)
|
||||
self.texturefilename = "".join([x for x in data[0:-1] if x in string.printable])
|
||||
self.hastexture = True
|
||||
else:
|
||||
self.hastexture = False
|
||||
self.texturefilename = None
|
||||
|
||||
class G3DMeshdataV3: #Calculate and read the Mesh Datapack
|
||||
def __init__(self,fileID,header):
|
||||
#Calculation of the Meshdatasize to load because its variable
|
||||
#Animationframes * Vertices per Animation * 3 (Each Point are 3 Float X Y Z Coordinates)
|
||||
vertex_format = "<%if" % int(header.framecount * header.vertexcount * 3)
|
||||
#The same for Normals
|
||||
normals_format = "<%if" % int(header.normalframecount * header.vertexcount * 3)
|
||||
#Same here but Textures are 2D so only 2 Floats needed for Position inside Texture Bitmap
|
||||
texturecoords_format = "<%if" % int(header.texturecoordframecount * header.vertexcount * 2)
|
||||
#Colors in format RGBA
|
||||
colors_format = "<%if" % int(header.colorframecount * 4)
|
||||
#Indices
|
||||
indices_format = "<%iI" % int(header.indexcount)
|
||||
#Load the Meshdata as calculated above
|
||||
self.vertices = struct.unpack(vertex_format,fileID.read(struct.calcsize(vertex_format)))
|
||||
self.normals = struct.unpack(normals_format,fileID.read(struct.calcsize(normals_format)))
|
||||
self.texturecoords = struct.unpack(texturecoords_format,fileID.read(struct.calcsize(texturecoords_format)))
|
||||
self.colors = struct.unpack(colors_format,fileID.read(struct.calcsize(colors_format)))
|
||||
self.indices = struct.unpack(indices_format ,fileID.read(struct.calcsize(indices_format)))
|
||||
|
||||
class G3DMeshdataV4: #Calculate and read the Mesh Datapack
|
||||
def __init__(self,fileID,header):
|
||||
#Calculation of the Meshdatasize to load because its variable
|
||||
#Animationframes * Points (Vertex) per Animation * 3 (Each Point are 3 Float X Y Z Coordinates)
|
||||
vertex_format = "<%if" % int(header.framecount * header.vertexcount * 3)
|
||||
#The same for Normals
|
||||
normals_format = "<%if" % int(header.framecount * header.vertexcount * 3)
|
||||
#Same here but Textures are 2D so only 2 Floats needed for Position inside Texture Bitmap
|
||||
texturecoords_format = "<%if" % int(header.vertexcount * 2)
|
||||
#Indices
|
||||
indices_format = "<%iI" % int(header.indexcount)
|
||||
#Load the Meshdata as calculated above
|
||||
self.vertices = struct.unpack(vertex_format,fileID.read(struct.calcsize(vertex_format)))
|
||||
self.normals = struct.unpack(normals_format,fileID.read(struct.calcsize(normals_format)))
|
||||
if header.hastexture:
|
||||
self.texturecoords = struct.unpack(texturecoords_format,fileID.read(struct.calcsize(texturecoords_format)))
|
||||
self.indices = struct.unpack(indices_format ,fileID.read(struct.calcsize(indices_format)))
|
||||
|
||||
def createMesh(filename,header,data): #Create a Mesh inside Blender
|
||||
mesh = NMesh.New() #New Mesh
|
||||
meshobj = Object.New("Mesh",header.meshname) #New Object for the new Mesh
|
||||
meshobj.link(mesh) #Link the Mesh to the Object
|
||||
sceneID.link (meshobj) #Link the Object to the actual Scene
|
||||
uvcoords = []
|
||||
if header.hastexture: #Load Texture when assigned
|
||||
texturefile = dirname(filename)+os.sep+header.texturefilename
|
||||
texture = Load(texturefile)
|
||||
mesh.hasFaceUV(1) #Because has Texture must have UV Coordinates
|
||||
mesh.hasVertexUV(1) #UV for each Vertex not only for Face
|
||||
for x in xrange(0,len(data.texturecoords),2): #Prepare the UVs
|
||||
uvcoords.append((data.texturecoords[x],data.texturecoords[x+1]))
|
||||
else: #Has no Texture
|
||||
texture = None
|
||||
mesh.hasFaceUV(0)
|
||||
if header.isv4:
|
||||
mesh.col(int(255*header.diffusecolor[0]),int(255*header.diffusecolor[1]),int(255*header.diffusecolor[2]),int(255*header.opacity))
|
||||
if header.istwosided:
|
||||
mesh.setMode("TwoSided","AutoSmooth") #Added Autosmooth because i think it does no harm
|
||||
else: #I wonder why TwoSided here takes no effect on Faces ??
|
||||
mesh.setMode("AutoSmooth") #Same here
|
||||
y=0
|
||||
for x in xrange(0,header.vertexcount*3,3): #Get the Vertices and Normals into empty Mesh
|
||||
vertex=NMesh.Vert() #and load UV coords when needed per Vertex
|
||||
vertex.co[0] = data.vertices[x]
|
||||
vertex.co[1] = data.vertices[x+1]
|
||||
vertex.co[2] = data.vertices[x+2]
|
||||
vertex.no[0] = data.normals[x]
|
||||
vertex.no[1] = data.normals[x+1]
|
||||
vertex.no[2] = data.normals[x+2]
|
||||
if header.hastexture: ###Have to Check this per Vertex UV### may not be needed
|
||||
vertex.uvco[0] = data.texturecoords[y] ###but seems to do no harm :-)###
|
||||
vertex.uvco[1] = data.texturecoords[y+1]
|
||||
mesh.verts.append(vertex)
|
||||
y= y+2
|
||||
for i in xrange(0,len(data.indices),3): #Build Faces into Mesh
|
||||
face = NMesh.Face()
|
||||
face.smooth = 1
|
||||
face.v.append(mesh.verts[data.indices[i]])
|
||||
face.v.append(mesh.verts[data.indices[i+1]])
|
||||
face.v.append(mesh.verts[data.indices[i+2]])
|
||||
if header.hastexture: #Put UV in Faces too and assign Texture when textured
|
||||
face.uv.append(uvcoords[data.indices[i]])
|
||||
face.uv.append(uvcoords[data.indices[i+1]])
|
||||
face.uv.append(uvcoords[data.indices[i+2]])
|
||||
face.image = texture
|
||||
if header.istwosided: #Finaly found out how it works :-)
|
||||
face.mode |= NMesh.FaceModes['TWOSIDE'] #Really Bad documented this works to set all modes
|
||||
mesh.faces.append(face)
|
||||
mesh.update() #Update changes to Mesh
|
||||
objdata = meshobj.getData() #Access Data of the Meshobject only the Obj has Key/IPOData
|
||||
imported.append(meshobj) #Add to Imported Objects
|
||||
for x in xrange(header.framecount): #Put in Vertex Positions for Keyanimation
|
||||
for i in xrange(0,header.vertexcount*3,3):
|
||||
objdata.verts[i/3].co[0]= data.vertices[x*header.vertexcount*3 + i]
|
||||
objdata.verts[i/3].co[1]= data.vertices[x*header.vertexcount*3 + i +1]
|
||||
objdata.verts[i/3].co[2]= data.vertices[x*header.vertexcount*3 + i +2 ]
|
||||
objdata.update()
|
||||
mesh.insertKey(x+1,"absolute")
|
||||
Blender.Set("curframe",x)
|
||||
|
||||
# Make the keys animate in the 3d view.
|
||||
key = mesh.key
|
||||
key.relative = False
|
||||
|
||||
# Add an IPO to teh Key
|
||||
ipo = Blender.Ipo.New('Key', 'md2')
|
||||
key.ipo = ipo
|
||||
# Add a curve to the IPO
|
||||
curve = ipo.addCurve('Basis')
|
||||
|
||||
# Add 2 points to cycle through the frames.
|
||||
curve.append((1, 0))
|
||||
curve.append((header.framecount, (header.framecount-1)/10.0))
|
||||
curve.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
|
||||
|
||||
return
|
||||
###########################################################################
|
||||
# Import
|
||||
###########################################################################
|
||||
def G3DLoader(filename): #Main Import Routine
|
||||
global imported, sceneID
|
||||
print "\nNow Importing File : " + filename
|
||||
fileID = open(filename,"rb")
|
||||
header = G3DHeader(fileID)
|
||||
print "\nHeader ID : " + header.id
|
||||
print "Version : " + str(header.version)
|
||||
if header.id != "G3D":
|
||||
print "This is Not a G3D Model File"
|
||||
fileID.close
|
||||
return
|
||||
if header.version not in (3, 4):
|
||||
print "The Version of this G3D File is not Supported"
|
||||
fileID.close
|
||||
return
|
||||
in_editmode = Blender.Window.EditMode() #Must leave Editmode when active
|
||||
if in_editmode: Blender.Window.EditMode(0)
|
||||
sceneID=Scene.getCurrent() #Get active Scene
|
||||
scenecontext=sceneID.getRenderingContext() #To Access the Start/Endframe its so hidden i searched till i got angry :-)
|
||||
basename=str(Blender.sys.makename(filename,"",1)) #Generate the Base Filename without Path + extension
|
||||
imported = []
|
||||
maxframe=0
|
||||
if header.version == 3:
|
||||
modelheader = G3DModelHeaderv3(fileID)
|
||||
print "Number of Meshes : " + str(modelheader.meshcount)
|
||||
for x in xrange(modelheader.meshcount):
|
||||
meshheader = G3DMeshHeaderv3(fileID)
|
||||
meshheader.isv4 = False
|
||||
print "\nMesh Number : " + str(x+1)
|
||||
print "framecount : " + str(meshheader.framecount)
|
||||
print "normalframecount : " + str(meshheader.normalframecount)
|
||||
print "texturecoordframecount: " + str(meshheader.texturecoordframecount)
|
||||
print "colorframecount : " + str(meshheader.colorframecount)
|
||||
print "pointcount : " + str(meshheader.vertexcount)
|
||||
print "indexcount : " + str(meshheader.indexcount)
|
||||
print "texturename : " + str(meshheader.texturefilename)
|
||||
print "hastexture : " + str(meshheader.hastexture)
|
||||
print "istwosided : " + str(meshheader.istwosided)
|
||||
print "customalpha : " + str(meshheader.customalpha)
|
||||
meshheader.meshname = basename+str(x+1) #Generate Meshname because V3 has none
|
||||
if meshheader.framecount > maxframe: maxframe = meshheader.framecount #Evaluate the maximal animationsteps
|
||||
meshdata = G3DMeshdataV3(fileID,meshheader)
|
||||
createMesh(filename,meshheader,meshdata)
|
||||
fileID.close
|
||||
print "Imported Objects: ",imported
|
||||
scenecontext.startFrame(1) #Yeah finally found this Options :-)
|
||||
scenecontext.endFrame(maxframe) #Set it correctly to the last Animationstep :-))))
|
||||
Blender.Set("curframe",1) #Why the Heck are the above Options not here accessible ????
|
||||
anchor = Object.New("Empty",basename) #Build an "empty" to Parent all meshes to it for easy handling
|
||||
sceneID.link(anchor) #Link it to current Scene
|
||||
anchor.makeParent(imported) #Make it Parent for all imported Meshes
|
||||
anchor.sel = 1 #Select it
|
||||
if in_editmode: Blender.Window.EditMode(1) # Be nice and restore Editmode when was active
|
||||
return
|
||||
if header.version == 4:
|
||||
modelheader = G3DModelHeaderv4(fileID)
|
||||
print "Number of Meshes : " + str(modelheader.meshcount)
|
||||
for x in xrange(modelheader.meshcount):
|
||||
meshheader = G3DMeshHeaderv4(fileID)
|
||||
meshheader.isv4 = False
|
||||
print "\nMesh Number : " + str(x+1)
|
||||
print "meshname : " + str(meshheader.meshname)
|
||||
print "framecount : " + str(meshheader.framecount)
|
||||
print "vertexcount : " + str(meshheader.vertexcount)
|
||||
print "indexcount : " + str(meshheader.indexcount)
|
||||
print "diffusecolor : %1.6f %1.6f %1.6f" %meshheader.diffusecolor
|
||||
print "specularcolor : %1.6f %1.6f %1.6f" %meshheader.specularcolor
|
||||
print "specularpower : %1.6f" %meshheader.specularpower
|
||||
print "opacity : %1.6f" %meshheader.opacity
|
||||
print "properties : " + str(meshheader.properties)
|
||||
print "textures : " + str(meshheader.textures)
|
||||
print "texturename : " + str(meshheader.texturefilename)
|
||||
if len(meshheader.meshname) ==0: #When no Meshname in File Generate one
|
||||
meshheader.meshname = basename+str(x+1)
|
||||
if meshheader.framecount > maxframe: maxframe = meshheader.framecount #Evaluate the maximal animationsteps
|
||||
meshdata = G3DMeshdataV4(fileID,meshheader)
|
||||
createMesh(filename,meshheader,meshdata)
|
||||
fileID.close
|
||||
scenecontext.startFrame(1) #Yeah finally found this Options :-)
|
||||
scenecontext.endFrame(maxframe) #Set it correctly to the last Animationstep :-))))
|
||||
Blender.Set("curframe",1) #Why the Heck are the above Options not here accessible ????
|
||||
anchor = Object.New("Empty",basename) #Build an "empty" to Parent all meshes to it for easy handling
|
||||
sceneID.link(anchor) #Link it to current Scene
|
||||
anchor.makeParent(imported) #Make it Parent for all imported Meshes
|
||||
anchor.sel = 1 #Select it
|
||||
if in_editmode: Blender.Window.EditMode(1) # Be nice and restore Editmode when was active
|
||||
print "Created a empty Object as 'Grip' where all imported Objects are parented to"
|
||||
print "To move the complete Meshes only select this empty Object and move it"
|
||||
print "All Done, have a good Day :-)\n\n"
|
||||
return
|
||||
###########################################################################
|
||||
# Export (Ripped out its work in Progress will be added soon
|
||||
###########################################################################
|
||||
def G3DSaverV3(filename):
|
||||
return
|
||||
|
||||
def G3DSaverV4(filename):
|
||||
return
|
||||
###########################################################################
|
||||
# Complete GUI Part of The Wizard
|
||||
###########################################################################
|
||||
# Events that can occure by pressing the Buttons
|
||||
EVENT_LOADG3D=2
|
||||
EVENT_SAVEG3DV3=3
|
||||
EVENT_SAVEG3DV4=4
|
||||
EVENT_EXIT=100
|
||||
###########################################################################
|
||||
# GUI eventhandler
|
||||
###########################################################################
|
||||
def event(evt, val):
|
||||
if evt == Blender.Draw.ESCKEY and not val: Blender.Draw.Exit()
|
||||
def button_event(evt):
|
||||
global EVENT_LOAD_G3D,EVENT_SAVE_G3DV3,EVENT_SAVE_G3DV4,EVENT_EXIT
|
||||
if evt == EVENT_EXIT: Exit()
|
||||
if evt == EVENT_LOADG3D:
|
||||
defaultname = os.sep + ".g3d"
|
||||
#I use this defaultnames only for development to have short ways to models
|
||||
#if u want make a path to your models here and comment the above defaultname out.
|
||||
#Be careful to not move the start of the Line because it matters in python
|
||||
# defaultname="I:/glest/glest_game/techs/magitech/factions/magic/units/magic_armor/models/magic_armor_walking.g3d"
|
||||
# defaultname="I:/glest/glest_game/techs/magitech/factions/.g3d"
|
||||
# defaultname="I:/entwicklung/blenderexport/test/swordman_sample/swordman.g3d"
|
||||
FileSelector(G3DLoader, "G3D to load", defaultname)
|
||||
Blender.Redraw()
|
||||
if evt==EVENT_SAVEG3DV3:
|
||||
defaultname = Blender.sys.makename(Blender.Get("filename"),".g3d",1)
|
||||
FileSelector(G3DSaverV3, "G3D V3 to save", defaultname)
|
||||
if evt==EVENT_SAVEG3DV4:
|
||||
defaultname = Blender.sys.makename(Blender.Get("filename"),".g3d",1)
|
||||
FileSelector(G3DSaverV4, "G3D V4 to save", defaultname)
|
||||
###########################################################################
|
||||
# GUI Screenmask as a nice looking feature i Center the Mask
|
||||
###########################################################################
|
||||
def gui():
|
||||
global EVENT_LOADG3D,EVENT_SAVEG3DV3,EVENT_SAVEG3DV4,EVENT_EXIT
|
||||
xmiddle= GetScreenSize()[0] / 2 #calculate horizontal middle of the screen
|
||||
#Clearing the Screen all here needs imported BGL + DRAW
|
||||
glClearColor(0.0, 0.0, 0.0,1)
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
# logo
|
||||
homedir = Blender.Get("homedir")
|
||||
Logo = Load(homedir+ os.sep + "scripts" + os.sep + "g3d_logo.png") # Load Logo file
|
||||
glEnable(GL_BLEND)
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
||||
Image(Logo,(xmiddle-(Logo.getSize()[0]/2)),20)
|
||||
glDisable(GL_BLEND)
|
||||
#Title
|
||||
tbuffer= "G3D Import Wizard supporting V3 / V4 models"
|
||||
xpos = xmiddle - (GetStringWidth(tbuffer) /2)
|
||||
glColor3f(1, 0, 0)
|
||||
glRasterPos2d(xpos, 70)
|
||||
Text(tbuffer)
|
||||
tbuffer= "Please view any Errors / Info in the Blender Console"
|
||||
xpos = xmiddle - (GetStringWidth(tbuffer) /2)
|
||||
glColor3f(1, 1, 0)
|
||||
glRasterPos2d(xpos, 55)
|
||||
Text(tbuffer)
|
||||
#Buttons
|
||||
Button("Load G3D",EVENT_LOADG3D , xmiddle-140, 10, 100, 40)
|
||||
#Button("Save G3D V3",EVENT_SAVEG3DV3 , xmiddle-100, 10, 100, 40)
|
||||
#Button("Save G3D V4",EVENT_SAVEG3DV4 , xmiddle, 10, 100, 40)
|
||||
Button("Exit",EVENT_EXIT , xmiddle+40, 10, 100, 40)
|
||||
###########################################################################
|
||||
# Registering GUI events (Activating GUI) THE END
|
||||
###########################################################################
|
||||
Register(gui, event, button_event)
|
|
@ -0,0 +1,535 @@
|
|||
#!BPY
|
||||
# coding: utf-8
|
||||
"""
|
||||
Name: 'G3D XML Exporter Ver:1.1'
|
||||
Blender: 2.43
|
||||
Group: 'Export'
|
||||
Tooltip: 'Exports directly to G3D(if xml2g is installed next to this script) or XML (which can be converted to .g3d using xml2g)'
|
||||
"""
|
||||
###########################################################################
|
||||
# Glest Model / Texture / Animation Exporter
|
||||
# for the game Glest that you can find at http://www.glest.org
|
||||
# copyright 2005-2006 By Vincent Gadoury
|
||||
# Started Date: December 18 2005 Put Public Decembre 20 2005
|
||||
# Ver: 1.0 (Jan 30 2009)
|
||||
# Distributed under the GNU PUBLIC LICENSE
|
||||
# Based on g3d_support.py by Andreas Becker
|
||||
# and on glexemel by Jonathan Merritt
|
||||
###########################################################################
|
||||
# (I'm sorry for the poor quality of this text,
|
||||
# I'm not a native English speaker)
|
||||
#
|
||||
#INSTALLATION :
|
||||
# Copy this Script into your .blender\scripts directory.
|
||||
# if you want direct .g3d support unpack all needed glexemel files to this directory too:
|
||||
# LINUX:
|
||||
# In case of linux its only: xml2g and g3d.dtd ( included is a binary for linux32 bit).
|
||||
# The sourcecode can be found here:
|
||||
# http://www.glest.org/files/contrib/tools/glexemel-0.1a.zip
|
||||
# WINDOWS:
|
||||
# If you are using windows, all files from the "bin" directory from the
|
||||
# following zip files are needed:
|
||||
# http://www.glest.org/files/contrib/tools/glexemel_win32_0.1a.zip
|
||||
#
|
||||
# In Blender, open a Script Window and in the menu choose "Update Menus"
|
||||
# Export with File->Export->G3D XML Exporter
|
||||
#
|
||||
#PREPARE THE MODEL :
|
||||
# Each of your meshes' faces must be a triangle (3 vertex)
|
||||
# In Edit mode, you can press Space, edit>faces>Convert to Triangles
|
||||
# Create and place all your meshes before texturing or animating.
|
||||
# The X axe is the floor and the Y axe is the elevation. The center
|
||||
# of the Blender's 3D space will be the center of you object, at the
|
||||
# ground level. Before exporting your model, apply the transformations
|
||||
# to each of your mesh (In the 3D space window's menu :
|
||||
# Object->Clear/Apply->Apply ... )
|
||||
# This will place the center of your mesh (the yellow or pink dot)
|
||||
# at the center of the Blender 3D space.
|
||||
#
|
||||
# !!!!!!!!!!!!!!
|
||||
# !!!new since 0.1.4: !!!
|
||||
# If you have a non animating model, you have to set the start frame
|
||||
# and the end frame to '1' in blenders 'timeline'-window. Otherwise a non
|
||||
# animating animation will be exported, containing a lot of frames and your
|
||||
# model gets really big.
|
||||
# !!!!!!!!!!!!!!
|
||||
#
|
||||
# Before doing any texturing or animation, try to export your model and
|
||||
# check your python console (the terminal which opens Blender) to see
|
||||
# if there is a warning about the number of used faces in the summary.
|
||||
# If there is, try to delete "false" faces (which use only 2 vertices)
|
||||
# and transform all your faces in triangle.
|
||||
#
|
||||
#EXPORTING :
|
||||
# You MUST select the meshes you want to export.
|
||||
# Only meshes are exported among the selected objects.
|
||||
#
|
||||
# The diffuse color of the mesh will be it's (first) material's color.
|
||||
# The opacity of the mesh will be it's material's alpha.
|
||||
# Double sided property of the mesh is exported (see F9).
|
||||
# If you want to use custom color in the texture, your mesh must be
|
||||
# double sided. If you don't want custom color to be activated for the
|
||||
# mesh, add a new boolean property to it (F4) named customColor and with
|
||||
# the false value. Custom Color set if the alpha of the texture is
|
||||
# replaced for the color of the player.
|
||||
#
|
||||
#TEXTURING :
|
||||
# To use a texture for the mesh, you must add a texture at the FIRST
|
||||
# position to the mesh's material. The texture type must be 'image'
|
||||
# and you should insert the real image. In fact, only the filename
|
||||
# of the image is used. After having mapped the image on the
|
||||
# mesh with UV Face selection, you don't need anymore to "stick"
|
||||
# the coordinates to the vertices.
|
||||
# Your texture's format must be TGA, without compression and with the origin
|
||||
# at the bottom left position. The side of the image must be a multiple
|
||||
# of 2. In practice, you must use only one image for all your meshes.
|
||||
#
|
||||
#ANIMATING :
|
||||
# You can export all animations made with blenders armature system.
|
||||
# You have to set the start frame and the end frame in the 'timeline'-window
|
||||
# to define the animation which will be exported.
|
||||
# If you animate without using the armatures it will not work!!
|
||||
#
|
||||
# LINKS :
|
||||
# Animating with armatures
|
||||
# http://www.blender.org/documentation/htmlI/x1829.html
|
||||
# Map an image on your mesh with UV Face selection :
|
||||
# http://en.wikibooks.org/wiki/Blender_3D:_Noob_to_Pro/UV_Map_Basics
|
||||
# http://download.blender.org/documentation/htmlI/ch11s05.html
|
||||
#
|
||||
#CONVERT TO .G3D
|
||||
# The following is no longer needed if you copied g3d.dtd and xml2g(.exe) next
|
||||
# to this script:
|
||||
#
|
||||
# Use the xml2g program of the glexemel tool at
|
||||
# http://www.glest.org/files/contrib/tools/
|
||||
# Syntax : ./xml2g ExportedFile.xml DesiredFile.g3d
|
||||
#
|
||||
# WARNING : The current version of this program don't seems to work...
|
||||
# You'll have to add the lines (if they aren't there) :
|
||||
# #pragma pack(push, 1)
|
||||
# near of the beginning of the file "g3dv4.h" of glexemel and
|
||||
# #pragma pack(pop)
|
||||
# before the #endif
|
||||
#
|
||||
#
|
||||
#ChangeLog :
|
||||
# 1.1: by Titus Tscharntke (titi)
|
||||
# fixed bug in windows ( problems with file sparator char )
|
||||
# 1.0: Big thanks go to Frank Tetzel (Yggdrasil) who finally made a
|
||||
# direct export to .g3d possible. If you copy g3d.dtd and
|
||||
# xml2g(.exe) next to this script it will export to .g3d.
|
||||
# If not, it will export to .xml like before.
|
||||
#
|
||||
# 0.1.7 : by Titus Tscharntke (titi)
|
||||
# removed non 7-bit ascii characters for newer versions of python
|
||||
# 0.1.6 : by justWeedy(weedkiller)
|
||||
# Basic colorsettings for maps are often unused but may cause
|
||||
# models look "bright".
|
||||
# There are Hardcoded defauld values to avoid this.
|
||||
# Turn On/Off due the boolean <useHardCodedColor>
|
||||
# 0.1.5 : by weedkiller
|
||||
# You don't have to apply scale and rotation anymore
|
||||
# 0.1.4 : by weedkiller and Titus Tscharntke ( www.titusgames.de )
|
||||
# New implementation of the animation export ( including some usage changes!!! )
|
||||
# Exporting animations is now possible with newer Blender versions ( tested with 2.43 )
|
||||
#
|
||||
# 0.1.3 : by Titus Tscharntke ( www.titusgames.de )
|
||||
# Fixed a bug with getProperty() in blender 2.43
|
||||
#
|
||||
# 0.1.2 :
|
||||
# Correcting an execution bug
|
||||
# Adding the "frameCount" property for each object
|
||||
# Using only the triangle faces for the index count
|
||||
# (problems of linking between index and vertex may occur)
|
||||
# Adding the summary display in the python console
|
||||
# Adding a better documentation
|
||||
# 0.1.1b :
|
||||
# Adding a vertex duplication method to correct the vertex UV problem.
|
||||
# Correcting NMVert.uvco misuse
|
||||
#
|
||||
#ToDo:
|
||||
# More tests...
|
||||
# More validations...
|
||||
# Warn the user if there is something wrong, e.g. :
|
||||
# - no mesh among the selected objects;
|
||||
# - texture without uvco;
|
||||
# - no material on a mesh.
|
||||
# Test and correct the theoric linking problem if faces are ignored...
|
||||
#
|
||||
#Contributions :
|
||||
# pseudonym404 : NMVert.uvco issue and solutions
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
import Blender
|
||||
from Blender import NMesh
|
||||
from Blender import sys as bsys
|
||||
|
||||
import subprocess, os
|
||||
|
||||
|
||||
# part Hardcoded Color >>
|
||||
HardCodedDiffuse=0.588235
|
||||
HardCodedSpecular=0.900000
|
||||
useHardCodedColor='true' #'false' if not wanted
|
||||
# part Hardcoded Color <<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
seenindex=set()
|
||||
uvlist=[]
|
||||
|
||||
# This list will contain the associative "real" vertex of each duplicated vertex
|
||||
# in ascendant order.
|
||||
# The fisrt "vertex" of the list (newvertices[0]) has the index len(mesh.verts)
|
||||
newvertices=[]
|
||||
currentnewvertex=0
|
||||
|
||||
#This list will contain all the "new" faces' indices
|
||||
newindices=[]
|
||||
|
||||
|
||||
|
||||
|
||||
def icmp(x,y):
|
||||
return cmp(x,y)
|
||||
|
||||
def notseenindex(index):
|
||||
seen = index in seenindex
|
||||
if not seen: seenindex.add(index)
|
||||
return not seen
|
||||
|
||||
# this will return the properties data if it exists, else the given defaultvalue
|
||||
def getPropertyIfExists(blenderobject,propertyName,defaultvalue):
|
||||
propertiesList = blenderobject.getAllProperties()
|
||||
lpropertiesList = range( 0 , len(propertiesList) )
|
||||
for iprop in lpropertiesList:
|
||||
objectProperty = propertiesList[iprop]
|
||||
currentPropertyName=objectProperty.getName()
|
||||
if currentPropertyName == propertyName:
|
||||
return objectProperty.getData()
|
||||
return defaultvalue
|
||||
|
||||
|
||||
def write_obj(filepath):
|
||||
out = file(filepath, 'w')
|
||||
|
||||
print("-----------------------------------------------")
|
||||
|
||||
#Header
|
||||
out.write( '<?xml version="1.0" encoding="ASCII" ?>\n' )
|
||||
out.write( '<!DOCTYPE G3D SYSTEM "g3d.dtd">\n' )
|
||||
out.write( '<!-- \n' )
|
||||
out.write( ' This file is an XML encoding of a G3D binary\n' )
|
||||
out.write( ' file. The XML format is by Jonathan Merritt\n' )
|
||||
out.write( ' (not yet accepted as part of Glest!).\n' )
|
||||
out.write( ' The file was exported from Blender with the\n' )
|
||||
out.write( ' G3D-XML Exporter script by Vincent Gadoury.\n' )
|
||||
out.write( '-->\n' )
|
||||
out.write( '<G3D version="4">\n' )
|
||||
|
||||
objects = Blender.Object.GetSelected()
|
||||
|
||||
print("Exporting %i selected objects to XML-G3D format..." %(len(objects)))
|
||||
|
||||
#FOR EACH MESH
|
||||
lobjects = range( 0 , len(objects) )
|
||||
for iobj in lobjects:
|
||||
object = objects[iobj]
|
||||
|
||||
mesh = object.getData()
|
||||
# Skip the object if it's not a mesh
|
||||
if type(mesh) != Blender.Types.NMeshType :
|
||||
continue
|
||||
|
||||
#Clear the lists
|
||||
seenindex.clear()
|
||||
uvlist[:]=[]
|
||||
newvertices[:]=[]
|
||||
newindices[:]=[]
|
||||
|
||||
currentnewvertex=(len(mesh.verts))
|
||||
|
||||
#Find some properties of the mesh
|
||||
|
||||
image = None
|
||||
textureName = ''
|
||||
diffuseTexture = 'false'
|
||||
opacity = 1
|
||||
diffuseColor = [ 1.0, 1.0, 1.0 ]
|
||||
|
||||
#Find if the mesh has a material and a texture
|
||||
# (opacity, diffuseColor, diffuseTexture, textureName)
|
||||
if len(mesh.materials) > 0:
|
||||
material = mesh.materials[0]
|
||||
|
||||
opacity = material.alpha
|
||||
diffuseColor[0] = material.rgbCol[0]
|
||||
diffuseColor[1] = material.rgbCol[1]
|
||||
diffuseColor[2] = material.rgbCol[2]
|
||||
|
||||
# part Hardcoded Color >>
|
||||
if useHardCodedColor :
|
||||
diffuseColor[0] = HardCodedDiffuse
|
||||
diffuseColor[1] = HardCodedDiffuse
|
||||
diffuseColor[2] = HardCodedDiffuse
|
||||
# part Hardcoded Color <<
|
||||
|
||||
if material.getTextures()[0]:
|
||||
image = material.getTextures()[0].tex.getImage()
|
||||
if image:
|
||||
textureName = image.getFilename()
|
||||
textureName = textureName.split(os.path.normcase('/'))[-1] #get only the filename
|
||||
diffuseTexture = 'true'
|
||||
#End material and texture
|
||||
|
||||
#TwoSided
|
||||
if mesh.mode & NMesh.Modes['TWOSIDED']:
|
||||
twoSided='true'
|
||||
else:
|
||||
twoSided='false'
|
||||
|
||||
#CustomColor
|
||||
customColor = 1
|
||||
customColor = getPropertyIfExists(object,'customColor',customColor)
|
||||
if customColor:
|
||||
customColor = 'true'
|
||||
else:
|
||||
customColor = 'false'
|
||||
|
||||
#Real face count (only use triangle)
|
||||
realFaceCount = 0
|
||||
for face in mesh.faces:
|
||||
if (len(face.v) == 3):
|
||||
realFaceCount += 1
|
||||
|
||||
#Frames number
|
||||
frameCount = 1
|
||||
#frameCount = getPropertyIfExists(object,'frameCount',frameCount)
|
||||
startFrame = Blender.Get('staframe')
|
||||
endFrame = Blender.Get('endframe')
|
||||
frameCount = endFrame-startFrame+1
|
||||
|
||||
# TRANSFERING FACE TEXTURE COORD. TO VERTEX TEXTURE COORD.
|
||||
# and duplicating vertex associated to different uvco
|
||||
|
||||
if textureName == '': #THERE IS NO TEXTURE
|
||||
#create the index list, don't care of newvertices
|
||||
for face in mesh.faces:
|
||||
faceindices = []
|
||||
if (len(face.v) == 3):
|
||||
for vert in face.v:
|
||||
faceindices.append(vert.index)
|
||||
newindices.append(faceindices[0:3])
|
||||
|
||||
else: # THERE IS A TEXTURE
|
||||
|
||||
uvlist[:] = [[0]*3 for i in range( len(mesh.verts) )]
|
||||
|
||||
for face in mesh.faces:
|
||||
faceindices = []
|
||||
if (len(face.v) == 3):
|
||||
for i in range(len(face.uv)):
|
||||
vindex = face.v[i].index
|
||||
|
||||
if notseenindex(vindex):
|
||||
uvlist[vindex] = [vindex, face.uv[i][0], face.uv[i][1]]
|
||||
|
||||
elif uvlist[vindex][1] != face.uv[i][0] or \
|
||||
uvlist[vindex][2] != face.uv[i][1]:
|
||||
#debug: print("dif: [%f,%f] et [%f,%f]" %( uvlist[vindex][1], face.uv[i][0], uvlist[vindex][2], face.uv[i][1] ))
|
||||
#Create a new "entry" for an existing vertex
|
||||
newvertices.append(vindex)
|
||||
uvlist.append([currentnewvertex, face.uv[i][0], face.uv[i][1]])
|
||||
vindex = currentnewvertex
|
||||
currentnewvertex += 1
|
||||
|
||||
faceindices.append(vindex)
|
||||
newindices.append(faceindices[0:3])
|
||||
|
||||
#End texture and vertex copy
|
||||
|
||||
|
||||
# ---- BEGINNING OF THE WRITING OF THE FILE ----
|
||||
|
||||
#MESH HEADER
|
||||
out.write( '\n<Mesh \n' )
|
||||
out.write( ' name="%s" \n' % (mesh.name) )
|
||||
out.write( ' frameCount="%i" \n' % ( frameCount ) )
|
||||
out.write( ' vertexCount="%i" \n' % (len(mesh.verts) + len(newvertices)) )
|
||||
out.write( ' indexCount="%i" \n' % ( realFaceCount * 3 ) )
|
||||
out.write( ' specularPower="9.999999" \n' )
|
||||
out.write( ' opacity="%f" \n' % (opacity) )
|
||||
out.write( ' twoSided="%s" \n' % ( twoSided ) )
|
||||
out.write( ' customColor="%s" \n' % ( customColor ) )
|
||||
out.write( ' diffuseTexture="%s" > \n' % ( diffuseTexture ) )
|
||||
|
||||
#DIFFUSE
|
||||
out.write( ' <Diffuse>\n <Color r="%f" g="%f" b="%f" />\n </Diffuse>\n' % ( diffuseColor[0], diffuseColor[1], diffuseColor[2] ) )
|
||||
|
||||
#SPECULAR # part Hardcoded Color: THIS WAS ALREADY HARDCODED ...
|
||||
out.write( ' <Specular><Color r="%f" g="%f" b="%f" /></Specular>\n' % (HardCodedSpecular, HardCodedSpecular, HardCodedSpecular) )
|
||||
|
||||
#TEXTURE
|
||||
if textureName == '':
|
||||
out.write( ' <!-- NO TEXTURE -->\n' )
|
||||
else:
|
||||
out.write( ' <Texture name="%s" />\n' % (textureName) )
|
||||
|
||||
#For each FRAME
|
||||
|
||||
#VERTICES
|
||||
framelist={}
|
||||
l = range( startFrame , startFrame+frameCount )
|
||||
for frame in l:
|
||||
# set the right frame
|
||||
Blender.Set('curframe', frame)
|
||||
curObject=object
|
||||
curMatrix= curObject.getMatrix('worldspace')
|
||||
|
||||
fmesh = curObject.getData()
|
||||
|
||||
# after creation of new Object, Selection is no longer reliable (new obj. are selected, too), already corrected in code (see: curObject= ...)
|
||||
defmesh=Blender.Mesh.New(curObject.name+'F'+str(frame))
|
||||
defmesh.getFromObject(curObject.name)
|
||||
|
||||
framelist[frame]=defmesh
|
||||
|
||||
# just to avoid work
|
||||
fmesh=defmesh
|
||||
|
||||
out.write( ' <Vertices frame="%i">\n' % ( frame-startFrame ) )
|
||||
# "real" vertex
|
||||
for vert in fmesh.verts:
|
||||
vert.co= vert.co * curMatrix
|
||||
out.write( ' <Vertex x="%f" y="%f" z="%f" />\n' % (vert.co.x,vert.co.y,vert.co.z) )
|
||||
# "linked" new vertex
|
||||
for ind in newvertices:
|
||||
out.write( ' <Vertex x="%f" y="%f" z="%f" />\n' % \
|
||||
(fmesh.verts[ind].co.x, fmesh.verts[ind].co.y, fmesh.verts[ind].co.z) )
|
||||
out.write( ' </Vertices>\n' )
|
||||
|
||||
#NORMALS
|
||||
l = range( startFrame , startFrame+frameCount )
|
||||
for frame in l:
|
||||
Blender.Set('curframe', frame)
|
||||
|
||||
# getting the created meshes
|
||||
fmesh = framelist[frame] #.getData()
|
||||
|
||||
out.write( ' <Normals frame="%i">\n' % ( frame-startFrame ) )
|
||||
# "real" vertex
|
||||
for vert in fmesh.verts:
|
||||
out.write( ' <Normal x="%f" y="%f" z="%f" />\n' % (vert.no.x, vert.no.y, vert.no.z) )
|
||||
# "linked" new vertex
|
||||
for ind in newvertices:
|
||||
out.write( ' <Normal x="%f" y="%f" z="%f" />\n' % \
|
||||
(fmesh.verts[ind].no.x, fmesh.verts[ind].no.y, fmesh.verts[ind].no.z) )
|
||||
out.write( ' </Normals>\n' )
|
||||
|
||||
#End FRAMES
|
||||
|
||||
|
||||
#TEXTURES COORDS
|
||||
if textureName == '':
|
||||
out.write( ' <!-- NO TEXTURE COORDS -->\n' )
|
||||
else:
|
||||
out.write( ' <TexCoords>\n' )
|
||||
#write list
|
||||
for uv in uvlist:
|
||||
out.write( ' <ST s="%f" t="%f" />\n' % (uv[1], uv[2]) )
|
||||
out.write( ' </TexCoords>\n' )
|
||||
|
||||
#INDICES
|
||||
out.write( ' <Indices>\n' )
|
||||
for face in newindices:
|
||||
for vert in face:
|
||||
out.write( ' <Ix i="%i" />\n' % (vert) )
|
||||
# out.write('\n')
|
||||
out.write( ' </Indices>\n' )
|
||||
|
||||
#END MESH
|
||||
out.write( '</Mesh>\n' )
|
||||
|
||||
#Printing a summary of the mesh to the output
|
||||
print("\nObject : %s" %(object.getName() ) )
|
||||
print("Mesh : %s" %(mesh.name) )
|
||||
print("%i frames" % ( frameCount ) )
|
||||
print("%i vertices" % (len(mesh.verts) + len(newvertices)) )
|
||||
print("%i exported faces (%i real faces)" % (realFaceCount, len(mesh.faces) ) )
|
||||
if realFaceCount != len(mesh.faces) :
|
||||
print("WARNING : some faces have been ignored (not triangle)\n" +
|
||||
" Errors may occur with faces and indices linking..." )
|
||||
Blender.Draw.PupMenu("export warning:%t|WARNING : some faces have been ignored (not triangle)|" +
|
||||
" Errors may occur with faces and indices linking...")
|
||||
print("%i indices" % (realFaceCount * 3) )
|
||||
print("opacity : %f" % (opacity) )
|
||||
print("two sided : %s" % (twoSided) )
|
||||
print("custom color : %s" % (customColor) )
|
||||
print("Use a diffuse texture : %s" % (diffuseTexture) )
|
||||
if textureName != '':
|
||||
print( " texture name : %s" % (textureName) )
|
||||
print("diffuse color : %f,%f,%f" % ( diffuseColor[0], diffuseColor[1], diffuseColor[2] ) )
|
||||
print("Number of new vertices to fit uv mapping : %i\n" % ( len(newvertices) ) )
|
||||
|
||||
#FOOTER
|
||||
out.write( '</G3D>\n' )
|
||||
|
||||
out.close()
|
||||
#END write_obj
|
||||
|
||||
# file selector based on ac3d_export.py by Willian P. Germano
|
||||
# File Selector callback:
|
||||
def fs_callback(filename):
|
||||
global cmd, extension, scriptsdir
|
||||
if not filename.endswith(extension): filename = '%s%s' % (filename, extension)
|
||||
if bsys.exists(filename):
|
||||
if Blender.Draw.PupMenu('OVERWRITE?%t|File exists') != 1:
|
||||
return
|
||||
if cmd:
|
||||
tmp = bsys.join(scriptsdir, "tmp.xml")
|
||||
write_obj(tmp)
|
||||
|
||||
print "running glexemel"
|
||||
cmd = [cmd, tmp, filename]
|
||||
print cmd
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
out = p.stdout.read()
|
||||
err = p.stderr.read()
|
||||
res = p.wait()
|
||||
if res != 0 or err:
|
||||
s = ''
|
||||
if out:
|
||||
s += out.replace('\n', '|')
|
||||
if err:
|
||||
s += err.replace('\n', '|')
|
||||
Blender.Draw.PupMenu('glexemel error: see console%t|' + s)
|
||||
print out
|
||||
print err
|
||||
print res
|
||||
else:
|
||||
write_obj(filename)
|
||||
print "glexemel not found"
|
||||
|
||||
|
||||
scriptsdir = Blender.Get('scriptsdir')
|
||||
files = os.listdir(scriptsdir)
|
||||
cmd = ''
|
||||
extension=".xml"
|
||||
for fname in files:
|
||||
if fname.startswith("xml2g"):
|
||||
cmd = bsys.join(scriptsdir, fname)
|
||||
extension = ".g3d"
|
||||
break
|
||||
|
||||
OBJS = Blender.Object.GetSelected()
|
||||
if not OBJS:
|
||||
Blender.Draw.PupMenu('ERROR: no objects selected')
|
||||
else:
|
||||
fname = bsys.makename(ext=extension)
|
||||
Blender.Window.FileSelector(fs_callback, "Export XML-G3D", fname)
|
||||
#Blender.Window.FileSelector(write_obj, "Export")
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* File: g3dv4.h
|
||||
*
|
||||
* Description:
|
||||
* Data types used by the G3D format.
|
||||
*
|
||||
* This file is copied from portions of the Glest project:
|
||||
* http://www.glest.org
|
||||
*
|
||||
* This file may be distributed under the terms of the GNU General Public
|
||||
* License.
|
||||
*/
|
||||
|
||||
#ifndef G3DV4_HEADER
|
||||
#define G3DV4_HEADER
|
||||
// bug fix from wiki
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef float float32;
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short int uint16;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
#define NAMESIZE 64
|
||||
|
||||
struct FileHeader{
|
||||
uint8 id[3];
|
||||
uint8 version;
|
||||
};
|
||||
|
||||
struct ModelHeader{
|
||||
uint16 meshCount;
|
||||
uint8 type;
|
||||
};
|
||||
enum ModelType{
|
||||
mtMorphMesh
|
||||
};
|
||||
|
||||
struct MeshHeader{
|
||||
uint8 name[NAMESIZE];
|
||||
uint32 frameCount;
|
||||
uint32 vertexCount;
|
||||
uint32 indexCount;
|
||||
float32 diffuseColor[3];
|
||||
float32 specularColor[3];
|
||||
float32 specularPower;
|
||||
float32 opacity;
|
||||
uint32 properties;
|
||||
uint32 textures;
|
||||
};
|
||||
enum MeshPropertyFlag{
|
||||
mpfTwoSided= 0,
|
||||
mpfCustomColor= 1
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
#endif
|
|
@ -0,0 +1,670 @@
|
|||
/**
|
||||
* File: xml2g.c
|
||||
* Written: Jonathan Merritt <jmerritt@warpax.com>
|
||||
*
|
||||
* Description:
|
||||
* Converts G3Dv4 XML files into the binary representation used in the game.
|
||||
* Requirements:
|
||||
* libxml2
|
||||
*
|
||||
* Copyright (C) Jonathan Merritt 2005.
|
||||
* This file may be distributed under the terms of the GNU General Public
|
||||
* License.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#include "g3dv4.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Forward function declarations.
|
||||
*/
|
||||
int xml2g3d(xmlDocPtr doc, FILE *outfile);
|
||||
void usage(char *execname);
|
||||
unsigned int countChildren(xmlNode *n, xmlChar *name);
|
||||
int processMesh(xmlNode *n, FILE *outfile);
|
||||
int readColorChild(xmlNode *n, char *childName, float32 *color);
|
||||
int processVertices(xmlNode *n, FILE *outfile, uint32 vertexCount);
|
||||
int processNormals(xmlNode *n, FILE *outfile, uint32 vertexCount);
|
||||
int processTexcoords(xmlNode *n, FILE *outfile, uint32 vertexCount);
|
||||
int processIndices(xmlNode *n, FILE *outfile, uint32 indexCount);
|
||||
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param argc: Number of arguments passed to the program.
|
||||
* @param argv: Array of string arguments.
|
||||
*
|
||||
* @returns: EXIT_SUCCESS or EXIT_FAILURE depending upon success or failure
|
||||
* of the conversion to XML.
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *infilename, *outfilename;
|
||||
FILE *outfile;
|
||||
int successFlag;
|
||||
xmlParserCtxtPtr ctxt;
|
||||
xmlDocPtr doc;
|
||||
|
||||
/* parse command line arguments */
|
||||
if (argc != 3)
|
||||
{
|
||||
usage(argv[0]);
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
infilename = argv[1];
|
||||
outfilename = argv[2];
|
||||
}
|
||||
|
||||
/* attempt to parse the XML file */
|
||||
LIBXML_TEST_VERSION
|
||||
ctxt = xmlNewParserCtxt();
|
||||
if (ctxt == NULL)
|
||||
{
|
||||
printf("Failed to allocate XML parser context!\n");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
doc = xmlCtxtReadFile(ctxt, infilename, NULL, XML_PARSE_DTDVALID);
|
||||
if (doc == NULL)
|
||||
{
|
||||
printf("Could not parse XML file \"%s\"!\n", infilename);
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* attempt to open the output binary file */
|
||||
outfile = fopen(outfilename, "wb");
|
||||
if (outfile == NULL)
|
||||
{
|
||||
printf("Could not open file \"%s\" for writing!\n",
|
||||
outfilename);
|
||||
xmlFreeDoc(doc);
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
xmlCleanupParser();
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* perform the conversion: XML -> binary */
|
||||
successFlag = xml2g3d(doc, outfile);
|
||||
|
||||
/* close the files */
|
||||
xmlFreeDoc(doc);
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
xmlCleanupParser();
|
||||
fclose(outfile);
|
||||
|
||||
/* return a success or failure flag */
|
||||
if (successFlag)
|
||||
return (EXIT_SUCCESS);
|
||||
else
|
||||
return (EXIT_FAILURE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Prints a "Usage:" string for the program.
|
||||
*
|
||||
* @param execname: Executable name of the program.
|
||||
*/
|
||||
void usage(char *execname)
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf(" %s infile.xml outfile.g3d\n", execname);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Performs the conversion from the XML file format to the G3D binary format.
|
||||
*
|
||||
* @param doc: XML DOM document for input.
|
||||
* @param outfile: Binary file, opened as "wb", for output.
|
||||
*/
|
||||
int xml2g3d(xmlDocPtr doc, FILE *outfile)
|
||||
{
|
||||
struct FileHeader fh;
|
||||
struct ModelHeader mh;
|
||||
xmlNode *root_element;
|
||||
xmlNode *curNode;
|
||||
xmlChar version[] = "version";
|
||||
|
||||
/* fetch the root element and check it */
|
||||
root_element = xmlDocGetRootElement(doc);
|
||||
assert(root_element->type == XML_ELEMENT_NODE);
|
||||
if (strcmp((char*)root_element->name, "G3D") != 0)
|
||||
{
|
||||
printf("G3D document not found!\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (strcmp((char*)xmlGetProp(root_element, version), "4") != 0)
|
||||
{
|
||||
printf("Only version 4 G3D documents can be handled!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* write out the file header */
|
||||
memset(&fh, 0, sizeof(struct FileHeader));
|
||||
fh.id[0] = 'G'; fh.id[1] = '3'; fh.id[2] = 'D'; fh.version=4;
|
||||
fwrite(&fh, sizeof(struct FileHeader), 1, outfile);
|
||||
|
||||
/* write out the model header */
|
||||
memset(&mh, 0, sizeof(struct ModelHeader));
|
||||
mh.meshCount = (uint16)countChildren(root_element, (xmlChar*)"Mesh");
|
||||
mh.type = 0;
|
||||
fwrite(&mh, sizeof(struct ModelHeader), 1, outfile);
|
||||
|
||||
/* process each mesh in the file */
|
||||
curNode = root_element->children;
|
||||
for (; curNode; curNode = curNode->next)
|
||||
{
|
||||
if (curNode->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
if (strcmp((char*)curNode->name, "Mesh") == 0)
|
||||
{
|
||||
if (processMesh(curNode, outfile) == FALSE)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Counts the number of child nodes with the specified name.
|
||||
*
|
||||
* @param n: Node to count the children from.
|
||||
* @param name: Name of the child nodes to count.
|
||||
*
|
||||
* @return: The number of child nodes.
|
||||
*/
|
||||
unsigned int countChildren(xmlNode *n, xmlChar *name)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
xmlNode *curNode = NULL;
|
||||
|
||||
for (curNode = n->children; curNode; curNode = curNode->next)
|
||||
{
|
||||
if (curNode->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
if (strcmp((char*)curNode->name, (char*)name) == 0)
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Processes all <Mesh> elements from the XML file.
|
||||
*
|
||||
* @param n: <Mesh> element
|
||||
* @param outfile: Binary file, opened as "wb", for output.
|
||||
*
|
||||
* @return: TRUE if successful, FALSE otherwise.
|
||||
*/
|
||||
int processMesh(xmlNode *n, FILE *outfile)
|
||||
{
|
||||
xmlChar name[] = "name";
|
||||
xmlChar frameCount[] = "frameCount";
|
||||
xmlChar vertexCount[] = "vertexCount";
|
||||
xmlChar indexCount[] = "indexCount";
|
||||
xmlChar specularPower[] = "specularPower";
|
||||
xmlChar opacity[] = "opacity";
|
||||
xmlChar twoSided[] = "twoSided";
|
||||
xmlChar customColor[] = "customColor";
|
||||
xmlChar diffuseTexture[] = "diffuseTexture";
|
||||
|
||||
float32 color[3];
|
||||
|
||||
struct MeshHeader mh;
|
||||
uint8 texname[NAMESIZE];
|
||||
|
||||
int foundFlag = FALSE;
|
||||
xmlNode *texn = NULL;
|
||||
xmlNode *curNode = NULL;
|
||||
|
||||
/* make sure we're dealing with a <Mesh> element */
|
||||
assert(strcmp((char*)n->name, "Mesh") == 0);
|
||||
|
||||
/* populate the MeshHeader structure appropriately */
|
||||
memset(&mh, 0, sizeof(struct MeshHeader));
|
||||
strncpy((char*)mh.name, (char*)xmlGetProp(n, name), NAMESIZE);
|
||||
mh.frameCount = (uint32)atoi((char*)xmlGetProp(n, frameCount));
|
||||
mh.vertexCount = (uint32)atoi((char*)xmlGetProp(n, vertexCount));
|
||||
mh.indexCount = (uint32)atoi((char*)xmlGetProp(n, indexCount));
|
||||
if (readColorChild(n, "Diffuse", color) == FALSE)
|
||||
return FALSE;
|
||||
mh.diffuseColor[0] = color[0];
|
||||
mh.diffuseColor[1] = color[1];
|
||||
mh.diffuseColor[2] = color[2];
|
||||
if (readColorChild(n, "Specular", color) == FALSE)
|
||||
return FALSE;
|
||||
mh.specularColor[0] = color[0];
|
||||
mh.specularColor[1] = color[1];
|
||||
mh.specularColor[2] = color[2];
|
||||
mh.specularPower = (float32)atof((char*)xmlGetProp(n, specularPower));
|
||||
mh.opacity = (float32)atof((char*)xmlGetProp(n, opacity));
|
||||
mh.properties = 0;
|
||||
if (strcmp((char*)xmlGetProp(n, twoSided), "true") == 0)
|
||||
mh.properties += (0x1 << mpfTwoSided);
|
||||
if (strcmp((char*)xmlGetProp(n, customColor), "true") == 0)
|
||||
mh.properties += (0x1 << mpfCustomColor);
|
||||
mh.textures = 0;
|
||||
if (strcmp((char*)xmlGetProp(n, diffuseTexture), "true") == 0)
|
||||
mh.textures = 1;
|
||||
|
||||
/* write the MeshHeader */
|
||||
fwrite(&mh, sizeof(struct MeshHeader), 1, outfile);
|
||||
|
||||
/* if we have a texture, then also write its name */
|
||||
foundFlag = FALSE;
|
||||
if (mh.textures)
|
||||
{
|
||||
for (texn=n->children; texn; texn = texn->next)
|
||||
{
|
||||
if (texn->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
if (strcmp((char*)texn->name, "Texture") == 0)
|
||||
{
|
||||
foundFlag = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (foundFlag == FALSE)
|
||||
{
|
||||
printf("Could not find <Texture> element!\n");
|
||||
return FALSE;
|
||||
}
|
||||
memset(texname, 0, NAMESIZE);
|
||||
strncpy((char*)texname,
|
||||
(char*)xmlGetProp(texn, (xmlChar*)"name"), NAMESIZE);
|
||||
fwrite(texname, NAMESIZE, 1, outfile);
|
||||
}
|
||||
|
||||
/* write out vertices */
|
||||
foundFlag = FALSE;
|
||||
for (curNode=n->children; curNode; curNode = curNode->next)
|
||||
{
|
||||
if (curNode->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
if (strcmp((char*)curNode->name, "Vertices") == 0)
|
||||
{
|
||||
foundFlag = TRUE;
|
||||
if (processVertices(curNode, outfile,
|
||||
mh.vertexCount) == FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (foundFlag == FALSE)
|
||||
{
|
||||
printf("No <Vertices> found!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* write out normals */
|
||||
foundFlag = FALSE;
|
||||
for (curNode=n->children; curNode; curNode = curNode->next)
|
||||
{
|
||||
if (curNode->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
if (strcmp((char*)curNode->name, "Normals") == 0)
|
||||
{
|
||||
foundFlag = TRUE;
|
||||
if (processNormals(curNode, outfile,
|
||||
mh.vertexCount) == FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (foundFlag == FALSE)
|
||||
{
|
||||
printf("No <Normals> found!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* write out texture coordinates */
|
||||
if (mh.textures)
|
||||
{
|
||||
foundFlag = FALSE;
|
||||
for (curNode=n->children; curNode; curNode = curNode->next)
|
||||
{
|
||||
if (curNode->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
if (strcmp((char*)curNode->name, "TexCoords")
|
||||
== 0)
|
||||
{
|
||||
foundFlag = TRUE;
|
||||
if (processTexcoords(curNode,
|
||||
outfile, mh.vertexCount) ==
|
||||
FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (foundFlag == FALSE)
|
||||
{
|
||||
printf("No <TexCoords> found!\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* write out indices */
|
||||
foundFlag = FALSE;
|
||||
for (curNode=n->children; curNode; curNode = curNode->next)
|
||||
{
|
||||
if (curNode->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
if (strcmp((char*)curNode->name, "Indices") == 0)
|
||||
{
|
||||
foundFlag = TRUE;
|
||||
if (processIndices(curNode, outfile,
|
||||
mh.indexCount) == FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (foundFlag == FALSE)
|
||||
{
|
||||
printf("No <Indices> found!\n");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reads the <Color> child of a child of a node.
|
||||
*
|
||||
* For example:
|
||||
* <Mesh>
|
||||
* <Diffuse>
|
||||
* <Color r="0.1" g="0.2" b="0.3"/>
|
||||
* </Diffuse>
|
||||
* </Mesh>
|
||||
* If <Mesh> is passed in as n and childNode is the string "Diffuse", then
|
||||
* the method will read the <Color> element from within the <Diffuse> element.
|
||||
*
|
||||
* @param n: Node from which the children should be read.
|
||||
* @param childNode: Name of the child element that owns a <Color> element.
|
||||
* @param color: float32[3] array to hold RGB color.
|
||||
*
|
||||
* @return TRUE if the method succeeds, FALSE otherwise.
|
||||
*/
|
||||
int readColorChild(xmlNode *n, char *childNode, float32 *color)
|
||||
{
|
||||
int foundFlag = FALSE;
|
||||
double r,g,b;
|
||||
xmlNode *curNode = NULL;
|
||||
|
||||
/* make sure that n is an element */
|
||||
assert(n->type == XML_ELEMENT_NODE);
|
||||
|
||||
/* search for the first child node matching the given name */
|
||||
for (curNode=n->children; curNode; curNode = curNode->next)
|
||||
{
|
||||
if (curNode->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
if (strcmp((char*)curNode->name, (char*)childNode) == 0)
|
||||
{
|
||||
foundFlag = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (foundFlag == FALSE)
|
||||
{
|
||||
printf("Could not find child node \"%s\"!\n", childNode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* search for a <Color> node child */
|
||||
for (curNode=curNode->children; curNode; curNode = curNode->next)
|
||||
{
|
||||
if (curNode->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
if (strcmp((char*)curNode->name, "Color") == 0)
|
||||
{
|
||||
r = atof((char*)xmlGetProp(curNode,
|
||||
(xmlChar*)"r"));
|
||||
g = atof((char*)xmlGetProp(curNode,
|
||||
(xmlChar*)"g"));
|
||||
b = atof((char*)xmlGetProp(curNode,
|
||||
(xmlChar*)"b"));
|
||||
color[0] = (float32)r;
|
||||
color[1] = (float32)g;
|
||||
color[2] = (float32)b;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("Could not find <Color> child of \"%s\"!\n", childNode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Writes vertices into the binary file.
|
||||
*
|
||||
* @param n: <Vertices> element.
|
||||
* @param outfile: Binary file, opened as "wb", for output.
|
||||
* @param vertexCount: Expected number of vertices to process.
|
||||
*
|
||||
* @return: TRUE if the method succeeds, FALSE otherwise.
|
||||
*/
|
||||
int processVertices(xmlNode *n, FILE *outfile, uint32 vertexCount)
|
||||
{
|
||||
xmlNode *v;
|
||||
uint32 counted_vertices = 0;
|
||||
float32 p[3];
|
||||
|
||||
/* check we've been passed a <Vertices> element */
|
||||
assert(n->type == XML_ELEMENT_NODE);
|
||||
assert(strcmp((char*)n->name, "Vertices") == 0);
|
||||
|
||||
/* iterate over all <Vertex> children */
|
||||
for (v=n->children; v; v=v->next)
|
||||
{
|
||||
if ((v->type == XML_ELEMENT_NODE) &&
|
||||
(strcmp((char*)v->name, "Vertex") == 0))
|
||||
{
|
||||
counted_vertices++;
|
||||
p[0] = (float32)atof((char*)xmlGetProp(v,
|
||||
(xmlChar*)"x"));
|
||||
p[1] = (float32)atof((char*)xmlGetProp(v,
|
||||
(xmlChar*)"y"));
|
||||
p[2] = (float32)atof((char*)xmlGetProp(v,
|
||||
(xmlChar*)"z"));
|
||||
fwrite(p, 3*sizeof(float32), 1, outfile);
|
||||
}
|
||||
}
|
||||
|
||||
/* check that the correct number of vertices were processed */
|
||||
if (counted_vertices != vertexCount)
|
||||
{
|
||||
printf("Found %d vertices, expected %d!\n",
|
||||
counted_vertices, vertexCount);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Writes normals into the binary file.
|
||||
*
|
||||
* @param n: <Normals> element.
|
||||
* @param outfile: Binary file, opened as "wb", for output.
|
||||
* @param vertexCount: Expected number of normals to process.
|
||||
*
|
||||
* @return: TRUE if the method succeeds, FALSE otherwise.
|
||||
*/
|
||||
int processNormals(xmlNode *n, FILE *outfile, uint32 vertexCount)
|
||||
{
|
||||
xmlNode *v;
|
||||
uint32 counted_normals = 0;
|
||||
float32 p[3];
|
||||
|
||||
/* check we've been passed a <Normals> element */
|
||||
assert(n->type == XML_ELEMENT_NODE);
|
||||
assert(strcmp((char*)n->name, "Normals") == 0);
|
||||
|
||||
/* iterate over all <Normal> elements */
|
||||
for (v=n->children; v; v=v->next)
|
||||
{
|
||||
if ((v->type == XML_ELEMENT_NODE) &&
|
||||
(strcmp((char*)v->name, "Normal") == 0))
|
||||
{
|
||||
counted_normals++;
|
||||
p[0] = (float32)atof((char*)xmlGetProp(v,
|
||||
(xmlChar*)"x"));
|
||||
p[1] = (float32)atof((char*)xmlGetProp(v,
|
||||
(xmlChar*)"y"));
|
||||
p[2] = (float32)atof((char*)xmlGetProp(v,
|
||||
(xmlChar*)"z"));
|
||||
fwrite(p, 3*sizeof(float32), 1, outfile);
|
||||
}
|
||||
}
|
||||
|
||||
/* check that the correct number of normals were processed */
|
||||
if (counted_normals != vertexCount)
|
||||
{
|
||||
printf("Found %d normals, expected %d!\n",
|
||||
counted_normals, vertexCount);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Writes texture coordinates into the binary file.
|
||||
*
|
||||
* @param n: <TexCoords> element.
|
||||
* @param outfile: Binary file, opened as "wb", for output.
|
||||
* @param vertexCount: Expected number of vertices to process.
|
||||
*
|
||||
* @return: TRUE if the method succeeds, FALSE otherwise.
|
||||
*/
|
||||
int processTexcoords(xmlNode *n, FILE *outfile, uint32 vertexCount)
|
||||
{
|
||||
xmlNode *v;
|
||||
uint32 counted_texco = 0;
|
||||
float32 p[2];
|
||||
|
||||
/* check we've been passed a <TexCoords> element */
|
||||
assert(n->type == XML_ELEMENT_NODE);
|
||||
assert(strcmp((char*)n->name, "TexCoords") == 0);
|
||||
|
||||
/* iterate over all <ST> children */
|
||||
for (v=n->children; v; v=v->next)
|
||||
{
|
||||
if ((v->type == XML_ELEMENT_NODE) &&
|
||||
(strcmp((char*)v->name, "ST") == 0))
|
||||
{
|
||||
++counted_texco;
|
||||
p[0] = (float32)atof((char*)xmlGetProp(v,
|
||||
(xmlChar*)"s"));
|
||||
p[1] = (float32)atof((char*)xmlGetProp(v,
|
||||
(xmlChar*)"t"));
|
||||
fwrite(p, 2*sizeof(float32), 1, outfile);
|
||||
}
|
||||
}
|
||||
|
||||
/* check that the correct number of texco were processed */
|
||||
if (counted_texco != vertexCount)
|
||||
{
|
||||
printf("Found %d texture coordinates, expected %d!\n",
|
||||
counted_texco, vertexCount);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Writes indices into the binary file.
|
||||
*
|
||||
* @param n: <Indices> element.
|
||||
* @param outfile: Binary file, opened as "wb", for output.
|
||||
* @param indexCount: Expected number of indices to process.
|
||||
*
|
||||
* @return: TRUE if the method succeeds, FALSE otherwise.
|
||||
*/
|
||||
int processIndices(xmlNode *n, FILE *outfile, uint32 indexCount)
|
||||
{
|
||||
xmlNode *v;
|
||||
uint32 counted_indices = 0;
|
||||
uint32 index;
|
||||
|
||||
/* check we've been passed an <Indices> element */
|
||||
assert(n->type == XML_ELEMENT_NODE);
|
||||
assert(strcmp((char*)n->name, "Indices") == 0);
|
||||
|
||||
/* iterate over all <Ix> children */
|
||||
for (v=n->children; v; v=v->next)
|
||||
{
|
||||
if ((v->type == XML_ELEMENT_NODE) &&
|
||||
(strcmp((char*)v->name, "Ix") == 0))
|
||||
{
|
||||
++counted_indices;
|
||||
index = (uint32)atoi((char*)xmlGetProp(v,
|
||||
(xmlChar*)"i"));
|
||||
fwrite(&index, 1*sizeof(uint32), 1, outfile);
|
||||
}
|
||||
}
|
||||
|
||||
/* check that the correct number of indices were processed */
|
||||
if (counted_indices != indexCount)
|
||||
{
|
||||
printf("Found %d indices, expected %d!\n",
|
||||
counted_indices, indexCount);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue