diff options
author | Luca Bonavita <mindrones@gmail.com> | 2010-10-30 17:25:24 +0400 |
---|---|---|
committer | Luca Bonavita <mindrones@gmail.com> | 2010-10-30 17:25:24 +0400 |
commit | e548e3e1d81e03c94993734de8af1ed7670a6d1c (patch) | |
tree | 32506fb4723e200884555f52929bcdd48803f7e6 /doc/blender_file_format/BlendFileDnaExporter_25.py | |
parent | ae9c4b164951e34d3d0858a990ea58c0eb2ced75 (diff) |
== blender file format ==
Hello, from the bconf 2010 from Jeroen and Luca. Our first combined commit :)
Automatically create sdna documentations from Trunk.
Usage:
blender2.5 -b -P BlendFileDnaExporter_25.py [-- [options]]
Options:
--dna-keep-blend: doesn't delete the produced blend file DNA export to html
--dna-debug: sets the logging level to DEBUG (lots of additional info)
--dna-versioned' saves version informations in the html and blend filenames
--dna-overwrite-css' overwrite dna.css, useful when modifying css in the script
Examples:
default: % blender2.5 -b -P BlendFileDnaExporter_25.py
with options: % blender2.5 -b -P BlendFileDnaExporter_25.py -- --dna-keep-blend --dna-debug
Diffstat (limited to 'doc/blender_file_format/BlendFileDnaExporter_25.py')
-rwxr-xr-x | doc/blender_file_format/BlendFileDnaExporter_25.py | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/doc/blender_file_format/BlendFileDnaExporter_25.py b/doc/blender_file_format/BlendFileDnaExporter_25.py new file mode 100755 index 00000000000..77656f43ae5 --- /dev/null +++ b/doc/blender_file_format/BlendFileDnaExporter_25.py @@ -0,0 +1,477 @@ +#! /usr/bin/env python3 + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# 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. +# +# ***** END GPL LICENCE BLOCK ***** + +###################################################### +# +# Name: +# dna.py +# +# Description: +# Creates a browsable DNA output to HTML. +# +# Author: +# Jeroen Bakker +# +# Version: +# v0.1 (12-05-2009) - migration of original source code to python. +# Added code to support blender 2.5 branch +# v0.2 (25-05-2009) - integrated with BlendFileReader.py +# +# Input: +# blender build executable +# +# Output: +# dna.html +# dna.css (will only be created when not existing) +# +# Startup: +# ./blender -P BlendFileDnaExporter.py +# +# Process: +# 1: write blend file with SDNA info +# 2: read blend header from blend file +# 3: seek DNA1 file-block +# 4: read dna record from blend file +# 5: close and eventually delete temp blend file +# 6: export dna to html and css +# 7: quit blender +# +###################################################### + +import struct +import sys +import getopt # command line arguments handling +from string import Template # strings completion + + +# logs +import logging +log = logging.getLogger("BlendFileDnaExporter") + +if '--dna-debug' in sys.argv: + logging.basicConfig(level=logging.DEBUG) +else: + logging.basicConfig(level=logging.INFO) + + +class DNACatalogHTML: + ''' + DNACatalog is a catalog of all information in the DNA1 file-block + ''' + + def __init__(self, catalog, bpy_module = None): + self.Catalog = catalog + self.bpy = bpy_module + + def WriteToHTML(self, handle): + + dna_html_template = """ + <!DOCTYPE html PUBLIC -//W3C//DTD HTML 4.01 Transitional//EN http://www.w3.org/TR/html4/loose.dtd> + <html> + <head> + <link rel="stylesheet" type="text/css" href="dna.css" media="screen, print" /> + <meta http-equiv="Content-Type" content="text/html"; charset="ISO-8859-1" /> + <title>The mystery of the blend</title> + </head> + <body> + <div class=title> + Blender ${version}<br/> + Internal SDNA structures + </div> + Architecture: ${bitness} ${endianness}<br/> + Build revision: <a href="https://svn.blender.org/svnroot/bf-blender/!svn/bc/${revision}/trunk/">${revision}</a><br/> + File format reference: <a href="mystery_of_the_blend.html">The mystery of the blend</a> by Jeroen Bakker<br/> + <h1>Index of blender structures</h1> + <ul class=multicolumn> + ${structs_list} + </ul> + ${structs_content} + </body> + </html>""" + + header = self.Catalog.Header + bpy = self.bpy + + # ${version} and ${revision} + if bpy: + version = '.'.join(map(str, bpy.app.version)) + revision = bpy.app.build_revision[:-1] + else: + version = str(header.Version) + revision = 'Unknown' + + # ${bitness} + if header.PointerSize == 8: + bitness = '64 bit' + else: + bitness = '32 bit' + + # ${endianness} + if header.LittleEndianness: + endianess= 'Little endianness' + else: + endianess= 'Big endianness' + + # ${structs_list} + log.debug("Creating structs index") + structs_list = '' + list_item = '<li class="multicolumn">({0}) <a href="#{1}">{1}</a></li>\n' + structureIndex = 0 + for structure in self.Catalog.Structs: + structs_list += list_item.format(structureIndex, structure.Type.Name) + structureIndex+=1 + + # ${structs_content} + log.debug("Creating structs content") + structs_content = '' + for structure in self.Catalog.Structs: + log.debug(structure.Type.Name) + structs_content += self.Structure(structure) + + d = dict( + version = version, + revision = revision, + bitness = bitness, + endianness = endianess, + structs_list = structs_list, + structs_content = structs_content + ) + + dna_html = Template(dna_html_template).substitute(d) + dna_html = self.format(dna_html) + handle.write(dna_html) + + def Structure(self, structure): + struct_table_template = """ + <table><a name="${struct_name}"></a> + <caption><a href="#${struct_name}">${struct_name}</a></caption> + <thead> + <tr> + <th>reference</th> + <th>structure</th> + <th>type</th> + <th>name</th> + <th>offset</th> + <th>size</th> + </tr> + </thead> + <tbody> + ${fields} + </tbody> + </table> + <label>Total size: ${size} bytes</label><br/> + <label>(<a href="#top">top</a>)</label><br/>""" + + d = dict( + struct_name = structure.Type.Name, + fields = self.StructureFields(structure, None, 0), + size = str(structure.Type.Size) + ) + + struct_table = Template(struct_table_template).substitute(d) + return struct_table + + def StructureFields(self, structure, parentReference, offset): + fields = '' + for field in structure.Fields: + fields += self.StructureField(field, structure, parentReference, offset) + offset += field.Size(self.Catalog.Header) + return fields + + def StructureField(self, field, structure, parentReference, offset): + structure_field_template = """ + <tr> + <td>${reference}</td> + <td>${struct}</td> + <td>${type}</td> + <td>${name}</td> + <td>${offset}</td> + <td>${size}</td> + </tr>""" + + if field.Type.Structure == None or field.Name.IsPointer(): + + # ${reference} + reference = field.Name.AsReference(parentReference) + + # ${struct} + if parentReference != None: + struct = '<a href="#{0}">{0}</a>'.format(structure.Type.Name) + else: + struct = structure.Type.Name + + # ${type} + type = field.Type.Name + + # ${name} + name = field.Name.Name + + # ${offset} + # offset already set + + # ${size} + size = field.Size(self.Catalog.Header) + + d = dict( + reference = reference, + struct = struct, + type = type, + name = name, + offset = offset, + size = size + ) + + structure_field = Template(structure_field_template).substitute(d) + + elif field.Type.Structure != None: + reference = field.Name.AsReference(parentReference) + structure_field = self.StructureFields(field.Type.Structure, reference, offset) + + return structure_field + + def indent(self, input, dent, startswith = ''): + output = '' + if dent < 0: + for line in input.split('\n'): + dent = abs(dent) + output += line[dent:] + '\n' # unindent of a desired amount + elif dent == 0: + for line in input.split('\n'): + output += line.lstrip() + '\n' # remove indentation completely + elif dent > 0: + for line in input.split('\n'): + output += ' '* dent + line + '\n' + return output + + def format(self, input): + diff = { + '\n<!DOCTYPE':'<!DOCTYPE', + '\n</ul>' :'</ul>', + '<a name' :'\n<a name', + '<tr>\n' :'<tr>', + '<tr>' :' <tr>', + '</th>\n' :'</th>', + '</td>\n' :'</td>', + '<tbody>\n' :'<tbody>' + } + output = self.indent(input, 0) + for key, value in diff.items(): + output = output.replace(key, value) + return output + + def WriteToCSS(self, handle): + ''' + Write the Cascading stylesheet template to the handle + It is expected that the handle is a Filehandle + ''' + css = """ + @CHARSET "ISO-8859-1"; + + body { + font-family: verdana; + font-size: small; + } + + div.title { + font-size: large; + text-align: center; + } + + h1 { + page-break-before: always; + } + + h1, h2 { + background-color: #D3D3D3; + color:#404040; + margin-right: 3%; + padding-left: 40px; + } + + h1:hover{ + background-color: #EBEBEB; + } + + h3 { + padding-left: 40px; + } + + table { + border-width: 1px; + border-style: solid; + border-color: #000000; + border-collapse: collapse; + width: 94%; + margin: 20px 3% 10px; + } + + caption { + margin-bottom: 5px; + } + + th { + background-color: #000000; + color:#ffffff; + padding-left:5px; + padding-right:5px; + } + + tr { + } + + td { + border-width: 1px; + border-style: solid; + border-color: #a0a0a0; + padding-left:5px; + padding-right:5px; + } + + label { + float:right; + margin-right: 3%; + } + + ul.multicolumn { + list-style:none; + float:left; + padding-right:0px; + margin-right:0px; + } + + li.multicolumn { + float:left; + width:200px; + margin-right:0px; + } + + a { + color:#a000a0; + text-decoration:none; + } + + a:hover { + color:#a000a0; + text-decoration:underline; + } + """ + + css = self.indent(css, 0) + + handle.write(css) + + +def usage(): + print("\nUsage: \n\tblender2.5 -b -P BlendFileDnaExporter_25.py [-- [options]]") + print("Options:") + print("\t--dna-keep-blend: doesn't delete the produced blend file DNA export to html") + print("\t--dna-debug: sets the logging level to DEBUG (lots of additional info)") + print("\t--dna-versioned' saves version informations in the html and blend filenames") + print("\t--dna-overwrite-css' overwrite dna.css, useful when modifying css in the script") + print("Examples:") + print("\tdefault: % blender2.5 -b -P BlendFileDnaExporter_25.py") + print("\twith options: % blender2.5 -b -P BlendFileDnaExporter_25.py -- --dna-keep-blend --dna-debug\n") + + +###################################################### +# Main +###################################################### + +def main(): + + import os, os.path + + try: + bpy = __import__('bpy') + + # Files + if '--dna-versioned' in sys.argv: + blender_version = '_'.join(map(str, bpy.app.version)) + filename = 'dna-{0}-{1}_endian-{2}-r{3}'.format(sys.arch, sys.byteorder, blender_version, bpy.app.build_revision[2:-1]) + else: + filename = 'dna' + dir = os.path.dirname(__file__) + Path_Blend = os.path.join(dir, filename + '.blend') # temporary blend file + Path_HTML = os.path.join(dir, filename + '.html') # output html file + Path_CSS = os.path.join(dir, 'dna.css') # output css file + + # create a blend file for dna parsing + if not os.path.exists(Path_Blend): + log.info("1: write temp blend file with SDNA info") + log.info(" saving to: " + Path_Blend) + try: + bpy.ops.wm.save_as_mainfile(filepath = Path_Blend, copy = True, compress = False) + except: + log.error("Filename {0} does not exist and can't be created... quitting".format(Path_Blend)) + return + else: + log.info("1: found blend file with SDNA info") + log.info(" " + Path_Blend) + + # read blend header from blend file + log.info("2: read file:") + + if not dir in sys.path: + sys.path.append(dir) + import BlendFileReader + + handle = BlendFileReader.openBlendFile(Path_Blend) + blendfile = BlendFileReader.BlendFile(handle) + catalog = DNACatalogHTML(blendfile.Catalog, bpy) + + # close temp file + handle.close() + + # deleting or not? + if '--dna-keep-blend' in sys.argv: + # keep the blend, useful for studying hexdumps + log.info("5: closing blend file:") + log.info(" {0}".format(Path_Blend)) + else: + # delete the blend + log.info("5: close and delete temp blend:") + log.info(" {0}".format(Path_Blend)) + os.remove(Path_Blend) + + # export dna to xhtml + log.info("6: export sdna to xhtml file") + handleHTML = open(Path_HTML, "w") + catalog.WriteToHTML(handleHTML) + handleHTML.close() + + # only write the css when doesn't exist or at explicit request + if not os.path.exists(Path_CSS) or '--dna-overwrite-css' in sys.argv: + handleCSS = open(Path_CSS, "w") + catalog.WriteToCSS(handleCSS) + handleCSS.close() + + # quit blender + if not bpy.app.background: + log.info("7: quit blender") + bpy.ops.wm.exit_blender() + + except ImportError: + log.warning(" skipping, not running in Blender") + usage() + sys.exit(2) + + +if __name__ == '__main__': + main() |