From 2c65f06323d310a712ed0688c922ea6a64c5e4fd Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 5 Aug 2017 15:23:24 +0300 Subject: [PATCH 01/50] Improves custom definition tokens menu, improves README --- .gitignore | 1 + README.md | 46 +++++++++++++++---------------- __init__.py | 79 +++++++++++++++++++++++++++++------------------------ 3 files changed, 68 insertions(+), 58 deletions(-) diff --git a/.gitignore b/.gitignore index 24abb64..a10c294 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /.project /.pylintrc /*.bat +/*.html diff --git a/README.md b/README.md index d0c106d..b334a6f 100644 --- a/README.md +++ b/README.md @@ -261,28 +261,28 @@ An object may contain other text in addition to definition tokens as long as the Blender adds a running index (e.g. `.003`) to the end of duplicate object, material, etc. names. This is handled correctly, you need not worry about it. The logic for removing the index simply checks if `.` is the fourth last character in the object name and simply removes it an everything after it. -Below is a full list of all definition tokens. For more information on what each of them do, read the rest of the readme. - -Token | Usable In | Description -------|-----------|------------ -`bounds` | Object name | The bounds object. -`collision` | Object name | A collision box. -`c` | Object name | Define object color. -`qt` | Object name | Sort quads in top section. -`qb` | Object name | Sort quads in bottom section. -`qn` | Object name | Sort quads in north section. -`qe` | Object name | Sort quads in east section. -`qs` | Object name | Sort quads in south section. -`qw` | Object name | Sort quads in west section. -`qo` | Object name | Sort quads in omni section. -`gridb` | Object name | Write brick grid `b` symbol. -`gridd` | Object name | Write brick grid `d` symbol. -`gridu` | Object name | Write brick grid `u` symbol. -`grid-` | Object name | Write brick grid `-` symbol. -`gridx` | Object name | Write brick grid `x` symbol. -`blank` | Material name | Do not write a color. -`cadd` | Material name, vertex color layer name | Use color as an additive color. -`csub` | Material name, vertex color layer name | Use color as a subtractive color. +Below is a full list of all definition tokens with a brief description. For more information on what each of them do, see the rest of the readme. + +Token | Category | Usable In | Description +------|----------|-----------|------------ +`bounds` | Definition objects | Object name | The bounds object. See [Definition Objects](#definition-objects). +`collision` | Definition objects | Object name | A BLB collision box/cuboid. +`gridb` | Definition objects: brick grid | Object name | Write brick grid `b` symbol. See [Defining Brick Grid](#defining-brick-grid). +`gridd` | Definition objects: brick grid | Object name | Write brick grid `d` symbol. +`gridu` | Definition objects: brick grid | Object name | Write brick grid `u` symbol. +`grid-` | Definition objects: brick grid | Object name | Write brick grid `-` symbol. +`gridx` | Definition objects: brick grid | Object name | Write brick grid `x` symbol. +`qt` | Quad sorting | Object name | Sort quads in top section. See [Defining Quad Sorting & Coverage](#defining-quad-sorting--coverage). +`qb` | Quad sorting | Object name | Sort quads in bottom section. +`qn` | Quad sorting | Object name | Sort quads in north section. +`qe` | Quad sorting | Object name | Sort quads in east section. +`qs` | Quad sorting | Object name | Sort quads in south section. +`qw` | Quad sorting | Object name | Sort quads in west section. +`qo` | Quad sorting | Object name | Sort quads in omni section. +`c` | Colors | Object name | Define object color in object name. See [Defining Colors](#defining-colors). +`blank` | Colors | Material name | Do not write a color: use in-game spray can color as is. +`cadd` | Colors | Material name, vertex color layer name | Add material/vertex color to in-game spray can color. +`csub` | Colors | Material name, vertex color layer name | Subtract material/vertex color from in-game spray can color. ### Definition Objects ### When a definition object token is read in an object's name it is treated as a definition object. Definition objects are never exported as visual 3D models, in fact they are not exported at all. Instead the data they contain in their name (or elsewhere) and the 3D space they represent is processed further to acquire the necessary information for the BLB file. @@ -417,7 +417,7 @@ Normal vectors | [Optional](#round-normals) [UV coordinates](#uv-mapping) | No ## Troubleshooting ## -Solutions to common issues with the BLB Exporter. If you have another issue with the exporter be sure to enable the [Write Log](#write-log) property and export again. The log file may contain warnings or errors describing the issue with the model. +Solutions to common issues with the BLB Exporter. If you have another issue with the exporter be sure to enable the [Write Log](#write-log) property and export again. The log file may contain warnings or errors describing issues with the models and how to fix them. ### Automatically calculated UV coordinates for brick textures are distorted ### The automatic UV calculation is only designed to work with rectangular quads. Manually define UV coordinates for non-rectangular quads. diff --git a/__init__.py b/__init__.py index d8d03d1..abc5b3c 100644 --- a/__init__.py +++ b/__init__.py @@ -45,6 +45,7 @@ # TODO: Render brick preview. # TODO: Panels in the UI? # TODO: Check that all docstrings and comments are still up to date. +# TODO: Quad sorting is per object but BLBs support per-quad sorting: the exporter does not support quad sorting for smoothed objects. class ExportBLB(bpy.types.Operator, ExportHelper): @@ -171,9 +172,9 @@ class ExportBLB(bpy.types.Operator, ExportHelper): default=True, ) - # ------------------- - # Calculate Collision - # ------------------- + # --------- + # Collision + # --------- calculate_collision = BoolProperty( name="Calculate Collision", description="Calculate cuboid collision for the brick if nothing is defined manually", @@ -345,12 +346,6 @@ class ExportBLB(bpy.types.Operator, ExportHelper): default="collision", ) - deftoken_color = StringProperty( - name="Object Color", - description="Token for specifying a color for an object using its name. Token must be followed by 4 values (red green blue alpha) separated with spaces using a comma (,) as decimal separator. Integers 0-255 also supported.", - default="c", - ) - # Sections deftoken_quad_sort_top = StringProperty( @@ -469,21 +464,27 @@ class ExportBLB(bpy.types.Operator, ExportHelper): # Colors + deftoken_color = StringProperty( + name="Object Color", + description="Token for specifying a color for an object using its name. Token must be followed by 4 values (red green blue alpha) separated with spaces using a comma (,) as decimal separator. Integers 0-255 also supported.", + default="c", + ) + deftoken_color_blank = StringProperty( - name="No Color", - description="Token for specifying that no color should be written for these faces", + name="In-Game Color", + description="No color is written for these faces: in-game spray color is used", default="blank", ) deftoken_color_add = StringProperty( name="Additive Color", - description="Token for specifying that this color is additive", + description="Blender material/vertex color is added to in-game spray color", default="cadd", ) deftoken_color_sub = StringProperty( name="Subtractive Color", - description="Token for specifying that this color is subtractive", + description="Blender material/vertex color is subtracted from in-game spray color", default="csub", ) @@ -778,11 +779,11 @@ def draw_grid_definition_property(symbol, prop_name): """A helper function for drawing the definition properties.""" row = box.row() - split = row.split(percentage=0.35) + split = row.split(percentage=0.25) col = split.column() col.label("{}".format(symbol)) - split = split.split(percentage=0.6) + split = split.split(percentage=0.7) col = split.column() col.prop(self, prop_name, "") @@ -792,39 +793,27 @@ def draw_grid_definition_property(symbol, prop_name): # This has duplicate data but I don't know how to access the property names defined earlier since self.deftoken_bounds.name doesn't seem to work. # For some reason self.deftoken_bounds = "deftoken_bounds" instead of an instance of StringProperty. + row = box.row() + row.alignment = "CENTER" + row.label("Definition Objects (Object Name)") draw_definition_property("Brick Bounds", "deftoken_bounds") draw_definition_property("Collision Cuboids", "deftoken_collision") - draw_definition_property("Object Colors", "deftoken_color") - # Sorting definitions. - - draw_definition_property("Top Quads", "deftoken_quad_sort_top") - draw_definition_property("Bottom Quads", "deftoken_quad_sort_bottom") - draw_definition_property("North Quads", "deftoken_quad_sort_north") - draw_definition_property("East Quads", "deftoken_quad_sort_east") - draw_definition_property("South Quads", "deftoken_quad_sort_south") - draw_definition_property("West Quads", "deftoken_quad_sort_west") - draw_definition_property("Omni Quads", "deftoken_quad_sort_omni") - draw_definition_property("No Color", "deftoken_color_blank") - draw_definition_property("Additive Color", "deftoken_color_add") - draw_definition_property("Subtractive Color", "deftoken_color_sub") - - # Grid definitions. + row = box.row() + row.alignment = "CENTER" + row.label("Definition Objects: Brick Grid (Object Name)") row = box.row() - split = row.split(percentage=0.35) + split = row.split(percentage=0.25) col = split.column() - col.label("Brick Grid") col.label("Symbol") - split = split.split(percentage=0.6) + split = split.split(percentage=0.7) col = split.column() - col.label() col.label("Token") split = split.split() col = split.column() - col.label() col.label("Priority") draw_grid_definition_property("b", "deftoken_gridb") @@ -833,6 +822,25 @@ def draw_grid_definition_property(symbol, prop_name): draw_grid_definition_property("-", "deftoken_griddash") draw_grid_definition_property("x", "deftoken_gridx") + row = box.row() + row.alignment = "CENTER" + row.label("Quad Sorting (Object Name)") + draw_definition_property("Top Quads", "deftoken_quad_sort_top") + draw_definition_property("Bottom Quads", "deftoken_quad_sort_bottom") + draw_definition_property("North Quads", "deftoken_quad_sort_north") + draw_definition_property("East Quads", "deftoken_quad_sort_east") + draw_definition_property("South Quads", "deftoken_quad_sort_south") + draw_definition_property("West Quads", "deftoken_quad_sort_west") + draw_definition_property("Omni Quads", "deftoken_quad_sort_omni") + + row = box.row() + row.alignment = "CENTER" + row.label("Colors (Object/Material/Vertex Color Name)") + draw_definition_property("Object Colors", "deftoken_color") + draw_definition_property("In-Game Color", "deftoken_color_blank") + draw_definition_property("Additive Color", "deftoken_color_add") + draw_definition_property("Subtractive Color", "deftoken_color_sub") + layout.separator() # ======= @@ -881,5 +889,6 @@ def unregister(): bpy.utils.unregister_module(__name__) bpy.types.INFO_MT_file_export.remove(menu_export) + if __name__ == "__main__": register() From e92f63c29e11efef49f9979f08f6dce479f83e47 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 11 Nov 2017 21:04:10 +0200 Subject: [PATCH 02/50] Add detailed descriptions of all warning messages to README, tweak warns --- README.md | 458 ++++++++++++++++++++++++++++++++++++++++++++++- __init__.py | 12 ++ blb_processor.py | 29 +-- const.py | 1 + export_blb.py | 3 + 5 files changed, 490 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b334a6f..6784c75 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,8 @@ The add-on does not support importing .BLB files yet. 1. [Troubleshooting](#troubleshooting) 1. [Automatically calculated UV coordinates for brick textures are distorted](#automatically-calculated-uv-coordinates-for-brick-textures-are-distorted) 1. [Automatically calculated UV coordinates for brick textures are rotated incorrectly](#automatically-calculated-uv-coordinates-for-brick-textures-are-rotated-incorrectly) +1. [Warning & Error Log Messages](#warning--error-log-messages) + 1. [Warnings](#warnings) 1. [Contributors](#contributors) ## Features ## @@ -351,7 +353,7 @@ Method | Overrides | Extent of Coloring | RGB Values | Alpha Value | Notes -------|-----------|--------------------|------------|-------------|------ Object Colors | In-game paint color | Entire object (color & alpha)| In object name after the [Color token](#mesh-definition-tokens-color) [**(1)**](#defining-colors-fn-1) | In object name after the red, green, and blue values | Implemented only to support legacy 3D brick models, not recommended for use. Material Colors | Object Colors | Assigned faces (color & alpha) | In `Material` tab as `Diffuse Color` | In `Material` tab under `Transparency` in `Alpha` slider| Recommended method for defining colors. Multiple materials may be used in a single object. -Vertex Colors | Material Colors | Entire object (per-vertex color), entire object (alpha) | In `Data` tab under `Vertex Color` as a vertex color layer, modified using the `Vertex Paint` mode | In `Data` tab under `Vertex Color` as the name of the vertex color layer [**(2)**](#defining-colors-fn-2) | Creating a vertex color layers will color the entire object white, but the color of individual vertices may be changed. +Vertex Colors | Material Colors | Entire object (per-vertex color), entire object (alpha) | In `Data` tab under `Vertex Color` as a vertex color layer, modified using the `Vertex Paint` mode | In `Data` tab under `Vertex Color` as the name of the vertex color layer [**(2)**](#defining-colors-fn-2) | Creating a vertex color layers will color the entire object white, but the color of individual vertices may be changed. There are three definition tokens that are specific to dealing with colors. @@ -418,6 +420,7 @@ Normal vectors | [Optional](#round-normals) ## Troubleshooting ## Solutions to common issues with the BLB Exporter. If you have another issue with the exporter be sure to enable the [Write Log](#write-log) property and export again. The log file may contain warnings or errors describing issues with the models and how to fix them. +Additional instructions on how to fix specific issues are detailed in the [Warning & Error Log Messages](#warning--error-log-messages) section. ### Automatically calculated UV coordinates for brick textures are distorted ### The automatic UV calculation is only designed to work with rectangular quads. Manually define UV coordinates for non-rectangular quads. @@ -425,6 +428,459 @@ The automatic UV calculation is only designed to work with rectangular quads. Ma ### Automatically calculated UV coordinates for brick textures are rotated incorrectly ### The quad with incorrectly rotated UV coordinates (e.g. the lightest side of the SIDE texture pointing sideways instead of up) is not a perfect rectangle. Even one vertex being off by some minuscule, visually indistinguishable amount from a perfectly rectangular shape can cause the automatic UV calculation to incorrectly determine the rotation of the quad. Double check all 4 coordinates of the quad and manually correct any floating point errors. If working on axis-aligned quads or if the vertices should be on grid points snapping the coordinates of the problem quad to grid coordinates using `Mesh > Snap > Snap Selection to Grid` usually fixes floating point errors. +## Warning & Error Log Messages ## +Detailed explanations of the warning and error messages logged by the program and directions on how to solve the associated issues. +In the messages listed in this section the `#` character is used to represent a variable numerical value. +Text surrounded by `%` describes a variable alphanumeric value. + +### Warnings ### +Warning log messages can be ignored as the issues are automatically corrected, but the resulting brick may not behave or look as excepted. +It is recommended to manually adjust the brick until no warning messages are present in the output log. + + + + + + + + + + + + + + + + + +
MessageCalculated bounds have a non-integer size # # #, rounding up.
CauseNo Bounds object was defined and the axis-aligned bounding box calculated from the visible 3D models has non-integer dimensions as a brick.
EffectBrick dimensions of the calculated bounding box will be rounded up to ensure that collision cuboids (if any) still fit within the bounds.
Solutions
    +
  1. Recommended: Manually define a bounds object.
  2. +
  3. Manually ensure that the visible parts of your brick model form an axis-aligned bounding box that has a valid size for a brick.
  4. +
+ + + + + + + + + + + + + + + + + +
MessageDefined bounds have a non-integer size # # #, rounding to a precision of #.
CauseThe axis-aligned bounding box calculated from the defined bounds object has non-integer dimensions as a brick.
EffectThe brick dimensions will be rounded to the specified precision.
SolutionEnsure that the defined bounds object aligns with the brick grid.
+ + + + + + + + + + + + + + + + + +
MessageBrick name was to be sourced from the name of the bounds definition object but no bounds definition object exists, file name used instead.
CauseThe "Brick Name(s) from" export property (either in single or multiple brick export mode) value was set to "Bounds" but no manually defined bounds object was found.
EffectThe file name specified in the export dialog is used as the name of the BLB file instead.
SolutionCreate a bounds object and in the name of the object separate the name of the BLB file from the bounds definition token with a whitespace character.
+ + + + + + + + + + + + + + + + + +
MessageBrick name was to be sourced from the name of the bounds definition object but no brick name was found after the bounds definition (separated with a space), file name used instead.
CauseThe "Brick Name(s) from" export property (either in single or multiple brick export mode) value was set to "Bounds" but no string was found after the bounds definition token in the name of the bounds object.
EffectThe file name specified in the export dialog is used as the name of the BLB file instead.
SolutionSeparate the name of the BLB file from the bounds definition token with a whitespace character, such as a space.
+ + + + + + + + + + + + + + + + + +
MessageNo brick grid definitions found. Automatically generated brick grid may be undesirable.
CauseThere are no brick grid definition objects.
EffectA full block brick grid will be generated. Brick will act as if it were a basic cuboid brick of that size.
SolutionCreate brick grid definitions for the model.
+ + + + + + + + + + + + + + + + + +
Message# brick grid definition(s) found but was/were not processed. Automatically generated brick grid may be undesirable.
CauseAn error occurred for all brick grid definition objects when converting into a brick placement rule.
EffectA full block brick grid will be generated. Brick will act as if it were a basic cuboid brick of that size.
SolutionCreate valid brick grid definitions for the model.
+ + + + + + + + + + + + + + + + + + + + + +
MessageCollision definition object '%object name%' has more than 8 vertices suggesting a shape other than a cuboid. The bounding box of this mesh will be used.
CauseA collision definition object contained more than 8 vertices.
EffectNo effect other this warning message.
SolutionEnsure that all collision definition objects have 2-8 vertices only.
NotesThis warning message exists to promote good modeling standards. The exporter uses the axis-aligned bounding box of a collision definition object as the BLB collision cuboid so from a technical standpoint the shape of the mesh is irrelevant. However from a practical standpoint, it does not make sense to use a shape other than a cuboid made from 8 vertices (or merely 2 vertices if you're being minimal) to represent a collision cuboid.
+ + + + + + + + + + + + + + + + + +
MessageNo collision definitions found. Brick will have no collision.
CauseNo collision definition objects were found and the Calculate Collision export property was disabled.
EffectThe brick will have no collision data and it cannot be interacted with in game in any way.
Solutions
    +
  1. Manually define collision objects.
  2. +
  3. Enable the Calculate Collision export property.
  4. +
+ + + + + + + + + + + + + + + + + +
Message# collision definition(s) found but was/were not processed. Brick will have no collision.
CauseAn error occurred for all collision definition objects when calculating their dimensions.
EffectThe brick will have no collision data and it cannot be interacted with in game in any way.
Solutions
    +
  1. Manually define valid collision objects.
  2. +
  3. Enable the Calculate Collision export property.
  4. +
+ + + + + + + + + + + + + + + + + + + + + +
MessageObject '%object name%' cannot be used to define bounds, must be a mesh.
CauseA non-mesh object such as a camera had a bounds definition token in its name.
EffectNo effect other this warning message.
SolutionRemove the bounds definition token from the name of the object.
NotesThis warning message exists to promote good naming standards. Definition token strings should not be used with anything other than definition objects..
+ + + + + + + + + + + + + + + + + + + + + +
MessageObject '%object name%' cannot be used to define brick grid, must be a mesh.
CauseA non-mesh object such as a camera had a brick grid definition token in its name.
EffectNo effect other this warning message.
SolutionRemove the brick grid definition token from the name of the object.
NotesThis warning message exists to promote good naming standards. Definition token strings should not be used with anything other than definition objects..
+ + + + + + + + + + + + + + + + + + + + + +
MessageObject '%object name%' cannot be used to define collision, must be a mesh.
CauseA non-mesh object such as a camera had a collision definition token in its name.
EffectNo effect other this warning message.
SolutionRemove the collision definition token from the name of the object.
NotesThis warning message exists to promote good naming standards. Definition token strings should not be used with anything other than definition objects..
+ + + + + + + + + + + + + + + + + +
MessageMultiple bounds definitions found. '%object name%' definition ignored.
CauseOne brick contained more than one bounds definition object.
EffectThe oldest bounds definition object is used and the rest are discarded.
SolutionDelete the additional bounds definition objects.
+ + + + + + + + + + + + + + + + + +
MessageMultiple brick grid definitions in object '%object name%', only the first one is used.
CauseA single definition object contained more than one brick grid definition token.
EffectOnly the first brick grid definition token is used.
SolutionDelete the additional brick grid definition tokens.
+ + + + + + + + + + + + + + + + + +
MessageNo brick bounds definition found. Automatically calculated brick size may be undesirable.
CauseBrick did not have a bounds definition object.
EffectThe axis-aligned bounding box of all visible meshes will rounded to the nearest brick dimensions and used as the brick bounds.
SolutionCreate a bounds definition object.
+ + + + + + + + + + + + + + + + + +
MessageMore than 4 color values defined for object '%object name%', only the first 4 values (RGBA) are used.
CauseObject name contained more than 4 color values. Colors must be defined by exactly 4 numbers.
EffectOnly the first 4 numbers are used as color values.
SolutionRemove the additional numbers.
+ + + + + + + + + + + + + + + + + +
MessageObject '%object name%' has # vertex color layers, only using the first.
CauseThe object had more than one vertex color layer.
EffectOnly the first vertex color layer is used.
SolutionDelete the additional vertex color layers.
+ + + + + + + + + + + + + + + + + +
MessageObject '%object name%' has # section definitions, only using the first one: %section name%
CauseThe object had more than one quad section definition token.
EffectOnly the first section definition token is used.
SolutionDelete the additional section definition tokens.
+ + + + + + + + + + + + + + + + + +
MessageMore than one brick texture name found in material '%material name%', only using the first one.
CauseThe material name contained more than one brick texture name.
EffectOnly the first brick texture name is used.
SolutionDelete the additional brick texture names.
+ + + + + + + + + + + + + + + + + +
MessageFace has UV coordinates but no brick texture, using SIDE by default.
CauseThe material assigned to a face had no brick texture defined but the face had UV coordinates.
EffectThe `side` brick texture is used for the face.
SolutionManually define brick textures in the names of the materials that are assigned to UV mapped faces.
+ + + + + + + + + + + + + + + + + +
MessageNo alpha value set in vertex color layer name, using 1.0.
CauseThe color defined in the vertex color layer did not contain an alpha value.
EffectAlpha of `1.0` is used resulting in an opaque color.
SolutionDefine the alpha value in the verter color layer name.
+ + + + + + + + + + + + + + + + + +
Message# triangles degenerated to quads.
CauseA mesh contained a triangle.
EffectThe triangle is forcefully converted into a quad by copying the first vertex and using that as the last vertex of a quad. This conversion has three different outcomes: +
    +
  • If flat shading is used for the face there is no change visually and the face will look like a triangle in game.
  • +
  • If the face and adjacent connected faces are planar and smooth shading is used there are no visual anomalies.
  • +
  • If the face and adjacent connected faces are not planar and smooth shading is used there may be shading errors.
  • +
SolutionDo not use triangles in any meshes.
+ + + + + + + + + + + + + + + + + +
Message# n-gons skipped.
CauseA mesh contained a face made from more than 4 vertices.
EffectFaces made from more than 4 vertices are not exported.
SolutionManually rebuild faces made from more than 4 vertices using quads.
+ ## Contributors ## - [Nick Smith](https://github.com/portify) - The original source code for reading, processing, and writing Blender data into the .BLB format. It has essentially been completely rewritten since. - [Demian Wright](https://github.com/DemianWright) - Everything else. diff --git a/__init__.py b/__init__.py index abc5b3c..d3665ee 100644 --- a/__init__.py +++ b/__init__.py @@ -46,6 +46,18 @@ # TODO: Panels in the UI? # TODO: Check that all docstrings and comments are still up to date. # TODO: Quad sorting is per object but BLBs support per-quad sorting: the exporter does not support quad sorting for smoothed objects. +# TODO: Add a section about brick size to the readme. +# TODO: Add a section about brick grid to the readme. +# TODO: Improve terminology section in the readme. Use dl? +# TODO: Make the capitalization consistent in the readme. +# TODO: Consider reformatting readme to have one sentence per line for nicer diffs. +# TODO: Consider refactoring readme for consistent use of mesh, model, and object words. +# TODO: Consider using unique IDs for errors and warnings? [WARNING:IOBLBW0000] and [ERROR:IOBLBE0000]? +# TODO: Clarify brick grid and brick grid placement rules. +# TODO: Clarify which errors occur when autogenerating brick grid. +# TODO: Improve warning and error messages. +# TODO: Fix link to Port's GitHub profile. +# TODO: Calculate Bounds property. class ExportBLB(bpy.types.Operator, ExportHelper): diff --git a/blb_processor.py b/blb_processor.py index 8bf8cf0..e5dfff5 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -31,9 +31,8 @@ import bpy from mathutils import Euler, Vector -import numpy - import bmesh +import numpy from . import common, const, logger from .const import Axis3D, AxisPlane3D, X, Y, Z @@ -943,18 +942,19 @@ def __record_bounds_data(properties, blb_data, bounds_data): for index, value in enumerate(bounds_size): # Round to the specified error amount. bounds_size[index] = round(properties.human_error * round(value / properties.human_error)) + # FIXME: Force to integer size? # The value type must be int because you can't have partial plates. Returns a list. blb_data.brick_size = __force_to_ints(bounds_size) if properties.blendprop.export_count == "SINGLE" and properties.blendprop.brick_name_source == "BOUNDS": if bounds_data.object_name is None: - logger.warning( - "Brick name was to be sourced from the name of the bounds definition object but no bounds definition object exists, file name used instead.", 1) + logger.warning("Brick name was to be sourced from the name of the bounds definition object but no bounds definition object exists, file name used instead.", 1) else: if len(bounds_data.object_name.split()) == 1: logger.warning( - "Brick name was to be sourced from the name of the bounds definition object but no brick name was found after the bounds definition (separated with a space), file name used instead.", 1) + "Brick name was to be sourced from the name of the bounds definition object but no brick name was found after the bounds definition (separated with a space), file name used instead.", + 1) else: # Brick name follows the bounds definition, must be separated by a space. # Substring the object name: everything after properties.deftokens.bounds and 1 space character till the end of the name. @@ -976,7 +976,8 @@ def __record_bounds_data(properties, blb_data, bounds_data): return "When exporting multiple bricks in separate layers, the brick name must be after the bounds definition (separated with a space) in the bounds definition object name." else: logger.warning( - "Brick name was to be sourced from the name of the bounds definition object but no brick name was found after the bounds definition (separated with a space), file name used instead.", 1) + "Brick name was to be sourced from the name of the bounds definition object but no brick name was found after the bounds definition (separated with a space), file name used instead.", + 1) else: # Brick name follows the bounds definition, must be separated by a space. # Substring the object name: everything after properties.deftokens.bounds and 1 space character till the end of the name. @@ -2129,16 +2130,18 @@ def __process_collision_definitions(properties, bounds_data, definition_objects, defcount = len(definition_objects) # Log messages for collision definitions. + # FIXME: Skip collision processing if calculating collision! if defcount == 0: if properties.blendprop.calculate_collision: - logger.warning("No collision definitions found. Calculating full brick collision.", 1) + logger.info("No collision definitions found. Brick collision will be the same size as the brick bounds.", 1) else: logger.warning("No collision definitions found. Brick will have no collision.", 1) elif defcount == 1: if processed == 0: if properties.blendprop.calculate_collision: + # TODO: Remove. logger.warning( - "{} collision definition found but was not processed. Calculating full brick collision.".format(defcount), 1) + "{} collision definition found but was not processed. Brick collision will be the same size as the brick bounds.".format(defcount), 1) else: logger.warning( "{} collision definition found but was not processed. Brick will have no collision.".format(defcount), 1) @@ -2149,6 +2152,7 @@ def __process_collision_definitions(properties, bounds_data, definition_objects, # Found more than one. if processed == 0: if properties.blendprop.calculate_collision: + # TODO: Remove. logger.warning( "{} collision definitions found but were not processed. Calculating full brick collision.".format(defcount), 1) else: @@ -2377,7 +2381,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ # Did user define at least 4 numerical values? if size >= 4: if size > 4: - logger.info("More than 4 colors defined for colored object '{}', only the first four values were used.".format(object_name), 2) + logger.warning("More than 4 color values defined for object '{}', only the first 4 values (RGBA) are used.".format(object_name), 2) # We're only interested in the first 4 values: R G B A floats = floats[:4] @@ -2406,7 +2410,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ if section_count >= 1: section = const.BLBQuadSection(properties.quad_sort_definitions.index(quad_sections[0])) if section_count > 1: - logger.warning("Object '{}' has {} section definitions, only one is allowed. Using the first one: {}".format( + logger.warning("Object '{}' has {} section definitions, only using the first one: {}".format( object_name, section_count, section), 2) # TODO: Do forward axis rotation of section in the format_blb_data function? @@ -2515,7 +2519,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ brick_texture = const.BrickTexture[texnames[0]] if texcount > 1: - logger.info("More than one brick texture name found in material '{}', only the first one is used.".format(matname), 2) + logger.warning("More than one brick texture name found in material '{}', only using the first one.".format(matname), 2) # else: No material name or a brick texture was not specified. Keep None to skip automatic UV generation. # === @@ -2555,7 +2559,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ if brick_texture is None: # Fall back to SIDE texture if nothing was specified. brick_texture = const.BrickTexture.SIDE - logger.warning("Please specify a brick texture if also specifying UV coordinates, using SIDE by default.", 2) + logger.warning("Face has UV coordinates but no brick texture, using SIDE by default.", 2) # Do we have UV coordinates for a tri? if len(uvs) == 3: @@ -2645,6 +2649,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ # The game can actually render per-vertex alpha but it doesn't seem to stick for longer than a second for whatever reason. name = common.to_float_or_none(" ".join(tokens)) + # FIXME: vertex_color_alpha is never assigned. if vertex_color_alpha is None: if name is None: vertex_color_alpha = 1.0 diff --git a/const.py b/const.py index da5b2e4..15db863 100644 --- a/const.py +++ b/const.py @@ -73,6 +73,7 @@ def as_list(cls): """Returns the names of the members of this enum as a list of uppercase strings.""" return [member.name for member in BrickTexture] + # BLB file strings. BLB_BRICK_TYPE_SPECIAL = "SPECIAL" BLB_SECTION_SEPARATOR = "---------------- {} QUADS ----------------" diff --git a/export_blb.py b/export_blb.py index 8cff1e7..4f88298 100644 --- a/export_blb.py +++ b/export_blb.py @@ -123,6 +123,7 @@ def __init__(self, properties): # Used for rounding vertex positions to the brick grid. self.human_error = Decimal("0.1") else: + # FIXME: Typo? Shouldn't I define self.human_error and self.plate_height? properties.human_error = properties.human_error * self.scale properties.plate_height = properties.plate_heigh * self.scale @@ -360,6 +361,7 @@ def export_brick(context, properties, export_dir, export_file, file_name, object # Group has at least one object in a visible layer, export group. # Else: Export all groups in the scene, no need to check anything. + # TODO: Is the newline intentional or left from development? logger.info("\nExporting group '{}'.".format(group.name)) # Objects in multiple groups will be exported more than once. @@ -390,6 +392,7 @@ def export_brick(context, properties, export_dir, export_file, file_name, object continue # Layer has at least one object in a visible layer, export layer objects. + # TODO: Is the newline intentional or left from development? logger.info("\nExporting layer {}.".format(layer_idx + 1)) # Get brick name from bounds. message = export_brick(context, deriv_properties, export_dir, None, file_name, layer_objects) From 35ba688dabf8f69c31e4c4fd915e965a58173a80 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 11 Nov 2017 21:35:25 +0200 Subject: [PATCH 03/50] Change a logged development error into an exception --- blb_processor.py | 16 ++++++++-------- export_blb.py | 4 ++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/blb_processor.py b/blb_processor.py index e5dfff5..81625aa 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -108,7 +108,7 @@ def make_decimal(value, quantize=None): elif isinstance(quantize, Decimal): pass else: - # Development error. + # EXCEPTION raise ValueError("__to_decimal(value) quantize must be a string or a Decimal, was '{}'.".format(type(quantize))) # Calculate the fraction that will be used to do the rounding to an arbitrary number. @@ -741,7 +741,7 @@ def __calculate_coverage(calculate_side=None, hide_adjacent=None, brick_grid=Non area += __count_occurrences(const.GRID_OUTSIDE, row, True) else: - # Development error. + # EXCEPTION raise RuntimeError("Invalid quad section index '{}'.".format(index)) else: @@ -1399,7 +1399,7 @@ def __get_2d_angle_axis(angle, plane=AxisPlane3D.XY): """ # The angle could easily be normalized here, but doing this has helped me track a couple of mistakes in the code. if angle < 0 or angle > const.TWO_PI: - # Development error. + # EXCEPTION raise ValueError("__get_2d_angle_axis(angle) expects angle to be normalized to range [0,2pi], value was:", angle) if angle >= const.RAD_315_DEG or angle >= 0 and angle < const.RAD_45_DEG: @@ -1439,7 +1439,7 @@ def __get_2d_angle_axis(angle, plane=AxisPlane3D.XY): def __get_normal_axis(normal): - """Determines the closes axis of the specified normal vector. + """Determines the closest axis of the specified normal vector. Args: normal (Vector): A normal vector in XYZ-space. @@ -1542,8 +1542,8 @@ def __get_normal_axis(normal): plane = None if point: - logger.error("Normal vector is point and has no direction. Returning +X axis by default.") - return Axis3D.POS_X + # EXCEPTION + raise ValueError("__get_normal_axis(normal) expects a vector, point '{}' given instead.".format(normal)) if plane is None: # TODO: Z-axis is ignored for now. Assume XY-plane. @@ -1654,7 +1654,7 @@ def get_side_uv(length): # Sanity check. if len(vert_coords) < 4: - # Development error. + # EXCEPTION raise ValueError("__calculate_uvs(brick_texture, vert_coords, normal) function expects a quad, input polygon was not a quad.") idx_coord = [(idx, coord) for idx, coord in enumerate(vert_coords)] @@ -1826,7 +1826,7 @@ def get_side_uv(length): (h, w)) else: - # Development error. + # EXCEPTION raise ValueError("Unknown texture name '{}'".format(brick_texture)) #print("__calculate_uvs | uvs_sorted:") diff --git a/export_blb.py b/export_blb.py index 4f88298..d35c56f 100644 --- a/export_blb.py +++ b/export_blb.py @@ -133,6 +133,7 @@ def __init__(self, properties): prec = properties.float_precision if common.to_float_or_none(prec) is None: + # FIXME: Concatenate message. self.error_message = "Invalid floating point precision value given." else: if prec == "0": @@ -166,6 +167,7 @@ def __build_grid_priority_tuples(cls, properties): tokens[properties.deftoken_gridb_priority] = properties.deftoken_gridb.upper() if None in tokens: + # FIXME: Return string. logger.error("Two or more brick grid definitions had the same priority. Unable to proceed.") return None else: @@ -347,6 +349,7 @@ def export_brick(context, properties, export_dir, export_file, file_name, object # Bricks in groups. if deriv_properties.blendprop.brick_definition == "GROUPS": if len(bpy.data.groups) == 0: + # RETURN ON ERROR return "No groups to export." else: # For all groups in the scene. @@ -403,4 +406,5 @@ def export_brick(context, properties, export_dir, export_file, file_name, object return message if exported == 0: + # RETURN ON ERROR return "Nothing to export in layers." From 578f7a2f5cd10f33ce85cedec0c81934a1e55c92 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 13:38:17 +0200 Subject: [PATCH 04/50] Add detailed descriptions of all error messages to README, tweak errors --- README.md | 610 ++++++++++++++++++++++++++++++++++++++++++++++- __init__.py | 2 + blb_processor.py | 24 +- export_blb.py | 10 +- 4 files changed, 629 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 6784c75..8c30bff 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,9 @@ The add-on does not support importing .BLB files yet. 1. [Automatically calculated UV coordinates for brick textures are rotated incorrectly](#automatically-calculated-uv-coordinates-for-brick-textures-are-rotated-incorrectly) 1. [Warning & Error Log Messages](#warning--error-log-messages) 1. [Warnings](#warnings) + 1. [Errors](#errors) + 1. [Fatal Errors](#fatal-errors) + 1. [Non-Fatal Errors](#non-fatal-errors) 1. [Contributors](#contributors) ## Features ## @@ -443,7 +446,7 @@ It is recommended to manually adjust the brick until no warning messages are pre Cause - No Bounds object was defined and the axis-aligned bounding box calculated from the visible 3D models has non-integer dimensions as a brick. + No bounds object was defined and the axis-aligned bounding box calculated from the visible 3D models has non-integer dimensions as a brick. Effect @@ -482,7 +485,7 @@ It is recommended to manually adjust the brick until no warning messages are pre Cause - The "Brick Name(s) from" export property (either in single or multiple brick export mode) value was set to "Bounds" but no manually defined bounds object was found. + The "Brick Name(s) from" export property (either in single or multiple brick export mode) value was set to Bounds but no manually defined bounds object was found. Effect @@ -500,7 +503,7 @@ It is recommended to manually adjust the brick until no warning messages are pre Cause - The "Brick Name(s) from" export property (either in single or multiple brick export mode) value was set to "Bounds" but no string was found after the bounds definition token in the name of the bounds object. + The "Brick Name(s) from" export property (either in single or multiple brick export mode) value was set to Bounds but no string was found after the bounds definition token in the name of the bounds object. Effect @@ -881,6 +884,607 @@ It is recommended to manually adjust the brick until no warning messages are pre +### Errors ### +Errors are separated into two categories: fatal and non-fatal errors. +* Fatal errors cause the program execution to stop as there is insuffient or incorrect input data to process into a Blockland brick. +* Non-fatal errors occur when the exporter attempts to do something (due to invalid input data) that would have caused an error when loading or using the exported brick in game. +Alternatively the user has attempted to do something that is explicitly not allowed by the exporter or would lead to a mathematical error. + +It is recommended to manually adjust the brick until no error messages are present in the output log. + +#### Fatal Errors #### +Fatal errors always lead to the program execution stopping. + + + + + + + + + + + + + + + + + +
MessageTwo or more brick grid definitions had the same priority.
CauseTwo or more user defined brick grid definition tokens had the same priority number.
ReasonThe user-intended priority order of the tokens cannot be automatically determined.
SolutionEnsure that all custom brick grid definition tokens have a unique priority number.
+ + + + + + + + + + + + + + + + + +
MessageWhen exporting multiple bricks in separate layers, a bounds definition object must exist in every layer. It is also used to provide a name for the brick.
CauseThe following export properties are set: + + + + + + + + + + + + + + + + + + + + + +
PropertyValue
Bricks to ExportMultiple
Brick Names from (Multiple Export)Bounds
Bricks Defined by (Multiple Export)Layers
+ And a visible layer did not contain a bounds definition object. +
ReasonIn the interest of promoting good workflow practices this is considered a fatal error instead of automatically naming the brick by the index of the layer it is contained in.
SolutionEnsure that there is exactly one valid bounds definition object in every visible layer.
+ + + + + + + + + + + + + + + + + +
MessageWhen exporting multiple bricks in separate layers, the brick name must be after the bounds definition token (separated with a space) in the bounds definition object name.
CauseThe following export properties are set: + + + + + + + + + + + + + + + + + + + + + +
PropertyValue
Bricks to ExportMultiple
Brick Names from (Multiple Export)Bounds
Bricks Defined by (Multiple Export)Layers
+ And a bounds definition object name did not contain the name of the brick. +
ReasonIn the interest of promoting good workflow practices this is considered a fatal error instead of automatically naming the brick by the index of the layer it is contained in.
SolutionEnsure that each bounds definition object contains the name of that brick.
+ + + + + + + + + + + + + + + + + +
MessageUnable to store UV coordinates in object '%object name%' while it is in edit mode.
CauseThe Store UVs property is enabled and the exporter attempted to write UV coordinates to a Blender object that is currently in edit mode.
ReasonThe authors have not bothered to find a way to automatically disable and re-enable the edit mode.
SolutionConfirm that you are not in the edit object interaction mode by changing to the Object Mode in the 3D viewport.
+ + + + + + + + + + + + + + + + + +
MessageBrick has no volume, brick could not be rendered in-game.
CauseThe bounds definition object or the automatically calculated axis-aligned bounding box of the brick was smaller than 1 brick on one or more axis.
ReasonA brick size cannot be zero on any axis.
SolutionEnsure that the manually defined bounds definition object or if none is defined, the actual model of the brick, is larger than a 1x1 plate brick.
+ + + + + + + + + + + + + + + + + +
MessageBrick size (#x#x#) exceeds the maximum brick size of 64 wide 64 deep and 256 plates tall.
CauseThe bounds definition object or the automatically calculated axis-aligned bounding box of the brick is larger than maximum brick size supported by Blockland.
ReasonThe maximum size of a single Blockland brick is 64 plates wide 64 plates deep and 256 plates tall.
SolutionMake your brick bounds smaller, while keeping in mind the rules regarding other definition objects.
+ + + + + + + + + + + + + + + + + +
MessageNo faces to export.
CauseNone of the non-definition objects had any faces.
ReasonCreating a brick with no visible faces is pointless.
SolutionEnsure that there is at least one face to export.
+ + + + + + + + + + + + + + + + + +
MessageNo objects to export.
CausesDepends on the values of various export properties. + + + + + + + + + + + + + + + + + + +
Value of Bricks to Export
ValueCauses
Single + + + + + + + + + + + + + + + + + + + + + + +
Value of Export Only (Single Export)
ValueCause
SelectionNo objects were selected. Selected objects have an orange outline.
LayersThere are no objects in the currently visible layers.
SceneThere are no objects in the current scene. In other words none of the layers in the current scene contained objects.
+
Multiple + + + + + + + + + + + + + + + + + + +
Value of Export Bricks in (Multiple Export)
ValueCauses
Layers + + + + + + + + + + + + + + + + + + +
Value of Bricks Defined by (Multiple Export)
ValueCause
GroupsNone of the groups in the current scene had any objects in the visible layers.
LayersNone of the visible layers contained any objects.
+
Scene + + + + + + + + + + + + + + + + + + +
Value of Bricks Defined by (Multiple Export)
ValueCause
GroupsNone of the groups in the current scene contained any objects.
LayersNone of the layers in the current scene contained any objects.
+
+
+
ReasonNo data to export, nothing to do.
SolutionsDepends on the values of various export properties. + + + + + + + + + + + + + + + + + + +
Value of Bricks to Export
ValueSolutions
Single + + + + + + + + + + + + + + + + + + + + + + +
Value of Export Only (Single Export)
ValueSolution
SelectionSelect some objects.
LayersSelect one or more layers with objects.
SceneYou are attempting to export an empty scene. Either add some objects to a layer in the scene or ensure that you are not in the wrong scene.
+
Multiple + + + + + + + + + + + + + + + + + + +
Value of Bricks to Export
ValueSolutions
Layers + + + + + + + + + + + + + + + + + + +
Value of Bricks Defined by (Multiple Export)
ValueSolution
GroupsEnsure that your groups have objects assigned to them and that you have selected layers with objects in them.
LayersSelect layers with objects.
+
Scene + + + + + + + + + + + + + + + + + + +
Value of Bricks Defined by (Multiple Export)
ValueSolution
GroupsAdd objects to a group in the current scene.
LayersYou are attempting to export an empty scene. Either add some objects to a layer in the scene or ensure that you are not in the wrong scene.
+
+
+
+ +#### Non-Fatal Errors #### + + + + + + + + + + + + + + + + + + + + + +
MessageBrick grid definition object '%object name%' has vertices outside the calculated brick bounds. Definition ignored.
CauseA brick grid definition object had vertices outside the automatically calculated brick bounds.
ReasonBlockland does not allow brick grid definitions outside the bounds of a brick.
EffectThe brick grid definition object is discarded.
Solutions
    +
  • Recommended: Manually create a bounds definition object that properly fits around the defined brick grid.
  • +
  • Ensure that the specified brick grid definition object is fully contained within the axis-aligned bounding box of the visual model.
  • +
+ + + + + + + + + + + + + + + + + + + + + +
MessageBrick grid definition object '%object name%' has vertices outside the bounds definition object '%object name%'. Definition ignored.
CauseA brick grid definition object had vertices outside the bounds object.
ReasonBlockland does not allow brick grid definitions outside the bounds of a brick.
EffectThe brick grid definition object is discarded.
Solutions
    +
  • Ensure that the specified brick grid definition object is fully contained within the bounds object.
  • +
  • Make the bounds definition object larger.
  • +
+ + + + + + + + + + + + + + + + + + + + + +
MessageBrick grid definition object '%object name%' has no volume. Definition ignored.
CauseThe axis-aligned bounding box of a brick grid definition object was either a plane or a point.
ReasonA brick grid definition with no volume does not produce any brick placement rules when calculating the brick grid.
EffectThe brick grid definition object is discarded.
SolutionEnsure that the specified brick grid definition object is not a point or a plane and has some volume.
+ + + + + + + + + + + + + + + + + + + + + +
Message# collision boxes defined but 10 is the maximum. Only the first 10 will be used.
CauseMore than 10 collision definition objects were found.
ReasonA BLB file may have a maximum of 10 collision boxes.
EffectOnly the 10 oldest objects marked as collision definitions will be used.
SolutionDelete the additional collision definition objects.
+ + + + + + + + + + + + + + + + + + + + + +
MessageCollision definition object '%object name%' has less than 2 vertices. Definition ignored.
CauseA collision definition object had 1 or 0 vertices.
ReasonAt least two points are required to specify a volume in three-dimensional space.
EffectThe specified collision definition object is discarded.
SolutionEnsure that the specified collision definition object has at least 2 vertices.
+ + + + + + + + + + + + + + + + + + + + + +
MessageCollision definition object '%object name%' has no volume. Definition ignored.
CauseThe axis-aligned bounding box of a collision definition object was either a plane or a point.
ReasonA two-dimensional collision box does nothing in game.
EffectThe collision definition object is discarded.
SolutionEnsure that the specified collision definition object is not a point or a plane and has some volume.
+ + + + + + + + + + + + + + + + + + + + + +
MessageCollision definition object '%object name%' has vertices outside the calculated brick bounds. Definition ignored.
CauseA collision definition object had vertices outside the automatically calculated brick bounds.
ReasonCollision boxes outside the bounds of a brick cause strange behavior in game.
EffectThe collision definition object is discarded.
Solutions
    +
  • Recommended: Manually create a bounds definition object that properly fits around the defined collision definition objects.
  • +
  • Ensure that the specified brick grid definition object is fully contained within the axis-aligned bounding box of the visual model.
  • +
+ + + + + + + + + + + + + + + + + + + + + +
MessageCollision definition object '%object name%' has vertices outside the bounds definition object '%object name%'. Definition ignored.
CauseA collision definition object had vertices outside the bounds object.
ReasonCollision boxes outside the bounds of a brick cause strange behavior in game.
EffectThe collision definition object is discarded.
Solutions
    +
  • Ensure that the specified collision definition object is fully contained within the bounds object.
  • +
  • Make the bounds definition object larger.
  • +
+ ## Contributors ## - [Nick Smith](https://github.com/portify) - The original source code for reading, processing, and writing Blender data into the .BLB format. It has essentially been completely rewritten since. - [Demian Wright](https://github.com/DemianWright) - Everything else. diff --git a/__init__.py b/__init__.py index d3665ee..128438f 100644 --- a/__init__.py +++ b/__init__.py @@ -58,6 +58,8 @@ # TODO: Improve warning and error messages. # TODO: Fix link to Port's GitHub profile. # TODO: Calculate Bounds property. +# TODO: Definition object bounds rules to readme. +# TODO: Define what a visible mesh is. class ExportBLB(bpy.types.Operator, ExportHelper): diff --git a/blb_processor.py b/blb_processor.py index 81625aa..9f46c8e 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -967,13 +967,14 @@ def __record_bounds_data(properties, blb_data, bounds_data): # RETURN ON ERROR return "When exporting multiple bricks in separate layers, a bounds definition object must exist in every layer. It is also used to provide a name for the brick." else: + # TODO: Does this work? Does it actually export multiple bricks or overwrite the first one? logger.warning( "Brick name was to be sourced from the name of the bounds definition object but no bounds definition object exists, file name used instead.", 1) else: if len(bounds_data.object_name.split()) == 1: if properties.blendprop.brick_definition == "LAYERS": # RETURN ON ERROR - return "When exporting multiple bricks in separate layers, the brick name must be after the bounds definition (separated with a space) in the bounds definition object name." + return "When exporting multiple bricks in separate layers, the brick name must be after the bounds definition token (separated with a space) in the bounds definition object name." else: logger.warning( "Brick name was to be sourced from the name of the bounds definition object but no brick name was found after the bounds definition (separated with a space), file name used instead.", @@ -1985,8 +1986,7 @@ def __process_grid_definitions(properties, blb_data, bounds_data, definition_obj processed += 1 except OutOfBoundsException: if bounds_data.object_name is None: - logger.error( - "Brick grid definition object '{}' has vertices outside the calculated brick bounds. Definition ignored.".format(grid_obj.name), 1) + logger.error("Brick grid definition object '{}' has vertices outside the calculated brick bounds. Definition ignored.".format(grid_obj.name), 1) else: logger.error("Brick grid definition object '{}' has vertices outside the bounds definition object '{}'. Definition ignored.".format( grid_obj.name, bounds_data.object_name)) @@ -2069,7 +2069,7 @@ def __process_collision_definitions(properties, bounds_data, definition_objects, processed = 0 if len(definition_objects) > 10: - logger.error("{} collision boxes defined but 10 is the maximum. Only the first 10 will be processed.".format(len(definition_objects)), 1) + logger.error("{} collision boxes defined but 10 is the maximum. Only the first 10 will be used.".format(len(definition_objects)), 1) for obj in definition_objects: # Break the loop as soon as 10 definitions have been processed. @@ -2103,6 +2103,7 @@ def __process_collision_definitions(properties, bounds_data, definition_objects, # Technically collision outside brick bounds is not invalid but the collision is also horribly broken and as such is not allowed. if __all_within_bounds(col_min, bounds_data.dimensions) and __all_within_bounds(col_max, bounds_data.dimensions): if not __has_volume(col_min, col_max): + # TODO: Test this. Does it actually work in game? logger.error("Collision definition object '{}' has no volume. Definition ignored.".format(obj.name), 1) # Skip the rest of the loop. continue @@ -2216,6 +2217,7 @@ def __process_definition_objects(properties, objects): # Ignore non-mesh objects if obj.type != "MESH": if obj_name.upper().startswith(properties.deftokens.bounds): + # FIXME: Change into errors. logger.warning("Object '{}' cannot be used to define bounds, must be a mesh.".format(obj_name), 1) elif obj_name.upper().startswith(properties.grid_def_obj_token_priority): logger.warning("Object '{}' cannot be used to define brick grid, must be a mesh.".format(obj_name), 1) @@ -2309,7 +2311,10 @@ def __process_definition_objects(properties, objects): # Bounds have been defined, check that brick size is within the limits. if blb_data.brick_size[X] <= const.MAX_BRICK_HORIZONTAL_PLATES and blb_data.brick_size[ Y] <= const.MAX_BRICK_HORIZONTAL_PLATES and blb_data.brick_size[Z] <= const.MAX_BRICK_VERTICAL_PLATES: + # Multiply the dimensions of the bounding box together: if any dimension is 0.0 the product is 0.0. if __sequence_product(blb_data.brick_size) < 1.0: + # TODO: Actually test this. + # TODO: Round 0 brick size up to 1? # RETURN ON ERROR return "Brick has no volume, brick could not be rendered in-game." else: @@ -2670,16 +2675,16 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ # Sanity check. if not len(positions) is len(normals) is len(uvs) is 4: - # RETURN ON ERROR - return "Vertex positions ({}), normals ({}), or UV coordinates ({}) did not contain data for all 4 vertices.".format( + # EXCEPTION + raise ValueError("Vertex positions ({}), normals ({}), or UV coordinates ({}) did not contain data for all 4 vertices.".format( len(positions), len(normals), - len(uvs)) + len(uvs))) if colors is not None: if len(colors) is not 4: - # RETURN ON ERROR - return "Quad color data only defined for {} vertices, 4 required.".format(len(colors)) + # EXCEPTION + raise ValueError("Quad color data only defined for {} vertices, 4 required.".format(len(colors))) # ROUND & CAST: Color values. colors = __to_decimal(colors) @@ -2705,6 +2710,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ count_quads = sum([len(sec) for sec in quads]) if count_quads == 0: + # TODO: Test if an invisible brick works and remove this error. # RETURN ON ERROR return "No faces to export." else: diff --git a/export_blb.py b/export_blb.py index d35c56f..b55060a 100644 --- a/export_blb.py +++ b/export_blb.py @@ -95,8 +95,8 @@ def __init__(self, properties): # Contains the brick grid definition object name tokens in reverse priority order. result = self.__build_grid_priority_tuples(properties) - if result is None: - self.error_message = "Two or more brick grid definitions had the same priority." + if isinstance(result, str): + self.error_message = result else: self.grid_def_obj_token_priority = result[0] self.grid_definitions_priority = result[1] @@ -167,9 +167,7 @@ def __build_grid_priority_tuples(cls, properties): tokens[properties.deftoken_gridb_priority] = properties.deftoken_gridb.upper() if None in tokens: - # FIXME: Return string. - logger.error("Two or more brick grid definitions had the same priority. Unable to proceed.") - return None + return "Two or more brick grid definitions had the same priority." else: symbols = [None] * 5 @@ -265,6 +263,7 @@ def get_objects(context, properties): for index in range(len(context.scene.layers)): # If this layer is visible. # And this object is in the layer. + # TODO: Clarify this funky condition. if True is obj.layers[index] == context.scene.layers[index]: # Append to the list of objects. objects.append(obj) @@ -274,6 +273,7 @@ def get_objects(context, properties): # If user wants to export the whole scene. # Or if user wanted to export only the selected objects or layers but they contained nothing. # Get all scene objects. + # TODO: Remove len(objects) == 0 condition. if properties.blendprop.export_objects == "SCENE" or len(objects) == 0: logger.info("Exporting scene to BLB.") objects = context.scene.objects From c5b44cd89f3713af053b4b15071e677f3f4724ad Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 13:58:31 +0200 Subject: [PATCH 05/50] Change some warnings into non-fatal errors --- README.md | 336 +++++++++++++++++++++++++---------------------- blb_processor.py | 17 ++- 2 files changed, 186 insertions(+), 167 deletions(-) diff --git a/README.md b/README.md index 8c30bff..f28c79d 100644 --- a/README.md +++ b/README.md @@ -614,108 +614,6 @@ It is recommended to manually adjust the brick until no warning messages are pre - - - - - - - - - - - - - - - - - - - - - -
MessageObject '%object name%' cannot be used to define bounds, must be a mesh.
CauseA non-mesh object such as a camera had a bounds definition token in its name.
EffectNo effect other this warning message.
SolutionRemove the bounds definition token from the name of the object.
NotesThis warning message exists to promote good naming standards. Definition token strings should not be used with anything other than definition objects..
- - - - - - - - - - - - - - - - - - - - - -
MessageObject '%object name%' cannot be used to define brick grid, must be a mesh.
CauseA non-mesh object such as a camera had a brick grid definition token in its name.
EffectNo effect other this warning message.
SolutionRemove the brick grid definition token from the name of the object.
NotesThis warning message exists to promote good naming standards. Definition token strings should not be used with anything other than definition objects..
- - - - - - - - - - - - - - - - - - - - - -
MessageObject '%object name%' cannot be used to define collision, must be a mesh.
CauseA non-mesh object such as a camera had a collision definition token in its name.
EffectNo effect other this warning message.
SolutionRemove the collision definition token from the name of the object.
NotesThis warning message exists to promote good naming standards. Definition token strings should not be used with anything other than definition objects..
- - - - - - - - - - - - - - - - - -
MessageMultiple bounds definitions found. '%object name%' definition ignored.
CauseOne brick contained more than one bounds definition object.
EffectThe oldest bounds definition object is used and the rest are discarded.
SolutionDelete the additional bounds definition objects.
- - - - - - - - - - - - - - - - - -
MessageMultiple brick grid definitions in object '%object name%', only the first one is used.
CauseA single definition object contained more than one brick grid definition token.
EffectOnly the first brick grid definition token is used.
SolutionDelete the additional brick grid definition tokens.
@@ -734,24 +632,6 @@ It is recommended to manually adjust the brick until no warning messages are pre
MessageCreate a bounds definition object.
- - - - - - - - - - - - - - - - - -
MessageMore than 4 color values defined for object '%object name%', only the first 4 values (RGBA) are used.
CauseObject name contained more than 4 color values. Colors must be defined by exactly 4 numbers.
EffectOnly the first 4 numbers are used as color values.
SolutionRemove the additional numbers.
@@ -770,42 +650,6 @@ It is recommended to manually adjust the brick until no warning messages are pre
MessageDelete the additional vertex color layers.
- - - - - - - - - - - - - - - - - -
MessageObject '%object name%' has # section definitions, only using the first one: %section name%
CauseThe object had more than one quad section definition token.
EffectOnly the first section definition token is used.
SolutionDelete the additional section definition tokens.
- - - - - - - - - - - - - - - - - -
MessageMore than one brick texture name found in material '%material name%', only using the first one.
CauseThe material name contained more than one brick texture name.
EffectOnly the first brick texture name is used.
SolutionDelete the additional brick texture names.
@@ -817,7 +661,7 @@ It is recommended to manually adjust the brick until no warning messages are pre - + @@ -835,7 +679,7 @@ It is recommended to manually adjust the brick until no warning messages are pre - + @@ -1484,6 +1328,182 @@ Fatal errors always lead to the program execution stopping.
Message
EffectThe `side` brick texture is used for the face.The side brick texture is used for the face.
Solution
EffectAlpha of `1.0` is used resulting in an opaque color.Alpha of 1.0 is used resulting in an opaque color.
Solution
+ + + + + + + + + + + + + + + + + + + + + +
MessageObject '%object name%' cannot be used to define bounds, must be a mesh.
CauseA non-mesh object such as a camera had a bounds definition token in its name.
ReasonNon-mesh objects do not contain data that can be used to calculate an axis-aligned bounding box.
EffectThe specified object is ignored.
SolutionRemove the bounds definition token from the name of the object.
+ + + + + + + + + + + + + + + + + + + + + +
MessageObject '%object name%' cannot be used to define brick grid, must be a mesh.
CauseA non-mesh object such as a camera had a brick grid definition token in its name.
ReasonNon-mesh objects do not contain data that can be used to calculate an axis-aligned bounding box.
EffectThe specified object is ignored.
SolutionRemove the brick grid definition token from the name of the object.
+ + + + + + + + + + + + + + + + + + + + + +
MessageObject '%object name%' cannot be used to define collision, must be a mesh.
CauseA non-mesh object such as a camera had a collision definition token in its name.
ReasonNon-mesh objects do not contain data that can be used to calculate an axis-aligned bounding box.
EffectThe specified object is ignored.
SolutionRemove the collision definition token from the name of the object.
+ + + + + + + + + + + + + + + + + + + + + +
MessageMultiple bounds definitions found. '%object name%' definition ignored.
CauseOne brick contained more than one bounds definition object.
ReasonAlthough it is technically possible to calculate the axis-aligned bounding box of multiple bounds definitions and use that as the final bounds of the brick a feature like this would be confusing for beginner users and breaks the "what you see is what you get" principle of the exporter.
EffectThe oldest bounds definition object is used and the rest are discarded.
SolutionDelete the additional bounds definition objects.
+ + + + + + + + + + + + + + + + + + + + + +
MessageMultiple brick grid definitions in object '%object name%', only the first one is used.
CauseA single definition object contained more than one brick grid definition token.
ReasonOne definition object may only be used to define one brick placement rule.
EffectOnly the first brick grid definition token is used.
SolutionDelete the additional brick grid definition tokens.
+ + + + + + + + + + + + + + + + + + + + + +
MessageMore than 4 color values defined for object '%object name%', only the first 4 values (RGBA) are used.
CauseObject name contained more than 4 color values.
ReasonAn RGBA color is be defined by exactly 4 numerical values: red, green, blue, and alpha.
EffectOnly the first 4 numbers are used as color values.
SolutionRemove the additional numbers.
+ + + + + + + + + + + + + + + + + + + + + +
MessageObject '%object name%' has # section definitions, only using the first one: %section name%
CauseThe object had more than one quad section definition token.
ReasonA single face cannot be in multiple quad sorting sections at the same time.
EffectOnly the first section definition token is used.
SolutionDelete the additional section definition tokens.
+ + + + + + + + + + + + + + + + + + + + + +
MessageMore than one brick texture name found in material '%material name%', only using the first one.
CauseThe material name contained more than one brick texture name.
ReasonA single face cannot have multiple brick textures at the same time.
EffectOnly the first brick texture name is used.
SolutionDelete the additional brick texture names.
## Contributors ## - [Nick Smith](https://github.com/portify) - The original source code for reading, processing, and writing Blender data into the .BLB format. It has essentially been completely rewritten since. diff --git a/blb_processor.py b/blb_processor.py index 9f46c8e..0b1ed59 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -2217,12 +2217,11 @@ def __process_definition_objects(properties, objects): # Ignore non-mesh objects if obj.type != "MESH": if obj_name.upper().startswith(properties.deftokens.bounds): - # FIXME: Change into errors. - logger.warning("Object '{}' cannot be used to define bounds, must be a mesh.".format(obj_name), 1) + logger.error("Object '{}' cannot be used to define bounds, must be a mesh.".format(obj_name), 1) elif obj_name.upper().startswith(properties.grid_def_obj_token_priority): - logger.warning("Object '{}' cannot be used to define brick grid, must be a mesh.".format(obj_name), 1) + logger.error("Object '{}' cannot be used to define brick grid, must be a mesh.".format(obj_name), 1) elif obj_name.upper().startswith(properties.deftokens.collision): - logger.warning("Object '{}' cannot be used to define collision, must be a mesh.".format(obj_name), 1) + logger.error("Object '{}' cannot be used to define collision, must be a mesh.".format(obj_name), 1) # Skip the rest of the if. continue @@ -2251,7 +2250,7 @@ def __process_definition_objects(properties, objects): "", bricks, (" brick", " bricks")), logger.build_countable_message("", blb_data.brick_size[Z] - bricks * 3, (" plate", " plates"))), 1) else: - logger.warning("Multiple bounds definitions found. '{}' definition ignored.".format(obj_name), 1) + logger.error("Multiple bounds definitions found. '{}' definition ignored.".format(obj_name), 1) continue # Is the current object a collision definition object? @@ -2262,7 +2261,7 @@ def __process_definition_objects(properties, objects): # Is the current object a brick grid definition object? elif len(object_grid_definitions) > 0: if len(object_grid_definitions) > 1: - logger.warning("Multiple brick grid definitions in object '{}', only the first one is used.".format(obj_name), 1) + logger.error("Multiple brick grid definitions in object '{}', only the first one is used.".format(obj_name), 1) # Get the priority index of this grid definition. index = properties.grid_def_obj_token_priority.index(object_grid_definitions[0]) @@ -2386,7 +2385,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ # Did user define at least 4 numerical values? if size >= 4: if size > 4: - logger.warning("More than 4 color values defined for object '{}', only the first 4 values (RGBA) are used.".format(object_name), 2) + logger.error("More than 4 color values defined for object '{}', only the first 4 values (RGBA) are used.".format(object_name), 2) # We're only interested in the first 4 values: R G B A floats = floats[:4] @@ -2415,7 +2414,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ if section_count >= 1: section = const.BLBQuadSection(properties.quad_sort_definitions.index(quad_sections[0])) if section_count > 1: - logger.warning("Object '{}' has {} section definitions, only using the first one: {}".format( + logger.error("Object '{}' has {} section definitions, only using the first one: {}".format( object_name, section_count, section), 2) # TODO: Do forward axis rotation of section in the format_blb_data function? @@ -2524,7 +2523,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ brick_texture = const.BrickTexture[texnames[0]] if texcount > 1: - logger.warning("More than one brick texture name found in material '{}', only using the first one.".format(matname), 2) + logger.error("More than one brick texture name found in material '{}', only using the first one.".format(matname), 2) # else: No material name or a brick texture was not specified. Keep None to skip automatic UV generation. # === From 49e43112ecb69ff1cf576eded7087a6457705844 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 14:14:51 +0200 Subject: [PATCH 06/50] Tweak README formatting --- README.md | 84 +++++++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index f28c79d..46b5007 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,6 @@ The add-on does not support importing .BLB files yet. 1. [Brick Textures](#brick-textures) 1. [UV Mapping](#uv-mapping) 1. [The TOP Brick Texture](#the-top-brick-texture) -1. [Rounded Values](#rounded-values) 1. [Troubleshooting](#troubleshooting) 1. [Automatically calculated UV coordinates for brick textures are distorted](#automatically-calculated-uv-coordinates-for-brick-textures-are-distorted) 1. [Automatically calculated UV coordinates for brick textures are rotated incorrectly](#automatically-calculated-uv-coordinates-for-brick-textures-are-rotated-incorrectly) @@ -55,6 +54,7 @@ The add-on does not support importing .BLB files yet. 1. [Errors](#errors) 1. [Fatal Errors](#fatal-errors) 1. [Non-Fatal Errors](#non-fatal-errors) +1. [Rounded Values](#rounded-values) 1. [Contributors](#contributors) ## Features ## @@ -404,23 +404,6 @@ If the [Calculate UVs](#calculate-uvs) property is enabled, UV coordinates will ### The TOP Brick Texture ### Blockland automatically performs rotations on the UV coordinates of the TOP brick texture during runtime so that the lightest side of the texture is always facing towards the sun. Because of this there is no correct way of representing the TOP brick texture in Blender. As a compromise the exporter will rotate the lightest side of the TOP brick texture to face towards the axis select in the [Forward Axis](#forward-axis) property. This means the UV coordinates of the TOP brick texture in Blender may not match those in the written BLB file. -## Rounded Values ## -Floating point numbers (numbers with a decimal point) contain [inherent inaccuracies](https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems). For example when exporting a 1x1x1 brick model at the maximum accuracy the vertex coordinate of one of the corners is `0.5 0.5 1.5000000596046448`. This causes the 1x1x1 brick to be `3.00000011920928955078125` plates tall instead of exactly `3.0` like it should. The only way to get rid of this error is to round the number (vertex coordinates). Practically speaking it is impossible to visually discern the difference between a brick that is 3 plates tall versus one that is `3.00000011920928955078125` plates tall in the game. The floating point errors are effectively 0. The only real benefit that comes from the rounding is nicer looking .BLB files. - -The default value of `0.000001` was chosen through manual testing. Rest assured that the rounding will cause no visual oddities whatsoever because the value is so small. This was manually confirmed with a sphere brick made from 524288 quads. Moving the camera as close to the surface of the brick as the game was capable of rendering, the surface of the sphere appeared mathematically perfect because the distance between the vertices was less than the size of a single pixel. - -:exclamation: The exporter will only ever write 16 decimal places regardless of the precision of the value. - -Floating Point Value | Rounded ----------------------|:------: -Visible mesh vertex coordinates | Yes -[Bounds object](#definition-objects-bounds) vertex coordinates | Yes -[Collision object](#definition-objects-collision) vertex coordinates | Yes -[Brick grid object](#defining-brick-grid) vertex coordinates | Yes -Normal vectors | [Optional](#round-normals) -[RGBA color](#defining-colors) values | No -[UV coordinates](#uv-mapping) | No - ## Troubleshooting ## Solutions to common issues with the BLB Exporter. If you have another issue with the exporter be sure to enable the [Write Log](#write-log) property and export again. The log file may contain warnings or errors describing issues with the models and how to fix them. Additional instructions on how to fix specific issues are detailed in the [Warning & Error Log Messages](#warning--error-log-messages) section. @@ -434,7 +417,7 @@ The quad with incorrectly rotated UV coordinates (e.g. the lightest side of the ## Warning & Error Log Messages ## Detailed explanations of the warning and error messages logged by the program and directions on how to solve the associated issues. In the messages listed in this section the `#` character is used to represent a variable numerical value. -Text surrounded by `%` describes a variable alphanumeric value. +Text in `code tags` describes a variable alphanumeric value, commonly the name of a Blender object. ### Warnings ### Warning log messages can be ignored as the issues are automatically corrected, but the resulting brick may not behave or look as excepted. @@ -442,7 +425,7 @@ It is recommended to manually adjust the brick until no warning messages are pre - + @@ -463,7 +446,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
MessageCalculated bounds have a non-integer size # # #, rounding up.Calculated bounds have a non-integer size # # #, rounding up.
Cause
- + @@ -535,7 +518,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
MessageDefined bounds have a non-integer size # # #, rounding to a precision of #.Defined bounds have a non-integer size # # #, rounding to a precision of #.
Cause
- + @@ -553,7 +536,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
Message# brick grid definition(s) found but was/were not processed. Automatically generated brick grid may be undesirable.# brick grid definition(s) found but was/were not processed. Automatically generated brick grid may be undesirable.
Cause
- + @@ -596,7 +579,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
MessageCollision definition object '%object name%' has more than 8 vertices suggesting a shape other than a cuboid. The bounding box of this mesh will be used.Collision definition object 'object name' has more than 8 vertices suggesting a shape other than a cuboid. The bounding box of this mesh will be used.
Cause
- + @@ -635,7 +618,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
Message# collision definition(s) found but was/were not processed. Brick will have no collision.# collision definition(s) found but was/were not processed. Brick will have no collision.
Cause
- + @@ -689,7 +672,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
MessageObject '%object name%' has # vertex color layers, only using the first.Object 'object name' has # vertex color layers, only using the first.
Cause
- + @@ -712,7 +695,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
Message# triangles degenerated to quads.# triangles degenerated to quads.
Cause
- + @@ -843,7 +826,7 @@ Fatal errors always lead to the program execution stopping.
Message# n-gons skipped.# n-gons skipped.
Cause
- + @@ -1143,7 +1126,7 @@ Fatal errors always lead to the program execution stopping.
MessageUnable to store UV coordinates in object '%object name%' while it is in edit mode.Unable to store UV coordinates in object 'object name' while it is in edit mode.
Cause
- + @@ -1193,7 +1176,7 @@ Fatal errors always lead to the program execution stopping.
MessageBrick grid definition object '%object name%' has vertices outside the calculated brick bounds. Definition ignored.Brick grid definition object 'object name' has vertices outside the calculated brick bounds. Definition ignored.
Cause
- + @@ -1237,7 +1220,7 @@ Fatal errors always lead to the program execution stopping.
MessageBrick grid definition object '%object name%' has no volume. Definition ignored.Brick grid definition object 'object name' has no volume. Definition ignored.
Cause
- + @@ -1259,7 +1242,7 @@ Fatal errors always lead to the program execution stopping.
MessageCollision definition object '%object name%' has less than 2 vertices. Definition ignored.Collision definition object 'object name' has less than 2 vertices. Definition ignored.
Cause
- + @@ -1281,7 +1264,7 @@ Fatal errors always lead to the program execution stopping.
MessageCollision definition object '%object name%' has no volume. Definition ignored.Collision definition object 'object name' has no volume. Definition ignored.
Cause
- + @@ -1306,7 +1289,7 @@ Fatal errors always lead to the program execution stopping.
MessageCollision definition object '%object name%' has vertices outside the calculated brick bounds. Definition ignored.Collision definition object 'object name' has vertices outside the calculated brick bounds. Definition ignored.
Cause
- + @@ -1331,7 +1314,7 @@ Fatal errors always lead to the program execution stopping.
MessageCollision definition object '%object name%' has vertices outside the bounds definition object '%object name%'. Definition ignored.Collision definition object 'object name' has vertices outside the bounds definition object 'object name'. Definition ignored.
Cause
- + @@ -1353,7 +1336,7 @@ Fatal errors always lead to the program execution stopping.
MessageObject '%object name%' cannot be used to define bounds, must be a mesh.Object 'object name' cannot be used to define bounds, must be a mesh.
Cause
- + @@ -1375,7 +1358,7 @@ Fatal errors always lead to the program execution stopping.
MessageObject '%object name%' cannot be used to define brick grid, must be a mesh.Object 'object name' cannot be used to define brick grid, must be a mesh.
Cause
- + @@ -1397,7 +1380,7 @@ Fatal errors always lead to the program execution stopping.
MessageObject '%object name%' cannot be used to define collision, must be a mesh.Object 'object name' cannot be used to define collision, must be a mesh.
Cause
- + @@ -1419,7 +1402,7 @@ Fatal errors always lead to the program execution stopping.
MessageMultiple bounds definitions found. '%object name%' definition ignored.Multiple bounds definitions found. 'object name' definition ignored.
Cause
- + @@ -1441,7 +1424,7 @@ Fatal errors always lead to the program execution stopping.
MessageMultiple brick grid definitions in object '%object name%', only the first one is used.Multiple brick grid definitions in object 'object name', only the first one is used.
Cause
- + @@ -1463,7 +1446,7 @@ Fatal errors always lead to the program execution stopping.
MessageMore than 4 color values defined for object '%object name%', only the first 4 values (RGBA) are used.More than 4 color values defined for object 'object name', only the first 4 values (RGBA) are used.
Cause
- + @@ -1485,7 +1468,7 @@ Fatal errors always lead to the program execution stopping.
MessageObject '%object name%' has # section definitions, only using the first one: %section name%Object 'object name' has # section definitions, only using the first one: section name
Cause
- + @@ -1505,6 +1488,23 @@ Fatal errors always lead to the program execution stopping.
MessageMore than one brick texture name found in material '%material name%', only using the first one.More than one brick texture name found in material 'material name', only using the first one.
Cause
+## Rounded Values ## +Floating point numbers (numbers with a decimal point) contain [inherent inaccuracies](https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems). For example when exporting a 1x1x1 brick model at the maximum accuracy the vertex coordinate of one of the corners is `0.5 0.5 1.5000000596046448`. This causes the 1x1x1 brick to be `3.00000011920928955078125` plates tall instead of exactly `3.0` like it should. The only way to get rid of this error is to round the number (vertex coordinates). Practically speaking it is impossible to visually discern the difference between a brick that is 3 plates tall versus one that is `3.00000011920928955078125` plates tall in the game. The floating point errors are effectively 0. The only real benefit that comes from the rounding is nicer looking .BLB files. + +The default value of `0.000001` was chosen through manual testing. Rest assured that the rounding will cause no visual oddities whatsoever because the value is so small. This was manually confirmed with a sphere brick made from 524288 quads. Moving the camera as close to the surface of the brick as the game was capable of rendering, the surface of the sphere appeared mathematically perfect because the distance between the vertices was less than the size of a single pixel. + +:exclamation: The exporter will only ever write 16 decimal places regardless of the precision of the value. + +Floating Point Value | Rounded +---------------------|:------: +Visible mesh vertex coordinates | Yes +[Bounds object](#definition-objects-bounds) vertex coordinates | Yes +[Collision object](#definition-objects-collision) vertex coordinates | Yes +[Brick grid object](#defining-brick-grid) vertex coordinates | Yes +Normal vectors | [Optional](#round-normals) +[RGBA color](#defining-colors) values | No +[UV coordinates](#uv-mapping) | No + ## Contributors ## - [Nick Smith](https://github.com/portify) - The original source code for reading, processing, and writing Blender data into the .BLB format. It has essentially been completely rewritten since. - [Demian Wright](https://github.com/DemianWright) - Everything else. From efbee3be96b1204aa0ef8c4d450fb07068058145 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 14:39:40 +0200 Subject: [PATCH 07/50] Change terminology table into a definition list, tweak definitions --- README.md | 83 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 46b5007..19a9669 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ The add-on does not support importing .BLB files yet. 1. [Planned Features](#planned-features) 1. [Installation](#installation) 1. [Updating](#updating) +1. [Terminology](#terminology) 1. [Blender Export Properties](#blender-export-properties) 1. [Bricks to Export](#bricks-to-export) 1. [Brick Name from (Single Export)](#brick-name-from-single-export) @@ -36,7 +37,6 @@ The add-on does not support importing .BLB files yet. 1. [Write Log](#write-log) 1. [Only on Warnings](#only-on-warnings) 1. [Precision](#precision) -1. [Terminology](#terminology) 1. [Definition Tokens](#definition-tokens) 1. [Definition Objects](#definition-objects) 1. [Defining Brick Grid](#defining-brick-grid) @@ -129,6 +129,64 @@ These features may or may not be implemented at some unspecified time in the fut 1. Expand the add-on by clicking the white triangle on the left, press the `Remove` button, and confirm the removal. 1. Follow the installation instructions above. +## Terminology ## +A list of more or less technical terms used in this document. The definitions are in the context of Blockland, Blender, and this exporter and may vary from their mathematical definitions. +
+
Axis-Aligned Plane
+
A plane whose vertices have the same coordinate on exactly one axis. When this two-dimensional plane is viewed from either of the other two axes it disappears from view.
+ +
Brick Grid
+
The three-dimensional space of the game divided into 1x1x1 brick plates, also the blocks of u, x, -, and other characters near the top of the .BLB file that define the brick's placement rules.
+ +
Brick
+
A collection of meshes that act as a single object in Blockland and all the non-visual data it contains. (E.g. brick grid information.)
+ +
Coverage
+
The coverage system describes how to hide faces on this and adjacent bricks, also the 6 pairs of integers near the top of the .BLB file.
+ +
Cuboid
+
More specifically a right cuboid. A convex polyhedron with 6 faces that are all at right angles with each other. I.e. a cube or a cube that has been scaled on one axis.
+ +
Definition Object
+
An object containing a special definition token. These objects cannot be seen in-game. They exist to tell the exporter how to create the brick.
+ +
Definition Token
+
A special word in an object's name that tells the exporter what to do with that object.
+ +
Face
+
A tri or a quad.
+ +
Mesh
+
The vertices, edges, and faces that make up a 3D model. Multiple meshes can be within an object. Used interchangeably with object and model.
+ +
Model
+
Used interchangeably with object and mesh.
+ +
N-gon
+
Technically any polygon but in Blender used to refer to a single face formed from more than 4 vertices. These are not supported by the exporter or Blockland.
+ +
Object
+
The things you see in the 3D viewport. Blender objects can contain multiple meshes. This document uses this term interchangeably with model and mesh.
+ +
Plane
+
A two-dimensional surface in 3D space. Used interchangeably with tri and quad.
+ +
Quad
+
A plane with 4 vertices.
+ +
Token
+
A string (word) of one or more letters surrounded with a whitespace character (usually a space) on one or both sides.
+ +
Tri
+
A plane with 3 vertices. Not supported by Blockland bricks, converted to quads automatically.
+ +
Volume
+
A piece of 3D space, usually cuboidal in shape in the context of this exporter.
+ +
Whitespace (Character)
+
In Blender, commonly a space or a tab character.
+
+ ## Blender Export Properties ## The following properties are present in the current version of the exporter. @@ -240,27 +298,6 @@ Write a log file only if warnings or errors occurred during the export process. #### Precision #### Allows you to specify a custom precision for floating point numbers. See [Rounded Values](#rounded-values) for more details. (Default: 0.000001) -## Terminology ## -Term | Definition ------|----------- -Axis Aligned Plane | A plane where all vertices have the same coordinates on exactly on axis. I.e. when viewed from one of the three axes the plane cannot be seen as it is viewed directly from the side. -Brick Grid | The three dimensional space of the game divided into 1x1x1 plates, also the blocks of characters near the top of the .BLB file containing characters such as `u`, `x`, and `-` that define whether bricks may be placed above, below, or inside this brick grid "slot" (the space of a 1x1x1 plate). -Brick | A collection of meshes that act as a single object in Blockland and all the non-visual data it contains. (E.g. brick grid information.) -Coverage | The coverage system describes how to hide faces on this and adjacent bricks, also the 6 pairs of integers near the top of the .BLB file. -Cuboid | More specifically a **right cuboid**. A [convex polyhedron](https://en.wikipedia.org/wiki/Convex_polytope) with 6 faces that are all at right angles with each other. I.e. a cube or a cube that has been scaled on one axis. -Definition Object | An object containing a special definition token. These objects cannot be seen in-game. They exist to tell the exporter how to create the brick. -Definition Token | A special word in an object's name that tells the exporter what to do with that object. -Face | A **tri** or a **quad**. -Mesh | The vertices, edges, and faces that make up a 3D model. Multiple meshes can be within an object. Used interchangeably with **object** and **model**. -Model | See object. Used interchangeably with **object** and **mesh**. -N-gon | A plane with more than 4 vertices. These are not supported. -Object | The things you see in the 3D viewport. Blender objects can contain multiple meshes. This document uses this term interchangeably with **model** and **mesh**. -Plane | A two-dimensional surface in 3D space. Used interchangeably with **tri** and **quad**. -Quad | A plane with 4 vertices. -Token | A string (word) of one or more letters surrounded with a whitespace character (usually a space) on one or both sides. -Tri | A plane with 3 vertices. (A triangle.) Not supported by Blockland bricks, converted to **quads** automatically. -Volume | A piece of 3D space, usually cuboidal in shape. - ## Definition Tokens ## An object may contain other text in addition to definition tokens as long as the tokens themselves are separated from other tokens and text by one whitespace character. (E.g. a space.) The definition tokens may be changed from the defaults by selecting `Custom Definition Tokens` in the export dialog. @@ -385,7 +422,7 @@ Defining brick textures is done using Blender materials. To assign a brick textu - `side` - `top` -If no brick texture is defined, `side` is used. Material name may contain other words as long as the brick texture name is separated from them with one whitespace character such as a space. A common combination is to define a brick texture name and the [definition token `blank`](#defining-colors-blank) (e.g. `blank ramp` or `ramp blank`) to allow the player to color the face in-game using the spray can. +If no brick texture is defined, `side` is used. Material name may contain other words as long as the brick texture name is separated from them with one whitespace character such as a space. A common combination is to define a brick texture name and the [definition token `blank`](#defining-colors-blank) (e.g. `blank ramp` or `side blank`) to allow the player to color the face in-game using the spray can. #### UV Mapping #### Manually defined UV coordinates must be stored in one or more UV layers that do not share a name with one of the automatically generated UV layers: From bdbaa438444febc9a97e050fc8a4ad1467ff95e6 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 17:53:48 +0200 Subject: [PATCH 08/50] Improve README terminology section --- README.md | 95 +++++++++++++++++++++++++++++++++++++++-------------- __init__.py | 2 -- 2 files changed, 71 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 19a9669..10f8c3d 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,10 @@ # Blender BLB Exporter # [![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://img.shields.io/badge/License-GPL%20v2-blue.svg) -A [Blender](https://www.blender.org/) add-on written in Python 3 for exporting [Blockland](http://blockland.us/) bricks (.BLB files) directly from Blender 2.67 and newer without the need for intermediary formats or external programs. It works on the principle of "what you see is what you get", the brick will look exactly the same in-game as it does in the 3D viewport[__*__](#exporter-fn-1). +A [Blender](https://www.blender.org/) add-on written in Python 3 for exporting [Blockland](http://blockland.us/) bricks (.BLB files) directly from Blender 2.67 and newer without the need for intermediary formats or external programs. It works on the principle of "what you see is what you get", the brick will look exactly the same in-game as it does in the 3D viewport[__*__](#exporter-fn-1). The add-on does not support importing .BLB files yet. - ## Table of Contents ## 1. [Features](#features) 1. [Additional Features](#additional-features) @@ -130,60 +129,108 @@ These features may or may not be implemented at some unspecified time in the fut 1. Follow the installation instructions above. ## Terminology ## -A list of more or less technical terms used in this document. The definitions are in the context of Blockland, Blender, and this exporter and may vary from their mathematical definitions. +A list of more or less technical terms used in this document. +The definitions are in the context of Blockland, Blender, and this exporter and may vary from their mathematical definitions.
-
Axis-Aligned Plane
-
A plane whose vertices have the same coordinate on exactly one axis. When this two-dimensional plane is viewed from either of the other two axes it disappears from view.
+
Axis-Aligned Plane
+
A plane whose vertices have the same coordinate on exactly one coordinate axis. +When this two-dimensional plane is viewed from either of the other two coordinate axes it disappears from view.
+ +
Axis-Aligned Bounding Box / Axis-Aligned Minimum Bounding Box
+
A cuboid that completely encompasses all vertices of one or more objects. +The faces of this cuboid are parallel with the coordinate axes.
Brick Grid
-
The three-dimensional space of the game divided into 1x1x1 brick plates, also the blocks of u, x, -, and other characters near the top of the .BLB file that define the brick's placement rules.
+
    +
  1. The three-dimensional space of the game divided into 1x1x1 brick plates
  2. +
  3. The blocks of u, x, -, and other characters near the top of the .BLB file that define the brick's placement rules. +See Defining Brick Grid.
Brick
-
A collection of meshes that act as a single object in Blockland and all the non-visual data it contains. (E.g. brick grid information.)
- -
Coverage
-
The coverage system describes how to hide faces on this and adjacent bricks, also the 6 pairs of integers near the top of the .BLB file.
+
    +
  1. A collection of faces that acts as a single object in Blockland and all the non-visual data it contains such as collision information.
  2. +
  3. The BLB file itself.
  4. +
  5. The Blender objects that when exported produce a BLB file.
  6. +
+
+ +
Coverage (System)
+
    +
  1. The Blockland coverage system describes how to hide faces on a brick and any adjacent bricks.
  2. +
  3. The six pairs of integers near the top of a BLB file.
  4. +
+
Cuboid
-
More specifically a right cuboid. A convex polyhedron with 6 faces that are all at right angles with each other. I.e. a cube or a cube that has been scaled on one axis.
+
More specifically a right cuboid in the context of Blockland bricks. +A convex polyhedron with 6 faces that are all at right angles to each other. +I.e. a regular cube or a cube that is elongated on one axis.
Definition Object
-
An object containing a special definition token. These objects cannot be seen in-game. They exist to tell the exporter how to create the brick.
+
An object containing one or more definition tokens in its name. +These objects cannot be seen in-game. +They exist to tell the exporter how to create the brick.
Definition Token
-
A special word in an object's name that tells the exporter what to do with that object.
+
A special token in an object's name that tells the exporter what to do with that object.
Face
-
A tri or a quad.
+
A visible surface that is rendered in game and in the Blender viewport. +The surface must be bound by or created by at least three vertices (making it a tri) or in deed any number of vertices (also called an n-gon). + +:exclamation: Blockland bricks only support faces made from exactly four vertices: quads.
Mesh
-
The vertices, edges, and faces that make up a 3D model. Multiple meshes can be within an object. Used interchangeably with object and model.
+
The vertices, edges, and faces that make up a 3D model.
+ +
Mesh Object
+
A Blender object that contains vertices, edges, and faces. +Commonly just referred to as an object.
Model
-
Used interchangeably with object and mesh.
+
One or more objects that make up a brick.
N-gon
-
Technically any polygon but in Blender used to refer to a single face formed from more than 4 vertices. These are not supported by the exporter or Blockland.
+
Technically any polygon but in this document used to refer to a single face formed from more than four vertices. +N-gons are not necessarily planes. + +:exclamation: These are not supported by the exporter or Blockland: the faces will be ignored.
Object
-
The things you see in the 3D viewport. Blender objects can contain multiple meshes. This document uses this term interchangeably with model and mesh.
+
Usually a mesh object. +Technically refers to all the meshes, cameras, lights, empties, and everything else you see in the 3D viewport. +Blender objects contain data about vertices, materials, groups, object names, and more.
Plane
-
A two-dimensional surface in 3D space. Used interchangeably with tri and quad.
+
A flat two-dimensional surface in 3D space. +A particular type of face.
Quad
-
A plane with 4 vertices.
+
A face with four vertices. +Quads are not necessarily planes.
+ +
String
+
A sequence of letters. +Usually a word.
Token
-
A string (word) of one or more letters surrounded with a whitespace character (usually a space) on one or both sides.
+
A string surrounded with a whitespace character on one or both sides.
Tri
-
A plane with 3 vertices. Not supported by Blockland bricks, converted to quads automatically.
+
A face with three vertices. +Triangles are always planes. + +:exclamation: These are not supported by Blockland bricks and they are converted to quads automatically.
+ +
Visible Object
+
Any mesh object that is not a definition object. +Visible objects are rendered and are seen in-game as a brick.
Volume
-
A piece of 3D space, usually cuboidal in shape in the context of this exporter.
+
A section of 3D space, usually cuboidal in shape in the context of this exporter.
-
Whitespace (Character)
+
Whitespace (Character)
In Blender, commonly a space or a tab character.
diff --git a/__init__.py b/__init__.py index 128438f..8ac5c77 100644 --- a/__init__.py +++ b/__init__.py @@ -48,7 +48,6 @@ # TODO: Quad sorting is per object but BLBs support per-quad sorting: the exporter does not support quad sorting for smoothed objects. # TODO: Add a section about brick size to the readme. # TODO: Add a section about brick grid to the readme. -# TODO: Improve terminology section in the readme. Use dl? # TODO: Make the capitalization consistent in the readme. # TODO: Consider reformatting readme to have one sentence per line for nicer diffs. # TODO: Consider refactoring readme for consistent use of mesh, model, and object words. @@ -59,7 +58,6 @@ # TODO: Fix link to Port's GitHub profile. # TODO: Calculate Bounds property. # TODO: Definition object bounds rules to readme. -# TODO: Define what a visible mesh is. class ExportBLB(bpy.types.Operator, ExportHelper): From f656dff4a9d967a0b0e92d98769acf8f081c68b3 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 20:37:12 +0200 Subject: [PATCH 09/50] Various README improvements --- README.md | 274 ++++++++++++++++++++++++++++++---------------------- __init__.py | 1 - 2 files changed, 156 insertions(+), 119 deletions(-) diff --git a/README.md b/README.md index 10f8c3d..1ebcd12 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ The add-on does not support importing .BLB files yet. ## Table of Contents ## 1. [Features](#features) - 1. [Additional Features](#additional-features) 1. [Planned Features](#planned-features) 1. [Installation](#installation) 1. [Updating](#updating) @@ -37,22 +36,24 @@ The add-on does not support importing .BLB files yet. 1. [Only on Warnings](#only-on-warnings) 1. [Precision](#precision) 1. [Definition Tokens](#definition-tokens) - 1. [Definition Objects](#definition-objects) - 1. [Defining Brick Grid](#defining-brick-grid) 1. [Mesh Definition Tokens](#mesh-definition-tokens) - 1. [Defining Quad Sorting & Coverage](#defining-quad-sorting--coverage) + 1. [Defining Quad Sections & Coverage](#defining-quad-sections--coverage) 1. [Defining Colors](#defining-colors) - 1. [Brick Textures](#brick-textures) + 1. [RGBA Color Format](#rgba-color-format) +1. [Definition Objects](#definition-objects) + 1. [Defining Collision](#defining-collision) + 1. [Defining Brick Grid](#defining-brick-grid) +1. [Brick Textures](#brick-textures) 1. [UV Mapping](#uv-mapping) - 1. [The TOP Brick Texture](#the-top-brick-texture) 1. [Troubleshooting](#troubleshooting) - 1. [Automatically calculated UV coordinates for brick textures are distorted](#automatically-calculated-uv-coordinates-for-brick-textures-are-distorted) - 1. [Automatically calculated UV coordinates for brick textures are rotated incorrectly](#automatically-calculated-uv-coordinates-for-brick-textures-are-rotated-incorrectly) + 1. [Automatically calculated UV coordinates for brick textures are distorted](#automatically-calculated-uv-coordinates-for-brick-textures-are-distorted) + 1. [Automatically calculated UV coordinates for brick textures are rotated incorrectly](#automatically-calculated-uv-coordinates-for-brick-textures-are-rotated-incorrectly) + 1. [The TOP brick texture has incorrect rotation in Blender](#the-top-brick-texture-has-incorrect-rotation-in-blender) 1. [Warning & Error Log Messages](#warning--error-log-messages) - 1. [Warnings](#warnings) - 1. [Errors](#errors) - 1. [Fatal Errors](#fatal-errors) - 1. [Non-Fatal Errors](#non-fatal-errors) + 1. [Warnings](#warnings) + 1. [Errors](#errors) + 1. [Fatal Errors](#fatal-errors) + 1. [Non-Fatal Errors](#non-fatal-errors) 1. [Rounded Values](#rounded-values) 1. [Contributors](#contributors) @@ -82,26 +83,24 @@ The exporter supports all BLB features. - Transparency - Additive and subtractive colors - [x] Flat and smooth shading -- [ ] DTS collision is intentionally not a part of this add-on as it an entirely different file format. - - See Nick Smith's [io_scene_dts](https://github.com/portify/io_scene_dts) for a Blender DTS importer/exporter. - -### Additional Features ### - [x] Save and load export settings - [x] Export multiple bricks from the same file - [x] Vertices are all relative to the defined or calculated brick bounds - - Object centers (orange dot) are irrelevant: calculations are performed using raw vertex world coordinates + - Object centers (orange dot) are irrelevant: calculations are performed using vertex world coordinates - Object locations relative to the origin of the world are irrelevant: the calculated center of the brick bounds acts as the new world origin - Object locations relative to the Blender grid are irrelevant: the brick bounds define the brick grid origin (however it is highly recommended to align the brick bounds object with the Blender grid for ease of use) - This allows you to easily create multiple bricks in the same file in any location in the 3D space and the bricks still export correctly as expected - Arbitrary brick grid rotation, however, is not supported - [x] Selective object export: selection, visible layers, entire scene -- [x] Change brick rotation during export: does not affect objects in viewport -- [x] Change brick scale during export: does not affect objects in viewport -- [x] Apply modifiers (e.g. edge split) during export: does not affect objects in viewport -- [x] Terse file writing: excludes optional lines from the BLB file +- [x] Change brick rotation during export: does not affect objects in the .BLEND file +- [x] Change brick scale during export: does not affect objects in the .BLEND file +- [x] Apply modifiers (e.g. edge split) during export: does not affect objects in the .BLEND file +- [x] Terse file writing: exclude optional lines from the BLB file - [x] Pretty .BLB files: extraneous zeros are not written at the end of floating point values and if possible, they are written as integers -- [x] Logging with descriptive error and warning messages to help you correct problems with the model -- [x] Changeable floating point accuracy +- [x] Logging with descriptive error and warning messages to help you correct problems with the brick +- [x] Customizable floating point accuracy +- [ ] DTS collision is intentionally not a part of this add-on as it an entirely different file format. + - See Nick Smith's [io_scene_dts](https://github.com/portify/io_scene_dts) for a Blender DTS importer/exporter. ### Planned Features ### These features may or may not be implemented at some unspecified time in the future. @@ -137,9 +136,12 @@ The definitions are in the context of Blockland, Blender, and this exporter and When this two-dimensional plane is viewed from either of the other two coordinate axes it disappears from view.
Axis-Aligned Bounding Box / Axis-Aligned Minimum Bounding Box
-
A cuboid that completely encompasses all vertices of one or more objects. +
A cuboid that completely encompasses all vertices of one or more objects. The faces of this cuboid are parallel with the coordinate axes.
+
Axis-Aligned Cuboid
+
A cuboid whose faces are parallel with the coordinate axes.
+
Brick Grid
  1. The three-dimensional space of the game divided into 1x1x1 brick plates
  2. @@ -168,9 +170,15 @@ A convex polyhedron I.e. a regular cube or a cube that is elongated on one axis.
Definition Object
-
An object containing one or more definition tokens in its name. +
An object that has a specific definition token in its name. These objects cannot be seen in-game. -They exist to tell the exporter how to create the brick.
+They exist to tell the exporter how to create the brick. +There are three different definition objects: +
Definition Token
A special token in an object's name that tells the exporter what to do with that object.
@@ -289,11 +297,12 @@ Scene | Export all bricks in the current scene. I.e. all bricks in all layers re #### Forward Axis #### The Blender 3D axis that will point forwards in-game when the player plants the brick directly in front of them without rotating it. Does not change the rotation of the objects in the Blender scene. -Possible values: -- Positive X-axis ("Right") -- Default: Positive Y-axis ("Forward") -- Negative X-axis ("Left") -- Negative Y-axis ("Back") +Value | Description +------|------------ ++X | Positive X-axis: right ++Y | Positive Y-axis: forward (Default) +-X | Negative X-axis: left +-Y | Negative Y-axis: back #### Scale #### The scale of the brick in-game. Values outside the the range of 0.001–400.0 may be typed in manually. Does not change the scale of the objects in the Blender scene. (Default: 100%) @@ -307,7 +316,7 @@ Applies any modifiers on the object before exporting. Does not change the modifi If no manual collision definition objects exist, calculates a cuboid collision that is the same size as the brick bounds. If disabled and no collision is defined, brick will have no collision. (Default: True) #### Coverage #### -Enable coverage calculations. Shows additional settings when selected. This is pointless unless [Automatic Quad Sorting](#automatic-quad-sorting) is enabled or at least one object has a quad sorting definition. See [Defining Quad Sorting & Coverage](#defining-quad-sorting--coverage) for more information. (Default: False) +Enable coverage calculations. Shows additional settings when selected. This is pointless unless [Automatic Quad Sorting](#automatic-quad-sorting) is enabled or at least one object has a quad sorting definition. See [Defining Quad Sorting & Coverage](#defining-quad-sections--coverage) for more information. (Default: False) #### Automatic Quad Sorting #### Automatically calculate the correct section for quads that in the same plane as the bounding planes of the bounds object. This is pointless unless [Coverage](#coverage) is enabled. (Default: True) @@ -346,78 +355,62 @@ Write a log file only if warnings or errors occurred during the export process. Allows you to specify a custom precision for floating point numbers. See [Rounded Values](#rounded-values) for more details. (Default: 0.000001) ## Definition Tokens ## -An object may contain other text in addition to definition tokens as long as the tokens themselves are separated from other tokens and text by one whitespace character. (E.g. a space.) The definition tokens may be changed from the defaults by selecting `Custom Definition Tokens` in the export dialog. - -Blender adds a running index (e.g. `.003`) to the end of duplicate object, material, etc. names. This is handled correctly, you need not worry about it. The logic for removing the index simply checks if `.` is the fourth last character in the object name and simply removes it an everything after it. - -Below is a full list of all definition tokens with a brief description. For more information on what each of them do, see the rest of the readme. - -Token | Category | Usable In | Description -------|----------|-----------|------------ -`bounds` | Definition objects | Object name | The bounds object. See [Definition Objects](#definition-objects). -`collision` | Definition objects | Object name | A BLB collision box/cuboid. -`gridb` | Definition objects: brick grid | Object name | Write brick grid `b` symbol. See [Defining Brick Grid](#defining-brick-grid). -`gridd` | Definition objects: brick grid | Object name | Write brick grid `d` symbol. -`gridu` | Definition objects: brick grid | Object name | Write brick grid `u` symbol. -`grid-` | Definition objects: brick grid | Object name | Write brick grid `-` symbol. -`gridx` | Definition objects: brick grid | Object name | Write brick grid `x` symbol. -`qt` | Quad sorting | Object name | Sort quads in top section. See [Defining Quad Sorting & Coverage](#defining-quad-sorting--coverage). -`qb` | Quad sorting | Object name | Sort quads in bottom section. -`qn` | Quad sorting | Object name | Sort quads in north section. -`qe` | Quad sorting | Object name | Sort quads in east section. -`qs` | Quad sorting | Object name | Sort quads in south section. -`qw` | Quad sorting | Object name | Sort quads in west section. -`qo` | Quad sorting | Object name | Sort quads in omni section. -`c` | Colors | Object name | Define object color in object name. See [Defining Colors](#defining-colors). -`blank` | Colors | Material name | Do not write a color: use in-game spray can color as is. -`cadd` | Colors | Material name, vertex color layer name | Add material/vertex color to in-game spray can color. -`csub` | Colors | Material name, vertex color layer name | Subtract material/vertex color from in-game spray can color. - -### Definition Objects ### -When a definition object token is read in an object's name it is treated as a definition object. Definition objects are never exported as visual 3D models, in fact they are not exported at all. Instead the data they contain in their name (or elsewhere) and the 3D space they represent is processed further to acquire the necessary information for the BLB file. - -Definition Object | Token | Requirements | Maximum Count/Brick | Axis Aligned | Brick Grid Aligned | Can Overlap | Description -------------------|-------|--------------|--------------------:|:------------:|:------------------:|:-----------:|------------ -Bounds | `bounds` | At least 2 vertices, must have volume | 1 | Yes [**(1)**](#definition-objects-fn-1) | Yes | N/A | Defines the brick bounds (brick size). -Collision | `collision` | At least 2 vertices, must be within [**Bounds**](#definition-objects-bounds) object [**(2)**](#definition-objects-fn-2) | 10 | Yes [**(3)**](#definition-objects-fn-3) | No | Yes | Defines a collision box. -Brick Grid | See [Defining Brick Grid](#defining-brick-grid) | At least 2 vertices, must have volume, must be within [**Bounds**](#definition-objects-bounds) object | Unlimited | Yes [**(1)**](#definition-objects-fn-1) | Yes | Yes [**(4)**](#definition-objects-fn-4) | Defines a volume in the brick grid to fill with a specific brick grid symbol. - -**(1)** It is highly recommended to use axis aligned cuboids to define bounds and the brick grid. However, if you insist on defining the size of your brick in monkey heads, you can. Only the minimum and maximum coordinates of the bounds and brick grid objects are used. - -**(2)** Collision boxes outside brick bounds are not invalid and the brick will function in-game. This behavior is not allowed by the exporter because collision outside brick bounds is horribly broken as it was never intended work in that manner. - -**(3)** Blockland only supports [AABB collision](https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box) with bricks. In other words brick collision may only be defined using boxes of varying sizes that align with the axes. You can rotate said boxes however you want but that does translate to collision boxes that are at an angle in-game. Only the the minimum and maximum coordinates of the object are used. Using anything else than cuboids to define collision is not recommended as it makes the Blender file more confusing to understand. - -**(4)** See [Defining Brick Grid](#defining-brick-grid) for the specific rules about overlapping brick grid definitions. - -#### Defining Brick Grid #### -Brick grid definitions represent a 3D volume in the 3D space the brick grid encompasses. You can imagine it as if the entire cuboidal shape of the brick would be filled with 1x1f plates and these volumes define the properties of all the 1x1f plates within that volume. Each brick grid definition has their own priority. When two or more brick grid definition objects overlap in 3D space, the one with the **higher** priority takes precedence and will overwrite the symbols in the brick grid that any definitions with lower priorities would have written. - -:exclamation: Be aware that if your brick does not contain a `brickd` definition on the bottom of the brick, the brick cannot be planted on other bricks or the ground. - -Token | Brick Grid Symbol | Description -------|:-----------------:|------------ -`gridb` | `b` | Bricks may be placed above and below this volume. This brick can be planted on the ground. -`gridd` | `d` | Bricks may be placed below this volume. This brick can be planted on the ground. -`gridu` | `u` | Bricks may be placed above this volume. -`grid-` | `-` | Bricks may be placed inside this volume. (I.e. empty space.) This is the default symbol, any volume that does not have a brick grid definition uses this symbol. -`gridx` | `x` | Bricks may not be placed inside this volume. +[Definition tokens](#def-definition-token) are special [strings](#def-string) added to the names of objects, materials, and other Blender data objects that have a name. +A name field may contain other text in addition to definition tokens as long as the tokens themselves are separated from other tokens and text by one [whitespace character](#def-whitespace) such as a space. +The definition tokens may be changed from the defaults by selecting [Custom Definition Tokens](#custom-definition-tokens) in the export dialog. + +:bulb: Blender adds a running index (e.g. `.003`) to the end of duplicate object, material, etc. names. +This is handled correctly, you need not worry about it. +The logic for removing the index simply checks if `.` is the fourth last character in the name and simply removes it an everything after it. + +:exclamation: Each definition token may only appear once in a name field. + +Below is a full list of all default definition tokens with a brief description. +For more information on what each of them do, see the specific section of the readme that relates to that token. +Note that not all definition tokens change the object into a [definition object](#definition-objects). + +Default Token | Category | Usable In | Is a [Definition Object](#def-definition-object) | Meaning +--------------|----------|-----------|:----------------------:|-------- +`bounds` | [Definition objects](#definition-objects) | [Object](#def-object) name | Yes | This is a bounds definition object. +`collision` | [Definition objects](#definition-objects) | [Object](#def-object) name | Yes | This is a collision definition object. +`gridb` | [Definition objects](#definition-objects) | [Object](#def-object) name | Yes | Write brick grid `b` symbol in this [volume](#def-volume). +`gridd` | [Definition objects](#definition-objects) | [Object](#def-object) name | Yes | Write brick grid `d` symbol in this [volume](#def-volume). +`gridu` | [Definition objects](#definition-objects) | [Object](#def-object) name | Yes | Write brick grid `u` symbol in this [volume](#def-volume). +`grid-` | [Definition objects](#definition-objects) | [Object](#def-object) name | Yes | Write brick grid `-` symbol in this [volume](#def-volume). +`gridx` | [Definition objects](#definition-objects) | [Object](#def-object) name | Yes | Write brick grid `x` symbol in this [volume](#def-volume). +`qt` | [Quad sorting](#defining-quad-sections--coverage) | [Object](#def-object) name | No | Sort these [faces](#def-face) in the top section. +`qb` | [Quad sorting](#defining-quad-sections--coverage) | [Object](#def-object) name | No | Sort these [faces](#def-face) in the bottom section. +`qn` | [Quad sorting](#defining-quad-sections--coverage) | [Object](#def-object) name | No | Sort these [faces](#def-face) in the north section. +`qe` | [Quad sorting](#defining-quad-sections--coverage) | [Object](#def-object) name | No | Sort these [faces](#def-face) in the east section. +`qs` | [Quad sorting](#defining-quad-sections--coverage) | [Object](#def-object) name | No | Sort these [faces](#def-face) in the south section. +`qw` | [Quad sorting](#defining-quad-sections--coverage) | [Object](#def-object) name | No | Sort these [faces](#def-face) in the west section. +`qo` | [Quad sorting](#defining-quad-sections--coverage) | [Object](#def-object) name | No | Sort these [faces](#def-face) in the omni section. +`c` | [Colors](#defining-colors) | [Object](#def-object) name | No | The next four numbers define the color for these [faces](#def-face). +`blank` | [Colors](#defining-colors) | Material name | No | Do not write a color for [faces](#def-face) using this material: use the in-game spray can color as is. +`cadd` | [Colors](#defining-colors) | Material name, vertex color layer name | No | Add the material/vertex color of these [faces](#def-face) to the in-game spray can color. +`csub` | [Colors](#defining-colors) | Material name, vertex color layer name | No | Subtract the material/vertex color of these [faces](#def-face) from the in-game spray can color. ### Mesh Definition Tokens ### -Objects that have one or more of these definition tokens are exported into the BLB file and can be seen in-game. The definition tokens below will not cause an object to be treated as a definition object. These objects are exported normally and can be seen in-game. Instead the definition token will change some aspect of the mesh or brick. +Mesh definition tokens are a sub-category of [definition tokens](#definition-tokens) that can only be used in the names of [objects](#def-objects) but do not change the object into an invisible [definition object](#definition-objects). +Objects that have one or more of these definition tokens are treated as [visible objects](#def-visible-object) and they govern some aspect of the [faces](#def-face) they are related to. + +:exclamation: Each definition token may only appear once in a name field but a name may contain both definition tokens. -A single object may not contain the same definition more than once. +Definition | Default Token | Requirements | Maximum Count/Brick | Description +-----------|---------------|--------------|--------------------:|------------ +Color | `c` | See [Defining Colors](#defining-colors) | Unlimited | Defines the color of the [faces](#def-face). +Coverage | See [Defining Quad Sorting & Coverage](#defining-quad-sections--coverage) | Must contain a [face](#def-face) | Unlimited | Assigns the object's quads into a specific section in the brick. -Definition | Token | Requirements | Maximum Count/Brick | Axis Aligned | Brick Grid Aligned | Description ------------|-------|--------------|--------------------:|:------------:|:------------------:|------------ -Color | `c` | See [Defining Colors](#defining-colors) | Unlimited | No | No | Defines the object's RGBA color. -Coverage | See [Defining Quad Sorting & Coverage](#defining-quad-sorting--coverage) | Must contain a face | Unlimited | No | No | Assigns the object's quads into a specific section in the brick. +#### Defining Quad Sections & Coverage #### +BLB files allow [mesh](#def-mesh) [faces](#def-face) to be sorted into seven sections: top, bottom, north, east, south, west, and omni. +Quads in these sections may then be automatically hidden in-game using the [coverage system](#def-coverage), if it is defined correctly in the BLB file. -#### Defining Quad Sorting & Coverage #### -BLB files allow model quads to be sorted into seven sections: top, bottom, north, east, south, west, and omni. Quads in these sections may then be automatically hidden in-game using the coverage system, if it is defined correctly in the BLB file. This way the game does not have to render quads that are completely covered by adjacent bricks improving frame rate when a large number of bricks are on the screen at once. Quads are sorted into these sections by using one of the tokens below in the name of the object containing the faces to be sorted in that section. If nothing is specified, omni section is used. +The coverage system allows the game to not render quads that are completely covered by adjacent bricks improving frame rate when a large number of bricks are on the screen at once. +Quads are sorted into these sections by using one of the tokens below in the name of the [object](#def-object) containing the faces to be sorted into that section. +If a [visible object](#def-visible-object) has no quad sorting token specified, the omni section is used. -Token | Section -------|-------- +Default Token | Section +--------------|-------- `qt` | Top `qb` | Bottom `qn` | North @@ -426,41 +419,86 @@ Token | Section `qw` | West `qo` | Omni ("any" or "none", default) -Sorting quads in the manner described above is pointless unless the [Coverage](#coverage) property in the export dialog is enabled and at least one option is enabled. The coverage properties have two options for each section/side of the brick: +:exclamation: Sorting quads in this manner is pointless unless the [Coverage](#coverage) property in the export dialog is enabled and at least one option is enabled. + +In the export dialog [Coverage](#coverage) properties there are two options for each section/side of the brick: Option | Description -------|------------ -Hide Self | When enabled, for example for the **top section**, the game will not render the quads in the **top** section of **this brick** when the **top** area of **this brick** is **completely covered**. -Hide Adjacent | When enabled, for example for the **top section**, the game will not render the quads in the **bottom** section of **adjacent bricks** on **top** of this brick if the coverage rules for those bricks are fulfilled. +Hide Self | For example when enabled for the top section, the game will not render the [quads](#def-quad) in the **top** section of **this brick** when the top area of this brick is completely covered. +Hide Adjacent | For example when enabled for the top section, the game will not render the [quads](#def-quad) in the **bottom** section of **adjacent bricks** on top of this brick if the coverage rules for those adjacent bricks are fulfilled. #### Defining Colors #### -The exporter supports three methods for defining vertex colors. To allow faces to be colored using the spray can tool in-game, do not assign a color those faces. +The exporter supports three methods for defining brick colors. +To allow faces to be colored using the spray can tool in game do not assign a color those faces. +See [RGBA Color Format](#rgba-color-format) for a detailed explanation of how to write an RGBA color value. Method | Overrides | Extent of Coloring | RGB Values | Alpha Value | Notes -------|-----------|--------------------|------------|-------------|------ -Object Colors | In-game paint color | Entire object (color & alpha)| In object name after the [Color token](#mesh-definition-tokens-color) [**(1)**](#defining-colors-fn-1) | In object name after the red, green, and blue values | Implemented only to support legacy 3D brick models, not recommended for use. -Material Colors | Object Colors | Assigned faces (color & alpha) | In `Material` tab as `Diffuse Color` | In `Material` tab under `Transparency` in `Alpha` slider| Recommended method for defining colors. Multiple materials may be used in a single object. -Vertex Colors | Material Colors | Entire object (per-vertex color), entire object (alpha) | In `Data` tab under `Vertex Color` as a vertex color layer, modified using the `Vertex Paint` mode | In `Data` tab under `Vertex Color` as the name of the vertex color layer [**(2)**](#defining-colors-fn-2) | Creating a vertex color layers will color the entire object white, but the color of individual vertices may be changed. +Object Colors | In-game paint color | Entire object (color & alpha)| In object name after the [Color token](#mesh-definition-tokens-color) | In object name after the red, green, and blue values | Implemented only to support legacy brick models, **not recommended for use**. +Material Colors | Object Colors | Assigned faces (color & alpha) | In `Material` tab as `Diffuse Color` | In `Material` tab under `Transparency` in `Alpha` slider| The **recommended method** for defining color. Multiple materials may be used in a single object. +Vertex Colors | Material Colors | Entire object (per-vertex color), entire object (alpha) | In `Data` tab under `Vertex Color` as a vertex color layer, modified using the `Vertex Paint` mode | In `Data` tab under `Vertex Color` as the name of the vertex color layer | Creating a vertex color layers will color the entire object white, but the color of individual vertices may be changed. There are three definition tokens that are specific to dealing with colors. Token | Usable In | Description ------|-----------|------------ `blank` | Material name | Ignore the material's color and do not write any color for the faces with this material assigned so they can be colored by the spray can in-game. This feature exists because an object that has a material, cannot have faces that do not have a material assigned to them. -`cadd` | Material name, vertex color layer name | Use this color as an additive color: add the values of this color to the spray can color in-game. For example to make the spray can color a little lighter use a **dark gray** color. -`csub` | Material name, vertex color layer name | Use this color as a subtractive color: subtract the values of this color from the spray can color in-game. For example to make the spray can color a lot darker use a **light gray** color. +`cadd` | Material name, vertex color layer name | Use this color as an additive color: add the values of this color to the spray can color in-game. For example to make the spray can color **a little lighter** use a **dark gray** color. +`csub` | Material name, vertex color layer name | Use this color as a subtractive color: subtract the values of this color from the spray can color in-game. For example to make the spray can color **a lot darker** use a **light gray** color. + +##### RGBA Color Format ##### +The exporter understands two ways of defining an RGBA color using text. -**(1)** The exporter understands two ways of defining an RGBA color using text: -1. The commonly used method of writing 4 integers that are in the range 0–255, where 0 is black, separated with a whitespace character such as a space. For example `127 255 10 191` for a yellow-green color that is 25% transparent. A full object name could be for example `glass c 240 255 255 128.001`. +:exclamation: Please note that you **must** use a comma character (`,`) as the decimal separator for floating point numbers. + +1. The commonly used method of writing 4 integers that are in the range 0–255, where 0 is black, separated with a whitespace character such as a space. +For example `127 255 10 191` for a yellow-green color that is 25% transparent. A full object name could be for example `glass c 240 255 255 128.001`. - In the above example the running index `.001` that Blender added at the end would be removed by the exporter. 1. Writing 4 decimals in the range 0.0–1.0, where 0.0 is black, separated with a whitespace character such as a space. An object could have a name such as `c 0,125 0,0 0,5 1,0 flower`, for example. - - :exclamation: Please note that you **must** use a comma character (`,`) as the decimal separator. - The leading zero may be omitted. - Up to 16 decimals are supported. -**(2)** The definition of the alpha color value follows the same rules as described in footnote [**(1)**](#defining-colors-fn-1). +## Definition Objects ## +When a definition object token is read in an object's name it is treated as a definition object. Definition objects are never exported as visual 3D models, in fact they are not exported at all. Instead the data they contain in their name (or elsewhere) and the 3D space they represent is processed further to acquire the necessary information for the BLB file. + +Definition Object | Default Token | Requirements | Maximum Count/Brick | Must Be Within [**Bounds**](#definition-objects-bounds) | Axis-Aligned | Brick Grid Aligned | Can Overlap | Description +------------------|---------------|--------------|--------------------:|:-------------------:|:------------:|:------------------:|:-----------:|------------ +Bounds | `bounds` | At least two vertices, must have volume | 1 | N/A | Yes [**(1)**](#definition-objects-fn-1) | Yes | N/A | Defines the dimensions or the size of the brick. +Collision | `collision` | At least two vertices, must have volume | 10 | Yes [**(2)**](#definition-objects-fn-2) | Yes | No | Yes | Defines a collision [cuboid](#def-cuboid). See [Defining Collision](#defining-collision) for more info. +Brick Grid | See [Defining Brick Grid](#defining-brick-grid) | At least two vertices, must have volume | Unlimited | Yes | Yes [**(1)**](#definition-objects-fn-1) | Yes | Yes [**(4)**](#definition-objects-fn-4) | Defines a volume in the brick grid to fill with a specific brick grid symbol. + +**(1)** It is highly recommended to use [axis-aligned cuboids](#def-aac) to define bounds and the [brick grid](#def-brick-grid). +However, if you insist on defining the size of your brick in monkey heads, you can. +Only the [axis-aligned bounding box](#def-aabb) of the bounds and brick grid objects are used. + +**(2)** Collision boxes outside brick bounds are technically not invalid and the brick will function in-game. +This behavior is not allowed by the exporter because collision outside brick bounds is horribly broken as it was never intended work in that manner. + +**(4)** See [Defining Brick Grid](#defining-brick-grid) for the specific rules about overlapping brick grid definitions. + +### Defining Collision ### +Blockland bricks only supports [AABB collision](https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box). +In other words brick collision may only be defined using [cuboids](#def-cuboids) of varying sizes that align with the coordinate axes. +You can rotate said cuboids however you want but that will not lead to rotated collision cuboids in-game. +Only the the [axis-aligned bounding box](#def-aabb) of the collision definition objects are used. + +:bulb: Using any other shape than an axis-aligned cuboid to define collision is not recommended as it makes the Blender file more difficult to understand and also breaks the "what you see is what you get" principle. + +### Defining Brick Grid ### +Brick grid definitions represent a 3D volume in the 3D space the brick grid encompasses. You can imagine it as if the entire cuboidal shape of the brick would be filled with 1x1f plates and these volumes define the properties of all the 1x1f plates within that volume. Each brick grid definition has their own priority. When two or more brick grid definition objects overlap in 3D space, the one with the **higher** priority takes precedence and will overwrite the symbols in the brick grid that any definitions with lower priorities would have written. -### Brick Textures ### +:exclamation: Be aware that if your brick does not contain a `brickd` definition on the bottom of the brick, the brick cannot be planted on other bricks or the ground. + +Default Token | Brick Grid Symbol | Description +--------------|:-----------------:|------------ +`gridb` | `b` | Bricks may be placed above and below this volume. This brick can be planted on the ground. +`gridd` | `d` | Bricks may be placed below this volume. This brick can be planted on the ground. +`gridu` | `u` | Bricks may be placed above this volume. +`grid-` | `-` | Bricks may be placed inside this volume. (I.e. empty space.) This is the default symbol, any volume that does not have a brick grid definition uses this symbol. +`gridx` | `x` | Bricks may not be placed inside this volume. + +## Brick Textures ## Defining brick textures is done using Blender materials. To assign a brick texture to a face, assign a material to it containing a valid brick texture name (case insensitive): - `bottomedge` - `bottomloop` @@ -471,7 +509,7 @@ Defining brick textures is done using Blender materials. To assign a brick textu If no brick texture is defined, `side` is used. Material name may contain other words as long as the brick texture name is separated from them with one whitespace character such as a space. A common combination is to define a brick texture name and the [definition token `blank`](#defining-colors-blank) (e.g. `blank ramp` or `side blank`) to allow the player to color the face in-game using the spray can. -#### UV Mapping #### +## UV Mapping ## Manually defined UV coordinates must be stored in one or more UV layers that do not share a name with one of the automatically generated UV layers: - `TEX:BOTTOMEDGE` - `TEX:BOTTOMLOOP` @@ -485,9 +523,6 @@ Any data in UV layers with one the names above will the overwritten during autom If the [Calculate UVs](#calculate-uvs) property is enabled, UV coordinates will be automatically calculated based on the dimensions of the quad and the name of the material assigned to it. (See [Brick Textures](#brick-textures) to learn how to define brick textures with materials.) The generated coordinates are only guaranteed to be correct for strictly rectangular quads, for any other shapes the results may not be satisfactory. If using brick textures on non-rectangular quads it is recommended to manually define the UV coordinates for best results. -### The TOP Brick Texture ### -Blockland automatically performs rotations on the UV coordinates of the TOP brick texture during runtime so that the lightest side of the texture is always facing towards the sun. Because of this there is no correct way of representing the TOP brick texture in Blender. As a compromise the exporter will rotate the lightest side of the TOP brick texture to face towards the axis select in the [Forward Axis](#forward-axis) property. This means the UV coordinates of the TOP brick texture in Blender may not match those in the written BLB file. - ## Troubleshooting ## Solutions to common issues with the BLB Exporter. If you have another issue with the exporter be sure to enable the [Write Log](#write-log) property and export again. The log file may contain warnings or errors describing issues with the models and how to fix them. Additional instructions on how to fix specific issues are detailed in the [Warning & Error Log Messages](#warning--error-log-messages) section. @@ -498,6 +533,9 @@ The automatic UV calculation is only designed to work with rectangular quads. Ma ### Automatically calculated UV coordinates for brick textures are rotated incorrectly ### The quad with incorrectly rotated UV coordinates (e.g. the lightest side of the SIDE texture pointing sideways instead of up) is not a perfect rectangle. Even one vertex being off by some minuscule, visually indistinguishable amount from a perfectly rectangular shape can cause the automatic UV calculation to incorrectly determine the rotation of the quad. Double check all 4 coordinates of the quad and manually correct any floating point errors. If working on axis-aligned quads or if the vertices should be on grid points snapping the coordinates of the problem quad to grid coordinates using `Mesh > Snap > Snap Selection to Grid` usually fixes floating point errors. +### The TOP brick texture has incorrect rotation in Blender ### +Blockland automatically performs rotations on the UV coordinates of the TOP brick texture during runtime so that the lightest side of the texture is always facing towards the sun. Because of this there is no correct way of representing the TOP brick texture in Blender. As a compromise the exporter will rotate the lightest side of the TOP brick texture to face towards the axis select in the [Forward Axis](#forward-axis) property. This means the UV coordinates of the TOP brick texture in Blender may not match those in the written BLB file. + ## Warning & Error Log Messages ## Detailed explanations of the warning and error messages logged by the program and directions on how to solve the associated issues. In the messages listed in this section the `#` character is used to represent a variable numerical value. @@ -1534,7 +1572,7 @@ Fatal errors always lead to the program execution stopping. Cause - The object had more than one quad section definition token. + The object had more than one quad section definition token. Reason @@ -1593,4 +1631,4 @@ Normal vectors | [Optional](#round-normals) - [Nick Smith](https://github.com/portify) - The original source code for reading, processing, and writing Blender data into the .BLB format. It has essentially been completely rewritten since. - [Demian Wright](https://github.com/DemianWright) - Everything else. -__*__ There's always a footnote, see the issue with [the TOP brick texture](#the-top-brick-texture). \ No newline at end of file +__*__ There's always a footnote, see the issue with [the TOP brick texture](#the-top-brick-texture-has-incorrect-rotation-in-blender). \ No newline at end of file diff --git a/__init__.py b/__init__.py index 8ac5c77..c37af12 100644 --- a/__init__.py +++ b/__init__.py @@ -57,7 +57,6 @@ # TODO: Improve warning and error messages. # TODO: Fix link to Port's GitHub profile. # TODO: Calculate Bounds property. -# TODO: Definition object bounds rules to readme. class ExportBLB(bpy.types.Operator, ExportHelper): From 60f3c151f489c66614161f357a607bae7391c341 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 20:58:08 +0200 Subject: [PATCH 10/50] Convert nested tables to a single table --- README.md | 268 +++++++++++++++++------------------------------------- 1 file changed, 85 insertions(+), 183 deletions(-) diff --git a/README.md b/README.md index 1ebcd12..79ce8fe 100644 --- a/README.md +++ b/README.md @@ -1026,105 +1026,56 @@ Fatal errors always lead to the program execution stopping. Causes Depends on the values of various export properties. - - - + + + - - + + + - - + + + + + + + + +
Value of Bricks to Export
ValueCausesBricks to ExportExport Only (Single Export)Cause
Single - - - - - - - - - - - - - - - - - - - - - - -
Value of Export Only (Single Export)
ValueCause
SelectionNo objects were selected. Selected objects have an orange outline.
LayersThere are no objects in the currently visible layers.
SceneThere are no objects in the current scene. In other words none of the layers in the current scene contained objects.
-
SingleSelectionNo objects were selected. Selected objects have an orange outline.
Multiple - - - - - - - - - - - - - - - - - - -
Value of Export Bricks in (Multiple Export)
ValueCauses
Layers - - - - - - - - - - - - - - - - - - -
Value of Bricks Defined by (Multiple Export)
ValueCause
GroupsNone of the groups in the current scene had any objects in the visible layers.
LayersNone of the visible layers contained any objects.
-
Scene - - - - - - - - - - - - - - - - - - -
Value of Bricks Defined by (Multiple Export)
ValueCause
GroupsNone of the groups in the current scene contained any objects.
LayersNone of the layers in the current scene contained any objects.
-
-
LayersThere are no objects in the currently visible layers.
SceneThere are no objects in the current scene. In other words none of the layers in the current scene contained objects.
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Bricks to ExportExport Bricks in (Multiple Export)Bricks Defined by (Multiple Export)Cause
MultipleLayersGroupsNone of the groups in the current scene had any objects in the visible layers.
LayersNone of the visible layers contained any objects.
SceneGroupsNone of the groups in the current scene contained any objects.
LayersNone of the layers in the current scene contained any objects.
@@ -1136,107 +1087,58 @@ Fatal errors always lead to the program execution stopping. Solutions - Depends on the values of various export properties. + Depends on the values of various export properties. - - - + + + - - + + + - - + + + + + + + + +
Value of Bricks to Export
ValueSolutionsBricks to ExportExport Only (Single Export)Solution
Single - - - - - - - - - - - - - - - - - - - - - - -
Value of Export Only (Single Export)
ValueSolution
SelectionSelect some objects.
LayersSelect one or more layers with objects.
SceneYou are attempting to export an empty scene. Either add some objects to a layer in the scene or ensure that you are not in the wrong scene.
-
SingleSelectionSelect some objects.
Multiple - - - - - - - - - - - - - - - - - - -
Value of Bricks to Export
ValueSolutions
Layers - - - - - - - - - - - - - - - - - - -
Value of Bricks Defined by (Multiple Export)
ValueSolution
GroupsEnsure that your groups have objects assigned to them and that you have selected layers with objects in them.
LayersSelect layers with objects.
-
Scene - - - - - - - - - - - - - - - - - - -
Value of Bricks Defined by (Multiple Export)
ValueSolution
GroupsAdd objects to a group in the current scene.
LayersYou are attempting to export an empty scene. Either add some objects to a layer in the scene or ensure that you are not in the wrong scene.
-
-
LayersSelect one or more layers with objects.
SceneYou are attempting to export an empty scene. Either add some objects to a layer in the scene or ensure that you are not in the wrong scene.
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Bricks to ExportExport Bricks in (Multiple Export)Bricks Defined by (Multiple Export)Solution
MultipleLayersGroupsEnsure that your groups have objects assigned to them and that you have selected layers with objects in them.
LayersSelect layers with objects.
SceneGroupsAdd objects to a group in the current scene.
LayersYou are attempting to export an empty scene. Either add some objects to a layer in the scene or ensure that you are not in the wrong scene.
From 5c223856178059081b7c8abf7d86bc7a9c3bf570 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 21:00:06 +0200 Subject: [PATCH 11/50] Tweak README formatting --- README.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 79ce8fe..62b5cee 100644 --- a/README.md +++ b/README.md @@ -305,54 +305,54 @@ Value | Description -Y | Negative Y-axis: back #### Scale #### -The scale of the brick in-game. Values outside the the range of 0.001–400.0 may be typed in manually. Does not change the scale of the objects in the Blender scene. (Default: 100%) +The scale of the brick in-game. Values outside the the range of 0.001–400.0 may be typed in manually. Does not change the scale of the objects in the Blender scene. (Default: 100%) :exclamation: Be aware that at 100% scale a 1x1x1 Blockland brick is defined to be 1.0 x 1.0 x 1.2 Blender units on the X, Y, and Z axes. In other words a 1x1f plate would be 1.0 x 1.0 x 0.4 Blender units. #### Apply Modifiers #### -Applies any modifiers on the object before exporting. Does not change the modifiers of the objects in the Blender scene. (Default: True) +Applies any modifiers on the object before exporting. Does not change the modifiers of the objects in the Blender scene. (Default: True) #### Calculate Collision #### -If no manual collision definition objects exist, calculates a cuboid collision that is the same size as the brick bounds. If disabled and no collision is defined, brick will have no collision. (Default: True) +If no manual collision definition objects exist, calculates a cuboid collision that is the same size as the brick bounds. If disabled and no collision is defined, brick will have no collision. (Default: True) #### Coverage #### -Enable coverage calculations. Shows additional settings when selected. This is pointless unless [Automatic Quad Sorting](#automatic-quad-sorting) is enabled or at least one object has a quad sorting definition. See [Defining Quad Sorting & Coverage](#defining-quad-sections--coverage) for more information. (Default: False) +Enable coverage calculations. Shows additional settings when selected. This is pointless unless [Automatic Quad Sorting](#automatic-quad-sorting) is enabled or at least one object has a quad sorting definition. See [Defining Quad Sorting & Coverage](#defining-quad-sections--coverage) for more information. (Default: False) #### Automatic Quad Sorting #### -Automatically calculate the correct section for quads that in the same plane as the bounding planes of the bounds object. This is pointless unless [Coverage](#coverage) is enabled. (Default: True) +Automatically calculate the correct section for quads that in the same plane as the bounding planes of the bounds object. This is pointless unless [Coverage](#coverage) is enabled. (Default: True) #### Use Material Colors #### -Get object colors from object materials. (Default: False) +Get object colors from object materials. (Default: False) #### Use Vertex Colors #### -Get object colors from vertex color layers. (Default: False) +Get object colors from vertex color layers. (Default: False) #### Parse Object Colors #### -Get object colors from object names. (Default: False) +Get object colors from object names. (Default: False) #### Calculate UVs #### -Automatically calculate correct UV coordinates based on the brick texture name specified in the material name. See [UV Mapping](#uv-mapping) for more information. (Default: True) +Automatically calculate correct UV coordinates based on the brick texture name specified in the material name. See [UV Mapping](#uv-mapping) for more information. (Default: True) #### Store UVs #### -Write calculated UVs into Blender objects. Data in existing generated UV layers will be overwritten. See [UV Mapping](#uv-mapping) for a list of generated UV layer names. (Default: True) +Write calculated UVs into Blender objects. Data in existing generated UV layers will be overwritten. See [UV Mapping](#uv-mapping) for a list of generated UV layer names. (Default: True) #### Round Normals #### -Round vertex normals to the user-defined floating point value precision. If disabled normals will be written as accurately as possible but extraneous zeros will still be removed. (Default: False) +Round vertex normals to the user-defined floating point value precision. If disabled normals will be written as accurately as possible but extraneous zeros will still be removed. (Default: False) #### Custom Definition Tokens #### -Allows you to specify the definition tokens the exporter uses. Shows additional settings when selected. See [Definition Tokens](#definition-tokens) for more information. (Default: False) +Allows you to specify the definition tokens the exporter uses. Shows additional settings when selected. See [Definition Tokens](#definition-tokens) for more information. (Default: False) #### Terse Mode #### -When enabled does not write optional lines to the .BLB file such as the lines marking the different quad sections. Using this option is not recommended as it makes the .BLB file harder to read and understand. Although the file is shorter, the difference in file size is negligible. (Default: False) +When enabled does not write optional lines to the .BLB file such as the lines marking the different quad sections. Using this option is not recommended as it makes the .BLB file harder to read and understand. Although the file is shorter, the difference in file size is negligible. (Default: False) #### Write Log #### -Write a log file to the same folder as the exported brick detailing the export process. Shows additional settings when selected. (Default: True) +Write a log file to the same folder as the exported brick detailing the export process. Shows additional settings when selected. (Default: True) #### Only on Warnings #### -Write a log file only if warnings or errors occurred during the export process. (Default: True) +Write a log file only if warnings or errors occurred during the export process. (Default: True) #### Precision #### -Allows you to specify a custom precision for floating point numbers. See [Rounded Values](#rounded-values) for more details. (Default: 0.000001) +Allows you to specify a custom precision for floating point numbers. See [Rounded Values](#rounded-values) for more details. (Default: 0.000001) ## Definition Tokens ## [Definition tokens](#def-definition-token) are special [strings](#def-string) added to the names of objects, materials, and other Blender data objects that have a name. @@ -984,7 +984,7 @@ Fatal errors always lead to the program execution stopping. - + @@ -1175,7 +1175,7 @@ Fatal errors always lead to the program execution stopping.
MessageBrick size (#x#x#) exceeds the maximum brick size of 64 wide 64 deep and 256 plates tall.Brick size (#x#x#) exceeds the maximum brick size of 64 wide 64 deep and 256 plates tall.
Cause
- + @@ -1222,7 +1222,7 @@ Fatal errors always lead to the program execution stopping.
MessageBrick grid definition object '%object name%' has vertices outside the bounds definition object '%object name%'. Definition ignored.Brick grid definition object 'object name' has vertices outside the bounds definition object 'object name'. Definition ignored.
Cause
- + From 317eec898651bf29af269493874fc6ae892b14c5 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 21:02:44 +0200 Subject: [PATCH 12/50] Convert dfn tags to a tags, GitHub seems to strip them out --- README.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 62b5cee..041f9d0 100644 --- a/README.md +++ b/README.md @@ -131,25 +131,25 @@ These features may or may not be implemented at some unspecified time in the fut A list of more or less technical terms used in this document. The definitions are in the context of Blockland, Blender, and this exporter and may vary from their mathematical definitions.
-
Axis-Aligned Plane
+
Axis-Aligned Plane
A plane whose vertices have the same coordinate on exactly one coordinate axis. When this two-dimensional plane is viewed from either of the other two coordinate axes it disappears from view.
-
Axis-Aligned Bounding Box / Axis-Aligned Minimum Bounding Box
+
Axis-Aligned Bounding Box / Axis-Aligned Minimum Bounding Box
A cuboid that completely encompasses all vertices of one or more objects. The faces of this cuboid are parallel with the coordinate axes.
-
Axis-Aligned Cuboid
+
Axis-Aligned Cuboid
A cuboid whose faces are parallel with the coordinate axes.
-
Brick Grid
+
Brick Grid
  1. The three-dimensional space of the game divided into 1x1x1 brick plates
  2. The blocks of u, x, -, and other characters near the top of the .BLB file that define the brick's placement rules. See Defining Brick Grid.
-
Brick
+
Brick
  1. A collection of faces that acts as a single object in Blockland and all the non-visual data it contains such as collision information.
  2. The BLB file itself.
  3. @@ -157,19 +157,19 @@ See Defining Brick Grid.
-
Coverage (System)
+
Coverage (System)
  1. The Blockland coverage system describes how to hide faces on a brick and any adjacent bricks.
  2. The six pairs of integers near the top of a BLB file.
-
Cuboid
+
Cuboid
More specifically a right cuboid in the context of Blockland bricks. A convex polyhedron with 6 faces that are all at right angles to each other. I.e. a regular cube or a cube that is elongated on one axis.
-
Definition Object
+
Definition Object
An object that has a specific definition token in its name. These objects cannot be seen in-game. They exist to tell the exporter how to create the brick. @@ -180,65 +180,65 @@ There are three different definition objects:
  • and a brick grid definition object.
  • -
    Definition Token
    +
    Definition Token
    A special token in an object's name that tells the exporter what to do with that object.
    -
    Face
    +
    Face
    A visible surface that is rendered in game and in the Blender viewport. The surface must be bound by or created by at least three vertices (making it a tri) or in deed any number of vertices (also called an n-gon). :exclamation: Blockland bricks only support faces made from exactly four vertices: quads.
    -
    Mesh
    +
    Mesh
    The vertices, edges, and faces that make up a 3D model.
    -
    Mesh Object
    +
    Mesh Object
    A Blender object that contains vertices, edges, and faces. Commonly just referred to as an object.
    -
    Model
    +
    Model
    One or more objects that make up a brick.
    -
    N-gon
    +
    N-gon
    Technically any polygon but in this document used to refer to a single face formed from more than four vertices. N-gons are not necessarily planes. :exclamation: These are not supported by the exporter or Blockland: the faces will be ignored.
    -
    Object
    +
    Object
    Usually a mesh object. Technically refers to all the meshes, cameras, lights, empties, and everything else you see in the 3D viewport. Blender objects contain data about vertices, materials, groups, object names, and more.
    -
    Plane
    +
    Plane
    A flat two-dimensional surface in 3D space. A particular type of face.
    -
    Quad
    +
    Quad
    A face with four vertices. Quads are not necessarily planes.
    -
    String
    +
    String
    A sequence of letters. Usually a word.
    -
    Token
    +
    Token
    A string surrounded with a whitespace character on one or both sides.
    -
    Tri
    +
    Tri
    A face with three vertices. Triangles are always planes. :exclamation: These are not supported by Blockland bricks and they are converted to quads automatically.
    -
    Visible Object
    +
    Visible Object
    Any mesh object that is not a definition object. Visible objects are rendered and are seen in-game as a brick.
    -
    Volume
    +
    Volume
    A section of 3D space, usually cuboidal in shape in the context of this exporter.
    -
    Whitespace (Character)
    +
    Whitespace (Character)
    In Blender, commonly a space or a tab character.
    From b949d0b65b380c5cdf01263633fd3a16b6c1220d Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 21:14:06 +0200 Subject: [PATCH 13/50] Fix rowspan, internal link, add link to TOC to the bottom --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 041f9d0..5bc6ecf 100644 --- a/README.md +++ b/README.md @@ -479,7 +479,7 @@ This behavior is not allowed by the exporter because collision outside brick bou ### Defining Collision ### Blockland bricks only supports [AABB collision](https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box). -In other words brick collision may only be defined using [cuboids](#def-cuboids) of varying sizes that align with the coordinate axes. +In other words brick collision may only be defined using [cuboids](#def-cuboid) of varying sizes that align with the coordinate axes. You can rotate said cuboids however you want but that will not lead to rotated collision cuboids in-game. Only the the [axis-aligned bounding box](#def-aabb) of the collision definition objects are used. @@ -1059,7 +1059,7 @@ Fatal errors always lead to the program execution stopping.
    - + @@ -1122,7 +1122,7 @@ Fatal errors always lead to the program execution stopping. - + @@ -1533,4 +1533,6 @@ Normal vectors | [Optional](#round-normals) - [Nick Smith](https://github.com/portify) - The original source code for reading, processing, and writing Blender data into the .BLB format. It has essentially been completely rewritten since. - [Demian Wright](https://github.com/DemianWright) - Everything else. -__*__ There's always a footnote, see the issue with [the TOP brick texture](#the-top-brick-texture-has-incorrect-rotation-in-blender). \ No newline at end of file +__*__ There's always a footnote, see the issue with [the TOP brick texture](#the-top-brick-texture-has-incorrect-rotation-in-blender). + +[:arrow_up: Back to Table of Contents](#table-of-contents) \ No newline at end of file From 8fed6e4a632919e95c811785fc11fc3765a86174 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 21:16:18 +0200 Subject: [PATCH 14/50] Fix link to Nick Smith's GitHub profile --- README.md | 4 ++-- __init__.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5bc6ecf..a3e4960 100644 --- a/README.md +++ b/README.md @@ -1530,8 +1530,8 @@ Normal vectors | [Optional](#round-normals) [UV coordinates](#uv-mapping) | No ## Contributors ## -- [Nick Smith](https://github.com/portify) - The original source code for reading, processing, and writing Blender data into the .BLB format. It has essentially been completely rewritten since. -- [Demian Wright](https://github.com/DemianWright) - Everything else. +- [Nick Smith](https://github.com/qoh) - The original source code for reading, processing, and writing Blender data into the .BLB format. A majority of his code has been rewritten since. +- [Demian Wright](https://github.com/DemianWright) - Significant extensions and rewrites to Nick's original code and everything else. __*__ There's always a footnote, see the issue with [the TOP brick texture](#the-top-brick-texture-has-incorrect-rotation-in-blender). diff --git a/__init__.py b/__init__.py index c37af12..eb40854 100644 --- a/__init__.py +++ b/__init__.py @@ -55,7 +55,6 @@ # TODO: Clarify brick grid and brick grid placement rules. # TODO: Clarify which errors occur when autogenerating brick grid. # TODO: Improve warning and error messages. -# TODO: Fix link to Port's GitHub profile. # TODO: Calculate Bounds property. From dfbd238bc842adf1d2d44a529d11b60467de7699 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 21:19:26 +0200 Subject: [PATCH 15/50] Add DTS collision exporting to planned features --- README.md | 4 ++-- __init__.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a3e4960..8140636 100644 --- a/README.md +++ b/README.md @@ -99,12 +99,12 @@ The exporter supports all BLB features. - [x] Pretty .BLB files: extraneous zeros are not written at the end of floating point values and if possible, they are written as integers - [x] Logging with descriptive error and warning messages to help you correct problems with the brick - [x] Customizable floating point accuracy -- [ ] DTS collision is intentionally not a part of this add-on as it an entirely different file format. - - See Nick Smith's [io_scene_dts](https://github.com/portify/io_scene_dts) for a Blender DTS importer/exporter. +- [ ] Exporting DTS collision is not yet supported. ### Planned Features ### These features may or may not be implemented at some unspecified time in the future. +- Exporting DTS collision using Nick Smith's [io_scene_dts](https://github.com/qoh/io_scene_dts) Blender plugin. - Importing .BLB files - Export-time brick rotation on the Z-axis - Automatic rendering of the brick preview icon diff --git a/__init__.py b/__init__.py index eb40854..4404e53 100644 --- a/__init__.py +++ b/__init__.py @@ -41,6 +41,7 @@ "tracker_url": "", "category": "Import-Export"} +# TODO: Exporting DTS collision. # TODO: Importing BLB files. # TODO: Render brick preview. # TODO: Panels in the UI? From d46aca0dbe9854b16e48b40d947919b477632095 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 12 Nov 2017 22:06:15 +0200 Subject: [PATCH 16/50] Improve error and warning messages --- README.md | 18 +++++++++--------- __init__.py | 1 - blb_processor.py | 35 +++++++++++++++-------------------- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 8140636..87e5c36 100644 --- a/README.md +++ b/README.md @@ -586,7 +586,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
    Message# collision boxes defined but 10 is the maximum. Only the first 10 will be used.# collision boxes defined but 10 is the maximum. Only the first 10 will be used.
    Cause
    MultipleMultiple Layers Groups None of the groups in the current scene had any objects in the visible layers.
    MultipleMultiple Layers Groups Ensure that your groups have objects assigned to them and that you have selected layers with objects in them.
    - + @@ -604,7 +604,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
    MessageBrick name was to be sourced from the name of the bounds definition object but no bounds definition object exists, file name used instead.Brick name was supposed to be in the bounds definition object but no such object exists, file name used instead.
    Cause
    - + @@ -622,7 +622,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
    MessageBrick name was to be sourced from the name of the bounds definition object but no brick name was found after the bounds definition (separated with a space), file name used instead.Brick name was supposed to be in the bounds definition object but no name (separated with a space) was found after the definition token, file name used instead.
    Cause
    - + @@ -640,7 +640,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
    MessageNo brick grid definitions found. Automatically generated brick grid may be undesirable.No brick grid definitions found. Full cuboid brick grid may be undesirable.
    Cause
    - + @@ -722,7 +722,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
    Message# brick grid definition(s) found but was/were not processed. Automatically generated brick grid may be undesirable.# brick grid definition(s) found but was/were not processed. Full cuboid brick grid may be undesirable.
    Cause
    - + @@ -758,7 +758,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
    MessageNo brick bounds definition found. Automatically calculated brick size may be undesirable.No brick bounds definition found. Calculated brick size may be undesirable.
    Cause
    - + @@ -794,7 +794,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
    MessageFace has UV coordinates but no brick texture, using SIDE by default.Face has UV coordinates but no brick texture was set in the material name, using SIDE by default.
    Cause
    - + @@ -1222,7 +1222,7 @@ Fatal errors always lead to the program execution stopping.
    Message# triangles degenerated to quads.# triangles converted to quads.
    Cause
    - + @@ -1404,7 +1404,7 @@ Fatal errors always lead to the program execution stopping.
    Message# collision boxes defined but 10 is the maximum. Only the first 10 will be used.# collision cuboids defined but 10 is the maximum, only using the first 10.
    Cause
    - + diff --git a/__init__.py b/__init__.py index 4404e53..12eabd8 100644 --- a/__init__.py +++ b/__init__.py @@ -55,7 +55,6 @@ # TODO: Consider using unique IDs for errors and warnings? [WARNING:IOBLBW0000] and [ERROR:IOBLBE0000]? # TODO: Clarify brick grid and brick grid placement rules. # TODO: Clarify which errors occur when autogenerating brick grid. -# TODO: Improve warning and error messages. # TODO: Calculate Bounds property. diff --git a/blb_processor.py b/blb_processor.py index 0b1ed59..89e95d4 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -949,12 +949,11 @@ def __record_bounds_data(properties, blb_data, bounds_data): if properties.blendprop.export_count == "SINGLE" and properties.blendprop.brick_name_source == "BOUNDS": if bounds_data.object_name is None: - logger.warning("Brick name was to be sourced from the name of the bounds definition object but no bounds definition object exists, file name used instead.", 1) + logger.warning("Brick name was supposed to be in the bounds definition object but no such object exists, file name used instead.", 1) else: if len(bounds_data.object_name.split()) == 1: - logger.warning( - "Brick name was to be sourced from the name of the bounds definition object but no brick name was found after the bounds definition (separated with a space), file name used instead.", - 1) + logger.warning("Brick name was supposed to be in the bounds definition object but no name (separated with a space) was found after the definition token, file name used instead.", + 1) else: # Brick name follows the bounds definition, must be separated by a space. # Substring the object name: everything after properties.deftokens.bounds and 1 space character till the end of the name. @@ -968,17 +967,15 @@ def __record_bounds_data(properties, blb_data, bounds_data): return "When exporting multiple bricks in separate layers, a bounds definition object must exist in every layer. It is also used to provide a name for the brick." else: # TODO: Does this work? Does it actually export multiple bricks or overwrite the first one? - logger.warning( - "Brick name was to be sourced from the name of the bounds definition object but no bounds definition object exists, file name used instead.", 1) + logger.warning("Brick name was supposed to be in the bounds definition object but no such object exists, file name used instead.", 1) else: if len(bounds_data.object_name.split()) == 1: if properties.blendprop.brick_definition == "LAYERS": # RETURN ON ERROR return "When exporting multiple bricks in separate layers, the brick name must be after the bounds definition token (separated with a space) in the bounds definition object name." else: - logger.warning( - "Brick name was to be sourced from the name of the bounds definition object but no brick name was found after the bounds definition (separated with a space), file name used instead.", - 1) + logger.warning("Brick name was supposed to be in the bounds definition object but no name (separated with a space) was found after the definition token, file name used instead.", + 1) else: # Brick name follows the bounds definition, must be separated by a space. # Substring the object name: everything after properties.deftokens.bounds and 1 space character till the end of the name. @@ -1995,18 +1992,16 @@ def __process_grid_definitions(properties, blb_data, bounds_data, definition_obj # Log messages for brick grid definitions. if total_definitions == 0: - logger.warning("No brick grid definitions found. Automatically generated brick grid may be undesirable.", 1) + logger.warning("No brick grid definitions found. Full cuboid brick grid may be undesirable.", 1) elif total_definitions == 1: if processed == 0: - logger.warning( - "{} brick grid definition found but was not processed. Automatically generated brick grid may be undesirable.".format(total_definitions), 1) + logger.warning("{} brick grid definition found but was not processed. Full cuboid brick grid may be undesirable.".format(total_definitions), 1) else: logger.info("Processed {} of {} brick grid definition.".format(processed, total_definitions), 1) else: # Found more than one. if processed == 0: - logger.warning( - "{} brick grid definitions found but were not processed. Automatically generated brick grid may be undesirable.".format(total_definitions), 1) + logger.warning("{} brick grid definitions found but were not processed. Full cuboid brick grid may be undesirable.".format(total_definitions), 1) else: logger.info("Processed {} of {} brick grid definitions.".format(processed, total_definitions), 1) @@ -2069,7 +2064,7 @@ def __process_collision_definitions(properties, bounds_data, definition_objects, processed = 0 if len(definition_objects) > 10: - logger.error("{} collision boxes defined but 10 is the maximum. Only the first 10 will be used.".format(len(definition_objects)), 1) + logger.error("{} collision cuboids defined but 10 is the maximum, only using the first 10.".format(len(definition_objects)), 1) for obj in definition_objects: # Break the loop as soon as 10 definitions have been processed. @@ -2142,7 +2137,7 @@ def __process_collision_definitions(properties, bounds_data, definition_objects, if properties.blendprop.calculate_collision: # TODO: Remove. logger.warning( - "{} collision definition found but was not processed. Brick collision will be the same size as the brick bounds.".format(defcount), 1) + "{} collision definition found but was not processed. Brick collision will be the same size and shape as the bounds.".format(defcount), 1) else: logger.warning( "{} collision definition found but was not processed. Brick will have no collision.".format(defcount), 1) @@ -2250,7 +2245,7 @@ def __process_definition_objects(properties, objects): "", bricks, (" brick", " bricks")), logger.build_countable_message("", blb_data.brick_size[Z] - bricks * 3, (" plate", " plates"))), 1) else: - logger.error("Multiple bounds definitions found. '{}' definition ignored.".format(obj_name), 1) + logger.error("Bounds already defined by '{}', bounds definition '{}' ignored.".format(bounds_data.object_name, obj_name), 1) continue # Is the current object a collision definition object? @@ -2282,7 +2277,7 @@ def __process_definition_objects(properties, objects): # No manually created bounds object was found, calculate brick bounds based on the minimum and maximum recorded mesh vertex positions. if bounds_data is None: - logger.warning("No brick bounds definition found. Automatically calculated brick size may be undesirable.", 1) + logger.warning("No brick bounds definition found. Calculated brick size may be undesirable.", 1) # ROUND & CAST bounds_data = __calculate_bounds(properties.scale, __to_decimal(min_world_coordinates), __to_decimal(max_world_coordinates)) @@ -2563,7 +2558,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ if brick_texture is None: # Fall back to SIDE texture if nothing was specified. brick_texture = const.BrickTexture.SIDE - logger.warning("Face has UV coordinates but no brick texture, using SIDE by default.", 2) + logger.warning("Face has UV coordinates but no brick texture was set in the material name, using SIDE by default.", 2) # Do we have UV coordinates for a tri? if len(uvs) == 3: @@ -2701,7 +2696,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ bpy.data.meshes.remove(mesh) if count_tris > 0: - logger.warning("{} triangles degenerated to quads.".format(count_tris), 2) + logger.warning("{} triangles converted to quads.".format(count_tris), 2) if count_ngon > 0: logger.warning("{} n-gons skipped.".format(count_ngon), 2) From 772d6f3c5ab1eb039313218e32b8fedce5d1d98d Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Mon, 13 Nov 2017 20:24:55 +0200 Subject: [PATCH 17/50] Move processing default collision cuboid to processor from writer --- blb_processor.py | 26 +++++++++++++++----------- blb_writer.py | 19 +++++-------------- const.py | 3 +++ 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/blb_processor.py b/blb_processor.py index 8bf8cf0..01d93db 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -31,9 +31,8 @@ import bpy from mathutils import Euler, Vector -import numpy - import bmesh +import numpy from . import common, const, logger from .const import Axis3D, AxisPlane3D, X, Y, Z @@ -2053,28 +2052,33 @@ def __process_grid_definitions(properties, blb_data, bounds_data, definition_obj return brick_grid -def __process_collision_definitions(properties, bounds_data, definition_objects,): +def __process_collision_definitions(properties, blb_data, bounds_data, definition_objects): """Processes the specified collision definitions. Args: properties (DerivateProperties): An object containing user properties. + blb_data (BLBData): A BLBData object containing all the necessary data for writing a BLB file. bounds_data (BrickBounds): A BrickBounds object containing the bounds data. definition_objects (a sequence of Blender object): A sequence of Blender objects representing collision definitions. Returns: - A sequence of tuples : [ (center coordinates in the local space of the brick, collision cuboid dimensions), ] + A sequence of tuples: [ (center coordinates in the local space of the brick, collision cuboid dimensions), ] + Sequence can be empty. """ collisions = [] processed = 0 - if len(definition_objects) > 10: - logger.error("{} collision boxes defined but 10 is the maximum. Only the first 10 will be processed.".format(len(definition_objects)), 1) + if properties.blendprop.calculate_collision: + logger.info("Ignoring custom collision definitions, using bounds as collision cuboid.", 1) + # Center of the full brick collision cuboid is at the middle of the brick. + # The size of the cuboid is the size of the bounds. + return [([0, 0, 0], blb_data.brick_size)] - for obj in definition_objects: - # Break the loop as soon as 10 definitions have been processed. - if processed > 9: - break + if len(definition_objects) > const.MAX_BRICK_COLLISION_CUBOIDS: + logger.error("{0} collision cuboids defined but {1} is the maximum. Only the first {1} will be processed.".format( + len(definition_objects), const.MAX_BRICK_COLLISION_CUBOIDS), 1) + for obj in definition_objects[:const.MAX_BRICK_COLLISION_CUBOIDS]: vert_count = len(obj.data.vertices) # At least two vertices are required for a valid bounding box. @@ -2311,7 +2315,7 @@ def __process_definition_objects(properties, objects): else: # Process brick grid and collision definitions now that a bounds definition exists. blb_data.brick_grid = __process_grid_definitions(properties, blb_data, bounds_data, brick_grid_objects) - blb_data.collision = __process_collision_definitions(properties, bounds_data, collision_objects) + blb_data.collision = __process_collision_definitions(properties, blb_data, bounds_data, collision_objects) # Return the data. return (blb_data, bounds_data, mesh_objects) diff --git a/blb_writer.py b/blb_writer.py index 4175480..11657cd 100644 --- a/blb_writer.py +++ b/blb_writer.py @@ -36,6 +36,7 @@ def __write_sequence(file, sequence, new_line=True, decimal_digits=const.MAX_FP_ decimal_digits (int): The number of decimal digits to write if the sequence contains floating point values or None to ignore. (Default: const.MAX_FP_DECIMALS_TO_WRITE) The default value prevents very small values from being written in scientific notation, which the game does not understand. """ + # TODO: Convert this into a string builder? for index, value in enumerate(sequence): if index != 0: # Write a space before each value except the first one. @@ -87,24 +88,14 @@ def write_file(properties, filepath, blb_data): # --------- # Collision # --------- - if len(blb_data.collision) == 0: - # TODO: Move to blb_processor. - if properties.blendprop.calculate_collision: - # Write default collision. - # Center of the cuboid is at the middle of the brick. - file.write("1\n\n0 0 0\n") - - # The size of the cuboid is the size of the bounds. - __write_sequence(file, blb_data.brick_size) - else: - # No collision. - file.write("0\n") + if len(blb_data.collision) < 1: + # No collision. + file.write("0\n") else: - # Write defined collisions. - # Write the number of collision cuboids. file.write("{}\n".format(str(len(blb_data.collision)))) + # Write the defined collision cuboids. for (center, dimensions) in blb_data.collision: file.write("\n") __write_sequence(file, center) diff --git a/const.py b/const.py index da5b2e4..2801faa 100644 --- a/const.py +++ b/const.py @@ -42,6 +42,8 @@ # Blockland does not accept bricks that are wide/deeper than 64 bricks or taller than 256 plates. MAX_BRICK_HORIZONTAL_PLATES = 64 MAX_BRICK_VERTICAL_PLATES = 256 +# Blockland supports up to 10 collision cuboids per BLB. +MAX_BRICK_COLLISION_CUBOIDS = 10 class BLBQuadSection(IntEnum): @@ -73,6 +75,7 @@ def as_list(cls): """Returns the names of the members of this enum as a list of uppercase strings.""" return [member.name for member in BrickTexture] + # BLB file strings. BLB_BRICK_TYPE_SPECIAL = "SPECIAL" BLB_SECTION_SEPARATOR = "---------------- {} QUADS ----------------" From e478ccc38c537b1c6aad46a1180252c477ac0e82 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Mon, 13 Nov 2017 21:48:41 +0200 Subject: [PATCH 18/50] Fix broken collision if forward axis was not +Y --- blb_processor.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/blb_processor.py b/blb_processor.py index 01d93db..d8a6f90 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -2722,6 +2722,9 @@ def __format_blb_data(blb_data, forward_axis): Returns: The formatted and rotated BLB data ready for writing. """ + # The exporter internally seems to work with +Y being forward because that makes the most sense to me. + # The standard conversion from +Y forward (exporter) to +X forward (Blockland) is to swizzle X Y Z ("abc") to Y X Z ("bac"). + # Size # Swizzle the values according to the forward axis. @@ -2732,12 +2735,19 @@ def __format_blb_data(blb_data, forward_axis): # Collision for index, (center, dimensions) in enumerate(blb_data.collision): - # Mirror center according to the forward axis. No idea why, but it works. - # Swizzle the values according to the forward axis. - if forward_axis is Axis3D.POS_Y or forward_axis is Axis3D.NEG_Y: + # Swizzle and rotate the values according to the forward axis. + # Collisions are defined by: + # - a center point coordinate in the coordinate space of the brick, + # - and the dimensions of the cuboid in plates. + if forward_axis is Axis3D.POS_Y: + # Still not entirely sure why I need to mirror the X coordinate here. blb_data.collision[index] = (common.swizzle(__mirror(center, forward_axis), "bac"), common.swizzle(dimensions, "bac")) + elif forward_axis is Axis3D.NEG_Y: + blb_data.collision[index] = (common.rotate(center, forward_axis), common.swizzle(dimensions, "bac")) + elif forward_axis is Axis3D.POS_X: + blb_data.collision[index] = (center, dimensions) else: - blb_data.collision[index] = (__mirror(center, forward_axis), dimensions) + blb_data.collision[index] = (common.rotate(center, forward_axis), dimensions) # Quads From bfeb26627075f939fc23e9e70c6ccf42c1015a4d Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Mon, 13 Nov 2017 22:15:36 +0200 Subject: [PATCH 19/50] Fix broken smooth shading --- blb_processor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blb_processor.py b/blb_processor.py index d8a6f90..6f843f0 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -2489,9 +2489,9 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ # Does the user want to round normals? if properties.blendprop.round_normals: # ROUND & CAST - normals = [__to_decimal(__loop_index_to_normal_vector(obj, mesh, vert_idx)) for vert_idx in reversed(loop_vert_idxs)] + normals = [__to_decimal(__loop_index_to_normal_vector(obj, mesh, vert_idx)) for vert_idx in loop_vert_idxs] else: - normals = [__loop_index_to_normal_vector(obj, mesh, vert_idx) for vert_idx in reversed(loop_vert_idxs)] + normals = [__loop_index_to_normal_vector(obj, mesh, vert_idx) for vert_idx in loop_vert_idxs] else: # Flat shading: every vertex in this loop has the same normal. # A tuple cannot be used because the values are changed afterwards when the brick is rotated. From 3ad14bf38ab429bf29a7f655166bbd2e25455082 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Mon, 13 Nov 2017 22:19:04 +0200 Subject: [PATCH 20/50] Fix broken vertex colors --- blb_processor.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/blb_processor.py b/blb_processor.py index 6f843f0..3c21e13 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -2626,8 +2626,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ if len(current_mesh.vertex_colors) != 0: colors = [] - # Blender vertex winding order (CCW) is reversed compared to Blockland. - for index in reversed(loop_vert_idxs): + for index in loop_vert_idxs: # Only use the first color layer. # color_layer.data[index] may contain more than 4 values. loop_color = current_mesh.vertex_colors[0].data[index] From 12d09e9d4b0ab30618a4d58cf094bc38069df4cd Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Tue, 14 Nov 2017 22:24:33 +0200 Subject: [PATCH 21/50] Add Default Collision property, refactor __process_collision_definitions - Refactor __calculate_bounds. - Remove some warning and error messages. - Change logic of Calculate Collision property. - Can no longer export brick with no collision. --- __init__.py | 27 +++-- blb_processor.py | 251 ++++++++++++++++++++++++++-------------------- dev/export-blb.py | 3 +- 3 files changed, 167 insertions(+), 114 deletions(-) diff --git a/__init__.py b/__init__.py index abc5b3c..774f5dd 100644 --- a/__init__.py +++ b/__init__.py @@ -46,6 +46,7 @@ # TODO: Panels in the UI? # TODO: Check that all docstrings and comments are still up to date. # TODO: Quad sorting is per object but BLBs support per-quad sorting: the exporter does not support quad sorting for smoothed objects. +# TODO: Serialize props to the start of the log? class ExportBLB(bpy.types.Operator, ExportHelper): @@ -175,10 +176,18 @@ class ExportBLB(bpy.types.Operator, ExportHelper): # --------- # Collision # --------- - calculate_collision = BoolProperty( - name="Calculate Collision", - description="Calculate cuboid collision for the brick if nothing is defined manually", - default=True, + custom_collision = BoolProperty( + name="Custom Collision", + description="Use custom collision definition objects (if any)", + default=False, + ) + + default_collision = EnumProperty( + items=[("BOUNDS", "Bounds", "Use brick bounds as collision"), + ("AABB", "AABB", "Calculate axis-aligned bounding box collision from visible meshes")], + name="Default Collision", + description="Collision type to use if no custom definitions exist", + default="BOUNDS" ) # -------- @@ -676,8 +685,14 @@ def draw(self, context): # BLB # === - # Properties: Collision - layout.prop(self, "calculate_collision") + # Property: Custom Collision + layout.prop(self, "custom_collision") + + # Property: Default Collision + row = layout.row() + row.label("Default Collision:") + row = layout.row() + row.prop(self, "default_collision", expand=True) # Properties: Coverage layout.prop(self, "calculate_coverage") diff --git a/blb_processor.py b/blb_processor.py index 3c21e13..374fa17 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -447,9 +447,11 @@ class BrickBounds(object): Stores the following data: - Blender object name, - object dimensions, - - object's location in world coordinates, - - minimum vertex world coordinate, - - and maximum vertex world coordinate. + - object center world coordinates, + - minimum vertex world coordinates, + - maximum vertex world coordinates, + - dimensions of the axis-aligned bounding box of visual meshes, + - and world center coordinates of the axis-aligned bounding box of visual meshes. """ def __init__(self): @@ -465,9 +467,14 @@ def __init__(self): self.world_coords_min = [] self.world_coords_max = [] + # TODO: Consider moving to another object? + # The axis-aligned bounding box of visual meshes of this brick. + self.aabb_dimensions = [] + self.aabb_world_center = [] + def __repr__(self): - return "".format( - self.object_name, self.dimensions, self.world_center, self.world_coords_min, self.world_coords_max) + return "".format( + self.object_name, self.dimensions, self.world_center, self.world_coords_min, self.world_coords_max, self.aabb_dimensions, self.aabb_world_center) class BLBData(object): @@ -986,6 +993,23 @@ def __record_bounds_data(properties, blb_data, bounds_data): return blb_data +def __calculate_bounding_box_size(min_coords, max_coords): + """Calculates the XYZ dimensions of a cuboid with the specified minimum and maximum coordinates. + + Args: + min_coords (sequence of numbers): The minimum coordinates as a sequence: [X, Y, Z] + max_coords (sequence of numbers): The maximum coordinates as a sequence: [X, Y, Z] + + Returns: + A sequence with the [X, Y, Z] dimensions of a cuboid as Decimal values. + """ + # Get the dimensions defined by the vectors. + # ROUND & CAST: calculated bounds object dimensions into Decimals for accuracy. + return __to_decimal((max_coords[X] - min_coords[X], + max_coords[Y] - min_coords[Y], + max_coords[Z] - min_coords[Z])) + + def __calculate_bounds(export_scale, min_world_coordinates, max_world_coordinates): """Calculates the brick bounds data from the recorded minimum and maximum vertex world coordinates. @@ -999,23 +1023,20 @@ def __calculate_bounds(export_scale, min_world_coordinates, max_world_coordinate """ bounds_data = BrickBounds() + # ROUND & CAST: The minimum and maximum calculated world coordinates. # USER SCALE: Multiply by user defined scale. - min_coord = __multiply_sequence(export_scale, min_world_coordinates) - max_coord = __multiply_sequence(export_scale, max_world_coordinates) + min_coords = __to_decimal(__multiply_sequence(export_scale, min_world_coordinates)) + max_coords = __to_decimal(__multiply_sequence(export_scale, max_world_coordinates)) - # Get the dimensions defined by the vectors. - # ROUND & CAST: calculated bounds object dimensions into Decimals for accuracy. - bounds_size = __to_decimal((max_coord[X] - min_coord[X], - max_coord[Y] - min_coord[Y], - max_coord[Z] - min_coord[Z])) + bounds_data.world_coords_min = min_coords + bounds_data.world_coords_max = max_coords - bounds_data.dimensions = bounds_size - - # ROUND & CAST: The minimum and maximum calculated world coordinates. - bounds_data.world_coords_min = __to_decimal(min_coord) - bounds_data.world_coords_max = __to_decimal(max_coord) + # USER SCALE: Multiply by user defined scale. + bounds_data.dimensions = __calculate_bounding_box_size(min_coords, max_coords) + bounds_data.world_center = __calculate_center(min_coords, bounds_data.dimensions) - bounds_data.world_center = __calculate_center(bounds_data.world_coords_min, bounds_data.dimensions) + bounds_data.aabb_dimensions = bounds_data.dimensions + bounds_data.aabb_world_center = bounds_data.world_center return bounds_data @@ -1992,17 +2013,17 @@ def __process_grid_definitions(properties, blb_data, bounds_data, definition_obj logger.error("Brick grid definition object '{}' has no volume. Definition ignored.".format(grid_obj.name)) # Log messages for brick grid definitions. - if total_definitions == 0: + if total_definitions < 1: logger.warning("No brick grid definitions found. Automatically generated brick grid may be undesirable.", 1) elif total_definitions == 1: - if processed == 0: + if processed < 1: logger.warning( "{} brick grid definition found but was not processed. Automatically generated brick grid may be undesirable.".format(total_definitions), 1) else: logger.info("Processed {} of {} brick grid definition.".format(processed, total_definitions), 1) else: # Found more than one. - if processed == 0: + if processed < 1: logger.warning( "{} brick grid definitions found but were not processed. Automatically generated brick grid may be undesirable.".format(total_definitions), 1) else: @@ -2021,7 +2042,7 @@ def __process_grid_definitions(properties, blb_data, bounds_data, definition_obj # Initialize the brick grid with the empty symbol with the dimensions of the brick. brick_grid = [[[const.GRID_OUTSIDE for w in range(grid_width)] for h in range(grid_height)] for d in range(grid_depth)] - if total_definitions == 0: + if total_definitions < 1: # Write the default brick grid. for d in range(grid_depth): for h in range(grid_height): @@ -2068,98 +2089,98 @@ def __process_collision_definitions(properties, blb_data, bounds_data, definitio collisions = [] processed = 0 - if properties.blendprop.calculate_collision: - logger.info("Ignoring custom collision definitions, using bounds as collision cuboid.", 1) - # Center of the full brick collision cuboid is at the middle of the brick. - # The size of the cuboid is the size of the bounds. - return [([0, 0, 0], blb_data.brick_size)] + if properties.blendprop.custom_collision: + if len(definition_objects) > const.MAX_BRICK_COLLISION_CUBOIDS: + logger.error("{0} collision cuboids defined but {1} is the maximum. Only the first {1} will be processed.".format( + len(definition_objects), const.MAX_BRICK_COLLISION_CUBOIDS), 1) - if len(definition_objects) > const.MAX_BRICK_COLLISION_CUBOIDS: - logger.error("{0} collision cuboids defined but {1} is the maximum. Only the first {1} will be processed.".format( - len(definition_objects), const.MAX_BRICK_COLLISION_CUBOIDS), 1) + for obj in definition_objects[:const.MAX_BRICK_COLLISION_CUBOIDS]: + vert_count = len(obj.data.vertices) - for obj in definition_objects[:const.MAX_BRICK_COLLISION_CUBOIDS]: - vert_count = len(obj.data.vertices) + # At least two vertices are required for a valid bounding box. + if vert_count < 2: + logger.error("Collision definition object '{}' has less than 2 vertices. Definition ignored.".format(obj.name), 1) + # Skip the rest of the loop and return to the beginning. + continue + elif vert_count > 8: + logger.warning( + "Collision definition object '{}' has more than 8 vertices suggesting a shape other than a cuboid. The bounding box of this mesh will be used.".format(obj.name), 1) + # The mesh is still valid. - # At least two vertices are required for a valid bounding box. - if vert_count < 2: - logger.error("Collision definition object '{}' has less than 2 vertices. Definition ignored.".format(obj.name), 1) - # Skip the rest of the loop and return to the beginning. - continue - elif vert_count > 8: - logger.warning( - "Collision definition object '{}' has more than 8 vertices suggesting a shape other than a cuboid. The bounding box of this mesh will be used.".format(obj.name), 1) - # The mesh is still valid. + # Find the minimum and maximum coordinates for the collision object. + col_min, col_max = __get_world_min_max(obj) - # Find the minimum and maximum coordinates for the collision object. - col_min, col_max = __get_world_min_max(obj) + # ROUND & CAST + # USER SCALE: Multiply by user defined scale. + col_min = __multiply_sequence(properties.scale, __to_decimal(col_min)) + col_max = __multiply_sequence(properties.scale, __to_decimal(col_max)) - # ROUND & CAST - # USER SCALE: Multiply by user defined scale. - col_min = __multiply_sequence(properties.scale, __to_decimal(col_min)) - col_max = __multiply_sequence(properties.scale, __to_decimal(col_max)) - - # Recenter the coordinates to the bounds. (Also rounds the values.) - col_min = __world_to_local(col_min, bounds_data.world_center) - col_max = __world_to_local(col_max, bounds_data.world_center) - - # Technically collision outside brick bounds is not invalid but the collision is also horribly broken and as such is not allowed. - if __all_within_bounds(col_min, bounds_data.dimensions) and __all_within_bounds(col_max, bounds_data.dimensions): - if not __has_volume(col_min, col_max): - logger.error("Collision definition object '{}' has no volume. Definition ignored.".format(obj.name), 1) - # Skip the rest of the loop. - continue + # Recenter the coordinates to the bounds. (Also rounds the values.) + col_min = __world_to_local(col_min, bounds_data.world_center) + col_max = __world_to_local(col_max, bounds_data.world_center) - center = [] - dimensions = [] + # Technically collision outside brick bounds is not invalid but the collision is also horribly broken and as such is not allowed. + if __all_within_bounds(col_min, bounds_data.dimensions) and __all_within_bounds(col_max, bounds_data.dimensions): + if not __has_volume(col_min, col_max): + logger.error("Collision definition object '{}' has no volume. Definition ignored.".format(obj.name), 1) + # Skip the rest of the loop. + continue - # Find the center coordinates and dimensions of the cuboid. - for index, value in enumerate(col_max): - center.append((value + col_min[index]) * const.DECIMAL_HALF) - dimensions.append(value - col_min[index]) + center = [] + dimensions = [] - processed += 1 + # Find the center coordinates and dimensions of the cuboid. + for index, value in enumerate(col_max): + center.append((value + col_min[index]) * const.DECIMAL_HALF) + dimensions.append(value - col_min[index]) - # ROUND & CAST - # Add the center and dimensions to the definition data as a tuple. - # The coordinates and dimensions are in plates. - collisions.append((__sequence_z_to_plates(center, properties.plate_height), __sequence_z_to_plates(dimensions, properties.plate_height))) - else: - if bounds_data.object_name is None: - logger.error("Collision definition object '{}' has vertices outside the calculated brick bounds. Definition ignored.".format(obj.name), 1) - else: - logger.error("Collision definition object '{}' has vertices outside the bounds definition object '{}'. Definition ignored.".format( - obj.name, bounds_data.object_name), 1) - - defcount = len(definition_objects) - # Log messages for collision definitions. - if defcount == 0: - if properties.blendprop.calculate_collision: - logger.warning("No collision definitions found. Calculating full brick collision.", 1) - else: - logger.warning("No collision definitions found. Brick will have no collision.", 1) - elif defcount == 1: - if processed == 0: - if properties.blendprop.calculate_collision: - logger.warning( - "{} collision definition found but was not processed. Calculating full brick collision.".format(defcount), 1) + # ROUND & CAST + # Add the center and dimensions to the definition data as a tuple. + # The center coordinates and dimensions are in plate coordinates. + collisions.append((__sequence_z_to_plates(center, properties.plate_height), __sequence_z_to_plates(dimensions, properties.plate_height))) + + processed += 1 else: - logger.warning( - "{} collision definition found but was not processed. Brick will have no collision.".format(defcount), 1) + if bounds_data.object_name is None: + logger.error("Collision definition object '{}' has vertices outside the calculated brick bounds. Definition ignored.".format(obj.name), 1) + else: + logger.error("Collision definition object '{}' has vertices outside the bounds definition object '{}'. Definition ignored.".format( + obj.name, bounds_data.object_name), 1) + defcount = len(definition_objects) + + # Log messages for collision definitions. + if defcount < 1: + logger.warning("No custom collision definitions found.", 1) + elif defcount == 1: + if processed < 1: + logger.warning("{} collision definition found but was not processed.".format(defcount), 1) + + else: + logger.info("Processed {} of {} collision definition.".format(processed, defcount), 1) else: - logger.info("Processed {} of {} collision definition.".format(processed, defcount), 1) - else: - # Found more than one. - if processed == 0: - if properties.blendprop.calculate_collision: - logger.warning( - "{} collision definitions found but were not processed. Calculating full brick collision.".format(defcount), 1) + # Found more than one. + if processed < 1: + logger.warning("{} collision definitions found but were not processed. Calculating full brick collision.".format(defcount), 1) else: - logger.warning( - "{} collision definitions found but were not processed. Brick will have no collision.".format(defcount), 1) + logger.info("Processed {} of {} collision definitions.".format(processed, defcount), 1) + + if processed < 1: + if properties.blendprop.default_collision == "BOUNDS": + logger.info("Using bounds as the collision cuboid.", 1) + # Center of the full brick collision cuboid is at the middle of the brick. + # The size of the cuboid is the size of the bounds. + collisions.append(([0, 0, 0], blb_data.brick_size)) else: - logger.info("Processed {} of {} collision definitions.".format(processed, defcount), 1) + # properties.blendprop.default_collision == "AABB" + logger.info("Using the axis-aligned bounding box of visual meshes as the collision cuboid.", 1) + collisions.append( + (__world_to_local( + bounds_data.aabb_world_center, + bounds_data.world_center), + __sequence_z_to_plates( + bounds_data.aabb_dimensions, + properties.plate_height))) return collisions @@ -2185,6 +2206,22 @@ def __process_definition_objects(properties, objects): 2. A sequence of mesh objects that will be exported as visible 3D models. Or an error message to be displayed to the user. """ + def calculate_aabb(bounds_data, min_world_coord, max_world_coord): + """Calculates the axis-aligned bounding box data for the specified minimum and maximum world coordinates of visual meshes and stores them to the specified bounds_data object. + + Args: + bounds_data (BrickBounds): A BrickBounds object containing the bounds data. + min_coords (sequence of numbers): The minimum coordinates as a sequence: [X, Y, Z] + max_coords (sequence of numbers): The maximum coordinates as a sequence: [X, Y, Z] + """ + min_coord = __multiply_sequence(properties.scale, __to_decimal(min_world_coord)) + max_coord = __multiply_sequence(properties.scale, __to_decimal(max_world_coord)) + + bounds_data.aabb_dimensions = __calculate_bounding_box_size(min_coord, max_coord) + bounds_data.aabb_world_center = __calculate_center(min_coord, bounds_data.aabb_dimensions) + + print("Calculated AABB. Min:", min_coord, "Max:", max_coord, "Size:", bounds_data.aabb_dimensions, "Center:", bounds_data.aabb_world_center) + blb_data = BLBData() bounds_data = None collision_objects = [] @@ -2269,15 +2306,12 @@ def __process_definition_objects(properties, objects): # Append the current definition object into the appropriate list. brick_grid_objects[index].append(obj) - # Else the object must be a regular mesh that is exported as a 3D model. + # Else the object must be a regular visible mesh that is exported as a 3D model. else: mesh_objects.append(obj) - # If no bounds object has been defined. - if bounds_data is None: - # Record min/max world coordinates for calculating the bounds. - min_world_coordinates, max_world_coordinates = __get_world_min_max(obj, min_world_coordinates, max_world_coordinates) - # Else a bounds object has been defined, recording the min/max coordinates is pointless. + # Record min/max world coordinates for calculating the axis-aligned bounding box. + min_world_coordinates, max_world_coordinates = __get_world_min_max(obj, min_world_coordinates, max_world_coordinates) # No manually created bounds object was found, calculate brick bounds based on the minimum and maximum recorded mesh vertex positions. if bounds_data is None: @@ -2305,6 +2339,9 @@ def __process_definition_objects(properties, objects): blb_data.brick_size[Y], logger.build_countable_message("", bricks, (" brick", " bricks")), logger.build_countable_message("", blb_data.brick_size[Z] - bricks * 3, (" plate", " plates"))), 1) + else: + # Manually defined bounds found, store the axis-aligned bounding box of the visible meshes. + calculate_aabb(bounds_data, min_world_coordinates, max_world_coordinates) # Bounds have been defined, check that brick size is within the limits. if blb_data.brick_size[X] <= const.MAX_BRICK_HORIZONTAL_PLATES and blb_data.brick_size[ @@ -2702,7 +2739,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ count_quads = sum([len(sec) for sec in quads]) - if count_quads == 0: + if count_quads < 1: # RETURN ON ERROR return "No faces to export." else: diff --git a/dev/export-blb.py b/dev/export-blb.py index 859aa35..b6d35a9 100644 --- a/dev/export-blb.py +++ b/dev/export-blb.py @@ -17,7 +17,8 @@ axis_blb_forward=pd['axis_blb_forward'], export_scale=pd['export_scale'], use_modifiers=pd['use_modifiers'], - calculate_collision=pd['calculate_collision'], + custom_collision=pd['custom_collision'], + default_collision=pd['default_collision'], calculate_coverage=pd['calculate_coverage'], coverage_top_calculate=pd['coverage_top_calculate'], coverage_top_hide=pd['coverage_top_hide'], From f3cbe5218ea86514a366001d717224a88f160aca Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Tue, 14 Nov 2017 22:46:50 +0200 Subject: [PATCH 22/50] Add section titles to properties --- __init__.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/__init__.py b/__init__.py index 774f5dd..37acca2 100644 --- a/__init__.py +++ b/__init__.py @@ -597,6 +597,9 @@ def draw(self, context): # ========== # Processing # ========== + row = layout.row() + row.alignment = "CENTER" + row.label("Blender Properties", icon="SCENE_DATA") # Property: Export Count row = layout.row() @@ -684,6 +687,9 @@ def draw(self, context): # === # BLB # === + row = layout.row() + row.alignment = "CENTER" + row.label("BLB Properties", icon="MESH_CUBE") # Property: Custom Collision layout.prop(self, "custom_collision") @@ -861,6 +867,9 @@ def draw_grid_definition_property(symbol, prop_name): # ======= # Writing # ======= + row = layout.row() + row.alignment = "CENTER" + row.label("File Writing", icon="TEXT") # Property: Terse Mode layout.prop(self, "terse_mode") From 0124221a9894f0491b5279e6a8f81f48d16b168b Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Tue, 14 Nov 2017 22:52:21 +0200 Subject: [PATCH 23/50] Reorder properties, improve custom definition tokens properties --- __init__.py | 599 +++++++++++++++++++++++++++------------------------- 1 file changed, 306 insertions(+), 293 deletions(-) diff --git a/__init__.py b/__init__.py index 37acca2..2c7450f 100644 --- a/__init__.py +++ b/__init__.py @@ -63,9 +63,9 @@ class ExportBLB(bpy.types.Operator, ExportHelper): # Properties # ========== - # ========== - # Processing - # ========== + # ================== + # Blender Properties + # ================== # ------------ # Export Count @@ -173,167 +173,6 @@ class ExportBLB(bpy.types.Operator, ExportHelper): default=True, ) - # --------- - # Collision - # --------- - custom_collision = BoolProperty( - name="Custom Collision", - description="Use custom collision definition objects (if any)", - default=False, - ) - - default_collision = EnumProperty( - items=[("BOUNDS", "Bounds", "Use brick bounds as collision"), - ("AABB", "AABB", "Calculate axis-aligned bounding box collision from visible meshes")], - name="Default Collision", - description="Collision type to use if no custom definitions exist", - default="BOUNDS" - ) - - # -------- - # Coverage - # -------- - calculate_coverage = BoolProperty( - name="Coverage", - description="Calculate brick coverage. Coverage relies on the quad section data to be of any use. The coverage system intelligently hides (non-omni) quads on the side of the brick when it is covered by other bricks.", - default=False, - ) - - coverage_top_calculate = BoolProperty( - name="Hide Own Top Faces", - description="Hide the top faces of this brick when the entire top side of this brick is covered", - default=False, - ) - - coverage_top_hide = BoolProperty( - name="Hide Adjacent Top Faces", - description="Hide the bottom faces of the adjacent brick(s) covering the top side of this brick", - default=False, - ) - - coverage_bottom_calculate = BoolProperty( - name="Hide Own Bottom Faces", - description="Hide the bottom faces of this brick when the entire bottom side of this brick is covered", - default=False, - ) - - coverage_bottom_hide = BoolProperty( - name="Hide Adjacent Bottom Faces", - description="Hide the top faces of the adjacent brick(s) covering the bottom side of this brick", - default=False, - ) - - coverage_north_calculate = BoolProperty( - name="Hide Own North Faces", - description="Hide the north faces of this brick when the entire north side of this brick is covered", - default=False, - ) - - coverage_north_hide = BoolProperty( - name="Hide Adjacent North Faces", - description="Hide the adjacent side faces of the adjacent brick(s) covering the north side of this brick", - default=False, - ) - - coverage_east_calculate = BoolProperty( - name="Hide Own East Faces", - description="Hide the east faces of this brick when the entire east side of this brick is covered", - default=False, - ) - - coverage_east_hide = BoolProperty( - name="Hide Adjacent East Faces", - description="Hide the adjacent side faces of the adjacent brick(s) covering the east side of this brick", - default=False, - ) - - coverage_south_calculate = BoolProperty( - name="Hide Own South Faces", - description="Hide the south faces of this brick when the entire south side of this brick is covered", - default=False, - ) - - coverage_south_hide = BoolProperty( - name="Hide Adjacent South Faces", - description="Hide the adjacent side faces of the adjacent brick(s) covering the south side of this brick", - default=False, - ) - - coverage_west_calculate = BoolProperty( - name="Hide Own West Faces", - description="Hide the west faces of this brick when the entire west side of this brick is covered", - default=False, - ) - - coverage_west_hide = BoolProperty( - name="Hide Adjacent West Faces", - description="Hide the adjacent side faces of the adjacent brick(s) covering the west side of this brick", - default=False, - ) - - # ------- - # Sorting - # ------- - auto_sort_quads = BoolProperty( - name="Automatic Quad Sorting", - description="Automatically sorts the quads of the meshes into the 7 sections. Coverage must be enabled for this to be of any use.", - default=True, - ) - - # ------------- - # Use Materials - # ------------- - use_materials = BoolProperty( - name="Use Material Colors", - description="Read quad colors from materials (recommended method, overrides object colors)", - default=False, - ) - - # ----------------- - # Use Vertex Colors - # ----------------- - use_vertex_colors = BoolProperty( - name="Use Vertex Colors", - description="Read quad colors from the first vertex color layer (overrides material colors)", - default=False, - ) - - # ----------------- - # Use Object Colors - # ----------------- - use_object_colors = BoolProperty( - name="Parse Object Colors", - description="Parse quad colors from object names using the definition token (intended as legacy support)", - default=False, - ) - - # ------------- - # Calculate UVs - # ------------- - calculate_uvs = BoolProperty( - name="Calculate UVs", - description="Calculate correct UV coordinates based on the brick texture name specified in the material name", - default=True, - ) - - # --------- - # Store UVs - # --------- - store_uvs = BoolProperty( - name="Store UVs", - description="Write calculated UVs into Blender objects (data in existing generated UV layers will be overwritten)", - default=True, - ) - - # ------------- - # Round Normals - # ------------- - round_normals = BoolProperty( - name="Round Normals", - description="Round vertex normal values to the precision defined below, if disabled normals will be written using up to 16 decimals whenever possible", - default=True, - ) - # ----------- # Definitions # ----------- @@ -471,30 +310,208 @@ class ExportBLB(bpy.types.Operator, ExportHelper): max=4, ) - # Colors - - deftoken_color = StringProperty( - name="Object Color", - description="Token for specifying a color for an object using its name. Token must be followed by 4 values (red green blue alpha) separated with spaces using a comma (,) as decimal separator. Integers 0-255 also supported.", - default="c", + # Colors + + deftoken_color = StringProperty( + name="Object Color", + description="Token for specifying a color for an object using its name. Token must be followed by 4 values (red green blue alpha) separated with spaces using a comma (,) as decimal separator. Integers 0-255 also supported.", + default="c", + ) + + deftoken_color_blank = StringProperty( + name="In-Game Color", + description="No color is written for these faces: in-game spray color is used", + default="blank", + ) + + deftoken_color_add = StringProperty( + name="Additive Color", + description="Blender material/vertex color is added to in-game spray color", + default="cadd", + ) + + deftoken_color_sub = StringProperty( + name="Subtractive Color", + description="Blender material/vertex color is subtracted from in-game spray color", + default="csub", + ) + + # ============== + # BLB Properties + # ============== + + # --------- + # Collision + # --------- + custom_collision = BoolProperty( + name="Custom Collision", + description="Use custom collision definition objects (if any)", + default=False, + ) + + default_collision = EnumProperty( + items=[("BOUNDS", "Bounds", "Use brick bounds as collision"), + ("AABB", "AABB", "Calculate axis-aligned bounding box collision from visible meshes")], + name="Default Collision", + description="Collision type to use if no custom definitions exist", + default="BOUNDS" + ) + + # -------- + # Coverage + # -------- + calculate_coverage = BoolProperty( + name="Coverage", + description="Calculate brick coverage. Coverage relies on quad section data to be of any use. The coverage system intelligently hides non-omni quads on the side of the brick when it is covered by other bricks.", + default=False, + ) + + coverage_top_calculate = BoolProperty( + name="Hide Own Top Faces", + description="Hide the top faces of this brick when the entire top side of this brick is covered", + default=False, + ) + + coverage_top_hide = BoolProperty( + name="Hide Adjacent Top Faces", + description="Hide the bottom faces of the adjacent brick(s) covering the top side of this brick", + default=False, + ) + + coverage_bottom_calculate = BoolProperty( + name="Hide Own Bottom Faces", + description="Hide the bottom faces of this brick when the entire bottom side of this brick is covered", + default=False, + ) + + coverage_bottom_hide = BoolProperty( + name="Hide Adjacent Bottom Faces", + description="Hide the top faces of the adjacent brick(s) covering the bottom side of this brick", + default=False, + ) + + coverage_north_calculate = BoolProperty( + name="Hide Own North Faces", + description="Hide the north faces of this brick when the entire north side of this brick is covered", + default=False, + ) + + coverage_north_hide = BoolProperty( + name="Hide Adjacent North Faces", + description="Hide the adjacent side faces of the adjacent brick(s) covering the north side of this brick", + default=False, + ) + + coverage_east_calculate = BoolProperty( + name="Hide Own East Faces", + description="Hide the east faces of this brick when the entire east side of this brick is covered", + default=False, + ) + + coverage_east_hide = BoolProperty( + name="Hide Adjacent East Faces", + description="Hide the adjacent side faces of the adjacent brick(s) covering the east side of this brick", + default=False, + ) + + coverage_south_calculate = BoolProperty( + name="Hide Own South Faces", + description="Hide the south faces of this brick when the entire south side of this brick is covered", + default=False, + ) + + coverage_south_hide = BoolProperty( + name="Hide Adjacent South Faces", + description="Hide the adjacent side faces of the adjacent brick(s) covering the south side of this brick", + default=False, + ) + + coverage_west_calculate = BoolProperty( + name="Hide Own West Faces", + description="Hide the west faces of this brick when the entire west side of this brick is covered", + default=False, + ) + + coverage_west_hide = BoolProperty( + name="Hide Adjacent West Faces", + description="Hide the adjacent side faces of the adjacent brick(s) covering the west side of this brick", + default=False, + ) + + # ------- + # Sorting + # ------- + auto_sort_quads = BoolProperty( + name="Automatic Quad Sorting", + description="Automatically sorts the quads of the meshes into the 7 sections. Coverage must be enabled for this to be of any use.", + default=True, + ) + + # ------------- + # Use Materials + # ------------- + use_materials = BoolProperty( + name="Use Material Colors", + description="Read quad colors from materials (recommended method, overrides object colors)", + default=False, + ) + + # ----------------- + # Use Vertex Colors + # ----------------- + use_vertex_colors = BoolProperty( + name="Use Vertex Colors", + description="Read quad colors from the first vertex color layer (overrides material colors)", + default=False, + ) + + # ----------------- + # Use Object Colors + # ----------------- + use_object_colors = BoolProperty( + name="Parse Object Colors", + description="Parse quad colors from object names using the definition token (intended as legacy support)", + default=False, + ) + + # ------------- + # Calculate UVs + # ------------- + calculate_uvs = BoolProperty( + name="Calculate UVs", + description="Calculate correct UV coordinates based on the brick texture name specified in the material name", + default=True, ) - deftoken_color_blank = StringProperty( - name="In-Game Color", - description="No color is written for these faces: in-game spray color is used", - default="blank", + # --------- + # Store UVs + # --------- + store_uvs = BoolProperty( + name="Store UVs", + description="Write calculated UVs into Blender objects (data in existing generated UV layers will be overwritten)", + default=True, ) - deftoken_color_add = StringProperty( - name="Additive Color", - description="Blender material/vertex color is added to in-game spray color", - default="cadd", + # ------------- + # Round Normals + # ------------- + round_normals = BoolProperty( + name="Round Normals", + description="Round vertex normal values to the precision defined below, if disabled normals will be written using up to 16 decimals whenever possible", + default=True, ) - deftoken_color_sub = StringProperty( - name="Subtractive Color", - description="Blender material/vertex color is subtracted from in-game spray color", - default="csub", + # --------- + # Precision + # --------- + # Smaller values will increase floating point errors in the exported brick. + # Larger values will decrease the quality of the visuals as vertex positions will become more deformed + # Setting to 0 actually uses the minimum precision of 1e-16 since only 16 decimals are ever written to file. + # Some floats (like UV coordinates) are not rounded. + float_precision = StringProperty( + name="Precision", + description="The precision to round most floating point values (e.g. vertex coordinates) to. Changing this value is discouraged unless you know what you're doing. 16 decimal places supported. Use 0 to disable.", + default="0.000001", ) # ======= @@ -506,7 +523,7 @@ class ExportBLB(bpy.types.Operator, ExportHelper): # ---------- terse_mode = BoolProperty( name="Terse Mode", - description="Exclude optional text from the BLB file making it slightly smaller and harder to read (not recommended, size difference is negligible)", + description="Exclude optional text from the BLB file making it slightly smaller and harder to read (not recommended, file size difference is negligible)", default=False, ) @@ -526,19 +543,6 @@ class ExportBLB(bpy.types.Operator, ExportHelper): default=True, ) - # --------- - # Precision - # --------- - # Smaller values will increase floating point errors in the exported brick. - # Larger values will decrease the quality of the visuals as vertex positions will become more deformed - # Setting to 0 actually uses the minimum precision of 1e-16 since only 16 decimals are ever written to file. - # Some floats (like UV coordinates) are not rounded. - float_precision = StringProperty( - name="Precision", - description="The precision to round most floating point values (e.g. vertex coordinates) to. Changing this value is discouraged unless you know what you're doing. 16 decimal places supported. Use 0 to disable.", - default="0.000001", - ) - # =============== # Export Function # =============== @@ -594,9 +598,9 @@ def draw(self, context): """Draws the UI in the export menu.""" layout = self.layout - # ========== - # Processing - # ========== + # ================== + # Blender Properties + # ================== row = layout.row() row.alignment = "CENTER" row.label("Blender Properties", icon="SCENE_DATA") @@ -663,12 +667,6 @@ def draw(self, context): row.enabled = not multi_export row.prop(self, "export_objects", expand=True) - layout.separator() - - # ================== - # Blender Properties - # ================== - # Property: BLB Forward Axis row = layout.row() row.label("Forward Axis:") @@ -682,6 +680,107 @@ def draw(self, context): # Property: Use Modifiers. layout.prop(self, "use_modifiers") + # Properties: Custom Definition Tokens + layout.prop(self, "custom_definitions") + + if self.custom_definitions: + box = layout.box() + box.label("Definition Tokens", icon="EDIT_VEC") + box.active = self.custom_definitions + + def draw_definition_property(label_text, prop_name): + """A helper function for drawing the definition properties.""" + row = box.row() + + split = row.split(percentage=0.6) + col = split.column() + col.label("{}:".format(label_text)) + + split = split.split() + col = split.column() + col.prop(self, prop_name, "") + + def draw_grid_definition_property(symbol, prop_name): + """A helper function for drawing the definition properties.""" + row = box.row() + + split = row.split(percentage=0.25) + col = split.column() + col.label("{}".format(symbol)) + + split = split.split(percentage=0.7) + col = split.column() + col.prop(self, prop_name, "") + + split = split.split() + col = split.column() + col.prop(self, "{}_priority".format(prop_name), "") + + # This has duplicate data but I don't know how to access the property names defined earlier since self.deftoken_bounds.name doesn't seem to work. + # For some reason self.deftoken_bounds = "deftoken_bounds" instead of an instance of StringProperty. + row = box.row() + row.alignment = "CENTER" + row.label("Definition Objects", icon="OBJECT_DATA") + row = box.row() + row.alignment = "CENTER" + row.label("Token In: Object Name") + + draw_definition_property("Brick Bounds", "deftoken_bounds") + draw_definition_property("Collision Cuboids", "deftoken_collision") + + row = box.row() + row.alignment = "CENTER" + row.label("Brick Grid Definition Objects", icon="GRID") + row = box.row() + row.alignment = "CENTER" + row.label("Token In: Object Name") + + row = box.row() + split = row.split(percentage=0.25) + col = split.column() + col.label("Symbol") + + split = split.split(percentage=0.7) + col = split.column() + col.label("Token") + + split = split.split() + col = split.column() + col.label("Priority") + + draw_grid_definition_property("b", "deftoken_gridb") + draw_grid_definition_property("d", "deftoken_gridd") + draw_grid_definition_property("u", "deftoken_gridu") + draw_grid_definition_property("-", "deftoken_griddash") + draw_grid_definition_property("x", "deftoken_gridx") + + row = box.row() + row.alignment = "CENTER" + row.label("Quad Sorting Tokens", icon="FACESEL") + row = box.row() + row.alignment = "CENTER" + row.label("Token In: Object Name") + + draw_definition_property("Top Quads", "deftoken_quad_sort_top") + draw_definition_property("Bottom Quads", "deftoken_quad_sort_bottom") + draw_definition_property("North Quads", "deftoken_quad_sort_north") + draw_definition_property("East Quads", "deftoken_quad_sort_east") + draw_definition_property("South Quads", "deftoken_quad_sort_south") + draw_definition_property("West Quads", "deftoken_quad_sort_west") + draw_definition_property("Omni Quads", "deftoken_quad_sort_omni") + + row = box.row() + row.alignment = "CENTER" + row.label("Color Tokens", icon="COLOR") + row = box.row() + row.alignment = "CENTER" + row.label("Token In: Object/Material/Vertex Color Layer Name") + + draw_definition_property("Object Colors", "deftoken_color") + draw_definition_property("In-Game Color", "deftoken_color_blank") + draw_definition_property("Additive Color", "deftoken_color_add") + draw_definition_property("Subtractive Color", "deftoken_color_sub") + layout.separator() # === @@ -776,91 +875,8 @@ def draw_coverage_property(label_text): # Property: Round Normals layout.prop(self, "round_normals") - # Properties: Custom Definition Tokens - layout.prop(self, "custom_definitions") - - if self.custom_definitions: - box = layout.box() - box.label("Definition Tokens", icon="EDIT_VEC") - box.active = self.custom_definitions - - def draw_definition_property(label_text, prop_name): - """A helper function for drawing the definition properties.""" - row = box.row() - - split = row.split(percentage=0.6) - col = split.column() - col.label("{}:".format(label_text)) - - split = split.split() - col = split.column() - col.prop(self, prop_name, "") - - def draw_grid_definition_property(symbol, prop_name): - """A helper function for drawing the definition properties.""" - row = box.row() - - split = row.split(percentage=0.25) - col = split.column() - col.label("{}".format(symbol)) - - split = split.split(percentage=0.7) - col = split.column() - col.prop(self, prop_name, "") - - split = split.split() - col = split.column() - col.prop(self, "{}_priority".format(prop_name), "") - - # This has duplicate data but I don't know how to access the property names defined earlier since self.deftoken_bounds.name doesn't seem to work. - # For some reason self.deftoken_bounds = "deftoken_bounds" instead of an instance of StringProperty. - row = box.row() - row.alignment = "CENTER" - row.label("Definition Objects (Object Name)") - draw_definition_property("Brick Bounds", "deftoken_bounds") - draw_definition_property("Collision Cuboids", "deftoken_collision") - - row = box.row() - row.alignment = "CENTER" - row.label("Definition Objects: Brick Grid (Object Name)") - - row = box.row() - split = row.split(percentage=0.25) - col = split.column() - col.label("Symbol") - - split = split.split(percentage=0.7) - col = split.column() - col.label("Token") - - split = split.split() - col = split.column() - col.label("Priority") - - draw_grid_definition_property("b", "deftoken_gridb") - draw_grid_definition_property("d", "deftoken_gridd") - draw_grid_definition_property("u", "deftoken_gridu") - draw_grid_definition_property("-", "deftoken_griddash") - draw_grid_definition_property("x", "deftoken_gridx") - - row = box.row() - row.alignment = "CENTER" - row.label("Quad Sorting (Object Name)") - draw_definition_property("Top Quads", "deftoken_quad_sort_top") - draw_definition_property("Bottom Quads", "deftoken_quad_sort_bottom") - draw_definition_property("North Quads", "deftoken_quad_sort_north") - draw_definition_property("East Quads", "deftoken_quad_sort_east") - draw_definition_property("South Quads", "deftoken_quad_sort_south") - draw_definition_property("West Quads", "deftoken_quad_sort_west") - draw_definition_property("Omni Quads", "deftoken_quad_sort_omni") - - row = box.row() - row.alignment = "CENTER" - row.label("Colors (Object/Material/Vertex Color Name)") - draw_definition_property("Object Colors", "deftoken_color") - draw_definition_property("In-Game Color", "deftoken_color_blank") - draw_definition_property("Additive Color", "deftoken_color_add") - draw_definition_property("Subtractive Color", "deftoken_color_sub") + # Property: Precision + layout.prop(self, "float_precision") layout.separator() @@ -889,9 +905,6 @@ def draw_grid_definition_property(symbol, prop_name): col = split.column() col.prop(self, "write_log_warnings") - # Property: Precision - layout.prop(self, "float_precision") - # ============= # Blender Stuff # ============= From c632ecaa0bf8222e8fe965b3f141e0ce088e123e Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Tue, 14 Nov 2017 22:57:04 +0200 Subject: [PATCH 24/50] Show hidden properties by default --- __init__.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/__init__.py b/__init__.py index 2c7450f..2c1aabb 100644 --- a/__init__.py +++ b/__init__.py @@ -866,11 +866,10 @@ def draw_coverage_property(label_text): col.prop(self, "calculate_uvs") # Property: Store UVs - if self.calculate_uvs: - split = split.split() - split.active = self.calculate_uvs - col = split.column() - col.prop(self, "store_uvs") + split = split.split() + split.active = self.calculate_uvs + col = split.column() + col.prop(self, "store_uvs") # Property: Round Normals layout.prop(self, "round_normals") @@ -898,12 +897,12 @@ def draw_coverage_property(label_text): # Property: Write Log on Warnings # Only show when Write Log is checked. - if self.write_log: - split = split.split() - # The "Only on Warnings" option is grayed out when "Write Log" is not enabled. - split.active = self.write_log - col = split.column() - col.prop(self, "write_log_warnings") + split = split.split() + + # The "Only on Warnings" option is grayed out when "Write Log" is not enabled. + split.active = self.write_log + col = split.column() + col.prop(self, "write_log_warnings") # ============= # Blender Stuff From 09ae8ce143668b9a163f5b8c112b04d4426b6838 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Tue, 14 Nov 2017 23:15:53 +0200 Subject: [PATCH 25/50] Add ellipses to property labels that display additional properties --- __init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/__init__.py b/__init__.py index 2c1aabb..381fc3a 100644 --- a/__init__.py +++ b/__init__.py @@ -681,7 +681,7 @@ def draw(self, context): layout.prop(self, "use_modifiers") # Properties: Custom Definition Tokens - layout.prop(self, "custom_definitions") + layout.prop(self, "custom_definitions", text="Custom Definition Tokens...") if self.custom_definitions: box = layout.box() @@ -800,7 +800,7 @@ def draw_grid_definition_property(symbol, prop_name): row.prop(self, "default_collision", expand=True) # Properties: Coverage - layout.prop(self, "calculate_coverage") + layout.prop(self, "calculate_coverage", text="Calculate Coverage...") if self.calculate_coverage: box = layout.box() From 5b602a4f9cb178369d04d1171882ed078ae0a5fe Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Tue, 14 Nov 2017 23:25:54 +0200 Subject: [PATCH 26/50] Correctly dynamically disable UI items and properties in export panel --- __init__.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/__init__.py b/__init__.py index 381fc3a..d420417 100644 --- a/__init__.py +++ b/__init__.py @@ -616,30 +616,30 @@ def draw(self, context): # When doing multi-brick export, swap the brick name and objects properties and add in the brick definition property. if multi_export: - brickgroups = self.brick_definition == "GROUPS" + bricks_in_groups = self.brick_definition == "GROUPS" # Property: Brick Name Multiple row = layout.row() - row.active = multi_export + row.enabled = multi_export row.label("Brick Names from:") row = layout.row() # Disable selecting values when bricks are in layers. - row.active = multi_export and brickgroups + row.enabled = multi_export and bricks_in_groups row.prop(self, "brick_name_source_multi", expand=True) - if not brickgroups: + if not bricks_in_groups: # If bricks are defined by layers, the brick names must come from bounds objects. # Otherwise you need to put all objects in every layer in their own group to define the name which defeats the purpose. self.brick_name_source_multi = "BOUNDS" # Property: Brick Definition row = layout.row() - row.active = multi_export + row.enabled = multi_export row.label("Bricks Defined by:") row = layout.row() - row.active = multi_export + row.enabled = multi_export row.prop(self, "brick_definition", expand=True) # Property: Export Objects Multi @@ -652,11 +652,11 @@ def draw(self, context): else: # Property: Brick Name row = layout.row() - row.active = not multi_export + row.enabled = not multi_export row.label("Brick Name From:") row = layout.row() - row.active = not multi_export + row.enabled = not multi_export row.prop(self, "brick_name_source", expand=True) # Property: Export Objects @@ -686,7 +686,7 @@ def draw(self, context): if self.custom_definitions: box = layout.box() box.label("Definition Tokens", icon="EDIT_VEC") - box.active = self.custom_definitions + box.enabled = self.custom_definitions def draw_definition_property(label_text, prop_name): """A helper function for drawing the definition properties.""" @@ -805,7 +805,7 @@ def draw_grid_definition_property(symbol, prop_name): if self.calculate_coverage: box = layout.box() box.label("Coverage Options", icon="GROUP") - box.active = self.calculate_coverage + box.enabled = self.calculate_coverage def draw_coverage_property(label_text): """A helper function for drawing the coverage properties.""" @@ -867,7 +867,11 @@ def draw_coverage_property(label_text): # Property: Store UVs split = split.split() - split.active = self.calculate_uvs + split.enabled = self.calculate_uvs + + if not self.calculate_uvs: + self.store_uvs = False + col = split.column() col.prop(self, "store_uvs") @@ -900,7 +904,11 @@ def draw_coverage_property(label_text): split = split.split() # The "Only on Warnings" option is grayed out when "Write Log" is not enabled. - split.active = self.write_log + split.enabled = self.write_log + + if not self.write_log: + self.write_log_warnings = False + col = split.column() col.prop(self, "write_log_warnings") From bb0a2efc720d7453fd40381465ef2736b8da0d51 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 11:30:29 +0200 Subject: [PATCH 27/50] Remove todo: using an enum for the symbols is unnecessarily unwieldy --- const.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/const.py b/const.py index 2801faa..c23816c 100644 --- a/const.py +++ b/const.py @@ -90,8 +90,6 @@ def as_list(cls): # The maximum area a brick's side can cover is 64 * 256 = 16384 plates. DEFAULT_COVERAGE = 99999 -# TODO: Refactor to use enum/dictionary for brick symbols. - # Brick grid symbols. GRID_INSIDE = "x" # Disallow building inside brick. GRID_OUTSIDE = "-" # Allow building in empty space. From 8cfd2292a7199317c88f2648eb92f840c342fb24 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 11:31:38 +0200 Subject: [PATCH 28/50] Fix invalid Decimal operation when calculating AABB and no meshes exist --- blb_processor.py | 19 ++++++++++--------- common.py | 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/blb_processor.py b/blb_processor.py index 374fa17..d0afb3c 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -469,8 +469,8 @@ def __init__(self): # TODO: Consider moving to another object? # The axis-aligned bounding box of visual meshes of this brick. - self.aabb_dimensions = [] - self.aabb_world_center = [] + self.aabb_dimensions = None + self.aabb_world_center = None def __repr__(self): return "".format( @@ -2166,6 +2166,8 @@ def __process_collision_definitions(properties, blb_data, bounds_data, definitio logger.info("Processed {} of {} collision definitions.".format(processed, defcount), 1) if processed < 1: + # No custom collision definitions. + if properties.blendprop.default_collision == "BOUNDS": logger.info("Using bounds as the collision cuboid.", 1) # Center of the full brick collision cuboid is at the middle of the brick. @@ -2178,9 +2180,9 @@ def __process_collision_definitions(properties, blb_data, bounds_data, definitio (__world_to_local( bounds_data.aabb_world_center, bounds_data.world_center), - __sequence_z_to_plates( - bounds_data.aabb_dimensions, - properties.plate_height))) + __sequence_z_to_plates( + bounds_data.aabb_dimensions, + properties.plate_height))) return collisions @@ -2219,8 +2221,7 @@ def calculate_aabb(bounds_data, min_world_coord, max_world_coord): bounds_data.aabb_dimensions = __calculate_bounding_box_size(min_coord, max_coord) bounds_data.aabb_world_center = __calculate_center(min_coord, bounds_data.aabb_dimensions) - - print("Calculated AABB. Min:", min_coord, "Max:", max_coord, "Size:", bounds_data.aabb_dimensions, "Center:", bounds_data.aabb_world_center) + # print("Calculated AABB. Min:", min_coord, "Max:", max_coord, "Size:", bounds_data.aabb_dimensions, "Center:", bounds_data.aabb_world_center) blb_data = BLBData() bounds_data = None @@ -2339,8 +2340,8 @@ def calculate_aabb(bounds_data, min_world_coord, max_world_coord): blb_data.brick_size[Y], logger.build_countable_message("", bricks, (" brick", " bricks")), logger.build_countable_message("", blb_data.brick_size[Z] - bricks * 3, (" plate", " plates"))), 1) - else: - # Manually defined bounds found, store the axis-aligned bounding box of the visible meshes. + elif len(mesh_objects) > 0: + # Manually defined bounds found, store the axis-aligned bounding box of the visible meshes, provided there are any. calculate_aabb(bounds_data, min_world_coordinates, max_world_coordinates) # Bounds have been defined, check that brick size is within the limits. diff --git a/common.py b/common.py index de63d3a..4a118d2 100644 --- a/common.py +++ b/common.py @@ -30,8 +30,8 @@ def swizzle(sequence, order): Args: sequence (sequence): A sequence of objects. - order (sequence or string): The new order of the sequence as string or a sequence of lower case Latin letters. - Sequence indices are represented using lower case letters a-z of the Latin alphabet. + order (sequence or string): The new order of the sequence as string or a sequence of lowercase Latin letters. + Sequence indices are represented using lowercase letters a-z of the Latin alphabet. I.e. "a" signifies the index 0 and "z" stands for index 25. Duplicating elements is possible by specifying the the same letter multiple times. Returns: From f48758d2f0d5056b9f258e2fef806895900a13c6 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 17:20:22 +0200 Subject: [PATCH 29/50] Demote warn about collision definitions having more than 8 verts to info --- README.md | 22 ---------------------- blb_processor.py | 6 ++++-- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 87e5c36..866329c 100644 --- a/README.md +++ b/README.md @@ -655,28 +655,6 @@ It is recommended to manually adjust the brick until no warning messages are pre
    MessageMultiple bounds definitions found. 'object name' definition ignored.Bounds already defined by 'object name', bounds definition 'object name' ignored.
    CauseCreate valid brick grid definitions for the model.
    - - - - - - - - - - - - - - - - - - - - - -
    MessageCollision definition object 'object name' has more than 8 vertices suggesting a shape other than a cuboid. The bounding box of this mesh will be used.
    CauseA collision definition object contained more than 8 vertices.
    EffectNo effect other this warning message.
    SolutionEnsure that all collision definition objects have 2-8 vertices only.
    NotesThis warning message exists to promote good modeling standards. The exporter uses the axis-aligned bounding box of a collision definition object as the BLB collision cuboid so from a technical standpoint the shape of the mesh is irrelevant. However from a practical standpoint, it does not make sense to use a shape other than a cuboid made from 8 vertices (or merely 2 vertices if you're being minimal) to represent a collision cuboid.
    diff --git a/blb_processor.py b/blb_processor.py index 68ebcca..ce3ee6a 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -2100,8 +2100,10 @@ def __process_collision_definitions(properties, blb_data, bounds_data, definitio # Skip the rest of the loop and return to the beginning. continue elif vert_count > 8: - logger.warning( - "Collision definition object '{}' has more than 8 vertices suggesting a shape other than a cuboid. The bounding box of this mesh will be used.".format(obj.name), 1) + logger.info( + "Collision definition object '{}' has more than 8 vertices suggesting a shape other than a cuboid. The bounding box of this mesh will be used.".format( + obj.name), + 1) # The mesh is still valid. # Find the minimum and maximum coordinates for the collision object. From 3bbdb0ce8a1c933b8c0a0dcfc862935c8516d105 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 17:30:30 +0200 Subject: [PATCH 30/50] Demote warning about no custom collision definitions to info --- README.md | 25 ++----------------------- blb_processor.py | 5 ++--- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 866329c..55a0b97 100644 --- a/README.md +++ b/README.md @@ -658,28 +658,7 @@ It is recommended to manually adjust the brick until no warning messages are pre
    Message
    - - - - - - - - - - - - - - -
    MessageNo collision definitions found. Brick will have no collision.
    CauseNo collision definition objects were found and the Calculate Collision export property was disabled.
    EffectThe brick will have no collision data and it cannot be interacted with in game in any way.
    Solutions
      -
    1. Manually define collision objects.
    2. -
    3. Enable the Calculate Collision export property.
    4. -
    - - - - + @@ -687,7 +666,7 @@ It is recommended to manually adjust the brick until no warning messages are pre - + diff --git a/blb_processor.py b/blb_processor.py index ce3ee6a..e7e764f 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -2149,9 +2149,8 @@ def __process_collision_definitions(properties, blb_data, bounds_data, definitio defcount = len(definition_objects) # Log messages for collision definitions. - # FIXME: Skip collision processing if calculating collision! if defcount < 1: - logger.warning("No custom collision definitions found.", 1) + logger.info("No custom collision definitions found.", 1) elif defcount == 1: if processed < 1: logger.warning("{} collision definition found but was not processed.".format(defcount), 1) @@ -2161,7 +2160,7 @@ def __process_collision_definitions(properties, blb_data, bounds_data, definitio else: # Found more than one. if processed < 1: - logger.warning("{} collision definitions found but were not processed. Calculating full brick collision.".format(defcount), 1) + logger.warning("{} collision definitions found but were not processed.".format(defcount), 1) else: logger.info("Processed {} of {} collision definitions.".format(processed, defcount), 1) From 86a64dd4cf53a1ac8f4570106382a3347b70ce72 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 17:46:07 +0200 Subject: [PATCH 31/50] Add codes to error/warn/fatal messages, tweak logger to support codes --- README.md | 180 ++++++++++++++++++++++++++++++++++++++++++----- __init__.py | 10 +-- blb_processor.py | 107 +++++++++++++++------------- export_blb.py | 8 ++- logger.py | 36 +++++++--- 5 files changed, 258 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index 55a0b97..8f70547 100644 --- a/README.md +++ b/README.md @@ -545,6 +545,10 @@ Text in `code tags` describes a variable alphanumeric value, commonly the name o Warning log messages can be ignored as the issues are automatically corrected, but the resulting brick may not behave or look as excepted. It is recommended to manually adjust the brick until no warning messages are present in the output log.
    Message# collision definition(s) found but was/were not processed. Brick will have no collision.# collision definition(s) found but was/were not processed.
    Cause
    EffectThe brick will have no collision data and it cannot be interacted with in game in any way.The fallback collision will be used.
    Solutions
    + + + + @@ -566,6 +570,10 @@ It is recommended to manually adjust the brick until no warning messages are pre
    CodeIOBLBW000
    Message Calculated bounds have a non-integer size # # #, rounding up.
    + + + + @@ -584,6 +592,10 @@ It is recommended to manually adjust the brick until no warning messages are pre
    CodeIOBLBW001
    Message Defined bounds have a non-integer size # # #, rounding to a precision of #.
    + + + + @@ -602,6 +614,10 @@ It is recommended to manually adjust the brick until no warning messages are pre
    CodeIOBLBW002
    Message Brick name was supposed to be in the bounds definition object but no such object exists, file name used instead.
    + + + + @@ -620,6 +636,10 @@ It is recommended to manually adjust the brick until no warning messages are pre
    CodeIOBLBW003
    Message Brick name was supposed to be in the bounds definition object but no name (separated with a space) was found after the definition token, file name used instead.
    + + + + @@ -638,6 +658,10 @@ It is recommended to manually adjust the brick until no warning messages are pre
    CodeIOBLBW004
    Message No brick grid definitions found. Full cuboid brick grid may be undesirable.
    + + + + @@ -656,6 +680,10 @@ It is recommended to manually adjust the brick until no warning messages are pre
    CodeIOBLBW005
    Message # brick grid definition(s) found but was/were not processed. Full cuboid brick grid may be undesirable.
    + + + + @@ -677,6 +705,10 @@ It is recommended to manually adjust the brick until no warning messages are pre
    CodeIOBLBW006
    Message # collision definition(s) found but was/were not processed.
    + + + + @@ -695,6 +727,10 @@ It is recommended to manually adjust the brick until no warning messages are pre
    CodeIOBLBW007
    Message No brick bounds definition found. Calculated brick size may be undesirable.
    + + + + @@ -713,6 +749,10 @@ It is recommended to manually adjust the brick until no warning messages are pre
    CodeIOBLBW008
    Message Object 'object name' has # vertex color layers, only using the first.
    + + + + @@ -731,6 +771,10 @@ It is recommended to manually adjust the brick until no warning messages are pre
    CodeIOBLBW009
    Message Face has UV coordinates but no brick texture was set in the material name, using SIDE by default.
    + + + + @@ -749,6 +793,10 @@ It is recommended to manually adjust the brick until no warning messages are pre
    CodeIOBLBW010
    Message No alpha value set in vertex color layer name, using 1.0.
    + + + + @@ -772,6 +820,10 @@ It is recommended to manually adjust the brick until no warning messages are pre
    CodeIOBLBW011
    Message # triangles converted to quads.
    + + + + @@ -802,23 +854,9 @@ It is recommended to manually adjust the brick until no error messages are prese Fatal errors always lead to the program execution stopping.
    CodeIOBLBW012
    Message # n-gons skipped.
    - - - - - - - - - - - - - - + + -
    MessageTwo or more brick grid definitions had the same priority.
    CauseTwo or more user defined brick grid definition tokens had the same priority number.
    ReasonThe user-intended priority order of the tokens cannot be automatically determined.
    SolutionEnsure that all custom brick grid definition tokens have a unique priority number.CodeIOBLBF000
    - @@ -861,6 +899,10 @@ Fatal errors always lead to the program execution stopping.
    Message When exporting multiple bricks in separate layers, a bounds definition object must exist in every layer. It is also used to provide a name for the brick.
    + + + + @@ -903,6 +945,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBF001
    Message When exporting multiple bricks in separate layers, the brick name must be after the bounds definition token (separated with a space) in the bounds definition object name.
    + + + + @@ -921,6 +967,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBF002
    Message Unable to store UV coordinates in object 'object name' while it is in edit mode.
    + + + + @@ -939,6 +989,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBF003
    Message Brick has no volume, brick could not be rendered in-game.
    + + + + @@ -957,6 +1011,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBF004
    Message Brick size (#x#x#) exceeds the maximum brick size of 64 wide 64 deep and 256 plates tall.
    + + + + @@ -975,6 +1033,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBF005
    Message No faces to export.
    + + + + @@ -1102,9 +1164,35 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBF006
    Message No objects to export.
    + + + + + + + + + + + + + + + + + + + + + +
    CodeIOBLBF007
    MessageTwo or more brick grid definitions had the same priority.
    CauseTwo or more user defined brick grid definition tokens had the same priority number.
    ReasonThe user-intended priority order of the tokens cannot be automatically determined.
    SolutionEnsure that all custom brick grid definition tokens have a unique priority number.
    #### Non-Fatal Errors #### + + + + @@ -1130,6 +1218,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE000
    Message Brick grid definition object 'object name' has vertices outside the calculated brick bounds. Definition ignored.
    + + + + @@ -1155,6 +1247,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE001
    Message Brick grid definition object 'object name' has vertices outside the bounds definition object 'object name'. Definition ignored.
    + + + + @@ -1177,6 +1273,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE002
    Message Brick grid definition object 'object name' has no volume. Definition ignored.
    + + + + @@ -1199,6 +1299,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE003
    Message # collision cuboids defined but 10 is the maximum, only using the first 10.
    + + + + @@ -1221,6 +1325,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE004
    Message Collision definition object 'object name' has less than 2 vertices. Definition ignored.
    + + + + @@ -1243,6 +1351,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE005
    Message Collision definition object 'object name' has no volume. Definition ignored.
    + + + + @@ -1268,6 +1380,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE006
    Message Collision definition object 'object name' has vertices outside the calculated brick bounds. Definition ignored.
    + + + + @@ -1293,6 +1409,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE007
    Message Collision definition object 'object name' has vertices outside the bounds definition object 'object name'. Definition ignored.
    + + + + @@ -1315,6 +1435,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE008
    Message Object 'object name' cannot be used to define bounds, must be a mesh.
    + + + + @@ -1337,6 +1461,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE009
    Message Object 'object name' cannot be used to define brick grid, must be a mesh.
    + + + + @@ -1359,6 +1487,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE010
    Message Object 'object name' cannot be used to define collision, must be a mesh.
    + + + + @@ -1381,6 +1513,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE011
    Message Bounds already defined by 'object name', bounds definition 'object name' ignored.
    + + + + @@ -1403,6 +1539,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE012
    Message Multiple brick grid definitions in object 'object name', only the first one is used.
    + + + + @@ -1425,6 +1565,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE013
    Message More than 4 color values defined for object 'object name', only the first 4 values (RGBA) are used.
    + + + + @@ -1447,6 +1591,10 @@ Fatal errors always lead to the program execution stopping.
    CodeIOBLBE014
    Message Object 'object name' has # section definitions, only using the first one: section name
    + + + + diff --git a/__init__.py b/__init__.py index 932c47c..ac7a543 100644 --- a/__init__.py +++ b/__init__.py @@ -53,11 +53,11 @@ # TODO: Make the capitalization consistent in the readme. # TODO: Consider reformatting readme to have one sentence per line for nicer diffs. # TODO: Consider refactoring readme for consistent use of mesh, model, and object words. -# TODO: Consider using unique IDs for errors and warnings? [WARNING:IOBLBW0000] and [ERROR:IOBLBE0000]? # TODO: Clarify brick grid and brick grid placement rules. # TODO: Clarify which errors occur when autogenerating brick grid. # TODO: Calculate Bounds property. + class ExportBLB(bpy.types.Operator, ExportHelper): """Export Blockland brick data.""" bl_idname = "export_scene.blb" @@ -247,7 +247,7 @@ class ExportBLB(bpy.types.Operator, ExportHelper): default="qo", ) - # Brick Grid + # Brick Grid deftoken_gridx = StringProperty( name="Brick Grid x", @@ -319,7 +319,7 @@ class ExportBLB(bpy.types.Operator, ExportHelper): max=4, ) - # Colors + # Colors deftoken_color = StringProperty( name="Object Color", @@ -366,7 +366,7 @@ class ExportBLB(bpy.types.Operator, ExportHelper): default="BOUNDS" ) - # -------- + # -------- # Coverage # -------- calculate_coverage = BoolProperty( @@ -584,7 +584,7 @@ def execute(self, context): if isinstance(message, str): # Log the message in case the user missed it. - logger.error(message) + logger.fatal(message) # Show an error popup in the UI. self.report({"ERROR"}, message) diff --git a/blb_processor.py b/blb_processor.py index e7e764f..8c57e85 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -933,18 +933,18 @@ def __record_bounds_data(properties, blb_data, bounds_data): # Are the dimensions of the bounds object not integers? if not __are_ints(bounds_size): if bounds_data.object_name is None: - logger.warning("Calculated bounds have a non-integer size {} {} {}, rounding up.".format(bounds_size[X], - bounds_size[Y], - bounds_size[Z]), 1) + logger.warning("IOBLBW000", "Calculated bounds have a non-integer size {} {} {}, rounding up.".format(bounds_size[X], + bounds_size[Y], + bounds_size[Z]), 1) # In case height conversion or rounding introduced floating point errors, round up to be on the safe side. for index, value in enumerate(bounds_size): bounds_size[index] = ceil(value) else: - logger.warning("Defined bounds have a non-integer size {} {} {}, rounding to a precision of {}.".format(bounds_size[X], - bounds_size[Y], - bounds_size[Z], - properties.human_error), 1) + logger.warning("IOBLBW001", "Defined bounds have a non-integer size {} {} {}, rounding to a precision of {}.".format(bounds_size[X], + bounds_size[Y], + bounds_size[Z], + properties.human_error), 1) for index, value in enumerate(bounds_size): # Round to the specified error amount. @@ -956,10 +956,10 @@ def __record_bounds_data(properties, blb_data, bounds_data): if properties.blendprop.export_count == "SINGLE" and properties.blendprop.brick_name_source == "BOUNDS": if bounds_data.object_name is None: - logger.warning("Brick name was supposed to be in the bounds definition object but no such object exists, file name used instead.", 1) + logger.warning("IOBLBW002", "Brick name was supposed to be in the bounds definition object but no such object exists, file name used instead.", 1) else: if len(bounds_data.object_name.split()) == 1: - logger.warning("Brick name was supposed to be in the bounds definition object but no name (separated with a space) was found after the definition token, file name used instead.", + logger.warning("IOBLBW003", "Brick name was supposed to be in the bounds definition object but no name (separated with a space) was found after the definition token, file name used instead.", 1) else: # Brick name follows the bounds definition, must be separated by a space. @@ -971,17 +971,17 @@ def __record_bounds_data(properties, blb_data, bounds_data): if bounds_data.object_name is None: if properties.blendprop.brick_definition == "LAYERS": # RETURN ON ERROR - return "When exporting multiple bricks in separate layers, a bounds definition object must exist in every layer. It is also used to provide a name for the brick." + return "IOBLBF000 When exporting multiple bricks in separate layers, a bounds definition object must exist in every layer. It is also used to provide a name for the brick." else: # TODO: Does this work? Does it actually export multiple bricks or overwrite the first one? - logger.warning("Brick name was supposed to be in the bounds definition object but no such object exists, file name used instead.", 1) + logger.warning("IOBLBW002", "Brick name was supposed to be in the bounds definition object but no such object exists, file name used instead.", 1) else: if len(bounds_data.object_name.split()) == 1: if properties.blendprop.brick_definition == "LAYERS": # RETURN ON ERROR - return "When exporting multiple bricks in separate layers, the brick name must be after the bounds definition token (separated with a space) in the bounds definition object name." + return "IOBLBF001 When exporting multiple bricks in separate layers, the brick name must be after the bounds definition token (separated with a space) in the bounds definition object name." else: - logger.warning("Brick name was supposed to be in the bounds definition object but no name (separated with a space) was found after the definition token, file name used instead.", + logger.warning("IOBLBW003", "Brick name was supposed to be in the bounds definition object but no name (separated with a space) was found after the definition token, file name used instead.", 1) else: # Brick name follows the bounds definition, must be separated by a space. @@ -1947,7 +1947,7 @@ def __store_uvs_in_mesh(poly_index, mesh, uvs, layer_name): Returns: None if UVs were stored successfully or a string containing an error message. """ - error_string = "Unable to store UV coordinates in object '{}' while it is in edit mode.".format(mesh.name) + error_string = "IOBLBF002 Unable to store UV coordinates in object '{}' while it is in edit mode.".format(mesh.name) # If no UV layer exists, create one. if layer_name not in mesh.uv_layers.keys(): @@ -2004,25 +2004,29 @@ def __process_grid_definitions(properties, blb_data, bounds_data, definition_obj processed += 1 except OutOfBoundsException: if bounds_data.object_name is None: - logger.error("Brick grid definition object '{}' has vertices outside the calculated brick bounds. Definition ignored.".format(grid_obj.name), 1) + logger.error( + "IOBLBE000", + "Brick grid definition object '{}' has vertices outside the calculated brick bounds. Definition ignored.".format( + grid_obj.name), + 1) else: - logger.error("Brick grid definition object '{}' has vertices outside the bounds definition object '{}'. Definition ignored.".format( + logger.error("IOBLBE001", "Brick grid definition object '{}' has vertices outside the bounds definition object '{}'. Definition ignored.".format( grid_obj.name, bounds_data.object_name)) except ZeroSizeException: - logger.error("Brick grid definition object '{}' has no volume. Definition ignored.".format(grid_obj.name)) + logger.error("IOBLBE002", "Brick grid definition object '{}' has no volume. Definition ignored.".format(grid_obj.name)) # Log messages for brick grid definitions. if total_definitions < 1: - logger.warning("No brick grid definitions found. Full cuboid brick grid may be undesirable.", 1) + logger.warning("IOBLBW004", "No brick grid definitions found. Full cuboid brick grid may be undesirable.", 1) elif total_definitions == 1: if processed < 1: - logger.warning("{} brick grid definition found but was not processed. Full cuboid brick grid may be undesirable.".format(total_definitions), 1) + logger.warning("IOBLBW005", "{} brick grid definition found but was not processed. Full cuboid brick grid may be undesirable.".format(total_definitions), 1) else: logger.info("Processed {} of {} brick grid definition.".format(processed, total_definitions), 1) else: # Found more than one. if processed < 1: - logger.warning("{} brick grid definitions found but were not processed. Full cuboid brick grid may be undesirable.".format(total_definitions), 1) + logger.warning("IOBLBW005", "{} brick grid definitions found but were not processed. Full cuboid brick grid may be undesirable.".format(total_definitions), 1) else: logger.info("Processed {} of {} brick grid definitions.".format(processed, total_definitions), 1) @@ -2088,7 +2092,7 @@ def __process_collision_definitions(properties, blb_data, bounds_data, definitio if properties.blendprop.custom_collision: if len(definition_objects) > const.MAX_BRICK_COLLISION_CUBOIDS: - logger.error("{0} collision cuboids defined but {1} is the maximum. Only the first {1} will be processed.".format( + logger.error("IOBLBE003", "{0} collision cuboids defined but {1} is the maximum. Only the first {1} will be processed.".format( len(definition_objects), const.MAX_BRICK_COLLISION_CUBOIDS), 1) for obj in definition_objects[:const.MAX_BRICK_COLLISION_CUBOIDS]: @@ -2096,7 +2100,7 @@ def __process_collision_definitions(properties, blb_data, bounds_data, definitio # At least two vertices are required for a valid bounding box. if vert_count < 2: - logger.error("Collision definition object '{}' has less than 2 vertices. Definition ignored.".format(obj.name), 1) + logger.error("IOBLBE004", "Collision definition object '{}' has less than 2 vertices. Definition ignored.".format(obj.name), 1) # Skip the rest of the loop and return to the beginning. continue elif vert_count > 8: @@ -2121,7 +2125,7 @@ def __process_collision_definitions(properties, blb_data, bounds_data, definitio # Technically collision outside brick bounds is not invalid but the collision is also horribly broken and as such is not allowed. if __all_within_bounds(col_min, bounds_data.dimensions) and __all_within_bounds(col_max, bounds_data.dimensions): if not __has_volume(col_min, col_max): - logger.error("Collision definition object '{}' has no volume. Definition ignored.".format(obj.name), 1) + logger.error("IOBLBE005", "Collision definition object '{}' has no volume. Definition ignored.".format(obj.name), 1) # Skip the rest of the loop. continue @@ -2141,9 +2145,13 @@ def __process_collision_definitions(properties, blb_data, bounds_data, definitio processed += 1 else: if bounds_data.object_name is None: - logger.error("Collision definition object '{}' has vertices outside the calculated brick bounds. Definition ignored.".format(obj.name), 1) + logger.error( + "IOBLBE006", + "Collision definition object '{}' has vertices outside the calculated brick bounds. Definition ignored.".format( + obj.name), + 1) else: - logger.error("Collision definition object '{}' has vertices outside the bounds definition object '{}'. Definition ignored.".format( + logger.error("IOBLBE007", "Collision definition object '{}' has vertices outside the bounds definition object '{}'. Definition ignored.".format( obj.name, bounds_data.object_name), 1) defcount = len(definition_objects) @@ -2153,14 +2161,13 @@ def __process_collision_definitions(properties, blb_data, bounds_data, definitio logger.info("No custom collision definitions found.", 1) elif defcount == 1: if processed < 1: - logger.warning("{} collision definition found but was not processed.".format(defcount), 1) - + logger.warning("IOBLBW006", "{} collision definition found but was not processed.".format(defcount), 1) else: logger.info("Processed {} of {} collision definition.".format(processed, defcount), 1) else: # Found more than one. if processed < 1: - logger.warning("{} collision definitions found but were not processed.".format(defcount), 1) + logger.warning("IOBLBW006", "{} collision definitions found but were not processed.".format(defcount), 1) else: logger.info("Processed {} of {} collision definitions.".format(processed, defcount), 1) @@ -2253,11 +2260,11 @@ def calculate_aabb(bounds_data, min_world_coord, max_world_coord): # Ignore non-mesh objects if obj.type != "MESH": if obj_name.upper().startswith(properties.deftokens.bounds): - logger.error("Object '{}' cannot be used to define bounds, must be a mesh.".format(obj_name), 1) + logger.error("IOBLBE008", "Object '{}' cannot be used to define bounds, must be a mesh.".format(obj_name), 1) elif obj_name.upper().startswith(properties.grid_def_obj_token_priority): - logger.error("Object '{}' cannot be used to define brick grid, must be a mesh.".format(obj_name), 1) + logger.error("IOBLBE009", "Object '{}' cannot be used to define brick grid, must be a mesh.".format(obj_name), 1) elif obj_name.upper().startswith(properties.deftokens.collision): - logger.error("Object '{}' cannot be used to define collision, must be a mesh.".format(obj_name), 1) + logger.error("IOBLBE010", "Object '{}' cannot be used to define collision, must be a mesh.".format(obj_name), 1) # Skip the rest of the if. continue @@ -2286,7 +2293,7 @@ def calculate_aabb(bounds_data, min_world_coord, max_world_coord): "", bricks, (" brick", " bricks")), logger.build_countable_message("", blb_data.brick_size[Z] - bricks * 3, (" plate", " plates"))), 1) else: - logger.error("Bounds already defined by '{}', bounds definition '{}' ignored.".format(bounds_data.object_name, obj_name), 1) + logger.error("IOBLBE011", "Bounds already defined by '{}', bounds definition '{}' ignored.".format(bounds_data.object_name, obj_name), 1) continue # Is the current object a collision definition object? @@ -2297,7 +2304,7 @@ def calculate_aabb(bounds_data, min_world_coord, max_world_coord): # Is the current object a brick grid definition object? elif len(object_grid_definitions) > 0: if len(object_grid_definitions) > 1: - logger.error("Multiple brick grid definitions in object '{}', only the first one is used.".format(obj_name), 1) + logger.error("IOBLBE012", "Multiple brick grid definitions in object '{}', only the first one is used.".format(obj_name), 1) # Get the priority index of this grid definition. index = properties.grid_def_obj_token_priority.index(object_grid_definitions[0]) @@ -2315,7 +2322,7 @@ def calculate_aabb(bounds_data, min_world_coord, max_world_coord): # No manually created bounds object was found, calculate brick bounds based on the minimum and maximum recorded mesh vertex positions. if bounds_data is None: - logger.warning("No brick bounds definition found. Calculated brick size may be undesirable.", 1) + logger.warning("IOBLBW007", "No brick bounds definition found. Calculated brick size may be undesirable.", 1) # ROUND & CAST bounds_data = __calculate_bounds(properties.scale, __to_decimal(min_world_coordinates), __to_decimal(max_world_coordinates)) @@ -2351,7 +2358,7 @@ def calculate_aabb(bounds_data, min_world_coord, max_world_coord): # TODO: Actually test this. # TODO: Round 0 brick size up to 1? # RETURN ON ERROR - return "Brick has no volume, brick could not be rendered in-game." + return "IOBLBF003 Brick has no volume, brick could not be rendered in-game." else: # Process brick grid and collision definitions now that a bounds definition exists. blb_data.brick_grid = __process_grid_definitions(properties, blb_data, bounds_data, brick_grid_objects) @@ -2362,11 +2369,11 @@ def calculate_aabb(bounds_data, min_world_coord, max_world_coord): else: # RETURN ON ERROR # The formatter fails miserably if this return is on one line so I've broken it in two. - msg = "Brick size ({0}x{1}x{2}) exceeds the maximum brick size of {3} wide {3} deep and {4} plates tall.".format(blb_data.brick_size[X], - blb_data.brick_size[Y], - blb_data.brick_size[Z], - const.MAX_BRICK_HORIZONTAL_PLATES, - const.MAX_BRICK_VERTICAL_PLATES) + msg = "IOBLBF004 Brick size ({0}x{1}x{2}) exceeds the maximum brick size of {3} wide {3} deep and {4} plates tall.".format(blb_data.brick_size[X], + blb_data.brick_size[Y], + blb_data.brick_size[Z], + const.MAX_BRICK_HORIZONTAL_PLATES, + const.MAX_BRICK_VERTICAL_PLATES) return "{}\nThe exported brick would not be loaded by the game.".format(msg) @@ -2421,7 +2428,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ # Did user define at least 4 numerical values? if size >= 4: if size > 4: - logger.error("More than 4 color values defined for object '{}', only the first 4 values (RGBA) are used.".format(object_name), 2) + logger.error("IOBLBE013", "More than 4 color values defined for object '{}', only the first 4 values (RGBA) are used.".format(object_name), 2) # We're only interested in the first 4 values: R G B A floats = floats[:4] @@ -2434,7 +2441,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ # Vertex color layer message. if len(current_mesh.vertex_colors) > 1: - logger.warning("Object '{}' has {} vertex color layers, only using the first.".format( + logger.warning("IOBLBW008", "Object '{}' has {} vertex color layers, only using the first.".format( object_name, len(current_mesh.vertex_colors)), 2) # =================== @@ -2450,7 +2457,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ if section_count >= 1: section = const.BLBQuadSection(properties.quad_sort_definitions.index(quad_sections[0])) if section_count > 1: - logger.error("Object '{}' has {} section definitions, only using the first one: {}".format( + logger.error("IOBLBE014", "Object '{}' has {} section definitions, only using the first one: {}".format( object_name, section_count, section), 2) # TODO: Do forward axis rotation of section in the format_blb_data function? @@ -2559,7 +2566,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ brick_texture = const.BrickTexture[texnames[0]] if texcount > 1: - logger.error("More than one brick texture name found in material '{}', only using the first one.".format(matname), 2) + logger.error("IOBLBE015", "More than one brick texture name found in material '{}', only using the first one.".format(matname), 2) # else: No material name or a brick texture was not specified. Keep None to skip automatic UV generation. # === @@ -2599,7 +2606,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ if brick_texture is None: # Fall back to SIDE texture if nothing was specified. brick_texture = const.BrickTexture.SIDE - logger.warning("Face has UV coordinates but no brick texture was set in the material name, using SIDE by default.", 2) + logger.warning("IOBLBW009", "Face has UV coordinates but no brick texture was set in the material name, using SIDE by default.", 2) # Do we have UV coordinates for a tri? if len(uvs) == 3: @@ -2692,7 +2699,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ if vertex_color_alpha is None: if name is None: vertex_color_alpha = 1.0 - logger.warning("No alpha value set in vertex color layer name, using 1.0.", 2) + logger.warning("IOBLBW010", "No alpha value set in vertex color layer name, using 1.0.", 2) else: vertex_color_alpha = name logger.info("Vertex color layer alpha set to {}.".format(vertex_color_alpha), 2) @@ -2736,17 +2743,17 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ bpy.data.meshes.remove(mesh) if count_tris > 0: - logger.warning("{} triangles converted to quads.".format(count_tris), 2) + logger.warning("IOBLBW011", "{} triangles converted to quads.".format(count_tris), 2) if count_ngon > 0: - logger.warning("{} n-gons skipped.".format(count_ngon), 2) + logger.warning("IOBLBW012", "{} n-gons skipped.".format(count_ngon), 2) count_quads = sum([len(sec) for sec in quads]) if count_quads < 1: # TODO: Test if an invisible brick works and remove this error. # RETURN ON ERROR - return "No faces to export." + return "IOBLBF005 No faces to export." else: logger.info("Brick quads: {}".format(count_quads), 1) @@ -2862,4 +2869,4 @@ def process_blender_data(context, properties, objects): return __format_blb_data(blb_data, properties.forward_axis) else: # RETURN ON ERROR - return "No objects to export." + return "IOBLBF006 No objects to export." diff --git a/export_blb.py b/export_blb.py index b55060a..f8e3754 100644 --- a/export_blb.py +++ b/export_blb.py @@ -167,7 +167,7 @@ def __build_grid_priority_tuples(cls, properties): tokens[properties.deftoken_gridb_priority] = properties.deftoken_gridb.upper() if None in tokens: - return "Two or more brick grid definitions had the same priority." + return "IOBLBF007 Two or more brick grid definitions had the same priority." else: symbols = [None] * 5 @@ -350,7 +350,8 @@ def export_brick(context, properties, export_dir, export_file, file_name, object if deriv_properties.blendprop.brick_definition == "GROUPS": if len(bpy.data.groups) == 0: # RETURN ON ERROR - return "No groups to export." + # TODO: Add to readme. + return "IOBLBF006 No groups to export." else: # For all groups in the scene. for group in bpy.data.groups: @@ -407,4 +408,5 @@ def export_brick(context, properties, export_dir, export_file, file_name, object if exported == 0: # RETURN ON ERROR - return "Nothing to export in layers." + # TODO: Add to readme. + return "IOBLBF007 Nothing to export in layers." diff --git a/logger.py b/logger.py index 2b2c053..02d95fa 100644 --- a/logger.py +++ b/logger.py @@ -45,17 +45,23 @@ def configure(write_file, write_only_on_warnings): __ON_WARNINGS_ONLY = write_only_on_warnings -def __log(message, is_warning, indents=0): +def __log(log_type, code, message, is_warning, indents=0): """Prints the given message to the console and additionally to a log file if so specified at logger configuration. Args: + log_type (string): Log type label. + code (string): Unique code for the message. message (string): Log message. is_warning (bool): Is the message a warning? indents (int): The number of indents to add in front of the message. (Default: 0) """ global __HAS_WARNINGS - message = "{}{}".format(const.LOG_INDENT * indents, message) + if log_type is None: + message = "{}{}".format(const.LOG_INDENT * indents, message) + else: + message = "{}[{}:{}] {}".format(const.LOG_INDENT * indents, log_type, code, message) + print(message) # If log will be written to a file, append the message to the sequence for writing later. @@ -73,27 +79,39 @@ def info(message, indents=0): message (string): Log message. indents (int): The number of indents to add in front of the message. (Default: 0) """ - __log(message, False, indents) + __log(None, None, message, False, indents) -def warning(message, indents=0): - """Prefixes the message with '[WARNING] ', prints it to the console (and additionally to a log file if so specified at logger configuration), and logs the message as a warning. +def warning(code, message, indents=0): + """Prefixes the message with '[WARNING:] ', prints it to the console (and additionally to a log file if so specified at logger configuration), and logs the message as a warning. Args: + code (string): Unique warning code. message (string): Log message. indents (int): The number of indents to add in front of the message. (Default: 0) """ - __log("[WARNING] " + message, True, indents) + __log("WARNING", code, message, True, indents) -def error(message, indents=0): - """Prefixes the message with '[ERROR] ', prints it to the console (and additionally to a log file if so specified at logger configuration), and logs the message as a warning. +def error(code, message, indents=0): + """Prefixes the message with '[ERROR:] ', prints it to the console (and additionally to a log file if so specified at logger configuration), and logs the message as a warning. Args: + code (string): Unique error code. message (string): Log message. indents (int): The number of indents to add in front of the message. (Default: 0) """ - __log("[ERROR] " + message, True, indents) + __log("ERROR", code, message, True, indents) + + +def fatal(message): + """Prefixes the message with '[FATAL:] ', prints it to the console (and additionally to a log file if so specified at logger configuration), and logs the message as a warning. + + Args: + message (string): The unique code followed by the log message after a space character. + """ + space_pos = message.index(" ") + __log("FATAL", message[:space_pos], message[space_pos + 1:], True, 0) def build_countable_message(message_start, count, alternatives, message_end="", message_zero=None): From e6907e418fc309dc15b752e2040dafc0ce556ac7 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 17:51:09 +0200 Subject: [PATCH 32/50] Change logic of export_objects property, cleanup todos - No longer exporting whole scene if nothing is selected. - Cannot do panels in the export dialog. - There are no special errors when generating brick placement rules. - Already implemented bounds calculation. --- __init__.py | 3 --- export_blb.py | 7 ++----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/__init__.py b/__init__.py index ac7a543..e56d2b6 100644 --- a/__init__.py +++ b/__init__.py @@ -44,7 +44,6 @@ # TODO: Exporting DTS collision. # TODO: Importing BLB files. # TODO: Render brick preview. -# TODO: Panels in the UI? # TODO: Check that all docstrings and comments are still up to date. # TODO: Quad sorting is per object but BLBs support per-quad sorting: the exporter does not support quad sorting for smoothed objects. # TODO: Serialize props to the start of the log? @@ -54,8 +53,6 @@ # TODO: Consider reformatting readme to have one sentence per line for nicer diffs. # TODO: Consider refactoring readme for consistent use of mesh, model, and object words. # TODO: Clarify brick grid and brick grid placement rules. -# TODO: Clarify which errors occur when autogenerating brick grid. -# TODO: Calculate Bounds property. class ExportBLB(bpy.types.Operator, ExportHelper): diff --git a/export_blb.py b/export_blb.py index f8e3754..796fceb 100644 --- a/export_blb.py +++ b/export_blb.py @@ -270,11 +270,8 @@ def get_objects(context, properties): logger.info(logger.build_countable_message("Found ", len(objects), (" object.", " objects."), "", "No objects in visible layers."), 1) - # If user wants to export the whole scene. - # Or if user wanted to export only the selected objects or layers but they contained nothing. - # Get all scene objects. - # TODO: Remove len(objects) == 0 condition. - if properties.blendprop.export_objects == "SCENE" or len(objects) == 0: + # Use the whole scene? + if properties.blendprop.export_objects == "SCENE": logger.info("Exporting scene to BLB.") objects = context.scene.objects logger.info(logger.build_countable_message("Found ", len(objects), (" object.", " objects."), "", "Scene has no objects."), 1) From 372c3b944944ab619301d087eb02851a3938f7bf Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 18:09:12 +0200 Subject: [PATCH 33/50] Fix typos in README --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8f70547..acd23a0 100644 --- a/README.md +++ b/README.md @@ -466,7 +466,7 @@ Definition Object | Default Token | Requirements | Maximum Count/Brick | Must Be ------------------|---------------|--------------|--------------------:|:-------------------:|:------------:|:------------------:|:-----------:|------------ Bounds | `bounds` | At least two vertices, must have volume | 1 | N/A | Yes [**(1)**](#definition-objects-fn-1) | Yes | N/A | Defines the dimensions or the size of the brick. Collision | `collision` | At least two vertices, must have volume | 10 | Yes [**(2)**](#definition-objects-fn-2) | Yes | No | Yes | Defines a collision [cuboid](#def-cuboid). See [Defining Collision](#defining-collision) for more info. -Brick Grid | See [Defining Brick Grid](#defining-brick-grid) | At least two vertices, must have volume | Unlimited | Yes | Yes [**(1)**](#definition-objects-fn-1) | Yes | Yes [**(4)**](#definition-objects-fn-4) | Defines a volume in the brick grid to fill with a specific brick grid symbol. +Brick Grid | See [Defining Brick Grid](#defining-brick-grid) | At least two vertices, must have volume | Unlimited | Yes | Yes [**(1)**](#definition-objects-fn-1) | Yes | Yes [**(3)**](#definition-objects-fn-4) | Defines a volume in the brick grid to fill with a specific brick grid symbol. **(1)** It is highly recommended to use [axis-aligned cuboids](#def-aac) to define bounds and the [brick grid](#def-brick-grid). However, if you insist on defining the size of your brick in monkey heads, you can. @@ -475,7 +475,7 @@ Only the [axis-aligned bounding box](#def-aabb) of the bounds and brick grid obj **(2)** Collision boxes outside brick bounds are technically not invalid and the brick will function in-game. This behavior is not allowed by the exporter because collision outside brick bounds is horribly broken as it was never intended work in that manner. -**(4)** See [Defining Brick Grid](#defining-brick-grid) for the specific rules about overlapping brick grid definitions. +**(3)** See [Defining Brick Grid](#defining-brick-grid) for the specific rules about overlapping brick grid definitions. ### Defining Collision ### Blockland bricks only supports [AABB collision](https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box). @@ -789,7 +789,7 @@ It is recommended to manually adjust the brick until no warning messages are pre - +
    CodeIOBLBE015
    Message More than one brick texture name found in material 'material name', only using the first one.
    SolutionDefine the alpha value in the verter color layer name.Define the alpha value in the vertex color layer name.
    @@ -844,7 +844,7 @@ It is recommended to manually adjust the brick until no warning messages are pre ### Errors ### Errors are separated into two categories: fatal and non-fatal errors. -* Fatal errors cause the program execution to stop as there is insuffient or incorrect input data to process into a Blockland brick. +* Fatal errors cause the program execution to stop as there is insufficient or incorrect input data to process into a Blockland brick. * Non-fatal errors occur when the exporter attempts to do something (due to invalid input data) that would have caused an error when loading or using the exported brick in game. Alternatively the user has attempted to do something that is explicitly not allowed by the exporter or would lead to a mathematical error. From 6e877984ef4277317ee5d50d12f9241f64e056cd Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 18:14:13 +0200 Subject: [PATCH 34/50] Default Custom Collision property to true for convenience --- __init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index e56d2b6..fb57540 100644 --- a/__init__.py +++ b/__init__.py @@ -352,7 +352,7 @@ class ExportBLB(bpy.types.Operator, ExportHelper): custom_collision = BoolProperty( name="Custom Collision", description="Use custom collision definition objects (if any)", - default=False, + default=True, ) default_collision = EnumProperty( From 0af066b34dd30cdc835958b996ce536ed7def4bb Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 18:15:58 +0200 Subject: [PATCH 35/50] Rename Default Collision to Fallback Collision --- __init__.py | 10 +++++----- blb_processor.py | 3 +-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/__init__.py b/__init__.py index fb57540..a172c84 100644 --- a/__init__.py +++ b/__init__.py @@ -355,10 +355,10 @@ class ExportBLB(bpy.types.Operator, ExportHelper): default=True, ) - default_collision = EnumProperty( + fallback_collision = EnumProperty( items=[("BOUNDS", "Bounds", "Use brick bounds as collision"), ("AABB", "AABB", "Calculate axis-aligned bounding box collision from visible meshes")], - name="Default Collision", + name="Fallback Collision", description="Collision type to use if no custom definitions exist", default="BOUNDS" ) @@ -799,11 +799,11 @@ def draw_grid_definition_property(symbol, prop_name): # Property: Custom Collision layout.prop(self, "custom_collision") - # Property: Default Collision + # Property: Fallback Collision row = layout.row() - row.label("Default Collision:") + row.label("Fallback Collision:") row = layout.row() - row.prop(self, "default_collision", expand=True) + row.prop(self, "fallback_collision", expand=True) # Properties: Coverage layout.prop(self, "calculate_coverage", text="Calculate Coverage...") diff --git a/blb_processor.py b/blb_processor.py index 8c57e85..887dabd 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -2173,8 +2173,7 @@ def __process_collision_definitions(properties, blb_data, bounds_data, definitio if processed < 1: # No custom collision definitions. - - if properties.blendprop.default_collision == "BOUNDS": + if properties.blendprop.fallback_collision == "BOUNDS": logger.info("Using bounds as the collision cuboid.", 1) # Center of the full brick collision cuboid is at the middle of the brick. # The size of the cuboid is the size of the bounds. From f7e2835cf009ce3e3b7f3386e10389e750ecb47b Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 18:17:00 +0200 Subject: [PATCH 36/50] Default Use Material Colors to True to have a default way to use color --- __init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index a172c84..0cc5551 100644 --- a/__init__.py +++ b/__init__.py @@ -459,7 +459,7 @@ class ExportBLB(bpy.types.Operator, ExportHelper): use_materials = BoolProperty( name="Use Material Colors", description="Read quad colors from materials (recommended method, overrides object colors)", - default=False, + default=True, ) # ----------------- From 29903b4f996bf3113e2728e210a3962b57c76565 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 18:51:02 +0200 Subject: [PATCH 37/50] Add missing fatal errors to README --- README.md | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ const.py | 3 ++ export_blb.py | 21 +++++++------ 3 files changed, 98 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index acd23a0..2d2d201 100644 --- a/README.md +++ b/README.md @@ -1186,6 +1186,90 @@ Fatal errors always lead to the program execution stopping.
    Ensure that all custom brick grid definition tokens have a unique priority number.
    + + + + + + + + + + + + + + + + + + + + + +
    CodeIOBLBF008
    MessageNo groups to export in the current scene.
    CauseThe following export properties are set: + + + + + + + + + + + + + + + + + +
    PropertyValue
    Bricks to ExportMultiple
    Bricks Defined by (Multiple Export)Groups
    + And the current scene does not contain any groups with objects in visible layers. +
    ReasonNo data to export, nothing to do.
    SolutionWhen exporting multiple bricks in groups, ensure that there are groups to export.
    + + + + + + + + + + + + + + + + + + + + + +
    CodeIOBLBF009
    MessageNothing to export in layers of the current scene.
    CauseThe following export properties are set: + + + + + + + + + + + + + + + + + +
    PropertyValue
    Bricks to ExportMultiple
    Bricks Defined by (Multiple Export)Layers
    + And the current scene does not contain any objects in visible layers. +
    ReasonNo data to export, nothing to do.
    SolutionWhen exporting multiple bricks in groups, ensure that there are groups to export.
    #### Non-Fatal Errors #### diff --git a/const.py b/const.py index c23816c..cb4aa3a 100644 --- a/const.py +++ b/const.py @@ -97,6 +97,9 @@ def as_list(cls): GRID_DOWN = "d" # Allow placing bricks below this plate. GRID_BOTH = "b" # Allow placing bricks above and below this plate. +# Blender has 20 layers. +BLENDER_MAX_LAYER_IDX = 19 + # Maximum number of decimal places to write to file. MAX_FP_DECIMALS_TO_WRITE = 16 diff --git a/export_blb.py b/export_blb.py index 796fceb..ed57d47 100644 --- a/export_blb.py +++ b/export_blb.py @@ -215,6 +215,7 @@ def __has_object_in_visible_layer(context, objects): for index, layer in enumerate(context.scene.layers): # List's first object is in current layer. # Current layer is visible. + # TODO: Clarify condition. if True is objects[0].layers[index] == layer: # List has at least one object in visible layer. return True @@ -345,10 +346,9 @@ def export_brick(context, properties, export_dir, export_file, file_name, object logger.info("Exporting multiple bricks.") # Bricks in groups. if deriv_properties.blendprop.brick_definition == "GROUPS": - if len(bpy.data.groups) == 0: + if len(bpy.data.groups) < 1: # RETURN ON ERROR - # TODO: Add to readme. - return "IOBLBF006 No groups to export." + return "IOBLBF008 No groups to export in the current scene." else: # For all groups in the scene. for group in bpy.data.groups: @@ -362,7 +362,7 @@ def export_brick(context, properties, export_dir, export_file, file_name, object # Group has at least one object in a visible layer, export group. # Else: Export all groups in the scene, no need to check anything. - # TODO: Is the newline intentional or left from development? + # TODO: Add the same header to all logs, not just the first. logger.info("\nExporting group '{}'.".format(group.name)) # Objects in multiple groups will be exported more than once. @@ -380,30 +380,31 @@ def export_brick(context, properties, export_dir, export_file, file_name, object else: # Bricks in layers. exported = 0 - # Blender has 20 layers, check every one. - for layer_idx in range(0, 19): + # Check all layers in the current scene. + for layer_idx in range(0, const.BLENDER_MAX_LAYER_IDX): # Add to list if object is in the layer. # Objects on multiple layers will be exported more than once. layer_objects = [ob for ob in bpy.context.scene.objects if ob.layers[layer_idx]] if deriv_properties.blendprop.export_objects_multi == "LAYERS": if not __has_object_in_visible_layer(context, layer_objects): - # This group didn't have objects in visible layers. + # This visible layer did not have any objects. # Skip the rest of the loop. continue # Layer has at least one object in a visible layer, export layer objects. - # TODO: Is the newline intentional or left from development? + # TODO: Add the same header to all logs, not just the first. logger.info("\nExporting layer {}.".format(layer_idx + 1)) # Get brick name from bounds. message = export_brick(context, deriv_properties, export_dir, None, file_name, layer_objects) exported += 1 + # TODO: Do not fail if one export fails. # If something went wrong stop export and return the error message. if message is not None: return message - if exported == 0: + if exported < 1: # RETURN ON ERROR # TODO: Add to readme. - return "IOBLBF007 Nothing to export in layers." + return "IOBLBF009 Nothing to export in layers of the current scene." From 0c3faeb0e2c06628bbbaebea4829b8f0fc4f121e Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 19:06:42 +0200 Subject: [PATCH 38/50] Fix fatal error attempting to export empty layers Logic error triggered when: - exporting multiple bricks, - defined by layers, - in the whole scene, - and there was layer with no objects. --- README.md | 2 +- export_blb.py | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 2d2d201..5af0acb 100644 --- a/README.md +++ b/README.md @@ -1235,7 +1235,7 @@ Fatal errors always lead to the program execution stopping. - + diff --git a/export_blb.py b/export_blb.py index ed57d47..d1ada1d 100644 --- a/export_blb.py +++ b/export_blb.py @@ -391,20 +391,20 @@ def export_brick(context, properties, export_dir, export_file, file_name, object # This visible layer did not have any objects. # Skip the rest of the loop. continue - # Layer has at least one object in a visible layer, export layer objects. + # Else: Layer has at least one object in a visible layer, export layer objects. - # TODO: Add the same header to all logs, not just the first. - logger.info("\nExporting layer {}.".format(layer_idx + 1)) - # Get brick name from bounds. - message = export_brick(context, deriv_properties, export_dir, None, file_name, layer_objects) - exported += 1 + if len(layer_objects) > 0: + # TODO: Add the same header to all logs, not just the first. + logger.info("\nExporting layer {}.".format(layer_idx + 1)) + # Get brick name from bounds. + message = export_brick(context, deriv_properties, export_dir, None, file_name, layer_objects) + exported += 1 - # TODO: Do not fail if one export fails. - # If something went wrong stop export and return the error message. - if message is not None: - return message + # TODO: Do not fail if one export fails. + # If something went wrong stop export and return the error message. + if message is not None: + return message if exported < 1: # RETURN ON ERROR - # TODO: Add to readme. - return "IOBLBF009 Nothing to export in layers of the current scene." + return "IOBLBF009 Nothing to export in the visible layers of the current scene." From e9c924a2e0a43a0ad1b79592074f4fd49595e257 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 19:12:58 +0200 Subject: [PATCH 39/50] Fix wrong property name in export-blb --- dev/export-blb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/export-blb.py b/dev/export-blb.py index b6d35a9..801e7eb 100644 --- a/dev/export-blb.py +++ b/dev/export-blb.py @@ -18,7 +18,7 @@ export_scale=pd['export_scale'], use_modifiers=pd['use_modifiers'], custom_collision=pd['custom_collision'], - default_collision=pd['default_collision'], + fallback_collision=pd['fallback_collision'], calculate_coverage=pd['calculate_coverage'], coverage_top_calculate=pd['coverage_top_calculate'], coverage_top_hide=pd['coverage_top_hide'], From 449b97106a8a1bf4028711fc5f817fe76c788ed7 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 19:35:47 +0200 Subject: [PATCH 40/50] Document a missing fatal error --- README.md | 22 ++++++++++++++++++++++ export_blb.py | 4 ++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5af0acb..b36d31c 100644 --- a/README.md +++ b/README.md @@ -1270,6 +1270,28 @@ Fatal errors always lead to the program execution stopping.
    MessageNothing to export in layers of the current scene.Nothing to export in the visible layers of the current scene.
    CauseWhen exporting multiple bricks in groups, ensure that there are groups to export.
    + + + + + + + + + + + + + + + + + + + + + +
    CodeIOBLBF010
    MessageInvalid floating point value given for floating point precision property.
    CauseThe string specified in the Precision property was not a numerical value.
    ReasonThe numerical values that are rounded to combat floating point inaccuracies cannot be rounded unless the floating point precision is set.
    SolutionWrite a numerical value as the Precision property.
    #### Non-Fatal Errors #### diff --git a/export_blb.py b/export_blb.py index d1ada1d..e509231 100644 --- a/export_blb.py +++ b/export_blb.py @@ -133,8 +133,7 @@ def __init__(self, properties): prec = properties.float_precision if common.to_float_or_none(prec) is None: - # FIXME: Concatenate message. - self.error_message = "Invalid floating point precision value given." + self.error_message = "IOBLBF010 Invalid floating point value given for floating point precision property." else: if prec == "0": logger.info("Setting floating point precision to minimum.") @@ -335,6 +334,7 @@ def export_brick(context, properties, export_dir, export_file, file_name, object deriv_properties = DerivativeProperties(properties) if deriv_properties.error_message is not None: + # RETURN ON ERROR return deriv_properties.error_message else: # Determine how many bricks to export from this file and the objects in every brick. From b74f58a2e9ec0d4ee30f36137fe49faf59761968 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 19:38:44 +0200 Subject: [PATCH 41/50] Fix exception when export scale is not 100% --- blb_processor.py | 8 ++++---- const.py | 7 +++++++ export_blb.py | 17 +++++++---------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/blb_processor.py b/blb_processor.py index 887dabd..cb3d0f9 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -112,7 +112,7 @@ def make_decimal(value, quantize=None): raise ValueError("__to_decimal(value) quantize must be a string or a Decimal, was '{}'.".format(type(quantize))) # Calculate the fraction that will be used to do the rounding to an arbitrary number. - fraction = Decimal("1.0") / quantize + fraction = const.DECIMAL_ONE / quantize # If the value is not a Decimal, convert the value to string and create a Decimal out of the formatted string. # Using strings is the only way to create Decimals accurately from numbers as the Decimal representation of @@ -126,7 +126,7 @@ def make_decimal(value, quantize=None): # Divide with the Decimal fraction. # Quantize the result to get the correct number of decimal digits. # Result: value is rounded to the nearest value of quantize (half rounded up) - return ((value * fraction).quantize(Decimal("1")) / fraction).quantize(quantize) + return ((value * fraction).quantize(const.DECIMAL_ONE) / fraction).quantize(quantize) result = [] @@ -944,11 +944,11 @@ def __record_bounds_data(properties, blb_data, bounds_data): logger.warning("IOBLBW001", "Defined bounds have a non-integer size {} {} {}, rounding to a precision of {}.".format(bounds_size[X], bounds_size[Y], bounds_size[Z], - properties.human_error), 1) + properties.human_brick_grid_error), 1) for index, value in enumerate(bounds_size): # Round to the specified error amount. - bounds_size[index] = round(properties.human_error * round(value / properties.human_error)) + bounds_size[index] = round(properties.human_brick_grid_error * round(value / properties.human_brick_grid_error)) # FIXME: Force to integer size? # The value type must be int because you can't have partial plates. Returns a list. diff --git a/const.py b/const.py index cb4aa3a..21d0146 100644 --- a/const.py +++ b/const.py @@ -39,6 +39,12 @@ Y = 1 Z = 2 +# Humans have wibbly-wobbly hands. +HUMAN_BRICK_GRID_ERROR = Decimal("0.1") + +# The defined height of a Blockland plate at 100% scale. +DEFAULT_PLATE_HEIGHT = Decimal("0.4") + # Blockland does not accept bricks that are wide/deeper than 64 bricks or taller than 256 plates. MAX_BRICK_HORIZONTAL_PLATES = 64 MAX_BRICK_VERTICAL_PLATES = 256 @@ -111,6 +117,7 @@ def as_list(cls): DEFAULT_UV_COORDINATES = ((0.5, 0.5),) * 4 # Often used Decimal values. +DECIMAL_ONE = Decimal("1.0") DECIMAL_HALF = Decimal("0.5") # Useful angles in radians. diff --git a/export_blb.py b/export_blb.py index e509231..0bb430f 100644 --- a/export_blb.py +++ b/export_blb.py @@ -62,7 +62,7 @@ class DerivativeProperties(object): quad_sort_definitions (sequence): A sequence containing the user-defined definitions for quad sorting. scale (Decimal): The scale to export the brick at. Value is in range [0.0,1.0]. plate_height (Decimal): The height of one Blockland plate in Blender units. - human_error (Decimal): Error allowed for manually created definition objects, because they must lie exactly on the brick grid. + human_brick_grid_error (Decimal): Error allowed for manually created definition objects, because they must lie exactly on the brick grid. precision (String): The precision to round floating point numbers to when performing calculations. """ @@ -116,16 +116,13 @@ def __init__(self, properties): # ========================== # Plate Height & Human Error # ========================== - if properties.export_scale == 100.0: - # A 1x1 Blockland plate is equal to 1.0 x 1.0 x 0.4 Blender units (X,Y,Z) - self.plate_height = Decimal("0.4") + # Used for rounding vertex positions to the brick grid. + self.human_brick_grid_error = const.HUMAN_BRICK_GRID_ERROR + # A 1x1 Blockland plate is equal to 1.0 x 1.0 x 0.4 Blender units (X,Y,Z) + self.plate_height = const.DEFAULT_PLATE_HEIGHT - # Used for rounding vertex positions to the brick grid. - self.human_error = Decimal("0.1") - else: - # FIXME: Typo? Shouldn't I define self.human_error and self.plate_height? - properties.human_error = properties.human_error * self.scale - properties.plate_height = properties.plate_heigh * self.scale + if self.scale != const.DECIMAL_ONE: + self.plate_height = self.plate_height * self.scale # ========= # Precision From 65cf60d327fa146bc7515d84561cc3bab0686e67 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sat, 18 Nov 2017 23:29:38 +0200 Subject: [PATCH 42/50] Modify writer to build a list of strings before writing all at once --- blb_processor.py | 13 ++-- blb_writer.py | 189 ++++++++++++++++++++++++----------------------- 2 files changed, 104 insertions(+), 98 deletions(-) diff --git a/blb_processor.py b/blb_processor.py index cb3d0f9..70287ca 100644 --- a/blb_processor.py +++ b/blb_processor.py @@ -949,7 +949,6 @@ def __record_bounds_data(properties, blb_data, bounds_data): for index, value in enumerate(bounds_size): # Round to the specified error amount. bounds_size[index] = round(properties.human_brick_grid_error * round(value / properties.human_brick_grid_error)) - # FIXME: Force to integer size? # The value type must be int because you can't have partial plates. Returns a list. blb_data.brick_size = __force_to_ints(bounds_size) @@ -2422,11 +2421,11 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ if properties.deftokens.color in tokens: # Parse floats from the expected color values. floats = __get_color_values(tokens[tokens.index(properties.deftokens.color) + 1:]) - size = len(floats) + num_count = len(floats) # Did user define at least 4 numerical values? - if size >= 4: - if size > 4: + if num_count >= 4: + if num_count > 4: logger.error("IOBLBE013", "More than 4 color values defined for object '{}', only the first 4 values (RGBA) are used.".format(object_name), 2) # We're only interested in the first 4 values: R G B A @@ -2434,9 +2433,9 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ # Add the RGBA values to the colors, 4 vertices per quad. colors = ([tuple(floats)] * 4) - elif size > 0: + elif num_count > 0: logger.info( - "Object '{}' is named as if it were colored but it was ignored because all 4 values (red green blue alpha) were not defined.".format(object_name), 2) + "Object '{}' is named as if it has custom color but it was ignored because all 4 values (red green blue alpha) were not defined.".format(object_name), 2) # Vertex color layer message. if len(current_mesh.vertex_colors) > 1: @@ -2694,7 +2693,7 @@ def __process_mesh_data(context, properties, bounds_data, mesh_objects, forward_ # The game can actually render per-vertex alpha but it doesn't seem to stick for longer than a second for whatever reason. name = common.to_float_or_none(" ".join(tokens)) - # FIXME: vertex_color_alpha is never assigned. + # Only log the vertex alpha message once per object: vertex color layers are per-object. if vertex_color_alpha is None: if name is None: vertex_color_alpha = 1.0 diff --git a/blb_writer.py b/blb_writer.py index 11657cd..4e404a3 100644 --- a/blb_writer.py +++ b/blb_writer.py @@ -25,34 +25,36 @@ from . import const -def __write_sequence(file, sequence, new_line=True, decimal_digits=const.MAX_FP_DECIMALS_TO_WRITE): +def __get_sequence_string(sequence, new_line=True, decimal_digits=const.MAX_FP_DECIMALS_TO_WRITE): """Writes the values of the specified sequence separated with spaces into the specified file. An optional new line character is added at the end of the line by default. Args: - file (object): The file to be written to. sequence (sequence): A sequence of data to be written. new_line (bool): Add a newline character at the end of the line? (Default: True) decimal_digits (int): The number of decimal digits to write if the sequence contains floating point values or None to ignore. (Default: const.MAX_FP_DECIMALS_TO_WRITE) The default value prevents very small values from being written in scientific notation, which the game does not understand. """ - # TODO: Convert this into a string builder? + parts = [] + for index, value in enumerate(sequence): if index != 0: - # Write a space before each value except the first one. - file.write(" ") + # Add a space before each value except the first one. + parts.append(" ") if value == 0: # Handle zeros. - file.write("0") + parts.append("0") else: # Format the value into string, remove all zeros from the end (if any), then remove all periods from the end (if any). if decimal_digits is None: - file.write("{}".format(value).rstrip("0").rstrip(".")) + parts.append("{}".format(value).rstrip("0").rstrip(".")) else: - file.write("{0:.{1}f}".format(value, decimal_digits).rstrip("0").rstrip(".")) + parts.append("{0:.{1}f}".format(value, decimal_digits).rstrip("0").rstrip(".")) if new_line: - # Write a new line after all values. - file.write("\n") + # Add a new line after all values. + parts.append("\n") + + return "".join(parts) def write_file(properties, filepath, blb_data): @@ -63,85 +65,90 @@ def write_file(properties, filepath, blb_data): filepath (string): Path to the BLB file to be written. blb_data (BLBData): A BLBData object containing the data to be written. """ + lines = [] + + # ---------- + # Brick Size + # ---------- + lines.append(__get_sequence_string(blb_data.brick_size)) + + # ---------- + # Brick Type + # ---------- + lines.append("{}\n\n".format(const.BLB_BRICK_TYPE_SPECIAL)) + + # ---------- + # Brick Grid + # ---------- + for axis_slice in blb_data.brick_grid: + for row in axis_slice: + # Join each Y-axis of data without a separator. + lines.append("".join(row) + "\n") + + # A new line after each axis slice. + lines.append("\n") + + # --------- + # Collision + # --------- + if len(blb_data.collision) < 1: + # No collision. + lines.append("0\n") + else: + # Write the number of collision cuboids. + lines.append("{}\n".format(str(len(blb_data.collision)))) + + # Write the defined collision cuboids. + for (center, dimensions) in blb_data.collision: + lines.append("\n") + lines.append(__get_sequence_string(center)) + lines.append(__get_sequence_string(dimensions)) + + # -------- + # Coverage + # -------- + # Only skip writing coverage if terse mode is True and coverage is False. + if not (properties.blendprop.terse_mode and not properties.blendprop.calculate_coverage): + lines.append("{}\n".format(const.BLB_HEADER_COVERAGE)) + for (hide_adjacent, plate_count) in blb_data.coverage: + lines.append("{} : {}\n".format(str(int(hide_adjacent)), str(plate_count))) + + # ----- + # Quads + # ----- + for section_name, section in const.BLBQuadSection.__members__.items(): + # Write section name. + lines.append("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_SECTION_SEPARATOR.format(section_name))) + + # Write section length. + lines.append("{}\n".format(str(len(blb_data.quads[section.value])))) + + for (positions, normals, uvs, colors, texture_name) in blb_data.quads[section.value]: + # Face texture name. + lines.append("\n{}{}\n".format(const.BLB_PREFIX_TEXTURE, texture_name)) + + # Vertex positions. + lines.append("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_HEADER_POSITION)) + + for position in positions: + lines.append(__get_sequence_string(position)) + + # Face UV coordinates. + lines.append("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_HEADER_UV)) + for uv_pair in uvs: + lines.append(__get_sequence_string(uv_pair)) + + # Vertex colors, if any. + if colors is not None: + lines.append("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_HEADER_COLORS)) + for color in colors: + lines.append(__get_sequence_string(color)) + + # Vertex normals. + lines.append("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_HEADER_NORMALS)) + for normal in normals: + lines.append(__get_sequence_string(normal)) + with open(filepath, "w") as file: - # ---------- - # Brick Size - # ---------- - __write_sequence(file, blb_data.brick_size) - - # ---------- - # Brick Type - # ---------- - file.write("{}\n\n".format(const.BLB_BRICK_TYPE_SPECIAL)) - - # ---------- - # Brick Grid - # ---------- - for axis_slice in blb_data.brick_grid: - for row in axis_slice: - # Join each Y-axis of data without a separator. - file.write("".join(row) + "\n") - - # A new line after each axis slice. - file.write("\n") - - # --------- - # Collision - # --------- - if len(blb_data.collision) < 1: - # No collision. - file.write("0\n") - else: - # Write the number of collision cuboids. - file.write("{}\n".format(str(len(blb_data.collision)))) - - # Write the defined collision cuboids. - for (center, dimensions) in blb_data.collision: - file.write("\n") - __write_sequence(file, center) - __write_sequence(file, dimensions) - - # -------- - # Coverage - # -------- - # Only skip writing coverage if terse mode is True and coverage is False. - if not (properties.blendprop.terse_mode and not properties.blendprop.calculate_coverage): - file.write("{}\n".format(const.BLB_HEADER_COVERAGE)) - for (hide_adjacent, plate_count) in blb_data.coverage: - file.write("{} : {}\n".format(str(int(hide_adjacent)), str(plate_count))) - - # ----- - # Quads - # ----- - for section_name, section in const.BLBQuadSection.__members__.items(): - # Write section name. - file.write("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_SECTION_SEPARATOR.format(section_name))) - - # Write section length. - file.write("{}\n".format(str(len(blb_data.quads[section.value])))) - - for (positions, normals, uvs, colors, texture_name) in blb_data.quads[section.value]: - # Face texture name. - file.write("\n{}{}\n".format(const.BLB_PREFIX_TEXTURE, texture_name)) - - # Vertex positions. - file.write("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_HEADER_POSITION)) - - for position in positions: - __write_sequence(file, position) - - # Face UV coordinates. - file.write("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_HEADER_UV)) - for uv_pair in uvs: - __write_sequence(file, uv_pair) - - # Vertex colors, if any. - if colors is not None: - file.write("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_HEADER_COLORS)) - for color in colors: - __write_sequence(file, color) - - # Vertex normals. - file.write("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_HEADER_NORMALS)) - for normal in normals: - __write_sequence(file, normal) + for line in lines: + file.write(line) From 263e900cb5e60d766b88e44cb8e8daded41d2070 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 19 Nov 2017 00:07:28 +0200 Subject: [PATCH 43/50] Reformat README to one sentence/line, doc missing props, tweak wording --- README.md | 169 +++++++++++++++++++++++++++++++++++++++------------- __init__.py | 3 +- 2 files changed, 127 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index b36d31c..d84e8cc 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # Blender BLB Exporter # [![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://img.shields.io/badge/License-GPL%20v2-blue.svg) -A [Blender](https://www.blender.org/) add-on written in Python 3 for exporting [Blockland](http://blockland.us/) bricks (.BLB files) directly from Blender 2.67 and newer without the need for intermediary formats or external programs. It works on the principle of "what you see is what you get", the brick will look exactly the same in-game as it does in the 3D viewport[__*__](#exporter-fn-1). +A [Blender](https://www.blender.org/) add-on written in Python 3 for exporting [Blockland](http://blockland.us/) bricks (.BLB files) directly from Blender 2.67 and newer without the need for intermediary formats or external programs. +It works on the principle of "what you see is what you get", the brick will look exactly the same in-game as it does in the 3D viewport[__*__](#exporter-fn-1). The add-on does not support importing .BLB files yet. @@ -295,7 +296,8 @@ Layers | Export all bricks in the layers that are currently visible. (Default) Scene | Export all bricks in the current scene. I.e. all bricks in all layers regardless of the layer visibility. #### Forward Axis #### -The Blender 3D axis that will point forwards in-game when the player plants the brick directly in front of them without rotating it. Does not change the rotation of the objects in the Blender scene. +The Blender 3D axis that will point forwards in-game when the player plants the brick directly in front of them without rotating it. +Does not change the rotation of the objects in the Blender scene. Value | Description ------|------------ @@ -305,54 +307,97 @@ Value | Description -Y | Negative Y-axis: back #### Scale #### -The scale of the brick in-game. Values outside the the range of 0.001–400.0 may be typed in manually. Does not change the scale of the objects in the Blender scene. (Default: 100%) +The scale of the brick in-game. +Values outside the the range of 0.001–400.0 may be typed in manually. +Does not change the scale of the objects in the Blender scene. +(Default: 100%) -:exclamation: Be aware that at 100% scale a 1x1x1 Blockland brick is defined to be 1.0 x 1.0 x 1.2 Blender units on the X, Y, and Z axes. In other words a 1x1f plate would be 1.0 x 1.0 x 0.4 Blender units. +:exclamation: Be aware that at 100% scale a 1x1x1 Blockland brick is defined to be 1.0 x 1.0 x 1.2 Blender units on the X, Y, and Z axes. +In other words a 1x1f plate would be 1.0 x 1.0 x 0.4 Blender units. #### Apply Modifiers #### -Applies any modifiers on the object before exporting. Does not change the modifiers of the objects in the Blender scene. (Default: True) +Applies any modifiers on the object before exporting. +Does not change the modifiers of the objects in the Blender scene. +(Default: True) -#### Calculate Collision #### -If no manual collision definition objects exist, calculates a cuboid collision that is the same size as the brick bounds. If disabled and no collision is defined, brick will have no collision. (Default: True) +#### Custom Collision #### +Export custom collision definitions if there are any. +See [Defining Collision](#defining-collision). +(Default: True) + +#### Fallback Collision #### +The type of collision to calculate for the brick if no custom collision definitions are found. + +Value | Description +------|------------ +Bounds | Use the defined or calculated [bounds](#definition-objects-bounds) of the brick as the collision cuboid. (Default) +AABB | Calculate the [axis-aligned bounding box](#def-aabb) of all [visible objects](#def-visible-object) and use that as the collision cuboid. #### Coverage #### -Enable coverage calculations. Shows additional settings when selected. This is pointless unless [Automatic Quad Sorting](#automatic-quad-sorting) is enabled or at least one object has a quad sorting definition. See [Defining Quad Sorting & Coverage](#defining-quad-sections--coverage) for more information. (Default: False) +Enable coverage calculations. +Shows additional settings when selected. +This is pointless unless [Automatic Quad Sorting](#automatic-quad-sorting) is enabled or at least one object has a quad sorting definition. +See [Defining Quad Sorting & Coverage](#defining-quad-sections--coverage) for more information. +(Default: False) #### Automatic Quad Sorting #### -Automatically calculate the correct section for quads that in the same plane as the bounding planes of the bounds object. This is pointless unless [Coverage](#coverage) is enabled. (Default: True) +Automatically calculate the correct section for quads that in the same plane as the bounding planes of the bounds object. +This is pointless unless [Coverage](#coverage) is enabled. +(Default: True) #### Use Material Colors #### -Get object colors from object materials. (Default: False) +Get object colors from object materials. +(Default: False) #### Use Vertex Colors #### -Get object colors from vertex color layers. (Default: False) +Get object colors from vertex color layers. +(Default: False) #### Parse Object Colors #### -Get object colors from object names. (Default: False) +Get object colors from object names. +(Default: False) #### Calculate UVs #### -Automatically calculate correct UV coordinates based on the brick texture name specified in the material name. See [UV Mapping](#uv-mapping) for more information. (Default: True) +Automatically calculate correct UV coordinates based on the brick texture name specified in the material name. +See [UV Mapping](#uv-mapping) for more information. +(Default: True) #### Store UVs #### -Write calculated UVs into Blender objects. Data in existing generated UV layers will be overwritten. See [UV Mapping](#uv-mapping) for a list of generated UV layer names. (Default: True) +Write calculated UVs into Blender objects. +Data in existing generated UV layers will be overwritten. +See [UV Mapping](#uv-mapping) for a list of generated UV layer names. +(Default: True) #### Round Normals #### -Round vertex normals to the user-defined floating point value precision. If disabled normals will be written as accurately as possible but extraneous zeros will still be removed. (Default: False) +Round vertex normals to the user-defined floating point value precision. +If disabled normals will be written as accurately as possible but extraneous zeros will still be removed. +(Default: False) #### Custom Definition Tokens #### -Allows you to specify the definition tokens the exporter uses. Shows additional settings when selected. See [Definition Tokens](#definition-tokens) for more information. (Default: False) +Allows you to specify the definition tokens the exporter uses. +Shows additional settings when selected. +See [Definition Tokens](#definition-tokens) for more information. +(Default: False) #### Terse Mode #### -When enabled does not write optional lines to the .BLB file such as the lines marking the different quad sections. Using this option is not recommended as it makes the .BLB file harder to read and understand. Although the file is shorter, the difference in file size is negligible. (Default: False) +When enabled does not write optional lines to the .BLB file such as the lines marking the different quad sections. +Using this option is not recommended as it makes the .BLB file harder to read and understand. +Although the file is shorter, the difference in file size is negligible. +(Default: False) #### Write Log #### -Write a log file to the same folder as the exported brick detailing the export process. Shows additional settings when selected. (Default: True) +Write a log file to the same folder as the exported brick detailing the export process. +Shows additional settings when selected. +(Default: True) #### Only on Warnings #### -Write a log file only if warnings or errors occurred during the export process. (Default: True) +Write a log file only if warnings or errors occurred during the export process. +(Default: True) #### Precision #### -Allows you to specify a custom precision for floating point numbers. See [Rounded Values](#rounded-values) for more details. (Default: 0.000001) +Allows you to specify a custom precision for floating point numbers. +See [Rounded Values](#rounded-values) for more details. +(Default: 0.000001) ## Definition Tokens ## [Definition tokens](#def-definition-token) are special [strings](#def-string) added to the names of objects, materials, and other Blender data objects that have a name. @@ -453,14 +498,18 @@ The exporter understands two ways of defining an RGBA color using text. :exclamation: Please note that you **must** use a comma character (`,`) as the decimal separator for floating point numbers. 1. The commonly used method of writing 4 integers that are in the range 0–255, where 0 is black, separated with a whitespace character such as a space. -For example `127 255 10 191` for a yellow-green color that is 25% transparent. A full object name could be for example `glass c 240 255 255 128.001`. +For example `127 255 10 191` for a yellow-green color that is 25% transparent. +A full object name could be for example `glass c 240 255 255 128.001`. - In the above example the running index `.001` that Blender added at the end would be removed by the exporter. -1. Writing 4 decimals in the range 0.0–1.0, where 0.0 is black, separated with a whitespace character such as a space. An object could have a name such as `c 0,125 0,0 0,5 1,0 flower`, for example. +1. Writing 4 decimals in the range 0.0–1.0, where 0.0 is black, separated with a whitespace character such as a space. +An object could have a name such as `c 0,125 0,0 0,5 1,0 flower`, for example. - The leading zero may be omitted. - Up to 16 decimals are supported. ## Definition Objects ## -When a definition object token is read in an object's name it is treated as a definition object. Definition objects are never exported as visual 3D models, in fact they are not exported at all. Instead the data they contain in their name (or elsewhere) and the 3D space they represent is processed further to acquire the necessary information for the BLB file. +When a definition object token is read in an object's name it is treated as a definition object. +Definition objects are never exported as visual 3D models, in fact they are not exported at all. +Instead the data they contain in their name (or elsewhere) and the 3D space they represent is processed further to acquire the necessary information for the BLB file. Definition Object | Default Token | Requirements | Maximum Count/Brick | Must Be Within [**Bounds**](#definition-objects-bounds) | Axis-Aligned | Brick Grid Aligned | Can Overlap | Description ------------------|---------------|--------------|--------------------:|:-------------------:|:------------:|:------------------:|:-----------:|------------ @@ -486,7 +535,10 @@ Only the the [axis-aligned bounding box](#def-aabb) of the collision definition :bulb: Using any other shape than an axis-aligned cuboid to define collision is not recommended as it makes the Blender file more difficult to understand and also breaks the "what you see is what you get" principle. ### Defining Brick Grid ### -Brick grid definitions represent a 3D volume in the 3D space the brick grid encompasses. You can imagine it as if the entire cuboidal shape of the brick would be filled with 1x1f plates and these volumes define the properties of all the 1x1f plates within that volume. Each brick grid definition has their own priority. When two or more brick grid definition objects overlap in 3D space, the one with the **higher** priority takes precedence and will overwrite the symbols in the brick grid that any definitions with lower priorities would have written. +Brick grid definitions represent a 3D volume in the 3D space the brick grid encompasses. +You can imagine it as if the entire cuboidal shape of the brick would be filled with 1x1f plates and these volumes define the properties of all the 1x1f plates within that volume. +Each brick grid definition has their own priority. +When two or more brick grid definition objects overlap in 3D space, the one with the **higher** priority takes precedence and will overwrite the symbols in the brick grid that any definitions with lower priorities would have written. :exclamation: Be aware that if your brick does not contain a `brickd` definition on the bottom of the brick, the brick cannot be planted on other bricks or the ground. @@ -499,7 +551,8 @@ Default Token | Brick Grid Symbol | Description `gridx` | `x` | Bricks may not be placed inside this volume. ## Brick Textures ## -Defining brick textures is done using Blender materials. To assign a brick texture to a face, assign a material to it containing a valid brick texture name (case insensitive): +Defining brick textures is done using Blender materials. +To assign a brick texture to a face, assign a material to it containing a valid brick texture name (case insensitive): - `bottomedge` - `bottomloop` - `print` @@ -507,7 +560,9 @@ Defining brick textures is done using Blender materials. To assign a brick textu - `side` - `top` -If no brick texture is defined, `side` is used. Material name may contain other words as long as the brick texture name is separated from them with one whitespace character such as a space. A common combination is to define a brick texture name and the [definition token `blank`](#defining-colors-blank) (e.g. `blank ramp` or `side blank`) to allow the player to color the face in-game using the spray can. +If no brick texture is defined, `side` is used. +Material name may contain other words as long as the brick texture name is separated from them with one whitespace character such as a space. +A common combination is to define a brick texture name and the [definition token `blank`](#defining-colors-blank) (e.g. `blank ramp` or `side blank`) to allow the player to color the face in-game using the spray can. ## UV Mapping ## Manually defined UV coordinates must be stored in one or more UV layers that do not share a name with one of the automatically generated UV layers: @@ -519,22 +574,36 @@ Manually defined UV coordinates must be stored in one or more UV layers that do Any data in UV layers with one the names above will the overwritten during automatic UV calculation. -:exclamation: Note that BLB files only support storing quads. As such, any tris with UV coordinates will have their last UV coordinate duplicated to transform it into a quad. This may or may not cause visual distortion in the UV mapping. +:exclamation: Note that BLB files only support storing quads. +As such, any tris with UV coordinates will have their last UV coordinate duplicated to transform it into a quad. +This may or may not cause visual distortion in the UV mapping. -If the [Calculate UVs](#calculate-uvs) property is enabled, UV coordinates will be automatically calculated based on the dimensions of the quad and the name of the material assigned to it. (See [Brick Textures](#brick-textures) to learn how to define brick textures with materials.) The generated coordinates are only guaranteed to be correct for strictly rectangular quads, for any other shapes the results may not be satisfactory. If using brick textures on non-rectangular quads it is recommended to manually define the UV coordinates for best results. +If the [Calculate UVs](#calculate-uvs) property is enabled, UV coordinates will be automatically calculated based on the dimensions of the quad and the name of the material assigned to it. +(See [Brick Textures](#brick-textures) to learn how to define brick textures with materials.) +The generated coordinates are only guaranteed to be correct for strictly rectangular quads, for any other shapes the results may not be satisfactory. +If using brick textures on non-rectangular quads it is recommended to manually define the UV coordinates for best results. ## Troubleshooting ## -Solutions to common issues with the BLB Exporter. If you have another issue with the exporter be sure to enable the [Write Log](#write-log) property and export again. The log file may contain warnings or errors describing issues with the models and how to fix them. +Solutions to common issues with the BLB Exporter. +If you have another issue with the exporter be sure to enable the [Write Log](#write-log) property and export again. +The log file may contain warnings or errors describing issues with the models and how to fix them. Additional instructions on how to fix specific issues are detailed in the [Warning & Error Log Messages](#warning--error-log-messages) section. ### Automatically calculated UV coordinates for brick textures are distorted ### -The automatic UV calculation is only designed to work with rectangular quads. Manually define UV coordinates for non-rectangular quads. +The automatic UV calculation is only designed to work with rectangular quads. +Manually define UV coordinates for non-rectangular quads. ### Automatically calculated UV coordinates for brick textures are rotated incorrectly ### -The quad with incorrectly rotated UV coordinates (e.g. the lightest side of the SIDE texture pointing sideways instead of up) is not a perfect rectangle. Even one vertex being off by some minuscule, visually indistinguishable amount from a perfectly rectangular shape can cause the automatic UV calculation to incorrectly determine the rotation of the quad. Double check all 4 coordinates of the quad and manually correct any floating point errors. If working on axis-aligned quads or if the vertices should be on grid points snapping the coordinates of the problem quad to grid coordinates using `Mesh > Snap > Snap Selection to Grid` usually fixes floating point errors. +The quad with incorrectly rotated UV coordinates (e.g. the lightest side of the SIDE texture pointing sideways instead of up) is not a perfect rectangle. +Even one vertex being off by some minuscule, visually indistinguishable amount from a perfectly rectangular shape can cause the automatic UV calculation to incorrectly determine the rotation of the quad. +Double check all 4 coordinates of the quad and manually correct any floating point errors. +If working on axis-aligned quads or if the vertices should be on grid points snapping the coordinates of the problem quad to grid coordinates using `Mesh > Snap > Snap Selection to Grid` usually fixes floating point errors. ### The TOP brick texture has incorrect rotation in Blender ### -Blockland automatically performs rotations on the UV coordinates of the TOP brick texture during runtime so that the lightest side of the texture is always facing towards the sun. Because of this there is no correct way of representing the TOP brick texture in Blender. As a compromise the exporter will rotate the lightest side of the TOP brick texture to face towards the axis select in the [Forward Axis](#forward-axis) property. This means the UV coordinates of the TOP brick texture in Blender may not match those in the written BLB file. +Blockland automatically performs rotations on the UV coordinates of the TOP brick texture during runtime so that the lightest side of the texture is always facing towards the sun. +Because of this there is no correct way of representing the TOP brick texture in Blender. +As a compromise the exporter will rotate the lightest side of the TOP brick texture to face towards the axis select in the [Forward Axis](#forward-axis) property. +This means the UV coordinates of the TOP brick texture in Blender may not match those in the written BLB file. ## Warning & Error Log Messages ## Detailed explanations of the warning and error messages logged by the program and directions on how to solve the associated issues. @@ -650,7 +719,8 @@ It is recommended to manually adjust the brick until no warning messages are pre - + @@ -672,7 +742,8 @@ It is recommended to manually adjust the brick until no warning messages are pre - + @@ -807,7 +878,8 @@ It is recommended to manually adjust the brick until no warning messages are pre - - + @@ -1064,7 +1137,7 @@ Fatal errors always lead to the program execution stopping. - +
    EffectA full block brick grid will be generated. Brick will act as if it were a basic cuboid brick of that size.A full block brick grid will be generated. + Brick will act as if it were a basic cuboid brick of that size.
    Solution
    EffectA full block brick grid will be generated. Brick will act as if it were a basic cuboid brick of that size.A full block brick grid will be generated. + Brick will act as if it were a basic cuboid brick of that size.
    Solution
    EffectThe triangle is forcefully converted into a quad by copying the first vertex and using that as the last vertex of a quad. This conversion has three different outcomes: + The triangle is forcefully converted into a quad by copying the first vertex and using that as the last vertex of a quad. + This conversion has three different outcomes:
    • If flat shading is used for the face there is no change visually and the face will look like a triangle in game.
    • If the face and adjacent connected faces are planar and smooth shading is used there are no visual anomalies.
    • @@ -1056,7 +1128,8 @@ Fatal errors always lead to the program execution stopping.
    Single SelectionNo objects were selected. Selected objects have an orange outline.No objects were selected. + Selected objects have an orange outline.
    Layers
    SceneThere are no objects in the current scene. In other words none of the layers in the current scene contained objects.None of the layers in the current scene contained any objects.
    @@ -1127,7 +1200,7 @@ Fatal errors always lead to the program execution stopping. Scene - You are attempting to export an empty scene. Either add some objects to a layer in the scene or ensure that you are not in the wrong scene. + Add objects to a layer in the scene or check that you are not in the wrong scene. @@ -1157,7 +1230,7 @@ Fatal errors always lead to the program execution stopping. Layers - You are attempting to export an empty scene. Either add some objects to a layer in the scene or ensure that you are not in the wrong scene. + Add objects to a layer in the scene or check that you are not in the wrong scene. @@ -1724,9 +1797,18 @@ Fatal errors always lead to the program execution stopping. ## Rounded Values ## -Floating point numbers (numbers with a decimal point) contain [inherent inaccuracies](https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems). For example when exporting a 1x1x1 brick model at the maximum accuracy the vertex coordinate of one of the corners is `0.5 0.5 1.5000000596046448`. This causes the 1x1x1 brick to be `3.00000011920928955078125` plates tall instead of exactly `3.0` like it should. The only way to get rid of this error is to round the number (vertex coordinates). Practically speaking it is impossible to visually discern the difference between a brick that is 3 plates tall versus one that is `3.00000011920928955078125` plates tall in the game. The floating point errors are effectively 0. The only real benefit that comes from the rounding is nicer looking .BLB files. - -The default value of `0.000001` was chosen through manual testing. Rest assured that the rounding will cause no visual oddities whatsoever because the value is so small. This was manually confirmed with a sphere brick made from 524288 quads. Moving the camera as close to the surface of the brick as the game was capable of rendering, the surface of the sphere appeared mathematically perfect because the distance between the vertices was less than the size of a single pixel. +Floating point numbers (numbers with a decimal point) contain [inherent inaccuracies](https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems). +For example when exporting a 1x1x1 brick model at the maximum accuracy the vertex coordinate of one of the corners is `0.5 0.5 1.5000000596046448`. +This causes the 1x1x1 brick to be `3.00000011920928955078125` plates tall instead of exactly `3.0` like it should. +The only way to get rid of this error is to round the number (vertex coordinates). +Practically speaking it is impossible to visually discern the difference between a brick that is 3 plates tall versus one that is `3.00000011920928955078125` plates tall in the game. +The floating point errors are effectively 0. +The only real benefit that comes from the rounding is nicer looking .BLB files. + +The default value of `0.000001` was chosen through manual testing. +Rest assured that the rounding will cause no visual oddities whatsoever because the value is so small. +This was manually confirmed with a sphere brick made from 524288 quads. +Moving the camera as close to the surface of the brick as the game was capable of rendering, the surface of the sphere appeared mathematically perfect because the distance between the vertices was less than the size of a single pixel. :exclamation: The exporter will only ever write 16 decimal places regardless of the precision of the value. @@ -1741,7 +1823,8 @@ Normal vectors | [Optional](#round-normals) [UV coordinates](#uv-mapping) | No ## Contributors ## -- [Nick Smith](https://github.com/qoh) - The original source code for reading, processing, and writing Blender data into the .BLB format. A majority of his code has been rewritten since. +- [Nick Smith](https://github.com/qoh) - The original source code for reading, processing, and writing Blender data into the .BLB format. +A majority of his code has been rewritten since. - [Demian Wright](https://github.com/DemianWright) - Significant extensions and rewrites to Nick's original code and everything else. __*__ There's always a footnote, see the issue with [the TOP brick texture](#the-top-brick-texture-has-incorrect-rotation-in-blender). diff --git a/__init__.py b/__init__.py index 0cc5551..98195b7 100644 --- a/__init__.py +++ b/__init__.py @@ -50,7 +50,6 @@ # TODO: Add a section about brick size to the readme. # TODO: Add a section about brick grid to the readme. # TODO: Make the capitalization consistent in the readme. -# TODO: Consider reformatting readme to have one sentence per line for nicer diffs. # TODO: Consider refactoring readme for consistent use of mesh, model, and object words. # TODO: Clarify brick grid and brick grid placement rules. @@ -357,7 +356,7 @@ class ExportBLB(bpy.types.Operator, ExportHelper): fallback_collision = EnumProperty( items=[("BOUNDS", "Bounds", "Use brick bounds as collision"), - ("AABB", "AABB", "Calculate axis-aligned bounding box collision from visible meshes")], + ("AABB", "AABB", "Calculate axis-aligned bounding box collision from visible objects")], name="Fallback Collision", description="Collision type to use if no custom definitions exist", default="BOUNDS" From e1d999eeaa14b8d6f8b4404ea144f531d204d549 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 19 Nov 2017 00:34:10 +0200 Subject: [PATCH 44/50] Add section about brick scale to README, tweak README formatting --- README.md | 70 +++++++++++++++++++++++++++++------------------------ __init__.py | 1 - 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index d84e8cc..9bdbf75 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ The add-on does not support importing .BLB files yet. 1. [Write Log](#write-log) 1. [Only on Warnings](#only-on-warnings) 1. [Precision](#precision) +1. [Brick Scale](#brick-scale) 1. [Definition Tokens](#definition-tokens) 1. [Mesh Definition Tokens](#mesh-definition-tokens) 1. [Defining Quad Sections & Coverage](#defining-quad-sections--coverage) @@ -105,7 +106,7 @@ The exporter supports all BLB features. ### Planned Features ### These features may or may not be implemented at some unspecified time in the future. -- Exporting DTS collision using Nick Smith's [io_scene_dts](https://github.com/qoh/io_scene_dts) Blender plugin. +- Exporting DTS collision using Nick Smith's [io_scene_dts](https://github.com/qoh/io_scene_dts) Blender add-on. - Importing .BLB files - Export-time brick rotation on the Z-axis - Automatic rendering of the brick preview icon @@ -251,7 +252,7 @@ How many bricks to export in one go from the file. Value | Description ------|------------ -Single | Export only one brick. (Default) +Single | Export only one brick. **(Default)** Multiple | Export one or more bricks. Shows additional settings when selected. #### Brick Name from (Single Export) #### @@ -259,7 +260,7 @@ Where the .BLB file name is defined. Value | Description ------|------------ -Bounds | Brick name is defined in the [Bounds object](#definition-objects-bounds) after the bounds definition token, separated with a whitespace character. Export file dialog is only used set to directory. (Default) +Bounds | Brick name is defined in the [Bounds object](#definition-objects-bounds) after the bounds definition token, separated with a whitespace character. Export file dialog is only used set to directory. **(Default)** File | Brick name is the same as the file name. Can be manually set in the export file dialog. #### Export Only (Single Export) #### @@ -267,7 +268,7 @@ Which objects to process and export to the .BLB file. Value | Description ------|------------ -Selection | Objects that are selected and have an orange outline. (Default) +Selection | Objects that are selected and have an orange outline. **(Default)** Layers | All objects in the layers that are currently visible, regardless of selection. Scene | All objects in the current scene. I.e. all objects in all layers regardless of the layer visibility. @@ -276,7 +277,7 @@ Where the names of the .BLB files are defined. Value | Description ------|------------ -Bounds | Brick names are defined in the [Bounds object](#definition-objects-bounds) after the bounds definition token, separated with a whitespace character. Export file dialog is only used set to directory. (Default) +Bounds | Brick names are defined in the [Bounds object](#definition-objects-bounds) after the bounds definition token, separated with a whitespace character. Export file dialog is only used set to directory. **(Default)** Groups | Brick names are the same as the names of the groups name. Export file dialog is only used set to directory. #### Bricks Defined by (Multiple Export) #### @@ -284,7 +285,7 @@ How is a single brick defined. Value | Description ------|------------ -Groups | Each brick is in its own group. Objects in multiple groups belong to multiple bricks. (Default) +Groups | Each brick is in its own group. Objects in multiple groups belong to multiple bricks. **(Default)** Layers | Each brick is in its own layer. Objects in multiple layers belong to multiple bricks. When selected brick names must be defined in the [Bounds object](#definition-objects-bounds). #### Export Bricks in (Multiple Export) #### @@ -292,45 +293,43 @@ Which bricks to process and export to .BLB files. Value | Description ------|------------ -Layers | Export all bricks in the layers that are currently visible. (Default) +Layers | Export all bricks in the layers that are currently visible. **(Default)** Scene | Export all bricks in the current scene. I.e. all bricks in all layers regardless of the layer visibility. #### Forward Axis #### -The Blender 3D axis that will point forwards in-game when the player plants the brick directly in front of them without rotating it. +The Blender coordinate axis that will point forwards in-game when the player plants the brick directly in front of them without rotating it. Does not change the rotation of the objects in the Blender scene. Value | Description ------|------------ -+X | Positive X-axis: right -+Y | Positive Y-axis: forward (Default) --X | Negative X-axis: left --Y | Negative Y-axis: back ++X | Positive X-axis ++Y | Positive Y-axis **(Default)** +-X | Negative X-axis +-Y | Negative Y-axis #### Scale #### The scale of the brick in-game. Values outside the the range of 0.001–400.0 may be typed in manually. Does not change the scale of the objects in the Blender scene. -(Default: 100%) - -:exclamation: Be aware that at 100% scale a 1x1x1 Blockland brick is defined to be 1.0 x 1.0 x 1.2 Blender units on the X, Y, and Z axes. -In other words a 1x1f plate would be 1.0 x 1.0 x 0.4 Blender units. +See [Brick Scale](#brick-scale) for additional information. +(Default: `100%`) #### Apply Modifiers #### Applies any modifiers on the object before exporting. Does not change the modifiers of the objects in the Blender scene. -(Default: True) +(Default: `True`) #### Custom Collision #### Export custom collision definitions if there are any. See [Defining Collision](#defining-collision). -(Default: True) +(Default: `True`) #### Fallback Collision #### The type of collision to calculate for the brick if no custom collision definitions are found. Value | Description ------|------------ -Bounds | Use the defined or calculated [bounds](#definition-objects-bounds) of the brick as the collision cuboid. (Default) +Bounds | Use the defined or calculated [bounds](#definition-objects-bounds) of the brick as the collision cuboid. **(Default)** AABB | Calculate the [axis-aligned bounding box](#def-aabb) of all [visible objects](#def-visible-object) and use that as the collision cuboid. #### Coverage #### @@ -338,66 +337,73 @@ Enable coverage calculations. Shows additional settings when selected. This is pointless unless [Automatic Quad Sorting](#automatic-quad-sorting) is enabled or at least one object has a quad sorting definition. See [Defining Quad Sorting & Coverage](#defining-quad-sections--coverage) for more information. -(Default: False) +(Default: `False`) #### Automatic Quad Sorting #### Automatically calculate the correct section for quads that in the same plane as the bounding planes of the bounds object. This is pointless unless [Coverage](#coverage) is enabled. -(Default: True) +(Default: `True`) #### Use Material Colors #### Get object colors from object materials. -(Default: False) +(Default: `False`) #### Use Vertex Colors #### Get object colors from vertex color layers. -(Default: False) +(Default: `False`) #### Parse Object Colors #### Get object colors from object names. -(Default: False) +(Default: `False`) #### Calculate UVs #### Automatically calculate correct UV coordinates based on the brick texture name specified in the material name. See [UV Mapping](#uv-mapping) for more information. -(Default: True) +(Default: `True`) #### Store UVs #### Write calculated UVs into Blender objects. Data in existing generated UV layers will be overwritten. See [UV Mapping](#uv-mapping) for a list of generated UV layer names. -(Default: True) +(Default: `True`) #### Round Normals #### Round vertex normals to the user-defined floating point value precision. If disabled normals will be written as accurately as possible but extraneous zeros will still be removed. -(Default: False) +(Default: `False`) #### Custom Definition Tokens #### Allows you to specify the definition tokens the exporter uses. Shows additional settings when selected. See [Definition Tokens](#definition-tokens) for more information. -(Default: False) +(Default: `False`) #### Terse Mode #### When enabled does not write optional lines to the .BLB file such as the lines marking the different quad sections. Using this option is not recommended as it makes the .BLB file harder to read and understand. Although the file is shorter, the difference in file size is negligible. -(Default: False) +(Default: `False`) #### Write Log #### Write a log file to the same folder as the exported brick detailing the export process. Shows additional settings when selected. -(Default: True) +(Default: `True`) #### Only on Warnings #### Write a log file only if warnings or errors occurred during the export process. -(Default: True) +(Default: `True`) #### Precision #### Allows you to specify a custom precision for floating point numbers. See [Rounded Values](#rounded-values) for more details. -(Default: 0.000001) +(Default: `0.000001`) + +## Brick Scale ## +This add-on defines a `1x1x1` Blockland brick to be exactly `1.0 1.0 1.2` Blender units on the X, Y, and Z axes. +Likewise a `1x1f` Blockland plate is defined to be exactly `1.0 1.0 0.4` Blender units. +However, the final scale of the exported brick can be changed with the [Scale](#scale) property. +For example setting the [Scale](#scale) property to `150%` means that during the exporting process, the [meshes](#def-mesh) are scaled by `1.5`. +This is particularly useful when exporting 3D models created for another BLB exporter/converter that has defined the size of a `1x1f` plate to be different from this exporter. ## Definition Tokens ## [Definition tokens](#def-definition-token) are special [strings](#def-string) added to the names of objects, materials, and other Blender data objects that have a name. diff --git a/__init__.py b/__init__.py index 98195b7..ed5d9dc 100644 --- a/__init__.py +++ b/__init__.py @@ -47,7 +47,6 @@ # TODO: Check that all docstrings and comments are still up to date. # TODO: Quad sorting is per object but BLBs support per-quad sorting: the exporter does not support quad sorting for smoothed objects. # TODO: Serialize props to the start of the log? -# TODO: Add a section about brick size to the readme. # TODO: Add a section about brick grid to the readme. # TODO: Make the capitalization consistent in the readme. # TODO: Consider refactoring readme for consistent use of mesh, model, and object words. From 2a5a4e17cf860020ae7aa32190fac1badc0cb463 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 19 Nov 2017 11:00:53 +0200 Subject: [PATCH 45/50] Make "object/mesh/model" consistent in README, wording tweaks, new links --- README.md | 141 ++++++++++++++++++++++++++-------------------------- __init__.py | 1 - 2 files changed, 71 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 9bdbf75..92c19a7 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ The definitions are in the context of Blockland, Blender, and this exporter and When this two-dimensional plane is viewed from either of the other two coordinate axes it disappears from view.
    Axis-Aligned Bounding Box / Axis-Aligned Minimum Bounding Box
    -
    A cuboid that completely encompasses all vertices of one or more objects. +
    A cuboid that completely encompasses all vertices of one or more mesh objects. The faces of this cuboid are parallel with the coordinate axes.
    Axis-Aligned Cuboid
    @@ -153,7 +153,7 @@ See Defining Brick Grid.Brick
      -
    1. A collection of faces that acts as a single object in Blockland and all the non-visual data it contains such as collision information.
    2. +
    3. A collection of meshes that acts as a single object in Blockland and all the non-visual data it contains such as collision information.
    4. The BLB file itself.
    5. The Blender objects that when exported produce a BLB file.
    @@ -183,7 +183,7 @@ There are three different definition objects:
    Definition Token
    -
    A special token in an object's name that tells the exporter what to do with that object.
    +
    A special token in an object's name that tells the exporter additional information about that object or the entire brick.
    Face
    A visible surface that is rendered in game and in the Blender viewport. @@ -192,7 +192,7 @@ The surface must be bound by or created by at least three vertices (making it a :exclamation: Blockland bricks only support faces made from exactly four vertices: quads.
    Mesh
    -
    The vertices, edges, and faces that make up a 3D model.
    +
    The vertices, edges, and faces that make up a 3D model.
    Mesh Object
    A Blender object that contains vertices, edges, and faces. @@ -264,7 +264,7 @@ Bounds | Brick name is defined in the [Bounds object](#definition-objects-bounds File | Brick name is the same as the file name. Can be manually set in the export file dialog. #### Export Only (Single Export) #### -Which objects to process and export to the .BLB file. +Which [objects](#def-object) to process and export to the .BLB file. Value | Description ------|------------ @@ -285,8 +285,8 @@ How is a single brick defined. Value | Description ------|------------ -Groups | Each brick is in its own group. Objects in multiple groups belong to multiple bricks. **(Default)** -Layers | Each brick is in its own layer. Objects in multiple layers belong to multiple bricks. When selected brick names must be defined in the [Bounds object](#definition-objects-bounds). +Groups | Each brick is in its own group. [Objects](#def-object) in multiple groups belong to multiple bricks. **(Default)** +Layers | Each brick is in its own layer. [Objects](#def-object) in multiple layers belong to multiple bricks. When selected brick names must be defined in the [Bounds object](#definition-objects-bounds). #### Export Bricks in (Multiple Export) #### Which bricks to process and export to .BLB files. @@ -298,7 +298,7 @@ Scene | Export all bricks in the current scene. I.e. all bricks in all layers re #### Forward Axis #### The Blender coordinate axis that will point forwards in-game when the player plants the brick directly in front of them without rotating it. -Does not change the rotation of the objects in the Blender scene. +Does not change the rotation of the [objects](#def-object) in the Blender scene. Value | Description ------|------------ @@ -310,12 +310,12 @@ Value | Description #### Scale #### The scale of the brick in-game. Values outside the the range of 0.001–400.0 may be typed in manually. -Does not change the scale of the objects in the Blender scene. +Does not change the scale of the [objects](#def-object) in the Blender scene. See [Brick Scale](#brick-scale) for additional information. (Default: `100%`) #### Apply Modifiers #### -Applies any modifiers on the object before exporting. +Applies any modifiers on the [object](#def-object) before exporting. Does not change the modifiers of the objects in the Blender scene. (Default: `True`) @@ -335,7 +335,7 @@ AABB | Calculate the [axis-aligned bounding box](#def-aabb) of all [visible obje #### Coverage #### Enable coverage calculations. Shows additional settings when selected. -This is pointless unless [Automatic Quad Sorting](#automatic-quad-sorting) is enabled or at least one object has a quad sorting definition. +This is pointless unless [Automatic Quad Sorting](#automatic-quad-sorting) is enabled or at least one [object](#def-object) has a quad sorting definition. See [Defining Quad Sorting & Coverage](#defining-quad-sections--coverage) for more information. (Default: `False`) @@ -345,15 +345,15 @@ This is pointless unless [Coverage](#coverage) is enabled. (Default: `True`) #### Use Material Colors #### -Get object colors from object materials. +Assign [face](#def-face) colors from [object](#def-object) materials. (Default: `False`) #### Use Vertex Colors #### -Get object colors from vertex color layers. +Assign [face](#def-face) colors from vertex color layers. (Default: `False`) #### Parse Object Colors #### -Get object colors from object names. +Assign [face](#def-face) colors from [object](#def-object) names. (Default: `False`) #### Calculate UVs #### @@ -362,7 +362,7 @@ See [UV Mapping](#uv-mapping) for more information. (Default: `True`) #### Store UVs #### -Write calculated UVs into Blender objects. +Write calculated UVs into Blender [objects](#def-object). Data in existing generated UV layers will be overwritten. See [UV Mapping](#uv-mapping) for a list of generated UV layer names. (Default: `True`) @@ -402,11 +402,11 @@ See [Rounded Values](#rounded-values) for more details. This add-on defines a `1x1x1` Blockland brick to be exactly `1.0 1.0 1.2` Blender units on the X, Y, and Z axes. Likewise a `1x1f` Blockland plate is defined to be exactly `1.0 1.0 0.4` Blender units. However, the final scale of the exported brick can be changed with the [Scale](#scale) property. -For example setting the [Scale](#scale) property to `150%` means that during the exporting process, the [meshes](#def-mesh) are scaled by `1.5`. +For example setting the [Scale](#scale) property to `150%` means that during the exporting process, the [objects](#def-object) are scaled by `1.5`. This is particularly useful when exporting 3D models created for another BLB exporter/converter that has defined the size of a `1x1f` plate to be different from this exporter. ## Definition Tokens ## -[Definition tokens](#def-definition-token) are special [strings](#def-string) added to the names of objects, materials, and other Blender data objects that have a name. +[Definition tokens](#def-definition-token) are special [strings](#def-string) added to the names of [objects](#def-object), materials, vertex color layers, and other Blender data objects that have a name. A name field may contain other text in addition to definition tokens as long as the tokens themselves are separated from other tokens and text by one [whitespace character](#def-whitespace) such as a space. The definition tokens may be changed from the defaults by selecting [Custom Definition Tokens](#custom-definition-tokens) in the export dialog. @@ -443,7 +443,7 @@ Default Token | Category | Usable In | Is a [Definition Object](#def-definition- ### Mesh Definition Tokens ### Mesh definition tokens are a sub-category of [definition tokens](#definition-tokens) that can only be used in the names of [objects](#def-objects) but do not change the object into an invisible [definition object](#definition-objects). -Objects that have one or more of these definition tokens are treated as [visible objects](#def-visible-object) and they govern some aspect of the [faces](#def-face) they are related to. +Objects that have one or more of these definition tokens are treated as [visible objects](#def-visible-object) and they govern some aspect of the [faces](#def-face) of the [mesh](#def-mesh) in that object. :exclamation: Each definition token may only appear once in a name field but a name may contain both definition tokens. @@ -454,9 +454,9 @@ Coverage | See [Defining Quad Sorting & Coverage](#defining-quad-sections--cover #### Defining Quad Sections & Coverage #### BLB files allow [mesh](#def-mesh) [faces](#def-face) to be sorted into seven sections: top, bottom, north, east, south, west, and omni. -Quads in these sections may then be automatically hidden in-game using the [coverage system](#def-coverage), if it is defined correctly in the BLB file. +Quads in these sections may then be automatically hidden in-game using the [coverage system](#def-coverage), if it is defined in a meaningful way in the BLB file. -The coverage system allows the game to not render quads that are completely covered by adjacent bricks improving frame rate when a large number of bricks are on the screen at once. +The coverage system allows the game to skip rendering quads that are completely covered by adjacent bricks improving the frame rate when a large number of bricks are on the screen at once. Quads are sorted into these sections by using one of the tokens below in the name of the [object](#def-object) containing the faces to be sorted into that section. If a [visible object](#def-visible-object) has no quad sorting token specified, the omni section is used. @@ -468,7 +468,7 @@ Default Token | Section `qe` | East `qs` | South `qw` | West -`qo` | Omni ("any" or "none", default) +`qo` | Omni ("any" or "none", **default**) :exclamation: Sorting quads in this manner is pointless unless the [Coverage](#coverage) property in the export dialog is enabled and at least one option is enabled. @@ -486,15 +486,15 @@ See [RGBA Color Format](#rgba-color-format) for a detailed explanation of how to Method | Overrides | Extent of Coloring | RGB Values | Alpha Value | Notes -------|-----------|--------------------|------------|-------------|------ -Object Colors | In-game paint color | Entire object (color & alpha)| In object name after the [Color token](#mesh-definition-tokens-color) | In object name after the red, green, and blue values | Implemented only to support legacy brick models, **not recommended for use**. +Object Colors | In-game paint color | Entire object (color & alpha)| In [object](#def-object) name after the [Color token](#mesh-definition-tokens-color) | In object name after the red, green, and blue values | Implemented only to support legacy brick [models](#def-model), **not recommended for use**. Material Colors | Object Colors | Assigned faces (color & alpha) | In `Material` tab as `Diffuse Color` | In `Material` tab under `Transparency` in `Alpha` slider| The **recommended method** for defining color. Multiple materials may be used in a single object. -Vertex Colors | Material Colors | Entire object (per-vertex color), entire object (alpha) | In `Data` tab under `Vertex Color` as a vertex color layer, modified using the `Vertex Paint` mode | In `Data` tab under `Vertex Color` as the name of the vertex color layer | Creating a vertex color layers will color the entire object white, but the color of individual vertices may be changed. +Vertex Colors | Material Colors | Entire [object](#def-object) (per-vertex color), entire object (alpha) | In `Data` tab under `Vertex Color` as a vertex color layer, modified using the `Vertex Paint` mode | In `Data` tab under `Vertex Color` as the name of the vertex color layer | Creating a vertex color layers will color the entire object white, but the color of individual vertices may be changed. There are three definition tokens that are specific to dealing with colors. Token | Usable In | Description ------|-----------|------------ -`blank` | Material name | Ignore the material's color and do not write any color for the faces with this material assigned so they can be colored by the spray can in-game. This feature exists because an object that has a material, cannot have faces that do not have a material assigned to them. +`blank` | Material name | Ignore the material's color and do not write any color for the faces with this material assigned so they can be colored by the spray can in-game. This feature exists because an [object](#def-object) that has a material, cannot have faces that do not have a material assigned to them. `cadd` | Material name, vertex color layer name | Use this color as an additive color: add the values of this color to the spray can color in-game. For example to make the spray can color **a little lighter** use a **dark gray** color. `csub` | Material name, vertex color layer name | Use this color as a subtractive color: subtract the values of this color from the spray can color in-game. For example to make the spray can color **a lot darker** use a **light gray** color. @@ -505,17 +505,16 @@ The exporter understands two ways of defining an RGBA color using text. 1. The commonly used method of writing 4 integers that are in the range 0–255, where 0 is black, separated with a whitespace character such as a space. For example `127 255 10 191` for a yellow-green color that is 25% transparent. -A full object name could be for example `glass c 240 255 255 128.001`. +A full [object](#def-object) name could be for example `glass c 240 255 255 128.001`. - In the above example the running index `.001` that Blender added at the end would be removed by the exporter. 1. Writing 4 decimals in the range 0.0–1.0, where 0.0 is black, separated with a whitespace character such as a space. -An object could have a name such as `c 0,125 0,0 0,5 1,0 flower`, for example. +An [object](#def-object) could have a name such as `c 0,125 0,0 0,5 1,0 flower`, for example. - The leading zero may be omitted. - Up to 16 decimals are supported. ## Definition Objects ## -When a definition object token is read in an object's name it is treated as a definition object. -Definition objects are never exported as visual 3D models, in fact they are not exported at all. -Instead the data they contain in their name (or elsewhere) and the 3D space they represent is processed further to acquire the necessary information for the BLB file. +When a specific definition token is read in an [object's](#def-object) name it is treated as a definition object. +Definition objects contain non-visual data about the [brick](#def-brick) and as such are not exported as [visual objects](#def-visual-object) Definition Object | Default Token | Requirements | Maximum Count/Brick | Must Be Within [**Bounds**](#definition-objects-bounds) | Axis-Aligned | Brick Grid Aligned | Can Overlap | Description ------------------|---------------|--------------|--------------------:|:-------------------:|:------------:|:------------------:|:-----------:|------------ @@ -592,7 +591,7 @@ If using brick textures on non-rectangular quads it is recommended to manually d ## Troubleshooting ## Solutions to common issues with the BLB Exporter. If you have another issue with the exporter be sure to enable the [Write Log](#write-log) property and export again. -The log file may contain warnings or errors describing issues with the models and how to fix them. +The log file may contain warnings or errors describing issues with the [objects](#def-object) and how to fix them. Additional instructions on how to fix specific issues are detailed in the [Warning & Error Log Messages](#warning--error-log-messages) section. ### Automatically calculated UV coordinates for brick textures are distorted ### @@ -603,7 +602,7 @@ Manually define UV coordinates for non-rectangular quads. The quad with incorrectly rotated UV coordinates (e.g. the lightest side of the SIDE texture pointing sideways instead of up) is not a perfect rectangle. Even one vertex being off by some minuscule, visually indistinguishable amount from a perfectly rectangular shape can cause the automatic UV calculation to incorrectly determine the rotation of the quad. Double check all 4 coordinates of the quad and manually correct any floating point errors. -If working on axis-aligned quads or if the vertices should be on grid points snapping the coordinates of the problem quad to grid coordinates using `Mesh > Snap > Snap Selection to Grid` usually fixes floating point errors. +If working on axis-aligned quads or if the vertices should be on grid points snapping the coordinates of the problem quad to grid coordinates by selecting `Mesh > Snap > Snap Selection to Grid` in the 3D viewport toolbar usually fixes floating point errors. ### The TOP brick texture has incorrect rotation in Blender ### Blockland automatically performs rotations on the UV coordinates of the TOP brick texture during runtime so that the lightest side of the texture is always facing towards the sun. @@ -630,7 +629,7 @@ It is recommended to manually adjust the brick until no warning messages are pre Cause - No bounds object was defined and the axis-aligned bounding box calculated from the visible 3D models has non-integer dimensions as a brick. + No bounds object was defined and the axis-aligned bounding box calculated from the has non-integer dimensions when converted to brick space. Effect @@ -640,7 +639,7 @@ It is recommended to manually adjust the brick until no warning messages are pre Solutions
    1. Recommended: Manually define a bounds object.
    2. -
    3. Manually ensure that the visible parts of your brick model form an axis-aligned bounding box that has a valid size for a brick.
    4. +
    5. Manually ensure that the visible objects of your brick model form an axis-aligned bounding box that has a valid size for a brick.
    @@ -685,7 +684,7 @@ It is recommended to manually adjust the brick until no warning messages are pre Solution - Create a bounds object and in the name of the object separate the name of the BLB file from the bounds definition token with a whitespace character. + Create a bounds object and in the name of the object separate the name of the BLB file from the bounds definition token with a whitespace character. @@ -730,7 +729,7 @@ It is recommended to manually adjust the brick until no warning messages are pre - +
    SolutionCreate brick grid definitions for the model.Create brick grid definitions for the model.
    @@ -753,7 +752,7 @@ It is recommended to manually adjust the brick until no warning messages are pre - +
    SolutionCreate valid brick grid definitions for the model.Create valid brick grid definitions for the model.
    @@ -796,7 +795,7 @@ It is recommended to manually adjust the brick until no warning messages are pre - + @@ -814,7 +813,7 @@ It is recommended to manually adjust the brick until no warning messages are pre - + @@ -880,7 +879,7 @@ It is recommended to manually adjust the brick until no warning messages are pre - + @@ -894,7 +893,7 @@ It is recommended to manually adjust the brick until no warning messages are pre - +
    EffectThe axis-aligned bounding box of all visible meshes will rounded to the nearest brick dimensions and used as the brick bounds.The axis-aligned bounding box of all visible objects will rounded to the nearest brick dimensions and used as the brick bounds.
    Solution
    CauseThe object had more than one vertex color layer.The object had more than one vertex color layer.
    Effect
    CauseA mesh contained a triangle.A mesh contained a triangle.
    Effect
    SolutionDo not use triangles in any meshes.Do not use triangles in any meshes.
    @@ -908,7 +907,7 @@ It is recommended to manually adjust the brick until no warning messages are pre - + @@ -1033,7 +1032,7 @@ Fatal errors always lead to the program execution stopping. - + @@ -1063,7 +1062,10 @@ Fatal errors always lead to the program execution stopping. - +
    CauseA mesh contained a face made from more than 4 vertices.A mesh contained a face made from more than 4 vertices.
    Effect
    CauseThe Store UVs property is enabled and the exporter attempted to write UV coordinates to a Blender object that is currently in edit mode.The Store UVs property is enabled and the exporter attempted to write UV coordinates to a Blender object that is currently in edit mode.
    Reason
    SolutionEnsure that the manually defined bounds definition object or if none is defined, the actual model of the brick, is larger than a 1x1 plate brick.
    @@ -1099,7 +1101,7 @@ Fatal errors always lead to the program execution stopping. - + @@ -1134,7 +1136,7 @@ Fatal errors always lead to the program execution stopping. - @@ -1160,7 +1162,7 @@ Fatal errors always lead to the program execution stopping. - + @@ -1206,7 +1208,7 @@ Fatal errors always lead to the program execution stopping. - +
    CauseNone of the non-definition objects had any faces.None of the had any faces.
    Reason
    Single SelectionNo objects were selected. + No objects were selected. Selected objects have an orange outline.
    Multiple Layers GroupsNone of the groups in the current scene had any objects in the visible layers.None of the groups in the current scene had any objects in the visible layers.
    Layers
    SceneAdd objects to a layer in the scene or check that you are not in the wrong scene.Add objects to a layer in the scene or check that you are not in the wrong scene.
    @@ -1223,7 +1225,7 @@ Fatal errors always lead to the program execution stopping. Multiple Layers Groups - Ensure that your groups have objects assigned to them and that you have selected layers with objects in them. + Ensure that your groups have objects assigned to them and that you have selected layers with objects in them. Layers @@ -1295,7 +1297,7 @@ Fatal errors always lead to the program execution stopping. - And the current scene does not contain any groups with objects in visible layers. + And the current scene does not contain any groups with objects in visible layers. @@ -1337,7 +1339,7 @@ Fatal errors always lead to the program execution stopping. - And the current scene does not contain any objects in visible layers. + And the current scene does not contain any objects in visible layers. @@ -1398,7 +1400,7 @@ Fatal errors always lead to the program execution stopping. Solutions
    • Recommended: Manually create a bounds definition object that properly fits around the defined brick grid.
    • -
    • Ensure that the specified brick grid definition object is fully contained within the axis-aligned bounding box of the visual model.
    • +
    • Ensure that the specified brick grid definition object is fully contained within the axis-aligned bounding box of the .
    @@ -1476,7 +1478,7 @@ Fatal errors always lead to the program execution stopping. Effect - Only the 10 oldest objects marked as collision definitions will be used. + Only the 10 oldest objects marked as collision definitions will be used. Solution @@ -1560,7 +1562,7 @@ Fatal errors always lead to the program execution stopping. Solutions
    • Recommended: Manually create a bounds definition object that properly fits around the defined collision definition objects.
    • -
    • Ensure that the specified brick grid definition object is fully contained within the axis-aligned bounding box of the visual model.
    • +
    • Ensure that the specified brick grid definition object is fully contained within the axis-aligned bounding box of the .
    @@ -1604,15 +1606,15 @@ Fatal errors always lead to the program execution stopping. Cause - A non-mesh object such as a camera had a bounds definition token in its name. + A non-definition token in its name. Reason - Non-mesh objects do not contain data that can be used to calculate an axis-aligned bounding box. + Non-axis-aligned bounding box. Effect - The specified object is ignored. + The specified object is ignored. Solution @@ -1630,15 +1632,15 @@ Fatal errors always lead to the program execution stopping. Cause - A non-mesh object such as a camera had a brick grid definition token in its name. + A non-definition token in its name. Reason - Non-mesh objects do not contain data that can be used to calculate an axis-aligned bounding box. + Non-axis-aligned bounding box. Effect - The specified object is ignored. + The specified object is ignored. Solution @@ -1656,15 +1658,15 @@ Fatal errors always lead to the program execution stopping. Cause - A non-mesh object such as a camera had a collision definition token in its name. + A non-definition token in its name. Reason - Non-mesh objects do not contain data that can be used to calculate an axis-aligned bounding box. + Non-axis-aligned bounding box. Effect - The specified object is ignored. + The specified object is ignored. Solution @@ -1686,7 +1688,7 @@ Fatal errors always lead to the program execution stopping. Reason - Although it is technically possible to calculate the axis-aligned bounding box of multiple bounds definitions and use that as the final bounds of the brick a feature like this would be confusing for beginner users and breaks the "what you see is what you get" principle of the exporter. + Although it is technically possible to calculate the axis-aligned bounding box of multiple bounds definitions and use that as the final bounds of the brick a feature like this would be confusing for beginner users and breaks the "what you see is what you get" principle of the exporter. Effect @@ -1712,7 +1714,7 @@ Fatal errors always lead to the program execution stopping. Reason - One definition object may only be used to define one brick placement rule. + One brick grid definition object may only be used to define one brick placement rule. Effect @@ -1804,11 +1806,10 @@ Fatal errors always lead to the program execution stopping. ## Rounded Values ## Floating point numbers (numbers with a decimal point) contain [inherent inaccuracies](https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems). -For example when exporting a 1x1x1 brick model at the maximum accuracy the vertex coordinate of one of the corners is `0.5 0.5 1.5000000596046448`. +For example when exporting a 1x1x1 brick [model](#def-model) at the maximum accuracy the vertex coordinate of one of the corners is `0.5 0.5 1.5000000596046448`. This causes the 1x1x1 brick to be `3.00000011920928955078125` plates tall instead of exactly `3.0` like it should. -The only way to get rid of this error is to round the number (vertex coordinates). +The only way to get fix this error is to round the vertex coordinates. Practically speaking it is impossible to visually discern the difference between a brick that is 3 plates tall versus one that is `3.00000011920928955078125` plates tall in the game. -The floating point errors are effectively 0. The only real benefit that comes from the rounding is nicer looking .BLB files. The default value of `0.000001` was chosen through manual testing. @@ -1816,11 +1817,11 @@ Rest assured that the rounding will cause no visual oddities whatsoever because This was manually confirmed with a sphere brick made from 524288 quads. Moving the camera as close to the surface of the brick as the game was capable of rendering, the surface of the sphere appeared mathematically perfect because the distance between the vertices was less than the size of a single pixel. -:exclamation: The exporter will only ever write 16 decimal places regardless of the precision of the value. +:exclamation: The exporter will only ever write up to 16 decimal places regardless of the precision of the value. Floating Point Value | Rounded ---------------------|:------: -Visible mesh vertex coordinates | Yes +[Visible object](#def-visible-object) vertex coordinates | Yes [Bounds object](#definition-objects-bounds) vertex coordinates | Yes [Collision object](#definition-objects-collision) vertex coordinates | Yes [Brick grid object](#defining-brick-grid) vertex coordinates | Yes @@ -1831,7 +1832,7 @@ Normal vectors | [Optional](#round-normals) ## Contributors ## - [Nick Smith](https://github.com/qoh) - The original source code for reading, processing, and writing Blender data into the .BLB format. A majority of his code has been rewritten since. -- [Demian Wright](https://github.com/DemianWright) - Significant extensions and rewrites to Nick's original code and everything else. +- [Demian Wright](https://github.com/DemianWright) - Significant extensions and rewrites to Nick's original code and all additional features. __*__ There's always a footnote, see the issue with [the TOP brick texture](#the-top-brick-texture-has-incorrect-rotation-in-blender). diff --git a/__init__.py b/__init__.py index ed5d9dc..f784e77 100644 --- a/__init__.py +++ b/__init__.py @@ -49,7 +49,6 @@ # TODO: Serialize props to the start of the log? # TODO: Add a section about brick grid to the readme. # TODO: Make the capitalization consistent in the readme. -# TODO: Consider refactoring readme for consistent use of mesh, model, and object words. # TODO: Clarify brick grid and brick grid placement rules. From 605a62903d7df9a7249244628db5892ff8db4904 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 19 Nov 2017 12:32:23 +0200 Subject: [PATCH 46/50] Add Pretty Print property, improve Precision property --- README.md | 28 ++++++++++++++++++++++++++++ __init__.py | 12 ++++++++++++ blb_writer.py | 32 +++++++++++++++----------------- dev/export-blb.py | 1 + export_blb.py | 34 +++++++++++++++++++++++++--------- 5 files changed, 81 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 92c19a7..2f95f45 100644 --- a/README.md +++ b/README.md @@ -378,6 +378,12 @@ Shows additional settings when selected. See [Definition Tokens](#definition-tokens) for more information. (Default: `False`) +#### Pretty Print #### +When enabled does not write extraneous zeros to the end of floating point numbers. +Additionally if a numerical value is exactly equal to an integer, no decimal places are written. +If disabled will write all floating point numbers using as many decimal places as used in the [Precision](#precision) property. +(Default: `True`) + #### Terse Mode #### When enabled does not write optional lines to the .BLB file such as the lines marking the different quad sections. Using this option is not recommended as it makes the .BLB file harder to read and understand. @@ -918,6 +924,28 @@ It is recommended to manually adjust the brick until no warning messages are pre Manually rebuild faces made from more than 4 vertices using quads. + + + + + + + + + + + + + + + + + + + + + +
    CodeIOBLBW013
    MessagePrecision has too many decimal digits, using 16 instead.
    CauseThe precision value set in the Precision property had more than 16 decimal digits.
    EffectIf Pretty Print is disabled the number of decimal digits written to the BLB file is clamped to 16.
    SolutionOnly write up to 16 decimal places in the Precision value.
    ### Errors ### Errors are separated into two categories: fatal and non-fatal errors. diff --git a/__init__.py b/__init__.py index f784e77..412e2bc 100644 --- a/__init__.py +++ b/__init__.py @@ -521,6 +521,15 @@ class ExportBLB(bpy.types.Operator, ExportHelper): # Writing # ======= + # ------------ + # Pretty Print + # ------------ + pretty_print = BoolProperty( + name="Pretty Print", + description="Trim unnecessary zeros from the end of all numbers and if a number is an integer, do not write any decimal places. If false will write as many decimal places as set in the Precision property.", + default=True, + ) + # ---------- # Terse Mode # ---------- @@ -893,6 +902,9 @@ def draw_coverage_property(label_text): row.alignment = "CENTER" row.label("File Writing", icon="TEXT") + # Property: Pretty Print + layout.prop(self, "pretty_print") + # Property: Terse Mode layout.prop(self, "terse_mode") diff --git a/blb_writer.py b/blb_writer.py index 4e404a3..84d0972 100644 --- a/blb_writer.py +++ b/blb_writer.py @@ -25,15 +25,15 @@ from . import const -def __get_sequence_string(sequence, new_line=True, decimal_digits=const.MAX_FP_DECIMALS_TO_WRITE): +def __get_sequence_string(sequence, pretty_print, decimal_digits=const.MAX_FP_DECIMALS_TO_WRITE, new_line=True): """Writes the values of the specified sequence separated with spaces into the specified file. An optional new line character is added at the end of the line by default. Args: sequence (sequence): A sequence of data to be written. - new_line (bool): Add a newline character at the end of the line? (Default: True) decimal_digits (int): The number of decimal digits to write if the sequence contains floating point values or None to ignore. (Default: const.MAX_FP_DECIMALS_TO_WRITE) The default value prevents very small values from being written in scientific notation, which the game does not understand. + new_line (bool): Add a newline character at the end of the line? (Default: True) """ parts = [] @@ -41,15 +41,13 @@ def __get_sequence_string(sequence, new_line=True, decimal_digits=const.MAX_FP_D if index != 0: # Add a space before each value except the first one. parts.append(" ") - if value == 0: - # Handle zeros. - parts.append("0") + + # Format the value into string. + if pretty_print and decimal_digits != 0: + # Remove all zeros from the end (if any), then remove all periods from the end (if any). + parts.append("{0:.{1}f}".format(value, decimal_digits).rstrip("0").rstrip(".")) else: - # Format the value into string, remove all zeros from the end (if any), then remove all periods from the end (if any). - if decimal_digits is None: - parts.append("{}".format(value).rstrip("0").rstrip(".")) - else: - parts.append("{0:.{1}f}".format(value, decimal_digits).rstrip("0").rstrip(".")) + parts.append("{0:.{1}f}".format(value, decimal_digits)) if new_line: # Add a new line after all values. parts.append("\n") @@ -70,7 +68,7 @@ def write_file(properties, filepath, blb_data): # ---------- # Brick Size # ---------- - lines.append(__get_sequence_string(blb_data.brick_size)) + lines.append(__get_sequence_string(blb_data.brick_size, False, 0)) # ---------- # Brick Type @@ -101,8 +99,8 @@ def write_file(properties, filepath, blb_data): # Write the defined collision cuboids. for (center, dimensions) in blb_data.collision: lines.append("\n") - lines.append(__get_sequence_string(center)) - lines.append(__get_sequence_string(dimensions)) + lines.append(__get_sequence_string(center, properties.blendprop.pretty_print, properties.decimal_digits)) + lines.append(__get_sequence_string(dimensions, properties.blendprop.pretty_print, properties.decimal_digits)) # -------- # Coverage @@ -131,23 +129,23 @@ def write_file(properties, filepath, blb_data): lines.append("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_HEADER_POSITION)) for position in positions: - lines.append(__get_sequence_string(position)) + lines.append(__get_sequence_string(position, properties.blendprop.pretty_print, properties.decimal_digits)) # Face UV coordinates. lines.append("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_HEADER_UV)) for uv_pair in uvs: - lines.append(__get_sequence_string(uv_pair)) + lines.append(__get_sequence_string(uv_pair, properties.blendprop.pretty_print, properties.decimal_digits)) # Vertex colors, if any. if colors is not None: lines.append("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_HEADER_COLORS)) for color in colors: - lines.append(__get_sequence_string(color)) + lines.append(__get_sequence_string(color, properties.blendprop.pretty_print, properties.decimal_digits)) # Vertex normals. lines.append("{}\n".format("" if properties.blendprop.terse_mode else const.BLB_HEADER_NORMALS)) for normal in normals: - lines.append(__get_sequence_string(normal)) + lines.append(__get_sequence_string(normal, properties.blendprop.pretty_print, properties.decimal_digits)) with open(filepath, "w") as file: for line in lines: diff --git a/dev/export-blb.py b/dev/export-blb.py index 801e7eb..6c47526 100644 --- a/dev/export-blb.py +++ b/dev/export-blb.py @@ -58,6 +58,7 @@ deftoken_gridu_priority=pd['deftoken_gridu_priority'], deftoken_gridd_priority=pd['deftoken_gridd_priority'], deftoken_gridb_priority=pd['deftoken_gridb_priority'], + pretty_print=pd['pretty_print'], terse_mode=pd['terse_mode'], write_log=pd['write_log'], write_log_warnings=pd['write_log_warnings'], diff --git a/export_blb.py b/export_blb.py index 0bb430f..ed381d9 100644 --- a/export_blb.py +++ b/export_blb.py @@ -64,6 +64,7 @@ class DerivativeProperties(object): plate_height (Decimal): The height of one Blockland plate in Blender units. human_brick_grid_error (Decimal): Error allowed for manually created definition objects, because they must lie exactly on the brick grid. precision (String): The precision to round floating point numbers to when performing calculations. + decimal_digits (int): The number of decimal digits in precision. """ def __init__(self, properties): @@ -72,6 +73,8 @@ def __init__(self, properties): Args: properties (Blender properties object): A Blender object containing user preferences. """ + logger.info("Export Properties:") + # ========== # Properties # ========== @@ -111,7 +114,7 @@ def __init__(self, properties): # ===== # export_scale is a percentage value. self.scale = Decimal("{0:.{1}f}".format(properties.export_scale, const.MAX_FP_DECIMALS_TO_WRITE)) * Decimal("0.01") - logger.info("Export at {} scale.".format(self.scale)) + logger.info("Scale: {}".format(self.scale.normalize()), 1) # ========================== # Plate Height & Human Error @@ -127,19 +130,32 @@ def __init__(self, properties): # ========= # Precision # ========= - prec = properties.float_precision + prec = common.to_float_or_none(properties.float_precision) - if common.to_float_or_none(prec) is None: + if prec is None: self.error_message = "IOBLBF010 Invalid floating point value given for floating point precision property." else: - if prec == "0": - logger.info("Setting floating point precision to minimum.") - # We're only writing 16 decimals anyway. - prec = "0.{}1".format("0" * (const.MAX_FP_DECIMALS_TO_WRITE - 1)) + min_prec = "0.{}1".format("0" * (const.MAX_FP_DECIMALS_TO_WRITE - 1)) + dot_idx = properties.float_precision.find(".") - logger.info("Using floating point precision: {}".format(prec)) + if dot_idx < 0: + self.decimal_digits = 0 + else: + self.decimal_digits = len(properties.float_precision) - (dot_idx + 1) + + if properties.float_precision == "0" or Decimal(properties.float_precision) < Decimal(min_prec): + logger.info("Setting floating point precision to minimum.", 1) + self.precision = min_prec + self.decimal_digits = const.MAX_FP_DECIMALS_TO_WRITE + elif self.decimal_digits > const.MAX_FP_DECIMALS_TO_WRITE: + logger.warning("IOBLBW013", "Precision has too many decimal digits, using {} instead.".format(const.MAX_FP_DECIMALS_TO_WRITE), 1) + self.decimal_digits = const.MAX_FP_DECIMALS_TO_WRITE + self.precision = properties.float_precision[:dot_idx] + "." + \ + properties.float_precision[dot_idx + 1:dot_idx + 1 + const.MAX_FP_DECIMALS_TO_WRITE] + else: + self.precision = properties.float_precision - self.precision = prec + logger.info("Floating point precision: {}".format(self.precision), 1) @classmethod def __build_grid_priority_tuples(cls, properties): From ee4f7a822c9d59acd3b8732c7ac35f4d61ad26a6 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 19 Nov 2017 12:46:53 +0200 Subject: [PATCH 47/50] Reorder properties, add missing and remove old properties from README --- README.md | 116 +++++++++++++++++++++++++++++----------------------- __init__.py | 32 +++++++-------- 2 files changed, 81 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 2f95f45..d45323b 100644 --- a/README.md +++ b/README.md @@ -12,30 +12,35 @@ The add-on does not support importing .BLB files yet. 1. [Installation](#installation) 1. [Updating](#updating) 1. [Terminology](#terminology) -1. [Blender Export Properties](#blender-export-properties) - 1. [Bricks to Export](#bricks-to-export) - 1. [Brick Name from (Single Export)](#brick-name-from-single-export) - 1. [Export Only (Single Export)](#export-only-single-export) - 1. [Brick Names from (Multiple Export)](#brick-names-from-multiple-export) - 1. [Bricks Defined by (Multiple Export)](#bricks-defined-by-multiple-export) - 1. [Export Bricks in (Multiple Export)](#export-bricks-in-multiple-export) - 1. [Forward Axis](#forward-axis) - 1. [Scale](#scale) - 1. [Apply Modifiers](#apply-modifiers) - 1. [Calculate Collision](#calculate-collision) - 1. [Coverage](#coverage) - 1. [Automatic Quad Sorting](#automatic-quad-sorting) - 1. [Use Material Colors](#use-material-colors) - 1. [Use Vertex Colors](#use-vertex-colors) - 1. [Parse Object Colors](#parse-object-colors) - 1. [Calculate UVs](#calculate-uvs) - 1. [Store UVs](#store-uvs) - 1. [Round Normals](#round-normals) - 1. [Custom Definition Tokens](#custom-definition-tokens) - 1. [Terse Mode](#terse-mode) - 1. [Write Log](#write-log) - 1. [Only on Warnings](#only-on-warnings) - 1. [Precision](#precision) +1. [Export Properties](#export-properties) + 1. [Blender Properties](#blender-properties) + 1. [Bricks to Export](#bricks-to-export) + 1. [Brick Name from (Single Export)](#brick-name-from-single-export) + 1. [Export Only (Single Export)](#export-only-single-export) + 1. [Brick Names from (Multiple Export)](#brick-names-from-multiple-export) + 1. [Bricks Defined by (Multiple Export)](#bricks-defined-by-multiple-export) + 1. [Export Bricks in (Multiple Export)](#export-bricks-in-multiple-export) + 1. [Forward Axis](#forward-axis) + 1. [Scale](#scale) + 1. [Apply Modifiers](#apply-modifiers) + 1. [Custom Definition Tokens](#custom-definition-tokens) + 1. [BLB Properties](#blb-properties) + 1. [Custom Collision](#custom-collision) + 1. [Fallback Collision](#fallback-collision) + 1. [Calculate Coverage](#calculate-coverage) + 1. [Automatic Quad Sorting](#automatic-quad-sorting) + 1. [Use Material Colors](#use-material-colors) + 1. [Use Vertex Colors](#use-vertex-colors) + 1. [Parse Object Colors](#parse-object-colors) + 1. [Calculate UVs](#calculate-uvs) + 1. [Store UVs](#store-uvs) + 1. [Round Normals](#round-normals) + 1. [Precision](#precision) + 1. [File Properties](#file-properties) + 1. [Pretty Print](#pretty-print) + 1. [Write Log](#write-log) + 1. [Only on Warnings](#only-on-warnings) + 1. [Terse Mode](#terse-mode) 1. [Brick Scale](#brick-scale) 1. [Definition Tokens](#definition-tokens) 1. [Mesh Definition Tokens](#mesh-definition-tokens) @@ -244,8 +249,10 @@ Visible objects are rendered and are seen in-game as a bric
    In Blender, commonly a space or a tab character.
    -## Blender Export Properties ## -The following properties are present in the current version of the exporter. +## Export Properties ## +The following user properties are present in the current version of the exporter. + +### Blender Properties ### #### Bricks to Export #### How many bricks to export in one go from the file. @@ -319,6 +326,15 @@ Applies any modifiers on the [object](#def-object) before exporting. Does not change the modifiers of the objects in the Blender scene. (Default: `True`) +#### Custom Definition Tokens #### +Allows you to specify the definition tokens the exporter uses. +See [Definition Tokens](#definition-tokens) for more information. +(Default: `False`) + +:bulb: Enabling this property shows additional properties. + +### BLB Properties ### + #### Custom Collision #### Export custom collision definitions if there are any. See [Defining Collision](#defining-collision). @@ -326,19 +342,21 @@ See [Defining Collision](#defining-collision). #### Fallback Collision #### The type of collision to calculate for the brick if no custom collision definitions are found. +Enabling this property shows additional properties. Value | Description ------|------------ Bounds | Use the defined or calculated [bounds](#definition-objects-bounds) of the brick as the collision cuboid. **(Default)** AABB | Calculate the [axis-aligned bounding box](#def-aabb) of all [visible objects](#def-visible-object) and use that as the collision cuboid. -#### Coverage #### +#### Calculate Coverage #### Enable coverage calculations. -Shows additional settings when selected. This is pointless unless [Automatic Quad Sorting](#automatic-quad-sorting) is enabled or at least one [object](#def-object) has a quad sorting definition. See [Defining Quad Sorting & Coverage](#defining-quad-sections--coverage) for more information. (Default: `False`) +:bulb: Enabling this property shows additional properties. + #### Automatic Quad Sorting #### Automatically calculate the correct section for quads that in the same plane as the bounding planes of the bounds object. This is pointless unless [Coverage](#coverage) is enabled. @@ -372,11 +390,12 @@ Round vertex normals to the user-defined floating point value precision. If disabled normals will be written as accurately as possible but extraneous zeros will still be removed. (Default: `False`) -#### Custom Definition Tokens #### -Allows you to specify the definition tokens the exporter uses. -Shows additional settings when selected. -See [Definition Tokens](#definition-tokens) for more information. -(Default: `False`) +#### Precision #### +Allows you to specify a custom precision for floating point numbers. +See [Rounded Values](#rounded-values) for more details. +(Default: `0.000001`) + +### File Properties ### #### Pretty Print #### When enabled does not write extraneous zeros to the end of floating point numbers. @@ -384,12 +403,6 @@ Additionally if a numerical value is exactly equal to an integer, no decimal pla If disabled will write all floating point numbers using as many decimal places as used in the [Precision](#precision) property. (Default: `True`) -#### Terse Mode #### -When enabled does not write optional lines to the .BLB file such as the lines marking the different quad sections. -Using this option is not recommended as it makes the .BLB file harder to read and understand. -Although the file is shorter, the difference in file size is negligible. -(Default: `False`) - #### Write Log #### Write a log file to the same folder as the exported brick detailing the export process. Shows additional settings when selected. @@ -399,10 +412,11 @@ Shows additional settings when selected. Write a log file only if warnings or errors occurred during the export process. (Default: `True`) -#### Precision #### -Allows you to specify a custom precision for floating point numbers. -See [Rounded Values](#rounded-values) for more details. -(Default: `0.000001`) +#### Terse Mode #### +When enabled does not write optional lines to the .BLB file such as the lines marking the different quad sections. +Using this option is not recommended as it makes the .BLB file harder to read and understand. +Although the file is shorter, the difference in file size is negligible. +(Default: `False`) ## Brick Scale ## This add-on defines a `1x1x1` Blockland brick to be exactly `1.0 1.0 1.2` Blender units on the X, Y, and Z axes. @@ -682,7 +696,7 @@ It is recommended to manually adjust the brick until no warning messages are pre Cause - The "Brick Name(s) from" export property (either in single or multiple brick export mode) value was set to Bounds but no manually defined bounds object was found. + The "Brick Name(s) from" export property (either in single or multiple brick export mode) value was set to Bounds but no manually defined bounds object was found. Effect @@ -704,7 +718,7 @@ It is recommended to manually adjust the brick until no warning messages are pre Cause - The "Brick Name(s) from" export property (either in single or multiple brick export mode) value was set to Bounds but no string was found after the bounds definition token in the name of the bounds object. + The "Brick Name(s) from" export property (either in single or multiple brick export mode) value was set to Bounds but no string was found after the bounds definition token in the name of the bounds object. Effect @@ -968,7 +982,7 @@ Fatal errors always lead to the program execution stopping. Cause - The following export properties are set: + The following export properties are set: @@ -1014,7 +1028,7 @@ Fatal errors always lead to the program execution stopping. -
    CauseThe following export properties are set: + The following export properties are set: @@ -1151,7 +1165,7 @@ Fatal errors always lead to the program execution stopping. -
    CausesDepends on the values of various export properties. + Depends on the values of various export properties. @@ -1215,7 +1229,7 @@ Fatal errors always lead to the program execution stopping. -
    SolutionsDepends on the values of various export properties. + Depends on the values of various export properties. @@ -1306,7 +1320,7 @@ Fatal errors always lead to the program execution stopping. -
    CauseThe following export properties are set: + The following export properties are set: @@ -1348,7 +1362,7 @@ Fatal errors always lead to the program execution stopping. -
    CauseThe following export properties are set: + The following export properties are set: diff --git a/__init__.py b/__init__.py index 412e2bc..4a261cc 100644 --- a/__init__.py +++ b/__init__.py @@ -137,9 +137,9 @@ class ExportBLB(bpy.types.Operator, ExportHelper): default="LAYERS" ) - # -------- - # Rotation - # -------- + # ------------ + # Forward Axis + # ------------ # For whatever reason BLB coordinates are rotated 90 degrees counter-clockwise to Blender coordinates. # I.e. -X is facing you when the brick is planted and +X is the brick north instead of +Y which makes more sense to me. # TODO: Support Z axis remapping. @@ -530,15 +530,6 @@ class ExportBLB(bpy.types.Operator, ExportHelper): default=True, ) - # ---------- - # Terse Mode - # ---------- - terse_mode = BoolProperty( - name="Terse Mode", - description="Exclude optional text from the BLB file making it slightly smaller and harder to read (not recommended, file size difference is negligible)", - default=False, - ) - # --- # Log # --- @@ -555,6 +546,15 @@ class ExportBLB(bpy.types.Operator, ExportHelper): default=True, ) + # ---------- + # Terse Mode + # ---------- + terse_mode = BoolProperty( + name="Terse Mode", + description="Exclude optional text from the BLB file making it slightly smaller and harder to read (not recommended, file size difference is negligible)", + default=False, + ) + # =============== # Export Function # =============== @@ -900,14 +900,11 @@ def draw_coverage_property(label_text): # ======= row = layout.row() row.alignment = "CENTER" - row.label("File Writing", icon="TEXT") + row.label("File Properties", icon="TEXT") # Property: Pretty Print layout.prop(self, "pretty_print") - # Property: Terse Mode - layout.prop(self, "terse_mode") - # Property: Write Log row = layout.row() split = row.split(percentage=0.4) @@ -927,6 +924,9 @@ def draw_coverage_property(label_text): col = split.column() col.prop(self, "write_log_warnings") + # Property: Terse Mode + layout.prop(self, "terse_mode") + # ============= # Blender Stuff # ============= From 566818627954d9f444b8528f3f53c825ed49a4d6 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 19 Nov 2017 12:50:43 +0200 Subject: [PATCH 48/50] Minor change to Planned Features in README --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d45323b..0dde301 100644 --- a/README.md +++ b/README.md @@ -110,11 +110,12 @@ The exporter supports all BLB features. ### Planned Features ### These features may or may not be implemented at some unspecified time in the future. +Listed below approximately in the order they are planned to be implemented in. -- Exporting DTS collision using Nick Smith's [io_scene_dts](https://github.com/qoh/io_scene_dts) Blender add-on. -- Importing .BLB files -- Export-time brick rotation on the Z-axis -- Automatic rendering of the brick preview icon +1. Exporting DTS collision using Nick Smith's [io_scene_dts](https://github.com/qoh/io_scene_dts) Blender add-on. +1. Importing .BLB files. +1. Automatic rendering of the brick preview icon. +1. Export-time brick rotation on the Z-axis. ## Installation ## 1. Download the add-on using one of them methods below: From 7a6641f9c7e12123bfafebe43d930f5e03c6cb85 Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Sun, 19 Nov 2017 12:55:42 +0200 Subject: [PATCH 49/50] Reorder sections of the README, no content changes --- README.md | 412 +++++++++++++++++++++++++++--------------------------- 1 file changed, 206 insertions(+), 206 deletions(-) diff --git a/README.md b/README.md index 0dde301..474bcaf 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,18 @@ The add-on does not support importing .BLB files yet. 1. [Installation](#installation) 1. [Updating](#updating) 1. [Terminology](#terminology) +1. [Brick Scale](#brick-scale) +1. [Definition Tokens](#definition-tokens) + 1. [Mesh Definition Tokens](#mesh-definition-tokens) + 1. [Defining Quad Sections & Coverage](#defining-quad-sections--coverage) + 1. [Defining Colors](#defining-colors) + 1. [RGBA Color Format](#rgba-color-format) +1. [Definition Objects](#definition-objects) + 1. [Defining Collision](#defining-collision) + 1. [Defining Brick Grid](#defining-brick-grid) +1. [Brick Textures](#brick-textures) +1. [UV Mapping](#uv-mapping) +1. [Rounded Values](#rounded-values) 1. [Export Properties](#export-properties) 1. [Blender Properties](#blender-properties) 1. [Bricks to Export](#bricks-to-export) @@ -41,17 +53,6 @@ The add-on does not support importing .BLB files yet. 1. [Write Log](#write-log) 1. [Only on Warnings](#only-on-warnings) 1. [Terse Mode](#terse-mode) -1. [Brick Scale](#brick-scale) -1. [Definition Tokens](#definition-tokens) - 1. [Mesh Definition Tokens](#mesh-definition-tokens) - 1. [Defining Quad Sections & Coverage](#defining-quad-sections--coverage) - 1. [Defining Colors](#defining-colors) - 1. [RGBA Color Format](#rgba-color-format) -1. [Definition Objects](#definition-objects) - 1. [Defining Collision](#defining-collision) - 1. [Defining Brick Grid](#defining-brick-grid) -1. [Brick Textures](#brick-textures) -1. [UV Mapping](#uv-mapping) 1. [Troubleshooting](#troubleshooting) 1. [Automatically calculated UV coordinates for brick textures are distorted](#automatically-calculated-uv-coordinates-for-brick-textures-are-distorted) 1. [Automatically calculated UV coordinates for brick textures are rotated incorrectly](#automatically-calculated-uv-coordinates-for-brick-textures-are-rotated-incorrectly) @@ -61,7 +62,6 @@ The add-on does not support importing .BLB files yet. 1. [Errors](#errors) 1. [Fatal Errors](#fatal-errors) 1. [Non-Fatal Errors](#non-fatal-errors) -1. [Rounded Values](#rounded-values) 1. [Contributors](#contributors) ## Features ## @@ -250,175 +250,6 @@ Visible objects are rendered and are seen in-game as a bric
    In Blender, commonly a space or a tab character.
    -## Export Properties ## -The following user properties are present in the current version of the exporter. - -### Blender Properties ### - -#### Bricks to Export #### -How many bricks to export in one go from the file. - -Value | Description -------|------------ -Single | Export only one brick. **(Default)** -Multiple | Export one or more bricks. Shows additional settings when selected. - -#### Brick Name from (Single Export) #### -Where the .BLB file name is defined. - -Value | Description -------|------------ -Bounds | Brick name is defined in the [Bounds object](#definition-objects-bounds) after the bounds definition token, separated with a whitespace character. Export file dialog is only used set to directory. **(Default)** -File | Brick name is the same as the file name. Can be manually set in the export file dialog. - -#### Export Only (Single Export) #### -Which [objects](#def-object) to process and export to the .BLB file. - -Value | Description -------|------------ -Selection | Objects that are selected and have an orange outline. **(Default)** -Layers | All objects in the layers that are currently visible, regardless of selection. -Scene | All objects in the current scene. I.e. all objects in all layers regardless of the layer visibility. - -#### Brick Names from (Multiple Export) #### -Where the names of the .BLB files are defined. - -Value | Description -------|------------ -Bounds | Brick names are defined in the [Bounds object](#definition-objects-bounds) after the bounds definition token, separated with a whitespace character. Export file dialog is only used set to directory. **(Default)** -Groups | Brick names are the same as the names of the groups name. Export file dialog is only used set to directory. - -#### Bricks Defined by (Multiple Export) #### -How is a single brick defined. - -Value | Description -------|------------ -Groups | Each brick is in its own group. [Objects](#def-object) in multiple groups belong to multiple bricks. **(Default)** -Layers | Each brick is in its own layer. [Objects](#def-object) in multiple layers belong to multiple bricks. When selected brick names must be defined in the [Bounds object](#definition-objects-bounds). - -#### Export Bricks in (Multiple Export) #### -Which bricks to process and export to .BLB files. - -Value | Description -------|------------ -Layers | Export all bricks in the layers that are currently visible. **(Default)** -Scene | Export all bricks in the current scene. I.e. all bricks in all layers regardless of the layer visibility. - -#### Forward Axis #### -The Blender coordinate axis that will point forwards in-game when the player plants the brick directly in front of them without rotating it. -Does not change the rotation of the [objects](#def-object) in the Blender scene. - -Value | Description -------|------------ -+X | Positive X-axis -+Y | Positive Y-axis **(Default)** --X | Negative X-axis --Y | Negative Y-axis - -#### Scale #### -The scale of the brick in-game. -Values outside the the range of 0.001–400.0 may be typed in manually. -Does not change the scale of the [objects](#def-object) in the Blender scene. -See [Brick Scale](#brick-scale) for additional information. -(Default: `100%`) - -#### Apply Modifiers #### -Applies any modifiers on the [object](#def-object) before exporting. -Does not change the modifiers of the objects in the Blender scene. -(Default: `True`) - -#### Custom Definition Tokens #### -Allows you to specify the definition tokens the exporter uses. -See [Definition Tokens](#definition-tokens) for more information. -(Default: `False`) - -:bulb: Enabling this property shows additional properties. - -### BLB Properties ### - -#### Custom Collision #### -Export custom collision definitions if there are any. -See [Defining Collision](#defining-collision). -(Default: `True`) - -#### Fallback Collision #### -The type of collision to calculate for the brick if no custom collision definitions are found. -Enabling this property shows additional properties. - -Value | Description -------|------------ -Bounds | Use the defined or calculated [bounds](#definition-objects-bounds) of the brick as the collision cuboid. **(Default)** -AABB | Calculate the [axis-aligned bounding box](#def-aabb) of all [visible objects](#def-visible-object) and use that as the collision cuboid. - -#### Calculate Coverage #### -Enable coverage calculations. -This is pointless unless [Automatic Quad Sorting](#automatic-quad-sorting) is enabled or at least one [object](#def-object) has a quad sorting definition. -See [Defining Quad Sorting & Coverage](#defining-quad-sections--coverage) for more information. -(Default: `False`) - -:bulb: Enabling this property shows additional properties. - -#### Automatic Quad Sorting #### -Automatically calculate the correct section for quads that in the same plane as the bounding planes of the bounds object. -This is pointless unless [Coverage](#coverage) is enabled. -(Default: `True`) - -#### Use Material Colors #### -Assign [face](#def-face) colors from [object](#def-object) materials. -(Default: `False`) - -#### Use Vertex Colors #### -Assign [face](#def-face) colors from vertex color layers. -(Default: `False`) - -#### Parse Object Colors #### -Assign [face](#def-face) colors from [object](#def-object) names. -(Default: `False`) - -#### Calculate UVs #### -Automatically calculate correct UV coordinates based on the brick texture name specified in the material name. -See [UV Mapping](#uv-mapping) for more information. -(Default: `True`) - -#### Store UVs #### -Write calculated UVs into Blender [objects](#def-object). -Data in existing generated UV layers will be overwritten. -See [UV Mapping](#uv-mapping) for a list of generated UV layer names. -(Default: `True`) - -#### Round Normals #### -Round vertex normals to the user-defined floating point value precision. -If disabled normals will be written as accurately as possible but extraneous zeros will still be removed. -(Default: `False`) - -#### Precision #### -Allows you to specify a custom precision for floating point numbers. -See [Rounded Values](#rounded-values) for more details. -(Default: `0.000001`) - -### File Properties ### - -#### Pretty Print #### -When enabled does not write extraneous zeros to the end of floating point numbers. -Additionally if a numerical value is exactly equal to an integer, no decimal places are written. -If disabled will write all floating point numbers using as many decimal places as used in the [Precision](#precision) property. -(Default: `True`) - -#### Write Log #### -Write a log file to the same folder as the exported brick detailing the export process. -Shows additional settings when selected. -(Default: `True`) - -#### Only on Warnings #### -Write a log file only if warnings or errors occurred during the export process. -(Default: `True`) - -#### Terse Mode #### -When enabled does not write optional lines to the .BLB file such as the lines marking the different quad sections. -Using this option is not recommended as it makes the .BLB file harder to read and understand. -Although the file is shorter, the difference in file size is negligible. -(Default: `False`) - ## Brick Scale ## This add-on defines a `1x1x1` Blockland brick to be exactly `1.0 1.0 1.2` Blender units on the X, Y, and Z axes. Likewise a `1x1f` Blockland plate is defined to be exactly `1.0 1.0 0.4` Blender units. @@ -609,6 +440,200 @@ If the [Calculate UVs](#calculate-uvs) property is enabled, UV coordinates will The generated coordinates are only guaranteed to be correct for strictly rectangular quads, for any other shapes the results may not be satisfactory. If using brick textures on non-rectangular quads it is recommended to manually define the UV coordinates for best results. +## Rounded Values ## +Floating point numbers (numbers with a decimal point) contain [inherent inaccuracies](https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems). +For example when exporting a 1x1x1 brick [model](#def-model) at the maximum accuracy the vertex coordinate of one of the corners is `0.5 0.5 1.5000000596046448`. +This causes the 1x1x1 brick to be `3.00000011920928955078125` plates tall instead of exactly `3.0` like it should. +The only way to get fix this error is to round the vertex coordinates. +Practically speaking it is impossible to visually discern the difference between a brick that is 3 plates tall versus one that is `3.00000011920928955078125` plates tall in the game. +The only real benefit that comes from the rounding is nicer looking .BLB files. + +The default value of `0.000001` was chosen through manual testing. +Rest assured that the rounding will cause no visual oddities whatsoever because the value is so small. +This was manually confirmed with a sphere brick made from 524288 quads. +Moving the camera as close to the surface of the brick as the game was capable of rendering, the surface of the sphere appeared mathematically perfect because the distance between the vertices was less than the size of a single pixel. + +:exclamation: The exporter will only ever write up to 16 decimal places regardless of the precision of the value. + +Floating Point Value | Rounded +---------------------|:------: +[Visible object](#def-visible-object) vertex coordinates | Yes +[Bounds object](#definition-objects-bounds) vertex coordinates | Yes +[Collision object](#definition-objects-collision) vertex coordinates | Yes +[Brick grid object](#defining-brick-grid) vertex coordinates | Yes +Normal vectors | [Optional](#round-normals) +[RGBA color](#defining-colors) values | No +[UV coordinates](#uv-mapping) | No + +## Export Properties ## +The following user properties are present in the current version of the exporter. + +### Blender Properties ### + +#### Bricks to Export #### +How many bricks to export in one go from the file. + +Value | Description +------|------------ +Single | Export only one brick. **(Default)** +Multiple | Export one or more bricks. Shows additional settings when selected. + +#### Brick Name from (Single Export) #### +Where the .BLB file name is defined. + +Value | Description +------|------------ +Bounds | Brick name is defined in the [Bounds object](#definition-objects-bounds) after the bounds definition token, separated with a whitespace character. Export file dialog is only used set to directory. **(Default)** +File | Brick name is the same as the file name. Can be manually set in the export file dialog. + +#### Export Only (Single Export) #### +Which [objects](#def-object) to process and export to the .BLB file. + +Value | Description +------|------------ +Selection | Objects that are selected and have an orange outline. **(Default)** +Layers | All objects in the layers that are currently visible, regardless of selection. +Scene | All objects in the current scene. I.e. all objects in all layers regardless of the layer visibility. + +#### Brick Names from (Multiple Export) #### +Where the names of the .BLB files are defined. + +Value | Description +------|------------ +Bounds | Brick names are defined in the [Bounds object](#definition-objects-bounds) after the bounds definition token, separated with a whitespace character. Export file dialog is only used set to directory. **(Default)** +Groups | Brick names are the same as the names of the groups name. Export file dialog is only used set to directory. + +#### Bricks Defined by (Multiple Export) #### +How is a single brick defined. + +Value | Description +------|------------ +Groups | Each brick is in its own group. [Objects](#def-object) in multiple groups belong to multiple bricks. **(Default)** +Layers | Each brick is in its own layer. [Objects](#def-object) in multiple layers belong to multiple bricks. When selected brick names must be defined in the [Bounds object](#definition-objects-bounds). + +#### Export Bricks in (Multiple Export) #### +Which bricks to process and export to .BLB files. + +Value | Description +------|------------ +Layers | Export all bricks in the layers that are currently visible. **(Default)** +Scene | Export all bricks in the current scene. I.e. all bricks in all layers regardless of the layer visibility. + +#### Forward Axis #### +The Blender coordinate axis that will point forwards in-game when the player plants the brick directly in front of them without rotating it. +Does not change the rotation of the [objects](#def-object) in the Blender scene. + +Value | Description +------|------------ ++X | Positive X-axis ++Y | Positive Y-axis **(Default)** +-X | Negative X-axis +-Y | Negative Y-axis + +#### Scale #### +The scale of the brick in-game. +Values outside the the range of 0.001–400.0 may be typed in manually. +Does not change the scale of the [objects](#def-object) in the Blender scene. +See [Brick Scale](#brick-scale) for additional information. +(Default: `100%`) + +#### Apply Modifiers #### +Applies any modifiers on the [object](#def-object) before exporting. +Does not change the modifiers of the objects in the Blender scene. +(Default: `True`) + +#### Custom Definition Tokens #### +Allows you to specify the definition tokens the exporter uses. +See [Definition Tokens](#definition-tokens) for more information. +(Default: `False`) + +:bulb: Enabling this property shows additional properties. + +### BLB Properties ### + +#### Custom Collision #### +Export custom collision definitions if there are any. +See [Defining Collision](#defining-collision). +(Default: `True`) + +#### Fallback Collision #### +The type of collision to calculate for the brick if no custom collision definitions are found. +Enabling this property shows additional properties. + +Value | Description +------|------------ +Bounds | Use the defined or calculated [bounds](#definition-objects-bounds) of the brick as the collision cuboid. **(Default)** +AABB | Calculate the [axis-aligned bounding box](#def-aabb) of all [visible objects](#def-visible-object) and use that as the collision cuboid. + +#### Calculate Coverage #### +Enable coverage calculations. +This is pointless unless [Automatic Quad Sorting](#automatic-quad-sorting) is enabled or at least one [object](#def-object) has a quad sorting definition. +See [Defining Quad Sorting & Coverage](#defining-quad-sections--coverage) for more information. +(Default: `False`) + +:bulb: Enabling this property shows additional properties. + +#### Automatic Quad Sorting #### +Automatically calculate the correct section for quads that in the same plane as the bounding planes of the bounds object. +This is pointless unless [Coverage](#coverage) is enabled. +(Default: `True`) + +#### Use Material Colors #### +Assign [face](#def-face) colors from [object](#def-object) materials. +(Default: `False`) + +#### Use Vertex Colors #### +Assign [face](#def-face) colors from vertex color layers. +(Default: `False`) + +#### Parse Object Colors #### +Assign [face](#def-face) colors from [object](#def-object) names. +(Default: `False`) + +#### Calculate UVs #### +Automatically calculate correct UV coordinates based on the brick texture name specified in the material name. +See [UV Mapping](#uv-mapping) for more information. +(Default: `True`) + +#### Store UVs #### +Write calculated UVs into Blender [objects](#def-object). +Data in existing generated UV layers will be overwritten. +See [UV Mapping](#uv-mapping) for a list of generated UV layer names. +(Default: `True`) + +#### Round Normals #### +Round vertex normals to the user-defined floating point value precision. +If disabled normals will be written as accurately as possible but extraneous zeros will still be removed. +(Default: `False`) + +#### Precision #### +Allows you to specify a custom precision for floating point numbers. +See [Rounded Values](#rounded-values) for more details. +(Default: `0.000001`) + +### File Properties ### + +#### Pretty Print #### +When enabled does not write extraneous zeros to the end of floating point numbers. +Additionally if a numerical value is exactly equal to an integer, no decimal places are written. +If disabled will write all floating point numbers using as many decimal places as used in the [Precision](#precision) property. +(Default: `True`) + +#### Write Log #### +Write a log file to the same folder as the exported brick detailing the export process. +Shows additional settings when selected. +(Default: `True`) + +#### Only on Warnings #### +Write a log file only if warnings or errors occurred during the export process. +(Default: `True`) + +#### Terse Mode #### +When enabled does not write optional lines to the .BLB file such as the lines marking the different quad sections. +Using this option is not recommended as it makes the .BLB file harder to read and understand. +Although the file is shorter, the difference in file size is negligible. +(Default: `False`) + ## Troubleshooting ## Solutions to common issues with the BLB Exporter. If you have another issue with the exporter be sure to enable the [Write Log](#write-log) property and export again. @@ -1847,31 +1872,6 @@ Fatal errors always lead to the program execution stopping.
    -## Rounded Values ## -Floating point numbers (numbers with a decimal point) contain [inherent inaccuracies](https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems). -For example when exporting a 1x1x1 brick [model](#def-model) at the maximum accuracy the vertex coordinate of one of the corners is `0.5 0.5 1.5000000596046448`. -This causes the 1x1x1 brick to be `3.00000011920928955078125` plates tall instead of exactly `3.0` like it should. -The only way to get fix this error is to round the vertex coordinates. -Practically speaking it is impossible to visually discern the difference between a brick that is 3 plates tall versus one that is `3.00000011920928955078125` plates tall in the game. -The only real benefit that comes from the rounding is nicer looking .BLB files. - -The default value of `0.000001` was chosen through manual testing. -Rest assured that the rounding will cause no visual oddities whatsoever because the value is so small. -This was manually confirmed with a sphere brick made from 524288 quads. -Moving the camera as close to the surface of the brick as the game was capable of rendering, the surface of the sphere appeared mathematically perfect because the distance between the vertices was less than the size of a single pixel. - -:exclamation: The exporter will only ever write up to 16 decimal places regardless of the precision of the value. - -Floating Point Value | Rounded ----------------------|:------: -[Visible object](#def-visible-object) vertex coordinates | Yes -[Bounds object](#definition-objects-bounds) vertex coordinates | Yes -[Collision object](#definition-objects-collision) vertex coordinates | Yes -[Brick grid object](#defining-brick-grid) vertex coordinates | Yes -Normal vectors | [Optional](#round-normals) -[RGBA color](#defining-colors) values | No -[UV coordinates](#uv-mapping) | No - ## Contributors ## - [Nick Smith](https://github.com/qoh) - The original source code for reading, processing, and writing Blender data into the .BLB format. A majority of his code has been rewritten since. From 18d5870ac7015a55c8c853f4fd5b6da7c7a2c4aa Mon Sep 17 00:00:00 2001 From: Demian Wright Date: Tue, 28 Nov 2017 19:10:45 +0200 Subject: [PATCH 50/50] Increase version number --- __init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index 4a261cc..48a7253 100644 --- a/__init__.py +++ b/__init__.py @@ -32,7 +32,7 @@ bl_info = { "name": "Export: Blockland Brick (.blb)", "author": "Demian Wright & Nick Smith", - "version": (1, 2, 3), + "version": (2, 0, 0), "blender": (2, 67, 0), "location": "File > Export > Blockland Brick (.blb)", "description": "Export Blockland brick format",