wip
This commit is contained in:
@@ -6,6 +6,7 @@ Core functionality for generating texture images with text overlays.
|
||||
import bpy
|
||||
|
||||
def generate_texture_image(props, width, height):
|
||||
pass
|
||||
"""
|
||||
Generate the actual texture image with overlays.
|
||||
|
||||
@@ -19,60 +20,61 @@ def generate_texture_image(props, width, height):
|
||||
Returns (None, None) on error
|
||||
"""
|
||||
try:
|
||||
print(f"[TTG DEBUG] Starting texture generation at {width}x{height}px")
|
||||
pass
|
||||
|
||||
# TODO: Implement actual texture generation logic
|
||||
# This is a minimal stub to resolve the import error
|
||||
# The full implementation should include:
|
||||
# - Background color/image handling
|
||||
# - Text overlay processing and rendering
|
||||
# - Normal map generation if enabled
|
||||
# - Image composition and final output
|
||||
# Enhanced texture generation with proper error handling and logging
|
||||
print(f"DEBUG: Starting texture generation {width}x{height}")
|
||||
|
||||
print(f"[TTG DEBUG] Step 1: Creating Blender image object")
|
||||
# Create Blender image directly without large numpy arrays
|
||||
img_name = f"TextTexture_{width}x{height}"
|
||||
if img_name in bpy.data.images:
|
||||
print(f"[TTG DEBUG] Step 1a: Removing existing image: {img_name}")
|
||||
pass
|
||||
bpy.data.images.remove(bpy.data.images[img_name])
|
||||
|
||||
print(f"[TTG DEBUG] Step 1b: Creating new Blender image: {img_name}")
|
||||
blender_img = bpy.data.images.new(img_name, width, height, alpha=True)
|
||||
print(f"[TTG DEBUG] Step 1c: Blender image created successfully")
|
||||
|
||||
print(f"[TTG DEBUG] Step 2: Creating text texture with PIL")
|
||||
# Use PIL to create a proper text texture instead of solid color
|
||||
# PIL dependency is declared in blender_manifest.toml and should be auto-installed by Blender
|
||||
try:
|
||||
pass
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
print(f"[TTG DEBUG] Step 2a: PIL imported successfully")
|
||||
print("DEBUG: PIL imported successfully")
|
||||
|
||||
# Create PIL image with transparent background
|
||||
if props.background_transparent:
|
||||
pass
|
||||
pil_img = Image.new('RGBA', (width, height), (0, 0, 0, 0))
|
||||
print(f"[TTG DEBUG] Step 2b: Created transparent PIL image")
|
||||
else:
|
||||
pass
|
||||
bg_color = tuple(int(c * 255) for c in props.background_color[:3]) + (255,)
|
||||
pil_img = Image.new('RGBA', (width, height), bg_color)
|
||||
print(f"[TTG DEBUG] Step 2b: Created PIL image with background color: {bg_color}")
|
||||
|
||||
# Draw text if provided (including prepend/append)
|
||||
full_text_parts = []
|
||||
if props.prepend_text.strip():
|
||||
pass
|
||||
full_text_parts.append(props.prepend_text.strip())
|
||||
if props.text.strip():
|
||||
pass
|
||||
full_text_parts.append(props.text.strip())
|
||||
if props.append_text.strip():
|
||||
pass
|
||||
full_text_parts.append(props.append_text.strip())
|
||||
|
||||
if full_text_parts:
|
||||
pass
|
||||
draw = ImageDraw.Draw(pil_img)
|
||||
print(f"DEBUG: Drawing text parts: {full_text_parts}")
|
||||
|
||||
# Combine text based on layout mode
|
||||
if props.prepend_append_layout == 'HORIZONTAL':
|
||||
pass
|
||||
# For horizontal layout, use simple space separation with margin control
|
||||
if len(full_text_parts) == 1:
|
||||
pass
|
||||
full_text = full_text_parts[0]
|
||||
else:
|
||||
pass
|
||||
# Calculate number of spaces based on margin (but reasonable amounts)
|
||||
prepend_spaces = max(1, int(props.prepend_margin / 10)) if props.prepend_text.strip() else 0
|
||||
append_spaces = max(1, int(props.append_margin / 10)) if props.append_text.strip() else 0
|
||||
@@ -80,36 +82,42 @@ def generate_texture_image(props, width, height):
|
||||
# Build text with controlled spacing
|
||||
text_parts_with_spacing = []
|
||||
for i, part in enumerate(full_text_parts):
|
||||
pass
|
||||
if i == 0 and prepend_spaces > 0:
|
||||
pass
|
||||
# Add spacing after prepend text
|
||||
text_parts_with_spacing.append(part + " " * prepend_spaces)
|
||||
elif i == len(full_text_parts) - 1 and append_spaces > 0:
|
||||
# Add spacing before append text
|
||||
text_parts_with_spacing.append(" " * append_spaces + part)
|
||||
else:
|
||||
pass
|
||||
text_parts_with_spacing.append(part)
|
||||
|
||||
full_text = " ".join(text_parts_with_spacing)
|
||||
layout_mode = "horizontal"
|
||||
else:
|
||||
pass
|
||||
# Vertical layout - keep parts separate for individual positioning
|
||||
full_text = "\n".join(full_text_parts)
|
||||
layout_mode = "vertical"
|
||||
|
||||
print(f"[TTG DEBUG] Step 2c: Full text composed: '{full_text}' (layout: {layout_mode})")
|
||||
|
||||
# Determine font size (with text fitting if enabled)
|
||||
font_size = props.font_size
|
||||
if props.enable_text_fitting:
|
||||
print(f"[TTG DEBUG] Step 2d: Text fitting enabled, calculating optimal size")
|
||||
pass
|
||||
|
||||
# Try to load font for sizing
|
||||
try:
|
||||
pass
|
||||
if props.use_custom_font and props.custom_font_path:
|
||||
pass
|
||||
test_font_path = props.custom_font_path
|
||||
elif props.font_path != "default":
|
||||
test_font_path = props.font_path
|
||||
else:
|
||||
pass
|
||||
test_font_path = None
|
||||
|
||||
# Binary search for optimal font size
|
||||
@@ -121,9 +129,12 @@ def generate_texture_image(props, width, height):
|
||||
optimal_size = min_size
|
||||
for test_size in range(min_size, max_size + 1, 2): # Step by 2 for performance
|
||||
try:
|
||||
pass
|
||||
if test_font_path:
|
||||
pass
|
||||
test_font = ImageFont.truetype(test_font_path, test_size)
|
||||
else:
|
||||
pass
|
||||
test_font = ImageFont.load_default()
|
||||
|
||||
bbox = draw.textbbox((0, 0), full_text, font=test_font)
|
||||
@@ -131,35 +142,38 @@ def generate_texture_image(props, width, height):
|
||||
test_height = bbox[3] - bbox[1]
|
||||
|
||||
if test_width <= target_width and test_height <= target_height:
|
||||
pass
|
||||
optimal_size = test_size
|
||||
else:
|
||||
pass
|
||||
break
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
break
|
||||
|
||||
font_size = optimal_size
|
||||
print(f"[TTG DEBUG] Step 2d: Optimal font size calculated: {font_size}")
|
||||
except Exception as e:
|
||||
print(f"[TTG DEBUG] Step 2d: Font fitting failed, using default size: {e}")
|
||||
pass
|
||||
font_size = props.font_size
|
||||
|
||||
# Load final font
|
||||
try:
|
||||
pass
|
||||
if props.use_custom_font and props.custom_font_path:
|
||||
pass
|
||||
font = ImageFont.truetype(props.custom_font_path, font_size)
|
||||
print(f"[TTG DEBUG] Step 2e: Using custom font: {props.custom_font_path}, size: {font_size}")
|
||||
elif props.font_path != "default":
|
||||
font = ImageFont.truetype(props.font_path, font_size)
|
||||
print(f"[TTG DEBUG] Step 2e: Using system font: {props.font_path}, size: {font_size}")
|
||||
else:
|
||||
pass
|
||||
font = ImageFont.load_default()
|
||||
print(f"[TTG DEBUG] Step 2e: Using default font, size: {font_size}")
|
||||
except (OSError, IOError) as e:
|
||||
print(f"[TTG DEBUG] Step 2e: Font loading failed, using default: {e}")
|
||||
pass
|
||||
font = ImageFont.load_default()
|
||||
|
||||
# Calculate text position and draw
|
||||
if layout_mode == "vertical" and props.prepend_append_layout == 'VERTICAL':
|
||||
pass
|
||||
# Draw each part separately for vertical layout
|
||||
y_offset = 0
|
||||
total_height = 0
|
||||
@@ -167,6 +181,7 @@ def generate_texture_image(props, width, height):
|
||||
# Calculate total height first
|
||||
part_heights = []
|
||||
for part in full_text_parts:
|
||||
pass
|
||||
bbox = draw.textbbox((0, 0), part, font=font)
|
||||
part_height = bbox[3] - bbox[1]
|
||||
part_heights.append(part_height)
|
||||
@@ -174,6 +189,7 @@ def generate_texture_image(props, width, height):
|
||||
|
||||
# Add spacing between parts
|
||||
if len(full_text_parts) > 1:
|
||||
pass
|
||||
spacing = font_size // 4 # 25% of font size as line spacing
|
||||
total_height += spacing * (len(full_text_parts) - 1)
|
||||
|
||||
@@ -185,18 +201,19 @@ def generate_texture_image(props, width, height):
|
||||
text_color = tuple(int(c * 255) for c in props.text_color[:4])
|
||||
|
||||
for i, part in enumerate(full_text_parts):
|
||||
pass
|
||||
bbox = draw.textbbox((0, 0), part, font=font)
|
||||
part_width = bbox[2] - bbox[0]
|
||||
x = (width - part_width) // 2 # Center horizontally
|
||||
|
||||
draw.text((x, current_y), part, font=font, fill=text_color)
|
||||
print(f"[TTG DEBUG] Step 2f: Drew part '{part}' at ({x}, {current_y})")
|
||||
|
||||
current_y += part_heights[i]
|
||||
if i < len(full_text_parts) - 1: # Add spacing except after last part
|
||||
current_y += font_size // 4
|
||||
|
||||
else:
|
||||
pass
|
||||
# Horizontal layout or single text
|
||||
text_bbox = draw.textbbox((0, 0), full_text, font=font)
|
||||
text_width = text_bbox[2] - text_bbox[0]
|
||||
@@ -209,57 +226,85 @@ def generate_texture_image(props, width, height):
|
||||
# Draw text
|
||||
text_color = tuple(int(c * 255) for c in props.text_color[:4])
|
||||
draw.text((x, y), full_text, font=font, fill=text_color)
|
||||
print(f"[TTG DEBUG] Step 2f: Full text '{full_text}' drawn at ({x}, {y}) with size {font_size}")
|
||||
print(f"DEBUG: Text drawn at position ({x}, {y}) with color {text_color}")
|
||||
else:
|
||||
print(f"[TTG DEBUG] Step 2d: No text provided, using solid background")
|
||||
pass
|
||||
print("DEBUG: No text provided, using solid background")
|
||||
|
||||
# Convert PIL image to Blender format (flip vertically to fix mirroring)
|
||||
print(f"[TTG DEBUG] Step 2f: Converting PIL to Blender format with vertical flip")
|
||||
pil_img = pil_img.transpose(Image.FLIP_TOP_BOTTOM) # Fix mirroring issue
|
||||
pil_pixels = list(pil_img.getdata())
|
||||
blender_pixels = []
|
||||
for r, g, b, a in pil_pixels:
|
||||
pass
|
||||
blender_pixels.extend([r/255.0, g/255.0, b/255.0, a/255.0])
|
||||
|
||||
print(f"DEBUG: Converting {len(pil_pixels)} PIL pixels to Blender format")
|
||||
blender_img.pixels[:] = blender_pixels
|
||||
print(f"[TTG DEBUG] Step 2g: Pixel data conversion completed with flip correction")
|
||||
|
||||
except ImportError:
|
||||
print(f"[TTG DEBUG] Step 2: PIL not available, falling back to solid color")
|
||||
# Fallback to solid color if PIL is not available
|
||||
pixel_pattern = [props.background_color[0], props.background_color[1], props.background_color[2], 1.0]
|
||||
print(f"DEBUG: Texture generation completed successfully")
|
||||
except ImportError as e:
|
||||
pass
|
||||
# PIL not available - should not happen with proper Blender manifest dependencies
|
||||
print(f"ERROR: PIL dependency not available despite manifest declaration: {e}")
|
||||
print(f"ERROR: Check if Blender properly installed addon dependencies from manifest")
|
||||
# Create a visible yellow error pattern to indicate dependency issue
|
||||
error_pattern = [1.0, 1.0, 0.0, 1.0] # Yellow color to indicate dependency problem
|
||||
total_pixels = width * height
|
||||
blender_img.pixels[:] = pixel_pattern * total_pixels
|
||||
blender_img.pixels[:] = error_pattern * total_pixels
|
||||
print(f"DEBUG: Yellow error texture created (dependency issue)")
|
||||
|
||||
except ImportError as e:
|
||||
pass
|
||||
# PIL installation or import failed - create visible error pattern
|
||||
print(f"ERROR: PIL import error: {e}")
|
||||
# Create a visible red error pattern instead of black
|
||||
error_pattern = [1.0, 0.0, 0.0, 1.0] # Red color to indicate PIL failure
|
||||
total_pixels = width * height
|
||||
blender_img.pixels[:] = error_pattern * total_pixels
|
||||
print(f"DEBUG: Red error texture created (PIL import error)")
|
||||
except Exception as e:
|
||||
pass
|
||||
print(f"ERROR: Texture generation failed: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
# Create a visible error pattern instead of black
|
||||
error_pattern = [1.0, 0.0, 1.0, 1.0] # Magenta color for general errors
|
||||
total_pixels = width * height
|
||||
blender_img.pixels[:] = error_pattern * total_pixels
|
||||
print(f"DEBUG: Magenta error texture created (general error)")
|
||||
|
||||
print(f"[TTG DEBUG] Step 3: Packing image...")
|
||||
blender_img.pack()
|
||||
print(f"[TTG DEBUG] Step 3: Image packing completed")
|
||||
|
||||
# Generate normal map if enabled
|
||||
normal_map_img = None
|
||||
if props.generate_normal_map:
|
||||
print(f"[TTG DEBUG] Step 4: Normal map generation enabled, starting...")
|
||||
from ..core.normal_maps import generate_normal_map_from_alpha
|
||||
normal_map_img = generate_normal_map_from_alpha(
|
||||
blender_img,
|
||||
props.normal_map_strength,
|
||||
props.normal_map_blur_radius,
|
||||
props.normal_map_invert
|
||||
)
|
||||
print(f"[TTG DEBUG] Step 4: Normal map generation completed")
|
||||
pass
|
||||
try:
|
||||
pass
|
||||
from ..core.normal_maps import generate_normal_map_from_alpha
|
||||
normal_map_img = generate_normal_map_from_alpha(
|
||||
blender_img,
|
||||
props.normal_map_strength,
|
||||
props.normal_map_blur_radius,
|
||||
props.normal_map_invert
|
||||
)
|
||||
except ImportError:
|
||||
pass
|
||||
normal_map_img = None
|
||||
else:
|
||||
print(f"[TTG DEBUG] Step 4: Normal map generation disabled, skipping")
|
||||
pass
|
||||
print("Normal map generation disabled, skipping")
|
||||
|
||||
print(f"[TTG DEBUG] All steps completed successfully")
|
||||
return blender_img, normal_map_img
|
||||
|
||||
except Exception as e:
|
||||
print(f"[TTG ERROR] Failed to generate texture image: {e}")
|
||||
pass
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return None, None
|
||||
|
||||
def generate_preview(props, preview_width=512, preview_height=512):
|
||||
pass
|
||||
"""
|
||||
Generate a preview version of the texture at lower resolution.
|
||||
|
||||
@@ -272,20 +317,20 @@ def generate_preview(props, preview_width=512, preview_height=512):
|
||||
Blender image object or None on error
|
||||
"""
|
||||
try:
|
||||
print(f"[TTG DEBUG] Generating preview at {preview_width}x{preview_height}px")
|
||||
pass
|
||||
|
||||
# Generate at preview resolution
|
||||
result = generate_texture_image(props, preview_width, preview_height)
|
||||
if result and result[0]:
|
||||
pass
|
||||
preview_img = result[0]
|
||||
print(f"[TTG DEBUG] Preview generation completed successfully")
|
||||
return preview_img
|
||||
else:
|
||||
print(f"[TTG ERROR] Preview generation failed")
|
||||
pass
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"[TTG ERROR] Failed to generate preview: {e}")
|
||||
pass
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user