#!/usr/bin/python # vim:tabstop=4:shiftwidth=4:syntax=python:expandtab """ This Version: $Id: 3ds2egg.py,v 1.13 2008/06/03 03:48:15 andyp Exp $ Info: info >at< pfastergames.com Extended from: http://panda3d.org/phpbb2/viewtopic.php?t=3378 .___..__ .___.___.___.__..__ . . | [__)[__ [__ [__ | |[__)|\/| | | \[___[___| |__|| \| | obj2egg.py [n##][b][t][s] filename1.3ds ... -n regenerate normals with # degree smoothing exaple -n30 (normals at less 30 degrees will be smoothed) -b make binarmals -t make tangents -s show in pview licensed under WTFPL (http://sam.zoy.org/wtfpl/) """ from pandac.PandaModules import * import struct import math import string import getopt import sys, os def floats(float_list): """coerce a list of strings that represent floats into a list of floats""" return [ float(number) for number in float_list ] def ints(int_list): """coerce a list of strings that represent integers into a list of integers""" return [ int(number) for number in int_list ] class TDSChunk: CHUNK_ATTRIB = {} # if "container" is True, then try to subdivide the chunk. # "name" is a printable name for the id. # see initChunkmakers() and TDSChunk.chunkmaker() for how the # "make" attrib is used. # the pieces of the .egg are produced on the return path of # a recursive traversal of the "chunk tree....have a look at # a few of the eggifygeometry() methods in various chunks... # generally, leaf chunks push relevant data up into their # parent's attribute dict. CHUNK_ATTRIB[0x4d4d] = { "container": True, "name": "root" } CHUNK_ATTRIB[0x0002] = { "container": False, "name": "version" } CHUNK_ATTRIB[0x0010] = { "container": False, "name": "colorf" } CHUNK_ATTRIB[0x0011] = { "container": False, "name": "color24" } CHUNK_ATTRIB[0x0030] = { "container": False, "name": "percentage" } CHUNK_ATTRIB[0x0100] = { "container": False, "name": "scale" } CHUNK_ATTRIB[0x1200] = { "container": True, "name": "solidbackground" } CHUNK_ATTRIB[0x1201] = { "container": True, "name": "usesolidbackground" } CHUNK_ATTRIB[0x1300] = { "container": False, "name": "vgradient" } CHUNK_ATTRIB[0x1400] = { "container": False, "name": "loshadowbias" } CHUNK_ATTRIB[0x1410] = { "container": False, "name": "hishadowbias" } CHUNK_ATTRIB[0x1420] = { "container": False, "name": "shadowmapsize" } CHUNK_ATTRIB[0x1450] = { "container": False, "name": "shadowfilter" } CHUNK_ATTRIB[0x1460] = { "container": False, "name": "raybias" } CHUNK_ATTRIB[0x2100] = { "container": True, "name": "ambientlight" } CHUNK_ATTRIB[0x2200] = { "container": False, "name": "fog" } CHUNK_ATTRIB[0x2300] = { "container": False, "name": "distancecue" } CHUNK_ATTRIB[0x2302] = { "container": False, "name": "layerfog" } CHUNK_ATTRIB[0x3d3d] = { "container": True, "name": "edit3ds" } CHUNK_ATTRIB[0x3d3e] = { "container": False, "name": "meshversion" } CHUNK_ATTRIB[0x4000] = { "container": True, "name": "namedobject" } CHUNK_ATTRIB[0x4100] = { "container": True, "name": "triobject" } CHUNK_ATTRIB[0x4110] = { "container": False, "name": "points" } CHUNK_ATTRIB[0x4111] = { "container": False, "name": "vertexoptions" } CHUNK_ATTRIB[0x4120] = { "container": True, "name": "faces" } CHUNK_ATTRIB[0x4130] = { "container": False, "name": "meshmatgroup" } CHUNK_ATTRIB[0x4140] = { "container": False, "name": "uvs" } CHUNK_ATTRIB[0x4150] = { "container": False, "name": "smoothgroup" } CHUNK_ATTRIB[0x4160] = { "container": False, "name": "meshmatrix" } CHUNK_ATTRIB[0x4165] = { "container": False, "name": "meshcolor" } CHUNK_ATTRIB[0x4700] = { "container": False, "name": "camera" } CHUNK_ATTRIB[0x8000] = { "container": True, "name": "xdata" } CHUNK_ATTRIB[0x8001] = { "container": False, "name": "xdataentry" } CHUNK_ATTRIB[0xa000] = { "container": False, "name": "materialname" } CHUNK_ATTRIB[0xa010] = { "container": True, "name": "ambient" } CHUNK_ATTRIB[0xa020] = { "container": True, "name": "diffuse" } CHUNK_ATTRIB[0xa030] = { "container": True, "name": "specular" } CHUNK_ATTRIB[0xa040] = { "container": True, "name": "shininess" } CHUNK_ATTRIB[0xa041] = { "container": True, "name": "shininess2" } CHUNK_ATTRIB[0xa050] = { "container": True, "name": "transparency" } CHUNK_ATTRIB[0xa052] = { "container": True, "name": "xpfall" } CHUNK_ATTRIB[0xa053] = { "container": True, "name": "refblur" } CHUNK_ATTRIB[0xa081] = { "container": True, "name": "twosided" } CHUNK_ATTRIB[0xa084] = { "container": True, "name": "selfillumpercent" } CHUNK_ATTRIB[0xa087] = { "container": True, "name": "wiresize" } CHUNK_ATTRIB[0xa08a] = { "container": True, "name": "xpfallin" } CHUNK_ATTRIB[0xa100] = { "container": True, "name": "shading" } CHUNK_ATTRIB[0xa200] = { "container": True, "name": "texturemap" } CHUNK_ATTRIB[0xa220] = { "container": True, "name": "reflectionmap" } CHUNK_ATTRIB[0xa300] = { "container": False, "name": "mapname" } CHUNK_ATTRIB[0xa351] = { "container": True, "name": "maptiling" } CHUNK_ATTRIB[0xa353] = { "container": True, "name": "maptexblur" } CHUNK_ATTRIB[0xafff] = { "container": True, "name": "material" } CHUNK_ATTRIB[0xb000] = { "container": True, "name": "keyf3ds" } CHUNK_ATTRIB[0xb002] = { "container": True, "name": "objectnodetag" } CHUNK_ATTRIB[0xb008] = { "container": False, "name": "kfseg" } CHUNK_ATTRIB[0xb009] = { "container": False, "name": "kftime" } CHUNK_ATTRIB[0xb00a] = { "container": False, "name": "kfhdr" } CHUNK_ATTRIB[0xb010] = { "container": False, "name": "nodeheader" } CHUNK_ATTRIB[0xb011] = { "container": False, "name": "instancename" } CHUNK_ATTRIB[0xb013] = { "container": False, "name": "pivot" } CHUNK_ATTRIB[0xb014] = { "container": False, "name": "boundbox" } CHUNK_ATTRIB[0xb020] = { "container": False, "name": "trackpos" } CHUNK_ATTRIB[0xb021] = { "container": False, "name": "trackrot" } CHUNK_ATTRIB[0xb022] = { "container": False, "name": "trackscl" } CHUNK_ATTRIB[0xb030] = { "container": False, "name": "nodeid" } def __init__(self, parent=None): self.parent = parent self.child = [] self.id = 0 self.base = 0 self.limit = 0 self.data = None self.attrib = {} def put(self, key, value): self.attrib[key] = value return self def get(self, key): if self.attrib.has_key(key): return self.attrib[key] return None def has_key(self, key): return self.attrib.has_key(key) def isContainer(self, id): if TDSChunk.CHUNK_ATTRIB.has_key(id): attr = TDSChunk.CHUNK_ATTRIB[id] return attr["container"] return False def getchunknamebyid(self, id): if TDSChunk.CHUNK_ATTRIB.has_key(id): attr = TDSChunk.CHUNK_ATTRIB[id] return attr["name"] return "UNKNOWN_%04x" % id def addChild(self, child): """add a child chunk to this chunk""" self.child.append(child) child.parent = self return self def subchunkbase(self, data): """skip over variable length data in a chunk""" return self.base + 6 def chunkmaker(self, parentchunk, id): """make a chunk, perhaps specialized, by .3ds chunk id""" maker = None if TDSChunk.CHUNK_ATTRIB.has_key(id) and TDSChunk.CHUNK_ATTRIB[id].has_key("make"): maker = TDSChunk.CHUNK_ATTRIB[id]["make"] if maker is None: maker = TDSChunk child = maker(parentchunk) child.id = id return child def subdivide(self, depth, parentchunk, data, verbose=True): """subdivide a chunk, provided its marked as a container""" if not self.isContainer(self.id): return self base = self.subchunkbase(data) limit = self.limit if (limit - base) < 6: return self while base < limit: id, length = struct.unpack("