diff --git a/fracture/__init__.py b/fracture/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..097daa72318f6a6e0e344295989f9e52be2411c6
--- /dev/null
+++ b/fracture/__init__.py
@@ -0,0 +1,52 @@
+# ##### 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,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+bl_addon_info = {
+    'name': 'Object: Fracture tools',
+    'author': 'pildanovak',
+    'version': '2.0',
+    'blender': (2, 5, 3),
+    'location': 'Fracture tools (Search > Fracture Object,' \
+        ' Add Bomb, Rigidbody Recorder)',
+    'url': 'http://wiki.blender.org/index.php/Extensions:2.5/Py/Scripts/',
+    'category': 'Object'}
+
+import bpy
+
+
+def register():
+    from fracture import fracture_ops, fracture_setup
+    bpy.types.register(fracture_ops.FractureSimple)
+    bpy.types.register(fracture_ops.FractureGroup)
+    bpy.types.register(fracture_ops.ImportRecorder)
+    bpy.types.register(fracture_ops.ImportBomb)
+    bpy.types.register(fracture_ops.ImportProjectile)
+    bpy.types.register(fracture_setup.SetupShards)
+
+
+def unregister():
+    from fracture import fracture_ops, fracture_setup
+    bpy.types.unregister(fracture_ops.FractureSimple)
+    bpy.types.unregister(fracture_ops.FractureGroup)
+    bpy.types.unregister(fracture_ops.ImportRecorder)
+    bpy.types.unregister(fracture_ops.ImportBomb)
+    bpy.types.unregister(fracture_ops.ImportProjectile)
+    bpy.types.unregister(fracture_setup.SetupShards)
+
+if __name__ == "__main__":
+    register()
diff --git a/fracture/data.blend b/fracture/data.blend
new file mode 100644
index 0000000000000000000000000000000000000000..e0e72dcf7abea16399db4f872c8354562b0d2196
Binary files /dev/null and b/fracture/data.blend differ
diff --git a/fracture/fracture_ops.py b/fracture/fracture_ops.py
new file mode 100644
index 0000000000000000000000000000000000000000..ab226da6faf6e5016ffb42e7ee3c4ea06b345d70
--- /dev/null
+++ b/fracture/fracture_ops.py
@@ -0,0 +1,484 @@
+# ##### 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,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+from bpy.props import *
+import os
+import random
+import mathutils
+from mathutils import *
+
+
+def create_cutter(context, crack_type, scale, roughness):
+    ncuts = 12
+    if crack_type == 'FLAT' or crack_type == 'FLAT_ROUGH':
+        bpy.ops.mesh.primitive_cube_add(
+            view_align=False,
+            enter_editmode=False,
+            location=(0, 0, 0),
+            rotation=(0, 0, 0),
+            layer=(True, False, False, False,
+                False, False, False, False,
+                False, False, False, False,
+                False, False, False, False,
+                False, False, False, False,
+                False, False, False, False,
+                False, False, False, False,
+                False, False, False, False))
+
+        for v in context.scene.objects.active.data.verts:
+            v.co[0] += 1
+            v.co[0] *= scale
+            v.co[1] *= scale
+            v.co[2] *= scale
+        bpy.ops.object.editmode_toggle()
+        bpy.ops.mesh.faces_shade_smooth()
+        bpy.ops.uv.reset()
+
+        if crack_type == 'FLAT_ROUGH':
+            bpy.ops.mesh.subdivide(
+                number_cuts=ncuts,
+                fractal=roughness * 7 * scale,
+                smoothness=0)
+
+            bpy.ops.mesh.vertices_smooth(repeat=5)
+
+        bpy.ops.object.editmode_toggle()
+
+    if crack_type == 'SPHERE' or crack_type == 'SPHERE_ROUGH':
+        bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4,
+            size=1,
+            view_align=False,
+            enter_editmode=False,
+            location=(0, 0, 0),
+            rotation=(0, 0, 0),
+            layer=(True, False, False, False,
+                False, False, False, False,
+                False, False, False, False,
+                False, False, False, False,
+                False, False, False, False,
+                False, False, False, False,
+                False, False, False, False,
+                False, False, False, False))
+
+        bpy.ops.object.editmode_toggle()
+        bpy.ops.mesh.faces_shade_smooth()
+        bpy.ops.uv.smart_project(angle_limit=66, island_margin=0)
+
+        bpy.ops.object.editmode_toggle()
+        for v in context.scene.objects.active.data.verts:
+            v.co[0] += 1
+            v.co[0] *= scale
+            v.co[1] *= scale
+            v.co[2] *= scale
+
+        if crack_type == 'SPHERE_ROUGH':
+            for v in context.scene.objects.active.data.verts:
+                v.co[0] += roughness * scale * 0.2 * (random.random() - 0.5)
+                v.co[1] += roughness * scale * 0.1 * (random.random() - 0.5)
+                v.co[2] += roughness * scale * 0.1 * (random.random() - 0.5)
+
+    bpy.context.scene.objects.active.selected = True
+    '''
+    # Adding fracture material
+    # @todo Doesn't work at all yet.
+    sce = bpy.context.scene
+    if bpy.data.materials.get('fracture')==None:
+        bpy.ops.material.new()
+        bpy.ops.object.material_slot_add()
+        sce.objects.active.material_slots[0].material.name = 'fracture'
+    else:
+        bpy.ops.object.material_slot_add()
+        sce.objects.active.material_slots[0].material
+            = bpy.data.materials['fracture']
+    '''
+
+
+#UNWRAP
+def getsizefrommesh(ob):
+    bb = ob.bound_box
+    return (
+        bb[5][0] - bb[0][0],
+        bb[3][1] - bb[0][1],
+        bb[1][2] - bb[0][2])
+
+
+def getIslands(shard):
+    sm = shard.data
+    islands = []
+    vgroups = []
+    fgroups = []
+    vgi = []
+    for v in sm.verts:
+        vgi.append(-1)
+
+    gindex = 0
+    for i in range(len(vgi)):
+        if vgi[i] == -1:
+            gproc = [i]
+            vgroups.append([i])
+            fgroups.append([])
+
+            while len(gproc) > 0:
+                i = gproc.pop(0)
+                for f in sm.faces:
+                    #if i in f.verts:
+                    for v in f.verts:
+                        if v == i:
+                            for v1 in f.verts:
+                                if vgi[v1] == -1:
+                                    vgi[v1] = gindex
+                                    vgroups[gindex].append(v1)
+                                    gproc.append(v1)
+
+                            fgroups[gindex].append(f.index)
+
+            gindex += 1
+
+    #print( gindex)
+
+    if gindex == 1:
+        shards = [shard]
+
+    else:
+        shards = []
+        for gi in range(0, gindex):
+            bpy.ops.object.select_all(action='DESELECT')
+            bpy.context.scene.objects.active = shard
+            shard.selected = True
+            bpy.ops.object.duplicate(linked=False, mode=1)
+            a = bpy.context.scene.objects.active
+            sm = a.data
+            print (a.name)
+
+            bpy.ops.object.editmode_toggle()
+            bpy.ops.mesh.select_all(action='DESELECT')
+            bpy.ops.object.editmode_toggle()
+
+            for x in range(len(sm.verts) - 1, -1, -1):
+                if vgi[x] != gi:
+                    print('selecting')
+                    print (x)
+                    a.data.verts[x].selected = True
+
+            print(bpy.context.scene.objects.active.name)
+
+            bpy.ops.object.editmode_toggle()
+            bpy.ops.mesh.delete()
+            bpy.ops.object.editmode_toggle()
+
+            bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
+
+            shards.append(a)
+
+        bpy.context.scene.objects.unlink(shard)
+
+    return shards
+
+
+def boolop(ob, cutter, op):
+    sce = bpy.context.scene
+    fault = 0
+    new_shards = []
+    sizex, sizey, sizez = getsizefrommesh(ob)
+    gsize = sizex + sizey + sizez
+
+    bpy.ops.object.select_all()
+    ob.selected = True
+    sce.objects.active = ob
+    cutter.selected = False
+
+    bpy.ops.object.modifier_add(type='BOOLEAN')
+    a = sce.objects.active
+    a.modifiers['Boolean'].object = cutter
+    a.modifiers['Boolean'].operation = op
+
+    nmesh = a.create_mesh(sce, apply_modifiers=True, settings='PREVIEW')
+
+    if len(nmesh.verts) > 0:
+        a.modifiers.remove(a.modifiers['Boolean'])
+        bpy.ops.object.duplicate(linked=False, mode=1)
+
+        new_shard = sce.objects.active
+        new_shard.data = nmesh
+        #scene.objects.link(new_shard)
+
+        new_shard.location = a.location
+        bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
+
+        sizex, sizey, sizez = getsizefrommesh(new_shard)
+        gsize2 = sizex + sizey + sizez
+
+        if gsize2 > gsize * 1.01:               # Size check
+            print (gsize2, gsize, ob.name, cutter.name)
+            fault = 1
+            #print ('boolop: sizeerror')
+
+        elif min(nmesh.edge_face_count) < 2:    # Manifold check
+            fault = 1
+
+        if not fault:
+            new_shards = getIslands(new_shard)
+
+        else:
+            sce.objects.unlink(new_shard)
+
+    else:
+        fault = 2
+
+    return fault, new_shards
+
+
+def splitobject(context, ob, crack_type, roughness):
+    scene = context.scene
+
+    size = getsizefrommesh(ob)
+    shards = []
+    scale = max(size) * 1.3
+
+    create_cutter(context, crack_type, scale, roughness)
+    cutter = context.active_object
+    cutter.location = ob.location
+
+    cutter.location[0] += random.random() * size[0] * 0.1
+    cutter.location[1] += random.random() * size[1] * 0.1
+    cutter.location[2] += random.random() * size[2] * 0.1
+    cutter.rotation_euler = [
+        random.random() * 5000.0,
+        random.random() * 5000.0,
+        random.random() * 5000.0]
+
+    scene.objects.active = ob
+    operations = ['INTERSECT', 'DIFFERENCE']
+
+    for op in operations:
+        fault, newshards = boolop(ob, cutter, op)
+
+        shards.extend(newshards)
+        if fault > 0:
+            # Delete all shards in case of fault from previous operation.
+            for s in shards:
+                scene.objects.unlink(s)
+
+            scene.objects.unlink(cutter)
+            #print('splitobject: fault')
+
+            return [ob]
+
+    if shards[0] != ob:
+        bpy.context.scene.objects.unlink(ob)
+
+    bpy.context.scene.objects.unlink(cutter)
+
+    return shards
+
+
+def fracture_basic(context, nshards, crack_type, roughness):
+    tobesplit = []
+    shards = []
+
+    for ob in context.scene.objects:
+        if ob.selected:
+            tobesplit.append(ob)
+
+    i = 1     # I counts shards, starts with 1 - the original object
+    iter = 0  # counts iterations, to prevent eternal loops in case
+              # of boolean faults
+
+    maxshards = nshards * len(tobesplit)
+
+    while i < maxshards and len(tobesplit) > 0 and iter < maxshards * 10:
+        ob = tobesplit.pop(0)
+        newshards = splitobject(context, ob, crack_type, roughness)
+
+        tobesplit.extend(newshards)
+
+        if len(newshards) > 1:
+            shards.extend(newshards)
+            #shards.remove(ob)
+
+            i += (len(newshards) - 1)
+
+            #print('fracture_basic: ' + str(i))
+            #print('fracture_basic: lenobs', len(context.scene.objects))
+
+        iter += 1
+
+
+def fracture_group(context, group):
+    tobesplit = []
+    shards = []
+
+    for ob in context.scene.objects:
+        if (ob.selected
+            and (len(ob.group_users) == 0 or ob.group_users[0].name != group)):
+            tobesplit.append(ob)
+
+    cutters = bpy.data.groups[group].objects
+
+    # @todo This can be optimized.
+    # Avoid booleans on obs where bbox doesn't intersect
+    i = 0
+    for ob in tobesplit:
+        for cutter in cutters:
+            fault, newshards = boolop(ob, cutter, 'INTERSECT')
+            shards.extend(newshards)
+
+            if fault == 1:
+               # Delete all shards in case of fault from previous operation.
+                for s in shards:
+                    bpy.context.scene.objects.unlink(s)
+
+                #print('fracture_group: fault')
+                #print('fracture_group: ' + str(i))
+
+                return
+
+            i += 1
+
+
+class FractureSimple(bpy.types.Operator):
+    '''Split object with boolean operations for simulation, uses an object.'''
+    bl_idname = "object.fracture_simple"
+    bl_label = "Fracture Object"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    exe = BoolProperty(name="Execute",
+        description="If it shall actually run, for optimal performance...",
+        default=False)
+
+    hierarchy = BoolProperty(name="Generate hierarchy",
+        description="Hierarchy is usefull for simulation of objects" \
+            " breaking in motion.",
+        default=False)
+
+    nshards = IntProperty(name="Number of shards",
+        description="Number of shards the object should be split into.",
+        default=5)
+
+    crack_type = EnumProperty(name='Crack type',
+        items=(('FLAT', 'Flat', 'a'),
+            ('FLAT_ROUGH', 'Flat rough', 'a'),
+            ('SPHERE', 'Spherical', 'a'),
+            ('SPHERE_ROUGH', 'Spherical rough', 'a')),
+        description='Look of the fracture surface',
+        default='FLAT')
+
+    roughness = FloatProperty(name="Roughness",
+        description="Roughness of the fracture surface",
+        max=3.0,
+        min=0.0,
+        default=0.5)
+
+    def execute(self, context):
+        #print(self.properties)
+        #getIslands(context.object)
+
+        if self.properties.exe:
+            #print ('go')
+            fracture_basic(context,
+                    self.properties.nshards,
+                    self.properties.crack_type,
+                    self.properties.roughness)
+
+        return {'FINISHED'}
+
+
+class FractureGroup(bpy.types.Operator):
+    '''Split object with boolean operations for simulation, uses a group.'''
+    bl_idname = "object.fracture_group"
+    bl_label = "Fracture Object (Group)"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    exe = BoolProperty(name="Execute",
+        description="If it shall actually run, for optimal performance...",
+        default=False)
+
+    e = []
+    for i, g in enumerate(bpy.data.groups):
+        e.append((g.name, g.name, ''))
+
+    group = EnumProperty(name='Group (hit F8 to refresh list)',
+        items=e,
+        description='Specify the group used for fracturing')
+
+    def execute(self, context):
+        #getIslands(context.object)
+
+        if self.properties.exe:
+            fracture_group(context, self.properties.group)
+
+        return {'FINISHED'}
+
+
+def import_object(obname):
+        opath = "//data.blend\\Object\\" + obname
+        s = os.sep
+        dpath = bpy.utils.script_paths()[0] + \
+            '%saddons%sfracture%sdata.blend\\Object\\' % (s, s, s)
+        print(opath)
+
+        bpy.ops.wm.link_append(
+                path=opath,
+                filename=obname,
+                directory=dpath,
+                filemode=1,
+                link=False,
+                autoselect=True,
+                active_layer=True,
+                instance_groups=True,
+                relative_paths=True)
+
+        for ob in bpy.context.selected_objects:
+            ob.location = bpy.context.scene.cursor_location
+
+
+class ImportRecorder(bpy.types.Operator):
+    '''Imports a rigidbody recorder'''
+    bl_idname = "object.import_recorder"
+    bl_label = "Add Rigidbody Recorder (Fracture)"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    def execute(self, context):
+        import_object("RECORDER")
+
+        return {'FINISHED'}
+
+
+class ImportBomb(bpy.types.Operator):
+    '''Import a bomb'''
+    bl_idname = "object.import_bomb"
+    bl_label = "Add Bomb (Fracture)"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    def execute(self, context):
+        import_object("BOMB")
+
+        return {'FINISHED'}
+
+
+class ImportProjectile(bpy.types.Operator, ):
+    '''Imports a projectile'''
+    bl_idname = "object.import_projectile"
+    bl_label = "Add Projectile (Fracture)"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    def execute(self, context):
+        import_object("PROJECTILE")
+
+        return {'FINISHED'}
diff --git a/fracture/fracture_setup.py b/fracture/fracture_setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..d8256da3289af26d5042dcadd39bd3da6aad09ec
--- /dev/null
+++ b/fracture/fracture_setup.py
@@ -0,0 +1,79 @@
+# ##### 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,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+from bpy.props import *
+
+
+def getsizefrommesh(ob):
+    bb = ob.bound_box
+    return(
+        bb[5][0] - bb[0][0],
+        bb[3][1] - bb[0][1],
+        bb[1][2] - bb[0][2])
+
+
+def setupshards(context):
+    sce = context.scene
+    #print(dir(context))
+    #bpy.data.scenes[0].game_data.all_frames
+
+    tobeprocessed = []
+    for ob in sce.objects:
+        if ob.selected:
+            tobeprocessed.append(ob)
+
+    for ob in tobeprocessed:
+        g = ob.game
+
+        g.physics_type = 'RIGID_BODY'
+        g.use_collision_bounds = 1
+        g.collision_bounds = 'CONVEX_HULL'
+        g.rotation_damping = 0.9
+
+        sizex, sizey, sizez = getsizefrommesh(ob)
+        approxvolume = sizex * sizey * sizez
+        g.mass = approxvolume
+
+        sce.objects.active = ob
+
+        bpy.ops.object.game_property_new()
+        g.properties['prop'].name = 'shard'
+        #sm=FloatProperty(name='shard',description='shardprop',default=0.0)
+        #print (sm)
+        #np=bpy.types.GameFloatProperty(sm)
+        #name='shard',type='BOOL', value=1
+        #print(ob)
+
+
+class SetupShards(bpy.types.Operator):
+    ''''''
+    bl_idname = "object.fracture_setup_shards"
+    bl_label = "Setup Fracture Shards"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    #def poll(self, context):
+
+    def execute(self, context):
+        setupshards(context)
+        return {'FINISHED'}
+
+#bpy.types.register(SetupShards)
+
+#if __name__ == "__main__":
+#    bpy.ops.object.fracture_setup_shards()