1 /++Authors: meatRay+/ 2 module meatbox.window; 3 4 public import derelict.opengl3.gl; 5 public import derelict.opengl3.gl3; 6 import derelict.sdl2.sdl; 7 import core.thread; 8 9 import meatbox.keyboard; 10 import meatbox.mouse; 11 import meatbox.frame; 12 13 static this() 14 { 15 DerelictGL3.load(); 16 DerelictGL.load(); 17 DerelictSDL2.load(); 18 } 19 20 //Port User functions to Frame? 21 //-Removes unneeded mucking about in hyperspace. 22 /++ Encapsulates state-based OpenGL and SDL2 into something much more friendly.+/ 23 public class Window 24 { 25 private: 26 SDL_Window* _window; 27 SDL_GLContext _context; 28 SDL_Event _wndwEvnt; 29 Thread _updateThread; 30 Keyboard _keyboard; 31 bool _running; 32 int _width, _height; 33 uint _mspf =16, _mspu =16; 34 35 void setSize( int width, int height ) 36 { 37 this._width =width; 38 this._height =height; 39 } 40 void runUpdate() 41 { 42 while( this._running ) 43 { 44 this.update(); 45 Thread.sleep( dur!("msecs")( _mspu ) ); 46 } 47 } 48 49 protected: 50 /++ Returns: Renders made each second.+/ 51 uint framesPerSecond() @property const 52 { return 1000 /_mspf; } 53 /++ Returns: Updates made each second.+/ 54 uint updatesPerSecond() @property const 55 { return 1000 /_mspu; } 56 /++ Override to specify update behaviour. 57 + Called by the Worker-thread to run non-visual updates.+/ 58 void update() 59 { this.onUpdate(); } 60 /++ 61 + Override to specify Render behaviour. 62 + Called once for each frame per second. 63 +/ 64 void render() 65 { this.onRender(); } 66 /++ Override to specify loading behaviour.+/ 67 void load() 68 { this.onLoad(); } 69 /++ Override to specify unique actions on SDL events.+/ 70 void processEvent( SDL_Event event ) 71 {} 72 73 public: 74 Frame currentFrame; 75 /++ Override to specify resizing behaviour.+/ 76 void resize( int width, int height ) 77 { 78 //Make a resize-stack. 79 this.onResize(); 80 this.setSize( width, height ); 81 this.currentFrame.renderContext()( width, height ); 82 } 83 /++ Returns: Reference to keyboard state.+/ 84 Keyboard keyboard() @property 85 { return this._keyboard; } 86 /++ Returns: Window width in pixels+/ 87 int width() @property const 88 { return this._width; } 89 /++ Returns: Window height in pixels+/ 90 int height() @property const 91 { return this._height; } 92 /// 93 float aspectRatio() @property const 94 { return cast(float)this._width /_height; } 95 /++ Halt running.+/ 96 void quit() 97 { this._running = false; } 98 /// 99 void run( ubyte fps, ubyte ups ) 100 { 101 this._mspu =1000 /ups; 102 this._mspf =1000 /fps; 103 run(); 104 } 105 /// 106 void run( ubyte fps ) 107 { 108 run( fps, fps); 109 } 110 /// 111 void run() 112 { 113 this.load(); 114 this.resize( _width, _height ); 115 _running = true; 116 117 _updateThread = new Thread( &runUpdate ); 118 _updateThread.start(); 119 120 while( _running) 121 { 122 while( SDL_PollEvent( &_wndwEvnt ) == 1) 123 { 124 switch ( _wndwEvnt.type ) 125 { 126 case( SDL_WINDOWEVENT ): 127 if( _wndwEvnt.window.event == SDL_WINDOWEVENT_RESIZED ) 128 { 129 this.resize( _wndwEvnt.window.data1, _wndwEvnt.window.data2 ); 130 this.currentFrame.renderContext()( width, height ); 131 } 132 break; 133 case( SDL_QUIT ): 134 this._running = false; 135 break; 136 default: 137 processEvent( _wndwEvnt ); 138 break; 139 } 140 } 141 render(); 142 SDL_GL_SwapWindow( _window ); 143 Thread.sleep( dur!("msecs")( _mspf ) ); 144 } 145 //if( _updateThread.isRunning ) 146 // { _updateThread.join(); } 147 } 148 /// 149 void delegate() onUpdate, onRender, onLoad, onResize; 150 151 this() 152 { this( "meatBox", 0, 0, 600, 450 ); } 153 /// 154 this( string title, int x, int y, int width, int height ) 155 { 156 scope( failure ) 157 { destroy( this ); } 158 159 SDL_Init( SDL_INIT_VIDEO ); 160 161 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); 162 SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 ); 163 164 import std.string: toStringz; 165 this._window =SDL_CreateWindow( toStringz(title), x, y, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE ); 166 this._context =SDL_GL_CreateContext( _window ); 167 this._keyboard =new Keyboard(); 168 169 setSize( width, height ); 170 onUpdate =onRender =onLoad =onResize =(){}; 171 172 DerelictGL3.reload(); 173 DerelictGL.reload(); 174 } 175 ~this() 176 { 177 SDL_GL_DeleteContext( _context ); 178 SDL_DestroyWindow( _window ); 179 SDL_Quit(); 180 } 181 }