Browse Source

Merged mage-CompressedData into default

Alex Szpakowski 12 years ago
parent
commit
c215541d6c
41 changed files with 2477 additions and 334 deletions
  1. 73 9
      platform/macosx/love-framework.xcodeproj/project.pbxproj
  2. 1 0
      src/common/runtime.cpp
  3. 2 0
      src/common/types.h
  4. 235 0
      src/libraries/ddsparse/ddsinfo.h
  5. 358 0
      src/libraries/ddsparse/ddsparse.cpp
  6. 144 0
      src/libraries/ddsparse/ddsparse.h
  7. 1 1
      src/modules/filesystem/physfs/wrap_FileData.cpp
  8. 28 6
      src/modules/filesystem/physfs/wrap_Filesystem.cpp
  9. 1 1
      src/modules/font/wrap_GlyphData.cpp
  10. 3 0
      src/modules/graphics/Graphics.cpp
  11. 3 0
      src/modules/graphics/Graphics.h
  12. 29 1
      src/modules/graphics/opengl/Graphics.cpp
  13. 1 1
      src/modules/graphics/opengl/Graphics.h
  14. 254 109
      src/modules/graphics/opengl/Image.cpp
  15. 33 16
      src/modules/graphics/opengl/Image.h
  16. 8 0
      src/modules/graphics/opengl/OpenGL.cpp
  17. 55 10
      src/modules/graphics/opengl/wrap_Graphics.cpp
  18. 8 0
      src/modules/graphics/opengl/wrap_Image.cpp
  19. 1 0
      src/modules/graphics/opengl/wrap_Image.h
  20. 127 0
      src/modules/image/CompressedData.cpp
  21. 132 0
      src/modules/image/CompressedData.h
  22. 21 12
      src/modules/image/Image.h
  23. 8 9
      src/modules/image/ImageData.cpp
  24. 19 18
      src/modules/image/ImageData.h
  25. 70 0
      src/modules/image/magpie/CompressedData.cpp
  26. 54 0
      src/modules/image/magpie/CompressedData.h
  27. 58 70
      src/modules/image/magpie/DevilHandler.cpp
  28. 59 0
      src/modules/image/magpie/DevilHandler.h
  29. 94 0
      src/modules/image/magpie/FormatHandler.h
  30. 19 16
      src/modules/image/magpie/Image.cpp
  31. 15 7
      src/modules/image/magpie/Image.h
  32. 133 0
      src/modules/image/magpie/ImageData.cpp
  33. 16 21
      src/modules/image/magpie/ImageData.h
  34. 106 0
      src/modules/image/magpie/ddsHandler.cpp
  35. 74 0
      src/modules/image/magpie/ddsHandler.h
  36. 129 0
      src/modules/image/wrap_CompressedData.cpp
  37. 44 0
      src/modules/image/wrap_CompressedData.h
  38. 56 24
      src/modules/image/wrap_Image.cpp
  39. 3 1
      src/modules/image/wrap_Image.h
  40. 1 1
      src/modules/image/wrap_ImageData.cpp
  41. 1 1
      src/modules/sound/wrap_SoundData.cpp

+ 73 - 9
platform/macosx/love-framework.xcodeproj/project.pbxproj

@@ -134,7 +134,7 @@
 		FA08F62D16C7541400F007B5 /* wrap_SpriteBatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02C16FDB537A702F4D42534E /* wrap_SpriteBatch.cpp */; };
 		FA08F62D16C7541400F007B5 /* wrap_SpriteBatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02C16FDB537A702F4D42534E /* wrap_SpriteBatch.cpp */; };
 		FA08F62E16C7542600F007B5 /* ImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 78115E763B723C0C40AD47CF /* ImageData.cpp */; };
 		FA08F62E16C7542600F007B5 /* ImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 78115E763B723C0C40AD47CF /* ImageData.cpp */; };
 		FA08F62F16C7542600F007B5 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 505F23A73BFE250833D650E4 /* Image.cpp */; };
 		FA08F62F16C7542600F007B5 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 505F23A73BFE250833D650E4 /* Image.cpp */; };
-		FA08F63016C7542600F007B5 /* ImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA7781A230065F346E2313A /* ImageData.cpp */; };
+		FA08F63016C7542600F007B5 /* DevilHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA7781A230065F346E2313A /* DevilHandler.cpp */; };
 		FA08F63116C7542600F007B5 /* wrap_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0B0728FA73B107B37A956A09 /* wrap_Image.cpp */; };
 		FA08F63116C7542600F007B5 /* wrap_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0B0728FA73B107B37A956A09 /* wrap_Image.cpp */; };
 		FA08F63216C7542600F007B5 /* wrap_ImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 076840774B0B6E721D0C18D0 /* wrap_ImageData.cpp */; };
 		FA08F63216C7542600F007B5 /* wrap_ImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 076840774B0B6E721D0C18D0 /* wrap_ImageData.cpp */; };
 		FA08F63316C7542D00F007B5 /* Joystick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 677F545C76EA3B247329358D /* Joystick.cpp */; };
 		FA08F63316C7542D00F007B5 /* Joystick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 677F545C76EA3B247329358D /* Joystick.cpp */; };
@@ -209,6 +209,7 @@
 		FA08F67A16C754B100F007B5 /* wrap_Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 695E4ED13AA0689E64280573 /* wrap_Timer.cpp */; };
 		FA08F67A16C754B100F007B5 /* wrap_Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 695E4ED13AA0689E64280573 /* wrap_Timer.cpp */; };
 		FA08F67B16C754BA00F007B5 /* Window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 351B09E51FDC338622F44624 /* Window.cpp */; };
 		FA08F67B16C754BA00F007B5 /* Window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 351B09E51FDC338622F44624 /* Window.cpp */; };
 		FA08F67C16C754BA00F007B5 /* Window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6CDD4F3320303D222C180CD0 /* Window.cpp */; };
 		FA08F67C16C754BA00F007B5 /* Window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6CDD4F3320303D222C180CD0 /* Window.cpp */; };
+		FA0CDE3D1710F9A50056E8D7 /* FormatHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0CDE3B1710F9A50056E8D7 /* FormatHandler.h */; };
 		FA5454C216F1310000D30303 /* MathModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA5454C016F1310000D30303 /* MathModule.cpp */; };
 		FA5454C216F1310000D30303 /* MathModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA5454C016F1310000D30303 /* MathModule.cpp */; };
 		FA5454C316F1310000D30303 /* MathModule.h in Headers */ = {isa = PBXBuildFile; fileRef = FA5454C116F1310000D30303 /* MathModule.h */; };
 		FA5454C316F1310000D30303 /* MathModule.h in Headers */ = {isa = PBXBuildFile; fileRef = FA5454C116F1310000D30303 /* MathModule.h */; };
 		FA577AB016C7507900860150 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7916C71A1700860150 /* Cocoa.framework */; };
 		FA577AB016C7507900860150 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7916C71A1700860150 /* Cocoa.framework */; };
@@ -225,7 +226,20 @@
 		FA577ACD16C7514C00860150 /* Vorbis.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7716C71A0800860150 /* Vorbis.framework */; };
 		FA577ACD16C7514C00860150 /* Vorbis.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7716C71A0800860150 /* Vorbis.framework */; };
 		FA7C937A16DCC6C2006F2BEE /* wrap_Math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */; };
 		FA7C937A16DCC6C2006F2BEE /* wrap_Math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */; };
 		FA7C937B16DCC6C2006F2BEE /* wrap_Math.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7C937616DCC6C2006F2BEE /* wrap_Math.h */; };
 		FA7C937B16DCC6C2006F2BEE /* wrap_Math.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7C937616DCC6C2006F2BEE /* wrap_Math.h */; };
+		FAAC6B02170A373B008A61C5 /* CompressedData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAAC6B00170A373A008A61C5 /* CompressedData.cpp */; };
+		FAAC6B03170A373B008A61C5 /* CompressedData.h in Headers */ = {isa = PBXBuildFile; fileRef = FAAC6B01170A373A008A61C5 /* CompressedData.h */; };
 		FAAFF04416CB11C700CCDE45 /* OpenAL-Soft.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAAFF04316CB11C700CCDE45 /* OpenAL-Soft.framework */; };
 		FAAFF04416CB11C700CCDE45 /* OpenAL-Soft.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAAFF04316CB11C700CCDE45 /* OpenAL-Soft.framework */; };
+		FAE010DB170DDE99006F29D0 /* ddsinfo.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE010D8170DDE99006F29D0 /* ddsinfo.h */; };
+		FAE010DC170DDE99006F29D0 /* ddsparse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE010D9170DDE99006F29D0 /* ddsparse.cpp */; };
+		FAE010DD170DDE99006F29D0 /* ddsparse.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE010DA170DDE99006F29D0 /* ddsparse.h */; };
+		FAE010E0170DE25E006F29D0 /* ddsHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE010DE170DE25E006F29D0 /* ddsHandler.cpp */; };
+		FAE010E1170DE25E006F29D0 /* ddsHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE010DF170DE25E006F29D0 /* ddsHandler.h */; };
+		FAE010E4170DF75C006F29D0 /* wrap_CompressedData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE010E2170DF75B006F29D0 /* wrap_CompressedData.cpp */; };
+		FAE010E5170DF75C006F29D0 /* wrap_CompressedData.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE010E3170DF75C006F29D0 /* wrap_CompressedData.h */; };
+		FAEC808A1710FEA60057279A /* ImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAEC80881710FEA60057279A /* ImageData.cpp */; };
+		FAEC808B1710FEA60057279A /* ImageData.h in Headers */ = {isa = PBXBuildFile; fileRef = FAEC80891710FEA60057279A /* ImageData.h */; };
+		FAEC808E1711E76C0057279A /* CompressedData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAEC808C1711E76C0057279A /* CompressedData.cpp */; };
+		FAEC808F1711E76C0057279A /* CompressedData.h in Headers */ = {isa = PBXBuildFile; fileRef = FAEC808D1711E76C0057279A /* CompressedData.h */; };
 		FAF272A416E3D44400CC193A /* Channel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF2729816E3D44400CC193A /* Channel.cpp */; };
 		FAF272A416E3D44400CC193A /* Channel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF2729816E3D44400CC193A /* Channel.cpp */; };
 		FAF272A516E3D44400CC193A /* Channel.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF2729916E3D44400CC193A /* Channel.h */; };
 		FAF272A516E3D44400CC193A /* Channel.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF2729916E3D44400CC193A /* Channel.h */; };
 		FAF272A616E3D44400CC193A /* LuaThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF2729A16E3D44400CC193A /* LuaThread.cpp */; };
 		FAF272A616E3D44400CC193A /* LuaThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF2729A16E3D44400CC193A /* LuaThread.cpp */; };
@@ -344,7 +358,7 @@
 		1A95437F513E662113AC154A /* b2Rope.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = b2Rope.h; sourceTree = "<group>"; };
 		1A95437F513E662113AC154A /* b2Rope.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = b2Rope.h; sourceTree = "<group>"; };
 		1A9810F758AC1D1E4B6431FD /* wrap_Graphics.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Graphics.cpp; sourceTree = "<group>"; };
 		1A9810F758AC1D1E4B6431FD /* wrap_Graphics.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Graphics.cpp; sourceTree = "<group>"; };
 		1AA213FC158815FA77C40330 /* ChainShape.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ChainShape.h; sourceTree = "<group>"; };
 		1AA213FC158815FA77C40330 /* ChainShape.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ChainShape.h; sourceTree = "<group>"; };
-		1AA7781A230065F346E2313A /* ImageData.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ImageData.cpp; sourceTree = "<group>"; };
+		1AA7781A230065F346E2313A /* DevilHandler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DevilHandler.cpp; sourceTree = "<group>"; };
 		1B036C7C5A8832AE53BB1C06 /* b2CollideEdge.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollideEdge.cpp; sourceTree = "<group>"; };
 		1B036C7C5A8832AE53BB1C06 /* b2CollideEdge.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollideEdge.cpp; sourceTree = "<group>"; };
 		1B1C4E4D288A1D2F29E57B1B /* Rasterizer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Rasterizer.cpp; sourceTree = "<group>"; };
 		1B1C4E4D288A1D2F29E57B1B /* Rasterizer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Rasterizer.cpp; sourceTree = "<group>"; };
 		1B4E22F1388E2B2E76E3377B /* wrap_GlyphData.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_GlyphData.cpp; sourceTree = "<group>"; };
 		1B4E22F1388E2B2E76E3377B /* wrap_GlyphData.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_GlyphData.cpp; sourceTree = "<group>"; };
@@ -389,7 +403,7 @@
 		27F777AB188D674F30BC1829 /* wrap_World.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wrap_World.h; sourceTree = "<group>"; };
 		27F777AB188D674F30BC1829 /* wrap_World.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wrap_World.h; sourceTree = "<group>"; };
 		28016C9B51FE1A893DC35B66 /* Variant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Variant.h; sourceTree = "<group>"; };
 		28016C9B51FE1A893DC35B66 /* Variant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Variant.h; sourceTree = "<group>"; };
 		28024635525B077E08A73D9B /* Source.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Source.cpp; sourceTree = "<group>"; };
 		28024635525B077E08A73D9B /* Source.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Source.cpp; sourceTree = "<group>"; };
-		283342E174613897621A43F1 /* ImageData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageData.h; sourceTree = "<group>"; };
+		283342E174613897621A43F1 /* DevilHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DevilHandler.h; sourceTree = "<group>"; };
 		286660042F9654F61AB90D7A /* Body.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Body.h; sourceTree = "<group>"; };
 		286660042F9654F61AB90D7A /* Body.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Body.h; sourceTree = "<group>"; };
 		2912092853050AF9785F39BE /* wrap_RevoluteJoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wrap_RevoluteJoint.h; sourceTree = "<group>"; };
 		2912092853050AF9785F39BE /* wrap_RevoluteJoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wrap_RevoluteJoint.h; sourceTree = "<group>"; };
 		295C665B1E0B6B2D03CC4937 /* wrap_Event.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wrap_Event.h; sourceTree = "<group>"; };
 		295C665B1E0B6B2D03CC4937 /* wrap_Event.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wrap_Event.h; sourceTree = "<group>"; };
@@ -677,6 +691,7 @@
 		7F796B7A3362196075C62E61 /* wrap_Fixture.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Fixture.cpp; sourceTree = "<group>"; };
 		7F796B7A3362196075C62E61 /* wrap_Fixture.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Fixture.cpp; sourceTree = "<group>"; };
 		7F911CF2107B22F44C5B2542 /* b2Collision.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = b2Collision.h; sourceTree = "<group>"; };
 		7F911CF2107B22F44C5B2542 /* b2Collision.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = b2Collision.h; sourceTree = "<group>"; };
 		FA08F5AE16C7525600F007B5 /* Info-Framework.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Framework.plist"; sourceTree = "<group>"; };
 		FA08F5AE16C7525600F007B5 /* Info-Framework.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Framework.plist"; sourceTree = "<group>"; };
+		FA0CDE3B1710F9A50056E8D7 /* FormatHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormatHandler.h; sourceTree = "<group>"; };
 		FA5454C016F1310000D30303 /* MathModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathModule.cpp; sourceTree = "<group>"; };
 		FA5454C016F1310000D30303 /* MathModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathModule.cpp; sourceTree = "<group>"; };
 		FA5454C116F1310000D30303 /* MathModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MathModule.h; sourceTree = "<group>"; };
 		FA5454C116F1310000D30303 /* MathModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MathModule.h; sourceTree = "<group>"; };
 		FA577A6716C719D900860150 /* FreeType.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FreeType.framework; path = /Library/Frameworks/FreeType.framework; sourceTree = "<absolute>"; };
 		FA577A6716C719D900860150 /* FreeType.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FreeType.framework; path = /Library/Frameworks/FreeType.framework; sourceTree = "<absolute>"; };
@@ -702,7 +717,20 @@
 		FA577AAF16C7507900860150 /* love.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = love.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		FA577AAF16C7507900860150 /* love.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = love.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Math.cpp; sourceTree = "<group>"; };
 		FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Math.cpp; sourceTree = "<group>"; };
 		FA7C937616DCC6C2006F2BEE /* wrap_Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Math.h; sourceTree = "<group>"; };
 		FA7C937616DCC6C2006F2BEE /* wrap_Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Math.h; sourceTree = "<group>"; };
+		FAAC6B00170A373A008A61C5 /* CompressedData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CompressedData.cpp; sourceTree = "<group>"; };
+		FAAC6B01170A373A008A61C5 /* CompressedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompressedData.h; sourceTree = "<group>"; };
 		FAAFF04316CB11C700CCDE45 /* OpenAL-Soft.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "OpenAL-Soft.framework"; path = "/Library/Frameworks/OpenAL-Soft.framework"; sourceTree = "<absolute>"; };
 		FAAFF04316CB11C700CCDE45 /* OpenAL-Soft.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "OpenAL-Soft.framework"; path = "/Library/Frameworks/OpenAL-Soft.framework"; sourceTree = "<absolute>"; };
+		FAE010D8170DDE99006F29D0 /* ddsinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ddsinfo.h; sourceTree = "<group>"; };
+		FAE010D9170DDE99006F29D0 /* ddsparse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ddsparse.cpp; sourceTree = "<group>"; };
+		FAE010DA170DDE99006F29D0 /* ddsparse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ddsparse.h; sourceTree = "<group>"; };
+		FAE010DE170DE25E006F29D0 /* ddsHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ddsHandler.cpp; sourceTree = "<group>"; };
+		FAE010DF170DE25E006F29D0 /* ddsHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ddsHandler.h; sourceTree = "<group>"; };
+		FAE010E2170DF75B006F29D0 /* wrap_CompressedData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_CompressedData.cpp; sourceTree = "<group>"; };
+		FAE010E3170DF75C006F29D0 /* wrap_CompressedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_CompressedData.h; sourceTree = "<group>"; };
+		FAEC80881710FEA60057279A /* ImageData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageData.cpp; sourceTree = "<group>"; };
+		FAEC80891710FEA60057279A /* ImageData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageData.h; sourceTree = "<group>"; };
+		FAEC808C1711E76C0057279A /* CompressedData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CompressedData.cpp; sourceTree = "<group>"; };
+		FAEC808D1711E76C0057279A /* CompressedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompressedData.h; sourceTree = "<group>"; };
 		FAF2729816E3D44400CC193A /* Channel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Channel.cpp; sourceTree = "<group>"; };
 		FAF2729816E3D44400CC193A /* Channel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Channel.cpp; sourceTree = "<group>"; };
 		FAF2729916E3D44400CC193A /* Channel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Channel.h; sourceTree = "<group>"; };
 		FAF2729916E3D44400CC193A /* Channel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Channel.h; sourceTree = "<group>"; };
 		FAF2729A16E3D44400CC193A /* LuaThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LuaThread.cpp; sourceTree = "<group>"; };
 		FAF2729A16E3D44400CC193A /* LuaThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LuaThread.cpp; sourceTree = "<group>"; };
@@ -748,10 +776,14 @@
 		003F4BA82B6046BC133B3F0F /* image */ = {
 		003F4BA82B6046BC133B3F0F /* image */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				FAAC6B00170A373A008A61C5 /* CompressedData.cpp */,
+				FAAC6B01170A373A008A61C5 /* CompressedData.h */,
 				25C325DC2128769F6C6A54C3 /* Image.h */,
 				25C325DC2128769F6C6A54C3 /* Image.h */,
 				78115E763B723C0C40AD47CF /* ImageData.cpp */,
 				78115E763B723C0C40AD47CF /* ImageData.cpp */,
 				07B301984BE42246402F7D27 /* ImageData.h */,
 				07B301984BE42246402F7D27 /* ImageData.h */,
-				13730AB030E309FF6E2961F1 /* devil */,
+				13730AB030E309FF6E2961F1 /* magpie */,
+				FAE010E2170DF75B006F29D0 /* wrap_CompressedData.cpp */,
+				FAE010E3170DF75C006F29D0 /* wrap_CompressedData.h */,
 				0B0728FA73B107B37A956A09 /* wrap_Image.cpp */,
 				0B0728FA73B107B37A956A09 /* wrap_Image.cpp */,
 				006B015320155B4D42B43B61 /* wrap_Image.h */,
 				006B015320155B4D42B43B61 /* wrap_Image.h */,
 				076840774B0B6E721D0C18D0 /* wrap_ImageData.cpp */,
 				076840774B0B6E721D0C18D0 /* wrap_ImageData.cpp */,
@@ -905,15 +937,22 @@
 			path = libluasocket;
 			path = libluasocket;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
-		13730AB030E309FF6E2961F1 /* devil */ = {
+		13730AB030E309FF6E2961F1 /* magpie */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				FAEC808C1711E76C0057279A /* CompressedData.cpp */,
+				FAEC808D1711E76C0057279A /* CompressedData.h */,
+				FAE010DE170DE25E006F29D0 /* ddsHandler.cpp */,
+				FAE010DF170DE25E006F29D0 /* ddsHandler.h */,
+				1AA7781A230065F346E2313A /* DevilHandler.cpp */,
+				283342E174613897621A43F1 /* DevilHandler.h */,
+				FA0CDE3B1710F9A50056E8D7 /* FormatHandler.h */,
 				505F23A73BFE250833D650E4 /* Image.cpp */,
 				505F23A73BFE250833D650E4 /* Image.cpp */,
 				68616BD516DB124312B47EB3 /* Image.h */,
 				68616BD516DB124312B47EB3 /* Image.h */,
-				1AA7781A230065F346E2313A /* ImageData.cpp */,
-				283342E174613897621A43F1 /* ImageData.h */,
+				FAEC80881710FEA60057279A /* ImageData.cpp */,
+				FAEC80891710FEA60057279A /* ImageData.h */,
 			);
 			);
-			path = devil;
+			path = magpie;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
 		153D76205F7A4ACD12FB4C0E /* window */ = {
 		153D76205F7A4ACD12FB4C0E /* window */ = {
@@ -1194,6 +1233,7 @@
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
 				63287ED84D0F2EEB65D249A3 /* Box2D */,
 				63287ED84D0F2EEB65D249A3 /* Box2D */,
+				FAE010D7170DDE99006F29D0 /* ddsparse */,
 				3AED1DE005A53DDB07902760 /* luasocket */,
 				3AED1DE005A53DDB07902760 /* luasocket */,
 				36C14C81334735EC54E33637 /* utf8 */,
 				36C14C81334735EC54E33637 /* utf8 */,
 			);
 			);
@@ -1619,6 +1659,16 @@
 			path = math;
 			path = math;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
+		FAE010D7170DDE99006F29D0 /* ddsparse */ = {
+			isa = PBXGroup;
+			children = (
+				FAE010D8170DDE99006F29D0 /* ddsinfo.h */,
+				FAE010D9170DDE99006F29D0 /* ddsparse.cpp */,
+				FAE010DA170DDE99006F29D0 /* ddsparse.h */,
+			);
+			path = ddsparse;
+			sourceTree = "<group>";
+		};
 		FAF272B016E3D46400CC193A /* sdl */ = {
 		FAF272B016E3D46400CC193A /* sdl */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
@@ -1647,6 +1697,14 @@
 				FAF272B616E3D46400CC193A /* Thread.h in Headers */,
 				FAF272B616E3D46400CC193A /* Thread.h in Headers */,
 				FAF272B816E3D46400CC193A /* threads.h in Headers */,
 				FAF272B816E3D46400CC193A /* threads.h in Headers */,
 				FA5454C316F1310000D30303 /* MathModule.h in Headers */,
 				FA5454C316F1310000D30303 /* MathModule.h in Headers */,
+				FAAC6B03170A373B008A61C5 /* CompressedData.h in Headers */,
+				FAE010DB170DDE99006F29D0 /* ddsinfo.h in Headers */,
+				FAE010DD170DDE99006F29D0 /* ddsparse.h in Headers */,
+				FAE010E1170DE25E006F29D0 /* ddsHandler.h in Headers */,
+				FAE010E5170DF75C006F29D0 /* wrap_CompressedData.h in Headers */,
+				FA0CDE3D1710F9A50056E8D7 /* FormatHandler.h in Headers */,
+				FAEC808B1710FEA60057279A /* ImageData.h in Headers */,
+				FAEC808F1711E76C0057279A /* CompressedData.h in Headers */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};
@@ -1837,7 +1895,7 @@
 				FA08F62D16C7541400F007B5 /* wrap_SpriteBatch.cpp in Sources */,
 				FA08F62D16C7541400F007B5 /* wrap_SpriteBatch.cpp in Sources */,
 				FA08F62E16C7542600F007B5 /* ImageData.cpp in Sources */,
 				FA08F62E16C7542600F007B5 /* ImageData.cpp in Sources */,
 				FA08F62F16C7542600F007B5 /* Image.cpp in Sources */,
 				FA08F62F16C7542600F007B5 /* Image.cpp in Sources */,
-				FA08F63016C7542600F007B5 /* ImageData.cpp in Sources */,
+				FA08F63016C7542600F007B5 /* DevilHandler.cpp in Sources */,
 				FA08F63116C7542600F007B5 /* wrap_Image.cpp in Sources */,
 				FA08F63116C7542600F007B5 /* wrap_Image.cpp in Sources */,
 				FA08F63216C7542600F007B5 /* wrap_ImageData.cpp in Sources */,
 				FA08F63216C7542600F007B5 /* wrap_ImageData.cpp in Sources */,
 				FA08F63316C7542D00F007B5 /* Joystick.cpp in Sources */,
 				FA08F63316C7542D00F007B5 /* Joystick.cpp in Sources */,
@@ -1922,6 +1980,12 @@
 				FAF272B516E3D46400CC193A /* Thread.cpp in Sources */,
 				FAF272B516E3D46400CC193A /* Thread.cpp in Sources */,
 				FAF272B716E3D46400CC193A /* threads.cpp in Sources */,
 				FAF272B716E3D46400CC193A /* threads.cpp in Sources */,
 				FA5454C216F1310000D30303 /* MathModule.cpp in Sources */,
 				FA5454C216F1310000D30303 /* MathModule.cpp in Sources */,
+				FAAC6B02170A373B008A61C5 /* CompressedData.cpp in Sources */,
+				FAE010DC170DDE99006F29D0 /* ddsparse.cpp in Sources */,
+				FAE010E0170DE25E006F29D0 /* ddsHandler.cpp in Sources */,
+				FAE010E4170DF75C006F29D0 /* wrap_CompressedData.cpp in Sources */,
+				FAEC808A1710FEA60057279A /* ImageData.cpp in Sources */,
+				FAEC808E1711E76C0057279A /* CompressedData.cpp in Sources */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};

+ 1 - 0
src/common/runtime.cpp

@@ -469,6 +469,7 @@ StringMap<Type, TYPE_MAX_ENUM>::Entry typeEntries[] =
 
 
 	// Image
 	// Image
 	{"ImageData", IMAGE_IMAGE_DATA_ID},
 	{"ImageData", IMAGE_IMAGE_DATA_ID},
+	{"CompressedData", IMAGE_COMPRESSED_DATA_ID},
 
 
 	// Audio
 	// Audio
 	{"Source", AUDIO_SOURCE_ID},
 	{"Source", AUDIO_SOURCE_ID},

+ 2 - 0
src/common/types.h

@@ -56,6 +56,7 @@ enum Type
 
 
 	// Image
 	// Image
 	IMAGE_IMAGE_DATA_ID,
 	IMAGE_IMAGE_DATA_ID,
+	IMAGE_COMPRESSED_DATA_ID,
 
 
 	// Audio
 	// Audio
 	AUDIO_SOURCE_ID,
 	AUDIO_SOURCE_ID,
@@ -127,6 +128,7 @@ const bits GRAPHICS_SHADER_T = (bits(1) << GRAPHICS_SHADER_ID) | OBJECT_T;
 
 
 // Image.
 // Image.
 const bits IMAGE_IMAGE_DATA_T = (bits(1) << IMAGE_IMAGE_DATA_ID) | DATA_T;
 const bits IMAGE_IMAGE_DATA_T = (bits(1) << IMAGE_IMAGE_DATA_ID) | DATA_T;
+const bits IMAGE_COMPRESSED_DATA_T = (bits(1) << IMAGE_COMPRESSED_DATA_ID) | DATA_T;
 
 
 // Audio.
 // Audio.
 const bits AUDIO_SOURCE_T = (bits(1) << AUDIO_SOURCE_ID) | OBJECT_T;
 const bits AUDIO_SOURCE_T = (bits(1) << AUDIO_SOURCE_ID) | OBJECT_T;

+ 235 - 0
src/libraries/ddsparse/ddsinfo.h

@@ -0,0 +1,235 @@
+/**
+ * Simple DDS data parser for compressed 2D textures.
+ *
+ * Copyright (c) 2013 Alexander Szpakowski.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *
+ * Enums and structs copied from Microsoft.
+ * http://msdn.microsoft.com/en-us/library/bb943991.aspx
+ **/
+
+#ifndef DDS_INFO_H
+#define DDS_INFO_H
+
+#include <stdint.h>
+
+namespace dds
+{
+namespace dxinfo
+{
+
+enum DDPF
+{
+	DDPF_ALPHAPIXELS = 0x000001,
+	DDPF_ALPHA       = 0x000002,
+	DDPF_FOURCC      = 0x000004,
+	DDPF_RGB         = 0x000040,
+	DDPF_YUV         = 0x000200,
+	DDPF_LUMINANCE   = 0x020000
+};
+
+enum D3D10ResourceDimension
+{
+	D3D10_RESOURCE_DIMENSION_UNKNOWN   = 0,
+	D3D10_RESOURCE_DIMENSION_BUFFER    = 1,
+	D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2,
+	D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3,
+	D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4
+};
+
+enum DXGIFormat
+{
+	DXGI_FORMAT_UNKNOWN                     = 0,
+
+	DXGI_FORMAT_R32G32B32A32_TYPELESS       = 1,
+	DXGI_FORMAT_R32G32B32A32_FLOAT          = 2,
+	DXGI_FORMAT_R32G32B32A32_UINT           = 3,
+	DXGI_FORMAT_R32G32B32A32_SINT           = 4,
+
+	DXGI_FORMAT_R32G32B32_TYPELESS          = 5,
+	DXGI_FORMAT_R32G32B32_FLOAT             = 6,
+	DXGI_FORMAT_R32G32B32_UINT              = 7,
+	DXGI_FORMAT_R32G32B32_SINT              = 8,
+
+	DXGI_FORMAT_R16G16B16A16_TYPELESS       = 9,
+	DXGI_FORMAT_R16G16B16A16_FLOAT          = 10,
+	DXGI_FORMAT_R16G16B16A16_UNORM          = 11,
+	DXGI_FORMAT_R16G16B16A16_UINT           = 12,
+	DXGI_FORMAT_R16G16B16A16_SNORM          = 13,
+	DXGI_FORMAT_R16G16B16A16_SINT           = 14,
+
+	DXGI_FORMAT_R32G32_TYPELESS             = 15,
+	DXGI_FORMAT_R32G32_FLOAT                = 16,
+	DXGI_FORMAT_R32G32_UINT                 = 17,
+	DXGI_FORMAT_R32G32_SINT                 = 18,
+
+	DXGI_FORMAT_R32G8X24_TYPELESS           = 19,
+	DXGI_FORMAT_D32_FLOAT_S8X24_UINT        = 20,
+	DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS    = 21,
+	DXGI_FORMAT_X32_TYPELESS_G8X24_UINT     = 22,
+
+	DXGI_FORMAT_R10G10B10A2_TYPELESS        = 23,
+	DXGI_FORMAT_R10G10B10A2_UNORM           = 24,
+	DXGI_FORMAT_R10G10B10A2_UINT            = 25,
+
+	DXGI_FORMAT_R11G11B10_FLOAT             = 26,
+
+	DXGI_FORMAT_R8G8B8A8_TYPELESS           = 27,
+	DXGI_FORMAT_R8G8B8A8_UNORM              = 28,
+	DXGI_FORMAT_R8G8B8A8_UNORM_SRGB         = 29,
+	DXGI_FORMAT_R8G8B8A8_UINT               = 30,
+	DXGI_FORMAT_R8G8B8A8_SNORM              = 31,
+	DXGI_FORMAT_R8G8B8A8_SINT               = 32,
+
+	DXGI_FORMAT_R16G16_TYPELESS             = 33,
+	DXGI_FORMAT_R16G16_FLOAT                = 34,
+	DXGI_FORMAT_R16G16_UNORM                = 35,
+	DXGI_FORMAT_R16G16_UINT                 = 36,
+	DXGI_FORMAT_R16G16_SNORM                = 37,
+	DXGI_FORMAT_R16G16_SINT                 = 38,
+
+	DXGI_FORMAT_R32_TYPELESS                = 39,
+	DXGI_FORMAT_D32_FLOAT                   = 40,
+	DXGI_FORMAT_R32_FLOAT                   = 41,
+	DXGI_FORMAT_R32_UINT                    = 42,
+	DXGI_FORMAT_R32_SINT                    = 43,
+
+	DXGI_FORMAT_R24G8_TYPELESS              = 44,
+	DXGI_FORMAT_D24_UNORM_S8_UINT           = 45,
+	DXGI_FORMAT_R24_UNORM_X8_TYPELESS       = 46,
+	DXGI_FORMAT_X24_TYPELESS_G8_UINT        = 47,
+
+	DXGI_FORMAT_R8G8_TYPELESS               = 48,
+	DXGI_FORMAT_R8G8_UNORM                  = 49,
+	DXGI_FORMAT_R8G8_UINT                   = 50,
+	DXGI_FORMAT_R8G8_SNORM                  = 51,
+	DXGI_FORMAT_R8G8_SINT                   = 52,
+
+	DXGI_FORMAT_R16_TYPELESS                = 53,
+	DXGI_FORMAT_R16_FLOAT                   = 54,
+	DXGI_FORMAT_D16_UNORM                   = 55,
+	DXGI_FORMAT_R16_UNORM                   = 56,
+	DXGI_FORMAT_R16_UINT                    = 57,
+	DXGI_FORMAT_R16_SNORM                   = 58,
+	DXGI_FORMAT_R16_SINT                    = 59,
+
+	DXGI_FORMAT_R8_TYPELESS                 = 60,
+	DXGI_FORMAT_R8_UNORM                    = 61,
+	DXGI_FORMAT_R8_UINT                     = 62,
+	DXGI_FORMAT_R8_SNORM                    = 63,
+	DXGI_FORMAT_R8_SINT                     = 64,
+	DXGI_FORMAT_A8_UNORM                    = 65,
+
+	DXGI_FORMAT_R1_UNORM                    = 66,
+
+	DXGI_FORMAT_R9G9B9E5_SHAREDEXP          = 67,
+
+	DXGI_FORMAT_R8G8_B8G8_UNORM             = 68,
+	DXGI_FORMAT_G8R8_G8B8_UNORM             = 69,
+
+	DXGI_FORMAT_BC1_TYPELESS                = 70,
+	DXGI_FORMAT_BC1_UNORM                   = 71,
+	DXGI_FORMAT_BC1_UNORM_SRGB              = 72,
+
+	DXGI_FORMAT_BC2_TYPELESS                = 73,
+	DXGI_FORMAT_BC2_UNORM                   = 74,
+	DXGI_FORMAT_BC2_UNORM_SRGB              = 75,
+
+	DXGI_FORMAT_BC3_TYPELESS                = 76,
+	DXGI_FORMAT_BC3_UNORM                   = 77,
+	DXGI_FORMAT_BC3_UNORM_SRGB              = 78,
+
+	DXGI_FORMAT_BC4_TYPELESS                = 79,
+	DXGI_FORMAT_BC4_UNORM                   = 80,
+	DXGI_FORMAT_BC4_SNORM                   = 81,
+
+	DXGI_FORMAT_BC5_TYPELESS                = 82,
+	DXGI_FORMAT_BC5_UNORM                   = 83,
+	DXGI_FORMAT_BC5_SNORM                   = 84,
+
+	DXGI_FORMAT_B5G6R5_UNORM                = 85,
+	DXGI_FORMAT_B5G5R5A1_UNORM              = 86,
+	DXGI_FORMAT_B8G8R8A8_UNORM              = 87,
+	DXGI_FORMAT_B8G8R8X8_UNORM              = 88,
+
+	DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM  = 89,
+	DXGI_FORMAT_B8G8R8A8_TYPELESS           = 90,
+	DXGI_FORMAT_B8G8R8A8_UNORM_SRGB         = 91,
+	DXGI_FORMAT_B8G8R8X8_TYPELESS           = 92,
+	DXGI_FORMAT_B8G8R8X8_UNORM_SRGB         = 93,
+
+	DXGI_FORMAT_BC6H_TYPELESS               = 94,
+	DXGI_FORMAT_BC6H_UF16                   = 95,
+	DXGI_FORMAT_BC6H_SF16                   = 96,
+
+	DXGI_FORMAT_BC7_TYPELESS                = 97,
+	DXGI_FORMAT_BC7_UNORM                   = 98,
+	DXGI_FORMAT_BC7_UNORM_SRGB              = 99,
+
+	DXGI_FORMAT_FORCE_UINT                  = 0xffffffffUL
+};
+
+struct DDSPixelFormat
+{
+	uint32_t size;
+	uint32_t flags;
+	uint32_t fourCC;
+	uint32_t rgbBitCount;
+	uint32_t rBitMask;
+	uint32_t gBitMask;
+	uint32_t bBitMask;
+	uint32_t aBitMask;
+};
+
+struct DDSHeader
+{
+	uint32_t size;
+	uint32_t flags;
+	uint32_t height;
+	uint32_t width;
+	uint32_t pitchOrLinearSize;
+	uint32_t depth;
+	uint32_t mipMapCount;
+	uint32_t reserved[11];
+
+	DDSPixelFormat format;
+
+	uint32_t caps1;
+	uint32_t caps2;
+	uint32_t caps3;
+	uint32_t caps4;
+	uint32_t reserved2;
+};
+
+struct DDSHeader10
+{
+	DXGIFormat dxgiFormat;
+	D3D10ResourceDimension resourceDimension;
+
+	uint32_t miscFlag;
+	uint32_t arraySize;
+	uint32_t reserved;
+};
+
+} // dxinfo
+} // dds
+
+#endif // DDS_INFO_H

+ 358 - 0
src/libraries/ddsparse/ddsparse.cpp

@@ -0,0 +1,358 @@
+/**
+ * Simple DDS data parser for compressed 2D textures.
+ *
+ * Copyright (c) 2013 Alexander Szpakowski.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ **/
+
+#include "ddsparse.h"
+#include "ddsinfo.h"
+
+#include <algorithm>
+
+namespace dds
+{
+
+using namespace dds::dxinfo;
+
+// Creates a packed uint representation of a FourCC code.
+static inline uint32_t FourCC(char a, char b, char c, char d)
+{
+	uint32_t fcc = ((uint32_t) a)
+	            | (((uint32_t) b) << 8)
+	            | (((uint32_t) c) << 16)
+	            | (((uint32_t) d) << 24);
+
+	return fcc;
+}
+
+Parser::Image::Image()
+	: width(0)
+	, height(0)
+	, dataSize(0)
+	, data(0)
+{
+}
+
+bool Parser::isDDS(const void *data, size_t dataSize)
+{
+	const uint8_t *readData = (const uint8_t *) data;
+	ptrdiff_t offset = 0;
+
+	// Is the data large enough to hold the DDS header?
+	if(dataSize < sizeof(uint32_t) + sizeof(DDSHeader))
+		return false;
+
+	// All DDS files start with "DDS ".
+	if((*(uint32_t *) readData) != FourCC('D','D','S',' '))
+		return false;
+
+	offset += sizeof(uint32_t);
+
+	DDSHeader *header = (DDSHeader *) &readData[offset];
+
+
+	// Verify header to validate DDS data.
+	if (header->size != sizeof(DDSHeader) || header->format.size != sizeof(DDSPixelFormat))
+		return false;
+
+	offset += sizeof(DDSHeader);
+
+	// Check for DX10 extension.
+	if ((header->format.flags & DDPF_FOURCC) && (header->format.fourCC == FourCC('D','X','1','0')))
+	{
+		// Data must be big enough for both headers plus the magic value.
+		if (dataSize < (sizeof(uint32_t) + sizeof(DDSHeader) + sizeof(DDSHeader10)))
+			return false;
+	}
+
+	return true;
+}
+
+bool Parser::isCompressedDDS(const void *data, size_t dataSize)
+{
+	if (!isDDS(data, dataSize))
+		return false;
+
+	const uint8_t *readData = (const uint8_t *) data;
+	ptrdiff_t offset = sizeof(uint32_t);
+
+	DDSHeader *header = (DDSHeader *) &readData[offset];
+	offset += sizeof(DDSHeader);
+
+	// Check for DX10 extension.
+	if ((header->format.flags & DDPF_FOURCC) && (header->format.fourCC == FourCC('D','X','1','0')))
+	{
+		DDSHeader10 *header10 = (DDSHeader10 *) &readData[offset];
+		return parseDX10Format(header10->dxgiFormat) != FORMAT_UNKNOWN;
+	}
+
+	return parseDDSFormat(header->format) != FORMAT_UNKNOWN;
+}
+
+Parser::Parser(const void *data, size_t dataSize)
+	: format(FORMAT_UNKNOWN)
+{
+	parseData(data, dataSize);
+}
+
+Parser::Parser(const Parser &other)
+	: texData(other.texData)
+	, format(other.format)
+{
+}
+
+Parser::Parser()
+	: format(FORMAT_UNKNOWN)
+{
+}
+
+Parser &Parser::operator = (const Parser &other)
+{
+	texData = other.texData;
+	format = other.format;
+
+	return *this;
+}
+
+Parser::~Parser()
+{
+}
+
+Format Parser::getFormat() const
+{
+	return format;
+}
+
+const Parser::Image *Parser::getImageData(size_t miplevel) const
+{
+	if (miplevel >= texData.size())
+		return 0;
+
+	return &texData[miplevel];
+}
+
+size_t Parser::getNumMipmaps() const
+{
+	return texData.size();
+}
+
+Format Parser::parseDDSFormat(const DDSPixelFormat &fmt)
+{
+	if (fmt.flags & DDPF_FOURCC)
+	{
+		if (fmt.fourCC == FourCC('D','X','T','1'))
+			return FORMAT_DXT1;
+		else if (fmt.fourCC == FourCC('D','X','T','3'))
+			return FORMAT_DXT3;
+		else if (fmt.fourCC == FourCC('D','X','T','5'))
+			return FORMAT_DXT5;
+		else if (fmt.fourCC == FourCC('A','T','I','1'))
+			return FORMAT_BC4;
+		else if (fmt.fourCC == FourCC('A','T','I','2'))
+			return FORMAT_BC5;
+		else if (fmt.fourCC == FourCC('B','C','4','U'))
+			return FORMAT_BC4;
+		else if (fmt.fourCC == FourCC('B','C','4','S'))
+			return FORMAT_BC4s;
+		else if (fmt.fourCC == FourCC('B','C','5','U'))
+			return FORMAT_BC5;
+		else if (fmt.fourCC == FourCC('B','C','5','S'))
+			return FORMAT_BC5s;
+	}
+
+	return FORMAT_UNKNOWN;
+}
+
+Format Parser::parseDX10Format(DXGIFormat fmt)
+{
+	Format f = FORMAT_UNKNOWN;
+
+	switch (fmt)
+	{
+	case DXGI_FORMAT_BC1_TYPELESS:
+	case DXGI_FORMAT_BC1_UNORM:
+	case DXGI_FORMAT_BC1_UNORM_SRGB:
+		f = FORMAT_DXT1;
+		break;
+	case DXGI_FORMAT_BC2_TYPELESS:
+	case DXGI_FORMAT_BC2_UNORM:
+	case DXGI_FORMAT_BC2_UNORM_SRGB:
+		f = FORMAT_DXT3;
+		break;
+	case DXGI_FORMAT_BC3_TYPELESS:
+	case DXGI_FORMAT_BC3_UNORM:
+	case DXGI_FORMAT_BC3_UNORM_SRGB:
+		f = FORMAT_DXT5;
+		break;
+	case DXGI_FORMAT_BC4_TYPELESS:
+	case DXGI_FORMAT_BC4_UNORM:
+		f = FORMAT_BC4;
+		break;
+	case DXGI_FORMAT_BC4_SNORM:
+		f = FORMAT_BC4s;
+		break;
+	case DXGI_FORMAT_BC5_TYPELESS:
+	case DXGI_FORMAT_BC5_UNORM:
+		f = FORMAT_BC5;
+		break;
+	case DXGI_FORMAT_BC5_SNORM:
+		f = FORMAT_BC5s;
+		break;
+	case DXGI_FORMAT_BC6H_TYPELESS:
+	case DXGI_FORMAT_BC6H_UF16:
+		f = FORMAT_BC6H;
+		break;
+	case DXGI_FORMAT_BC6H_SF16:
+		f = FORAMT_BC6Hs;
+		break;
+	case DXGI_FORMAT_BC7_TYPELESS:
+	case DXGI_FORMAT_BC7_UNORM:
+		f = FORMAT_BC7;
+		break;
+	case DXGI_FORMAT_BC7_UNORM_SRGB:
+		f = FORMAT_BC7srgb;
+		break;
+	default:
+		break;
+	}
+
+	return f;
+}
+
+size_t Parser::parseImageSize(Format fmt, int width, int height) const
+{
+	size_t size = 0;
+
+	switch (fmt)
+	{
+	case FORMAT_DXT1:
+	case FORMAT_DXT3:
+	case FORMAT_DXT5:
+	case FORMAT_BC5s:
+	case FORMAT_BC5:
+	case FORMAT_BC7:
+	case FORMAT_BC7srgb:
+		{
+			int numBlocksWide = 0;
+			if (width > 0)
+				numBlocksWide = std::max(1, (width + 3) / 4);
+
+			int numBlocksHigh = 0;
+			if (height > 0)
+				numBlocksHigh = std::max(1, (height + 3) / 4);
+
+			int numBytesPerBlock = (fmt == FORMAT_DXT1 ? 8 : 16);
+
+			size = numBlocksWide * numBytesPerBlock * numBlocksHigh;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return size;
+}
+
+bool Parser::parseTexData(const uint8_t *data, size_t dataSize, Format fmt, int w, int h, int mips)
+{
+	size_t offset = 0;
+	std::vector<Image> newTexData;
+
+	for (int i = 0; i < mips; i++)
+	{
+		Image img;
+		img.width = w;
+		img.height = h;
+
+		img.dataSize = parseImageSize(fmt, img.width, img.height);
+
+		// Make sure the data size is valid.
+		if (img.dataSize == 0 || (offset + img.dataSize) > dataSize)
+			return false;
+
+		// Store the memory address of the data representing this mip level.
+		img.data = &data[offset];
+
+		newTexData.push_back(img);
+
+		// Move to the next mip level.
+		offset += img.dataSize;
+
+		w = std::max(w / 2, 1);
+		h = std::max(h / 2, 1);
+	}
+
+	texData = newTexData;
+
+	return true;
+}
+
+bool Parser::parseData(const void *data, size_t dataSize)
+{
+	if (!isDDS(data, dataSize))
+		return false;
+
+	const uint8_t *readData = (const uint8_t *) data;
+	ptrdiff_t offset = sizeof(uint32_t);
+
+	DDSHeader *header = (DDSHeader *) &readData[offset];
+	offset += sizeof(DDSHeader);
+
+
+	// Check for DX10 extension.
+	if ((header->format.flags & DDPF_FOURCC) && (header->format.fourCC == FourCC('D','X','1','0')))
+	{
+		DDSHeader10 *header10 = (DDSHeader10 *) &readData[offset];
+		offset += sizeof(DDSHeader10);
+
+		// We can't deal with 1D/3D textures.
+		switch (header10->resourceDimension)
+		{
+		case D3D10_RESOURCE_DIMENSION_TEXTURE2D:
+		case D3D10_RESOURCE_DIMENSION_UNKNOWN:
+			break;
+		default:
+			return false;
+		}
+
+		// We also can't deal with texture arrays and cubemaps.
+		if (header10->arraySize > 1)
+			return false;
+
+		format = parseDX10Format(header10->dxgiFormat);
+	}
+	else
+		format = parseDDSFormat(header->format);
+
+
+	if (format == FORMAT_UNKNOWN)
+		return false;
+
+
+	int w = header->width;
+	int h = header->height;
+
+	int mips = std::max((int) header->mipMapCount, 1);
+
+	return parseTexData(&readData[offset], dataSize - offset, format, w, h, mips);
+}
+
+} // dds

+ 144 - 0
src/libraries/ddsparse/ddsparse.h

@@ -0,0 +1,144 @@
+/**
+ * Simple DDS data parser for compressed 2D textures.
+ *
+ * Copyright (c) 2013 Alexander Szpakowski.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ **/
+
+#ifndef DDS_PARSE_H
+#define DDS_PARSE_H
+
+#include "ddsinfo.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+#include <exception>
+
+namespace dds
+{
+
+// Supported DDS formats.
+// Formats with an 's' suffix have signed data.
+enum Format
+{
+	FORMAT_DXT1,
+	FORMAT_DXT3,
+	FORMAT_DXT5,
+	FORMAT_BC4,
+	FORMAT_BC4s,
+	FORMAT_BC5,
+	FORMAT_BC5s,
+	FORMAT_BC6H,
+	FORAMT_BC6Hs,
+	FORMAT_BC7,
+	FORMAT_BC7srgb, // sRGB color space.
+	FORMAT_UNKNOWN
+};
+
+class Parser
+{
+public:
+
+	// Represents a single mipmap level of a texture.
+	struct Image
+	{
+		int width;
+		int height;
+		size_t dataSize;
+		const uint8_t *data;
+
+		Image();
+	};
+
+	/**
+	 * Determines whether the input byte data represents a valid DDS file.
+	 * Does not take into account whether the texture format is supported.
+	 *
+	 * @param data     The byte data to parse.
+	 * @param dataSize The size in bytes of the data.
+	 **/
+	static bool isDDS(const void *data, size_t dataSize);
+
+	/**
+	 * Determines whether the input byte data represents a valid compressed DDS
+	 * file. Takes into account texture format, but not type (3D textures, etc.)
+	 *
+	 * @param data     The byte data to parse.
+	 * @param dataSize The size in bytes of the data.
+	 **/
+	static bool isCompressedDDS(const void *data, size_t dataSize);
+
+	/**
+	 * Constructor.
+	 * Attempts to parse byte data as a compressed DDS file.
+	 *
+	 * @param data     The byte data to parse.
+	 * @param dataSize The size in bytes of the data.
+	 **/
+	Parser(const void *data, size_t dataSize);
+	Parser(const Parser &other);
+	Parser();
+
+	Parser &operator = (const Parser &other);
+
+	~Parser();
+
+	/**
+	 * Gets the format of this texture.
+	 **/
+	Format getFormat() const;
+
+	/**
+	 * Gets the data of this texture at a mipmap level. Mipmap level 0
+	 * represents the base image.
+	 *
+	 * @param miplevel The mipmap level to get the data of.
+	 * @return Pointer to the image data, or NULL if miplevel is not within the
+	 *         range of [0, numMipmaps).
+	 **/
+	const Image *getImageData(size_t miplevel = 0) const;
+
+	/**
+	 * Gets the number of mipmap levels in this texture.
+	 * Includes the base mip level.
+	 **/
+	size_t getNumMipmaps() const;
+
+private:
+
+	static Format parseDDSFormat(const dxinfo::DDSPixelFormat &fmt);
+	static Format parseDX10Format(dxinfo::DXGIFormat fmt);
+
+	size_t parseImageSize(Format fmt, int width, int height) const;
+
+	bool parseTexData(const uint8_t *data, size_t dataSize, Format fmt, int w, int h, int mips);
+
+	bool parseData(const void *data, size_t dataSize);
+
+	std::vector<Image> texData;
+	Format format;
+
+}; // Parser
+
+} // dds
+
+#endif // DDS_PARSE_H

+ 1 - 1
src/modules/filesystem/physfs/wrap_FileData.cpp

@@ -52,7 +52,7 @@ static const luaL_Reg w_FileData_functions[] =
 {
 {
 
 
 	// Data
 	// Data
-	{ "getPointer", w_Data_getPointer },
+//	{ "getPointer", w_Data_getPointer },
 	{ "getSize", w_Data_getSize },
 	{ "getSize", w_Data_getSize },
 
 
 	{ "getFilename", w_FileData_getFilename },
 	{ "getFilename", w_FileData_getFilename },

+ 28 - 6
src/modules/filesystem/physfs/wrap_Filesystem.cpp

@@ -105,14 +105,36 @@ int w_newFile(lua_State *L)
 
 
 int w_newFileData(lua_State *L)
 int w_newFileData(lua_State *L)
 {
 {
-	if (!lua_isstring(L, 1))
-		return luaL_error(L, "String expected.");
-	if (!lua_isstring(L, 2))
-		return luaL_error(L, "String expected.");
+	// Single argument: treat as filepath or File.
+	if (lua_gettop(L) == 1)
+	{
+		if (lua_isstring(L, 1))
+			luax_convobj(L, 1, "filesystem", "newFile");
+
+		// Get FileData from the File.
+		if (luax_istype(L, 1, FILESYSTEM_FILE_T))
+		{
+			File *file = luax_checktype<File>(L, 1, "File", FILESYSTEM_FILE_T);
+
+			FileData *data = 0;
+			try
+			{
+				data = file->read();
+			}
+			catch (love::Exception &e)
+			{
+				return luaL_error(L, "%s", e.what());
+			}
+			luax_newtype(L, "FileData", FILESYSTEM_FILE_DATA_T, (void *) data);
+			return 1;
+		}
+		else
+			return luaL_argerror(L, 1, "string or File expected");
+	}
 
 
 	size_t length = 0;
 	size_t length = 0;
-	const char *str = lua_tolstring(L, 1, &length);
-	const char *filename = lua_tostring(L, 2);
+	const char *str = luaL_checklstring(L, 1, &length);
+	const char *filename = luaL_checkstring(L, 2);
 	const char *decstr = lua_isstring(L, 3) ? lua_tostring(L, 3) : 0;
 	const char *decstr = lua_isstring(L, 3) ? lua_tostring(L, 3) : 0;
 
 
 	FileData::Decoder decoder = FileData::FILE;
 	FileData::Decoder decoder = FileData::FILE;

+ 1 - 1
src/modules/font/wrap_GlyphData.cpp

@@ -32,7 +32,7 @@ GlyphData *luax_checkglyphdata(lua_State *L, int idx)
 
 
 static const luaL_Reg functions[] =
 static const luaL_Reg functions[] =
 {
 {
-	{ "getPointer", w_Data_getPointer },
+//	{ "getPointer", w_Data_getPointer },
 	{ "getSize", w_Data_getSize },
 	{ "getSize", w_Data_getSize },
 	{ 0, 0 }
 	{ 0, 0 }
 };
 };

+ 3 - 0
src/modules/graphics/Graphics.cpp

@@ -163,6 +163,9 @@ StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::suppor
 	{ "npot", Graphics::SUPPORT_NPOT },
 	{ "npot", Graphics::SUPPORT_NPOT },
 	{ "subtractive", Graphics::SUPPORT_SUBTRACTIVE },
 	{ "subtractive", Graphics::SUPPORT_SUBTRACTIVE },
 	{ "mipmap", Graphics::SUPPORT_MIPMAP },
 	{ "mipmap", Graphics::SUPPORT_MIPMAP },
+	{ "dxt", Graphics::SUPPORT_DXT },
+	{ "bc5", Graphics::SUPPORT_BC5 },
+	{ "bc7", Graphics::SUPPORT_BC7 },
 };
 };
 
 
 StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries));
 StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries));

+ 3 - 0
src/modules/graphics/Graphics.h

@@ -92,6 +92,9 @@ public:
 		SUPPORT_NPOT,
 		SUPPORT_NPOT,
 		SUPPORT_SUBTRACTIVE,
 		SUPPORT_SUBTRACTIVE,
 		SUPPORT_MIPMAP,
 		SUPPORT_MIPMAP,
+		SUPPORT_DXT,
+		SUPPORT_BC5,
+		SUPPORT_BC7,
 		SUPPORT_MAX_ENUM
 		SUPPORT_MAX_ENUM
 	};
 	};
 
 

+ 29 - 1
src/modules/graphics/opengl/Graphics.cpp

@@ -225,6 +225,9 @@ void Graphics::present()
 
 
 void Graphics::setIcon(Image *image)
 void Graphics::setIcon(Image *image)
 {
 {
+	if (image->isCompressed())
+		throw love::Exception("Cannot use compressed image data to set an icon.");
+
 	currentWindow->setIcon(image->getData());
 	currentWindow->setIcon(image->getData());
 }
 }
 
 
@@ -331,9 +334,11 @@ int Graphics::getScissor(lua_State *L) const
 
 
 void Graphics::defineStencil()
 void Graphics::defineStencil()
 {
 {
+	// Disable color writes but don't save the mask values.
 	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-	glEnable(GL_STENCIL_TEST);
+
 	glClear(GL_STENCIL_BUFFER_BIT);
 	glClear(GL_STENCIL_BUFFER_BIT);
+	glEnable(GL_STENCIL_TEST);
 	glStencilFunc(GL_ALWAYS, 1, 1);
 	glStencilFunc(GL_ALWAYS, 1, 1);
 	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
 	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
 }
 }
@@ -374,6 +379,29 @@ Image *Graphics::newImage(love::image::ImageData *data)
 	return image;
 	return image;
 }
 }
 
 
+Image *Graphics::newImage(love::image::CompressedData *cdata)
+{
+	// Create the image.
+	Image *image = new Image(cdata);
+	bool success;
+	try
+	{
+		success = image->load();
+	}
+	catch(love::Exception &)
+	{
+		image->release();
+		throw;
+	}
+	if (!success)
+	{
+		image->release();
+		return 0;
+	}
+
+	return image;
+}
+
 Quad *Graphics::newQuad(float x, float y, float w, float h, float sw, float sh)
 Quad *Graphics::newQuad(float x, float y, float w, float h, float sw, float sh)
 {
 {
 	Quad::Viewport v;
 	Quad::Viewport v;

+ 1 - 1
src/modules/graphics/opengl/Graphics.h

@@ -251,8 +251,8 @@ public:
 	/**
 	/**
 	 * Creates an Image object with padding and/or optimization.
 	 * Creates an Image object with padding and/or optimization.
 	 **/
 	 **/
-	Image *newImage(love::filesystem::File *file);
 	Image *newImage(love::image::ImageData *data);
 	Image *newImage(love::image::ImageData *data);
+	Image *newImage(love::image::CompressedData *cdata);
 
 
 	/**
 	/**
 	 * Creates a Quad object.
 	 * Creates a Quad object.

+ 254 - 109
src/modules/graphics/opengl/Image.cpp

@@ -24,8 +24,6 @@
 #include <cstring> // For memcpy
 #include <cstring> // For memcpy
 #include <algorithm> // for min/max
 #include <algorithm> // for min/max
 
 
-#include <iostream>
-
 namespace love
 namespace love
 {
 {
 namespace graphics
 namespace graphics
@@ -39,43 +37,39 @@ Image::FilterMode Image::defaultMipmapFilter = Image::FILTER_NONE;
 float Image::defaultMipmapSharpness = 0.0f;
 float Image::defaultMipmapSharpness = 0.0f;
 
 
 Image::Image(love::image::ImageData *data)
 Image::Image(love::image::ImageData *data)
-	: width((float)(data->getWidth()))
+	: cdata(0)
+	, width((float)(data->getWidth()))
 	, height((float)(data->getHeight()))
 	, height((float)(data->getHeight()))
 	, texture(0)
 	, texture(0)
 	, mipmapSharpness(defaultMipmapSharpness)
 	, mipmapSharpness(defaultMipmapSharpness)
 	, mipmapsCreated(false)
 	, mipmapsCreated(false)
+	, compressed(false)
 {
 {
 	data->retain();
 	data->retain();
 	this->data = data;
 	this->data = data;
+	preload();
+}
 
 
-	memset(vertices, 255, sizeof(vertex)*4);
-
-	vertices[0].x = 0;
-	vertices[0].y = 0;
-	vertices[1].x = 0;
-	vertices[1].y = height;
-	vertices[2].x = width;
-	vertices[2].y = height;
-	vertices[3].x = width;
-	vertices[3].y = 0;
-
-	vertices[0].s = 0;
-	vertices[0].t = 0;
-	vertices[1].s = 0;
-	vertices[1].t = 1;
-	vertices[2].s = 1;
-	vertices[2].t = 1;
-	vertices[3].s = 1;
-	vertices[3].t = 0;
-
-	filter = getDefaultFilter();
-	filter.mipmap = defaultMipmapFilter;
+Image::Image(love::image::CompressedData *cdata)
+	: data(0)
+	, width((float)(cdata->getWidth(0)))
+	, height((float)(cdata->getHeight(0)))
+	, texture(0)
+	, mipmapSharpness(defaultMipmapSharpness)
+	, mipmapsCreated(false)
+	, compressed(true)
+{
+	cdata->retain();
+	this->cdata = cdata;
+	preload();
 }
 }
 
 
 Image::~Image()
 Image::~Image()
 {
 {
 	if (data != 0)
 	if (data != 0)
 		data->release();
 		data->release();
+	if (cdata != 0)
+		cdata->release();
 	unload();
 	unload();
 }
 }
 
 
@@ -99,40 +93,6 @@ love::image::ImageData *Image::getData() const
 	return data;
 	return data;
 }
 }
 
 
-void Image::getRectangleVertices(int x, int y, int w, int h, vertex *vertices) const
-{
-	// Check upper.
-	x = (x+w > (int)width) ? (int)width-w : x;
-	y = (y+h > (int)height) ? (int)height-h : y;
-
-	// Check lower.
-	x = (x < 0) ? 0 : x;
-	y = (y < 0) ? 0 : y;
-
-	vertices[0].x = 0;
-	vertices[0].y = 0;
-	vertices[1].x = 0;
-	vertices[1].y = (float)h;
-	vertices[2].x = (float)w;
-	vertices[2].y = (float)h;
-	vertices[3].x = (float)w;
-	vertices[3].y = 0;
-
-	float tx = (float)x/width;
-	float ty = (float)y/height;
-	float tw = (float)w/width;
-	float th = (float)h/height;
-
-	vertices[0].s = tx;
-	vertices[0].t = ty;
-	vertices[1].s = tx;
-	vertices[1].t = ty+th;
-	vertices[2].s = tx+tw;
-	vertices[2].t = ty+th;
-	vertices[3].s = tx+tw;
-	vertices[3].t = ty;
-}
-
 void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
 void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
 {
 {
 	static Matrix t;
 	static Matrix t;
@@ -150,19 +110,57 @@ void Image::drawq(love::graphics::Quad *quad, float x, float y, float angle, flo
 	drawv(t, v);
 	drawv(t, v);
 }
 }
 
 
-void Image::checkMipmapsCreated()
+void Image::uploadCompressedMipmaps()
+{
+	if (!isCompressed() || !cdata || !hasCompressedTextureSupport(cdata->getType()))
+		return;
+
+	bind();
+
+	int numMipmaps = cdata->getNumMipmaps();
+
+	// We have to inform OpenGL if the image doesn't have all mipmap levels.
+	if (GLEE_VERSION_1_2 || GLEE_SGIS_texture_lod)
+	{
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, numMipmaps - 1);
+	}
+	else if (cdata->getWidth(numMipmaps-1) > 1 || cdata->getHeight(numMipmaps-1) > 1)
+	{
+		// Telling OpenGL to ignore certain levels isn't always supported.
+		throw love::Exception("Cannot load mipmaps: "
+		      "compressed image does not have all required levels.");
+	}
+
+	for (int i = 1; i < numMipmaps; i++)
+	{
+		glCompressedTexImage2DARB(GL_TEXTURE_2D,
+		                          i,
+		                          getCompressedFormat(cdata->getType()),
+		                          cdata->getWidth(i),
+		                          cdata->getHeight(i),
+		                          0,
+		                          GLsizei(cdata->getSize(i)),
+		                          cdata->getData(i));
+	}
+}
+
+void Image::createMipmaps()
 {
 {
-	if (mipmapsCreated || (filter.mipmap != FILTER_NEAREST && filter.mipmap != FILTER_LINEAR))
+	if (!data)
 		return;
 		return;
 
 
 	if (!hasMipmapSupport())
 	if (!hasMipmapSupport())
 		throw love::Exception("Mipmap filtering is not supported on this system.");
 		throw love::Exception("Mipmap filtering is not supported on this system.");
 
 
-	// Some old drivers claim support for NPOT textures, but fail when creating mipmaps.
-	// we can't detect which systems will do this, so we fail gracefully for all NPOT images.
+	// Some old drivers claim support for NPOT textures, but fail when creating
+	// mipmaps. We can't detect which systems will do this, so we fail gracefully
+	// for all NPOT images.
 	int w = int(width), h = int(height);
 	int w = int(width), h = int(height);
 	if (w != next_p2(w) || h != next_p2(h))
 	if (w != next_p2(w) || h != next_p2(h))
-		throw love::Exception("Cannot create mipmaps: image does not have power of two dimensions.");
+	{
+		throw love::Exception("Cannot create mipmaps: "
+		      "image does not have power of two dimensions.");
+	}
 
 
 	bind();
 	bind();
 
 
@@ -171,14 +169,14 @@ void Image::checkMipmapsCreated()
 		// AMD/ATI drivers have several bugs when generating mipmaps,
 		// AMD/ATI drivers have several bugs when generating mipmaps,
 		// re-uploading the entire base image seems to be required.
 		// re-uploading the entire base image seems to be required.
 		glTexImage2D(GL_TEXTURE_2D,
 		glTexImage2D(GL_TEXTURE_2D,
-		             0,
-		             GL_RGBA8,
-		             (GLsizei)width,
-		             (GLsizei)height,
-		             0,
-		             GL_RGBA,
-		             GL_UNSIGNED_BYTE,
-		             data->getData());
+					 0,
+					 GL_RGBA8,
+					 (GLsizei)width,
+					 (GLsizei)height,
+					 0,
+					 GL_RGBA,
+					 GL_UNSIGNED_BYTE,
+					 data->getData());
 
 
 		// More bugs: http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation
 		// More bugs: http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation
 		glEnable(GL_TEXTURE_2D);
 		glEnable(GL_TEXTURE_2D);
@@ -188,15 +186,28 @@ void Image::checkMipmapsCreated()
 	{
 	{
 		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
 		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
 		glTexSubImage2D(GL_TEXTURE_2D,
 		glTexSubImage2D(GL_TEXTURE_2D,
-		                0,
-		                0,
-		                0,
-		                (GLsizei)width,
-		                (GLsizei)height,
-		                GL_RGBA,
-		                GL_UNSIGNED_BYTE,
-		                data->getData());
+						0,
+						0,
+						0,
+						(GLsizei)width,
+						(GLsizei)height,
+						GL_RGBA,
+						GL_UNSIGNED_BYTE,
+						data->getData());
 	}
 	}
+}
+
+void Image::checkMipmapsCreated()
+{
+	if (mipmapsCreated || filter.mipmap == FILTER_NONE)
+		return;
+
+	if (isCompressed() && cdata && hasCompressedTextureSupport(cdata->getType()))
+		uploadCompressedMipmaps();
+	else if (data)
+		createMipmaps();
+	else
+		return;
 
 
 	mipmapsCreated = true;
 	mipmapsCreated = true;
 }
 }
@@ -236,7 +247,9 @@ void Image::setMipmapSharpness(float sharpness)
 		mipmapSharpness = std::min(std::max(sharpness, -maxMipmapSharpness + 0.01f), maxMipmapSharpness - 0.01f);
 		mipmapSharpness = std::min(std::max(sharpness, -maxMipmapSharpness + 0.01f), maxMipmapSharpness - 0.01f);
 
 
 		bind();
 		bind();
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapSharpness); // negative bias is sharper
+
+		// negative bias is sharper
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapSharpness);
 	}
 	}
 	else
 	else
 		mipmapSharpness = 0.0f;
 		mipmapSharpness = 0.0f;
@@ -255,6 +268,32 @@ void Image::bind() const
 	bindTexture(texture);
 	bindTexture(texture);
 }
 }
 
 
+void Image::preload()
+{
+	memset(vertices, 255, sizeof(vertex)*4);
+
+	vertices[0].x = 0;
+	vertices[0].y = 0;
+	vertices[1].x = 0;
+	vertices[1].y = height;
+	vertices[2].x = width;
+	vertices[2].y = height;
+	vertices[3].x = width;
+	vertices[3].y = 0;
+
+	vertices[0].s = 0;
+	vertices[0].t = 0;
+	vertices[1].s = 0;
+	vertices[1].t = 1;
+	vertices[2].s = 1;
+	vertices[2].t = 1;
+	vertices[3].s = 1;
+	vertices[3].t = 0;
+
+	filter = getDefaultFilter();
+	filter.mipmap = defaultMipmapFilter;
+}
+
 bool Image::load()
 bool Image::load()
 {
 {
 	return loadVolatile();
 	return loadVolatile();
@@ -267,6 +306,18 @@ void Image::unload()
 
 
 bool Image::loadVolatile()
 bool Image::loadVolatile()
 {
 {
+	if (isCompressed() && cdata && !hasCompressedTextureSupport(cdata->getType()))
+	{
+		const char *str;
+		if (image::CompressedData::getConstant(cdata->getType(), str))
+		{
+			throw love::Exception("Cannot create image: "
+			      "%s compressed images are not supported on this system.", str);
+		}
+		else
+			throw love::Exception("cannot create image: format is not supported on this system.");
+	}
+
 	if (hasMipmapSharpnessSupport() && maxMipmapSharpness == 0.0f)
 	if (hasMipmapSharpnessSupport() && maxMipmapSharpness == 0.0f)
 		glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxMipmapSharpness);
 		glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxMipmapSharpness);
 
 
@@ -296,25 +347,45 @@ bool Image::loadVolatilePOT()
 
 
 	while (glGetError() != GL_NO_ERROR); // clear errors
 	while (glGetError() != GL_NO_ERROR); // clear errors
 
 
-	glTexImage2D(GL_TEXTURE_2D,
-	             0,
-	             GL_RGBA8,
-	             (GLsizei)p2width,
-	             (GLsizei)p2height,
-	             0,
-	             GL_RGBA,
-	             GL_UNSIGNED_BYTE,
-	             0);
-
-	glTexSubImage2D(GL_TEXTURE_2D,
-	                0,
-	                0,
-	                0,
-	                (GLsizei)width,
-	                (GLsizei)height,
-	                GL_RGBA,
-	                GL_UNSIGNED_BYTE,
-	                data->getData());
+	if (isCompressed() && cdata)
+	{
+		if (s < 1.0f || t < 1.0f)
+		{
+			throw love::Exception("Cannot create image: "
+				  "compressed NPOT images are not supported on this system.");
+		}
+
+		glCompressedTexImage2DARB(GL_TEXTURE_2D,
+		                          0,
+		                          getCompressedFormat(cdata->getType()),
+		                          cdata->getWidth(0),
+		                          cdata->getHeight(0),
+		                          0,
+		                          GLsizei(cdata->getSize(0)),
+		                          cdata->getData(0));
+	}
+	else if (data)
+	{
+		glTexImage2D(GL_TEXTURE_2D,
+		             0,
+		             GL_RGBA8,
+		             (GLsizei)p2width,
+		             (GLsizei)p2height,
+		             0,
+		             GL_RGBA,
+		             GL_UNSIGNED_BYTE,
+		             0);
+
+		glTexSubImage2D(GL_TEXTURE_2D,
+		                0,
+		                0,
+		                0,
+		                (GLsizei)width,
+		                (GLsizei)height,
+		                GL_RGBA,
+		                GL_UNSIGNED_BYTE,
+		                data->getData());
+	}
 
 
 	if (glGetError() != GL_NO_ERROR)
 	if (glGetError() != GL_NO_ERROR)
 		throw love::Exception("Cannot create image: size may be too large for this system.");
 		throw love::Exception("Cannot create image: size may be too large for this system.");
@@ -337,15 +408,30 @@ bool Image::loadVolatileNPOT()
 
 
 	while (glGetError() != GL_NO_ERROR); // clear errors
 	while (glGetError() != GL_NO_ERROR); // clear errors
 
 
-	glTexImage2D(GL_TEXTURE_2D,
-	             0,
-	             GL_RGBA8,
-	             (GLsizei)width,
-	             (GLsizei)height,
-	             0,
-	             GL_RGBA,
-	             GL_UNSIGNED_BYTE,
-	             data->getData());
+	if (isCompressed() && cdata)
+	{
+		GLenum format = getCompressedFormat(cdata->getType());
+		glCompressedTexImage2DARB(GL_TEXTURE_2D,
+		                          0,
+		                          format,
+		                          cdata->getWidth(0),
+		                          cdata->getHeight(0),
+		                          0,
+		                          GLsizei(cdata->getSize(0)),
+		                          cdata->getData(0));
+	}
+	else if (data)
+	{
+		glTexImage2D(GL_TEXTURE_2D,
+		             0,
+		             GL_RGBA8,
+		             (GLsizei)width,
+		             (GLsizei)height,
+		             0,
+		             GL_RGBA,
+		             GL_UNSIGNED_BYTE,
+		             data->getData());
+	}
 
 
 	if (glGetError() != GL_NO_ERROR)
 	if (glGetError() != GL_NO_ERROR)
 		throw love::Exception("Cannot create image: size may be too large for this system.");
 		throw love::Exception("Cannot create image: size may be too large for this system.");
@@ -407,6 +493,34 @@ Image::FilterMode Image::getDefaultMipmapFilter()
 	return defaultMipmapFilter;
 	return defaultMipmapFilter;
 }
 }
 
 
+bool Image::isCompressed() const
+{
+	return compressed;
+}
+
+GLenum Image::getCompressedFormat(image::CompressedData::TextureType type) const
+{
+	switch (type)
+	{
+	case image::CompressedData::TYPE_DXT1:
+		return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+	case image::CompressedData::TYPE_DXT3:
+		return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+	case image::CompressedData::TYPE_DXT5:
+		return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+	case image::CompressedData::TYPE_BC5:
+		return GL_COMPRESSED_RG_RGTC2;
+	case image::CompressedData::TYPE_BC5s:
+		return GL_COMPRESSED_SIGNED_RG_RGTC2;
+	case image::CompressedData::TYPE_BC7:
+		return GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
+	case image::CompressedData::TYPE_BC7srgb:
+		return GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB;
+	default:
+		return GL_RGBA8;
+	}
+}
+
 bool Image::hasNpot()
 bool Image::hasNpot()
 {
 {
 	return GLEE_VERSION_2_0 || GLEE_ARB_texture_non_power_of_two;
 	return GLEE_VERSION_2_0 || GLEE_ARB_texture_non_power_of_two;
@@ -427,6 +541,37 @@ bool Image::hasMipmapSharpnessSupport()
 	return GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias;
 	return GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias;
 }
 }
 
 
+bool Image::hasCompressedTextureSupport()
+{
+	return GLEE_VERSION_1_3 || GLEE_ARB_texture_compression;
+}
+
+bool Image::hasCompressedTextureSupport(image::CompressedData::TextureType type)
+{
+	if (!hasCompressedTextureSupport())
+		return false;
+
+	switch (type)
+	{
+	case image::CompressedData::TYPE_DXT1:
+	case image::CompressedData::TYPE_DXT3:
+	case image::CompressedData::TYPE_DXT5:
+		return GLEE_EXT_texture_compression_s3tc;
+
+	case image::CompressedData::TYPE_BC5:
+	case image::CompressedData::TYPE_BC5s:
+		return (GLEE_VERSION_3_0 || GLEE_ARB_texture_compression_rgtc || GLEE_EXT_texture_compression_rgtc);
+
+	case image::CompressedData::TYPE_BC7:
+	case image::CompressedData::TYPE_BC7srgb:
+		return (GLEE_VERSION_4_2 || GLEE_ARB_texture_compression_bptc);
+
+	default:
+		return false;
+
+	}
+}
+
 } // opengl
 } // opengl
 } // graphics
 } // graphics
 } // love
 } // love

+ 33 - 16
src/modules/graphics/opengl/Image.h

@@ -26,6 +26,7 @@
 #include "common/math.h"
 #include "common/math.h"
 #include "common/config.h"
 #include "common/config.h"
 #include "image/ImageData.h"
 #include "image/ImageData.h"
+#include "image/CompressedData.h"
 #include "graphics/Image.h"
 #include "graphics/Image.h"
 
 
 // OpenGL
 // OpenGL
@@ -52,10 +53,17 @@ public:
 	 * Creates a new Image. Not that anything is ready to use
 	 * Creates a new Image. Not that anything is ready to use
 	 * before load is called.
 	 * before load is called.
 	 *
 	 *
-	 * @param file The file from which to load the image.
+	 * @param data The data from which to load the image.
 	 **/
 	 **/
 	Image(love::image::ImageData *data);
 	Image(love::image::ImageData *data);
 
 
+	/**
+	 * Creates a new Image with compressed image data.
+	 *
+	 * @param cdata The compressed data from which to load the image.
+	 **/
+	Image(love::image::CompressedData *cdata);
+
 	/**
 	/**
 	 * Destructor. Deletes the hardware texture and other resources.
 	 * Destructor. Deletes the hardware texture and other resources.
 	 **/
 	 **/
@@ -68,20 +76,6 @@ public:
 
 
 	love::image::ImageData *getData() const;
 	love::image::ImageData *getData() const;
 
 
-	/**
-	 * Generate vertices according to a subimage.
-	 *
-	 * Note: out-of-range values will be clamped.
-	 * Note: the vertex colors will not be changed.
-	 *
-	 * @param x The top-left corner of the subimage along the x-axis.
-	 * @param y The top-left corner of the subimage along the y-axis.
-	 * @param w The width of the subimage.
-	 * @param h The height of the subimage.
-	 * @param vertices A vertex array of size four.
-	 **/
-	void getRectangleVertices(int x, int y, int w, int h, vertex *vertices) const;
-
 	/**
 	/**
 	 * @copydoc Drawable::draw()
 	 * @copydoc Drawable::draw()
 	 **/
 	 **/
@@ -107,6 +101,11 @@ public:
 	void setMipmapSharpness(float sharpness);
 	void setMipmapSharpness(float sharpness);
 	float getMipmapSharpness() const;
 	float getMipmapSharpness() const;
 
 
+	/**
+	 * Whether this Image is using a compressed texture (via CompressedData).
+	 **/
+	bool isCompressed() const;
+
 	void bind() const;
 	void bind() const;
 
 
 	bool load();
 	bool load();
@@ -126,6 +125,9 @@ public:
 	static bool hasMipmapSupport();
 	static bool hasMipmapSupport();
 	static bool hasMipmapSharpnessSupport();
 	static bool hasMipmapSharpnessSupport();
 
 
+	static bool hasCompressedTextureSupport();
+	static bool hasCompressedTextureSupport(image::CompressedData::TextureType type);
+
 private:
 private:
 
 
 	void drawv(const Matrix &t, const vertex *v) const;
 	void drawv(const Matrix &t, const vertex *v) const;
@@ -135,9 +137,15 @@ private:
 	{
 	{
 		return texture;
 		return texture;
 	}
 	}
-	// The ImageData from which the texture is created.
+
+	// The ImageData from which the texture is created. May be null if
+	// Compressed image data was used to create the texture.
 	love::image::ImageData *data;
 	love::image::ImageData *data;
 
 
+	// Or the Compressed Image Data from which the texture is created. May be
+	// null if raw ImageData was used to create the texture.
+	love::image::CompressedData *cdata;
+
 	// Width and height of the hardware texture.
 	// Width and height of the hardware texture.
 	float width, height;
 	float width, height;
 
 
@@ -153,15 +161,22 @@ private:
 	// True if mipmaps have been created for this Image.
 	// True if mipmaps have been created for this Image.
 	bool mipmapsCreated;
 	bool mipmapsCreated;
 
 
+	// Whether this Image is using a compressed texture.
+	bool compressed;
+
 	// The image's filter mode
 	// The image's filter mode
 	Image::Filter filter;
 	Image::Filter filter;
 
 
 	// The image's wrap mode
 	// The image's wrap mode
 	Image::Wrap wrap;
 	Image::Wrap wrap;
 
 
+	void preload();
+
 	bool loadVolatilePOT();
 	bool loadVolatilePOT();
 	bool loadVolatileNPOT();
 	bool loadVolatileNPOT();
 
 
+	void uploadCompressedMipmaps();
+	void createMipmaps();
 	void checkMipmapsCreated();
 	void checkMipmapsCreated();
 
 
 	static float maxMipmapSharpness;
 	static float maxMipmapSharpness;
@@ -169,6 +184,8 @@ private:
 	static FilterMode defaultMipmapFilter;
 	static FilterMode defaultMipmapFilter;
 	static float defaultMipmapSharpness;
 	static float defaultMipmapSharpness;
 
 
+	GLenum getCompressedFormat(image::CompressedData::TextureType type) const;
+
 }; // Image
 }; // Image
 
 
 } // opengl
 } // opengl

+ 8 - 0
src/modules/graphics/opengl/OpenGL.cpp

@@ -97,6 +97,14 @@ void initializeContext()
 		glUnmapBufferARB = (GLEEPFNGLUNMAPBUFFERARBPROC) glUnmapBuffer;
 		glUnmapBufferARB = (GLEEPFNGLUNMAPBUFFERARBPROC) glUnmapBuffer;
 	}
 	}
 
 
+	// Same deal for compressed textures.
+	if (GLEE_VERSION_1_3 && !GLEE_ARB_texture_compression)
+	{
+		glCompressedTexImage2DARB = (GLEEPFNGLCOMPRESSEDTEXIMAGE2DARBPROC) glCompressedTexImage2D;
+		glCompressedTexSubImage2DARB = (GLEEPFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) glCompressedTexSubImage2D;
+		glGetCompressedTexImageARB = (GLEEPFNGLGETCOMPRESSEDTEXIMAGEARBPROC) glGetCompressedTexImage;
+	}
+
 	if (GLEE_EXT_texture_filter_anisotropic)
 	if (GLEE_EXT_texture_filter_anisotropic)
 		glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
 		glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
 	else
 	else

+ 55 - 10
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -158,7 +158,14 @@ int w_present(lua_State *)
 int w_setIcon(lua_State *L)
 int w_setIcon(lua_State *L)
 {
 {
 	Image *image = luax_checktype<Image>(L, 1, "Image", GRAPHICS_IMAGE_T);
 	Image *image = luax_checktype<Image>(L, 1, "Image", GRAPHICS_IMAGE_T);
-	instance->setIcon(image);
+	try
+	{
+		instance->setIcon(image);
+	}
+	catch (love::Exception &e)
+	{
+		return luaL_error(L, "%s", e.what());
+	}
 	return 0;
 	return 0;
 }
 }
 
 
@@ -269,21 +276,45 @@ int w_setInvertedStencil(lua_State *L)
 
 
 int w_newImage(lua_State *L)
 int w_newImage(lua_State *L)
 {
 {
-	// Convert to File, if necessary.
-	if (lua_isstring(L, 1))
-		luax_convobj(L, 1, "filesystem", "newFile");
+	love::image::ImageData *data = 0;
+	love::image::CompressedData *cdata = 0;
 
 
-	// Convert to ImageData, if necessary.
-	if (luax_istype(L, 1, FILESYSTEM_FILE_T))
-		luax_convobj(L, 1, "image", "newImageData");
+	// Convert to FileData, if necessary.
+	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
+		luax_convobj(L, 1, "filesystem", "newFileData");
+
+	// Convert to ImageData/CompressedData, if necessary.
+	if (luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
+	{
+		// Determine whether to convert to ImageData or CompressedData.
+		luax_getfunction(L, "image", "isCompressed");
+		lua_pushvalue(L, 1);
+		lua_call(L, 1, 1);
+
+		bool compressed = luax_toboolean(L, -1);
+		lua_pop(L, 1);
 
 
-	love::image::ImageData *data = luax_checktype<love::image::ImageData>(L, 1, "ImageData", IMAGE_IMAGE_DATA_T);
+		if (compressed)
+			luax_convobj(L, 1, "image", "newCompressedData");
+		else
+			luax_convobj(L, 1, "image", "newImageData");
+	}
+
+	if (luax_istype(L, 1, IMAGE_COMPRESSED_DATA_T))
+		cdata = luax_checktype<love::image::CompressedData>(L, 1, "CompressedData", IMAGE_COMPRESSED_DATA_T);
+	else
+		data = luax_checktype<love::image::ImageData>(L, 1, "ImageData", IMAGE_IMAGE_DATA_T);
 
 
 	// Create the image.
 	// Create the image.
 	Image *image = 0;
 	Image *image = 0;
 	try
 	try
 	{
 	{
-		image = instance->newImage(data);
+		if (cdata)
+			image = instance->newImage(cdata);
+		else if (data)
+			image = instance->newImage(data);
+		else
+			throw love::Exception("Error creating image.");
 	}
 	}
 	catch(love::Exception &e)
 	catch(love::Exception &e)
 	{
 	{
@@ -387,7 +418,7 @@ int w_newImageFont(lua_State *L)
 	int startIndex = 2;
 	int startIndex = 2;
 
 
 	// Convert to ImageData if necessary.
 	// Convert to ImageData if necessary.
-	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || (luax_istype(L, 1, DATA_T) && !luax_istype(L, 1, IMAGE_IMAGE_DATA_T)))
+	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
 		luax_convobj(L, 1, "image", "newImageData");
 		luax_convobj(L, 1, "image", "newImageData");
 	else if (luax_istype(L, 1, GRAPHICS_IMAGE_T))
 	else if (luax_istype(L, 1, GRAPHICS_IMAGE_T))
 	{
 	{
@@ -395,6 +426,8 @@ int w_newImageFont(lua_State *L)
 		img_filter = i->getFilter();
 		img_filter = i->getFilter();
 		setFilter = true;
 		setFilter = true;
 		love::image::ImageData *id = i->getData();
 		love::image::ImageData *id = i->getData();
+		if (!id)
+			return luaL_argerror(L, 1, "image cannot be compressed");
 		luax_newtype(L, "ImageData", IMAGE_IMAGE_DATA_T, (void *)id, false);
 		luax_newtype(L, "ImageData", IMAGE_IMAGE_DATA_T, (void *)id, false);
 		lua_replace(L, 1);
 		lua_replace(L, 1);
 	}
 	}
@@ -1110,6 +1143,18 @@ int w_isSupported(lua_State *L)
 			if (!Image::hasMipmapSupport())
 			if (!Image::hasMipmapSupport())
 				supported = false;
 				supported = false;
 			break;
 			break;
+		case Graphics::SUPPORT_DXT:
+			if (!Image::hasCompressedTextureSupport(image::CompressedData::TYPE_DXT5))
+				supported = false;
+			break;
+		case Graphics::SUPPORT_BC5:
+			if (!Image::hasCompressedTextureSupport(image::CompressedData::TYPE_BC5))
+				supported = false;
+			break;
+		case Graphics::SUPPORT_BC7:
+			if (!Image::hasCompressedTextureSupport(image::CompressedData::TYPE_BC7))
+				supported = false;
+			break;
 		default:
 		default:
 			supported = false;
 			supported = false;
 		}
 		}

+ 8 - 0
src/modules/graphics/opengl/wrap_Image.cpp

@@ -175,6 +175,13 @@ int w_Image_getWrap(lua_State *L)
 	return 2;
 	return 2;
 }
 }
 
 
+int w_Image_isCompressed(lua_State *L)
+{
+	Image *i = luax_checkimage(L, 1);
+	luax_pushboolean(L, i->isCompressed());
+	return 1;
+}
+
 static const luaL_Reg functions[] =
 static const luaL_Reg functions[] =
 {
 {
 	{ "getWidth", w_Image_getWidth },
 	{ "getWidth", w_Image_getWidth },
@@ -186,6 +193,7 @@ static const luaL_Reg functions[] =
 	{ "getWrap", w_Image_getWrap },
 	{ "getWrap", w_Image_getWrap },
 	{ "setMipmapFilter", w_Image_setMipmapFilter },
 	{ "setMipmapFilter", w_Image_setMipmapFilter },
 	{ "getMipmapFilter", w_Image_getMipmapFilter },
 	{ "getMipmapFilter", w_Image_getMipmapFilter },
+	{ "isCompressed", w_Image_isCompressed },
 	{ 0, 0 }
 	{ 0, 0 }
 };
 };
 
 

+ 1 - 0
src/modules/graphics/opengl/wrap_Image.h

@@ -42,6 +42,7 @@ int w_Image_setMipmapFilter(lua_State *L);
 int w_Image_getMipmapFilter(lua_State *L);
 int w_Image_getMipmapFilter(lua_State *L);
 int w_Image_setWrap(lua_State *L);
 int w_Image_setWrap(lua_State *L);
 int w_Image_getWrap(lua_State *L);
 int w_Image_getWrap(lua_State *L);
+int w_Image_isCompressed(lua_State *L);
 extern "C" int luaopen_image(lua_State *L);
 extern "C" int luaopen_image(lua_State *L);
 
 
 } // opengl
 } // opengl

+ 127 - 0
src/modules/image/CompressedData.cpp

@@ -0,0 +1,127 @@
+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "CompressedData.h"
+
+namespace love
+{
+namespace image
+{
+
+CompressedData::CompressedData()
+	: type(TYPE_UNKNOWN)
+{
+}
+
+CompressedData::~CompressedData()
+{
+}
+
+int CompressedData::getSize() const
+{
+	// Adding up the total size for all mipmap levels would make more sense, but
+	// it's probably better for getSize() to match getData() so no bad memory
+	// accesses happen...
+	if (dataImages.size() > 0)
+		return dataImages[0].size;
+	else
+		return 0;
+}
+
+void *CompressedData::getData() const
+{
+	// Data for different mipmap levels is not stored contiguously in memory, so
+	// getData() won't work properly for CompressedData.
+	if (dataImages.size() > 0)
+		return (void *) &(dataImages[0].data[0]);
+	else
+		return 0;
+}
+
+int CompressedData::getNumMipmaps() const
+{
+	return dataImages.size();
+}
+
+int CompressedData::getSize(int miplevel) const
+{
+	checkMipmapLevelExists(miplevel);
+
+	return dataImages[miplevel].size;
+}
+
+void *CompressedData::getData(int miplevel) const
+{
+	checkMipmapLevelExists(miplevel);
+
+	return (void *) &dataImages[miplevel].data[0];
+}
+
+int CompressedData::getWidth(int miplevel) const
+{
+	checkMipmapLevelExists(miplevel);
+
+	return dataImages[miplevel].width;
+}
+
+int CompressedData::getHeight(int miplevel) const
+{
+	checkMipmapLevelExists(miplevel);
+
+	return dataImages[miplevel].height;
+}
+
+CompressedData::TextureType CompressedData::getType() const
+{
+	return type;
+}
+
+void CompressedData::checkMipmapLevelExists(int miplevel) const
+{
+	if (miplevel < 0 || miplevel >= dataImages.size())
+		throw love::Exception("Mipmap level %d does not exist", miplevel);
+}
+
+bool CompressedData::getConstant(const char *in, CompressedData::TextureType &out)
+{
+	return types.find(in, out);
+}
+
+bool CompressedData::getConstant(CompressedData::TextureType in, const char *&out)
+{
+	return types.find(in, out);
+}
+
+StringMap<CompressedData::TextureType, CompressedData::TYPE_MAX_ENUM>::Entry CompressedData::typeEntries[] =
+{
+	{"unknown", CompressedData::TYPE_UNKNOWN},
+	{"dxt1", CompressedData::TYPE_DXT1},
+	{"dxt3", CompressedData::TYPE_DXT3},
+	{"dxt5", CompressedData::TYPE_DXT5},
+	{"bc5", CompressedData::TYPE_BC5},
+	{"bc5s", CompressedData::TYPE_BC5s},
+	{"bc7", CompressedData::TYPE_BC7},
+	{"bc7srgb", CompressedData::TYPE_BC7srgb},
+};
+
+StringMap<CompressedData::TextureType, CompressedData::TYPE_MAX_ENUM> CompressedData::types(CompressedData::typeEntries, sizeof(CompressedData::typeEntries));
+
+} // image
+} // love

+ 132 - 0
src/modules/image/CompressedData.h

@@ -0,0 +1,132 @@
+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_IMAGE_COMPRESSED_DATA_H
+#define LOVE_IMAGE_COMPRESSED_DATA_H
+
+// LOVE
+#include "common/Data.h"
+#include "common/StringMap.h"
+#include "thread/threads.h"
+
+using love::thread::Mutex;
+
+// STL
+#include <vector>
+
+namespace love
+{
+namespace image
+{
+
+// CompressedData represents image data which is designed to be uploaded to the
+// GPU and rendered in its compressed form, without being un-compressed.
+// http://renderingpipeline.com/2012/07/texture-compression/
+
+class CompressedData : public Data
+{
+public:
+
+	// Types of compressed image data.
+	enum TextureType
+	{
+		TYPE_UNKNOWN,
+		TYPE_DXT1,
+		TYPE_DXT3,
+		TYPE_DXT5,
+		TYPE_BC5,
+		TYPE_BC5s,
+		TYPE_BC7,
+		TYPE_BC7srgb,
+		TYPE_MAX_ENUM
+	};
+
+	// Compressed image data can have multiple mipmap levels, each represented
+	// by a sub-image.
+	struct SubImage
+	{
+		int width, height;
+		size_t size;
+		std::vector<unsigned char> data;
+	};
+
+	CompressedData();
+	virtual ~CompressedData();
+
+	// Implements Data. Note that data for different mipmap levels is not always
+	// stored contiguously in memory, so getData() and getSize() don't make
+	// much sense. Use getData(miplevel) and getSize(mipleveL) instead.
+	virtual void *getData() const;
+	virtual int getSize() const;
+
+	/**
+	 * Gets the number of mipmaps in this CompressedData.
+	 * Includes the base image level.
+	 **/
+	int getNumMipmaps() const;
+
+	/**
+	 * Gets the size in bytes of a sub-image at the specified mipmap level.
+	 **/
+	int getSize(int miplevel) const;
+
+	/**
+	 * Gets the byte data of a sub-image at the specified mipmap level.
+	 **/
+	void *getData(int miplevel) const;
+
+	/**
+	 * Gets the width of a sub-image at the specified mipmap level.
+	 **/
+	int getWidth(int miplevel) const;
+
+	/**
+	 * Gets the height of a sub-image at the specified mipmap level.
+	 **/
+	int getHeight(int miplevel) const;
+
+	/**
+	 * Gets the type of the compressed data.
+	 **/
+	TextureType getType() const;
+
+	static bool getConstant(const char *in, TextureType &out);
+	static bool getConstant(TextureType in, const char *&out);
+
+protected:
+
+	TextureType type;
+
+	// Texture info for each mipmap level.
+	std::vector<SubImage> dataImages;
+
+	void checkMipmapLevelExists(int miplevel) const;
+
+private:
+
+	static StringMap<TextureType, TYPE_MAX_ENUM>::Entry typeEntries[];
+	static StringMap<TextureType, TYPE_MAX_ENUM> types;
+
+}; // CompressedData
+
+} // image
+} // love
+
+#endif // LOVE_IMAGE_COMPRESSED_DATA_H

+ 21 - 12
src/modules/image/Image.h

@@ -26,6 +26,7 @@
 #include "common/Module.h"
 #include "common/Module.h"
 #include "filesystem/File.h"
 #include "filesystem/File.h"
 #include "ImageData.h"
 #include "ImageData.h"
+#include "CompressedData.h"
 
 
 namespace love
 namespace love
 {
 {
@@ -34,8 +35,10 @@ namespace image
 
 
 /**
 /**
  * This module is responsible for decoding files such as PNG, GIF, JPEG
  * This module is responsible for decoding files such as PNG, GIF, JPEG
- * into raw pixel data. This module does not know how to draw images on
- * screen; only love.graphics knows that.
+ * into raw pixel data, as well as parsing compressed formats which are designed
+ * to be uploaded to the GPU and rendered without being un-compressed.
+ * This module does not know how to draw images on screen; only love.graphics
+ * knows that.
  **/
  **/
 class Image : public Module
 class Image : public Module
 {
 {
@@ -47,18 +50,11 @@ public:
 	virtual ~Image() {};
 	virtual ~Image() {};
 
 
 	/**
 	/**
-	 * Creates new ImageData from a file.
-	 * @param file The file containing the encoded image data.
+	 * Creates new ImageData from FileData.
+	 * @param data The FileData containing the encoded image data.
 	 * @return The new ImageData.
 	 * @return The new ImageData.
 	 **/
 	 **/
-	virtual ImageData *newImageData(love::filesystem::File *file) = 0;
-
-	/**
-	 * Creates new ImageData from a raw Data.
-	 * @param data The object containing encoded pixel data.
-	 * @return The new ImageData.
-	 **/
-	virtual ImageData *newImageData(Data *data) = 0;
+	virtual ImageData *newImageData(love::filesystem::FileData *data) = 0;
 
 
 	/**
 	/**
 	 * Creates empty ImageData with the given size.
 	 * Creates empty ImageData with the given size.
@@ -77,6 +73,19 @@ public:
 	 **/
 	 **/
 	virtual ImageData *newImageData(int width, int height, void *data) = 0;
 	virtual ImageData *newImageData(int width, int height, void *data) = 0;
 
 
+	/**
+	 * Creates new CompressedData from FileData.
+	 * @param data The FileData containing the compressed image data.
+	 * @return The new CompressedData.
+	 **/
+	virtual CompressedData *newCompressedData(love::filesystem::FileData *data) = 0;
+
+	/**
+	 * Determines whether a FileData is Compressed image data or not.
+	 * @param data The FileData to test.
+	 **/
+	virtual bool isCompressed(love::filesystem::FileData *data) = 0;
+
 }; // Image
 }; // Image
 
 
 } // image
 } // image

+ 8 - 9
src/modules/image/ImageData.cpp

@@ -20,8 +20,6 @@
 
 
 #include "ImageData.h"
 #include "ImageData.h"
 
 
-#include <stdio.h>
-
 using love::thread::Lock;
 using love::thread::Lock;
 
 
 namespace love
 namespace love
@@ -30,6 +28,7 @@ namespace image
 {
 {
 
 
 ImageData::ImageData()
 ImageData::ImageData()
+	: data(0)
 {
 {
 	mutex = thread::newMutex();
 	mutex = thread::newMutex();
 }
 }
@@ -39,14 +38,19 @@ ImageData::~ImageData()
 	delete mutex;
 	delete mutex;
 }
 }
 
 
+int ImageData::getSize() const
+{
+	return getWidth()*getHeight()*sizeof(pixel);
+}
+
 void *ImageData::getData() const
 void *ImageData::getData() const
 {
 {
 	return data;
 	return data;
 }
 }
 
 
-int ImageData::getSize() const
+bool ImageData::inside(int x, int y) const
 {
 {
-	return getWidth()*getHeight()*sizeof(pixel);
+	return x >= 0 && x < getWidth() && y >= 0 && y < getHeight();
 }
 }
 
 
 int ImageData::getWidth() const
 int ImageData::getWidth() const
@@ -59,11 +63,6 @@ int ImageData::getHeight() const
 	return height;
 	return height;
 }
 }
 
 
-bool ImageData::inside(int x, int y) const
-{
-	return x >= 0 && x < getWidth() && y >= 0 && y < getHeight();
-}
-
 void ImageData::setPixel(int x, int y, pixel c)
 void ImageData::setPixel(int x, int y, pixel c)
 {
 {
 	if (!inside(x, y))
 	if (!inside(x, y))

+ 19 - 18
src/modules/image/ImageData.h

@@ -45,22 +45,6 @@ struct pixel
  **/
  **/
 class ImageData : public Data
 class ImageData : public Data
 {
 {
-protected:
-
-	// The width of the image data.
-	int width;
-
-	// The height of the image data.
-	int height;
-
-	// The actual data.
-	unsigned char *data;
-
-	// We need to be thread-safe
-	// so we lock when we're accessing our
-	// data
-	Mutex *mutex;
-
 public:
 public:
 
 
 	enum Format
 	enum Format
@@ -137,10 +121,27 @@ public:
 	virtual void encode(love::filesystem::File *f, Format format) = 0;
 	virtual void encode(love::filesystem::File *f, Format format) = 0;
 
 
 	// Implements Data.
 	// Implements Data.
-	void *getData() const;
-	int getSize() const;
+	virtual void *getData() const;
+	virtual int getSize() const;
+
+protected:
+
+	// The width of the image data.
+	int width;
+
+	// The height of the image data.
+	int height;
+
+	// The actual data.
+	unsigned char *data;
+
+	// We need to be thread-safe
+	// so we lock when we're accessing our
+	// data
+	Mutex *mutex;
 
 
 private:
 private:
+
 	static StringMap<Format, FORMAT_MAX_ENUM>::Entry formatEntries[];
 	static StringMap<Format, FORMAT_MAX_ENUM>::Entry formatEntries[];
 	static StringMap<Format, FORMAT_MAX_ENUM> formats;
 	static StringMap<Format, FORMAT_MAX_ENUM> formats;
 
 

+ 70 - 0
src/modules/image/magpie/CompressedData.cpp

@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "CompressedData.h"
+
+#include "ddsHandler.h"
+
+namespace love
+{
+namespace image
+{
+namespace magpie
+{
+
+CompressedData::CompressedData(love::filesystem::FileData *data)
+{
+	load(data);
+}
+
+CompressedData::~CompressedData()
+{
+}
+
+void CompressedData::load(love::filesystem::FileData *data)
+{
+	// SubImage vector will be populated by a parser.
+	std::vector<SubImage> parsedimages;
+	TextureType textype = TYPE_UNKNOWN;
+
+	if (ddsHandler::canParse(data))
+		textype = ddsHandler::parse(data, parsedimages);
+
+	if (textype == TYPE_UNKNOWN)
+		throw love::Exception("Could not parse compressed data: Unknown format.");
+
+	if (parsedimages.size() == 0)
+		throw love::Exception("Could not parse compressed data: No valid data?");
+
+	dataImages = parsedimages;
+	type = textype;
+}
+
+bool CompressedData::isCompressed(love::filesystem::FileData *data)
+{
+	if (ddsHandler::canParse(data))
+		return true;
+
+	return false;
+}
+
+} // magpie
+} // image
+} // love

+ 54 - 0
src/modules/image/magpie/CompressedData.h

@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_IMAGE_MAGPIE_COMPRESSED_DATA_H
+#define LOVE_IMAGE_MAGPIE_COMPRESSED_DATA_H
+
+// LOVE
+#include "filesystem/FileData.h"
+#include "image/CompressedData.h"
+
+namespace love
+{
+namespace image
+{
+namespace magpie
+{
+
+class CompressedData : public love::image::CompressedData
+{
+public:
+
+	CompressedData(love::filesystem::FileData *data);
+	virtual ~CompressedData();
+
+	static bool isCompressed(love::filesystem::FileData *data);
+
+private:
+
+	void load(love::filesystem::FileData *data);
+
+}; // CompressedData
+
+} // magpie
+} // image
+} // love
+
+#endif // LOVE_IMAGE_MAGPIE_COMPRESSED_DATA_H

+ 58 - 70
src/modules/image/devil/ImageData.cpp → src/modules/image/magpie/DevilHandler.cpp

@@ -18,16 +18,15 @@
  * 3. This notice may not be removed or altered from any source distribution.
  * 3. This notice may not be removed or altered from any source distribution.
  **/
  **/
 
 
-#include "ImageData.h"
-
-// STD
-#include <cstring>
-#include <iostream>
+#include "DevilHandler.h"
 
 
 // LOVE
 // LOVE
 #include "common/Exception.h"
 #include "common/Exception.h"
 #include "common/math.h"
 #include "common/math.h"
-#include "filesystem/File.h"
+#include "thread/threads.h"
+
+// DevIL
+#include <IL/il.h>
 
 
 using love::thread::Lock;
 using love::thread::Lock;
 
 
@@ -37,7 +36,7 @@ namespace love
 {
 {
 namespace image
 namespace image
 {
 {
-namespace devil
+namespace magpie
 {
 {
 
 
 static inline void ilxClearErrors()
 static inline void ilxClearErrors()
@@ -45,81 +44,61 @@ static inline void ilxClearErrors()
 	while (ilGetError() != IL_NO_ERROR);
 	while (ilGetError() != IL_NO_ERROR);
 }
 }
 
 
-ImageData::ImageData(Data *data)
+void DevilHandler::init()
 {
 {
-	load(data);
+	ilInit();
+	ilEnable(IL_ORIGIN_SET);
+	ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
 }
 }
 
 
-ImageData::ImageData(filesystem::File *file)
+void DevilHandler::quit()
 {
 {
-	Data *data = file->read();
-	try
-	{
-		load(data);
-	}
-	catch (love::Exception &)
-	{
-		data->release();
-		throw;
-	}
-	data->release();
+	ilShutDown();
 }
 }
 
 
-ImageData::ImageData(int width, int height)
+bool DevilHandler::canDecode(love::filesystem::FileData *data)
 {
 {
-	this->width = width;
-	this->height = height;
-	create(width, height);
-
-	// Set to black.
-	memset(data, 0, width*height*4);
+	// DevIL can decode a lot of formats...
+	return true;
 }
 }
 
 
-ImageData::ImageData(int width, int height, void *data)
+bool DevilHandler::canEncode(ImageData::Format format)
 {
 {
-	this->width = width;
-	this->height = height;
-	create(width, height, data);
-}
-
-ImageData::~ImageData()
-{
-	delete[] data;
-}
-
-void ImageData::create(int width, int height, void *data)
-{
-	try
+	switch (format)
 	{
 	{
-		this->data = new unsigned char[width*height*sizeof(pixel)];
-	}
-	catch(std::bad_alloc &)
-	{
-		throw love::Exception("Out of memory");
+	case ImageData::FORMAT_BMP:
+	case ImageData::FORMAT_TGA:
+	case ImageData::FORMAT_JPG:
+	case ImageData::FORMAT_PNG:
+		return true;
+	default:
+		return false;
 	}
 	}
 
 
-	if (data)
-		memcpy(this->data, data, width*height*sizeof(pixel));
+	return false;
 }
 }
 
 
-void ImageData::load(Data *data)
+DevilHandler::DecodedImage DevilHandler::decode(love::filesystem::FileData *data)
 {
 {
 	if (!devilMutex)
 	if (!devilMutex)
 		devilMutex = thread::newMutex();
 		devilMutex = thread::newMutex();
 
 
 	Lock lock(devilMutex);
 	Lock lock(devilMutex);
+
 	ILuint image = ilGenImage();
 	ILuint image = ilGenImage();
 	ilBindImage(image);
 	ilBindImage(image);
 
 
+	DecodedImage img;
+
 	try
 	try
 	{
 	{
-		bool success = IL_TRUE == ilLoadL(IL_TYPE_UNKNOWN, (void *)data->getData(), data->getSize());
+		bool success = ilLoadL(IL_TYPE_UNKNOWN, (void *)data->getData(), data->getSize()) == IL_TRUE;
 
 
 		if (!success)
 		if (!success)
 			throw love::Exception("Could not decode image!");
 			throw love::Exception("Could not decode image!");
 
 
-		width = ilGetInteger(IL_IMAGE_WIDTH);
-		height = ilGetInteger(IL_IMAGE_HEIGHT);
+		img.width = ilGetInteger(IL_IMAGE_WIDTH);
+		img.height = ilGetInteger(IL_IMAGE_HEIGHT);
 
 
 		// Make sure the image is in RGBA format.
 		// Make sure the image is in RGBA format.
 		ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE);
 		ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE);
@@ -129,7 +108,18 @@ void ImageData::load(Data *data)
 		if (bpp != sizeof(pixel))
 		if (bpp != sizeof(pixel))
 			throw love::Exception("Could not convert image!");
 			throw love::Exception("Could not convert image!");
 
 
-		create(width, height, ilGetData());
+		img.size = ilGetInteger(IL_IMAGE_SIZE_OF_DATA);
+
+		try
+		{
+			img.data = new ILubyte[img.size];
+		}
+		catch (std::bad_alloc &)
+		{
+			throw love::Exception("Out of memory.");
+		}
+
+		memcpy(img.data, ilGetData(), img.size);
 	}
 	}
 	catch (std::exception &e)
 	catch (std::exception &e)
 	{
 	{
@@ -139,25 +129,26 @@ void ImageData::load(Data *data)
 	}
 	}
 
 
 	ilDeleteImage(image);
 	ilDeleteImage(image);
+
+	return img;
 }
 }
 
 
-void ImageData::encode(love::filesystem::File *f, ImageData::Format format)
+DevilHandler::EncodedImage DevilHandler::encode(const DecodedImage &img, ImageData::Format format)
 {
 {
 	if (!devilMutex)
 	if (!devilMutex)
 		devilMutex = thread::newMutex();
 		devilMutex = thread::newMutex();
 
 
-	Lock lock1(devilMutex);
-	Lock lock2(mutex);
+	Lock lock(devilMutex);
 
 
 	ILuint tempimage = ilGenImage();
 	ILuint tempimage = ilGenImage();
 	ilBindImage(tempimage);
 	ilBindImage(tempimage);
 	ilxClearErrors();
 	ilxClearErrors();
 
 
-	ILubyte *encoded_data = NULL;
+	EncodedImage encodedimage;
 
 
 	try
 	try
 	{
 	{
-		bool success = IL_TRUE == ilTexImage(width, height, 1, sizeof(pixel), IL_RGBA, IL_UNSIGNED_BYTE, this->data);
+		bool success = ilTexImage(img.width, img.height, 1, sizeof(pixel), IL_RGBA, IL_UNSIGNED_BYTE, img.data) ==  IL_TRUE;
 
 
 		ILenum err = ilGetError();
 		ILenum err = ilGetError();
 		ilxClearErrors();
 		ilxClearErrors();
@@ -202,37 +193,34 @@ void ImageData::encode(love::filesystem::File *f, ImageData::Format format)
 			break;
 			break;
 		}
 		}
 
 
-		ILuint size = ilSaveL(ilFormat, NULL, 0);
-		if (!size)
+		encodedimage.size = ilSaveL(ilFormat, NULL, 0);
+		if (!encodedimage.size)
 			throw love::Exception("Could not encode image!");
 			throw love::Exception("Could not encode image!");
 
 
 		try
 		try
 		{
 		{
-			encoded_data = new ILubyte[size];
+			encodedimage.data = new ILubyte[encodedimage.size];
 		}
 		}
 		catch(std::bad_alloc &)
 		catch(std::bad_alloc &)
 		{
 		{
 			throw love::Exception("Out of memory");
 			throw love::Exception("Out of memory");
 		}
 		}
 
 
-		ilSaveL(ilFormat, encoded_data, size);
-
-		f->open(love::filesystem::File::WRITE);
-		f->write(encoded_data, size);
-		f->close();
+		ilSaveL(ilFormat, encodedimage.data, encodedimage.size);
 	}
 	}
 	catch (std::exception &e)
 	catch (std::exception &e)
 	{
 	{
 		// catches love and std exceptions
 		// catches love and std exceptions
 		ilDeleteImage(tempimage);
 		ilDeleteImage(tempimage);
-		delete[] encoded_data;
+		delete[] encodedimage.data;
 		throw love::Exception("%s", e.what());
 		throw love::Exception("%s", e.what());
 	}
 	}
 
 
 	ilDeleteImage(tempimage);
 	ilDeleteImage(tempimage);
-	delete[] encoded_data;
+
+	return encodedimage;
 }
 }
 
 
-} // devil
+} // magpie
 } // image
 } // image
 } // love
 } // love

+ 59 - 0
src/modules/image/magpie/DevilHandler.h

@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_IMAGE_MAGPIE_DEVIL_HANDLER_H
+#define LOVE_IMAGE_MAGPIE_DEVIL_HANDLER_H
+
+// LOVE
+#include "filesystem/FileData.h"
+#include "FormatHandler.h"
+
+namespace love
+{
+namespace image
+{
+namespace magpie
+{
+
+/**
+ * Interface between ImageData and DevIL.
+ **/
+class DevilHandler : public FormatHandler
+{
+public:
+
+	static void init();
+	static void quit();
+
+	// Implements FormatHandler.
+
+	static bool canDecode(love::filesystem::FileData *data);
+	static bool canEncode(ImageData::Format format);
+
+	static DecodedImage decode(love::filesystem::FileData *data);
+	static EncodedImage encode(const DecodedImage &img, ImageData::Format format);
+
+}; // DevilHandler
+
+} // magpie
+} // image
+} // love
+
+#endif // LOVE_IMAGE_MAGPIE_DEVIL_HANDLER_H

+ 94 - 0
src/modules/image/magpie/FormatHandler.h

@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_IMAGE_MAGPIE_FORMAT_HANDLER_H
+#define LOVE_IMAGE_MAGPIE_FORMAT_HANDLER_H
+
+// LOVE
+#include "image/ImageData.h"
+#include "filesystem/FileData.h"
+
+namespace love
+{
+namespace image
+{
+namespace magpie
+{
+
+/**
+ * Base class for all ImageData encoder/decoder library interfaces.
+ **/
+class FormatHandler
+{
+public:
+
+	// Raw RGBA pixel data.
+	struct DecodedImage
+	{
+		int width, height;
+		size_t size;
+		unsigned char *data;
+		DecodedImage() : width(0), height(0), size(0), data(0) {};
+	};
+
+	// Pixel data encoded in a particular format.
+	struct EncodedImage
+	{
+		size_t size;
+		unsigned char *data;
+		EncodedImage() : size(0), data(0) {};
+	};
+
+	// Lets pretend we have virtual static methods...
+
+	/**
+	 * Determines whether a particular FileData can be decoded by this handler.
+	 * @param data The data to decode.
+	 **/
+	// virtual static bool canDecode(love::filesystem::FileData *data) = 0;
+
+	/**
+	 * Determines whether this handler can encode to a particular format.
+	 * @param format The format to encode to.
+	 **/
+	// virtual static bool canEncode(ImageData::Format format) = 0;
+
+	/**
+	 * Decodes an image from its encoded form into raw pixel data.
+	 * @param data The encoded data to decode.
+	 * @return The decoded pixel data.
+	 **/
+	// virtual static DecodedImage decode(love::filesystem::FileData *data) = 0;
+
+	/**
+	 * Encodes an image from raw pixel data into a particular format.
+	 * @param img The raw image data to encode.
+	 * @param format The format to encode to.
+	 * @return The encoded image data.
+	 **/
+	// virtual static EncodedImage encode(const DecodedImage &img, ImageData::Format format) = 0;
+
+}; // FormatHandler
+
+} // magpie
+} // image
+} // love
+
+#endif // LOVE_IMAGE_MAGPIE_FORMAT_HANDLER_H

+ 19 - 16
src/modules/image/devil/Image.cpp → src/modules/image/magpie/Image.cpp

@@ -20,41 +20,34 @@
 
 
 #include "Image.h"
 #include "Image.h"
 
 
-#include "ImageData.h"
+#include "imageData.h"
+#include "CompressedData.h"
 
 
-// DevIL
-#include <IL/il.h>
+#include "DevilHandler.h"
 
 
 namespace love
 namespace love
 {
 {
 namespace image
 namespace image
 {
 {
-namespace devil
+namespace magpie
 {
 {
 
 
 Image::Image()
 Image::Image()
 {
 {
-	ilInit();
-	ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
-	ilEnable(IL_ORIGIN_SET);
+	DevilHandler::init();
 }
 }
 
 
 Image::~Image()
 Image::~Image()
 {
 {
-	ilShutDown();
+	DevilHandler::quit();
 }
 }
 
 
 const char *Image::getName() const
 const char *Image::getName() const
 {
 {
-	return "love.image.devil";
+	return "love.image.magpie";
 }
 }
 
 
-love::image::ImageData *Image::newImageData(love::filesystem::File *file)
-{
-	return new ImageData(file);
-}
-
-love::image::ImageData *Image::newImageData(Data *data)
+love::image::ImageData *Image::newImageData(love::filesystem::FileData *data)
 {
 {
 	return new ImageData(data);
 	return new ImageData(data);
 }
 }
@@ -69,6 +62,16 @@ love::image::ImageData *Image::newImageData(int width, int height, void *data)
 	return new ImageData(width, height, data);
 	return new ImageData(width, height, data);
 }
 }
 
 
-} // devil
+love::image::CompressedData *Image::newCompressedData(love::filesystem::FileData *data)
+{
+	return new CompressedData(data);
+}
+
+bool Image::isCompressed(love::filesystem::FileData *data)
+{
+	return CompressedData::isCompressed(data);
+}
+
+} // magpie
 } // image
 } // image
 } // love
 } // love

+ 15 - 7
src/modules/image/devil/Image.h → src/modules/image/magpie/Image.h

@@ -18,8 +18,8 @@
  * 3. This notice may not be removed or altered from any source distribution.
  * 3. This notice may not be removed or altered from any source distribution.
  **/
  **/
 
 
-#ifndef LOVE_IMAGE_DEVIL_IMAGE_H
-#define LOVE_IMAGE_DEVIL_IMAGE_H
+#ifndef LOVE_IMAGE_MAGPIE_IMAGE_H
+#define LOVE_IMAGE_MAGPIE_IMAGE_H
 
 
 // LOVE
 // LOVE
 #include "image/Image.h"
 #include "image/Image.h"
@@ -28,9 +28,14 @@ namespace love
 {
 {
 namespace image
 namespace image
 {
 {
-namespace devil
+namespace magpie
 {
 {
 
 
+/**
+ * Similar to love.sound's Lullaby module, love.image.magpie interfaces with
+ * multiple image libraries and determines the correct one to use on a
+ * per-image basis at runtime.
+ **/
 class Image : public love::image::Image
 class Image : public love::image::Image
 {
 {
 public:
 public:
@@ -41,15 +46,18 @@ public:
 	// Implements Module.
 	// Implements Module.
 	const char *getName() const;
 	const char *getName() const;
 
 
-	love::image::ImageData *newImageData(love::filesystem::File *file);
-	love::image::ImageData *newImageData(Data *data);
+	love::image::ImageData *newImageData(love::filesystem::FileData *data);
 	love::image::ImageData *newImageData(int width, int height);
 	love::image::ImageData *newImageData(int width, int height);
 	love::image::ImageData *newImageData(int width, int height, void *data);
 	love::image::ImageData *newImageData(int width, int height, void *data);
 
 
+	love::image::CompressedData *newCompressedData(love::filesystem::FileData *data);
+
+	bool isCompressed(love::filesystem::FileData *data);
+
 }; // Image
 }; // Image
 
 
-} // devil
+} // magpie
 } // image
 } // image
 } // love
 } // love
 
 
-#endif // LOVE_IMAGE_DEVIL_IMAGE_H
+#endif // LOVE_IMAGE_MAGPIE_IMAGE_H

+ 133 - 0
src/modules/image/magpie/ImageData.cpp

@@ -0,0 +1,133 @@
+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "ImageData.h"
+
+#include "FormatHandler.h"
+#include "DevilHandler.h"
+
+namespace love
+{
+namespace image
+{
+namespace magpie
+{
+
+ImageData::ImageData(love::filesystem::FileData *data)
+{
+	decode(data);
+}
+
+ImageData::ImageData(int width, int height)
+{
+	this->width = width;
+	this->height = height;
+	create(width, height);
+
+	// Set to black/transparency.
+	memset(data, 0, width*height*sizeof(pixel));
+}
+
+ImageData::ImageData(int width, int height, void *data)
+{
+	this->width = width;
+	this->height = height;
+	create(width, height, data);
+}
+
+ImageData::~ImageData()
+{
+	delete[] data;
+}
+
+void ImageData::create(int width, int height, void *data)
+{
+	try
+	{
+		this->data = new unsigned char[width*height*sizeof(pixel)];
+	}
+	catch(std::bad_alloc &)
+	{
+		throw love::Exception("Out of memory");
+	}
+
+	if (data)
+		memcpy(this->data, data, width*height*sizeof(pixel));
+}
+
+void ImageData::decode(love::filesystem::FileData *data)
+{
+	FormatHandler::DecodedImage decodedimage;
+
+	if (DevilHandler::canDecode(data))
+		decodedimage = DevilHandler::decode(data);
+	else
+		throw love::Exception("Could not decode image: unrecognized format.");
+
+	// The decoder *must* output a 32 bits-per-pixel image.
+	if (decodedimage.size != decodedimage.width*decodedimage.height*sizeof(pixel))
+	{
+		delete[] decodedimage.data;
+		throw love::Exception("Coult not convert image!");
+	}
+
+	if (this->data)
+		delete[] this->data;
+
+	this->width = decodedimage.width;
+	this->height = decodedimage.height;
+	this->data = decodedimage.data;
+}
+
+void ImageData::encode(love::filesystem::File *f, ImageData::Format format)
+{
+	thread::Lock lock(mutex);
+
+	FormatHandler::DecodedImage rawimage;
+	rawimage.width = width;
+	rawimage.height = height;
+	rawimage.size = width*height*sizeof(pixel);
+	rawimage.data = data;
+
+	FormatHandler::EncodedImage encodedimage;
+
+	try
+	{
+		if (DevilHandler::canEncode(format))
+			encodedimage = DevilHandler::encode(rawimage, format);
+		else
+			throw love::Exception("Image format has no suitable encoder.");
+
+		f->open(love::filesystem::File::WRITE);
+		f->write(encodedimage.data, encodedimage.size);
+		f->close();
+	}
+	catch (love::Exception &)
+	{
+		delete[] encodedimage.data;
+		throw;
+	}
+
+	delete[] encodedimage.data;
+}
+
+} // magpie
+} // image
+} // love

+ 16 - 21
src/modules/image/devil/ImageData.h → src/modules/image/magpie/ImageData.h

@@ -18,49 +18,44 @@
  * 3. This notice may not be removed or altered from any source distribution.
  * 3. This notice may not be removed or altered from any source distribution.
  **/
  **/
 
 
-#ifndef LOVE_DEVIL_IMAGE_DATA_H
-#define LOVE_DEVIL_IMAGE_DATA_H
+#ifndef LOVE_IMAGE_MAGPIE_IMAGE_DATA_H
+#define LOVE_IMAGE_MAGPIE_IMAGE_DATA_H
 
 
 // LOVE
 // LOVE
 #include "filesystem/File.h"
 #include "filesystem/File.h"
 #include "image/ImageData.h"
 #include "image/ImageData.h"
 
 
-// DevIL
-#include <IL/il.h>
-
-
 namespace love
 namespace love
 {
 {
 namespace image
 namespace image
 {
 {
-namespace devil
+namespace magpie
 {
 {
 
 
 class ImageData : public love::image::ImageData
 class ImageData : public love::image::ImageData
 {
 {
-private:
-
-	// Create imagedata. Initialize with data if not null.
-	void create(int width, int height, void *data = 0);
-
-	// Load an encoded format.
-	void load(Data *data);
-
 public:
 public:
 
 
-	ImageData(Data *data);
-	ImageData(love::filesystem::File *file);
+	ImageData(love::filesystem::FileData *data);
 	ImageData(int width, int height);
 	ImageData(int width, int height);
 	ImageData(int width, int height, void *data);
 	ImageData(int width, int height, void *data);
 	virtual ~ImageData();
 	virtual ~ImageData();
 
 
-	// Implements ImageData.
-	void encode(love::filesystem::File *f, Format format);
+	// Implements image::ImageData.
+	virtual void encode(love::filesystem::File *f, ImageData::Format format);
+
+private:
+
+	// Create imagedata. Initialize with data if not null.
+	void create(int width, int height, void *data = 0);
+
+	// Decode and load an encoded format.
+	void decode(love::filesystem::FileData *data);
 
 
 }; // ImageData
 }; // ImageData
 
 
-} // devil
+} // magpie
 } // image
 } // image
 } // love
 } // love
 
 
-#endif // LOVE_DEVIL_IMAGE_DATA_H
+#endif // LOVE_IMAGE_MAGPIE_IMAGE_DATA_H

+ 106 - 0
src/modules/image/magpie/ddsHandler.cpp

@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "ddsHandler.h"
+
+namespace love
+{
+namespace image
+{
+namespace magpie
+{
+
+bool ddsHandler::canParse(const filesystem::FileData *data)
+{
+	if (data->getExtension().compare("dds") != 0)
+		return false;
+
+	return dds::Parser::isCompressedDDS(data->getData(), data->getSize());
+}
+
+CompressedData::TextureType ddsHandler::parse(filesystem::FileData *data, std::vector<CompressedData::SubImage> &images)
+{
+	if (!dds::Parser::isDDS(data->getData(), data->getSize()))
+		throw love::Exception("Could not decode compressed data (not a DDS file?)");
+
+	CompressedData::TextureType textype = CompressedData::TYPE_UNKNOWN;
+
+	try
+	{
+		dds::Parser parser(data->getData(), data->getSize());
+
+		textype = convertFormat(parser.getFormat());
+
+		if (textype == CompressedData::TYPE_UNKNOWN)
+			throw love::Exception("Could not parse compressed data: Unsupported format.");
+
+		if (parser.getNumMipmaps() == 0)
+			throw love::Exception("Could not parse compressed data: No readable texture data.");
+
+		for (size_t i = 0; i < parser.getNumMipmaps(); i++)
+		{
+			const dds::Parser::Image *img = parser.getImageData(i);
+
+			CompressedData::SubImage mip;
+
+			mip.width = img->width;
+			mip.height = img->height;
+			mip.size = img->dataSize;
+			mip.data.insert(mip.data.begin(), &img->data[0], &img->data[mip.size]);
+
+			images.push_back(mip);
+		}
+	}
+	catch (std::exception &e)
+	{
+		throw love::Exception(e.what());
+	}
+
+	return textype;
+}
+
+CompressedData::TextureType ddsHandler::convertFormat(dds::Format ddsformat)
+{
+	switch (ddsformat)
+	{
+	case dds::FORMAT_DXT1:
+		return CompressedData::TYPE_DXT1;
+	case dds::FORMAT_DXT3:
+		return CompressedData::TYPE_DXT3;
+	case dds::FORMAT_DXT5:
+		return CompressedData::TYPE_DXT5;
+	case dds::FORMAT_BC5:
+		return CompressedData::TYPE_BC5;
+	case dds::FORMAT_BC5s:
+		return CompressedData::TYPE_BC5s;
+	case dds::FORMAT_BC7:
+		return CompressedData::TYPE_BC7;
+	case dds::FORMAT_BC7srgb:
+		return CompressedData::TYPE_BC7srgb;
+	default:
+		return CompressedData::TYPE_UNKNOWN;
+	}
+
+	return CompressedData::TYPE_UNKNOWN;
+}
+
+} // magpie
+} // image
+} // love

+ 74 - 0
src/modules/image/magpie/ddsHandler.h

@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_IMAGE_MAGPIE_DDS_HANDLER_H
+#define LOVE_IMAGE_MAGPIE_DDS_HANDLER_H
+
+// LOVE
+#include "filesystem/FileData.h"
+#include "image/CompressedData.h"
+
+// dds parser
+#include "ddsparse/ddsparse.h"
+
+// STL
+#include <string>
+
+namespace love
+{
+namespace image
+{
+namespace magpie
+{
+
+/**
+ * Interface between CompressedData and the ddsparse library.
+ **/
+class ddsHandler
+{
+public:
+
+	/**
+	 * Determines whether a particular FileData can be parsed as CompressedData
+	 * by this handler.
+	 * @param data The data to parse.
+	 **/
+	static bool canParse(const filesystem::FileData *data);
+
+	/**
+	 * Parses Compressed image data into a list of sub-images.
+	 * @param[in]  data The data to parse.
+	 * @param[out] images The list of sub-images (including byte data for each)
+	 *             parsed from the file data.
+	 * @return The type of CompressedData.
+	 **/
+	static CompressedData::TextureType parse(filesystem::FileData *data, std::vector<CompressedData::SubImage> &images);
+
+private:
+
+	static CompressedData::TextureType convertFormat(dds::Format ddsformat);
+
+}; // ddsHandler
+
+} // magpie
+} // image
+} // love
+
+#endif // LOVE_IMAGE_MAGPIE_DDS_HANDLER_H

+ 129 - 0
src/modules/image/wrap_CompressedData.cpp

@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "wrap_CompressedData.h"
+#include "common/wrap_Data.h"
+
+namespace love
+{
+namespace image
+{
+
+CompressedData *luax_checkcompresseddata(lua_State *L, int idx)
+{
+	return luax_checktype<CompressedData>(L, idx, "CompressedData", IMAGE_COMPRESSED_DATA_T);
+}
+
+int w_CompressedData_getWidth(lua_State *L)
+{
+	CompressedData *t = luax_checkcompresseddata(L, 1);
+	int miplevel = luaL_optinteger(L, 2, 1);
+	int width = 0;
+	try
+	{
+		width = t->getWidth(miplevel >= 1 ? miplevel - 1 : 0);
+	}
+	catch (love::Exception &e)
+	{
+		return luaL_error(L, "%s", e.what());
+	}
+	lua_pushinteger(L, width);
+	return 1;
+}
+
+int w_CompressedData_getHeight(lua_State *L)
+{
+	CompressedData *t = luax_checkcompresseddata(L, 1);
+	int miplevel = luaL_optinteger(L, 2, 1);
+	int height = 0;
+	try
+	{
+		height = t->getHeight(miplevel >= 1 ? miplevel - 1 : 0);
+	}
+	catch (love::Exception &e)
+	{
+		return luaL_error(L, "%s", e.what());
+	}
+	lua_pushinteger(L, height);
+	return 1;
+}
+
+int w_CompressedData_getDimensions(lua_State *L)
+{
+	CompressedData *t = luax_checkcompresseddata(L, 1);
+	int miplevel = luaL_optinteger(L, 2, 1);
+	int width = 0, height = 0;
+	try
+	{
+		width = t->getWidth(miplevel >= 1 ? miplevel - 1 : 0);
+		height = t->getHeight(miplevel >= 1 ? miplevel - 1 : 0);
+	}
+	catch (love::Exception &e)
+	{
+		return luaL_error(L, "%s", e.what());
+	}
+	lua_pushinteger(L, width);
+	lua_pushinteger(L, height);
+	return 2;
+}
+
+int w_CompressedData_getNumMipmaps(lua_State *L)
+{
+	CompressedData *t = luax_checkcompresseddata(L, 1);
+	lua_pushinteger(L, t->getNumMipmaps());
+	return 1;
+}
+
+int w_CompressedData_getType(lua_State *L)
+{
+	CompressedData *t = luax_checkcompresseddata(L, 1);
+
+	image::CompressedData::TextureType type = t->getType();
+	const char *str;
+
+	if (image::CompressedData::getConstant(type, str))
+		lua_pushstring(L, str);
+	else
+		lua_pushstring(L, "unknown");
+
+	return 1;
+}
+
+static const luaL_Reg functions[] =
+{
+	// Data
+//	{ "getPointer", w_Data_getPointer },
+	{ "getSize", w_Data_getSize },
+
+	{ "getWidth", w_CompressedData_getWidth },
+	{ "getHeight", w_CompressedData_getHeight },
+	{ "getDimensions", w_CompressedData_getDimensions },
+	{ "getNumMipmaps", w_CompressedData_getNumMipmaps },
+	{ "getType", w_CompressedData_getType },
+	{ 0, 0 },
+};
+
+extern "C" int luaopen_compresseddata(lua_State *L)
+{
+	return luax_register_type(L, "CompressedData", functions);
+}
+
+} // image
+} // love

+ 44 - 0
src/modules/image/wrap_CompressedData.h

@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_IMAGE_WRAP_COMRESSED_DATA_H
+#define LOVE_IMAGE_WRAP_COMRESSED_DATA_H
+
+// LOVE
+#include "common/runtime.h"
+#include "CompressedData.h"
+
+namespace love
+{
+namespace image
+{
+
+CompressedData *luax_checkcompresseddata(lua_State *L, int idx);
+int w_CompressedData_getWidth(lua_State *L);
+int w_CompressedData_getHeight(lua_State *L);
+int w_CompressedData_getDimensions(lua_State *L);
+int w_CompressedData_getNumMipmaps(lua_State *L);
+int w_CompressedData_getType(lua_State *L);
+extern "C" int luaopen_compresseddata(lua_State *L);
+
+} // image
+} // love
+
+#endif // LOVE_IMAGE_WRAP_COMRESSED_DATA_H

+ 56 - 24
src/modules/image/wrap_Image.cpp

@@ -23,7 +23,7 @@
 #include "common/Data.h"
 #include "common/Data.h"
 #include "common/StringMap.h"
 #include "common/StringMap.h"
 
 
-#include "devil/Image.h"
+#include "magpie/Image.h"
 
 
 namespace love
 namespace love
 {
 {
@@ -55,41 +55,70 @@ int w_newImageData(lua_State *L)
 		return 1;
 		return 1;
 	}
 	}
 
 
-	// Case 2: Data
-	if (luax_istype(L, 1, DATA_T))
+	// Case 2: File(Data).
+
+	// Convert to FileData, if necessary.
+	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
+		luax_convobj(L, 1, "filesystem", "newFileData");
+
+	love::filesystem::FileData *data = luax_checktype<love::filesystem::FileData>(L, 1, "FileData", FILESYSTEM_FILE_DATA_T);
+
+	ImageData *t = 0;
+	try
 	{
 	{
-		Data *d = luax_checktype<Data>(L, 1, "Data", DATA_T);
-		ImageData *t = 0;
-		try
-		{
-			t = instance->newImageData(d);
-		}
-		catch(love::Exception &e)
-		{
-			return luaL_error(L, "%s", e.what());
-		}
-		luax_newtype(L, "ImageData", IMAGE_IMAGE_DATA_T, (void *)t);
-		return 1;
+		t = instance->newImageData(data);
+	}
+	catch (love::Exception &e)
+	{
+		return luaL_error(L, "%s", e.what());
 	}
 	}
 
 
-	// Case 3: String/File.
+	luax_newtype(L, "ImageData", IMAGE_IMAGE_DATA_T, (void *) t);
 
 
-	// Convert to File, if necessary.
-	if (lua_isstring(L, 1))
-		luax_convobj(L, 1, "filesystem", "newFile");
+	return 1;
+}
 
 
-	love::filesystem::File *file = luax_checktype<love::filesystem::File>(L, 1, "File", FILESYSTEM_FILE_T);
+int w_newCompressedData(lua_State *L)
+{
+	// Convert to FileData, if necessary.
+	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
+		luax_convobj(L, 1, "filesystem", "newFileData");
 
 
-	ImageData *t = 0;
+	love::filesystem::FileData *data = luax_checktype<love::filesystem::FileData>(L, 1, "FileData", FILESYSTEM_FILE_DATA_T);
+
+	CompressedData *t = 0;
 	try
 	try
 	{
 	{
-		t = instance->newImageData(file);
+		t = instance->newCompressedData(data);
 	}
 	}
 	catch(love::Exception &e)
 	catch(love::Exception &e)
 	{
 	{
 		return luaL_error(L, "%s", e.what());
 		return luaL_error(L, "%s", e.what());
 	}
 	}
-	luax_newtype(L, "ImageData", IMAGE_IMAGE_DATA_T, (void *)t);
+
+	luax_newtype(L, "CompressedData", IMAGE_COMPRESSED_DATA_T, (void *) t);
+
+	return 1;
+}
+
+int w_isCompressed(lua_State *L)
+{
+	// Convert to FileData, if necessary.
+	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
+		luax_convobj(L, 1, "filesystem", "newFileData");
+
+	love::filesystem::FileData *data = luax_checktype<love::filesystem::FileData>(L, 1, "FileData", FILESYSTEM_FILE_DATA_T);
+
+	bool compressed = false;
+	try
+	{
+		compressed = instance->isCompressed(data);
+	}
+	catch (love::Exception &e)
+	{
+		return luaL_error(L, "%s", e.what());
+	}
+	luax_pushboolean(L, compressed);
 	return 1;
 	return 1;
 }
 }
 
 
@@ -97,12 +126,15 @@ int w_newImageData(lua_State *L)
 static const luaL_Reg functions[] =
 static const luaL_Reg functions[] =
 {
 {
 	{ "newImageData",  w_newImageData },
 	{ "newImageData",  w_newImageData },
+	{ "newCompressedData", w_newCompressedData },
+	{ "isCompressed", w_isCompressed },
 	{ 0, 0 }
 	{ 0, 0 }
 };
 };
 
 
 static const lua_CFunction types[] =
 static const lua_CFunction types[] =
 {
 {
 	luaopen_imagedata,
 	luaopen_imagedata,
+	luaopen_compresseddata,
 	0
 	0
 };
 };
 
 
@@ -112,7 +144,7 @@ extern "C" int luaopen_love_image(lua_State *L)
 	{
 	{
 		try
 		try
 		{
 		{
-			instance = new love::image::devil::Image();
+			instance = new love::image::magpie::Image();
 		}
 		}
 		catch(Exception &e)
 		catch(Exception &e)
 		{
 		{

+ 3 - 1
src/modules/image/wrap_Image.h

@@ -24,14 +24,16 @@
 // LOVE
 // LOVE
 #include "Image.h"
 #include "Image.h"
 #include "wrap_ImageData.h"
 #include "wrap_ImageData.h"
+#include "wrap_CompressedData.h"
 
 
 namespace love
 namespace love
 {
 {
 namespace image
 namespace image
 {
 {
 
 
-int w_getFormats(lua_State *L);
 int w_newImageData(lua_State *L);
 int w_newImageData(lua_State *L);
+int w_newCompressedData(lua_State *L);
+int w_isCompressed(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_image(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_image(lua_State *L);
 
 
 } // image
 } // image

+ 1 - 1
src/modules/image/wrap_ImageData.cpp

@@ -191,7 +191,7 @@ int w_ImageData_encode(lua_State *L)
 static const luaL_Reg functions[] =
 static const luaL_Reg functions[] =
 {
 {
 	// Data
 	// Data
-	{ "getPointer", w_Data_getPointer },
+//	{ "getPointer", w_Data_getPointer },
 	{ "getSize", w_Data_getSize },
 	{ "getSize", w_Data_getSize },
 
 
 	{ "getWidth", w_ImageData_getWidth },
 	{ "getWidth", w_ImageData_getWidth },

+ 1 - 1
src/modules/sound/wrap_SoundData.cpp

@@ -88,7 +88,7 @@ static const luaL_Reg functions[] =
 {
 {
 
 
 	// Data
 	// Data
-	{ "getPointer", w_Data_getPointer },
+//	{ "getPointer", w_Data_getPointer },
 	{ "getSize", w_Data_getSize },
 	{ "getSize", w_Data_getSize },
 
 
 	{ "getChannels", w_SoundData_getChannels },
 	{ "getChannels", w_SoundData_getChannels },