2010-02-12 11:34:25 +00:00
|
|
|
# ##### 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,
|
2010-02-12 13:34:04 +00:00
|
|
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2010-02-12 11:34:25 +00:00
|
|
|
#
|
|
|
|
# ##### END GPL LICENSE BLOCK #####
|
|
|
|
|
2011-07-25 05:10:44 +00:00
|
|
|
# <pep8-80 compliant>
|
2010-02-12 11:34:25 +00:00
|
|
|
|
|
|
|
import bpy
|
2011-08-12 06:57:00 +00:00
|
|
|
from bpy.types import Operator
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
from bpy.props import StringProperty
|
2010-03-07 09:23:57 +00:00
|
|
|
|
2010-04-04 14:52:15 +00:00
|
|
|
|
2011-08-12 06:57:00 +00:00
|
|
|
class EditExternally(Operator):
|
2012-07-03 09:02:41 +00:00
|
|
|
"""Edit image in an external application"""
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
bl_idname = "image.external_edit"
|
|
|
|
bl_label = "Image Edit Externally"
|
|
|
|
bl_options = {'REGISTER'}
|
|
|
|
|
2011-07-25 05:10:44 +00:00
|
|
|
filepath = StringProperty(
|
2011-12-11 21:23:29 +00:00
|
|
|
subtype='FILE_PATH',
|
2011-07-25 05:10:44 +00:00
|
|
|
)
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
|
|
|
|
def _editor_guess(self, context):
|
2011-03-11 01:24:16 +00:00
|
|
|
import sys
|
2010-03-07 09:23:57 +00:00
|
|
|
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
image_editor = context.user_preferences.filepaths.image_editor
|
2010-03-07 09:23:57 +00:00
|
|
|
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
# use image editor in the preferences when available.
|
|
|
|
if not image_editor:
|
2011-03-11 01:24:16 +00:00
|
|
|
if sys.platform[:3] == "win":
|
2010-09-07 15:17:42 +00:00
|
|
|
image_editor = ["start"] # not tested!
|
2011-03-11 01:24:16 +00:00
|
|
|
elif sys.platform == "darwin":
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
image_editor = ["open"]
|
|
|
|
else:
|
|
|
|
image_editor = ["gimp"]
|
2010-03-07 09:23:57 +00:00
|
|
|
else:
|
2011-03-11 01:24:16 +00:00
|
|
|
if sys.platform == "darwin":
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
# blender file selector treats .app as a folder
|
|
|
|
# and will include a trailing backslash, so we strip it.
|
|
|
|
image_editor.rstrip('\\')
|
|
|
|
image_editor = ["open", "-a", image_editor]
|
2010-04-12 02:43:17 +00:00
|
|
|
else:
|
|
|
|
image_editor = [image_editor]
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
|
|
|
|
return image_editor
|
|
|
|
|
|
|
|
def execute(self, context):
|
2010-08-03 23:02:18 +00:00
|
|
|
import os
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
import subprocess
|
2011-08-08 03:31:25 +00:00
|
|
|
|
|
|
|
filepath = self.filepath
|
|
|
|
|
|
|
|
if not filepath:
|
|
|
|
self.report({'ERROR'}, "Image path not set")
|
|
|
|
return {'CANCELLED'}
|
|
|
|
|
2012-03-06 21:54:33 +00:00
|
|
|
if not os.path.exists(filepath) or not os.path.isfile(filepath):
|
2011-07-25 05:10:44 +00:00
|
|
|
self.report({'ERROR'},
|
|
|
|
"Image path %r not found, image may be packed or "
|
2011-09-19 14:00:42 +00:00
|
|
|
"unsaved" % filepath)
|
2010-08-03 23:02:18 +00:00
|
|
|
return {'CANCELLED'}
|
|
|
|
|
|
|
|
cmd = self._editor_guess(context) + [filepath]
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
|
2011-03-28 13:44:56 +00:00
|
|
|
try:
|
|
|
|
subprocess.Popen(cmd)
|
|
|
|
except:
|
|
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
2011-07-25 05:10:44 +00:00
|
|
|
self.report({'ERROR'},
|
|
|
|
"Image editor not found, "
|
|
|
|
"please specify in User Preferences > File")
|
|
|
|
|
2011-03-28 13:44:56 +00:00
|
|
|
return {'CANCELLED'}
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
|
|
|
|
return {'FINISHED'}
|
2010-03-07 09:23:57 +00:00
|
|
|
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
def invoke(self, context, event):
|
2011-10-11 04:09:11 +00:00
|
|
|
import os
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
try:
|
2011-10-11 04:09:11 +00:00
|
|
|
image = context.space_data.image
|
|
|
|
except AttributeError:
|
|
|
|
self.report({'ERROR'}, "Context incorrect, image not found")
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
return {'CANCELLED'}
|
|
|
|
|
2012-04-03 12:02:32 +00:00
|
|
|
if image.packed_file:
|
|
|
|
self.report({'ERROR'}, "Image is packed, unpack before editing")
|
|
|
|
return {'CANCELLED'}
|
|
|
|
|
2011-10-11 04:09:11 +00:00
|
|
|
filepath = bpy.path.abspath(image.filepath, library=image.library)
|
|
|
|
|
|
|
|
self.filepath = os.path.normpath(filepath)
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
self.execute(context)
|
2010-04-04 14:52:15 +00:00
|
|
|
|
merge own commits into render branch into trunk since 27560
27562, 27570, 27571, 27574, 27576, 27577, 27579, 27590, 27591, 27594, 27595, 27596, 27599, 27605, 27611, 27612, 27613, 27614, 27623
2010-03-20 16:41:01 +00:00
|
|
|
return {'FINISHED'}
|
2010-03-06 01:40:29 +00:00
|
|
|
|
2010-03-07 02:38:15 +00:00
|
|
|
|
2011-08-12 06:57:00 +00:00
|
|
|
class SaveDirty(Operator):
|
2010-10-15 08:41:58 +00:00
|
|
|
"""Save all modified textures"""
|
2010-02-12 11:34:25 +00:00
|
|
|
bl_idname = "image.save_dirty"
|
|
|
|
bl_label = "Save Dirty"
|
2010-03-01 00:03:51 +00:00
|
|
|
bl_options = {'REGISTER', 'UNDO'}
|
2010-02-12 11:34:25 +00:00
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
unique_paths = set()
|
|
|
|
for image in bpy.data.images:
|
2010-08-18 07:14:10 +00:00
|
|
|
if image.is_dirty:
|
2012-05-04 17:39:37 +00:00
|
|
|
if image.packed_file:
|
|
|
|
if image.library:
|
|
|
|
self.report({'WARNING'},
|
2012-05-15 18:50:51 +00:00
|
|
|
"Packed library image: %r from library %r"
|
|
|
|
" can't be re-packed" %
|
2012-05-04 17:39:37 +00:00
|
|
|
(image.name, image.library.filepath))
|
|
|
|
else:
|
|
|
|
image.pack(as_png=True)
|
2010-02-12 11:34:25 +00:00
|
|
|
else:
|
2012-05-15 18:50:51 +00:00
|
|
|
filepath = bpy.path.abspath(image.filepath,
|
|
|
|
library=image.library)
|
2012-05-04 17:39:37 +00:00
|
|
|
if "\\" not in filepath and "/" not in filepath:
|
|
|
|
self.report({'WARNING'}, "Invalid path: " + filepath)
|
|
|
|
elif filepath in unique_paths:
|
|
|
|
self.report({'WARNING'},
|
|
|
|
"Path used by more then one image: %r" %
|
|
|
|
filepath)
|
|
|
|
else:
|
|
|
|
unique_paths.add(filepath)
|
|
|
|
image.save()
|
2010-02-12 11:34:25 +00:00
|
|
|
return {'FINISHED'}
|
|
|
|
|
2010-02-14 11:21:21 +00:00
|
|
|
|
2011-08-12 06:57:00 +00:00
|
|
|
class ProjectEdit(Operator):
|
2012-02-08 04:37:37 +00:00
|
|
|
"""Edit a snapshot of the view-port in an external image editor"""
|
2010-03-06 21:47:16 +00:00
|
|
|
bl_idname = "image.project_edit"
|
|
|
|
bl_label = "Project Edit"
|
|
|
|
bl_options = {'REGISTER'}
|
2010-03-14 23:26:17 +00:00
|
|
|
|
2010-03-07 09:23:57 +00:00
|
|
|
_proj_hack = [""]
|
2010-03-06 21:47:16 +00:00
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
import os
|
|
|
|
|
2010-09-07 15:17:42 +00:00
|
|
|
EXT = "png" # could be made an option but for now ok
|
2010-03-07 09:23:57 +00:00
|
|
|
|
2010-03-06 21:47:16 +00:00
|
|
|
for image in bpy.data.images:
|
|
|
|
image.tag = True
|
|
|
|
|
2011-10-28 02:10:02 +00:00
|
|
|
# opengl buffer may fail, we can't help this, but best report it.
|
|
|
|
try:
|
2011-11-16 16:38:37 +00:00
|
|
|
bpy.ops.paint.image_from_view()
|
2011-10-28 02:10:02 +00:00
|
|
|
except RuntimeError as err:
|
|
|
|
self.report({'ERROR'}, str(err))
|
2010-09-16 15:54:48 +00:00
|
|
|
return {'CANCELLED'}
|
2010-03-14 23:26:17 +00:00
|
|
|
|
2010-03-06 21:47:16 +00:00
|
|
|
image_new = None
|
|
|
|
for image in bpy.data.images:
|
|
|
|
if not image.tag:
|
|
|
|
image_new = image
|
|
|
|
break
|
2010-03-14 23:26:17 +00:00
|
|
|
|
2010-03-06 21:47:16 +00:00
|
|
|
if not image_new:
|
|
|
|
self.report({'ERROR'}, "Could not make new image")
|
|
|
|
return {'CANCELLED'}
|
2010-03-14 23:26:17 +00:00
|
|
|
|
2010-06-02 17:58:28 +00:00
|
|
|
filepath = os.path.basename(bpy.data.filepath)
|
|
|
|
filepath = os.path.splitext(filepath)[0]
|
2011-07-25 05:10:44 +00:00
|
|
|
# fixes <memory> rubbish, needs checking
|
|
|
|
# filepath = bpy.path.clean_name(filepath)
|
2010-03-06 21:47:16 +00:00
|
|
|
|
2011-07-25 05:10:44 +00:00
|
|
|
if bpy.data.is_saved:
|
|
|
|
filepath = "//" + filepath
|
|
|
|
else:
|
2010-04-07 09:07:06 +00:00
|
|
|
tmpdir = context.user_preferences.filepaths.temporary_directory
|
2010-06-02 17:58:28 +00:00
|
|
|
filepath = os.path.join(tmpdir, "project_edit")
|
2010-03-14 23:26:17 +00:00
|
|
|
|
2010-03-06 21:47:16 +00:00
|
|
|
obj = context.object
|
|
|
|
|
|
|
|
if obj:
|
2010-08-06 01:40:54 +00:00
|
|
|
filepath += "_" + bpy.path.clean_name(obj.name)
|
2010-03-14 23:26:17 +00:00
|
|
|
|
2010-06-02 17:58:28 +00:00
|
|
|
filepath_final = filepath + "." + EXT
|
2010-03-06 21:47:16 +00:00
|
|
|
i = 0
|
|
|
|
|
2010-08-06 01:40:54 +00:00
|
|
|
while os.path.exists(bpy.path.abspath(filepath_final)):
|
2010-06-02 17:58:28 +00:00
|
|
|
filepath_final = filepath + ("%.3d.%s" % (i, EXT))
|
2010-03-06 21:47:16 +00:00
|
|
|
i += 1
|
2010-03-14 23:26:17 +00:00
|
|
|
|
2011-07-20 08:10:01 +00:00
|
|
|
image_new.name = bpy.path.basename(filepath_final)
|
2010-03-07 09:23:57 +00:00
|
|
|
ProjectEdit._proj_hack[0] = image_new.name
|
2010-03-14 23:26:17 +00:00
|
|
|
|
2010-09-07 15:17:42 +00:00
|
|
|
image_new.filepath_raw = filepath_final # TODO, filepath raw is crummy
|
2010-03-07 20:39:27 +00:00
|
|
|
image_new.file_format = 'PNG'
|
2010-03-06 21:47:16 +00:00
|
|
|
image_new.save()
|
2010-03-14 23:26:17 +00:00
|
|
|
|
2011-11-01 23:01:57 +00:00
|
|
|
filepath_final = bpy.path.abspath(filepath_final)
|
|
|
|
|
2011-03-28 13:44:56 +00:00
|
|
|
try:
|
|
|
|
bpy.ops.image.external_edit(filepath=filepath_final)
|
|
|
|
except RuntimeError as re:
|
|
|
|
self.report({'ERROR'}, str(re))
|
2010-03-14 23:26:17 +00:00
|
|
|
|
2010-03-06 21:47:16 +00:00
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
|
|
|
2011-08-12 06:57:00 +00:00
|
|
|
class ProjectApply(Operator):
|
2010-10-15 08:41:58 +00:00
|
|
|
"""Project edited image back onto the object"""
|
2010-03-06 21:47:16 +00:00
|
|
|
bl_idname = "image.project_apply"
|
|
|
|
bl_label = "Project Apply"
|
|
|
|
bl_options = {'REGISTER'}
|
|
|
|
|
|
|
|
def execute(self, context):
|
2010-09-07 15:17:42 +00:00
|
|
|
image_name = ProjectEdit._proj_hack[0] # TODO, deal with this nicer
|
2010-03-06 21:47:16 +00:00
|
|
|
|
|
|
|
try:
|
2012-12-09 14:17:33 +00:00
|
|
|
image = bpy.data.images[image_name, None]
|
2010-03-06 21:47:16 +00:00
|
|
|
except KeyError:
|
2011-03-28 13:44:56 +00:00
|
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
2010-03-06 21:47:16 +00:00
|
|
|
self.report({'ERROR'}, "Could not find image '%s'" % image_name)
|
|
|
|
return {'CANCELLED'}
|
|
|
|
|
|
|
|
image.reload()
|
|
|
|
bpy.ops.paint.project_image(image=image_name)
|
|
|
|
|
|
|
|
return {'FINISHED'}
|