1 /* 2 * BSD 3-Clause License 3 * 4 * Copyright (c) 2016, Mango-Engine Team 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * * Redistributions of source code must retain the above copyright notice, this 11 * list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * * Neither the name of the copyright holder nor the names of its 18 * contributors may be used to endorse or promote products derived from 19 * this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 module mango_engine.graphics.window; 33 34 import mango_engine.util; 35 import mango_engine.game; 36 import mango_engine.event.graphics; 37 import mango_engine.graphics.renderer; 38 39 import mango_stl.misc; 40 41 /// Represents different screen sync types 42 enum SyncType { 43 /// No sync 44 SYNC_NONE, 45 /// Vertical Sync (double/triple buffering) 46 SYNC_VSYNC, 47 /// Adaptive Sync (G-Sync, FreeSync) 48 SYNC_ADAPTIVE 49 } 50 51 /// Thrown when there is an error creating the Window context. 52 class WindowContextFailedException : Exception { 53 this(in string message) { 54 super(message); 55 } 56 } 57 58 // TODO: Seperate input handling into a seperate InputManager? 59 alias InputHook = void delegate() @system; 60 61 /// Backend interface class: represents a window. 62 abstract class Window { 63 immutable SyncType syncType; 64 65 private shared GameManager _game; 66 private shared Renderer _renderer; 67 68 private shared string _title; 69 private shared uint _width; 70 private shared uint _height; 71 private shared bool _visible = false; 72 73 @property protected GameManager game() @trusted nothrow { return cast(GameManager) _game; } 74 @property protected Renderer renderer() @trusted nothrow { return cast(Renderer) _renderer; } 75 76 /// The title of the Window. 77 @property string title() @safe nothrow { return _title; } 78 /// The title of the Window. 79 @property void title(in string title) @trusted { 80 _title = title; // TODO: concurrency fixes! 81 game.eventManager.fireEvent(new WindowTitleChangeEvent(title, this)); 82 setTitle_(title); 83 } 84 85 /// The width of the window in pixels. 86 @property uint width() @safe nothrow { return _width; } 87 /// The height of the window in pixels. 88 @property uint height() @safe nothrow { return _height; } 89 /// If the window is currently being displayed. 90 @property bool visible() @safe nothrow { return _visible; } 91 /// Show or hide the window. 92 @property void visible(bool visible) @trusted { 93 _visible = visible; 94 game.eventManager.fireEvent(visible ? new WindowShowEvent(this) : new WindowShowEvent(this)); 95 setVisible_(visible); 96 } 97 98 protected this(Renderer renderer, in string title, in uint width, in uint height, SyncType syncType) @trusted nothrow { 99 this._renderer = cast(shared) renderer; 100 this.syncType = syncType; 101 102 this._title = title; 103 this._width = width; 104 this._height = height; 105 } 106 107 static Window build(Renderer renderer, in string title, in uint width, in uint height, SyncType syncType) { 108 mixin(InterfaceClassFactory!("window", "Window", "renderer, title, width, height, syncType")); 109 } 110 111 /++ 112 FOR INTERNAL USE!!! 113 114 Because a Window instance is created before a 115 GameManager instance exists, the GameManager needs 116 to notify the Window class that it has been created, 117 and pass an instance of itself to the window. 118 +/ 119 void gamemanager_notify(GameManager game) @trusted 120 in { 121 assert(_game is null, "Tried to set GameManager when it was already set."); 122 } body { 123 this._game = cast(shared) game; 124 onGamemanager_notify(); 125 } 126 127 protected abstract void onGamemanager_notify() @system; 128 protected abstract void setTitle_(in string title) @system; 129 protected abstract void setVisible_(in bool visible) @system; 130 protected abstract void resize_(in uint width, in uint height) @system; 131 }