summaryrefslogtreecommitdiff
path: root/drafts/init-v0.1-from-3DS-io-addon.py
blob: 32d0ad04220904464c41de3d78369eb9d23b27b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

bl_info = {
    "name": "Export Half-Life 1 Tools Format(.map)",
    "author": "Ludovic Pouzenc",
    "version": (0, 1, 0),
    "blender": (2, 79, 0),
    "location": "File > Export > Half-Life 1 tools (.map)",
    "description": "Export mesh to Half-Life 1 tools (.map)",
    "warning": "",
    #"wiki_url": "http://to.do",
    "category": "Import-Export"}

"""
Related links:
https://developer.valvesoftware.com/wiki/MAP_file_format

Usage Notes:
Map file could be opened in Valve Hammer 3.4 editor (prefered bit windows only)
or passed to orignal's or ZLHT's compiler tools (use wine to run them on linux)

MAP format defines solids (brushes) as a set of intersecting planes.
Planes a defined by 3 points in space (could be different from face's vertices)

This is (very) unusual. This cannot reprents things such as :
* Concave meshes
* Non-planar faces
Existing tools that use this .map format probably don't cope with :
* ngons with n > 32

For now this script do :
* For each mesh in current scene
** Simplify it (remove doubles in vertices, fill holes, connect vertices to not have concave faces nor non planar faces)
** Recalc face normals to have them pointing to this outside of the mesh
* For each object in current scene that is type 'MESH'
** Take the mesh and local to world matrix
** Make a .map brush for each mesh's blender face (world coords, scaled by blender_to_map_scale_factor)
** Put AAATRIGGER texture stupidly
** Output it as part of worldspawn entity in .map

"""

if "bpy" in locals():
    import importlib
#   if "import_3ds" in locals():
#       importlib.reload(import_hl1map)
    if "export_hl1map" in locals():
        importlib.reload(export_hl1map)

import bpy
from bpy.props import (
        BoolProperty,
        CollectionProperty,
        FloatProperty,
        StringProperty,
        )
from bpy_extras.io_utils import (
#       ImportHelper,
        ExportHelper,
        )

#class ImportHL1MAP(bpy.types.Operator, ImportHelper):
#   """Import Half-Life 1 Tools Format(.map)"""
#   bl_idname = "import_scene.hl1_map"
#   bl_label = 'Half-Life 1 tools (.map)'
#   bl_options = {'UNDO'}

#   filename_ext = ".map"
#   filter_glob = StringProperty(default="*.map", options={'HIDDEN'})

#   constrain_size = FloatProperty(
#           name="Size Constraint",
#           description="Scale the model by 10 until it reaches the "
#                       "size constraint (0 to disable)",
#           min=0.0, max=1000.0,
#           soft_min=0.0, soft_max=1000.0,
#           default=10.0,
#           )
#   use_image_search = BoolProperty(
#           name="Image Search",
#           description="Search subdirectories for any associated images "
#                       "(Warning, may be slow)",
#           default=True,
#           )
#   use_apply_transform = BoolProperty(
#           name="Apply Transform",
#           description="Workaround for object transformations "
#                       "importing incorrectly",
#           default=True,
#           )

#   def execute(self, context):
#       from . import import_3ds

#       keywords = self.as_keywords(ignore=("axis_forward",
#                                           "axis_up",
#                                           "filter_glob",
#                                           ))

#       global_matrix = axis_conversion(from_forward=self.axis_forward,
#                                       from_up=self.axis_up,
#                                       ).to_4x4()
#       keywords["global_matrix"] = global_matrix

#       return import_3ds.load(self, context, **keywords)

class WorldSpawnEntityProp(bpy.types.PropertyGroup):
    value = bpy.props.StringProperty(name='')

class ExportHL1MAP(bpy.types.Operator, ExportHelper):
    """Export Half-Life 1 Tools Format(.map)"""
    bl_idname = 'export_scene.hl1_map'
    bl_label = 'Export HL1 .map'

    filename_ext = '.map'
    
    filter_glob = StringProperty(default='*'+filename_ext, options={'HIDDEN'})

    use_selection = BoolProperty(
            name='Selection Only',
            description='Export selected objects only',
            default=False,
            )

    blender_to_map_scale_factor = FloatProperty(
            name='Upscaling factor',
            description='Scale from blender world coordinates to map brush coordinates',
            default=100,
            )
    # self.attrs is a list of objects representing application specific and dynamically set attributes
    attrs = []
    # https://developer.valvesoftware.com/wiki/MAP_file_format
    collection = CollectionProperty(
            name='Worldspawn entity properties',
            description='All non-entity brushes in .map belongs to a Worldspawn entity that have mandatory properties to be ran in-game',
            type=WorldSpawnEntityProp,
            )

    worldspawn_props = {
        'classname': 'worldspawn',
        'sounds': 1,
        'MaxRange': 4096,
        'mapversion': 220,
        'wad': '\\half-life\\valve\\xeno.wad;\\half-life\\valve\\decals.wad;\\half-life\\valve\\halflife.wad;\\half-life\\valve\\liquids.wad'
    }
    def invoke(self, context, event):
        self.collection.clear()
        for attr in self.attrs:
            # create a new item in self.collection
            collectionItem = self.collection.add()
            collectionItem.name = attr.name
            collectionItem.value = attr.value
            attr.collectionItem = collectionItem
        return super(ExportHL1MAP, self).invoke(context, event)
    # FIXME https://blenderartists.org/t/how-to-set-a-property-for-an-operator-dynamically/615897/6
    # def draw(self, context):
        # layout = self.layout
        # for attr in self.attrs:
            # attrName = attr[0]
            # row = self.layout.split()
            # # it's not possible to set the name for an item in self.collection,
            # # however it's possible to set a label dynamically
            # row.label(attr.name)
            # # the following property refers to the attribute <value> of the item in self.collection
            # # remember the attribute <value> was defined in the class CustomFloatProperty
            # row.prop(attr.collectionItem, "value")
        # return super(ExportHL1MAP, self).draw(context)

    def execute(self, context):
        from . import export_hl1map
        keywords = self.as_keywords(ignore=('filter_glob','check_existing'))
        keywords['worldspawn_props'] = self.worldspawn_props
        print('export_hl1map.save(self, context, ', keywords, ')')
        return export_hl1map.save(self, context, **keywords)



# Add to a menu
def menu_func_export(self, context):
    self.layout.operator(ExportHL1MAP.bl_idname, text="Half-Life 1 tools (.map)")

#def menu_func_import(self, context):
#    self.layout.operator(ImportHL1MAP.bl_idname, text="Half-Life 1 tools (.map)")


def register():
    bpy.utils.register_module(__name__)
#   bpy.types.INFO_MT_file_import.append(menu_func_import)
    bpy.types.INFO_MT_file_export.append(menu_func_export)


def unregister():
    bpy.utils.unregister_module(__name__)
#   bpy.types.INFO_MT_file_import.remove(menu_func_import)
    bpy.types.INFO_MT_file_export.remove(menu_func_export)

if __name__ == "__main__":
    register()