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 const scaleX = event.originalWidth / event.width; 64 const scaleY = event.originalHeight / event.height; 65 glViewport(0, 0, event.width * scaleX, event.height * scaleY); 66 } 67 68 private void initPlatform() { 69 platformInit(); 70 71 auto window = platformCreateWindow( 72 "RPUI", 73 windowData.viewportWidth, 74 windowData.viewportHeight 75 ); 76 77 windowData.window = window.handle; 78 windowData.glContext = window.gapiContext; 79 80 isPlatformInit = true; 81 } 82 83 private void initGL() { 84 glDisable(GL_CULL_FACE); 85 glDisable(GL_MULTISAMPLE); 86 glDisable(GL_DEPTH_TEST); 87 glEnable(GL_BLEND); 88 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 89 glClearColor(150.0f/255.0f, 150.0f/255.0f, 150.0f/255.0f, 0); 90 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 91 } 92 93 private void mainLoop() { 94 bool running = true; 95 int width; 96 int height; 97 int originalWidth; 98 int originalHeight; 99 100 SDL_GetWindowSize(cast(SDL_Window*) windowData.window, &width, &height); 101 SDL_GL_GetDrawableSize(cast(SDL_Window*) windowData.window, &originalWidth, &originalHeight); 102 103 events.notify( 104 WindowResizeEvent( 105 width, 106 height, 107 originalWidth, 108 originalHeight 109 ) 110 ); 111 112 while (running) { 113 SDL_GetWindowSize(cast(SDL_Window*) windowData.window, &width, &height); 114 115 windowData.viewportWidth = width; 116 windowData.viewportHeight = height; 117 118 times.current = platformGetTicks(); 119 running = platformEventLoop(windowData.window, events); 120 render(); 121 } 122 } 123 124 private void render() { 125 if (times.current >= times.last + times.part) { 126 times.delta = (times.current - times.last) / 1000.0f; 127 onProgress(ProgressEvent(times.delta)); 128 times.last = times.current; 129 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 130 onRender(); 131 platformSwapWindow(windowData.window); 132 } 133 } 134 135 override void onWindowExposed(in WindowExposedEvent event) { 136 // TODO(Andrey): test on windows 137 // glViewport(0, 0, windowData.viewportWidth, windowData.viewportHeight); 138 int width; 139 int height; 140 SDL_GetWindowSize(cast(SDL_Window*) windowData.window, &width, &height); 141 142 windowData.viewportWidth = width; 143 windowData.viewportHeight = height; 144 145 onProgress(ProgressEvent(0)); 146 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 147 onRender(); 148 platformSwapWindow(windowData.window); 149 } 150 151 void onRender() { 152 } 153 154 void onCreate() { 155 } 156 157 void onDestroy() { 158 } 159 160 void onProgress(in ProgressEvent event) { 161 } 162 }