├── LICENSES ├── README.md ├── example ├── OpenGLWindow │ ├── CommonWindowInterface.h │ ├── MacOpenGLWindow.h │ ├── MacOpenGLWindow.mm │ ├── OpenGL2Include.h │ ├── OpenGLInclude.h │ ├── Win32InternalWindowData.h │ ├── Win32OpenGLWindow.cpp │ ├── Win32OpenGLWindow.h │ ├── Win32Window.cpp │ ├── Win32Window.h │ ├── X11OpenGLWindow.cpp │ └── X11OpenGLWindow.h ├── README.md ├── Roboto-Bold.ttf ├── Roboto-Light.ttf ├── Roboto-Regular.ttf ├── ThirdPartyLibs │ └── Glew │ │ ├── CustomGL │ │ ├── glew.h │ │ ├── glxew.h │ │ └── wglew.h │ │ └── glew.c ├── bt3-browser-shim.js ├── bt3gui.js ├── entypo.ttf ├── findOpenGLGlewGlut.lua ├── images.txt ├── images │ ├── image1.jpg │ ├── image10.jpg │ ├── image11.jpg │ ├── image12.jpg │ ├── image2.jpg │ ├── image3.jpg │ ├── image4.jpg │ ├── image5.jpg │ ├── image6.jpg │ ├── image7.jpg │ ├── image8.jpg │ └── image9.jpg ├── input.js ├── main.cc ├── perf.c └── perf.h ├── game ├── game.js └── images │ ├── hyptosis_sprites_organized.png │ ├── hyptosis_til-art-batch-2.png │ ├── hyptosis_tile-art-batch-1.png │ ├── hyptosis_tile-art-batch-3.png │ ├── hyptosis_tile-art-batch-4.png │ └── hyptosis_tile-art-batch-5.png ├── images ├── screenshot-linux.png ├── screenshot-win.jpg └── screenshot.png ├── premake4.lua └── src ├── duk_config.h ├── duktape.c ├── duktape.h ├── fontstash.h ├── nanovg.c ├── nanovg.h ├── nanovg_gl.h ├── nanovg_gl_utils.h ├── stb_image.h └── stb_truetype.h /LICENSES: -------------------------------------------------------------------------------- 1 | # Licenses 2 | 3 | * NanoCanvas : MIT License 4 | * Duktape : MIT License http://duktape.org/ 5 | * NanoVG : zlib License https://github.com/memononen/nanovg 6 | * bt3gui : zlib License https://github.com/bulletphysics/bullet3/blob/master/LICENSE.txt 7 | * Glew : The source code is licensed under the Modified BSD License, the Mesa 3-D License (MIT) and the Khronos License (MIT). https://github.com/nigels-com/glew#copyright-and-licensing 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NanoCanvas, portable JavaScript vector graphics engine. 2 | 3 | ![](images/screenshot.png) 4 | ![](images/screenshot-win.jpg) 5 | ![](images/screenshot-linux.png) 6 | 7 | NanoCanvas is a portable vector graphics engine using JavaScript binding of NanoVG. 8 | NanoCanvas is build on top of Duktape, NanoVG and OpenGL2(or GLESv2). 9 | 10 | ## Platform 11 | 12 | * Mac OS X 13 | * Linux 14 | * Windows 15 | * iOS/Android(TODO) 16 | 17 | ## Requirements 18 | 19 | * OpenGL2 20 | * GLESv2 21 | * premake5 22 | 23 | ## Build 24 | 25 | ### Linux and MacOSX 26 | 27 | $ premake5 gmake 28 | $ cd build 29 | $ make 30 | 31 | ### Windows 32 | 33 | Visual Studio 2015 is required to build an example. 34 | 35 | > premake5.exe vs2015 36 | > cd build 37 | 38 | Open solution file and build it with Visual Studio 2015. 39 | 40 | Visual Studio 2013 may work. To compile with Visual Studio 2013 use the following premake flag. 41 | 42 | > premake5.exe vs2013 43 | 44 | ## Example 45 | 46 | See `example/main.cc` and `example/input.js`. 47 | 48 | ### NanoVG demo 49 | 50 | $ cd build 51 | $ ./example 52 | 53 | ### Game demo 54 | 55 | $ cd build 56 | $ ./example ../game/game.js 57 | 58 | ## License 59 | 60 | NanoCanvas example code is licensed under MIT license. 61 | NanoCanvas uses third party libraries. See `LICENSES` file for more details. 62 | 63 | ### Game example 64 | 65 | Game assets are by Hyptosis. Licensed under CC-BY 3.0. 66 | http://opengameart.org/content/lots-of-free-2d-tiles-and-sprites-by-hyptosis 67 | 68 | ## TODO 69 | 70 | * [ ] More HTML5 compatible APIs. 71 | * [ ] Expressive error handling. 72 | * [ ] Expressive error report of parsing JavaScript code. 73 | * [ ] Refactor source code. 74 | * [ ] Text paragraph 75 | * [x] Mouse interaction 76 | 77 | -------------------------------------------------------------------------------- /example/OpenGLWindow/CommonWindowInterface.h: -------------------------------------------------------------------------------- 1 | #ifndef B3G_WINDOW_INTERFACE_H 2 | #define B3G_WINDOW_INTERFACE_H 3 | 4 | 5 | typedef void (*b3WheelCallback)(float deltax, float deltay); 6 | typedef void (*b3ResizeCallback)( float width, float height); 7 | typedef void (*b3MouseMoveCallback)( float x, float y); 8 | typedef void (*b3MouseButtonCallback)(int button, int state, float x, float y); 9 | typedef void (*b3KeyboardCallback)(int keycode, int state); 10 | typedef void (*b3RenderCallback) (); 11 | 12 | enum { 13 | B3G_ESCAPE = 27, 14 | B3G_F1 = 0xff00, 15 | B3G_F2, 16 | B3G_F3, 17 | B3G_F4, 18 | B3G_F5, 19 | B3G_F6, 20 | B3G_F7, 21 | B3G_F8, 22 | B3G_F9, 23 | B3G_F10, 24 | B3G_F11, 25 | B3G_F12, 26 | B3G_F13, 27 | B3G_F14, 28 | B3G_F15, 29 | B3G_LEFT_ARROW, 30 | B3G_RIGHT_ARROW, 31 | B3G_UP_ARROW, 32 | B3G_DOWN_ARROW, 33 | B3G_PAGE_UP, 34 | B3G_PAGE_DOWN, 35 | B3G_END, 36 | B3G_HOME, 37 | B3G_INSERT, 38 | B3G_DELETE, 39 | B3G_BACKSPACE, 40 | B3G_SHIFT, 41 | B3G_CONTROL, 42 | B3G_ALT, 43 | B3G_RETURN 44 | }; 45 | 46 | struct b3gWindowConstructionInfo 47 | { 48 | int m_width; 49 | int m_height; 50 | bool m_fullscreen; 51 | int m_colorBitsPerPixel; 52 | void* m_windowHandle; 53 | const char* m_title; 54 | int m_openglVersion; 55 | 56 | 57 | b3gWindowConstructionInfo(int width=1024, int height=768) 58 | :m_width(width), 59 | m_height(height), 60 | m_fullscreen(false), 61 | m_colorBitsPerPixel(32), 62 | m_windowHandle(0), 63 | m_title("title"), 64 | m_openglVersion(3) 65 | { 66 | } 67 | }; 68 | 69 | 70 | class CommonWindowInterface 71 | { 72 | public: 73 | 74 | virtual ~CommonWindowInterface() 75 | { 76 | } 77 | 78 | virtual void createDefaultWindow(int width, int height, const char* title) 79 | { 80 | b3gWindowConstructionInfo ci(width,height); 81 | ci.m_title = title; 82 | createWindow(ci); 83 | } 84 | 85 | virtual void createWindow(const b3gWindowConstructionInfo& ci)=0; 86 | 87 | virtual void closeWindow()=0; 88 | 89 | virtual void runMainLoop()=0; 90 | virtual float getTimeInSeconds()=0; 91 | 92 | virtual bool requestedExit() const = 0; 93 | virtual void setRequestExit() = 0; 94 | 95 | virtual void startRendering()=0; 96 | 97 | virtual void endRendering()=0; 98 | 99 | virtual bool isModifierKeyPressed(int key) = 0; 100 | 101 | virtual void setMouseMoveCallback(b3MouseMoveCallback mouseCallback)=0; 102 | virtual b3MouseMoveCallback getMouseMoveCallback()=0; 103 | 104 | virtual void setMouseButtonCallback(b3MouseButtonCallback mouseCallback)=0; 105 | virtual b3MouseButtonCallback getMouseButtonCallback()=0; 106 | 107 | virtual void setResizeCallback(b3ResizeCallback resizeCallback)=0; 108 | virtual b3ResizeCallback getResizeCallback()=0; 109 | 110 | virtual void setWheelCallback(b3WheelCallback wheelCallback)=0; 111 | virtual b3WheelCallback getWheelCallback()=0; 112 | 113 | virtual void setKeyboardCallback( b3KeyboardCallback keyboardCallback)=0; 114 | virtual b3KeyboardCallback getKeyboardCallback()=0; 115 | 116 | virtual void setRenderCallback( b3RenderCallback renderCallback) = 0; 117 | 118 | virtual void setWindowTitle(const char* title)=0; 119 | 120 | virtual float getRetinaScale() const =0; 121 | virtual void setAllowRetina(bool allow) =0; 122 | 123 | virtual int getWidth() const = 0; 124 | virtual int getHeight() const = 0; 125 | 126 | virtual int fileOpenDialog(char* fileName, int maxFileNameLength) = 0; 127 | 128 | }; 129 | 130 | #endif //B3G_WINDOW_INTERFACE_H -------------------------------------------------------------------------------- /example/OpenGLWindow/MacOpenGLWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAC_OPENGL_WINDOW_H 2 | #define MAC_OPENGL_WINDOW_H 3 | 4 | #include "CommonWindowInterface.h" 5 | 6 | #define b3gDefaultOpenGLWindow MacOpenGLWindow 7 | 8 | class MacOpenGLWindow : public CommonWindowInterface 9 | { 10 | struct MacOpenGLWindowInternalData* m_internalData; 11 | float m_mouseX; 12 | float m_mouseY; 13 | int m_modifierFlags; 14 | 15 | b3MouseButtonCallback m_mouseButtonCallback; 16 | b3MouseMoveCallback m_mouseMoveCallback; 17 | b3WheelCallback m_wheelCallback; 18 | b3KeyboardCallback m_keyboardCallback; 19 | b3RenderCallback m_renderCallback; 20 | 21 | float m_retinaScaleFactor; 22 | bool m_allowRetina; 23 | 24 | public: 25 | 26 | MacOpenGLWindow(); 27 | virtual ~MacOpenGLWindow(); 28 | 29 | void init(int width, int height, const char* windowTitle); 30 | 31 | void closeWindow(); 32 | 33 | void startRendering(); 34 | 35 | void endRendering();//swap buffers 36 | 37 | virtual bool requestedExit() const; 38 | 39 | virtual void setRequestExit(); 40 | 41 | void getMouseCoordinates(int& x, int& y); 42 | 43 | void runMainLoop(); 44 | 45 | virtual bool isModifierKeyPressed(int key); 46 | 47 | void setMouseButtonCallback(b3MouseButtonCallback mouseCallback) 48 | { 49 | m_mouseButtonCallback = mouseCallback; 50 | } 51 | 52 | void setMouseMoveCallback(b3MouseMoveCallback mouseCallback) 53 | { 54 | m_mouseMoveCallback = mouseCallback; 55 | } 56 | 57 | void setResizeCallback(b3ResizeCallback resizeCallback); 58 | 59 | 60 | void setKeyboardCallback( b3KeyboardCallback keyboardCallback) 61 | { 62 | m_keyboardCallback = keyboardCallback; 63 | } 64 | 65 | virtual b3MouseMoveCallback getMouseMoveCallback() 66 | { 67 | return m_mouseMoveCallback; 68 | } 69 | virtual b3MouseButtonCallback getMouseButtonCallback() 70 | { 71 | return m_mouseButtonCallback; 72 | } 73 | virtual b3ResizeCallback getResizeCallback(); 74 | 75 | virtual b3WheelCallback getWheelCallback() 76 | { 77 | return m_wheelCallback; 78 | } 79 | 80 | b3KeyboardCallback getKeyboardCallback() 81 | { 82 | return m_keyboardCallback; 83 | } 84 | 85 | void setWheelCallback (b3WheelCallback wheelCallback) 86 | { 87 | m_wheelCallback = wheelCallback; 88 | } 89 | 90 | float getRetinaScale() const 91 | { 92 | return m_retinaScaleFactor; 93 | } 94 | virtual void setAllowRetina(bool allow) 95 | { 96 | m_allowRetina = allow; 97 | } 98 | 99 | virtual void createWindow(const b3gWindowConstructionInfo& ci); 100 | 101 | virtual float getTimeInSeconds(); 102 | 103 | 104 | virtual int getWidth() const; 105 | virtual int getHeight() const; 106 | 107 | 108 | virtual void setRenderCallback( b3RenderCallback renderCallback); 109 | 110 | virtual void setWindowTitle(const char* title); 111 | 112 | int fileOpenDialog(char* filename, int maxNameLength); 113 | 114 | }; 115 | 116 | 117 | #endif 118 | 119 | -------------------------------------------------------------------------------- /example/OpenGLWindow/MacOpenGLWindow.mm: -------------------------------------------------------------------------------- 1 | #include "MacOpenGLWindow.h" 2 | 3 | #define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED 4 | #import 5 | #include "OpenGLInclude.h" 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | enum 15 | { 16 | MY_MAC_ALTKEY=1, 17 | MY_MAC_SHIFTKEY=2, 18 | MY_MAC_CONTROL_KEY=4 19 | }; 20 | 21 | /* report GL errors, if any, to stderr */ 22 | static void checkError(const char *functionName) 23 | { 24 | GLenum error; 25 | while (( error = glGetError() ) != GL_NO_ERROR) 26 | { 27 | fprintf (stderr, "GL error 0x%X detected in %s\n", error, functionName); 28 | } 29 | } 30 | 31 | void dumpInfo(void) 32 | { 33 | printf ("Vendor: %s\n", glGetString (GL_VENDOR)); 34 | printf ("Renderer: %s\n", glGetString (GL_RENDERER)); 35 | printf ("Version: %s\n", glGetString (GL_VERSION)); 36 | printf ("GLSL: %s\n", glGetString (GL_SHADING_LANGUAGE_VERSION)); 37 | checkError ("dumpInfo"); 38 | } 39 | 40 | 41 | 42 | 43 | // -------------------- View ------------------------ 44 | 45 | @interface TestView : NSView 46 | { 47 | NSOpenGLContext* m_context; 48 | int m_lastWidth; 49 | int m_lastHeight; 50 | bool m_requestClose; 51 | b3ResizeCallback m_resizeCallback; 52 | 53 | } 54 | -(void)drawRect:(NSRect)rect; 55 | -(void) MakeContext:(int) openglVersion; 56 | -(void) MakeCurrent; 57 | -(float) GetWindowWidth; 58 | -(float) GetWindowHeight; 59 | -(BOOL) GetRequestClose; 60 | - (BOOL)windowShouldClose:(id)sender; 61 | -(void) setResizeCallback:(b3ResizeCallback) callback; 62 | -(b3ResizeCallback) getResizeCallback; 63 | -(NSOpenGLContext*) getContext; 64 | @end 65 | 66 | float loop; 67 | 68 | #define Pi 3.1415 69 | 70 | @implementation TestView 71 | 72 | - (BOOL)windowShouldClose:(id)sender 73 | { 74 | m_requestClose = true; 75 | return false; 76 | } 77 | -(BOOL) GetRequestClose 78 | { 79 | return m_requestClose; 80 | } 81 | -(float) GetWindowWidth 82 | { 83 | return m_lastWidth; 84 | } 85 | -(float) GetWindowHeight 86 | { 87 | return m_lastHeight; 88 | } 89 | 90 | -(b3ResizeCallback) getResizeCallback 91 | { 92 | return m_resizeCallback; 93 | } 94 | 95 | -(NSOpenGLContext*) getContext 96 | { 97 | return m_context; 98 | } 99 | -(void)setResizeCallback:(b3ResizeCallback)callback 100 | { 101 | m_resizeCallback = callback; 102 | } 103 | -(void)drawRect:(NSRect)rect 104 | { 105 | if (([self frame].size.width != m_lastWidth) || ([self frame].size.height != m_lastHeight)) 106 | { 107 | m_lastWidth = [self frame].size.width; 108 | m_lastHeight = [self frame].size.height; 109 | 110 | // Only needed on resize: 111 | [m_context clearDrawable]; 112 | 113 | // reshape([self frame].size.width, [self frame].size.height); 114 | float width = [self frame].size.width; 115 | float height = [self frame].size.height; 116 | 117 | 118 | // Get view dimensions in pixels 119 | // glViewport(0,0,10,10); 120 | 121 | if (m_resizeCallback) 122 | { 123 | (*m_resizeCallback)(width,height); 124 | } 125 | #ifndef NO_OPENGL3 126 | NSRect backingBounds = [self convertRectToBacking:[self bounds]]; 127 | GLsizei backingPixelWidth = (GLsizei)(backingBounds.size.width), 128 | backingPixelHeight = (GLsizei)(backingBounds.size.height); 129 | 130 | // Set viewport 131 | glViewport(0, 0, backingPixelWidth, backingPixelHeight); 132 | #else 133 | glViewport(0,0,(GLsizei)width,(GLsizei)height); 134 | #endif 135 | } 136 | 137 | [m_context setView: self]; 138 | [m_context makeCurrentContext]; 139 | 140 | // Draw 141 | //display(); 142 | 143 | [m_context flushBuffer]; 144 | [NSOpenGLContext clearCurrentContext]; 145 | 146 | loop = loop + 0.1; 147 | } 148 | 149 | -(void) MakeContext :(int) openglVersion 150 | { 151 | // NSWindow *w; 152 | NSOpenGLPixelFormat *fmt; 153 | 154 | m_requestClose = false; 155 | 156 | 157 | 158 | #ifndef NO_OPENGL3 159 | if (openglVersion==3) 160 | { 161 | NSOpenGLPixelFormatAttribute attrs[] = 162 | { 163 | NSOpenGLPFAOpenGLProfile, 164 | NSOpenGLProfileVersion3_2Core, 165 | NSOpenGLPFADoubleBuffer, 166 | NSOpenGLPFADepthSize, 32, 167 | NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute)8, 168 | (NSOpenGLPixelFormatAttribute)0 169 | }; 170 | 171 | // Init GL context 172 | fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: (NSOpenGLPixelFormatAttribute*)attrs]; 173 | } else 174 | #endif 175 | { 176 | NSOpenGLPixelFormatAttribute attrs[] = 177 | { 178 | NSOpenGLPFADoubleBuffer, 179 | NSOpenGLPFADepthSize, 32, 180 | NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute)8, 181 | (NSOpenGLPixelFormatAttribute)0 182 | }; 183 | // Init GL context 184 | fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: (NSOpenGLPixelFormatAttribute*)attrs]; 185 | 186 | } 187 | m_context = [[NSOpenGLContext alloc] initWithFormat: fmt shareContext: nil]; 188 | [fmt release]; 189 | [m_context makeCurrentContext]; 190 | 191 | checkError("makeCurrentContext"); 192 | } 193 | 194 | -(void) MakeCurrent 195 | { 196 | [m_context makeCurrentContext]; 197 | } 198 | -(void)windowWillClose:(NSNotification *)note 199 | { 200 | [[NSApplication sharedApplication] terminate:self]; 201 | } 202 | @end 203 | 204 | struct MacOpenGLWindowInternalData 205 | { 206 | MacOpenGLWindowInternalData() 207 | { 208 | m_myApp = 0; 209 | m_myview = 0; 210 | m_pool = 0; 211 | m_window = 0; 212 | m_width = -1; 213 | m_height = -1; 214 | m_exitRequested = false; 215 | } 216 | NSApplication* m_myApp; 217 | TestView* m_myview; 218 | NSAutoreleasePool* m_pool; 219 | NSWindow* m_window; 220 | int m_width; 221 | int m_height; 222 | bool m_exitRequested; 223 | 224 | }; 225 | 226 | MacOpenGLWindow::MacOpenGLWindow() 227 | :m_internalData(0), 228 | m_mouseX(0), 229 | m_mouseY(0), 230 | m_modifierFlags(0), 231 | m_mouseMoveCallback(0), 232 | m_mouseButtonCallback(0), 233 | m_wheelCallback(0), 234 | m_keyboardCallback(0), 235 | m_retinaScaleFactor(1), 236 | m_allowRetina(true) 237 | { 238 | } 239 | 240 | MacOpenGLWindow::~MacOpenGLWindow() 241 | { 242 | if (m_internalData) 243 | closeWindow(); 244 | } 245 | 246 | 247 | bool MacOpenGLWindow::isModifierKeyPressed(int key) 248 | { 249 | bool isPressed = false; 250 | 251 | switch (key) 252 | { 253 | case B3G_ALT: 254 | { 255 | isPressed = ((m_modifierFlags & MY_MAC_ALTKEY)!=0); 256 | break; 257 | }; 258 | case B3G_SHIFT: 259 | { 260 | isPressed = ((m_modifierFlags & MY_MAC_SHIFTKEY)!=0); 261 | break; 262 | }; 263 | case B3G_CONTROL: 264 | { 265 | isPressed = ((m_modifierFlags & MY_MAC_CONTROL_KEY )!=0); 266 | break; 267 | }; 268 | 269 | default: 270 | { 271 | } 272 | }; 273 | return isPressed; 274 | } 275 | 276 | float MacOpenGLWindow::getTimeInSeconds() 277 | { 278 | return 0.f; 279 | } 280 | 281 | 282 | void MacOpenGLWindow::setRenderCallback( b3RenderCallback renderCallback) 283 | { 284 | m_renderCallback = renderCallback; 285 | } 286 | 287 | void MacOpenGLWindow::setWindowTitle(const char* windowTitle) 288 | { 289 | [m_internalData->m_window setTitle:[NSString stringWithCString:windowTitle encoding:NSISOLatin1StringEncoding]] ; 290 | } 291 | 292 | void MacOpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) 293 | { 294 | if (m_internalData) 295 | closeWindow(); 296 | 297 | int width = ci.m_width; 298 | int height = ci.m_height; 299 | const char* windowTitle = ci.m_title; 300 | 301 | 302 | 303 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 304 | 305 | m_internalData = new MacOpenGLWindowInternalData; 306 | m_internalData->m_width = width; 307 | m_internalData->m_height = height; 308 | 309 | m_internalData->m_pool = [NSAutoreleasePool new]; 310 | m_internalData->m_myApp = [NSApplication sharedApplication]; 311 | //myApp = [MyApp sharedApplication]; 312 | //home(); 313 | 314 | [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; 315 | 316 | id menubar = [[NSMenu new] autorelease]; 317 | id appMenuItem = [[NSMenuItem new] autorelease]; 318 | [menubar addItem:appMenuItem]; 319 | [NSApp setMainMenu:menubar]; 320 | 321 | id appMenu = [[NSMenu new] autorelease]; 322 | id appName = [[NSProcessInfo processInfo] processName]; 323 | id quitTitle = [@"Quit " stringByAppendingString:appName]; 324 | id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle 325 | action:@selector(terminate:) keyEquivalent:@"q"] autorelease]; 326 | 327 | [appMenu addItem:quitMenuItem]; 328 | [appMenuItem setSubmenu:appMenu]; 329 | 330 | NSMenuItem *fileMenuItem = [[NSMenuItem new] autorelease]; 331 | NSMenu *fileMenu = [[NSMenu alloc] initWithTitle:@"File"]; 332 | [fileMenuItem setSubmenu: fileMenu]; // was setMenu: 333 | 334 | NSMenuItem *newMenu = [[NSMenuItem alloc] initWithTitle:@"New" action:NULL keyEquivalent:@""]; 335 | NSMenuItem *openMenu = [[NSMenuItem alloc] initWithTitle:@"Open" action:NULL keyEquivalent:@""]; 336 | NSMenuItem *saveMenu = [[NSMenuItem alloc] initWithTitle:@"Save" action:NULL keyEquivalent:@""]; 337 | 338 | [fileMenu addItem: newMenu]; 339 | [fileMenu addItem: openMenu]; 340 | [fileMenu addItem: saveMenu]; 341 | [menubar addItem: fileMenuItem]; 342 | 343 | 344 | // add Edit menu 345 | NSMenuItem *editMenuItem = [[NSMenuItem new] autorelease]; 346 | NSMenu *menu = [[NSMenu allocWithZone:[NSMenu menuZone]]initWithTitle:@"Edit"]; 347 | [editMenuItem setSubmenu: menu]; 348 | 349 | NSMenuItem *copyItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]]initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]; 350 | 351 | [menu addItem:copyItem]; 352 | [menubar addItem:editMenuItem]; 353 | 354 | // [mainMenu setSubmenu:menu forItem:menuItem]; 355 | 356 | 357 | //NSMenuItem *fileMenuItem = [[NSMenuItem alloc] initWithTitle: @"File"]; 358 | /*[fileMenuItem setSubmenu: fileMenu]; // was setMenu: 359 | [fileMenuItem release]; 360 | */ 361 | 362 | /*NSMenu *newMenu; 363 | NSMenuItem *newItem; 364 | 365 | // Add the submenu 366 | newItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] 367 | initWithTitle:@"Flashy" action:NULL keyEquivalent:@""]; 368 | newMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] 369 | initWithTitle:@"Flashy"]; 370 | [newItem setSubmenu:newMenu]; 371 | [newMenu release]; 372 | [[NSApp mainMenu] addItem:newItem]; 373 | [newItem release]; 374 | */ 375 | 376 | NSRect frame = NSMakeRect(0., 0., width, height); 377 | 378 | m_internalData->m_window = [NSWindow alloc]; 379 | [m_internalData->m_window initWithContentRect:frame 380 | styleMask:NSTitledWindowMask |NSResizableWindowMask| NSClosableWindowMask | NSMiniaturizableWindowMask 381 | backing:NSBackingStoreBuffered 382 | defer:false]; 383 | 384 | 385 | [m_internalData->m_window setTitle:[NSString stringWithCString:windowTitle encoding:NSISOLatin1StringEncoding]] ; 386 | 387 | m_internalData->m_myview = [TestView alloc]; 388 | 389 | [m_internalData->m_myview setResizeCallback:0]; 390 | ///ci.m_resizeCallback]; 391 | 392 | [m_internalData->m_myview initWithFrame: frame]; 393 | 394 | // OpenGL init! 395 | [m_internalData->m_myview MakeContext : ci.m_openglVersion]; 396 | 397 | // https://developer.apple.com/library/mac/#documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/CapturingScreenContents/CapturingScreenContents.html#//apple_ref/doc/uid/TP40012302-CH10-SW1 398 | //support HighResolutionOSX for Retina Macbook 399 | if (ci.m_openglVersion>=3) 400 | { 401 | if (m_allowRetina) 402 | { 403 | [m_internalData->m_myview setWantsBestResolutionOpenGLSurface:YES]; 404 | } 405 | } 406 | NSSize sz; 407 | sz.width = 1; 408 | sz.height = 1; 409 | 410 | // float newBackingScaleFactor = [m_internalData->m_window backingScaleFactor]; 411 | 412 | dumpInfo(); 413 | 414 | 415 | 416 | 417 | [m_internalData->m_window setContentView: m_internalData->m_myview]; 418 | 419 | 420 | 421 | [m_internalData->m_window setDelegate:(id) m_internalData->m_myview]; 422 | 423 | [m_internalData->m_window makeKeyAndOrderFront: nil]; 424 | 425 | [m_internalData->m_myview MakeCurrent]; 426 | m_internalData->m_width = m_internalData->m_myview.GetWindowWidth; 427 | m_internalData->m_height = m_internalData->m_myview.GetWindowHeight; 428 | 429 | 430 | [NSApp activateIgnoringOtherApps:YES]; 431 | 432 | 433 | //[m_internalData->m_window setLevel:NSMainMenuWindowLevel]; 434 | 435 | // [NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMovedMask]; 436 | 437 | // [NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMovedMask handler:^(NSEvent *event) 438 | // { 439 | //[window setFrameOrigin:[NSEvent mouseLocation]]; 440 | // NSPoint eventLocation = [m_internalData->m_window mouseLocationOutsideOfEventStream]; 441 | 442 | // NSPoint eventLocation = [event locationInWindow]; 443 | //NSPoint center = [m_internalData->m_myview convertPoint:eventLocation fromView:nil]; 444 | // m_mouseX = center.x; 445 | // m_mouseY = [m_internalData->m_myview GetWindowHeight] - center.y; 446 | 447 | 448 | // printf("mouse coord = %f, %f\n",m_mouseX,m_mouseY); 449 | // if (m_mouseMoveCallback) 450 | // (*m_mouseMoveCallback)(m_mouseX,m_mouseY); 451 | 452 | // }]; 453 | 454 | //see http://stackoverflow.com/questions/8238473/cant-get-nsmousemoved-events-from-nexteventmatchingmask-with-an-nsopenglview 455 | /* ProcessSerialNumber psn; 456 | GetCurrentProcess(&psn); 457 | TransformProcessType(&psn, kProcessTransformToForegroundApplication); 458 | SetFrontProcess(&psn); 459 | */ 460 | #ifndef NO_OPENGL3 461 | m_retinaScaleFactor = [m_internalData->m_myview convertSizeToBacking:sz].width; 462 | #else 463 | m_retinaScaleFactor=1.f; 464 | #endif 465 | 466 | [m_internalData->m_myApp finishLaunching]; 467 | [pool release]; 468 | 469 | } 470 | 471 | void MacOpenGLWindow::runMainLoop() 472 | { 473 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 474 | // FILE* dump = fopen ("/Users/erwincoumans/yes.txt","wb"); 475 | // fclose(dump); 476 | 477 | 478 | 479 | 480 | [pool release]; 481 | 482 | } 483 | 484 | void MacOpenGLWindow::closeWindow() 485 | { 486 | 487 | delete m_internalData; 488 | m_internalData = 0; 489 | 490 | } 491 | extern float m_azi; 492 | extern float m_ele; 493 | extern float m_cameraDistance; 494 | 495 | 496 | /* 497 | * Summary: 498 | * Virtual keycodes 499 | * 500 | * Discussion: 501 | * These constants are the virtual keycodes defined originally in 502 | * Inside Mac Volume V, pg. V-191. They identify physical keys on a 503 | * keyboard. Those constants with "ANSI" in the name are labeled 504 | * according to the key position on an ANSI-standard US keyboard. 505 | * For example, kVK_ANSI_A indicates the virtual keycode for the key 506 | * with the letter 'A' in the US keyboard layout. Other keyboard 507 | * layouts may have the 'A' key label on a different physical key; 508 | * in this case, pressing 'A' will generate a different virtual 509 | * keycode. 510 | */ 511 | enum { 512 | kVK_ANSI_A = 0x00, 513 | kVK_ANSI_S = 0x01, 514 | kVK_ANSI_D = 0x02, 515 | kVK_ANSI_F = 0x03, 516 | kVK_ANSI_H = 0x04, 517 | kVK_ANSI_G = 0x05, 518 | kVK_ANSI_Z = 0x06, 519 | kVK_ANSI_X = 0x07, 520 | kVK_ANSI_C = 0x08, 521 | kVK_ANSI_V = 0x09, 522 | kVK_ANSI_B = 0x0B, 523 | kVK_ANSI_Q = 0x0C, 524 | kVK_ANSI_W = 0x0D, 525 | kVK_ANSI_E = 0x0E, 526 | kVK_ANSI_R = 0x0F, 527 | kVK_ANSI_Y = 0x10, 528 | kVK_ANSI_T = 0x11, 529 | kVK_ANSI_1 = 0x12, 530 | kVK_ANSI_2 = 0x13, 531 | kVK_ANSI_3 = 0x14, 532 | kVK_ANSI_4 = 0x15, 533 | kVK_ANSI_6 = 0x16, 534 | kVK_ANSI_5 = 0x17, 535 | kVK_ANSI_Equal = 0x18, 536 | kVK_ANSI_9 = 0x19, 537 | kVK_ANSI_7 = 0x1A, 538 | kVK_ANSI_Minus = 0x1B, 539 | kVK_ANSI_8 = 0x1C, 540 | kVK_ANSI_0 = 0x1D, 541 | kVK_ANSI_RightBracket = 0x1E, 542 | kVK_ANSI_O = 0x1F, 543 | kVK_ANSI_U = 0x20, 544 | kVK_ANSI_LeftBracket = 0x21, 545 | kVK_ANSI_I = 0x22, 546 | kVK_ANSI_P = 0x23, 547 | kVK_ANSI_L = 0x25, 548 | kVK_ANSI_J = 0x26, 549 | kVK_ANSI_Quote = 0x27, 550 | kVK_ANSI_K = 0x28, 551 | kVK_ANSI_Semicolon = 0x29, 552 | kVK_ANSI_Backslash = 0x2A, 553 | kVK_ANSI_Comma = 0x2B, 554 | kVK_ANSI_Slash = 0x2C, 555 | kVK_ANSI_N = 0x2D, 556 | kVK_ANSI_M = 0x2E, 557 | kVK_ANSI_Period = 0x2F, 558 | kVK_ANSI_Grave = 0x32, 559 | kVK_ANSI_KeypadDecimal = 0x41, 560 | kVK_ANSI_KeypadMultiply = 0x43, 561 | kVK_ANSI_KeypadPlus = 0x45, 562 | kVK_ANSI_KeypadClear = 0x47, 563 | kVK_ANSI_KeypadDivide = 0x4B, 564 | kVK_ANSI_KeypadEnter = 0x4C, 565 | kVK_ANSI_KeypadMinus = 0x4E, 566 | kVK_ANSI_KeypadEquals = 0x51, 567 | kVK_ANSI_Keypad0 = 0x52, 568 | kVK_ANSI_Keypad1 = 0x53, 569 | kVK_ANSI_Keypad2 = 0x54, 570 | kVK_ANSI_Keypad3 = 0x55, 571 | kVK_ANSI_Keypad4 = 0x56, 572 | kVK_ANSI_Keypad5 = 0x57, 573 | kVK_ANSI_Keypad6 = 0x58, 574 | kVK_ANSI_Keypad7 = 0x59, 575 | kVK_ANSI_Keypad8 = 0x5B, 576 | kVK_ANSI_Keypad9 = 0x5C 577 | }; 578 | 579 | /* keycodes for keys that are independent of keyboard layout*/ 580 | enum { 581 | kVK_Return = 0x24, 582 | kVK_Tab = 0x30, 583 | kVK_Space = 0x31, 584 | kVK_Delete = 0x33, 585 | kVK_Escape = 0x35, 586 | kVK_Command = 0x37, 587 | kVK_Shift = 0x38, 588 | kVK_CapsLock = 0x39, 589 | kVK_Option = 0x3A, 590 | kVK_Control = 0x3B, 591 | kVK_RightShift = 0x3C, 592 | kVK_RightOption = 0x3D, 593 | kVK_RightControl = 0x3E, 594 | kVK_Function = 0x3F, 595 | kVK_F17 = 0x40, 596 | kVK_VolumeUp = 0x48, 597 | kVK_VolumeDown = 0x49, 598 | kVK_Mute = 0x4A, 599 | kVK_F18 = 0x4F, 600 | kVK_F19 = 0x50, 601 | kVK_F20 = 0x5A, 602 | kVK_F5 = 0x60, 603 | kVK_F6 = 0x61, 604 | kVK_F7 = 0x62, 605 | kVK_F3 = 0x63, 606 | kVK_F8 = 0x64, 607 | kVK_F9 = 0x65, 608 | kVK_F11 = 0x67, 609 | kVK_F13 = 0x69, 610 | kVK_F16 = 0x6A, 611 | kVK_F14 = 0x6B, 612 | kVK_F10 = 0x6D, 613 | kVK_F12 = 0x6F, 614 | kVK_F15 = 0x71, 615 | kVK_Help = 0x72, 616 | kVK_Home = 0x73, 617 | kVK_PageUp = 0x74, 618 | kVK_ForwardDelete = 0x75, 619 | kVK_F4 = 0x76, 620 | kVK_End = 0x77, 621 | kVK_F2 = 0x78, 622 | kVK_PageDown = 0x79, 623 | kVK_F1 = 0x7A, 624 | kVK_LeftArrow = 0x7B, 625 | kVK_RightArrow = 0x7C, 626 | kVK_DownArrow = 0x7D, 627 | kVK_UpArrow = 0x7E 628 | }; 629 | 630 | /* ISO keyboards only*/ 631 | enum { 632 | kVK_ISO_Section = 0x0A 633 | }; 634 | 635 | /* JIS keyboards only*/ 636 | enum { 637 | kVK_JIS_Yen = 0x5D, 638 | kVK_JIS_Underscore = 0x5E, 639 | kVK_JIS_KeypadComma = 0x5F, 640 | kVK_JIS_Eisu = 0x66, 641 | kVK_JIS_Kana = 0x68 642 | }; 643 | 644 | int getAsciiCodeFromVirtualKeycode(int virtualKeyCode) 645 | { 646 | int keycode = 0xffffffff; 647 | 648 | switch (virtualKeyCode) 649 | { 650 | 651 | case kVK_ANSI_A : {keycode = 'a'; break;} 652 | case kVK_ANSI_B : {keycode = 'b'; break;} 653 | case kVK_ANSI_C : {keycode = 'c'; break;} 654 | case kVK_ANSI_D : {keycode = 'd';break;} 655 | case kVK_ANSI_E : {keycode = 'e'; break;} 656 | case kVK_ANSI_F : {keycode = 'f'; break;} 657 | case kVK_ANSI_G : {keycode = 'g'; break;} 658 | case kVK_ANSI_H : {keycode = 'h'; break;} 659 | case kVK_ANSI_I : {keycode = 'i'; break;} 660 | case kVK_ANSI_J : {keycode = 'j'; break;} 661 | case kVK_ANSI_K : {keycode = 'k'; break;} 662 | case kVK_ANSI_L : {keycode = 'l'; break;} 663 | case kVK_ANSI_M : {keycode = 'm'; break;} 664 | case kVK_ANSI_N : {keycode = 'n'; break;} 665 | case kVK_ANSI_O : {keycode = 'o'; break;} 666 | case kVK_ANSI_P : {keycode = 'p'; break;} 667 | case kVK_ANSI_Q : {keycode = 'q'; break;} 668 | case kVK_ANSI_R : {keycode = 'r'; break;} 669 | case kVK_ANSI_S : {keycode = 's';break;} 670 | case kVK_ANSI_T : {keycode = 't'; break;} 671 | case kVK_ANSI_U : {keycode = 'u'; break;} 672 | case kVK_ANSI_V : {keycode = 'v'; break;} 673 | case kVK_ANSI_W : {keycode = 'w'; break;} 674 | case kVK_ANSI_X : {keycode = 'x'; break;} 675 | case kVK_ANSI_Y : {keycode = 'y'; break;} 676 | case kVK_ANSI_Z : {keycode = 'z'; break;} 677 | 678 | case kVK_ANSI_1 : {keycode = '1'; break;} 679 | case kVK_ANSI_2 : {keycode = '2'; break;} 680 | case kVK_ANSI_3 : {keycode = '3'; break;} 681 | case kVK_ANSI_4 : {keycode = '4'; break;} 682 | case kVK_ANSI_5 : {keycode = '5'; break;} 683 | case kVK_ANSI_6 : {keycode = '6'; break;} 684 | case kVK_ANSI_7 : {keycode = '7'; break;} 685 | case kVK_ANSI_8 : {keycode = '8'; break;} 686 | case kVK_ANSI_9 : {keycode = '9'; break;} 687 | case kVK_ANSI_0 : {keycode = '0'; break;} 688 | case kVK_ANSI_Equal : {keycode = '='; break;} 689 | case kVK_ANSI_Minus : {keycode = '-'; break;} 690 | 691 | case kVK_Tab: {keycode = 9; break;} 692 | case kVK_Space: {keycode=' '; break;} 693 | case kVK_Escape: {keycode=27; break;} 694 | case kVK_Delete: {keycode=8; break;} 695 | case kVK_ForwardDelete: {keycode=B3G_INSERT; break;} 696 | 697 | 698 | case kVK_F1: {keycode = B3G_F1; break;} 699 | case kVK_F2: {keycode = B3G_F2; break;} 700 | case kVK_F3: {keycode = B3G_F3; break;} 701 | case kVK_F4: {keycode = B3G_F4; break;} 702 | case kVK_F5: {keycode = B3G_F5; break;} 703 | case kVK_F6: {keycode = B3G_F6; break;} 704 | case kVK_F7: {keycode = B3G_F7; break;} 705 | case kVK_F8: {keycode = B3G_F8; break;} 706 | case kVK_F9: {keycode = B3G_F9; break;} 707 | case kVK_F10: {keycode = B3G_F10; break;} 708 | case kVK_F11: {keycode = B3G_F11; break;} 709 | case kVK_F12: {keycode = B3G_F12; break;} 710 | case kVK_F13: {keycode = B3G_F13; break;} 711 | case kVK_F14: {keycode = B3G_F14; break;} 712 | case kVK_F15: {keycode = B3G_F15; break;} 713 | 714 | case kVK_LeftArrow: {keycode = B3G_LEFT_ARROW;break;} 715 | case kVK_RightArrow: {keycode = B3G_RIGHT_ARROW;break;} 716 | case kVK_UpArrow: {keycode = B3G_UP_ARROW;break;} 717 | case kVK_DownArrow: {keycode = B3G_DOWN_ARROW;break;} 718 | 719 | case kVK_PageUp :{keycode = B3G_PAGE_UP;break;} 720 | case kVK_PageDown :{keycode = B3G_PAGE_DOWN;break;} 721 | case kVK_End :{keycode = B3G_END;break;} 722 | case kVK_Home :{keycode = B3G_HOME;break;} 723 | case kVK_Control: {keycode = B3G_CONTROL;break;} 724 | case kVK_Option: {keycode = B3G_ALT;break;} 725 | 726 | case kVK_ANSI_RightBracket : {keycode = ']'; break;} 727 | case kVK_ANSI_LeftBracket : {keycode = '['; break;} 728 | case kVK_ANSI_Quote : {keycode = '\''; break;} 729 | case kVK_ANSI_Semicolon : {keycode = ';'; break;} 730 | case kVK_ANSI_Backslash : {keycode = '\\'; break;} 731 | case kVK_ANSI_Comma : {keycode = ','; break;} 732 | case kVK_ANSI_Slash : {keycode = '/'; break;} 733 | case kVK_ANSI_Period : {keycode = '.'; break;} 734 | case kVK_ANSI_Grave : {keycode = '`'; break;} 735 | case kVK_ANSI_KeypadDecimal : {keycode = '.'; break;} 736 | case kVK_ANSI_KeypadMultiply : {keycode = '*'; break;} 737 | case kVK_ANSI_KeypadPlus : {keycode = '+'; break;} 738 | case kVK_ANSI_KeypadClear : {keycode = '?'; break;} 739 | case kVK_ANSI_KeypadDivide : {keycode = '/'; break;} 740 | case kVK_ANSI_KeypadEnter : {keycode = B3G_RETURN; break;} 741 | case kVK_ANSI_KeypadMinus : {keycode = '-'; break;} 742 | case kVK_ANSI_KeypadEquals : {keycode = '='; break;} 743 | case kVK_ANSI_Keypad0 : {keycode = '0'; break;} 744 | case kVK_ANSI_Keypad1 : {keycode = '1'; break;} 745 | case kVK_ANSI_Keypad2 : {keycode = '2'; break;} 746 | case kVK_ANSI_Keypad3 : {keycode = '3'; break;} 747 | case kVK_ANSI_Keypad4 : {keycode = '4'; break;} 748 | case kVK_ANSI_Keypad5 : {keycode = '5'; break;} 749 | case kVK_ANSI_Keypad6 : {keycode = '6'; break;} 750 | case kVK_ANSI_Keypad7 : {keycode = '7'; break;} 751 | case kVK_ANSI_Keypad8 : {keycode = '8'; break;} 752 | case kVK_ANSI_Keypad9 : {keycode = '9'; break;} 753 | case kVK_Return: 754 | { 755 | keycode = B3G_RETURN; break; 756 | } 757 | 758 | default: 759 | { 760 | 761 | printf("unknown keycode\n"); 762 | } 763 | } 764 | return keycode; 765 | } 766 | 767 | 768 | void MacOpenGLWindow::startRendering() 769 | { 770 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 771 | 772 | 773 | GLint err = glGetError(); 774 | assert(err==GL_NO_ERROR); 775 | 776 | 777 | NSEvent *event = nil; 778 | bool handledEvent = false; 779 | 780 | do 781 | { 782 | [pool release]; 783 | pool = [[NSAutoreleasePool alloc] init]; 784 | event = [m_internalData->m_myApp 785 | nextEventMatchingMask:NSAnyEventMask 786 | untilDate:[NSDate distantPast] 787 | inMode:NSDefaultRunLoopMode 788 | // inMode:NSEventTrackingRunLoopMode 789 | dequeue:YES]; 790 | 791 | //NSShiftKeyMask = 1 << 17, 792 | //NSControlKeyMask 793 | 794 | if ([event type] == NSFlagsChanged) 795 | { 796 | int modifiers = [event modifierFlags]; 797 | if (m_keyboardCallback) 798 | { 799 | if ((modifiers & NSShiftKeyMask)) 800 | { 801 | m_keyboardCallback(B3G_SHIFT,1); 802 | m_modifierFlags |= MY_MAC_SHIFTKEY; 803 | }else 804 | { 805 | if (m_modifierFlags& MY_MAC_SHIFTKEY) 806 | { 807 | m_keyboardCallback(B3G_SHIFT,0); 808 | m_modifierFlags &= ~MY_MAC_SHIFTKEY; 809 | } 810 | } 811 | if (modifiers & NSControlKeyMask) 812 | { 813 | m_keyboardCallback(B3G_CONTROL,1); 814 | m_modifierFlags |= MY_MAC_CONTROL_KEY; 815 | } else 816 | { 817 | if (m_modifierFlags&MY_MAC_CONTROL_KEY) 818 | { 819 | m_keyboardCallback(B3G_CONTROL,0); 820 | m_modifierFlags &= ~MY_MAC_CONTROL_KEY; 821 | } 822 | } 823 | if (modifiers & NSAlternateKeyMask) 824 | { 825 | m_keyboardCallback(B3G_ALT,1); 826 | m_modifierFlags |= MY_MAC_ALTKEY; 827 | } else 828 | { 829 | if (m_modifierFlags&MY_MAC_ALTKEY) 830 | { 831 | m_keyboardCallback(B3G_ALT,0); 832 | m_modifierFlags &= ~MY_MAC_ALTKEY; 833 | 834 | } 835 | } 836 | //handle NSCommandKeyMask 837 | 838 | } 839 | } 840 | if ([event type] == NSKeyUp) 841 | { 842 | handledEvent = true; 843 | 844 | uint32 virtualKeycode = [event keyCode]; 845 | 846 | int keycode = getAsciiCodeFromVirtualKeycode(virtualKeycode); 847 | // printf("keycode = %d\n", keycode); 848 | 849 | if (m_keyboardCallback) 850 | { 851 | int state = 0; 852 | m_keyboardCallback(keycode,state); 853 | } 854 | } 855 | if ([event type] == NSKeyDown) 856 | { 857 | handledEvent = true; 858 | 859 | if (![event isARepeat]) 860 | { 861 | uint32 virtualKeycode = [event keyCode]; 862 | 863 | int keycode = getAsciiCodeFromVirtualKeycode(virtualKeycode); 864 | //printf("keycode = %d\n", keycode); 865 | 866 | if (m_keyboardCallback) 867 | { 868 | int state = 1; 869 | m_keyboardCallback(keycode,state); 870 | } 871 | } 872 | } 873 | 874 | 875 | if (([event type]== NSRightMouseDown) || ([ event type]==NSLeftMouseDown)||([event type]==NSOtherMouseDown)) 876 | { 877 | // printf("right mouse!"); 878 | // float mouseX,mouseY; 879 | 880 | NSPoint eventLocation = [event locationInWindow]; 881 | NSPoint center = [m_internalData->m_myview convertPoint:eventLocation fromView:nil]; 882 | m_mouseX = center.x; 883 | m_mouseY = [m_internalData->m_myview GetWindowHeight] - center.y; 884 | int button=0; 885 | switch ([event type]) 886 | { 887 | case NSLeftMouseDown: 888 | { 889 | button=0; 890 | break; 891 | } 892 | case NSOtherMouseDown: 893 | { 894 | button=1; 895 | break; 896 | } 897 | case NSRightMouseDown: 898 | { 899 | button=2; 900 | break; 901 | } 902 | default: 903 | { 904 | 905 | } 906 | }; 907 | // printf("mouse coord = %f, %f\n",mouseX,mouseY); 908 | if (m_mouseButtonCallback) 909 | { 910 | //handledEvent = true; 911 | (*m_mouseButtonCallback)(button,1,m_mouseX,m_mouseY); 912 | } 913 | } 914 | 915 | 916 | if (([event type]== NSRightMouseUp) || ([ event type]==NSLeftMouseUp)||([event type]==NSOtherMouseUp)) 917 | { 918 | // printf("right mouse!"); 919 | // float mouseX,mouseY; 920 | 921 | NSPoint eventLocation = [event locationInWindow]; 922 | NSPoint center = [m_internalData->m_myview convertPoint:eventLocation fromView:nil]; 923 | m_mouseX = center.x; 924 | m_mouseY = [m_internalData->m_myview GetWindowHeight] - center.y; 925 | 926 | int button=0; 927 | switch ([event type]) 928 | { 929 | case NSLeftMouseUp: 930 | { 931 | button=0; 932 | break; 933 | } 934 | case NSOtherMouseUp: 935 | { 936 | button=1; 937 | break; 938 | } 939 | case NSRightMouseUp: 940 | { 941 | button=2; 942 | break; 943 | } 944 | default: 945 | { 946 | 947 | } 948 | }; 949 | 950 | // printf("mouse coord = %f, %f\n",mouseX,mouseY); 951 | if (m_mouseButtonCallback) 952 | (*m_mouseButtonCallback)(button,0,m_mouseX,m_mouseY); 953 | 954 | } 955 | 956 | 957 | if ([event type] == NSMouseMoved) 958 | { 959 | 960 | // http://stackoverflow.com/questions/4630509/how-to-find-if-the-mouse-is-over-a-view 961 | NSPoint globalLocation = [ NSEvent mouseLocation ]; 962 | NSPoint windowLocation = [ [m_internalData->m_myview window] convertScreenToBase:globalLocation ]; 963 | NSPoint viewLocation = [ m_internalData->m_myview convertPoint:windowLocation fromView: nil ]; 964 | //printf("global = %f, %f\n", globalLocation.x, globalLocation.y); 965 | //printf("window = %f, %f\n", windowLocation.x, windowLocation.y); 966 | //printf("view = %f, %f\n", viewLocation.x, viewLocation.y); 967 | 968 | //NSPoint eventLocation = [event locationInWindow]; 969 | //NSPoint center = [m_internalData->m_myview convertPoint:eventLocation fromView:nil]; 970 | NSPoint center = viewLocation; 971 | m_mouseX = center.x; 972 | m_mouseY = [m_internalData->m_myview GetWindowHeight] - center.y; 973 | 974 | // printf("mouse coord = %f, %f\n",m_mouseX,m_mouseY); 975 | if (m_mouseMoveCallback) 976 | { 977 | //handledEvent = true; 978 | (*m_mouseMoveCallback)(m_mouseX,m_mouseY); 979 | } 980 | } 981 | 982 | if (([event type] == NSLeftMouseDragged) || ([event type] == NSRightMouseDragged) || ([event type] == NSOtherMouseDragged)) 983 | { 984 | int dx1, dy1; 985 | CGGetLastMouseDelta (&dx1, &dy1); 986 | 987 | NSPoint eventLocation = [event locationInWindow]; 988 | NSPoint center = [m_internalData->m_myview convertPoint:eventLocation fromView:nil]; 989 | m_mouseX = center.x; 990 | m_mouseY = [m_internalData->m_myview GetWindowHeight] - center.y; 991 | 992 | if (m_mouseMoveCallback) 993 | { 994 | //handledEvent = true; 995 | (*m_mouseMoveCallback)(m_mouseX,m_mouseY); 996 | } 997 | 998 | // printf("mouse coord = %f, %f\n",m_mouseX,m_mouseY); 999 | } 1000 | 1001 | if ([event type] == NSScrollWheel) 1002 | { 1003 | float dy, dx; 1004 | dy = [ event deltaY ]; 1005 | dx = [ event deltaX ]; 1006 | 1007 | if (m_wheelCallback) 1008 | { 1009 | handledEvent = true; 1010 | (*m_wheelCallback)(dx,dy); 1011 | } 1012 | // m_cameraDistance -= dy*0.1; 1013 | // m_azi -= dx*0.1; 1014 | 1015 | } 1016 | 1017 | if (!handledEvent) 1018 | [m_internalData->m_myApp sendEvent:event]; 1019 | 1020 | [m_internalData->m_myApp updateWindows]; 1021 | } while (event); 1022 | 1023 | err = glGetError(); 1024 | assert(err==GL_NO_ERROR); 1025 | 1026 | [m_internalData->m_myview MakeCurrent]; 1027 | err = glGetError(); 1028 | assert(err==GL_NO_ERROR); 1029 | 1030 | 1031 | // glClearColor(1,1,1,1); 1032 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //clear buffers 1033 | 1034 | err = glGetError(); 1035 | assert(err==GL_NO_ERROR); 1036 | 1037 | //glCullFace(GL_BACK); 1038 | //glFrontFace(GL_CCW); 1039 | glEnable(GL_DEPTH_TEST); 1040 | err = glGetError(); 1041 | assert(err==GL_NO_ERROR); 1042 | 1043 | float aspect; 1044 | //b3Vector3 extents; 1045 | 1046 | if (m_internalData->m_width > m_internalData->m_height) 1047 | { 1048 | aspect = (float)m_internalData->m_width / (float)m_internalData->m_height; 1049 | //extents.setValue(aspect * 1.0f, 1.0f,0); 1050 | } else 1051 | { 1052 | aspect = (float)m_internalData->m_height / (float)m_internalData->m_width; 1053 | //extents.setValue(1.0f, aspect*1.f,0); 1054 | } 1055 | 1056 | err = glGetError(); 1057 | assert(err==GL_NO_ERROR); 1058 | [pool release]; 1059 | 1060 | } 1061 | 1062 | void MacOpenGLWindow::endRendering() 1063 | { 1064 | [m_internalData->m_myview MakeCurrent]; 1065 | //#ifndef NO_OPENGL3 1066 | // glSwapAPPLE(); 1067 | //#else 1068 | [[m_internalData->m_myview getContext] flushBuffer]; 1069 | // #endif 1070 | 1071 | } 1072 | 1073 | bool MacOpenGLWindow::requestedExit() const 1074 | { 1075 | bool closeme = m_internalData->m_myview.GetRequestClose; 1076 | return m_internalData->m_exitRequested || closeme; 1077 | } 1078 | 1079 | void MacOpenGLWindow::setRequestExit() 1080 | { 1081 | m_internalData->m_exitRequested = true; 1082 | } 1083 | 1084 | #include 1085 | int MacOpenGLWindow::fileOpenDialog(char* filename, int maxNameLength) 1086 | { 1087 | //save/restore the OpenGL context, NSOpenPanel can mess it up 1088 | //http://stackoverflow.com/questions/13987148/nsopenpanel-breaks-my-sdl-opengl-app 1089 | 1090 | NSOpenGLContext *foo = [NSOpenGLContext currentContext]; 1091 | // get the url of a .txt file 1092 | NSOpenPanel * zOpenPanel = [NSOpenPanel openPanel]; 1093 | NSArray * zAryOfExtensions = [NSArray arrayWithObjects:@"urdf",@"bullet",@"obj",@"sdf",nil]; 1094 | [zOpenPanel setAllowedFileTypes:zAryOfExtensions]; 1095 | NSInteger zIntResult = [zOpenPanel runModal]; 1096 | 1097 | [foo makeCurrentContext]; 1098 | 1099 | if (zIntResult == NSFileHandlingPanelCancelButton) { 1100 | NSLog(@"readUsingOpenPanel cancelled"); 1101 | return 0; 1102 | } 1103 | NSURL *zUrl = [zOpenPanel URL]; 1104 | if (zUrl) 1105 | { 1106 | //without the file:// 1107 | NSString *myString = [zUrl absoluteString]; 1108 | int slen = [myString length]; 1109 | if (slen < maxNameLength) 1110 | { 1111 | const char *cfilename=[myString UTF8String]; 1112 | //expect file:// at start of URL 1113 | const char* p = strstr(cfilename, "file://"); 1114 | if (p==cfilename) 1115 | { 1116 | int actualLen = strlen(cfilename)-7; 1117 | memcpy(filename, cfilename+7,actualLen); 1118 | filename[actualLen]=0; 1119 | return actualLen; 1120 | } 1121 | } 1122 | } 1123 | 1124 | return 0; 1125 | } 1126 | 1127 | 1128 | 1129 | void MacOpenGLWindow::getMouseCoordinates(int& x, int& y) 1130 | { 1131 | 1132 | NSPoint pt = [m_internalData->m_window mouseLocationOutsideOfEventStream]; 1133 | m_mouseX = pt.x; 1134 | m_mouseY = pt.y; 1135 | 1136 | x = m_mouseX; 1137 | //our convention is x,y is upper left hand side 1138 | y = [m_internalData->m_myview GetWindowHeight]-m_mouseY; 1139 | 1140 | 1141 | } 1142 | 1143 | int MacOpenGLWindow::getWidth() const 1144 | { 1145 | if (m_internalData && m_internalData->m_myview && m_internalData->m_myview.GetWindowWidth) 1146 | return m_internalData->m_myview.GetWindowWidth; 1147 | return 0; 1148 | } 1149 | 1150 | int MacOpenGLWindow::getHeight() const 1151 | { 1152 | if (m_internalData && m_internalData->m_myview && m_internalData->m_myview.GetWindowHeight) 1153 | return m_internalData->m_myview.GetWindowHeight; 1154 | return 0; 1155 | } 1156 | 1157 | 1158 | void MacOpenGLWindow::setResizeCallback(b3ResizeCallback resizeCallback) 1159 | { 1160 | [m_internalData->m_myview setResizeCallback:resizeCallback]; 1161 | if (resizeCallback) 1162 | { 1163 | (resizeCallback)(m_internalData->m_width,m_internalData->m_height); 1164 | } 1165 | } 1166 | 1167 | b3ResizeCallback MacOpenGLWindow::getResizeCallback() 1168 | { 1169 | return [m_internalData->m_myview getResizeCallback]; 1170 | } 1171 | 1172 | -------------------------------------------------------------------------------- /example/OpenGLWindow/OpenGL2Include.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012 Advanced Micro Devices, Inc. 3 | 4 | This software is provided 'as-is', without any express or implied warranty. 5 | In no event will the authors be held liable for any damages arising from the use of this software. 6 | Permission is granted to anyone to use this software for any purpose, 7 | including commercial applications, and to alter it and redistribute it freely, 8 | subject to the following restrictions: 9 | 10 | 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. 11 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 12 | 3. This notice may not be removed or altered from any source distribution. 13 | */ 14 | //Originally written by Erwin Coumans 15 | 16 | 17 | #ifndef __OPENGL_INCLUDE_H 18 | #define __OPENGL_INCLUDE_H 19 | 20 | 21 | //think different 22 | #if defined(__APPLE__) && !defined (VMDMESA) 23 | #include 24 | #include 25 | #else 26 | 27 | #ifdef GLEW_STATIC 28 | #include "CustomGL/glew.h" 29 | #else 30 | #include 31 | #endif//GLEW_STATIC 32 | 33 | #ifdef _WINDOWS 34 | #include 35 | //#include 36 | //#include 37 | #else 38 | //#include 39 | //#include 40 | #endif //_WINDOWS 41 | #endif //APPLE 42 | 43 | //disable glGetError 44 | //#undef glGetError 45 | //#define glGetError MyGetError 46 | // 47 | //GLenum inline MyGetError() 48 | //{ 49 | // return 0; 50 | //} 51 | 52 | ///on Linux only glDrawElementsInstancedARB is defined?!? 53 | //#ifdef __linux 54 | //#define glDrawElementsInstanced glDrawElementsInstancedARB 55 | // 56 | //#endif //__linux 57 | 58 | #endif //__OPENGL_INCLUDE_H 59 | 60 | -------------------------------------------------------------------------------- /example/OpenGLWindow/OpenGLInclude.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012 Advanced Micro Devices, Inc. 3 | 4 | This software is provided 'as-is', without any express or implied warranty. 5 | In no event will the authors be held liable for any damages arising from the use of this software. 6 | Permission is granted to anyone to use this software for any purpose, 7 | including commercial applications, and to alter it and redistribute it freely, 8 | subject to the following restrictions: 9 | 10 | 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. 11 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 12 | 3. This notice may not be removed or altered from any source distribution. 13 | */ 14 | //Originally written by Erwin Coumans 15 | 16 | 17 | #ifndef __OPENGL_INCLUDE_H 18 | #define __OPENGL_INCLUDE_H 19 | 20 | 21 | //think different 22 | #if defined(__APPLE__) && !defined (VMDMESA) 23 | #include 24 | //#include 25 | //#include 26 | //#import 27 | #if defined (USE_OPENGL2) || defined (NO_OPENGL3) 28 | #include 29 | #else 30 | #include 31 | #endif 32 | #else 33 | 34 | #ifdef GLEW_STATIC 35 | #include "CustomGL/glew.h" 36 | #else 37 | #include 38 | #endif //GLEW_STATIC 39 | 40 | #ifdef _WINDOWS 41 | #include 42 | //#include 43 | //#include 44 | #else 45 | //#include 46 | //#include 47 | #endif //_WINDOWS 48 | #endif //APPLE 49 | 50 | //disable glGetError 51 | //#undef glGetError 52 | //#define glGetError MyGetError 53 | // 54 | //GLenum inline MyGetError() 55 | //{ 56 | // return 0; 57 | //} 58 | 59 | ///on Linux only glDrawElementsInstancedARB is defined?!? 60 | //#ifdef __linux 61 | //#define glDrawElementsInstanced glDrawElementsInstancedARB 62 | // 63 | //#endif //__linux 64 | 65 | #endif //__OPENGL_INCLUDE_H 66 | 67 | -------------------------------------------------------------------------------- /example/OpenGLWindow/Win32InternalWindowData.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef WIN32_INTERNAL_WINDOW_DATA_H 3 | #define WIN32_INTERNAL_WINDOW_DATA_H 4 | 5 | #include 6 | 7 | 8 | struct InternalData2 9 | { 10 | HWND m_hWnd;; 11 | int m_fullWindowWidth;//includes borders etc 12 | int m_fullWindowHeight; 13 | 14 | int m_openglViewportWidth;//just the 3d viewport/client area 15 | int m_openglViewportHeight; 16 | 17 | HDC m_hDC; 18 | HGLRC m_hRC; 19 | bool m_OpenGLInitialized; 20 | int m_oldScreenWidth; 21 | int m_oldHeight; 22 | int m_oldBitsPerPel; 23 | bool m_quit; 24 | int m_mouseLButton; 25 | int m_mouseRButton; 26 | int m_mouseMButton; 27 | int m_mouseXpos; 28 | int m_mouseYpos; 29 | 30 | int m_internalKeyModifierFlags; 31 | 32 | b3WheelCallback m_wheelCallback; 33 | b3MouseMoveCallback m_mouseMoveCallback; 34 | b3MouseButtonCallback m_mouseButtonCallback; 35 | b3ResizeCallback m_resizeCallback; 36 | b3KeyboardCallback m_keyboardCallback; 37 | 38 | 39 | 40 | InternalData2() 41 | { 42 | m_hWnd = 0; 43 | m_mouseLButton=0; 44 | m_mouseRButton=0; 45 | m_mouseMButton=0; 46 | m_internalKeyModifierFlags = 0; 47 | m_fullWindowWidth = 0; 48 | m_fullWindowHeight= 0; 49 | m_openglViewportHeight=0; 50 | m_openglViewportWidth=0; 51 | m_hDC = 0; 52 | m_hRC = 0; 53 | m_OpenGLInitialized = false; 54 | m_oldScreenWidth = 0; 55 | m_oldHeight = 0; 56 | m_oldBitsPerPel = 0; 57 | m_quit = false; 58 | 59 | m_keyboardCallback = 0; 60 | m_mouseMoveCallback = 0; 61 | m_mouseButtonCallback = 0; 62 | m_resizeCallback = 0; 63 | m_wheelCallback = 0; 64 | 65 | } 66 | }; 67 | 68 | #endif //WIN32_INTERNAL_WINDOW_DATA_H -------------------------------------------------------------------------------- /example/OpenGLWindow/Win32OpenGLWindow.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | /* 3 | Copyright (c) 2012 Advanced Micro Devices, Inc. 4 | 5 | This software is provided 'as-is', without any express or implied warranty. 6 | In no event will the authors be held liable for any damages arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it freely, 9 | subject to the following restrictions: 10 | 11 | 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. 12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 13 | 3. This notice may not be removed or altered from any source distribution. 14 | */ 15 | //Originally written by Erwin Coumans 16 | 17 | 18 | #include "Win32OpenGLWindow.h" 19 | 20 | #include "OpenGLInclude.h" 21 | 22 | //#include "Bullet3Common/b3Vector3.h" 23 | 24 | #include "Win32InternalWindowData.h" 25 | #include 26 | 27 | static void printGLString(const char *name, GLenum s) { 28 | const char *v = (const char *) glGetString(s); 29 | printf("%s = %s\n",name, v); 30 | } 31 | 32 | bool sOpenGLVerbose = true; 33 | 34 | void Win32OpenGLWindow::enableOpenGL() 35 | { 36 | 37 | PIXELFORMATDESCRIPTOR pfd; 38 | int format; 39 | 40 | // get the device context (DC) 41 | m_data->m_hDC = GetDC( m_data->m_hWnd ); 42 | 43 | // set the pixel format for the DC 44 | ZeroMemory( &pfd, sizeof( pfd ) ); 45 | pfd.nSize = sizeof( pfd ); 46 | pfd.nVersion = 1; 47 | pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; 48 | pfd.iPixelType = PFD_TYPE_RGBA; 49 | pfd.cColorBits = 32; 50 | pfd.cRedBits = 8; 51 | pfd.cGreenBits = 8; 52 | pfd.cBlueBits = 8; 53 | pfd.cAlphaBits = 8; 54 | 55 | pfd.cDepthBits = 24; 56 | pfd.cStencilBits = 8;//1; 57 | pfd.iLayerType = PFD_MAIN_PLANE; 58 | format = ChoosePixelFormat( m_data->m_hDC, &pfd ); 59 | SetPixelFormat( m_data->m_hDC, format, &pfd ); 60 | 61 | // create and enable the render context (RC) 62 | m_data->m_hRC = wglCreateContext( m_data->m_hDC ); 63 | wglMakeCurrent( m_data->m_hDC, m_data->m_hRC ); 64 | 65 | if (sOpenGLVerbose) 66 | { 67 | printGLString("Version", GL_VERSION); 68 | printGLString("Vendor", GL_VENDOR); 69 | printGLString("Renderer", GL_RENDERER); 70 | } 71 | //printGLString("Extensions", GL_EXTENSIONS); 72 | 73 | } 74 | 75 | 76 | 77 | void Win32OpenGLWindow::disableOpenGL() 78 | { 79 | wglMakeCurrent( NULL, NULL ); 80 | wglDeleteContext( m_data->m_hRC ); 81 | // ReleaseDC( m_data->m_hWnd, m_data->m_hDC ); 82 | 83 | } 84 | 85 | 86 | 87 | 88 | 89 | void Win32OpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) 90 | { 91 | Win32Window::createWindow(ci); 92 | 93 | //VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, this); 94 | enableOpenGL(); 95 | 96 | } 97 | 98 | 99 | 100 | 101 | Win32OpenGLWindow::Win32OpenGLWindow() 102 | { 103 | 104 | 105 | } 106 | 107 | Win32OpenGLWindow::~Win32OpenGLWindow() 108 | { 109 | 110 | } 111 | 112 | 113 | void Win32OpenGLWindow::closeWindow() 114 | { 115 | disableOpenGL(); 116 | 117 | Win32Window::closeWindow(); 118 | } 119 | 120 | 121 | 122 | void Win32OpenGLWindow::startRendering() 123 | { 124 | pumpMessage(); 125 | //don't clear all 3 buffers because some AMD drivers are buggy 126 | //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); 127 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 128 | 129 | 130 | //glCullFace(GL_BACK); 131 | //glFrontFace(GL_CCW); 132 | glEnable(GL_DEPTH_TEST); 133 | 134 | } 135 | 136 | 137 | void Win32OpenGLWindow::renderAllObjects() 138 | { 139 | } 140 | 141 | void Win32OpenGLWindow::endRendering() 142 | { 143 | SwapBuffers( m_data->m_hDC ); 144 | 145 | } 146 | 147 | int Win32OpenGLWindow::fileOpenDialog(char* fileName, int maxFileNameLength) 148 | { 149 | //wchar_t wideChars[1024]; 150 | 151 | OPENFILENAME ofn ; 152 | ZeroMemory( &ofn , sizeof( ofn)); 153 | ofn.lStructSize = sizeof ( ofn ); 154 | ofn.hwndOwner = NULL ; 155 | 156 | #ifdef UNICODE 157 | WCHAR bla[1024]; 158 | ofn.lpstrFile = bla; 159 | ofn.lpstrFile[0] = '\0'; 160 | ofn.nMaxFile = 1023; 161 | ofn.lpstrFilter = L"All Files\0*.*\0URDF\0*.urdf\0.bullet\0*.bullet\0"; 162 | #else 163 | ofn.lpstrFile = fileName; 164 | ofn.lpstrFile[0] = '\0'; 165 | ofn.nMaxFile = 1023; 166 | //ofn.lpstrFilter = "All\0*.*\0Text\0*.TXT\0"; 167 | ofn.lpstrFilter = "All Files\0*.*\0URDF\0*.urdf\0.bullet\0*.bullet\0"; 168 | 169 | #endif 170 | 171 | ofn.nFilterIndex =1; 172 | ofn.lpstrFileTitle = NULL ; 173 | ofn.nMaxFileTitle = 0 ; 174 | ofn.lpstrInitialDir=NULL ; 175 | ofn.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST ; 176 | GetOpenFileName( &ofn ); 177 | return strlen(fileName); 178 | 179 | 180 | //return 0; 181 | } 182 | 183 | int Win32OpenGLWindow::getWidth() const 184 | { 185 | if (m_data) 186 | return m_data->m_openglViewportWidth; 187 | return 0; 188 | } 189 | 190 | int Win32OpenGLWindow::getHeight() const 191 | { 192 | if (m_data) 193 | return m_data->m_openglViewportHeight; 194 | return 0; 195 | } 196 | 197 | 198 | #endif 199 | 200 | 201 | -------------------------------------------------------------------------------- /example/OpenGLWindow/Win32OpenGLWindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012 Advanced Micro Devices, Inc. 3 | 4 | This software is provided 'as-is', without any express or implied warranty. 5 | In no event will the authors be held liable for any damages arising from the use of this software. 6 | Permission is granted to anyone to use this software for any purpose, 7 | including commercial applications, and to alter it and redistribute it freely, 8 | subject to the following restrictions: 9 | 10 | 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. 11 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 12 | 3. This notice may not be removed or altered from any source distribution. 13 | */ 14 | //Originally written by Erwin Coumans 15 | 16 | 17 | #ifndef _WIN32_OPENGL_RENDER_MANAGER_H 18 | #define _WIN32_OPENGL_RENDER_MANAGER_H 19 | 20 | 21 | 22 | #include "Win32Window.h" 23 | 24 | #define b3gDefaultOpenGLWindow Win32OpenGLWindow 25 | 26 | class Win32OpenGLWindow : public Win32Window 27 | { 28 | bool m_OpenGLInitialized; 29 | 30 | protected: 31 | 32 | 33 | void enableOpenGL(); 34 | 35 | void disableOpenGL(); 36 | 37 | public: 38 | 39 | Win32OpenGLWindow(); 40 | 41 | virtual ~Win32OpenGLWindow(); 42 | 43 | virtual void createWindow(const b3gWindowConstructionInfo& ci); 44 | 45 | virtual void closeWindow(); 46 | 47 | virtual void startRendering(); 48 | 49 | virtual void renderAllObjects(); 50 | 51 | virtual void endRendering(); 52 | 53 | virtual float getRetinaScale() const {return 1.f;} 54 | virtual void setAllowRetina(bool /*allowRetina*/) {}; 55 | 56 | virtual int getWidth() const; 57 | virtual int getHeight() const; 58 | 59 | virtual int fileOpenDialog(char* fileName, int maxFileNameLength); 60 | }; 61 | 62 | 63 | 64 | #endif //_WIN32_OPENGL_RENDER_MANAGER_H 65 | -------------------------------------------------------------------------------- /example/OpenGLWindow/Win32Window.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | /* 3 | Copyright (c) 2012 Advanced Micro Devices, Inc. 4 | 5 | This software is provided 'as-is', without any express or implied warranty. 6 | In no event will the authors be held liable for any damages arising from the use of this software. 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it freely, 9 | subject to the following restrictions: 10 | 11 | 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. 12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 13 | 3. This notice may not be removed or altered from any source distribution. 14 | */ 15 | //Originally written by Erwin Coumans 16 | 17 | 18 | #include "Win32Window.h" 19 | 20 | #include "OpenGLInclude.h" 21 | 22 | #include 23 | static InternalData2* sData = 0; 24 | 25 | #include "Win32InternalWindowData.h" 26 | 27 | 28 | enum 29 | { 30 | INTERNAL_SHIFT_MODIFIER=1, 31 | INTERNAL_ALT_MODIFIER=2, 32 | INTERNAL_CONTROL_MODIFIER=4, 33 | INTERNAL_TAB_MODIFIER=8, 34 | }; 35 | 36 | void Win32Window::pumpMessage() 37 | { 38 | MSG msg; 39 | // check for messages 40 | //'if' instead of 'while' can make mainloop smoother. 41 | //@todo: use separate threads for input and rendering 42 | while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) 43 | { 44 | 45 | // handle or dispatch messages 46 | if ( msg.message == WM_QUIT ) 47 | { 48 | m_data->m_quit = TRUE; 49 | } 50 | else 51 | { 52 | TranslateMessage( &msg ); 53 | DispatchMessage( &msg ); 54 | } 55 | 56 | // gDemoApplication->displayCallback(); 57 | 58 | 59 | }; 60 | } 61 | 62 | int getSpecialKeyFromVirtualKeycode(int virtualKeyCode) 63 | { 64 | int keycode = -1; 65 | if (virtualKeyCode >= 'A' && virtualKeyCode <= 'Z') 66 | { 67 | return virtualKeyCode+32;//todo: fix the ascii A vs a input 68 | } 69 | 70 | switch (virtualKeyCode) 71 | { 72 | case VK_RETURN: {keycode = B3G_RETURN; break; }; 73 | case VK_F1: {keycode = B3G_F1; break;} 74 | case VK_F2: {keycode = B3G_F2; break;} 75 | case VK_F3: {keycode = B3G_F3; break;} 76 | case VK_F4: {keycode = B3G_F4; break;} 77 | case VK_F5: {keycode = B3G_F5; break;} 78 | case VK_F6: {keycode = B3G_F6; break;} 79 | case VK_F7: {keycode = B3G_F7; break;} 80 | case VK_F8: {keycode = B3G_F8; break;} 81 | case VK_F9: {keycode = B3G_F9; break;} 82 | case VK_F10: {keycode= B3G_F10; break;} 83 | 84 | //case VK_SPACE: {keycode= ' '; break;} 85 | 86 | case VK_NEXT: {keycode= B3G_PAGE_DOWN; break;} 87 | case VK_PRIOR: {keycode= B3G_PAGE_UP; break;} 88 | 89 | case VK_INSERT: {keycode= B3G_INSERT; break;} 90 | case VK_BACK: {keycode= B3G_BACKSPACE; break;} 91 | case VK_DELETE: {keycode= B3G_DELETE; break;} 92 | 93 | case VK_END:{keycode= B3G_END; break;} 94 | case VK_HOME:{keycode= B3G_HOME; break;} 95 | case VK_LEFT:{keycode= B3G_LEFT_ARROW; break;} 96 | case VK_UP:{keycode= B3G_UP_ARROW; break;} 97 | case VK_RIGHT:{keycode= B3G_RIGHT_ARROW; break;} 98 | case VK_DOWN:{keycode= B3G_DOWN_ARROW; break;} 99 | case VK_SHIFT:{keycode=B3G_SHIFT;break;} 100 | case VK_TAB:{keycode=9;break;} 101 | case VK_MENU:{keycode=B3G_ALT;break;} 102 | case VK_CONTROL:{keycode=B3G_CONTROL;break;} 103 | default: 104 | { 105 | //keycode = MapVirtualKey( virtualKeyCode, MAPVK_VK_TO_CHAR ) & 0x0000FFFF; 106 | } 107 | }; 108 | 109 | return keycode; 110 | } 111 | 112 | 113 | int getAsciiCodeFromVirtualKeycode(int virtualKeyCode) 114 | { 115 | int keycode = 0xffffffff; 116 | 117 | if (virtualKeyCode >= 'a' && virtualKeyCode <= 'z') 118 | { 119 | return virtualKeyCode; 120 | } 121 | 122 | if (virtualKeyCode >= 'A' && virtualKeyCode <= 'Z') 123 | { 124 | return virtualKeyCode+32;//todo: fix the ascii A vs a input 125 | } 126 | 127 | return keycode; 128 | } 129 | 130 | bool Win32Window::isModifierKeyPressed(int key) 131 | { 132 | bool isPressed = false; 133 | 134 | switch (key) 135 | { 136 | case B3G_ALT: 137 | { 138 | isPressed = ((sData->m_internalKeyModifierFlags&INTERNAL_ALT_MODIFIER)!=0); 139 | break; 140 | }; 141 | case B3G_SHIFT: 142 | { 143 | isPressed = ((sData->m_internalKeyModifierFlags&INTERNAL_SHIFT_MODIFIER)!=0); 144 | break; 145 | }; 146 | case B3G_CONTROL: 147 | { 148 | isPressed = ((sData->m_internalKeyModifierFlags&INTERNAL_CONTROL_MODIFIER)!=0); 149 | break; 150 | }; 151 | case 9: // tab 152 | { 153 | isPressed = ((sData->m_internalKeyModifierFlags&INTERNAL_TAB_MODIFIER)!=0); 154 | break; 155 | }; 156 | 157 | default: 158 | { 159 | } 160 | }; 161 | return isPressed;//m_internalKeyModifierFlags 162 | } 163 | 164 | 165 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 166 | { 167 | //printf("msg = %d\n", message); 168 | switch (message) 169 | { 170 | 171 | case WM_PAINT: 172 | { 173 | PAINTSTRUCT ps; 174 | BeginPaint(hWnd, &ps); 175 | EndPaint(hWnd, &ps); 176 | } 177 | return 1; 178 | 179 | case WM_ERASEBKGND: 180 | return 1; 181 | 182 | case WM_CLOSE: 183 | if (sData) 184 | sData->m_quit = true; 185 | //PostQuitMessage(0); 186 | return 1; 187 | 188 | case WM_DESTROY: 189 | if (sData) 190 | sData->m_quit = true; 191 | //PostQuitMessage(0); 192 | return 1; 193 | 194 | case WM_SYSKEYUP: 195 | case WM_KEYUP: 196 | { 197 | 198 | int keycode = getSpecialKeyFromVirtualKeycode(wParam); 199 | switch (keycode) 200 | { 201 | case B3G_ALT: 202 | { 203 | sData->m_internalKeyModifierFlags&=~INTERNAL_ALT_MODIFIER; 204 | break; 205 | }; 206 | case B3G_SHIFT: 207 | { 208 | sData->m_internalKeyModifierFlags &= ~INTERNAL_SHIFT_MODIFIER; 209 | break; 210 | }; 211 | case B3G_CONTROL: 212 | { 213 | sData->m_internalKeyModifierFlags &=~INTERNAL_CONTROL_MODIFIER; 214 | break; 215 | }; 216 | case 9: // tab 217 | { 218 | sData->m_internalKeyModifierFlags &=~INTERNAL_TAB_MODIFIER; 219 | break; 220 | }; 221 | } 222 | 223 | if (keycode>=0 && sData && sData->m_keyboardCallback ) 224 | { 225 | int state=0; 226 | (*sData->m_keyboardCallback)(keycode,state); 227 | } 228 | return 0; 229 | } 230 | case WM_CHAR: 231 | { 232 | //skip 'enter' key, it is processed in WM_KEYUP/WM_KEYDOWN 233 | int keycode = getAsciiCodeFromVirtualKeycode(wParam); 234 | if (keycode < 0) 235 | { 236 | if (sData && sData->m_keyboardCallback && ((HIWORD(lParam) & KF_REPEAT) == 0)) 237 | { 238 | int state = 1; 239 | (*sData->m_keyboardCallback)(wParam, state); 240 | } 241 | } 242 | return 0; 243 | } 244 | case WM_SYSKEYDOWN: 245 | case WM_KEYDOWN: 246 | { 247 | int keycode = getSpecialKeyFromVirtualKeycode(wParam); 248 | switch (keycode) 249 | { 250 | case B3G_ALT: 251 | { 252 | sData->m_internalKeyModifierFlags|=INTERNAL_ALT_MODIFIER; 253 | break; 254 | }; 255 | case B3G_SHIFT: 256 | { 257 | sData->m_internalKeyModifierFlags |= INTERNAL_SHIFT_MODIFIER; 258 | break; 259 | }; 260 | case B3G_CONTROL: 261 | { 262 | sData->m_internalKeyModifierFlags |=INTERNAL_CONTROL_MODIFIER; 263 | break; 264 | }; 265 | case 9: // tab 266 | { 267 | sData->m_internalKeyModifierFlags |=INTERNAL_TAB_MODIFIER; 268 | break; 269 | }; 270 | } 271 | if (keycode>=0 && sData && sData->m_keyboardCallback)// && ((HIWORD(lParam) & KF_REPEAT) == 0)) 272 | { 273 | int state = 1; 274 | (*sData->m_keyboardCallback)(keycode,state); 275 | return 1; 276 | } 277 | return 0; 278 | } 279 | 280 | case WM_MBUTTONUP: 281 | { 282 | int xPos = LOWORD(lParam); 283 | int yPos = HIWORD(lParam); 284 | if (sData) 285 | { 286 | sData->m_mouseMButton=0; 287 | sData->m_mouseXpos = xPos; 288 | sData->m_mouseYpos = yPos; 289 | if (sData && sData->m_mouseButtonCallback) 290 | (*sData->m_mouseButtonCallback)(1,0,xPos,yPos); 291 | } 292 | break; 293 | } 294 | case WM_MBUTTONDOWN: 295 | { 296 | int xPos = LOWORD(lParam); 297 | int yPos = HIWORD(lParam); 298 | if (sData) 299 | { 300 | sData->m_mouseMButton=1; 301 | sData->m_mouseXpos = xPos; 302 | sData->m_mouseYpos = yPos; 303 | if (sData && sData->m_mouseButtonCallback) 304 | (*sData->m_mouseButtonCallback)(1,1,xPos,yPos); 305 | } 306 | break; 307 | } 308 | 309 | case WM_LBUTTONUP: 310 | { 311 | int xPos = LOWORD(lParam); 312 | int yPos = HIWORD(lParam); 313 | if (sData) 314 | { 315 | sData->m_mouseLButton=0; 316 | sData->m_mouseXpos = xPos; 317 | sData->m_mouseYpos = yPos; 318 | 319 | if (sData && sData->m_mouseButtonCallback) 320 | (*sData->m_mouseButtonCallback)(0,0,xPos,yPos); 321 | 322 | } 323 | // gDemoApplication->mouseFunc(0,1,xPos,yPos); 324 | break; 325 | } 326 | case WM_LBUTTONDOWN: 327 | { 328 | int xPos = LOWORD(lParam); 329 | int yPos = HIWORD(lParam); 330 | if (sData) 331 | { 332 | sData->m_mouseLButton=1; 333 | sData->m_mouseXpos = xPos; 334 | sData->m_mouseYpos = yPos; 335 | 336 | if (sData && sData->m_mouseButtonCallback) 337 | (*sData->m_mouseButtonCallback)(0,1,xPos,yPos); 338 | } 339 | break; 340 | } 341 | 342 | case 0x020e://WM_MOUSEWHEEL_LEFT_RIGHT 343 | { 344 | 345 | int zDelta = (short)HIWORD(wParam); 346 | int xPos = LOWORD(lParam); 347 | int yPos = HIWORD(lParam); 348 | //m_cameraDistance -= zDelta*0.01; 349 | if (sData && sData->m_wheelCallback) 350 | (*sData->m_wheelCallback)(-float(zDelta)*0.05f,0); 351 | return 1; 352 | break; 353 | } 354 | case 0x020A://WM_MOUSEWHEEL: 355 | { 356 | 357 | int zDelta = (short)HIWORD(wParam); 358 | int xPos = LOWORD(lParam); 359 | int yPos = HIWORD(lParam); 360 | //m_cameraDistance -= zDelta*0.01; 361 | if (sData && sData->m_wheelCallback) 362 | (*sData->m_wheelCallback)(0,float(zDelta)*0.05f); 363 | return 1; 364 | break; 365 | } 366 | 367 | case WM_MOUSEMOVE: 368 | { 369 | int xPos = LOWORD(lParam); 370 | int yPos = HIWORD(lParam); 371 | sData->m_mouseXpos = xPos; 372 | sData->m_mouseYpos = yPos; 373 | 374 | if (sData && sData->m_mouseMoveCallback) 375 | (*sData->m_mouseMoveCallback)(xPos,yPos); 376 | 377 | break; 378 | } 379 | case WM_RBUTTONUP: 380 | { 381 | int xPos = LOWORD(lParam); 382 | int yPos = HIWORD(lParam); 383 | sData->m_mouseRButton = 1; 384 | 385 | if (sData && sData->m_mouseButtonCallback) 386 | (*sData->m_mouseButtonCallback)(2,0,sData->m_mouseXpos,sData->m_mouseYpos); 387 | 388 | //gDemoApplication->mouseFunc(2,1,xPos,yPos); 389 | break; 390 | } 391 | case WM_RBUTTONDOWN: 392 | { 393 | int xPos = LOWORD(lParam); 394 | int yPos = HIWORD(lParam); 395 | sData->m_mouseRButton = 0; 396 | if (sData && sData->m_mouseButtonCallback) 397 | (*sData->m_mouseButtonCallback)(2,1,sData->m_mouseXpos,sData->m_mouseYpos); 398 | 399 | break; 400 | } 401 | case WM_QUIT: 402 | { 403 | return 0; 404 | break; 405 | } 406 | case WM_SIZE: // Size Action Has Taken Place 407 | 408 | RECT clientRect; 409 | GetClientRect(hWnd,&clientRect); 410 | 411 | switch (wParam) // Evaluate Size Action 412 | { 413 | 414 | case SIZE_MINIMIZED: // Was Window Minimized? 415 | return 0; // Return 416 | 417 | case SIZE_MAXIMIZED: // Was Window Maximized? 418 | case SIZE_RESTORED: // Was Window Restored? 419 | RECT wr; 420 | GetWindowRect(hWnd,&wr); 421 | 422 | sData->m_fullWindowWidth = wr.right-wr.left; 423 | sData->m_fullWindowHeight = wr.bottom-wr.top;//LOWORD (lParam) HIWORD (lParam); 424 | sData->m_openglViewportWidth = clientRect.right; 425 | sData->m_openglViewportHeight = clientRect.bottom; 426 | glViewport(0, 0, sData->m_openglViewportWidth, sData->m_openglViewportHeight); 427 | 428 | if (sData->m_resizeCallback) 429 | (*sData->m_resizeCallback)(sData->m_openglViewportWidth,sData->m_openglViewportHeight); 430 | //if (sOpenGLInitialized) 431 | //{ 432 | // //gDemoApplication->reshape(sWidth,sHeight); 433 | //} 434 | return 0; // Return 435 | } 436 | break; 437 | 438 | default:{ 439 | 440 | 441 | } 442 | }; 443 | 444 | return DefWindowProc(hWnd, message, wParam, lParam); 445 | } 446 | 447 | 448 | 449 | void Win32Window::setWindowTitle(const char* titleChar) 450 | { 451 | 452 | wchar_t windowTitle[1024]; 453 | swprintf(windowTitle, 1024, L"%hs", titleChar); 454 | 455 | DWORD dwResult; 456 | 457 | #ifdef _WIN64 458 | SetWindowTextW(m_data->m_hWnd, windowTitle); 459 | #else 460 | SendMessageTimeoutW(m_data->m_hWnd, WM_SETTEXT, 0, 461 | reinterpret_cast(windowTitle), 462 | SMTO_ABORTIFHUNG, 2000, &dwResult); 463 | #endif 464 | } 465 | 466 | void Win32Window::createWindow(const b3gWindowConstructionInfo& ci) 467 | { 468 | int oglViewportWidth = ci.m_width; 469 | int oglViewportHeight = ci.m_height; 470 | bool fullscreen = ci.m_fullscreen; 471 | int colorBitsPerPixel = ci.m_colorBitsPerPixel; 472 | void* windowHandle = ci.m_windowHandle; 473 | 474 | // get handle to exe file 475 | HINSTANCE hInstance = GetModuleHandle(0); 476 | 477 | 478 | // create the window if we need to and we do not use the null device 479 | if (!windowHandle) 480 | { 481 | #ifdef UNICODE 482 | const wchar_t * ClassName = L"DeviceWin32"; 483 | const wchar_t* emptyString= L""; 484 | #else 485 | const char* ClassName = "DeviceWin32"; 486 | const char* emptyString = ""; 487 | #endif 488 | // Register Class 489 | WNDCLASSEX wcex; 490 | wcex.cbSize = sizeof(WNDCLASSEX); 491 | wcex.style = CS_HREDRAW | CS_VREDRAW; 492 | wcex.lpfnWndProc = WndProc; 493 | wcex.cbClsExtra = 0; 494 | wcex.cbWndExtra = 0; 495 | wcex.hInstance = hInstance; 496 | wcex.hIcon = LoadIcon( NULL, IDI_APPLICATION ); //(HICON)LoadImage(hInstance, "bullet_ico.ico", IMAGE_ICON, 0,0, LR_LOADTRANSPARENT);//LR_LOADFROMFILE); 497 | wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 498 | wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 499 | wcex.lpszMenuName = 0; 500 | wcex.lpszClassName = ClassName; 501 | wcex.hIconSm = 0; 502 | 503 | // if there is an icon, load it 504 | // wcex.hIcon = (HICON)LoadImage(hInstance, "bullet.ico", IMAGE_ICON, 0,0, LR_LOADFROMFILE); 505 | 506 | RegisterClassEx(&wcex); 507 | 508 | // calculate client size 509 | 510 | RECT clientSize; 511 | clientSize.top = 0; 512 | clientSize.left = 0; 513 | clientSize.right = oglViewportWidth; 514 | clientSize.bottom = oglViewportHeight; 515 | 516 | DWORD style = WS_POPUP; 517 | 518 | if (!fullscreen) 519 | style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX; 520 | 521 | AdjustWindowRect(&clientSize, style, false); 522 | 523 | m_data->m_fullWindowWidth = clientSize.right - clientSize.left; 524 | m_data->m_fullWindowHeight = clientSize.bottom - clientSize.top; 525 | 526 | int windowLeft = (GetSystemMetrics(SM_CXSCREEN) - m_data->m_fullWindowWidth) / 2; 527 | int windowTop = (GetSystemMetrics(SM_CYSCREEN) - m_data->m_fullWindowHeight) / 2; 528 | 529 | if (fullscreen) 530 | { 531 | windowLeft = 0; 532 | windowTop = 0; 533 | } 534 | 535 | // create window 536 | 537 | m_data->m_hWnd = CreateWindow( ClassName, emptyString, style, windowLeft, windowTop, 538 | m_data->m_fullWindowWidth, m_data->m_fullWindowHeight,NULL, NULL, hInstance, NULL); 539 | 540 | 541 | RECT clientRect; 542 | GetClientRect(m_data->m_hWnd,&clientRect); 543 | 544 | 545 | 546 | ShowWindow(m_data->m_hWnd, SW_SHOW); 547 | UpdateWindow(m_data->m_hWnd); 548 | 549 | MoveWindow(m_data->m_hWnd, windowLeft, windowTop, m_data->m_fullWindowWidth, m_data->m_fullWindowHeight, TRUE); 550 | 551 | GetClientRect(m_data->m_hWnd,&clientRect); 552 | int w = clientRect.right-clientRect.left; 553 | int h = clientRect.bottom-clientRect.top; 554 | // printf("actual client OpenGL viewport width / height = %d, %d\n",w,h); 555 | m_data->m_openglViewportHeight = h; 556 | m_data->m_openglViewportWidth = w; 557 | 558 | } 559 | else if (windowHandle) 560 | { 561 | // attach external window 562 | m_data->m_hWnd = static_cast(windowHandle); 563 | RECT r; 564 | GetWindowRect(m_data->m_hWnd, &r); 565 | m_data->m_fullWindowWidth = r.right - r.left; 566 | m_data->m_fullWindowHeight= r.bottom - r.top; 567 | 568 | 569 | //sFullScreen = false; 570 | //sExternalWindow = true; 571 | } 572 | 573 | 574 | if (fullscreen) 575 | { 576 | DEVMODE dm; 577 | memset(&dm, 0, sizeof(dm)); 578 | dm.dmSize = sizeof(dm); 579 | // use default values from current setting 580 | EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm); 581 | m_data->m_oldScreenWidth = dm.dmPelsWidth; 582 | m_data->m_oldHeight = dm.dmPelsHeight; 583 | m_data->m_oldBitsPerPel = dm.dmBitsPerPel; 584 | 585 | dm.dmPelsWidth = oglViewportWidth; 586 | dm.dmPelsHeight = oglViewportHeight; 587 | if (colorBitsPerPixel) 588 | { 589 | dm.dmBitsPerPel = colorBitsPerPixel; 590 | } 591 | dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; 592 | 593 | LONG res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); 594 | if (res != DISP_CHANGE_SUCCESSFUL) 595 | { // try again without forcing display frequency 596 | dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; 597 | res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); 598 | } 599 | 600 | } 601 | 602 | 603 | } 604 | 605 | 606 | void Win32Window::switchFullScreen(bool fullscreen,int width,int height,int colorBitsPerPixel) 607 | { 608 | 609 | LONG res; 610 | DEVMODE dm; 611 | memset(&dm, 0, sizeof(dm)); 612 | dm.dmSize = sizeof(dm); 613 | // use default values from current setting 614 | EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm); 615 | 616 | dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; 617 | 618 | if (fullscreen && !m_data->m_oldScreenWidth) 619 | { 620 | m_data->m_oldScreenWidth = dm.dmPelsWidth; 621 | m_data->m_oldHeight = dm.dmPelsHeight; 622 | m_data->m_oldBitsPerPel = dm.dmBitsPerPel; 623 | 624 | if (width && height) 625 | { 626 | dm.dmPelsWidth = width; 627 | dm.dmPelsHeight = height; 628 | } else 629 | { 630 | dm.dmPelsWidth = m_data->m_fullWindowWidth; 631 | dm.dmPelsHeight = m_data->m_fullWindowHeight; 632 | } 633 | if (colorBitsPerPixel) 634 | { 635 | dm.dmBitsPerPel = colorBitsPerPixel; 636 | } 637 | } else 638 | { 639 | if (m_data->m_oldScreenWidth) 640 | { 641 | dm.dmPelsWidth = m_data->m_oldScreenWidth; 642 | dm.dmPelsHeight= m_data->m_oldHeight; 643 | dm.dmBitsPerPel = m_data->m_oldBitsPerPel; 644 | } 645 | } 646 | 647 | if (fullscreen) 648 | { 649 | 650 | res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); 651 | if (!res) 652 | { 653 | dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; 654 | res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); 655 | } 656 | 657 | DWORD style = WS_POPUP; 658 | SetWindowLong(m_data->m_hWnd, GWL_STYLE, style); 659 | 660 | MoveWindow(m_data->m_hWnd, 0, 0, m_data->m_fullWindowWidth, m_data->m_fullWindowHeight, TRUE); 661 | 662 | SetWindowPos(m_data->m_hWnd, NULL,0,0, (int)width, (int)height, 663 | SWP_FRAMECHANGED |SWP_SHOWWINDOW);//|SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOOWNERZORDER | SWP_NOREPOSITION | SWP_NOZORDER); 664 | 665 | 666 | } else 667 | { 668 | res = ChangeDisplaySettings(&dm, 0); 669 | 670 | DWORD style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX; 671 | SetWindowLong(m_data->m_hWnd, GWL_STYLE, style); 672 | 673 | SetWindowPos(m_data->m_hWnd, NULL,0,0, (int)width, (int)height, 674 | SWP_FRAMECHANGED |SWP_SHOWWINDOW); 675 | //|SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOOWNERZORDER | SWP_NOREPOSITION | SWP_NOZORDER); 676 | 677 | } 678 | 679 | 680 | } 681 | 682 | 683 | 684 | Win32Window::Win32Window() 685 | { 686 | m_data = new InternalData2(); 687 | sData = m_data; 688 | 689 | } 690 | 691 | Win32Window::~Win32Window() 692 | { 693 | setKeyboardCallback(0); 694 | setMouseMoveCallback(0); 695 | setMouseButtonCallback(0); 696 | setWheelCallback(0); 697 | setResizeCallback(0); 698 | 699 | sData = 0; 700 | delete m_data; 701 | 702 | } 703 | 704 | void Win32Window::setRenderCallback( b3RenderCallback renderCallback) 705 | { 706 | 707 | } 708 | 709 | void Win32Window::closeWindow() 710 | { 711 | setKeyboardCallback(0); 712 | setMouseMoveCallback(0); 713 | setMouseButtonCallback(0); 714 | setWheelCallback(0); 715 | setResizeCallback(0); 716 | setRenderCallback(0); 717 | 718 | 719 | DestroyWindow(this->m_data->m_hWnd); 720 | } 721 | 722 | void Win32Window::getMouseCoordinates(int& x, int& y) 723 | { 724 | x = m_data->m_mouseXpos; 725 | y = m_data->m_mouseYpos; 726 | 727 | } 728 | 729 | void Win32Window::runMainLoop() 730 | { 731 | 732 | } 733 | 734 | 735 | void Win32Window::startRendering() 736 | { 737 | pumpMessage(); 738 | 739 | // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //clear buffers 740 | 741 | //glCullFace(GL_BACK); 742 | //glFrontFace(GL_CCW); 743 | // glEnable(GL_DEPTH_TEST); 744 | 745 | 746 | 747 | } 748 | 749 | 750 | void Win32Window::renderAllObjects() 751 | { 752 | } 753 | 754 | void Win32Window::endRendering() 755 | { 756 | SwapBuffers( m_data->m_hDC ); 757 | } 758 | 759 | float Win32Window::getTimeInSeconds() 760 | { 761 | return 0.f; 762 | } 763 | 764 | void Win32Window::setDebugMessage(int x,int y,const char* message) 765 | { 766 | } 767 | 768 | void Win32Window::setRequestExit() 769 | { 770 | m_data->m_quit = true; 771 | } 772 | bool Win32Window::requestedExit() const 773 | { 774 | return m_data->m_quit; 775 | } 776 | 777 | void Win32Window::setWheelCallback(b3WheelCallback wheelCallback) 778 | { 779 | m_data->m_wheelCallback = wheelCallback; 780 | } 781 | 782 | void Win32Window::setMouseMoveCallback(b3MouseMoveCallback mouseCallback) 783 | { 784 | m_data->m_mouseMoveCallback = mouseCallback; 785 | } 786 | 787 | void Win32Window::setMouseButtonCallback(b3MouseButtonCallback mouseCallback) 788 | { 789 | m_data->m_mouseButtonCallback = mouseCallback; 790 | } 791 | 792 | void Win32Window::setResizeCallback(b3ResizeCallback resizeCallback) 793 | { 794 | m_data->m_resizeCallback = resizeCallback; 795 | if (m_data->m_resizeCallback) 796 | (*m_data->m_resizeCallback)(m_data->m_openglViewportWidth,m_data->m_openglViewportHeight); 797 | } 798 | 799 | void Win32Window::setKeyboardCallback( b3KeyboardCallback keyboardCallback) 800 | { 801 | m_data->m_keyboardCallback = keyboardCallback; 802 | 803 | } 804 | 805 | b3KeyboardCallback Win32Window::getKeyboardCallback() 806 | { 807 | return m_data->m_keyboardCallback; 808 | } 809 | 810 | b3MouseMoveCallback Win32Window::getMouseMoveCallback() 811 | { 812 | return m_data->m_mouseMoveCallback; 813 | } 814 | b3MouseButtonCallback Win32Window::getMouseButtonCallback() 815 | { 816 | return m_data->m_mouseButtonCallback; 817 | } 818 | b3ResizeCallback Win32Window::getResizeCallback() 819 | { 820 | return m_data->m_resizeCallback; 821 | } 822 | b3WheelCallback Win32Window::getWheelCallback() 823 | { 824 | return m_data->m_wheelCallback; 825 | } 826 | #endif 827 | 828 | -------------------------------------------------------------------------------- /example/OpenGLWindow/Win32Window.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012 Advanced Micro Devices, Inc. 3 | 4 | This software is provided 'as-is', without any express or implied warranty. 5 | In no event will the authors be held liable for any damages arising from the use of this software. 6 | Permission is granted to anyone to use this software for any purpose, 7 | including commercial applications, and to alter it and redistribute it freely, 8 | subject to the following restrictions: 9 | 10 | 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. 11 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 12 | 3. This notice may not be removed or altered from any source distribution. 13 | */ 14 | //Originally written by Erwin Coumans 15 | 16 | 17 | #ifndef _WIN32_WINDOW_H 18 | #define _WIN32_WINDOW_H 19 | 20 | 21 | 22 | struct InternalData2; 23 | 24 | #include "CommonWindowInterface.h" 25 | 26 | class Win32Window : public CommonWindowInterface 27 | { 28 | protected: 29 | 30 | struct InternalData2* m_data; 31 | 32 | 33 | void pumpMessage(); 34 | 35 | 36 | 37 | public: 38 | 39 | Win32Window(); 40 | 41 | virtual ~Win32Window(); 42 | 43 | virtual void createWindow(const b3gWindowConstructionInfo& ci); 44 | 45 | virtual void switchFullScreen(bool fullscreen,int width=0,int height=0,int colorBitsPerPixel=0); 46 | 47 | virtual void closeWindow(); 48 | 49 | virtual void runMainLoop(); 50 | 51 | virtual void startRendering(); 52 | 53 | virtual void renderAllObjects(); 54 | 55 | virtual void endRendering(); 56 | 57 | virtual float getTimeInSeconds(); 58 | 59 | virtual void setDebugMessage(int x,int y,const char* message); 60 | 61 | virtual bool requestedExit() const; 62 | 63 | virtual void setRequestExit(); 64 | 65 | virtual void getMouseCoordinates(int& x, int& y); 66 | 67 | virtual void setMouseMoveCallback(b3MouseMoveCallback mouseCallback); 68 | virtual void setMouseButtonCallback(b3MouseButtonCallback mouseCallback); 69 | virtual void setResizeCallback(b3ResizeCallback resizeCallback); 70 | virtual void setWheelCallback(b3WheelCallback wheelCallback); 71 | virtual void setKeyboardCallback( b3KeyboardCallback keyboardCallback); 72 | 73 | virtual b3MouseMoveCallback getMouseMoveCallback(); 74 | virtual b3MouseButtonCallback getMouseButtonCallback(); 75 | virtual b3ResizeCallback getResizeCallback(); 76 | virtual b3WheelCallback getWheelCallback(); 77 | virtual b3KeyboardCallback getKeyboardCallback(); 78 | 79 | virtual void setRenderCallback( b3RenderCallback renderCallback); 80 | 81 | virtual void setWindowTitle(const char* title); 82 | 83 | virtual bool isModifierKeyPressed(int key); 84 | }; 85 | 86 | #endif //_WIN32_WINDOW_H 87 | -------------------------------------------------------------------------------- /example/OpenGLWindow/X11OpenGLWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef X11_OPENGL_WINDOW_H 2 | #define X11_OPENGL_WINDOW_H 3 | 4 | #define b3gDefaultOpenGLWindow X11OpenGLWindow 5 | 6 | #include "CommonWindowInterface.h" 7 | 8 | class X11OpenGLWindow : public CommonWindowInterface 9 | { 10 | 11 | struct InternalData2* m_data; 12 | bool m_OpenGLInitialized; 13 | bool m_requestedExit; 14 | 15 | protected: 16 | 17 | void enableOpenGL(); 18 | 19 | void disableOpenGL(); 20 | 21 | void pumpMessage(); 22 | 23 | int getAsciiCodeFromVirtualKeycode(int orgCode); 24 | 25 | public: 26 | 27 | X11OpenGLWindow(); 28 | 29 | virtual ~X11OpenGLWindow(); 30 | 31 | virtual void createWindow(const b3gWindowConstructionInfo& ci); 32 | 33 | virtual void closeWindow(); 34 | 35 | virtual void startRendering(); 36 | 37 | virtual void renderAllObjects(); 38 | 39 | virtual void endRendering(); 40 | 41 | virtual float getRetinaScale() const {return 1.f;} 42 | virtual void setAllowRetina(bool /*allowRetina*/) {}; 43 | 44 | virtual void runMainLoop(); 45 | virtual float getTimeInSeconds(); 46 | 47 | virtual bool requestedExit() const; 48 | virtual void setRequestExit() ; 49 | 50 | virtual bool isModifierKeyPressed(int key); 51 | 52 | virtual void setMouseMoveCallback(b3MouseMoveCallback mouseCallback); 53 | virtual void setMouseButtonCallback(b3MouseButtonCallback mouseCallback); 54 | virtual void setResizeCallback(b3ResizeCallback resizeCallback); 55 | virtual void setWheelCallback(b3WheelCallback wheelCallback); 56 | virtual void setKeyboardCallback( b3KeyboardCallback keyboardCallback); 57 | 58 | virtual b3MouseMoveCallback getMouseMoveCallback(); 59 | virtual b3MouseButtonCallback getMouseButtonCallback(); 60 | virtual b3ResizeCallback getResizeCallback(); 61 | virtual b3WheelCallback getWheelCallback(); 62 | virtual b3KeyboardCallback getKeyboardCallback(); 63 | 64 | virtual void setRenderCallback( b3RenderCallback renderCallback); 65 | 66 | virtual void setWindowTitle(const char* title); 67 | 68 | virtual int getWidth() const; 69 | 70 | virtual int getHeight() const; 71 | 72 | int fileOpenDialog(char* filename, int maxNameLength); 73 | }; 74 | 75 | 76 | 77 | #endif 78 | 79 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | .ttf fonts, images, perf.c are comming from NanoVG example. 2 | -------------------------------------------------------------------------------- /example/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/Roboto-Bold.ttf -------------------------------------------------------------------------------- /example/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/Roboto-Light.ttf -------------------------------------------------------------------------------- /example/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/Roboto-Regular.ttf -------------------------------------------------------------------------------- /example/bt3-browser-shim.js: -------------------------------------------------------------------------------- 1 | // bt3-browser-shim: shim that simulates the browser, built on bt3gui 2 | 3 | // translates `button` code to `buttons` codes (that can be summed with `|`) 4 | // see: https://developer.mozilla.org/en-US/docs/Web/Events/click 5 | var button_to_buttons = { 6 | 0: 1, 7 | 1: 2, 8 | 2: 4, 9 | 3: 8, 10 | 4: 16 11 | }; 12 | 13 | var handlers = { 14 | 'mousedown': [], 15 | 'mouseup': [], 16 | 'click': [], 17 | 'keydown': [], 18 | 'keyup': [], 19 | 'keypress': [] 20 | }; 21 | 22 | // wrap existing addEventListener, if one exists 23 | if (this.addEventListener) 24 | var orig_addEventListener = this.addEventListener; 25 | 26 | this.addEventListener = function(evt_name, fn) { 27 | if (evt_name in handlers) 28 | handlers[evt_name].push(fn); 29 | else if (orig_addEventListener) 30 | orig_addEventListener.apply(this, arguments); 31 | }; 32 | 33 | bt3gui.addEventListener('mousebutton', function(btn, state, x, y) { 34 | var evt = { 35 | screenX: x, 36 | screenY: y, 37 | clientX: x, 38 | clientY: y, 39 | button: btn, // left=0, middle=1, right=2 40 | buttons: button_to_buttons[btn] // TODO: detect multiple buttons pressed 41 | }; 42 | _setModifiers(evt); 43 | 44 | if (state == bt3gui.MOUSEDOWN) { 45 | _nameAndFire('mousedown', evt); 46 | } 47 | else if (state == bt3gui.MOUSEUP) { 48 | _nameAndFire('mouseup', evt); 49 | _nameAndFire('click', evt); 50 | } 51 | }); 52 | 53 | bt3gui.addEventListener('keyboard', function(code, state) { 54 | var keyCode; 55 | if (code == 32 || (code >= 48 && code <= 57)) // space & number keys 56 | keyCode = code; 57 | else if (code >= 97 && code <= 122) // a-z 58 | keyCode = code - 32; 59 | else 60 | keyCode = null; // TODO: implement these (will require research, the other keys aren't a consistent delta) 61 | 62 | var evt = { 63 | which: keyCode, 64 | keyCode: keyCode, 65 | charCode: 0 66 | }; 67 | _setModifiers(evt); 68 | 69 | var keypress_evt = { 70 | which: code, 71 | keyCode: code, 72 | charCode: code 73 | }; 74 | _setModifiers(keypress_evt); 75 | 76 | // TODO: in the browser, if a key is held down then 'keydown' and 'keypress' fire repeatedly 77 | if (state == bt3gui.KEYDOWN) { 78 | _nameAndFire('keydown', evt); 79 | _nameAndFire('keypress', keypress_evt); 80 | } 81 | else if (state == bt3gui.KEYUP) { 82 | _nameAndFire('keyup', evt); 83 | } 84 | }); 85 | 86 | function _nameAndFire(evt_name, evt) { 87 | evt.type = evt_name; 88 | handlers[evt.type].forEach(function(fn) { 89 | fn(evt); 90 | }); 91 | }; 92 | 93 | function _setModifiers(evt) { 94 | // TODO: implement .metaKey (not exposed in bt3gui.isModifierKeyPressed) 95 | evt.ctrlKey = bt3gui.isModifierKeyPressed(bt3gui.CTRL); 96 | evt.altKey = bt3gui.isModifierKeyPressed(bt3gui.ALT); 97 | evt.shiftKey = bt3gui.isModifierKeyPressed(bt3gui.SHIFT); 98 | } 99 | -------------------------------------------------------------------------------- /example/bt3gui.js: -------------------------------------------------------------------------------- 1 | // bt3gui namespace 2 | this.bt3gui = {}; 3 | 4 | bt3gui._evt_handlers = { 5 | mousebutton: [], 6 | mousemove: [], 7 | wheel: [], 8 | keyboard: [] 9 | }; 10 | 11 | bt3gui.SHIFT = 65306; 12 | bt3gui.CTRL = 65307; 13 | bt3gui.ALT = 65308; 14 | 15 | bt3gui.KEYUP = 0; 16 | bt3gui.KEYDOWN = 1; 17 | bt3gui.MOUSEUP = 0; 18 | bt3gui.MOUSEDOWN = 1; 19 | 20 | bt3gui.addEventListener = function(evt_name, fn) { 21 | var handlers = bt3gui._evt_handlers; 22 | handlers = handlers[evt_name].push(fn); 23 | }; 24 | 25 | bt3gui.emit = function(evt_name) { 26 | var args = Array.prototype.slice.call(arguments, 1); 27 | var handlers = bt3gui._evt_handlers[evt_name]; 28 | handlers.forEach(function(handler) { 29 | handler.apply(null, args); 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /example/entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/entypo.ttf -------------------------------------------------------------------------------- /example/findOpenGLGlewGlut.lua: -------------------------------------------------------------------------------- 1 | 2 | function findOpenGL() 3 | configuration{} 4 | if os.is("Linux") then 5 | return true 6 | end 7 | --assume OpenGL is available on Mac OSX, Windows etc 8 | return true 9 | end 10 | 11 | function findOpenGL3() 12 | configuration{} 13 | if os.is("MacOSX") then 14 | local osversion = os.getversion() 15 | --Mac OSX 10.9 and above supports OpenGL 3, below doesn't, so ... 16 | if osversion.majorversion > 10 or (osversion.majorversion == 10 and osversion.minorversion >=9) then 17 | return findOpenGL() 18 | else 19 | return false 20 | end 21 | else 22 | return findOpenGL() 23 | end 24 | end 25 | 26 | 27 | function initOpenGL() 28 | configuration {} 29 | configuration {"Windows"} 30 | links {"opengl32","glu32"} 31 | configuration {"MacOSX"} 32 | links { "OpenGL.framework"} 33 | configuration {"not Windows", "not MacOSX"} 34 | if os.is("Linux") then 35 | if _OPTIONS["enable_system_opengl"] and (os.isdir("/usr/include") and os.isfile("/usr/include/GL/gl.h")) then 36 | links {"GL"} 37 | else 38 | print("No GL/gl.h found, using dynamic loading of GL using glew") 39 | defines {"GLEW_INIT_OPENGL11_FUNCTIONS=1"} 40 | links {"dl"} 41 | end 42 | end 43 | configuration{} 44 | end 45 | 46 | 47 | function initGlew() 48 | configuration {} 49 | if os.is("Windows") then 50 | configuration {"Windows"} 51 | defines { "GLEW_STATIC"} 52 | includedirs { 53 | projectRootDir .. "ThirdPartyLibs/Glew" 54 | } 55 | files { projectRootDir .. "ThirdPartyLibs/Glew/glew.c"} 56 | end 57 | if os.is("Linux") then 58 | configuration{"Linux"} 59 | if _OPTIONS["enable_system_opengl"] and (os.isdir("/usr/include") and os.isfile("/usr/include/GL/gl.h") and os.isfile("/usr/include/GL/glew.h")) then 60 | links {"GLEW"} 61 | print ("linking against system GLEW") 62 | else 63 | print("Using static glew and dynamic loading of glx functions") 64 | defines { "GLEW_STATIC","GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1"} 65 | includedirs { 66 | projectRootDir .. "ThirdPartyLibs/Glew" 67 | } 68 | files { projectRootDir .. "ThirdPartyLibs/Glew/glew.c"} 69 | links {"dl"} 70 | end 71 | 72 | end 73 | configuration{} 74 | end 75 | 76 | function initX11() 77 | if os.is("Linux") then 78 | if _OPTIONS["enable_system_x11"] and (os.isdir("/usr/include") and os.isfile("/usr/include/X11/X.h")) then 79 | links{"X11","pthread"} 80 | else 81 | print("No X11/X.h found, using dynamic loading of X11") 82 | includedirs { 83 | projectRootDir .. "ThirdPartyLibs/optionalX11" 84 | } 85 | defines {"DYNAMIC_LOAD_X11_FUNCTIONS"} 86 | links {"dl","pthread"} 87 | end 88 | end 89 | end 90 | 91 | -------------------------------------------------------------------------------- /example/images.txt: -------------------------------------------------------------------------------- 1 | Image credits 2 | http://cuteoverload.com/2013/11/05/mom-taxi-xvi-birthday-party/ 3 | http://cuteoverload.com/2013/11/05/benson-hedges-private-eye-in-the-case-of-the-crafty-craftsman/ 4 | http://cuteoverload.com/2013/11/05/no-underwater-ballets/ 5 | http://cuteoverload.com/2013/11/05/every-nose-has-a-story/ 6 | http://cuteoverload.com/2013/11/04/nosevember-nozzle-nose/ 7 | http://cuteoverload.com/2013/11/04/this-just-in-super-strength-cute/ 8 | http://cuteoverload.com/2013/11/03/have-a-bunderful-sunday/ 9 | http://cuteoverload.com/2013/11/02/caturday-sense-a-common-theme-here/ 10 | http://cuteoverload.com/2013/11/01/nosevember-1st-24-hours-of-noses-1148pm-pt/ 11 | http://cuteoverload.com/2013/04/02/there-might-be-something-cuter-than-this/ 12 | http://cuteoverload.com/2013/07/17/snorting-micro-peeg-gets-belleh-rubs-interwebs-explode/ 13 | http://cuteoverload.com/2013/08/07/bark-in-the-park-v3-0/ -------------------------------------------------------------------------------- /example/images/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/images/image1.jpg -------------------------------------------------------------------------------- /example/images/image10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/images/image10.jpg -------------------------------------------------------------------------------- /example/images/image11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/images/image11.jpg -------------------------------------------------------------------------------- /example/images/image12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/images/image12.jpg -------------------------------------------------------------------------------- /example/images/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/images/image2.jpg -------------------------------------------------------------------------------- /example/images/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/images/image3.jpg -------------------------------------------------------------------------------- /example/images/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/images/image4.jpg -------------------------------------------------------------------------------- /example/images/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/images/image5.jpg -------------------------------------------------------------------------------- /example/images/image6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/images/image6.jpg -------------------------------------------------------------------------------- /example/images/image7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/images/image7.jpg -------------------------------------------------------------------------------- /example/images/image8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/images/image8.jpg -------------------------------------------------------------------------------- /example/images/image9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/example/images/image9.jpg -------------------------------------------------------------------------------- /example/input.js: -------------------------------------------------------------------------------- 1 | // How to work with non-BMP characters 2 | // https://github.com/svaarala/duktape-wiki/blob/add-nonbmp-howto/HowtoNonBmpCharacters.md 3 | var ICON_SEARCH = Duktape.dec('jx', '"\\U0001f50d"'); 4 | var ICON_CIRCLED_CROSS = "\u2716" 5 | var ICON_CHEVRON_RIGHT = "\uE75E" 6 | var ICON_CHECK = "\u2713" 7 | var ICON_LOGIN = "\uE740" 8 | var ICON_TRASH = "\uE729" 9 | 10 | this.addEventListener('click', function(evt) { 11 | print(evt.type + ', ' + evt.clientX + ', ' + evt.button + ', ctrl: ' + evt.ctrlKey + ', alt: ' + evt.altKey + ', shift: ' + evt.shiftKey); 12 | }); 13 | this.addEventListener('keydown', function(evt) { 14 | print('keydown', evt.which, evt.keyCode, evt.charCode); 15 | }); 16 | this.addEventListener('keyup', function(evt) { 17 | print('keyup', evt.which, evt.keyCode, evt.charCode); 18 | }); 19 | this.addEventListener('keypress', function(evt) { 20 | print('keypress', evt.which, evt.keyCode, evt.charCode); 21 | }); 22 | 23 | // on ESC, exit 24 | this.addEventListener('keypress', function(evt) { 25 | if (evt.keyCode == 27) 26 | bt3gui.setRequestExit(); 27 | }); 28 | 29 | function isBlack(r, g, b, a) { 30 | if (r === 0.0 && g === 0.0 && b === 0.0 && a === 0.0) { 31 | return true; 32 | } 33 | return false; 34 | } 35 | 36 | function hue(h, m1, m2) 37 | { 38 | if (h < 0) h += 1; 39 | if (h > 1) h -= 1; 40 | if (h < 1.0/6.0) 41 | return m1 + (m2 - m1) * h * 6.0; 42 | else if (h < 3.0/6.0) 43 | return m2; 44 | else if (h < 4.0/6.0) 45 | return m1 + (m2 - m1) * (2.0/3.0 - h) * 6.0; 46 | return m1; 47 | } 48 | 49 | function hsl2rgb(h, s, l) 50 | { 51 | var m1, m2; 52 | h = h % 1.0; 53 | if (h < 0.0) h += 1.0; 54 | s = Math.max(0.0, Math.min(s, 1.0)); 55 | l = Math.max(0.0, Math.min(l, 1.0)); 56 | m2 = l <= 0.5 ? (l * (1 + s)) : (l + s - l * s); 57 | m1 = 2 * l - m2; 58 | var r = Math.max(0.0, 256*Math.min(hue(h + 1.0/3.0, m1, m2), 255)); 59 | var g = Math.max(0.0, 256*Math.min(hue(h, m1, m2), 255)); 60 | var b = Math.max(0.0, 256*Math.min(hue(h - 1.0/3.0, m1, m2), 255)); 61 | //col.a = a/255.0f; 62 | return {r: r, g:g, b:b} 63 | } 64 | 65 | function drawEyes(vg, x, y, w, h, mx, my, t) 66 | { 67 | var ex = w *0.23; 68 | var ey = h * 0.5; 69 | var lx = x + ex; 70 | var ly = y + ey; 71 | var rx = x + w - ex; 72 | var ry = y + ey; 73 | var dx,dy,d; 74 | var br = (ex < ey ? ex : ey) * 0.5; 75 | var blink = 1 - Math.pow(Math.sin(t*0.5),200)*0.8; 76 | 77 | vg.beginPath(); 78 | vg.ellipse(lx+3.0,ly+16.0, ex,ey); 79 | vg.ellipse(rx+3.0,ry+16.0, ex,ey); 80 | vg.linearGradient(x,y+h*0.5,x+w*0.1,y+h, 0,0,0,32, 0,0,0,16); 81 | vg.fill(); 82 | 83 | vg.beginPath(vg); 84 | vg.ellipse(lx,ly, ex,ey); 85 | vg.ellipse(rx,ry, ex,ey); 86 | vg.linearGradient(x,y+h*0.25,x+w*0.1,y+h, 220,220,220,255, 128,128,128,255); 87 | vg.fill(); 88 | 89 | dx = (mx - rx) / (ex * 10); 90 | dy = (my - ry) / (ey * 10); 91 | d = Math.sqrt(dx*dx+dy*dy); 92 | if (d > 1.0) { 93 | dx /= d; dy /= d; 94 | } 95 | dx *= ex*0.4; 96 | dy *= ey*0.5; 97 | vg.beginPath(); 98 | vg.ellipse(lx+dx,ly+dy+ey*0.25*(1-blink), br,br*blink); 99 | vg.fillColor(32,32,32,255); 100 | vg.fill(); 101 | 102 | dx = (mx - rx) / (ex * 10); 103 | dy = (my - ry) / (ey * 10); 104 | d = Math.sqrt(dx*dx+dy*dy); 105 | if (d > 1.0) { 106 | dx /= d; dy /= d; 107 | } 108 | 109 | dx *= ex*0.4; 110 | dy *= ey*0.5; 111 | vg.beginPath(); 112 | vg.ellipse(rx+dx,ry+dy+ey*0.25*(1-blink), br,br*blink); 113 | vg.fillColor(32,32,32,255); 114 | vg.fill(); 115 | 116 | } 117 | 118 | 119 | function drawGraph(vg, x, y, w, h, t) 120 | { 121 | var samples = new Array(6); 122 | var sx = new Array(6); 123 | var sy = new Array(6); 124 | var dx = w/5.0; 125 | var i; 126 | 127 | samples[0] = (1+Math.sin(t*1.2345+Math.cos(t*0.33457)*0.44))*0.5; 128 | samples[1] = (1+Math.sin(t*0.68363+Math.cos(t*1.3)*1.55))*0.5; 129 | samples[2] = (1+Math.sin(t*1.1642+Math.cos(t*0.33457)*1.24))*0.5; 130 | samples[3] = (1+Math.sin(t*0.56345+Math.cos(t*1.63)*0.14))*0.5; 131 | samples[4] = (1+Math.sin(t*1.6245+Math.cos(t*0.254)*0.3))*0.5; 132 | samples[5] = (1+Math.sin(t*0.345+Math.cos(t*0.03)*0.6))*0.5; 133 | 134 | for (i = 0; i < 6; i++) { 135 | sx[i] = x+i*dx; 136 | sy[i] = y+h*samples[i]*0.8; 137 | } 138 | 139 | // Graph background 140 | vg.beginPath(); 141 | vg.moveTo(sx[0], sy[0]); 142 | for (i = 1; i < 6; i++) { 143 | vg.bezierTo(sx[i-1]+dx*0.5,sy[i-1], sx[i]-dx*0.5,sy[i], sx[i],sy[i]); 144 | } 145 | vg.lineTo(x+w, y+h); 146 | vg.lineTo(x, y+h); 147 | vg.linearGradient(x,y,x,y+h, 0,160,192,0, 0,160,192,64); 148 | vg.fill(); 149 | 150 | // Graph line 151 | vg.beginPath(); 152 | vg.moveTo(sx[0], sy[0]+2); 153 | for (i = 1; i < 6; i++) { 154 | vg.bezierTo(sx[i-1]+dx*0.5,sy[i-1]+2, sx[i]-dx*0.5,sy[i]+2, sx[i],sy[i]+2); 155 | } 156 | vg.strokeColor(0,0,0,32); 157 | vg.strokeWidth(3.0); 158 | vg.stroke(); 159 | 160 | vg.beginPath(); 161 | vg.moveTo(sx[0], sy[0]); 162 | for (i = 1; i < 6; i++) { 163 | vg.bezierTo(sx[i-1]+dx*0.5,sy[i-1], sx[i]-dx*0.5,sy[i], sx[i],sy[i]); 164 | } 165 | vg.strokeColor(0,160,192,255); 166 | vg.strokeWidth(3.0); 167 | vg.stroke(); 168 | 169 | // Graph sample pos 170 | for (i = 0; i < 6; i++) { 171 | vg.beginPath(); 172 | vg.rect(sx[i]-10, sy[i]-10+2, 20,20); 173 | vg.radialGradient(sx[i],sy[i]+2, 3.0,8.0, 0,0,0,32, 0,0,0,0); 174 | vg.fill(); 175 | } 176 | 177 | vg.beginPath(); 178 | for (i = 0; i < 6; i++) { 179 | vg.circle(sx[i], sy[i], 4.0); 180 | } 181 | vg.fillColor(0,160,192,255); 182 | vg.fill(); 183 | vg.beginPath(); 184 | for (i = 0; i < 6; i++) { 185 | vg.circle(sx[i], sy[i], 2.0); 186 | } 187 | vg.fillColor(220,220,220,255); 188 | vg.fill(); 189 | 190 | vg.strokeWidth(1.0); 191 | } 192 | 193 | function drawButton(vg, icon, text, x, y, w, h, r, g, b, a) { 194 | var cornerRadius = 4.0; 195 | 196 | var alpha = isBlack(r, g, b, a) ? 16 : 32; 197 | 198 | vg.beginPath(); 199 | vg.roundedRect(x+1,y+1, w-2,h-2, cornerRadius-1); 200 | if (!isBlack(r,g,b,a)) { 201 | vg.fillColor(r,g,b,a); 202 | vg.fill(); 203 | } 204 | vg.linearGradient(x,y,x,y+h, 255,255,255,alpha, 0,0,0,alpha); 205 | vg.fill(); 206 | 207 | vg.beginPath(); 208 | vg.roundedRect(x+0.5,y+0.5, w-1,h-1, cornerRadius-0.5); 209 | vg.strokeColor(0,0,0,48); 210 | vg.stroke(); 211 | 212 | 213 | vg.fontSize(20.0); 214 | vg.fontFace("sans-bold"); 215 | var tw = vg.textBounds(0,0,text); 216 | var iw = 0; 217 | if (icon != 0) { 218 | vg.fontSize(h*1.3); 219 | vg.fontFace("icons"); 220 | iw = vg.textBounds(0,0, icon); 221 | iw += h*0.15; 222 | } 223 | 224 | if (icon != 0) { 225 | vg.fontSize(h*1.3); 226 | vg.fontFace("icons"); 227 | vg.fillColor(255,255,255,96); 228 | vg.textAlign(vg.ALIGN_LEFT | vg.ALIGN_MIDDLE); 229 | vg.text(x+w*0.5-tw*0.5-iw*0.75, y+h*0.5, icon); 230 | } 231 | 232 | vg.fontSize(20.0); 233 | vg.fontFace("sans-bold"); 234 | vg.textAlign(vg.ALIGN_LEFT | vg.ALIGN_MIDDLE); 235 | vg.fillColor(0,0,0,160); 236 | vg.text(x+w*0.5-tw*0.5+iw*0.25,y+h*0.5-1,text); 237 | vg.fillColor(255,255,255,160); 238 | vg.text(x+w*0.5-tw*0.5+iw*0.25,y+h*0.5,text); 239 | 240 | } 241 | 242 | function drawSearchBox(vg, text, x, y, w, h) 243 | { 244 | var cornerRadius = h/2-1; 245 | 246 | // Edit 247 | vg.beginPath(); 248 | vg.roundedRect(x,y, w,h, cornerRadius); 249 | vg.boxGradient(x,y+1.5, w,h, h/2,5, 0,0,0,16, 0,0,0,92); 250 | vg.fill(); 251 | 252 | vg.fontSize(h*1.3); 253 | vg.fontFace("icons"); 254 | vg.fillColor(255,255,255,64); 255 | vg.textAlign(vg.ALIGN_CENTER|vg.ALIGN_MIDDLE); 256 | vg.text(x+h*0.55, y+h*0.55, ICON_SEARCH); 257 | 258 | vg.fontSize(20.0); 259 | vg.fontFace("sans"); 260 | vg.fillColor(255,255,255,32); 261 | 262 | vg.textAlign(vg.ALIGN_LEFT|vg.ALIGN_MIDDLE); 263 | vg.text(x+h*1.05,y+h*0.5,text); 264 | 265 | vg.fontSize(h*1.3); 266 | vg.fontFace("icons"); 267 | vg.fillColor(255,255,255,32); 268 | vg.textAlign(vg.ALIGN_CENTER|vg.ALIGN_MIDDLE); 269 | vg.text(x+w-h*0.55, y+h*0.55, ICON_CIRCLED_CROSS); 270 | } 271 | 272 | function drawWindow(vg, title, x, y, w, h) { 273 | var cornerRadius = 3.0; 274 | vg.save(); 275 | 276 | // window 277 | vg.beginPath(); 278 | vg.roundedRect(x,y,w,h,cornerRadius); 279 | vg.fillColor(28,30,34,192); 280 | vg.fill(); 281 | 282 | // drop shadow 283 | vg.beginPath(); 284 | vg.rect(x-10,y-10,w+20,h+30); 285 | vg.roundedRect(x,y,w,h,cornerRadius); 286 | vg.pathWinding(vg.HOLE); 287 | vg.boxGradient(x,y+2,w,h,cornerRadius*2, 10,0,0,0,128, 0,0,0,0); 288 | vg.fill(); 289 | 290 | // header 291 | vg.beginPath() 292 | vg.roundedRect(x+1,y+1,w-2,30,cornerRadius-1); 293 | vg.linearGradient(x,y,x,y+15,255,255,255,8,0,0,0,16); 294 | vg.fill(); 295 | 296 | vg.beginPath(); 297 | vg.moveTo(x+0.5,y+0.5+30); 298 | vg.lineTo(x+0.5+w-1,y+0.5+30); 299 | vg.strokeColor(0,0,0,32); 300 | vg.stroke(); 301 | 302 | vg.fontSize(18.0); 303 | vg.fontFace('sans-bold'); 304 | vg.textAlign(vg.ALIGN_CENTER); 305 | vg.fontBlur(2); 306 | vg.fillColor(0,0,0,128); 307 | vg.text(x+w/2, y+16+1, title); 308 | 309 | vg.fontBlur(0); 310 | vg.fillColor(220,220,220,160); 311 | vg.text(x+w/2, y+16, title); 312 | 313 | vg.restore(); 314 | } 315 | 316 | function drawDropDown(vg, text, x, y, w, h) 317 | { 318 | var cornerRadius = 4.0; 319 | 320 | vg.beginPath(); 321 | vg.roundedRect(x+1,y+1, w-2,h-2, cornerRadius-1); 322 | vg.linearGradient(x,y,x,y+h, 255,255,255,16, 0,0,0,16); 323 | vg.fill(); 324 | 325 | vg.beginPath(); 326 | vg.roundedRect(x+0.5,y+0.5, w-1,h-1, cornerRadius-0.5); 327 | vg.strokeColor(0,0,0,48); 328 | vg.stroke(); 329 | 330 | vg.fontSize(20.0); 331 | vg.fontFace("sans"); 332 | vg.fillColor(255,255,255,160); 333 | vg.textAlign(vg.ALIGN_LEFT|vg.ALIGN_MIDDLE); 334 | vg.text(x+h*0.3,y+h*0.5,text); 335 | 336 | vg.fontSize(h*1.3); 337 | vg.fontFace("icons"); 338 | vg.fillColor(255,255,255,64); 339 | vg.textAlign(vg.ALIGN_CENTER|vg.ALIGN_MIDDLE); 340 | vg.text(x+w-h*0.5, y+h*0.5, ICON_CHEVRON_RIGHT); 341 | } 342 | 343 | function drawColorwheel(vg, x, y, w, h, t) 344 | { 345 | var hueVal = Math.sin(t * 0.12); 346 | 347 | vg.save(); 348 | 349 | var cx = x + w*0.5; 350 | var cy = y + h*0.5; 351 | var r1 = (w < h ? w : h) * 0.5 - 5.0; 352 | var r0 = r1 - 20.0; 353 | var aeps = 0.5 / r1; // half a pixel arc length in radians (2pi cancels out). 354 | 355 | for (var i = 0; i < 6; i++) { 356 | var a0 = i / 6.0 * Math.PI * 2.0 - aeps; 357 | var a1 = (i+1.0) / 6.0 * Math.PI * 2.0 + aeps; 358 | vg.beginPath(); 359 | vg.arc(cx,cy, r0, a0, a1, vg.CW); 360 | vg.arc(cx,cy, r1, a1, a0, vg.CCW); 361 | vg.closePath(); 362 | var ax = cx + Math.cos(a0) * (r0+r1)*0.5; 363 | var ay = cy + Math.sin(a0) * (r0+r1)*0.5; 364 | var bx = cx + Math.cos(a1) * (r0+r1)*0.5; 365 | var by = cy + Math.sin(a1) * (r0+r1)*0.5; 366 | c0 = hsl2rgb(a0/(Math.PI*2),1.0,0.55); 367 | c1 = hsl2rgb(a1/(Math.PI*2),1.0,0.55); 368 | vg.linearGradient(ax,ay, bx,by, c0.r, c0.g, c0.b, 255, c1.r, c1.g, c1.b, 255); 369 | vg.fill(); 370 | } 371 | 372 | vg.beginPath(); 373 | vg.circle(cx,cy, r0-0.5); 374 | vg.circle(cx,cy, r1+0.5); 375 | vg.strokeColor(0,0,0,64); 376 | vg.stroke(); 377 | 378 | // Selector 379 | vg.save(); 380 | vg.translate(cx,cy); 381 | vg.rotate(hueVal*Math.PI*2); 382 | 383 | // Marker on 384 | vg.strokeWidth(2.0); 385 | vg.beginPath(); 386 | vg.rect(r0-1,-3,r1-r0+2,6); 387 | vg.strokeColor(255,255,255,192); 388 | vg.stroke(); 389 | 390 | vg.beginPath(); 391 | vg.rect(r0-2-10,-4-10,r1-r0+4+20,8+20); 392 | vg.rect(r0-2,-4,r1-r0+4,8); 393 | vg.pathWinding(vg.HOLE); 394 | vg.boxGradient(r0-3,-5,r1-r0+6,10, 2,4, 0,0,0,128, 0,0,0,0); 395 | vg.fill(); 396 | 397 | // Center triangle 398 | var r = r0 - 6; 399 | ax = Math.cos(120.0/180.0*Math.PI) * r; 400 | ay = Math.sin(120.0/180.0*Math.PI) * r; 401 | bx = Math.cos(-120.0/180.0*Math.PI) * r; 402 | by = Math.sin(-120.0/180.0*Math.PI) * r; 403 | vg.beginPath(); 404 | vg.moveTo(r,0); 405 | vg.lineTo(ax,ay); 406 | vg.lineTo(bx,by); 407 | vg.closePath(); 408 | col = hsl2rgb(hueVal, 1.0, 0.5); 409 | vg.linearGradient(r,0, ax,ay, col.r, col.g, col.b, 255, 255,255,255,255); 410 | vg.fill(); 411 | vg.linearGradient((r+ax)*0.5,(0+ay)*0.5, bx,by, 0,0,0,0, 0,0,0,255); 412 | vg.fill(); 413 | vg.strokeColor(0,0,0,64); 414 | vg.stroke(); 415 | 416 | // Select circle on triangle 417 | var ax = Math.cos(120.0/180.0*Math.PI) * r*0.3; 418 | var ay = Math.sin(120.0/180.0*Math.PI) * r*0.4; 419 | vg.strokeWidth(2.0); 420 | vg.beginPath(); 421 | vg.circle(ax,ay,5); 422 | vg.strokeColor(255,255,255,192); 423 | vg.stroke(); 424 | 425 | vg.beginPath(); 426 | vg.rect(ax-20,ay-20,40,40); 427 | vg.circle(ax,ay,7); 428 | vg.pathWinding(vg.HOLE); 429 | vg.radialGradient(ax,ay, 7,9, 0,0,0,64, 0,0,0,0); 430 | vg.fill(); 431 | 432 | vg.restore(); 433 | vg.restore(); 434 | } 435 | 436 | function drawLabel(vg, text, x, y, w, h) 437 | { 438 | vg.fontSize(18.0); 439 | vg.fontFace("sans"); 440 | vg.fillColor(255,255,255,128); 441 | 442 | vg.textAlign(vg.ALIGN_LEFT|vg.ALIGN_MIDDLE); 443 | vg.text(x,y+h*0.5,text); 444 | } 445 | 446 | function drawEditBoxBase(vg, x, y, w, h) 447 | { 448 | // Edit 449 | vg.beginPath(); 450 | vg.roundedRect(x+1,y+1, w-2,h-2, 4-1); 451 | vg.boxGradient(x+1,y+1+1.5, w-2,h-2, 3,4, 255,255,255,32, 32,32,32,32); 452 | vg.fill(); 453 | 454 | vg.beginPath(); 455 | vg.roundedRect(x+0.5,y+0.5, w-1,h-1, 4-0.5); 456 | vg.strokeColor(0,0,0,48); 457 | vg.stroke(); 458 | } 459 | 460 | function drawEditBox(vg, text, x, y, w, h) 461 | { 462 | drawEditBoxBase(vg, x,y, w,h); 463 | 464 | vg.fontSize(20.0); 465 | vg.fontFace("sans"); 466 | vg.fillColor(255,255,255,64); 467 | vg.textAlign(vg.ALIGN_LEFT|vg.ALIGN_MIDDLE); 468 | vg.text(x+h*0.3,y+h*0.5,text); 469 | } 470 | 471 | function drawEditBoxNum(vg, text, units, x, y, w, h) 472 | { 473 | drawEditBoxBase(vg, x,y, w,h); 474 | 475 | var uw = vg.textBounds(0,0, units); 476 | 477 | vg.fontSize(18.0); 478 | vg.fontFace("sans"); 479 | vg.fillColor(255,255,255,64); 480 | vg.textAlign(vg.ALIGN_RIGHT|vg.ALIGN_MIDDLE); 481 | vg.text(x+w-h*0.3,y+h*0.5,units); 482 | 483 | vg.fontSize(20.0); 484 | vg.fontFace("sans"); 485 | vg.fillColor(255,255,255,128); 486 | vg.textAlign(vg.ALIGN_RIGHT|vg.ALIGN_MIDDLE); 487 | vg.text(x+w-uw-h*0.5,y+h*0.5,text); 488 | } 489 | 490 | function drawCheckBox(vg, text, x, y, w, h) 491 | { 492 | vg.fontSize(18.0); 493 | vg.fontFace("sans"); 494 | vg.fillColor(255,255,255,160); 495 | 496 | vg.textAlign(vg.ALIGN_LEFT|vg.ALIGN_MIDDLE); 497 | vg.text(x+28,y+h*0.5,text); 498 | 499 | vg.beginPath(); 500 | vg.roundedRect(x+1,y+(h*0.5)-9, 18,18, 3); 501 | vg.boxGradient(x+1,y+(h*0.5)-9+1, 18,18, 3,3, 0,0,0,32, 0,0,0,92); 502 | vg.fill(vg); 503 | 504 | vg.fontSize(40); 505 | vg.fontFace("icons"); 506 | vg.fillColor(255,255,255,128); 507 | vg.textAlign(vg.ALIGN_CENTER|vg.ALIGN_MIDDLE); 508 | vg.text(x+9+2, y+h*0.5, ICON_CHECK); 509 | } 510 | 511 | function drawSlider(vg, pos, x, y, w, h) 512 | { 513 | var cy = y+(h*0.5); 514 | var kr = (h*0.25); 515 | 516 | vg.save(); 517 | 518 | // Slot 519 | vg.beginPath(); 520 | vg.roundedRect(x,cy-2, w,4, 2); 521 | vg.boxGradient(x,cy-2+1, w,4, 2,2, 0,0,0,32, 0,0,0,128); 522 | vg.fill(); 523 | 524 | // Knob Shadow 525 | vg.beginPath(); 526 | vg.rect(x+(pos*w)-kr-5,cy-kr-5,kr*2+5+5,kr*2+5+5+3); 527 | vg.circle(x+(pos*w),cy, kr); 528 | vg.pathWinding(vg.HOLE); 529 | vg.radialGradient(x+(pos*w),cy+1, kr-3,kr+3, 0,0,0,64, 0,0,0,0); 530 | vg.fill(); 531 | 532 | // Knob 533 | vg.beginPath(); 534 | vg.circle(x+(pos*w),cy, kr-1); 535 | vg.fillColor(40,43,48,255); 536 | vg.fill(); 537 | vg.linearGradient(x,cy-kr,x,cy+kr, 255,255,255,16, 0,0,0,16); 538 | vg.fill(); 539 | 540 | vg.beginPath(); 541 | vg.circle(x+(pos*w),cy, kr-0.5); 542 | vg.strokeColor(0,0,0,92); 543 | vg.stroke(); 544 | 545 | vg.restore(); 546 | } 547 | 548 | function drawSpinner(vg, cx, cy, r, t) 549 | { 550 | var a0 = 0.0 + t*6; 551 | var a1 = Math.PI + t*6; 552 | var r0 = r; 553 | var r1 = r * 0.75; 554 | var ax,ay, bx,by; 555 | 556 | vg.save(); 557 | 558 | vg.beginPath(); 559 | vg.arc(cx,cy, r0, a0, a1, vg.CW); 560 | vg.arc(cx,cy, r1, a1, a0, vg.CCW); 561 | vg.closePath(); 562 | ax = cx + Math.cos(a0) * (r0+r1)*0.5; 563 | ay = cy + Math.sin(a0) * (r0+r1)*0.5; 564 | bx = cx + Math.cos(a1) * (r0+r1)*0.5; 565 | by = cy + Math.sin(a1) * (r0+r1)*0.5; 566 | vg.linearGradient(ax,ay, bx,by, 0,0,0,0, 0,0,0,128); 567 | vg.fill(); 568 | 569 | vg.restore(); 570 | } 571 | 572 | function drawThumbnails(vg, x, y, w, h, images, nimages, t) 573 | { 574 | var cornerRadius = 3.0; 575 | var ix,iy,iw,ih; 576 | var thumb = 60.0; 577 | var arry = 30.5; 578 | var imgw, imgh; 579 | var stackh = (nimages/2) * (thumb+10) + 10; 580 | var i; 581 | var u = (1+Math.cos(t*0.5))*0.5; 582 | var u2 = (1-Math.cos(t*0.2))*0.5; 583 | var scrollh, dv; 584 | 585 | vg.save(); 586 | 587 | vg.beginPath(); 588 | vg.rect(x-10,y-10, w+20,h+30); 589 | vg.roundedRect(x,y, w,h, cornerRadius); 590 | vg.pathWinding(vg.HOLE); 591 | vg.boxGradient(x,y+4, w,h, cornerRadius*2, 20, 0,0,0,128, 0,0,0,0); 592 | vg.fill(); 593 | 594 | // Window 595 | vg.beginPath(); 596 | vg.roundedRect(x,y, w,h, cornerRadius); 597 | vg.moveTo(x-10,y+arry); 598 | vg.lineTo(x+1,y+arry-11); 599 | vg.lineTo(x+1,y+arry+11); 600 | vg.fillColor(200,200,200,255); 601 | vg.fill(); 602 | 603 | vg.save(); 604 | vg.scissor(x,y,w,h); 605 | vg.translate(0, -(stackh - h)*u); 606 | 607 | dv = 1.0 / (nimages-1); 608 | 609 | for (i = 0; i < nimages; i++) { 610 | var tx, ty, v, a; 611 | tx = x+10; 612 | ty = y+10; 613 | tx += (i%2) * (thumb+10); 614 | ty += (i/2) * (thumb+10); 615 | imgSize = vg.imageSize(images[i]); 616 | imgw = imgSize.width; 617 | imgh = imgSize.height 618 | if (imgw < imgh) { 619 | iw = thumb; 620 | ih = iw * imgh/imgw; 621 | ix = 0; 622 | iy = -(ih-thumb)*0.5; 623 | } else { 624 | ih = thumb; 625 | iw = ih * imgw/imgh; 626 | ix = -(iw-thumb)*0.5; 627 | iy = 0; 628 | } 629 | 630 | v = i * dv; 631 | a = Math.min(Math.max((u2-v)/dv, 0.0), 1.0); 632 | 633 | if (a < 1.0) { 634 | drawSpinner(vg, tx+thumb/2,ty+thumb/2, thumb*0.25, t); 635 | } 636 | 637 | vg.beginPath(); 638 | vg.roundedRect(tx,ty, thumb,thumb, 5); 639 | vg.imagePattern(tx+ix, ty+iy, iw,ih, 0.0/180.0*Math.PI, images[i], a); 640 | vg.fill(); 641 | 642 | vg.beginPath(); 643 | vg.rect(tx-5,ty-5, thumb+10,thumb+10); 644 | vg.roundedRect(tx,ty, thumb,thumb, 6); 645 | vg.pathWinding(vg.HOLE); 646 | vg.boxGradient(tx-1,ty, thumb+2,thumb+2, 5, 3, 0,0,0,128, 0,0,0,0); 647 | vg.fill(); 648 | 649 | vg.beginPath(); 650 | vg.roundedRect(tx+0.5,ty+0.5, thumb-1,thumb-1, 4-0.5); 651 | vg.strokeWidth(1.0); 652 | vg.strokeColor(255,255,255,192); 653 | vg.stroke(); 654 | 655 | } 656 | 657 | vg.restore(); 658 | 659 | // Hide fades 660 | vg.beginPath(); 661 | vg.rect(x+4,y,w-8,6); 662 | vg.linearGradient(x,y,x,y+6, 200,200,200,255, 200,200,200,0); 663 | vg.fill(); 664 | 665 | vg.beginPath(); 666 | vg.rect(x+4,y+h-6,w-8,6); 667 | vg.linearGradient(x,y+h,x,y+h-6, 200,200,200,255, 200,200,200,0); 668 | vg.fill(); 669 | 670 | // Scroll bar 671 | vg.beginPath(); 672 | vg.roundedRect(x+w-12,y+4, 8,h-8, 3); 673 | vg.boxGradient(x+w-12+1,y+4+1, 8,h-8, 3,4, 0,0,0,32, 0,0,0,92); 674 | vg.fill(); 675 | 676 | scrollh = (h/stackh) * (h-8); 677 | vg.beginPath(); 678 | vg.roundedRect(x+w-12+1,y+4+1 + (h-8-scrollh)*u, 8-2,scrollh-2, 2); 679 | vg.boxGradient(x+w-12-1,y+4+(h-8-scrollh)*u-1, 8,scrollh, 3,4, 220,220,220,255, 128,128,128,255); 680 | vg.fill(); 681 | 682 | vg.restore(); 683 | } 684 | 685 | function drawLines(vg, x, y, w, h, t) 686 | { 687 | var i, j; 688 | var pad = 5.0, s = w/9.0 - pad*2; 689 | var pts = [0,0,0,0,0,0,0,0]; 690 | var fx, fy; 691 | var joins = [vg.MITER, vg.ROUND, vg.BEVEL]; 692 | var caps = [vg.BUTT, vg.ROUND, vg.SQUARE]; 693 | 694 | vg.save(vg); 695 | pts[0] = -s*0.25 + Math.cos(t*0.3) * s*0.5; 696 | pts[1] = Math.sin(t*0.3) * s*0.5; 697 | pts[2] = -s*0.25; 698 | pts[3] = 0; 699 | pts[4] = s*0.25; 700 | pts[5] = 0; 701 | pts[6] = s*0.25 + Math.cos(-t*0.3) * s*0.5; 702 | pts[7] = Math.sin(-t*0.3) * s*0.5; 703 | 704 | for (var i = 0; i < 3; i++) { 705 | for (var j = 0; j < 3; j++) { 706 | fx = x + s*0.5 + (i*3+j)/9.0*w + pad; 707 | fy = y - s*0.5 + pad; 708 | 709 | vg.lineCap(caps[i]); 710 | vg.lineJoin(joins[j]); 711 | 712 | vg.strokeWidth(s*0.3); 713 | vg.strokeColor(0,0,0,160); 714 | vg.beginPath(); 715 | vg.moveTo(fx+pts[0], fy+pts[1]); 716 | vg.lineTo(fx+pts[2], fy+pts[3]); 717 | vg.lineTo(fx+pts[4], fy+pts[5]); 718 | vg.lineTo(fx+pts[6], fy+pts[7]); 719 | vg.stroke(); 720 | 721 | vg.lineCap(vg.BUTT); 722 | vg.lineJoin(vg.BEVEL); 723 | 724 | vg.strokeWidth(1.0); 725 | vg.strokeColor(0,192,255,255); 726 | vg.beginPath(); 727 | vg.moveTo(fx+pts[0], fy+pts[1]); 728 | vg.lineTo(fx+pts[2], fy+pts[3]); 729 | vg.lineTo(fx+pts[4], fy+pts[5]); 730 | vg.lineTo(fx+pts[6], fy+pts[7]); 731 | vg.stroke(); 732 | } 733 | } 734 | 735 | vg.restore(vg); 736 | } 737 | 738 | /* TODO 739 | function drawParagraph(vg, x, y, width, height, mx, my) 740 | { 741 | //NVGtextRow rows[3]; 742 | //NVGglyphPosition glyphs[100]; 743 | var text = "This is longer chunk of text.\n \n Would have used lorem ipsum but she was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party."; 744 | //const char* start; 745 | //const char* end; 746 | //int nrows, i, nglyphs, j, lnum = 0; 747 | //float lineh; 748 | //float caretx, px; 749 | //float bounds[4]; 750 | //float a; 751 | //float gx,gy; 752 | //int gutter = 0; 753 | 754 | vg.save(vg); 755 | 756 | vg.fontSize(18.0); 757 | vg.fontFace("sans"); 758 | vg.textAlign(vg.ALIGN_LEFT|vg.ALIGN_TOP); 759 | vg.textMetrics(NULL, NULL, &lineh); 760 | 761 | // The text break API can be used to fill a large buffer of rows, 762 | // or to iterate over the text just few lines (or just one) at a time. 763 | // The "next" variable of the last returned item tells where to continue. 764 | start = text; 765 | end = text + strlen(text); 766 | while ((nrows = nvgTextBreakLines(vg, start, end, width, rows, 3))) { 767 | for (i = 0; i < nrows; i++) { 768 | NVGtextRow* row = &rows[i]; 769 | int hit = mx > x && mx < (x+width) && my >= y && my < (y+lineh); 770 | 771 | nvgBeginPath(vg); 772 | nvgFillColor(vg, nvgRGBA(255,255,255,hit?64:16)); 773 | nvgRect(vg, x, y, row->width, lineh); 774 | nvgFill(vg); 775 | 776 | nvgFillColor(vg, nvgRGBA(255,255,255,255)); 777 | nvgText(vg, x, y, row->start, row->end); 778 | 779 | if (hit) { 780 | caretx = (mx < x+row->width/2) ? x : x+row->width; 781 | px = x; 782 | nglyphs = nvgTextGlyphPositions(vg, x, y, row->start, row->end, glyphs, 100); 783 | for (j = 0; j < nglyphs; j++) { 784 | float x0 = glyphs[j].x; 785 | float x1 = (j+1 < nglyphs) ? glyphs[j+1].x : x+row->width; 786 | float gx = x0 * 0.3f + x1 * 0.7f; 787 | if (mx >= px && mx < gx) 788 | caretx = glyphs[j].x; 789 | px = gx; 790 | } 791 | nvgBeginPath(vg); 792 | nvgFillColor(vg, nvgRGBA(255,192,0,255)); 793 | nvgRect(vg, caretx, y, 1, lineh); 794 | nvgFill(vg); 795 | 796 | gutter = lnum+1; 797 | gx = x - 10; 798 | gy = y + lineh/2; 799 | } 800 | lnum++; 801 | y += lineh; 802 | } 803 | // Keep going... 804 | start = rows[nrows-1].next; 805 | } 806 | 807 | if (gutter) { 808 | char txt[16]; 809 | snprintf(txt, sizeof(txt), "%d", gutter); 810 | nvgFontSize(vg, 13.0f); 811 | nvgTextAlign(vg, NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE); 812 | 813 | nvgTextBounds(vg, gx,gy, txt, NULL, bounds); 814 | 815 | nvgBeginPath(vg); 816 | nvgFillColor(vg, nvgRGBA(255,192,0,255)); 817 | nvgRoundedRect(vg, (int)bounds[0]-4,(int)bounds[1]-2, (int)(bounds[2]-bounds[0])+8, (int)(bounds[3]-bounds[1])+4, ((int)(bounds[3]-bounds[1])+4)/2-1); 818 | nvgFill(vg); 819 | 820 | nvgFillColor(vg, nvgRGBA(32,32,32,255)); 821 | nvgText(vg, gx,gy, txt, NULL); 822 | } 823 | 824 | y += 20.0f; 825 | 826 | nvgFontSize(vg, 13.0f); 827 | nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_TOP); 828 | nvgTextLineHeight(vg, 1.2f); 829 | 830 | nvgTextBoxBounds(vg, x,y, 150, "Hover your mouse over the text to see calculated caret position.", NULL, bounds); 831 | 832 | // Fade the tooltip out when close to it. 833 | gx = fabsf((mx - (bounds[0]+bounds[2])*0.5f) / (bounds[0] - bounds[2])); 834 | gy = fabsf((my - (bounds[1]+bounds[3])*0.5f) / (bounds[1] - bounds[3])); 835 | a = maxf(gx, gy) - 0.5f; 836 | a = clampf(a, 0, 1); 837 | nvgGlobalAlpha(vg, a); 838 | 839 | nvgBeginPath(vg); 840 | nvgFillColor(vg, nvgRGBA(220,220,220,255)); 841 | nvgRoundedRect(vg, bounds[0]-2,bounds[1]-2, (int)(bounds[2]-bounds[0])+4, (int)(bounds[3]-bounds[1])+4, 3); 842 | px = (int)((bounds[2]+bounds[0])/2); 843 | nvgMoveTo(vg, px,bounds[1] - 10); 844 | nvgLineTo(vg, px+7,bounds[1]+1); 845 | nvgLineTo(vg, px-7,bounds[1]+1); 846 | nvgFill(vg); 847 | 848 | nvgFillColor(vg, nvgRGBA(0,0,0,220)); 849 | nvgTextBox(vg, x,y, 150, "Hover your mouse over the text to see calculated caret position.", NULL); 850 | 851 | nvgRestore(vg); 852 | } 853 | */ 854 | 855 | function drawWidths(vg, x, y, width) 856 | { 857 | vg.save(); 858 | 859 | vg.strokeColor(0,0,0,255); 860 | 861 | for (var i = 0; i < 20; i++) { 862 | var w = (i+0.5)*0.1; 863 | vg.strokeWidth(w); 864 | vg.beginPath(); 865 | vg.moveTo(x,y); 866 | vg.lineTo(x+width,y+width*0.3); 867 | vg.stroke(); 868 | y += 10; 869 | } 870 | 871 | vg.restore(); 872 | } 873 | 874 | function drawCaps(vg, x, y, width) 875 | { 876 | var caps = [vg.BUTT, vg.ROUND, vg.SQUARE]; 877 | var lineWidth = 8.0; 878 | 879 | vg.save(); 880 | 881 | vg.beginPath(); 882 | vg.rect(x-lineWidth/2, y, width+lineWidth, 40); 883 | vg.fillColor(255,255,255,32); 884 | vg.fill(); 885 | 886 | vg.beginPath(); 887 | vg.rect(x, y, width, 40); 888 | vg.fillColor(255,255,255,32); 889 | vg.fill(); 890 | 891 | vg.strokeWidth(lineWidth); 892 | for (var i = 0; i < 3; i++) { 893 | vg.lineCap(caps[i]); 894 | vg.strokeColor(0,0,0,255); 895 | vg.beginPath(); 896 | vg.moveTo(x, y + i*10 + 5); 897 | vg.lineTo(x+width, y + i*10 + 5); 898 | vg.stroke(); 899 | } 900 | 901 | vg.restore(); 902 | } 903 | 904 | function drawScissor(vg, x, y, t) 905 | { 906 | vg.save(vg); 907 | 908 | // Draw first rect and set scissor to it's area. 909 | vg.translate(x, y); 910 | vg.rotate(5*Math.PI/180.0); 911 | vg.beginPath(); 912 | vg.rect(-20,-20,60,40); 913 | vg.fillColor(255,0,0,255); 914 | vg.fill(); 915 | vg.scissor(-20,-20,60,40); 916 | 917 | // Draw second rectangle with offset and rotation. 918 | vg.translate( 40,0); 919 | vg.rotate(t); 920 | 921 | // Draw the intended second rectangle without any scissoring. 922 | vg.save(); 923 | vg.resetScissor(); 924 | vg.beginPath(); 925 | vg.rect(-20,-10,60,30); 926 | vg.fillColor(255,128,0,64); 927 | vg.fill(); 928 | vg.restore(); 929 | 930 | // Draw second rectangle with combined scissoring. 931 | vg.intersectScissor(-20,-10,60,30); 932 | vg.beginPath(); 933 | vg.rect(-20,-10,60,30); 934 | vg.fillColor(255,128,0,255); 935 | vg.fill(); 936 | 937 | vg.restore(); 938 | } 939 | 940 | var VG = undefined; 941 | var gImages = []; 942 | var t = 0.0; 943 | 944 | function onInit() { 945 | try { 946 | vg = new NanoVG(); 947 | 948 | for (var i = 0; i < 12; i++) { 949 | var imageId = vg.createImage("../example/images/image" + (i+1) + ".jpg", 0); 950 | gImages.push(imageId); 951 | } 952 | 953 | t = 0.0; 954 | 955 | } catch(e) { 956 | print(e.stack); 957 | } 958 | 959 | } 960 | 961 | function onQuit() { 962 | for (var i = 0; i < 12; i++) { 963 | vg.deleteImage(gImages[i]); 964 | } 965 | } 966 | 967 | function onDraw() { 968 | 969 | try { 970 | if (VG == undefined) { 971 | VG = new NanoVG(); 972 | } 973 | var vg = VG; 974 | //var tw = vg.textBounds(0,0,'text'); 975 | var width = 1000; 976 | var height = 600; 977 | t = t + 0.02; 978 | var x, y, popy; 979 | 980 | drawEyes(vg, width - 250, 50, 150, 100, 0, 0, t); 981 | drawGraph(vg, 0, height/2, width, height/2, t); 982 | drawColorwheel(vg, width - 300, height - 300, 250, 250, t); 983 | 984 | // Line joints 985 | drawLines(vg, 120, height-50, 600, 50, t); 986 | 987 | // Line caps 988 | drawWidths(vg, 10, 50, 30); 989 | 990 | // Line caps 991 | drawCaps(vg, 10, 300, 30); 992 | 993 | drawScissor(vg, 50, height-80, t); 994 | 995 | vg.save(); 996 | 997 | // Widgets 998 | drawWindow(vg, "Widgets `n Stuff", 50, 50, 300, 400); 999 | x = 60; y = 95; 1000 | drawSearchBox(vg, "Search", x,y,280,25); 1001 | y += 40; 1002 | drawDropDown(vg, "Effects", x,y,280,28); 1003 | popy = y + 14; 1004 | y += 45; 1005 | 1006 | // Form 1007 | drawLabel(vg, "Login", x,y, 280,20); 1008 | y += 25; 1009 | drawEditBox(vg, "Email", x,y, 280,28); 1010 | y += 35; 1011 | drawEditBox(vg, "Password", x,y, 280,28); 1012 | y += 38; 1013 | drawCheckBox(vg, "Remember me", x,y, 140,28); 1014 | drawButton(vg, ICON_LOGIN, "Sign in", x+138, y, 140, 28, 0,96,128,255); 1015 | y += 45; 1016 | 1017 | 1018 | // Slider 1019 | drawLabel(vg, "Diameter", x,y, 280,20); 1020 | y += 25; 1021 | drawEditBoxNum(vg, "123.00", "px", x+180,y, 100,28); 1022 | drawSlider(vg, 0.4, x,y, 170,28); 1023 | y += 55; 1024 | 1025 | drawButton(vg, ICON_TRASH, "Delete", x, y, 160, 28, 128,16,8,255); 1026 | drawButton(vg, 0, "Cancel", x+170, y, 110, 28, 0,0,0,0); 1027 | 1028 | // Thumbnails box 1029 | drawThumbnails(vg, 365, popy-30, 160, 300, gImages, 12, t); 1030 | 1031 | vg.restore(); 1032 | } catch(e) { 1033 | print(e.stack); 1034 | } 1035 | 1036 | } 1037 | -------------------------------------------------------------------------------- /example/main.cc: -------------------------------------------------------------------------------- 1 | #define USE_OPENGL2 2 | #include "OpenGLWindow/OpenGLInclude.h" 3 | #ifdef _WIN32 4 | #include "OpenGLWindow/Win32OpenGLWindow.h" 5 | #elif defined __APPLE__ 6 | #include "OpenGLWindow/MacOpenGLWindow.h" 7 | #else 8 | // assume linux 9 | #include "OpenGLWindow/X11OpenGLWindow.h" 10 | #endif 11 | 12 | #include "nanovg.h" 13 | #define NANOVG_GL2_IMPLEMENTATION 14 | #include "nanovg_gl.h" 15 | 16 | #include "perf.h" 17 | 18 | #include "duktape.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | NVGcontext* vg; 26 | b3gDefaultOpenGLWindow *window = 0; 27 | 28 | #ifdef _WIN32 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | # include 33 | # include 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | #pragma comment( lib, "winmm.lib" ) 38 | #else 39 | #if defined(__unix__) || defined(__APPLE__) 40 | # include 41 | # else 42 | # include 43 | # endif 44 | #endif 45 | 46 | bool mouse_btn = false; 47 | int mouse_btn_button = 0; 48 | int mouse_btn_state = 0; 49 | float mouse_btn_x = 0.0; 50 | float mouse_btn_y = 0.0; 51 | 52 | bool keyboard_btn = false; 53 | int keyboard_code = 0; 54 | int keyboard_state = 0; 55 | 56 | class timer{ 57 | public: 58 | #ifdef _WIN32 59 | typedef DWORD time_t; 60 | 61 | timer() {::timeBeginPeriod( 1 );} 62 | ~timer(){::timeEndPeriod(1);} 63 | 64 | void start(){t_[0] = ::timeGetTime();} 65 | void end() {t_[1] = ::timeGetTime();} 66 | 67 | time_t sec() {return (time_t)( (t_[1]-t_[0]) / 1000 );} 68 | time_t msec(){return (time_t)( (t_[1]-t_[0]) );} 69 | time_t usec(){return (time_t)( (t_[1]-t_[0]) * 1000 );} 70 | 71 | #else 72 | #if defined(__unix__) || defined(__APPLE__) 73 | typedef unsigned long int time_t; 74 | 75 | 76 | void start(){gettimeofday(tv+0, &tz);} 77 | void end() {gettimeofday(tv+1, &tz);} 78 | 79 | time_t sec() {return (time_t)(tv[1].tv_sec-tv[0].tv_sec);} 80 | time_t msec(){return this->sec()*1000 + (time_t)((tv[1].tv_usec-tv[0].tv_usec)/1000);} 81 | time_t usec(){return this->sec()*1000000 + (time_t)(tv[1].tv_usec-tv[0].tv_usec);} 82 | 83 | #else //C timer 84 | //using namespace std; 85 | typedef clock_t time_t; 86 | 87 | void start(){t_[0] = clock();} 88 | void end() {t_[1] = clock();} 89 | 90 | time_t sec() {return (time_t)( (t_[1]-t_[0]) / CLOCKS_PER_SEC );} 91 | time_t msec(){return (time_t)( (t_[1]-t_[0]) * 1000 / CLOCKS_PER_SEC );} 92 | time_t usec(){return (time_t)( (t_[1]-t_[0]) * 1000000 / CLOCKS_PER_SEC );} 93 | 94 | #endif 95 | #endif 96 | 97 | private: 98 | 99 | #ifdef _WIN32 100 | DWORD t_[2]; 101 | #else 102 | #if defined(__unix__) || defined(__APPLE__) 103 | struct timeval tv[2]; 104 | struct timezone tz; 105 | #else 106 | time_t t_[2]; 107 | #endif 108 | #endif 109 | 110 | }; 111 | 112 | #if 0 // not used yet 113 | #define USE_ATOF 114 | 115 | #define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) 116 | #define IS_DIGIT(x) \ 117 | (static_cast((x) - '0') < static_cast(10)) 118 | 119 | // [0, 255] -> [0.0, 1.0] 120 | static inline float itof(int i) 121 | { 122 | if (i < 0) i = 0; 123 | if (i > 255) i = 255; 124 | 125 | return i / 255.0f; 126 | } 127 | 128 | // Tries to parse a floating point number located at s. 129 | // 130 | // s_end should be a location in the string where reading should absolutely 131 | // stop. For example at the end of the string, to prevent buffer overflows. 132 | // 133 | // Parses the following EBNF grammar: 134 | // sign = "+" | "-" ; 135 | // END = ? anything not in digit ? 136 | // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; 137 | // integer = [sign] , digit , {digit} ; 138 | // decimal = integer , ["." , integer] ; 139 | // float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; 140 | // 141 | // Valid strings are for example: 142 | // -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 143 | // 144 | // If the parsing is a success, result is set to the parsed value and true 145 | // is returned. 146 | // 147 | // The function is greedy and will parse until any of the following happens: 148 | // - a non-conforming character is encountered. 149 | // - s_end is reached. 150 | // 151 | // The following situations triggers a failure: 152 | // - s >= s_end. 153 | // - parse failure. 154 | // 155 | static bool tryParseDouble(const char *s, const char *s_end, double *result) { 156 | if (s >= s_end) { 157 | return false; 158 | } 159 | 160 | double mantissa = 0.0; 161 | // This exponent is base 2 rather than 10. 162 | // However the exponent we parse is supposed to be one of ten, 163 | // thus we must take care to convert the exponent/and or the 164 | // mantissa to a * 2^E, where a is the mantissa and E is the 165 | // exponent. 166 | // To get the final double we will use ldexp, it requires the 167 | // exponent to be in base 2. 168 | int exponent = 0; 169 | 170 | // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED 171 | // TO JUMP OVER DEFINITIONS. 172 | char sign = '+'; 173 | char exp_sign = '+'; 174 | char const *curr = s; 175 | 176 | // How many characters were read in a loop. 177 | int read = 0; 178 | // Tells whether a loop terminated due to reaching s_end. 179 | bool end_not_reached = false; 180 | 181 | /* 182 | BEGIN PARSING. 183 | */ 184 | 185 | // Find out what sign we've got. 186 | if (*curr == '+' || *curr == '-') { 187 | sign = *curr; 188 | curr++; 189 | } else if (IS_DIGIT(*curr)) { /* Pass through. */ 190 | } else { 191 | goto fail; 192 | } 193 | 194 | // Read the integer part. 195 | end_not_reached = (curr != s_end); 196 | while (end_not_reached && IS_DIGIT(*curr)) { 197 | mantissa *= 10; 198 | mantissa += static_cast(*curr - 0x30); 199 | curr++; 200 | read++; 201 | end_not_reached = (curr != s_end); 202 | } 203 | 204 | // We must make sure we actually got something. 205 | if (read == 0) goto fail; 206 | // We allow numbers of form "#", "###" etc. 207 | if (!end_not_reached) goto assemble; 208 | 209 | // Read the decimal part. 210 | if (*curr == '.') { 211 | curr++; 212 | read = 1; 213 | end_not_reached = (curr != s_end); 214 | while (end_not_reached && IS_DIGIT(*curr)) { 215 | // NOTE: Don't use powf here, it will absolutely murder precision. 216 | mantissa += static_cast(*curr - 0x30) * pow(10.0, -read); 217 | read++; 218 | curr++; 219 | end_not_reached = (curr != s_end); 220 | } 221 | } else if (*curr == 'e' || *curr == 'E') { 222 | } else { 223 | goto assemble; 224 | } 225 | 226 | if (!end_not_reached) goto assemble; 227 | 228 | // Read the exponent part. 229 | if (*curr == 'e' || *curr == 'E') { 230 | curr++; 231 | // Figure out if a sign is present and if it is. 232 | end_not_reached = (curr != s_end); 233 | if (end_not_reached && (*curr == '+' || *curr == '-')) { 234 | exp_sign = *curr; 235 | curr++; 236 | } else if (IS_DIGIT(*curr)) { /* Pass through. */ 237 | } else { 238 | // Empty E is not allowed. 239 | goto fail; 240 | } 241 | 242 | read = 0; 243 | end_not_reached = (curr != s_end); 244 | while (end_not_reached && IS_DIGIT(*curr)) { 245 | exponent *= 10; 246 | exponent += static_cast(*curr - 0x30); 247 | curr++; 248 | read++; 249 | end_not_reached = (curr != s_end); 250 | } 251 | exponent *= (exp_sign == '+' ? 1 : -1); 252 | if (read == 0) goto fail; 253 | } 254 | 255 | assemble: 256 | *result = 257 | (sign == '+' ? 1 : -1) * ldexp(mantissa * pow(5.0, exponent), exponent); 258 | return true; 259 | fail: 260 | return false; 261 | } 262 | 263 | 264 | static inline float parseFloat(const char **token) { 265 | (*token) += strspn((*token), " \t"); 266 | // Behavior of atof() is affected by C locale setting, so we use custom float parser. 267 | const char *end = (*token) + strcspn((*token), " \t\r"); 268 | double val = 0.0; 269 | tryParseDouble((*token), end, &val); 270 | float f = static_cast(val); 271 | (*token) = end; 272 | return f; 273 | } 274 | 275 | static inline int parseHex(const char **token) { 276 | char x0 = (*token)[0]; 277 | char x1 = (*token)[1]; 278 | 279 | unsigned char x = 0; 280 | if ((x0 >= 'a') && ((x0 <= 'f'))) { 281 | x += (x0 - 'a') << 4; 282 | } else if ((x0 >= 'A') && ((x0 <= 'F'))) { 283 | x += (x0 - 'A') << 4; 284 | } 285 | 286 | if ((x1 >= 'a') && ((x1 <= 'f'))) { 287 | x += (x1 - 'a'); 288 | } else if ((x1 >= 'A') && ((x1 <= 'F'))) { 289 | x += (x1 - 'A'); 290 | } 291 | 292 | return x; 293 | } 294 | 295 | static inline int parseInt(const char **token) { 296 | (*token) += strspn((*token), " \t"); 297 | int i = atoi((*token)); 298 | return i; 299 | } 300 | 301 | static inline void consumeComma(const char **token) { 302 | (*token) += strcspn((*token), ","); 303 | (*token)++; 304 | return; 305 | } 306 | 307 | static inline void consumeClosingParenthesis(const char **token) { 308 | (*token) += strcspn((*token), ")"); 309 | (*token)++; 310 | return; 311 | } 312 | 313 | static inline bool parsePercent(const char **token) { 314 | (*token) += strspn((*token), " \t"); 315 | bool ret = false; 316 | if ((*token) && ((*token)[0]) == ',') { 317 | (*token)++; 318 | ret = true; 319 | } 320 | (*token) += strcspn((*token), " \t\r"); 321 | return ret; 322 | } 323 | 324 | bool parseColor(float rgba[4], std::string s) 325 | { 326 | const char* token = s.c_str(); 327 | 328 | // @todo { parse error check. } 329 | 330 | // Supported patterns. 331 | // rgb(INT,INT,INT) 332 | // rgba(INT,INT,INT,FLOAT) 333 | // hsl(INT,INT%,INT%) 334 | // hsla(INT,INT%,INT%,FLOAT) 335 | // #ffffff (hexvalue) 336 | // 337 | if (strncmp(token, "rgb(", strlen("rgb(")) == 0) { 338 | token += strlen("rgb("); 339 | int r = parseInt(&token); 340 | consumeComma(&token); 341 | int g = parseInt(&token); 342 | consumeComma(&token); 343 | int b = parseInt(&token); 344 | consumeClosingParenthesis(&token); 345 | 346 | rgba[0] = itof(r); 347 | rgba[1] = itof(g); 348 | rgba[2] = itof(b); 349 | rgba[3] = 1.0f; 350 | return true; 351 | } else if (strcmp(token, "rgba(") == 0) { 352 | token += strlen("rgba("); 353 | 354 | int r = parseInt(&token); 355 | consumeComma(&token); 356 | int g = parseInt(&token); 357 | consumeComma(&token); 358 | int b = parseInt(&token); 359 | consumeComma(&token); 360 | float a = parseFloat(&token); 361 | consumeClosingParenthesis(&token); 362 | 363 | rgba[0] = itof(r); 364 | rgba[1] = itof(g); 365 | rgba[2] = itof(b); 366 | rgba[3] = a; 367 | 368 | return true; 369 | } else if (strcmp(token, "hsl(") == 0) { 370 | token += strlen("hsl("); 371 | // @todo 372 | assert(0); 373 | return false; 374 | } else if (strcmp(token, "hsla(") == 0) { 375 | token += strlen("hsla("); 376 | // @todo 377 | assert(0); 378 | return false; 379 | } else if (strcmp(token, "#") == 0) { 380 | token += 1; // '#' 381 | 382 | int r = parseHex(&token); 383 | token += 2; 384 | int g = parseHex(&token); 385 | token += 2; 386 | int b = parseHex(&token); 387 | token += 2; 388 | 389 | rgba[0] = itof(r); 390 | rgba[1] = itof(g); 391 | rgba[2] = itof(b); 392 | rgba[3] = 1.0f; 393 | 394 | return true; 395 | } else { 396 | // Unknown color string. 397 | } 398 | 399 | return false; 400 | } 401 | #endif 402 | 403 | unsigned char fclamp(float x) 404 | { 405 | int i = (int)x; 406 | 407 | if (i < 0) i = 0; 408 | if (i > 255) i = 255; 409 | 410 | return (unsigned char)(i); 411 | } 412 | 413 | void fatal_function(duk_context *ctx, duk_errcode_t code, const char *msg) 414 | { 415 | printf("FATAL: %d\n", code); 416 | printf("FATAL: %s\n", msg); 417 | (void)ctx; 418 | exit(-1); 419 | } 420 | 421 | void checkErrors(const char *desc) { 422 | GLenum e = glGetError(); 423 | if (e != GL_NO_ERROR) { 424 | fprintf(stderr, "OpenGL error in \"%s\": %d (%d)\n", desc, e, e); 425 | exit(20); 426 | } 427 | } 428 | 429 | duk_ret_t beginPath(duk_context *ctx) 430 | { 431 | (void)ctx; 432 | nvgBeginPath(vg); 433 | return 0; 434 | } 435 | 436 | duk_ret_t closePath(duk_context *ctx) 437 | { 438 | (void)ctx; 439 | nvgClosePath(vg); 440 | return 0; 441 | } 442 | 443 | duk_ret_t moveTo(duk_context *ctx) 444 | { 445 | float x = duk_require_number(ctx, 0); 446 | float y = duk_require_number(ctx, 1); 447 | 448 | nvgMoveTo(vg, x, y); 449 | return 0; 450 | } 451 | 452 | duk_ret_t lineTo(duk_context *ctx) 453 | { 454 | float x = duk_require_number(ctx, 0); 455 | float y = duk_require_number(ctx, 1); 456 | 457 | nvgLineTo(vg, x, y); 458 | return 0; 459 | } 460 | 461 | duk_ret_t lineCap(duk_context *ctx) 462 | { 463 | duk_int_t cap = duk_require_int(ctx, 0); 464 | 465 | nvgLineCap(vg, cap); 466 | return 0; 467 | } 468 | 469 | duk_ret_t lineJoin(duk_context *ctx) 470 | { 471 | duk_int_t join = duk_require_int(ctx, 0); 472 | 473 | nvgLineJoin(vg, join); 474 | return 0; 475 | } 476 | 477 | duk_ret_t translate(duk_context *ctx) 478 | { 479 | float x = duk_require_number(ctx, 0); 480 | float y = duk_require_number(ctx, 1); 481 | 482 | nvgTranslate(vg, x, y); 483 | return 0; 484 | } 485 | 486 | duk_ret_t rotate(duk_context *ctx) 487 | { 488 | float r = duk_require_number(ctx, 0); 489 | 490 | nvgRotate(vg, r); 491 | return 0; 492 | } 493 | 494 | duk_ret_t arc(duk_context *ctx) 495 | { 496 | float cx = duk_require_number(ctx, 0); 497 | float cy = duk_require_number(ctx, 1); 498 | float radius = duk_require_number(ctx, 2); 499 | float sAngle = duk_require_number(ctx, 3); 500 | float eAngle = duk_require_number(ctx, 4); 501 | duk_uint_t flag = duk_require_number(ctx, 5); 502 | 503 | nvgArc(vg, cx, cy, radius, sAngle, eAngle, flag); 504 | return 0; 505 | } 506 | 507 | duk_ret_t fillColor(duk_context *ctx) 508 | { 509 | float r = duk_require_number(ctx, 0); 510 | float g = duk_require_number(ctx, 1); 511 | float b = duk_require_number(ctx, 2); 512 | float a = duk_require_number(ctx, 3); 513 | 514 | nvgFillColor(vg, nvgRGBA(fclamp(r), fclamp(g), fclamp(b), fclamp(a))); 515 | return 0; 516 | } 517 | 518 | duk_ret_t stroke(duk_context *ctx) 519 | { 520 | (void)ctx; 521 | nvgStroke(vg); 522 | return 0; 523 | } 524 | 525 | duk_ret_t strokeColor(duk_context *ctx) 526 | { 527 | // Assume 0~255 528 | float r = duk_require_number(ctx, 0); 529 | float g = duk_require_number(ctx, 1); 530 | float b = duk_require_number(ctx, 2); 531 | float a = duk_require_number(ctx, 3); 532 | 533 | nvgStrokeColor(vg, nvgRGBA(fclamp(r), fclamp(g), fclamp(b), fclamp(a))); 534 | return 0; 535 | } 536 | 537 | duk_ret_t strokeWidth(duk_context *ctx) 538 | { 539 | float w = duk_require_number(ctx, 0); 540 | 541 | nvgStrokeWidth(vg, w); 542 | return 0; 543 | } 544 | 545 | duk_ret_t linearGradient(duk_context *ctx) 546 | { 547 | float ax = duk_require_number(ctx, 0); 548 | float ay = duk_require_number(ctx, 1); 549 | float bx = duk_require_number(ctx, 2); 550 | float by = duk_require_number(ctx, 3); 551 | // Assume 0~255 552 | float r0 = duk_require_number(ctx, 4); 553 | float g0 = duk_require_number(ctx, 5); 554 | float b0 = duk_require_number(ctx, 6); 555 | float a0 = duk_require_number(ctx, 7); 556 | float r1 = duk_require_number(ctx, 8); 557 | float g1 = duk_require_number(ctx, 9); 558 | float b1 = duk_require_number(ctx, 10); 559 | float a1 = duk_require_number(ctx, 11); 560 | 561 | NVGpaint paint = nvgLinearGradient(vg, ax, ay, bx, by, nvgRGBA(fclamp(r0), fclamp(g0), fclamp(b0), fclamp(a0)), nvgRGBA(fclamp(r1), fclamp(g1), fclamp(b1), fclamp(a1))); 562 | nvgFillPaint(vg, paint); 563 | //nvgFill(vg); 564 | 565 | return 0; 566 | } 567 | 568 | duk_ret_t boxGradient(duk_context *ctx) 569 | { 570 | float ax = duk_require_number(ctx, 0); 571 | float ay = duk_require_number(ctx, 1); 572 | float bx = duk_require_number(ctx, 2); 573 | float by = duk_require_number(ctx, 3); 574 | float radius = duk_require_number(ctx, 4); 575 | float f = duk_require_number(ctx, 5); 576 | // Assume 0~255 577 | float r0 = duk_require_number(ctx, 6); 578 | float g0 = duk_require_number(ctx, 7); 579 | float b0 = duk_require_number(ctx, 8); 580 | float a0 = duk_require_number(ctx, 9); 581 | float r1 = duk_require_number(ctx, 10); 582 | float g1 = duk_require_number(ctx, 11); 583 | float b1 = duk_require_number(ctx, 12); 584 | float a1 = duk_require_number(ctx, 13); 585 | 586 | NVGpaint paint = nvgBoxGradient(vg, ax, ay, bx, by, radius, f, nvgRGBA(fclamp(r0), fclamp(g0), fclamp(b0), fclamp(a0)), nvgRGBA(fclamp(r1), fclamp(g1), fclamp(b1), fclamp(a1))); 587 | nvgFillPaint(vg, paint); 588 | 589 | return 0; 590 | } 591 | 592 | duk_ret_t radialGradient(duk_context *ctx) 593 | { 594 | float ax = duk_require_number(ctx, 0); 595 | float ay = duk_require_number(ctx, 1); 596 | float bx = duk_require_number(ctx, 2); 597 | float by = duk_require_number(ctx, 3); 598 | // Assume 0~255 599 | float r0 = duk_require_number(ctx, 4); 600 | float g0 = duk_require_number(ctx, 5); 601 | float b0 = duk_require_number(ctx, 6); 602 | float a0 = duk_require_number(ctx, 7); 603 | float r1 = duk_require_number(ctx, 8); 604 | float g1 = duk_require_number(ctx, 9); 605 | float b1 = duk_require_number(ctx, 10); 606 | float a1 = duk_require_number(ctx, 11); 607 | 608 | NVGpaint paint = nvgRadialGradient(vg, ax, ay, bx, by, nvgRGBA(fclamp(r0), fclamp(g0), fclamp(b0), fclamp(a0)), nvgRGBA(fclamp(r1), fclamp(g1), fclamp(b1), fclamp(a1))); 609 | nvgFillPaint(vg, paint); 610 | //nvgFill(vg); 611 | 612 | return 0; 613 | } 614 | 615 | 616 | 617 | duk_ret_t fill(duk_context *ctx) 618 | { 619 | (void)ctx; 620 | nvgFill(vg); 621 | return 0; 622 | } 623 | 624 | duk_ret_t scissor(duk_context *ctx) 625 | { 626 | int n = duk_get_top(ctx); 627 | assert(n == 4); 628 | float x = duk_require_number(ctx, 0); 629 | float y = duk_require_number(ctx, 1); 630 | float w = duk_require_number(ctx, 2); 631 | float h = duk_require_number(ctx, 3); 632 | nvgScissor(vg, x, y, w, h); 633 | return 0; 634 | } 635 | 636 | duk_ret_t rect(duk_context *ctx) 637 | { 638 | int n = duk_get_top(ctx); 639 | assert(n == 4); 640 | float x = duk_require_number(ctx, 0); 641 | float y = duk_require_number(ctx, 1); 642 | float w = duk_require_number(ctx, 2); 643 | float h = duk_require_number(ctx, 3); 644 | nvgRect(vg, x, y, w, h); 645 | return 0; 646 | } 647 | 648 | duk_ret_t roundedRect(duk_context *ctx) 649 | { 650 | int n = duk_get_top(ctx); 651 | assert(n == 5); 652 | float x = duk_require_number(ctx, 0); 653 | float y = duk_require_number(ctx, 1); 654 | float w = duk_require_number(ctx, 2); 655 | float h = duk_require_number(ctx, 3); 656 | float r = duk_require_number(ctx, 4); 657 | nvgRoundedRect(vg, x, y, w, h, r); 658 | return 0; 659 | } 660 | 661 | duk_ret_t circle(duk_context *ctx) 662 | { 663 | int n = duk_get_top(ctx); 664 | assert(n == 3); 665 | float x = duk_require_number(ctx, 0); 666 | float y = duk_require_number(ctx, 1); 667 | float r = duk_require_number(ctx, 2); 668 | nvgCircle(vg, x, y, r); 669 | return 0; 670 | } 671 | 672 | duk_ret_t ellipse(duk_context *ctx) 673 | { 674 | int n = duk_get_top(ctx); 675 | assert(n == 4); 676 | float x = duk_require_number(ctx, 0); 677 | float y = duk_require_number(ctx, 1); 678 | float ra = duk_require_number(ctx, 2); 679 | float rb = duk_require_number(ctx, 3); 680 | nvgEllipse(vg, x, y, ra, rb); 681 | return 0; 682 | } 683 | 684 | duk_ret_t bezierTo(duk_context *ctx) 685 | { 686 | int n = duk_get_top(ctx); 687 | assert(n == 6); 688 | float x0 = duk_require_number(ctx, 0); 689 | float y0 = duk_require_number(ctx, 1); 690 | float x1 = duk_require_number(ctx, 2); 691 | float y1 = duk_require_number(ctx, 3); 692 | float x2 = duk_require_number(ctx, 4); 693 | float y2 = duk_require_number(ctx, 5); 694 | nvgBezierTo(vg, x0, y0, x1, y1, x2, y2); 695 | return 0; 696 | } 697 | 698 | duk_ret_t fontSize(duk_context *ctx) 699 | { 700 | float sz = duk_require_number(ctx, 0); 701 | nvgFontSize(vg, sz); 702 | 703 | return 0; 704 | } 705 | 706 | duk_ret_t fontFace(duk_context *ctx) 707 | { 708 | const char* face = duk_to_string(ctx, 0); 709 | nvgFontFace(vg, face); 710 | 711 | return 0; 712 | } 713 | 714 | duk_ret_t fontBlur(duk_context *ctx) 715 | { 716 | float blur = duk_require_number(ctx, 0); 717 | nvgFontBlur(vg, blur); 718 | 719 | return 0; 720 | } 721 | 722 | duk_ret_t textAlign(duk_context *ctx) 723 | { 724 | duk_uint_t flag = duk_require_uint(ctx, 0); 725 | nvgTextAlign(vg, flag); 726 | 727 | return 0; 728 | } 729 | 730 | 731 | duk_ret_t text(duk_context *ctx) 732 | { 733 | float x = duk_require_number(ctx, 0); 734 | float y = duk_require_number(ctx, 1); 735 | const char* text = duk_safe_to_string(ctx, 2); 736 | 737 | nvgText(vg, x, y, text, NULL); 738 | 739 | return 0; 740 | } 741 | 742 | duk_ret_t textBounds(duk_context *ctx) 743 | { 744 | float x = duk_require_number(ctx, 0); 745 | float y = duk_require_number(ctx, 1); 746 | const char* text = duk_safe_to_string(ctx, 2); 747 | 748 | float tw = nvgTextBounds(vg, x, y, text, NULL, NULL); 749 | 750 | duk_push_number(ctx, (double)tw); 751 | 752 | return 1; 753 | } 754 | 755 | duk_ret_t textMetrics(duk_context *ctx) 756 | { 757 | float ascender; 758 | float descender; 759 | float lineh; 760 | nvgTextMetrics(vg, &ascender, &descender, &lineh); 761 | 762 | duk_idx_t obj_idx = duk_push_object(ctx); 763 | duk_push_number(ctx, ascender); 764 | duk_put_prop_string(ctx, obj_idx, "ascender"); 765 | duk_push_number(ctx, descender); 766 | duk_put_prop_string(ctx, obj_idx, "descender"); 767 | duk_push_number(ctx, lineh); 768 | duk_put_prop_string(ctx, obj_idx, "lineh"); 769 | 770 | return 1; 771 | } 772 | 773 | duk_ret_t createImage(duk_context *ctx) 774 | { 775 | const char* filename = duk_safe_to_string(ctx, 0); 776 | duk_uint_t flag = duk_require_uint(ctx, 1); 777 | 778 | int id = nvgCreateImage(vg, filename, flag); 779 | 780 | duk_push_uint(ctx, id); 781 | 782 | return 1; 783 | } 784 | 785 | duk_ret_t imageSize(duk_context *ctx) 786 | { 787 | duk_uint_t id = duk_require_uint(ctx, 0); 788 | 789 | int w, h; 790 | nvgImageSize(vg, id, &w, &h); 791 | 792 | duk_idx_t obj_idx = duk_push_object(ctx); 793 | duk_push_uint(ctx, w); 794 | duk_put_prop_string(ctx, obj_idx, "width"); 795 | duk_push_uint(ctx, h); 796 | duk_put_prop_string(ctx, obj_idx, "height"); 797 | 798 | return 1; 799 | } 800 | 801 | duk_ret_t deleteImage(duk_context *ctx) 802 | { 803 | duk_uint_t id = duk_require_uint(ctx, 0); 804 | 805 | nvgDeleteImage(vg, id); 806 | 807 | return 0; 808 | } 809 | 810 | duk_ret_t imagePattern(duk_context *ctx) 811 | { 812 | float ox = duk_require_number(ctx, 0); 813 | float oy = duk_require_number(ctx, 1); 814 | float ex = duk_require_number(ctx, 2); 815 | float ey = duk_require_number(ctx, 3); 816 | float angle = duk_require_number(ctx, 4); 817 | duk_int_t imgId = duk_require_int(ctx, 5); 818 | float alpha = duk_require_number(ctx, 6); 819 | 820 | NVGpaint paint = nvgImagePattern(vg, ox, oy, ex, ey, angle, imgId, alpha); 821 | nvgFillPaint(vg, paint); 822 | 823 | return 0; 824 | } 825 | 826 | duk_ret_t save(duk_context *ctx) 827 | { 828 | (void)ctx; 829 | nvgSave(vg); 830 | return 0; 831 | } 832 | 833 | duk_ret_t restore(duk_context *ctx) 834 | { 835 | (void)ctx; 836 | nvgRestore(vg); 837 | return 0; 838 | } 839 | 840 | duk_ret_t pathWinding(duk_context *ctx) 841 | { 842 | duk_uint_t flag = duk_require_uint(ctx, 0); 843 | nvgPathWinding(vg, flag); 844 | return 0; 845 | } 846 | 847 | duk_ret_t intersectScissor(duk_context *ctx) 848 | { 849 | float x = duk_require_number(ctx, 0); 850 | float y = duk_require_number(ctx, 1); 851 | float w = duk_require_number(ctx, 2); 852 | float h = duk_require_number(ctx, 3); 853 | 854 | nvgIntersectScissor(vg, x, y, w, h); 855 | 856 | return 0; 857 | } 858 | 859 | duk_ret_t resetScissor(duk_context *ctx) 860 | { 861 | (void)ctx; 862 | nvgResetScissor(vg); 863 | 864 | return 0; 865 | } 866 | 867 | duk_ret_t onClick(duk_context *ctx) 868 | { 869 | (void)ctx; 870 | printf("On click\n"); 871 | return 0; 872 | } 873 | 874 | /* MyObject */ 875 | duk_ret_t myobject_constructor(duk_context *ctx) { 876 | if (!duk_is_constructor_call(ctx)) { 877 | return DUK_RET_TYPE_ERROR; 878 | } 879 | 880 | /* Set this.name = name; */ 881 | duk_push_this(ctx); 882 | duk_dup(ctx, 0); 883 | duk_put_prop_string(ctx, -2, "name"); 884 | 885 | return 0; /* use default instance */ 886 | } 887 | 888 | /* NanoVG */ 889 | duk_ret_t nanocanvas_constructor(duk_context *ctx) { 890 | if (!duk_is_constructor_call(ctx)) { 891 | return DUK_RET_TYPE_ERROR; 892 | } 893 | 894 | /* Set some constant/enum value; */ 895 | duk_push_this(ctx); 896 | 897 | duk_push_uint(ctx, NVG_CCW); 898 | duk_put_prop_string(ctx, -2, "CCW"); 899 | duk_push_uint(ctx, NVG_CW); 900 | duk_put_prop_string(ctx, -2, "CW"); 901 | 902 | duk_push_uint(ctx, NVG_SOLID); 903 | duk_put_prop_string(ctx, -2, "SOLID"); 904 | duk_push_uint(ctx, NVG_HOLE); 905 | duk_put_prop_string(ctx, -2, "HOLE"); 906 | 907 | duk_push_uint(ctx, NVG_BUTT); 908 | duk_put_prop_string(ctx, -2, "BUTT"); 909 | duk_push_uint(ctx, NVG_ROUND); 910 | duk_put_prop_string(ctx, -2, "ROUND"); 911 | duk_push_uint(ctx, NVG_SQUARE); 912 | duk_put_prop_string(ctx, -2, "SQUARE"); 913 | duk_push_uint(ctx, NVG_BEVEL); 914 | duk_put_prop_string(ctx, -2, "BEVEL"); 915 | duk_push_uint(ctx, NVG_MITER); 916 | duk_put_prop_string(ctx, -2, "MITER"); 917 | 918 | duk_push_uint(ctx, NVG_ALIGN_LEFT); 919 | duk_put_prop_string(ctx, -2, "ALIGN_LEFT"); 920 | duk_push_uint(ctx, NVG_ALIGN_CENTER); 921 | duk_put_prop_string(ctx, -2, "ALIGN_CENTER"); 922 | duk_push_uint(ctx, NVG_ALIGN_RIGHT); 923 | duk_put_prop_string(ctx, -2, "ALIGN_RIGHT"); 924 | duk_push_uint(ctx, NVG_ALIGN_TOP); 925 | duk_put_prop_string(ctx, -2, "ALIGN_TOP"); 926 | duk_push_uint(ctx, NVG_ALIGN_MIDDLE); 927 | duk_put_prop_string(ctx, -2, "ALIGN_MIDDLE"); 928 | duk_push_uint(ctx, NVG_ALIGN_BOTTOM); 929 | duk_put_prop_string(ctx, -2, "ALIGN_BOTTOM"); 930 | duk_push_uint(ctx, NVG_ALIGN_BASELINE); 931 | duk_put_prop_string(ctx, -2, "ALIGN_BASELINE"); 932 | 933 | return 0; /* use default instance */ 934 | } 935 | 936 | 937 | duk_ret_t print_name(duk_context *ctx) 938 | { 939 | duk_push_this(ctx); 940 | duk_get_prop_string(ctx, -1, "name"); 941 | printf("My name is: %s\n", duk_safe_to_string(ctx, -1)); 942 | return 0; 943 | } 944 | 945 | duk_ret_t bt3gui_isModifierKeyPressed(duk_context *ctx) { 946 | int modifier_key = duk_to_int(ctx, 0); 947 | duk_push_boolean(ctx, window->isModifierKeyPressed(modifier_key)); 948 | return 1; 949 | } 950 | 951 | duk_ret_t bt3gui_setRequestExit(duk_context *ctx) { 952 | window->setRequestExit(); 953 | return 0; 954 | } 955 | 956 | void decode_test(duk_context* ctx) 957 | { 958 | duk_set_top(ctx, 0); 959 | duk_push_string(ctx, "dGVzdCBzdHJpbmc="); 960 | duk_base64_decode(ctx, -1); 961 | printf("base64 decode: %s\n", duk_to_string(ctx, -1)); 962 | duk_set_top(ctx, 0); 963 | } 964 | 965 | void keyboardCallback(int keycode, int state) { 966 | keyboard_btn = true; 967 | keyboard_code = keycode; 968 | keyboard_state = state; 969 | } 970 | 971 | void mouseButtonCallback(int button, int state, float x, float y) { 972 | mouse_btn = true; 973 | mouse_btn_button = button; 974 | mouse_btn_state = state; 975 | mouse_btn_x = x; 976 | mouse_btn_y = y; 977 | } 978 | 979 | void mouseMoveCallback(float x, float y) { 980 | //printf("mouse move, x: %.2f, y: %.2f\n", x, y); 981 | } 982 | 983 | std::string ReadJSFile(const char* filename) 984 | { 985 | std::ifstream f(filename, std::ifstream::binary); 986 | if (!f) { 987 | printf("File not found %s\n", filename); 988 | return std::string(); 989 | } 990 | 991 | f.seekg(0, f.end); 992 | size_t sz = f.tellg(); 993 | std::vector buf(sz+1); 994 | 995 | f.seekg(0, f.beg); 996 | f.read(&buf.at(0), sz); 997 | f.close(); 998 | 999 | buf[sz] = '\0'; 1000 | 1001 | return std::string(&buf.at(0)); 1002 | } 1003 | 1004 | //void tests() 1005 | //{ 1006 | // float rgba[4]; 1007 | // std::string s = "rgb(64, 255, 128)"; 1008 | // bool ret = parseColor(rgba, s); 1009 | // if (!ret) { 1010 | // printf("parse err\n"); 1011 | // exit(-1); 1012 | // } 1013 | // printf("rgba = %f, %f, %f, %f\n", rgba[0], rgba[1], rgba[2], rgba[3]); 1014 | //} 1015 | 1016 | int main(int argc, char** argv) 1017 | { 1018 | int width = 1024; 1019 | int height = 600; 1020 | 1021 | std::string filename = "../example/input.js"; 1022 | if (argc > 1) { 1023 | filename = std::string(argv[1]); 1024 | } 1025 | 1026 | 1027 | std::string js = ReadJSFile(filename.c_str()); 1028 | printf("js = %s\n", js.c_str()); 1029 | 1030 | PerfGraph fps; 1031 | initGraph(&fps, GRAPH_RENDER_FPS, "Frame Time"); 1032 | 1033 | window = new b3gDefaultOpenGLWindow; 1034 | b3gWindowConstructionInfo ci; 1035 | #ifdef USE_OPENGL2 1036 | ci.m_openglVersion = 2; 1037 | #endif 1038 | ci.m_width = width; 1039 | ci.m_height = height; 1040 | window->createWindow(ci); 1041 | 1042 | window->setWindowTitle("NanoCanvas"); 1043 | 1044 | #ifndef __APPLE__ 1045 | #ifndef _WIN32 1046 | // some Linux implementations need the 'glewExperimental' to be true 1047 | glewExperimental = GL_TRUE; 1048 | #endif 1049 | if (glewInit() != GLEW_OK) { 1050 | fprintf(stderr, "Failed to initialize GLEW\n"); 1051 | exit(-1); 1052 | } 1053 | 1054 | if (!GLEW_VERSION_2_1) { 1055 | fprintf(stderr, "OpenGL 2.1 is not available\n"); 1056 | exit(-1); 1057 | } 1058 | #endif 1059 | 1060 | window->setMouseButtonCallback(mouseButtonCallback); 1061 | window->setMouseMoveCallback(mouseMoveCallback); 1062 | checkErrors("mouse"); 1063 | window->setKeyboardCallback(keyboardCallback); 1064 | checkErrors("keyboard"); 1065 | 1066 | vg = nvgCreateGL2(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG); 1067 | 1068 | nvgCreateFont(vg, "sans", "../example/Roboto-Regular.ttf"); 1069 | nvgCreateFont(vg, "sans-bold", "../example/Roboto-Bold.ttf"); 1070 | nvgCreateFont(vg, "icons", "../example/entypo.ttf"); 1071 | 1072 | duk_context *ctx = duk_create_heap(NULL, NULL, NULL, NULL, fatal_function); 1073 | 1074 | const duk_function_list_entry my_module_funcs[] = { 1075 | { "beginPath", beginPath, 0 /* no args */ }, 1076 | { "closePath", closePath, 0 }, 1077 | { "moveTo", moveTo, 2 }, 1078 | { "lineTo", lineTo, 2 }, 1079 | { "lineCap", lineCap, 1 }, 1080 | { "lineJoin", lineJoin, 1 }, 1081 | { "translate", translate, 2 }, 1082 | { "rotate", rotate, 1 }, 1083 | { "fillColor", fillColor, 4 }, 1084 | { "fill", fill, 0 }, 1085 | { "scissor", scissor, 4 }, 1086 | { "rect", rect, 4 }, 1087 | { "arc", arc, 6 }, 1088 | { "circle", circle, 3 }, 1089 | { "ellipse", ellipse, 4 }, 1090 | { "bezierTo", bezierTo, 6 }, 1091 | { "roundedRect", roundedRect, 5 }, 1092 | { "linearGradient", linearGradient, 12 }, 1093 | { "radialGradient", radialGradient, 12 }, 1094 | { "stroke", stroke, 0 }, 1095 | { "strokeWidth", strokeWidth, 1 }, 1096 | { "strokeColor", strokeColor, 4 }, 1097 | { "save", save, 0 }, 1098 | { "restore", restore, 0 }, 1099 | { "text", text, 3 }, 1100 | { "pathWinding", pathWinding, 1 }, 1101 | { "boxGradient", boxGradient,14 }, 1102 | { "fontSize", fontSize, 1 }, 1103 | { "fontFace", fontFace, 1 }, 1104 | { "fontBlur", fontBlur, 1 }, 1105 | { "textAlign", textAlign, 1 }, 1106 | { "textBounds", textBounds, 3 }, 1107 | { "textMetrics", textMetrics, 1 }, 1108 | { "createImage", createImage, 2 }, 1109 | { "imageSize", imageSize, 1 }, 1110 | { "deleteImage", deleteImage, 1 }, 1111 | { "imagePattern", imagePattern, 7 }, 1112 | { "intersectScissor", intersectScissor, 4 }, 1113 | { "resetScissor", resetScissor, 0 }, 1114 | { NULL, NULL, 0 } 1115 | }; 1116 | 1117 | duk_push_c_function(ctx, nanocanvas_constructor, /* nargs */0); 1118 | duk_push_object(ctx); // push NanoVG.prototype. 1119 | duk_put_function_list(ctx, -1, my_module_funcs); 1120 | duk_put_prop_string(ctx, -2, "prototype"); 1121 | duk_put_global_string(ctx, "NanoVG"); /* -> [ ... global ] */ 1122 | 1123 | #if 0 1124 | const duk_function_list_entry my_event_funcs[] = { 1125 | { "onClick", onClick, 0 /* no args */ }, 1126 | }; 1127 | duk_push_c_function(ctx, myobject_constructor, 1); 1128 | duk_push_object(ctx); /* -> [ ... global obj ] */ 1129 | duk_put_function_list(ctx, -1, my_event_funcs); 1130 | //duk_push_c_function(ctx, print_name, 0); 1131 | //duk_put_prop_string(ctx, -2, "printName"); 1132 | duk_put_prop_string(ctx, -2, "prototype"); 1133 | duk_put_global_string(ctx, "Slider"); /* -> [ ... global ] */ 1134 | //duk_pop(ctx); 1135 | 1136 | decode_test(ctx); 1137 | #endif 1138 | 1139 | // thin wrapper around bt3gui 1140 | std::string bt3gui_js = ReadJSFile("../example/bt3gui.js"); 1141 | if (duk_peval_string(ctx, bt3gui_js.c_str()) != 0) { 1142 | printf("bt3gui eval failed: %s\n", duk_safe_to_string(ctx, -1)); 1143 | exit(-1); 1144 | } 1145 | duk_push_global_object(ctx); // [global] 1146 | duk_get_prop_string(ctx, -1 /*index*/, "bt3gui"); // [global, bt3gui] 1147 | duk_push_c_function(ctx, bt3gui_isModifierKeyPressed, /* nargs */1); // [global, bt3gui, isModifierKeyPressed] 1148 | duk_put_prop_string(ctx, -2, "isModifierKeyPressed"); // [global, bt3gui] 1149 | duk_push_c_function(ctx, bt3gui_setRequestExit, 0); // [global, bt3gui, setRequestExit] 1150 | duk_put_prop_string(ctx, -2, "setRequestExit"); // [global, bt3gui] 1151 | duk_pop(ctx); // [global] 1152 | duk_pop(ctx); // [] 1153 | 1154 | // eval the bt3-browser-shim (simulates browser events) 1155 | std::string bt3_browser_shim = ReadJSFile("../example/bt3-browser-shim.js"); 1156 | if (duk_peval_string(ctx, bt3_browser_shim.c_str()) != 0) { 1157 | printf("bt3-browser-shim eval failed: %s\n", duk_safe_to_string(ctx, -1)); 1158 | exit(-1); 1159 | } 1160 | 1161 | // eval the user's JS file 1162 | if (duk_peval_string(ctx, js.c_str()) != 0) { 1163 | printf("eval failed: %s\n", duk_safe_to_string(ctx, -1)); 1164 | exit(-1); 1165 | } 1166 | 1167 | duk_push_global_object(ctx); 1168 | duk_get_prop_string(ctx, -1 /*index*/, "onInit"); 1169 | if (duk_pcall(ctx, 0 /*nargs*/) != 0) { 1170 | printf("Error: %s\n", duk_safe_to_string(ctx, -1)); 1171 | } 1172 | duk_pop(ctx); /* pop result/error */ 1173 | 1174 | timer tm; 1175 | 1176 | tm.start(); 1177 | double prevt = 0.0; 1178 | tm.end(); 1179 | prevt = tm.msec() / 1000.0; // [s] 1180 | 1181 | while (!window->requestedExit()) { 1182 | window->startRendering(); 1183 | 1184 | double t, dt; 1185 | 1186 | tm.end(); 1187 | t = tm.msec() / 1000.0; // [s] 1188 | 1189 | dt = t - prevt; 1190 | prevt = t; 1191 | updateGraph(&fps, dt); 1192 | 1193 | // Update and render 1194 | glViewport(0, 0, width, height); 1195 | glClearColor(0.3f, 0.3f, 0.32f, 1.0f); 1196 | glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); 1197 | 1198 | nvgBeginFrame(vg, width, height, width / (float)height); 1199 | 1200 | duk_push_global_object(ctx); 1201 | duk_get_prop_string(ctx, -1 /*index*/, "onDraw"); 1202 | if (duk_pcall(ctx, 0 /*nargs*/) != 0) { 1203 | printf("Error: %s\n", duk_safe_to_string(ctx, -1)); 1204 | } else { 1205 | //printf("%s\n", duk_safe_to_string(ctx, -1)); 1206 | } 1207 | duk_pop(ctx); /* pop result/error */ 1208 | 1209 | // call bt3gui.emit() if mouse or keyboard events have occurred 1210 | duk_push_global_object(ctx); 1211 | duk_get_prop_string(ctx, -1 /*index*/, "bt3gui"); 1212 | 1213 | if (mouse_btn) { 1214 | duk_get_prop_string(ctx, -1 /*index*/, "emit"); 1215 | duk_push_string(ctx, "mousebutton"); 1216 | duk_push_number(ctx, mouse_btn_button); 1217 | duk_push_number(ctx, mouse_btn_state); 1218 | duk_push_number(ctx, mouse_btn_x); 1219 | duk_push_number(ctx, mouse_btn_y); 1220 | if (duk_pcall(ctx, 5 /*nargs*/) != 0) { 1221 | printf("Error: %s\n", duk_safe_to_string(ctx, -1)); 1222 | } 1223 | duk_pop(ctx); /* pop result/error */ 1224 | mouse_btn = false; 1225 | } 1226 | 1227 | if (keyboard_btn) { 1228 | duk_get_prop_string(ctx, -1 /*index*/, "emit"); 1229 | duk_push_string(ctx, "keyboard"); 1230 | duk_push_number(ctx, keyboard_code); 1231 | duk_push_number(ctx, keyboard_state); 1232 | if (duk_pcall(ctx, 3 /*nargs*/) != 0) { 1233 | printf("Error: %s\n", duk_safe_to_string(ctx, -1)); 1234 | } 1235 | duk_pop(ctx); /* pop result/error */ 1236 | keyboard_btn = false; 1237 | } 1238 | 1239 | duk_pop(ctx); /* pop bt3gui namespace */ 1240 | duk_pop(ctx); /* pop global */ 1241 | 1242 | renderGraph(vg, 5,5, &fps); 1243 | 1244 | nvgEndFrame(vg); 1245 | 1246 | window->endRendering(); 1247 | } 1248 | 1249 | duk_push_global_object(ctx); 1250 | duk_get_prop_string(ctx, -1 /*index*/, "onQuit"); 1251 | if (duk_pcall(ctx, 0 /*nargs*/) != 0) { 1252 | printf("Error: %s\n", duk_safe_to_string(ctx, -1)); 1253 | } else { 1254 | //printf("%s\n", duk_safe_to_string(ctx, -1)); 1255 | } 1256 | duk_pop(ctx); /* pop result/error */ 1257 | 1258 | duk_destroy_heap(ctx); 1259 | 1260 | nvgDeleteGL2(vg); 1261 | 1262 | delete window; 1263 | 1264 | return 0; 1265 | } 1266 | 1267 | -------------------------------------------------------------------------------- /example/perf.c: -------------------------------------------------------------------------------- 1 | #include "perf.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #define USE_OPENGL2 7 | #include "OpenGLWindow/OpenGLInclude.h" 8 | 9 | #include "nanovg.h" 10 | 11 | #ifdef _MSC_VER 12 | #define snprintf _snprintf 13 | #elif !defined(__MINGW32__) 14 | #include 15 | #endif 16 | 17 | // timer query support 18 | #ifndef GL_ARB_timer_query 19 | #define GL_TIME_ELAPSED 0x88BF 20 | //typedef void (APIENTRY *pfnGLGETQUERYOBJECTUI64V)(GLuint id, GLenum pname, GLuint64* params); 21 | //pfnGLGETQUERYOBJECTUI64V glGetQueryObjectui64v = 0; 22 | #endif 23 | 24 | void initGPUTimer(GPUtimer* timer) 25 | { 26 | memset(timer, 0, sizeof(*timer)); 27 | 28 | /* timer->supported = glfwExtensionSupported("GL_ARB_timer_query"); 29 | if (timer->supported) { 30 | #ifndef GL_ARB_timer_query 31 | glGetQueryObjectui64v = (pfnGLGETQUERYOBJECTUI64V)glfwGetProcAddress("glGetQueryObjectui64v"); 32 | printf("glGetQueryObjectui64v=%p\n", glGetQueryObjectui64v); 33 | if (!glGetQueryObjectui64v) { 34 | timer->supported = GL_FALSE; 35 | return; 36 | } 37 | #endif 38 | glGenQueries(GPU_QUERY_COUNT, timer->queries); 39 | }*/ 40 | } 41 | 42 | void startGPUTimer(GPUtimer* timer) 43 | { 44 | if (!timer->supported) 45 | return; 46 | glBeginQuery(GL_TIME_ELAPSED, timer->queries[timer->cur % GPU_QUERY_COUNT] ); 47 | timer->cur++; 48 | } 49 | 50 | int stopGPUTimer(GPUtimer* timer, float* times, int maxTimes) 51 | { 52 | NVG_NOTUSED(times); 53 | NVG_NOTUSED(maxTimes); 54 | GLint available = 1; 55 | int n = 0; 56 | if (!timer->supported) 57 | return 0; 58 | 59 | glEndQuery(GL_TIME_ELAPSED); 60 | while (available && timer->ret <= timer->cur) { 61 | // check for results if there are any 62 | glGetQueryObjectiv(timer->queries[timer->ret % GPU_QUERY_COUNT], GL_QUERY_RESULT_AVAILABLE, &available); 63 | if (available) { 64 | /* GLuint64 timeElapsed = 0; 65 | glGetQueryObjectui64v(timer->queries[timer->ret % GPU_QUERY_COUNT], GL_QUERY_RESULT, &timeElapsed); 66 | timer->ret++; 67 | if (n < maxTimes) { 68 | times[n] = (float)((double)timeElapsed * 1e-9); 69 | n++; 70 | }*/ 71 | } 72 | } 73 | return n; 74 | } 75 | 76 | 77 | void initGraph(PerfGraph* fps, int style, const char* name) 78 | { 79 | memset(fps, 0, sizeof(PerfGraph)); 80 | fps->style = style; 81 | strncpy(fps->name, name, sizeof(fps->name)); 82 | fps->name[sizeof(fps->name)-1] = '\0'; 83 | } 84 | 85 | void updateGraph(PerfGraph* fps, float frameTime) 86 | { 87 | fps->head = (fps->head+1) % GRAPH_HISTORY_COUNT; 88 | fps->values[fps->head] = frameTime; 89 | } 90 | 91 | float getGraphAverage(PerfGraph* fps) 92 | { 93 | int i; 94 | float avg = 0; 95 | for (i = 0; i < GRAPH_HISTORY_COUNT; i++) { 96 | avg += fps->values[i]; 97 | } 98 | return avg / (float)GRAPH_HISTORY_COUNT; 99 | } 100 | 101 | void renderGraph(NVGcontext* vg, float x, float y, PerfGraph* fps) 102 | { 103 | int i; 104 | float avg, w, h; 105 | char str[64]; 106 | 107 | avg = getGraphAverage(fps); 108 | 109 | w = 200; 110 | h = 35; 111 | 112 | nvgBeginPath(vg); 113 | nvgRect(vg, x,y, w,h); 114 | nvgFillColor(vg, nvgRGBA(0,0,0,128)); 115 | nvgFill(vg); 116 | 117 | nvgBeginPath(vg); 118 | nvgMoveTo(vg, x, y+h); 119 | if (fps->style == GRAPH_RENDER_FPS) { 120 | for (i = 0; i < GRAPH_HISTORY_COUNT; i++) { 121 | float v = 1.0f / (0.00001f + fps->values[(fps->head+i) % GRAPH_HISTORY_COUNT]); 122 | float vx, vy; 123 | if (v > 80.0f) v = 80.0f; 124 | vx = x + ((float)i/(GRAPH_HISTORY_COUNT-1)) * w; 125 | vy = y + h - ((v / 80.0f) * h); 126 | nvgLineTo(vg, vx, vy); 127 | } 128 | } else if (fps->style == GRAPH_RENDER_PERCENT) { 129 | for (i = 0; i < GRAPH_HISTORY_COUNT; i++) { 130 | float v = fps->values[(fps->head+i) % GRAPH_HISTORY_COUNT] * 1.0f; 131 | float vx, vy; 132 | if (v > 100.0f) v = 100.0f; 133 | vx = x + ((float)i/(GRAPH_HISTORY_COUNT-1)) * w; 134 | vy = y + h - ((v / 100.0f) * h); 135 | nvgLineTo(vg, vx, vy); 136 | } 137 | } else { 138 | for (i = 0; i < GRAPH_HISTORY_COUNT; i++) { 139 | float v = fps->values[(fps->head+i) % GRAPH_HISTORY_COUNT] * 1000.0f; 140 | float vx, vy; 141 | if (v > 20.0f) v = 20.0f; 142 | vx = x + ((float)i/(GRAPH_HISTORY_COUNT-1)) * w; 143 | vy = y + h - ((v / 20.0f) * h); 144 | nvgLineTo(vg, vx, vy); 145 | } 146 | } 147 | nvgLineTo(vg, x+w, y+h); 148 | nvgFillColor(vg, nvgRGBA(255,192,0,128)); 149 | nvgFill(vg); 150 | 151 | nvgFontFace(vg, "sans"); 152 | 153 | if (fps->name[0] != '\0') { 154 | nvgFontSize(vg, 14.0f); 155 | nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_TOP); 156 | nvgFillColor(vg, nvgRGBA(240,240,240,192)); 157 | nvgText(vg, x+3,y+1, fps->name, NULL); 158 | } 159 | 160 | if (fps->style == GRAPH_RENDER_FPS) { 161 | nvgFontSize(vg, 18.0f); 162 | nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_TOP); 163 | nvgFillColor(vg, nvgRGBA(240,240,240,255)); 164 | sprintf(str, "%.2f FPS", 1.0f / avg); 165 | nvgText(vg, x+w-3,y+1, str, NULL); 166 | 167 | nvgFontSize(vg, 15.0f); 168 | nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_BOTTOM); 169 | nvgFillColor(vg, nvgRGBA(240,240,240,160)); 170 | sprintf(str, "%.2f ms", avg * 1000.0f); 171 | nvgText(vg, x+w-3,y+h-1, str, NULL); 172 | } 173 | else if (fps->style == GRAPH_RENDER_PERCENT) { 174 | nvgFontSize(vg, 18.0f); 175 | nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_TOP); 176 | nvgFillColor(vg, nvgRGBA(240,240,240,255)); 177 | sprintf(str, "%.1f %%", avg * 1.0f); 178 | nvgText(vg, x+w-3,y+1, str, NULL); 179 | } else { 180 | nvgFontSize(vg, 18.0f); 181 | nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_TOP); 182 | nvgFillColor(vg, nvgRGBA(240,240,240,255)); 183 | sprintf(str, "%.2f ms", avg * 1000.0f); 184 | nvgText(vg, x+w-3,y+1, str, NULL); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /example/perf.h: -------------------------------------------------------------------------------- 1 | #ifndef PERF_H 2 | #define PERF_H 3 | 4 | #include "nanovg.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | enum GraphrenderStyle { 11 | GRAPH_RENDER_FPS, 12 | GRAPH_RENDER_MS, 13 | GRAPH_RENDER_PERCENT, 14 | }; 15 | 16 | #define GRAPH_HISTORY_COUNT 100 17 | struct PerfGraph { 18 | int style; 19 | char name[32]; 20 | float values[GRAPH_HISTORY_COUNT]; 21 | int head; 22 | }; 23 | typedef struct PerfGraph PerfGraph; 24 | 25 | void initGraph(PerfGraph* fps, int style, const char* name); 26 | void updateGraph(PerfGraph* fps, float frameTime); 27 | void renderGraph(NVGcontext* vg, float x, float y, PerfGraph* fps); 28 | float getGraphAverage(PerfGraph* fps); 29 | 30 | #define GPU_QUERY_COUNT 5 31 | struct GPUtimer { 32 | int supported; 33 | int cur, ret; 34 | unsigned int queries[GPU_QUERY_COUNT]; 35 | }; 36 | typedef struct GPUtimer GPUtimer; 37 | 38 | void initGPUTimer(GPUtimer* timer); 39 | void startGPUTimer(GPUtimer* timer); 40 | int stopGPUTimer(GPUtimer* timer, float* times, int maxTimes); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | #endif // PERF_H -------------------------------------------------------------------------------- /game/images/hyptosis_sprites_organized.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/game/images/hyptosis_sprites_organized.png -------------------------------------------------------------------------------- /game/images/hyptosis_til-art-batch-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/game/images/hyptosis_til-art-batch-2.png -------------------------------------------------------------------------------- /game/images/hyptosis_tile-art-batch-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/game/images/hyptosis_tile-art-batch-1.png -------------------------------------------------------------------------------- /game/images/hyptosis_tile-art-batch-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/game/images/hyptosis_tile-art-batch-3.png -------------------------------------------------------------------------------- /game/images/hyptosis_tile-art-batch-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/game/images/hyptosis_tile-art-batch-4.png -------------------------------------------------------------------------------- /game/images/hyptosis_tile-art-batch-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/game/images/hyptosis_tile-art-batch-5.png -------------------------------------------------------------------------------- /images/screenshot-linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/images/screenshot-linux.png -------------------------------------------------------------------------------- /images/screenshot-win.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/images/screenshot-win.jpg -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syoyo/nanocanvas/755312ba6bd25bb167bde222d352bde457546e2e/images/screenshot.png -------------------------------------------------------------------------------- /premake4.lua: -------------------------------------------------------------------------------- 1 | 2 | local action = _ACTION or "" 3 | 4 | solution "nanocanvas" 5 | projectRootDir = os.getcwd() .. "/example/" 6 | dofile ("example/findOpenGLGlewGlut.lua") 7 | initOpenGL() 8 | initGlew() 9 | 10 | location ( "build" ) 11 | configurations { "Debug", "Release" } 12 | platforms {"native", "x64", "x32"} 13 | 14 | project "nanocanvas" 15 | language "C" 16 | kind "StaticLib" 17 | includedirs { "src" } 18 | files { "src/*.c" } 19 | targetdir("build") 20 | defines { "_CRT_SECURE_NO_WARNINGS" } 21 | 22 | configuration "Debug" 23 | defines { "DEBUG" } 24 | flags { "Symbols", "ExtraWarnings"} 25 | 26 | configuration "Release" 27 | defines { "NDEBUG" } 28 | flags { "Optimize", "ExtraWarnings"} 29 | 30 | project "example" 31 | 32 | kind "ConsoleApp" 33 | language "C++" 34 | files { "example/main.cc", "example/perf.c" } 35 | includedirs { "src", "example" } 36 | targetdir("build") 37 | links { "nanocanvas" } 38 | 39 | configuration { "linux" } 40 | files { 41 | "example/OpenGLWindow/X11OpenGLWindow.cpp", 42 | "example/OpenGLWindow/X11OpenGLWindows.h" 43 | } 44 | links {"X11", "pthread", "dl"} 45 | 46 | configuration { "windows" } 47 | defines { "NOMINMAX" } 48 | buildoptions { "/W4" } -- raise compile error level. 49 | files{ 50 | "example/OpenGLWindow/Win32OpenGLWindow.cpp", 51 | "example/OpenGLWindow/Win32OpenGLWindow.h", 52 | "example/OpenGLWindow/Win32Window.cpp", 53 | "example/OpenGLWindow/Win32Window.h", 54 | } 55 | 56 | configuration { "macosx" } 57 | buildoptions { "-fsanitize=address" } 58 | linkoptions { "-fsanitize=address" } 59 | links {"Cocoa.framework"} 60 | files { 61 | "example/OpenGLWindow/MacOpenGLWindow.h", 62 | "example/OpenGLWindow/MacOpenGLWindow.mm", 63 | } 64 | 65 | configuration "Debug" 66 | defines { "DEBUG" } 67 | flags { "Symbols", "ExtraWarnings"} 68 | 69 | configuration "Release" 70 | defines { "NDEBUG" } 71 | flags { "Optimize", "ExtraWarnings"} 72 | 73 | -------------------------------------------------------------------------------- /src/nanovg.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Mikko Mononen memon@inside.org 3 | // 4 | // This software is provided 'as-is', without any express or implied 5 | // warranty. In no event will the authors be held liable for any damages 6 | // arising from the use of this software. 7 | // Permission is granted to anyone to use this software for any purpose, 8 | // including commercial applications, and to alter it and redistribute it 9 | // freely, subject to the following restrictions: 10 | // 1. The origin of this software must not be misrepresented; you must not 11 | // claim that you wrote the original software. If you use this software 12 | // in a product, an acknowledgment in the product documentation would be 13 | // appreciated but is not required. 14 | // 2. Altered source versions must be plainly marked as such, and must not be 15 | // misrepresented as being the original software. 16 | // 3. This notice may not be removed or altered from any source distribution. 17 | // 18 | 19 | #ifndef NANOVG_H 20 | #define NANOVG_H 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #define NVG_PI 3.14159265358979323846264338327f 27 | 28 | #ifdef _MSC_VER 29 | #pragma warning(push) 30 | #pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union 31 | #endif 32 | 33 | typedef struct NVGcontext NVGcontext; 34 | 35 | struct NVGcolor { 36 | union { 37 | float rgba[4]; 38 | struct { 39 | float r,g,b,a; 40 | }; 41 | }; 42 | }; 43 | typedef struct NVGcolor NVGcolor; 44 | 45 | struct NVGpaint { 46 | float xform[6]; 47 | float extent[2]; 48 | float radius; 49 | float feather; 50 | NVGcolor innerColor; 51 | NVGcolor outerColor; 52 | int image; 53 | }; 54 | typedef struct NVGpaint NVGpaint; 55 | 56 | enum NVGwinding { 57 | NVG_CCW = 1, // Winding for solid shapes 58 | NVG_CW = 2, // Winding for holes 59 | }; 60 | 61 | enum NVGsolidity { 62 | NVG_SOLID = 1, // CCW 63 | NVG_HOLE = 2, // CW 64 | }; 65 | 66 | enum NVGlineCap { 67 | NVG_BUTT, 68 | NVG_ROUND, 69 | NVG_SQUARE, 70 | NVG_BEVEL, 71 | NVG_MITER, 72 | }; 73 | 74 | enum NVGalign { 75 | // Horizontal align 76 | NVG_ALIGN_LEFT = 1<<0, // Default, align text horizontally to left. 77 | NVG_ALIGN_CENTER = 1<<1, // Align text horizontally to center. 78 | NVG_ALIGN_RIGHT = 1<<2, // Align text horizontally to right. 79 | // Vertical align 80 | NVG_ALIGN_TOP = 1<<3, // Align text vertically to top. 81 | NVG_ALIGN_MIDDLE = 1<<4, // Align text vertically to middle. 82 | NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom. 83 | NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline. 84 | }; 85 | 86 | enum NVGblendFactor { 87 | NVG_ZERO = 1<<0, 88 | NVG_ONE = 1<<1, 89 | NVG_SRC_COLOR = 1<<2, 90 | NVG_ONE_MINUS_SRC_COLOR = 1<<3, 91 | NVG_DST_COLOR = 1<<4, 92 | NVG_ONE_MINUS_DST_COLOR = 1<<5, 93 | NVG_SRC_ALPHA = 1<<6, 94 | NVG_ONE_MINUS_SRC_ALPHA = 1<<7, 95 | NVG_DST_ALPHA = 1<<8, 96 | NVG_ONE_MINUS_DST_ALPHA = 1<<9, 97 | NVG_SRC_ALPHA_SATURATE = 1<<10, 98 | }; 99 | 100 | enum NVGcompositeOperation { 101 | NVG_SOURCE_OVER, 102 | NVG_SOURCE_IN, 103 | NVG_SOURCE_OUT, 104 | NVG_ATOP, 105 | NVG_DESTINATION_OVER, 106 | NVG_DESTINATION_IN, 107 | NVG_DESTINATION_OUT, 108 | NVG_DESTINATION_ATOP, 109 | NVG_LIGHTER, 110 | NVG_COPY, 111 | NVG_XOR, 112 | }; 113 | 114 | struct NVGcompositeOperationState { 115 | int srcRGB; 116 | int dstRGB; 117 | int srcAlpha; 118 | int dstAlpha; 119 | }; 120 | typedef struct NVGcompositeOperationState NVGcompositeOperationState; 121 | 122 | struct NVGglyphPosition { 123 | const char* str; // Position of the glyph in the input string. 124 | float x; // The x-coordinate of the logical glyph position. 125 | float minx, maxx; // The bounds of the glyph shape. 126 | }; 127 | typedef struct NVGglyphPosition NVGglyphPosition; 128 | 129 | struct NVGtextRow { 130 | const char* start; // Pointer to the input text where the row starts. 131 | const char* end; // Pointer to the input text where the row ends (one past the last character). 132 | const char* next; // Pointer to the beginning of the next row. 133 | float width; // Logical width of the row. 134 | float minx, maxx; // Actual bounds of the row. Logical with and bounds can differ because of kerning and some parts over extending. 135 | }; 136 | typedef struct NVGtextRow NVGtextRow; 137 | 138 | enum NVGimageFlags { 139 | NVG_IMAGE_GENERATE_MIPMAPS = 1<<0, // Generate mipmaps during creation of the image. 140 | NVG_IMAGE_REPEATX = 1<<1, // Repeat image in X direction. 141 | NVG_IMAGE_REPEATY = 1<<2, // Repeat image in Y direction. 142 | NVG_IMAGE_FLIPY = 1<<3, // Flips (inverses) image in Y direction when rendered. 143 | NVG_IMAGE_PREMULTIPLIED = 1<<4, // Image data has premultiplied alpha. 144 | }; 145 | 146 | // Begin drawing a new frame 147 | // Calls to nanovg drawing API should be wrapped in nvgBeginFrame() & nvgEndFrame() 148 | // nvgBeginFrame() defines the size of the window to render to in relation currently 149 | // set viewport (i.e. glViewport on GL backends). Device pixel ration allows to 150 | // control the rendering on Hi-DPI devices. 151 | // For example, GLFW returns two dimension for an opened window: window size and 152 | // frame buffer size. In that case you would set windowWidth/Height to the window size 153 | // devicePixelRatio to: frameBufferWidth / windowWidth. 154 | void nvgBeginFrame(NVGcontext* ctx, int windowWidth, int windowHeight, float devicePixelRatio); 155 | 156 | // Cancels drawing the current frame. 157 | void nvgCancelFrame(NVGcontext* ctx); 158 | 159 | // Ends drawing flushing remaining render state. 160 | void nvgEndFrame(NVGcontext* ctx); 161 | 162 | // 163 | // Composite operation 164 | // 165 | // The composite operations in NanoVG are modeled after HTML Canvas API, and 166 | // the blend func is based on OpenGL (see corresponding manuals for more info). 167 | // The colors in the blending state have premultiplied alpha. 168 | 169 | // Sets the composite operation. The op parameter should be one of NVGcompositeOperation. 170 | void nvgGlobalCompositeOperation(NVGcontext* ctx, int op); 171 | 172 | // Sets the composite operation with custom pixel arithmetic. The parameters should be one of NVGblendFactor. 173 | void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor); 174 | 175 | // Sets the composite operation with custom pixel arithmetic for RGB and alpha components separately. The parameters should be one of NVGblendFactor. 176 | void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha); 177 | 178 | // 179 | // Color utils 180 | // 181 | // Colors in NanoVG are stored as unsigned ints in ABGR format. 182 | 183 | // Returns a color value from red, green, blue values. Alpha will be set to 255 (1.0f). 184 | NVGcolor nvgRGB(unsigned char r, unsigned char g, unsigned char b); 185 | 186 | // Returns a color value from red, green, blue values. Alpha will be set to 1.0f. 187 | NVGcolor nvgRGBf(float r, float g, float b); 188 | 189 | 190 | // Returns a color value from red, green, blue and alpha values. 191 | NVGcolor nvgRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a); 192 | 193 | // Returns a color value from red, green, blue and alpha values. 194 | NVGcolor nvgRGBAf(float r, float g, float b, float a); 195 | 196 | 197 | // Linearly interpolates from color c0 to c1, and returns resulting color value. 198 | NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u); 199 | 200 | // Sets transparency of a color value. 201 | NVGcolor nvgTransRGBA(NVGcolor c0, unsigned char a); 202 | 203 | // Sets transparency of a color value. 204 | NVGcolor nvgTransRGBAf(NVGcolor c0, float a); 205 | 206 | // Returns color value specified by hue, saturation and lightness. 207 | // HSL values are all in range [0..1], alpha will be set to 255. 208 | NVGcolor nvgHSL(float h, float s, float l); 209 | 210 | // Returns color value specified by hue, saturation and lightness and alpha. 211 | // HSL values are all in range [0..1], alpha in range [0..255] 212 | NVGcolor nvgHSLA(float h, float s, float l, unsigned char a); 213 | 214 | // 215 | // State Handling 216 | // 217 | // NanoVG contains state which represents how paths will be rendered. 218 | // The state contains transform, fill and stroke styles, text and font styles, 219 | // and scissor clipping. 220 | 221 | // Pushes and saves the current render state into a state stack. 222 | // A matching nvgRestore() must be used to restore the state. 223 | void nvgSave(NVGcontext* ctx); 224 | 225 | // Pops and restores current render state. 226 | void nvgRestore(NVGcontext* ctx); 227 | 228 | // Resets current render state to default values. Does not affect the render state stack. 229 | void nvgReset(NVGcontext* ctx); 230 | 231 | // 232 | // Render styles 233 | // 234 | // Fill and stroke render style can be either a solid color or a paint which is a gradient or a pattern. 235 | // Solid color is simply defined as a color value, different kinds of paints can be created 236 | // using nvgLinearGradient(), nvgBoxGradient(), nvgRadialGradient() and nvgImagePattern(). 237 | // 238 | // Current render style can be saved and restored using nvgSave() and nvgRestore(). 239 | 240 | // Sets current stroke style to a solid color. 241 | void nvgStrokeColor(NVGcontext* ctx, NVGcolor color); 242 | 243 | // Sets current stroke style to a paint, which can be a one of the gradients or a pattern. 244 | void nvgStrokePaint(NVGcontext* ctx, NVGpaint paint); 245 | 246 | // Sets current fill style to a solid color. 247 | void nvgFillColor(NVGcontext* ctx, NVGcolor color); 248 | 249 | // Sets current fill style to a paint, which can be a one of the gradients or a pattern. 250 | void nvgFillPaint(NVGcontext* ctx, NVGpaint paint); 251 | 252 | // Sets the miter limit of the stroke style. 253 | // Miter limit controls when a sharp corner is beveled. 254 | void nvgMiterLimit(NVGcontext* ctx, float limit); 255 | 256 | // Sets the stroke width of the stroke style. 257 | void nvgStrokeWidth(NVGcontext* ctx, float size); 258 | 259 | // Sets how the end of the line (cap) is drawn, 260 | // Can be one of: NVG_BUTT (default), NVG_ROUND, NVG_SQUARE. 261 | void nvgLineCap(NVGcontext* ctx, int cap); 262 | 263 | // Sets how sharp path corners are drawn. 264 | // Can be one of NVG_MITER (default), NVG_ROUND, NVG_BEVEL. 265 | void nvgLineJoin(NVGcontext* ctx, int join); 266 | 267 | // Sets the transparency applied to all rendered shapes. 268 | // Already transparent paths will get proportionally more transparent as well. 269 | void nvgGlobalAlpha(NVGcontext* ctx, float alpha); 270 | 271 | // 272 | // Transforms 273 | // 274 | // The paths, gradients, patterns and scissor region are transformed by an transformation 275 | // matrix at the time when they are passed to the API. 276 | // The current transformation matrix is a affine matrix: 277 | // [sx kx tx] 278 | // [ky sy ty] 279 | // [ 0 0 1] 280 | // Where: sx,sy define scaling, kx,ky skewing, and tx,ty translation. 281 | // The last row is assumed to be 0,0,1 and is not stored. 282 | // 283 | // Apart from nvgResetTransform(), each transformation function first creates 284 | // specific transformation matrix and pre-multiplies the current transformation by it. 285 | // 286 | // Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore(). 287 | 288 | // Resets current transform to a identity matrix. 289 | void nvgResetTransform(NVGcontext* ctx); 290 | 291 | // Premultiplies current coordinate system by specified matrix. 292 | // The parameters are interpreted as matrix as follows: 293 | // [a c e] 294 | // [b d f] 295 | // [0 0 1] 296 | void nvgTransform(NVGcontext* ctx, float a, float b, float c, float d, float e, float f); 297 | 298 | // Translates current coordinate system. 299 | void nvgTranslate(NVGcontext* ctx, float x, float y); 300 | 301 | // Rotates current coordinate system. Angle is specified in radians. 302 | void nvgRotate(NVGcontext* ctx, float angle); 303 | 304 | // Skews the current coordinate system along X axis. Angle is specified in radians. 305 | void nvgSkewX(NVGcontext* ctx, float angle); 306 | 307 | // Skews the current coordinate system along Y axis. Angle is specified in radians. 308 | void nvgSkewY(NVGcontext* ctx, float angle); 309 | 310 | // Scales the current coordinate system. 311 | void nvgScale(NVGcontext* ctx, float x, float y); 312 | 313 | // Stores the top part (a-f) of the current transformation matrix in to the specified buffer. 314 | // [a c e] 315 | // [b d f] 316 | // [0 0 1] 317 | // There should be space for 6 floats in the return buffer for the values a-f. 318 | void nvgCurrentTransform(NVGcontext* ctx, float* xform); 319 | 320 | 321 | // The following functions can be used to make calculations on 2x3 transformation matrices. 322 | // A 2x3 matrix is represented as float[6]. 323 | 324 | // Sets the transform to identity matrix. 325 | void nvgTransformIdentity(float* dst); 326 | 327 | // Sets the transform to translation matrix matrix. 328 | void nvgTransformTranslate(float* dst, float tx, float ty); 329 | 330 | // Sets the transform to scale matrix. 331 | void nvgTransformScale(float* dst, float sx, float sy); 332 | 333 | // Sets the transform to rotate matrix. Angle is specified in radians. 334 | void nvgTransformRotate(float* dst, float a); 335 | 336 | // Sets the transform to skew-x matrix. Angle is specified in radians. 337 | void nvgTransformSkewX(float* dst, float a); 338 | 339 | // Sets the transform to skew-y matrix. Angle is specified in radians. 340 | void nvgTransformSkewY(float* dst, float a); 341 | 342 | // Sets the transform to the result of multiplication of two transforms, of A = A*B. 343 | void nvgTransformMultiply(float* dst, const float* src); 344 | 345 | // Sets the transform to the result of multiplication of two transforms, of A = B*A. 346 | void nvgTransformPremultiply(float* dst, const float* src); 347 | 348 | // Sets the destination to inverse of specified transform. 349 | // Returns 1 if the inverse could be calculated, else 0. 350 | int nvgTransformInverse(float* dst, const float* src); 351 | 352 | // Transform a point by given transform. 353 | void nvgTransformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy); 354 | 355 | // Converts degrees to radians and vice versa. 356 | float nvgDegToRad(float deg); 357 | float nvgRadToDeg(float rad); 358 | 359 | // 360 | // Images 361 | // 362 | // NanoVG allows you to load jpg, png, psd, tga, pic and gif files to be used for rendering. 363 | // In addition you can upload your own image. The image loading is provided by stb_image. 364 | // The parameter imageFlags is combination of flags defined in NVGimageFlags. 365 | 366 | // Creates image by loading it from the disk from specified file name. 367 | // Returns handle to the image. 368 | int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags); 369 | 370 | // Creates image by loading it from the specified chunk of memory. 371 | // Returns handle to the image. 372 | int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata); 373 | 374 | // Creates image from specified image data. 375 | // Returns handle to the image. 376 | int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data); 377 | 378 | // Updates image data specified by image handle. 379 | void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data); 380 | 381 | // Returns the dimensions of a created image. 382 | void nvgImageSize(NVGcontext* ctx, int image, int* w, int* h); 383 | 384 | // Deletes created image. 385 | void nvgDeleteImage(NVGcontext* ctx, int image); 386 | 387 | // 388 | // Paints 389 | // 390 | // NanoVG supports four types of paints: linear gradient, box gradient, radial gradient and image pattern. 391 | // These can be used as paints for strokes and fills. 392 | 393 | // Creates and returns a linear gradient. Parameters (sx,sy)-(ex,ey) specify the start and end coordinates 394 | // of the linear gradient, icol specifies the start color and ocol the end color. 395 | // The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). 396 | NVGpaint nvgLinearGradient(NVGcontext* ctx, float sx, float sy, float ex, float ey, 397 | NVGcolor icol, NVGcolor ocol); 398 | 399 | // Creates and returns a box gradient. Box gradient is a feathered rounded rectangle, it is useful for rendering 400 | // drop shadows or highlights for boxes. Parameters (x,y) define the top-left corner of the rectangle, 401 | // (w,h) define the size of the rectangle, r defines the corner radius, and f feather. Feather defines how blurry 402 | // the border of the rectangle is. Parameter icol specifies the inner color and ocol the outer color of the gradient. 403 | // The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). 404 | NVGpaint nvgBoxGradient(NVGcontext* ctx, float x, float y, float w, float h, 405 | float r, float f, NVGcolor icol, NVGcolor ocol); 406 | 407 | // Creates and returns a radial gradient. Parameters (cx,cy) specify the center, inr and outr specify 408 | // the inner and outer radius of the gradient, icol specifies the start color and ocol the end color. 409 | // The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). 410 | NVGpaint nvgRadialGradient(NVGcontext* ctx, float cx, float cy, float inr, float outr, 411 | NVGcolor icol, NVGcolor ocol); 412 | 413 | // Creates and returns an image patter. Parameters (ox,oy) specify the left-top location of the image pattern, 414 | // (ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render. 415 | // The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). 416 | NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey, 417 | float angle, int image, float alpha); 418 | 419 | // 420 | // Scissoring 421 | // 422 | // Scissoring allows you to clip the rendering into a rectangle. This is useful for various 423 | // user interface cases like rendering a text edit or a timeline. 424 | 425 | // Sets the current scissor rectangle. 426 | // The scissor rectangle is transformed by the current transform. 427 | void nvgScissor(NVGcontext* ctx, float x, float y, float w, float h); 428 | 429 | // Intersects current scissor rectangle with the specified rectangle. 430 | // The scissor rectangle is transformed by the current transform. 431 | // Note: in case the rotation of previous scissor rect differs from 432 | // the current one, the intersection will be done between the specified 433 | // rectangle and the previous scissor rectangle transformed in the current 434 | // transform space. The resulting shape is always rectangle. 435 | void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h); 436 | 437 | // Reset and disables scissoring. 438 | void nvgResetScissor(NVGcontext* ctx); 439 | 440 | // 441 | // Paths 442 | // 443 | // Drawing a new shape starts with nvgBeginPath(), it clears all the currently defined paths. 444 | // Then you define one or more paths and sub-paths which describe the shape. The are functions 445 | // to draw common shapes like rectangles and circles, and lower level step-by-step functions, 446 | // which allow to define a path curve by curve. 447 | // 448 | // NanoVG uses even-odd fill rule to draw the shapes. Solid shapes should have counter clockwise 449 | // winding and holes should have counter clockwise order. To specify winding of a path you can 450 | // call nvgPathWinding(). This is useful especially for the common shapes, which are drawn CCW. 451 | // 452 | // Finally you can fill the path using current fill style by calling nvgFill(), and stroke it 453 | // with current stroke style by calling nvgStroke(). 454 | // 455 | // The curve segments and sub-paths are transformed by the current transform. 456 | 457 | // Clears the current path and sub-paths. 458 | void nvgBeginPath(NVGcontext* ctx); 459 | 460 | // Starts new sub-path with specified point as first point. 461 | void nvgMoveTo(NVGcontext* ctx, float x, float y); 462 | 463 | // Adds line segment from the last point in the path to the specified point. 464 | void nvgLineTo(NVGcontext* ctx, float x, float y); 465 | 466 | // Adds cubic bezier segment from last point in the path via two control points to the specified point. 467 | void nvgBezierTo(NVGcontext* ctx, float c1x, float c1y, float c2x, float c2y, float x, float y); 468 | 469 | // Adds quadratic bezier segment from last point in the path via a control point to the specified point. 470 | void nvgQuadTo(NVGcontext* ctx, float cx, float cy, float x, float y); 471 | 472 | // Adds an arc segment at the corner defined by the last path point, and two specified points. 473 | void nvgArcTo(NVGcontext* ctx, float x1, float y1, float x2, float y2, float radius); 474 | 475 | // Closes current sub-path with a line segment. 476 | void nvgClosePath(NVGcontext* ctx); 477 | 478 | // Sets the current sub-path winding, see NVGwinding and NVGsolidity. 479 | void nvgPathWinding(NVGcontext* ctx, int dir); 480 | 481 | // Creates new circle arc shaped sub-path. The arc center is at cx,cy, the arc radius is r, 482 | // and the arc is drawn from angle a0 to a1, and swept in direction dir (NVG_CCW, or NVG_CW). 483 | // Angles are specified in radians. 484 | void nvgArc(NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir); 485 | 486 | // Creates new rectangle shaped sub-path. 487 | void nvgRect(NVGcontext* ctx, float x, float y, float w, float h); 488 | 489 | // Creates new rounded rectangle shaped sub-path. 490 | void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r); 491 | 492 | // Creates new rounded rectangle shaped sub-path with varying radii for each corner. 493 | void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft); 494 | 495 | // Creates new ellipse shaped sub-path. 496 | void nvgEllipse(NVGcontext* ctx, float cx, float cy, float rx, float ry); 497 | 498 | // Creates new circle shaped sub-path. 499 | void nvgCircle(NVGcontext* ctx, float cx, float cy, float r); 500 | 501 | // Fills the current path with current fill style. 502 | void nvgFill(NVGcontext* ctx); 503 | 504 | // Fills the current path with current stroke style. 505 | void nvgStroke(NVGcontext* ctx); 506 | 507 | 508 | // 509 | // Text 510 | // 511 | // NanoVG allows you to load .ttf files and use the font to render text. 512 | // 513 | // The appearance of the text can be defined by setting the current text style 514 | // and by specifying the fill color. Common text and font settings such as 515 | // font size, letter spacing and text align are supported. Font blur allows you 516 | // to create simple text effects such as drop shadows. 517 | // 518 | // At render time the font face can be set based on the font handles or name. 519 | // 520 | // Font measure functions return values in local space, the calculations are 521 | // carried in the same resolution as the final rendering. This is done because 522 | // the text glyph positions are snapped to the nearest pixels sharp rendering. 523 | // 524 | // The local space means that values are not rotated or scale as per the current 525 | // transformation. For example if you set font size to 12, which would mean that 526 | // line height is 16, then regardless of the current scaling and rotation, the 527 | // returned line height is always 16. Some measures may vary because of the scaling 528 | // since aforementioned pixel snapping. 529 | // 530 | // While this may sound a little odd, the setup allows you to always render the 531 | // same way regardless of scaling. I.e. following works regardless of scaling: 532 | // 533 | // const char* txt = "Text me up."; 534 | // nvgTextBounds(vg, x,y, txt, NULL, bounds); 535 | // nvgBeginPath(vg); 536 | // nvgRoundedRect(vg, bounds[0],bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]); 537 | // nvgFill(vg); 538 | // 539 | // Note: currently only solid color fill is supported for text. 540 | 541 | // Creates font by loading it from the disk from specified file name. 542 | // Returns handle to the font. 543 | int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename); 544 | 545 | // Creates font by loading it from the specified memory chunk. 546 | // Returns handle to the font. 547 | int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData); 548 | 549 | // Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found. 550 | int nvgFindFont(NVGcontext* ctx, const char* name); 551 | 552 | // Adds a fallback font by handle. 553 | int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont); 554 | 555 | // Adds a fallback font by name. 556 | int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont); 557 | 558 | // Sets the font size of current text style. 559 | void nvgFontSize(NVGcontext* ctx, float size); 560 | 561 | // Sets the blur of current text style. 562 | void nvgFontBlur(NVGcontext* ctx, float blur); 563 | 564 | // Sets the letter spacing of current text style. 565 | void nvgTextLetterSpacing(NVGcontext* ctx, float spacing); 566 | 567 | // Sets the proportional line height of current text style. The line height is specified as multiple of font size. 568 | void nvgTextLineHeight(NVGcontext* ctx, float lineHeight); 569 | 570 | // Sets the text align of current text style, see NVGalign for options. 571 | void nvgTextAlign(NVGcontext* ctx, int align); 572 | 573 | // Sets the font face based on specified id of current text style. 574 | void nvgFontFaceId(NVGcontext* ctx, int font); 575 | 576 | // Sets the font face based on specified name of current text style. 577 | void nvgFontFace(NVGcontext* ctx, const char* font); 578 | 579 | // Draws text string at specified location. If end is specified only the sub-string up to the end is drawn. 580 | float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* end); 581 | 582 | // Draws multi-line text string at specified location wrapped at the specified width. If end is specified only the sub-string up to the end is drawn. 583 | // White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered. 584 | // Words longer than the max width are slit at nearest character (i.e. no hyphenation). 585 | void nvgTextBox(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end); 586 | 587 | // Measures the specified text string. Parameter bounds should be a pointer to float[4], 588 | // if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax] 589 | // Returns the horizontal advance of the measured text (i.e. where the next character should drawn). 590 | // Measured values are returned in local coordinate space. 591 | float nvgTextBounds(NVGcontext* ctx, float x, float y, const char* string, const char* end, float* bounds); 592 | 593 | // Measures the specified multi-text string. Parameter bounds should be a pointer to float[4], 594 | // if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax] 595 | // Measured values are returned in local coordinate space. 596 | void nvgTextBoxBounds(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds); 597 | 598 | // Calculates the glyph x positions of the specified text. If end is specified only the sub-string will be used. 599 | // Measured values are returned in local coordinate space. 600 | int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string, const char* end, NVGglyphPosition* positions, int maxPositions); 601 | 602 | // Returns the vertical metrics based on the current text style. 603 | // Measured values are returned in local coordinate space. 604 | void nvgTextMetrics(NVGcontext* ctx, float* ascender, float* descender, float* lineh); 605 | 606 | // Breaks the specified text into lines. If end is specified only the sub-string will be used. 607 | // White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered. 608 | // Words longer than the max width are slit at nearest character (i.e. no hyphenation). 609 | int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, float breakRowWidth, NVGtextRow* rows, int maxRows); 610 | 611 | // 612 | // Internal Render API 613 | // 614 | enum NVGtexture { 615 | NVG_TEXTURE_ALPHA = 0x01, 616 | NVG_TEXTURE_RGBA = 0x02, 617 | }; 618 | 619 | struct NVGscissor { 620 | float xform[6]; 621 | float extent[2]; 622 | }; 623 | typedef struct NVGscissor NVGscissor; 624 | 625 | struct NVGvertex { 626 | float x,y,u,v; 627 | }; 628 | typedef struct NVGvertex NVGvertex; 629 | 630 | struct NVGpath { 631 | int first; 632 | int count; 633 | unsigned char closed; 634 | int nbevel; 635 | NVGvertex* fill; 636 | int nfill; 637 | NVGvertex* stroke; 638 | int nstroke; 639 | int winding; 640 | int convex; 641 | }; 642 | typedef struct NVGpath NVGpath; 643 | 644 | struct NVGparams { 645 | void* userPtr; 646 | int edgeAntiAlias; 647 | int (*renderCreate)(void* uptr); 648 | int (*renderCreateTexture)(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data); 649 | int (*renderDeleteTexture)(void* uptr, int image); 650 | int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data); 651 | int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h); 652 | void (*renderViewport)(void* uptr, int width, int height, float devicePixelRatio); 653 | void (*renderCancel)(void* uptr); 654 | void (*renderFlush)(void* uptr, NVGcompositeOperationState compositeOperation); 655 | void (*renderFill)(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths); 656 | void (*renderStroke)(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths); 657 | void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts); 658 | void (*renderDelete)(void* uptr); 659 | }; 660 | typedef struct NVGparams NVGparams; 661 | 662 | // Constructor and destructor, called by the render back-end. 663 | NVGcontext* nvgCreateInternal(NVGparams* params); 664 | void nvgDeleteInternal(NVGcontext* ctx); 665 | 666 | NVGparams* nvgInternalParams(NVGcontext* ctx); 667 | 668 | // Debug function to dump cached path data. 669 | void nvgDebugDumpPathCache(NVGcontext* ctx); 670 | 671 | #ifdef _MSC_VER 672 | #pragma warning(pop) 673 | #endif 674 | 675 | #define NVG_NOTUSED(v) for (;;) { (void)(1 ? (void)0 : ( (void)(v) ) ); break; } 676 | 677 | #ifdef __cplusplus 678 | } 679 | #endif 680 | 681 | #endif // NANOVG_H 682 | -------------------------------------------------------------------------------- /src/nanovg_gl_utils.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2009-2013 Mikko Mononen memon@inside.org 3 | // 4 | // This software is provided 'as-is', without any express or implied 5 | // warranty. In no event will the authors be held liable for any damages 6 | // arising from the use of this software. 7 | // Permission is granted to anyone to use this software for any purpose, 8 | // including commercial applications, and to alter it and redistribute it 9 | // freely, subject to the following restrictions: 10 | // 1. The origin of this software must not be misrepresented; you must not 11 | // claim that you wrote the original software. If you use this software 12 | // in a product, an acknowledgment in the product documentation would be 13 | // appreciated but is not required. 14 | // 2. Altered source versions must be plainly marked as such, and must not be 15 | // misrepresented as being the original software. 16 | // 3. This notice may not be removed or altered from any source distribution. 17 | // 18 | #ifndef NANOVG_GL_UTILS_H 19 | #define NANOVG_GL_UTILS_H 20 | 21 | struct NVGLUframebuffer { 22 | NVGcontext* ctx; 23 | GLuint fbo; 24 | GLuint rbo; 25 | GLuint texture; 26 | int image; 27 | }; 28 | typedef struct NVGLUframebuffer NVGLUframebuffer; 29 | 30 | // Helper function to create GL frame buffer to render to. 31 | void nvgluBindFramebuffer(NVGLUframebuffer* fb); 32 | NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags); 33 | void nvgluDeleteFramebuffer(NVGLUframebuffer* fb); 34 | 35 | #endif // NANOVG_GL_UTILS_H 36 | 37 | #ifdef NANOVG_GL_IMPLEMENTATION 38 | 39 | #if defined(NANOVG_GL3) || defined(NANOVG_GLES2) || defined(NANOVG_GLES3) 40 | // FBO is core in OpenGL 3>. 41 | # define NANOVG_FBO_VALID 1 42 | #elif defined(NANOVG_GL2) 43 | // On OS X including glext defines FBO on GL2 too. 44 | # ifdef __APPLE__ 45 | # include 46 | # define NANOVG_FBO_VALID 1 47 | # endif 48 | #endif 49 | 50 | static GLint defaultFBO = -1; 51 | 52 | NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags) 53 | { 54 | #ifdef NANOVG_FBO_VALID 55 | GLint defaultFBO; 56 | GLint defaultRBO; 57 | NVGLUframebuffer* fb = NULL; 58 | 59 | glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); 60 | glGetIntegerv(GL_RENDERBUFFER_BINDING, &defaultRBO); 61 | 62 | fb = (NVGLUframebuffer*)malloc(sizeof(NVGLUframebuffer)); 63 | if (fb == NULL) goto error; 64 | memset(fb, 0, sizeof(NVGLUframebuffer)); 65 | 66 | fb->image = nvgCreateImageRGBA(ctx, w, h, imageFlags | NVG_IMAGE_FLIPY | NVG_IMAGE_PREMULTIPLIED, NULL); 67 | 68 | #if defined NANOVG_GL2 69 | fb->texture = nvglImageHandleGL2(ctx, fb->image); 70 | #elif defined NANOVG_GL3 71 | fb->texture = nvglImageHandleGL3(ctx, fb->image); 72 | #elif defined NANOVG_GLES2 73 | fb->texture = nvglImageHandleGLES2(ctx, fb->image); 74 | #elif defined NANOVG_GLES3 75 | fb->texture = nvglImageHandleGLES3(ctx, fb->image); 76 | #endif 77 | 78 | fb->ctx = ctx; 79 | 80 | // frame buffer object 81 | glGenFramebuffers(1, &fb->fbo); 82 | glBindFramebuffer(GL_FRAMEBUFFER, fb->fbo); 83 | 84 | // render buffer object 85 | glGenRenderbuffers(1, &fb->rbo); 86 | glBindRenderbuffer(GL_RENDERBUFFER, fb->rbo); 87 | glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, w, h); 88 | 89 | // combine all 90 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0); 91 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo); 92 | 93 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) goto error; 94 | 95 | glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); 96 | glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO); 97 | return fb; 98 | error: 99 | glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); 100 | glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO); 101 | nvgluDeleteFramebuffer(fb); 102 | return NULL; 103 | #else 104 | NVG_NOTUSED(ctx); 105 | NVG_NOTUSED(w); 106 | NVG_NOTUSED(h); 107 | NVG_NOTUSED(imageFlags); 108 | return NULL; 109 | #endif 110 | } 111 | 112 | void nvgluBindFramebuffer(NVGLUframebuffer* fb) 113 | { 114 | #ifdef NANOVG_FBO_VALID 115 | if (defaultFBO == -1) glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); 116 | glBindFramebuffer(GL_FRAMEBUFFER, fb != NULL ? fb->fbo : defaultFBO); 117 | #else 118 | NVG_NOTUSED(fb); 119 | #endif 120 | } 121 | 122 | void nvgluDeleteFramebuffer(NVGLUframebuffer* fb) 123 | { 124 | #ifdef NANOVG_FBO_VALID 125 | if (fb == NULL) return; 126 | if (fb->fbo != 0) 127 | glDeleteFramebuffers(1, &fb->fbo); 128 | if (fb->rbo != 0) 129 | glDeleteRenderbuffers(1, &fb->rbo); 130 | if (fb->image >= 0) 131 | nvgDeleteImage(fb->ctx, fb->image); 132 | fb->ctx = NULL; 133 | fb->fbo = 0; 134 | fb->rbo = 0; 135 | fb->texture = 0; 136 | fb->image = -1; 137 | free(fb); 138 | #else 139 | NVG_NOTUSED(fb); 140 | #endif 141 | } 142 | 143 | #endif // NANOVG_GL_IMPLEMENTATION 144 | --------------------------------------------------------------------------------