265 lines
7.6 KiB
Python
265 lines
7.6 KiB
Python
VERSION = 'prealpha'
|
||
|
||
import bpy
|
||
import bpy_extras
|
||
import mathutils
|
||
|
||
__ENUM_POI_TYPE__ = {
|
||
('CASTLE', 'Castle', 'creepy castle', 1),
|
||
('RUIN', 'Ruin', 'repressive ruins', 2),
|
||
('CITY', 'City', 'callous city', 3),
|
||
('VILLAGE', 'Village', 'vengeful village', 4),
|
||
('SWAMP', 'Swamp', 'scornful swamp', 5),
|
||
}
|
||
|
||
|
||
class GaiaException(Exception):
|
||
pass
|
||
|
||
class GaiaNotActivated(GaiaException):
|
||
message = 'Gaia is not activated in this scene!'
|
||
|
||
|
||
# This allows you to right click on a button and link to documentation
|
||
def gaia_manual_map():
|
||
|
||
return (
|
||
'https://docs.phryk.net/gaia/latest/index.html', #prefix
|
||
( # mappings
|
||
('gaia.scene_enable', '#scene_enable'),
|
||
('gaia.poi_add', '#poi_add'),
|
||
)
|
||
)
|
||
|
||
|
||
def gaia_enabled():
|
||
if 'gaia_enabled' in bpy.context.scene:
|
||
return bpy.context.scene['gaia_enabled'] == VERSION
|
||
return False
|
||
|
||
|
||
def gaia_collection(name=None):
|
||
|
||
"""
|
||
returns gaia root collection, or sub-collection if `name` is passed
|
||
but only if Gaia is activated in this scene.
|
||
"""
|
||
|
||
root_collection_name = '__gaia__'
|
||
|
||
if gaia_enabled():
|
||
|
||
if not 'gaia_collections' in bpy.context.scene:
|
||
bpy.context.scene['gaia_collections'] = {}
|
||
|
||
# check if root Gaia collection exists
|
||
if 'root' in bpy.context.scene['gaia_collections'] and bpy.context.scene['gaia_collections']['root'] in bpy.data.collections:
|
||
root_collection = bpy.data.collections[bpy.context.scene['gaia_collections']['root']]
|
||
|
||
else:
|
||
# add root Gaia collection if not
|
||
root_collection = bpy.data.collections.new(root_collection_name)
|
||
bpy.context.scene['gaia_collections']['root'] = root_collection.name
|
||
bpy.context.scene.collection.children.link(root_collection)
|
||
|
||
if name is None:
|
||
return root_collection
|
||
|
||
else:
|
||
if name in bpy.context.scene['gaia_collections'] and bpy.context.scene['gaia_collections'][name] in bpy.data.collections:
|
||
return bpy.data.collections[bpy.context.scene['gaia_collections'][name]]
|
||
else:
|
||
collection = bpy.data.collections.new(name)
|
||
bpy.context.scene['gaia_collections'][name] = collection.name
|
||
root_collection.children.link(collection)
|
||
return collection
|
||
|
||
raise GaiaNotActivated()
|
||
|
||
|
||
def collection_get_recursive(collection, otype=None):
|
||
|
||
objects = []
|
||
for o in collection.objects.values():
|
||
#if otype is None or isinstance(o, otype): # since we can't create new bpy.types isinstance is not accurate enough (will match any subclasses, which if passed Object to filter for empties will just not do anything)
|
||
if type(o) == otype: # strict (same class) type checking
|
||
objects.append(o)
|
||
|
||
for c in collection.children.values():
|
||
objects += collection_get_recursive(c, type=type)
|
||
|
||
return objects
|
||
|
||
|
||
class SceneEnable(bpy.types.Operator):
|
||
|
||
bl_idname = "gaia.scene_enable"
|
||
bl_label = "Enable Gaia in this scene"
|
||
bl_options = {'REGISTER', 'UNDO'}
|
||
|
||
def execute(self, context):
|
||
|
||
context.scene['gaia_enabled'] = VERSION
|
||
return {'FINISHED'}
|
||
|
||
|
||
class POIAdd(bpy.types.Operator, bpy_extras.object_utils.AddObjectHelper):
|
||
|
||
"""Create a new Point of Interest"""
|
||
bl_idname = "gaia.poi_add"
|
||
bl_label = "Add Point of Interest"
|
||
bl_options = {'REGISTER', 'UNDO'}
|
||
|
||
def execute(self, context):
|
||
|
||
col = gaia_collection('POI')
|
||
|
||
bpy.ops.object.empty_add(type='SPHERE')
|
||
obj = bpy.context.active_object
|
||
obj.name = 'New POI'
|
||
|
||
col.objects.link(obj)
|
||
bpy.context.scene.collection.objects.unlink(obj)
|
||
|
||
return {'FINISHED'}
|
||
|
||
|
||
class POIGraph(bpy.types.Operator):
|
||
|
||
bl_idname = "gaia.poi_graph"
|
||
bl_label = "Build POI graph"
|
||
bl_options = {'REGISTER', 'UNDO'}
|
||
|
||
def execute(self, context):
|
||
|
||
self.report({'INFO'}, "FNORP")
|
||
|
||
poicol = gaia_collection('POI')
|
||
pois = collection_get_recursive(poicol, otype=bpy.types.Object) # Object means it'll filter for empties
|
||
|
||
vertices = []
|
||
for poi in pois:
|
||
self.report({'INFO'}, "POI!")
|
||
self.report({'INFO'}, poi.name)
|
||
vertices.append(poi.location)
|
||
|
||
vertices_2d = [mathutils.Vector((vert[0], vert[1])) for vert in vertices]
|
||
|
||
tri_verts, tri_edges, tri_faces, orig_verts, orig_edges, orig_faces = mathutils.geometry.delaunay_2d_cdt(vertices_2d, [], [], 1, 0.01)
|
||
|
||
self.report({'INFO'}, f"TRIANGULATION RESULT: {tri_edges}, {tri_faces}")
|
||
mesh = bpy.data.meshes.new('POIGraph')
|
||
mesh.from_pydata(vertices, tri_edges, tri_faces)
|
||
mesh.update()
|
||
|
||
meshobj = bpy.data.objects.new('POIGraph', mesh)
|
||
|
||
meshcol = gaia_collection('Meshes')
|
||
meshcol.objects.link(meshobj)
|
||
|
||
return {'FINISHED'}
|
||
|
||
|
||
def poi_add_button(self, context):
|
||
self.layout.operator(
|
||
POIAdd.bl_idname,
|
||
text="Point of Interest",
|
||
icon='PLUGIN'
|
||
)
|
||
|
||
def poi_graph_button(self, context):
|
||
self.layout.operator(
|
||
POIGraph.bl_idname,
|
||
text="Generate POI graph",
|
||
icon='PLUGIN'
|
||
)
|
||
|
||
class POIPanel(bpy.types.Panel):
|
||
|
||
bl_idname = "OBJECT_PT_GAIA_POI"
|
||
bl_label = "Gaia POI Properties"
|
||
bl_space_type = 'PROPERTIES'
|
||
bl_region_type = 'WINDOW'
|
||
bl_context = "object"
|
||
|
||
def draw(self, context):
|
||
|
||
layout = self.layout
|
||
|
||
if context.active_object.type != 'EMPTY':
|
||
row = layout.row()
|
||
row.label(text="This is not a Point of Interest.")
|
||
else:
|
||
row = layout.row()
|
||
row.prop(bpy.context.active_object, 'POI_type')
|
||
|
||
|
||
class GaiaPanel(bpy.types.Panel):
|
||
|
||
bl_idname = "VIEW3D_PT_GAIA"
|
||
bl_label = "Gaia"
|
||
bl_space_type = 'VIEW_3D'
|
||
bl_region_type = 'UI'
|
||
bl_category = 'Gaia'
|
||
|
||
def draw(self, context):
|
||
|
||
layout = self.layout
|
||
|
||
if not 'gaia_enabled' in bpy.context.scene:
|
||
row = layout.row()
|
||
row.label(text="Gaia not enabled.")
|
||
row = layout.row()
|
||
row.operator("gaia.scene_enable")
|
||
|
||
else: # gaia *is* enabled
|
||
if bpy.context.scene['gaia_enabled'] != VERSION:
|
||
|
||
row = layout.row()
|
||
row.label(text="Gaia enabled, but with a different version!")
|
||
|
||
row = layout.row()
|
||
row.label(text=f"Scene is on '{bpy.context.scene['gaia_enabled']}'.")
|
||
|
||
row = layout.row()
|
||
row.label(text=f"We are on '{VERSION}'.")
|
||
|
||
row = layout.row()
|
||
row.operator("gaia.scene_enable")
|
||
|
||
else:
|
||
|
||
row = layout.row()
|
||
row.label(text="Gaia enabled – place step 1 button here")
|
||
|
||
|
||
def register():
|
||
|
||
bpy.types.Object.POI_type = bpy.props.EnumProperty(name="POI type", items=__ENUM_POI_TYPE__)
|
||
|
||
bpy.utils.register_class(GaiaPanel)
|
||
bpy.utils.register_class(SceneEnable)
|
||
bpy.utils.register_class(POIAdd)
|
||
bpy.utils.register_class(POIGraph)
|
||
bpy.utils.register_class(POIPanel)
|
||
bpy.types.VIEW3D_MT_mesh_add.append(poi_add_button)
|
||
GaiaPanel.append(poi_graph_button)
|
||
bpy.utils.register_manual_map(gaia_manual_map)
|
||
|
||
|
||
def unregister():
|
||
|
||
bpy.utils.unregister_class(GaiaPanel)
|
||
bpy.utils.unregister_class(SceneEnable)
|
||
bpy.utils.unregister_class(POIAdd)
|
||
bpy.utils.unregister_class(POIGraph)
|
||
bpy.utils.unregister_class(POIPanel)
|
||
bpy.types.VIEW3D_MT_mesh_add.remove(poi_add_button)
|
||
GaiaPanel.remove(poi_graph_button)
|
||
bpy.utils.unregister_manual_map(add_object_manual_map)
|
||
|
||
del(bpy.types.Object.POI_type)
|
||
|
||
if __name__ == "__main__":
|
||
register()
|