diff --git a/io_scene_3ds/export_3ds.py b/io_scene_3ds/export_3ds.py
index 7b37db23ac88fa311151ebd5403b035a3664b53b..40fdeda364844c11665e24f695182a78264fc957 100644
--- a/io_scene_3ds/export_3ds.py
+++ b/io_scene_3ds/export_3ds.py
@@ -49,8 +49,21 @@ MATAMBIENT = 0xA010  # Ambient color of the object/material
 MATDIFFUSE = 0xA020  # This holds the color of the object/material
 MATSPECULAR = 0xA030  # SPecular color of the object/material
 MATSHINESS = 0xA040  # ??
-MATMAP = 0xA200  # This is a header for a new material
-MATMAPFILE = 0xA300  # This holds the file name of the texture
+
+MAT_DIFFUSEMAP = 0xA200  # This is a header for a new diffuse texture
+MAT_OPACMAP = 0xA210  # head for opacity map
+MAT_BUMPMAP = 0xA230  # read for normal map
+MAT_SPECMAP = 0xA204  # read for specularity map
+
+#>------ sub defines of MAT_???MAP
+MATMAPFILE = 0xA300  # This holds the file name of a texture
+
+MAT_MAP_TILING = 0xa351   # 2nd bit (from LSB) is mirror UV flag
+MAT_MAP_USCALE = 0xA354   # U axis scaling
+MAT_MAP_VSCALE = 0xA356   # V axis scaling
+MAT_MAP_UOFFSET = 0xA358  # U axis offset
+MAT_MAP_VOFFSET = 0xA35A  # V axis offset
+MAT_MAP_ANG = 0xA35C      # UV rotation around the z-axis in rad
 
 RGB1 = 0x0011
 RGB2 = 0x0012
@@ -423,10 +436,10 @@ class _3ds_chunk(object):
 # EXPORT
 ######################################################
 
-def get_material_images(material):
+def get_material_image_texslots(material):
     # blender utility func.
     if material:
-        return [s.texture.image for s in material.texture_slots if s and s.texture.type == 'IMAGE' and s.texture.image]
+        return [s for s in material.texture_slots if s and s.texture.type == 'IMAGE' and s.texture.image]
 
     return []
 # 	images = []
@@ -454,22 +467,76 @@ def make_material_subchunk(chunk_id, color):
     return mat_sub
 
 
-def make_material_texture_chunk(chunk_id, images):
-    """Make Material Map texture chunk
+def make_material_texture_chunk(chunk_id, texslots, tess_uv_image=None):
+    """Make Material Map texture chunk given a seq. of `MaterialTextureSlot`'s
+
+        `tess_uv_image` is optionally used as image source if the slots are
+        empty. No additional filtering for mapping modes is done, all
+        slots are written "as is".
     """
+
     mat_sub = _3ds_chunk(chunk_id)
+    has_entry = False
+
+    import bpy
+
+    def add_texslot(texslot):
+        texture = texslot.texture
+        image = texture.image
 
-    def add_image(image):
-        import bpy
         filename = bpy.path.basename(image.filepath)
         mat_sub_file = _3ds_chunk(MATMAPFILE)
         mat_sub_file.add_variable("mapfile", _3ds_string(sane_name(filename)))
         mat_sub.add_subchunk(mat_sub_file)
 
-    for image in images:
-        add_image(image)
+        maptile = 0
+
+        # no perfect mapping for mirror modes - 3DS only has uniform mirror w. repeat=2
+        if texture.extension == 'REPEAT' and (texture.use_mirror_x and texture.repeat_x > 1) \
+           or (texture.use_mirror_y and texture.repeat_y > 1):
+            maptile |= 0x2
+        # CLIP maps to 3DS' decal flag
+        elif texture.extension == 'CLIP':
+            maptile |= 0x10
+
+        mat_sub_tile = _3ds_chunk(MAT_MAP_TILING)
+        mat_sub_tile.add_variable("maptiling", _3ds_ushort(maptile))
+        mat_sub.add_subchunk(mat_sub_tile)
+
+        mat_sub_uscale = _3ds_chunk(MAT_MAP_USCALE)
+        mat_sub_uscale.add_variable("mapuscale", _3ds_float(texslot.scale[0]))
+        mat_sub.add_subchunk(mat_sub_uscale)
+
+        mat_sub_vscale = _3ds_chunk(MAT_MAP_VSCALE)
+        mat_sub_vscale.add_variable("mapuscale", _3ds_float(texslot.scale[1]))
+        mat_sub.add_subchunk(mat_sub_vscale)
+
+        mat_sub_uoffset = _3ds_chunk(MAT_MAP_UOFFSET)
+        mat_sub_uoffset.add_variable("mapuoffset", _3ds_float(texslot.offset[0]))
+        mat_sub.add_subchunk(mat_sub_uoffset)
+
+        mat_sub_voffset = _3ds_chunk(MAT_MAP_VOFFSET)
+        mat_sub_voffset.add_variable("mapvoffset", _3ds_float(texslot.offset[1]))
+        mat_sub.add_subchunk(mat_sub_voffset)
+
+    # store all textures for this mapto in order. This at least is what
+    # the 3DS exporter did so far, afaik most readers will just skip
+    # over 2nd textures.
+    for slot in texslots:
+        add_texslot(slot)
+        has_entry = True
+
+    # image from tess. UV face - basically the code above should handle
+    # this already. No idea why its here so keep it :-)
+    if tess_uv_image and not has_entry:
+        has_entry = True
+
+        filename = bpy.path.basename(tess_uv_image.filepath)
+        mat_sub_file = _3ds_chunk(MATMAPFILE)
+        mat_sub_file.add_variable("mapfile", _3ds_string(sane_name(filename)))
+        mat_sub.add_subchunk(mat_sub_file)
 
-    return mat_sub
+    return mat_sub if has_entry else None
 
 
 def make_material_chunk(material, image):
@@ -495,12 +562,40 @@ def make_material_chunk(material, image):
         material_chunk.add_subchunk(make_material_subchunk(MATDIFFUSE, material.diffuse_color[:]))
         material_chunk.add_subchunk(make_material_subchunk(MATSPECULAR, material.specular_color[:]))
 
-        images = get_material_images(material)  # can be None
-        if image:
-            images.append(image)
-
-        if images:
-            material_chunk.add_subchunk(make_material_texture_chunk(MATMAP, images))
+        slots = get_material_image_texslots(material)  # can be None
+
+        if slots:
+
+            spec = [s for s in slots if s.use_map_specular or s.use_map_color_spec]
+            matmap = make_material_texture_chunk(MAT_SPECMAP, spec)
+            if matmap:
+                material_chunk.add_subchunk(matmap)
+
+            alpha = [s for s in slots if s.use_map_alpha]
+            matmap = make_material_texture_chunk(MAT_OPACMAP, alpha)
+            if matmap:
+                material_chunk.add_subchunk(matmap)
+
+            normal = [s for s in slots if s.use_map_normal]
+            matmap = make_material_texture_chunk(MAT_BUMPMAP, normal)
+            if matmap:
+                material_chunk.add_subchunk(matmap)
+
+            # make sure no textures are lost. Everything that doesn't fit
+            # into a channel is exported as diffuse texture with a
+            # warning.
+            diffuse = []
+            for s in slots:
+                if s.use_map_color_diffuse:
+                    diffuse.append(s)
+                elif not (s in normal or s in alpha or s in spec):
+                    print('\nwarning: failed to map texture to 3DS map channel, assuming diffuse')
+                    diffuse.append(s)
+
+            if diffuse:
+                matmap = make_material_texture_chunk(MAT_DIFFUSEMAP, diffuse, image)
+                if matmap:
+                    material_chunk.add_subchunk(matmap)
 
     return material_chunk
 
diff --git a/io_scene_3ds/import_3ds.py b/io_scene_3ds/import_3ds.py
index 32a41b1a782e2a9ba28209d553f13391d77c4f97..338bf02a0cee0cb6c9b25db6277c8d25d0d43058 100644
--- a/io_scene_3ds/import_3ds.py
+++ b/io_scene_3ds/import_3ds.py
@@ -66,6 +66,13 @@ MAT_REFLECTION_MAP = 0xA220  # This is a header for a new reflection map
 MAT_BUMP_MAP = 0xA230  # This is a header for a new bump map
 MAT_MAP_FILEPATH = 0xA300  # This holds the file name of the texture
 
+MAT_MAP_TILING = 0xa351   # 2nd bit (from LSB) is mirror UV flag
+MAT_MAP_USCALE = 0xA354   # U axis scaling
+MAT_MAP_VSCALE = 0xA356   # V axis scaling
+MAT_MAP_UOFFSET = 0xA358  # U axis offset
+MAT_MAP_VOFFSET = 0xA35A  # V axis offset
+MAT_MAP_ANG = 0xA35C      # UV rotation around the z-axis in rad
+
 MAT_FLOAT_COLOR = 0x0010  # color defined as 3 floats
 MAT_24BIT_COLOR = 0x0011  # color defined as 3 bytes
 
@@ -211,7 +218,7 @@ def skip_to_end(file, skip_chunk):
     skip_chunk.bytes_read += buffer_size
 
 
-def add_texture_to_material(image, texture, material, mapto):
+def add_texture_to_material(image, texture, scale, offset, extension, material, mapto):
     #print('assigning %s to %s' % (texture, material))
 
     if mapto not in {'COLOR', 'SPECULARITY', 'ALPHA', 'NORMAL'}:
@@ -226,6 +233,18 @@ def add_texture_to_material(image, texture, material, mapto):
     mtex.texture_coords = 'UV'
     mtex.use_map_color_diffuse = False
 
+    mtex.scale = (scale[0], scale[1], 1.0)
+    mtex.offset = (offset[0], offset[1], 0.0)
+
+    texture.extension = 'REPEAT'
+    if extension == 'mirror':
+        # 3DS mirror flag can be emulated by these settings (at least so it seems)
+        texture.repeat_x = texture.repeat_y = 2
+        texture.use_mirror_x = texture.use_mirror_y = True
+    elif extension == 'decal':
+        # 3DS' decal mode maps best to Blenders CLIP
+        texture.extension = 'CLIP'
+
     if mapto == 'COLOR':
         mtex.use_map_color_diffuse = True
     elif mapto == 'SPECULARITY':
@@ -255,6 +274,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
 # 	TEXMODE = Mesh.FaceModes['TEX']
 
     # Localspace variable names, faster.
+    STRUCT_SIZE_FLOAT = struct.calcsize('f')
     STRUCT_SIZE_2FLOAT = struct.calcsize('2f')
     STRUCT_SIZE_3FLOAT = struct.calcsize('3f')
     STRUCT_SIZE_4FLOAT = struct.calcsize('4f')
@@ -330,7 +350,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
 
                     uvl[pl.loop_start].uv = contextMeshUV[v1 * 2: (v1 * 2) + 2]
                     uvl[pl.loop_start + 1].uv = contextMeshUV[v2 * 2: (v2 * 2) + 2]
-                    uvl[pl.loop_start + 2].uv = contextMeshUV[v3 * 2: ( v3 * 2) + 2]
+                    uvl[pl.loop_start + 2].uv = contextMeshUV[v3 * 2: (v3 * 2) + 2]
                     # always a tri
 
         bmesh.validate()
@@ -352,10 +372,20 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
     CreateBlenderObject = False
 
     def read_float_color(temp_chunk):
-        temp_data = file.read(struct.calcsize('3f'))
-        temp_chunk.bytes_read += 12
+        temp_data = file.read(STRUCT_SIZE_3FLOAT)
+        temp_chunk.bytes_read += STRUCT_SIZE_3FLOAT
         return [float(col) for col in struct.unpack('<3f', temp_data)]
 
+    def read_float(temp_chunk):
+        temp_data = file.read(STRUCT_SIZE_FLOAT)
+        temp_chunk.bytes_read += STRUCT_SIZE_FLOAT
+        return struct.unpack('<f', temp_data)[0]
+
+    def read_short(temp_chunk):
+        temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
+        temp_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
+        return struct.unpack('<H', temp_data)[0]
+
     def read_byte_color(temp_chunk):
         temp_data = file.read(struct.calcsize('3B'))
         temp_chunk.bytes_read += 3
@@ -364,24 +394,46 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
     def read_texture(new_chunk, temp_chunk, name, mapto):
         new_texture = bpy.data.textures.new(name, type='IMAGE')
 
-        img = None
+        u_scale, v_scale, u_offset, v_offset = 1.0, 1.0, 0.0, 0.0
+        mirror = False
+        extension = 'wrap'
         while (new_chunk.bytes_read < new_chunk.length):
             #print 'MAT_TEXTURE_MAP..while', new_chunk.bytes_read, new_chunk.length
             read_chunk(file, temp_chunk)
 
             if temp_chunk.ID == MAT_MAP_FILEPATH:
                 texture_name, read_str_len = read_string(file)
+
                 img = TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname)
-                new_chunk.bytes_read += read_str_len  # plus one for the null character that gets removed
+                temp_chunk.bytes_read += read_str_len  # plus one for the null character that gets removed
 
-            else:
-                skip_to_end(file, temp_chunk)
+            elif temp_chunk.ID == MAT_MAP_USCALE:
+                u_scale = read_float(temp_chunk)
+            elif temp_chunk.ID == MAT_MAP_VSCALE:
+                v_scale = read_float(temp_chunk)
+
+            elif temp_chunk.ID == MAT_MAP_UOFFSET:
+                u_offset = read_float(temp_chunk)
+            elif temp_chunk.ID == MAT_MAP_VOFFSET:
+                v_offset = read_float(temp_chunk)
+
+            elif temp_chunk.ID == MAT_MAP_TILING:
+                tiling = read_short(temp_chunk)
+                if tiling & 0x2:
+                    extension = 'mirror'
+                elif tiling & 0x10:
+                    extension = 'decal'
+
+            elif temp_chunk.ID == MAT_MAP_ANG:
+                print("\nwarning: ignoring UV rotation")
 
+            skip_to_end(file, temp_chunk)
             new_chunk.bytes_read += temp_chunk.bytes_read
 
         # add the map to the material in the right channel
         if img:
-            add_texture_to_material(img, new_texture, contextMaterial, mapto)
+            add_texture_to_material(img, new_texture, (u_scale, v_scale),
+                                    (u_offset, v_offset), extension, contextMaterial, mapto)
 
     dirname = os.path.dirname(file.name)