From 8161ab573fd6f8a45b3986278ce7fc1596140526 Mon Sep 17 00:00:00 2001
From: Kahrl <kahrl@gmx.net>
Date: Mon, 24 Jun 2013 04:17:50 +0200
Subject: [PATCH] Remove texture atlas / AtlasPointer, rename getTextureRaw to
 getTexture

---
 minetest.conf.example    |   3 -
 src/client.cpp           |  11 -
 src/content_cao.cpp      |  25 +-
 src/content_cso.cpp      |   2 +-
 src/content_mapblock.cpp | 170 +++++---------
 src/defaultsettings.cpp  |   1 -
 src/farmesh.cpp          |   2 +-
 src/game.cpp             |  13 +-
 src/guiFormSpecMenu.cpp  |   6 +-
 src/hud.cpp              |   6 +-
 src/itemdef.cpp          |   6 +-
 src/mapblock_mesh.cpp    |  81 +++----
 src/nodedef.cpp          |  19 +-
 src/nodedef.h            |   1 -
 src/particles.cpp        |  60 +++--
 src/particles.h          |  15 +-
 src/tile.cpp             | 478 ++++++---------------------------------
 src/tile.h               | 114 ++--------
 18 files changed, 260 insertions(+), 753 deletions(-)

diff --git a/minetest.conf.example b/minetest.conf.example
index 3f1977268..75e546c2f 100644
--- a/minetest.conf.example
+++ b/minetest.conf.example
@@ -112,9 +112,6 @@
 # Enable smooth lighting with simple ambient occlusion;
 # disable for speed or for different looks.
 #smooth_lighting = true
-# Enable combining mainly used textures to a bigger one for improved speed
-# disable if it causes graphics glitches.
-#enable_texture_atlas = false
 # Path to texture directory. All textures are first searched from here.
 #texture_path = 
 # Video back-end.
diff --git a/src/client.cpp b/src/client.cpp
index c82d9b050..5e682aaa3 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -320,12 +320,6 @@ Client::Client(
 	m_playerpos_send_timer = 0.0;
 	m_ignore_damage_timer = 0.0;
 
-	// Build main texture atlas, now that the GameDef exists (that is, us)
-	if(g_settings->getBool("enable_texture_atlas"))
-		m_tsrc->buildMainAtlas(this);
-	else
-		infostream<<"Not building texture atlas."<<std::endl;
-	
 	/*
 		Add local player
 	*/
@@ -2855,11 +2849,6 @@ void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
 	infostream<<"- Rebuilding images and textures"<<std::endl;
 	m_tsrc->rebuildImagesAndTextures();
 
-	// Update texture atlas
-	infostream<<"- Updating texture atlas"<<std::endl;
-	if(g_settings->getBool("enable_texture_atlas"))
-		m_tsrc->buildMainAtlas(this);
-
 	// Rebuild shaders
 	m_shsrc->rebuildShaders();
 
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
index f79d0d6f6..ece284343 100644
--- a/src/content_cao.cpp
+++ b/src/content_cao.cpp
@@ -223,7 +223,7 @@ void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
 	// Set material
 	buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
 	buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
-	buf->getMaterial().setTexture(0, tsrc->getTextureRaw("rat.png"));
+	buf->getMaterial().setTexture(0, tsrc->getTexture("rat.png"));
 	buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 	buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 	buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -393,7 +393,7 @@ void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
 	buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
 	buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
 	// Initialize with a generated placeholder texture
-	buf->getMaterial().setTexture(0, tsrc->getTextureRaw(""));
+	buf->getMaterial().setTexture(0, tsrc->getTexture(""));
 	buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 	buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 	buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -864,7 +864,7 @@ class GenericCAO : public ClientActiveObject
 			m_spritenode = smgr->addBillboardSceneNode(
 					NULL, v2f(1, 1), v3f(0,0,0), -1);
 			m_spritenode->setMaterialTexture(0,
-					tsrc->getTextureRaw("unknown_node.png"));
+					tsrc->getTexture("unknown_node.png"));
 			m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
 			m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
 			m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
@@ -1273,7 +1273,7 @@ class GenericCAO : public ClientActiveObject
 					texturestring = m_prop.textures[0];
 				texturestring += mod;
 				m_spritenode->setMaterialTexture(0,
-						tsrc->getTextureRaw(texturestring));
+						tsrc->getTexture(texturestring));
 
 				// This allows setting per-material colors. However, until a real lighting
 				// system is added, the code below will have no effect. Once MineTest
@@ -1300,7 +1300,7 @@ class GenericCAO : public ClientActiveObject
 					if(texturestring == "")
 						continue; // Empty texture string means don't modify that material
 					texturestring += mod;
-					video::ITexture* texture = tsrc->getTextureRaw(texturestring);
+					video::ITexture* texture = tsrc->getTexture(texturestring);
 					if(!texture)
 					{
 						errorstream<<"GenericCAO::updateTextures(): Could not load texture "<<texturestring<<std::endl;
@@ -1338,20 +1338,15 @@ class GenericCAO : public ClientActiveObject
 					if(m_prop.textures.size() > i)
 						texturestring = m_prop.textures[i];
 					texturestring += mod;
-					AtlasPointer ap = tsrc->getTexture(texturestring);
 
-					// Get the tile texture and atlas transformation
-					video::ITexture* atlas = ap.atlas;
-					v2f pos = ap.pos;
-					v2f size = ap.size;
 
 					// Set material flags and texture
 					video::SMaterial& material = m_meshnode->getMaterial(i);
 					material.setFlag(video::EMF_LIGHTING, false);
 					material.setFlag(video::EMF_BILINEAR_FILTER, false);
-					material.setTexture(0, atlas);
-					material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
-					material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
+					material.setTexture(0,
+							tsrc->getTexture(texturestring));
+					material.getTextureMatrix(0).makeIdentity();
 
 					// This allows setting per-material colors. However, until a real lighting
 					// system is added, the code below will have no effect. Once MineTest
@@ -1378,7 +1373,7 @@ class GenericCAO : public ClientActiveObject
 					tname += mod;
 					scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
 					buf->getMaterial().setTexture(0,
-							tsrc->getTextureRaw(tname));
+							tsrc->getTexture(tname));
 					
 					// This allows setting per-material colors. However, until a real lighting
 					// system is added, the code below will have no effect. Once MineTest
@@ -1403,7 +1398,7 @@ class GenericCAO : public ClientActiveObject
 					tname += mod;
 					scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
 					buf->getMaterial().setTexture(0,
-							tsrc->getTextureRaw(tname));
+							tsrc->getTexture(tname));
 
 					// This allows setting per-material colors. However, until a real lighting
 					// system is added, the code below will have no effect. Once MineTest
diff --git a/src/content_cso.cpp b/src/content_cso.cpp
index 73d5f2b48..4f652a8a3 100644
--- a/src/content_cso.cpp
+++ b/src/content_cso.cpp
@@ -50,7 +50,7 @@ class SmokePuffCSO: public ClientSimpleObject
 		m_spritenode = smgr->addBillboardSceneNode(
 				NULL, v2f(1,1), pos, -1);
 		m_spritenode->setMaterialTexture(0,
-				env->getGameDef()->tsrc()->getTextureRaw("smoke_puff.png"));
+				env->getGameDef()->tsrc()->getTexture("smoke_puff.png"));
 		m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
 		m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
 		//m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp
index 84408e776..bc17e19aa 100644
--- a/src/content_mapblock.cpp
+++ b/src/content_mapblock.cpp
@@ -99,7 +99,6 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box,
 		video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
 	};
 
-	v2f t;
 	for(int i = 0; i < tilecount; i++)
 				{
 				switch (tiles[i].rotation)
@@ -119,49 +118,43 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box,
 						vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
 					break;
 				case 4: //FXR90
-					for (int x = 0; x < 4; x++)
+					for (int x = 0; x < 4; x++){
+						vertices[i*4+x].TCoords.X = 1.0 - vertices[i*4+x].TCoords.X;
 						vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
-
-					tiles[i].texture.pos.Y += tiles[i].texture.size.Y;
-					tiles[i].texture.size.Y *= -1;
+					}
 					break;
 				case 5: //FXR270
-					for (int x = 0; x < 4; x++)
+					for (int x = 0; x < 4; x++){
+						vertices[i*4+x].TCoords.X = 1.0 - vertices[i*4+x].TCoords.X;
 						vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
-					t=vertices[i*4].TCoords;
-					tiles[i].texture.pos.Y += tiles[i].texture.size.Y;
-					tiles[i].texture.size.Y *= -1;
+					}
 					break;
 				case 6: //FYR90
-					for (int x = 0; x < 4; x++)
+					for (int x = 0; x < 4; x++){
+						vertices[i*4+x].TCoords.Y = 1.0 - vertices[i*4+x].TCoords.Y;
 						vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
-					tiles[i].texture.pos.X += tiles[i].texture.size.X;
-					tiles[i].texture.size.X *= -1;
+					}
 					break;
 				case 7: //FYR270
-					for (int x = 0; x < 4; x++)
+					for (int x = 0; x < 4; x++){
+						vertices[i*4+x].TCoords.Y = 1.0 - vertices[i*4+x].TCoords.Y;
 						vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
-					tiles[i].texture.pos.X += tiles[i].texture.size.X;
-					tiles[i].texture.size.X *= -1;
+					}
 					break;
 				case 8: //FX
-					tiles[i].texture.pos.Y += tiles[i].texture.size.Y;
-					tiles[i].texture.size.Y *= -1;
+					for (int x = 0; x < 4; x++){
+						vertices[i*4+x].TCoords.X = 1.0 - vertices[i*4+x].TCoords.X;
+					}
 					break;
 				case 9: //FY
-					tiles[i].texture.pos.X += tiles[i].texture.size.X;
-					tiles[i].texture.size.X *= -1;
+					for (int x = 0; x < 4; x++){
+						vertices[i*4+x].TCoords.Y = 1.0 - vertices[i*4+x].TCoords.Y;
+					}
 					break;
 				default:
 					break;
 				}
 			}
-		for(s32 j=0; j<24; j++)
-	{
-		int tileindex = MYMIN(j/4, tilecount-1);
-		vertices[j].TCoords *= tiles[tileindex].texture.size;
-		vertices[j].TCoords += tiles[tileindex].texture.pos;
-	}
 	u16 indices[] = {0,1,2,2,3,0};
 	// Add to mesh collector
 	for(s32 j=0; j<24; j+=4)
@@ -218,7 +211,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 			*/
 			TileSpec tile_liquid = f.special_tiles[0];
 			TileSpec tile_liquid_bfculled = getNodeTile(n, p, v3s16(0,0,0), data);
-			AtlasPointer &pa_liquid = tile_liquid.texture;
 
 			bool top_is_same_liquid = false;
 			MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
@@ -280,14 +272,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 
 				video::S3DVertex vertices[4] =
 				{
-					video::S3DVertex(-BS/2,0,BS/2,0,0,0, c,
-							pa_liquid.x0(), pa_liquid.y1()),
-					video::S3DVertex(BS/2,0,BS/2,0,0,0, c,
-							pa_liquid.x1(), pa_liquid.y1()),
-					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
-							pa_liquid.x1(), pa_liquid.y0()),
-					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
-							pa_liquid.x0(), pa_liquid.y0()),
+					video::S3DVertex(-BS/2,0,BS/2,0,0,0, c, 0,1),
+					video::S3DVertex(BS/2,0,BS/2,0,0,0, c, 1,1),
+					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
+					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
 				};
 
 				/*
@@ -359,14 +347,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 			
 			video::S3DVertex vertices[4] =
 			{
-				video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
-						pa_liquid.x0(), pa_liquid.y1()),
-				video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
-						pa_liquid.x1(), pa_liquid.y1()),
-				video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
-						pa_liquid.x1(), pa_liquid.y0()),
-				video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
-						pa_liquid.x0(), pa_liquid.y0()),
+				video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
+				video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
+				video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,0),
+				video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,0),
 			};
 
 			v3f offset(p.X*BS, p.Y*BS + (-0.5+node_liquid_level)*BS, p.Z*BS);
@@ -386,7 +370,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 			*/
 			TileSpec tile_liquid = f.special_tiles[0];
 			TileSpec tile_liquid_bfculled = f.special_tiles[1];
-			AtlasPointer &pa_liquid = tile_liquid.texture;
 
 			bool top_is_same_liquid = false;
 			MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
@@ -566,14 +549,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 				
 				video::S3DVertex vertices[4] =
 				{
-					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
-							pa_liquid.x0(), pa_liquid.y1()),
-					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
-							pa_liquid.x1(), pa_liquid.y1()),
-					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
-							pa_liquid.x1(), pa_liquid.y0()),
-					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
-							pa_liquid.x0(), pa_liquid.y0()),
+					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
+					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
+					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
+					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
 				};
 				
 				/*
@@ -647,14 +626,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 			{
 				video::S3DVertex vertices[4] =
 				{
-					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
-							pa_liquid.x0(), pa_liquid.y1()),
-					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
-							pa_liquid.x1(), pa_liquid.y1()),
-					video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
-							pa_liquid.x1(), pa_liquid.y0()),
-					video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
-							pa_liquid.x0(), pa_liquid.y0()),
+					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
+					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
+					video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,0),
+					video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,0),
 				};
 				
 				// To get backface culling right, the vertices need to go
@@ -725,7 +700,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 		case NDT_GLASSLIKE:
 		{
 			TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data);
-			AtlasPointer ap = tile.texture;
 
 			u16 l = getInteriorLight(n, 1, data);
 			video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
@@ -741,14 +715,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 
 				// The face at Z+
 				video::S3DVertex vertices[4] = {
-					video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
-						ap.x0(), ap.y1()),
-					video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
-						ap.x1(), ap.y1()),
-					video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
-						ap.x1(), ap.y0()),
-					video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
-						ap.x0(), ap.y0()),
+					video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
+					video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
+					video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
+					video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),
 				};
 				
 				// Rotations in the g_6dirs format
@@ -910,7 +880,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 		{
 			TileSpec tile_leaves = getNodeTile(n, p,
 					v3s16(0,0,0), data);
-			AtlasPointer pa_leaves = tile_leaves.texture;
 
 			u16 l = getInteriorLight(n, 1, data);
 			video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
@@ -945,22 +914,16 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 			tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
 			tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
 
-			AtlasPointer ap = tile.texture;
-
 			u16 l = getInteriorLight(n, 1, data);
 			video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
 
 			// Wall at X+ of node
 			video::S3DVertex vertices[4] =
 			{
-				video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
-						ap.x0(), ap.y1()),
-				video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
-						ap.x1(), ap.y1()),
-				video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
-						ap.x1(), ap.y0()),
-				video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
-						ap.x0(), ap.y0()),
+				video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
+				video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
+				video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
+				video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
 			};
 
 			for(s32 i=0; i<4; i++)
@@ -990,7 +953,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 			TileSpec tile = getNodeTileN(n, p, 0, data);
 			tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
 			tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
-			AtlasPointer ap = tile.texture;
 
 			u16 l = getInteriorLight(n, 0, data);
 			video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
@@ -999,14 +961,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 			// Wall at X+ of node
 			video::S3DVertex vertices[4] =
 			{
-				video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c,
-						ap.x0(), ap.y0()),
-				video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
-						ap.x1(), ap.y0()),
-				video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
-						ap.x1(), ap.y1()),
-				video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
-						ap.x0(), ap.y1()),
+				video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 0,0),
+				video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 1,0),
+				video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 1,1),
+				video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 0,1),
 			};
 
 			v3s16 dir = n.getWallMountedDir(nodedef);
@@ -1037,7 +995,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 		{
 			TileSpec tile = getNodeTileN(n, p, 0, data);
 			tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
-			AtlasPointer ap = tile.texture;
 			
 			u16 l = getInteriorLight(n, 1, data);
 			video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
@@ -1046,16 +1003,12 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 			{
 				video::S3DVertex vertices[4] =
 				{
-					video::S3DVertex(-BS/2*f.visual_scale,-BS/2,0, 0,0,0, c,
-						ap.x0(), ap.y1()),
-					video::S3DVertex( BS/2*f.visual_scale,-BS/2,0, 0,0,0, c,
-						ap.x1(), ap.y1()),
+					video::S3DVertex(-BS/2*f.visual_scale,-BS/2,0, 0,0,0, c, 0,1),
+					video::S3DVertex( BS/2*f.visual_scale,-BS/2,0, 0,0,0, c, 1,1),
 					video::S3DVertex( BS/2*f.visual_scale,
-						-BS/2 + f.visual_scale*BS,0, 0,0,0, c,
-						ap.x1(), ap.y0()),
+						-BS/2 + f.visual_scale*BS,0, 0,0,0, c, 1,0),
 					video::S3DVertex(-BS/2*f.visual_scale,
-						-BS/2 + f.visual_scale*BS,0, 0,0,0, c,
-						ap.x0(), ap.y0()),
+						-BS/2 + f.visual_scale*BS,0, 0,0,0, c, 0,0),
 				};
 
 				if(j == 0)
@@ -1088,10 +1041,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 			
 			// A hack to put wood the right way around in the posts
 			ITextureSource *tsrc = data->m_gamedef->tsrc();
+			std::string texturestring_rot = tsrc->getTextureName(
+					tile.texture_id) + "^[transformR90";
 			TileSpec tile_rot = tile;
-			tile_rot.texture = tsrc->getTexture(tsrc->getTextureName(
-					tile.texture.id) + "^[transformR90");
-					
+			tile_rot.texture = tsrc->getTexture(
+					texturestring_rot,
+					&tile_rot.texture_id);
+			
 			u16 l = getInteriorLight(n, 1, data);
 			video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
 
@@ -1341,8 +1297,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 			tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
 			tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
 
-			AtlasPointer ap = tile.texture;
-			
 			u16 l = getInteriorLight(n, 0, data);
 			video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
 
@@ -1354,14 +1308,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 
 			video::S3DVertex vertices[4] =
 			{
-					video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c,
-							ap.x0(), ap.y1()),
-					video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c,
-							ap.x1(), ap.y1()),
-					video::S3DVertex(BS/2,g*BS/2+d,BS/2, 0,0,0, c,
-							ap.x1(), ap.y0()),
-					video::S3DVertex(-BS/2,g*BS/2+d,BS/2, 0,0,0, c,
-							ap.x0(), ap.y0()),
+					video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c, 0,1),
+					video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c, 1,1),
+					video::S3DVertex(BS/2,g*BS/2+d,BS/2, 0,0,0, c, 1,0),
+					video::S3DVertex(-BS/2,g*BS/2+d,BS/2, 0,0,0, c, 0,0),
 			};
 
 			for(s32 i=0; i<4; i++)
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 501a04f51..44f5d1e86 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -94,7 +94,6 @@ void set_default_settings(Settings *settings)
 	settings->setDefault("new_style_water", "false");
 	settings->setDefault("new_style_leaves", "true");
 	settings->setDefault("smooth_lighting", "true");
-	settings->setDefault("enable_texture_atlas", "false");
 	settings->setDefault("texture_path", "");
 	settings->setDefault("shader_path", "");
 	settings->setDefault("video_driver", "opengl");
diff --git a/src/farmesh.cpp b/src/farmesh.cpp
index ecf01ee07..93c50e5d0 100644
--- a/src/farmesh.cpp
+++ b/src/farmesh.cpp
@@ -65,7 +65,7 @@ FarMesh::FarMesh(
 	m_materials[1].setFlag(video::EMF_BACK_FACE_CULLING, false);
 	m_materials[1].setFlag(video::EMF_BILINEAR_FILTER, false);
 	m_materials[1].setFlag(video::EMF_FOG_ENABLE, false);
-	m_materials[1].setTexture(0, client->tsrc()->getTextureRaw("treeprop.png"));
+	m_materials[1].setTexture(0, client->tsrc()->getTexture("treeprop.png"));
 	m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
 	m_materials[1].setFlag(video::EMF_FOG_ENABLE, true);
 
diff --git a/src/game.cpp b/src/game.cpp
index 65b52777a..bcd155a79 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -1345,7 +1345,7 @@ void the_game(
 	*/
 	int crack_animation_length = 5;
 	{
-		video::ITexture *t = tsrc->getTextureRaw("crack_anylength.png");
+		video::ITexture *t = tsrc->getTexture("crack_anylength.png");
 		v2u32 size = t->getOriginalSize();
 		crack_animation_length = size.Y / size.X;
 	}
@@ -2312,7 +2312,7 @@ void the_game(
 				else if(event.type == CE_SPAWN_PARTICLE)
 				{
 					LocalPlayer* player = client.getEnv().getLocalPlayer();
-					AtlasPointer ap =
+					video::ITexture *texture =
 						gamedef->tsrc()->getTexture(*(event.spawn_particle.texture));
 
 					new Particle(gamedef, smgr, player, client.getEnv(),
@@ -2321,12 +2321,15 @@ void the_game(
 						*event.spawn_particle.acc,
 						 event.spawn_particle.expirationtime,
 						 event.spawn_particle.size,
-						 event.spawn_particle.collisiondetection, ap);
+						 event.spawn_particle.collisiondetection,
+						 texture,
+						 v2f(0.0, 0.0),
+						 v2f(1.0, 1.0));
 				}
 				else if(event.type == CE_ADD_PARTICLESPAWNER)
 				{
 					LocalPlayer* player = client.getEnv().getLocalPlayer();
-					AtlasPointer ap =
+					video::ITexture *texture =
 						gamedef->tsrc()->getTexture(*(event.add_particlespawner.texture));
 
 					new ParticleSpawner(gamedef, smgr, player,
@@ -2343,7 +2346,7 @@ void the_game(
 						 event.add_particlespawner.minsize,
 						 event.add_particlespawner.maxsize,
 						 event.add_particlespawner.collisiondetection,
-						 ap,
+						 texture,
 						 event.add_particlespawner.id);
 				}
 				else if(event.type == CE_DELETE_PARTICLESPAWNER)
diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp
index c1b256f08..ee39df8b7 100644
--- a/src/guiFormSpecMenu.cpp
+++ b/src/guiFormSpecMenu.cpp
@@ -519,7 +519,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
 			if(type == "image_button_exit")
 				spec.is_exit = true;
 			
-			video::ITexture *texture = m_gamedef->tsrc()->getTextureRaw(fimage);
+			video::ITexture *texture = m_gamedef->tsrc()->getTexture(fimage);
 			gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
 			e->setUseAlphaChannel(true);
 			e->setImage(texture);
@@ -805,7 +805,7 @@ void GUIFormSpecMenu::drawMenu()
 	{
 		const ImageDrawSpec &spec = m_backgrounds[i];
 		video::ITexture *texture =
-				m_gamedef->tsrc()->getTextureRaw(spec.name);
+				m_gamedef->tsrc()->getTexture(spec.name);
 		// Image size on screen
 		core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
 		// Image rectangle on screen
@@ -825,7 +825,7 @@ void GUIFormSpecMenu::drawMenu()
 	{
 		const ImageDrawSpec &spec = m_images[i];
 		video::ITexture *texture =
-				m_gamedef->tsrc()->getTextureRaw(spec.name);
+				m_gamedef->tsrc()->getTexture(spec.name);
 		// Image size on screen
 		core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
 		// Image rectangle on screen
diff --git a/src/hud.cpp b/src/hud.cpp
index 9404ed997..f1a4ab523 100644
--- a/src/hud.cpp
+++ b/src/hud.cpp
@@ -178,7 +178,7 @@ void Hud::drawLuaElements() {
 		v2s32 pos(e->pos.X * screensize.X, e->pos.Y * screensize.Y);
 		switch (e->type) {
 			case HUD_ELEM_IMAGE: {
-				video::ITexture *texture = tsrc->getTextureRaw(e->text);
+				video::ITexture *texture = tsrc->getTexture(e->text);
 				if (!texture)
 					continue;
 
@@ -228,7 +228,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s
 	const video::SColor color(255, 255, 255, 255);
 	const video::SColor colors[] = {color, color, color, color};
 	
-	video::ITexture *stat_texture = tsrc->getTextureRaw(texture);
+	video::ITexture *stat_texture = tsrc->getTexture(texture);
 	if (!stat_texture)
 		return;
 		
@@ -306,7 +306,7 @@ void Hud::drawCrosshair() {
 		return;
 		
 	if (use_crosshair_image) {
-		video::ITexture *crosshair = tsrc->getTextureRaw("crosshair.png");
+		video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
 		v2u32 size  = crosshair->getOriginalSize();
 		v2s32 lsize = v2s32(displaycenter.X - (size.X / 2),
 							displaycenter.Y - (size.Y / 2));
diff --git a/src/itemdef.cpp b/src/itemdef.cpp
index d660db77f..b582aef78 100644
--- a/src/itemdef.cpp
+++ b/src/itemdef.cpp
@@ -341,7 +341,7 @@ class CItemDefManager: public IWritableItemDefManager
 		cc->inventory_texture = NULL;
 		if(def->inventory_image != "")
 		{
-			cc->inventory_texture = tsrc->getTextureRaw(def->inventory_image);
+			cc->inventory_texture = tsrc->getTexture(def->inventory_image);
 		}
 		else if(def->type == ITEM_NODE)
 		{
@@ -365,7 +365,7 @@ class CItemDefManager: public IWritableItemDefManager
 				imagename = def->inventory_image;
 
 			cc->wield_mesh = createExtrudedMesh(
-					tsrc->getTextureRaw(imagename),
+					tsrc->getTexture(imagename),
 					driver,
 					def->wield_scale * v3f(40.0, 40.0, 4.0));
 			if(cc->wield_mesh == NULL)
@@ -446,7 +446,7 @@ class CItemDefManager: public IWritableItemDefManager
 				if(cc->inventory_texture == NULL)
 				{
 					cc->inventory_texture =
-						tsrc->getTextureRaw(f.tiledef[0].name);
+						tsrc->getTexture(f.tiledef[0].name);
 				}
 			}
 			else
diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp
index be88b1973..a9ed75325 100644
--- a/src/mapblock_mesh.cpp
+++ b/src/mapblock_mesh.cpp
@@ -452,6 +452,11 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
 	// Position is at the center of the cube.
 	v3f pos = p * BS;
 
+	float x0 = 0.0;
+	float y0 = 0.0;
+	float w = 1.0;
+	float h = 1.0;
+
 	v3f vertex_pos[4];
 	v3s16 vertex_dirs[4];
 	getNodeVertexDirs(dir, vertex_dirs);
@@ -488,8 +493,8 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
 		vertex_dirs[3] = vertex_dirs[2];
 		vertex_dirs[2] = vertex_dirs[1];
 		vertex_dirs[1] = t;
-		tile.texture.pos.Y += tile.texture.size.Y;
-		tile.texture.size.Y *= -1;
+		y0 += h;
+		h *= -1;
 		break;
 	case 5: //FXR270
 		t = vertex_dirs[0];
@@ -497,8 +502,8 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
 		vertex_dirs[1] = vertex_dirs[2];
 		vertex_dirs[2] = vertex_dirs[3];
 		vertex_dirs[3] = t;
-		tile.texture.pos.Y += tile.texture.size.Y;
-		tile.texture.size.Y *= -1;
+		y0 += h;
+		h *= -1;
 		break;
 	case 6: //FYR90
 		t = vertex_dirs[0];
@@ -506,8 +511,8 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
 		vertex_dirs[3] = vertex_dirs[2];
 		vertex_dirs[2] = vertex_dirs[1];
 		vertex_dirs[1] = t;
-		tile.texture.pos.X += tile.texture.size.X;
-		tile.texture.size.X *= -1;
+		x0 += w;
+		w *= -1;
 		break;
 	case 7: //FYR270
 		t = vertex_dirs[0];
@@ -515,16 +520,16 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
 		vertex_dirs[1] = vertex_dirs[2];
 		vertex_dirs[2] = vertex_dirs[3];
 		vertex_dirs[3] = t;
-		tile.texture.pos.X += tile.texture.size.X;
-		tile.texture.size.X *= -1;
+		x0 += w;
+		w *= -1;
 		break;
 	case 8: //FX
-		tile.texture.pos.Y += tile.texture.size.Y;
-		tile.texture.size.Y *= -1;
+		y0 += h;
+		h *= -1;
 		break;
 	case 9: //FY
-		tile.texture.pos.X += tile.texture.size.X;
-		tile.texture.size.X *= -1;
+		x0 += w;
+		w *= -1;
 		break;
 	default:
 		break;
@@ -555,11 +560,6 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
 
 	u8 alpha = tile.alpha;
 
-	float x0 = tile.texture.pos.X;
-	float y0 = tile.texture.pos.Y;
-	float w = tile.texture.size.X;
-	float h = tile.texture.size.Y;
-
 	face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
 			MapBlock_LightColor(alpha, li0, light_source),
 			core::vector2d<f32>(x0+w*abs_scale, y0+h));
@@ -645,12 +645,6 @@ TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
 	if(p == data->m_crack_pos_relative)
 	{
 		spec.material_flags |= MATERIAL_FLAG_CRACK;
-		spec.texture = data->m_gamedef->tsrc()->getTextureRawAP(spec.texture);
-	}
-	// If animated, replace tile texture with one without texture atlas
-	if(spec.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
-	{
-		spec.texture = data->m_gamedef->tsrc()->getTextureRawAP(spec.texture);
 	}
 	return spec;
 }
@@ -717,7 +711,7 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
 	u16 tile_index=facedir*16 + dir_i;
 	TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
 	spec.rotation=dir_to_tile[tile_index + 1];
-	spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture.id);
+	spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture_id);
 	return spec;
 }
 
@@ -889,23 +883,7 @@ static void updateFastFaceRow(
 
 		continuous_tiles_count++;
 		
-		// This is set to true if the texture doesn't allow more tiling
-		bool end_of_texture = false;
-		/*
-			If there is no texture, it can be tiled infinitely.
-			If tiled==0, it means the texture can be tiled infinitely.
-			Otherwise check tiled agains continuous_tiles_count.
-		*/
-		if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
-		{
-			if(tile.texture.tiled <= continuous_tiles_count)
-				end_of_texture = true;
-		}
-		
-		// Do this to disable tiling textures
-		//end_of_texture = true; //DEBUG
-		
-		if(next_is_different || end_of_texture)
+		if(next_is_different)
 		{
 			/*
 				Create a face if there should be one
@@ -1060,7 +1038,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
 			const u16 indices[] = {0,1,2,2,3,0};
 			const u16 indices_alternate[] = {0,1,3,2,3,1};
 			
-			if(f.tile.texture.atlas == NULL)
+			if(f.tile.texture == NULL)
 				continue;
 
 			const u16 *indices_p = indices;
@@ -1112,7 +1090,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
 		if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
 		{
 			ITextureSource *tsrc = data->m_gamedef->tsrc();
-			std::string crack_basename = tsrc->getTextureName(p.tile.texture.id);
+			std::string crack_basename = tsrc->getTextureName(p.tile.texture_id);
 			if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
 				crack_basename += "^[cracko";
 			else
@@ -1137,9 +1115,11 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
 			}
 			// Replace tile texture with the first animation frame
 			std::ostringstream os(std::ios::binary);
-			os<<tsrc->getTextureName(p.tile.texture.id);
+			os<<tsrc->getTextureName(p.tile.texture_id);
 			os<<"^[verticalframe:"<<(int)p.tile.animation_frame_count<<":0";
-			p.tile.texture = tsrc->getTexture(os.str());
+			p.tile.texture = tsrc->getTexture(
+					os.str(),
+					&p.tile.texture_id);
 		}
 		// - Classic lighting (shaders handle this by themselves)
 		if(!enable_shaders)
@@ -1173,7 +1153,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
 		//material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
 		material.MaterialType
 				= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
-		material.setTexture(0, p.tile.texture.atlas);
+		material.setTexture(0, p.tile.texture);
 		if(enable_shaders)
 			p.tile.applyMaterialOptionsWithShaders(material, shadermat1, shadermat2, shadermat3);
 		else
@@ -1259,8 +1239,8 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
 			ITextureSource *tsrc = m_gamedef->getTextureSource();
 			std::ostringstream os;
 			os<<basename<<crack;
-			AtlasPointer ap = tsrc->getTexture(os.str());
-			buf->getMaterial().setTexture(0, ap.atlas);
+			buf->getMaterial().setTexture(0,
+					tsrc->getTexture(os.str()));
 		}
 
 		m_last_crack = crack;
@@ -1287,11 +1267,10 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
 
 		// Create new texture name from original
 		std::ostringstream os(std::ios::binary);
-		os<<tsrc->getTextureName(tile.texture.id);
+		os<<tsrc->getTextureName(tile.texture_id);
 		os<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame;
 		// Set the texture
-		AtlasPointer ap = tsrc->getTexture(os.str());
-		buf->getMaterial().setTexture(0, ap.atlas);
+		buf->getMaterial().setTexture(0, tsrc->getTexture(os.str()));
 	}
 
 	// Day-night transition
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index 7d8ce70d3..13e7e9958 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -674,7 +674,9 @@ class CNodeDefManager: public IWritableNodeDefManager
 			// Tiles (fill in f->tiles[])
 			for(u16 j=0; j<6; j++){
 				// Texture
-				f->tiles[j].texture = tsrc->getTexture(tiledef[j].name);
+				f->tiles[j].texture = tsrc->getTexture(
+						tiledef[j].name,
+						&f->tiles[j].texture_id);
 				// Alpha
 				f->tiles[j].alpha = f->alpha;
 				// Material type
@@ -689,10 +691,9 @@ class CNodeDefManager: public IWritableNodeDefManager
 				if(f->tiles[j].material_flags &
 						MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
 				{
-					// Get raw texture size to determine frame count by
+					// Get texture size to determine frame count by
 					// aspect ratio
-					video::ITexture *t = tsrc->getTextureRaw(tiledef[j].name);
-					v2u32 size = t->getOriginalSize();
+					v2u32 size = f->tiles[j].texture->getOriginalSize();
 					int frame_height = (float)size.X /
 							(float)tiledef[j].animation.aspect_w *
 							(float)tiledef[j].animation.aspect_h;
@@ -715,8 +716,9 @@ class CNodeDefManager: public IWritableNodeDefManager
 			// Special tiles (fill in f->special_tiles[])
 			for(u16 j=0; j<CF_SPECIAL_COUNT; j++){
 				// Texture
-				f->special_tiles[j].texture =
-						tsrc->getTexture(f->tiledef_special[j].name);
+				f->special_tiles[j].texture = tsrc->getTexture(
+						f->tiledef_special[j].name,
+						&f->special_tiles[j].texture_id);
 				// Alpha
 				f->special_tiles[j].alpha = f->alpha;
 				// Material type
@@ -731,10 +733,9 @@ class CNodeDefManager: public IWritableNodeDefManager
 				if(f->special_tiles[j].material_flags &
 						MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
 				{
-					// Get raw texture size to determine frame count by
+					// Get texture size to determine frame count by
 					// aspect ratio
-					video::ITexture *t = tsrc->getTextureRaw(f->tiledef_special[j].name);
-					v2u32 size = t->getOriginalSize();
+					v2u32 size = f->special_tiles[j].texture->getOriginalSize();
 					int frame_height = (float)size.X /
 							(float)f->tiledef_special[j].animation.aspect_w *
 							(float)f->tiledef_special[j].animation.aspect_h;
diff --git a/src/nodedef.h b/src/nodedef.h
index e397d20e0..665a5ddc2 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -312,7 +312,6 @@ class IWritableNodeDefManager : public INodeDefManager
 
 	/*
 		Update tile textures to latest return values of TextueSource.
-		Call after updating the texture atlas of a TextureSource.
 	*/
 	virtual void updateTextures(ITextureSource *tsrc)=0;
 
diff --git a/src/particles.cpp b/src/particles.cpp
index 1d814f619..88905d40d 100644
--- a/src/particles.cpp
+++ b/src/particles.cpp
@@ -57,7 +57,9 @@ Particle::Particle(
 	float expirationtime,
 	float size,
 	bool collisiondetection,
-	AtlasPointer ap
+	video::ITexture *texture,
+	v2f texpos,
+	v2f texsize
 ):
 	scene::ISceneNode(smgr->getRootSceneNode(), smgr)
 {
@@ -70,8 +72,9 @@ Particle::Particle(
 	m_material.setFlag(video::EMF_BILINEAR_FILTER, false);
 	m_material.setFlag(video::EMF_FOG_ENABLE, true);
 	m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
-	m_material.setTexture(0, ap.atlas);
-	m_ap = ap;
+	m_material.setTexture(0, texture);
+	m_texpos = texpos;
+	m_texsize = texsize;
 
 
 	// Particle related
@@ -180,14 +183,19 @@ void Particle::updateLight(ClientEnvironment &env)
 void Particle::updateVertices()
 {
 	video::SColor c(255, m_light, m_light, m_light);
+	f32 tx0 = m_texpos.X;
+	f32 tx1 = m_texpos.X + m_texsize.X;
+	f32 ty0 = m_texpos.Y;
+	f32 ty1 = m_texpos.Y + m_texsize.Y;
+
 	m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0,
-			c, m_ap.x0(), m_ap.y1());
+			c, tx0, ty1);
 	m_vertices[1] = video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0,
-			c, m_ap.x1(), m_ap.y1());
+			c, tx1, ty1);
 	m_vertices[2] = video::S3DVertex(m_size/2,m_size/2,0, 0,0,0,
-			c, m_ap.x1(), m_ap.y0());
+			c, tx1, ty0);
 	m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0,
-			c ,m_ap.x0(), m_ap.y0());
+			c, tx0, ty0);
 
 	for(u16 i=0; i<4; i++)
 	{
@@ -248,19 +256,19 @@ void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
 {
 	// Texture
 	u8 texid = myrand_range(0,5);
-	AtlasPointer ap = tiles[texid].texture;
-	float size = rand()%64/512.;
-	float visual_size = BS*size;
-	float texsize = size*2;
+	video::ITexture *texture = tiles[texid].texture;
 
-	float x1 = ap.x1();
-	float y1 = ap.y1();
+	// Only use first frame of animated texture
+	f32 ymax = 1;
+	if(tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
+		ymax /= tiles[texid].animation_frame_count;
 
-	ap.size.X = (ap.x1() - ap.x0()) * texsize;
-	ap.size.Y = (ap.x1() - ap.x0()) * texsize;
-
-	ap.pos.X = ap.x0() + (x1 - ap.x0()) * ((rand()%64)/64.-texsize);
-	ap.pos.Y = ap.y0() + (y1 - ap.y0()) * ((rand()%64)/64.-texsize);
+	float size = rand()%64/512.;
+	float visual_size = BS*size;
+	v2f texsize(size*2, ymax*size*2);
+	v2f texpos;
+	texpos.X = ((rand()%64)/64.-texsize.X);
+	texpos.Y = ymax*((rand()%64)/64.-texsize.Y);
 
 	// Physics
 	v3f velocity(	(rand()%100/50.-1)/1.5,
@@ -285,7 +293,9 @@ void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
 		rand()%100/100., // expiration time
 		visual_size,
 		true,
-		ap);
+		texture,
+		texpos,
+		texsize);
 }
 
 /*
@@ -296,7 +306,7 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
 	u16 amount, float time,
 	v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
 	float minexptime, float maxexptime, float minsize, float maxsize,
-	bool collisiondetection, AtlasPointer ap, u32 id)
+	bool collisiondetection, video::ITexture *texture, u32 id)
 {
 	m_gamedef = gamedef;
 	m_smgr = smgr;
@@ -314,7 +324,7 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
 	m_minsize = minsize;
 	m_maxsize = maxsize;
 	m_collisiondetection = collisiondetection;
-	m_ap = ap;
+	m_texture = texture;
 	m_time = 0;
 
 	for (u16 i = 0; i<=m_amount; i++)
@@ -362,7 +372,9 @@ void ParticleSpawner::step(float dtime, ClientEnvironment &env)
 					exptime,
 					size,
 					m_collisiondetection,
-					m_ap);
+					m_texture,
+					v2f(0.0, 0.0),
+					v2f(1.0, 1.0));
 				m_spawntimes.erase(i);
 			}
 			else
@@ -398,7 +410,9 @@ void ParticleSpawner::step(float dtime, ClientEnvironment &env)
 					exptime,
 					size,
 					m_collisiondetection,
-					m_ap);
+					m_texture,
+					v2f(0.0, 0.0),
+					v2f(1.0, 1.0));
 			}
 		}
 	}
diff --git a/src/particles.h b/src/particles.h
index 308da551f..327dcbc9e 100644
--- a/src/particles.h
+++ b/src/particles.h
@@ -42,7 +42,9 @@ class Particle : public scene::ISceneNode
 		float expirationtime,
 		float size,
 		bool collisiondetection,
-		AtlasPointer texture
+		video::ITexture *texture,
+		v2f texpos,
+		v2f texsize
 	);
 	~Particle();
 
@@ -81,16 +83,13 @@ class Particle : public scene::ISceneNode
 	core::aabbox3d<f32> m_box;
 	core::aabbox3d<f32> m_collisionbox;
 	video::SMaterial m_material;
+	v2f m_texpos;
+	v2f m_texsize;
 	v3f m_pos;
 	v3f m_velocity;
 	v3f m_acceleration;
-	float tex_x0;
-	float tex_x1;
-	float tex_y0;
-	float tex_y1;
 	LocalPlayer *m_player;
 	float m_size;
-	AtlasPointer m_ap;
 	u8 m_light;
 	bool m_collisiondetection;
 };
@@ -109,7 +108,7 @@ class ParticleSpawner
 		float minexptime, float maxexptime,
 		float minsize, float maxsize,
 		bool collisiondetection,
-		AtlasPointer ap,
+		video::ITexture *texture,
 		u32 id);
 
 	~ParticleSpawner();
@@ -136,7 +135,7 @@ class ParticleSpawner
 	float m_maxexptime;
 	float m_minsize;
 	float m_maxsize;
-	AtlasPointer m_ap;
+	video::ITexture *m_texture;
 	std::vector<float> m_spawntimes;
 	bool m_collisiondetection;
 };
diff --git a/src/tile.cpp b/src/tile.cpp
index f176d1549..da286fda9 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -25,8 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mesh.h"
 #include <ICameraSceneNode.h>
 #include "log.h"
-#include "mapnode.h" // For texture atlas making
-#include "nodedef.h" // For texture atlas making
 #include "gamedef.h"
 #include "util/string.h"
 #include "util/container.h"
@@ -165,31 +163,23 @@ std::string getTexturePath(const std::string &filename)
 }
 
 /*
-	An internal variant of AtlasPointer with more data.
-	(well, more like a wrapper)
+	Stores internal information about a texture.
 */
 
-struct SourceAtlasPointer
+struct TextureInfo
 {
 	std::string name;
-	AtlasPointer a;
-	video::IImage *atlas_img; // The source image of the atlas
-	// Integer variants of position and size
-	v2s32 intpos;
-	v2u32 intsize;
+	video::ITexture *texture;
+	video::IImage *img; // The source image
 
-	SourceAtlasPointer(
+	TextureInfo(
 			const std::string &name_,
-			AtlasPointer a_=AtlasPointer(0, NULL),
-			video::IImage *atlas_img_=NULL,
-			v2s32 intpos_=v2s32(0,0),
-			v2u32 intsize_=v2u32(0,0)
+			video::ITexture *texture_=NULL,
+			video::IImage *img_=NULL
 		):
 		name(name_),
-		a(a_),
-		atlas_img(atlas_img_),
-		intpos(intpos_),
-		intsize(intsize_)
+		texture(texture_),
+		img(img_)
 	{
 	}
 };
@@ -307,7 +297,7 @@ class TextureSource : public IWritableTextureSource
 
 		Example case #2:
 		- Assume a texture with the id 1 exists, and has the name
-		  "stone.png^mineral1" and is specified as a part of some atlas.
+		  "stone.png^mineral_coal.png".
 		- Now getNodeTile() stumbles upon a node which uses
 		  texture id 1, and determines that MATERIAL_FLAG_CRACK
 		  must be applied to the tile
@@ -315,7 +305,7 @@ class TextureSource : public IWritableTextureSource
 		  has received the current crack level 0 from the client. It
 		  finds out the name of the texture with getTextureName(1),
 		  appends "^crack0" to it and gets a new texture id with
-		  getTextureId("stone.png^mineral1^crack0").
+		  getTextureId("stone.png^mineral_coal.png^crack0").
 
 	*/
 	
@@ -354,25 +344,9 @@ class TextureSource : public IWritableTextureSource
 		and not found in cache, the call is queued to the main thread
 		for processing.
 	*/
-	AtlasPointer getTexture(u32 id);
-	
-	AtlasPointer getTexture(const std::string &name)
-	{
-		return getTexture(getTextureId(name));
-	}
-	
-	// Gets a separate texture
-	video::ITexture* getTextureRaw(const std::string &name)
-	{
-		AtlasPointer ap = getTexture(name + m_forcesingle_suffix);
-		return ap.atlas;
-	}
+	video::ITexture* getTexture(u32 id);
 
-	// Gets a separate texture atlas pointer
-	AtlasPointer getTextureRawAP(const AtlasPointer &ap)
-	{
-		return getTexture(getTextureName(ap.id) + m_forcesingle_suffix);
-	}
+	video::ITexture* getTexture(const std::string &name, u32 *id);
 
 	// Returns a pointer to the irrlicht device
 	virtual IrrlichtDevice* getDevice()
@@ -380,10 +354,6 @@ class TextureSource : public IWritableTextureSource
 		return m_device;
 	}
 
-	// Update new texture pointer and texture coordinates to an
-	// AtlasPointer based on it's texture id
-	void updateAP(AtlasPointer &ap);
- 
 	bool isKnownSourceImage(const std::string &name)
 	{
 		bool is_known = false;
@@ -407,10 +377,6 @@ class TextureSource : public IWritableTextureSource
 	// Rebuild images and textures from the current set of source images
 	// Shall be called from the main thread.
 	void rebuildImagesAndTextures();
-
-	// Build the main texture atlas which contains most of the
-	// textures.
-	void buildMainAtlas(class IGameDef *gamedef);
 	
 private:
 	
@@ -428,17 +394,12 @@ class TextureSource : public IWritableTextureSource
 
 	// A texture id is index in this array.
 	// The first position contains a NULL texture.
-	std::vector<SourceAtlasPointer> m_atlaspointer_cache;
+	std::vector<TextureInfo> m_textureinfo_cache;
 	// Maps a texture name to an index in the former.
 	std::map<std::string, u32> m_name_to_id;
 	// The two former containers are behind this mutex
-	JMutex m_atlaspointer_cache_mutex;
+	JMutex m_textureinfo_cache_mutex;
 	
-	// Main texture atlas. This is filled at startup and is then not touched.
-	video::IImage *m_main_atlas_image;
-	video::ITexture *m_main_atlas_texture;
-	std::string m_forcesingle_suffix;
-
 	// Queued texture fetches (to be processed by the main thread)
 	RequestQueue<std::string, u32, u8, u8> m_get_texture_queue;
 
@@ -453,18 +414,16 @@ IWritableTextureSource* createTextureSource(IrrlichtDevice *device)
 }
 
 TextureSource::TextureSource(IrrlichtDevice *device):
-		m_device(device),
-		m_main_atlas_image(NULL),
-		m_main_atlas_texture(NULL)
+		m_device(device)
 {
 	assert(m_device);
 	
-	m_atlaspointer_cache_mutex.Init();
+	m_textureinfo_cache_mutex.Init();
 	
 	m_main_thread = get_current_thread_id();
 	
-	// Add a NULL AtlasPointer as the first index, named ""
-	m_atlaspointer_cache.push_back(SourceAtlasPointer(""));
+	// Add a NULL TextureInfo as the first index, named ""
+	m_textureinfo_cache.push_back(TextureInfo(""));
 	m_name_to_id[""] = 0;
 }
 
@@ -474,21 +433,19 @@ TextureSource::~TextureSource()
 
 	unsigned int textures_before = driver->getTextureCount();
 
-	for (std::vector<SourceAtlasPointer>::iterator iter =
-			m_atlaspointer_cache.begin();  iter != m_atlaspointer_cache.end();
-			iter++)
+	for (std::vector<TextureInfo>::iterator iter =
+			m_textureinfo_cache.begin();
+			iter != m_textureinfo_cache.end(); iter++)
 	{
-		video::ITexture *t = driver->getTexture(iter->name.c_str());
-
 		//cleanup texture
-		if (t)
-			driver->removeTexture(t);
+		if (iter->texture)
+			driver->removeTexture(iter->texture);
 
 		//cleanup source image
-		if (iter->atlas_img)
-			iter->atlas_img->drop();
+		if (iter->img)
+			iter->img->drop();
 	}
-	m_atlaspointer_cache.clear();
+	m_textureinfo_cache.clear();
 
 	for (std::list<video::ITexture*>::iterator iter =
 			m_texture_trash.begin(); iter != m_texture_trash.end();
@@ -512,7 +469,7 @@ u32 TextureSource::getTextureId(const std::string &name)
 		/*
 			See if texture already exists
 		*/
-		JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+		JMutexAutoLock lock(m_textureinfo_cache_mutex);
 		std::map<std::string, u32>::iterator n;
 		n = m_name_to_id.find(name);
 		if(n != m_name_to_id.end())
@@ -591,8 +548,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
 /*
 	Generates an image from a full string like
 	"stone.png^mineral_coal.png^[crack0".
-
-	This is used by buildMainAtlas().
 */
 video::IImage* generate_image_from_scratch(std::string name,
 		IrrlichtDevice *device, SourceImageCache *sourcecache);
@@ -625,7 +580,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
 		See if texture already exists
 	*/
 	{
-		JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+		JMutexAutoLock lock(m_textureinfo_cache_mutex);
 
 		std::map<std::string, u32>::iterator n;
 		n = m_name_to_id.find(name);
@@ -693,13 +648,11 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
 	// If a base image was found, copy it to baseimg
 	if(base_image_id != 0)
 	{
-		JMutexAutoLock lock(m_atlaspointer_cache_mutex);
-
-		SourceAtlasPointer ap = m_atlaspointer_cache[base_image_id];
+		JMutexAutoLock lock(m_textureinfo_cache_mutex);
 
-		video::IImage *image = ap.atlas_img;
+		TextureInfo *ti = &m_textureinfo_cache[base_image_id];
 		
-		if(image == NULL)
+		if(ti->img == NULL)
 		{
 			infostream<<"getTextureIdDirect(): WARNING: NULL image in "
 					<<"cache: \""<<base_image_name<<"\""
@@ -707,17 +660,14 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
 		}
 		else
 		{
-			core::dimension2d<u32> dim = ap.intsize;
+			core::dimension2d<u32> dim = ti->img->getDimension();
 
 			baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
 
-			core::position2d<s32> pos_to(0,0);
-			core::position2d<s32> pos_from = ap.intpos;
-			
-			image->copyTo(
+			ti->img->copyTo(
 					baseimg, // target
 					v2s32(0,0), // position in target
-					core::rect<s32>(pos_from, dim) // from
+					core::rect<s32>(v2s32(0,0), dim) // from
 			);
 
 			/*infostream<<"getTextureIdDirect(): Loaded \""
@@ -759,19 +709,11 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
 		Add texture to caches (add NULL textures too)
 	*/
 
-	JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+	JMutexAutoLock lock(m_textureinfo_cache_mutex);
 	
-	u32 id = m_atlaspointer_cache.size();
-	AtlasPointer ap(id);
-	ap.atlas = t;
-	ap.pos = v2f(0,0);
-	ap.size = v2f(1,1);
-	ap.tiled = 0;
-	core::dimension2d<u32> baseimg_dim(0,0);
-	if(baseimg)
-		baseimg_dim = baseimg->getDimension();
-	SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg_dim);
-	m_atlaspointer_cache.push_back(nap);
+	u32 id = m_textureinfo_cache.size();
+	TextureInfo ti(name, t, baseimg);
+	m_textureinfo_cache.push_back(ti);
 	m_name_to_id[name] = id;
 
 	/*infostream<<"getTextureIdDirect(): "
@@ -782,34 +724,36 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
 
 std::string TextureSource::getTextureName(u32 id)
 {
-	JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+	JMutexAutoLock lock(m_textureinfo_cache_mutex);
 
-	if(id >= m_atlaspointer_cache.size())
+	if(id >= m_textureinfo_cache.size())
 	{
 		errorstream<<"TextureSource::getTextureName(): id="<<id
-				<<" >= m_atlaspointer_cache.size()="
-				<<m_atlaspointer_cache.size()<<std::endl;
+				<<" >= m_textureinfo_cache.size()="
+				<<m_textureinfo_cache.size()<<std::endl;
 		return "";
 	}
 	
-	return m_atlaspointer_cache[id].name;
+	return m_textureinfo_cache[id].name;
 }
 
-
-AtlasPointer TextureSource::getTexture(u32 id)
+video::ITexture* TextureSource::getTexture(u32 id)
 {
-	JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+	JMutexAutoLock lock(m_textureinfo_cache_mutex);
 
-	if(id >= m_atlaspointer_cache.size())
-		return AtlasPointer(0, NULL);
-	
-	return m_atlaspointer_cache[id].a;
+	if(id >= m_textureinfo_cache.size())
+		return NULL;
+
+	return m_textureinfo_cache[id].texture;
 }
 
-void TextureSource::updateAP(AtlasPointer &ap)
+video::ITexture* TextureSource::getTexture(const std::string &name, u32 *id)
 {
-	AtlasPointer ap2 = getTexture(ap.id);
-	ap = ap2;
+	u32 actual_id = getTextureId(name);
+	if(id){
+		*id = actual_id;
+	}
+	return getTexture(actual_id);
 }
 
 void TextureSource::processQueue()
@@ -849,299 +793,29 @@ void TextureSource::insertSourceImage(const std::string &name, video::IImage *im
 	
 void TextureSource::rebuildImagesAndTextures()
 {
-	JMutexAutoLock lock(m_atlaspointer_cache_mutex);
-
-	/*// Oh well... just clear everything, they'll load sometime.
-	m_atlaspointer_cache.clear();
-	m_name_to_id.clear();*/
+	JMutexAutoLock lock(m_textureinfo_cache_mutex);
 
 	video::IVideoDriver* driver = m_device->getVideoDriver();
-	
-	// Remove source images from textures to disable inheriting textures
-	// from existing textures
-	/*for(u32 i=0; i<m_atlaspointer_cache.size(); i++){
-		SourceAtlasPointer *sap = &m_atlaspointer_cache[i];
-		sap->atlas_img->drop();
-		sap->atlas_img = NULL;
-	}*/
-	
+
 	// Recreate textures
-	for(u32 i=0; i<m_atlaspointer_cache.size(); i++){
-		SourceAtlasPointer *sap = &m_atlaspointer_cache[i];
+	for(u32 i=0; i<m_textureinfo_cache.size(); i++){
+		TextureInfo *ti = &m_textureinfo_cache[i];
 		video::IImage *img =
-			generate_image_from_scratch(sap->name, m_device, &m_sourcecache);
+			generate_image_from_scratch(ti->name, m_device, &m_sourcecache);
 		// Create texture from resulting image
 		video::ITexture *t = NULL;
 		if(img)
-			t = driver->addTexture(sap->name.c_str(), img);
-		video::ITexture *t_old = sap->a.atlas;
+			t = driver->addTexture(ti->name.c_str(), img);
+		video::ITexture *t_old = ti->texture;
 		// Replace texture
-		sap->a.atlas = t;
-		sap->a.pos = v2f(0,0);
-		sap->a.size = v2f(1,1);
-		sap->a.tiled = 0;
-		sap->atlas_img = img;
-		sap->intpos = v2s32(0,0);
-		sap->intsize = img->getDimension();
+		ti->texture = t;
+		ti->img = img;
 
 		if (t_old != 0)
 			m_texture_trash.push_back(t_old);
 	}
 }
 
-void TextureSource::buildMainAtlas(class IGameDef *gamedef) 
-{
-	assert(gamedef->tsrc() == this);
-	INodeDefManager *ndef = gamedef->ndef();
-
-	infostream<<"TextureSource::buildMainAtlas()"<<std::endl;
-
-	//return; // Disable (for testing)
-	
-	video::IVideoDriver* driver = m_device->getVideoDriver();
-	assert(driver);
-
-	JMutexAutoLock lock(m_atlaspointer_cache_mutex);
-
-	// Create an image of the right size
-	core::dimension2d<u32> max_dim = driver->getMaxTextureSize();
-	core::dimension2d<u32> atlas_dim(2048,2048);
-	atlas_dim.Width  = MYMIN(atlas_dim.Width,  max_dim.Width);
-	atlas_dim.Height = MYMIN(atlas_dim.Height, max_dim.Height);
-	video::IImage *atlas_img =
-			driver->createImage(video::ECF_A8R8G8B8, atlas_dim);
-	//assert(atlas_img);
-	if(atlas_img == NULL)
-	{
-		errorstream<<"TextureSource::buildMainAtlas(): Failed to create atlas "
-				"image; not building texture atlas."<<std::endl;
-		return;
-	}
-
-	/*
-		Grab list of stuff to include in the texture atlas from the
-		main content features
-	*/
-
-	std::set<std::string> sourcelist;
-
-	for(u16 j=0; j<MAX_CONTENT+1; j++)
-	{
-		if(j == CONTENT_IGNORE || j == CONTENT_AIR)
-			continue;
-		const ContentFeatures &f = ndef->get(j);
-		for(u32 i=0; i<6; i++)
-		{
-			std::string name = f.tiledef[i].name;
-			sourcelist.insert(name);
-		}
-	}
-	
-	infostream<<"Creating texture atlas out of textures: ";
-	for(std::set<std::string>::iterator
-			i = sourcelist.begin();
-			i != sourcelist.end(); ++i)
-	{
-		std::string name = *i;
-		infostream<<"\""<<name<<"\" ";
-	}
-	infostream<<std::endl;
-
-	// Padding to disallow texture bleeding
-	// (16 needed if mipmapping is used; otherwise less will work too)
-	s32 padding = 16;
-	s32 column_padding = 16;
-	s32 column_width = 256; // Space for 16 pieces of 16x16 textures
-
-	/*
-		First pass: generate almost everything
-	*/
-	core::position2d<s32> pos_in_atlas(0,0);
-	
-	pos_in_atlas.X = column_padding;
-	pos_in_atlas.Y = padding;
-
-	for(std::set<std::string>::iterator
-			i = sourcelist.begin();
-			i != sourcelist.end(); ++i)
-	{
-		std::string name = *i;
-
-		// Generate image by name
-		video::IImage *img2 = generate_image_from_scratch(name, m_device,
-				&m_sourcecache);
-		if(img2 == NULL)
-		{
-			errorstream<<"TextureSource::buildMainAtlas(): "
-					<<"Couldn't generate image \""<<name<<"\""<<std::endl;
-			continue;
-		}
-
-		core::dimension2d<u32> dim = img2->getDimension();
-
-		// Don't add to atlas if image is too large
-		core::dimension2d<u32> max_size_in_atlas(64,64);
-		if(dim.Width > max_size_in_atlas.Width
-		|| dim.Height > max_size_in_atlas.Height)
-		{
-			infostream<<"TextureSource::buildMainAtlas(): Not adding "
-					<<"\""<<name<<"\" because image is large"<<std::endl;
-			continue;
-		}
-
-		// Wrap columns and stop making atlas if atlas is full
-		if(pos_in_atlas.Y + dim.Height > atlas_dim.Height)
-		{
-			if(pos_in_atlas.X > (s32)atlas_dim.Width - column_width - column_padding){
-				errorstream<<"TextureSource::buildMainAtlas(): "
-						<<"Atlas is full, not adding more textures."
-						<<std::endl;
-				break;
-			}
-			pos_in_atlas.Y = padding;
-			pos_in_atlas.X += column_width + column_padding*2;
-		}
-		
-		/*infostream<<"TextureSource::buildMainAtlas(): Adding \""<<name
-				<<"\" to texture atlas"<<std::endl;*/
-
-		// Tile it a few times in the X direction
-		u16 xwise_tiling = column_width / dim.Width;
-		if(xwise_tiling > 16) // Limit to 16 (more gives no benefit)
-			xwise_tiling = 16;
-		for(u32 j=0; j<xwise_tiling; j++)
-		{
-			// Copy the copy to the atlas
-			/*img2->copyToWithAlpha(atlas_img,
-					pos_in_atlas + v2s32(j*dim.Width,0),
-					core::rect<s32>(v2s32(0,0), dim),
-					video::SColor(255,255,255,255),
-					NULL);*/
-			img2->copyTo(atlas_img,
-					pos_in_atlas + v2s32(j*dim.Width,0),
-					core::rect<s32>(v2s32(0,0), dim),
-					NULL);
-		}
-
-		// Copy the borders a few times to disallow texture bleeding
-		for(u32 side=0; side<2; side++) // top and bottom
-		for(s32 y0=0; y0<padding; y0++)
-		for(s32 x0=0; x0<(s32)xwise_tiling*(s32)dim.Width; x0++)
-		{
-			s32 dst_y;
-			s32 src_y;
-			if(side==0)
-			{
-				dst_y = y0 + pos_in_atlas.Y + dim.Height;
-				src_y = pos_in_atlas.Y + dim.Height - 1;
-			}
-			else
-			{
-				dst_y = -y0 + pos_in_atlas.Y-1;
-				src_y = pos_in_atlas.Y;
-			}
-			s32 x = x0 + pos_in_atlas.X;
-			video::SColor c = atlas_img->getPixel(x, src_y);
-			atlas_img->setPixel(x,dst_y,c);
-		}
-
-		for(u32 side=0; side<2; side++) // left and right
-		for(s32 x0=0; x0<column_padding; x0++)
-		for(s32 y0=-padding; y0<(s32)dim.Height+padding; y0++)
-		{
-			s32 dst_x;
-			s32 src_x;
-			if(side==0)
-			{
-				dst_x = x0 + pos_in_atlas.X + dim.Width*xwise_tiling;
-				src_x = pos_in_atlas.X + dim.Width*xwise_tiling - 1;
-			}
-			else
-			{
-				dst_x = -x0 + pos_in_atlas.X-1;
-				src_x = pos_in_atlas.X;
-			}
-			s32 y = y0 + pos_in_atlas.Y;
-			s32 src_y = MYMAX((int)pos_in_atlas.Y, MYMIN((int)pos_in_atlas.Y + (int)dim.Height - 1, y));
-			s32 dst_y = y;
-			video::SColor c = atlas_img->getPixel(src_x, src_y);
-			atlas_img->setPixel(dst_x,dst_y,c);
-		}
-
-		img2->drop();
-
-		/*
-			Add texture to caches
-		*/
-		
-		bool reuse_old_id = false;
-		u32 id = m_atlaspointer_cache.size();
-		// Check old id without fetching a texture
-		std::map<std::string, u32>::iterator n;
-		n = m_name_to_id.find(name);
-		// If it exists, we will replace the old definition
-		if(n != m_name_to_id.end()){
-			id = n->second;
-			reuse_old_id = true;
-			/*infostream<<"TextureSource::buildMainAtlas(): "
-					<<"Replacing old AtlasPointer"<<std::endl;*/
-		}
-
-		// Create AtlasPointer
-		AtlasPointer ap(id);
-		ap.atlas = NULL; // Set on the second pass
-		ap.pos = v2f((float)pos_in_atlas.X/(float)atlas_dim.Width,
-				(float)pos_in_atlas.Y/(float)atlas_dim.Height);
-		ap.size = v2f((float)dim.Width/(float)atlas_dim.Width,
-				(float)dim.Width/(float)atlas_dim.Height);
-		ap.tiled = xwise_tiling;
-
-		// Create SourceAtlasPointer and add to containers
-		SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
-		if(reuse_old_id)
-			m_atlaspointer_cache[id] = nap;
-		else
-			m_atlaspointer_cache.push_back(nap);
-		m_name_to_id[name] = id;
-			
-		// Increment position
-		pos_in_atlas.Y += dim.Height + padding * 2;
-	}
-
-	/*
-		Make texture
-	*/
-	video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
-	assert(t);
-
-	/*
-		Second pass: set texture pointer in generated AtlasPointers
-	*/
-	for(std::set<std::string>::iterator
-			i = sourcelist.begin();
-			i != sourcelist.end(); ++i)
-	{
-		std::string name = *i;
-		if(m_name_to_id.find(name) == m_name_to_id.end())
-			continue;
-		u32 id = m_name_to_id[name];
-		//infostream<<"id of name "<<name<<" is "<<id<<std::endl;
-		m_atlaspointer_cache[id].a.atlas = t;
-	}
-
-	/*
-		Write image to file so that it can be inspected
-	*/
-	/*std::string atlaspath = porting::path_user
-			+ DIR_DELIM + "generated_texture_atlas.png";
-	infostream<<"Removing and writing texture atlas for inspection to "
-			<<atlaspath<<std::endl;
-	fs::RecursiveDelete(atlaspath);
-	driver->writeImageToFile(atlas_img, atlaspath.c_str());*/
-
-	m_forcesingle_suffix = "^[forcesingle";
-}
-
 video::IImage* generate_image_from_scratch(std::string name,
 		IrrlichtDevice *device, SourceImageCache *sourcecache)
 {
@@ -1285,31 +959,11 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
 				<<"modification \""<<part_of_name<<"\""
 				<<std::endl;*/
 		
-		/*
-			This is the simplest of all; it just adds stuff to the
-			name so that a separate texture is created.
-
-			It is used to make textures for stuff that doesn't want
-			to implement getting the texture from a bigger texture
-			atlas.
-		*/
-		if(part_of_name == "[forcesingle")
-		{
-			// If base image is NULL, create a random color
-			if(baseimg == NULL)
-			{
-				core::dimension2d<u32> dim(1,1);
-				baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
-				assert(baseimg);
-				baseimg->setPixel(0,0, video::SColor(255,myrand()%256,
-						myrand()%256,myrand()%256));
-			}
-		}
 		/*
 			[crackN
 			Adds a cracking texture
 		*/
-		else if(part_of_name.substr(0,6) == "[crack")
+		if(part_of_name.substr(0,6) == "[crack")
 		{
 			if(baseimg == NULL)
 			{
diff --git a/src/tile.h b/src/tile.h
index 531a93172..144cb6475 100644
--- a/src/tile.h
+++ b/src/tile.h
@@ -57,69 +57,6 @@ std::string getImagePath(std::string path);
 */
 std::string getTexturePath(const std::string &filename);
 
-/*
-	Specifies a texture in an atlas.
-
-	This is used to specify single textures also.
-
-	This has been designed to be small enough to be thrown around a lot.
-*/
-struct AtlasPointer
-{
-	u32 id; // Texture id
-	video::ITexture *atlas; // Atlas in where the texture is
-	v2f pos; // Position in atlas
-	v2f size; // Size in atlas
-	u16 tiled; // X-wise tiling count. If 0, width of atlas is width of image.
-
-	AtlasPointer():
-		id(0),
-		atlas(NULL),
-		pos(0,0),
-		size(1,1),
-		tiled(1)
-	{}
-
-	AtlasPointer(
-			u16 id_,
-			video::ITexture *atlas_=NULL,
-			v2f pos_=v2f(0,0),
-			v2f size_=v2f(1,1),
-			u16 tiled_=1
-		):
-		id(id_),
-		atlas(atlas_),
-		pos(pos_),
-		size(size_),
-		tiled(tiled_)
-	{
-	}
-
-	bool operator==(const AtlasPointer &other) const
-	{
-		return (
-			id == other.id
-		);
-		/*return (
-			id == other.id &&
-			atlas == other.atlas &&
-			pos == other.pos &&
-			size == other.size &&
-			tiled == other.tiled
-		);*/
-	}
-
-	bool operator!=(const AtlasPointer &other) const
-	{
-		return !(*this == other);
-	}
-
-	float x0(){ return pos.X; }
-	float x1(){ return pos.X + size.X; }
-	float y0(){ return pos.Y; }
-	float y1(){ return pos.Y + size.Y; }
-};
-
 /*
 	TextureSource creates and caches textures.
 */
@@ -132,16 +69,14 @@ class ITextureSource
 	virtual u32 getTextureId(const std::string &name){return 0;}
 	virtual u32 getTextureIdDirect(const std::string &name){return 0;}
 	virtual std::string getTextureName(u32 id){return "";}
-	virtual AtlasPointer getTexture(u32 id){return AtlasPointer(0);}
-	virtual AtlasPointer getTexture(const std::string &name)
-		{return AtlasPointer(0);}
-	virtual video::ITexture* getTextureRaw(const std::string &name)
-		{return NULL;}
-	virtual AtlasPointer getTextureRawAP(const AtlasPointer &ap)
-		{return AtlasPointer(0);}
+	virtual video::ITexture* getTexture(u32 id){return NULL;}
+	virtual video::ITexture* getTexture(
+			const std::string &name, u32 *id = NULL){
+		if(id) *id = 0;
+		return NULL;
+	}
 	virtual IrrlichtDevice* getDevice()
 		{return NULL;}
-	virtual void updateAP(AtlasPointer &ap){};
 	virtual bool isKnownSourceImage(const std::string &name)=0;
 };
 
@@ -153,20 +88,18 @@ class IWritableTextureSource : public ITextureSource
 	virtual u32 getTextureId(const std::string &name){return 0;}
 	virtual u32 getTextureIdDirect(const std::string &name){return 0;}
 	virtual std::string getTextureName(u32 id){return "";}
-	virtual AtlasPointer getTexture(u32 id){return AtlasPointer(0);}
-	virtual AtlasPointer getTexture(const std::string &name)
-		{return AtlasPointer(0);}
-	virtual video::ITexture* getTextureRaw(const std::string &name)
-		{return NULL;}
-	virtual IrrlichtDevice* getDevice()
-		{return NULL;}
-	virtual void updateAP(AtlasPointer &ap){};
+	virtual video::ITexture* getTexture(u32 id){return NULL;}
+	virtual video::ITexture* getTexture(
+			const std::string &name, u32 *id = NULL){
+		if(id) *id = 0;
+		return NULL;
+	}
+	virtual IrrlichtDevice* getDevice(){return NULL;}
 	virtual bool isKnownSourceImage(const std::string &name)=0;
 
 	virtual void processQueue()=0;
 	virtual void insertSourceImage(const std::string &name, video::IImage *img)=0;
 	virtual void rebuildImagesAndTextures()=0;
-	virtual void buildMainAtlas(class IGameDef *gamedef)=0;
 };
 
 IWritableTextureSource* createTextureSource(IrrlichtDevice *device);
@@ -189,8 +122,6 @@ enum MaterialType{
 // Animation made up by splitting the texture to vertical frames, as
 // defined by extra parameters
 #define MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES 0x08
-// Whether liquid shader should be used
-#define MATERIAL_FLAG_
 
 /*
 	This fully defines the looks of a tile.
@@ -199,7 +130,8 @@ enum MaterialType{
 struct TileSpec
 {
 	TileSpec():
-		texture(0),
+		texture_id(0),
+		texture(NULL),
 		alpha(255),
 		material_type(TILE_MATERIAL_BASIC),
 		material_flags(
@@ -207,14 +139,16 @@ struct TileSpec
 			MATERIAL_FLAG_BACKFACE_CULLING
 		),
 		animation_frame_count(1),
-		animation_frame_length_ms(0)
+		animation_frame_length_ms(0),
+		rotation(0)
 	{
 	}
 
 	bool operator==(const TileSpec &other) const
 	{
 		return (
-			texture == other.texture &&
+			texture_id == other.texture_id &&
+			/* texture == other.texture && */
 			alpha == other.alpha &&
 			material_type == other.material_type &&
 			material_flags == other.material_flags &&
@@ -268,14 +202,8 @@ struct TileSpec
 		material.BackfaceCulling = (material_flags & MATERIAL_FLAG_BACKFACE_CULLING) ? true : false;
 	}
 	
-	// NOTE: Deprecated, i guess?
-	void setTexturePos(u8 tx_, u8 ty_, u8 tw_, u8 th_)
-	{
-		texture.pos = v2f((float)tx_/256.0, (float)ty_/256.0);
-		texture.size = v2f(((float)tw_ + 1.0)/256.0, ((float)th_ + 1.0)/256.0);
-	}
-	
-	AtlasPointer texture;
+	u32 texture_id;
+	video::ITexture *texture;
 	// Vertex alpha (when MATERIAL_ALPHA_VERTEX is used)
 	u8 alpha;
 	// Material parameters
-- 
GitLab