monitor.cc (11895B)
1 //======================================================================== 2 // GLFW 3.3 - www.glfw.org 3 //------------------------------------------------------------------------ 4 // Copyright (c) 2002-2006 Marcus Geelnard 5 // Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org> 6 // 7 // This software is provided 'as-is', without any express or implied 8 // warranty. In no event will the authors be held liable for any damages 9 // arising from the use of this software. 10 // 11 // Permission is granted to anyone to use this software for any purpose, 12 // including commercial applications, and to alter it and redistribute it 13 // freely, subject to the following restrictions: 14 // 15 // 1. The origin of this software must not be misrepresented; you must not 16 // claim that you wrote the original software. If you use this software 17 // in a product, an acknowledgment in the product documentation would 18 // be appreciated but is not required. 19 // 20 // 2. Altered source versions must be plainly marked as such, and must not 21 // be misrepresented as being the original software. 22 // 23 // 3. This notice may not be removed or altered from any source 24 // distribution. 25 // 26 //======================================================================== 27 28 #include "internal.h" 29 30 #include <assert.h> 31 #include <math.h> 32 #include <float.h> 33 #include <string.h> 34 #include <stdlib.h> 35 #include <limits.h> 36 37 38 // Lexically compare video modes, used by qsort 39 // 40 static int compareVideoModes(const void* fp, const void* sp) 41 { 42 const GLFWvidmode* fm = fp; 43 const GLFWvidmode* sm = sp; 44 const int fbpp = fm->redBits + fm->greenBits + fm->blueBits; 45 const int sbpp = sm->redBits + sm->greenBits + sm->blueBits; 46 const int farea = fm->width * fm->height; 47 const int sarea = sm->width * sm->height; 48 49 // First sort on color bits per pixel 50 if (fbpp != sbpp) 51 return fbpp - sbpp; 52 53 // Then sort on screen area 54 if (farea != sarea) 55 return farea - sarea; 56 57 // Lastly sort on refresh rate 58 return fm->refreshRate - sm->refreshRate; 59 } 60 61 // Retrieves the available modes for the specified monitor 62 // 63 static GLFWbool refreshVideoModes(_GLFWmonitor* monitor) 64 { 65 int modeCount; 66 GLFWvidmode* modes; 67 68 if (monitor->modes) 69 return GLFW_TRUE; 70 71 modes = _glfwPlatformGetVideoModes(monitor, &modeCount); 72 if (!modes) 73 return GLFW_FALSE; 74 75 qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes); 76 77 free(monitor->modes); 78 monitor->modes = modes; 79 monitor->modeCount = modeCount; 80 81 return GLFW_TRUE; 82 } 83 84 85 ////////////////////////////////////////////////////////////////////////// 86 ////// GLFW event API ////// 87 ////////////////////////////////////////////////////////////////////////// 88 89 void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) 90 { 91 if (action == GLFW_CONNECTED) 92 { 93 _glfw.monitorCount++; 94 _glfw.monitors = 95 realloc(_glfw.monitors, sizeof(_GLFWmonitor*) * _glfw.monitorCount); 96 97 if (placement == _GLFW_INSERT_FIRST) 98 { 99 memmove(_glfw.monitors + 1, 100 _glfw.monitors, 101 (_glfw.monitorCount - 1) * sizeof(_GLFWmonitor*)); 102 _glfw.monitors[0] = monitor; 103 } 104 else 105 _glfw.monitors[_glfw.monitorCount - 1] = monitor; 106 } 107 else if (action == GLFW_DISCONNECTED) 108 { 109 int i; 110 111 for (i = 0; i < _glfw.monitorCount; i++) 112 { 113 if (_glfw.monitors[i] == monitor) 114 { 115 _glfw.monitorCount--; 116 memmove(_glfw.monitors + i, 117 _glfw.monitors + i + 1, 118 (_glfw.monitorCount - i) * sizeof(_GLFWmonitor*)); 119 break; 120 } 121 } 122 } 123 124 if (_glfw.callbacks.monitor) 125 _glfw.callbacks.monitor((GLFWmonitor*) monitor, action); 126 127 if (action == GLFW_DISCONNECTED) 128 _glfwFreeMonitor(monitor); 129 } 130 131 void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window) 132 { 133 monitor->window = window; 134 } 135 136 137 ////////////////////////////////////////////////////////////////////////// 138 ////// GLFW internal API ////// 139 ////////////////////////////////////////////////////////////////////////// 140 141 _GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM) 142 { 143 _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor)); 144 monitor->widthMM = widthMM; 145 monitor->heightMM = heightMM; 146 147 if (name) 148 monitor->name = strdup(name); 149 150 return monitor; 151 } 152 153 void _glfwFreeMonitor(_GLFWmonitor* monitor) 154 { 155 if (monitor == NULL) 156 return; 157 158 _glfwFreeGammaArrays(&monitor->originalRamp); 159 _glfwFreeGammaArrays(&monitor->currentRamp); 160 161 free(monitor->modes); 162 free(monitor->name); 163 free(monitor); 164 } 165 166 void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size) 167 { 168 ramp->red = calloc(size, sizeof(unsigned short)); 169 ramp->green = calloc(size, sizeof(unsigned short)); 170 ramp->blue = calloc(size, sizeof(unsigned short)); 171 ramp->size = size; 172 } 173 174 void _glfwFreeGammaArrays(GLFWgammaramp* ramp) 175 { 176 free(ramp->red); 177 free(ramp->green); 178 free(ramp->blue); 179 180 memset(ramp, 0, sizeof(GLFWgammaramp)); 181 } 182 183 const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor, 184 const GLFWvidmode* desired) 185 { 186 int i; 187 unsigned int sizeDiff, leastSizeDiff = UINT_MAX; 188 unsigned int rateDiff, leastRateDiff = UINT_MAX; 189 unsigned int colorDiff, leastColorDiff = UINT_MAX; 190 const GLFWvidmode* current; 191 const GLFWvidmode* closest = NULL; 192 193 if (!refreshVideoModes(monitor)) 194 return NULL; 195 196 for (i = 0; i < monitor->modeCount; i++) 197 { 198 current = monitor->modes + i; 199 200 colorDiff = 0; 201 202 if (desired->redBits != GLFW_DONT_CARE) 203 colorDiff += abs(current->redBits - desired->redBits); 204 if (desired->greenBits != GLFW_DONT_CARE) 205 colorDiff += abs(current->greenBits - desired->greenBits); 206 if (desired->blueBits != GLFW_DONT_CARE) 207 colorDiff += abs(current->blueBits - desired->blueBits); 208 209 sizeDiff = abs((current->width - desired->width) * 210 (current->width - desired->width) + 211 (current->height - desired->height) * 212 (current->height - desired->height)); 213 214 if (desired->refreshRate != GLFW_DONT_CARE) 215 rateDiff = abs(current->refreshRate - desired->refreshRate); 216 else 217 rateDiff = UINT_MAX - current->refreshRate; 218 219 if ((colorDiff < leastColorDiff) || 220 (colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) || 221 (colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff)) 222 { 223 closest = current; 224 leastSizeDiff = sizeDiff; 225 leastRateDiff = rateDiff; 226 leastColorDiff = colorDiff; 227 } 228 } 229 230 return closest; 231 } 232 233 int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm) 234 { 235 return compareVideoModes(fm, sm); 236 } 237 238 void _glfwSplitBPP(int bpp, int* red, int* green, int* blue) 239 { 240 int delta; 241 242 // We assume that by 32 the user really meant 24 243 if (bpp == 32) 244 bpp = 24; 245 246 // Convert "bits per pixel" to red, green & blue sizes 247 248 *red = *green = *blue = bpp / 3; 249 delta = bpp - (*red * 3); 250 if (delta >= 1) 251 *green = *green + 1; 252 253 if (delta == 2) 254 *red = *red + 1; 255 } 256 257 258 ////////////////////////////////////////////////////////////////////////// 259 ////// GLFW public API ////// 260 ////////////////////////////////////////////////////////////////////////// 261 262 GLFWAPI GLFWmonitor** glfwGetMonitors(int* count) 263 { 264 assert(count != NULL); 265 266 *count = 0; 267 268 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 269 270 *count = _glfw.monitorCount; 271 return (GLFWmonitor**) _glfw.monitors; 272 } 273 274 GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void) 275 { 276 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 277 278 if (!_glfw.monitorCount) 279 return NULL; 280 281 return (GLFWmonitor*) _glfw.monitors[0]; 282 } 283 284 GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos) 285 { 286 _GLFWmonitor* monitor = (_GLFWmonitor*) handle; 287 assert(monitor != NULL); 288 289 if (xpos) 290 *xpos = 0; 291 if (ypos) 292 *ypos = 0; 293 294 _GLFW_REQUIRE_INIT(); 295 296 _glfwPlatformGetMonitorPos(monitor, xpos, ypos); 297 } 298 299 GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM) 300 { 301 _GLFWmonitor* monitor = (_GLFWmonitor*) handle; 302 assert(monitor != NULL); 303 304 if (widthMM) 305 *widthMM = 0; 306 if (heightMM) 307 *heightMM = 0; 308 309 _GLFW_REQUIRE_INIT(); 310 311 if (widthMM) 312 *widthMM = monitor->widthMM; 313 if (heightMM) 314 *heightMM = monitor->heightMM; 315 } 316 317 GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle) 318 { 319 _GLFWmonitor* monitor = (_GLFWmonitor*) handle; 320 assert(monitor != NULL); 321 322 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 323 return monitor->name; 324 } 325 326 GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun) 327 { 328 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 329 _GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun); 330 return cbfun; 331 } 332 333 GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count) 334 { 335 _GLFWmonitor* monitor = (_GLFWmonitor*) handle; 336 assert(monitor != NULL); 337 assert(count != NULL); 338 339 *count = 0; 340 341 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 342 343 if (!refreshVideoModes(monitor)) 344 return NULL; 345 346 *count = monitor->modeCount; 347 return monitor->modes; 348 } 349 350 GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle) 351 { 352 _GLFWmonitor* monitor = (_GLFWmonitor*) handle; 353 assert(monitor != NULL); 354 355 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 356 357 _glfwPlatformGetVideoMode(monitor, &monitor->currentMode); 358 return &monitor->currentMode; 359 } 360 361 GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) 362 { 363 int i; 364 unsigned short values[256]; 365 GLFWgammaramp ramp; 366 assert(handle != NULL); 367 assert(gamma == gamma); 368 assert(gamma >= 0.f); 369 assert(gamma <= FLT_MAX); 370 371 _GLFW_REQUIRE_INIT(); 372 373 if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX) 374 { 375 _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma); 376 return; 377 } 378 379 for (i = 0; i < 256; i++) 380 { 381 double value; 382 383 // Calculate intensity 384 value = i / 255.0; 385 // Apply gamma curve 386 value = pow(value, 1.0 / gamma) * 65535.0 + 0.5; 387 388 // Clamp to value range 389 if (value > 65535.0) 390 value = 65535.0; 391 392 values[i] = (unsigned short) value; 393 } 394 395 ramp.red = values; 396 ramp.green = values; 397 ramp.blue = values; 398 ramp.size = 256; 399 400 glfwSetGammaRamp(handle, &ramp); 401 } 402 403 GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) 404 { 405 _GLFWmonitor* monitor = (_GLFWmonitor*) handle; 406 assert(monitor != NULL); 407 408 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 409 410 _glfwFreeGammaArrays(&monitor->currentRamp); 411 _glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp); 412 413 return &monitor->currentRamp; 414 } 415 416 GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp) 417 { 418 _GLFWmonitor* monitor = (_GLFWmonitor*) handle; 419 assert(monitor != NULL); 420 assert(ramp != NULL); 421 assert(ramp->size > 0); 422 assert(ramp->red != NULL); 423 assert(ramp->green != NULL); 424 assert(ramp->blue != NULL); 425 426 if (ramp->size <= 0) 427 { 428 _glfwInputError(GLFW_INVALID_VALUE, 429 "Invalid gamma ramp size %i", 430 ramp->size); 431 return; 432 } 433 434 _GLFW_REQUIRE_INIT(); 435 436 if (!monitor->originalRamp.size) 437 _glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp); 438 439 _glfwPlatformSetGammaRamp(monitor, ramp); 440 } 441