Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OoT] Improved "Add Path" button #257

Merged
merged 4 commits into from
Dec 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 73 additions & 1 deletion fast64_internal/oot/oot_utility.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import bpy, math, os, re
import bpy
import math
import os
import re

from ast import parse, Expression, Num, UnaryOp, USub, Invert, BinOp
from mathutils import Vector
from bpy.types import Object
from bpy.utils import register_class, unregister_class
from typing import Callable
Expand Down Expand Up @@ -869,3 +874,70 @@ def _eval(node):
raise ValueError(f"Unsupported AST node {node}")

return f"0x{_eval(node.body):X}"


def getNewPath(type: str, isClosedShape: bool):
"""
Returns a new Curve Object with the selected spline shape

Parameters:
- ``type``: the path's type (square, line, etc)
- ``isClosedShape``: choose if the spline should have an extra point to make a closed shape
"""

# create a new curve
newCurve = bpy.data.curves.new("New Path", "CURVE")
newCurve.dimensions = "3D"

# add a new spline to the curve
newSpline = newCurve.splines.new("NURBS") # comes with 1 point

# generate shape based on 'type' parameter
scaleDivBy2 = bpy.context.scene.ootBlenderScale / 2
match type:
case "Line":
newSpline.points.add(1)
for i, point in enumerate(newSpline.points):
point.co.x = i * bpy.context.scene.ootBlenderScale
point.co.w = 1
case "Triangle":
newSpline.points.add(2)
for i, point in enumerate(newSpline.points):
point.co.x = i * scaleDivBy2
if i == 1:
point.co.y = (len(newSpline.points) * scaleDivBy2) / 2
point.co.w = 1
case "Square" | "Trapezium":
newSpline.points.add(3)
for i, point in enumerate(newSpline.points):
point.co.x = i * scaleDivBy2
if i in [1, 2]:
if type == "Square":
point.co.y = (len(newSpline.points) - 1) * scaleDivBy2
if i == 1:
point.co.x = newSpline.points[0].co.x
else:
point.co.x = point.co.y
else:
point.co.y = 1 * scaleDivBy2
point.co.w = 1
case _:
raise PluginError("ERROR: Invalid Path Type!")

if isClosedShape and type != "Line":
newSpline.points.add(1)
newSpline.points[-1].co = newSpline.points[0].co

# make the curve's display accurate to the point's shape
newSpline.use_cyclic_u = True
newSpline.use_endpoint_u = False
newSpline.resolution_u = 64
newSpline.order_u = 2

# create a new object and add the curve as data
newPath = bpy.data.objects.new("New Path", newCurve)
newPath.show_name = True
newPath.location = Vector(bpy.context.scene.cursor.location)
bpy.context.view_layer.active_layer_collection.collection.objects.link(newPath)

return newPath
38 changes: 32 additions & 6 deletions fast64_internal/oot/tools/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
from mathutils import Vector
from bpy.ops import mesh, object, curve
from bpy.types import Operator, Object, Context
from bpy.props import FloatProperty, StringProperty
from bpy.props import FloatProperty, StringProperty, EnumProperty, BoolProperty
from ...operators import AddWaterBox, addMaterialByName
from ...utility import parentObject, setOrigin
from ..cutscene.motion.utility import setupCutscene, createNewCameraShot
from ..oot_utility import getNewPath


class OOT_AddWaterBox(AddWaterBox):
Expand Down Expand Up @@ -181,23 +182,48 @@ def draw(self, context):
class OOT_AddPath(Operator):
bl_idname = "object.oot_add_path"
bl_label = "Add Path"
bl_options = {"REGISTER", "UNDO", "PRESET"}
bl_options = {"REGISTER", "UNDO"}

isClosedShape: BoolProperty(name="", default=True)
pathType: EnumProperty(
name="",
items=[
("Line", "Line", "Line"),
("Square", "Square", "Square"),
("Triangle", "Triangle", "Triangle"),
("Trapezium", "Trapezium", "Trapezium"),
],
default="Line",
)

def execute(self, context):
if context.mode != "OBJECT":
object.mode_set(mode="OBJECT")
object.select_all(action="DESELECT")

location = Vector(context.scene.cursor.location)
curve.primitive_nurbs_path_add(radius=1, align="WORLD", location=location[:])
pathObj = context.view_layer.objects.active
pathObj.name = "New Path"
pathObj = getNewPath(self.pathType, self.isClosedShape)
activeObj = context.view_layer.objects.active
if activeObj.type == "EMPTY" and activeObj.ootEmptyType == "Scene":
pathObj.parent = activeObj

object.select_all(action="DESELECT")
pathObj.select_set(True)
context.view_layer.objects.active = pathObj
return {"FINISHED"}

def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self, width=320)

def draw(self, context):
layout = self.layout
layout.label(text="Path Settings")
props = [("Path Type", "pathType"), ("Closed Shape", "isClosedShape")]

for desc, propName in props:
split = layout.split(factor=0.30)
split.label(text=desc)
split.prop(self, propName)


class OOTClearTransformAndLock(Operator):
bl_idname = "object.oot_clear_transform"
Expand Down