1 module rpui.application; 2 3 import std.conv; 4 import std.array; 5 import std.string; 6 7 import derelict.sdl2.sdl; 8 9 import gapi.opengl; 10 import rpui.events; 11 import rpui.events_observer; 12 import rpui.input; 13 import rpui.cursor; 14 import rpui.primitives; 15 import rpui.platform; 16 17 abstract class Application : EventsListenerEmpty { 18 struct WindowData { 19 void* window; 20 void* glContext; 21 int viewportWidth = 1024; 22 int viewportHeight = 768; 23 } 24 25 struct Times { 26 float current = 0f; 27 float delta = 0f; 28 float last = 0f; 29 immutable part = 1_000.0 / 60.0; 30 } 31 32 protected EventsObserver events; 33 protected CursorManager cursorManager; 34 35 protected WindowData windowData; 36 private Times times; 37 private bool isPlatformInit = false; 38 39 this() { 40 events = new EventsObserver(); 41 cursorManager = new CursorManager(); 42 events.subscribe(this); 43 } 44 45 ~this() { 46 if (isPlatformInit) { 47 platformGapiDeleteContext(windowData.glContext); 48 platformDestroyWindow(windowData.window); 49 platformShutdown(); 50 } 51 } 52 53 final void run() { 54 initPlatform(); 55 initGL(); 56 onCreate(); 57 mainLoop(); 58 } 59 60 override void onWindowResize(in WindowResizeEvent event) { 61 windowData.viewportWidth = event.width; 62 windowData.viewportHeight = event.height; 63 glViewport(0, 0, event.width, event.height); 64 } 65 66 private void initPlatform() { 67 platformInit(); 68 69 auto window = platformCreateWindow( 70 "RPUI", 71 windowData.viewportWidth, 72 windowData.viewportHeight 73 ); 74 75 windowData.window = window.handle; 76 windowData.glContext = window.gapiContext; 77 78 isPlatformInit = true; 79 } 80 81 private void initGL() { 82 glDisable(GL_CULL_FACE); 83 glDisable(GL_MULTISAMPLE); 84 glDisable(GL_DEPTH_TEST); 85 glEnable(GL_BLEND); 86 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 87 glClearColor(150.0f/255.0f, 150.0f/255.0f, 150.0f/255.0f, 0); 88 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 89 } 90 91 private void mainLoop() { 92 bool running = true; 93 events.notify(WindowResizeEvent(windowData.viewportWidth, windowData.viewportHeight)); 94 95 while (running) { 96 int width; 97 int height; 98 SDL_GetWindowSize(cast(SDL_Window*) windowData.window, &width, &height); 99 100 windowData.viewportHeight = width; 101 windowData.viewportHeight = height; 102 103 times.current = platformGetTicks(); 104 running = platformEventLoop(windowData.window, events); 105 render(); 106 } 107 } 108 109 private void render() { 110 if (times.current >= times.last + times.part) { 111 times.delta = (times.current - times.last) / 1000.0f; 112 onProgress(ProgressEvent(times.delta)); 113 times.last = times.current; 114 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 115 onRender(); 116 platformSwapWindow(windowData.window); 117 } 118 } 119 120 override void onWindowExposed(in WindowExposedEvent event) { 121 // TODO(Andrey): test on windows 122 // glViewport(0, 0, windowData.viewportWidth, windowData.viewportHeight); 123 int width; 124 int height; 125 SDL_GetWindowSize(cast(SDL_Window*) windowData.window, &width, &height); 126 127 windowData.viewportHeight = width; 128 windowData.viewportHeight = height; 129 130 onProgress(ProgressEvent(0)); 131 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 132 onRender(); 133 platformSwapWindow(windowData.window); 134 } 135 136 void onRender() { 137 } 138 139 void onCreate() { 140 } 141 142 void onDestroy() { 143 } 144 145 void onProgress(in ProgressEvent event) { 146 } 147 }