1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
20 "name": "ANT Landscape",
21 "author": "Jimmy Hazevoet",
23 "blender": (2, 61, 0),
24 "location": "View3D > Add > Mesh",
25 "description": "Add a landscape primitive",
26 "warning": "", # used for warning icon and text in addons panel
27 "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
28 "Scripts/Add_Mesh/ANT_Landscape",
29 "tracker_url": "https://developer.blender.org/T23130",
30 "category": "Add Mesh"}
33 Another Noise Tool: Landscape mesh generator
36 Mesh update: Turn this on for interactive mesh update.
37 Sphere: Generate sphere or a grid mesh. (Turn height falloff off for sphere mesh)
38 Smooth: Generate smooth shaded mesh.
39 Subdivision: Number of mesh subdivisions, higher numbers gives more detail but also slows down the script.
40 Mesh size: X,Y size of the grid mesh (in blender units).
42 NOISE OPTIONS: ( Most of these options are the same as in blender textures. )
43 Random seed: Use this to randomise the origin of the noise function.
44 Noise size: Size of the noise.
45 Noise type: Available noise types: multiFractal, ridgedMFractal, hybridMFractal, heteroTerrain, Turbulence, Distorted Noise, Cellnoise, Shattered_hTerrain, Marble
46 Noise basis: Blender, Perlin, NewPerlin, Voronoi_F1, Voronoi_F2, Voronoi_F3, Voronoi_F4, Voronoi_F2-F1, Voronoi Crackle, Cellnoise
47 VLNoise basis: Blender, Perlin, NewPerlin, Voronoi_F1, Voronoi_F2, Voronoi_F3, Voronoi_F4, Voronoi_F2-F1, Voronoi Crackle, Cellnoise
48 Distortion: Distortion amount.
49 Hard: Hard/Soft turbulence noise.
50 Depth: Noise depth, number of frequencies in the fBm.
51 Dimension: Musgrave: Fractal dimension of the roughest areas.
52 Lacunarity: Musgrave: Gap between successive frequencies.
53 Offset: Musgrave: Raises the terrain from sea level.
54 Gain: Musgrave: Scale factor.
55 Marble Bias: Sin, Tri, Saw
56 Marble Sharpnes: Soft, Sharp, Sharper
57 Marble Shape: Shape of the marble function: Default, Ring, Swirl, X, Y
60 Invert: Invert terrain height.
61 Height: Scale terrain height.
62 Offset: Terrain height offset.
63 Falloff: Terrain height falloff: Type 1, Type 2, X, Y
64 Sealevel: Flattens terrain below sealevel.
65 Platlevel: Flattens terrain above plateau level.
66 Strata: Strata amount, number of strata/terrace layers.
67 Strata type: Strata types, Smooth, Sharp-sub, Sharp-add
72 from bpy
.props
import *
73 from mathutils
import *
74 from mathutils
.noise
import *
78 # Create a new mesh (object) from verts/edges/faces.
79 # verts/edges/faces ... List of vertices/edges/faces for the
80 # new mesh (as used in from_pydata).
81 # name ... Name of the new mesh (& object).
82 def create_mesh_object(context
, verts
, edges
, faces
, name
):
84 mesh
= bpy
.data
.meshes
.new(name
)
86 # Make a mesh from a list of verts/edges/faces.
87 mesh
.from_pydata(verts
, edges
, faces
)
89 # Update mesh geometry after adding stuff.
92 from bpy_extras
import object_utils
93 return object_utils
.object_data_add(context
, mesh
, operator
=None)
95 # A very simple "bridge" tool.
96 # Connects two equally long vertex rows with faces.
97 # Returns a list of the new faces (list of lists)
99 # vertIdx1 ... First vertex list (list of vertex indices).
100 # vertIdx2 ... Second vertex list (list of vertex indices).
101 # closed ... Creates a loop (first & last are closed).
102 # flipped ... Invert the normal of the face(s).
104 # Note: You can set vertIdx1 to a single vertex index to create
105 # a fan/star of faces.
106 # Note: If both vertex idx list are the same length they have
107 # to have at least 2 vertices.
108 def createFaces(vertIdx1
, vertIdx2
, closed
=False, flipped
=False):
111 if not vertIdx1
or not vertIdx2
:
114 if len(vertIdx1
) < 2 and len(vertIdx2
) < 2:
118 if (len(vertIdx1
) != len(vertIdx2
)):
119 if (len(vertIdx1
) == 1 and len(vertIdx2
) > 1):
124 total
= len(vertIdx2
)
127 # Bridge the start with the end.
134 face
.append(vertIdx1
[total
- 1])
138 face
= [vertIdx2
[0], vertIdx1
[0]]
140 face
.append(vertIdx1
[total
- 1])
141 face
.append(vertIdx2
[total
- 1])
144 # Bridge the rest of the faces.
145 for num
in range(total
- 1):
148 face
= [vertIdx2
[num
], vertIdx1
[0], vertIdx2
[num
+ 1]]
150 face
= [vertIdx2
[num
], vertIdx1
[num
],
151 vertIdx1
[num
+ 1], vertIdx2
[num
+ 1]]
155 face
= [vertIdx1
[0], vertIdx2
[num
], vertIdx2
[num
+ 1]]
157 face
= [vertIdx1
[num
], vertIdx2
[num
],
158 vertIdx2
[num
+ 1], vertIdx1
[num
+ 1]]
164 ###------------------------------------------------------------
165 ###------------------------------------------------------------
166 # some functions for marble_noise
168 return 0.5 + 0.5 * sin(a
)
172 a
= 1 - 2 * abs(floor((a
* (1/b
))+0.5) - (a
*(1/b
)))
189 return sharp(sharp(a
))
191 def shapes(x
,y
,shape
=0):
196 s
= (-cos(x
**2+y
**2)/(x
**2+y
**2+0.5))
201 s
= (( x
*sin( x
*x
+y
*y
) + y
*cos( x
*x
+y
*y
) ) / (x
**2+y
**2+0.5))
206 s
= ((cos( x
*pi
) + cos( y
*pi
))-0.5)
219 def marble_noise(x
,y
,z
, origin
, size
, shape
, bias
, sharpnes
, turb
, depth
, hard
, basis
):
223 s
= shapes(x
,y
,shape
)
228 value
= s
+ turb
* turbulence_vector((x
,y
,z
), depth
, hard
, basis
)[0]
231 value
= tri_bias( value
)
233 value
= saw_bias( value
)
235 value
= sin_bias( value
)
238 value
= sharp( value
)
240 value
= sharper( value
)
242 value
= soft( value
)
246 ###------------------------------------------------------------
249 # shattered_hterrain:
250 def shattered_hterrain( x
,y
,z
, H
, lacunarity
, octaves
, offset
, distort
, basis
):
251 d
= ( turbulence_vector( ( x
, y
, z
), 6, 0, 0 )[0] * 0.5 + 0.5 )*distort
*0.5
252 t1
= ( turbulence_vector( ( x
+d
, y
+d
, z
), 0, 0, 7 )[0] + 0.5 )
253 t2
= ( hetero_terrain(( x
*2, y
*2, z
*2 ), H
, lacunarity
, octaves
, offset
, basis
)*0.5 )
254 return (( t1
*t2
)+t2
*0.5) * 0.5
257 def strata_hterrain( x
,y
,z
, H
, lacunarity
, octaves
, offset
, distort
, basis
):
258 value
= hetero_terrain(( x
, y
, z
), H
, lacunarity
, octaves
, offset
, basis
)*0.5
259 steps
= ( sin( value
*(distort
*5)*pi
) * ( 0.1/(distort
*5)*pi
) )
260 return ( value
* (1.0-0.5) + steps
*0.5 )
262 ###------------------------------------------------------------
264 def landscape_gen(x
,y
,z
,falloffsize
,options
=[0,1.0,1, 0,0,1.0,0,6,1.0,2.0,1.0,2.0,0,0,0, 1.0,0.0,1,0.0,1.0,0,0,0]):
269 ntype
= int( options
[2][0] )
270 nbasis
= int( options
[3][0] )
271 vlbasis
= int( options
[4][0] )
272 distortion
= options
[5]
273 hardnoise
= options
[6]
275 dimension
= options
[8]
276 lacunarity
= options
[9]
279 marblebias
= int( options
[12][0] )
280 marblesharpnes
= int( options
[13][0] )
281 marbleshape
= int( options
[14][0] )
284 heightoffset
= options
[17]
285 falloff
= int( options
[18][0] )
286 sealevel
= options
[19]
287 platlevel
= options
[20]
289 stratatype
= options
[22]
301 origin
= random_unit_vector()
302 origin_x
= ( 0.5 - origin
[0] ) * 1000.0
303 origin_y
= ( 0.5 - origin
[1] ) * 1000.0
304 origin_z
= ( 0.5 - origin
[2] ) * 1000.0
306 # adjust noise size and origin
307 ncoords
= ( x
/ nsize
+ origin_x
, y
/ nsize
+ origin_y
, z
/ nsize
+ origin_z
)
310 if nbasis
== 9: nbasis
= 14 # to get cellnoise basis you must set 14 instead of 9
311 if vlbasis
==9: vlbasis
= 14
313 if ntype
== 0: value
= multi_fractal( ncoords
, dimension
, lacunarity
, depth
, nbasis
) * 0.5
314 elif ntype
== 1: value
= ridged_multi_fractal( ncoords
, dimension
, lacunarity
, depth
, offset
, gain
, nbasis
) * 0.5
315 elif ntype
== 2: value
= hybrid_multi_fractal( ncoords
, dimension
, lacunarity
, depth
, offset
, gain
, nbasis
) * 0.5
316 elif ntype
== 3: value
= hetero_terrain( ncoords
, dimension
, lacunarity
, depth
, offset
, nbasis
) * 0.25
317 elif ntype
== 4: value
= fractal( ncoords
, dimension
, lacunarity
, depth
, nbasis
)
318 elif ntype
== 5: value
= turbulence_vector( ncoords
, depth
, hardnoise
, nbasis
)[0]
319 elif ntype
== 6: value
= variable_lacunarity( ncoords
, distortion
, nbasis
, vlbasis
) + 0.5
320 elif ntype
== 7: value
= marble_noise( x
*2.0/falloffsize
,y
*2.0/falloffsize
,z
*2/falloffsize
, origin
, nsize
, marbleshape
, marblebias
, marblesharpnes
, distortion
, depth
, hardnoise
, nbasis
)
321 elif ntype
== 8: value
= shattered_hterrain( ncoords
[0], ncoords
[1], ncoords
[2], dimension
, lacunarity
, depth
, offset
, distortion
, nbasis
)
322 elif ntype
== 9: value
= strata_hterrain( ncoords
[0], ncoords
[1], ncoords
[2], dimension
, lacunarity
, depth
, offset
, distortion
, nbasis
)
328 value
= (1-value
) * height
+ heightoffset
330 value
= value
* height
+ heightoffset
333 if sphere
== 0: # no edge falloff if spherical
335 fallofftypes
= [ 0, sqrt((x
*x
)**2+(y
*y
)**2), sqrt(x
*x
+y
*y
), sqrt(y
*y
), sqrt(x
*x
) ]
336 dist
= fallofftypes
[ falloff
]
338 radius
= (falloffsize
/2)**2
340 radius
= falloffsize
/2
341 value
= value
- sealevel
344 dist
= ( (dist
) * (dist
) * ( 3-2*(dist
) ) )
345 value
= ( value
- value
* dist
) + sealevel
349 # strata / terrace / layered
351 strata
= strata
/ height
352 if stratatype
== '1':
354 steps
= ( sin( value
*strata
*pi
) * ( 0.1/strata
*pi
) )
355 value
= ( value
* (1.0-0.5) + steps
*0.5 ) * 2.0
356 elif stratatype
== '2':
357 steps
= -abs( sin( value
*(strata
)*pi
) * ( 0.1/(strata
)*pi
) )
358 value
=( value
* (1.0-0.5) + steps
*0.5 ) * 2.0
359 elif stratatype
== '3':
360 steps
= abs( sin( value
*(strata
)*pi
) * ( 0.1/(strata
)*pi
) )
361 value
=( value
* (1.0-0.5) + steps
*0.5 ) * 2.0
366 if ( value
< sealevel
): value
= sealevel
367 if ( value
> platlevel
): value
= platlevel
373 def grid_gen( sub_d
, size_me
, options
):
379 delta
= size_me
/ float(sub_d
- 1)
380 start
= -(size_me
/ 2.0)
382 for row_x
in range(sub_d
):
384 x
= start
+ row_x
* delta
385 for row_y
in range(sub_d
):
386 y
= start
+ row_y
* delta
387 z
= landscape_gen(x
,y
,0.0,size_me
,options
)
389 edgeloop_cur
.append(len(verts
))
390 verts
.append((x
,y
,z
))
392 if len(edgeloop_prev
) > 0:
393 faces_row
= createFaces(edgeloop_prev
, edgeloop_cur
)
394 faces
.extend(faces_row
)
396 edgeloop_prev
= edgeloop_cur
402 def sphere_gen( sub_d
, size_me
, options
):
408 for row_x
in range(sub_d
):
410 for row_y
in range(sub_d
):
411 u
= sin(row_y
*pi
*2/(sub_d
-1)) * cos(-pi
/2+row_x
*pi
/(sub_d
-1)) * size_me
/2
412 v
= cos(row_y
*pi
*2/(sub_d
-1)) * cos(-pi
/2+row_x
*pi
/(sub_d
-1)) * size_me
/2
413 w
= sin(-pi
/2+row_x
*pi
/(sub_d
-1)) * size_me
/2
414 h
= landscape_gen(u
,v
,w
,size_me
,options
) / size_me
415 u
,v
,w
= u
+u
*h
, v
+v
*h
, w
+w
*h
417 edgeloop_cur
.append(len(verts
))
418 verts
.append((u
, v
, w
))
420 if len(edgeloop_prev
) > 0:
421 faces_row
= createFaces(edgeloop_prev
, edgeloop_cur
)
422 faces
.extend(faces_row
)
424 edgeloop_prev
= edgeloop_cur
429 ###------------------------------------------------------------
431 class landscape_add(bpy
.types
.Operator
):
432 """Add a landscape mesh"""
433 bl_idname
= "mesh.landscape_add"
434 bl_label
= "Landscape"
435 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
436 bl_description
= "Add landscape mesh"
439 AutoUpdate
= BoolProperty(name
="Mesh update",
441 description
="Update mesh")
443 SphereMesh
= BoolProperty(name
="Sphere",
445 description
="Generate Sphere mesh")
447 SmoothMesh
= BoolProperty(name
="Smooth",
449 description
="Shade smooth")
451 Subdivision
= IntProperty(name
="Subdivisions",
455 description
="Mesh x y subdivisions")
457 MeshSize
= FloatProperty(name
="Mesh Size",
461 description
="Mesh size")
463 RandomSeed
= IntProperty(name
="Random Seed",
467 description
="Randomize noise origin")
469 NoiseSize
= FloatProperty(name
="Noise Size",
473 description
="Noise size")
476 ("0","multiFractal","multiFractal"),
477 ("1","ridgedMFractal","ridgedMFractal"),
478 ("2","hybridMFractal","hybridMFractal"),
479 ("3","heteroTerrain","heteroTerrain"),
481 ("5","Turbulence","Turbulence"),
482 ("6","Distorted Noise","Distorted Noise"),
483 ("7","Marble","Marble"),
484 ("8","Shattered_hTerrain","Shattered_hTerrain"),
485 ("9","Strata_hTerrain","Strata_hTerrain")]
487 NoiseType
= EnumProperty(name
="Type",
488 description
="Noise type",
492 ("0","Blender","Blender"),
493 ("1","Perlin","Perlin"),
494 ("2","NewPerlin","NewPerlin"),
495 ("3","Voronoi_F1","Voronoi_F1"),
496 ("4","Voronoi_F2","Voronoi_F2"),
497 ("5","Voronoi_F3","Voronoi_F3"),
498 ("6","Voronoi_F4","Voronoi_F4"),
499 ("7","Voronoi_F2-F1","Voronoi_F2-F1"),
500 ("8","Voronoi Crackle","Voronoi Crackle"),
501 ("9","Cellnoise","Cellnoise")]
502 BasisType
= EnumProperty(name
="Basis",
503 description
="Noise basis",
507 ("0","Blender","Blender"),
508 ("1","Perlin","Perlin"),
509 ("2","NewPerlin","NewPerlin"),
510 ("3","Voronoi_F1","Voronoi_F1"),
511 ("4","Voronoi_F2","Voronoi_F2"),
512 ("5","Voronoi_F3","Voronoi_F3"),
513 ("6","Voronoi_F4","Voronoi_F4"),
514 ("7","Voronoi_F2-F1","Voronoi_F2-F1"),
515 ("8","Voronoi Crackle","Voronoi Crackle"),
516 ("9","Cellnoise","Cellnoise")]
517 VLBasisType
= EnumProperty(name
="VLBasis",
518 description
="VLNoise basis",
521 Distortion
= FloatProperty(name
="Distortion",
525 description
="Distortion amount")
527 HardNoise
= BoolProperty(name
="Hard",
529 description
="Hard noise")
531 NoiseDepth
= IntProperty(name
="Depth",
535 description
="Noise Depth - number of frequencies in the fBm")
537 mDimension
= FloatProperty(name
="Dimension",
541 description
="H - fractal dimension of the roughest areas")
543 mLacunarity
= FloatProperty(name
="Lacunarity",
547 description
="Lacunarity - gap between successive frequencies")
549 mOffset
= FloatProperty(name
="Offset",
553 description
="Offset - raises the terrain from sea level")
555 mGain
= FloatProperty(name
="Gain",
559 description
="Gain - scale factor")
565 MarbleBias
= EnumProperty(name
="Bias",
566 description
="Marble bias",
571 ("1","Sharp","Sharp"),
572 ("2","Sharper","Sharper")]
573 MarbleSharp
= EnumProperty(name
="Sharp",
574 description
="Marble sharp",
578 ("0","Default","Default"),
580 ("2","Swirl","Swirl"),
584 MarbleShape
= EnumProperty(name
="Shape",
585 description
="Marble shape",
588 Invert
= BoolProperty(name
="Invert",
590 description
="Invert noise input")
592 Height
= FloatProperty(name
="Height",
596 description
="Height scale")
598 Offset
= FloatProperty(name
="Offset",
602 description
="Height offset")
606 ("1","Type 1","Type 1"),
607 ("2","Type 2","Type 2"),
610 Falloff
= EnumProperty(name
="Falloff",
611 description
="Edge falloff",
615 Sealevel
= FloatProperty(name
="Sealevel",
619 description
="Sealevel")
621 Plateaulevel
= FloatProperty(name
="Plateau",
625 description
="Plateau level")
627 Strata
= FloatProperty(name
="Strata",
631 description
="Strata amount")
635 ("1","Type 1","Type 1"),
636 ("2","Type 2","Type 2"),
637 ("3","Type 3","Type 3")]
638 StrataType
= EnumProperty(name
="Strata",
639 description
="Strata type",
643 ###------------------------------------------------------------
645 def draw(self
, context
):
649 box
.prop(self
, 'AutoUpdate')
650 box
.prop(self
, 'SphereMesh')
651 box
.prop(self
, 'SmoothMesh')
652 box
.prop(self
, 'Subdivision')
653 box
.prop(self
, 'MeshSize')
656 box
.prop(self
, 'NoiseType')
657 if self
.NoiseType
!= '7':
658 box
.prop(self
, 'BasisType')
659 box
.prop(self
, 'RandomSeed')
660 box
.prop(self
, 'NoiseSize')
661 if self
.NoiseType
== '0':
662 box
.prop(self
, 'NoiseDepth')
663 box
.prop(self
, 'mDimension')
664 box
.prop(self
, 'mLacunarity')
665 elif self
.NoiseType
== '1':
666 box
.prop(self
, 'NoiseDepth')
667 box
.prop(self
, 'mDimension')
668 box
.prop(self
, 'mLacunarity')
669 box
.prop(self
, 'mOffset')
670 box
.prop(self
, 'mGain')
671 elif self
.NoiseType
== '2':
672 box
.prop(self
, 'NoiseDepth')
673 box
.prop(self
, 'mDimension')
674 box
.prop(self
, 'mLacunarity')
675 box
.prop(self
, 'mOffset')
676 box
.prop(self
, 'mGain')
677 elif self
.NoiseType
== '3':
678 box
.prop(self
, 'NoiseDepth')
679 box
.prop(self
, 'mDimension')
680 box
.prop(self
, 'mLacunarity')
681 box
.prop(self
, 'mOffset')
682 elif self
.NoiseType
== '4':
683 box
.prop(self
, 'NoiseDepth')
684 box
.prop(self
, 'mDimension')
685 box
.prop(self
, 'mLacunarity')
686 elif self
.NoiseType
== '5':
687 box
.prop(self
, 'NoiseDepth')
688 box
.prop(self
, 'HardNoise')
689 elif self
.NoiseType
== '6':
690 box
.prop(self
, 'VLBasisType')
691 box
.prop(self
, 'Distortion')
692 elif self
.NoiseType
== '7':
693 box
.prop(self
, 'MarbleShape')
694 box
.prop(self
, 'MarbleBias')
695 box
.prop(self
, 'MarbleSharp')
696 box
.prop(self
, 'Distortion')
697 box
.prop(self
, 'NoiseDepth')
698 box
.prop(self
, 'HardNoise')
699 elif self
.NoiseType
== '8':
700 box
.prop(self
, 'NoiseDepth')
701 box
.prop(self
, 'mDimension')
702 box
.prop(self
, 'mLacunarity')
703 box
.prop(self
, 'mOffset')
704 box
.prop(self
, 'Distortion')
705 elif self
.NoiseType
== '9':
706 box
.prop(self
, 'NoiseDepth')
707 box
.prop(self
, 'mDimension')
708 box
.prop(self
, 'mLacunarity')
709 box
.prop(self
, 'mOffset')
710 box
.prop(self
, 'Distortion')
713 box
.prop(self
, 'Invert')
714 box
.prop(self
, 'Height')
715 box
.prop(self
, 'Offset')
716 box
.prop(self
, 'Plateaulevel')
717 box
.prop(self
, 'Sealevel')
718 if self
.SphereMesh
== False:
719 box
.prop(self
, 'Falloff')
720 box
.prop(self
, 'StrataType')
721 if self
.StrataType
!= '0':
722 box
.prop(self
, 'Strata')
724 ###------------------------------------------------------------
726 def execute(self
, context
):
729 if self
.AutoUpdate
!= 0:
732 undo
= bpy
.context
.user_preferences
.edit
.use_global_undo
733 bpy
.context
.user_preferences
.edit
.use_global_undo
= False
735 # deselect all objects when in object mode
736 if bpy
.ops
.object.select_all
.poll():
737 bpy
.ops
.object.select_all(action
='DESELECT')
754 self
.MarbleSharp
, #13
755 self
.MarbleShape
, #14
761 self
.Plateaulevel
, #20
768 if self
.SphereMesh
!=0:
770 verts
, faces
= sphere_gen( self
.Subdivision
, self
.MeshSize
, options
)
773 verts
, faces
= grid_gen( self
.Subdivision
, self
.MeshSize
, options
)
776 obj
= create_mesh_object(context
, verts
, [], faces
, "Landscape")
777 bpy
.ops
.object.mode_set(mode
='EDIT')
778 bpy
.ops
.mesh
.normals_make_consistent(inside
=False)
779 bpy
.ops
.object.mode_set(mode
='OBJECT')
780 # sphere, remove doubles
781 if self
.SphereMesh
!=0:
782 bpy
.ops
.object.mode_set(mode
='EDIT')
783 bpy
.ops
.mesh
.remove_doubles(threshold
=0.0001)
784 bpy
.ops
.object.mode_set(mode
='OBJECT')
787 if self
.SmoothMesh
!=0:
788 if bpy
.ops
.object.shade_smooth
.poll():
789 bpy
.ops
.object.shade_smooth()
791 bpy
.ops
.mesh
.faces_shade_smooth()
793 # restore pre operator undo state
794 bpy
.context
.user_preferences
.edit
.use_global_undo
= undo
798 return {'PASS_THROUGH'}
801 ###------------------------------------------------------------
804 # Define "Landscape" menu
805 def menu_func_landscape(self
, context
):
806 self
.layout
.operator(landscape_add
.bl_idname
, text
="Landscape", icon
="PLUGIN")
809 bpy
.utils
.register_module(__name__
)
811 bpy
.types
.INFO_MT_mesh_add
.append(menu_func_landscape
)
814 bpy
.utils
.unregister_module(__name__
)
816 bpy
.types
.INFO_MT_mesh_add
.remove(menu_func_landscape
)
818 if __name__
== "__main__":