commit 13d8e6e56359016de986fd65eca84c0bd56eb8ad Author: Omar Mohamed Ali Mudhir Date: Sat Jan 14 18:30:19 2017 +0000 base setup for osx in place diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fdbb84d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +xcuserdata +libs + diff --git a/data/image.png b/data/image.png new file mode 100644 index 0000000..646e361 Binary files /dev/null and b/data/image.png differ diff --git a/engine.xcodeproj/project.pbxproj b/engine.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a344240 --- /dev/null +++ b/engine.xcodeproj/project.pbxproj @@ -0,0 +1,307 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + AD58E0531E107411006ACC15 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD58E0521E107411006ACC15 /* main.cpp */; }; + AD58E05A1E10752E006ACC15 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD58E0591E10752E006ACC15 /* OpenGL.framework */; }; + AD58E05C1E107536006ACC15 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD58E05B1E107536006ACC15 /* Cocoa.framework */; }; + AD58E05E1E10754F006ACC15 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD58E05D1E10754F006ACC15 /* CoreFoundation.framework */; }; + AD58E0601E12DA86006ACC15 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD58E05F1E12DA86006ACC15 /* CoreVideo.framework */; }; + AD58E0621E17F249006ACC15 /* data in CopyFiles */ = {isa = PBXBuildFile; fileRef = AD58E0611E17F23D006ACC15 /* data */; }; + AD58E0651E2A76FD006ACC15 /* shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD58E0631E2A76FD006ACC15 /* shader.cpp */; }; + AD58E0681E2A7741006ACC15 /* image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD58E0661E2A7741006ACC15 /* image.cpp */; }; + AD58E06B1E2A774F006ACC15 /* texture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD58E0691E2A774F006ACC15 /* texture.cpp */; }; + AD58E06F1E2A80BC006ACC15 /* shape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD58E06D1E2A80BC006ACC15 /* shape.cpp */; }; + AD58E0721E2A90EF006ACC15 /* app.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD58E0701E2A90EF006ACC15 /* app.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + AD58E04D1E107411006ACC15 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 12; + dstPath = ""; + dstSubfolderSpec = 7; + files = ( + AD58E0621E17F249006ACC15 /* data in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + AD58E04F1E107411006ACC15 /* engine */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = engine; sourceTree = BUILT_PRODUCTS_DIR; }; + AD58E0521E107411006ACC15 /* main.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = main.cpp; sourceTree = ""; }; + AD58E0591E10752E006ACC15 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + AD58E05B1E107536006ACC15 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + AD58E05D1E10754F006ACC15 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + AD58E05F1E12DA86006ACC15 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; + AD58E0611E17F23D006ACC15 /* data */ = {isa = PBXFileReference; lastKnownFileType = folder; path = data; sourceTree = ""; }; + AD58E0631E2A76FD006ACC15 /* shader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shader.cpp; sourceTree = ""; }; + AD58E0641E2A76FD006ACC15 /* shader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = shader.hpp; sourceTree = ""; }; + AD58E0661E2A7741006ACC15 /* image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = image.cpp; sourceTree = ""; }; + AD58E0671E2A7741006ACC15 /* image.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = image.hpp; sourceTree = ""; }; + AD58E0691E2A774F006ACC15 /* texture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = texture.cpp; sourceTree = ""; }; + AD58E06A1E2A774F006ACC15 /* texture.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = texture.hpp; sourceTree = ""; }; + AD58E06C1E2A78BD006ACC15 /* pch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pch.h; sourceTree = ""; }; + AD58E06D1E2A80BC006ACC15 /* shape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shape.cpp; sourceTree = ""; }; + AD58E06E1E2A80BC006ACC15 /* shape.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = shape.hpp; sourceTree = ""; }; + AD58E0701E2A90EF006ACC15 /* app.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = app.cpp; sourceTree = ""; }; + AD58E0711E2A90EF006ACC15 /* app.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = app.hpp; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + AD58E04C1E107411006ACC15 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AD58E0601E12DA86006ACC15 /* CoreVideo.framework in Frameworks */, + AD58E05E1E10754F006ACC15 /* CoreFoundation.framework in Frameworks */, + AD58E05C1E107536006ACC15 /* Cocoa.framework in Frameworks */, + AD58E05A1E10752E006ACC15 /* OpenGL.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + AD58E0461E107411006ACC15 = { + isa = PBXGroup; + children = ( + AD58E0611E17F23D006ACC15 /* data */, + AD58E05F1E12DA86006ACC15 /* CoreVideo.framework */, + AD58E05D1E10754F006ACC15 /* CoreFoundation.framework */, + AD58E05B1E107536006ACC15 /* Cocoa.framework */, + AD58E0591E10752E006ACC15 /* OpenGL.framework */, + AD58E0511E107411006ACC15 /* engine */, + AD58E0501E107411006ACC15 /* Products */, + ); + sourceTree = ""; + }; + AD58E0501E107411006ACC15 /* Products */ = { + isa = PBXGroup; + children = ( + AD58E04F1E107411006ACC15 /* engine */, + ); + name = Products; + sourceTree = ""; + }; + AD58E0511E107411006ACC15 /* engine */ = { + isa = PBXGroup; + children = ( + AD58E0631E2A76FD006ACC15 /* shader.cpp */, + AD58E0641E2A76FD006ACC15 /* shader.hpp */, + AD58E0521E107411006ACC15 /* main.cpp */, + AD58E06D1E2A80BC006ACC15 /* shape.cpp */, + AD58E0701E2A90EF006ACC15 /* app.cpp */, + AD58E0711E2A90EF006ACC15 /* app.hpp */, + AD58E06E1E2A80BC006ACC15 /* shape.hpp */, + AD58E0661E2A7741006ACC15 /* image.cpp */, + AD58E0671E2A7741006ACC15 /* image.hpp */, + AD58E0691E2A774F006ACC15 /* texture.cpp */, + AD58E06A1E2A774F006ACC15 /* texture.hpp */, + AD58E06C1E2A78BD006ACC15 /* pch.h */, + ); + path = engine; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + AD58E04E1E107411006ACC15 /* engine */ = { + isa = PBXNativeTarget; + buildConfigurationList = AD58E0561E107411006ACC15 /* Build configuration list for PBXNativeTarget "engine" */; + buildPhases = ( + AD58E04B1E107411006ACC15 /* Sources */, + AD58E04C1E107411006ACC15 /* Frameworks */, + AD58E04D1E107411006ACC15 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = engine; + productName = engine; + productReference = AD58E04F1E107411006ACC15 /* engine */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + AD58E0471E107411006ACC15 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = "Omar Mohamed Ali Mudhir"; + TargetAttributes = { + AD58E04E1E107411006ACC15 = { + CreatedOnToolsVersion = 7.2; + }; + }; + }; + buildConfigurationList = AD58E04A1E107411006ACC15 /* Build configuration list for PBXProject "engine" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = AD58E0461E107411006ACC15; + productRefGroup = AD58E0501E107411006ACC15 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + AD58E04E1E107411006ACC15 /* engine */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + AD58E04B1E107411006ACC15 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AD58E06F1E2A80BC006ACC15 /* shape.cpp in Sources */, + AD58E0651E2A76FD006ACC15 /* shader.cpp in Sources */, + AD58E06B1E2A774F006ACC15 /* texture.cpp in Sources */, + AD58E0721E2A90EF006ACC15 /* app.cpp in Sources */, + AD58E0531E107411006ACC15 /* main.cpp in Sources */, + AD58E0681E2A7741006ACC15 /* image.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + AD58E0541E107411006ACC15 /* 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_PRECOMPILE_PREFIX_HEADER = YES; + 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; + HEADER_SEARCH_PATHS = ( + /opt/local/include, + libs, + ); + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + AD58E0551E107411006ACC15 /* 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_PRECOMPILE_PREFIX_HEADER = 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; + HEADER_SEARCH_PATHS = ( + /opt/local/include, + libs, + ); + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + AD58E0571E107411006ACC15 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + AD58E0581E107411006ACC15 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + AD58E04A1E107411006ACC15 /* Build configuration list for PBXProject "engine" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AD58E0541E107411006ACC15 /* Debug */, + AD58E0551E107411006ACC15 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + AD58E0561E107411006ACC15 /* Build configuration list for PBXNativeTarget "engine" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AD58E0571E107411006ACC15 /* Debug */, + AD58E0581E107411006ACC15 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = AD58E0471E107411006ACC15 /* Project object */; +} diff --git a/engine.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/engine.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..2c9d68e --- /dev/null +++ b/engine.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/engine.xcodeproj/xcuserdata/omimac.xcuserdatad/xcschemes/engine.xcscheme b/engine.xcodeproj/xcuserdata/omimac.xcuserdatad/xcschemes/engine.xcscheme new file mode 100644 index 0000000..48a3201 --- /dev/null +++ b/engine.xcodeproj/xcuserdata/omimac.xcuserdatad/xcschemes/engine.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine.xcodeproj/xcuserdata/omimac.xcuserdatad/xcschemes/xcschememanagement.plist b/engine.xcodeproj/xcuserdata/omimac.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..d4e76f9 --- /dev/null +++ b/engine.xcodeproj/xcuserdata/omimac.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + engine.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + AD58E04E1E107411006ACC15 + + primary + + + + + diff --git a/engine/app.cpp b/engine/app.cpp new file mode 100644 index 0000000..a39d7df --- /dev/null +++ b/engine/app.cpp @@ -0,0 +1,102 @@ +#include "pch.h" +#include "app.hpp" + +App App::I; // singleton + +void App::create() +{ + width = 800; + height = 600; +} + +void App::init() +{ + static const char* shader_v = + "#version 150\n" + "uniform mat4 mvp;" + "in vec4 pos;" + "in vec2 uvs;" + "out vec2 uv;" + "void main(){" + " gl_Position = mvp * pos;" + " uv = uvs;" + "}"; + static const char* shader_f = + "#version 150\n" + "uniform sampler2D tex;" + "in vec2 uv;" + "out vec4 frag;" + "void main(){" + " frag = texture(tex, uv, 0.0);" + "}"; + static const char* shader_color_v = + "#version 150\n" + "uniform mat4 mvp;" + "in vec4 pos;" + "void main(){" + " gl_Position = mvp * pos;" + "}"; + static const char* shader_color_f = + "#version 150\n" + "uniform vec4 col;" + "out vec4 frag;" + "void main(){" + " frag = col;" + "}"; + shader.create(shader_v, shader_f); + shader_color.create(shader_color_v, shader_color_f); + plane.create<15>(.5f, .5f); + longPlane.create<1>(.3, .05f); + circle.create<6>(.5f); + if (!tex.load("data/image.png")) + printf("error loading image\n"); + + glViewport(0, 0, width, height); + glEnable(GL_TEXTURE); + glDisable(GL_DEPTH_TEST); + glPointSize(5); + glLineWidth(15); + + int n; + glGetIntegerv(GL_NUM_EXTENSIONS, &n); + for (int i = 0; i < n; i++) + { + const unsigned char* s = glGetStringi(GL_EXTENSIONS, i); + printf("GL ext %03d: %s\n", i, s); + } + printf("GL version: %s\n", glGetString(GL_VERSION)); + printf("GL vendor: %s\n", glGetString(GL_VENDOR)); + printf("GL renderer: %s\n", glGetString(GL_RENDERER)); + + GLfloat width_range[2]; + glGetFloatv(GL_LINE_WIDTH_RANGE, width_range); + printf("GL line range: %f - %f\n", width_range[0], width_range[1]); +} + +void App::update(float dt) +{ + static float theta = 0; + theta += M_PI * 0.5f * dt; + float red = fabsf(sinf(theta)); + + glm::mat4 proj = glm::perspective(glm::radians(85.f), 1.f, .1f, 100.f); + glm::mat4 model = glm::translate(glm::vec3(0, 0, 0)); + glm::mat4 view = glm::lookAt(glm::vec3(sinf(theta), 0, 1), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)); + auto mvp = proj * view * model; + + glClearColor(red, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + shader.use(); + shader.u_mat4("mvp", glm::mat4()); + shader.u_int("tex", 0); + + glActiveTexture(GL_TEXTURE0); + tex.bind(); + //circle.draw_fill(); + tex.unbind(); + + shader_color.use(); + shader_color.u_mat4("mvp", glm::mat4()); + shader_color.u_vec4("col", {1, 1, 1, 1}); + circle.draw_stroke(); +} diff --git a/engine/app.hpp b/engine/app.hpp new file mode 100644 index 0000000..0cac64c --- /dev/null +++ b/engine/app.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "shader.hpp" +#include "shape.hpp" +#include "texture.hpp" + +class App +{ + Shader shader; + Shader shader_color; + Plane plane; + Plane longPlane; + Circle circle; + Texture2D tex; +public: + static App I; + int width; + int height; + void init(); + void create(); + void update(float dt); +}; diff --git a/engine/image.cpp b/engine/image.cpp new file mode 100644 index 0000000..9cf3234 --- /dev/null +++ b/engine/image.cpp @@ -0,0 +1,13 @@ +#include "pch.h" +#include "image.hpp" + +#define STB_IMAGE_IMPLEMENTATION +#include + +bool Image::load(std::string filename) +{ + stbi_set_flip_vertically_on_load(true); + uint8_t* buffer = stbi_load(filename.c_str(), &width, &height, &comp, 0); + m_data = std::unique_ptr(buffer); + return true; +} diff --git a/engine/image.hpp b/engine/image.hpp new file mode 100644 index 0000000..8cad34e --- /dev/null +++ b/engine/image.hpp @@ -0,0 +1,13 @@ +#pragma once + +class Image +{ + std::unique_ptr m_data; +public: + int width; + int height; + int comp; + bool load(std::string filename); + const uint8_t* data() const { return m_data.get(); } + int size() const { return width * height * comp; } +}; diff --git a/engine/main.cpp b/engine/main.cpp new file mode 100644 index 0000000..f3dfb6a --- /dev/null +++ b/engine/main.cpp @@ -0,0 +1,191 @@ +#include "pch.h" +#include "shader.hpp" +#include "shape.hpp" +#include "texture.hpp" +#include "image.hpp" +#include "app.hpp" + +#include +#include +#include +#include + +@interface View : NSOpenGLView +{ + CVDisplayLinkRef dl; +} +@end @implementation View +- (instancetype)initWithFrame:(NSRect)frameRect +{ + NSOpenGLPixelFormatAttribute attrs[] = + { + NSOpenGLPFADoubleBuffer, + NSOpenGLPFADepthSize, 24, + // Must specify the 3.2 Core Profile to use OpenGL 3.2 + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core, + // Multisample + NSOpenGLPFAMultisample, + NSOpenGLPFASamples, 2, + NSOpenGLPFASampleBuffers, 1, + 0 + }; + NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; + NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil]; + self = [super initWithFrame:frameRect pixelFormat:pf]; + [self setPixelFormat:pf]; + [self setOpenGLContext:context]; + return self; +} +- (void)prepareOpenGL +{ + NSLog(@"prepare"); + + // Synchronize buffer swaps with vertical refresh rate + GLint swapInt = 1; + [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; + + // Create a display link capable of being used with all active displays + CVDisplayLinkCreateWithActiveCGDisplays(&dl); + + // Set the renderer output callback function + CVDisplayLinkSetOutputCallback(dl, &MyDisplayLinkCallback, (__bridge void*)self); + + // Set the display link for the current renderer + CGLContextObj cglContext = [[self openGLContext] CGLContextObj]; + CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj]; + CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(dl, cglContext, cglPixelFormat); + + // Activate the display link + CVDisplayLinkStart(dl); + + CGLEnable([self.openGLContext CGLContextObj], kCGLCECrashOnRemovedFunctions); + + App::I.init(); +} + +// This is the renderer output callback function +static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, + const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) +{ + CVReturn result = [(__bridge View*)displayLinkContext getFrameForTime:outputTime]; + return result; +} + +- (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime +{ + static double _timeFreq = CVGetHostClockFrequency(); + static double _prevTime = (double)outputTime->hostTime / _timeFreq; + double hostTime = (double)outputTime->hostTime; + double now = hostTime / _timeFreq; + + // this will not update unless 1/30th of a second has passed since the last update + if ( now < _prevTime + (1.0 / 30.0) ) + { + // Add your drawing codes here + [[self openGLContext] makeCurrentContext]; + + App::I.update(now - _prevTime); + + [[self openGLContext] flushBuffer]; + // returning NO will cause the layer to NOT be redrawn + return NO; + } + else + { + // change whatever you want to change here, as a function of time elapsed + _prevTime = now; + // return YES to have your layer redrawn + return YES; + } + + return kCVReturnSuccess; +} + +- (void)dealloc +{ + // Release the display link + CVDisplayLinkRelease(dl); +} + +- (void)drawRect:(NSRect)dirtyRect +{ + NSLog(@"drawRect"); +} +@end + +@interface Window : NSWindow +@end @implementation Window +- (void)keyDown:(NSEvent *)theEvent +{ + [[self windowController] keyDown:theEvent]; +} +@end + +@interface Controller : NSWindowController +@end @implementation Controller +- (void)keyDown:(NSEvent *)theEvent +{ + unichar c = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]; + if (c == 27) + { + [[NSApplication sharedApplication] terminate:nil]; + } +} +@end + +@interface AppOSX : NSApplication +{ + Window* window; + Controller* controller; + View* view; +} +@end @implementation AppOSX +- (instancetype)init +{ + self = [super init]; + [self setActivationPolicy:NSApplicationActivationPolicyRegular]; // make it to the front + [self setDelegate:self]; + return self; +} +- (void)applicationDidFinishLaunching:(NSNotification *)notification +{ + auto& app = App::I; + app.create(); + NSRect r = NSMakeRect(0, 0, app.width, app.height); + + view = [[View alloc] initWithFrame:r]; + + window = [[Window alloc] initWithContentRect:r + styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + [window setTitle:@"hello engine"]; + [window center]; + [window makeKeyAndOrderFront:controller]; + [window setContentView:view]; + + controller = [[Controller alloc] initWithWindow:window]; + + auto menubar = [NSMenu new]; + auto appMenuItem = [NSMenuItem new]; + [menubar addItem:appMenuItem]; + [self setMainMenu:menubar]; + + auto appMenu = [NSMenu new]; + auto appName = [[NSProcessInfo processInfo] processName]; + auto quitTitle = [@"Quit " stringByAppendingString:appName]; + auto quitMenuItem = [[NSMenuItem alloc] initWithTitle:quitTitle + action:@selector(terminate:) keyEquivalent:@"q"]; + [appMenu addItem:quitMenuItem]; + [appMenuItem setSubmenu:appMenu]; + + NSLog(@"app launched"); +} +@end + +int main(int argc, const char * argv[]) +{ + AppOSX* app = [AppOSX sharedApplication]; + [app run]; + return 0; +} diff --git a/engine/pch.h b/engine/pch.h new file mode 100644 index 0000000..b3dd34a --- /dev/null +++ b/engine/pch.h @@ -0,0 +1,17 @@ +#ifndef pch_h +#define pch_h + +#include +#include + +#include + +#define GLM_FORCE_RADIANS +#define GLM_SWIZZLE +#include +#include +#include +#include +#include + +#endif diff --git a/engine/shader.cpp b/engine/shader.cpp new file mode 100644 index 0000000..9c30763 --- /dev/null +++ b/engine/shader.cpp @@ -0,0 +1,97 @@ +#include "pch.h" +#include "shader.hpp" + +bool Shader::create(std::string vertex, std::string fragment) +{ + GLint status; + static char infolog[4096]; + int infolen; + const GLchar* source; + + auto vs = glCreateShader(GL_VERTEX_SHADER); + if (!vs) + { + return false; + } + source = vertex.c_str(); + glShaderSource(vs, 1, &source, nullptr); + glCompileShader(vs); + glGetShaderiv(vs, GL_COMPILE_STATUS, &status); + glGetShaderInfoLog(vs, sizeof(infolog), &infolen, infolog); + if (infolen > 0) + printf("VERTEX SHADER:\n%s", infolog); + if (status == 0) + { + glDeleteShader(vs); + return false; + } + + auto fs = glCreateShader(GL_FRAGMENT_SHADER); + if (!fs) + { + glDeleteShader(vs); + return false; + } + source = fragment.c_str(); + glShaderSource(fs, 1, &source, nullptr); + glCompileShader(fs); + glGetShaderiv(fs, GL_COMPILE_STATUS, &status); + glGetShaderInfoLog(fs, sizeof(infolog), &infolen, infolog); + if (infolen > 0) + printf("FRAGMENT SHADER:\n%s", infolog); + if (status == 0) + { + glDeleteShader(vs); + glDeleteShader(fs); + return false; + } + + auto ps = glCreateProgram(); + if (!ps) + { + glDeleteShader(vs); + glDeleteShader(fs); + return false; + } + glAttachShader(ps, vs); + glAttachShader(ps, fs); + glDeleteShader(vs); + glDeleteShader(fs); + + glBindAttribLocation(ps, 0, "pos"); + glBindAttribLocation(ps, 1, "uvs"); + + glLinkProgram(ps); + glGetShaderiv(ps, GL_LINK_STATUS, &status); + glGetShaderInfoLog(ps, sizeof(infolog), &infolen, infolog); + if (infolen > 0) + printf("LINK SHADER:\n%s", infolog); + if (status == 0) + { + glDeleteProgram(ps); + return false; + } + + prog = ps; + + return true; +} +void Shader::use() +{ + glUseProgram(prog); +} +void Shader::u_vec4(std::string name, const glm::vec4& v) +{ + auto loc = glGetUniformLocation(prog, name.c_str()); + glUniform4fv(loc, 1, glm::value_ptr(v)); +} +void Shader::u_mat4(std::string name, const glm::mat4& m) +{ + auto loc = glGetUniformLocation(prog, name.c_str()); + glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(m)); +} +void Shader::u_int(std::string name, int i) +{ + auto loc = glGetUniformLocation(prog, name.c_str()); + glUniform1i(loc, i); +} diff --git a/engine/shader.hpp b/engine/shader.hpp new file mode 100644 index 0000000..236d1d2 --- /dev/null +++ b/engine/shader.hpp @@ -0,0 +1,12 @@ +#pragma once + +class Shader +{ + GLuint prog; +public: + bool create(std::string vertex, std::string fragment); + void use(); + void u_vec4(std::string name, const glm::vec4& v); + void u_mat4(std::string name, const glm::mat4& m); + void u_int(std::string name, int i); +}; diff --git a/engine/shape.cpp b/engine/shape.cpp new file mode 100644 index 0000000..199c2d4 --- /dev/null +++ b/engine/shape.cpp @@ -0,0 +1,38 @@ +#include "pch.h" +#include "shape.hpp" + +void Shape::create_buffers(GLvoid* idx, GLvoid* vertices, int isize, int vsize) +{ + glGenBuffers(2, buffers); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, isize, idx, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glBufferData(GL_ARRAY_BUFFER, vsize, vertices, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glGenVertexArrays(2, arrays); + + for (int i = 0; i < 2; i++) + { + glBindVertexArray(arrays[i]); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)0); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs)); + } + + glBindVertexArray(0); +} +void Shape::draw_fill() const +{ + glBindVertexArray(arrays[0]); + glDrawElements(GL_TRIANGLES, count[0], GL_UNSIGNED_SHORT, ioff[0]); +} +void Shape::draw_stroke() const +{ + glBindVertexArray(arrays[1]); + glDrawElements(GL_LINES, count[1], GL_UNSIGNED_SHORT, ioff[1]); +} diff --git a/engine/shape.hpp b/engine/shape.hpp new file mode 100644 index 0000000..4e79e0f --- /dev/null +++ b/engine/shape.hpp @@ -0,0 +1,154 @@ +#pragma once + +class Shape +{ +protected: + GLuint buffers[2]; + GLuint arrays[2]; + GLuint count[2]; + GLvoid* ioff[2]; + struct vertex_t { glm::vec4 pos; glm::vec2 uvs; }; +public: + void create_buffers(GLvoid* idx, GLvoid* vertices, int isize, int vsize); + void draw_fill() const; + void draw_stroke() const; +}; + +class Plane : public Shape +{ +public: + template + bool create(float w, float h) + { + + static GLshort idx[div * div * 6 + 4]; + static vertex_t vertices[(div+1)*(div+1)]; + + count[0] = div * div * 6; + count[1] = 4; + ioff[0] = (GLvoid*)4; + ioff[1] = (GLvoid*)0; + + const float dx = w / div; + const float dy = h / div; + const float ox = -w * 0.5f; + const float oy = -h * 0.5f; + int v_index = 0; + for (int y = 0; y <= div; y++) + { + for (int x = 0; x <= div; x++) + { + vertex_t v; + v.pos.x = ox + dx * (float)x; + v.pos.y = oy + dy * (float)y; + v.pos.z = 0; + v.pos.w = 1; + v.uvs = glm::vec2(x, y) / (float)div; + vertices[v_index++] = v; + } + } + + // generate indices + auto pidx = idx; + *pidx++ = 0; + *pidx++ = div; + *pidx++ = (div+1)*(div); + *pidx++ = (div+1)*(div+1)-1; + for (int y = 0; y < div; y++) + { + int i = y * (div+1); + for (int x = 0; x < div; x++) + { + *pidx++ = i; + *pidx++ = i + div + 1; + *pidx++ = i + div + 2; + *pidx++ = i; + *pidx++ = i + div + 2; + *pidx++ = i + 1; + i++; + } + } + + create_buffers(idx, vertices, sizeof(idx), sizeof(vertices)); + + return true; + } +}; + +class Circle : public Shape +{ +public: + template + bool create(float radius) + { + static GLushort idx[div * 3 + div * 2]; + static vertex_t vertices[div + 1]; + + count[0] = div * 3; + count[1] = div * 2; + ioff[0] = (GLvoid*)0; + ioff[1] = (GLvoid*)(div * 3 * sizeof(idx[0])); + + auto pidx = idx; + auto pidx2 = idx + div * 3; + for (int i = 0; i < div; i++) + { + vertex_t v; + float theta = (float)i / div * M_PI * 2.f; + v.pos.x = sinf(theta) * radius; + v.pos.y = cosf(theta) * radius; + v.pos.z = 0; + v.pos.w = 1; + v.uvs = v.pos.xy() * 0.5f + 0.5f; + vertices[i+1] = v; + + *pidx++ = 0; + *pidx++ = i+1; + *pidx++ = ((i+1) % div) + 1; + + *pidx2++ = 1 + i; + *pidx2++ = 1 + ((i+1) % div); + } + vertices[0].pos = { 0, 0, 0, 1 }; + vertices[0].uvs = { 0.5f, 0.5f }; + + create_buffers(idx, vertices, sizeof(idx), sizeof(vertices)); + + return true; + } + template + bool create(float radius_out, float radius_in) + { + static GLubyte idx[div*6 + div*2]; + static vertex_t vertices[div * 2]; + + count[0] = div * 6; + count[1] = div * 2; + + auto pidx = idx; + auto pidx2 = idx + div * 6; + for (int i = 0; i < div; i++) + { + float theta = (float)i / div * M_PI * 2.f; + vertices[i*2].pos = { sinf(theta) * radius_in, cosf(theta) * radius_in, 0, 1 }; + vertices[i*2].uvs = vertices[i*2].pos.xy() * 0.5f + 0.5f; + vertices[i*2+1].pos = { sinf(theta) * radius_out, cosf(theta) * radius_out, 0, 1 }; + vertices[i*2+1].uvs = vertices[i*2+1].pos.xy() * 0.5f + 0.5f; + + *pidx++ = i*2; // A + *pidx++ = i*2+1; // B + *pidx++ = ((i+1)*2+1) % (div*2); // C + + *pidx++ = i*2; // A + *pidx++ = ((i+1)*2+1) % (div*2); // C + *pidx++ = ((i+1)*2) % (div*2); // D + + *pidx2++ = 1 + i; + *pidx2++ = 1 + ((i+1) % div); + } + + create_buffers(idx, vertices, sizeof(idx), sizeof(vertices)); + + return true; + } +}; diff --git a/engine/texture.cpp b/engine/texture.cpp new file mode 100644 index 0000000..2f0938b --- /dev/null +++ b/engine/texture.cpp @@ -0,0 +1,36 @@ +#include "pch.h" +#include "texture.hpp" +#include "image.hpp" + +bool Texture2D::create(int width, int height, GLint format, const uint8_t* data, GLint filter, GLint wrap) +{ + m_width = width; + m_height = height; + m_format = format; + glGenTextures(1, &m_tex); + bind(); + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap); + unbind(); + return true; +} +bool Texture2D::create(const Image& img) +{ + static GLint formats[] = { GL_R, GL_RG, GL_RGB, GL_RGBA }; + return create(img.width, img.height, formats[img.comp - 1], img.data()); +} +bool Texture2D::load(std::string filename) +{ + Image img; + if (!img.load(filename)) + return false; + return create(img); +} +void Texture2D::update(const uint8_t* data) +{ + bind(); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_width, m_height, m_format, GL_UNSIGNED_BYTE, data); +} diff --git a/engine/texture.hpp b/engine/texture.hpp new file mode 100644 index 0000000..08b40b5 --- /dev/null +++ b/engine/texture.hpp @@ -0,0 +1,18 @@ +#pragma once + +class Texture2D +{ + GLuint m_tex; + int m_width; + int m_height; + GLint m_format; +public: + bool create(int width, int height, GLint format = GL_RGBA, + const uint8_t* data = nullptr, GLint filter = GL_LINEAR, GLint wrap = GL_CLAMP_TO_EDGE); + bool create(const class Image& img); + bool load(std::string filename); + void destroy() { glDeleteTextures(1, &m_tex); } + void bind() const { glBindTexture(GL_TEXTURE_2D, m_tex); } + void unbind() const { glBindTexture(GL_TEXTURE_2D, 0); } + void update(const uint8_t* data); +};