File: openctm_export.py

package info (click to toggle)
openctm 1.0.3%2Bdfsg1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,704 kB
  • sloc: ansic: 9,241; cpp: 5,199; python: 735; makefile: 29
file content (332 lines) | stat: -rw-r--r-- 10,368 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#!BPY

"""
Name: 'OpenCTM (*.ctm)...'
Blender: 248
Group: 'Export'
Tooltip: 'Export active object to OpenCTM (compressed) format'
"""

import bpy
import Blender
from Blender import Mesh, Scene, Window, sys, Image, Draw
import BPyMesh
import ctypes
from ctypes import *
from ctypes.util import find_library
import os


__author__ = "Marcus Geelnard"
__version__ = "0.4"
__bpydoc__ = """\
This script exports OpenCTM files from Blender. It supports normals,
colours, and UV coordinates per vertex. Only one mesh can be exported
at a time.
"""

# Copyright (C) 2009-2010: Marcus Geelnard
#
# This program is released to the public domain.
#
# Portions of this code are taken from ply_export.py in Blender
# 2.48.
#
# The script uses the OpenCTM shared library (.so, .dll, etc). If no
# such library can be found, the script will exit with an error
# message.
#
# v0.4, 2009-09-14
#    - Updated to OpenCTM API version 0.8 (texture maps are now called UV maps)
#
# v0.3, 2009-08-09
#    - Changed vertex color attribute name to "Color"
#
# v0.2, 2009-06-30
#    - Added precision settings for MG2 export
#    - Added some error checking
#
# v0.1, 2009-05-31
#    - First test version with an alpha version of the OpenCTM API
#


def file_callback(filename):
	
	if not filename.lower().endswith('.ctm'):
		filename += '.ctm'

	# Get object mesh from the selected object
	scn = bpy.data.scenes.active
	ob = scn.objects.active
	if not ob:
		Blender.Draw.PupMenu('Error%t|Select 1 active object')
		return
	mesh = BPyMesh.getMeshFromObject(ob, None, False, False, scn)
	if not mesh:
		Blender.Draw.PupMenu('Error%t|Could not get mesh data from active object')
		return

	# Check which mesh properties are present...
	hasVertexUV = mesh.vertexUV or mesh.faceUV
	hasVertexColors = mesh.vertexColors

	# Show a GUI for the export settings
	pupBlock = []
	EXPORT_APPLY_MODIFIERS = Draw.Create(1)
	pupBlock.append(('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data.'))
	EXPORT_NORMALS = Draw.Create(1)
	pupBlock.append(('Normals', EXPORT_NORMALS, 'Export vertex normal data.'))
	if hasVertexUV:
		EXPORT_UV = Draw.Create(1)
		pupBlock.append(('UVs', EXPORT_UV, 'Export texface UV coords.'))
	if hasVertexColors:
		EXPORT_COLORS = Draw.Create(1)
		pupBlock.append(('Colors', EXPORT_COLORS, 'Export vertex Colors.'))
	EXPORT_MG2 = Draw.Create(0)
	pupBlock.append(('Fixed Point', EXPORT_MG2, 'Use limited precision algorithm (MG2 method = better compression).'))
	if not Draw.PupBlock('Export...', pupBlock):
		return

	# Adjust export settings according to GUI selections
	EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val
	EXPORT_NORMALS = EXPORT_NORMALS.val
	if hasVertexUV:
		EXPORT_UV = EXPORT_UV.val
	else:
		EXPORT_UV = False
	if hasVertexColors:
		EXPORT_COLORS = EXPORT_COLORS.val
	else:
		EXPORT_COLORS = False
	EXPORT_MG2 = EXPORT_MG2.val

	# If the user wants to export MG2, then show another GUI...
	if EXPORT_MG2:
		pupBlock = []
		EXPORT_VPREC = Draw.Create(0.01)
		pupBlock.append(('Vertex', EXPORT_VPREC, 0.0001, 1.0, 'Relative vertex precision (fixed point).'))
		if EXPORT_NORMALS:
			EXPORT_NPREC = Draw.Create(1.0/256.0)
			pupBlock.append(('Normal', EXPORT_NPREC, 0.0001, 1.0, 'Normal precision (fixed point).'))
		if EXPORT_UV:
			EXPORT_UVPREC = Draw.Create(1.0/1024.0)
			pupBlock.append(('UV', EXPORT_UVPREC, 0.0001, 1.0, 'UV precision (fixed point).'))
		if EXPORT_COLORS:
			EXPORT_CPREC = Draw.Create(1.0/256.0)
			pupBlock.append(('Color', EXPORT_CPREC, 0.0001, 1.0, 'Color precision (fixed point).'))
		if not Draw.PupBlock('Fixed point precision...', pupBlock):
			return

	# Adjust export settings according to GUI selections
	if EXPORT_MG2:
		EXPORT_VPREC = EXPORT_VPREC.val
	else:
		EXPORT_VPREC = 0.1
	if EXPORT_MG2 and EXPORT_NORMALS:
		EXPORT_NPREC = EXPORT_NPREC.val
	else:
		EXPORT_NPREC = 0.1
	if EXPORT_MG2 and EXPORT_UV:
		EXPORT_UVPREC = EXPORT_UVPREC.val
	else:
		EXPORT_UVPREC = 0.1
	if EXPORT_MG2 and EXPORT_COLORS:
		EXPORT_CPREC = EXPORT_CPREC.val
	else:
		EXPORT_CPREC = 0.1

	is_editmode = Blender.Window.EditMode()
	if is_editmode:
		Blender.Window.EditMode(0, '', 0)
	Window.WaitCursor(1)
	try:
		# Get the mesh, again, if we wanted modifiers (from GUI selection)
		if EXPORT_APPLY_MODIFIERS:
			mesh = BPyMesh.getMeshFromObject(ob, None, EXPORT_APPLY_MODIFIERS, False, scn)
			if not mesh:
				Blender.Draw.PupMenu('Error%t|Could not get mesh data from active object')
				return
			mesh.transform(ob.matrixWorld, True)

		# Count triangles (quads count as two triangles)
		triangleCount = 0
		for f in mesh.faces:
			if len(f.v) == 4:
				triangleCount += 2
			else:
				triangleCount += 1

		# Extract indices from the Blender mesh (quads are split into two triangles)
		pindices = cast((c_int * 3 * triangleCount)(), POINTER(c_int))
		i = 0
		for f in mesh.faces:
			pindices[i] = c_int(f.v[0].index)
			pindices[i + 1] = c_int(f.v[1].index)
			pindices[i + 2] = c_int(f.v[2].index)
			i += 3
			if len(f.v) == 4:
				pindices[i] = c_int(f.v[0].index)
				pindices[i + 1] = c_int(f.v[2].index)
				pindices[i + 2] = c_int(f.v[3].index)
				i += 3

		# Extract vertex array from the Blender mesh
		vertexCount = len(mesh.verts)
		pvertices = cast((c_float * 3 * vertexCount)(), POINTER(c_float))
		i = 0
		for v in mesh.verts:
			pvertices[i] = c_float(v.co.x)
			pvertices[i + 1] = c_float(v.co.y)
			pvertices[i + 2] = c_float(v.co.z)
			i += 3

		# Extract normals
		if EXPORT_NORMALS:
			pnormals = cast((c_float * 3 * vertexCount)(), POINTER(c_float))
			i = 0
			for v in mesh.verts:
				pnormals[i] = c_float(v.no.x)
				pnormals[i + 1] = c_float(v.no.y)
				pnormals[i + 2] = c_float(v.no.z)
				i += 3
		else:
			pnormals = POINTER(c_float)()

		# Extract UVs
		if EXPORT_UV:
			ptexCoords = cast((c_float * 2 * vertexCount)(), POINTER(c_float))
			if mesh.faceUV:
				for f in mesh.faces:
					for j, v in enumerate(f.v):
						k = v.index
						if k < vertexCount:
							uv = f.uv[j]
							ptexCoords[k * 2] = uv[0]
							ptexCoords[k * 2 + 1] = uv[1]
			else:
				i = 0
				for v in mesh.verts:
					ptexCoords[i] = c_float(v.uvco[0])
					ptexCoords[i + 1] = c_float(v.uvco[1])
					i += 2
		else:
			ptexCoords = POINTER(c_float)()

		# Extract colors
		if EXPORT_COLORS:
			pcolors = cast((c_float * 4 * vertexCount)(), POINTER(c_float))
			for f in mesh.faces:
				for j, v in enumerate(f.v):
					k = v.index
					if k < vertexCount:
						col = f.col[j]
						pcolors[k * 4] = col.r / 255.0
						pcolors[k * 4 + 1] = col.g / 255.0
						pcolors[k * 4 + 2] = col.b / 255.0
						pcolors[k * 4 + 3] = 1.0
		else:
			pcolors = POINTER(c_float)()

		# Load the OpenCTM shared library
		if os.name == 'nt':
			libHDL = WinDLL('openctm.dll')
		else:
			libName = find_library('openctm')
			if not libName:
				Blender.Draw.PupMenu('Could not find the OpenCTM shared library')
				return
			libHDL = CDLL(libName)
		if not libHDL:
			Blender.Draw.PupMenu('Could not open the OpenCTM shared library')
			return

		# Get all the functions from the shared library that we need
		ctmNewContext = libHDL.ctmNewContext
		ctmNewContext.argtypes = [c_int]
		ctmNewContext.restype = c_void_p
		ctmFreeContext = libHDL.ctmFreeContext
		ctmFreeContext.argtypes = [c_void_p]
		ctmGetError = libHDL.ctmGetError
		ctmGetError.argtypes = [c_void_p]
		ctmGetError.restype = c_int
		ctmErrorString = libHDL.ctmErrorString
		ctmErrorString.argtypes = [c_int]
		ctmErrorString.restype = c_char_p
		ctmFileComment = libHDL.ctmFileComment
		ctmFileComment.argtypes = [c_void_p, c_char_p]
		ctmDefineMesh = libHDL.ctmDefineMesh
		ctmDefineMesh.argtypes = [c_void_p, POINTER(c_float), c_int, POINTER(c_int), c_int, POINTER(c_float)]
		ctmSave = libHDL.ctmSave
		ctmSave.argtypes = [c_void_p, c_char_p]
		ctmAddUVMap = libHDL.ctmAddUVMap
		ctmAddUVMap.argtypes = [c_void_p, POINTER(c_float), c_char_p, c_char_p]
		ctmAddUVMap.restype = c_int
		ctmAddAttribMap = libHDL.ctmAddAttribMap
		ctmAddAttribMap.argtypes = [c_void_p, POINTER(c_float), c_char_p]
		ctmAddAttribMap.restype = c_int
		ctmCompressionMethod = libHDL.ctmCompressionMethod
		ctmCompressionMethod.argtypes = [c_void_p, c_int]
		ctmVertexPrecisionRel = libHDL.ctmVertexPrecisionRel
		ctmVertexPrecisionRel.argtypes = [c_void_p, c_float]
		ctmNormalPrecision = libHDL.ctmNormalPrecision
		ctmNormalPrecision.argtypes = [c_void_p, c_float]
		ctmUVCoordPrecision = libHDL.ctmUVCoordPrecision
		ctmUVCoordPrecision.argtypes = [c_void_p, c_int, c_float]
		ctmAttribPrecision = libHDL.ctmAttribPrecision
		ctmAttribPrecision.argtypes = [c_void_p, c_int, c_float]

		# Create an OpenCTM context
		ctm = ctmNewContext(0x0102)  # CTM_EXPORT
		try:
			# Set the file comment
			ctmFileComment(ctm, c_char_p('%s - created by Blender %s (www.blender.org)' % (ob.getName(), Blender.Get('version'))))

			# Define the mesh
			ctmDefineMesh(ctm, pvertices, c_int(vertexCount), pindices, c_int(triangleCount), pnormals)

			# Add UV coordinates?
			if EXPORT_UV:
				tm = ctmAddUVMap(ctm, ptexCoords, c_char_p(), c_char_p())
				if EXPORT_MG2:
					ctmUVCoordPrecision(ctm, tm, EXPORT_UVPREC)

			# Add colors?
			if EXPORT_COLORS:
				cm = ctmAddAttribMap(ctm, pcolors, c_char_p('Color'))
				if EXPORT_MG2:
					ctmAttribPrecision(ctm, cm, EXPORT_CPREC)

			# Set compression method
			if EXPORT_MG2:
				ctmCompressionMethod(ctm, 0x0203)  # CTM_METHOD_MG2
				ctmVertexPrecisionRel(ctm, EXPORT_VPREC)
				if EXPORT_NORMALS:
					ctmNormalPrecision(ctm, EXPORT_NPREC)

			else:
				ctmCompressionMethod(ctm, 0x0202)  # CTM_METHOD_MG1

			# Save the file
			ctmSave(ctm, c_char_p(filename))

			# Check for errors
			e = ctmGetError(ctm)
			if e != 0:
				s = ctmErrorString(e)
				Blender.Draw.PupMenu('Error%t|Could not save the file: ' + s)

		finally:
			# Free the OpenCTM context
			ctmFreeContext(ctm)

	finally:
		Window.WaitCursor(0)
		if is_editmode:
			Blender.Window.EditMode(1, '', 0)

def main():
	Blender.Window.FileSelector(file_callback, 'Export OpenCTM', Blender.sys.makename(ext='.ctm'))

if __name__=='__main__':
	main()