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 glfwGetFramebufferSize(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 glfwGetFramebufferSize(window.window, &width, &height); 222 glViewport(x, y, width, height); 223 224 windowWidth = width; 225 windowHeight = height; 226 } 227 228 void onScroll(double hOffset, double vOffset) 229 { 230 mouseScroll = -cast(int)vOffset; 231 } 232 233 private: 234 Window window; 235 int windowWidth; 236 int windowHeight; 237 238 bool checkState1 = false; 239 bool checkState2 = false; 240 bool checkState3 = true; 241 bool collapseState1 = true; 242 bool collapseState2 = false; 243 244 RGBAF color; 245 float brightness = 0; 246 247 float disabledSliderValue = 30.0; 248 int scrollArea1 = 0; 249 int scrollArea2 = 0; 250 int scrollArea3 = 0; 251 int mouseScroll = 0; 252 253 char[] lastInfo; // last clicked element information 254 char[1024] buffer; // buffer to hold our text 255 } 256 257 int main(string[] args) 258 { 259 int width = 1024, height = 768; 260 261 auto window = createWindow("imgui", WindowMode.windowed, width, height); 262 263 GUI gui = GUI(window); 264 265 glfwSwapInterval(1); 266 267 string fontPath = thisExePath().dirName().buildPath("../").buildPath("DroidSans.ttf"); 268 269 enforce(imguiInit(fontPath)); 270 271 glClearColor(0.8f, 0.8f, 0.8f, 1.0f); 272 glEnable(GL_BLEND); 273 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 274 glDisable(GL_DEPTH_TEST); 275 276 while (!glfwWindowShouldClose(window.window)) 277 { 278 gui.render(); 279 280 /* Swap front and back buffers. */ 281 window.swap_buffers(); 282 283 /* Poll for and process events. */ 284 glfwPollEvents(); 285 286 if (window.is_key_down(GLFW_KEY_ESCAPE)) 287 glfwSetWindowShouldClose(window.window, true); 288 } 289 290 // Clean UI 291 imguiDestroy(); 292 293 return 0; 294 }