1 /* 2 * Copyright Andrej Mitrovic 2014. 3 * Distributed under the Boost Software License, Version 1.0. 4 * (See accompanying file LICENSE_1_0.txt or copy at 5 * http://www.boost.org/LICENSE_1_0.txt) 6 */ 7 module colors; 8 9 import std.exception; 10 import std.file; 11 import std.path; 12 import std.range; 13 import std.stdio; 14 import std.string; 15 16 import deimos.glfw.glfw3; 17 18 import glad.gl.enums; 19 import glad.gl.ext; 20 import glad.gl.funcs; 21 import glad.gl.loader; 22 import glad.gl.types; 23 24 import glwtf.input; 25 import glwtf.window; 26 27 import imgui; 28 29 import window; 30 31 struct RGBAF 32 { 33 float r = 0.0, g = 0.0, b = 0.0, a = 0.0; 34 35 RGBAF opBinary(string op)(RGBAF rgba) 36 { 37 RGBAF res = this; 38 39 mixin("res.r = res.r " ~ op ~ " rgba.r;"); 40 mixin("res.g = res.g " ~ op ~ " rgba.g;"); 41 mixin("res.b = res.b " ~ op ~ " rgba.b;"); 42 mixin("res.a = res.a " ~ op ~ " rgba.a;"); 43 44 return res; 45 } 46 } 47 48 auto clamp(T1, T2, T3)(T1 value, T2 min, T3 max) 49 { 50 return (((value) >(max)) ? (max) : (((value) <(min)) ? (min) : (value))); 51 } 52 53 RGBA toRGBA(RGBAF c) 54 { 55 return RGBA(cast(ubyte)(255.0f * clamp(c.r, 0.0, 1.0)), 56 cast(ubyte)(255.0f * clamp(c.g, 0.0, 1.0)), 57 cast(ubyte)(255.0f * clamp(c.b, 0.0, 1.0)), 58 cast(ubyte)(255.0f * clamp(c.a, 0.0, 1.0))); 59 } 60 61 RGBAF toRGBAF(RGBA c) 62 { 63 return RGBAF(clamp((cast(float)c.r) / 255.0, 0.0, 1.0), 64 clamp((cast(float)c.g) / 255.0, 0.0, 1.0), 65 clamp((cast(float)c.b) / 255.0, 0.0, 1.0), 66 clamp((cast(float)c.a) / 255.0, 0.0, 1.0)); 67 } 68 69 struct GUI 70 { 71 this(Window window) 72 { 73 this.window = window; 74 75 window.on_scroll.strongConnect(&onScroll); 76 77 int width; 78 int height; 79 glfwGetWindowSize(window.window, &width, &height); 80 81 // trigger initial viewport transform. 82 onWindowResize(width, height); 83 84 window.on_resize.strongConnect(&onWindowResize); 85 86 oldColorScheme = defaultColorScheme; 87 updateColorScheme(); 88 } 89 90 ColorScheme oldColorScheme; 91 92 void updateColorScheme() 93 { 94 auto rgbaBright = RGBAF(brightness, brightness, brightness, 0); 95 96 foreach (ref outColor, oldColor; zip(defaultColorScheme.walkColors, oldColorScheme.walkColors)) 97 { 98 auto oldRGBAF = toRGBAF(*oldColor); 99 auto res = oldRGBAF + color + rgbaBright; 100 *outColor = res.toRGBA(); 101 } 102 } 103 104 void render() 105 { 106 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 107 108 // Mouse states 109 ubyte mousebutton = 0; 110 double mouseX; 111 double mouseY; 112 glfwGetCursorPos(window.window, &mouseX, &mouseY); 113 114 const scrollAreaWidth = windowWidth / 4; 115 const scrollAreaHeight = windowHeight - 20; 116 117 int mousex = cast(int)mouseX; 118 int mousey = cast(int)mouseY; 119 120 mousey = windowHeight - mousey; 121 int leftButton = glfwGetMouseButton(window.window, GLFW_MOUSE_BUTTON_LEFT); 122 int rightButton = glfwGetMouseButton(window.window, GLFW_MOUSE_BUTTON_RIGHT); 123 int middleButton = glfwGetMouseButton(window.window, GLFW_MOUSE_BUTTON_MIDDLE); 124 125 if (leftButton == GLFW_PRESS) 126 mousebutton |= MouseButton.left; 127 128 imguiBeginFrame(mousex, mousey, mousebutton, mouseScroll); 129 130 if (mouseScroll != 0) 131 mouseScroll = 0; 132 133 imguiBeginScrollArea("Scroll area 1", 10, 10, scrollAreaWidth, scrollAreaHeight, &scrollArea1); 134 135 imguiSeparatorLine(); 136 imguiSeparator(); 137 138 if (imguiSlider("Transparency Alpha", &color.a, 0.0, 1.0, 0.01f)) 139 updateColorScheme(); 140 141 if (imguiSlider("Brightness", &brightness, -1.0, 1.0, 0.01f)) 142 updateColorScheme(); 143 144 if (imguiSlider("Red Channel", &color.r, 0.0, 1.0, 0.01f)) 145 updateColorScheme(); 146 147 if (imguiSlider("Green Channel", &color.g, 0.0, 1.0, 0.01f)) 148 updateColorScheme(); 149 150 if (imguiSlider("Blue Channel", &color.b, 0.0, 1.0, 0.01f)) 151 updateColorScheme(); 152 153 // should not be clickable 154 enforce(!imguiSlider("Disabled slider", &disabledSliderValue, 0.0, 100.0, 1.0f, Enabled.no)); 155 156 imguiIndent(); 157 imguiLabel("Indented"); 158 imguiUnindent(); 159 imguiLabel("Unindented"); 160 161 imguiEndScrollArea(); 162 163 imguiBeginScrollArea("Scroll area 2", 20 + (1 * scrollAreaWidth), 10, scrollAreaWidth, scrollAreaHeight, &scrollArea2); 164 imguiSeparatorLine(); 165 imguiSeparator(); 166 167 foreach (i; 0 .. 100) 168 imguiLabel("A wall of text"); 169 170 imguiEndScrollArea(); 171 172 imguiBeginScrollArea("Scroll area 3", 30 + (2 * scrollAreaWidth), 10, scrollAreaWidth, scrollAreaHeight, &scrollArea3); 173 imguiLabel(lastInfo); 174 imguiEndScrollArea(); 175 176 imguiEndFrame(); 177 178 const graphicsXPos = 40 + (3 * scrollAreaWidth); 179 180 imguiDrawText(graphicsXPos, scrollAreaHeight, TextAlign.left, "Free text", RGBA(32, 192, 32, 192)); 181 imguiDrawText(graphicsXPos + 100, windowHeight - 40, TextAlign.right, "Free text", RGBA(32, 32, 192, 192)); 182 imguiDrawText(graphicsXPos + 50, windowHeight - 60, TextAlign.center, "Free text", RGBA(192, 32, 32, 192)); 183 184 imguiDrawLine(graphicsXPos, windowHeight - 80, graphicsXPos + 100, windowHeight - 60, 1.0f, RGBA(32, 192, 32, 192)); 185 imguiDrawLine(graphicsXPos, windowHeight - 100, graphicsXPos + 100, windowHeight - 80, 2.0, RGBA(32, 32, 192, 192)); 186 imguiDrawLine(graphicsXPos, windowHeight - 120, graphicsXPos + 100, windowHeight - 100, 3.0, RGBA(192, 32, 32, 192)); 187 188 imguiDrawRoundedRect(graphicsXPos, windowHeight - 240, 100, 100, 5.0, RGBA(32, 192, 32, 192)); 189 imguiDrawRoundedRect(graphicsXPos, windowHeight - 350, 100, 100, 10.0, RGBA(32, 32, 192, 192)); 190 imguiDrawRoundedRect(graphicsXPos, windowHeight - 470, 100, 100, 20.0, RGBA(192, 32, 32, 192)); 191 192 imguiDrawRect(graphicsXPos, windowHeight - 590, 100, 100, RGBA(32, 192, 32, 192)); 193 imguiDrawRect(graphicsXPos, windowHeight - 710, 100, 100, RGBA(32, 32, 192, 192)); 194 imguiDrawRect(graphicsXPos, windowHeight - 830, 100, 100, RGBA(192, 32, 32, 192)); 195 196 imguiRender(windowWidth, windowHeight); 197 } 198 199 /** 200 This tells OpenGL what area of the available area we are 201 rendering to. In this case, we change it to match the 202 full available area. Without this function call resizing 203 the window would have no effect on the rendering. 204 */ 205 void onWindowResize(int width, int height) 206 { 207 // bottom-left position. 208 enum int x = 0; 209 enum int y = 0; 210 211 /** 212 This function defines the current viewport transform. 213 It defines as a region of the window, specified by the 214 bottom-left position and a width/height. 215 216 Note about the viewport transform: 217 It is the process of transforming vertex data from normalized 218 device coordinate space to window space. It specifies the 219 viewable region of a window. 220 */ 221 glViewport(x, y, width, height); 222 223 windowWidth = width; 224 windowHeight = height; 225 } 226 227 void onScroll(double hOffset, double vOffset) 228 { 229 mouseScroll = -cast(int)vOffset; 230 } 231 232 private: 233 Window window; 234 int windowWidth; 235 int windowHeight; 236 237 bool checkState1 = false; 238 bool checkState2 = false; 239 bool checkState3 = true; 240 bool collapseState1 = true; 241 bool collapseState2 = false; 242 243 RGBAF color; 244 float brightness = 0; 245 246 float disabledSliderValue = 30.0; 247 int scrollArea1 = 0; 248 int scrollArea2 = 0; 249 int scrollArea3 = 0; 250 int mouseScroll = 0; 251 252 char[] lastInfo; // last clicked element information 253 char[1024] buffer; // buffer to hold our text 254 } 255 256 int main(string[] args) 257 { 258 int width = 1024, height = 768; 259 260 auto window = createWindow("imgui", WindowMode.windowed, width, height); 261 262 GUI gui = GUI(window); 263 264 glfwSwapInterval(1); 265 266 string fontPath = thisExePath().dirName().buildPath("../").buildPath("DroidSans.ttf"); 267 268 enforce(imguiInit(fontPath)); 269 270 glClearColor(0.8f, 0.8f, 0.8f, 1.0f); 271 glEnable(GL_BLEND); 272 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 273 glDisable(GL_DEPTH_TEST); 274 275 while (!glfwWindowShouldClose(window.window)) 276 { 277 gui.render(); 278 279 /* Swap front and back buffers. */ 280 window.swap_buffers(); 281 282 /* Poll for and process events. */ 283 glfwPollEvents(); 284 285 if (window.is_key_down(GLFW_KEY_ESCAPE)) 286 glfwSetWindowShouldClose(window.window, true); 287 } 288 289 // Clean UI 290 imguiDestroy(); 291 292 return 0; 293 }