Page Menu
Home
Search
Configure Global Search
Log In
Files
F23293
import_ldraw.py
Public
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Authored By
kevin loddewykx (mageoftheforest)
Nov 13 2013, 5:11 PM
Size
15 KB
Subscribers
•
samuel galemiri (samgalala)
import_ldraw.py
View Options
import
os
import
bpy
import
bmesh
import
io
# TODO: add support for, CHROME, METAL, RUBBER, .... (Need material artist)
# TODO: add edge rendering, 2 options in import menu: add edges, add optional edges (Maybe do it myself, otherwise ask help, if possible)
# FIXME: blender will transform color values, to his color space, maybe better result (Ask on forum)
colorsDict
=
{}
cursor
=
bpy
.
context
.
scene
.
cursor_location
class
ColorEntry
:
def
__init__
(
self
,
partColor
,
edgeColor
):
self
.
partColor
=
partColor
self
.
edgeColor
=
edgeColor
def
getPartColor
(
self
):
return
self
.
partColor
def
getEdgeColor
(
self
):
return
self
.
edgeColor
class
ColorSheet
:
def
__init__
(
self
,
sheetPath
):
with
open
(
sheetPath
,
'r'
)
as
f
:
for
line
in
f
:
if
(
not
line
.
startswith
(
"0 !COLOUR"
)):
continue
self
.
parse
(
line
)
def
parse
(
self
,
line
):
s
=
line
.
split
()
index
=
3
succeeded
=
False
if
(
s
[
index
]
==
'CODE'
):
index
+=
1
colorIndex
=
int
(
s
[
index
])
index
+=
1
mat
=
bpy
.
data
.
materials
.
new
(
str
(
colorIndex
))
if
(
s
[
index
]
==
'VALUE'
):
index
+=
1
partColor
=
htmlColorToIntRGBArray
(
s
[
index
])
index
+=
1
if
(
s
[
index
]
==
'EDGE'
):
index
+=
1
edgeColor
=
htmlColorToIntRGBArray
(
s
[
index
])
index
+=
1
if
(
index
<
len
(
s
)
and
s
[
index
]
==
'ALPHA'
):
index
+=
1
partColor
[
3
]
=
int
(
s
[
index
])
/
255
edgeColor
[
3
]
=
int
(
s
[
index
])
/
255
index
+=
1
if
(
partColor
[
3
]
<
1
):
mat
.
alpha
=
partColor
[
3
]
mat
.
use_transparency
=
True
if
(
index
<
len
(
s
)):
if
(
s
[
index
]
==
"LUMINANCE"
):
index
+=
1
mat
.
emit
=
int
(
s
[
index
])
/
255
index
+=
1
pass
if
(
index
<
len
(
s
)):
if
(
s
[
index
]
==
"CHROME"
):
pass
elif
(
s
[
index
]
==
"PEARLESCENT"
):
pass
elif
(
s
[
index
]
==
"METAL"
):
pass
elif
(
s
[
index
]
==
"RUBBER"
):
pass
elif
(
s
[
index
]
==
"MATERIAL"
):
index
+=
1
if
(
s
[
index
]
==
"SPECKLE"
):
pass
elif
(
s
[
index
]
==
"GLITTER"
):
pass
else
:
pass
succeeded
=
True
if
(
not
succeeded
):
raise
Exception
(
"Parsing of color config file failed."
)
mat2
=
colorsDict
.
get
(
str
(
colorIndex
)
+
"_EDGE"
)
if
(
mat2
==
None
):
mat2
=
bpy
.
data
.
materials
.
new
(
str
(
colorIndex
)
+
"_EDGE"
)
mat2
.
diffuse_color
=
(
edgeColor
[
0
],
edgeColor
[
1
],
edgeColor
[
2
])
colorsDict
[
colorIndex
]
=
ColorEntry
(
mat
,
mat2
)
class
LegoParser
:
def
__init__
(
self
,
modelPath
,
libraryPath
,
removeDoubles
=
False
,
scaleFactor
=
0.1
):
bpy
.
ops
.
object
.
select_all
(
action
=
'DESELECT'
)
self
.
matrices
=
[]
self
.
internalFiles
=
{}
self
.
paths
=
[
None
]
*
2
self
.
groupName
=
[]
self
.
removeDoubles
=
removeDoubles
self
.
scaleFactor
=
scaleFactor
self
.
paths
[
0
]
=
libraryPath
+
os
.
sep
+
"p"
self
.
paths
[
1
]
=
libraryPath
+
os
.
sep
+
"parts"
self
.
parse
(
modelPath
,
colorsDict
[
16
])
bpy
.
ops
.
object
.
origin_set
(
type
=
'ORIGIN_GEOMETRY'
)
def
parse
(
self
,
filePath
,
currentColor
,
object
=
None
,
verts
=
None
,
faces
=
None
,
mats
=
None
,
matsIndex
=
None
):
if
(
filePath
==
"light.dat"
):
lamp_data
=
bpy
.
data
.
lamps
.
new
(
name
=
filePath
,
type
=
"POINT"
)
lamp_object
=
bpy
.
data
.
objects
.
new
(
name
=
filePath
,
object_data
=
lamp_data
)
bpy
.
context
.
scene
.
objects
.
link
(
lamp_object
)
lamp_object
.
location
=
self
.
toOriginal
((
0
,
0
,
0
))
bpy
.
context
.
scene
.
objects
.
active
=
lamp_object
for
groupName
in
self
.
groupName
:
bpy
.
ops
.
object
.
group_link
(
group
=
groupName
)
return
file
,
primitive
=
self
.
findFile
(
filePath
)
if
(
not
primitive
):
mesh
=
bpy
.
data
.
meshes
.
new
(
os
.
path
.
basename
(
filePath
))
object
=
bpy
.
data
.
objects
.
new
(
os
.
path
.
basename
(
filePath
),
mesh
)
verts
=
[]
faces
=
[]
mats
=
[]
matsIndex
=
[]
if
(
file
==
None
):
if
filePath
in
self
.
internalFiles
:
name
=
bpy
.
data
.
groups
.
new
(
filePath
)
.
name
self
.
groupName
.
append
(
name
)
self
.
parseBrickFromBuffer
(
self
.
internalFiles
[
filePath
],
currentColor
,
object
,
verts
,
faces
,
mats
,
matsIndex
)
self
.
groupName
.
remove
(
name
)
else
:
raise
Exception
(
"A file hasn't been found, "
+
filePath
)
else
:
self
.
parseBrickFromFile
(
file
,
currentColor
,
object
,
verts
,
faces
,
mats
,
matsIndex
)
if
(
not
primitive
and
len
(
verts
)
!=
0
):
bpy
.
context
.
scene
.
objects
.
link
(
object
)
mesh
.
from_pydata
(
verts
,
[],
faces
)
mesh
.
update
()
counter
=
0
bpy
.
context
.
scene
.
objects
.
active
=
object
object
.
select
=
True
bpy
.
ops
.
object
.
mode_set
(
mode
=
'EDIT'
)
bm
=
bmesh
.
from_edit_mesh
(
mesh
)
for
f
in
bm
.
faces
:
f
.
material_index
=
matsIndex
[
counter
]
counter
+=
1
if
(
self
.
removeDoubles
):
bpy
.
ops
.
mesh
.
remove_doubles
()
bpy
.
ops
.
object
.
mode_set
(
mode
=
'OBJECT'
)
for
groupName
in
self
.
groupName
:
bpy
.
ops
.
object
.
group_link
(
group
=
groupName
)
def
findFile
(
self
,
filePath
):
if
(
os
.
sep
==
"/"
):
filePath
=
filePath
.
replace
(
"
\\
"
,
"/"
)
if
(
os
.
path
.
isfile
(
filePath
)):
return
(
filePath
,
False
)
for
path
in
self
.
paths
:
file
=
path
+
os
.
sep
+
filePath
if
(
os
.
path
.
isfile
(
file
)):
if
(
self
.
paths
[
0
]
==
path
or
filePath
[:
2
]
==
"s"
+
os
.
sep
):
return
(
file
,
True
)
else
:
return
(
file
,
False
)
return
None
,
None
def
parseBrickFromBuffer
(
self
,
file
,
currentColor
,
object
,
verts
,
faces
,
mats
,
matsIndex
):
for
line
in
file
.
splitlines
():
line
=
line
.
strip
()
if
(
line
==
""
):
continue
data
=
line
.
split
()
if
(
data
[
0
]
!=
"0"
):
self
.
parseMesh
(
data
,
currentColor
,
object
,
verts
,
faces
,
mats
,
matsIndex
)
def
parseBrickFromFile
(
self
,
file
,
currentColor
,
object
,
verts
,
faces
,
mats
,
matsIndex
):
with
open
(
file
,
'r'
)
as
f
:
for
line
in
f
:
line
=
line
.
strip
()
if
(
line
==
""
):
continue
data
=
line
.
split
()
if
(
len
(
data
)
>
2
and
data
[
0
]
==
"0"
and
data
[
1
]
==
"FILE"
):
headFile
=
self
.
parseFile
(
file
)
self
.
parse
(
headFile
,
currentColor
)
break
elif
(
data
[
0
]
!=
"0"
):
if
(
len
(
self
.
groupName
)
==
0
):
name
=
bpy
.
data
.
groups
.
new
(
"MAIN"
)
.
name
self
.
groupName
.
append
(
name
)
self
.
parseMesh
(
data
,
currentColor
,
object
,
verts
,
faces
,
mats
,
matsIndex
)
def
parseFile
(
self
,
file
):
headFileName
=
None
currentFileName
=
None
currentFileContent
=
""
with
open
(
file
,
'r'
)
as
f
:
for
line
in
f
:
if
(
line
==
""
):
continue
data
=
line
.
split
(
None
,
2
)
if
(
len
(
data
)
==
3
and
data
[
0
]
==
"0"
and
data
[
1
]
==
"FILE"
):
if
(
currentFileName
!=
None
):
self
.
internalFiles
[
currentFileName
]
=
currentFileContent
currentFileContent
=
""
if
(
headFileName
==
None
):
headFileName
=
os
.
path
.
basename
(
data
[
2
])
currentFileName
=
os
.
path
.
basename
(
data
[
2
])
else
:
currentFileName
=
data
[
2
]
.
strip
()
else
:
currentFileContent
+=
line
self
.
internalFiles
[
currentFileName
]
=
currentFileContent
return
headFileName
def
parseMesh
(
self
,
data
,
currentColor
,
object
,
verts
,
faces
,
mats
,
matsIndex
):
colorIndex
=
int
(
data
[
1
])
if
(
colorIndex
==
16
or
colorIndex
==
24
):
colorEntry
=
currentColor
if
(
colorIndex
==
24
):
color
=
colorEntry
.
getEdgeColor
()
else
:
color
=
colorEntry
.
getPartColor
()
else
:
colorEntry
=
colorsDict
.
get
(
colorIndex
)
if
(
colorEntry
==
None
):
a
=
((
colorIndex
>>
24
)
&
0xFF
)
if
(
a
==
2
or
a
==
3
):
r
=
((
colorIndex
>>
16
)
&
0xFF
)
/
255
g
=
((
colorIndex
>>
8
)
&
0xFF
)
/
255
b
=
(
colorIndex
&
0xFF
)
/
255
mat
=
bpy
.
data
.
materials
.
new
(
str
(
colorIndex
))
mat
.
diffuse_color
=
(
r
,
g
,
b
)
if
(
a
==
3
):
mat
.
alpha
=
0.5
mat
.
use_transparency
=
True
colorEntry
=
ColorEntry
(
mat
,
mat
)
colorsDict
[
colorIndex
]
=
colorEntry
elif
(
a
==
4
or
a
==
6
):
mat
=
self
.
createNodeSetup
(
colorIndex
,
a
)
colorEntry
=
ColorEntry
(
mat
,
mat
)
colorsDict
[
colorIndex
]
=
colorEntry
else
:
print
(
"Color not found, fallback to main color"
)
colorEntry
=
colorsDict
[
16
]
color
=
colorEntry
.
getPartColor
()
if
(
data
[
0
]
==
"1"
):
mm
=
(
float
(
data
[
2
]),
float
(
data
[
3
]),
float
(
data
[
4
]),
float
(
data
[
5
]),
float
(
data
[
6
]),
float
(
data
[
7
]),
float
(
data
[
8
]),
float
(
data
[
9
]),
float
(
data
[
10
]),
float
(
data
[
11
]),
float
(
data
[
12
]),
float
(
data
[
13
]))
self
.
matrices
.
append
(
mm
)
self
.
parse
(
data
[
14
],
colorEntry
,
object
,
verts
,
faces
,
mats
,
matsIndex
)
self
.
matrices
.
remove
(
mm
)
elif
(
data
[
0
]
==
"2"
):
# line
pass
elif
(
data
[
0
]
==
"3"
or
data
[
0
]
==
"4"
):
if
color
in
mats
:
matsIndex
.
append
(
mats
.
index
(
color
))
else
:
object
.
data
.
materials
.
append
(
color
)
mats
.
append
(
color
)
matsIndex
.
append
(
len
(
mats
)
-
1
)
length
=
len
(
verts
)
if
(
data
[
0
]
==
"3"
):
p1
=
self
.
toOriginal
((
float
(
data
[
2
]),
float
(
data
[
3
]),
float
(
data
[
4
])))
p2
=
self
.
toOriginal
((
float
(
data
[
5
]),
float
(
data
[
6
]),
float
(
data
[
7
])))
p3
=
self
.
toOriginal
((
float
(
data
[
8
]),
float
(
data
[
9
]),
float
(
data
[
10
])))
verts
.
extend
((
p1
,
p2
,
p3
))
faces
.
append
((
length
,
length
+
1
,
length
+
2
))
else
:
p1
=
self
.
toOriginal
((
float
(
data
[
2
]),
float
(
data
[
3
]),
float
(
data
[
4
])))
p2
=
self
.
toOriginal
((
float
(
data
[
5
]),
float
(
data
[
6
]),
float
(
data
[
7
])))
p3
=
self
.
toOriginal
((
float
(
data
[
8
]),
float
(
data
[
9
]),
float
(
data
[
10
])))
p4
=
self
.
toOriginal
((
float
(
data
[
11
]),
float
(
data
[
12
]),
float
(
data
[
13
])))
verts
.
extend
((
p1
,
p2
,
p3
,
p4
))
faces
.
append
((
length
,
length
+
1
,
length
+
2
,
length
+
3
))
elif
(
data
[
0
]
==
"5"
):
# optional line
pass
def
toOriginal
(
self
,
coordinate
):
x
=
coordinate
[
0
]
y
=
coordinate
[
1
]
z
=
coordinate
[
2
]
if
(
len
(
self
.
matrices
)
!=
0
):
for
matrix
in
reversed
(
self
.
matrices
):
tempX
=
matrix
[
3
]
*
x
+
matrix
[
4
]
*
y
+
matrix
[
5
]
*
z
+
matrix
[
0
]
tempY
=
matrix
[
6
]
*
x
+
matrix
[
7
]
*
y
+
matrix
[
8
]
*
z
+
matrix
[
1
]
tempZ
=
matrix
[
9
]
*
x
+
matrix
[
10
]
*
y
+
matrix
[
11
]
*
z
+
matrix
[
2
]
x
=
tempX
y
=
tempY
z
=
tempZ
return
(
x
*
self
.
scaleFactor
+
cursor
[
0
],
z
*
self
.
scaleFactor
+
cursor
[
1
],
-
y
*
self
.
scaleFactor
+
cursor
[
2
])
def
createNodeSetup
(
self
,
colorIndex
,
type
):
r1
=
((
colorIndex
>>
20
)
&
0xF
)
*
17
/
255
g1
=
((
colorIndex
>>
16
)
&
0xF
)
*
17
/
255
b1
=
((
colorIndex
>>
12
)
&
0xF
)
*
17
/
255
r2
=
((
colorIndex
>>
8
)
&
0xF
)
*
17
/
255
g2
=
((
colorIndex
>>
4
)
&
0xF
)
*
17
/
255
b2
=
(
colorIndex
&
0xF
)
*
17
/
255
mat
=
bpy
.
data
.
materials
.
new
(
str
(
colorIndex
))
mat
.
use_nodes
=
True
if
(
type
==
6
):
alpha
=
0.5
mat
.
use_transparency
=
True
else
:
alpha
=
1
tree
=
mat
.
node_tree
tree
.
nodes
.
clear
()
color1_n
=
tree
.
nodes
.
new
(
'ShaderNodeRGB'
)
color1_n
.
location
=
0
,
220
color1_n
.
outputs
[
0
]
.
default_value
=
(
r1
,
g1
,
b1
,
1
)
color2_n
=
tree
.
nodes
.
new
(
'ShaderNodeRGB'
)
color2_n
.
location
=
0
,
0
color2_n
.
outputs
[
0
]
.
default_value
=
(
r2
,
g2
,
b2
,
1
)
mix_n
=
tree
.
nodes
.
new
(
'ShaderNodeMixRGB'
)
mix_n
.
location
=
220
,
100
mat2
=
bpy
.
data
.
materials
.
new
(
str
(
colorIndex
)
+
'_node'
)
mat2
.
alpha
=
alpha
mat_n
=
tree
.
nodes
.
new
(
'ShaderNodeMaterial'
)
mat_n
.
location
=
440
,
0
mat_n
.
material
=
mat2
output_n
=
tree
.
nodes
.
new
(
'ShaderNodeOutput'
)
output_n
.
location
=
660
,
100
tree
.
links
.
new
(
color1_n
.
outputs
[
0
],
mix_n
.
inputs
[
1
])
tree
.
links
.
new
(
color2_n
.
outputs
[
0
],
mix_n
.
inputs
[
2
])
tree
.
links
.
new
(
mix_n
.
outputs
[
0
],
mat_n
.
inputs
[
0
])
tree
.
links
.
new
(
mat_n
.
outputs
[
0
],
output_n
.
inputs
[
0
])
tree
.
links
.
new
(
mat_n
.
outputs
[
1
],
output_n
.
inputs
[
1
])
return
mat
def
htmlColorToIntRGBArray
(
str
):
if
(
len
(
str
)
!=
7
or
not
str
.
startswith
(
'#'
)):
raise
Exception
(
"Parsing of color config file failed."
)
rgba
=
[
None
]
*
4
rgba
[
0
]
=
int
(
str
[
1
:
3
],
16
)
/
255
rgba
[
1
]
=
int
(
str
[
3
:
5
],
16
)
/
255
rgba
[
2
]
=
int
(
str
[
5
:
7
],
16
)
/
255
rgba
[
3
]
=
1
return
rgba
def
load
(
filepath
,
ldconfig
,
library
,
global_scale
,
use_remove_doubles
):
if
(
len
(
colorsDict
)
==
0
):
ColorSheet
(
ldconfig
)
LegoParser
(
filepath
,
library
,
use_remove_doubles
,
global_scale
)
return
{
'FINISHED'
}
File Metadata
Details
Mime Type
text/x-c++
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
3e/c1/1a5f659de1b325afeee90d08c501
Event Timeline
•
samuel galemiri (samgalala)
added a subscriber:
•
samuel galemiri (samgalala)
.
Nov 28 2013, 5:55 PM
•
samuel galemiri (samgalala)
added a comment.
Nov 28 2013, 5:55 PM
Comment Actions
HI
Log In to Comment