[doc] prepare next generation development
4
.gitattributes
vendored
@ -4,5 +4,5 @@
|
||||
*.bin binary
|
||||
# json is data and not good for human reading(althought I edit it on my own hand.)
|
||||
# so set it as binary
|
||||
ballance_blender_plugin/json/basic_blocks/*.json binary
|
||||
ballance_blender_plugin/json/derived_blocks/*.json binary
|
||||
bbp_ng/json/basic_blocks/*.json binary
|
||||
bbp_ng/json/derived_blocks/*.json binary
|
179
README.md
@ -1,179 +1,10 @@
|
||||
# Ballance Blender Helper
|
||||
# BBP NG
|
||||
|
||||
[中文版本](README_ZH.md)
|
||||
|
||||
BBP NG, abbr **B**allance **B**lender **P**lugin **N**ext **G**eneration.
|
||||
|
||||
## Brief Introduction
|
||||
|
||||
This is a Blender plugin which is served for Ballance mapping in Blender.
|
||||
The latest commit may not be stable to use, please use the latest commit with git tag as the stable version.
|
||||
This plugin contain various aspect of Ballance mapping. However, if some features can be easily gotten from other Blender plugin, this plugin will not provide them duplicatedly. We highly recommend that use this plugin with following plugins.
|
||||
|
||||
* [BenjaminSauder/SimpleLattice](https://github.com/BenjaminSauder/SimpleLattice): Create lattice quickly to transform object.
|
||||
* [JulienHeijmans/quicksnap](https://github.com/JulienHeijmans/quicksnap): Provide powerful align functions which far beyond vanilla Blender align function.
|
||||
|
||||
## Technical Infomation
|
||||
|
||||
Used BM file spec can be found in [there](https://github.com/yyc12345/gist/blob/master/BMFileSpec/BMSpec_ZH.md) (Chinese only).
|
||||
Used tools chain principle and the file format located in `meshes` can be found in [there](https://github.com/yyc12345/gist/blob/master/BMFileSpec/YYCToolsChainSpec_ZH.md) (Chinese only).
|
||||
The format of the files which are under the `jsons` folder and belong to the BMERevenge section, can be found in [here](https://github.com/yyc12345/gist/blob/master/BMERevenge/DevDocument_ZH.md) (Chinese only).
|
||||
|
||||
This plugin will continuously support Blender lastest **LTS** version. This plugin will migrate to new version when the new LTS version released. Currently, it based on Blender **3.6.x**.
|
||||
|
||||
## Installation
|
||||
|
||||
Put `ballance_blender_plugin` into Blender's plugin folder, `scripts/addons`. Then enable this plugin in Blender's preferences (DO NOT forget to configure this plugin's settings after first installation or updating plugin.).
|
||||
|
||||
> **Note**
|
||||
After the version 3.3 supporting Blender 3.6 LTS, you should install this plugin in `scripts/addons`, not `scripts/addons_contrib` due to Blender do not support testing plugin anymore. If you still have old version in `scripts/addons_contrib`, please **DELETE** it **BEFORE** install the new version.
|
||||
|
||||
## Feature Introduction
|
||||
|
||||
### Plugin Settings
|
||||
|
||||
* External Texture Folder: Please fill in the `Texture` directory of Ballance, the plugin will refer the external texture file from this directory (the texture file originally with Ballance)
|
||||
* No Component Collection: Objects located in this collection will be forced to be set as non-component. If left blank, this function will be shutdown. This function is frequently used in forced component replacement.
|
||||
* Temp Texture Folder: used to cache texture files extracted from BM files. Please arrange a directory that will not be automatically cleaned up. Since Blender will continue to read texture files from this directory, it can not be emptied casually.
|
||||
|
||||
Temp Texture Folder does not allow files with duplicated name. Because of this, imagine this situation, there are two texture files with the same name in two BM files, but they represent different images. When you import them one by one for different maps. The later file will overwrite the previous file, And this will cause a texture error when the first Blender document was opened again. For the solution of this issue, the best way is to force packaging once. After successfully importing the BM, click `File - External Data - Pack Resources`, then you can clear Temp Texture Folder safely. With your preference, you also can click `File - External Data - Unpack Resources` to extract textures. This operation will extract and re-refer all textures into standalone texture folder within the folder where this Blender document is.
|
||||
|
||||
### BM Import / Export
|
||||
|
||||
Click `File - Import - Ballance Map` to import BM file.
|
||||
When name conflicts occur during importing BM, you have ability to choose different strategies for 4 different data types, Texture, Material, Mesh and Object. You can specify them to create a new instance or use current data block.
|
||||
|
||||
Click `File - Export - Ballance Map` to export a BM file.
|
||||
You can export a collection or an object (Export Mode), and specify target (Export Target) correspondingly.
|
||||
Although plugin provide Virtools Group feature and give you ability to grouping object in Blender. The export function also depend on Tools Chain Principle. Because of this, if you do not follow Tools Chain Principle, some convenient features will be disabled, for example, your exported BM file may larger than common one.
|
||||
|
||||
It should be noted that once the BM is exported, all the faces in the file will be converted to triangular faces, please make a backup in advance.
|
||||
It is recommended to use a flat collection structure, do not put a collection within another collection, which may cause some unnecessary problems.
|
||||
The suffix name of BM file is BMX, X stands for compression. BMX and BM is the same thing.
|
||||
|
||||
### Ballance 3D
|
||||
|
||||
Ballance 3D is a set of light tools related to 3D operations, which can be found in the upper left corner menu bar of 3D View. This menu is named as Ballance.
|
||||
|
||||
#### 3ds Max Align
|
||||
|
||||
Provide 3ds Max like align tools. Current active object will be seen as reference object. All selected objects (except active object) will be seen as operating object (So you can select multiple objects to align to a single object).
|
||||
|
||||
#### Create Rail UV
|
||||
|
||||
To create UVs for the rails in the map, you need to select the objects that need to add UVs similar to the rails, and then click this button to create.
|
||||
In the dialog, you can select the material to be used. You can also choose the unfolding mode. In some unfolding modes, projection axis and zoom ratio options is available. Although Ballance will process all rail UV in game internally, it is essential that give a perfect UV in designer.
|
||||
If you want that the rail have in-game UV (it represent as smooth texture), you can choose `TT_ReflectionMapping` unfolding mode. This mode is written with the reverse work of game used function. This unfolding mode may be useful when you creating advertisement image in Blender for your map.
|
||||
|
||||
#### Flatten UV
|
||||
|
||||
In the object editing mode, it is a operator which is used to attach the currently selected surface to the UV. And you can specific the edge which will be attached into the V axis.
|
||||
Note that only convex face is supported. Applying this for a concave face will cause undefined behavior.
|
||||
|
||||
In the edit mode, select the surface, click Flatten UV, and then scroll the slider to select an edge as a reference.
|
||||
If the generated UV is not attached correctly, such as the FloorSide's band is pasted to the bottom, you can reselect the reference edge and redo the operation until it is correct.
|
||||
|
||||
For the UV flatten by plugin, it must have a scale property. For example, the UV scale of normal floor is 5. However, the UV scale of sink floor is slightly larger than 5. Because the sink floor is "sink" in the floor block. There are 2 methods provided by plugin to getting this proper scale number. You can choose one from Scale Mode.
|
||||
The first method is that user specify a direct scale number. You just need select Scale Size in Scale Mode and fill with a proper scale number. This option is frequently used for fill a large borderless floor.
|
||||
The second method is reference point mode. You need specify a reference point and corresponding U component of its UV. Plugin will calculate the scale size automatically. This method is used for expanding a path of floor.
|
||||
|
||||
### Quick Struct Adder
|
||||
|
||||
In the add menu, we have added a set of commonly used objects. After adding, the object will move to the 3D cursor.
|
||||
|
||||
#### Elements
|
||||
|
||||
Add elements, you can also specify attributes such as section when adding (it will not be displayed for unique objects such as start point)
|
||||
|
||||
#### Rail section
|
||||
|
||||
Add rail section, you can choose monorail or rail (just decide the number of rail section loops added, and will not help you rotate the angle), as well as rail radius and rail span (default value is standard value).
|
||||
|
||||
#### Floors
|
||||
|
||||
A powerful floor adder feature belong to the extension of BMERevenge project.
|
||||
In menu, Basic Floor is basic floor component. Derived Floor is consisted by basic floor components. Commonly, frequently used models are located in Derived Floor section.
|
||||
After selecting a floor type, you can assign 2 expand value at most, according to its property. You also can use options to decide whether side faces and bottom face can be generated.
|
||||
Comparing with trditional Ballance Map Editor, this function can massively reduce useless vertices.
|
||||
|
||||
The floor type can be simply grouped as Flat Floor, Sink Floor, Wide Floor and Platform.
|
||||
Additionally, Trafo Block and Transition between Flat Floor and Sink Floor are available.
|
||||
|
||||
It is recommended to merge the vertices by distance, unless you need do some special work.
|
||||
|
||||
### Virtools Group
|
||||
|
||||
Plugin add a new property for each Blender objects, called Virtools Group. It takes the same functionality of Group in Virtools.
|
||||
Select an object, You can find `Virtools Group` panel in `Object Properties` panel.
|
||||
Click Add or Delete icon to group or ungroup for object.
|
||||
Double click item in list to rename it.
|
||||
|
||||
After click Add button, you can choose Predefined option, and select a name from all legal Ballance used group names.
|
||||
Or, choose Custom option and write your own group name.
|
||||
|
||||
### Virtools Material
|
||||
|
||||
Plugin add a new property for each Blender materials, called Virtools Material. It create a bridge between Virtools Material and Blender Material.
|
||||
Navigate to `Material Properties` panel, select a material, you can find `Virtools Material` panel.
|
||||
In default, user created material will not enable Virtools Material feature. You need to click checkbox of `Virtools Material` panel to enable or disable it.
|
||||
|
||||
After enable Virtools Material, `Basic Parameters` section and `Advanced Parameters` section can be set. Set your material peroperties just like operating in Virtools.
|
||||
Just like its name, `Basic Parameters` is basic material properties. `Advanced Parameters` is mainly related to transparent properties and usually used in the bottom of transparent column.
|
||||
Additionally, `Basic Parameters` section provide a preset function, allowing user to use some preset material settings, which only affect 4 basic colors, just for convenient using.
|
||||
|
||||
In `Operation` section, `Apply Virtools Material` will clean all existed Blender material and create a new material graph according to Virtools material properties.
|
||||
And, `Parse from Blender Principled BSDF` will try parsing a Principled BSDF to Virtools material.
|
||||
If your material highly rely on Blender material, please execute `Parse from Blender Principled BSDF` or disable Virtools Material feature before exporting BM file, otherwise material can not be saved correctly.
|
||||
|
||||
### Select by Virtools Group
|
||||
|
||||
Plugin add a selection function according to Virtools Group in Select menu.
|
||||
|
||||
This function firstly have 5 different selection strategies which is exactly matched with Blender selection method. Just use it like Blender selection (Set, Extend, Subtract, Invert, Intersect).
|
||||
Then, select your group name to start a selection.
|
||||
|
||||
If you can, using Subtract or Intersect modes would be better than other modes. Because these modes avoid analyzing too many objects.
|
||||
For example, first, select a rough range, and then use the Intersect mode to filter objects, which is more efficient than directly using the Start mode to select.
|
||||
|
||||
### Quick Grouping
|
||||
|
||||
Plugin add quick grouping menu in 2 places.
|
||||
You can select various objects, right click and find quick grouping menu in Object Context menu.
|
||||
Also you can pick objects in Outline View and right click them, find quick grouping menu in Object menu.
|
||||
|
||||
#### Group into
|
||||
|
||||
Group selected objects into your specified group.
|
||||
|
||||
#### Ungroup from
|
||||
|
||||
Ungroup selected objects from your specified group.
|
||||
|
||||
#### Clear Grouping
|
||||
|
||||
Clean the grouping infomation for selected objects.
|
||||
|
||||
### Auto Grouping & Rename
|
||||
|
||||
In Outline View, you can find auto grouping and rename menu via right click any collection.
|
||||
|
||||
This plugin now support 2 name standard.
|
||||
First one has been introduced in Technical Infomation chapter. In plugin, its name is `YYC Tools Chains`.
|
||||
The second one is used by [Imengyu/Ballance](https://github.com/imengyu/Ballance). In plugin, its name is `Imengyu Ballance`.
|
||||
|
||||
All functions within this menu will only output a summary when finishing. If you want to check out some objects in detail, please click `Window - Switch System Terminal`. Plugin output a detailed report in that place.
|
||||
|
||||
#### Rename by Group
|
||||
|
||||
Rename object with proper name according to its Virtools Group properties.
|
||||
This usually use when migrating original map. Some Ballance derived applications do not have Group concept. They rely on name to get group infomations.
|
||||
|
||||
#### Convert Name
|
||||
|
||||
Convert name between different name standard.
|
||||
Frequently used in convertion between 2 different Ballance derived applications.
|
||||
|
||||
#### Auto Grouping
|
||||
|
||||
Auto grouping according to specified name standard.
|
||||
Please pay attention that previous grouping infomations will be overwritten.
|
||||
If you following some mapping standard during all mapping stages, this function will auto grouping all objects for you.
|
||||
|
||||
The next generation of original Ballance Blender Helper. This plugin is fully rewritten.
|
||||
This plugin still work in progress. The development will be pushed into `ng` branch in main repository. For legacy plugin user, please visit `master` branch directly.
|
||||
|
179
README_ZH.md
@ -1,179 +1,10 @@
|
||||
# Ballance Blender Helper
|
||||
# BBP NG
|
||||
|
||||
[English version](README.md)
|
||||
|
||||
BBP NG,又名**B**allance **B**lender **P**lugin **N**ext **G**eneration(下一代Ballance Blender插件)。
|
||||
|
||||
## 简介
|
||||
|
||||
这是一个用于Blender的插件,其主要是服务于Ballance制图。
|
||||
请选择打了tag的最新commit使用。最新的commit不能保证其是稳定可用的。
|
||||
本插件囊括了Ballance制图中可能会用到的各种功能。对于一些其它插件可以提供的功能,本插件不再重复提供。建议与下列插件合用以取得更好制图效果:
|
||||
|
||||
* [BenjaminSauder/SimpleLattice](https://github.com/BenjaminSauder/SimpleLattice):快速创建晶格以便变形物体。
|
||||
* [JulienHeijmans/quicksnap](https://github.com/JulienHeijmans/quicksnap):提供远超Blender原生的对齐功能。
|
||||
|
||||
## 技术信息
|
||||
|
||||
使用的BM文件标准可以在[这里](https://github.com/yyc12345/gist/blob/master/BMFileSpec/BMSpec_ZH.md)查找。
|
||||
使用的制图链标准以及`meshes`文件夹下的文件的格式可以在[这里](https://github.com/yyc12345/gist/blob/master/BMFileSpec/YYCToolsChainSpec_ZH.md)查找
|
||||
`jsons`文件夹下的,隶属于BMERevenge部分的文件的格式可以在[这里](https://github.com/yyc12345/gist/blob/master/BMERevenge/DevDocument_ZH.md)查找
|
||||
|
||||
支持Blender的原则是支持当前最新的 **LTS** 版本,在最新的LTS版本释出之后会花一些时间迁移插件。当前插件基于**3.6.x**版本
|
||||
|
||||
## 安装
|
||||
|
||||
将`ballance_blender_plugin`直接复制到Blender插件目录`scripts/addons`内即可。然后在Blender偏好设置中启用即可(请在第一次安装后或更新插件后配置插件设置)。
|
||||
|
||||
> **Note**
|
||||
在对标Blender 3.6 LTS的3.3版本之后,您应该将此插件安装在`scripts/addons`中,而不是`scripts/addons_contrib`中,因为Blender不再支持Testing类型插件。 如果您在`scripts/addons_contrib`中仍有旧版本,请在安装新版本**之前删除**它。
|
||||
|
||||
## 功能介绍
|
||||
|
||||
### 插件设置
|
||||
|
||||
* External texture folder:请填写为Ballance的`Texture`目录,插件将从此目录下调用外置贴图文件(即Ballance原本带有的贴图文件)
|
||||
* No component collection:处于此集合中的物体将被强制指定为非Component。如果留空则表示不需要这个功能。此功能通常用于机关模型强制替换。
|
||||
* Temp texture folder:用于缓存从BM文件中提取的贴图文件,请安排一个平时不会被自动清理的目录。由于Blender会持续从这个目录读取贴图文件,因此不能随意清空。
|
||||
|
||||
Temp texture folder不允许同名文件存在,即如果我为2个地图分别导入两个BM,这两个BM中存在贴图文件名相同但图像不同的两个文件,那么后来的文件将会覆盖前面的文件,并进而导致前者导入后的文档再次打开时出现贴图错误。关于这个问题的解决方案,最好的方法是强制打包一次。在导入BM成功之后,选择`文件-外部数据-打包资源`,然后就可以安全清空Temp texture folder所在目录或导入新BM文件。如果有需要可以再点击`文件-外部数据-解包资源`,将贴图重新依赖到工程文件夹下的独立贴图库内。
|
||||
|
||||
### BM导入导出
|
||||
|
||||
点击`文件-导入-Ballance Map`以导入BM文件。
|
||||
在导入发生名称冲突时,可以对贴图,材质,网格,物体这四种类型的数据分别决定是使用现有数据还是创建新的数据。
|
||||
|
||||
点击`文件-导出-Ballance Map`以导出BM文件。
|
||||
可以选择导出一个集合或者是一个物体(Export mode),并给定对象(Export target)即可。
|
||||
尽管插件提供了Virtools组功能,让你可以直接在Blender中归组完毕,但BM导出功能仍然受限于制图链标准。因此如果不按照制图链标准进行命名,那么在导出过程中则无法享受一些便利性功能,例如最终导出的文件可能会过大等。
|
||||
|
||||
一旦导出BM,文件中所有的面将全部转换为三角形面,请提前做好备份。
|
||||
在导出时,建议使用平铺的集合结构,不要在集合内嵌套集合,因为这样可能会导致一些不必要的问题。
|
||||
BM文件的后缀名是BMX,表示BM的压缩。BMX与BM为同一含义。
|
||||
|
||||
### Ballance 3D
|
||||
|
||||
Ballance 3D是一套简单的用于制图3D相关的轻型工具集合,可以在3D视图左上角菜单栏中找到,菜单名称为Ballance。
|
||||
|
||||
#### 3ds Max Align
|
||||
|
||||
提供一种类似于3ds Max的对齐方式。当前活动物体将被设为参照对象,当前选中的所有物体(如果参照也被选中则去掉参照对象)将被视为操作对象(因此可以选择多个物体一起对齐到参照对象)。
|
||||
|
||||
#### Create Rail UV
|
||||
|
||||
为地图中的钢轨创建UV,你需要先选中需要添加类似钢轨UV的物体,然后点击这个按钮以创建。
|
||||
在弹出设置窗口中,可以选择使用的材质。还可以选择展开模式,在部分展开模式下,还可以选择投影轴和缩放大小。尽管Ballance最终会为所有钢轨重新上UV,一个在界面中看着赏心悦目的钢轨贴图还是比较重要的。
|
||||
如果您需要在Blender中呈现游戏内钢轨的贴图效果(表现为所谓的平滑贴图),您可以选择`TT_ReflectionMapping`展开模式。此功能由逆向游戏所用函数得来。这在渲染地图宣传画时可能会很有用。
|
||||
|
||||
#### Flatten UV
|
||||
|
||||
在物体编辑模式下,用于将当前选中面按某一边贴附到V轴上的模式,展开到UV上。
|
||||
此功能只支持凸多边形面,对于凹多边形面会有未定义行为。
|
||||
|
||||
编辑模式下,选中面,点击Flatten UV,然后选中一个边作为参考。
|
||||
如果最后生成的边贴附不对,比如把路面花纹贴到了下部,可以重新选择参考边再进行操作,直到正确为止。
|
||||
|
||||
对于粘贴的贴图的UV,需要具有一定缩放,比如对于平路面,这个缩放比是5,而对于凹路面,则要比5大一些,因为凹路面由于凹进路面。为了方便确认这个缩放值,我们提供了两种方式,可以在Scale Mode种选择。
|
||||
一种是用户直接指定,选择Scale Mode为Scale Size并填写合适的缩放数值即可。此选项适合平谱无边框路面。
|
||||
另一种即为参考点模式。用户指定一个参考点,并指定此参考点在U轴上的位置,插件会自动计算缩放值应为多少。此选项适合展开路面路径的贴图。
|
||||
|
||||
### 快速添加结构
|
||||
|
||||
在添加菜单中我们添加了一系列较为常用的物体。添加后物体会移动到3D游标处。
|
||||
|
||||
#### Elements
|
||||
|
||||
添加机关,添加时还可以指定添加的小节等属性(对于飞船等唯一物体不会显示)
|
||||
|
||||
#### Rail section
|
||||
|
||||
添加钢轨截面,可以选择单轨还是双轨(只是决定添加的界面数量,并不会帮你旋转角度),以及轨道半径和轨道间距(默认值就是标准数据)。
|
||||
|
||||
#### Floors
|
||||
|
||||
一个非常强大的添加路面功能,隶属于BMERevenge工程的拓展。
|
||||
菜单中的Basic floor是基本的路面组件,而Derived floor则是由基本组件组成的常用组件。通常而言,大部分需要的路面都在Derived floor中。
|
||||
在选择一个路面后,可以根据其本身属性,设置最多2个延展方向的数值。此外还可以控制侧面和底面是否生成。
|
||||
与Ballance Map Editor相比,还具有减少大量无用顶点的优势。
|
||||
|
||||
可添加的路面大致分为平路面,凹路面,宽路面以及各类平台。
|
||||
此外还有变球器底座,平凹转换路面可供添加。
|
||||
|
||||
建议添加后除有特殊需求外,应该立即按距离合并顶点一次以避免各类问题。
|
||||
|
||||
### Virtools组
|
||||
|
||||
插件为每一个Blender物体添加了新的属性,被称为Virtools Group。与Virtools中的组具有相同的功能。
|
||||
选择一个物体,在`物体属性`面板可以找到`Virtools Group`面板。
|
||||
可以点击添加与删除图标,为物体归组和取消归组。
|
||||
亦可在列表中双击修改组名。
|
||||
|
||||
在点击添加按钮后,可以选择预定义,然后从所有合法的Ballance组名中选择一个添加。
|
||||
或选择自定义,然后输入你想要的组名添加。
|
||||
|
||||
### Virtools材质
|
||||
|
||||
插件为每一个Blender材质添加了新的属性,被称为Virtools Material。它在Virtools材质与Blender材质之间架起沟通的桥梁。
|
||||
转到`材质属性`面板,选择一个材质,即可以找到`Virtools Material`面板。
|
||||
默认情况下,由用户创建的材质不启用Virtools Material,您可以通过点击`Virtools Material`面板的复选框来启用或关闭它。
|
||||
|
||||
在启用Virtools Material后,可以在`Basic Parameters`和`Advanced Parameters`中设置材质属性,就像在Virtools中操作一般。
|
||||
`Basic Parameters`是基础材质属性。`Advanced Parameters`则是与透明相关的材质属性,主要用于半透明柱子底部等。
|
||||
另外,`Basic Parameters`部分提供了预设功能,允许用户使用一些预设的材质设置,这些设置只影响4种基本颜色,方便使用。
|
||||
|
||||
`Operation`中的`Apply Virtools Material`将把Virtools Material应用到Blender材质上。
|
||||
而`Parse from Blender Principled BSDF`将尝试将一个原理化BSDF转换为Virtools材质数据。
|
||||
如果您是从Blender材质编辑的,请务必对此材质在导出前执行`Parse from Blender Principled BSDF`,或关闭Virtools Material功能,否则材质将无法正确保存。
|
||||
|
||||
### 按组选择
|
||||
|
||||
选择菜单中新增了一项按照Virtools归组数据进行筛选的功能。
|
||||
|
||||
该功能首先有5种不同的选择策略,与Blender的选择方法完全匹配(开始、扩选、相减、反转、相交)。只需像Blender选择那样使用它。
|
||||
然后,选择你需要的组的名称,然后开始一次选择或筛选。
|
||||
|
||||
如果可以,请尽可能使用相减或相交模式。因为这样可以避免分析过多的物体。
|
||||
例如先选定一个大致的范围,然后使用相交模式过滤,比直接使用开始模式效率更高。
|
||||
|
||||
### 快速归组
|
||||
|
||||
插件在2个地方添加了为物体快速归组的功能。
|
||||
可以选择一系列物体,然后右键,在物体上下文菜单中找到快速归组功能。
|
||||
也可以在大纲窗口中,右键选择的物体,找到快速归组功能。
|
||||
|
||||
#### Group into
|
||||
|
||||
把选择物体归入你选择的组。
|
||||
|
||||
#### Ungroup from
|
||||
|
||||
把选择物体从你选择的组中取消归组。
|
||||
|
||||
#### Clear Grouping
|
||||
|
||||
清空选择物体的所有归组信息。
|
||||
|
||||
### 自动归组与重命名
|
||||
|
||||
在大纲视图中,对任意集合右键,可以得到自动归组与重命名菜单。
|
||||
|
||||
本插件目前支持两种命名标准。
|
||||
其一为技术信息章节已经阐述的制图链标准,在本插件中的名称为`YYC Tools Chains`。
|
||||
其二为[Imengyu/Ballance](https://github.com/imengyu/Ballance)所用命名标准,在本插件中的名称为`Imengyu Ballance`。
|
||||
|
||||
这些功能最终只会展示成功与否的一个概括性消息。如果您需要详细查看某个物体为什么不能转换,请点击`窗口-切换系统控制台`,插件在那里有更详细的输出。
|
||||
|
||||
#### Rename by Group
|
||||
|
||||
根据当前物体的归组信息,为其重命名为合适的名称。
|
||||
这通常用在迁移原版地图的过程中。一些Ballance衍生程序没有Virtools组概念,因此需要依赖名称来取得归组信息。
|
||||
|
||||
#### Convert Name
|
||||
|
||||
在不同命名标准之间切换。
|
||||
通常用于在不同Ballance衍生程序中进行转换。
|
||||
|
||||
#### Auto Grouping
|
||||
|
||||
根据给定的命名标准,为物体自动填充归组信息。
|
||||
需要注意的是,原有的归组信息会被覆盖。
|
||||
在制图过程中,如果你遵守了某些命名标准,则此功能可以为你自动完成归组功能。
|
||||
|
||||
下一代的Ballance Blender插件。此插件完全重写了上一代插件。
|
||||
此插件仍然在开发过程中。开发内容会被推送到主仓库的`ng`分支中。对于旧插件的用户,请直接访问`master`分支。
|
||||
|
@ -1,364 +0,0 @@
|
||||
import bpy,bmesh,bpy_extras,mathutils
|
||||
import pathlib,zipfile,time,os,tempfile,math
|
||||
import struct, shutil
|
||||
from bpy_extras import io_utils, node_shader_utils
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_file_io, UTILS_zip_helper, UTILS_virtools_prop, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_export_bm(bpy.types.Operator, bpy_extras.io_utils.ExportHelper):
|
||||
"""Save a Ballance Map File (BM file spec 1.4)"""
|
||||
bl_idname = "ballance.export_bm"
|
||||
bl_label = 'Export BM'
|
||||
bl_options = {'PRESET'}
|
||||
|
||||
# ExportHelper mixin class uses this
|
||||
filename_ext = ".bmx"
|
||||
filter_glob: bpy.props.StringProperty(
|
||||
default="*.bmx",
|
||||
options={'HIDDEN'},
|
||||
maxlen=255, # Max internal buffer length, longer would be clamped.
|
||||
)
|
||||
|
||||
export_mode: bpy.props.EnumProperty(
|
||||
name="Export mode",
|
||||
items=(('COLLECTION', "Collection", "Export a collection"),
|
||||
('OBJECT', "Objects", "Export an objects"),
|
||||
),
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
# detect edit mode
|
||||
in_edit_mode = False
|
||||
if bpy.context.object and bpy.context.object.mode == "EDIT":
|
||||
in_edit_mode = True
|
||||
bpy.ops.object.editmode_toggle()
|
||||
|
||||
if ((self.export_mode == 'COLLECTION' and context.scene.BallanceBlenderPluginProperty.collection_picker is None) or
|
||||
(self.export_mode == 'OBJECT' and context.scene.BallanceBlenderPluginProperty.object_picker is None)):
|
||||
UTILS_functions.show_message_box(("No specific target", ), "Lost parameter", UTILS_icons_manager.blender_error_icon)
|
||||
else:
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
|
||||
if self.export_mode == 'COLLECTION':
|
||||
export_bm(context, self.filepath,
|
||||
prefs.no_component_collection,
|
||||
self.export_mode, context.scene.BallanceBlenderPluginProperty.collection_picker)
|
||||
elif self.export_mode == 'OBJECT':
|
||||
export_bm(context, self.filepath,
|
||||
prefs.no_component_collection,
|
||||
self.export_mode, context.scene.BallanceBlenderPluginProperty.object_picker)
|
||||
|
||||
# restore edit mode
|
||||
if in_edit_mode:
|
||||
bpy.ops.object.editmode_toggle()
|
||||
|
||||
self.report({'INFO'}, "BM File Export Finished.")
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "export_mode", expand=True)
|
||||
if self.export_mode == 'COLLECTION':
|
||||
layout.prop(context.scene.BallanceBlenderPluginProperty, "collection_picker")
|
||||
elif self.export_mode == 'OBJECT':
|
||||
layout.prop(context.scene.BallanceBlenderPluginProperty, "object_picker")
|
||||
|
||||
|
||||
def export_bm(context, bmx_filepath, prefs_fncg, opts_exportMode, opts_exportTarget):
|
||||
# ============================================ alloc a temp folder
|
||||
utils_tempFolderObj = tempfile.TemporaryDirectory()
|
||||
utils_tempFolder = utils_tempFolderObj.name
|
||||
utils_tempTextureFolder = os.path.join(utils_tempFolder, "Texture")
|
||||
os.makedirs(utils_tempTextureFolder)
|
||||
|
||||
# ============================================
|
||||
# find export target.
|
||||
# do not need check them validation in there.
|
||||
# just collect them.
|
||||
if opts_exportMode== "COLLECTION":
|
||||
objectList = opts_exportTarget.all_objects
|
||||
else:
|
||||
objectList = [opts_exportTarget, ]
|
||||
|
||||
# try get fncg collection
|
||||
# fncg stands with forced non-component group
|
||||
try:
|
||||
object_fncgCollection = bpy.data.collections[prefs_fncg]
|
||||
except:
|
||||
object_fncgCollection = None
|
||||
|
||||
# ============================================ export
|
||||
with open(os.path.join(utils_tempFolder, "index.bm"), "wb") as finfo:
|
||||
UTILS_file_io.write_uint32(finfo, UTILS_constants.bmfile_currentVersion)
|
||||
|
||||
# ====================== export object
|
||||
meshSet = set()
|
||||
meshList = []
|
||||
meshCount = 0
|
||||
with open(os.path.join(utils_tempFolder, "object.bm"), "wb") as fobject:
|
||||
for obj in objectList:
|
||||
# only export mesh object
|
||||
if obj.type != 'MESH':
|
||||
continue
|
||||
|
||||
# clean no mesh object
|
||||
object_blenderMesh = obj.data
|
||||
if object_blenderMesh is None:
|
||||
continue
|
||||
|
||||
# check component
|
||||
if (object_fncgCollection is not None) and (obj.name in object_fncgCollection.objects):
|
||||
# it should be set as normal object forcely
|
||||
object_isComponent = False
|
||||
else:
|
||||
# check isComponent normally
|
||||
object_isComponent = UTILS_functions.is_component(obj.name)
|
||||
|
||||
# triangle first and then group
|
||||
if not object_isComponent:
|
||||
if object_blenderMesh not in meshSet:
|
||||
_mesh_triangulate(object_blenderMesh)
|
||||
meshSet.add(object_blenderMesh)
|
||||
meshList.append(object_blenderMesh)
|
||||
object_meshIndex = meshCount
|
||||
meshCount += 1
|
||||
else:
|
||||
object_meshIndex = meshList.index(object_blenderMesh)
|
||||
else:
|
||||
object_meshIndex = UTILS_functions.get_component_id(obj.name)
|
||||
|
||||
# get visibility
|
||||
object_isHidden = not obj.visible_get()
|
||||
|
||||
# try get grouping data
|
||||
object_groupList = UTILS_virtools_prop.get_virtools_group_data(obj)
|
||||
|
||||
# =======================
|
||||
# write to files
|
||||
# write finfo first
|
||||
UTILS_file_io.write_string(finfo, obj.name)
|
||||
UTILS_file_io.write_uint8(finfo, UTILS_constants.BmfileInfoType.OBJECT)
|
||||
UTILS_file_io.write_uint64(finfo, fobject.tell())
|
||||
|
||||
# write fobject
|
||||
UTILS_file_io.write_bool(fobject, object_isComponent)
|
||||
UTILS_file_io.write_bool(fobject, object_isHidden)
|
||||
UTILS_file_io.write_world_matrix(fobject, obj.matrix_world)
|
||||
UTILS_file_io.write_uint32(fobject, len(object_groupList))
|
||||
for item in object_groupList:
|
||||
UTILS_file_io.write_string(fobject, item)
|
||||
UTILS_file_io.write_uint32(fobject, object_meshIndex)
|
||||
|
||||
# ====================== export mesh
|
||||
materialSet = set()
|
||||
materialList = []
|
||||
with open(os.path.join(utils_tempFolder, "mesh.bm"), "wb") as fmesh:
|
||||
for mesh in meshList:
|
||||
# split normals
|
||||
mesh.calc_normals_split()
|
||||
|
||||
# write finfo first
|
||||
UTILS_file_io.write_string(finfo, mesh.name)
|
||||
UTILS_file_io.write_uint8(finfo, UTILS_constants.BmfileInfoType.MESH)
|
||||
UTILS_file_io.write_uint64(finfo, fmesh.tell())
|
||||
|
||||
# write fmesh
|
||||
# vertices
|
||||
mesh_vecList = mesh.vertices[:]
|
||||
UTILS_file_io.write_uint32(fmesh, len(mesh_vecList))
|
||||
for vec in mesh_vecList:
|
||||
#swap yz
|
||||
UTILS_file_io.write_3vector(fmesh,vec.co[0],vec.co[2],vec.co[1])
|
||||
|
||||
# uv
|
||||
mesh_faceIndexPairs = [(face, index) for index, face in enumerate(mesh.polygons)]
|
||||
UTILS_file_io.write_uint32(fmesh, len(mesh_faceIndexPairs) * 3)
|
||||
if mesh.uv_layers.active is not None:
|
||||
uv_layer = mesh.uv_layers.active.uv
|
||||
for f, f_index in mesh_faceIndexPairs:
|
||||
# it should be triangle face, otherwise throw a error
|
||||
if (f.loop_total != 3):
|
||||
raise Exception("Not a triangle", f.poly.loop_total)
|
||||
|
||||
for loop_index in range(f.loop_start, f.loop_start + f.loop_total):
|
||||
uv = uv_layer[loop_index].vector
|
||||
# reverse v
|
||||
UTILS_file_io.write_2vector(fmesh, uv[0], -uv[1])
|
||||
else:
|
||||
# no uv data. write garbage
|
||||
for i in range(len(mesh_faceIndexPairs) * 3):
|
||||
UTILS_file_io.write_2vector(fmesh, 0.0, 0.0)
|
||||
|
||||
# normals
|
||||
UTILS_file_io.write_uint32(fmesh, len(mesh_faceIndexPairs) * 3)
|
||||
for f, f_index in mesh_faceIndexPairs:
|
||||
# no need to check triangle again
|
||||
for loop_index in range(f.loop_start, f.loop_start + f.loop_total):
|
||||
nml = mesh.loops[loop_index].normal
|
||||
# swap yz
|
||||
UTILS_file_io.write_3vector(fmesh, nml[0], nml[2], nml[1])
|
||||
|
||||
# face
|
||||
# get material first
|
||||
mesh_usedBlenderMtl = mesh.materials[:]
|
||||
mesh_noMaterial = len(mesh_usedBlenderMtl) == 0
|
||||
for mat in mesh_usedBlenderMtl:
|
||||
# skip empty mtl slot
|
||||
if mat is None:
|
||||
continue
|
||||
# add into mtl set
|
||||
if mat not in materialSet:
|
||||
materialSet.add(mat)
|
||||
materialList.append(mat)
|
||||
|
||||
UTILS_file_io.write_uint32(fmesh, len(mesh_faceIndexPairs))
|
||||
mesh_vtIndex = []
|
||||
mesh_vnIndex = []
|
||||
mesh_vIndex = []
|
||||
for f, f_index in mesh_faceIndexPairs:
|
||||
# confirm material use
|
||||
# a face without mtl have 2 situations. first is the whole object do not have mtl
|
||||
# another is this face use an empty mtl slot.
|
||||
mesh_faceNoMtl = mesh_noMaterial or (mesh_usedBlenderMtl[f.material_index] is None)
|
||||
if mesh_faceNoMtl:
|
||||
mesh_materialIndex = 0
|
||||
else:
|
||||
mesh_materialIndex = materialList.index(mesh_usedBlenderMtl[f.material_index])
|
||||
|
||||
# export face
|
||||
mesh_vtIndex.clear()
|
||||
mesh_vnIndex.clear()
|
||||
mesh_vIndex.clear()
|
||||
|
||||
counter = 0
|
||||
for loop_index in range(f.loop_start, f.loop_start + f.loop_total):
|
||||
mesh_vIndex.append(mesh.loops[loop_index].vertex_index)
|
||||
mesh_vnIndex.append(f_index * 3 + counter)
|
||||
mesh_vtIndex.append(f_index * 3 + counter)
|
||||
counter += 1
|
||||
# reverse vertices sort
|
||||
UTILS_file_io.write_face(fmesh,
|
||||
mesh_vIndex[2], mesh_vtIndex[2], mesh_vnIndex[2],
|
||||
mesh_vIndex[1], mesh_vtIndex[1], mesh_vnIndex[1],
|
||||
mesh_vIndex[0], mesh_vtIndex[0], mesh_vnIndex[0])
|
||||
|
||||
# set used material
|
||||
UTILS_file_io.write_bool(fmesh, not mesh_faceNoMtl)
|
||||
UTILS_file_io.write_uint32(fmesh, mesh_materialIndex)
|
||||
|
||||
# free splited normals
|
||||
mesh.free_normals_split()
|
||||
|
||||
# ====================== export material
|
||||
textureSet = set()
|
||||
textureList = []
|
||||
textureCount = 0
|
||||
with open(os.path.join(utils_tempFolder, "material.bm"), "wb") as fmaterial:
|
||||
for material in materialList:
|
||||
# write finfo first
|
||||
UTILS_file_io.write_string(finfo, material.name)
|
||||
UTILS_file_io.write_uint8(finfo, UTILS_constants.BmfileInfoType.MATERIAL)
|
||||
UTILS_file_io.write_uint64(finfo, fmaterial.tell())
|
||||
|
||||
# try get original written data
|
||||
(material_enableVirtoolsMat,
|
||||
material_colAmbient, material_colDiffuse, material_colSpecular, material_colEmissive, material_specularPower,
|
||||
material_alphaTest, material_alphaBlend, material_zBuffer, material_twoSided,
|
||||
material_texture) = UTILS_virtools_prop.get_virtools_material_data(material)
|
||||
|
||||
# only try get from Principled BSDF when we couldn't get from virtools_material props
|
||||
if not material_enableVirtoolsMat:
|
||||
v = UTILS_functions.parse_material_nodes(material)
|
||||
if v is not None:
|
||||
(material_enableVirtoolsMat,
|
||||
material_colAmbient, material_colDiffuse, material_colSpecular, material_colEmissive, material_specularPower,
|
||||
material_alphaTest, material_alphaBlend, material_zBuffer, material_twoSided,
|
||||
material_texture) = v
|
||||
|
||||
# check texture index
|
||||
if material_texture is None:
|
||||
material_useTexture = False
|
||||
material_textureIndex = 0
|
||||
else:
|
||||
# add into texture list
|
||||
if material_texture not in textureSet:
|
||||
textureSet.add(material_texture)
|
||||
textureList.append(material_texture)
|
||||
textureIndex = textureCount
|
||||
textureCount += 1
|
||||
else:
|
||||
textureIndex = textureList.index(material_texture)
|
||||
|
||||
material_useTexture = True
|
||||
material_textureIndex = textureIndex
|
||||
|
||||
UTILS_file_io.write_color(fmaterial, material_colAmbient)
|
||||
UTILS_file_io.write_color(fmaterial, material_colDiffuse)
|
||||
UTILS_file_io.write_color(fmaterial, material_colSpecular)
|
||||
UTILS_file_io.write_color(fmaterial, material_colEmissive)
|
||||
UTILS_file_io.write_float(fmaterial, material_specularPower)
|
||||
UTILS_file_io.write_bool(fmaterial, material_alphaTest)
|
||||
UTILS_file_io.write_bool(fmaterial, material_alphaBlend)
|
||||
UTILS_file_io.write_bool(fmaterial, material_zBuffer)
|
||||
UTILS_file_io.write_bool(fmaterial, material_twoSided)
|
||||
UTILS_file_io.write_bool(fmaterial, material_useTexture)
|
||||
UTILS_file_io.write_uint32(fmaterial, material_textureIndex)
|
||||
|
||||
|
||||
# ====================== export texture
|
||||
texture_blenderFilePath = os.path.dirname(bpy.data.filepath)
|
||||
texture_existedTextureFilepath = set()
|
||||
with open(os.path.join(utils_tempFolder, "texture.bm"), "wb") as ftexture:
|
||||
for texture in textureList:
|
||||
# write finfo first
|
||||
UTILS_file_io.write_string(finfo, texture.name)
|
||||
UTILS_file_io.write_uint8(finfo, UTILS_constants.BmfileInfoType.TEXTURE)
|
||||
UTILS_file_io.write_uint64(finfo, ftexture.tell())
|
||||
|
||||
# confirm whether it is internal texture
|
||||
# get absolute texture path
|
||||
texture_filepath = io_utils.path_reference(texture.filepath, texture_blenderFilePath, utils_tempTextureFolder,
|
||||
'ABSOLUTE', "", None, texture.library)
|
||||
# texture_filepath = bpy.path.abspath(texture.filepath, start=texture_blenderFilePath, library=texture.library)
|
||||
|
||||
# get file name and write it
|
||||
texture_filename = os.path.basename(texture_filepath)
|
||||
UTILS_file_io.write_string(ftexture, texture_filename)
|
||||
|
||||
if (_is_external_texture(texture_filename)):
|
||||
# write directly, use Ballance texture
|
||||
UTILS_file_io.write_bool(ftexture, True)
|
||||
else:
|
||||
# copy internal texture, if this file is copied, do not copy it again
|
||||
UTILS_file_io.write_bool(ftexture, False)
|
||||
if texture_filename not in texture_existedTextureFilepath:
|
||||
shutil.copy(texture_filepath, os.path.join(utils_tempTextureFolder, texture_filename))
|
||||
texture_existedTextureFilepath.add(texture_filename)
|
||||
|
||||
|
||||
# ============================================
|
||||
# save zip and clean up folder
|
||||
UTILS_zip_helper.compress(utils_tempFolder, bmx_filepath)
|
||||
utils_tempFolderObj.cleanup()
|
||||
|
||||
# ==========================================
|
||||
# blender related functions
|
||||
|
||||
def _is_external_texture(name):
|
||||
if name in UTILS_constants.bmfile_externalTextureSet:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def _mesh_triangulate(me):
|
||||
bm = bmesh.new()
|
||||
bm.from_mesh(me)
|
||||
bmesh.ops.triangulate(bm, faces=bm.faces)
|
||||
bm.to_mesh(me)
|
||||
bm.free()
|
||||
|
||||
def _set_value_when_none(obj, newValue):
|
||||
if obj is None:
|
||||
return newValue
|
||||
else:
|
||||
return obj
|
||||
|
@ -1,374 +0,0 @@
|
||||
import bpy,bmesh,bpy_extras,mathutils
|
||||
import pathlib,zipfile,time,os,tempfile,math
|
||||
import struct, shutil
|
||||
from bpy_extras import io_utils,node_shader_utils
|
||||
from bpy_extras.io_utils import unpack_list
|
||||
from bpy_extras.image_utils import load_image
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_file_io, UTILS_zip_helper, UTILS_virtools_prop, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_import_bm(bpy.types.Operator, bpy_extras.io_utils.ImportHelper):
|
||||
"""Load a Ballance Map File (BM file spec 1.4)"""
|
||||
bl_idname = "ballance.import_bm"
|
||||
bl_label = "Import BM "
|
||||
bl_options = {'PRESET', 'UNDO'}
|
||||
|
||||
# ImportHelper mixin class uses this
|
||||
filename_ext = ".bmx"
|
||||
filter_glob: bpy.props.StringProperty(
|
||||
default="*.bmx",
|
||||
options={'HIDDEN'},
|
||||
maxlen=255, # Max internal buffer length, longer would be clamped.
|
||||
)
|
||||
|
||||
texture_conflict_strategy: bpy.props.EnumProperty(
|
||||
name="Texture name conflict",
|
||||
items=(('NEW', "New instance", "Create a new instance"),
|
||||
('CURRENT', "Use current", "Use current"),),
|
||||
description="Define how to process texture name conflict",
|
||||
default='CURRENT',
|
||||
)
|
||||
|
||||
material_conflict_strategy: bpy.props.EnumProperty(
|
||||
name="Material name conflict",
|
||||
items=(('RENAME', "Rename", "Rename the new one"),
|
||||
('CURRENT', "Use current", "Use current"),),
|
||||
description="Define how to process material name conflict",
|
||||
default='RENAME',
|
||||
)
|
||||
|
||||
mesh_conflict_strategy: bpy.props.EnumProperty(
|
||||
name="Mesh name conflict",
|
||||
items=(('RENAME', "Rename", "Rename the new one"),
|
||||
('CURRENT', "Use current", "Use current"),),
|
||||
description="Define how to process mesh name conflict",
|
||||
default='RENAME',
|
||||
)
|
||||
|
||||
object_conflict_strategy: bpy.props.EnumProperty(
|
||||
name="Object name conflict",
|
||||
items=(('RENAME', "Rename", "Rename the new one"),
|
||||
('CURRENT', "Use current", "Use current"),),
|
||||
description="Define how to process object name conflict",
|
||||
default='RENAME',
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
return (os.path.isdir(prefs.temp_texture_folder) and os.path.isdir(prefs.external_folder))
|
||||
|
||||
def execute(self, context):
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
import_bm(context, self.filepath,
|
||||
prefs.no_component_collection, prefs.external_folder, prefs.temp_texture_folder,
|
||||
self.texture_conflict_strategy, self.material_conflict_strategy,
|
||||
self.mesh_conflict_strategy, self.object_conflict_strategy)
|
||||
|
||||
self.report({'INFO'}, "BM File Import Finished.")
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def import_bm(context, bmx_filepath, prefs_fncg, prefs_externalTexture, prefs_tempTextureFolder, opts_texture, opts_material, opts_mesh, opts_object):
|
||||
# ============================================
|
||||
# alloc a temp folder for decompress
|
||||
utils_tempFolderObj = tempfile.TemporaryDirectory()
|
||||
utils_tempFolder = utils_tempFolderObj.name
|
||||
utils_tempTextureFolder = os.path.join(utils_tempFolder, "Texture")
|
||||
# decompress
|
||||
UTILS_zip_helper.decompress(utils_tempFolder, bmx_filepath)
|
||||
|
||||
# ============================================
|
||||
# read bmx file officially
|
||||
# index.bm
|
||||
objectList = []
|
||||
meshList = []
|
||||
materialList = []
|
||||
textureList = []
|
||||
with open(os.path.join(utils_tempFolder, "index.bm"), "rb") as findex:
|
||||
# check version first
|
||||
index_gottenVersion = UTILS_file_io.read_uint32(findex)
|
||||
if (index_gottenVersion != UTILS_constants.bmfile_currentVersion):
|
||||
# clean temp folder, output error
|
||||
UTILS_functions.show_message_box(
|
||||
("Unsupported BM spec. Expect: {} Gotten: {}".format(UTILS_constants.bmfile_currentVersion, index_gottenVersion), ),
|
||||
"Unsupported BM spec", UTILS_icons_manager.blender_error_icon)
|
||||
findex.close()
|
||||
utils_tempFolderObj.cleanup()
|
||||
return
|
||||
|
||||
# collect block header data
|
||||
while len(UTILS_file_io.peek_stream(findex)) != 0:
|
||||
# read
|
||||
index_name = UTILS_file_io.read_string(findex)
|
||||
index_type = UTILS_file_io.read_uint8(findex)
|
||||
index_offset = UTILS_file_io.read_uint64(findex)
|
||||
index_blockCache = _InfoBlockHelper(index_name, index_offset)
|
||||
|
||||
# grouping into list
|
||||
if index_type == UTILS_constants.BmfileInfoType.OBJECT:
|
||||
objectList.append(index_blockCache)
|
||||
elif index_type == UTILS_constants.BmfileInfoType.MESH:
|
||||
meshList.append(index_blockCache)
|
||||
elif index_type == UTILS_constants.BmfileInfoType.MATERIAL:
|
||||
materialList.append(index_blockCache)
|
||||
elif index_type == UTILS_constants.BmfileInfoType.TEXTURE:
|
||||
textureList.append(index_blockCache)
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
# texture.bm
|
||||
with open(os.path.join(utils_tempFolder, "texture.bm"), "rb") as ftexture:
|
||||
for item in textureList:
|
||||
# seek to block
|
||||
ftexture.seek(item.offset, os.SEEK_SET)
|
||||
|
||||
# read data
|
||||
texture_filename = UTILS_file_io.read_string(ftexture)
|
||||
texture_isExternal = UTILS_file_io.read_bool(ftexture)
|
||||
if texture_isExternal:
|
||||
(texture_target, skip_init) = UTILS_functions.create_instance_with_option(
|
||||
UTILS_constants.BmfileInfoType.TEXTURE, item.name, opts_texture,
|
||||
extra_texture_filename= texture_filename, extra_texture_path= prefs_externalTexture)
|
||||
else:
|
||||
# not external. copy temp file into blender temp. then use it.
|
||||
# try copy. if fail, don't need to do more
|
||||
try:
|
||||
shutil.copy(os.path.join(utils_tempTextureFolder, texture_filename),
|
||||
os.path.join(prefs_tempTextureFolder, texture_filename))
|
||||
except:
|
||||
pass
|
||||
|
||||
(texture_target, skip_init) = UTILS_functions.create_instance_with_option(
|
||||
UTILS_constants.BmfileInfoType.TEXTURE, item.name, opts_texture,
|
||||
extra_texture_filename= texture_filename, extra_texture_path= prefs_tempTextureFolder)
|
||||
|
||||
# setup name and blender data for header
|
||||
item.blender_data = texture_target
|
||||
|
||||
# material.bm
|
||||
# WARNING: this code is shared with add_floor - create_or_get_material()
|
||||
with open(os.path.join(utils_tempFolder, "material.bm"), "rb") as fmaterial:
|
||||
for item in materialList:
|
||||
# seek to block
|
||||
fmaterial.seek(item.offset, os.SEEK_SET)
|
||||
|
||||
# read data
|
||||
material_colAmbient = UTILS_file_io.read_3vector(fmaterial)
|
||||
material_colDiffuse = UTILS_file_io.read_3vector(fmaterial)
|
||||
material_colSpecular = UTILS_file_io.read_3vector(fmaterial)
|
||||
material_colEmissive = UTILS_file_io.read_3vector(fmaterial)
|
||||
material_specularPower = UTILS_file_io.read_float(fmaterial)
|
||||
material_alphaTest = UTILS_file_io.read_bool(fmaterial)
|
||||
material_alphaBlend = UTILS_file_io.read_bool(fmaterial)
|
||||
material_zBuffer = UTILS_file_io.read_bool(fmaterial)
|
||||
material_twoSided = UTILS_file_io.read_bool(fmaterial)
|
||||
material_useTexture = UTILS_file_io.read_bool(fmaterial)
|
||||
material_texture = UTILS_file_io.read_uint32(fmaterial)
|
||||
|
||||
# alloc basic material
|
||||
(material_target, skip_init) = UTILS_functions.create_instance_with_option(
|
||||
UTILS_constants.BmfileInfoType.MATERIAL, item.name, opts_material)
|
||||
item.blender_data = material_target
|
||||
if skip_init:
|
||||
continue
|
||||
|
||||
# try create material nodes
|
||||
UTILS_functions.create_blender_material(material_target,
|
||||
(True,
|
||||
material_colAmbient, material_colDiffuse, material_colSpecular, material_colEmissive, material_specularPower,
|
||||
material_alphaTest, material_alphaBlend, material_zBuffer, material_twoSided,
|
||||
textureList[material_texture].blender_data if material_useTexture else None)
|
||||
)
|
||||
|
||||
# mesh.bm
|
||||
# WARNING: this code is shared with add_floor
|
||||
with open(os.path.join(utils_tempFolder, "mesh.bm"), "rb") as fmesh:
|
||||
mesh_vList=[]
|
||||
mesh_vtList=[]
|
||||
mesh_vnList=[]
|
||||
mesh_faceList=[]
|
||||
mesh_materialSolt = []
|
||||
for item in meshList:
|
||||
fmesh.seek(item.offset, os.SEEK_SET)
|
||||
|
||||
# create real mesh
|
||||
(mesh_target, skip_init) = UTILS_functions.create_instance_with_option(
|
||||
UTILS_constants.BmfileInfoType.MESH, item.name, opts_mesh)
|
||||
item.blender_data = mesh_target
|
||||
if skip_init:
|
||||
continue
|
||||
|
||||
mesh_vList.clear()
|
||||
mesh_vtList.clear()
|
||||
mesh_vnList.clear()
|
||||
mesh_faceList.clear()
|
||||
mesh_materialSolt.clear()
|
||||
# in first read, store all data into list
|
||||
mesh_listCount = UTILS_file_io.read_uint32(fmesh)
|
||||
for i in range(mesh_listCount):
|
||||
cache = UTILS_file_io.read_3vector(fmesh)
|
||||
# switch yz
|
||||
mesh_vList.append((cache[0], cache[2], cache[1]))
|
||||
mesh_listCount = UTILS_file_io.read_uint32(fmesh)
|
||||
for i in range(mesh_listCount):
|
||||
cache = UTILS_file_io.read_2vector(fmesh)
|
||||
# reverse v
|
||||
mesh_vtList.append((cache[0], -cache[1]))
|
||||
mesh_listCount = UTILS_file_io.read_uint32(fmesh)
|
||||
for i in range(mesh_listCount):
|
||||
cache = UTILS_file_io.read_3vector(fmesh)
|
||||
# switch yz
|
||||
mesh_vnList.append((cache[0], cache[2], cache[1]))
|
||||
|
||||
mesh_listCount = UTILS_file_io.read_uint32(fmesh)
|
||||
for i in range(mesh_listCount):
|
||||
mesh_faceData = UTILS_file_io.read_face(fmesh)
|
||||
mesh_useMaterial = UTILS_file_io.read_bool(fmesh)
|
||||
mesh_materialIndex = UTILS_file_io.read_uint32(fmesh)
|
||||
|
||||
if mesh_useMaterial:
|
||||
mesh_neededMaterial = materialList[mesh_materialIndex].blender_data
|
||||
if mesh_neededMaterial in mesh_materialSolt:
|
||||
mesh_blenderMtlIndex = mesh_materialSolt.index(mesh_neededMaterial)
|
||||
else:
|
||||
mesh_blenderMtlIndex = len(mesh_materialSolt)
|
||||
mesh_materialSolt.append(mesh_neededMaterial)
|
||||
else:
|
||||
mesh_blenderMtlIndex = -1
|
||||
|
||||
# we need invert triangle sort
|
||||
mesh_faceList.append((
|
||||
mesh_faceData[6], mesh_faceData[7], mesh_faceData[8],
|
||||
mesh_faceData[3], mesh_faceData[4], mesh_faceData[5],
|
||||
mesh_faceData[0], mesh_faceData[1], mesh_faceData[2],
|
||||
mesh_blenderMtlIndex
|
||||
))
|
||||
|
||||
# and then we need add material solt for this mesh
|
||||
for mat in mesh_materialSolt:
|
||||
mesh_target.materials.append(mat)
|
||||
|
||||
# then, we need add correspond count for vertices
|
||||
mesh_target.vertices.add(len(mesh_vList))
|
||||
mesh_target.loops.add(len(mesh_faceList)*3) # triangle face confirm
|
||||
mesh_target.polygons.add(len(mesh_faceList))
|
||||
mesh_target.uv_layers.new(do_init=False)
|
||||
mesh_target.create_normals_split()
|
||||
|
||||
# add vertices data
|
||||
mesh_target.vertices.foreach_set("co", unpack_list(mesh_vList))
|
||||
mesh_target.loops.foreach_set("vertex_index", unpack_list(_flat_vertices_index(mesh_faceList)))
|
||||
mesh_target.loops.foreach_set("normal", unpack_list(_flat_vertices_normal(mesh_faceList, mesh_vnList)))
|
||||
mesh_target.uv_layers[0].uv.foreach_set("vector", unpack_list(_flat_vertices_uv(mesh_faceList, mesh_vtList))) # Blender 3.5 CHANGED
|
||||
for i in range(len(mesh_faceList)):
|
||||
mesh_target.polygons[i].loop_start = i * 3
|
||||
# mesh_target.polygons[i].loop_total = 3 # Blender 3.6 CHANGED
|
||||
if mesh_faceList[i][9] != -1:
|
||||
mesh_target.polygons[i].material_index = mesh_faceList[i][9]
|
||||
|
||||
mesh_target.polygons[i].use_smooth = True
|
||||
|
||||
mesh_target.validate(clean_customdata=False)
|
||||
mesh_target.update(calc_edges=False, calc_edges_loose=False)
|
||||
|
||||
|
||||
# object
|
||||
with open(os.path.join(utils_tempFolder, "object.bm"), "rb") as fobject:
|
||||
|
||||
# we need get needed collection first
|
||||
blender_viewLayer = context.view_layer
|
||||
blender_collection = blender_viewLayer.active_layer_collection.collection
|
||||
if prefs_fncg == "":
|
||||
# fncg stands with Forced Non-Component Group
|
||||
object_fncgCollection = None
|
||||
else:
|
||||
try:
|
||||
# try get collection
|
||||
object_fncgCollection = bpy.data.collections[prefs_fncg]
|
||||
except:
|
||||
# fail to get, create new one under active collection instead
|
||||
object_fncgCollection = bpy.data.collections.new(prefs_fncg)
|
||||
blender_collection.children.link(object_fncgCollection)
|
||||
|
||||
# start process it
|
||||
object_groupList = []
|
||||
for item in objectList:
|
||||
fobject.seek(item.offset, os.SEEK_SET)
|
||||
|
||||
# read data
|
||||
object_isComponent = UTILS_file_io.read_bool(fobject)
|
||||
#object_isForcedNoComponent = UTILS_file_io.read_bool(fobject)
|
||||
object_isHidden = UTILS_file_io.read_bool(fobject)
|
||||
object_worldMatrix = UTILS_file_io.read_world_materix(fobject)
|
||||
object_groupListCount = UTILS_file_io.read_uint32(fobject)
|
||||
object_groupList.clear()
|
||||
for i in range(object_groupListCount):
|
||||
object_groupList.append(UTILS_file_io.read_string(fobject))
|
||||
object_meshIndex = UTILS_file_io.read_uint32(fobject)
|
||||
|
||||
# got mesh first
|
||||
if object_isComponent:
|
||||
object_neededMesh = UTILS_functions.load_component(object_meshIndex)
|
||||
else:
|
||||
object_neededMesh = meshList[object_meshIndex].blender_data
|
||||
|
||||
# create real object
|
||||
(object_target, skip_init) = UTILS_functions.create_instance_with_option(
|
||||
UTILS_constants.BmfileInfoType.OBJECT, item.name, opts_object,
|
||||
extra_mesh=object_neededMesh)
|
||||
if skip_init:
|
||||
continue
|
||||
|
||||
# link to correct collection
|
||||
if (object_fncgCollection is not None) and (not object_isComponent) and UTILS_functions.is_component(item.name):
|
||||
# a object should be grouped into fncg should check following requirements
|
||||
# fncg is not null
|
||||
# this object is a normal object
|
||||
# but its name match component format
|
||||
object_fncgCollection.objects.link(object_target)
|
||||
else:
|
||||
# otherwise, group it into normal collection
|
||||
blender_collection.objects.link(object_target)
|
||||
object_target.matrix_world = object_worldMatrix
|
||||
object_target.hide_set(object_isHidden)
|
||||
|
||||
# write custom property
|
||||
if len(object_groupList) != 0:
|
||||
UTILS_virtools_prop.fill_virtools_group_data(object_target, tuple(object_groupList))
|
||||
else:
|
||||
UTILS_virtools_prop.fill_virtools_group_data(object_target, None)
|
||||
|
||||
# update view layer after all objects has been imported
|
||||
blender_viewLayer.update()
|
||||
|
||||
# release temp folder
|
||||
utils_tempFolderObj.cleanup()
|
||||
|
||||
|
||||
# ==========================================
|
||||
# blender related functions
|
||||
|
||||
class _InfoBlockHelper():
|
||||
def __init__(self, name, offset):
|
||||
self.name = name
|
||||
self.offset = offset
|
||||
self.blender_data = None
|
||||
|
||||
def _flat_vertices_index(faceList):
|
||||
for item in faceList:
|
||||
yield (item[0], )
|
||||
yield (item[3], )
|
||||
yield (item[6], )
|
||||
|
||||
def _flat_vertices_normal(faceList, vnList):
|
||||
for item in faceList:
|
||||
yield vnList[item[2]]
|
||||
yield vnList[item[5]]
|
||||
yield vnList[item[8]]
|
||||
|
||||
def _flat_vertices_uv(faceList, vtList):
|
||||
for item in faceList:
|
||||
yield vtList[item[1]]
|
||||
yield vtList[item[4]]
|
||||
yield vtList[item[7]]
|
@ -1,132 +0,0 @@
|
||||
import bpy, mathutils
|
||||
from . import UTILS_functions
|
||||
|
||||
class BALLANCE_OT_super_align(bpy.types.Operator):
|
||||
"""Align object with 3ds Max style"""
|
||||
bl_idname = "ballance.super_align"
|
||||
bl_label = "3ds Max Align"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
align_x: bpy.props.BoolProperty(name="X position")
|
||||
align_y: bpy.props.BoolProperty(name="Y position")
|
||||
align_z: bpy.props.BoolProperty(name="Z position")
|
||||
|
||||
current_references: bpy.props.EnumProperty(
|
||||
name="Reference (Active Object)",
|
||||
items=(('MIN', "Min", ""),
|
||||
('CENTER', "Center (bound box)", ""),
|
||||
('POINT', "Center (axis)", ""),
|
||||
('MAX', "Max", "")
|
||||
),
|
||||
default='POINT',
|
||||
)
|
||||
|
||||
target_references: bpy.props.EnumProperty(
|
||||
name="Target (Other Objects)",
|
||||
items=(('MIN', "Min", ""),
|
||||
('CENTER', "Center (bound box)", ""),
|
||||
('POINT', "Center (axis)", ""),
|
||||
('MAX', "Max", "")
|
||||
),
|
||||
default='POINT',
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return _check_align_target()
|
||||
|
||||
def execute(self, context):
|
||||
_align_object(self.align_x, self.align_y, self.align_z, self.current_references, self.target_references)
|
||||
return {'FINISHED'}
|
||||
|
||||
"""
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
"""
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
col = layout.column()
|
||||
col.label(text="Align axis")
|
||||
|
||||
row = col.row()
|
||||
row.prop(self, "align_x")
|
||||
row.prop(self, "align_y")
|
||||
row.prop(self, "align_z")
|
||||
|
||||
col.prop(self, "current_references")
|
||||
col.prop(self, "target_references")
|
||||
|
||||
# ============================== method
|
||||
|
||||
def _check_align_target():
|
||||
if bpy.context.active_object is None:
|
||||
return False
|
||||
|
||||
selected = bpy.context.selected_objects[:]
|
||||
length = len(selected)
|
||||
if bpy.context.active_object in selected:
|
||||
length -= 1
|
||||
if length == 0:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _align_object(use_x, use_y, use_z, currentMode, targetMode):
|
||||
if not (use_x or use_y or use_z):
|
||||
return
|
||||
|
||||
# calc active object data
|
||||
currentObj = bpy.context.active_object
|
||||
currentObjBbox = [currentObj.matrix_world @ mathutils.Vector(corner) for corner in currentObj.bound_box]
|
||||
currentObjRef = _provide_obj_reference_point(currentObj, currentObjBbox, currentMode)
|
||||
|
||||
# calc target
|
||||
targetObjList = bpy.context.selected_objects[:]
|
||||
if currentObj in targetObjList:
|
||||
targetObjList.remove(currentObj)
|
||||
|
||||
# process each obj
|
||||
for targetObj in targetObjList:
|
||||
targetObjBbox = [targetObj.matrix_world @ mathutils.Vector(corner) for corner in targetObj.bound_box]
|
||||
targetObjRef = _provide_obj_reference_point(targetObj, targetObjBbox, targetMode)
|
||||
|
||||
if use_x:
|
||||
targetObj.location.x += currentObjRef.x - targetObjRef.x
|
||||
if use_y:
|
||||
targetObj.location.y += currentObjRef.y - targetObjRef.y
|
||||
if use_z:
|
||||
targetObj.location.z += currentObjRef.z - targetObjRef.z
|
||||
|
||||
def _provide_obj_reference_point(obj, vecList, mode):
|
||||
refPoint = mathutils.Vector((0, 0, 0))
|
||||
|
||||
if (mode == 'MIN'):
|
||||
refPoint.x = min([vec.x for vec in vecList])
|
||||
refPoint.y = min([vec.y for vec in vecList])
|
||||
refPoint.z = min([vec.z for vec in vecList])
|
||||
elif (mode == 'MAX'):
|
||||
refPoint.x = max([vec.x for vec in vecList])
|
||||
refPoint.y = max([vec.y for vec in vecList])
|
||||
refPoint.z = max([vec.z for vec in vecList])
|
||||
elif (mode == 'CENTER'):
|
||||
maxVecCache = mathutils.Vector((0, 0, 0))
|
||||
minVecCache = mathutils.Vector((0, 0, 0))
|
||||
|
||||
minVecCache.x = min([vec.x for vec in vecList])
|
||||
minVecCache.y = min([vec.y for vec in vecList])
|
||||
minVecCache.z = min([vec.z for vec in vecList])
|
||||
maxVecCache.x = max([vec.x for vec in vecList])
|
||||
maxVecCache.y = max([vec.y for vec in vecList])
|
||||
maxVecCache.z = max([vec.z for vec in vecList])
|
||||
|
||||
refPoint.x = (maxVecCache.x + minVecCache.x) / 2
|
||||
refPoint.y = (maxVecCache.y + minVecCache.y) / 2
|
||||
refPoint.z = (maxVecCache.z + minVecCache.z) / 2
|
||||
else:
|
||||
refPoint.x = obj.location.x
|
||||
refPoint.y = obj.location.y
|
||||
refPoint.z = obj.location.z
|
||||
|
||||
return refPoint
|
@ -1,240 +0,0 @@
|
||||
import bpy,mathutils
|
||||
import bmesh
|
||||
import math
|
||||
from . import UTILS_functions
|
||||
|
||||
class ScaleDataUnion(object):
|
||||
def __init__(self):
|
||||
self.UseRefPoint: bool = None
|
||||
def SetAsScale(self, scale_num: float):
|
||||
self.UseRefPoint: bool = False
|
||||
self.ScaleSize: float = scale_num
|
||||
def SetAsRefPoint(self, ref_point: int, ref_point_uv: float):
|
||||
self.UseRefPoint: bool = True
|
||||
self.ReferencePoint: int = ref_point
|
||||
self.ReferenceUV: float = ref_point_uv
|
||||
|
||||
class BALLANCE_OT_flatten_uv(bpy.types.Operator):
|
||||
"""Flatten selected face UV. Only works for convex face"""
|
||||
bl_idname = "ballance.flatten_uv"
|
||||
bl_label = "Flatten UV"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
reference_edge : bpy.props.IntProperty(
|
||||
name="Reference Edge",
|
||||
description="The references edge of UV.\nIt will be placed in V axis.",
|
||||
min=0,
|
||||
soft_min=0, soft_max=3,
|
||||
default=0,
|
||||
)
|
||||
|
||||
scale_mode: bpy.props.EnumProperty(
|
||||
name="Scale Mode",
|
||||
items=(('NUM', "Scale Size", "Scale UV with specific number."),
|
||||
('REF', "Ref. Point", "Scale UV with Reference Point feature."),
|
||||
),
|
||||
)
|
||||
|
||||
scale_number : bpy.props.FloatProperty(
|
||||
name="Scale Size",
|
||||
description="The size which will be applied for scale.",
|
||||
min=0,
|
||||
soft_min=0, soft_max=5,
|
||||
default=5.0,
|
||||
step=0.1, precision=1,
|
||||
)
|
||||
|
||||
reference_point : bpy.props.IntProperty(
|
||||
name="Reference Point",
|
||||
description="The references point of UV.\nIt's U component will be set to the number specified by Reference Point UV.\nThis point index is related to the start point of reference edge.",
|
||||
min=2, # 0 and 1 is invalid. we can not order the reference edge to be set on the outside of uv axis
|
||||
soft_min=2, soft_max=3,
|
||||
default=2,
|
||||
)
|
||||
|
||||
reference_uv : bpy.props.FloatProperty(
|
||||
name="Reference Point UV",
|
||||
description="The U component which should be applied to references point in UV.",
|
||||
soft_min=0, soft_max=1,
|
||||
default=0.5,
|
||||
step=0.1, precision=2,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
obj = bpy.context.active_object
|
||||
if obj is None:
|
||||
return False
|
||||
if obj.type != 'MESH':
|
||||
return False
|
||||
if obj.mode != 'EDIT':
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
# construct scale data
|
||||
scale_data: ScaleDataUnion = ScaleDataUnion()
|
||||
if self.scale_mode == 'NUM':
|
||||
scale_data.SetAsScale(self.scale_number)
|
||||
else:
|
||||
scale_data.SetAsRefPoint(self.reference_point, self.reference_uv)
|
||||
|
||||
# do flatten uv and report
|
||||
no_processed_count = _real_flatten_uv(bpy.context.active_object.data, self.reference_edge, scale_data)
|
||||
if no_processed_count != 0:
|
||||
print("[Flatten UV] {} faces may not be processed correctly because they have problem.".format(no_processed_count))
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.emboss = 'NORMAL'
|
||||
layout.prop(self, "reference_edge")
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="Scale Mode")
|
||||
layout.prop(self, "scale_mode", expand=True)
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="Scale Config")
|
||||
if self.scale_mode == 'NUM':
|
||||
layout.prop(self, "scale_number")
|
||||
else:
|
||||
layout.prop(self, "reference_point")
|
||||
layout.prop(self, "reference_uv")
|
||||
|
||||
def _real_flatten_uv(mesh, reference_edge, scale_data: ScaleDataUnion):
|
||||
no_processed_count = 0
|
||||
|
||||
if mesh.uv_layers.active is None:
|
||||
# if no uv, create it
|
||||
mesh.uv_layers.new(do_init=False)
|
||||
|
||||
bm = bmesh.from_edit_mesh(mesh)
|
||||
uv_lay = bm.loops.layers.uv.active # NOTE: this is a part of bmesh. not affected by Blender 3.5 CHANGED.
|
||||
for face in bm.faces:
|
||||
# ========== only process selected face ==========
|
||||
if not face.select:
|
||||
continue
|
||||
|
||||
# ========== resolve reference edge and point ==========
|
||||
# check reference validation
|
||||
allPoint = len(face.loops)
|
||||
if reference_edge >= allPoint: # reference edge overflow
|
||||
no_processed_count += 1
|
||||
continue
|
||||
|
||||
# check scale validation
|
||||
if scale_data.UseRefPoint:
|
||||
if ((scale_data.ReferencePoint <= 1) # reference point too low
|
||||
or (scale_data.ReferencePoint >= allPoint)): # reference point overflow
|
||||
no_processed_count += 1
|
||||
continue
|
||||
else:
|
||||
if round(scale_data.ScaleSize, 7) == 0.0: # invalid scale size
|
||||
no_processed_count += 1
|
||||
continue
|
||||
|
||||
# ========== get correct new corrdinate system ==========
|
||||
# yyc mark:
|
||||
# we use 3 points located in this face to calc
|
||||
# the base of this local uv corredinate system.
|
||||
# however if this 3 points are set in a line,
|
||||
# this method will cause a error, zero vector error.
|
||||
#
|
||||
# if z axis is zero vector, we will try using face normal instead
|
||||
# to try getting correct data.
|
||||
#
|
||||
# zero base is not important. because it will not raise any math exception
|
||||
# just a weird uv. user will notice this problem.
|
||||
|
||||
# get point
|
||||
p1Relative = reference_edge
|
||||
p2Relative = reference_edge + 1
|
||||
p3Relative = reference_edge + 2
|
||||
if p2Relative >= allPoint:
|
||||
p2Relative -= allPoint
|
||||
if p3Relative >= allPoint:
|
||||
p3Relative -= allPoint
|
||||
|
||||
p1 = mathutils.Vector(tuple(face.loops[p1Relative].vert.co[x] for x in range(3)))
|
||||
p2 = mathutils.Vector(tuple(face.loops[p2Relative].vert.co[x] for x in range(3)))
|
||||
p3 = mathutils.Vector(tuple(face.loops[p3Relative].vert.co[x] for x in range(3)))
|
||||
|
||||
# get y axis
|
||||
new_y_axis = p2 - p1
|
||||
new_y_axis.normalize()
|
||||
vec1 = p3 - p2
|
||||
vec1.normalize()
|
||||
|
||||
# get z axis
|
||||
new_z_axis = new_y_axis.cross(vec1)
|
||||
new_z_axis.normalize()
|
||||
if not any(round(v, 7) for v in new_z_axis): # if z is a zero vector, use face normal instead
|
||||
new_z_axis = face.normal.normalized()
|
||||
|
||||
# get x axis
|
||||
new_x_axis = new_y_axis.cross(new_z_axis)
|
||||
new_x_axis.normalize()
|
||||
|
||||
# construct rebase matrix
|
||||
origin_base = mathutils.Matrix((
|
||||
(1.0, 0, 0),
|
||||
(0, 1.0, 0),
|
||||
(0, 0, 1.0)
|
||||
))
|
||||
origin_base.invert_safe()
|
||||
new_base = mathutils.Matrix((
|
||||
(new_x_axis.x, new_y_axis.x, new_z_axis.x),
|
||||
(new_x_axis.y, new_y_axis.y, new_z_axis.y),
|
||||
(new_x_axis.z, new_y_axis.z, new_z_axis.z)
|
||||
))
|
||||
transition_matrix = origin_base @ new_base
|
||||
transition_matrix.invert_safe()
|
||||
|
||||
# ========== rescale correction ==========
|
||||
if scale_data.UseRefPoint:
|
||||
# ref point method
|
||||
# get reference point from loop
|
||||
refpRelative = p1Relative + scale_data.ReferencePoint
|
||||
if refpRelative >= allPoint:
|
||||
refpRelative -= allPoint
|
||||
pRef = mathutils.Vector(tuple(face.loops[refpRelative].vert.co[x] for x in range(3))) - p1
|
||||
|
||||
# calc its U component
|
||||
vec_u = abs((transition_matrix @ pRef).x)
|
||||
if round(vec_u, 7) == 0.0:
|
||||
rescale = 1 # fallback. rescale = 1 will not affect anything
|
||||
else:
|
||||
rescale = scale_data.ReferenceUV / vec_u
|
||||
else:
|
||||
# scale size method
|
||||
# apply rescale directly
|
||||
rescale = 1.0 / scale_data.ScaleSize
|
||||
|
||||
# construct matrix
|
||||
# we only rescale U component (X component)
|
||||
# and 5.0 scale for V component (Y component)
|
||||
scale_matrix = mathutils.Matrix((
|
||||
(rescale, 0, 0),
|
||||
(0, 1.0 / 5.0, 0),
|
||||
(0, 0, 1.0)
|
||||
))
|
||||
# order can not be changed. we order do transition first, then scale it.
|
||||
rescale_transition_matrix = scale_matrix @ transition_matrix
|
||||
|
||||
# ========== process each face ==========
|
||||
for loop_index in range(allPoint):
|
||||
pp = mathutils.Vector(tuple(face.loops[loop_index].vert.co[x] for x in range(3))) - p1
|
||||
ppuv = rescale_transition_matrix @ pp
|
||||
|
||||
# y axis always use 5.0 to scale
|
||||
# however, x need use custom scale correction which has been calculated by our matrix.
|
||||
face.loops[loop_index][uv_lay].uv = (
|
||||
abs(ppuv.x),
|
||||
ppuv.y
|
||||
)
|
||||
|
||||
# Show the updates in the viewport
|
||||
bmesh.update_edit_mesh(mesh)
|
||||
return no_processed_count
|
||||
|
@ -1,193 +0,0 @@
|
||||
import bpy,bmesh
|
||||
import mathutils
|
||||
import bpy.types
|
||||
from . import UTILS_functions, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_rail_uv(bpy.types.Operator):
|
||||
"""Create a UV for rail"""
|
||||
bl_idname = "ballance.rail_uv"
|
||||
bl_label = "Create Rail UV"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
uv_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="Define how to create UV",
|
||||
items=(
|
||||
("POINT", "Point", "All UV will be created in a specific point"),
|
||||
("UNIFORM", "Uniform", "All UV will be created within 1x1"),
|
||||
("SCALE", "Scale", "Give a scale number to scale UV"),
|
||||
("TT", "TT_ReflectionMapping", "The real internal process of Ballance rail")
|
||||
),
|
||||
)
|
||||
|
||||
projection_axis: bpy.props.EnumProperty(
|
||||
name="Projection axis",
|
||||
description="Projection axis",
|
||||
items=(
|
||||
("X", "X axis", "X axis"),
|
||||
("Y", "Y axis", "Y axis"),
|
||||
("Z", "Z axis", "Z axis")
|
||||
),
|
||||
)
|
||||
|
||||
uv_scale : bpy.props.FloatProperty(
|
||||
name="Scale",
|
||||
description="The scale of UV",
|
||||
min=0.0,
|
||||
default=1.0,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return _check_rail_target()
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def execute(self, context):
|
||||
if context.scene.BallanceBlenderPluginProperty.material_picker == None:
|
||||
UTILS_functions.show_message_box(("No specific material", ), "Lost parameter", UTILS_icons_manager.blender_error_icon)
|
||||
else:
|
||||
_create_rail_uv(self.uv_type, context.scene.BallanceBlenderPluginProperty.material_picker, self.uv_scale, self.projection_axis)
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "uv_type")
|
||||
layout.prop(context.scene.BallanceBlenderPluginProperty, "material_picker")
|
||||
if self.uv_type == 'SCALE' or self.uv_type == 'UNIFORM':
|
||||
layout.prop(self, "projection_axis")
|
||||
if self.uv_type == 'SCALE':
|
||||
layout.prop(self, "uv_scale")
|
||||
|
||||
# ====================== method
|
||||
|
||||
def _check_rail_target():
|
||||
for obj in bpy.context.selected_objects:
|
||||
if obj.type != 'MESH':
|
||||
continue
|
||||
if obj.mode != 'OBJECT':
|
||||
continue
|
||||
return True
|
||||
return False
|
||||
|
||||
def _get_distance(iterator):
|
||||
is_first_min = True
|
||||
is_first_max = True
|
||||
max_value = 0.0
|
||||
min_value = 0.0
|
||||
|
||||
for item in iterator:
|
||||
if is_first_max:
|
||||
is_first_max = False
|
||||
max_value = item
|
||||
else:
|
||||
if item > max_value:
|
||||
max_value = item
|
||||
if is_first_min:
|
||||
is_first_min = False
|
||||
min_value = item
|
||||
else:
|
||||
if item < min_value:
|
||||
min_value = item
|
||||
|
||||
return max_value - min_value
|
||||
|
||||
def _create_rail_uv(rail_type, material_pointer, scale_size, projection_axis):
|
||||
objList = []
|
||||
ignoredObj = []
|
||||
for obj in bpy.context.selected_objects:
|
||||
if obj.type != 'MESH':
|
||||
ignoredObj.append(obj.name)
|
||||
continue
|
||||
if obj.mode != 'OBJECT':
|
||||
ignoredObj.append(obj.name)
|
||||
continue
|
||||
if obj.data.uv_layers.active is None:
|
||||
# create a empty uv for it.
|
||||
obj.data.uv_layers.new(do_init=False)
|
||||
|
||||
objList.append(obj)
|
||||
|
||||
for obj in objList:
|
||||
mesh = obj.data
|
||||
|
||||
# clean it material and set rail first
|
||||
obj.data.materials.clear()
|
||||
obj.data.materials.append(material_pointer)
|
||||
|
||||
# copy mesh vec for scale or uniform mode
|
||||
vecList = mesh.vertices[:]
|
||||
real_scale = 1.0
|
||||
if rail_type == 'SCALE':
|
||||
real_scale = scale_size
|
||||
elif rail_type == 'UNIFORM':
|
||||
# calc proper scale
|
||||
if projection_axis == 'X':
|
||||
maxLength = max(
|
||||
_get_distance(vec.co[1] for vec in vecList),
|
||||
_get_distance(vec.co[2] for vec in vecList)
|
||||
)
|
||||
elif projection_axis == 'Y':
|
||||
maxLength = max(
|
||||
_get_distance(vec.co[0] for vec in vecList),
|
||||
_get_distance(vec.co[2] for vec in vecList)
|
||||
)
|
||||
elif projection_axis == 'Z':
|
||||
maxLength = max(
|
||||
_get_distance(vec.co[0] for vec in vecList),
|
||||
_get_distance(vec.co[1] for vec in vecList)
|
||||
)
|
||||
real_scale = 1.0 / maxLength
|
||||
|
||||
# Blender 3.5 CHANGED: mesh.uv_layers.active.data -> mesh.uv_layers.active.uv
|
||||
# .uv -> .vector
|
||||
uv_layer = mesh.uv_layers.active.uv
|
||||
for poly in mesh.polygons:
|
||||
for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total):
|
||||
# get correspond vec index
|
||||
index = mesh.loops[loop_index].vertex_index
|
||||
if rail_type == 'POINT':
|
||||
# set to 1 point
|
||||
uv_layer[loop_index].vector[0] = 0
|
||||
uv_layer[loop_index].vector[1] = 1
|
||||
elif rail_type == 'SCALE' or rail_type == 'UNIFORM':
|
||||
# following xy -> uv scale
|
||||
#
|
||||
# use Z axis: X->U Y->V
|
||||
# use X axis: Y->U Z->V
|
||||
# use Y axis: X->U Z->V
|
||||
if projection_axis == 'X':
|
||||
uv_layer[loop_index].vector[0] = vecList[index].co[1] * real_scale
|
||||
uv_layer[loop_index].vector[1] = vecList[index].co[2] * real_scale
|
||||
elif projection_axis == 'Y':
|
||||
uv_layer[loop_index].vector[0] = vecList[index].co[0] * real_scale
|
||||
uv_layer[loop_index].vector[1] = vecList[index].co[2] * real_scale
|
||||
elif projection_axis == 'Z':
|
||||
uv_layer[loop_index].vector[0] = vecList[index].co[0] * real_scale
|
||||
uv_layer[loop_index].vector[1] = vecList[index].co[1] * real_scale
|
||||
elif rail_type == 'TT':
|
||||
(uv_layer[loop_index].vector[0], uv_layer[loop_index].vector[1]) = _tt_reflection_mapping_compute(
|
||||
vecList[index].co,
|
||||
mesh.loops[loop_index].normal,
|
||||
(0.0, 0.0, 0.0)
|
||||
)
|
||||
|
||||
if len(ignoredObj) != 0:
|
||||
UTILS_functions.show_message_box(
|
||||
("Following objects are not processed due to they are not suit for this function now: ", ) + tuple(ignoredObj),
|
||||
"Execution result", UTILS_icons_manager.blender_info_icon
|
||||
)
|
||||
|
||||
def _tt_reflection_mapping_compute(_point, _n, _refobj):
|
||||
# switch blender coord to virtools coord for convenient calc
|
||||
point = mathutils.Vector((_point[0], _point[2], _point[1]))
|
||||
n = mathutils.Vector((_n[0], _n[2], _n[1])).normalized()
|
||||
refobj = mathutils.Vector((_refobj[0], _refobj[2], _refobj[1]))
|
||||
|
||||
p = (refobj - point).normalized()
|
||||
b=(((2*(p*n))*n)-p).normalized()
|
||||
|
||||
# convert back to blender coord
|
||||
return ((b.x + 1.0) / 2.0, -(b.z + 1.0) / 2.0)
|
@ -1,561 +0,0 @@
|
||||
import bpy
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_virtools_prop, UTILS_icons_manager
|
||||
|
||||
class rename_system_props(bpy.types.Operator):
|
||||
name_standard: bpy.props.EnumProperty(
|
||||
name="Name Standard",
|
||||
description="Choose your name standard",
|
||||
items=(
|
||||
("YYC", "YYC Tools Chains", "YYC Tools Chains name standard."),
|
||||
("IMENGYU", "Imengyu Ballance", "Auto grouping name standard for Imengyu/Ballance")
|
||||
),
|
||||
)
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "name_standard")
|
||||
|
||||
class BALLANCE_OT_rename_by_group(rename_system_props):
|
||||
"""Rename object by Virtools groups"""
|
||||
bl_idname = "ballance.rename_by_group"
|
||||
bl_label = "Rename by Group"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
_rename_core(_NameStandard.CKGROUP, _NameStandard.cvt_std_from_str_to_int(self.name_standard))
|
||||
return {'FINISHED'}
|
||||
|
||||
class BALLANCE_OT_convert_name(rename_system_props):
|
||||
"""Convert name from one name standard to another one."""
|
||||
bl_idname = "ballance.convert_name"
|
||||
bl_label = "Convert Name"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
dest_name_standard: bpy.props.EnumProperty(
|
||||
name="Destination Name Standard",
|
||||
description="Choose your name standard",
|
||||
items=(
|
||||
("YYC", "YYC Tools Chains", "YYC Tools Chains name standard."),
|
||||
("IMENGYU", "Imengyu Ballance", "Auto grouping name standard for Imengyu/Ballance")
|
||||
),
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
_rename_core(
|
||||
_NameStandard.cvt_std_from_str_to_int(self.name_standard),
|
||||
_NameStandard.cvt_std_from_str_to_int(self.dest_name_standard))
|
||||
return {'FINISHED'}
|
||||
|
||||
# rewrite draw func
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "name_standard")
|
||||
layout.prop(self, "dest_name_standard")
|
||||
|
||||
class BALLANCE_OT_auto_grouping(rename_system_props):
|
||||
"""Auto Grouping object according to specific name standard."""
|
||||
bl_idname = "ballance.auto_grouping"
|
||||
bl_label = "Auto Grouping"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
_rename_core(_NameStandard.cvt_std_from_str_to_int(self.name_standard), _NameStandard.CKGROUP)
|
||||
return {'FINISHED'}
|
||||
|
||||
# ==========================================
|
||||
# rename misc funcs
|
||||
|
||||
class _RenameErrorType():
|
||||
ERROR = 0
|
||||
WARNING = 1
|
||||
INFO = 2
|
||||
|
||||
@staticmethod
|
||||
def cvt_err_from_int_to_str(err_t):
|
||||
if err_t == _RenameErrorType.ERROR:
|
||||
return "ERROR"
|
||||
elif err_t == _RenameErrorType.WARNING:
|
||||
return "WARNING"
|
||||
elif err_t == _RenameErrorType.INFO:
|
||||
return "INFO"
|
||||
else:
|
||||
raise Exception("Unknown error type.")
|
||||
|
||||
class _RenameErrorItem():
|
||||
def __init__(self, err_t, description):
|
||||
self.err_type = err_t
|
||||
self.description = description
|
||||
|
||||
def get_presentation(self):
|
||||
return "[{}]\t{}".format(_RenameErrorType.cvt_err_from_int_to_str(self.err_type), self.description)
|
||||
|
||||
class _RenameErrorReporter():
|
||||
def __init__(self):
|
||||
self.err_container: list[_RenameErrorItem] = []
|
||||
|
||||
def add_error(self, description):
|
||||
self.err_container.append(_RenameErrorItem(_RenameErrorType.ERROR, description))
|
||||
def add_warning(self, description):
|
||||
self.err_container.append(_RenameErrorItem(_RenameErrorType.WARNING, description))
|
||||
def add_info(self, description):
|
||||
self.err_container.append(_RenameErrorItem(_RenameErrorType.INFO, description))
|
||||
|
||||
def can_report(self):
|
||||
return len(self.err_container) != 0
|
||||
|
||||
def report(self, header):
|
||||
print(header)
|
||||
for i in self.err_container:
|
||||
print('\t' + i.get_presentation())
|
||||
|
||||
def clear(self):
|
||||
self.err_container.clear()
|
||||
|
||||
class _ObjectBasicType():
|
||||
COMPONENT = 0
|
||||
|
||||
FLOOR = 1
|
||||
RAIL = 2
|
||||
WOOD = 3
|
||||
STOPPER = 4
|
||||
|
||||
DEPTH_CUBE = 5
|
||||
|
||||
DECORATION = 6
|
||||
|
||||
LEVEL_START = 7
|
||||
LEVEL_END = 8
|
||||
CHECKPOINT = 9
|
||||
RESETPOINT = 10
|
||||
|
||||
class _NameStandard():
|
||||
CKGROUP = 0
|
||||
YYC = 1
|
||||
IMENGYU = 2
|
||||
|
||||
@staticmethod
|
||||
def cvt_std_from_str_to_int(std_str):
|
||||
if std_str == "YYC":
|
||||
return _NameStandard.YYC
|
||||
elif std_str == "IMENGYU":
|
||||
return _NameStandard.IMENGYU
|
||||
else:
|
||||
raise Exception("Unknown name standard.")
|
||||
|
||||
class _NameInfoHelper():
|
||||
def __init__(self, _basic_type):
|
||||
self.basic_type = _basic_type
|
||||
|
||||
# extra field notes:
|
||||
# COMPONENT:
|
||||
# component_type(string)
|
||||
# sector(int)
|
||||
# CHECKPOINT, RESETPOINT:
|
||||
# sector(int)(following Ballance index, checkpoint starts with 1)
|
||||
|
||||
def _get_selected_objects():
|
||||
return bpy.context.view_layer.active_layer_collection.collection.objects
|
||||
|
||||
def _get_sector_from_ckgroup(group_set):
|
||||
# this counter is served for stupid
|
||||
# multi-sector-grouping accident.
|
||||
counter = 0
|
||||
last_matched_sector = ''
|
||||
for i in group_set:
|
||||
regex_result = UTILS_constants.rename_regexCKGroupSector.match(i)
|
||||
if regex_result is not None:
|
||||
last_matched_sector = regex_result.group(1)
|
||||
counter += 1
|
||||
|
||||
if counter != 1:
|
||||
return None
|
||||
else:
|
||||
return last_matched_sector
|
||||
|
||||
|
||||
# ==========================================
|
||||
# rename core funcs
|
||||
|
||||
# NOTE: the implement of this function are copied from
|
||||
# BallanceVirtoolsHelper/bvh/features/mapping/grouping.cpp
|
||||
# ---
|
||||
# YYC Tools Chains name standard is Ballance-compatible name standard.
|
||||
# So this functions also serving for `_get_name_info_from_group` function
|
||||
# to help get sector field from PC/PR elements. In ordinary call(external call)
|
||||
# The final error output should be outputed normally. But in the call from
|
||||
# `_get_name_info_from_group`, this function should not output any error.
|
||||
# So parameter `call_internal` is served for this work. In common it is False
|
||||
# to let function output error str normally. But only set it to True in
|
||||
# the call from `_get_name_info_from_group` to disable error output.
|
||||
def _get_name_info_from_yyc_name(obj_name, err_reporter: _RenameErrorReporter, call_internal = False):
|
||||
|
||||
# check component first
|
||||
regex_result = UTILS_constants.rename_regexYYCComponent.match(obj_name)
|
||||
if regex_result is not None:
|
||||
data = _NameInfoHelper(_ObjectBasicType.COMPONENT)
|
||||
data.component_type = regex_result.group(1)
|
||||
data.sector = int(regex_result.group(2))
|
||||
return data
|
||||
|
||||
# check PC PR elements
|
||||
regex_result = UTILS_constants.rename_regexYYCPC.match(obj_name)
|
||||
if regex_result is not None:
|
||||
data = _NameInfoHelper(_ObjectBasicType.CHECKPOINT)
|
||||
data.sector = int(regex_result.group(1))
|
||||
return data
|
||||
regex_result = UTILS_constants.rename_regexYYCPR.match(obj_name)
|
||||
if regex_result is not None:
|
||||
data = _NameInfoHelper(_ObjectBasicType.RESETPOINT)
|
||||
data.sector = int(regex_result.group(1))
|
||||
return data
|
||||
|
||||
# check other unique elements
|
||||
if obj_name == "PS_FourFlames_01":
|
||||
return _NameInfoHelper(_ObjectBasicType.LEVEL_START)
|
||||
if obj_name == "PE_Balloon_01":
|
||||
return _NameInfoHelper(_ObjectBasicType.LEVEL_END)
|
||||
|
||||
# process floors
|
||||
if obj_name.startswith("A_Floor"):
|
||||
return _NameInfoHelper(_ObjectBasicType.FLOOR)
|
||||
if obj_name.startswith("A_Wood"):
|
||||
return _NameInfoHelper(_ObjectBasicType.WOOD)
|
||||
if obj_name.startswith("A_Rail"):
|
||||
return _NameInfoHelper(_ObjectBasicType.RAIL)
|
||||
if obj_name.startswith("A_Stopper"):
|
||||
return _NameInfoHelper(_ObjectBasicType.STOPPER)
|
||||
|
||||
# process others
|
||||
if obj_name.startswith("DepthCubes"):
|
||||
return _NameInfoHelper(_ObjectBasicType.DEPTH_CUBE)
|
||||
if obj_name.startswith("D_"):
|
||||
return _NameInfoHelper(_ObjectBasicType.DECORATION)
|
||||
|
||||
# only output in external calling
|
||||
if not call_internal:
|
||||
err_reporter.add_error("Name match lost.")
|
||||
|
||||
return None
|
||||
|
||||
def _get_name_info_from_imengyu_name(obj_name, err_reporter: _RenameErrorReporter):
|
||||
|
||||
# check component first
|
||||
regex_result = UTILS_constants.rename_regexImengyuComponent.match(obj_name)
|
||||
if regex_result is not None:
|
||||
data = _NameInfoHelper(_ObjectBasicType.COMPONENT)
|
||||
data.component_type = regex_result.group(1)
|
||||
data.sector = int(regex_result.group(2))
|
||||
return data
|
||||
|
||||
# check PC PR elements
|
||||
regex_result = UTILS_constants.rename_regexImengyuPCRComp.match(obj_name)
|
||||
if regex_result is not None:
|
||||
eles_name = regex_result.group(1)
|
||||
if eles_name == 'PC_CheckPoint':
|
||||
data = _NameInfoHelper(_ObjectBasicType.CHECKPOINT)
|
||||
elif eles_name == 'PR_ResetPoint':
|
||||
data = _NameInfoHelper(_ObjectBasicType.RESETPOINT)
|
||||
data.sector = int(regex_result.group(2))
|
||||
return data
|
||||
|
||||
# check other unique elements
|
||||
if obj_name == "PS_LevelStart":
|
||||
return _NameInfoHelper(_ObjectBasicType.LEVEL_START)
|
||||
if obj_name == "PE_LevelEnd":
|
||||
return _NameInfoHelper(_ObjectBasicType.LEVEL_END)
|
||||
|
||||
# process floors
|
||||
if obj_name.startswith("S_Floors"):
|
||||
return _NameInfoHelper(_ObjectBasicType.FLOOR)
|
||||
if obj_name.startswith("S_FloorWoods"):
|
||||
return _NameInfoHelper(_ObjectBasicType.WOOD)
|
||||
if obj_name.startswith("S_FloorRails"):
|
||||
return _NameInfoHelper(_ObjectBasicType.RAIL)
|
||||
if obj_name.startswith("S_FloorStopper"):
|
||||
return _NameInfoHelper(_ObjectBasicType.STOPPER)
|
||||
|
||||
# process others
|
||||
if obj_name.startswith("DepthTestCubes"):
|
||||
return _NameInfoHelper(_ObjectBasicType.DEPTH_CUBE)
|
||||
if obj_name.startswith("O_"):
|
||||
return _NameInfoHelper(_ObjectBasicType.DECORATION)
|
||||
|
||||
err_reporter.add_error("Name match lost.")
|
||||
return None
|
||||
|
||||
def _get_name_info_from_group(obj, err_reporter: _RenameErrorReporter):
|
||||
group_list = UTILS_virtools_prop.get_virtools_group_data(obj)
|
||||
if len(group_list) == 0:
|
||||
# name it as a decoration
|
||||
return _NameInfoHelper(_ObjectBasicType.DECORATION)
|
||||
|
||||
group_set = set(group_list)
|
||||
|
||||
# try to filter unique elements first
|
||||
set_result = UTILS_constants.rename_uniqueComponentsGroupName.intersection(group_set)
|
||||
if len(set_result) == 1:
|
||||
# get it
|
||||
gotten_group_name = (list(set_result))[0]
|
||||
if gotten_group_name == 'PS_Levelstart':
|
||||
return _NameInfoHelper(_ObjectBasicType.LEVEL_START)
|
||||
elif gotten_group_name == 'PE_Levelende':
|
||||
return _NameInfoHelper(_ObjectBasicType.LEVEL_END)
|
||||
elif gotten_group_name == 'PC_Checkpoints' or gotten_group_name == 'PR_Resetpoints':
|
||||
# these type's data should be gotten from its name
|
||||
# use _get_name_info_from_yyc_name to get it
|
||||
# _get_name_info_from_yyc_name is Ballance-compatible name standard
|
||||
data = _get_name_info_from_yyc_name(obj.name, err_reporter, call_internal=True)
|
||||
if data is None:
|
||||
err_reporter.add_error("PC_Checkpoints or PR_Resetpoints detected. But couldn't get sector from name.")
|
||||
return None
|
||||
if data.basic_type != _ObjectBasicType.CHECKPOINT and data.basic_type != _ObjectBasicType.RESETPOINT:
|
||||
# check whether it is checkpoint or resetpoint
|
||||
# if not, it mean that we got error data from name
|
||||
# return None instead
|
||||
err_reporter.add_error("PC_Checkpoints or PR_Resetpoints detected. But name is illegal.")
|
||||
return None
|
||||
# otherwise return data
|
||||
return data
|
||||
else:
|
||||
err_reporter.add_error("The match of Unique Component lost.")
|
||||
return None
|
||||
elif len(set_result) != 0:
|
||||
# must be a weird grouping, report it
|
||||
err_reporter.add_error("A Multi-grouping Unique Component.")
|
||||
return None
|
||||
|
||||
# distinguish normal elements
|
||||
set_result = UTILS_constants.rename_normalComponentsGroupName.intersection(group_set)
|
||||
if len(set_result) == 1:
|
||||
# get it
|
||||
# now try get its sector
|
||||
gotten_elements = (tuple(set_result))[0]
|
||||
gotten_sector = _get_sector_from_ckgroup(group_set)
|
||||
if gotten_sector is None:
|
||||
# fail to get sector
|
||||
err_reporter.add_error("Component detected. But couldn't get sector from CKGroup data.")
|
||||
return None
|
||||
|
||||
data = _NameInfoHelper(_ObjectBasicType.COMPONENT)
|
||||
data.component_type = gotten_elements
|
||||
data.sector = int(gotten_sector)
|
||||
return data
|
||||
elif len(set_result) != 0:
|
||||
# must be a weird grouping, report it
|
||||
err_reporter.add_error("A Multi-grouping Component.")
|
||||
return None
|
||||
|
||||
# distinguish road
|
||||
if 'Phys_FloorRails' in group_set:
|
||||
# rail
|
||||
return _NameInfoHelper(_ObjectBasicType.RAIL)
|
||||
elif 'Phys_Floors' in group_set:
|
||||
# distinguish it between Floor and Wood
|
||||
floor_result =UTILS_constants.rename_floorGroupTester.intersection(group_set)
|
||||
rail_result = UTILS_constants.rename_woodGroupTester.intersection(group_set)
|
||||
if len(floor_result) > 0 and len(rail_result) == 0:
|
||||
return _NameInfoHelper(_ObjectBasicType.FLOOR)
|
||||
elif len(floor_result) == 0 and len(rail_result) > 0:
|
||||
return _NameInfoHelper(_ObjectBasicType.WOOD)
|
||||
else:
|
||||
err_reporter.add_warning("Can't distinguish object between Floors and Rails. Suppose it is Floors.")
|
||||
return _NameInfoHelper(_ObjectBasicType.FLOOR)
|
||||
elif 'Phys_FloorStopper' in group_set:
|
||||
return _NameInfoHelper(_ObjectBasicType.STOPPER)
|
||||
elif 'DepthTestCubes' in group_set:
|
||||
return _NameInfoHelper(_ObjectBasicType.DEPTH_CUBE)
|
||||
|
||||
# no matched
|
||||
err_reporter.add_error("Group match lost.")
|
||||
return None
|
||||
|
||||
def _set_for_yyc_name(obj, name_info, err_reporter: _RenameErrorReporter):
|
||||
basic_type = name_info.basic_type
|
||||
if basic_type == _ObjectBasicType.DECORATION:
|
||||
obj.name = "D_"
|
||||
|
||||
elif basic_type == _ObjectBasicType.LEVEL_START:
|
||||
obj.name = "PS_FourFlames_01"
|
||||
elif basic_type == _ObjectBasicType.LEVEL_END:
|
||||
obj.name = "PE_Balloon_01"
|
||||
elif basic_type == _ObjectBasicType.RESETPOINT:
|
||||
obj.name = "PR_Resetpoint_{:0>2d}".format(name_info.sector)
|
||||
elif basic_type == _ObjectBasicType.CHECKPOINT:
|
||||
obj.name = "PC_TwoFlames_{:0>2d}".format(name_info.sector)
|
||||
|
||||
elif basic_type == _ObjectBasicType.DEPTH_CUBE:
|
||||
obj.name = "DepthCubes_"
|
||||
|
||||
elif basic_type == _ObjectBasicType.FLOOR:
|
||||
obj.name = "A_Floor_"
|
||||
elif basic_type == _ObjectBasicType.WOOD:
|
||||
obj.name = "A_Wood_"
|
||||
elif basic_type == _ObjectBasicType.RAIL:
|
||||
obj.name = "A_Rail_"
|
||||
elif basic_type == _ObjectBasicType.STOPPER:
|
||||
obj.name = "A_Stopper_"
|
||||
|
||||
elif basic_type == _ObjectBasicType.COMPONENT:
|
||||
obj.name = "{}_{:0>2d}_".format(name_info.component_type, name_info.sector)
|
||||
|
||||
|
||||
def _set_for_imengyu_name(obj, name_info, err_reporter: _RenameErrorReporter):
|
||||
basic_type = name_info.basic_type
|
||||
if basic_type == _ObjectBasicType.DECORATION:
|
||||
obj.name = "O_"
|
||||
|
||||
elif basic_type == _ObjectBasicType.LEVEL_START:
|
||||
obj.name = "PS_LevelStart"
|
||||
elif basic_type == _ObjectBasicType.LEVEL_END:
|
||||
obj.name = "PE_LevelEnd"
|
||||
elif basic_type == _ObjectBasicType.RESETPOINT:
|
||||
obj.name = "PR_ResetPoint:{:d}".format(name_info.sector)
|
||||
elif basic_type == _ObjectBasicType.CHECKPOINT:
|
||||
obj.name = "PC_CheckPoint:{:d}".format(name_info.sector + 1)
|
||||
|
||||
elif basic_type == _ObjectBasicType.DEPTH_CUBE:
|
||||
obj.name = "DepthTestCubes"
|
||||
|
||||
elif basic_type == _ObjectBasicType.FLOOR:
|
||||
obj.name = "S_Floors"
|
||||
elif basic_type == _ObjectBasicType.WOOD:
|
||||
obj.name = "S_FloorWoods"
|
||||
elif basic_type == _ObjectBasicType.RAIL:
|
||||
obj.name = "S_FloorRails"
|
||||
elif basic_type == _ObjectBasicType.STOPPER:
|
||||
obj.name = "S_FloorStopper"
|
||||
|
||||
elif basic_type == _ObjectBasicType.COMPONENT:
|
||||
obj.name = "{}:{}:{:d}".format(name_info.component_type, obj.name.replace(":", "_"), name_info.sector)
|
||||
|
||||
# NOTE: the implement of this function are copied from
|
||||
# BallanceVirtoolsHelper/bvh/features/mapping/grouping.cpp
|
||||
def _set_for_group(obj, name_info, err_reporter: _RenameErrorReporter):
|
||||
gps = []
|
||||
basic_type = name_info.basic_type
|
||||
|
||||
if basic_type == _ObjectBasicType.DECORATION:
|
||||
# decoration do not need grouping
|
||||
pass
|
||||
|
||||
elif basic_type == _ObjectBasicType.LEVEL_START:
|
||||
gps.append("PS_Levelstart")
|
||||
elif basic_type == _ObjectBasicType.LEVEL_END:
|
||||
gps.append("PE_Levelende")
|
||||
elif basic_type == _ObjectBasicType.RESETPOINT:
|
||||
gps.append("PC_Checkpoints")
|
||||
elif basic_type == _ObjectBasicType.CHECKPOINT:
|
||||
gps.append("PR_Resetpoints")
|
||||
|
||||
elif basic_type == _ObjectBasicType.DEPTH_CUBE:
|
||||
gps.append("DepthTestCubes")
|
||||
|
||||
elif basic_type == _ObjectBasicType.FLOOR:
|
||||
gps.append("Phys_Floors")
|
||||
gps.append("Sound_HitID_01")
|
||||
gps.append("Sound_RollID_01")
|
||||
gps.append("Shadow")
|
||||
elif basic_type == _ObjectBasicType.WOOD:
|
||||
gps.append("Phys_FloorRails")
|
||||
gps.append("Sound_HitID_03")
|
||||
gps.append("Sound_RollID_03")
|
||||
elif basic_type == _ObjectBasicType.RAIL:
|
||||
gps.append("Phys_Floors")
|
||||
gps.append("Sound_HitID_02")
|
||||
gps.append("Sound_RollID_02")
|
||||
gps.append("Shadow")
|
||||
elif basic_type == _ObjectBasicType.STOPPER:
|
||||
gps.append("Phys_FloorStopper")
|
||||
|
||||
elif basic_type == _ObjectBasicType.COMPONENT:
|
||||
gps.append(name_info.component_type)
|
||||
|
||||
# set compabitility for 999 sector loader
|
||||
if (name_info.sector == 9):
|
||||
gps.append("Sector_9")
|
||||
else:
|
||||
gps.append("Sector_{:0>2d}".format(name_info.sector))
|
||||
|
||||
|
||||
# apply to custom property
|
||||
UTILS_virtools_prop.fill_virtools_group_data(obj, tuple(gps))
|
||||
|
||||
# ==========================================
|
||||
# assemble funcs
|
||||
|
||||
def _get_data(obj, standard, err_reporter: _RenameErrorReporter):
|
||||
if standard == _NameStandard.YYC:
|
||||
return _get_name_info_from_yyc_name(obj.name, err_reporter)
|
||||
elif standard == _NameStandard.IMENGYU:
|
||||
return _get_name_info_from_imengyu_name(obj.name, err_reporter)
|
||||
elif standard == _NameStandard.CKGROUP:
|
||||
return _get_name_info_from_group(obj, err_reporter)
|
||||
else:
|
||||
raise Exception("Unknown standard")
|
||||
|
||||
def _set_data(obj, name_info, standard, err_reporter: _RenameErrorReporter):
|
||||
if standard == _NameStandard.YYC:
|
||||
return _set_for_yyc_name(obj, name_info, err_reporter)
|
||||
elif standard == _NameStandard.IMENGYU:
|
||||
return _set_for_imengyu_name(obj, name_info, err_reporter)
|
||||
elif standard == _NameStandard.CKGROUP:
|
||||
return _set_for_group(obj, name_info, err_reporter)
|
||||
else:
|
||||
raise Exception("Unknown standard")
|
||||
|
||||
def _rename_core(source_std, dest_std):
|
||||
if source_std == dest_std:
|
||||
# if source == dest
|
||||
# we do not to do anything
|
||||
return
|
||||
|
||||
# create fail counter and error reporter
|
||||
failed_obj_counter = 0
|
||||
all_obj_counter = 0
|
||||
err_reporter = _RenameErrorReporter()
|
||||
|
||||
print('============')
|
||||
print('Rename System Report')
|
||||
print('------------')
|
||||
for obj in _get_selected_objects():
|
||||
# set counter and name
|
||||
all_obj_counter += 1
|
||||
old_name = new_name = obj.name
|
||||
# get data
|
||||
info = _get_data(obj, source_std, err_reporter)
|
||||
|
||||
# do operation according to whether getting data successfully
|
||||
if info is None:
|
||||
failed_obj_counter += 1
|
||||
else:
|
||||
_set_data(obj, info, dest_std, err_reporter)
|
||||
# refresh obj name
|
||||
new_name = obj.name
|
||||
|
||||
# report result
|
||||
if err_reporter.can_report():
|
||||
if new_name == old_name:
|
||||
report_header = 'For object "{}"'.format(new_name)
|
||||
else:
|
||||
report_header = 'For object "{}" (Old name: "{}")'.format(new_name, old_name)
|
||||
|
||||
err_reporter.report(report_header)
|
||||
# clear report
|
||||
err_reporter.clear()
|
||||
|
||||
|
||||
print('------------')
|
||||
print('All / Failed - {} / {}'.format(all_obj_counter, failed_obj_counter))
|
||||
print('============')
|
||||
|
||||
UTILS_functions.show_message_box(
|
||||
('Rename system report',
|
||||
'View console to get more detail',
|
||||
'All: {}'.format(all_obj_counter),
|
||||
'Failed: {}'.format(failed_obj_counter)),
|
||||
"Info", UTILS_icons_manager.blender_error_icon
|
||||
)
|
@ -1,234 +0,0 @@
|
||||
import bpy, mathutils
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_icons_manager
|
||||
|
||||
# =============== Common Class ================
|
||||
class common_add_component_props(bpy.types.Operator):
|
||||
attentionElements = ("PC_TwoFlames", "PR_Resetpoint")
|
||||
uniqueElements = ("PS_FourFlames", "PE_Balloon")
|
||||
|
||||
elements_sector: bpy.props.IntProperty(
|
||||
name="Sector",
|
||||
description="Define which sector the object will be grouped in",
|
||||
min=1, max=8,
|
||||
default=1,
|
||||
)
|
||||
|
||||
def get_component_name(self, raw_comp_name):
|
||||
if raw_comp_name in self.uniqueElements:
|
||||
return raw_comp_name + "_01"
|
||||
elif raw_comp_name in self.attentionElements:
|
||||
return raw_comp_name + "_0" + str(self.elements_sector)
|
||||
else:
|
||||
return raw_comp_name + "_0" + str(self.elements_sector) + "_"
|
||||
|
||||
def parent_draw(self, parent_layout, raw_comp_name):
|
||||
if raw_comp_name not in self.uniqueElements:
|
||||
parent_layout.prop(self, 'elements_sector')
|
||||
|
||||
class BALLANCE_OT_add_components(common_add_component_props):
|
||||
"""Add Elements"""
|
||||
bl_idname = "ballance.add_components"
|
||||
bl_label = "Add Elements"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
elements_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="This element type",
|
||||
#items=tuple(map(lambda x: (x, x, ""), UTILS_constants.bmfile_componentList)),
|
||||
items=tuple(
|
||||
# token, display name, descriptions, icon, index
|
||||
(blk, blk, "", UTILS_icons_manager.get_element_icon(blk), idx)
|
||||
for idx, blk in enumerate(UTILS_constants.bmfile_componentList)
|
||||
),
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
# get name
|
||||
finalObjectName = self.get_component_name(self.elements_type)
|
||||
|
||||
# create object
|
||||
loadedMesh = UTILS_functions.load_component(
|
||||
UTILS_constants.bmfile_componentList.index(self.elements_type)
|
||||
)
|
||||
obj = bpy.data.objects.new(finalObjectName, loadedMesh)
|
||||
UTILS_functions.add_into_scene_and_move_to_cursor(obj)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
# attension notice
|
||||
if self.elements_type in self.attentionElements:
|
||||
layout.label(text="NOTE: Check Sector ID carefully.")
|
||||
if self.elements_type in self.uniqueElements:
|
||||
layout.label(text="NOTE: This element have unique name.")
|
||||
|
||||
# cfg
|
||||
layout.prop(self, "elements_type")
|
||||
self.parent_draw(layout, self.elements_type)
|
||||
|
||||
@classmethod
|
||||
def draw_blc_menu(self, layout):
|
||||
for item in UTILS_constants.bmfile_componentList:
|
||||
cop = layout.operator(
|
||||
self.bl_idname, text=item,
|
||||
icon_value = UTILS_icons_manager.get_element_icon(item))
|
||||
cop.elements_type = item
|
||||
|
||||
|
||||
class BALLANCE_OT_add_components_dup(common_add_component_props):
|
||||
"""Add Duplicated Elements"""
|
||||
bl_idname = "ballance.add_components_dup"
|
||||
bl_label = "Add Duplicated Elements"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
can_duplicated_elements = (
|
||||
'P_Extra_Point', 'P_Modul_18', 'P_Modul_26'
|
||||
)
|
||||
|
||||
elements_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="This element type",
|
||||
#items=tuple(map(lambda x: (x, x, ""), UTILS_constants.bmfile_componentList)),
|
||||
items=tuple(
|
||||
# token, display name, descriptions, icon, index
|
||||
(blk, blk, "", UTILS_icons_manager.get_element_icon(blk), idx)
|
||||
for idx, blk in enumerate(can_duplicated_elements)
|
||||
),
|
||||
)
|
||||
|
||||
elements_dup_times: bpy.props.IntProperty(
|
||||
name="Duplication Count",
|
||||
description="How many this element should be duplicated.",
|
||||
min=2, max=64,
|
||||
soft_min=2, soft_max=32,
|
||||
default=2,
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
# get name
|
||||
finalObjectName = self.get_component_name(self.elements_type)
|
||||
|
||||
# load mesh
|
||||
loadedMesh = UTILS_functions.load_component(
|
||||
UTILS_constants.bmfile_componentList.index(self.elements_type)
|
||||
)
|
||||
# create object
|
||||
for i in range(self.elements_dup_times):
|
||||
obj = bpy.data.objects.new(finalObjectName, loadedMesh)
|
||||
UTILS_functions.add_into_scene_and_move_to_cursor(obj)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "elements_type")
|
||||
self.parent_draw(layout, self.elements_type)
|
||||
layout.prop(self, "elements_dup_times")
|
||||
|
||||
@classmethod
|
||||
def draw_blc_menu(self, layout):
|
||||
for item in self.can_duplicated_elements:
|
||||
cop = layout.operator(
|
||||
self.bl_idname, text=item,
|
||||
icon_value = UTILS_icons_manager.get_element_icon(item))
|
||||
cop.elements_type = item
|
||||
|
||||
|
||||
class BALLANCE_OT_add_components_series(common_add_component_props):
|
||||
"""Add Elements with a Series."""
|
||||
bl_idname = "ballance.add_components_series"
|
||||
bl_label = "Add Series Elements"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
supported_series = {
|
||||
# format: key: (description: str, real_component: str, unit_transition: mathutils.Vector, default_span: float)
|
||||
# key will become enum property's identifier
|
||||
"MODUL_41": ('Tilting Block Series', 'P_Modul_41', mathutils.Vector((1.0, 0.0, 0.0)), 6.0022),
|
||||
"MODUL_18_V": ('Fan Vertical Series', 'P_Modul_18', mathutils.Vector((0.0, 0.0, 1.0)), 15),
|
||||
"MODUL_18_H": ('Fan Horizonal Series', 'P_Modul_18', mathutils.Vector((1.0, 0.0, 0.0)), 30),
|
||||
}
|
||||
|
||||
# the updator for default span
|
||||
def element_type_updated(self, context):
|
||||
# set span
|
||||
self.elements_span = BALLANCE_OT_add_components_series.supported_series[self.elements_type][3]
|
||||
|
||||
# blender required
|
||||
return None
|
||||
|
||||
elements_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="This element type",
|
||||
#items=tuple(map(lambda x: (x, x, ""), UTILS_constants.bmfile_componentList)),
|
||||
items=tuple(
|
||||
# token, display name, descriptions, icon, index
|
||||
(skey, sitem[0], "", UTILS_icons_manager.get_element_icon(sitem[1]), idx)
|
||||
for (idx, (skey, sitem)) in enumerate(supported_series.items())
|
||||
),
|
||||
default=0,
|
||||
update=element_type_updated
|
||||
)
|
||||
|
||||
elements_dup_times: bpy.props.IntProperty(
|
||||
name="Duplication Count",
|
||||
description="How many this element should be duplicated.",
|
||||
min=2, max=64,
|
||||
soft_min=2, soft_max=32,
|
||||
default=2,
|
||||
)
|
||||
|
||||
elements_span: bpy.props.FloatProperty(
|
||||
name="Elements Span",
|
||||
description="The span between each elements.",
|
||||
min=0.0,
|
||||
default=0.0,
|
||||
)
|
||||
|
||||
def invoke(self, context, event):
|
||||
# force trigger span update once to treat span normally
|
||||
self.element_type_updated(context)
|
||||
|
||||
return self.execute(context)
|
||||
|
||||
def execute(self, context):
|
||||
# get unit span and real element name for loading mesh and creating name
|
||||
(_, real_element_name, unit_span, _) = self.supported_series[self.elements_type]
|
||||
|
||||
# get name
|
||||
finalObjectName = self.get_component_name(real_element_name)
|
||||
# load mesh
|
||||
loadedMesh = UTILS_functions.load_component(
|
||||
UTILS_constants.bmfile_componentList.index(real_element_name)
|
||||
)
|
||||
|
||||
# create object
|
||||
for i in range(self.elements_dup_times):
|
||||
obj = bpy.data.objects.new(finalObjectName, loadedMesh)
|
||||
UTILS_functions.add_into_scene_and_move_to_cursor(obj)
|
||||
obj.matrix_world.translation += unit_span * (self.elements_span * i)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "elements_type")
|
||||
self.parent_draw(layout, self.elements_type)
|
||||
layout.prop(self, "elements_dup_times")
|
||||
layout.prop(self, "elements_span")
|
||||
|
||||
@classmethod
|
||||
def draw_blc_menu(self, layout):
|
||||
for key, item in self.supported_series.items():
|
||||
cop = layout.operator(
|
||||
self.bl_idname, text=item[0],
|
||||
icon_value = UTILS_icons_manager.get_element_icon(item[1]))
|
||||
cop.elements_type = key
|
@ -1,540 +0,0 @@
|
||||
import bpy,mathutils
|
||||
import os, math
|
||||
import ast
|
||||
from bpy_extras import io_utils,node_shader_utils
|
||||
# from bpy_extras.io_utils import unpack_list
|
||||
from bpy_extras.image_utils import load_image
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_safe_eval, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_add_floors(bpy.types.Operator):
|
||||
"""Add Ballance floor"""
|
||||
bl_idname = "ballance.add_floors"
|
||||
bl_label = "Add floor"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
# the updator for default side value
|
||||
def floor_type_updated(self, context):
|
||||
# get floor prototype
|
||||
floor_prototype = UTILS_constants.floor_blockDict[self.floor_type]
|
||||
|
||||
# try sync default value
|
||||
default_sides = floor_prototype['DefaultSideConfig']
|
||||
self.use_2d_top = default_sides['UseTwoDTop']
|
||||
self.use_2d_right = default_sides['UseTwoDRight']
|
||||
self.use_2d_bottom = default_sides['UseTwoDBottom']
|
||||
self.use_2d_left = default_sides['UseTwoDLeft']
|
||||
self.use_3d_top = default_sides['UseThreeDTop']
|
||||
self.use_3d_bottom = default_sides['UseThreeDBottom']
|
||||
|
||||
# blender required
|
||||
return None
|
||||
|
||||
floor_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="Floor type",
|
||||
#items=tuple(
|
||||
# # token, display name, descriptions
|
||||
# (blk, blk, "")
|
||||
# for blk in UTILS_constants.floor_blockDict.keys()
|
||||
#),
|
||||
items=tuple(
|
||||
# token, display name, descriptions, icon, index
|
||||
(blk, blk, "", UTILS_icons_manager.get_floor_icon(blk), idx)
|
||||
for idx, blk in enumerate(UTILS_constants.floor_blockDict.keys())
|
||||
),
|
||||
update=floor_type_updated
|
||||
)
|
||||
|
||||
expand_length_1 : bpy.props.IntProperty(
|
||||
name="D1 length",
|
||||
description="The length of expand direction 1",
|
||||
min=0,
|
||||
default=0,
|
||||
)
|
||||
|
||||
expand_length_2 : bpy.props.IntProperty(
|
||||
name="D2 length",
|
||||
description="The length of expand direction 2",
|
||||
min=0,
|
||||
default=0,
|
||||
)
|
||||
|
||||
height_multiplier : bpy.props.FloatProperty(
|
||||
name="Height",
|
||||
description="The multiplier for height. Default height is 5",
|
||||
min=0.0,
|
||||
default=1.0,
|
||||
)
|
||||
|
||||
use_2d_top : bpy.props.BoolProperty(
|
||||
name="Top edge",
|
||||
default=True
|
||||
)
|
||||
use_2d_right : bpy.props.BoolProperty(
|
||||
name="Right edge",
|
||||
default=False
|
||||
)
|
||||
use_2d_bottom : bpy.props.BoolProperty(
|
||||
name="Bottom edge",
|
||||
default=True
|
||||
)
|
||||
use_2d_left : bpy.props.BoolProperty(
|
||||
name="Left edge",
|
||||
default=True
|
||||
)
|
||||
use_3d_top : bpy.props.BoolProperty(
|
||||
name="Top face",
|
||||
default=True
|
||||
)
|
||||
use_3d_bottom : bpy.props.BoolProperty(
|
||||
name="Bottom face",
|
||||
default=True
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
return os.path.isdir(prefs.external_folder)
|
||||
|
||||
def execute(self, context):
|
||||
# get prefs
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
prefs_externalTexture = prefs.external_folder
|
||||
|
||||
# load mesh
|
||||
objmesh = bpy.data.meshes.new('done_')
|
||||
if self.floor_type in UTILS_constants.floor_basicBlockList:
|
||||
_load_basic_floor(
|
||||
objmesh,
|
||||
self.floor_type,
|
||||
'R0',
|
||||
self.height_multiplier,
|
||||
self.expand_length_1,
|
||||
self.expand_length_2,
|
||||
(self.use_2d_top,
|
||||
self.use_2d_right,
|
||||
self.use_2d_bottom,
|
||||
self.use_2d_left,
|
||||
self.use_3d_top,
|
||||
self.use_3d_bottom),
|
||||
(0.0, 0.0, 0.0),
|
||||
prefs_externalTexture)
|
||||
elif self.floor_type in UTILS_constants.floor_derivedBlockList:
|
||||
_load_derived_floor(
|
||||
objmesh,
|
||||
self.floor_type,
|
||||
self.height_multiplier,
|
||||
self.expand_length_1,
|
||||
self.expand_length_2,
|
||||
(self.use_2d_top,
|
||||
self.use_2d_right,
|
||||
self.use_2d_bottom,
|
||||
self.use_2d_left,
|
||||
self.use_3d_top,
|
||||
self.use_3d_bottom),
|
||||
prefs_externalTexture)
|
||||
else:
|
||||
raise Exception("Fatal error: unknown floor type.")
|
||||
|
||||
# normalization mesh
|
||||
objmesh.validate(clean_customdata=False)
|
||||
objmesh.update(calc_edges=False, calc_edges_loose=False)
|
||||
|
||||
# create object and link it
|
||||
obj=bpy.data.objects.new('A_Floor_BMERevenge_', objmesh)
|
||||
UTILS_functions.add_into_scene_and_move_to_cursor(obj)
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
# yyc marked. Blumia reported.
|
||||
# prepare settings before registing
|
||||
# otherwise the mesh will not be created when first run.
|
||||
# (do not change any properties)
|
||||
|
||||
# yyc marked again.
|
||||
# now I migrate default side value setter to updator of enum property.
|
||||
# nothing need to process in here now.
|
||||
|
||||
# trigger default side props updator
|
||||
self.floor_type_updated(context)
|
||||
|
||||
return self.execute(context)
|
||||
|
||||
|
||||
def draw(self, context):
|
||||
# get floor prototype
|
||||
floor_prototype = UTILS_constants.floor_blockDict[self.floor_type]
|
||||
|
||||
# show property
|
||||
layout = self.layout
|
||||
col = layout.column()
|
||||
col.label(text="Basic param")
|
||||
col.prop(self, "floor_type")
|
||||
col.prop(self, "height_multiplier")
|
||||
|
||||
col.separator()
|
||||
col.label(text="Expand")
|
||||
if floor_prototype['ExpandType'] == 'Column' or floor_prototype['ExpandType'] == 'Freedom':
|
||||
col.prop(self, "expand_length_1")
|
||||
if floor_prototype['ExpandType'] == 'Freedom':
|
||||
col.prop(self, "expand_length_2")
|
||||
col.label(text="Unit size: " + floor_prototype['UnitSize'])
|
||||
col.label(text="Expand mode: " + floor_prototype['ExpandType'])
|
||||
grids = col.grid_flow(row_major=True, columns=3, even_columns=True, even_rows=True, align=True)
|
||||
grids.alignment = 'CENTER'
|
||||
grids.separator()
|
||||
grids.label(text=UTILS_constants.floor_expandDirectionMap[floor_prototype['InitColumnDirection']][floor_prototype['ExpandType']][0])
|
||||
grids.separator()
|
||||
grids.label(text=UTILS_constants.floor_expandDirectionMap[floor_prototype['InitColumnDirection']][floor_prototype['ExpandType']][3])
|
||||
grids.template_icon(icon_value = UTILS_icons_manager.get_floor_icon(self.floor_type))
|
||||
grids.label(text=UTILS_constants.floor_expandDirectionMap[floor_prototype['InitColumnDirection']][floor_prototype['ExpandType']][1])
|
||||
grids.separator()
|
||||
grids.label(text=UTILS_constants.floor_expandDirectionMap[floor_prototype['InitColumnDirection']][floor_prototype['ExpandType']][2])
|
||||
grids.separator()
|
||||
|
||||
col.separator()
|
||||
col.label(text="Faces")
|
||||
row = col.row()
|
||||
row.prop(self, "use_3d_top")
|
||||
row.prop(self, "use_3d_bottom")
|
||||
|
||||
col.separator()
|
||||
col.label(text="Sides")
|
||||
grids = col.grid_flow(row_major=True, columns=3, even_columns=True, even_rows=True, align=True)
|
||||
grids.alignment = 'CENTER'
|
||||
grids.separator()
|
||||
grids.prop(self, "use_2d_top")
|
||||
grids.separator()
|
||||
grids.prop(self, "use_2d_left")
|
||||
grids.template_icon(icon_value = UTILS_icons_manager.get_floor_icon(self.floor_type))
|
||||
grids.prop(self, "use_2d_right")
|
||||
grids.separator()
|
||||
grids.prop(self, "use_2d_bottom")
|
||||
grids.separator()
|
||||
|
||||
def _face_fallback(normal_face, expand_face, height):
|
||||
if expand_face == None:
|
||||
return normal_face
|
||||
|
||||
if height <= 1.0:
|
||||
return normal_face
|
||||
else:
|
||||
return expand_face
|
||||
|
||||
def _create_or_get_material(material_name, prefs_externalTexture):
|
||||
# WARNING: this code is shared with bm_import_export
|
||||
deconflict_mtl_name = "BMERevenge_" + material_name
|
||||
|
||||
# create or get material
|
||||
(mtl, skip_init) = UTILS_functions.create_instance_with_option(
|
||||
UTILS_constants.BmfileInfoType.MATERIAL,
|
||||
deconflict_mtl_name, 'CURRENT'
|
||||
)
|
||||
if skip_init:
|
||||
return mtl
|
||||
|
||||
# initialize material parameter
|
||||
# load texture first
|
||||
texture_filename = UTILS_constants.floor_textureReflactionMap[material_name]
|
||||
deconflict_texture_name = "BMERevenge_" + texture_filename
|
||||
(texture, skip_init) = UTILS_functions.create_instance_with_option(
|
||||
UTILS_constants.BmfileInfoType.TEXTURE,
|
||||
deconflict_texture_name, 'CURRENT',
|
||||
extra_texture_path = prefs_externalTexture, extra_texture_filename = texture_filename
|
||||
)
|
||||
|
||||
# iterate material statistic to get corresponding mtl data
|
||||
for try_item in UTILS_constants.floor_materialStatistic:
|
||||
if material_name in try_item['member']:
|
||||
# got it
|
||||
# set material data
|
||||
# all floor do not have any transparency props, so we provide 4 False value.
|
||||
UTILS_functions.create_blender_material(mtl,
|
||||
(True,
|
||||
try_item['data']['ambient'], try_item['data']['diffuse'],
|
||||
try_item['data']['specular'], try_item['data']['emissive'],
|
||||
try_item['data']['power'],
|
||||
False, False, True, False,
|
||||
texture)
|
||||
)
|
||||
break
|
||||
|
||||
# return mtl
|
||||
return mtl
|
||||
|
||||
def _solve_vec_data(str_data, d1, d2, d3, unit):
|
||||
(cmd_x, cmd_y, cmd_z) = map(lambda x: x.strip(), str_data.split(','))
|
||||
|
||||
# calc raw expand data
|
||||
raw_d1 = d1 * unit
|
||||
raw_d2 = d2 * unit
|
||||
raw_d3 = (d3 - 1) * 5.0 # the 3d heigh unit of ballance floor is always 5.0
|
||||
|
||||
# do safe eval
|
||||
return (
|
||||
UTILS_safe_eval.do_vec_calc(cmd_x, raw_d1, raw_d2, raw_d3),
|
||||
UTILS_safe_eval.do_vec_calc(cmd_y, raw_d1, raw_d2, raw_d3),
|
||||
UTILS_safe_eval.do_vec_calc(cmd_z, raw_d1, raw_d2, raw_d3)
|
||||
)
|
||||
|
||||
def _rotate_translate_vec(_vec, rotation, unit, extra_translate):
|
||||
vec = (
|
||||
_vec[0] - unit / 2,
|
||||
_vec[1] - unit / 2,
|
||||
_vec[2]
|
||||
)
|
||||
|
||||
if rotation == 'R0':
|
||||
coso=1
|
||||
sino=0
|
||||
elif rotation == 'R90':
|
||||
coso=0
|
||||
sino=1
|
||||
elif rotation == 'R180':
|
||||
coso=-1
|
||||
sino=0
|
||||
elif rotation == 'R270':
|
||||
coso=0
|
||||
sino=-1
|
||||
|
||||
return (
|
||||
coso * vec[0] - sino * vec[1] + unit / 2 + extra_translate[0],
|
||||
sino * vec[0] + coso * vec[1] + unit / 2 + extra_translate[1],
|
||||
vec[2] + extra_translate[2]
|
||||
)
|
||||
|
||||
|
||||
def _solve_uv_data(str_data, d1, d2, d3, unit):
|
||||
(cmd_u, cmd_v) = map(lambda x: x.strip(), str_data.split(','))
|
||||
|
||||
# calc raw expand data
|
||||
raw_d1 = d1 * unit
|
||||
raw_d2 = d2 * unit
|
||||
raw_d3 = float(d3 - 1) # the uv heigh unit of ballance floor is always 1.0
|
||||
|
||||
# do safe eval
|
||||
return (
|
||||
UTILS_safe_eval.do_vec_calc(cmd_u, raw_d1, raw_d2, raw_d3),
|
||||
UTILS_safe_eval.do_vec_calc(cmd_v, raw_d1, raw_d2, raw_d3)
|
||||
)
|
||||
|
||||
def _solve_normal_data(point1, point2, point3):
|
||||
p1 = mathutils.Vector(point1)
|
||||
p2 = mathutils.Vector(point2)
|
||||
p3 = mathutils.Vector(point3)
|
||||
|
||||
vector1 = p2 - p1
|
||||
vector2 = p3 - p2
|
||||
|
||||
# do vector x mutiply
|
||||
# vector1 x vector2
|
||||
corss_mul = vector1.cross(vector2)
|
||||
|
||||
# do a normalization
|
||||
corss_mul.normalize()
|
||||
|
||||
return (corss_mul[0], corss_mul[1], corss_mul[2])
|
||||
|
||||
def _solve_expand_param(str_data, d1, d2):
|
||||
(cmd_d1, cmd_d2) = map(lambda x: x.strip(), str_data.split(','))
|
||||
|
||||
# do safe eval
|
||||
return (
|
||||
UTILS_safe_eval.do_expand_calc(cmd_d1, d1, d2),
|
||||
UTILS_safe_eval.do_expand_calc(cmd_d2, d1, d2)
|
||||
)
|
||||
|
||||
def _virtual_foreach_set(collection, field, base_num, data):
|
||||
counter = 0
|
||||
for i in data:
|
||||
exec("a[j]." + field + "=q", {}, {
|
||||
'a': collection,
|
||||
'j': counter + base_num,
|
||||
'q': i
|
||||
})
|
||||
counter+=1
|
||||
|
||||
|
||||
|
||||
'''
|
||||
sides_struct should be a tuple and it always have 6 bool items
|
||||
|
||||
(use_2d_top, use_2d_right, use_2d_bottom, use_2d_left, use_3d_top, use_3d_bottom)
|
||||
|
||||
WARNING: this code is shared with bm import export
|
||||
|
||||
'''
|
||||
def _load_basic_floor(mesh, floor_type, rotation, height_multiplier, d1, d2, sides_struct, extra_translate, prefs_externalTexture):
|
||||
floor_prototype = UTILS_constants.floor_blockDict[floor_type]
|
||||
|
||||
# set some unit
|
||||
if floor_prototype['UnitSize'] == 'Small':
|
||||
block_3dworld_unit = 2.5
|
||||
block_uvworld_unit = 0.5
|
||||
elif floor_prototype['UnitSize'] == 'Large':
|
||||
block_3dworld_unit = 5.0
|
||||
block_uvworld_unit = 1.0
|
||||
|
||||
# got all needed faces
|
||||
needCreatedFaces = []
|
||||
if sides_struct[0]:
|
||||
needCreatedFaces.append(_face_fallback(floor_prototype['TwoDTopSide'], floor_prototype['TwoDTopSideExpand'], height_multiplier))
|
||||
if sides_struct[1]:
|
||||
needCreatedFaces.append(_face_fallback(floor_prototype['TwoDRightSide'], floor_prototype['TwoDRightSideExpand'], height_multiplier))
|
||||
if sides_struct[2]:
|
||||
needCreatedFaces.append(_face_fallback(floor_prototype['TwoDBottomSide'], floor_prototype['TwoDBottomSideExpand'], height_multiplier))
|
||||
if sides_struct[3]:
|
||||
needCreatedFaces.append(_face_fallback(floor_prototype['TwoDLeftSide'], floor_prototype['TwoDLeftSideExpand'], height_multiplier))
|
||||
if sides_struct[4]:
|
||||
needCreatedFaces.append(floor_prototype['ThreeDTopFace'])
|
||||
if sides_struct[5]:
|
||||
needCreatedFaces.append(floor_prototype['ThreeDBottomFace'])
|
||||
|
||||
# resolve face
|
||||
# solve material first
|
||||
materialDict = {}
|
||||
allmat = mesh.materials[:]
|
||||
counter = len(allmat)
|
||||
for face_define in needCreatedFaces:
|
||||
for face in face_define['Faces']:
|
||||
new_texture = face['Textures']
|
||||
if new_texture not in materialDict.keys():
|
||||
# try get from existed solt
|
||||
pending_material = _create_or_get_material(new_texture, prefs_externalTexture)
|
||||
if pending_material not in allmat:
|
||||
# no matched. add it
|
||||
mesh.materials.append(pending_material)
|
||||
materialDict[new_texture] = counter
|
||||
counter += 1
|
||||
else:
|
||||
# use existed index
|
||||
materialDict[new_texture] = allmat.index(pending_material)
|
||||
|
||||
# now, we can process real mesh
|
||||
# load existed base count
|
||||
global_offset_vec = len(mesh.vertices)
|
||||
global_offset_polygons = len(mesh.polygons)
|
||||
global_offset_loops = len(mesh.loops)
|
||||
vecList = []
|
||||
uvList = []
|
||||
normalList = []
|
||||
faceList = []
|
||||
faceIndList = []
|
||||
faceMatList = []
|
||||
for face_define in needCreatedFaces:
|
||||
base_indices = len(vecList)
|
||||
for vec in face_define['Vertices']:
|
||||
vecList.append(_rotate_translate_vec(
|
||||
_solve_vec_data(vec, d1, d2, height_multiplier, block_3dworld_unit),
|
||||
rotation, block_3dworld_unit, extra_translate))
|
||||
|
||||
for face in face_define['Faces']:
|
||||
if face['Type'] == 'RECTANGLE':
|
||||
# rectangle
|
||||
vec_indices = tuple(map(lambda x: x + base_indices, face['Indices']))
|
||||
indCount = 4
|
||||
elif face['Type'] == 'TRIANGLE':
|
||||
# triangle
|
||||
vec_indices = tuple(map(lambda x: x + base_indices, face['Indices']))
|
||||
indCount = 3
|
||||
|
||||
# we need calc normal and push it into list
|
||||
point_normal = _solve_normal_data(vecList[vec_indices[0]], vecList[vec_indices[1]], vecList[vec_indices[2]])
|
||||
for i in range(indCount):
|
||||
normalList.append(point_normal)
|
||||
|
||||
# push indices into list
|
||||
for i in range(indCount):
|
||||
faceList.append(vec_indices[i] + global_offset_vec)
|
||||
|
||||
# push uvs into list
|
||||
for i in range(indCount):
|
||||
uvList.append(_solve_uv_data(face['UVs'][i], d1, d2, height_multiplier, block_uvworld_unit))
|
||||
|
||||
# push material into list
|
||||
faceMatList.append(materialDict[face['Textures']])
|
||||
|
||||
# push face vec count into list
|
||||
faceIndList.append(indCount)
|
||||
|
||||
# push data into blender struct
|
||||
mesh.vertices.add(len(vecList))
|
||||
mesh.loops.add(len(faceList))
|
||||
mesh.polygons.add(len(faceMatList))
|
||||
mesh.create_normals_split()
|
||||
if mesh.uv_layers.active is None:
|
||||
# if no uv, create it
|
||||
mesh.uv_layers.new(do_init=False)
|
||||
|
||||
_virtual_foreach_set(mesh.vertices, "co", global_offset_vec, vecList)
|
||||
_virtual_foreach_set(mesh.loops, "vertex_index", global_offset_loops, faceList)
|
||||
_virtual_foreach_set(mesh.loops, "normal", global_offset_loops, normalList)
|
||||
# Blender 3.5 CHANGED. MeshUVLoop is deprecated and removed in 4.0
|
||||
# See https://wiki.blender.org/wiki/Reference/Release_Notes/3.5/Python_API
|
||||
# use MeshUVLoopLayer.uv[i].vector instead. MeshUVLoopLayer can be fetched from `mesh.uv_layers[i]` or `mesh.uv_layers.active`
|
||||
_virtual_foreach_set(mesh.uv_layers[0].uv, "vector", global_offset_loops, uvList)
|
||||
|
||||
cache_counter = 0
|
||||
for i in range(len(faceMatList)):
|
||||
indCount = faceIndList[i]
|
||||
mesh.polygons[i + global_offset_polygons].loop_start = global_offset_loops + cache_counter
|
||||
# Blender 3.6 CHANGED. loop_total is readonly now. the count of consumed vertices is decided by next loop's loop_start
|
||||
# See: https://wiki.blender.org/wiki/Reference/Release_Notes/3.6/Python_API
|
||||
# mesh.polygons[i + global_offset_polygons].loop_total = indCount
|
||||
mesh.polygons[i + global_offset_polygons].material_index = faceMatList[i]
|
||||
mesh.polygons[i + global_offset_polygons].use_smooth = True
|
||||
cache_counter += indCount
|
||||
|
||||
|
||||
def _load_derived_floor(mesh, floor_type, height_multiplier, d1, d2, sides_struct, prefs_externalTexture):
|
||||
floor_prototype = UTILS_constants.floor_blockDict[floor_type]
|
||||
|
||||
# set some unit
|
||||
if floor_prototype['UnitSize'] == 'Small':
|
||||
block_3dworld_unit = 2.5
|
||||
elif floor_prototype['UnitSize'] == 'Large':
|
||||
block_3dworld_unit = 5.0
|
||||
|
||||
# construct face dict
|
||||
sides_dict = {
|
||||
'True': True,
|
||||
'False': False,
|
||||
'2dTop': sides_struct[0],
|
||||
'2dRight': sides_struct[1],
|
||||
'2dBottom': sides_struct[2],
|
||||
'2dLeft': sides_struct[3],
|
||||
'3dTop': sides_struct[4],
|
||||
'3dBottom': sides_struct[5]
|
||||
}
|
||||
|
||||
# iterate smahsed blocks
|
||||
for blk in floor_prototype['SmashedBlocks']:
|
||||
# calc basic parameter
|
||||
start_pos = _solve_vec_data(blk['StartPosition'], d1, d2, height_multiplier, block_3dworld_unit)
|
||||
expand_param = _solve_expand_param(blk['ExpandParam'], d1, d2)
|
||||
|
||||
# re-calc height multiply for this block.
|
||||
# if the translation of Z is not zero
|
||||
if start_pos[2] != 0.0:
|
||||
raw_height = (height_multiplier - 1) * 5.0 + start_pos[2] # test height
|
||||
blk_height = max(0, (raw_height / 5.0) + 1) # prevent minus height
|
||||
else:
|
||||
blk_height = height_multiplier
|
||||
|
||||
# get face data
|
||||
sides_data = tuple(sides_dict[x] for x in blk['SideSync'].split(';'))
|
||||
|
||||
# call basic floor creator
|
||||
_load_basic_floor(
|
||||
mesh,
|
||||
blk['Type'],
|
||||
blk['Rotation'],
|
||||
blk_height,
|
||||
expand_param[0],
|
||||
expand_param[1],
|
||||
sides_data,
|
||||
start_pos,
|
||||
prefs_externalTexture
|
||||
)
|
||||
|
||||
|
@ -1,140 +0,0 @@
|
||||
import bpy, mathutils
|
||||
from . import UTILS_functions
|
||||
|
||||
class BALLANCE_OT_add_rails(bpy.types.Operator):
|
||||
"""Add rail"""
|
||||
bl_idname = "ballance.add_rails"
|
||||
bl_label = "Add rail section"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
rail_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="Rail type",
|
||||
items=(
|
||||
('MONO', "Monorail", ""),
|
||||
('DOUBLE', "Rail", ""),
|
||||
),
|
||||
default='DOUBLE',
|
||||
)
|
||||
|
||||
rail_radius: bpy.props.FloatProperty(
|
||||
name="Rail Radius",
|
||||
description="Define rail section radius",
|
||||
default=0.375,
|
||||
)
|
||||
|
||||
rail_span: bpy.props.FloatProperty(
|
||||
name="Rail Span",
|
||||
description="The length between 2 single rails.",
|
||||
default=3.75,
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
# create one first
|
||||
firstObj = _create_ballance_circle(self.rail_radius, (0.0, 0.0, 0.0))
|
||||
|
||||
# for double rail
|
||||
if self.rail_type == 'DOUBLE':
|
||||
# create another one
|
||||
secondObj = _create_ballance_circle(self.rail_radius, (self.rail_span, 0.0, 0.0))
|
||||
# merge
|
||||
firstObj = _merge_two_circle(firstObj, secondObj)
|
||||
|
||||
# rename
|
||||
if self.rail_type == 'DOUBLE':
|
||||
firstObj.name = "A_Rail_"
|
||||
else:
|
||||
firstObj.name = "A_Rail_Mono_"
|
||||
# apply 3d cursor
|
||||
UTILS_functions.move_to_cursor(firstObj)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "rail_type")
|
||||
layout.prop(self, "rail_radius")
|
||||
if self.rail_type == 'DOUBLE':
|
||||
layout.prop(self, "rail_span")
|
||||
|
||||
class BALLANCE_OT_add_tunnels(bpy.types.Operator):
|
||||
"""Add rail"""
|
||||
bl_idname = "ballance.add_tunnels"
|
||||
bl_label = "Add tunnel section"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
use_outside: bpy.props.BoolProperty(
|
||||
name="Double Sides",
|
||||
description="Create tunnel section with double sides, not a single face.",
|
||||
default=True,
|
||||
)
|
||||
|
||||
inside_radius: bpy.props.FloatProperty(
|
||||
name="Inside Radius",
|
||||
description="Tunnel inside radius",
|
||||
default=2.5,
|
||||
)
|
||||
|
||||
outside_radius: bpy.props.FloatProperty(
|
||||
name="Outside Radius",
|
||||
description="Tunnel outside radius",
|
||||
default=2.6,
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
# create one first
|
||||
firstObj = _create_ballance_circle(self.inside_radius, (0.0, 0.0, 0.0))
|
||||
|
||||
# for double rail
|
||||
if self.use_outside:
|
||||
# create another one
|
||||
secondObj = _create_ballance_circle(self.outside_radius, (0.0, 0.0, 0.0))
|
||||
# merge
|
||||
firstObj = _merge_two_circle(firstObj, secondObj)
|
||||
|
||||
# rename
|
||||
firstObj.name = "A_Rail_Tunnel_"
|
||||
# apply 3d cursor
|
||||
UTILS_functions.move_to_cursor(firstObj)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "use_outside")
|
||||
layout.prop(self, "inside_radius")
|
||||
if self.use_outside:
|
||||
layout.prop(self, "outside_radius")
|
||||
|
||||
def _create_ballance_circle(radius, loc):
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
bpy.ops.mesh.primitive_circle_add(
|
||||
vertices=8,
|
||||
radius=radius,
|
||||
fill_type='NOTHING',
|
||||
calc_uvs=False,
|
||||
enter_editmode=False,
|
||||
align='WORLD',
|
||||
location=loc
|
||||
)
|
||||
|
||||
created_obj = bpy.context.selected_objects[0]
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
return created_obj
|
||||
|
||||
def _merge_two_circle(obj1, obj2):
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
bpy.context.view_layer.objects.active = obj1
|
||||
obj1.select_set(True)
|
||||
obj2.select_set(True)
|
||||
bpy.ops.object.join()
|
||||
|
||||
return obj1
|
@ -1,161 +0,0 @@
|
||||
import bpy
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_virtools_prop, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_select_virtools_group(UTILS_virtools_prop.common_group_name_props):
|
||||
"""Select objects by Virtools Group."""
|
||||
bl_idname = "ballance.select_virtools_group"
|
||||
bl_label = "Select by Virtools Group"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
selection_type: bpy.props.EnumProperty(
|
||||
name="Mode",
|
||||
description="Selection mode",
|
||||
items=(
|
||||
('SET', "Set", "Sets a new selection.", "SELECT_SET", 0),
|
||||
('EXTEND', "Extend", "Adds newly selected items to the existing selection.", "SELECT_EXTEND", 1),
|
||||
('SUBTRACT', "Subtract", "Removes newly selected items from the existing selection.", "SELECT_SUBTRACT", 2),
|
||||
('DIFFERENCE', "Invert", "Inverts the selection.", "SELECT_DIFFERENCE", 3),
|
||||
('INTERSECT', "Intersect", "Selects items that intersect with the existing selection.", "SELECT_INTERSECT", 4),
|
||||
),
|
||||
default='SET'
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
if self.selection_type == 'SET':
|
||||
# iterate object
|
||||
for obj in bpy.context.scene.objects:
|
||||
# check group and decide whether select this obj
|
||||
obj.select_set(UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string()))
|
||||
|
||||
elif self.selection_type == 'EXTEND':
|
||||
# also iterate all objects
|
||||
for obj in bpy.context.scene.objects:
|
||||
# directly add if group matched. do not deselect anything
|
||||
if UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string()):
|
||||
obj.select_set(True)
|
||||
elif self.selection_type == 'SUBTRACT':
|
||||
# subtract only involving selected item. so we get selected objest first
|
||||
# and iterate it to reduce useless operations
|
||||
selected = bpy.context.selected_objects[:]
|
||||
for obj in selected:
|
||||
# remove matched only
|
||||
if UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string()):
|
||||
obj.select_set(False)
|
||||
|
||||
elif self.selection_type == 'DIFFERENCE':
|
||||
# construct a selected obj set for convenient operations
|
||||
selected_set = set(bpy.context.selected_objects)
|
||||
# iterate all objects
|
||||
for obj in bpy.context.scene.objects:
|
||||
# use xor to select
|
||||
# in_selected XOR in_group
|
||||
obj.select_set((obj in selected_set) ^ UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string()))
|
||||
elif self.selection_type == 'INTERSECT':
|
||||
# like subtract, only iterate selected obj
|
||||
selected = bpy.context.selected_objects[:]
|
||||
for obj in selected:
|
||||
# remove not matched
|
||||
if not UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string()):
|
||||
obj.select_set(False)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.label(text='Selection Parameters')
|
||||
layout.prop(self, 'selection_type', expand=True, icon_only=True)
|
||||
|
||||
layout.separator()
|
||||
layout.label(text='Group Parameters')
|
||||
self.parent_draw(layout)
|
||||
|
||||
class BALLANCE_OT_ctx_set_group(UTILS_virtools_prop.common_group_name_props):
|
||||
"""Grouping selected objects"""
|
||||
bl_idname = "ballance.ctx_set_group"
|
||||
bl_label = "Grouping Objects"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return len(bpy.context.selected_objects) != 0
|
||||
|
||||
def execute(self, context):
|
||||
has_duplicated = False
|
||||
|
||||
# iterate object
|
||||
for obj in bpy.context.selected_objects:
|
||||
# try setting
|
||||
if not UTILS_virtools_prop.add_virtools_group_data(obj, self.get_group_name_string()):
|
||||
has_duplicated = True
|
||||
|
||||
# throw a warning if some objects have duplicated group
|
||||
if has_duplicated:
|
||||
UTILS_functions.show_message_box(
|
||||
("Some objects have duplicated group name.", "These objects have been omitted.", ),
|
||||
"Duplicated Group", UTILS_icons_manager.blender_error_icon
|
||||
)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
self.parent_draw(layout)
|
||||
|
||||
class BALLANCE_OT_ctx_unset_group(UTILS_virtools_prop.common_group_name_props):
|
||||
"""Ungrouping selected objects"""
|
||||
bl_idname = "ballance.ctx_unset_group"
|
||||
bl_label = "Ungrouping Objects"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return len(bpy.context.selected_objects) != 0
|
||||
|
||||
def execute(self, context):
|
||||
lack_group = False
|
||||
|
||||
# iterate object
|
||||
for obj in bpy.context.selected_objects:
|
||||
# try unsetting
|
||||
if not UTILS_virtools_prop.remove_virtools_group_data(obj, self.get_group_name_string()):
|
||||
lack_group = True
|
||||
|
||||
# throw a warning if some objects have duplicated group
|
||||
if lack_group:
|
||||
UTILS_functions.show_message_box(
|
||||
("Some objects lack specified group name.", "These objects have been omitted.", ),
|
||||
"Lack Group", UTILS_icons_manager.blender_error_icon
|
||||
)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
self.parent_draw(layout)
|
||||
|
||||
class BALLANCE_OT_ctx_clear_group(bpy.types.Operator):
|
||||
"""Clear Virtools Groups for selected objects"""
|
||||
bl_idname = "ballance.ctx_clear_group"
|
||||
bl_label = "Clear Grouping"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return len(bpy.context.selected_objects) != 0
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_confirm(self, event)
|
||||
|
||||
def execute(self, context):
|
||||
# iterate object
|
||||
for obj in bpy.context.selected_objects:
|
||||
UTILS_virtools_prop.clear_virtools_group_data(obj)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
@ -1,95 +0,0 @@
|
||||
import bpy
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_virtools_prop, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_add_virtools_group(UTILS_virtools_prop.common_group_name_props):
|
||||
"""Add a Virtools Group for Active Object."""
|
||||
bl_idname = "ballance.add_virtools_group"
|
||||
bl_label = "Add Virtools Group"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return context.object is not None
|
||||
|
||||
def execute(self, context):
|
||||
# try adding
|
||||
obj = context.object
|
||||
if not UTILS_virtools_prop.add_virtools_group_data(obj, self.get_group_name_string()):
|
||||
UTILS_functions.show_message_box(("Group name is duplicated!", ), "Duplicated Name", UTILS_icons_manager.blender_error_icon)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
self.parent_draw(self.layout)
|
||||
|
||||
|
||||
class BALLANCE_OT_rm_virtools_group(bpy.types.Operator):
|
||||
"""Remove a Virtools Group for Active Object."""
|
||||
bl_idname = "ballance.rm_virtools_group"
|
||||
bl_label = "Remove Virtools Group"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
if context.object is None:
|
||||
return False
|
||||
|
||||
obj = context.object
|
||||
gp = UTILS_virtools_prop.get_virtools_group(obj)
|
||||
active_gp = UTILS_virtools_prop.get_active_virtools_group(obj)
|
||||
return int(active_gp) >= 0 and int(active_gp) < len(gp)
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.object
|
||||
UTILS_virtools_prop.remove_virtools_group_data_by_index(obj, int(UTILS_virtools_prop.get_active_virtools_group(obj)))
|
||||
return {'FINISHED'}
|
||||
|
||||
class BALLANCE_OT_clear_virtools_group(bpy.types.Operator):
|
||||
"""Clear All Virtools Group for Active Object."""
|
||||
bl_idname = "ballance.clear_virtools_group"
|
||||
bl_label = "Clear Virtools Group"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return context.object is not None
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_confirm(self, event)
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.object
|
||||
UTILS_virtools_prop.clear_virtools_group_data(obj)
|
||||
return {'FINISHED'}
|
||||
|
||||
class BALLANCE_UL_virtools_group(bpy.types.UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
layout.label(text=item.group_name, translate=False, icon='GROUP')
|
||||
#layout.prop(item, 'group_name', icon='GROUP', emboss=False, text="")
|
||||
|
||||
class BALLANCE_PT_virtools_group(bpy.types.Panel):
|
||||
"""Show Virtools Group Properties."""
|
||||
bl_label = "Virtools Group"
|
||||
bl_idname = "BALLANCE_PT_virtools_group"
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "object"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.object is not None
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
target = bpy.context.active_object
|
||||
|
||||
row = layout.row()
|
||||
row.template_list("BALLANCE_UL_virtools_group", "", target, "virtools_group",
|
||||
target, "active_virtools_group")
|
||||
|
||||
col = row.column(align=True)
|
||||
col.operator(BALLANCE_OT_add_virtools_group.bl_idname, icon='ADD', text="")
|
||||
col.operator(BALLANCE_OT_rm_virtools_group.bl_idname, icon='REMOVE', text="")
|
||||
col.separator()
|
||||
col.operator(BALLANCE_OT_clear_virtools_group.bl_idname, icon='TRASH', text="")
|
@ -1,135 +0,0 @@
|
||||
import bpy
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_virtools_prop, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_apply_virtools_material(bpy.types.Operator):
|
||||
"""Apply Virtools Material to Blender Material."""
|
||||
bl_idname = "ballance.apply_virtools_material"
|
||||
bl_label = "Apply Virtools Material"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.material is not None
|
||||
|
||||
def execute(self, context):
|
||||
mtl = context.material
|
||||
mtl_data = UTILS_virtools_prop.get_virtools_material_data(mtl)
|
||||
|
||||
# check enable, [0] is enable_virtools_material
|
||||
if mtl_data[0]:
|
||||
UTILS_functions.create_material_nodes(mtl, mtl_data)
|
||||
else:
|
||||
UTILS_functions.show_message_box(("Virtools Material is not enabled.", ), "Apply Failed", UTILS_icons_manager.blender_error_icon)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class BALLANCE_OT_parse_virtools_material(bpy.types.Operator):
|
||||
"""Apply Virtools Material to Blender Material."""
|
||||
bl_idname = "ballance.parse_virtools_material"
|
||||
bl_label = "Parse from Blender Principled BSDF"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.material is not None
|
||||
|
||||
def execute(self, context):
|
||||
mtl = context.material
|
||||
mtl_data = UTILS_functions.parse_material_nodes(mtl)
|
||||
if mtl_data is None:
|
||||
UTILS_functions.show_message_box(("Fail to parse Principled BSDF.", ), "Parsing Failed", UTILS_icons_manager.blender_error_icon)
|
||||
else:
|
||||
UTILS_virtools_prop.set_virtools_material_data(mtl, mtl_data)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class BALLANCE_OT_preset_virtools_material(bpy.types.Operator):
|
||||
"""Preset Virtools Material with Original Ballance Data."""
|
||||
bl_idname = "ballance.preset_virtools_material"
|
||||
bl_label = "Preset Virtools Material"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
preset_type: bpy.props.EnumProperty(
|
||||
name="Preset",
|
||||
description="The preset which you want to apply.",
|
||||
items=tuple(
|
||||
(str(idx), item["human-readable"], "Suit for: " + ", ".join(item["member"]))
|
||||
for idx, item in enumerate(UTILS_constants.floor_materialStatistic)
|
||||
),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.material is not None
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
self.layout.prop(self, "preset_type")
|
||||
|
||||
def execute(self, context):
|
||||
preset_idx = int(self.preset_type)
|
||||
preset_data = UTILS_constants.floor_materialStatistic[preset_idx]
|
||||
|
||||
# get data self and only change core colors
|
||||
mtl = context.material
|
||||
vtmtl = UTILS_virtools_prop.get_virtools_material(mtl)
|
||||
|
||||
vtmtl.ambient = preset_data['data']['ambient']
|
||||
vtmtl.diffuse = preset_data['data']['diffuse']
|
||||
vtmtl.specular = preset_data['data']['specular']
|
||||
vtmtl.emissive = preset_data['data']['emissive']
|
||||
vtmtl.specular_power = preset_data['data']['power']
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class BALLANCE_PT_virtools_material(bpy.types.Panel):
|
||||
"""Show Virtools Material Properties."""
|
||||
bl_label = "Virtools Material"
|
||||
bl_idname = "BALLANCE_PT_virtools_material"
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "material"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.material is not None
|
||||
|
||||
def draw_header(self, context):
|
||||
# draw a checkbox in header
|
||||
target = UTILS_virtools_prop.get_virtools_material(context.material)
|
||||
self.layout.prop(target, "enable_virtools_material", text="")
|
||||
|
||||
def draw(self, context):
|
||||
# get layout and target
|
||||
layout = self.layout
|
||||
target = UTILS_virtools_prop.get_virtools_material(context.material)
|
||||
|
||||
# decide visible
|
||||
layout.enabled = target.enable_virtools_material
|
||||
|
||||
# draw layout
|
||||
row = layout.row()
|
||||
row.label(text="Basic Parameters")
|
||||
row.operator(BALLANCE_OT_preset_virtools_material.bl_idname, text="", icon="PRESET")
|
||||
layout.prop(target, 'ambient')
|
||||
layout.prop(target, 'diffuse')
|
||||
layout.prop(target, 'specular')
|
||||
layout.prop(target, 'emissive')
|
||||
layout.prop(target, 'specular_power')
|
||||
layout.prop(target, 'texture', emboss=True)
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="Advanced Parameters")
|
||||
layout.prop(target, 'alpha_test')
|
||||
layout.prop(target, 'alpha_blend')
|
||||
layout.prop(target, 'z_buffer')
|
||||
layout.prop(target, 'two_sided')
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="Operations")
|
||||
layout.operator(BALLANCE_OT_apply_virtools_material.bl_idname, icon="NODETREE")
|
||||
layout.operator(BALLANCE_OT_parse_virtools_material.bl_idname, icon="HIDE_OFF")
|
||||
|
@ -1,399 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
||||
bmfile_currentVersion = 14
|
||||
bmfile_flagUnicode = 0x800
|
||||
bmfile_flagDeflatedMaximum = 0x2
|
||||
bmfile_globalComment = 'Use BM Spec 1.4'.encode('utf-8')
|
||||
|
||||
class BmfileInfoType():
|
||||
OBJECT = 0
|
||||
MESH = 1
|
||||
MATERIAL = 2
|
||||
TEXTURE = 3
|
||||
|
||||
bmfile_externalTextureSet = set([
|
||||
"atari.avi",
|
||||
"atari.bmp",
|
||||
"Ball_LightningSphere1.bmp",
|
||||
"Ball_LightningSphere2.bmp",
|
||||
"Ball_LightningSphere3.bmp",
|
||||
"Ball_Paper.bmp",
|
||||
"Ball_Stone.bmp",
|
||||
"Ball_Wood.bmp",
|
||||
"Brick.bmp",
|
||||
"Button01_deselect.tga",
|
||||
"Button01_select.tga",
|
||||
"Button01_special.tga",
|
||||
"Column_beige.bmp",
|
||||
"Column_beige_fade.tga",
|
||||
"Column_blue.bmp",
|
||||
"Cursor.tga",
|
||||
"Dome.bmp",
|
||||
"DomeEnvironment.bmp",
|
||||
"DomeShadow.tga",
|
||||
"ExtraBall.bmp",
|
||||
"ExtraParticle.bmp",
|
||||
"E_Holzbeschlag.bmp",
|
||||
"FloorGlow.bmp",
|
||||
"Floor_Side.bmp",
|
||||
"Floor_Top_Border.bmp",
|
||||
"Floor_Top_Borderless.bmp",
|
||||
"Floor_Top_Checkpoint.bmp",
|
||||
"Floor_Top_Flat.bmp",
|
||||
"Floor_Top_Profil.bmp",
|
||||
"Floor_Top_ProfilFlat.bmp",
|
||||
"Font_1.tga",
|
||||
"Gravitylogo_intro.bmp",
|
||||
"HardShadow.bmp",
|
||||
"Laterne_Glas.bmp",
|
||||
"Laterne_Schatten.tga",
|
||||
"Laterne_Verlauf.tga",
|
||||
"Logo.bmp",
|
||||
"Metal_stained.bmp",
|
||||
"Misc_Ufo.bmp",
|
||||
"Misc_UFO_Flash.bmp",
|
||||
"Modul03_Floor.bmp",
|
||||
"Modul03_Wall.bmp",
|
||||
"Modul11_13_Wood.bmp",
|
||||
"Modul11_Wood.bmp",
|
||||
"Modul15.bmp",
|
||||
"Modul16.bmp",
|
||||
"Modul18.bmp",
|
||||
"Modul18_Gitter.tga",
|
||||
"Modul30_d_Seiten.bmp",
|
||||
"Particle_Flames.bmp",
|
||||
"Particle_Smoke.bmp",
|
||||
"PE_Bal_balloons.bmp",
|
||||
"PE_Bal_platform.bmp",
|
||||
"PE_Ufo_env.bmp",
|
||||
"Pfeil.tga",
|
||||
"P_Extra_Life_Oil.bmp",
|
||||
"P_Extra_Life_Particle.bmp",
|
||||
"P_Extra_Life_Shadow.bmp",
|
||||
"Rail_Environment.bmp",
|
||||
"sandsack.bmp",
|
||||
"SkyLayer.bmp",
|
||||
"Sky_Vortex.bmp",
|
||||
"Stick_Bottom.tga",
|
||||
"Stick_Stripes.bmp",
|
||||
"Target.bmp",
|
||||
"Tower_Roof.bmp",
|
||||
"Trafo_Environment.bmp",
|
||||
"Trafo_FlashField.bmp",
|
||||
"Trafo_Shadow_Big.tga",
|
||||
"Tut_Pfeil01.tga",
|
||||
"Tut_Pfeil_Hoch.tga",
|
||||
"Wolken_intro.tga",
|
||||
"Wood_Metal.bmp",
|
||||
"Wood_MetalStripes.bmp",
|
||||
"Wood_Misc.bmp",
|
||||
"Wood_Nailed.bmp",
|
||||
"Wood_Old.bmp",
|
||||
"Wood_Panel.bmp",
|
||||
"Wood_Plain.bmp",
|
||||
"Wood_Plain2.bmp",
|
||||
"Wood_Raft.bmp"
|
||||
])
|
||||
|
||||
bmfile_componentList = [
|
||||
"P_Extra_Life",
|
||||
"P_Extra_Point",
|
||||
"P_Trafo_Paper",
|
||||
"P_Trafo_Stone",
|
||||
"P_Trafo_Wood",
|
||||
"P_Ball_Paper",
|
||||
"P_Ball_Stone",
|
||||
"P_Ball_Wood",
|
||||
"P_Box",
|
||||
"P_Dome",
|
||||
"P_Modul_01",
|
||||
"P_Modul_03",
|
||||
"P_Modul_08",
|
||||
"P_Modul_17",
|
||||
"P_Modul_18",
|
||||
"P_Modul_19",
|
||||
"P_Modul_25",
|
||||
"P_Modul_26",
|
||||
"P_Modul_29",
|
||||
"P_Modul_30",
|
||||
"P_Modul_34",
|
||||
"P_Modul_37",
|
||||
"P_Modul_41",
|
||||
"PC_TwoFlames",
|
||||
"PE_Balloon",
|
||||
"PR_Resetpoint",
|
||||
"PS_FourFlames"
|
||||
]
|
||||
|
||||
'''
|
||||
format: key is diection, value is a dict
|
||||
dict's key is expand mode, value is a tuple
|
||||
tuple always have 4 items, it means (TOP_STR, RIGHT_STR, BOTTOM_STR, LEFT_STR)
|
||||
'''
|
||||
floor_expandDirectionMap = {
|
||||
"PositiveX": {
|
||||
"Static": ("X", "X", "X", "X"),
|
||||
"Column": ("X", "X", "D1", "X"),
|
||||
"Freedom": ("X", "X", "D1", "D2"),
|
||||
},
|
||||
"NegativeX": {
|
||||
"Static": ("X", "X", "X", "X"),
|
||||
"Column": ("D1", "X", "X", "X"),
|
||||
"Freedom": ("D1", "D2", "X", "X"),
|
||||
},
|
||||
"PositiveY": {
|
||||
"Static": ("X", "X", "X", "X"),
|
||||
"Column": ("X", "D1", "X", "X"),
|
||||
"Freedom": ("X", "D1", "D2", "X"),
|
||||
},
|
||||
"NegativeY": {
|
||||
"Static": ("X", "X", "X", "X"),
|
||||
"Column": ("X", "X", "X", "D1"),
|
||||
"Freedom": ("D2", "X", "X", "D1"),
|
||||
}
|
||||
}
|
||||
|
||||
floor_textureReflactionMap = {
|
||||
"FloorSide": "Floor_Side.bmp",
|
||||
"FloorTopBorder": "Floor_Top_Border.bmp",
|
||||
"FloorTopBorder_ForSide": "Floor_Top_Border.bmp",
|
||||
"FloorTopBorderless": "Floor_Top_Borderless.bmp",
|
||||
"FloorTopBorderless_ForSide": "Floor_Top_Borderless.bmp",
|
||||
"FloorTopFlat": "Floor_Top_Flat.bmp",
|
||||
"FloorTopProfil": "Floor_Top_Profil.bmp",
|
||||
"FloorTopProfilFlat": "Floor_Top_ProfilFlat.bmp",
|
||||
"BallWood": "Ball_Wood.bmp",
|
||||
"BallPaper": "Ball_Paper.bmp",
|
||||
"BallStone": "Ball_Stone.bmp"
|
||||
}
|
||||
|
||||
# WARNING: this data is shared with `BallanceVirtoolsPlugin/bvh/features/mapping/bmfile_fix_texture.cpp`
|
||||
floor_materialStatistic = [
|
||||
{
|
||||
"human-readable": "Floor Side",
|
||||
"member": [
|
||||
"FloorSide",
|
||||
"FloorTopBorder_ForSide",
|
||||
"FloorTopBorderless_ForSide"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (0, 0, 0),
|
||||
"diffuse": (122 / 255.0, 122 / 255.0, 122 / 255.0),
|
||||
"specular": (0.0, 0.0, 0.0),
|
||||
"emissive": (104 / 255.0, 104 / 255.0, 104 / 255.0),
|
||||
"power": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Floor Top",
|
||||
"member": [
|
||||
"FloorTopBorder",
|
||||
"FloorTopBorderless",
|
||||
"FloorTopFlat",
|
||||
"FloorTopProfil",
|
||||
"FloorTopProfilFlat"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (0, 0, 0),
|
||||
"diffuse": (1.0, 1.0, 1.0),
|
||||
"specular": (80 / 255.0, 80 / 255.0, 80 / 255.0),
|
||||
"emissive": (0.0, 0.0, 0.0),
|
||||
"power": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Transform Paper",
|
||||
"member": [
|
||||
"BallPaper"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (25 / 255.0, 25 / 255.0, 25 / 255.0),
|
||||
"diffuse": (1.0, 1.0, 1.0),
|
||||
"specular": (0.0, 0.0, 0.0),
|
||||
"emissive": (100 / 255.0, 100 / 255.0, 100 / 255.0),
|
||||
"power": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Transform Stone & Wood",
|
||||
"member": [
|
||||
"BallStone",
|
||||
"BallWood"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (25 / 255.0, 25 / 255.0, 25 / 255.0),
|
||||
"diffuse": (1.0, 1.0, 1.0),
|
||||
"specular": (229 / 255.0, 229 / 255.0, 229 / 255.0),
|
||||
"emissive": (60 / 255.0, 60 / 255.0, 60 / 255.0),
|
||||
"power": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Rail",
|
||||
"member": [
|
||||
"Rail"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (0.0, 0.0, 0.0),
|
||||
"diffuse": (100 / 255.0, 118 / 255.0, 133 / 255.0),
|
||||
"specular": (210 / 255.0, 210 / 255.0, 210 / 255.0),
|
||||
"emissive": (124 / 255.0, 134 / 255.0, 150 / 255.0),
|
||||
"power": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Wood Path",
|
||||
"member": [
|
||||
"WoodPanel"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (2 / 255.0, 2 / 255.0, 2 / 255.0),
|
||||
"diffuse": (1.0, 1.0, 1.0),
|
||||
"specular": (59 / 255.0, 59 / 255.0, 59 / 255.0),
|
||||
"emissive": (30 / 255.0, 30 / 255.0, 30 / 255.0),
|
||||
"power": 25
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Wood Chip",
|
||||
"member": [
|
||||
"WoodPlain2"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (25 / 255.0, 25 / 255.0, 25 / 255.0),
|
||||
"diffuse": (1.0, 1.0, 1.0),
|
||||
"specular": (100 / 255.0, 100 / 255.0, 100 / 255.0),
|
||||
"emissive": (50 / 255.0, 50 / 255.0, 50 / 255.0),
|
||||
"power": 50
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
floor_blockDict = {}
|
||||
floor_basicBlockList = []
|
||||
floor_derivedBlockList = []
|
||||
# read from json
|
||||
for walk_root, walk_dirs, walk_files in os.walk(os.path.join(os.path.dirname(__file__), "json", "basic_blocks")):
|
||||
for relfile in walk_files:
|
||||
if not relfile.endswith('.json'): continue
|
||||
with open(os.path.join(walk_root, relfile)) as fp:
|
||||
for item in json.load(fp):
|
||||
floor_basicBlockList.append(item["Type"])
|
||||
floor_blockDict[item["Type"]] = item
|
||||
for walk_root, walk_dirs, walk_files in os.walk(os.path.join(os.path.dirname(__file__), "json", "derived_blocks")):
|
||||
for relfile in walk_files:
|
||||
if not relfile.endswith('.json'): continue
|
||||
with open(os.path.join(walk_root, relfile)) as fp:
|
||||
for item in json.load(fp):
|
||||
floor_derivedBlockList.append(item["Type"])
|
||||
floor_blockDict[item["Type"]] = item
|
||||
|
||||
rename_normalComponentsGroupName = set([
|
||||
"P_Extra_Life",
|
||||
"P_Extra_Point",
|
||||
"P_Trafo_Paper",
|
||||
"P_Trafo_Stone",
|
||||
"P_Trafo_Wood",
|
||||
"P_Ball_Paper",
|
||||
"P_Ball_Stone",
|
||||
"P_Ball_Wood",
|
||||
"P_Box",
|
||||
"P_Dome",
|
||||
"P_Modul_01",
|
||||
"P_Modul_03",
|
||||
"P_Modul_08",
|
||||
"P_Modul_17",
|
||||
"P_Modul_18",
|
||||
"P_Modul_19",
|
||||
"P_Modul_25",
|
||||
"P_Modul_26",
|
||||
"P_Modul_29",
|
||||
"P_Modul_30",
|
||||
"P_Modul_34",
|
||||
"P_Modul_37",
|
||||
"P_Modul_41"
|
||||
])
|
||||
|
||||
rename_uniqueComponentsGroupName = set([
|
||||
"PS_Levelstart",
|
||||
"PE_Levelende",
|
||||
"PC_Checkpoints",
|
||||
"PR_Resetpoints"
|
||||
])
|
||||
|
||||
rename_floorGroupTester = set([
|
||||
"Sound_HitID_01",
|
||||
"Sound_RollID_01"
|
||||
])
|
||||
|
||||
rename_woodGroupTester = set([
|
||||
"Sound_HitID_02",
|
||||
"Sound_RollID_02"
|
||||
])
|
||||
|
||||
# 61 mark: Sector_(0[1-8]|[1-9][0-9]{1,2}|9) may also work
|
||||
rename_regexCKGroupSector = re.compile('^Sector_([123456789]{1}[0123456789]{1}[0123456789]{1}|[123456789]{1}[0123456789]{1}|0[12345678]{1}|9)$')
|
||||
rename_regexYYCComponent = re.compile('^(' + '|'.join(rename_normalComponentsGroupName) + ')_(0[1-9]|[1-9][0-9])_.*$')
|
||||
rename_regexYYCPC = re.compile('^PC_TwoFlames_(0[1-7])$')
|
||||
rename_regexYYCPR = re.compile('^PR_Resetpoint_(0[1-8])$')
|
||||
rename_regexImengyuComponent = re.compile('^(' + '|'.join(rename_normalComponentsGroupName) + '):[^:]*:([1-9]|[1-9][0-9])$')
|
||||
rename_regexImengyuPCRComp = re.compile('^(PC_CheckPoint|PR_ResetPoint):([0-9]+)$')
|
||||
|
||||
propsVtGroups_availableGroups = (
|
||||
"Sector_01",
|
||||
"Sector_02",
|
||||
"Sector_03",
|
||||
"Sector_04",
|
||||
"Sector_05",
|
||||
"Sector_06",
|
||||
"Sector_07",
|
||||
"Sector_08",
|
||||
|
||||
"P_Extra_Life",
|
||||
"P_Extra_Point",
|
||||
"P_Trafo_Paper",
|
||||
"P_Trafo_Stone",
|
||||
"P_Trafo_Wood",
|
||||
"P_Ball_Paper",
|
||||
"P_Ball_Stone",
|
||||
"P_Ball_Wood",
|
||||
"P_Box",
|
||||
"P_Dome",
|
||||
"P_Modul_01",
|
||||
"P_Modul_03",
|
||||
"P_Modul_08",
|
||||
"P_Modul_17",
|
||||
"P_Modul_18",
|
||||
"P_Modul_19",
|
||||
"P_Modul_25",
|
||||
"P_Modul_26",
|
||||
"P_Modul_29",
|
||||
"P_Modul_30",
|
||||
"P_Modul_34",
|
||||
"P_Modul_37",
|
||||
"P_Modul_41",
|
||||
|
||||
"PS_Levelstart",
|
||||
"PE_Levelende",
|
||||
"PC_Checkpoints",
|
||||
"PR_Resetpoints",
|
||||
|
||||
"Sound_HitID_01",
|
||||
"Sound_RollID_01",
|
||||
"Sound_HitID_02",
|
||||
"Sound_RollID_02",
|
||||
"Sound_HitID_03",
|
||||
"Sound_RollID_03",
|
||||
|
||||
"DepthTestCubes",
|
||||
|
||||
"Phys_Floors",
|
||||
"Phys_FloorRails",
|
||||
"Phys_FloorStopper",
|
||||
|
||||
"Shadow"
|
||||
)
|
||||
|
||||
|
@ -1,96 +0,0 @@
|
||||
import bpy, bmesh, bpy_extras, mathutils
|
||||
import struct, shutil, os
|
||||
|
||||
# writer
|
||||
|
||||
def write_string(fs,str):
|
||||
count=len(str)
|
||||
write_uint32(fs,count)
|
||||
fs.write(str.encode("utf_32_le"))
|
||||
|
||||
def write_uint8(fs,num):
|
||||
fs.write(struct.pack("B", num))
|
||||
|
||||
def write_uint32(fs,num):
|
||||
fs.write(struct.pack("I", num))
|
||||
|
||||
def write_uint64(fs,num):
|
||||
fs.write(struct.pack("Q", num))
|
||||
|
||||
def write_bool(fs,boolean):
|
||||
if boolean:
|
||||
write_uint8(fs, 1)
|
||||
else:
|
||||
write_uint8(fs, 0)
|
||||
|
||||
def write_float(fs,fl):
|
||||
fs.write(struct.pack("f", fl))
|
||||
|
||||
def write_world_matrix(fs, matt):
|
||||
mat = matt.transposed()
|
||||
fs.write(struct.pack("ffffffffffffffff",
|
||||
mat[0][0],mat[0][2], mat[0][1], mat[0][3],
|
||||
mat[2][0],mat[2][2], mat[2][1], mat[2][3],
|
||||
mat[1][0],mat[1][2], mat[1][1], mat[1][3],
|
||||
mat[3][0],mat[3][2], mat[3][1], mat[3][3]))
|
||||
|
||||
def write_3vector(fs, x, y ,z):
|
||||
fs.write(struct.pack("fff", x, y ,z))
|
||||
|
||||
def write_color(fs, colors):
|
||||
write_3vector(fs, colors[0], colors[1], colors[2])
|
||||
|
||||
def write_2vector(fs, u, v):
|
||||
fs.write(struct.pack("ff", u, v))
|
||||
|
||||
def write_face(fs, v1, vt1, vn1, v2, vt2, vn2, v3, vt3, vn3):
|
||||
fs.write(struct.pack("IIIIIIIII", v1, vt1, vn1, v2, vt2, vn2, v3, vt3, vn3))
|
||||
|
||||
# reader
|
||||
|
||||
def peek_stream(fs):
|
||||
res = fs.read(1)
|
||||
fs.seek(-1, os.SEEK_CUR)
|
||||
return res
|
||||
|
||||
def read_float(fs):
|
||||
return struct.unpack("f", fs.read(4))[0]
|
||||
|
||||
def read_uint8(fs):
|
||||
return struct.unpack("B", fs.read(1))[0]
|
||||
|
||||
def read_uint32(fs):
|
||||
return struct.unpack("I", fs.read(4))[0]
|
||||
|
||||
def read_uint64(fs):
|
||||
return struct.unpack("Q", fs.read(8))[0]
|
||||
|
||||
def read_string(fs):
|
||||
count = read_uint32(fs)
|
||||
return fs.read(count*4).decode("utf_32_le")
|
||||
|
||||
def read_bool(fs):
|
||||
return read_uint8(fs) != 0
|
||||
|
||||
def read_world_materix(fs):
|
||||
p = struct.unpack("ffffffffffffffff", fs.read(4*4*4))
|
||||
res = mathutils.Matrix((
|
||||
(p[0], p[2], p[1], p[3]),
|
||||
(p[8], p[10], p[9], p[11]),
|
||||
(p[4], p[6], p[5], p[7]),
|
||||
(p[12], p[14], p[13], p[15])))
|
||||
return res.transposed()
|
||||
|
||||
def read_3vector(fs):
|
||||
return struct.unpack("fff", fs.read(3*4))
|
||||
|
||||
def read_2vector(fs):
|
||||
return struct.unpack("ff", fs.read(2*4))
|
||||
|
||||
def read_face(fs):
|
||||
return struct.unpack("IIIIIIIII", fs.read(4*9))
|
||||
|
||||
def read_component_face(fs):
|
||||
return struct.unpack("IIIIII", fs.read(4*6))
|
||||
|
||||
|
@ -1,278 +0,0 @@
|
||||
import bpy, bmesh, bpy_extras, mathutils
|
||||
import struct, shutil, os
|
||||
from bpy_extras.io_utils import unpack_list
|
||||
from bpy_extras.image_utils import load_image
|
||||
from bpy_extras import io_utils, node_shader_utils
|
||||
from . import UTILS_file_io, UTILS_constants, UTILS_virtools_prop
|
||||
|
||||
# =================================
|
||||
# scene operation
|
||||
|
||||
def show_message_box(message, title, icon):
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
for item in message:
|
||||
layout.label(text=item, translate=False)
|
||||
|
||||
bpy.context.window_manager.popup_menu(draw, title = title, icon = icon)
|
||||
|
||||
def add_into_scene_and_move_to_cursor(obj):
|
||||
move_to_cursor(obj)
|
||||
|
||||
view_layer = bpy.context.view_layer
|
||||
collection = view_layer.active_layer_collection.collection
|
||||
collection.objects.link(obj)
|
||||
|
||||
def move_to_cursor(obj):
|
||||
obj.location = bpy.context.scene.cursor.location
|
||||
|
||||
# =================================
|
||||
# is compoent
|
||||
|
||||
def is_component(name):
|
||||
return get_component_id(name) != -1
|
||||
|
||||
def get_component_id(name):
|
||||
for ind, comp in enumerate(UTILS_constants.bmfile_componentList):
|
||||
if name.startswith(comp):
|
||||
return ind
|
||||
return -1
|
||||
|
||||
# =================================
|
||||
# create / parse material
|
||||
|
||||
def create_blender_material(input_mtl, packed_data):
|
||||
# adding material nodes
|
||||
create_material_nodes(input_mtl, packed_data)
|
||||
|
||||
# write custom property
|
||||
UTILS_virtools_prop.set_virtools_material_data(input_mtl, packed_data)
|
||||
|
||||
def create_material_nodes(input_mtl, packed_data):
|
||||
(enable_virtools_material,
|
||||
ambient, diffuse, specular, emissive, specular_power,
|
||||
alpha_test, alpha_blend, z_buffer, two_sided,
|
||||
texture) = packed_data
|
||||
|
||||
# enable nodes mode
|
||||
input_mtl.use_nodes=True
|
||||
# delete all existed nodes
|
||||
for node in input_mtl.node_tree.nodes:
|
||||
input_mtl.node_tree.nodes.remove(node)
|
||||
|
||||
# create ballance-style blender material
|
||||
bnode = input_mtl.node_tree.nodes.new(type="ShaderNodeBsdfPrincipled")
|
||||
mnode = input_mtl.node_tree.nodes.new(type="ShaderNodeOutputMaterial")
|
||||
input_mtl.node_tree.links.new(bnode.outputs[0],mnode.inputs[0])
|
||||
|
||||
input_mtl.metallic = sum(ambient) / 3
|
||||
input_mtl.diffuse_color = [i for i in diffuse] + [1]
|
||||
input_mtl.specular_color = specular
|
||||
input_mtl.specular_intensity = specular_power
|
||||
|
||||
# adding a texture
|
||||
if texture is not None:
|
||||
inode = input_mtl.node_tree.nodes.new(type="ShaderNodeTexImage")
|
||||
inode.image = texture
|
||||
input_mtl.node_tree.links.new(inode.outputs[0], bnode.inputs[0])
|
||||
|
||||
# return None if fail to parse
|
||||
def parse_material_nodes(mtl):
|
||||
# get node
|
||||
mat_wrap = node_shader_utils.PrincipledBSDFWrapper(mtl)
|
||||
# check existence of Principled BSDF
|
||||
if mat_wrap:
|
||||
# we trying get texture data from Principled BSDF
|
||||
use_mirror = mat_wrap.metallic != 0.0
|
||||
if use_mirror:
|
||||
mtl_ambient = (mat_wrap.metallic, mat_wrap.metallic, mat_wrap.metallic)
|
||||
else:
|
||||
mtl_ambient = (1.0, 1.0, 1.0)
|
||||
mtl_diffuse = (mat_wrap.base_color[0], mat_wrap.base_color[1], mat_wrap.base_color[2])
|
||||
mtl_specular = (mat_wrap.specular, mat_wrap.specular, mat_wrap.specular)
|
||||
mtl_emissive = mat_wrap.emission_color[:3]
|
||||
mtl_specularPower = 0.0
|
||||
|
||||
# confirm texture
|
||||
mtl_texture = None
|
||||
tex_wrap = getattr(mat_wrap, "base_color_texture", None)
|
||||
if tex_wrap:
|
||||
image = tex_wrap.image
|
||||
if image:
|
||||
mtl_texture = image
|
||||
|
||||
# return value
|
||||
return (True,
|
||||
mtl_ambient, mtl_diffuse, mtl_specular, mtl_emissive, mtl_specularPower,
|
||||
False, False, True, False,
|
||||
mtl_texture
|
||||
)
|
||||
|
||||
else:
|
||||
return None
|
||||
|
||||
# =================================
|
||||
# load component
|
||||
|
||||
def load_component(component_id):
|
||||
# get component name from id
|
||||
component_name = UTILS_constants.bmfile_componentList[component_id]
|
||||
|
||||
# create real mesh.
|
||||
# if component mesh is existed, use existed one.
|
||||
(mesh, skip_init) = create_instance_with_option(
|
||||
UTILS_constants.BmfileInfoType.MESH,
|
||||
"BlcBldPlg_EleMesh_" + component_name,
|
||||
'CURRENT'
|
||||
)
|
||||
if skip_init:
|
||||
return mesh
|
||||
|
||||
# mesh is not existing. start to load mesh
|
||||
# get file first
|
||||
selected_file = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'meshes',
|
||||
component_name + '.bin'
|
||||
)
|
||||
|
||||
# read file. please note this sector is sync with import_bm's mesh's code. when something change, please change each other.
|
||||
fmesh = open(selected_file, 'rb')
|
||||
|
||||
vList = []
|
||||
vnList = []
|
||||
faceList = []
|
||||
# in first read, store all data into list
|
||||
listCount = UTILS_file_io.read_uint32(fmesh)
|
||||
for i in range(listCount):
|
||||
cache = UTILS_file_io.read_3vector(fmesh)
|
||||
# switch yz
|
||||
vList.append((cache[0], cache[2], cache[1]))
|
||||
listCount = UTILS_file_io.read_uint32(fmesh)
|
||||
for i in range(listCount):
|
||||
cache = UTILS_file_io.read_3vector(fmesh)
|
||||
# switch yz
|
||||
vnList.append((cache[0], cache[2], cache[1]))
|
||||
|
||||
listCount = UTILS_file_io.read_uint32(fmesh)
|
||||
for i in range(listCount):
|
||||
faceData = UTILS_file_io.read_component_face(fmesh)
|
||||
|
||||
# we need invert triangle sort
|
||||
faceList.append((
|
||||
faceData[4], faceData[5],
|
||||
faceData[2], faceData[3],
|
||||
faceData[0], faceData[1]
|
||||
))
|
||||
|
||||
# then, we need add correspond count for vertices
|
||||
mesh.vertices.add(len(vList))
|
||||
mesh.loops.add(len(faceList)*3) # triangle face confirmed
|
||||
mesh.polygons.add(len(faceList))
|
||||
mesh.create_normals_split()
|
||||
|
||||
# add vertices data
|
||||
mesh.vertices.foreach_set("co", unpack_list(vList))
|
||||
mesh.loops.foreach_set("vertex_index", unpack_list(_flat_component_vertices_index(faceList)))
|
||||
mesh.loops.foreach_set("normal", unpack_list(_flat_component_vertices_normal(faceList, vnList)))
|
||||
for i in range(len(faceList)):
|
||||
mesh.polygons[i].loop_start = i * 3
|
||||
# mesh.polygons[i].loop_total = 3 # Blender 3.6 CHANGED
|
||||
mesh.polygons[i].use_smooth = True
|
||||
|
||||
mesh.validate(clean_customdata=False)
|
||||
mesh.update(calc_edges=False, calc_edges_loose=False)
|
||||
|
||||
fmesh.close()
|
||||
|
||||
return mesh
|
||||
|
||||
|
||||
def _flat_component_vertices_index(faceList):
|
||||
for item in faceList:
|
||||
yield (item[0], )
|
||||
yield (item[2], )
|
||||
yield (item[4], )
|
||||
|
||||
def _flat_component_vertices_normal(faceList, vnList):
|
||||
for item in faceList:
|
||||
yield vnList[item[1]]
|
||||
yield vnList[item[3]]
|
||||
yield vnList[item[5]]
|
||||
|
||||
# =================================
|
||||
# create instance with option
|
||||
|
||||
def create_instance_with_option(instance_type, instance_name, instance_opt,
|
||||
extra_mesh = None, extra_texture_path = None, extra_texture_filename = None):
|
||||
"""
|
||||
Create instance with opetions
|
||||
|
||||
`instance_type`, `instance_name`, `instance_opt` are essential for each type instances.
|
||||
For object, you should provide `extra_mesh`.
|
||||
For texture, you should provide `extra_texture_path` and `extra_texture_filename`.
|
||||
|
||||
Value type:
|
||||
`instance_type`: one integer in UTILS_constants.BmfileInfoType
|
||||
`instance_name`: a string of new data block name
|
||||
`instance_opt`: 'RENAME' or 'CURRENT'
|
||||
"""
|
||||
|
||||
def get_instance():
|
||||
try:
|
||||
if instance_type == UTILS_constants.BmfileInfoType.OBJECT:
|
||||
temp_instance = bpy.data.objects[instance_name]
|
||||
elif instance_type == UTILS_constants.BmfileInfoType.MESH:
|
||||
temp_instance = bpy.data.meshes[instance_name]
|
||||
elif instance_type == UTILS_constants.BmfileInfoType.MATERIAL:
|
||||
temp_instance = bpy.data.materials[instance_name]
|
||||
elif instance_type == UTILS_constants.BmfileInfoType.TEXTURE:
|
||||
temp_instance = bpy.data.images[instance_name]
|
||||
|
||||
temp_is_existed = True
|
||||
except:
|
||||
temp_instance = None
|
||||
temp_is_existed = False
|
||||
|
||||
return (temp_instance, temp_is_existed)
|
||||
|
||||
def create_instance():
|
||||
if instance_type == UTILS_constants.BmfileInfoType.OBJECT:
|
||||
instance_obj = bpy.data.objects.new(instance_name, extra_mesh)
|
||||
#instance_obj.name = instance_name
|
||||
elif instance_type == UTILS_constants.BmfileInfoType.MESH:
|
||||
instance_obj = bpy.data.meshes.new(instance_name)
|
||||
#instance_obj.name = instance_name
|
||||
elif instance_type == UTILS_constants.BmfileInfoType.MATERIAL:
|
||||
instance_obj = bpy.data.materials.new(instance_name)
|
||||
#instance_obj.name = instance_name
|
||||
elif instance_type == UTILS_constants.BmfileInfoType.TEXTURE:
|
||||
# this command will also check current available texture
|
||||
# because `get_instance()` only check texture name
|
||||
# but this strategy is not based on texture filepath, so this create method will
|
||||
# correct this problem
|
||||
instance_obj = load_image(extra_texture_filename, extra_texture_path, check_existing=(instance_opt == 'CURRENT'))
|
||||
instance_obj.name = instance_name
|
||||
|
||||
return instance_obj
|
||||
|
||||
# analyze options
|
||||
if (not isinstance(instance_opt, str)) or instance_opt == 'RENAME':
|
||||
# create new instance
|
||||
# or always create new instance if opts is not string
|
||||
temp_instance = create_instance()
|
||||
temp_skip_init = False
|
||||
elif instance_opt == 'CURRENT':
|
||||
# try get instance
|
||||
(temp_instance, temp_is_existed) = get_instance()
|
||||
# if got instance successfully, we do not create new one, otherwise, we should
|
||||
# create new instance
|
||||
if not temp_is_existed:
|
||||
temp_instance = create_instance()
|
||||
temp_skip_init = False
|
||||
else:
|
||||
temp_skip_init = True
|
||||
|
||||
return (temp_instance, temp_skip_init)
|
||||
|
@ -1,98 +0,0 @@
|
||||
import bpy
|
||||
import bpy.utils.previews
|
||||
import os
|
||||
from . import UTILS_constants
|
||||
|
||||
blender_info_icon = 'INFO'
|
||||
blender_warning_icon = 'ERROR'
|
||||
blender_error_icon = 'CANCEL'
|
||||
|
||||
# universal icon loader, all icon are stored in this preview collection
|
||||
universal_icons = None
|
||||
|
||||
# empty icon for placeholder
|
||||
empty_icon_id = 0
|
||||
|
||||
# a map. key is block name, value is loaded icon id
|
||||
floor_icons_map: dict = {}
|
||||
element_icons_map: dict = {}
|
||||
groupext_icons_map: dict = {}
|
||||
|
||||
group_name_conv_map: dict = {
|
||||
"PS_Levelstart": "PS_FourFlames",
|
||||
"PE_Levelende": "PE_Balloon",
|
||||
"PC_Checkpoints": "PC_TwoFlames",
|
||||
"PR_Resetpoints": "PR_Resetpoint",
|
||||
|
||||
"Sound_HitID_01": "SoundID_01",
|
||||
"Sound_RollID_01": "SoundID_01",
|
||||
"Sound_HitID_02": "SoundID_02",
|
||||
"Sound_RollID_02": "SoundID_02",
|
||||
"Sound_HitID_03": "SoundID_03",
|
||||
"Sound_RollID_03": "SoundID_03"
|
||||
}
|
||||
|
||||
def register_icons():
|
||||
global universal_icons
|
||||
global empty_icon_id
|
||||
global floor_icons_map, element_icons_map, groupext_icons_map
|
||||
|
||||
# create preview collection and get icon folder
|
||||
icon_path = os.path.join(os.path.dirname(__file__), "icons")
|
||||
universal_icons = bpy.utils.previews.new()
|
||||
|
||||
# load empty
|
||||
universal_icons.load("BlcBldPlg_EmptyIcon", os.path.join(icon_path, "Empty.png"), 'IMAGE')
|
||||
empty_icon_id = universal_icons["BlcBldPlg_EmptyIcon"].icon_id
|
||||
|
||||
# add floor icon
|
||||
for key, value in UTILS_constants.floor_blockDict.items():
|
||||
blockIconName = "BlcBldPlg_FloorIcon_" + key
|
||||
universal_icons.load(blockIconName, os.path.join(icon_path, "floor", value["BindingDisplayTexture"]), 'IMAGE')
|
||||
floor_icons_map[key] = universal_icons[blockIconName].icon_id
|
||||
|
||||
# add elements icon
|
||||
for elename in UTILS_constants.bmfile_componentList:
|
||||
blockIconName = "BlcBldPlg_ElementIcon_" + elename
|
||||
universal_icons.load(blockIconName, os.path.join(icon_path, "element", elename + '.png'), 'IMAGE')
|
||||
element_icons_map[elename] = universal_icons[blockIconName].icon_id
|
||||
|
||||
# add extra group icon
|
||||
for grp in ("SoundID_01", "SoundID_02", "SoundID_03"):
|
||||
blockIconName = "BlcBldPlg_GroupIcon_" + grp
|
||||
universal_icons.load(blockIconName, os.path.join(icon_path, "group", grp + '.png'), 'IMAGE')
|
||||
groupext_icons_map[grp] = universal_icons[blockIconName].icon_id
|
||||
|
||||
def unregister_icons():
|
||||
global universal_icons
|
||||
global floor_icons_map, element_icons_map, groupext_icons_map
|
||||
|
||||
bpy.utils.previews.remove(universal_icons)
|
||||
floor_icons_map.clear()
|
||||
element_icons_map.clear()
|
||||
groupext_icons_map.clear()
|
||||
|
||||
def get_floor_icon(floor_blk_name: str):
|
||||
# default return empty icon
|
||||
return floor_icons_map.get(floor_blk_name, empty_icon_id)
|
||||
|
||||
def get_element_icon(element_name: str):
|
||||
# default return empty icon
|
||||
return element_icons_map.get(element_name, empty_icon_id)
|
||||
|
||||
def get_group_icon(group_name: str):
|
||||
# try parse string
|
||||
# if not found, return self
|
||||
conv_name = group_name_conv_map.get(group_name, group_name)
|
||||
|
||||
# get from extra group icon first
|
||||
idx = groupext_icons_map.get(conv_name, empty_icon_id)
|
||||
if idx != empty_icon_id:
|
||||
return idx
|
||||
|
||||
# if failed, get from element. if still failed, return empty icon
|
||||
return get_element_icon(conv_name)
|
||||
|
||||
# no matter how, register icon always
|
||||
# and no unregister call
|
||||
register_icons()
|
@ -1,49 +0,0 @@
|
||||
import bpy
|
||||
import bpy.types
|
||||
|
||||
class MyPropertyGroup(bpy.types.PropertyGroup):
|
||||
material_picker : bpy.props.PointerProperty(
|
||||
type=bpy.types.Material,
|
||||
name="Material",
|
||||
description="The material used for rail"
|
||||
)
|
||||
|
||||
collection_picker : bpy.props.PointerProperty(
|
||||
type=bpy.types.Collection,
|
||||
name="Collection",
|
||||
description="The collection which will be exported"
|
||||
)
|
||||
|
||||
object_picker : bpy.props.PointerProperty(
|
||||
type=bpy.types.Object,
|
||||
name="Object",
|
||||
description="The object which will be exported"
|
||||
)
|
||||
|
||||
class BallanceBlenderPluginPreferences(bpy.types.AddonPreferences):
|
||||
bl_idname = __package__
|
||||
|
||||
external_folder: bpy.props.StringProperty(
|
||||
name="External texture folder",
|
||||
description="The Ballance texture folder which will be used by this plugin to get external texture.",
|
||||
)
|
||||
|
||||
no_component_collection: bpy.props.StringProperty(
|
||||
name="No component collection",
|
||||
description="(Import) The object which stored in this collectiion will not be saved as component. (Export) All forced no component objects will be stored in this collection",
|
||||
)
|
||||
|
||||
temp_texture_folder: bpy.props.StringProperty(
|
||||
name="Temp texture folder",
|
||||
description="The folder which will temporarily store the textures which are extracted from bm. Due to system temp folder will be deleted after decoding of bm, so this path should not be blank.",
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
|
||||
col.prop(self, "external_folder")
|
||||
col.prop(self, "no_component_collection")
|
||||
col.prop(self, "temp_texture_folder")
|
@ -1,68 +0,0 @@
|
||||
import ast
|
||||
|
||||
class SimpleCalcEnsurance(ast.NodeVisitor):
|
||||
def __init__(self):
|
||||
self.is_illegal_syntax: bool = False
|
||||
self.allow_float: bool = True
|
||||
self.param_name: tuple = tuple()
|
||||
|
||||
def wrapper_visit(self, node: ast.AST, allow_float: bool, param_name: tuple) -> bool:
|
||||
self.is_illegal_syntax = False
|
||||
self.allow_float = allow_float
|
||||
self.param_name = param_name
|
||||
|
||||
self.visit(node)
|
||||
return self.is_illegal_syntax
|
||||
|
||||
def generic_visit(node):
|
||||
self.is_illegal_syntax = True
|
||||
|
||||
def visit_Expression(self, node: ast.Expression):
|
||||
self.visit(node.body)
|
||||
|
||||
def visit_BinOp(self, node: ast.BinOp):
|
||||
if isinstance(node.op, ast.Add) or isinstance(node.op, ast.Sub) or isinstance(node.op, ast.Mult) or isinstance(node.op, ast.Div):
|
||||
self.visit(node.left)
|
||||
self.visit(node.right)
|
||||
else:
|
||||
self.is_illegal_syntax = True
|
||||
|
||||
def visit_UnaryOp(self, node: ast.UnaryOp):
|
||||
if isinstance(node.op, ast.USub):
|
||||
self.visit(node.operand)
|
||||
else:
|
||||
self.is_illegal_syntax = True
|
||||
|
||||
def visit_Constant(self, node: ast.Constant):
|
||||
if (self.allow_float and isinstance(node.value, float)) or isinstance(node.value, int):
|
||||
pass
|
||||
else:
|
||||
self.is_illegal_syntax = True
|
||||
|
||||
|
||||
def visit_Name(self, node: ast.Name):
|
||||
if node.id in self.param_name and isinstance(node.ctx, ast.Load):
|
||||
pass
|
||||
else:
|
||||
self.is_illegal_syntax = True
|
||||
|
||||
def _do_calc(szEval: str, allow_float: bool, d: dict):
|
||||
ast_tree = ast.parse(szEval, mode='eval')
|
||||
walker = SimpleCalcEnsurance()
|
||||
if walker.wrapper_visit(ast_tree, allow_float, d.keys()):
|
||||
raise Exception("Illegal AST Tree. Tree contain illegal syntax. Please check BMERevenge.")
|
||||
|
||||
return eval(compile(ast_tree, '', mode='eval'), {}, d)
|
||||
|
||||
def do_vec_calc(szEval: str, raw_d1: float, raw_d2: float, raw_d3: float) -> float:
|
||||
return float(_do_calc(szEval, True, {
|
||||
"d1": raw_d1,
|
||||
"d2": raw_d2,
|
||||
"d3": raw_d3
|
||||
}))
|
||||
|
||||
def do_expand_calc(szEval: str, d1: int, d2: int) -> int:
|
||||
return int(_do_calc(szEval, False, {
|
||||
"d1": d1,
|
||||
"d2": d2
|
||||
}))
|
@ -1,241 +0,0 @@
|
||||
import bpy
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_PG_virtools_material(bpy.types.PropertyGroup):
|
||||
enable_virtools_material: bpy.props.BoolProperty(
|
||||
name="Enable Virtools Material",
|
||||
default=False,
|
||||
)
|
||||
|
||||
ambient: bpy.props.FloatVectorProperty(
|
||||
name="Ambient",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[76 / 255, 76 / 255, 76 / 255]
|
||||
)
|
||||
|
||||
diffuse: bpy.props.FloatVectorProperty(
|
||||
name="Diffuse",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[178 / 255, 178 / 255, 178 / 255]
|
||||
)
|
||||
|
||||
specular: bpy.props.FloatVectorProperty(
|
||||
name="Specular",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[127 / 255, 127 / 255, 127 / 255]
|
||||
)
|
||||
|
||||
emissive: bpy.props.FloatVectorProperty(
|
||||
name="Emissive",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[0.0, 0.0, 0.0]
|
||||
)
|
||||
|
||||
specular_power: bpy.props.FloatProperty(
|
||||
name="Specular Power",
|
||||
min=0.0,
|
||||
max=100.0,
|
||||
default=0.0,
|
||||
)
|
||||
|
||||
alpha_test: bpy.props.BoolProperty(
|
||||
name="Alpha Test",
|
||||
description="Alpha Func: VXCMP_GREATER. Alpha Ref: 1.",
|
||||
default=False,
|
||||
)
|
||||
|
||||
alpha_blend: bpy.props.BoolProperty(
|
||||
name="Alpha Blend",
|
||||
description="Source Blend: VXBLEND_SRCALPHA. Dest Blend: VXBLEND_INVSRCALPHA.",
|
||||
default=False,
|
||||
)
|
||||
|
||||
z_buffer: bpy.props.BoolProperty(
|
||||
name="Z Buffer",
|
||||
description="ZFunc: VXCMP_LESSEQUAL.",
|
||||
default=True,
|
||||
)
|
||||
|
||||
two_sided: bpy.props.BoolProperty(
|
||||
name="Two Sided",
|
||||
default=False,
|
||||
)
|
||||
|
||||
texture: bpy.props.PointerProperty(
|
||||
type=bpy.types.Image,
|
||||
name="Texture",
|
||||
description="The texture used for Virtools material"
|
||||
)
|
||||
|
||||
class BALLANCE_PG_virtools_group(bpy.types.PropertyGroup):
|
||||
group_name: bpy.props.StringProperty(
|
||||
name="Group Name",
|
||||
default=""
|
||||
)
|
||||
|
||||
class common_group_name_props(bpy.types.Operator):
|
||||
group_name_source: bpy.props.EnumProperty(
|
||||
name="Group Name Source",
|
||||
items=(('DEFINED', "Predefined", "Pre-defined group name."),
|
||||
('CUSTOM', "Custom", "User specified group name."),
|
||||
),
|
||||
)
|
||||
|
||||
group_name: bpy.props.EnumProperty(
|
||||
name="Group Name",
|
||||
description="Pick vanilla Ballance group name.",
|
||||
#items=tuple((x, x, "") for x in UTILS_constants.propsVtGroups_availableGroups),
|
||||
items=tuple(
|
||||
# token, display name, descriptions, icon, index
|
||||
(grp, grp, "", UTILS_icons_manager.get_group_icon(grp), idx)
|
||||
for idx, grp in enumerate(UTILS_constants.propsVtGroups_availableGroups)
|
||||
),
|
||||
)
|
||||
|
||||
custom_group_name: bpy.props.StringProperty(
|
||||
name="Custom Group Name",
|
||||
description="Input your custom group name.",
|
||||
default="",
|
||||
)
|
||||
|
||||
def parent_draw(self, parent_layout):
|
||||
parent_layout.prop(self, 'group_name_source', expand=True)
|
||||
if (self.group_name_source == 'CUSTOM'):
|
||||
parent_layout.prop(self, 'custom_group_name')
|
||||
else:
|
||||
parent_layout.prop(self, 'group_name') # do not translate group name. it's weird
|
||||
|
||||
def get_group_name_string(self):
|
||||
return str(self.custom_group_name if self.group_name_source == 'CUSTOM' else self.group_name)
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def get_virtools_material(mtl):
|
||||
return mtl.virtools_material
|
||||
|
||||
def get_virtools_material_data(mtl):
|
||||
data = get_virtools_material(mtl)
|
||||
return (
|
||||
data.enable_virtools_material,
|
||||
data.ambient,
|
||||
data.diffuse,
|
||||
data.specular,
|
||||
data.emissive,
|
||||
data.specular_power,
|
||||
data.alpha_test,
|
||||
data.alpha_blend,
|
||||
data.z_buffer,
|
||||
data.two_sided,
|
||||
data.texture
|
||||
)
|
||||
|
||||
def set_virtools_material_data(mtl, packed_data):
|
||||
data = get_virtools_material(mtl)
|
||||
# packed_data have the same order with the return value of `get_virtools_material_data`
|
||||
(data.enable_virtools_material,
|
||||
data.ambient, data.diffuse, data.specular, data.emissive, data.specular_power,
|
||||
data.alpha_test, data.alpha_blend, data.z_buffer, data.two_sided,
|
||||
data.texture) = packed_data
|
||||
|
||||
def get_active_virtools_group(obj):
|
||||
return obj.active_virtools_group
|
||||
def get_virtools_group(obj):
|
||||
return obj.virtools_group
|
||||
|
||||
def check_virtools_group_data(obj, probe):
|
||||
for item in get_virtools_group(obj):
|
||||
if probe == str(item.group_name):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def add_virtools_group_data(obj, new_data):
|
||||
# check exist
|
||||
if check_virtools_group_data(obj, new_data):
|
||||
# existed, give up
|
||||
return False
|
||||
|
||||
# "add" do not need operate active_virtools_group
|
||||
data = get_virtools_group(obj)
|
||||
it = data.add()
|
||||
it.name = ""
|
||||
it.group_name = new_data
|
||||
|
||||
return True
|
||||
|
||||
def remove_virtools_group_data(obj, rm_data):
|
||||
gp = get_virtools_group(obj)
|
||||
active_gp = get_active_virtools_group(obj)
|
||||
|
||||
for idx, item in enumerate(gp):
|
||||
if rm_data == str(item.group_name):
|
||||
# decrease active group if removed item is ahead of active group
|
||||
if idx <= active_gp:
|
||||
active_gp -= 1
|
||||
# remove
|
||||
gp.remove(idx)
|
||||
# indicate success
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def remove_virtools_group_data_by_index(obj, rm_idx):
|
||||
gp = get_virtools_group(obj)
|
||||
active_gp = get_active_virtools_group(obj)
|
||||
|
||||
# report error
|
||||
if rm_idx >= len(gp):
|
||||
return False
|
||||
|
||||
# remove
|
||||
if rm_idx <= active_gp:
|
||||
active_gp -= 1
|
||||
gp.remove(rm_idx)
|
||||
return True
|
||||
|
||||
def clear_virtools_group_data(obj):
|
||||
gp = get_virtools_group(obj)
|
||||
active_gp = get_active_virtools_group(obj)
|
||||
|
||||
gp.clear()
|
||||
active_gp = 0
|
||||
|
||||
def fill_virtools_group_data(obj, data_list):
|
||||
# clear first
|
||||
clear_virtools_group_data(obj)
|
||||
|
||||
# if no data to add, return
|
||||
if data_list is None:
|
||||
return
|
||||
|
||||
# add one by one after check duplication
|
||||
data = get_virtools_group(obj)
|
||||
for item in set(data_list):
|
||||
it = data.add()
|
||||
it.name = ""
|
||||
it.group_name = item
|
||||
|
||||
def get_virtools_group_data(obj):
|
||||
return tuple(str(item.group_name) for item in get_virtools_group(obj))
|
||||
|
||||
def register_props():
|
||||
bpy.types.Object.virtools_group = bpy.props.CollectionProperty(type=BALLANCE_PG_virtools_group)
|
||||
bpy.types.Object.active_virtools_group = bpy.props.IntProperty()
|
||||
bpy.types.Material.virtools_material = bpy.props.PointerProperty(type=BALLANCE_PG_virtools_material)
|
||||
|
||||
def unregister_props():
|
||||
del bpy.types.Material.virtools_material
|
||||
del bpy.types.Object.virtools_group
|
||||
del bpy.types.Object.active_virtools_group
|
||||
|
||||
|
@ -1,48 +0,0 @@
|
||||
import pathlib, zipfile, os, shutil
|
||||
from . import UTILS_constants
|
||||
|
||||
def compress(folder, zip_file):
|
||||
# remove target file first
|
||||
if os.path.isfile(zip_file):
|
||||
os.remove(zip_file)
|
||||
|
||||
# compress data
|
||||
with zipfile.ZipFile(zip_file, mode= 'w', compression= zipfile.ZIP_DEFLATED, compresslevel= 9, allowZip64= False) as zip_obj:
|
||||
# set global comment
|
||||
zip_obj.comment = UTILS_constants.bmfile_globalComment
|
||||
|
||||
# iterate folder and add files
|
||||
for folder_name, subfolders, filenames in os.walk(folder):
|
||||
for filename in filenames:
|
||||
# construct zip_entry
|
||||
abstract_filepath = os.path.join(folder_name, filename)
|
||||
relative_filepath = os.path.relpath(abstract_filepath, folder)
|
||||
zip_entry = zipfile.ZipInfo.from_file(abstract_filepath, arcname= relative_filepath)
|
||||
zip_entry.compress_type = zipfile.ZIP_DEFLATED
|
||||
|
||||
# compress file
|
||||
with open(abstract_filepath, 'rb') as fs_in:
|
||||
with zip_obj.open(zip_entry, mode= 'w') as zip_in:
|
||||
# References
|
||||
# https://stackoverflow.com/questions/53254622/zipfile-header-language-encoding-bit-set-differently-between-python2-and-python3
|
||||
# set unicode flag after opening internal file.
|
||||
# for the shit implement of python module zipfile, we need set Deflated:Maximum manually
|
||||
zip_entry.flag_bits |= UTILS_constants.bmfile_flagUnicode
|
||||
zip_entry.flag_bits |= UTILS_constants.bmfile_flagDeflatedMaximum
|
||||
# copy file
|
||||
shutil.copyfileobj(fs_in, zip_in)
|
||||
|
||||
|
||||
def decompress(folder, zip_file):
|
||||
with zipfile.ZipFile(zip_file, mode= 'r', compression= zipfile.ZIP_DEFLATED, compresslevel= 9, allowZip64= False) as zip_obj:
|
||||
for zip_entry in zip_obj.infolist():
|
||||
if (zip_entry.flag_bits & UTILS_constants.bmfile_flagUnicode) == 0:
|
||||
# lost unicode flag, throw error
|
||||
raise Exception("Zip Entry lost UNICODE flag.")
|
||||
|
||||
# decompress file
|
||||
zip_obj.extract(zip_entry, path= folder)
|
||||
|
||||
|
||||
|
||||
|
@ -1,290 +0,0 @@
|
||||
bl_info={
|
||||
"name":"Ballance Blender Plugin",
|
||||
"description":"Ballance mapping tools for Blender",
|
||||
"author":"yyc12345",
|
||||
"version":(3,3),
|
||||
"blender":(3,6,0),
|
||||
"category":"Object",
|
||||
"support":"COMMUNITY",
|
||||
"warning": "Please read document before using this plugin.",
|
||||
"wiki_url": "https://github.com/yyc12345/BallanceBlenderHelper",
|
||||
"tracker_url": "https://github.com/yyc12345/BallanceBlenderHelper/issues"
|
||||
}
|
||||
|
||||
# =============================================
|
||||
# import system
|
||||
import bpy
|
||||
|
||||
# import my code (with reload)
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
if "UTILS_constants" in locals():
|
||||
importlib.reload(UTILS_constants)
|
||||
if "UTILS_functions" in locals():
|
||||
importlib.reload(UTILS_functions)
|
||||
if "UTILS_preferences" in locals():
|
||||
importlib.reload(UTILS_preferences)
|
||||
if "UTILS_file_io" in locals():
|
||||
importlib.reload(UTILS_file_io)
|
||||
if "UTILS_zip_helper" in locals():
|
||||
importlib.reload(UTILS_zip_helper)
|
||||
if "UTILS_virtools_prop" in locals():
|
||||
importlib.reload(UTILS_virtools_prop)
|
||||
if "UTILS_safe_eval" in locals():
|
||||
importlib.reload(UTILS_safe_eval)
|
||||
if "UTILS_icons_manager" in locals():
|
||||
importlib.reload(UTILS_icons_manager)
|
||||
|
||||
if "BMFILE_export" in locals():
|
||||
importlib.reload(BMFILE_export)
|
||||
if "BMFILE_import" in locals():
|
||||
importlib.reload(BMFILE_import)
|
||||
|
||||
if "MODS_rail_uv" in locals():
|
||||
importlib.reload(MODS_rail_uv)
|
||||
if "MODS_3dsmax_align" in locals():
|
||||
importlib.reload(MODS_3dsmax_align)
|
||||
if "MODS_flatten_uv" in locals():
|
||||
importlib.reload(MODS_flatten_uv)
|
||||
|
||||
if "OBJS_add_components" in locals():
|
||||
importlib.reload(OBJS_add_components)
|
||||
if "OBJS_add_floors" in locals():
|
||||
importlib.reload(OBJS_add_floors)
|
||||
if "OBJS_add_rails" in locals():
|
||||
importlib.reload(OBJS_add_rails)
|
||||
if "OBJS_group_opers" in locals():
|
||||
importlib.reload(OBJS_group_opers)
|
||||
|
||||
if "NAMES_rename_system" in locals():
|
||||
importlib.reload(NAMES_rename_system)
|
||||
|
||||
if "PROPS_virtools_group" in locals():
|
||||
importlib.reload(PROPS_virtools_group)
|
||||
if "PROPS_virtools_material" in locals():
|
||||
importlib.reload(PROPS_virtools_material)
|
||||
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_preferences, UTILS_virtools_prop, UTILS_safe_eval, UTILS_icons_manager
|
||||
from . import BMFILE_export, BMFILE_import
|
||||
from . import MODS_3dsmax_align, MODS_flatten_uv, MODS_rail_uv
|
||||
from . import OBJS_add_components, OBJS_add_floors, OBJS_add_rails, OBJS_group_opers
|
||||
from . import NAMES_rename_system
|
||||
from . import PROPS_virtools_group, PROPS_virtools_material
|
||||
|
||||
# =============================================
|
||||
# menu system
|
||||
|
||||
class BALLANCE_MT_ThreeDViewerMenu(bpy.types.Menu):
|
||||
"""Ballance 3D operators"""
|
||||
bl_idname = "BALLANCE_MT_ThreeDViewerMenu"
|
||||
bl_label = "Ballance"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator(MODS_3dsmax_align.BALLANCE_OT_super_align.bl_idname)
|
||||
layout.operator(MODS_rail_uv.BALLANCE_OT_rail_uv.bl_idname)
|
||||
layout.operator(MODS_flatten_uv.BALLANCE_OT_flatten_uv.bl_idname)
|
||||
|
||||
class BALLANCE_MT_AddFloorMenu(bpy.types.Menu):
|
||||
"""Add Ballance Floor"""
|
||||
bl_idname = "BALLANCE_MT_AddFloorMenu"
|
||||
bl_label = "Floors"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.label(text="Basic floor")
|
||||
for item in UTILS_constants.floor_basicBlockList:
|
||||
cop = layout.operator(
|
||||
OBJS_add_floors.BALLANCE_OT_add_floors.bl_idname,
|
||||
text=item, icon_value = UTILS_icons_manager.get_floor_icon(item))
|
||||
cop.floor_type = item
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="Derived floor")
|
||||
for item in UTILS_constants.floor_derivedBlockList:
|
||||
cop = layout.operator(
|
||||
OBJS_add_floors.BALLANCE_OT_add_floors.bl_idname,
|
||||
text=item, icon_value = UTILS_icons_manager.get_floor_icon(item))
|
||||
cop.floor_type = item
|
||||
|
||||
class BALLANCE_MT_AddRailMenu(bpy.types.Menu):
|
||||
"""Add Ballance Rail"""
|
||||
bl_idname = "BALLANCE_MT_AddRailMenu"
|
||||
bl_label = "Rails"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator(OBJS_add_rails.BALLANCE_OT_add_rails.bl_idname, text="Rail Section")
|
||||
layout.operator(OBJS_add_rails.BALLANCE_OT_add_tunnels.bl_idname, text="Tunnel Section")
|
||||
|
||||
class BALLANCE_MT_AddNormalElementsMenu(bpy.types.Menu):
|
||||
"""Add Ballance Elements"""
|
||||
bl_idname = "BALLANCE_MT_AddNormalElementsMenu"
|
||||
bl_label = "Elements"
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
OBJS_add_components.BALLANCE_OT_add_components.draw_blc_menu(layout)
|
||||
class BALLANCE_MT_AddDupElementsMenu(bpy.types.Menu):
|
||||
"""Add Ballance Elements"""
|
||||
bl_idname = "BALLANCE_MT_AddDupElementsMenu"
|
||||
bl_label = "Elements"
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
OBJS_add_components.BALLANCE_OT_add_components_dup.draw_blc_menu(layout)
|
||||
class BALLANCE_MT_AddElementsMenu(bpy.types.Menu):
|
||||
"""Add Ballance Elements"""
|
||||
bl_idname = "BALLANCE_MT_AddElementsMenu"
|
||||
bl_label = "Elements"
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.label(text="Basic Elements")
|
||||
OBJS_add_components.BALLANCE_OT_add_components.draw_blc_menu(layout)
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="Duplicated Elements")
|
||||
OBJS_add_components.BALLANCE_OT_add_components_dup.draw_blc_menu(layout)
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="Elements Series")
|
||||
OBJS_add_components.BALLANCE_OT_add_components_series.draw_blc_menu(layout)
|
||||
|
||||
# =============================================
|
||||
# blender call system
|
||||
|
||||
classes = (
|
||||
UTILS_preferences.BallanceBlenderPluginPreferences,
|
||||
UTILS_preferences.MyPropertyGroup,
|
||||
|
||||
BMFILE_import.BALLANCE_OT_import_bm,
|
||||
BMFILE_export.BALLANCE_OT_export_bm,
|
||||
|
||||
MODS_rail_uv.BALLANCE_OT_rail_uv,
|
||||
MODS_3dsmax_align.BALLANCE_OT_super_align,
|
||||
MODS_flatten_uv.BALLANCE_OT_flatten_uv,
|
||||
BALLANCE_MT_ThreeDViewerMenu,
|
||||
|
||||
OBJS_add_components.BALLANCE_OT_add_components,
|
||||
OBJS_add_components.BALLANCE_OT_add_components_dup,
|
||||
OBJS_add_components.BALLANCE_OT_add_components_series,
|
||||
OBJS_add_rails.BALLANCE_OT_add_rails,
|
||||
OBJS_add_rails.BALLANCE_OT_add_tunnels,
|
||||
OBJS_add_floors.BALLANCE_OT_add_floors,
|
||||
BALLANCE_MT_AddFloorMenu,
|
||||
BALLANCE_MT_AddRailMenu,
|
||||
BALLANCE_MT_AddElementsMenu,
|
||||
|
||||
NAMES_rename_system.BALLANCE_OT_rename_by_group,
|
||||
NAMES_rename_system.BALLANCE_OT_convert_name,
|
||||
NAMES_rename_system.BALLANCE_OT_auto_grouping,
|
||||
|
||||
UTILS_virtools_prop.BALLANCE_PG_virtools_material,
|
||||
UTILS_virtools_prop.BALLANCE_PG_virtools_group,
|
||||
PROPS_virtools_group.BALLANCE_OT_add_virtools_group,
|
||||
PROPS_virtools_group.BALLANCE_OT_rm_virtools_group,
|
||||
PROPS_virtools_group.BALLANCE_OT_clear_virtools_group,
|
||||
PROPS_virtools_group.BALLANCE_UL_virtools_group,
|
||||
PROPS_virtools_group.BALLANCE_PT_virtools_group,
|
||||
PROPS_virtools_material.BALLANCE_OT_apply_virtools_material,
|
||||
PROPS_virtools_material.BALLANCE_OT_parse_virtools_material,
|
||||
PROPS_virtools_material.BALLANCE_OT_preset_virtools_material,
|
||||
PROPS_virtools_material.BALLANCE_PT_virtools_material,
|
||||
|
||||
OBJS_group_opers.BALLANCE_OT_select_virtools_group,
|
||||
OBJS_group_opers.BALLANCE_OT_ctx_set_group,
|
||||
OBJS_group_opers.BALLANCE_OT_ctx_unset_group,
|
||||
OBJS_group_opers.BALLANCE_OT_ctx_clear_group,
|
||||
|
||||
)
|
||||
|
||||
def menu_func_bm_import(self, context):
|
||||
self.layout.operator(BMFILE_import.BALLANCE_OT_import_bm.bl_idname, text="Ballance Map (.bmx)")
|
||||
def menu_func_bm_export(self, context):
|
||||
self.layout.operator(BMFILE_export.BALLANCE_OT_export_bm.bl_idname, text="Ballance Map (.bmx)")
|
||||
def menu_func_ballance_3d(self, context):
|
||||
layout = self.layout
|
||||
layout.menu(BALLANCE_MT_ThreeDViewerMenu.bl_idname)
|
||||
def menu_func_ballance_add(self, context):
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
layout.label(text="Ballance")
|
||||
layout.menu(BALLANCE_MT_AddFloorMenu.bl_idname, icon='MESH_CUBE')
|
||||
layout.menu(BALLANCE_MT_AddRailMenu.bl_idname, icon='MESH_CIRCLE')
|
||||
layout.menu(BALLANCE_MT_AddElementsMenu.bl_idname, icon='MESH_ICOSPHERE')
|
||||
#layout.operator_menu_enum(
|
||||
# OBJS_add_components.BALLANCE_OT_add_components.bl_idname,
|
||||
# "elements_type", icon='MESH_ICOSPHERE', text="Elements")
|
||||
def menu_func_ballance_rename(self, context):
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
col = layout.column()
|
||||
col.operator_context = 'INVOKE_DEFAULT'
|
||||
col.label(text="Ballance")
|
||||
col.operator(NAMES_rename_system.BALLANCE_OT_rename_by_group.bl_idname, icon='GREASEPENCIL')
|
||||
col.operator(NAMES_rename_system.BALLANCE_OT_convert_name.bl_idname, icon='ARROW_LEFTRIGHT')
|
||||
col.operator(NAMES_rename_system.BALLANCE_OT_auto_grouping.bl_idname, icon='GROUP')
|
||||
def menu_func_ballance_select(self, context):
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
layout.label(text="Ballance")
|
||||
layout.operator(OBJS_group_opers.BALLANCE_OT_select_virtools_group.bl_idname, icon='RESTRICT_SELECT_OFF')
|
||||
def menu_func_ballance_grouping(self, context):
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
col = layout.column()
|
||||
col.operator_context = 'INVOKE_DEFAULT'
|
||||
col.label(text="Ballance")
|
||||
col.operator(OBJS_group_opers.BALLANCE_OT_ctx_set_group.bl_idname, icon='ADD', text="Group into...")
|
||||
col.operator(OBJS_group_opers.BALLANCE_OT_ctx_unset_group.bl_idname, icon='REMOVE', text="Ungroup from...")
|
||||
col.operator(OBJS_group_opers.BALLANCE_OT_ctx_clear_group.bl_idname, icon='TRASH', text="Clear Grouping")
|
||||
|
||||
|
||||
def register():
|
||||
# we need init all icon first
|
||||
#UTILS_icons_manager.register_icons()
|
||||
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
bpy.types.Scene.BallanceBlenderPluginProperty = bpy.props.PointerProperty(type=UTILS_preferences.MyPropertyGroup)
|
||||
UTILS_virtools_prop.register_props()
|
||||
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func_bm_import)
|
||||
bpy.types.TOPBAR_MT_file_export.append(menu_func_bm_export)
|
||||
|
||||
bpy.types.VIEW3D_MT_editor_menus.prepend(menu_func_ballance_3d)
|
||||
bpy.types.VIEW3D_MT_add.append(menu_func_ballance_add)
|
||||
bpy.types.OUTLINER_MT_collection.append(menu_func_ballance_rename)
|
||||
|
||||
bpy.types.VIEW3D_MT_select_object.append(menu_func_ballance_select)
|
||||
|
||||
bpy.types.VIEW3D_MT_object_context_menu.append(menu_func_ballance_grouping)
|
||||
bpy.types.OUTLINER_MT_object.append(menu_func_ballance_grouping) # share the same menu
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_bm_import)
|
||||
bpy.types.TOPBAR_MT_file_export.remove(menu_func_bm_export)
|
||||
|
||||
bpy.types.VIEW3D_MT_editor_menus.remove(menu_func_ballance_3d)
|
||||
bpy.types.VIEW3D_MT_add.remove(menu_func_ballance_add)
|
||||
bpy.types.OUTLINER_MT_collection.remove(menu_func_ballance_rename)
|
||||
|
||||
bpy.types.VIEW3D_MT_select_object.remove(menu_func_ballance_select)
|
||||
|
||||
bpy.types.VIEW3D_MT_object_context_menu.remove(menu_func_ballance_grouping)
|
||||
bpy.types.OUTLINER_MT_object.append(menu_func_ballance_grouping)
|
||||
|
||||
UTILS_virtools_prop.unregister_props()
|
||||
del bpy.types.Scene.BallanceBlenderPluginProperty
|
||||
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
# we need uninstall all icon after all classes unregister
|
||||
#UTILS_icons_manager.unregister_icons()
|
||||
|
||||
if __name__=="__main__":
|
||||
register()
|
Before Width: | Height: | Size: 785 B |
Before Width: | Height: | Size: 663 B |
Before Width: | Height: | Size: 745 B |
Before Width: | Height: | Size: 945 B |
Before Width: | Height: | Size: 818 B |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 984 B |
Before Width: | Height: | Size: 611 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 471 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 494 B |
Before Width: | Height: | Size: 360 B |
Before Width: | Height: | Size: 992 B |
Before Width: | Height: | Size: 444 B |
Before Width: | Height: | Size: 691 B |
Before Width: | Height: | Size: 775 B |
Before Width: | Height: | Size: 807 B |
Before Width: | Height: | Size: 652 B |
Before Width: | Height: | Size: 695 B |
Before Width: | Height: | Size: 550 B |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 251 B |
@ -1,483 +0,0 @@
|
||||
[
|
||||
{
|
||||
"Type": "Flat",
|
||||
"BindingDisplayTexture": "Flat.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Freedom",
|
||||
"InitColumnDirection": "PositiveY",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": false,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"0, 0, 0",
|
||||
"2.5+d2, 0, 0",
|
||||
"2.5+d2, 2.5+d1, 0",
|
||||
"0, 2.5+d1, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0, -d2",
|
||||
"0.5+d1, -d2",
|
||||
"0.5+d1, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"2.5+d2, 0, -5-d3",
|
||||
"2.5+d2, 2.5+d1, -5-d3",
|
||||
"0, 2.5+d1, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0, -d2",
|
||||
"0.5+d1, -d2",
|
||||
"0.5+d1, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 0, 0",
|
||||
"0, 2.5+d1, 0",
|
||||
"0, 2.5+d1, -5-d3",
|
||||
"0, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"0, 0.5+d1",
|
||||
"1+d3, 0.5+d1",
|
||||
"1+d3, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"2.5+d2, 2.5+d1, 0",
|
||||
"2.5+d2, 2.5+d1, -5-d3",
|
||||
"0, 2.5+d1, -5-d3",
|
||||
"0, 2.5+d1, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d2",
|
||||
"1+d3, -d2",
|
||||
"1+d3, 0.5",
|
||||
"0, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"2.5+d2, 2.5+d1, 0",
|
||||
"2.5+d2, 0, 0",
|
||||
"2.5+d2, 0, -5-d3",
|
||||
"2.5+d2, 2.5+d1, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5+d1",
|
||||
"0, 0",
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5+d1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"0, 0, 0",
|
||||
"0, 0, -5-d3",
|
||||
"2.5+d2, 0, -5-d3",
|
||||
"2.5+d2, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"1+d3, 0.5",
|
||||
"1+d3, -d2",
|
||||
"0, -d2"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": null,
|
||||
"TwoDRightSideExpand": null,
|
||||
"TwoDBottomSideExpand": null,
|
||||
"TwoDLeftSideExpand": null
|
||||
},
|
||||
{
|
||||
"Type": "NormalSinkTransition",
|
||||
"BindingDisplayTexture": "NormalSinkTransition.png",
|
||||
"UnitSize": "Large",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"0, 0, 0",
|
||||
"5, 0, 0",
|
||||
"0, 2.5, -0.7",
|
||||
"5, 5, 0",
|
||||
"0, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopProfilFlat",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"UVs": [
|
||||
"0, 1",
|
||||
"0, 0",
|
||||
"0.5, 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopProfilFlat",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1
|
||||
],
|
||||
"UVs": [
|
||||
"1, 0",
|
||||
"0.5, 1",
|
||||
"0, 0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopProfilFlat",
|
||||
"Indices": [
|
||||
2,
|
||||
3,
|
||||
4
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 1",
|
||||
"1, 0",
|
||||
"1, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"5, 0, -5-d3",
|
||||
"5, 5, -5-d3",
|
||||
"0, 5, -5-d3",
|
||||
"0, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 1",
|
||||
"1, 1",
|
||||
"1, 0",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0",
|
||||
"0, 2.5, -0.7",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 5, -5-d3",
|
||||
"0, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"0, 1",
|
||||
"0.5, 0.86",
|
||||
"0.5, -d3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2
|
||||
],
|
||||
"UVs": [
|
||||
"1, 1",
|
||||
"1, -d3",
|
||||
"0.5, -d3",
|
||||
"0.5, 0.86"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"5, 5, 0",
|
||||
"5, 5, -5-d3",
|
||||
"0, 5, -5-d3",
|
||||
"0, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"5, 5, 0",
|
||||
"5, 0, 0",
|
||||
"5, 0, -5-d3",
|
||||
"5, 5, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 1",
|
||||
"0, 0",
|
||||
"1+d3, 0",
|
||||
"1+d3, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"5, 0, 0",
|
||||
"5, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 1",
|
||||
"1+d3, 1",
|
||||
"1+d3, 0",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": null,
|
||||
"TwoDRightSideExpand": {
|
||||
"Vertices": [
|
||||
"0, 5, 0",
|
||||
"5, 5, 0",
|
||||
"5, 5, -2.5",
|
||||
"0, 5, -2.5",
|
||||
"0, 5, -5-d3",
|
||||
"5, 5, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorder_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 1",
|
||||
"0, 0",
|
||||
"0.5, 0",
|
||||
"0.5, 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2
|
||||
],
|
||||
"UVs": [
|
||||
"0.5+d3, 0",
|
||||
"0.5+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSideExpand": null,
|
||||
"TwoDLeftSideExpand": {
|
||||
"Vertices": [
|
||||
"0, 0, 0",
|
||||
"5, 0, 0",
|
||||
"5, 0, -2.5",
|
||||
"0, 0, -2.5",
|
||||
"0, 0, -5-d3",
|
||||
"5, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorder_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 1",
|
||||
"0.5, 0",
|
||||
"0, 0",
|
||||
"0, 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"0, 1",
|
||||
"0.5+d3, 1",
|
||||
"0.5+d3, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
@ -1,680 +0,0 @@
|
||||
[
|
||||
{
|
||||
"Type": "NormalBorder",
|
||||
"BindingDisplayTexture": "NormalBorder.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Column",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"0, 0, 0",
|
||||
"2.5+d1, 0, 0",
|
||||
"2.5+d1, 2.5, 0",
|
||||
"0, 2.5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopFlat",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0, -d1",
|
||||
"0.5, -d1",
|
||||
"0.5, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, -5-d3",
|
||||
"2.5+d1, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0.5, 0.5",
|
||||
"0.5, -d1",
|
||||
"0, -d1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 2.5, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0, 0",
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 2.5, 0",
|
||||
"2.5+d1, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 2.5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d1",
|
||||
"1+d3, -d1",
|
||||
"1+d3, 0.5",
|
||||
"0, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, -5-d3",
|
||||
"2.5+d1, 2.5, -5-d3",
|
||||
"2.5+d1, 2.5, 0",
|
||||
"2.5+d1, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0.5",
|
||||
"1+d3, 0",
|
||||
"0, 0",
|
||||
"0, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, 0",
|
||||
"2.5+d1, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"1+d3, 0.5",
|
||||
"1+d3, -d1",
|
||||
"0, -d1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": null,
|
||||
"TwoDRightSideExpand": null,
|
||||
"TwoDBottomSideExpand": null,
|
||||
"TwoDLeftSideExpand": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, -2.5",
|
||||
"2.5+d1, 0, -2.5",
|
||||
"2.5+d1, 0, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorder_ForSide",
|
||||
"Indices": [
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 0.5",
|
||||
"0.5, -d1",
|
||||
"0, -d1",
|
||||
"0, 0.5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d1",
|
||||
"0, 0.5",
|
||||
"0.5+d3, 0.5",
|
||||
"0.5+d3, -d1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": "NormalOutterCorner",
|
||||
"BindingDisplayTexture": "NormalOutterCorner.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"0, 0, 0",
|
||||
"2.5, 0, 0",
|
||||
"2.5, 2.5, 0",
|
||||
"0, 2.5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopFlat",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0, 1",
|
||||
"0.5, 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopFlat",
|
||||
"Indices": [
|
||||
0,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1, 0.5",
|
||||
"0.5, 1",
|
||||
"1, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"2.5, 0, -5-d3",
|
||||
"2.5, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0.5, 0.5",
|
||||
"0.5, 0",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0",
|
||||
"0, 2.5, 0",
|
||||
"0, 2.5, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"0, 0",
|
||||
"0, 0.5",
|
||||
"1+d3, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"2.5, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 2.5, 0",
|
||||
"2.5, 2.5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5",
|
||||
"0, 0.5",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"2.5, 0, -5-d3",
|
||||
"2.5, 2.5, -5-d3",
|
||||
"2.5, 2.5, 0",
|
||||
"2.5, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5",
|
||||
"0, 0.5",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"2.5, 0, 0",
|
||||
"2.5, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"1+d3, 0.5",
|
||||
"1+d3, 0",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 2.5, -2.5",
|
||||
"0, 0, -2.5",
|
||||
"0, 0, 0",
|
||||
"0, 2.5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorder_ForSide",
|
||||
"Indices": [
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 0.5",
|
||||
"0.5, 0",
|
||||
"0, 0",
|
||||
"0, 0.5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"0, 0.5",
|
||||
"0.5+d3, 0.5",
|
||||
"0.5+d3, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSideExpand": null,
|
||||
"TwoDBottomSideExpand": null,
|
||||
"TwoDLeftSideExpand": {
|
||||
"Vertices": [
|
||||
"2.5, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, -2.5",
|
||||
"2.5, 0, -2.5",
|
||||
"2.5, 0, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorder_ForSide",
|
||||
"Indices": [
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 0.5",
|
||||
"0.5, 0",
|
||||
"0, 0",
|
||||
"0, 0.5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"0, 0.5",
|
||||
"0.5+d3, 0.5",
|
||||
"0.5+d3, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": "NormalInnerCorner",
|
||||
"BindingDisplayTexture": "NormalInnerCorner.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": false,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"2.5, 0, 0",
|
||||
"2.5, 2.5, 0",
|
||||
"0, 0, 0",
|
||||
"0, 2.5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopFlat",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 1",
|
||||
"0, 1",
|
||||
"0.5, 0.5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopFlat",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 1",
|
||||
"0.5, 0.5",
|
||||
"1, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"2.5, 0, -5-d3",
|
||||
"2.5, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0.5, 0.5",
|
||||
"0.5, 0",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 0, 0",
|
||||
"0, 2.5, 0",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"0, 0.5",
|
||||
"1+d3, 0.5",
|
||||
"1+d3, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"2.5, 2.5, 0",
|
||||
"2.5, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 2.5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5",
|
||||
"0, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"2.5, 2.5, 0",
|
||||
"2.5, 0, 0",
|
||||
"2.5, 0, -5-d3",
|
||||
"2.5, 2.5, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0, 0",
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"0, 0, 0",
|
||||
"0, 0, -5-d3",
|
||||
"2.5, 0, -5-d3",
|
||||
"2.5, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"1+d3, 0.5",
|
||||
"1+d3, 0",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": null,
|
||||
"TwoDRightSideExpand": null,
|
||||
"TwoDBottomSideExpand": null,
|
||||
"TwoDLeftSideExpand": null
|
||||
}
|
||||
]
|
@ -1,493 +0,0 @@
|
||||
[
|
||||
{
|
||||
"Type": "RibbonBorder",
|
||||
"BindingDisplayTexture": "RibbonBorder.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Column",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, 0",
|
||||
"2.5+d1, 2.5, -0.7",
|
||||
"0, 2.5, -0.7",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopFlat",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d1",
|
||||
"1, -d1",
|
||||
"1, 0.5",
|
||||
"0, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, -5-d3",
|
||||
"2.5+d1, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0.5, 0.5",
|
||||
"0.5, -d1",
|
||||
"0, -d1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0",
|
||||
"0, 2.5, -0.7",
|
||||
"0, 2.5, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"0, 0",
|
||||
"0.14, 0.5",
|
||||
"1+d3, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 2.5, -0.7",
|
||||
"2.5+d1, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 2.5, -0.7"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0.14, -d1",
|
||||
"1+d3, -d1",
|
||||
"1+d3, 0.5",
|
||||
"0.14, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, 0",
|
||||
"2.5+d1, 0, -5-d3",
|
||||
"2.5+d1, 2.5, -5-d3",
|
||||
"2.5+d1, 2.5, -0.7"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5",
|
||||
"0.14, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, 0",
|
||||
"2.5+d1, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"1+d3, 0.5",
|
||||
"1+d3, -d1",
|
||||
"0, -d1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": null,
|
||||
"TwoDRightSideExpand": null,
|
||||
"TwoDBottomSideExpand": null,
|
||||
"TwoDLeftSideExpand": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, -2.5",
|
||||
"2.5+d1, 0, -2.5",
|
||||
"2.5+d1, 0, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorder_ForSide",
|
||||
"Indices": [
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 0.5",
|
||||
"0.5, -d1",
|
||||
"0, -d1",
|
||||
"0, 0.5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d1",
|
||||
"0, 0.5",
|
||||
"0.5+d3, 0.5",
|
||||
"0.5+d3, -d1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": "RibbonOutterCorner",
|
||||
"BindingDisplayTexture": "RibbonOutterCorner.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"0, 0, 0",
|
||||
"2.5, 0, 0",
|
||||
"2.5, 2.5, -0.7",
|
||||
"0, 2.5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopFlat",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"0, 1",
|
||||
"1, 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopFlat",
|
||||
"Indices": [
|
||||
0,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1, 0",
|
||||
"0, 1",
|
||||
"1, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"2.5, 0, -5-d3",
|
||||
"2.5, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0.5, 0.5",
|
||||
"0.5, 0",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0",
|
||||
"0, 2.5, 0",
|
||||
"0, 2.5, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"0, 0",
|
||||
"0, 0.5",
|
||||
"1+d3, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"2.5, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 2.5, 0",
|
||||
"2.5, 2.5, -0.7"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5",
|
||||
"0, 0.5",
|
||||
"0.14, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"2.5, 0, -5-d3",
|
||||
"2.5, 2.5, -5-d3",
|
||||
"2.5, 2.5, -0.7",
|
||||
"2.5, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5",
|
||||
"0.14, 0.5",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"2.5, 0, 0",
|
||||
"2.5, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"1+d3, 0.5",
|
||||
"1+d3, 0",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 2.5, -2.5",
|
||||
"0, 0, -2.5",
|
||||
"0, 0, 0",
|
||||
"0, 2.5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorder_ForSide",
|
||||
"Indices": [
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 0.5",
|
||||
"0.5, 0",
|
||||
"0, 0",
|
||||
"0, 0.5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"0, 0.5",
|
||||
"0.5+d3, 0.5",
|
||||
"0.5+d3, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSideExpand": null,
|
||||
"TwoDBottomSideExpand": null,
|
||||
"TwoDLeftSideExpand": {
|
||||
"Vertices": [
|
||||
"2.5, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, -2.5",
|
||||
"2.5, 0, -2.5",
|
||||
"2.5, 0, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorder_ForSide",
|
||||
"Indices": [
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 0.5",
|
||||
"0.5, 0",
|
||||
"0, 0",
|
||||
"0, 0.5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"0, 0.5",
|
||||
"0.5+d3, 0.5",
|
||||
"0.5+d3, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
@ -1,680 +0,0 @@
|
||||
[
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"BindingDisplayTexture": "SinkBorder.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Column",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, 0",
|
||||
"2.5+d1, 2.5, -0.7",
|
||||
"0, 2.5, -0.7",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopProfil",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d1",
|
||||
"0.5, -d1",
|
||||
"0.5, 0.5",
|
||||
"0, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, -5-d3",
|
||||
"2.5+d1, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0.5, 0.5",
|
||||
"0.5, -d1",
|
||||
"0, -d1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0",
|
||||
"0, 2.5, -0.7",
|
||||
"0, 2.5, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"0, 0",
|
||||
"0.14, 0.5",
|
||||
"1+d3, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 2.5, -0.7",
|
||||
"2.5+d1, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 2.5, -0.7"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0.14, -d1",
|
||||
"1+d3, -d1",
|
||||
"1+d3, 0.5",
|
||||
"0.14, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, 0",
|
||||
"2.5+d1, 0, -5-d3",
|
||||
"2.5+d1, 2.5, -5-d3",
|
||||
"2.5+d1, 2.5, -0.7"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5",
|
||||
"0.14, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, 0",
|
||||
"2.5+d1, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"1+d3, 0.5",
|
||||
"1+d3, -d1",
|
||||
"0, -d1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": null,
|
||||
"TwoDRightSideExpand": null,
|
||||
"TwoDBottomSideExpand": null,
|
||||
"TwoDLeftSideExpand": {
|
||||
"Vertices": [
|
||||
"2.5+d1, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, -2.5",
|
||||
"2.5+d1, 0, -2.5",
|
||||
"2.5+d1, 0, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorder_ForSide",
|
||||
"Indices": [
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 0.5",
|
||||
"0.5, -d1",
|
||||
"0, -d1",
|
||||
"0, 0.5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d1",
|
||||
"0, 0.5",
|
||||
"0.5+d3, 0.5",
|
||||
"0.5+d3, -d1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"BindingDisplayTexture": "SinkOutterCorner.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"0, 0, 0",
|
||||
"2.5, 0, 0",
|
||||
"2.5, 2.5, -0.7",
|
||||
"0, 2.5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopProfil",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0, 1",
|
||||
"0.5, 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopProfil",
|
||||
"Indices": [
|
||||
0,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1, 0.5",
|
||||
"0.5, 1",
|
||||
"1, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"2.5, 0, -5-d3",
|
||||
"2.5, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0.5, 0.5",
|
||||
"0.5, 0",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0",
|
||||
"0, 2.5, 0",
|
||||
"0, 2.5, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"0, 0",
|
||||
"0, 0.5",
|
||||
"1+d3, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"2.5, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 2.5, 0",
|
||||
"2.5, 2.5, -0.7"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5",
|
||||
"0, 0.5",
|
||||
"0.14, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"2.5, 0, -5-d3",
|
||||
"2.5, 2.5, -5-d3",
|
||||
"2.5, 2.5, -0.7",
|
||||
"2.5, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5",
|
||||
"0.14, 0.5",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"2.5, 0, 0",
|
||||
"2.5, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"1+d3, 0.5",
|
||||
"1+d3, 0",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 2.5, -2.5",
|
||||
"0, 0, -2.5",
|
||||
"0, 0, 0",
|
||||
"0, 2.5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorder_ForSide",
|
||||
"Indices": [
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 0.5",
|
||||
"0.5, 0",
|
||||
"0, 0",
|
||||
"0, 0.5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"0, 0.5",
|
||||
"0.5+d3, 0.5",
|
||||
"0.5+d3, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSideExpand": null,
|
||||
"TwoDBottomSideExpand": null,
|
||||
"TwoDLeftSideExpand": {
|
||||
"Vertices": [
|
||||
"2.5, 0, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, -2.5",
|
||||
"2.5, 0, -2.5",
|
||||
"2.5, 0, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorder_ForSide",
|
||||
"Indices": [
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 0.5",
|
||||
"0.5, 0",
|
||||
"0, 0",
|
||||
"0, 0.5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"0, 0.5",
|
||||
"0.5+d3, 0.5",
|
||||
"0.5+d3, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"BindingDisplayTexture": "SinkInnerCorner.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": false,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"2.5, 0, -0.7",
|
||||
"2.5, 2.5, 0",
|
||||
"0, 0, -0.7",
|
||||
"0, 2.5, -0.7"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopProfil",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 1",
|
||||
"0, 1",
|
||||
"0.5, 0.5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "TRIANGLE",
|
||||
"Textures": "FloorTopProfil",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1
|
||||
],
|
||||
"UVs": [
|
||||
"0.5, 1",
|
||||
"0.5, 0.5",
|
||||
"1, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"2.5, 0, -5-d3",
|
||||
"2.5, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0.5, 0.5",
|
||||
"0.5, 0",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 0, -0.7",
|
||||
"0, 2.5, -0.7",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0.14, 0",
|
||||
"0.14, 0.5",
|
||||
"1+d3, 0.5",
|
||||
"1+d3, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"2.5, 2.5, 0",
|
||||
"2.5, 2.5, -5-d3",
|
||||
"0, 2.5, -5-d3",
|
||||
"0, 2.5, -0.7"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5",
|
||||
"0.14, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"2.5, 2.5, 0",
|
||||
"2.5, 0, -0.7",
|
||||
"2.5, 0, -5-d3",
|
||||
"2.5, 2.5, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0.5",
|
||||
"0.14, 0",
|
||||
"1+d3, 0",
|
||||
"1+d3, 0.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"0, 0, -0.7",
|
||||
"0, 0, -5-d3",
|
||||
"2.5, 0, -5-d3",
|
||||
"2.5, 0, -0.7"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "FloorTopBorderless_ForSide",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0.14, 0.5",
|
||||
"1+d3, 0.5",
|
||||
"1+d3, 0",
|
||||
"0.14, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": null,
|
||||
"TwoDRightSideExpand": null,
|
||||
"TwoDBottomSideExpand": null,
|
||||
"TwoDLeftSideExpand": null
|
||||
}
|
||||
]
|
@ -1,827 +0,0 @@
|
||||
[
|
||||
{
|
||||
"Type": "WoodTrafo",
|
||||
"BindingDisplayTexture": "WoodTrafo.png",
|
||||
"UnitSize": "Large",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": true,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": true
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"0, 5, 0",
|
||||
"0, 0, 0",
|
||||
"5, 0, 0",
|
||||
"5, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallWood",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"1, 0",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 5, -5-d3",
|
||||
"5, 5, -5-d3",
|
||||
"5, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallWood",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"1, 0",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 5, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0",
|
||||
"0, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallWood",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"1, -d3",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"5, 5, -5-d3",
|
||||
"0, 5, -5-d3",
|
||||
"0, 5, 0",
|
||||
"5, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallWood",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"1, -d3",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"5, 0, -5-d3",
|
||||
"5, 5, -5-d3",
|
||||
"5, 5, 0",
|
||||
"5, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallWood",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"1, -d3",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"5, 0, -5-d3",
|
||||
"5, 0, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallWood",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"1, -d3",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": {
|
||||
"Vertices": [
|
||||
"0, 5, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0",
|
||||
"0, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallWood",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSideExpand": {
|
||||
"Vertices": [
|
||||
"5, 5, -5-d3",
|
||||
"0, 5, -5-d3",
|
||||
"0, 5, 0",
|
||||
"5, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallWood",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSideExpand": {
|
||||
"Vertices": [
|
||||
"5, 0, -5-d3",
|
||||
"5, 5, -5-d3",
|
||||
"5, 5, 0",
|
||||
"5, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallWood",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSideExpand": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"5, 0, -5-d3",
|
||||
"5, 0, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallWood",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": "StoneTrafo",
|
||||
"BindingDisplayTexture": "StoneTrafo.png",
|
||||
"UnitSize": "Large",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": true,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": true
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"0, 5, 0",
|
||||
"0, 0, 0",
|
||||
"5, 0, 0",
|
||||
"5, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallStone",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"1, 0",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 5, -5-d3",
|
||||
"5, 5, -5-d3",
|
||||
"5, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallStone",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"1, 0",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 5, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0",
|
||||
"0, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallStone",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"1, -d3",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"5, 5, -5-d3",
|
||||
"0, 5, -5-d3",
|
||||
"0, 5, 0",
|
||||
"5, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallStone",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"1, -d3",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"5, 0, -5-d3",
|
||||
"5, 5, -5-d3",
|
||||
"5, 5, 0",
|
||||
"5, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallStone",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"1, -d3",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"5, 0, -5-d3",
|
||||
"5, 0, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallStone",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"1, -d3",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": {
|
||||
"Vertices": [
|
||||
"0, 5, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0",
|
||||
"0, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallStone",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSideExpand": {
|
||||
"Vertices": [
|
||||
"5, 5, -5-d3",
|
||||
"0, 5, -5-d3",
|
||||
"0, 5, 0",
|
||||
"5, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallStone",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSideExpand": {
|
||||
"Vertices": [
|
||||
"5, 0, -5-d3",
|
||||
"5, 5, -5-d3",
|
||||
"5, 5, 0",
|
||||
"5, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallStone",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSideExpand": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"5, 0, -5-d3",
|
||||
"5, 0, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallStone",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": "PaperTrafo",
|
||||
"BindingDisplayTexture": "PaperTrafo.png",
|
||||
"UnitSize": "Large",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": true,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": true
|
||||
},
|
||||
"ThreeDTopFace": {
|
||||
"Vertices": [
|
||||
"0, 5, 0",
|
||||
"0, 0, 0",
|
||||
"5, 0, 0",
|
||||
"5, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallPaper",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"1, 0",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ThreeDBottomFace": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"0, 5, -5-d3",
|
||||
"5, 5, -5-d3",
|
||||
"5, 0, -5-d3"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallPaper",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, 0",
|
||||
"1, 0",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSide": {
|
||||
"Vertices": [
|
||||
"0, 5, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0",
|
||||
"0, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallPaper",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"1, -d3",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSide": {
|
||||
"Vertices": [
|
||||
"5, 5, -5-d3",
|
||||
"0, 5, -5-d3",
|
||||
"0, 5, 0",
|
||||
"5, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallPaper",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"1, -d3",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSide": {
|
||||
"Vertices": [
|
||||
"5, 0, -5-d3",
|
||||
"5, 5, -5-d3",
|
||||
"5, 5, 0",
|
||||
"5, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallPaper",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"1, -d3",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSide": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"5, 0, -5-d3",
|
||||
"5, 0, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallPaper",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"0, -d3",
|
||||
"1, -d3",
|
||||
"1, 1",
|
||||
"0, 1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDTopSideExpand": {
|
||||
"Vertices": [
|
||||
"0, 5, -5-d3",
|
||||
"0, 0, -5-d3",
|
||||
"0, 0, 0",
|
||||
"0, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallPaper",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDRightSideExpand": {
|
||||
"Vertices": [
|
||||
"5, 5, -5-d3",
|
||||
"0, 5, -5-d3",
|
||||
"0, 5, 0",
|
||||
"5, 5, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallPaper",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDBottomSideExpand": {
|
||||
"Vertices": [
|
||||
"5, 0, -5-d3",
|
||||
"5, 5, -5-d3",
|
||||
"5, 5, 0",
|
||||
"5, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallPaper",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TwoDLeftSideExpand": {
|
||||
"Vertices": [
|
||||
"0, 0, -5-d3",
|
||||
"5, 0, -5-d3",
|
||||
"5, 0, 0",
|
||||
"0, 0, 0"
|
||||
],
|
||||
"Faces": [
|
||||
{
|
||||
"Type": "RECTANGLE",
|
||||
"Textures": "BallPaper",
|
||||
"Indices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"UVs": [
|
||||
"1+d3, 0",
|
||||
"1+d3, 1",
|
||||
"0, 1",
|
||||
"0, 0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
@ -1,317 +0,0 @@
|
||||
[
|
||||
{
|
||||
"Type": "NormalFloor",
|
||||
"BindingDisplayTexture": "NormalFloor.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Column",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "NormalBorder",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;2dBottom;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "d1, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalBorder",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "2dBottom;False;2dTop;2dRight;3dTop;3dBottom",
|
||||
"StartPosition": "d1, (2.5*1), 0",
|
||||
"ExpandParam": "d1, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "NormalFloorTerminal",
|
||||
"BindingDisplayTexture": "NormalFloorTerminal.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "NormalOutterCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;2dBottom;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalOutterCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;2dBottom;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "Normal1x1",
|
||||
"BindingDisplayTexture": "Normal1x1.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": true,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "NormalOutterCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalOutterCorner",
|
||||
"Rotation": "R90",
|
||||
"SideSync": "2dLeft;False;False;2dBottom;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalOutterCorner",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "2dBottom;False;False;2dRight;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalOutterCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;False;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "NormalPlatform",
|
||||
"BindingDisplayTexture": "NormalPlatform.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Freedom",
|
||||
"InitColumnDirection": "PositiveY",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": true,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "Flat",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;False;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), (2.5*1), 0",
|
||||
"ExpandParam": "d1, d2"
|
||||
},
|
||||
{
|
||||
"Type": "NormalBorder",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), 0, 0",
|
||||
"ExpandParam": "d2, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalBorder",
|
||||
"Rotation": "R90",
|
||||
"SideSync": "False;False;False;2dBottom;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2) +d2, (2.5*1), 0",
|
||||
"ExpandParam": "d1, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalBorder",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "False;False;False;2dRight;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1) +d2, (2.5*2) +d1, 0",
|
||||
"ExpandParam": "d2, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalBorder",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "False;False;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1) +d1, 0",
|
||||
"ExpandParam": "d1, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalOutterCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalOutterCorner",
|
||||
"Rotation": "R90",
|
||||
"SideSync": "2dLeft;False;False;2dBottom;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2) +d2, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalOutterCorner",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "2dBottom;False;False;2dRight;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2) +d2, (2.5*2) +d1, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalOutterCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;False;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*2) +d1, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "NormalLConnector",
|
||||
"BindingDisplayTexture": "NormalLConnector.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "NormalOutterCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalBorder",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;2dBottom;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalInnerCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;2dRight;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalBorder",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;False;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "NormalTConnector",
|
||||
"BindingDisplayTexture": "NormalTConnector.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": false,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "NormalInnerCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "False;2dBottom;2dLeft;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalInnerCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;2dRight;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalBorder",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;False;2dLeft;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1), 0",
|
||||
"ExpandParam": "1, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "NormalCrossroad",
|
||||
"BindingDisplayTexture": "NormalCrossroad.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": false,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "NormalInnerCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;2dRight;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalInnerCorner",
|
||||
"Rotation": "R90",
|
||||
"SideSync": "False;2dTop;2dRight;False;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalInnerCorner",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "False;2dLeft;2dTop;False;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "NormalInnerCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "False;2dBottom;2dLeft;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -1,397 +0,0 @@
|
||||
[
|
||||
{
|
||||
"Type": "SinkFloor",
|
||||
"BindingDisplayTexture": "SinkFloor.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Column",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;2dBottom;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "d1, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "2dBottom;False;2dTop;2dRight;3dTop;3dBottom",
|
||||
"StartPosition": "d1, (2.5*1), 0",
|
||||
"ExpandParam": "d1, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "SinkFloorTerminal",
|
||||
"BindingDisplayTexture": "SinkFloorTerminal.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;2dBottom;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;2dBottom;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "Sink1x1",
|
||||
"BindingDisplayTexture": "Sink1x1.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": true,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R90",
|
||||
"SideSync": "2dLeft;False;False;2dBottom;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "2dBottom;False;False;2dRight;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;False;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "SinkPlatform",
|
||||
"BindingDisplayTexture": "SinkPlatform.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Freedom",
|
||||
"InitColumnDirection": "PositiveY",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": true,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "Flat",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;False;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), (2.5*1), -0.7",
|
||||
"ExpandParam": "d1, d2"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), 0, 0",
|
||||
"ExpandParam": "d2, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R90",
|
||||
"SideSync": "False;False;False;2dBottom;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2) +d2, (2.5*1), 0",
|
||||
"ExpandParam": "d1, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "False;False;False;2dRight;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1) +d2, (2.5*2) +d1, 0",
|
||||
"ExpandParam": "d2, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "False;False;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1) +d1, 0",
|
||||
"ExpandParam": "d1, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R90",
|
||||
"SideSync": "2dLeft;False;False;2dBottom;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2) +d2, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "2dBottom;False;False;2dRight;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2) +d2, (2.5*2) +d1, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;False;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*2) +d1, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "RibbonPlatform",
|
||||
"BindingDisplayTexture": "RibbonPlatform.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Freedom",
|
||||
"InitColumnDirection": "PositiveY",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": true,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "Flat",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;False;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), (2.5*1), -0.7",
|
||||
"ExpandParam": "d1, d2"
|
||||
},
|
||||
{
|
||||
"Type": "RibbonBorder",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), 0, 0",
|
||||
"ExpandParam": "d2, 0"
|
||||
},
|
||||
{
|
||||
"Type": "RibbonBorder",
|
||||
"Rotation": "R90",
|
||||
"SideSync": "False;False;False;2dBottom;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2) +d2, (2.5*1), 0",
|
||||
"ExpandParam": "d1, 0"
|
||||
},
|
||||
{
|
||||
"Type": "RibbonBorder",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "False;False;False;2dRight;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1) +d2, (2.5*2) +d1, 0",
|
||||
"ExpandParam": "d2, 0"
|
||||
},
|
||||
{
|
||||
"Type": "RibbonBorder",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "False;False;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1) +d1, 0",
|
||||
"ExpandParam": "d1, 0"
|
||||
},
|
||||
{
|
||||
"Type": "RibbonOutterCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "RibbonOutterCorner",
|
||||
"Rotation": "R90",
|
||||
"SideSync": "2dLeft;False;False;2dBottom;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2) +d2, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "RibbonOutterCorner",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "2dBottom;False;False;2dRight;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2) +d2, (2.5*2) +d1, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "RibbonOutterCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;False;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*2) +d1, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "SinkLConnector",
|
||||
"BindingDisplayTexture": "SinkLConnector.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;2dBottom;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;2dRight;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;False;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "SinkTConnector",
|
||||
"BindingDisplayTexture": "SinkTConnector.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": false,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "False;2dBottom;2dLeft;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;2dRight;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;False;2dLeft;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1), 0",
|
||||
"ExpandParam": "1, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "SinkCrossroad",
|
||||
"BindingDisplayTexture": "SinkCrossroad.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Static",
|
||||
"InitColumnDirection": "PositiveX",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": false,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;2dRight;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R90",
|
||||
"SideSync": "False;2dTop;2dRight;False;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1), 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "False;2dLeft;2dTop;False;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "False;2dBottom;2dLeft;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -1,262 +0,0 @@
|
||||
[
|
||||
{
|
||||
"Type": "WideFloor",
|
||||
"BindingDisplayTexture": "WideFloor.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Freedom",
|
||||
"InitColumnDirection": "PositiveY",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;2dBottom;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "d2, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "2dBottom;False;2dTop;2dRight;3dTop;3dBottom",
|
||||
"StartPosition": "d2, (2.5*2)+d1, 0",
|
||||
"ExpandParam": "d2, 0"
|
||||
},
|
||||
{
|
||||
"Type": "Flat",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1), -0.7",
|
||||
"ExpandParam": "d1, d2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "WideFloorTerminal",
|
||||
"BindingDisplayTexture": "WideFloorTerminal.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Column",
|
||||
"InitColumnDirection": "PositiveY",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": true,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;2dBottom;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;2dBottom;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*2)+d1, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "False;2dBottom;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*1) +d1, 0",
|
||||
"ExpandParam": "d1, 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "WideLConnector",
|
||||
"BindingDisplayTexture": "WideLConnector.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Column",
|
||||
"InitColumnDirection": "PositiveY",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": true,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "SinkOutterCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;2dBottom;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*1), 0, 0",
|
||||
"ExpandParam": "d1 + 1, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;2dRight;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2) + d1, (2.5*2) + d1, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;False;False;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*2)+d1, 0",
|
||||
"ExpandParam": "d1 + 1, 0"
|
||||
},
|
||||
{
|
||||
"Type": "Flat",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "2.5, 2.5, -0.7",
|
||||
"ExpandParam": "d1, d1 + 1"
|
||||
},
|
||||
{
|
||||
"Type": "Flat",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;2dRight;False;False;3dTop;3dBottom",
|
||||
"StartPosition": "2.5, (2.5 * 2) + d1, -0.7",
|
||||
"ExpandParam": "0, d1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "WideTConnector",
|
||||
"BindingDisplayTexture": "WideTConnector.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Column",
|
||||
"InitColumnDirection": "PositiveY",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": true,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": false,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "False;2dBottom;2dLeft;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2) + d1, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;2dRight;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2) + d1, (2.5*2) + d1, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkBorder",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "2dRight;False;2dLeft;2dTop;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*2) + d1, 0",
|
||||
"ExpandParam": "d1 + 2, 0"
|
||||
},
|
||||
{
|
||||
"Type": "Flat",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "2.5, 2.5, -0.7",
|
||||
"ExpandParam": "d1, d1+1"
|
||||
},
|
||||
{
|
||||
"Type": "Flat",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "2.5, 0, -0.7",
|
||||
"ExpandParam": "0, d1"
|
||||
},
|
||||
{
|
||||
"Type": "Flat",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;2dRight;False;False;3dTop;3dBottom",
|
||||
"StartPosition": "2.5, (2.5*2)+d1, -0.7",
|
||||
"ExpandParam": "0, d1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "WideCrossroad",
|
||||
"BindingDisplayTexture": "WideCrossroad.png",
|
||||
"UnitSize": "Small",
|
||||
"ExpandType": "Column",
|
||||
"InitColumnDirection": "PositiveY",
|
||||
"DefaultSideConfig": {
|
||||
"UseTwoDTop": false,
|
||||
"UseTwoDRight": false,
|
||||
"UseTwoDBottom": false,
|
||||
"UseTwoDLeft": false,
|
||||
"UseThreeDTop": true,
|
||||
"UseThreeDBottom": false
|
||||
},
|
||||
"SmashedBlocks": [
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;2dRight;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2)+d1, (2.5*2)+d1, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R90",
|
||||
"SideSync": "False;2dTop;2dRight;False;3dTop;3dBottom",
|
||||
"StartPosition": "0, (2.5*2)+d1, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R180",
|
||||
"SideSync": "False;2dLeft;2dTop;False;3dTop;3dBottom",
|
||||
"StartPosition": "0, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "SinkInnerCorner",
|
||||
"Rotation": "R270",
|
||||
"SideSync": "False;2dBottom;2dLeft;False;3dTop;3dBottom",
|
||||
"StartPosition": "(2.5*2)+d1, 0, 0",
|
||||
"ExpandParam": "0, 0"
|
||||
},
|
||||
{
|
||||
"Type": "Flat",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "2dTop;False;2dBottom;False;3dTop;3dBottom",
|
||||
"StartPosition": "0, 2.5, -0.7",
|
||||
"ExpandParam": "d1, d1+2"
|
||||
},
|
||||
{
|
||||
"Type": "Flat",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;False;False;2dLeft;3dTop;3dBottom",
|
||||
"StartPosition": "2.5, 0, -0.7",
|
||||
"ExpandParam": "0, d1"
|
||||
},
|
||||
{
|
||||
"Type": "Flat",
|
||||
"Rotation": "R0",
|
||||
"SideSync": "False;2dRight;False;False;3dTop;3dBottom",
|
||||
"StartPosition": "2.5, (2.5*2)+d1, -0.7",
|
||||
"ExpandParam": "0, d1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|