Skip to content

Commit

Permalink
Generate UVs on terrain tiles.
Browse files Browse the repository at this point in the history
Use multilayer for terrain
add placeholder for parallax interiors
  • Loading branch information
Simarilius-uk committed Nov 11, 2023
1 parent 3ea6752 commit 213a62d
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 9 deletions.
152 changes: 148 additions & 4 deletions i_scene_cp77_gltf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,145 @@ def draw(self, context):
col.prop(self, "show_meshtools")
col.prop(self, "show_collisiontools")
col.prop(self, "show_animtools")


class CP77ScriptManager(bpy.types.Panel):
bl_label = "Script Manager"
bl_idname = "CP77_PT_ScriptManagerPanel"
bl_space_type = 'TEXT_EDITOR'
bl_region_type = 'UI'
bl_category = "CP77 Modding"

def draw(self, context):
layout = self.layout
box = layout.box()
col = box.column()
# Get the path to the "scripts" folder in the add-on's root directory
script_dir = os.path.join(os.path.dirname(__file__), "scripts")

# List available scripts
script_files = [f for f in os.listdir(script_dir) if f.endswith(".py")]


for script_file in script_files:
row = col.row(align=True)
row.operator("script_manager.save_script", text="", icon="APPEND_BLEND").script_file = script_file
row.operator("script_manager.load_script", text=script_file).script_file = script_file
row.operator("script_manager.delete_script", text="", icon="X").script_file = script_file

row = box.row(align=True)
row.operator("script_manager.create_script")


class CP77CreateScript(bpy.types.Operator):
bl_idname = "script_manager.create_script"
bl_label = "Create New Script"
bl_description = "create a new script in the cp77 modding scripts directory"

def execute(self, context):
script_dir = os.path.join(os.path.dirname(__file__), "scripts")
base_name = "new_script"
script_name = base_name + ".py"

# Check if a script with the default name already exists
i = 1
while os.path.exists(os.path.join(script_dir, script_name)):
script_name = f"{base_name}_{i}.py"
i += 1

script_path = os.path.join(script_dir, script_name)

with open(script_path, 'w') as f:
f.write("# New Script")

return {'FINISHED'}


class CP77LoadScript(bpy.types.Operator):
bl_idname = "script_manager.load_script"
bl_label = "Load Script"
bl_description = "Click to load or switch to this script, ctrl+click to rename"

script_file: bpy.props.StringProperty()
new_name: bpy.props.StringProperty(name="New name", default=".py")

def execute(self, context):
script_name = self.script_file

if self.new_name:
# Rename the script
script_path = os.path.join(os.path.dirname(__file__), "scripts", script_name)
new_script_path = os.path.join(os.path.dirname(__file__), "scripts", self.new_name)

if os.path.exists(script_path):
if not os.path.exists(new_script_path):
os.rename(script_path, new_script_path)
self.report({'INFO'}, f"Renamed '{script_name}' to '{self.new_name}'")
else:
self.report({'ERROR'}, f"A script with the name '{self.new_name}' already exists.")
else:
# Check if the script is already loaded
script_text = bpy.data.texts.get(script_name)
# Switch to the loaded script if present
if script_text is not None:
context.space_data.text = script_text
else:
# If the script is not loaded, load it
script_path = os.path.join(os.path.dirname(__file__), "scripts", script_name)

if os.path.exists(script_path):
with open(script_path, 'r') as f:
text_data = bpy.data.texts.new(name=script_name)
text_data.from_string(f.read())
# Set the loaded script as active
context.space_data.text = text_data

return {'FINISHED'}

def invoke(self, context, event):
if event.ctrl:
# Ctrl+Click to rename
return context.window_manager.invoke_props_dialog(self)
else:
self.new_name = ""
return self.execute(context)

def draw(self, context):
layout = self.layout
layout.prop(self, "new_name")


class CP77SaveScript(bpy.types.Operator):
bl_idname = "script_manager.save_script"
bl_label = "Save Script"
bl_description = "Press to save this script"

script_file: bpy.props.StringProperty()

def execute(self, context):
script_text = context.space_data.text
if script_text:
script_path = os.path.join(os.path.dirname(__file__), "scripts", self.script_file)
with open(script_path, 'w') as f:
f.write(script_text.as_string())

return {'FINISHED'}


class CP77DeleteScript(bpy.types.Operator):
bl_idname = "script_manager.delete_script"
bl_label = "Delete Script"
bl_description = "Press to delete this script"

script_file: bpy.props.StringProperty()

def execute(self, context):
script_path = os.path.join(os.path.dirname(__file__), "scripts", self.script_file)

if os.path.exists(script_path):
os.remove(script_path)

return {'FINISHED'}


def SetCyclesRenderer(use_cycles=True, set_gi_params=False):
Expand Down Expand Up @@ -377,11 +516,11 @@ def execute(self, context):

def invoke(self, context, event):
if event.ctrl:
self.new_name = self.name
return context.window_manager.invoke_props_dialog(self)
else:
self.new_name = ""
return self.execute(context)


# inserts a keyframe on the current frame
class CP77Keyframe(bpy.types.Operator):
Expand Down Expand Up @@ -531,9 +670,9 @@ def draw(self, context):
row = box.row(align=True)
row.prop(active_action, 'frame_start', text="")
row.prop(active_action, 'frame_end', text="")
else:
row.separator()
row.operator('reset_armature.cp77')

row.separator()
row.operator('reset_armature.cp77')

box = layout.box()
row = box.row(align=True)
Expand Down Expand Up @@ -1029,7 +1168,12 @@ def menu_func_export(self, context):
CP77CollisionExport,
CP77CollisionGenerator,
CP77Animset,
CP77ScriptManager,
CP77DeleteScript,
CP77CreateScript,
CP77LoadScript,
CP77AnimsDelete,
CP77SaveScript,
CP77IOSuitePreferences,
CollectionAppearancePanel,
CP77HairProfileExport,
Expand Down
3 changes: 3 additions & 0 deletions i_scene_cp77_gltf/importers/import_with_materials.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from io_scene_gltf2.blender.imp.gltf2_blender_gltf import BlenderGlTF
from ..main.setup import MaterialBuilder
from ..main.common import json_ver_validate
from ..main.common import UV_by_bounds
from .attribute_import import manage_garment_support

def CP77GLBimport(self, exclude_unused_mats=True, image_format='png', with_materials=True, filepath='', hide_armatures=True, update_gi=True, import_garmentsupport=False, files=[], directory='', appearances=[]):
Expand Down Expand Up @@ -42,6 +43,8 @@ def CP77GLBimport(self, exclude_unused_mats=True, image_format='png', with_mater
existingMaterials = bpy.data.materials.keys()
BlenderGlTF.create(gltf_importer)
imported= context.selected_objects #the new stuff should be selected
if f['name'][:7]=='terrain':
UV_by_bounds(imported)
collection = bpy.data.collections.new(os.path.splitext(f['name'])[0])
bpy.context.scene.collection.children.link(collection)
for o in imported:
Expand Down
35 changes: 35 additions & 0 deletions i_scene_cp77_gltf/main/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,41 @@
import math
from mathutils import Color
import pkg_resources
import bpy
import bmesh
from mathutils import Vector

def UV_by_bounds(selected_objects):
current_mode = bpy.context.object.mode
min_vertex = Vector((float('inf'), float('inf'), float('inf')))
max_vertex = Vector((float('-inf'), float('-inf'), float('-inf')))
for obj in selected_objects:
if obj.type == 'MESH':
matrix = obj.matrix_world
mesh = obj.data
for vertex in mesh.vertices:
vertex_world = matrix @ vertex.co
min_vertex = Vector(min(min_vertex[i], vertex_world[i]) for i in range(3))
max_vertex = Vector(max(max_vertex[i], vertex_world[i]) for i in range(3))

for obj in selected_objects:
if len(obj.data.uv_layers)<1:
me = obj.data
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bm = bmesh.from_edit_mesh(me)

uv_layer = bm.loops.layers.uv.verify()

# adjust uv coordinates
for face in bm.faces:
for loop in face.loops:
loop_uv = loop[uv_layer]
# use xy position of the vertex as a uv coordinate
loop_uv.uv[0]=(loop.vert.co.x-min_vertex[0])/(max_vertex[0]-min_vertex[0])
loop_uv.uv[1]=(loop.vert.co.y-min_vertex[1])/(max_vertex[1]-min_vertex[1])

bmesh.update_edit_mesh(me)
bpy.ops.object.mode_set(mode=current_mode)

def get_inputs(tree):
return ([x for x in tree.interface.items_tree if (x.item_type == 'SOCKET' and x.in_out == 'INPUT')])
Expand Down
17 changes: 12 additions & 5 deletions i_scene_cp77_gltf/main/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from ..material_types.decal import Decal
from ..material_types.decal_gradientmap_recolor import DecalGradientmapRecolor
from ..material_types.televisionad import TelevisionAd
from ..material_types.window_parallax_interior_proxy import windowParallaxIntProx


class MaterialBuilder:
Expand Down Expand Up @@ -53,13 +54,14 @@ def create(self,materialIndex):
bpyMat.use_nodes = True
no_shadows=False
match rawMat["MaterialTemplate"]:
case "engine\\materials\\multilayered.mt" | "base\\materials\\vehicle_destr_blendshape.mt" | "base\\materials\\multilayered_clear_coat.mt":
case "engine\\materials\\multilayered.mt" | "base\\materials\\vehicle_destr_blendshape.mt" | "base\\materials\\multilayered_clear_coat.mt" | "base\\materials\\multilayered_terrain.mt":
multilayered = Multilayered(self.BasePath,self.image_format,self.ProjPath)
multilayered.create(rawMat["Data"],bpyMat)

case "base\\materials\\multilayered_terrain.mt":
multilayeredTerrain = Multilayered(self.BasePath,self.image_format, self.ProjPath)
multilayeredTerrain.create(rawMat["Data"],bpyMat)

#case "base\\materials\\multilayered_terrain.mt":
# multilayeredTerrain = Multilayered(self.BasePath,self.image_format, self.ProjPath)
# multilayeredTerrain.create(rawMat["Data"],bpyMat)

# This material should be handled within the main multilayered.py file. Commenting this out for now in case I broke something - jato
#case "base\\materials\\multilayered_clear_coat.mt":
Expand Down Expand Up @@ -172,7 +174,11 @@ def create(self,materialIndex):
case "base\\fx\\shaders\\television_ad.mt" :
televisionAd = TelevisionAd(self.BasePath,self.image_format,self.ProjPath)
televisionAd.create(rawMat["Data"],bpyMat)


case "base\\materials\\window_parallax_interior_proxy.mt":
window = windowParallaxIntProx(self.BasePath,self.image_format,self.ProjPath)
window.create(rawMat["Data"],bpyMat)

case _:
print('Unhandled mt - ', rawMat["MaterialTemplate"])

Expand Down Expand Up @@ -201,6 +207,7 @@ def create(self,materialIndex):
print('decal_gradientmap_recolor.mt')
decalGradientMapRecolor = DecalGradientmapRecolor(self.BasePath,self.image_format, self.ProjPath)
decalGradientMapRecolor.create(self.obj["Data"]["RootChunk"],bpyMat)


case _:
print(self.obj["Data"]["RootChunk"]["baseMaterial"]["DepotPath"]['$value']," | unimplemented yet")
Expand Down
50 changes: 50 additions & 0 deletions i_scene_cp77_gltf/material_types/window_parallax_interior_proxy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import bpy
import os
from ..main.common import *

class windowParallaxIntProx:
def __init__(self, BasePath,image_format, ProjPath):
self.BasePath = BasePath
self.ProjPath = ProjPath
self.image_format = image_format
def create(self,Data,Mat):
CurMat = Mat.node_tree
pBSDF=CurMat.nodes['Principled BSDF']


# RoomAtlas
if "RoomAtlas" in Data:
bcolImg=imageFromRelPath(Data["RoomAtlas"],self.image_format,DepotPath=self.BasePath, ProjPath=self.ProjPath)
bColNode = create_node(CurMat.nodes,"ShaderNodeTexImage", (-600,450), label="RoomAtlas", image=bcolImg)
CurMat.links.new(bColNode.outputs[0],pBSDF.inputs['Base Color'])

# AtlasGridUvRatio
# roomWidth
if 'roomWidth' in Data:
roomWidth = CreateShaderNodeValue(CurMat,Data["roomWidth"],-800, -100,"roomWidth")
# roomHeight
if 'roomHeight' in Data:
mScale = CreateShaderNodeValue(CurMat,Data["roomHeight"],-8000, -200,"roomHeight")
# roomDepth
if 'roomDepth' in Data:
mScale = CreateShaderNodeValue(CurMat,Data["roomDepth"],-800, -300,"roomDepth")

par=createParallaxGroup()
# LightsTempVariationAtNight
# AmountTurnOffAtNight
# TintColorAtNight
# EmissiveEV
# positionXoffset
# positionYoffset
# AtlasDepth
# scaleXrandomization
# positionXrandomization
# EmissiveEVRaytracingBias
# EmissiveDirectionality
# EnableRaytracedEmissive
# ColorOverlayTexture
# Curtain
# CurtainDepth
# CurtainMaxCover
# CurtainCoverRandomize
# CurtainAlpha

0 comments on commit 213a62d

Please sign in to comment.