Parcourir la source

Add basic graphics components.

Sam Jaffe il y a 6 ans
Parent
commit
83ba529a71

+ 306 - 0
graphics/graphics.xcodeproj/project.pbxproj

@@ -0,0 +1,306 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		CD3AC6F21D2C03B7002B4BB0 /* material.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3AC6F01D2C03B7002B4BB0 /* material.cpp */; };
+		CD3AC6F31D2C03B7002B4BB0 /* material.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CD3AC6F11D2C03B7002B4BB0 /* material.hpp */; };
+		CD3AC6F51D2C04DC002B4BB0 /* libmath.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CD3AC6F41D2C04DC002B4BB0 /* libmath.dylib */; };
+		CD3AC6F81D2C0518002B4BB0 /* texture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3AC6F61D2C0518002B4BB0 /* texture.cpp */; };
+		CD3AC6F91D2C0518002B4BB0 /* texture.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CD3AC6F71D2C0518002B4BB0 /* texture.hpp */; };
+		CD3AC6FD1D2C06B5002B4BB0 /* shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3AC6FB1D2C06B5002B4BB0 /* shader.cpp */; };
+		CD3AC6FE1D2C06B5002B4BB0 /* shader.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CD3AC6FC1D2C06B5002B4BB0 /* shader.hpp */; };
+		CD3AC7191D2C0950002B4BB0 /* shader_program.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3AC7171D2C0950002B4BB0 /* shader_program.cpp */; };
+		CD3AC71A1D2C0950002B4BB0 /* shader_program.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CD3AC7181D2C0950002B4BB0 /* shader_program.hpp */; };
+		CD3AC7261D2C0C63002B4BB0 /* object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3AC7241D2C0C63002B4BB0 /* object.cpp */; };
+		CD3AC7271D2C0C63002B4BB0 /* object.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CD3AC7251D2C0C63002B4BB0 /* object.hpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		CD3AC6E21D2C0364002B4BB0 /* libgraphics.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libgraphics.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+		CD3AC6F01D2C03B7002B4BB0 /* material.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = material.cpp; sourceTree = "<group>"; };
+		CD3AC6F11D2C03B7002B4BB0 /* material.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = material.hpp; sourceTree = "<group>"; };
+		CD3AC6F41D2C04DC002B4BB0 /* libmath.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libmath.dylib; path = "../../../../../Library/Developer/Xcode/DerivedData/game-fzozuoevjsbueyhaskmxixpdawcn/Build/Products/Debug/libmath.dylib"; sourceTree = "<group>"; };
+		CD3AC6F61D2C0518002B4BB0 /* texture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = texture.cpp; sourceTree = "<group>"; };
+		CD3AC6F71D2C0518002B4BB0 /* texture.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = texture.hpp; sourceTree = "<group>"; };
+		CD3AC6FB1D2C06B5002B4BB0 /* shader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shader.cpp; sourceTree = "<group>"; };
+		CD3AC6FC1D2C06B5002B4BB0 /* shader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = shader.hpp; sourceTree = "<group>"; };
+		CD3AC7171D2C0950002B4BB0 /* shader_program.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shader_program.cpp; sourceTree = "<group>"; };
+		CD3AC7181D2C0950002B4BB0 /* shader_program.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = shader_program.hpp; sourceTree = "<group>"; };
+		CD3AC7241D2C0C63002B4BB0 /* object.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = object.cpp; sourceTree = "<group>"; };
+		CD3AC7251D2C0C63002B4BB0 /* object.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = object.hpp; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		CD3AC6DF1D2C0364002B4BB0 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CD3AC6F51D2C04DC002B4BB0 /* libmath.dylib in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		CD3AC6D91D2C0364002B4BB0 = {
+			isa = PBXGroup;
+			children = (
+				CD3AC6F41D2C04DC002B4BB0 /* libmath.dylib */,
+				CD3AC6E41D2C0364002B4BB0 /* src */,
+				CD3AC6E31D2C0364002B4BB0 /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		CD3AC6E31D2C0364002B4BB0 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				CD3AC6E21D2C0364002B4BB0 /* libgraphics.dylib */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		CD3AC6E41D2C0364002B4BB0 /* src */ = {
+			isa = PBXGroup;
+			children = (
+				CD3AC71B1D2C0955002B4BB0 /* datamodel */,
+			);
+			name = src;
+			path = graphics;
+			sourceTree = "<group>";
+		};
+		CD3AC71B1D2C0955002B4BB0 /* datamodel */ = {
+			isa = PBXGroup;
+			children = (
+				CD3AC6F01D2C03B7002B4BB0 /* material.cpp */,
+				CD3AC6F11D2C03B7002B4BB0 /* material.hpp */,
+				CD3AC6FB1D2C06B5002B4BB0 /* shader.cpp */,
+				CD3AC6FC1D2C06B5002B4BB0 /* shader.hpp */,
+				CD3AC7171D2C0950002B4BB0 /* shader_program.cpp */,
+				CD3AC7181D2C0950002B4BB0 /* shader_program.hpp */,
+				CD3AC6F61D2C0518002B4BB0 /* texture.cpp */,
+				CD3AC6F71D2C0518002B4BB0 /* texture.hpp */,
+				CD3AC7241D2C0C63002B4BB0 /* object.cpp */,
+				CD3AC7251D2C0C63002B4BB0 /* object.hpp */,
+			);
+			name = datamodel;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		CD3AC6E01D2C0364002B4BB0 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CD3AC6F91D2C0518002B4BB0 /* texture.hpp in Headers */,
+				CD3AC6FE1D2C06B5002B4BB0 /* shader.hpp in Headers */,
+				CD3AC71A1D2C0950002B4BB0 /* shader_program.hpp in Headers */,
+				CD3AC6F31D2C03B7002B4BB0 /* material.hpp in Headers */,
+				CD3AC7271D2C0C63002B4BB0 /* object.hpp in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+		CD3AC6E11D2C0364002B4BB0 /* graphics */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = CD3AC6ED1D2C0364002B4BB0 /* Build configuration list for PBXNativeTarget "graphics" */;
+			buildPhases = (
+				CD3AC6DE1D2C0364002B4BB0 /* Sources */,
+				CD3AC6DF1D2C0364002B4BB0 /* Frameworks */,
+				CD3AC6E01D2C0364002B4BB0 /* Headers */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = graphics;
+			productName = graphics;
+			productReference = CD3AC6E21D2C0364002B4BB0 /* libgraphics.dylib */;
+			productType = "com.apple.product-type.library.dynamic";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		CD3AC6DA1D2C0364002B4BB0 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0720;
+				ORGANIZATIONNAME = "Sam Jaffe";
+				TargetAttributes = {
+					CD3AC6E11D2C0364002B4BB0 = {
+						CreatedOnToolsVersion = 7.2.1;
+					};
+				};
+			};
+			buildConfigurationList = CD3AC6DD1D2C0364002B4BB0 /* Build configuration list for PBXProject "graphics" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = CD3AC6D91D2C0364002B4BB0;
+			productRefGroup = CD3AC6E31D2C0364002B4BB0 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				CD3AC6E11D2C0364002B4BB0 /* graphics */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		CD3AC6DE1D2C0364002B4BB0 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CD3AC6FD1D2C06B5002B4BB0 /* shader.cpp in Sources */,
+				CD3AC7191D2C0950002B4BB0 /* shader_program.cpp in Sources */,
+				CD3AC6F21D2C03B7002B4BB0 /* material.cpp in Sources */,
+				CD3AC6F81D2C0518002B4BB0 /* texture.cpp in Sources */,
+				CD3AC7261D2C0C63002B4BB0 /* object.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		CD3AC6EB1D2C0364002B4BB0 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "-";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		CD3AC6EC1D2C0364002B4BB0 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "-";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		CD3AC6EE1D2C0364002B4BB0 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				EXECUTABLE_PREFIX = lib;
+				GCC_ENABLE_CPP_EXCEPTIONS = YES;
+				GCC_ENABLE_CPP_RTTI = YES;
+				GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = ".. ../include";
+			};
+			name = Debug;
+		};
+		CD3AC6EF1D2C0364002B4BB0 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DYLIB_COMPATIBILITY_VERSION = 1;
+				DYLIB_CURRENT_VERSION = 1;
+				EXECUTABLE_PREFIX = lib;
+				GCC_ENABLE_CPP_EXCEPTIONS = YES;
+				GCC_ENABLE_CPP_RTTI = YES;
+				GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = ".. ../include";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		CD3AC6DD1D2C0364002B4BB0 /* Build configuration list for PBXProject "graphics" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				CD3AC6EB1D2C0364002B4BB0 /* Debug */,
+				CD3AC6EC1D2C0364002B4BB0 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		CD3AC6ED1D2C0364002B4BB0 /* Build configuration list for PBXNativeTarget "graphics" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				CD3AC6EE1D2C0364002B4BB0 /* Debug */,
+				CD3AC6EF1D2C0364002B4BB0 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = CD3AC6DA1D2C0364002B4BB0 /* Project object */;
+}

+ 8 - 0
graphics/graphics/material.cpp

@@ -0,0 +1,8 @@
+//
+//  material.cpp
+//  graphics
+//
+//  Created by Sam Jaffe on 7/5/16.
+//
+
+#include "material.hpp"

+ 21 - 0
graphics/graphics/material.hpp

@@ -0,0 +1,21 @@
+//
+//  material.hpp
+//  graphics
+//
+//  Created by Sam Jaffe on 7/5/16.
+//
+
+#pragma once
+
+#include "graphics/shader_program.hpp"
+
+#include "util/identity.hpp"
+
+namespace graphics {
+  class material : public identity<material> {
+  public:
+    program const shaders;
+  private:
+    material(unsigned int, program);
+  };
+}

+ 8 - 0
graphics/graphics/object.cpp

@@ -0,0 +1,8 @@
+//
+//  object.cpp
+//  graphics
+//
+//  Created by Sam Jaffe on 7/5/16.
+//
+
+#include "object.hpp"

+ 28 - 0
graphics/graphics/object.hpp

@@ -0,0 +1,28 @@
+//
+//  object.hpp
+//  graphics
+//
+//  Created by Sam Jaffe on 7/5/16.
+//
+
+#pragma once
+
+#include "math/vector/vector.hpp"
+#include "math/math_fwd.hpp"
+#include "math/shape.hpp"
+
+#include "graphics/material.hpp"
+
+namespace graphics {
+  struct bound {
+    math::vec2 corner;
+    math::vec2 size;
+  };
+  
+  struct object {
+    bound location;
+    math::quad points;
+    material material;
+    bound frame;
+  }; // size:56, align:4
+}

+ 8 - 0
graphics/graphics/shader.cpp

@@ -0,0 +1,8 @@
+//
+//  shader.cpp
+//  graphics
+//
+//  Created by Sam Jaffe on 7/5/16.
+//
+
+#include "shader.hpp"

+ 18 - 0
graphics/graphics/shader.hpp

@@ -0,0 +1,18 @@
+//
+//  shader.hpp
+//  graphics
+//
+//  Created by Sam Jaffe on 7/5/16.
+//
+
+#pragma once
+
+#include "util/identity.hpp"
+
+namespace graphics {
+  class shader : public identity<shader> {
+  public:
+  private:
+    shader(unsigned int);
+  };
+}

+ 8 - 0
graphics/graphics/shader_program.cpp

@@ -0,0 +1,8 @@
+//
+//  shader_program.cpp
+//  graphics
+//
+//  Created by Sam Jaffe on 7/5/16.
+//
+
+#include "shader_program.hpp"

+ 18 - 0
graphics/graphics/shader_program.hpp

@@ -0,0 +1,18 @@
+//
+//  shader_program.hpp
+//  graphics
+//
+//  Created by Sam Jaffe on 7/5/16.
+//
+
+#pragma once
+
+#include "util/identity.hpp"
+
+namespace graphics {
+  class program : public identity<program> {
+  public:
+  private:
+    program(unsigned int);
+  };
+}

+ 71 - 0
graphics/graphics/texture.cpp

@@ -0,0 +1,71 @@
+//
+//  texture.cpp
+//  graphics
+//
+//  Created by Sam Jaffe on 7/5/16.
+//
+
+#include "texture.hpp"
+
+#include "util/scope_exit.hpp"
+
+#include <unordered_map>
+#include <string>
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "include/stb/stb_image.h"
+
+unsigned char * stbi_load( char const *, int *, int *, int *, int );
+void stbi_image_free( void * );
+
+template <typename T, typename Key = std::string>
+class private_factory {
+public:
+  using key_t = Key;
+  
+  template <typename... Args>
+  static T create(key_t const & key) {
+    auto found = instances.find(key);
+    if (found != instances.end()) { return found->second; }
+    else {
+      return instances.emplace(key, T::create(key)).first->second;
+    }
+  }
+private:
+  static std::unordered_map<key_t, T> instances;
+};
+
+namespace graphics {
+  
+  namespace detail {
+    namespace texture {
+      
+      struct format {};
+      
+      std::unordered_map<std::string, ::graphics::texture> g_textures;
+    
+      unsigned int init(format = {}, math::vec2i = {}, unsigned char * = {});
+    }
+  }
+  
+  texture texture::create( std::string const & imagefile ) {
+    using detail::texture::g_textures;
+    auto found = g_textures.find(imagefile);
+    if (found != g_textures.end()) { return found->second; }
+    
+    int components = 0;
+    math::vec2i size;
+    unsigned char * data = stbi_load( imagefile.c_str(), &size.x(), &size.y(), &components, 0 );
+    scope(exit) { stbi_image_free( data ); };
+    return g_textures.emplace(imagefile, texture{ detail::texture::init({}, size, data), size }).first->second;
+  }
+  
+  texture texture::create( unsigned char * data, math::vec2i size ) {
+    return { detail::texture::init({}, size, data), size };
+  }
+  
+  texture::texture( unsigned int id, math::vec2i sz ) : identity<graphics::texture>(id), size(sz) {
+    
+  }
+  
+}

+ 28 - 0
graphics/graphics/texture.hpp

@@ -0,0 +1,28 @@
+//
+//  texture.hpp
+//  graphics
+//
+//  Created by Sam Jaffe on 7/5/16.
+//
+
+#pragma once
+
+#include "math/vector/vector.hpp"
+#include "math/math_fwd.hpp"
+#include "util/identity.hpp"
+
+namespace graphics {
+  class texture : public identity<texture> {
+  public:
+    static texture create(std::string const & imagefile);
+    
+    static texture const WHITE;
+    static texture const DARK_YELLOW;
+    static texture const LIGHT_BLUE;
+    
+    math::vec2i const size;
+  private:
+    static texture create( unsigned char *, math::vec2i );
+    texture( unsigned int, math::vec2i = math::vec2i{{0, 0}} );
+  };
+}